@mozaic-ds/vue 1.0.0-beta.8 → 1.0.0-beta.9

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 (64) hide show
  1. package/README.md +1 -1
  2. package/dist/mozaic-vue.css +1 -1
  3. package/dist/mozaic-vue.d.ts +410 -198
  4. package/dist/mozaic-vue.js +1100 -777
  5. package/dist/mozaic-vue.js.map +1 -1
  6. package/dist/mozaic-vue.umd.cjs +1 -1
  7. package/dist/mozaic-vue.umd.cjs.map +1 -1
  8. package/package.json +8 -11
  9. package/src/components/Contributing.mdx +1 -1
  10. package/src/components/GettingStarted.mdx +2 -7
  11. package/src/components/Introduction.mdx +41 -21
  12. package/src/components/Support.mdx +1 -1
  13. package/src/components/breadcrumb/MBreadcrumb.stories.ts +11 -13
  14. package/src/components/breadcrumb/MBreadcrumb.vue +1 -1
  15. package/src/components/button/MButton.stories.ts +1 -8
  16. package/src/components/checkbox/MCheckbox.stories.ts +2 -2
  17. package/src/components/checkboxgroup/MCheckboxGroup.stories.ts +2 -2
  18. package/src/components/divider/MDivider.stories.ts +2 -2
  19. package/src/components/divider/MDivider.vue +2 -2
  20. package/src/components/drawer/MDrawer.spec.ts +100 -0
  21. package/src/components/drawer/MDrawer.stories.ts +128 -0
  22. package/src/components/drawer/MDrawer.vue +140 -0
  23. package/src/components/field/MField.stories.ts +2 -9
  24. package/src/components/fieldgroup/MFieldGroup.stories.ts +2 -9
  25. package/src/components/iconbutton/MIconButton.stories.ts +12 -4
  26. package/src/components/link/MLink.stories.ts +3 -12
  27. package/src/components/loader/MLoader.stories.ts +3 -5
  28. package/src/components/loader/MLoader.vue +1 -0
  29. package/src/components/loadingoverlay/MLoadingOverlay.spec.ts +37 -0
  30. package/src/components/loadingoverlay/MLoadingOverlay.stories.ts +40 -0
  31. package/src/components/loadingoverlay/MLoadingOverlay.vue +28 -0
  32. package/src/components/modal/MModal.spec.ts +103 -0
  33. package/src/components/modal/MModal.stories.ts +127 -0
  34. package/src/components/modal/MModal.vue +131 -0
  35. package/src/components/numberbadge/MNumberBadge.stories.ts +3 -5
  36. package/src/components/overlay/MOverlay.stories.ts +3 -8
  37. package/src/components/pagination/MPagination.stories.ts +3 -3
  38. package/src/components/pagination/MPagination.vue +5 -3
  39. package/src/components/passwordinput/MPasswordInput.stories.ts +2 -2
  40. package/src/components/passwordinput/MPasswordInput.vue +2 -5
  41. package/src/components/pincode/MPincode.spec.ts +126 -0
  42. package/src/components/pincode/MPincode.stories.ts +68 -0
  43. package/src/components/pincode/MPincode.vue +139 -0
  44. package/src/components/quantityselector/MQuantitySelector.stories.ts +2 -2
  45. package/src/components/radio/MRadio.stories.ts +2 -2
  46. package/src/components/radiogroup/MRadioGroup.stories.ts +2 -2
  47. package/src/components/select/MSelect.stories.ts +2 -2
  48. package/src/components/statusbadge/MStatusBadge.stories.ts +1 -1
  49. package/src/components/statusdot/MStatusDot.stories.ts +1 -1
  50. package/src/components/statusnotification/MStatusNotification.spec.ts +12 -8
  51. package/src/components/statusnotification/MStatusNotification.stories.ts +2 -9
  52. package/src/components/statusnotification/MStatusNotification.vue +8 -8
  53. package/src/components/tabs/MTabs.stories.ts +4 -4
  54. package/src/components/tabs/MTabs.vue +2 -2
  55. package/src/components/tabs/Mtabs.spec.ts +56 -61
  56. package/src/components/tag/MTag.stories.ts +2 -2
  57. package/src/components/tag/MTag.vue +1 -4
  58. package/src/components/textarea/MTextArea.stories.ts +2 -2
  59. package/src/components/textinput/MTextInput.stories.ts +2 -9
  60. package/src/components/toggle/MToggle.stories.ts +2 -2
  61. package/src/components/togglegroup/MToggleGroup.stories.ts +2 -2
  62. package/src/components/usingIcons.mdx +5 -13
  63. package/src/components/usingPresets.mdx +12 -9
  64. package/src/main.ts +4 -0
