@tekki-forge/runtime-admin 0.2.0 → 0.3.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 (136) hide show
  1. package/dist/admin-dashboard.d.ts +16 -0
  2. package/dist/admin-dashboard.js +60 -0
  3. package/dist/admin-dashboard.js.map +1 -0
  4. package/dist/admin-orgs.d.ts +14 -0
  5. package/dist/admin-orgs.js +75 -0
  6. package/dist/admin-orgs.js.map +1 -0
  7. package/dist/admin-shell.d.ts +55 -0
  8. package/dist/admin-shell.js +141 -0
  9. package/dist/admin-shell.js.map +1 -0
  10. package/dist/admin.js +35 -4
  11. package/dist/admin.js.map +1 -1
  12. package/dist/app-pages.d.ts +19 -0
  13. package/dist/app-pages.js +109 -0
  14. package/dist/app-pages.js.map +1 -0
  15. package/dist/auth-pages.js +7 -2
  16. package/dist/auth-pages.js.map +1 -1
  17. package/dist/charts.d.ts +98 -2
  18. package/dist/charts.js +264 -24
  19. package/dist/charts.js.map +1 -1
  20. package/dist/context.js +32 -1
  21. package/dist/context.js.map +1 -1
  22. package/dist/dashboard.d.ts +63 -8
  23. package/dist/dashboard.js +180 -36
  24. package/dist/dashboard.js.map +1 -1
  25. package/dist/i18n/messages/de.js +751 -0
  26. package/dist/i18n/messages/de.js.map +1 -1
  27. package/dist/i18n/messages/en.js +751 -0
  28. package/dist/i18n/messages/en.js.map +1 -1
  29. package/dist/i18n/messages/es.js +751 -0
  30. package/dist/i18n/messages/es.js.map +1 -1
  31. package/dist/i18n/messages/fr.js +751 -0
  32. package/dist/i18n/messages/fr.js.map +1 -1
  33. package/dist/i18n/messages/pt.js +751 -0
  34. package/dist/i18n/messages/pt.js.map +1 -1
  35. package/dist/index.d.ts +9 -0
  36. package/dist/index.js +9 -0
  37. package/dist/index.js.map +1 -1
  38. package/dist/shell.js +37 -34
  39. package/dist/shell.js.map +1 -1
  40. package/dist/site/editor/api.d.ts +74 -0
  41. package/dist/site/editor/api.js +93 -0
  42. package/dist/site/editor/api.js.map +1 -0
  43. package/dist/site/editor/content-page.d.ts +4 -0
  44. package/dist/site/editor/content-page.js +65 -0
  45. package/dist/site/editor/content-page.js.map +1 -0
  46. package/dist/site/editor/inbox-tab.d.ts +4 -0
  47. package/dist/site/editor/inbox-tab.js +88 -0
  48. package/dist/site/editor/inbox-tab.js.map +1 -0
  49. package/dist/site/editor/index.d.ts +1 -0
  50. package/dist/site/editor/index.js +3 -0
  51. package/dist/site/editor/index.js.map +1 -0
  52. package/dist/site/editor/model.d.ts +145 -0
  53. package/dist/site/editor/model.js +408 -0
  54. package/dist/site/editor/model.js.map +1 -0
  55. package/dist/site/editor/page-editor.d.ts +10 -0
  56. package/dist/site/editor/page-editor.js +257 -0
  57. package/dist/site/editor/page-editor.js.map +1 -0
  58. package/dist/site/editor/page-settings.d.ts +9 -0
  59. package/dist/site/editor/page-settings.js +105 -0
  60. package/dist/site/editor/page-settings.js.map +1 -0
  61. package/dist/site/editor/pages-tab.d.ts +5 -0
  62. package/dist/site/editor/pages-tab.js +108 -0
  63. package/dist/site/editor/pages-tab.js.map +1 -0
  64. package/dist/site/editor/posts-tab.d.ts +6 -0
  65. package/dist/site/editor/posts-tab.js +139 -0
  66. package/dist/site/editor/posts-tab.js.map +1 -0
  67. package/dist/site/editor/preview.d.ts +32 -0
  68. package/dist/site/editor/preview.js +104 -0
  69. package/dist/site/editor/preview.js.map +1 -0
  70. package/dist/site/editor/prop-fields.d.ts +53 -0
  71. package/dist/site/editor/prop-fields.js +233 -0
  72. package/dist/site/editor/prop-fields.js.map +1 -0
  73. package/dist/site/editor/section-list.d.ts +14 -0
  74. package/dist/site/editor/section-list.js +110 -0
  75. package/dist/site/editor/section-list.js.map +1 -0
  76. package/dist/site/editor/section-picker.d.ts +12 -0
  77. package/dist/site/editor/section-picker.js +44 -0
  78. package/dist/site/editor/section-picker.js.map +1 -0
  79. package/dist/site/editor/widgets.d.ts +84 -0
  80. package/dist/site/editor/widgets.js +130 -0
  81. package/dist/site/editor/widgets.js.map +1 -0
  82. package/dist/site/format.d.ts +31 -0
  83. package/dist/site/format.js +106 -0
  84. package/dist/site/format.js.map +1 -0
  85. package/dist/site/forms.d.ts +43 -0
  86. package/dist/site/forms.js +155 -0
  87. package/dist/site/forms.js.map +1 -0
  88. package/dist/site/header.d.ts +32 -0
  89. package/dist/site/header.js +76 -0
  90. package/dist/site/header.js.map +1 -0
  91. package/dist/site/icons.d.ts +10 -0
  92. package/dist/site/icons.js +28 -0
  93. package/dist/site/icons.js.map +1 -0
  94. package/dist/site/index.d.ts +11 -0
  95. package/dist/site/index.js +13 -0
  96. package/dist/site/index.js.map +1 -0
  97. package/dist/site/markdown.d.ts +14 -0
  98. package/dist/site/markdown.js +457 -0
  99. package/dist/site/markdown.js.map +1 -0
  100. package/dist/site/page.d.ts +16 -0
  101. package/dist/site/page.js +65 -0
  102. package/dist/site/page.js.map +1 -0
  103. package/dist/site/proxy.d.ts +13 -0
  104. package/dist/site/proxy.js +43 -0
  105. package/dist/site/proxy.js.map +1 -0
  106. package/dist/site/sections.d.ts +43 -0
  107. package/dist/site/sections.js +560 -0
  108. package/dist/site/sections.js.map +1 -0
  109. package/dist/site/server.d.ts +73 -0
  110. package/dist/site/server.js +235 -0
  111. package/dist/site/server.js.map +1 -0
  112. package/dist/site/types.d.ts +137 -0
  113. package/dist/site/types.js +2 -0
  114. package/dist/site/types.js.map +1 -0
  115. package/dist/support.d.ts +29 -0
  116. package/dist/support.js +165 -0
  117. package/dist/support.js.map +1 -0
  118. package/dist/system-config.d.ts +24 -0
  119. package/dist/system-config.js +37 -0
  120. package/dist/system-config.js.map +1 -0
  121. package/dist/system-settings.d.ts +9 -0
  122. package/dist/system-settings.js +60 -0
  123. package/dist/system-settings.js.map +1 -0
  124. package/dist/theme-catalog.d.ts +72 -2
  125. package/dist/theme-catalog.js +47 -0
  126. package/dist/theme-catalog.js.map +1 -1
  127. package/dist/theme-switcher.d.ts +8 -0
  128. package/dist/theme-switcher.js +39 -4
  129. package/dist/theme-switcher.js.map +1 -1
  130. package/dist/theme.js +8 -0
  131. package/dist/theme.js.map +1 -1
  132. package/dist/transactions.d.ts +4 -0
  133. package/dist/transactions.js +60 -0
  134. package/dist/transactions.js.map +1 -0
  135. package/package.json +9 -5
  136. package/styles.css +1089 -0
