@k2b/ui 0.45.0 → 0.46.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (96) hide show
  1. package/dist/browser/actions/Dropdown.js +8 -1
  2. package/dist/browser/actions/Dropdown.js.map +1 -1
  3. package/dist/browser/actions/FilterChip.js +11 -5
  4. package/dist/browser/actions/FilterChip.js.map +1 -1
  5. package/dist/browser/actions/ViewTabs.js +225 -93
  6. package/dist/browser/actions/ViewTabs.js.map +1 -1
  7. package/dist/browser/content/FileGrid.js +125 -99
  8. package/dist/browser/content/FileGrid.js.map +1 -1
  9. package/dist/browser/inputs/choice.js +36 -9
  10. package/dist/browser/inputs/choice.js.map +1 -1
  11. package/dist/browser/layout/AppWorkspace.js +30 -26
  12. package/dist/browser/layout/AppWorkspace.js.map +1 -1
  13. package/dist/browser/layout/DetailPanel.js +130 -108
  14. package/dist/browser/layout/DetailPanel.js.map +1 -1
  15. package/dist/browser/layout/DetailSections.js +1019 -0
  16. package/dist/browser/layout/DetailSections.js.map +1 -0
  17. package/dist/browser/layout/DetailsToggle.js +32 -0
  18. package/dist/browser/layout/DetailsToggle.js.map +1 -0
  19. package/dist/browser/layout/Discussion.js +3 -0
  20. package/dist/browser/layout/Discussion.js.map +1 -1
  21. package/dist/browser/layout/MobileShell.js +116 -94
  22. package/dist/browser/layout/MobileShell.js.map +1 -1
  23. package/dist/browser/layout/PageTitle.js +33 -10
  24. package/dist/browser/layout/PageTitle.js.map +1 -1
  25. package/dist/browser/layout/app-workspace-controller.js +12 -0
  26. package/dist/browser/layout/app-workspace-controller.js.map +1 -1
  27. package/dist/browser/layout/detail-sections-messages.js +123 -0
  28. package/dist/browser/layout/detail-sections-messages.js.map +1 -0
  29. package/dist/browser/layout/index.js +2 -0
  30. package/dist/browser/layout/index.js.map +1 -1
  31. package/dist/browser/surfaces/Avatar.js +3 -1
  32. package/dist/browser/surfaces/Avatar.js.map +1 -1
  33. package/dist/browser/surfaces/AvatarStack.js +95 -61
  34. package/dist/browser/surfaces/AvatarStack.js.map +1 -1
  35. package/dist/browser/surfaces/ChangeList.js +77 -0
  36. package/dist/browser/surfaces/ChangeList.js.map +1 -0
  37. package/dist/browser/surfaces/index.js +2 -1
  38. package/dist/browser/surfaces/index.js.map +1 -1
  39. package/dist/browser/text-editor/TextEditor.js +19 -8
  40. package/dist/browser/text-editor/TextEditor.js.map +1 -1
  41. package/dist/ssr/actions/Dropdown.js +6 -0
  42. package/dist/ssr/actions/Dropdown.js.map +1 -1
  43. package/dist/ssr/actions/FilterChip.js +1 -1
  44. package/dist/ssr/actions/FilterChip.js.map +1 -1
  45. package/dist/ssr/actions/ViewTabs.js +144 -37
  46. package/dist/ssr/actions/ViewTabs.js.map +1 -1
  47. package/dist/ssr/content/FileGrid.js +36 -22
  48. package/dist/ssr/content/FileGrid.js.map +1 -1
  49. package/dist/ssr/inputs/choice.js +36 -9
  50. package/dist/ssr/inputs/choice.js.map +1 -1
  51. package/dist/ssr/layout/AppWorkspace.js +27 -27
  52. package/dist/ssr/layout/AppWorkspace.js.map +1 -1
  53. package/dist/ssr/layout/DetailPanel.js +17 -0
  54. package/dist/ssr/layout/DetailPanel.js.map +1 -1
  55. package/dist/ssr/layout/DetailSections.js +762 -0
  56. package/dist/ssr/layout/DetailSections.js.map +1 -0
  57. package/dist/ssr/layout/DetailsToggle.js +29 -0
  58. package/dist/ssr/layout/DetailsToggle.js.map +1 -0
  59. package/dist/ssr/layout/Discussion.js +3 -0
  60. package/dist/ssr/layout/Discussion.js.map +1 -1
  61. package/dist/ssr/layout/MobileShell.js +45 -28
  62. package/dist/ssr/layout/MobileShell.js.map +1 -1
  63. package/dist/ssr/layout/PageTitle.js +29 -6
  64. package/dist/ssr/layout/PageTitle.js.map +1 -1
  65. package/dist/ssr/layout/app-workspace-controller.js +12 -0
  66. package/dist/ssr/layout/app-workspace-controller.js.map +1 -1
  67. package/dist/ssr/layout/detail-sections-messages.js +123 -0
  68. package/dist/ssr/layout/detail-sections-messages.js.map +1 -0
  69. package/dist/ssr/layout/index.js +2 -0
  70. package/dist/ssr/layout/index.js.map +1 -1
  71. package/dist/ssr/surfaces/Avatar.js +3 -1
  72. package/dist/ssr/surfaces/Avatar.js.map +1 -1
  73. package/dist/ssr/surfaces/AvatarStack.js +61 -32
  74. package/dist/ssr/surfaces/AvatarStack.js.map +1 -1
  75. package/dist/ssr/surfaces/ChangeList.js +37 -0
  76. package/dist/ssr/surfaces/ChangeList.js.map +1 -0
  77. package/dist/ssr/surfaces/index.js +2 -1
  78. package/dist/ssr/surfaces/index.js.map +1 -1
  79. package/dist/ssr/text-editor/TextEditor.js +19 -8
  80. package/dist/ssr/text-editor/TextEditor.js.map +1 -1
  81. package/dist/styles.css +1 -1
  82. package/dist/types/actions/FilterChip.d.ts +4 -0
  83. package/dist/types/actions/ViewTabs.d.ts +11 -1
  84. package/dist/types/content/FileGrid.d.ts +6 -0
  85. package/dist/types/inputs/choice.d.ts +9 -3
  86. package/dist/types/layout/DetailPanel.d.ts +9 -0
  87. package/dist/types/layout/DetailSections.d.ts +156 -0
  88. package/dist/types/layout/DetailsToggle.d.ts +13 -0
  89. package/dist/types/layout/PageTitle.d.ts +7 -0
  90. package/dist/types/layout/detail-sections-messages.d.ts +59 -0
  91. package/dist/types/layout/index.d.ts +4 -1
  92. package/dist/types/surfaces/Avatar.d.ts +3 -0
  93. package/dist/types/surfaces/AvatarStack.d.ts +20 -1
  94. package/dist/types/surfaces/ChangeList.d.ts +20 -0
  95. package/dist/types/surfaces/index.d.ts +5 -3
  96. package/package.json +3 -3
@@ -1,3 +1,4 @@
1
+ import { memo as _$memo } from "solid-js/web";
1
2
  import { ssrAttribute as _$ssrAttribute } from "solid-js/web";
2
3
  import { createComponent as _$createComponent } from "solid-js/web";
3
4
  import { ssr as _$ssr } from "solid-js/web";
@@ -5,13 +6,15 @@ import { escape as _$escape } from "solid-js/web";
5
6
  var _tmpl$ = ["<span class=\"k2b-view-tabs__count\">", "</span>"],
6
7
  _tmpl$2 = ["<span class=\"k2b-view-tabs__label k2b-truncate-fade\">", "</span>"],
7
8
  _tmpl$3 = ["<i", " aria-hidden=\"true\"></i>"],
