@vantageos/mosaic 0.1.1 → 0.2.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 (110) 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/preact/artifacts.js +3 -0
  38. package/dist/preact/artifacts.js.map +1 -0
  39. package/dist/preact/confirmation.js +3 -0
  40. package/dist/preact/confirmation.js.map +1 -0
  41. package/dist/preact/display.js +3 -0
  42. package/dist/preact/display.js.map +1 -0
  43. package/dist/preact/index.js +3 -0
  44. package/dist/preact/index.js.map +1 -0
  45. package/dist/preact/input.js +3 -0
  46. package/dist/preact/input.js.map +1 -0
  47. package/dist/preact/media.js +3 -0
  48. package/dist/preact/media.js.map +1 -0
  49. package/dist/preact/progress.js +3 -0
  50. package/dist/preact/progress.js.map +1 -0
  51. package/dist/progress.cjs +125 -0
  52. package/dist/progress.cjs.map +1 -0
  53. package/dist/progress.d.cts +29 -0
  54. package/dist/progress.d.ts +29 -0
  55. package/dist/progress.js +121 -0
  56. package/dist/progress.js.map +1 -0
  57. package/dist/react/artifacts.cjs +4 -0
  58. package/dist/react/artifacts.cjs.map +1 -0
  59. package/dist/react/artifacts.d.cts +2 -0
  60. package/dist/react/artifacts.d.ts +2 -0
  61. package/dist/react/artifacts.js +3 -0
  62. package/dist/react/artifacts.js.map +1 -0
  63. package/dist/react/confirmation.cjs +4 -0
  64. package/dist/react/confirmation.cjs.map +1 -0
  65. package/dist/react/confirmation.d.cts +2 -0
  66. package/dist/react/confirmation.d.ts +2 -0
  67. package/dist/react/confirmation.js +3 -0
  68. package/dist/react/confirmation.js.map +1 -0
  69. package/dist/react/display.cjs +4 -0
  70. package/dist/react/display.cjs.map +1 -0
  71. package/dist/react/display.d.cts +2 -0
  72. package/dist/react/display.d.ts +2 -0
  73. package/dist/react/display.js +3 -0
  74. package/dist/react/display.js.map +1 -0
  75. package/dist/react/index.cjs +4 -0
  76. package/dist/react/index.cjs.map +1 -0
  77. package/dist/react/index.d.cts +2 -0
  78. package/dist/react/index.d.ts +2 -0
  79. package/dist/react/index.js +3 -0
  80. package/dist/react/index.js.map +1 -0
  81. package/dist/react/input.cjs +4 -0
  82. package/dist/react/input.cjs.map +1 -0
  83. package/dist/react/input.d.cts +2 -0
  84. package/dist/react/input.d.ts +2 -0
  85. package/dist/react/input.js +3 -0
  86. package/dist/react/input.js.map +1 -0
  87. package/dist/react/media.cjs +4 -0
  88. package/dist/react/media.cjs.map +1 -0
  89. package/dist/react/media.d.cts +2 -0
  90. package/dist/react/media.d.ts +2 -0
  91. package/dist/react/media.js +3 -0
  92. package/dist/react/media.js.map +1 -0
  93. package/dist/react/progress.cjs +4 -0
  94. package/dist/react/progress.cjs.map +1 -0
  95. package/dist/react/progress.d.cts +2 -0
  96. package/dist/react/progress.d.ts +2 -0
  97. package/dist/react/progress.js +3 -0
  98. package/dist/react/progress.js.map +1 -0
  99. package/dist/server.cjs +121 -0
  100. package/dist/server.cjs.map +1 -0
  101. package/dist/server.d.cts +33 -0
  102. package/dist/server.d.ts +33 -0
  103. package/dist/server.js +116 -0
  104. package/dist/server.js.map +1 -0
  105. package/dist/tokens.cjs +95 -0
  106. package/dist/tokens.cjs.map +1 -0
  107. package/dist/tokens.js +84 -0
  108. package/dist/tokens.js.map +1 -0
  109. package/package.json +127 -9
  110. package/registry.yaml +1 -1
