fix(progress-indicator): allow currentIndex to be programmatically updated

This commit is contained in:
Eric Liu 2020-11-20 06:21:27 -08:00
commit c513279751
6 changed files with 110 additions and 36 deletions

View file

@ -2503,7 +2503,7 @@ None.
| currentIndex | <code>let</code> | Yes | <code>number</code> | <code>0</code> | Specify the current step index | | currentIndex | <code>let</code> | Yes | <code>number</code> | <code>0</code> | Specify the current step index |
| vertical | <code>let</code> | No | <code>boolean</code> | <code>false</code> | Set to `true` to use the vertical variant | | vertical | <code>let</code> | No | <code>boolean</code> | <code>false</code> | Set to `true` to use the vertical variant |
| spaceEqually | <code>let</code> | No | <code>boolean</code> | <code>false</code> | Set to `true` to specify whether the progress steps should be split equally in size in the div | | spaceEqually | <code>let</code> | No | <code>boolean</code> | <code>false</code> | Set to `true` to specify whether the progress steps should be split equally in size in the div |
| preventChangeOnClick | <code>let</code> | No | <code>boolean</code> | <code>false</code> | Set to `true` to prevent updating `currentIndex` | | preventChangeOnClick | <code>let</code> | No | <code>boolean</code> | <code>false</code> | Set to `true` to prevent `currentIndex` from updating |
### Slots ### Slots
@ -2514,12 +2514,12 @@ None.
### Events ### Events
| Event name | Type | Detail | | Event name | Type | Detail |
| :--------- | :--------- | :----- | | :--------- | :--------- | :------------------ |
| change | dispatched | <code>number</code> |
| click | forwarded | -- | | click | forwarded | -- |
| mouseover | forwarded | -- | | mouseover | forwarded | -- |
| mouseenter | forwarded | -- | | mouseenter | forwarded | -- |
| mouseleave | forwarded | -- | | mouseleave | forwarded | -- |
| change | dispatched | -- |
## `ProgressIndicatorSkeleton` ## `ProgressIndicatorSkeleton`

View file

@ -6697,7 +6697,7 @@
{ {
"name": "preventChangeOnClick", "name": "preventChangeOnClick",
"kind": "let", "kind": "let",
"description": "Set to `true` to prevent updating `currentIndex`", "description": "Set to `true` to prevent `currentIndex` from updating",
"type": "boolean", "type": "boolean",
"value": "false", "value": "false",
"isFunction": false, "isFunction": false,
@ -6707,11 +6707,11 @@
], ],
"slots": [{ "name": "__default__", "default": true, "slot_props": "{}" }], "slots": [{ "name": "__default__", "default": true, "slot_props": "{}" }],
"events": [ "events": [
{ "type": "dispatched", "name": "change", "detail": "number" },
{ "type": "forwarded", "name": "click", "element": "ul" }, { "type": "forwarded", "name": "click", "element": "ul" },
{ "type": "forwarded", "name": "mouseover", "element": "ul" }, { "type": "forwarded", "name": "mouseover", "element": "ul" },
{ "type": "forwarded", "name": "mouseenter", "element": "ul" }, { "type": "forwarded", "name": "mouseenter", "element": "ul" },
{ "type": "forwarded", "name": "mouseleave", "element": "ul" }, { "type": "forwarded", "name": "mouseleave", "element": "ul" }
{ "type": "dispatched", "name": "change" }
], ],
"typedefs": [], "typedefs": [],
"rest_props": { "type": "Element", "name": "ul" } "rest_props": { "type": "Element", "name": "ul" }

View file

@ -0,0 +1,52 @@
<script>
import {
ProgressIndicator,
ProgressStep,
Button,
} from "carbon-components-svelte";
let currentIndex = 1;
let thirdStepComplete = false;
</script>
<ProgressIndicator bind:currentIndex>
<ProgressStep
complete
label="Step 1"
description="The progress indicator will listen for clicks on the steps"
/>
<ProgressStep
complete
label="Step 2"
description="The progress indicator will listen for clicks on the steps"
/>
<ProgressStep
complete="{thirdStepComplete}"
label="Step 3"
description="The progress indicator will listen for clicks on the steps"
/>
<ProgressStep
label="Step 4"
description="The progress indicator will listen for clicks on the steps"
/>
</ProgressIndicator>
<div style="margin: var(--cds-layout-02) 0">
<Button
on:click="{() => {
currentIndex = 2;
}}"
>
Set index to 2
</Button>
<Button
kind="ghost"
on:click="{() => {
thirdStepComplete = !thirdStepComplete;
}}"
>
Toggle step 3
</Button>
</div>
<h3>Current index: {currentIndex}</h3>

