@segnavia/format 0.23.0 → 0.25.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.
@@ -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, SlotSource, SlotState, SlotType, SlotValue, Slots, SlotsInput, SlotsOptions, mergeSlotDeclarations } from "./slots.js";
21
+ import { Fill, FillValues, SLOT_TYPES, SlotDeclaration, SlotDeclarationInput, SlotKey, 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>;
@@ -631,6 +634,8 @@ export declare function jsonSchemas(): {
631
634
  ltr: "ltr";
632
635
  rtl: "rtl";
633
636
  }>>;
637
+ marks: z.ZodDefault<z.ZodBoolean>;
638
+ cornerMarks: z.ZodDefault<z.ZodBoolean>;
634
639
  }, z.core.$strip>>;
635
640
  deck: z.core.ZodStandardJSONSchemaPayload<z.ZodObject<{
636
641
  title: z.ZodString;
@@ -1134,4 +1139,4 @@ export declare function jsonSchemas(): {
1134
1139
  }>>>;
1135
1140
  };
1136
1141
  //#endregion
1137
- 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, 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, 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, FillValues, 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, SlotKey, 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
@@ -1,12 +1,12 @@
1
1
  import { Direction, TextDirection, firstStrongDirection, languageDirection, resolveDirection } from "./direction.js";
2
2
  import { Scripts } from "./scripts.js";
3
- import { SLOT_TYPES, SlotDeclaration, SlotDeclarationInput, SlotType, Slots, SlotsInput, mergeSlotDeclarations } from "./slots.js";
3
+ import { FillValues, SLOT_TYPES, SlotDeclaration, SlotDeclarationInput, SlotKey, SlotType, SlotValue, Slots, SlotsInput, mergeSlotDeclarations } from "./slots.js";
4
4
  import { MAX_SLIDE_TIMING_MS } from "./timing.js";
5
5
  import { DEFAULT_TRANSITION_DURATION_MS, MAX_TRANSITION_DURATION_MS, MIN_TRANSITION_DURATION_MS, Transition } from "./transition.js";
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, FillValues, 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, SlotKey, SlotType, SlotValue, 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
@@ -10,6 +10,8 @@ export declare const SlotType: z.ZodEnum<{
10
10
  image: "image";
11
11
  }>;
12
12
  export type SlotType = z.infer<typeof SlotType>;
13
+ export declare const SlotKey: z.ZodString;
14
+ export type SlotKey = z.infer<typeof SlotKey>;
13
15
  export declare const SlotDeclaration: z.ZodPipe<z.ZodObject<{
14
16
  key: z.ZodString;
15
17
  label: z.ZodString;
@@ -164,13 +166,18 @@ export declare const SlotsInput: z.ZodArray<z.ZodPipe<z.ZodObject<{
164
166
  minSize?: number | undefined;
165
167
  }>>>;
166
168
  export type SlotsInput = z.input<typeof SlotsInput>;
167
- export type SlotValue = string | {
168
- asset: string;
169
- };
169
+ export declare const SlotValue: z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
170
+ asset: z.ZodString;
171
+ }, z.core.$strip>]>;
172
+ export type SlotValue = z.infer<typeof SlotValue>;
173
+ export declare const FillValues: z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
174
+ asset: z.ZodString;
175
+ }, z.core.$strip>]>>;
176
+ export type FillValues = z.infer<typeof FillValues>;
170
177
  export interface Fill {
171
178
  id: string;
172
179
  label?: string;
173
- values: Record<string, SlotValue>;
180
+ values: FillValues;
174
181
  }
175
182
  export interface SlotSource {
176
183
  id: string;
@@ -191,7 +198,7 @@ export interface SlotsOptions {
191
198
  source?: Fill;
192
199
  fill?: Fill;
193
200
  declarations?: SlotDeclarationInput[];
194
- /** Resolve an asset without network access. Hosts should honour the signal so timed-out renders stop this work promptly. */
201
+ /** Resolve an asset without network access. Hosts should honor the signal so timed-out renders stop this work promptly. */
195
202
  resolveAsset?: (ref: string, options: {
196
203
  signal: AbortSignal;
197
204
  }) => Promise<string>;
package/dist/slots.js CHANGED
@@ -9,8 +9,9 @@ const SLOT_TYPES = [
9
9
  "image"
10
10
  ];
11
11
  const SlotType = z.enum(SLOT_TYPES);
12
+ const SlotKey = z.string().regex(/^[^.\s]+(?:\.[^.\s]+)*$/, "a slot key must be a dotted path");
12
13
  const SlotDeclarationShape = {
13
- key: z.string().regex(/^[^.\s]+(?:\.[^.\s]+)*$/, "a slot key must be a dotted path"),
14
+ key: SlotKey,
14
15
  label: z.string().min(1),
15
16
  type: SlotType,
16
17
  required: z.boolean().default(false),
@@ -69,6 +70,8 @@ const SlotsInput = z.array(SlotDeclarationInput).superRefine((slots, ctx) => {
69
70
  seen.add(slot.key);
70
71
  });
71
72
  });
73
+ const SlotValue = z.union([z.string(), z.object({ asset: z.string() })]);
74
+ const FillValues = z.record(SlotKey, SlotValue);
72
75
  function mergeSlotDeclarations(...groups) {
73
76
  const merged = /* @__PURE__ */ new Map();
74
77
  for (const slot of groups.flat()) {
@@ -82,4 +85,4 @@ function mergeSlotDeclarations(...groups) {
82
85
  return [...merged.values()];
83
86
  }
84
87
  //#endregion
85
- export { SLOT_TYPES, SlotDeclaration, SlotDeclarationInput, SlotType, Slots, SlotsInput, mergeSlotDeclarations };
88
+ export { FillValues, SLOT_TYPES, SlotDeclaration, SlotDeclarationInput, SlotKey, SlotType, SlotValue, Slots, SlotsInput, mergeSlotDeclarations };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@segnavia/format",
3
- "version": "0.23.0",
3
+ "version": "0.25.0",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "repository": {