@k2b/ui 0.33.0 → 0.35.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.
Files changed (310) hide show
  1. package/dist/base.css +14 -1
  2. package/dist/browser/actions/ContextMenu.js +13 -0
  3. package/dist/browser/actions/ContextMenu.js.map +1 -1
  4. package/dist/browser/actions/Dropdown.js +16 -4
  5. package/dist/browser/actions/Dropdown.js.map +1 -1
  6. package/dist/browser/actions/SelectionToolbar.js +129 -0
  7. package/dist/browser/actions/SelectionToolbar.js.map +1 -0
  8. package/dist/browser/actions/index.js +1 -0
  9. package/dist/browser/actions/index.js.map +1 -1
  10. package/dist/browser/charts.js +6 -0
  11. package/dist/browser/charts.js.map +1 -0
  12. package/dist/browser/chat/ChatComposer.js +525 -407
  13. package/dist/browser/chat/ChatComposer.js.map +1 -1
  14. package/dist/browser/chat/chat-messages.js +4 -0
  15. package/dist/browser/chat/chat-messages.js.map +1 -1
  16. package/dist/browser/chat/composer-document.js +19 -0
  17. package/dist/browser/chat/composer-document.js.map +1 -1
  18. package/dist/browser/chat/index.js.map +1 -1
  19. package/dist/browser/content/Chart.js +8 -0
  20. package/dist/browser/content/Chart.js.map +1 -1
  21. package/dist/browser/content/FileGrid.js +231 -9
  22. package/dist/browser/content/FileGrid.js.map +1 -1
  23. package/dist/browser/content/FileTypeIcon.js +15 -0
  24. package/dist/browser/content/FileTypeIcon.js.map +1 -1
  25. package/dist/browser/content/FileView.js +11 -4
  26. package/dist/browser/content/FileView.js.map +1 -1
  27. package/dist/browser/content/MatchText.js +61 -0
  28. package/dist/browser/content/MatchText.js.map +1 -0
  29. package/dist/browser/content/MessageRow.js +73 -53
  30. package/dist/browser/content/MessageRow.js.map +1 -1
  31. package/dist/browser/content/ReactionBar.js +3 -1
  32. package/dist/browser/content/ReactionBar.js.map +1 -1
  33. package/dist/browser/content/calendar-day-scroll.js +4 -3
  34. package/dist/browser/content/calendar-day-scroll.js.map +1 -1
  35. package/dist/browser/content/chart-bar.js +476 -0
  36. package/dist/browser/content/chart-bar.js.map +1 -0
  37. package/dist/browser/content/file-list-messages.js +52 -0
  38. package/dist/browser/content/file-list-messages.js.map +1 -0
  39. package/dist/browser/content/index.js +2 -1
  40. package/dist/browser/content/index.js.map +1 -1
  41. package/dist/browser/feedback/Tooltip.js +31 -14
  42. package/dist/browser/feedback/Tooltip.js.map +1 -1
  43. package/dist/browser/inputs/ChoiceList.js +178 -0
  44. package/dist/browser/inputs/ChoiceList.js.map +1 -0
  45. package/dist/browser/inputs/ChoiceSlider.js +314 -0
  46. package/dist/browser/inputs/ChoiceSlider.js.map +1 -0
  47. package/dist/browser/inputs/ChoiceTiles.js +135 -0
  48. package/dist/browser/inputs/ChoiceTiles.js.map +1 -0
  49. package/dist/browser/inputs/ColorChoices.js +120 -0
  50. package/dist/browser/inputs/ColorChoices.js.map +1 -0
  51. package/dist/browser/inputs/QrScanner.js +95 -13
  52. package/dist/browser/inputs/QrScanner.js.map +1 -1
  53. package/dist/browser/inputs/TextInput.js +15 -13
  54. package/dist/browser/inputs/TextInput.js.map +1 -1
  55. package/dist/browser/inputs/index.js +4 -0
  56. package/dist/browser/inputs/index.js.map +1 -1
  57. package/dist/browser/inputs/qr-messages.js +2 -0
  58. package/dist/browser/inputs/qr-messages.js.map +1 -1
  59. package/dist/browser/internal/radio-keys.js +13 -0
  60. package/dist/browser/internal/radio-keys.js.map +1 -0
  61. package/dist/browser/layout/AnchoredPopover.js +180 -0
  62. package/dist/browser/layout/AnchoredPopover.js.map +1 -0
  63. package/dist/browser/layout/AppWorkspace.js +155 -20
  64. package/dist/browser/layout/AppWorkspace.js.map +1 -1
  65. package/dist/browser/layout/DetailPanel.js +443 -333
  66. package/dist/browser/layout/DetailPanel.js.map +1 -1
  67. package/dist/browser/layout/MobileShell.js +21 -7
  68. package/dist/browser/layout/MobileShell.js.map +1 -1
  69. package/dist/browser/layout/Settings.js +283 -175
  70. package/dist/browser/layout/Settings.js.map +1 -1
  71. package/dist/browser/layout/SidebarRailHint.js +79 -0
  72. package/dist/browser/layout/SidebarRailHint.js.map +1 -0
  73. package/dist/browser/layout/SidebarSwitcher.js +79 -66
  74. package/dist/browser/layout/SidebarSwitcher.js.map +1 -1
  75. package/dist/browser/layout/TabBar.js +18 -4
  76. package/dist/browser/layout/TabBar.js.map +1 -1
  77. package/dist/browser/layout/app-workspace-controller.js +11 -4
  78. package/dist/browser/layout/app-workspace-controller.js.map +1 -1
  79. package/dist/browser/layout/detail-panel-messages.js +4 -2
  80. package/dist/browser/layout/detail-panel-messages.js.map +1 -1
  81. package/dist/browser/layout/index.js +2 -1
  82. package/dist/browser/layout/index.js.map +1 -1
  83. package/dist/browser/layout/settings-messages.js +26 -2
  84. package/dist/browser/layout/settings-messages.js.map +1 -1
  85. package/dist/browser/surfaces/Avatar.js +2 -14
  86. package/dist/browser/surfaces/Avatar.js.map +1 -1
  87. package/dist/browser/surfaces/DotStrip.js +70 -0
  88. package/dist/browser/surfaces/DotStrip.js.map +1 -0
  89. package/dist/browser/surfaces/ProgressRing.js +3 -0
  90. package/dist/browser/surfaces/ProgressRing.js.map +1 -1
  91. package/dist/browser/surfaces/ResourceCard.js +125 -68
  92. package/dist/browser/surfaces/ResourceCard.js.map +1 -1
  93. package/dist/browser/surfaces/index.js +2 -0
  94. package/dist/browser/surfaces/index.js.map +1 -1
  95. package/dist/browser/surfaces/person-color.js +18 -0
  96. package/dist/browser/surfaces/person-color.js.map +1 -0
  97. package/dist/browser/surfaces/resource-messages.js +6 -2
  98. package/dist/browser/surfaces/resource-messages.js.map +1 -1
  99. package/dist/browser/text-editor/TextEditor.js +1358 -0
  100. package/dist/browser/text-editor/TextEditor.js.map +1 -0
  101. package/dist/browser/text-editor/clipboard-html.js +152 -0
  102. package/dist/browser/text-editor/clipboard-html.js.map +1 -0
  103. package/dist/browser/text-editor/clipboard-loading.js +68 -0
  104. package/dist/browser/text-editor/clipboard-loading.js.map +1 -0
  105. package/dist/browser/text-editor/clipboard.js +51 -0
  106. package/dist/browser/text-editor/clipboard.js.map +1 -0
  107. package/dist/browser/text-editor/engine.js +125 -0
  108. package/dist/browser/text-editor/engine.js.map +1 -0
  109. package/dist/browser/text-editor/format.js +218 -0
  110. package/dist/browser/text-editor/format.js.map +1 -0
  111. package/dist/browser/text-editor/formatted.js +164 -0
  112. package/dist/browser/text-editor/formatted.js.map +1 -0
  113. package/dist/browser/text-editor/language.js +19 -0
  114. package/dist/browser/text-editor/language.js.map +1 -0
  115. package/dist/browser/text-editor/markdown-table.js +563 -0
  116. package/dist/browser/text-editor/markdown-table.js.map +1 -0
  117. package/dist/browser/text-editor/messages.js +233 -0
  118. package/dist/browser/text-editor/messages.js.map +1 -0
  119. package/dist/browser/text-editor/paste.js +115 -0
  120. package/dist/browser/text-editor/paste.js.map +1 -0
  121. package/dist/browser/text-editor/table.js +1760 -0
  122. package/dist/browser/text-editor/table.js.map +1 -0
  123. package/dist/browser/text-editor.js +5 -0
  124. package/dist/browser/text-editor.js.map +1 -0
  125. package/dist/browser/widgets/Widget.js +3 -2
  126. package/dist/browser/widgets/Widget.js.map +1 -1
  127. package/dist/ssr/actions/ContextMenu.js +9 -0
  128. package/dist/ssr/actions/ContextMenu.js.map +1 -1
  129. package/dist/ssr/actions/Dropdown.js +15 -4
  130. package/dist/ssr/actions/Dropdown.js.map +1 -1
  131. package/dist/ssr/actions/SelectionToolbar.js +104 -0
  132. package/dist/ssr/actions/SelectionToolbar.js.map +1 -0
  133. package/dist/ssr/actions/index.js +1 -0
  134. package/dist/ssr/actions/index.js.map +1 -1
  135. package/dist/ssr/charts.js +6 -0
  136. package/dist/ssr/charts.js.map +1 -0
  137. package/dist/ssr/chat/ChatComposer.js +132 -53
  138. package/dist/ssr/chat/ChatComposer.js.map +1 -1
  139. package/dist/ssr/chat/chat-messages.js +4 -0
  140. package/dist/ssr/chat/chat-messages.js.map +1 -1
  141. package/dist/ssr/chat/composer-document.js +19 -0
  142. package/dist/ssr/chat/composer-document.js.map +1 -1
  143. package/dist/ssr/chat/index.js.map +1 -1
  144. package/dist/ssr/content/Chart.js +8 -0
  145. package/dist/ssr/content/Chart.js.map +1 -1
  146. package/dist/ssr/content/FileGrid.js +132 -5
  147. package/dist/ssr/content/FileGrid.js.map +1 -1
  148. package/dist/ssr/content/FileTypeIcon.js +15 -0
  149. package/dist/ssr/content/FileTypeIcon.js.map +1 -1
  150. package/dist/ssr/content/FileView.js +11 -4
  151. package/dist/ssr/content/FileView.js.map +1 -1
  152. package/dist/ssr/content/MatchText.js +56 -0
  153. package/dist/ssr/content/MatchText.js.map +1 -0
  154. package/dist/ssr/content/MessageRow.js +16 -6
  155. package/dist/ssr/content/MessageRow.js.map +1 -1
  156. package/dist/ssr/content/ReactionBar.js +3 -1
  157. package/dist/ssr/content/ReactionBar.js.map +1 -1
  158. package/dist/ssr/content/calendar-day-scroll.js +4 -3
  159. package/dist/ssr/content/calendar-day-scroll.js.map +1 -1
  160. package/dist/ssr/content/chart-bar.js +476 -0
  161. package/dist/ssr/content/chart-bar.js.map +1 -0
  162. package/dist/ssr/content/file-list-messages.js +52 -0
  163. package/dist/ssr/content/file-list-messages.js.map +1 -0
  164. package/dist/ssr/content/index.js +2 -1
  165. package/dist/ssr/content/index.js.map +1 -1
  166. package/dist/ssr/feedback/Tooltip.js +31 -14
  167. package/dist/ssr/feedback/Tooltip.js.map +1 -1
  168. package/dist/ssr/inputs/ChoiceList.js +95 -0
  169. package/dist/ssr/inputs/ChoiceList.js.map +1 -0
  170. package/dist/ssr/inputs/ChoiceSlider.js +191 -0
  171. package/dist/ssr/inputs/ChoiceSlider.js.map +1 -0
  172. package/dist/ssr/inputs/ChoiceTiles.js +61 -0
  173. package/dist/ssr/inputs/ChoiceTiles.js.map +1 -0
  174. package/dist/ssr/inputs/ColorChoices.js +60 -0
  175. package/dist/ssr/inputs/ColorChoices.js.map +1 -0
  176. package/dist/ssr/inputs/QrScanner.js +89 -10
  177. package/dist/ssr/inputs/QrScanner.js.map +1 -1
  178. package/dist/ssr/inputs/TextInput.js +13 -1
  179. package/dist/ssr/inputs/TextInput.js.map +1 -1
  180. package/dist/ssr/inputs/index.js +4 -0
  181. package/dist/ssr/inputs/index.js.map +1 -1
  182. package/dist/ssr/inputs/qr-messages.js +2 -0
  183. package/dist/ssr/inputs/qr-messages.js.map +1 -1
  184. package/dist/ssr/internal/radio-keys.js +13 -0
  185. package/dist/ssr/internal/radio-keys.js.map +1 -0
  186. package/dist/ssr/layout/AnchoredPopover.js +142 -0
  187. package/dist/ssr/layout/AnchoredPopover.js.map +1 -0
  188. package/dist/ssr/layout/AppWorkspace.js +154 -20
  189. package/dist/ssr/layout/AppWorkspace.js.map +1 -1
  190. package/dist/ssr/layout/DetailPanel.js +181 -108
  191. package/dist/ssr/layout/DetailPanel.js.map +1 -1
  192. package/dist/ssr/layout/MobileShell.js +20 -6
  193. package/dist/ssr/layout/MobileShell.js.map +1 -1
  194. package/dist/ssr/layout/Settings.js +122 -45
  195. package/dist/ssr/layout/Settings.js.map +1 -1
  196. package/dist/ssr/layout/SidebarRailHint.js +79 -0
  197. package/dist/ssr/layout/SidebarRailHint.js.map +1 -0
  198. package/dist/ssr/layout/SidebarSwitcher.js +13 -3
  199. package/dist/ssr/layout/SidebarSwitcher.js.map +1 -1
  200. package/dist/ssr/layout/TabBar.js +11 -3
  201. package/dist/ssr/layout/TabBar.js.map +1 -1
  202. package/dist/ssr/layout/app-workspace-controller.js +11 -4
  203. package/dist/ssr/layout/app-workspace-controller.js.map +1 -1
  204. package/dist/ssr/layout/detail-panel-messages.js +4 -2
  205. package/dist/ssr/layout/detail-panel-messages.js.map +1 -1
  206. package/dist/ssr/layout/index.js +2 -1
  207. package/dist/ssr/layout/index.js.map +1 -1
  208. package/dist/ssr/layout/settings-messages.js +26 -2
  209. package/dist/ssr/layout/settings-messages.js.map +1 -1
  210. package/dist/ssr/surfaces/Avatar.js +2 -14
  211. package/dist/ssr/surfaces/Avatar.js.map +1 -1
  212. package/dist/ssr/surfaces/DotStrip.js +31 -0
  213. package/dist/ssr/surfaces/DotStrip.js.map +1 -0
  214. package/dist/ssr/surfaces/ProgressRing.js +3 -0
  215. package/dist/ssr/surfaces/ProgressRing.js.map +1 -1
  216. package/dist/ssr/surfaces/ResourceCard.js +40 -15
  217. package/dist/ssr/surfaces/ResourceCard.js.map +1 -1
  218. package/dist/ssr/surfaces/index.js +2 -0
  219. package/dist/ssr/surfaces/index.js.map +1 -1
  220. package/dist/ssr/surfaces/person-color.js +18 -0
  221. package/dist/ssr/surfaces/person-color.js.map +1 -0
  222. package/dist/ssr/surfaces/resource-messages.js +6 -2
  223. package/dist/ssr/surfaces/resource-messages.js.map +1 -1
  224. package/dist/ssr/text-editor/TextEditor.js +1155 -0
  225. package/dist/ssr/text-editor/TextEditor.js.map +1 -0
  226. package/dist/ssr/text-editor/clipboard-html.js +152 -0
  227. package/dist/ssr/text-editor/clipboard-html.js.map +1 -0
  228. package/dist/ssr/text-editor/clipboard-loading.js +68 -0
  229. package/dist/ssr/text-editor/clipboard-loading.js.map +1 -0
  230. package/dist/ssr/text-editor/clipboard.js +51 -0
  231. package/dist/ssr/text-editor/clipboard.js.map +1 -0
  232. package/dist/ssr/text-editor/engine.js +125 -0
  233. package/dist/ssr/text-editor/engine.js.map +1 -0
  234. package/dist/ssr/text-editor/format.js +218 -0
  235. package/dist/ssr/text-editor/format.js.map +1 -0
  236. package/dist/ssr/text-editor/formatted.js +164 -0
  237. package/dist/ssr/text-editor/formatted.js.map +1 -0
  238. package/dist/ssr/text-editor/language.js +19 -0
  239. package/dist/ssr/text-editor/language.js.map +1 -0
  240. package/dist/ssr/text-editor/markdown-table.js +563 -0
  241. package/dist/ssr/text-editor/markdown-table.js.map +1 -0
  242. package/dist/ssr/text-editor/messages.js +233 -0
  243. package/dist/ssr/text-editor/messages.js.map +1 -0
  244. package/dist/ssr/text-editor/paste.js +115 -0
  245. package/dist/ssr/text-editor/paste.js.map +1 -0
  246. package/dist/ssr/text-editor/table.js +1760 -0
  247. package/dist/ssr/text-editor/table.js.map +1 -0
  248. package/dist/ssr/text-editor.js +5 -0
  249. package/dist/ssr/text-editor.js.map +1 -0
  250. package/dist/ssr/widgets/Widget.js +3 -2
  251. package/dist/ssr/widgets/Widget.js.map +1 -1
  252. package/dist/styles.css +1 -1
  253. package/dist/types/actions/ContextMenu.d.ts +5 -0
  254. package/dist/types/actions/Dropdown.d.ts +7 -0
  255. package/dist/types/actions/SelectionToolbar.d.ts +38 -0
  256. package/dist/types/actions/index.d.ts +2 -0
  257. package/dist/types/charts.d.ts +5 -0
  258. package/dist/types/chat/ChatComposer.d.ts +15 -0
  259. package/dist/types/chat/chat-messages.d.ts +2 -0
  260. package/dist/types/chat/composer-document.d.ts +5 -0
  261. package/dist/types/chat/index.d.ts +1 -1
  262. package/dist/types/content/Chart.d.ts +2 -1
  263. package/dist/types/content/FileGrid.d.ts +43 -3
  264. package/dist/types/content/FileTypeIcon.d.ts +10 -0
  265. package/dist/types/content/FileView.d.ts +5 -1
  266. package/dist/types/content/MatchText.d.ts +21 -0
  267. package/dist/types/content/MessageRow.d.ts +2 -0
  268. package/dist/types/content/calendar-day-scroll.d.ts +2 -1
  269. package/dist/types/content/chart-bar.d.ts +60 -0
  270. package/dist/types/content/file-list-messages.d.ts +24 -0
  271. package/dist/types/content/index.d.ts +3 -2
  272. package/dist/types/feedback/Tooltip.d.ts +8 -2
  273. package/dist/types/inputs/ChoiceList.d.ts +28 -0
  274. package/dist/types/inputs/ChoiceSlider.d.ts +36 -0
  275. package/dist/types/inputs/ChoiceTiles.d.ts +25 -0
  276. package/dist/types/inputs/ColorChoices.d.ts +19 -0
  277. package/dist/types/inputs/index.d.ts +8 -0
  278. package/dist/types/inputs/qr-messages.d.ts +1 -0
  279. package/dist/types/internal/radio-keys.d.ts +5 -0
  280. package/dist/types/layout/AnchoredPopover.d.ts +31 -0
  281. package/dist/types/layout/AppWorkspace.d.ts +10 -0
  282. package/dist/types/layout/DetailPanel.d.ts +17 -0
  283. package/dist/types/layout/MobileShell.d.ts +5 -2
  284. package/dist/types/layout/Settings.d.ts +22 -0
  285. package/dist/types/layout/SidebarRailHint.d.ts +26 -0
  286. package/dist/types/layout/TabBar.d.ts +5 -0
  287. package/dist/types/layout/detail-panel-messages.d.ts +1 -0
  288. package/dist/types/layout/index.d.ts +3 -2
  289. package/dist/types/layout/settings-messages.d.ts +12 -0
  290. package/dist/types/surfaces/DotStrip.d.ts +22 -0
  291. package/dist/types/surfaces/ProgressRing.d.ts +2 -1
  292. package/dist/types/surfaces/ResourceCard.d.ts +9 -0
  293. package/dist/types/surfaces/index.d.ts +4 -1
  294. package/dist/types/surfaces/person-color.d.ts +10 -0
  295. package/dist/types/surfaces/resource-messages.d.ts +2 -0
  296. package/dist/types/text-editor/TextEditor.d.ts +69 -0
  297. package/dist/types/text-editor/clipboard-html.d.ts +9 -0
  298. package/dist/types/text-editor/clipboard-loading.d.ts +8 -0
  299. package/dist/types/text-editor/clipboard.d.ts +20 -0
  300. package/dist/types/text-editor/engine.d.ts +34 -0
  301. package/dist/types/text-editor/format.d.ts +34 -0
  302. package/dist/types/text-editor/formatted.d.ts +1 -0
  303. package/dist/types/text-editor/language.d.ts +8 -0
  304. package/dist/types/text-editor/markdown-table.d.ts +105 -0
  305. package/dist/types/text-editor/messages.d.ts +113 -0
  306. package/dist/types/text-editor/paste.d.ts +6 -0
  307. package/dist/types/text-editor/table.d.ts +81 -0
  308. package/dist/types/text-editor.d.ts +4 -0
  309. package/dist/types/widgets/Widget.d.ts +3 -2
  310. package/package.json +28 -3
@@ -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 = Math.min(widthClass, levels().length);
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 = isAnchor() ? undefined : {
585
- // A stored width keeps to this pane's limits before the controller attaches.
586
- "--k2b-workspace-panel-size": `clamp(${minSize()}px, var(${variable}, ${appWorkspaceWidthCss(defaultSize(), "var(--k2b-workspace-width)")}), ${maxSize()}px)`,
587
- "--k2b-workspace-panel-min": `${minSize()}px`
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 = () => control.grouped ? {
1431
- class: "k2b-app-workspace__sidebar-item-main"
1432
- } : common();
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
- if (!props.href || props.disabled) return (() => {
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