@k2b/ui 0.33.0 → 0.34.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (240) 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 +15 -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/MessageRow.js +73 -53
  28. package/dist/browser/content/MessageRow.js.map +1 -1
  29. package/dist/browser/content/ReactionBar.js +3 -1
  30. package/dist/browser/content/ReactionBar.js.map +1 -1
  31. package/dist/browser/content/calendar-day-scroll.js +4 -3
  32. package/dist/browser/content/calendar-day-scroll.js.map +1 -1
  33. package/dist/browser/content/chart-bar.js +476 -0
  34. package/dist/browser/content/chart-bar.js.map +1 -0
  35. package/dist/browser/content/file-list-messages.js +52 -0
  36. package/dist/browser/content/file-list-messages.js.map +1 -0
  37. package/dist/browser/content/index.js +1 -1
  38. package/dist/browser/content/index.js.map +1 -1
  39. package/dist/browser/feedback/Tooltip.js +31 -14
  40. package/dist/browser/feedback/Tooltip.js.map +1 -1
  41. package/dist/browser/inputs/ChoiceList.js +178 -0
  42. package/dist/browser/inputs/ChoiceList.js.map +1 -0
  43. package/dist/browser/inputs/ChoiceSlider.js +314 -0
  44. package/dist/browser/inputs/ChoiceSlider.js.map +1 -0
  45. package/dist/browser/inputs/ChoiceTiles.js +135 -0
  46. package/dist/browser/inputs/ChoiceTiles.js.map +1 -0
  47. package/dist/browser/inputs/ColorChoices.js +120 -0
  48. package/dist/browser/inputs/ColorChoices.js.map +1 -0
  49. package/dist/browser/inputs/QrScanner.js +95 -13
  50. package/dist/browser/inputs/QrScanner.js.map +1 -1
  51. package/dist/browser/inputs/TextInput.js +15 -13
  52. package/dist/browser/inputs/TextInput.js.map +1 -1
  53. package/dist/browser/inputs/index.js +4 -0
  54. package/dist/browser/inputs/index.js.map +1 -1
  55. package/dist/browser/inputs/qr-messages.js +2 -0
  56. package/dist/browser/inputs/qr-messages.js.map +1 -1
  57. package/dist/browser/internal/radio-keys.js +13 -0
  58. package/dist/browser/internal/radio-keys.js.map +1 -0
  59. package/dist/browser/layout/AnchoredPopover.js +180 -0
  60. package/dist/browser/layout/AnchoredPopover.js.map +1 -0
  61. package/dist/browser/layout/AppWorkspace.js +155 -20
  62. package/dist/browser/layout/AppWorkspace.js.map +1 -1
  63. package/dist/browser/layout/DetailPanel.js +443 -333
  64. package/dist/browser/layout/DetailPanel.js.map +1 -1
  65. package/dist/browser/layout/MobileShell.js +21 -7
  66. package/dist/browser/layout/MobileShell.js.map +1 -1
  67. package/dist/browser/layout/Settings.js +283 -175
  68. package/dist/browser/layout/Settings.js.map +1 -1
  69. package/dist/browser/layout/SidebarRailHint.js +79 -0
  70. package/dist/browser/layout/SidebarRailHint.js.map +1 -0
  71. package/dist/browser/layout/SidebarSwitcher.js +79 -66
  72. package/dist/browser/layout/SidebarSwitcher.js.map +1 -1
  73. package/dist/browser/layout/TabBar.js +18 -4
  74. package/dist/browser/layout/TabBar.js.map +1 -1
  75. package/dist/browser/layout/app-workspace-controller.js +11 -4
  76. package/dist/browser/layout/app-workspace-controller.js.map +1 -1
  77. package/dist/browser/layout/detail-panel-messages.js +4 -2
  78. package/dist/browser/layout/detail-panel-messages.js.map +1 -1
  79. package/dist/browser/layout/index.js +2 -1
  80. package/dist/browser/layout/index.js.map +1 -1
  81. package/dist/browser/layout/settings-messages.js +26 -2
  82. package/dist/browser/layout/settings-messages.js.map +1 -1
  83. package/dist/browser/surfaces/Avatar.js +2 -14
  84. package/dist/browser/surfaces/Avatar.js.map +1 -1
  85. package/dist/browser/surfaces/DotStrip.js +70 -0
  86. package/dist/browser/surfaces/DotStrip.js.map +1 -0
  87. package/dist/browser/surfaces/ProgressRing.js +3 -0
  88. package/dist/browser/surfaces/ProgressRing.js.map +1 -1
  89. package/dist/browser/surfaces/ResourceCard.js +125 -68
  90. package/dist/browser/surfaces/ResourceCard.js.map +1 -1
  91. package/dist/browser/surfaces/index.js +2 -0
  92. package/dist/browser/surfaces/index.js.map +1 -1
  93. package/dist/browser/surfaces/person-color.js +18 -0
  94. package/dist/browser/surfaces/person-color.js.map +1 -0
  95. package/dist/browser/surfaces/resource-messages.js +6 -2
  96. package/dist/browser/surfaces/resource-messages.js.map +1 -1
  97. package/dist/browser/widgets/Widget.js +3 -2
  98. package/dist/browser/widgets/Widget.js.map +1 -1
  99. package/dist/ssr/actions/ContextMenu.js +9 -0
  100. package/dist/ssr/actions/ContextMenu.js.map +1 -1
  101. package/dist/ssr/actions/Dropdown.js +14 -4
  102. package/dist/ssr/actions/Dropdown.js.map +1 -1
  103. package/dist/ssr/actions/SelectionToolbar.js +104 -0
  104. package/dist/ssr/actions/SelectionToolbar.js.map +1 -0
  105. package/dist/ssr/actions/index.js +1 -0
  106. package/dist/ssr/actions/index.js.map +1 -1
  107. package/dist/ssr/charts.js +6 -0
  108. package/dist/ssr/charts.js.map +1 -0
  109. package/dist/ssr/chat/ChatComposer.js +132 -53
  110. package/dist/ssr/chat/ChatComposer.js.map +1 -1
  111. package/dist/ssr/chat/chat-messages.js +4 -0
  112. package/dist/ssr/chat/chat-messages.js.map +1 -1
  113. package/dist/ssr/chat/composer-document.js +19 -0
  114. package/dist/ssr/chat/composer-document.js.map +1 -1
  115. package/dist/ssr/chat/index.js.map +1 -1
  116. package/dist/ssr/content/Chart.js +8 -0
  117. package/dist/ssr/content/Chart.js.map +1 -1
  118. package/dist/ssr/content/FileGrid.js +132 -5
  119. package/dist/ssr/content/FileGrid.js.map +1 -1
  120. package/dist/ssr/content/FileTypeIcon.js +15 -0
  121. package/dist/ssr/content/FileTypeIcon.js.map +1 -1
  122. package/dist/ssr/content/FileView.js +11 -4
  123. package/dist/ssr/content/FileView.js.map +1 -1
  124. package/dist/ssr/content/MessageRow.js +16 -6
  125. package/dist/ssr/content/MessageRow.js.map +1 -1
  126. package/dist/ssr/content/ReactionBar.js +3 -1
  127. package/dist/ssr/content/ReactionBar.js.map +1 -1
  128. package/dist/ssr/content/calendar-day-scroll.js +4 -3
  129. package/dist/ssr/content/calendar-day-scroll.js.map +1 -1
  130. package/dist/ssr/content/chart-bar.js +476 -0
  131. package/dist/ssr/content/chart-bar.js.map +1 -0
  132. package/dist/ssr/content/file-list-messages.js +52 -0
  133. package/dist/ssr/content/file-list-messages.js.map +1 -0
  134. package/dist/ssr/content/index.js +1 -1
  135. package/dist/ssr/content/index.js.map +1 -1
  136. package/dist/ssr/feedback/Tooltip.js +31 -14
  137. package/dist/ssr/feedback/Tooltip.js.map +1 -1
  138. package/dist/ssr/inputs/ChoiceList.js +95 -0
  139. package/dist/ssr/inputs/ChoiceList.js.map +1 -0
  140. package/dist/ssr/inputs/ChoiceSlider.js +191 -0
  141. package/dist/ssr/inputs/ChoiceSlider.js.map +1 -0
  142. package/dist/ssr/inputs/ChoiceTiles.js +61 -0
  143. package/dist/ssr/inputs/ChoiceTiles.js.map +1 -0
  144. package/dist/ssr/inputs/ColorChoices.js +60 -0
  145. package/dist/ssr/inputs/ColorChoices.js.map +1 -0
  146. package/dist/ssr/inputs/QrScanner.js +89 -10
  147. package/dist/ssr/inputs/QrScanner.js.map +1 -1
  148. package/dist/ssr/inputs/TextInput.js +13 -1
  149. package/dist/ssr/inputs/TextInput.js.map +1 -1
  150. package/dist/ssr/inputs/index.js +4 -0
  151. package/dist/ssr/inputs/index.js.map +1 -1
  152. package/dist/ssr/inputs/qr-messages.js +2 -0
  153. package/dist/ssr/inputs/qr-messages.js.map +1 -1
  154. package/dist/ssr/internal/radio-keys.js +13 -0
  155. package/dist/ssr/internal/radio-keys.js.map +1 -0
  156. package/dist/ssr/layout/AnchoredPopover.js +142 -0
  157. package/dist/ssr/layout/AnchoredPopover.js.map +1 -0
  158. package/dist/ssr/layout/AppWorkspace.js +154 -20
  159. package/dist/ssr/layout/AppWorkspace.js.map +1 -1
  160. package/dist/ssr/layout/DetailPanel.js +181 -108
  161. package/dist/ssr/layout/DetailPanel.js.map +1 -1
  162. package/dist/ssr/layout/MobileShell.js +20 -6
  163. package/dist/ssr/layout/MobileShell.js.map +1 -1
  164. package/dist/ssr/layout/Settings.js +122 -45
  165. package/dist/ssr/layout/Settings.js.map +1 -1
  166. package/dist/ssr/layout/SidebarRailHint.js +79 -0
  167. package/dist/ssr/layout/SidebarRailHint.js.map +1 -0
  168. package/dist/ssr/layout/SidebarSwitcher.js +13 -3
  169. package/dist/ssr/layout/SidebarSwitcher.js.map +1 -1
  170. package/dist/ssr/layout/TabBar.js +11 -3
  171. package/dist/ssr/layout/TabBar.js.map +1 -1
  172. package/dist/ssr/layout/app-workspace-controller.js +11 -4
  173. package/dist/ssr/layout/app-workspace-controller.js.map +1 -1
  174. package/dist/ssr/layout/detail-panel-messages.js +4 -2
  175. package/dist/ssr/layout/detail-panel-messages.js.map +1 -1
  176. package/dist/ssr/layout/index.js +2 -1
  177. package/dist/ssr/layout/index.js.map +1 -1
  178. package/dist/ssr/layout/settings-messages.js +26 -2
  179. package/dist/ssr/layout/settings-messages.js.map +1 -1
  180. package/dist/ssr/surfaces/Avatar.js +2 -14
  181. package/dist/ssr/surfaces/Avatar.js.map +1 -1
  182. package/dist/ssr/surfaces/DotStrip.js +31 -0
  183. package/dist/ssr/surfaces/DotStrip.js.map +1 -0
  184. package/dist/ssr/surfaces/ProgressRing.js +3 -0
  185. package/dist/ssr/surfaces/ProgressRing.js.map +1 -1
  186. package/dist/ssr/surfaces/ResourceCard.js +40 -15
  187. package/dist/ssr/surfaces/ResourceCard.js.map +1 -1
  188. package/dist/ssr/surfaces/index.js +2 -0
  189. package/dist/ssr/surfaces/index.js.map +1 -1
  190. package/dist/ssr/surfaces/person-color.js +18 -0
  191. package/dist/ssr/surfaces/person-color.js.map +1 -0
  192. package/dist/ssr/surfaces/resource-messages.js +6 -2
  193. package/dist/ssr/surfaces/resource-messages.js.map +1 -1
  194. package/dist/ssr/widgets/Widget.js +3 -2
  195. package/dist/ssr/widgets/Widget.js.map +1 -1
  196. package/dist/styles.css +1 -1
  197. package/dist/types/actions/ContextMenu.d.ts +5 -0
  198. package/dist/types/actions/Dropdown.d.ts +5 -0
  199. package/dist/types/actions/SelectionToolbar.d.ts +38 -0
  200. package/dist/types/actions/index.d.ts +2 -0
  201. package/dist/types/charts.d.ts +5 -0
  202. package/dist/types/chat/ChatComposer.d.ts +15 -0
  203. package/dist/types/chat/chat-messages.d.ts +2 -0
  204. package/dist/types/chat/composer-document.d.ts +5 -0
  205. package/dist/types/chat/index.d.ts +1 -1
  206. package/dist/types/content/Chart.d.ts +2 -1
  207. package/dist/types/content/FileGrid.d.ts +43 -3
  208. package/dist/types/content/FileTypeIcon.d.ts +10 -0
  209. package/dist/types/content/FileView.d.ts +5 -1
  210. package/dist/types/content/MessageRow.d.ts +2 -0
  211. package/dist/types/content/calendar-day-scroll.d.ts +2 -1
  212. package/dist/types/content/chart-bar.d.ts +60 -0
  213. package/dist/types/content/file-list-messages.d.ts +24 -0
  214. package/dist/types/content/index.d.ts +2 -2
  215. package/dist/types/feedback/Tooltip.d.ts +8 -2
  216. package/dist/types/inputs/ChoiceList.d.ts +28 -0
  217. package/dist/types/inputs/ChoiceSlider.d.ts +36 -0
  218. package/dist/types/inputs/ChoiceTiles.d.ts +25 -0
  219. package/dist/types/inputs/ColorChoices.d.ts +19 -0
  220. package/dist/types/inputs/index.d.ts +8 -0
  221. package/dist/types/inputs/qr-messages.d.ts +1 -0
  222. package/dist/types/internal/radio-keys.d.ts +5 -0
  223. package/dist/types/layout/AnchoredPopover.d.ts +31 -0
  224. package/dist/types/layout/AppWorkspace.d.ts +10 -0
  225. package/dist/types/layout/DetailPanel.d.ts +17 -0
  226. package/dist/types/layout/MobileShell.d.ts +5 -2
  227. package/dist/types/layout/Settings.d.ts +22 -0
  228. package/dist/types/layout/SidebarRailHint.d.ts +26 -0
  229. package/dist/types/layout/TabBar.d.ts +5 -0
  230. package/dist/types/layout/detail-panel-messages.d.ts +1 -0
  231. package/dist/types/layout/index.d.ts +3 -2
  232. package/dist/types/layout/settings-messages.d.ts +12 -0
  233. package/dist/types/surfaces/DotStrip.d.ts +22 -0
  234. package/dist/types/surfaces/ProgressRing.d.ts +2 -1
  235. package/dist/types/surfaces/ResourceCard.d.ts +9 -0
  236. package/dist/types/surfaces/index.d.ts +4 -1
  237. package/dist/types/surfaces/person-color.d.ts +10 -0
  238. package/dist/types/surfaces/resource-messages.d.ts +2 -0
  239. package/dist/types/widgets/Widget.d.ts +3 -2
  240. package/package.json +6 -1