8
- _tmpl$4 = ["<span class=\"k2b-view-tabs__label\">", "</span>"],
9
- _tmpl$5 = ["<span class=\"k2b-view-tabs__more-count\" data-level=\"wide\">+", "</span>"],
10
- _tmpl$6 = ["<span class=\"k2b-view-tabs__more-count\" data-level=\"compact\">+", "</span>"],
11
- _tmpl$7 = "<i class=\"ti ti-chevron-down\" aria-hidden=\"true\"></i>",
12
- _tmpl$8 = ["<li class=\"k2b-view-tabs__more\"", ">", "</li>"],
13
- _tmpl$9 = ["<nav class=\"", "\"", "><ul class=\"k2b-view-tabs__list\" data-scroll-fade-mode=\"both\" data-scroll-fade-axis=\"horizontal\">", "", "</ul><script>", "</script></nav>"],
14
- _tmpl$0 = ["<li class=\"k2b-view-tabs__item\"", "><a class=\"k2b-view-tabs__tab\"", ">", "</a></li>"];
9
+ _tmpl$4 = ["<span class=\"k2b-view-tabs__badge\">", "</span>"],
10
+ _tmpl$5 = ["<li class=\"k2b-view-tabs__item\"", "><a class=\"k2b-view-tabs__tab\"", ">", "</a></li>"],
11
+ _tmpl$6 = ["<span class=\"k2b-view-tabs__label\">", "</span>"],
12
+ _tmpl$7 = ["<span class=\"k2b-view-tabs__more-count\" data-level=\"wide\">+", "</span>"],
13
+ _tmpl$8 = ["<span class=\"k2b-view-tabs__more-count\" data-level=\"compact\">+", "</span>"],
14
+ _tmpl$9 = "<span class=\"k2b-view-tabs__more-count\" data-level=\"fit\"></span>",
15
+ _tmpl$0 = "<i class=\"ti ti-chevron-down\" aria-hidden=\"true\"></i>",
16
+ _tmpl$1 = ["<li class=\"k2b-view-tabs__more\"", ">", "</li>"],
17
+ _tmpl$10 = ["<nav class=\"", "\"", "><ul class=\"k2b-view-tabs__list\" data-scroll-fade-mode=\"both\" data-scroll-fade-axis=\"horizontal\"", ">", "", "", "</ul><script>", "</script></nav>"];
15
18
  import { createEffect, createMemo, createSignal, For, on, onCleanup, onMount, Show } from "solid-js";
16
19
  import { useUiMessages } from "../intl/messages";
17
20
  import { createScrollFade, scrollFadeEdges } from "../layout/scroll-fade";
