@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,7 +1,7 @@
1
1
  import { template as _$template } from "solid-js/web";
2
2
  import { delegateEvents as _$delegateEvents } from "solid-js/web";
3
- import { getNextMarker as _$getNextMarker } from "solid-js/web";
4
3
  import { runHydrationEvents as _$runHydrationEvents } from "solid-js/web";
4
+ import { getNextMarker as _$getNextMarker } from "solid-js/web";
5
5
  import { spread as _$spread } from "solid-js/web";
6
6
  import { memo as _$memo } from "solid-js/web";
7
7
  import { setAttribute as _$setAttribute } from "solid-js/web";
@@ -13,15 +13,17 @@ import { use as _$use } from "solid-js/web";
13
13
  import { mergeProps as _$mergeProps } from "solid-js/web";
14
14
  import { createComponent as _$createComponent } from "solid-js/web";
15
15
  var _tmpl$ = /*#__PURE__*/_$template(`<div role=grid>`),
16
- _tmpl$2 = /*#__PURE__*/_$template(`<div role=row class=k2b-file-grid__row><div><div class=k2b-file-grid__preview></div><div class=k2b-file-grid__name></div><div class=k2b-file-grid__meta></div><div class=k2b-file-grid__actions>`),
17
- _tmpl$3 = /*#__PURE__*/_$template(`<div data-open-items=true role=list>`),
18
- _tmpl$4 = /*#__PURE__*/_$template(`<div role=listitem class=k2b-file-grid__row><div><button type=button class=k2b-file-grid__open></button><div class=k2b-file-grid__preview></div><div class=k2b-file-grid__name></div><div class=k2b-file-grid__meta></div><div class=k2b-file-grid__actions>`),
19
- _tmpl$5 = /*#__PURE__*/_$template(`<div class=k2b-file-grid-stack__toolbar>`),
20
- _tmpl$6 = /*#__PURE__*/_$template(`<button type=button class=k2b-file-grid-stack__more aria-expanded=true><span></span><i class="ti ti-chevron-up"aria-hidden=true>`),
21
- _tmpl$7 = /*#__PURE__*/_$template(`<div class=k2b-file-grid-stack><!$><!/><!$><!/><!$><!/>`),
22
- _tmpl$8 = /*#__PURE__*/_$template(`<div class=k2b-file-grid-stack__group><div class=k2b-file-grid-stack__label><!$><!/><span class=k2b-file-grid-stack__count></span></div><!$><!/>`),
23
- _tmpl$9 = /*#__PURE__*/_$template(`<span class=k2b-file-grid-stack__more-meta>`),
24
- _tmpl$0 = /*#__PURE__*/_$template(`<button type=button class=k2b-file-grid-stack__more aria-expanded=false><span></span><i class="ti ti-chevron-down"aria-hidden=true></i><!$><!/>`);
16
+ _tmpl$2 = /*#__PURE__*/_$template(`<div role=row class=k2b-file-grid__row><div><!$><!/><div class=k2b-file-grid__preview></div><div class=k2b-file-grid__name></div><div class=k2b-file-grid__meta></div><div class=k2b-file-grid__actions>`),
17
+ _tmpl$3 = /*#__PURE__*/_$template(`<span class=k2b-file-grid__check-box><i class="ti ti-check">`),
18
+ _tmpl$4 = /*#__PURE__*/_$template(`<span class=k2b-file-grid__check aria-hidden=true>`),
19
+ _tmpl$5 = /*#__PURE__*/_$template(`<div data-open-items=true role=list>`),
20
+ _tmpl$6 = /*#__PURE__*/_$template(`<div role=listitem class=k2b-file-grid__row><div><button type=button class=k2b-file-grid__open></button><div class=k2b-file-grid__preview></div><div class=k2b-file-grid__name></div><div class=k2b-file-grid__meta></div><div class=k2b-file-grid__actions>`),
21
+ _tmpl$7 = /*#__PURE__*/_$template(`<div class=k2b-file-grid-stack__toolbar>`),
22
+ _tmpl$8 = /*#__PURE__*/_$template(`<button type=button class=k2b-file-grid-stack__more aria-expanded=true><span></span><i class="ti ti-chevron-up"aria-hidden=true>`),
23
+ _tmpl$9 = /*#__PURE__*/_$template(`<div class=k2b-file-grid-stack><!$><!/><!$><!/><!$><!/>`),
24
+ _tmpl$0 = /*#__PURE__*/_$template(`<div class=k2b-file-grid-stack__group><div class=k2b-file-grid-stack__label><!$><!/><span class=k2b-file-grid-stack__count></span></div><!$><!/>`),
25
+ _tmpl$1 = /*#__PURE__*/_$template(`<span class=k2b-file-grid-stack__more-meta>`),
26
+ _tmpl$10 = /*#__PURE__*/_$template(`<button type=button class=k2b-file-grid-stack__more aria-expanded=false><span></span><i class="ti ti-chevron-down"aria-hidden=true></i><!$><!/>`);
25
27
  import { createEffect, createMemo, createSignal, createUniqueId, For, Index, on, Show } from "solid-js";
26
28
  import { useFileListMessages } from "./file-list-messages";
27
29
 
@@ -75,7 +77,9 @@ function SelectableFileGrid(props) {
75
77
  return (() => {
76
78
  var _el$2 = _$getNextElement(_tmpl$2),
77
79
  _el$3 = _el$2.firstChild,
78
- _el$4 = _el$3.firstChild,
80
+ _el$8 = _el$3.firstChild,
81
+ [_el$9, _co$] = _$getNextMarker(_el$8.nextSibling),
82
+ _el$4 = _el$9.nextSibling,
79
83
  _el$5 = _el$4.nextSibling,
80
84
  _el$6 = _el$5.nextSibling,
81
85
  _el$7 = _el$6.nextSibling;
@@ -112,6 +116,25 @@ function SelectableFileGrid(props) {
112
116
  }
113
117
  }
114
118
  }), false, true);
119
+ _$insert(_el$3, _$createComponent(Show, {
120
+ get when() {
121
+ return props.checks;
122
+ },
123
+ children: checks => (() => {
124
+ var _el$0 = _$getNextElement(_tmpl$4);
125
+ _$insert(_el$0, _$createComponent(Show, {
126
+ get when() {
127
+ return checks()(row);
128
+ },
129
+ get children() {
130
+ var _el$1 = _$getNextElement(_tmpl$3);
131
+ _$effect(() => _$setAttribute(_el$1, "data-shape", props.selection.multiple ? "box" : "circle"));
132
+ return _el$1;
133
+ }
134
+ }));
135
+ return _el$0;
136
+ })()
137
+ }), _el$9, _co$);
115
138
  _$insert(_el$4, () => props.renderPreview(row));
