@carbon/vue 3.0.6-alpha.0 → 3.0.7-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/dist/carbon-vue-3.common.js +11880 -8135
  2. package/dist/carbon-vue-3.common.js.map +1 -1
  3. package/dist/carbon-vue-3.umd.js +11880 -8135
  4. package/dist/carbon-vue-3.umd.js.map +1 -1
  5. package/dist/carbon-vue-3.umd.min.js +4 -4
  6. package/dist/carbon-vue-3.umd.min.js.map +1 -1
  7. package/package.json +4 -4
  8. package/src/components/CvAccordion/CvAccordion.stories.js +1 -0
  9. package/src/components/CvButton/CvButton.stories.js +3 -3
  10. package/src/components/CvButton/CvButtonSkeleton.stories.js +79 -0
  11. package/src/components/CvButton/CvButtonSkeleton.vue +19 -0
  12. package/src/components/CvButton/index.js +8 -1
  13. package/src/components/CvDatePicker/CvDatePicker.vue +1 -1
  14. package/src/components/CvDropdown/CvDropdown.stories.mdx +407 -0
  15. package/src/components/CvDropdown/CvDropdown.vue +418 -0
  16. package/src/components/CvDropdown/CvDropdownItem.vue +86 -0
  17. package/src/components/CvDropdown/CvDropdownSkeleton.vue +17 -0
  18. package/src/components/CvDropdown/index.js +5 -0
  19. package/src/components/CvForm/CvFormGroup.vue +1 -1
  20. package/src/components/CvInlineLoading/CvInlineLoading.stories.mdx +87 -0
  21. package/src/components/CvInlineLoading/CvInlineLoading.vue +144 -0
  22. package/src/components/CvInlineLoading/consts.js +9 -0
  23. package/src/components/CvInlineLoading/index.js +4 -0
  24. package/src/components/CvModal/CvModal.stories.mdx +4 -2
  25. package/src/components/CvModal/CvModal.vue +3 -5
  26. package/src/components/CvMultiSelect/CvMultiSelect.stories.mdx +333 -0
  27. package/src/components/CvMultiSelect/CvMultiSelect.vue +705 -0
  28. package/src/components/CvMultiSelect/consts.js +16 -0
  29. package/src/components/CvMultiSelect/index.js +3 -0
  30. package/src/components/CvNumberInput/CvNumberInput.stories.js +265 -0
  31. package/src/components/CvNumberInput/CvNumberInput.vue +227 -0
  32. package/src/components/CvNumberInput/CvNumberInputSkeleton.stories.js +30 -0
  33. package/src/components/CvNumberInput/CvNumberInputSkeleton.vue +10 -0
  34. package/src/components/CvNumberInput/StorybookGroupConst.js +1 -0
  35. package/src/components/CvNumberInput/__tests__/__snapshots__/CvNumberInput.spec.js.snap +21 -0
  36. package/src/components/CvNumberInput/index.js +5 -0
  37. package/src/components/CvTabs/CvTab.vue +77 -0
  38. package/src/components/CvTabs/CvTabs.stories.mdx +175 -0
  39. package/src/components/CvTabs/CvTabs.vue +406 -0
  40. package/src/components/CvTabs/CvTabsSkeleton.vue +24 -0
  41. package/src/components/CvTabs/_SbContainer.vue +22 -0
  42. package/src/components/CvTabs/index.js +5 -0
  43. package/src/components/CvToggle/CvToggle-Skeleton.vue +29 -0
  44. package/src/components/CvToggle/CvToggle.stories.js +232 -0
  45. package/src/components/CvToggle/CvToggle.vue +70 -0
  46. package/src/components/CvToggle/__tests__/__snapshots__/CvToggle.spec.js.snap +7 -0
  47. package/src/components/CvToggle/index.js +4 -0
  48. package/src/global/storybook-utils/story-source-code.js +1 -0
  49. package/src/use/cvInput.js +34 -0
