@vantageos/mosaic 0.3.0-alpha.1 → 0.3.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 (97) hide show
  1. package/CHANGELOG.md +145 -0
  2. package/README.md +12 -0
  3. package/dist/{Alert.schema-BQsZGG6P.d.cts → Alert.schema-LPJE5gFP.d.cts} +31 -1
  4. package/dist/{Alert.schema-BQsZGG6P.d.ts → Alert.schema-LPJE5gFP.d.ts} +31 -1
  5. package/dist/MarkdownRenderer.schema-Rx7kIeVA.d.cts +22 -0
  6. package/dist/MarkdownRenderer.schema-Rx7kIeVA.d.ts +22 -0
  7. package/dist/ProgressBar.schema-CdVYx0Wq.d.cts +22 -0
  8. package/dist/ProgressBar.schema-CdVYx0Wq.d.ts +22 -0
  9. package/dist/StatusBadge.schema-1tOjB4Ir.d.cts +22 -0
  10. package/dist/StatusBadge.schema-1tOjB4Ir.d.ts +22 -0
  11. package/dist/artifacts.cjs +126 -2
  12. package/dist/artifacts.cjs.map +1 -1
  13. package/dist/artifacts.d.cts +3 -21
  14. package/dist/artifacts.d.ts +3 -21
  15. package/dist/artifacts.js +126 -2
  16. package/dist/artifacts.js.map +1 -1
  17. package/dist/confirmation.cjs +126 -2
  18. package/dist/confirmation.cjs.map +1 -1
  19. package/dist/confirmation.d.cts +3 -32
  20. package/dist/confirmation.d.ts +3 -32
  21. package/dist/confirmation.js +126 -2
  22. package/dist/confirmation.js.map +1 -1
  23. package/dist/display.cjs +129 -2
  24. package/dist/display.cjs.map +1 -1
  25. package/dist/display.d.cts +132 -2
  26. package/dist/display.d.ts +132 -2
  27. package/dist/display.js +129 -2
  28. package/dist/display.js.map +1 -1
  29. package/dist/forms.cjs +20 -17
  30. package/dist/forms.cjs.map +1 -1
  31. package/dist/forms.js +20 -17
  32. package/dist/forms.js.map +1 -1
  33. package/dist/index.cjs +129 -2
  34. package/dist/index.cjs.map +1 -1
  35. package/dist/index.d.cts +9 -7
  36. package/dist/index.d.ts +9 -7
  37. package/dist/index.js +129 -2
  38. package/dist/index.js.map +1 -1
  39. package/dist/media.cjs +126 -2
  40. package/dist/media.cjs.map +1 -1
  41. package/dist/media.d.cts +3 -21
  42. package/dist/media.d.ts +3 -21
  43. package/dist/media.js +126 -2
  44. package/dist/media.js.map +1 -1
  45. package/dist/preact/artifacts.d.ts +39 -1
  46. package/dist/preact/artifacts.js +234 -0
  47. package/dist/preact/artifacts.js.map +1 -1
  48. package/dist/preact/confirmation.d.ts +31 -1
  49. package/dist/preact/confirmation.js +245 -5
  50. package/dist/preact/confirmation.js.map +1 -1
  51. package/dist/preact/display.d.ts +127 -1
  52. package/dist/preact/display.js +419 -11
  53. package/dist/preact/display.js.map +1 -1
  54. package/dist/preact/forms.js +22 -19
  55. package/dist/preact/forms.js.map +1 -1
  56. package/dist/preact/input.js +2 -2
  57. package/dist/preact/progress.d.ts +35 -1
  58. package/dist/preact/progress.js +263 -0
  59. package/dist/preact/progress.js.map +1 -1
  60. package/dist/progress.cjs +126 -2
  61. package/dist/progress.cjs.map +1 -1
  62. package/dist/progress.d.cts +3 -21
  63. package/dist/progress.d.ts +3 -21
  64. package/dist/progress.js +126 -2
  65. package/dist/progress.js.map +1 -1
  66. package/dist/react/artifacts.cjs +241 -0
  67. package/dist/react/artifacts.cjs.map +1 -1
  68. package/dist/react/artifacts.d.cts +20 -1
  69. package/dist/react/artifacts.d.ts +20 -1
  70. package/dist/react/artifacts.js +234 -0
  71. package/dist/react/artifacts.js.map +1 -1
  72. package/dist/react/confirmation.cjs +248 -2
  73. package/dist/react/confirmation.cjs.map +1 -1
  74. package/dist/react/confirmation.d.cts +3 -3
  75. package/dist/react/confirmation.d.ts +3 -3
  76. package/dist/react/confirmation.js +244 -4
  77. package/dist/react/confirmation.js.map +1 -1
  78. package/dist/react/display.cjs +418 -2
  79. package/dist/react/display.cjs.map +1 -1
  80. package/dist/react/display.d.cts +20 -3
  81. package/dist/react/display.d.ts +20 -3
  82. package/dist/react/display.js +413 -4
  83. package/dist/react/display.js.map +1 -1
  84. package/dist/react/forms.cjs +20 -17
  85. package/dist/react/forms.cjs.map +1 -1
  86. package/dist/react/forms.js +20 -17
  87. package/dist/react/forms.js.map +1 -1
  88. package/dist/react/progress.cjs +266 -0
  89. package/dist/react/progress.cjs.map +1 -1
  90. package/dist/react/progress.d.cts +17 -1
  91. package/dist/react/progress.d.ts +17 -1
  92. package/dist/react/progress.js +263 -0
  93. package/dist/react/progress.js.map +1 -1
  94. package/package.json +15 -13
  95. package/registry.yaml +34 -21
  96. package/dist/Skeleton.schema-BO0ca2UX.d.cts +0 -135
  97. package/dist/Skeleton.schema-BO0ca2UX.d.ts +0 -135