116
139
  _$insert(_el$5, () => props.renderLabel(row));
117
140
  _$insert(_el$6, () => props.renderMeta?.(row));
@@ -126,14 +149,16 @@ function SelectableFileGrid(props) {
126
149
  _v$2 = props.size ?? "md",
127
150
  _v$3 = props.layout ?? "grid",
128
151
  _v$4 = props.actionVisibility ?? "always",
129
- _v$5 = props.label,
130
- _v$6 = props.selection.multiple;
152
+ _v$5 = props.checks ? "true" : undefined,
153
+ _v$6 = props.label,
154
+ _v$7 = props.selection.multiple;
131
155
  _v$ !== _p$.e && _$className(_el$, _p$.e = _v$);
132
156
  _v$2 !== _p$.t && _$setAttribute(_el$, "data-size", _p$.t = _v$2);
133
157
  _v$3 !== _p$.a && _$setAttribute(_el$, "data-layout", _p$.a = _v$3);
134
158
  _v$4 !== _p$.o && _$setAttribute(_el$, "data-action-visibility", _p$.o = _v$4);
135
- _v$5 !== _p$.i && _$setAttribute(_el$, "aria-label", _p$.i = _v$5);
136
- _v$6 !== _p$.n && _$setAttribute(_el$, "aria-multiselectable", _p$.n = _v$6);
159
+ _v$5 !== _p$.i && _$setAttribute(_el$, "data-checks", _p$.i = _v$5);
160
+ _v$6 !== _p$.n && _$setAttribute(_el$, "aria-label", _p$.n = _v$6);
161
+ _v$7 !== _p$.s && _$setAttribute(_el$, "aria-multiselectable", _p$.s = _v$7);
137
162
  return _p$;
138
163
  }, {
139
164
  e: undefined,
@@ -141,7 +166,8 @@ function SelectableFileGrid(props) {
141
166
  a: undefined,
142
167
  o: undefined,
143
168
  i: undefined,
144
- n: undefined
169
+ n: undefined,
170
+ s: undefined
145
171
  });
146
172
  return _el$;
147
173
  })();
@@ -175,51 +201,51 @@ function OpenFileGrid(props) {
175
201
  rows: full() || !limited() ? props.rows : props.rows.slice(0, props.limit)
176
202
  }]);