@@ -0,0 +1,131 @@
1
+ <template>
2
+ <MOverlay :is-visible="open" dialogLabel="modalTitle">
3
+ <section
4
+ class="mc-modal"
5
+ :class="classObject"
6
+ role="dialog"
7
+ aria-labelledby="modalTitle"
8
+ :aria-modal="open ? 'true' : 'false'"
9
+ tabindex="-1"
10
+ :aria-hidden="!open"
11
+ v-bind="$attrs"
12
+ @keydown.esc="onClose"
13
+ >
14
+ <div class="mc-modal__dialog" role="document">
15
+ <header class="mc-modal__header">
16
+ <span v-if="$slots.icon" class="mc-modal__icon">
17
+ <slot name="icon" />
18
+ </span>
19
+ <h2 class="mc-modal__title" id="modalTitle">
20
+ {{ title }}
21
+ </h2>
22
+ <MIconButton
23
+ v-if="closable"
24
+ class="mc-modal__close"
25
+ aria-label="Close"
26
+ ghost
27
+ @click="onClose"
28
+ >
29
+ <template #icon>
30
+ <Cross24 aria-hidden="true" />
31
+ </template>
32
+ </MIconButton>
33
+ </header>
34
+ <main class="mc-modal__body">
35
+ <p>{{ description }}</p>
36
+ <slot />
37
+ </main>
38
+ <footer v-if="$slots.footer" class="mc-modal__footer">
39
+ <span class="mc-modal__link">
40
+ <slot name="link" />
41
+ </span>
42
+ <slot name="footer" />
43
+ </footer>
44
+ </div>
45
+ </section>
46
+ </MOverlay>
47
+ </template>
48
+
49
+ <script setup lang="ts">
50
+ import { computed, watch, type VNode } from 'vue';
51
+ import Cross24 from '@mozaic-ds/icons-vue/src/components/Cross24/Cross24.vue';
52
+ import MIconButton from '../iconbutton/MIconButton.vue';
53
+ import MOverlay from '../overlay/MOverlay.vue';
54
+ /**
55
+ * A modal is a dialog window that appears on top of the main content, requiring user interaction before returning to the main interface. It is used to focus attention on a specific task, provide important information, or request confirmation for an action. Modals typically include a title, description, and primary/secondary actions and should be used for single, focused tasks to avoid disrupting the user experience.
56
+ */
57
+ const props = withDefaults(
58
+ defineProps<{
59
+ /**
60
+ * if `true`, display the modal.
61
+ */
62
+ open?: boolean;
63
+ /**
64
+ * Title of the modal
65
+ */
66
+ title: string;
67
+ /**
68
+ * Description of the modal
69
+ */
70
+ description?: string;
71
+ /**
72
+ * if `true`, display the close button.
73
+ */
74
+ closable?: boolean;
75
+ }>(),
76
+ {
77
+ closable: true,
78
+ },
79
+ );
80
+
81
+ defineSlots<{
82
+ /**
83
+ * Use this slot to insert an icon next to the title of the modal
84
+ */
85
+ icon?: VNode;
86
+ /**
87
+ * Use this slot to insert the content of the modal
88
+ */
89
+ default?: VNode;
90
+ /**
91
+ * Use this slot to insert a link in the footer
92
+ */
93
+ link?: VNode;
94
+ /**
95
+ * Use this slot to insert buttons in the footer
96
+ */
97
+ footer?: VNode;
98
+ }>();
99
+
100
+ const classObject = computed(() => {
101
+ return {
102
+ 'is-open': props.open,
103
+ };
104
+ });
105
+
106
+ watch(
107
+ () => props.open,
108
+ (newValue) => {
109
+ emit('update:open', newValue);
110
+ },
111
+ );
112
+
113
+ const onClose = () => {
114
+ emit('update:open', false);
115
+ };
116
+
117
+ const emit = defineEmits<{
118
+ /**
119
+ * Emits when the checkbox value changes, updating the modelValue prop.
120
+ */
121
+ (on: 'update:open', value: boolean): void;
122
+ }>();
123
+ </script>
124
+
125
+ <style lang="scss" scoped>
126
+ @use '@mozaic-ds/styles/components/modal';
127
+
128
+ .mc-overlay {
129
+ filter: none;
130
+ }
131
+ </style>
@@ -1,4 +1,4 @@
1
- import type { Meta, StoryObj } from '@storybook/vue3';
1
+ import type { Meta, StoryObj } from '@storybook/vue3-vite';
2
2
  import MNumberBadge from './MNumberBadge.vue';