@@ -2,8 +2,7 @@ import { z } from 'zod';
2
2
  import { jsx, jsxs } from 'preact/jsx-runtime';
3
3
  import { h } from 'preact';
4
4
  import { useVirtualizer } from '@tanstack/react-virtual';
5
- import { useRef, useCallback } from 'react';
6
- import { jsx as jsx$1 } from 'react/jsx-runtime';
5
+ import { useRef, useCallback, useState, useEffect } from 'preact/compat';
7
6
 
8
7
  // src/components/display/EmptyState.logic.ts
9
8
  var ACTION_VARIANT_CLASSES = {
@@ -25,6 +24,7 @@ function validateEmptyStateProps(raw) {
25
24
 
26
25
  // src/i18n/strings.ts
27
26
  var EN = {
27
+ // ─── Non-forms components ──────────────────────────────────────────────────
28
28
  "ProgressBar.aria.label": "Progress",
29
29
  "ProgressBar.error.invalidProps": "ProgressBar: invalid props",
30
30
  "ConfirmDialog.button.confirm": "Confirm",
@@ -52,9 +52,71 @@ var EN = {
52
52
  "VirtualList.empty.message": "No items to display",
53
53
  "VirtualList.error.invalidProps": "VirtualList: invalid props",
54
54
  "Skeleton.aria.label": "Loading",
55
- "Skeleton.error.invalidProps": "Skeleton: invalid props"
55
+ "Skeleton.error.invalidProps": "Skeleton: invalid props",
56
+ // ─── Forms — useMosaicForm ─────────────────────────────────────────────────
57
+ "useMosaicForm.error.invalidProps": "useMosaicForm: invalid options",
58
+ // ─── Forms — FormProvider ──────────────────────────────────────────────────
59
+ "FormProvider.error.invalidProps": "FormProvider: invalid props",
60
+ // ─── Forms — FormField ────────────────────────────────────────────────────
61
+ "FormField.error.invalidProps": "FormField: invalid props",
62
+ // ─── Forms — ErrorDisplay ─────────────────────────────────────────────────
63
+ "ErrorDisplay.error.required": "This field is required",
64
+ "ErrorDisplay.error.min": "Value is below the minimum",
65
+ "ErrorDisplay.error.max": "Value exceeds the maximum",
66
+ "ErrorDisplay.error.minLength": "Input is too short",
67
+ "ErrorDisplay.error.maxLength": "Input is too long",
68
+ "ErrorDisplay.error.pattern": "Invalid format",
69
+ "ErrorDisplay.error.email": "Enter a valid email address",
70
+ "ErrorDisplay.error.url": "Enter a valid URL",
71
+ "ErrorDisplay.error.generic": "Invalid value",
72
+ // ─── Forms — SubmitButton ─────────────────────────────────────────────────
73
+ "SubmitButton.aria.submit": "Submit form",
74
+ "SubmitButton.state.loading": "Submitting\u2026",
75
+ "SubmitButton.error.invalidProps": "SubmitButton: invalid props",
76
+ // ─── Forms — Input ────────────────────────────────────────────────────────
77
+ "Input.aria.label": "Input field",
78
+ "Input.error.required": "This field is required",
79
+ "Input.error.invalid": "Invalid value",
80
+ "Input.error.tooLong": "Input is too long",
81
+ "Input.error.tooShort": "Input is too short",
82
+ "Input.error.invalidProps": "Input: invalid props",
83
+ // ─── Forms — Textarea ─────────────────────────────────────────────────────
84
+ "Textarea.aria.label": "Text area",
85
+ "Textarea.error.required": "This field is required",
86
+ "Textarea.error.tooLong": "Text is too long",
87
+ "Textarea.counter.remaining": "characters remaining",
88
+ "Textarea.error.invalidProps": "Textarea: invalid props",
89
+ // ─── Forms — FieldArray ───────────────────────────────────────────────────
90
+ "FieldArray.aria.list": "List of items",
91
+ "FieldArray.aria.addItem": "Add item",
92
+ "FieldArray.aria.removeItem": "Remove item",
93
+ "FieldArray.error.invalidProps": "FieldArray: invalid props",
94
+ // ─── Forms — Checkbox ─────────────────────────────────────────────────────
95
+ "Checkbox.aria.label": "Checkbox",
96
+ "Checkbox.error.required": "This field must be checked",
97
+ "Checkbox.error.invalidProps": "Checkbox: invalid props",
98
+ // ─── Forms — MultiSelect ──────────────────────────────────────────────────
99
+ "MultiSelect.aria.label": "Multi-select field",
100
+ "MultiSelect.aria.removeChip": "Remove",
101
+ "MultiSelect.error.required": "Select at least one option",
102
+ "MultiSelect.error.maxItems": "Maximum number of selections reached",
103
+ "MultiSelect.placeholder": "Select options\u2026",
104
+ "MultiSelect.search.placeholder": "Search\u2026",
105
+ "MultiSelect.empty": "No options available",
106
+ "MultiSelect.error.invalidProps": "MultiSelect: invalid props",
107
+ // ─── Forms — RadioGroup ───────────────────────────────────────────────────
108
+ "RadioGroup.aria.label": "Radio group",
109
+ "RadioGroup.error.required": "Select one option",
110
+ "RadioGroup.error.invalidProps": "RadioGroup: invalid props",
111
+ // ─── Forms — Select ───────────────────────────────────────────────────────
112
+ "Select.placeholder": "Select an option\u2026",
113
+ "Select.search.placeholder": "Search\u2026",
114
+ "Select.empty": "No options available",
115
+ "Select.error.required": "Select an option",
116
+ "Select.error.invalidProps": "Select: invalid props"
56
117
  };
57
118
  var FR = {
119
+ // ─── Non-forms components ──────────────────────────────────────────────────
58
120
  "ProgressBar.aria.label": "Progression",
59
121
  "ProgressBar.error.invalidProps": "ProgressBar : propri\xE9t\xE9s invalides",
60
122
  "ConfirmDialog.button.confirm": "Confirmer",
@@ -82,7 +144,68 @@ var FR = {
82
144
  "VirtualList.empty.message": "Aucun \xE9l\xE9ment \xE0 afficher",
83
145
  "VirtualList.error.invalidProps": "VirtualList : propri\xE9t\xE9s invalides",
84
146
  "Skeleton.aria.label": "Chargement",
85
- "Skeleton.error.invalidProps": "Skeleton : propri\xE9t\xE9s invalides"
147
+ "Skeleton.error.invalidProps": "Skeleton : propri\xE9t\xE9s invalides",
148
+ // ─── Forms — useMosaicForm ─────────────────────────────────────────────────
149
+ "useMosaicForm.error.invalidProps": "useMosaicForm : options invalides",
150
+ // ─── Forms — FormProvider ──────────────────────────────────────────────────
151
+ "FormProvider.error.invalidProps": "FormProvider : propri\xE9t\xE9s invalides",
152
+ // ─── Forms — FormField ────────────────────────────────────────────────────
153
+ "FormField.error.invalidProps": "FormField : propri\xE9t\xE9s invalides",
154
+ // ─── Forms — ErrorDisplay ─────────────────────────────────────────────────
155
+ "ErrorDisplay.error.required": "Ce champ est obligatoire",
156
+ "ErrorDisplay.error.min": "La valeur est inf\xE9rieure au minimum",
157
+ "ErrorDisplay.error.max": "La valeur d\xE9passe le maximum",
158
+ "ErrorDisplay.error.minLength": "La saisie est trop courte",
159
+ "ErrorDisplay.error.maxLength": "La saisie est trop longue",
160
+ "ErrorDisplay.error.pattern": "Format invalide",
161
+ "ErrorDisplay.error.email": "Saisissez une adresse e-mail valide",
162
+ "ErrorDisplay.error.url": "Saisissez une URL valide",
163
+ "ErrorDisplay.error.generic": "Valeur invalide",
164
+ // ─── Forms — SubmitButton ─────────────────────────────────────────────────
165
+ "SubmitButton.aria.submit": "Soumettre le formulaire",
166
+ "SubmitButton.state.loading": "Envoi en cours\u2026",
167
+ "SubmitButton.error.invalidProps": "SubmitButton : propri\xE9t\xE9s invalides",
168
+ // ─── Forms — Input ────────────────────────────────────────────────────────
169
+ "Input.aria.label": "Champ de saisie",
170
+ "Input.error.required": "Ce champ est obligatoire",
171
+ "Input.error.invalid": "Valeur invalide",
172
+ "Input.error.tooLong": "La saisie est trop longue",
173
+ "Input.error.tooShort": "La saisie est trop courte",
174
+ "Input.error.invalidProps": "Input : propri\xE9t\xE9s invalides",
175
+ // ─── Forms — Textarea ─────────────────────────────────────────────────────
176
+ "Textarea.aria.label": "Zone de texte",
177
+ "Textarea.error.required": "Ce champ est obligatoire",
178
+ "Textarea.error.tooLong": "Le texte est trop long",
179
+ "Textarea.counter.remaining": "caract\xE8res restants",
180
+ "Textarea.error.invalidProps": "Textarea : propri\xE9t\xE9s invalides",
181
+ // ─── Forms — FieldArray ───────────────────────────────────────────────────
182
+ "FieldArray.aria.list": "Liste d'\xE9l\xE9ments",
183
+ "FieldArray.aria.addItem": "Ajouter un \xE9l\xE9ment",
184
+ "FieldArray.aria.removeItem": "Supprimer l'\xE9l\xE9ment",
185
+ "FieldArray.error.invalidProps": "FieldArray : propri\xE9t\xE9s invalides",
186
+ // ─── Forms — Checkbox ─────────────────────────────────────────────────────
187
+ "Checkbox.aria.label": "Case \xE0 cocher",
188
+ "Checkbox.error.required": "Ce champ doit \xEAtre coch\xE9",
189
+ "Checkbox.error.invalidProps": "Checkbox : propri\xE9t\xE9s invalides",
190
+ // ─── Forms — MultiSelect ──────────────────────────────────────────────────
191
+ "MultiSelect.aria.label": "Champ de s\xE9lection multiple",
192
+ "MultiSelect.aria.removeChip": "Retirer",
193
+ "MultiSelect.error.required": "S\xE9lectionnez au moins une option",
194
+ "MultiSelect.error.maxItems": "Nombre maximum de s\xE9lections atteint",
195
+ "MultiSelect.placeholder": "S\xE9lectionner des options\u2026",
196
+ "MultiSelect.search.placeholder": "Rechercher\u2026",
197
+ "MultiSelect.empty": "Aucune option disponible",
198
+ "MultiSelect.error.invalidProps": "MultiSelect : propri\xE9t\xE9s invalides",
199
+ // ─── Forms — RadioGroup ───────────────────────────────────────────────────
200
+ "RadioGroup.aria.label": "Groupe de boutons radio",
201
+ "RadioGroup.error.required": "S\xE9lectionnez une option",
202
+ "RadioGroup.error.invalidProps": "RadioGroup : propri\xE9t\xE9s invalides",
203
+ // ─── Forms — Select ───────────────────────────────────────────────────────
204
+ "Select.placeholder": "S\xE9lectionner une option\u2026",
205
+ "Select.search.placeholder": "Rechercher\u2026",
206
+ "Select.empty": "Aucune option disponible",
207
+ "Select.error.required": "S\xE9lectionnez une option",
208
+ "Select.error.invalidProps": "Select : propri\xE9t\xE9s invalides"
86
209
  };
87
210
  var TABLE = {
88
211
  en: EN,
@@ -273,13 +396,13 @@ function VirtualList(props) {
273
396
  });
274
397
  } catch {
275
398
  const locale2 = props.locale === "fr" ? "fr" : "en";
276
- return /* @__PURE__ */ jsx$1("div", { role: "alert", children: t("VirtualList.error.invalidProps", locale2) });
399
+ return /* @__PURE__ */ jsx("div", { role: "alert", children: t("VirtualList.error.invalidProps", locale2) });
277
400
  }
278
401
  const locale = props.locale === "fr" ? "fr" : "en";
279
402
  if (props.items.length === 0) {
280
- return /* @__PURE__ */ jsx$1("output", { "aria-live": "polite", children: t("VirtualList.empty.message", locale) });
403
+ return /* @__PURE__ */ jsx("output", { "aria-live": "polite", children: t("VirtualList.empty.message", locale) });
281
404
  }
282
- return /* @__PURE__ */ jsx$1(
405
+ return /* @__PURE__ */ jsx(
283
406
  VirtualListInner,
284
407
  {
285
408
  items: props.items,
@@ -319,14 +442,14 @@ function VirtualListInner({
319
442
  });
320
443
  const virtualItems = rowVirtualizer.getVirtualItems();
321
444
  const totalSize = rowVirtualizer.getTotalSize();
322
- return /* @__PURE__ */ jsx$1(
445
+ return /* @__PURE__ */ jsx(
323
446
  "div",
324
447
  {
325
448
  "data-virtual": "true",
326
449
  ref: scrollRef,
327
450
  className,
328
451
  style: { height: 400, overflow: "auto", position: "relative" },
329
- children: /* @__PURE__ */ jsx$1("div", { style: { height: `${totalSize}px`, position: "relative" }, children: virtualItems.map((virtualRow) => {
452
+ children: /* @__PURE__ */ jsx("div", { style: { height: `${totalSize}px`, position: "relative" }, children: virtualItems.map((virtualRow) => {
330
453
  const item = items[virtualRow.index];
331
454
  const index = virtualRow.index;
332
455
  const rowProps = onRowClick ? {
@@ -358,12 +481,297 @@ function VirtualListInner({
358
481
  transform: `translateY(${virtualRow.start}px)`
359
482
  }
360
483
  };
361
- return /* @__PURE__ */ jsx$1("div", { ...rowProps, children: renderItem(item, index) }, virtualRow.key);
484
+ return /* @__PURE__ */ jsx("div", { ...rowProps, children: renderItem(item, index) }, virtualRow.key);
362
485
  }) })
363
486
  }
364
487
  );
365
488
  }
489
+ var StatusBadgePropsSchema = z.object({
490
+ status: z.string(),
491
+ variant: z.enum(["success", "warning", "danger", "info", "neutral"]).default("neutral"),
492
+ label: z.string().optional(),
493
+ locale: z.enum(["en", "fr"])
494
+ });
495
+ function validateProps(raw) {
496
+ return StatusBadgePropsSchema.parse(raw);
497
+ }
498
+ var variantClasses = {
499
+ success: "bg-green-100 text-green-800 ring-1 ring-green-300",
500
+ warning: "bg-amber-100 text-amber-800 ring-1 ring-amber-300",
501
+ danger: "bg-red-100 text-red-800 ring-1 ring-red-300",
502
+ info: "bg-blue-100 text-blue-800 ring-1 ring-blue-300",
503
+ neutral: "bg-slate-100 text-slate-800 ring-1 ring-slate-300"
504
+ };
505
+ function StatusBadgeInner({ status, variant, label, locale }) {
506
+ const ariaLabel = label ?? status;
507
+ return /* @__PURE__ */ jsx(
508
+ "output",
509
+ {
510
+ "aria-label": ariaLabel,
511
+ lang: locale,
512
+ class: `inline-flex items-center rounded-full px-2.5 py-0.5 text-xs font-medium ${variantClasses[variant]}`,
513
+ children: label ?? status
514
+ }
515
+ );
516
+ }
517
+ function StatusBadge(raw) {
518
+ try {
519
+ const props = validateProps(raw);
520
+ return /* @__PURE__ */ jsx(StatusBadgeInner, { ...props });
521
+ } catch {
522
+ const locale = raw.locale === "fr" ? "fr" : "en";
523
+ return /* @__PURE__ */ jsx("span", { role: "alert", children: t("StatusBadge.error.invalidProps", locale) });
524
+ }
525
+ }
526
+ var ColumnDefSchema = z.object({
527
+ key: z.string().min(1),
528
+ header: z.string().min(1)
529
+ // render is a runtime function — excluded from Zod, typed separately
530
+ });
531
+ var TableViewPropsSchema = z.object({
532
+ columns: z.array(ColumnDefSchema).min(1, "TableView requires at least one column"),
533
+ virtualizeThreshold: z.number().int().positive().default(100),
534
+ ariaLabel: z.string().min(1),
535
+ locale: z.enum(["en", "fr"]).default("en")
536
+ });
537
+ function validateTableViewProps(raw) {
538
+ return TableViewPropsSchema.parse(raw);
539
+ }
540
+ var OVERSCAN = 5;
541
+ function TableView(props) {
542
+ let validatedThreshold = 100;
543
+ try {
544
+ const validated = validateTableViewProps({
545
+ columns: props.columns.map(({ key, header }) => ({ key, header })),
546
+ virtualizeThreshold: props.virtualizeThreshold,
547
+ ariaLabel: props.ariaLabel,
548
+ locale: props.locale
549
+ });
550
+ validatedThreshold = validated.virtualizeThreshold;
551
+ } catch {
552
+ const locale = props.locale === "fr" ? "fr" : "en";
553
+ return /* @__PURE__ */ jsx("div", { role: "alert", children: t("TableView.error.invalidProps", locale) });
554
+ }
555
+ const isVirtual = props.rows.length > validatedThreshold;
556
+ const resolvedLocale = props.locale === "fr" ? "fr" : "en";
557
+ if (isVirtual) {
558
+ return /* @__PURE__ */ jsx(
559
+ VirtualTable,
560
+ {
561
+ rows: props.rows,
562
+ columns: props.columns,
563
+ ariaLabel: props.ariaLabel,
564
+ locale: resolvedLocale,
565
+ onRowClick: props.onRowClick
566
+ }
567
+ );
568
+ }
569
+ return /* @__PURE__ */ jsx(
570
+ StaticTable,
571
+ {
572
+ rows: props.rows,
573
+ columns: props.columns,
574
+ ariaLabel: props.ariaLabel,
575
+ locale: resolvedLocale,
576
+ onRowClick: props.onRowClick
577
+ }
578
+ );
579
+ }
580
+ function StreamingTableView(props) {
581
+ let validatedThreshold = 100;
582
+ try {
583
+ const validated = validateTableViewProps({
584
+ columns: props.columns.map(({ key, header }) => ({ key, header })),
585
+ virtualizeThreshold: props.virtualizeThreshold,
586
+ ariaLabel: props.ariaLabel,
587
+ locale: props.locale
588
+ });
589
+ validatedThreshold = validated.virtualizeThreshold;
590
+ } catch {
591
+ const locale = props.locale === "fr" ? "fr" : "en";
592
+ return /* @__PURE__ */ jsx("div", { role: "alert", children: t("TableView.error.invalidProps", locale) });
593
+ }
594
+ return /* @__PURE__ */ jsx(
595
+ StreamingTableViewInner,
596
+ {
597
+ ...props,
598
+ virtualizeThreshold: validatedThreshold,
599
+ onRowClick: props.onRowClick
600
+ }
601
+ );
602
+ }
603
+ function StreamingTableViewInner({
604
+ columns,
605
+ rows$,
606
+ virtualizeThreshold = 100,
607
+ ariaLabel,
608
+ locale,
609
+ onRowClick
610
+ }) {
611
+ const resolvedLocale = locale === "fr" ? "fr" : "en";
612
+ const [rows, setRows] = useState([]);
613
+ useEffect(() => {
614
+ setRows([]);
615
+ const sub = rows$.subscribe((chunk) => {
616
+ setRows((prev) => [...prev, ...chunk]);
617
+ });
618
+ return () => {
619
+ sub.unsubscribe();
620
+ };
621
+ }, [rows$]);
622
+ const isVirtual = rows.length > virtualizeThreshold;
623
+ if (isVirtual) {
624
+ return /* @__PURE__ */ jsx(
625
+ VirtualTable,
626
+ {
627
+ rows,
628
+ columns,
629
+ ariaLabel,
630
+ locale: resolvedLocale,
631
+ onRowClick
632
+ }
633
+ );
634
+ }
635
+ return /* @__PURE__ */ jsx(
636
+ StaticTable,
637
+ {
638
+ rows,
639
+ columns,
640
+ ariaLabel,
641
+ locale: resolvedLocale,
642
+ onRowClick
643
+ }
644
+ );
645
+ }
646
+ function renderCell(col, row) {
647
+ if (col.render) {
648
+ return col.render(row);
649
+ }
650
+ return String(row[col.key] ?? "");
651
+ }
652
+ function StaticTable({
653
+ rows,
654
+ columns,
655
+ ariaLabel,
656
+ locale,
657
+ onRowClick
658
+ }) {
659
+ const emptyMsg = t("TableView.empty.message", locale);
660
+ return /* @__PURE__ */ jsxs(
661
+ "table",
662
+ {
663
+ "aria-label": ariaLabel,
664
+ "aria-rowcount": rows.length,
665
+ style: { width: "100%", borderCollapse: "collapse" },
666
+ children: [
667
+ /* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsx("tr", { children: columns.map((col) => /* @__PURE__ */ jsx("th", { scope: "col", children: col.header }, col.key)) }) }),
668
+ /* @__PURE__ */ jsx("tbody", { children: rows.length === 0 ? /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsx("td", { colSpan: columns.length, "aria-label": emptyMsg, children: emptyMsg }) }) : rows.map((row, rowIndex) => /* @__PURE__ */ jsx(
669
+ "tr",
670
+ {
671
+ "aria-rowindex": rowIndex + 2,
672
+ ...onRowClick ? {
673
+ role: "button",
674
+ tabIndex: 0,
675
+ style: { cursor: "pointer" },
676
+ onClick: () => onRowClick(row, rowIndex),
677
+ onKeyDown: (e) => {
678
+ if (e.key === "Enter" || e.key === " ") {
679
+ e.preventDefault();
680
+ onRowClick(row, rowIndex);
681
+ }
682
+ }
683
+ } : {},
684
+ children: columns.map((col) => /* @__PURE__ */ jsx("td", { children: renderCell(col, row) }, col.key))
685
+ },
686
+ row.id != null ? String(row.id) : `row-${rowIndex}`
687
+ )) })
688
+ ]
689
+ }
690
+ );
691
+ }
692
+ function VirtualTable({
693
+ rows,
694
+ columns,
695
+ ariaLabel,
696
+ // locale reserved for future virtual-mode empty/pagination strings
697
+ locale: _locale,
698
+ onRowClick
699
+ }) {
700
+ const scrollRef = useRef(null);
701
+ const rowVirtualizer = useVirtualizer({
702
+ count: rows.length,
703
+ /* v8 ignore next 1 */
704
+ getScrollElement: () => scrollRef.current,
705
+ estimateSize: useCallback(() => 40, []),
706
+ overscan: OVERSCAN
707
+ });
708
+ const virtualItems = rowVirtualizer.getVirtualItems();
709
+ const totalSize = rowVirtualizer.getTotalSize();
710
+ return /* @__PURE__ */ jsx(
711
+ "div",
712
+ {
713
+ "data-virtual": "true",
714
+ ref: scrollRef,
715
+ tabIndex: 0,
716
+ role: "region",
717
+ "aria-label": ariaLabel,
718
+ style: { height: 400, overflow: "auto", position: "relative" },
719
+ children: /* @__PURE__ */ jsxs(
720
+ "table",
721
+ {
722
+ "aria-label": ariaLabel,
723
+ "aria-rowcount": rows.length,
724
+ style: { width: "100%", borderCollapse: "collapse" },
725
+ children: [
726
+ /* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsx("tr", { children: columns.map((col) => /* @__PURE__ */ jsx("th", { scope: "col", children: col.header }, col.key)) }) }),
727
+ /* @__PURE__ */ jsx(
728
+ "tbody",
729
+ {
730
+ style: {
731
+ height: `${totalSize}px`,
732
+ position: "relative",
733
+ display: "block"
734
+ },
735
+ children: virtualItems.map((virtualRow) => {
736
+ const row = rows[virtualRow.index] ?? {};
737
+ return /* @__PURE__ */ jsx(
738
+ "tr",
739
+ {
740
+ "aria-rowindex": virtualRow.index + 2,
741
+ style: {
742
+ position: "absolute",
743
+ top: 0,
744
+ left: 0,
745
+ width: "100%",
746
+ transform: `translateY(${virtualRow.start}px)`,
747
+ display: "flex",
748
+ ...onRowClick ? { cursor: "pointer" } : {}
749
+ },
750
+ ...onRowClick ? {
751
+ role: "button",
752
+ tabIndex: 0,
753
+ onClick: () => onRowClick(row, virtualRow.index),
754
+ onKeyDown: (e) => {
755
+ if (e.key === "Enter" || e.key === " ") {
756
+ e.preventDefault();
757
+ onRowClick(row, virtualRow.index);
758
+ }
759
+ }
760
+ } : {},
761
+ children: columns.map((col) => /* @__PURE__ */ jsx("td", { style: { flex: 1 }, children: renderCell(col, row) }, col.key))
762
+ },
763
+ row.id != null ? String(row.id) : `vrow-${virtualRow.index}`
764
+ );
765
+ })
766
+ }
767
+ )
768
+ ]
769
+ }
770
+ )
771
+ }
772
+ );
773
+ }
366
774
 
367
- export { EmptyState, EmptyStatePropsSchema, Skeleton, SkeletonPropsSchema, VirtualList, VirtualListPropsSchema, resolveSkeletonDimensions, validateEmptyStateProps, validateSkeletonProps, validateVirtualListProps };
775
+ export { EmptyState, EmptyStatePropsSchema, Skeleton, SkeletonPropsSchema, StatusBadge, StatusBadgePropsSchema, StreamingTableView, TableView, TableViewPropsSchema, VirtualList, VirtualListPropsSchema, resolveSkeletonDimensions, validateEmptyStateProps, validateSkeletonProps, validateProps as validateStatusBadgeProps, validateTableViewProps, validateVirtualListProps };
368
776
  //# sourceMappingURL=display.js.map
369
777
  //# sourceMappingURL=display.js.map