177
203
  const list = (group, labelId) => (() => {
178
- var _el$8 = _$getNextElement(_tmpl$3);
179
- _$setAttribute(_el$8, "aria-labelledby", labelId);
180
- _$insert(_el$8, _$createComponent(For, {
204
+ var _el$10 = _$getNextElement(_tmpl$5);
205
+ _$setAttribute(_el$10, "aria-labelledby", labelId);
206
+ _$insert(_el$10, _$createComponent(For, {
181
207
  get each() {
182
208
  return group().rows;
183
209
  },
184
210
  children: row => {
185
211
  const id = `k2b-file-grid-${createUniqueId()}`;
186
212
  return (() => {
187
- var _el$9 = _$getNextElement(_tmpl$4),
188
- _el$0 = _el$9.firstChild,
189
- _el$1 = _el$0.firstChild,
190
- _el$10 = _el$1.nextSibling,
191
- _el$11 = _el$10.nextSibling,
192
- _el$12 = _el$11.nextSibling,
193
- _el$13 = _el$12.nextSibling;
194
- _$spread(_el$0, _$mergeProps(() => props.itemProps?.(row), {
213
+ var _el$11 = _$getNextElement(_tmpl$6),
214
+ _el$12 = _el$11.firstChild,
215
+ _el$13 = _el$12.firstChild,
216
+ _el$14 = _el$13.nextSibling,
217
+ _el$15 = _el$14.nextSibling,
218
+ _el$16 = _el$15.nextSibling,
219
+ _el$17 = _el$16.nextSibling;
220
+ _$spread(_el$12, _$mergeProps(() => props.itemProps?.(row), {
195
221
  "class": "k2b-file-grid__item"
196
222
  }), false, true);
197
- _el$1.$$contextmenu = () => props.onContextMenu?.(row);
198
- _el$1.$$click = () => props.onOpen(row);
199
- _$setAttribute(_el$1, "aria-labelledby", `${id}-name`);
200
- _$insert(_el$10, () => props.renderPreview(row));
201
- _$setAttribute(_el$11, "id", `${id}-name`);
202
- _$insert(_el$11, () => props.renderLabel(row));
203
- _$setAttribute(_el$12, "id", `${id}-meta`);
204
- _$insert(_el$12, () => props.renderMeta?.(row));
205
- _$insert(_el$13, () => props.renderActions?.(row));
206
- _$effect(() => _$setAttribute(_el$1, "aria-describedby", props.renderMeta ? `${id}-meta` : undefined));
223
+ _el$13.$$contextmenu = () => props.onContextMenu?.(row);
224
+ _el$13.$$click = () => props.onOpen(row);
225
+ _$setAttribute(_el$13, "aria-labelledby", `${id}-name`);
226
+ _$insert(_el$14, () => props.renderPreview(row));
227
+ _$setAttribute(_el$15, "id", `${id}-name`);
228
+ _$insert(_el$15, () => props.renderLabel(row));
229
+ _$setAttribute(_el$16, "id", `${id}-meta`);
230
+ _$insert(_el$16, () => props.renderMeta?.(row));
231
+ _$insert(_el$17, () => props.renderActions?.(row));
232
+ _$effect(() => _$setAttribute(_el$13, "aria-describedby", props.renderMeta ? `${id}-meta` : undefined));
207
233
  _$runHydrationEvents();
208
- return _el$9;
234
+ return _el$11;
209
235
  })();
210
236
  }
211
237
  }));
212
238
  _$effect(_p$ => {
213
- var _v$7 = `k2b-file-grid ${props.class ?? ""}`,
214
- _v$8 = props.size ?? "md",
215
- _v$9 = group().layout === "tiles" ? "tiles" : props.layout ?? "grid",
216
- _v$0 = props.actionVisibility ?? "always",
217
- _v$1 = labelId ? undefined : props.label;
218
- _v$7 !== _p$.e && _$className(_el$8, _p$.e = _v$7);
219
- _v$8 !== _p$.t && _$setAttribute(_el$8, "data-size", _p$.t = _v$8);
220
- _v$9 !== _p$.a && _$setAttribute(_el$8, "data-layout", _p$.a = _v$9);
221
- _v$0 !== _p$.o && _$setAttribute(_el$8, "data-action-visibility", _p$.o = _v$0);
222
- _v$1 !== _p$.i && _$setAttribute(_el$8, "aria-label", _p$.i = _v$1);
239
+ var _v$8 = `k2b-file-grid ${props.class ?? ""}`,
240
+ _v$9 = props.size ?? "md",
241
+ _v$0 = group().layout === "tiles" ? "tiles" : props.layout ?? "grid",
242
+ _v$1 = props.actionVisibility ?? "always",
243
+ _v$10 = labelId ? undefined : props.label;
244
+ _v$8 !== _p$.e && _$className(_el$10, _p$.e = _v$8);
245
+ _v$9 !== _p$.t && _$setAttribute(_el$10, "data-size", _p$.t = _v$9);
246
+ _v$0 !== _p$.a && _$setAttribute(_el$10, "data-layout", _p$.a = _v$0);
247
+ _v$1 !== _p$.o && _$setAttribute(_el$10, "data-action-visibility", _p$.o = _v$1);
248
+ _v$10 !== _p$.i && _$setAttribute(_el$10, "aria-label", _p$.i = _v$10);
223
249
  return _p$;
224
250
  }, {
225
251
  e: undefined,
@@ -228,27 +254,27 @@ function OpenFileGrid(props) {
228
254
  o: undefined,
229
255
  i: undefined
230
256
  });
231
- return _el$8;
257
+ return _el$10;
232
258
  })();
233
259
  return (() => {
234
- var _el$14 = _$getNextElement(_tmpl$7),
235
- _el$18 = _el$14.firstChild,
236
- [_el$19, _co$] = _$getNextMarker(_el$18.nextSibling),
237
- _el$20 = _el$19.nextSibling,
238
- [_el$21, _co$2] = _$getNextMarker(_el$20.nextSibling),
239
- _el$22 = _el$21.nextSibling,
240
- [_el$23, _co$3] = _$getNextMarker(_el$22.nextSibling);
241
- _$insert(_el$14, _$createComponent(Show, {
260
+ var _el$18 = _$getNextElement(_tmpl$9),
261
+ _el$22 = _el$18.firstChild,
262
+ [_el$23, _co$2] = _$getNextMarker(_el$22.nextSibling),
263
+ _el$24 = _el$23.nextSibling,
264
+ [_el$25, _co$3] = _$getNextMarker(_el$24.nextSibling),
265
+ _el$26 = _el$25.nextSibling,
266
+ [_el$27, _co$4] = _$getNextMarker(_el$26.nextSibling);
267
+ _$insert(_el$18, _$createComponent(Show, {
242
268
  get when() {
243
269
  return _$memo(() => !!full())() && props.toolbar;
244
270
  },
245
271
  get children() {
246
- var _el$15 = _$getNextElement(_tmpl$5);
247
- _$insert(_el$15, () => props.toolbar);
248
- return _el$15;
272
+ var _el$19 = _$getNextElement(_tmpl$7);
273
+ _$insert(_el$19, () => props.toolbar);
274
+ return _el$19;
249
275
  }
250
- }), _el$19, _co$);
251
- _$insert(_el$14, _$createComponent(Index, {
276
+ }), _el$23, _co$2);
277
+ _$insert(_el$18, _$createComponent(Index, {
252
278
  get each() {
253
279
  return groups();
254
280
  },
@@ -262,23 +288,23 @@ function OpenFileGrid(props) {
262
288
  return list(group);
263
289
  },
264
290
  get children() {
265
- var _el$24 = _$getNextElement(_tmpl$8),
266
- _el$25 = _el$24.firstChild,
267
- _el$27 = _el$25.firstChild,
268
- [_el$28, _co$4] = _$getNextMarker(_el$27.nextSibling),
269
- _el$26 = _el$28.nextSibling,
270
- _el$29 = _el$25.nextSibling,
271
- [_el$30, _co$5] = _$getNextMarker(_el$29.nextSibling);
272
- _$setAttribute(_el$25, "id", labelId);
273
- _$insert(_el$25, () => group().label, _el$28, _co$4);
274
- _$insert(_el$26, () => group().rows.length);
275
- _$insert(_el$24, () => list(group, labelId), _el$30, _co$5);
276
- return _el$24;
291
+ var _el$28 = _$getNextElement(_tmpl$0),
292
+ _el$29 = _el$28.firstChild,
293
+ _el$31 = _el$29.firstChild,
294
+ [_el$32, _co$5] = _$getNextMarker(_el$31.nextSibling),
295
+ _el$30 = _el$32.nextSibling,
296
+ _el$33 = _el$29.nextSibling,
297
+ [_el$34, _co$6] = _$getNextMarker(_el$33.nextSibling);
298
+ _$setAttribute(_el$29, "id", labelId);
299
+ _$insert(_el$29, () => group().label, _el$32, _co$5);
300
+ _$insert(_el$30, () => group().rows.length);
301
+ _$insert(_el$28, () => list(group, labelId), _el$34, _co$6);
302
+ return _el$28;
277
303
  }
278
304
  });
279
305
  }
280
- }), _el$21, _co$2);
281
- _$insert(_el$14, _$createComponent(Show, {
306
+ }), _el$25, _co$3);
307
+ _$insert(_el$18, _$createComponent(Show, {
282
308
  get when() {
283
309
  return limited();
284
310
  },
@@ -289,46 +315,46 @@ function OpenFileGrid(props) {
289
315
  },
290
316
  get fallback() {
291
317
  return (() => {
292
- var _el$31 = _$getNextElement(_tmpl$0),
293
- _el$32 = _el$31.firstChild,
294
- _el$33 = _el$32.nextSibling,
295
- _el$35 = _el$33.nextSibling,
296
- [_el$36, _co$6] = _$getNextMarker(_el$35.nextSibling);
297
- _el$31.$$click = () => toggle(true);
318
+ var _el$35 = _$getNextElement(_tmpl$10),
319
+ _el$36 = _el$35.firstChild,
320
+ _el$37 = _el$36.nextSibling,
321
+ _el$39 = _el$37.nextSibling,
322
+ [_el$40, _co$7] = _$getNextMarker(_el$39.nextSibling);
323
+ _el$35.$$click = () => toggle(true);
298
324
  var _ref$3 = more;
299
- typeof _ref$3 === "function" ? _$use(_ref$3, _el$31) : more = _el$31;
300
- _$insert(_el$32, () => messages().showAll({
325
+ typeof _ref$3 === "function" ? _$use(_ref$3, _el$35) : more = _el$35;
326
+ _$insert(_el$36, () => messages().showAll({
301
327
  count: props.rows.length
302
328
  }));
303
- _$insert(_el$31, _$createComponent(Show, {
329
+ _$insert(_el$35, _$createComponent(Show, {
304
330
  get when() {
305
331
  return props.moreMeta;
306
332
  },
307
333
  get children() {
308
- var _el$34 = _$getNextElement(_tmpl$9);
309
- _$insert(_el$34, () => props.moreMeta);
310
- return _el$34;
334
+ var _el$38 = _$getNextElement(_tmpl$1);
335
+ _$insert(_el$38, () => props.moreMeta);
336
+ return _el$38;
311
337
  }
312
- }), _el$36, _co$6);
338
+ }), _el$40, _co$7);
313
339
  _$runHydrationEvents();
314
- return _el$31;
340
+ return _el$35;
315
341
  })();
316
342
  },
317
343
  get children() {
318
- var _el$16 = _$getNextElement(_tmpl$6),
319
- _el$17 = _el$16.firstChild;
320
- _el$16.$$click = () => toggle(false);
344
+ var _el$20 = _$getNextElement(_tmpl$8),
345
+ _el$21 = _el$20.firstChild;
346
+ _el$20.$$click = () => toggle(false);
321
347
  var _ref$2 = less;
322
- typeof _ref$2 === "function" ? _$use(_ref$2, _el$16) : less = _el$16;
323
- _$insert(_el$17, () => messages().showLess);
348
+ typeof _ref$2 === "function" ? _$use(_ref$2, _el$20) : less = _el$20;
349
+ _$insert(_el$21, () => messages().showLess);
324
350
  _$runHydrationEvents();
325
- return _el$16;
351
+ return _el$20;
326
352
  }
327
353
  });
328
354
  }
329
- }), _el$23, _co$3);
330
- _$effect(() => _$setAttribute(_el$14, "data-expanded", full() ? "true" : undefined));
331
- return _el$14;
355
+ }), _el$27, _co$4);
356
+ _$effect(() => _$setAttribute(_el$18, "data-expanded", full() ? "true" : undefined));
357
+ return _el$18;
332
358
  })();
333
359
  }
334
360
  _$delegateEvents(["click", "contextmenu"]);
@@ -1 +1 @@
1
- {"version":3,"names":[],"sources":["content/FileGrid.tsx"],"sourcesContent":["import { createEffect, createMemo, createSignal, createUniqueId, For, Index, type JSX, on, Show } from \"solid-js\";\nimport type { CollectionSelection } from \"./collection-selection\";\nimport { useFileListMessages } from \"./file-list-messages\";\n\n/** One part of an open file list, such as its files as rows and its images as tiles. */\nexport type FileGridGroup<T> = {\n id: string;\n label: JSX.Element;\n rows: readonly T[];\n /** `tiles` fills each item with its preview and lays the name over it. Defaults to `list`. */\n layout?: \"list\" | \"tiles\";\n};\n\ntype FileGridBaseProps<T> = {\n rows: readonly T[];\n getRowId: (row: T) => string;\n label: string;\n size?: \"sm\" | \"md\" | \"lg\";\n /** `list` shows one compact row per item: preview, name, and meta beside each other. Defaults to `grid`. */\n layout?: \"grid\" | \"list\";\n renderPreview: (row: T) => JSX.Element;\n renderLabel: (row: T) => JSX.Element;\n renderMeta?: (row: T) => JSX.Element;\n renderActions?: (row: T) => JSX.Element;\n /**\n * `progressive` shows the actions on hover, keyboard focus, or an open menu with a mouse or trackpad, and always\n * on touch. Their slot is reserved in both states, so nothing moves. Defaults to `always`.\n */\n actionVisibility?: \"always\" | \"progressive\";\n onOpen: (row: T) => void;\n onContextMenu?: (row: T) => void;\n /** Extra attributes for one tile, for example drag-and-drop handlers or data attributes the host styles. */\n itemProps?: (row: T) => JSX.HTMLAttributes<HTMLDivElement>;\n class?: string;\n};\n\n/** A browser or picker: items are selected, and Enter or a double click opens them. */\nexport type FileGridSelectableProps<T> = FileGridBaseProps<T> & {\n selection: CollectionSelection;\n onRowClick?: (row: T) => void;\n limit?: never;\n expanded?: never;\n onExpandedChange?: never;\n moreMeta?: never;\n toolbar?: never;\n groups?: never;\n};\n\n/** A list without selection, as in a details panel: one click on an item opens it. */\nexport type FileGridOpenProps<T> = FileGridBaseProps<T> & {\n selection?: never;\n onRowClick?: never;\n /** Shows the first `limit` items, then \"Show all N\", which opens the full list in place. Without it, the list is always full. */\n limit?: number;\n /** Controls whether the full list is open. Without it, the list keeps its own state. */\n expanded?: boolean;\n onExpandedChange?: (expanded: boolean) => void;\n /** A quiet note at the end of \"Show all N\", such as how many duplicates were merged. */\n moreMeta?: JSX.Element;\n /** Shown above the full list, such as a count, an arrangement switch, or \"Download all\"; not in the short list. */\n toolbar?: JSX.Element;\n /** How the full list arranges its items, such as files as rows, then images as tiles; the short list stays one list. */\n groups?: (rows: readonly T[]) => readonly FileGridGroup<T>[];\n};\n\nexport type FileGridProps<T> = FileGridSelectableProps<T> | FileGridOpenProps<T>;\n\n/**\n * File presentation only; the host owns data, menus, leases and permissions. Items the selection marks with\n * `isDisabled` stay reachable by keyboard but cannot be selected or opened; say why in `renderMeta`.\n */\nexport function FileGrid<T>(props: FileGridProps<T>) {\n return (\n <Show when={props.selection} fallback={<OpenFileGrid {...(props as FileGridOpenProps<T>)} />}>\n {(selection) => <SelectableFileGrid {...(props as FileGridSelectableProps<T>)} selection={selection()} />}\n </Show>\n );\n}\n\nfunction SelectableFileGrid<T>(props: FileGridSelectableProps<T>) {\n let grid: HTMLDivElement | undefined;\n // Both clicks of a double-click belong to the item that took the first one. When that click replaced the rows,\n // for example by opening a folder, the item now under the pointer ignores the rest of the gesture.\n let pressed: EventTarget | null | undefined;\n const ownsClick = (event: MouseEvent) => {\n if (event.detail > 1 && pressed !== event.currentTarget) pressed = null;\n else pressed = event.currentTarget;\n return pressed !== null;\n };\n const columns = () => (grid ? Math.max(1, getComputedStyle(grid).gridTemplateColumns.split(\" \").length) : 1);\n const nested = (event: Event) =>\n event.target instanceof Element &&\n !!event.target.closest(\"button,a,input,label,select,textarea,summary,[contenteditable],[role=button],[role=menu]\");\n return (\n <div\n ref={grid}\n class={`k2b-file-grid ${props.class ?? \"\"}`}\n data-size={props.size ?? \"md\"}\n data-layout={props.layout ?? \"grid\"}\n data-action-visibility={props.actionVisibility ?? \"always\"}\n role=\"grid\"\n aria-label={props.label}\n aria-multiselectable={props.selection.multiple}\n >\n <For each={props.rows}>\n {(row) => {\n const id = () => props.getRowId(row);\n const disabled = () => props.selection.isDisabled(id());\n return (\n <div role=\"row\" class=\"k2b-file-grid__row\">\n <div\n {...props.itemProps?.(row)}\n role=\"gridcell\"\n class=\"k2b-file-grid__item\"\n aria-selected={props.selection.selected().has(id())}\n aria-disabled={disabled() || undefined}\n ref={(element) => props.selection.register(id(), element)}\n tabIndex={props.selection.focused() === id() ? 0 : -1}\n onFocus={() => props.selection.markFocused(id())}\n onClick={(event) => {\n if (!nested(event) && ownsClick(event) && !disabled()) {\n props.selection.select(id(), event);\n props.onRowClick?.(row);\n }\n }}\n onDblClick={(event) => {\n if (!nested(event) && pressed !== null && !disabled()) props.onOpen(row);\n }}\n onContextMenu={() => props.onContextMenu?.(row)}\n onKeyDown={(event) => {\n if (nested(event)) return;\n if (props.selection.keyDown(event, id(), columns())) return;\n if (event.key === \"Enter\") {\n event.preventDefault();\n if (!disabled()) props.onOpen(row);\n }\n }}\n >\n <div class=\"k2b-file-grid__preview\">{props.renderPreview(row)}</div>\n <div class=\"k2b-file-grid__name\">{props.renderLabel(row)}</div>\n <div class=\"k2b-file-grid__meta\">{props.renderMeta?.(row)}</div>\n <div class=\"k2b-file-grid__actions\">{props.renderActions?.(row)}</div>\n </div>\n </div>\n );\n }}\n </For>\n </div>\n );\n}\n\nfunction OpenFileGrid<T>(props: FileGridOpenProps<T>) {\n const messages = useFileListMessages();\n const [ownExpanded, setOwnExpanded] = createSignal(false);\n const limited = () => props.limit !== undefined && props.rows.length > props.limit;\n // Without a limit the list is always complete, so its toolbar and groups always apply.\n const full = () => props.limit === undefined || (limited() && (props.expanded ?? ownExpanded()));\n let more: HTMLButtonElement | undefined;\n let less: HTMLButtonElement | undefined;\n let moveFocus = false;\n const toggle = (next: boolean) => {\n moveFocus = true;\n if (props.expanded === undefined) setOwnExpanded(next);\n props.onExpandedChange?.(next);\n };\n // The pressed button leaves with the state it showed; once the new state is there, focus moves to its\n // counterpart, also when a controlling host applies it later.\n createEffect(\n on(\n full,\n (open) => {\n if (!moveFocus) return;\n moveFocus = false;\n queueMicrotask(() => (open ? less : more)?.focus());\n },\n { defer: true },\n ),\n );\n const groups = createMemo((): readonly FileGridGroup<T>[] =>\n full() && props.groups\n ? props.groups(props.rows).filter((group) => group.rows.length > 0)\n : [{ id: \"rows\", label: undefined, rows: full() || !limited() ? props.rows : props.rows.slice(0, props.limit) }],\n );\n\n const list = (group: () => FileGridGroup<T>, labelId?: string) => (\n <div\n class={`k2b-file-grid ${props.class ?? \"\"}`}\n data-size={props.size ?? \"md\"}\n data-layout={group().layout === \"tiles\" ? \"tiles\" : (props.layout ?? \"grid\")}\n data-action-visibility={props.actionVisibility ?? \"always\"}\n data-open-items=\"true\"\n role=\"list\"\n aria-label={labelId ? undefined : props.label}\n aria-labelledby={labelId}\n >\n {/* Keyed by the row itself: new data keeps every existing item, its focus, and its state. */}\n <For each={group().rows}>\n {(row) => {\n const id = `k2b-file-grid-${createUniqueId()}`;\n return (\n <div role=\"listitem\" class=\"k2b-file-grid__row\">\n <div {...props.itemProps?.(row)} class=\"k2b-file-grid__item\">\n {/* The whole item opens the file; its actions lie above this layer in their own slot. */}\n <button\n type=\"button\"\n class=\"k2b-file-grid__open\"\n aria-labelledby={`${id}-name`}\n aria-describedby={props.renderMeta ? `${id}-meta` : undefined}\n onClick={() => props.onOpen(row)}\n onContextMenu={() => props.onContextMenu?.(row)}\n />\n <div class=\"k2b-file-grid__preview\">{props.renderPreview(row)}</div>\n <div class=\"k2b-file-grid__name\" id={`${id}-name`}>\n {props.renderLabel(row)}\n </div>\n <div class=\"k2b-file-grid__meta\" id={`${id}-meta`}>\n {props.renderMeta?.(row)}\n </div>\n <div class=\"k2b-file-grid__actions\">{props.renderActions?.(row)}</div>\n </div>\n </div>\n );\n }}\n </For>\n </div>\n );\n\n return (\n <div class=\"k2b-file-grid-stack\" data-expanded={full() ? \"true\" : undefined}>\n <Show when={full() && props.toolbar}>\n <div class=\"k2b-file-grid-stack__toolbar\">{props.toolbar}</div>\n </Show>\n {/* By position: a group that only changes its rows keeps its list, so new data remounts nothing. */}\n <Index each={groups()}>\n {(group) => {\n const labelId = `k2b-file-grid-group-${createUniqueId()}`;\n return (\n <Show when={group().label !== undefined} fallback={list(group)}>\n <div class=\"k2b-file-grid-stack__group\">\n <div class=\"k2b-file-grid-stack__label\" id={labelId}>\n {group().label}\n <span class=\"k2b-file-grid-stack__count\">{group().rows.length}</span>\n </div>\n {list(group, labelId)}\n </div>\n </Show>\n );\n }}\n </Index>\n <Show when={limited()}>\n <Show\n when={full()}\n fallback={\n <button ref={more} type=\"button\" class=\"k2b-file-grid-stack__more\" aria-expanded=\"false\" onClick={() => toggle(true)}>\n <span>{messages().showAll({ count: props.rows.length })}</span>\n <i class=\"ti ti-chevron-down\" aria-hidden=\"true\" />\n <Show when={props.moreMeta}>\n <span class=\"k2b-file-grid-stack__more-meta\">{props.moreMeta}</span>\n </Show>\n </button>\n }\n >\n <button ref={less} type=\"button\" class=\"k2b-file-grid-stack__more\" aria-expanded=\"true\" onClick={() => toggle(false)}>\n <span>{messages().showLess}</span>\n <i class=\"ti ti-chevron-up\" aria-hidden=\"true\" />\n </button>\n </Show>\n </Show>\n </div>\n );\n}\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"names":[],"sources":["content/FileGrid.tsx"],"sourcesContent":["import { createEffect, createMemo, createSignal, createUniqueId, For, Index, type JSX, on, Show } from \"solid-js\";\nimport type { CollectionSelection } from \"./collection-selection\";\nimport { useFileListMessages } from \"./file-list-messages\";\n\n/** One part of an open file list, such as its files as rows and its images as tiles. */\nexport type FileGridGroup<T> = {\n id: string;\n label: JSX.Element;\n rows: readonly T[];\n /** `tiles` fills each item with its preview and lays the name over it. Defaults to `list`. */\n layout?: \"list\" | \"tiles\";\n};\n\ntype FileGridBaseProps<T> = {\n rows: readonly T[];\n getRowId: (row: T) => string;\n label: string;\n size?: \"sm\" | \"md\" | \"lg\";\n /** `list` shows one compact row per item: preview, name, and meta beside each other. Defaults to `grid`. */\n layout?: \"grid\" | \"list\";\n renderPreview: (row: T) => JSX.Element;\n renderLabel: (row: T) => JSX.Element;\n renderMeta?: (row: T) => JSX.Element;\n renderActions?: (row: T) => JSX.Element;\n /**\n * `progressive` shows the actions on hover, keyboard focus, or an open menu with a mouse or trackpad, and always\n * on touch. Their slot is reserved in both states, so nothing moves. Defaults to `always`.\n */\n actionVisibility?: \"always\" | \"progressive\";\n onOpen: (row: T) => void;\n onContextMenu?: (row: T) => void;\n /** Extra attributes for one tile, for example drag-and-drop handlers or data attributes the host styles. */\n itemProps?: (row: T) => JSX.HTMLAttributes<HTMLDivElement>;\n class?: string;\n};\n\n/** A browser or picker: items are selected, and Enter or a double click opens them. */\nexport type FileGridSelectableProps<T> = FileGridBaseProps<T> & {\n selection: CollectionSelection;\n onRowClick?: (row: T) => void;\n /**\n * Shows a check box before each item that `checks` returns `true` for, or a circle when only one item may be\n * selected. The check only mirrors the selection; items without one keep its slot, so names stay in line.\n */\n checks?: (row: T) => boolean;\n limit?: never;\n expanded?: never;\n onExpandedChange?: never;\n moreMeta?: never;\n toolbar?: never;\n groups?: never;\n};\n\n/** A list without selection, as in a details panel: one click on an item opens it. */\nexport type FileGridOpenProps<T> = FileGridBaseProps<T> & {\n selection?: never;\n onRowClick?: never;\n checks?: never;\n /** Shows the first `limit` items, then \"Show all N\", which opens the full list in place. Without it, the list is always full. */\n limit?: number;\n /** Controls whether the full list is open. Without it, the list keeps its own state. */\n expanded?: boolean;\n onExpandedChange?: (expanded: boolean) => void;\n /** A quiet note at the end of \"Show all N\", such as how many duplicates were merged. */\n moreMeta?: JSX.Element;\n /** Shown above the full list, such as a count, an arrangement switch, or \"Download all\"; not in the short list. */\n toolbar?: JSX.Element;\n /** How the full list arranges its items, such as files as rows, then images as tiles; the short list stays one list. */\n groups?: (rows: readonly T[]) => readonly FileGridGroup<T>[];\n};\n\nexport type FileGridProps<T> = FileGridSelectableProps<T> | FileGridOpenProps<T>;\n\n/**\n * File presentation only; the host owns data, menus, leases and permissions. Items the selection marks with\n * `isDisabled` stay reachable by keyboard but cannot be selected or opened; say why in `renderMeta`.\n */\nexport function FileGrid<T>(props: FileGridProps<T>) {\n return (\n <Show when={props.selection} fallback={<OpenFileGrid {...(props as FileGridOpenProps<T>)} />}>\n {(selection) => <SelectableFileGrid {...(props as FileGridSelectableProps<T>)} selection={selection()} />}\n </Show>\n );\n}\n\nfunction SelectableFileGrid<T>(props: FileGridSelectableProps<T>) {\n let grid: HTMLDivElement | undefined;\n // Both clicks of a double-click belong to the item that took the first one. When that click replaced the rows,\n // for example by opening a folder, the item now under the pointer ignores the rest of the gesture.\n let pressed: EventTarget | null | undefined;\n const ownsClick = (event: MouseEvent) => {\n if (event.detail > 1 && pressed !== event.currentTarget) pressed = null;\n else pressed = event.currentTarget;\n return pressed !== null;\n };\n const columns = () => (grid ? Math.max(1, getComputedStyle(grid).gridTemplateColumns.split(\" \").length) : 1);\n const nested = (event: Event) =>\n event.target instanceof Element &&\n !!event.target.closest(\"button,a,input,label,select,textarea,summary,[contenteditable],[role=button],[role=menu]\");\n return (\n <div\n ref={grid}\n class={`k2b-file-grid ${props.class ?? \"\"}`}\n data-size={props.size ?? \"md\"}\n data-layout={props.layout ?? \"grid\"}\n data-action-visibility={props.actionVisibility ?? \"always\"}\n data-checks={props.checks ? \"true\" : undefined}\n role=\"grid\"\n aria-label={props.label}\n aria-multiselectable={props.selection.multiple}\n >\n <For each={props.rows}>\n {(row) => {\n const id = () => props.getRowId(row);\n const disabled = () => props.selection.isDisabled(id());\n return (\n <div role=\"row\" class=\"k2b-file-grid__row\">\n <div\n {...props.itemProps?.(row)}\n role=\"gridcell\"\n class=\"k2b-file-grid__item\"\n aria-selected={props.selection.selected().has(id())}\n aria-disabled={disabled() || undefined}\n ref={(element) => props.selection.register(id(), element)}\n tabIndex={props.selection.focused() === id() ? 0 : -1}\n onFocus={() => props.selection.markFocused(id())}\n onClick={(event) => {\n if (!nested(event) && ownsClick(event) && !disabled()) {\n props.selection.select(id(), event);\n props.onRowClick?.(row);\n }\n }}\n onDblClick={(event) => {\n if (!nested(event) && pressed !== null && !disabled()) props.onOpen(row);\n }}\n onContextMenu={() => props.onContextMenu?.(row)}\n onKeyDown={(event) => {\n if (nested(event)) return;\n if (props.selection.keyDown(event, id(), columns())) return;\n if (event.key === \"Enter\") {\n event.preventDefault();\n if (!disabled()) props.onOpen(row);\n }\n }}\n >\n <Show when={props.checks}>\n {(checks) => (\n <span class=\"k2b-file-grid__check\" aria-hidden=\"true\">\n <Show when={checks()(row)}>\n <span class=\"k2b-file-grid__check-box\" data-shape={props.selection.multiple ? \"box\" : \"circle\"}>\n <i class=\"ti ti-check\" />\n </span>\n </Show>\n </span>\n )}\n </Show>\n <div class=\"k2b-file-grid__preview\">{props.renderPreview(row)}</div>\n <div class=\"k2b-file-grid__name\">{props.renderLabel(row)}</div>\n <div class=\"k2b-file-grid__meta\">{props.renderMeta?.(row)}</div>\n <div class=\"k2b-file-grid__actions\">{props.renderActions?.(row)}</div>\n </div>\n </div>\n );\n }}\n </For>\n </div>\n );\n}\n\nfunction OpenFileGrid<T>(props: FileGridOpenProps<T>) {\n const messages = useFileListMessages();\n const [ownExpanded, setOwnExpanded] = createSignal(false);\n const limited = () => props.limit !== undefined && props.rows.length > props.limit;\n // Without a limit the list is always complete, so its toolbar and groups always apply.\n const full = () => props.limit === undefined || (limited() && (props.expanded ?? ownExpanded()));\n let more: HTMLButtonElement | undefined;\n let less: HTMLButtonElement | undefined;\n let moveFocus = false;\n const toggle = (next: boolean) => {\n moveFocus = true;\n if (props.expanded === undefined) setOwnExpanded(next);\n props.onExpandedChange?.(next);\n };\n // The pressed button leaves with the state it showed; once the new state is there, focus moves to its\n // counterpart, also when a controlling host applies it later.\n createEffect(\n on(\n full,\n (open) => {\n if (!moveFocus) return;\n moveFocus = false;\n queueMicrotask(() => (open ? less : more)?.focus());\n },\n { defer: true },\n ),\n );\n const groups = createMemo((): readonly FileGridGroup<T>[] =>\n full() && props.groups\n ? props.groups(props.rows).filter((group) => group.rows.length > 0)\n : [{ id: \"rows\", label: undefined, rows: full() || !limited() ? props.rows : props.rows.slice(0, props.limit) }],\n );\n\n const list = (group: () => FileGridGroup<T>, labelId?: string) => (\n <div\n class={`k2b-file-grid ${props.class ?? \"\"}`}\n data-size={props.size ?? \"md\"}\n data-layout={group().layout === \"tiles\" ? \"tiles\" : (props.layout ?? \"grid\")}\n data-action-visibility={props.actionVisibility ?? \"always\"}\n data-open-items=\"true\"\n role=\"list\"\n aria-label={labelId ? undefined : props.label}\n aria-labelledby={labelId}\n >\n {/* Keyed by the row itself: new data keeps every existing item, its focus, and its state. */}\n <For each={group().rows}>\n {(row) => {\n const id = `k2b-file-grid-${createUniqueId()}`;\n return (\n <div role=\"listitem\" class=\"k2b-file-grid__row\">\n <div {...props.itemProps?.(row)} class=\"k2b-file-grid__item\">\n {/* The whole item opens the file; its actions lie above this layer in their own slot. */}\n <button\n type=\"button\"\n class=\"k2b-file-grid__open\"\n aria-labelledby={`${id}-name`}\n aria-describedby={props.renderMeta ? `${id}-meta` : undefined}\n onClick={() => props.onOpen(row)}\n onContextMenu={() => props.onContextMenu?.(row)}\n />\n <div class=\"k2b-file-grid__preview\">{props.renderPreview(row)}</div>\n <div class=\"k2b-file-grid__name\" id={`${id}-name`}>\n {props.renderLabel(row)}\n </div>\n <div class=\"k2b-file-grid__meta\" id={`${id}-meta`}>\n {props.renderMeta?.(row)}\n </div>\n <div class=\"k2b-file-grid__actions\">{props.renderActions?.(row)}</div>\n </div>\n </div>\n );\n }}\n </For>\n </div>\n );\n\n return (\n <div class=\"k2b-file-grid-stack\" data-expanded={full() ? \"true\" : undefined}>\n <Show when={full() && props.toolbar}>\n <div class=\"k2b-file-grid-stack__toolbar\">{props.toolbar}</div>\n </Show>\n {/* By position: a group that only changes its rows keeps its list, so new data remounts nothing. */}\n <Index each={groups()}>\n {(group) => {\n const labelId = `k2b-file-grid-group-${createUniqueId()}`;\n return (\n <Show when={group().label !== undefined} fallback={list(group)}>\n <div class=\"k2b-file-grid-stack__group\">\n <div class=\"k2b-file-grid-stack__label\" id={labelId}>\n {group().label}\n <span class=\"k2b-file-grid-stack__count\">{group().rows.length}</span>\n </div>\n {list(group, labelId)}\n </div>\n </Show>\n );\n }}\n </Index>\n <Show when={limited()}>\n <Show\n when={full()}\n fallback={\n <button ref={more} type=\"button\" class=\"k2b-file-grid-stack__more\" aria-expanded=\"false\" onClick={() => toggle(true)}>\n <span>{messages().showAll({ count: props.rows.length })}</span>\n <i class=\"ti ti-chevron-down\" aria-hidden=\"true\" />\n <Show when={props.moreMeta}>\n <span class=\"k2b-file-grid-stack__more-meta\">{props.moreMeta}</span>\n </Show>\n </button>\n }\n >\n <button ref={less} type=\"button\" class=\"k2b-file-grid-stack__more\" aria-expanded=\"true\" onClick={() => toggle(false)}>\n <span>{messages().showLess}</span>\n <i class=\"ti ti-chevron-up\" aria-hidden=\"true\" />\n </button>\n </Show>\n </Show>\n </div>\n );\n}\n"],"mappings":"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","ignoreList":[]}
@@ -62,10 +62,16 @@ export function createChoiceLoader(loader, debounceMs) {
62
62
  timer = undefined;
63
63
  controller?.abort();
64
64
  controller = undefined;
65
+ request++;
66
+ setLoading(false);
65
67
  };
66
68
  const run = async query => {
67
69
  const loadOptions = loader();
68
- if (!loadOptions) return;
70
+ if (!loadOptions) {
71
+ // The source went away while its search waited out the debounce.
72
+ setLoading(false);
73
+ return;
74
+ }
69
75
  controller?.abort();
70
76
  controller = new AbortController();
71
77
  const currentController = controller;
@@ -81,13 +87,16 @@ export function createChoiceLoader(loader, debounceMs) {
81
87
  setError(errorMessage(reason));
82
88
  }
83
89
  } finally {
84
- if (currentRequest === request) setLoading(false);
90
+ if (currentRequest === request && !timer) setLoading(false);
85
91
  }
86
92
  };
87
93
  const load = (query, immediate = false) => {
88
94
  lastQuery = query;
89
95
  if (timer) clearTimeout(timer);
90
96
  timer = undefined;
97
+ // A search waiting out its debounce is already loading: the list shows its
98
+ // loading rows, not "no results" for a request that has not run yet.
99
+ if (loader()) setLoading(true);
91
100
  if (immediate || debounceMs() <= 0) {
92
101
  void run(query);
93
102
  return;
@@ -115,15 +124,23 @@ const popoverIsOpen = popover => {
115
124
  return false;
116
125
  }
117
126
  };
118
- export const placeChoicePopover = (trigger, popover, placement = {}) => {
127
+ /**
128
+ * Places the popover under (or above) its trigger. `floor` is the narrowest
129
+ * width it may take, such as the width it already had while open, so filtering
130
+ * the options never makes it narrower.
131
+ */
132
+ export const placeChoicePopover = (trigger, popover, placement = {}, floor = 0) => {
119
133
  const margin = 8;
120
134
  const gap = 4;
121
135
  const triggerRect = trigger.getBoundingClientRect();
122
- // Cloud sizes its dropdowns to the trigger exactly (`dialog.style.width =
123
- // rect.width`). Keep that so a narrow toolbar select does not open a wide
124
- // panel that no longer lines up with the control it belongs to.
125
- const triggerWidth = Math.min(triggerRect.width, window.innerWidth - margin * 2);
126
- if (placement.width !== "own") popover.style.width = `${triggerWidth}px`;
136
+ // The popover starts at the trigger's left edge and is never narrower than
137
+ // the trigger. Its stylesheet lets it grow to its longest name, as a menu
138
+ // does, so a name stays on one line beside a narrow trigger.
139
+ if (placement.width !== "own") {
140
+ popover.dataset.width = "fit";
141
+ const minWidth = Math.min(Math.max(triggerRect.width, floor), window.innerWidth - margin * 2);
142
+ popover.style.setProperty("--k2b-choice-min-width", `${minWidth}px`);
143
+ }
127
144
 
128
145
  // A stylesheet minimum, such as a popover with filter chips, can make it
129
146
  // wider than the trigger, so the clamp below uses the rendered width.
@@ -142,14 +159,24 @@ export function createChoicePopover(disabled, placement = () => ({})) {
142
159
  const [trigger, setTrigger] = createSignal();
143
160
  const [popover, setPopover] = createSignal();
144
161
  let triggerRing = true;
162
+ // The widest the open popover has been: typing a filter never narrows it.
163
+ let widest = 0;
145
164
  const place = () => {
146
165
  const triggerElement = trigger();
147
166
  const popoverElement = popover();
148
- if (triggerElement && popoverElement && open()) placeChoicePopover(triggerElement, popoverElement, placement());
167
+ if (!triggerElement || !popoverElement || !open()) return;
168
+ placeChoicePopover(triggerElement, popoverElement, placement(), widest);
169
+ widest = popoverElement.getBoundingClientRect().width;
170
+ // Hold the width now, while it is the one on screen. Shorter results then
171
+ // keep it without a resize, so the observer below never has to widen the
172
+ // popover again during its own delivery, which WebKit reports as a
173
+ // "ResizeObserver loop" error.
174
+ if (placement().width !== "own") popoverElement.style.setProperty("--k2b-choice-min-width", `${widest}px`);
149
175
  };
150
176
  const show = () => {
151
177
  const popoverElement = popover();
152
178
  if (disabled() || !popoverElement || popoverIsOpen(popoverElement)) return;
179
+ widest = 0;
153
180
  triggerRing = ringOnReturn(trigger());
154
181
  popoverElement.showPopover();
155
182
  setOpen(true);