@@ -0,0 +1,84 @@
1
+ import { type ReactNode } from "react";
2
+ declare const WIDTHS: {
3
+ readonly md: "max-w-md";
4
+ readonly lg: "max-w-2xl";
5
+ readonly xl: "max-w-5xl";
6
+ };
7
+ /** Modal dialog: traps focus, Escape closes, focus goes back where it was. */
8
+ export declare function EditorDialog({ open, onClose, title, description, children, footer, size }: {
9
+ open: boolean;
10
+ onClose: () => void;
11
+ title: string;
12
+ description?: string;
13
+ children: ReactNode;
14
+ footer?: ReactNode;
15
+ size?: keyof typeof WIDTHS;
16
+ }): import("react").JSX.Element | null;
17
+ /** Side panel over the page (right on wide screens, full width on phones). */
18
+ export declare function Drawer({ open, onClose, title, children, footer }: {
19
+ open: boolean;
20
+ onClose: () => void;
21
+ title: string;
22
+ children: ReactNode;
23
+ footer?: ReactNode;
24
+ }): import("react").JSX.Element | null;
25
+ export interface TabItem<K extends string> {
26
+ key: K;
27
+ label: string;
28
+ icon?: ReactNode;
29
+ badge?: ReactNode;
30
+ }
31
+ /** WAI-ARIA tabs: arrows / Home / End move between tabs (automatic activation). */
32
+ export declare function Tabs<K extends string>({ tabs, value, onChange, label, idPrefix, size }: {
33
+ tabs: TabItem<K>[];
34
+ value: K;
35
+ onChange: (k: K) => void;
36
+ label: string;
37
+ idPrefix: string;
38
+ size?: "sm" | "md";
39
+ }): import("react").JSX.Element;
40
+ export declare function TabPanel({ idPrefix, tab, children, className }: {
41
+ idPrefix: string;
42
+ tab: string;
43
+ children: ReactNode;
44
+ className?: string;
45
+ }): import("react").JSX.Element;
46
+ export declare function Switch({ id, checked, onChange, label, disabled }: {
47
+ id?: string;
48
+ checked: boolean;
49
+ onChange: (v: boolean) => void;
50
+ label?: string;
51
+ disabled?: boolean;
52
+ }): import("react").JSX.Element;
53
+ /** A small coloured pill (status, origin, conflict). */
54
+ export declare function Pill({ tone, children, title }: {
55
+ tone: "success" | "muted" | "warning" | "danger" | "info";
56
+ children: ReactNode;
57
+ title?: string;
58
+ }): import("react").JSX.Element;
59
+ export type SaveState = "idle" | "dirty" | "saving" | "saved" | "error" | "invalid";
60
+ /** "Saving…" / "Saved" / "Couldn't save" next to the editor's title; announced politely. */
61
+ export declare function SaveIndicator({ state, message }: {
62
+ state: SaveState;
63
+ message?: string;
64
+ }): import("react").JSX.Element;
65
+ /** A visually hidden polite live region; `announce(text)` reads text out (reorders, adds, removals). */
66
+ export declare function useAnnouncer(): [ReactNode, (text: string) => void];
67
+ /** Confirmation in an accessible dialog (focus starts on Cancel, the safe choice). */
68
+ export declare function Confirm({ open, title, message, confirmLabel, danger, loading, onConfirm, onClose }: {
69
+ open: boolean;
70
+ title: string;
71
+ message: ReactNode;
72
+ confirmLabel: string;
73
+ danger?: boolean;
74
+ loading?: boolean;
75
+ onConfirm: () => void;
76
+ onClose: () => void;
77
+ }): import("react").JSX.Element;
78
+ /** Text with a live "12 / 160" counter (SEO fields). */
79
+ export declare function Counter({ value, max, recommended }: {
80
+ value: string;
81
+ max: number;
82
+ recommended?: number;
83
+ }): import("react").JSX.Element;
84
+ export {};
@@ -0,0 +1,130 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
+ /*
4
+ * Small building blocks of the website editor: an accessible dialog/drawer (focus trap, focus return), a keyboard
5
+ * tablist, a switch, status badges, the save indicator and a polite live region for announcements.
6
+ */
7
+ import { CircleAlert, CircleCheck, CloudUpload, LoaderCircle, X } from "lucide-react";
8
+ import { useCallback, useEffect, useId, useRef, useState } from "react";
9
+ import { useT } from "../../context.js";
10
+ import { cn } from "../../ui.js";
11
+ const FOCUSABLE = 'a[href], button:not([disabled]), input:not([disabled]):not([type="hidden"]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])';
12
+ function useFocusTrap(open, onClose) {
13
+ const ref = useRef(null);
14
+ const closeRef = useRef(onClose);
15
+ closeRef.current = onClose;
16
+ useEffect(() => {
17
+ if (!open)
18
+ return;
19
+ const previous = document.activeElement;
20
+ const node = ref.current;
21
+ // Focus the first field (or the dialog itself) once it is on screen.
22
+ const first = node?.querySelector("[data-autofocus]") ?? node?.querySelector("input, select, textarea") ?? node;
23
+ first?.focus();
24
+ const onKey = (e) => {
25
+ if (e.key === "Escape") {
26
+ // Let an inner control (a picked-up row) handle Escape first.
27
+ if (e.defaultPrevented)
28
+ return;
29
+ e.stopPropagation();
30
+ closeRef.current();
31
+ return;
32
+ }
33
+ if (e.key !== "Tab" || !node)
34
+ return;
35
+ const items = [...node.querySelectorAll(FOCUSABLE)].filter((el) => el.offsetParent !== null || el === document.activeElement);
36
+ if (!items.length)
37
+ return;
38
+ const firstItem = items[0];
39
+ const last = items[items.length - 1];
40
+ if (e.shiftKey && (document.activeElement === firstItem || document.activeElement === node)) {
41
+ e.preventDefault();
42
+ last.focus();
43
+ }
44
+ else if (!e.shiftKey && document.activeElement === last) {
45
+ e.preventDefault();
46
+ firstItem.focus();
47
+ }
48
+ };
49
+ node?.addEventListener("keydown", onKey);
50
+ return () => {
51
+ node?.removeEventListener("keydown", onKey);
52
+ if (previous && document.contains(previous))
53
+ previous.focus();
54
+ };
55
+ }, [open]);
56
+ return ref;
57
+ }
58
+ const WIDTHS = { md: "max-w-md", lg: "max-w-2xl", xl: "max-w-5xl" };
59
+ /** Modal dialog: traps focus, Escape closes, focus goes back where it was. */
60
+ export function EditorDialog({ open, onClose, title, description, children, footer, size = "md" }) {
61
+ const t = useT();
62
+ const ref = useFocusTrap(open, onClose);
63
+ const titleId = useId();
64
+ if (!open)
65
+ return null;
66
+ return (_jsxs("div", { className: "fixed inset-0 z-50 flex items-center justify-center p-4", children: [_jsx("div", { className: "forge-overlay absolute inset-0", onClick: onClose, "aria-hidden": true }), _jsxs("div", { ref: ref, role: "dialog", "aria-modal": "true", "aria-labelledby": titleId, tabIndex: -1, className: cn("forge-dialog forge-pop relative flex max-h-[90vh] w-full flex-col outline-none", WIDTHS[size]), children: [_jsxs("div", { className: "flex items-start justify-between gap-4 border-b border-line px-5 py-3", children: [_jsxs("div", { className: "min-w-0", children: [_jsx("h2", { id: titleId, className: "text-sm font-semibold text-ink", children: title }), description && _jsx("p", { className: "mt-0.5 text-xs text-ink-muted", children: description })] }), _jsx("button", { type: "button", onClick: onClose, className: "forge-btn forge-btn-ghost p-1", "aria-label": t("common.close"), children: _jsx(X, { className: "size-4", "aria-hidden": true }) })] }), _jsx("div", { className: "min-h-0 overflow-y-auto px-5 py-4 text-sm text-ink", children: children }), footer && _jsx("div", { className: "flex flex-wrap justify-end gap-2 border-t border-line px-5 py-3", children: footer })] })] }));
67
+ }
68
+ /** Side panel over the page (right on wide screens, full width on phones). */
69
+ export function Drawer({ open, onClose, title, children, footer }) {
70
+ const t = useT();
71
+ const ref = useFocusTrap(open, onClose);
72
+ const titleId = useId();
73
+ if (!open)
74
+ return null;
75
+ return (_jsxs("div", { className: "fixed inset-0 z-50 flex justify-end", children: [_jsx("div", { className: "forge-overlay absolute inset-0", onClick: onClose, "aria-hidden": true }), _jsxs("div", { ref: ref, role: "dialog", "aria-modal": "true", "aria-labelledby": titleId, tabIndex: -1, className: "forge-dialog forge-drawer relative flex h-full w-full max-w-md flex-col rounded-none outline-none sm:rounded-l-[var(--forge-radius)]", children: [_jsxs("div", { className: "flex items-center justify-between gap-4 border-b border-line px-5 py-3", children: [_jsx("h2", { id: titleId, className: "text-sm font-semibold text-ink", children: title }), _jsx("button", { type: "button", onClick: onClose, className: "forge-btn forge-btn-ghost p-1", "aria-label": t("common.close"), children: _jsx(X, { className: "size-4", "aria-hidden": true }) })] }), _jsx("div", { className: "min-h-0 flex-1 overflow-y-auto px-5 py-4 text-sm text-ink", children: children }), footer && _jsx("div", { className: "flex flex-wrap justify-end gap-2 border-t border-line px-5 py-3", children: footer })] })] }));
76
+ }
77
+ /** WAI-ARIA tabs: arrows / Home / End move between tabs (automatic activation). */
78
+ export function Tabs({ tabs, value, onChange, label, idPrefix, size = "md" }) {
79
+ const refs = useRef([]);
80
+ const onKey = (e, i) => {
81
+ const next = e.key === "ArrowRight" ? (i + 1) % tabs.length : e.key === "ArrowLeft" ? (i - 1 + tabs.length) % tabs.length : e.key === "Home" ? 0 : e.key === "End" ? tabs.length - 1 : -1;
82
+ if (next < 0)
83
+ return;
84
+ e.preventDefault();
85
+ onChange(tabs[next].key);
86
+ refs.current[next]?.focus();
87
+ };
88
+ return (_jsx("div", { role: "tablist", "aria-label": label, className: cn("forge-input flex max-w-full items-center gap-0.5 overflow-x-auto p-0.5", size === "sm" ? "h-8" : "h-9"), children: tabs.map((tab, i) => (_jsxs("button", { ref: (el) => {
89
+ refs.current[i] = el;
90
+ }, id: `${idPrefix}-tab-${tab.key}`, type: "button", role: "tab", "aria-selected": value === tab.key, "aria-controls": `${idPrefix}-panel-${tab.key}`, tabIndex: value === tab.key ? 0 : -1, onClick: () => onChange(tab.key), onKeyDown: (e) => onKey(e, i), className: cn("forge-focusable flex h-full shrink-0 items-center gap-1.5 rounded px-3 whitespace-nowrap", size === "sm" ? "text-xs" : "text-sm", value === tab.key ? "bg-selected text-ink" : "text-ink-muted hover:text-ink"), children: [tab.icon, tab.label, tab.badge] }, tab.key))) }));
91
+ }
92
+ export function TabPanel({ idPrefix, tab, children, className }) {
93
+ return (_jsx("div", { role: "tabpanel", id: `${idPrefix}-panel-${tab}`, "aria-labelledby": `${idPrefix}-tab-${tab}`, className: className, children: children }));
94
+ }
95
+ export function Switch({ id, checked, onChange, label, disabled }) {
96
+ return (_jsx("button", { id: id, type: "button", role: "switch", "aria-checked": checked, "aria-label": label, disabled: disabled, onClick: () => onChange(!checked), className: "forge-switch relative inline-flex h-6 w-11 shrink-0 items-center disabled:opacity-50", children: _jsx("span", { className: cn("forge-switch-thumb inline-block size-5 transition-transform motion-reduce:transition-none", checked ? "translate-x-5" : "translate-x-0.5") }) }));
97
+ }
98
+ /** A small coloured pill (status, origin, conflict). */
99
+ export function Pill({ tone, children, title }) {
100
+ const color = { success: "var(--forge-success)", muted: "var(--forge-ink-muted)", warning: "var(--forge-accent)", danger: "var(--forge-danger)", info: "var(--forge-info)" }[tone];
101
+ return (_jsx("span", { title: title, className: "forge-badge inline-flex shrink-0 items-center gap-1 px-2 py-0.5 text-xs font-medium whitespace-nowrap", style: { "--tone": color }, children: children }));
102
+ }
103
+ /** "Saving…" / "Saved" / "Couldn't save" next to the editor's title; announced politely. */
104
+ export function SaveIndicator({ state, message }) {
105
+ const t = useT();
106
+ const content = state === "saving" ? (_jsxs(_Fragment, { children: [_jsx(LoaderCircle, { className: "size-3.5 animate-spin motion-reduce:animate-none", "aria-hidden": true }), " ", t("siteAdmin.save.saving")] })) : state === "saved" ? (_jsxs(_Fragment, { children: [_jsx(CircleCheck, { className: "size-3.5 text-[var(--forge-success)]", "aria-hidden": true }), " ", t("siteAdmin.save.saved")] })) : state === "error" ? (_jsxs(_Fragment, { children: [_jsx(CircleAlert, { className: "size-3.5 text-danger", "aria-hidden": true }), " ", message ?? t("siteAdmin.save.error")] })) : state === "invalid" ? (_jsxs(_Fragment, { children: [_jsx(CircleAlert, { className: "size-3.5 text-danger", "aria-hidden": true }), " ", t("siteAdmin.save.invalid")] })) : state === "dirty" ? (_jsxs(_Fragment, { children: [_jsx(CloudUpload, { className: "size-3.5", "aria-hidden": true }), " ", t("siteAdmin.save.pending")] })) : null;
107
+ return (_jsx("span", { role: "status", "aria-live": "polite", className: "inline-flex min-h-5 items-center gap-1.5 text-xs text-ink-muted", children: content }));
108
+ }
109
+ /** A visually hidden polite live region; `announce(text)` reads text out (reorders, adds, removals). */
110
+ export function useAnnouncer() {
111
+ const [text, setText] = useState("");
112
+ const announce = useCallback((next) => {
113
+ // Clear first so the same sentence twice is still announced.
114
+ setText("");
115
+ requestAnimationFrame(() => setText(next));
116
+ }, []);
117
+ const region = (_jsx("div", { "aria-live": "assertive", "aria-atomic": "true", className: "sr-only", children: text }));
118
+ return [region, announce];
119
+ }
120
+ /** Confirmation in an accessible dialog (focus starts on Cancel, the safe choice). */
121
+ export function Confirm({ open, title, message, confirmLabel, danger, loading, onConfirm, onClose }) {
122
+ const t = useT();
123
+ return (_jsx(EditorDialog, { open: open, onClose: onClose, title: title, footer: _jsxs(_Fragment, { children: [_jsx("button", { type: "button", "data-autofocus": true, className: "forge-btn forge-btn-secondary inline-flex h-[var(--forge-control-h)] items-center px-3.5 text-sm font-medium", onClick: onClose, children: t("common.cancel") }), _jsxs("button", { type: "button", disabled: loading, className: cn("forge-btn inline-flex h-[var(--forge-control-h)] items-center gap-1.5 px-3.5 text-sm font-medium", danger ? "forge-btn-danger" : "forge-btn-primary"), onClick: onConfirm, children: [loading && _jsx(LoaderCircle, { className: "size-3.5 animate-spin motion-reduce:animate-none", "aria-hidden": true }), confirmLabel] })] }), children: message }));
124
+ }
125
+ /** Text with a live "12 / 160" counter (SEO fields). */
126
+ export function Counter({ value, max, recommended }) {
127
+ const over = value.length > (recommended ?? max);
128
+ return _jsx("span", { className: cn("text-xs tabular-nums", over ? "text-danger" : "text-ink-subtle"), children: `${value.length} / ${recommended ?? max}` });
129
+ }
130
+ //# sourceMappingURL=widgets.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"widgets.js","sourceRoot":"","sources":["../../../src/site/editor/widgets.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ import type { EntityIR, FieldIR } from "@tekki-forge/compiler";
2
+ import type { ReactNode } from "react";
3
+ import { type Messages, type TranslateVars } from "../i18n/locale.js";
4
+ import type { SiteApp } from "./types.js";
5
+ export type SiteT = (key: string, vars?: TranslateVars) => string;
6
+ /** The app with its schema texts in `locale` (entity and field labels), and `t` for the website's own words. */
7
+ export declare function siteTranslator<A extends SiteApp>(baseApp: A, locale?: string, messages?: Record<string, Messages>): {
8
+ app: A;
9
+ lang: string;
10
+ t: SiteT;
11
+ };
12
+ /** A date (ISO string) in the visitor's language: "12 March 2026". Date-only values are not shifted by time zones. */
13
+ export declare function formatDate(value: unknown, locale: string, withTime?: boolean): string;
14
+ /** The field of an entity by name or API name ("owner" / "ownerId"). */
15
+ export declare const entityField: (entity: EntityIR, name: string) => FieldIR | undefined;
16
+ /** The value of a field in a row returned by the resource API (keyed by apiName, relations by name). */
17
+ export declare const rowValue: (row: Record<string, unknown>, f: FieldIR | undefined, name: string) => unknown;
18
+ /** An uploaded file or image as the API presents it ({ url, name }), or a plain URL. */
19
+ export declare function fileOf(value: unknown): {
20
+ url: string;
21
+ name: string;
22
+ } | null;
23
+ /** One value as text, formatted by the field's kind: money, numbers, dates, yes/no, enum and relation labels. */
24
+ export declare function formatFieldText(f: FieldIR | undefined, value: unknown, locale: string, t: SiteT): string;
25
+ /** One value as content: links for URLs, e-mails and files, a swatch for colours, text otherwise. */
26
+ export declare function SiteFieldValue({ field, value, locale, t }: {
27
+ field: FieldIR | undefined;
28
+ value: unknown;
29
+ locale: string;
30
+ t: SiteT;
31
+ }): ReactNode;
@@ -0,0 +1,106 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { localizeSchema } from "@tekki-forge/compiler/i18n";
3
+ import { validHref, validImage } from "@tekki-forge/compiler/site";
4
+ import { uiCatalogs } from "../i18n/catalog.js";
5
+ import { translate } from "../i18n/locale.js";
6
+ /** The app with its schema texts in `locale` (entity and field labels), and `t` for the website's own words. */
7
+ export function siteTranslator(baseApp, locale, messages = {}) {
8
+ const lang = locale ?? baseApp.i18n?.defaultLocale ?? "en";
9
+ const app = lang === (baseApp.i18n?.defaultLocale ?? "en") || !messages[lang] ? baseApp : { ...baseApp, ...localizeSchema(baseApp, {}, messages[lang]).app };
10
+ return { app, lang, t: (key, vars) => translate([...uiCatalogs(lang), messages[lang] ?? {}], lang, key, vars) };
11
+ }
12
+ /** A date (ISO string) in the visitor's language: "12 March 2026". Date-only values are not shifted by time zones. */
13
+ export function formatDate(value, locale, withTime = false) {
14
+ if (typeof value !== "string" && !(value instanceof Date))
15
+ return "";
16
+ const s = String(value instanceof Date ? value.toISOString() : value);
17
+ const dateOnly = /^\d{4}-\d{2}-\d{2}$/.test(s);
18
+ const d = new Date(dateOnly ? `${s}T00:00:00Z` : s);
19
+ if (Number.isNaN(d.getTime()))
20
+ return s;
21
+ try {
22
+ return new Intl.DateTimeFormat(locale, { dateStyle: "medium", ...(withTime && !dateOnly ? { timeStyle: "short" } : {}), ...(dateOnly || !withTime ? { timeZone: "UTC" } : {}) }).format(d);
23
+ }
24
+ catch {
25
+ return s.slice(0, 10);
26
+ }
27
+ }
28
+ /** The field of an entity by name or API name ("owner" / "ownerId"). */
29
+ export const entityField = (entity, name) => entity.fields.find((f) => f.name === name || f.apiName === name);
30
+ /** The value of a field in a row returned by the resource API (keyed by apiName, relations by name). */
31
+ export const rowValue = (row, f, name) => (f ? (row[f.name] ?? row[f.apiName]) : row[name]);
32
+ /** An uploaded file or image as the API presents it ({ url, name }), or a plain URL. */
33
+ export function fileOf(value) {
34
+ if (typeof value === "string")
35
+ return validImage(value) ? { url: value, name: value.split("/").pop() ?? value } : null;
36
+ if (value && typeof value === "object" && typeof value.url === "string") {
37
+ const url = value.url;
38
+ return validImage(url) ? { url, name: String(value.name ?? url.split("/").pop() ?? "") } : null;
39
+ }
40
+ return null;
41
+ }
42
+ /** One value as text, formatted by the field's kind: money, numbers, dates, yes/no, enum and relation labels. */
43
+ export function formatFieldText(f, value, locale, t) {
44
+ if (value === null || value === undefined || value === "")
45
+ return "";
46
+ if (!f)
47
+ return typeof value === "object" ? "" : String(value);
48
+ try {
49
+ switch (f.kind) {
50
+ case "money":
51
+ return new Intl.NumberFormat(locale, { style: "currency", currency: f.currency ?? "USD" }).format(Number(value));
52
+ case "integer":
53
+ case "decimal":
54
+ return new Intl.NumberFormat(locale, f.scale !== undefined ? { maximumFractionDigits: f.scale } : {}).format(Number(value));
55
+ case "percentage":
56
+ return new Intl.NumberFormat(locale, { style: "percent", maximumFractionDigits: 2 }).format(Number(value) / 100);
57
+ case "boolean":
58
+ return value ? t("site.value.yes") : t("site.value.no");
59
+ case "date":
60
+ return formatDate(value, locale);
61
+ case "datetime":
62
+ return formatDate(value, locale, true);
63
+ case "enum":
64
+ return f.enumValues?.find((v) => v.value === value)?.label ?? String(value);
65
+ case "relation": {
66
+ const label = (v) => (v && typeof v === "object" ? String(v.label ?? "") : "");
67
+ return Array.isArray(value) ? value.map(label).filter(Boolean).join(", ") : label(value);
68
+ }
69
+ case "location": {
70
+ const { lat, lng } = value;
71
+ return typeof lat === "number" && typeof lng === "number" ? `${lat.toFixed(4)}, ${lng.toFixed(4)}` : "";
72
+ }
73
+ case "file":
74
+ case "image":
75
+ return fileOf(value)?.name ?? "";
76
+ case "json":
77
+ return "";
78
+ default:
79
+ return typeof value === "object" ? "" : String(value);
80
+ }
81
+ }
82
+ catch {
83
+ return String(value);
84
+ }
85
+ }
86
+ /** One value as content: links for URLs, e-mails and files, a swatch for colours, text otherwise. */
87
+ export function SiteFieldValue({ field, value, locale, t }) {
88
+ if (value === null || value === undefined || value === "")
89
+ return null;
90
+ if (field?.kind === "url" && typeof value === "string" && /^https?:\/\//i.test(value) && validHref(value)) {
91
+ return (_jsx("a", { href: value, rel: "noopener", className: "forge-focusable text-link underline-offset-2 hover:underline", children: value.replace(/^https?:\/\/(www\.)?/i, "").replace(/\/$/, "") }));
92
+ }
93
+ if (field?.kind === "email" && typeof value === "string" && validHref(`mailto:${value}`)) {
94
+ return (_jsx("a", { href: `mailto:${value}`, className: "forge-focusable text-link underline-offset-2 hover:underline", children: value }));
95
+ }
96
+ if (field?.kind === "file") {
97
+ const file = fileOf(value);
98
+ return file ? (_jsx("a", { href: file.url, className: "forge-focusable text-link underline-offset-2 hover:underline", children: file.name })) : null;
99
+ }
100
+ if (field?.kind === "color" && typeof value === "string" && /^#[0-9a-f]{3,8}$/i.test(value)) {
101
+ return (_jsxs("span", { className: "inline-flex items-center gap-1.5", children: [_jsx("span", { className: "size-3 rounded-full ring-1 ring-line", style: { background: value }, "aria-hidden": true }), value] }));
102
+ }
103
+ const text = formatFieldText(field, value, locale, t);
104
+ return text || null;
105
+ }
106
+ //# sourceMappingURL=format.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format.js","sourceRoot":"","sources":["../../src/site/format.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,43 @@
1
+ export interface SiteFormLabels {
2
+ name: string;
3
+ email: string;
4
+ company: string;
5
+ message: string;
6
+ optional: string;
7
+ submit: string;
8
+ sending: string;
9
+ success: string;
10
+ required: string;
11
+ invalidEmail: string;
12
+ tooLong: string;
13
+ messageTooShort: string;
14
+ error: string;
15
+ rateLimited: string;
16
+ /** Label of the honeypot (never seen by people). */
17
+ honeypot: string;
18
+ }
19
+ export interface ContactFormProps {
20
+ labels: SiteFormLabels;
21
+ /** Ask for a company name. */
22
+ company?: boolean;
23
+ buttonLabel?: string;
24
+ successMessage?: string;
25
+ /** Path of the page the form is on (stored with the message). */
26
+ page?: string;
27
+ endpoint?: string;
28
+ /** Editor preview: shown but not sendable. */
29
+ disabled?: boolean;
30
+ }
31
+ export declare function ContactForm({ labels, company, buttonLabel, successMessage, page, endpoint, disabled }: ContactFormProps): import("react").JSX.Element;
32
+ export interface NewsletterFormProps {
33
+ labels: Pick<SiteFormLabels, "email" | "submit" | "sending" | "success" | "required" | "invalidEmail" | "error" | "rateLimited" | "honeypot">;
34
+ buttonLabel?: string;
35
+ successMessage?: string;
36
+ /** Where the address was collected (stored with it). */
37
+ source?: string;
38
+ /** "row": field and button side by side (from medium widths). */
39
+ layout?: "row" | "stacked";
40
+ endpoint?: string;
41
+ disabled?: boolean;
42
+ }
43
+ export declare function NewsletterForm({ labels, buttonLabel, successMessage, source, layout, endpoint, disabled }: NewsletterFormProps): import("react").JSX.Element;
@@ -0,0 +1,155 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { CircleCheck, LoaderCircle } from "lucide-react";
4
+ import { useEffect, useId, useRef, useState } from "react";
5
+ const EMAIL = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
6
+ async function post(endpoint, body) {
7
+ try {
8
+ const res = await fetch(endpoint, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify(body), credentials: "same-origin" });
9
+ if (res.ok)
10
+ return { ok: true };
11
+ const data = (await res.json().catch(() => ({})));
12
+ return { ok: false, status: res.status, issues: Array.isArray(data.issues) ? data.issues : [] };
13
+ }
14
+ catch {
15
+ return { ok: false, status: 0, issues: [] };
16
+ }
17
+ }
18
+ /** The honeypot: off-screen, out of the tab order and hidden from screen readers. Bots fill every field. */
19
+ function Honeypot({ label, value, onChange }) {
20
+ const id = useId();
21
+ return (_jsxs("div", { "aria-hidden": "true", className: "forge-site-honeypot", children: [_jsx("label", { htmlFor: id, children: label }), _jsx("input", { id: id, name: "website", type: "text", tabIndex: -1, autoComplete: "off", value: value, onChange: (e) => onChange(e.target.value) })] }));
22
+ }
23
+ /** When the form appeared (set after hydration so server and client markup match). */
24
+ function useStartedAt() {
25
+ const startedAt = useRef(0);
26
+ useEffect(() => {
27
+ startedAt.current = Date.now();
28
+ }, []);
29
+ return startedAt;
30
+ }
31
+ function Field({ id, label, hint, error, children }) {
32
+ return (_jsxs("div", { className: "grid gap-1.5", children: [_jsxs("label", { htmlFor: id, className: "text-sm font-medium text-ink", children: [label, hint && _jsx("span", { className: "ml-1.5 font-normal text-ink-muted", children: hint })] }), children, error && (_jsx("p", { id: `${id}-error`, className: "forge-site-field-error text-sm", children: error }))] }));
33
+ }
34
+ function Success({ text }) {
35
+ return (_jsxs("span", { className: "flex items-start gap-3", children: [_jsx(CircleCheck, { className: "forge-site-success-icon mt-0.5 size-5 shrink-0", "aria-hidden": true }), _jsx("span", { children: text })] }));
36
+ }
37
+ export function ContactForm({ labels, company = false, buttonLabel, successMessage, page, endpoint = "/api/site/contact", disabled = false }) {
38
+ const id = useId();
39
+ const startedAt = useStartedAt();
40
+ const [values, setValues] = useState({ name: "", email: "", company: "", message: "" });
41
+ const [website, setWebsite] = useState("");
42
+ const [errors, setErrors] = useState({});
43
+ const [tried, setTried] = useState(false);
44
+ const [state, setState] = useState("idle");
45
+ const [failure, setFailure] = useState(null);
46
+ const form = useRef(null);
47
+ const check = (v) => {
48
+ const e = {};
49
+ if (!v.name.trim())
50
+ e.name = labels.required;
51
+ else if (v.name.length > 100)
52
+ e.name = labels.tooLong.replace("{max}", "100");
53
+ if (!v.email.trim())
54
+ e.email = labels.required;
55
+ else if (!EMAIL.test(v.email.trim()) || v.email.length > 200)
56
+ e.email = labels.invalidEmail;
57
+ if (company && v.company.length > 100)
58
+ e.company = labels.tooLong.replace("{max}", "100");
59
+ if (!v.message.trim())
60
+ e.message = labels.required;
61
+ else if (v.message.trim().length < 10)
62
+ e.message = labels.messageTooShort.replace("{min}", "10");
63
+ else if (v.message.length > 5000)
64
+ e.message = labels.tooLong.replace("{max}", "5000");
65
+ return e;
66
+ };
67
+ const set = (k) => (e) => {
68
+ const next = { ...values, [k]: e.target.value };
69
+ setValues(next);
70
+ if (tried)
71
+ setErrors(check(next));
72
+ };
73
+ async function submit(e) {
74
+ e.preventDefault();
75
+ if (disabled || state === "sending")
76
+ return;
77
+ setTried(true);
78
+ setFailure(null);
79
+ const found = check(values);
80
+ setErrors(found);
81
+ const first = ["name", "email", "company", "message"].find((k) => found[k]);
82
+ if (first) {
83
+ form.current?.querySelector(`#${CSS.escape(`${id}-${first}`)}`)?.focus();
84
+ return;
85
+ }
86
+ setState("sending");
87
+ const result = await post(endpoint, {
88
+ name: values.name.trim(),
89
+ email: values.email.trim(),
90
+ ...(company && values.company.trim() ? { company: values.company.trim() } : {}),
91
+ message: values.message.trim(),
92
+ ...(page ? { page } : {}),
93
+ website,
94
+ startedAt: startedAt.current || Date.now(),
95
+ });
96
+ if (result.ok) {
97
+ setState("done");
98
+ return;
99
+ }
100
+ setState("idle");
101
+ const fieldErrors = {};
102
+ for (const issue of result.issues) {
103
+ const key = issue.path.split(".")[0];
104
+ if (["name", "email", "company", "message"].includes(key))
105
+ fieldErrors[key] = issue.message;
106
+ }
107
+ if (Object.keys(fieldErrors).length)
108
+ setErrors(fieldErrors);
109
+ else
110
+ setFailure(result.status === 429 ? labels.rateLimited : labels.error);
111
+ }
112
+ const done = state === "done";
113
+ const describedBy = (k) => (errors[k] ? `${id}-${k}-error` : undefined);
114
+ return (_jsxs("div", { className: "forge-site-form", children: [!done && (_jsxs("form", { ref: form, noValidate: true, onSubmit: submit, className: "grid gap-5", "aria-busy": state === "sending", children: [_jsxs("div", { className: "grid gap-5 @xl:grid-cols-2", children: [_jsx(Field, { id: `${id}-name`, label: labels.name, error: errors.name, children: _jsx("input", { id: `${id}-name`, name: "name", autoComplete: "name", required: true, maxLength: 100, value: values.name, onChange: set("name"), "aria-invalid": !!errors.name, "aria-describedby": describedBy("name"), className: "forge-input h-11 w-full px-3.5 text-base" }) }), _jsx(Field, { id: `${id}-email`, label: labels.email, error: errors.email, children: _jsx("input", { id: `${id}-email`, name: "email", type: "email", autoComplete: "email", inputMode: "email", required: true, maxLength: 200, value: values.email, onChange: set("email"), "aria-invalid": !!errors.email, "aria-describedby": describedBy("email"), className: "forge-input h-11 w-full px-3.5 text-base" }) })] }), company && (_jsx(Field, { id: `${id}-company`, label: labels.company, hint: labels.optional, error: errors.company, children: _jsx("input", { id: `${id}-company`, name: "company", autoComplete: "organization", maxLength: 100, value: values.company, onChange: set("company"), "aria-invalid": !!errors.company, "aria-describedby": describedBy("company"), className: "forge-input h-11 w-full px-3.5 text-base" }) })), _jsx(Field, { id: `${id}-message`, label: labels.message, error: errors.message, children: _jsx("textarea", { id: `${id}-message`, name: "message", required: true, rows: 6, maxLength: 5000, value: values.message, onChange: set("message"), "aria-invalid": !!errors.message, "aria-describedby": describedBy("message"), className: "forge-input min-h-36 w-full resize-y px-3.5 py-3 text-base" }) }), _jsx(Honeypot, { label: labels.honeypot, value: website, onChange: setWebsite }), failure && (_jsx("p", { role: "alert", className: "forge-alert px-3.5 py-2.5 text-sm", "data-forge-alert": "error", children: failure })), _jsx("div", { children: _jsxs("button", { type: "submit", disabled: disabled || state === "sending", className: "forge-btn forge-btn-primary inline-flex h-11 items-center justify-center gap-2 px-6 text-base font-medium", children: [state === "sending" && _jsx(LoaderCircle, { className: "forge-site-spin size-4", "aria-hidden": true }), state === "sending" ? labels.sending : buttonLabel || labels.submit] }) })] })), _jsx("div", { role: "status", "aria-live": "polite", className: done ? "forge-site-success p-5 text-base" : "sr-only", children: done ? _jsx(Success, { text: successMessage || labels.success }) : "" })] }));
115
+ }
116
+ export function NewsletterForm({ labels, buttonLabel, successMessage, source, layout = "row", endpoint = "/api/site/newsletter", disabled = false }) {
117
+ const id = useId();
118
+ const [email, setEmail] = useState("");
119
+ const [website, setWebsite] = useState("");
120
+ const [error, setError] = useState(null);
121
+ const [state, setState] = useState("idle");
122
+ const [failure, setFailure] = useState(null);
123
+ const input = useRef(null);
124
+ const check = (v) => (!v.trim() ? labels.required : !EMAIL.test(v.trim()) || v.length > 200 ? labels.invalidEmail : null);
125
+ async function submit(e) {
126
+ e.preventDefault();
127
+ if (disabled || state === "sending")
128
+ return;
129
+ setFailure(null);
130
+ const problem = check(email);
131
+ setError(problem);
132
+ if (problem) {
133
+ input.current?.focus();
134
+ return;
135
+ }
136
+ setState("sending");
137
+ const result = await post(endpoint, { email: email.trim(), website, ...(source ? { source } : {}) });
138
+ if (result.ok)
139
+ setState("done");
140
+ else {
141
+ setState("idle");
142
+ if (result.issues.length)
143
+ setError(result.issues[0].message);
144
+ else
145
+ setFailure(result.status === 429 ? labels.rateLimited : labels.error);
146
+ }
147
+ }
148
+ const done = state === "done";
149
+ return (_jsxs("div", { className: "forge-site-form w-full", children: [!done && (_jsxs("form", { noValidate: true, onSubmit: submit, "aria-busy": state === "sending", children: [_jsxs("div", { className: layout === "row" ? "flex flex-col gap-2.5 @md:flex-row" : "grid gap-2.5", children: [_jsx("label", { htmlFor: `${id}-email`, className: "sr-only", children: labels.email }), _jsx("input", { ref: input, id: `${id}-email`, name: "email", type: "email", autoComplete: "email", inputMode: "email", required: true, maxLength: 200, placeholder: labels.email, value: email, onChange: (e) => {
150
+ setEmail(e.target.value);
151
+ if (error)
152
+ setError(check(e.target.value));
153
+ }, "aria-invalid": !!error, "aria-describedby": error ? `${id}-error` : undefined, className: "forge-input h-11 w-full min-w-0 flex-1 px-3.5 text-base" }), _jsxs("button", { type: "submit", disabled: disabled || state === "sending", className: "forge-btn forge-btn-primary inline-flex h-11 shrink-0 items-center justify-center gap-2 px-5 text-base font-medium", children: [state === "sending" && _jsx(LoaderCircle, { className: "forge-site-spin size-4", "aria-hidden": true }), state === "sending" ? labels.sending : buttonLabel || labels.submit] })] }), error && (_jsx("p", { id: `${id}-error`, className: "forge-site-field-error mt-2 text-sm", children: error })), _jsx(Honeypot, { label: labels.honeypot, value: website, onChange: setWebsite }), failure && (_jsx("p", { role: "alert", className: "forge-alert mt-3 px-3.5 py-2.5 text-sm", "data-forge-alert": "error", children: failure }))] })), _jsx("div", { role: "status", "aria-live": "polite", className: done ? "forge-site-success p-4 text-base" : "sr-only", children: done ? _jsx(Success, { text: successMessage || labels.success }) : "" })] }));
154
+ }
155
+ //# sourceMappingURL=forms.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"forms.js","sourceRoot":"","sources":["../../src/site/forms.tsx"],"names":[],"mappings":"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"}