@mozaic-ds/vue 2.15.0 → 2.17.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 (125) hide show
  1. package/dist/mozaic-vue.css +2 -1
  2. package/dist/mozaic-vue.d.ts +1040 -408
  3. package/dist/mozaic-vue.js +17183 -6742
  4. package/dist/mozaic-vue.js.map +1 -1
  5. package/dist/mozaic-vue.umd.cjs +26 -6
  6. package/dist/mozaic-vue.umd.cjs.map +1 -1
  7. package/package.json +11 -5
  8. package/src/components/BrandPresets.mdx +2 -2
  9. package/src/components/ComponentsMapping.mdx +98 -0
  10. package/src/components/accordionlist/MAccordionList.figma.ts +43 -0
  11. package/src/components/accordionlistitem/MAccordionListItem.figma.ts +27 -0
  12. package/src/components/actionbottombar/MActionBottomBar.figma.ts +24 -0
  13. package/src/components/actionlistbox/MActionListbox.figma.ts +30 -0
  14. package/src/components/actionlistbox/MActionListbox.spec.ts +14 -0
  15. package/src/components/actionlistbox/MActionListbox.stories.ts +15 -8
  16. package/src/components/actionlistbox/MActionListbox.vue +13 -1
  17. package/src/components/actionlistbox/README.md +2 -1
  18. package/src/components/avatar/MAvatar.figma.ts +31 -0
  19. package/src/components/breadcrumb/MBreadcrumb.figma.ts +31 -0
  20. package/src/components/builtinmenu/MBuiltInMenu.figma.ts +23 -0
  21. package/src/components/button/MButton.figma.ts +41 -0
  22. package/src/components/button/README.md +2 -0
  23. package/src/components/callout/MCallout.figma.ts +29 -0
  24. package/src/components/carousel/MCarousel.figma.ts +32 -0
  25. package/src/components/checkbox/MCheckbox.figma.ts +45 -0
  26. package/src/components/checkboxgroup/MCheckboxGroup.figma.ts +30 -0
  27. package/src/components/checklistmenu/MCheckListMenu.figma.ts +29 -0
  28. package/src/components/circularprogressbar/MCircularProgressbar.figma.ts +31 -0
  29. package/src/components/combobox/MCombobox.figma.ts +48 -0
  30. package/src/components/combobox/MCombobox.spec.ts +246 -0
  31. package/src/components/combobox/MCombobox.stories.ts +190 -0
  32. package/src/components/combobox/MCombobox.vue +286 -0
  33. package/src/components/combobox/README.md +52 -0
  34. package/src/components/container/MContainer.figma.ts +30 -0
  35. package/src/components/datatable/DataTable.stories.ts +277 -0
  36. package/src/components/datatable/DataTableCells.stories.ts +251 -0
  37. package/src/components/datatable/DataTableEmpty.stories.ts +102 -0
  38. package/src/components/datatable/DataTableExpandable.stories.ts +95 -0
  39. package/src/components/datatable/DataTableNested.stories.ts +96 -0
  40. package/src/components/datatable/DataTableSelectable.stories.ts +124 -0
  41. package/src/components/datatable/DataTableSortable.stories.ts +164 -0
  42. package/src/components/datatable/MDataTable.types.ts +54 -0
  43. package/src/components/datatable/assets/styles.scss +10 -0
  44. package/src/components/datatable/datatable.mdx +62 -0
  45. package/src/components/datatable/tools/data.js +8 -0
  46. package/src/components/datatable/tools/data.json +2018 -0
  47. package/src/components/datatable/utils.js +19 -0
  48. package/src/components/datepicker/MDatepicker.figma.ts +20 -0
  49. package/src/components/divider/MDivider.figma.ts +30 -0
  50. package/src/components/drawer/MDrawer.figma.ts +37 -0
  51. package/src/components/drawer/README.md +1 -1
  52. package/src/components/field/MField.figma.ts +30 -0
  53. package/src/components/field/MField.stories.ts +105 -0
  54. package/src/components/fileuploader/MFileUploader.figma.ts +23 -0
  55. package/src/components/fileuploaderitem/MFileUploaderItem.figma.ts +27 -0
  56. package/src/components/flag/MFlag.figma.ts +26 -0
  57. package/src/components/iconbutton/MIconButton.figma.ts +54 -0
  58. package/src/components/kpiitem/MKpiItem.figma.ts +33 -0
  59. package/src/components/linearprogressbarbuffer/MLinearProgressbarBuffer.figma.ts +31 -0
  60. package/src/components/linearprogressbarpercentage/MLinearProgressbarPercentage.figma.ts +26 -0
  61. package/src/components/link/MLink.figma.ts +32 -0
  62. package/src/components/loader/MLoader.figma.ts +30 -0
  63. package/src/components/loadingoverlay/MLoadingOverlay.figma.ts +18 -0
  64. package/src/components/modal/MModal.figma.ts +27 -0
  65. package/src/components/navigationindicator/MNavigationIndicator.figma.ts +24 -0
  66. package/src/components/numberbadge/MNumberBadge.figma.ts +31 -0
  67. package/src/components/optionListbox/MOptionListbox.figma.ts +36 -0
  68. package/src/components/optionListbox/MOptionListbox.spec.ts +527 -0
  69. package/src/components/optionListbox/MOptionListbox.vue +470 -0
  70. package/src/components/optionListbox/README.md +63 -0
  71. package/src/components/overlay/MOverlay.figma.ts +20 -0
  72. package/src/components/pageheader/MPageHeader.figma.ts +21 -0
  73. package/src/components/pagination/MPagination.figma.ts +34 -0
  74. package/src/components/passwordinput/MPasswordInput.figma.ts +30 -0
  75. package/src/components/phonenumber/MPhoneNumber.figma.ts +47 -0
  76. package/src/components/pincode/MPincode.figma.ts +41 -0
  77. package/src/components/pincode/MPincode.spec.ts +1 -4
  78. package/src/components/pincode/MPincode.vue +11 -15
  79. package/src/components/popover/MPopover.figma.ts +42 -0
  80. package/src/components/quantityselector/MQuantitySelector.figma.ts +50 -0
  81. package/src/components/radio/MRadio.figma.ts +40 -0
  82. package/src/components/radiogroup/MRadioGroup.figma.ts +30 -0
  83. package/src/components/segmentedcontrol/MSegmentedControl.figma.ts +33 -0
  84. package/src/components/select/MSelect.figma.ts +49 -0
  85. package/src/components/sidebar/MSidebar.figma.ts +28 -0
  86. package/src/components/sidebarexpandableitem/MSidebarExpandableItem.figma.ts +19 -0
  87. package/src/components/sidebarfooter/MSidebarFooter.figma.ts +21 -0
  88. package/src/components/sidebarheader/MSidebarHeader.figma.ts +18 -0
  89. package/src/components/sidebarnavitem/MSidebarNavItem.figma.ts +23 -0
  90. package/src/components/sidebarshortcutitem/MSidebarShortcutItem.figma.ts +20 -0
  91. package/src/components/starrating/MStarRating.figma.ts +35 -0
  92. package/src/components/statusbadge/MStatusBadge.figma.ts +27 -0
  93. package/src/components/statusdot/MStatusDot.figma.ts +31 -0
  94. package/src/components/statusmessage/MStatusMessage.figma.ts +28 -0
  95. package/src/components/statusmessage/MStatusMessage.spec.ts +15 -0
  96. package/src/components/statusmessage/MStatusMessage.stories.ts +4 -0
  97. package/src/components/statusmessage/MStatusMessage.vue +7 -0
  98. package/src/components/statusmessage/README.md +2 -0
  99. package/src/components/statusnotification/MStatusNotification.figma.ts +29 -0
  100. package/src/components/stepperbottombar/MStepperBottomBar.figma.ts +20 -0
  101. package/src/components/steppercompact/MStepperCompact.figma.ts +21 -0
  102. package/src/components/stepperinline/MStepperInline.figma.ts +23 -0
  103. package/src/components/stepperstacked/MStepperStacked.figma.ts +23 -0
  104. package/src/components/stepperstacked/MStepperStacked.spec.ts +162 -0
  105. package/src/components/stepperstacked/MStepperStacked.stories.ts +57 -0
  106. package/src/components/stepperstacked/MStepperStacked.vue +106 -0
  107. package/src/components/stepperstacked/README.md +15 -0
  108. package/src/components/tabs/MTabs.figma.ts +33 -0
  109. package/src/components/tag/MTag.figma.ts +26 -0
  110. package/src/components/tag/MTag.stories.ts +13 -3
  111. package/src/components/tag/MTag.vue +11 -1
  112. package/src/components/tag/README.md +6 -0
  113. package/src/components/textarea/MTextArea.figma.ts +28 -0
  114. package/src/components/textinput/MTextInput.figma.ts +51 -0
  115. package/src/components/textinput/MTextInput.vue +13 -1
  116. package/src/components/textinput/README.md +15 -1
  117. package/src/components/tile/MTile.figma.ts +31 -0
  118. package/src/components/tileclickable/MTileClickable.figma.ts +31 -0
  119. package/src/components/tileexpandable/MTileExpandable.figma.ts +31 -0
  120. package/src/components/tileselectable/MTileSelectable.figma.ts +29 -0
  121. package/src/components/toaster/MToaster.figma.ts +25 -0
  122. package/src/components/toggle/MToggle.figma.ts +39 -0
  123. package/src/components/togglegroup/MToggleGroup.figma.ts +30 -0
  124. package/src/components/tooltip/MTooltip.figma.ts +29 -0
  125. package/src/main.ts +1 -0
