@k2b/ui 0.27.0 → 0.28.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/README.md +1 -1
- package/dist/base.css +147 -2
- package/dist/browser/actions/ContextMenu.js +30 -4
- package/dist/browser/actions/ContextMenu.js.map +1 -1
- package/dist/browser/actions/Dropdown.js +184 -158
- package/dist/browser/actions/Dropdown.js.map +1 -1
- package/dist/browser/actions/GestureMenu.js +71 -138
- package/dist/browser/actions/GestureMenu.js.map +1 -1
- package/dist/browser/actions/Toolbar.js +379 -48
- package/dist/browser/actions/Toolbar.js.map +1 -1
- package/dist/browser/actions/index.js.map +1 -1
- package/dist/browser/actions/menu-rows.js +15 -0
- package/dist/browser/actions/menu-rows.js.map +1 -0
- package/dist/browser/actions/menu-sheet.js +154 -0
- package/dist/browser/actions/menu-sheet.js.map +1 -0
- package/dist/browser/actions/toolbar-messages.js +20 -0
- package/dist/browser/actions/toolbar-messages.js.map +1 -0
- package/dist/browser/chart-inspection.js +3 -0
- package/dist/browser/chart-inspection.js.map +1 -0
- package/dist/browser/chat/ChatComposer.js +581 -397
- package/dist/browser/chat/ChatComposer.js.map +1 -1
- package/dist/browser/chat/chat-messages.js +19 -1
- package/dist/browser/chat/chat-messages.js.map +1 -1
- package/dist/browser/chat/command-search.js +3 -0
- package/dist/browser/chat/command-search.js.map +1 -1
- package/dist/browser/chat/index.js +2 -0
- package/dist/browser/chat/index.js.map +1 -1
- package/dist/browser/chat/reaction-people.js +15 -0
- package/dist/browser/chat/reaction-people.js.map +1 -0
- package/dist/browser/content/Chart.js +6 -15
- package/dist/browser/content/Chart.js.map +1 -1
- package/dist/browser/content/ChartSnapshotView.js +7 -10
- package/dist/browser/content/ChartSnapshotView.js.map +1 -1
- package/dist/browser/content/MessageRow.js +330 -448
- package/dist/browser/content/MessageRow.js.map +1 -1
- package/dist/browser/content/ReactionBar.js +419 -0
- package/dist/browser/content/ReactionBar.js.map +1 -0
- package/dist/browser/content/chart-inspection-core.js +557 -0
- package/dist/browser/content/chart-inspection-core.js.map +1 -0
- package/dist/browser/content/chart-inspection.js +10 -445
- package/dist/browser/content/chart-inspection.js.map +1 -1
- package/dist/browser/content/chart-line-gaps.js +1 -1
- package/dist/browser/content/chart-line-gaps.js.map +1 -1
- package/dist/browser/content/chart-snapshot.js +1 -1
- package/dist/browser/content/chart-snapshot.js.map +1 -1
- package/dist/browser/content/index.js +1 -0
- package/dist/browser/content/index.js.map +1 -1
- package/dist/browser/feedback/dialog-core.js +135 -23
- package/dist/browser/feedback/dialog-core.js.map +1 -1
- package/dist/browser/index.js +1 -0
- package/dist/browser/index.js.map +1 -1
- package/dist/browser/input-mode.js +40 -0
- package/dist/browser/input-mode.js.map +1 -0
- package/dist/browser/inputs/FileDropTarget.js +24 -9
- package/dist/browser/inputs/FileDropTarget.js.map +1 -1
- package/dist/browser/inputs/FileInputs.js +2 -2
- package/dist/browser/inputs/FileInputs.js.map +1 -1
- package/dist/browser/inputs/SelectChip.js +9 -0
- package/dist/browser/inputs/SelectChip.js.map +1 -1
- package/dist/browser/inputs/emoji/EmojiPicker.js +13 -0
- package/dist/browser/inputs/emoji/EmojiPicker.js.map +1 -1
- package/dist/browser/inputs/file-drop.js.map +1 -1
- package/dist/browser/layout/DetailPanel.js +283 -197
- package/dist/browser/layout/DetailPanel.js.map +1 -1
- package/dist/browser/layout/Discussion.js +233 -185
- package/dist/browser/layout/Discussion.js.map +1 -1
- package/dist/browser/layout/TableOfContents.js +10 -2
- package/dist/browser/layout/TableOfContents.js.map +1 -1
- package/dist/browser/layout/detail-panel-messages.js +35 -0
- package/dist/browser/layout/detail-panel-messages.js.map +1 -0
- package/dist/browser/surfaces/Avatar.js +50 -20
- package/dist/browser/surfaces/Avatar.js.map +1 -1
- package/dist/browser/surfaces/AvatarStack.js +406 -0
- package/dist/browser/surfaces/AvatarStack.js.map +1 -0
- package/dist/browser/surfaces/avatar-messages.js +8 -2
- package/dist/browser/surfaces/avatar-messages.js.map +1 -1
- package/dist/browser/surfaces/index.js +1 -0
- package/dist/browser/surfaces/index.js.map +1 -1
- package/dist/ssr/actions/ContextMenu.js +21 -3
- package/dist/ssr/actions/ContextMenu.js.map +1 -1
- package/dist/ssr/actions/Dropdown.js +140 -72
- package/dist/ssr/actions/Dropdown.js.map +1 -1
- package/dist/ssr/actions/GestureMenu.js +52 -106
- package/dist/ssr/actions/GestureMenu.js.map +1 -1
- package/dist/ssr/actions/Toolbar.js +294 -14
- package/dist/ssr/actions/Toolbar.js.map +1 -1
- package/dist/ssr/actions/index.js.map +1 -1
- package/dist/ssr/actions/menu-rows.js +15 -0
- package/dist/ssr/actions/menu-rows.js.map +1 -0
- package/dist/ssr/actions/menu-sheet.js +138 -0
- package/dist/ssr/actions/menu-sheet.js.map +1 -0
- package/dist/ssr/actions/toolbar-messages.js +20 -0
- package/dist/ssr/actions/toolbar-messages.js.map +1 -0
- package/dist/ssr/chart-inspection.js +3 -0
- package/dist/ssr/chart-inspection.js.map +1 -0
- package/dist/ssr/chat/ChatComposer.js +263 -89
- package/dist/ssr/chat/ChatComposer.js.map +1 -1
- package/dist/ssr/chat/chat-messages.js +19 -1
- package/dist/ssr/chat/chat-messages.js.map +1 -1
- package/dist/ssr/chat/command-search.js +3 -0
- package/dist/ssr/chat/command-search.js.map +1 -1
- package/dist/ssr/chat/index.js +2 -0
- package/dist/ssr/chat/index.js.map +1 -1
- package/dist/ssr/chat/reaction-people.js +15 -0
- package/dist/ssr/chat/reaction-people.js.map +1 -0
- package/dist/ssr/content/Chart.js +6 -15
- package/dist/ssr/content/Chart.js.map +1 -1
- package/dist/ssr/content/ChartSnapshotView.js +7 -10
- package/dist/ssr/content/ChartSnapshotView.js.map +1 -1
- package/dist/ssr/content/MessageRow.js +98 -152
- package/dist/ssr/content/MessageRow.js.map +1 -1
- package/dist/ssr/content/ReactionBar.js +304 -0
- package/dist/ssr/content/ReactionBar.js.map +1 -0
- package/dist/ssr/content/chart-inspection-core.js +557 -0
- package/dist/ssr/content/chart-inspection-core.js.map +1 -0
- package/dist/ssr/content/chart-inspection.js +10 -445
- package/dist/ssr/content/chart-inspection.js.map +1 -1
- package/dist/ssr/content/chart-line-gaps.js +1 -1
- package/dist/ssr/content/chart-line-gaps.js.map +1 -1
- package/dist/ssr/content/chart-snapshot.js +1 -1
- package/dist/ssr/content/chart-snapshot.js.map +1 -1
- package/dist/ssr/content/index.js +1 -0
- package/dist/ssr/content/index.js.map +1 -1
- package/dist/ssr/feedback/dialog-core.js +135 -23
- package/dist/ssr/feedback/dialog-core.js.map +1 -1
- package/dist/ssr/index.js +1 -0
- package/dist/ssr/index.js.map +1 -1
- package/dist/ssr/input-mode.js +40 -0
- package/dist/ssr/input-mode.js.map +1 -0
- package/dist/ssr/inputs/FileDropTarget.js +17 -5
- package/dist/ssr/inputs/FileDropTarget.js.map +1 -1
- package/dist/ssr/inputs/FileInputs.js +2 -2
- package/dist/ssr/inputs/FileInputs.js.map +1 -1
- package/dist/ssr/inputs/SelectChip.js +9 -0
- package/dist/ssr/inputs/SelectChip.js.map +1 -1
- package/dist/ssr/inputs/emoji/EmojiPicker.js +12 -0
- package/dist/ssr/inputs/emoji/EmojiPicker.js.map +1 -1
- package/dist/ssr/inputs/file-drop.js.map +1 -1
- package/dist/ssr/layout/DetailPanel.js +112 -58
- package/dist/ssr/layout/DetailPanel.js.map +1 -1
- package/dist/ssr/layout/Discussion.js +63 -36
- package/dist/ssr/layout/Discussion.js.map +1 -1
- package/dist/ssr/layout/TableOfContents.js +10 -2
- package/dist/ssr/layout/TableOfContents.js.map +1 -1
- package/dist/ssr/layout/detail-panel-messages.js +35 -0
- package/dist/ssr/layout/detail-panel-messages.js.map +1 -0
- package/dist/ssr/surfaces/Avatar.js +20 -2
- package/dist/ssr/surfaces/Avatar.js.map +1 -1
- package/dist/ssr/surfaces/AvatarStack.js +286 -0
- package/dist/ssr/surfaces/AvatarStack.js.map +1 -0
- package/dist/ssr/surfaces/avatar-messages.js +8 -2
- package/dist/ssr/surfaces/avatar-messages.js.map +1 -1
- package/dist/ssr/surfaces/index.js +1 -0
- package/dist/ssr/surfaces/index.js.map +1 -1
- package/dist/styles.css +1 -1
- package/dist/types/actions/ContextMenu.d.ts +8 -0
- package/dist/types/actions/Dropdown.d.ts +12 -5
- package/dist/types/actions/GestureMenu.d.ts +6 -4
- package/dist/types/actions/Toolbar.d.ts +20 -0
- package/dist/types/actions/index.d.ts +1 -1
- package/dist/types/actions/menu-rows.d.ts +5 -0
- package/dist/types/actions/menu-sheet.d.ts +22 -0
- package/dist/types/actions/toolbar-messages.d.ts +8 -0
- package/dist/types/chart-inspection.d.ts +2 -0
- package/dist/types/chat/ChatComposer.d.ts +7 -0
- package/dist/types/chat/chat-messages.d.ts +10 -2
- package/dist/types/chat/command-search.d.ts +2 -0
- package/dist/types/chat/index.d.ts +2 -0
- package/dist/types/chat/reaction-people.d.ts +9 -0
- package/dist/types/content/Chart.d.ts +2 -2
- package/dist/types/content/MessageRow.d.ts +3 -10
- package/dist/types/content/ReactionBar.d.ts +32 -0
- package/dist/types/content/chart-inspection-core.d.ts +61 -0
- package/dist/types/content/chart-inspection.d.ts +4 -20
- package/dist/types/content/chart-snapshot.d.ts +1 -1
- package/dist/types/content/index.d.ts +2 -1
- package/dist/types/feedback/dialog-core.d.ts +16 -1
- package/dist/types/index.d.ts +1 -0
- package/dist/types/input-mode.d.ts +7 -0
- package/dist/types/inputs/FileDropTarget.d.ts +6 -3
- package/dist/types/inputs/SelectChip.d.ts +2 -0
- package/dist/types/inputs/file-drop.d.ts +2 -0
- package/dist/types/layout/DetailPanel.d.ts +11 -0
- package/dist/types/layout/Discussion.d.ts +8 -0
- package/dist/types/layout/TableOfContents.d.ts +2 -0
- package/dist/types/layout/detail-panel-messages.d.ts +15 -0
- package/dist/types/surfaces/Avatar.d.ts +12 -0
- package/dist/types/surfaces/AvatarStack.d.ts +41 -0
- package/dist/types/surfaces/avatar-messages.d.ts +3 -0
- package/dist/types/surfaces/index.d.ts +3 -1
- package/package.json +6 -1
|
@@ -2,20 +2,125 @@ import { createComponent as _$createComponent } from "solid-js/web";
|
|
|
2
2
|
import { ssr as _$ssr } from "solid-js/web";
|
|
3
3
|
import { ssrAttribute as _$ssrAttribute } from "solid-js/web";
|
|
4
4
|
import { escape as _$escape } from "solid-js/web";
|
|
5
|
-
var _tmpl$ = ["<
|
|
6
|
-
_tmpl$2 = ["<span class=\"", "\"
|
|
7
|
-
_tmpl$3 = "<
|
|
8
|
-
_tmpl$4 = ["<
|
|
9
|
-
|
|
5
|
+
var _tmpl$ = ["<i", " aria-hidden=\"true\"></i>"],
|
|
6
|
+
_tmpl$2 = ["<span class=\"", "\">", "</span>"],
|
|
7
|
+
_tmpl$3 = ["<div class=\"", "\" role=\"group\"", ">", "</div>"],
|
|
8
|
+
_tmpl$4 = ["<span class=\"", "\" role=\"separator\"", "></span>"],
|
|
9
|
+
_tmpl$5 = "<span class=\"k2b-toolbar__spacer\" aria-hidden=\"true\"></span>",
|
|
10
|
+
_tmpl$6 = "<i class=\"ti ti-dots\" aria-hidden=\"true\"></i>",
|
|
11
|
+
_tmpl$7 = ["<div class=\"k2b-toolbar__more\" data-overflow=\"hidden\">", "</div>"],
|
|
12
|
+
_tmpl$8 = ["<div class=\"", "\" role=\"toolbar\"", ">", "", "</div>"],
|
|
13
|
+
_tmpl$9 = ["<div class=\"k2b-toolbar-float\">", "</div>"];
|
|
14
|
+
import { createContext, createEffect, createSignal, onCleanup, onMount, Show, sharedConfig, useContext } from "solid-js";
|
|
15
|
+
import { isServer } from "solid-js/web";
|
|
16
|
+
import { Kbd } from "../content/Kbd";
|
|
17
|
+
import { useLocale } from "../intl/locale";
|
|
18
|
+
import { formatShortcut, keyboardPlatform } from "../intl/shortcut";
|
|
19
|
+
import { IconButton } from "./Button";
|
|
20
|
+
import { Dropdown } from "./Dropdown";
|
|
21
|
+
import { useToolbarMessages } from "./toolbar-messages";
|
|
10
22
|
const defaultToolbarOrientation = () => "horizontal";
|
|
11
23
|
const ToolbarOrientationContext = createContext(defaultToolbarOrientation);
|
|
12
|
-
|
|
24
|
+
|
|
25
|
+
// `item` is created once per action: the More menu keys its rows by identity, so a remeasure keeps a focused row.
|
|
26
|
+
|
|
27
|
+
const ToolbarActionsContext = createContext();
|
|
28
|
+
const overflowAttribute = "data-overflow";
|
|
29
|
+
const hide = element => element.setAttribute(overflowAttribute, "hidden");
|
|
30
|
+
const reveal = element => element.removeAttribute(overflowAttribute);
|
|
31
|
+
|
|
32
|
+
// ARIA uses language-independent key names, unlike the translated tooltip and caps.
|
|
33
|
+
const ariaShortcut = (keys, platform) => {
|
|
34
|
+
if (!keys || !formatShortcut(keys, {
|
|
35
|
+
platform,
|
|
36
|
+
locale: "en"
|
|
37
|
+
}).keys.length) return undefined;
|
|
38
|
+
const input = keys.trim().toLowerCase();
|
|
39
|
+
const plus = input === "+" || input.endsWith("++");
|
|
40
|
+
const parts = (plus ? input.slice(0, -1) : input).split("+");
|
|
41
|
+
// ARIA separates keys with "+", so the plus key itself is named "plus".
|
|
42
|
+
const key = plus ? "plus" : parts.pop() || "space";
|
|
43
|
+
if (plus) parts.pop();
|
|
44
|
+
const names = {
|
|
45
|
+
mod: platform === "apple" ? "Meta" : "Control",
|
|
46
|
+
ctrl: "Control",
|
|
47
|
+
alt: "Alt",
|
|
48
|
+
shift: "Shift",
|
|
49
|
+
meta: "Meta",
|
|
50
|
+
arrowup: "ArrowUp",
|
|
51
|
+
arrowdown: "ArrowDown",
|
|
52
|
+
arrowleft: "ArrowLeft",
|
|
53
|
+
arrowright: "ArrowRight",
|
|
54
|
+
escape: "Escape",
|
|
55
|
+
esc: "Escape",
|
|
56
|
+
backspace: "Backspace",
|
|
57
|
+
enter: "Enter",
|
|
58
|
+
delete: "Delete",
|
|
59
|
+
space: "Space",
|
|
60
|
+
tab: "Tab",
|
|
61
|
+
home: "Home",
|
|
62
|
+
end: "End",
|
|
63
|
+
pageup: "PageUp",
|
|
64
|
+
pagedown: "PageDown",
|
|
65
|
+
plus: "plus"
|
|
66
|
+
};
|
|
67
|
+
const final = key.length === 1 || /^f(?:[1-9]|1[0-2])$/.test(key) ? key.toUpperCase() : names[key];
|
|
68
|
+
return final ? [...new Set(parts.map(part => names[part])), final].join("+") : undefined;
|
|
69
|
+
};
|
|
70
|
+
const ToolbarAction = props => {
|
|
71
|
+
const register = useContext(ToolbarActionsContext);
|
|
72
|
+
const locale = useLocale();
|
|
73
|
+
const [platform, setPlatform] = createSignal(isServer || sharedConfig.context ? "other" : keyboardPlatform());
|
|
74
|
+
onMount(() => setPlatform(keyboardPlatform()));
|
|
75
|
+
const tooltip = () => {
|
|
76
|
+
const shortcut = props.keys ? formatShortcut(props.keys, {
|
|
77
|
+
platform: platform(),
|
|
78
|
+
locale: locale()
|
|
79
|
+
}).label : "";
|
|
80
|
+
return shortcut ? `${props.label} (${shortcut})` : props.label;
|
|
81
|
+
};
|
|
82
|
+
return _$createComponent(IconButton, {
|
|
83
|
+
"class": "k2b-toolbar__action",
|
|
84
|
+
get label() {
|
|
85
|
+
return props.label;
|
|
86
|
+
},
|
|
87
|
+
variant: "ghost",
|
|
88
|
+
get tooltip() {
|
|
89
|
+
return tooltip();
|
|
90
|
+
},
|
|
91
|
+
get ["aria-keyshortcuts"]() {
|
|
92
|
+
return ariaShortcut(props.keys, platform());
|
|
93
|
+
},
|
|
94
|
+
get ["data-priority"]() {
|
|
95
|
+
return props.priority;
|
|
96
|
+
},
|
|
97
|
+
get disabled() {
|
|
98
|
+
return props.disabled;
|
|
99
|
+
},
|
|
100
|
+
onClick: () => props.onClick?.(),
|
|
101
|
+
get children() {
|
|
102
|
+
return [_$ssr(_tmpl$, _$ssrAttribute("class", _$escape(props.icon, true), false)), _$createComponent(Show, {
|
|
103
|
+
get when() {
|
|
104
|
+
return props.keys;
|
|
105
|
+
},
|
|
106
|
+
children: keys => _$createComponent(Kbd, {
|
|
107
|
+
get keys() {
|
|
108
|
+
return keys();
|
|
109
|
+
},
|
|
110
|
+
"class": "k2b-kbd-hint k2b-toolbar__hint"
|
|
111
|
+
})
|
|
112
|
+
})];
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
};
|
|
116
|
+
const ToolbarLabel = props => _$ssr(_tmpl$2, `k2b-toolbar__label ${_$escape(props.class ?? "", true)}`, _$escape(props.children));
|
|
117
|
+
const ToolbarGroup = props => _$ssr(_tmpl$3, `k2b-toolbar__group ${_$escape(props.class ?? "", true)}`, _$ssrAttribute("aria-label", _$escape(props.label, true), false), _$escape(props.children));
|
|
13
118
|
const ToolbarSeparator = props => {
|
|
14
119
|
const toolbarOrientation = useContext(ToolbarOrientationContext);
|
|
15
120
|
const separatorOrientation = () => toolbarOrientation() === "horizontal" ? "vertical" : "horizontal";
|
|
16
|
-
return _$ssr(_tmpl$
|
|
121
|
+
return _$ssr(_tmpl$4, `k2b-toolbar__separator ${_$escape(props.class ?? "", true)}`, _$ssrAttribute("aria-orientation", _$escape(separatorOrientation(), true), false) + _$ssrAttribute("data-orientation", _$escape(separatorOrientation(), true), false));
|
|
17
122
|
};
|
|
18
|
-
const ToolbarSpacer = () => _$ssr(_tmpl$
|
|
123
|
+
const ToolbarSpacer = () => _$ssr(_tmpl$5);
|
|
19
124
|
const rovingFocus = (root, orientation) => {
|
|
20
125
|
let last;
|
|
21
126
|
const setLast = item => {
|
|
@@ -29,7 +134,7 @@ const rovingFocus = (root, orientation) => {
|
|
|
29
134
|
const nested = item.closest('[role="menu"], [role="listbox"], [role="dialog"], [popover]');
|
|
30
135
|
return !nested || !root.contains(nested);
|
|
31
136
|
});
|
|
32
|
-
const items = () => controls().filter(item => !item.matches(":disabled") && item.getClientRects().length > 0);
|
|
137
|
+
const items = () => controls().filter(item => !item.matches(":disabled") && !item.closest('[data-overflow="hidden"]') && item.getClientRects().length > 0);
|
|
33
138
|
const sync = () => {
|
|
34
139
|
const available = items();
|
|
35
140
|
if (!last || !available.includes(last)) setLast(available[0]);
|
|
@@ -61,7 +166,7 @@ const rovingFocus = (root, orientation) => {
|
|
|
61
166
|
childList: true,
|
|
62
167
|
subtree: true,
|
|
63
168
|
attributes: true,
|
|
64
|
-
attributeFilter: ["disabled", "hidden", "class", "style"]
|
|
169
|
+
attributeFilter: ["disabled", "hidden", "class", "style", overflowAttribute]
|
|
65
170
|
});
|
|
66
171
|
const resizeObserver = new ResizeObserver(sync);
|
|
67
172
|
resizeObserver.observe(root);
|
|
@@ -69,6 +174,7 @@ const rovingFocus = (root, orientation) => {
|
|
|
69
174
|
sync();
|
|
70
175
|
return {
|
|
71
176
|
keydown,
|
|
177
|
+
sync,
|
|
72
178
|
cleanup: () => {
|
|
73
179
|
observer.disconnect();
|
|
74
180
|
resizeObserver.disconnect();
|
|
@@ -76,21 +182,195 @@ const rovingFocus = (root, orientation) => {
|
|
|
76
182
|
}
|
|
77
183
|
};
|
|
78
184
|
};
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* All measurement writes are DOM attributes: reactive writes do not flush during onMount. More is never toggled while
|
|
188
|
+
* measuring: hiding it, even for a moment, can make the browser drop focus from it or from its open menu. An idle More
|
|
189
|
+
* stays out of the flow but keeps its box, so its width is always known.
|
|
190
|
+
*/
|
|
191
|
+
const measureOverflow = (root, more, actions, available) => {
|
|
192
|
+
for (const element of root.querySelectorAll(`[${overflowAttribute}]`)) if (element !== more) reveal(element);
|
|
193
|
+
const children = Array.from(root.children).filter(element => element instanceof HTMLElement && element !== more);
|
|
194
|
+
const visible = element => !element.matches("[popover]") && element.getClientRects().length > 0;
|
|
195
|
+
const separator = element => element.classList.contains("k2b-toolbar__separator");
|
|
196
|
+
const item = element => !separator(element) && !element.classList.contains("k2b-toolbar__spacer");
|
|
197
|
+
// Separators are tidied in DOM order with More, the last control, counted as shown when `withMore` is set.
|
|
198
|
+
const all = Array.from(root.children).filter(element => element instanceof HTMLElement);
|
|
199
|
+
const tidy = withMore => {
|
|
200
|
+
for (const group of root.querySelectorAll(".k2b-toolbar__group")) {
|
|
201
|
+
reveal(group);
|
|
202
|
+
if (!Array.from(group.children).some(visible)) hide(group);
|
|
203
|
+
}
|
|
204
|
+
for (const child of children) if (separator(child)) reveal(child);
|
|
205
|
+
const shown = element => element === more ? withMore : visible(element);
|
|
206
|
+
let preceding = false;
|
|
207
|
+
for (let index = 0; index < all.length; index++) {
|
|
208
|
+
const child = all[index];
|
|
209
|
+
if (!shown(child)) continue;
|
|
210
|
+
if (separator(child)) {
|
|
211
|
+
const following = all.slice(index + 1).some(next => item(next) && shown(next));
|
|
212
|
+
if (!preceding || !following) hide(child);else preceding = false;
|
|
213
|
+
} else if (item(child)) preceding = true;
|
|
214
|
+
}
|
|
215
|
+
};
|
|
216
|
+
const style = getComputedStyle(root);
|
|
217
|
+
const edges = [style.paddingLeft, style.paddingRight, style.borderLeftWidth, style.borderRightWidth].reduce((sum, value) => sum + (Number.parseFloat(value) || 0), 0);
|
|
218
|
+
const gap = Number.parseFloat(style.columnGap) || 0;
|
|
219
|
+
// A label may shrink in an overfull pill; measure its untruncated width (up to its cap) so actions move before the
|
|
220
|
+
// count or title truncates.
|
|
221
|
+
const width = child => {
|
|
222
|
+
// Separators carry inline margins, which bounding boxes leave out.
|
|
223
|
+
const childStyle = getComputedStyle(child);
|
|
224
|
+
const box = child.getBoundingClientRect().width + (Number.parseFloat(childStyle.marginLeft) || 0) + (Number.parseFloat(childStyle.marginRight) || 0);
|
|
225
|
+
if (!child.classList.contains("k2b-toolbar__label")) return box;
|
|
226
|
+
const cap = Number.parseFloat(childStyle.maxWidth);
|
|
227
|
+
return Math.max(box, Math.min(child.scrollWidth, Number.isNaN(cap) ? Number.POSITIVE_INFINITY : cap));
|
|
228
|
+
};
|
|
229
|
+
const moreWidth = width(more) + gap;
|
|
230
|
+
const used = withMore => {
|
|
231
|
+
const shown = children.filter(visible);
|
|
232
|
+
return shown.reduce((sum, child) => sum + width(child), edges) + gap * Math.max(0, shown.length - 1) + (withMore ? moreWidth : 0);
|
|
233
|
+
};
|
|
234
|
+
// Stable sort retains DOM order for the menu, but removes later actions first on a priority tie.
|
|
235
|
+
const candidates = actions
|
|
236
|
+
// An action its application hides, even with `visibility: hidden`, must not reappear as a More row.
|
|
237
|
+
.filter(action => action.props.priority !== undefined && visible(action.element) && getComputedStyle(action.element).visibility !== "hidden").reverse().sort((a, b) => b.props.priority - a.props.priority);
|
|
238
|
+
let movedAny = false;
|
|
239
|
+
tidy(false);
|
|
240
|
+
for (const action of candidates) {
|
|
241
|
+
if (used(movedAny) <= available) break;
|
|
242
|
+
hide(action.element);
|
|
243
|
+
movedAny = true;
|
|
244
|
+
tidy(true);
|
|
245
|
+
}
|
|
246
|
+
// More changes only here, and only when its state changes.
|
|
247
|
+
if (movedAny) reveal(more);else if (!more.hasAttribute(overflowAttribute)) hide(more);
|
|
248
|
+
return actions.filter(action => action.element.hasAttribute(overflowAttribute));
|
|
249
|
+
};
|
|
79
250
|
export const Toolbar = Object.assign(props => {
|
|
80
|
-
|
|
251
|
+
// The variant decides the DOM shape, so it is read once.
|
|
252
|
+
const floating = props.variant === "floating";
|
|
253
|
+
const orientation = () => floating ? "horizontal" : props.orientation ?? "horizontal";
|
|
254
|
+
const messages = useToolbarMessages();
|
|
255
|
+
const actions = new Set();
|
|
256
|
+
const [revision, setRevision] = createSignal(0);
|
|
257
|
+
const [moved, setMoved] = createSignal([]);
|
|
81
258
|
let root;
|
|
259
|
+
let strip;
|
|
260
|
+
let more;
|
|
261
|
+
let trigger;
|
|
262
|
+
let mounted = false;
|
|
82
263
|
let navigation;
|
|
264
|
+
// Only the floating variant moves actions into More; inline toolbars keep every action in place.
|
|
265
|
+
const measure = () => {
|
|
266
|
+
if (!mounted || !strip || !more) return;
|
|
267
|
+
const style = getComputedStyle(strip);
|
|
268
|
+
const available = strip.clientWidth - Number.parseFloat(style.paddingLeft) - Number.parseFloat(style.paddingRight);
|
|
269
|
+
if (available <= 0) return;
|
|
270
|
+
const ordered = [...actions].sort((a, b) => a.element.compareDocumentPosition(b.element) & Node.DOCUMENT_POSITION_FOLLOWING ? -1 : 1);
|
|
271
|
+
const focused = document.activeElement;
|
|
272
|
+
// Cleared before measuring so the pending `visibility: hidden` does not hide every action from the check
|
|
273
|
+
// below; the whole measurement still runs before the next paint.
|
|
274
|
+
root.removeAttribute("data-overflow-pending");
|
|
275
|
+
const next = measureOverflow(root, more, ordered, available);
|
|
276
|
+
setMoved(previous => previous.length === next.length && previous.every((action, index) => action === next[index]) ? previous : next);
|
|
277
|
+
navigation?.sync();
|
|
278
|
+
// Focus on an action that moved, on a menu row whose action came back, or on a More that disappeared goes to
|
|
279
|
+
// More, or to the toolbar's tab stop when nothing is left in More. Inside an effect the menu rows update after
|
|
280
|
+
// this function returns, so the check waits for that flush; a microtask still runs before the next paint.
|
|
281
|
+
queueMicrotask(() => {
|
|
282
|
+
const lost = next.some(action => action.element === focused) || focused instanceof HTMLElement && !focused.isConnected || focused === trigger && !next.length;
|
|
283
|
+
if (lost) (next.length ? trigger : root.querySelector('[tabindex="0"]'))?.focus();
|
|
284
|
+
});
|
|
285
|
+
};
|
|
286
|
+
const register = action => {
|
|
287
|
+
actions.add(action);
|
|
288
|
+
setRevision(value => value + 1);
|
|
289
|
+
return () => {
|
|
290
|
+
actions.delete(action);
|
|
291
|
+
setRevision(value => value + 1);
|
|
292
|
+
};
|
|
293
|
+
};
|
|
294
|
+
if (floating) createEffect(() => {
|
|
295
|
+
revision();
|
|
296
|
+
for (const action of actions) {
|
|
297
|
+
// Content and priority changes can affect intrinsic widths as well as menu rows.
|
|
298
|
+
void action.props.priority;
|
|
299
|
+
void action.props.label;
|
|
300
|
+
void action.props.icon;
|
|
301
|
+
void action.props.keys;
|
|
302
|
+
}
|
|
303
|
+
measure();
|
|
304
|
+
});
|
|
83
305
|
onMount(() => {
|
|
306
|
+
mounted = true;
|
|
84
307
|
navigation = rovingFocus(root, orientation);
|
|
85
|
-
onCleanup(
|
|
308
|
+
onCleanup(() => {
|
|
309
|
+
mounted = false;
|
|
310
|
+
navigation?.cleanup();
|
|
311
|
+
});
|
|
312
|
+
if (!strip) return;
|
|
313
|
+
measure();
|
|
314
|
+
const observer = new ResizeObserver(measure);
|
|
315
|
+
observer.observe(strip);
|
|
316
|
+
observer.observe(root);
|
|
317
|
+
const mutations = new MutationObserver(measure);
|
|
318
|
+
// Visibility an application sets also counts. Measurement writes only data attributes, which stay unobserved.
|
|
319
|
+
mutations.observe(root, {
|
|
320
|
+
childList: true,
|
|
321
|
+
subtree: true,
|
|
322
|
+
characterData: true,
|
|
323
|
+
attributes: true,
|
|
324
|
+
attributeFilter: ["hidden", "class", "style"]
|
|
325
|
+
});
|
|
326
|
+
onCleanup(() => {
|
|
327
|
+
observer.disconnect();
|
|
328
|
+
mutations.disconnect();
|
|
329
|
+
});
|
|
86
330
|
});
|
|
87
|
-
|
|
331
|
+
const menuItems = () => moved().map(action => action.item);
|
|
332
|
+
const content = _$createComponent(ToolbarOrientationContext.Provider, {
|
|
88
333
|
value: orientation,
|
|
89
334
|
get children() {
|
|
90
|
-
return _$
|
|
335
|
+
return _$createComponent(ToolbarActionsContext.Provider, {
|
|
336
|
+
value: floating ? register : undefined,
|
|
337
|
+
get children() {
|
|
338
|
+
return _$ssr(_tmpl$8, `k2b-toolbar ${_$escape(props.class ?? "", true)}`, _$ssrAttribute("aria-label", _$escape(props.label, true), false) + _$ssrAttribute("aria-orientation", _$escape(orientation(), true), false) + _$ssrAttribute("data-orientation", _$escape(orientation(), true), false) + _$ssrAttribute("data-variant", floating ? "floating" : _$escape(undefined, true), false) + _$ssrAttribute("data-wrap", !floating && props.wrap ? "true" : _$escape(undefined, true), false) + _$ssrAttribute("data-overflow-pending", floating ? "" : _$escape(undefined, true), false), _$escape(props.children), _$escape(_$createComponent(Show, {
|
|
339
|
+
when: floating,
|
|
340
|
+
get children() {
|
|
341
|
+
return _$ssr(_tmpl$7, _$escape(_$createComponent(Dropdown.Root, {
|
|
342
|
+
get items() {
|
|
343
|
+
return menuItems();
|
|
344
|
+
},
|
|
345
|
+
position: "top-left",
|
|
346
|
+
get label() {
|
|
347
|
+
return messages().moreActions;
|
|
348
|
+
},
|
|
349
|
+
get disabled() {
|
|
350
|
+
return moved().length === 0;
|
|
351
|
+
},
|
|
352
|
+
get children() {
|
|
353
|
+
return _$createComponent(Dropdown.Trigger, {
|
|
354
|
+
iconOnly: true,
|
|
355
|
+
get label() {
|
|
356
|
+
return messages().moreActions;
|
|
357
|
+
},
|
|
358
|
+
get children() {
|
|
359
|
+
return _$ssr(_tmpl$6);
|
|
360
|
+
}
|
|
361
|
+
});
|
|
362
|
+
}
|
|
363
|
+
})));
|
|
364
|
+
}
|
|
365
|
+
})));
|
|
366
|
+
}
|
|
367
|
+
});
|
|
91
368
|
}
|
|
92
369
|
});
|
|
370
|
+
return floating ? _$ssr(_tmpl$9, _$escape(content)) : content;
|
|
93
371
|
}, {
|
|
372
|
+
Action: ToolbarAction,
|
|
373
|
+
Label: ToolbarLabel,
|
|
94
374
|
Group: ToolbarGroup,
|
|
95
375
|
Separator: ToolbarSeparator,
|
|
96
376
|
Spacer: ToolbarSpacer
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":[],"sources":["actions/Toolbar.tsx"],"sourcesContent":["import { createContext, type JSX, onCleanup, onMount, useContext } from \"solid-js\";\n\nexport type ToolbarProps = {\n children: JSX.Element;\n label: string;\n orientation?: \"horizontal\" | \"vertical\";\n wrap?: boolean;\n class?: string;\n};\n\nexport type ToolbarGroupProps = { children: JSX.Element; label?: string; class?: string };\nexport type ToolbarSeparatorProps = { class?: string };\n\ntype ToolbarComponent = ((props: ToolbarProps) => JSX.Element) & {\n Group: (props: ToolbarGroupProps) => JSX.Element;\n Separator: (props: ToolbarSeparatorProps) => JSX.Element;\n Spacer: () => JSX.Element;\n};\n\ntype ToolbarOrientation = NonNullable<ToolbarProps[\"orientation\"]>;\n\nconst defaultToolbarOrientation: () => ToolbarOrientation = () => \"horizontal\";\nconst ToolbarOrientationContext = createContext(defaultToolbarOrientation);\n\nconst ToolbarGroup = (props: ToolbarGroupProps): JSX.Element => (\n <div class={`k2b-toolbar__group ${props.class ?? \"\"}`} role=\"group\" aria-label={props.label}>\n {props.children}\n </div>\n);\n\nconst ToolbarSeparator = (props: ToolbarSeparatorProps): JSX.Element => {\n const toolbarOrientation = useContext(ToolbarOrientationContext);\n const separatorOrientation = () => (toolbarOrientation() === \"horizontal\" ? \"vertical\" : \"horizontal\");\n\n return (\n <span\n class={`k2b-toolbar__separator ${props.class ?? \"\"}`}\n role=\"separator\"\n aria-orientation={separatorOrientation()}\n data-orientation={separatorOrientation()}\n />\n );\n};\n\nconst ToolbarSpacer = (): JSX.Element => <span class=\"k2b-toolbar__spacer\" aria-hidden=\"true\" />;\n\nconst rovingFocus = (root: HTMLDivElement, orientation: () => ToolbarOrientation) => {\n let last: HTMLElement | undefined;\n const setLast = (item: HTMLElement | undefined) => {\n if (item === last) return;\n if (last) resizeObserver.unobserve(last);\n last = item;\n if (last) resizeObserver.observe(last);\n };\n const controls = () =>\n Array.from(root.querySelectorAll<HTMLElement>(\"button, a[href], input, select, textarea, [tabindex]\")).filter((item) => {\n if (\n item.matches(\"textarea, select\") ||\n item.isContentEditable ||\n (item.matches(\"input\") && !/^(button|checkbox|reset|submit|image|color|file)$/i.test(item.getAttribute(\"type\") ?? \"text\"))\n )\n return false;\n const nested = item.closest('[role=\"menu\"], [role=\"listbox\"], [role=\"dialog\"], [popover]');\n return !nested || !root.contains(nested);\n });\n const items = () => controls().filter((item) => !item.matches(\":disabled\") && item.getClientRects().length > 0);\n const sync = () => {\n const available = items();\n if (!last || !available.includes(last)) setLast(available[0]);\n for (const item of controls()) item.tabIndex = item === last ? 0 : -1;\n };\n const focusin = (event: FocusEvent) => {\n if (event.target instanceof HTMLElement && items().includes(event.target)) {\n setLast(event.target);\n sync();\n }\n };\n const keydown = (event: KeyboardEvent) => {\n if (event.defaultPrevented || event.altKey || event.ctrlKey || event.metaKey || event.shiftKey) return;\n const available = items();\n const target = event.target;\n if (!(target instanceof HTMLElement) || !available.includes(target)) return;\n const forward = orientation() === \"vertical\" ? \"ArrowDown\" : getComputedStyle(root).direction === \"rtl\" ? \"ArrowLeft\" : \"ArrowRight\";\n const backward = orientation() === \"vertical\" ? \"ArrowUp\" : forward === \"ArrowRight\" ? \"ArrowLeft\" : \"ArrowRight\";\n const index = available.indexOf(target);\n const next =\n event.key === \"Home\"\n ? 0\n : event.key === \"End\"\n ? available.length - 1\n : event.key === forward\n ? (index + 1) % available.length\n : event.key === backward\n ? (index + available.length - 1) % available.length\n : -1;\n if (next < 0) return;\n event.preventDefault();\n setLast(available[next]);\n sync();\n last?.focus();\n };\n const observer = new MutationObserver(sync);\n observer.observe(root, { childList: true, subtree: true, attributes: true, attributeFilter: [\"disabled\", \"hidden\", \"class\", \"style\"] });\n const resizeObserver = new ResizeObserver(sync);\n resizeObserver.observe(root);\n root.addEventListener(\"focusin\", focusin);\n sync();\n return {\n keydown,\n cleanup: () => {\n observer.disconnect();\n resizeObserver.disconnect();\n root.removeEventListener(\"focusin\", focusin);\n },\n };\n};\n\nexport const Toolbar = Object.assign(\n (props: ToolbarProps): JSX.Element => {\n const orientation = () => props.orientation ?? \"horizontal\";\n let root!: HTMLDivElement;\n let navigation: ReturnType<typeof rovingFocus> | undefined;\n onMount(() => {\n navigation = rovingFocus(root, orientation);\n onCleanup(navigation.cleanup);\n });\n\n return (\n <ToolbarOrientationContext.Provider value={orientation}>\n <div\n ref={root}\n onKeyDown={(event) => navigation?.keydown(event)}\n class={`k2b-toolbar ${props.class ?? \"\"}`}\n role=\"toolbar\"\n aria-label={props.label}\n aria-orientation={orientation()}\n data-orientation={orientation()}\n data-wrap={props.wrap ? \"true\" : undefined}\n >\n {props.children}\n </div>\n </ToolbarOrientationContext.Provider>\n );\n },\n { Group: ToolbarGroup, Separator: ToolbarSeparator, Spacer: ToolbarSpacer },\n) as ToolbarComponent;\n\nexport default Toolbar;\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"names":[],"sources":["actions/Toolbar.tsx"],"sourcesContent":["import { createContext, createEffect, createSignal, type JSX, onCleanup, onMount, Show, sharedConfig, useContext } from \"solid-js\";\nimport { isServer } from \"solid-js/web\";\nimport { Kbd } from \"../content/Kbd\";\nimport { useLocale } from \"../intl/locale\";\nimport { formatShortcut, type KeyboardPlatform, keyboardPlatform } from \"../intl/shortcut\";\nimport { IconButton } from \"./Button\";\nimport { Dropdown, type DropdownAction } from \"./Dropdown\";\nimport { useToolbarMessages } from \"./toolbar-messages\";\n\nexport type ToolbarProps = {\n children: JSX.Element;\n label: string;\n orientation?: \"horizontal\" | \"vertical\";\n wrap?: boolean;\n /** `floating` floats the toolbar at the bottom of its column. Defaults to `inline`. */\n variant?: \"inline\" | \"floating\";\n class?: string;\n};\n\nexport type ToolbarActionProps = {\n /** Accessible name, tooltip text, and the row label in the More menu. */\n label: string;\n /** Icon class, such as \"ti ti-archive\". */\n icon: string;\n /** Shortcut hint, tooltip suffix, and aria-keyshortcuts; does not register a shortcut handler. */\n keys?: string;\n /** 1 is most important. Larger numbers move first; ties move later DOM actions first. Omit to keep fixed. */\n priority?: number;\n disabled?: boolean;\n onClick?: () => void;\n};\nexport type ToolbarLabelProps = { children: JSX.Element; class?: string };\n\nexport type ToolbarGroupProps = { children: JSX.Element; label?: string; class?: string };\nexport type ToolbarSeparatorProps = { class?: string };\n\ntype ToolbarComponent = ((props: ToolbarProps) => JSX.Element) & {\n Action: (props: ToolbarActionProps) => JSX.Element;\n Label: (props: ToolbarLabelProps) => JSX.Element;\n Group: (props: ToolbarGroupProps) => JSX.Element;\n Separator: (props: ToolbarSeparatorProps) => JSX.Element;\n Spacer: () => JSX.Element;\n};\n\ntype ToolbarOrientation = NonNullable<ToolbarProps[\"orientation\"]>;\n\nconst defaultToolbarOrientation: () => ToolbarOrientation = () => \"horizontal\";\nconst ToolbarOrientationContext = createContext(defaultToolbarOrientation);\n\n// `item` is created once per action: the More menu keys its rows by identity, so a remeasure keeps a focused row.\ntype RegisteredAction = { element: HTMLButtonElement; props: ToolbarActionProps; item: DropdownAction };\nconst ToolbarActionsContext = createContext<(action: RegisteredAction) => () => void>();\nconst overflowAttribute = \"data-overflow\";\nconst hide = (element: Element) => element.setAttribute(overflowAttribute, \"hidden\");\nconst reveal = (element: Element) => element.removeAttribute(overflowAttribute);\n\n// ARIA uses language-independent key names, unlike the translated tooltip and caps.\nconst ariaShortcut = (keys: string | undefined, platform: KeyboardPlatform): string | undefined => {\n if (!keys || !formatShortcut(keys, { platform, locale: \"en\" }).keys.length) return undefined;\n const input = keys.trim().toLowerCase();\n const plus = input === \"+\" || input.endsWith(\"++\");\n const parts = (plus ? input.slice(0, -1) : input).split(\"+\");\n // ARIA separates keys with \"+\", so the plus key itself is named \"plus\".\n const key = plus ? \"plus\" : parts.pop() || \"space\";\n if (plus) parts.pop();\n const names: Record<string, string> = {\n mod: platform === \"apple\" ? \"Meta\" : \"Control\",\n ctrl: \"Control\",\n alt: \"Alt\",\n shift: \"Shift\",\n meta: \"Meta\",\n arrowup: \"ArrowUp\",\n arrowdown: \"ArrowDown\",\n arrowleft: \"ArrowLeft\",\n arrowright: \"ArrowRight\",\n escape: \"Escape\",\n esc: \"Escape\",\n backspace: \"Backspace\",\n enter: \"Enter\",\n delete: \"Delete\",\n space: \"Space\",\n tab: \"Tab\",\n home: \"Home\",\n end: \"End\",\n pageup: \"PageUp\",\n pagedown: \"PageDown\",\n plus: \"plus\",\n };\n const final = key.length === 1 || /^f(?:[1-9]|1[0-2])$/.test(key) ? key.toUpperCase() : names[key];\n return final ? [...new Set(parts.map((part) => names[part])), final].join(\"+\") : undefined;\n};\n\nconst ToolbarAction = (props: ToolbarActionProps): JSX.Element => {\n const register = useContext(ToolbarActionsContext);\n const locale = useLocale();\n const [platform, setPlatform] = createSignal<KeyboardPlatform>(isServer || sharedConfig.context ? \"other\" : keyboardPlatform());\n onMount(() => setPlatform(keyboardPlatform()));\n const tooltip = () => {\n const shortcut = props.keys ? formatShortcut(props.keys, { platform: platform(), locale: locale() }).label : \"\";\n return shortcut ? `${props.label} (${shortcut})` : props.label;\n };\n return (\n <IconButton\n ref={(element) => {\n const item: DropdownAction = {\n get label() {\n return props.label;\n },\n get icon() {\n return props.icon;\n },\n get disabled() {\n return props.disabled;\n },\n action: () => props.onClick?.(),\n };\n const unregister = register?.({ element, props, item });\n if (unregister) onCleanup(unregister);\n }}\n class=\"k2b-toolbar__action\"\n label={props.label}\n variant=\"ghost\"\n tooltip={tooltip()}\n aria-keyshortcuts={ariaShortcut(props.keys, platform())}\n data-priority={props.priority}\n disabled={props.disabled}\n onClick={() => props.onClick?.()}\n >\n <i class={props.icon} aria-hidden=\"true\" />\n <Show when={props.keys}>{(keys) => <Kbd keys={keys()} class=\"k2b-kbd-hint k2b-toolbar__hint\" />}</Show>\n </IconButton>\n );\n};\n\nconst ToolbarLabel = (props: ToolbarLabelProps): JSX.Element => (\n <span class={`k2b-toolbar__label ${props.class ?? \"\"}`}>{props.children}</span>\n);\n\nconst ToolbarGroup = (props: ToolbarGroupProps): JSX.Element => (\n <div class={`k2b-toolbar__group ${props.class ?? \"\"}`} role=\"group\" aria-label={props.label}>\n {props.children}\n </div>\n);\n\nconst ToolbarSeparator = (props: ToolbarSeparatorProps): JSX.Element => {\n const toolbarOrientation = useContext(ToolbarOrientationContext);\n const separatorOrientation = () => (toolbarOrientation() === \"horizontal\" ? \"vertical\" : \"horizontal\");\n\n return (\n <span\n class={`k2b-toolbar__separator ${props.class ?? \"\"}`}\n role=\"separator\"\n aria-orientation={separatorOrientation()}\n data-orientation={separatorOrientation()}\n />\n );\n};\n\nconst ToolbarSpacer = (): JSX.Element => <span class=\"k2b-toolbar__spacer\" aria-hidden=\"true\" />;\n\nconst rovingFocus = (root: HTMLDivElement, orientation: () => ToolbarOrientation) => {\n let last: HTMLElement | undefined;\n const setLast = (item: HTMLElement | undefined) => {\n if (item === last) return;\n if (last) resizeObserver.unobserve(last);\n last = item;\n if (last) resizeObserver.observe(last);\n };\n const controls = () =>\n Array.from(root.querySelectorAll<HTMLElement>(\"button, a[href], input, select, textarea, [tabindex]\")).filter((item) => {\n if (\n item.matches(\"textarea, select\") ||\n item.isContentEditable ||\n (item.matches(\"input\") && !/^(button|checkbox|reset|submit|image|color|file)$/i.test(item.getAttribute(\"type\") ?? \"text\"))\n )\n return false;\n const nested = item.closest('[role=\"menu\"], [role=\"listbox\"], [role=\"dialog\"], [popover]');\n return !nested || !root.contains(nested);\n });\n const items = () =>\n controls().filter(\n (item) => !item.matches(\":disabled\") && !item.closest('[data-overflow=\"hidden\"]') && item.getClientRects().length > 0,\n );\n const sync = () => {\n const available = items();\n if (!last || !available.includes(last)) setLast(available[0]);\n for (const item of controls()) item.tabIndex = item === last ? 0 : -1;\n };\n const focusin = (event: FocusEvent) => {\n if (event.target instanceof HTMLElement && items().includes(event.target)) {\n setLast(event.target);\n sync();\n }\n };\n const keydown = (event: KeyboardEvent) => {\n if (event.defaultPrevented || event.altKey || event.ctrlKey || event.metaKey || event.shiftKey) return;\n const available = items();\n const target = event.target;\n if (!(target instanceof HTMLElement) || !available.includes(target)) return;\n const forward = orientation() === \"vertical\" ? \"ArrowDown\" : getComputedStyle(root).direction === \"rtl\" ? \"ArrowLeft\" : \"ArrowRight\";\n const backward = orientation() === \"vertical\" ? \"ArrowUp\" : forward === \"ArrowRight\" ? \"ArrowLeft\" : \"ArrowRight\";\n const index = available.indexOf(target);\n const next =\n event.key === \"Home\"\n ? 0\n : event.key === \"End\"\n ? available.length - 1\n : event.key === forward\n ? (index + 1) % available.length\n : event.key === backward\n ? (index + available.length - 1) % available.length\n : -1;\n if (next < 0) return;\n event.preventDefault();\n setLast(available[next]);\n sync();\n last?.focus();\n };\n const observer = new MutationObserver(sync);\n observer.observe(root, {\n childList: true,\n subtree: true,\n attributes: true,\n attributeFilter: [\"disabled\", \"hidden\", \"class\", \"style\", overflowAttribute],\n });\n const resizeObserver = new ResizeObserver(sync);\n resizeObserver.observe(root);\n root.addEventListener(\"focusin\", focusin);\n sync();\n return {\n keydown,\n sync,\n cleanup: () => {\n observer.disconnect();\n resizeObserver.disconnect();\n root.removeEventListener(\"focusin\", focusin);\n },\n };\n};\n\n/**\n * All measurement writes are DOM attributes: reactive writes do not flush during onMount. More is never toggled while\n * measuring: hiding it, even for a moment, can make the browser drop focus from it or from its open menu. An idle More\n * stays out of the flow but keeps its box, so its width is always known.\n */\nconst measureOverflow = (\n root: HTMLDivElement,\n more: HTMLDivElement,\n actions: RegisteredAction[],\n available: number,\n): RegisteredAction[] => {\n for (const element of root.querySelectorAll(`[${overflowAttribute}]`)) if (element !== more) reveal(element);\n const children = Array.from(root.children).filter(\n (element): element is HTMLElement => element instanceof HTMLElement && element !== more,\n );\n const visible = (element: Element) => !element.matches(\"[popover]\") && element.getClientRects().length > 0;\n const separator = (element: Element) => element.classList.contains(\"k2b-toolbar__separator\");\n const item = (element: Element) => !separator(element) && !element.classList.contains(\"k2b-toolbar__spacer\");\n // Separators are tidied in DOM order with More, the last control, counted as shown when `withMore` is set.\n const all = Array.from(root.children).filter((element): element is HTMLElement => element instanceof HTMLElement);\n const tidy = (withMore: boolean) => {\n for (const group of root.querySelectorAll(\".k2b-toolbar__group\")) {\n reveal(group);\n if (!Array.from(group.children).some(visible)) hide(group);\n }\n for (const child of children) if (separator(child)) reveal(child);\n const shown = (element: HTMLElement) => (element === more ? withMore : visible(element));\n let preceding = false;\n for (let index = 0; index < all.length; index++) {\n const child = all[index]!;\n if (!shown(child)) continue;\n if (separator(child)) {\n const following = all.slice(index + 1).some((next) => item(next) && shown(next));\n if (!preceding || !following) hide(child);\n else preceding = false;\n } else if (item(child)) preceding = true;\n }\n };\n const style = getComputedStyle(root);\n const edges = [style.paddingLeft, style.paddingRight, style.borderLeftWidth, style.borderRightWidth].reduce(\n (sum, value) => sum + (Number.parseFloat(value) || 0),\n 0,\n );\n const gap = Number.parseFloat(style.columnGap) || 0;\n // A label may shrink in an overfull pill; measure its untruncated width (up to its cap) so actions move before the\n // count or title truncates.\n const width = (child: HTMLElement) => {\n // Separators carry inline margins, which bounding boxes leave out.\n const childStyle = getComputedStyle(child);\n const box =\n child.getBoundingClientRect().width +\n (Number.parseFloat(childStyle.marginLeft) || 0) +\n (Number.parseFloat(childStyle.marginRight) || 0);\n if (!child.classList.contains(\"k2b-toolbar__label\")) return box;\n const cap = Number.parseFloat(childStyle.maxWidth);\n return Math.max(box, Math.min(child.scrollWidth, Number.isNaN(cap) ? Number.POSITIVE_INFINITY : cap));\n };\n const moreWidth = width(more) + gap;\n const used = (withMore: boolean) => {\n const shown = children.filter(visible);\n return shown.reduce((sum, child) => sum + width(child), edges) + gap * Math.max(0, shown.length - 1) + (withMore ? moreWidth : 0);\n };\n // Stable sort retains DOM order for the menu, but removes later actions first on a priority tie.\n const candidates = actions\n // An action its application hides, even with `visibility: hidden`, must not reappear as a More row.\n .filter(\n (action) =>\n action.props.priority !== undefined && visible(action.element) && getComputedStyle(action.element).visibility !== \"hidden\",\n )\n .reverse()\n .sort((a, b) => b.props.priority! - a.props.priority!);\n let movedAny = false;\n tidy(false);\n for (const action of candidates) {\n if (used(movedAny) <= available) break;\n hide(action.element);\n movedAny = true;\n tidy(true);\n }\n // More changes only here, and only when its state changes.\n if (movedAny) reveal(more);\n else if (!more.hasAttribute(overflowAttribute)) hide(more);\n return actions.filter((action) => action.element.hasAttribute(overflowAttribute));\n};\n\nexport const Toolbar = Object.assign(\n (props: ToolbarProps): JSX.Element => {\n // The variant decides the DOM shape, so it is read once.\n const floating = props.variant === \"floating\";\n const orientation = () => (floating ? \"horizontal\" : (props.orientation ?? \"horizontal\"));\n const messages = useToolbarMessages();\n const actions = new Set<RegisteredAction>();\n const [revision, setRevision] = createSignal(0);\n const [moved, setMoved] = createSignal<RegisteredAction[]>([]);\n let root!: HTMLDivElement;\n let strip: HTMLDivElement | undefined;\n let more: HTMLDivElement | undefined;\n let trigger: HTMLButtonElement | undefined;\n let mounted = false;\n let navigation: ReturnType<typeof rovingFocus> | undefined;\n // Only the floating variant moves actions into More; inline toolbars keep every action in place.\n const measure = () => {\n if (!mounted || !strip || !more) return;\n const style = getComputedStyle(strip);\n const available = strip.clientWidth - Number.parseFloat(style.paddingLeft) - Number.parseFloat(style.paddingRight);\n if (available <= 0) return;\n const ordered = [...actions].sort((a, b) =>\n a.element.compareDocumentPosition(b.element) & Node.DOCUMENT_POSITION_FOLLOWING ? -1 : 1,\n );\n const focused = document.activeElement;\n // Cleared before measuring so the pending `visibility: hidden` does not hide every action from the check\n // below; the whole measurement still runs before the next paint.\n root.removeAttribute(\"data-overflow-pending\");\n const next = measureOverflow(root, more, ordered, available);\n setMoved((previous) =>\n previous.length === next.length && previous.every((action, index) => action === next[index]) ? previous : next,\n );\n navigation?.sync();\n // Focus on an action that moved, on a menu row whose action came back, or on a More that disappeared goes to\n // More, or to the toolbar's tab stop when nothing is left in More. Inside an effect the menu rows update after\n // this function returns, so the check waits for that flush; a microtask still runs before the next paint.\n queueMicrotask(() => {\n const lost =\n next.some((action) => action.element === focused) ||\n (focused instanceof HTMLElement && !focused.isConnected) ||\n (focused === trigger && !next.length);\n if (lost) (next.length ? trigger : root.querySelector<HTMLElement>('[tabindex=\"0\"]'))?.focus();\n });\n };\n const register = (action: RegisteredAction) => {\n actions.add(action);\n setRevision((value) => value + 1);\n return () => {\n actions.delete(action);\n setRevision((value) => value + 1);\n };\n };\n if (floating)\n createEffect(() => {\n revision();\n for (const action of actions) {\n // Content and priority changes can affect intrinsic widths as well as menu rows.\n void action.props.priority;\n void action.props.label;\n void action.props.icon;\n void action.props.keys;\n }\n measure();\n });\n onMount(() => {\n mounted = true;\n navigation = rovingFocus(root, orientation);\n onCleanup(() => {\n mounted = false;\n navigation?.cleanup();\n });\n if (!strip) return;\n measure();\n const observer = new ResizeObserver(measure);\n observer.observe(strip);\n observer.observe(root);\n const mutations = new MutationObserver(measure);\n // Visibility an application sets also counts. Measurement writes only data attributes, which stay unobserved.\n mutations.observe(root, {\n childList: true,\n subtree: true,\n characterData: true,\n attributes: true,\n attributeFilter: [\"hidden\", \"class\", \"style\"],\n });\n onCleanup(() => {\n observer.disconnect();\n mutations.disconnect();\n });\n });\n const menuItems = (): DropdownAction[] => moved().map((action) => action.item);\n const content = (\n <ToolbarOrientationContext.Provider value={orientation}>\n <ToolbarActionsContext.Provider value={floating ? register : undefined}>\n <div\n ref={root}\n onKeyDown={(event) => navigation?.keydown(event)}\n class={`k2b-toolbar ${props.class ?? \"\"}`}\n role=\"toolbar\"\n aria-label={props.label}\n aria-orientation={orientation()}\n data-orientation={orientation()}\n data-variant={floating ? \"floating\" : undefined}\n data-wrap={!floating && props.wrap ? \"true\" : undefined}\n data-overflow-pending={floating ? \"\" : undefined}\n >\n {props.children}\n <Show when={floating}>\n <div ref={more} class=\"k2b-toolbar__more\" data-overflow=\"hidden\">\n <Dropdown.Root\n items={menuItems()}\n position=\"top-left\"\n label={messages().moreActions}\n // An open menu closes when its last row returns to the toolbar.\n disabled={moved().length === 0}\n >\n <Dropdown.Trigger ref={trigger} iconOnly label={messages().moreActions}>\n <i class=\"ti ti-dots\" aria-hidden=\"true\" />\n </Dropdown.Trigger>\n </Dropdown.Root>\n </div>\n </Show>\n </div>\n </ToolbarActionsContext.Provider>\n </ToolbarOrientationContext.Provider>\n );\n return floating ? (\n <div ref={strip} class=\"k2b-toolbar-float\">\n {content}\n </div>\n ) : (\n content\n );\n },\n { Action: ToolbarAction, Label: ToolbarLabel, Group: ToolbarGroup, Separator: ToolbarSeparator, Spacer: ToolbarSpacer },\n) as ToolbarComponent;\n\nexport default Toolbar;\n"],"mappings":";;;;;;;;;;;;;AAAA,SAAS,aAAa,EAAE,YAAY,EAAE,YAAY,EAAY,SAAS,EAAE,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,UAAU,QAAQ,UAAU;AAClI,SAAS,QAAQ,QAAQ,cAAc;AACvC,SAAS,GAAG,QAAQ,gBAAgB;AACpC,SAAS,SAAS,QAAQ,gBAAgB;AAC1C,SAAS,cAAc,EAAyB,gBAAgB,QAAQ,kBAAkB;AAC1F,SAAS,UAAU,QAAQ,UAAU;AACrC,SAAS,QAAQ,QAA6B,YAAY;AAC1D,SAAS,kBAAkB,QAAQ,oBAAoB;AAuCvD,MAAM,yBAAmD,GAAG,MAAM,YAAY;AAC9E,MAAM,yBAAyB,GAAG,aAAa,CAAC,yBAAyB,CAAC;;AAE1E;;AAEA,MAAM,qBAAqB,GAAG,aAAa,CAA2C,CAAC;AACvF,MAAM,iBAAiB,GAAG,eAAe;AACzC,MAAM,IAAI,GAAI,OAAgB,IAAK,OAAO,CAAC,YAAY,CAAC,iBAAiB,EAAE,QAAQ,CAAC;AACpF,MAAM,MAAM,GAAI,OAAgB,IAAK,OAAO,CAAC,eAAe,CAAC,iBAAiB,CAAC;;AAE/E;AACA,MAAM,YAAY,GAAG,CAAC,IAAwB,EAAE,QAA0B,KAAyB;EACjG,IAAI,CAAC,IAAI,IAAI,CAAC,cAAc,CAAC,IAAI,EAAE;IAAE,QAAQ;IAAE,MAAM,EAAE;EAAK,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,EAAE,OAAO,SAAS;EAC5F,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC;EACvC,MAAM,IAAI,GAAG,KAAK,KAAK,GAAG,IAAI,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC;EAClD,MAAM,KAAK,GAAG,CAAC,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC;EAC5D;EACA,MAAM,GAAG,GAAG,IAAI,GAAG,MAAM,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,OAAO;EAClD,IAAI,IAAI,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;EACrB,MAAM,KAA6B,GAAG;IACpC,GAAG,EAAE,QAAQ,KAAK,OAAO,GAAG,MAAM,GAAG,SAAS;IAC9C,IAAI,EAAE,SAAS;IACf,GAAG,EAAE,KAAK;IACV,KAAK,EAAE,OAAO;IACd,IAAI,EAAE,MAAM;IACZ,OAAO,EAAE,SAAS;IAClB,SAAS,EAAE,WAAW;IACtB,SAAS,EAAE,WAAW;IACtB,UAAU,EAAE,YAAY;IACxB,MAAM,EAAE,QAAQ;IAChB,GAAG,EAAE,QAAQ;IACb,SAAS,EAAE,WAAW;IACtB,KAAK,EAAE,OAAO;IACd,MAAM,EAAE,QAAQ;IAChB,KAAK,EAAE,OAAO;IACd,GAAG,EAAE,KAAK;IACV,IAAI,EAAE,MAAM;IACZ,GAAG,EAAE,KAAK;IACV,MAAM,EAAE,QAAQ;IAChB,QAAQ,EAAE,UAAU;IACpB,IAAI,EAAE;EACR,CAAC;EACD,MAAM,KAAK,GAAG,GAAG,CAAC,MAAM,KAAK,CAAC,IAAI,qBAAqB,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,WAAW,CAAC,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC;EAClG,OAAO,KAAK,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,GAAG,CAAE,IAAI,IAAK,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,SAAS;AAC5F,CAAC;AAED,MAAM,aAAa,GAAI,KAAyB,IAAkB;EAChE,MAAM,QAAQ,GAAG,UAAU,CAAC,qBAAqB,CAAC;EAClD,MAAM,MAAM,GAAG,SAAS,CAAC,CAAC;EAC1B,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,GAAG,YAAY,CAAmB,QAAQ,IAAI,YAAY,CAAC,OAAO,GAAG,OAAO,GAAG,gBAAgB,CAAC,CAAC,CAAC;EAC/H,OAAO,CAAC,MAAM,WAAW,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC;EAC9C,MAAM,OAAO,GAAG,MAAM;IACpB,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,GAAG,cAAc,CAAC,KAAK,CAAC,IAAI,EAAE;MAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC;MAAE,MAAM,EAAE,MAAM,CAAC;IAAE,CAAC,CAAC,CAAC,KAAK,GAAG,EAAE;IAC/G,OAAO,QAAQ,GAAG,GAAG,KAAK,CAAC,KAAK,KAAK,QAAQ,GAAG,GAAG,KAAK,CAAC,KAAK;EAChE,CAAC;EACD,yBACG,UAAU;IAAA;IAAA,IAkBT,KAAK;MAAA,OAAE,KAAK,CAAC,KAAK;IAAA;IAClB,OAAO;IAAA,IACP,OAAO;MAAA,OAAE,OAAO,CAAC,CAAC;IAAA;IAAA;MAAA,OACC,YAAY,CAAC,KAAK,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC;IAAA;IAAA;MAAA,OACxC,KAAK,CAAC,QAAQ;IAAA;IAAA,IAC7B,QAAQ;MAAA,OAAE,KAAK,CAAC,QAAQ;IAAA;IACxB,OAAO,EAAE,MAAM,KAAK,CAAC,OAAO,GAAG,CAAC;IAAA;MAAA,uDAEtB,KAAK,CAAC,IAAI,oCACnB,IAAI;QAAA,IAAC,IAAI;UAAA,OAAE,KAAK,CAAC,IAAI;QAAA;QAAA,UAAI,IAAI,sBAAM,GAAG;UAAA,IAAC,IAAI;YAAA,OAAE,IAAI,CAAC,CAAC;UAAA;UAAA;QAAA;MAA2C;IAAA;EAAA;AAGrG,CAAC;AAED,MAAM,YAAY,GAAI,KAAwB,mBAC/B,+BAAsB,KAAK,CAAC,KAAK,IAAI,EAAE,SAAE,WAAG,KAAK,CAAC,QAAQ,EACxE;AAED,MAAM,YAAY,GAAI,KAAwB,mBAChC,+BAAsB,KAAK,CAAC,KAAK,IAAI,EAAE,SAAE,wCAA2B,KAAK,CAAC,KAAK,0BACxF,KAAK,CAAC,QAAQ,EAElB;AAED,MAAM,gBAAgB,GAAI,KAA4B,IAAkB;EACtE,MAAM,kBAAkB,GAAG,UAAU,CAAC,yBAAyB,CAAC;EAChE,MAAM,oBAAoB,GAAG,MAAO,kBAAkB,CAAC,CAAC,KAAK,YAAY,GAAG,UAAU,GAAG,YAAa;EAEtG,sBAEW,mCAA0B,KAAK,CAAC,KAAK,IAAI,EAAE,SAAE,8CAElC,oBAAoB,CAAC,CAAC,8DACtB,oBAAoB,CAAC,CAAC;AAG9C,CAAC;AAED,MAAM,aAAa,GAAG,oBAA0E;AAEhG,MAAM,WAAW,GAAG,CAAC,IAAoB,EAAE,WAAqC,KAAK;EACnF,IAAI,IAA6B;EACjC,MAAM,OAAO,GAAI,IAA6B,IAAK;IACjD,IAAI,IAAI,KAAK,IAAI,EAAE;IACnB,IAAI,IAAI,EAAE,cAAc,CAAC,SAAS,CAAC,IAAI,CAAC;IACxC,IAAI,GAAG,IAAI;IACX,IAAI,IAAI,EAAE,cAAc,CAAC,OAAO,CAAC,IAAI,CAAC;EACxC,CAAC;EACD,MAAM,QAAQ,GAAG,MACf,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,gBAAgB,CAAc,sDAAsD,CAAC,CAAC,CAAC,MAAM,CAAE,IAAI,IAAK;IACtH,IACE,IAAI,CAAC,OAAO,CAAC,kBAAkB,CAAC,IAChC,IAAI,CAAC,iBAAiB,IACrB,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,oDAAoD,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,IAAI,MAAM,CAAE,EAE1H,OAAO,KAAK;IACd,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,6DAA6D,CAAC;IAC1F,OAAO,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC;EAC1C,CAAC,CAAC;EACJ,MAAM,KAAK,GAAG,MACZ,QAAQ,CAAC,CAAC,CAAC,MAAM,CACd,IAAI,IAAK,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,0BAA0B,CAAC,IAAI,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,MAAM,GAAG,CACtH,CAAC;EACH,MAAM,IAAI,GAAG,MAAM;IACjB,MAAM,SAAS,GAAG,KAAK,CAAC,CAAC;IACzB,IAAI,CAAC,IAAI,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;IAC7D,KAAK,MAAM,IAAI,IAAI,QAAQ,CAAC,CAAC,EAAE,IAAI,CAAC,QAAQ,GAAG,IAAI,KAAK,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;EACvE,CAAC;EACD,MAAM,OAAO,GAAI,KAAiB,IAAK;IACrC,IAAI,KAAK,CAAC,MAAM,YAAY,WAAW,IAAI,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE;MACzE,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC;MACrB,IAAI,CAAC,CAAC;IACR;EACF,CAAC;EACD,MAAM,OAAO,GAAI,KAAoB,IAAK;IACxC,IAAI,KAAK,CAAC,gBAAgB,IAAI,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC,OAAO,IAAI,KAAK,CAAC,OAAO,IAAI,KAAK,CAAC,QAAQ,EAAE;IAChG,MAAM,SAAS,GAAG,KAAK,CAAC,CAAC;IACzB,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM;IAC3B,IAAI,EAAE,MAAM,YAAY,WAAW,CAAC,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE;IACrE,MAAM,OAAO,GAAG,WAAW,CAAC,CAAC,KAAK,UAAU,GAAG,WAAW,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC,SAAS,KAAK,KAAK,GAAG,WAAW,GAAG,YAAY;IACpI,MAAM,QAAQ,GAAG,WAAW,CAAC,CAAC,KAAK,UAAU,GAAG,SAAS,GAAG,OAAO,KAAK,YAAY,GAAG,WAAW,GAAG,YAAY;IACjH,MAAM,KAAK,GAAG,SAAS,CAAC,OAAO,CAAC,MAAM,CAAC;IACvC,MAAM,IAAI,GACR,KAAK,CAAC,GAAG,KAAK,MAAM,GAChB,CAAC,GACD,KAAK,CAAC,GAAG,KAAK,KAAK,GACjB,SAAS,CAAC,MAAM,GAAG,CAAC,GACpB,KAAK,CAAC,GAAG,KAAK,OAAO,GACnB,CAAC,KAAK,GAAG,CAAC,IAAI,SAAS,CAAC,MAAM,GAC9B,KAAK,CAAC,GAAG,KAAK,QAAQ,GACpB,CAAC,KAAK,GAAG,SAAS,CAAC,MAAM,GAAG,CAAC,IAAI,SAAS,CAAC,MAAM,GACjD,CAAC,CAAC;IACd,IAAI,IAAI,GAAG,CAAC,EAAE;IACd,KAAK,CAAC,cAAc,CAAC,CAAC;IACtB,OAAO,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;IACxB,IAAI,CAAC,CAAC;IACN,IAAI,EAAE,KAAK,CAAC,CAAC;EACf,CAAC;EACD,MAAM,QAAQ,GAAG,IAAI,gBAAgB,CAAC,IAAI,CAAC;EAC3C,QAAQ,CAAC,OAAO,CAAC,IAAI,EAAE;IACrB,SAAS,EAAE,IAAI;IACf,OAAO,EAAE,IAAI;IACb,UAAU,EAAE,IAAI;IAChB,eAAe,EAAE,CAAC,UAAU,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,iBAAiB;EAC7E,CAAC,CAAC;EACF,MAAM,cAAc,GAAG,IAAI,cAAc,CAAC,IAAI,CAAC;EAC/C,cAAc,CAAC,OAAO,CAAC,IAAI,CAAC;EAC5B,IAAI,CAAC,gBAAgB,CAAC,SAAS,EAAE,OAAO,CAAC;EACzC,IAAI,CAAC,CAAC;EACN,OAAO;IACL,OAAO;IACP,IAAI;IACJ,OAAO,EAAE,MAAM;MACb,QAAQ,CAAC,UAAU,CAAC,CAAC;MACrB,cAAc,CAAC,UAAU,CAAC,CAAC;MAC3B,IAAI,CAAC,mBAAmB,CAAC,SAAS,EAAE,OAAO,CAAC;IAC9C;EACF,CAAC;AACH,CAAC;;AAED;AACA;AACA;AACA;AACA;AACA,MAAM,eAAe,GAAG,CACtB,IAAoB,EACpB,IAAoB,EACpB,OAA2B,EAC3B,SAAiB,KACM;EACvB,KAAK,MAAM,OAAO,IAAI,IAAI,CAAC,gBAAgB,CAAC,IAAI,iBAAiB,GAAG,CAAC,EAAE,IAAI,OAAO,KAAK,IAAI,EAAE,MAAM,CAAC,OAAO,CAAC;EAC5G,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,MAAM,CAC9C,OAAO,IAA6B,OAAO,YAAY,WAAW,IAAI,OAAO,KAAK,IACrF,CAAC;EACD,MAAM,OAAO,GAAI,OAAgB,IAAK,CAAC,OAAO,CAAC,OAAO,CAAC,WAAW,CAAC,IAAI,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC;EAC1G,MAAM,SAAS,GAAI,OAAgB,IAAK,OAAO,CAAC,SAAS,CAAC,QAAQ,CAAC,wBAAwB,CAAC;EAC5F,MAAM,IAAI,GAAI,OAAgB,IAAK,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,QAAQ,CAAC,qBAAqB,CAAC;EAC5G;EACA,MAAM,GAAG,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAE,OAAO,IAA6B,OAAO,YAAY,WAAW,CAAC;EACjH,MAAM,IAAI,GAAI,QAAiB,IAAK;IAClC,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,gBAAgB,CAAC,qBAAqB,CAAC,EAAE;MAChE,MAAM,CAAC,KAAK,CAAC;MACb,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC;IAC5D;IACA,KAAK,MAAM,KAAK,IAAI,QAAQ,EAAE,IAAI,SAAS,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC,KAAK,CAAC;IACjE,MAAM,KAAK,GAAI,OAAoB,IAAM,OAAO,KAAK,IAAI,GAAG,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAE;IACxF,IAAI,SAAS,GAAG,KAAK;IACrB,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,GAAG,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE;MAC/C,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAE;MACzB,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE;MACnB,IAAI,SAAS,CAAC,KAAK,CAAC,EAAE;QACpB,MAAM,SAAS,GAAG,GAAG,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,IAAI,CAAE,IAAI,IAAK,IAAI,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,CAAC;QAChF,IAAI,CAAC,SAAS,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,KACrC,SAAS,GAAG,KAAK;MACxB,CAAC,MAAM,IAAI,IAAI,CAAC,KAAK,CAAC,EAAE,SAAS,GAAG,IAAI;IAC1C;EACF,CAAC;EACD,MAAM,KAAK,GAAG,gBAAgB,CAAC,IAAI,CAAC;EACpC,MAAM,KAAK,GAAG,CAAC,KAAK,CAAC,WAAW,EAAE,KAAK,CAAC,YAAY,EAAE,KAAK,CAAC,eAAe,EAAE,KAAK,CAAC,gBAAgB,CAAC,CAAC,MAAM,CACzG,CAAC,GAAG,EAAE,KAAK,KAAK,GAAG,IAAI,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,EACrD,CACF,CAAC;EACD,MAAM,GAAG,GAAG,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC,SAAS,CAAC,IAAI,CAAC;EACnD;EACA;EACA,MAAM,KAAK,GAAI,KAAkB,IAAK;IACpC;IACA,MAAM,UAAU,GAAG,gBAAgB,CAAC,KAAK,CAAC;IAC1C,MAAM,GAAG,GACP,KAAK,CAAC,qBAAqB,CAAC,CAAC,CAAC,KAAK,IAClC,MAAM,CAAC,UAAU,CAAC,UAAU,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,IAC9C,MAAM,CAAC,UAAU,CAAC,UAAU,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;IAClD,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,QAAQ,CAAC,oBAAoB,CAAC,EAAE,OAAO,GAAG;IAC/D,MAAM,GAAG,GAAG,MAAM,CAAC,UAAU,CAAC,UAAU,CAAC,QAAQ,CAAC;IAClD,OAAO,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,WAAW,EAAE,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,iBAAiB,GAAG,GAAG,CAAC,CAAC;EACvG,CAAC;EACD,MAAM,SAAS,GAAG,KAAK,CAAC,IAAI,CAAC,GAAG,GAAG;EACnC,MAAM,IAAI,GAAI,QAAiB,IAAK;IAClC,MAAM,KAAK,GAAG,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC;IACtC,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,KAAK,KAAK,GAAG,GAAG,KAAK,CAAC,KAAK,CAAC,EAAE,KAAK,CAAC,GAAG,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,IAAI,QAAQ,GAAG,SAAS,GAAG,CAAC,CAAC;EACnI,CAAC;EACD;EACA,MAAM,UAAU,GAAG;EACjB;EAAA,CACC,MAAM,CACJ,MAAM,IACL,MAAM,CAAC,KAAK,CAAC,QAAQ,KAAK,SAAS,IAAI,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,gBAAgB,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,UAAU,KAAK,QACtH,CAAC,CACA,OAAO,CAAC,CAAC,CACT,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,QAAQ,GAAI,CAAC,CAAC,KAAK,CAAC,QAAS,CAAC;EACxD,IAAI,QAAQ,GAAG,KAAK;EACpB,IAAI,CAAC,KAAK,CAAC;EACX,KAAK,MAAM,MAAM,IAAI,UAAU,EAAE;IAC/B,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,SAAS,EAAE;IACjC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC;IACpB,QAAQ,GAAG,IAAI;IACf,IAAI,CAAC,IAAI,CAAC;EACZ;EACA;EACA,IAAI,QAAQ,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,KACtB,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,iBAAiB,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC;EAC1D,OAAO,OAAO,CAAC,MAAM,CAAE,MAAM,IAAK,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC,iBAAiB,CAAC,CAAC;AACnF,CAAC;AAED,OAAO,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,CACjC,KAAmB,IAAkB;EACpC;EACA,MAAM,QAAQ,GAAG,KAAK,CAAC,OAAO,KAAK,UAAU;EAC7C,MAAM,WAAW,GAAG,MAAO,QAAQ,GAAG,YAAY,GAAI,KAAK,CAAC,WAAW,IAAI,YAAc;EACzF,MAAM,QAAQ,GAAG,kBAAkB,CAAC,CAAC;EACrC,MAAM,OAAO,GAAG,IAAI,GAAG,CAAmB,CAAC;EAC3C,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,GAAG,YAAY,CAAC,CAAC,CAAC;EAC/C,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,YAAY,CAAqB,EAAE,CAAC;EAC9D,IAAI,IAAqB;EACzB,IAAI,KAAiC;EACrC,IAAI,IAAgC;EACpC,IAAI,OAAsC;EAC1C,IAAI,OAAO,GAAG,KAAK;EACnB,IAAI,UAAsD;EAC1D;EACA,MAAM,OAAO,GAAG,MAAM;IACpB,IAAI,CAAC,OAAO,IAAI,CAAC,KAAK,IAAI,CAAC,IAAI,EAAE;IACjC,MAAM,KAAK,GAAG,gBAAgB,CAAC,KAAK,CAAC;IACrC,MAAM,SAAS,GAAG,KAAK,CAAC,WAAW,GAAG,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC,WAAW,CAAC,GAAG,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC,YAAY,CAAC;IAClH,IAAI,SAAS,IAAI,CAAC,EAAE;IACpB,MAAM,OAAO,GAAG,CAAC,GAAG,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,KACrC,CAAC,CAAC,OAAO,CAAC,uBAAuB,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC,2BAA2B,GAAG,CAAC,CAAC,GAAG,CACzF,CAAC;IACD,MAAM,OAAO,GAAG,QAAQ,CAAC,aAAa;IACtC;IACA;IACA,IAAI,CAAC,eAAe,CAAC,uBAAuB,CAAC;IAC7C,MAAM,IAAI,GAAG,eAAe,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,SAAS,CAAC;IAC5D,QAAQ,CAAE,QAAQ,IAChB,QAAQ,CAAC,MAAM,KAAK,IAAI,CAAC,MAAM,IAAI,QAAQ,CAAC,KAAK,CAAC,CAAC,MAAM,EAAE,KAAK,KAAK,MAAM,KAAK,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,QAAQ,GAAG,IAC5G,CAAC;IACD,UAAU,EAAE,IAAI,CAAC,CAAC;IAClB;IACA;IACA;IACA,cAAc,CAAC,MAAM;MACnB,MAAM,IAAI,GACR,IAAI,CAAC,IAAI,CAAE,MAAM,IAAK,MAAM,CAAC,OAAO,KAAK,OAAO,CAAC,IAChD,OAAO,YAAY,WAAW,IAAI,CAAC,OAAO,CAAC,WAAY,IACvD,OAAO,KAAK,OAAO,IAAI,CAAC,IAAI,CAAC,MAAO;MACvC,IAAI,IAAI,EAAE,CAAC,IAAI,CAAC,MAAM,GAAG,OAAO,GAAG,IAAI,CAAC,aAAa,CAAc,gBAAgB,CAAC,GAAG,KAAK,CAAC,CAAC;IAChG,CAAC,CAAC;EACJ,CAAC;EACD,MAAM,QAAQ,GAAI,MAAwB,IAAK;IAC7C,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC;IACnB,WAAW,CAAE,KAAK,IAAK,KAAK,GAAG,CAAC,CAAC;IACjC,OAAO,MAAM;MACX,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC;MACtB,WAAW,CAAE,KAAK,IAAK,KAAK,GAAG,CAAC,CAAC;IACnC,CAAC;EACH,CAAC;EACD,IAAI,QAAQ,EACV,YAAY,CAAC,MAAM;IACjB,QAAQ,CAAC,CAAC;IACV,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE;MAC5B;MACA,KAAK,MAAM,CAAC,KAAK,CAAC,QAAQ;MAC1B,KAAK,MAAM,CAAC,KAAK,CAAC,KAAK;MACvB,KAAK,MAAM,CAAC,KAAK,CAAC,IAAI;MACtB,KAAK,MAAM,CAAC,KAAK,CAAC,IAAI;IACxB;IACA,OAAO,CAAC,CAAC;EACX,CAAC,CAAC;EACJ,OAAO,CAAC,MAAM;IACZ,OAAO,GAAG,IAAI;IACd,UAAU,GAAG,WAAW,CAAC,IAAI,EAAE,WAAW,CAAC;IAC3C,SAAS,CAAC,MAAM;MACd,OAAO,GAAG,KAAK;MACf,UAAU,EAAE,OAAO,CAAC,CAAC;IACvB,CAAC,CAAC;IACF,IAAI,CAAC,KAAK,EAAE;IACZ,OAAO,CAAC,CAAC;IACT,MAAM,QAAQ,GAAG,IAAI,cAAc,CAAC,OAAO,CAAC;IAC5C,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC;IACvB,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC;IACtB,MAAM,SAAS,GAAG,IAAI,gBAAgB,CAAC,OAAO,CAAC;IAC/C;IACA,SAAS,CAAC,OAAO,CAAC,IAAI,EAAE;MACtB,SAAS,EAAE,IAAI;MACf,OAAO,EAAE,IAAI;MACb,aAAa,EAAE,IAAI;MACnB,UAAU,EAAE,IAAI;MAChB,eAAe,EAAE,CAAC,QAAQ,EAAE,OAAO,EAAE,OAAO;IAC9C,CAAC,CAAC;IACF,SAAS,CAAC,MAAM;MACd,QAAQ,CAAC,UAAU,CAAC,CAAC;MACrB,SAAS,CAAC,UAAU,CAAC,CAAC;IACxB,CAAC,CAAC;EACJ,CAAC,CAAC;EACF,MAAM,SAAS,GAAG,MAAwB,KAAK,CAAC,CAAC,CAAC,GAAG,CAAE,MAAM,IAAK,MAAM,CAAC,IAAI,CAAC;EAC9E,MAAM,OAAO,qBACV,yBAAyB,CAAC,QAAQ;IAAC,KAAK,EAAE,WAAW;IAAA;MAAA,yBACnD,qBAAqB,CAAC,QAAQ;QAAC,KAAK,EAAE,QAAQ,GAAG,QAAQ,GAAG,SAAS;QAAA;UAAA,sBAI3D,wBAAe,KAAK,CAAC,KAAK,IAAI,EAAE,SAAE,wCAE7B,KAAK,CAAC,KAAK,8DACL,WAAW,CAAC,CAAC,8DACb,WAAW,CAAC,CAAC,iDACjB,QAAQ,GAAG,UAAU,YAAG,SAAS,8CACpC,CAAC,QAAQ,IAAI,KAAK,CAAC,IAAI,GAAG,MAAM,YAAG,SAAS,0DAChC,QAAQ,GAAG,EAAE,YAAG,SAAS,0BAE/C,KAAK,CAAC,QAAQ,8BACd,IAAI;YAAC,IAAI,EAAE,QAAQ;YAAA;cAAA,iDAEf,QAAQ,CAAC,IAAI;gBAAA,IACZ,KAAK;kBAAA,OAAE,SAAS,CAAC,CAAC;gBAAA;gBAClB,QAAQ;gBAAA,IACR,KAAK;kBAAA,OAAE,QAAQ,CAAC,CAAC,CAAC,WAAW;gBAAA;gBAAA,IAE7B,QAAQ;kBAAA,OAAE,KAAK,CAAC,CAAC,CAAC,MAAM,KAAK,CAAC;gBAAA;gBAAA;kBAAA,yBAE7B,QAAQ,CAAC,OAAO;oBAAe,QAAQ;oBAAA,IAAC,KAAK;sBAAA,OAAE,QAAQ,CAAC,CAAC,CAAC,WAAW;oBAAA;oBAAA;sBAAA;oBAAA;kBAAA;gBAAA;cAAA;YAAA;UAAA;QAAA;MAAA;IAAA;EAAA,EASnF;EACD,OAAO,QAAQ,2BAEV,OAAO,KAGV,OACD;AACH,CAAC,EACD;EAAE,MAAM,EAAE,aAAa;EAAE,KAAK,EAAE,YAAY;EAAE,KAAK,EAAE,YAAY;EAAE,SAAS,EAAE,gBAAgB;EAAE,MAAM,EAAE;AAAc,CACxH,CAAqB;AAErB,eAAe,OAAO","ignoreList":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":[],"sources":["actions/index.ts"],"sourcesContent":["export type { ButtonAlign, ButtonLinkProps, ButtonProps, ButtonSize, ButtonVariant, IconButtonLinkProps, IconButtonProps } from \"./Button\";\nexport { Button, ButtonLink, IconButton, IconButtonLink } from \"./Button\";\nexport type { ContextMenuProps } from \"./ContextMenu\";\nexport { ContextMenu } from \"./ContextMenu\";\nexport type { CopyButtonProps, CopyButtonValue } from \"./CopyButton\";\nexport { CopyButton } from \"./CopyButton\";\nexport type { DisclosureProps } from \"./Disclosure\";\nexport { Disclosure } from \"./Disclosure\";\nexport type {\n DropdownAction,\n DropdownActionBase,\n DropdownChoice,\n DropdownItemProps,\n DropdownPosition,\n DropdownProps,\n DropdownSection,\n DropdownTriggerProps,\n} from \"./Dropdown\";\nexport { Dropdown, DropdownItem, dropdownPosition } from \"./Dropdown\";\nexport type { FilterChipOption, FilterChipProps, FilterChipSection } from \"./FilterChip\";\nexport { FilterChip } from \"./FilterChip\";\nexport type { GestureKind, GestureMenuAction, GestureMenuItem, GestureMenuProps, GestureMenuSection } from \"./GestureMenu\";\nexport { GestureMenu } from \"./GestureMenu\";\nexport type { RemoveButtonProps } from \"./RemoveButton\";\nexport { RemoveButton } from \"./RemoveButton\";\nexport type { SegmentedControlProps, SegmentOption } from \"./SegmentedControl\";\nexport { SegmentedControl } from \"./SegmentedControl\";\nexport type { SplitButtonProps } from \"./SplitButton\";\nexport { SplitButton } from \"./SplitButton\";\nexport type {\n SpotlightButtonProps,\n SpotlightButtonVariant,\n SpotlightSearchOptions,\n SpotlightSearchResolver,\n} from \"./SpotlightSearch\";\nexport {\n openSpotlightSearch,\n SpotlightButton,\n} from \"./SpotlightSearch\";\nexport type { TabOption, TabsItemProps, TabsProps } from \"./Tabs\";\nexport { Tabs } from \"./Tabs\";\nexport type { ToolbarGroupProps, ToolbarProps, ToolbarSeparatorProps } from \"./Toolbar\";\nexport { Toolbar } from \"./Toolbar\";\n"],"mappings":"AACA,SAAS,MAAM,EAAE,UAAU,EAAE,UAAU,EAAE,cAAc,QAAQ,UAAU;AAEzE,SAAS,WAAW,QAAQ,eAAe;AAE3C,SAAS,UAAU,QAAQ,cAAc;AAEzC,SAAS,UAAU,QAAQ,cAAc;AAWzC,SAAS,QAAQ,EAAE,YAAY,EAAE,gBAAgB,QAAQ,YAAY;AAErE,SAAS,UAAU,QAAQ,cAAc;AAEzC,SAAS,WAAW,QAAQ,eAAe;AAE3C,SAAS,YAAY,QAAQ,gBAAgB;AAE7C,SAAS,gBAAgB,QAAQ,oBAAoB;AAErD,SAAS,WAAW,QAAQ,eAAe;AAO3C,SACE,mBAAmB,EACnB,eAAe,QACV,mBAAmB;AAE1B,SAAS,IAAI,QAAQ,QAAQ;AAE7B,SAAS,OAAO,QAAQ,WAAW","ignoreList":[]}
|
|
1
|
+
{"version":3,"names":[],"sources":["actions/index.ts"],"sourcesContent":["export type { ButtonAlign, ButtonLinkProps, ButtonProps, ButtonSize, ButtonVariant, IconButtonLinkProps, IconButtonProps } from \"./Button\";\nexport { Button, ButtonLink, IconButton, IconButtonLink } from \"./Button\";\nexport type { ContextMenuProps } from \"./ContextMenu\";\nexport { ContextMenu } from \"./ContextMenu\";\nexport type { CopyButtonProps, CopyButtonValue } from \"./CopyButton\";\nexport { CopyButton } from \"./CopyButton\";\nexport type { DisclosureProps } from \"./Disclosure\";\nexport { Disclosure } from \"./Disclosure\";\nexport type {\n DropdownAction,\n DropdownActionBase,\n DropdownChoice,\n DropdownItemProps,\n DropdownPosition,\n DropdownProps,\n DropdownSection,\n DropdownTriggerProps,\n} from \"./Dropdown\";\nexport { Dropdown, DropdownItem, dropdownPosition } from \"./Dropdown\";\nexport type { FilterChipOption, FilterChipProps, FilterChipSection } from \"./FilterChip\";\nexport { FilterChip } from \"./FilterChip\";\nexport type { GestureKind, GestureMenuAction, GestureMenuItem, GestureMenuProps, GestureMenuSection } from \"./GestureMenu\";\nexport { GestureMenu } from \"./GestureMenu\";\nexport type { RemoveButtonProps } from \"./RemoveButton\";\nexport { RemoveButton } from \"./RemoveButton\";\nexport type { SegmentedControlProps, SegmentOption } from \"./SegmentedControl\";\nexport { SegmentedControl } from \"./SegmentedControl\";\nexport type { SplitButtonProps } from \"./SplitButton\";\nexport { SplitButton } from \"./SplitButton\";\nexport type {\n SpotlightButtonProps,\n SpotlightButtonVariant,\n SpotlightSearchOptions,\n SpotlightSearchResolver,\n} from \"./SpotlightSearch\";\nexport {\n openSpotlightSearch,\n SpotlightButton,\n} from \"./SpotlightSearch\";\nexport type { TabOption, TabsItemProps, TabsProps } from \"./Tabs\";\nexport { Tabs } from \"./Tabs\";\nexport type { ToolbarActionProps, ToolbarGroupProps, ToolbarLabelProps, ToolbarProps, ToolbarSeparatorProps } from \"./Toolbar\";\nexport { Toolbar } from \"./Toolbar\";\n"],"mappings":"AACA,SAAS,MAAM,EAAE,UAAU,EAAE,UAAU,EAAE,cAAc,QAAQ,UAAU;AAEzE,SAAS,WAAW,QAAQ,eAAe;AAE3C,SAAS,UAAU,QAAQ,cAAc;AAEzC,SAAS,UAAU,QAAQ,cAAc;AAWzC,SAAS,QAAQ,EAAE,YAAY,EAAE,gBAAgB,QAAQ,YAAY;AAErE,SAAS,UAAU,QAAQ,cAAc;AAEzC,SAAS,WAAW,QAAQ,eAAe;AAE3C,SAAS,YAAY,QAAQ,gBAAgB;AAE7C,SAAS,gBAAgB,QAAQ,oBAAoB;AAErD,SAAS,WAAW,QAAQ,eAAe;AAO3C,SACE,mBAAmB,EACnB,eAAe,QACV,mBAAmB;AAE1B,SAAS,IAAI,QAAQ,QAAQ;AAE7B,SAAS,OAAO,QAAQ,WAAW","ignoreList":[]}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Left and Right cycle through the segments of a row section; Up and Down leave it like any item. Returns whether
|
|
3
|
+
* the key moved focus.
|
|
4
|
+
*/
|
|
5
|
+
export const focusRowSegment = (items, key) => {
|
|
6
|
+
if (key !== "ArrowLeft" && key !== "ArrowRight") return false;
|
|
7
|
+
const active = document.activeElement;
|
|
8
|
+
const row = active?.closest(".k2b-dropdown__row");
|
|
9
|
+
if (!active || !row) return false;
|
|
10
|
+
const segments = items.filter(item => row.contains(item));
|
|
11
|
+
const next = segments.indexOf(active) + (key === "ArrowRight" ? 1 : -1);
|
|
12
|
+
segments[(next + segments.length) % segments.length]?.focus();
|
|
13
|
+
return true;
|
|
14
|
+
};
|
|
15
|
+
//# sourceMappingURL=menu-rows.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":[],"sources":["actions/menu-rows.ts"],"sourcesContent":["/**\n * Left and Right cycle through the segments of a row section; Up and Down leave it like any item. Returns whether\n * the key moved focus.\n */\nexport const focusRowSegment = (items: HTMLElement[], key: string): boolean => {\n if (key !== \"ArrowLeft\" && key !== \"ArrowRight\") return false;\n const active = document.activeElement as HTMLElement | null;\n const row = active?.closest(\".k2b-dropdown__row\");\n if (!active || !row) return false;\n const segments = items.filter((item) => row.contains(item));\n const next = segments.indexOf(active) + (key === \"ArrowRight\" ? 1 : -1);\n segments[(next + segments.length) % segments.length]?.focus();\n return true;\n};\n"],"mappings":"AAAA;AACA;AACA;AACA;AACA,OAAO,MAAM,eAAe,GAAG,CAAC,KAAoB,EAAE,GAAW,KAAc;EAC7E,IAAI,GAAG,KAAK,WAAW,IAAI,GAAG,KAAK,YAAY,EAAE,OAAO,KAAK;EAC7D,MAAM,MAAM,GAAG,QAAQ,CAAC,aAAmC;EAC3D,MAAM,GAAG,GAAG,MAAM,EAAE,OAAO,CAAC,oBAAoB,CAAC;EACjD,IAAI,CAAC,MAAM,IAAI,CAAC,GAAG,EAAE,OAAO,KAAK;EACjC,MAAM,QAAQ,GAAG,KAAK,CAAC,MAAM,CAAE,IAAI,IAAK,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;EAC3D,MAAM,IAAI,GAAG,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,GAAG,KAAK,YAAY,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;EACvE,QAAQ,CAAC,CAAC,IAAI,GAAG,QAAQ,CAAC,MAAM,IAAI,QAAQ,CAAC,MAAM,CAAC,EAAE,KAAK,CAAC,CAAC;EAC7D,OAAO,IAAI;AACb,CAAC","ignoreList":[]}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { ssr as _$ssr } from "solid-js/web";
|
|
2
|
+
import { createComponent as _$createComponent } from "solid-js/web";
|
|
3
|
+
import { ssrAttribute as _$ssrAttribute } from "solid-js/web";
|
|
4
|
+
import { escape as _$escape } from "solid-js/web";
|
|
5
|
+
var _tmpl$ = ["<div class=\"k2b-gesture-menu__sheet-menu\" role=\"menu\"", ">", "</div>"];
|
|
6
|
+
import { onCleanup, onMount } from "solid-js";
|
|
7
|
+
import { dialogCore } from "../feedback/dialog-core";
|
|
8
|
+
import { LocaleProvider } from "../intl/locale";
|
|
9
|
+
import BottomSheet, { bottomSheetOptions } from "../layout/BottomSheet";
|
|
10
|
+
import { focusRowSegment } from "./menu-rows";
|
|
11
|
+
|
|
12
|
+
/** Phones, where a menu opens as a bottom sheet instead of beside its trigger. */
|
|
13
|
+
export const PHONE_SHEET_QUERY = "(max-width: 47.999rem)";
|
|
14
|
+
export const prefersMenuSheet = () => typeof matchMedia === "function" && matchMedia(PHONE_SHEET_QUERY).matches;
|
|
15
|
+
/**
|
|
16
|
+
* Follows a link the way a click on it would, so a page's own link handling, such as progressive navigation, still
|
|
17
|
+
* applies; it runs only after the sheet has left the history.
|
|
18
|
+
*/
|
|
19
|
+
const followLink = href => {
|
|
20
|
+
const link = document.createElement("a");
|
|
21
|
+
link.href = href;
|
|
22
|
+
link.hidden = true;
|
|
23
|
+
document.body.append(link);
|
|
24
|
+
link.click();
|
|
25
|
+
link.remove();
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* The sheet's items hand their action to `run` instead of running it while the sheet closes: `dialogCore` settles the
|
|
30
|
+
* sheet after it left the history, and only then may an action navigate or open the next dialog.
|
|
31
|
+
* A choice or action that keeps the menu open, or an `immediate` action, runs at once.
|
|
32
|
+
*/
|
|
33
|
+
const afterClose = (items, run) => {
|
|
34
|
+
const entry = item => {
|
|
35
|
+
// A plain link would navigate while the sheet's history entry is still being removed, and that Back could
|
|
36
|
+
// undo the navigation; a plain click instead follows it once the sheet is gone. Modified clicks and external
|
|
37
|
+
// links keep the browser's own behavior.
|
|
38
|
+
if (!item.action && "href" in item && item.href && !("external" in item && item.external)) {
|
|
39
|
+
const href = item.href;
|
|
40
|
+
return {
|
|
41
|
+
...item,
|
|
42
|
+
action: () => run(() => followLink(href))
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
const action = item.action;
|
|
46
|
+
if (!action || "closeOnSelect" in item && item.closeOnSelect === false || "immediate" in item && item.immediate) return item;
|
|
47
|
+
return {
|
|
48
|
+
...item,
|
|
49
|
+
action: () => run(action)
|
|
50
|
+
};
|
|
51
|
+
};
|
|
52
|
+
return items.map(item => {
|
|
53
|
+
const sheetItem = item;
|
|
54
|
+
return "items" in sheetItem ? {
|
|
55
|
+
...sheetItem,
|
|
56
|
+
items: sheetItem.items.map(entry)
|
|
57
|
+
} : entry(sheetItem);
|
|
58
|
+
});
|
|
59
|
+
};
|
|
60
|
+
const menuItems = menu => Array.from(menu.querySelectorAll("[role^='menuitem']:not([aria-disabled='true'])"));
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* The menu inside the sheet: the same items, at touch size, with arrow keys for a connected keyboard. Focus starts on
|
|
64
|
+
* the sheet itself, which shows no ring on a phone; the first arrow key moves it into the menu.
|
|
65
|
+
*/
|
|
66
|
+
function SheetMenu(props) {
|
|
67
|
+
let menu;
|
|
68
|
+
const focus = index => {
|
|
69
|
+
const items = menuItems(menu);
|
|
70
|
+
items[(index + items.length) % items.length]?.focus();
|
|
71
|
+
};
|
|
72
|
+
const onKeyDown = event => {
|
|
73
|
+
const items = menuItems(menu);
|
|
74
|
+
const current = items.indexOf(document.activeElement);
|
|
75
|
+
if (event.key === "ArrowDown") focus(current + 1);else if (event.key === "ArrowUp") focus(current < 0 ? -1 : current - 1);else if (event.key === "Home" || event.key === "End") focus(event.key === "Home" ? 0 : -1);else if (!focusRowSegment(items, event.key)) return;
|
|
76
|
+
event.preventDefault();
|
|
77
|
+
};
|
|
78
|
+
// Keys pressed on the sheet itself, while it is the top level of the shared dialog.
|
|
79
|
+
const onSheetKeyDown = event => {
|
|
80
|
+
if (event.target === props.dialog && props.dialog.lastElementChild?.contains(menu)) onKeyDown(event);
|
|
81
|
+
};
|
|
82
|
+
onMount(() => {
|
|
83
|
+
props.dialog.addEventListener("keydown", onSheetKeyDown);
|
|
84
|
+
onCleanup(() => props.dialog.removeEventListener("keydown", onSheetKeyDown));
|
|
85
|
+
});
|
|
86
|
+
return _$ssr(_tmpl$, _$ssrAttribute("aria-label", _$escape(props.label, true), false), _$escape(_$createComponent(props.Items, {
|
|
87
|
+
get items() {
|
|
88
|
+
return props.items;
|
|
89
|
+
},
|
|
90
|
+
close: () => props.close()
|
|
91
|
+
})));
|
|
92
|
+
}
|
|
93
|
+
/** Opens menu items as a bottom sheet; resolves after the sheet closed and the chosen action ran. */
|
|
94
|
+
export const openMenuSheet = options => {
|
|
95
|
+
let chosen;
|
|
96
|
+
const choose = action => {
|
|
97
|
+
chosen = action;
|
|
98
|
+
};
|
|
99
|
+
return dialogCore.open((close, context) => _$createComponent(LocaleProvider, {
|
|
100
|
+
get locale() {
|
|
101
|
+
return options.locale;
|
|
102
|
+
},
|
|
103
|
+
get children() {
|
|
104
|
+
return _$createComponent(BottomSheet, {
|
|
105
|
+
get onDismiss() {
|
|
106
|
+
return context.requestDismiss;
|
|
107
|
+
},
|
|
108
|
+
get children() {
|
|
109
|
+
return _$createComponent(BottomSheet.Body, {
|
|
110
|
+
get children() {
|
|
111
|
+
return [options.top?.(() => close()), _$createComponent(SheetMenu, {
|
|
112
|
+
get Items() {
|
|
113
|
+
return options.Items;
|
|
114
|
+
},
|
|
115
|
+
get items() {
|
|
116
|
+
return afterClose(options.items, choose);
|
|
117
|
+
},
|
|
118
|
+
get label() {
|
|
119
|
+
return options.label;
|
|
120
|
+
},
|
|
121
|
+
close: () => close(),
|
|
122
|
+
get dialog() {
|
|
123
|
+
return context.dialog;
|
|
124
|
+
}
|
|
125
|
+
})];
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
}), {
|
|
132
|
+
...bottomSheetOptions,
|
|
133
|
+
ariaLabel: options.label,
|
|
134
|
+
history: true,
|
|
135
|
+
signal: options.signal
|
|
136
|
+
}).then(() => chosen?.());
|
|
137
|
+
};
|
|
138
|
+
//# sourceMappingURL=menu-sheet.js.map
|