@drawnagency/primitives 0.1.82 → 0.1.84

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 (32) hide show
  1. package/dist/{chunk-5UDIQLGQ.js → chunk-56J4QMF4.js} +2 -2
  2. package/dist/{chunk-22GU6GNP.js → chunk-665DW3HR.js} +1 -1
  3. package/dist/{chunk-6NRVX6NQ.js → chunk-DO3ZENLN.js} +1 -1
  4. package/dist/{chunk-ETJYYUQX.js → chunk-E3MTIMOG.js} +1 -1
  5. package/dist/{chunk-Y54G2XSC.js → chunk-EP3LVOXZ.js} +1 -1
  6. package/dist/components/editor/index.js +1 -1
  7. package/dist/components/primitives/index.js +1 -1
  8. package/dist/components/sections/brand-guide.js +2 -2
  9. package/dist/components/sections/register-schemas.js +3 -3
  10. package/dist/components/sections/register.js +3 -3
  11. package/dist/components/shell/EditorShell.d.ts.map +1 -1
  12. package/dist/document/assets/fonts/albra-grotesk-bold.woff +0 -0
  13. package/dist/document/assets/fonts/albra-grotesk-regular.woff +0 -0
  14. package/dist/document/assets/fonts/kapra-neue-expanded-medium.woff +0 -0
  15. package/dist/document/assets/fonts/kapra-neue-expanded-regular.woff +0 -0
  16. package/dist/document/components/DocViewer.d.ts +4 -1
  17. package/dist/document/components/DocViewer.d.ts.map +1 -1
  18. package/dist/document/index.js +29 -15
  19. package/dist/index.js +3 -3
  20. package/dist/lib/index.js +2 -2
  21. package/dist/media/index.js +1 -1
  22. package/dist/schemas/index.js +2 -2
  23. package/dist/schemas/site-config.d.ts +1 -1
  24. package/dist/schemas/site-config.d.ts.map +1 -1
  25. package/package.json +1 -1
  26. package/src/components/shell/EditorShell.tsx +3 -2
  27. package/src/document/assets/fonts/albra-grotesk-bold.woff +0 -0
  28. package/src/document/assets/fonts/albra-grotesk-regular.woff +0 -0
  29. package/src/document/assets/fonts/kapra-neue-expanded-medium.woff +0 -0
  30. package/src/document/assets/fonts/kapra-neue-expanded-regular.woff +0 -0
  31. package/src/document/components/DocViewer.tsx +39 -15
  32. package/src/schemas/site-config.ts +1 -1
@@ -3,7 +3,7 @@ import {
3
3
  pluralize,
4
4
  stripHtmlToPlainText,
5
5
  truncate
6
- } from "./chunk-22GU6GNP.js";
6
+ } from "./chunk-665DW3HR.js";
7
7
  import {
8
8
  DeleteButton,
9
9
  DragHandle,
@@ -51,7 +51,7 @@ import {
51
51
  } from "./chunk-TZQPOR5A.js";
52
52
  import {
53
53
  SingleMediaReferenceSchema
54
- } from "./chunk-ETJYYUQX.js";
54
+ } from "./chunk-E3MTIMOG.js";
55
55
  import {
56
56
  defineSection,
57
57
  getSection
@@ -30,7 +30,7 @@ import {
30
30
  import {
31
31
  HexColorSchema,
32
32
  SingleMediaReferenceSchema
33
- } from "./chunk-ETJYYUQX.js";
33
+ } from "./chunk-E3MTIMOG.js";
34
34
  import {
35
35
  defineSection
36
36
  } from "./chunk-VKAGMEKE.js";
@@ -9,7 +9,7 @@ import {
9
9
  } from "./chunk-TZQPOR5A.js";
10
10
  import {
11
11
  IndexSchema
12
- } from "./chunk-ETJYYUQX.js";
12
+ } from "./chunk-E3MTIMOG.js";
13
13
  import {
14
14
  getAllSchemas
15
15
  } from "./chunk-VKAGMEKE.js";