@@ -9,16 +9,18 @@ import { insert as _$insert } from "solid-js/web";
9
9
  import { className as _$className } from "solid-js/web";
10
10
  import { effect as _$effect } from "solid-js/web";
11
11
  import { getNextElement as _$getNextElement } from "solid-js/web";
12
- var _tmpl$ = /*#__PURE__*/_$template(`<span class=k2b-resource-card__icon aria-hidden=true><i>`),
12
+ var _tmpl$ = /*#__PURE__*/_$template(`<span aria-hidden=true><i>`),
13
13
  _tmpl$2 = /*#__PURE__*/_$template(`<span class=k2b-resource-card__meta>`),
14
14
  _tmpl$3 = /*#__PURE__*/_$template(`<span class=k2b-resource-card__preview>`),
15
- _tmpl$4 = /*#__PURE__*/_$template(`<span class=k2b-resource-card__copy><span class=k2b-resource-card__title></span><!$><!/><!$><!/>`),
16
- _tmpl$5 = /*#__PURE__*/_$template(`<span class=k2b-resource-card__icon aria-hidden=true>`),
17
- _tmpl$6 = /*#__PURE__*/_$template(`<span class=k2b-resource-card__copy><span class=k2b-resource-card__bar aria-hidden=true></span><span class=k2b-resource-card__bar aria-hidden=true></span><span class=k2b-sr-only>`),
18
- _tmpl$7 = /*#__PURE__*/_$template(`<span class=k2b-resource-card__copy><span class=k2b-resource-card__label>`),
19
- _tmpl$8 = /*#__PURE__*/_$template(`<div>`),
20
- _tmpl$9 = /*#__PURE__*/_$template(`<a>`),
21
- _tmpl$0 = /*#__PURE__*/_$template(`<button type=button>`);
15
+ _tmpl$4 = /*#__PURE__*/_$template(`<span class=k2b-resource-card__copy><!$><!/><span class=k2b-resource-card__title></span><!$><!/><!$><!/>`),
16
+ _tmpl$5 = /*#__PURE__*/_$template(`<span class=k2b-resource-card__status>`),
17
+ _tmpl$6 = /*#__PURE__*/_$template(`<span class=k2b-resource-card__icon aria-hidden=true>`),
18
+ _tmpl$7 = /*#__PURE__*/_$template(`<span class=k2b-resource-card__copy><span class=k2b-resource-card__bar aria-hidden=true></span><span class=k2b-resource-card__bar aria-hidden=true></span><span class=k2b-sr-only>`),
19
+ _tmpl$8 = /*#__PURE__*/_$template(`<span class=k2b-resource-card__icon aria-hidden=true><i>`),
20
+ _tmpl$9 = /*#__PURE__*/_$template(`<span class=k2b-resource-card__copy><span class=k2b-resource-card__meta></span><span class=k2b-resource-card__label></span><!$><!/>`),
21
+ _tmpl$0 = /*#__PURE__*/_$template(`<div>`),
22
+ _tmpl$1 = /*#__PURE__*/_$template(`<a>`),
23
+ _tmpl$10 = /*#__PURE__*/_$template(`<button type=button>`);
22
24
  import { Match, Show, Switch } from "solid-js";
23
25
  import { useUiMessages } from "../intl/messages";
24
26
  import { useResourceMessages } from "./resource-messages";
@@ -28,6 +30,8 @@ import { useResourceMessages } from "./resource-messages";
28
30
  * why it cannot be shown.
29
31
  */
30
32
 
33
+ /** The icon chip's colour, from the same palette as `LinkCard`. */
34
+
31
35
  const DEFAULT_ICON = "ti ti-file";
32
36
  const LINK_PROTOCOLS = new Set(["https:", "http:"]);
33
37
  const STATE_ICONS = {
@@ -73,51 +77,81 @@ export function ResourceCard(props) {
73
77
  return [(() => {
74
78
  var _el$ = _$getNextElement(_tmpl$),
75
79
  _el$2 = _el$.firstChild;
76
- _$effect(() => _$className(_el$2, props.icon ?? DEFAULT_ICON));
80
+ _$effect(_p$ => {
81
+ var _v$ = `k2b-resource-card__icon${props.color ? " k2b-icon-tile" : ""}`,
82
+ _v$2 = props.icon ?? DEFAULT_ICON;
83
+ _v$ !== _p$.e && _$className(_el$, _p$.e = _v$);
84
+ _v$2 !== _p$.t && _$className(_el$2, _p$.t = _v$2);
85
+ return _p$;
86
+ }, {
87
+ e: undefined,
88
+ t: undefined
89
+ });
77
90
  return _el$;
78
91
  })(), (() => {
79
92
  var _el$3 = _$getNextElement(_tmpl$4),
80
- _el$4 = _el$3.firstChild,
81
- _el$7 = _el$4.nextSibling,
82
- [_el$8, _co$] = _$getNextMarker(_el$7.nextSibling),
83
- _el$9 = _el$8.nextSibling,
84
- [_el$0, _co$2] = _$getNextMarker(_el$9.nextSibling);
85
- _$insert(_el$4, title);
93
+ _el$8 = _el$3.firstChild,
94
+ [_el$9, _co$] = _$getNextMarker(_el$8.nextSibling),
95
+ _el$5 = _el$9.nextSibling,
96
+ _el$0 = _el$5.nextSibling,
97
+ [_el$1, _co$2] = _$getNextMarker(_el$0.nextSibling),
98
+ _el$10 = _el$1.nextSibling,
99
+ [_el$11, _co$3] = _$getNextMarker(_el$10.nextSibling);
100
+ _$insert(_el$3, _$createComponent(Show, {
101
+ get when() {
102
+ return props.context?.trim();
103
+ },
104
+ get children() {
105
+ var _el$4 = _$getNextElement(_tmpl$2);
106
+ _$insert(_el$4, () => props.context);
107
+ return _el$4;
108
+ }
109
+ }), _el$9, _co$);
110
+ _$insert(_el$5, title);
86
111
  _$insert(_el$3, _$createComponent(Show, {
87
112
  get when() {
88
113
  return meta();
89
114
  },
90
115
  get children() {
91
- var _el$5 = _$getNextElement(_tmpl$2);
92
- _$insert(_el$5, meta);
93
- return _el$5;
116
+ var _el$6 = _$getNextElement(_tmpl$2);
117
+ _$insert(_el$6, meta);
118
+ return _el$6;
94
119
  }
95
- }), _el$8, _co$);
120
+ }), _el$1, _co$2);
96
121
  _$insert(_el$3, _$createComponent(Show, {
97
122
  get when() {
98
123
  return props.preview?.trim();
99
124
  },
100
125
  get children() {
101
- var _el$6 = _$getNextElement(_tmpl$3);
102
- _$insert(_el$6, () => props.preview);
103
- return _el$6;
126
+ var _el$7 = _$getNextElement(_tmpl$3);
127
+ _$insert(_el$7, () => props.preview);
128
+ return _el$7;
104
129
  }
105
- }), _el$0, _co$2);
130
+ }), _el$11, _co$3);
106
131
  return _el$3;
107
- })()];
132
+ })(), _$createComponent(Show, {
133
+ get when() {
134
+ return props.status?.trim();
135
+ },
136
+ get children() {
137
+ var _el$12 = _$getNextElement(_tmpl$5);
138
+ _$insert(_el$12, () => props.status);
139
+ return _el$12;
140
+ }
141
+ })];
108
142
  }
109
143
  }), _$createComponent(Match, {
110
144
  get when() {
111
145
  return state() === "loading";
112
146
  },
113
147
  get children() {
114
- return [_$getNextElement(_tmpl$5), (() => {
115
- var _el$10 = _$getNextElement(_tmpl$6),
116
- _el$11 = _el$10.firstChild,
117
- _el$12 = _el$11.nextSibling,
118
- _el$13 = _el$12.nextSibling;
119
- _$insert(_el$13, () => messages().loading);
120
- return _el$10;
148
+ return [_$getNextElement(_tmpl$6), (() => {
149
+ var _el$14 = _$getNextElement(_tmpl$7),
150
+ _el$15 = _el$14.firstChild,
151
+ _el$16 = _el$15.nextSibling,
152
+ _el$17 = _el$16.nextSibling;
153
+ _$insert(_el$17, () => messages().loading);
154
+ return _el$14;
121
155
  })()];
122
156
  }
123
157
  }), _$createComponent(Match, {
@@ -125,18 +159,32 @@ export function ResourceCard(props) {
125
159
  return reason();
126
160
  },
127
161
  children: reason => [(() => {
128
- var _el$14 = _$getNextElement(_tmpl$),
129
- _el$15 = _el$14.firstChild;
130
- _$effect(() => _$className(_el$15, STATE_ICONS[reason()]));
131
- return _el$14;
162
+ var _el$18 = _$getNextElement(_tmpl$8),
163
+ _el$19 = _el$18.firstChild;
164
+ _$effect(() => _$className(_el$19, STATE_ICONS[reason()]));
165
+ return _el$18;
132
166
  })(), (() => {
133
- var _el$16 = _$getNextElement(_tmpl$7),
134
- _el$17 = _el$16.firstChild;
135
- _$insert(_el$17, (() => {
167
+ var _el$20 = _$getNextElement(_tmpl$9),
168
+ _el$21 = _el$20.firstChild,
169
+ _el$22 = _el$21.nextSibling,
170
+ _el$24 = _el$22.nextSibling,
171
+ [_el$25, _co$4] = _$getNextMarker(_el$24.nextSibling);
172
+ _$insert(_el$21, () => resourceMessages().resourceKind);
173
+ _$insert(_el$22, (() => {
136
174
  var _c$ = _$memo(() => reason() === "no_access");
137
175
  return () => _c$() ? resourceMessages().resourceNoAccess : _$memo(() => reason() === "deleted")() ? resourceMessages().resourceDeleted : resourceMessages().resourceUnavailable;
138
176
  })());
139
- return _el$16;
177
+ _$insert(_el$20, _$createComponent(Show, {
178
+ get when() {
179
+ return reason() === "no_access";
180
+ },
181
+ get children() {
182
+ var _el$23 = _$getNextElement(_tmpl$2);
183
+ _$insert(_el$23, () => resourceMessages().resourceNoAccessHint);
184
+ return _el$23;
185
+ }
186
+ }), _el$25, _co$4);
187
+ return _el$20;
140
188
  })()]
141
189
  })];
142
190
  }
@@ -152,60 +200,69 @@ export function ResourceCard(props) {
152
200
  },
153
201
  get fallback() {
154
202
  return (() => {
155
- var _el$18 = _$getNextElement(_tmpl$8);
156
- _$insert(_el$18, content);
203
+ var _el$26 = _$getNextElement(_tmpl$0);
204
+ _$insert(_el$26, content);
157
205
  _$effect(_p$ => {
158
- var _v$ = className(),
159
- _v$2 = state(),
160
- _v$3 = state() === "loading" ? "true" : undefined;
161
- _v$ !== _p$.e && _$className(_el$18, _p$.e = _v$);
162
- _v$2 !== _p$.t && _$setAttribute(_el$18, "data-state", _p$.t = _v$2);
163
- _v$3 !== _p$.a && _$setAttribute(_el$18, "aria-busy", _p$.a = _v$3);
206
+ var _v$3 = className(),
207
+ _v$4 = state(),
208
+ _v$5 = ok() ? props.color : undefined,
209
+ _v$6 = state() === "loading" ? "true" : undefined;
210
+ _v$3 !== _p$.e && _$className(_el$26, _p$.e = _v$3);
211
+ _v$4 !== _p$.t && _$setAttribute(_el$26, "data-state", _p$.t = _v$4);
212
+ _v$5 !== _p$.a && _$setAttribute(_el$26, "data-color", _p$.a = _v$5);
213
+ _v$6 !== _p$.o && _$setAttribute(_el$26, "aria-busy", _p$.o = _v$6);
164
214
  return _p$;
165
215
  }, {
166
216
  e: undefined,
167
217
  t: undefined,
168
- a: undefined
218
+ a: undefined,
219
+ o: undefined
169
220
  });
170
- return _el$18;
221
+ return _el$26;
171
222
  })();
172
223
  },
173
224
  children: href => (() => {
174
- var _el$19 = _$getNextElement(_tmpl$9);
175
- _$insert(_el$19, content);
225
+ var _el$27 = _$getNextElement(_tmpl$1);
226
+ _$insert(_el$27, content);
176
227
  _$effect(_p$ => {
177
- var _v$4 = className(),
178
- _v$5 = state(),
179
- _v$6 = href();
180
- _v$4 !== _p$.e && _$className(_el$19, _p$.e = _v$4);
181
- _v$5 !== _p$.t && _$setAttribute(_el$19, "data-state", _p$.t = _v$5);
182
- _v$6 !== _p$.a && _$setAttribute(_el$19, "href", _p$.a = _v$6);
228
+ var _v$7 = className(),
229
+ _v$8 = state(),
230
+ _v$9 = props.color,
231
+ _v$0 = href();
232
+ _v$7 !== _p$.e && _$className(_el$27, _p$.e = _v$7);
233
+ _v$8 !== _p$.t && _$setAttribute(_el$27, "data-state", _p$.t = _v$8);
234
+ _v$9 !== _p$.a && _$setAttribute(_el$27, "data-color", _p$.a = _v$9);
235
+ _v$0 !== _p$.o && _$setAttribute(_el$27, "href", _p$.o = _v$0);
183
236
  return _p$;
184
237
  }, {
185
238
  e: undefined,
186
239
  t: undefined,
187
- a: undefined
240
+ a: undefined,
241
+ o: undefined
188
242
  });
189
- return _el$19;
243
+ return _el$27;
190
244
  })()
191
245
  });
192
246
  },
193
247
  children: open => (() => {
194
- var _el$20 = _$getNextElement(_tmpl$0);
195
- _el$20.$$click = () => open()();
196
- _$insert(_el$20, content);
248
+ var _el$28 = _$getNextElement(_tmpl$10);
249
+ _el$28.$$click = () => open()();
250
+ _$insert(_el$28, content);
197
251
  _$effect(_p$ => {
198
- var _v$7 = className(),
199
- _v$8 = state();
200
- _v$7 !== _p$.e && _$className(_el$20, _p$.e = _v$7);
201
- _v$8 !== _p$.t && _$setAttribute(_el$20, "data-state", _p$.t = _v$8);
252
+ var _v$1 = className(),
253
+ _v$10 = state(),
254
+ _v$11 = props.color;
255
+ _v$1 !== _p$.e && _$className(_el$28, _p$.e = _v$1);
256
+ _v$10 !== _p$.t && _$setAttribute(_el$28, "data-state", _p$.t = _v$10);
257
+ _v$11 !== _p$.a && _$setAttribute(_el$28, "data-color", _p$.a = _v$11);
202
258
  return _p$;
203
259
  }, {
204
260
  e: undefined,
205
- t: undefined
261
+ t: undefined,
262
+ a: undefined
206
263
  });
207
264
  _$runHydrationEvents();
208
- return _el$20;
265
+ return _el$28;
209
266
  })()
210
267
  });
