@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 @@
1
+ {"version":3,"names":[],"sources":["internal/radio-keys.ts"],"sourcesContent":["/**\n * Roving focus for a single-choice radio group: arrows move and select with wrapping, Home and End select the first\n * and last option. Returns the index to select, or `undefined` for keys the group does not handle.\n */\nexport const radioKeyTarget = (key: string, index: number, count: number): number | undefined => {\n if (count === 0) return undefined;\n if (key === \"ArrowRight\" || key === \"ArrowDown\") return (index + 1) % count;\n if (key === \"ArrowLeft\" || key === \"ArrowUp\") return (index - 1 + count) % count;\n if (key === \"Home\") return 0;\n if (key === \"End\") return count - 1;\n return undefined;\n};\n"],"mappings":"AAAA;AACA;AACA;AACA;AACA,OAAO,MAAM,cAAc,GAAG,CAAC,GAAW,EAAE,KAAa,EAAE,KAAa,KAAyB;EAC/F,IAAI,KAAK,KAAK,CAAC,EAAE,OAAO,SAAS;EACjC,IAAI,GAAG,KAAK,YAAY,IAAI,GAAG,KAAK,WAAW,EAAE,OAAO,CAAC,KAAK,GAAG,CAAC,IAAI,KAAK;EAC3E,IAAI,GAAG,KAAK,WAAW,IAAI,GAAG,KAAK,SAAS,EAAE,OAAO,CAAC,KAAK,GAAG,CAAC,GAAG,KAAK,IAAI,KAAK;EAChF,IAAI,GAAG,KAAK,MAAM,EAAE,OAAO,CAAC;EAC5B,IAAI,GAAG,KAAK,KAAK,EAAE,OAAO,KAAK,GAAG,CAAC;EACnC,OAAO,SAAS;AAClB,CAAC","ignoreList":[]}
@@ -0,0 +1,142 @@
1
+ import { ssr as _$ssr } from "solid-js/web";
2
+ import { createComponent as _$createComponent } from "solid-js/web";
3
+ import { ssrStyle as _$ssrStyle } from "solid-js/web";
4
+ import { ssrAttribute as _$ssrAttribute } from "solid-js/web";
5
+ import { escape as _$escape } from "solid-js/web";
6
+ var _tmpl$ = ["<div popover=\"auto\" role=\"dialog\"", " tabindex=\"-1\"", " style=\"", "\">", "</div>"];
7
+ import { createEffect, createSignal, onCleanup, onMount, Show, untrack } from "solid-js";
8
+ import { returnFocus, ringOnReturn } from "../internal/focus-return";
9
+ const GAP = 6;
10
+ const MARGIN = 8;
11
+ const sheetQuery = "(max-width: 47.999rem)";
12
+
13
+ /**
14
+ * 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
15
+ * side with room and keeps that side while open, so a panel that changes its content never jumps to the other side.
16
+ * Escape, a click outside and another press of the anchor close it; the focus returns to where it was. On a phone it
17
+ * is a bottom sheet.
18
+ */
19
+ export function AnchoredPopover(props) {
20
+ let surface;
21
+ let previous = null;
22
+ let ring = false;
23
+ let pressedAnchor;
24
+ /** The side chosen when the panel opened; kept until it closes. */
25
+ let openedAbove;
26
+ const [shown, setShown] = createSignal();
27
+ const [sheet, setSheet] = createSignal(false);
28
+ const place = () => {
29
+ const anchor = shown();
30
+ if (!surface || !anchor) return;
31
+ if (!anchor.isConnected) {
32
+ hide();
33
+ props.onClose();
34
+ return;
35
+ }
36
+ if (sheet()) {
37
+ surface.style.left = "";
38
+ surface.style.top = "";
39
+ return;
40
+ }
41
+ const viewport = window.visualViewport;
42
+ const view = {
43
+ top: (viewport?.offsetTop ?? 0) + MARGIN,
44
+ bottom: (viewport ? viewport.offsetTop + viewport.height : window.innerHeight) - MARGIN,
45
+ left: (viewport?.offsetLeft ?? 0) + MARGIN,
46
+ right: (viewport ? viewport.offsetLeft + viewport.width : window.innerWidth) - MARGIN
47
+ };
48
+ const box = anchor.getBoundingClientRect();
49
+ const size = surface.getBoundingClientRect();
50
+ const roomAbove = box.top - GAP - view.top;
51
+ const roomBelow = view.bottom - box.bottom - GAP;
52
+ if (openedAbove === undefined) {
53
+ const planned = Math.max(size.height, props.plannedHeight ?? 0);
54
+ openedAbove = (props.side ?? "below") === "above" ? planned <= roomAbove || roomAbove > roomBelow : planned > roomBelow && roomAbove > roomBelow;
55
+ }
56
+ surface.style.setProperty("--k2b-anchored-popover-room", `${Math.round(Math.max(120, openedAbove ? roomAbove : roomBelow))}px`);
57
+ const top = openedAbove ? box.top - GAP - size.height : box.bottom + GAP;
58
+ const left = (props.align ?? "end") === "end" ? box.right - size.width : box.left;
59
+ surface.style.left = `${Math.round(Math.max(view.left, Math.min(left, view.right - size.width)))}px`;
60
+ surface.style.top = `${Math.round(Math.max(view.top, Math.min(top, view.bottom - size.height)))}px`;
61
+ };
62
+ const restoreFocus = () => {
63
+ const focused = document.activeElement;
64
+ if (focused && focused !== document.body && !surface?.contains(focused)) return;
65
+ if (previous?.isConnected) returnFocus(previous, ring);
66
+ };
67
+ const hide = () => {
68
+ restoreFocus();
69
+ if (surface?.matches(":popover-open")) surface.hidePopover();
70
+ openedAbove = undefined;
71
+ setShown(undefined);
72
+ };
73
+ const pressed = event => {
74
+ const anchor = shown();
75
+ pressedAnchor = anchor && event.target instanceof Node && anchor.contains(event.target) ? anchor : undefined;
76
+ };
77
+ const clicked = event => {
78
+ const anchor = shown();
79
+ if (!anchor || !(event.target instanceof Node) || !anchor.contains(event.target)) return;
80
+ pressedAnchor = anchor;
81
+ hide();
82
+ props.onClose();
83
+ };
84
+ createEffect(() => {
85
+ const anchor = props.anchor ?? undefined;
86
+ untrack(() => {
87
+ if (!anchor) {
88
+ if (shown()) hide();
89
+ return;
90
+ }
91
+ if (anchor === pressedAnchor) {
92
+ pressedAnchor = undefined;
93
+ props.onClose();
94
+ return;
95
+ }
96
+ if (shown() === anchor || !surface) return;
97
+ if (!shown()) {
98
+ previous = document.activeElement instanceof HTMLElement ? document.activeElement : null;
99
+ ring = ringOnReturn(previous ?? anchor);
100
+ }
101
+ setSheet(typeof matchMedia === "function" && matchMedia(sheetQuery).matches);
102
+ setShown(anchor);
103
+ if (!surface.matches(":popover-open")) surface.showPopover();
104
+ place();
105
+ queueMicrotask(() => (props.initialFocus?.() ?? surface)?.focus({
106
+ preventScroll: true
107
+ }));
108
+ });
109
+ });
110
+ const scrolled = event => {
111
+ if (!(event.target instanceof Node && surface?.contains(event.target))) place();
112
+ };
113
+ onMount(() => {
114
+ window.addEventListener("resize", place);
115
+ window.addEventListener("scroll", scrolled, true);
116
+ window.visualViewport?.addEventListener("resize", place);
117
+ document.addEventListener("pointerdown", pressed, true);
118
+ document.addEventListener("click", clicked, true);
119
+ const observer = typeof ResizeObserver === "function" && surface ? new ResizeObserver(place) : undefined;
120
+ if (surface) observer?.observe(surface);
121
+ onCleanup(() => {
122
+ observer?.disconnect();
123
+ window.removeEventListener("resize", place);
124
+ window.removeEventListener("scroll", scrolled, true);
125
+ window.visualViewport?.removeEventListener("resize", place);
126
+ document.removeEventListener("pointerdown", pressed, true);
127
+ document.removeEventListener("click", clicked, true);
128
+ if (surface?.matches(":popover-open")) hide();
129
+ });
130
+ });
131
+ return _$ssr(_tmpl$, _$ssrAttribute("aria-label", _$escape(props.label, true), false), _$ssrAttribute("class", _$escape(["k2b-anchored-popover", props.class].filter(Boolean).join(" "), true), false) + _$ssrAttribute("data-sheet", sheet() ? "" : _$escape(undefined, true), false), _$ssrStyle(props.width ? {
132
+ "--k2b-anchored-popover-width": props.width
133
+ } : undefined), _$escape(_$createComponent(Show, {
134
+ get when() {
135
+ return shown();
136
+ },
137
+ get children() {
138
+ return props.children;
139
+ }
140
+ })));
141
+ }
142
+ //# 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":[]}
@@ -73,6 +73,7 @@ import { Dynamic, isServer } from "solid-js/web";
73
73
  import { Button, ButtonLink, IconButton, IconButtonLink } from "../actions/Button";