@@ -130,7 +130,7 @@ var SectionMetaSchema = z3.object({
130
130
  status: StatusSchema,
131
131
  access: z3.array(z3.string())
132
132
  });
133
- var RESERVED_SLUGS = ["edit", "api", "login", "set-password", "404", "present"];
133
+ var RESERVED_SLUGS = ["edit", "api", "login", "set-password", "404", "present", "print"];
134
134
  var PARSE_REJECTED_SLUGS = ["edit", "api", "login", "set-password", "404"];
135
135
  var PageStatusSchema = z3.enum(["live", "archived"]);
136
136
  var PageSchema = z3.object({
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  HexColorSchema
3
- } from "./chunk-ETJYYUQX.js";
3
+ } from "./chunk-E3MTIMOG.js";
4
4
 
5
5
  // src/schemas/audience.ts
6
6
  import { z } from "zod";
@@ -24,7 +24,7 @@ import {
24
24
  cn
25
25
  } from "../../chunk-7EOSDFS3.js";
26
26
  import "../../chunk-YBVK254P.js";
27
- import "../../chunk-ETJYYUQX.js";
27
+ import "../../chunk-E3MTIMOG.js";
28
28
  import "../../chunk-FM4M4Q2W.js";
29
29
  import "../../chunk-JSBRDJBE.js";
30
30
 
@@ -23,7 +23,7 @@ import {
23
23
  cn
24
24
  } from "../../chunk-7EOSDFS3.js";
25
25
  import "../../chunk-YBVK254P.js";
26
- import "../../chunk-ETJYYUQX.js";
26
+ import "../../chunk-E3MTIMOG.js";
27
27
  import "../../chunk-VKAGMEKE.js";
28
28
  import "../../chunk-FM4M4Q2W.js";
29
29
  import "../../chunk-JSBRDJBE.js";
@@ -2,7 +2,7 @@ import {
2
2
  ColorItemSchema,
3
3
  ColorSpaceSchema,
4
4
  brandGuideSectionDefs
5
- } from "../../chunk-22GU6GNP.js";
5
+ } from "../../chunk-665DW3HR.js";
6
6
  import "../../chunk-5THS4K5D.js";
7
7
  import "../../chunk-DKXISNJ2.js";
8
8
  import "../../chunk-MBJUWOM2.js";
@@ -11,7 +11,7 @@ import "../../chunk-PZJL2S3Z.js";
11
11
  import "../../chunk-WDSVHKAH.js";
12
12
  import "../../chunk-7EOSDFS3.js";
13
13
  import "../../chunk-YBVK254P.js";
14
- import "../../chunk-ETJYYUQX.js";
14
+ import "../../chunk-E3MTIMOG.js";
15
15
  import "../../chunk-VKAGMEKE.js";
16
16
  import "../../chunk-FM4M4Q2W.js";
17
17
  import "../../chunk-JSBRDJBE.js";
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  allSectionDefs
3
- } from "../../chunk-5UDIQLGQ.js";
4
- import "../../chunk-22GU6GNP.js";
3
+ } from "../../chunk-56J4QMF4.js";
4
+ import "../../chunk-665DW3HR.js";
5
5
  import "../../chunk-Q6LZOH5M.js";
6
6
  import "../../chunk-5THS4K5D.js";
7
7
  import "../../chunk-FDBZZ4AT.js";
@@ -16,7 +16,7 @@ import "../../chunk-53DKVAB6.js";
16
16
  import "../../chunk-7EOSDFS3.js";
17
17
  import "../../chunk-YBVK254P.js";
18
18
  import "../../chunk-TZQPOR5A.js";
19
- import "../../chunk-ETJYYUQX.js";
19
+ import "../../chunk-E3MTIMOG.js";
20
20
  import {
21
21
  registerRichText,
22
22
  registerSchema
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  allSectionDefs
3
- } from "../../chunk-5UDIQLGQ.js";
4
- import "../../chunk-22GU6GNP.js";
3
+ } from "../../chunk-56J4QMF4.js";
4
+ import "../../chunk-665DW3HR.js";
5
5
  import "../../chunk-Q6LZOH5M.js";
6
6
  import "../../chunk-5THS4K5D.js";