211
268
  }
@@ -1 +1 @@
1
- {"version":3,"names":[],"sources":["surfaces/ResourceCard.tsx"],"sourcesContent":["import { type JSX, Match, Show, Switch } from \"solid-js\";\nimport { useUiMessages } from \"../intl/messages\";\nimport { useResourceMessages } from \"./resource-messages\";\n\n/**\n * What a card can show of the element it stands for: the element itself, a placeholder while it is being looked up, or\n * why it cannot be shown.\n */\nexport type ResourceCardState = \"ok\" | \"loading\" | \"no_access\" | \"deleted\" | \"unavailable\";\n\nexport type ResourceCardProps = {\n /** Defaults to `\"ok\"`. Every state has the same size, so a card that changes state moves nothing around it. */\n state?: ResourceCardState;\n /** The element's name. Shown only in state `\"ok\"`, as \"Untitled\" when blank, so a card that opens always has a name. */\n title?: string;\n /** Icon class of the element's kind, for example `ti ti-notebook`. Shown only in state `\"ok\"`. */\n icon?: string;\n /** What the element belongs to, for example the application or service. Shown only in state `\"ok\"`. */\n source?: string;\n /** Where the element lives within its source, for example a folder or a project. Shown only in state `\"ok\"`. */\n location?: string;\n /** One line of plain text from the element. Shown only in state `\"ok\"`. */\n preview?: string;\n /** Opens the element, for example in a panel. Takes precedence over `href`. Only in state `\"ok\"`. */\n onOpen?: () => void;\n /** Opens the element. Absolute `https` or `http`, or relative. Only in state `\"ok\"`. */\n href?: string;\n class?: string;\n};\n\nconst DEFAULT_ICON = \"ti ti-file\";\nconst LINK_PROTOCOLS = new Set([\"https:\", \"http:\"]);\nconst STATE_ICONS = { no_access: \"ti ti-lock\", deleted: \"ti ti-trash\", unavailable: \"ti ti-cloud-off\" } as const;\n\n/** A link the card may open: absolute with an allowed scheme, or relative to the page. */\nconst linkUrl = (href: string | undefined): string | undefined => {\n if (!href) return undefined;\n try {\n return LINK_PROTOCOLS.has(new URL(href, \"https://relative.invalid/\").protocol) ? href : undefined;\n } catch {\n return undefined;\n }\n};\n\n/**\n * A card for an element that something refers to, such as a task or a document, with the same size in every state.\n * Outside state `\"ok\"`, it shows none of the element's fields and opens nothing, whatever the caller passes.\n */\nexport function ResourceCard(props: ResourceCardProps): JSX.Element {\n const messages = useUiMessages();\n const resourceMessages = useResourceMessages();\n const state = () => props.state ?? \"ok\";\n const ok = () => state() === \"ok\";\n const title = () => (props.title?.trim() ? props.title : resourceMessages().resourceUntitled);\n const meta = () => [props.source, props.location].filter((part) => part?.trim()).join(\" · \");\n /** Why the element cannot be shown, outside `\"ok\"` and `\"loading\"`. */\n const reason = (): Exclude<ResourceCardState, \"ok\" | \"loading\"> | undefined => {\n const current = state();\n return current === \"ok\" || current === \"loading\" ? undefined : current;\n };\n const className = () => `k2b-resource-card${props.class ? ` ${props.class}` : \"\"}`;\n\n const content = () => (\n <Switch>\n <Match when={ok()}>\n <span class=\"k2b-resource-card__icon\" aria-hidden=\"true\">\n <i class={props.icon ?? DEFAULT_ICON} />\n </span>\n <span class=\"k2b-resource-card__copy\">\n <span class=\"k2b-resource-card__title\">{title()}</span>\n <Show when={meta()}>\n <span class=\"k2b-resource-card__meta\">{meta()}</span>\n </Show>\n <Show when={props.preview?.trim()}>\n <span class=\"k2b-resource-card__preview\">{props.preview}</span>\n </Show>\n </span>\n </Match>\n <Match when={state() === \"loading\"}>\n <span class=\"k2b-resource-card__icon\" aria-hidden=\"true\" />\n <span class=\"k2b-resource-card__copy\">\n <span class=\"k2b-resource-card__bar\" aria-hidden=\"true\" />\n <span class=\"k2b-resource-card__bar\" aria-hidden=\"true\" />\n <span class=\"k2b-sr-only\">{messages().loading}</span>\n </span>\n </Match>\n <Match when={reason()}>\n {(reason) => (\n <>\n <span class=\"k2b-resource-card__icon\" aria-hidden=\"true\">\n <i class={STATE_ICONS[reason()]} />\n </span>\n <span class=\"k2b-resource-card__copy\">\n <span class=\"k2b-resource-card__label\">\n {reason() === \"no_access\"\n ? resourceMessages().resourceNoAccess\n : reason() === \"deleted\"\n ? resourceMessages().resourceDeleted\n : resourceMessages().resourceUnavailable}\n </span>\n </span>\n </>\n )}\n </Match>\n </Switch>\n );\n\n return (\n <Show\n when={ok() && props.onOpen}\n fallback={\n <Show\n when={ok() && linkUrl(props.href)}\n fallback={\n <div class={className()} data-state={state()} aria-busy={state() === \"loading\" ? \"true\" : undefined}>\n {content()}\n </div>\n }\n >\n {(href) => (\n <a class={className()} data-state={state()} href={href()}>\n {content()}\n </a>\n )}\n </Show>\n }\n >\n {(open) => (\n <button type=\"button\" class={className()} data-state={state()} onClick={() => open()()}>\n {content()}\n </button>\n )}\n </Show>\n );\n}\n\nexport default ResourceCard;\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"names":[],"sources":["surfaces/ResourceCard.tsx"],"sourcesContent":["import { type JSX, Match, Show, Switch } from \"solid-js\";\nimport { useUiMessages } from \"../intl/messages\";\nimport type { LinkCardColor } from \"./LinkCard\";\nimport { useResourceMessages } from \"./resource-messages\";\n\n/**\n * What a card can show of the element it stands for: the element itself, a placeholder while it is being looked up, or\n * why it cannot be shown.\n */\nexport type ResourceCardState = \"ok\" | \"loading\" | \"no_access\" | \"deleted\" | \"unavailable\";\n\n/** The icon chip's colour, from the same palette as `LinkCard`. */\nexport type ResourceCardColor = LinkCardColor;\n\nexport type ResourceCardProps = {\n /** Defaults to `\"ok\"`. Every state has the same size, so a card that changes state moves nothing around it. */\n state?: ResourceCardState;\n /** The element's name. Shown only in state `\"ok\"`, as \"Untitled\" when blank, so a card that opens always has a name. */\n title?: string;\n /** Icon class of the element's kind, for example `ti ti-notebook`. Shown only in state `\"ok\"`. */\n icon?: string;\n /** Colour of the icon chip, usually one per kind of element. Without it the chip stays neutral. Only in state `\"ok\"`. */\n color?: ResourceCardColor;\n /** One line above the title: what and where the element is, for example \"Task in IT planning · due 30 Oct\". Only in state `\"ok\"`. */\n context?: string;\n /** The element's current state as a short label, for example \"Open\", shown at the end. Only in state `\"ok\"`. */\n status?: string;\n /** What the element belongs to, for example the application or service. Shown only in state `\"ok\"`. */\n source?: string;\n /** Where the element lives within its source, for example a folder or a project. Shown only in state `\"ok\"`. */\n location?: string;\n /** One line of plain text from the element. Shown only in state `\"ok\"`. */\n preview?: string;\n /** Opens the element, for example in a panel. Takes precedence over `href`. Only in state `\"ok\"`. */\n onOpen?: () => void;\n /** Opens the element. Absolute `https` or `http`, or relative. Only in state `\"ok\"`. */\n href?: string;\n class?: string;\n};\n\nconst DEFAULT_ICON = \"ti ti-file\";\nconst LINK_PROTOCOLS = new Set([\"https:\", \"http:\"]);\nconst STATE_ICONS = { no_access: \"ti ti-lock\", deleted: \"ti ti-trash\", unavailable: \"ti ti-cloud-off\" } as const;\n\n/** A link the card may open: absolute with an allowed scheme, or relative to the page. */\nconst linkUrl = (href: string | undefined): string | undefined => {\n if (!href) return undefined;\n try {\n return LINK_PROTOCOLS.has(new URL(href, \"https://relative.invalid/\").protocol) ? href : undefined;\n } catch {\n return undefined;\n }\n};\n\n/**\n * A card for an element that something refers to, such as a task or a document, with the same size in every state.\n * Outside state `\"ok\"`, it shows none of the element's fields and opens nothing, whatever the caller passes.\n */\nexport function ResourceCard(props: ResourceCardProps): JSX.Element {\n const messages = useUiMessages();\n const resourceMessages = useResourceMessages();\n const state = () => props.state ?? \"ok\";\n const ok = () => state() === \"ok\";\n const title = () => (props.title?.trim() ? props.title : resourceMessages().resourceUntitled);\n const meta = () => [props.source, props.location].filter((part) => part?.trim()).join(\" · \");\n /** Why the element cannot be shown, outside `\"ok\"` and `\"loading\"`. */\n const reason = (): Exclude<ResourceCardState, \"ok\" | \"loading\"> | undefined => {\n const current = state();\n return current === \"ok\" || current === \"loading\" ? undefined : current;\n };\n const className = () => `k2b-resource-card${props.class ? ` ${props.class}` : \"\"}`;\n\n const content = () => (\n <Switch>\n <Match when={ok()}>\n <span class={`k2b-resource-card__icon${props.color ? \" k2b-icon-tile\" : \"\"}`} aria-hidden=\"true\">\n <i class={props.icon ?? DEFAULT_ICON} />\n </span>\n <span class=\"k2b-resource-card__copy\">\n <Show when={props.context?.trim()}>\n <span class=\"k2b-resource-card__meta\">{props.context}</span>\n </Show>\n <span class=\"k2b-resource-card__title\">{title()}</span>\n <Show when={meta()}>\n <span class=\"k2b-resource-card__meta\">{meta()}</span>\n </Show>\n <Show when={props.preview?.trim()}>\n <span class=\"k2b-resource-card__preview\">{props.preview}</span>\n </Show>\n </span>\n <Show when={props.status?.trim()}>\n <span class=\"k2b-resource-card__status\">{props.status}</span>\n </Show>\n </Match>\n <Match when={state() === \"loading\"}>\n <span class=\"k2b-resource-card__icon\" aria-hidden=\"true\" />\n <span class=\"k2b-resource-card__copy\">\n <span class=\"k2b-resource-card__bar\" aria-hidden=\"true\" />\n <span class=\"k2b-resource-card__bar\" aria-hidden=\"true\" />\n <span class=\"k2b-sr-only\">{messages().loading}</span>\n </span>\n </Match>\n <Match when={reason()}>\n {(reason) => (\n <>\n <span class=\"k2b-resource-card__icon\" aria-hidden=\"true\">\n <i class={STATE_ICONS[reason()]} />\n </span>\n <span class=\"k2b-resource-card__copy\">\n <span class=\"k2b-resource-card__meta\">{resourceMessages().resourceKind}</span>\n <span class=\"k2b-resource-card__label\">\n {reason() === \"no_access\"\n ? resourceMessages().resourceNoAccess\n : reason() === \"deleted\"\n ? resourceMessages().resourceDeleted\n : resourceMessages().resourceUnavailable}\n </span>\n <Show when={reason() === \"no_access\"}>\n <span class=\"k2b-resource-card__meta\">{resourceMessages().resourceNoAccessHint}</span>\n </Show>\n </span>\n </>\n )}\n </Match>\n </Switch>\n );\n\n return (\n <Show\n when={ok() && props.onOpen}\n fallback={\n <Show\n when={ok() && linkUrl(props.href)}\n fallback={\n <div\n class={className()}\n data-state={state()}\n data-color={ok() ? props.color : undefined}\n aria-busy={state() === \"loading\" ? \"true\" : undefined}\n >\n {content()}\n </div>\n }\n >\n {(href) => (\n <a class={className()} data-state={state()} data-color={props.color} href={href()}>\n {content()}\n </a>\n )}\n </Show>\n }\n >\n {(open) => (\n <button type=\"button\" class={className()} data-state={state()} data-color={props.color} onClick={() => open()()}>\n {content()}\n </button>\n )}\n </Show>\n );\n}\n\nexport default ResourceCard;\n"],"mappings":"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","ignoreList":[]}
@@ -1,6 +1,7 @@
1
1
  export { Avatar } from "./Avatar";
