@zeyos/zx 2.1.0 → 2.2.1

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 (311) hide show
  1. package/CHANGELOG.md +51 -0
  2. package/README.md +15 -0
  3. package/dist/types/compat/base.d.ts +156 -0
  4. package/dist/types/compat/globals.d.ts +20 -0
  5. package/dist/types/compat/index.d.ts +128 -0
  6. package/dist/types/compat/map/basic.d.ts +175 -0
  7. package/dist/types/compat/map/data.d.ts +102 -0
  8. package/dist/types/compat/map/date-time.d.ts +80 -0
  9. package/dist/types/compat/map/factory.d.ts +9 -0
  10. package/dist/types/compat/map/form.d.ts +98 -0
  11. package/dist/types/compat/map/helpers.d.ts +12 -0
  12. package/dist/types/compat/map/http.d.ts +36 -0
  13. package/dist/types/compat/map/layout.d.ts +106 -0
  14. package/dist/types/compat/map/options.d.ts +80 -0
  15. package/dist/types/compat/map/select.d.ts +95 -0
  16. package/dist/types/compat/map/stubs.d.ts +32 -0
  17. package/dist/types/compat/map/utilities.d.ts +37 -0
  18. package/dist/types/compat-entry.d.ts +5 -0
  19. package/dist/types/components/badge/badge.d.ts +46 -0
  20. package/dist/types/components/breadcrumb/breadcrumb.d.ts +200 -0
  21. package/dist/types/components/button/button.d.ts +42 -0
  22. package/dist/types/components/check-button/check-button.d.ts +98 -0
  23. package/dist/types/components/checklist/checklist.d.ts +143 -0
  24. package/dist/types/components/checklist/field-adapter.d.ts +5 -0
  25. package/dist/types/components/context-menu/context-menu.d.ts +130 -0
  26. package/dist/types/components/copy/copy-button.d.ts +48 -0
  27. package/dist/types/components/copy/copy-input.d.ts +91 -0
  28. package/dist/types/components/data-filter/data-filter.d.ts +250 -0
  29. package/dist/types/components/data-filter/filter-core.d.ts +52 -0
  30. package/dist/types/components/date-picker/date-picker.d.ts +137 -0
  31. package/dist/types/components/date-picker/date-range-picker.d.ts +350 -0
  32. package/dist/types/components/date-picker/field-adapter.d.ts +6 -0
  33. package/dist/types/components/date-picker/month-picker.d.ts +75 -0
  34. package/dist/types/components/date-picker/range-field-adapter.d.ts +7 -0
  35. package/dist/types/components/date-picker/time-picker.d.ts +127 -0
  36. package/dist/types/components/datebox/date-range-box.d.ts +218 -0
  37. package/dist/types/components/datebox/datebox.d.ts +160 -0
  38. package/dist/types/components/datebox/field-adapter.d.ts +5 -0
  39. package/dist/types/components/dialog/dialog.d.ts +284 -0
  40. package/dist/types/components/dropdown/dropdown.d.ts +118 -0
  41. package/dist/types/components/empty-state/empty-state.d.ts +38 -0
  42. package/dist/types/components/field/field.d.ts +231 -0
  43. package/dist/types/components/field-upload/field-adapter.d.ts +5 -0
  44. package/dist/types/components/field-upload/field-upload.d.ts +213 -0
  45. package/dist/types/components/fieldset/fieldset.d.ts +125 -0
  46. package/dist/types/components/finder/finder.d.ts +252 -0
  47. package/dist/types/components/form/form.d.ts +194 -0
  48. package/dist/types/components/groupbox/groupbox.d.ts +89 -0
  49. package/dist/types/components/layout/layout.d.ts +132 -0
  50. package/dist/types/components/loading/inline-loading.d.ts +86 -0
  51. package/dist/types/components/loading/progress-bar.d.ts +168 -0
  52. package/dist/types/components/loading/spinner.d.ts +34 -0
  53. package/dist/types/components/master-panel/master-panel.d.ts +112 -0
  54. package/dist/types/components/menu-button/menu-button.d.ts +142 -0
  55. package/dist/types/components/message/message.d.ts +212 -0
  56. package/dist/types/components/modal/modal.d.ts +105 -0
  57. package/dist/types/components/multi-value-editor/field-adapter.d.ts +5 -0
  58. package/dist/types/components/multi-value-editor/multi-value-editor.d.ts +66 -0
  59. package/dist/types/components/navigation-bar/navigation-bar.d.ts +229 -0
  60. package/dist/types/components/number-field/field-adapter.d.ts +5 -0
  61. package/dist/types/components/number-field/number-field.d.ts +292 -0
  62. package/dist/types/components/pagination/pagination.d.ts +267 -0
  63. package/dist/types/components/panel/panel.d.ts +194 -0
  64. package/dist/types/components/permission/permission.d.ts +93 -0
  65. package/dist/types/components/rating/field-adapter.d.ts +5 -0
  66. package/dist/types/components/rating/rating.d.ts +213 -0
  67. package/dist/types/components/search/search.d.ts +98 -0
  68. package/dist/types/components/select/field-adapter.d.ts +5 -0
  69. package/dist/types/components/select/filter.d.ts +11 -0
  70. package/dist/types/components/select/select.d.ts +235 -0
  71. package/dist/types/components/skeleton/skeleton.d.ts +97 -0
  72. package/dist/types/components/slider/field-adapter.d.ts +5 -0
  73. package/dist/types/components/slider/slider.d.ts +216 -0
  74. package/dist/types/components/split-view/split-view.d.ts +335 -0
  75. package/dist/types/components/stepper/stepper.d.ts +314 -0
  76. package/dist/types/components/stepper/steps.d.ts +131 -0
  77. package/dist/types/components/tabbox/tabbox.d.ts +230 -0
  78. package/dist/types/components/table/sort.d.ts +49 -0
  79. package/dist/types/components/table/table.d.ts +872 -0
  80. package/dist/types/components/tag-picker/field-adapter.d.ts +5 -0
  81. package/dist/types/components/tag-picker/tag-picker.d.ts +375 -0
  82. package/dist/types/components/timebox/field-adapter.d.ts +5 -0
  83. package/dist/types/components/timebox/timebox.d.ts +121 -0
  84. package/dist/types/components/toggle/field-adapter.d.ts +5 -0
  85. package/dist/types/components/toggle/toggle.d.ts +94 -0
  86. package/dist/types/components/toolbar/toolbar.d.ts +230 -0
  87. package/dist/types/components/tooltip/tooltip.d.ts +183 -0
  88. package/dist/types/components/tree/hierarchy.d.ts +113 -0
  89. package/dist/types/components/tree/tree.d.ts +383 -0
  90. package/dist/types/components/truncate/truncate.d.ts +61 -0
  91. package/dist/types/components/value-list/field-adapter.d.ts +5 -0
  92. package/dist/types/components/value-list/value-list.d.ts +143 -0
  93. package/dist/types/core/breakpoint.d.ts +68 -0
  94. package/dist/types/core/component.d.ts +115 -0
  95. package/dist/types/core/date.d.ts +50 -0
  96. package/dist/types/core/dom.d.ts +86 -0
  97. package/dist/types/core/export.d.ts +70 -0
  98. package/dist/types/core/fontawesome.d.ts +107 -0
  99. package/dist/types/core/format.d.ts +107 -0
  100. package/dist/types/core/http.d.ts +122 -0
  101. package/dist/types/core/i18n.d.ts +35 -0
  102. package/dist/types/core/icons.d.ts +137 -0
  103. package/dist/types/core/keyboard.d.ts +72 -0
  104. package/dist/types/core/position.d.ts +45 -0
  105. package/dist/types/core/storage.d.ts +46 -0
  106. package/dist/types/core/util.d.ts +117 -0
  107. package/dist/types/elements/define.d.ts +73 -0
  108. package/dist/types/elements/reflect.d.ts +27 -0
  109. package/dist/types/index.d.ts +79 -0
  110. package/dist/types/zeyos/connect.d.ts +65 -0
  111. package/dist/types/zeyos/form.d.ts +140 -0
  112. package/dist/types/zeyos/icons.d.ts +104 -0
  113. package/dist/types/zeyos/index.d.ts +12 -0
  114. package/dist/types/zeyos/modules.d.ts +110 -0
  115. package/dist/types/zeyos/query.d.ts +157 -0
  116. package/dist/types/zeyos/schema.d.ts +79 -0
  117. package/dist/types/zeyos/select.d.ts +167 -0
  118. package/dist/types/zeyos/table.d.ts +205 -0
  119. package/dist/zx-compat.esm.js +375 -39
  120. package/dist/zx-compat.esm.min.js +1 -1
  121. package/dist/zx-compat.global.js +372 -73
  122. package/dist/zx-compat.global.min.js +3 -3
  123. package/dist/zx-zeyos.esm.js +355 -49
  124. package/dist/zx-zeyos.esm.min.js +1 -1
  125. package/dist/zx.css +68 -6
  126. package/dist/zx.esm.js +359 -73
  127. package/dist/zx.esm.min.js +3 -3
  128. package/dist/zx.global.js +359 -73
  129. package/dist/zx.global.min.js +3 -3
  130. package/dist/zx.min.css +1 -1
  131. package/docs/api.json +48 -2
  132. package/docs/llms.md +31 -0
  133. package/package.json +37 -9
  134. package/src/compat/base.js +291 -0
  135. package/src/compat/globals.js +165 -0
  136. package/src/compat/index.js +84 -0
  137. package/src/compat/map/basic.js +464 -0
  138. package/src/compat/map/data.js +232 -0
  139. package/src/compat/map/date-time.js +177 -0
  140. package/src/compat/map/factory.js +45 -0
  141. package/src/compat/map/form.js +330 -0
  142. package/src/compat/map/helpers.js +46 -0
  143. package/src/compat/map/http.js +117 -0
  144. package/src/compat/map/layout.js +256 -0
  145. package/src/compat/map/options.js +267 -0
  146. package/src/compat/map/select.js +198 -0
  147. package/src/compat/map/stubs.js +26 -0
  148. package/src/compat/map/utilities.js +113 -0
  149. package/src/compat-entry.js +11 -0
  150. package/src/components/badge/badge.css +147 -0
  151. package/src/components/badge/badge.js +92 -0
  152. package/src/components/breadcrumb/breadcrumb.css +105 -0
  153. package/src/components/breadcrumb/breadcrumb.js +331 -0
  154. package/src/components/button/button.css +104 -0
  155. package/src/components/button/button.js +76 -0
  156. package/src/components/check-button/check-button.css +66 -0
  157. package/src/components/check-button/check-button.js +167 -0
  158. package/src/components/checklist/checklist.css +65 -0
  159. package/src/components/checklist/checklist.js +282 -0
  160. package/src/components/checklist/field-adapter.js +46 -0
  161. package/src/components/context-menu/context-menu.css +54 -0
  162. package/src/components/context-menu/context-menu.js +334 -0
  163. package/src/components/copy/copy-button.css +27 -0
  164. package/src/components/copy/copy-button.js +78 -0
  165. package/src/components/copy/copy-input.css +59 -0
  166. package/src/components/copy/copy-input.js +123 -0
  167. package/src/components/data-filter/data-filter.css +53 -0
  168. package/src/components/data-filter/data-filter.js +400 -0
  169. package/src/components/data-filter/filter-core.js +128 -0
  170. package/src/components/date-picker/date-picker.css +181 -0
  171. package/src/components/date-picker/date-picker.js +500 -0
  172. package/src/components/date-picker/date-range-picker.css +264 -0
  173. package/src/components/date-picker/date-range-picker.js +990 -0
  174. package/src/components/date-picker/field-adapter.js +36 -0
  175. package/src/components/date-picker/month-picker.js +223 -0
  176. package/src/components/date-picker/range-field-adapter.js +31 -0
  177. package/src/components/date-picker/time-picker.css +191 -0
  178. package/src/components/date-picker/time-picker.js +406 -0
  179. package/src/components/datebox/date-range-box.css +128 -0
  180. package/src/components/datebox/date-range-box.js +492 -0
  181. package/src/components/datebox/datebox.css +108 -0
  182. package/src/components/datebox/datebox.js +358 -0
  183. package/src/components/datebox/field-adapter.js +34 -0
  184. package/src/components/dialog/dialog.css +74 -0
  185. package/src/components/dialog/dialog.js +450 -0
  186. package/src/components/dropdown/dropdown.css +24 -0
  187. package/src/components/dropdown/dropdown.js +288 -0
  188. package/src/components/empty-state/empty-state.css +80 -0
  189. package/src/components/empty-state/empty-state.js +92 -0
  190. package/src/components/field/field.css +127 -0
  191. package/src/components/field/field.js +605 -0
  192. package/src/components/field-upload/field-adapter.js +21 -0
  193. package/src/components/field-upload/field-upload.css +108 -0
  194. package/src/components/field-upload/field-upload.js +475 -0
  195. package/src/components/fieldset/fieldset.css +37 -0
  196. package/src/components/fieldset/fieldset.js +307 -0
  197. package/src/components/finder/finder.css +98 -0
  198. package/src/components/finder/finder.js +509 -0
  199. package/src/components/form/form.css +32 -0
  200. package/src/components/form/form.js +302 -0
  201. package/src/components/groupbox/groupbox.css +51 -0
  202. package/src/components/groupbox/groupbox.js +199 -0
  203. package/src/components/layout/layout.css +117 -0
  204. package/src/components/layout/layout.js +136 -0
  205. package/src/components/loading/inline-loading.css +34 -0
  206. package/src/components/loading/inline-loading.js +140 -0
  207. package/src/components/loading/progress-bar.css +115 -0
  208. package/src/components/loading/progress-bar.js +259 -0
  209. package/src/components/loading/spinner.css +58 -0
  210. package/src/components/loading/spinner.js +57 -0
  211. package/src/components/master-panel/master-panel.css +51 -0
  212. package/src/components/master-panel/master-panel.js +203 -0
  213. package/src/components/menu-button/menu-button.css +49 -0
  214. package/src/components/menu-button/menu-button.js +294 -0
  215. package/src/components/message/message.css +122 -0
  216. package/src/components/message/message.js +499 -0
  217. package/src/components/modal/modal.css +47 -0
  218. package/src/components/modal/modal.js +203 -0
  219. package/src/components/multi-value-editor/field-adapter.js +44 -0
  220. package/src/components/multi-value-editor/multi-value-editor.css +56 -0
  221. package/src/components/multi-value-editor/multi-value-editor.js +170 -0
  222. package/src/components/navigation-bar/navigation-bar.css +130 -0
  223. package/src/components/navigation-bar/navigation-bar.js +450 -0
  224. package/src/components/number-field/field-adapter.js +40 -0
  225. package/src/components/number-field/number-field.css +77 -0
  226. package/src/components/number-field/number-field.js +545 -0
  227. package/src/components/pagination/pagination.css +95 -0
  228. package/src/components/pagination/pagination.js +481 -0
  229. package/src/components/panel/panel.css +123 -0
  230. package/src/components/panel/panel.js +336 -0
  231. package/src/components/permission/permission.css +47 -0
  232. package/src/components/permission/permission.js +198 -0
  233. package/src/components/rating/field-adapter.js +34 -0
  234. package/src/components/rating/rating.css +97 -0
  235. package/src/components/rating/rating.js +395 -0
  236. package/src/components/search/search.css +70 -0
  237. package/src/components/search/search.js +193 -0
  238. package/src/components/select/field-adapter.js +24 -0
  239. package/src/components/select/filter.js +39 -0
  240. package/src/components/select/select.css +180 -0
  241. package/src/components/select/select.js +663 -0
  242. package/src/components/skeleton/skeleton.css +76 -0
  243. package/src/components/skeleton/skeleton.js +139 -0
  244. package/src/components/slider/field-adapter.js +36 -0
  245. package/src/components/slider/slider.css +181 -0
  246. package/src/components/slider/slider.js +399 -0
  247. package/src/components/split-view/split-view.css +139 -0
  248. package/src/components/split-view/split-view.js +806 -0
  249. package/src/components/stepper/stepper.css +234 -0
  250. package/src/components/stepper/stepper.js +459 -0
  251. package/src/components/stepper/steps.js +131 -0
  252. package/src/components/tabbox/tabbox.css +281 -0
  253. package/src/components/tabbox/tabbox.js +484 -0
  254. package/src/components/table/sort.js +85 -0
  255. package/src/components/table/table.css +364 -0
  256. package/src/components/table/table.js +1711 -0
  257. package/src/components/tag-picker/field-adapter.js +35 -0
  258. package/src/components/tag-picker/tag-picker.css +169 -0
  259. package/src/components/tag-picker/tag-picker.js +837 -0
  260. package/src/components/timebox/field-adapter.js +24 -0
  261. package/src/components/timebox/timebox.css +51 -0
  262. package/src/components/timebox/timebox.js +276 -0
  263. package/src/components/toggle/field-adapter.js +24 -0
  264. package/src/components/toggle/toggle.css +66 -0
  265. package/src/components/toggle/toggle.js +150 -0
  266. package/src/components/toolbar/toolbar.css +81 -0
  267. package/src/components/toolbar/toolbar.js +511 -0
  268. package/src/components/tooltip/tooltip.css +36 -0
  269. package/src/components/tooltip/tooltip.js +420 -0
  270. package/src/components/tree/hierarchy.js +151 -0
  271. package/src/components/tree/tree.css +99 -0
  272. package/src/components/tree/tree.js +784 -0
  273. package/src/components/truncate/truncate.css +20 -0
  274. package/src/components/truncate/truncate.js +92 -0
  275. package/src/components/value-list/field-adapter.js +24 -0
  276. package/src/components/value-list/value-list.css +108 -0
  277. package/src/components/value-list/value-list.js +336 -0
  278. package/src/core/breakpoint.js +150 -0
  279. package/src/core/component.js +292 -0
  280. package/src/core/date.js +216 -0
  281. package/src/core/dom.js +260 -0
  282. package/src/core/export.js +204 -0
  283. package/src/core/fontawesome.js +177 -0
  284. package/src/core/format.js +283 -0
  285. package/src/core/http.js +246 -0
  286. package/src/core/i18n.js +83 -0
  287. package/src/core/icons.js +283 -0
  288. package/src/core/keyboard.js +240 -0
  289. package/src/core/position.js +177 -0
  290. package/src/core/storage.js +175 -0
  291. package/src/core/util.js +336 -0
  292. package/src/elements/define.js +715 -0
  293. package/src/elements/reflect.js +79 -0
  294. package/src/index.js +131 -0
  295. package/src/zeyos/connect.js +142 -0
  296. package/src/zeyos/form.js +254 -0
  297. package/src/zeyos/icons.js +92 -0
  298. package/src/zeyos/index.js +21 -0
  299. package/src/zeyos/modules.js +269 -0
  300. package/src/zeyos/query.js +199 -0
  301. package/src/zeyos/schema.js +474 -0
  302. package/src/zeyos/select.js +175 -0
  303. package/src/zeyos/table.js +272 -0
  304. package/styles/base.css +124 -0
  305. package/styles/icons.css +34 -0
  306. package/styles/tokens/dark.css +84 -0
  307. package/styles/tokens/density.css +9 -0
  308. package/styles/tokens/global.css +80 -0
  309. package/styles/tokens/modules.css +109 -0
  310. package/styles/tokens/semantic.css +49 -0
  311. package/styles/zx.css +61 -0
