@cosmicdrift/kumiko-document-designer 0.0.0-stage → 0.364.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 (126) hide show
  1. package/LICENSE +57 -0
  2. package/README.md +37 -2
  3. package/dist/constants.d.ts +27 -0
  4. package/dist/constants.js +37 -0
  5. package/dist/feature.d.ts +2 -0
  6. package/dist/feature.js +85 -0
  7. package/dist/i18n.d.ts +6 -0
  8. package/dist/i18n.js +764 -0
  9. package/dist/index.d.ts +2 -0
  10. package/dist/index.js +2 -0
  11. package/dist/list-definition.d.ts +6 -0
  12. package/dist/list-definition.js +109 -0
  13. package/dist/web/cells.d.ts +10 -0
  14. package/dist/web/cells.js +87 -0
  15. package/dist/web/client-plugin.d.ts +12 -0
  16. package/dist/web/client-plugin.js +43 -0
  17. package/dist/web/compose-layout.d.ts +6 -0
  18. package/dist/web/compose-layout.js +13 -0
  19. package/dist/web/editor-header.d.ts +37 -0
  20. package/dist/web/editor-header.js +43 -0
  21. package/dist/web/editor-shell.d.ts +40 -0
  22. package/dist/web/editor-shell.js +36 -0
  23. package/dist/web/errors.d.ts +6 -0
  24. package/dist/web/errors.js +24 -0
  25. package/dist/web/field-issue-text.d.ts +4 -0
  26. package/dist/web/field-issue-text.js +12 -0
  27. package/dist/web/file-name.d.ts +2 -0
  28. package/dist/web/file-name.js +17 -0
  29. package/dist/web/i18n.d.ts +2 -0
  30. package/dist/web/i18n.js +146 -0
  31. package/dist/web/index.d.ts +6 -0
  32. package/dist/web/index.js +7 -0
  33. package/dist/web/layout-editor-body.d.ts +14 -0
  34. package/dist/web/layout-editor-body.js +187 -0
  35. package/dist/web/layout-editor.d.ts +2 -0
  36. package/dist/web/layout-editor.js +43 -0
  37. package/dist/web/layout-html.d.ts +9 -0
  38. package/dist/web/layout-html.js +93 -0
  39. package/dist/web/layout-meta.d.ts +29 -0
  40. package/dist/web/layout-meta.js +32 -0
  41. package/dist/web/layout-rails.d.ts +28 -0
  42. package/dist/web/layout-rails.js +100 -0
  43. package/dist/web/layout-types.d.ts +66 -0
  44. package/dist/web/layout-types.js +1 -0
  45. package/dist/web/layout-users.d.ts +4 -0
  46. package/dist/web/layout-users.js +11 -0
  47. package/dist/web/mail-dialogs.d.ts +24 -0
  48. package/dist/web/mail-dialogs.js +15 -0
  49. package/dist/web/mail-draft.d.ts +19 -0
  50. package/dist/web/mail-draft.js +154 -0
  51. package/dist/web/mail-edit-center.d.ts +19 -0
  52. package/dist/web/mail-edit-center.js +12 -0
  53. package/dist/web/mail-editor-body.d.ts +17 -0
  54. package/dist/web/mail-editor-body.js +209 -0
  55. package/dist/web/mail-editor.d.ts +2 -0
  56. package/dist/web/mail-editor.js +68 -0
  57. package/dist/web/mail-footer.d.ts +10 -0
  58. package/dist/web/mail-footer.js +43 -0
  59. package/dist/web/mail-left-rail.d.ts +23 -0
  60. package/dist/web/mail-left-rail.js +56 -0
  61. package/dist/web/mail-missing-locale.d.ts +10 -0
  62. package/dist/web/mail-missing-locale.js +45 -0
  63. package/dist/web/mail-origin-bar.d.ts +15 -0
  64. package/dist/web/mail-origin-bar.js +60 -0
  65. package/dist/web/mail-pdf-link-modal.d.ts +11 -0
  66. package/dist/web/mail-pdf-link-modal.js +54 -0
  67. package/dist/web/mail-preview-side.d.ts +19 -0
  68. package/dist/web/mail-preview-side.js +57 -0
  69. package/dist/web/mail-preview.d.ts +24 -0
  70. package/dist/web/mail-preview.js +54 -0
  71. package/dist/web/mail-right-rail.d.ts +19 -0
  72. package/dist/web/mail-right-rail.js +57 -0
  73. package/dist/web/mail-types.d.ts +117 -0
  74. package/dist/web/mail-types.js +1 -0
  75. package/dist/web/mail-upload-modal.d.ts +16 -0
  76. package/dist/web/mail-upload-modal.js +56 -0
  77. package/dist/web/mail-versions.d.ts +6 -0
  78. package/dist/web/mail-versions.js +43 -0
  79. package/dist/web/origin-bar.d.ts +22 -0
  80. package/dist/web/origin-bar.js +104 -0
  81. package/dist/web/overrides-drawer.d.ts +10 -0
  82. package/dist/web/overrides-drawer.js +95 -0
  83. package/dist/web/overview-row.d.ts +23 -0
  84. package/dist/web/overview-row.js +48 -0
  85. package/dist/web/page-canvas.d.ts +19 -0
  86. package/dist/web/page-canvas.js +48 -0
  87. package/dist/web/pdf-footer.d.ts +13 -0
  88. package/dist/web/pdf-footer.js +34 -0
  89. package/dist/web/pdf-left-rail.d.ts +9 -0
  90. package/dist/web/pdf-left-rail.js +16 -0
  91. package/dist/web/pdf-meta.d.ts +21 -0
  92. package/dist/web/pdf-meta.js +95 -0
  93. package/dist/web/pdf-preview.d.ts +4 -0
  94. package/dist/web/pdf-preview.js +112 -0
  95. package/dist/web/pdf-template-editor.d.ts +8 -0
  96. package/dist/web/pdf-template-editor.js +340 -0
  97. package/dist/web/preview-record-picker.d.ts +12 -0
  98. package/dist/web/preview-record-picker.js +7 -0
  99. package/dist/web/rail.d.ts +30 -0
  100. package/dist/web/rail.js +22 -0
  101. package/dist/web/relative-time.d.ts +1 -0
  102. package/dist/web/relative-time.js +18 -0
  103. package/dist/web/settings-panel.d.ts +23 -0
  104. package/dist/web/settings-panel.js +36 -0
  105. package/dist/web/status-label.d.ts +14 -0
  106. package/dist/web/status-label.js +26 -0
  107. package/dist/web/template-rows.d.ts +9 -0
  108. package/dist/web/template-rows.js +34 -0
  109. package/dist/web/types.d.ts +126 -0
  110. package/dist/web/types.js +3 -0
  111. package/dist/web/use-insert-targets.d.ts +9 -0
  112. package/dist/web/use-insert-targets.js +17 -0
  113. package/dist/web/use-mail-persistence.d.ts +14 -0
  114. package/dist/web/use-mail-persistence.js +49 -0
  115. package/dist/web/use-overview-rows.d.ts +7 -0
  116. package/dist/web/use-overview-rows.js +19 -0
  117. package/dist/web/use-own-address.d.ts +5 -0
  118. package/dist/web/use-own-address.js +14 -0
  119. package/dist/web/use-settled-value.d.ts +2 -0
  120. package/dist/web/use-settled-value.js +18 -0
  121. package/dist/web/use-test-mail.d.ts +15 -0
  122. package/dist/web/use-test-mail.js +27 -0
  123. package/dist/web/used-by-label.d.ts +9 -0
  124. package/dist/web/used-by-label.js +32 -0
  125. package/package.json +63 -4
  126. package/src/changes.json +44 -0