View file

@ -8,7 +8,7 @@
/** Set to `true` to specify whether the progress steps should be split equally in size in the div */ /** Set to `true` to specify whether the progress steps should be split equally in size in the div */
export let spaceEqually = false; export let spaceEqually = false;
/** Set to `true` to prevent updating `currentIndex` */ /** Set to `true` to prevent `currentIndex` from updating */
export let preventChangeOnClick = false; export let preventChangeOnClick = false;
import { createEventDispatcher, setContext } from "svelte"; import { createEventDispatcher, setContext } from "svelte";
@ -24,28 +24,40 @@
steps, steps,
stepsById, stepsById,
add: (step) => { add: (step) => {
steps.update((_) => [ steps.update((_) => {
if (step.id in $stepsById) {
return _.map((_step) => {
if (_step.id === step.id) return { ..._step, ...step };
return _step;
});
}
return [
..._, ..._,
{ {
...step, ...step,
index: _.length, index: _.length,
current: _.length === currentIndex, current: _.length === currentIndex,
complete: _.length <= currentIndex, complete: step.complete,
}, },
]); ];
});
}, },
change: (index) => { change: (index) => {
if (preventChangeOnClick) return; if (preventChangeOnClick) return;
currentIndex = index; currentIndex = index;
steps.update((_) =>
[..._].map((step, i) => ({ /** @event {number} change */
...step,
current: i === index,
}))
);
dispatch("change", index); dispatch("change", index);
}, },
}); });
$: steps.update((_) =>
_.map((step, i) => ({
...step,
current: i === currentIndex,
}))
);
</script> </script>
<ul <ul

View file

@ -23,19 +23,29 @@
/** Set an id for the top-level element */ /** Set an id for the top-level element */
export let id = "ccs-" + Math.random().toString(36); export let id = "ccs-" + Math.random().toString(36);
import { getContext } from "svelte"; import { onMount, getContext } from "svelte";
import CheckmarkOutline16 from "carbon-icons-svelte/lib/CheckmarkOutline16"; import CheckmarkOutline16 from "carbon-icons-svelte/lib/CheckmarkOutline16";
import Warning16 from "carbon-icons-svelte/lib/Warning16"; import Warning16 from "carbon-icons-svelte/lib/Warning16";
let step = {};
const { stepsById, add, change } = getContext("ProgressIndicator"); const { stepsById, add, change } = getContext("ProgressIndicator");
add({ id, disabled }); $: add({ id, complete, disabled });
$: step = $stepsById[id]; const unsubscribe = stepsById.subscribe((value) => {
$: { if (value[id]) {
step = value[id];
current = step.current; current = step.current;
complete = step.complete; complete = step.complete;
} }
});
onMount(() => {
return () => {
unsubscribe();
};
});
</script> </script>
<li <li

View file

@ -20,7 +20,7 @@ export interface ProgressIndicatorProps extends svelte.JSX.HTMLAttributes<HTMLEl
spaceEqually?: boolean; spaceEqually?: boolean;
/** /**
* Set to `true` to prevent updating `currentIndex` * Set to `true` to prevent `currentIndex` from updating
* @default false * @default false
*/ */
preventChangeOnClick?: boolean; preventChangeOnClick?: boolean;
@ -32,10 +32,10 @@ export default class ProgressIndicator {
default: {}; default: {};
}; };
$on(eventname: "change", cb: (event: CustomEvent<number>) => void): () => void;
$on(eventname: "click", cb: (event: WindowEventMap["click"]) => void): () => void; $on(eventname: "click", cb: (event: WindowEventMap["click"]) => void): () => void;
$on(eventname: "mouseover", cb: (event: WindowEventMap["mouseover"]) => void): () => void; $on(eventname: "mouseover", cb: (event: WindowEventMap["mouseover"]) => void): () => void;
$on(eventname: "mouseenter", cb: (event: WindowEventMap["mouseenter"]) => void): () => void; $on(eventname: "mouseenter", cb: (event: WindowEventMap["mouseenter"]) => void): () => void;
$on(eventname: "mouseleave", cb: (event: WindowEventMap["mouseleave"]) => void): () => void; $on(eventname: "mouseleave", cb: (event: WindowEventMap["mouseleave"]) => void): () => void;
$on(eventname: "change", cb: (event: CustomEvent<any>) => void): () => void;
$on(eventname: string, cb: (event: Event) => void): () => void; $on(eventname: string, cb: (event: Event) => void): () => void;
} }