@@ -0,0 +1,418 @@
1
+ <!--
2
+ Carbon Style Dropdown
3
+
4
+ Attributes:
5
+ placeholder: Placeholder text displayed before any selection is made.
6
+
7
+ Usage:
8
+ <cv-dropdown placeholder="Choose an option">
9
+ <cv-dropdown-item value="10">Option 1</cv-dropdown-item>
10
+ <cv-dropdown-item value="20">Option 2</cv-dropdown-item>
11
+ <cv-dropdown-item value="30">Option 3</cv-dropdown-item>
12
+ <cv-dropdown-item value="40">Option 4</cv-dropdown-item>
13
+ <cv-dropdown-item value="50">Option 5</cv-dropdown-item>
14
+ </cv-dropdown>
15
+
16
+ -->
17
+
18
+ <template>
19
+ <div :id="uid" ref="el" :class="{ [`${carbonPrefix}--form-item`]: formItem }">
20
+ <div
21
+ :class="[
22
+ `${carbonPrefix}--dropdown__wrapper`,
23
+ `${carbonPrefix}--list-box__wrapper`,
24
+ {
25
+ [`${carbonPrefix}--dropdown__wrapper--inline`]: inline,
26
+ [`${carbonPrefix}--list-box__wrapper--inline`]: inline,
27
+ 'cv-dropdown': !formItem,
28
+ },
29
+ ]"
30
+ :style="wrapperStyleOverride"
31
+ >
32
+ <label
33
+ v-if="label"
34
+ :id="`${uid}-label`"
35
+ :class="[
36
+ `${carbonPrefix}--label`,
37
+ { [`${carbonPrefix}--label--disabled`]: disabled },
38
+ ]"
39
+ >{{ label }}</label
40
+ >
41
+
42
+ <div
43
+ ref="listBox"
44
+ :aria-label="ariaLabel"
45
+ :class="[
46
+ `${carbonPrefix}--dropdown`,
47
+ `${carbonPrefix}--dropdown--${size}`,
48
+ {
49
+ [`${carbonPrefix}--dropdown--show-selected`]: !hideSelected,
50
+ [`${carbonPrefix}--dropdown--warning`]: isWarning,
51
+ [`${carbonPrefix}--list-box--warning`]: isWarning,
52
+ [`${carbonPrefix}--dropdown--invalid`]: data.isInvalid,
53
+ [`${carbonPrefix}--list-box`]: true,
54
+ [`${carbonPrefix}--dropdown--light`]: isLight,
55
+ [`${carbonPrefix}--list-box--up`]: up,
56
+ [`${carbonPrefix}--dropdown--open`]: open,
57
+ [`${carbonPrefix}--list-box--expanded`]: open,
58
+ [`${carbonPrefix}--dropdown--disabled`]: disabled,
59
+ [`${carbonPrefix}--dropdown--inline`]: inline,
60
+ },
61
+ ]"
62
+ :data-invalid="data.isInvalid"
63
+ :data-value="dataValue"
64
+ data-dropdown
65
+ v-bind="$attrs"
66
+ @click="onClick"
67
+ @keydown.down.prevent="onDown"
68
+ @keydown.up.prevent="onUp"
69
+ @keydown.enter.prevent="onClick"
70
+ @keydown.esc.prevent="onEsc"
71
+ @keydown.tab="onTab"
72
+ >
73
+ <button
74
+ ref="button"
75
+ :aria-controls="`${uid}-menu`"
76
+ :aria-disabled="disabled"
77
+ :aria-expanded="open ? 'true' : 'false'"
78
+ :aria-labelledby="ariaLabeledBy"
79
+ :class="`${carbonPrefix}--list-box__field`"
80
+ :disabled="disabled"
81
+ aria-haspopup="true"
82
+ type="button"
83
+ >
84
+ <warning-alt-filled
85
+ v-if="isWarning"
86
+ :class="`${carbonPrefix}--list-box__invalid-icon ${carbonPrefix}--list-box__invalid-icon--warning`"
87
+ />
88
+ <warning-filled
89
+ v-else-if="data.isInvalid"
90
+ :class="`${carbonPrefix}--list-box__invalid-icon`"
91
+ />
92
+ <span
93
+ :id="`${uid}-value`"
94
+ :class="`${carbonPrefix}--list-box__label`"
95
+ data-test="internalCaption"
96
+ >
97
+ <slot name="internal-caption">{{ internalCaption }}</slot>
98
+ </span>
99
+ <div
100
+ :class="[
101
+ `${carbonPrefix}--list-box__menu-icon`,
102
+ { [`${carbonPrefix}--list-box__menu-icon--open`]: open },
103
+ ]"
104
+ >
105
+ <chevron-down :aria-label="open ? 'Close menu' : 'Open menu'" />
106
+ </div>
107
+ </button>
108
+ <ul
109
+ :id="`${uid}-menu`"
110
+ ref="dropList"
111
+ :aria-hidden="!open ? 'true' : 'false'"
112
+ :aria-labelledby="`${uid}-label`"
113
+ :class="`${carbonPrefix}--list-box__menu`"
114
+ role="menu"
115
+ tabindex="-1"
116
+ >
117
+ <slot>
118
+ <cv-dropdown-item
119
+ v-for="item in items"
120
+ v-bind:key="item"
121
+ :value="item"
122
+ >{{ item }}</cv-dropdown-item
123
+ >
124
+ </slot>
125
+ </ul>
126
+ </div>
127
+ <div v-if="data.isInvalid" :class="`${carbonPrefix}--form-requirement`">
128
+ <slot name="invalid-message">{{ invalidMessage }}</slot>
129
+ </div>
130
+ <div v-else-if="isWarning" :class="`${carbonPrefix}--form-requirement`">
131
+ <slot name="warning-message">{{ warningMessage }}</slot>
132
+ </div>
133
+ <div
134
+ v-else-if="data.isHelper"
135
+ :aria-disabled="disabled"
136
+ :class="[
137
+ `${carbonPrefix}--form__helper-text`,
138
+ { [`${carbonPrefix}--form__helper-text--disabled`]: disabled },
139
+ ]"
140
+ >
141
+ <slot name="helper-text">{{ helperText }}</slot>
142
+ </div>
143
+ </div>
144
+ </div>
145
+ </template>
146
+
147
+ <script setup>
148
+ import { carbonPrefix } from '../../global/settings';
149
+ import { props as propsCvId, useCvId } from '../../use/cvId';
150
+ import { props as propsCvTheme, useIsLight } from '../../use/cvTheme';
151
+ import CvDropdownItem from './CvDropdownItem.vue';
152
+ import ChevronDown from '@carbon/icons-vue/es/chevron--down/16';
153
+ import WarningFilled from '@carbon/icons-vue/es/warning--filled/16';
154
+ import WarningAltFilled from '@carbon/icons-vue/es/warning--alt--filled/16';
155
+ import {
156
+ computed,
157
+ nextTick,
158
+ onMounted,
159
+ onUpdated,
160
+ provide,
161
+ reactive,
162
+ ref,
163
+ useSlots,
164
+ watch,
165
+ } from 'vue';
166
+ import { onClickOutside } from '@vueuse/core';
167
+
168
+ const props = defineProps({
169
+ /**
170
+ * 'aria-label' of the ListBox component.
171
+ */
172
+ ariaLabel: { type: String, default: 'Dropdown' },
173
+ /**
174
+ * Disable the control
175
+ */
176
+ disabled: { type: Boolean, default: false },
177
+ /**
178
+ * Add carbon form classes to the dropdown list
179
+ */
180
+ formItem: { type: Boolean, default: true },
181
+ /**
182
+ * Provide helper text that is used alongside the control label for additional help
183
+ */
184
+ helperText: { type: String, default: undefined },
185
+ /**
186
+ * Not documented in react. Removes `dropdown--show-selected` class from component.
187
+ */
188
+ hideSelected: { type: Boolean, default: false },
189
+ /**
190
+ * Specify whether you want the inline version of this control
191
+ */
192
+ inline: { type: Boolean, default: false },
193
+ /**
194
+ * Message which is displayed if the value is invalid.
195
+ */
196
+ invalidMessage: { type: String, default: undefined },
197
+ /**
198
+ * an array of strings to display as choices.
199
+ */
200
+ items: {
201
+ type: Array,
202
+ validator(arr) {
203
+ if (!Array.isArray(arr)) {
204
+ console.warn('CvDropdown - items must be in array');
205
+ }
206
+ return arr;
207
+ },
208
+ },
209
+ /**
210
+ * Generic label that will be used as the textual representation of what this field is for
211
+ */
212
+ label: String,
213
+ /**
214
+ * Value shown when nothing has been selected
215
+ */
216
+ placeholder: {
217
+ type: String,
218
+ default: 'Choose an option',
219
+ },
220
+ /**
221
+ * Specify the size of the ListBox. Currently, supports either `sm`, `md` or `lg` as an option.
222
+ * @values sm,md,lg
223
+ */
224
+ size: {
225
+ type: String,
226
+ default: 'md',
227
+ validator: val => ['sm', 'md', 'lg'].includes(val),
228
+ },
229
+ /**
230
+ * Specify the direction of the dropdown. Can be either true (top) or (false) bottom.
231
+ */
232
+ up: { type: Boolean, default: false },
233
+ /**
234
+ * Render with a value already selected. Available as `v-model:value`.
235
+ */
236
+ value: String,
237
+ /**
238
+ * Provide the text that is displayed and put the control in warning state
239
+ */
240
+ warningMessage: { type: String, default: undefined },
241
+ /**
242
+ * @deprecated - use v-model:value
243
+ */
244
+ modelValue: {
245
+ type: String,
246
+ validator: val => {
247
+ console.warn(
248
+ `v-model for cv-dropdown is deprecated. Specify "v-model:value" instead [${val}]`
249
+ );
250
+ return true;
251
+ },
252
+ default: undefined,
253
+ },
254
+
255
+ ...propsCvId,
256
+ ...propsCvTheme,
257
+ });
258
+ const uid = useCvId(props, true);
259
+ const isLight = useIsLight(props);
260
+ const dataValue = ref(props.value);
261
+ provide('dropdown-selected', dataValue);
262
+ const focusItem = ref(undefined);
263
+ provide('dropdown-focus', focusItem);
264
+ const dataCaption = ref(undefined);
265
+ provide('dropdown-caption', dataCaption);
266
+ /**
267
+ * List of children values
268
+ * @type {Ref<UnwrapRef<[{value:string}]>>}
269
+ */
270
+ const itemsList = ref([]);
271
+ provide('dropdown-items', itemsList);
272
+ const open = ref(false);
273
+ const data = reactive({
274
+ isHelper: false,
275
+ isInvalid: undefined,
276
+ isWarning: false,
277
+ });
278
+ const slots = useSlots();
279
+ function checkSlots() {
280
+ // NOTE: slots is not reactive so needs to be managed on updated
281
+ data.isInvalid =
282
+ !!(slots['invalid-message'] || props.invalidMessage?.length) || undefined;
283
+ data.isWarning = !!(slots['warning-message'] || props.warningMessage?.length);
284
+ data.isHelper = !!(slots['helper-text'] || props.helperText?.length);
285
+ }
286
+ const isWarning = computed(() => {
287
+ if (data.isInvalid) return false;
288
+ else return !!data.isWarning;
289
+ });
290
+ onMounted(checkSlots);
291
+ onUpdated(checkSlots);
292
+ const emit = defineEmits(['update:value', 'update:modelValue', 'change']);
293
+ watch(
294
+ () => props.value,
295
+ () => {
296
+ dataValue.value = props.value;
297
+ }
298
+ );
299
+ watch(dataValue, () => {
300
+ emit('change', dataValue.value);
301
+ emit('update:value', dataValue.value);
302
+ emit('update:modelValue', dataValue.value);
303
+ });
304
+ watch(open, () => {
305
+ focusItem.value = '';
306
+ });
307
+ const ariaLabeledBy = computed(() => {
308
+ if (props.label) {
309
+ return `${uid}-label ${uid}-value`;
310
+ } else {
311
+ return `${uid}-value`;
312
+ }
313
+ });
314
+ const internalCaption = computed(() => {
315
+ if (dataCaption.value) {
316
+ return dataCaption.value;
317
+ } else {
318
+ return props.placeholder;
319
+ }
320
+ });
321
+
322
+ const wrapperStyleOverride = computed(() => {
323
+ // ensures correct width when used inside tabs component
324
+ return { width: '100%' };
325
+ });
326
+ const el = ref(null);
327
+ function onClickOut() {
328
+ // eslint-disable-next-line no-console
329
+ console.log('onClickOut');
330
+ open.value = false;
331
+ }
332
+ onClickOutside(el, onClickOut);
333
+
334
+ /**
335
+ * Set the focus on one of the items in the dropdown list
336
+ * @param {boolean} up - Direction to move focus
337
+ */
338
+ function doMove(up) {
339
+ // re-query could have changed
340
+ const currentFocusEl = el.value?.querySelector('.cv-dropdown-item :focus');
341
+ const numChildren = itemsList.value.length || 0;
342
+
343
+ const currentFocusValue =
344
+ currentFocusEl?.parentNode?.getAttribute('data-value');
345
+
346
+ const currentFocusIndex = itemsList.value?.findIndex(
347
+ child => child.value === currentFocusValue
348
+ );
349
+
350
+ const direction = up ? -1 : 1;
351
+ let nextFocusIndex = currentFocusIndex + direction;
352
+ if (nextFocusIndex >= numChildren) nextFocusIndex = 0;
353
+ else if (nextFocusIndex < 0) nextFocusIndex = numChildren - 1;
354
+ focusItem.value = itemsList.value[nextFocusIndex]?.value;
355
+ }
356
+ const dropList = ref(null);
357
+ function doFocus() {
358
+ nextTick(() => {
359
+ if (open.value) {
360
+ dropList.value?.focus();
361
+ } else {
362
+ focus();
363
+ }
364
+ });
365
+ }
366
+ function onDown() {
367
+ if (!open.value) {
368
+ open.value = true;
369
+ } else {
370
+ doMove(false);
371
+ }
372
+ }
373
+ function onUp() {
374
+ if (open.value) {
375
+ doMove(true);
376
+ }
377
+ }
378
+ function onEsc() {
379
+ open.value = false;
380
+ doFocus();
381
+ }
382
+ const button = ref(null);
383
+ const listBox = ref(null);
384
+ function onTab(ev) {
385
+ if (open.value) {
386
+ if (button.value === ev.target) {
387
+ // button has focus ensure we are closed
388
+ open.value = false;
389
+ } else if (ev.target === null || listBox.value?.contains(ev.target)) {
390
+ // list has focus, close and return focus to dropdown
391
+ open.value = false;
392
+ doFocus();
393
+ ev.preventDefault();
394
+ }
395
+ }
396
+ }
397
+ function onClick(ev) {
398
+ if (props.disabled) {
399
+ ev.preventDefault();
400
+ } else {
401
+ open.value = !open.value;
402
+ doFocus(); // open or close (Some browsers do not focus on button when clicked)
403
+
404
+ let target = ev.target;
405
+ while (
406
+ !target.classList.contains(`${carbonPrefix}--dropdown-link`) &&
407
+ dropList.value?.contains(target)
408
+ ) {
409
+ target = target.parentNode; // try next one up
410
+ }
411
+
412
+ if (target.classList.contains(`${carbonPrefix}--dropdown-link`)) {
413
+ const targetItemEl = target.parentNode;
414
+ dataValue.value = targetItemEl.getAttribute('data-value');
415
+ }
416
+ }
417
+ }
418
+ </script>
@@ -0,0 +1,86 @@
1
+ <!--
2
+ Carbon dropdown item
3
+
4
+ Attributes:
5
+ value: The value for the item. Optional.
6
+
7
+ Usage:
8
+ See dropdown.vue
9
+
10
+ -->
11
+
12
+ <template>
13
+ <li
14
+ data-option
15
+ :data-value="value"
16
+ :class="[
17
+ `cv-dropdown-item ${carbonPrefix}--dropdown-item`,
18
+ { [`${carbonPrefix}--dropdown--selected`]: dataSelected },
19
+ ]"
20
+ role="menuitem"
21
+ >
22
+ <a
23
+ :aria-checked="dataSelected"
24
+ :class="`${carbonPrefix}--dropdown-link`"
25
+ href="javascript:void(0)"
26
+ ref="link"
27
+ role="menuitemradio"
28
+ tabindex="-1"
29
+ >
30
+ <slot></slot>
31
+ </a>
32
+ </li>
33
+ </template>
34
+
35
+ <script setup>
36
+ import { carbonPrefix } from '../../global/settings';
37
+ import { inject, onBeforeUnmount, onMounted, ref, watch } from 'vue';
38
+ const props = defineProps({
39
+ value: {
40
+ type: String,
41
+ required: true,
42
+ },
43
+ selected: { type: Boolean, default: false },
44
+ });
45
+ const dataSelected = ref(props.selected);
46
+ /**
47
+ * @type {Ref<string>}
48
+ */
49
+ const parentSelected = inject('dropdown-selected');
50
+ /**
51
+ * @type {Ref<string>}
52
+ */
53
+ const parentFocus = inject('dropdown-focus');
54
+ const parentCaption = inject('dropdown-caption');
55
+ watch(
56
+ () => props.selected,
57
+ () => {
58
+ dataSelected.value = props.selected;
59
+ }
60
+ );
61
+ watch(parentSelected, () => {
62
+ dataSelected.value = props.value === parentSelected.value;
63
+ });
64
+ const link = ref(null);
65
+ watch(parentFocus, () => {
66
+ if (props.value === parentFocus.value) link.value?.focus();
67
+ });
68
+ watch(dataSelected, val => {
69
+ if (val) {
70
+ parentSelected.value = props.value;
71
+ parentCaption.value = link.value?.text || props.value;
72
+ }
73
+ });
74
+ const parentList = inject('dropdown-items');
75
+ onMounted(() => {
76
+ dataSelected.value = props.value === parentSelected.value;
77
+ parentList.value?.push({
78
+ value: props.value,
79
+ selected: props.selected,
80
+ });
81
+ });
82
+ onBeforeUnmount(() => {
83
+ const index = parentList.value?.findIndex(item => item.value === props.value);
84
+ if (index > -1) parentList.value?.splice(index, 1);
85
+ });
86
+ </script>
@@ -0,0 +1,17 @@
1
+ <template>
2
+ <div
3
+ disabled
4
+ :class="[
5
+ `${carbonPrefix}--list-box ${carbonPrefix}--dropdown ${carbonPrefix}--skeleton`,
6
+ { [`${carbonPrefix}--list-box--inline`]: inline },
7
+ ]"
8
+ ></div>
9
+ </template>
10
+
11
+ <script setup>
12
+ import { carbonPrefix } from '../../global/settings';
13
+
14
+ defineProps({
15
+ inline: { type: Boolean, default: false },
16
+ });
17
+ </script>
@@ -0,0 +1,5 @@
1
+ import CvDropdown from './CvDropdown.vue';
2
+ import CvDropdownItem from './CvDropdownItem.vue';
3
+ import CvDropdownSkeleton from './CvDropdownSkeleton.vue';
4
+
5
+ export { CvDropdown, CvDropdownItem, CvDropdownSkeleton };
@@ -19,7 +19,7 @@
19
19
  <script setup>
