@digdir/designsystemet-web 1.13.2 → 1.14.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/cjs/_vendors/invokers-polyfill/invoker.cjs.map +1 -1
- package/dist/cjs/field/field.cjs +1 -1
- package/dist/cjs/field/field.cjs.map +1 -1
- package/dist/cjs/suggestion/suggestion.cjs +1 -1
- package/dist/cjs/suggestion/suggestion.cjs.map +1 -1
- package/dist/custom-elements.json +0 -7
- package/dist/esm/_vendors/invokers-polyfill/invoker.js.map +1 -1
- package/dist/esm/field/field.js +1 -1
- package/dist/esm/field/field.js.map +1 -1
- package/dist/esm/suggestion/suggestion.js +1 -1
- package/dist/esm/suggestion/suggestion.js.map +1 -1
- package/dist/index.d.ts +108 -91
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +944 -1028
- package/dist/index.js.map +1 -0
- package/dist/umd/index.js +12 -13
- package/dist/umd/index.js.map +1 -1
- package/package.json +9 -9
- package/dist/web.manifest.json +0 -1019
- package/dist/web.vscode.json +0 -60
package/dist/index.js
CHANGED
|
@@ -1,1069 +1,985 @@
|
|
|
1
|
-
|
|
1
|
+
import "@u-elements/u-details/polyfill";
|
|
2
|
+
import { autoUpdate, computePosition, flip, limitShift, offset, shift, size } from "@floating-ui/dom";
|
|
3
|
+
import { UHTMLComboboxElement } from "@u-elements/u-combobox";
|
|
4
|
+
import * as UTabs from "@u-elements/u-tabs";
|
|
5
|
+
export * from "@u-elements/u-datalist";
|
|
6
|
+
//#region ../../node_modules/.pnpm/invokers-polyfill@1.0.3/node_modules/invokers-polyfill/invoker.js
|
|
2
7
|
function isSupported() {
|
|
3
|
-
|
|
8
|
+
return typeof HTMLButtonElement !== "undefined" && "command" in HTMLButtonElement.prototype && "source" in ((globalThis.CommandEvent || {}).prototype || {});
|
|
4
9
|
}
|
|
5
10
|
function apply() {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
);
|
|
225
|
-
return;
|
|
226
|
-
}
|
|
227
|
-
const invokee = source.commandForElement;
|
|
228
|
-
if (!invokee) return;
|
|
229
|
-
const invokeEvent = new CommandEvent("command", {
|
|
230
|
-
command: source.command,
|
|
231
|
-
source,
|
|
232
|
-
cancelable: true
|
|
233
|
-
});
|
|
234
|
-
invokee.dispatchEvent(invokeEvent);
|
|
235
|
-
if (invokeEvent.defaultPrevented) return;
|
|
236
|
-
const command = invokeEvent.command.toLowerCase();
|
|
237
|
-
if (invokee.popover) {
|
|
238
|
-
const canShow = !invokee.matches(":popover-open");
|
|
239
|
-
const shouldShow = canShow && (command === "toggle-popover" || command === "show-popover");
|
|
240
|
-
const shouldHide = !canShow && command === "hide-popover";
|
|
241
|
-
if (shouldShow) {
|
|
242
|
-
invokee.showPopover({ source });
|
|
243
|
-
} else if (shouldHide) {
|
|
244
|
-
invokee.hidePopover();
|
|
245
|
-
}
|
|
246
|
-
} else if (invokee.localName === "dialog") {
|
|
247
|
-
const canShow = !invokee.hasAttribute("open");
|
|
248
|
-
if (canShow && command == "show-modal") {
|
|
249
|
-
invokee.showModal();
|
|
250
|
-
} else if (!canShow && command == "close") {
|
|
251
|
-
invokee.close(source.value ? source.value : void 0);
|
|
252
|
-
} else if (!canShow && command == "request-close") {
|
|
253
|
-
if (!HTMLDialogElement.prototype.requestClose) {
|
|
254
|
-
HTMLDialogElement.prototype.requestClose = function() {
|
|
255
|
-
const cancelEvent = new Event("cancel", { cancelable: true });
|
|
256
|
-
this.dispatchEvent(cancelEvent);
|
|
257
|
-
if (!cancelEvent.defaultPrevented) {
|
|
258
|
-
this.close();
|
|
259
|
-
}
|
|
260
|
-
};
|
|
261
|
-
}
|
|
262
|
-
invokee.requestClose(source.value ? source.value : void 0);
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
}
|
|
266
|
-
function setupInvokeListeners(target) {
|
|
267
|
-
target.addEventListener("click", handleInvokerActivation, true);
|
|
268
|
-
}
|
|
269
|
-
function observeShadowRoots(ElementClass, callback) {
|
|
270
|
-
const attachShadow = ElementClass.prototype.attachShadow;
|
|
271
|
-
ElementClass.prototype.attachShadow = function(init) {
|
|
272
|
-
const shadow = attachShadow.call(this, init);
|
|
273
|
-
callback(shadow);
|
|
274
|
-
return shadow;
|
|
275
|
-
};
|
|
276
|
-
const attachInternals = ElementClass.prototype.attachInternals;
|
|
277
|
-
ElementClass.prototype.attachInternals = function() {
|
|
278
|
-
const internals = attachInternals.call(this);
|
|
279
|
-
if (internals.shadowRoot) callback(internals.shadowRoot);
|
|
280
|
-
return internals;
|
|
281
|
-
};
|
|
282
|
-
}
|
|
283
|
-
applyInvokerMixin(HTMLButtonElement);
|
|
284
|
-
observeShadowRoots(HTMLElement, (shadow) => {
|
|
285
|
-
setupInvokeListeners(shadow);
|
|
286
|
-
oncommandObserver.observe(shadow, { attributeFilter: ["oncommand"] });
|
|
287
|
-
applyOnCommandHandler(shadow.querySelectorAll("[oncommand]"));
|
|
288
|
-
});
|
|
289
|
-
setupInvokeListeners(document);
|
|
290
|
-
Object.assign(globalThis, { CommandEvent });
|
|
11
|
+
document.addEventListener("invoke", (e) => {
|
|
12
|
+
if (e.type == "invoke" && e.isTrusted) {
|
|
13
|
+
e.stopImmediatePropagation();
|
|
14
|
+
e.preventDefault();
|
|
15
|
+
}
|
|
16
|
+
}, true);
|
|
17
|
+
document.addEventListener("command", (e) => {
|
|
18
|
+
if (e.type == "command" && e.isTrusted) {
|
|
19
|
+
e.stopImmediatePropagation();
|
|
20
|
+
e.preventDefault();
|
|
21
|
+
}
|
|
22
|
+
}, true);
|
|
23
|
+
function enumerate(obj, key, enumerable = true) {
|
|
24
|
+
Object.defineProperty(obj, key, {
|
|
25
|
+
...Object.getOwnPropertyDescriptor(obj, key),
|
|
26
|
+
enumerable
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
function getRootNode(node) {
|
|
30
|
+
if (node && typeof node.getRootNode === "function") return node.getRootNode();
|
|
31
|
+
if (node && node.parentNode) return getRootNode(node.parentNode);
|
|
32
|
+
return node;
|
|
33
|
+
}
|
|
34
|
+
const commandEventSourceElements = /* @__PURE__ */ new WeakMap();
|
|
35
|
+
const commandEventActions = /* @__PURE__ */ new WeakMap();
|
|
36
|
+
class CommandEvent extends Event {
|
|
37
|
+
constructor(type, invokeEventInit = {}) {
|
|
38
|
+
super(type, invokeEventInit);
|
|
39
|
+
const { source, command } = invokeEventInit;
|
|
40
|
+
if (source != null && !(source instanceof Element)) throw new TypeError(`source must be an element`);
|
|
41
|
+
commandEventSourceElements.set(this, source || null);
|
|
42
|
+
commandEventActions.set(this, command !== void 0 ? String(command) : "");
|
|
43
|
+
}
|
|
44
|
+
get [Symbol.toStringTag]() {
|
|
45
|
+
return "CommandEvent";
|
|
46
|
+
}
|
|
47
|
+
get source() {
|
|
48
|
+
if (!commandEventSourceElements.has(this)) throw new TypeError("illegal invocation");
|
|
49
|
+
const source = commandEventSourceElements.get(this);
|
|
50
|
+
if (!(source instanceof Element)) return null;
|
|
51
|
+
const invokerRoot = getRootNode(source);
|
|
52
|
+
if (invokerRoot !== getRootNode(this.target || document)) return invokerRoot.host;
|
|
53
|
+
return source;
|
|
54
|
+
}
|
|
55
|
+
get command() {
|
|
56
|
+
if (!commandEventActions.has(this)) throw new TypeError("illegal invocation");
|
|
57
|
+
return commandEventActions.get(this);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
enumerate(CommandEvent.prototype, "source");
|
|
61
|
+
enumerate(CommandEvent.prototype, "command");
|
|
62
|
+
const invokerAssociatedElements = /* @__PURE__ */ new WeakMap();
|
|
63
|
+
function applyInvokerMixin(ElementClass) {
|
|
64
|
+
Object.defineProperties(ElementClass.prototype, {
|
|
65
|
+
commandForElement: {
|
|
66
|
+
enumerable: true,
|
|
67
|
+
configurable: true,
|
|
68
|
+
set(targetElement) {
|
|
69
|
+
if (targetElement === null) {
|
|
70
|
+
this.removeAttribute("commandfor");
|
|
71
|
+
invokerAssociatedElements.delete(this);
|
|
72
|
+
} else if (!(targetElement instanceof Element)) throw new TypeError(`commandForElement must be an element or null`);
|
|
73
|
+
else {
|
|
74
|
+
this.setAttribute("commandfor", "");
|
|
75
|
+
const targetRootNode = getRootNode(targetElement);
|
|
76
|
+
if (getRootNode(this) === targetRootNode || targetRootNode === this.ownerDocument) invokerAssociatedElements.set(this, targetElement);
|
|
77
|
+
else invokerAssociatedElements.delete(this);
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
get() {
|
|
81
|
+
if (this.localName !== "button") return null;
|
|
82
|
+
if (this.disabled) return null;
|
|
83
|
+
if (this.form && this.getAttribute("type") !== "button") {
|
|
84
|
+
console.warn("Element with `commandFor` is a form participant. It should explicitly set `type=button` in order for `commandFor` to work");
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
const targetElement = invokerAssociatedElements.get(this);
|
|
88
|
+
if (targetElement) if (targetElement.isConnected) return targetElement;
|
|
89
|
+
else {
|
|
90
|
+
invokerAssociatedElements.delete(this);
|
|
91
|
+
return null;
|
|
92
|
+
}
|
|
93
|
+
const root = getRootNode(this);
|
|
94
|
+
const idref = this.getAttribute("commandfor");
|
|
95
|
+
if ((root instanceof Document || root instanceof ShadowRoot) && idref) return root.getElementById(idref) || null;
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
command: {
|
|
100
|
+
enumerable: true,
|
|
101
|
+
configurable: true,
|
|
102
|
+
get() {
|
|
103
|
+
const value = this.getAttribute("command") || "";
|
|
104
|
+
if (value.startsWith("--")) return value;
|
|
105
|
+
const valueLower = value.toLowerCase();
|
|
106
|
+
switch (valueLower) {
|
|
107
|
+
case "show-modal":
|
|
108
|
+
case "request-close":
|
|
109
|
+
case "close":
|
|
110
|
+
case "toggle-popover":
|
|
111
|
+
case "hide-popover":
|
|
112
|
+
case "show-popover": return valueLower;
|
|
113
|
+
}
|
|
114
|
+
return "";
|
|
115
|
+
},
|
|
116
|
+
set(value) {
|
|
117
|
+
this.setAttribute("command", value);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
const onHandlers = /* @__PURE__ */ new WeakMap();
|
|
123
|
+
Object.defineProperties(HTMLElement.prototype, { oncommand: {
|
|
124
|
+
enumerable: true,
|
|
125
|
+
configurable: true,
|
|
126
|
+
get() {
|
|
127
|
+
oncommandObserver.takeRecords();
|
|
128
|
+
return onHandlers.get(this) || null;
|
|
129
|
+
},
|
|
130
|
+
set(handler) {
|
|
131
|
+
const existing = onHandlers.get(this) || null;
|
|
132
|
+
if (existing) this.removeEventListener("command", existing);
|
|
133
|
+
onHandlers.set(this, typeof handler === "object" || typeof handler === "function" ? handler : null);
|
|
134
|
+
if (typeof handler == "function") this.addEventListener("command", handler);
|
|
135
|
+
}
|
|
136
|
+
} });
|
|
137
|
+
function applyOnCommandHandler(els) {
|
|
138
|
+
for (const el of els) el.oncommand = new Function("event", el.getAttribute("oncommand"));
|
|
139
|
+
}
|
|
140
|
+
const oncommandObserver = new MutationObserver((records) => {
|
|
141
|
+
for (const record of records) {
|
|
142
|
+
const { target } = record;
|
|
143
|
+
if (record.type === "childList") applyOnCommandHandler(target.querySelectorAll("[oncommand]"));
|
|
144
|
+
else applyOnCommandHandler([target]);
|
|
145
|
+
}
|
|
146
|
+
});
|
|
147
|
+
oncommandObserver.observe(document, {
|
|
148
|
+
subtree: true,
|
|
149
|
+
childList: true,
|
|
150
|
+
attributeFilter: ["oncommand"]
|
|
151
|
+
});
|
|
152
|
+
applyOnCommandHandler(document.querySelectorAll("[oncommand]"));
|
|
153
|
+
const processedEvents = /* @__PURE__ */ new WeakSet();
|
|
154
|
+
function handleInvokerActivation(event) {
|
|
155
|
+
if (processedEvents.has(event)) return;
|
|
156
|
+
processedEvents.add(event);
|
|
157
|
+
if (event.defaultPrevented) return;
|
|
158
|
+
if (event.type !== "click") return;
|
|
159
|
+
const source = event.composedPath().find((el) => el.matches?.("button[commandfor], button[command]"));
|
|
160
|
+
if (!source) return;
|
|
161
|
+
if (source.form && source.getAttribute("type") !== "button") {
|
|
162
|
+
event.preventDefault();
|
|
163
|
+
throw new Error("Element with `commandFor` is a form participant. It should explicitly set `type=button` in order for `commandFor` to work. In order for it to act as a Submit button, it must not have command or commandfor attributes");
|
|
164
|
+
}
|
|
165
|
+
if (source.hasAttribute("command") !== source.hasAttribute("commandfor")) {
|
|
166
|
+
const attr = source.hasAttribute("command") ? "command" : "commandfor";
|
|
167
|
+
const missing = source.hasAttribute("command") ? "commandfor" : "command";
|
|
168
|
+
throw new Error(`Element with ${attr} attribute must also have a ${missing} attribute to function.`);
|
|
169
|
+
}
|
|
170
|
+
if (source.command !== "show-popover" && source.command !== "hide-popover" && source.command !== "toggle-popover" && source.command !== "show-modal" && source.command !== "request-close" && source.command !== "close" && !source.command.startsWith("--")) {
|
|
171
|
+
console.warn(`"${source.command}" is not a valid command value. Custom commands must begin with --`);
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
const invokee = source.commandForElement;
|
|
175
|
+
if (!invokee) return;
|
|
176
|
+
const invokeEvent = new CommandEvent("command", {
|
|
177
|
+
command: source.command,
|
|
178
|
+
source,
|
|
179
|
+
cancelable: true
|
|
180
|
+
});
|
|
181
|
+
invokee.dispatchEvent(invokeEvent);
|
|
182
|
+
if (invokeEvent.defaultPrevented) return;
|
|
183
|
+
const command = invokeEvent.command.toLowerCase();
|
|
184
|
+
if (invokee.popover) {
|
|
185
|
+
const canShow = !invokee.matches(":popover-open");
|
|
186
|
+
const shouldShow = canShow && (command === "toggle-popover" || command === "show-popover");
|
|
187
|
+
const shouldHide = !canShow && command === "hide-popover";
|
|
188
|
+
if (shouldShow) invokee.showPopover({ source });
|
|
189
|
+
else if (shouldHide) invokee.hidePopover();
|
|
190
|
+
} else if (invokee.localName === "dialog") {
|
|
191
|
+
const canShow = !invokee.hasAttribute("open");
|
|
192
|
+
if (canShow && command == "show-modal") invokee.showModal();
|
|
193
|
+
else if (!canShow && command == "close") invokee.close(source.value ? source.value : void 0);
|
|
194
|
+
else if (!canShow && command == "request-close") {
|
|
195
|
+
if (!HTMLDialogElement.prototype.requestClose) HTMLDialogElement.prototype.requestClose = function() {
|
|
196
|
+
const cancelEvent = new Event("cancel", { cancelable: true });
|
|
197
|
+
this.dispatchEvent(cancelEvent);
|
|
198
|
+
if (!cancelEvent.defaultPrevented) this.close();
|
|
199
|
+
};
|
|
200
|
+
invokee.requestClose(source.value ? source.value : void 0);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
function setupInvokeListeners(target) {
|
|
205
|
+
target.addEventListener("click", handleInvokerActivation, true);
|
|
206
|
+
}
|
|
207
|
+
function observeShadowRoots(ElementClass, callback) {
|
|
208
|
+
const attachShadow = ElementClass.prototype.attachShadow;
|
|
209
|
+
ElementClass.prototype.attachShadow = function(init) {
|
|
210
|
+
const shadow = attachShadow.call(this, init);
|
|
211
|
+
callback(shadow);
|
|
212
|
+
return shadow;
|
|
213
|
+
};
|
|
214
|
+
const attachInternals = ElementClass.prototype.attachInternals;
|
|
215
|
+
ElementClass.prototype.attachInternals = function() {
|
|
216
|
+
const internals = attachInternals.call(this);
|
|
217
|
+
if (internals.shadowRoot) callback(internals.shadowRoot);
|
|
218
|
+
return internals;
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
applyInvokerMixin(HTMLButtonElement);
|
|
222
|
+
observeShadowRoots(HTMLElement, (shadow) => {
|
|
223
|
+
setupInvokeListeners(shadow);
|
|
224
|
+
oncommandObserver.observe(shadow, { attributeFilter: ["oncommand"] });
|
|
225
|
+
applyOnCommandHandler(shadow.querySelectorAll("[oncommand]"));
|
|
226
|
+
});
|
|
227
|
+
setupInvokeListeners(document);
|
|
228
|
+
Object.assign(globalThis, { CommandEvent });
|
|
291
229
|
}
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
230
|
+
//#endregion
|
|
231
|
+
//#region src/utils/utils.ts
|
|
232
|
+
const QUICK_EVENT = {
|
|
233
|
+
passive: true,
|
|
234
|
+
capture: true
|
|
235
|
+
};
|
|
236
|
+
const isBrowser = () => typeof window !== "undefined" && typeof document !== "undefined";
|
|
237
|
+
const isWindows = () => isBrowser() && /^Win/i.test(navigator.userAgentData?.platform || navigator.platform);
|
|
238
|
+
const DSElement = typeof HTMLElement === "undefined" ? class {} : HTMLElement;
|
|
300
239
|
function debounce(callback, delay) {
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
240
|
+
let timer;
|
|
241
|
+
return function(...args) {
|
|
242
|
+
clearTimeout(timer);
|
|
243
|
+
timer = setTimeout(() => callback.apply(this, args), delay);
|
|
244
|
+
};
|
|
306
245
|
}
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
246
|
+
const warn = (message, ...args) => !isBrowser() || window.dsWarnings === false || console.log(`\x1B[1mDesignsystemet:\x1B[m ${message}`, ...args);
|
|
247
|
+
/**
|
|
248
|
+
* attr
|
|
249
|
+
* @description Utility to quickly get, set and remove attributes
|
|
250
|
+
* @param el The Element to read/write attributes from
|
|
251
|
+
* @param name The attribute name to get, set or remove, or a object to set multiple attributes
|
|
252
|
+
* @param value A valid attribute value or null to remove attribute
|
|
253
|
+
*/
|
|
254
|
+
const attr = (el, name, value) => {
|
|
255
|
+
if (value === void 0) return el.getAttribute(name) ?? null;
|
|
256
|
+
if (value === null) el.removeAttribute(name);
|
|
257
|
+
else if (el.getAttribute(name) !== value) el.setAttribute(name, value);
|
|
258
|
+
return null;
|
|
259
|
+
};
|
|
260
|
+
/**
|
|
261
|
+
* getCSSProp
|
|
262
|
+
* @description Retrieves and CSS property value and trims it
|
|
263
|
+
* @param el The Element to read attributes/CSS from
|
|
264
|
+
* @param name Attribute or CSS property to get
|
|
265
|
+
* @return string CSS property value
|
|
266
|
+
*/
|
|
267
|
+
const getCSSProp = (el, prop) => getComputedStyle(el).getPropertyValue(prop).trim();
|
|
268
|
+
const STRIP_QUOTES = /^["']|["']$/g;
|
|
269
|
+
/**
|
|
270
|
+
* attrOrCSS
|
|
271
|
+
* @description Retrieves and updates attribute based on attribute or CSS property value
|
|
272
|
+
* @param el The Element to read attributes/CSS from
|
|
273
|
+
* @param name Attribute or CSS property to get
|
|
274
|
+
* @return string attribute or CSS property value
|
|
275
|
+
*/
|
|
276
|
+
const attrOrCSS = (el, name) => {
|
|
277
|
+
let value = attr(el, name);
|
|
278
|
+
if (!value) value = getCSSProp(el, `--_ds-${name}`).replace(STRIP_QUOTES, "").trim();
|
|
279
|
+
if (!value) warn(`Missing ${name} on:`, el);
|
|
280
|
+
return value || null;
|
|
281
|
+
};
|
|
282
|
+
/**
|
|
283
|
+
* on
|
|
284
|
+
* @param el The Element to use as EventTarget
|
|
285
|
+
* @param types A space separated string of event types
|
|
286
|
+
* @param listener An event listener function or listener object
|
|
287
|
+
*/
|
|
288
|
+
const on = (el, ...rest) => {
|
|
289
|
+
const [types, ...options] = rest;
|
|
290
|
+
for (const type of types.split(" ")) el.addEventListener(type, ...options);
|
|
291
|
+
return () => off(el, ...rest);
|
|
292
|
+
};
|
|
293
|
+
/**
|
|
294
|
+
* off
|
|
295
|
+
* @param el The Element to use as EventTarget
|
|
296
|
+
* @param types A space separated string of event types
|
|
297
|
+
* @param listener An event listener function or listener object
|
|
298
|
+
*/
|
|
299
|
+
const off = (el, ...rest) => {
|
|
300
|
+
const [types, ...options] = rest;
|
|
301
|
+
for (const type of types.split(" ")) el.removeEventListener(type, ...options);
|
|
302
|
+
};
|
|
303
|
+
/**
|
|
304
|
+
* onHotReload
|
|
305
|
+
* @description Runs a callback when window is loaded in browser, and ensures cleanup when hot-reloading
|
|
306
|
+
* @param key The key to identify setup and corresponding cleanup
|
|
307
|
+
* @param callback The callback to run when the page is ready
|
|
308
|
+
*/
|
|
309
|
+
const onHotReload = (key, setup) => {
|
|
310
|
+
if (!isBrowser()) return;
|
|
311
|
+
if (!window._dsHotReloadCleanup) window._dsHotReloadCleanup = /* @__PURE__ */ new Map();
|
|
312
|
+
window._dsHotReloadCleanup?.get(key)?.map((cleanup) => cleanup());
|
|
313
|
+
window._dsHotReloadCleanup?.set(key, setup());
|
|
314
|
+
};
|
|
315
|
+
/**
|
|
316
|
+
* MutationObserver wrapper with automatic cleanup
|
|
317
|
+
* @return new MutaionObserver
|
|
318
|
+
*/
|
|
319
|
+
const onMutation = (el, callback, options) => {
|
|
320
|
+
const cleanup = () => observer.disconnect();
|
|
321
|
+
const observer = new MutationObserver((records) => {
|
|
322
|
+
if (!isBrowser() || !el.isConnected) return cleanup();
|
|
323
|
+
callback(el, records);
|
|
324
|
+
});
|
|
325
|
+
callback(el);
|
|
326
|
+
observer.observe(el, options);
|
|
327
|
+
return cleanup;
|
|
328
|
+
};
|
|
329
|
+
/**
|
|
330
|
+
* tag
|
|
331
|
+
* @description creates element and assigns properties
|
|
332
|
+
* @param tagName The tagname of element to create
|
|
333
|
+
* @param attrs Optional attributes to add to the element
|
|
334
|
+
* @param text Optional text content to add to the element
|
|
335
|
+
* @return HTMLElement with props
|
|
336
|
+
*/
|
|
337
|
+
const tag = (tagName, attrs) => {
|
|
338
|
+
const el = document.createElement(tagName);
|
|
339
|
+
if (attrs) for (const [key, val] of Object.entries(attrs)) attr(el, key, val);
|
|
340
|
+
return el;
|
|
341
|
+
};
|
|
342
|
+
/**
|
|
343
|
+
* customElements.define
|
|
344
|
+
* @description Defines a customElement if running in browser and if not already registered
|
|
345
|
+
* Scoped/named "customElements.define" so @custom-elements-manifest/analyzer can find tag names
|
|
346
|
+
*/
|
|
347
|
+
const customElements = { define: (name, instance) => !isBrowser() || window.customElements.get(name) || window.customElements.define(name, instance) };
|
|
348
|
+
let id = 0;
|
|
357
349
|
function useId(el) {
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
350
|
+
if (!isBrowser()) return `:ds:${++id}`;
|
|
351
|
+
if (!window.dsUseId) window.dsUseId = 0;
|
|
352
|
+
if (el && !el.id) el.id = `:ds:${++window.dsUseId}`;
|
|
353
|
+
return el?.id || "";
|
|
362
354
|
}
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
}
|
|
433
|
-
|
|
434
|
-
const r = el?.closest?.("dialog")?.getBoundingClientRect();
|
|
435
|
-
const isInside = r && r.top <= y && y <= r.bottom && r.left <= x && x <= r.right;
|
|
436
|
-
DOWN_INSIDE = !!isInside;
|
|
437
|
-
} else {
|
|
438
|
-
const isDialog = el instanceof HTMLDialogElement;
|
|
439
|
-
const isClose = isDialog && !DOWN_INSIDE && attr(el, "closedby") === "any";
|
|
440
|
-
DOWN_INSIDE = false;
|
|
441
|
-
if (isClose) requestAnimationFrame(() => el.open && el.close());
|
|
442
|
-
}
|
|
443
|
-
};
|
|
444
|
-
var BUTTONS = isBrowser() ? document.getElementsByTagName("button") : [];
|
|
445
|
-
var handleAriaAttributes = () => {
|
|
446
|
-
for (const btn of BUTTONS)
|
|
447
|
-
if (btn.getAttribute("command")?.endsWith("-modal"))
|
|
448
|
-
btn.setAttribute("aria-haspopup", "dialog");
|
|
449
|
-
};
|
|
450
|
-
var handleCommand = ({ command, target }) => command === "--show-non-modal" && target instanceof HTMLDialogElement && target.show();
|
|
355
|
+
/**
|
|
356
|
+
* @description Based off speak function from [U-elements](https://github.com/u-elements/u-elements/blob/main/packages/utils.ts#L210)
|
|
357
|
+
* @param text The text to announce
|
|
358
|
+
*/
|
|
359
|
+
let LIVE_EL;
|
|
360
|
+
let LIVE_FIX = 0;
|
|
361
|
+
let LIVE_CLEAR = 0;
|
|
362
|
+
const announce = (text) => {
|
|
363
|
+
clearTimeout(LIVE_CLEAR);
|
|
364
|
+
if (LIVE_EL) LIVE_EL.textContent = `${text}${LIVE_FIX++ % 2 ? "\xA0" : ""}`;
|
|
365
|
+
if (text) LIVE_CLEAR = setTimeout(announce, 2e3, "");
|
|
366
|
+
};
|
|
367
|
+
const announceMount = () => {
|
|
368
|
+
if (document.readyState !== "complete") return;
|
|
369
|
+
if (!LIVE_EL) {
|
|
370
|
+
LIVE_EL = tag("div", { "aria-live": "assertive" });
|
|
371
|
+
LIVE_EL.style.overflow = "hidden";
|
|
372
|
+
LIVE_EL.style.position = "fixed";
|
|
373
|
+
LIVE_EL.style.whiteSpace = "nowrap";
|
|
374
|
+
LIVE_EL.style.width = "1px";
|
|
375
|
+
}
|
|
376
|
+
if (!LIVE_EL.isConnected) document.body.appendChild(LIVE_EL);
|
|
377
|
+
};
|
|
378
|
+
onHotReload("announce", () => [on(document, "focus mouseover", announceMount, QUICK_EVENT)]);
|
|
379
|
+
//#endregion
|
|
380
|
+
//#region src/clickdelegatefor/clickdelegatefor.ts
|
|
381
|
+
const CLASS_HOVER = ":click-delegate-hover";
|
|
382
|
+
const ATTR_CLICKDELEGATEFOR = "data-clickdelegatefor";
|
|
383
|
+
const SELECTOR_CLICKDELEGATEFOR = `[${ATTR_CLICKDELEGATEFOR}]`;
|
|
384
|
+
const SELECTOR_SKIP = "a,button,label,input,select,textarea,details,dialog,[role=\"button\"],[popover],[contenteditable]";
|
|
385
|
+
const handleClickDelegateFor = (event) => {
|
|
386
|
+
const isNewTab = event.button === 1 || event.metaKey || event.ctrlKey;
|
|
387
|
+
const delegateTarget = event.button < 2 && getDelegateTarget(event);
|
|
388
|
+
if (!delegateTarget || delegateTarget.contains(event.target)) return;
|
|
389
|
+
if (isNewTab && delegateTarget instanceof HTMLAnchorElement) return window.open(delegateTarget.href, void 0, delegateTarget.rel);
|
|
390
|
+
event.stopImmediatePropagation();
|
|
391
|
+
delegateTarget.click();
|
|
392
|
+
};
|
|
393
|
+
let HOVER;
|
|
394
|
+
const handleMouseOver = (event) => {
|
|
395
|
+
const delegateTarget = getDelegateTarget(event);
|
|
396
|
+
if (HOVER === delegateTarget) return;
|
|
397
|
+
if (HOVER) HOVER.classList.remove(CLASS_HOVER);
|
|
398
|
+
if (delegateTarget) delegateTarget.classList.add(CLASS_HOVER);
|
|
399
|
+
HOVER = delegateTarget;
|
|
400
|
+
};
|
|
401
|
+
const getDelegateTarget = ({ target: el }) => {
|
|
402
|
+
const id = (el instanceof Element ? el.closest(SELECTOR_CLICKDELEGATEFOR) : null)?.getAttribute(ATTR_CLICKDELEGATEFOR);
|
|
403
|
+
const target = id && document.getElementById(id) || void 0;
|
|
404
|
+
const skip = target && el.closest(SELECTOR_SKIP);
|
|
405
|
+
return (!skip || skip === target) && !target?.disabled ? target : void 0;
|
|
406
|
+
};
|
|
407
|
+
onHotReload("clickdelegatefor", () => [on(window, "click auxclick", handleClickDelegateFor, true), on(document, "mouseover", handleMouseOver, QUICK_EVENT)]);
|
|
408
|
+
//#endregion
|
|
409
|
+
//#region src/dialog/dialog.ts
|
|
410
|
+
let DOWN_INSIDE = false;
|
|
411
|
+
const handleClosedbyAny = ({ type, target: el, clientX: x = 0, clientY: y = 0 }) => {
|
|
412
|
+
if (type === "pointerdown") {
|
|
413
|
+
const r = el?.closest?.("dialog")?.getBoundingClientRect();
|
|
414
|
+
DOWN_INSIDE = !!(r && r.top <= y && y <= r.bottom && r.left <= x && x <= r.right);
|
|
415
|
+
} else {
|
|
416
|
+
const isClose = el instanceof HTMLDialogElement && !DOWN_INSIDE && attr(el, "closedby") === "any";
|
|
417
|
+
DOWN_INSIDE = false;
|
|
418
|
+
if (isClose) requestAnimationFrame(() => el.open && el.close());
|
|
419
|
+
}
|
|
420
|
+
};
|
|
421
|
+
const BUTTONS = isBrowser() ? document.getElementsByTagName("button") : [];
|
|
422
|
+
const handleAriaAttributes$2 = () => {
|
|
423
|
+
for (const btn of BUTTONS) if (btn.getAttribute("command")?.endsWith("-modal")) btn.setAttribute("aria-haspopup", "dialog");
|
|
424
|
+
};
|
|
425
|
+
const handleCommand = ({ command, target }) => command === "--show-non-modal" && target instanceof HTMLDialogElement && target.show();
|
|
451
426
|
onHotReload("dialog", () => [
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
]);
|
|
461
|
-
|
|
462
|
-
// src/fieldset/fieldset.ts
|
|
463
|
-
var FIELDSETS = isBrowser() ? document.getElementsByTagName("fieldset") : [];
|
|
464
|
-
var handleFieldsetMutations = () => {
|
|
465
|
-
for (const el of FIELDSETS) {
|
|
466
|
-
if (el.hasAttribute("aria-labelledby")) continue;
|
|
467
|
-
const labelledby = `${useId(el.querySelector("legend"))} ${useId(el.querySelector(':scope > :is([data-field="description"],legend + p)'))}`;
|
|
468
|
-
attr(el, "aria-labelledby", labelledby.trim() || null);
|
|
469
|
-
}
|
|
470
|
-
};
|
|
471
|
-
onHotReload("fieldset", () => [
|
|
472
|
-
onMutation(document, handleFieldsetMutations, {
|
|
473
|
-
childList: true,
|
|
474
|
-
subtree: true
|
|
475
|
-
})
|
|
427
|
+
on(document, "command", handleCommand, QUICK_EVENT),
|
|
428
|
+
on(document, "pointerdown pointerup", handleClosedbyAny, QUICK_EVENT),
|
|
429
|
+
onMutation(document, handleAriaAttributes$2, {
|
|
430
|
+
attributeFilter: ["command"],
|
|
431
|
+
attributes: true,
|
|
432
|
+
childList: true,
|
|
433
|
+
subtree: true
|
|
434
|
+
})
|
|
476
435
|
]);
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
436
|
+
//#endregion
|
|
437
|
+
//#region src/fieldset/fieldset.ts
|
|
438
|
+
const FIELDSETS = isBrowser() ? document.getElementsByTagName("fieldset") : [];
|
|
439
|
+
const handleFieldsetMutations = () => {
|
|
440
|
+
for (const el of FIELDSETS) {
|
|
441
|
+
if (el.hasAttribute("aria-labelledby")) continue;
|
|
442
|
+
attr(el, "aria-labelledby", `${useId(el.querySelector("legend"))} ${useId(el.querySelector(":scope > :is([data-field=\"description\"],legend + p)"))}`.trim() || null);
|
|
443
|
+
}
|
|
444
|
+
};
|
|
445
|
+
onHotReload("fieldset", () => [onMutation(document, handleFieldsetMutations, {
|
|
446
|
+
childList: true,
|
|
447
|
+
subtree: true
|
|
448
|
+
})]);
|
|
449
|
+
//#endregion
|
|
450
|
+
//#region src/popover/popover.ts
|
|
451
|
+
const ATTR_PLACE = "data-placement";
|
|
452
|
+
const ATTR_AUTO = "data-autoplacement";
|
|
453
|
+
const POPOVERS = /* @__PURE__ */ new Map();
|
|
491
454
|
function handleToggle(event) {
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
if (!source?.isConnected) return POPOVERS.get(el)?.();
|
|
537
|
-
const { x, y } = await computePosition(source, el, options);
|
|
538
|
-
el.style.translate = `${x}px ${y}px`;
|
|
539
|
-
});
|
|
540
|
-
POPOVERS.set(el, () => POPOVERS.delete(el) && unfloat());
|
|
455
|
+
let { newState, oldState, target: el, source = event.detail } = event;
|
|
456
|
+
const float = el instanceof HTMLElement && attr(el, "popover") !== null && getCSSProp(el, "--_ds-floating");
|
|
457
|
+
if (!float) return;
|
|
458
|
+
if (newState === "closed") return POPOVERS.get(el)?.();
|
|
459
|
+
if (!source) {
|
|
460
|
+
const root = el.getRootNode();
|
|
461
|
+
const css = `[popovertarget="${el.id}"],[commandfor="${el.id}"]`;
|
|
462
|
+
source = el.id && root?.querySelector?.(css) || void 0;
|
|
463
|
+
}
|
|
464
|
+
if (!source || source === el || oldState && oldState === newState) return;
|
|
465
|
+
const padding = 10;
|
|
466
|
+
const overscroll = getCSSProp(el, "--_ds-floating-overscroll");
|
|
467
|
+
const placement = attr(el, ATTR_PLACE) || attr(source, ATTR_PLACE) || float;
|
|
468
|
+
const auto = attr(el, ATTR_AUTO) || attr(source, ATTR_AUTO);
|
|
469
|
+
const arrowSize = parseFloat(getComputedStyle(el, "::before").height) || 0;
|
|
470
|
+
const shiftProp = placement.match(/left|right/gi) ? "Height" : "Width";
|
|
471
|
+
const shiftLimit = source[`offset${shiftProp}`] / 2 + arrowSize;
|
|
472
|
+
if (placement === "none") return;
|
|
473
|
+
const options = {
|
|
474
|
+
strategy: "absolute",
|
|
475
|
+
placement,
|
|
476
|
+
middleware: [
|
|
477
|
+
offset(arrowSize || 0),
|
|
478
|
+
shift({
|
|
479
|
+
padding,
|
|
480
|
+
limiter: limitShift({ offset: { mainAxis: shiftLimit } })
|
|
481
|
+
}),
|
|
482
|
+
arrowPseudo(),
|
|
483
|
+
...auto !== "false" ? [flip({
|
|
484
|
+
padding,
|
|
485
|
+
crossAxis: false
|
|
486
|
+
})] : [],
|
|
487
|
+
...overscroll ? [size({ apply({ availableHeight }) {
|
|
488
|
+
if (overscroll === "fit") el.style.width = `${source.clientWidth}px`;
|
|
489
|
+
el.style.maxHeight = `${Math.max(50, availableHeight - padding * 2)}px`;
|
|
490
|
+
} })] : []
|
|
491
|
+
]
|
|
492
|
+
};
|
|
493
|
+
const unfloat = autoUpdate(source, el, async () => {
|
|
494
|
+
if (!source?.isConnected) return POPOVERS.get(el)?.();
|
|
495
|
+
const { x, y } = await computePosition(source, el, options);
|
|
496
|
+
el.style.translate = `${x}px ${y}px`;
|
|
497
|
+
});
|
|
498
|
+
POPOVERS.set(el, () => POPOVERS.delete(el) && unfloat());
|
|
541
499
|
}
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
target.style.setProperty("--_ds-floating-arrow-x", x);
|
|
562
|
-
target.style.setProperty("--_ds-floating-arrow-y", y);
|
|
563
|
-
attr(target, "data-floating", data.placement);
|
|
564
|
-
return data;
|
|
565
|
-
}
|
|
500
|
+
let IS_SCROLL;
|
|
501
|
+
const handleScrollbar = ({ type }) => {
|
|
502
|
+
if (type === "mousedown") IS_SCROLL = false;
|
|
503
|
+
if (type === "scroll" && IS_SCROLL === false) IS_SCROLL = true;
|
|
504
|
+
if (type === "mouseup" && IS_SCROLL) for (const [popover] of POPOVERS) popover.showPopover();
|
|
505
|
+
};
|
|
506
|
+
onHotReload("popover", () => [on(document, "mousedown scroll mouseup", handleScrollbar, true), on(document, "toggle ds-toggle-source", handleToggle, QUICK_EVENT)]);
|
|
507
|
+
const arrowPseudo = () => ({
|
|
508
|
+
name: "arrowPseudo",
|
|
509
|
+
fn(data) {
|
|
510
|
+
const target = data.elements.floating;
|
|
511
|
+
const source = data.rects.reference;
|
|
512
|
+
const x = `${Math.round(source.width / 2 + source.x - data.x)}px`;
|
|
513
|
+
const y = `${Math.round(source.height / 2 + source.y - data.y)}px`;
|
|
514
|
+
target.style.setProperty("--_ds-floating-arrow-x", x);
|
|
515
|
+
target.style.setProperty("--_ds-floating-arrow-y", y);
|
|
516
|
+
attr(target, "data-floating", data.placement);
|
|
517
|
+
return data;
|
|
518
|
+
}
|
|
566
519
|
});
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
if (e.target instanceof HTMLSelectElement && isReadOnly(e.target))
|
|
592
|
-
e.preventDefault();
|
|
520
|
+
//#endregion
|
|
521
|
+
//#region src/readonly/readonly.ts
|
|
522
|
+
const isReadOnly = (el) => (el instanceof HTMLSelectElement || el instanceof HTMLInputElement) && (el.hasAttribute("readonly") || attr(el, "aria-readonly") === "true");
|
|
523
|
+
const handleKeyDown = (e) => {
|
|
524
|
+
if (e.key !== "Tab" && isReadOnly(e.target)) {
|
|
525
|
+
const isArrow = e.key?.startsWith("Arrow");
|
|
526
|
+
const isModifier = e.altKey || e.ctrlKey || e.metaKey;
|
|
527
|
+
if (isArrow || !isModifier) e.preventDefault();
|
|
528
|
+
if (isArrow && attr(e.target, "type") === "radio") {
|
|
529
|
+
const all = document.querySelectorAll(`input[name="${e.target.name}"]`);
|
|
530
|
+
const move = e.key?.match(/Arrow(Right|Down)/) ? 1 : -1;
|
|
531
|
+
all[(all.length + [...all].indexOf(e.target) + move) % all.length]?.focus();
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
};
|
|
535
|
+
const handleClick = (e) => {
|
|
536
|
+
const input = e.target?.closest?.("label")?.control || e.target;
|
|
537
|
+
if (isReadOnly(input)) {
|
|
538
|
+
e.preventDefault();
|
|
539
|
+
input.focus();
|
|
540
|
+
}
|
|
541
|
+
};
|
|
542
|
+
const handleMouseDown = (e) => {
|
|
543
|
+
if (e.target instanceof HTMLSelectElement && isReadOnly(e.target)) e.preventDefault();
|
|
593
544
|
};
|
|
594
545
|
onHotReload("readonly", () => [
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
on(document, "mousedown", handleMouseDown)
|
|
599
|
-
// mousedown needed for <select>
|
|
546
|
+
on(document, "keydown", handleKeyDown),
|
|
547
|
+
on(document, "click", handleClick),
|
|
548
|
+
on(document, "mousedown", handleMouseDown)
|
|
600
549
|
]);
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
SOURCE = void 0;
|
|
722
|
-
SKIP_TIMER = setTimeout(handleClose, DELAY_SKIP);
|
|
723
|
-
}
|
|
550
|
+
//#endregion
|
|
551
|
+
//#region src/toggle-group/toggle-group.ts
|
|
552
|
+
const ARIA_LABELLEDBY = "aria-labelledby";
|
|
553
|
+
const ARIA_LABEL$1 = "aria-label";
|
|
554
|
+
const ATTR_TOGGLEGROUP = "data-toggle-group";
|
|
555
|
+
const SELECTOR_TOGGLEGROUP = `[${ATTR_TOGGLEGROUP}]`;
|
|
556
|
+
const handleAriaAttributes$1 = () => {
|
|
557
|
+
for (const group of document.querySelectorAll(SELECTOR_TOGGLEGROUP)) attr(group, "aria-label", attrOrCSS(group, ATTR_TOGGLEGROUP));
|
|
558
|
+
};
|
|
559
|
+
const handleKeydown = (event) => {
|
|
560
|
+
const { key, target: el } = event;
|
|
561
|
+
const group = el instanceof HTMLInputElement && el.closest(SELECTOR_TOGGLEGROUP);
|
|
562
|
+
if (!group) return;
|
|
563
|
+
if (!attr(group, ARIA_LABEL$1) && !attr(group, ARIA_LABELLEDBY)) attr(group, ARIA_LABEL$1, attrOrCSS(group, ATTR_TOGGLEGROUP));
|
|
564
|
+
if (key === "Enter") el.click();
|
|
565
|
+
if (key?.startsWith("Arrow")) {
|
|
566
|
+
event.preventDefault?.();
|
|
567
|
+
const inputs = [...group.getElementsByTagName("input")];
|
|
568
|
+
const index = inputs.indexOf(el);
|
|
569
|
+
const move = key.match(/Arrow(Right|Down)/) ? 1 : -1;
|
|
570
|
+
let nextIndex = index;
|
|
571
|
+
for (let i = 0; i < inputs.length; i++) {
|
|
572
|
+
nextIndex = (inputs.length + nextIndex + move) % inputs.length;
|
|
573
|
+
if (!inputs[nextIndex]?.disabled) {
|
|
574
|
+
inputs[nextIndex]?.focus();
|
|
575
|
+
break;
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
};
|
|
580
|
+
onHotReload("toggle-group", () => [on(document, "keydown", handleKeydown), onMutation(document, handleAriaAttributes$1, {
|
|
581
|
+
attributeFilter: [ATTR_TOGGLEGROUP],
|
|
582
|
+
attributes: true,
|
|
583
|
+
childList: true,
|
|
584
|
+
subtree: true
|
|
585
|
+
})]);
|
|
586
|
+
//#endregion
|
|
587
|
+
//#region src/tooltip/tooltip.ts
|
|
588
|
+
let TIP;
|
|
589
|
+
let SOURCE;
|
|
590
|
+
let IS_HOVERING = false;
|
|
591
|
+
let HOVER_TIMER = 0;
|
|
592
|
+
let SKIP_TIMER = 0;
|
|
593
|
+
const IS_IOS = isBrowser() && /iPad|iPhone|iPod/.test(navigator.userAgent);
|
|
594
|
+
const ATTR_TOOLTIP = "data-tooltip";
|
|
595
|
+
const ATTR_COLOR = "data-color";
|
|
596
|
+
const ARIA_LABEL = "aria-label";
|
|
597
|
+
const ARIA_DESC = "aria-description";
|
|
598
|
+
const SELECTOR_COLOR = `[${ATTR_COLOR}]`;
|
|
599
|
+
const SELECTOR_TOOLTIP = `[${ATTR_TOOLTIP}]`;
|
|
600
|
+
const ATTR_SCHEME = "data-color-scheme";
|
|
601
|
+
const SELECTOR_SCHEME = `[${ATTR_SCHEME}]`;
|
|
602
|
+
const SELECTOR_INTERACTIVE = "a,button,input,label,select,textarea,[tabindex]";
|
|
603
|
+
const DELAY_HOVER = 300;
|
|
604
|
+
const DELAY_SKIP = 300;
|
|
605
|
+
/**
|
|
606
|
+
* setTooltipElement
|
|
607
|
+
* @description Allows setting a custom tooltip element. It does not need to, and should not, be injected to document.body, as we inject on hover to ensure React hydration works as expected.
|
|
608
|
+
* @param el The HTMLElement to use as tooltip
|
|
609
|
+
*/
|
|
610
|
+
const setTooltipElement = (el) => {
|
|
611
|
+
if (el && !(el instanceof HTMLElement)) warn("setTooltipElement expects an HTMLElement, got: ", el);
|
|
612
|
+
clearTimeout(SKIP_TIMER);
|
|
613
|
+
clearTimeout(HOVER_TIMER);
|
|
614
|
+
SOURCE = void 0;
|
|
615
|
+
IS_HOVERING = false;
|
|
616
|
+
TIP = el || void 0;
|
|
617
|
+
};
|
|
618
|
+
const handleAriaAttributes = () => {
|
|
619
|
+
for (const el of document.querySelectorAll(SELECTOR_TOOLTIP)) {
|
|
620
|
+
const text = attrOrCSS(el, ATTR_TOOLTIP);
|
|
621
|
+
if (!text) return;
|
|
622
|
+
if (text !== (el.getAttribute(ARIA_LABEL) || el.getAttribute(ARIA_DESC))) {
|
|
623
|
+
const hasText = attr(el, "role") !== "img" && el.textContent?.trim();
|
|
624
|
+
attr(el, ATTR_TOOLTIP, text);
|
|
625
|
+
attr(el, ARIA_LABEL, hasText ? null : text);
|
|
626
|
+
attr(el, ARIA_DESC, hasText ? text : null);
|
|
627
|
+
if (!el.matches(SELECTOR_INTERACTIVE)) warn("Missing tabindex=\"0\" attribute on: ", el);
|
|
628
|
+
}
|
|
629
|
+
const isCurrent = el === SOURCE && TIP?.offsetHeight && TIP?.offsetWidth;
|
|
630
|
+
const isChanged = isCurrent && text && TIP?.textContent !== text;
|
|
631
|
+
if (isCurrent && isChanged) {
|
|
632
|
+
if (TIP) TIP.textContent = text;
|
|
633
|
+
if (document.activeElement === el) announce(text);
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
};
|
|
637
|
+
const handleInterest = ({ type, target }) => {
|
|
638
|
+
clearTimeout(HOVER_TIMER);
|
|
639
|
+
if (target === TIP) return;
|
|
640
|
+
if (type === "mouseover" && !IS_HOVERING && !IS_IOS) {
|
|
641
|
+
HOVER_TIMER = setTimeout(handleInterest, DELAY_HOVER, { target });
|
|
642
|
+
return;
|
|
643
|
+
}
|
|
644
|
+
const source = target?.closest?.(`[${ATTR_TOOLTIP}]`);
|
|
645
|
+
if (source === SOURCE) return;
|
|
646
|
+
if (!source) return hideTooltip();
|
|
647
|
+
if (!TIP) TIP = tag("div", { class: "ds-tooltip" });
|
|
648
|
+
if (!TIP.isConnected) document.body.appendChild(TIP);
|
|
649
|
+
const color = source.closest(SELECTOR_COLOR);
|
|
650
|
+
const scheme = source.closest(SELECTOR_SCHEME);
|
|
651
|
+
const isReset = color !== scheme && color?.contains(scheme);
|
|
652
|
+
clearTimeout(SKIP_TIMER);
|
|
653
|
+
attr(TIP, "popover", "manual");
|
|
654
|
+
attr(TIP, ATTR_SCHEME, scheme?.getAttribute(ATTR_SCHEME) || null);
|
|
655
|
+
attr(TIP, ATTR_COLOR, isReset && color?.getAttribute(ATTR_COLOR) || null);
|
|
656
|
+
TIP.textContent = attr(source, ATTR_TOOLTIP);
|
|
657
|
+
TIP.showPopover();
|
|
658
|
+
TIP.dispatchEvent(new CustomEvent("ds-toggle-source", { detail: source }));
|
|
659
|
+
IS_HOVERING = true;
|
|
660
|
+
SOURCE = source;
|
|
661
|
+
};
|
|
662
|
+
const hideTooltip = () => TIP?.isConnected && TIP.popover && TIP.hidePopover();
|
|
663
|
+
const handleClose = (event) => {
|
|
664
|
+
if (event?.type === "keydown") return event?.key === "Escape" && hideTooltip();
|
|
665
|
+
if (!event) IS_HOVERING = false;
|
|
666
|
+
else if (event.target === TIP && event.newState === "closed") {
|
|
667
|
+
SOURCE = void 0;
|
|
668
|
+
SKIP_TIMER = setTimeout(handleClose, DELAY_SKIP);
|
|
669
|
+
}
|
|
724
670
|
};
|
|
725
671
|
onHotReload("tooltip", () => [
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
672
|
+
on(document, "blur focus mouseover", handleInterest, QUICK_EVENT),
|
|
673
|
+
on(document, "toggle keydown", handleClose, QUICK_EVENT),
|
|
674
|
+
onMutation(document, handleAriaAttributes, {
|
|
675
|
+
attributeFilter: [ATTR_TOOLTIP],
|
|
676
|
+
attributes: true,
|
|
677
|
+
childList: true,
|
|
678
|
+
subtree: true
|
|
679
|
+
})
|
|
734
680
|
]);
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
// src/breadcrumbs/breadcrumbs.ts
|
|
740
|
-
var ATTR_LABEL = "aria-label";
|
|
681
|
+
//#endregion
|
|
682
|
+
//#region src/breadcrumbs/breadcrumbs.ts
|
|
683
|
+
const ATTR_LABEL$1 = "aria-label";
|
|
741
684
|
var DSBreadcrumbsElement = class extends DSElement {
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
for (const item of self._items || [])
|
|
778
|
-
attr(item, "aria-current", item === lastItemInList ? "page" : null);
|
|
685
|
+
_items;
|
|
686
|
+
_label = null;
|
|
687
|
+
_unresize;
|
|
688
|
+
_unmutate;
|
|
689
|
+
static get observedAttributes() {
|
|
690
|
+
return [ATTR_LABEL$1];
|
|
691
|
+
}
|
|
692
|
+
connectedCallback() {
|
|
693
|
+
const resize = debounce(() => render$3(this), 100);
|
|
694
|
+
this._label = attrOrCSS(this, ATTR_LABEL$1);
|
|
695
|
+
this._items = this.getElementsByTagName("a");
|
|
696
|
+
this._unresize = on(window, "resize", resize);
|
|
697
|
+
this._unmutate = onMutation(this, render$3, {
|
|
698
|
+
childList: true,
|
|
699
|
+
subtree: true
|
|
700
|
+
});
|
|
701
|
+
}
|
|
702
|
+
attributeChangedCallback(_name, _prev, next) {
|
|
703
|
+
if (!this._unmutate || !next) return;
|
|
704
|
+
this._label = next;
|
|
705
|
+
render$3(this);
|
|
706
|
+
}
|
|
707
|
+
disconnectedCallback() {
|
|
708
|
+
this._unresize?.();
|
|
709
|
+
this._unmutate?.();
|
|
710
|
+
this._unresize = this._unmutate = this._items = void 0;
|
|
711
|
+
}
|
|
712
|
+
};
|
|
713
|
+
const render$3 = (self) => {
|
|
714
|
+
const lastItem = self._items?.[self._items.length - 1];
|
|
715
|
+
const lastItemInList = lastItem?.parentElement === self ? null : lastItem;
|
|
716
|
+
const isListHidden = !lastItemInList?.offsetHeight;
|
|
717
|
+
attr(self, "role", isListHidden ? null : "navigation");
|
|
718
|
+
attr(self, ATTR_LABEL$1, isListHidden ? null : self._label);
|
|
719
|
+
for (const item of self._items || []) attr(item, "aria-current", item === lastItemInList ? "page" : null);
|
|
779
720
|
};
|
|
780
721
|
customElements.define("ds-breadcrumbs", DSBreadcrumbsElement);
|
|
781
|
-
|
|
782
|
-
|
|
722
|
+
//#endregion
|
|
723
|
+
//#region src/error-summary/error-summary.ts
|
|
783
724
|
var DSErrorSummaryElement = class extends DSElement {
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
if (heading) attr(self, "aria-labelledby", useId(heading));
|
|
725
|
+
_unmutate;
|
|
726
|
+
connectedCallback() {
|
|
727
|
+
on(this, "animationend", this, QUICK_EVENT);
|
|
728
|
+
attr(this, "tabindex", "-1");
|
|
729
|
+
this._unmutate = onMutation(this, render$2, {
|
|
730
|
+
childList: true,
|
|
731
|
+
subtree: true
|
|
732
|
+
});
|
|
733
|
+
this.focus();
|
|
734
|
+
}
|
|
735
|
+
handleEvent({ target }) {
|
|
736
|
+
if (target === this) this.focus();
|
|
737
|
+
}
|
|
738
|
+
disconnectedCallback() {
|
|
739
|
+
off(this, "animationend", this, QUICK_EVENT);
|
|
740
|
+
this._unmutate?.();
|
|
741
|
+
this._unmutate = void 0;
|
|
742
|
+
}
|
|
743
|
+
};
|
|
744
|
+
const render$2 = (self) => {
|
|
745
|
+
const heading = self.querySelector("h2,h3,h4,h5,h6");
|
|
746
|
+
if (heading) attr(self, "aria-labelledby", useId(heading));
|
|
807
747
|
};
|
|
808
748
|
customElements.define("ds-error-summary", DSErrorSummaryElement);
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
};
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
input.style.setProperty("--_ds-field-sizing", "auto");
|
|
897
|
-
input.style.setProperty("--_ds-field-sizing", `${input.scrollHeight}px`);
|
|
898
|
-
}
|
|
899
|
-
};
|
|
900
|
-
var debouncedCounterLiveRegion = debounce((input, text) => {
|
|
901
|
-
if (document.activeElement === input) announce(text);
|
|
749
|
+
//#endregion
|
|
750
|
+
//#region src/field/field.ts
|
|
751
|
+
const ATTR_INVALID = "aria-invalid";
|
|
752
|
+
const ATTR_DESCRIBEDBY = "aria-describedby";
|
|
753
|
+
const ATTR_INDETERMINATE = "data-indeterminate";
|
|
754
|
+
const COUNTER_DEBOUNCE = isWindows() ? 800 : 200;
|
|
755
|
+
const COUNTS = /* @__PURE__ */ new WeakMap();
|
|
756
|
+
const FIELDS = /* @__PURE__ */ new Map();
|
|
757
|
+
const VALIDATIONS = /* @__PURE__ */ new WeakSet();
|
|
758
|
+
const WARNING_MULTIPLE_INPUTS = `Fields should only have one input element. Use <fieldset> to group multiple fields:`;
|
|
759
|
+
const handleFieldMutations = (_doc, records = []) => {
|
|
760
|
+
for (const { target } of records) {
|
|
761
|
+
const isFieldset = target instanceof HTMLFieldSetElement;
|
|
762
|
+
for (const [field] of FIELDS) if (isFieldset ? target.contains(field) : field.contains(target)) handleFieldMutation(field);
|
|
763
|
+
}
|
|
764
|
+
};
|
|
765
|
+
const handleFieldMutation = (field) => {
|
|
766
|
+
const labels = [];
|
|
767
|
+
const nextDescs = [];
|
|
768
|
+
const prevDescs = FIELDS.get(field) || [];
|
|
769
|
+
let input;
|
|
770
|
+
let counter;
|
|
771
|
+
let hasValidation = false;
|
|
772
|
+
let invalid = false;
|
|
773
|
+
for (const el of field.getElementsByTagName("*")) {
|
|
774
|
+
if (el instanceof HTMLLabelElement) labels.push(el);
|
|
775
|
+
if (el.hidden) continue;
|
|
776
|
+
if (isInputLike(el)) if (input) warn(WARNING_MULTIPLE_INPUTS, field);
|
|
777
|
+
else input = el;
|
|
778
|
+
else {
|
|
779
|
+
const type = el.getAttribute("data-field");
|
|
780
|
+
if (type === "counter") counter = el;
|
|
781
|
+
if (type === "validation") {
|
|
782
|
+
nextDescs.unshift(useId(el));
|
|
783
|
+
hasValidation = true;
|
|
784
|
+
invalid = invalid || isInvalid(el);
|
|
785
|
+
} else if (type) nextDescs.push(useId(el));
|
|
786
|
+
}
|
|
787
|
+
}
|
|
788
|
+
if (!input) return;
|
|
789
|
+
if (counter) COUNTS.set(input, counter);
|
|
790
|
+
for (const label of labels) attr(label, "for", useId(input));
|
|
791
|
+
const fieldsetValidation = field.closest("fieldset")?.querySelector(":scope > [data-field=\"validation\"]");
|
|
792
|
+
if (fieldsetValidation && !fieldsetValidation?.hidden) {
|
|
793
|
+
hasValidation = true;
|
|
794
|
+
invalid = invalid || isInvalid(fieldsetValidation);
|
|
795
|
+
nextDescs.unshift(useId(fieldsetValidation));
|
|
796
|
+
}
|
|
797
|
+
const indeterminate = attr(input, ATTR_INDETERMINATE);
|
|
798
|
+
if (indeterminate) input.indeterminate = indeterminate === "true";
|
|
799
|
+
if (input.type === "radio" || input.type === "checkbox") attr(field, "data-clickdelegatefor", useId(input));
|
|
800
|
+
const keep = (attr(input, ATTR_DESCRIBEDBY)?.trim().split(/\s+/))?.filter((id) => !prevDescs.includes(id)) || [];
|
|
801
|
+
attr(input, ATTR_DESCRIBEDBY, [...nextDescs, ...keep].join(" ") || null);
|
|
802
|
+
FIELDS.set(field, nextDescs);
|
|
803
|
+
const hadValidation = VALIDATIONS.has(input);
|
|
804
|
+
if (hasValidation && !hadValidation && !input.hasAttribute(ATTR_INVALID)) {
|
|
805
|
+
attr(input, ATTR_INVALID, "true");
|
|
806
|
+
VALIDATIONS.add(input);
|
|
807
|
+
} else if (!hasValidation && hadValidation) {
|
|
808
|
+
attr(input, ATTR_INVALID, null);
|
|
809
|
+
VALIDATIONS.delete(input);
|
|
810
|
+
}
|
|
811
|
+
handleFieldInput(input);
|
|
812
|
+
};
|
|
813
|
+
const TEXTS = {
|
|
814
|
+
over: "%d tegn for mye",
|
|
815
|
+
under: "%d tegn igjen"
|
|
816
|
+
};
|
|
817
|
+
const handleFieldInput = (e) => {
|
|
818
|
+
const input = e.target || e;
|
|
819
|
+
const counter = COUNTS.get(input);
|
|
820
|
+
if (counter?.isConnected) {
|
|
821
|
+
const count = (Number(attr(counter, "data-limit")) || 0) - input.value.length;
|
|
822
|
+
const state = count < 0 ? "over" : "under";
|
|
823
|
+
const label = (attrOrCSS(counter, `data-${state}`) || TEXTS[state])?.replace("%d", `${Math.abs(count)}`);
|
|
824
|
+
attr(counter, "data-label", label);
|
|
825
|
+
attr(counter, "data-state", state);
|
|
826
|
+
attr(counter, "data-color", count < 0 ? "danger" : null);
|
|
827
|
+
if (e.type === "input" && label) debouncedCounterLiveRegion(input, label);
|
|
828
|
+
}
|
|
829
|
+
if (input instanceof HTMLTextAreaElement) {
|
|
830
|
+
input.style.setProperty("--_ds-field-sizing", "auto");
|
|
831
|
+
input.style.setProperty("--_ds-field-sizing", `${input.scrollHeight}px`);
|
|
832
|
+
}
|
|
833
|
+
};
|
|
834
|
+
const debouncedCounterLiveRegion = debounce((input, text) => {
|
|
835
|
+
if (document.activeElement === input) announce(text);
|
|
902
836
|
}, COUNTER_DEBOUNCE);
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
!(el instanceof HTMLButtonElement) && // But skip <button> elements
|
|
906
|
-
el.type !== "hidden";
|
|
837
|
+
const isInvalid = (el) => el.getAttribute("data-color") !== "success";
|
|
838
|
+
const isInputLike = (el) => el instanceof HTMLElement && "validity" in el && !(el instanceof HTMLButtonElement) && el.type !== "hidden";
|
|
907
839
|
var DSFieldElement = class extends DSElement {
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
840
|
+
connectedCallback() {
|
|
841
|
+
FIELDS.set(this, []);
|
|
842
|
+
handleFieldMutation(this);
|
|
843
|
+
}
|
|
844
|
+
disconnectedCallback() {
|
|
845
|
+
FIELDS.delete(this);
|
|
846
|
+
}
|
|
915
847
|
};
|
|
916
848
|
customElements.define("ds-field", DSFieldElement);
|
|
917
|
-
onHotReload("field", () => [
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
next: current < total ? current + 1 : 0,
|
|
945
|
-
pages: getSteps(current, total, show).map((page, index) => ({
|
|
946
|
-
current: page === current && "page",
|
|
947
|
-
key: `key-${page}-${index}`,
|
|
948
|
-
page
|
|
949
|
-
}))
|
|
849
|
+
onHotReload("field", () => [on(document, "input", handleFieldInput, QUICK_EVENT), onMutation(document, handleFieldMutations, {
|
|
850
|
+
attributeFilter: [
|
|
851
|
+
"data-field",
|
|
852
|
+
"data-limit",
|
|
853
|
+
"hidden",
|
|
854
|
+
"id",
|
|
855
|
+
"value",
|
|
856
|
+
ATTR_INDETERMINATE
|
|
857
|
+
],
|
|
858
|
+
attributes: true,
|
|
859
|
+
childList: true,
|
|
860
|
+
subtree: true
|
|
861
|
+
})]);
|
|
862
|
+
//#endregion
|
|
863
|
+
//#region src/pagination/pagination.ts
|
|
864
|
+
const ATTR_LABEL = "aria-label";
|
|
865
|
+
const ATTR_CURRENT = "data-current";
|
|
866
|
+
const ATTR_TOTAL = "data-total";
|
|
867
|
+
const ATTR_HREF = "data-href";
|
|
868
|
+
const pagination = ({ current = 1, total = 10, show = 7 }) => ({
|
|
869
|
+
prev: current > 1 ? current - 1 : 0,
|
|
870
|
+
next: current < total ? current + 1 : 0,
|
|
871
|
+
pages: getSteps(current, total, show).map((page, index) => ({
|
|
872
|
+
current: page === current && "page",
|
|
873
|
+
key: `key-${page}-${index}`,
|
|
874
|
+
page
|
|
875
|
+
}))
|
|
950
876
|
});
|
|
951
877
|
var DSPaginationElement = class extends DSElement {
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
};
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
878
|
+
_unmutate;
|
|
879
|
+
_render;
|
|
880
|
+
static get observedAttributes() {
|
|
881
|
+
return [
|
|
882
|
+
ATTR_LABEL,
|
|
883
|
+
ATTR_CURRENT,
|
|
884
|
+
ATTR_TOTAL,
|
|
885
|
+
ATTR_HREF
|
|
886
|
+
];
|
|
887
|
+
}
|
|
888
|
+
connectedCallback() {
|
|
889
|
+
const total = attr(this, ATTR_TOTAL);
|
|
890
|
+
const current = attr(this, ATTR_CURRENT);
|
|
891
|
+
if (current && !total) warn(`Missing ${ATTR_TOTAL} attribute on:`, this);
|
|
892
|
+
if (total && !current) warn(`Missing ${ATTR_CURRENT} attribute on:`, this);
|
|
893
|
+
attr(this, ATTR_LABEL, attrOrCSS(this, ATTR_LABEL));
|
|
894
|
+
attr(this, "role", "navigation");
|
|
895
|
+
this._unmutate = onMutation(this, render$1, {
|
|
896
|
+
childList: true,
|
|
897
|
+
subtree: true
|
|
898
|
+
});
|
|
899
|
+
}
|
|
900
|
+
attributeChangedCallback() {
|
|
901
|
+
if (this._unmutate) render$1(this);
|
|
902
|
+
}
|
|
903
|
+
disconnectedCallback() {
|
|
904
|
+
this._unmutate?.();
|
|
905
|
+
this._unmutate = this._render = void 0;
|
|
906
|
+
}
|
|
907
|
+
};
|
|
908
|
+
const render$1 = (self) => {
|
|
909
|
+
const current = Number(attr(self, ATTR_CURRENT));
|
|
910
|
+
const total = Number(attr(self, ATTR_TOTAL));
|
|
911
|
+
if (current && total) {
|
|
912
|
+
const items = self.querySelectorAll("button,a");
|
|
913
|
+
const show = items.length - 2;
|
|
914
|
+
const href = attr(self, ATTR_HREF);
|
|
915
|
+
const { next, prev, pages } = pagination({
|
|
916
|
+
current,
|
|
917
|
+
total,
|
|
918
|
+
show
|
|
919
|
+
});
|
|
920
|
+
items.forEach((item, i) => {
|
|
921
|
+
const page = i ? items[i + 1] ? pages[i - 1]?.page : next : prev;
|
|
922
|
+
attr(item, "aria-current", pages[i - 1]?.current ? "true" : null);
|
|
923
|
+
attr(item, "aria-label", `${page ?? "hidden"}`);
|
|
924
|
+
attr(item, "role", page ? null : "none");
|
|
925
|
+
attr(item, "tabindex", page ? null : "-1");
|
|
926
|
+
if (item instanceof HTMLButtonElement) attr(item, "value", `${page}`);
|
|
927
|
+
if (href && item instanceof HTMLAnchorElement) attr(item, "href", href.replace("%d", `${page}`));
|
|
928
|
+
});
|
|
929
|
+
}
|
|
930
|
+
};
|
|
931
|
+
const getSteps = (now, max, show = Number.POSITIVE_INFINITY) => {
|
|
932
|
+
const offset = (show - 1) / 2;
|
|
933
|
+
const start = Math.max(Math.min(now - Math.floor(offset), max - show + 1), 1);
|
|
934
|
+
const end = Math.min(Math.max(now + Math.ceil(offset), show), max);
|
|
935
|
+
const pages = Array.from({ length: end + 1 - start }, (_, i) => i + start);
|
|
936
|
+
if (show > 4 && start > 1) pages.splice(0, 2, 1, 0);
|
|
937
|
+
if (show > 3 && end < max) pages.splice(-2, 2, 0, max);
|
|
938
|
+
return pages;
|
|
1006
939
|
};
|
|
1007
940
|
customElements.define("ds-pagination", DSPaginationElement);
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
import { UHTMLComboboxElement } from "@u-elements/u-combobox";
|
|
941
|
+
//#endregion
|
|
942
|
+
//#region src/suggestion/suggestion.ts
|
|
1011
943
|
var DSSuggestionElement = class extends UHTMLComboboxElement {
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
if (detail)
|
|
1036
|
-
self.list?.dispatchEvent(new CustomEvent("ds-toggle-source", { detail }));
|
|
944
|
+
_unmutate;
|
|
945
|
+
connectedCallback() {
|
|
946
|
+
super.connectedCallback();
|
|
947
|
+
this._unmutate = onMutation(this, render, { childList: true });
|
|
948
|
+
on(this, "toggle", polyfillToggleSource, QUICK_EVENT);
|
|
949
|
+
}
|
|
950
|
+
disconnectedCallback() {
|
|
951
|
+
super.disconnectedCallback();
|
|
952
|
+
this._unmutate?.();
|
|
953
|
+
this._unmutate = void 0;
|
|
954
|
+
off(this, "toggle", polyfillToggleSource, QUICK_EVENT);
|
|
955
|
+
}
|
|
956
|
+
};
|
|
957
|
+
const render = ({ control, list }) => {
|
|
958
|
+
if (control && !control.placeholder) attr(control, "placeholder", " ");
|
|
959
|
+
if (control) attr(control, "popovertarget", useId(list) || null);
|
|
960
|
+
if (list) attr(list, "popover", "manual");
|
|
961
|
+
if (list) attr(list, "data-is-floating", "true");
|
|
962
|
+
};
|
|
963
|
+
const polyfillToggleSource = (event) => {
|
|
964
|
+
const self = event.currentTarget;
|
|
965
|
+
const detail = event.newState === "open" && self.control;
|
|
966
|
+
if (detail) self.list?.dispatchEvent(new CustomEvent("ds-toggle-source", { detail }));
|
|
1037
967
|
};
|
|
1038
968
|
customElements.define("ds-suggestion", DSSuggestionElement);
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
var
|
|
1043
|
-
};
|
|
1044
|
-
var
|
|
1045
|
-
};
|
|
1046
|
-
var DSTabElement = class extends UTabs.UHTMLTabElement {
|
|
1047
|
-
};
|
|
1048
|
-
var DSTabPanelElement = class extends UTabs.UHTMLTabPanelElement {
|
|
1049
|
-
};
|
|
969
|
+
//#endregion
|
|
970
|
+
//#region src/tabs/tabs.ts
|
|
971
|
+
var DSTabsElement = class extends UTabs.UHTMLTabsElement {};
|
|
972
|
+
var DSTabListElement = class extends UTabs.UHTMLTabListElement {};
|
|
973
|
+
var DSTabElement = class extends UTabs.UHTMLTabElement {};
|
|
974
|
+
var DSTabPanelElement = class extends UTabs.UHTMLTabPanelElement {};
|
|
1050
975
|
customElements.define("ds-tabs", DSTabsElement);
|
|
1051
976
|
customElements.define("ds-tablist", DSTabListElement);
|
|
1052
977
|
customElements.define("ds-tab", DSTabElement);
|
|
1053
978
|
customElements.define("ds-tabpanel", DSTabPanelElement);
|
|
1054
|
-
|
|
1055
|
-
|
|
979
|
+
//#endregion
|
|
980
|
+
//#region src/index.ts
|
|
1056
981
|
if (isBrowser() && !isSupported()) apply();
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
DSPaginationElement,
|
|
1062
|
-
DSSuggestionElement,
|
|
1063
|
-
DSTabElement,
|
|
1064
|
-
DSTabListElement,
|
|
1065
|
-
DSTabPanelElement,
|
|
1066
|
-
DSTabsElement,
|
|
1067
|
-
pagination,
|
|
1068
|
-
setTooltipElement
|
|
1069
|
-
};
|
|
982
|
+
//#endregion
|
|
983
|
+
export { DSBreadcrumbsElement, DSErrorSummaryElement, DSFieldElement, DSPaginationElement, DSSuggestionElement, DSTabElement, DSTabListElement, DSTabPanelElement, DSTabsElement, pagination, setTooltipElement };
|
|
984
|
+
|
|
985
|
+
//# sourceMappingURL=index.js.map
|