74
74
  import { useFilterMessages } from "../actions/filter-messages";
75
75
  import { dialogCore } from "../feedback/dialog-core";
76
+ import { Tooltip } from "../feedback/Tooltip";
76
77
  import { RenderErrorBoundary } from "../internal/render-error";
77
78
  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";
78
79
  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";
@@ -80,11 +81,23 @@ import { appWorkspaceInverseWidthCss, appWorkspaceWidthCss, appWorkspaceWidthTok
80
81
  import BottomSheet, { bottomSheetAdaptiveOptions } from "./BottomSheet";
81
82
  import { PageTitle, usePageTrail } from "./PageTitle";
82
83
  import { SidebarItemPreview } from "./SidebarItemPreview";
84
+ import { inSidebarRail, SidebarRailHint } from "./SidebarRailHint";
83
85
  import { AppWorkspaceSidebarSwitcher } from "./SidebarSwitcher";
84
86
  import { createScrollFade, scrollFadeEdges } from "./scroll-fade";
85
87
  import { rememberSidebarScroll } from "./sidebar-scroll-memory";
86
88
  import { assertStableUiId, assertUniqueStableUiIds } from "./stable-id";
87
89
  import { useWorkspaceMessages } from "./workspace-messages";
90
+ /** The narrowest container of each levels width class, as the stylesheet's breakpoints define them (48rem, 80rem). */
91
+ const LEVEL_CLASS_WIDTH = {
92
+ 1: 0,
93
+ 2: 768,
94
+ 3: 1280
95
+ };
96
+ /** The last shown level's minimum width when the level does not declare one; the stylesheet uses the same value. */
97
+ const LEVEL_LAST_MIN = 320;
98
+ /** The width the last shown level keeps at least: its declared minimum, never below the default. */
99
+ const levelLastMin = minSize => Math.max(minSize ?? 0, LEVEL_LAST_MIN);
100
+ const nonEmptyStyle = style => Object.keys(style).length ? style : undefined;
88
101
  const ResizeContext = createContext(true);
89
102
  /** The enclosing workspace: its head names the sidebar, and a nested workspace leaves the page title to it. */
90
103
  const WorkspaceContext = createContext();
@@ -244,8 +257,20 @@ function AppWorkspaceMain(props) {
244
257
  return open;
245
258
  });