2
2
  export { AvatarStack } from "./AvatarStack";
3
3
  export { DescriptionList } from "./DescriptionList";
4
+ export { DotStrip } from "./DotStrip";
4
5
  export { LinkCard } from "./LinkCard";
5
6
  export { NotFoundState } from "./NotFoundState";
6
7
  export { NOTICE_CARD_CLASSES, NoticeCard } from "./NoticeCard";
@@ -8,6 +9,7 @@ export { Paper } from "./Paper";
8
9
  export { default as Placeholder } from "./Placeholder";
9
10
  export { ProgressBar } from "./ProgressBar";
10
11
  export { ProgressRing } from "./ProgressRing";
12
+ export { PERSON_COLORS, personColor } from "./person-color";
11
13
  export { ResourceCard } from "./ResourceCard";
12
14
  export { Skeleton } from "./Skeleton";
13
15
  export { StatCell } from "./StatCell";
@@ -1 +1 @@
1
- {"version":3,"names":[],"sources":["surfaces/index.ts"],"sourcesContent":["export type { AvatarProps, AvatarRing, AvatarShape, AvatarSize } from \"./Avatar\";\nexport { Avatar } from \"./Avatar\";\nexport type { AvatarStackPerson, AvatarStackProps } from \"./AvatarStack\";\nexport { AvatarStack } from \"./AvatarStack\";\nexport type { DescriptionListItem, DescriptionListProps } from \"./DescriptionList\";\nexport { DescriptionList } from \"./DescriptionList\";\nexport type { LinkCardColor, LinkCardProps } from \"./LinkCard\";\nexport { LinkCard } from \"./LinkCard\";\nexport type { NotFoundStateAction, NotFoundStateProps } from \"./NotFoundState\";\nexport { NotFoundState } from \"./NotFoundState\";\nexport type { NoticeCardProps, NoticeGridProps, NoticeTone } from \"./NoticeCard\";\nexport { NOTICE_CARD_CLASSES, NoticeCard } from \"./NoticeCard\";\nexport type { PaperProps, PaperTag } from \"./Paper\";\nexport { Paper } from \"./Paper\";\nexport type {\n PlaceholderAlign,\n PlaceholderProps,\n PlaceholderState,\n PlaceholderSurface,\n PlaceholderVariant,\n} from \"./Placeholder\";\nexport { default as Placeholder } from \"./Placeholder\";\nexport type { ProgressBarProps, ProgressBarTone } from \"./ProgressBar\";\nexport { ProgressBar } from \"./ProgressBar\";\nexport type { ProgressRingProps, ProgressRingTone } from \"./ProgressRing\";\nexport { ProgressRing } from \"./ProgressRing\";\nexport type { ResourceCardProps, ResourceCardState } from \"./ResourceCard\";\nexport { ResourceCard } from \"./ResourceCard\";\nexport { Skeleton, type SkeletonProps } from \"./Skeleton\";\nexport type { StatCellAccent, StatCellProps, StatCellTone } from \"./StatCell\";\nexport { StatCell } from \"./StatCell\";\nexport type {\n StatGridAction,\n StatGridColumns,\n StatGridProps,\n StatGridSize,\n StatGridSurface,\n} from \"./StatGrid\";\nexport { StatGrid } from \"./StatGrid\";\nexport type { StatusBadgeProps, StatusTone } from \"./StatusBadge\";\nexport { StatusBadge } from \"./StatusBadge\";\nexport type { TagProps, TagSize } from \"./Tag\";\nexport { Tag } from \"./Tag\";\n"],"mappings":"AACA,SAAS,MAAM,QAAQ,UAAU;AAEjC,SAAS,WAAW,QAAQ,eAAe;AAE3C,SAAS,eAAe,QAAQ,mBAAmB;AAEnD,SAAS,QAAQ,QAAQ,YAAY;AAErC,SAAS,aAAa,QAAQ,iBAAiB;AAE/C,SAAS,mBAAmB,EAAE,UAAU,QAAQ,cAAc;AAE9D,SAAS,KAAK,QAAQ,SAAS;AAQ/B,SAAS,OAAO,IAAI,WAAW,QAAQ,eAAe;AAEtD,SAAS,WAAW,QAAQ,eAAe;AAE3C,SAAS,YAAY,QAAQ,gBAAgB;AAE7C,SAAS,YAAY,QAAQ,gBAAgB;AAC7C,SAAS,QAAQ,QAA4B,YAAY;AAEzD,SAAS,QAAQ,QAAQ,YAAY;AAQrC,SAAS,QAAQ,QAAQ,YAAY;AAErC,SAAS,WAAW,QAAQ,eAAe;AAE3C,SAAS,GAAG,QAAQ,OAAO","ignoreList":[]}
1
+ {"version":3,"names":[],"sources":["surfaces/index.ts"],"sourcesContent":["export type { AvatarProps, AvatarRing, AvatarShape, AvatarSize } from \"./Avatar\";\nexport { Avatar } from \"./Avatar\";\nexport type { AvatarStackPerson, AvatarStackProps } from \"./AvatarStack\";\nexport { AvatarStack } from \"./AvatarStack\";\nexport type { DescriptionListItem, DescriptionListProps } from \"./DescriptionList\";\nexport { DescriptionList } from \"./DescriptionList\";\nexport type { DotStripProps, DotStripTone } from \"./DotStrip\";\nexport { DotStrip } from \"./DotStrip\";\nexport type { LinkCardColor, LinkCardProps } from \"./LinkCard\";\nexport { LinkCard } from \"./LinkCard\";\nexport type { NotFoundStateAction, NotFoundStateProps } from \"./NotFoundState\";\nexport { NotFoundState } from \"./NotFoundState\";\nexport type { NoticeCardProps, NoticeGridProps, NoticeTone } from \"./NoticeCard\";\nexport { NOTICE_CARD_CLASSES, NoticeCard } from \"./NoticeCard\";\nexport type { PaperProps, PaperTag } from \"./Paper\";\nexport { Paper } from \"./Paper\";\nexport type {\n PlaceholderAlign,\n PlaceholderProps,\n PlaceholderState,\n PlaceholderSurface,\n PlaceholderVariant,\n} from \"./Placeholder\";\nexport { default as Placeholder } from \"./Placeholder\";\nexport type { ProgressBarProps, ProgressBarTone } from \"./ProgressBar\";\nexport { ProgressBar } from \"./ProgressBar\";\nexport type { ProgressRingProps, ProgressRingTone } from \"./ProgressRing\";\nexport { ProgressRing } from \"./ProgressRing\";\nexport { PERSON_COLORS, personColor } from \"./person-color\";\nexport type { ResourceCardColor, ResourceCardProps, ResourceCardState } from \"./ResourceCard\";\nexport { ResourceCard } from \"./ResourceCard\";\nexport { Skeleton, type SkeletonProps } from \"./Skeleton\";\nexport type { StatCellAccent, StatCellProps, StatCellTone } from \"./StatCell\";\nexport { StatCell } from \"./StatCell\";\nexport type {\n StatGridAction,\n StatGridColumns,\n StatGridProps,\n StatGridSize,\n StatGridSurface,\n} from \"./StatGrid\";\nexport { StatGrid } from \"./StatGrid\";\nexport type { StatusBadgeProps, StatusTone } from \"./StatusBadge\";\nexport { StatusBadge } from \"./StatusBadge\";\nexport type { TagProps, TagSize } from \"./Tag\";\nexport { Tag } from \"./Tag\";\n"],"mappings":"AACA,SAAS,MAAM,QAAQ,UAAU;AAEjC,SAAS,WAAW,QAAQ,eAAe;AAE3C,SAAS,eAAe,QAAQ,mBAAmB;AAEnD,SAAS,QAAQ,QAAQ,YAAY;AAErC,SAAS,QAAQ,QAAQ,YAAY;AAErC,SAAS,aAAa,QAAQ,iBAAiB;AAE/C,SAAS,mBAAmB,EAAE,UAAU,QAAQ,cAAc;AAE9D,SAAS,KAAK,QAAQ,SAAS;AAQ/B,SAAS,OAAO,IAAI,WAAW,QAAQ,eAAe;AAEtD,SAAS,WAAW,QAAQ,eAAe;AAE3C,SAAS,YAAY,QAAQ,gBAAgB;AAC7C,SAAS,aAAa,EAAE,WAAW,QAAQ,gBAAgB;AAE3D,SAAS,YAAY,QAAQ,gBAAgB;AAC7C,SAAS,QAAQ,QAA4B,YAAY;AAEzD,SAAS,QAAQ,QAAQ,YAAY;AAQrC,SAAS,QAAQ,QAAQ,YAAY;AAErC,SAAS,WAAW,QAAQ,eAAe;AAE3C,SAAS,GAAG,QAAQ,OAAO","ignoreList":[]}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * The colors that stand for a person: the tint behind avatar initials, a collaborator's cursor, and the marks and
3
+ * comments a person leaves. The palette leaves out cyan, which means AI, and yellow, which reads as a text highlight.
4
+ * Several people can share a color, so a person's name always appears next to it.
5
+ */
6
+ export const PERSON_COLORS = ["#3b82f6", "#6366f1", "#8b5cf6", "#c026d3", "#ec4899", "#e11d48", "#f97316", "#16a34a"];
7
+
8
+ /** The palette index for a name, the order of the `.k2b-avatar[data-tint]` rules. Surrounding spaces do not count. */
9
+ export const personTint = name => {
10
+ const trimmed = name.trim();
11
+ let hash = 0;
12
+ for (let index = 0; index < trimmed.length; index++) hash = hash * 31 + trimmed.charCodeAt(index) >>> 0;
13
+ return hash % PERSON_COLORS.length;
14
+ };
15
+
16
+ /** A person's color from their display name, the same wherever Cloud shows that person. */
17
+ export const personColor = name => PERSON_COLORS[personTint(name)];
18
+ //# sourceMappingURL=person-color.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":[],"sources":["surfaces/person-color.ts"],"sourcesContent":["/**\n * The colors that stand for a person: the tint behind avatar initials, a collaborator's cursor, and the marks and\n * comments a person leaves. The palette leaves out cyan, which means AI, and yellow, which reads as a text highlight.\n * Several people can share a color, so a person's name always appears next to it.\n */\nexport const PERSON_COLORS = [\"#3b82f6\", \"#6366f1\", \"#8b5cf6\", \"#c026d3\", \"#ec4899\", \"#e11d48\", \"#f97316\", \"#16a34a\"] as const;\n\n/** The palette index for a name, the order of the `.k2b-avatar[data-tint]` rules. Surrounding spaces do not count. */\nexport const personTint = (name: string): number => {\n const trimmed = name.trim();\n let hash = 0;\n for (let index = 0; index < trimmed.length; index++) hash = (hash * 31 + trimmed.charCodeAt(index)) >>> 0;\n return hash % PERSON_COLORS.length;\n};\n\n/** A person's color from their display name, the same wherever Cloud shows that person. */\nexport const personColor = (name: string): string => PERSON_COLORS[personTint(name)]!;\n"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA,OAAO,MAAM,aAAa,GAAG,CAAC,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,CAAU;;AAE9H;AACA,OAAO,MAAM,UAAU,GAAI,IAAY,IAAa;EAClD,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC;EAC3B,IAAI,IAAI,GAAG,CAAC;EACZ,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,OAAO,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,IAAI,GAAI,IAAI,GAAG,EAAE,GAAG,OAAO,CAAC,UAAU,CAAC,KAAK,CAAC,KAAM,CAAC;EACzG,OAAO,IAAI,GAAG,aAAa,CAAC,MAAM;AACpC,CAAC;;AAED;AACA,OAAO,MAAM,WAAW,GAAI,IAAY,IAAa,aAAa,CAAC,UAAU,CAAC,IAAI,CAAC,CAAE","ignoreList":[]}
@@ -7,13 +7,17 @@ const resourceMessages = i18n.define({
7
7
  resourceUntitled: "Untitled",
8
8
  resourceNoAccess: "Item not available",
9
9
  resourceDeleted: "Item deleted",
10
- resourceUnavailable: "Not available right now"
10
+ resourceUnavailable: "Not available right now",
11
+ resourceKind: "Cloud element",
12
+ resourceNoAccessHint: "You have no access. Title and content stay hidden."
11
13
  },
12
14
  de: {
13
15
  resourceUntitled: "Ohne Titel",
14
16
  resourceNoAccess: "Element nicht verfügbar",
15
17
  resourceDeleted: "Element gelöscht",
16
- resourceUnavailable: "Gerade nicht verfügbar"
18
+ resourceUnavailable: "Gerade nicht verfügbar",
19
+ resourceKind: "Cloud-Element",
20
+ resourceNoAccessHint: "Du hast keinen Zugriff. Titel und Inhalt bleiben verborgen."
17
21
  }
18
22
  }