20
20
  import { carbonPrefix } from '../../global/settings';
21
21
 
22
- const props = defineProps({
22
+ defineProps({
23
23
  invalid: Boolean,
24
24
  message: String,
25
25
  noMargin: Boolean,
@@ -0,0 +1,87 @@
1
+ import { Canvas, Meta, Story } from '@storybook/addon-docs';
2
+ import CvInlineLoading from './CvInlineLoading.vue';
3
+ import { sbCompPrefix } from '../../global/storybook-utils';
4
+
5
+ <Meta title={`${sbCompPrefix}/CvInlineLoading`} component={CvInlineLoading} />
6
+
7
+ export const Template = args => ({
8
+ // Components used in your story `template` are defined in the `components` object
9
+ components: {
10
+ CvInlineLoading,
11
+ },
12
+ // The story's `args` need to be mapped into the template through the `setup()` method
13
+ setup() {
14
+ return {
15
+ description: args.description,
16
+ errorText: args.errorText,
17
+ endingText: args.endingText,
18
+ loadingText: args.loadingText,
19
+ loadedText: args.loadedText,
20
+ state: args.state,
21
+ };
22
+ },
23
+ template: args.template,
24
+ });
25
+ const defaultTemplate = `
26
+ <cv-inline-loading
27
+ :description="description"
28
+ :ending-text="endingText"
29
+ :error-text="errorText"
30
+ :loading-text="loadingText"
31
+ :loaded-text="loadedText"
32
+ :state="state" />
33
+ `;
34
+
35
+ # CvInlineLoading
36
+
37
+ Migration notes:
38
+
39
+ - The `active` property is still available but does not actually work. Please use the `state` property instead.
40
+ - The state has two new values to make it easier to transition form `loading` to either `loaded` or `error`.
41
+ Setting `state` to "ending:loaded" or "ending:error" will first set the `ending` state and then, when
42
+ the ending animation completes, the `loaded` or `error` state.
43
+ - The states can be imported like `import { STATES } from "@/components/CvInlineLoading";` and used
44
+ as:
45
+ - `STATES.LOADING`
46
+ - `STATES.ENDING`
47
+ - `STATES.LOADED`
48
+ - `STATES.ERROR`
49
+ - `STATES.ENDING_LOADED`
50
+ - `STATES.ENDING_ERROR`
51
+
52
+ <Canvas>
53
+ <Story
54
+ name="Default"
55
+ parameters={{
56
+ controls: {
57
+ exclude: ['template'],
58
+ },
59
+ docs: { source: { code: defaultTemplate } },
60
+ }}
61
+ args={{
62
+ template: defaultTemplate,
63
+ endingText: 'Jumping to warp 9',
64
+ description: 'Warp engine status',
65
+ errorText: 'Warp drive is damaged',
66
+ loadingText: 'Warp drive coming online...',
67
+ loadedText: 'Warp drive engaged',
68
+ state: 'loading',
69
+ }}
70
+ argTypes={{
71
+ state: {
72
+ control: 'select',
73
+ default: 'loading',
74
+ options: [
75
+ 'loading',
76
+ 'ending',
77
+ 'loaded',
78
+ 'error',
79
+ 'ending:loaded',
80
+ 'ending:error',
81
+ ],
82
+ },
83
+ }}
84
+ >
85
+ {Template.bind({})}
86
+ </Story>
87
+ </Canvas>