@@ -20,10 +23,14 @@ import Dropdown from "./Dropdown";
20
23
  export function viewTabsLayout(items, current, max = 5) {
21
24
  // At least one slot keeps the current view visible, including for an invalid limit.
22
25
  const limit = Number.isFinite(max) ? Math.max(1, Math.floor(max)) : 5;
26
+ // Pinned views never overflow, so they take no slot.
27
+ const flowing = items.flatMap((item, index) => item.pinned ? [] : [index]);
28
+ const pinned = items.flatMap((item, index) => item.pinned ? [index] : []);
23
29
  const currentIndex = items.findIndex(item => item.id === current);
30
+ const currentPosition = flowing.indexOf(currentIndex);
24
31
  const visible = size => {
25
- const indices = items.slice(0, size).map((_, index) => index);
26
- if (currentIndex >= size) indices[indices.length - 1] = currentIndex;
32
+ const indices = flowing.slice(0, size);
33
+ if (currentPosition >= size) indices[indices.length - 1] = currentIndex;
27
34
  return indices;
28
35
  };
29
36
  const wide = visible(limit);
@@ -31,14 +38,50 @@ export function viewTabsLayout(items, current, max = 5) {
31
38
  return {
32
39
  wide,
33
40
  compact,
34
- wideHidden: items.length - wide.length,
35
- compactHidden: items.length - compact.length
41
+ pinned,
42
+ wideHidden: flowing.length - wide.length,
43
+ compactHidden: flowing.length - compact.length
36
44
  };
37
45
  }
38
46
 
39
- /** Self-contained: the server script embeds this before hydration. */
47
+ /**
48
+ * Self-contained: the server script embeds this before hydration. A fitting strip first keeps only the views that fit
49
+ * its room and counts the rest in More; then the open or focused view scrolls into the strip.
50
+ */
40
51
  function settleViewTabs(list, edges, focused) {
41
52
  if (!(list instanceof HTMLElement)) return;
53
+ const more = list.querySelector(":scope > .k2b-view-tabs__more");
54
+ const fitCount = more?.querySelector('.k2b-view-tabs__more-count[data-level="fit"]');
55
+ const flowing = Array.from(list.querySelectorAll(":scope > .k2b-view-tabs__item:not([data-pinned])"));
56
+ for (const item of flowing) item.removeAttribute("data-fit-hidden");
57
+ more?.removeAttribute("data-fit");
58
+ // The shown entries against the strip's inner room, whatever its scroll and padding.
59
+ const overflows = () => {
60
+ const boxes = Array.from(list.children).filter(child => child instanceof HTMLElement && child.tagName === "LI" && child.getClientRects().length > 0).map(child => child.getBoundingClientRect());
61
+ if (boxes.length === 0) return false;
62
+ const style = getComputedStyle(list);
63
+ const room = list.clientWidth - (parseFloat(style.paddingLeft) || 0) - (parseFloat(style.paddingRight) || 0);
64
+ return Math.max(...boxes.map(box => box.right)) - Math.min(...boxes.map(box => box.left)) > room + 0.5;
65
+ };
66
+ // The phone head row keeps its scrolling strip: its CSS turns fitting off.
67
+ const fits = list.hasAttribute("data-fit-room") && getComputedStyle(list).getPropertyValue("--k2b-view-tabs-fit").trim() !== "none";
68
+ if (fits && more && fitCount && overflows()) {
69
+ // Count from the level on screen: the compact strip already keeps fewer views than the wide one.
70
+ const compact = more.querySelector('.k2b-view-tabs__more-count[data-level="compact"]');
71
+ const compactShown = Boolean(compact && getComputedStyle(compact).display !== "none");
72
+ const behind = Number(compactShown ? more.dataset.behindCompact : more.dataset.behindWide) || 0;
73
+ // The last views on screen leave first; the open view stays.
74
+ const candidates = flowing.filter(item => item.getClientRects().length > 0 && !item.querySelector("[aria-current=page]")).reverse();
75
+ more.setAttribute("data-fit", "");
76
+ let hidden = 0;
77
+ for (const item of candidates) {
78
+ item.setAttribute("data-fit-hidden", "");
79
+ hidden += 1;
80
+ fitCount.textContent = `+${behind + hidden}`;
81
+ if (!overflows()) break;
82
+ }
83
+ if (hidden === 0) more.removeAttribute("data-fit");
84
+ }
42
85
  const current = focused ?? list.querySelector(".k2b-view-tabs__tab[aria-current=page]");
43
86
  if (current && current.getClientRects().length > 0 && list.scrollWidth - list.clientWidth > 1) {
44
87
  const bounds = list.getBoundingClientRect();
@@ -63,9 +106,20 @@ function settleViewTabs(list, edges, focused) {
63
106
  const fade = edges(list);
64
107
  if (fade) list.setAttribute("data-scroll-fade", fade);else list.removeAttribute("data-scroll-fade");
65
108
  }
66
- /** Also embedded, so it must not close over module state. */
109
+ /**
110
+ * Also embedded, so it must not close over module state.
111
+ *
112
+ * A fitting strip converges by construction. It fits again only when the strip renders, web fonts finish loading, or
113
+ * a notification finds another width of the head lead or of an entry that the last fit left shown. A fit only shows
114
+ * and hides entries: the lead is an inline-size container that takes no width from the strip, and every entry keeps
115
+ * its own width (`flex: none`), so the notifications a fit causes find the widths it ended with and stop there.
116
+ */
67
117
  function watchViewTabs(list, settle, edges) {
68
118
  if (!(list instanceof HTMLElement)) return;
119
+ const fits = list.hasAttribute("data-fit-room");
120
+ const roomOf = () => list.closest(".k2b-app-workspace__head-lead");
121
+ // What a fit depends on: the lead's width and each shown entry's width, which fonts, icons and labels change.
122
+ const measured = () => [roomOf()?.clientWidth ?? -1, ...Array.from(list.children, child => child.getBoundingClientRect().width)].join(" ");
69
123
  // A DOM property survives hydration: one observer and focus listener per reused list.
70
124
  let watch = list.__k2bViewTabsWatch;
71
125
  if (!watch) {
@@ -76,29 +130,66 @@ function watchViewTabs(list, settle, edges) {
76
130
  settle(list, edges, event.target);
77
131
  }
78
132
  };
133
+ const settleNow = () => {
134
+ const focused = document.activeElement;
135
+ if (watch?.preferCurrent === false && focused instanceof HTMLElement && list.contains(focused) && focused.matches(".k2b-view-tabs__tab:focus-visible")) settle(list, edges, focused);else settle(list, edges);
136
+ };
137
+ // Head actions parse after the views; settle again after their layout, before paint, and on later resizes.
138
+ const connect = () => {
139
+ if (!watch) return;
140
+ watch.resize.disconnect();
141
+ watch.resize.observe(list);
142
+ for (const child of Array.from(list.children)) watch.resize.observe(child);
143
+ const room = roomOf();
144
+ if (fits && room) watch.resize.observe(room);
145
+ };
146
+ // Fitting resizes the strip and possibly the head, which other observers may watch. Inside a ResizeObserver
147
+ // callback that would leave their notifications undelivered, so a fit runs in the next frame, still before it paints.
148
+ const schedule = () => {
149
+ if (!watch || watch.frame) return;
150
+ watch.frame = requestAnimationFrame(() => {
151
+ if (!watch) return;
152
+ watch.frame = 0;
153
+ if (!list.isConnected) return;
154
+ settleNow();
155
+ watch.room = measured();
156
+ });
157
+ };
79
158
  watch = {
80
159
  resize: new ResizeObserver(() => {
81
- const focused = document.activeElement;
82
- if (watch?.preferCurrent === false && focused instanceof HTMLElement && list.contains(focused) && focused.matches(".k2b-view-tabs__tab:focus-visible")) settle(list, edges, focused);else settle(list, edges);
160
+ // A scrolling strip only scrolls and settles at once.
161
+ if (!fits) return settleNow();
162
+ // Heights follow the fit, and hidden entries measure 0 by its own doing: only another measure counts.
163
+ if (watch && measured() !== watch.room) watch.schedule();
83
164
  }),
84
165
  focus,
85
- preferCurrent: true
166
+ preferCurrent: true,
167
+ connect,
168
+ schedule,
169
+ frame: 0,
170
+ room: "",
171
+ fonts: () => watch?.schedule()
86
172
  };
87
173
  Object.defineProperty(list, "__k2bViewTabsWatch", {
88
174
  value: watch,
89
175
  configurable: true
90
176
  });
91
177
  list.addEventListener("focusin", focus);
178
+ // A first visit can paint before the web fonts load; the server frame and the client then fit the same metrics.
179
+ if (fits && document.fonts) {
180
+ document.fonts.addEventListener("loadingdone", watch.fonts);
181
+ void document.fonts.ready.then(watch.fonts);
182
+ }
92
183
  }
93
184
  watch.preferCurrent = true;
94
- const {
95
- resize
96
- } = watch;
97
- resize.disconnect();
98
- // Head actions parse after the views; settle again after their layout, before paint, and on later resizes.
99
- resize.observe(list);
100
- for (const child of Array.from(list.children)) resize.observe(child);
185
+ watch.connect();
101
186
  settle(list, edges);
187
+ if (fits) {
188
+ watch.room = measured();
189
+ // The head's actions parse after the views. A frame's animation callbacks run before its first layout and
190
+ // paint, so this fit also counts their room in the first frame.
191
+ watch.schedule();
192
+ }
102
193
  return watch;
103
194
  }
104
195
  const VIEW_TABS_SCRIPT = `(${watchViewTabs})(document.currentScript&&document.currentScript.previousElementSibling,${settleViewTabs},${scrollFadeEdges})`;
@@ -125,6 +216,8 @@ export function ViewTabs(props) {
125
216
  onCleanup(() => {
126
217
  disposed = true;
127
218
  watch?.resize.disconnect();
219
+ if (watch?.frame) cancelAnimationFrame(watch.frame);
220
+ if (watch) document.fonts?.removeEventListener("loadingdone", watch.fonts);
128
221
  if (list && watch) {
129
222
  list.removeEventListener("focusin", watch.focus);
130
223
  Reflect.deleteProperty(list, "__k2bViewTabsWatch");
@@ -132,14 +225,17 @@ export function ViewTabs(props) {
132
225
  });
133
226
  });
134
227
  // User effects run after Solid's render effects, including For and aria-current, in the same task.
135
- createEffect(on(() => props.current, () => watchViewTabs(list ?? null, settleViewTabs, scrollFadeEdges), {
228
+ // What the strip shows: another open view, view, label, count or badge can change what fits. Equal content in a new
229
+ // array settles nothing again.
230
+ const shown = createMemo(() => [props.current ?? "", layout().wide.join(","), ...props.items.map(item => `${item.id}\u0000${item.label}\u0000${item.count ?? ""}\u0000${item.badge ?? ""}`)].join("\u0001"));
231
+ createEffect(on(shown, () => watchViewTabs(list ?? null, settleViewTabs, scrollFadeEdges), {
136
232
  defer: true
137
233
  }));
138
234
  const [open, setOpen] = createSignal(false);
139
235
  const [menuItems, setMenuItems] = createSignal([]);
140
236
  const onOpenChange = next => {
141
237
  if (next) {
142
- setMenuItems(props.items.filter((item, index) => item.id !== props.current && (!layout().wide.includes(index) || stripItems.get(index)?.getClientRects().length === 0)).map(item => ({
238
+ setMenuItems(props.items.filter((item, index) => !item.pinned && item.id !== props.current && (!layout().wide.includes(index) || stripItems.get(index)?.getClientRects().length === 0)).map(item => ({
143
239
  href: item.href,
144
240
  label: item.label,
145
241
  icon: item.icon,
@@ -160,22 +256,28 @@ export function ViewTabs(props) {
160
256
  get children() {
161
257
  return _$ssr(_tmpl$, _$escape(item.count));
162
258
  }
259
+ }), _$createComponent(Show, {
260
+ get when() {
261
+ return item.badge;
262
+ },
263
+ children: badge => _$ssr(_tmpl$4, _$escape(badge()))
163
264
  })];
164
- return _$ssr(_tmpl$9, `k2b-view-tabs ${_$escape(props.class ?? "", true)}`, _$ssrAttribute("aria-label", _$escape(props.label, true), false), _$escape(_$createComponent(For, {
265
+ const stripItem = index => {
266
+ const item = () => props.items[index];
267
+ onCleanup(() => stripItems.delete(index));
268
+ return _$ssr(_tmpl$5, _$ssrAttribute("data-view-tab", _$escape(item().id, true), false) + _$ssrAttribute("data-pinned", item().pinned ? "" : _$escape(undefined, true), false) + _$ssrAttribute("data-compact-hidden", !item().pinned && !layout().compact.includes(index) ? "" : _$escape(undefined, true), false), _$ssrAttribute("href", _$escape(item().href, true), false) + _$ssrAttribute("aria-current", item().id === props.current ? "page" : _$escape(undefined, true), false), _$escape(tabContent(item())));
269
+ };
270
+ return _$ssr(_tmpl$10, `k2b-view-tabs ${_$escape(props.class ?? "", true)}`, _$ssrAttribute("aria-label", _$escape(props.label, true), false), _$ssrAttribute("data-fit-room", props.fit ? "" : _$escape(undefined, true), false), _$escape(_$createComponent(For, {
165
271
  get each() {
166
272
  return layout().wide;
167
273
  },
168
- children: index => {
169
- const item = () => props.items[index];
170
- onCleanup(() => stripItems.delete(index));
171
- return _$ssr(_tmpl$0, _$ssrAttribute("data-view-tab", _$escape(item().id, true), false) + _$ssrAttribute("data-compact-hidden", !layout().compact.includes(index) ? "" : _$escape(undefined, true), false), _$ssrAttribute("href", _$escape(item().href, true), false) + _$ssrAttribute("aria-current", item().id === props.current ? "page" : _$escape(undefined, true), false), _$escape(tabContent(item())));
172
- }
274
+ children: stripItem
173
275
  })), _$escape(_$createComponent(Show, {
174
276
  get when() {
175
- return layout().compactHidden + layout().wideHidden > 0;
277
+ return layout().compactHidden + layout().wideHidden > 0 || props.fit && layout().wide.length > 1;
176
278
  },
177
279
  get children() {
178
- return _$ssr(_tmpl$8, _$ssrAttribute("data-wide", layout().wideHidden > 0 ? "" : _$escape(undefined, true), false), _$escape(_$createComponent(Dropdown.Root, {
280
+ return _$ssr(_tmpl$1, _$ssrAttribute("data-wide", layout().wideHidden > 0 ? "" : _$escape(undefined, true), false) + _$ssrAttribute("data-behind-wide", _$escape(layout().wideHidden, true), false) + _$ssrAttribute("data-behind-compact", _$escape(layout().compactHidden, true), false), _$escape(_$createComponent(Dropdown.Root, {
179
281
  get items() {
180
282
  return menuItems();
181
283
  },
@@ -194,26 +296,31 @@ export function ViewTabs(props) {
194
296
  return messages().moreViews;
195
297
  },
196
298
  get children() {
197
- return [_$ssr(_tmpl$4, _$escape(messages().more)), _$createComponent(Show, {
299
+ return [_$ssr(_tmpl$6, _$escape(messages().more)), _$createComponent(Show, {
198
300
  get when() {
199
301
  return layout().wideHidden > 0;
200
302
  },
201
303
  get children() {
202
- return _$ssr(_tmpl$5, _$escape(layout().wideHidden));
304
+ return _$ssr(_tmpl$7, _$escape(layout().wideHidden));
203
305
  }
204
306
  }), _$createComponent(Show, {
205
307
  get when() {
206
308
  return layout().compactHidden > 0;
207
309
  },
208
310
  get children() {
209
- return _$ssr(_tmpl$6, _$escape(layout().compactHidden));
311
+ return _$ssr(_tmpl$8, _$escape(layout().compactHidden));
210
312
  }
211
- }), _$ssr(_tmpl$7)];
313
+ }), _$ssr(_tmpl$9), _$ssr(_tmpl$0)];
212
314
  }
213
315
  });
214
316
  }
215
317
  })));
216
318
  }
319
+ })), _$escape(_$createComponent(For, {
320
+ get each() {
321
+ return layout().pinned;
322
+ },
323
+ children: stripItem
217
324
  })), VIEW_TABS_SCRIPT);
218
325
  }
219
326
  //# sourceMappingURL=ViewTabs.js.map
@@ -1 +1 @@
1
- {"version":3,"names":[],"sources":["actions/ViewTabs.tsx"],"sourcesContent":["import { createEffect, createMemo, createSignal, For, type JSX, on, onCleanup, onMount, Show } from \"solid-js\";\nimport { useUiMessages } from \"../intl/messages\";\nimport { createScrollFade, scrollFadeEdges } from \"../layout/scroll-fade\";\nimport Dropdown, { type DropdownItem } from \"./Dropdown\";\n\nexport type ViewTab = { id: string; label: string; href: string; icon?: string; count?: number | string };\nexport type ViewTabsProps = {\n /** Accessible name of the navigation landmark, e.g. \"Views\". */\n label: string;\n items: readonly ViewTab[];\n /** Id of the open view; the server reads it from `?view=`. Unknown ids select nothing. */\n current: string | undefined;\n /** Tabs shown before More (default 5). */\n max?: number;\n class?: string;\n};\n\n/** Two deterministic strip levels; only opening the menu reads CSS visibility. */\nexport function viewTabsLayout(items: readonly ViewTab[], current: string | undefined, max = 5) {\n // At least one slot keeps the current view visible, including for an invalid limit.\n const limit = Number.isFinite(max) ? Math.max(1, Math.floor(max)) : 5;\n const currentIndex = items.findIndex((item) => item.id === current);\n const visible = (size: number) => {\n const indices = items.slice(0, size).map((_, index) => index);\n if (currentIndex >= size) indices[indices.length - 1] = currentIndex;\n return indices;\n };\n const wide = visible(limit);\n const compact = visible(Math.min(limit, 3));\n return { wide, compact, wideHidden: items.length - wide.length, compactHidden: items.length - compact.length };\n}\n\n/** Self-contained: the server script embeds this before hydration. */\nfunction settleViewTabs(list: Element | null, edges: (element: HTMLElement) => string | undefined, focused?: HTMLElement) {\n if (!(list instanceof HTMLElement)) return;\n const current = focused ?? list.querySelector(\".k2b-view-tabs__tab[aria-current=page]\");\n if (current && current.getClientRects().length > 0 && list.scrollWidth - list.clientWidth > 1) {\n const bounds = list.getBoundingClientRect();\n const item = current.getBoundingClientRect();\n const fade = edges(list);\n const style = getComputedStyle(list);\n const left = fade === \"top\" || fade === \"both\" ? parseFloat(style.scrollPaddingLeft) || 0 : 0;\n const right = fade === \"bottom\" || fade === \"both\" ? parseFloat(style.scrollPaddingRight) || 0 : 0;\n if (item.left < bounds.left + left || item.right > bounds.right - right) {\n let offset = item.left - bounds.left - (bounds.width - item.width) / 2;\n if (focused) {\n // Reserve padding at the destination edge; native clamping drops it when that end is reached.\n offset =\n item.left < bounds.left + left\n ? item.left - bounds.left - (parseFloat(style.scrollPaddingLeft) || 0)\n : item.right - bounds.right + (parseFloat(style.scrollPaddingRight) || 0);\n }\n // Only the strip moves: scrollIntoView would also scroll the page. Instant keeps the first frame free of animation.\n list.scrollTo({ left: list.scrollLeft + offset, behavior: \"instant\" });\n }\n }\n const fade = edges(list);\n if (fade) list.setAttribute(\"data-scroll-fade\", fade);\n else list.removeAttribute(\"data-scroll-fade\");\n}\n\ntype WatchedViewTabs = HTMLElement & {\n __k2bViewTabsWatch?: { resize: ResizeObserver; focus: (event: FocusEvent) => void; preferCurrent: boolean };\n};\n\n/** Also embedded, so it must not close over module state. */\nfunction watchViewTabs(list: WatchedViewTabs | null, settle: typeof settleViewTabs, edges: (element: HTMLElement) => string | undefined) {\n if (!(list instanceof HTMLElement)) return;\n // A DOM property survives hydration: one observer and focus listener per reused list.\n let watch = list.__k2bViewTabsWatch;\n if (!watch) {\n const focus = (event: FocusEvent) => {\n // Pointer focus must not move the target under the pointer.\n if (watch && event.target instanceof HTMLElement && event.target.matches(\".k2b-view-tabs__tab:focus-visible\")) {\n watch.preferCurrent = false;\n settle(list, edges, event.target);\n }\n };\n watch = {\n resize: new ResizeObserver(() => {\n const focused = document.activeElement;\n if (\n watch?.preferCurrent === false &&\n focused instanceof HTMLElement &&\n list.contains(focused) &&\n focused.matches(\".k2b-view-tabs__tab:focus-visible\")\n )\n settle(list, edges, focused);\n else settle(list, edges);\n }),\n focus,\n preferCurrent: true,\n };\n Object.defineProperty(list, \"__k2bViewTabsWatch\", { value: watch, configurable: true });\n list.addEventListener(\"focusin\", focus);\n }\n watch.preferCurrent = true;\n const { resize } = watch;\n resize.disconnect();\n // Head actions parse after the views; settle again after their layout, before paint, and on later resizes.\n resize.observe(list);\n for (const child of Array.from(list.children)) resize.observe(child);\n settle(list, edges);\n return watch;\n}\nconst VIEW_TABS_SCRIPT = `(${watchViewTabs})(document.currentScript&&document.currentScript.previousElementSibling,${settleViewTabs},${scrollFadeEdges})`;\n\n/**\n * URL-backed object views. Every view is an ordinary document link, in the strip and under More, so reload, back,\n * and forward keep the view the URL names.\n */\nexport function ViewTabs(props: ViewTabsProps): JSX.Element {\n const messages = useUiMessages();\n const layout = createMemo(() => viewTabsLayout(props.items, props.current, props.max));\n const stripItems = new Map<number, HTMLLIElement>();\n let list: HTMLUListElement | undefined;\n createScrollFade(\n () => list,\n () => true,\n );\n onMount(() => {\n const watch = watchViewTabs(list ?? null, settleViewTabs, scrollFadeEdges);\n let disposed = false;\n // Later mount effects can invalidate WebKit's scroll layout after this\n // initial settle. Finish once the mount task is complete, before its first\n // frame; ResizeObserver alone runs too late for that frame.\n queueMicrotask(() => {\n if (!disposed && watch?.preferCurrent) settleViewTabs(list ?? null, scrollFadeEdges);\n });\n onCleanup(() => {\n disposed = true;\n watch?.resize.disconnect();\n if (list && watch) {\n list.removeEventListener(\"focusin\", watch.focus);\n Reflect.deleteProperty(list, \"__k2bViewTabsWatch\");\n }\n });\n });\n // User effects run after Solid's render effects, including For and aria-current, in the same task.\n createEffect(\n on(\n () => props.current,\n () => watchViewTabs(list ?? null, settleViewTabs, scrollFadeEdges),\n { defer: true },\n ),\n );\n const [open, setOpen] = createSignal(false);\n const [menuItems, setMenuItems] = createSignal<DropdownItem[]>([]);\n const onOpenChange = (next: boolean) => {\n if (next) {\n setMenuItems(\n props.items\n .filter(\n (item, index) =>\n item.id !== props.current && (!layout().wide.includes(index) || stripItems.get(index)?.getClientRects().length === 0),\n )\n .map((item) => ({\n href: item.href,\n label: item.label,\n icon: item.icon,\n trailing: item.count !== undefined ? <span class=\"k2b-view-tabs__count\">{item.count}</span> : undefined,\n })),\n );\n }\n setOpen(next);\n };\n const tabContent = (item: ViewTab) => (\n <>\n <Show when={item.icon}>{(icon) => <i class={icon()} aria-hidden=\"true\" />}</Show>\n <span class=\"k2b-view-tabs__label k2b-truncate-fade\">{item.label}</span>\n <Show when={item.count !== undefined}>\n <span class=\"k2b-view-tabs__count\">{item.count}</span>\n </Show>\n </>\n );\n return (\n <nav class={`k2b-view-tabs ${props.class ?? \"\"}`} aria-label={props.label}>\n <ul ref={list} class=\"k2b-view-tabs__list\" data-scroll-fade-mode=\"both\" data-scroll-fade-axis=\"horizontal\">\n <For each={layout().wide}>\n {(index) => {\n const item = () => props.items[index]!;\n onCleanup(() => stripItems.delete(index));\n return (\n <li\n ref={(element) => stripItems.set(index, element)}\n class=\"k2b-view-tabs__item\"\n data-view-tab={item().id}\n data-compact-hidden={!layout().compact.includes(index) ? \"\" : undefined}\n >\n <a class=\"k2b-view-tabs__tab\" href={item().href} aria-current={item().id === props.current ? \"page\" : undefined}>\n {tabContent(item())}\n </a>\n </li>\n );\n }}\n </For>\n <Show when={layout().compactHidden + layout().wideHidden > 0}>\n <li class=\"k2b-view-tabs__more\" data-wide={layout().wideHidden > 0 ? \"\" : undefined}>\n <Dropdown.Root items={menuItems()} open={open()} onOpenChange={onOpenChange} label={messages().moreViews}>\n <Dropdown.Trigger appearance=\"plain\" class=\"k2b-view-tabs__tab k2b-view-tabs__more-trigger\" label={messages().moreViews}>\n <span class=\"k2b-view-tabs__label\">{messages().more}</span>\n <Show when={layout().wideHidden > 0}>\n <span class=\"k2b-view-tabs__more-count\" data-level=\"wide\">\n +{layout().wideHidden}\n </span>\n </Show>\n <Show when={layout().compactHidden > 0}>\n <span class=\"k2b-view-tabs__more-count\" data-level=\"compact\">\n +{layout().compactHidden}\n </span>\n </Show>\n <i class=\"ti ti-chevron-down\" aria-hidden=\"true\" />\n </Dropdown.Trigger>\n </Dropdown.Root>\n </li>\n </Show>\n </ul>\n <script innerHTML={VIEW_TABS_SCRIPT} />\n </nav>\n );\n}\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"names":[],"sources":["actions/ViewTabs.tsx"],"sourcesContent":["import { createEffect, createMemo, createSignal, For, type JSX, on, onCleanup, onMount, Show } from \"solid-js\";\nimport { useUiMessages } from \"../intl/messages\";\nimport { createScrollFade, scrollFadeEdges } from \"../layout/scroll-fade\";\nimport Dropdown, { type DropdownItem } from \"./Dropdown\";\n\nexport type ViewTab = {\n id: string;\n label: string;\n href: string;\n icon?: string;\n count?: number | string;\n /** A short quiet label after the count, such as \"New\" for a view people have not opened yet. */\n badge?: string;\n /** Stays in the strip after More at every width, for a view of another kind than the ones that overflow. */\n pinned?: boolean;\n};\nexport type ViewTabsProps = {\n /** Accessible name of the navigation landmark, e.g. \"Views\". */\n label: string;\n items: readonly ViewTab[];\n /** Id of the open view; the server reads it from `?view=`. Unknown ids select nothing. */\n current: string | undefined;\n /** At most this many views before More (default 5). */\n max?: number;\n /**\n * The strip shows only the views that fit its room and counts the rest in More, instead of scrolling them. The open\n * view and pinned views stay. Pair it with a larger `max` so a wide head shows more views.\n */\n fit?: boolean;\n class?: string;\n};\n\n/** Two deterministic strip levels; only opening the menu reads CSS visibility. */\nexport function viewTabsLayout(items: readonly ViewTab[], current: string | undefined, max = 5) {\n // At least one slot keeps the current view visible, including for an invalid limit.\n const limit = Number.isFinite(max) ? Math.max(1, Math.floor(max)) : 5;\n // Pinned views never overflow, so they take no slot.\n const flowing = items.flatMap((item, index) => (item.pinned ? [] : [index]));\n const pinned = items.flatMap((item, index) => (item.pinned ? [index] : []));\n const currentIndex = items.findIndex((item) => item.id === current);\n const currentPosition = flowing.indexOf(currentIndex);\n const visible = (size: number) => {\n const indices = flowing.slice(0, size);\n if (currentPosition >= size) indices[indices.length - 1] = currentIndex;\n return indices;\n };\n const wide = visible(limit);\n const compact = visible(Math.min(limit, 3));\n return { wide, compact, pinned, wideHidden: flowing.length - wide.length, compactHidden: flowing.length - compact.length };\n}\n\n/**\n * Self-contained: the server script embeds this before hydration. A fitting strip first keeps only the views that fit\n * its room and counts the rest in More; then the open or focused view scrolls into the strip.\n */\nfunction settleViewTabs(list: Element | null, edges: (element: HTMLElement) => string | undefined, focused?: HTMLElement) {\n if (!(list instanceof HTMLElement)) return;\n const more = list.querySelector<HTMLElement>(\":scope > .k2b-view-tabs__more\");\n const fitCount = more?.querySelector<HTMLElement>('.k2b-view-tabs__more-count[data-level=\"fit\"]');\n const flowing = Array.from(list.querySelectorAll<HTMLElement>(\":scope > .k2b-view-tabs__item:not([data-pinned])\"));\n\n for (const item of flowing) item.removeAttribute(\"data-fit-hidden\");\n more?.removeAttribute(\"data-fit\");\n // The shown entries against the strip's inner room, whatever its scroll and padding.\n const overflows = () => {\n const boxes = Array.from(list.children)\n .filter((child) => child instanceof HTMLElement && child.tagName === \"LI\" && child.getClientRects().length > 0)\n .map((child) => child.getBoundingClientRect());\n if (boxes.length === 0) return false;\n const style = getComputedStyle(list);\n const room = list.clientWidth - (parseFloat(style.paddingLeft) || 0) - (parseFloat(style.paddingRight) || 0);\n return Math.max(...boxes.map((box) => box.right)) - Math.min(...boxes.map((box) => box.left)) > room + 0.5;\n };\n // The phone head row keeps its scrolling strip: its CSS turns fitting off.\n const fits = list.hasAttribute(\"data-fit-room\") && getComputedStyle(list).getPropertyValue(\"--k2b-view-tabs-fit\").trim() !== \"none\";\n if (fits && more && fitCount && overflows()) {\n // Count from the level on screen: the compact strip already keeps fewer views than the wide one.\n const compact = more.querySelector<HTMLElement>('.k2b-view-tabs__more-count[data-level=\"compact\"]');\n const compactShown = Boolean(compact && getComputedStyle(compact).display !== \"none\");\n const behind = Number(compactShown ? more.dataset.behindCompact : more.dataset.behindWide) || 0;\n // The last views on screen leave first; the open view stays.\n const candidates = flowing.filter((item) => item.getClientRects().length > 0 && !item.querySelector(\"[aria-current=page]\")).reverse();\n more.setAttribute(\"data-fit\", \"\");\n let hidden = 0;\n for (const item of candidates) {\n item.setAttribute(\"data-fit-hidden\", \"\");\n hidden += 1;\n fitCount.textContent = `+${behind + hidden}`;\n if (!overflows()) break;\n }\n if (hidden === 0) more.removeAttribute(\"data-fit\");\n }\n const current = focused ?? list.querySelector(\".k2b-view-tabs__tab[aria-current=page]\");\n if (current && current.getClientRects().length > 0 && list.scrollWidth - list.clientWidth > 1) {\n const bounds = list.getBoundingClientRect();\n const item = current.getBoundingClientRect();\n const fade = edges(list);\n const style = getComputedStyle(list);\n const left = fade === \"top\" || fade === \"both\" ? parseFloat(style.scrollPaddingLeft) || 0 : 0;\n const right = fade === \"bottom\" || fade === \"both\" ? parseFloat(style.scrollPaddingRight) || 0 : 0;\n if (item.left < bounds.left + left || item.right > bounds.right - right) {\n let offset = item.left - bounds.left - (bounds.width - item.width) / 2;\n if (focused) {\n // Reserve padding at the destination edge; native clamping drops it when that end is reached.\n offset =\n item.left < bounds.left + left\n ? item.left - bounds.left - (parseFloat(style.scrollPaddingLeft) || 0)\n : item.right - bounds.right + (parseFloat(style.scrollPaddingRight) || 0);\n }\n // Only the strip moves: scrollIntoView would also scroll the page. Instant keeps the first frame free of animation.\n list.scrollTo({ left: list.scrollLeft + offset, behavior: \"instant\" });\n }\n }\n const fade = edges(list);\n if (fade) list.setAttribute(\"data-scroll-fade\", fade);\n else list.removeAttribute(\"data-scroll-fade\");\n}\n\ntype WatchedViewTabs = HTMLElement & {\n __k2bViewTabsWatch?: {\n resize: ResizeObserver;\n focus: (event: FocusEvent) => void;\n preferCurrent: boolean;\n connect: () => void;\n /** Runs one fit in the next frame; calls before it runs share it. */\n schedule: () => void;\n frame: number;\n /** The head lead's width and the widths of the shown entries when the last fit ended. */\n room: string;\n /** Fits again once web fonts finish loading: their metrics change every view's width, not the lead's. */\n fonts: () => void;\n };\n};\n\n/**\n * Also embedded, so it must not close over module state.\n *\n * A fitting strip converges by construction. It fits again only when the strip renders, web fonts finish loading, or\n * a notification finds another width of the head lead or of an entry that the last fit left shown. A fit only shows\n * and hides entries: the lead is an inline-size container that takes no width from the strip, and every entry keeps\n * its own width (`flex: none`), so the notifications a fit causes find the widths it ended with and stop there.\n */\nfunction watchViewTabs(list: WatchedViewTabs | null, settle: typeof settleViewTabs, edges: (element: HTMLElement) => string | undefined) {\n if (!(list instanceof HTMLElement)) return;\n const fits = list.hasAttribute(\"data-fit-room\");\n const roomOf = () => list.closest<HTMLElement>(\".k2b-app-workspace__head-lead\");\n // What a fit depends on: the lead's width and each shown entry's width, which fonts, icons and labels change.\n const measured = () =>\n [roomOf()?.clientWidth ?? -1, ...Array.from(list.children, (child) => child.getBoundingClientRect().width)].join(\" \");\n // A DOM property survives hydration: one observer and focus listener per reused list.\n let watch = list.__k2bViewTabsWatch;\n if (!watch) {\n const focus = (event: FocusEvent) => {\n // Pointer focus must not move the target under the pointer.\n if (watch && event.target instanceof HTMLElement && event.target.matches(\".k2b-view-tabs__tab:focus-visible\")) {\n watch.preferCurrent = false;\n settle(list, edges, event.target);\n }\n };\n const settleNow = () => {\n const focused = document.activeElement;\n if (\n watch?.preferCurrent === false &&\n focused instanceof HTMLElement &&\n list.contains(focused) &&\n focused.matches(\".k2b-view-tabs__tab:focus-visible\")\n )\n settle(list, edges, focused);\n else settle(list, edges);\n };\n // Head actions parse after the views; settle again after their layout, before paint, and on later resizes.\n const connect = () => {\n if (!watch) return;\n watch.resize.disconnect();\n watch.resize.observe(list);\n for (const child of Array.from(list.children)) watch.resize.observe(child);\n const room = roomOf();\n if (fits && room) watch.resize.observe(room);\n };\n // Fitting resizes the strip and possibly the head, which other observers may watch. Inside a ResizeObserver\n // callback that would leave their notifications undelivered, so a fit runs in the next frame, still before it paints.\n const schedule = () => {\n if (!watch || watch.frame) return;\n watch.frame = requestAnimationFrame(() => {\n if (!watch) return;\n watch.frame = 0;\n if (!list.isConnected) return;\n settleNow();\n watch.room = measured();\n });\n };\n watch = {\n resize: new ResizeObserver(() => {\n // A scrolling strip only scrolls and settles at once.\n if (!fits) return settleNow();\n // Heights follow the fit, and hidden entries measure 0 by its own doing: only another measure counts.\n if (watch && measured() !== watch.room) watch.schedule();\n }),\n focus,\n preferCurrent: true,\n connect,\n schedule,\n frame: 0,\n room: \"\",\n fonts: () => watch?.schedule(),\n };\n Object.defineProperty(list, \"__k2bViewTabsWatch\", { value: watch, configurable: true });\n list.addEventListener(\"focusin\", focus);\n // A first visit can paint before the web fonts load; the server frame and the client then fit the same metrics.\n if (fits && document.fonts) {\n document.fonts.addEventListener(\"loadingdone\", watch.fonts);\n void document.fonts.ready.then(watch.fonts);\n }\n }\n watch.preferCurrent = true;\n watch.connect();\n settle(list, edges);\n if (fits) {\n watch.room = measured();\n // The head's actions parse after the views. A frame's animation callbacks run before its first layout and\n // paint, so this fit also counts their room in the first frame.\n watch.schedule();\n }\n return watch;\n}\nconst VIEW_TABS_SCRIPT = `(${watchViewTabs})(document.currentScript&&document.currentScript.previousElementSibling,${settleViewTabs},${scrollFadeEdges})`;\n\n/**\n * URL-backed object views. Every view is an ordinary document link, in the strip and under More, so reload, back,\n * and forward keep the view the URL names.\n */\nexport function ViewTabs(props: ViewTabsProps): JSX.Element {\n const messages = useUiMessages();\n const layout = createMemo(() => viewTabsLayout(props.items, props.current, props.max));\n const stripItems = new Map<number, HTMLLIElement>();\n let list: HTMLUListElement | undefined;\n createScrollFade(\n () => list,\n () => true,\n );\n onMount(() => {\n const watch = watchViewTabs(list ?? null, settleViewTabs, scrollFadeEdges);\n let disposed = false;\n // Later mount effects can invalidate WebKit's scroll layout after this\n // initial settle. Finish once the mount task is complete, before its first\n // frame; ResizeObserver alone runs too late for that frame.\n queueMicrotask(() => {\n if (!disposed && watch?.preferCurrent) settleViewTabs(list ?? null, scrollFadeEdges);\n });\n onCleanup(() => {\n disposed = true;\n watch?.resize.disconnect();\n if (watch?.frame) cancelAnimationFrame(watch.frame);\n if (watch) document.fonts?.removeEventListener(\"loadingdone\", watch.fonts);\n if (list && watch) {\n list.removeEventListener(\"focusin\", watch.focus);\n Reflect.deleteProperty(list, \"__k2bViewTabsWatch\");\n }\n });\n });\n // User effects run after Solid's render effects, including For and aria-current, in the same task.\n // What the strip shows: another open view, view, label, count or badge can change what fits. Equal content in a new\n // array settles nothing again.\n const shown = createMemo(() =>\n [\n props.current ?? \"\",\n layout().wide.join(\",\"),\n ...props.items.map((item) => `${item.id}\\u0000${item.label}\\u0000${item.count ?? \"\"}\\u0000${item.badge ?? \"\"}`),\n ].join(\"\\u0001\"),\n );\n createEffect(on(shown, () => watchViewTabs(list ?? null, settleViewTabs, scrollFadeEdges), { defer: true }));\n const [open, setOpen] = createSignal(false);\n const [menuItems, setMenuItems] = createSignal<DropdownItem[]>([]);\n const onOpenChange = (next: boolean) => {\n if (next) {\n setMenuItems(\n props.items\n .filter(\n (item, index) =>\n !item.pinned &&\n item.id !== props.current &&\n (!layout().wide.includes(index) || stripItems.get(index)?.getClientRects().length === 0),\n )\n .map((item) => ({\n href: item.href,\n label: item.label,\n icon: item.icon,\n trailing: item.count !== undefined ? <span class=\"k2b-view-tabs__count\">{item.count}</span> : undefined,\n })),\n );\n }\n setOpen(next);\n };\n const tabContent = (item: ViewTab) => (\n <>\n <Show when={item.icon}>{(icon) => <i class={icon()} aria-hidden=\"true\" />}</Show>\n <span class=\"k2b-view-tabs__label k2b-truncate-fade\">{item.label}</span>\n <Show when={item.count !== undefined}>\n <span class=\"k2b-view-tabs__count\">{item.count}</span>\n </Show>\n <Show when={item.badge}>{(badge) => <span class=\"k2b-view-tabs__badge\">{badge()}</span>}</Show>\n </>\n );\n const stripItem = (index: number) => {\n const item = () => props.items[index]!;\n onCleanup(() => stripItems.delete(index));\n return (\n <li\n ref={(element) => stripItems.set(index, element)}\n class=\"k2b-view-tabs__item\"\n data-view-tab={item().id}\n data-pinned={item().pinned ? \"\" : undefined}\n data-compact-hidden={!item().pinned && !layout().compact.includes(index) ? \"\" : undefined}\n >\n <a class=\"k2b-view-tabs__tab\" href={item().href} aria-current={item().id === props.current ? \"page\" : undefined}>\n {tabContent(item())}\n </a>\n </li>\n );\n };\n return (\n <nav class={`k2b-view-tabs ${props.class ?? \"\"}`} aria-label={props.label}>\n <ul\n ref={list}\n class=\"k2b-view-tabs__list\"\n data-scroll-fade-mode=\"both\"\n data-scroll-fade-axis=\"horizontal\"\n data-fit-room={props.fit ? \"\" : undefined}\n >\n <For each={layout().wide}>{stripItem}</For>\n {/* A fitting strip keeps More ready, hidden until a view leaves the strip. */}\n <Show when={layout().compactHidden + layout().wideHidden > 0 || (props.fit && layout().wide.length > 1)}>\n <li\n class=\"k2b-view-tabs__more\"\n data-wide={layout().wideHidden > 0 ? \"\" : undefined}\n data-behind-wide={layout().wideHidden}\n data-behind-compact={layout().compactHidden}\n >\n <Dropdown.Root items={menuItems()} open={open()} onOpenChange={onOpenChange} label={messages().moreViews}>\n <Dropdown.Trigger appearance=\"plain\" class=\"k2b-view-tabs__tab k2b-view-tabs__more-trigger\" label={messages().moreViews}>\n <span class=\"k2b-view-tabs__label\">{messages().more}</span>\n <Show when={layout().wideHidden > 0}>\n <span class=\"k2b-view-tabs__more-count\" data-level=\"wide\">\n +{layout().wideHidden}\n </span>\n </Show>\n <Show when={layout().compactHidden > 0}>\n <span class=\"k2b-view-tabs__more-count\" data-level=\"compact\">\n +{layout().compactHidden}\n </span>\n </Show>\n {/* Written by the strip's fit, never by the render, so a rerender keeps the count it measured. */}\n <span class=\"k2b-view-tabs__more-count\" data-level=\"fit\" />\n <i class=\"ti ti-chevron-down\" aria-hidden=\"true\" />\n </Dropdown.Trigger>\n </Dropdown.Root>\n </li>\n </Show>\n <For each={layout().pinned}>{stripItem}</For>\n </ul>\n <script innerHTML={VIEW_TABS_SCRIPT} />\n </nav>\n );\n}\n"],"mappings":"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","ignoreList":[]}
@@ -11,17 +11,19 @@ var _tmpl$ = ["<div class=\"", "\"", " role=\"grid\"", ">", "</div>"],
11
11
  _tmpl$4 = ["<div class=\"k2b-file-grid__meta\">", "</div>"],
12
12
  _tmpl$5 = ["<div class=\"k2b-file-grid__actions\">", "</div>"],
13
13
  _tmpl$6 = ["<div role=\"row\" class=\"k2b-file-grid__row\">", "</div>"],
14
- _tmpl$7 = ["<div class=\"", "\"", " data-open-items=\"true\" role=\"list\"", ">", "</div>"],
15
- _tmpl$8 = ["<button type=\"button\" class=\"k2b-file-grid__open\" aria-labelledby=\"", "\"", "></button>"],
16
- _tmpl$9 = ["<div class=\"k2b-file-grid__name\" id=\"", "\">", "</div>"],
17
- _tmpl$0 = ["<div class=\"k2b-file-grid__meta\" id=\"", "\">", "</div>"],
18
- _tmpl$1 = ["<div role=\"listitem\" class=\"k2b-file-grid__row\">", "</div>"],
19
- _tmpl$10 = ["<div class=\"k2b-file-grid-stack__toolbar\">", "</div>"],
20
- _tmpl$11 = ["<button type=\"button\" class=\"k2b-file-grid-stack__more\" aria-expanded=\"true\"><span>", "</span><i class=\"ti ti-chevron-up\" aria-hidden=\"true\"></i></button>"],
21
- _tmpl$12 = ["<div class=\"k2b-file-grid-stack\"", ">", "", "", "</div>"],
22
- _tmpl$13 = ["<div class=\"k2b-file-grid-stack__group\"><div class=\"k2b-file-grid-stack__label\"", ">", "<span class=\"k2b-file-grid-stack__count\">", "</span></div>", "</div>"],
23
- _tmpl$14 = ["<span class=\"k2b-file-grid-stack__more-meta\">", "</span>"],
24
- _tmpl$15 = ["<button type=\"button\" class=\"k2b-file-grid-stack__more\" aria-expanded=\"false\"><span>", "</span><i class=\"ti ti-chevron-down\" aria-hidden=\"true\"></i>", "</button>"];
14
+ _tmpl$7 = ["<span class=\"k2b-file-grid__check-box\"", "><i class=\"ti ti-check\"></i></span>"],
15
+ _tmpl$8 = ["<span class=\"k2b-file-grid__check\" aria-hidden=\"true\">", "</span>"],
16
+ _tmpl$9 = ["<div class=\"", "\"", " data-open-items=\"true\" role=\"list\"", ">", "</div>"],
17
+ _tmpl$0 = ["<button type=\"button\" class=\"k2b-file-grid__open\" aria-labelledby=\"", "\"", "></button>"],
18
+ _tmpl$1 = ["<div class=\"k2b-file-grid__name\" id=\"", "\">", "</div>"],
19
+ _tmpl$10 = ["<div class=\"k2b-file-grid__meta\" id=\"", "\">", "</div>"],
20
+ _tmpl$11 = ["<div role=\"listitem\" class=\"k2b-file-grid__row\">", "</div>"],
21
+ _tmpl$12 = ["<div class=\"k2b-file-grid-stack__toolbar\">", "</div>"],
22
+ _tmpl$13 = ["<button type=\"button\" class=\"k2b-file-grid-stack__more\" aria-expanded=\"true\"><span>", "</span><i class=\"ti ti-chevron-up\" aria-hidden=\"true\"></i></button>"],
23
+ _tmpl$14 = ["<div class=\"k2b-file-grid-stack\"", ">", "", "", "</div>"],
24
+ _tmpl$15 = ["<div class=\"k2b-file-grid-stack__group\"><div class=\"k2b-file-grid-stack__label\"", ">", "<span class=\"k2b-file-grid-stack__count\">", "</span></div>", "</div>"],
25
+ _tmpl$16 = ["<span class=\"k2b-file-grid-stack__more-meta\">", "</span>"],
26
+ _tmpl$17 = ["<button type=\"button\" class=\"k2b-file-grid-stack__more\" aria-expanded=\"false\"><span>", "</span><i class=\"ti ti-chevron-down\" aria-hidden=\"true\"></i>", "</button>"];
25
27
  import { createEffect, createMemo, createSignal, createUniqueId, For, Index, on, Show } from "solid-js";
26
28
  import { useFileListMessages } from "./file-list-messages";
27
29
 
@@ -61,7 +63,7 @@ function SelectableFileGrid(props) {
61
63
  };
62
64
  const columns = () => grid ? Math.max(1, getComputedStyle(grid).gridTemplateColumns.split(" ").length) : 1;
63
65
  const nested = event => event.target instanceof Element && !!event.target.closest("button,a,input,label,select,textarea,summary,[contenteditable],[role=button],[role=menu]");
64
- return _$ssr(_tmpl$, `k2b-file-grid ${_$escape(props.class ?? "", true)}`, _$ssrAttribute("data-size", _$escape(props.size ?? "md", true), false) + _$ssrAttribute("data-layout", _$escape(props.layout ?? "grid", true), false) + _$ssrAttribute("data-action-visibility", _$escape(props.actionVisibility ?? "always", true), false), _$ssrAttribute("aria-label", _$escape(props.label, true), false) + _$ssrAttribute("aria-multiselectable", _$escape(props.selection.multiple, true), false), _$escape(_$createComponent(For, {
66
+ return _$ssr(_tmpl$, `k2b-file-grid ${_$escape(props.class ?? "", true)}`, _$ssrAttribute("data-size", _$escape(props.size ?? "md", true), false) + _$ssrAttribute("data-layout", _$escape(props.layout ?? "grid", true), false) + _$ssrAttribute("data-action-visibility", _$escape(props.actionVisibility ?? "always", true), false) + _$ssrAttribute("data-checks", props.checks ? "true" : _$escape(undefined, true), false), _$ssrAttribute("aria-label", _$escape(props.label, true), false) + _$ssrAttribute("aria-multiselectable", _$escape(props.selection.multiple, true), false), _$escape(_$createComponent(For, {
65
67
  get each() {
66
68
  return props.rows;
67
69
  },
@@ -80,7 +82,19 @@ function SelectableFileGrid(props) {
80
82
  get tabIndex() {
81
83
  return props.selection.focused() === id() ? 0 : -1;
82
84
  }
83
- }), [_$ssr(_tmpl$2, _$escape(props.renderPreview(row))), _$ssr(_tmpl$3, _$escape(props.renderLabel(row))), _$ssr(_tmpl$4, _$escape(props.renderMeta?.(row))), _$ssr(_tmpl$5, _$escape(props.renderActions?.(row)))], false));
85
+ }), [_$escape(_$createComponent(Show, {
86
+ get when() {
87
+ return props.checks;
88
+ },
89
+ children: checks => _$ssr(_tmpl$8, _$escape(_$createComponent(Show, {
90
+ get when() {
91
+ return checks()(row);
92
+ },
93
+ get children() {
94
+ return _$ssr(_tmpl$7, _$ssrAttribute("data-shape", props.selection.multiple ? "box" : "circle", false));
95
+ }
96
+ })))
97
+ })), _$ssr(_tmpl$2, _$escape(props.renderPreview(row))), _$ssr(_tmpl$3, _$escape(props.renderLabel(row))), _$ssr(_tmpl$4, _$escape(props.renderMeta?.(row))), _$ssr(_tmpl$5, _$escape(props.renderActions?.(row)))], false));
84
98
  }
85
99
  })));
86
100
  }
@@ -112,23 +126,23 @@ function OpenFileGrid(props) {
112
126
  label: undefined,
113
127
  rows: full() || !limited() ? props.rows : props.rows.slice(0, props.limit)
114
128
  }]);
115
- const list = (group, labelId) => _$ssr(_tmpl$7, `k2b-file-grid ${_$escape(props.class ?? "", true)}`, _$ssrAttribute("data-size", _$escape(props.size ?? "md", true), false) + _$ssrAttribute("data-layout", group().layout === "tiles" ? "tiles" : _$escape(props.layout ?? "grid", true), false) + _$ssrAttribute("data-action-visibility", _$escape(props.actionVisibility ?? "always", true), false), _$ssrAttribute("aria-label", labelId ? _$escape(undefined, true) : _$escape(props.label, true), false) + _$ssrAttribute("aria-labelledby", _$escape(labelId, true), false), _$escape(_$createComponent(For, {
129
+ const list = (group, labelId) => _$ssr(_tmpl$9, `k2b-file-grid ${_$escape(props.class ?? "", true)}`, _$ssrAttribute("data-size", _$escape(props.size ?? "md", true), false) + _$ssrAttribute("data-layout", group().layout === "tiles" ? "tiles" : _$escape(props.layout ?? "grid", true), false) + _$ssrAttribute("data-action-visibility", _$escape(props.actionVisibility ?? "always", true), false), _$ssrAttribute("aria-label", labelId ? _$escape(undefined, true) : _$escape(props.label, true), false) + _$ssrAttribute("aria-labelledby", _$escape(labelId, true), false), _$escape(_$createComponent(For, {
116
130
  get each() {
117
131
  return group().rows;
118
132
  },
119
133
  children: row => {
120
134
  const id = `k2b-file-grid-${createUniqueId()}`;
121
- return _$ssr(_tmpl$1, _$ssrElement("div", _$mergeProps(() => props.itemProps?.(row), {
135
+ return _$ssr(_tmpl$11, _$ssrElement("div", _$mergeProps(() => props.itemProps?.(row), {
122
136
  "class": "k2b-file-grid__item"
123
- }), [_$ssr(_tmpl$8, `${_$escape(id, true)}-name`, _$ssrAttribute("aria-describedby", props.renderMeta ? `${_$escape(id, true)}-meta` : _$escape(undefined, true), false)), _$ssr(_tmpl$2, _$escape(props.renderPreview(row))), _$ssr(_tmpl$9, `${_$escape(id, true)}-name`, _$escape(props.renderLabel(row))), _$ssr(_tmpl$0, `${_$escape(id, true)}-meta`, _$escape(props.renderMeta?.(row))), _$ssr(_tmpl$5, _$escape(props.renderActions?.(row)))], false));
137
+ }), [_$ssr(_tmpl$0, `${_$escape(id, true)}-name`, _$ssrAttribute("aria-describedby", props.renderMeta ? `${_$escape(id, true)}-meta` : _$escape(undefined, true), false)), _$ssr(_tmpl$2, _$escape(props.renderPreview(row))), _$ssr(_tmpl$1, `${_$escape(id, true)}-name`, _$escape(props.renderLabel(row))), _$ssr(_tmpl$10, `${_$escape(id, true)}-meta`, _$escape(props.renderMeta?.(row))), _$ssr(_tmpl$5, _$escape(props.renderActions?.(row)))], false));
124
138
  }
125
139
  })));
126
- return _$ssr(_tmpl$12, _$ssrAttribute("data-expanded", full() ? "true" : _$escape(undefined, true), false), _$escape(_$createComponent(Show, {
140
+ return _$ssr(_tmpl$14, _$ssrAttribute("data-expanded", full() ? "true" : _$escape(undefined, true), false), _$escape(_$createComponent(Show, {
127
141
  get when() {
128
142
  return _$memo(() => !!full())() && props.toolbar;
129
143
  },
130
144
  get children() {
131
- return _$ssr(_tmpl$10, _$escape(props.toolbar));
145
+ return _$ssr(_tmpl$12, _$escape(props.toolbar));
132
146
  }
133
147
  })), _$escape(_$createComponent(Index, {
134
148
  get each() {
@@ -144,7 +158,7 @@ function OpenFileGrid(props) {
144
158
  return list(group);
145
159
  },
146
160
  get children() {
147
- return _$ssr(_tmpl$13, _$ssrAttribute("id", _$escape(labelId, true), false), _$escape(group().label), _$escape(group().rows.length), _$escape(list(group, labelId)));
161
+ return _$ssr(_tmpl$15, _$ssrAttribute("id", _$escape(labelId, true), false), _$escape(group().label), _$escape(group().rows.length), _$escape(list(group, labelId)));
148
162
  }
149
163
  });
150
164
  }
@@ -158,19 +172,19 @@ function OpenFileGrid(props) {
158
172
  return full();
159
173
  },
160
174
  get fallback() {
161
- return _$ssr(_tmpl$15, _$escape(messages().showAll({
175
+ return _$ssr(_tmpl$17, _$escape(messages().showAll({
162
176
  count: props.rows.length
163
177
  })), _$escape(_$createComponent(Show, {
164
178
  get when() {
165
179
  return props.moreMeta;
166
180
  },
167
181
  get children() {
168
- return _$ssr(_tmpl$14, _$escape(props.moreMeta));
182
+ return _$ssr(_tmpl$16, _$escape(props.moreMeta));
169
183
  }
170
184
  })));
171
185
  },
172
186
  get children() {
173
- return _$ssr(_tmpl$11, _$escape(messages().showLess));
187
+ return _$ssr(_tmpl$13, _$escape(messages().showLess));
174
188
  }
175
189
  });
176
190
  }