@segnavia/format 0.22.0 → 0.24.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.
@@ -125,9 +125,11 @@ export declare function deckFromSlides(rows: SlideRow[], options: DeckFromSlides
125
125
  slots?: {
126
126
  key: string;
127
127
  label: string;
128
- type: "text" | "phone" | "email" | "link" | "image";
128
+ type: "text" | "phone" | "email" | "link" | "qr" | "image";
129
129
  required: boolean;
130
+ overflow: "refuse" | "shrink" | "truncate" | "wrap";
130
131
  placeholder?: string | undefined;
132
+ minSize?: number | undefined;
131
133
  }[] | undefined;
132
134
  };
133
135
  //#endregion
package/dist/deck.d.ts CHANGED
@@ -438,7 +438,7 @@ export declare const Deck: z.ZodObject<{
438
438
  off: "off";
439
439
  viewer: "viewer";
440
440
  }>>;
441
- slots: z.ZodOptional<z.ZodArray<z.ZodObject<{
441
+ slots: z.ZodOptional<z.ZodArray<z.ZodPipe<z.ZodObject<{
442
442
  key: z.ZodString;
443
443
  label: z.ZodString;
444
444
  type: z.ZodEnum<{
@@ -446,11 +446,35 @@ export declare const Deck: z.ZodObject<{
446
446
  phone: "phone";
447
447
  email: "email";
448
448
  link: "link";
449
+ qr: "qr";
449
450
  image: "image";
450
451
  }>;
451
452
  required: z.ZodDefault<z.ZodBoolean>;
452
453
  placeholder: z.ZodOptional<z.ZodString>;
453
- }, z.core.$strip>>>;
454
+ overflow: z.ZodDefault<z.ZodEnum<{
455
+ refuse: "refuse";
456
+ shrink: "shrink";
457
+ truncate: "truncate";
458
+ wrap: "wrap";
459
+ }>>;
460
+ minSize: z.ZodOptional<z.ZodNumber>;
461
+ }, z.core.$strip>, z.ZodTransform<{
462
+ key: string;
463
+ label: string;
464
+ type: "text" | "phone" | "email" | "link" | "qr" | "image";
465
+ required: boolean;
466
+ overflow: "refuse" | "shrink" | "truncate" | "wrap";
467
+ placeholder?: string | undefined;
468
+ minSize?: number | undefined;
469
+ }, {
470
+ key: string;
471
+ label: string;
472
+ type: "text" | "phone" | "email" | "link" | "qr" | "image";
473
+ required: boolean;
474
+ overflow: "refuse" | "shrink" | "truncate" | "wrap";
475
+ placeholder?: string | undefined;
476
+ minSize?: number | undefined;
477
+ }>>>>;
454
478
  slides: z.ZodArray<z.ZodObject<{
455
479
  id: z.ZodString;
456
480
  content: z.ZodDiscriminatedUnion<[z.ZodObject<{
@@ -0,0 +1,18 @@
1
+ import { MarkSegment } from "./paper.js";
2
+ import { Imposition } from "./index.js";
3
+ //#region src/imposition-marks.d.ts
4
+ export declare const MIN_MARK_LENGTH_MM = 2;
5
+ export type ImpositionMarkEdge = 'top' | 'right' | 'bottom' | 'left';
6
+ export interface OmittedImpositionMark {
7
+ side: 'front' | 'back';
8
+ edge: ImpositionMarkEdge;
9
+ cutPosition: number;
10
+ }
11
+ export interface ImpositionSideMarks {
12
+ side: 'front' | 'back';
13
+ marks: MarkSegment[];
14
+ omittedMarks: OmittedImpositionMark[];
15
+ }
16
+ /** Computes physical crop-mark geometry without changing the fixed paper size. */
17
+ export declare function impositionMarks(imposition: Imposition): ImpositionSideMarks[];
18
+ //#endregion
@@ -0,0 +1,198 @@
1
+ import { roundMillimeters } from "./paper.js";
2
+ import { impose } from "./imposition.js";
3
+ //#region src/imposition-marks.ts
4
+ const MIN_MARK_LENGTH_MM = 2;
5
+ const unique = (values) => [...new Set(values.map(roundMillimeters))].sort((a, b) => a - b);
6
+ function addMark(result, edge, cutPosition, start, available, horizontal, direction) {
7
+ const length = Math.min(5, roundMillimeters(available));
8
+ if (length < 2) {
9
+ result.omittedMarks.push({
10
+ side: result.side,
11
+ edge,
12
+ cutPosition
13
+ });
14
+ return;
15
+ }
16
+ const end = roundMillimeters(start + direction * length);
17
+ result.marks.push(horizontal ? {
18
+ x1: Math.min(start, end),
19
+ y1: cutPosition,
20
+ x2: Math.max(start, end),
21
+ y2: cutPosition
22
+ } : {
23
+ x1: cutPosition,
24
+ y1: Math.min(start, end),
25
+ x2: cutPosition,
26
+ y2: Math.max(start, end)
27
+ });
28
+ }
29
+ function outerMarks(side, placements, paper) {
30
+ const verticalCuts = unique(placements.flatMap(({ trim }) => [trim.x, trim.x + trim.width]));
31
+ const horizontalCuts = unique(placements.flatMap(({ trim }) => [trim.y, trim.y + trim.height]));
32
+ const top = Math.min(...placements.map(({ bleedBox }) => bleedBox.y));
33
+ const right = Math.max(...placements.map(({ bleedBox }) => bleedBox.x + bleedBox.width));
34
+ const bottom = Math.max(...placements.map(({ bleedBox }) => bleedBox.y + bleedBox.height));
35
+ const left = Math.min(...placements.map(({ bleedBox }) => bleedBox.x));
36
+ for (const cut of verticalCuts) {
37
+ addMark(side, "top", cut, roundMillimeters(top - 1), top - 1, false, -1);
38
+ addMark(side, "bottom", cut, roundMillimeters(bottom + 1), paper.height - bottom - 1, false, 1);
39
+ }
40
+ for (const cut of horizontalCuts) {
41
+ addMark(side, "left", cut, roundMillimeters(left - 1), left - 1, true, -1);
42
+ addMark(side, "right", cut, roundMillimeters(right + 1), paper.width - right - 1, true, 1);
43
+ }
44
+ }
45
+ function intersectsBleed(mark, boxes) {
46
+ return boxes.some((box) => Math.max(mark.x1, box.x) <= Math.min(mark.x2, box.x + box.width) && Math.max(mark.y1, box.y) <= Math.min(mark.y2, box.y + box.height));
47
+ }
48
+ function rayRoom(start, cut, horizontal, direction, boxes) {
49
+ const obstacles = boxes.filter((box) => {
50
+ const acrossStart = horizontal ? box.y : box.x;
51
+ const acrossEnd = acrossStart + (horizontal ? box.height : box.width);
52
+ if (cut < acrossStart || cut > acrossEnd) return false;
53
+ const alongStart = horizontal ? box.x : box.y;
54
+ const alongEnd = alongStart + (horizontal ? box.width : box.height);
55
+ return direction < 0 ? alongEnd <= start : alongStart >= start;
56
+ }).map((box) => {
57
+ const alongStart = horizontal ? box.x : box.y;
58
+ const alongEnd = alongStart + (horizontal ? box.width : box.height);
59
+ return direction < 0 ? start - alongEnd - 1 : alongStart - start - 1;
60
+ });
61
+ return Math.max(0, Math.min(5, ...obstacles));
62
+ }
63
+ function cornerMarks(side, placements, rows) {
64
+ const boxes = placements.map(({ bleedBox }) => bleedBox);
65
+ const left = Math.min(...placements.map(({ trim }) => trim.x));
66
+ const right = Math.max(...placements.map(({ trim }) => trim.x + trim.width));
67
+ for (const placement of placements) {
68
+ const { trim, bleedBox, row } = placement;
69
+ const candidates = [];
70
+ if (row > 0) {
71
+ candidates.push([
72
+ "top",
73
+ trim.x,
74
+ bleedBox.y - 1,
75
+ false,
76
+ -1
77
+ ]);
78
+ candidates.push([
79
+ "top",
80
+ trim.x + trim.width,
81
+ bleedBox.y - 1,
82
+ false,
83
+ -1
84
+ ]);
85
+ }
86
+ if (row < rows - 1) {
87
+ candidates.push([
88
+ "bottom",
89
+ trim.x,
90
+ bleedBox.y + bleedBox.height + 1,
91
+ false,
92
+ 1
93
+ ]);
94
+ candidates.push([
95
+ "bottom",
96
+ trim.x + trim.width,
97
+ bleedBox.y + bleedBox.height + 1,
98
+ false,
99
+ 1
100
+ ]);
101
+ }
102
+ if (trim.x > left) {
103
+ candidates.push([
104
+ "left",
105
+ trim.y,
106
+ bleedBox.x - 1,
107
+ true,
108
+ -1
109
+ ]);
110
+ candidates.push([
111
+ "left",
112
+ trim.y + trim.height,
113
+ bleedBox.x - 1,
114
+ true,
115
+ -1
116
+ ]);
117
+ }
118
+ if (trim.x + trim.width < right) {
119
+ candidates.push([
120
+ "right",
121
+ trim.y,
122
+ bleedBox.x + bleedBox.width + 1,
123
+ true,
124
+ 1
125
+ ]);
126
+ candidates.push([
127
+ "right",
128
+ trim.y + trim.height,
129
+ bleedBox.x + bleedBox.width + 1,
130
+ true,
131
+ 1
132
+ ]);
133
+ }
134
+ for (const [edge, cut, start, horizontal, direction] of candidates) {
135
+ const before = side.marks.length;
136
+ addMark(side, edge, roundMillimeters(cut), roundMillimeters(start), rayRoom(start, cut, horizontal, direction, boxes), horizontal, direction);
137
+ const mark = side.marks.at(-1);
138
+ if (side.marks.length > before && mark && intersectsBleed(mark, boxes)) {
139
+ side.marks.pop();
140
+ side.omittedMarks.push({
141
+ side: side.side,
142
+ edge,
143
+ cutPosition: roundMillimeters(cut)
144
+ });
145
+ }
146
+ }
147
+ }
148
+ }
149
+ /** Computes physical crop-mark geometry without changing the fixed paper size. */
150
+ function impositionMarks(imposition) {
151
+ if (!imposition.marks) return [];
152
+ const cellCount = imposition.columns * imposition.rows;
153
+ const frontImposed = impose({
154
+ ...imposition,
155
+ sides: "one",
156
+ fill: "sequence",
157
+ skip: 0
158
+ }, cellCount);
159
+ const frontPlacements = frontImposed.placements;
160
+ const build = (sideName, placements) => {
161
+ const side = {
162
+ side: sideName,
163
+ marks: [],
164
+ omittedMarks: []
165
+ };
166
+ outerMarks(side, placements, frontImposed.paper);
167
+ if (imposition.cornerMarks) cornerMarks(side, placements, imposition.rows);
168
+ return side;
169
+ };
170
+ const front = build("front", frontPlacements);
171
+ if (imposition.sides === "one") return [front];
172
+ const portrait = frontImposed.paper.width <= frontImposed.paper.height;
173
+ const axis = imposition.flip === "long" === portrait ? "x" : "y";
174
+ const mirrorMark = (mark) => axis === "x" ? {
175
+ ...mark,
176
+ x1: roundMillimeters(frontImposed.paper.width - mark.x1),
177
+ x2: roundMillimeters(frontImposed.paper.width - mark.x2)
178
+ } : {
179
+ ...mark,
180
+ y1: roundMillimeters(frontImposed.paper.height - mark.y1),
181
+ y2: roundMillimeters(frontImposed.paper.height - mark.y2)
182
+ };
183
+ const mirrorEdge = (edge) => {
184
+ if (axis === "x") return edge === "left" ? "right" : edge === "right" ? "left" : edge;
185
+ return edge === "top" ? "bottom" : edge === "bottom" ? "top" : edge;
186
+ };
187
+ return [front, {
188
+ side: "back",
189
+ marks: front.marks.map(mirrorMark),
190
+ omittedMarks: front.omittedMarks.map(({ edge, cutPosition }) => ({
191
+ side: "back",
192
+ edge: mirrorEdge(edge),
193
+ cutPosition: roundMillimeters(axis === "x" && (edge === "top" || edge === "bottom") ? frontImposed.paper.width - cutPosition : axis === "y" && (edge === "left" || edge === "right") ? frontImposed.paper.height - cutPosition : cutPosition)
194
+ }))
195
+ }];
196
+ }
197
+ //#endregion
198
+ export { MIN_MARK_LENGTH_MM, impositionMarks };
package/dist/index.d.ts CHANGED
@@ -9,15 +9,16 @@ import { assignMembership, fitSection, fitTouchedSections, makeRoom, settleBoard
9
9
  import { Book, BookContents, BookFrontMatterEntry, BookInput, BookMode, BookPage, BookSection, BookView, BookViewInput, Chapter, isBookContents, isHebrew, noteMarkerIssues } from "./book.js";
10
10
  import { DeckFromSlidesOptions, SlideRow, deckFromSlides } from "./deck-from-slides.js";
11
11
  import { Direction, TextDirection, firstStrongDirection, languageDirection, resolveDirection } from "./direction.js";
12
- import { CUSTOM_PAPER_MAX_MM, CUSTOM_PAPER_MIN_MM, MARK_GAP_MM, MARK_LENGTH_MM, MM_PER_PT, NAMED_PAPERS, NamedPaper, NamedPaperMetadata, ORIENTATIONS, Orientation, PAPER_GROUPS, PAPER_METADATA, PAPER_MM, PAPER_UNITS, PX_PER_MM, Paper, PaperBox, PaperGroup, PaperUnit, PrintSetting, PrintSettingInput, fromMillimeters, printBoxes, printPadding, printProperties, roundMillimeters, sheetMm, toMillimeters } from "./paper.js";
12
+ import { CUSTOM_PAPER_MAX_MM, CUSTOM_PAPER_MIN_MM, MARK_GAP_MM, MARK_LENGTH_MM, MM_PER_PT, MarkSegment, NAMED_PAPERS, NamedPaper, NamedPaperMetadata, ORIENTATIONS, Orientation, PAPER_GROUPS, PAPER_METADATA, PAPER_MM, PAPER_UNITS, PX_PER_MM, Paper, PaperBox, PaperGroup, PaperUnit, PrintSetting, PrintSettingInput, fromMillimeters, paperPixels, printBoxes, printPadding, printProperties, roundMillimeters, sheetMm, toMillimeters } from "./paper.js";
13
13
  import { Imposed, MillimeterEdges, PageFit, PagePlacementKind, PagePlacementLayout, Placement, fitPage, impose, mirrorPlacement, pagePlacementLayout } from "./imposition.js";
14
+ import { ImpositionMarkEdge, ImpositionSideMarks, MIN_MARK_LENGTH_MM, OmittedImpositionMark, impositionMarks } from "./imposition-marks.js";
14
15
  import { Lexicon, PronunciationEntry, lexiconVersion } from "./lexicon.js";
15
16
  import { NoteMarker, NumberSystem, formatNumber, noteMarker } from "./numbering.js";
16
17
  import { Scripts } from "./scripts.js";
17
18
  import { ShotUse, shotsUsed } from "./shots-used.js";
18
19
  import { MAX_SLIDE_TIMING_MS } from "./timing.js";
19
20
  import { DEFAULT_TRANSITION_DURATION_MS, MAX_TRANSITION_DURATION_MS, MIN_TRANSITION_DURATION_MS, Transition, TransitionInput } from "./transition.js";
20
- import { Fill, SLOT_TYPES, SlotDeclaration, SlotDeclarationInput, SlotReport, SlotState, SlotType, SlotValue, Slots, SlotsInput, SlotsOptions, mergeSlotDeclarations } from "./slots.js";
21
+ import { Fill, SLOT_TYPES, SlotDeclaration, SlotDeclarationInput, SlotReport, SlotSource, SlotState, SlotType, SlotValue, Slots, SlotsInput, SlotsOptions, mergeSlotDeclarations } from "./slots.js";
21
22
  import { z } from "zod";
22
23
  //#region src/index.d.ts
23
24
  export declare const Margin: z.ZodObject<{
@@ -167,6 +168,8 @@ export declare const Imposition: z.ZodObject<{
167
168
  ltr: "ltr";
168
169
  rtl: "rtl";
169
170
  }>>;
171
+ marks: z.ZodDefault<z.ZodBoolean>;
172
+ cornerMarks: z.ZodDefault<z.ZodBoolean>;
170
173
  }, z.core.$strip>;
171
174
  export type Imposition = z.infer<typeof Imposition>;
172
175
  export type ImpositionInput = z.input<typeof Imposition>;
@@ -250,7 +253,7 @@ export declare const Page: z.ZodObject<{
250
253
  safe: z.ZodDefault<z.ZodNumber>;
251
254
  marks: z.ZodDefault<z.ZodBoolean>;
252
255
  }, z.core.$strip>>;
253
- slots: z.ZodOptional<z.ZodArray<z.ZodObject<{
256
+ slots: z.ZodOptional<z.ZodArray<z.ZodPipe<z.ZodObject<{
254
257
  key: z.ZodString;
255
258
  label: z.ZodString;
256
259
  type: z.ZodEnum<{
@@ -258,11 +261,35 @@ export declare const Page: z.ZodObject<{
258
261
  phone: "phone";
259
262
  email: "email";
260
263
  link: "link";
264
+ qr: "qr";
261
265
  image: "image";
262
266
  }>;
263
267
  required: z.ZodDefault<z.ZodBoolean>;
264
268
  placeholder: z.ZodOptional<z.ZodString>;
265
- }, z.core.$strip>>>;
269
+ overflow: z.ZodDefault<z.ZodEnum<{
270
+ refuse: "refuse";
271
+ shrink: "shrink";
272
+ truncate: "truncate";
273
+ wrap: "wrap";
274
+ }>>;
275
+ minSize: z.ZodOptional<z.ZodNumber>;
276
+ }, z.core.$strip>, z.ZodTransform<{
277
+ key: string;
278
+ label: string;
279
+ type: "text" | "phone" | "email" | "link" | "qr" | "image";
280
+ required: boolean;
281
+ overflow: "refuse" | "shrink" | "truncate" | "wrap";
282
+ placeholder?: string | undefined;
283
+ minSize?: number | undefined;
284
+ }, {
285
+ key: string;
286
+ label: string;
287
+ type: "text" | "phone" | "email" | "link" | "qr" | "image";
288
+ required: boolean;
289
+ overflow: "refuse" | "shrink" | "truncate" | "wrap";
290
+ placeholder?: string | undefined;
291
+ minSize?: number | undefined;
292
+ }>>>>;
266
293
  }, z.core.$strip>;
267
294
  export type Page = z.infer<typeof Page>;
268
295
  export type PageInput = z.input<typeof Page>;
@@ -476,7 +503,7 @@ export declare function jsonSchemas(): {
476
503
  safe: z.ZodDefault<z.ZodNumber>;
477
504
  marks: z.ZodDefault<z.ZodBoolean>;
478
505
  }, z.core.$strip>>;
479
- slots: z.ZodOptional<z.ZodArray<z.ZodObject<{
506
+ slots: z.ZodOptional<z.ZodArray<z.ZodPipe<z.ZodObject<{
480
507
  key: z.ZodString;
481
508
  label: z.ZodString;
482
509
  type: z.ZodEnum<{
@@ -484,11 +511,35 @@ export declare function jsonSchemas(): {
484
511
  phone: "phone";
485
512
  email: "email";
486
513
  link: "link";
514
+ qr: "qr";
487
515
  image: "image";
488
516
  }>;
489
517
  required: z.ZodDefault<z.ZodBoolean>;
490
518
  placeholder: z.ZodOptional<z.ZodString>;
491
- }, z.core.$strip>>>;
519
+ overflow: z.ZodDefault<z.ZodEnum<{
520
+ refuse: "refuse";
521
+ shrink: "shrink";
522
+ truncate: "truncate";
523
+ wrap: "wrap";
524
+ }>>;
525
+ minSize: z.ZodOptional<z.ZodNumber>;
526
+ }, z.core.$strip>, z.ZodTransform<{
527
+ key: string;
528
+ label: string;
529
+ type: "text" | "phone" | "email" | "link" | "qr" | "image";
530
+ required: boolean;
531
+ overflow: "refuse" | "shrink" | "truncate" | "wrap";
532
+ placeholder?: string | undefined;
533
+ minSize?: number | undefined;
534
+ }, {
535
+ key: string;
536
+ label: string;
537
+ type: "text" | "phone" | "email" | "link" | "qr" | "image";
538
+ required: boolean;
539
+ overflow: "refuse" | "shrink" | "truncate" | "wrap";
540
+ placeholder?: string | undefined;
541
+ minSize?: number | undefined;
542
+ }>>>>;
492
543
  }, z.core.$strip>>;
493
544
  lexicon: z.core.ZodStandardJSONSchemaPayload<z.ZodObject<{
494
545
  entries: z.ZodArray<z.ZodObject<{
@@ -583,6 +634,8 @@ export declare function jsonSchemas(): {
583
634
  ltr: "ltr";
584
635
  rtl: "rtl";
585
636
  }>>;
637
+ marks: z.ZodDefault<z.ZodBoolean>;
638
+ cornerMarks: z.ZodDefault<z.ZodBoolean>;
586
639
  }, z.core.$strip>>;
587
640
  deck: z.core.ZodStandardJSONSchemaPayload<z.ZodObject<{
588
641
  title: z.ZodString;
@@ -628,7 +681,7 @@ export declare function jsonSchemas(): {
628
681
  off: "off";
629
682
  viewer: "viewer";
630
683
  }>>;
631
- slots: z.ZodOptional<z.ZodArray<z.ZodObject<{
684
+ slots: z.ZodOptional<z.ZodArray<z.ZodPipe<z.ZodObject<{
632
685
  key: z.ZodString;
633
686
  label: z.ZodString;
634
687
  type: z.ZodEnum<{
@@ -636,11 +689,35 @@ export declare function jsonSchemas(): {
636
689
  phone: "phone";
637
690
  email: "email";
638
691
  link: "link";
692
+ qr: "qr";
639
693
  image: "image";
640
694
  }>;
641
695
  required: z.ZodDefault<z.ZodBoolean>;
642
696
  placeholder: z.ZodOptional<z.ZodString>;
643
- }, z.core.$strip>>>;
697
+ overflow: z.ZodDefault<z.ZodEnum<{
698
+ refuse: "refuse";
699
+ shrink: "shrink";
700
+ truncate: "truncate";
701
+ wrap: "wrap";
702
+ }>>;
703
+ minSize: z.ZodOptional<z.ZodNumber>;
704
+ }, z.core.$strip>, z.ZodTransform<{
705
+ key: string;
706
+ label: string;
707
+ type: "text" | "phone" | "email" | "link" | "qr" | "image";
708
+ required: boolean;
709
+ overflow: "refuse" | "shrink" | "truncate" | "wrap";
710
+ placeholder?: string | undefined;
711
+ minSize?: number | undefined;
712
+ }, {
713
+ key: string;
714
+ label: string;
715
+ type: "text" | "phone" | "email" | "link" | "qr" | "image";
716
+ required: boolean;
717
+ overflow: "refuse" | "shrink" | "truncate" | "wrap";
718
+ placeholder?: string | undefined;
719
+ minSize?: number | undefined;
720
+ }>>>>;
644
721
  slides: z.ZodArray<z.ZodObject<{
645
722
  id: z.ZodString;
646
723
  content: z.ZodDiscriminatedUnion<[z.ZodObject<{
@@ -986,7 +1063,7 @@ export declare function jsonSchemas(): {
986
1063
  landscape: "landscape";
987
1064
  }>;
988
1065
  }, z.core.$strict>>;
989
- slotDeclaration: z.core.ZodStandardJSONSchemaPayload<z.ZodObject<{
1066
+ slotDeclaration: z.core.ZodStandardJSONSchemaPayload<z.ZodPipe<z.ZodObject<{
990
1067
  key: z.ZodString;
991
1068
  label: z.ZodString;
992
1069
  type: z.ZodEnum<{
@@ -994,12 +1071,36 @@ export declare function jsonSchemas(): {
994
1071
  phone: "phone";
995
1072
  email: "email";
996
1073
  link: "link";
1074
+ qr: "qr";
997
1075
  image: "image";
998
1076
  }>;
999
1077
  required: z.ZodDefault<z.ZodBoolean>;
1000
1078
  placeholder: z.ZodOptional<z.ZodString>;
1001
- }, z.core.$strip>>;
1002
- slotDeclarationInput: z.core.ZodStandardJSONSchemaPayload<z.ZodObject<{
1079
+ overflow: z.ZodDefault<z.ZodEnum<{
1080
+ refuse: "refuse";
1081
+ shrink: "shrink";
1082
+ truncate: "truncate";
1083
+ wrap: "wrap";
1084
+ }>>;
1085
+ minSize: z.ZodOptional<z.ZodNumber>;
1086
+ }, z.core.$strip>, z.ZodTransform<{
1087
+ key: string;
1088
+ label: string;
1089
+ type: "text" | "phone" | "email" | "link" | "qr" | "image";
1090
+ required: boolean;
1091
+ overflow: "refuse" | "shrink" | "truncate" | "wrap";
1092
+ placeholder?: string | undefined;
1093
+ minSize?: number | undefined;
1094
+ }, {
1095
+ key: string;
1096
+ label: string;
1097
+ type: "text" | "phone" | "email" | "link" | "qr" | "image";
1098
+ required: boolean;
1099
+ overflow: "refuse" | "shrink" | "truncate" | "wrap";
1100
+ placeholder?: string | undefined;
1101
+ minSize?: number | undefined;
1102
+ }>>>;
1103
+ slotDeclarationInput: z.core.ZodStandardJSONSchemaPayload<z.ZodPipe<z.ZodObject<{
1003
1104
  key: z.ZodString;
1004
1105
  label: z.ZodString;
1005
1106
  type: z.ZodEnum<{
@@ -1007,11 +1108,35 @@ export declare function jsonSchemas(): {
1007
1108
  phone: "phone";
1008
1109
  email: "email";
1009
1110
  link: "link";
1111
+ qr: "qr";
1010
1112
  image: "image";
1011
1113
  }>;
1012
1114
  required: z.ZodDefault<z.ZodBoolean>;
1013
1115
  placeholder: z.ZodOptional<z.ZodString>;
1014
- }, z.core.$strict>>;
1116
+ overflow: z.ZodDefault<z.ZodEnum<{
1117
+ refuse: "refuse";
1118
+ shrink: "shrink";
1119
+ truncate: "truncate";
1120
+ wrap: "wrap";
1121
+ }>>;
1122
+ minSize: z.ZodOptional<z.ZodNumber>;
1123
+ }, z.core.$strict>, z.ZodTransform<{
1124
+ key: string;
1125
+ label: string;
1126
+ type: "text" | "phone" | "email" | "link" | "qr" | "image";
1127
+ required: boolean;
1128
+ overflow: "refuse" | "shrink" | "truncate" | "wrap";
1129
+ placeholder?: string | undefined;
1130
+ minSize?: number | undefined;
1131
+ }, {
1132
+ key: string;
1133
+ label: string;
1134
+ type: "text" | "phone" | "email" | "link" | "qr" | "image";
1135
+ required: boolean;
1136
+ overflow: "refuse" | "shrink" | "truncate" | "wrap";
1137
+ placeholder?: string | undefined;
1138
+ minSize?: number | undefined;
1139
+ }>>>;
1015
1140
  };
1016
1141
  //#endregion
1017
- export { Annotation, type ArrangeOptions, Board, type BoardInput, BoardItem, type BoardItemAnchor, BoardLabel, type BoardListingGroup, BoardSection, type BoardShapes, type BoardView, Book, BookContents, BookFrontMatterEntry, type BookInput, BookMode, BookPage, BookSection, BookView, type BookViewInput, Box, CUSTOM_PAPER_MAX_MM, CUSTOM_PAPER_MIN_MM, Chapter, Cue, DECK_SIZE, DEFAULT_TRANSITION_DURATION_MS, Deck, type DeckFromSlidesOptions, type DeckInput, type DeckLimits, Direction, Fill, GridCell, type GridDropTarget, ImageFit, type Imposed, Lexicon, MAKE_ROOM_LIMIT, MARK_GAP_MM, MARK_LENGTH_MM, MAX_BOARD_ZOOM, MAX_SLIDE_TIMING_MS, MAX_TRANSITION_DURATION_MS, MIN_BOARD_ITEM_WIDTH, MIN_BOARD_ZOOM, MIN_TRANSITION_DURATION_MS, MM_PER_PT, Manifest, type MillimeterEdges, NAMED_PAPERS, type NamedPaper, type NamedPaperMetadata, Narration, NoteMarker, NumberSystem, ORIENTATIONS, Orientation, PAPER_GROUPS, PAPER_METADATA, PAPER_MM, PAPER_UNITS, PLAYBACK_MODES, PX_PER_MM, type PageFit, type PagePlacementKind, type PagePlacementLayout, Paper, type PaperBox, type PaperGroup, PaperUnit, type Placement, Playback, type PlaybackMode, Point, PrintSetting, PrintSettingInput, PronunciationEntry, PublishedShot, SECTION_GAP, SECTION_MIN_SIZE, SECTION_PADDING, SECTION_TITLE_ROOM, SHOT_KEY, SLOT_TYPES, Scripts, Shot, type ShotUse, Size, Slide, SlideContent, type SlideRow, SlotDeclaration, SlotDeclarationInput, SlotReport, SlotState, SlotType, SlotValue, Slots, SlotsInput, SlotsOptions, TextDirection, Transition, TransitionInput, Word, type ZoomBounds, addItem, annotationCueIssues, arrange, assignMembership, boardBounds, boardListing, boardListingIsEmpty, boardToScreen, deckFromSlides, deriveSectionCells, exceedsLimits, firstStrongDirection, fitPage, fitSection, fitTouchedSections, foldForSearch, formatNumber, fromMillimeters, gridDropMarkerBox, gridDropTarget, impose, insertIntoGrid, isBookContents, isHebrew, itemAt, itemHeight, languageDirection, layoutSection, lexiconVersion, makeRoom, mergeSlotDeclarations, mirrorPlacement, moveItems, moveSection, nameMatches, noteMarker, noteMarkerIssues, pagePlacementLayout, parsePlayback, printBoxes, printPadding, printProperties, removeFromGrid, removeItems, resizeItem, resolveDirection, revealView, roundMillimeters, screenToBoard, settleBoard, sheetMm, shotsUsed, toMillimeters, visibleItems, zoomAt, zoomToFit };
1142
+ export { Annotation, type ArrangeOptions, Board, type BoardInput, BoardItem, type BoardItemAnchor, BoardLabel, type BoardListingGroup, BoardSection, type BoardShapes, type BoardView, Book, BookContents, BookFrontMatterEntry, type BookInput, BookMode, BookPage, BookSection, BookView, type BookViewInput, Box, CUSTOM_PAPER_MAX_MM, CUSTOM_PAPER_MIN_MM, Chapter, Cue, DECK_SIZE, DEFAULT_TRANSITION_DURATION_MS, Deck, type DeckFromSlidesOptions, type DeckInput, type DeckLimits, Direction, Fill, GridCell, type GridDropTarget, ImageFit, type Imposed, type ImpositionMarkEdge, type ImpositionSideMarks, Lexicon, MAKE_ROOM_LIMIT, MARK_GAP_MM, MARK_LENGTH_MM, MAX_BOARD_ZOOM, MAX_SLIDE_TIMING_MS, MAX_TRANSITION_DURATION_MS, MIN_BOARD_ITEM_WIDTH, MIN_BOARD_ZOOM, MIN_MARK_LENGTH_MM, MIN_TRANSITION_DURATION_MS, MM_PER_PT, Manifest, type MarkSegment, type MillimeterEdges, NAMED_PAPERS, type NamedPaper, type NamedPaperMetadata, Narration, NoteMarker, NumberSystem, ORIENTATIONS, type OmittedImpositionMark, Orientation, PAPER_GROUPS, PAPER_METADATA, PAPER_MM, PAPER_UNITS, PLAYBACK_MODES, PX_PER_MM, type PageFit, type PagePlacementKind, type PagePlacementLayout, Paper, type PaperBox, type PaperGroup, PaperUnit, type Placement, Playback, type PlaybackMode, Point, PrintSetting, PrintSettingInput, PronunciationEntry, PublishedShot, SECTION_GAP, SECTION_MIN_SIZE, SECTION_PADDING, SECTION_TITLE_ROOM, SHOT_KEY, SLOT_TYPES, Scripts, Shot, type ShotUse, Size, Slide, SlideContent, type SlideRow, SlotDeclaration, SlotDeclarationInput, SlotReport, SlotSource, SlotState, SlotType, SlotValue, Slots, SlotsInput, SlotsOptions, TextDirection, Transition, TransitionInput, Word, type ZoomBounds, addItem, annotationCueIssues, arrange, assignMembership, boardBounds, boardListing, boardListingIsEmpty, boardToScreen, deckFromSlides, deriveSectionCells, exceedsLimits, firstStrongDirection, fitPage, fitSection, fitTouchedSections, foldForSearch, formatNumber, fromMillimeters, gridDropMarkerBox, gridDropTarget, impose, impositionMarks, insertIntoGrid, isBookContents, isHebrew, itemAt, itemHeight, languageDirection, layoutSection, lexiconVersion, makeRoom, mergeSlotDeclarations, mirrorPlacement, moveItems, moveSection, nameMatches, noteMarker, noteMarkerIssues, pagePlacementLayout, paperPixels, parsePlayback, printBoxes, printPadding, printProperties, removeFromGrid, removeItems, resizeItem, resolveDirection, revealView, roundMillimeters, screenToBoard, settleBoard, sheetMm, shotsUsed, toMillimeters, visibleItems, zoomAt, zoomToFit };
package/dist/index.js CHANGED
@@ -6,7 +6,7 @@ import { DEFAULT_TRANSITION_DURATION_MS, MAX_TRANSITION_DURATION_MS, MIN_TRANSIT
6
6
  import { Annotation, Box, Cue, DECK_SIZE, Deck, DeckShape, ImageFit, Manifest, Narration, PLAYBACK_MODES, Playback, Point, PublishedShot, SHOT_KEY, Shot, Size, Slide, SlideContent, Word, annotationCueIssues, exceedsLimits, parsePlayback } from "./deck.js";
7
7
  import { Board, BoardItem, BoardLabel, BoardSection, GridCell } from "./board.js";
8
8
  import { NoteMarker, NumberSystem, formatNumber, noteMarker } from "./numbering.js";
9
- import { CUSTOM_PAPER_MAX_MM, CUSTOM_PAPER_MIN_MM, MARK_GAP_MM, MARK_LENGTH_MM, MM_PER_PT, NAMED_PAPERS, ORIENTATIONS, Orientation, PAPER_GROUPS, PAPER_METADATA, PAPER_MM, PAPER_UNITS, PX_PER_MM, Paper, PaperUnit, PrintSetting, PrintSettingInput, fromMillimeters, printBoxes, printPadding, printProperties, roundMillimeters, sheetMm, toMillimeters } from "./paper.js";
9
+ import { CUSTOM_PAPER_MAX_MM, CUSTOM_PAPER_MIN_MM, MARK_GAP_MM, MARK_LENGTH_MM, MM_PER_PT, NAMED_PAPERS, ORIENTATIONS, Orientation, PAPER_GROUPS, PAPER_METADATA, PAPER_MM, PAPER_UNITS, PX_PER_MM, Paper, PaperUnit, PrintSetting, PrintSettingInput, fromMillimeters, paperPixels, printBoxes, printPadding, printProperties, roundMillimeters, sheetMm, toMillimeters } from "./paper.js";
10
10
  import { Book, BookContents, BookFrontMatterEntry, BookMode, BookPage, BookSection, BookShape, BookView, Chapter, isBookContents, isHebrew, noteMarkerIssues } from "./book.js";
11
11
  import { Lexicon, PronunciationEntry, lexiconVersion } from "./lexicon.js";
12
12
  import { MIN_BOARD_ITEM_WIDTH, addItem, moveItems, moveSection, removeItems, resizeItem } from "./board-edit.js";
@@ -17,6 +17,7 @@ import { deriveSectionCells, gridDropMarkerBox, gridDropTarget, insertIntoGrid,
17
17
  import { assignMembership, fitSection, fitTouchedSections, makeRoom, settleBoard } from "./board-sections.js";
18
18
  import { deckFromSlides } from "./deck-from-slides.js";
19
19
  import { fitPage, impose, mirrorPlacement, pagePlacementLayout } from "./imposition.js";
20
+ import { MIN_MARK_LENGTH_MM, impositionMarks } from "./imposition-marks.js";
20
21
  import { shotsUsed } from "./shots-used.js";
21
22
  import { z } from "zod";
22
23
  //#region src/index.ts
@@ -78,9 +79,16 @@ const Imposition = z.object({
78
79
  sides: z.enum(["one", "two"]).default("one"),
79
80
  flip: z.enum(["long", "short"]).default("long"),
80
81
  skip: z.number().int().nonnegative().default(0),
81
- dir: z.enum(["ltr", "rtl"]).default("ltr")
82
+ dir: z.enum(["ltr", "rtl"]).default("ltr"),
83
+ marks: z.boolean().default(false),
84
+ cornerMarks: z.boolean().default(false)
82
85
  }).superRefine((imposition, ctx) => {
83
86
  const cellCount = BigInt(imposition.columns) * BigInt(imposition.rows);
87
+ if (imposition.cornerMarks && !imposition.marks) ctx.addIssue({
88
+ code: "custom",
89
+ path: ["cornerMarks"],
90
+ message: "cornerMarks requires marks to be true"
91
+ });
84
92
  if (imposition.columns > 1e4 || imposition.rows > 1e4 || cellCount > BigInt(1e4)) {
85
93
  ctx.addIssue({
86
94
  code: "custom",
@@ -162,4 +170,4 @@ function jsonSchemas() {
162
170
  };
163
171
  }
164
172
  //#endregion
165
- export { Annotation, Board, BoardItem, BoardLabel, BoardSection, Book, BookContents, BookFrontMatterEntry, BookMode, BookPage, BookSection, BookView, Box, CUSTOM_PAPER_MAX_MM, CUSTOM_PAPER_MIN_MM, Chapter, Cue, DECK_SIZE, DEFAULT_TRANSITION_DURATION_MS, Deck, Direction, GridCell, ImageFit, Imposition, Lexicon, MAKE_ROOM_LIMIT, MARK_GAP_MM, MARK_LENGTH_MM, MAX_BOARD_ZOOM, MAX_IMPOSITION_CELLS, MAX_SLIDE_TIMING_MS, MAX_TRANSITION_DURATION_MS, MIN_BOARD_ITEM_WIDTH, MIN_BOARD_ZOOM, MIN_TRANSITION_DURATION_MS, MM_PER_PT, Manifest, Margin, NAMED_PAPERS, Narration, NoteMarker, NumberSystem, ORIENTATIONS, Orientation, PAPER_GROUPS, PAPER_METADATA, PAPER_MM, PAPER_UNITS, PLAYBACK_MODES, PX_PER_MM, Page, PageSize, Paper, PaperUnit, Playback, Point, Print, PrintSetting, PrintSettingInput, PronunciationEntry, PublishedShot, SECTION_GAP, SECTION_MIN_SIZE, SECTION_PADDING, SECTION_TITLE_ROOM, SHOT_KEY, SLOT_TYPES, Scripts, Shot, Size, Slide, SlideContent, SlotDeclaration, SlotDeclarationInput, SlotType, Slots, SlotsInput, TextDirection, Transition, Word, addItem, annotationCueIssues, arrange, assignMembership, boardBounds, boardListing, boardListingIsEmpty, boardToScreen, deckFromSlides, deriveSectionCells, exceedsLimits, firstStrongDirection, fitPage, fitSection, fitTouchedSections, foldForSearch, formatNumber, fromMillimeters, gridDropMarkerBox, gridDropTarget, impose, insertIntoGrid, isBookContents, isHebrew, itemAt, itemHeight, jsonSchemas, languageDirection, layoutSection, lexiconVersion, makeRoom, mergeSlotDeclarations, mirrorPlacement, moveItems, moveSection, nameMatches, noteMarker, noteMarkerIssues, pagePlacementLayout, parsePlayback, printBoxes, printPadding, printProperties, removeFromGrid, removeItems, resizeItem, resolveDirection, revealView, roundMillimeters, screenToBoard, settleBoard, sheetMm, shotsUsed, toMillimeters, visibleItems, zoomAt, zoomToFit };
173
+ export { Annotation, Board, BoardItem, BoardLabel, BoardSection, Book, BookContents, BookFrontMatterEntry, BookMode, BookPage, BookSection, BookView, Box, CUSTOM_PAPER_MAX_MM, CUSTOM_PAPER_MIN_MM, Chapter, Cue, DECK_SIZE, DEFAULT_TRANSITION_DURATION_MS, Deck, Direction, GridCell, ImageFit, Imposition, Lexicon, MAKE_ROOM_LIMIT, MARK_GAP_MM, MARK_LENGTH_MM, MAX_BOARD_ZOOM, MAX_IMPOSITION_CELLS, MAX_SLIDE_TIMING_MS, MAX_TRANSITION_DURATION_MS, MIN_BOARD_ITEM_WIDTH, MIN_BOARD_ZOOM, MIN_MARK_LENGTH_MM, MIN_TRANSITION_DURATION_MS, MM_PER_PT, Manifest, Margin, NAMED_PAPERS, Narration, NoteMarker, NumberSystem, ORIENTATIONS, Orientation, PAPER_GROUPS, PAPER_METADATA, PAPER_MM, PAPER_UNITS, PLAYBACK_MODES, PX_PER_MM, Page, PageSize, Paper, PaperUnit, Playback, Point, Print, PrintSetting, PrintSettingInput, PronunciationEntry, PublishedShot, SECTION_GAP, SECTION_MIN_SIZE, SECTION_PADDING, SECTION_TITLE_ROOM, SHOT_KEY, SLOT_TYPES, Scripts, Shot, Size, Slide, SlideContent, SlotDeclaration, SlotDeclarationInput, SlotType, Slots, SlotsInput, TextDirection, Transition, Word, addItem, annotationCueIssues, arrange, assignMembership, boardBounds, boardListing, boardListingIsEmpty, boardToScreen, deckFromSlides, deriveSectionCells, exceedsLimits, firstStrongDirection, fitPage, fitSection, fitTouchedSections, foldForSearch, formatNumber, fromMillimeters, gridDropMarkerBox, gridDropTarget, impose, impositionMarks, insertIntoGrid, isBookContents, isHebrew, itemAt, itemHeight, jsonSchemas, languageDirection, layoutSection, lexiconVersion, makeRoom, mergeSlotDeclarations, mirrorPlacement, moveItems, moveSection, nameMatches, noteMarker, noteMarkerIssues, pagePlacementLayout, paperPixels, parsePlayback, printBoxes, printPadding, printProperties, removeFromGrid, removeItems, resizeItem, resolveDirection, revealView, roundMillimeters, screenToBoard, settleBoard, sheetMm, shotsUsed, toMillimeters, visibleItems, zoomAt, zoomToFit };
package/dist/paper.d.ts CHANGED
@@ -303,6 +303,7 @@ export declare function sheetMm(print: Pick<Print, 'paper' | 'orientation'>): {
303
303
  height: number;
304
304
  };
305
305
  export declare const PX_PER_MM: number;
306
+ export declare const paperPixels: (millimeters: number) => number;
306
307
  export declare function printProperties(print: Pick<Print, 'bleed' | 'safe'>, unit?: 'mm' | 'in' | 'pt'): string;
307
308
  export declare function printPadding(edges: {
308
309
  top: number;
package/dist/paper.js CHANGED
@@ -373,6 +373,7 @@ function sheetMm(print) {
373
373
  };
374
374
  }
375
375
  const PX_PER_MM = 96 / 25.4;
376
+ const paperPixels = (millimeters) => Math.ceil(millimeters * PX_PER_MM - 1e-9);
376
377
  function printProperties(print, unit = "mm") {
377
378
  return `:root{--segnavia-bleed:${roundMillimeters(toMillimeters(print.bleed, unit))}mm;--segnavia-safe:${roundMillimeters(toMillimeters(print.safe, unit))}mm}`;
378
379
  }
@@ -482,4 +483,4 @@ function printBoxes(print) {
482
483
  };
483
484
  }
484
485
  //#endregion
485
- export { CUSTOM_PAPER_MAX_MM, CUSTOM_PAPER_MIN_MM, MARK_GAP_MM, MARK_LENGTH_MM, MM_PER_PT, NAMED_PAPERS, ORIENTATIONS, Orientation, PAPER_GROUPS, PAPER_METADATA, PAPER_MM, PAPER_UNITS, PX_PER_MM, Paper, PaperUnit, PrintSetting, PrintSettingInput, fromMillimeters, printBoxes, printPadding, printProperties, roundMillimeters, sheetMm, toMillimeters };
486
+ export { CUSTOM_PAPER_MAX_MM, CUSTOM_PAPER_MIN_MM, MARK_GAP_MM, MARK_LENGTH_MM, MM_PER_PT, NAMED_PAPERS, ORIENTATIONS, Orientation, PAPER_GROUPS, PAPER_METADATA, PAPER_MM, PAPER_UNITS, PX_PER_MM, Paper, PaperUnit, PrintSetting, PrintSettingInput, fromMillimeters, paperPixels, printBoxes, printPadding, printProperties, roundMillimeters, sheetMm, toMillimeters };
package/dist/slots.d.ts CHANGED
@@ -1,15 +1,16 @@
1
1
  import { z } from "zod";
2
2
  //#region src/slots.d.ts
3
- export declare const SLOT_TYPES: readonly ["text", "phone", "email", "link", "image"];
3
+ export declare const SLOT_TYPES: readonly ["text", "phone", "email", "link", "qr", "image"];
4
4
  export declare const SlotType: z.ZodEnum<{
5
5
  text: "text";
6
6
  phone: "phone";
7
7
  email: "email";
8
8
  link: "link";
9
+ qr: "qr";
9
10
  image: "image";
10
11
  }>;
11
12
  export type SlotType = z.infer<typeof SlotType>;
12
- export declare const SlotDeclaration: z.ZodObject<{
13
+ export declare const SlotDeclaration: z.ZodPipe<z.ZodObject<{
13
14
  key: z.ZodString;
14
15
  label: z.ZodString;
15
16
  type: z.ZodEnum<{
@@ -17,13 +18,39 @@ export declare const SlotDeclaration: z.ZodObject<{
17
18
  phone: "phone";
18
19
  email: "email";
19
20
  link: "link";
21
+ qr: "qr";
20
22
  image: "image";
21
23
  }>;
22
24
  required: z.ZodDefault<z.ZodBoolean>;
23
25
  placeholder: z.ZodOptional<z.ZodString>;
24
- }, z.core.$strip>;
25
- export type SlotDeclaration = z.infer<typeof SlotDeclaration>;
26
- export declare const SlotDeclarationInput: z.ZodObject<{
26
+ overflow: z.ZodDefault<z.ZodEnum<{
27
+ refuse: "refuse";
28
+ shrink: "shrink";
29
+ truncate: "truncate";
30
+ wrap: "wrap";
31
+ }>>;
32
+ minSize: z.ZodOptional<z.ZodNumber>;
33
+ }, z.core.$strip>, z.ZodTransform<{
34
+ key: string;
35
+ label: string;
36
+ type: "text" | "phone" | "email" | "link" | "qr" | "image";
37
+ required: boolean;
38
+ overflow: "refuse" | "shrink" | "truncate" | "wrap";
39
+ placeholder?: string | undefined;
40
+ minSize?: number | undefined;
41
+ }, {
42
+ key: string;
43
+ label: string;
44
+ type: "text" | "phone" | "email" | "link" | "qr" | "image";
45
+ required: boolean;
46
+ overflow: "refuse" | "shrink" | "truncate" | "wrap";
47
+ placeholder?: string | undefined;
48
+ minSize?: number | undefined;
49
+ }>>;
50
+ export type SlotDeclaration = Omit<z.infer<typeof SlotDeclaration>, 'overflow'> & {
51
+ overflow?: z.infer<typeof SlotDeclaration>['overflow'];
52
+ };
53
+ export declare const SlotDeclarationInput: z.ZodPipe<z.ZodObject<{
27
54
  key: z.ZodString;
28
55
  label: z.ZodString;
29
56
  type: z.ZodEnum<{
@@ -31,13 +58,37 @@ export declare const SlotDeclarationInput: z.ZodObject<{
31
58
  phone: "phone";
32
59
  email: "email";
33
60
  link: "link";
61
+ qr: "qr";
34
62
  image: "image";
35
63
  }>;
36
64
  required: z.ZodDefault<z.ZodBoolean>;
37
65
  placeholder: z.ZodOptional<z.ZodString>;
38
- }, z.core.$strict>;
66
+ overflow: z.ZodDefault<z.ZodEnum<{
67
+ refuse: "refuse";
68
+ shrink: "shrink";
69
+ truncate: "truncate";
70
+ wrap: "wrap";
71
+ }>>;
72
+ minSize: z.ZodOptional<z.ZodNumber>;
73
+ }, z.core.$strict>, z.ZodTransform<{
74
+ key: string;
75
+ label: string;
76
+ type: "text" | "phone" | "email" | "link" | "qr" | "image";
77
+ required: boolean;
78
+ overflow: "refuse" | "shrink" | "truncate" | "wrap";
79
+ placeholder?: string | undefined;
80
+ minSize?: number | undefined;
81
+ }, {
82
+ key: string;
83
+ label: string;
84
+ type: "text" | "phone" | "email" | "link" | "qr" | "image";
85
+ required: boolean;
86
+ overflow: "refuse" | "shrink" | "truncate" | "wrap";
87
+ placeholder?: string | undefined;
88
+ minSize?: number | undefined;
89
+ }>>;
39
90
  export type SlotDeclarationInput = z.input<typeof SlotDeclarationInput>;
40
- export declare const Slots: z.ZodArray<z.ZodObject<{
91
+ export declare const Slots: z.ZodArray<z.ZodPipe<z.ZodObject<{
41
92
  key: z.ZodString;
42
93
  label: z.ZodString;
43
94
  type: z.ZodEnum<{
@@ -45,13 +96,37 @@ export declare const Slots: z.ZodArray<z.ZodObject<{
45
96
  phone: "phone";
46
97
  email: "email";
47
98
  link: "link";
99
+ qr: "qr";
48
100
  image: "image";
49
101
  }>;
50
102
  required: z.ZodDefault<z.ZodBoolean>;
51
103
  placeholder: z.ZodOptional<z.ZodString>;
52
- }, z.core.$strip>>;
104
+ overflow: z.ZodDefault<z.ZodEnum<{
105
+ refuse: "refuse";
106
+ shrink: "shrink";
107
+ truncate: "truncate";
108
+ wrap: "wrap";
109
+ }>>;
110
+ minSize: z.ZodOptional<z.ZodNumber>;
111
+ }, z.core.$strip>, z.ZodTransform<{
112
+ key: string;
113
+ label: string;
114
+ type: "text" | "phone" | "email" | "link" | "qr" | "image";
115
+ required: boolean;
116
+ overflow: "refuse" | "shrink" | "truncate" | "wrap";
117
+ placeholder?: string | undefined;
118
+ minSize?: number | undefined;
119
+ }, {
120
+ key: string;
121
+ label: string;
122
+ type: "text" | "phone" | "email" | "link" | "qr" | "image";
123
+ required: boolean;
124
+ overflow: "refuse" | "shrink" | "truncate" | "wrap";
125
+ placeholder?: string | undefined;
126
+ minSize?: number | undefined;
127
+ }>>>;
53
128
  export type Slots = z.infer<typeof Slots>;
54
- export declare const SlotsInput: z.ZodArray<z.ZodObject<{
129
+ export declare const SlotsInput: z.ZodArray<z.ZodPipe<z.ZodObject<{
55
130
  key: z.ZodString;
56
131
  label: z.ZodString;
57
132
  type: z.ZodEnum<{
@@ -59,11 +134,35 @@ export declare const SlotsInput: z.ZodArray<z.ZodObject<{
59
134
  phone: "phone";
60
135
  email: "email";
61
136
  link: "link";
137
+ qr: "qr";
62
138
  image: "image";
63
139
  }>;
64
140
  required: z.ZodDefault<z.ZodBoolean>;
65
141
  placeholder: z.ZodOptional<z.ZodString>;
66
- }, z.core.$strict>>;
142
+ overflow: z.ZodDefault<z.ZodEnum<{
143
+ refuse: "refuse";
144
+ shrink: "shrink";
145
+ truncate: "truncate";
146
+ wrap: "wrap";
147
+ }>>;
148
+ minSize: z.ZodOptional<z.ZodNumber>;
149
+ }, z.core.$strict>, z.ZodTransform<{
150
+ key: string;
151
+ label: string;
152
+ type: "text" | "phone" | "email" | "link" | "qr" | "image";
153
+ required: boolean;
154
+ overflow: "refuse" | "shrink" | "truncate" | "wrap";
155
+ placeholder?: string | undefined;
156
+ minSize?: number | undefined;
157
+ }, {
158
+ key: string;
159
+ label: string;
160
+ type: "text" | "phone" | "email" | "link" | "qr" | "image";
161
+ required: boolean;
162
+ overflow: "refuse" | "shrink" | "truncate" | "wrap";
163
+ placeholder?: string | undefined;
164
+ minSize?: number | undefined;
165
+ }>>>;
67
166
  export type SlotsInput = z.input<typeof SlotsInput>;
68
167
  export type SlotValue = string | {
69
168
  asset: string;
@@ -73,15 +172,26 @@ export interface Fill {
73
172
  label?: string;
74
173
  values: Record<string, SlotValue>;
75
174
  }
76
- export type SlotState = 'filled' | 'placeholder' | 'unavailable' | 'invalid';
175
+ export interface SlotSource {
176
+ id: string;
177
+ label: string;
178
+ fields: string[];
179
+ list(options: {
180
+ signal: AbortSignal;
181
+ }): Promise<Fill[]>;
182
+ }
183
+ export type SlotState = 'filled' | 'placeholder' | 'unavailable' | 'invalid' | 'fit' | 'shrunk' | 'overflowed';
77
184
  export interface SlotReport {
78
185
  fill: string | null;
79
186
  slots: Record<string, SlotState>;
187
+ origins: Record<string, 'hand' | 'source'>;
80
188
  }
81
189
  export interface SlotsOptions {
190
+ /** The fill selected from a host data source; hand values override it per declared key. */
191
+ source?: Fill;
82
192
  fill?: Fill;
83
193
  declarations?: SlotDeclarationInput[];
84
- /** Resolve an asset without network access. Hosts should honour the signal so timed-out renders stop this work promptly. */
194
+ /** Resolve an asset without network access. Hosts should honor the signal so timed-out renders stop this work promptly. */
85
195
  resolveAsset?: (ref: string, options: {
86
196
  signal: AbortSignal;
87
197
  }) => Promise<string>;
package/dist/slots.js CHANGED
@@ -5,6 +5,7 @@ const SLOT_TYPES = [
5
5
  "phone",
6
6
  "email",
7
7
  "link",
8
+ "qr",
8
9
  "image"
9
10
  ];
10
11
  const SlotType = z.enum(SLOT_TYPES);
@@ -13,10 +14,39 @@ const SlotDeclarationShape = {
13
14
  label: z.string().min(1),
14
15
  type: SlotType,
15
16
  required: z.boolean().default(false),
16
- placeholder: z.string().optional()
17
+ placeholder: z.string().optional(),
18
+ overflow: z.enum([
19
+ "shrink",
20
+ "truncate",
21
+ "wrap",
22
+ "refuse"
23
+ ]).default("wrap"),
24
+ minSize: z.number().positive().finite().optional()
17
25
  };
18
- const SlotDeclaration = z.object(SlotDeclarationShape);
19
- const SlotDeclarationInput = z.strictObject(SlotDeclarationShape);
26
+ function validateOverflow(slot, ctx) {
27
+ if ((slot.type === "qr" || slot.type === "image") && slot.overflow !== "wrap") ctx.addIssue({
28
+ code: "custom",
29
+ path: ["overflow"],
30
+ message: `overflow cannot be declared for ${slot.type} slots`
31
+ });
32
+ if (slot.type === "qr" || slot.type === "image") {
33
+ if (slot.minSize !== void 0) ctx.addIssue({
34
+ code: "custom",
35
+ path: ["minSize"],
36
+ message: `minSize cannot be declared for ${slot.type} slots`
37
+ });
38
+ } else if (slot.overflow !== "shrink" && slot.minSize !== void 0) ctx.addIssue({
39
+ code: "custom",
40
+ path: ["minSize"],
41
+ message: "minSize can be declared only when overflow is shrink"
42
+ });
43
+ }
44
+ const withOverflowDefaults = (slot) => slot.overflow === "shrink" ? {
45
+ ...slot,
46
+ minSize: slot.minSize ?? 6
47
+ } : slot;
48
+ const SlotDeclaration = z.object(SlotDeclarationShape).superRefine(validateOverflow).transform(withOverflowDefaults);
49
+ const SlotDeclarationInput = z.strictObject(SlotDeclarationShape).superRefine(validateOverflow).transform(withOverflowDefaults);
20
50
  const Slots = z.array(SlotDeclaration).superRefine((slots, ctx) => {
21
51
  const seen = /* @__PURE__ */ new Set();
22
52
  slots.forEach((slot, index) => {
@@ -47,7 +77,7 @@ function mergeSlotDeclarations(...groups) {
47
77
  merged.set(slot.key, slot);
48
78
  continue;
49
79
  }
50
- if (previous.type !== slot.type || previous.required !== slot.required) throw new RangeError(`Slot "${slot.key}" has conflicting declarations: type ${previous.type}, required ${previous.required}; type ${slot.type}, required ${slot.required}.`);
80
+ if (previous.type !== slot.type || previous.required !== slot.required || (previous.overflow ?? "wrap") !== (slot.overflow ?? "wrap") || previous.minSize !== slot.minSize) throw new RangeError(`Slot "${slot.key}" has conflicting declarations: type ${previous.type}, required ${previous.required}, overflow ${previous.overflow ?? "wrap"}; type ${slot.type}, required ${slot.required}, overflow ${slot.overflow ?? "wrap"}.`);
51
81
  }
52
82
  return [...merged.values()];
53
83
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@segnavia/format",
3
- "version": "0.22.0",
3
+ "version": "0.24.0",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "repository": {