246
259
  const depth = () => Math.max(1, levels().findIndex(pane => pane.props.id === props.level) + 1);
260
+ /** How many of the deepest levels a width class shows: up to its count, as long as their minimum widths fit. */
261
+ const levelCount = widthClass => {
262
+ const all = levels();
263
+ let count = Math.min(widthClass, all.length);
264
+ while (count > 1) {
265
+ const end = Math.max(depth(), count);
266
+ 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);
267
+ if (needed <= LEVEL_CLASS_WIDTH[widthClass]) break;
268
+ count--;
269
+ }
270
+ return count;
271
+ };
247
272
  const levelClasses = (index, kind) => [1, 2, 3].filter(widthClass => {
248
- const count = Math.min(widthClass, levels().length);
273
+ const count = levelCount(widthClass);
249
274
  const end = Math.max(depth(), count);
250
275
  const start = end - count + 1;
251
276
  return kind === "first" ? index === start && index > 1 : kind === "last" ? index === end : kind === "handle" ? index >= start && index + 1 <= end : index >= start && index <= end;
@@ -399,11 +424,18 @@ function AppWorkspaceMain(props) {
399
424
  get children() {
400
425
  return handle();
401
426
  }
402
- }), _$ssr(_tmpl$8, _$ssrAttribute("id", _$escape(pane.domId, true), false), `k2b-app-workspace__main-pane ${isAnchor() ? "is-primary" : ""} ${_$escape(pane.props.class ?? "", true)}`, _$ssrAttribute("aria-label", _$escape(pane.props.label, true), false) + _$ssrAttribute("data-workspace-level", levelsMode() ? _$escape(levelIndex(), true) : _$escape(undefined, true), false) + _$ssrAttribute("data-workspace-level-shown", _$escape(levelAttr("shown"), true), false) + _$ssrAttribute("data-workspace-level-first", _$escape(levelAttr("first"), true), false) + _$ssrAttribute("data-workspace-level-last", _$escape(levelAttr("last"), true), false) + _$ssrAttribute("data-workspace-main-region", _$escape(pane.props.id, true), false) + _$ssrAttribute("data-workspace-mobile-active", (levelsMode() ? levelClasses(levelIndex(), "shown").split(" ").includes("1") : activeMobilePane() === pane.props.id) ? "true" : "false", false) + _$ssrAttribute("data-workspace-panel-id", _$escape(panelId, true), false) + _$ssrAttribute("data-workspace-resizable", resizable() ? "true" : "false", false) + _$ssrAttribute("data-surface", pane.props.surface === "navigation" ? "navigation" : _$escape(undefined, true), false) + _$ssrAttribute("data-scroll", !levelsMode() && pane.props.scroll === false ? "false" : _$escape(undefined, true), false) + _$ssrAttribute("data-scroll-fade-mode", !levelsMode() && pane.props.scroll !== false && pane.props.scrollFade !== false ? "both" : _$escape(undefined, true), false), _$ssrStyle(isAnchor() ? undefined : {
403
- // A stored width keeps to this pane's limits before the controller attaches.
404
- "--k2b-workspace-panel-size": `clamp(${minSize()}px, var(${variable}, ${appWorkspaceWidthCss(defaultSize(), "var(--k2b-workspace-width)")}), ${maxSize()}px)`,
405
- "--k2b-workspace-panel-min": `${minSize()}px`
406
- }), levelsMode() ? _$escape([_$createComponent(LevelHead, {
427
+ }), _$ssr(_tmpl$8, _$ssrAttribute("id", _$escape(pane.domId, true), false), `k2b-app-workspace__main-pane ${isAnchor() ? "is-primary" : ""} ${_$escape(pane.props.class ?? "", true)}`, _$ssrAttribute("aria-label", _$escape(pane.props.label, true), false) + _$ssrAttribute("data-workspace-level", levelsMode() ? _$escape(levelIndex(), true) : _$escape(undefined, true), false) + _$ssrAttribute("data-workspace-level-shown", _$escape(levelAttr("shown"), true), false) + _$ssrAttribute("data-workspace-level-first", _$escape(levelAttr("first"), true), false) + _$ssrAttribute("data-workspace-level-last", _$escape(levelAttr("last"), true), false) + _$ssrAttribute("data-workspace-main-region", _$escape(pane.props.id, true), false) + _$ssrAttribute("data-workspace-mobile-active", (levelsMode() ? levelClasses(levelIndex(), "shown").split(" ").includes("1") : activeMobilePane() === pane.props.id) ? "true" : "false", false) + _$ssrAttribute("data-workspace-panel-id", _$escape(panelId, true), false) + _$ssrAttribute("data-workspace-resizable", resizable() ? "true" : "false", false) + _$ssrAttribute("data-surface", pane.props.surface === "navigation" ? "navigation" : _$escape(undefined, true), false) + _$ssrAttribute("data-scroll", !levelsMode() && pane.props.scroll === false ? "false" : _$escape(undefined, true), false) + _$ssrAttribute("data-scroll-fade-mode", !levelsMode() && pane.props.scroll !== false && pane.props.scrollFade !== false ? "both" : _$escape(undefined, true), false), _$ssrStyle(nonEmptyStyle({
428
+ ...(isAnchor() ? {} : {
429
+ // A stored width keeps to this pane's limits before the controller attaches.
430
+ "--k2b-workspace-panel-size": `clamp(${minSize()}px, var(${variable}, ${appWorkspaceWidthCss(defaultSize(), "var(--k2b-workspace-width)")}), ${maxSize()}px)`,
431
+ "--k2b-workspace-panel-min": `${minSize()}px`
432
+ }),
433
+ // The last shown level fills the rest, but never below its minimum; set on every level, so a workspace
434
+ // nested in a wide level does not inherit that minimum.
435
+ ...(levelsMode() ? {
436
+ "--k2b-workspace-level-min": `${levelLastMin(pane.props.minSize)}px`
437
+ } : {})
438
+ })), levelsMode() ? _$escape([_$createComponent(LevelHead, {
407
439
  get label() {
408
440
  return pane.props.label;
409
441
  },
@@ -987,13 +1019,73 @@ const AppWorkspaceSidebarItemStatus = props => {
987
1019
  }
988
1020
  })));
989
1021
  };
1022
+ /**
1023
+ * Hover actions overlay a row's end, so the label and count under them fade
1024
+ * out while they show. The row measures how far the overlay reaches into its
1025
+ * count (`--k2b-sidebar-item-cover`) and how much of that the count and gap
1026
+ * after the label already take (`--k2b-sidebar-item-label-trail`), so the
1027
+ * label keeps all the width the overlay leaves it. The stylesheet applies
1028
+ * both only while the overlay shows, and assumes its usual size until then.
1029
+ */
1030
+ function observeSidebarRowCover(row) {
1031
+ if (isServer || typeof ResizeObserver === "undefined") return;
1032
+ // A hidden count, such as an empty status, or hidden actions have no box to measure from.
1033
+ const laidOut = element => Boolean(element?.getClientRects().length);
1034
+ const measure = () => {
1035
+ const main = row.querySelector(":scope > .k2b-app-workspace__sidebar-item-main");
1036
+ const label = main?.querySelector(":scope > :is(.k2b-app-workspace__sidebar-item-copy, .k2b-app-workspace__sidebar-item-label)");
1037
+ 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");
1038
+ if (!main || !laidOut(label) || !overlays.length) {
1039
+ row.style.removeProperty("--k2b-sidebar-item-cover");
1040
+ row.style.removeProperty("--k2b-sidebar-item-label-trail");
1041
+ return;
1042
+ }
1043
+ // Lengths along the inline axis, measured toward the row's end.
1044
+ const rtl = getComputedStyle(row).direction === "rtl";
1045
+ const end = element => {
1046
+ const box = element.getBoundingClientRect();
1047
+ return rtl ? -box.left : box.right;
1048
+ };
1049
+ const start = Math.min(...overlays.map(element => {
1050
+ const box = element.getBoundingClientRect();
1051
+ return rtl ? -box.right : box.left;
1052
+ }));
1053
+ const meta = main.querySelector(":scope > .k2b-app-workspace__sidebar-item-meta");
1054
+ const content = end(laidOut(meta) ? meta : label);
1055
+ row.style.setProperty("--k2b-sidebar-item-cover", `${Math.max(0, content - start)}px`);
1056
+ row.style.setProperty("--k2b-sidebar-item-label-trail", `${Math.max(0, content - end(label))}px`);
1057
+ };
1058
+ const resized = new ResizeObserver(measure);
1059
+ // The label, the count, and the actions can be replaced while the row stays.
1060
+ const replaced = new MutationObserver(() => observe());
1061
+ const observe = () => {
1062
+ const main = row.querySelector(":scope > .k2b-app-workspace__sidebar-item-main");
1063
+ if (main) replaced.observe(main, {
1064
+ childList: true
1065
+ });
1066
+ resized.disconnect();
1067
+ resized.observe(row);
1068
+ 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);
1069
+ };
1070
+ replaced.observe(row, {
1071
+ childList: true
1072
+ });
1073
+ observe();
1074
+ onCleanup(() => {
1075
+ replaced.disconnect();
1076
+ resized.disconnect();
1077
+ });
1078
+ }
1079
+
990
1080
  /** Shared visual and semantic row frame for flat sidebar items and tree items. */
991
1081
  function AppWorkspaceSidebarRow(props) {
1082
+ const [link, setLink] = createSignal();
1083
+ const [hinted, setHinted] = createSignal(false);
992
1084
  const className = () => `k2b-app-workspace__sidebar-item ${props.hasActions ? "has-action" : ""} ${props.active ? props.activeClass ?? "is-active" : ""} ${props.class ?? ""}`;
993
1085
  const data = () => Object.fromEntries(Object.entries(props.data ?? {}).filter(([, value]) => value !== undefined && value !== null).map(([key, value]) => [`data-${key}`, String(value)]));
994
1086
  const common = () => ({
995
1087
  class: className(),
996
- title: props.title,
1088
+ title: hinted() ? undefined : props.title,
997
1089
  "data-tone": props.tone,
998
1090
  style: {
999
1091
  "view-transition-name": props.viewTransitionName,
@@ -1003,9 +1095,12 @@ function AppWorkspaceSidebarRow(props) {
1003
1095
  });
1004
1096
  const current = () => props.active === "ancestor" ? "true" : props.active ? "page" : undefined;
1005
1097
  const Control = control => {
1006
- const attrs = () => control.grouped ? {
1007
- class: "k2b-app-workspace__sidebar-item-main"
1008
- } : common();
1098
+ const attrs = () => ({
1099
+ ...(control.grouped ? {
1100
+ class: "k2b-app-workspace__sidebar-item-main"
1101
+ } : common()),
1102
+ ref: setLink
1103
+ });
1009
1104
  return _$createComponent(Show, {
1010
1105
  get when() {
1011
1106
  return Boolean(props.href && !props.disabled);
@@ -1074,7 +1169,7 @@ function AppWorkspaceSidebarRow(props) {
1074
1169
  }
1075
1170
  });
1076
1171
  };
1077
- return _$createComponent(Show, {
1172
+ return [_$createComponent(Show, {
1078
1173
  get when() {
1079
1174
  return props.hasActions;
1080
1175
  },
@@ -1092,7 +1187,26 @@ function AppWorkspaceSidebarRow(props) {
1092
1187
  grouped: true
1093
1188
  })), _$escape(props.actions)], false);
1094
1189
  }
1095
- });
1190
+ }), _$createComponent(Show, {
1191
+ get when() {
1192
+ return link();
1193
+ },
1194
+ keyed: true,
1195
+ children: element => _$createComponent(SidebarRailHint, {
1196
+ target: () => element,
1197
+ get label() {
1198
+ return props.title ?? props.hint;
1199
+ },
1200
+ get focusTarget() {
1201
+ return props.focusTarget ?? (() => element);
1202
+ },
1203
+ labelSelector: ".k2b-app-workspace__sidebar-item-label-text",
1204
+ get titled() {
1205
+ return props.title !== undefined;
1206
+ },
1207
+ onArm: () => setHinted(true)
1208
+ })
1209
+ })];
1096
1210
  }
1097
1211
  function AppWorkspaceSidebarItem(props) {
1098
1212
  const workspaceMessages = useWorkspaceMessages();
@@ -1254,6 +1368,9 @@ function AppWorkspaceSidebarItem(props) {
1254
1368
  get title() {
1255
1369
  return props.title;
1256
1370
  },
1371
+ get hint() {
1372
+ return _$memo(() => typeof label() === "string")() ? label() : undefined;
1373
+ },
1257
1374
  get viewTransitionName() {
1258
1375
  return props.viewTransitionName;
1259
1376
  },
@@ -1371,7 +1488,7 @@ const AppWorkspaceNavTree = props => {
1371
1488
  },
1372
1489
  children: (item, place) => {
1373
1490
  const nested = createMemo(() => navTreeItems(item.children));
1374
- const hasChildren = () => nested().length > 0;
1491
+ const hasChildren = () => item.hasChildren ?? nested().length > 0;
1375
1492
  const selected = () => props.selectedId === item.id;
1376
1493
  const siblingIndex = id => siblings().findIndex(sibling => sibling.id === id);
1377
1494
  const movable = () => Boolean(props.onMove && item.movable && !item.disabled);
@@ -1548,6 +1665,10 @@ const AppWorkspaceNavTree = props => {
1548
1665
  get title() {
1549
1666
  return item.title;
1550
1667
  },
1668
+ get hint() {
1669
+ return _$memo(() => typeof item.label === "string")() ? item.label : undefined;
1670
+ },
1671
+ focusTarget: () => treeItem,
1551
1672
  get viewTransitionName() {
1552
1673
  return item.viewTransitionName;
1553
1674
  },
@@ -1664,10 +1785,11 @@ const AppWorkspaceSidebarIconGrid = props => _$ssrElement("section", _$mergeProp
1664
1785
  children: title => _$ssr(_tmpl$22, _$escape(title()))
1665
1786
  })), _$ssr(_tmpl$47, _$ssrAttribute("data-columns", _$escape(props.columns ?? 2, true), false), _$escape(props.children))], false);
1666
1787
  const AppWorkspaceSidebarIconAction = props => {
1788
+ let target;
1667
1789
  const content = _$ssr(_tmpl$48, _$ssrAttribute("class", _$escape(iconClass(props.icon), true), false));
1668
1790
  const attrs = () => ({
1791
+ ref: element => target = element,
1669
1792
  class: `k2b-app-workspace__sidebar-icon-action ${props.active ? "is-active" : ""}`,
1670
- title: props.label,
1671
1793
  "aria-label": props.label,
1672
1794
  "data-tone": props.tone,
1673
1795
  style: {
@@ -1675,19 +1797,31 @@ const AppWorkspaceSidebarIconAction = props => {
1675
1797
  },
1676
1798
  ...modeAttrs(props.sidebarMode)
1677
1799
  });
1678
- if (!props.href || props.disabled) return _$ssrElement("button", _$mergeProps({
1800
+ // The icon never shows its label, so the hint names it in every state; in the collapsed rail it sits beside the
1801
+ // icon like the rail's other entries.
1802
+ const hint = _$createComponent(Tooltip, {
1803
+ target: () => target,
1804
+ get content() {
1805
+ return props.label;
1806
+ },
1807
+ get placement() {
1808
+ return inSidebarRail(target) ? "right" : undefined;
1809
+ },
1810
+ delay: 0
1811
+ });
1812
+ if (!props.href || props.disabled) return [_$ssrElement("button", _$mergeProps({
1679
1813
  type: "button"
1680
1814
  }, attrs, {
1681
1815
  get disabled() {
1682
1816
  return props.disabled;
1683
1817
  }
1684
- }), _$escape(content), false);
1685
- if (props.navigation !== "enhanced" || !props.onNavigate) return _$ssrElement("a", _$mergeProps({
1818
+ }), _$escape(content), false), hint];
1819
+ if (props.navigation !== "enhanced" || !props.onNavigate) return [_$ssrElement("a", _$mergeProps({
1686
1820
  get href() {
1687
1821
  return props.href;
1688
1822
  }
1689
- }, attrs), _$escape(content), false);
1690
- return _$createComponent(Link, _$mergeProps({
1823
+ }, attrs), _$escape(content), false), hint];
1824
+ return [_$createComponent(Link, _$mergeProps({
1691
1825
  get href() {
1692
1826
  return props.href;
1693
1827
  }
@@ -1705,7 +1839,7 @@ const AppWorkspaceSidebarIconAction = props => {
1705
1839
  return props.onClick;
1706
1840
  },
1707
1841
  children: content
1708
- }));
1842
+ })), hint];
1709
1843
  };
1710
1844
  /**
1711
1845
  * The row above the work area. From 48 to 64 rem it holds the button that