@k2b/ui 0.33.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 +15 -4
- package/dist/browser/actions/Dropdown.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/index.js +1 -0
- package/dist/browser/actions/index.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 +525 -407
- package/dist/browser/chat/ChatComposer.js.map +1 -1
- package/dist/browser/chat/chat-messages.js +4 -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/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 +73 -53
- package/dist/browser/content/MessageRow.js.map +1 -1
- package/dist/browser/content/ReactionBar.js +3 -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 +1 -1
- 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/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 +15 -13
- 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/layout/AnchoredPopover.js +180 -0
- package/dist/browser/layout/AnchoredPopover.js.map +1 -0
- package/dist/browser/layout/AppWorkspace.js +155 -20
- 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 +21 -7
- 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 +2 -1
- package/dist/browser/layout/index.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/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 +6 -2
- 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 +14 -4
- package/dist/ssr/actions/Dropdown.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/index.js +1 -0
- package/dist/ssr/actions/index.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 +132 -53
- package/dist/ssr/chat/ChatComposer.js.map +1 -1
- package/dist/ssr/chat/chat-messages.js +4 -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/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 +16 -6
- package/dist/ssr/content/MessageRow.js.map +1 -1
- package/dist/ssr/content/ReactionBar.js +3 -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 +1 -1
- 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/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 +13 -1
- 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/layout/AnchoredPopover.js +142 -0
- package/dist/ssr/layout/AnchoredPopover.js.map +1 -0
- package/dist/ssr/layout/AppWorkspace.js +154 -20
- 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 +20 -6
- 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 +2 -1
- package/dist/ssr/layout/index.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/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 +6 -2
- 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 +5 -0
- package/dist/types/actions/SelectionToolbar.d.ts +38 -0
- package/dist/types/actions/index.d.ts +2 -0
- package/dist/types/charts.d.ts +5 -0
- package/dist/types/chat/ChatComposer.d.ts +15 -0
- package/dist/types/chat/chat-messages.d.ts +2 -0
- package/dist/types/chat/composer-document.d.ts +5 -0
- package/dist/types/chat/index.d.ts +1 -1
- 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 +2 -0
- 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 +2 -2
- package/dist/types/feedback/Tooltip.d.ts +8 -2
- 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/layout/AnchoredPopover.d.ts +31 -0
- package/dist/types/layout/AppWorkspace.d.ts +10 -0
- package/dist/types/layout/DetailPanel.d.ts +17 -0
- package/dist/types/layout/MobileShell.d.ts +5 -2
- 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 +3 -2
- package/dist/types/layout/settings-messages.d.ts +12 -0
- package/dist/types/surfaces/DotStrip.d.ts +22 -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 +6 -1
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import { template as _$template } from "solid-js/web";
|
|
2
|
+
import { style as _$style } from "solid-js/web";
|
|
3
|
+
import { className as _$className } from "solid-js/web";
|
|
4
|
+
import { setAttribute as _$setAttribute } from "solid-js/web";
|
|
5
|
+
import { effect as _$effect } from "solid-js/web";
|
|
6
|
+
import { getNextElement as _$getNextElement } from "solid-js/web";
|
|
7
|
+
import { insert as _$insert } from "solid-js/web";
|
|
8
|
+
import { createComponent as _$createComponent } from "solid-js/web";
|
|
9
|
+
import { use as _$use } from "solid-js/web";
|
|
10
|
+
var _tmpl$ = /*#__PURE__*/_$template(`<div popover=auto role=dialog tabindex=-1>`);
|
|
11
|
+
import { createEffect, createSignal, onCleanup, onMount, Show, untrack } from "solid-js";
|
|
12
|
+
import { returnFocus, ringOnReturn } from "../internal/focus-return";
|
|
13
|
+
const GAP = 6;
|
|
14
|
+
const MARGIN = 8;
|
|
15
|
+
const sheetQuery = "(max-width: 47.999rem)";
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* A panel anchored to a control, for content that is more than a menu, such as a card with a slider. It opens on the
|
|
19
|
+
* side with room and keeps that side while open, so a panel that changes its content never jumps to the other side.
|
|
20
|
+
* Escape, a click outside and another press of the anchor close it; the focus returns to where it was. On a phone it
|
|
21
|
+
* is a bottom sheet.
|
|
22
|
+
*/
|
|
23
|
+
export function AnchoredPopover(props) {
|
|
24
|
+
let surface;
|
|
25
|
+
let previous = null;
|
|
26
|
+
let ring = false;
|
|
27
|
+
let pressedAnchor;
|
|
28
|
+
/** The side chosen when the panel opened; kept until it closes. */
|
|
29
|
+
let openedAbove;
|
|
30
|
+
const [shown, setShown] = createSignal();
|
|
31
|
+
const [sheet, setSheet] = createSignal(false);
|
|
32
|
+
const place = () => {
|
|
33
|
+
const anchor = shown();
|
|
34
|
+
if (!surface || !anchor) return;
|
|
35
|
+
if (!anchor.isConnected) {
|
|
36
|
+
hide();
|
|
37
|
+
props.onClose();
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
if (sheet()) {
|
|
41
|
+
surface.style.left = "";
|
|
42
|
+
surface.style.top = "";
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
const viewport = window.visualViewport;
|
|
46
|
+
const view = {
|
|
47
|
+
top: (viewport?.offsetTop ?? 0) + MARGIN,
|
|
48
|
+
bottom: (viewport ? viewport.offsetTop + viewport.height : window.innerHeight) - MARGIN,
|
|
49
|
+
left: (viewport?.offsetLeft ?? 0) + MARGIN,
|
|
50
|
+
right: (viewport ? viewport.offsetLeft + viewport.width : window.innerWidth) - MARGIN
|
|
51
|
+
};
|
|
52
|
+
const box = anchor.getBoundingClientRect();
|
|
53
|
+
const size = surface.getBoundingClientRect();
|
|
54
|
+
const roomAbove = box.top - GAP - view.top;
|
|
55
|
+
const roomBelow = view.bottom - box.bottom - GAP;
|
|
56
|
+
if (openedAbove === undefined) {
|
|
57
|
+
const planned = Math.max(size.height, props.plannedHeight ?? 0);
|
|
58
|
+
openedAbove = (props.side ?? "below") === "above" ? planned <= roomAbove || roomAbove > roomBelow : planned > roomBelow && roomAbove > roomBelow;
|
|
59
|
+
}
|
|
60
|
+
surface.style.setProperty("--k2b-anchored-popover-room", `${Math.round(Math.max(120, openedAbove ? roomAbove : roomBelow))}px`);
|
|
61
|
+
const top = openedAbove ? box.top - GAP - size.height : box.bottom + GAP;
|
|
62
|
+
const left = (props.align ?? "end") === "end" ? box.right - size.width : box.left;
|
|
63
|
+
surface.style.left = `${Math.round(Math.max(view.left, Math.min(left, view.right - size.width)))}px`;
|
|
64
|
+
surface.style.top = `${Math.round(Math.max(view.top, Math.min(top, view.bottom - size.height)))}px`;
|
|
65
|
+
};
|
|
66
|
+
const restoreFocus = () => {
|
|
67
|
+
const focused = document.activeElement;
|
|
68
|
+
if (focused && focused !== document.body && !surface?.contains(focused)) return;
|
|
69
|
+
if (previous?.isConnected) returnFocus(previous, ring);
|
|
70
|
+
};
|
|
71
|
+
const hide = () => {
|
|
72
|
+
restoreFocus();
|
|
73
|
+
if (surface?.matches(":popover-open")) surface.hidePopover();
|
|
74
|
+
openedAbove = undefined;
|
|
75
|
+
setShown(undefined);
|
|
76
|
+
};
|
|
77
|
+
const pressed = event => {
|
|
78
|
+
const anchor = shown();
|
|
79
|
+
pressedAnchor = anchor && event.target instanceof Node && anchor.contains(event.target) ? anchor : undefined;
|
|
80
|
+
};
|
|
81
|
+
const clicked = event => {
|
|
82
|
+
const anchor = shown();
|
|
83
|
+
if (!anchor || !(event.target instanceof Node) || !anchor.contains(event.target)) return;
|
|
84
|
+
pressedAnchor = anchor;
|
|
85
|
+
hide();
|
|
86
|
+
props.onClose();
|
|
87
|
+
};
|
|
88
|
+
createEffect(() => {
|
|
89
|
+
const anchor = props.anchor ?? undefined;
|
|
90
|
+
untrack(() => {
|
|
91
|
+
if (!anchor) {
|
|
92
|
+
if (shown()) hide();
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
if (anchor === pressedAnchor) {
|
|
96
|
+
pressedAnchor = undefined;
|
|
97
|
+
props.onClose();
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
if (shown() === anchor || !surface) return;
|
|
101
|
+
if (!shown()) {
|
|
102
|
+
previous = document.activeElement instanceof HTMLElement ? document.activeElement : null;
|
|
103
|
+
ring = ringOnReturn(previous ?? anchor);
|
|
104
|
+
}
|
|
105
|
+
setSheet(typeof matchMedia === "function" && matchMedia(sheetQuery).matches);
|
|
106
|
+
setShown(anchor);
|
|
107
|
+
if (!surface.matches(":popover-open")) surface.showPopover();
|
|
108
|
+
place();
|
|
109
|
+
queueMicrotask(() => (props.initialFocus?.() ?? surface)?.focus({
|
|
110
|
+
preventScroll: true
|
|
111
|
+
}));
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
const scrolled = event => {
|
|
115
|
+
if (!(event.target instanceof Node && surface?.contains(event.target))) place();
|
|
116
|
+
};
|
|
117
|
+
onMount(() => {
|
|
118
|
+
window.addEventListener("resize", place);
|
|
119
|
+
window.addEventListener("scroll", scrolled, true);
|
|
120
|
+
window.visualViewport?.addEventListener("resize", place);
|
|
121
|
+
document.addEventListener("pointerdown", pressed, true);
|
|
122
|
+
document.addEventListener("click", clicked, true);
|
|
123
|
+
const observer = typeof ResizeObserver === "function" && surface ? new ResizeObserver(place) : undefined;
|
|
124
|
+
if (surface) observer?.observe(surface);
|
|
125
|
+
onCleanup(() => {
|
|
126
|
+
observer?.disconnect();
|
|
127
|
+
window.removeEventListener("resize", place);
|
|
128
|
+
window.removeEventListener("scroll", scrolled, true);
|
|
129
|
+
window.visualViewport?.removeEventListener("resize", place);
|
|
130
|
+
document.removeEventListener("pointerdown", pressed, true);
|
|
131
|
+
document.removeEventListener("click", clicked, true);
|
|
132
|
+
if (surface?.matches(":popover-open")) hide();
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
return (() => {
|
|
136
|
+
var _el$ = _$getNextElement(_tmpl$);
|
|
137
|
+
_el$.addEventListener("toggle", event => {
|
|
138
|
+
if (event.newState === "open") return;
|
|
139
|
+
if (shown()) {
|
|
140
|
+
openedAbove = undefined;
|
|
141
|
+
setShown(undefined);
|
|
142
|
+
restoreFocus();
|
|
143
|
+
props.onClose();
|
|
144
|
+
}
|
|
145
|
+
setTimeout(() => {
|
|
146
|
+
pressedAnchor = undefined;
|
|
147
|
+
});
|
|
148
|
+
});
|
|
149
|
+
var _ref$ = surface;
|
|
150
|
+
typeof _ref$ === "function" ? _$use(_ref$, _el$) : surface = _el$;
|
|
151
|
+
_$insert(_el$, _$createComponent(Show, {
|
|
152
|
+
get when() {
|
|
153
|
+
return shown();
|
|
154
|
+
},
|
|
155
|
+
get children() {
|
|
156
|
+
return props.children;
|
|
157
|
+
}
|
|
158
|
+
}));
|
|
159
|
+
_$effect(_p$ => {
|
|
160
|
+
var _v$ = props.label,
|
|
161
|
+
_v$2 = ["k2b-anchored-popover", props.class].filter(Boolean).join(" "),
|
|
162
|
+
_v$3 = sheet() ? "" : undefined,
|
|
163
|
+
_v$4 = props.width ? {
|
|
164
|
+
"--k2b-anchored-popover-width": props.width
|
|
165
|
+
} : undefined;
|
|
166
|
+
_v$ !== _p$.e && _$setAttribute(_el$, "aria-label", _p$.e = _v$);
|
|
167
|
+
_v$2 !== _p$.t && _$className(_el$, _p$.t = _v$2);
|
|
168
|
+
_v$3 !== _p$.a && _$setAttribute(_el$, "data-sheet", _p$.a = _v$3);
|
|
169
|
+
_p$.o = _$style(_el$, _v$4, _p$.o);
|
|
170
|
+
return _p$;
|
|
171
|
+
}, {
|
|
172
|
+
e: undefined,
|
|
173
|
+
t: undefined,
|
|
174
|
+
a: undefined,
|
|
175
|
+
o: undefined
|
|
176
|
+
});
|
|
177
|
+
return _el$;
|
|
178
|
+
})();
|
|
179
|
+
}
|
|
180
|
+
//# sourceMappingURL=AnchoredPopover.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":[],"sources":["layout/AnchoredPopover.tsx"],"sourcesContent":["import { createEffect, createSignal, type JSX, onCleanup, onMount, Show, untrack } from \"solid-js\";\nimport { returnFocus, ringOnReturn } from \"../internal/focus-return\";\n\nexport type AnchoredPopoverProps = {\n /** The control the panel belongs to. The panel is open while this is set. */\n anchor: HTMLElement | null | undefined;\n /** Called on Escape, a click outside, another press of the anchor, and when the anchor leaves the page. */\n onClose: () => void;\n /** The panel's accessible name; it is a non-modal dialog. */\n label: string;\n children: JSX.Element;\n /** Which edge lines up with the anchor. Defaults to `end`, like a menu at the end of a toolbar. */\n align?: \"start\" | \"end\";\n /** The side tried first; the panel flips only when the other side has more room. Defaults to `below`. */\n side?: \"below\" | \"above\";\n /**\n * The tallest the panel gets while open, in px, such as a list it can switch to. The side is chosen for this height\n * and kept, so a panel that grows never flips. Defaults to its height when it opens.\n */\n plannedHeight?: number;\n /** Width of the panel on wide screens, such as `21rem`. On a phone it is a bottom sheet across the screen. */\n width?: string;\n /** Moves the focus into the panel when it opens; defaults to the panel itself. */\n initialFocus?: () => HTMLElement | null | undefined;\n class?: string;\n};\n\nconst GAP = 6;\nconst MARGIN = 8;\nconst sheetQuery = \"(max-width: 47.999rem)\";\n\n/**\n * A panel anchored to a control, for content that is more than a menu, such as a card with a slider. It opens on the\n * side with room and keeps that side while open, so a panel that changes its content never jumps to the other side.\n * Escape, a click outside and another press of the anchor close it; the focus returns to where it was. On a phone it\n * is a bottom sheet.\n */\nexport function AnchoredPopover(props: AnchoredPopoverProps): JSX.Element {\n let surface: HTMLDivElement | undefined;\n let previous: HTMLElement | null = null;\n let ring = false;\n let pressedAnchor: HTMLElement | undefined;\n /** The side chosen when the panel opened; kept until it closes. */\n let openedAbove: boolean | undefined;\n const [shown, setShown] = createSignal<HTMLElement>();\n const [sheet, setSheet] = createSignal(false);\n\n const place = () => {\n const anchor = shown();\n if (!surface || !anchor) return;\n if (!anchor.isConnected) {\n hide();\n props.onClose();\n return;\n }\n if (sheet()) {\n surface.style.left = \"\";\n surface.style.top = \"\";\n return;\n }\n const viewport = window.visualViewport;\n const view = {\n top: (viewport?.offsetTop ?? 0) + MARGIN,\n bottom: (viewport ? viewport.offsetTop + viewport.height : window.innerHeight) - MARGIN,\n left: (viewport?.offsetLeft ?? 0) + MARGIN,\n right: (viewport ? viewport.offsetLeft + viewport.width : window.innerWidth) - MARGIN,\n };\n const box = anchor.getBoundingClientRect();\n const size = surface.getBoundingClientRect();\n const roomAbove = box.top - GAP - view.top;\n const roomBelow = view.bottom - box.bottom - GAP;\n if (openedAbove === undefined) {\n const planned = Math.max(size.height, props.plannedHeight ?? 0);\n openedAbove =\n (props.side ?? \"below\") === \"above\" ? planned <= roomAbove || roomAbove > roomBelow : planned > roomBelow && roomAbove > roomBelow;\n }\n surface.style.setProperty(\"--k2b-anchored-popover-room\", `${Math.round(Math.max(120, openedAbove ? roomAbove : roomBelow))}px`);\n const top = openedAbove ? box.top - GAP - size.height : box.bottom + GAP;\n const left = (props.align ?? \"end\") === \"end\" ? box.right - size.width : box.left;\n surface.style.left = `${Math.round(Math.max(view.left, Math.min(left, view.right - size.width)))}px`;\n surface.style.top = `${Math.round(Math.max(view.top, Math.min(top, view.bottom - size.height)))}px`;\n };\n\n const restoreFocus = () => {\n const focused = document.activeElement;\n if (focused && focused !== document.body && !surface?.contains(focused)) return;\n if (previous?.isConnected) returnFocus(previous, ring);\n };\n\n const hide = () => {\n restoreFocus();\n if (surface?.matches(\":popover-open\")) surface.hidePopover();\n openedAbove = undefined;\n setShown(undefined);\n };\n\n const pressed = (event: PointerEvent) => {\n const anchor = shown();\n pressedAnchor = anchor && event.target instanceof Node && anchor.contains(event.target) ? anchor : undefined;\n };\n const clicked = (event: MouseEvent) => {\n const anchor = shown();\n if (!anchor || !(event.target instanceof Node) || !anchor.contains(event.target)) return;\n pressedAnchor = anchor;\n hide();\n props.onClose();\n };\n\n createEffect(() => {\n const anchor = props.anchor ?? undefined;\n untrack(() => {\n if (!anchor) {\n if (shown()) hide();\n return;\n }\n if (anchor === pressedAnchor) {\n pressedAnchor = undefined;\n props.onClose();\n return;\n }\n if (shown() === anchor || !surface) return;\n if (!shown()) {\n previous = document.activeElement instanceof HTMLElement ? document.activeElement : null;\n ring = ringOnReturn(previous ?? anchor);\n }\n setSheet(typeof matchMedia === \"function\" && matchMedia(sheetQuery).matches);\n setShown(anchor);\n if (!surface.matches(\":popover-open\")) surface.showPopover();\n place();\n queueMicrotask(() => (props.initialFocus?.() ?? surface)?.focus({ preventScroll: true }));\n });\n });\n\n const scrolled = (event: Event) => {\n if (!(event.target instanceof Node && surface?.contains(event.target))) place();\n };\n\n onMount(() => {\n window.addEventListener(\"resize\", place);\n window.addEventListener(\"scroll\", scrolled, true);\n window.visualViewport?.addEventListener(\"resize\", place);\n document.addEventListener(\"pointerdown\", pressed, true);\n document.addEventListener(\"click\", clicked, true);\n const observer = typeof ResizeObserver === \"function\" && surface ? new ResizeObserver(place) : undefined;\n if (surface) observer?.observe(surface);\n onCleanup(() => {\n observer?.disconnect();\n window.removeEventListener(\"resize\", place);\n window.removeEventListener(\"scroll\", scrolled, true);\n window.visualViewport?.removeEventListener(\"resize\", place);\n document.removeEventListener(\"pointerdown\", pressed, true);\n document.removeEventListener(\"click\", clicked, true);\n if (surface?.matches(\":popover-open\")) hide();\n });\n });\n\n return (\n <div\n ref={surface}\n popover=\"auto\"\n role=\"dialog\"\n aria-label={props.label}\n tabIndex={-1}\n class={[\"k2b-anchored-popover\", props.class].filter(Boolean).join(\" \")}\n data-sheet={sheet() ? \"\" : undefined}\n style={props.width ? { \"--k2b-anchored-popover-width\": props.width } : undefined}\n onToggle={(event) => {\n if ((event as ToggleEvent).newState === \"open\") return;\n if (shown()) {\n openedAbove = undefined;\n setShown(undefined);\n restoreFocus();\n props.onClose();\n }\n setTimeout(() => {\n pressedAnchor = undefined;\n });\n }}\n >\n <Show when={shown()}>{props.children}</Show>\n </div>\n );\n}\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -87,6 +87,7 @@ import { Dynamic, isServer } from "solid-js/web";
|
|
|
87
87
|
import { Button, ButtonLink, IconButton, IconButtonLink } from "../actions/Button";
|
|
88
88
|
import { useFilterMessages } from "../actions/filter-messages";
|
|
89
89
|
import { dialogCore } from "../feedback/dialog-core";
|
|
90
|
+
import { Tooltip } from "../feedback/Tooltip";
|
|
90
91
|
import { RenderErrorBoundary } from "../internal/render-error";
|
|
91
92
|
import { APP_WORKSPACE_DETAIL_CLOSE_EVENT, APP_WORKSPACE_DETAIL_OPEN_EVENT, APP_WORKSPACE_DETAIL_STEP_EVENT, APP_WORKSPACE_SIDEBAR_HIDE_EVENT, installAppWorkspaceController } from "./app-workspace-controller";
|
|
92
93
|
import { APP_WORKSPACE_DETAIL_DEFAULT, APP_WORKSPACE_DETAIL_MAX, APP_WORKSPACE_DETAIL_MIN, APP_WORKSPACE_DRAWER_DEFAULT, APP_WORKSPACE_DRAWER_MAX, APP_WORKSPACE_DRAWER_MIN, APP_WORKSPACE_MAIN_MIN, APP_WORKSPACE_PANE_DEFAULT, APP_WORKSPACE_PANE_MAX, APP_WORKSPACE_PANE_MIN, APP_WORKSPACE_SIDEBAR_COLLAPSED, APP_WORKSPACE_SIDEBAR_DEFAULT, APP_WORKSPACE_SIDEBAR_MAX, APP_WORKSPACE_SIDEBAR_MIN, appWorkspaceLayoutStyle, appWorkspacePanelVariable } from "./app-workspace-state";
|
|
@@ -94,11 +95,23 @@ import { appWorkspaceInverseWidthCss, appWorkspaceWidthCss, appWorkspaceWidthTok
|
|
|
94
95
|
import BottomSheet, { bottomSheetAdaptiveOptions } from "./BottomSheet";
|
|
95
96
|
import { PageTitle, usePageTrail } from "./PageTitle";
|
|
96
97
|
import { SidebarItemPreview } from "./SidebarItemPreview";
|
|
98
|
+
import { inSidebarRail, SidebarRailHint } from "./SidebarRailHint";
|
|
97
99
|
import { AppWorkspaceSidebarSwitcher } from "./SidebarSwitcher";
|
|
98
100
|
import { createScrollFade, scrollFadeEdges } from "./scroll-fade";
|
|
99
101
|
import { rememberSidebarScroll } from "./sidebar-scroll-memory";
|
|
100
102
|
import { assertStableUiId, assertUniqueStableUiIds } from "./stable-id";
|
|
101
103
|
import { useWorkspaceMessages } from "./workspace-messages";
|
|
104
|
+
/** The narrowest container of each levels width class, as the stylesheet's breakpoints define them (48rem, 80rem). */
|
|
105
|
+
const LEVEL_CLASS_WIDTH = {
|
|
106
|
+
1: 0,
|
|
107
|
+
2: 768,
|
|
108
|
+
3: 1280
|
|
109
|
+
};
|
|
110
|
+
/** The last shown level's minimum width when the level does not declare one; the stylesheet uses the same value. */
|
|
111
|
+
const LEVEL_LAST_MIN = 320;
|
|
112
|
+
/** The width the last shown level keeps at least: its declared minimum, never below the default. */
|
|
113
|
+
const levelLastMin = minSize => Math.max(minSize ?? 0, LEVEL_LAST_MIN);
|
|
114
|
+
const nonEmptyStyle = style => Object.keys(style).length ? style : undefined;
|
|
102
115
|
const ResizeContext = createContext(true);
|
|
103
116
|
/** The enclosing workspace: its head names the sidebar, and a nested workspace leaves the page title to it. */
|
|
104
117
|
const WorkspaceContext = createContext();
|
|
@@ -335,8 +348,20 @@ function AppWorkspaceMain(props) {
|
|
|
335
348
|
return open;
|
|
336
349
|
});
|
|
337
350
|
const depth = () => Math.max(1, levels().findIndex(pane => pane.props.id === props.level) + 1);
|
|
351
|
+
/** How many of the deepest levels a width class shows: up to its count, as long as their minimum widths fit. */
|
|
352
|
+
const levelCount = widthClass => {
|
|
353
|
+
const all = levels();
|
|
354
|
+
let count = Math.min(widthClass, all.length);
|
|
355
|
+
while (count > 1) {
|
|
356
|
+
const end = Math.max(depth(), count);
|
|
357
|
+
const needed = all.slice(end - count, end).reduce((sum, pane, offset) => sum + (end - count + offset + 1 === end ? levelLastMin(pane.props.minSize) : pane.props.minSize ?? APP_WORKSPACE_PANE_MIN), 0);
|
|
358
|
+
if (needed <= LEVEL_CLASS_WIDTH[widthClass]) break;
|
|
359
|
+
count--;
|
|
360
|
+
}
|
|
361
|
+
return count;
|
|
362
|
+
};
|
|
338
363
|
const levelClasses = (index, kind) => [1, 2, 3].filter(widthClass => {
|
|
339
|
-
const count =
|
|
364
|
+
const count = levelCount(widthClass);
|
|
340
365
|
const end = Math.max(depth(), count);
|
|
341
366
|
const start = end - count + 1;
|
|
342
367
|
return kind === "first" ? index === start && index > 1 : kind === "last" ? index === end : kind === "handle" ? index >= start && index + 1 <= end : index >= start && index <= end;
|
|
@@ -581,11 +606,18 @@ function AppWorkspaceMain(props) {
|
|
|
581
606
|
_v$24 = pane.props.surface === "navigation" ? "navigation" : undefined,
|
|
582
607
|
_v$25 = !levelsMode() && pane.props.scroll === false ? "false" : undefined,
|
|
583
608
|
_v$26 = !levelsMode() && pane.props.scroll !== false && pane.props.scrollFade !== false ? "both" : undefined,
|
|
584
|
-
_v$27 =
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
609
|
+
_v$27 = nonEmptyStyle({
|
|
610
|
+
...(isAnchor() ? {} : {
|
|
611
|
+
// A stored width keeps to this pane's limits before the controller attaches.
|
|
612
|
+
"--k2b-workspace-panel-size": `clamp(${minSize()}px, var(${variable}, ${appWorkspaceWidthCss(defaultSize(), "var(--k2b-workspace-width)")}), ${maxSize()}px)`,
|
|
613
|
+
"--k2b-workspace-panel-min": `${minSize()}px`
|
|
614
|
+
}),
|
|
615
|
+
// The last shown level fills the rest, but never below its minimum; set on every level, so a workspace
|
|
616
|
+
// nested in a wide level does not inherit that minimum.
|
|
617
|
+
...(levelsMode() ? {
|
|
618
|
+
"--k2b-workspace-level-min": `${levelLastMin(pane.props.minSize)}px`
|
|
619
|
+
} : {})
|
|
620
|
+
});
|
|
589
621
|
_v$14 !== _p$.e && _$setAttribute(_el$18, "id", _p$.e = _v$14);
|
|
590
622
|
_v$15 !== _p$.t && _$className(_el$18, _p$.t = _v$15);
|
|
591
623
|
_v$16 !== _p$.a && _$setAttribute(_el$18, "aria-label", _p$.a = _v$16);
|
|
@@ -1411,13 +1443,73 @@ const AppWorkspaceSidebarItemStatus = props => {
|
|
|
1411
1443
|
return _el$55;
|
|
1412
1444
|
})();
|
|
1413
1445
|
};
|
|
1446
|
+
/**
|
|
1447
|
+
* Hover actions overlay a row's end, so the label and count under them fade
|
|
1448
|
+
* out while they show. The row measures how far the overlay reaches into its
|
|
1449
|
+
* count (`--k2b-sidebar-item-cover`) and how much of that the count and gap
|
|
1450
|
+
* after the label already take (`--k2b-sidebar-item-label-trail`), so the
|
|
1451
|
+
* label keeps all the width the overlay leaves it. The stylesheet applies
|
|
1452
|
+
* both only while the overlay shows, and assumes its usual size until then.
|
|
1453
|
+
*/
|
|
1454
|
+
function observeSidebarRowCover(row) {
|
|
1455
|
+
if (isServer || typeof ResizeObserver === "undefined") return;
|
|
1456
|
+
// A hidden count, such as an empty status, or hidden actions have no box to measure from.
|
|
1457
|
+
const laidOut = element => Boolean(element?.getClientRects().length);
|
|
1458
|
+
const measure = () => {
|
|
1459
|
+
const main = row.querySelector(":scope > .k2b-app-workspace__sidebar-item-main");
|
|
1460
|
+
const label = main?.querySelector(":scope > :is(.k2b-app-workspace__sidebar-item-copy, .k2b-app-workspace__sidebar-item-label)");
|
|
1461
|
+
const overlays = Array.from(row.querySelectorAll(':scope > .k2b-app-workspace__sidebar-item-actions[data-visibility="hover"]:last-child, :scope > .k2b-app-workspace__sidebar-item-action[data-visibility="hover"]')).filter(element => laidOut(element) && getComputedStyle(element).position === "absolute");
|
|
1462
|
+
if (!main || !laidOut(label) || !overlays.length) {
|
|
1463
|
+
row.style.removeProperty("--k2b-sidebar-item-cover");
|
|
1464
|
+
row.style.removeProperty("--k2b-sidebar-item-label-trail");
|
|
1465
|
+
return;
|
|
1466
|
+
}
|
|
1467
|
+
// Lengths along the inline axis, measured toward the row's end.
|
|
1468
|
+
const rtl = getComputedStyle(row).direction === "rtl";
|
|
1469
|
+
const end = element => {
|
|
1470
|
+
const box = element.getBoundingClientRect();
|
|
1471
|
+
return rtl ? -box.left : box.right;
|
|
1472
|
+
};
|
|
1473
|
+
const start = Math.min(...overlays.map(element => {
|
|
1474
|
+
const box = element.getBoundingClientRect();
|
|
1475
|
+
return rtl ? -box.right : box.left;
|
|
1476
|
+
}));
|
|
1477
|
+
const meta = main.querySelector(":scope > .k2b-app-workspace__sidebar-item-meta");
|
|
1478
|
+
const content = end(laidOut(meta) ? meta : label);
|
|
1479
|
+
row.style.setProperty("--k2b-sidebar-item-cover", `${Math.max(0, content - start)}px`);
|
|
1480
|
+
row.style.setProperty("--k2b-sidebar-item-label-trail", `${Math.max(0, content - end(label))}px`);
|
|
1481
|
+
};
|
|
1482
|
+
const resized = new ResizeObserver(measure);
|
|
1483
|
+
// The label, the count, and the actions can be replaced while the row stays.
|
|
1484
|
+
const replaced = new MutationObserver(() => observe());
|
|
1485
|
+
const observe = () => {
|
|
1486
|
+
const main = row.querySelector(":scope > .k2b-app-workspace__sidebar-item-main");
|
|
1487
|
+
if (main) replaced.observe(main, {
|
|
1488
|
+
childList: true
|
|
1489
|
+
});
|
|
1490
|
+
resized.disconnect();
|
|
1491
|
+
resized.observe(row);
|
|
1492
|
+
for (const element of row.querySelectorAll(":scope > .k2b-app-workspace__sidebar-item-main > :is(.k2b-app-workspace__sidebar-item-copy, .k2b-app-workspace__sidebar-item-label, .k2b-app-workspace__sidebar-item-meta), :scope > :is(.k2b-app-workspace__sidebar-item-actions, .k2b-app-workspace__sidebar-item-action)")) resized.observe(element);
|
|
1493
|
+
};
|
|
1494
|
+
replaced.observe(row, {
|
|
1495
|
+
childList: true
|
|
1496
|
+
});
|
|
1497
|
+
observe();
|
|
1498
|
+
onCleanup(() => {
|
|
1499
|
+
replaced.disconnect();
|
|
1500
|
+
resized.disconnect();
|
|
1501
|
+
});
|
|
1502
|
+
}
|
|
1503
|
+
|
|
1414
1504
|
/** Shared visual and semantic row frame for flat sidebar items and tree items. */
|
|
1415
1505
|
function AppWorkspaceSidebarRow(props) {
|
|
1506
|
+
const [link, setLink] = createSignal();
|
|
1507
|
+
const [hinted, setHinted] = createSignal(false);
|
|
1416
1508
|
const className = () => `k2b-app-workspace__sidebar-item ${props.hasActions ? "has-action" : ""} ${props.active ? props.activeClass ?? "is-active" : ""} ${props.class ?? ""}`;
|
|
1417
1509
|
const data = () => Object.fromEntries(Object.entries(props.data ?? {}).filter(([, value]) => value !== undefined && value !== null).map(([key, value]) => [`data-${key}`, String(value)]));
|
|
1418
1510
|
const common = () => ({
|
|
1419
1511
|
class: className(),
|
|
1420
|
-
title: props.title,
|
|
1512
|
+
title: hinted() ? undefined : props.title,
|
|
1421
1513
|
"data-tone": props.tone,
|
|
1422
1514
|
style: {
|
|
1423
1515
|
"view-transition-name": props.viewTransitionName,
|
|
@@ -1427,9 +1519,12 @@ function AppWorkspaceSidebarRow(props) {
|
|
|
1427
1519
|
});
|
|
1428
1520
|
const current = () => props.active === "ancestor" ? "true" : props.active ? "page" : undefined;
|
|
1429
1521
|
const Control = control => {
|
|
1430
|
-
const attrs = () =>
|
|
1431
|
-
|
|
1432
|
-
|
|
1522
|
+
const attrs = () => ({
|
|
1523
|
+
...(control.grouped ? {
|
|
1524
|
+
class: "k2b-app-workspace__sidebar-item-main"
|
|
1525
|
+
} : common()),
|
|
1526
|
+
ref: setLink
|
|
1527
|
+
});
|
|
1433
1528
|
return _$createComponent(Show, {
|
|
1434
1529
|
get when() {
|
|
1435
1530
|
return Boolean(props.href && !props.disabled);
|
|
@@ -1514,7 +1609,7 @@ function AppWorkspaceSidebarRow(props) {
|
|
|
1514
1609
|
}
|
|
1515
1610
|
});
|
|
1516
1611
|
};
|
|
1517
|
-
return _$createComponent(Show, {
|
|
1612
|
+
return [_$createComponent(Show, {
|
|
1518
1613
|
get when() {
|
|
1519
1614
|
return props.hasActions;
|
|
1520
1615
|
},
|
|
@@ -1529,6 +1624,7 @@ function AppWorkspaceSidebarRow(props) {
|
|
|
1529
1624
|
[_el$69, _co$1] = _$getNextMarker(_el$68.nextSibling),
|
|
1530
1625
|
_el$70 = _el$69.nextSibling,
|
|
1531
1626
|
[_el$71, _co$10] = _$getNextMarker(_el$70.nextSibling);
|
|
1627
|
+
_$use(row => onMount(() => observeSidebarRowCover(row)), _el$67);
|
|
1532
1628
|
_$spread(_el$67, _$mergeProps(common, {
|
|
1533
1629
|
get ["data-disabled"]() {
|
|
1534
1630
|
return props.disabled ? "true" : undefined;
|
|
@@ -1541,7 +1637,26 @@ function AppWorkspaceSidebarRow(props) {
|
|
|
1541
1637
|
_$runHydrationEvents();
|
|
1542
1638
|
return _el$67;
|
|
1543
1639
|
}
|
|
1544
|
-
})
|
|
1640
|
+
}), _$createComponent(Show, {
|
|
1641
|
+
get when() {
|
|
1642
|
+
return link();
|
|
1643
|
+
},
|
|
1644
|
+
keyed: true,
|
|
1645
|
+
children: element => _$createComponent(SidebarRailHint, {
|
|
1646
|
+
target: () => element,
|
|
1647
|
+
get label() {
|
|
1648
|
+
return props.title ?? props.hint;
|
|
1649
|
+
},
|
|
1650
|
+
get focusTarget() {
|
|
1651
|
+
return props.focusTarget ?? (() => element);
|
|
1652
|
+
},
|
|
1653
|
+
labelSelector: ".k2b-app-workspace__sidebar-item-label-text",
|
|
1654
|
+
get titled() {
|
|
1655
|
+
return props.title !== undefined;
|
|
1656
|
+
},
|
|
1657
|
+
onArm: () => setHinted(true)
|
|
1658
|
+
})
|
|
1659
|
+
})];
|
|
1545
1660
|
}
|
|
1546
1661
|
function AppWorkspaceSidebarItem(props) {
|
|
1547
1662
|
const workspaceMessages = useWorkspaceMessages();
|
|
@@ -1794,6 +1909,9 @@ function AppWorkspaceSidebarItem(props) {
|
|
|
1794
1909
|
get title() {
|
|
1795
1910
|
return props.title;
|
|
1796
1911
|
},
|
|
1912
|
+
get hint() {
|
|
1913
|
+
return _$memo(() => typeof label() === "string")() ? label() : undefined;
|
|
1914
|
+
},
|
|
1797
1915
|
get viewTransitionName() {
|
|
1798
1916
|
return props.viewTransitionName;
|
|
1799
1917
|
},
|
|
@@ -1911,7 +2029,7 @@ const AppWorkspaceNavTree = props => {
|
|
|
1911
2029
|
},
|
|
1912
2030
|
children: (item, place) => {
|
|
1913
2031
|
const nested = createMemo(() => navTreeItems(item.children));
|
|
1914
|
-
const hasChildren = () => nested().length > 0;
|
|
2032
|
+
const hasChildren = () => item.hasChildren ?? nested().length > 0;
|
|
1915
2033
|
const selected = () => props.selectedId === item.id;
|
|
1916
2034
|
const siblingIndex = id => siblings().findIndex(sibling => sibling.id === id);
|
|
1917
2035
|
const movable = () => Boolean(props.onMove && item.movable && !item.disabled);
|
|
@@ -2120,6 +2238,10 @@ const AppWorkspaceNavTree = props => {
|
|
|
2120
2238
|
get title() {
|
|
2121
2239
|
return item.title;
|
|
2122
2240
|
},
|
|
2241
|
+
get hint() {
|
|
2242
|
+
return _$memo(() => typeof item.label === "string")() ? item.label : undefined;
|
|
2243
|
+
},
|
|
2244
|
+
focusTarget: () => treeItem,
|
|
2123
2245
|
get viewTransitionName() {
|
|
2124
2246
|
return item.viewTransitionName;
|
|
2125
2247
|
},
|
|
@@ -2335,14 +2457,15 @@ const AppWorkspaceSidebarIconGrid = props => (() => {
|
|
|
2335
2457
|
return _el$109;
|
|
2336
2458
|
})();
|
|
2337
2459
|
const AppWorkspaceSidebarIconAction = props => {
|
|
2460
|
+
let target;
|
|
2338
2461
|
const content = (() => {
|
|
2339
2462
|
var _el$114 = _$getNextElement(_tmpl$54);
|
|
2340
2463
|
_$effect(() => _$className(_el$114, iconClass(props.icon)));
|
|
2341
2464
|
return _el$114;
|
|
2342
2465
|
})();
|
|
2343
2466
|
const attrs = () => ({
|
|
2467
|
+
ref: element => target = element,
|
|
2344
2468
|
class: `k2b-app-workspace__sidebar-icon-action ${props.active ? "is-active" : ""}`,
|
|
2345
|
-
title: props.label,
|
|
2346
2469
|
"aria-label": props.label,
|
|
2347
2470
|
"data-tone": props.tone,
|
|
2348
2471
|
style: {
|
|
@@ -2350,7 +2473,19 @@ const AppWorkspaceSidebarIconAction = props => {
|
|
|
2350
2473
|
},
|
|
2351
2474
|
...modeAttrs(props.sidebarMode)
|
|
2352
2475
|
});
|
|
2353
|
-
|
|
2476
|
+
// The icon never shows its label, so the hint names it in every state; in the collapsed rail it sits beside the
|
|
2477
|
+
// icon like the rail's other entries.
|
|
2478
|
+
const hint = _$createComponent(Tooltip, {
|
|
2479
|
+
target: () => target,
|
|
2480
|
+
get content() {
|
|
2481
|
+
return props.label;
|
|
2482
|
+
},
|
|
2483
|
+
get placement() {
|
|
2484
|
+
return inSidebarRail(target) ? "right" : undefined;
|
|
2485
|
+
},
|
|
2486
|
+
delay: 0
|
|
2487
|
+
});
|
|
2488
|
+
if (!props.href || props.disabled) return [(() => {
|
|
2354
2489
|
var _el$115 = _$getNextElement(_tmpl$33);
|
|
2355
2490
|
_$spread(_el$115, _$mergeProps(attrs, {
|
|
2356
2491
|
get disabled() {
|
|
@@ -2363,8 +2498,8 @@ const AppWorkspaceSidebarIconAction = props => {
|
|
|
2363
2498
|
_$insert(_el$115, content);
|
|
2364
2499
|
_$runHydrationEvents();
|
|
2365
2500
|
return _el$115;
|
|
2366
|
-
})();
|
|
2367
|
-
if (props.navigation !== "enhanced" || !props.onNavigate) return (() => {
|
|
2501
|
+
})(), hint];
|
|
2502
|
+
if (props.navigation !== "enhanced" || !props.onNavigate) return [(() => {
|
|
2368
2503
|
var _el$116 = _$getNextElement(_tmpl$34);
|
|
2369
2504
|
_$spread(_el$116, _$mergeProps({
|
|
2370
2505
|
get href() {
|
|
@@ -2378,8 +2513,8 @@ const AppWorkspaceSidebarIconAction = props => {
|
|
|
2378
2513
|
_$insert(_el$116, content);
|
|
2379
2514
|
_$runHydrationEvents();
|
|
2380
2515
|
return _el$116;
|
|
2381
|
-
})();
|
|
2382
|
-
return _$createComponent(Link, _$mergeProps({
|
|
2516
|
+
})(), hint];
|
|
2517
|
+
return [_$createComponent(Link, _$mergeProps({
|
|
2383
2518
|
get href() {
|
|
2384
2519
|
return props.href;
|
|
2385
2520
|
}
|
|
@@ -2397,7 +2532,7 @@ const AppWorkspaceSidebarIconAction = props => {
|
|
|
2397
2532
|
return props.onClick;
|
|
2398
2533
|
},
|
|
2399
2534
|
children: content
|
|
2400
|
-
}));
|
|
2535
|
+
})), hint];
|
|
2401
2536
|
};
|
|
2402
2537
|
/**
|
|
2403
2538
|
* The row above the work area. From 48 to 64 rem it holds the button that
|