@destyler/combobox 0.0.5 → 0.0.7-beta.1

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.
@@ -1,1064 +0,0 @@
1
- import { defineComponent, h, mergeProps, toRefs, ref, watch, computed, nextTick, onMounted, withDirectives, withKeys } from 'vue';
2
- import { primitiveProps, Primitive } from '@destyler/primitive';
3
- import { useForwardExpose, useDirection, useVModel, useFormControl, useBodyScrollLock, useHideOthers, useForwardProps, useForwardPropsEmits, useId, useMutationObserver } from '@destyler/composition';
4
- import { PopperAnchor, PopperRoot, popperContentProps, PopperContent, PopperArrow } from '@destyler/popper';
5
- import { popperArrowProps } from '@destyler/popper/component';
6
- import { createContext, isEqual, handleAndDispatchCustomEvent } from '@destyler/shared';
7
- import { VisuallyHiddenInput } from '@destyler/visually-hidden/component';
8
- import { createCollection } from '@destyler/collection/composition';
9
- import { CollectionSlot, CollectionItem } from '@destyler/collection';
10
- import { dismissableLayerProps, DismissableLayer } from '@destyler/dismissable-layer';
11
- import { dismissableLayerEmits } from '@destyler/dismissable-layer/component';
12
- import { BindOnceDirective } from '@destyler/directives';
13
- import { Presence } from '@destyler/presence';
14
- import { teleportPrimitiveProps, TeleportPrimitive } from '@destyler/teleport';
15
-
16
- const comboboxAnchorProps = {
17
- ...primitiveProps
18
- };
19
- const ComboboxAnchor = defineComponent({
20
- name: "DestylerComboboxAnchor",
21
- props: comboboxAnchorProps,
22
- setup() {
23
- const { forwardRef } = useForwardExpose();
24
- return {
25
- forwardRef
26
- };
27
- },
28
- render() {
29
- return h(PopperAnchor, {
30
- asChild: true
31
- }, () => {
32
- return h(Primitive, mergeProps(this.$attrs, {
33
- ref: (el) => this.forwardRef(el),
34
- as: this.$props.as,
35
- asChild: this.$props.asChild
36
- }), {
37
- default: () => this.$slots.default?.()
38
- });
39
- });
40
- }
41
- });
42
-
43
- const comboboxRootProps = {
44
- ...primitiveProps,
45
- /**
46
- * The controlled value of the Combobox. Can be binded-with with `v-model`.
47
- *
48
- * @default undefined
49
- */
50
- modelValue: {
51
- type: [String, Number, Boolean, Object, Array],
52
- required: false,
53
- default: void 0
54
- },
55
- /**
56
- * The value of the combobox when initially rendered.
57
- * Use when you do not need to control the state of the Combobox
58
- *
59
- * @default undefined
60
- */
61
- defaultValue: {
62
- type: [String, Number, Boolean, Object, Array],
63
- required: false,
64
- default: void 0
65
- },
66
- /**
67
- * The controlled open state of the Combobox. Can be binded-with with `v-model:open`.
68
- *
69
- * @default undefined
70
- */
71
- open: {
72
- type: Boolean,
73
- required: false,
74
- default: void 0
75
- },
76
- /**
77
- * The open state of the combobox when it is initially rendered.
78
- * Use when you do not need to control its open state.
79
- */
80
- defaultOpen: {
81
- type: Boolean,
82
- required: false
83
- },
84
- /**
85
- * The controlled search term of the Combobox.
86
- * Can be binded-with with `v-model:searchTerm`.
87
- */
88
- searchTerm: {
89
- type: String,
90
- required: false
91
- },
92
- /**
93
- * Whether multiple options can be selected or not.
94
- *
95
- * @default false
96
- */
97
- multiple: {
98
- type: Boolean,
99
- required: false,
100
- default: false
101
- },
102
- /**
103
- * When `true`, prevents the user from interacting with Combobox.
104
- *
105
- * @default false
106
- */
107
- disabled: {
108
- type: Boolean,
109
- required: false,
110
- default: false
111
- },
112
- /**
113
- * The name of the Combobox. Submitted with its owning form as part of a name/value pair.
114
- */
115
- name: {
116
- type: String,
117
- required: false
118
- },
119
- /**
120
- * The reading direction of the combobox when applicable.
121
- */
122
- dir: {
123
- type: String,
124
- required: false
125
- },
126
- /**
127
- * The custom filter function for filtering `ComboboxItem`.
128
- */
129
- filterFunction: {
130
- type: Function,
131
- required: false
132
- },
133
- /**
134
- * The display value of input for selected item. Does not work with `multiple`.
135
- */
136
- displayValue: {
137
- type: Function,
138
- required: false
139
- }
140
- };
141
- const comboboxRootEmits = {
142
- /**
143
- * Event handler called when the value changes.
144
- */
145
- "update:modelValue": (_value) => true,
146
- /**
147
- * Event handler called when the open state of the combobox changes.
148
- */
149
- "update:open": (_value) => true,
150
- /**
151
- * Event handler called when the searchTerm of the combobox changes.
152
- */
153
- "update:searchTerm": (_value) => true
154
- };
155
- const [injectComboboxRootContext, provideComboboxRootContext] = createContext("DestylerComboboxRoot");
156
- const ComboboxRoot = defineComponent({
157
- name: "DestylerComboboxRoot",
158
- props: comboboxRootProps,
159
- emits: comboboxRootEmits,
160
- slots: Object,
161
- setup(props, { emit }) {
162
- const { multiple, disabled, dir: propDir } = toRefs(props);
163
- const dir = useDirection(propDir);
164
- const searchTerm = useVModel(props, "searchTerm", emit, {
165
- defaultValue: "",
166
- passive: props.searchTerm === void 0
167
- });
168
- const modelValue = useVModel(props, "modelValue", emit, {
169
- defaultValue: props.defaultValue ?? multiple.value ? [] : void 0,
170
- passive: props.modelValue === void 0,
171
- deep: true
172
- });
173
- const open = useVModel(props, "open", emit, {
174
- defaultValue: props.defaultOpen,
175
- passive: props.open === void 0
176
- });
177
- const selectedValue = ref();
178
- const inputElement = ref();
179
- const contentElement = ref();
180
- const { forwardRef, currentElement: parentElement } = useForwardExpose();
181
- const { getItems, reactiveItems, itemMapSize } = createCollection("data-destyler-combobox-item");
182
- const isUserInputted = ref(false);
183
- async function onOpenChange(val) {
184
- open.value = val;
185
- await nextTick();
186
- if (val) {
187
- if (modelValue.value) {
188
- if (Array.isArray(modelValue.value) && multiple.value)
189
- selectedValue.value = getItems().find((i) => i.ref?.dataset?.state === "checked")?.value;
190
- else
191
- selectedValue.value = modelValue.value;
192
- }
193
- inputElement.value?.focus();
194
- scrollSelectedValueIntoView();
195
- } else {
196
- isUserInputted.value = false;
197
- resetSearchTerm();
198
- }
199
- }
200
- function onValueChange(val) {
201
- if (Array.isArray(modelValue.value) && multiple.value) {
202
- const index = modelValue.value.findIndex((i) => isEqual(i, val));
203
- index === -1 ? modelValue.value.push(val) : modelValue.value.splice(index, 1);
204
- } else {
205
- modelValue.value = val;
206
- onOpenChange(false);
207
- }
208
- }
209
- const options = ref([]);
210
- watch(() => itemMapSize.value, () => {
211
- options.value = getItems().map((i) => i.value);
212
- }, { immediate: true });
213
- const filteredOptions = computed(() => {
214
- if (isUserInputted.value) {
215
- if (props.filterFunction)
216
- return props.filterFunction(options.value, searchTerm.value);
217
- const optionsWithTypeString = options.value.filter((i) => typeof i === "string");
218
- if (optionsWithTypeString.length)
219
- return optionsWithTypeString.filter((i) => i.toLowerCase().includes(searchTerm.value?.toLowerCase()));
220
- }
221
- return options.value;
222
- });
223
- function resetSearchTerm() {
224
- if (!multiple.value && modelValue.value && !Array.isArray(modelValue.value)) {
225
- if (props.displayValue)
226
- searchTerm.value = props.displayValue(modelValue.value);
227
- else if (typeof modelValue.value !== "object")
228
- searchTerm.value = modelValue.value.toString();
229
- else
230
- searchTerm.value = "";
231
- } else {
232
- searchTerm.value = "";
233
- }
234
- }
235
- const activeIndex = computed(() => filteredOptions.value.findIndex((i) => isEqual(i, selectedValue.value)));
236
- const selectedElement = computed(() => {
237
- return reactiveItems.value.find((i) => i.value === selectedValue.value)?.ref;
238
- });
239
- const stringifiedModelValue = computed(() => JSON.stringify(modelValue.value));
240
- watch(stringifiedModelValue, async () => {
241
- await nextTick();
242
- await nextTick();
243
- resetSearchTerm();
244
- }, { immediate: true });
245
- watch(() => filteredOptions.value.length, async (length) => {
246
- await nextTick();
247
- await nextTick();
248
- if (length && activeIndex.value === -1)
249
- selectedValue.value = filteredOptions.value[0];
250
- });
251
- const isFormControl = useFormControl(parentElement);
252
- function scrollSelectedValueIntoView() {
253
- if (selectedElement.value instanceof Element)
254
- selectedElement.value.scrollIntoView({ block: "nearest" });
255
- }
256
- provideComboboxRootContext({
257
- searchTerm,
258
- modelValue,
259
- onValueChange,
260
- isUserInputted,
261
- multiple,
262
- disabled,
263
- open,
264
- onOpenChange,
265
- filteredOptions,
266
- contentId: "",
267
- inputElement,
268
- onInputElementChange: (val) => inputElement.value = val,
269
- onInputNavigation: async (val) => {
270
- const index = activeIndex.value;
271
- if (index === 0 && val === "up" || index === filteredOptions.value.length - 1 && val === "down")
272
- return;
273
- if (index === -1 && filteredOptions.value.length || val === "home")
274
- selectedValue.value = filteredOptions.value[0];
275
- else if (val === "end")
276
- selectedValue.value = filteredOptions.value[filteredOptions.value.length - 1];
277
- else
278
- selectedValue.value = filteredOptions.value[val === "up" ? index - 1 : index + 1];
279
- scrollSelectedValueIntoView();
280
- },
281
- onInputEnter: async () => {
282
- if (filteredOptions.value.length && selectedValue.value && selectedElement.value instanceof Element)
283
- selectedElement.value?.click();
284
- },
285
- selectedValue,
286
- onSelectedValueChange: (val) => selectedValue.value = val,
287
- parentElement,
288
- contentElement,
289
- onContentElementChange: (val) => contentElement.value = val
290
- });
291
- return {
292
- forwardRef,
293
- isFormControl,
294
- open,
295
- modelValue,
296
- dir
297
- };
298
- },
299
- render() {
300
- return h(PopperRoot, null, {
301
- default: () => {
302
- return h(Primitive, mergeProps(this.$attrs, {
303
- ref: (el) => this.forwardRef(el),
304
- style: {
305
- pointerEvents: this.open ? "auto" : void 0
306
- },
307
- as: this.$props.as,
308
- asChild: this.$props.asChild,
309
- dir: this.dir
310
- }), {
311
- default: () => {
312
- return [
313
- this.$slots.default?.({ open: this.open, modelValue: this.modelValue }),
314
- this.isFormControl && this.$props.name ? h(VisuallyHiddenInput, {
315
- name: this.$props.name,
316
- value: this.modelValue
317
- }) : null
318
- ];
319
- }
320
- });
321
- }
322
- });
323
- }
324
- });
325
-
326
- const comboboxContentImplProps = {
327
- ...dismissableLayerProps,
328
- ...popperContentProps,
329
- /**
330
- * The positioning mode to use, <br>
331
- * `inline` is the default and you can control the position using CSS. <br>
332
- * `popper` positions content in the same way as our other primitives, for example `Popover` or `DropdownMenu`.
333
- *
334
- * @default inline
335
- */
336
- position: {
337
- type: String,
338
- required: false,
339
- default: "inline"
340
- },
341
- /**
342
- * The document.body will be lock, and scrolling will be disabled.
343
- */
344
- bodyLock: {
345
- type: Boolean,
346
- required: false
347
- },
348
- /**
349
- * Allow component to be dismissableLayer.
350
- *
351
- * @default true
352
- */
353
- dismissable: {
354
- type: Boolean,
355
- required: false,
356
- default: true
357
- }
358
- };
359
- const comboboxContentImplEmits = {
360
- ...dismissableLayerEmits
361
- };
362
- const [injectComboboxContentContext, provideComboboxContentContext] = createContext("DestylerComboboxContent");
363
- const ComboboxContentImpl = defineComponent({
364
- name: "DestylerComboboxContentImpl",
365
- props: comboboxContentImplProps,
366
- emits: comboboxContentImplEmits,
367
- setup(props) {
368
- const { position } = toRefs(props);
369
- const rootContext = injectComboboxRootContext();
370
- useBodyScrollLock(props.bodyLock);
371
- const { forwardRef, currentElement } = useForwardExpose();
372
- useHideOthers(currentElement);
373
- const pickedProps = computed(() => {
374
- if (props.position === "popper")
375
- return props;
376
- else
377
- return {};
378
- });
379
- const forwardedProps = useForwardProps(pickedProps.value);
380
- function handleLeave() {
381
- rootContext.onSelectedValueChange("");
382
- }
383
- onMounted(() => {
384
- rootContext.onContentElementChange(currentElement.value);
385
- });
386
- const popperStyle = {
387
- "boxSizing": "border-box",
388
- "--destyler-combobox-content-transform-origin": "var(--destyler-popper-transform-origin)",
389
- "--destyler-combobox-content-available-width": "var(--destyler-popper-available-width)",
390
- "--destyler-combobox-content-available-height": "var(--destyler-popper-available-height)",
391
- "--destyler-combobox-trigger-width": "var(--destyler-popper-anchor-width)",
392
- "--destyler-combobox-trigger-height": "var(--destyler-popper-anchor-height)"
393
- };
394
- provideComboboxContentContext({ position });
395
- return {
396
- rootContext,
397
- popperStyle,
398
- forwardedProps,
399
- pickedProps,
400
- forwardRef,
401
- handleLeave
402
- };
403
- },
404
- render() {
405
- return h(CollectionSlot, null, {
406
- default: () => {
407
- return [
408
- this.$props.dismissable ? h(DismissableLayer, {
409
- asChild: true,
410
- disableOutsidePointerEvents: this.$props.disableOutsidePointerEvents,
411
- onDismiss: () => {
412
- this.rootContext.onOpenChange(false);
413
- },
414
- onFocusOutside: (event) => {
415
- if (this.rootContext.parentElement.value?.contains(event.target))
416
- event.preventDefault();
417
- this.$emit("focusOutside", event);
418
- },
419
- onInteractOutside: (event) => {
420
- this.$emit("interactOutside", event);
421
- },
422
- onEscapeKeyDown: (event) => {
423
- this.$emit("escapeKeyDown", event);
424
- },
425
- onPointerDownOutside: (event) => {
426
- if (this.rootContext.parentElement.value?.contains(event.target))
427
- event.preventDefault();
428
- this.$emit("pointerDownOutside", event);
429
- }
430
- }, {
431
- default: () => {
432
- return withDirectives(h(this.$props.position === "popper" ? PopperContent : Primitive, mergeProps(this.$attrs, this.forwardedProps, {
433
- "ref": (el) => this.forwardRef(el),
434
- "role": "listbox",
435
- "data-state": this.rootContext.open.value ? "open" : "closed",
436
- "style": {
437
- display: "flex",
438
- flexDirection: "column",
439
- outline: "none",
440
- ...this.$props.position === "popper" ? this.popperStyle : {}
441
- },
442
- "onPointerleave": () => {
443
- this.handleLeave();
444
- }
445
- }), {
446
- default: () => this.$slots.default?.()
447
- }), [
448
- [BindOnceDirective, { id: this.rootContext.contentId }]
449
- ]);
450
- }
451
- }) : withDirectives(h(this.$props.position === "popper" ? PopperContent : Primitive, mergeProps(this.$attrs, this.pickedProps, {
452
- "ref": (el) => this.forwardRef(el),
453
- "role": "listbox",
454
- "data-state": this.rootContext.open.value ? "open" : "closed",
455
- "style": {
456
- display: "flex",
457
- flexDirection: "column",
458
- outline: "none",
459
- ...this.$props.position === "popper" ? this.popperStyle : {}
460
- },
461
- "onPointerleave": () => {
462
- this.handleLeave();
463
- }
464
- }), {
465
- default: () => this.$slots.default?.()
466
- }), [
467
- [BindOnceDirective, { id: this.rootContext.contentId }]
468
- ])
469
- ];
470
- }
471
- });
472
- }
473
- });
474
-
475
- const comboboxArrowProps = {
476
- ...popperArrowProps
477
- };
478
- const ComboboxArrow = defineComponent({
479
- name: "DestylerComboboxArrow",
480
- props: comboboxArrowProps,
481
- setup() {
482
- useForwardExpose();
483
- const rootContext = injectComboboxRootContext();
484
- const contentContext = injectComboboxContentContext();
485
- return {
486
- rootContext,
487
- contentContext
488
- };
489
- },
490
- render() {
491
- if (this.rootContext.open.value && this.contentContext.position.value === "popper")
492
- return h(PopperArrow, this.$props, () => this.$slots.default?.());
493
- else
494
- return null;
495
- }
496
- });
497
-
498
- const comboboxCancelProps = {
499
- ...primitiveProps,
500
- /**
501
- * @default button
502
- */
503
- as: {
504
- ...primitiveProps.as,
505
- default: "button"
506
- }
507
- };
508
- const ComboboxCancel = defineComponent({
509
- name: "DestylerComboboxCancel",
510
- props: comboboxCancelProps,
511
- setup() {
512
- useForwardExpose();
513
- const rootContext = injectComboboxRootContext();
514
- function handleClick() {
515
- rootContext.searchTerm.value = "";
516
- rootContext.inputElement.value?.focus();
517
- }
518
- return {
519
- rootContext,
520
- handleClick
521
- };
522
- },
523
- render() {
524
- return h(Primitive, mergeProps(this.$props, {
525
- type: this.$props.as === "button" ? "button" : void 0,
526
- tabindex: "-1",
527
- onClick: () => {
528
- this.handleClick();
529
- }
530
- }), () => this.$slots.default?.());
531
- }
532
- });
533
-
534
- const comboboxContentProps = {
535
- ...comboboxContentImplProps,
536
- /**
537
- * Used to force mounting when more control is needed.
538
- * Useful when controlling animation with Vue animation libraries.
539
- */
540
- forceMount: {
541
- type: Boolean,
542
- required: false
543
- }
544
- };
545
- const comboboxContentEmits = {
546
- ...comboboxContentImplEmits
547
- };
548
- const ComboboxContent = defineComponent({
549
- name: "DestylerComboboxContent",
550
- props: comboboxContentProps,
551
- emits: comboboxContentEmits,
552
- setup(props, { emit }) {
553
- const forwarded = useForwardPropsEmits(props, emit);
554
- const { forwardRef } = useForwardExpose();
555
- const rootContext = injectComboboxRootContext();
556
- rootContext.contentId || (rootContext.contentId = useId(void 0, "destyler-combobox-content"));
557
- return {
558
- forwardRef,
559
- forwarded,
560
- rootContext
561
- };
562
- },
563
- render() {
564
- return h(Presence, {
565
- present: this.$props.forceMount || this.rootContext.open.value
566
- }, () => h(ComboboxContentImpl, mergeProps(this.$attrs, this.forwarded, {
567
- ref: (el) => this.forwardRef(el)
568
- }), () => this.$slots.default?.()));
569
- }
570
- });
571
-
572
- const comboboxEmptyProps = {
573
- ...primitiveProps
574
- };
575
- const ComboboxEmpty = defineComponent({
576
- name: "DestylerComboboxEmpty",
577
- props: comboboxEmptyProps,
578
- setup() {
579
- useForwardExpose();
580
- const rootContext = injectComboboxRootContext();
581
- const isEmpty = computed(() => rootContext.filteredOptions.value.length === 0);
582
- return {
583
- rootContext,
584
- isEmpty
585
- };
586
- },
587
- render() {
588
- if (this.isEmpty) {
589
- return h(Primitive, this.$props, {
590
- default: () => this.$slots.default ? this.$slots.default?.() : "No options"
591
- });
592
- }
593
- }
594
- });
595
-
596
- const comboboxGroupProps = {
597
- ...primitiveProps
598
- };
599
- const [injectComboboxGroupContext, provideComboboxGroupContext] = createContext("DestylerComboboxGroup");
600
- const ComboboxGroup = defineComponent({
601
- name: "DestylerComboboxGroup",
602
- props: comboboxGroupProps,
603
- setup() {
604
- const { currentRef, currentElement } = useForwardExpose();
605
- const id = useId(void 0, "destyler-combobox-group");
606
- const rootContext = injectComboboxRootContext();
607
- const hasOptions = ref(false);
608
- function checkCollectionItem() {
609
- if (!currentElement.value)
610
- return;
611
- const collectionItem = currentElement.value.querySelectorAll("[data-destyler-combobox-item]:not([data-hidden])");
612
- hasOptions.value = !!collectionItem.length;
613
- }
614
- useMutationObserver(currentElement, () => {
615
- checkCollectionItem();
616
- }, {
617
- childList: true
618
- });
619
- watch(() => rootContext.searchTerm.value, () => {
620
- nextTick(() => {
621
- checkCollectionItem();
622
- });
623
- }, {
624
- immediate: true
625
- });
626
- provideComboboxGroupContext({
627
- id
628
- });
629
- return {
630
- currentRef,
631
- hasOptions,
632
- id
633
- };
634
- },
635
- render() {
636
- return h(Primitive, mergeProps(this.$props, {
637
- "ref": "currentRef",
638
- "role": "group",
639
- "aria-labelledby": this.id,
640
- ...this.hasOptions ? {} : { style: { display: "none" } }
641
- }), {
642
- default: () => this.$slots.default?.()
643
- });
644
- }
645
- });
646
-
647
- const comboboxInputProps = {
648
- ...primitiveProps,
649
- /**
650
- * @default input
651
- */
652
- as: {
653
- ...primitiveProps.as,
654
- default: "input"
655
- },
656
- /**
657
- * Native input type
658
- *
659
- * @default text
660
- */
661
- type: {
662
- type: String,
663
- required: false,
664
- default: "text"
665
- },
666
- /**
667
- * When `true`, prevents the user from interacting with item
668
- */
669
- disabled: {
670
- type: Boolean,
671
- required: false
672
- },
673
- /**
674
- * Focus on element when mounted.
675
- *
676
- * @default false
677
- */
678
- autoFocus: {
679
- type: Boolean,
680
- required: false
681
- }
682
- };
683
- const ComboboxInput = defineComponent({
684
- name: "DestylerComboboxInput",
685
- props: comboboxInputProps,
686
- setup(props) {
687
- const rootContext = injectComboboxRootContext();
688
- const { forwardRef, currentElement } = useForwardExpose();
689
- onMounted(() => {
690
- const inputEl = currentElement.value.nodeName === "INPUT" ? currentElement.value : currentElement.value.querySelector("input");
691
- if (!inputEl)
692
- return;
693
- rootContext.onInputElementChange(inputEl);
694
- setTimeout(() => {
695
- if (props.autoFocus)
696
- inputEl?.focus();
697
- }, 1);
698
- });
699
- const disabled = computed(() => props.disabled || rootContext.disabled.value || false);
700
- function handleKeyDown(ev) {
701
- if (!rootContext.open.value)
702
- rootContext.onOpenChange(true);
703
- else
704
- rootContext.onInputNavigation(ev.key === "ArrowUp" ? "up" : "down");
705
- }
706
- function handleHomeEnd(ev) {
707
- if (!rootContext.open.value)
708
- return;
709
- rootContext.onInputNavigation(ev.key === "Home" ? "home" : "end");
710
- }
711
- function handleInput(event) {
712
- rootContext.searchTerm.value = event.target?.value;
713
- if (!rootContext.open.value)
714
- rootContext.onOpenChange(true);
715
- rootContext.isUserInputted.value = true;
716
- }
717
- return {
718
- disabled,
719
- rootContext,
720
- forwardRef,
721
- handleInput,
722
- handleKeyDown,
723
- handleHomeEnd
724
- };
725
- },
726
- render() {
727
- return h(Primitive, {
728
- "ref": (el) => this.forwardRef(el),
729
- "as": this.$props.as,
730
- "asChild": this.$props.asChild,
731
- "type": this.$props.type,
732
- "disabled": this.disabled,
733
- "value": this.rootContext.searchTerm.value,
734
- "aria-expanded": this.rootContext.open.value,
735
- "aria-controls": this.rootContext.contentId,
736
- "aria-disabled": this.disabled ?? void 0,
737
- "aria-autocomplete": "list",
738
- "role": "combobox",
739
- "autocomplete": "false",
740
- "onInput": (event) => {
741
- this.handleInput(event);
742
- },
743
- "onKeydown": withKeys((event) => {
744
- switch (event.key) {
745
- case "ArrowUp":
746
- case "ArrowDown":
747
- event.preventDefault();
748
- this.handleKeyDown(event);
749
- break;
750
- case "Home":
751
- case "End":
752
- event.preventDefault();
753
- this.handleHomeEnd(event);
754
- break;
755
- case "Enter":
756
- this.rootContext.onInputEnter();
757
- break;
758
- }
759
- }, ["down", "up", "enter", "home", "end"])
760
- }, {
761
- default: () => this.$slots.default?.()
762
- });
763
- }
764
- });
765
-
766
- const COMBOBOX_SELECT = "combobox.select";
767
- const comboboxItemProps = {
768
- ...primitiveProps,
769
- /**
770
- * The value given as data when submitted with a `name`.
771
- */
772
- value: {
773
- type: [String, Number, Boolean, Object],
774
- required: true
775
- },
776
- /**
777
- * When true, prevents the user from interacting with the `item`.
778
- */
779
- disabled: {
780
- type: Boolean,
781
- required: false
782
- }
783
- };
784
- const comboboxItemEmits = {
785
- /**
786
- * Event handler called when the selecting item. <br>
787
- * It can be prevented by calling `event.preventDefault`.
788
- */
789
- select: (_ev) => true
790
- };
791
- const [injectComboboxItemContext, provideComboboxItemContext] = createContext("DestylerComboboxItem");
792
- const ComboboxItem = defineComponent({
793
- name: "DestylerComboboxItem",
794
- props: comboboxItemProps,
795
- emits: comboboxItemEmits,
796
- setup(props, { emit }) {
797
- const { disabled } = toRefs(props);
798
- const rootContext = injectComboboxRootContext();
799
- injectComboboxGroupContext({ id: "", options: ref([]) });
800
- const { forwardRef } = useForwardExpose();
801
- const isSelected = computed(
802
- () => rootContext.multiple.value && Array.isArray(rootContext.modelValue.value) ? rootContext.modelValue.value?.some((val) => isEqual(val, props.value)) : isEqual(rootContext.modelValue?.value, props.value)
803
- );
804
- const isFocused = computed(() => isEqual(rootContext.selectedValue.value, props.value));
805
- const textId = useId(void 0, "destyler-combobox-item");
806
- const isInOption = computed(() => rootContext.isUserInputted.value ? rootContext.searchTerm.value === "" || !!rootContext.filteredOptions.value.find((i) => isEqual(i, props.value)) : true);
807
- async function handleSelect(ev) {
808
- emit("select", ev);
809
- if (ev?.defaultPrevented)
810
- return;
811
- if (!disabled.value && ev)
812
- rootContext.onValueChange(props.value);
813
- }
814
- function handleSelectCustomEvent(ev) {
815
- if (!ev)
816
- return;
817
- const eventDetail = { originalEvent: ev, value: props.value };
818
- handleAndDispatchCustomEvent(COMBOBOX_SELECT, handleSelect, eventDetail);
819
- }
820
- async function handlePointerMove(event) {
821
- await nextTick();
822
- if (event.defaultPrevented)
823
- return;
824
- rootContext.onSelectedValueChange(props.value);
825
- }
826
- if (props.value === "") {
827
- throw new Error(
828
- "A <DestylerSelectItem /> must have a value prop that is not an empty string. This is because the Select value can be set to an empty string to clear the selection and show the placeholder."
829
- );
830
- }
831
- provideComboboxItemContext({
832
- isSelected
833
- });
834
- return {
835
- forwardRef,
836
- textId,
837
- isFocused,
838
- isSelected,
839
- isInOption,
840
- handleSelectCustomEvent,
841
- handlePointerMove
842
- };
843
- },
844
- render() {
845
- return h(CollectionItem, null, {
846
- default: () => {
847
- return h(Primitive, {
848
- "ref": (el) => this.forwardRef(el),
849
- "role": "option",
850
- "tabindex": "-1",
851
- "aria-labelledby": this.textId,
852
- "data-highlighted": this.isFocused ? "" : void 0,
853
- "aria-selected": this.isSelected,
854
- "data-state": this.isSelected ? "checked" : "unchecked",
855
- "aria-disabled": this.$props.disabled || void 0,
856
- "data-disabled": this.$props.disabled ? "" : void 0,
857
- "as": this.$props.as,
858
- "asChild": this.$props.asChild,
859
- "data-hidden": !this.isInOption ? true : void 0,
860
- "onClick": (event) => {
861
- this.handleSelectCustomEvent(event);
862
- },
863
- "onPointermove": (event) => {
864
- this.handlePointerMove(event);
865
- },
866
- ...this.isInOption ? {} : { style: { display: "none" } }
867
- }, {
868
- default: () => this.$slots.default ? this.$slots.default?.() : this.$props.value
869
- });
870
- }
871
- });
872
- }
873
- });
874
-
875
- const comboboxItemIndicatorProps = {
876
- ...primitiveProps,
877
- /**
878
- * @default span
879
- */
880
- as: {
881
- ...primitiveProps.as,
882
- default: "span"
883
- }
884
- };
885
- const ComboboxItemIndicator = defineComponent({
886
- name: "DestylerComboboxItemIndicator",
887
- props: comboboxItemIndicatorProps,
888
- setup() {
889
- useForwardExpose();
890
- const itemContext = injectComboboxItemContext();
891
- return {
892
- itemContext
893
- };
894
- },
895
- render() {
896
- if (this.itemContext.isSelected.value) {
897
- return h(Primitive, mergeProps(this.$props, {
898
- "aria-hidden": ""
899
- }), {
900
- default: () => this.$slots.default?.()
901
- });
902
- }
903
- }
904
- });
905
-
906
- const comboboxLabelProps = {
907
- ...primitiveProps,
908
- /**
909
- * The id of the element the label is associated with.
910
- */
911
- for: {
912
- type: String,
913
- required: false
914
- }
915
- };
916
- const ComboboxLabel = defineComponent({
917
- name: "DestylerComboboxLabel",
918
- props: comboboxLabelProps,
919
- setup() {
920
- useForwardExpose();
921
- const groupContext = injectComboboxGroupContext({ id: "" });
922
- return {
923
- groupContext
924
- };
925
- },
926
- render() {
927
- return withDirectives(h(Primitive, this.$props, {
928
- default: () => this.$slots.default?.()
929
- }), [
930
- [BindOnceDirective, { id: this.groupContext.id }]
931
- ]);
932
- }
933
- });
934
-
935
- const comboboxPortalProps = {
936
- ...teleportPrimitiveProps
937
- };
938
- const ComboboxPortal = defineComponent({
939
- name: "DestylerComboboxPortal",
940
- props: comboboxPortalProps,
941
- render() {
942
- return h(TeleportPrimitive, this.$props, {
943
- default: () => this.$slots.default?.()
944
- });
945
- }
946
- });
947
-
948
- const comboboxSeparatorProps = {
949
- ...primitiveProps
950
- };
951
- const ComboboxSeparator = defineComponent({
952
- name: "DestylerComboboxSeparator",
953
- props: comboboxSeparatorProps,
954
- setup() {
955
- useForwardExpose();
956
- },
957
- render() {
958
- return h(Primitive, mergeProps(this.$props, {
959
- "aria-hidden": ""
960
- }), () => this.$slots.default?.());
961
- }
962
- });
963
-
964
- const comboboxTriggerProps = {
965
- ...primitiveProps,
966
- /**
967
- * @default button
968
- */
969
- as: {
970
- ...primitiveProps.as,
971
- default: "button"
972
- },
973
- /**
974
- * When `true`, prevents the user from interacting with item.
975
- */
976
- disabled: {
977
- type: Boolean,
978
- required: false
979
- }
980
- };
981
- const ComboboxTrigger = defineComponent({
982
- name: "DestylerComboboxTrigger",
983
- props: comboboxTriggerProps,
984
- setup(props) {
985
- useForwardExpose();
986
- const rootContext = injectComboboxRootContext();
987
- const disabled = computed(() => props.disabled || rootContext.disabled.value || false);
988
- return {
989
- rootContext,
990
- disabled
991
- };
992
- },
993
- render() {
994
- return h(Primitive, mergeProps(this.$props, {
995
- "type": this.$props.as === "button" ? "button" : void 0,
996
- "tabindex": "-1",
997
- "aria-label": "Show popup",
998
- "aria-haspopup": "listbox",
999
- "aria-expanded": this.rootContext.open.value,
1000
- "aria-controls": this.rootContext.contentId,
1001
- "data-state": this.rootContext.open.value ? "open" : "closed",
1002
- "disabled": this.disabled,
1003
- "data-disabled": this.disabled ? "" : void 0,
1004
- "aria-disabled": this.disabled ?? void 0,
1005
- "onClick": () => {
1006
- this.rootContext.onOpenChange(!this.rootContext.open.value);
1007
- }
1008
- }), {
1009
- default: () => this.$slots.default?.()
1010
- });
1011
- }
1012
- });
1013
-
1014
- const comboboxViewportProps = {
1015
- ...primitiveProps,
1016
- /**
1017
- * Will add `nonce` attribute to the style tag which can be used by Content Security Policy.
1018
- */
1019
- nonce: {
1020
- type: String,
1021
- required: false
1022
- }
1023
- };
1024
- const ComboboxViewport = defineComponent({
1025
- name: "DestylerComboboxViewport",
1026
- props: comboboxViewportProps,
1027
- inheritAttrs: false,
1028
- setup() {
1029
- const { forwardRef } = useForwardExpose();
1030
- return {
1031
- forwardRef
1032
- };
1033
- },
1034
- render() {
1035
- return [
1036
- h(Primitive, mergeProps(this.$attrs, this.$props, {
1037
- "ref": (el) => this.forwardRef(el),
1038
- "data-destyler-combobox-viewport": "",
1039
- "role": "presentation",
1040
- "style": {
1041
- position: "relative",
1042
- flex: 1,
1043
- overflow: "auto"
1044
- }
1045
- }), () => this.$slots.default?.()),
1046
- h(Primitive, {
1047
- as: "style",
1048
- nonce: this.$props.nonce
1049
- }, () => `
1050
- /* Hide scrollbars cross-browser and enable momentum scroll for touch devices */
1051
- [data-destyler-combobox-viewport] {
1052
- scrollbar-width:none;
1053
- -ms-overflow-style: none;
1054
- -webkit-overflow-scrolling: touch;
1055
- }
1056
- [data-destyler-combobox-viewport]::-webkit-scrollbar {
1057
- display: none;
1058
- }
1059
- `)
1060
- ];
1061
- }
1062
- });
1063
-
1064
- export { ComboboxAnchor, ComboboxArrow, ComboboxCancel, ComboboxContent, ComboboxContentImpl, ComboboxEmpty, ComboboxGroup, ComboboxInput, ComboboxItem, ComboboxItemIndicator, ComboboxLabel, ComboboxPortal, ComboboxRoot, ComboboxSeparator, ComboboxTrigger, ComboboxViewport, comboboxAnchorProps, comboboxArrowProps, comboboxCancelProps, comboboxContentEmits, comboboxContentImplEmits, comboboxContentImplProps, comboboxContentProps, comboboxEmptyProps, comboboxGroupProps, comboboxInputProps, comboboxItemEmits, comboboxItemIndicatorProps, comboboxItemProps, comboboxLabelProps, comboboxPortalProps, comboboxRootEmits, comboboxRootProps, comboboxSeparatorProps, comboboxTriggerProps, comboboxViewportProps };