@destyler/combobox 0.2.6 → 0.2.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.
- package/dist/index.d.mts +49 -38
- package/dist/index.mjs +50 -12
- package/package.json +10 -10
package/dist/index.d.mts
CHANGED
|
@@ -7,7 +7,7 @@ import { FocusOutsideEvent, InteractOutsideEvent, InteractOutsideHandlers, Point
|
|
|
7
7
|
import { CommonProperties, DirectionProperty, NormalizeProps, PropTypes, RequiredBy } from "@destyler/types";
|
|
8
8
|
|
|
9
9
|
//#region src/anatomy.d.ts
|
|
10
|
-
declare const anatomy: _destyler_anatomy0.AnatomyInstance<"root" | "
|
|
10
|
+
declare const anatomy: _destyler_anatomy0.AnatomyInstance<"root" | "label" | "control" | "input" | "content" | "trigger" | "clearTrigger" | "item" | "positioner" | "itemGroup" | "itemGroupLabel" | "itemIndicator" | "itemText" | "list">;
|
|
11
11
|
//#endregion
|
|
12
12
|
//#region src/collection.d.ts
|
|
13
13
|
declare function collection<T extends CollectionItem$1>(options: CollectionOptions$1<T>): ListCollection<T>;
|
|
@@ -59,56 +59,67 @@ interface PublicContext<T extends CollectionItem = CollectionItem> extends Direc
|
|
|
59
59
|
/**
|
|
60
60
|
* Whether the combobox is open
|
|
61
61
|
*/
|
|
62
|
-
|
|
62
|
+
open?: boolean | undefined;
|
|
63
63
|
/**
|
|
64
|
-
*
|
|
64
|
+
* The initial open state of the combobox when it is not controlled.
|
|
65
|
+
* Prefer this over seeding with `open` for uncontrolled usage.
|
|
65
66
|
*/
|
|
66
|
-
|
|
67
|
+
defaultOpen?: boolean | undefined;
|
|
67
68
|
/**
|
|
68
69
|
* The ids of the elements in the combobox. Useful for composition.
|
|
69
70
|
*/
|
|
70
|
-
|
|
71
|
+
ids?: ElementIds | undefined;
|
|
71
72
|
/**
|
|
72
|
-
* The
|
|
73
|
+
* The controlled value of the combobox's input
|
|
73
74
|
*/
|
|
74
|
-
|
|
75
|
+
inputValue?: string | undefined;
|
|
76
|
+
/**
|
|
77
|
+
* The initial value of the combobox's input when it is not controlled.
|
|
78
|
+
* Prefer this over seeding with `inputValue` for uncontrolled usage.
|
|
79
|
+
*/
|
|
80
|
+
defaultInputValue?: string | undefined;
|
|
75
81
|
/**
|
|
76
82
|
* The `name` attribute of the combobox's input. Useful for form submission
|
|
77
83
|
*/
|
|
78
|
-
|
|
84
|
+
name?: string | undefined;
|
|
79
85
|
/**
|
|
80
86
|
* The associate form of the combobox.
|
|
81
87
|
*/
|
|
82
|
-
|
|
88
|
+
form?: string | undefined;
|
|
83
89
|
/**
|
|
84
90
|
* Whether the combobox is disabled
|
|
85
91
|
*/
|
|
86
|
-
|
|
92
|
+
disabled?: boolean | undefined;
|
|
87
93
|
/**
|
|
88
94
|
* Whether the combobox is readonly. This puts the combobox in a "non-editable" mode
|
|
89
95
|
* but the user can still interact with it
|
|
90
96
|
*/
|
|
91
|
-
|
|
97
|
+
readOnly?: boolean | undefined;
|
|
92
98
|
/**
|
|
93
99
|
* Whether the combobox is invalid
|
|
94
100
|
*/
|
|
95
|
-
|
|
101
|
+
invalid?: boolean | undefined;
|
|
96
102
|
/**
|
|
97
103
|
* Whether the combobox is required
|
|
98
104
|
*/
|
|
99
|
-
|
|
105
|
+
required?: boolean | undefined;
|
|
100
106
|
/**
|
|
101
107
|
* The placeholder text of the combobox's input
|
|
102
108
|
*/
|
|
103
|
-
|
|
109
|
+
placeholder?: string | undefined;
|
|
104
110
|
/**
|
|
105
111
|
* The active item's id. Used to set the `aria-activedescendant` attribute
|
|
106
112
|
*/
|
|
107
|
-
|
|
113
|
+
highlightedValue: string | null;
|
|
114
|
+
/**
|
|
115
|
+
* The controlled keys of the selected items
|
|
116
|
+
*/
|
|
117
|
+
value?: string[] | undefined;
|
|
108
118
|
/**
|
|
109
|
-
* The keys of the selected items
|
|
119
|
+
* The initial keys of the selected items when it is not controlled.
|
|
120
|
+
* Prefer this over seeding with `value` for uncontrolled usage.
|
|
110
121
|
*/
|
|
111
|
-
|
|
122
|
+
defaultValue?: string[] | undefined;
|
|
112
123
|
/**
|
|
113
124
|
* Defines the auto-completion behavior of the combobox.
|
|
114
125
|
*
|
|
@@ -117,7 +128,7 @@ interface PublicContext<T extends CollectionItem = CollectionItem> extends Direc
|
|
|
117
128
|
*
|
|
118
129
|
* @default "none"
|
|
119
130
|
*/
|
|
120
|
-
|
|
131
|
+
inputBehavior: 'autohighlight' | 'autocomplete' | 'none';
|
|
121
132
|
/**
|
|
122
133
|
* The behavior of the combobox input when an item is selected
|
|
123
134
|
*
|
|
@@ -127,92 +138,92 @@ interface PublicContext<T extends CollectionItem = CollectionItem> extends Direc
|
|
|
127
138
|
*
|
|
128
139
|
* @default "replace"
|
|
129
140
|
*/
|
|
130
|
-
|
|
141
|
+
selectionBehavior: 'clear' | 'replace' | 'preserve';
|
|
131
142
|
/**
|
|
132
143
|
* Whether to autofocus the input on mount
|
|
133
144
|
*/
|
|
134
|
-
|
|
145
|
+
autoFocus?: boolean | undefined;
|
|
135
146
|
/**
|
|
136
147
|
* Whether to open the combobox popup on initial click on the input
|
|
137
148
|
* @default false
|
|
138
149
|
*/
|
|
139
|
-
|
|
150
|
+
openOnClick?: boolean | undefined;
|
|
140
151
|
/**
|
|
141
152
|
* Whether to show the combobox when the input value changes
|
|
142
153
|
* @default true
|
|
143
154
|
*/
|
|
144
|
-
|
|
155
|
+
openOnChange?: boolean | ((details: InputValueChangeDetails) => boolean) | undefined;
|
|
145
156
|
/**
|
|
146
157
|
* Whether to allow typing custom values in the input
|
|
147
158
|
*/
|
|
148
|
-
|
|
159
|
+
allowCustomValue?: boolean | undefined;
|
|
149
160
|
/**
|
|
150
161
|
* Whether to loop the keyboard navigation through the items
|
|
151
162
|
* @default true
|
|
152
163
|
*/
|
|
153
|
-
|
|
164
|
+
loopFocus?: boolean | undefined;
|
|
154
165
|
/**
|
|
155
166
|
* The positioning options to dynamically position the menu
|
|
156
167
|
*/
|
|
157
|
-
|
|
168
|
+
positioning: PositioningOptions;
|
|
158
169
|
/**
|
|
159
170
|
* Function called when the input's value changes
|
|
160
171
|
*/
|
|
161
|
-
|
|
172
|
+
onInputValueChange?: ((details: InputValueChangeDetails) => void) | undefined;
|
|
162
173
|
/**
|
|
163
174
|
* Function called when a new item is selected
|
|
164
175
|
*/
|
|
165
|
-
|
|
176
|
+
onValueChange?: ((details: ValueChangeDetails<T>) => void) | undefined;
|
|
166
177
|
/**
|
|
167
178
|
* Function called when an item is highlighted using the pointer
|
|
168
179
|
* or keyboard navigation.
|
|
169
180
|
*/
|
|
170
|
-
|
|
181
|
+
onHighlightChange?: ((details: HighlightChangeDetails<T>) => void) | undefined;
|
|
171
182
|
/**
|
|
172
183
|
* Function called when the popup is opened
|
|
173
184
|
*/
|
|
174
|
-
|
|
185
|
+
onOpenChange?: ((details: OpenChangeDetails) => void) | undefined;
|
|
175
186
|
/**
|
|
176
187
|
* Specifies the localized strings that identifies the accessibility elements and their states
|
|
177
188
|
*/
|
|
178
|
-
|
|
189
|
+
translations: IntlTranslations;
|
|
179
190
|
/**
|
|
180
191
|
* The collection of items
|
|
181
192
|
*/
|
|
182
|
-
|
|
193
|
+
collection: ListCollection<any>;
|
|
183
194
|
/**
|
|
184
195
|
* Whether to allow multiple selection.
|
|
185
196
|
*
|
|
186
197
|
* **Good to know:** When `multiple` is `true`, the `selectionBehavior` is automatically set to `clear`.
|
|
187
198
|
* It is recommended to render the selected items in a separate container.
|
|
188
199
|
*/
|
|
189
|
-
|
|
200
|
+
multiple?: boolean | undefined;
|
|
190
201
|
/**
|
|
191
202
|
* Whether to close the combobox when an item is selected.
|
|
192
203
|
*/
|
|
193
|
-
|
|
204
|
+
closeOnSelect?: boolean | undefined;
|
|
194
205
|
/**
|
|
195
206
|
* Whether to open the combobox on arrow key press
|
|
196
207
|
* @default true
|
|
197
208
|
*/
|
|
198
|
-
|
|
209
|
+
openOnKeyPress: boolean;
|
|
199
210
|
/**
|
|
200
211
|
* Function to scroll to a specific index
|
|
201
212
|
*/
|
|
202
|
-
|
|
213
|
+
scrollToIndexFn?: ((details: ScrollToIndexDetails) => void) | undefined;
|
|
203
214
|
/**
|
|
204
215
|
* Whether the combobox is a composed with other composite widgets like tabs
|
|
205
216
|
* @default true
|
|
206
217
|
*/
|
|
207
|
-
|
|
218
|
+
composite: boolean;
|
|
208
219
|
/**
|
|
209
220
|
* Whether to disable registering this a dismissable layer
|
|
210
221
|
*/
|
|
211
|
-
|
|
222
|
+
disableLayer?: boolean | undefined;
|
|
212
223
|
/**
|
|
213
224
|
* Function to navigate to the selected item
|
|
214
225
|
*/
|
|
215
|
-
|
|
226
|
+
navigate: (details: NavigateDetails) => void;
|
|
216
227
|
}
|
|
217
228
|
type UserDefinedContext<T extends CollectionItem = CollectionItem> = RequiredBy<PublicContext<T>, 'id' | 'collection'>;
|
|
218
229
|
type ComputedContext = Readonly<{
|
package/dist/index.mjs
CHANGED
|
@@ -5,7 +5,7 @@ import { ariaAttr, clickIfLink, createScope, dataAttr, getEventKey, isAnchorElem
|
|
|
5
5
|
import { getPlacement, getPlacementStyles } from "@destyler/popper";
|
|
6
6
|
import { ariaHidden } from "@destyler/aria-hidden";
|
|
7
7
|
import { trackDismissableElement } from "@destyler/dismissable";
|
|
8
|
-
import { addOrRemove, compact, isArray, isBoolean, isEqual, match } from "@destyler/utils";
|
|
8
|
+
import { addOrRemove, compact, isArray, isBoolean, isControlled, isEqual, isPropUserProvided, match, resolveControllableOpen, resolveControllableProp, withControllableProvided } from "@destyler/utils";
|
|
9
9
|
|
|
10
10
|
//#region src/anatomy.ts
|
|
11
11
|
const anatomy = createAnatomy("combobox").parts("root", "clearTrigger", "content", "control", "input", "item", "itemGroup", "itemGroupLabel", "itemIndicator", "itemText", "label", "list", "positioner", "trigger");
|
|
@@ -389,7 +389,7 @@ function connect(state, send, normalize) {
|
|
|
389
389
|
return normalize.element({
|
|
390
390
|
...parts.list.attrs,
|
|
391
391
|
"role": !composite ? "listbox" : void 0,
|
|
392
|
-
"aria-labelledby": dom.getLabelId(state.context),
|
|
392
|
+
"aria-labelledby": !composite ? dom.getLabelId(state.context) : void 0,
|
|
393
393
|
"aria-multiselectable": state.context.multiple && !composite ? true : void 0
|
|
394
394
|
});
|
|
395
395
|
},
|
|
@@ -488,6 +488,7 @@ function connect(state, send, normalize) {
|
|
|
488
488
|
const { id } = props;
|
|
489
489
|
return normalize.element({
|
|
490
490
|
...parts.itemGroup.attrs,
|
|
491
|
+
"role": "group",
|
|
491
492
|
"dir": state.context.dir,
|
|
492
493
|
"id": dom.getItemGroupId(state.context, id),
|
|
493
494
|
"aria-labelledby": dom.getItemGroupLabelId(state.context, id)
|
|
@@ -498,8 +499,7 @@ function connect(state, send, normalize) {
|
|
|
498
499
|
return normalize.element({
|
|
499
500
|
...parts.itemGroupLabel.attrs,
|
|
500
501
|
dir: state.context.dir,
|
|
501
|
-
id: dom.getItemGroupLabelId(state.context, htmlFor)
|
|
502
|
-
role: "group"
|
|
502
|
+
id: dom.getItemGroupLabelId(state.context, htmlFor)
|
|
503
503
|
});
|
|
504
504
|
}
|
|
505
505
|
};
|
|
@@ -548,17 +548,32 @@ const invoke = {
|
|
|
548
548
|
ctx.onInputValueChange?.({ inputValue: ctx.inputValue });
|
|
549
549
|
}
|
|
550
550
|
};
|
|
551
|
+
function proposeValueChange(ctx, value) {
|
|
552
|
+
const prevSelectedItems = ctx.selectedItems;
|
|
553
|
+
const items = value.map((v) => {
|
|
554
|
+
const foundItem = prevSelectedItems.find((item) => ctx.collection.getItemValue(item) === v);
|
|
555
|
+
if (foundItem) return foundItem;
|
|
556
|
+
return ctx.collection.find(v);
|
|
557
|
+
});
|
|
558
|
+
ctx.onValueChange?.({
|
|
559
|
+
value: Array.from(value),
|
|
560
|
+
items: Array.from(items)
|
|
561
|
+
});
|
|
562
|
+
}
|
|
551
563
|
const set = {
|
|
552
564
|
value: (ctx, value, force = false) => {
|
|
553
565
|
if (isEqual(ctx.value, value)) return;
|
|
554
566
|
if (value == null && !force) return;
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
567
|
+
let next;
|
|
568
|
+
if (value == null) next = [];
|
|
569
|
+
else if (isArray(value)) next = value;
|
|
570
|
+
else next = ctx.multiple ? addOrRemove(ctx.value, value) : [value];
|
|
571
|
+
if (isEqual(ctx.value, next)) return;
|
|
572
|
+
if (isControlled(ctx, "value")) {
|
|
573
|
+
proposeValueChange(ctx, next);
|
|
558
574
|
return;
|
|
559
575
|
}
|
|
560
|
-
|
|
561
|
-
else if (value != null) ctx.value = ctx.multiple ? addOrRemove(ctx.value, value) : [value];
|
|
576
|
+
ctx.value = next;
|
|
562
577
|
invoke.valueChange(ctx);
|
|
563
578
|
},
|
|
564
579
|
highlightedValue: (ctx, value, force = false) => {
|
|
@@ -569,15 +584,36 @@ const set = {
|
|
|
569
584
|
},
|
|
570
585
|
inputValue: (ctx, value) => {
|
|
571
586
|
if (isEqual(ctx.inputValue, value)) return;
|
|
587
|
+
if (isControlled(ctx, "inputValue")) {
|
|
588
|
+
ctx.onInputValueChange?.({ inputValue: value });
|
|
589
|
+
return;
|
|
590
|
+
}
|
|
572
591
|
ctx.inputValue = value;
|
|
573
592
|
invoke.inputChange(ctx);
|
|
574
593
|
}
|
|
575
594
|
};
|
|
576
595
|
function machine(userContext) {
|
|
577
|
-
const ctx = compact(userContext
|
|
596
|
+
const ctx = compact(withControllableProvided(userContext, [
|
|
597
|
+
"open",
|
|
598
|
+
"value",
|
|
599
|
+
"inputValue"
|
|
600
|
+
]));
|
|
601
|
+
const { initialOpen } = resolveControllableOpen(ctx);
|
|
602
|
+
const { initial: initialValue } = resolveControllableProp({
|
|
603
|
+
value: ctx.value,
|
|
604
|
+
defaultValue: ctx.defaultValue,
|
|
605
|
+
valueProvided: isPropUserProvided(ctx, "value"),
|
|
606
|
+
fallback: []
|
|
607
|
+
});
|
|
608
|
+
const { initial: initialInputValue } = resolveControllableProp({
|
|
609
|
+
value: ctx.inputValue,
|
|
610
|
+
defaultValue: ctx.defaultInputValue,
|
|
611
|
+
valueProvided: isPropUserProvided(ctx, "inputValue"),
|
|
612
|
+
fallback: ""
|
|
613
|
+
});
|
|
578
614
|
return createMachine({
|
|
579
615
|
id: "combobox",
|
|
580
|
-
initial:
|
|
616
|
+
initial: initialOpen ? "suggesting" : "idle",
|
|
581
617
|
context: {
|
|
582
618
|
loopFocus: true,
|
|
583
619
|
openOnClick: false,
|
|
@@ -597,6 +633,8 @@ function machine(userContext) {
|
|
|
597
633
|
clickIfLink(node);
|
|
598
634
|
},
|
|
599
635
|
...ctx,
|
|
636
|
+
value: initialValue,
|
|
637
|
+
inputValue: initialInputValue,
|
|
600
638
|
highlightedItem: null,
|
|
601
639
|
selectedItems: [],
|
|
602
640
|
valueAsString: "",
|
|
@@ -1091,7 +1129,7 @@ function machine(userContext) {
|
|
|
1091
1129
|
allowCustomValue: (ctx$1) => !!ctx$1.allowCustomValue,
|
|
1092
1130
|
hasHighlightedItem: (ctx$1) => ctx$1.highlightedValue != null,
|
|
1093
1131
|
closeOnSelect: (ctx$1) => !!ctx$1.closeOnSelect,
|
|
1094
|
-
isOpenControlled: (ctx$1) =>
|
|
1132
|
+
isOpenControlled: (ctx$1) => isControlled(ctx$1, "open"),
|
|
1095
1133
|
openOnChange: (ctx$1, evt) => {
|
|
1096
1134
|
if (isBoolean(ctx$1.openOnChange)) return ctx$1.openOnChange;
|
|
1097
1135
|
return !!ctx$1.openOnChange?.({ inputValue: evt.value });
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@destyler/combobox",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.2.
|
|
4
|
+
"version": "0.2.9",
|
|
5
5
|
"description": "autocomplete input and command palette with a list of suggestions.",
|
|
6
6
|
"author": "Elone Hoo <elonehoo@gmail.com>",
|
|
7
7
|
"license": "MIT",
|
|
@@ -22,15 +22,15 @@
|
|
|
22
22
|
"dist"
|
|
23
23
|
],
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@destyler/
|
|
26
|
-
"@destyler/
|
|
27
|
-
"@destyler/collection": "0.2.
|
|
28
|
-
"@destyler/
|
|
29
|
-
"@destyler/
|
|
30
|
-
"@destyler/
|
|
31
|
-
"@destyler/
|
|
32
|
-
"@destyler/
|
|
33
|
-
"@destyler/
|
|
25
|
+
"@destyler/aria-hidden": "0.2.9",
|
|
26
|
+
"@destyler/anatomy": "0.2.9",
|
|
27
|
+
"@destyler/collection": "0.2.9",
|
|
28
|
+
"@destyler/popper": "0.2.9",
|
|
29
|
+
"@destyler/types": "0.2.9",
|
|
30
|
+
"@destyler/dismissable": "0.2.9",
|
|
31
|
+
"@destyler/utils": "0.2.9",
|
|
32
|
+
"@destyler/dom": "0.2.9",
|
|
33
|
+
"@destyler/xstate": "0.2.9"
|
|
34
34
|
},
|
|
35
35
|
"publishConfig": {
|
|
36
36
|
"access": "public"
|