19
23
  });
@@ -1 +1 @@
1
- {"version":3,"names":[],"sources":["surfaces/resource-messages.ts"],"sourcesContent":["import { i18n } from \"@k2b/stdlib\";\nimport { useLocale } from \"../intl/locale\";\n\nconst resourceMessages = i18n.define({\n baseLocale: \"en\",\n messages: {\n en: {\n resourceUntitled: \"Untitled\",\n resourceNoAccess: \"Item not available\",\n resourceDeleted: \"Item deleted\",\n resourceUnavailable: \"Not available right now\",\n },\n de: {\n resourceUntitled: \"Ohne Titel\",\n resourceNoAccess: \"Element nicht verfügbar\",\n resourceDeleted: \"Element gelöscht\",\n resourceUnavailable: \"Gerade nicht verfügbar\",\n },\n },\n});\n\nexport type ResourceMessages = ReturnType<(typeof resourceMessages)[\"resolve\"]>[\"t\"];\n\n/** Resolved from the inherited render locale. */\nexport const useResourceMessages = (): (() => ResourceMessages) => {\n const locale = useLocale();\n return () => resourceMessages.resolve([locale()]).t;\n};\n\nexport const checkResourceMessages = () => resourceMessages.check();\n"],"mappings":"AAAA,SAAS,IAAI,QAAQ,aAAa;AAClC,SAAS,SAAS,QAAQ,gBAAgB;AAE1C,MAAM,gBAAgB,GAAG,IAAI,CAAC,MAAM,CAAC;EACnC,UAAU,EAAE,IAAI;EAChB,QAAQ,EAAE;IACR,EAAE,EAAE;MACF,gBAAgB,EAAE,UAAU;MAC5B,gBAAgB,EAAE,oBAAoB;MACtC,eAAe,EAAE,cAAc;MAC/B,mBAAmB,EAAE;IACvB,CAAC;IACD,EAAE,EAAE;MACF,gBAAgB,EAAE,YAAY;MAC9B,gBAAgB,EAAE,yBAAyB;MAC3C,eAAe,EAAE,kBAAkB;MACnC,mBAAmB,EAAE;IACvB;EACF;AACF,CAAC,CAAC;AAIF;AACA,OAAO,MAAM,mBAAmB,GAAG,MAAgC;EACjE,MAAM,MAAM,GAAG,SAAS,CAAC,CAAC;EAC1B,OAAO,MAAM,gBAAgB,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACrD,CAAC;AAED,OAAO,MAAM,qBAAqB,GAAG,MAAM,gBAAgB,CAAC,KAAK,CAAC,CAAC","ignoreList":[]}
1
+ {"version":3,"names":[],"sources":["surfaces/resource-messages.ts"],"sourcesContent":["import { i18n } from \"@k2b/stdlib\";\nimport { useLocale } from \"../intl/locale\";\n\nconst resourceMessages = i18n.define({\n baseLocale: \"en\",\n messages: {\n en: {\n resourceUntitled: \"Untitled\",\n resourceNoAccess: \"Item not available\",\n resourceDeleted: \"Item deleted\",\n resourceUnavailable: \"Not available right now\",\n resourceKind: \"Cloud element\",\n resourceNoAccessHint: \"You have no access. Title and content stay hidden.\",\n },\n de: {\n resourceUntitled: \"Ohne Titel\",\n resourceNoAccess: \"Element nicht verfügbar\",\n resourceDeleted: \"Element gelöscht\",\n resourceUnavailable: \"Gerade nicht verfügbar\",\n resourceKind: \"Cloud-Element\",\n resourceNoAccessHint: \"Du hast keinen Zugriff. Titel und Inhalt bleiben verborgen.\",\n },\n },\n});\n\nexport type ResourceMessages = ReturnType<(typeof resourceMessages)[\"resolve\"]>[\"t\"];\n\n/** Resolved from the inherited render locale. */\nexport const useResourceMessages = (): (() => ResourceMessages) => {\n const locale = useLocale();\n return () => resourceMessages.resolve([locale()]).t;\n};\n\nexport const checkResourceMessages = () => resourceMessages.check();\n"],"mappings":"AAAA,SAAS,IAAI,QAAQ,aAAa;AAClC,SAAS,SAAS,QAAQ,gBAAgB;AAE1C,MAAM,gBAAgB,GAAG,IAAI,CAAC,MAAM,CAAC;EACnC,UAAU,EAAE,IAAI;EAChB,QAAQ,EAAE;IACR,EAAE,EAAE;MACF,gBAAgB,EAAE,UAAU;MAC5B,gBAAgB,EAAE,oBAAoB;MACtC,eAAe,EAAE,cAAc;MAC/B,mBAAmB,EAAE,yBAAyB;MAC9C,YAAY,EAAE,eAAe;MAC7B,oBAAoB,EAAE;IACxB,CAAC;IACD,EAAE,EAAE;MACF,gBAAgB,EAAE,YAAY;MAC9B,gBAAgB,EAAE,yBAAyB;MAC3C,eAAe,EAAE,kBAAkB;MACnC,mBAAmB,EAAE,wBAAwB;MAC7C,YAAY,EAAE,eAAe;MAC7B,oBAAoB,EAAE;IACxB;EACF;AACF,CAAC,CAAC;AAIF;AACA,OAAO,MAAM,mBAAmB,GAAG,MAAgC;EACjE,MAAM,MAAM,GAAG,SAAS,CAAC,CAAC;EAC1B,OAAO,MAAM,gBAAgB,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACrD,CAAC;AAED,OAAO,MAAM,qBAAqB,GAAG,MAAM,gBAAgB,CAAC,KAAK,CAAC,CAAC","ignoreList":[]}
@@ -18,8 +18,9 @@ import { Show } from "solid-js";
18
18
  import { Paper } from "../surfaces/Paper";
19
19
 
20
20
  /**
21
- * `standard` is 25rem high and `compact` 14rem; `fill` takes the height its container gives it, such as a grid cell,
22
- * and `content` has no fixed height. Every size except `content` scrolls body content taller than itself.
21
+ * `standard` is 25rem high and `compact` 14rem; `fill` takes the height and the width its container gives it, such as
22
+ * a grid cell, and does not size itself from its content; `content` has no fixed height. Every size except `content`
23
+ * scrolls body content taller than itself.
23
24
  */
24
25
 
