@agnos-ui/core 0.0.1-alpha.3 → 0.0.1-alpha.5

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 (96) hide show
  1. package/{accordion.d.ts → components/accordion/accordion.d.ts} +13 -4
  2. package/{accordion.js → components/accordion/accordion.js} +17 -11
  3. package/components/alert/alert.d.ts +32 -0
  4. package/components/alert/alert.js +23 -0
  5. package/{alert.d.ts → components/alert/common.d.ts} +17 -21
  6. package/{alert.js → components/alert/common.js} +12 -12
  7. package/{modal → components/modal}/modal.d.ts +28 -21
  8. package/{modal → components/modal}/modal.js +39 -13
  9. package/{pagination.d.ts → components/pagination/pagination.d.ts} +3 -3
  10. package/{pagination.js → components/pagination/pagination.js} +6 -4
  11. package/{progressbar.d.ts → components/progressbar/progressbar.d.ts} +2 -3
  12. package/{progressbar.js → components/progressbar/progressbar.js} +6 -6
  13. package/{rating.d.ts → components/rating/rating.d.ts} +2 -3
  14. package/{rating.js → components/rating/rating.js} +6 -9
  15. package/components/select/select.d.ts +337 -0
  16. package/components/select/select.js +266 -0
  17. package/components/slider/slider.d.ts +239 -0
  18. package/components/slider/slider.js +389 -0
  19. package/config.d.ts +13 -8
  20. package/config.js +3 -3
  21. package/index.d.ts +23 -12
  22. package/index.js +29 -12
  23. package/package.json +32 -4
  24. package/services/extendWidget.d.ts +23 -0
  25. package/{extendWidget.js → services/extendWidget.js} +8 -1
  26. package/services/floatingUI.d.ts +48 -0
  27. package/services/floatingUI.js +97 -0
  28. package/services/focustrack.js +1 -1
  29. package/services/intersection.d.ts +1 -1
  30. package/services/intersection.js +2 -2
  31. package/services/navManager.d.ts +83 -1
  32. package/services/navManager.js +153 -37
  33. package/services/portal.js +8 -4
  34. package/services/siblingsInert.d.ts +2 -1
  35. package/services/siblingsInert.js +2 -2
  36. package/{transitions → services/transitions}/baseTransitions.d.ts +1 -2
  37. package/{transitions → services/transitions}/baseTransitions.js +7 -10
  38. package/services/transitions/bootstrap/collapse.d.ts +2 -0
  39. package/services/transitions/bootstrap/fade.d.ts +1 -0
  40. package/services/transitions/bootstrap.d.ts +2 -0
  41. package/services/transitions/bootstrap.js +2 -0
  42. package/{transitions → services/transitions}/collapse.js +1 -1
  43. package/{transitions → services/transitions}/cssTransitions.js +2 -4
  44. package/{transitions → services/transitions}/simpleClassTransition.js +1 -1
  45. package/types.d.ts +37 -4
  46. package/types.js +1 -0
  47. package/{services/directiveUtils.js → utils/directive.js} +1 -1
  48. package/{services → utils/internal}/checks.d.ts +12 -0
  49. package/{services → utils/internal}/checks.js +12 -0
  50. package/utils/internal/dom.d.ts +13 -0
  51. package/utils/internal/dom.js +49 -0
  52. package/utils/internal/isFocusable.d.ts +9 -0
  53. package/utils/internal/isFocusable.js +35 -0
  54. package/utils/internal/math.d.ts +5 -0
  55. package/utils/internal/math.js +13 -0
  56. package/utils/internal/promise.d.ts +31 -0
  57. package/utils/internal/promise.js +113 -0
  58. package/{modal → utils/internal}/scrollbars.js +1 -1
  59. package/utils/internal/textDirection.d.ts +1 -0
  60. package/utils/internal/textDirection.js +1 -0
  61. package/utils/internal/traversal.d.ts +54 -0
  62. package/utils/internal/traversal.js +105 -0
  63. package/{services → utils}/stores.d.ts +11 -35
  64. package/{services → utils}/stores.js +21 -19
  65. package/utils/writables.d.ts +26 -0
  66. package/utils/writables.js +66 -0
  67. package/extendWidget.d.ts +0 -3
  68. package/select.d.ts +0 -196
  69. package/select.js +0 -240
  70. package/services/index.d.ts +0 -8
  71. package/services/index.js +0 -8
  72. package/services/writables.d.ts +0 -8
  73. package/services/writables.js +0 -30
  74. package/transitions/bootstrap/collapse.d.ts +0 -2
  75. package/transitions/bootstrap/fade.d.ts +0 -1
  76. package/transitions/bootstrap/index.d.ts +0 -2
  77. package/transitions/bootstrap/index.js +0 -2
  78. package/transitions/index.d.ts +0 -5
  79. package/transitions/index.js +0 -5
  80. package/transitions/utils.d.ts +0 -20
  81. package/transitions/utils.js +0 -83
  82. /package/{commonProps.d.ts → components/commonProps.d.ts} +0 -0
  83. /package/{commonProps.js → components/commonProps.js} +0 -0
  84. /package/{pagination.utils.d.ts → components/pagination/bootstrap.d.ts} +0 -0
  85. /package/{pagination.utils.js → components/pagination/bootstrap.js} +0 -0
  86. /package/{transitions → services/transitions}/bootstrap/collapse.js +0 -0
  87. /package/{transitions → services/transitions}/bootstrap/fade.js +0 -0
  88. /package/{transitions → services/transitions}/collapse.d.ts +0 -0
  89. /package/{transitions → services/transitions}/cssTransitions.d.ts +0 -0
  90. /package/{transitions → services/transitions}/simpleClassTransition.d.ts +0 -0
  91. /package/{services/directiveUtils.d.ts → utils/directive.d.ts} +0 -0
  92. /package/{utils.d.ts → utils/internal/func.d.ts} +0 -0
  93. /package/{utils.js → utils/internal/func.js} +0 -0
  94. /package/{modal → utils/internal}/scrollbars.d.ts +0 -0
  95. /package/{services/sortUtils.d.ts → utils/internal/sort.d.ts} +0 -0
  96. /package/{services/sortUtils.js → utils/internal/sort.js} +0 -0
