@k2b/ui 0.44.0 → 0.46.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/browser/actions/Dropdown.js +8 -1
- package/dist/browser/actions/Dropdown.js.map +1 -1
- package/dist/browser/actions/FilterChip.js +11 -5
- package/dist/browser/actions/FilterChip.js.map +1 -1
- package/dist/browser/actions/Tabs.js +3 -4
- package/dist/browser/actions/Tabs.js.map +1 -1
- package/dist/browser/actions/ViewTabs.js +225 -93
- package/dist/browser/actions/ViewTabs.js.map +1 -1
- package/dist/browser/actions/menu-sheet.js +2 -3
- package/dist/browser/actions/menu-sheet.js.map +1 -1
- package/dist/browser/actions/phone-sheet.js +4 -0
- package/dist/browser/actions/phone-sheet.js.map +1 -0
- package/dist/browser/content/DataTable.js +47 -51
- package/dist/browser/content/DataTable.js.map +1 -1
- package/dist/browser/content/FileGrid.js +125 -99
- package/dist/browser/content/FileGrid.js.map +1 -1
- package/dist/browser/feedback/dialog-core.js +5 -1
- package/dist/browser/feedback/dialog-core.js.map +1 -1
- package/dist/browser/feedback/dialog-tone.js +26 -0
- package/dist/browser/feedback/dialog-tone.js.map +1 -0
- package/dist/browser/feedback/index.js.map +1 -1
- package/dist/browser/feedback/prompt-confirm.js +223 -0
- package/dist/browser/feedback/prompt-confirm.js.map +1 -0
- package/dist/browser/feedback/prompts.js +195 -343
- package/dist/browser/feedback/prompts.js.map +1 -1
- package/dist/browser/inputs/ChoiceList.js +45 -17
- package/dist/browser/inputs/ChoiceList.js.map +1 -1
- package/dist/browser/inputs/DatePicker.js +1647 -334
- package/dist/browser/inputs/DatePicker.js.map +1 -1
- package/dist/browser/inputs/TextInput.js +5 -4
- package/dist/browser/inputs/TextInput.js.map +1 -1
- package/dist/browser/inputs/choice.js +36 -9
- package/dist/browser/inputs/choice.js.map +1 -1
- package/dist/browser/inputs/date-input-messages.js +128 -0
- package/dist/browser/inputs/date-input-messages.js.map +1 -0
- package/dist/browser/inputs/date-input-status.js +132 -0
- package/dist/browser/inputs/date-input-status.js.map +1 -0
- package/dist/browser/inputs/date-input.js +334 -0
- package/dist/browser/inputs/date-input.js.map +1 -0
- package/dist/browser/inputs/date-sheet.js +49 -0
- package/dist/browser/inputs/date-sheet.js.map +1 -0
- package/dist/browser/internal/reveal-in-scroller.js +28 -0
- package/dist/browser/internal/reveal-in-scroller.js.map +1 -0
- package/dist/browser/intl/messages.js +6 -0
- package/dist/browser/intl/messages.js.map +1 -1
- package/dist/browser/layout/AppWorkspace.js +556 -528
- package/dist/browser/layout/AppWorkspace.js.map +1 -1
- package/dist/browser/layout/BottomSheet.js +3 -0
- package/dist/browser/layout/BottomSheet.js.map +1 -1
- package/dist/browser/layout/DetailPanel.js +130 -108
- package/dist/browser/layout/DetailPanel.js.map +1 -1
- package/dist/browser/layout/DetailSections.js +1019 -0
- package/dist/browser/layout/DetailSections.js.map +1 -0
- package/dist/browser/layout/DetailsToggle.js +32 -0
- package/dist/browser/layout/DetailsToggle.js.map +1 -0
- package/dist/browser/layout/Discussion.js +3 -0
- package/dist/browser/layout/Discussion.js.map +1 -1
- package/dist/browser/layout/MobileShell.js +116 -94
- package/dist/browser/layout/MobileShell.js.map +1 -1
- package/dist/browser/layout/PageTitle.js +33 -10
- package/dist/browser/layout/PageTitle.js.map +1 -1
- package/dist/browser/layout/PanelDialog.js +167 -132
- package/dist/browser/layout/PanelDialog.js.map +1 -1
- package/dist/browser/layout/Settings.js +175 -139
- package/dist/browser/layout/Settings.js.map +1 -1
- package/dist/browser/layout/SettingsModal.js +2 -4
- package/dist/browser/layout/SettingsModal.js.map +1 -1
- package/dist/browser/layout/app-workspace-controller.js +12 -0
- package/dist/browser/layout/app-workspace-controller.js.map +1 -1
- package/dist/browser/layout/detail-sections-messages.js +123 -0
- package/dist/browser/layout/detail-sections-messages.js.map +1 -0
- package/dist/browser/layout/index.js +2 -0
- package/dist/browser/layout/index.js.map +1 -1
- package/dist/browser/surfaces/Avatar.js +3 -1
- package/dist/browser/surfaces/Avatar.js.map +1 -1
- package/dist/browser/surfaces/AvatarStack.js +95 -61
- package/dist/browser/surfaces/AvatarStack.js.map +1 -1
- package/dist/browser/surfaces/ChangeList.js +77 -0
- package/dist/browser/surfaces/ChangeList.js.map +1 -0
- package/dist/browser/surfaces/StatusBadge.js +47 -14
- package/dist/browser/surfaces/StatusBadge.js.map +1 -1
- package/dist/browser/surfaces/index.js +2 -1
- package/dist/browser/surfaces/index.js.map +1 -1
- package/dist/browser/text-editor/TextEditor.js +26 -8
- package/dist/browser/text-editor/TextEditor.js.map +1 -1
- package/dist/ssr/actions/Dropdown.js +6 -0
- package/dist/ssr/actions/Dropdown.js.map +1 -1
- package/dist/ssr/actions/FilterChip.js +1 -1
- package/dist/ssr/actions/FilterChip.js.map +1 -1
- package/dist/ssr/actions/Tabs.js +3 -4
- package/dist/ssr/actions/Tabs.js.map +1 -1
- package/dist/ssr/actions/ViewTabs.js +144 -37
- package/dist/ssr/actions/ViewTabs.js.map +1 -1
- package/dist/ssr/actions/menu-sheet.js +2 -3
- package/dist/ssr/actions/menu-sheet.js.map +1 -1
- package/dist/ssr/actions/phone-sheet.js +4 -0
- package/dist/ssr/actions/phone-sheet.js.map +1 -0
- package/dist/ssr/content/DataTable.js +1 -2
- package/dist/ssr/content/DataTable.js.map +1 -1
- package/dist/ssr/content/FileGrid.js +36 -22
- package/dist/ssr/content/FileGrid.js.map +1 -1
- package/dist/ssr/feedback/dialog-core.js +5 -1
- package/dist/ssr/feedback/dialog-core.js.map +1 -1
- package/dist/ssr/feedback/dialog-tone.js +26 -0
- package/dist/ssr/feedback/dialog-tone.js.map +1 -0
- package/dist/ssr/feedback/index.js.map +1 -1
- package/dist/ssr/feedback/prompt-confirm.js +123 -0
- package/dist/ssr/feedback/prompt-confirm.js.map +1 -0
- package/dist/ssr/feedback/prompts.js +60 -132
- package/dist/ssr/feedback/prompts.js.map +1 -1
- package/dist/ssr/inputs/ChoiceList.js +29 -9
- package/dist/ssr/inputs/ChoiceList.js.map +1 -1
- package/dist/ssr/inputs/DatePicker.js +1183 -166
- package/dist/ssr/inputs/DatePicker.js.map +1 -1
- package/dist/ssr/inputs/TextInput.js +5 -4
- package/dist/ssr/inputs/TextInput.js.map +1 -1
- package/dist/ssr/inputs/choice.js +36 -9
- package/dist/ssr/inputs/choice.js.map +1 -1
- package/dist/ssr/inputs/date-input-messages.js +128 -0
- package/dist/ssr/inputs/date-input-messages.js.map +1 -0
- package/dist/ssr/inputs/date-input-status.js +132 -0
- package/dist/ssr/inputs/date-input-status.js.map +1 -0
- package/dist/ssr/inputs/date-input.js +334 -0
- package/dist/ssr/inputs/date-input.js.map +1 -0
- package/dist/ssr/inputs/date-sheet.js +44 -0
- package/dist/ssr/inputs/date-sheet.js.map +1 -0
- package/dist/ssr/internal/reveal-in-scroller.js +28 -0
- package/dist/ssr/internal/reveal-in-scroller.js.map +1 -0
- package/dist/ssr/intl/messages.js +6 -0
- package/dist/ssr/intl/messages.js.map +1 -1
- package/dist/ssr/layout/AppWorkspace.js +71 -50
- package/dist/ssr/layout/AppWorkspace.js.map +1 -1
- package/dist/ssr/layout/BottomSheet.js +3 -0
- package/dist/ssr/layout/BottomSheet.js.map +1 -1
- package/dist/ssr/layout/DetailPanel.js +17 -0
- package/dist/ssr/layout/DetailPanel.js.map +1 -1
- package/dist/ssr/layout/DetailSections.js +762 -0
- package/dist/ssr/layout/DetailSections.js.map +1 -0
- package/dist/ssr/layout/DetailsToggle.js +29 -0
- package/dist/ssr/layout/DetailsToggle.js.map +1 -0
- package/dist/ssr/layout/Discussion.js +3 -0
- package/dist/ssr/layout/Discussion.js.map +1 -1
- package/dist/ssr/layout/MobileShell.js +45 -28
- package/dist/ssr/layout/MobileShell.js.map +1 -1
- package/dist/ssr/layout/PageTitle.js +29 -6
- package/dist/ssr/layout/PageTitle.js.map +1 -1
- package/dist/ssr/layout/PanelDialog.js +48 -30
- package/dist/ssr/layout/PanelDialog.js.map +1 -1
- package/dist/ssr/layout/Settings.js +34 -18
- package/dist/ssr/layout/Settings.js.map +1 -1
- package/dist/ssr/layout/SettingsModal.js +2 -4
- package/dist/ssr/layout/SettingsModal.js.map +1 -1
- package/dist/ssr/layout/app-workspace-controller.js +12 -0
- package/dist/ssr/layout/app-workspace-controller.js.map +1 -1
- package/dist/ssr/layout/detail-sections-messages.js +123 -0
- package/dist/ssr/layout/detail-sections-messages.js.map +1 -0
- package/dist/ssr/layout/index.js +2 -0
- package/dist/ssr/layout/index.js.map +1 -1
- package/dist/ssr/surfaces/Avatar.js +3 -1
- package/dist/ssr/surfaces/Avatar.js.map +1 -1
- package/dist/ssr/surfaces/AvatarStack.js +61 -32
- package/dist/ssr/surfaces/AvatarStack.js.map +1 -1
- package/dist/ssr/surfaces/ChangeList.js +37 -0
- package/dist/ssr/surfaces/ChangeList.js.map +1 -0
- package/dist/ssr/surfaces/StatusBadge.js +26 -8
- package/dist/ssr/surfaces/StatusBadge.js.map +1 -1
- package/dist/ssr/surfaces/index.js +2 -1
- package/dist/ssr/surfaces/index.js.map +1 -1
- package/dist/ssr/text-editor/TextEditor.js +26 -8
- package/dist/ssr/text-editor/TextEditor.js.map +1 -1
- package/dist/styles.css +1 -1
- package/dist/types/actions/FilterChip.d.ts +4 -0
- package/dist/types/actions/ViewTabs.d.ts +11 -1
- package/dist/types/actions/menu-sheet.d.ts +1 -3
- package/dist/types/actions/phone-sheet.d.ts +3 -0
- package/dist/types/content/FileGrid.d.ts +6 -0
- package/dist/types/feedback/dialog-tone.d.ts +10 -0
- package/dist/types/feedback/index.d.ts +1 -0
- package/dist/types/feedback/prompt-confirm.d.ts +19 -0
- package/dist/types/feedback/prompts.d.ts +4 -8
- package/dist/types/inputs/ChoiceList.d.ts +7 -3
- package/dist/types/inputs/DatePicker.d.ts +13 -3
- package/dist/types/inputs/TextInput.d.ts +1 -1
- package/dist/types/inputs/choice.d.ts +9 -3
- package/dist/types/inputs/date-input-messages.d.ts +64 -0
- package/dist/types/inputs/date-input-status.d.ts +35 -0
- package/dist/types/inputs/date-input.d.ts +90 -0
- package/dist/types/inputs/date-sheet.d.ts +14 -0
- package/dist/types/internal/reveal-in-scroller.d.ts +6 -0
- package/dist/types/intl/messages.d.ts +3 -0
- package/dist/types/layout/AppWorkspace.d.ts +14 -0
- package/dist/types/layout/BottomSheet.d.ts +3 -0
- package/dist/types/layout/DetailPanel.d.ts +9 -0
- package/dist/types/layout/DetailSections.d.ts +156 -0
- package/dist/types/layout/DetailsToggle.d.ts +13 -0
- package/dist/types/layout/PageTitle.d.ts +7 -0
- package/dist/types/layout/PanelDialog.d.ts +3 -0
- package/dist/types/layout/Settings.d.ts +17 -1
- package/dist/types/layout/detail-sections-messages.d.ts +59 -0
- package/dist/types/layout/index.d.ts +5 -2
- package/dist/types/surfaces/Avatar.d.ts +3 -0
- package/dist/types/surfaces/AvatarStack.d.ts +20 -1
- package/dist/types/surfaces/ChangeList.d.ts +20 -0
- package/dist/types/surfaces/StatusBadge.d.ts +5 -0
- package/dist/types/surfaces/index.d.ts +5 -3
- package/package.json +3 -3
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { template as _$template } from "solid-js/web";
|
|
2
2
|
import { setProperty as _$setProperty } from "solid-js/web";
|
|
3
|
-
import { setAttribute as _$setAttribute } from "solid-js/web";
|
|
4
3
|
import { getNextMarker as _$getNextMarker } from "solid-js/web";
|
|
4
|
+
import { memo as _$memo } from "solid-js/web";
|
|
5
|
+
import { setAttribute as _$setAttribute } from "solid-js/web";
|
|
5
6
|
import { use as _$use } from "solid-js/web";
|
|
6
7
|
import { className as _$className } from "solid-js/web";
|
|
7
8
|
import { effect as _$effect } from "solid-js/web";
|
|
@@ -11,13 +12,15 @@ import { insert as _$insert } from "solid-js/web";
|
|
|
11
12
|
var _tmpl$ = /*#__PURE__*/_$template(`<span class=k2b-view-tabs__count>`),
|
|
12
13
|
_tmpl$2 = /*#__PURE__*/_$template(`<span class="k2b-view-tabs__label k2b-truncate-fade">`),
|
|
13
14
|
_tmpl$3 = /*#__PURE__*/_$template(`<i aria-hidden=true>`),
|
|
14
|
-
_tmpl$4 = /*#__PURE__*/_$template(`<span class=k2b-view-
|
|
15
|
-
_tmpl$5 = /*#__PURE__*/_$template(`<
|
|
16
|
-
_tmpl$6 = /*#__PURE__*/_$template(`<span class=k2b-view-
|
|
17
|
-
_tmpl$7 = /*#__PURE__*/_$template(`<
|
|
18
|
-
_tmpl$8 = /*#__PURE__*/_$template(`<
|
|
19
|
-
_tmpl$9 = /*#__PURE__*/_$template(`<
|
|
20
|
-
_tmpl$0 = /*#__PURE__*/_$template(`<
|
|
15
|
+
_tmpl$4 = /*#__PURE__*/_$template(`<span class=k2b-view-tabs__badge>`),
|
|
16
|
+
_tmpl$5 = /*#__PURE__*/_$template(`<li class=k2b-view-tabs__item><a class=k2b-view-tabs__tab>`),
|
|
17
|
+
_tmpl$6 = /*#__PURE__*/_$template(`<span class=k2b-view-tabs__label>`),
|
|
18
|
+
_tmpl$7 = /*#__PURE__*/_$template(`<span class=k2b-view-tabs__more-count data-level=wide>+<!$><!/>`),
|
|
19
|
+
_tmpl$8 = /*#__PURE__*/_$template(`<span class=k2b-view-tabs__more-count data-level=compact>+<!$><!/>`),
|
|
20
|
+
_tmpl$9 = /*#__PURE__*/_$template(`<span class=k2b-view-tabs__more-count data-level=fit>`),
|
|
21
|
+
_tmpl$0 = /*#__PURE__*/_$template(`<i class="ti ti-chevron-down"aria-hidden=true>`),
|
|
22
|
+
_tmpl$1 = /*#__PURE__*/_$template(`<li class=k2b-view-tabs__more>`),
|
|
23
|
+
_tmpl$10 = /*#__PURE__*/_$template(`<nav><ul class=k2b-view-tabs__list data-scroll-fade-mode=both data-scroll-fade-axis=horizontal><!$><!/><!$><!/><!$><!/></ul><script>`);
|
|
21
24
|
import { createEffect, createMemo, createSignal, For, on, onCleanup, onMount, Show } from "solid-js";
|
|
22
25
|
import { useUiMessages } from "../intl/messages";
|
|
23
26
|
import { createScrollFade, scrollFadeEdges } from "../layout/scroll-fade";
|
|
@@ -26,10 +29,14 @@ import Dropdown from "./Dropdown";
|
|
|
26
29
|
export function viewTabsLayout(items, current, max = 5) {
|
|
27
30
|
// At least one slot keeps the current view visible, including for an invalid limit.
|
|
28
31
|
const limit = Number.isFinite(max) ? Math.max(1, Math.floor(max)) : 5;
|
|
32
|
+
// Pinned views never overflow, so they take no slot.
|
|
33
|
+
const flowing = items.flatMap((item, index) => item.pinned ? [] : [index]);
|
|
34
|
+
const pinned = items.flatMap((item, index) => item.pinned ? [index] : []);
|
|
29
35
|
const currentIndex = items.findIndex(item => item.id === current);
|
|
36
|
+
const currentPosition = flowing.indexOf(currentIndex);
|
|
30
37
|
const visible = size => {
|
|
31
|
-
const indices =
|
|
32
|
-
if (
|
|
38
|
+
const indices = flowing.slice(0, size);
|
|
39
|
+
if (currentPosition >= size) indices[indices.length - 1] = currentIndex;
|
|
33
40
|
return indices;
|
|
34
41
|
};
|
|
35
42
|
const wide = visible(limit);
|
|
@@ -37,14 +44,50 @@ export function viewTabsLayout(items, current, max = 5) {
|
|
|
37
44
|
return {
|
|
38
45
|
wide,
|
|
39
46
|
compact,
|
|
40
|
-
|
|
41
|
-
|
|
47
|
+
pinned,
|
|
48
|
+
wideHidden: flowing.length - wide.length,
|
|
49
|
+
compactHidden: flowing.length - compact.length
|
|
42
50
|
};
|
|
43
51
|
}
|
|
44
52
|
|
|
45
|
-
/**
|
|
53
|
+
/**
|
|
54
|
+
* Self-contained: the server script embeds this before hydration. A fitting strip first keeps only the views that fit
|
|
55
|
+
* its room and counts the rest in More; then the open or focused view scrolls into the strip.
|
|
56
|
+
*/
|
|
46
57
|
function settleViewTabs(list, edges, focused) {
|
|
47
58
|
if (!(list instanceof HTMLElement)) return;
|
|
59
|
+
const more = list.querySelector(":scope > .k2b-view-tabs__more");
|
|
60
|
+
const fitCount = more?.querySelector('.k2b-view-tabs__more-count[data-level="fit"]');
|
|
61
|
+
const flowing = Array.from(list.querySelectorAll(":scope > .k2b-view-tabs__item:not([data-pinned])"));
|
|
62
|
+
for (const item of flowing) item.removeAttribute("data-fit-hidden");
|
|
63
|
+
more?.removeAttribute("data-fit");
|
|
64
|
+
// The shown entries against the strip's inner room, whatever its scroll and padding.
|
|
65
|
+
const overflows = () => {
|
|
66
|
+
const boxes = Array.from(list.children).filter(child => child instanceof HTMLElement && child.tagName === "LI" && child.getClientRects().length > 0).map(child => child.getBoundingClientRect());
|
|
67
|
+
if (boxes.length === 0) return false;
|
|
68
|
+
const style = getComputedStyle(list);
|
|
69
|
+
const room = list.clientWidth - (parseFloat(style.paddingLeft) || 0) - (parseFloat(style.paddingRight) || 0);
|
|
70
|
+
return Math.max(...boxes.map(box => box.right)) - Math.min(...boxes.map(box => box.left)) > room + 0.5;
|
|
71
|
+
};
|
|
72
|
+
// The phone head row keeps its scrolling strip: its CSS turns fitting off.
|
|
73
|
+
const fits = list.hasAttribute("data-fit-room") && getComputedStyle(list).getPropertyValue("--k2b-view-tabs-fit").trim() !== "none";
|
|
74
|
+
if (fits && more && fitCount && overflows()) {
|
|
75
|
+
// Count from the level on screen: the compact strip already keeps fewer views than the wide one.
|
|
76
|
+
const compact = more.querySelector('.k2b-view-tabs__more-count[data-level="compact"]');
|
|
77
|
+
const compactShown = Boolean(compact && getComputedStyle(compact).display !== "none");
|
|
78
|
+
const behind = Number(compactShown ? more.dataset.behindCompact : more.dataset.behindWide) || 0;
|
|
79
|
+
// The last views on screen leave first; the open view stays.
|
|
80
|
+
const candidates = flowing.filter(item => item.getClientRects().length > 0 && !item.querySelector("[aria-current=page]")).reverse();
|
|
81
|
+
more.setAttribute("data-fit", "");
|
|
82
|
+
let hidden = 0;
|
|
83
|
+
for (const item of candidates) {
|
|
84
|
+
item.setAttribute("data-fit-hidden", "");
|
|
85
|
+
hidden += 1;
|
|
86
|
+
fitCount.textContent = `+${behind + hidden}`;
|
|
87
|
+
if (!overflows()) break;
|
|
88
|
+
}
|
|
89
|
+
if (hidden === 0) more.removeAttribute("data-fit");
|
|
90
|
+
}
|
|
48
91
|
const current = focused ?? list.querySelector(".k2b-view-tabs__tab[aria-current=page]");
|
|
49
92
|
if (current && current.getClientRects().length > 0 && list.scrollWidth - list.clientWidth > 1) {
|
|
50
93
|
const bounds = list.getBoundingClientRect();
|
|
@@ -69,9 +112,20 @@ function settleViewTabs(list, edges, focused) {
|
|
|
69
112
|
const fade = edges(list);
|
|
70
113
|
if (fade) list.setAttribute("data-scroll-fade", fade);else list.removeAttribute("data-scroll-fade");
|
|
71
114
|
}
|
|
72
|
-
/**
|
|
115
|
+
/**
|
|
116
|
+
* Also embedded, so it must not close over module state.
|
|
117
|
+
*
|
|
118
|
+
* A fitting strip converges by construction. It fits again only when the strip renders, web fonts finish loading, or
|
|
119
|
+
* a notification finds another width of the head lead or of an entry that the last fit left shown. A fit only shows
|
|
120
|
+
* and hides entries: the lead is an inline-size container that takes no width from the strip, and every entry keeps
|
|
121
|
+
* its own width (`flex: none`), so the notifications a fit causes find the widths it ended with and stop there.
|
|
122
|
+
*/
|
|
73
123
|
function watchViewTabs(list, settle, edges) {
|
|
74
124
|
if (!(list instanceof HTMLElement)) return;
|
|
125
|
+
const fits = list.hasAttribute("data-fit-room");
|
|
126
|
+
const roomOf = () => list.closest(".k2b-app-workspace__head-lead");
|
|
127
|
+
// What a fit depends on: the lead's width and each shown entry's width, which fonts, icons and labels change.
|
|
128
|
+
const measured = () => [roomOf()?.clientWidth ?? -1, ...Array.from(list.children, child => child.getBoundingClientRect().width)].join(" ");
|
|
75
129
|
// A DOM property survives hydration: one observer and focus listener per reused list.
|
|
76
130
|
let watch = list.__k2bViewTabsWatch;
|
|
77
131
|
if (!watch) {
|
|
@@ -82,29 +136,66 @@ function watchViewTabs(list, settle, edges) {
|
|
|
82
136
|
settle(list, edges, event.target);
|
|
83
137
|
}
|
|
84
138
|
};
|
|
139
|
+
const settleNow = () => {
|
|
140
|
+
const focused = document.activeElement;
|
|
141
|
+
if (watch?.preferCurrent === false && focused instanceof HTMLElement && list.contains(focused) && focused.matches(".k2b-view-tabs__tab:focus-visible")) settle(list, edges, focused);else settle(list, edges);
|
|
142
|
+
};
|
|
143
|
+
// Head actions parse after the views; settle again after their layout, before paint, and on later resizes.
|
|
144
|
+
const connect = () => {
|
|
145
|
+
if (!watch) return;
|
|
146
|
+
watch.resize.disconnect();
|
|
147
|
+
watch.resize.observe(list);
|
|
148
|
+
for (const child of Array.from(list.children)) watch.resize.observe(child);
|
|
149
|
+
const room = roomOf();
|
|
150
|
+
if (fits && room) watch.resize.observe(room);
|
|
151
|
+
};
|
|
152
|
+
// Fitting resizes the strip and possibly the head, which other observers may watch. Inside a ResizeObserver
|
|
153
|
+
// callback that would leave their notifications undelivered, so a fit runs in the next frame, still before it paints.
|
|
154
|
+
const schedule = () => {
|
|
155
|
+
if (!watch || watch.frame) return;
|
|
156
|
+
watch.frame = requestAnimationFrame(() => {
|
|
157
|
+
if (!watch) return;
|
|
158
|
+
watch.frame = 0;
|
|
159
|
+
if (!list.isConnected) return;
|
|
160
|
+
settleNow();
|
|
161
|
+
watch.room = measured();
|
|
162
|
+
});
|
|
163
|
+
};
|
|
85
164
|
watch = {
|
|
86
165
|
resize: new ResizeObserver(() => {
|
|
87
|
-
|
|
88
|
-
if (
|
|
166
|
+
// A scrolling strip only scrolls and settles at once.
|
|
167
|
+
if (!fits) return settleNow();
|
|
168
|
+
// Heights follow the fit, and hidden entries measure 0 by its own doing: only another measure counts.
|
|
169
|
+
if (watch && measured() !== watch.room) watch.schedule();
|
|
89
170
|
}),
|
|
90
171
|
focus,
|
|
91
|
-
preferCurrent: true
|
|
172
|
+
preferCurrent: true,
|
|
173
|
+
connect,
|
|
174
|
+
schedule,
|
|
175
|
+
frame: 0,
|
|
176
|
+
room: "",
|
|
177
|
+
fonts: () => watch?.schedule()
|
|
92
178
|
};
|
|
93
179
|
Object.defineProperty(list, "__k2bViewTabsWatch", {
|
|
94
180
|
value: watch,
|
|
95
181
|
configurable: true
|
|
96
182
|
});
|
|
97
183
|
list.addEventListener("focusin", focus);
|
|
184
|
+
// A first visit can paint before the web fonts load; the server frame and the client then fit the same metrics.
|
|
185
|
+
if (fits && document.fonts) {
|
|
186
|
+
document.fonts.addEventListener("loadingdone", watch.fonts);
|
|
187
|
+
void document.fonts.ready.then(watch.fonts);
|
|
188
|
+
}
|
|
98
189
|
}
|
|
99
190
|
watch.preferCurrent = true;
|
|
100
|
-
|
|
101
|
-
resize
|
|
102
|
-
} = watch;
|
|
103
|
-
resize.disconnect();
|
|
104
|
-
// Head actions parse after the views; settle again after their layout, before paint, and on later resizes.
|
|
105
|
-
resize.observe(list);
|
|
106
|
-
for (const child of Array.from(list.children)) resize.observe(child);
|
|
191
|
+
watch.connect();
|
|
107
192
|
settle(list, edges);
|
|
193
|
+
if (fits) {
|
|
194
|
+
watch.room = measured();
|
|
195
|
+
// The head's actions parse after the views. A frame's animation callbacks run before its first layout and
|
|
196
|
+
// paint, so this fit also counts their room in the first frame.
|
|
197
|
+
watch.schedule();
|
|
198
|
+
}
|
|
108
199
|
return watch;
|
|
109
200
|
}
|
|
110
201
|
const VIEW_TABS_SCRIPT = `(${watchViewTabs})(document.currentScript&&document.currentScript.previousElementSibling,${settleViewTabs},${scrollFadeEdges})`;
|
|
@@ -131,6 +222,8 @@ export function ViewTabs(props) {
|
|
|
131
222
|
onCleanup(() => {
|
|
132
223
|
disposed = true;
|
|
133
224
|
watch?.resize.disconnect();
|
|
225
|
+
if (watch?.frame) cancelAnimationFrame(watch.frame);
|
|
226
|
+
if (watch) document.fonts?.removeEventListener("loadingdone", watch.fonts);
|
|
134
227
|
if (list && watch) {
|
|
135
228
|
list.removeEventListener("focusin", watch.focus);
|
|
136
229
|
Reflect.deleteProperty(list, "__k2bViewTabsWatch");
|
|
@@ -138,14 +231,17 @@ export function ViewTabs(props) {
|
|
|
138
231
|
});
|
|
139
232
|
});
|
|
140
233
|
// User effects run after Solid's render effects, including For and aria-current, in the same task.
|
|
141
|
-
|
|
234
|
+
// What the strip shows: another open view, view, label, count or badge can change what fits. Equal content in a new
|
|
235
|
+
// array settles nothing again.
|
|
236
|
+
const shown = createMemo(() => [props.current ?? "", layout().wide.join(","), ...props.items.map(item => `${item.id}\u0000${item.label}\u0000${item.count ?? ""}\u0000${item.badge ?? ""}`)].join("\u0001"));
|
|
237
|
+
createEffect(on(shown, () => watchViewTabs(list ?? null, settleViewTabs, scrollFadeEdges), {
|
|
142
238
|
defer: true
|
|
143
239
|
}));
|
|
144
240
|
const [open, setOpen] = createSignal(false);
|
|
145
241
|
const [menuItems, setMenuItems] = createSignal([]);
|
|
146
242
|
const onOpenChange = next => {
|
|
147
243
|
if (next) {
|
|
148
|
-
setMenuItems(props.items.filter((item, index) => item.id !== props.current && (!layout().wide.includes(index) || stripItems.get(index)?.getClientRects().length === 0)).map(item => ({
|
|
244
|
+
setMenuItems(props.items.filter((item, index) => !item.pinned && item.id !== props.current && (!layout().wide.includes(index) || stripItems.get(index)?.getClientRects().length === 0)).map(item => ({
|
|
149
245
|
href: item.href,
|
|
150
246
|
label: item.label,
|
|
151
247
|
icon: item.icon,
|
|
@@ -180,56 +276,71 @@ export function ViewTabs(props) {
|
|
|
180
276
|
_$insert(_el$3, () => item.count);
|
|
181
277
|
return _el$3;
|
|
182
278
|
}
|
|
279
|
+
}), _$createComponent(Show, {
|
|
280
|
+
get when() {
|
|
281
|
+
return item.badge;
|
|
282
|
+
},
|
|
283
|
+
children: badge => (() => {
|
|
284
|
+
var _el$5 = _$getNextElement(_tmpl$4);
|
|
285
|
+
_$insert(_el$5, badge);
|
|
286
|
+
return _el$5;
|
|
287
|
+
})()
|
|
183
288
|
})];
|
|
289
|
+
const stripItem = index => {
|
|
290
|
+
const item = () => props.items[index];
|
|
291
|
+
onCleanup(() => stripItems.delete(index));
|
|
292
|
+
return (() => {
|
|
293
|
+
var _el$6 = _$getNextElement(_tmpl$5),
|
|
294
|
+
_el$7 = _el$6.firstChild;
|
|
295
|
+
_$use(element => stripItems.set(index, element), _el$6);
|
|
296
|
+
_$insert(_el$7, () => tabContent(item()));
|
|
297
|
+
_$effect(_p$ => {
|
|
298
|
+
var _v$ = item().id,
|
|
299
|
+
_v$2 = item().pinned ? "" : undefined,
|
|
300
|
+
_v$3 = !item().pinned && !layout().compact.includes(index) ? "" : undefined,
|
|
301
|
+
_v$4 = item().href,
|
|
302
|
+
_v$5 = item().id === props.current ? "page" : undefined;
|
|
303
|
+
_v$ !== _p$.e && _$setAttribute(_el$6, "data-view-tab", _p$.e = _v$);
|
|
304
|
+
_v$2 !== _p$.t && _$setAttribute(_el$6, "data-pinned", _p$.t = _v$2);
|
|
305
|
+
_v$3 !== _p$.a && _$setAttribute(_el$6, "data-compact-hidden", _p$.a = _v$3);
|
|
306
|
+
_v$4 !== _p$.o && _$setAttribute(_el$7, "href", _p$.o = _v$4);
|
|
307
|
+
_v$5 !== _p$.i && _$setAttribute(_el$7, "aria-current", _p$.i = _v$5);
|
|
308
|
+
return _p$;
|
|
309
|
+
}, {
|
|
310
|
+
e: undefined,
|
|
311
|
+
t: undefined,
|
|
312
|
+
a: undefined,
|
|
313
|
+
o: undefined,
|
|
314
|
+
i: undefined
|
|
315
|
+
});
|
|
316
|
+
return _el$6;
|
|
317
|
+
})();
|
|
318
|
+
};
|
|
184
319
|
return (() => {
|
|
185
|
-
var _el$
|
|
186
|
-
_el$
|
|
187
|
-
_el$
|
|
188
|
-
[_el$
|
|
189
|
-
_el$
|
|
190
|
-
[_el$
|
|
191
|
-
_el$
|
|
320
|
+
var _el$8 = _$getNextElement(_tmpl$10),
|
|
321
|
+
_el$9 = _el$8.firstChild,
|
|
322
|
+
_el$20 = _el$9.firstChild,
|
|
323
|
+
[_el$21, _co$3] = _$getNextMarker(_el$20.nextSibling),
|
|
324
|
+
_el$22 = _el$21.nextSibling,
|
|
325
|
+
[_el$23, _co$4] = _$getNextMarker(_el$22.nextSibling),
|
|
326
|
+
_el$24 = _el$23.nextSibling,
|
|
327
|
+
[_el$25, _co$5] = _$getNextMarker(_el$24.nextSibling),
|
|
328
|
+
_el$26 = _el$9.nextSibling;
|
|
192
329
|
var _ref$ = list;
|
|
193
|
-
typeof _ref$ === "function" ? _$use(_ref$, _el$
|
|
194
|
-
_$insert(_el$
|
|
330
|
+
typeof _ref$ === "function" ? _$use(_ref$, _el$9) : list = _el$9;
|
|
331
|
+
_$insert(_el$9, _$createComponent(For, {
|
|
195
332
|
get each() {
|
|
196
333
|
return layout().wide;
|
|
197
334
|
},
|
|
198
|
-
children:
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
return (() => {
|
|
202
|
-
var _el$21 = _$getNextElement(_tmpl$0),
|
|
203
|
-
_el$22 = _el$21.firstChild;
|
|
204
|
-
_$use(element => stripItems.set(index, element), _el$21);
|
|
205
|
-
_$insert(_el$22, () => tabContent(item()));
|
|
206
|
-
_$effect(_p$ => {
|
|
207
|
-
var _v$3 = item().id,
|
|
208
|
-
_v$4 = !layout().compact.includes(index) ? "" : undefined,
|
|
209
|
-
_v$5 = item().href,
|
|
210
|
-
_v$6 = item().id === props.current ? "page" : undefined;
|
|
211
|
-
_v$3 !== _p$.e && _$setAttribute(_el$21, "data-view-tab", _p$.e = _v$3);
|
|
212
|
-
_v$4 !== _p$.t && _$setAttribute(_el$21, "data-compact-hidden", _p$.t = _v$4);
|
|
213
|
-
_v$5 !== _p$.a && _$setAttribute(_el$22, "href", _p$.a = _v$5);
|
|
214
|
-
_v$6 !== _p$.o && _$setAttribute(_el$22, "aria-current", _p$.o = _v$6);
|
|
215
|
-
return _p$;
|
|
216
|
-
}, {
|
|
217
|
-
e: undefined,
|
|
218
|
-
t: undefined,
|
|
219
|
-
a: undefined,
|
|
220
|
-
o: undefined
|
|
221
|
-
});
|
|
222
|
-
return _el$21;
|
|
223
|
-
})();
|
|
224
|
-
}
|
|
225
|
-
}), _el$17, _co$3);
|
|
226
|
-
_$insert(_el$6, _$createComponent(Show, {
|
|
335
|
+
children: stripItem
|
|
336
|
+
}), _el$21, _co$3);
|
|
337
|
+
_$insert(_el$9, _$createComponent(Show, {
|
|
227
338
|
get when() {
|
|
228
|
-
return layout().compactHidden + layout().wideHidden > 0;
|
|
339
|
+
return layout().compactHidden + layout().wideHidden > 0 || props.fit && layout().wide.length > 1;
|
|
229
340
|
},
|
|
230
341
|
get children() {
|
|
231
|
-
var _el$
|
|
232
|
-
_$insert(_el$
|
|
342
|
+
var _el$0 = _$getNextElement(_tmpl$1);
|
|
343
|
+
_$insert(_el$0, _$createComponent(Dropdown.Root, {
|
|
233
344
|
get items() {
|
|
234
345
|
return menuItems();
|
|
235
346
|
},
|
|
@@ -249,54 +360,75 @@ export function ViewTabs(props) {
|
|
|
249
360
|
},
|
|
250
361
|
get children() {
|
|
251
362
|
return [(() => {
|
|
252
|
-
var _el$
|
|
253
|
-
_$insert(_el$
|
|
254
|
-
return _el$
|
|
363
|
+
var _el$1 = _$getNextElement(_tmpl$6);
|
|
364
|
+
_$insert(_el$1, () => messages().more);
|
|
365
|
+
return _el$1;
|
|
255
366
|
})(), _$createComponent(Show, {
|
|
256
367
|
get when() {
|
|
257
368
|
return layout().wideHidden > 0;
|
|
258
369
|
},
|
|
259
370
|
get children() {
|
|
260
|
-
var _el$
|
|
261
|
-
_el$
|
|
262
|
-
_el$
|
|
263
|
-
[_el$
|
|
264
|
-
_$insert(_el$
|
|
265
|
-
return _el$
|
|
371
|
+
var _el$10 = _$getNextElement(_tmpl$7),
|
|
372
|
+
_el$11 = _el$10.firstChild,
|
|
373
|
+
_el$12 = _el$11.nextSibling,
|
|
374
|
+
[_el$13, _co$] = _$getNextMarker(_el$12.nextSibling);
|
|
375
|
+
_$insert(_el$10, () => layout().wideHidden, _el$13, _co$);
|
|
376
|
+
return _el$10;
|
|
266
377
|
}
|
|
267
378
|
}), _$createComponent(Show, {
|
|
268
379
|
get when() {
|
|
269
380
|
return layout().compactHidden > 0;
|
|
270
381
|
},
|
|
271
382
|
get children() {
|
|
272
|
-
var _el$
|
|
273
|
-
_el$
|
|
274
|
-
_el$
|
|
275
|
-
[_el$
|
|
276
|
-
_$insert(_el$
|
|
277
|
-
return _el$
|
|
383
|
+
var _el$14 = _$getNextElement(_tmpl$8),
|
|
384
|
+
_el$15 = _el$14.firstChild,
|
|
385
|
+
_el$16 = _el$15.nextSibling,
|
|
386
|
+
[_el$17, _co$2] = _$getNextMarker(_el$16.nextSibling);
|
|
387
|
+
_$insert(_el$14, () => layout().compactHidden, _el$17, _co$2);
|
|
388
|
+
return _el$14;
|
|
278
389
|
}
|
|
279
|
-
}), _$getNextElement(_tmpl$
|
|
390
|
+
}), _$getNextElement(_tmpl$9), _$getNextElement(_tmpl$0)];
|
|
280
391
|
}
|
|
281
392
|
});
|
|
282
393
|
}
|
|
283
394
|
}));
|
|
284
|
-
_$effect(
|
|
285
|
-
|
|
395
|
+
_$effect(_p$ => {
|
|
396
|
+
var _v$6 = layout().wideHidden > 0 ? "" : undefined,
|
|
397
|
+
_v$7 = layout().wideHidden,
|
|
398
|
+
_v$8 = layout().compactHidden;
|
|
399
|
+
_v$6 !== _p$.e && _$setAttribute(_el$0, "data-wide", _p$.e = _v$6);
|
|
400
|
+
_v$7 !== _p$.t && _$setAttribute(_el$0, "data-behind-wide", _p$.t = _v$7);
|
|
401
|
+
_v$8 !== _p$.a && _$setAttribute(_el$0, "data-behind-compact", _p$.a = _v$8);
|
|
402
|
+
return _p$;
|
|
403
|
+
}, {
|
|
404
|
+
e: undefined,
|
|
405
|
+
t: undefined,
|
|
406
|
+
a: undefined
|
|
407
|
+
});
|
|
408
|
+
return _el$0;
|
|
286
409
|
}
|
|
287
|
-
}), _el$
|
|
288
|
-
_$
|
|
410
|
+
}), _el$23, _co$4);
|
|
411
|
+
_$insert(_el$9, _$createComponent(For, {
|
|
412
|
+
get each() {
|
|
413
|
+
return layout().pinned;
|
|
414
|
+
},
|
|
415
|
+
children: stripItem
|
|
416
|
+
}), _el$25, _co$5);
|
|
417
|
+
_$setProperty(_el$26, "innerHTML", VIEW_TABS_SCRIPT);
|
|
289
418
|
_$effect(_p$ => {
|
|
290
|
-
var _v$ = `k2b-view-tabs ${props.class ?? ""}`,
|
|
291
|
-
_v$
|
|
292
|
-
|
|
293
|
-
_v$
|
|
419
|
+
var _v$9 = `k2b-view-tabs ${props.class ?? ""}`,
|
|
420
|
+
_v$0 = props.label,
|
|
421
|
+
_v$1 = props.fit ? "" : undefined;
|
|
422
|
+
_v$9 !== _p$.e && _$className(_el$8, _p$.e = _v$9);
|
|
423
|
+
_v$0 !== _p$.t && _$setAttribute(_el$8, "aria-label", _p$.t = _v$0);
|
|
424
|
+
_v$1 !== _p$.a && _$setAttribute(_el$9, "data-fit-room", _p$.a = _v$1);
|
|
294
425
|
return _p$;
|
|
295
426
|
}, {
|
|
296
427
|
e: undefined,
|
|
297
|
-
t: undefined
|
|
428
|
+
t: undefined,
|
|
429
|
+
a: undefined
|
|
298
430
|
});
|
|
299
|
-
return _el$
|
|
431
|
+
return _el$8;
|
|
300
432
|
})();
|
|
301
433
|
}
|
|
302
434
|
//# sourceMappingURL=ViewTabs.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":[],"sources":["actions/ViewTabs.tsx"],"sourcesContent":["import { createEffect, createMemo, createSignal, For, type JSX, on, onCleanup, onMount, Show } from \"solid-js\";\nimport { useUiMessages } from \"../intl/messages\";\nimport { createScrollFade, scrollFadeEdges } from \"../layout/scroll-fade\";\nimport Dropdown, { type DropdownItem } from \"./Dropdown\";\n\nexport type ViewTab = { id: string; label: string; href: string; icon?: string; count?: number | string };\nexport type ViewTabsProps = {\n /** Accessible name of the navigation landmark, e.g. \"Views\". */\n label: string;\n items: readonly ViewTab[];\n /** Id of the open view; the server reads it from `?view=`. Unknown ids select nothing. */\n current: string | undefined;\n /** Tabs shown before More (default 5). */\n max?: number;\n class?: string;\n};\n\n/** Two deterministic strip levels; only opening the menu reads CSS visibility. */\nexport function viewTabsLayout(items: readonly ViewTab[], current: string | undefined, max = 5) {\n // At least one slot keeps the current view visible, including for an invalid limit.\n const limit = Number.isFinite(max) ? Math.max(1, Math.floor(max)) : 5;\n const currentIndex = items.findIndex((item) => item.id === current);\n const visible = (size: number) => {\n const indices = items.slice(0, size).map((_, index) => index);\n if (currentIndex >= size) indices[indices.length - 1] = currentIndex;\n return indices;\n };\n const wide = visible(limit);\n const compact = visible(Math.min(limit, 3));\n return { wide, compact, wideHidden: items.length - wide.length, compactHidden: items.length - compact.length };\n}\n\n/** Self-contained: the server script embeds this before hydration. */\nfunction settleViewTabs(list: Element | null, edges: (element: HTMLElement) => string | undefined, focused?: HTMLElement) {\n if (!(list instanceof HTMLElement)) return;\n const current = focused ?? list.querySelector(\".k2b-view-tabs__tab[aria-current=page]\");\n if (current && current.getClientRects().length > 0 && list.scrollWidth - list.clientWidth > 1) {\n const bounds = list.getBoundingClientRect();\n const item = current.getBoundingClientRect();\n const fade = edges(list);\n const style = getComputedStyle(list);\n const left = fade === \"top\" || fade === \"both\" ? parseFloat(style.scrollPaddingLeft) || 0 : 0;\n const right = fade === \"bottom\" || fade === \"both\" ? parseFloat(style.scrollPaddingRight) || 0 : 0;\n if (item.left < bounds.left + left || item.right > bounds.right - right) {\n let offset = item.left - bounds.left - (bounds.width - item.width) / 2;\n if (focused) {\n // Reserve padding at the destination edge; native clamping drops it when that end is reached.\n offset =\n item.left < bounds.left + left\n ? item.left - bounds.left - (parseFloat(style.scrollPaddingLeft) || 0)\n : item.right - bounds.right + (parseFloat(style.scrollPaddingRight) || 0);\n }\n // Only the strip moves: scrollIntoView would also scroll the page. Instant keeps the first frame free of animation.\n list.scrollTo({ left: list.scrollLeft + offset, behavior: \"instant\" });\n }\n }\n const fade = edges(list);\n if (fade) list.setAttribute(\"data-scroll-fade\", fade);\n else list.removeAttribute(\"data-scroll-fade\");\n}\n\ntype WatchedViewTabs = HTMLElement & {\n __k2bViewTabsWatch?: { resize: ResizeObserver; focus: (event: FocusEvent) => void; preferCurrent: boolean };\n};\n\n/** Also embedded, so it must not close over module state. */\nfunction watchViewTabs(list: WatchedViewTabs | null, settle: typeof settleViewTabs, edges: (element: HTMLElement) => string | undefined) {\n if (!(list instanceof HTMLElement)) return;\n // A DOM property survives hydration: one observer and focus listener per reused list.\n let watch = list.__k2bViewTabsWatch;\n if (!watch) {\n const focus = (event: FocusEvent) => {\n // Pointer focus must not move the target under the pointer.\n if (watch && event.target instanceof HTMLElement && event.target.matches(\".k2b-view-tabs__tab:focus-visible\")) {\n watch.preferCurrent = false;\n settle(list, edges, event.target);\n }\n };\n watch = {\n resize: new ResizeObserver(() => {\n const focused = document.activeElement;\n if (\n watch?.preferCurrent === false &&\n focused instanceof HTMLElement &&\n list.contains(focused) &&\n focused.matches(\".k2b-view-tabs__tab:focus-visible\")\n )\n settle(list, edges, focused);\n else settle(list, edges);\n }),\n focus,\n preferCurrent: true,\n };\n Object.defineProperty(list, \"__k2bViewTabsWatch\", { value: watch, configurable: true });\n list.addEventListener(\"focusin\", focus);\n }\n watch.preferCurrent = true;\n const { resize } = watch;\n resize.disconnect();\n // Head actions parse after the views; settle again after their layout, before paint, and on later resizes.\n resize.observe(list);\n for (const child of Array.from(list.children)) resize.observe(child);\n settle(list, edges);\n return watch;\n}\nconst VIEW_TABS_SCRIPT = `(${watchViewTabs})(document.currentScript&&document.currentScript.previousElementSibling,${settleViewTabs},${scrollFadeEdges})`;\n\n/**\n * URL-backed object views. Every view is an ordinary document link, in the strip and under More, so reload, back,\n * and forward keep the view the URL names.\n */\nexport function ViewTabs(props: ViewTabsProps): JSX.Element {\n const messages = useUiMessages();\n const layout = createMemo(() => viewTabsLayout(props.items, props.current, props.max));\n const stripItems = new Map<number, HTMLLIElement>();\n let list: HTMLUListElement | undefined;\n createScrollFade(\n () => list,\n () => true,\n );\n onMount(() => {\n const watch = watchViewTabs(list ?? null, settleViewTabs, scrollFadeEdges);\n let disposed = false;\n // Later mount effects can invalidate WebKit's scroll layout after this\n // initial settle. Finish once the mount task is complete, before its first\n // frame; ResizeObserver alone runs too late for that frame.\n queueMicrotask(() => {\n if (!disposed && watch?.preferCurrent) settleViewTabs(list ?? null, scrollFadeEdges);\n });\n onCleanup(() => {\n disposed = true;\n watch?.resize.disconnect();\n if (list && watch) {\n list.removeEventListener(\"focusin\", watch.focus);\n Reflect.deleteProperty(list, \"__k2bViewTabsWatch\");\n }\n });\n });\n // User effects run after Solid's render effects, including For and aria-current, in the same task.\n createEffect(\n on(\n () => props.current,\n () => watchViewTabs(list ?? null, settleViewTabs, scrollFadeEdges),\n { defer: true },\n ),\n );\n const [open, setOpen] = createSignal(false);\n const [menuItems, setMenuItems] = createSignal<DropdownItem[]>([]);\n const onOpenChange = (next: boolean) => {\n if (next) {\n setMenuItems(\n props.items\n .filter(\n (item, index) =>\n item.id !== props.current && (!layout().wide.includes(index) || stripItems.get(index)?.getClientRects().length === 0),\n )\n .map((item) => ({\n href: item.href,\n label: item.label,\n icon: item.icon,\n trailing: item.count !== undefined ? <span class=\"k2b-view-tabs__count\">{item.count}</span> : undefined,\n })),\n );\n }\n setOpen(next);\n };\n const tabContent = (item: ViewTab) => (\n <>\n <Show when={item.icon}>{(icon) => <i class={icon()} aria-hidden=\"true\" />}</Show>\n <span class=\"k2b-view-tabs__label k2b-truncate-fade\">{item.label}</span>\n <Show when={item.count !== undefined}>\n <span class=\"k2b-view-tabs__count\">{item.count}</span>\n </Show>\n </>\n );\n return (\n <nav class={`k2b-view-tabs ${props.class ?? \"\"}`} aria-label={props.label}>\n <ul ref={list} class=\"k2b-view-tabs__list\" data-scroll-fade-mode=\"both\" data-scroll-fade-axis=\"horizontal\">\n <For each={layout().wide}>\n {(index) => {\n const item = () => props.items[index]!;\n onCleanup(() => stripItems.delete(index));\n return (\n <li\n ref={(element) => stripItems.set(index, element)}\n class=\"k2b-view-tabs__item\"\n data-view-tab={item().id}\n data-compact-hidden={!layout().compact.includes(index) ? \"\" : undefined}\n >\n <a class=\"k2b-view-tabs__tab\" href={item().href} aria-current={item().id === props.current ? \"page\" : undefined}>\n {tabContent(item())}\n </a>\n </li>\n );\n }}\n </For>\n <Show when={layout().compactHidden + layout().wideHidden > 0}>\n <li class=\"k2b-view-tabs__more\" data-wide={layout().wideHidden > 0 ? \"\" : undefined}>\n <Dropdown.Root items={menuItems()} open={open()} onOpenChange={onOpenChange} label={messages().moreViews}>\n <Dropdown.Trigger appearance=\"plain\" class=\"k2b-view-tabs__tab k2b-view-tabs__more-trigger\" label={messages().moreViews}>\n <span class=\"k2b-view-tabs__label\">{messages().more}</span>\n <Show when={layout().wideHidden > 0}>\n <span class=\"k2b-view-tabs__more-count\" data-level=\"wide\">\n +{layout().wideHidden}\n </span>\n </Show>\n <Show when={layout().compactHidden > 0}>\n <span class=\"k2b-view-tabs__more-count\" data-level=\"compact\">\n +{layout().compactHidden}\n </span>\n </Show>\n <i class=\"ti ti-chevron-down\" aria-hidden=\"true\" />\n </Dropdown.Trigger>\n </Dropdown.Root>\n </li>\n </Show>\n </ul>\n <script innerHTML={VIEW_TABS_SCRIPT} />\n </nav>\n );\n}\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"names":[],"sources":["actions/ViewTabs.tsx"],"sourcesContent":["import { createEffect, createMemo, createSignal, For, type JSX, on, onCleanup, onMount, Show } from \"solid-js\";\nimport { useUiMessages } from \"../intl/messages\";\nimport { createScrollFade, scrollFadeEdges } from \"../layout/scroll-fade\";\nimport Dropdown, { type DropdownItem } from \"./Dropdown\";\n\nexport type ViewTab = {\n id: string;\n label: string;\n href: string;\n icon?: string;\n count?: number | string;\n /** A short quiet label after the count, such as \"New\" for a view people have not opened yet. */\n badge?: string;\n /** Stays in the strip after More at every width, for a view of another kind than the ones that overflow. */\n pinned?: boolean;\n};\nexport type ViewTabsProps = {\n /** Accessible name of the navigation landmark, e.g. \"Views\". */\n label: string;\n items: readonly ViewTab[];\n /** Id of the open view; the server reads it from `?view=`. Unknown ids select nothing. */\n current: string | undefined;\n /** At most this many views before More (default 5). */\n max?: number;\n /**\n * The strip shows only the views that fit its room and counts the rest in More, instead of scrolling them. The open\n * view and pinned views stay. Pair it with a larger `max` so a wide head shows more views.\n */\n fit?: boolean;\n class?: string;\n};\n\n/** Two deterministic strip levels; only opening the menu reads CSS visibility. */\nexport function viewTabsLayout(items: readonly ViewTab[], current: string | undefined, max = 5) {\n // At least one slot keeps the current view visible, including for an invalid limit.\n const limit = Number.isFinite(max) ? Math.max(1, Math.floor(max)) : 5;\n // Pinned views never overflow, so they take no slot.\n const flowing = items.flatMap((item, index) => (item.pinned ? [] : [index]));\n const pinned = items.flatMap((item, index) => (item.pinned ? [index] : []));\n const currentIndex = items.findIndex((item) => item.id === current);\n const currentPosition = flowing.indexOf(currentIndex);\n const visible = (size: number) => {\n const indices = flowing.slice(0, size);\n if (currentPosition >= size) indices[indices.length - 1] = currentIndex;\n return indices;\n };\n const wide = visible(limit);\n const compact = visible(Math.min(limit, 3));\n return { wide, compact, pinned, wideHidden: flowing.length - wide.length, compactHidden: flowing.length - compact.length };\n}\n\n/**\n * Self-contained: the server script embeds this before hydration. A fitting strip first keeps only the views that fit\n * its room and counts the rest in More; then the open or focused view scrolls into the strip.\n */\nfunction settleViewTabs(list: Element | null, edges: (element: HTMLElement) => string | undefined, focused?: HTMLElement) {\n if (!(list instanceof HTMLElement)) return;\n const more = list.querySelector<HTMLElement>(\":scope > .k2b-view-tabs__more\");\n const fitCount = more?.querySelector<HTMLElement>('.k2b-view-tabs__more-count[data-level=\"fit\"]');\n const flowing = Array.from(list.querySelectorAll<HTMLElement>(\":scope > .k2b-view-tabs__item:not([data-pinned])\"));\n\n for (const item of flowing) item.removeAttribute(\"data-fit-hidden\");\n more?.removeAttribute(\"data-fit\");\n // The shown entries against the strip's inner room, whatever its scroll and padding.\n const overflows = () => {\n const boxes = Array.from(list.children)\n .filter((child) => child instanceof HTMLElement && child.tagName === \"LI\" && child.getClientRects().length > 0)\n .map((child) => child.getBoundingClientRect());\n if (boxes.length === 0) return false;\n const style = getComputedStyle(list);\n const room = list.clientWidth - (parseFloat(style.paddingLeft) || 0) - (parseFloat(style.paddingRight) || 0);\n return Math.max(...boxes.map((box) => box.right)) - Math.min(...boxes.map((box) => box.left)) > room + 0.5;\n };\n // The phone head row keeps its scrolling strip: its CSS turns fitting off.\n const fits = list.hasAttribute(\"data-fit-room\") && getComputedStyle(list).getPropertyValue(\"--k2b-view-tabs-fit\").trim() !== \"none\";\n if (fits && more && fitCount && overflows()) {\n // Count from the level on screen: the compact strip already keeps fewer views than the wide one.\n const compact = more.querySelector<HTMLElement>('.k2b-view-tabs__more-count[data-level=\"compact\"]');\n const compactShown = Boolean(compact && getComputedStyle(compact).display !== \"none\");\n const behind = Number(compactShown ? more.dataset.behindCompact : more.dataset.behindWide) || 0;\n // The last views on screen leave first; the open view stays.\n const candidates = flowing.filter((item) => item.getClientRects().length > 0 && !item.querySelector(\"[aria-current=page]\")).reverse();\n more.setAttribute(\"data-fit\", \"\");\n let hidden = 0;\n for (const item of candidates) {\n item.setAttribute(\"data-fit-hidden\", \"\");\n hidden += 1;\n fitCount.textContent = `+${behind + hidden}`;\n if (!overflows()) break;\n }\n if (hidden === 0) more.removeAttribute(\"data-fit\");\n }\n const current = focused ?? list.querySelector(\".k2b-view-tabs__tab[aria-current=page]\");\n if (current && current.getClientRects().length > 0 && list.scrollWidth - list.clientWidth > 1) {\n const bounds = list.getBoundingClientRect();\n const item = current.getBoundingClientRect();\n const fade = edges(list);\n const style = getComputedStyle(list);\n const left = fade === \"top\" || fade === \"both\" ? parseFloat(style.scrollPaddingLeft) || 0 : 0;\n const right = fade === \"bottom\" || fade === \"both\" ? parseFloat(style.scrollPaddingRight) || 0 : 0;\n if (item.left < bounds.left + left || item.right > bounds.right - right) {\n let offset = item.left - bounds.left - (bounds.width - item.width) / 2;\n if (focused) {\n // Reserve padding at the destination edge; native clamping drops it when that end is reached.\n offset =\n item.left < bounds.left + left\n ? item.left - bounds.left - (parseFloat(style.scrollPaddingLeft) || 0)\n : item.right - bounds.right + (parseFloat(style.scrollPaddingRight) || 0);\n }\n // Only the strip moves: scrollIntoView would also scroll the page. Instant keeps the first frame free of animation.\n list.scrollTo({ left: list.scrollLeft + offset, behavior: \"instant\" });\n }\n }\n const fade = edges(list);\n if (fade) list.setAttribute(\"data-scroll-fade\", fade);\n else list.removeAttribute(\"data-scroll-fade\");\n}\n\ntype WatchedViewTabs = HTMLElement & {\n __k2bViewTabsWatch?: {\n resize: ResizeObserver;\n focus: (event: FocusEvent) => void;\n preferCurrent: boolean;\n connect: () => void;\n /** Runs one fit in the next frame; calls before it runs share it. */\n schedule: () => void;\n frame: number;\n /** The head lead's width and the widths of the shown entries when the last fit ended. */\n room: string;\n /** Fits again once web fonts finish loading: their metrics change every view's width, not the lead's. */\n fonts: () => void;\n };\n};\n\n/**\n * Also embedded, so it must not close over module state.\n *\n * A fitting strip converges by construction. It fits again only when the strip renders, web fonts finish loading, or\n * a notification finds another width of the head lead or of an entry that the last fit left shown. A fit only shows\n * and hides entries: the lead is an inline-size container that takes no width from the strip, and every entry keeps\n * its own width (`flex: none`), so the notifications a fit causes find the widths it ended with and stop there.\n */\nfunction watchViewTabs(list: WatchedViewTabs | null, settle: typeof settleViewTabs, edges: (element: HTMLElement) => string | undefined) {\n if (!(list instanceof HTMLElement)) return;\n const fits = list.hasAttribute(\"data-fit-room\");\n const roomOf = () => list.closest<HTMLElement>(\".k2b-app-workspace__head-lead\");\n // What a fit depends on: the lead's width and each shown entry's width, which fonts, icons and labels change.\n const measured = () =>\n [roomOf()?.clientWidth ?? -1, ...Array.from(list.children, (child) => child.getBoundingClientRect().width)].join(\" \");\n // A DOM property survives hydration: one observer and focus listener per reused list.\n let watch = list.__k2bViewTabsWatch;\n if (!watch) {\n const focus = (event: FocusEvent) => {\n // Pointer focus must not move the target under the pointer.\n if (watch && event.target instanceof HTMLElement && event.target.matches(\".k2b-view-tabs__tab:focus-visible\")) {\n watch.preferCurrent = false;\n settle(list, edges, event.target);\n }\n };\n const settleNow = () => {\n const focused = document.activeElement;\n if (\n watch?.preferCurrent === false &&\n focused instanceof HTMLElement &&\n list.contains(focused) &&\n focused.matches(\".k2b-view-tabs__tab:focus-visible\")\n )\n settle(list, edges, focused);\n else settle(list, edges);\n };\n // Head actions parse after the views; settle again after their layout, before paint, and on later resizes.\n const connect = () => {\n if (!watch) return;\n watch.resize.disconnect();\n watch.resize.observe(list);\n for (const child of Array.from(list.children)) watch.resize.observe(child);\n const room = roomOf();\n if (fits && room) watch.resize.observe(room);\n };\n // Fitting resizes the strip and possibly the head, which other observers may watch. Inside a ResizeObserver\n // callback that would leave their notifications undelivered, so a fit runs in the next frame, still before it paints.\n const schedule = () => {\n if (!watch || watch.frame) return;\n watch.frame = requestAnimationFrame(() => {\n if (!watch) return;\n watch.frame = 0;\n if (!list.isConnected) return;\n settleNow();\n watch.room = measured();\n });\n };\n watch = {\n resize: new ResizeObserver(() => {\n // A scrolling strip only scrolls and settles at once.\n if (!fits) return settleNow();\n // Heights follow the fit, and hidden entries measure 0 by its own doing: only another measure counts.\n if (watch && measured() !== watch.room) watch.schedule();\n }),\n focus,\n preferCurrent: true,\n connect,\n schedule,\n frame: 0,\n room: \"\",\n fonts: () => watch?.schedule(),\n };\n Object.defineProperty(list, \"__k2bViewTabsWatch\", { value: watch, configurable: true });\n list.addEventListener(\"focusin\", focus);\n // A first visit can paint before the web fonts load; the server frame and the client then fit the same metrics.\n if (fits && document.fonts) {\n document.fonts.addEventListener(\"loadingdone\", watch.fonts);\n void document.fonts.ready.then(watch.fonts);\n }\n }\n watch.preferCurrent = true;\n watch.connect();\n settle(list, edges);\n if (fits) {\n watch.room = measured();\n // The head's actions parse after the views. A frame's animation callbacks run before its first layout and\n // paint, so this fit also counts their room in the first frame.\n watch.schedule();\n }\n return watch;\n}\nconst VIEW_TABS_SCRIPT = `(${watchViewTabs})(document.currentScript&&document.currentScript.previousElementSibling,${settleViewTabs},${scrollFadeEdges})`;\n\n/**\n * URL-backed object views. Every view is an ordinary document link, in the strip and under More, so reload, back,\n * and forward keep the view the URL names.\n */\nexport function ViewTabs(props: ViewTabsProps): JSX.Element {\n const messages = useUiMessages();\n const layout = createMemo(() => viewTabsLayout(props.items, props.current, props.max));\n const stripItems = new Map<number, HTMLLIElement>();\n let list: HTMLUListElement | undefined;\n createScrollFade(\n () => list,\n () => true,\n );\n onMount(() => {\n const watch = watchViewTabs(list ?? null, settleViewTabs, scrollFadeEdges);\n let disposed = false;\n // Later mount effects can invalidate WebKit's scroll layout after this\n // initial settle. Finish once the mount task is complete, before its first\n // frame; ResizeObserver alone runs too late for that frame.\n queueMicrotask(() => {\n if (!disposed && watch?.preferCurrent) settleViewTabs(list ?? null, scrollFadeEdges);\n });\n onCleanup(() => {\n disposed = true;\n watch?.resize.disconnect();\n if (watch?.frame) cancelAnimationFrame(watch.frame);\n if (watch) document.fonts?.removeEventListener(\"loadingdone\", watch.fonts);\n if (list && watch) {\n list.removeEventListener(\"focusin\", watch.focus);\n Reflect.deleteProperty(list, \"__k2bViewTabsWatch\");\n }\n });\n });\n // User effects run after Solid's render effects, including For and aria-current, in the same task.\n // What the strip shows: another open view, view, label, count or badge can change what fits. Equal content in a new\n // array settles nothing again.\n const shown = createMemo(() =>\n [\n props.current ?? \"\",\n layout().wide.join(\",\"),\n ...props.items.map((item) => `${item.id}\\u0000${item.label}\\u0000${item.count ?? \"\"}\\u0000${item.badge ?? \"\"}`),\n ].join(\"\\u0001\"),\n );\n createEffect(on(shown, () => watchViewTabs(list ?? null, settleViewTabs, scrollFadeEdges), { defer: true }));\n const [open, setOpen] = createSignal(false);\n const [menuItems, setMenuItems] = createSignal<DropdownItem[]>([]);\n const onOpenChange = (next: boolean) => {\n if (next) {\n setMenuItems(\n props.items\n .filter(\n (item, index) =>\n !item.pinned &&\n item.id !== props.current &&\n (!layout().wide.includes(index) || stripItems.get(index)?.getClientRects().length === 0),\n )\n .map((item) => ({\n href: item.href,\n label: item.label,\n icon: item.icon,\n trailing: item.count !== undefined ? <span class=\"k2b-view-tabs__count\">{item.count}</span> : undefined,\n })),\n );\n }\n setOpen(next);\n };\n const tabContent = (item: ViewTab) => (\n <>\n <Show when={item.icon}>{(icon) => <i class={icon()} aria-hidden=\"true\" />}</Show>\n <span class=\"k2b-view-tabs__label k2b-truncate-fade\">{item.label}</span>\n <Show when={item.count !== undefined}>\n <span class=\"k2b-view-tabs__count\">{item.count}</span>\n </Show>\n <Show when={item.badge}>{(badge) => <span class=\"k2b-view-tabs__badge\">{badge()}</span>}</Show>\n </>\n );\n const stripItem = (index: number) => {\n const item = () => props.items[index]!;\n onCleanup(() => stripItems.delete(index));\n return (\n <li\n ref={(element) => stripItems.set(index, element)}\n class=\"k2b-view-tabs__item\"\n data-view-tab={item().id}\n data-pinned={item().pinned ? \"\" : undefined}\n data-compact-hidden={!item().pinned && !layout().compact.includes(index) ? \"\" : undefined}\n >\n <a class=\"k2b-view-tabs__tab\" href={item().href} aria-current={item().id === props.current ? \"page\" : undefined}>\n {tabContent(item())}\n </a>\n </li>\n );\n };\n return (\n <nav class={`k2b-view-tabs ${props.class ?? \"\"}`} aria-label={props.label}>\n <ul\n ref={list}\n class=\"k2b-view-tabs__list\"\n data-scroll-fade-mode=\"both\"\n data-scroll-fade-axis=\"horizontal\"\n data-fit-room={props.fit ? \"\" : undefined}\n >\n <For each={layout().wide}>{stripItem}</For>\n {/* A fitting strip keeps More ready, hidden until a view leaves the strip. */}\n <Show when={layout().compactHidden + layout().wideHidden > 0 || (props.fit && layout().wide.length > 1)}>\n <li\n class=\"k2b-view-tabs__more\"\n data-wide={layout().wideHidden > 0 ? \"\" : undefined}\n data-behind-wide={layout().wideHidden}\n data-behind-compact={layout().compactHidden}\n >\n <Dropdown.Root items={menuItems()} open={open()} onOpenChange={onOpenChange} label={messages().moreViews}>\n <Dropdown.Trigger appearance=\"plain\" class=\"k2b-view-tabs__tab k2b-view-tabs__more-trigger\" label={messages().moreViews}>\n <span class=\"k2b-view-tabs__label\">{messages().more}</span>\n <Show when={layout().wideHidden > 0}>\n <span class=\"k2b-view-tabs__more-count\" data-level=\"wide\">\n +{layout().wideHidden}\n </span>\n </Show>\n <Show when={layout().compactHidden > 0}>\n <span class=\"k2b-view-tabs__more-count\" data-level=\"compact\">\n +{layout().compactHidden}\n </span>\n </Show>\n {/* Written by the strip's fit, never by the render, so a rerender keeps the count it measured. */}\n <span class=\"k2b-view-tabs__more-count\" data-level=\"fit\" />\n <i class=\"ti ti-chevron-down\" aria-hidden=\"true\" />\n </Dropdown.Trigger>\n </Dropdown.Root>\n </li>\n </Show>\n <For each={layout().pinned}>{stripItem}</For>\n </ul>\n <script innerHTML={VIEW_TABS_SCRIPT} />\n </nav>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAAA,SAAS,YAAY,EAAE,UAAU,EAAE,YAAY,EAAE,GAAG,EAAY,EAAE,EAAE,SAAS,EAAE,OAAO,EAAE,IAAI,QAAQ,UAAU;AAC9G,SAAS,aAAa,QAAQ,kBAAkB;AAChD,SAAS,gBAAgB,EAAE,eAAe,QAAQ,uBAAuB;AACzE,OAAO,QAAQ,MAA6B,YAAY;AA6BxD;AACA,OAAO,SAAS,cAAc,CAAC,KAAyB,EAAE,OAA2B,EAAE,GAAG,GAAG,CAAC,EAAE;EAC9F;EACA,MAAM,KAAK,GAAG,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC;EACrE;EACA,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,KAAK,KAAM,IAAI,CAAC,MAAM,GAAG,EAAE,GAAG,CAAC,KAAK,CAAE,CAAC;EAC5E,MAAM,MAAM,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,KAAK,KAAM,IAAI,CAAC,MAAM,GAAG,CAAC,KAAK,CAAC,GAAG,EAAG,CAAC;EAC3E,MAAM,YAAY,GAAG,KAAK,CAAC,SAAS,CAAE,IAAI,IAAK,IAAI,CAAC,EAAE,KAAK,OAAO,CAAC;EACnE,MAAM,eAAe,GAAG,OAAO,CAAC,OAAO,CAAC,YAAY,CAAC;EACrD,MAAM,OAAO,GAAI,IAAY,IAAK;IAChC,MAAM,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC;IACtC,IAAI,eAAe,IAAI,IAAI,EAAE,OAAO,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,GAAG,YAAY;IACvE,OAAO,OAAO;EAChB,CAAC;EACD,MAAM,IAAI,GAAG,OAAO,CAAC,KAAK,CAAC;EAC3B,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;EAC3C,OAAO;IAAE,IAAI;IAAE,OAAO;IAAE,MAAM;IAAE,UAAU,EAAE,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM;IAAE,aAAa,EAAE,OAAO,CAAC,MAAM,GAAG,OAAO,CAAC;EAAO,CAAC;AAC5H;;AAEA;AACA;AACA;AACA;AACA,SAAS,cAAc,CAAC,IAAoB,EAAE,KAAmD,EAAE,OAAqB,EAAE;EACxH,IAAI,EAAE,IAAI,YAAY,WAAW,CAAC,EAAE;EACpC,MAAM,IAAI,GAAG,IAAI,CAAC,aAAa,CAAc,+BAA+B,CAAC;EAC7E,MAAM,QAAQ,GAAG,IAAI,EAAE,aAAa,CAAc,8CAA8C,CAAC;EACjG,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,gBAAgB,CAAc,kDAAkD,CAAC,CAAC;EAElH,KAAK,MAAM,IAAI,IAAI,OAAO,EAAE,IAAI,CAAC,eAAe,CAAC,iBAAiB,CAAC;EACnE,IAAI,EAAE,eAAe,CAAC,UAAU,CAAC;EACjC;EACA,MAAM,SAAS,GAAG,MAAM;IACtB,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CACpC,MAAM,CAAE,KAAK,IAAK,KAAK,YAAY,WAAW,IAAI,KAAK,CAAC,OAAO,KAAK,IAAI,IAAI,KAAK,CAAC,cAAc,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAC9G,GAAG,CAAE,KAAK,IAAK,KAAK,CAAC,qBAAqB,CAAC,CAAC,CAAC;IAChD,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,OAAO,KAAK;IACpC,MAAM,KAAK,GAAG,gBAAgB,CAAC,IAAI,CAAC;IACpC,MAAM,IAAI,GAAG,IAAI,CAAC,WAAW,IAAI,UAAU,CAAC,KAAK,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,IAAI,UAAU,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;IAC5G,OAAO,IAAI,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,GAAG,CAAE,GAAG,IAAK,GAAG,CAAC,KAAK,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,GAAG,CAAE,GAAG,IAAK,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,IAAI,GAAG,GAAG;EAC5G,CAAC;EACD;EACA,MAAM,IAAI,GAAG,IAAI,CAAC,YAAY,CAAC,eAAe,CAAC,IAAI,gBAAgB,CAAC,IAAI,CAAC,CAAC,gBAAgB,CAAC,qBAAqB,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,MAAM;EACnI,IAAI,IAAI,IAAI,IAAI,IAAI,QAAQ,IAAI,SAAS,CAAC,CAAC,EAAE;IAC3C;IACA,MAAM,OAAO,GAAG,IAAI,CAAC,aAAa,CAAc,kDAAkD,CAAC;IACnG,MAAM,YAAY,GAAG,OAAO,CAAC,OAAO,IAAI,gBAAgB,CAAC,OAAO,CAAC,CAAC,OAAO,KAAK,MAAM,CAAC;IACrF,MAAM,MAAM,GAAG,MAAM,CAAC,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC;IAC/F;IACA,MAAM,UAAU,GAAG,OAAO,CAAC,MAAM,CAAE,IAAI,IAAK,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,qBAAqB,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;IACrI,IAAI,CAAC,YAAY,CAAC,UAAU,EAAE,EAAE,CAAC;IACjC,IAAI,MAAM,GAAG,CAAC;IACd,KAAK,MAAM,IAAI,IAAI,UAAU,EAAE;MAC7B,IAAI,CAAC,YAAY,CAAC,iBAAiB,EAAE,EAAE,CAAC;MACxC,MAAM,IAAI,CAAC;MACX,QAAQ,CAAC,WAAW,GAAG,IAAI,MAAM,GAAG,MAAM,EAAE;MAC5C,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE;IACpB;IACA,IAAI,MAAM,KAAK,CAAC,EAAE,IAAI,CAAC,eAAe,CAAC,UAAU,CAAC;EACpD;EACA,MAAM,OAAO,GAAG,OAAO,IAAI,IAAI,CAAC,aAAa,CAAC,wCAAwC,CAAC;EACvF,IAAI,OAAO,IAAI,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,IAAI,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,WAAW,GAAG,CAAC,EAAE;IAC7F,MAAM,MAAM,GAAG,IAAI,CAAC,qBAAqB,CAAC,CAAC;IAC3C,MAAM,IAAI,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAAC;IAC5C,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC;IACxB,MAAM,KAAK,GAAG,gBAAgB,CAAC,IAAI,CAAC;IACpC,MAAM,IAAI,GAAG,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,MAAM,GAAG,UAAU,CAAC,KAAK,CAAC,iBAAiB,CAAC,IAAI,CAAC,GAAG,CAAC;IAC7F,MAAM,KAAK,GAAG,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,MAAM,GAAG,UAAU,CAAC,KAAK,CAAC,kBAAkB,CAAC,IAAI,CAAC,GAAG,CAAC;IAClG,IAAI,IAAI,CAAC,IAAI,GAAG,MAAM,CAAC,IAAI,GAAG,IAAI,IAAI,IAAI,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK,GAAG,KAAK,EAAE;MACvE,IAAI,MAAM,GAAG,IAAI,CAAC,IAAI,GAAG,MAAM,CAAC,IAAI,GAAG,CAAC,MAAM,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,CAAC;MACtE,IAAI,OAAO,EAAE;QACX;QACA,MAAM,GACJ,IAAI,CAAC,IAAI,GAAG,MAAM,CAAC,IAAI,GAAG,IAAI,GAC1B,IAAI,CAAC,IAAI,GAAG,MAAM,CAAC,IAAI,IAAI,UAAU,CAAC,KAAK,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC,GACpE,IAAI,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK,IAAI,UAAU,CAAC,KAAK,CAAC,kBAAkB,CAAC,IAAI,CAAC,CAAC;MAC/E;MACA;MACA,IAAI,CAAC,QAAQ,CAAC;QAAE,IAAI,EAAE,IAAI,CAAC,UAAU,GAAG,MAAM;QAAE,QAAQ,EAAE;MAAU,CAAC,CAAC;IACxE;EACF;EACA,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC;EACxB,IAAI,IAAI,EAAE,IAAI,CAAC,YAAY,CAAC,kBAAkB,EAAE,IAAI,CAAC,CAAC,KACjD,IAAI,CAAC,eAAe,CAAC,kBAAkB,CAAC;AAC/C;AAkBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS,aAAa,CAAC,IAA4B,EAAE,MAA6B,EAAE,KAAmD,EAAE;EACvI,IAAI,EAAE,IAAI,YAAY,WAAW,CAAC,EAAE;EACpC,MAAM,IAAI,GAAG,IAAI,CAAC,YAAY,CAAC,eAAe,CAAC;EAC/C,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,CAAc,+BAA+B,CAAC;EAC/E;EACA,MAAM,QAAQ,GAAG,MACf,CAAC,MAAM,CAAC,CAAC,EAAE,WAAW,IAAI,CAAC,CAAC,EAAE,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAG,KAAK,IAAK,KAAK,CAAC,qBAAqB,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;EACvH;EACA,IAAI,KAAK,GAAG,IAAI,CAAC,kBAAkB;EACnC,IAAI,CAAC,KAAK,EAAE;IACV,MAAM,KAAK,GAAI,KAAiB,IAAK;MACnC;MACA,IAAI,KAAK,IAAI,KAAK,CAAC,MAAM,YAAY,WAAW,IAAI,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,mCAAmC,CAAC,EAAE;QAC7G,KAAK,CAAC,aAAa,GAAG,KAAK;QAC3B,MAAM,CAAC,IAAI,EAAE,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC;MACnC;IACF,CAAC;IACD,MAAM,SAAS,GAAG,MAAM;MACtB,MAAM,OAAO,GAAG,QAAQ,CAAC,aAAa;MACtC,IACE,KAAK,EAAE,aAAa,KAAK,KAAK,IAC9B,OAAO,YAAY,WAAW,IAC9B,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,IACtB,OAAO,CAAC,OAAO,CAAC,mCAAmC,CAAC,EAEpD,MAAM,CAAC,IAAI,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC,KAC1B,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC;IAC1B,CAAC;IACD;IACA,MAAM,OAAO,GAAG,MAAM;MACpB,IAAI,CAAC,KAAK,EAAE;MACZ,KAAK,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;MACzB,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC;MAC1B,KAAK,MAAM,KAAK,IAAI,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC;MAC1E,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC;MACrB,IAAI,IAAI,IAAI,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC;IAC9C,CAAC;IACD;IACA;IACA,MAAM,QAAQ,GAAG,MAAM;MACrB,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,KAAK,EAAE;MAC3B,KAAK,CAAC,KAAK,GAAG,qBAAqB,CAAC,MAAM;QACxC,IAAI,CAAC,KAAK,EAAE;QACZ,KAAK,CAAC,KAAK,GAAG,CAAC;QACf,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE;QACvB,SAAS,CAAC,CAAC;QACX,KAAK,CAAC,IAAI,GAAG,QAAQ,CAAC,CAAC;MACzB,CAAC,CAAC;IACJ,CAAC;IACD,KAAK,GAAG;MACN,MAAM,EAAE,IAAI,cAAc,CAAC,MAAM;QAC/B;QACA,IAAI,CAAC,IAAI,EAAE,OAAO,SAAS,CAAC,CAAC;QAC7B;QACA,IAAI,KAAK,IAAI,QAAQ,CAAC,CAAC,KAAK,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC;MAC1D,CAAC,CAAC;MACF,KAAK;MACL,aAAa,EAAE,IAAI;MACnB,OAAO;MACP,QAAQ;MACR,KAAK,EAAE,CAAC;MACR,IAAI,EAAE,EAAE;MACR,KAAK,EAAE,MAAM,KAAK,EAAE,QAAQ,CAAC;IAC/B,CAAC;IACD,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,oBAAoB,EAAE;MAAE,KAAK,EAAE,KAAK;MAAE,YAAY,EAAE;IAAK,CAAC,CAAC;IACvF,IAAI,CAAC,gBAAgB,CAAC,SAAS,EAAE,KAAK,CAAC;IACvC;IACA,IAAI,IAAI,IAAI,QAAQ,CAAC,KAAK,EAAE;MAC1B,QAAQ,CAAC,KAAK,CAAC,gBAAgB,CAAC,aAAa,EAAE,KAAK,CAAC,KAAK,CAAC;MAC3D,KAAK,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC;IAC7C;EACF;EACA,KAAK,CAAC,aAAa,GAAG,IAAI;EAC1B,KAAK,CAAC,OAAO,CAAC,CAAC;EACf,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC;EACnB,IAAI,IAAI,EAAE;IACR,KAAK,CAAC,IAAI,GAAG,QAAQ,CAAC,CAAC;IACvB;IACA;IACA,KAAK,CAAC,QAAQ,CAAC,CAAC;EAClB;EACA,OAAO,KAAK;AACd;AACA,MAAM,gBAAgB,GAAG,IAAI,aAAa,2EAA2E,cAAc,IAAI,eAAe,GAAG;;AAEzJ;AACA;AACA;AACA;AACA,OAAO,SAAS,QAAQ,CAAC,KAAoB,EAAe;EAC1D,MAAM,QAAQ,GAAG,aAAa,CAAC,CAAC;EAChC,MAAM,MAAM,GAAG,UAAU,CAAC,MAAM,cAAc,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;EACtF,MAAM,UAAU,GAAG,IAAI,GAAG,CAAwB,CAAC;EACnD,IAAI,IAAkC;EACtC,gBAAgB,CACd,MAAM,IAAI,EACV,MAAM,IACR,CAAC;EACD,OAAO,CAAC,MAAM;IACZ,MAAM,KAAK,GAAG,aAAa,CAAC,IAAI,IAAI,IAAI,EAAE,cAAc,EAAE,eAAe,CAAC;IAC1E,IAAI,QAAQ,GAAG,KAAK;IACpB;IACA;IACA;IACA,cAAc,CAAC,MAAM;MACnB,IAAI,CAAC,QAAQ,IAAI,KAAK,EAAE,aAAa,EAAE,cAAc,CAAC,IAAI,IAAI,IAAI,EAAE,eAAe,CAAC;IACtF,CAAC,CAAC;IACF,SAAS,CAAC,MAAM;MACd,QAAQ,GAAG,IAAI;MACf,KAAK,EAAE,MAAM,CAAC,UAAU,CAAC,CAAC;MAC1B,IAAI,KAAK,EAAE,KAAK,EAAE,oBAAoB,CAAC,KAAK,CAAC,KAAK,CAAC;MACnD,IAAI,KAAK,EAAE,QAAQ,CAAC,KAAK,EAAE,mBAAmB,CAAC,aAAa,EAAE,KAAK,CAAC,KAAK,CAAC;MAC1E,IAAI,IAAI,IAAI,KAAK,EAAE;QACjB,IAAI,CAAC,mBAAmB,CAAC,SAAS,EAAE,KAAK,CAAC,KAAK,CAAC;QAChD,OAAO,CAAC,cAAc,CAAC,IAAI,EAAE,oBAAoB,CAAC;MACpD;IACF,CAAC,CAAC;EACJ,CAAC,CAAC;EACF;EACA;EACA;EACA,MAAM,KAAK,GAAG,UAAU,CAAC,MACvB,CACE,KAAK,CAAC,OAAO,IAAI,EAAE,EACnB,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EACvB,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAE,IAAI,IAAK,GAAG,IAAI,CAAC,EAAE,SAAS,IAAI,CAAC,KAAK,SAAS,IAAI,CAAC,KAAK,IAAI,EAAE,SAAS,IAAI,CAAC,KAAK,IAAI,EAAE,EAAE,CAAC,CAChH,CAAC,IAAI,CAAC,QAAQ,CACjB,CAAC;EACD,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,aAAa,CAAC,IAAI,IAAI,IAAI,EAAE,cAAc,EAAE,eAAe,CAAC,EAAE;IAAE,KAAK,EAAE;EAAK,CAAC,CAAC,CAAC;EAC5G,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,YAAY,CAAC,KAAK,CAAC;EAC3C,MAAM,CAAC,SAAS,EAAE,YAAY,CAAC,GAAG,YAAY,CAAiB,EAAE,CAAC;EAClE,MAAM,YAAY,GAAI,IAAa,IAAK;IACtC,IAAI,IAAI,EAAE;MACR,YAAY,CACV,KAAK,CAAC,KAAK,CACR,MAAM,CACL,CAAC,IAAI,EAAE,KAAK,KACV,CAAC,IAAI,CAAC,MAAM,IACZ,IAAI,CAAC,EAAE,KAAK,KAAK,CAAC,OAAO,KACxB,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,cAAc,CAAC,CAAC,CAAC,MAAM,KAAK,CAAC,CAC3F,CAAC,CACA,GAAG,CAAE,IAAI,KAAM;QACd,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,KAAK,EAAE,IAAI,CAAC,KAAK;QACjB,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,QAAQ,EAAE,IAAI,CAAC,KAAK,KAAK,SAAS;UAAA;UAAA,qBAAuC,IAAI,CAAC,KAAK;UAAA;QAAA,OAAW;MAChG,CAAC,CAAC,CACN,CAAC;IACH;IACA,OAAO,CAAC,IAAI,CAAC;EACf,CAAC;EACD,MAAM,UAAU,GAAI,IAAa,uBAE5B,IAAI;IAAA,IAAC,IAAI;MAAA,OAAE,IAAI,CAAC,IAAI;IAAA;IAAA,UAAI,IAAI;MAAA;MAAA,kCAAe,IAAI,CAAC,CAAC;MAAA;IAAA;EAAuB;IAAA;IAAA,sBACnB,IAAI,CAAC,KAAK;IAAA;EAAA,wBAC/D,IAAI;IAAA,IAAC,IAAI;MAAA,OAAE,IAAI,CAAC,KAAK,KAAK,SAAS;IAAA;IAAA;MAAA;MAAA,sBACE,IAAI,CAAC,KAAK;MAAA;IAAA;EAAA,sBAE/C,IAAI;IAAA,IAAC,IAAI;MAAA,OAAE,IAAI,CAAC,KAAK;IAAA;IAAA,UAAI,KAAK;MAAA;MAAA,gBAAyC,KAAK;MAAA;IAAA;EAAU,GAE1F;EACD,MAAM,SAAS,GAAI,KAAa,IAAK;IACnC,MAAM,IAAI,GAAG,MAAM,KAAK,CAAC,KAAK,CAAC,KAAK,CAAE;IACtC,SAAS,CAAC,MAAM,UAAU,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACzC;MAAA;QAAA;MAAA,MAEU,OAAO,IAAK,UAAU,CAAC,GAAG,CAAC,KAAK,EAAE,OAAO,CAAC;MAAA,sBAO7C,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC;MAAA;QAAA,UALN,IAAI,CAAC,CAAC,CAAC,EAAE;UAAA,OACX,IAAI,CAAC,CAAC,CAAC,MAAM,GAAG,EAAE,GAAG,SAAS;UAAA,OACtB,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,EAAE,GAAG,SAAS;UAAA,OAErD,IAAI,CAAC,CAAC,CAAC,IAAI;UAAA,OAAgB,IAAI,CAAC,CAAC,CAAC,EAAE,KAAK,KAAK,CAAC,OAAO,GAAG,MAAM,GAAG,SAAS;QAAA;QAAA;QAAA;QAAA;QAAA;QAAA;MAAA;QAAA;QAAA;QAAA;QAAA;QAAA;MAAA;MAAA;IAAA;EAKrH,CAAC;EACD;IAAA;MAAA;MAAA;MAAA;MAAA;MAAA;MAAA;MAAA;MAAA;IAAA,YAGW,IAAI;IAAA,oDAAJ,IAAI;IAAA,kCAMR,GAAG;MAAA,IAAC,IAAI;QAAA,OAAE,MAAM,CAAC,CAAC,CAAC,IAAI;MAAA;MAAA,UAAG;IAAS;IAAA,kCAEnC,IAAI;MAAA,IAAC,IAAI;QAAA,OAAE,MAAM,CAAC,CAAC,CAAC,aAAa,GAAG,MAAM,CAAC,CAAC,CAAC,UAAU,GAAG,CAAC,IAAK,KAAK,CAAC,GAAG,IAAI,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,GAAG,CAAE;MAAA;MAAA;QAAA;QAAA,kCAOlG,QAAQ,CAAC,IAAI;UAAA,IAAC,KAAK;YAAA,OAAE,SAAS,CAAC,CAAC;UAAA;UAAA,IAAE,IAAI;YAAA,OAAE,IAAI,CAAC,CAAC;UAAA;UAAE,YAAY,EAAE,YAAY;UAAA,IAAE,KAAK;YAAA,OAAE,QAAQ,CAAC,CAAC,CAAC,SAAS;UAAA;UAAA;YAAA,yBACrG,QAAQ,CAAC,OAAO;cAAC,UAAU;cAAA;cAAA,IAAgE,KAAK;gBAAA,OAAE,QAAQ,CAAC,CAAC,CAAC,SAAS;cAAA;cAAA;gBAAA;kBAAA;kBAAA,sBACjF,QAAQ,CAAC,CAAC,CAAC,IAAI;kBAAA;gBAAA,wBAClD,IAAI;kBAAA,IAAC,IAAI;oBAAA,OAAE,MAAM,CAAC,CAAC,CAAC,UAAU,GAAG,CAAC;kBAAA;kBAAA;oBAAA;sBAAA;sBAAA;sBAAA;oBAAA,uBAE7B,MAAM,CAAC,CAAC,CAAC,UAAU;oBAAA;kBAAA;gBAAA,sBAGxB,IAAI;kBAAA,IAAC,IAAI;oBAAA,OAAE,MAAM,CAAC,CAAC,CAAC,aAAa,GAAG,CAAC;kBAAA;kBAAA;oBAAA;sBAAA;sBAAA;sBAAA;oBAAA,uBAEhC,MAAM,CAAC,CAAC,CAAC,aAAa;oBAAA;kBAAA;gBAAA;cAAA;YAAA;UAAA;QAAA;QAAA;UAAA,WAdrB,MAAM,CAAC,CAAC,CAAC,UAAU,GAAG,CAAC,GAAG,EAAE,GAAG,SAAS;YAAA,OACjC,MAAM,CAAC,CAAC,CAAC,UAAU;YAAA,OAChB,MAAM,CAAC,CAAC,CAAC,aAAa;UAAA;UAAA;UAAA;UAAA;QAAA;UAAA;UAAA;UAAA;QAAA;QAAA;MAAA;IAAA;IAAA,kCAsB9C,GAAG;MAAA,IAAC,IAAI;QAAA,OAAE,MAAM,CAAC,CAAC,CAAC,MAAM;MAAA;MAAA,UAAG;IAAS;IAAA,mCAErB,gBAAgB;IAAA;MAAA,WAvCzB,iBAAiB,KAAK,CAAC,KAAK,IAAI,EAAE,EAAE;QAAA,OAAc,KAAK,CAAC,KAAK;QAAA,OAMtD,KAAK,CAAC,GAAG,GAAG,EAAE,GAAG,SAAS;MAAA;MAAA;MAAA;MAAA;IAAA;MAAA;MAAA;MAAA;IAAA;IAAA;EAAA;AAoCjD","ignoreList":[]}
|
|
@@ -18,9 +18,8 @@ import BottomSheet, { bottomSheetOptions } from "../layout/BottomSheet";
|
|
|
18
18
|
import { focusMenuRow, focusRowSegment } from "./menu-rows";
|
|
19
19
|
import { filterDropdownItems, MenuSearch } from "./menu-search";
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
export
|
|
23
|
-
export const prefersMenuSheet = () => typeof matchMedia === "function" && matchMedia(PHONE_SHEET_QUERY).matches;
|
|
21
|
+
// Kept apart so a control can check for phones without loading the sheet and its dialog imports.
|
|
22
|
+
export { PHONE_SHEET_QUERY, prefersMenuSheet } from "./phone-sheet";
|
|
24
23
|
/**
|
|
25
24
|
* Follows a link the way a click on it would, so a page's own link handling, such as progressive navigation, still
|
|
26
25
|
* applies; it runs only after the sheet has left the history.
|