@singleton-sd/post-kit-editor 0.4.0 → 0.6.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.
- package/README.md +68 -14
- package/dist/EditorErrorBoundary.d.ts +15 -0
- package/dist/EditorErrorBoundary.js +32 -0
- package/dist/EditorErrorBoundary.js.map +1 -0
- package/dist/canvas/EmailBuilderCanvas.js +2 -2
- package/dist/canvas/EmailBuilderCanvas.js.map +1 -1
- package/dist/editor-shell-states.d.ts +8 -0
- package/dist/editor-shell-states.js +15 -0
- package/dist/editor-shell-states.js.map +1 -0
- package/dist/email-template-editor.d.ts +9 -3
- package/dist/email-template-editor.js +137 -3
- package/dist/email-template-editor.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +4 -1
- package/dist/index.js.map +1 -1
- package/dist/metadata/MetadataPanel.d.ts +3 -1
- package/dist/metadata/MetadataPanel.js +15 -3
- package/dist/metadata/MetadataPanel.js.map +1 -1
- package/dist/preview/PreviewDataEditor.d.ts +3 -1
- package/dist/preview/PreviewDataEditor.js +9 -2
- package/dist/preview/PreviewDataEditor.js.map +1 -1
- package/dist/preview/PreviewPane.d.ts +3 -1
- package/dist/preview/PreviewPane.js +5 -1
- package/dist/preview/PreviewPane.js.map +1 -1
- package/dist/save-send/SaveSendBar.d.ts +12 -0
- package/dist/save-send/SaveSendBar.js +43 -0
- package/dist/save-send/SaveSendBar.js.map +1 -0
- package/dist/save-send/dirty.d.ts +3 -0
- package/dist/save-send/dirty.js +27 -0
- package/dist/save-send/dirty.js.map +1 -0
- package/dist/save-send/recipient.d.ts +1 -0
- package/dist/save-send/recipient.js +15 -0
- package/dist/save-send/recipient.js.map +1 -0
- package/dist/save-send/types.d.ts +21 -0
- package/dist/save-send/types.js +27 -0
- package/dist/save-send/types.js.map +1 -0
- package/dist/validation/ValidationSummary.d.ts +5 -0
- package/dist/validation/ValidationSummary.js +29 -0
- package/dist/validation/ValidationSummary.js.map +1 -0
- package/dist/validation/extract-placeholders.d.ts +2 -0
- package/dist/validation/extract-placeholders.js +49 -0
- package/dist/validation/extract-placeholders.js.map +1 -0
- package/dist/validation/validate.d.ts +17 -0
- package/dist/validation/validate.js +154 -0
- package/dist/validation/validate.js.map +1 -0
- package/dist/variables/VariableCatalogue.js +1 -1
- package/dist/variables/VariableCatalogue.js.map +1 -1
- package/package.json +1 -1
|
@@ -4,13 +4,15 @@ exports.PreviewDataEditor = PreviewDataEditor;
|
|
|
4
4
|
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
5
5
|
const react_1 = require("react");
|
|
6
6
|
const email_template_editor_1 = require("../email-template-editor");
|
|
7
|
+
const validate_1 = require("../validation/validate");
|
|
7
8
|
const preview_rows_1 = require("./preview-rows");
|
|
8
|
-
function PreviewDataEditor({ declaredVariables, previewData, onChange, }) {
|
|
9
|
+
function PreviewDataEditor({ declaredVariables, previewData, onChange, issues = [], }) {
|
|
9
10
|
const p = email_template_editor_1.EDITOR_CLASS_PREFIX;
|
|
10
11
|
const rows = (0, preview_rows_1.buildPreviewRows)(declaredVariables, previewData);
|
|
11
12
|
const [newKey, setNewKey] = (0, react_1.useState)('');
|
|
12
13
|
const [addError, setAddError] = (0, react_1.useState)(null);
|
|
13
14
|
const addInputId = (0, react_1.useId)();
|
|
15
|
+
const issuesForKey = (key) => issues.filter((i) => i.field === 'previewData' && i.variable === key);
|
|
14
16
|
const handleValueChange = (0, react_1.useCallback)((key, value) => {
|
|
15
17
|
onChange((0, preview_rows_1.setPreviewValue)(previewData, key, value));
|
|
16
18
|
}, [onChange, previewData]);
|
|
@@ -29,7 +31,12 @@ function PreviewDataEditor({ declaredVariables, previewData, onChange, }) {
|
|
|
29
31
|
setNewKey('');
|
|
30
32
|
onChange(next);
|
|
31
33
|
}, [newKey, onChange, previewData]);
|
|
32
|
-
return ((0, jsx_runtime_1.jsxs)("section", { className: `${p}preview-data`, "data-testid": `${p}preview-data`, children: [(0, jsx_runtime_1.jsx)("h2", { className: `${p}preview-data-heading`, children: "Preview data" }), (0, jsx_runtime_1.jsx)("p", { className: `${p}preview-data-hint`, children: "Sample values only \u2014 never real personal data. These are committed with the template source." }), (0, jsx_runtime_1.jsx)("ul", { className: `${p}preview-data-list`, "data-testid": `${p}preview-data-list`, children: rows.map((row) =>
|
|
34
|
+
return ((0, jsx_runtime_1.jsxs)("section", { className: `${p}preview-data`, "data-testid": `${p}preview-data`, children: [(0, jsx_runtime_1.jsx)("h2", { className: `${p}preview-data-heading`, children: "Preview data" }), (0, jsx_runtime_1.jsx)("p", { className: `${p}preview-data-hint`, children: "Sample values only \u2014 never real personal data. These are committed with the template source." }), (0, jsx_runtime_1.jsx)("ul", { className: `${p}preview-data-list`, "data-testid": `${p}preview-data-list`, children: rows.map((row) => {
|
|
35
|
+
const rowIssues = issuesForKey(row.key);
|
|
36
|
+
const describedBy = rowIssues.map((i) => (0, validate_1.inlineIssueId)(i.code, i.variable)).join(' ');
|
|
37
|
+
const inputId = `${p}preview-${(0, validate_1.domIdSegment)(row.key)}`;
|
|
38
|
+
return ((0, jsx_runtime_1.jsxs)("li", { className: `${p}preview-data-row${row.extra ? ` ${p}preview-data-row-extra` : ''}`, "data-testid": `${p}preview-data-row`, "data-extra": row.extra ? 'true' : 'false', "data-key": row.key, children: [(0, jsx_runtime_1.jsxs)("label", { className: `${p}preview-data-key`, htmlFor: inputId, children: [row.key, row.extra ? ((0, jsx_runtime_1.jsx)("span", { className: `${p}preview-data-extra-badge`, "data-testid": `${p}preview-extra`, children: "extra" })) : null] }), (0, jsx_runtime_1.jsx)("input", { id: inputId, className: `${p}preview-data-value`, type: "text", value: row.value, onChange: (event) => handleValueChange(row.key, event.target.value), "data-testid": `${p}preview-value-${row.key}`, autoComplete: "off", spellCheck: false, "aria-invalid": rowIssues.length > 0, "aria-describedby": describedBy || undefined }), rowIssues.map((issue) => ((0, jsx_runtime_1.jsxs)("p", { id: (0, validate_1.inlineIssueId)(issue.code, issue.variable), className: `${p}preview-data-row-error`, "data-testid": `${p}preview-validation-${row.key}`, role: "status", children: [(0, jsx_runtime_1.jsx)("span", { "aria-hidden": "true", children: issue.severity === 'error' ? '!' : 'i' }), ' ', issue.message] }, `${issue.code}:${issue.variable}`))), (0, jsx_runtime_1.jsx)("button", { type: "button", className: `${p}preview-data-remove`, onClick: () => handleRemove(row.key), "data-testid": `${p}preview-remove-${row.key}`, "aria-label": `Remove preview value ${row.key}`, children: "Remove" })] }, row.key));
|
|
39
|
+
}) }), (0, jsx_runtime_1.jsxs)("form", { className: `${p}preview-data-add`, onSubmit: handleAdd, "data-testid": `${p}preview-data-add`, children: [(0, jsx_runtime_1.jsx)("label", { className: `${p}preview-data-label`, htmlFor: addInputId, children: "Add preview key" }), (0, jsx_runtime_1.jsx)("input", { id: addInputId, className: `${p}preview-data-input`, type: "text", value: newKey, onChange: (event) => {
|
|
33
40
|
setNewKey(event.target.value);
|
|
34
41
|
setAddError(null);
|
|
35
42
|
}, placeholder: "variable.name", autoComplete: "off", spellCheck: false, "data-testid": `${p}preview-add-key` }), (0, jsx_runtime_1.jsx)("button", { type: "submit", className: `${p}preview-data-add-button`, "data-testid": `${p}preview-add`, children: "Add" }), addError ? ((0, jsx_runtime_1.jsx)("p", { className: `${p}preview-data-error`, "data-testid": `${p}preview-add-error`, role: "status", children: addError })) : null] })] }));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PreviewDataEditor.js","sourceRoot":"","sources":["../../src/preview/PreviewDataEditor.tsx"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"PreviewDataEditor.js","sourceRoot":"","sources":["../../src/preview/PreviewDataEditor.tsx"],"names":[],"mappings":"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"}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import type { TemplateSourceFiles } from '../types';
|
|
2
|
+
import { type PreviewRenderResult } from './render-template-preview';
|
|
2
3
|
export interface PreviewPaneProps {
|
|
3
4
|
files: TemplateSourceFiles;
|
|
4
5
|
onPreviewRendered?: (html: string) => void;
|
|
6
|
+
onPreviewResultChange?: (result: PreviewRenderResult | null) => void;
|
|
5
7
|
debounceMs?: number;
|
|
6
8
|
}
|
|
7
|
-
export declare function PreviewPane({ files, onPreviewRendered, debounceMs, }: PreviewPaneProps): JSX.Element;
|
|
9
|
+
export declare function PreviewPane({ files, onPreviewRendered, onPreviewResultChange, debounceMs, }: PreviewPaneProps): JSX.Element;
|
|
@@ -6,15 +6,18 @@ const react_1 = require("react");
|
|
|
6
6
|
const email_template_editor_1 = require("../email-template-editor");
|
|
7
7
|
const preview_frame_1 = require("./preview-frame");
|
|
8
8
|
const render_template_preview_1 = require("./render-template-preview");
|
|
9
|
-
function PreviewPane({ files, onPreviewRendered, debounceMs = render_template_preview_1.PREVIEW_DEBOUNCE_MS, }) {
|
|
9
|
+
function PreviewPane({ files, onPreviewRendered, onPreviewResultChange, debounceMs = render_template_preview_1.PREVIEW_DEBOUNCE_MS, }) {
|
|
10
10
|
const p = email_template_editor_1.EDITOR_CLASS_PREFIX;
|
|
11
11
|
const [result, setResult] = (0, react_1.useState)(null);
|
|
12
12
|
const [pending, setPending] = (0, react_1.useState)(true);
|
|
13
13
|
const onPreviewRenderedRef = (0, react_1.useRef)(onPreviewRendered);
|
|
14
14
|
onPreviewRenderedRef.current = onPreviewRendered;
|
|
15
|
+
const onPreviewResultChangeRef = (0, react_1.useRef)(onPreviewResultChange);
|
|
16
|
+
onPreviewResultChangeRef.current = onPreviewResultChange;
|
|
15
17
|
const requestIdRef = (0, react_1.useRef)(0);
|
|
16
18
|
(0, react_1.useEffect)(() => {
|
|
17
19
|
setPending(true);
|
|
20
|
+
onPreviewResultChangeRef.current?.(null);
|
|
18
21
|
const requestId = ++requestIdRef.current;
|
|
19
22
|
const timer = setTimeout(() => {
|
|
20
23
|
void (async () => {
|
|
@@ -24,6 +27,7 @@ function PreviewPane({ files, onPreviewRendered, debounceMs = render_template_pr
|
|
|
24
27
|
}
|
|
25
28
|
setResult(next);
|
|
26
29
|
setPending(false);
|
|
30
|
+
onPreviewResultChangeRef.current?.(next);
|
|
27
31
|
if (next.ok) {
|
|
28
32
|
onPreviewRenderedRef.current?.(next.html);
|
|
29
33
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PreviewPane.js","sourceRoot":"","sources":["../../src/preview/PreviewPane.tsx"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"PreviewPane.js","sourceRoot":"","sources":["../../src/preview/PreviewPane.tsx"],"names":[],"mappings":";;AAoCA,kCA6DC;;AAjGD,iCAA2D;AAE3D,oEAA+D;AAE/D,mDAAmE;AACnE,uEAImC;AA2BnC,SAAgB,WAAW,CAAC,EAC1B,KAAK,EACL,iBAAiB,EACjB,qBAAqB,EACrB,UAAU,GAAG,6CAAmB,GACf;IACjB,MAAM,CAAC,GAAG,2CAAmB,CAAC;IAC9B,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,IAAA,gBAAQ,EAA6B,IAAI,CAAC,CAAC;IACvE,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,IAAA,gBAAQ,EAAC,IAAI,CAAC,CAAC;IAC7C,MAAM,oBAAoB,GAAG,IAAA,cAAM,EAAC,iBAAiB,CAAC,CAAC;IACvD,oBAAoB,CAAC,OAAO,GAAG,iBAAiB,CAAC;IACjD,MAAM,wBAAwB,GAAG,IAAA,cAAM,EAAC,qBAAqB,CAAC,CAAC;IAC/D,wBAAwB,CAAC,OAAO,GAAG,qBAAqB,CAAC;IACzD,MAAM,YAAY,GAAG,IAAA,cAAM,EAAC,CAAC,CAAC,CAAC;IAE/B,IAAA,iBAAS,EAAC,GAAG,EAAE;QACb,UAAU,CAAC,IAAI,CAAC,CAAC;QAGjB,wBAAwB,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,CAAC;QACzC,MAAM,SAAS,GAAG,EAAE,YAAY,CAAC,OAAO,CAAC;QACzC,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE;YAC5B,KAAK,CAAC,KAAK,IAAI,EAAE;gBACf,MAAM,IAAI,GAAG,MAAM,IAAA,+CAAqB,EAAC,KAAK,CAAC,CAAC;gBAEhD,IAAI,SAAS,KAAK,YAAY,CAAC,OAAO,EAAE,CAAC;oBACvC,OAAO;gBACT,CAAC;gBACD,SAAS,CAAC,IAAI,CAAC,CAAC;gBAChB,UAAU,CAAC,KAAK,CAAC,CAAC;gBAClB,wBAAwB,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,CAAC;gBACzC,IAAI,IAAI,CAAC,EAAE,EAAE,CAAC;oBACZ,oBAAoB,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBAC5C,CAAC;YACH,CAAC,CAAC,EAAE,CAAC;QACP,CAAC,EAAE,UAAU,CAAC,CAAC;QAEf,OAAO,GAAG,EAAE;YACV,YAAY,CAAC,KAAK,CAAC,CAAC;YAEpB,YAAY,CAAC,OAAO,IAAI,CAAC,CAAC;QAC5B,CAAC,CAAC;IACJ,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC,CAAC;IAExB,OAAO,CACL,qCAAS,SAAS,EAAE,GAAG,CAAC,cAAc,iBAAe,GAAG,CAAC,cAAc,aACrE,+BAAI,SAAS,EAAE,GAAG,CAAC,sBAAsB,wBAAc,EACtD,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,CACjB,8BAAG,SAAS,EAAE,GAAG,CAAC,qBAAqB,iBAAe,GAAG,CAAC,iBAAiB,wCAEvE,CACL,CAAC,CAAC,CAAC,IAAI,EACP,OAAO,IAAI,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,CAC5B,8BAAG,SAAS,EAAE,GAAG,CAAC,qBAAqB,iBAAe,GAAG,CAAC,kBAAkB,uCAExE,CACL,CAAC,CAAC,CAAC,IAAI,EACP,MAAM,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,uBAAC,kCAAkB,IAAC,OAAO,EAAE,MAAM,CAAC,KAAK,GAAI,CAAC,CAAC,CAAC,IAAI,EAC3E,MAAM,EAAE,EAAE,CAAC,CAAC,CAAC,uBAAC,4BAAY,IAAC,IAAI,EAAE,MAAM,CAAC,IAAI,GAAI,CAAC,CAAC,CAAC,IAAI,IAChD,CACX,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { ActionFeedback } from './types';
|
|
2
|
+
export interface SaveSendBarProps {
|
|
3
|
+
saveFeedback: ActionFeedback;
|
|
4
|
+
sendFeedback: ActionFeedback;
|
|
5
|
+
busy: boolean;
|
|
6
|
+
validationBlocked?: boolean;
|
|
7
|
+
validationBlockedReason?: string;
|
|
8
|
+
showSendTest: boolean;
|
|
9
|
+
onSave: () => void;
|
|
10
|
+
onSendTest: (recipient: string) => void;
|
|
11
|
+
}
|
|
12
|
+
export declare function SaveSendBar({ saveFeedback, sendFeedback, busy, validationBlocked, validationBlockedReason, showSendTest, onSave, onSendTest, }: SaveSendBarProps): JSX.Element;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SaveSendBar = SaveSendBar;
|
|
4
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
5
|
+
const react_1 = require("react");
|
|
6
|
+
const email_template_editor_1 = require("../email-template-editor");
|
|
7
|
+
const recipient_1 = require("./recipient");
|
|
8
|
+
function SaveSendBar({ saveFeedback, sendFeedback, busy, validationBlocked = false, validationBlockedReason = 'Fix validation errors before saving.', showSendTest, onSave, onSendTest, }) {
|
|
9
|
+
const p = email_template_editor_1.EDITOR_CLASS_PREFIX;
|
|
10
|
+
const recipientId = (0, react_1.useId)();
|
|
11
|
+
const blockedId = (0, react_1.useId)();
|
|
12
|
+
const [recipient, setRecipient] = (0, react_1.useState)('');
|
|
13
|
+
const [recipientError, setRecipientError] = (0, react_1.useState)(null);
|
|
14
|
+
const controlsDisabled = busy || validationBlocked;
|
|
15
|
+
const handleSend = (event) => {
|
|
16
|
+
event.preventDefault();
|
|
17
|
+
if (controlsDisabled) {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
const error = (0, recipient_1.validateSendTestRecipient)(recipient);
|
|
21
|
+
if (error) {
|
|
22
|
+
setRecipientError(error);
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
setRecipientError(null);
|
|
26
|
+
onSendTest(recipient.trim());
|
|
27
|
+
};
|
|
28
|
+
return ((0, jsx_runtime_1.jsxs)("section", { className: `${p}save-send`, "data-testid": `${p}save-send`, children: [(0, jsx_runtime_1.jsx)("h2", { className: `${p}save-send-heading`, children: showSendTest ? 'Save & send test' : 'Save' }), validationBlocked ? ((0, jsx_runtime_1.jsx)("p", { id: blockedId, className: `${p}save-send-blocked`, "data-testid": `${p}save-blocked-reason`, role: "status", children: validationBlockedReason })) : null, (0, jsx_runtime_1.jsxs)("div", { className: `${p}save-send-actions`, children: [(0, jsx_runtime_1.jsx)("button", { type: "button", className: `${p}save-button`, "data-testid": `${p}save`, disabled: controlsDisabled, "aria-describedby": validationBlocked ? blockedId : undefined, onClick: onSave, children: saveFeedback.status === 'pending' ? 'Saving…' : 'Save' }), (0, jsx_runtime_1.jsx)(ActionStatusMessage, { feedback: saveFeedback, testId: `${p}save-status`, successLabel: "Saved." })] }), showSendTest ? ((0, jsx_runtime_1.jsxs)("form", { className: `${p}send-test`, "data-testid": `${p}send-test`, onSubmit: handleSend, children: [(0, jsx_runtime_1.jsx)("label", { className: `${p}send-test-label`, htmlFor: recipientId, children: "Send test to" }), (0, jsx_runtime_1.jsx)("input", { id: recipientId, className: `${p}send-test-input`, type: "email", value: recipient, disabled: controlsDisabled, autoComplete: "off", spellCheck: false, placeholder: "you@example.com", "data-testid": `${p}send-test-recipient`, onChange: (event) => {
|
|
29
|
+
setRecipient(event.target.value);
|
|
30
|
+
setRecipientError(null);
|
|
31
|
+
} }), (0, jsx_runtime_1.jsx)("button", { type: "submit", className: `${p}send-test-button`, "data-testid": `${p}send-test-submit`, disabled: controlsDisabled, "aria-describedby": validationBlocked ? blockedId : undefined, children: sendFeedback.status === 'pending' ? 'Sending…' : 'Send test' }), recipientError ? ((0, jsx_runtime_1.jsx)("p", { className: `${p}send-test-error`, "data-testid": `${p}send-test-invalid`, role: "status", children: recipientError })) : null, (0, jsx_runtime_1.jsx)(ActionStatusMessage, { feedback: sendFeedback, testId: `${p}send-test-status`, successLabel: "Test send completed." })] })) : null] }));
|
|
32
|
+
}
|
|
33
|
+
function ActionStatusMessage({ feedback, testId, successLabel, }) {
|
|
34
|
+
const p = email_template_editor_1.EDITOR_CLASS_PREFIX;
|
|
35
|
+
if (feedback.status === 'idle' || feedback.status === 'pending') {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
const text = feedback.status === 'success'
|
|
39
|
+
? (feedback.message ?? successLabel)
|
|
40
|
+
: (feedback.message ?? 'Something went wrong.');
|
|
41
|
+
return ((0, jsx_runtime_1.jsx)("p", { className: `${p}action-status ${p}action-status-${feedback.status}`, "data-testid": testId, role: feedback.status === 'failure' ? 'alert' : 'status', children: text }));
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=SaveSendBar.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SaveSendBar.js","sourceRoot":"","sources":["../../src/save-send/SaveSendBar.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.stableStringify = stableStringify;
|
|
4
|
+
exports.isWorkingDirty = isWorkingDirty;
|
|
5
|
+
function stableStringify(value) {
|
|
6
|
+
return JSON.stringify(sortKeys(value));
|
|
7
|
+
}
|
|
8
|
+
function sortKeys(value) {
|
|
9
|
+
if (value === null || typeof value !== 'object') {
|
|
10
|
+
return value;
|
|
11
|
+
}
|
|
12
|
+
if (Array.isArray(value)) {
|
|
13
|
+
return value.map(sortKeys);
|
|
14
|
+
}
|
|
15
|
+
const record = value;
|
|
16
|
+
const sorted = {};
|
|
17
|
+
for (const key of Object.keys(record).sort()) {
|
|
18
|
+
sorted[key] = sortKeys(record[key]);
|
|
19
|
+
}
|
|
20
|
+
return sorted;
|
|
21
|
+
}
|
|
22
|
+
function isWorkingDirty(seed, working) {
|
|
23
|
+
return (stableStringify(seed.templateJson) !== stableStringify(working.templateJson) ||
|
|
24
|
+
stableStringify(seed.metadata) !== stableStringify(working.metadata) ||
|
|
25
|
+
stableStringify(seed.previewData) !== stableStringify(working.previewData));
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=dirty.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dirty.js","sourceRoot":"","sources":["../../src/save-send/dirty.ts"],"names":[],"mappings":";;AAMA,0CAEC;AAqBD,wCAMC;AA7BD,SAAgB,eAAe,CAAC,KAAc;IAC5C,OAAO,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC;AACzC,CAAC;AAED,SAAS,QAAQ,CAAC,KAAc;IAC9B,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAChD,OAAO,KAAK,CAAC;IACf,CAAC;IACD,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IAC7B,CAAC;IACD,MAAM,MAAM,GAAG,KAAgC,CAAC;IAChD,MAAM,MAAM,GAA4B,EAAE,CAAC;IAC3C,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC;QAC7C,MAAM,CAAC,GAAG,CAAC,GAAG,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;IACtC,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAMD,SAAgB,cAAc,CAAC,IAAyB,EAAE,OAA4B;IACpF,OAAO,CACL,eAAe,CAAC,IAAI,CAAC,YAAY,CAAC,KAAK,eAAe,CAAC,OAAO,CAAC,YAAY,CAAC;QAC5E,eAAe,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,eAAe,CAAC,OAAO,CAAC,QAAQ,CAAC;QACpE,eAAe,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,eAAe,CAAC,OAAO,CAAC,WAAW,CAAC,CAC3E,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function validateSendTestRecipient(recipient: string): string | null;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.validateSendTestRecipient = validateSendTestRecipient;
|
|
4
|
+
const BASIC_EMAIL = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
5
|
+
function validateSendTestRecipient(recipient) {
|
|
6
|
+
const trimmed = recipient.trim();
|
|
7
|
+
if (!trimmed) {
|
|
8
|
+
return 'Enter a recipient email address.';
|
|
9
|
+
}
|
|
10
|
+
if (!BASIC_EMAIL.test(trimmed)) {
|
|
11
|
+
return 'Enter a valid email address.';
|
|
12
|
+
}
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=recipient.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recipient.js","sourceRoot":"","sources":["../../src/save-send/recipient.ts"],"names":[],"mappings":";;AAMA,8DASC;AAXD,MAAM,WAAW,GAAG,4BAA4B,CAAC;AAEjD,SAAgB,yBAAyB,CAAC,SAAiB;IACzD,MAAM,OAAO,GAAG,SAAS,CAAC,IAAI,EAAE,CAAC;IACjC,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,kCAAkC,CAAC;IAC5C,CAAC;IACD,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;QAC/B,OAAO,8BAA8B,CAAC;IACxC,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { TemplateSourceFiles } from '../types';
|
|
2
|
+
import { serializeTemplateSource } from '../serialization';
|
|
3
|
+
export type SerializedTemplateSource = ReturnType<typeof serializeTemplateSource>;
|
|
4
|
+
export interface SaveResult {
|
|
5
|
+
ok: boolean;
|
|
6
|
+
message?: string;
|
|
7
|
+
}
|
|
8
|
+
export interface SendTestResult {
|
|
9
|
+
ok: boolean;
|
|
10
|
+
message?: string;
|
|
11
|
+
}
|
|
12
|
+
export type ActionStatus = 'idle' | 'pending' | 'success' | 'failure';
|
|
13
|
+
export interface ActionFeedback {
|
|
14
|
+
status: ActionStatus;
|
|
15
|
+
message?: string;
|
|
16
|
+
}
|
|
17
|
+
export declare function invokeConsumerAction(run: () => Promise<SaveResult | SendTestResult | void> | SaveResult | SendTestResult | void): Promise<SaveResult | SendTestResult>;
|
|
18
|
+
export declare function buildSavePayload(files: TemplateSourceFiles): {
|
|
19
|
+
serialized: SerializedTemplateSource;
|
|
20
|
+
files: TemplateSourceFiles;
|
|
21
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.invokeConsumerAction = invokeConsumerAction;
|
|
4
|
+
exports.buildSavePayload = buildSavePayload;
|
|
5
|
+
const serialization_1 = require("../serialization");
|
|
6
|
+
async function invokeConsumerAction(run) {
|
|
7
|
+
try {
|
|
8
|
+
const result = await run();
|
|
9
|
+
if (result && typeof result === 'object' && 'ok' in result) {
|
|
10
|
+
return result;
|
|
11
|
+
}
|
|
12
|
+
return { ok: true };
|
|
13
|
+
}
|
|
14
|
+
catch (error) {
|
|
15
|
+
return {
|
|
16
|
+
ok: false,
|
|
17
|
+
message: error instanceof Error ? error.message : String(error),
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
function buildSavePayload(files) {
|
|
22
|
+
return {
|
|
23
|
+
serialized: (0, serialization_1.serializeTemplateSource)(files),
|
|
24
|
+
files,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/save-send/types.ts"],"names":[],"mappings":";;AA8BA,oDAeC;AAGD,4CAQC;AAvDD,oDAA2D;AA6BpD,KAAK,UAAU,oBAAoB,CACxC,GAA2F;IAE3F,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,GAAG,EAAE,CAAC;QAC3B,IAAI,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,IAAI,IAAI,MAAM,EAAE,CAAC;YAC3D,OAAO,MAAM,CAAC;QAChB,CAAC;QACD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;IACtB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO;YACL,EAAE,EAAE,KAAK;YACT,OAAO,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;SAChE,CAAC;IACJ,CAAC;AACH,CAAC;AAGD,SAAgB,gBAAgB,CAAC,KAA0B;IAIzD,OAAO;QACL,UAAU,EAAE,IAAA,uCAAuB,EAAC,KAAK,CAAC;QAC1C,KAAK;KACN,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ValidationSummary = ValidationSummary;
|
|
4
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
5
|
+
const email_template_editor_1 = require("../email-template-editor");
|
|
6
|
+
const validate_1 = require("./validate");
|
|
7
|
+
function ValidationSummary({ issues }) {
|
|
8
|
+
const p = email_template_editor_1.EDITOR_CLASS_PREFIX;
|
|
9
|
+
if (issues.length === 0) {
|
|
10
|
+
return null;
|
|
11
|
+
}
|
|
12
|
+
const errors = issues.filter((i) => i.severity === 'error');
|
|
13
|
+
const warnings = issues.filter((i) => i.severity === 'warning');
|
|
14
|
+
return ((0, jsx_runtime_1.jsxs)("section", { className: `${p}validation`, "data-testid": `${p}validation`, "aria-label": "Template validation", children: [(0, jsx_runtime_1.jsx)("h2", { className: `${p}validation-heading`, children: "Validation" }), (0, jsx_runtime_1.jsxs)("div", { className: `${p}validation-live`, "data-testid": `${p}validation-live`, "aria-live": "polite", "aria-relevant": "additions text", children: [errors.length > 0 ? (0, jsx_runtime_1.jsx)(IssueGroup, { title: "Errors", severity: "error", issues: errors }) : null, warnings.length > 0 ? ((0, jsx_runtime_1.jsx)(IssueGroup, { title: "Warnings", severity: "warning", issues: warnings })) : null] })] }));
|
|
15
|
+
}
|
|
16
|
+
function IssueGroup({ title, severity, issues, }) {
|
|
17
|
+
const p = email_template_editor_1.EDITOR_CLASS_PREFIX;
|
|
18
|
+
return ((0, jsx_runtime_1.jsxs)("div", { className: `${p}validation-group ${p}validation-group-${severity}`, "data-testid": `${p}validation-${severity}s`, children: [(0, jsx_runtime_1.jsxs)("h3", { className: `${p}validation-group-title`, children: [(0, jsx_runtime_1.jsx)("span", { className: `${p}validation-icon`, "aria-hidden": "true", children: severity === 'error' ? '!' : 'i' }), ' ', title] }), (0, jsx_runtime_1.jsx)("ul", { className: `${p}validation-list`, children: issues.map((issue) => {
|
|
19
|
+
const targetId = (0, validate_1.focusTargetIdForIssue)(issue);
|
|
20
|
+
const key = `${issue.code}:${issue.field}:${issue.variable ?? ''}:${issue.message}`;
|
|
21
|
+
return ((0, jsx_runtime_1.jsx)("li", { className: `${p}validation-item`, children: (0, jsx_runtime_1.jsxs)("button", { type: "button", className: `${p}validation-link`, "data-testid": `${p}validation-link-${issue.code}`, "data-focus-target": targetId, onClick: () => {
|
|
22
|
+
const el = document.getElementById(targetId);
|
|
23
|
+
if (el && 'focus' in el && typeof el.focus === 'function') {
|
|
24
|
+
el.focus();
|
|
25
|
+
}
|
|
26
|
+
}, children: [(0, jsx_runtime_1.jsx)("span", { className: `${p}validation-code`, children: issue.code }), ': ', issue.message] }) }, key));
|
|
27
|
+
}) })] }));
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=ValidationSummary.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ValidationSummary.js","sourceRoot":"","sources":["../../src/validation/ValidationSummary.tsx"],"names":[],"mappings":";;AAaA,8CA6BC;;AAxCD,oEAA+D;AAC/D,yCAAkG;AAUlG,SAAgB,iBAAiB,CAAC,EAAE,MAAM,EAA0B;IAClE,MAAM,CAAC,GAAG,2CAAmB,CAAC;IAC9B,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC;IAC5D,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC;IAEhE,OAAO,CACL,qCACE,SAAS,EAAE,GAAG,CAAC,YAAY,iBACd,GAAG,CAAC,YAAY,gBAClB,qBAAqB,aAEhC,+BAAI,SAAS,EAAE,GAAG,CAAC,oBAAoB,2BAAiB,EACxD,iCACE,SAAS,EAAE,GAAG,CAAC,iBAAiB,iBACnB,GAAG,CAAC,iBAAiB,eACxB,QAAQ,mBACJ,gBAAgB,aAE7B,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,uBAAC,UAAU,IAAC,KAAK,EAAC,QAAQ,EAAC,QAAQ,EAAC,OAAO,EAAC,MAAM,EAAE,MAAM,GAAI,CAAC,CAAC,CAAC,IAAI,EACzF,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CACrB,uBAAC,UAAU,IAAC,KAAK,EAAC,UAAU,EAAC,QAAQ,EAAC,SAAS,EAAC,MAAM,EAAE,QAAQ,GAAI,CACrE,CAAC,CAAC,CAAC,IAAI,IACJ,IACE,CACX,CAAC;AACJ,CAAC;AAED,SAAS,UAAU,CAAC,EAClB,KAAK,EACL,QAAQ,EACR,MAAM,GAKP;IACC,MAAM,CAAC,GAAG,2CAAmB,CAAC;IAC9B,OAAO,CACL,iCACE,SAAS,EAAE,GAAG,CAAC,oBAAoB,CAAC,oBAAoB,QAAQ,EAAE,iBACrD,GAAG,CAAC,cAAc,QAAQ,GAAG,aAE1C,gCAAI,SAAS,EAAE,GAAG,CAAC,wBAAwB,aACzC,iCAAM,SAAS,EAAE,GAAG,CAAC,iBAAiB,iBAAc,MAAM,YACvD,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,GAC5B,EAAC,GAAG,EACV,KAAK,IACH,EACL,+BAAI,SAAS,EAAE,GAAG,CAAC,iBAAiB,YACjC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE;oBACpB,MAAM,QAAQ,GAAG,IAAA,gCAAqB,EAAC,KAAK,CAAC,CAAC;oBAC9C,MAAM,GAAG,GAAG,GAAG,KAAK,CAAC,IAAI,IAAI,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC,QAAQ,IAAI,EAAE,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC;oBACpF,OAAO,CACL,+BAAc,SAAS,EAAE,GAAG,CAAC,iBAAiB,YAC5C,oCACE,IAAI,EAAC,QAAQ,EACb,SAAS,EAAE,GAAG,CAAC,iBAAiB,iBACnB,GAAG,CAAC,mBAAmB,KAAK,CAAC,IAAI,EAAE,uBAC7B,QAAQ,EAC3B,OAAO,EAAE,GAAG,EAAE;gCACZ,MAAM,EAAE,GAAG,QAAQ,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC;gCAC7C,IAAI,EAAE,IAAI,OAAO,IAAI,EAAE,IAAI,OAAO,EAAE,CAAC,KAAK,KAAK,UAAU,EAAE,CAAC;oCAC1D,EAAE,CAAC,KAAK,EAAE,CAAC;gCACb,CAAC;4BACH,CAAC,aAED,iCAAM,SAAS,EAAE,GAAG,CAAC,iBAAiB,YAAG,KAAK,CAAC,IAAI,GAAQ,EAC1D,IAAI,EACJ,KAAK,CAAC,OAAO,IACP,IAhBF,GAAG,CAiBP,CACN,CAAC;gBACJ,CAAC,CAAC,GACC,IACD,CACP,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.extractPlaceholdersFromText = extractPlaceholdersFromText;
|
|
4
|
+
exports.extractPlaceholdersFromDocument = extractPlaceholdersFromDocument;
|
|
5
|
+
const PLACEHOLDER_RE = /\{\{\s*([a-zA-Z0-9_.-]+)\s*\}\}/g;
|
|
6
|
+
function extractPlaceholdersFromText(text) {
|
|
7
|
+
const seen = new Set();
|
|
8
|
+
const ordered = [];
|
|
9
|
+
PLACEHOLDER_RE.lastIndex = 0;
|
|
10
|
+
let match;
|
|
11
|
+
while ((match = PLACEHOLDER_RE.exec(text)) !== null) {
|
|
12
|
+
const name = match[1];
|
|
13
|
+
if (!seen.has(name)) {
|
|
14
|
+
seen.add(name);
|
|
15
|
+
ordered.push(name);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
return ordered;
|
|
19
|
+
}
|
|
20
|
+
function extractPlaceholdersFromDocument(document) {
|
|
21
|
+
const seen = new Set();
|
|
22
|
+
const ordered = [];
|
|
23
|
+
const visit = (value) => {
|
|
24
|
+
if (typeof value === 'string') {
|
|
25
|
+
for (const name of extractPlaceholdersFromText(value)) {
|
|
26
|
+
if (!seen.has(name)) {
|
|
27
|
+
seen.add(name);
|
|
28
|
+
ordered.push(name);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
if (value === null || typeof value !== 'object') {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
if (Array.isArray(value)) {
|
|
37
|
+
for (const item of value) {
|
|
38
|
+
visit(item);
|
|
39
|
+
}
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
for (const child of Object.values(value)) {
|
|
43
|
+
visit(child);
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
visit(document);
|
|
47
|
+
return ordered;
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=extract-placeholders.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extract-placeholders.js","sourceRoot":"","sources":["../../src/validation/extract-placeholders.ts"],"names":[],"mappings":";;AAQA,kEAaC;AAMD,0EA8BC;AApDD,MAAM,cAAc,GAAG,kCAAkC,CAAC;AAG1D,SAAgB,2BAA2B,CAAC,IAAY;IACtD,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,cAAc,CAAC,SAAS,GAAG,CAAC,CAAC;IAC7B,IAAI,KAA6B,CAAC;IAClC,OAAO,CAAC,KAAK,GAAG,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;QACpD,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QACtB,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YACpB,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YACf,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACrB,CAAC;IACH,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAMD,SAAgB,+BAA+B,CAAC,QAAiB;IAC/D,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,MAAM,OAAO,GAAa,EAAE,CAAC;IAE7B,MAAM,KAAK,GAAG,CAAC,KAAc,EAAQ,EAAE;QACrC,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;YAC9B,KAAK,MAAM,IAAI,IAAI,2BAA2B,CAAC,KAAK,CAAC,EAAE,CAAC;gBACtD,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;oBACpB,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;oBACf,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBACrB,CAAC;YACH,CAAC;YACD,OAAO;QACT,CAAC;QACD,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;YAChD,OAAO;QACT,CAAC;QACD,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;YACzB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;gBACzB,KAAK,CAAC,IAAI,CAAC,CAAC;YACd,CAAC;YACD,OAAO;QACT,CAAC;QACD,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,MAAM,CAAC,KAAgC,CAAC,EAAE,CAAC;YACpE,KAAK,CAAC,KAAK,CAAC,CAAC;QACf,CAAC;IACH,CAAC,CAAC;IAEF,KAAK,CAAC,QAAQ,CAAC,CAAC;IAChB,OAAO,OAAO,CAAC;AACjB,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { TemplateSourceFiles } from '../types';
|
|
2
|
+
export type ValidationSeverity = 'error' | 'warning';
|
|
3
|
+
export interface ValidationIssue {
|
|
4
|
+
severity: ValidationSeverity;
|
|
5
|
+
code: string;
|
|
6
|
+
message: string;
|
|
7
|
+
field: 'metadata' | 'subject' | 'document' | 'previewData';
|
|
8
|
+
variable?: string;
|
|
9
|
+
}
|
|
10
|
+
export interface ValidateTemplateOptions {
|
|
11
|
+
renderError?: string | null;
|
|
12
|
+
}
|
|
13
|
+
export declare function validateTemplate(files: TemplateSourceFiles, options?: ValidateTemplateOptions): ValidationIssue[];
|
|
14
|
+
export declare function hasValidationErrors(issues: readonly ValidationIssue[]): boolean;
|
|
15
|
+
export declare function focusTargetIdForIssue(issue: ValidationIssue): string;
|
|
16
|
+
export declare function domIdSegment(value: string): string;
|
|
17
|
+
export declare function inlineIssueId(code: string, variable?: string): string;
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.validateTemplate = validateTemplate;
|
|
4
|
+
exports.hasValidationErrors = hasValidationErrors;
|
|
5
|
+
exports.focusTargetIdForIssue = focusTargetIdForIssue;
|
|
6
|
+
exports.domIdSegment = domIdSegment;
|
|
7
|
+
exports.inlineIssueId = inlineIssueId;
|
|
8
|
+
const template_key_1 = require("../metadata/template-key");
|
|
9
|
+
const extract_placeholders_1 = require("./extract-placeholders");
|
|
10
|
+
function validateTemplate(files, options = {}) {
|
|
11
|
+
const issues = [];
|
|
12
|
+
const { metadata, previewData, templateJson } = files;
|
|
13
|
+
const key = metadata.key.trim();
|
|
14
|
+
if (key === '') {
|
|
15
|
+
issues.push({
|
|
16
|
+
severity: 'error',
|
|
17
|
+
code: 'missing-key',
|
|
18
|
+
message: 'Template key is required.',
|
|
19
|
+
field: 'metadata',
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
const keyError = (0, template_key_1.templateKeyInputError)(metadata.key);
|
|
24
|
+
if (keyError) {
|
|
25
|
+
issues.push({
|
|
26
|
+
severity: 'error',
|
|
27
|
+
code: 'invalid-key',
|
|
28
|
+
message: keyError,
|
|
29
|
+
field: 'metadata',
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
if (metadata.name.trim() === '') {
|
|
34
|
+
issues.push({
|
|
35
|
+
severity: 'error',
|
|
36
|
+
code: 'missing-name',
|
|
37
|
+
message: 'Template name is required.',
|
|
38
|
+
field: 'metadata',
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
if (metadata.subject.trim() === '') {
|
|
42
|
+
issues.push({
|
|
43
|
+
severity: 'error',
|
|
44
|
+
code: 'missing-subject',
|
|
45
|
+
message: 'Subject is required.',
|
|
46
|
+
field: 'subject',
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
const declared = metadata.variables;
|
|
50
|
+
const declaredSet = new Set(declared);
|
|
51
|
+
const subjectPlaceholders = (0, extract_placeholders_1.extractPlaceholdersFromText)(metadata.subject);
|
|
52
|
+
const documentPlaceholders = (0, extract_placeholders_1.extractPlaceholdersFromDocument)(templateJson);
|
|
53
|
+
const used = new Set([...subjectPlaceholders, ...documentPlaceholders]);
|
|
54
|
+
for (const name of subjectPlaceholders) {
|
|
55
|
+
if (!declaredSet.has(name)) {
|
|
56
|
+
issues.push({
|
|
57
|
+
severity: 'error',
|
|
58
|
+
code: 'undeclared-variable',
|
|
59
|
+
message: `Variable "{{${name}}}" is used in the subject but is not declared.`,
|
|
60
|
+
field: 'subject',
|
|
61
|
+
variable: name,
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
for (const name of documentPlaceholders) {
|
|
66
|
+
if (!declaredSet.has(name)) {
|
|
67
|
+
issues.push({
|
|
68
|
+
severity: 'error',
|
|
69
|
+
code: 'undeclared-variable',
|
|
70
|
+
message: `Variable "{{${name}}}" is used in the document but is not declared.`,
|
|
71
|
+
field: 'document',
|
|
72
|
+
variable: name,
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
for (const name of declared) {
|
|
77
|
+
const value = previewData[name];
|
|
78
|
+
if (value === undefined || value.trim() === '') {
|
|
79
|
+
issues.push({
|
|
80
|
+
severity: 'error',
|
|
81
|
+
code: 'missing-preview-value',
|
|
82
|
+
message: `Declared variable "${name}" has no preview value.`,
|
|
83
|
+
field: 'previewData',
|
|
84
|
+
variable: name,
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
for (const name of declared) {
|
|
89
|
+
if (!used.has(name)) {
|
|
90
|
+
issues.push({
|
|
91
|
+
severity: 'warning',
|
|
92
|
+
code: 'unused-variable',
|
|
93
|
+
message: `Declared variable "${name}" is not used in the subject or document.`,
|
|
94
|
+
field: 'metadata',
|
|
95
|
+
variable: name,
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
for (const name of Object.keys(previewData)) {
|
|
100
|
+
if (!declaredSet.has(name)) {
|
|
101
|
+
issues.push({
|
|
102
|
+
severity: 'warning',
|
|
103
|
+
code: 'extra-preview-value',
|
|
104
|
+
message: `Preview value "${name}" is not declared in metadata.variables.`,
|
|
105
|
+
field: 'previewData',
|
|
106
|
+
variable: name,
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
if (options.renderError) {
|
|
111
|
+
issues.push({
|
|
112
|
+
severity: 'error',
|
|
113
|
+
code: 'render-failed',
|
|
114
|
+
message: options.renderError,
|
|
115
|
+
field: 'document',
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
return issues;
|
|
119
|
+
}
|
|
120
|
+
function hasValidationErrors(issues) {
|
|
121
|
+
return issues.some((issue) => issue.severity === 'error');
|
|
122
|
+
}
|
|
123
|
+
function focusTargetIdForIssue(issue) {
|
|
124
|
+
const p = 'pk-editor-';
|
|
125
|
+
switch (issue.field) {
|
|
126
|
+
case 'metadata':
|
|
127
|
+
if (issue.code === 'missing-key' || issue.code === 'invalid-key') {
|
|
128
|
+
return `${p}meta-key`;
|
|
129
|
+
}
|
|
130
|
+
if (issue.code === 'missing-name') {
|
|
131
|
+
return `${p}meta-name`;
|
|
132
|
+
}
|
|
133
|
+
if (issue.code === 'unused-variable') {
|
|
134
|
+
return `${p}variables`;
|
|
135
|
+
}
|
|
136
|
+
return `${p}meta-key`;
|
|
137
|
+
case 'subject':
|
|
138
|
+
return `${p}meta-subject`;
|
|
139
|
+
case 'document':
|
|
140
|
+
return `${p}canvas`;
|
|
141
|
+
case 'previewData':
|
|
142
|
+
return issue.variable ? `${p}preview-${domIdSegment(issue.variable)}` : `${p}preview-data`;
|
|
143
|
+
default:
|
|
144
|
+
return `${p}root`;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
function domIdSegment(value) {
|
|
148
|
+
return encodeURIComponent(value).replace(/%/g, '_');
|
|
149
|
+
}
|
|
150
|
+
function inlineIssueId(code, variable) {
|
|
151
|
+
const suffix = variable ? `${code}-${domIdSegment(variable)}` : code;
|
|
152
|
+
return `pk-editor-issue-${suffix}`;
|
|
153
|
+
}
|
|
154
|
+
//# sourceMappingURL=validate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validate.js","sourceRoot":"","sources":["../../src/validation/validate.ts"],"names":[],"mappings":"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"}
|
|
@@ -61,7 +61,7 @@ function VariableCatalogue({ availableVariables, metadataVariables, onMetadataVa
|
|
|
61
61
|
}, [metadataVariables, onMetadataVariablesChange]);
|
|
62
62
|
const insertDisabled = target === null;
|
|
63
63
|
const insertDisabledReason = 'Focus the subject field (or another editable target) before inserting a variable.';
|
|
64
|
-
return ((0, jsx_runtime_1.jsxs)("section", { className: `${p}variables`, "data-testid": `${p}variables`, children: [(0, jsx_runtime_1.jsx)("h2", { className: `${p}variables-heading`, children: "Available variables" }), (0, jsx_runtime_1.jsx)("input", { ref: fallbackSelectRef, className: `${p}variables-clipboard-fallback`, type: "text", readOnly: true, "aria-hidden": "true", tabIndex: -1, "data-testid": `${p}variables-clipboard-fallback` }), entries.length === 0 ? ((0, jsx_runtime_1.jsx)("p", { className: `${p}variables-empty`, children: "No variables declared yet." })) : ((0, jsx_runtime_1.jsx)("ul", { className: `${p}variables-list`, children: entries.map((entry) => {
|
|
64
|
+
return ((0, jsx_runtime_1.jsxs)("section", { id: `${p}variables`, className: `${p}variables`, "data-testid": `${p}variables`, tabIndex: -1, "aria-label": "Available variables", children: [(0, jsx_runtime_1.jsx)("h2", { className: `${p}variables-heading`, children: "Available variables" }), (0, jsx_runtime_1.jsx)("input", { ref: fallbackSelectRef, className: `${p}variables-clipboard-fallback`, type: "text", readOnly: true, "aria-hidden": "true", tabIndex: -1, "data-testid": `${p}variables-clipboard-fallback` }), entries.length === 0 ? ((0, jsx_runtime_1.jsx)("p", { className: `${p}variables-empty`, children: "No variables declared yet." })) : ((0, jsx_runtime_1.jsx)("ul", { className: `${p}variables-list`, children: entries.map((entry) => {
|
|
65
65
|
const placeholder = (0, insert_at_cursor_1.variablePlaceholder)(entry.name);
|
|
66
66
|
const label = entry.label ?? entry.name;
|
|
67
67
|
return ((0, jsx_runtime_1.jsxs)("li", { className: `${p}variables-item`, children: [(0, jsx_runtime_1.jsxs)("div", { className: `${p}variables-item-main`, children: [(0, jsx_runtime_1.jsx)("span", { className: `${p}variables-item-label`, children: label }), (0, jsx_runtime_1.jsx)("code", { className: `${p}variables-item-placeholder`, children: placeholder }), entry.description ? ((0, jsx_runtime_1.jsx)("span", { className: `${p}variables-item-description`, children: entry.description })) : null] }), (0, jsx_runtime_1.jsxs)("div", { className: `${p}variables-item-actions`, children: [(0, jsx_runtime_1.jsx)("button", { type: "button", className: `${p}variables-copy`, onClick: () => {
|