@@ -0,0 +1,126 @@
1
+ import type { FieldIssue } from "@cosmicdrift/kumiko-headless";
2
+ import type { TemplateDiff } from "./layout-types.js";
3
+ export type TemplateScope = "system" | "tenant";
4
+ export type TemplateStatus = "draft" | "active" | "archived";
5
+ export declare const DOCUMENT_PDF_KIND: "document-pdf";
6
+ export declare const PDF_LAYOUT_KIND: "pdf-layout";
7
+ export declare const DEFAULT_LAYOUT_SLUG = "default";
8
+ export type TemplateListRow = {
9
+ readonly id: string;
10
+ readonly tenantId: string;
11
+ readonly slug: string;
12
+ readonly kind: string;
13
+ readonly locale: string;
14
+ readonly scope: TemplateScope;
15
+ readonly status: TemplateStatus;
16
+ readonly contentFormat: string;
17
+ readonly modifiedAt: string | null;
18
+ };
19
+ export type TemplateDetail = {
20
+ readonly id: string;
21
+ readonly version: number;
22
+ readonly tenantId: string;
23
+ readonly slug: string;
24
+ readonly kind: string;
25
+ readonly locale: string;
26
+ readonly content: string;
27
+ readonly contentFormat: string;
28
+ readonly variableSchema: string | null;
29
+ readonly linkedResources: string | null;
30
+ readonly meta: string | null;
31
+ readonly scope: TemplateScope;
32
+ readonly parentTemplateId: string | null;
33
+ readonly status: TemplateStatus;
34
+ readonly modifiedAt: string | null;
35
+ readonly active?: ServedVersionView | null;
36
+ };
37
+ /** The version the resolver serves while a draft is open beside it. */
38
+ export type ServedVersionView = {
39
+ readonly version: number;
40
+ readonly since: string;
41
+ };
42
+ export type VariableType = "text" | "link" | "money" | "date" | "list";
43
+ export type VariableInfo = {
44
+ readonly type: VariableType;
45
+ readonly label?: string;
46
+ readonly required?: boolean;
47
+ readonly item?: Readonly<Record<string, {
48
+ readonly type: VariableType;
49
+ readonly label?: string;
50
+ }>>;
51
+ };
52
+ export type ValidationWarning = {
53
+ readonly code: string;
54
+ readonly detail: string;
55
+ readonly i18nKey: string;
56
+ };
57
+ export type ValidationResult = {
58
+ readonly canSave: boolean;
59
+ readonly canPublish: boolean;
60
+ readonly issues: readonly FieldIssue[];
61
+ readonly publishIssues: readonly FieldIssue[];
62
+ readonly used: readonly string[];
63
+ readonly unknown: readonly string[];
64
+ readonly missingRequired: readonly string[];
65
+ readonly warnings: readonly ValidationWarning[];
66
+ readonly variables: Readonly<Record<string, VariableInfo>>;
67
+ readonly systemPlaceholders: readonly string[];
68
+ };
69
+ export type LayoutRegionsHtml = {
70
+ readonly header: string;
71
+ readonly signature: string;
72
+ readonly footer: string;
73
+ };
74
+ export type PreviewResult = {
75
+ readonly layout: {
76
+ readonly slug: string;
77
+ readonly scope: TemplateScope;
78
+ readonly html: string;
79
+ readonly regions: LayoutRegionsHtml;
80
+ } | null;
81
+ };
82
+ export type PuppeteerStatus = {
83
+ readonly available: true;
84
+ } | {
85
+ readonly available: false;
86
+ readonly error?: string;
87
+ readonly message?: string;
88
+ };
89
+ export type PdfPreviewResult = {
90
+ readonly fileName: string;
91
+ readonly pdfBase64: string;
92
+ readonly pageCount: number;
93
+ readonly sizeBytes: number;
94
+ readonly durationMs: number;
95
+ };
96
+ export type TenantOverrideRow = {
97
+ readonly tenantId: string;
98
+ readonly tenantName: string;
99
+ readonly templateId: string;
100
+ readonly locale: string;
101
+ readonly status: "active" | "draft";
102
+ readonly version: number;
103
+ readonly changedAt: string;
104
+ readonly changedBy: string | null;
105
+ };
106
+ export type TenantOverrides = {
107
+ readonly activeOverrides: number;
108
+ readonly draftOverrides: number;
109
+ readonly totalTenants: number | null;
110
+ readonly rows: readonly TenantOverrideRow[];
111
+ readonly diff: TemplateDiff | null;
112
+ };
113
+ export type SaveResult = {
114
+ readonly id: string;
115
+ readonly slug: string;
116
+ readonly isNew: boolean;
117
+ };
118
+ export type TemplateUsage = {
119
+ readonly usedBy: readonly {
120
+ readonly qualifiedName: string;
121
+ readonly feature: string;
122
+ readonly notification: string;
123
+ readonly trigger: string | null;
124
+ readonly role: string;
125
+ }[];
126
+ };
@@ -0,0 +1,3 @@
1
+ export const DOCUMENT_PDF_KIND = "document-pdf";
2
+ export const PDF_LAYOUT_KIND = "pdf-layout";
3
+ export const DEFAULT_LAYOUT_SLUG = "default";
@@ -0,0 +1,9 @@
1
+ import type { DocumentEditorHandle } from "@cosmicdrift/kumiko-bundled-features/template-resolver/web";
2
+ export type InsertField = "subject" | "previewText" | "body" | "title" | "author";
3
+ export type InsertTargets = {
4
+ readonly register: (field: InsertField) => (handle: DocumentEditorHandle) => void;
5
+ readonly markFocused: (field: InsertField) => () => void;
6
+ readonly insertPlaceholder: (name: string) => void;
7
+ readonly insertResource: (key: string) => void;
8
+ };
9
+ export declare function useInsertTargets(): InsertTargets;
@@ -0,0 +1,17 @@
1
+ import { useRef } from "react";
2
+ // The editors are lazy and report their handle once loaded; the rails insert into whichever
3
+ // field had focus last (the content when none had).
4
+ export function useInsertTargets() {
5
+ const handles = useRef({});
6
+ const lastFocused = useRef("body");
7
+ return {
8
+ register: (field) => (handle) => {
9
+ handles.current[field] = handle;
10
+ },
11
+ markFocused: (field) => () => {
12
+ lastFocused.current = field;
13
+ },
14
+ insertPlaceholder: (name) => handles.current[lastFocused.current]?.insertPlaceholder(name),
15
+ insertResource: (key) => handles.current.body?.insertResource(key),
16
+ };
17
+ }
@@ -0,0 +1,14 @@
1
+ import type { MailDraft, TemplateRowView } from "./mail-types.js";
2
+ export type MailPersistence = {
3
+ readonly save: (draft: MailDraft, publish: boolean) => Promise<boolean>;
4
+ readonly busy: boolean;
5
+ readonly error: string | null;
6
+ readonly clearError: () => void;
7
+ };
8
+ export declare function useMailPersistence(args: {
9
+ readonly slug: string;
10
+ readonly locale: string;
11
+ readonly title: string;
12
+ readonly isSystemAdmin: boolean;
13
+ readonly row: TemplateRowView | null;
14
+ }): MailPersistence;
@@ -0,0 +1,49 @@
1
+ // @runtime client
2
+ import { TemplateResolverHandlers } from "@cosmicdrift/kumiko-bundled-features/template-resolver/web";
3
+ import { useMutation, useTranslation } from "@cosmicdrift/kumiko-renderer";
4
+ import { useState } from "react";
5
+ import { errorTextWithFieldIssues } from "./field-issue-text.js";
6
+ import { buildMeta, parseJsonRecord } from "./mail-draft.js";
7
+ // One write for save and publish. The overview title is passed on every write because the
8
+ // upsert replaces a missing title with null and find-by-id does not return it.
9
+ export function useMailPersistence(args) {
10
+ const t = useTranslation();
11
+ const upsertTenant = useMutation(TemplateResolverHandlers.upsertTenant);
12
+ const upsertSystem = useMutation(TemplateResolverHandlers.upsertSystem);
13
+ const publishSystem = useMutation(TemplateResolverHandlers.publishSystem);
14
+ const [error, setError] = useState(null);
15
+ const save = async (draft, publish) => {
16
+ setError(null);
17
+ const base = {
18
+ slug: args.slug,
19
+ kind: "mail",
20
+ locale: args.locale,
21
+ title: args.title,
22
+ content: draft.body,
23
+ contentFormat: "html",
24
+ meta: buildMeta(draft),
25
+ variableSchema: parseJsonRecord(args.row?.variableSchema),
26
+ };
27
+ const saved = args.isSystemAdmin
28
+ ? await upsertSystem.mutate(base)
29
+ : await upsertTenant.mutate({ ...base, status: publish ? "active" : "draft" });
30
+ if (!saved.isSuccess) {
31
+ setError(errorTextWithFieldIssues(saved.error, t));
32
+ return false;
33
+ }
34
+ if (args.isSystemAdmin && publish) {
35
+ const published = await publishSystem.mutate({ id: saved.data.id });
36
+ if (!published.isSuccess) {
37
+ setError(errorTextWithFieldIssues(published.error, t));
38
+ return false;
39
+ }
40
+ }
41
+ return true;
42
+ };
43
+ return {
44
+ save,
45
+ busy: upsertTenant.pending || upsertSystem.pending || publishSystem.pending,
46
+ error,
47
+ clearError: () => setError(null),
48
+ };
49
+ }
@@ -0,0 +1,7 @@
1
+ import { type OverviewRowView } from "./overview-row.js";
2
+ export type OverviewRows = {
3
+ readonly rows: readonly OverviewRowView[];
4
+ readonly loaded: boolean;
5
+ readonly refetch: () => Promise<void>;
6
+ };
7
+ export declare function useOverviewRows(kind: string, search?: string): OverviewRows;
@@ -0,0 +1,19 @@
1
+ // @runtime client
2
+ import { TemplateResolverQueries } from "@cosmicdrift/kumiko-bundled-features/template-resolver/web";
3
+ import { useQuery } from "@cosmicdrift/kumiko-renderer";
4
+ import { parseOverviewRow } from "./overview-row.js";
5
+ // One overview row per slug and kind; the filter is applied on the server.
6
+ export function useOverviewRows(kind, search) {
7
+ const query = useQuery(TemplateResolverQueries.overview, {
8
+ filters: [{ field: "kind", op: "in", value: [kind] }],
9
+ limit: 200,
10
+ ...(search !== undefined && { search }),
11
+ });
12
+ return {
13
+ rows: (query.data?.rows ?? []).flatMap((row) => parseOverviewRow(row) ?? []),
14
+ loaded: query.data !== null,
15
+ refetch: async () => {
16
+ await query.refetch();
17
+ },
18
+ };
19
+ }
@@ -0,0 +1,5 @@
1
+ export type OwnAddress = {
2
+ readonly email: string | null;
3
+ readonly profileScreenId: string | null;
4
+ };
5
+ export declare function useOwnAddress(): OwnAddress;
@@ -0,0 +1,14 @@
1
+ // @runtime client
2
+ import { useAppFeatures, useQuery } from "@cosmicdrift/kumiko-renderer";
3
+ import { PROFILE_FEATURE_NAME, PROFILE_SCREEN_ID, USER_ME_QUERY_QN } from "../constants.js";
4
+ export function useOwnAddress() {
5
+ const features = useAppFeatures();
6
+ const me = useQuery(USER_ME_QUERY_QN, {});
7
+ const email = me.data?.email;
8
+ const hasProfileScreen = features.some((feature) => feature.featureName === PROFILE_FEATURE_NAME &&
9
+ feature.screens.some((screen) => screen.id === PROFILE_SCREEN_ID));
10
+ return {
11
+ email: typeof email === "string" && email !== "" ? email : null,
12
+ profileScreenId: hasProfileScreen ? PROFILE_SCREEN_ID : null,
13
+ };
14
+ }
@@ -0,0 +1,2 @@
1
+ export declare const SETTLE_DELAY_MS = 400;
2
+ export declare function useSettledValue<T>(initial: T): readonly [T, (next: T) => void];
@@ -0,0 +1,18 @@
1
+ // @runtime client
2
+ import { useCallback, useRef, useState } from "react";
3
+ export const SETTLE_DELAY_MS = 400;
4
+ // Handler-driven debounce: the timer starts in the change handler, so no effect is needed.
5
+ // A timer that fires after unmount only sets state on an unmounted component, which is a no-op.
6
+ export function useSettledValue(initial) {
7
+ const [settled, setSettled] = useState(initial);
8
+ const timer = useRef(null);
9
+ const push = useCallback((next) => {
10
+ if (timer.current !== null)
11
+ clearTimeout(timer.current);
12
+ timer.current = setTimeout(() => {
13
+ timer.current = null;
14
+ setSettled(next);
15
+ }, SETTLE_DELAY_MS);
16
+ }, []);
17
+ return [settled, push];
18
+ }
@@ -0,0 +1,15 @@
1
+ export type TestMailState = {
2
+ readonly kind: "idle";
3
+ } | {
4
+ readonly kind: "sent";
5
+ readonly subject: string;
6
+ } | {
7
+ readonly kind: "error";
8
+ readonly text: string;
9
+ };
10
+ export type TestMail = {
11
+ readonly state: TestMailState;
12
+ readonly pending: boolean;
13
+ readonly send: (payload: Readonly<Record<string, unknown>>) => Promise<void>;
14
+ };
15
+ export declare function useTestMail(): TestMail;
@@ -0,0 +1,27 @@
1
+ // @runtime client
2
+ import { TemplateResolverHandlers } from "@cosmicdrift/kumiko-bundled-features/template-resolver/web";
3
+ import { dispatcherErrorText, useMutation, useTranslation } from "@cosmicdrift/kumiko-renderer";
4
+ import { useState } from "react";
5
+ const TOO_MANY_REQUESTS = 429;
6
+ // The recipient is always the caller; the server never returns the address.
7
+ export function useTestMail() {
8
+ const t = useTranslation();
9
+ const sendTest = useMutation(TemplateResolverHandlers.sendTest);
10
+ const [state, setState] = useState({ kind: "idle" });
11
+ const send = async (payload) => {
12
+ setState({ kind: "idle" });
13
+ const result = await sendTest.mutate(payload);
14
+ if (result.isSuccess) {
15
+ setState({ kind: "sent", subject: result.data.subject });
16
+ }
17
+ else {
18
+ setState({
19
+ kind: "error",
20
+ text: result.error.httpStatus === TOO_MANY_REQUESTS
21
+ ? t("documentDesigner.mail.testMail.rateLimited")
22
+ : dispatcherErrorText(result.error, t),
23
+ });
24
+ }
25
+ };
26
+ return { state, pending: sendTest.pending, send };
27
+ }
@@ -0,0 +1,9 @@
1
+ import type { OverviewRowView, OverviewUsageView } from "./overview-row.js";
2
+ type Translate = (key: string, params?: Readonly<Record<string, unknown>>) => string;
3
+ export declare function usageParts(t: Translate, usage: OverviewUsageView): {
4
+ readonly feature: string;
5
+ readonly notification: string;
6
+ };
7
+ export declare function usageLabel(t: Translate, usage: OverviewUsageView): string;
8
+ export declare function usedByLabel(t: Translate, row: OverviewRowView): string;
9
+ export {};
@@ -0,0 +1,32 @@
1
+ // @runtime client
2
+ import { DEFAULT_LAYOUT_SLUG } from "../constants.js";
3
+ // t() returns the key itself when no translation exists.
4
+ function translateOrRaw(t, key, raw) {
5
+ const translated = t(key);
6
+ return translated === key ? raw : translated;
7
+ }
8
+ export function usageParts(t, usage) {
9
+ return {
10
+ feature: translateOrRaw(t, `${usage.feature}:feature.label`, usage.feature),
11
+ notification: translateOrRaw(t, `${usage.feature}:notify.${usage.notification}.label`, usage.notification),
12
+ };
13
+ }
14
+ export function usageLabel(t, usage) {
15
+ const { feature, notification } = usageParts(t, usage);
16
+ return usage.feature === "" ? notification : `${feature} · ${notification}`;
17
+ }
18
+ export function usedByLabel(t, row) {
19
+ const emptyMark = "–";
20
+ if (row.kind === "mail-layout" || row.kind === "pdf-layout") {
21
+ if (row.slug === DEFAULT_LAYOUT_SLUG) {
22
+ return t(row.kind === "mail-layout"
23
+ ? "documentDesigner.usedBy.allMails"
24
+ : "documentDesigner.usedBy.allPdfs");
25
+ }
26
+ return row.usedByCount === 0
27
+ ? emptyMark
28
+ : t("documentDesigner.usedBy.templates", { count: row.usedByCount });
29
+ }
30
+ const first = row.usedBy[0];
31
+ return first === undefined ? emptyMark : usageLabel(t, first);
32
+ }
package/package.json CHANGED
@@ -1,6 +1,65 @@
1
1
  {
2
2
  "name": "@cosmicdrift/kumiko-document-designer",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.364.0",
4
+ "description": "Document designer for Kumiko: template overview, layout editor (mail layout, PDF letterhead) and the PDF template editor.",
5
+ "license": "BUSL-1.1",
6
+ "author": "Marc Frost <marc@cosmicdriftgamestudio.com>",
7
+ "type": "module",
8
+ "kumiko": {
9
+ "runtime": "runtime"
10
+ },
11
+ "exports": {
12
+ ".": {
13
+ "types": "./dist/index.d.ts",
14
+ "default": "./dist/index.js"
15
+ },
16
+ "./web": {
17
+ "types": "./dist/web/index.d.ts",
18
+ "default": "./dist/web/index.js"
19
+ }
20
+ },
21
+ "dependencies": {
22
+ "@cosmicdrift/kumiko-bundled-features": "0.364.0",
23
+ "@cosmicdrift/kumiko-framework": "0.364.0",
24
+ "@cosmicdrift/kumiko-headless": "0.364.0",
25
+ "@cosmicdrift/kumiko-renderer": "0.364.0",
26
+ "@cosmicdrift/kumiko-renderer-puppeteer-client": "0.364.0",
27
+ "@cosmicdrift/kumiko-renderer-web": "0.364.0",
28
+ "@cosmicdrift/kumiko-types": "0.364.0",
29
+ "pdfjs-dist": "6.3.289",
30
+ "react": "^19.2.6"
31
+ },
32
+ "devDependencies": {
33
+ "@testing-library/react": "^16.3.2",
34
+ "@types/react": "^19.2.14"
35
+ },
36
+ "repository": {
37
+ "type": "git",
38
+ "url": "git+https://github.com/CosmicDriftGameStudio/kumiko-framework.git",
39
+ "directory": "packages/document-designer"
40
+ },
41
+ "homepage": "https://kumiko.rocks",
42
+ "bugs": {
43
+ "url": "https://github.com/CosmicDriftGameStudio/kumiko-framework/issues"
44
+ },
45
+ "publishConfig": {
46
+ "registry": "https://registry.npmjs.org",
47
+ "access": "public",
48
+ "exports": {
49
+ ".": {
50
+ "types": "./dist/index.d.ts",
51
+ "default": "./dist/index.js"
52
+ },
53
+ "./web": {
54
+ "types": "./dist/web/index.d.ts",
55
+ "default": "./dist/web/index.js"
56
+ }
57
+ }
58
+ },
59
+ "files": [
60
+ "dist",
61
+ "src/changes.json",
62
+ "README.md",
63
+ "LICENSE"
64
+ ]
65
+ }
@@ -0,0 +1,44 @@
1
+ [
2
+ {
3
+ "version": "0.364.0",
4
+ "type": "improvement",
5
+ "title": "Editors and overview show an open draft beside the active version",
6
+ "detail": "The editor header shows the served version (Active vN) next to the open draft (Draft vM), fed by the active field of find-by-id and layout-source; the template overview shows the draftVersion badge under the status of an active row."
7
+ },
8
+ {
9
+ "version": "0.364.0",
10
+ "type": "improvement",
11
+ "title": "Document designer editors follow the approved board",
12
+ "detail": "Mail-layout templates accept appearance meta (width, font, outer background, accent line, button style) that the mail renderer applies, and the layout-source query returns it. The layout editor uses the shared editor shell with one paper and one shared toolbar (`DocumentContentEditor` gains `toolbarHost`). Mail and PDF editors share frame, info bar, rails and footer.\nThe unused `sender` key of mail template meta is gone from the editor; stored rows that still carry it are read without it, so they stay editable.\nInvalid template meta now reports per-field messages (`templateResolver.errors.template.meta.<field>.required|invalid`) instead of the parser text; the editors show them at the field. The `tenant-overrides` query additionally returns one row per customising tenant (name, status, version, changed at/by) and, with `diffTenantId`, the diff to the system version. A language without a version shows an empty state in the mail editor instead of a disabled editor.\nThe `compileDocumentBody` option `resourceImageMaxWidthPx` caps resource images in mails (180 px). The `send-test` command takes `prefixSubject` (default true) to skip the `[TEST]` subject prefix, the template preview returns `mailLayout` (slug, scope, version of the layout used), and `RenderedMail` carries the layout ref."
13
+ },
14
+ {
15
+ "version": "0.364.0",
16
+ "type": "fix",
17
+ "title": "PDF editor keeps unset margins unset, frees old PDF previews, and shows reset and diff errors",
18
+ "detail": "Setting one margin no longer stores the other three as 15 mm, so the layout's header and footer margins still apply to them. The PDF preview no longer re-renders pages or stacks text layers on re-render and destroys the previous document. A failed reset to the system version shows an error banner in the PDF and mail editors, and a failing diff query shows an error state with retry instead of loading forever. The canvas reserves the footer margin like the renderer. Page formats, orientations and default margins now come from template-resolver (new exports PDF_ORIENTATIONS, PDF_DEFAULT_MARGIN_MM, PDF_HEADER_MARGIN_MM, PDF_FOOTER_MARGIN_MM, PdfOrientation)."
19
+ },
20
+ {
21
+ "version": "0.364.0",
22
+ "type": "fix",
23
+ "title": "Layout editor shows the real number of mails or PDFs using a layout",
24
+ "detail": "The editor asks the overview for the users of one layout (kind and layoutSlug filter) and takes the count from total, so a tenant with more than 200 templates no longer sees a too low usage number."
25
+ },
26
+ {
27
+ "version": "0.363.0",
28
+ "type": "improvement",
29
+ "title": "Mail templates open in a mail editor with preview and test mail",
30
+ "detail": "The \"Edit\" row action of a mail template opens the new mail-editor screen: subject, preview text and content with placeholders from the notification, logo and file attachments, PDF-template attachments, layout and category, sandboxed preview (HTML or text, desktop or 375 px), test mail to the signed-in user and the audit-based version list. PreviewRecordPickerProvider is an optional slot for a \"pick a record\" action in the preview."
31
+ },
32
+ {
33
+ "version": "0.363.0",
34
+ "type": "improvement",
35
+ "title": "Template overview, layout editor and an options object for documentDesignerClient",
36
+ "detail": "The package gains the server feature createDocumentDesignerFeature with the templates and platform-templates overviews and the layout-editor screen. documentDesignerClient now takes an options object instead of a screen id, and appLocales sets the languages column of the overview. The feature declares the pdf-template-editor screen (PDF_TEMPLATE_EDITOR_SCREEN_ID) and PDF rows open the PDF editor."
37
+ },
38
+ {
39
+ "version": "0.363.0",
40
+ "type": "improvement",
41
+ "title": "New package with the PDF template editor screen",
42
+ "detail": "\"@cosmicdrift/kumiko-document-designer/web\" exports documentDesignerClient(screenId), PdfTemplateEditorScreen, PdfTemplateEditor and documentDesignerTranslations. The screen takes the template from the URL (?slug=...&locale=...), edits the system template for a SystemAdmin and a tenant customisation for everyone else, and previews the printed PDF with pdf.js. template-resolver/web additionally exports DocumentEditorHandle, TemplateResolverQueries, TemplateResolverHandlers and TemplateResolverErrors."
43
+ }
44
+ ]