3
3
 
4
4
  const meta: Meta<typeof MNumberBadge> = {
@@ -37,10 +37,8 @@ export const Danger: Story = {
37
37
  };
38
38
 
39
39
  export const Inverse: Story = {
40
- parameters: {
41
- backgrounds: {
42
- default: 'Inverse',
43
- },
40
+ globals: {
41
+ backgrounds: { value: 'inverse' },
44
42
  },
45
43
  args: { appearance: 'inverse' },
46
44
  };
@@ -1,11 +1,13 @@
1
- import type { Meta, StoryObj } from '@storybook/vue3';
1
+ import type { Meta, StoryObj } from '@storybook/vue3-vite';
2
2
  import MOverlay from './MOverlay.vue';
3
3
 
4
4
  const meta: Meta<typeof MOverlay> = {
5
5
  title: 'Overlay/Overlay',
6
6
  component: MOverlay,
7
7
  parameters: {
8
+ layout: 'fullscreen',
8
9
  docs: {
10
+ story: { height: '400px' },
9
11
  description: {
10
12
  component:
11
13
  'An overlay component is a UI element that appears above the main content to display additional information or interactions, often blocking or dimming the background.',
@@ -15,13 +17,6 @@ const meta: Meta<typeof MOverlay> = {
15
17
  args: {
16
18
  isVisible: true,
17
19
  },
18
- argTypes: {
19
- $slots: {
20
- table: {
21
- disable: true,
22
- },
23
- },
24
- },
25
20
  render: (args) => ({
26
21
  components: { MOverlay },
27
22
  setup() {
@@ -1,10 +1,10 @@
1
- import type { Meta, StoryObj } from '@storybook/vue3';
2
- import { action } from '@storybook/addon-actions';
1
+ import type { Meta, StoryObj } from '@storybook/vue3-vite';
2
+ import { action } from 'storybook/actions';
3
3
 
4
4
  import MPagination from './MPagination.vue';
5
5
 
6
6
  const meta: Meta<typeof MPagination> = {
7
- title: 'Navgation/Pagination',
7
+ title: 'Navigation/Pagination',
8
8
  component: MPagination,
9
9
  parameters: {
10
10
  docs: {
@@ -31,7 +31,7 @@
31
31
  </div>
32
32
 
33
33
  <span v-if="compact" class="mc-pagination__label" aria-current="page">
34
- {{ options.find(option => option.value === currentValue)?.text }}
34
+ {{ options.find((option) => option.value === currentValue)?.text }}
35
35
  </span>
36
36
 
37
37
  <MButton
@@ -108,11 +108,13 @@ watch(currentValue, (newVal) => {
108
108
  });
109
109
 
110
110
  const currentIndex = computed(() =>
111
- props.options.findIndex(opt => opt.value === currentValue.value)
111
+ props.options.findIndex((opt) => opt.value === currentValue.value),
112
112
  );
113
113
 
114
114
  const isFirstPage = computed(() => currentIndex.value === 0);
115
- const isLastPage = computed(() => currentIndex.value === props.options.length - 1);
115
+ const isLastPage = computed(
116
+ () => currentIndex.value === props.options.length - 1,
117
+ );
116
118
 
117
119
  const previous = () => {
118
120
  const currentIndex = props.options.findIndex(
@@ -1,5 +1,5 @@
1
- import type { Meta, StoryObj } from '@storybook/vue3';
2
- import { action } from '@storybook/addon-actions';
1
+ import type { Meta, StoryObj } from '@storybook/vue3-vite';
2
+ import { action } from 'storybook/actions';
3
3
 
4
4
  import MPasswordInput from './MPasswordInput.vue';
5
5
 
@@ -16,10 +16,7 @@
16
16
  "
17
17
  />
18
18
  <div v-if="isClearable && modelValue" class="mc-controls-options">
19
- <button
20
- class="mc-controls-options__button"
21
- @click="clearValue"
22
- >
19
+ <button class="mc-controls-options__button" @click="clearValue">
23
20
  <CrossCircleFilled24
24
21
  class="mc-controls-options__icon"
25
22
  aria-hidden="true"
@@ -33,7 +30,7 @@
33
30
  :aria-checked="ariaChecked"
34
31
  :disabled="disabled"
35
32
  @click="toggleVisibility"
36
- size="s"
33
+ size="s"
37
34
  ghost
38
35
  >
39
36
  {{ isVisible ? buttonLabel.hide : buttonLabel.show }}
@@ -0,0 +1,126 @@
1
+ import { describe, it, expect, vi } from 'vitest';
2
+ import { mount } from '@vue/test-utils';
3
+ import MPincode from './MPincode.vue';
4
+
5
+ describe('MPincode component', () => {
6
+ if (typeof ClipboardEvent === 'undefined') {
7
+ global.ClipboardEvent = class ClipboardEvent extends Event {
8
+ clipboardData: DataTransfer;
9
+ constructor(type: string, eventInitDict?: ClipboardEventInit) {
10
+ super(type, eventInitDict);
11
+ this.clipboardData =
12
+ (eventInitDict && eventInitDict.clipboardData) || new DataTransfer();
13
+ }
14
+ // eslint-disable-next-line
15
+ } as any;
16
+ }
17
+
18
+ it('renders correct number of input fields based on length', () => {
19
+ const wrapper = mount(MPincode, {
20
+ props: {
21
+ id: 'otp',
22
+ length: 6,
23
+ modelValue: '',
24
+ },
25
+ });
26
+
27
+ const inputs = wrapper.findAll('input');
28
+ expect(inputs).toHaveLength(6);
29
+ });
30
+
31
+ it('updates modelValue as user types', async () => {
32
+ const wrapper = mount(MPincode, {
33
+ props: {
34
+ id: 'otp',
35
+ length: 4,
36
+ modelValue: '',
37
+ 'onUpdate:modelValue': vi.fn(),
38
+ },
39
+ });
40
+
41
+ const inputs = wrapper.findAll('input');
42
+ await inputs[0].setValue('1');
43
+ await inputs[1].setValue('2');
44
+ await inputs[2].setValue('3');
45
+ await inputs[3].setValue('4');
46
+
47
+ expect(wrapper.emitted('update:modelValue')).toBeTruthy();
48
+ const emitted = wrapper.emitted('update:modelValue');
49
+ const lastEmitted = emitted?.[emitted.length - 1][0];
50
+ expect(lastEmitted).toBe('1234');
51
+ });
52
+
53
+ it('moves focus to next input on input', async () => {
54
+ const wrapper = mount(MPincode, {
55
+ attachTo: document.body, // Needed for focus
56
+ props: {
57
+ id: 'otp',
58
+ length: 4,
59
+ modelValue: '',
60
+ },
61
+ });
62
+
63
+ const inputs = wrapper.findAll('input');
64
+ await inputs[0].setValue('5');
65
+ expect(document.activeElement).toBe(inputs[1].element);
66
+ });
67
+
68
+ it('moves focus to previous input on backspace if current is empty', async () => {
69
+ const wrapper = mount(MPincode, {
70
+ attachTo: document.body,
71
+ props: {
72
+ id: 'otp',
73
+ length: 4,
74
+ modelValue: '',
75
+ },
76
+ });
77
+
78
+ const inputs = wrapper.findAll('input');
79
+ await inputs[0].setValue('5');
80
+ await inputs[1].element.focus();
81
+ const event = new KeyboardEvent('keydown', { key: 'Backspace' });
82
+ inputs[1].element.dispatchEvent(event);
83
+ await wrapper.vm.$nextTick();
84
+
85
+ expect(document.activeElement).toBe(inputs[0].element);
86
+ });
87
+
88
+ it('renders invalid class when isInvalid is true', () => {
89
+ const wrapper = mount(MPincode, {
90
+ props: {
91
+ id: 'otp',
92
+ isInvalid: true,
93
+ },
94
+ });
95
+
96
+ expect(wrapper.classes()).toContain('is-invalid');
97
+ });
98
+
99
+ it('disables inputs when disabled is true', () => {
100
+ const wrapper = mount(MPincode, {
101
+ props: {
102
+ id: 'otp',
103
+ disabled: true,
104
+ },
105
+ });
106
+
107
+ const inputs = wrapper.findAll('input');
108
+ for (const input of inputs) {
109
+ expect(input.attributes('disabled')).toBeDefined();
110
+ }
111
+ });
112
+
113
+ it('makes inputs readonly when readonly is true', () => {
114
+ const wrapper = mount(MPincode, {
115
+ props: {
116
+ id: 'otp',
117
+ readonly: true,
118
+ },
119
+ });
120
+
121
+ const inputs = wrapper.findAll('input');
122
+ for (const input of inputs) {
123
+ expect(input.attributes('readonly')).toBeDefined();
124
+ }
125
+ });
126
+ });
@@ -0,0 +1,68 @@
1
+ import type { Meta, StoryObj } from '@storybook/vue3-vite';
2
+ import { action } from 'storybook/actions';
3
+
4
+ import MPincode from './MPincode.vue';
5
+
6
+ const meta: Meta<typeof MPincode> = {
7
+ title: 'Form Elements/Pincode',
8
+ component: MPincode,
9
+ parameters: {
10
+ docs: {
11
+ description: {
12
+ component:
13
+ 'A pincode input is a specialized input field used to enter short numeric codes, such as verification codes, security PINs, or authentication tokens. It typically separates each digit into individual fields to improve readability and ease of entry. This component is commonly used in two-factor authentication (2FA), password recovery, and secure access flows, ensuring a structured and user-friendly experience.',
14
+ },
15
+ },
16
+ },
17
+ args: {
18
+ id: 'pincodeId',
19
+ ariaLabel: 'enter your code',
20
+ },
21
+ render: (args) => ({
22
+ components: { MPincode },
23
+ setup() {
24
+ const handleUpdate = action('update:modelValue');
25
+
26
+ return { args, handleUpdate };
27
+ },
28
+ template: `
29
+ <MPincode
30
+ v-bind="args"
31
+ @update:modelValue="handleUpdate"
32
+ />
33
+ `,
34
+ }),
35
+ };
36
+ export default meta;
37
+ type Story = StoryObj<typeof MPincode>;
38
+
39
+ export const WithValue: Story = {
40
+ args: {
41
+ id: 'valueId',
42
+ modelValue: '123098',
43
+ },
44
+ };
45
+
46
+ export const Default: Story = {};
47
+
48
+ export const Disabled: Story = {
49
+ args: {
50
+ id: 'disableId',
51
+ disabled: true,
52
+ },
53
+ };
54
+
55
+ export const ReadOnly: Story = {
56
+ args: {
57
+ id: 'readonlyId',
58
+ modelValue: '123098',
59
+ readonly: true,
60
+ },
61
+ };
62
+
63
+ export const Invalid: Story = {
64
+ args: {
65
+ id: 'invalidId',
66
+ isInvalid: true,
67
+ },
68
+ };
@@ -0,0 +1,139 @@
1
+ <template>
2
+ <div class="mc-pincode-input" :class="classObject" @paste="onPaste">
3
+ <input
4
+ v-for="(digit, index) in otp"
5
+ :key="index"
6
+ :id="`pincodeItem${index}`"
7
+ :ref="(el) => setInputRef(el, index)"
8
+ type="text"
9
+ inputmode="numeric"
10
+ maxlength="1"
11
+ pattern="\d*"
12
+ autocomplete="one-time-code"
13
+ :name="name || `pincode-${id}`"
14
+ class="mc-pincode-input__control"
15
+ :disabled="disabled"
16
+ :readonly="readonly"
17
+ :value="digit"
18
+ v-bind="$attrs"
19
+ @input="(e) => onInput(e, index)"
20
+ @keydown.backspace="(e) => onBackspace(e, index)"
21
+ @keydown="(e) => onKeyDown(e, index)"
22
+ />
23
+ </div>
24
+ </template>
25
+
26
+ <script setup lang="ts">
27
+ import { ref, computed, watch, nextTick, type ComponentPublicInstance } from 'vue';
28
+ /**
29
+ * A pincode input is a specialized input field used to enter short numeric codes, such as verification codes, security PINs, or authentication tokens. It typically separates each digit into individual fields to improve readability and ease of entry. This component is commonly used in two-factor authentication (2FA), password recovery, and secure access flows, ensuring a structured and user-friendly experience.
30
+ */
31
+ const props = withDefaults(
32
+ defineProps<{
33
+ /**
34
+ * A unique identifier for the pincode element, used to associate the label with the form element.
35
+ */
36
+ id: string;
37
+ /**
38
+ * The number of input displayed in the pincode element.
39
+ */
40
+ length?: 4 | 5 | 6;
41
+ /**
42
+ * The name attribute for the pincode element, typically used for form submission.
43
+ */
44
+ name?: string;
45
+ /**
46
+ * The current value of the pincode field.
47
+ */
48
+ modelValue?: string | number;
49
+ /**
50
+ * If `true`, applies an invalid state to the pincode.
51
+ */
52
+ isInvalid?: boolean;
53
+ /**
54
+ * If `true`, disables the pincode, making it non-interactive.
55
+ */
56
+ disabled?: boolean;
57
+ /**
58
+ * If `true`, the pincode is read-only (cannot be edited).
59
+ */
60
+ readonly?: boolean;
61
+ }>(),
62
+ {
63
+ length: 6,
64
+ },
65
+ );
66
+
67
+ const classObject = computed(() => {
68
+ return {
69
+ 'is-invalid': props.isInvalid,
70
+ };
71
+ });
72
+
73
+ const emit = defineEmits<{
74
+ (on: 'update:modelValue', value: string): void;
75
+ }>();
76
+
77
+ const otp = ref<string[]>(Array(props.length).fill(''));
78
+ const inputRefs = ref<(HTMLInputElement | null)[]>([]);
79
+
80
+ const setInputRef = (el: Element | ComponentPublicInstance | null, index: number) => {
81
+ inputRefs.value[index] = el as HTMLInputElement | null;
82
+ };
83
+
84
+ watch(
85
+ () => props.modelValue,
86
+ (value) => {
87
+ const str = String(value ?? '');
88
+ otp.value = Array.from({ length: props.length }, (_, i) => str[i] ?? '');
89
+ },
90
+ { immediate: true },
91
+ );
92
+
93
+ const focusInput = (index: number) => {
94
+ nextTick(() => inputRefs.value[index]?.focus());
95
+ };
96
+
97
+ const onInput = (e: Event, index: number) => {
98
+ const val = (e.target as HTMLInputElement).value.replace(/\D/g, '');
99
+ if (val) {
100
+ otp.value[index] = val[0];
101
+ emit('update:modelValue', otp.value.join(''));
102
+ if (index + 1 < props.length) focusInput(index + 1);
103
+ } else {
104
+ otp.value[index] = '';
105
+ emit('update:modelValue', otp.value.join(''));
106
+ }
107
+ };
108
+
109
+ const onKeyDown = (e: KeyboardEvent, index: number) => {
110
+ if (e.key === 'ArrowLeft' && index > 0) {
111
+ focusInput(index - 1);
112
+ } else if (e.key === 'ArrowRight' && index < props.length - 1) {
113
+ focusInput(index + 1);
114
+ } else if (e.key === 'Backspace') {
115
+ onBackspace(e, index);
116
+ }
117
+ };
118
+
119
+ const onBackspace = (e: KeyboardEvent, index: number) => {
120
+ if (otp.value[index] === '' && index > 0) {
121
+ otp.value[index - 1] = '';
122
+ emit('update:modelValue', otp.value.join(''));
123
+ focusInput(index - 1);
124
+ }
125
+ };
126
+
127
+ const onPaste = (e: ClipboardEvent) => {
128
+ e.preventDefault();
129
+ const pasted = e.clipboardData?.getData('text') ?? '';
130
+ const digits = pasted.replace(/\D/g, '').slice(0, props.length).split('');
131
+ otp.value = Array.from({ length: props.length }, (_, i) => digits[i] ?? '');
132
+ emit('update:modelValue', otp.value.join(''));
133
+ focusInput(Math.min(digits.length, props.length - 1));
134
+ };
135
+ </script>
136
+
137
+ <style lang="scss" scoped>
138
+ @use '@mozaic-ds/styles/components/pincode-input';
139
+ </style>
@@ -1,5 +1,5 @@
1
- import type { Meta, StoryObj } from '@storybook/vue3';
2
- import { action } from '@storybook/addon-actions';
1
+ import type { Meta, StoryObj } from '@storybook/vue3-vite';
2
+ import { action } from 'storybook/actions';
3
3
 
4
4
  import MQuantitySelector from './MQuantitySelector.vue';
5
5
 
@@ -1,5 +1,5 @@
1
- import type { Meta, StoryObj } from '@storybook/vue3';
2
- import { action } from '@storybook/addon-actions';
1
+ import type { Meta, StoryObj } from '@storybook/vue3-vite';
2
+ import { action } from 'storybook/actions';
3
3
 
4
4
  import MRadio from './MRadio.vue';
5
5
 
@@ -1,5 +1,5 @@
1
- import type { Meta, StoryObj } from '@storybook/vue3';
2
- import { action } from '@storybook/addon-actions';
1
+ import type { Meta, StoryObj } from '@storybook/vue3-vite';
2
+ import { action } from 'storybook/actions';
3
3
 
4
4
  import MRadioGroup from './MRadioGroup.vue';
5
5
 
@@ -1,5 +1,5 @@
1
- import type { Meta, StoryObj } from '@storybook/vue3';
2
- import { action } from '@storybook/addon-actions';
1
+ import type { Meta, StoryObj } from '@storybook/vue3-vite';
2
+ import { action } from 'storybook/actions';
3
3
 
4
4
  import MSelect from './MSelect.vue';
5
5
 
@@ -1,4 +1,4 @@
1
- import type { Meta, StoryObj } from '@storybook/vue3';
1
+ import type { Meta, StoryObj } from '@storybook/vue3-vite';
2
2
  import MStatusBadge from './MStatusBadge.vue';
3
3
 
4
4
  const meta: Meta<typeof MStatusBadge> = {
@@ -1,4 +1,4 @@
1
- import type { Meta, StoryObj } from '@storybook/vue3';
1
+ import type { Meta, StoryObj } from '@storybook/vue3-vite';
2
2
  import MStatusDot from './MStatusDot.vue';
3
3
 
4
4
  const meta: Meta<typeof MStatusDot> = {