@@ -0,0 +1,470 @@
1
+ <template>
2
+ <div
3
+ ref="listboxEl"
4
+ class="mc-option-listbox mc-listbox__content mc-combobox__listbox"
5
+ >
6
+ <template v-if="search">
7
+ <div class="mc-option-listbox__search">
8
+ <MTextInput
9
+ ref="textInput"
10
+ v-model="searchText"
11
+ role="combobox"
12
+ :id="`search-${id}`"
13
+ size="s"
14
+ :placeholder="searchPlaceholder"
15
+ autocomplete="off"
16
+ :aria-expanded="open"
17
+ :aria-controls="`listbox-${id}`"
18
+ aria-autocomplete="list"
19
+ :aria-activedescendant="activeDescendantId"
20
+ @input="updateFilteredResults"
21
+ @keydown="handleKeydown"
22
+ >
23
+ <template #icon>
24
+ <Search24 />
25
+ </template>
26
+ </MTextInput>
27
+ </div>
28
+
29
+ <hr class="mc-option-listbox__separator" />
30
+ </template>
31
+
32
+ <template v-if="multiple && actions">
33
+ <div class="mc-option-listbox__actions">
34
+ <MButton appearance="accent" ghost size="s" @click="selectAll">
35
+ {{ selectLabel }}
36
+ </MButton>
37
+ <MButton appearance="standard" ghost size="s" @click="clearSelection">
38
+ {{ clearLabel }}
39
+ </MButton>
40
+ </div>
41
+ <hr class="mc-option-listbox__separator" />
42
+ </template>
43
+
44
+ <ul
45
+ class="mc-option-listbox__list"
46
+ role="listbox"
47
+ :id="`listbox-${id}`"
48
+ :tabindex="-1"
49
+ aria-label="Suggestions"
50
+ :aria-multiselectable="multiple"
51
+ >
52
+ <li
53
+ v-for="(item, index) in filteredResults"
54
+ :key="index"
55
+ :id="`option-${id}-${index}`"
56
+ :class="{
57
+ 'mc-option-listbox__item': true,
58
+ 'mc-option-listbox__item--section': item.type === 'section',
59
+ 'mc-option-listbox__item--readonly': readonly,
60
+ 'mc-option-listbox__item--disabled': item.disabled,
61
+ 'mc-option-listbox__item--selectable': isSelectable(item),
62
+ 'mc-option-listbox__item--active': activeIndex === index,
63
+ 'mc-option-listbox__item--selected':
64
+ item.type === 'section'
65
+ ? isSectionSelected(item) || isIndeterminate(item)
66
+ : isOptionSelected(item),
67
+ }"
68
+ v-bind="
69
+ item.type === 'section' && !checkableSections
70
+ ? {
71
+ role: 'presentation',
72
+ }
73
+ : {
74
+ role: 'option',
75
+ ['aria-disabled']: item.disabled,
76
+ ['aria-selected']: isOptionSelected(item),
77
+ onClick: () =>
78
+ item.type === 'section'
79
+ ? toggleSection(item)
80
+ : toggleValue(item),
81
+ }
82
+ "
83
+ >
84
+ <div class="mc-option-listbox__label">
85
+ <slot name="item" v-bind="{ item }">
86
+ <div class="mc-option-listbox__content">
87
+ <span
88
+ :class="
89
+ item.type === 'section'
90
+ ? 'mc-option-listbox__section-title'
91
+ : 'mc-option-listbox__text'
92
+ "
93
+ >
94
+ {{ item.label }}
95
+ </span>
96
+
97
+ <span v-if="item.content" class="mc-option-listbox__additional">
98
+ {{ item.content }}
99
+ </span>
100
+ </div>
101
+ </slot>
102
+
103
+ <div class="mc-option-listbox__spacer"></div>
104
+
105
+ <template v-if="isSelectable(item)">
106
+ <span
107
+ v-if="item.type === 'section'"
108
+ class="mc-option-listbox__checkbox"
109
+ >
110
+ <component :is="isIndeterminate(item) ? Less20 : Check20" />
111
+ </span>
112
+
113
+ <template v-else>
114
+ <span v-if="multiple" class="mc-option-listbox__checkbox">
115
+ <Check20 />
116
+ </span>
117
+
118
+ <CheckCircleFilled24
119
+ v-else
120
+ class="mc-option-listbox__selection-icon"
121
+ />
122
+ </template>
123
+ </template>
124
+ </div>
125
+ </li>
126
+ </ul>
127
+ </div>
128
+ </template>
129
+
130
+ <script setup lang="ts">
131
+ import { computed, ref, useTemplateRef, watch, type VNode } from 'vue';
132
+ import MButton from '../button/MButton.vue';
133
+ import MTextInput from '../textinput/MTextInput.vue';
134
+ import {
135
+ CheckCircleFilled24,
136
+ Search24,
137
+ Less20,
138
+ Check20,
139
+ } from '@mozaic-ds/icons-vue';
140
+ import { debounce } from 'lodash';
141
+
142
+ /**
143
+ * An Option Listbox is a customizable, accessible listbox component designed to power dropdowns and comboboxes with advanced selection capabilities. It supports single or multiple selection, optional search, grouped options with section headers, and full keyboard navigation.
144
+ */
145
+ export type ListboxOption = {
146
+ label: string;
147
+ content?: string;
148
+ value?: string | number;
149
+ disabled?: boolean;
150
+ type?: 'option' | 'section';
151
+ };
152
+
153
+ const props = withDefaults(
154
+ defineProps<{
155
+ /**
156
+ * The current selected value(s) of the listbox.
157
+ */
158
+ modelValue: string | number | null | (string | number)[];
159
+ /**
160
+ * Unique identifier for the listbox.
161
+ */
162
+ id: string;
163
+ /**
164
+ * Whether the listbox is open.
165
+ */
166
+ open?: boolean;
167
+ /**
168
+ * Enable multiple selection.
169
+ */
170
+ multiple?: boolean;
171
+ /**
172
+ * Make the listbox read-only.
173
+ */
174
+ readonly?: boolean;
175
+ /**
176
+ * Show a search input above the options.
177
+ */
178
+ search?: boolean;
179
+ /**
180
+ * Show select all / clear buttons when multiple.
181
+ */
182
+ actions?: boolean;
183
+ /**
184
+ * Enable checkable section headers.
185
+ */
186
+ checkableSections?: boolean;
187
+ /**
188
+ * Placeholder text for the search input.
189
+ */
190
+ searchPlaceholder?: string;
191
+ /**
192
+ * Label for the "Select all" button.
193
+ */
194
+ selectLabel?: string;
195
+ /**
196
+ * Label for the "Clear selection" button.
197
+ */
198
+ clearLabel?: string;
199
+ /**
200
+ * Array of options and sections to display in the listbox.
201
+ */
202
+ options: Array<ListboxOption>;
203
+ }>(),
204
+ {
205
+ searchPlaceholder: 'Find an option...',
206
+ selectLabel: 'Select all',
207
+ clearLabel: 'Clear',
208
+ },
209
+ );
210
+
211
+ const emit = defineEmits<{
212
+ /**
213
+ * Emits when the selected value changes.
214
+ */
215
+ (
216
+ on: 'update:modelValue',
217
+ value: string | number | null | (string | number)[],
218
+ ): void;
219
+ /**
220
+ * Emits when the listbox should open.
221
+ */
222
+ (on: 'open'): void;
223
+ /**
224
+ * Emits when the listbox should close.
225
+ */
226
+ (on: 'close'): void;
227
+ }>();
228
+
229
+ defineSlots<{
230
+ /**
231
+ * Use this slot to customize the content of each item.
232
+ */
233
+ item(props: { item: ListboxOption }): VNode;
234
+ }>();
235
+
236
+ const listboxEl = useTemplateRef('listboxEl');
237
+ const textInput = useTemplateRef('textInput');
238
+
239
+ const activeIndex = ref<number>(-1);
240
+
241
+ const searchText = ref('');
242
+
243
+ const filteredResults = ref<ListboxOption[]>(props.options);
244
+
245
+ const selection = computed({
246
+ get() {
247
+ return props.modelValue;
248
+ },
249
+ set(value: string | number | null | (string | number)[]) {
250
+ emit('update:modelValue', value);
251
+ },
252
+ });
253
+
254
+ const activeDescendantId = computed(() => {
255
+ return activeIndex.value >= 0
256
+ ? `option-${props.id}-${activeIndex.value}`
257
+ : undefined;
258
+ });
259
+
260
+ const updateFilteredResults = debounce(() => {
261
+ const search = searchText.value.toLowerCase().trim();
262
+
263
+ if (!search) {
264
+ filteredResults.value = props.options;
265
+ return;
266
+ }
267
+
268
+ filteredResults.value = props.options.filter((option) =>
269
+ option.label.toLowerCase().includes(search),
270
+ );
271
+
272
+ activeIndex.value = filteredResults.value.length ? 0 : -1;
273
+ }, 200);
274
+
275
+ const sectionMap = computed(() => {
276
+ const map = new Map<string, ListboxOption[]>();
277
+ let currentSection: ListboxOption | null = null;
278
+
279
+ props.options.forEach((option) => {
280
+ if (option.type === 'section') {
281
+ currentSection = option;
282
+ map.set(currentSection?.value?.toString() || currentSection.label, []);
283
+ } else if (currentSection) {
284
+ map
285
+ .get(currentSection?.value?.toString() || currentSection.label)!
286
+ .push(option);
287
+ }
288
+ });
289
+
290
+ return map;
291
+ });
292
+
293
+ function toggleSection(item: ListboxOption) {
294
+ if (!props.checkableSections || !props.multiple) return;
295
+
296
+ const sectionItems =
297
+ sectionMap.value.get(item.value?.toString() || item.label) || [];
298
+ const selectedItems = selection.value as (string | number)[];
299
+
300
+ if (isSectionSelected(item)) {
301
+ selection.value = selectedItems.filter(
302
+ (opt) => !sectionItems.find((item) => item.value === opt),
303
+ );
304
+ } else {
305
+ selection.value = [
306
+ ...selectedItems,
307
+ ...sectionItems
308
+ .filter((opt) => !selectedItems.includes(opt.value!))
309
+ .map((item) => item.value!),
310
+ ];
311
+ }
312
+ }
313
+
314
+ function toggleValue(item?: ListboxOption) {
315
+ if (!item || !isSelectable(item)) return;
316
+
317
+ if (Array.isArray(selection.value)) {
318
+ if (isOptionSelected(item)) {
319
+ selection.value = (selection.value as (string | number)[]).filter(
320
+ (el) => el !== item.value,
321
+ );
322
+ } else {
323
+ selection.value = [...selection.value, item.value!];
324
+ }
325
+ } else {
326
+ selection.value = isOptionSelected(item) ? null : item.value!;
327
+ }
328
+ }
329
+
330
+ function selectAll() {
331
+ selection.value = [
332
+ ...props.options
333
+ .filter(
334
+ (option) =>
335
+ !!option.value && !option.disabled && option.type !== 'section',
336
+ )
337
+ .map((item) => item.value!),
338
+ ];
339
+ }
340
+
341
+ function clearSelection() {
342
+ if (Array.isArray(selection.value)) {
343
+ selection.value = [];
344
+ } else {
345
+ selection.value = null;
346
+ }
347
+ }
348
+
349
+ function isSelectable(item: ListboxOption) {
350
+ return (
351
+ (item.type !== 'section' && !item.disabled) ||
352
+ (item.type === 'section' && props.checkableSections && props.multiple)
353
+ );
354
+ }
355
+
356
+ function isSectionSelected(item: ListboxOption) {
357
+ if (!props.checkableSections || !props.multiple) return false;
358
+
359
+ const sectionItems =
360
+ sectionMap.value.get(item.value?.toString() || item.label) || [];
361
+ const selectedItems = selection.value as (string | number)[];
362
+
363
+ return sectionItems.every((opt) => selectedItems.includes(opt.value!));
364
+ }
365
+
366
+ function isOptionSelected(item: ListboxOption) {
367
+ if (!item.value) return false;
368
+
369
+ if (Array.isArray(selection.value)) {
370
+ return (selection.value as (string | number)[])?.includes(item.value!);
371
+ } else {
372
+ return item.value === selection.value;
373
+ }
374
+ }
375
+
376
+ function isIndeterminate(item: ListboxOption) {
377
+ const section = sectionMap.value.get(item.value?.toString() || item.label);
378
+ return (
379
+ section?.some((option) => isOptionSelected(option)) &&
380
+ !section?.every((option) => isOptionSelected(option))
381
+ );
382
+ }
383
+
384
+ function moveActive(delta: number) {
385
+ if (!props.open || filteredResults.value.length === 0) return;
386
+
387
+ let nextIndex = activeIndex.value + delta;
388
+
389
+ if (nextIndex < 0) nextIndex = filteredResults.value.length - 1;
390
+ if (nextIndex >= filteredResults.value.length) nextIndex = 0;
391
+
392
+ while (!isSelectable(filteredResults.value[nextIndex])) {
393
+ nextIndex += delta > 0 ? 1 : -1;
394
+ if (nextIndex < 0) nextIndex = filteredResults.value.length - 1;
395
+ if (nextIndex >= filteredResults.value.length) nextIndex = 0;
396
+ }
397
+
398
+ activeIndex.value = nextIndex;
399
+ }
400
+
401
+ function selectActive() {
402
+ const item = filteredResults.value[activeIndex.value];
403
+ if (!item || !isSelectable(item)) return;
404
+
405
+ if (item.type === 'section') {
406
+ toggleSection(item);
407
+ } else {
408
+ toggleValue(item);
409
+ }
410
+ }
411
+
412
+ function handleKeydown(event: KeyboardEvent) {
413
+ switch (event.key) {
414
+ case 'ArrowDown':
415
+ event.preventDefault();
416
+ if (!props.open) {
417
+ emit('open');
418
+ activeIndex.value = 0;
419
+ } else {
420
+ moveActive(1);
421
+ }
422
+ break;
423
+ case 'ArrowUp':
424
+ event.preventDefault();
425
+ if (!props.open) {
426
+ emit('open');
427
+ activeIndex.value = filteredResults.value.length - 1;
428
+ } else {
429
+ moveActive(-1);
430
+ }
431
+ break;
432
+ case 'Enter':
433
+ event.preventDefault();
434
+ if (!props.open) {
435
+ emit('open');
436
+ activeIndex.value = 0;
437
+ } else {
438
+ selectActive();
439
+ }
440
+ break;
441
+ case 'Escape':
442
+ event.preventDefault();
443
+ emit('close');
444
+ break;
445
+ }
446
+ }
447
+
448
+ watch(
449
+ () => props.open,
450
+ (v) => {
451
+ if (v) {
452
+ setTimeout(() => {
453
+ textInput.value?.focus();
454
+ }, 50);
455
+ }
456
+ },
457
+ );
458
+
459
+ defineExpose({
460
+ handleKeydown,
461
+ toggleValue,
462
+ clearSelection,
463
+ listboxEl,
464
+ activeIndex,
465
+ });
466
+ </script>
467
+
468
+ <style lang="scss">
469
+ @use '@mozaic-ds/styles/components/option-listbox';
470
+ </style>
@@ -0,0 +1,63 @@
1
+ # MOptionListbox
2
+
3
+ An Option Listbox is a customizable, accessible listbox component designed to power dropdowns and comboboxes with advanced selection capabilities. It supports single or multiple selection, optional search, grouped options with section headers, and full keyboard navigation.
4
+
5
+
6
+ ## Props
7
+
8
+ | Name | Description | Type | Default |
9
+ | --- | --- | --- | --- |
10
+ | `modelValue*` | The current selected value(s) of the listbox. | `string` `number` `(string` `number)[]` `null` | - |
11
+ | `id*` | Unique identifier for the listbox. | `string` | - |
12
+ | `open` | Whether the listbox is open. | `boolean` | - |
13
+ | `multiple` | Enable multiple selection. | `boolean` | - |
14
+ | `readonly` | Make the listbox read-only. | `boolean` | - |
15
+ | `search` | Show a search input above the options. | `boolean` | - |
16
+ | `actions` | Show select all / clear buttons when multiple. | `boolean` | - |
17
+ | `checkableSections` | Enable checkable section headers. | `boolean` | - |
18
+ | `searchPlaceholder` | Placeholder text for the search input. | `string` | `"Find an option..."` |
19
+ | `selectLabel` | Label for the "Select all" button. | `string` | `"Select all"` |
20
+ | `clearLabel` | Label for the "Clear selection" button. | `string` | `"Clear"` |
21
+ | `options*` | Array of options and sections to display in the listbox. | `ListboxOption[]` | - |
22
+
23
+ ## Slots
24
+
25
+ | Name | Description |
26
+ | --- | --- |
27
+ | `item` | Use this slot to customize the content of each item. |
28
+
29
+ ## Events
30
+
31
+ | Name | Description | Type |
32
+ | --- | --- | --- |
33
+ | `update:modelValue` | - | `[value: string` `number` `(string` `number)[]` `null]` |
34
+ | `close` | Emits when the listbox should close. | [] |
35
+ | `open` | Emits when the selected value changes. / ( on: 'update:modelValue', value: string | number | null | (string | number)[], ): void; /** Emits when the listbox should open. | [] |
36
+
37
+ ## Dependencies
38
+
39
+ ### Depends on
40
+
41
+ - [MButton](../button)
42
+ - [MTextInput](../textinput)
43
+
44
+ ### Graph
45
+
46
+ ```mermaid
47
+ graph TD;
48
+ MOptionListbox --> MButton
49
+ MOptionListbox --> MTextInput
50
+ style MOptionListbox fill:#008240,stroke:#333,stroke-width:4px
51
+ ```
52
+
53
+ ### Used By
54
+
55
+ - [MCombobox](../combobox)
56
+
57
+ ### Graph
58
+
59
+ ```mermaid
60
+ graph TD;
61
+ MCombobox --> MOptionListbox
62
+ style MOptionListbox fill:#008240,stroke:#333,stroke-width:4px
63
+ ```
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Code Connect mapping for MOverlay
3
+ * Links Figma Overlay (ADS2) to @mozaic-ds/vue
4
+ */
5
+ import figma, { html } from '@figma/code-connect/html';
6
+
7
+ figma.connect(
8
+ 'https://www.figma.com/design/Zyh9RyabNaqkjbuFWP9Aqj/%E2%9C%A8-Components--ADS2---Stable-version-?node-id=6-19511',
9
+ {
10
+ props: {},
11
+ example: () =>
12
+ html`<script setup>
13
+ import { MOverlay } from '@mozaic-ds/vue';
14
+ </script>
15
+
16
+ <MOverlay is-visible dialog-label="Overlay">
17
+ <p>Overlay content</p>
18
+ </MOverlay>`,
19
+ },
20
+ );
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Code Connect mapping for MPageHeader
3
+ * Links Figma Page header (ADS2) to @mozaic-ds/vue
4
+ */
5
+ import figma, { html } from '@figma/code-connect/html';
6
+
7
+ figma.connect(
8
+ 'https://www.figma.com/design/Zyh9RyabNaqkjbuFWP9Aqj/%E2%9C%A8-Components--ADS2---Stable-version-?node-id=16419-62764',
9
+ {
10
+ props: {
11
+ title: figma.string('Title'),
12
+ shadow: figma.boolean('Has shadow'),
13
+ },
14
+ example: ({ title, shadow }) =>
15
+ html`<script setup>
16
+ import { MPageHeader } from '@mozaic-ds/vue';
17
+ </script>
18
+
19
+ <MPageHeader title=${title} shadow=${shadow} />`,
20
+ },
21
+ );
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Code Connect mapping for MPagination
3
+ * Links Figma Pagination (ADS2) to @mozaic-ds/vue
4
+ */
5
+ import figma, { html } from '@figma/code-connect/html';
6
+
7
+ figma.connect(
8
+ 'https://www.figma.com/design/Zyh9RyabNaqkjbuFWP9Aqj/%E2%9C%A8-Components--ADS2---Stable-version-?node-id=6-11558',
9
+ {
10
+ props: {
11
+ compact: figma.enum('Compact mode', {
12
+ True: true,
13
+ False: false,
14
+ }),
15
+ },
16
+ example: ({ compact }) =>
17
+ html`<script setup>
18
+ import { MPagination } from '@mozaic-ds/vue';
19
+ </script>
20
+
21
+ <MPagination
22
+ id="pagination-id"
23
+ :model-value="1"
24
+ :compact=${compact}
25
+ :options="[
26
+ { text: 'Page 1 of 99', value: 1 },
27
+ { text: 'Page 2 of 99', value: 2 },
28
+ { text: 'Page 99 of 99', value: 99 },
29
+ ]"
30
+ select-label="Select page"
31
+ aria-label="pagination"
32
+ ></MPagination>`,
33
+ },
34
+ );
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Code Connect mapping for MPasswordInput
3
+ * Links Figma _password input / base to @mozaic-ds/vue
4
+ */
5
+ import figma, { html } from '@figma/code-connect/html';
6
+
7
+ figma.connect(
8
+ 'https://www.figma.com/design/Zyh9RyabNaqkjbuFWP9Aqj/%E2%9C%A8-Components--ADS2---Stable-version-?node-id=6-29957',
9
+ {
10
+ props: {
11
+ isInvalid: figma.enum('Is invalid', {
12
+ True: true,
13
+ False: false,
14
+ }),
15
+ isClearable: figma.boolean('Is clearable'),
16
+ },
17
+ example: ({ isInvalid, isClearable }) =>
18
+ html`<script setup>
19
+ import { MPasswordInput } from '@mozaic-ds/vue';
20
+ </script>
21
+
22
+ <MPasswordInput
23
+ id="password-input-id"
24
+ :is-invalid=${isInvalid}
25
+ :is-clearable=${isClearable}
26
+ placeholder="Enter your password"
27
+ model-value=""
28
+ ></MPasswordInput>`,
29
+ },
30
+ );
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Code Connect mapping for MPhoneNumber
3
+ * Links Figma _phone number input / base to @mozaic-ds/vue
4
+ */
5
+ import figma, { html } from '@figma/code-connect/html';
6
+
7
+ figma.connect(
8
+ 'https://www.figma.com/design/Zyh9RyabNaqkjbuFWP9Aqj/%E2%9C%A8-Components--ADS2---Stable-version-?node-id=5022-21080',
9
+ {
10
+ props: {
11
+ size: figma.enum('Size', {
12
+ S: 's',
13
+ 'M (default)': 'm',
14
+ }),
15
+ disabled: figma.enum('State', {
16
+ Disabled: true,
17
+ Default: false,
18
+ Hovered: false,
19
+ Focused: false,
20
+ 'Read-only': false,
21
+ }),
22
+ readonly: figma.enum('State', {
23
+ 'Read-only': true,
24
+ Default: false,
25
+ Hovered: false,
26
+ Focused: false,
27
+ Disabled: false,
28
+ }),
29
+ isInvalid: figma.enum('Is invalid', {
30
+ True: true,
31
+ False: false,
32
+ }),
33
+ },
34
+ example: ({ size, disabled, readonly, isInvalid }) =>
35
+ html`<script setup>
36
+ import { MPhoneNumber } from '@mozaic-ds/vue';
37
+ </script>
38
+
39
+ <MPhoneNumber
40
+ id="phone-number-id"
41
+ size=${size}
42
+ disabled=${disabled}
43
+ readonly=${readonly}
44
+ :is-invalid=${isInvalid}
45
+ ></MPhoneNumber>`,
46
+ },
47
+ );