@k2b/ui 0.41.0 → 0.42.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/base.css +22 -0
- package/dist/browser/actions/Dropdown.js +220 -110
- package/dist/browser/actions/Dropdown.js.map +1 -1
- package/dist/browser/actions/index.js.map +1 -1
- package/dist/browser/actions/menu-search.js +166 -0
- package/dist/browser/actions/menu-search.js.map +1 -0
- package/dist/browser/actions/menu-sheet.js +107 -13
- package/dist/browser/actions/menu-sheet.js.map +1 -1
- package/dist/browser/content/CalendarWeekView.js +13 -1
- package/dist/browser/content/CalendarWeekView.js.map +1 -1
- package/dist/browser/inputs/IconChoices.js +121 -0
- package/dist/browser/inputs/IconChoices.js.map +1 -0
- package/dist/browser/inputs/index.js +1 -0
- package/dist/browser/inputs/index.js.map +1 -1
- package/dist/browser/intl/messages.js +6 -0
- package/dist/browser/intl/messages.js.map +1 -1
- package/dist/browser/layout/AppWorkspace.js +118 -93
- package/dist/browser/layout/AppWorkspace.js.map +1 -1
- package/dist/browser/text-editor/format.js +11 -7
- package/dist/browser/text-editor/format.js.map +1 -1
- package/dist/browser/text-editor/table.js +39 -11
- package/dist/browser/text-editor/table.js.map +1 -1
- package/dist/browser/text-editor.js +1 -1
- package/dist/browser/text-editor.js.map +1 -1
- package/dist/ssr/actions/Dropdown.js +118 -40
- package/dist/ssr/actions/Dropdown.js.map +1 -1
- package/dist/ssr/actions/index.js.map +1 -1
- package/dist/ssr/actions/menu-search.js +113 -0
- package/dist/ssr/actions/menu-search.js.map +1 -0
- package/dist/ssr/actions/menu-sheet.js +82 -13
- package/dist/ssr/actions/menu-sheet.js.map +1 -1
- package/dist/ssr/content/CalendarWeekView.js +13 -1
- package/dist/ssr/content/CalendarWeekView.js.map +1 -1
- package/dist/ssr/inputs/IconChoices.js +59 -0
- package/dist/ssr/inputs/IconChoices.js.map +1 -0
- package/dist/ssr/inputs/index.js +1 -0
- package/dist/ssr/inputs/index.js.map +1 -1
- package/dist/ssr/intl/messages.js +6 -0
- package/dist/ssr/intl/messages.js.map +1 -1
- package/dist/ssr/layout/AppWorkspace.js +40 -20
- package/dist/ssr/layout/AppWorkspace.js.map +1 -1
- package/dist/ssr/text-editor/format.js +11 -7
- package/dist/ssr/text-editor/format.js.map +1 -1
- package/dist/ssr/text-editor/table.js +39 -11
- package/dist/ssr/text-editor/table.js.map +1 -1
- package/dist/ssr/text-editor.js +1 -1
- package/dist/ssr/text-editor.js.map +1 -1
- package/dist/styles.css +1 -1
- package/dist/types/actions/Dropdown.d.ts +34 -3
- package/dist/types/actions/index.d.ts +1 -1
- package/dist/types/actions/menu-search.d.ts +27 -0
- package/dist/types/actions/menu-sheet.d.ts +5 -1
- package/dist/types/inputs/IconChoices.d.ts +19 -0
- package/dist/types/inputs/index.d.ts +2 -0
- package/dist/types/intl/messages.d.ts +3 -0
- package/dist/types/layout/AppWorkspace.d.ts +6 -1
- package/dist/types/text-editor/table.d.ts +2 -0
- package/dist/types/text-editor.d.ts +1 -1
- package/package.json +3 -1
package/dist/base.css
CHANGED
|
@@ -447,6 +447,28 @@
|
|
|
447
447
|
margin: 0;
|
|
448
448
|
}
|
|
449
449
|
|
|
450
|
+
/* Not the native box: it ignores border-radius, so it could not match the
|
|
451
|
+
@k2b/ui checkbox. Radio buttons stay native; they are round anyway. */
|
|
452
|
+
input[type="checkbox"] {
|
|
453
|
+
box-sizing: border-box;
|
|
454
|
+
appearance: none;
|
|
455
|
+
border: 1px solid var(--k2b-border-strong);
|
|
456
|
+
border-radius: 0.25rem;
|
|
457
|
+
background: var(--k2b-surface);
|
|
458
|
+
cursor: pointer;
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
input[type="checkbox"]:checked {
|
|
462
|
+
border-color: var(--k2b-action-solid);
|
|
463
|
+
/* Two gradient strokes, not an image: a host's img-src policy may refuse a
|
|
464
|
+
data: URL, and an input has no reliable pseudo-element in every engine. */
|
|
465
|
+
background:
|
|
466
|
+
linear-gradient(45deg, transparent 27%, #fff 29.5%, #fff 49.2%, transparent 51.7%) 23.08% 0 / 22% 100% no-repeat,
|
|
467
|
+
linear-gradient(135deg, transparent 41.1%, #fff 43.6%, #fff 60.6%, transparent 63.1%) 68.97% 0 / 42% 100% no-repeat,
|
|
468
|
+
var(--k2b-action-solid);
|
|
469
|
+
forced-color-adjust: none;
|
|
470
|
+
}
|
|
471
|
+
|
|
450
472
|
input[type="range"] {
|
|
451
473
|
width: 100%;
|
|
452
474
|
}
|
|
@@ -19,20 +19,22 @@ var _tmpl$ = /*#__PURE__*/_$template(`<span class=k2b-dropdown__copy><span></spa
|
|
|
19
19
|
_tmpl$2 = /*#__PURE__*/_$template(`<i aria-hidden=true>`),
|
|
20
20
|
_tmpl$3 = /*#__PURE__*/_$template(`<img class=k2b-dropdown__image alt>`),
|
|
21
21
|
_tmpl$4 = /*#__PURE__*/_$template(`<small>`),
|
|
22
|
-
_tmpl$5 = /*#__PURE__*/_$template(`<button type=button
|
|
23
|
-
_tmpl$6 = /*#__PURE__*/_$template(`<a
|
|
22
|
+
_tmpl$5 = /*#__PURE__*/_$template(`<button type=button tabindex=-1>`),
|
|
23
|
+
_tmpl$6 = /*#__PURE__*/_$template(`<a tabindex=-1>`),
|
|
24
24
|
_tmpl$7 = /*#__PURE__*/_$template(`<div class=k2b-dropdown__pair><!$><!/><!$><!/>`),
|
|
25
|
-
_tmpl$8 = /*#__PURE__*/_$template(`<
|
|
26
|
-
_tmpl$9 = /*#__PURE__*/_$template(`<
|
|
27
|
-
_tmpl$0 = /*#__PURE__*/_$template(`<
|
|
28
|
-
_tmpl$1 = /*#__PURE__*/_$template(`<
|
|
29
|
-
_tmpl$10 = /*#__PURE__*/_$template(`<
|
|
30
|
-
_tmpl$11 = /*#__PURE__*/_$template(`<div class=k2b-
|
|
31
|
-
_tmpl$12 = /*#__PURE__*/_$template(`<div class=k2b-
|
|
32
|
-
_tmpl$13 = /*#__PURE__*/_$template(`<div class=
|
|
33
|
-
_tmpl$14 = /*#__PURE__*/_$template(`<
|
|
34
|
-
_tmpl$15 = /*#__PURE__*/_$template(`<
|
|
35
|
-
|
|
25
|
+
_tmpl$8 = /*#__PURE__*/_$template(`<button type=button role=menuitem tabindex=-1>`),
|
|
26
|
+
_tmpl$9 = /*#__PURE__*/_$template(`<i class="ti ti-check">`),
|
|
27
|
+
_tmpl$0 = /*#__PURE__*/_$template(`<span class=k2b-dropdown__checkbox aria-hidden=true>`),
|
|
28
|
+
_tmpl$1 = /*#__PURE__*/_$template(`<i class="ti ti-check k2b-dropdown__check"aria-hidden=true>`),
|
|
29
|
+
_tmpl$10 = /*#__PURE__*/_$template(`<span class=k2b-dropdown__color aria-hidden=true>`),
|
|
30
|
+
_tmpl$11 = /*#__PURE__*/_$template(`<div class=k2b-dropdown__row>`),
|
|
31
|
+
_tmpl$12 = /*#__PURE__*/_$template(`<div class=k2b-dropdown__section role=group><!$><!/><!$><!/>`),
|
|
32
|
+
_tmpl$13 = /*#__PURE__*/_$template(`<div class=k2b-dropdown__label>`),
|
|
33
|
+
_tmpl$14 = /*#__PURE__*/_$template(`<div class="k2b-dropdown__label k2b-dropdown__label--action"><span></span><!$><!/>`),
|
|
34
|
+
_tmpl$15 = /*#__PURE__*/_$template(`<button>`),
|
|
35
|
+
_tmpl$16 = /*#__PURE__*/_$template(`<p class=k2b-dropdown__note aria-hidden=true>`),
|
|
36
|
+
_tmpl$17 = /*#__PURE__*/_$template(`<span><!$><!/><div popover=auto>`);
|
|
37
|
+
import { createContext, createEffect, createSignal, createUniqueId, mergeProps, onCleanup, onMount, Show, splitProps, untrack, useContext } from "solid-js";
|
|
36
38
|
import { Dynamic } from "solid-js/web";
|
|
37
39
|
import { Tooltip, useLabelTooltip } from "../feedback/Tooltip";
|
|
38
40
|
import { returnFocus, ringOnReturn } from "../internal/focus-return";
|
|
@@ -41,6 +43,7 @@ import { useLocale } from "../intl/locale";
|
|
|
41
43
|
import { useUiMessages } from "../intl/messages";
|
|
42
44
|
import { Button, iconTitle } from "./Button";
|
|
43
45
|
import { focusMenuRow, focusRowSegment } from "./menu-rows";
|
|
46
|
+
import { MenuSearch } from "./menu-search";
|
|
44
47
|
import { openMenuSheet, prefersMenuSheet } from "./menu-sheet";
|
|
45
48
|
|
|
46
49
|
// Resolved outside JSX: a conditional attribute compiles to a lazy memo, which would be created inside the click handler.
|
|
@@ -57,9 +60,11 @@ const externalOf = item => "external" in item ? item.external : undefined;
|
|
|
57
60
|
|
|
58
61
|
/** Declarative radio or checkbox row for compact action menus. */
|
|
59
62
|
|
|
63
|
+
/** A search field above the entries, for a menu long enough that finding an entry takes reading. */
|
|
64
|
+
|
|
60
65
|
const MenuContext = createContext();
|
|
61
66
|
const DropdownContext = createContext();
|
|
62
|
-
const actionableItems = menu => menu ? Array.from(menu.querySelectorAll(["[role='menuitem']:not([aria-disabled='true'])", "[role='menuitemcheckbox']:not([aria-disabled='true'])", "[role='menuitemradio']:not([aria-disabled='true'])"].join(", "))) : [];
|
|
67
|
+
const actionableItems = menu => menu ? Array.from(menu.querySelectorAll(["[role='menuitem']:not([aria-disabled='true'])", "[role='menuitemcheckbox']:not([aria-disabled='true'])", "[role='menuitemradio']:not([aria-disabled='true'])", "[role='option']:not([aria-disabled='true'])"].join(", "))) : [];
|
|
63
68
|
const focusMenuItem = (menu, index) => {
|
|
64
69
|
const items = actionableItems(menu).filter(item => !item.classList.contains("k2b-dropdown__secondary"));
|
|
65
70
|
if (items.length === 0) return;
|
|
@@ -121,6 +126,7 @@ const itemContent = props => [_$createComponent(Show, {
|
|
|
121
126
|
export function DropdownItem(props) {
|
|
122
127
|
const menu = useContext(MenuContext);
|
|
123
128
|
const danger = () => props.danger || props.variant === "danger";
|
|
129
|
+
const role = () => menu?.role ?? "menuitem";
|
|
124
130
|
const content = itemContent(props);
|
|
125
131
|
return _$createComponent(Show, {
|
|
126
132
|
get when() {
|
|
@@ -132,28 +138,36 @@ export function DropdownItem(props) {
|
|
|
132
138
|
_el$8.$$click = event => {
|
|
133
139
|
event.preventDefault();
|
|
134
140
|
event.stopPropagation();
|
|
141
|
+
// Read before closing: a searchable menu clears its query as it closes, and the row then shows another entry.
|
|
142
|
+
const select = props.onSelect;
|
|
135
143
|
if (props.closeOnSelect !== false) menu?.close();
|
|
136
|
-
|
|
144
|
+
select?.();
|
|
137
145
|
};
|
|
138
146
|
_$insert(_el$8, content);
|
|
139
147
|
_$effect(_p$ => {
|
|
140
|
-
var _v$ =
|
|
141
|
-
_v$2 =
|
|
142
|
-
_v$3 =
|
|
143
|
-
_v$4 =
|
|
144
|
-
_v$5 = props.
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
_v$
|
|
148
|
-
_v$
|
|
149
|
-
_v$
|
|
148
|
+
var _v$ = role(),
|
|
149
|
+
_v$2 = props.ariaLabel,
|
|
150
|
+
_v$3 = `k2b-dropdown__item ${props.class ?? ""}`,
|
|
151
|
+
_v$4 = danger() ? "true" : undefined,
|
|
152
|
+
_v$5 = props.variant === "accent" ? "true" : undefined,
|
|
153
|
+
_v$6 = props.disabled,
|
|
154
|
+
_v$7 = props.disabled ? "true" : undefined;
|
|
155
|
+
_v$ !== _p$.e && _$setAttribute(_el$8, "role", _p$.e = _v$);
|
|
156
|
+
_v$2 !== _p$.t && _$setAttribute(_el$8, "aria-label", _p$.t = _v$2);
|
|
157
|
+
_v$3 !== _p$.a && _$className(_el$8, _p$.a = _v$3);
|
|
158
|
+
_v$4 !== _p$.o && _$setAttribute(_el$8, "data-danger", _p$.o = _v$4);
|
|
159
|
+
_v$5 !== _p$.i && _$setAttribute(_el$8, "data-accent", _p$.i = _v$5);
|
|
160
|
+
_v$6 !== _p$.n && _$setProperty(_el$8, "disabled", _p$.n = _v$6);
|
|
161
|
+
_v$7 !== _p$.s && _$setAttribute(_el$8, "aria-disabled", _p$.s = _v$7);
|
|
150
162
|
return _p$;
|
|
151
163
|
}, {
|
|
152
164
|
e: undefined,
|
|
153
165
|
t: undefined,
|
|
154
166
|
a: undefined,
|
|
155
167
|
o: undefined,
|
|
156
|
-
i: undefined
|
|
168
|
+
i: undefined,
|
|
169
|
+
n: undefined,
|
|
170
|
+
s: undefined
|
|
157
171
|
});
|
|
158
172
|
_$runHydrationEvents();
|
|
159
173
|
return _el$8;
|
|
@@ -163,28 +177,33 @@ export function DropdownItem(props) {
|
|
|
163
177
|
var _el$9 = _$getNextElement(_tmpl$6);
|
|
164
178
|
_el$9.$$click = event => {
|
|
165
179
|
// With `onSelect`, a plain click runs it in place of the link; a modified click keeps its browser meaning.
|
|
166
|
-
|
|
180
|
+
const select = props.onSelect;
|
|
181
|
+
if (select && !(event.metaKey || event.ctrlKey || event.shiftKey || event.altKey)) {
|
|
167
182
|
event.preventDefault();
|
|
168
183
|
menu?.close();
|
|
169
|
-
|
|
184
|
+
select();
|
|
170
185
|
return;
|
|
171
186
|
}
|
|
172
187
|
menu?.close(false);
|
|
173
188
|
};
|
|
174
189
|
_$insert(_el$9, content);
|
|
175
190
|
_$effect(_p$ => {
|
|
176
|
-
var _v$
|
|
177
|
-
_v$
|
|
178
|
-
_v$
|
|
179
|
-
_v$
|
|
180
|
-
_v$
|
|
181
|
-
_v$
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
_v$8 !== _p$.
|
|
185
|
-
_v$9 !== _p$.
|
|
186
|
-
_v$0 !== _p$.
|
|
187
|
-
_v$1 !== _p$.
|
|
191
|
+
var _v$8 = href(),
|
|
192
|
+
_v$9 = props.external ? "_blank" : undefined,
|
|
193
|
+
_v$0 = props.external ? "noopener noreferrer" : undefined,
|
|
194
|
+
_v$1 = role(),
|
|
195
|
+
_v$10 = props.ariaLabel,
|
|
196
|
+
_v$11 = `k2b-dropdown__item ${props.class ?? ""}`,
|
|
197
|
+
_v$12 = danger() ? "true" : undefined,
|
|
198
|
+
_v$13 = props.variant === "accent" ? "true" : undefined;
|
|
199
|
+
_v$8 !== _p$.e && _$setAttribute(_el$9, "href", _p$.e = _v$8);
|
|
200
|
+
_v$9 !== _p$.t && _$setAttribute(_el$9, "target", _p$.t = _v$9);
|
|
201
|
+
_v$0 !== _p$.a && _$setAttribute(_el$9, "rel", _p$.a = _v$0);
|
|
202
|
+
_v$1 !== _p$.o && _$setAttribute(_el$9, "role", _p$.o = _v$1);
|
|
203
|
+
_v$10 !== _p$.i && _$setAttribute(_el$9, "aria-label", _p$.i = _v$10);
|
|
204
|
+
_v$11 !== _p$.n && _$className(_el$9, _p$.n = _v$11);
|
|
205
|
+
_v$12 !== _p$.s && _$setAttribute(_el$9, "data-danger", _p$.s = _v$12);
|
|
206
|
+
_v$13 !== _p$.h && _$setAttribute(_el$9, "data-accent", _p$.h = _v$13);
|
|
188
207
|
return _p$;
|
|
189
208
|
}, {
|
|
190
209
|
e: undefined,
|
|
@@ -192,7 +211,9 @@ export function DropdownItem(props) {
|
|
|
192
211
|
a: undefined,
|
|
193
212
|
o: undefined,
|
|
194
213
|
i: undefined,
|
|
195
|
-
n: undefined
|
|
214
|
+
n: undefined,
|
|
215
|
+
s: undefined,
|
|
216
|
+
h: undefined
|
|
196
217
|
});
|
|
197
218
|
_$runHydrationEvents();
|
|
198
219
|
return _el$9;
|
|
@@ -200,9 +221,11 @@ export function DropdownItem(props) {
|
|
|
200
221
|
});
|
|
201
222
|
}
|
|
202
223
|
function DropdownChoiceItem(props) {
|
|
224
|
+
const menu = useContext(MenuContext);
|
|
225
|
+
// A searchable menu's field keeps the focus, so a second button in a row could not be reached; it is left out.
|
|
203
226
|
return _$createComponent(Show, {
|
|
204
227
|
get when() {
|
|
205
|
-
return props.secondary;
|
|
228
|
+
return _$memo(() => menu?.role !== "option")() && props.secondary;
|
|
206
229
|
},
|
|
207
230
|
get fallback() {
|
|
208
231
|
return _$createComponent(DropdownChoiceRow, props);
|
|
@@ -223,7 +246,7 @@ function DropdownChoiceItem(props) {
|
|
|
223
246
|
}
|
|
224
247
|
function DropdownSecondaryButton(props) {
|
|
225
248
|
return (() => {
|
|
226
|
-
var _el$13 = _$getNextElement(_tmpl$
|
|
249
|
+
var _el$13 = _$getNextElement(_tmpl$8);
|
|
227
250
|
_el$13.$$click = event => {
|
|
228
251
|
event.preventDefault();
|
|
229
252
|
event.stopPropagation();
|
|
@@ -231,10 +254,10 @@ function DropdownSecondaryButton(props) {
|
|
|
231
254
|
};
|
|
232
255
|
_$insert(_el$13, () => props.label);
|
|
233
256
|
_$effect(_p$ => {
|
|
234
|
-
var _v$
|
|
235
|
-
_v$
|
|
236
|
-
_v$
|
|
237
|
-
_v$
|
|
257
|
+
var _v$14 = props.class,
|
|
258
|
+
_v$15 = props.ariaLabel;
|
|
259
|
+
_v$14 !== _p$.e && _$className(_el$13, _p$.e = _v$14);
|
|
260
|
+
_v$15 !== _p$.t && _$setAttribute(_el$13, "aria-label", _p$.t = _v$15);
|
|
238
261
|
return _p$;
|
|
239
262
|
}, {
|
|
240
263
|
e: undefined,
|
|
@@ -262,7 +285,7 @@ function DropdownChoiceRow(props) {
|
|
|
262
285
|
return !props.disabled && props.href ? undefined : "button";
|
|
263
286
|
},
|
|
264
287
|
get role() {
|
|
265
|
-
return props.choice === "checkbox" ? "menuitemcheckbox" : "menuitemradio";
|
|
288
|
+
return _$memo(() => menu?.role === "option")() ? "option" : props.choice === "checkbox" ? "menuitemcheckbox" : "menuitemradio";
|
|
266
289
|
},
|
|
267
290
|
get ["aria-label"]() {
|
|
268
291
|
return props.ariaLabel;
|
|
@@ -290,8 +313,9 @@ function DropdownChoiceRow(props) {
|
|
|
290
313
|
}
|
|
291
314
|
event.preventDefault();
|
|
292
315
|
event.stopPropagation();
|
|
316
|
+
const action = props.action;
|
|
293
317
|
if (props.closeOnSelect !== false) menu?.close();
|
|
294
|
-
|
|
318
|
+
action();
|
|
295
319
|
},
|
|
296
320
|
onKeyDown: event => {
|
|
297
321
|
// A link answers only Enter; as a menu choice it also answers Space, like the button form.
|
|
@@ -305,13 +329,13 @@ function DropdownChoiceRow(props) {
|
|
|
305
329
|
return props.choice === "checkbox";
|
|
306
330
|
},
|
|
307
331
|
get children() {
|
|
308
|
-
var _el$14 = _$getNextElement(_tmpl$
|
|
332
|
+
var _el$14 = _$getNextElement(_tmpl$0);
|
|
309
333
|
_$insert(_el$14, _$createComponent(Show, {
|
|
310
334
|
get when() {
|
|
311
335
|
return checked();
|
|
312
336
|
},
|
|
313
337
|
get children() {
|
|
314
|
-
return _$getNextElement(_tmpl$
|
|
338
|
+
return _$getNextElement(_tmpl$9);
|
|
315
339
|
}
|
|
316
340
|
}));
|
|
317
341
|
return _el$14;
|
|
@@ -342,7 +366,7 @@ function DropdownChoiceRow(props) {
|
|
|
342
366
|
return props.color;
|
|
343
367
|
},
|
|
344
368
|
children: color => (() => {
|
|
345
|
-
var _el$23 = _$getNextElement(_tmpl$
|
|
369
|
+
var _el$23 = _$getNextElement(_tmpl$10);
|
|
346
370
|
_$effect(_$p => _$setStyleProperty(_el$23, "--k2b-dropdown-color", color()));
|
|
347
371
|
return _el$23;
|
|
348
372
|
})()
|
|
@@ -368,7 +392,7 @@ function DropdownChoiceRow(props) {
|
|
|
368
392
|
return props.choice === "radio";
|
|
369
393
|
},
|
|
370
394
|
get children() {
|
|
371
|
-
var _el$20 = _$getNextElement(_tmpl$
|
|
395
|
+
var _el$20 = _$getNextElement(_tmpl$1);
|
|
372
396
|
_$effect(() => _$setAttribute(_el$20, "data-hidden", checked() ? undefined : "true"));
|
|
373
397
|
return _el$20;
|
|
374
398
|
}
|
|
@@ -428,7 +452,8 @@ export function DropdownItems(props) {
|
|
|
428
452
|
return _$createComponent(MenuContext.Provider, {
|
|
429
453
|
get value() {
|
|
430
454
|
return {
|
|
431
|
-
close: props.close
|
|
455
|
+
close: props.close,
|
|
456
|
+
role: props.role ?? "menuitem"
|
|
432
457
|
};
|
|
433
458
|
},
|
|
434
459
|
get children() {
|
|
@@ -447,7 +472,7 @@ export function DropdownItems(props) {
|
|
|
447
472
|
return renderItem(current);
|
|
448
473
|
},
|
|
449
474
|
get children() {
|
|
450
|
-
var _el$25 = _$getNextElement(_tmpl$
|
|
475
|
+
var _el$25 = _$getNextElement(_tmpl$12),
|
|
451
476
|
_el$27 = _el$25.firstChild,
|
|
452
477
|
[_el$28, _co$5] = _$getNextMarker(_el$27.nextSibling),
|
|
453
478
|
_el$29 = _el$28.nextSibling,
|
|
@@ -458,17 +483,17 @@ export function DropdownItems(props) {
|
|
|
458
483
|
},
|
|
459
484
|
children: label => _$createComponent(Show, {
|
|
460
485
|
get when() {
|
|
461
|
-
return current().labelAction;
|
|
486
|
+
return _$memo(() => props.role !== "option")() && current().labelAction;
|
|
462
487
|
},
|
|
463
488
|
get fallback() {
|
|
464
489
|
return (() => {
|
|
465
|
-
var _el$31 = _$getNextElement(_tmpl$
|
|
490
|
+
var _el$31 = _$getNextElement(_tmpl$13);
|
|
466
491
|
_$insert(_el$31, label);
|
|
467
492
|
return _el$31;
|
|
468
493
|
})();
|
|
469
494
|
},
|
|
470
495
|
children: action => (() => {
|
|
471
|
-
var _el$32 = _$getNextElement(_tmpl$
|
|
496
|
+
var _el$32 = _$getNextElement(_tmpl$14),
|
|
472
497
|
_el$33 = _el$32.firstChild,
|
|
473
498
|
_el$34 = _el$33.nextSibling,
|
|
474
499
|
[_el$35, _co$7] = _$getNextMarker(_el$34.nextSibling);
|
|
@@ -494,7 +519,7 @@ export function DropdownItems(props) {
|
|
|
494
519
|
});
|
|
495
520
|
},
|
|
496
521
|
get children() {
|
|
497
|
-
var _el$26 = _$getNextElement(_tmpl$
|
|
522
|
+
var _el$26 = _$getNextElement(_tmpl$11);
|
|
498
523
|
_$insert(_el$26, _$createComponent(KeyedFor, {
|
|
499
524
|
get each() {
|
|
500
525
|
return current().items;
|
|
@@ -506,10 +531,10 @@ export function DropdownItems(props) {
|
|
|
506
531
|
}
|
|
507
532
|
}), _el$30, _co$6);
|
|
508
533
|
_$effect(_p$ => {
|
|
509
|
-
var _v$
|
|
510
|
-
_v$
|
|
511
|
-
_v$
|
|
512
|
-
_v$
|
|
534
|
+
var _v$16 = index() > 0 ? "true" : undefined,
|
|
535
|
+
_v$17 = current().sectionLabel ?? (current().layout === "row" ? undefined : messages().actions);
|
|
536
|
+
_v$16 !== _p$.e && _$setAttribute(_el$25, "data-divided", _p$.e = _v$16);
|
|
537
|
+
_v$17 !== _p$.t && _$setAttribute(_el$25, "aria-label", _p$.t = _v$17);
|
|
513
538
|
return _p$;
|
|
514
539
|
}, {
|
|
515
540
|
e: undefined,
|
|
@@ -549,7 +574,9 @@ function DropdownTrigger(props) {
|
|
|
549
574
|
get ["aria-expanded"]() {
|
|
550
575
|
return context.open();
|
|
551
576
|
},
|
|
552
|
-
"aria-haspopup"
|
|
577
|
+
get ["aria-haspopup"]() {
|
|
578
|
+
return context.popup();
|
|
579
|
+
},
|
|
553
580
|
get ["aria-label"]() {
|
|
554
581
|
return local.label;
|
|
555
582
|
},
|
|
@@ -593,7 +620,7 @@ function DropdownTrigger(props) {
|
|
|
593
620
|
}));
|
|
594
621
|
}
|
|
595
622
|
return [(() => {
|
|
596
|
-
var _el$36 = _$getNextElement(_tmpl$
|
|
623
|
+
var _el$36 = _$getNextElement(_tmpl$15);
|
|
597
624
|
_$use(register, _el$36);
|
|
598
625
|
_$spread(_el$36, _$mergeProps(rest, {
|
|
599
626
|
get ["aria-controls"]() {
|
|
@@ -602,7 +629,9 @@ function DropdownTrigger(props) {
|
|
|
602
629
|
get ["aria-expanded"]() {
|
|
603
630
|
return context.open();
|
|
604
631
|
},
|
|
605
|
-
"aria-haspopup"
|
|
632
|
+
get ["aria-haspopup"]() {
|
|
633
|
+
return context.popup();
|
|
634
|
+
},
|
|
606
635
|
get ["aria-label"]() {
|
|
607
636
|
return local.label;
|
|
608
637
|
},
|
|
@@ -664,6 +693,8 @@ function DropdownRoot(props) {
|
|
|
664
693
|
const [internalOpen, setInternalOpen] = createSignal(false);
|
|
665
694
|
const [entriesShown, setEntriesShown] = createSignal(!props.lazy);
|
|
666
695
|
let triggerRef;
|
|
696
|
+
const [query, setQuery] = createSignal("");
|
|
697
|
+
let searchApi;
|
|
667
698
|
/** Set while the menu is open from `openAt`: it appears beside `anchor`, and focus returns to `origin`. */
|
|
668
699
|
let anchor;
|
|
669
700
|
let origin;
|
|
@@ -712,6 +743,7 @@ function DropdownRoot(props) {
|
|
|
712
743
|
// Before hiding, so the popover does not return focus on its own.
|
|
713
744
|
if (restoreFocus) returnFocus(originElement() ?? triggerRef, triggerRing);
|
|
714
745
|
if (menuRef?.matches(":popover-open")) menuRef.hidePopover();
|
|
746
|
+
setQuery("");
|
|
715
747
|
// Like `open`, expose the closed state now: the toggle event can arrive after the next key press, and a trigger
|
|
716
748
|
// that still reads as open would ignore Enter (Escape, then Enter at once, must reopen).
|
|
717
749
|
setInternalOpen(false);
|
|
@@ -728,7 +760,8 @@ function DropdownRoot(props) {
|
|
|
728
760
|
attachViewportListeners();
|
|
729
761
|
place();
|
|
730
762
|
queueMicrotask(() => {
|
|
731
|
-
if (focus)
|
|
763
|
+
if (!focus) return;
|
|
764
|
+
if (searchApi) searchApi.focus(focus);else focusMenuItem(menuRef, focus === "first" ? 0 : -1);
|
|
732
765
|
});
|
|
733
766
|
};
|
|
734
767
|
const requestOpen = (next, focus = "first") => {
|
|
@@ -755,6 +788,9 @@ function DropdownRoot(props) {
|
|
|
755
788
|
label: props.label ?? messages().dropdownMenu,
|
|
756
789
|
locale: locale(),
|
|
757
790
|
top: props.sheetTop,
|
|
791
|
+
search: props.search,
|
|
792
|
+
icons: props.icons,
|
|
793
|
+
note: props.note,
|
|
758
794
|
signal: current.signal
|
|
759
795
|
}).finally(() => {
|
|
760
796
|
sheet = undefined;
|
|
@@ -772,7 +808,8 @@ function DropdownRoot(props) {
|
|
|
772
808
|
};
|
|
773
809
|
const handleMenuKeyDown = event => {
|
|
774
810
|
const items = actionableItems(menuRef);
|
|
775
|
-
|
|
811
|
+
// A searchable menu's field keeps the focus and moves the marked entry itself.
|
|
812
|
+
if (!props.search && (focusMenuRow(items, event.key) || focusRowSegment(items, event.key))) {
|
|
776
813
|
event.preventDefault();
|
|
777
814
|
} else if (event.key === "Escape") {
|
|
778
815
|
event.preventDefault();
|
|
@@ -782,6 +819,25 @@ function DropdownRoot(props) {
|
|
|
782
819
|
requestOpen(false);
|
|
783
820
|
}
|
|
784
821
|
};
|
|
822
|
+
const triggerKey = event => {
|
|
823
|
+
if (!["Enter", " ", "ArrowDown", "ArrowUp"].includes(event.key)) return;
|
|
824
|
+
// Ctrl+Enter and the like keep their browser meaning on an adopted link, such as opening it in a new tab.
|
|
825
|
+
if (event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) return;
|
|
826
|
+
event.preventDefault();
|
|
827
|
+
event.stopPropagation();
|
|
828
|
+
if (isOpen()) {
|
|
829
|
+
if (searchApi) searchApi.focus(event.key === "ArrowUp" ? "last" : "first");else focusMenuItem(menuRef, event.key === "ArrowUp" ? -1 : 0);
|
|
830
|
+
return;
|
|
831
|
+
}
|
|
832
|
+
anchor = origin = undefined;
|
|
833
|
+
keyFocus = event.key === "ArrowUp" ? "last" : "first";
|
|
834
|
+
requestOpen(true, keyFocus);
|
|
835
|
+
keyFocus = false;
|
|
836
|
+
};
|
|
837
|
+
const toggle = () => {
|
|
838
|
+
if (!isOpen()) anchor = origin = undefined;
|
|
839
|
+
requestOpen(!isOpen());
|
|
840
|
+
};
|
|
785
841
|
const context = {
|
|
786
842
|
disabled: () => Boolean(props.disabled),
|
|
787
843
|
menuId,
|
|
@@ -789,23 +845,9 @@ function DropdownRoot(props) {
|
|
|
789
845
|
registerTrigger: element => {
|
|
790
846
|
triggerRef = element;
|
|
791
847
|
},
|
|
792
|
-
toggle
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
},
|
|
796
|
-
triggerKeyDown: event => {
|
|
797
|
-
if (!["Enter", " ", "ArrowDown", "ArrowUp"].includes(event.key)) return;
|
|
798
|
-
event.preventDefault();
|
|
799
|
-
event.stopPropagation();
|
|
800
|
-
if (isOpen()) {
|
|
801
|
-
focusMenuItem(menuRef, event.key === "ArrowUp" ? -1 : 0);
|
|
802
|
-
return;
|
|
803
|
-
}
|
|
804
|
-
anchor = origin = undefined;
|
|
805
|
-
keyFocus = event.key === "ArrowUp" ? "last" : "first";
|
|
806
|
-
requestOpen(true, keyFocus);
|
|
807
|
-
keyFocus = false;
|
|
808
|
-
}
|
|
848
|
+
toggle,
|
|
849
|
+
popup: () => props.search ? "dialog" : "menu",
|
|
850
|
+
triggerKeyDown: event => triggerKey(event)
|
|
809
851
|
};
|
|
810
852
|
createEffect(() => {
|
|
811
853
|
const controlled = props.open;
|
|
@@ -832,16 +874,33 @@ function DropdownRoot(props) {
|
|
|
832
874
|
mounted = true;
|
|
833
875
|
if (props.open) open(false);
|
|
834
876
|
onCleanup(detachViewportListeners);
|
|
877
|
+
const adopted = props.attach?.();
|
|
878
|
+
if (!adopted) return;
|
|
879
|
+
triggerRef = adopted;
|
|
880
|
+
adopted.setAttribute("aria-controls", menuId);
|
|
881
|
+
const onClick = event => {
|
|
882
|
+
if (event.defaultPrevented || event.button !== 0 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) return;
|
|
883
|
+
event.preventDefault();
|
|
884
|
+
event.stopPropagation();
|
|
885
|
+
toggle();
|
|
886
|
+
};
|
|
887
|
+
adopted.addEventListener("click", onClick);
|
|
888
|
+
adopted.addEventListener("keydown", triggerKey);
|
|
889
|
+
createEffect(() => adopted.setAttribute("aria-expanded", String(isOpen())));
|
|
890
|
+
onCleanup(() => {
|
|
891
|
+
adopted.removeEventListener("click", onClick);
|
|
892
|
+
adopted.removeEventListener("keydown", triggerKey);
|
|
893
|
+
});
|
|
835
894
|
});
|
|
836
895
|
onCleanup(() => sheet?.abort());
|
|
837
896
|
return _$createComponent(DropdownContext.Provider, {
|
|
838
897
|
value: context,
|
|
839
898
|
get children() {
|
|
840
|
-
var _el$37 = _$getNextElement(_tmpl$
|
|
841
|
-
_el$
|
|
842
|
-
[_el$
|
|
843
|
-
_el$38 = _el$
|
|
844
|
-
_$insert(_el$37, () => props.children, _el$
|
|
899
|
+
var _el$37 = _$getNextElement(_tmpl$17),
|
|
900
|
+
_el$40 = _el$37.firstChild,
|
|
901
|
+
[_el$41, _co$8] = _$getNextMarker(_el$40.nextSibling),
|
|
902
|
+
_el$38 = _el$41.nextSibling;
|
|
903
|
+
_$insert(_el$37, () => props.children, _el$41, _co$8);
|
|
845
904
|
_el$38.addEventListener("toggle", event => {
|
|
846
905
|
const nextOpen = event.newState === "open";
|
|
847
906
|
const wasOpen = event.oldState === "open";
|
|
@@ -853,6 +912,7 @@ function DropdownRoot(props) {
|
|
|
853
912
|
const focused = document.activeElement;
|
|
854
913
|
const target = wasOpen && !nextOpen ? originElement() : undefined;
|
|
855
914
|
if (target?.isConnected && (!focused || focused === document.body || menuRef?.contains(focused))) returnFocus(target, triggerRing);
|
|
915
|
+
if (wasOpen && !nextOpen) setQuery("");
|
|
856
916
|
if (wasOpen && !nextOpen) props.onClose?.();
|
|
857
917
|
if (!nextOpen && props.open === true) queueMicrotask(() => props.open === true && open(false));
|
|
858
918
|
});
|
|
@@ -865,31 +925,77 @@ function DropdownRoot(props) {
|
|
|
865
925
|
return entriesShown();
|
|
866
926
|
},
|
|
867
927
|
get children() {
|
|
868
|
-
return _$createComponent(
|
|
869
|
-
get
|
|
870
|
-
return props.
|
|
928
|
+
return [_$createComponent(Show, {
|
|
929
|
+
get when() {
|
|
930
|
+
return props.search;
|
|
871
931
|
},
|
|
872
|
-
|
|
873
|
-
|
|
932
|
+
get fallback() {
|
|
933
|
+
return _$createComponent(DropdownItems, {
|
|
934
|
+
get items() {
|
|
935
|
+
return props.items;
|
|
936
|
+
},
|
|
937
|
+
close: close
|
|
938
|
+
});
|
|
939
|
+
},
|
|
940
|
+
children: search => _$createComponent(MenuSearch, {
|
|
941
|
+
Items: DropdownItems,
|
|
942
|
+
get items() {
|
|
943
|
+
return props.items;
|
|
944
|
+
},
|
|
945
|
+
get search() {
|
|
946
|
+
return search();
|
|
947
|
+
},
|
|
948
|
+
get label() {
|
|
949
|
+
return props.label ?? messages().dropdownMenu;
|
|
950
|
+
},
|
|
951
|
+
query: query,
|
|
952
|
+
setQuery: setQuery,
|
|
953
|
+
close: close,
|
|
954
|
+
api: api => {
|
|
955
|
+
searchApi = api;
|
|
956
|
+
onCleanup(() => {
|
|
957
|
+
if (searchApi === api) searchApi = undefined;
|
|
958
|
+
});
|
|
959
|
+
}
|
|
960
|
+
})
|
|
961
|
+
}), _$createComponent(Show, {
|
|
962
|
+
get when() {
|
|
963
|
+
return props.note;
|
|
964
|
+
},
|
|
965
|
+
get children() {
|
|
966
|
+
var _el$39 = _$getNextElement(_tmpl$16);
|
|
967
|
+
_$setAttribute(_el$39, "id", `${menuId}-note`);
|
|
968
|
+
_$insert(_el$39, () => props.note);
|
|
969
|
+
return _el$39;
|
|
970
|
+
}
|
|
971
|
+
})];
|
|
874
972
|
}
|
|
875
973
|
}));
|
|
876
974
|
_$effect(_p$ => {
|
|
877
|
-
var _v$
|
|
878
|
-
_v$
|
|
879
|
-
_v$
|
|
880
|
-
_v$
|
|
975
|
+
var _v$18 = `k2b-dropdown ${props.class ?? ""}`,
|
|
976
|
+
_v$19 = props.search ? "dialog" : "menu",
|
|
977
|
+
_v$20 = props.label ?? messages().dropdownMenu,
|
|
978
|
+
_v$21 = props.note ? `${menuId}-note` : undefined,
|
|
979
|
+
_v$22 = `k2b-dropdown__menu ${props.menuClass ?? ""}`,
|
|
980
|
+
_v$23 = props.width ? {
|
|
881
981
|
"--k2b-dropdown-width": props.width
|
|
882
982
|
} : undefined,
|
|
883
|
-
_v$
|
|
884
|
-
_v$
|
|
885
|
-
_v$
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
_v$
|
|
889
|
-
_p$.
|
|
890
|
-
_v$
|
|
891
|
-
_v$
|
|
892
|
-
_v$
|
|
983
|
+
_v$24 = props.width ? "fixed" : undefined,
|
|
984
|
+
_v$25 = props.variant ?? "default",
|
|
985
|
+
_v$26 = props.icons === "tile" ? "tile" : undefined,
|
|
986
|
+
_v$27 = props.search ? "" : undefined,
|
|
987
|
+
_v$28 = position();
|
|
988
|
+
_v$18 !== _p$.e && _$className(_el$37, _p$.e = _v$18);
|
|
989
|
+
_v$19 !== _p$.t && _$setAttribute(_el$38, "role", _p$.t = _v$19);
|
|
990
|
+
_v$20 !== _p$.a && _$setAttribute(_el$38, "aria-label", _p$.a = _v$20);
|
|
991
|
+
_v$21 !== _p$.o && _$setAttribute(_el$38, "aria-describedby", _p$.o = _v$21);
|
|
992
|
+
_v$22 !== _p$.i && _$className(_el$38, _p$.i = _v$22);
|
|
993
|
+
_p$.n = _$style(_el$38, _v$23, _p$.n);
|
|
994
|
+
_v$24 !== _p$.s && _$setAttribute(_el$38, "data-width", _p$.s = _v$24);
|
|
995
|
+
_v$25 !== _p$.h && _$setAttribute(_el$38, "data-variant", _p$.h = _v$25);
|
|
996
|
+
_v$26 !== _p$.r && _$setAttribute(_el$38, "data-icons", _p$.r = _v$26);
|
|
997
|
+
_v$27 !== _p$.d && _$setAttribute(_el$38, "data-search", _p$.d = _v$27);
|
|
998
|
+
_v$28 !== _p$.l && _$setAttribute(_el$38, "data-position", _p$.l = _v$28);
|
|
893
999
|
return _p$;
|
|
894
1000
|
}, {
|
|
895
1001
|
e: undefined,
|
|
@@ -898,7 +1004,11 @@ function DropdownRoot(props) {
|
|
|
898
1004
|
o: undefined,
|
|
899
1005
|
i: undefined,
|
|
900
1006
|
n: undefined,
|
|
901
|
-
s: undefined
|
|
1007
|
+
s: undefined,
|
|
1008
|
+
h: undefined,
|
|
1009
|
+
r: undefined,
|
|
1010
|
+
d: undefined,
|
|
1011
|
+
l: undefined
|
|
902
1012
|
});
|
|
903
1013
|
_$runHydrationEvents();
|
|
904
1014
|
return _el$37;
|