@@ -0,0 +1,337 @@
1
+ import type { Placement } from '@floating-ui/dom';
2
+ import type { FloatingUI } from '../../services/floatingUI';
3
+ import type { HasFocus } from '../../services/focustrack';
4
+ import type { PropsConfig, SlotContent, Widget, WidgetSlotContext } from '../../types';
5
+ import type { WidgetsCommonPropsAndState } from '../commonProps';
6
+ /**
7
+ * A type for the slot context of the pagination widget
8
+ */
9
+ export type SelectContext<Item> = WidgetSlotContext<SelectWidget<Item>>;
10
+ export interface SelectItemContext<Item> extends SelectContext<Item> {
11
+ /**
12
+ * Contextual data related to an item
13
+ */
14
+ itemContext: ItemContext<Item>;
15
+ }
16
+ export interface SelectCommonPropsAndState<Item> extends WidgetsCommonPropsAndState {
17
+ /**
18
+ * id used for the input inside the select
19
+ */
20
+ id: string | undefined;
21
+ /**
22
+ * aria-label used for the input inside the select
23
+ */
24
+ ariaLabel: string | undefined;
25
+ /**
26
+ * List of selected item ids
27
+ */
28
+ selected: Item[];
29
+ /**
30
+ * Filtered text to be display in the filter input
31
+ */
32
+ filterText: string;
33
+ /**
34
+ * true if the select is disabled
35
+ */
36
+ disabled: boolean;
37
+ /**
38
+ * true if the select is open
39
+ */
40
+ open: boolean;
41
+ /**
42
+ * Class to be added on the dropdown menu container
43
+ */
44
+ menuClassName: string;
45
+ /**
46
+ * Class to be added on menu items
47
+ */
48
+ menuItemClassName: string;
49
+ /**
50
+ * Class to be added on selected items (displayed in the input zone)
51
+ */
52
+ badgeClassName: string;
53
+ /**
54
+ * true if a loading process is being done
55
+ */
56
+ loading: boolean;
57
+ /**
58
+ * The template to override the way each badge on the left of the input is displayed.
59
+ * This define the content of the badge inside the badge container.
60
+ */
61
+ slotBadgeLabel: SlotContent<SelectItemContext<Item>>;
62
+ /**
63
+ * The template to override the way each item is displayed in the list.
64
+ * This define the content of the badge inside the badge container.
65
+ */
66
+ slotItem: SlotContent<SelectItemContext<Item>>;
67
+ }
68
+ export interface SelectProps<T> extends SelectCommonPropsAndState<T> {
69
+ /**
70
+ * List of available items for the dropdown
71
+ */
72
+ items: T[];
73
+ /**
74
+ * List of allowed placements for the dropdown.
75
+ * This refers to the [allowedPlacements from floating UI](https://floating-ui.com/docs/autoPlacement#allowedplacements), given the different [Placement possibilities](https://floating-ui.com/docs/computePosition#placement).
76
+ */
77
+ allowedPlacements: Placement[];
78
+ /**
79
+ * Custom function to get the id of an item
80
+ * By default, the item is returned
81
+ */
82
+ itemIdFn(item: T): string;
83
+ /**
84
+ * Callback called dropdown open state change
85
+ * @param isOpen - updated open state
86
+ */
87
+ onOpenChange(isOpen: boolean): void;
88
+ /**
89
+ * Callback called when the text filter change
90
+ * @param text - Filtered text
91
+ */
92
+ onFilterTextChange(text: string): void;
93
+ /**
94
+ * Callback called when the selection change
95
+ */
96
+ onSelectedChange(selected: T[]): void;
97
+ }
98
+ /**
99
+ * Item representation built from the items provided in parameters
100
+ */
101
+ export interface ItemContext<T> {
102
+ /**
103
+ * Original item given in the parameters
104
+ */
105
+ item: T;
106
+ /**
107
+ * Unique id to identify the item
108
+ */
109
+ id: string;
110
+ /**
111
+ * Specify if the item is checked
112
+ */
113
+ selected: boolean;
114
+ }
115
+ export interface SelectState<Item> extends SelectCommonPropsAndState<Item> {
116
+ /**
117
+ * List of item contexts, to be displayed in the menu
118
+ */
119
+ visibleItems: ItemContext<Item>[];
120
+ /**
121
+ /**
122
+ * List of selected items to be display
123
+ */
124
+ selectedContexts: ItemContext<Item>[];
125
+ /**
126
+ * Highlighted item context.
127
+ * It is designed to define the highlighted item in the dropdown menu
128
+ */
129
+ highlighted: ItemContext<Item> | undefined;
130
+ /**
131
+ * Current placement of the dropdown
132
+ */
133
+ placement: Placement | undefined;
134
+ }
135
+ export interface SelectApi<Item> {
136
+ /**
137
+ * Clear all the selected items
138
+ */
139
+ clear(): void;
140
+ /**
141
+ * Clear the filter text
142
+ */
143
+ clearText(): void;
144
+ /**
145
+ * Highlight the given item, if there is a corresponding match among the visible list
146
+ */
147
+ highlight(item: Item): void;
148
+ /**
149
+ * Highlight the first item among the visible list
150
+ */
151
+ highlightFirst(): void;
152
+ /**
153
+ * Highlight the previous item among the visible list
154
+ * Loop to the last item if needed
155
+ */
156
+ highlightPrevious(): void;
157
+ /**
158
+ * Highlight the next item among the visible list.
159
+ * Loop to the first item if needed
160
+ */
161
+ highlightNext(): void;
162
+ /**
163
+ * Highlight the last item among the visible list
164
+ */
165
+ highlightLast(): void;
166
+ /**
167
+ * Focus the provided item among the selected list.
168
+ * The focus feature is designed to know what item must be focused in the UI, i.e. among the badge elements.
169
+ */
170
+ focus(item: Item): void;
171
+ /**
172
+ * Focus the first element
173
+ */
174
+ focusFirst(): void;
175
+ /**
176
+ * Focus the previous element. If no element was focused before the call, nothing happens.
177
+ */
178
+ focusPrevious(): void;
179
+ /**
180
+ * Focus the next element. If no element was focused before the call, nothing happens.
181
+ */
182
+ focusNext(): void;
183
+ /**
184
+ * Focus the last element. If no element was focused before the call, nothing happens.
185
+ */
186
+ focusLast(): void;
187
+ /**
188
+ * Select the provided item.
189
+ * The selected list is used to
190
+ * @param item - the item to select
191
+ */
192
+ select(item: Item): void;
193
+ /**
194
+ * Unselect the provided item.
195
+ * @param item - the item to unselect
196
+ */
197
+ unselect(item: Item): void;
198
+ /**
199
+ * Toggle the selection of an item
200
+ * @param item - the item to toggle
201
+ * @param selected - an optional boolean to enforce the selected/unselected state instead of toggling
202
+ */
203
+ toggleItem(item: Item, selected?: boolean): void;
204
+ /**
205
+ * open the select
206
+ */
207
+ open(): void;
208
+ /**
209
+ * close the select
210
+ */
211
+ close(): void;
212
+ /**
213
+ * Toggle the dropdown menu
214
+ * @param isOpen - If specified, set the menu in the defined state.
215
+ */
216
+ toggle(isOpen?: boolean): void;
217
+ }
218
+ export interface SelectDirectives {
219
+ /**
220
+ * Directive to be used in the input group and the menu containers
221
+ */
222
+ hasFocusDirective: HasFocus['directive'];
223
+ /**
224
+ * Directive that enables dynamic positioning of menu element
225
+ */
226
+ floatingDirective: FloatingUI['directives']['floatingDirective'];
227
+ /**
228
+ * A directive to be applied to the input group element serves as the base for menu positioning
229
+ */
230
+ referenceDirective: FloatingUI['directives']['referenceDirective'];
231
+ }
232
+ export interface SelectActions {
233
+ /**
234
+ * Method to be plugged to on the 'input' event. The input text will be used as the filter text.
235
+ */
236
+ onInput: (e: {
237
+ target: any;
238
+ }) => void;
239
+ /**
240
+ * Method to be plugged to on an keydown event, in order to control the keyboard interactions with the highlighted item.
241
+ * It manages arrow keys to move the highlighted item, or enter to toggle the item.
242
+ */
243
+ onInputKeydown: (e: any) => void;
244
+ }
245
+ export type SelectWidget<Item> = Widget<SelectProps<Item>, SelectState<Item>, SelectApi<Item>, SelectActions, SelectDirectives>;
246
+ export declare const defaultConfig: SelectProps<any>;
247
+ /**
248
+ * Returns a shallow copy of the default select config.
249
+ * @returns a copy of the default config
250
+ */
251
+ export declare function getSelectDefaultConfig(): {
252
+ /**
253
+ * List of available items for the dropdown
254
+ */
255
+ items: any[];
256
+ /**
257
+ * List of allowed placements for the dropdown.
258
+ * This refers to the [allowedPlacements from floating UI](https://floating-ui.com/docs/autoPlacement#allowedplacements), given the different [Placement possibilities](https://floating-ui.com/docs/computePosition#placement).
259
+ */
260
+ allowedPlacements: Placement[];
261
+ /**
262
+ * Custom function to get the id of an item
263
+ * By default, the item is returned
264
+ */
265
+ itemIdFn(item: any): string;
266
+ /**
267
+ * Callback called dropdown open state change
268
+ * @param isOpen - updated open state
269
+ */
270
+ onOpenChange(isOpen: boolean): void;
271
+ /**
272
+ * Callback called when the text filter change
273
+ * @param text - Filtered text
274
+ */
275
+ onFilterTextChange(text: string): void;
276
+ /**
277
+ * Callback called when the selection change
278
+ */
279
+ onSelectedChange(selected: any[]): void;
280
+ /**
281
+ * id used for the input inside the select
282
+ */
283
+ id: string | undefined;
284
+ /**
285
+ * aria-label used for the input inside the select
286
+ */
287
+ ariaLabel: string | undefined;
288
+ /**
289
+ * List of selected item ids
290
+ */
291
+ selected: any[];
292
+ /**
293
+ * Filtered text to be display in the filter input
294
+ */
295
+ filterText: string;
296
+ /**
297
+ * true if the select is disabled
298
+ */
299
+ disabled: boolean;
300
+ /**
301
+ * true if the select is open
302
+ */
303
+ open: boolean;
304
+ /**
305
+ * Class to be added on the dropdown menu container
306
+ */
307
+ menuClassName: string;
308
+ /**
309
+ * Class to be added on menu items
310
+ */
311
+ menuItemClassName: string;
312
+ /**
313
+ * Class to be added on selected items (displayed in the input zone)
314
+ */
315
+ badgeClassName: string;
316
+ /**
317
+ * true if a loading process is being done
318
+ */
319
+ loading: boolean;
320
+ /**
321
+ * The template to override the way each badge on the left of the input is displayed.
322
+ * This define the content of the badge inside the badge container.
323
+ */
324
+ slotBadgeLabel: SlotContent<SelectItemContext<any>>;
325
+ /**
326
+ * The template to override the way each item is displayed in the list.
327
+ * This define the content of the badge inside the badge container.
328
+ */
329
+ slotItem: SlotContent<SelectItemContext<any>>;
330
+ className: string;
331
+ };
332
+ /**
333
+ * Create a SelectWidget with given config props
334
+ * @param config - an optional alert config
335
+ * @returns a SelectWidget
336
+ */
337
+ export declare function createSelect<Item>(config?: PropsConfig<SelectProps<Item>>): SelectWidget<Item>;
@@ -0,0 +1,266 @@
1
+ import { asWritable, computed, writable } from '@amadeus-it-group/tansu';
2
+ import { autoPlacement, offset, size } from '@floating-ui/dom';
3
+ import { createFloatingUI } from '../../services/floatingUI';
4
+ import { createHasFocus } from '../../services/focustrack';
5
+ import { noop } from '../../utils/internal/func';
6
+ import { bindableDerived, stateStores, writablesForProps } from '../../utils/stores';
7
+ const defaultItemId = (item) => '' + item;
8
+ export const defaultConfig = {
9
+ id: undefined,
10
+ ariaLabel: 'Select',
11
+ open: false,
12
+ disabled: false,
13
+ items: [],
14
+ filterText: '',
15
+ loading: false,
16
+ selected: [],
17
+ itemIdFn: defaultItemId,
18
+ onOpenChange: noop,
19
+ onFilterTextChange: noop,
20
+ onSelectedChange: noop,
21
+ allowedPlacements: ['bottom-start', 'top-start', 'bottom-end', 'top-end'],
22
+ className: '',
23
+ menuClassName: '',
24
+ menuItemClassName: '',
25
+ badgeClassName: '',
26
+ slotBadgeLabel: ({ itemContext }) => itemContext.item,
27
+ slotItem: ({ itemContext }) => itemContext.item,
28
+ };
29
+ /**
30
+ * Returns a shallow copy of the default select config.
31
+ * @returns a copy of the default config
32
+ */
33
+ export function getSelectDefaultConfig() {
34
+ return { ...defaultConfig };
35
+ }
36
+ /**
37
+ * Create a SelectWidget with given config props
38
+ * @param config - an optional alert config
39
+ * @returns a SelectWidget
40
+ */
41
+ export function createSelect(config) {
42
+ // Props
43
+ const [{ open$: _dirtyOpen$, filterText$: _dirtyFilterText$, items$, itemIdFn$, onOpenChange$, onFilterTextChange$, onSelectedChange$, allowedPlacements$, ...stateProps }, patch,] = writablesForProps(defaultConfig, config);
44
+ const { selected$ } = stateProps;
45
+ const filterText$ = bindableDerived(onFilterTextChange$, [_dirtyFilterText$]);
46
+ const { hasFocus$, directive: hasFocusDirective } = createHasFocus();
47
+ const open$ = bindableDerived(onOpenChange$, [_dirtyOpen$, hasFocus$], ([_dirtyOpen, hasFocus]) => _dirtyOpen && hasFocus);
48
+ const selectedContextsMap$ = computed(() => {
49
+ const selectedItemsContext = new Map();
50
+ const itemIdFn = itemIdFn$();
51
+ for (const item of selected$()) {
52
+ const id = itemIdFn(item);
53
+ selectedItemsContext.set(id, {
54
+ item,
55
+ id: itemIdFn(item),
56
+ selected: true,
57
+ });
58
+ }
59
+ return selectedItemsContext;
60
+ });
61
+ const selectedContexts$ = computed(() => [...selectedContextsMap$().values()]);
62
+ const highlightedIndex$ = (function () {
63
+ const store = writable(0);
64
+ return asWritable(store, (index) => {
65
+ const { length } = visibleItems$();
66
+ if (index != undefined) {
67
+ if (!length) {
68
+ index = undefined;
69
+ }
70
+ else if (index < 0) {
71
+ index = length - 1;
72
+ }
73
+ else if (index >= length) {
74
+ index = 0;
75
+ }
76
+ }
77
+ store.set(index);
78
+ });
79
+ })();
80
+ const itemContexts$ = computed(() => {
81
+ const itemContexts = new Map();
82
+ if (open$()) {
83
+ const selectedContextsMap = selectedContextsMap$();
84
+ const itemIdFn = itemIdFn$();
85
+ for (const item of items$()) {
86
+ const id = itemIdFn(item);
87
+ itemContexts.set(id, {
88
+ item,
89
+ id,
90
+ selected: selectedContextsMap.has(id),
91
+ });
92
+ }
93
+ }
94
+ return itemContexts;
95
+ });
96
+ const visibleItems$ = computed(() => (open$() ? [...itemContexts$().values()] : []));
97
+ const highlighted$ = computed(() => {
98
+ const visibleItems = visibleItems$();
99
+ const highlightedIndex = highlightedIndex$();
100
+ return visibleItems.length && highlightedIndex != undefined ? visibleItems[highlightedIndex] : undefined;
101
+ });
102
+ const { directives: { floatingDirective, referenceDirective }, stores: { placement$ }, } = createFloatingUI({
103
+ props: {
104
+ computePositionOptions: asWritable(computed(() => ({
105
+ middleware: [
106
+ offset(5),
107
+ autoPlacement({
108
+ allowedPlacements: allowedPlacements$(),
109
+ }),
110
+ size(),
111
+ ],
112
+ }))),
113
+ },
114
+ });
115
+ const widget = {
116
+ ...stateStores({
117
+ visibleItems$,
118
+ highlighted$,
119
+ open$,
120
+ selectedContexts$,
121
+ filterText$,
122
+ placement$,
123
+ ...stateProps,
124
+ }),
125
+ patch,
126
+ api: {
127
+ clear() {
128
+ selected$.set([]);
129
+ },
130
+ select(item) {
131
+ widget.api.toggleItem(item, true);
132
+ },
133
+ unselect(item) {
134
+ widget.api.toggleItem(item, false);
135
+ },
136
+ toggleItem(item, selected) {
137
+ const itemIdFn = itemIdFn$();
138
+ const itemId = itemIdFn(item);
139
+ const selectedContextsMap = selectedContextsMap$();
140
+ const isInSelected = selectedContextsMap.has(itemId);
141
+ if (selected == null) {
142
+ selected = !isInSelected;
143
+ }
144
+ if ((selected && !itemContexts$().has(itemId)) || (!selected && !isInSelected)) {
145
+ // Nothing to do in this case
146
+ return;
147
+ }
148
+ selected$.update((selectedItems) => {
149
+ selectedItems = [...selectedItems]; // Mutate the array
150
+ if (selected && !isInSelected) {
151
+ selectedItems.push(item);
152
+ }
153
+ else if (!selected && isInSelected) {
154
+ const index = selectedItems.findIndex((item) => itemIdFn(item) === itemId);
155
+ selectedItems.splice(index, 1);
156
+ }
157
+ onSelectedChange$()?.(selectedItems);
158
+ return selectedItems;
159
+ });
160
+ },
161
+ clearText() {
162
+ // FIXME: not implemented yet!
163
+ },
164
+ highlight(item) {
165
+ const index = visibleItems$().findIndex((itemCtx) => itemCtx.item === item);
166
+ highlightedIndex$.set(index === -1 ? undefined : index);
167
+ },
168
+ highlightFirst() {
169
+ highlightedIndex$.set(0);
170
+ },
171
+ highlightPrevious() {
172
+ highlightedIndex$.update((highlightedIndex) => {
173
+ return highlightedIndex != null ? highlightedIndex - 1 : -1;
174
+ });
175
+ },
176
+ highlightNext() {
177
+ highlightedIndex$.update((highlightedIndex) => {
178
+ return highlightedIndex != null ? highlightedIndex + 1 : Infinity;
179
+ });
180
+ },
181
+ highlightLast() {
182
+ highlightedIndex$.set(-1);
183
+ },
184
+ focus(item) {
185
+ // FIXME: not implemented yet!
186
+ },
187
+ focusFirst() {
188
+ // FIXME: not implemented yet!
189
+ },
190
+ focusPrevious() {
191
+ // FIXME: not implemented yet!
192
+ },
193
+ focusNext() {
194
+ // FIXME: not implemented yet!
195
+ },
196
+ focusLast() {
197
+ // FIXME: not implemented yet!
198
+ },
199
+ open: () => widget.api.toggle(true),
200
+ close: () => widget.api.toggle(false),
201
+ toggle(isOpen) {
202
+ _dirtyOpen$.update((value) => (isOpen != null ? isOpen : !value));
203
+ },
204
+ },
205
+ directives: {
206
+ hasFocusDirective,
207
+ floatingDirective,
208
+ referenceDirective,
209
+ },
210
+ actions: {
211
+ onInput({ target }) {
212
+ const value = target.value;
213
+ patch({
214
+ open: value != null && value !== '',
215
+ filterText: value,
216
+ });
217
+ },
218
+ onInputKeydown(e) {
219
+ const { ctrlKey, key } = e;
220
+ let keyManaged = true;
221
+ switch (key) {
222
+ case 'ArrowDown': {
223
+ const isOpen = open$();
224
+ if (isOpen) {
225
+ if (ctrlKey) {
226
+ widget.api.highlightLast();
227
+ }
228
+ else {
229
+ widget.api.highlightNext();
230
+ }
231
+ }
232
+ else {
233
+ widget.api.open();
234
+ widget.api.highlightFirst();
235
+ }
236
+ break;
237
+ }
238
+ case 'ArrowUp':
239
+ if (ctrlKey) {
240
+ widget.api.highlightFirst();
241
+ }
242
+ else {
243
+ widget.api.highlightPrevious();
244
+ }
245
+ break;
246
+ case 'Enter': {
247
+ const itemCtx = highlighted$();
248
+ if (itemCtx) {
249
+ widget.api.toggleItem(itemCtx.item);
250
+ }
251
+ break;
252
+ }
253
+ case 'Escape':
254
+ _dirtyOpen$.set(false);
255
+ break;
256
+ default:
257
+ keyManaged = false;
258
+ }
259
+ if (keyManaged) {
260
+ e.preventDefault();
261
+ }
262
+ },
263
+ },
264
+ };
265
+ return widget;
266
+ }