@@ -0,0 +1,113 @@
1
+ 'use strict';
2
+
3
+ var DOMPurify = require('dompurify');
4
+ var marked = require('marked');
5
+ var zod = require('zod');
6
+ var jsxRuntime = require('react/jsx-runtime');
7
+
8
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
9
+
10
+ var DOMPurify__default = /*#__PURE__*/_interopDefault(DOMPurify);
11
+
12
+ // src/components/artifacts/MarkdownRenderer.tsx
13
+
14
+ // src/i18n/strings.ts
15
+ var EN = {
16
+ "ProgressBar.aria.label": "Progress",
17
+ "ProgressBar.error.invalidProps": "ProgressBar: invalid props",
18
+ "ConfirmDialog.button.confirm": "Confirm",
19
+ "ConfirmDialog.button.cancel": "Cancel",
20
+ "ConfirmDialog.aria.dialog": "Confirmation dialog",
21
+ "TableView.aria.table": "Data table",
22
+ "TableView.pagination.next": "Next page",
23
+ "TableView.pagination.prev": "Previous page",
24
+ "TableView.empty.message": "No data to display",
25
+ "TableView.error.invalidProps": "TableView: invalid props",
26
+ "MarkdownRenderer.aria.content": "Rendered Markdown content",
27
+ "MarkdownRenderer.error.invalidProps": "MarkdownRenderer: invalid props",
28
+ "MarkdownRenderer.error.tooLong": "Content exceeds maximum length",
29
+ "TokenDisplayOnceModal.button.copy": "Copy token",
30
+ "TokenDisplayOnceModal.button.close": "Close",
31
+ "TokenDisplayOnceModal.warning.once": "This token will only be shown once. Copy it now.",
32
+ "TokenDisplayOnceModal.copied": "Copied",
33
+ "StatusBadge.aria.status": "Status",
34
+ "StatusBadge.error.invalidProps": "StatusBadge: invalid props"
35
+ };
36
+ var FR = {
37
+ "ProgressBar.aria.label": "Progression",
38
+ "ProgressBar.error.invalidProps": "ProgressBar : propri\xE9t\xE9s invalides",
39
+ "ConfirmDialog.button.confirm": "Confirmer",
40
+ "ConfirmDialog.button.cancel": "Annuler",
41
+ "ConfirmDialog.aria.dialog": "Bo\xEEte de dialogue de confirmation",
42
+ "TableView.aria.table": "Tableau de donn\xE9es",
43
+ "TableView.pagination.next": "Page suivante",
44
+ "TableView.pagination.prev": "Page pr\xE9c\xE9dente",
45
+ "TableView.empty.message": "Aucune donn\xE9e \xE0 afficher",
46
+ "TableView.error.invalidProps": "TableView : propri\xE9t\xE9s invalides",
47
+ "MarkdownRenderer.aria.content": "Contenu Markdown rendu",
48
+ "MarkdownRenderer.error.invalidProps": "MarkdownRenderer : propri\xE9t\xE9s invalides",
49
+ "MarkdownRenderer.error.tooLong": "Le contenu d\xE9passe la longueur maximale",
50
+ "TokenDisplayOnceModal.button.copy": "Copier le jeton",
51
+ "TokenDisplayOnceModal.button.close": "Fermer",
52
+ "TokenDisplayOnceModal.warning.once": "Ce jeton ne sera affich\xE9 qu'une seule fois. Copiez-le maintenant.",
53
+ "TokenDisplayOnceModal.copied": "Copi\xE9",
54
+ "StatusBadge.aria.status": "Statut",
55
+ "StatusBadge.error.invalidProps": "StatusBadge : propri\xE9t\xE9s invalides"
56
+ };
57
+ var TABLE = {
58
+ en: EN,
59
+ fr: FR
60
+ };
61
+ function t(key, locale = "en") {
62
+ return TABLE[locale]?.[key] ?? TABLE.en[key];
63
+ }
64
+ var MarkdownRendererPropsSchema = zod.z.object({
65
+ content: zod.z.string(),
66
+ locale: zod.z.enum(["en", "fr"]),
67
+ maxLength: zod.z.number().positive().default(5e4),
68
+ allowHtml: zod.z.boolean().default(false)
69
+ });
70
+ function validateProps(raw) {
71
+ return MarkdownRendererPropsSchema.parse(raw);
72
+ }
73
+ var tooLongMessages = {
74
+ en: "Content exceeds maximum length.",
75
+ fr: "Le contenu d\xE9passe la longueur maximale."
76
+ };
77
+ function MarkdownRendererInner({
78
+ content,
79
+ locale,
80
+ maxLength,
81
+ allowHtml
82
+ }) {
83
+ if (content.length > maxLength) {
84
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { role: "alert", lang: locale, children: tooLongMessages[locale] });
85
+ }
86
+ const source = allowHtml ? content : content.replace(/<[^>]*>/g, "");
87
+ const rawHtml = marked.marked.parse(source, { async: false });
88
+ const cleanHtml = DOMPurify__default.default.sanitize(rawHtml);
89
+ const ariaLabel = locale === "fr" ? "Contenu format\xE9" : "Formatted content";
90
+ return /* @__PURE__ */ jsxRuntime.jsx(
91
+ "article",
92
+ {
93
+ "aria-label": ariaLabel,
94
+ lang: locale,
95
+ dangerouslySetInnerHTML: { __html: cleanHtml }
96
+ }
97
+ );
98
+ }
99
+ function MarkdownRenderer(raw) {
100
+ try {
101
+ const props = validateProps(raw);
102
+ return /* @__PURE__ */ jsxRuntime.jsx(MarkdownRendererInner, { ...props });
103
+ } catch {
104
+ const locale = raw.locale === "fr" ? "fr" : "en";
105
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { role: "alert", children: t("MarkdownRenderer.error.invalidProps", locale) });
106
+ }
107
+ }
108
+
109
+ exports.MarkdownRenderer = MarkdownRenderer;
110
+ exports.MarkdownRendererPropsSchema = MarkdownRendererPropsSchema;
111
+ exports.validateMarkdownRendererProps = validateProps;
112
+ //# sourceMappingURL=artifacts.cjs.map
113
+ //# sourceMappingURL=artifacts.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/i18n/strings.ts","../src/components/artifacts/MarkdownRenderer.schema.ts","../src/components/artifacts/MarkdownRenderer.tsx"],"names":["z","jsx","marked","DOMPurify"],"mappings":"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","file":"artifacts.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 { z } from \"zod\";\n\nexport const MarkdownRendererPropsSchema = z.object({\n content: z.string(),\n locale: z.enum([\"en\", \"fr\"]),\n maxLength: z.number().positive().default(50000),\n allowHtml: z.boolean().default(false),\n});\n\nexport type MarkdownRendererProps = z.infer<typeof MarkdownRendererPropsSchema>;\n\nexport function validateProps(raw: unknown): MarkdownRendererProps {\n return MarkdownRendererPropsSchema.parse(raw);\n}\n","import DOMPurify from \"dompurify\";\nimport { marked } from \"marked\";\n// i18nKeys: MarkdownRenderer.aria.content, MarkdownRenderer.error.invalidProps, MarkdownRenderer.error.tooLong\nimport React from \"react\";\nimport { type MosaicLocale, t } from \"../../i18n/strings.js\";\nimport { type MarkdownRendererProps, validateProps } from \"./MarkdownRenderer.schema\";\n\ninterface MarkdownRendererInnerProps {\n content: string;\n locale: \"en\" | \"fr\";\n maxLength: number;\n allowHtml: boolean;\n}\n\nconst tooLongMessages: Record<\"en\" | \"fr\", string> = {\n en: \"Content exceeds maximum length.\",\n fr: \"Le contenu dépasse la longueur maximale.\",\n};\n\nfunction MarkdownRendererInner({\n content,\n locale,\n maxLength,\n allowHtml,\n}: MarkdownRendererInnerProps) {\n if (content.length > maxLength) {\n return (\n <div role=\"alert\" lang={locale}>\n {tooLongMessages[locale]}\n </div>\n );\n }\n\n // When allowHtml=false, strip raw HTML tags from source before parsing,\n // so user-supplied HTML is neutralised before marked converts markdown to HTML.\n const source = allowHtml ? content : content.replace(/<[^>]*>/g, \"\");\n const rawHtml = marked.parse(source, { async: false }) as string;\n // Always sanitize the marked output to prevent XSS from markdown-injected HTML.\n const cleanHtml = DOMPurify.sanitize(rawHtml);\n\n const ariaLabel = locale === \"fr\" ? \"Contenu formaté\" : \"Formatted content\";\n\n return (\n <article\n aria-label={ariaLabel}\n lang={locale}\n // biome-ignore lint/security/noDangerouslySetInnerHtml: sanitized by DOMPurify\n dangerouslySetInnerHTML={{ __html: cleanHtml }}\n />\n );\n}\n\n/**\n * MarkdownRenderer accepts any props object for JSX and MCP postMessage injection alike.\n * Internal Zod validation narrows the type — invalid data renders an accessible error fallback.\n */\nexport function MarkdownRenderer(raw: Record<string, unknown>) {\n try {\n const props = validateProps(raw);\n return <MarkdownRendererInner {...props} />;\n } catch {\n const locale: MosaicLocale = raw.locale === \"fr\" ? \"fr\" : \"en\";\n return <div role=\"alert\">{t(\"MarkdownRenderer.error.invalidProps\", locale)}</div>;\n }\n}\n"]}
@@ -0,0 +1,29 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { z } from 'zod';
3
+
4
+ /**
5
+ * MarkdownRenderer accepts any props object for JSX and MCP postMessage injection alike.
6
+ * Internal Zod validation narrows the type — invalid data renders an accessible error fallback.
7
+ */
8
+ declare function MarkdownRenderer(raw: Record<string, unknown>): react_jsx_runtime.JSX.Element;
9
+
10
+ declare const MarkdownRendererPropsSchema: z.ZodObject<{
11
+ content: z.ZodString;
12
+ locale: z.ZodEnum<["en", "fr"]>;
13
+ maxLength: z.ZodDefault<z.ZodNumber>;
14
+ allowHtml: z.ZodDefault<z.ZodBoolean>;
15
+ }, "strip", z.ZodTypeAny, {
16
+ locale: "en" | "fr";
17
+ content: string;
18
+ maxLength: number;
19
+ allowHtml: boolean;
20
+ }, {
21
+ locale: "en" | "fr";
22
+ content: string;
23
+ maxLength?: number | undefined;
24
+ allowHtml?: boolean | undefined;
25
+ }>;
26
+ type MarkdownRendererProps = z.infer<typeof MarkdownRendererPropsSchema>;
27
+ declare function validateProps(raw: unknown): MarkdownRendererProps;
28
+
29
+ export { MarkdownRenderer, type MarkdownRendererProps, MarkdownRendererPropsSchema, validateProps as validateMarkdownRendererProps };
@@ -0,0 +1,29 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { z } from 'zod';
3
+
4
+ /**
5
+ * MarkdownRenderer accepts any props object for JSX and MCP postMessage injection alike.
6
+ * Internal Zod validation narrows the type — invalid data renders an accessible error fallback.
7
+ */
8
+ declare function MarkdownRenderer(raw: Record<string, unknown>): react_jsx_runtime.JSX.Element;
9
+
10
+ declare const MarkdownRendererPropsSchema: z.ZodObject<{
11
+ content: z.ZodString;
12
+ locale: z.ZodEnum<["en", "fr"]>;
13
+ maxLength: z.ZodDefault<z.ZodNumber>;
14
+ allowHtml: z.ZodDefault<z.ZodBoolean>;
15
+ }, "strip", z.ZodTypeAny, {
16
+ locale: "en" | "fr";
17
+ content: string;
18
+ maxLength: number;
19
+ allowHtml: boolean;
20
+ }, {
21
+ locale: "en" | "fr";
22
+ content: string;
23
+ maxLength?: number | undefined;
24
+ allowHtml?: boolean | undefined;
25
+ }>;
26
+ type MarkdownRendererProps = z.infer<typeof MarkdownRendererPropsSchema>;
27
+ declare function validateProps(raw: unknown): MarkdownRendererProps;
28
+
29
+ export { MarkdownRenderer, type MarkdownRendererProps, MarkdownRendererPropsSchema, validateProps as validateMarkdownRendererProps };
@@ -0,0 +1,105 @@
1
+ import DOMPurify from 'dompurify';
2
+ import { marked } from 'marked';
3
+ import { z } from 'zod';
4
+ import { jsx } from 'react/jsx-runtime';
5
+
6
+ // src/components/artifacts/MarkdownRenderer.tsx
7
+
8
+ // src/i18n/strings.ts
9
+ var EN = {
10
+ "ProgressBar.aria.label": "Progress",
11
+ "ProgressBar.error.invalidProps": "ProgressBar: invalid props",
12
+ "ConfirmDialog.button.confirm": "Confirm",
13
+ "ConfirmDialog.button.cancel": "Cancel",
14
+ "ConfirmDialog.aria.dialog": "Confirmation dialog",
15
+ "TableView.aria.table": "Data table",
16
+ "TableView.pagination.next": "Next page",
17
+ "TableView.pagination.prev": "Previous page",
18
+ "TableView.empty.message": "No data to display",
19
+ "TableView.error.invalidProps": "TableView: invalid props",
20
+ "MarkdownRenderer.aria.content": "Rendered Markdown content",
21
+ "MarkdownRenderer.error.invalidProps": "MarkdownRenderer: invalid props",
22
+ "MarkdownRenderer.error.tooLong": "Content exceeds maximum length",
23
+ "TokenDisplayOnceModal.button.copy": "Copy token",
24
+ "TokenDisplayOnceModal.button.close": "Close",
25
+ "TokenDisplayOnceModal.warning.once": "This token will only be shown once. Copy it now.",
26
+ "TokenDisplayOnceModal.copied": "Copied",
27
+ "StatusBadge.aria.status": "Status",
28
+ "StatusBadge.error.invalidProps": "StatusBadge: invalid props"
29
+ };
30
+ var FR = {
31
+ "ProgressBar.aria.label": "Progression",
32
+ "ProgressBar.error.invalidProps": "ProgressBar : propri\xE9t\xE9s invalides",
33
+ "ConfirmDialog.button.confirm": "Confirmer",
34
+ "ConfirmDialog.button.cancel": "Annuler",
35
+ "ConfirmDialog.aria.dialog": "Bo\xEEte de dialogue de confirmation",
36
+ "TableView.aria.table": "Tableau de donn\xE9es",
37
+ "TableView.pagination.next": "Page suivante",
38
+ "TableView.pagination.prev": "Page pr\xE9c\xE9dente",
39
+ "TableView.empty.message": "Aucune donn\xE9e \xE0 afficher",
40
+ "TableView.error.invalidProps": "TableView : propri\xE9t\xE9s invalides",
41
+ "MarkdownRenderer.aria.content": "Contenu Markdown rendu",
42
+ "MarkdownRenderer.error.invalidProps": "MarkdownRenderer : propri\xE9t\xE9s invalides",
43
+ "MarkdownRenderer.error.tooLong": "Le contenu d\xE9passe la longueur maximale",
44
+ "TokenDisplayOnceModal.button.copy": "Copier le jeton",
45
+ "TokenDisplayOnceModal.button.close": "Fermer",
46
+ "TokenDisplayOnceModal.warning.once": "Ce jeton ne sera affich\xE9 qu'une seule fois. Copiez-le maintenant.",
47
+ "TokenDisplayOnceModal.copied": "Copi\xE9",
48
+ "StatusBadge.aria.status": "Statut",
49
+ "StatusBadge.error.invalidProps": "StatusBadge : propri\xE9t\xE9s invalides"
50
+ };
51
+ var TABLE = {
52
+ en: EN,
53
+ fr: FR
54
+ };
55
+ function t(key, locale = "en") {
56
+ return TABLE[locale]?.[key] ?? TABLE.en[key];
57
+ }
58
+ var MarkdownRendererPropsSchema = z.object({
59
+ content: z.string(),
60
+ locale: z.enum(["en", "fr"]),
61
+ maxLength: z.number().positive().default(5e4),
62
+ allowHtml: z.boolean().default(false)
63
+ });
64
+ function validateProps(raw) {
65
+ return MarkdownRendererPropsSchema.parse(raw);
66
+ }
67
+ var tooLongMessages = {
68
+ en: "Content exceeds maximum length.",
69
+ fr: "Le contenu d\xE9passe la longueur maximale."
70
+ };
71
+ function MarkdownRendererInner({
72
+ content,
73
+ locale,
74
+ maxLength,
75
+ allowHtml
76
+ }) {
77
+ if (content.length > maxLength) {
78
+ return /* @__PURE__ */ jsx("div", { role: "alert", lang: locale, children: tooLongMessages[locale] });
79
+ }
80
+ const source = allowHtml ? content : content.replace(/<[^>]*>/g, "");
81
+ const rawHtml = marked.parse(source, { async: false });
82
+ const cleanHtml = DOMPurify.sanitize(rawHtml);
83
+ const ariaLabel = locale === "fr" ? "Contenu format\xE9" : "Formatted content";
84
+ return /* @__PURE__ */ jsx(
85
+ "article",
86
+ {
87
+ "aria-label": ariaLabel,
88
+ lang: locale,
89
+ dangerouslySetInnerHTML: { __html: cleanHtml }
90
+ }
91
+ );
92
+ }
93
+ function MarkdownRenderer(raw) {
94
+ try {
95
+ const props = validateProps(raw);
96
+ return /* @__PURE__ */ jsx(MarkdownRendererInner, { ...props });
97
+ } catch {
98
+ const locale = raw.locale === "fr" ? "fr" : "en";
99
+ return /* @__PURE__ */ jsx("div", { role: "alert", children: t("MarkdownRenderer.error.invalidProps", locale) });
100
+ }
101
+ }
102
+
103
+ export { MarkdownRenderer, MarkdownRendererPropsSchema, validateProps as validateMarkdownRendererProps };
104
+ //# sourceMappingURL=artifacts.js.map
105
+ //# sourceMappingURL=artifacts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/i18n/strings.ts","../src/components/artifacts/MarkdownRenderer.schema.ts","../src/components/artifacts/MarkdownRenderer.tsx"],"names":[],"mappings":"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","file":"artifacts.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\nexport const MarkdownRendererPropsSchema = z.object({\n content: z.string(),\n locale: z.enum([\"en\", \"fr\"]),\n maxLength: z.number().positive().default(50000),\n allowHtml: z.boolean().default(false),\n});\n\nexport type MarkdownRendererProps = z.infer<typeof MarkdownRendererPropsSchema>;\n\nexport function validateProps(raw: unknown): MarkdownRendererProps {\n return MarkdownRendererPropsSchema.parse(raw);\n}\n","import DOMPurify from \"dompurify\";\nimport { marked } from \"marked\";\n// i18nKeys: MarkdownRenderer.aria.content, MarkdownRenderer.error.invalidProps, MarkdownRenderer.error.tooLong\nimport React from \"react\";\nimport { type MosaicLocale, t } from \"../../i18n/strings.js\";\nimport { type MarkdownRendererProps, validateProps } from \"./MarkdownRenderer.schema\";\n\ninterface MarkdownRendererInnerProps {\n content: string;\n locale: \"en\" | \"fr\";\n maxLength: number;\n allowHtml: boolean;\n}\n\nconst tooLongMessages: Record<\"en\" | \"fr\", string> = {\n en: \"Content exceeds maximum length.\",\n fr: \"Le contenu dépasse la longueur maximale.\",\n};\n\nfunction MarkdownRendererInner({\n content,\n locale,\n maxLength,\n allowHtml,\n}: MarkdownRendererInnerProps) {\n if (content.length > maxLength) {\n return (\n <div role=\"alert\" lang={locale}>\n {tooLongMessages[locale]}\n </div>\n );\n }\n\n // When allowHtml=false, strip raw HTML tags from source before parsing,\n // so user-supplied HTML is neutralised before marked converts markdown to HTML.\n const source = allowHtml ? content : content.replace(/<[^>]*>/g, \"\");\n const rawHtml = marked.parse(source, { async: false }) as string;\n // Always sanitize the marked output to prevent XSS from markdown-injected HTML.\n const cleanHtml = DOMPurify.sanitize(rawHtml);\n\n const ariaLabel = locale === \"fr\" ? \"Contenu formaté\" : \"Formatted content\";\n\n return (\n <article\n aria-label={ariaLabel}\n lang={locale}\n // biome-ignore lint/security/noDangerouslySetInnerHtml: sanitized by DOMPurify\n dangerouslySetInnerHTML={{ __html: cleanHtml }}\n />\n );\n}\n\n/**\n * MarkdownRenderer accepts any props object for JSX and MCP postMessage injection alike.\n * Internal Zod validation narrows the type — invalid data renders an accessible error fallback.\n */\nexport function MarkdownRenderer(raw: Record<string, unknown>) {\n try {\n const props = validateProps(raw);\n return <MarkdownRendererInner {...props} />;\n } catch {\n const locale: MosaicLocale = raw.locale === \"fr\" ? \"fr\" : \"en\";\n return <div role=\"alert\">{t(\"MarkdownRenderer.error.invalidProps\", locale)}</div>;\n }\n}\n"]}
@@ -0,0 +1,180 @@
1
+ 'use strict';
2
+
3
+ var react = require('react');
4
+ var zod = require('zod');
5
+ var jsxRuntime = require('react/jsx-runtime');
6
+
7
+ // src/components/confirmation/TokenDisplayOnceModal.tsx
8
+
9
+ // src/i18n/strings.ts
10
+ var EN = {
11
+ "ProgressBar.aria.label": "Progress",
12
+ "ProgressBar.error.invalidProps": "ProgressBar: invalid props",
13
+ "ConfirmDialog.button.confirm": "Confirm",
14
+ "ConfirmDialog.button.cancel": "Cancel",
15
+ "ConfirmDialog.aria.dialog": "Confirmation dialog",
16
+ "TableView.aria.table": "Data table",
17
+ "TableView.pagination.next": "Next page",
18
+ "TableView.pagination.prev": "Previous page",
19
+ "TableView.empty.message": "No data to display",
20
+ "TableView.error.invalidProps": "TableView: invalid props",
21
+ "MarkdownRenderer.aria.content": "Rendered Markdown content",
22
+ "MarkdownRenderer.error.invalidProps": "MarkdownRenderer: invalid props",
23
+ "MarkdownRenderer.error.tooLong": "Content exceeds maximum length",
24
+ "TokenDisplayOnceModal.button.copy": "Copy token",
25
+ "TokenDisplayOnceModal.button.close": "Close",
26
+ "TokenDisplayOnceModal.warning.once": "This token will only be shown once. Copy it now.",
27
+ "TokenDisplayOnceModal.copied": "Copied",
28
+ "StatusBadge.aria.status": "Status",
29
+ "StatusBadge.error.invalidProps": "StatusBadge: invalid props"
30
+ };
31
+ var FR = {
32
+ "ProgressBar.aria.label": "Progression",
33
+ "ProgressBar.error.invalidProps": "ProgressBar : propri\xE9t\xE9s invalides",
34
+ "ConfirmDialog.button.confirm": "Confirmer",
35
+ "ConfirmDialog.button.cancel": "Annuler",
36
+ "ConfirmDialog.aria.dialog": "Bo\xEEte de dialogue de confirmation",
37
+ "TableView.aria.table": "Tableau de donn\xE9es",
38
+ "TableView.pagination.next": "Page suivante",
39
+ "TableView.pagination.prev": "Page pr\xE9c\xE9dente",
40
+ "TableView.empty.message": "Aucune donn\xE9e \xE0 afficher",
41
+ "TableView.error.invalidProps": "TableView : propri\xE9t\xE9s invalides",
42
+ "MarkdownRenderer.aria.content": "Contenu Markdown rendu",
43
+ "MarkdownRenderer.error.invalidProps": "MarkdownRenderer : propri\xE9t\xE9s invalides",
44
+ "MarkdownRenderer.error.tooLong": "Le contenu d\xE9passe la longueur maximale",
45
+ "TokenDisplayOnceModal.button.copy": "Copier le jeton",
46
+ "TokenDisplayOnceModal.button.close": "Fermer",
47
+ "TokenDisplayOnceModal.warning.once": "Ce jeton ne sera affich\xE9 qu'une seule fois. Copiez-le maintenant.",
48
+ "TokenDisplayOnceModal.copied": "Copi\xE9",
49
+ "StatusBadge.aria.status": "Statut",
50
+ "StatusBadge.error.invalidProps": "StatusBadge : propri\xE9t\xE9s invalides"
51
+ };
52
+ var TABLE = {
53
+ en: EN,
54
+ fr: FR
55
+ };
56
+ function t(key, locale = "en") {
57
+ return TABLE[locale]?.[key] ?? TABLE.en[key];
58
+ }
59
+ var TokenDisplayOnceModalPropsSchema = zod.z.object({
60
+ token: zod.z.string().min(1),
61
+ title: zod.z.string().min(1),
62
+ warningMessage: zod.z.string().min(1),
63
+ copyLabel: zod.z.string().min(1),
64
+ closeLabel: zod.z.string().min(1),
65
+ locale: zod.z.enum(["en", "fr"]).default("en")
66
+ });
67
+ function validateTokenDisplayOnceModalProps(raw) {
68
+ return TokenDisplayOnceModalPropsSchema.parse(raw);
69
+ }
70
+ function TokenDisplayOnceModalInner({
71
+ token,
72
+ title,
73
+ warningMessage,
74
+ copyLabel,
75
+ closeLabel,
76
+ locale,
77
+ onClose
78
+ }) {
79
+ const dialogRef = react.useRef(null);
80
+ const titleId = react.useId();
81
+ const warningId = react.useId();
82
+ const [copied, setCopied] = react.useState(false);
83
+ const [secureToken] = react.useState(token);
84
+ react.useEffect(() => {
85
+ const dialog = dialogRef.current;
86
+ if (!dialog) return;
87
+ dialog.showModal();
88
+ return () => {
89
+ if (dialog.open) dialog.close();
90
+ };
91
+ }, []);
92
+ async function handleCopy() {
93
+ try {
94
+ await navigator.clipboard.writeText(secureToken);
95
+ setCopied(true);
96
+ setTimeout(() => setCopied(false), 2e3);
97
+ } catch {
98
+ setCopied(false);
99
+ }
100
+ }
101
+ function handleKeyDown(e) {
102
+ if (e.key === "Escape") {
103
+ e.preventDefault();
104
+ onClose();
105
+ }
106
+ }
107
+ function handleBackdropClick(e) {
108
+ if (e.target === dialogRef.current) {
109
+ onClose();
110
+ }
111
+ }
112
+ return /* @__PURE__ */ jsxRuntime.jsx(
113
+ "dialog",
114
+ {
115
+ ref: dialogRef,
116
+ "aria-modal": "true",
117
+ "aria-labelledby": titleId,
118
+ "aria-describedby": warningId,
119
+ onKeyDown: handleKeyDown,
120
+ onClick: handleBackdropClick,
121
+ className: "rounded-lg shadow-xl p-0 backdrop:bg-black/40 w-full max-w-lg mx-auto",
122
+ children: /* @__PURE__ */ jsxRuntime.jsxs(
123
+ "div",
124
+ {
125
+ className: "p-6 flex flex-col gap-4",
126
+ onClick: (e) => e.stopPropagation(),
127
+ onKeyDown: (e) => e.stopPropagation(),
128
+ children: [
129
+ /* @__PURE__ */ jsxRuntime.jsx("h2", { id: titleId, className: "text-lg font-semibold text-gray-900", children: title }),
130
+ /* @__PURE__ */ jsxRuntime.jsx(
131
+ "p",
132
+ {
133
+ id: warningId,
134
+ className: "text-sm text-amber-700 bg-amber-50 border border-amber-200 rounded-md px-3 py-2",
135
+ children: warningMessage
136
+ }
137
+ ),
138
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-2 bg-gray-50 border border-gray-200 rounded-md px-3 py-2", children: /* @__PURE__ */ jsxRuntime.jsx("code", { className: "flex-1 text-sm font-mono text-gray-800 break-all select-all", children: secureToken }) }),
139
+ /* @__PURE__ */ jsxRuntime.jsx("output", { "aria-live": "polite", "aria-atomic": "true", className: "min-h-[1.25rem] block", children: copied && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-green-700 font-medium", children: t("TokenDisplayOnceModal.copied", locale) }) }),
140
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-end gap-3 mt-2", children: [
141
+ /* @__PURE__ */ jsxRuntime.jsx(
142
+ "button",
143
+ {
144
+ type: "button",
145
+ onClick: handleCopy,
146
+ 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",
147
+ children: copyLabel
148
+ }
149
+ ),
150
+ /* @__PURE__ */ jsxRuntime.jsx(
151
+ "button",
152
+ {
153
+ type: "button",
154
+ onClick: onClose,
155
+ 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",
156
+ children: closeLabel
157
+ }
158
+ )
159
+ ] })
160
+ ]
161
+ }
162
+ )
163
+ }
164
+ );
165
+ }
166
+ function TokenDisplayOnceModal(raw) {
167
+ try {
168
+ const parsed = validateTokenDisplayOnceModalProps(raw);
169
+ return /* @__PURE__ */ jsxRuntime.jsx(TokenDisplayOnceModalInner, { ...parsed, onClose: raw.onClose });
170
+ } catch (err) {
171
+ console.warn("[TokenDisplayOnceModal] Invalid props \u2014 component will not render.", err);
172
+ return null;
173
+ }
174
+ }
175
+
176
+ exports.TokenDisplayOnceModal = TokenDisplayOnceModal;
177
+ exports.TokenDisplayOnceModalPropsSchema = TokenDisplayOnceModalPropsSchema;
178
+ exports.validateTokenDisplayOnceModalProps = validateTokenDisplayOnceModalProps;
179
+ //# sourceMappingURL=confirmation.cjs.map
180
+ //# sourceMappingURL=confirmation.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/i18n/strings.ts","../src/components/confirmation/TokenDisplayOnceModal.schema.ts","../src/components/confirmation/TokenDisplayOnceModal.tsx"],"names":["z","useRef","useId","useState","useEffect","jsx","jsxs"],"mappings":"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","file":"confirmation.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 { 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,33 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { z } from 'zod';
3
+
4
+ declare const TokenDisplayOnceModalPropsSchema: z.ZodObject<{
5
+ token: z.ZodString;
6
+ title: z.ZodString;
7
+ warningMessage: z.ZodString;
8
+ copyLabel: z.ZodString;
9
+ closeLabel: z.ZodString;
10
+ locale: z.ZodDefault<z.ZodEnum<["en", "fr"]>>;
11
+ }, "strip", z.ZodTypeAny, {
12
+ locale: "en" | "fr";
13
+ title: string;
14
+ token: string;
15
+ warningMessage: string;
16
+ copyLabel: string;
17
+ closeLabel: string;
18
+ }, {
19
+ title: string;
20
+ token: string;
21
+ warningMessage: string;
22
+ copyLabel: string;
23
+ closeLabel: string;
24
+ locale?: "en" | "fr" | undefined;
25
+ }>;
26
+ type TokenDisplayOnceModalProps = z.infer<typeof TokenDisplayOnceModalPropsSchema> & {
27
+ onClose: () => void;
28
+ };
29
+ declare function validateTokenDisplayOnceModalProps(raw: unknown): z.infer<typeof TokenDisplayOnceModalPropsSchema>;
30
+
31
+ declare function TokenDisplayOnceModal(raw: Omit<TokenDisplayOnceModalProps, "locale"> & Partial<Pick<TokenDisplayOnceModalProps, "locale">>): react_jsx_runtime.JSX.Element | null;
32
+
33
+ export { TokenDisplayOnceModal, type TokenDisplayOnceModalProps, TokenDisplayOnceModalPropsSchema, validateTokenDisplayOnceModalProps };
@@ -0,0 +1,33 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { z } from 'zod';
3
+
4
+ declare const TokenDisplayOnceModalPropsSchema: z.ZodObject<{
5
+ token: z.ZodString;
6
+ title: z.ZodString;
7
+ warningMessage: z.ZodString;
8
+ copyLabel: z.ZodString;
9
+ closeLabel: z.ZodString;
10
+ locale: z.ZodDefault<z.ZodEnum<["en", "fr"]>>;
11
+ }, "strip", z.ZodTypeAny, {
12
+ locale: "en" | "fr";
13
+ title: string;
14
+ token: string;
15
+ warningMessage: string;
16
+ copyLabel: string;
17
+ closeLabel: string;
18
+ }, {
19
+ title: string;
20
+ token: string;
21
+ warningMessage: string;
22
+ copyLabel: string;
23
+ closeLabel: string;
24
+ locale?: "en" | "fr" | undefined;
25
+ }>;
26
+ type TokenDisplayOnceModalProps = z.infer<typeof TokenDisplayOnceModalPropsSchema> & {
27
+ onClose: () => void;
28
+ };
29
+ declare function validateTokenDisplayOnceModalProps(raw: unknown): z.infer<typeof TokenDisplayOnceModalPropsSchema>;
30
+
31
+ declare function TokenDisplayOnceModal(raw: Omit<TokenDisplayOnceModalProps, "locale"> & Partial<Pick<TokenDisplayOnceModalProps, "locale">>): react_jsx_runtime.JSX.Element | null;
32
+
33
+ export { TokenDisplayOnceModal, type TokenDisplayOnceModalProps, TokenDisplayOnceModalPropsSchema, validateTokenDisplayOnceModalProps };