@vantageos/mosaic 0.1.1 → 0.1.2

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 (49) hide show
  1. package/dist/artifacts.cjs +113 -0
  2. package/dist/artifacts.cjs.map +1 -0
  3. package/dist/artifacts.d.cts +29 -0
  4. package/dist/artifacts.d.ts +29 -0
  5. package/dist/artifacts.js +105 -0
  6. package/dist/artifacts.js.map +1 -0
  7. package/dist/confirmation.cjs +180 -0
  8. package/dist/confirmation.cjs.map +1 -0
  9. package/dist/confirmation.d.cts +33 -0
  10. package/dist/confirmation.d.ts +33 -0
  11. package/dist/confirmation.js +176 -0
  12. package/dist/confirmation.js.map +1 -0
  13. package/dist/display.cjs +273 -0
  14. package/dist/display.cjs.map +1 -0
  15. package/dist/display.d.cts +94 -0
  16. package/dist/display.d.ts +94 -0
  17. package/dist/display.js +268 -0
  18. package/dist/display.js.map +1 -0
  19. package/dist/index.cjs +40 -2
  20. package/dist/index.cjs.map +1 -1
  21. package/dist/index.d.cts +12 -232
  22. package/dist/index.d.ts +12 -232
  23. package/dist/index.js +40 -3
  24. package/dist/index.js.map +1 -1
  25. package/dist/input.cjs +102 -0
  26. package/dist/input.cjs.map +1 -0
  27. package/dist/input.d.cts +34 -0
  28. package/dist/input.d.ts +34 -0
  29. package/dist/input.js +98 -0
  30. package/dist/input.js.map +1 -0
  31. package/dist/media.cjs +98 -0
  32. package/dist/media.cjs.map +1 -0
  33. package/dist/media.d.cts +29 -0
  34. package/dist/media.d.ts +29 -0
  35. package/dist/media.js +94 -0
  36. package/dist/media.js.map +1 -0
  37. package/dist/progress.cjs +125 -0
  38. package/dist/progress.cjs.map +1 -0
  39. package/dist/progress.d.cts +29 -0
  40. package/dist/progress.d.ts +29 -0
  41. package/dist/progress.js +121 -0
  42. package/dist/progress.js.map +1 -0
  43. package/dist/server.cjs +121 -0
  44. package/dist/server.cjs.map +1 -0
  45. package/dist/server.d.cts +33 -0
  46. package/dist/server.d.ts +33 -0
  47. package/dist/server.js +116 -0
  48. package/dist/server.js.map +1 -0
  49. package/package.json +45 -7