package/dist/zx.esm.js CHANGED
@@ -70,7 +70,8 @@ function deepMerge(a, b) {
70
70
  );
71
71
  }
72
72
  function isElement(value) {
73
- return Boolean(value && typeof value === "object" && value.nodeType === 1);
73
+ return Boolean(value && typeof value === "object" && /** @type {{nodeType?: unknown}} */
74
+ value.nodeType === 1);
74
75
  }
75
76
  function clamp(n, min, max) {
76
77
  return Math.min(max, Math.max(min, n));
@@ -78,11 +79,15 @@ function clamp(n, min, max) {
78
79
  function toArray(value) {
79
80
  if (value == null) return [];
80
81
  if (Array.isArray(value)) return value.slice();
81
- if (typeof value !== "string" && typeof value[Symbol.iterator] === "function") {
82
- return Array.from(value);
82
+ const candidate = (
83
+ /** @type {any} */
84
+ value
85
+ );
86
+ if (typeof value !== "string" && typeof candidate?.[Symbol.iterator] === "function") {
87
+ return Array.from(candidate);
83
88
  }
84
- if (typeof value !== "string" && typeof value.length === "number") {
85
- return Array.from(value);
89
+ if (typeof value !== "string" && typeof candidate?.length === "number") {
90
+ return Array.from(candidate);
86
91
  }
87
92
  return [
88
93
  /** @type {T} */
@@ -291,8 +296,12 @@ function resolveElement(target) {
291
296
  }
292
297
  function isPropsObject(value) {
293
298
  if (value === null || typeof value !== "object" || Array.isArray(value)) return false;
294
- if (typeof value.nodeType === "number") return false;
295
- return typeof value.toElement !== "function";
299
+ const candidate = (
300
+ /** @type {Record<string, unknown>} */
301
+ value
302
+ );
303
+ if (typeof candidate.nodeType === "number") return false;
304
+ return typeof candidate.toElement !== "function";
296
305
  }
297
306
  function applyProperty(element, key, value) {
298
307
  if (key === "ref") {
@@ -350,15 +359,33 @@ function ariaAttribute(key) {
350
359
  return "aria-" + key.slice(4).toLowerCase();
351
360
  }
352
361
  function appendChildren(parent, children) {
353
- for (const child of children.flat(Infinity)) {
354
- if (child == null) continue;
355
- if (typeof child === "string" || typeof child === "number") {
356
- parent.append(document.createTextNode(String(child)));
357
- } else if (child && typeof child === "object" && typeof child.nodeType === "number") {
358
- parent.append(child);
359
- } else if (typeof child === "object" && typeof child.toElement === "function") {
362
+ const host = (
363
+ /** @type {ParentNode} */
364
+ parent
365
+ );
366
+ for (
367
+ const raw2 of
368
+ /** @type {any[]} */
369
+ children.flat(Infinity)
370
+ ) {
371
+ if (raw2 == null) continue;
372
+ if (typeof raw2 === "string" || typeof raw2 === "number") {
373
+ host.append(document.createTextNode(String(raw2)));
374
+ continue;
375
+ }
376
+ if (typeof raw2 !== "object") continue;
377
+ const child = (
378
+ /** @type {{nodeType?: number, toElement?: () => Node|null}} */
379
+ raw2
380
+ );
381
+ if (typeof child.nodeType === "number") {
382
+ host.append(
383
+ /** @type {Node} */
384
+ raw2
385
+ );
386
+ } else if (typeof child.toElement === "function") {
360
387
  const element = child.toElement();
361
- if (element) parent.append(element);
388
+ if (element) host.append(element);
362
389
  }
363
390
  }
364
391
  }
@@ -413,11 +440,18 @@ var registry = /* @__PURE__ */ new WeakMap();
413
440
  var Component = class extends EventTarget {
414
441
  /** @type {ComponentOptions} */
415
442
  static defaults = {};
443
+ /**
444
+ * BEM block a subclass wants on its root, without the `zx-` prefix. Empty on the base, which is
445
+ * the same falsy answer the undeclared property gave — declared so the statics are visible to
446
+ * `this.constructor` and to the generated declarations.
447
+ * @type {string}
448
+ */
449
+ static cssName = "";
416
450
  /** @type {Element} Root element. */
417
451
  el;
418
452
  /** @type {Record<string, Element>} Elements captured by `h()` ref properties. */
419
453
  refs;
420
- /** @type {Readonly<ComponentOptions>} Merged component options. */
454
+ /** @type {Readonly<TOptions>} Merged component options. */
421
455
  options;
422
456
  #abort = new AbortController();
423
457
  #created = false;
@@ -426,17 +460,27 @@ var Component = class extends EventTarget {
426
460
  /**
427
461
  * Creates a component around an existing target, or asks `render()` to create its root.
428
462
  * @param {Element|string|null} target Existing element, selector, or null.
429
- * @param {ComponentOptions} [options={}] Component options.
463
+ * @param {TOptions} [options={}] Component options.
430
464
  */
431
- constructor(target, options = {}) {
465
+ constructor(target, options = (
466
+ /** @type {TOptions} */
467
+ {}
468
+ )) {
432
469
  super();
470
+ const self = (
471
+ /** @type {typeof Component} */
472
+ this.constructor
473
+ );
433
474
  this.#created = target === null;
434
475
  const resolved = resolveElement(target);
435
476
  if (target !== null && !resolved) throw new TypeError("Component target could not be resolved");
436
477
  this.el = /** @type {Element} */
437
478
  resolved;
438
479
  this.refs = {};
439
- const merged = mergeOptions(this.constructor, options);
480
+ const merged = (
481
+ /** @type {TOptions} */
482
+ mergeOptions(self, options)
483
+ );
440
484
  const eventOptions = [];
441
485
  for (const [key, value] of Object.entries(merged)) {
442
486
  if (/^on[a-z]/.test(key) && typeof value === "function") {
@@ -466,7 +510,7 @@ var Component = class extends EventTarget {
466
510
  this.#abort.abort();
467
511
  throw new TypeError("Component requires a root Element");
468
512
  }
469
- const cssName = this.constructor.cssName;
513
+ const cssName = self.cssName;
470
514
  if (typeof cssName === "string" && cssName) {
471
515
  const className = `zx-${cssName}`;
472
516
  this.#addedRootClass = !this.el.classList.contains(className);
@@ -587,7 +631,10 @@ var Component = class extends EventTarget {
587
631
  this.#destroyed = true;
588
632
  this.#abort.abort();
589
633
  if (registry.get(this.el) === this) registry.delete(this.el);
590
- const cssName = this.constructor.cssName;
634
+ const cssName = (
635
+ /** @type {typeof Component} */
636
+ this.constructor.cssName
637
+ );
591
638
  if (this.#addedRootClass && typeof cssName === "string" && this.el) {
592
639
  this.el.classList.remove(`zx-${cssName}`);
593
640
  }
@@ -1571,7 +1618,10 @@ function getWeekStart(lang = getLanguage()) {
1571
1618
  if (!lang) return 1;
1572
1619
  if (lang.toLowerCase() === "en") return 1;
1573
1620
  try {
1574
- const locale = new Intl.Locale(lang);
1621
+ const locale = (
1622
+ /** @type {Intl.Locale & {getWeekInfo?: () => {firstDay?: number}, weekInfo?: {firstDay?: number}}} */
1623
+ new Intl.Locale(lang)
1624
+ );
1575
1625
  const weekInfo = locale.getWeekInfo?.() ?? locale.weekInfo;
1576
1626
  if (weekInfo?.firstDay) return weekInfo.firstDay % 7;
1577
1627
  } catch {
@@ -1699,25 +1749,28 @@ function loadFontAwesomeKit(kit) {
1699
1749
  const url = kitUrl(kit);
1700
1750
  const pending = kitLoads.get(url);
1701
1751
  if (pending) return pending;
1702
- const promise = new Promise((resolve, reject) => {
1703
- const absolute = new URL(url, document.baseURI).href;
1704
- const existing = [...document.scripts].find((script2) => script2.src === absolute);
1705
- if (existing && globalThis.FontAwesomeKitConfig) {
1706
- resolve();
1707
- return;
1708
- }
1709
- const script = existing ?? document.createElement("script");
1710
- script.addEventListener("load", () => resolve(), { once: true });
1711
- script.addEventListener("error", () => {
1712
- kitLoads.delete(url);
1713
- reject(new Error(`Font Awesome kit failed to load: ${url}`));
1714
- }, { once: true });
1715
- if (existing) return;
1716
- script.src = url;
1717
- script.async = true;
1718
- script.crossOrigin = "anonymous";
1719
- document.head.append(script);
1720
- });
1752
+ const promise = (
1753
+ /** @type {Promise<void>} */
1754
+ new Promise((resolve, reject) => {
1755
+ const absolute = new URL(url, document.baseURI).href;
1756
+ const existing = [...document.scripts].find((script2) => script2.src === absolute);
1757
+ if (existing && globalThis.FontAwesomeKitConfig) {
1758
+ resolve();
1759
+ return;
1760
+ }
1761
+ const script = existing ?? document.createElement("script");
1762
+ script.addEventListener("load", () => resolve(), { once: true });
1763
+ script.addEventListener("error", () => {
1764
+ kitLoads.delete(url);
1765
+ reject(new Error(`Font Awesome kit failed to load: ${url}`));
1766
+ }, { once: true });
1767
+ if (existing) return;
1768
+ script.src = url;
1769
+ script.async = true;
1770
+ script.crossOrigin = "anonymous";
1771
+ document.head.append(script);
1772
+ })
1773
+ );
1721
1774
  kitLoads.set(url, promise);
1722
1775
  return promise;
1723
1776
  }
@@ -2974,9 +3027,11 @@ function updateFallback(anchor, floating, { placement, offset, flip, matchWidth
2974
3027
  const topY = anchorRect.top - offset - floatingRect.height;
2975
3028
  if (flip) {
2976
3029
  if (prefersBottom && bottomY + floatingRect.height > viewportHeight && topY >= 0) {
2977
- actualPlacement = placement.replace("bottom", "top");
3030
+ actualPlacement = /** @type {typeof placement} */
3031
+ placement.replace("bottom", "top");
2978
3032
  } else if (!prefersBottom && topY < 0 && bottomY + floatingRect.height <= viewportHeight) {
2979
- actualPlacement = placement.replace("top", "bottom");
3033
+ actualPlacement = /** @type {typeof placement} */
3034
+ placement.replace("top", "bottom");
2980
3035
  }
2981
3036
  }
2982
3037
  let left;
@@ -5989,10 +6044,13 @@ function rovingTabindex(container, itemSelector, { orientation = "vertical", wra
5989
6044
  const originals = /* @__PURE__ */ new Map();
5990
6045
  let destroyed = false;
5991
6046
  function items() {
5992
- return Array.from(container.querySelectorAll(itemSelector)).filter((item) => {
5993
- remember(item);
5994
- return isAvailable(item);
5995
- });
6047
+ return (
6048
+ /** @type {HTMLElement[]} */
6049
+ Array.from(container.querySelectorAll(itemSelector)).filter((item) => {
6050
+ remember(item);
6051
+ return isAvailable(item);
6052
+ })
6053
+ );
5996
6054
  }
5997
6055
  function remember(item) {
5998
6056
  if (!originals.has(item)) originals.set(item, item.getAttribute("tabindex"));
@@ -6007,7 +6065,11 @@ function rovingTabindex(container, itemSelector, { orientation = "vertical", wra
6007
6065
  }
6008
6066
  function onKeydown(event) {
6009
6067
  const available = items();
6010
- const current = event.target?.closest?.(itemSelector);
6068
+ const current = (
6069
+ /** @type {HTMLElement|null} */
6070
+ /** @type {Element|null} */
6071
+ event.target?.closest?.(itemSelector) ?? null
6072
+ );
6011
6073
  const index = available.indexOf(current);
6012
6074
  if (index < 0) return;
6013
6075
  const previousKey = orientation === "horizontal" ? "ArrowLeft" : "ArrowUp";
@@ -6025,7 +6087,11 @@ function rovingTabindex(container, itemSelector, { orientation = "vertical", wra
6025
6087
  available[nextIndex].focus();
6026
6088
  }
6027
6089
  function onFocus(event) {
6028
- const item = event.target?.closest?.(itemSelector);
6090
+ const item = (
6091
+ /** @type {HTMLElement|null} */
6092
+ /** @type {Element|null} */
6093
+ event.target?.closest?.(itemSelector) ?? null
6094
+ );
6029
6095
  if (item && container.contains(item)) update(item);
6030
6096
  }
6031
6097
  container.addEventListener("keydown", onKeydown, { signal: controller.signal });
@@ -6085,8 +6151,9 @@ function typeahead(getItems, onMatch) {
6085
6151
  };
6086
6152
  }
6087
6153
  function focusableItems(container) {
6088
- return Array.from(container.querySelectorAll(FOCUSABLE_SELECTOR)).filter(
6089
- (item) => isAvailable(item) && item.getClientRects().length > 0
6154
+ return (
6155
+ /** @type {HTMLElement[]} */
6156
+ Array.from(container.querySelectorAll(FOCUSABLE_SELECTOR)).filter((item) => isAvailable(item) && item.getClientRects().length > 0)
6090
6157
  );
6091
6158
  }
6092
6159
  function isAvailable(item) {
@@ -6100,7 +6167,11 @@ function itemText(item) {
6100
6167
  return String(item.textContent ?? "").trim().toLocaleLowerCase();
6101
6168
  }
6102
6169
  if (item && typeof item === "object") {
6103
- const value = item.label ?? item.text ?? item.value;
6170
+ const shape = (
6171
+ /** @type {{label?: unknown, text?: unknown, value?: unknown}} */
6172
+ item
6173
+ );
6174
+ const value = shape.label ?? shape.text ?? shape.value;
6104
6175
  if (value != null) return String(value).trim().toLocaleLowerCase();
6105
6176
  }
6106
6177
  return String(item ?? "").trim().toLocaleLowerCase();
@@ -8583,11 +8654,19 @@ function matchBreakpoint(name, width) {
8583
8654
  }
8584
8655
  function onBreakpoint(handler, options = {}) {
8585
8656
  if (typeof handler !== "function") throw new TypeError("onBreakpoint requires a handler");
8657
+ if ("target" in options && !isElement(options.target) && /** @type {unknown} */
8658
+ options.target !== /** @type {unknown} */
8659
+ globalThis) {
8660
+ throw new TypeError("onBreakpoint target must be an Element or the window");
8661
+ }
8586
8662
  const target = options.target ?? globalThis;
8587
- const element = target instanceof Element ? target : null;
8663
+ const element = isElement(target) ? (
8664
+ /** @type {Element} */
8665
+ target
8666
+ ) : null;
8588
8667
  let name = (
8589
- /** @type {BreakpointName} */
8590
- "xs"
8668
+ /** @type {BreakpointName|null} */
8669
+ null
8591
8670
  );
8592
8671
  let destroyed = false;
8593
8672
  let observer = null;
@@ -8595,24 +8674,33 @@ function onBreakpoint(handler, options = {}) {
8595
8674
  const update = () => {
8596
8675
  if (destroyed) return;
8597
8676
  const width = measure();
8677
+ if (element && width === 0) return;
8598
8678
  const next = breakpointOf(width);
8599
8679
  if (next === name) return;
8600
8680
  name = next;
8601
8681
  handler(name, width);
8602
8682
  };
8603
- name = breakpointOf(measure());
8604
- handler(name, measure());
8683
+ update();
8684
+ let frame = 0;
8685
+ const schedule = () => {
8686
+ if (frame || destroyed) return;
8687
+ frame = requestAnimationFrame(() => {
8688
+ frame = 0;
8689
+ update();
8690
+ });
8691
+ };
8605
8692
  if (element && typeof ResizeObserver === "function") {
8606
- observer = new ResizeObserver(update);
8693
+ observer = new ResizeObserver(schedule);
8607
8694
  observer.observe(element);
8608
8695
  } else {
8609
8696
  globalThis.addEventListener?.("resize", update, { passive: true });
8610
8697
  }
8611
8698
  return {
8612
- current: () => name,
8699
+ current: () => name ?? breakpointOf(measure()),
8613
8700
  destroy: () => {
8614
8701
  if (destroyed) return;
8615
8702
  destroyed = true;
8703
+ if (frame) cancelAnimationFrame(frame);
8616
8704
  observer?.disconnect();
8617
8705
  globalThis.removeEventListener?.("resize", update);
8618
8706
  }
@@ -8679,7 +8767,10 @@ var Http = class {
8679
8767
  try {
8680
8768
  json2 = JSON.parse(text4);
8681
8769
  } catch (cause) {
8682
- const error = new Error("Invalid JSON response", { cause });
8770
+ const error = (
8771
+ /** @type {Error & {response?: Response}} */
8772
+ new Error("Invalid JSON response", { cause })
8773
+ );
8683
8774
  error.response = response;
8684
8775
  throw error;
8685
8776
  }
@@ -8691,7 +8782,10 @@ var Http = class {
8691
8782
  error2.response = response;
8692
8783
  throw error2;
8693
8784
  }
8694
- const error = new Error(`HTTP ${response.status} ${response.statusText}`.trim());
8785
+ const error = (
8786
+ /** @type {Error & {response?: Response}} */
8787
+ new Error(`HTTP ${response.status} ${response.statusText}`.trim())
8788
+ );
8695
8789
  error.response = response;
8696
8790
  throw error;
8697
8791
  }
@@ -8799,7 +8893,10 @@ function appendFormValue2(form, key, value) {
8799
8893
  for (const item of value) appendFormValue2(form, key, item);
8800
8894
  } else {
8801
8895
  const isBlob = typeof Blob === "function" && value instanceof Blob;
8802
- form.append(key, typeof value === "object" && !isBlob ? JSON.stringify(value) : value);
8896
+ form.append(key, typeof value === "object" && !isBlob ? JSON.stringify(value) : (
8897
+ /** @type {string|Blob} */
8898
+ value
8899
+ ));
8803
8900
  }
8804
8901
  }
8805
8902
  function isFileList(value) {
@@ -8872,7 +8969,11 @@ function formatRelativeTime(date, options = {}) {
8872
8969
  const diff = target.getTime() - reference.getTime();
8873
8970
  const division = TIME_DIVISIONS.find(({ ms, limit }) => Math.abs(diff) / ms < limit) ?? TIME_DIVISIONS[TIME_DIVISIONS.length - 1];
8874
8971
  const value = Math.round(diff / division.ms);
8875
- return relativeFormatter(locale, numeric).format(value, division.unit);
8972
+ return relativeFormatter(locale, numeric).format(
8973
+ value,
8974
+ /** @type {Intl.RelativeTimeFormatUnit} */
8975
+ division.unit
8976
+ );
8876
8977
  }
8877
8978
  function format(locale, options, value) {
8878
8979
  const key = `${locale}\0${JSON.stringify(options)}`;
@@ -9176,7 +9277,10 @@ function escapeField(field, delimiter, guard = false) {
9176
9277
  }
9177
9278
  function toBlob(data, type) {
9178
9279
  if (typeof Blob === "function" && data instanceof Blob) return data;
9179
- const parts = typeof data === "string" && /^text\/csv\b/i.test(type) ? ["\uFEFF", data] : [data];
9280
+ const parts = (
9281
+ /** @type {BlobPart[]} */
9282
+ typeof data === "string" && /^text\/csv\b/i.test(type) ? ["\uFEFF", data] : [data]
9283
+ );
9180
9284
  return new Blob(parts, { type });
9181
9285
  }
9182
9286
 
@@ -10565,6 +10669,8 @@ var Table = class extends Component {
10565
10669
  sortMode: "local",
10566
10670
  selectable: false,
10567
10671
  stickyHeader: true,
10672
+ responsive: false,
10673
+ growing: false,
10568
10674
  height: null,
10569
10675
  emptyText: null,
10570
10676
  rowClass: null,
@@ -10585,6 +10691,7 @@ var Table = class extends Component {
10585
10691
  /** @type {HTMLElement} */
10586
10692
  this.el ?? h("div")
10587
10693
  );
10694
+ this.el = root;
10588
10695
  this._originalChildren = this.el ? Array.from(this.el.childNodes) : null;
10589
10696
  this._columns = Array.isArray(this.options.columns) ? this.options.columns.map((column) => ({ ...column })) : [];
10590
10697
  this._data = Array.isArray(this.options.data) ? [...this.options.data] : [];
@@ -10597,6 +10704,11 @@ var Table = class extends Component {
10597
10704
  this._editMode = normalizeEditMode(this.options.editMode);
10598
10705
  this._edit = null;
10599
10706
  this._editMessage = null;
10707
+ this._stacked = false;
10708
+ this._width = null;
10709
+ this._growStep = growStep(this.options.growing);
10710
+ this._rendered = this._growStep ?? Infinity;
10711
+ this._more = null;
10600
10712
  this._rovingKey = null;
10601
10713
  this._rovingCell = null;
10602
10714
  this._rovingMatched = false;
@@ -10631,6 +10743,7 @@ var Table = class extends Component {
10631
10743
  this._renderColumns();
10632
10744
  this._renderHeader();
10633
10745
  this._renderBody();
10746
+ this._watchWidth();
10634
10747
  this.listen(this._tbody, "click", (event) => this._handleBodyClick(event));
10635
10748
  this.listen(this._tbody, "dblclick", (event) => this._handleBodyDoubleClick(event));
10636
10749
  if (this._editMode !== false) {
@@ -10664,6 +10777,7 @@ var Table = class extends Component {
10664
10777
  * @fires Table#editcancel
10665
10778
  */
10666
10779
  setData(rows) {
10780
+ this._rendered = this._growStep ?? Infinity;
10667
10781
  this.setLoading(false);
10668
10782
  assertRows(rows);
10669
10783
  this._data = [...rows];
@@ -10938,9 +11052,150 @@ var Table = class extends Component {
10938
11052
  getEditing() {
10939
11053
  return this._edit ? { id: this._edit.id, columnId: this._edit.columnId } : null;
10940
11054
  }
11055
+ /**
11056
+ * The rows currently rendered — all of them unless `growing` is on.
11057
+ * @returns {TableRow[]}
11058
+ */
11059
+ _visibleData() {
11060
+ return this._rendered === Infinity ? this._data : this._data.slice(0, this._rendered);
11061
+ }
11062
+ /**
11063
+ * Renders the next batch of rows.
11064
+ * @param {number} [count] How many to add; defaults to the configured batch size.
11065
+ * @returns {this}
11066
+ * @fires Table#grow
11067
+ */
11068
+ growBy(count2) {
11069
+ if (!this._growStep) return this;
11070
+ const step = Number(count2) > 0 ? Math.trunc(Number(count2)) : this._growStep;
11071
+ const before = this._rendered;
11072
+ this._rendered = Math.min(this._data.length, this._rendered + step);
11073
+ if (this._rendered === before) return this;
11074
+ this._renderBody();
11075
+ this.emit("grow", { rendered: this._rendered, total: this._data.length });
11076
+ return this;
11077
+ }
11078
+ /**
11079
+ * Renders every remaining row.
11080
+ * @returns {this}
11081
+ * @fires Table#grow
11082
+ */
11083
+ showAll() {
11084
+ return this.growBy(this._data.length);
11085
+ }
11086
+ /**
11087
+ * How many rows are currently rendered.
11088
+ * @returns {number}
11089
+ */
11090
+ getRenderedCount() {
11091
+ return Math.min(this._rendered, this._data.length);
11092
+ }
11093
+ /**
11094
+ * Keeps the "show more" control in step with what is rendered.
11095
+ *
11096
+ * The control sits outside the table rather than in a `<tfoot>` row spanning every column: it is
11097
+ * a command, not data, and a button inside the grid would be reachable by the row navigation
11098
+ * keys as though it were a cell.
11099
+ * @returns {void}
11100
+ */
11101
+ _syncGrowing() {
11102
+ if (!this._growStep) return;
11103
+ const remaining = this._data.length - this.getRenderedCount();
11104
+ if (remaining <= 0) {
11105
+ this._more?.remove();
11106
+ this._more = null;
11107
+ return;
11108
+ }
11109
+ const label = this._message("table.more", "Show %1 more", [remaining]);
11110
+ if (!this._more) {
11111
+ this._more = h("button", {
11112
+ class: "zx-table__more",
11113
+ type: "button",
11114
+ onclick: () => this.growBy()
11115
+ });
11116
+ this.el.append(this._more);
11117
+ }
11118
+ this._more.textContent = label;
11119
+ this._more.setAttribute("aria-label", label);
11120
+ }
11121
+ /**
11122
+ * Resolves a localized message, falling back to a built-in template.
11123
+ * @param {string} key Message key.
11124
+ * @param {string} fallback Template used when the host has no translation.
11125
+ * @param {unknown[]} args Positional interpolation values.
11126
+ * @returns {string}
11127
+ */
11128
+ _message(key, fallback, args) {
11129
+ const message = this.msg(key, ...args);
11130
+ return message === key ? printf(fallback, args) : message;
11131
+ }
11132
+ /**
11133
+ * Watches the table's own width and stacks the rows below `responsive`.
11134
+ *
11135
+ * The width comes from `onBreakpoint` observing this element rather than the window, which is the
11136
+ * whole point of the option: a table inside a split pane or a modal has no idea how wide the
11137
+ * viewport is, and a media query would stack it on a phone while leaving it unreadable in a
11138
+ * 320px pane on a desktop.
11139
+ * @returns {void}
11140
+ */
11141
+ _watchWidth() {
11142
+ this._width?.destroy();
11143
+ this._width = null;
11144
+ const threshold = this.options.responsive;
11145
+ if (!threshold || !(threshold in breakpoints)) return;
11146
+ this._width = onBreakpoint(
11147
+ (_name, width) => this._setStacked(width > 0 && width < breakpoints[threshold]),
11148
+ { target: this.el }
11149
+ );
11150
+ }
11151
+ /**
11152
+ * Enters or leaves stacked mode.
11153
+ * @param {boolean} stacked Whether rows should stack.
11154
+ * @returns {void}
11155
+ * @fires Table#stackedchange
11156
+ */
11157
+ _setStacked(stacked) {
11158
+ if (this._stacked === stacked) return;
11159
+ this._stacked = stacked;
11160
+ this.el.toggleAttribute("data-stacked", stacked);
11161
+ this._applyStackedRoles(stacked);
11162
+ this.emit("stackedchange", { stacked });
11163
+ }
11164
+ /**
11165
+ * States the table roles explicitly while stacked, and removes them again on the way out.
11166
+ *
11167
+ * Stacking works by changing `display` on the table elements, and a table whose display is not
11168
+ * `table` loses its implicit ARIA roles — leaving a screen reader with a pile of generic blocks
11169
+ * where a table used to be. The roles are only asserted while the layout has taken them away.
11170
+ * @param {boolean} stacked Whether the roles should be present.
11171
+ * @returns {void}
11172
+ */
11173
+ _applyStackedRoles(stacked) {
11174
+ const parts = [[this._table, "table"], [this._thead, "rowgroup"], [this._tbody, "rowgroup"]];
11175
+ for (const [element, role] of parts) {
11176
+ if (!element) continue;
11177
+ if (stacked) element.setAttribute("role", role);
11178
+ else element.removeAttribute("role");
11179
+ }
11180
+ for (const [selector, role] of [["tr", "row"], ["td", "cell"], ["th", "columnheader"]]) {
11181
+ for (const element of this._table.querySelectorAll(selector)) {
11182
+ if (stacked) element.setAttribute("role", role);
11183
+ else element.removeAttribute("role");
11184
+ }
11185
+ }
11186
+ }
11187
+ /**
11188
+ * Reports whether the rows are currently stacked.
11189
+ * @returns {boolean}
11190
+ */
11191
+ isStacked() {
11192
+ return Boolean(this._stacked);
11193
+ }
10941
11194
  /** Restores an enhanced target and releases all component listeners. @returns {void} */
10942
11195
  destroy() {
10943
11196
  this._teardownEdit();
11197
+ this._width?.destroy();
11198
+ this._width = null;
10944
11199
  if (this.el) delete this.el.dataset.editMode;
10945
11200
  if (!this._restored && this._originalChildren) {
10946
11201
  this.el.replaceChildren(...this._originalChildren);
@@ -10968,6 +11223,7 @@ var Table = class extends Component {
10968
11223
  /** @returns {void} */
10969
11224
  _renderHeader() {
10970
11225
  const row2 = h("tr", { class: "zx-table__header-row" });
11226
+ if (this._growStep) row2.setAttribute("aria-rowindex", "1");
10971
11227
  if (this.options.selectable === "multi") {
10972
11228
  this._selectAll = h("input", {
10973
11229
  class: "zx-table__checkbox zx-table__select-all",
@@ -10981,9 +11237,9 @@ var Table = class extends Component {
10981
11237
  row2.append(selectionHeader);
10982
11238
  this.listen(this._selectAll, "click", () => {
10983
11239
  if (this._selectAll.checked) {
10984
- for (const dataRow of this._data) this._selected.add(this._idFor(dataRow));
11240
+ for (const dataRow of this._visibleData()) this._selected.add(this._idFor(dataRow));
10985
11241
  } else {
10986
- this._selected.clear();
11242
+ for (const dataRow of this._visibleData()) this._selected.delete(this._idFor(dataRow));
10987
11243
  }
10988
11244
  this._selectionAnchorId = null;
10989
11245
  this._syncSelection();
@@ -11025,17 +11281,36 @@ var Table = class extends Component {
11025
11281
  this._rovingCell = null;
11026
11282
  this._rovingMatched = false;
11027
11283
  if (this._data.length === 0) {
11028
- const text4 = this.options.emptyText == null ? this.msg("table.empty") : String(this.options.emptyText);
11029
11284
  fragment.append(h(
11030
11285
  "tr",
11031
11286
  { class: "zx-table__empty-row" },
11032
- h("td", { class: "zx-table__empty", colspan: this._columns.length + (this.options.selectable === "multi" ? 1 : 0) }, text4)
11287
+ h("td", {
11288
+ class: "zx-table__empty",
11289
+ colspan: this._columns.length + (this.options.selectable === "multi" ? 1 : 0)
11290
+ }, this._emptyContent())
11033
11291
  ));
11034
11292
  } else {
11035
- this._data.forEach((row2, index) => fragment.append(this._createRow(row2, index)));
11293
+ this._visibleData().forEach((row2, index) => fragment.append(this._createRow(row2, index)));
11036
11294
  }
11037
11295
  this._tbody.replaceChildren(fragment);
11296
+ if (this._growStep) this._table.setAttribute("aria-rowcount", String(this._data.length + 1));
11038
11297
  this._syncSelectAll();
11298
+ this._syncGrowing();
11299
+ if (this._stacked) this._applyStackedRoles(true);
11300
+ }
11301
+ /**
11302
+ * What to put in the empty row.
11303
+ *
11304
+ * An empty table is a screen in its own right — the place to say why there is nothing and what to
11305
+ * do about it — so this takes a node as readily as a string. A function is re-called on every
11306
+ * render, which matters when the placeholder contains a button: reusing one node would move the
11307
+ * same element between renders and quietly share its listeners.
11308
+ * @returns {Node|string}
11309
+ */
11310
+ _emptyContent() {
11311
+ const empty = this.options.emptyText;
11312
+ if (empty == null) return this.msg("table.empty");
11313
+ return typeof empty === "function" ? empty() : empty;
11039
11314
  }
11040
11315
  /** @param {TableRow} row @param {number} index @returns {HTMLTableRowElement} */
11041
11316
  _createRow(row2, index) {
@@ -11044,6 +11319,7 @@ var Table = class extends Component {
11044
11319
  /** @type {HTMLTableRowElement} */
11045
11320
  h("tr", { dataset: { row: "" } })
11046
11321
  );
11322
+ if (this._growStep) tr.setAttribute("aria-rowindex", String(index + 2));
11047
11323
  const rowClass = typeof this.options.rowClass === "function" ? this.options.rowClass(row2) : "";
11048
11324
  if (rowClass) tr.classList.add(...String(rowClass).split(/\s+/).filter(Boolean));
11049
11325
  if (this.options.selectable !== false) tr.setAttribute("aria-selected", String(this._selected.has(id)));
@@ -11066,6 +11342,8 @@ var Table = class extends Component {
11066
11342
  h("td")
11067
11343
  );
11068
11344
  if (column.align) cell.dataset.align = column.align;
11345
+ cell.dataset.label = column.label;
11346
+ if (column.popin === false) cell.dataset.popin = "false";
11069
11347
  if (this._editMode !== false) {
11070
11348
  cell.dataset.column = column.id;
11071
11349
  if (resolveEditable(column, row2) !== false) {
@@ -11549,10 +11827,14 @@ var Table = class extends Component {
11549
11827
  /** @returns {void} */
11550
11828
  _syncSelectAll() {
11551
11829
  if (!this._selectAll) return;
11552
- const selectedRows = this._data.reduce((count2, row2) => count2 + Number(this._selected.has(this._idFor(row2))), 0);
11553
- this._selectAll.disabled = this._data.length === 0;
11554
- this._selectAll.checked = this._data.length > 0 && selectedRows === this._data.length;
11555
- this._selectAll.indeterminate = selectedRows > 0 && selectedRows < this._data.length;
11830
+ const visible = this._visibleData();
11831
+ const selectedRows = visible.reduce(
11832
+ (count2, row2) => count2 + Number(this._selected.has(this._idFor(row2))),
11833
+ 0
11834
+ );
11835
+ this._selectAll.disabled = visible.length === 0;
11836
+ this._selectAll.checked = visible.length > 0 && selectedRows === visible.length;
11837
+ this._selectAll.indeterminate = selectedRows > 0 && selectedRows < visible.length;
11556
11838
  }
11557
11839
  /** @returns {void} */
11558
11840
  _syncSortHeader() {
@@ -11684,6 +11966,10 @@ function assertRows(rows) {
11684
11966
  function sameSet(left, right) {
11685
11967
  return left.size === right.size && [...left].every((value) => right.has(value));
11686
11968
  }
11969
+ function growStep(growing) {
11970
+ const step = Math.trunc(Number(growing));
11971
+ return Number.isFinite(step) && step > 0 ? step : null;
11972
+ }
11687
11973
 
11688
11974
  // src/elements/reflect.js
11689
11975
  var INVALID_ATTRIBUTE = /* @__PURE__ */ Symbol("invalid attribute");