keystra 0.0.0-stage → 0.1.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.
Files changed (52) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/LICENSE +21 -0
  3. package/README.md +78 -2
  4. package/dist/chunk-2BLQUBG7.js +816 -0
  5. package/dist/chunk-77GGU3AX.js +135 -0
  6. package/dist/chunk-KDOJARJD.js +29 -0
  7. package/dist/chunk-LYYUOTBP.js +125 -0
  8. package/dist/chunk-S5YVXIMA.js +61 -0
  9. package/dist/chunk-SSIKGDD4.js +255 -0
  10. package/dist/chunk-U7YK6PPT.js +1729 -0
  11. package/dist/chunk-XFNYIPOW.js +253 -0
  12. package/dist/chunk-ZOJRXXQN.js +308 -0
  13. package/dist/core.cjs +2861 -0
  14. package/dist/core.d.cts +41 -0
  15. package/dist/core.d.ts +41 -0
  16. package/dist/core.js +7 -0
  17. package/dist/engine-COPfXXTp.d.ts +229 -0
  18. package/dist/engine-DcbkGRgz.d.cts +229 -0
  19. package/dist/focus.cjs +374 -0
  20. package/dist/focus.d.cts +74 -0
  21. package/dist/focus.d.ts +74 -0
  22. package/dist/focus.js +2 -0
  23. package/dist/index-IZkcWAXP.d.cts +395 -0
  24. package/dist/index-IZkcWAXP.d.ts +395 -0
  25. package/dist/index.cjs +3745 -0
  26. package/dist/index.d.cts +9 -0
  27. package/dist/index.d.ts +9 -0
  28. package/dist/index.global.js +1 -0
  29. package/dist/index.js +9 -0
  30. package/dist/layout-C2-n8aUI.d.ts +17 -0
  31. package/dist/layout-CBzD-87D.d.cts +17 -0
  32. package/dist/navigation.cjs +293 -0
  33. package/dist/navigation.d.cts +33 -0
  34. package/dist/navigation.d.ts +33 -0
  35. package/dist/navigation.js +2 -0
  36. package/dist/patterns.cjs +3505 -0
  37. package/dist/patterns.d.cts +12 -0
  38. package/dist/patterns.d.ts +12 -0
  39. package/dist/patterns.js +7 -0
  40. package/dist/roving-focus-CT7Dm6di.d.ts +63 -0
  41. package/dist/roving-focus-ZQ0v7hLe.d.cts +63 -0
  42. package/dist/selection.cjs +266 -0
  43. package/dist/selection.d.cts +43 -0
  44. package/dist/selection.d.ts +43 -0
  45. package/dist/selection.js +2 -0
  46. package/dist/utils-CkveVeIJ.d.cts +18 -0
  47. package/dist/utils-JmPZTlys.d.ts +18 -0
  48. package/dist/utils.cjs +195 -0
  49. package/dist/utils.d.cts +3 -0
  50. package/dist/utils.d.ts +3 -0
  51. package/dist/utils.js +2 -0
  52. package/package.json +147 -4
