@k2b/ui 0.32.0 → 0.34.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/base.css +14 -1
- package/dist/browser/actions/ContextMenu.js +13 -0
- package/dist/browser/actions/ContextMenu.js.map +1 -1
- package/dist/browser/actions/Dropdown.js +173 -102
- package/dist/browser/actions/Dropdown.js.map +1 -1
- package/dist/browser/actions/FilterChip.js +113 -56
- package/dist/browser/actions/FilterChip.js.map +1 -1
- package/dist/browser/actions/SelectionToolbar.js +129 -0
- package/dist/browser/actions/SelectionToolbar.js.map +1 -0
- package/dist/browser/actions/filter-messages.js +26 -2
- package/dist/browser/actions/filter-messages.js.map +1 -1
- package/dist/browser/actions/index.js +1 -0
- package/dist/browser/actions/index.js.map +1 -1
- package/dist/browser/actions/menu-rows.js +23 -3
- package/dist/browser/actions/menu-rows.js.map +1 -1
- package/dist/browser/actions/menu-sheet.js +2 -7
- package/dist/browser/actions/menu-sheet.js.map +1 -1
- package/dist/browser/charts.js +6 -0
- package/dist/browser/charts.js.map +1 -0
- package/dist/browser/chat/ChatComposer.js +616 -421
- package/dist/browser/chat/ChatComposer.js.map +1 -1
- package/dist/browser/chat/chat-messages.js +18 -0
- package/dist/browser/chat/chat-messages.js.map +1 -1
- package/dist/browser/chat/composer-document.js +19 -0
- package/dist/browser/chat/composer-document.js.map +1 -1
- package/dist/browser/chat/index.js.map +1 -1
- package/dist/browser/content/Calendar.js +39 -29
- package/dist/browser/content/Calendar.js.map +1 -1
- package/dist/browser/content/CalendarDayView.js +159 -165
- package/dist/browser/content/CalendarDayView.js.map +1 -1
- package/dist/browser/content/Chart.js +8 -0
- package/dist/browser/content/Chart.js.map +1 -1
- package/dist/browser/content/FileGrid.js +231 -9
- package/dist/browser/content/FileGrid.js.map +1 -1
- package/dist/browser/content/FileTypeIcon.js +15 -0
- package/dist/browser/content/FileTypeIcon.js.map +1 -1
- package/dist/browser/content/FileView.js +11 -4
- package/dist/browser/content/FileView.js.map +1 -1
- package/dist/browser/content/MessageRow.js +627 -343
- package/dist/browser/content/MessageRow.js.map +1 -1
- package/dist/browser/content/ReactionBar.js +20 -1
- package/dist/browser/content/ReactionBar.js.map +1 -1
- package/dist/browser/content/calendar-day-scroll.js +4 -3
- package/dist/browser/content/calendar-day-scroll.js.map +1 -1
- package/dist/browser/content/chart-bar.js +476 -0
- package/dist/browser/content/chart-bar.js.map +1 -0
- package/dist/browser/content/file-list-messages.js +52 -0
- package/dist/browser/content/file-list-messages.js.map +1 -0
- package/dist/browser/content/index.js +2 -2
- package/dist/browser/content/index.js.map +1 -1
- package/dist/browser/feedback/Tooltip.js +31 -14
- package/dist/browser/feedback/Tooltip.js.map +1 -1
- package/dist/browser/feedback/dialog-core.js +6 -0
- package/dist/browser/feedback/dialog-core.js.map +1 -1
- package/dist/browser/inputs/ChoiceList.js +178 -0
- package/dist/browser/inputs/ChoiceList.js.map +1 -0
- package/dist/browser/inputs/ChoiceSlider.js +314 -0
- package/dist/browser/inputs/ChoiceSlider.js.map +1 -0
- package/dist/browser/inputs/ChoiceTiles.js +135 -0
- package/dist/browser/inputs/ChoiceTiles.js.map +1 -0
- package/dist/browser/inputs/ColorChoices.js +120 -0
- package/dist/browser/inputs/ColorChoices.js.map +1 -0
- package/dist/browser/inputs/QrScanner.js +95 -13
- package/dist/browser/inputs/QrScanner.js.map +1 -1
- package/dist/browser/inputs/TextInput.js +19 -14
- package/dist/browser/inputs/TextInput.js.map +1 -1
- package/dist/browser/inputs/index.js +4 -0
- package/dist/browser/inputs/index.js.map +1 -1
- package/dist/browser/inputs/qr-messages.js +2 -0
- package/dist/browser/inputs/qr-messages.js.map +1 -1
- package/dist/browser/internal/radio-keys.js +13 -0
- package/dist/browser/internal/radio-keys.js.map +1 -0
- package/dist/browser/intl/shortcut-messages.js +4 -0
- package/dist/browser/intl/shortcut-messages.js.map +1 -1
- package/dist/browser/intl/shortcut.js +4 -0
- package/dist/browser/intl/shortcut.js.map +1 -1
- package/dist/browser/layout/AnchoredPopover.js +180 -0
- package/dist/browser/layout/AnchoredPopover.js.map +1 -0
- package/dist/browser/layout/AppWorkspace.js +684 -532
- package/dist/browser/layout/AppWorkspace.js.map +1 -1
- package/dist/browser/layout/DetailPanel.js +443 -333
- package/dist/browser/layout/DetailPanel.js.map +1 -1
- package/dist/browser/layout/MobileShell.js +231 -42
- package/dist/browser/layout/MobileShell.js.map +1 -1
- package/dist/browser/layout/Settings.js +283 -175
- package/dist/browser/layout/Settings.js.map +1 -1
- package/dist/browser/layout/SidebarRailHint.js +79 -0
- package/dist/browser/layout/SidebarRailHint.js.map +1 -0
- package/dist/browser/layout/SidebarSwitcher.js +79 -66
- package/dist/browser/layout/SidebarSwitcher.js.map +1 -1
- package/dist/browser/layout/TabBar.js +18 -4
- package/dist/browser/layout/TabBar.js.map +1 -1
- package/dist/browser/layout/app-workspace-controller.js +11 -4
- package/dist/browser/layout/app-workspace-controller.js.map +1 -1
- package/dist/browser/layout/detail-panel-messages.js +4 -2
- package/dist/browser/layout/detail-panel-messages.js.map +1 -1
- package/dist/browser/layout/index.js +3 -1
- package/dist/browser/layout/index.js.map +1 -1
- package/dist/browser/layout/scroll-fade.js +32 -5
- package/dist/browser/layout/scroll-fade.js.map +1 -1
- package/dist/browser/layout/settings-messages.js +26 -2
- package/dist/browser/layout/settings-messages.js.map +1 -1
- package/dist/browser/surfaces/Avatar.js +2 -14
- package/dist/browser/surfaces/Avatar.js.map +1 -1
- package/dist/browser/surfaces/DotStrip.js +70 -0
- package/dist/browser/surfaces/DotStrip.js.map +1 -0
- package/dist/browser/surfaces/NoticeCard.js +46 -30
- package/dist/browser/surfaces/NoticeCard.js.map +1 -1
- package/dist/browser/surfaces/ProgressRing.js +3 -0
- package/dist/browser/surfaces/ProgressRing.js.map +1 -1
- package/dist/browser/surfaces/ResourceCard.js +125 -68
- package/dist/browser/surfaces/ResourceCard.js.map +1 -1
- package/dist/browser/surfaces/index.js +2 -0
- package/dist/browser/surfaces/index.js.map +1 -1
- package/dist/browser/surfaces/person-color.js +18 -0
- package/dist/browser/surfaces/person-color.js.map +1 -0
- package/dist/browser/surfaces/resource-messages.js +8 -4
- package/dist/browser/surfaces/resource-messages.js.map +1 -1
- package/dist/browser/widgets/Widget.js +3 -2
- package/dist/browser/widgets/Widget.js.map +1 -1
- package/dist/ssr/actions/ContextMenu.js +9 -0
- package/dist/ssr/actions/ContextMenu.js.map +1 -1
- package/dist/ssr/actions/Dropdown.js +65 -31
- package/dist/ssr/actions/Dropdown.js.map +1 -1
- package/dist/ssr/actions/FilterChip.js +67 -16
- package/dist/ssr/actions/FilterChip.js.map +1 -1
- package/dist/ssr/actions/SelectionToolbar.js +104 -0
- package/dist/ssr/actions/SelectionToolbar.js.map +1 -0
- package/dist/ssr/actions/filter-messages.js +26 -2
- package/dist/ssr/actions/filter-messages.js.map +1 -1
- package/dist/ssr/actions/index.js +1 -0
- package/dist/ssr/actions/index.js.map +1 -1
- package/dist/ssr/actions/menu-rows.js +23 -3
- package/dist/ssr/actions/menu-rows.js.map +1 -1
- package/dist/ssr/actions/menu-sheet.js +2 -7
- package/dist/ssr/actions/menu-sheet.js.map +1 -1
- package/dist/ssr/charts.js +6 -0
- package/dist/ssr/charts.js.map +1 -0
- package/dist/ssr/chat/ChatComposer.js +184 -76
- package/dist/ssr/chat/ChatComposer.js.map +1 -1
- package/dist/ssr/chat/chat-messages.js +18 -0
- package/dist/ssr/chat/chat-messages.js.map +1 -1
- package/dist/ssr/chat/composer-document.js +19 -0
- package/dist/ssr/chat/composer-document.js.map +1 -1
- package/dist/ssr/chat/index.js.map +1 -1
- package/dist/ssr/content/Calendar.js +40 -31
- package/dist/ssr/content/Calendar.js.map +1 -1
- package/dist/ssr/content/CalendarDayView.js +40 -48
- package/dist/ssr/content/CalendarDayView.js.map +1 -1
- package/dist/ssr/content/Chart.js +8 -0
- package/dist/ssr/content/Chart.js.map +1 -1
- package/dist/ssr/content/FileGrid.js +132 -5
- package/dist/ssr/content/FileGrid.js.map +1 -1
- package/dist/ssr/content/FileTypeIcon.js +15 -0
- package/dist/ssr/content/FileTypeIcon.js.map +1 -1
- package/dist/ssr/content/FileView.js +11 -4
- package/dist/ssr/content/FileView.js.map +1 -1
- package/dist/ssr/content/MessageRow.js +274 -91
- package/dist/ssr/content/MessageRow.js.map +1 -1
- package/dist/ssr/content/ReactionBar.js +20 -1
- package/dist/ssr/content/ReactionBar.js.map +1 -1
- package/dist/ssr/content/calendar-day-scroll.js +4 -3
- package/dist/ssr/content/calendar-day-scroll.js.map +1 -1
- package/dist/ssr/content/chart-bar.js +476 -0
- package/dist/ssr/content/chart-bar.js.map +1 -0
- package/dist/ssr/content/file-list-messages.js +52 -0
- package/dist/ssr/content/file-list-messages.js.map +1 -0
- package/dist/ssr/content/index.js +2 -2
- package/dist/ssr/content/index.js.map +1 -1
- package/dist/ssr/feedback/Tooltip.js +31 -14
- package/dist/ssr/feedback/Tooltip.js.map +1 -1
- package/dist/ssr/feedback/dialog-core.js +6 -0
- package/dist/ssr/feedback/dialog-core.js.map +1 -1
- package/dist/ssr/inputs/ChoiceList.js +95 -0
- package/dist/ssr/inputs/ChoiceList.js.map +1 -0
- package/dist/ssr/inputs/ChoiceSlider.js +191 -0
- package/dist/ssr/inputs/ChoiceSlider.js.map +1 -0
- package/dist/ssr/inputs/ChoiceTiles.js +61 -0
- package/dist/ssr/inputs/ChoiceTiles.js.map +1 -0
- package/dist/ssr/inputs/ColorChoices.js +60 -0
- package/dist/ssr/inputs/ColorChoices.js.map +1 -0
- package/dist/ssr/inputs/QrScanner.js +89 -10
- package/dist/ssr/inputs/QrScanner.js.map +1 -1
- package/dist/ssr/inputs/TextInput.js +17 -2
- package/dist/ssr/inputs/TextInput.js.map +1 -1
- package/dist/ssr/inputs/index.js +4 -0
- package/dist/ssr/inputs/index.js.map +1 -1
- package/dist/ssr/inputs/qr-messages.js +2 -0
- package/dist/ssr/inputs/qr-messages.js.map +1 -1
- package/dist/ssr/internal/radio-keys.js +13 -0
- package/dist/ssr/internal/radio-keys.js.map +1 -0
- package/dist/ssr/intl/shortcut-messages.js +4 -0
- package/dist/ssr/intl/shortcut-messages.js.map +1 -1
- package/dist/ssr/intl/shortcut.js +4 -0
- package/dist/ssr/intl/shortcut.js.map +1 -1
- package/dist/ssr/layout/AnchoredPopover.js +142 -0
- package/dist/ssr/layout/AnchoredPopover.js.map +1 -0
- package/dist/ssr/layout/AppWorkspace.js +287 -141
- package/dist/ssr/layout/AppWorkspace.js.map +1 -1
- package/dist/ssr/layout/DetailPanel.js +181 -108
- package/dist/ssr/layout/DetailPanel.js.map +1 -1
- package/dist/ssr/layout/MobileShell.js +118 -24
- package/dist/ssr/layout/MobileShell.js.map +1 -1
- package/dist/ssr/layout/Settings.js +122 -45
- package/dist/ssr/layout/Settings.js.map +1 -1
- package/dist/ssr/layout/SidebarRailHint.js +79 -0
- package/dist/ssr/layout/SidebarRailHint.js.map +1 -0
- package/dist/ssr/layout/SidebarSwitcher.js +13 -3
- package/dist/ssr/layout/SidebarSwitcher.js.map +1 -1
- package/dist/ssr/layout/TabBar.js +11 -3
- package/dist/ssr/layout/TabBar.js.map +1 -1
- package/dist/ssr/layout/app-workspace-controller.js +11 -4
- package/dist/ssr/layout/app-workspace-controller.js.map +1 -1
- package/dist/ssr/layout/detail-panel-messages.js +4 -2
- package/dist/ssr/layout/detail-panel-messages.js.map +1 -1
- package/dist/ssr/layout/index.js +3 -1
- package/dist/ssr/layout/index.js.map +1 -1
- package/dist/ssr/layout/scroll-fade.js +32 -5
- package/dist/ssr/layout/scroll-fade.js.map +1 -1
- package/dist/ssr/layout/settings-messages.js +26 -2
- package/dist/ssr/layout/settings-messages.js.map +1 -1
- package/dist/ssr/surfaces/Avatar.js +2 -14
- package/dist/ssr/surfaces/Avatar.js.map +1 -1
- package/dist/ssr/surfaces/DotStrip.js +31 -0
- package/dist/ssr/surfaces/DotStrip.js.map +1 -0
- package/dist/ssr/surfaces/NoticeCard.js +21 -12
- package/dist/ssr/surfaces/NoticeCard.js.map +1 -1
- package/dist/ssr/surfaces/ProgressRing.js +3 -0
- package/dist/ssr/surfaces/ProgressRing.js.map +1 -1
- package/dist/ssr/surfaces/ResourceCard.js +40 -15
- package/dist/ssr/surfaces/ResourceCard.js.map +1 -1
- package/dist/ssr/surfaces/index.js +2 -0
- package/dist/ssr/surfaces/index.js.map +1 -1
- package/dist/ssr/surfaces/person-color.js +18 -0
- package/dist/ssr/surfaces/person-color.js.map +1 -0
- package/dist/ssr/surfaces/resource-messages.js +8 -4
- package/dist/ssr/surfaces/resource-messages.js.map +1 -1
- package/dist/ssr/widgets/Widget.js +3 -2
- package/dist/ssr/widgets/Widget.js.map +1 -1
- package/dist/styles.css +1 -1
- package/dist/types/actions/ContextMenu.d.ts +5 -0
- package/dist/types/actions/Dropdown.d.ts +19 -0
- package/dist/types/actions/FilterChip.d.ts +11 -0
- package/dist/types/actions/SelectionToolbar.d.ts +38 -0
- package/dist/types/actions/filter-messages.d.ts +12 -0
- package/dist/types/actions/index.d.ts +2 -0
- package/dist/types/actions/menu-rows.d.ts +7 -2
- package/dist/types/charts.d.ts +5 -0
- package/dist/types/chat/ChatComposer.d.ts +28 -0
- package/dist/types/chat/chat-messages.d.ts +9 -0
- package/dist/types/chat/composer-document.d.ts +5 -0
- package/dist/types/chat/index.d.ts +1 -1
- package/dist/types/content/Calendar.d.ts +7 -0
- package/dist/types/content/Chart.d.ts +2 -1
- package/dist/types/content/FileGrid.d.ts +43 -3
- package/dist/types/content/FileTypeIcon.d.ts +10 -0
- package/dist/types/content/FileView.d.ts +5 -1
- package/dist/types/content/MessageRow.d.ts +66 -2
- package/dist/types/content/calendar-day-scroll.d.ts +2 -1
- package/dist/types/content/chart-bar.d.ts +60 -0
- package/dist/types/content/file-list-messages.d.ts +24 -0
- package/dist/types/content/index.d.ts +4 -4
- package/dist/types/feedback/Tooltip.d.ts +8 -2
- package/dist/types/feedback/dialog-core.d.ts +3 -0
- package/dist/types/inputs/ChoiceList.d.ts +28 -0
- package/dist/types/inputs/ChoiceSlider.d.ts +36 -0
- package/dist/types/inputs/ChoiceTiles.d.ts +25 -0
- package/dist/types/inputs/ColorChoices.d.ts +19 -0
- package/dist/types/inputs/index.d.ts +8 -0
- package/dist/types/inputs/qr-messages.d.ts +1 -0
- package/dist/types/internal/radio-keys.d.ts +5 -0
- package/dist/types/intl/shortcut-messages.d.ts +2 -0
- package/dist/types/layout/AnchoredPopover.d.ts +31 -0
- package/dist/types/layout/AppWorkspace.d.ts +12 -0
- package/dist/types/layout/DetailPanel.d.ts +17 -0
- package/dist/types/layout/MobileShell.d.ts +55 -5
- package/dist/types/layout/Settings.d.ts +22 -0
- package/dist/types/layout/SidebarRailHint.d.ts +26 -0
- package/dist/types/layout/TabBar.d.ts +5 -0
- package/dist/types/layout/detail-panel-messages.d.ts +1 -0
- package/dist/types/layout/index.d.ts +5 -3
- package/dist/types/layout/scroll-fade.d.ts +5 -0
- package/dist/types/layout/settings-messages.d.ts +12 -0
- package/dist/types/surfaces/DotStrip.d.ts +22 -0
- package/dist/types/surfaces/NoticeCard.d.ts +3 -0
- package/dist/types/surfaces/ProgressRing.d.ts +2 -1
- package/dist/types/surfaces/ResourceCard.d.ts +9 -0
- package/dist/types/surfaces/index.d.ts +4 -1
- package/dist/types/surfaces/person-color.d.ts +10 -0
- package/dist/types/surfaces/resource-messages.d.ts +2 -0
- package/dist/types/widgets/Widget.d.ts +3 -2
- package/package.json +7 -2
package/dist/base.css
CHANGED
|
@@ -967,10 +967,23 @@
|
|
|
967
967
|
}
|
|
968
968
|
|
|
969
969
|
.stdlib-chart :is(.stdlib-chart-tick-label, .stdlib-chart-bar-value, .stdlib-chart-axis-label) {
|
|
970
|
-
font-family: var(--k2b-font-mono);
|
|
971
970
|
font-variant-numeric: tabular-nums;
|
|
972
971
|
}
|
|
973
972
|
|
|
973
|
+
.stdlib-chart .stdlib-chart-category-label { font-size: 11px; opacity: 0.8; }
|
|
974
|
+
.stdlib-chart .stdlib-chart-bar-value { font-size: 11px; opacity: 0.9; }
|
|
975
|
+
.stdlib-chart .stdlib-chart-axis-label { font-weight: 500; }
|
|
976
|
+
|
|
977
|
+
/* Horizontal bar rows keep their own height; a shorter box scrolls. */
|
|
978
|
+
.k2b-chart:has(> .k2b-chart__svg > svg[data-bar-layout="rows"]) {
|
|
979
|
+
overflow-y: auto;
|
|
980
|
+
}
|
|
981
|
+
|
|
982
|
+
.k2b-chart__svg:has(> svg[data-bar-layout="rows"]) {
|
|
983
|
+
flex: none;
|
|
984
|
+
height: var(--k2b-chart-height);
|
|
985
|
+
}
|
|
986
|
+
|
|
974
987
|
.stdlib-chart-series-0 { fill: var(--stdlib-chart-c1); stroke: var(--stdlib-chart-c1); }
|
|
975
988
|
.stdlib-chart-series-1 { fill: var(--stdlib-chart-c2); stroke: var(--stdlib-chart-c2); }
|
|
976
989
|
.stdlib-chart-series-2 { fill: var(--stdlib-chart-c3); stroke: var(--stdlib-chart-c3); }
|
|
@@ -19,6 +19,7 @@ import { returnFocus, ringOnReturn } from "../internal/focus-return";
|
|
|
19
19
|
import { useUiMessages } from "../intl/messages";
|
|
20
20
|
import { DropdownItems, dropdownPosition } from "./Dropdown";
|
|
21
21
|
import { focusRowSegment } from "./menu-rows";
|
|
22
|
+
const NATIVE_MENU_TARGETS = "a[href], input, textarea, select, [contenteditable]:not([contenteditable='false'])";
|
|
22
23
|
let closeActiveContextMenu;
|
|
23
24
|
const focusableItems = 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(", "))) : [];
|
|
24
25
|
|
|
@@ -52,6 +53,14 @@ export function ContextMenuBase(props) {
|
|
|
52
53
|
};
|
|
53
54
|
let resizeObserver;
|
|
54
55
|
const isOpen = () => position() !== undefined;
|
|
56
|
+
const keepsNativeMenu = target => {
|
|
57
|
+
if (!props.keepNativeMenu || !(target instanceof Node)) return false;
|
|
58
|
+
const element = target instanceof Element ? target : target.parentElement;
|
|
59
|
+
const native = element?.closest(NATIVE_MENU_TARGETS);
|
|
60
|
+
if (native && host?.contains(native)) return true;
|
|
61
|
+
const selection = window.getSelection();
|
|
62
|
+
return Boolean(selection && !selection.isCollapsed && selection.toString().trim() && selection.containsNode(target, true));
|
|
63
|
+
};
|
|
55
64
|
const hostClass = createMemo(() => typeof props.class === "function" ? props.class(isOpen()) : props.class);
|
|
56
65
|
const items = createMemo(() => props.items);
|
|
57
66
|
const dismiss = event => {
|
|
@@ -181,6 +190,8 @@ export function ContextMenuBase(props) {
|
|
|
181
190
|
var _el$ = _$getNextElement(_tmpl$);
|
|
182
191
|
_el$.$$keydown = event => {
|
|
183
192
|
if (props.disabled || event.key !== "ContextMenu" && !(event.shiftKey && event.key === "F10")) return;
|
|
193
|
+
// A nested context menu already opened its own; a field keeps the browser's.
|
|
194
|
+
if (event.defaultPrevented || props.keepNativeMenu && event.target instanceof Element && event.target.closest(NATIVE_MENU_TARGETS)) return;
|
|
184
195
|
event.preventDefault();
|
|
185
196
|
// Beside the focused element, such as a row of a composite widget, rather than the corner of the whole host.
|
|
186
197
|
const focused = document.activeElement;
|
|
@@ -189,6 +200,8 @@ export function ContextMenuBase(props) {
|
|
|
189
200
|
};
|
|
190
201
|
_el$.$$contextmenu = event => {
|
|
191
202
|
if (props.disabled) return;
|
|
203
|
+
// An enclosing context menu must not take over the browser's own either.
|
|
204
|
+
if (keepsNativeMenu(event.target)) return void event.stopPropagation();
|
|
192
205
|
event.preventDefault();
|
|
193
206
|
event.stopPropagation();
|
|
194
207
|
open(event.clientX, event.clientY);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":[],"sources":["actions/ContextMenu.tsx"],"sourcesContent":["import { createMemo, createSignal, createUniqueId, type JSX, onCleanup, onMount, Show } from \"solid-js\";\nimport { Portal } from \"solid-js/web\";\nimport { returnFocus, ringOnReturn } from \"../internal/focus-return\";\nimport { useUiMessages } from \"../intl/messages\";\nimport { type DropdownItem, DropdownItems, type DropdownPosition, dropdownPosition } from \"./Dropdown\";\nimport { focusRowSegment } from \"./menu-rows\";\n\nexport type ContextMenuProps = {\n items: readonly DropdownItem[];\n children: JSX.Element;\n class?: string | ((isOpen: boolean) => string);\n /** Tab order of the context-menu host. Descendant-focused composite widgets use -1. */\n tabIndex?: number;\n disabled?: boolean;\n onClose?: () => void;\n onOpen?: () => void;\n id?: string;\n label?: string;\n};\n\nlet closeActiveContextMenu: (() => void) | undefined;\n\nconst focusableItems = (menu: HTMLElement | undefined): HTMLElement[] =>\n menu\n ? Array.from(\n menu.querySelectorAll<HTMLElement>(\n [\n \"[role='menuitem']:not([aria-disabled='true'])\",\n \"[role='menuitemcheckbox']:not([aria-disabled='true'])\",\n \"[role='menuitemradio']:not([aria-disabled='true'])\",\n ].join(\", \"),\n ),\n )\n : [];\n\n/** Right-click menu with keyboard invocation, one-open-at-a-time behavior, and viewport clamping. */\nexport function ContextMenu(props: ContextMenuProps): JSX.Element {\n return ContextMenuBase(props);\n}\n\n/**\n * Package-internal, not exported from the package index: `openAt` lets GestureMenu open the menu at a held finger, and\n * `title` names what was pressed above the entries, since the finger covers it.\n */\nexport function ContextMenuBase(\n props: ContextMenuProps & {\n openAt?: (open: (x: number, y: number) => void) => void;\n title?: string;\n closeWith?: (close: () => void) => void;\n },\n): JSX.Element {\n const messages = useUiMessages();\n const generatedId = `k2b-context-${createUniqueId()}`;\n const menuId = `${generatedId}-menu`;\n const [position, setPosition] = createSignal<{ x: number; y: number }>();\n let host: HTMLDivElement | undefined;\n let menu: HTMLDivElement | undefined;\n let listenersAttached = false;\n let hostRing = true;\n /** The element inside the host that had focus as the menu opened, such as a row or a day of a composite widget. */\n let opener: HTMLElement | undefined;\n let anchor = { x: 0, y: 0 };\n let viewport = { width: 0, height: 0 };\n let resizeObserver: ResizeObserver | undefined;\n\n const isOpen = () => position() !== undefined;\n const hostClass = createMemo(() => (typeof props.class === \"function\" ? props.class(isOpen()) : props.class));\n const items = createMemo<readonly DropdownItem[]>(() => props.items);\n\n const dismiss = (event: PointerEvent) => {\n if (menu?.contains(event.target as Node)) return;\n close();\n };\n const closeOnScroll = (event: Event) => {\n const target = event.target;\n if (target instanceof Node && menu?.contains(target)) return;\n close();\n };\n // A resize event may leave the viewport's size unchanged; headless Chromium\n // was seen to fire one on a fresh page. The clamped menu is still in place.\n const closeOnResize = () => {\n if (window.innerWidth === viewport.width && window.innerHeight === viewport.height) return;\n close();\n };\n const attachOpenListeners = () => {\n if (listenersAttached) return;\n listenersAttached = true;\n document.addEventListener(\"pointerdown\", dismiss);\n document.addEventListener(\"keydown\", keyDown);\n window.addEventListener(\"resize\", closeOnResize);\n window.addEventListener(\"scroll\", closeOnScroll, true);\n };\n const detachOpenListeners = () => {\n if (!listenersAttached) return;\n listenersAttached = false;\n document.removeEventListener(\"pointerdown\", dismiss);\n document.removeEventListener(\"keydown\", keyDown);\n window.removeEventListener(\"resize\", closeOnResize);\n window.removeEventListener(\"scroll\", closeOnScroll, true);\n resizeObserver?.disconnect();\n };\n /** Clamps the rendered menu into the viewport beside the point that opened it. */\n const place = () => {\n if (!isOpen() || !menu?.isConnected) return;\n const point = dropdownPosition(\n new DOMRect(anchor.x, anchor.y, 0, 0),\n menu.getBoundingClientRect(),\n \"bottom-right\" satisfies DropdownPosition,\n { width: window.innerWidth, height: window.innerHeight },\n 0,\n );\n setPosition({ x: point.left, y: point.top });\n };\n const close = () => {\n detachOpenListeners();\n if (!isOpen()) return;\n setPosition();\n if (closeActiveContextMenu === close) closeActiveContextMenu = undefined;\n props.onClose?.();\n };\n const focusItem = (index: number) => {\n const items = focusableItems(menu);\n if (items.length === 0) return;\n items[(index + items.length) % items.length]?.focus();\n };\n const open = (x: number, y: number) => {\n if (props.disabled) return;\n closeActiveContextMenu?.();\n // Focus may sit on a descendant of the host, as in composite widgets; Escape returns it there.\n const focused = document.activeElement;\n opener = focused instanceof HTMLElement && focused !== host && host?.contains(focused) ? focused : undefined;\n hostRing = ringOnReturn(focused);\n anchor = { x, y };\n viewport = { width: window.innerWidth, height: window.innerHeight };\n setPosition({ x, y });\n closeActiveContextMenu = close;\n attachOpenListeners();\n props.onOpen?.();\n // The menu sizes to its entries, so it is measured once rendered and\n // clamped into the viewport before the next paint, and again whenever its\n // entries change its size while it is open.\n queueMicrotask(() => {\n if (!isOpen() || !menu?.isConnected) return;\n place();\n if (typeof ResizeObserver !== \"undefined\") {\n resizeObserver ??= new ResizeObserver(place);\n resizeObserver.observe(menu);\n }\n focusItem(0);\n });\n };\n const keyDown = (event: KeyboardEvent) => {\n if (!isOpen()) return;\n const items = focusableItems(menu);\n const current = items.indexOf(document.activeElement as HTMLElement);\n if (event.key === \"ArrowDown\" || event.key === \"ArrowUp\") {\n event.preventDefault();\n focusItem(current + (event.key === \"ArrowDown\" ? 1 : -1));\n } else if (focusRowSegment(items, event.key)) {\n event.preventDefault();\n } else if (event.key === \"Home\" || event.key === \"End\") {\n event.preventDefault();\n focusItem(event.key === \"Home\" ? 0 : -1);\n } else if (event.key === \"Escape\") {\n event.preventDefault();\n close();\n returnFocus(opener?.isConnected ? opener : host, hostRing);\n } else if (event.key === \"Tab\") {\n close();\n }\n };\n\n props.openAt?.(open);\n // A close from outside, such as a drag taking over the press, returns focus that sits in the menu to where it came from.\n props.closeWith?.(() => {\n if (isOpen() && menu?.contains(document.activeElement)) returnFocus(opener?.isConnected ? opener : host, hostRing);\n close();\n });\n\n onMount(() => {\n onCleanup(() => {\n detachOpenListeners();\n if (closeActiveContextMenu === close) closeActiveContextMenu = undefined;\n });\n });\n\n return (\n <>\n {/* biome-ignore lint/a11y/useAriaPropsSupportedByRole: the named group owns the context-menu relationship without pretending arbitrary children form one button. */}\n <div\n ref={host}\n id={props.id ?? generatedId}\n class={hostClass()}\n role=\"group\"\n tabIndex={props.disabled ? undefined : (props.tabIndex ?? 0)}\n aria-label={props.label ?? messages().contextMenu}\n aria-haspopup=\"menu\"\n aria-expanded={isOpen()}\n aria-controls={isOpen() ? menuId : undefined}\n aria-disabled={props.disabled ? \"true\" : undefined}\n onContextMenu={(event) => {\n if (props.disabled) return;\n event.preventDefault();\n event.stopPropagation();\n open(event.clientX, event.clientY);\n }}\n onKeyDown={(event) => {\n if (props.disabled || (event.key !== \"ContextMenu\" && !(event.shiftKey && event.key === \"F10\"))) return;\n event.preventDefault();\n // Beside the focused element, such as a row of a composite widget, rather than the corner of the whole host.\n const focused = document.activeElement;\n const rect = (focused instanceof HTMLElement && host?.contains(focused) ? focused : host)?.getBoundingClientRect();\n if (rect) open(rect.left + 12, rect.top + 12);\n }}\n >\n {props.children}\n </div>\n <Show when={position()}>\n {(point) => (\n <Portal>\n <div\n ref={menu}\n id={menuId}\n class=\"k2b-ui k2b-context-menu\"\n role=\"menu\"\n aria-label={props.label ?? messages().contextMenu}\n style={{ left: `${point().x}px`, top: `${point().y}px` }}\n onPointerDown={(event) => event.stopPropagation()}\n >\n {/* The menu carries the same name for assistive technology. */}\n <Show when={props.title}>\n <div class=\"k2b-context-menu__title\" aria-hidden=\"true\">\n {props.title}\n </div>\n </Show>\n <DropdownItems items={items()} close={close} />\n </div>\n </Portal>\n )}\n </Show>\n </>\n );\n}\n\nexport default ContextMenu;\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"names":[],"sources":["actions/ContextMenu.tsx"],"sourcesContent":["import { createMemo, createSignal, createUniqueId, type JSX, onCleanup, onMount, Show } from \"solid-js\";\nimport { Portal } from \"solid-js/web\";\nimport { returnFocus, ringOnReturn } from \"../internal/focus-return\";\nimport { useUiMessages } from \"../intl/messages\";\nimport { type DropdownItem, DropdownItems, type DropdownPosition, dropdownPosition } from \"./Dropdown\";\nimport { focusRowSegment } from \"./menu-rows\";\n\nexport type ContextMenuProps = {\n items: readonly DropdownItem[];\n children: JSX.Element;\n class?: string | ((isOpen: boolean) => string);\n /** Tab order of the context-menu host. Descendant-focused composite widgets use -1. */\n tabIndex?: number;\n disabled?: boolean;\n onClose?: () => void;\n onOpen?: () => void;\n id?: string;\n label?: string;\n /**\n * Links, form fields, editable text, and selected text inside the host keep the browser's own menu, with its Copy,\n * Paste, and Open link. Use it where the host wraps readable content rather than one row.\n */\n keepNativeMenu?: boolean;\n};\n\nconst NATIVE_MENU_TARGETS = \"a[href], input, textarea, select, [contenteditable]:not([contenteditable='false'])\";\n\nlet closeActiveContextMenu: (() => void) | undefined;\n\nconst focusableItems = (menu: HTMLElement | undefined): HTMLElement[] =>\n menu\n ? Array.from(\n menu.querySelectorAll<HTMLElement>(\n [\n \"[role='menuitem']:not([aria-disabled='true'])\",\n \"[role='menuitemcheckbox']:not([aria-disabled='true'])\",\n \"[role='menuitemradio']:not([aria-disabled='true'])\",\n ].join(\", \"),\n ),\n )\n : [];\n\n/** Right-click menu with keyboard invocation, one-open-at-a-time behavior, and viewport clamping. */\nexport function ContextMenu(props: ContextMenuProps): JSX.Element {\n return ContextMenuBase(props);\n}\n\n/**\n * Package-internal, not exported from the package index: `openAt` lets GestureMenu open the menu at a held finger, and\n * `title` names what was pressed above the entries, since the finger covers it.\n */\nexport function ContextMenuBase(\n props: ContextMenuProps & {\n openAt?: (open: (x: number, y: number) => void) => void;\n title?: string;\n closeWith?: (close: () => void) => void;\n },\n): JSX.Element {\n const messages = useUiMessages();\n const generatedId = `k2b-context-${createUniqueId()}`;\n const menuId = `${generatedId}-menu`;\n const [position, setPosition] = createSignal<{ x: number; y: number }>();\n let host: HTMLDivElement | undefined;\n let menu: HTMLDivElement | undefined;\n let listenersAttached = false;\n let hostRing = true;\n /** The element inside the host that had focus as the menu opened, such as a row or a day of a composite widget. */\n let opener: HTMLElement | undefined;\n let anchor = { x: 0, y: 0 };\n let viewport = { width: 0, height: 0 };\n let resizeObserver: ResizeObserver | undefined;\n\n const isOpen = () => position() !== undefined;\n const keepsNativeMenu = (target: EventTarget | null): boolean => {\n if (!props.keepNativeMenu || !(target instanceof Node)) return false;\n const element = target instanceof Element ? target : target.parentElement;\n const native = element?.closest(NATIVE_MENU_TARGETS);\n if (native && host?.contains(native)) return true;\n const selection = window.getSelection();\n return Boolean(selection && !selection.isCollapsed && selection.toString().trim() && selection.containsNode(target, true));\n };\n const hostClass = createMemo(() => (typeof props.class === \"function\" ? props.class(isOpen()) : props.class));\n const items = createMemo<readonly DropdownItem[]>(() => props.items);\n\n const dismiss = (event: PointerEvent) => {\n if (menu?.contains(event.target as Node)) return;\n close();\n };\n const closeOnScroll = (event: Event) => {\n const target = event.target;\n if (target instanceof Node && menu?.contains(target)) return;\n close();\n };\n // A resize event may leave the viewport's size unchanged; headless Chromium\n // was seen to fire one on a fresh page. The clamped menu is still in place.\n const closeOnResize = () => {\n if (window.innerWidth === viewport.width && window.innerHeight === viewport.height) return;\n close();\n };\n const attachOpenListeners = () => {\n if (listenersAttached) return;\n listenersAttached = true;\n document.addEventListener(\"pointerdown\", dismiss);\n document.addEventListener(\"keydown\", keyDown);\n window.addEventListener(\"resize\", closeOnResize);\n window.addEventListener(\"scroll\", closeOnScroll, true);\n };\n const detachOpenListeners = () => {\n if (!listenersAttached) return;\n listenersAttached = false;\n document.removeEventListener(\"pointerdown\", dismiss);\n document.removeEventListener(\"keydown\", keyDown);\n window.removeEventListener(\"resize\", closeOnResize);\n window.removeEventListener(\"scroll\", closeOnScroll, true);\n resizeObserver?.disconnect();\n };\n /** Clamps the rendered menu into the viewport beside the point that opened it. */\n const place = () => {\n if (!isOpen() || !menu?.isConnected) return;\n const point = dropdownPosition(\n new DOMRect(anchor.x, anchor.y, 0, 0),\n menu.getBoundingClientRect(),\n \"bottom-right\" satisfies DropdownPosition,\n { width: window.innerWidth, height: window.innerHeight },\n 0,\n );\n setPosition({ x: point.left, y: point.top });\n };\n const close = () => {\n detachOpenListeners();\n if (!isOpen()) return;\n setPosition();\n if (closeActiveContextMenu === close) closeActiveContextMenu = undefined;\n props.onClose?.();\n };\n const focusItem = (index: number) => {\n const items = focusableItems(menu);\n if (items.length === 0) return;\n items[(index + items.length) % items.length]?.focus();\n };\n const open = (x: number, y: number) => {\n if (props.disabled) return;\n closeActiveContextMenu?.();\n // Focus may sit on a descendant of the host, as in composite widgets; Escape returns it there.\n const focused = document.activeElement;\n opener = focused instanceof HTMLElement && focused !== host && host?.contains(focused) ? focused : undefined;\n hostRing = ringOnReturn(focused);\n anchor = { x, y };\n viewport = { width: window.innerWidth, height: window.innerHeight };\n setPosition({ x, y });\n closeActiveContextMenu = close;\n attachOpenListeners();\n props.onOpen?.();\n // The menu sizes to its entries, so it is measured once rendered and\n // clamped into the viewport before the next paint, and again whenever its\n // entries change its size while it is open.\n queueMicrotask(() => {\n if (!isOpen() || !menu?.isConnected) return;\n place();\n if (typeof ResizeObserver !== \"undefined\") {\n resizeObserver ??= new ResizeObserver(place);\n resizeObserver.observe(menu);\n }\n focusItem(0);\n });\n };\n const keyDown = (event: KeyboardEvent) => {\n if (!isOpen()) return;\n const items = focusableItems(menu);\n const current = items.indexOf(document.activeElement as HTMLElement);\n if (event.key === \"ArrowDown\" || event.key === \"ArrowUp\") {\n event.preventDefault();\n focusItem(current + (event.key === \"ArrowDown\" ? 1 : -1));\n } else if (focusRowSegment(items, event.key)) {\n event.preventDefault();\n } else if (event.key === \"Home\" || event.key === \"End\") {\n event.preventDefault();\n focusItem(event.key === \"Home\" ? 0 : -1);\n } else if (event.key === \"Escape\") {\n event.preventDefault();\n close();\n returnFocus(opener?.isConnected ? opener : host, hostRing);\n } else if (event.key === \"Tab\") {\n close();\n }\n };\n\n props.openAt?.(open);\n // A close from outside, such as a drag taking over the press, returns focus that sits in the menu to where it came from.\n props.closeWith?.(() => {\n if (isOpen() && menu?.contains(document.activeElement)) returnFocus(opener?.isConnected ? opener : host, hostRing);\n close();\n });\n\n onMount(() => {\n onCleanup(() => {\n detachOpenListeners();\n if (closeActiveContextMenu === close) closeActiveContextMenu = undefined;\n });\n });\n\n return (\n <>\n {/* biome-ignore lint/a11y/useAriaPropsSupportedByRole: the named group owns the context-menu relationship without pretending arbitrary children form one button. */}\n <div\n ref={host}\n id={props.id ?? generatedId}\n class={hostClass()}\n role=\"group\"\n tabIndex={props.disabled ? undefined : (props.tabIndex ?? 0)}\n aria-label={props.label ?? messages().contextMenu}\n aria-haspopup=\"menu\"\n aria-expanded={isOpen()}\n aria-controls={isOpen() ? menuId : undefined}\n aria-disabled={props.disabled ? \"true\" : undefined}\n onContextMenu={(event) => {\n if (props.disabled) return;\n // An enclosing context menu must not take over the browser's own either.\n if (keepsNativeMenu(event.target)) return void event.stopPropagation();\n event.preventDefault();\n event.stopPropagation();\n open(event.clientX, event.clientY);\n }}\n onKeyDown={(event) => {\n if (props.disabled || (event.key !== \"ContextMenu\" && !(event.shiftKey && event.key === \"F10\"))) return;\n // A nested context menu already opened its own; a field keeps the browser's.\n if (\n event.defaultPrevented ||\n (props.keepNativeMenu && event.target instanceof Element && event.target.closest(NATIVE_MENU_TARGETS))\n )\n return;\n event.preventDefault();\n // Beside the focused element, such as a row of a composite widget, rather than the corner of the whole host.\n const focused = document.activeElement;\n const rect = (focused instanceof HTMLElement && host?.contains(focused) ? focused : host)?.getBoundingClientRect();\n if (rect) open(rect.left + 12, rect.top + 12);\n }}\n >\n {props.children}\n </div>\n <Show when={position()}>\n {(point) => (\n <Portal>\n <div\n ref={menu}\n id={menuId}\n class=\"k2b-ui k2b-context-menu\"\n role=\"menu\"\n aria-label={props.label ?? messages().contextMenu}\n style={{ left: `${point().x}px`, top: `${point().y}px` }}\n onPointerDown={(event) => event.stopPropagation()}\n >\n {/* The menu carries the same name for assistive technology. */}\n <Show when={props.title}>\n <div class=\"k2b-context-menu__title\" aria-hidden=\"true\">\n {props.title}\n </div>\n </Show>\n <DropdownItems items={items()} close={close} />\n </div>\n </Portal>\n )}\n </Show>\n </>\n );\n}\n\nexport default ContextMenu;\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -3,8 +3,8 @@ import { delegateEvents as _$delegateEvents } from "solid-js/web";
|
|
|
3
3
|
import { style as _$style } from "solid-js/web";
|
|
4
4
|
import { use as _$use } from "solid-js/web";
|
|
5
5
|
import { spread as _$spread } from "solid-js/web";
|
|
6
|
-
import { mergeProps as _$mergeProps } from "solid-js/web";
|
|
7
6
|
import { setStyleProperty as _$setStyleProperty } from "solid-js/web";
|
|
7
|
+
import { mergeProps as _$mergeProps } from "solid-js/web";
|
|
8
8
|
import { setProperty as _$setProperty } from "solid-js/web";
|
|
9
9
|
import { runHydrationEvents as _$runHydrationEvents } from "solid-js/web";
|
|
10
10
|
import { setAttribute as _$setAttribute } from "solid-js/web";
|
|
@@ -21,15 +21,17 @@ var _tmpl$ = /*#__PURE__*/_$template(`<span class=k2b-dropdown__copy><span></spa
|
|
|
21
21
|
_tmpl$4 = /*#__PURE__*/_$template(`<small>`),
|
|
22
22
|
_tmpl$5 = /*#__PURE__*/_$template(`<button type=button role=menuitem tabindex=-1>`),
|
|
23
23
|
_tmpl$6 = /*#__PURE__*/_$template(`<a role=menuitem tabindex=-1>`),
|
|
24
|
-
_tmpl$7 = /*#__PURE__*/_$template(`<
|
|
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(`<div class=k2b-
|
|
30
|
-
_tmpl$11 = /*#__PURE__*/_$template(`<div class=k2b-
|
|
31
|
-
_tmpl$12 = /*#__PURE__*/_$template(`<
|
|
32
|
-
_tmpl$13 = /*#__PURE__*/_$template(`<
|
|
24
|
+
_tmpl$7 = /*#__PURE__*/_$template(`<div class=k2b-dropdown__pair><!$><!/><!$><!/>`),
|
|
25
|
+
_tmpl$8 = /*#__PURE__*/_$template(`<i class="ti ti-check">`),
|
|
26
|
+
_tmpl$9 = /*#__PURE__*/_$template(`<span class=k2b-dropdown__checkbox aria-hidden=true>`),
|
|
27
|
+
_tmpl$0 = /*#__PURE__*/_$template(`<i class="ti ti-check k2b-dropdown__check"aria-hidden=true>`),
|
|
28
|
+
_tmpl$1 = /*#__PURE__*/_$template(`<span class=k2b-dropdown__color aria-hidden=true>`),
|
|
29
|
+
_tmpl$10 = /*#__PURE__*/_$template(`<div class=k2b-dropdown__row>`),
|
|
30
|
+
_tmpl$11 = /*#__PURE__*/_$template(`<div class=k2b-dropdown__section role=group><!$><!/><!$><!/>`),
|
|
31
|
+
_tmpl$12 = /*#__PURE__*/_$template(`<div class=k2b-dropdown__label>`),
|
|
32
|
+
_tmpl$13 = /*#__PURE__*/_$template(`<div class="k2b-dropdown__label k2b-dropdown__label--action"><span></span><!$><!/>`),
|
|
33
|
+
_tmpl$14 = /*#__PURE__*/_$template(`<button>`),
|
|
34
|
+
_tmpl$15 = /*#__PURE__*/_$template(`<span><!$><!/><div popover=auto role=menu>`);
|
|
33
35
|
import { createContext, createEffect, createSignal, createUniqueId, For, onCleanup, onMount, Show, splitProps, useContext } from "solid-js";
|
|
34
36
|
import { Dynamic } from "solid-js/web";
|
|
35
37
|
import { Tooltip, useLabelTooltip } from "../feedback/Tooltip";
|
|
@@ -37,19 +39,21 @@ import { returnFocus, ringOnReturn } from "../internal/focus-return";
|
|
|
37
39
|
import { useLocale } from "../intl/locale";
|
|
38
40
|
import { useUiMessages } from "../intl/messages";
|
|
39
41
|
import { Button, iconTitle } from "./Button";
|
|
40
|
-
import { focusRowSegment } from "./menu-rows";
|
|
42
|
+
import { focusMenuRow, focusRowSegment } from "./menu-rows";
|
|
41
43
|
import { openMenuSheet, prefersMenuSheet } from "./menu-sheet";
|
|
42
44
|
|
|
43
45
|
// Resolved outside JSX: a conditional attribute compiles to a lazy memo, which would be created inside the click handler.
|
|
44
46
|
const selectAction = item => item.action;
|
|
45
47
|
|
|
48
|
+
/** A second, smaller action at the end of a row, such as "Only" beside a checkbox; it keeps the menu open. */
|
|
49
|
+
|
|
46
50
|
/** Declarative radio or checkbox row for compact action menus. */
|
|
47
51
|
|
|
48
52
|
const MenuContext = createContext();
|
|
49
53
|
const DropdownContext = createContext();
|
|
50
54
|
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(", "))) : [];
|
|
51
55
|
const focusMenuItem = (menu, index) => {
|
|
52
|
-
const items = actionableItems(menu);
|
|
56
|
+
const items = actionableItems(menu).filter(item => !item.classList.contains("k2b-dropdown__secondary"));
|
|
53
57
|
if (items.length === 0) return;
|
|
54
58
|
items[(index + items.length) % items.length]?.focus();
|
|
55
59
|
};
|
|
@@ -188,6 +192,51 @@ export function DropdownItem(props) {
|
|
|
188
192
|
});
|
|
189
193
|
}
|
|
190
194
|
function DropdownChoiceItem(props) {
|
|
195
|
+
return _$createComponent(Show, {
|
|
196
|
+
get when() {
|
|
197
|
+
return props.secondary;
|
|
198
|
+
},
|
|
199
|
+
get fallback() {
|
|
200
|
+
return _$createComponent(DropdownChoiceRow, props);
|
|
201
|
+
},
|
|
202
|
+
children: secondary => (() => {
|
|
203
|
+
var _el$0 = _$getNextElement(_tmpl$7),
|
|
204
|
+
_el$1 = _el$0.firstChild,
|
|
205
|
+
[_el$10, _co$2] = _$getNextMarker(_el$1.nextSibling),
|
|
206
|
+
_el$11 = _el$10.nextSibling,
|
|
207
|
+
[_el$12, _co$3] = _$getNextMarker(_el$11.nextSibling);
|
|
208
|
+
_$insert(_el$0, _$createComponent(DropdownChoiceRow, props), _el$10, _co$2);
|
|
209
|
+
_$insert(_el$0, _$createComponent(DropdownSecondaryButton, _$mergeProps(secondary, {
|
|
210
|
+
"class": "k2b-dropdown__secondary"
|
|
211
|
+
})), _el$12, _co$3);
|
|
212
|
+
return _el$0;
|
|
213
|
+
})()
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
function DropdownSecondaryButton(props) {
|
|
217
|
+
return (() => {
|
|
218
|
+
var _el$13 = _$getNextElement(_tmpl$5);
|
|
219
|
+
_el$13.$$click = event => {
|
|
220
|
+
event.preventDefault();
|
|
221
|
+
event.stopPropagation();
|
|
222
|
+
props.action();
|
|
223
|
+
};
|
|
224
|
+
_$insert(_el$13, () => props.label);
|
|
225
|
+
_$effect(_p$ => {
|
|
226
|
+
var _v$10 = props.class,
|
|
227
|
+
_v$11 = props.ariaLabel;
|
|
228
|
+
_v$10 !== _p$.e && _$className(_el$13, _p$.e = _v$10);
|
|
229
|
+
_v$11 !== _p$.t && _$setAttribute(_el$13, "aria-label", _p$.t = _v$11);
|
|
230
|
+
return _p$;
|
|
231
|
+
}, {
|
|
232
|
+
e: undefined,
|
|
233
|
+
t: undefined
|
|
234
|
+
});
|
|
235
|
+
_$runHydrationEvents();
|
|
236
|
+
return _el$13;
|
|
237
|
+
})();
|
|
238
|
+
}
|
|
239
|
+
function DropdownChoiceRow(props) {
|
|
191
240
|
const menu = useContext(MenuContext);
|
|
192
241
|
const checked = () => typeof props.checked === "function" ? props.checked() : props.checked;
|
|
193
242
|
let element;
|
|
@@ -248,16 +297,16 @@ function DropdownChoiceItem(props) {
|
|
|
248
297
|
return props.choice === "checkbox";
|
|
249
298
|
},
|
|
250
299
|
get children() {
|
|
251
|
-
var _el$
|
|
252
|
-
_$insert(_el$
|
|
300
|
+
var _el$14 = _$getNextElement(_tmpl$9);
|
|
301
|
+
_$insert(_el$14, _$createComponent(Show, {
|
|
253
302
|
get when() {
|
|
254
303
|
return checked();
|
|
255
304
|
},
|
|
256
305
|
get children() {
|
|
257
|
-
return _$getNextElement(_tmpl$
|
|
306
|
+
return _$getNextElement(_tmpl$8);
|
|
258
307
|
}
|
|
259
308
|
}));
|
|
260
|
-
return _el$
|
|
309
|
+
return _el$14;
|
|
261
310
|
}
|
|
262
311
|
}), _$createComponent(Show, {
|
|
263
312
|
get when() {
|
|
@@ -269,51 +318,51 @@ function DropdownChoiceItem(props) {
|
|
|
269
318
|
return props.icon;
|
|
270
319
|
},
|
|
271
320
|
children: icon => (() => {
|
|
272
|
-
var _el$
|
|
273
|
-
_$effect(() => _$className(_el$
|
|
274
|
-
return _el$
|
|
321
|
+
var _el$21 = _$getNextElement(_tmpl$2);
|
|
322
|
+
_$effect(() => _$className(_el$21, icon()));
|
|
323
|
+
return _el$21;
|
|
275
324
|
})()
|
|
276
325
|
});
|
|
277
326
|
},
|
|
278
327
|
children: image => (() => {
|
|
279
|
-
var _el$
|
|
280
|
-
_$effect(() => _$setAttribute(_el$
|
|
281
|
-
return _el$
|
|
328
|
+
var _el$22 = _$getNextElement(_tmpl$3);
|
|
329
|
+
_$effect(() => _$setAttribute(_el$22, "src", image()));
|
|
330
|
+
return _el$22;
|
|
282
331
|
})()
|
|
283
332
|
}), _$createComponent(Show, {
|
|
284
333
|
get when() {
|
|
285
334
|
return props.color;
|
|
286
335
|
},
|
|
287
336
|
children: color => (() => {
|
|
288
|
-
var _el$
|
|
289
|
-
_$effect(_$p => _$setStyleProperty(_el$
|
|
290
|
-
return _el$
|
|
337
|
+
var _el$23 = _$getNextElement(_tmpl$1);
|
|
338
|
+
_$effect(_$p => _$setStyleProperty(_el$23, "--k2b-dropdown-color", color()));
|
|
339
|
+
return _el$23;
|
|
291
340
|
})()
|
|
292
341
|
}), (() => {
|
|
293
|
-
var _el$
|
|
294
|
-
_el$
|
|
295
|
-
_el$
|
|
296
|
-
[_el$
|
|
297
|
-
_$insert(_el$
|
|
298
|
-
_$insert(_el$
|
|
342
|
+
var _el$16 = _$getNextElement(_tmpl$),
|
|
343
|
+
_el$17 = _el$16.firstChild,
|
|
344
|
+
_el$18 = _el$17.nextSibling,
|
|
345
|
+
[_el$19, _co$4] = _$getNextMarker(_el$18.nextSibling);
|
|
346
|
+
_$insert(_el$17, () => props.label);
|
|
347
|
+
_$insert(_el$16, _$createComponent(Show, {
|
|
299
348
|
get when() {
|
|
300
349
|
return props.description;
|
|
301
350
|
},
|
|
302
351
|
children: description => (() => {
|
|
303
|
-
var _el$
|
|
304
|
-
_$insert(_el$
|
|
305
|
-
return _el$
|
|
352
|
+
var _el$24 = _$getNextElement(_tmpl$4);
|
|
353
|
+
_$insert(_el$24, description);
|
|
354
|
+
return _el$24;
|
|
306
355
|
})()
|
|
307
|
-
}), _el$
|
|
308
|
-
return _el$
|
|
356
|
+
}), _el$19, _co$4);
|
|
357
|
+
return _el$16;
|
|
309
358
|
})(), _$memo(() => props.trailing), _$createComponent(Show, {
|
|
310
359
|
get when() {
|
|
311
360
|
return props.choice === "radio";
|
|
312
361
|
},
|
|
313
362
|
get children() {
|
|
314
|
-
var _el$
|
|
315
|
-
_$effect(() => _$setAttribute(_el$
|
|
316
|
-
return _el$
|
|
363
|
+
var _el$20 = _$getNextElement(_tmpl$0);
|
|
364
|
+
_$effect(() => _$setAttribute(_el$20, "data-hidden", checked() ? undefined : "true"));
|
|
365
|
+
return _el$20;
|
|
317
366
|
}
|
|
318
367
|
})];
|
|
319
368
|
}
|
|
@@ -381,22 +430,40 @@ export function DropdownItems(props) {
|
|
|
381
430
|
return renderItem(item);
|
|
382
431
|
},
|
|
383
432
|
get children() {
|
|
384
|
-
var _el$
|
|
385
|
-
_el$
|
|
386
|
-
[_el$
|
|
387
|
-
_el$
|
|
388
|
-
[_el$
|
|
389
|
-
_$insert(_el$
|
|
433
|
+
var _el$25 = _$getNextElement(_tmpl$11),
|
|
434
|
+
_el$27 = _el$25.firstChild,
|
|
435
|
+
[_el$28, _co$5] = _$getNextMarker(_el$27.nextSibling),
|
|
436
|
+
_el$29 = _el$28.nextSibling,
|
|
437
|
+
[_el$30, _co$6] = _$getNextMarker(_el$29.nextSibling);
|
|
438
|
+
_$insert(_el$25, _$createComponent(Show, {
|
|
390
439
|
get when() {
|
|
391
440
|
return item.sectionLabel;
|
|
392
441
|
},
|
|
393
|
-
children: label => (
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
442
|
+
children: label => _$createComponent(Show, {
|
|
443
|
+
get when() {
|
|
444
|
+
return item.labelAction;
|
|
445
|
+
},
|
|
446
|
+
get fallback() {
|
|
447
|
+
return (() => {
|
|
448
|
+
var _el$31 = _$getNextElement(_tmpl$12);
|
|
449
|
+
_$insert(_el$31, label);
|
|
450
|
+
return _el$31;
|
|
451
|
+
})();
|
|
452
|
+
},
|
|
453
|
+
children: action => (() => {
|
|
454
|
+
var _el$32 = _$getNextElement(_tmpl$13),
|
|
455
|
+
_el$33 = _el$32.firstChild,
|
|
456
|
+
_el$34 = _el$33.nextSibling,
|
|
457
|
+
[_el$35, _co$7] = _$getNextMarker(_el$34.nextSibling);
|
|
458
|
+
_$insert(_el$33, label);
|
|
459
|
+
_$insert(_el$32, _$createComponent(DropdownSecondaryButton, _$mergeProps(action, {
|
|
460
|
+
"class": "k2b-dropdown__label-action"
|
|
461
|
+
})), _el$35, _co$7);
|
|
462
|
+
return _el$32;
|
|
463
|
+
})()
|
|
464
|
+
})
|
|
465
|
+
}), _el$28, _co$5);
|
|
466
|
+
_$insert(_el$25, _$createComponent(Show, {
|
|
400
467
|
get when() {
|
|
401
468
|
return item.layout === "row";
|
|
402
469
|
},
|
|
@@ -409,27 +476,27 @@ export function DropdownItems(props) {
|
|
|
409
476
|
});
|
|
410
477
|
},
|
|
411
478
|
get children() {
|
|
412
|
-
var _el$
|
|
413
|
-
_$insert(_el$
|
|
479
|
+
var _el$26 = _$getNextElement(_tmpl$10);
|
|
480
|
+
_$insert(_el$26, _$createComponent(For, {
|
|
414
481
|
get each() {
|
|
415
482
|
return item.items;
|
|
416
483
|
},
|
|
417
484
|
children: renderItem
|
|
418
485
|
}));
|
|
419
|
-
return _el$
|
|
486
|
+
return _el$26;
|
|
420
487
|
}
|
|
421
|
-
}), _el$
|
|
488
|
+
}), _el$30, _co$6);
|
|
422
489
|
_$effect(_p$ => {
|
|
423
|
-
var _v$
|
|
424
|
-
_v$
|
|
425
|
-
_v$
|
|
426
|
-
_v$
|
|
490
|
+
var _v$12 = index() > 0 ? "true" : undefined,
|
|
491
|
+
_v$13 = item.sectionLabel ?? (item.layout === "row" ? undefined : messages().actions);
|
|
492
|
+
_v$12 !== _p$.e && _$setAttribute(_el$25, "data-divided", _p$.e = _v$12);
|
|
493
|
+
_v$13 !== _p$.t && _$setAttribute(_el$25, "aria-label", _p$.t = _v$13);
|
|
427
494
|
return _p$;
|
|
428
495
|
}, {
|
|
429
496
|
e: undefined,
|
|
430
497
|
t: undefined
|
|
431
498
|
});
|
|
432
|
-
return _el$
|
|
499
|
+
return _el$25;
|
|
433
500
|
}
|
|
434
501
|
})
|
|
435
502
|
});
|
|
@@ -506,9 +573,9 @@ function DropdownTrigger(props) {
|
|
|
506
573
|
}));
|
|
507
574
|
}
|
|
508
575
|
return [(() => {
|
|
509
|
-
var _el$
|
|
510
|
-
_$use(register, _el$
|
|
511
|
-
_$spread(_el$
|
|
576
|
+
var _el$36 = _$getNextElement(_tmpl$14);
|
|
577
|
+
_$use(register, _el$36);
|
|
578
|
+
_$spread(_el$36, _$mergeProps(rest, {
|
|
512
579
|
get ["aria-controls"]() {
|
|
513
580
|
return context.menuId;
|
|
514
581
|
},
|
|
@@ -539,9 +606,9 @@ function DropdownTrigger(props) {
|
|
|
539
606
|
return iconTitle(local.title, tooltip());
|
|
540
607
|
}
|
|
541
608
|
}), false, true);
|
|
542
|
-
_$insert(_el$
|
|
609
|
+
_$insert(_el$36, () => local.children);
|
|
543
610
|
_$runHydrationEvents();
|
|
544
|
-
return _el$
|
|
611
|
+
return _el$36;
|
|
545
612
|
})(), _$createComponent(Show, {
|
|
546
613
|
get when() {
|
|
547
614
|
return _$memo(() => tooltip() !== false)() && tooltip() !== undefined;
|
|
@@ -575,6 +642,7 @@ function DropdownRoot(props) {
|
|
|
575
642
|
const id = createUniqueId().replace(/[^a-zA-Z0-9_-]/g, "-");
|
|
576
643
|
const menuId = `k2b-dropdown-${id}`;
|
|
577
644
|
const [internalOpen, setInternalOpen] = createSignal(false);
|
|
645
|
+
const [entriesShown, setEntriesShown] = createSignal(!props.lazy);
|
|
578
646
|
let triggerRef;
|
|
579
647
|
let menuRef;
|
|
580
648
|
let triggerRing = true;
|
|
@@ -627,6 +695,8 @@ function DropdownRoot(props) {
|
|
|
627
695
|
const open = (focus = "first") => {
|
|
628
696
|
if (props.disabled || !menuRef || menuRef.matches(":popover-open")) return;
|
|
629
697
|
triggerRing = ringOnReturn(triggerRef);
|
|
698
|
+
// A lazy menu's entries exist before it shows, so it places and focuses them as any other.
|
|
699
|
+
setEntriesShown(true);
|
|
630
700
|
menuRef.showPopover();
|
|
631
701
|
// The toggle event arrives a task later; expose the open state before focus moves into the menu.
|
|
632
702
|
setInternalOpen(true);
|
|
@@ -667,15 +737,8 @@ function DropdownRoot(props) {
|
|
|
667
737
|
};
|
|
668
738
|
const handleMenuKeyDown = event => {
|
|
669
739
|
const items = actionableItems(menuRef);
|
|
670
|
-
|
|
671
|
-
if (event.key === "ArrowDown" || event.key === "ArrowUp") {
|
|
672
|
-
event.preventDefault();
|
|
673
|
-
focusMenuItem(menuRef, current + (event.key === "ArrowDown" ? 1 : -1));
|
|
674
|
-
} else if (focusRowSegment(items, event.key)) {
|
|
740
|
+
if (focusMenuRow(items, event.key) || focusRowSegment(items, event.key)) {
|
|
675
741
|
event.preventDefault();
|
|
676
|
-
} else if (event.key === "Home" || event.key === "End") {
|
|
677
|
-
event.preventDefault();
|
|
678
|
-
focusMenuItem(menuRef, event.key === "Home" ? 0 : -1);
|
|
679
742
|
} else if (event.key === "Escape") {
|
|
680
743
|
event.preventDefault();
|
|
681
744
|
returnFocus(triggerRef, triggerRing);
|
|
@@ -725,47 +788,55 @@ function DropdownRoot(props) {
|
|
|
725
788
|
return _$createComponent(DropdownContext.Provider, {
|
|
726
789
|
value: context,
|
|
727
790
|
get children() {
|
|
728
|
-
var _el$
|
|
729
|
-
_el$
|
|
730
|
-
[_el$
|
|
731
|
-
_el$
|
|
732
|
-
_$insert(_el$
|
|
733
|
-
_el$
|
|
791
|
+
var _el$37 = _$getNextElement(_tmpl$15),
|
|
792
|
+
_el$39 = _el$37.firstChild,
|
|
793
|
+
[_el$40, _co$8] = _$getNextMarker(_el$39.nextSibling),
|
|
794
|
+
_el$38 = _el$40.nextSibling;
|
|
795
|
+
_$insert(_el$37, () => props.children, _el$40, _co$8);
|
|
796
|
+
_el$38.addEventListener("toggle", event => {
|
|
734
797
|
const nextOpen = event.newState === "open";
|
|
735
798
|
const wasOpen = event.oldState === "open";
|
|
736
799
|
setInternalOpen(nextOpen);
|
|
800
|
+
if (nextOpen) setEntriesShown(true);
|
|
737
801
|
if (nextOpen) attachViewportListeners();else detachViewportListeners();
|
|
738
802
|
if (props.open === undefined || props.open !== nextOpen) props.onOpenChange?.(nextOpen);
|
|
739
803
|
if (wasOpen && !nextOpen) props.onClose?.();
|
|
740
804
|
if (!nextOpen && props.open === true) queueMicrotask(() => props.open === true && open(false));
|
|
741
805
|
});
|
|
742
|
-
_el$
|
|
806
|
+
_el$38.$$keydown = handleMenuKeyDown;
|
|
743
807
|
var _ref$ = menuRef;
|
|
744
|
-
typeof _ref$ === "function" ? _$use(_ref$, _el$
|
|
745
|
-
_$setAttribute(_el$
|
|
746
|
-
_$insert(_el$
|
|
747
|
-
get
|
|
748
|
-
return
|
|
808
|
+
typeof _ref$ === "function" ? _$use(_ref$, _el$38) : menuRef = _el$38;
|
|
809
|
+
_$setAttribute(_el$38, "id", menuId);
|
|
810
|
+
_$insert(_el$38, _$createComponent(Show, {
|
|
811
|
+
get when() {
|
|
812
|
+
return entriesShown();
|
|
749
813
|
},
|
|
750
|
-
|
|
814
|
+
get children() {
|
|
815
|
+
return _$createComponent(DropdownItems, {
|
|
816
|
+
get items() {
|
|
817
|
+
return props.items;
|
|
818
|
+
},
|
|
819
|
+
close: close
|
|
820
|
+
});
|
|
821
|
+
}
|
|
751
822
|
}));
|
|
752
823
|
_$effect(_p$ => {
|
|
753
|
-
var _v$
|
|
754
|
-
_v$
|
|
755
|
-
_v$
|
|
756
|
-
_v$
|
|
824
|
+
var _v$14 = `k2b-dropdown ${props.class ?? ""}`,
|
|
825
|
+
_v$15 = props.label ?? messages().dropdownMenu,
|
|
826
|
+
_v$16 = `k2b-dropdown__menu ${props.menuClass ?? ""}`,
|
|
827
|
+
_v$17 = props.width ? {
|
|
757
828
|
"--k2b-dropdown-width": props.width
|
|
758
829
|
} : undefined,
|
|
759
|
-
_v$
|
|
760
|
-
_v$
|
|
761
|
-
_v$
|
|
762
|
-
_v$
|
|
763
|
-
_v$
|
|
764
|
-
_v$
|
|
765
|
-
_p$.o = _$style(_el$
|
|
766
|
-
_v$
|
|
767
|
-
_v$
|
|
768
|
-
_v$
|
|
830
|
+
_v$18 = props.width ? "fixed" : undefined,
|
|
831
|
+
_v$19 = props.variant ?? "default",
|
|
832
|
+
_v$20 = position();
|
|
833
|
+
_v$14 !== _p$.e && _$className(_el$37, _p$.e = _v$14);
|
|
834
|
+
_v$15 !== _p$.t && _$setAttribute(_el$38, "aria-label", _p$.t = _v$15);
|
|
835
|
+
_v$16 !== _p$.a && _$className(_el$38, _p$.a = _v$16);
|
|
836
|
+
_p$.o = _$style(_el$38, _v$17, _p$.o);
|
|
837
|
+
_v$18 !== _p$.i && _$setAttribute(_el$38, "data-width", _p$.i = _v$18);
|
|
838
|
+
_v$19 !== _p$.n && _$setAttribute(_el$38, "data-variant", _p$.n = _v$19);
|
|
839
|
+
_v$20 !== _p$.s && _$setAttribute(_el$38, "data-position", _p$.s = _v$20);
|
|
769
840
|
return _p$;
|
|
770
841
|
}, {
|
|
771
842
|
e: undefined,
|
|
@@ -777,7 +848,7 @@ function DropdownRoot(props) {
|
|
|
777
848
|
s: undefined
|
|
778
849
|
});
|
|
779
850
|
_$runHydrationEvents();
|
|
780
|
-
return _el$
|
|
851
|
+
return _el$37;
|
|
781
852
|
}
|
|
782
853
|
});
|
|
783
854
|
}
|