25
26
  function Header(props) {
@@ -1 +1 @@
1
- {"version":3,"names":[],"sources":["widgets/Widget.tsx"],"sourcesContent":["import { type JSX, Show } from \"solid-js\";\nimport { Paper } from \"../surfaces/Paper\";\n\n/**\n * `standard` is 25rem high and `compact` 14rem; `fill` takes the height its container gives it, such as a grid cell,\n * and `content` has no fixed height. Every size except `content` scrolls body content taller than itself.\n */\nexport type WidgetSize = \"content\" | \"compact\" | \"standard\" | \"fill\";\n\nexport type WidgetProps = {\n title: string;\n icon?: string;\n href?: string;\n meta?: string;\n size?: WidgetSize;\n children: JSX.Element;\n};\n\nfunction Header(props: WidgetProps): JSX.Element {\n return (\n <>\n <Show when={props.icon}>\n {(icon) => (\n <span class=\"k2b-widget__icon k2b-icon-tile\" aria-hidden=\"true\">\n <i class={icon()} />\n </span>\n )}\n </Show>\n <span class=\"k2b-widget__heading\">\n <span class=\"k2b-widget__title\">{props.title}</span>\n <Show when={props.meta}>{(meta) => <span class=\"k2b-widget__meta\">{meta()}</span>}</Show>\n </span>\n <Show when={props.href}>\n <i class=\"ti ti-chevron-right k2b-widget__chevron\" aria-hidden=\"true\" />\n </Show>\n </>\n );\n}\n\nexport function Widget(props: WidgetProps): JSX.Element {\n return (\n <Paper class=\"k2b-widget\" data-size={props.size ?? \"standard\"}>\n <Show\n when={props.href}\n fallback={\n <div class=\"k2b-widget__header\">\n <Header {...props} />\n </div>\n }\n >\n {(href) => (\n <a href={href()} class=\"k2b-widget__header\">\n <Header {...props} />\n </a>\n )}\n </Show>\n <div class=\"k2b-widget__body\">{props.children}</div>\n </Paper>\n );\n}\n\nexport default Widget;\n"],"mappings":";;;;;;;;;;;;;;;;AAAA,SAAmB,IAAI,QAAQ,UAAU;AACzC,SAAS,KAAK,QAAQ,mBAAmB;;AAEzC;AACA;AACA;AACA;;AAYA,SAAS,MAAM,CAAC,KAAkB,EAAe;EAC/C,0BAEK,IAAI;IAAA,IAAC,IAAI;MAAA,OAAE,KAAK,CAAC,IAAI;IAAA;IAAA,UAClB,IAAI;MAAA;QAAA;MAAA,kCAEQ,IAAI,CAAC,CAAC;MAAA;IAAA;EAEnB;IAAA;MAAA;MAAA;MAAA;IAAA,sBAGgC,KAAK,CAAC,KAAK;IAAA,iCAC3C,IAAI;MAAA,IAAC,IAAI;QAAA,OAAE,KAAK,CAAC,IAAI;MAAA;MAAA,UAAI,IAAI;QAAA;QAAA,gBAAqC,IAAI;QAAA;MAAA;IAAU;IAAA;EAAA,wBAElF,IAAI;IAAA,IAAC,IAAI;MAAA,OAAE,KAAK,CAAC,IAAI;IAAA;IAAA;MAAA;IAAA;EAAA;AAK5B;AAEA,OAAO,SAAS,MAAM,CAAC,KAAkB,EAAe;EACtD,yBACG,KAAK;IAAA;IAAA;MAAA,OAA+B,KAAK,CAAC,IAAI,IAAI,UAAU;IAAA;IAAA;MAAA,0BAC1D,IAAI;QAAA,IACH,IAAI;UAAA,OAAE,KAAK,CAAC,IAAI;QAAA;QAAA,IAChB,QAAQ;UAAA;YAAA;YAAA,kCAEH,MAAM,EAAK,KAAK;YAAA;UAAA;QAAA;QAAA,UAInB,IAAI;UAAA;UAAA,kCAED,MAAM,EAAK,KAAK;UAAA,6CADV,IAAI,CAAC,CAAC;UAAA;QAAA;MAGhB;QAAA;QAAA,sBAE4B,KAAK,CAAC,QAAQ;QAAA;MAAA;IAAA;EAAA;AAGnD;AAEA,eAAe,MAAM","ignoreList":[]}
1
+ {"version":3,"names":[],"sources":["widgets/Widget.tsx"],"sourcesContent":["import { type JSX, Show } from \"solid-js\";\nimport { Paper } from \"../surfaces/Paper\";\n\n/**\n * `standard` is 25rem high and `compact` 14rem; `fill` takes the height and the width its container gives it, such as\n * a grid cell, and does not size itself from its content; `content` has no fixed height. Every size except `content`\n * scrolls body content taller than itself.\n */\nexport type WidgetSize = \"content\" | \"compact\" | \"standard\" | \"fill\";\n\nexport type WidgetProps = {\n title: string;\n icon?: string;\n href?: string;\n meta?: string;\n size?: WidgetSize;\n children: JSX.Element;\n};\n\nfunction Header(props: WidgetProps): JSX.Element {\n return (\n <>\n <Show when={props.icon}>\n {(icon) => (\n <span class=\"k2b-widget__icon k2b-icon-tile\" aria-hidden=\"true\">\n <i class={icon()} />\n </span>\n )}\n </Show>\n <span class=\"k2b-widget__heading\">\n <span class=\"k2b-widget__title\">{props.title}</span>\n <Show when={props.meta}>{(meta) => <span class=\"k2b-widget__meta\">{meta()}</span>}</Show>\n </span>\n <Show when={props.href}>\n <i class=\"ti ti-chevron-right k2b-widget__chevron\" aria-hidden=\"true\" />\n </Show>\n </>\n );\n}\n\nexport function Widget(props: WidgetProps): JSX.Element {\n return (\n <Paper class=\"k2b-widget\" data-size={props.size ?? \"standard\"}>\n <Show\n when={props.href}\n fallback={\n <div class=\"k2b-widget__header\">\n <Header {...props} />\n </div>\n }\n >\n {(href) => (\n <a href={href()} class=\"k2b-widget__header\">\n <Header {...props} />\n </a>\n )}\n </Show>\n <div class=\"k2b-widget__body\">{props.children}</div>\n </Paper>\n );\n}\n\nexport default Widget;\n"],"mappings":";;;;;;;;;;;;;;;;AAAA,SAAmB,IAAI,QAAQ,UAAU;AACzC,SAAS,KAAK,QAAQ,mBAAmB;;AAEzC;AACA;AACA;AACA;AACA;;AAYA,SAAS,MAAM,CAAC,KAAkB,EAAe;EAC/C,0BAEK,IAAI;IAAA,IAAC,IAAI;MAAA,OAAE,KAAK,CAAC,IAAI;IAAA;IAAA,UAClB,IAAI;MAAA;QAAA;MAAA,kCAEQ,IAAI,CAAC,CAAC;MAAA;IAAA;EAEnB;IAAA;MAAA;MAAA;MAAA;IAAA,sBAGgC,KAAK,CAAC,KAAK;IAAA,iCAC3C,IAAI;MAAA,IAAC,IAAI;QAAA,OAAE,KAAK,CAAC,IAAI;MAAA;MAAA,UAAI,IAAI;QAAA;QAAA,gBAAqC,IAAI;QAAA;MAAA;IAAU;IAAA;EAAA,wBAElF,IAAI;IAAA,IAAC,IAAI;MAAA,OAAE,KAAK,CAAC,IAAI;IAAA;IAAA;MAAA;IAAA;EAAA;AAK5B;AAEA,OAAO,SAAS,MAAM,CAAC,KAAkB,EAAe;EACtD,yBACG,KAAK;IAAA;IAAA;MAAA,OAA+B,KAAK,CAAC,IAAI,IAAI,UAAU;IAAA;IAAA;MAAA,0BAC1D,IAAI;QAAA,IACH,IAAI;UAAA,OAAE,KAAK,CAAC,IAAI;QAAA;QAAA,IAChB,QAAQ;UAAA;YAAA;YAAA,kCAEH,MAAM,EAAK,KAAK;YAAA;UAAA;QAAA;QAAA,UAInB,IAAI;UAAA;UAAA,kCAED,MAAM,EAAK,KAAK;UAAA,6CADV,IAAI,CAAC,CAAC;UAAA;QAAA;MAGhB;QAAA;QAAA,sBAE4B,KAAK,CAAC,QAAQ;QAAA;MAAA;IAAA;EAAA;AAGnD;AAEA,eAAe,MAAM","ignoreList":[]}
@@ -12,6 +12,7 @@ import { returnFocus, ringOnReturn } from "../internal/focus-return";
12
12
  import { useUiMessages } from "../intl/messages";
13
13
  import { DropdownItems, dropdownPosition } from "./Dropdown";
14
14
  import { focusRowSegment } from "./menu-rows";
15
+ const NATIVE_MENU_TARGETS = "a[href], input, textarea, select, [contenteditable]:not([contenteditable='false'])";
15
16
  let closeActiveContextMenu;
16
17
  const focusableItems = menu => menu ? Array.from(menu.querySelectorAll(["[role='menuitem']:not([aria-disabled='true'])", "[role='menuitemcheckbox']:not([aria-disabled='true'])", "[role='menuitemradio']:not([aria-disabled='true'])"].join(", "))) : [];
17
18
 
@@ -45,6 +46,14 @@ export function ContextMenuBase(props) {
45
46
  };
46
47
  let resizeObserver;
47
48
  const isOpen = () => position() !== undefined;
49
+ const keepsNativeMenu = target => {
50
+ if (!props.keepNativeMenu || !(target instanceof Node)) return false;
51
+ const element = target instanceof Element ? target : target.parentElement;
52
+ const native = element?.closest(NATIVE_MENU_TARGETS);
53
+ if (native && host?.contains(native)) return true;
54
+ const selection = window.getSelection();
55
+ return Boolean(selection && !selection.isCollapsed && selection.toString().trim() && selection.containsNode(target, true));
56
+ };
48
57
  const hostClass = createMemo(() => typeof props.class === "function" ? props.class(isOpen()) : props.class);
49
58
  const items = createMemo(() => props.items);
50
59
  const dismiss = event => {
@@ -1 +1 @@
1
- {"version":3,"names":[],"sources":["actions/ContextMenu.tsx"],"sourcesContent":["import { createMemo, createSignal, createUniqueId, type JSX, onCleanup, onMount, Show } from \"solid-js\";\nimport { Portal } from \"solid-js/web\";\nimport { returnFocus, ringOnReturn } from \"../internal/focus-return\";\nimport { useUiMessages } from \"../intl/messages\";\nimport { type DropdownItem, DropdownItems, type DropdownPosition, dropdownPosition } from \"./Dropdown\";\nimport { focusRowSegment } from \"./menu-rows\";\n\nexport type ContextMenuProps = {\n items: readonly DropdownItem[];\n children: JSX.Element;\n class?: string | ((isOpen: boolean) => string);\n /** Tab order of the context-menu host. Descendant-focused composite widgets use -1. */\n tabIndex?: number;\n disabled?: boolean;\n onClose?: () => void;\n onOpen?: () => void;\n id?: string;\n label?: string;\n};\n\nlet closeActiveContextMenu: (() => void) | undefined;\n\nconst focusableItems = (menu: HTMLElement | undefined): HTMLElement[] =>\n menu\n ? Array.from(\n menu.querySelectorAll<HTMLElement>(\n [\n \"[role='menuitem']:not([aria-disabled='true'])\",\n \"[role='menuitemcheckbox']:not([aria-disabled='true'])\",\n \"[role='menuitemradio']:not([aria-disabled='true'])\",\n ].join(\", \"),\n ),\n )\n : [];\n\n/** Right-click menu with keyboard invocation, one-open-at-a-time behavior, and viewport clamping. */\nexport function ContextMenu(props: ContextMenuProps): JSX.Element {\n return ContextMenuBase(props);\n}\n\n/**\n * Package-internal, not exported from the package index: `openAt` lets GestureMenu open the menu at a held finger, and\n * `title` names what was pressed above the entries, since the finger covers it.\n */\nexport function ContextMenuBase(\n props: ContextMenuProps & {\n openAt?: (open: (x: number, y: number) => void) => void;\n title?: string;\n closeWith?: (close: () => void) => void;\n },\n): JSX.Element {\n const messages = useUiMessages();\n const generatedId = `k2b-context-${createUniqueId()}`;\n const menuId = `${generatedId}-menu`;\n const [position, setPosition] = createSignal<{ x: number; y: number }>();\n let host: HTMLDivElement | undefined;\n let menu: HTMLDivElement | undefined;\n let listenersAttached = false;\n let hostRing = true;\n /** The element inside the host that had focus as the menu opened, such as a row or a day of a composite widget. */\n let opener: HTMLElement | undefined;\n let anchor = { x: 0, y: 0 };\n let viewport = { width: 0, height: 0 };\n let resizeObserver: ResizeObserver | undefined;\n\n const isOpen = () => position() !== undefined;\n const hostClass = createMemo(() => (typeof props.class === \"function\" ? props.class(isOpen()) : props.class));\n const items = createMemo<readonly DropdownItem[]>(() => props.items);\n\n const dismiss = (event: PointerEvent) => {\n if (menu?.contains(event.target as Node)) return;\n close();\n };\n const closeOnScroll = (event: Event) => {\n const target = event.target;\n if (target instanceof Node && menu?.contains(target)) return;\n close();\n };\n // A resize event may leave the viewport's size unchanged; headless Chromium\n // was seen to fire one on a fresh page. The clamped menu is still in place.\n const closeOnResize = () => {\n if (window.innerWidth === viewport.width && window.innerHeight === viewport.height) return;\n close();\n };\n const attachOpenListeners = () => {\n if (listenersAttached) return;\n listenersAttached = true;\n document.addEventListener(\"pointerdown\", dismiss);\n document.addEventListener(\"keydown\", keyDown);\n window.addEventListener(\"resize\", closeOnResize);\n window.addEventListener(\"scroll\", closeOnScroll, true);\n };\n const detachOpenListeners = () => {\n if (!listenersAttached) return;\n listenersAttached = false;\n document.removeEventListener(\"pointerdown\", dismiss);\n document.removeEventListener(\"keydown\", keyDown);\n window.removeEventListener(\"resize\", closeOnResize);\n window.removeEventListener(\"scroll\", closeOnScroll, true);\n resizeObserver?.disconnect();\n };\n /** Clamps the rendered menu into the viewport beside the point that opened it. */\n const place = () => {\n if (!isOpen() || !menu?.isConnected) return;\n const point = dropdownPosition(\n new DOMRect(anchor.x, anchor.y, 0, 0),\n menu.getBoundingClientRect(),\n \"bottom-right\" satisfies DropdownPosition,\n { width: window.innerWidth, height: window.innerHeight },\n 0,\n );\n setPosition({ x: point.left, y: point.top });\n };\n const close = () => {\n detachOpenListeners();\n if (!isOpen()) return;\n setPosition();\n if (closeActiveContextMenu === close) closeActiveContextMenu = undefined;\n props.onClose?.();\n };\n const focusItem = (index: number) => {\n const items = focusableItems(menu);\n if (items.length === 0) return;\n items[(index + items.length) % items.length]?.focus();\n };\n const open = (x: number, y: number) => {\n if (props.disabled) return;\n closeActiveContextMenu?.();\n // Focus may sit on a descendant of the host, as in composite widgets; Escape returns it there.\n const focused = document.activeElement;\n opener = focused instanceof HTMLElement && focused !== host && host?.contains(focused) ? focused : undefined;\n hostRing = ringOnReturn(focused);\n anchor = { x, y };\n viewport = { width: window.innerWidth, height: window.innerHeight };\n setPosition({ x, y });\n closeActiveContextMenu = close;\n attachOpenListeners();\n props.onOpen?.();\n // The menu sizes to its entries, so it is measured once rendered and\n // clamped into the viewport before the next paint, and again whenever its\n // entries change its size while it is open.\n queueMicrotask(() => {\n if (!isOpen() || !menu?.isConnected) return;\n place();\n if (typeof ResizeObserver !== \"undefined\") {\n resizeObserver ??= new ResizeObserver(place);\n resizeObserver.observe(menu);\n }\n focusItem(0);\n });\n };\n const keyDown = (event: KeyboardEvent) => {\n if (!isOpen()) return;\n const items = focusableItems(menu);\n const current = items.indexOf(document.activeElement as HTMLElement);\n if (event.key === \"ArrowDown\" || event.key === \"ArrowUp\") {\n event.preventDefault();\n focusItem(current + (event.key === \"ArrowDown\" ? 1 : -1));\n } else if (focusRowSegment(items, event.key)) {\n event.preventDefault();\n } else if (event.key === \"Home\" || event.key === \"End\") {\n event.preventDefault();\n focusItem(event.key === \"Home\" ? 0 : -1);\n } else if (event.key === \"Escape\") {\n event.preventDefault();\n close();\n returnFocus(opener?.isConnected ? opener : host, hostRing);\n } else if (event.key === \"Tab\") {\n close();\n }\n };\n\n props.openAt?.(open);\n // A close from outside, such as a drag taking over the press, returns focus that sits in the menu to where it came from.\n props.closeWith?.(() => {\n if (isOpen() && menu?.contains(document.activeElement)) returnFocus(opener?.isConnected ? opener : host, hostRing);\n close();\n });\n\n onMount(() => {\n onCleanup(() => {\n detachOpenListeners();\n if (closeActiveContextMenu === close) closeActiveContextMenu = undefined;\n });\n });\n\n return (\n <>\n {/* biome-ignore lint/a11y/useAriaPropsSupportedByRole: the named group owns the context-menu relationship without pretending arbitrary children form one button. */}\n <div\n ref={host}\n id={props.id ?? generatedId}\n class={hostClass()}\n role=\"group\"\n tabIndex={props.disabled ? undefined : (props.tabIndex ?? 0)}\n aria-label={props.label ?? messages().contextMenu}\n aria-haspopup=\"menu\"\n aria-expanded={isOpen()}\n aria-controls={isOpen() ? menuId : undefined}\n aria-disabled={props.disabled ? \"true\" : undefined}\n onContextMenu={(event) => {\n if (props.disabled) return;\n event.preventDefault();\n event.stopPropagation();\n open(event.clientX, event.clientY);\n }}\n onKeyDown={(event) => {\n if (props.disabled || (event.key !== \"ContextMenu\" && !(event.shiftKey && event.key === \"F10\"))) return;\n event.preventDefault();\n // Beside the focused element, such as a row of a composite widget, rather than the corner of the whole host.\n const focused = document.activeElement;\n const rect = (focused instanceof HTMLElement && host?.contains(focused) ? focused : host)?.getBoundingClientRect();\n if (rect) open(rect.left + 12, rect.top + 12);\n }}\n >\n {props.children}\n </div>\n <Show when={position()}>\n {(point) => (\n <Portal>\n <div\n ref={menu}\n id={menuId}\n class=\"k2b-ui k2b-context-menu\"\n role=\"menu\"\n aria-label={props.label ?? messages().contextMenu}\n style={{ left: `${point().x}px`, top: `${point().y}px` }}\n onPointerDown={(event) => event.stopPropagation()}\n >\n {/* The menu carries the same name for assistive technology. */}\n <Show when={props.title}>\n <div class=\"k2b-context-menu__title\" aria-hidden=\"true\">\n {props.title}\n </div>\n </Show>\n <DropdownItems items={items()} close={close} />\n </div>\n </Portal>\n )}\n </Show>\n </>\n );\n}\n\nexport default ContextMenu;\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"names":[],"sources":["actions/ContextMenu.tsx"],"sourcesContent":["import { createMemo, createSignal, createUniqueId, type JSX, onCleanup, onMount, Show } from \"solid-js\";\nimport { Portal } from \"solid-js/web\";\nimport { returnFocus, ringOnReturn } from \"../internal/focus-return\";\nimport { useUiMessages } from \"../intl/messages\";\nimport { type DropdownItem, DropdownItems, type DropdownPosition, dropdownPosition } from \"./Dropdown\";\nimport { focusRowSegment } from \"./menu-rows\";\n\nexport type ContextMenuProps = {\n items: readonly DropdownItem[];\n children: JSX.Element;\n class?: string | ((isOpen: boolean) => string);\n /** Tab order of the context-menu host. Descendant-focused composite widgets use -1. */\n tabIndex?: number;\n disabled?: boolean;\n onClose?: () => void;\n onOpen?: () => void;\n id?: string;\n label?: string;\n /**\n * Links, form fields, editable text, and selected text inside the host keep the browser's own menu, with its Copy,\n * Paste, and Open link. Use it where the host wraps readable content rather than one row.\n */\n keepNativeMenu?: boolean;\n};\n\nconst NATIVE_MENU_TARGETS = \"a[href], input, textarea, select, [contenteditable]:not([contenteditable='false'])\";\n\nlet closeActiveContextMenu: (() => void) | undefined;\n\nconst focusableItems = (menu: HTMLElement | undefined): HTMLElement[] =>\n menu\n ? Array.from(\n menu.querySelectorAll<HTMLElement>(\n [\n \"[role='menuitem']:not([aria-disabled='true'])\",\n \"[role='menuitemcheckbox']:not([aria-disabled='true'])\",\n \"[role='menuitemradio']:not([aria-disabled='true'])\",\n ].join(\", \"),\n ),\n )\n : [];\n\n/** Right-click menu with keyboard invocation, one-open-at-a-time behavior, and viewport clamping. */\nexport function ContextMenu(props: ContextMenuProps): JSX.Element {\n return ContextMenuBase(props);\n}\n\n/**\n * Package-internal, not exported from the package index: `openAt` lets GestureMenu open the menu at a held finger, and\n * `title` names what was pressed above the entries, since the finger covers it.\n */\nexport function ContextMenuBase(\n props: ContextMenuProps & {\n openAt?: (open: (x: number, y: number) => void) => void;\n title?: string;\n closeWith?: (close: () => void) => void;\n },\n): JSX.Element {\n const messages = useUiMessages();\n const generatedId = `k2b-context-${createUniqueId()}`;\n const menuId = `${generatedId}-menu`;\n const [position, setPosition] = createSignal<{ x: number; y: number }>();\n let host: HTMLDivElement | undefined;\n let menu: HTMLDivElement | undefined;\n let listenersAttached = false;\n let hostRing = true;\n /** The element inside the host that had focus as the menu opened, such as a row or a day of a composite widget. */\n let opener: HTMLElement | undefined;\n let anchor = { x: 0, y: 0 };\n let viewport = { width: 0, height: 0 };\n let resizeObserver: ResizeObserver | undefined;\n\n const isOpen = () => position() !== undefined;\n const keepsNativeMenu = (target: EventTarget | null): boolean => {\n if (!props.keepNativeMenu || !(target instanceof Node)) return false;\n const element = target instanceof Element ? target : target.parentElement;\n const native = element?.closest(NATIVE_MENU_TARGETS);\n if (native && host?.contains(native)) return true;\n const selection = window.getSelection();\n return Boolean(selection && !selection.isCollapsed && selection.toString().trim() && selection.containsNode(target, true));\n };\n const hostClass = createMemo(() => (typeof props.class === \"function\" ? props.class(isOpen()) : props.class));\n const items = createMemo<readonly DropdownItem[]>(() => props.items);\n\n const dismiss = (event: PointerEvent) => {\n if (menu?.contains(event.target as Node)) return;\n close();\n };\n const closeOnScroll = (event: Event) => {\n const target = event.target;\n if (target instanceof Node && menu?.contains(target)) return;\n close();\n };\n // A resize event may leave the viewport's size unchanged; headless Chromium\n // was seen to fire one on a fresh page. The clamped menu is still in place.\n const closeOnResize = () => {\n if (window.innerWidth === viewport.width && window.innerHeight === viewport.height) return;\n close();\n };\n const attachOpenListeners = () => {\n if (listenersAttached) return;\n listenersAttached = true;\n document.addEventListener(\"pointerdown\", dismiss);\n document.addEventListener(\"keydown\", keyDown);\n window.addEventListener(\"resize\", closeOnResize);\n window.addEventListener(\"scroll\", closeOnScroll, true);\n };\n const detachOpenListeners = () => {\n if (!listenersAttached) return;\n listenersAttached = false;\n document.removeEventListener(\"pointerdown\", dismiss);\n document.removeEventListener(\"keydown\", keyDown);\n window.removeEventListener(\"resize\", closeOnResize);\n window.removeEventListener(\"scroll\", closeOnScroll, true);\n resizeObserver?.disconnect();\n };\n /** Clamps the rendered menu into the viewport beside the point that opened it. */\n const place = () => {\n if (!isOpen() || !menu?.isConnected) return;\n const point = dropdownPosition(\n new DOMRect(anchor.x, anchor.y, 0, 0),\n menu.getBoundingClientRect(),\n \"bottom-right\" satisfies DropdownPosition,\n { width: window.innerWidth, height: window.innerHeight },\n 0,\n );\n setPosition({ x: point.left, y: point.top });\n };\n const close = () => {\n detachOpenListeners();\n if (!isOpen()) return;\n setPosition();\n if (closeActiveContextMenu === close) closeActiveContextMenu = undefined;\n props.onClose?.();\n };\n const focusItem = (index: number) => {\n const items = focusableItems(menu);\n if (items.length === 0) return;\n items[(index + items.length) % items.length]?.focus();\n };\n const open = (x: number, y: number) => {\n if (props.disabled) return;\n closeActiveContextMenu?.();\n // Focus may sit on a descendant of the host, as in composite widgets; Escape returns it there.\n const focused = document.activeElement;\n opener = focused instanceof HTMLElement && focused !== host && host?.contains(focused) ? focused : undefined;\n hostRing = ringOnReturn(focused);\n anchor = { x, y };\n viewport = { width: window.innerWidth, height: window.innerHeight };\n setPosition({ x, y });\n closeActiveContextMenu = close;\n attachOpenListeners();\n props.onOpen?.();\n // The menu sizes to its entries, so it is measured once rendered and\n // clamped into the viewport before the next paint, and again whenever its\n // entries change its size while it is open.\n queueMicrotask(() => {\n if (!isOpen() || !menu?.isConnected) return;\n place();\n if (typeof ResizeObserver !== \"undefined\") {\n resizeObserver ??= new ResizeObserver(place);\n resizeObserver.observe(menu);\n }\n focusItem(0);\n });\n };\n const keyDown = (event: KeyboardEvent) => {\n if (!isOpen()) return;\n const items = focusableItems(menu);\n const current = items.indexOf(document.activeElement as HTMLElement);\n if (event.key === \"ArrowDown\" || event.key === \"ArrowUp\") {\n event.preventDefault();\n focusItem(current + (event.key === \"ArrowDown\" ? 1 : -1));\n } else if (focusRowSegment(items, event.key)) {\n event.preventDefault();\n } else if (event.key === \"Home\" || event.key === \"End\") {\n event.preventDefault();\n focusItem(event.key === \"Home\" ? 0 : -1);\n } else if (event.key === \"Escape\") {\n event.preventDefault();\n close();\n returnFocus(opener?.isConnected ? opener : host, hostRing);\n } else if (event.key === \"Tab\") {\n close();\n }\n };\n\n props.openAt?.(open);\n // A close from outside, such as a drag taking over the press, returns focus that sits in the menu to where it came from.\n props.closeWith?.(() => {\n if (isOpen() && menu?.contains(document.activeElement)) returnFocus(opener?.isConnected ? opener : host, hostRing);\n close();\n });\n\n onMount(() => {\n onCleanup(() => {\n detachOpenListeners();\n if (closeActiveContextMenu === close) closeActiveContextMenu = undefined;\n });\n });\n\n return (\n <>\n {/* biome-ignore lint/a11y/useAriaPropsSupportedByRole: the named group owns the context-menu relationship without pretending arbitrary children form one button. */}\n <div\n ref={host}\n id={props.id ?? generatedId}\n class={hostClass()}\n role=\"group\"\n tabIndex={props.disabled ? undefined : (props.tabIndex ?? 0)}\n aria-label={props.label ?? messages().contextMenu}\n aria-haspopup=\"menu\"\n aria-expanded={isOpen()}\n aria-controls={isOpen() ? menuId : undefined}\n aria-disabled={props.disabled ? \"true\" : undefined}\n onContextMenu={(event) => {\n if (props.disabled) return;\n // An enclosing context menu must not take over the browser's own either.\n if (keepsNativeMenu(event.target)) return void event.stopPropagation();\n event.preventDefault();\n event.stopPropagation();\n open(event.clientX, event.clientY);\n }}\n onKeyDown={(event) => {\n if (props.disabled || (event.key !== \"ContextMenu\" && !(event.shiftKey && event.key === \"F10\"))) return;\n // A nested context menu already opened its own; a field keeps the browser's.\n if (\n event.defaultPrevented ||\n (props.keepNativeMenu && event.target instanceof Element && event.target.closest(NATIVE_MENU_TARGETS))\n )\n return;\n event.preventDefault();\n // Beside the focused element, such as a row of a composite widget, rather than the corner of the whole host.\n const focused = document.activeElement;\n const rect = (focused instanceof HTMLElement && host?.contains(focused) ? focused : host)?.getBoundingClientRect();\n if (rect) open(rect.left + 12, rect.top + 12);\n }}\n >\n {props.children}\n </div>\n <Show when={position()}>\n {(point) => (\n <Portal>\n <div\n ref={menu}\n id={menuId}\n class=\"k2b-ui k2b-context-menu\"\n role=\"menu\"\n aria-label={props.label ?? messages().contextMenu}\n style={{ left: `${point().x}px`, top: `${point().y}px` }}\n onPointerDown={(event) => event.stopPropagation()}\n >\n {/* The menu carries the same name for assistive technology. */}\n <Show when={props.title}>\n <div class=\"k2b-context-menu__title\" aria-hidden=\"true\">\n {props.title}\n </div>\n </Show>\n <DropdownItems items={items()} close={close} />\n </div>\n </Portal>\n )}\n </Show>\n </>\n );\n}\n\nexport default ContextMenu;\n"],"mappings":";;;;;;;;AAAA,SAAS,UAAU,EAAE,YAAY,EAAE,cAAc,EAAY,SAAS,EAAE,OAAO,EAAE,IAAI,QAAQ,UAAU;AACvG,SAAS,MAAM,QAAQ,cAAc;AACrC,SAAS,WAAW,EAAE,YAAY,QAAQ,0BAA0B;AACpE,SAAS,aAAa,QAAQ,kBAAkB;AAChD,SAA4B,aAAa,EAAyB,gBAAgB,QAAQ,YAAY;AACtG,SAAS,eAAe,QAAQ,aAAa;AAoB7C,MAAM,mBAAmB,GAAG,oFAAoF;AAEhH,IAAI,sBAAgD;AAEpD,MAAM,cAAc,GAAI,IAA6B,IACnD,IAAI,GACA,KAAK,CAAC,IAAI,CACR,IAAI,CAAC,gBAAgB,CACnB,CACE,+CAA+C,EAC/C,uDAAuD,EACvD,oDAAoD,CACrD,CAAC,IAAI,CAAC,IAAI,CACb,CACF,CAAC,GACD,EAAE;;AAER;AACA,OAAO,SAAS,WAAW,CAAC,KAAuB,EAAe;EAChE,OAAO,eAAe,CAAC,KAAK,CAAC;AAC/B;;AAEA;AACA;AACA;AACA;AACA,OAAO,SAAS,eAAe,CAC7B,KAIC,EACY;EACb,MAAM,QAAQ,GAAG,aAAa,CAAC,CAAC;EAChC,MAAM,WAAW,GAAG,eAAe,cAAc,CAAC,CAAC,EAAE;EACrD,MAAM,MAAM,GAAG,GAAG,WAAW,OAAO;EACpC,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,GAAG,YAAY,CAA2B,CAAC;EACxE,IAAI,IAAgC;EACpC,IAAI,IAAgC;EACpC,IAAI,iBAAiB,GAAG,KAAK;EAC7B,IAAI,QAAQ,GAAG,IAAI;EACnB;EACA,IAAI,MAA+B;EACnC,IAAI,MAAM,GAAG;IAAE,CAAC,EAAE,CAAC;IAAE,CAAC,EAAE;EAAE,CAAC;EAC3B,IAAI,QAAQ,GAAG;IAAE,KAAK,EAAE,CAAC;IAAE,MAAM,EAAE;EAAE,CAAC;EACtC,IAAI,cAA0C;EAE9C,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,CAAC,KAAK,SAAS;EAC7C,MAAM,eAAe,GAAI,MAA0B,IAAc;IAC/D,IAAI,CAAC,KAAK,CAAC,cAAc,IAAI,EAAE,MAAM,YAAY,IAAI,CAAC,EAAE,OAAO,KAAK;IACpE,MAAM,OAAO,GAAG,MAAM,YAAY,OAAO,GAAG,MAAM,GAAG,MAAM,CAAC,aAAa;IACzE,MAAM,MAAM,GAAG,OAAO,EAAE,OAAO,CAAC,mBAAmB,CAAC;IACpD,IAAI,MAAM,IAAI,IAAI,EAAE,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,IAAI;IACjD,MAAM,SAAS,GAAG,MAAM,CAAC,YAAY,CAAC,CAAC;IACvC,OAAO,OAAO,CAAC,SAAS,IAAI,CAAC,SAAS,CAAC,WAAW,IAAI,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,SAAS,CAAC,YAAY,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;EAC5H,CAAC;EACD,MAAM,SAAS,GAAG,UAAU,CAAC,MAAO,OAAO,KAAK,CAAC,KAAK,KAAK,UAAU,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,KAAM,CAAC;EAC7G,MAAM,KAAK,GAAG,UAAU,CAA0B,MAAM,KAAK,CAAC,KAAK,CAAC;EAEpE,MAAM,OAAO,GAAI,KAAmB,IAAK;IACvC,IAAI,IAAI,EAAE,QAAQ,CAAC,KAAK,CAAC,MAAc,CAAC,EAAE;IAC1C,KAAK,CAAC,CAAC;EACT,CAAC;EACD,MAAM,aAAa,GAAI,KAAY,IAAK;IACtC,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM;IAC3B,IAAI,MAAM,YAAY,IAAI,IAAI,IAAI,EAAE,QAAQ,CAAC,MAAM,CAAC,EAAE;IACtD,KAAK,CAAC,CAAC;EACT,CAAC;EACD;EACA;EACA,MAAM,aAAa,GAAG,MAAM;IAC1B,IAAI,MAAM,CAAC,UAAU,KAAK,QAAQ,CAAC,KAAK,IAAI,MAAM,CAAC,WAAW,KAAK,QAAQ,CAAC,MAAM,EAAE;IACpF,KAAK,CAAC,CAAC;EACT,CAAC;EACD,MAAM,mBAAmB,GAAG,MAAM;IAChC,IAAI,iBAAiB,EAAE;IACvB,iBAAiB,GAAG,IAAI;IACxB,QAAQ,CAAC,gBAAgB,CAAC,aAAa,EAAE,OAAO,CAAC;IACjD,QAAQ,CAAC,gBAAgB,CAAC,SAAS,EAAE,OAAO,CAAC;IAC7C,MAAM,CAAC,gBAAgB,CAAC,QAAQ,EAAE,aAAa,CAAC;IAChD,MAAM,CAAC,gBAAgB,CAAC,QAAQ,EAAE,aAAa,EAAE,IAAI,CAAC;EACxD,CAAC;EACD,MAAM,mBAAmB,GAAG,MAAM;IAChC,IAAI,CAAC,iBAAiB,EAAE;IACxB,iBAAiB,GAAG,KAAK;IACzB,QAAQ,CAAC,mBAAmB,CAAC,aAAa,EAAE,OAAO,CAAC;IACpD,QAAQ,CAAC,mBAAmB,CAAC,SAAS,EAAE,OAAO,CAAC;IAChD,MAAM,CAAC,mBAAmB,CAAC,QAAQ,EAAE,aAAa,CAAC;IACnD,MAAM,CAAC,mBAAmB,CAAC,QAAQ,EAAE,aAAa,EAAE,IAAI,CAAC;IACzD,cAAc,EAAE,UAAU,CAAC,CAAC;EAC9B,CAAC;EACD;EACA,MAAM,KAAK,GAAG,MAAM;IAClB,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,WAAW,EAAE;IACrC,MAAM,KAAK,GAAG,gBAAgB,CAC5B,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EACrC,IAAI,CAAC,qBAAqB,CAAC,CAAC,EAC5B,cAAc,EACd;MAAE,KAAK,EAAE,MAAM,CAAC,UAAU;MAAE,MAAM,EAAE,MAAM,CAAC;IAAY,CAAC,EACxD,CACF,CAAC;IACD,WAAW,CAAC;MAAE,CAAC,EAAE,KAAK,CAAC,IAAI;MAAE,CAAC,EAAE,KAAK,CAAC;IAAI,CAAC,CAAC;EAC9C,CAAC;EACD,MAAM,KAAK,GAAG,MAAM;IAClB,mBAAmB,CAAC,CAAC;IACrB,IAAI,CAAC,MAAM,CAAC,CAAC,EAAE;IACf,WAAW,CAAC,CAAC;IACb,IAAI,sBAAsB,KAAK,KAAK,EAAE,sBAAsB,GAAG,SAAS;IACxE,KAAK,CAAC,OAAO,GAAG,CAAC;EACnB,CAAC;EACD,MAAM,SAAS,GAAI,KAAa,IAAK;IACnC,MAAM,KAAK,GAAG,cAAc,CAAC,IAAI,CAAC;IAClC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE;IACxB,KAAK,CAAC,CAAC,KAAK,GAAG,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC,MAAM,CAAC,EAAE,KAAK,CAAC,CAAC;EACvD,CAAC;EACD,MAAM,IAAI,GAAG,CAAC,CAAS,EAAE,CAAS,KAAK;IACrC,IAAI,KAAK,CAAC,QAAQ,EAAE;IACpB,sBAAsB,GAAG,CAAC;IAC1B;IACA,MAAM,OAAO,GAAG,QAAQ,CAAC,aAAa;IACtC,MAAM,GAAG,OAAO,YAAY,WAAW,IAAI,OAAO,KAAK,IAAI,IAAI,IAAI,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,OAAO,GAAG,SAAS;IAC5G,QAAQ,GAAG,YAAY,CAAC,OAAO,CAAC;IAChC,MAAM,GAAG;MAAE,CAAC;MAAE;IAAE,CAAC;IACjB,QAAQ,GAAG;MAAE,KAAK,EAAE,MAAM,CAAC,UAAU;MAAE,MAAM,EAAE,MAAM,CAAC;IAAY,CAAC;IACnE,WAAW,CAAC;MAAE,CAAC;MAAE;IAAE,CAAC,CAAC;IACrB,sBAAsB,GAAG,KAAK;IAC9B,mBAAmB,CAAC,CAAC;IACrB,KAAK,CAAC,MAAM,GAAG,CAAC;IAChB;IACA;IACA;IACA,cAAc,CAAC,MAAM;MACnB,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,WAAW,EAAE;MACrC,KAAK,CAAC,CAAC;MACP,IAAI,OAAO,cAAc,KAAK,WAAW,EAAE;QACzC,cAAc,KAAK,IAAI,cAAc,CAAC,KAAK,CAAC;QAC5C,cAAc,CAAC,OAAO,CAAC,IAAI,CAAC;MAC9B;MACA,SAAS,CAAC,CAAC,CAAC;IACd,CAAC,CAAC;EACJ,CAAC;EACD,MAAM,OAAO,GAAI,KAAoB,IAAK;IACxC,IAAI,CAAC,MAAM,CAAC,CAAC,EAAE;IACf,MAAM,KAAK,GAAG,cAAc,CAAC,IAAI,CAAC;IAClC,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,aAA4B,CAAC;IACpE,IAAI,KAAK,CAAC,GAAG,KAAK,WAAW,IAAI,KAAK,CAAC,GAAG,KAAK,SAAS,EAAE;MACxD,KAAK,CAAC,cAAc,CAAC,CAAC;MACtB,SAAS,CAAC,OAAO,IAAI,KAAK,CAAC,GAAG,KAAK,WAAW,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;IAC3D,CAAC,MAAM,IAAI,eAAe,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,EAAE;MAC5C,KAAK,CAAC,cAAc,CAAC,CAAC;IACxB,CAAC,MAAM,IAAI,KAAK,CAAC,GAAG,KAAK,MAAM,IAAI,KAAK,CAAC,GAAG,KAAK,KAAK,EAAE;MACtD,KAAK,CAAC,cAAc,CAAC,CAAC;MACtB,SAAS,CAAC,KAAK,CAAC,GAAG,KAAK,MAAM,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;IAC1C,CAAC,MAAM,IAAI,KAAK,CAAC,GAAG,KAAK,QAAQ,EAAE;MACjC,KAAK,CAAC,cAAc,CAAC,CAAC;MACtB,KAAK,CAAC,CAAC;MACP,WAAW,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,GAAG,IAAI,EAAE,QAAQ,CAAC;IAC5D,CAAC,MAAM,IAAI,KAAK,CAAC,GAAG,KAAK,KAAK,EAAE;MAC9B,KAAK,CAAC,CAAC;IACT;EACF,CAAC;EAED,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC;EACpB;EACA,KAAK,CAAC,SAAS,GAAG,MAAM;IACtB,IAAI,MAAM,CAAC,CAAC,IAAI,IAAI,EAAE,QAAQ,CAAC,QAAQ,CAAC,aAAa,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,GAAG,IAAI,EAAE,QAAQ,CAAC;IAClH,KAAK,CAAC,CAAC;EACT,CAAC,CAAC;EAEF,OAAO,CAAC,MAAM;IACZ,SAAS,CAAC,MAAM;MACd,mBAAmB,CAAC,CAAC;MACrB,IAAI,sBAAsB,KAAK,KAAK,EAAE,sBAAsB,GAAG,SAAS;IAC1E,CAAC,CAAC;EACJ,CAAC,CAAC;EAEF,oDAKU,KAAK,CAAC,EAAE,IAAI,WAAW,mDACpB,SAAS,CAAC,CAAC,4CAER,KAAK,CAAC,QAAQ,YAAG,SAAS,mBAAI,KAAK,CAAC,QAAQ,IAAI,CAAC,OAAC,iDAChD,KAAK,CAAC,KAAK,IAAI,QAAQ,CAAC,CAAC,CAAC,WAAW,0DAElC,MAAM,CAAC,CAAC,kDACR,MAAM,CAAC,CAAC,YAAG,MAAM,mBAAG,SAAS,kDAC7B,KAAK,CAAC,QAAQ,GAAG,MAAM,YAAG,SAAS,0BAwBjD,KAAK,CAAC,QAAQ,sBAEhB,IAAI;IAAA,IAAC,IAAI;MAAA,OAAE,QAAQ,CAAC,CAAC;IAAA;IAAA,UAClB,KAAK,sBACJ,MAAM;MAAA;QAAA,oDAGC,MAAM,uDAGE,KAAK,CAAC,KAAK,IAAI,QAAQ,CAAC,CAAC,CAAC,WAAW,6CAClC,YAAG,KAAK,CAAC,CAAC,CAAC,CAAC,WAAI,gCAAO,YAAG,KAAK,CAAC,CAAC,CAAC,CAAC,WAAI,8BAIrD,IAAI;UAAA,IAAC,IAAI;YAAA,OAAE,KAAK,CAAC,KAAK;UAAA;UAAA;YAAA,+BAElB,KAAK,CAAC,KAAK;UAAA;QAAA,gCAGf,aAAa;UAAA,IAAC,KAAK;YAAA,OAAE,KAAK,CAAC,CAAC;UAAA;UAAE,KAAK,EAAE;QAAK;MAAA;IAAA;EAGhD;AAIT;AAEA,eAAe,WAAW","ignoreList":[]}
@@ -444,6 +444,7 @@ function DropdownRoot(props) {
444
444
  const id = createUniqueId().replace(/[^a-zA-Z0-9_-]/g, "-");
445
445
  const menuId = `k2b-dropdown-${id}`;
446
446
  const [internalOpen, setInternalOpen] = createSignal(false);
447
+ const [entriesShown, setEntriesShown] = createSignal(!props.lazy);
447
448
  let triggerRef;
448
449
  let menuRef;
449
450
  let triggerRing = true;
@@ -496,6 +497,8 @@ function DropdownRoot(props) {
496
497
  const open = (focus = "first") => {
497
498
  if (props.disabled || !menuRef || menuRef.matches(":popover-open")) return;
498
499
  triggerRing = ringOnReturn(triggerRef);
500
+ // A lazy menu's entries exist before it shows, so it places and focuses them as any other.
501
+ setEntriesShown(true);
499
502
  menuRef.showPopover();
500
503
  // The toggle event arrives a task later; expose the open state before focus moves into the menu.
501
504
  setInternalOpen(true);
@@ -589,11 +592,18 @@ function DropdownRoot(props) {
589
592
  get children() {
590
593
  return _$ssr(_tmpl$15, `k2b-dropdown ${_$escape(props.class ?? "", true)}`, _$escape(props.children), _$ssrAttribute("id", _$escape(menuId, true), false), _$ssrAttribute("aria-label", _$escape(props.label ?? messages().dropdownMenu, true), false), `k2b-dropdown__menu ${_$escape(props.menuClass ?? "", true)}`, _$ssrStyle(props.width ? {
591
594
  "--k2b-dropdown-width": props.width
592
- } : undefined), _$ssrAttribute("data-width", props.width ? "fixed" : _$escape(undefined, true), false) + _$ssrAttribute("data-variant", _$escape(props.variant ?? "default", true), false) + _$ssrAttribute("data-position", _$escape(position(), true), false), _$escape(_$createComponent(DropdownItems, {
593
- get items() {
594
- return props.items;
595
+ } : undefined), _$ssrAttribute("data-width", props.width ? "fixed" : _$escape(undefined, true), false) + _$ssrAttribute("data-variant", _$escape(props.variant ?? "default", true), false) + _$ssrAttribute("data-position", _$escape(position(), true), false), _$escape(_$createComponent(Show, {
596
+ get when() {
597
+ return entriesShown();
595
598
  },
596
- close: close
599
+ get children() {
600
+ return _$createComponent(DropdownItems, {
601
+ get items() {
602
+ return props.items;
603
+ },
604
+ close: close
605
+ });
606
+ }
597
607
  })));
598
608
  }
599
609
  });