@@ -0,0 +1,135 @@
1
+ // src/utils/dom.ts
2
+ function hasDom() {
3
+ return typeof globalThis !== "undefined" && typeof globalThis.document !== "undefined";
4
+ }
5
+ function resolveElement(target, root = null) {
6
+ if (target == null) return null;
7
+ if (typeof target === "function") {
8
+ return resolveElement(target(), root);
9
+ }
10
+ if (typeof target === "string") {
11
+ const scope = root ?? (hasDom() ? document : null);
12
+ if (!scope) return null;
13
+ try {
14
+ return scope.querySelector(target);
15
+ } catch {
16
+ return null;
17
+ }
18
+ }
19
+ return target;
20
+ }
21
+ function queryItems(container, selector) {
22
+ if (!container) return [];
23
+ if (typeof selector === "function") {
24
+ const result = selector(container);
25
+ return Array.from(result);
26
+ }
27
+ if (!selector) return [];
28
+ try {
29
+ return Array.from(container.querySelectorAll(selector));
30
+ } catch {
31
+ return [];
32
+ }
33
+ }
34
+ var DISABLED_SELECTOR_DEFAULT = "[disabled],[aria-disabled='true']";
35
+ function isDisabled(element, selector = DISABLED_SELECTOR_DEFAULT) {
36
+ if (!selector) return false;
37
+ const html = element;
38
+ if (html.disabled === true) return true;
39
+ if (element.getAttribute("aria-disabled") === "true") return true;
40
+ if (selector === DISABLED_SELECTOR_DEFAULT) return element.hasAttribute("disabled");
41
+ try {
42
+ return element.matches(selector);
43
+ } catch {
44
+ return false;
45
+ }
46
+ }
47
+ function isHidden(element) {
48
+ const html = element;
49
+ const probe = html;
50
+ if (typeof probe.checkVisibility === "function") {
51
+ try {
52
+ return !probe.checkVisibility.call(html, { checkOpacity: false, checkVisibilityCSS: true });
53
+ } catch {
54
+ }
55
+ }
56
+ let node = html;
57
+ while (node && node.nodeType === 1) {
58
+ if (node.hidden === true) return true;
59
+ if (node.style && node.style.display === "none") return true;
60
+ node = node.parentElement;
61
+ }
62
+ return false;
63
+ }
64
+ function isFocusable(element) {
65
+ const html = element;
66
+ if (typeof html.focus !== "function") return false;
67
+ if (isDisabled(element)) return false;
68
+ return !isHidden(element);
69
+ }
70
+ var EDITABLE_SELECTOR_DEFAULT = "input:not([type='hidden']):not([readonly]),textarea:not([readonly]),select,[contenteditable=''],[contenteditable='true'],[iscontenteditable]";
71
+ function isEditableTarget(target, extraSelector) {
72
+ if (!target || typeof target.matches !== "function") return false;
73
+ const element = target;
74
+ const selector = extraSelector ? `${EDITABLE_SELECTOR_DEFAULT},${extraSelector}` : EDITABLE_SELECTOR_DEFAULT;
75
+ try {
76
+ if (element.matches(selector)) return true;
77
+ } catch {
78
+ }
79
+ const html = element;
80
+ return html.isContentEditable === true;
81
+ }
82
+ function getText(element) {
83
+ const label = element.getAttribute("aria-label") ?? element.textContent ?? "";
84
+ return label.replace(/\s+/g, " ").trim();
85
+ }
86
+ function setAttribute(element, name, value) {
87
+ if (value === null) element.removeAttribute(name);
88
+ else if (element.getAttribute(name) !== value) element.setAttribute(name, value);
89
+ }
90
+ function toggleClass(element, name, on) {
91
+ if (!name) return;
92
+ const html = element;
93
+ if (typeof html.classList?.toggle === "function") html.classList.toggle(name, on);
94
+ }
95
+ function focusElement(element, preventScroll = true) {
96
+ if (typeof element.focus !== "function") return false;
97
+ try {
98
+ element.focus({ preventScroll });
99
+ } catch {
100
+ try {
101
+ element.focus();
102
+ } catch {
103
+ return false;
104
+ }
105
+ }
106
+ return true;
107
+ }
108
+ function contains(parent, child) {
109
+ if (!parent || !child) return false;
110
+ if (parent === child) return true;
111
+ if (typeof parent.contains === "function") return parent.contains(child);
112
+ let node = child;
113
+ while (node) {
114
+ if (node === parent) return true;
115
+ node = node.parentNode;
116
+ }
117
+ return false;
118
+ }
119
+ function resolveEventTarget(target) {
120
+ if (target == null) return null;
121
+ if (typeof target === "string") return resolveElement(target);
122
+ if (typeof target === "function") return resolveEventTarget(target());
123
+ return target;
124
+ }
125
+ var idCounter = 0;
126
+ function ensureId(element, prefix) {
127
+ const existing = element.id;
128
+ if (existing) return existing;
129
+ idCounter += 1;
130
+ const generated = `${prefix}-${idCounter}`;
131
+ element.id = generated;
132
+ return generated;
133
+ }
134
+
135
+ export { contains, ensureId, focusElement, getText, hasDom, isDisabled, isEditableTarget, isFocusable, isHidden, queryItems, resolveElement, resolveEventTarget, setAttribute, toggleClass };
@@ -0,0 +1,29 @@
1
+ // src/navigation/custom.ts
2
+ function createCustomStrategy(hooks) {
3
+ const resolved = typeof hooks === "function" ? { onNavigate: hooks } : hooks;
4
+ return (context) => {
5
+ if (context.direction || isMovementAction(context.action)) {
6
+ const result2 = resolved.onNavigate?.(context);
7
+ if (typeof result2 === "number") return result2;
8
+ return resolved.fallback ? resolved.fallback(context) : null;
9
+ }
10
+ const result = resolved.onAction?.(context);
11
+ if (typeof result === "number") return result;
12
+ return resolved.onNavigate?.(context) ?? null;
13
+ };
14
+ }
15
+ function composeStrategies(...strategies) {
16
+ const list = strategies.filter(Boolean);
17
+ return (context) => {
18
+ for (let i = 0; i < list.length; i++) {
19
+ const result = list[i](context);
20
+ if (typeof result === "number" && result >= 0) return result;
21
+ }
22
+ return null;
23
+ };
24
+ }
25
+ function isMovementAction(action) {
26
+ return action === "next" || action === "previous" || action === "first" || action === "last" || action === "pageUp" || action === "pageDown";
27
+ }
28
+
29
+ export { composeStrategies, createCustomStrategy };
@@ -0,0 +1,125 @@
1
+ import { KeyMatcher, EventManager, normalizeKeyEvent, createKeystra } from './chunk-U7YK6PPT.js';
2
+ import { resolveElement, resolveEventTarget, isEditableTarget } from './chunk-77GGU3AX.js';
3
+
4
+ // src/core/hooks.ts
5
+ function resolveContainer(target) {
6
+ return resolveElement(target, typeof document !== "undefined" ? document : null);
7
+ }
8
+ function useKeystra(options = {}) {
9
+ let stored = { ...options };
10
+ let instance = null;
11
+ let container = resolveContainer(stored.container);
12
+ let detached = false;
13
+ let resumeOnAttach = false;
14
+ let destroyed = false;
15
+ const handle = {
16
+ get instance() {
17
+ return instance;
18
+ },
19
+ get container() {
20
+ return container;
21
+ },
22
+ attach(target) {
23
+ if (destroyed) return null;
24
+ const element = resolveContainer(target);
25
+ if (!element) return instance;
26
+ if (!instance) {
27
+ container = element;
28
+ instance = createKeystra({ ...stored, container: element });
29
+ return instance;
30
+ }
31
+ if (element !== container) {
32
+ container = element;
33
+ instance.update({ container: element });
34
+ }
35
+ if (detached) {
36
+ detached = false;
37
+ if (resumeOnAttach) instance.enable();
38
+ resumeOnAttach = false;
39
+ }
40
+ return instance;
41
+ },
42
+ detach() {
43
+ if (!instance || detached) return;
44
+ resumeOnAttach = instance.enabled;
45
+ detached = true;
46
+ instance.disable();
47
+ container = null;
48
+ },
49
+ destroy() {
50
+ destroyed = true;
51
+ instance?.destroy();
52
+ instance = null;
53
+ container = null;
54
+ detached = false;
55
+ resumeOnAttach = false;
56
+ }
57
+ };
58
+ if (container) handle.attach(container);
59
+ return handle;
60
+ }
61
+ var SHORTCUT_ACTION = "shortcut";
62
+ function isChord(match) {
63
+ const binding = match.binding;
64
+ return binding.ctrl === true || binding.alt === true || binding.meta === true;
65
+ }
66
+ function createKeyBinding(binding, handler, options = {}) {
67
+ const matcher = new KeyMatcher({ [SHORTCUT_ACTION]: binding }, options.sequences ?? []);
68
+ const events = new EventManager();
69
+ const capture = options.capture === true;
70
+ const shouldPrevent = options.preventDefault !== false;
71
+ const shouldStop = options.stopPropagation === true;
72
+ const allowInEditable = options.allowInEditable === true;
73
+ const editableSelector = options.editableSelector ?? null;
74
+ let disposer = null;
75
+ let destroyed = false;
76
+ function target() {
77
+ const explicit = resolveEventTarget(options.target);
78
+ if (explicit) return explicit;
79
+ return typeof document !== "undefined" ? document : null;
80
+ }
81
+ function onKeyDown(rawEvent) {
82
+ if (destroyed) return;
83
+ if (options.when && !options.when()) return;
84
+ const event = rawEvent;
85
+ const match = matcher.match(normalizeKeyEvent(event), handle);
86
+ const editable = !allowInEditable && isEditableTarget(event.target, editableSelector);
87
+ if (!match) return;
88
+ if (!match.complete) {
89
+ if (match.preventDefault && shouldPrevent && !(editable && !isChord(match))) event.preventDefault();
90
+ return;
91
+ }
92
+ if (editable && !isChord(match)) return;
93
+ if (shouldPrevent && match.preventDefault !== false) event.preventDefault();
94
+ if (shouldStop) event.stopPropagation();
95
+ handler(event, { action: match.actions[0] ?? SHORTCUT_ACTION, fromSequence: match.fromSequence });
96
+ }
97
+ const handle = {
98
+ enable() {
99
+ if (destroyed || disposer) return;
100
+ const listenOn = target();
101
+ if (!listenOn) return;
102
+ disposer = events.add(listenOn, "keydown", onKeyDown, { capture, passive: false });
103
+ },
104
+ disable() {
105
+ if (!disposer) return;
106
+ disposer();
107
+ disposer = null;
108
+ matcher.resetSequence();
109
+ },
110
+ destroy() {
111
+ destroyed = true;
112
+ handle.disable();
113
+ matcher.dispose();
114
+ events.dispose();
115
+ },
116
+ matches(event) {
117
+ const match = matcher.match(normalizeKeyEvent(event), handle);
118
+ return match !== null && match.complete;
119
+ }
120
+ };
121
+ if (options.enabled !== false) handle.enable();
122
+ return handle;
123
+ }
124
+
125
+ export { createKeyBinding, useKeystra };
@@ -0,0 +1,61 @@
1
+ // src/utils/emitter.ts
2
+ var Emitter = class {
3
+ constructor() {
4
+ this.handlers = null;
5
+ }
6
+ on(event, handler) {
7
+ if (!this.handlers) this.handlers = /* @__PURE__ */ new Map();
8
+ let set = this.handlers.get(event);
9
+ if (!set) {
10
+ set = /* @__PURE__ */ new Set();
11
+ this.handlers.set(event, set);
12
+ }
13
+ set.add(handler);
14
+ let disposed = false;
15
+ return () => {
16
+ if (disposed) return;
17
+ disposed = true;
18
+ this.off(event, handler);
19
+ };
20
+ }
21
+ off(event, handler) {
22
+ const set = this.handlers?.get(event);
23
+ if (!set) return;
24
+ if (handler) set.delete(handler);
25
+ else set.clear();
26
+ if (set.size === 0) this.handlers?.delete(event);
27
+ }
28
+ emit(event, payload) {
29
+ const set = this.handlers?.get(event);
30
+ if (!set || set.size === 0) return;
31
+ for (const handler of Array.from(set)) {
32
+ handler(payload);
33
+ }
34
+ }
35
+ clear() {
36
+ this.handlers?.clear();
37
+ this.handlers = null;
38
+ }
39
+ get size() {
40
+ if (!this.handlers) return 0;
41
+ let total = 0;
42
+ for (const set of this.handlers.values()) total += set.size;
43
+ return total;
44
+ }
45
+ };
46
+
47
+ // src/utils/layout.ts
48
+ var LayoutCache = class {
49
+ constructor() {
50
+ this.rects = /* @__PURE__ */ new WeakMap();
51
+ }
52
+ rect(element, version) {
53
+ const cached = this.rects.get(element);
54
+ if (cached && cached.version === version) return cached.rect;
55
+ const rect = element.getBoundingClientRect();
56
+ this.rects.set(element, { version, rect });
57
+ return rect;
58
+ }
59
+ };
60
+
61
+ export { Emitter, LayoutCache };
@@ -0,0 +1,255 @@
1
+ import { setAttribute, toggleClass } from './chunk-77GGU3AX.js';
2
+
3
+ // src/selection/selection-manager.ts
4
+ var SelectionManager = class {
5
+ constructor(options = {}) {
6
+ this.selectedItems = [];
7
+ this.itemsValue = [];
8
+ this.provider = null;
9
+ this.anchorElement = null;
10
+ this.touched = /* @__PURE__ */ new Set();
11
+ this.onDiff = null;
12
+ this.needsInitial = true;
13
+ this.options = options;
14
+ this.modeValue = options.mode ?? "single";
15
+ this.attribute = options.attribute ?? null;
16
+ this.selectedClass = options.selectedClass;
17
+ this.aria = options.aria === true;
18
+ }
19
+ get mode() {
20
+ return this.modeValue;
21
+ }
22
+ get selected() {
23
+ return this.selectedItems;
24
+ }
25
+ get items() {
26
+ return this.provider ? this.provider() : this.itemsValue;
27
+ }
28
+ get selectedIndexes() {
29
+ const result = [];
30
+ for (let i = 0; i < this.selectedItems.length; i++) {
31
+ const index = this.items.indexOf(this.selectedItems[i]);
32
+ if (index !== -1) result.push(index);
33
+ }
34
+ return result.sort((a, b) => a - b);
35
+ }
36
+ get anchor() {
37
+ return this.anchorElement;
38
+ }
39
+ get size() {
40
+ return this.selectedItems.length;
41
+ }
42
+ bindItems(provider) {
43
+ this.provider = provider;
44
+ }
45
+ setDiffHandler(handler) {
46
+ this.onDiff = handler;
47
+ }
48
+ sync(items) {
49
+ if (this.itemsValue === items && !this.needsInitial) return;
50
+ this.itemsValue = items;
51
+ const current = this.items;
52
+ if (this.needsInitial) {
53
+ this.needsInitial = false;
54
+ this.applyInitial(this.options.initial);
55
+ }
56
+ if (this.aria || this.attribute || this.selectedClass) {
57
+ for (let i = 0; i < current.length; i++) {
58
+ const element = current[i];
59
+ this.paint(element, this.selectedItems.indexOf(element) !== -1);
60
+ }
61
+ }
62
+ if (this.touched.size > current.length) {
63
+ for (const element of this.touched) {
64
+ if (!element.isConnected && this.selectedItems.indexOf(element) === -1) this.touched.delete(element);
65
+ }
66
+ }
67
+ if (this.selectedItems.length === 0 && this.anchorElement === null) return;
68
+ let changed = false;
69
+ const kept = [];
70
+ for (const element of this.selectedItems) {
71
+ if (current.indexOf(element) !== -1) kept.push(element);
72
+ else {
73
+ this.paint(element, false);
74
+ changed = true;
75
+ }
76
+ }
77
+ if (this.anchorElement && current.indexOf(this.anchorElement) === -1) {
78
+ this.anchorElement = kept[0] ?? null;
79
+ changed = true;
80
+ }
81
+ if (changed) {
82
+ const previous = this.selectedItems;
83
+ this.selectedItems = kept;
84
+ this.options.onChange?.(this.selectedItems);
85
+ this.onDiff?.(this.selectedItems, [], previous.filter((element) => kept.indexOf(element) === -1));
86
+ }
87
+ }
88
+ applyInitial(initial) {
89
+ if (initial == null) return;
90
+ const current = this.items;
91
+ if (typeof initial === "number") {
92
+ const element = current[initial];
93
+ if (element) this.select(element);
94
+ return;
95
+ }
96
+ const list = Array.isArray(initial) ? initial : [initial];
97
+ for (const element of list) if (element) this.select(element, this.modeValue !== "single");
98
+ }
99
+ select(elementOrIndex, extend = false) {
100
+ if (this.modeValue === "none") return;
101
+ const element = this.resolve(elementOrIndex);
102
+ if (!element) return;
103
+ if (this.modeValue === "single" || !extend && this.modeValue !== "multiple") {
104
+ if (this.selectedItems.length === 1 && this.selectedItems[0] === element) {
105
+ this.anchorElement = element;
106
+ return;
107
+ }
108
+ const removed = this.selectedItems.slice();
109
+ this.selectedItems = [element];
110
+ this.anchorElement = element;
111
+ for (const item of removed) this.paint(item, false);
112
+ this.paint(element, true);
113
+ this.emit(removed);
114
+ return;
115
+ }
116
+ if (this.modeValue === "range" && extend && this.anchorElement) {
117
+ this.selectRange(this.anchorElement, element);
118
+ return;
119
+ }
120
+ if (this.selectedItems.indexOf(element) === -1) {
121
+ const previous = this.selectedItems.slice();
122
+ this.selectedItems.push(element);
123
+ this.paint(element, true);
124
+ this.emit(previous);
125
+ }
126
+ if (!this.anchorElement) this.anchorElement = element;
127
+ }
128
+ toggle(elementOrIndex) {
129
+ if (this.modeValue === "none") return;
130
+ const element = this.resolve(elementOrIndex);
131
+ if (!element) return;
132
+ if (this.modeValue === "single") {
133
+ if (this.selectedItems[0] === element) this.clear();
134
+ else this.select(element);
135
+ return;
136
+ }
137
+ const previous = this.selectedItems.slice();
138
+ const index = previous.indexOf(element);
139
+ if (index === -1) {
140
+ this.selectedItems.push(element);
141
+ this.paint(element, true);
142
+ } else {
143
+ this.selectedItems.splice(index, 1);
144
+ this.paint(element, false);
145
+ if (this.anchorElement === element) this.anchorElement = this.selectedItems[0] ?? null;
146
+ }
147
+ this.emit(previous);
148
+ if (!this.anchorElement && index === -1) this.anchorElement = element;
149
+ }
150
+ deselect(elementOrIndex) {
151
+ const element = this.resolve(elementOrIndex);
152
+ if (!element) return;
153
+ const index = this.selectedItems.indexOf(element);
154
+ if (index === -1) return;
155
+ const previous = this.selectedItems.slice();
156
+ this.selectedItems.splice(index, 1);
157
+ this.paint(element, false);
158
+ if (this.anchorElement === element) this.anchorElement = this.selectedItems[0] ?? null;
159
+ this.emit(previous);
160
+ }
161
+ selectRange(from, to) {
162
+ if (this.modeValue === "none") return;
163
+ const start = this.resolve(from);
164
+ const end = this.resolve(to);
165
+ if (!start || !end) return;
166
+ let a = this.items.indexOf(start);
167
+ let b = this.items.indexOf(end);
168
+ if (a === -1 || b === -1) return;
169
+ if (a > b) {
170
+ const swap = a;
171
+ a = b;
172
+ b = swap;
173
+ }
174
+ const previous = this.selectedItems.slice();
175
+ const next = [];
176
+ for (let i = a; i <= b; i++) {
177
+ const element = this.items[i];
178
+ if (element) next.push(element);
179
+ }
180
+ this.selectedItems = next;
181
+ this.anchorElement = start;
182
+ for (const element of previous) if (next.indexOf(element) === -1) this.paint(element, false);
183
+ for (const element of next) this.paint(element, true);
184
+ this.emit(previous);
185
+ }
186
+ selectAll() {
187
+ if (this.modeValue === "none" || this.modeValue === "single") {
188
+ if (this.modeValue === "single" && this.items[0]) this.select(this.items[0]);
189
+ return;
190
+ }
191
+ const previous = this.selectedItems.slice();
192
+ this.selectedItems = this.items.slice();
193
+ for (const element of this.selectedItems) this.paint(element, true);
194
+ this.anchorElement = this.items[0] ?? null;
195
+ this.emit(previous);
196
+ }
197
+ clear() {
198
+ if (this.selectedItems.length === 0 && !this.anchorElement) return;
199
+ const previous = this.selectedItems.slice();
200
+ this.selectedItems = [];
201
+ this.anchorElement = null;
202
+ for (const element of previous) this.paint(element, false);
203
+ this.emit(previous);
204
+ }
205
+ isSelected(elementOrIndex) {
206
+ const element = this.resolve(elementOrIndex);
207
+ return element !== null && this.selectedItems.indexOf(element) !== -1;
208
+ }
209
+ indexOfSelected(element) {
210
+ return this.selectedItems.indexOf(element);
211
+ }
212
+ setMode(mode) {
213
+ if (mode === this.modeValue) return;
214
+ this.modeValue = mode;
215
+ if (mode === "single" && this.selectedItems.length > 1) {
216
+ const previous = this.selectedItems.slice();
217
+ this.selectedItems = previous.slice(0, 1);
218
+ for (const element of previous) if (this.selectedItems.indexOf(element) === -1) this.paint(element, false);
219
+ this.emit(previous);
220
+ }
221
+ if (mode === "none") this.clear();
222
+ }
223
+ dispose() {
224
+ this.provider = null;
225
+ for (const element of this.touched) {
226
+ if (this.aria) setAttribute(element, "aria-selected", null);
227
+ if (this.attribute) element.removeAttribute(this.attribute);
228
+ toggleClass(element, this.selectedClass, false);
229
+ }
230
+ this.touched.clear();
231
+ this.selectedItems = [];
232
+ this.anchorElement = null;
233
+ this.itemsValue = [];
234
+ }
235
+ resolve(elementOrIndex) {
236
+ if (elementOrIndex === void 0 || elementOrIndex === null) return null;
237
+ if (typeof elementOrIndex === "number") return this.items[elementOrIndex] ?? null;
238
+ return elementOrIndex;
239
+ }
240
+ paint(element, on) {
241
+ this.touched.add(element);
242
+ if (this.aria) setAttribute(element, "aria-selected", on ? "true" : "false");
243
+ if (this.attribute) setAttribute(element, this.attribute, on ? "true" : null);
244
+ toggleClass(element, this.selectedClass, on);
245
+ }
246
+ emit(previous) {
247
+ const added = this.selectedItems.filter((element) => previous.indexOf(element) === -1);
248
+ const removed = previous.filter((element) => this.selectedItems.indexOf(element) === -1);
249
+ if (added.length === 0 && removed.length === 0) return;
250
+ this.options.onChange?.(this.selectedItems);
251
+ this.onDiff?.(this.selectedItems, added, removed);
252
+ }
253
+ };
254
+
255
+ export { SelectionManager };