7
7
  import "../../chunk-FDBZZ4AT.js";
@@ -16,7 +16,7 @@ import "../../chunk-53DKVAB6.js";
16
16
  import "../../chunk-7EOSDFS3.js";
17
17
  import "../../chunk-YBVK254P.js";
18
18
  import "../../chunk-TZQPOR5A.js";
19
- import "../../chunk-ETJYYUQX.js";
19
+ import "../../chunk-E3MTIMOG.js";
20
20
  import {
21
21
  registerSection
22
22
  } from "../../chunk-VKAGMEKE.js";
@@ -1 +1 @@
1
- {"version":3,"file":"EditorShell.d.ts","sourceRoot":"","sources":["../../../src/components/shell/EditorShell.tsx"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AASjD,OAAO,EAAoC,KAAK,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAwDtF,OAAO,KAAK,EAAE,eAAe,EAA2D,MAAM,oBAAoB,CAAC;AAmCnH,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAoBxD,UAAU,KAAK;IACb,OAAO,EAAE,MAAM,CAAC;IAIhB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,QAAQ,EAAE,CAAC;IACtB,YAAY,EAAE;QACZ,KAAK,EAAE,OAAO,CAAC;QACf,aAAa,EAAE,OAAO,CAAC;QACvB,YAAY,EAAE,OAAO,CAAC;QACtB,cAAc,EAAE,OAAO,CAAC;QACxB,kBAAkB,EAAE,OAAO,CAAC;QAC5B,cAAc,EAAE,OAAO,CAAC;KACzB,CAAC;IACF,WAAW,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,OAAO,GAAG,QAAQ,CAAA;KAAE,GAAG,IAAI,CAAC;IAIhE,sBAAsB,CAAC,EAAE,OAAO,CAAC;IAKjC,eAAe,CAAC,EAAE,eAAe,GAAG,IAAI,CAAC;CAC1C;AAED,MAAM,CAAC,OAAO,UAAU,WAAW,CAAC,EAClC,OAAO,EACP,YAAY,EACZ,MAAM,EACN,SAAS,EAAE,gBAAgB,EAC3B,YAAY,EACZ,WAAW,EACX,sBAA8B,EAC9B,eAAe,GAChB,EAAE,KAAK,2CAqiDP;AAuED;6EAC6E;AAC7E,wBAAgB,kBAAkB,CAChC,YAAY,EAAE,WAAW,CAAC,YAAY,CAAC,EACvC,aAAa,EAAE,MAAM,GAAG,IAAI,EAC5B,eAAe,EAAE,MAAM,GAAG,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAK/B"}
1
+ {"version":3,"file":"EditorShell.d.ts","sourceRoot":"","sources":["../../../src/components/shell/EditorShell.tsx"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AASjD,OAAO,EAAoC,KAAK,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAwDtF,OAAO,KAAK,EAAE,eAAe,EAA2D,MAAM,oBAAoB,CAAC;AAmCnH,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAoBxD,UAAU,KAAK;IACb,OAAO,EAAE,MAAM,CAAC;IAIhB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,QAAQ,EAAE,CAAC;IACtB,YAAY,EAAE;QACZ,KAAK,EAAE,OAAO,CAAC;QACf,aAAa,EAAE,OAAO,CAAC;QACvB,YAAY,EAAE,OAAO,CAAC;QACtB,cAAc,EAAE,OAAO,CAAC;QACxB,kBAAkB,EAAE,OAAO,CAAC;QAC5B,cAAc,EAAE,OAAO,CAAC;KACzB,CAAC;IACF,WAAW,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,OAAO,GAAG,QAAQ,CAAA;KAAE,GAAG,IAAI,CAAC;IAIhE,sBAAsB,CAAC,EAAE,OAAO,CAAC;IAKjC,eAAe,CAAC,EAAE,eAAe,GAAG,IAAI,CAAC;CAC1C;AAED,MAAM,CAAC,OAAO,UAAU,WAAW,CAAC,EAClC,OAAO,EACP,YAAY,EACZ,MAAM,EACN,SAAS,EAAE,gBAAgB,EAC3B,YAAY,EACZ,WAAW,EACX,sBAA8B,EAC9B,eAAe,GAChB,EAAE,KAAK,2CAsiDP;AAuED;6EAC6E;AAC7E,wBAAgB,kBAAkB,CAChC,YAAY,EAAE,WAAW,CAAC,YAAY,CAAC,EACvC,aAAa,EAAE,MAAM,GAAG,IAAI,EAC5B,eAAe,EAAE,MAAM,GAAG,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAK/B"}
@@ -9,10 +9,13 @@ export interface DocViewerProps {
9
9
  selectedChunkId?: string | null;
10
10
  onSelectChunk?: (chunkId: string | null) => void;
11
11
  onClose?: () => void;
12
+ /** Present mode only: when set, the toolbar shows a "Download PDF" link (the /present
13
+ * route passes the gated /api/document-pdf href when a PDF exists for this viewer). */
14
+ downloadHref?: string | null;
12
15
  onDocState?: (state: {
13
16
  chunks: Chunk[];
14
17
  warningsByChunk: Record<string, string[]>;
15
18
  }) => void;
16
19
  }
17
- export declare function DocViewer({ source, document: doc, host, mode, selectedChunkId, onSelectChunk, onClose, onDocState, }: DocViewerProps): import("react/jsx-runtime").JSX.Element;
20
+ export declare function DocViewer({ source, document: doc, host, mode, selectedChunkId, onSelectChunk, onClose, downloadHref, onDocState, }: DocViewerProps): import("react/jsx-runtime").JSX.Element;
18
21
  //# sourceMappingURL=DocViewer.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"DocViewer.d.ts","sourceRoot":"","sources":["../../../src/document/components/DocViewer.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAE1D,OAAO,KAAK,EAAE,KAAK,EAAY,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAGzE,OAAO,EAAkB,KAAK,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAOhE,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,gBAAgB,GAAG,IAAI,CAAC;IAChC,QAAQ,EAAE,eAAe,CAAC;IAC1B,IAAI,EAAE,OAAO,CAAC;IACd,IAAI,EAAE,SAAS,GAAG,MAAM,CAAC;IAEzB,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,aAAa,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IACjD,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IAKrB,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE;QAAE,MAAM,EAAE,KAAK,EAAE,CAAC;QAAC,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAA;KAAE,KAAK,IAAI,CAAC;CAC9F;AAUD,wBAAgB,SAAS,CAAC,EACxB,MAAM,EACN,QAAQ,EAAE,GAAG,EACb,IAAI,EACJ,IAAI,EACJ,eAAe,EACf,aAAa,EACb,OAAO,EACP,UAAU,GACX,EAAE,cAAc,2CA8JhB"}
1
+ {"version":3,"file":"DocViewer.d.ts","sourceRoot":"","sources":["../../../src/document/components/DocViewer.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAE1D,OAAO,KAAK,EAAE,KAAK,EAAY,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAGzE,OAAO,EAAkB,KAAK,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAOhE,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,gBAAgB,GAAG,IAAI,CAAC;IAChC,QAAQ,EAAE,eAAe,CAAC;IAC1B,IAAI,EAAE,OAAO,CAAC;IACd,IAAI,EAAE,SAAS,GAAG,MAAM,CAAC;IAEzB,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,aAAa,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IACjD,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB;2FACuF;IACvF,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAK7B,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE;QAAE,MAAM,EAAE,KAAK,EAAE,CAAC;QAAC,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAA;KAAE,KAAK,IAAI,CAAC;CAC9F;AAUD,wBAAgB,SAAS,CAAC,EACxB,MAAM,EACN,QAAQ,EAAE,GAAG,EACb,IAAI,EACJ,IAAI,EACJ,eAAe,EACf,aAAa,EACb,OAAO,EACP,YAAY,EACZ,UAAU,GACX,EAAE,cAAc,2CA0KhB"}
@@ -764,6 +764,7 @@ function DocViewer({
764
764
  selectedChunkId,
765
765
  onSelectChunk,
766
766
  onClose,
767
+ downloadHref,
767
768
  onDocState
768
769
  }) {
769
770
  const { chunks, pages, measuring, warningsByChunk } = useDocPages({ source, sections: doc.sections });
@@ -847,16 +848,28 @@ function DocViewer({
847
848
  /* @__PURE__ */ jsxs6("div", { className: "flex h-full min-h-0 min-w-0 flex-1 flex-col", children: [
848
849
  mode === "present" ? /* @__PURE__ */ jsxs6("div", { className: "flex items-center justify-between border-b border-base-200 bg-base px-4 py-2", children: [
849
850
  /* @__PURE__ */ jsx6("span", { className: "text-sm font-medium text-base-contrast", children: source?.pageTitle ?? "Document" }),
850
- onClose ? /* @__PURE__ */ jsx6(
851
- "button",
852
- {
853
- type: "button",
854
- "aria-label": "Close",
855
- onClick: onClose,
856
- className: "rounded border border-base-200 px-3 py-1 text-xs font-medium text-base-contrast hover:bg-base-accent/30",
857
- children: "\u2715"
858
- }
859
- ) : null
851
+ /* @__PURE__ */ jsxs6("div", { className: "flex items-center gap-2", children: [
852
+ downloadHref ? /* @__PURE__ */ jsx6(
853
+ "a",
854
+ {
855
+ href: downloadHref,
856
+ download: true,
857
+ "aria-label": "Download PDF",
858
+ className: "rounded border border-base-200 px-3 py-1 text-xs font-medium text-base-contrast hover:bg-base-accent/30",
859
+ children: "Download PDF"
860
+ }
861
+ ) : null,
862
+ onClose ? /* @__PURE__ */ jsx6(
863
+ "button",
864
+ {
865
+ type: "button",
866
+ "aria-label": "Close",
867
+ onClick: onClose,
868
+ className: "rounded border border-base-200 px-3 py-1 text-xs font-medium text-base-contrast hover:bg-base-accent/30",
869
+ children: "\u2715"
870
+ }
871
+ ) : null
872
+ ] })
860
873
  ] }) : null,
861
874
  /* @__PURE__ */ jsxs6("div", { className: "flex min-h-0 min-w-0 flex-1", children: [
862
875
  railOpen ? /* @__PURE__ */ jsx6(
@@ -912,13 +925,14 @@ function DocCanvas({
912
925
  const el = containerRef.current;
913
926
  if (!el || typeof ResizeObserver === "undefined") return;
914
927
  const observer = new ResizeObserver(() => {
915
- const available = el.clientWidth - 48;
916
- setScale(Math.min(0.75, Math.max(0.15, available / PAGE_W2)));
928
+ const availW = el.clientWidth - 48;
929
+ const availH = el.clientHeight - 48;
930
+ setScale(Math.max(0.15, Math.min(availW / PAGE_W2, availH / PAGE_H2)));
917
931
  });
918
932
  observer.observe(el);
919
933
  return () => observer.disconnect();
920
934
  }, []);
921
- const note = (text) => /* @__PURE__ */ jsx6("p", { className: "mt-24 text-sm text-neutral-400", children: text });
935
+ const note = (text) => /* @__PURE__ */ jsx6("p", { className: "text-sm text-neutral-400", children: text });
922
936
  let body;
923
937
  if (active?.kind === "cover") {
924
938
  body = noContent ? /* @__PURE__ */ jsxs6("div", { className: "flex flex-col items-center gap-4", children: [
@@ -937,8 +951,8 @@ function DocCanvas({
937
951
  {
938
952
  ref: containerRef,
939
953
  "data-testid": "doc-canvas",
940
- className: "flex flex-1 items-start justify-center overflow-auto bg-neutral-100 p-6",
941
- children: body
954
+ className: "flex min-h-0 min-w-0 flex-1 overflow-auto bg-neutral-100 p-6",
955
+ children: /* @__PURE__ */ jsx6("div", { className: "m-auto", children: body })
942
956
  }
943
957
  );
944
958
  }
package/dist/index.js CHANGED
@@ -49,7 +49,7 @@ import {
49
49
  AudienceNameSchema,
50
50
  MediaGridOptionsSchema,
51
51
  slugifyAudienceName
52
- } from "./chunk-Y54G2XSC.js";
52
+ } from "./chunk-EP3LVOXZ.js";
53
53
  import {
54
54
  AudienceSchema,
55
55
  RoleSchema,
@@ -71,7 +71,7 @@ import {
71
71
  loadStaticSiteContent,
72
72
  mergeSiteContent,
73
73
  safeRedirect
74
- } from "./chunk-6NRVX6NQ.js";
74
+ } from "./chunk-DO3ZENLN.js";
75
75
  import {
76
76
  curatedIcons,
77
77
  getIcon
@@ -124,7 +124,7 @@ import {
124
124
  TextLineSchema,
125
125
  VariantSchema,
126
126
  normalizeSiteIndex
127
- } from "./chunk-ETJYYUQX.js";
127
+ } from "./chunk-E3MTIMOG.js";
128
128
  import {
129
129
  clearRegistry,
130
130
  createRegistry,
package/dist/lib/index.js CHANGED
@@ -7,7 +7,7 @@ import {
7
7
  loadStaticSiteContent,
8
8
  mergeSiteContent,
9
9
  safeRedirect
10
- } from "../chunk-6NRVX6NQ.js";
10
+ } from "../chunk-DO3ZENLN.js";
11
11
  import {
12
12
  curatedIcons,
13
13
  getIcon
@@ -33,7 +33,7 @@ import {
33
33
  } from "../chunk-YBVK254P.js";
34
34
  import "../chunk-75P6HWPN.js";
35
35
  import "../chunk-TZQPOR5A.js";
36
- import "../chunk-ETJYYUQX.js";
36
+ import "../chunk-E3MTIMOG.js";
37
37
  import {
38
38
  clearRegistry,
39
39
  createRegistry,
@@ -24,7 +24,7 @@ import {
24
24
  MediaFolderSchema,
25
25
  MediaItemSchema,
26
26
  VariantSchema
27
- } from "../chunk-ETJYYUQX.js";
27
+ } from "../chunk-E3MTIMOG.js";
28
28
  import "../chunk-FM4M4Q2W.js";
29
29
  import "../chunk-JSBRDJBE.js";
30
30
  export {
@@ -3,7 +3,7 @@ import {
3
3
  AudienceNameSchema,
4
4
  MediaGridOptionsSchema,
5
5
  slugifyAudienceName
6
- } from "../chunk-Y54G2XSC.js";
6
+ } from "../chunk-EP3LVOXZ.js";
7
7
  import {
8
8
  AudienceSchema,
9
9
  RoleSchema,
@@ -40,7 +40,7 @@ import {
40
40
  TextLineSchema,
41
41
  VariantSchema,
42
42
  normalizeSiteIndex
43
- } from "../chunk-ETJYYUQX.js";
43
+ } from "../chunk-E3MTIMOG.js";
44
44
  import "../chunk-VKAGMEKE.js";
45
45
  import "../chunk-FM4M4Q2W.js";
46
46
  import "../chunk-NSCT3AMV.js";
@@ -10,7 +10,7 @@ export declare const SectionMetaSchema: z.ZodObject<{
10
10
  access: z.ZodArray<z.ZodString>;
11
11
  }, z.core.$strip>;
12
12
  export type SectionMeta = z.infer<typeof SectionMetaSchema>;
13
- export declare const RESERVED_SLUGS: readonly ["edit", "api", "login", "set-password", "404", "present"];
13
+ export declare const RESERVED_SLUGS: readonly ["edit", "api", "login", "set-password", "404", "present", "print"];
14
14
  export declare const PageStatusSchema: z.ZodEnum<{
15
15
  live: "live";
16
16
  archived: "archived";
@@ -1 +1 @@
1
- {"version":3,"file":"site-config.d.ts","sourceRoot":"","sources":["../../src/schemas/site-config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAaxB,eAAO,MAAM,iBAAiB;;;;;;;;;iBAI5B,CAAC;AAEH,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAQ5D,eAAO,MAAM,cAAc,qEAAsE,CAAC;AAWlG,eAAO,MAAM,gBAAgB;;;EAA+B,CAAC;AAE7D,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAUrB,CAAC;AAEH,MAAM,MAAM,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,CAAC;AA0C9C,QAAA,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA6CtB,CAAC;AAEL,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAAyE,CAAC;AAElG,MAAM,MAAM,SAAS,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAE7D,oFAAoF;AACpF,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,OAAO,GAAG,SAAS,CAE1D;AAMD,eAAO,MAAM,iBAAiB;;;;;iBAM5B,CAAC;AACH,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAE5D,eAAO,MAAM,mBAAmB;;;;;;;;;;;iBAwB5B,CAAC;AACL,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAEhE,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA4B3B,CAAC;AAEH,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC"}
1
+ {"version":3,"file":"site-config.d.ts","sourceRoot":"","sources":["../../src/schemas/site-config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAaxB,eAAO,MAAM,iBAAiB;;;;;;;;;iBAI5B,CAAC;AAEH,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAQ5D,eAAO,MAAM,cAAc,8EAA+E,CAAC;AAW3G,eAAO,MAAM,gBAAgB;;;EAA+B,CAAC;AAE7D,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAUrB,CAAC;AAEH,MAAM,MAAM,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,CAAC;AA0C9C,QAAA,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA6CtB,CAAC;AAEL,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAAyE,CAAC;AAElG,MAAM,MAAM,SAAS,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAE7D,oFAAoF;AACpF,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,OAAO,GAAG,SAAS,CAE1D;AAMD,eAAO,MAAM,iBAAiB;;;;;iBAM5B,CAAC;AACH,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAE5D,eAAO,MAAM,mBAAmB;;;;;;;;;;;iBAwB5B,CAAC;AACL,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAEhE,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA4B3B,CAAC;AAEH,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@drawnagency/primitives",
3
- "version": "0.1.82",
3
+ "version": "0.1.84",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  "./package.json": "./package.json",
@@ -1473,8 +1473,9 @@ export default function EditorShell({
1473
1473
  className="cursor-pointer fixed bottom-40 right-4 lg:right-auto z-50 flex h-10 w-10 items-center justify-center rounded-full bg-primary text-primary-contrast shadow-lg hover:opacity-90 transition-opacity fab-container-right"
1474
1474
  >
1475
1475
  <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" aria-hidden="true">
1476
- <rect x="3" y="4" width="18" height="14" rx="2" />
1477
- <path d="M8 21h8" />
1476
+ <rect x="3" y="5" width="18" height="14" rx="1" />
1477
+ <path d="M7 10h10" />
1478
+ <path d="M7 14h7" />
1478
1479
  </svg>
1479
1480
  </button>
1480
1481
  )}
@@ -20,6 +20,9 @@ export interface DocViewerProps {
20
20
  selectedChunkId?: string | null;
21
21
  onSelectChunk?: (chunkId: string | null) => void; // null = cover selected
22
22
  onClose?: () => void; // present mode: close control
23
+ /** Present mode only: when set, the toolbar shows a "Download PDF" link (the /present
24
+ * route passes the gated /api/document-pdf href when a PDF exists for this viewer). */
25
+ downloadHref?: string | null;
23
26
  // Optional pagination-state hook (present mode unaffected — the present route
24
27
  // never passes it). Fires, identity-guarded, whenever the internal useDocPages
25
28
  // output changes, so a host (the edit overlay) can reuse this single pass for
@@ -43,6 +46,7 @@ export function DocViewer({
43
46
  selectedChunkId,
44
47
  onSelectChunk,
45
48
  onClose,
49
+ downloadHref,
46
50
  onDocState,
47
51
  }: DocViewerProps) {
48
52
  const { chunks, pages, measuring, warningsByChunk } = useDocPages({ source, sections: doc.sections });
@@ -154,16 +158,28 @@ export function DocViewer({
154
158
  {mode === "present" ? (
155
159
  <div className="flex items-center justify-between border-b border-base-200 bg-base px-4 py-2">
156
160
  <span className="text-sm font-medium text-base-contrast">{source?.pageTitle ?? "Document"}</span>
157
- {onClose ? (
158
- <button
159
- type="button"
160
- aria-label="Close"
161
- onClick={onClose}
162
- className="rounded border border-base-200 px-3 py-1 text-xs font-medium text-base-contrast hover:bg-base-accent/30"
163
- >
164
- ✕
165
- </button>
166
- ) : null}
161
+ <div className="flex items-center gap-2">
162
+ {downloadHref ? (
163
+ <a
164
+ href={downloadHref}
165
+ download
166
+ aria-label="Download PDF"
167
+ className="rounded border border-base-200 px-3 py-1 text-xs font-medium text-base-contrast hover:bg-base-accent/30"
168
+ >
169
+ Download PDF
170
+ </a>
171
+ ) : null}
172
+ {onClose ? (
173
+ <button
174
+ type="button"
175
+ aria-label="Close"
176
+ onClick={onClose}
177
+ className="rounded border border-base-200 px-3 py-1 text-xs font-medium text-base-contrast hover:bg-base-accent/30"
178
+ >
179
+ ✕
180
+ </button>
181
+ ) : null}
182
+ </div>
167
183
  </div>
168
184
  ) : null}
169
185
  <div className="flex min-h-0 min-w-0 flex-1">
@@ -227,14 +243,19 @@ function DocCanvas({
227
243
  const el = containerRef.current;
228
244
  if (!el || typeof ResizeObserver === "undefined") return;
229
245
  const observer = new ResizeObserver(() => {
230
- const available = el.clientWidth - 48;
231
- setScale(Math.min(0.75, Math.max(0.15, available / PAGE_W)));
246
+ // Fill the canvas: fit both dimensions (clientWidth/Height include the
247
+ // p-6 padding — subtract it) and take the limiting axis. The page keeps
248
+ // its true 1632×1056 layout and is transform-scaled, so what's shown is
249
+ // byte-identical to the print layout at any size.
250
+ const availW = el.clientWidth - 48;
251
+ const availH = el.clientHeight - 48;
252
+ setScale(Math.max(0.15, Math.min(availW / PAGE_W, availH / PAGE_H)));
232
253
  });
233
254
  observer.observe(el);
234
255
  return () => observer.disconnect();
235
256
  }, []);
236
257
 
237
- const note = (text: string) => <p className="mt-24 text-sm text-neutral-400">{text}</p>;
258
+ const note = (text: string) => <p className="text-sm text-neutral-400">{text}</p>;
238
259
 
239
260
  let body: ReactNode;
240
261
  if (active?.kind === "cover") {
@@ -267,9 +288,12 @@ function DocCanvas({
267
288
  <div
268
289
  ref={containerRef}
269
290
  data-testid="doc-canvas"
270
- className="flex flex-1 items-start justify-center overflow-auto bg-neutral-100 p-6"
291
+ className="flex min-h-0 min-w-0 flex-1 overflow-auto bg-neutral-100 p-6"
271
292
  >
272
- {body}
293
+ {/* m-auto instead of items/justify-center: centers both axes when the
294
+ page fits, but keeps the top/left edge reachable when it overflows
295
+ (flex centering clips overflow irretrievably; auto margins don't). */}
296
+ <div className="m-auto">{body}</div>
273
297
  </div>
274
298
  );
275
299
  }
@@ -25,7 +25,7 @@ export type SectionMeta = z.infer<typeof SectionMetaSchema>;
25
25
  // add its first segment here (the test in Step 1 guards the known set). This is
26
26
  // the single source of truth for reserved slugs; the schema, uniquePageSlug, and
27
27
  // /api/save all import it.
28
- export const RESERVED_SLUGS = ["edit", "api", "login", "set-password", "404", "present"] as const;
28
+ export const RESERVED_SLUGS = ["edit", "api", "login", "set-password", "404", "present", "print"] as const;
29
29
 
30
30
  // Subset of RESERVED_SLUGS the index schema hard-rejects at parse time. Only
31
31
  // slugs reserved since before client sites existed may hard-fail here: parse-