@oscarpalmer/oui 0.33.0 → 0.34.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.
- package/dist/js/combobox/constants.combobox.d.mts +2 -0
- package/dist/js/combobox/constants.combobox.mjs +46 -0
- package/dist/js/combobox/data.combobox.d.mts +18 -0
- package/dist/js/combobox/data.combobox.mjs +2 -0
- package/dist/js/combobox/dom.combobox.d.mts +110 -0
- package/dist/js/combobox/dom.combobox.mjs +2 -0
- package/dist/js/combobox/event.combobox.d.mts +17 -0
- package/dist/js/combobox/event.combobox.mjs +2 -0
- package/dist/js/combobox/form.combobox.d.mts +6 -0
- package/dist/js/combobox/form.combobox.mjs +2 -0
- package/dist/js/combobox/i18n.combobox.d.mts +2 -0
- package/dist/js/combobox/i18n.combobox.mjs +2 -0
- package/dist/js/combobox/index.d.mts +2 -0
- package/dist/js/combobox/index.mjs +194 -0
- package/dist/js/combobox/misc.combobox.d.mts +14 -0
- package/dist/js/combobox/misc.combobox.mjs +2 -0
- package/dist/js/combobox/models.combobox.d.mts +2 -0
- package/dist/js/combobox/models.combobox.mjs +1 -0
- package/dist/js/combobox/state.combobox.d.mts +11 -0
- package/dist/js/combobox/state.combobox.mjs +2 -0
- package/dist/js/constants.combobox-DqNUGBLS.d.mts +243 -0
- package/dist/js/data.combobox-8RwBv5ey.mjs +1077 -0
- package/dist/js/dialog.mjs +3 -2
- package/dist/js/floatable/floatable.embedded.mjs +4 -4
- package/dist/js/focus-trap/focus-trap.embedded.mjs +3 -3
- package/dist/js/index.d.mts +14 -643
- package/dist/js/index.mjs +19 -4875
- package/dist/js/internal/draggable.mjs +6 -6
- package/dist/js/internal/navigable.mjs +3 -3
- package/dist/js/menu.d.mts +1 -1
- package/dist/js/menu.mjs +3 -2
- package/dist/js/movable/movable.embedded.mjs +3 -3
- package/dist/js/popover.mjs +1 -1
- package/dist/js/resizable/resizable.embedded.mjs +7 -7
- package/dist/js/sortable/sortable.embedded.mjs +7 -6
- package/dist/js/splitter.mjs +7 -13
- package/dist/js/toolbar.d.mts +1 -1
- package/dist/js/tooltip.mjs +3 -3
- package/package.json +4 -4
- package/src/js/combobox/constants.combobox.ts +62 -0
- package/src/js/combobox/data.combobox.ts +236 -0
- package/src/js/combobox/dom.combobox.ts +794 -0
- package/src/js/combobox/event.combobox.ts +454 -0
- package/src/js/combobox/form.combobox.ts +115 -0
- package/src/js/combobox/i18n.combobox.ts +179 -0
- package/src/js/combobox/index.ts +307 -0
- package/src/js/combobox/misc.combobox.ts +138 -0
- package/src/js/combobox/models.combobox.ts +94 -0
- package/src/js/combobox/state.combobox.ts +235 -0
- package/src/js/index.ts +1 -1
- package/src/js/internal/draggable.ts +3 -3
- package/src/js/movable/movable.embedded.ts +2 -2
- package/src/js/resizable/resizable.embedded.ts +3 -3
- package/src/js/sortable/sortable.embedded.ts +2 -2
- package/src/js/splitter.ts +2 -2
- package/dist/js/combobox.d.mts +0 -91
- package/dist/js/combobox.mjs +0 -797
- package/src/js/combobox.ts +0 -2410
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { dispatch, getEventPosition, on } from "@oscarpalmer/toretto/event";
|
|
2
2
|
import { getAttribute, setAttribute } from "@oscarpalmer/toretto/attribute";
|
|
3
|
-
import { dispatch, getPosition, on } from "@oscarpalmer/toretto/event";
|
|
4
|
-
import { findAncestor } from "@oscarpalmer/toretto/find";
|
|
5
|
-
import { setStyle, setStyles, toggleStyles } from "@oscarpalmer/toretto/style";
|
|
6
3
|
import { isHTMLOrSVGElement } from "@oscarpalmer/toretto/is";
|
|
4
|
+
import { setStyle, setStyles, toggleStyles } from "@oscarpalmer/toretto/style";
|
|
5
|
+
import { clamp } from "@oscarpalmer/atoms/number";
|
|
6
|
+
import { findAncestor } from "@oscarpalmer/toretto/find";
|
|
7
7
|
import supportsTouch from "@oscarpalmer/toretto/touch";
|
|
8
8
|
//#region src/js/internal/draggable.ts
|
|
9
9
|
var OuiDraggable = class {
|
|
@@ -118,7 +118,7 @@ function onPointerdown(event) {
|
|
|
118
118
|
if (handle == null) return;
|
|
119
119
|
const dragged = item.state.options.getDragged();
|
|
120
120
|
const rectangle = dragged.getBoundingClientRect();
|
|
121
|
-
const position =
|
|
121
|
+
const position = getEventPosition(event) ?? {
|
|
122
122
|
x: 0,
|
|
123
123
|
y: 0
|
|
124
124
|
};
|
|
@@ -153,7 +153,7 @@ function onPointerdown(event) {
|
|
|
153
153
|
}
|
|
154
154
|
function onPointermove(event) {
|
|
155
155
|
if (current == null) return;
|
|
156
|
-
const position =
|
|
156
|
+
const position = getEventPosition(event);
|
|
157
157
|
if (position == null) return;
|
|
158
158
|
const next = getNextPosition(current, position);
|
|
159
159
|
if (globals.element != null) setStyle(globals.element.node, "inset", `${next.y}px auto auto ${next.x}px`);
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { clamp } from "@oscarpalmer/atoms/number";
|
|
2
1
|
import { getAria, setRole } from "@oscarpalmer/toretto/aria";
|
|
3
2
|
import { dispatch, on } from "@oscarpalmer/toretto/event";
|
|
4
|
-
import { findAncestor } from "@oscarpalmer/toretto/find";
|
|
5
3
|
import { isHTMLOrSVGElement } from "@oscarpalmer/toretto/is";
|
|
4
|
+
import { clamp } from "@oscarpalmer/atoms/number";
|
|
5
|
+
import { findAncestor } from "@oscarpalmer/toretto/find";
|
|
6
6
|
//#region src/js/internal/navigable.ts
|
|
7
7
|
var OuiNavigable = class {
|
|
8
8
|
active = { index: 0 };
|
|
@@ -17,7 +17,7 @@ var OuiNavigable = class {
|
|
|
17
17
|
onFocusin(this, event);
|
|
18
18
|
}), on(element, "keydown", (event) => {
|
|
19
19
|
onKeydown(this, event);
|
|
20
|
-
})];
|
|
20
|
+
}, { passive: false })];
|
|
21
21
|
this.orientation = getOrientation(element, options);
|
|
22
22
|
if (options.role != null) setRole(element, options.role);
|
|
23
23
|
}
|
package/dist/js/menu.d.mts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export {}
|
package/dist/js/menu.mjs
CHANGED
|
@@ -2,8 +2,8 @@ import { createEmbeddedFloatable, getOnBeforeToggleListener } from "./floatable/
|
|
|
2
2
|
import { attributable } from "./internal/attributable.mjs";
|
|
3
3
|
import { NAVIGABLE_KEYS_HORIZONTAL, NAVIGABLE_KEYS_VERTICAL, getNavigable, updateNavigableFocus } from "./internal/navigable.mjs";
|
|
4
4
|
import { setAria, setRole } from "@oscarpalmer/toretto/aria";
|
|
5
|
-
import { setAttribute, setAttributes } from "@oscarpalmer/toretto/attribute";
|
|
6
5
|
import { on } from "@oscarpalmer/toretto/event";
|
|
6
|
+
import { setAttribute, setAttributes } from "@oscarpalmer/toretto/attribute";
|
|
7
7
|
import { findAncestor } from "@oscarpalmer/toretto/find";
|
|
8
8
|
//#region src/js/menu.ts
|
|
9
9
|
var OuiMenu = class {
|
|
@@ -120,7 +120,8 @@ function onDeactivate(_, navigable) {
|
|
|
120
120
|
if (instance != null) updateNavigableFocus(instance.navigable, true);
|
|
121
121
|
}
|
|
122
122
|
function onPreventNavigation(_, navigable) {
|
|
123
|
-
|
|
123
|
+
const instance = menubars.get(navigable.element) ?? menus.get(navigable.element);
|
|
124
|
+
return findAncestor(instance?.element.parentElement, SELECTORS) != null;
|
|
124
125
|
}
|
|
125
126
|
function onShouldActivate(event, navigable) {
|
|
126
127
|
let activate = false;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { attributable } from "../internal/attributable.mjs";
|
|
2
2
|
import { OuiDraggable, addDraggable, getDraggableStates, removeDraggable } from "../internal/draggable.mjs";
|
|
3
|
+
import { dispatch, getEventPosition, on } from "@oscarpalmer/toretto/event";
|
|
3
4
|
import { setAttribute } from "@oscarpalmer/toretto/attribute";
|
|
4
|
-
import { dispatch, getPosition, on } from "@oscarpalmer/toretto/event";
|
|
5
|
-
import { getStyles, setStyle, setStyles } from "@oscarpalmer/toretto/style";
|
|
6
5
|
import { isHTMLOrSVGElement } from "@oscarpalmer/toretto/is";
|
|
6
|
+
import { getStyles, setStyle, setStyles } from "@oscarpalmer/toretto/style";
|
|
7
7
|
//#region src/js/movable/movable.embedded.ts
|
|
8
8
|
var OuiMovable = class extends OuiDraggable {
|
|
9
9
|
#element;
|
|
@@ -112,7 +112,7 @@ function onEnd(event, globals, item, reset) {
|
|
|
112
112
|
if (container != null) setOffset(state, container);
|
|
113
113
|
const dispatched = dispatch(state.element, "movable:end", { detail: {
|
|
114
114
|
from: { ...globals.original },
|
|
115
|
-
to:
|
|
115
|
+
to: getEventPosition(event)
|
|
116
116
|
} });
|
|
117
117
|
setTimeout(() => {
|
|
118
118
|
if (dispatched.defaultPrevented) onCancel(globals, item);
|
package/dist/js/popover.mjs
CHANGED
|
@@ -2,8 +2,8 @@ import { createEmbeddedFloatable, getOnBeforeToggleListener } from "./floatable/
|
|
|
2
2
|
import { attributable } from "./internal/attributable.mjs";
|
|
3
3
|
import { createFocusTrap } from "./focus-trap/focus-trap.embedded.mjs";
|
|
4
4
|
import { getAria, setAria } from "@oscarpalmer/toretto/aria";
|
|
5
|
-
import { setAttribute } from "@oscarpalmer/toretto/attribute";
|
|
6
5
|
import { on } from "@oscarpalmer/toretto/event";
|
|
6
|
+
import { setAttribute } from "@oscarpalmer/toretto/attribute";
|
|
7
7
|
import { isHTMLOrSVGElement } from "@oscarpalmer/toretto/is";
|
|
8
8
|
//#region src/js/popover.ts
|
|
9
9
|
var OuiPopover = class {
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { attributable } from "../internal/attributable.mjs";
|
|
2
|
-
import {
|
|
3
|
-
import { getAttribute, setAttribute } from "@oscarpalmer/toretto/attribute";
|
|
4
|
-
import { dispatch, getPosition, on } from "@oscarpalmer/toretto/event";
|
|
5
|
-
import { findAncestor } from "@oscarpalmer/toretto/find";
|
|
6
|
-
import { setStyles, toggleStyles } from "@oscarpalmer/toretto/style";
|
|
2
|
+
import { dispatch, getEventPosition, on } from "@oscarpalmer/toretto/event";
|
|
7
3
|
import { isPlainObject } from "@oscarpalmer/atoms/is";
|
|
4
|
+
import { getAttribute, setAttribute } from "@oscarpalmer/toretto/attribute";
|
|
8
5
|
import { isHTMLOrSVGElement } from "@oscarpalmer/toretto/is";
|
|
6
|
+
import { setStyles, toggleStyles } from "@oscarpalmer/toretto/style";
|
|
7
|
+
import { getNumber } from "@oscarpalmer/atoms/number";
|
|
8
|
+
import { findAncestor } from "@oscarpalmer/toretto/find";
|
|
9
9
|
import supportsTouch from "@oscarpalmer/toretto/touch";
|
|
10
10
|
//#region src/js/resizable/resizable.embedded.ts
|
|
11
11
|
var OuiResizable = class {
|
|
@@ -127,7 +127,7 @@ function onPointerdown(event) {
|
|
|
127
127
|
const handle = findAncestor(event, SELECTOR_HANDLE);
|
|
128
128
|
const element = handle && findAncestor(handle, SELECTOR);
|
|
129
129
|
const stored = element && items.get(element);
|
|
130
|
-
const position =
|
|
130
|
+
const position = getEventPosition(event);
|
|
131
131
|
if (stored == null || position == null) return;
|
|
132
132
|
if (supportsTouch.value) event.preventDefault();
|
|
133
133
|
const dispatched = dispatch(element, "resizable:begin");
|
|
@@ -141,7 +141,7 @@ function onPointerdown(event) {
|
|
|
141
141
|
}
|
|
142
142
|
function onPointermove(event) {
|
|
143
143
|
if (current == null) return;
|
|
144
|
-
const { x, y } =
|
|
144
|
+
const { x, y } = getEventPosition(event) ?? {};
|
|
145
145
|
if (x == null || y == null) return;
|
|
146
146
|
const width = current.state.width + (x - (start?.x ?? 0));
|
|
147
147
|
const height = current.state.height + (y - (start?.y ?? 0));
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { attributable } from "../internal/attributable.mjs";
|
|
2
2
|
import { OuiDraggable, addDraggable, getDraggableStates, removeDraggable } from "../internal/draggable.mjs";
|
|
3
|
+
import { dispatch, getEventPosition } from "@oscarpalmer/toretto/event";
|
|
3
4
|
import { getAttribute, setAttribute, setAttributes } from "@oscarpalmer/toretto/attribute";
|
|
4
|
-
import { createElement } from "@oscarpalmer/toretto/create";
|
|
5
|
-
import { dispatch, getPosition } from "@oscarpalmer/toretto/event";
|
|
6
|
-
import { findAncestor, getElementFromPosition } from "@oscarpalmer/toretto/find";
|
|
7
|
-
import { setStyle } from "@oscarpalmer/toretto/style";
|
|
8
5
|
import { isHTMLOrSVGElement } from "@oscarpalmer/toretto/is";
|
|
6
|
+
import { setStyle } from "@oscarpalmer/toretto/style";
|
|
7
|
+
import { findAncestor, getElementFromPosition } from "@oscarpalmer/toretto/find";
|
|
8
|
+
import { createElement } from "@oscarpalmer/toretto/create";
|
|
9
9
|
//#region src/js/sortable/sortable.embedded.ts
|
|
10
10
|
var OuiSortable = class extends OuiDraggable {
|
|
11
11
|
constructor(element, options) {
|
|
@@ -92,7 +92,7 @@ function onCancel(_, item) {
|
|
|
92
92
|
}
|
|
93
93
|
function onEnd(event, globals, item, reset) {
|
|
94
94
|
const { origin } = item.state;
|
|
95
|
-
const position =
|
|
95
|
+
const position = getEventPosition(event) ?? {
|
|
96
96
|
x: 0,
|
|
97
97
|
y: 0
|
|
98
98
|
};
|
|
@@ -258,6 +258,7 @@ const placeholder = {
|
|
|
258
258
|
position: void 0
|
|
259
259
|
};
|
|
260
260
|
const addSortable = addDraggable.bind(bound);
|
|
261
|
-
|
|
261
|
+
const removeSortable = removeDraggable.bind(bound);
|
|
262
|
+
attributable(ATTRIBUTE, addSortable, removeSortable);
|
|
262
263
|
//#endregion
|
|
263
264
|
export { OuiSortable, createSortable };
|
package/dist/js/splitter.mjs
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { clamp } from "@oscarpalmer/atoms/number";
|
|
2
1
|
import { setAria } from "@oscarpalmer/toretto/aria";
|
|
2
|
+
import { getEventPosition, on } from "@oscarpalmer/toretto/event";
|
|
3
|
+
import { isNullableOrWhitespace } from "@oscarpalmer/atoms/is";
|
|
3
4
|
import { getAttribute, setAttribute } from "@oscarpalmer/toretto/attribute";
|
|
4
|
-
import { getPosition, on } from "@oscarpalmer/toretto/event";
|
|
5
|
-
import { findAncestor } from "@oscarpalmer/toretto/find";
|
|
6
5
|
import { setStyle, toggleStyles } from "@oscarpalmer/toretto/style";
|
|
7
|
-
import {
|
|
6
|
+
import { clamp } from "@oscarpalmer/atoms/number";
|
|
7
|
+
import { findAncestor } from "@oscarpalmer/toretto/find";
|
|
8
8
|
import supportsTouch from "@oscarpalmer/toretto/touch";
|
|
9
9
|
import { round } from "@oscarpalmer/atoms/math";
|
|
10
10
|
//#region src/js/splitter.ts
|
|
@@ -130,10 +130,7 @@ var OuiSplitterElement = class extends HTMLElement {
|
|
|
130
130
|
case ATTRIBUTE_SIZE:
|
|
131
131
|
this.#splitter.updateValues();
|
|
132
132
|
break;
|
|
133
|
-
case ATTRIBUTE_TYPE:
|
|
134
|
-
this.#splitter.updateOrientation();
|
|
135
|
-
break;
|
|
136
|
-
default: break;
|
|
133
|
+
case ATTRIBUTE_TYPE: this.#splitter.updateOrientation();
|
|
137
134
|
}
|
|
138
135
|
}
|
|
139
136
|
};
|
|
@@ -213,10 +210,7 @@ function onKeydown(event) {
|
|
|
213
210
|
case KEYS_ALL.has(event.key):
|
|
214
211
|
onNavigate(event);
|
|
215
212
|
break;
|
|
216
|
-
case event.key === "Escape":
|
|
217
|
-
onEnd(true);
|
|
218
|
-
break;
|
|
219
|
-
default: break;
|
|
213
|
+
case event.key === "Escape": onEnd(true);
|
|
220
214
|
}
|
|
221
215
|
}
|
|
222
216
|
function onNavigate(event) {
|
|
@@ -256,7 +250,7 @@ function onPointerdown(event) {
|
|
|
256
250
|
}
|
|
257
251
|
function onPointermove(event) {
|
|
258
252
|
if (splitter == null) return;
|
|
259
|
-
const position =
|
|
253
|
+
const position = getEventPosition(event);
|
|
260
254
|
if (position != null) {
|
|
261
255
|
splitter.values.now.current = getSize(splitter, splitter.types.horizontal ? position.y : position.x);
|
|
262
256
|
setSize(splitter, splitter.values.now.current);
|
package/dist/js/toolbar.d.mts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export {}
|
package/dist/js/tooltip.mjs
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { createEmbeddedFloatable } from "./floatable/floatable.embedded.mjs";
|
|
2
2
|
import { attributable } from "./internal/attributable.mjs";
|
|
3
3
|
import { getAria } from "@oscarpalmer/toretto/aria";
|
|
4
|
-
import { setAttribute } from "@oscarpalmer/toretto/attribute";
|
|
5
|
-
import { createElement } from "@oscarpalmer/toretto/create";
|
|
6
4
|
import { on } from "@oscarpalmer/toretto/event";
|
|
7
|
-
import { findAncestor } from "@oscarpalmer/toretto/find";
|
|
8
5
|
import { isNullableOrWhitespace } from "@oscarpalmer/atoms/is";
|
|
6
|
+
import { setAttribute } from "@oscarpalmer/toretto/attribute";
|
|
7
|
+
import { findAncestor } from "@oscarpalmer/toretto/find";
|
|
8
|
+
import { createElement } from "@oscarpalmer/toretto/create";
|
|
9
9
|
//#region src/js/tooltip.ts
|
|
10
10
|
var OuiTooltip = class {
|
|
11
11
|
#state;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oscarpalmer/oui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.34.0",
|
|
4
4
|
"description": "Styles, components, and utilities for building websites and applications.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"css",
|
|
@@ -34,8 +34,8 @@
|
|
|
34
34
|
"default": "./dist/js/index.mjs"
|
|
35
35
|
},
|
|
36
36
|
"./combobox": {
|
|
37
|
-
"types": "./dist/js/combobox.d.mts",
|
|
38
|
-
"default": "./dist/js/combobox.mjs"
|
|
37
|
+
"types": "./dist/js/combobox/index.d.mts",
|
|
38
|
+
"default": "./dist/js/combobox/index.mjs"
|
|
39
39
|
},
|
|
40
40
|
"./dialog": {
|
|
41
41
|
"types": "./dist/js/dialog.d.mts",
|
|
@@ -95,7 +95,7 @@
|
|
|
95
95
|
},
|
|
96
96
|
"dependencies": {
|
|
97
97
|
"@oscarpalmer/atoms": "^0.188.1",
|
|
98
|
-
"@oscarpalmer/toretto": "^0.
|
|
98
|
+
"@oscarpalmer/toretto": "^0.50.1"
|
|
99
99
|
},
|
|
100
100
|
"devDependencies": {
|
|
101
101
|
"@oxlint/plugins": "^1.77",
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import type {OuiComboboxAutoCompleteType, OuiComboboxType} from './models.combobox';
|
|
2
|
+
|
|
3
|
+
// #region Variables
|
|
4
|
+
|
|
5
|
+
export const COMBOBOX_TAGNAME = 'oui-combobox';
|
|
6
|
+
|
|
7
|
+
export const COMBOBOX_ATTRIBUTE_ANCHOR = `${COMBOBOX_TAGNAME}-anchor`;
|
|
8
|
+
|
|
9
|
+
export const COMBOBOX_ATTRIBUTE_CONTENT = `${COMBOBOX_TAGNAME}-content`;
|
|
10
|
+
|
|
11
|
+
export const COMBOBOX_ATTRIBUTE_FILTER = `${COMBOBOX_TAGNAME}-filter`;
|
|
12
|
+
|
|
13
|
+
export const COMBOBOX_ATTRIBUTE_FILTER_INPUT = `${COMBOBOX_ATTRIBUTE_FILTER}-input`;
|
|
14
|
+
|
|
15
|
+
export const COMBOBOX_ATTRIBUTE_HEADER = `${COMBOBOX_TAGNAME}-header`;
|
|
16
|
+
|
|
17
|
+
export const COMBOBOX_ATTRIBUTE_HIDDEN = `${COMBOBOX_TAGNAME}-hidden`;
|
|
18
|
+
|
|
19
|
+
export const COMBOBOX_ATTRIBUTE_LIST = `${COMBOBOX_TAGNAME}-list`;
|
|
20
|
+
|
|
21
|
+
export const COMBOBOX_ATTRIBUTE_MESSAGE = `${COMBOBOX_TAGNAME}-message`;
|
|
22
|
+
|
|
23
|
+
export const COMBOBOX_ATTRIBUTE_OPTION = `${COMBOBOX_TAGNAME}-option`;
|
|
24
|
+
|
|
25
|
+
export const COMBOBOX_ATTRIBUTE_OPTION_ACTIVE = `${COMBOBOX_TAGNAME}-option-active`;
|
|
26
|
+
|
|
27
|
+
export const COMBOBOX_ATTRIBUTE_SELECTION = `${COMBOBOX_TAGNAME}-selection`;
|
|
28
|
+
|
|
29
|
+
export const COMBOBOX_ATTRIBUTE_SELECTION_ITEM = `${COMBOBOX_TAGNAME}-selection-item`;
|
|
30
|
+
|
|
31
|
+
export const COMBOBOX_AUTOCOMPLETES = new Set<OuiComboboxAutoCompleteType>([
|
|
32
|
+
'both',
|
|
33
|
+
'inline',
|
|
34
|
+
'list',
|
|
35
|
+
'none',
|
|
36
|
+
]);
|
|
37
|
+
|
|
38
|
+
export const COMBOBOX_KEYS_ACTIVATION = new Set([' ', 'Backspace', 'Delete', 'Enter']);
|
|
39
|
+
|
|
40
|
+
export const COMBOBOX_KEYS_NAVIGATION = new Set(['ArrowDown', 'ArrowUp', 'PageDown', 'PageUp']);
|
|
41
|
+
|
|
42
|
+
export const COMBOBOX_KEYS_SELECTION = new Set(['ArrowRight', 'End']);
|
|
43
|
+
|
|
44
|
+
export const COMBOBOX_MESSAGE_LABEL = `<${COMBOBOX_TAGNAME}> must contain a <label> element for the <select> element`;
|
|
45
|
+
|
|
46
|
+
export const COMBOBOX_MESSAGE_SELECT = `<${COMBOBOX_TAGNAME}> must contain a valid <select> element`;
|
|
47
|
+
|
|
48
|
+
export const COMBOBOX_SELECTOR_ANCHOR = `[${COMBOBOX_ATTRIBUTE_ANCHOR}]`;
|
|
49
|
+
|
|
50
|
+
export const COMBOBOX_SELECTOR_SELECTION_ITEM = `[${COMBOBOX_ATTRIBUTE_SELECTION_ITEM}]`;
|
|
51
|
+
|
|
52
|
+
export const COMBOBOX_SELECTOR_OPTION = `[${COMBOBOX_ATTRIBUTE_OPTION}]`;
|
|
53
|
+
|
|
54
|
+
export const COMBOBOX_TYPES = new Set<OuiComboboxType>(['autocomplete', 'select']);
|
|
55
|
+
|
|
56
|
+
export const comboboxScrollOptions: ScrollIntoViewOptions = {
|
|
57
|
+
behavior: 'auto',
|
|
58
|
+
block: 'nearest',
|
|
59
|
+
inline: 'nearest',
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
// #endregion
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
import {getString} from '@oscarpalmer/atoms/string';
|
|
2
|
+
import {setAria} from '@oscarpalmer/toretto/aria';
|
|
3
|
+
import {getData} from '@oscarpalmer/toretto/data';
|
|
4
|
+
import {
|
|
5
|
+
updateComboboxMessage,
|
|
6
|
+
updateComboboxPreview,
|
|
7
|
+
updateComboboxSelection,
|
|
8
|
+
} from './dom.combobox';
|
|
9
|
+
import {onComboboxFilter} from './event.combobox';
|
|
10
|
+
import {updateComboboxForm} from './form.combobox';
|
|
11
|
+
import type {OuiComboboxState} from './models.combobox';
|
|
12
|
+
|
|
13
|
+
// #region Types
|
|
14
|
+
|
|
15
|
+
type ApplySelectionParameters = {
|
|
16
|
+
added: boolean;
|
|
17
|
+
emit?: boolean;
|
|
18
|
+
option?: HTMLElement;
|
|
19
|
+
selected?: HTMLElement[];
|
|
20
|
+
state: OuiComboboxState;
|
|
21
|
+
values?: string[];
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
// #endregion
|
|
25
|
+
|
|
26
|
+
// #region Functions
|
|
27
|
+
|
|
28
|
+
export function applyComboboxSelection(parameters: ApplySelectionParameters): void {
|
|
29
|
+
const {added, emit, option, selected, state} = parameters;
|
|
30
|
+
|
|
31
|
+
const {length} = state.options.all;
|
|
32
|
+
|
|
33
|
+
for (let index = 0; index < length; index += 1) {
|
|
34
|
+
const option = state.options.all[index];
|
|
35
|
+
|
|
36
|
+
setAria(option, 'selected', (selected ?? state.options.selected).includes(option));
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const values =
|
|
40
|
+
parameters.values ??
|
|
41
|
+
(state.autocomplete.none
|
|
42
|
+
? [state.filter.element.value]
|
|
43
|
+
: (selected ?? state.options.selected).map(option => getData(option, 'value', false) ?? ''));
|
|
44
|
+
|
|
45
|
+
if (values.length === 0) {
|
|
46
|
+
values.push('');
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (selected != null) {
|
|
50
|
+
state.options.selected = selected;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const update =
|
|
54
|
+
values.length === state.values.current.length
|
|
55
|
+
? values.some(value => !state.values.current.includes(value))
|
|
56
|
+
: true;
|
|
57
|
+
|
|
58
|
+
if (!update) {
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
updateComboboxForm(state, values, emit);
|
|
63
|
+
updateComboboxPreview('set', state, option);
|
|
64
|
+
updateComboboxSelection(state, option, added, selected);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export function filterComboboxOption(
|
|
68
|
+
state: OuiComboboxState,
|
|
69
|
+
value: unknown,
|
|
70
|
+
textContent?: boolean,
|
|
71
|
+
): HTMLElement | undefined {
|
|
72
|
+
const filterTextContent = textContent ?? false;
|
|
73
|
+
|
|
74
|
+
const filter = getString(value).toLocaleLowerCase();
|
|
75
|
+
|
|
76
|
+
filterComboboxOptions(state);
|
|
77
|
+
|
|
78
|
+
const {length} = state.options.all;
|
|
79
|
+
let match: HTMLElement | undefined;
|
|
80
|
+
|
|
81
|
+
for (let index = 0; index < length; index += 1) {
|
|
82
|
+
const option = state.options.all[index];
|
|
83
|
+
|
|
84
|
+
const value = (
|
|
85
|
+
filterTextContent ? option.textContent : (getData(option, 'value', false) ?? '')
|
|
86
|
+
).toLocaleLowerCase();
|
|
87
|
+
|
|
88
|
+
if (value === filter) {
|
|
89
|
+
match = option;
|
|
90
|
+
|
|
91
|
+
break;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return match;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export function filterComboboxOptions(state: OuiComboboxState): HTMLElement | undefined {
|
|
99
|
+
function filter(options: HTMLElement[]): boolean {
|
|
100
|
+
const {length} = options;
|
|
101
|
+
|
|
102
|
+
let count = 0;
|
|
103
|
+
|
|
104
|
+
for (let index = 0; index < length; index += 1) {
|
|
105
|
+
const option = options[index];
|
|
106
|
+
|
|
107
|
+
option.hidden =
|
|
108
|
+
!state.autocomplete.none && !option.textContent.toLocaleLowerCase().includes(value);
|
|
109
|
+
|
|
110
|
+
if (!option.hidden) {
|
|
111
|
+
count += 1;
|
|
112
|
+
|
|
113
|
+
visible.push(option);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return count === 0;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const value = state.filter.element.value.toLocaleLowerCase();
|
|
121
|
+
|
|
122
|
+
const visible: HTMLElement[] = [];
|
|
123
|
+
|
|
124
|
+
if (state.groups == null) {
|
|
125
|
+
filter(state.options.all);
|
|
126
|
+
} else {
|
|
127
|
+
const groupsLength = state.groups.length;
|
|
128
|
+
|
|
129
|
+
for (let groupIndex = 0; groupIndex < groupsLength; groupIndex += 1) {
|
|
130
|
+
const {element, options} = state.groups[groupIndex];
|
|
131
|
+
|
|
132
|
+
element.hidden = filter(options);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
updateComboboxMessage(state, visible.length);
|
|
137
|
+
|
|
138
|
+
return state.active != null && visible.includes(state.active) ? state.active : visible[0];
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
export function setComboboxValue(state: OuiComboboxState, value: unknown, emit?: boolean): void {
|
|
142
|
+
if (state.autocomplete.none) {
|
|
143
|
+
state.filter.element.value = getString(value);
|
|
144
|
+
|
|
145
|
+
onComboboxFilter('insertText', state, true, emit);
|
|
146
|
+
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
const option = filterComboboxOption(state, value);
|
|
151
|
+
|
|
152
|
+
if (option != null) {
|
|
153
|
+
setComboboxValues(state, [value], emit);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
export function setComboboxValues(state: OuiComboboxState, value: unknown, emit?: boolean): void {
|
|
158
|
+
if (!Array.isArray(value)) {
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
const values = (state.multiple ? value : value.slice(0, 1)).map(value =>
|
|
163
|
+
getString(value).toLocaleLowerCase(),
|
|
164
|
+
);
|
|
165
|
+
|
|
166
|
+
if (values.length === 0) {
|
|
167
|
+
values.push('');
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
if (state.autocomplete.none) {
|
|
171
|
+
setComboboxValue(state, values[0], emit);
|
|
172
|
+
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
const {length} = state.options.all;
|
|
177
|
+
|
|
178
|
+
const selected: HTMLElement[] = [];
|
|
179
|
+
|
|
180
|
+
for (let index = 0; index < length; index += 1) {
|
|
181
|
+
const option = state.options.all[index];
|
|
182
|
+
|
|
183
|
+
if (values.includes(getData(option, 'value', false)?.toLocaleLowerCase() ?? '')) {
|
|
184
|
+
selected.push(option);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
applyComboboxSelection({
|
|
189
|
+
emit,
|
|
190
|
+
selected,
|
|
191
|
+
state,
|
|
192
|
+
added: true,
|
|
193
|
+
option: selected[0] ?? state.options.all[0],
|
|
194
|
+
values: state.autocomplete.none ? values : undefined,
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
export function toggleComboboxOption(state: OuiComboboxState, option?: HTMLElement): void {
|
|
199
|
+
if (option == null || (!state.multiple && state.options.selected.includes(option))) {
|
|
200
|
+
state.floatable.hide();
|
|
201
|
+
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
const selected = state.options.selected.slice();
|
|
206
|
+
|
|
207
|
+
let added = true;
|
|
208
|
+
|
|
209
|
+
if (state.multiple) {
|
|
210
|
+
const index = selected.indexOf(option);
|
|
211
|
+
|
|
212
|
+
if (index === -1) {
|
|
213
|
+
selected.push(option);
|
|
214
|
+
} else {
|
|
215
|
+
added = false;
|
|
216
|
+
|
|
217
|
+
selected.splice(index, 1);
|
|
218
|
+
}
|
|
219
|
+
} else {
|
|
220
|
+
selected.splice(0, selected.length, option);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
applyComboboxSelection({
|
|
224
|
+
added,
|
|
225
|
+
option,
|
|
226
|
+
selected,
|
|
227
|
+
state,
|
|
228
|
+
values: state.autocomplete.none && option != null ? [option.textContent] : undefined,
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
if (!state.multiple) {
|
|
232
|
+
state.floatable.hide();
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// #endregion
|