@@ -0,0 +1,176 @@
1
+ import { useRef, useId, useState, useEffect } from 'react';
2
+ import { z } from 'zod';
3
+ import { jsx, jsxs } from 'react/jsx-runtime';
4
+
5
+ // src/components/confirmation/TokenDisplayOnceModal.tsx
6
+
7
+ // src/i18n/strings.ts
8
+ var EN = {
9
+ "ProgressBar.aria.label": "Progress",
10
+ "ProgressBar.error.invalidProps": "ProgressBar: invalid props",
11
+ "ConfirmDialog.button.confirm": "Confirm",
12
+ "ConfirmDialog.button.cancel": "Cancel",
13
+ "ConfirmDialog.aria.dialog": "Confirmation dialog",
14
+ "TableView.aria.table": "Data table",
15
+ "TableView.pagination.next": "Next page",
16
+ "TableView.pagination.prev": "Previous page",
17
+ "TableView.empty.message": "No data to display",
18
+ "TableView.error.invalidProps": "TableView: invalid props",
19
+ "MarkdownRenderer.aria.content": "Rendered Markdown content",
20
+ "MarkdownRenderer.error.invalidProps": "MarkdownRenderer: invalid props",
21
+ "MarkdownRenderer.error.tooLong": "Content exceeds maximum length",
22
+ "TokenDisplayOnceModal.button.copy": "Copy token",
23
+ "TokenDisplayOnceModal.button.close": "Close",
24
+ "TokenDisplayOnceModal.warning.once": "This token will only be shown once. Copy it now.",
25
+ "TokenDisplayOnceModal.copied": "Copied",
26
+ "StatusBadge.aria.status": "Status",
27
+ "StatusBadge.error.invalidProps": "StatusBadge: invalid props"
28
+ };
29
+ var FR = {
30
+ "ProgressBar.aria.label": "Progression",
31
+ "ProgressBar.error.invalidProps": "ProgressBar : propri\xE9t\xE9s invalides",
32
+ "ConfirmDialog.button.confirm": "Confirmer",
33
+ "ConfirmDialog.button.cancel": "Annuler",
34
+ "ConfirmDialog.aria.dialog": "Bo\xEEte de dialogue de confirmation",
35
+ "TableView.aria.table": "Tableau de donn\xE9es",
36
+ "TableView.pagination.next": "Page suivante",
37
+ "TableView.pagination.prev": "Page pr\xE9c\xE9dente",
38
+ "TableView.empty.message": "Aucune donn\xE9e \xE0 afficher",
39
+ "TableView.error.invalidProps": "TableView : propri\xE9t\xE9s invalides",
40
+ "MarkdownRenderer.aria.content": "Contenu Markdown rendu",
41
+ "MarkdownRenderer.error.invalidProps": "MarkdownRenderer : propri\xE9t\xE9s invalides",
42
+ "MarkdownRenderer.error.tooLong": "Le contenu d\xE9passe la longueur maximale",
43
+ "TokenDisplayOnceModal.button.copy": "Copier le jeton",
44
+ "TokenDisplayOnceModal.button.close": "Fermer",
45
+ "TokenDisplayOnceModal.warning.once": "Ce jeton ne sera affich\xE9 qu'une seule fois. Copiez-le maintenant.",
46
+ "TokenDisplayOnceModal.copied": "Copi\xE9",
47
+ "StatusBadge.aria.status": "Statut",
48
+ "StatusBadge.error.invalidProps": "StatusBadge : propri\xE9t\xE9s invalides"
49
+ };
50
+ var TABLE = {
51
+ en: EN,
52
+ fr: FR
53
+ };
54
+ function t(key, locale = "en") {
55
+ return TABLE[locale]?.[key] ?? TABLE.en[key];
56
+ }
57
+ var TokenDisplayOnceModalPropsSchema = z.object({
58
+ token: z.string().min(1),
59
+ title: z.string().min(1),
60
+ warningMessage: z.string().min(1),
61
+ copyLabel: z.string().min(1),
62
+ closeLabel: z.string().min(1),
63
+ locale: z.enum(["en", "fr"]).default("en")
64
+ });
65
+ function validateTokenDisplayOnceModalProps(raw) {
66
+ return TokenDisplayOnceModalPropsSchema.parse(raw);
67
+ }
68
+ function TokenDisplayOnceModalInner({
69
+ token,
70
+ title,
71
+ warningMessage,
72
+ copyLabel,
73
+ closeLabel,
74
+ locale,
75
+ onClose
76
+ }) {
77
+ const dialogRef = useRef(null);
78
+ const titleId = useId();
79
+ const warningId = useId();
80
+ const [copied, setCopied] = useState(false);
81
+ const [secureToken] = useState(token);
82
+ useEffect(() => {
83
+ const dialog = dialogRef.current;
84
+ if (!dialog) return;
85
+ dialog.showModal();
86
+ return () => {
87
+ if (dialog.open) dialog.close();
88
+ };
89
+ }, []);
90
+ async function handleCopy() {
91
+ try {
92
+ await navigator.clipboard.writeText(secureToken);
93
+ setCopied(true);
94
+ setTimeout(() => setCopied(false), 2e3);
95
+ } catch {
96
+ setCopied(false);
97
+ }
98
+ }
99
+ function handleKeyDown(e) {
100
+ if (e.key === "Escape") {
101
+ e.preventDefault();
102
+ onClose();
103
+ }
104
+ }
105
+ function handleBackdropClick(e) {
106
+ if (e.target === dialogRef.current) {
107
+ onClose();
108
+ }
109
+ }
110
+ return /* @__PURE__ */ jsx(
111
+ "dialog",
112
+ {
113
+ ref: dialogRef,
114
+ "aria-modal": "true",
115
+ "aria-labelledby": titleId,
116
+ "aria-describedby": warningId,
117
+ onKeyDown: handleKeyDown,
118
+ onClick: handleBackdropClick,
119
+ className: "rounded-lg shadow-xl p-0 backdrop:bg-black/40 w-full max-w-lg mx-auto",
120
+ children: /* @__PURE__ */ jsxs(
121
+ "div",
122
+ {
123
+ className: "p-6 flex flex-col gap-4",
124
+ onClick: (e) => e.stopPropagation(),
125
+ onKeyDown: (e) => e.stopPropagation(),
126
+ children: [
127
+ /* @__PURE__ */ jsx("h2", { id: titleId, className: "text-lg font-semibold text-gray-900", children: title }),
128
+ /* @__PURE__ */ jsx(
129
+ "p",
130
+ {
131
+ id: warningId,
132
+ className: "text-sm text-amber-700 bg-amber-50 border border-amber-200 rounded-md px-3 py-2",
133
+ children: warningMessage
134
+ }
135
+ ),
136
+ /* @__PURE__ */ jsx("div", { className: "flex items-center gap-2 bg-gray-50 border border-gray-200 rounded-md px-3 py-2", children: /* @__PURE__ */ jsx("code", { className: "flex-1 text-sm font-mono text-gray-800 break-all select-all", children: secureToken }) }),
137
+ /* @__PURE__ */ jsx("output", { "aria-live": "polite", "aria-atomic": "true", className: "min-h-[1.25rem] block", children: copied && /* @__PURE__ */ jsx("span", { className: "text-sm text-green-700 font-medium", children: t("TokenDisplayOnceModal.copied", locale) }) }),
138
+ /* @__PURE__ */ jsxs("div", { className: "flex justify-end gap-3 mt-2", children: [
139
+ /* @__PURE__ */ jsx(
140
+ "button",
141
+ {
142
+ type: "button",
143
+ onClick: handleCopy,
144
+ className: "px-4 py-2 rounded-md text-sm font-medium bg-gray-100 text-gray-800 hover:bg-gray-200 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-gray-400 transition-colors",
145
+ children: copyLabel
146
+ }
147
+ ),
148
+ /* @__PURE__ */ jsx(
149
+ "button",
150
+ {
151
+ type: "button",
152
+ onClick: onClose,
153
+ className: "px-4 py-2 rounded-md text-sm font-medium bg-gray-900 text-white hover:bg-gray-700 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-gray-900 transition-colors",
154
+ children: closeLabel
155
+ }
156
+ )
157
+ ] })
158
+ ]
159
+ }
160
+ )
161
+ }
162
+ );
163
+ }
164
+ function TokenDisplayOnceModal(raw) {
165
+ try {
166
+ const parsed = validateTokenDisplayOnceModalProps(raw);
167
+ return /* @__PURE__ */ jsx(TokenDisplayOnceModalInner, { ...parsed, onClose: raw.onClose });
168
+ } catch (err) {
169
+ console.warn("[TokenDisplayOnceModal] Invalid props \u2014 component will not render.", err);
170
+ return null;
171
+ }
172
+ }
173
+
174
+ export { TokenDisplayOnceModal, TokenDisplayOnceModalPropsSchema, validateTokenDisplayOnceModalProps };
175
+ //# sourceMappingURL=confirmation.js.map
176
+ //# sourceMappingURL=confirmation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/i18n/strings.ts","../src/components/confirmation/TokenDisplayOnceModal.schema.ts","../src/components/confirmation/TokenDisplayOnceModal.tsx"],"names":[],"mappings":"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","file":"confirmation.js","sourcesContent":["/**\n * Compile-time mirror of `@vantageos/mosaic-i18n` EN/FR locales for the 6\n * v0.1.0 components. Inlined here so that `<Comp>` renderers can resolve\n * `t(key, locale)` without dragging react-i18next into the component runtime\n * (keeps bundle small and tests provider-free). Drift is gated by\n * `mosaic-registry-drift-check.mjs` which validates the canonical\n * `packages/mosaic-i18n/src/locales/{en,fr}.json` against `registry.yaml`.\n *\n * Mosaic standard §8: production JSX MUST resolve user-facing strings via\n * `t()` — no hardcoded English literals.\n */\nexport type MosaicLocale = \"en\" | \"fr\";\n\nconst EN = {\n \"ProgressBar.aria.label\": \"Progress\",\n \"ProgressBar.error.invalidProps\": \"ProgressBar: invalid props\",\n \"ConfirmDialog.button.confirm\": \"Confirm\",\n \"ConfirmDialog.button.cancel\": \"Cancel\",\n \"ConfirmDialog.aria.dialog\": \"Confirmation dialog\",\n \"TableView.aria.table\": \"Data table\",\n \"TableView.pagination.next\": \"Next page\",\n \"TableView.pagination.prev\": \"Previous page\",\n \"TableView.empty.message\": \"No data to display\",\n \"TableView.error.invalidProps\": \"TableView: invalid props\",\n \"MarkdownRenderer.aria.content\": \"Rendered Markdown content\",\n \"MarkdownRenderer.error.invalidProps\": \"MarkdownRenderer: invalid props\",\n \"MarkdownRenderer.error.tooLong\": \"Content exceeds maximum length\",\n \"TokenDisplayOnceModal.button.copy\": \"Copy token\",\n \"TokenDisplayOnceModal.button.close\": \"Close\",\n \"TokenDisplayOnceModal.warning.once\": \"This token will only be shown once. Copy it now.\",\n \"TokenDisplayOnceModal.copied\": \"Copied\",\n \"StatusBadge.aria.status\": \"Status\",\n \"StatusBadge.error.invalidProps\": \"StatusBadge: invalid props\",\n} as const;\n\nconst FR: Record<keyof typeof EN, string> = {\n \"ProgressBar.aria.label\": \"Progression\",\n \"ProgressBar.error.invalidProps\": \"ProgressBar : propriétés invalides\",\n \"ConfirmDialog.button.confirm\": \"Confirmer\",\n \"ConfirmDialog.button.cancel\": \"Annuler\",\n \"ConfirmDialog.aria.dialog\": \"Boîte de dialogue de confirmation\",\n \"TableView.aria.table\": \"Tableau de données\",\n \"TableView.pagination.next\": \"Page suivante\",\n \"TableView.pagination.prev\": \"Page précédente\",\n \"TableView.empty.message\": \"Aucune donnée à afficher\",\n \"TableView.error.invalidProps\": \"TableView : propriétés invalides\",\n \"MarkdownRenderer.aria.content\": \"Contenu Markdown rendu\",\n \"MarkdownRenderer.error.invalidProps\": \"MarkdownRenderer : propriétés invalides\",\n \"MarkdownRenderer.error.tooLong\": \"Le contenu dépasse la longueur maximale\",\n \"TokenDisplayOnceModal.button.copy\": \"Copier le jeton\",\n \"TokenDisplayOnceModal.button.close\": \"Fermer\",\n \"TokenDisplayOnceModal.warning.once\":\n \"Ce jeton ne sera affiché qu'une seule fois. Copiez-le maintenant.\",\n \"TokenDisplayOnceModal.copied\": \"Copié\",\n \"StatusBadge.aria.status\": \"Statut\",\n \"StatusBadge.error.invalidProps\": \"StatusBadge : propriétés invalides\",\n};\n\nexport type MosaicI18nKey = keyof typeof EN;\n\nconst TABLE: Record<MosaicLocale, Record<MosaicI18nKey, string>> = {\n en: EN,\n fr: FR,\n};\n\n/** Resolves a Mosaic i18n key for the given locale, falling back to EN. */\nexport function t(key: MosaicI18nKey, locale: MosaicLocale = \"en\"): string {\n return TABLE[locale]?.[key] ?? TABLE.en[key];\n}\n","import { z } from \"zod\";\n\n// i18nKeys: TokenDisplayOnceModal.button.copy, TokenDisplayOnceModal.button.close,\n// TokenDisplayOnceModal.warning.once, TokenDisplayOnceModal.copied\n\nexport const TokenDisplayOnceModalPropsSchema = z.object({\n token: z.string().min(1),\n title: z.string().min(1),\n warningMessage: z.string().min(1),\n copyLabel: z.string().min(1),\n closeLabel: z.string().min(1),\n locale: z.enum([\"en\", \"fr\"]).default(\"en\"),\n});\n\nexport type TokenDisplayOnceModalProps = z.infer<typeof TokenDisplayOnceModalPropsSchema> & {\n onClose: () => void;\n};\n\nexport function validateTokenDisplayOnceModalProps(\n raw: unknown,\n): z.infer<typeof TokenDisplayOnceModalPropsSchema> {\n return TokenDisplayOnceModalPropsSchema.parse(raw);\n}\n","\"use client\";\n\n// i18nKeys: TokenDisplayOnceModal.button.copy, TokenDisplayOnceModal.button.close,\n// TokenDisplayOnceModal.warning.once, TokenDisplayOnceModal.copied\n\nimport { type KeyboardEvent, type MouseEvent, useEffect, useId, useRef, useState } from \"react\";\nimport { t } from \"../../i18n/strings.js\";\nimport {\n type TokenDisplayOnceModalProps,\n validateTokenDisplayOnceModalProps,\n} from \"./TokenDisplayOnceModal.schema\";\n\nfunction TokenDisplayOnceModalInner({\n token,\n title,\n warningMessage,\n copyLabel,\n closeLabel,\n locale,\n onClose,\n}: TokenDisplayOnceModalProps) {\n const dialogRef = useRef<HTMLDialogElement>(null);\n const titleId = useId();\n const warningId = useId();\n const [copied, setCopied] = useState(false);\n // Security: token is held only in this useState — on unmount, released by React GC.\n // NEVER logged, NEVER stored in data-*, NEVER written to innerHTML.\n const [secureToken] = useState<string>(token);\n\n useEffect(() => {\n const dialog = dialogRef.current;\n /* v8 ignore next 2 */\n if (!dialog) return;\n dialog.showModal();\n return () => {\n if (dialog.open) dialog.close();\n };\n }, []);\n\n async function handleCopy() {\n try {\n await navigator.clipboard.writeText(secureToken);\n setCopied(true);\n setTimeout(() => setCopied(false), 2000);\n } catch {\n // Copy failed — do not leak token in error message\n setCopied(false);\n }\n }\n\n function handleKeyDown(e: KeyboardEvent<HTMLDialogElement>) {\n if (e.key === \"Escape\") {\n e.preventDefault();\n onClose();\n }\n }\n\n function handleBackdropClick(e: MouseEvent<HTMLDialogElement>) {\n if (e.target === dialogRef.current) {\n onClose();\n }\n }\n\n return (\n <dialog\n ref={dialogRef}\n aria-modal=\"true\"\n aria-labelledby={titleId}\n aria-describedby={warningId}\n onKeyDown={handleKeyDown}\n onClick={handleBackdropClick}\n className=\"rounded-lg shadow-xl p-0 backdrop:bg-black/40 w-full max-w-lg mx-auto\"\n >\n {/* Inner div stops click propagation so backdrop-click only fires on <dialog> itself */}\n <div\n className=\"p-6 flex flex-col gap-4\"\n onClick={(e) => e.stopPropagation()}\n onKeyDown={(e) => e.stopPropagation()}\n >\n <h2 id={titleId} className=\"text-lg font-semibold text-gray-900\">\n {title}\n </h2>\n <p\n id={warningId}\n className=\"text-sm text-amber-700 bg-amber-50 border border-amber-200 rounded-md px-3 py-2\"\n >\n {warningMessage}\n </p>\n <div className=\"flex items-center gap-2 bg-gray-50 border border-gray-200 rounded-md px-3 py-2\">\n <code className=\"flex-1 text-sm font-mono text-gray-800 break-all select-all\">\n {secureToken}\n </code>\n </div>\n {/* Ephemeral \"Copied\" toast — aria-live polite, no token text */}\n <output aria-live=\"polite\" aria-atomic=\"true\" className=\"min-h-[1.25rem] block\">\n {copied && (\n <span className=\"text-sm text-green-700 font-medium\">\n {t(\"TokenDisplayOnceModal.copied\", locale)}\n </span>\n )}\n </output>\n <div className=\"flex justify-end gap-3 mt-2\">\n <button\n type=\"button\"\n onClick={handleCopy}\n className=\"px-4 py-2 rounded-md text-sm font-medium bg-gray-100 text-gray-800 hover:bg-gray-200 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-gray-400 transition-colors\"\n >\n {copyLabel}\n </button>\n <button\n type=\"button\"\n onClick={onClose}\n className=\"px-4 py-2 rounded-md text-sm font-medium bg-gray-900 text-white hover:bg-gray-700 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-gray-900 transition-colors\"\n >\n {closeLabel}\n </button>\n </div>\n </div>\n </dialog>\n );\n}\n\nexport function TokenDisplayOnceModal(\n raw: Omit<TokenDisplayOnceModalProps, \"locale\"> &\n Partial<Pick<TokenDisplayOnceModalProps, \"locale\">>,\n) {\n try {\n const parsed = validateTokenDisplayOnceModalProps(raw);\n return <TokenDisplayOnceModalInner {...parsed} onClose={raw.onClose} />;\n } catch (err) {\n // Security: use console.warn (not console.error) and do not expose token value in log\n console.warn(\"[TokenDisplayOnceModal] Invalid props — component will not render.\", err);\n return null;\n }\n}\n"]}
@@ -0,0 +1,273 @@
1
+ 'use strict';
2
+
3
+ var reactVirtual = require('@tanstack/react-virtual');
4
+ var react = require('react');
5
+ var zod = require('zod');
6
+ var jsxRuntime = require('react/jsx-runtime');
7
+
8
+ // src/components/display/TableView.tsx
9
+
10
+ // src/i18n/strings.ts
11
+ var EN = {
12
+ "ProgressBar.aria.label": "Progress",
13
+ "ProgressBar.error.invalidProps": "ProgressBar: invalid props",
14
+ "ConfirmDialog.button.confirm": "Confirm",
15
+ "ConfirmDialog.button.cancel": "Cancel",
16
+ "ConfirmDialog.aria.dialog": "Confirmation dialog",
17
+ "TableView.aria.table": "Data table",
18
+ "TableView.pagination.next": "Next page",
19
+ "TableView.pagination.prev": "Previous page",
20
+ "TableView.empty.message": "No data to display",
21
+ "TableView.error.invalidProps": "TableView: invalid props",
22
+ "MarkdownRenderer.aria.content": "Rendered Markdown content",
23
+ "MarkdownRenderer.error.invalidProps": "MarkdownRenderer: invalid props",
24
+ "MarkdownRenderer.error.tooLong": "Content exceeds maximum length",
25
+ "TokenDisplayOnceModal.button.copy": "Copy token",
26
+ "TokenDisplayOnceModal.button.close": "Close",
27
+ "TokenDisplayOnceModal.warning.once": "This token will only be shown once. Copy it now.",
28
+ "TokenDisplayOnceModal.copied": "Copied",
29
+ "StatusBadge.aria.status": "Status",
30
+ "StatusBadge.error.invalidProps": "StatusBadge: invalid props"
31
+ };
32
+ var FR = {
33
+ "ProgressBar.aria.label": "Progression",
34
+ "ProgressBar.error.invalidProps": "ProgressBar : propri\xE9t\xE9s invalides",
35
+ "ConfirmDialog.button.confirm": "Confirmer",
36
+ "ConfirmDialog.button.cancel": "Annuler",
37
+ "ConfirmDialog.aria.dialog": "Bo\xEEte de dialogue de confirmation",
38
+ "TableView.aria.table": "Tableau de donn\xE9es",
39
+ "TableView.pagination.next": "Page suivante",
40
+ "TableView.pagination.prev": "Page pr\xE9c\xE9dente",
41
+ "TableView.empty.message": "Aucune donn\xE9e \xE0 afficher",
42
+ "TableView.error.invalidProps": "TableView : propri\xE9t\xE9s invalides",
43
+ "MarkdownRenderer.aria.content": "Contenu Markdown rendu",
44
+ "MarkdownRenderer.error.invalidProps": "MarkdownRenderer : propri\xE9t\xE9s invalides",
45
+ "MarkdownRenderer.error.tooLong": "Le contenu d\xE9passe la longueur maximale",
46
+ "TokenDisplayOnceModal.button.copy": "Copier le jeton",
47
+ "TokenDisplayOnceModal.button.close": "Fermer",
48
+ "TokenDisplayOnceModal.warning.once": "Ce jeton ne sera affich\xE9 qu'une seule fois. Copiez-le maintenant.",
49
+ "TokenDisplayOnceModal.copied": "Copi\xE9",
50
+ "StatusBadge.aria.status": "Statut",
51
+ "StatusBadge.error.invalidProps": "StatusBadge : propri\xE9t\xE9s invalides"
52
+ };
53
+ var TABLE = {
54
+ en: EN,
55
+ fr: FR
56
+ };
57
+ function t(key, locale = "en") {
58
+ return TABLE[locale]?.[key] ?? TABLE.en[key];
59
+ }
60
+ var ColumnDefSchema = zod.z.object({
61
+ key: zod.z.string().min(1),
62
+ header: zod.z.string().min(1)
63
+ // render is a runtime function — excluded from Zod, typed separately
64
+ });
65
+ var TableViewPropsSchema = zod.z.object({
66
+ columns: zod.z.array(ColumnDefSchema).min(1, "TableView requires at least one column"),
67
+ virtualizeThreshold: zod.z.number().int().positive().default(100),
68
+ ariaLabel: zod.z.string().min(1),
69
+ locale: zod.z.enum(["en", "fr"]).default("en")
70
+ });
71
+ function validateTableViewProps(raw) {
72
+ return TableViewPropsSchema.parse(raw);
73
+ }
74
+ var OVERSCAN = 5;
75
+ function TableView(props) {
76
+ let validatedThreshold = 100;
77
+ try {
78
+ const validated = validateTableViewProps({
79
+ columns: props.columns.map(({ key, header }) => ({ key, header })),
80
+ virtualizeThreshold: props.virtualizeThreshold,
81
+ ariaLabel: props.ariaLabel,
82
+ locale: props.locale
83
+ });
84
+ validatedThreshold = validated.virtualizeThreshold;
85
+ } catch {
86
+ const locale = props.locale === "fr" ? "fr" : "en";
87
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { role: "alert", children: t("TableView.error.invalidProps", locale) });
88
+ }
89
+ const isVirtual = props.rows.length > validatedThreshold;
90
+ const resolvedLocale = props.locale === "fr" ? "fr" : "en";
91
+ if (isVirtual) {
92
+ return /* @__PURE__ */ jsxRuntime.jsx(
93
+ VirtualTable,
94
+ {
95
+ rows: props.rows,
96
+ columns: props.columns,
97
+ ariaLabel: props.ariaLabel,
98
+ locale: resolvedLocale
99
+ }
100
+ );
101
+ }
102
+ return /* @__PURE__ */ jsxRuntime.jsx(
103
+ StaticTable,
104
+ {
105
+ rows: props.rows,
106
+ columns: props.columns,
107
+ ariaLabel: props.ariaLabel,
108
+ locale: resolvedLocale
109
+ }
110
+ );
111
+ }
112
+ function StreamingTableView(props) {
113
+ let validatedThreshold = 100;
114
+ try {
115
+ const validated = validateTableViewProps({
116
+ columns: props.columns.map(({ key, header }) => ({ key, header })),
117
+ virtualizeThreshold: props.virtualizeThreshold,
118
+ ariaLabel: props.ariaLabel,
119
+ locale: props.locale
120
+ });
121
+ validatedThreshold = validated.virtualizeThreshold;
122
+ } catch {
123
+ const locale = props.locale === "fr" ? "fr" : "en";
124
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { role: "alert", children: t("TableView.error.invalidProps", locale) });
125
+ }
126
+ return /* @__PURE__ */ jsxRuntime.jsx(StreamingTableViewInner, { ...props, virtualizeThreshold: validatedThreshold });
127
+ }
128
+ function StreamingTableViewInner({
129
+ columns,
130
+ rows$,
131
+ virtualizeThreshold = 100,
132
+ ariaLabel,
133
+ locale
134
+ }) {
135
+ const resolvedLocale = locale === "fr" ? "fr" : "en";
136
+ const [rows, setRows] = react.useState([]);
137
+ react.useEffect(() => {
138
+ setRows([]);
139
+ const sub = rows$.subscribe((chunk) => {
140
+ setRows((prev) => [...prev, ...chunk]);
141
+ });
142
+ return () => {
143
+ sub.unsubscribe();
144
+ };
145
+ }, [rows$]);
146
+ const isVirtual = rows.length > virtualizeThreshold;
147
+ if (isVirtual) {
148
+ return /* @__PURE__ */ jsxRuntime.jsx(
149
+ VirtualTable,
150
+ {
151
+ rows,
152
+ columns,
153
+ ariaLabel,
154
+ locale: resolvedLocale
155
+ }
156
+ );
157
+ }
158
+ return /* @__PURE__ */ jsxRuntime.jsx(
159
+ StaticTable,
160
+ {
161
+ rows,
162
+ columns,
163
+ ariaLabel,
164
+ locale: resolvedLocale
165
+ }
166
+ );
167
+ }
168
+ function renderCell(col, row) {
169
+ if (col.render) {
170
+ return col.render(row);
171
+ }
172
+ return String(row[col.key] ?? "");
173
+ }
174
+ function StaticTable({
175
+ rows,
176
+ columns,
177
+ ariaLabel,
178
+ locale
179
+ }) {
180
+ const emptyMsg = t("TableView.empty.message", locale);
181
+ return /* @__PURE__ */ jsxRuntime.jsxs(
182
+ "table",
183
+ {
184
+ "aria-label": ariaLabel,
185
+ "aria-rowcount": rows.length,
186
+ style: { width: "100%", borderCollapse: "collapse" },
187
+ children: [
188
+ /* @__PURE__ */ jsxRuntime.jsx("thead", { children: /* @__PURE__ */ jsxRuntime.jsx("tr", { children: columns.map((col) => /* @__PURE__ */ jsxRuntime.jsx("th", { scope: "col", children: col.header }, col.key)) }) }),
189
+ /* @__PURE__ */ jsxRuntime.jsx("tbody", { children: rows.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("tr", { children: /* @__PURE__ */ jsxRuntime.jsx("td", { colSpan: columns.length, "aria-label": emptyMsg, children: emptyMsg }) }) : rows.map((row, rowIndex) => /* @__PURE__ */ jsxRuntime.jsx(
190
+ "tr",
191
+ {
192
+ "aria-rowindex": rowIndex + 2,
193
+ children: columns.map((col) => /* @__PURE__ */ jsxRuntime.jsx("td", { children: renderCell(col, row) }, col.key))
194
+ },
195
+ row.id != null ? String(row.id) : `row-${rowIndex}`
196
+ )) })
197
+ ]
198
+ }
199
+ );
200
+ }
201
+ function VirtualTable({
202
+ rows,
203
+ columns,
204
+ ariaLabel,
205
+ // locale reserved for future virtual-mode empty/pagination strings
206
+ locale: _locale
207
+ }) {
208
+ const scrollRef = react.useRef(null);
209
+ const rowVirtualizer = reactVirtual.useVirtualizer({
210
+ count: rows.length,
211
+ /* v8 ignore next 1 */
212
+ getScrollElement: () => scrollRef.current,
213
+ estimateSize: react.useCallback(() => 40, []),
214
+ overscan: OVERSCAN
215
+ });
216
+ const virtualItems = rowVirtualizer.getVirtualItems();
217
+ const totalSize = rowVirtualizer.getTotalSize();
218
+ return /* @__PURE__ */ jsxRuntime.jsx(
219
+ "div",
220
+ {
221
+ "data-virtual": "true",
222
+ ref: scrollRef,
223
+ style: { height: 400, overflow: "auto", position: "relative" },
224
+ children: /* @__PURE__ */ jsxRuntime.jsxs(
225
+ "table",
226
+ {
227
+ "aria-label": ariaLabel,
228
+ "aria-rowcount": rows.length,
229
+ style: { width: "100%", borderCollapse: "collapse" },
230
+ children: [
231
+ /* @__PURE__ */ jsxRuntime.jsx("thead", { children: /* @__PURE__ */ jsxRuntime.jsx("tr", { children: columns.map((col) => /* @__PURE__ */ jsxRuntime.jsx("th", { scope: "col", children: col.header }, col.key)) }) }),
232
+ /* @__PURE__ */ jsxRuntime.jsx(
233
+ "tbody",
234
+ {
235
+ style: {
236
+ height: `${totalSize}px`,
237
+ position: "relative",
238
+ display: "block"
239
+ },
240
+ children: virtualItems.map((virtualRow) => {
241
+ const row = rows[virtualRow.index] ?? {};
242
+ return /* @__PURE__ */ jsxRuntime.jsx(
243
+ "tr",
244
+ {
245
+ "aria-rowindex": virtualRow.index + 2,
246
+ style: {
247
+ position: "absolute",
248
+ top: 0,
249
+ left: 0,
250
+ width: "100%",
251
+ transform: `translateY(${virtualRow.start}px)`,
252
+ display: "flex"
253
+ },
254
+ children: columns.map((col) => /* @__PURE__ */ jsxRuntime.jsx("td", { style: { flex: 1 }, children: renderCell(col, row) }, col.key))
255
+ },
256
+ row.id != null ? String(row.id) : `vrow-${virtualRow.index}`
257
+ );
258
+ })
259
+ }
260
+ )
261
+ ]
262
+ }
263
+ )
264
+ }
265
+ );
266
+ }
267
+
268
+ exports.StreamingTableView = StreamingTableView;
269
+ exports.TableView = TableView;
270
+ exports.TableViewPropsSchema = TableViewPropsSchema;
271
+ exports.validateTableViewProps = validateTableViewProps;
272
+ //# sourceMappingURL=display.cjs.map
273
+ //# sourceMappingURL=display.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/i18n/strings.ts","../src/components/display/TableView.schema.ts","../src/components/display/TableView.tsx"],"names":["z","jsx","useState","useEffect","jsxs","useRef","useVirtualizer","useCallback"],"mappings":";;;;;;;;;;AAaA,IAAM,EAAA,GAAK;AAAA,EACT,wBAAA,EAA0B,UAAA;AAAA,EAC1B,gCAAA,EAAkC,4BAAA;AAAA,EAClC,8BAAA,EAAgC,SAAA;AAAA,EAChC,6BAAA,EAA+B,QAAA;AAAA,EAC/B,2BAAA,EAA6B,qBAAA;AAAA,EAC7B,sBAAA,EAAwB,YAAA;AAAA,EACxB,2BAAA,EAA6B,WAAA;AAAA,EAC7B,2BAAA,EAA6B,eAAA;AAAA,EAC7B,yBAAA,EAA2B,oBAAA;AAAA,EAC3B,8BAAA,EAAgC,0BAAA;AAAA,EAChC,+BAAA,EAAiC,2BAAA;AAAA,EACjC,qCAAA,EAAuC,iCAAA;AAAA,EACvC,gCAAA,EAAkC,gCAAA;AAAA,EAClC,mCAAA,EAAqC,YAAA;AAAA,EACrC,oCAAA,EAAsC,OAAA;AAAA,EACtC,oCAAA,EAAsC,kDAAA;AAAA,EACtC,8BAAA,EAAgC,QAAA;AAAA,EAChC,yBAAA,EAA2B,QAAA;AAAA,EAC3B,gCAAA,EAAkC;AACpC,CAAA;AAEA,IAAM,EAAA,GAAsC;AAAA,EAC1C,wBAAA,EAA0B,aAAA;AAAA,EAC1B,gCAAA,EAAkC,0CAAA;AAAA,EAClC,8BAAA,EAAgC,WAAA;AAAA,EAChC,6BAAA,EAA+B,SAAA;AAAA,EAC/B,2BAAA,EAA6B,sCAAA;AAAA,EAC7B,sBAAA,EAAwB,uBAAA;AAAA,EACxB,2BAAA,EAA6B,eAAA;AAAA,EAC7B,2BAAA,EAA6B,uBAAA;AAAA,EAC7B,yBAAA,EAA2B,gCAAA;AAAA,EAC3B,8BAAA,EAAgC,wCAAA;AAAA,EAChC,+BAAA,EAAiC,wBAAA;AAAA,EACjC,qCAAA,EAAuC,+CAAA;AAAA,EACvC,gCAAA,EAAkC,4CAAA;AAAA,EAClC,mCAAA,EAAqC,iBAAA;AAAA,EACrC,oCAAA,EAAsC,QAAA;AAAA,EACtC,oCAAA,EACE,sEAAA;AAAA,EACF,8BAAA,EAAgC,UAAA;AAAA,EAChC,yBAAA,EAA2B,QAAA;AAAA,EAC3B,gCAAA,EAAkC;AACpC,CAAA;AAIA,IAAM,KAAA,GAA6D;AAAA,EACjE,EAAA,EAAI,EAAA;AAAA,EACJ,EAAA,EAAI;AACN,CAAA;AAGO,SAAS,CAAA,CAAE,GAAA,EAAoB,MAAA,GAAuB,IAAA,EAAc;AACzE,EAAA,OAAO,MAAM,MAAM,CAAA,GAAI,GAAG,CAAA,IAAK,KAAA,CAAM,GAAG,GAAG,CAAA;AAC7C;AC9DO,IAAM,eAAA,GAAkBA,MAAE,MAAA,CAAO;AAAA,EACtC,GAAA,EAAKA,KAAA,CAAE,MAAA,EAAO,CAAE,IAAI,CAAC,CAAA;AAAA,EACrB,MAAA,EAAQA,KAAA,CAAE,MAAA,EAAO,CAAE,IAAI,CAAC;AAAA;AAE1B,CAAC,CAAA;AAaM,IAAM,oBAAA,GAAuBA,MAAE,MAAA,CAAO;AAAA,EAC3C,SAASA,KAAA,CAAE,KAAA,CAAM,eAAe,CAAA,CAAE,GAAA,CAAI,GAAG,wCAAwC,CAAA;AAAA,EACjF,mBAAA,EAAqBA,MAAE,MAAA,EAAO,CAAE,KAAI,CAAE,QAAA,EAAS,CAAE,OAAA,CAAQ,GAAG,CAAA;AAAA,EAC5D,SAAA,EAAWA,KAAA,CAAE,MAAA,EAAO,CAAE,IAAI,CAAC,CAAA;AAAA,EAC3B,MAAA,EAAQA,MAAE,IAAA,CAAK,CAAC,MAAM,IAAI,CAAC,CAAA,CAAE,OAAA,CAAQ,IAAI;AAC3C,CAAC;AA+BM,SAAS,uBAAuB,GAAA,EAA0C;AAC/E,EAAA,OAAO,oBAAA,CAAqB,MAAM,GAAG,CAAA;AACvC;ACpDA,IAAM,QAAA,GAAW,CAAA;AAUV,SAAS,UACd,KAAA,EACA;AAEA,EAAA,IAAI,kBAAA,GAAqB,GAAA;AACzB,EAAA,IAAI;AACF,IAAA,MAAM,YAAY,sBAAA,CAAuB;AAAA,MACvC,OAAA,EAAS,KAAA,CAAM,OAAA,CAAQ,GAAA,CAAI,CAAC,EAAE,GAAA,EAAK,MAAA,EAAO,MAAO,EAAE,GAAA,EAAK,MAAA,EAAO,CAAE,CAAA;AAAA,MACjE,qBAAqB,KAAA,CAAM,mBAAA;AAAA,MAC3B,WAAW,KAAA,CAAM,SAAA;AAAA,MACjB,QAAQ,KAAA,CAAM;AAAA,KACf,CAAA;AACD,IAAA,kBAAA,GAAqB,SAAA,CAAU,mBAAA;AAAA,EACjC,CAAA,CAAA,MAAQ;AACN,IAAA,MAAM,MAAA,GAAuB,KAAA,CAAM,MAAA,KAAW,IAAA,GAAO,IAAA,GAAO,IAAA;AAC5D,IAAA,sCAAQ,KAAA,EAAA,EAAI,IAAA,EAAK,SAAS,QAAA,EAAA,CAAA,CAAE,8BAAA,EAAgC,MAAM,CAAA,EAAE,CAAA;AAAA,EACtE;AAEA,EAAA,MAAM,SAAA,GAAY,KAAA,CAAM,IAAA,CAAK,MAAA,GAAS,kBAAA;AACtC,EAAA,MAAM,cAAA,GAA+B,KAAA,CAAM,MAAA,KAAW,IAAA,GAAO,IAAA,GAAO,IAAA;AAEpE,EAAA,IAAI,SAAA,EAAW;AACb,IAAA,uBACEC,cAAA;AAAA,MAAC,YAAA;AAAA,MAAA;AAAA,QACC,MAAM,KAAA,CAAM,IAAA;AAAA,QACZ,SAAS,KAAA,CAAM,OAAA;AAAA,QACf,WAAW,KAAA,CAAM,SAAA;AAAA,QACjB,MAAA,EAAQ;AAAA;AAAA,KACV;AAAA,EAEJ;AAEA,EAAA,uBACEA,cAAA;AAAA,IAAC,WAAA;AAAA,IAAA;AAAA,MACC,MAAM,KAAA,CAAM,IAAA;AAAA,MACZ,SAAS,KAAA,CAAM,OAAA;AAAA,MACf,WAAW,KAAA,CAAM,SAAA;AAAA,MACjB,MAAA,EAAQ;AAAA;AAAA,GACV;AAEJ;AAYO,SAAS,mBACd,KAAA,EACA;AAEA,EAAA,IAAI,kBAAA,GAAqB,GAAA;AACzB,EAAA,IAAI;AACF,IAAA,MAAM,YAAY,sBAAA,CAAuB;AAAA,MACvC,OAAA,EAAS,KAAA,CAAM,OAAA,CAAQ,GAAA,CAAI,CAAC,EAAE,GAAA,EAAK,MAAA,EAAO,MAAO,EAAE,GAAA,EAAK,MAAA,EAAO,CAAE,CAAA;AAAA,MACjE,qBAAqB,KAAA,CAAM,mBAAA;AAAA,MAC3B,WAAW,KAAA,CAAM,SAAA;AAAA,MACjB,QAAQ,KAAA,CAAM;AAAA,KACf,CAAA;AACD,IAAA,kBAAA,GAAqB,SAAA,CAAU,mBAAA;AAAA,EACjC,CAAA,CAAA,MAAQ;AACN,IAAA,MAAM,MAAA,GAAuB,KAAA,CAAM,MAAA,KAAW,IAAA,GAAO,IAAA,GAAO,IAAA;AAC5D,IAAA,sCAAQ,KAAA,EAAA,EAAI,IAAA,EAAK,SAAS,QAAA,EAAA,CAAA,CAAE,8BAAA,EAAgC,MAAM,CAAA,EAAE,CAAA;AAAA,EACtE;AAEA,EAAA,uBAAOA,cAAA,CAAC,uBAAA,EAAA,EAA+B,GAAG,KAAA,EAAO,qBAAqB,kBAAA,EAAoB,CAAA;AAC5F;AAIA,SAAS,uBAAA,CAAwF;AAAA,EAC/F,OAAA;AAAA,EACA,KAAA;AAAA,EACA,mBAAA,GAAsB,GAAA;AAAA,EACtB,SAAA;AAAA,EACA;AACF,CAAA,EAAoE;AAClE,EAAA,MAAM,cAAA,GAA+B,MAAA,KAAW,IAAA,GAAO,IAAA,GAAO,IAAA;AAC9D,EAAA,MAAM,CAAC,IAAA,EAAM,OAAO,CAAA,GAAIC,cAAA,CAA0B,EAAE,CAAA;AAGpD,EAAAC,eAAA,CAAU,MAAM;AACd,IAAA,OAAA,CAAQ,EAAE,CAAA;AACV,IAAA,MAAM,GAAA,GAAM,KAAA,CAAM,SAAA,CAAU,CAAC,KAAA,KAAU;AACrC,MAAA,OAAA,CAAQ,CAAC,IAAA,KAAS,CAAC,GAAG,IAAA,EAAM,GAAG,KAAK,CAAC,CAAA;AAAA,IACvC,CAAC,CAAA;AACD,IAAA,OAAO,MAAM;AACX,MAAA,GAAA,CAAI,WAAA,EAAY;AAAA,IAClB,CAAA;AAAA,EACF,CAAA,EAAG,CAAC,KAAK,CAAC,CAAA;AAEV,EAAA,MAAM,SAAA,GAAY,KAAK,MAAA,GAAS,mBAAA;AAEhC,EAAA,IAAI,SAAA,EAAW;AACb,IAAA,uBACEF,cAAA;AAAA,MAAC,YAAA;AAAA,MAAA;AAAA,QACC,IAAA;AAAA,QACA,OAAA;AAAA,QACA,SAAA;AAAA,QACA,MAAA,EAAQ;AAAA;AAAA,KACV;AAAA,EAEJ;AAEA,EAAA,uBACEA,cAAA;AAAA,IAAC,WAAA;AAAA,IAAA;AAAA,MACC,IAAA;AAAA,MACA,OAAA;AAAA,MACA,SAAA;AAAA,MACA,MAAA,EAAQ;AAAA;AAAA,GACV;AAEJ;AAYA,SAAS,UAAA,CACP,KACA,GAAA,EACiB;AACjB,EAAA,IAAI,IAAI,MAAA,EAAQ;AACd,IAAA,OAAO,GAAA,CAAI,OAAO,GAAW,CAAA;AAAA,EAC/B;AACA,EAAA,OAAO,MAAA,CAAQ,GAAA,CAAgC,GAAA,CAAI,GAAG,KAAK,EAAE,CAAA;AAC/D;AAEA,SAAS,WAAA,CAAkD;AAAA,EACzD,IAAA;AAAA,EACA,OAAA;AAAA,EACA,SAAA;AAAA,EACA;AACF,CAAA,EAA4B;AAC1B,EAAA,MAAM,QAAA,GAAW,CAAA,CAAE,yBAAA,EAA2B,MAAM,CAAA;AACpD,EAAA,uBACEG,eAAA;AAAA,IAAC,OAAA;AAAA,IAAA;AAAA,MACC,YAAA,EAAY,SAAA;AAAA,MACZ,iBAAe,IAAA,CAAK,MAAA;AAAA,MACpB,KAAA,EAAO,EAAE,KAAA,EAAO,MAAA,EAAQ,gBAAgB,UAAA,EAAW;AAAA,MAEnD,QAAA,EAAA;AAAA,wBAAAH,cAAA,CAAC,WACC,QAAA,kBAAAA,cAAA,CAAC,IAAA,EAAA,EACE,QAAA,EAAA,OAAA,CAAQ,GAAA,CAAI,CAAC,GAAA,qBACZA,cAAA,CAAC,IAAA,EAAA,EAAiB,KAAA,EAAM,OACrB,QAAA,EAAA,GAAA,CAAI,MAAA,EAAA,EADE,IAAI,GAEb,CACD,GACH,CAAA,EACF,CAAA;AAAA,wBACAA,cAAA,CAAC,WACE,QAAA,EAAA,IAAA,CAAK,MAAA,KAAW,oBACfA,cAAA,CAAC,IAAA,EAAA,EACC,yCAAC,IAAA,EAAA,EAAG,OAAA,EAAS,QAAQ,MAAA,EAAQ,YAAA,EAAY,UACtC,QAAA,EAAA,QAAA,EACH,CAAA,EACF,IAEA,IAAA,CAAK,GAAA,CAAI,CAAC,GAAA,EAAK,QAAA,qBACbA,cAAA;AAAA,UAAC,IAAA;AAAA,UAAA;AAAA,YAMC,iBAAe,QAAA,GAAW,CAAA;AAAA,YAEzB,QAAA,EAAA,OAAA,CAAQ,GAAA,CAAI,CAAC,GAAA,qBACZA,cAAA,CAAC,IAAA,EAAA,EAAkB,QAAA,EAAA,UAAA,CAAW,GAAA,EAAK,GAAG,CAAA,EAAA,EAA7B,GAAA,CAAI,GAA2B,CACzC;AAAA,WAAA;AAAA,UARE,GAAA,CAAgC,MAAM,IAAA,GACnC,MAAA,CAAQ,IAAgC,EAAE,CAAA,GAC1C,OAAO,QAAQ,CAAA;AAAA,SAQxB,CAAA,EAEL;AAAA;AAAA;AAAA,GACF;AAEJ;AAIA,SAAS,YAAA,CAAmD;AAAA,EAC1D,IAAA;AAAA,EACA,OAAA;AAAA,EACA,SAAA;AAAA;AAAA,EAEA,MAAA,EAAQ;AACV,CAAA,EAA4B;AAC1B,EAAA,MAAM,SAAA,GAAYI,aAAuB,IAAI,CAAA;AAE7C,EAAA,MAAM,iBAAiBC,2BAAA,CAAe;AAAA,IACpC,OAAO,IAAA,CAAK,MAAA;AAAA;AAAA,IAEZ,gBAAA,EAAkB,MAAM,SAAA,CAAU,OAAA;AAAA,IAClC,YAAA,EAAcC,iBAAA,CAAY,MAAM,EAAA,EAAI,EAAE,CAAA;AAAA,IACtC,QAAA,EAAU;AAAA,GACX,CAAA;AAED,EAAA,MAAM,YAAA,GAAe,eAAe,eAAA,EAAgB;AACpD,EAAA,MAAM,SAAA,GAAY,eAAe,YAAA,EAAa;AAE9C,EAAA,uBACEN,cAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,cAAA,EAAa,MAAA;AAAA,MACb,GAAA,EAAK,SAAA;AAAA,MACL,OAAO,EAAE,MAAA,EAAQ,KAAK,QAAA,EAAU,MAAA,EAAQ,UAAU,UAAA,EAAW;AAAA,MAE7D,QAAA,kBAAAG,eAAA;AAAA,QAAC,OAAA;AAAA,QAAA;AAAA,UACC,YAAA,EAAY,SAAA;AAAA,UACZ,iBAAe,IAAA,CAAK,MAAA;AAAA,UACpB,KAAA,EAAO,EAAE,KAAA,EAAO,MAAA,EAAQ,gBAAgB,UAAA,EAAW;AAAA,UAEnD,QAAA,EAAA;AAAA,4BAAAH,cAAA,CAAC,WACC,QAAA,kBAAAA,cAAA,CAAC,IAAA,EAAA,EACE,QAAA,EAAA,OAAA,CAAQ,GAAA,CAAI,CAAC,GAAA,qBACZA,cAAA,CAAC,IAAA,EAAA,EAAiB,KAAA,EAAM,OACrB,QAAA,EAAA,GAAA,CAAI,MAAA,EAAA,EADE,IAAI,GAEb,CACD,GACH,CAAA,EACF,CAAA;AAAA,4BACAA,cAAA;AAAA,cAAC,OAAA;AAAA,cAAA;AAAA,gBACC,KAAA,EAAO;AAAA,kBACL,MAAA,EAAQ,GAAG,SAAS,CAAA,EAAA,CAAA;AAAA,kBACpB,QAAA,EAAU,UAAA;AAAA,kBACV,OAAA,EAAS;AAAA,iBACX;AAAA,gBAEC,QAAA,EAAA,YAAA,CAAa,GAAA,CAAI,CAAC,UAAA,KAAe;AAEhC,kBAAA,MAAM,GAAA,GAAM,IAAA,CAAK,UAAA,CAAW,KAAK,KAAM,EAAC;AACxC,kBAAA,uBACEA,cAAA;AAAA,oBAAC,IAAA;AAAA,oBAAA;AAAA,sBAMC,eAAA,EAAe,WAAW,KAAA,GAAQ,CAAA;AAAA,sBAClC,KAAA,EAAO;AAAA,wBACL,QAAA,EAAU,UAAA;AAAA,wBACV,GAAA,EAAK,CAAA;AAAA,wBACL,IAAA,EAAM,CAAA;AAAA,wBACN,KAAA,EAAO,MAAA;AAAA,wBACP,SAAA,EAAW,CAAA,WAAA,EAAc,UAAA,CAAW,KAAK,CAAA,GAAA,CAAA;AAAA,wBACzC,OAAA,EAAS;AAAA,uBACX;AAAA,sBAEC,kBAAQ,GAAA,CAAI,CAAC,GAAA,qBACZA,cAAA,CAAC,QAAiB,KAAA,EAAO,EAAE,IAAA,EAAM,CAAA,IAC9B,QAAA,EAAA,UAAA,CAAW,GAAA,EAAK,GAAG,CAAA,EAAA,EADb,GAAA,CAAI,GAEb,CACD;AAAA,qBAAA;AAAA,oBAlBE,GAAA,CAAgC,MAAM,IAAA,GACnC,MAAA,CAAQ,IAAgC,EAAE,CAAA,GAC1C,CAAA,KAAA,EAAQ,UAAA,CAAW,KAAK,CAAA;AAAA,mBAiBhC;AAAA,gBAEJ,CAAC;AAAA;AAAA;AACH;AAAA;AAAA;AACF;AAAA,GACF;AAEJ","file":"display.cjs","sourcesContent":["/**\n * Compile-time mirror of `@vantageos/mosaic-i18n` EN/FR locales for the 6\n * v0.1.0 components. Inlined here so that `<Comp>` renderers can resolve\n * `t(key, locale)` without dragging react-i18next into the component runtime\n * (keeps bundle small and tests provider-free). Drift is gated by\n * `mosaic-registry-drift-check.mjs` which validates the canonical\n * `packages/mosaic-i18n/src/locales/{en,fr}.json` against `registry.yaml`.\n *\n * Mosaic standard §8: production JSX MUST resolve user-facing strings via\n * `t()` — no hardcoded English literals.\n */\nexport type MosaicLocale = \"en\" | \"fr\";\n\nconst EN = {\n \"ProgressBar.aria.label\": \"Progress\",\n \"ProgressBar.error.invalidProps\": \"ProgressBar: invalid props\",\n \"ConfirmDialog.button.confirm\": \"Confirm\",\n \"ConfirmDialog.button.cancel\": \"Cancel\",\n \"ConfirmDialog.aria.dialog\": \"Confirmation dialog\",\n \"TableView.aria.table\": \"Data table\",\n \"TableView.pagination.next\": \"Next page\",\n \"TableView.pagination.prev\": \"Previous page\",\n \"TableView.empty.message\": \"No data to display\",\n \"TableView.error.invalidProps\": \"TableView: invalid props\",\n \"MarkdownRenderer.aria.content\": \"Rendered Markdown content\",\n \"MarkdownRenderer.error.invalidProps\": \"MarkdownRenderer: invalid props\",\n \"MarkdownRenderer.error.tooLong\": \"Content exceeds maximum length\",\n \"TokenDisplayOnceModal.button.copy\": \"Copy token\",\n \"TokenDisplayOnceModal.button.close\": \"Close\",\n \"TokenDisplayOnceModal.warning.once\": \"This token will only be shown once. Copy it now.\",\n \"TokenDisplayOnceModal.copied\": \"Copied\",\n \"StatusBadge.aria.status\": \"Status\",\n \"StatusBadge.error.invalidProps\": \"StatusBadge: invalid props\",\n} as const;\n\nconst FR: Record<keyof typeof EN, string> = {\n \"ProgressBar.aria.label\": \"Progression\",\n \"ProgressBar.error.invalidProps\": \"ProgressBar : propriétés invalides\",\n \"ConfirmDialog.button.confirm\": \"Confirmer\",\n \"ConfirmDialog.button.cancel\": \"Annuler\",\n \"ConfirmDialog.aria.dialog\": \"Boîte de dialogue de confirmation\",\n \"TableView.aria.table\": \"Tableau de données\",\n \"TableView.pagination.next\": \"Page suivante\",\n \"TableView.pagination.prev\": \"Page précédente\",\n \"TableView.empty.message\": \"Aucune donnée à afficher\",\n \"TableView.error.invalidProps\": \"TableView : propriétés invalides\",\n \"MarkdownRenderer.aria.content\": \"Contenu Markdown rendu\",\n \"MarkdownRenderer.error.invalidProps\": \"MarkdownRenderer : propriétés invalides\",\n \"MarkdownRenderer.error.tooLong\": \"Le contenu dépasse la longueur maximale\",\n \"TokenDisplayOnceModal.button.copy\": \"Copier le jeton\",\n \"TokenDisplayOnceModal.button.close\": \"Fermer\",\n \"TokenDisplayOnceModal.warning.once\":\n \"Ce jeton ne sera affiché qu'une seule fois. Copiez-le maintenant.\",\n \"TokenDisplayOnceModal.copied\": \"Copié\",\n \"StatusBadge.aria.status\": \"Statut\",\n \"StatusBadge.error.invalidProps\": \"StatusBadge : propriétés invalides\",\n};\n\nexport type MosaicI18nKey = keyof typeof EN;\n\nconst TABLE: Record<MosaicLocale, Record<MosaicI18nKey, string>> = {\n en: EN,\n fr: FR,\n};\n\n/** Resolves a Mosaic i18n key for the given locale, falling back to EN. */\nexport function t(key: MosaicI18nKey, locale: MosaicLocale = \"en\"): string {\n return TABLE[locale]?.[key] ?? TABLE.en[key];\n}\n","import type { ReactNode } from \"react\";\nimport type { Observable } from \"rxjs\";\nimport { z } from \"zod\";\n\n// i18nKeys: TableView.aria.table, TableView.pagination.next, TableView.pagination.prev, TableView.empty.message, TableView.error.invalidProps\n\nexport const ColumnDefSchema = z.object({\n key: z.string().min(1),\n header: z.string().min(1),\n // render is a runtime function — excluded from Zod, typed separately\n});\n\nexport type ColumnDef<TRow extends Record<string, unknown> = Record<string, unknown>> = {\n key: string;\n header: string;\n render?: (row: TRow) => ReactNode;\n};\n\n/**\n * Validates the serialisable (non-function) portion of TableView props.\n * The `rows$` Observable and `render` callbacks are not Zod-parseable and\n * must be validated at the call-site type level.\n */\nexport const TableViewPropsSchema = z.object({\n columns: z.array(ColumnDefSchema).min(1, \"TableView requires at least one column\"),\n virtualizeThreshold: z.number().int().positive().default(100),\n ariaLabel: z.string().min(1),\n locale: z.enum([\"en\", \"fr\"]).default(\"en\"),\n});\n\nexport type TableViewPropsSchemaInput = z.input<typeof TableViewPropsSchema>;\nexport type TableViewPropsSchemaOutput = z.output<typeof TableViewPropsSchema>;\n\n/**\n * Props for the static TableView — accepts a plain array of rows.\n * Primary API for already-fetched data (no rxjs required).\n */\nexport type TableViewProps<TRow extends Record<string, unknown> = Record<string, unknown>> = {\n columns: ColumnDef<TRow>[];\n rows: Partial<TRow>[];\n virtualizeThreshold?: number;\n ariaLabel: string;\n locale?: \"en\" | \"fr\";\n};\n\n/**\n * Props for StreamingTableView — accepts an RxJS Observable for incremental row appending.\n * Consumers using this variant MUST install rxjs ^7.8.0 in their project.\n */\nexport type StreamingTableViewProps<\n TRow extends Record<string, unknown> = Record<string, unknown>,\n> = {\n columns: ColumnDef<TRow>[];\n rows$: Observable<Partial<TRow>[]>;\n virtualizeThreshold?: number;\n ariaLabel: string;\n locale?: \"en\" | \"fr\";\n};\n\nexport function validateTableViewProps(raw: unknown): TableViewPropsSchemaOutput {\n return TableViewPropsSchema.parse(raw);\n}\n","// i18nKeys: TableView.aria.table, TableView.pagination.next, TableView.pagination.prev, TableView.empty.message, TableView.error.invalidProps\n\nimport { useVirtualizer } from \"@tanstack/react-virtual\";\nimport type React from \"react\";\nimport { useCallback, useEffect, useRef, useState } from \"react\";\nimport { type MosaicLocale, t } from \"../../i18n/strings.js\";\nimport { validateTableViewProps } from \"./TableView.schema\";\nimport type { StreamingTableViewProps, TableViewProps } from \"./TableView.schema\";\n\nconst OVERSCAN = 5;\n\n/**\n * TableView — Static rows variant (primary API).\n *\n * Accepts `rows: Row[]` for already-fetched data — no rxjs required.\n * Activates TanStack Virtual v3 windowing when rows.length > virtualizeThreshold.\n * Zod-validates serialisable props; renders role=\"alert\" fallback on failure.\n * Fully accessible: aria-rowcount, aria-label, scope=\"col\".\n */\nexport function TableView<TRow extends Record<string, unknown> = Record<string, unknown>>(\n props: TableViewProps<TRow>,\n) {\n // ── Zod validation (serialisable props only) ───────────────────────────────\n let validatedThreshold = 100;\n try {\n const validated = validateTableViewProps({\n columns: props.columns.map(({ key, header }) => ({ key, header })),\n virtualizeThreshold: props.virtualizeThreshold,\n ariaLabel: props.ariaLabel,\n locale: props.locale,\n });\n validatedThreshold = validated.virtualizeThreshold;\n } catch {\n const locale: MosaicLocale = props.locale === \"fr\" ? \"fr\" : \"en\";\n return <div role=\"alert\">{t(\"TableView.error.invalidProps\", locale)}</div>;\n }\n\n const isVirtual = props.rows.length > validatedThreshold;\n const resolvedLocale: MosaicLocale = props.locale === \"fr\" ? \"fr\" : \"en\";\n\n if (isVirtual) {\n return (\n <VirtualTable<TRow>\n rows={props.rows}\n columns={props.columns}\n ariaLabel={props.ariaLabel}\n locale={resolvedLocale}\n />\n );\n }\n\n return (\n <StaticTable<TRow>\n rows={props.rows}\n columns={props.columns}\n ariaLabel={props.ariaLabel}\n locale={resolvedLocale}\n />\n );\n}\n\n/**\n * StreamingTableView — Streaming rows variant (advanced, opt-in).\n *\n * Pattern 4 Streaming Hydration reference implementation.\n * Consumes an RxJS Observable<Row[]> for incremental row appending.\n * Consumers MUST install rxjs ^7.8.0 in their project.\n * Activates TanStack Virtual v3 windowing when rows.length > virtualizeThreshold.\n * Zod-validates serialisable props; renders role=\"alert\" fallback on failure.\n * Fully accessible: aria-rowcount, aria-label, scope=\"col\".\n */\nexport function StreamingTableView<TRow extends Record<string, unknown> = Record<string, unknown>>(\n props: StreamingTableViewProps<TRow>,\n) {\n // ── Zod validation (serialisable props only) ───────────────────────────────\n let validatedThreshold = 100;\n try {\n const validated = validateTableViewProps({\n columns: props.columns.map(({ key, header }) => ({ key, header })),\n virtualizeThreshold: props.virtualizeThreshold,\n ariaLabel: props.ariaLabel,\n locale: props.locale,\n });\n validatedThreshold = validated.virtualizeThreshold;\n } catch {\n const locale: MosaicLocale = props.locale === \"fr\" ? \"fr\" : \"en\";\n return <div role=\"alert\">{t(\"TableView.error.invalidProps\", locale)}</div>;\n }\n\n return <StreamingTableViewInner<TRow> {...props} virtualizeThreshold={validatedThreshold} />;\n}\n\n// ── Inner implementation for streaming (rendered only after validation passes) ──\n\nfunction StreamingTableViewInner<TRow extends Record<string, unknown> = Record<string, unknown>>({\n columns,\n rows$,\n virtualizeThreshold = 100,\n ariaLabel,\n locale,\n}: StreamingTableViewProps<TRow> & { virtualizeThreshold: number }) {\n const resolvedLocale: MosaicLocale = locale === \"fr\" ? \"fr\" : \"en\";\n const [rows, setRows] = useState<Partial<TRow>[]>([]);\n\n // Subscribe to the Observable and accumulate chunks\n useEffect(() => {\n setRows([]);\n const sub = rows$.subscribe((chunk) => {\n setRows((prev) => [...prev, ...chunk]);\n });\n return () => {\n sub.unsubscribe();\n };\n }, [rows$]);\n\n const isVirtual = rows.length > virtualizeThreshold;\n\n if (isVirtual) {\n return (\n <VirtualTable<TRow>\n rows={rows}\n columns={columns}\n ariaLabel={ariaLabel}\n locale={resolvedLocale}\n />\n );\n }\n\n return (\n <StaticTable<TRow>\n rows={rows}\n columns={columns}\n ariaLabel={ariaLabel}\n locale={resolvedLocale}\n />\n );\n}\n\n// ── Static table (rows <= virtualizeThreshold) ────────────────────────────────\n\ntype TableContentProps<TRow extends Record<string, unknown>> = {\n rows: Partial<TRow>[];\n columns: TableViewProps<TRow>[\"columns\"];\n ariaLabel: string;\n locale: MosaicLocale;\n};\n\n/** Renders a single cell — uses col.render if provided, else converts to string */\nfunction renderCell<TRow extends Record<string, unknown>>(\n col: TableViewProps<TRow>[\"columns\"][number],\n row: Partial<TRow>,\n): React.ReactNode {\n if (col.render) {\n return col.render(row as TRow);\n }\n return String((row as Record<string, unknown>)[col.key] ?? \"\");\n}\n\nfunction StaticTable<TRow extends Record<string, unknown>>({\n rows,\n columns,\n ariaLabel,\n locale,\n}: TableContentProps<TRow>) {\n const emptyMsg = t(\"TableView.empty.message\", locale);\n return (\n <table\n aria-label={ariaLabel}\n aria-rowcount={rows.length}\n style={{ width: \"100%\", borderCollapse: \"collapse\" }}\n >\n <thead>\n <tr>\n {columns.map((col) => (\n <th key={col.key} scope=\"col\">\n {col.header}\n </th>\n ))}\n </tr>\n </thead>\n <tbody>\n {rows.length === 0 ? (\n <tr>\n <td colSpan={columns.length} aria-label={emptyMsg}>\n {emptyMsg}\n </td>\n </tr>\n ) : (\n rows.map((row, rowIndex) => (\n <tr\n key={\n (row as Record<string, unknown>).id != null\n ? String((row as Record<string, unknown>).id)\n : `row-${rowIndex}`\n }\n aria-rowindex={rowIndex + 2}\n >\n {columns.map((col) => (\n <td key={col.key}>{renderCell(col, row)}</td>\n ))}\n </tr>\n ))\n )}\n </tbody>\n </table>\n );\n}\n\n// ── Virtual table (rows > virtualizeThreshold) — TanStack Virtual v3 ─────────\n\nfunction VirtualTable<TRow extends Record<string, unknown>>({\n rows,\n columns,\n ariaLabel,\n // locale reserved for future virtual-mode empty/pagination strings\n locale: _locale,\n}: TableContentProps<TRow>) {\n const scrollRef = useRef<HTMLDivElement>(null);\n\n const rowVirtualizer = useVirtualizer({\n count: rows.length,\n /* v8 ignore next 1 */\n getScrollElement: () => scrollRef.current,\n estimateSize: useCallback(() => 40, []),\n overscan: OVERSCAN,\n });\n\n const virtualItems = rowVirtualizer.getVirtualItems();\n const totalSize = rowVirtualizer.getTotalSize();\n\n return (\n <div\n data-virtual=\"true\"\n ref={scrollRef}\n style={{ height: 400, overflow: \"auto\", position: \"relative\" }}\n >\n <table\n aria-label={ariaLabel}\n aria-rowcount={rows.length}\n style={{ width: \"100%\", borderCollapse: \"collapse\" }}\n >\n <thead>\n <tr>\n {columns.map((col) => (\n <th key={col.key} scope=\"col\">\n {col.header}\n </th>\n ))}\n </tr>\n </thead>\n <tbody\n style={{\n height: `${totalSize}px`,\n position: \"relative\",\n display: \"block\",\n }}\n >\n {virtualItems.map((virtualRow) => {\n /* v8 ignore next */\n const row = rows[virtualRow.index] ?? ({} as Partial<TRow>);\n return (\n <tr\n key={\n (row as Record<string, unknown>).id != null\n ? String((row as Record<string, unknown>).id)\n : `vrow-${virtualRow.index}`\n }\n aria-rowindex={virtualRow.index + 2}\n style={{\n position: \"absolute\",\n top: 0,\n left: 0,\n width: \"100%\",\n transform: `translateY(${virtualRow.start}px)`,\n display: \"flex\",\n }}\n >\n {columns.map((col) => (\n <td key={col.key} style={{ flex: 1 }}>\n {renderCell(col, row)}\n </td>\n ))}\n </tr>\n );\n })}\n </tbody>\n </table>\n </div>\n );\n}\n"]}
@@ -0,0 +1,94 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { ReactNode } from 'react';
3
+ import { Observable } from 'rxjs';
4
+ import { z } from 'zod';
5
+
6
+ type ColumnDef<TRow extends Record<string, unknown> = Record<string, unknown>> = {
7
+ key: string;
8
+ header: string;
9
+ render?: (row: TRow) => ReactNode;
10
+ };
11
+ /**
12
+ * Validates the serialisable (non-function) portion of TableView props.
13
+ * The `rows$` Observable and `render` callbacks are not Zod-parseable and
14
+ * must be validated at the call-site type level.
15
+ */
16
+ declare const TableViewPropsSchema: z.ZodObject<{
17
+ columns: z.ZodArray<z.ZodObject<{
18
+ key: z.ZodString;
19
+ header: z.ZodString;
20
+ }, "strip", z.ZodTypeAny, {
21
+ key: string;
22
+ header: string;
23
+ }, {
24
+ key: string;
25
+ header: string;
26
+ }>, "many">;
27
+ virtualizeThreshold: z.ZodDefault<z.ZodNumber>;
28
+ ariaLabel: z.ZodString;
29
+ locale: z.ZodDefault<z.ZodEnum<["en", "fr"]>>;
30
+ }, "strip", z.ZodTypeAny, {
31
+ locale: "en" | "fr";
32
+ columns: {
33
+ key: string;
34
+ header: string;
35
+ }[];
36
+ virtualizeThreshold: number;
37
+ ariaLabel: string;
38
+ }, {
39
+ columns: {
40
+ key: string;
41
+ header: string;
42
+ }[];
43
+ ariaLabel: string;
44
+ locale?: "en" | "fr" | undefined;
45
+ virtualizeThreshold?: number | undefined;
46
+ }>;
47
+ type TableViewPropsSchemaInput = z.input<typeof TableViewPropsSchema>;
48
+ type TableViewPropsSchemaOutput = z.output<typeof TableViewPropsSchema>;
49
+ /**
50
+ * Props for the static TableView — accepts a plain array of rows.
51
+ * Primary API for already-fetched data (no rxjs required).
52
+ */
53
+ type TableViewProps<TRow extends Record<string, unknown> = Record<string, unknown>> = {
54
+ columns: ColumnDef<TRow>[];
55
+ rows: Partial<TRow>[];
56
+ virtualizeThreshold?: number;
57
+ ariaLabel: string;
58
+ locale?: "en" | "fr";
59
+ };
60
+ /**
61
+ * Props for StreamingTableView — accepts an RxJS Observable for incremental row appending.
62
+ * Consumers using this variant MUST install rxjs ^7.8.0 in their project.
63
+ */
64
+ type StreamingTableViewProps<TRow extends Record<string, unknown> = Record<string, unknown>> = {
65
+ columns: ColumnDef<TRow>[];
66
+ rows$: Observable<Partial<TRow>[]>;
67
+ virtualizeThreshold?: number;
68
+ ariaLabel: string;
69
+ locale?: "en" | "fr";
70
+ };
71
+ declare function validateTableViewProps(raw: unknown): TableViewPropsSchemaOutput;
72
+
73
+ /**
74
+ * TableView — Static rows variant (primary API).
75
+ *
76
+ * Accepts `rows: Row[]` for already-fetched data — no rxjs required.
77
+ * Activates TanStack Virtual v3 windowing when rows.length > virtualizeThreshold.
78
+ * Zod-validates serialisable props; renders role="alert" fallback on failure.
79
+ * Fully accessible: aria-rowcount, aria-label, scope="col".
80
+ */
81
+ declare function TableView<TRow extends Record<string, unknown> = Record<string, unknown>>(props: TableViewProps<TRow>): react_jsx_runtime.JSX.Element;
82
+ /**
83
+ * StreamingTableView — Streaming rows variant (advanced, opt-in).
84
+ *
85
+ * Pattern 4 Streaming Hydration reference implementation.
86
+ * Consumes an RxJS Observable<Row[]> for incremental row appending.
87
+ * Consumers MUST install rxjs ^7.8.0 in their project.
88
+ * Activates TanStack Virtual v3 windowing when rows.length > virtualizeThreshold.
89
+ * Zod-validates serialisable props; renders role="alert" fallback on failure.
90
+ * Fully accessible: aria-rowcount, aria-label, scope="col".
91
+ */
92
+ declare function StreamingTableView<TRow extends Record<string, unknown> = Record<string, unknown>>(props: StreamingTableViewProps<TRow>): react_jsx_runtime.JSX.Element;
93
+
94
+ export { type ColumnDef, StreamingTableView, type StreamingTableViewProps, TableView, type TableViewProps, TableViewPropsSchema, type TableViewPropsSchemaInput, type TableViewPropsSchemaOutput, validateTableViewProps };