@magicpages/kalotyp-core 0.1.2 → 0.2.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.
- package/dist/index.d.ts +5 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +616 -342
- package/dist/index.js.map +1 -1
- package/dist/plugins/annotate/bake.d.ts +19 -6
- package/dist/plugins/annotate/bake.d.ts.map +1 -1
- package/dist/plugins/annotate/fonts.d.ts +55 -0
- package/dist/plugins/annotate/fonts.d.ts.map +1 -0
- package/dist/plugins/annotate/geometry.d.ts +5 -14
- package/dist/plugins/annotate/geometry.d.ts.map +1 -1
- package/dist/plugins/annotate/hit-test.d.ts.map +1 -1
- package/dist/plugins/annotate/state.d.ts +58 -7
- package/dist/plugins/annotate/state.d.ts.map +1 -1
- package/dist/plugins/annotate/text-layout.d.ts +40 -0
- package/dist/plugins/annotate/text-layout.d.ts.map +1 -0
- package/package.json +2 -2
|
@@ -4,13 +4,26 @@ export interface AnnotateBakeInput {
|
|
|
4
4
|
readonly shapes: ReadonlyArray<Shape>;
|
|
5
5
|
}
|
|
6
6
|
/**
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
7
|
+
* Resolve an emoji character to a drawable image (its vector artwork). Returns
|
|
8
|
+
* `null` when no image is available yet, so the caller falls back to the OS
|
|
9
|
+
* emoji font. Supplied by the UI layer, which owns the async image cache —
|
|
10
|
+
* keeping this module DOM-free (it just calls `drawImage` on whatever source it
|
|
11
|
+
* is handed).
|
|
10
12
|
*/
|
|
11
|
-
export
|
|
13
|
+
export type ResolveEmojiImage = (emoji: string) => CanvasImageSource | null;
|
|
14
|
+
export interface PaintShapeOptions {
|
|
15
|
+
readonly resolveEmojiImage?: ResolveEmojiImage;
|
|
16
|
+
}
|
|
17
|
+
/** Re-exported from fonts.ts; the system stack is the default font key's value. */
|
|
18
|
+
export { SYSTEM_FONT_STACK } from './fonts.js';
|
|
19
|
+
/**
|
|
20
|
+
* Ensure every font face used by the text shapes is loaded before bake, so the
|
|
21
|
+
* baked output matches the on-screen preview. Bounded by a timeout and a
|
|
22
|
+
* no-op where `document.fonts` is unavailable (jsdom / worker / OffscreenCanvas).
|
|
23
|
+
*/
|
|
24
|
+
export declare function awaitFontsForBake(shapes: ReadonlyArray<Shape>): Promise<void>;
|
|
12
25
|
/** Paint every shape onto a fresh canvas at the source's dimensions. */
|
|
13
|
-
export declare function bakeAnnotate(state: AnnotateBakeInput, source: SourceImage): Promise<SourceImage>;
|
|
26
|
+
export declare function bakeAnnotate(state: AnnotateBakeInput, source: SourceImage, opts?: PaintShapeOptions): Promise<SourceImage>;
|
|
14
27
|
/** Paint one shape; caller positions the context for image-space coordinates. Shared by preview and bake. */
|
|
15
|
-
export declare function paintShape(ctx: CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D, shape: Shape): void;
|
|
28
|
+
export declare function paintShape(ctx: CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D, shape: Shape, opts?: PaintShapeOptions): void;
|
|
16
29
|
//# sourceMappingURL=bake.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bake.d.ts","sourceRoot":"","sources":["../../../src/plugins/annotate/bake.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"bake.d.ts","sourceRoot":"","sources":["../../../src/plugins/annotate/bake.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAGjD,OAAO,EAAmC,KAAK,KAAK,EAAE,MAAM,YAAY,CAAC;AAGzE,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC,KAAK,CAAC,CAAC;CACvC;AAED;;;;;;GAMG;AACH,MAAM,MAAM,iBAAiB,GAAG,CAAC,KAAK,EAAE,MAAM,KAAK,iBAAiB,GAAG,IAAI,CAAC;AAE5E,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,iBAAiB,CAAC,EAAE,iBAAiB,CAAC;CAChD;AAED,mFAAmF;AACnF,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAS/C;;;;GAIG;AAGH,wBAAsB,iBAAiB,CAAC,MAAM,EAAE,aAAa,CAAC,KAAK,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAiBnF;AAED,wEAAwE;AACxE,wBAAsB,YAAY,CAChC,KAAK,EAAE,iBAAiB,EACxB,MAAM,EAAE,WAAW,EACnB,IAAI,CAAC,EAAE,iBAAiB,GACvB,OAAO,CAAC,WAAW,CAAC,CAsBtB;AAED,6GAA6G;AAC7G,wBAAgB,UAAU,CACxB,GAAG,EAAE,wBAAwB,GAAG,iCAAiC,EACjE,KAAK,EAAE,KAAK,EACZ,IAAI,CAAC,EAAE,iBAAiB,GACvB,IAAI,CA0BN"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Font catalogue for the text annotation tool. The set mirrors the fonts
|
|
3
|
+
* Ghost's own admin offers (loaded from fonts.bunny.net by Ghost's
|
|
4
|
+
* `admin-x-design-system`), so annotations can match a site's typography.
|
|
5
|
+
* The UI loads the same families from Bunny at runtime; this module is the
|
|
6
|
+
* single source for the CSS family stacks and the `font` shorthand used by
|
|
7
|
+
* the inline editor, the canvas preview, and the bake — keeping all three
|
|
8
|
+
* byte-identical (WYSIWYG).
|
|
9
|
+
*/
|
|
10
|
+
import type { TextShape } from './state.js';
|
|
11
|
+
/**
|
|
12
|
+
* System stack — the default, always available with no web font. Resolves to
|
|
13
|
+
* platform UI fonts.
|
|
14
|
+
*/
|
|
15
|
+
export declare const SYSTEM_FONT_STACK = "-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, sans-serif";
|
|
16
|
+
/**
|
|
17
|
+
* Colour-emoji stack for the emoji sticker tool. Emoji render with the
|
|
18
|
+
* platform's native colour-emoji font (no web font requested), so the baked
|
|
19
|
+
* appearance is whatever the editing browser drew. `sans-serif` is the last
|
|
20
|
+
* resort if no emoji font is installed (renders the dotted-box fallback).
|
|
21
|
+
*/
|
|
22
|
+
export declare const EMOJI_FONT_STACK = "\"Apple Color Emoji\", \"Segoe UI Emoji\", \"Noto Color Emoji\", \"Twemoji Mozilla\", \"Android Emoji\", sans-serif";
|
|
23
|
+
export interface FontDef {
|
|
24
|
+
/** Stable key stored on the shape; resolved to a CSS stack via `fontStackFor`. */
|
|
25
|
+
readonly key: string;
|
|
26
|
+
/** Human label shown in the picker. */
|
|
27
|
+
readonly label: string;
|
|
28
|
+
/** CSS font-family stack, including a generic fallback. */
|
|
29
|
+
readonly stack: string;
|
|
30
|
+
/**
|
|
31
|
+
* fonts.bunny.net family slug, or `null` for the system default (no web
|
|
32
|
+
* font to request). The UI builds one combined Bunny request from these.
|
|
33
|
+
*/
|
|
34
|
+
readonly bunnyName: string | null;
|
|
35
|
+
/** Generic CSS fallback class, used to build the stack and as a hint. */
|
|
36
|
+
readonly generic: 'sans-serif' | 'serif' | 'monospace';
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* The catalogue. The first entry (`system`) is the default. The rest mirror
|
|
40
|
+
* Ghost's curated Bunny set; their family names match Bunny's font CSS so the
|
|
41
|
+
* loaded `@font-face` families resolve.
|
|
42
|
+
*/
|
|
43
|
+
export declare const TEXT_FONTS: readonly FontDef[];
|
|
44
|
+
/** Resolve a font key to its CSS family stack, falling back to the system stack. */
|
|
45
|
+
export declare function fontStackFor(key: string): string;
|
|
46
|
+
/** Look up a font definition by key, or the default if unknown. */
|
|
47
|
+
export declare function fontDefFor(key: string): FontDef;
|
|
48
|
+
/**
|
|
49
|
+
* Build the CSS `font` shorthand for a text shape:
|
|
50
|
+
* `"<style> <weight> <fontSize>px <stack>"`. The single source consumed by
|
|
51
|
+
* the inline editor, canvas preview, bake, and `document.fonts.load`.
|
|
52
|
+
* `scale` lets the editor render at the on-screen (zoomed) size.
|
|
53
|
+
*/
|
|
54
|
+
export declare function cssFontString(shape: TextShape, scale?: number): string;
|
|
55
|
+
//# sourceMappingURL=fonts.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fonts.d.ts","sourceRoot":"","sources":["../../../src/plugins/annotate/fonts.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAE5C;;;GAGG;AACH,eAAO,MAAM,iBAAiB,mGACgE,CAAC;AAE/F;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,wHACgF,CAAC;AAE9G,MAAM,WAAW,OAAO;IACtB,kFAAkF;IAClF,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,uCAAuC;IACvC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,2DAA2D;IAC3D,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB;;;OAGG;IACH,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,yEAAyE;IACzE,QAAQ,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,GAAG,WAAW,CAAC;CACxD;AAED;;;;GAIG;AACH,eAAO,MAAM,UAAU,EAAE,SAAS,OAAO,EAyIxC,CAAC;AAIF,oFAAoF;AACpF,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAEhD;AAED,mEAAmE;AACnE,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAE/C;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,SAAS,EAAE,KAAK,SAAI,GAAG,MAAM,CAKjE"}
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import type { Rect } from '../../geometry/rect.js';
|
|
2
2
|
import { type Shape } from './state.js';
|
|
3
3
|
/**
|
|
4
|
-
* Axis-aligned bounding box in image-space pixels.
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* Axis-aligned bounding box in image-space pixels. `shape.x, shape.y` is the
|
|
5
|
+
* text block's top-left for every `textAlign` (alignment justifies lines within
|
|
6
|
+
* the block, it doesn't move the origin), so the box origin is the anchor. A
|
|
7
|
+
* font-metric estimate is used here (jsdom's `measureText` returns 0); the
|
|
8
|
+
* renderer measures real text at paint time.
|
|
7
9
|
*/
|
|
8
10
|
export declare function boundingBoxOf(shape: Shape): Rect;
|
|
9
11
|
/**
|
|
@@ -22,15 +24,4 @@ export declare function rectFromHandleDrag(initial: Rect, handle: SelectionHandl
|
|
|
22
24
|
x: number;
|
|
23
25
|
y: number;
|
|
24
26
|
}): Rect;
|
|
25
|
-
/**
|
|
26
|
-
* Estimate painted text size without `measureText` (jsdom returns 0).
|
|
27
|
-
* Uses 0.55em mean Latin char width and 1.2em line height — close enough
|
|
28
|
-
* for selection-handle placement.
|
|
29
|
-
*/
|
|
30
|
-
export declare function estimateTextSize(text: string, fontSize: number): {
|
|
31
|
-
width: number;
|
|
32
|
-
height: number;
|
|
33
|
-
};
|
|
34
|
-
/** Convert a text shape's anchor to the bounding box's top-left given `textAlign`. */
|
|
35
|
-
export declare function alignToOrigin(anchorX: number, width: number, align: 'left' | 'center' | 'right'): number;
|
|
36
27
|
//# sourceMappingURL=geometry.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"geometry.d.ts","sourceRoot":"","sources":["../../../src/plugins/annotate/geometry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,wBAAwB,CAAC;AACnD,OAAO,
|
|
1
|
+
{"version":3,"file":"geometry.d.ts","sourceRoot":"","sources":["../../../src/plugins/annotate/geometry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,wBAAwB,CAAC;AACnD,OAAO,EAAmC,KAAK,KAAK,EAAE,MAAM,YAAY,CAAC;AAGzE;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI,CA2ChD;AAED;;;GAGG;AACH,MAAM,MAAM,eAAe,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC;AAEhF,eAAO,MAAM,qBAAqB,EAAE,SAAS,eAAe,EAS3D,CAAC;AAEF,6EAA6E;AAC7E,wBAAgB,wBAAwB,CACtC,IAAI,EAAE,IAAI,GACT,MAAM,CAAC,eAAe,EAAE;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAiBnD;AAED,kFAAkF;AAClF,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,IAAI,EACb,MAAM,EAAE,eAAe,EACvB,OAAO,EAAE;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,GAChC,IAAI,CAYN"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hit-test.d.ts","sourceRoot":"","sources":["../../../src/plugins/annotate/hit-test.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,wBAAwB,CAAC;AAEpD,OAAO,EAAe,KAAK,KAAK,EAAE,MAAM,YAAY,CAAC;AAErD,mFAAmF;AACnF,eAAO,MAAM,cAAc,IAAI,CAAC;AAEhC,kFAAkF;AAClF,wBAAgB,SAAS,CAAC,MAAM,EAAE,aAAa,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,KAAK,GAAG,KAAK,GAAG,SAAS,CAMvF;AAED,wBAAgB,OAAO,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,GAAG,OAAO,
|
|
1
|
+
{"version":3,"file":"hit-test.d.ts","sourceRoot":"","sources":["../../../src/plugins/annotate/hit-test.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,wBAAwB,CAAC;AAEpD,OAAO,EAAe,KAAK,KAAK,EAAE,MAAM,YAAY,CAAC;AAErD,mFAAmF;AACnF,eAAO,MAAM,cAAc,IAAI,CAAC;AAEhC,kFAAkF;AAClF,wBAAgB,SAAS,CAAC,MAAM,EAAE,aAAa,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,KAAK,GAAG,KAAK,GAAG,SAAS,CAMvF;AAED,wBAAgB,OAAO,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,GAAG,OAAO,CA0E3D"}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* union keyed on `kind`; all coordinates are image-space pixels.
|
|
4
4
|
*/
|
|
5
5
|
import type { Point } from '../../geometry/rect.js';
|
|
6
|
-
export type ShapeKind = 'text' | 'rect' | 'ellipse' | 'arrow' | 'freehand' | 'highlight';
|
|
6
|
+
export type ShapeKind = 'text' | 'rect' | 'ellipse' | 'arrow' | 'freehand' | 'highlight' | 'emoji';
|
|
7
7
|
/** Tools the annotation plugin exposes. `select` is the picker. */
|
|
8
8
|
export type AnnotateTool = ShapeKind | 'select';
|
|
9
9
|
interface ShapeBase {
|
|
@@ -11,17 +11,25 @@ interface ShapeBase {
|
|
|
11
11
|
readonly id: string;
|
|
12
12
|
readonly kind: ShapeKind;
|
|
13
13
|
}
|
|
14
|
+
export type TextFontWeight = 'normal' | 'bold';
|
|
15
|
+
export type TextFontStyle = 'normal' | 'italic';
|
|
16
|
+
export type TextAlign = 'left' | 'center' | 'right';
|
|
14
17
|
export interface TextShape extends ShapeBase {
|
|
15
18
|
readonly kind: 'text';
|
|
16
19
|
/** Top-left anchor in image-space pixels. */
|
|
17
20
|
readonly x: number;
|
|
18
21
|
readonly y: number;
|
|
19
22
|
readonly text: string;
|
|
20
|
-
/** Font size in image-space pixels. */
|
|
23
|
+
/** Font size in image-space pixels. Changed via the panel, not by handles. */
|
|
21
24
|
readonly fontSize: number;
|
|
22
25
|
/** CSS colour string. */
|
|
23
26
|
readonly color: string;
|
|
24
|
-
|
|
27
|
+
/** Glyph justification (multi-line text aligns relative to the anchor). */
|
|
28
|
+
readonly textAlign: TextAlign;
|
|
29
|
+
/** Font key from the font catalogue (see fonts.ts), e.g. `'system'`, `'inter'`. */
|
|
30
|
+
readonly fontFamily: string;
|
|
31
|
+
readonly fontWeight: TextFontWeight;
|
|
32
|
+
readonly fontStyle: TextFontStyle;
|
|
25
33
|
}
|
|
26
34
|
export interface RectShape extends ShapeBase {
|
|
27
35
|
readonly kind: 'rect';
|
|
@@ -70,7 +78,19 @@ export interface HighlightShape extends ShapeBase {
|
|
|
70
78
|
readonly color: string;
|
|
71
79
|
readonly strokeWidth: number;
|
|
72
80
|
}
|
|
73
|
-
export
|
|
81
|
+
export interface EmojiShape extends ShapeBase {
|
|
82
|
+
readonly kind: 'emoji';
|
|
83
|
+
/** Top-left of the (square) sticker box, in image-space pixels. */
|
|
84
|
+
readonly x: number;
|
|
85
|
+
readonly y: number;
|
|
86
|
+
/** The emoji character; resolved to vector artwork at paint time. */
|
|
87
|
+
readonly emoji: string;
|
|
88
|
+
/** Box edge length in image-space pixels; the glyph is drawn at this size. */
|
|
89
|
+
readonly size: number;
|
|
90
|
+
/** Clockwise rotation in degrees about the box centre (0 = upright). */
|
|
91
|
+
readonly rotation: number;
|
|
92
|
+
}
|
|
93
|
+
export type Shape = TextShape | RectShape | EllipseShape | ArrowShape | FreehandShape | HighlightShape | EmojiShape;
|
|
74
94
|
export interface StylePalette {
|
|
75
95
|
readonly color: string;
|
|
76
96
|
readonly strokeWidth: number;
|
|
@@ -78,6 +98,13 @@ export interface StylePalette {
|
|
|
78
98
|
readonly fillColor: string | null;
|
|
79
99
|
/** Used for new text shapes. In image-space pixels. */
|
|
80
100
|
readonly fontSize: number;
|
|
101
|
+
/** Font key for new text shapes (see fonts.ts). */
|
|
102
|
+
readonly fontFamily: string;
|
|
103
|
+
readonly fontWeight: TextFontWeight;
|
|
104
|
+
readonly fontStyle: TextFontStyle;
|
|
105
|
+
readonly textAlign: TextAlign;
|
|
106
|
+
/** The armed emoji for new emoji stickers (see fonts: native OS emoji). */
|
|
107
|
+
readonly emoji: string;
|
|
81
108
|
}
|
|
82
109
|
export interface AnnotateState {
|
|
83
110
|
readonly shapes: ReadonlyArray<Shape>;
|
|
@@ -99,7 +126,31 @@ export declare const FREEHAND_DEFAULT_STROKE = 6;
|
|
|
99
126
|
export declare const TEXT_DEFAULT_FONT_SIZE = 32;
|
|
100
127
|
export declare const DEFAULT_PALETTE_COLOR = "#ff3b30";
|
|
101
128
|
export declare const DEFAULT_STROKE_WIDTH = 4;
|
|
129
|
+
/** Default font key for new text shapes; resolves to the system stack. */
|
|
130
|
+
export declare const DEFAULT_FONT_KEY = "system";
|
|
131
|
+
/** The emoji a fresh editor session arms for the emoji sticker tool. */
|
|
132
|
+
export declare const DEFAULT_EMOJI = "\uD83D\uDE00";
|
|
133
|
+
/** Smallest emoji sticker edge in image-space pixels (floor for handle resize). */
|
|
134
|
+
export declare const EMOJI_MIN_SIZE = 8;
|
|
135
|
+
/**
|
|
136
|
+
* Default edge length for a freshly placed emoji sticker, scaled to the image
|
|
137
|
+
* so a sticker reads at a sensible size on both tiny and huge sources. Shared by
|
|
138
|
+
* click-placement and centre-insert so the two paths agree.
|
|
139
|
+
*/
|
|
140
|
+
export declare function defaultEmojiSize(imageSize: {
|
|
141
|
+
readonly width: number;
|
|
142
|
+
readonly height: number;
|
|
143
|
+
}): number;
|
|
144
|
+
/** Wrap an angle in degrees into the [0, 360) range. */
|
|
145
|
+
export declare function normalizeAngle(degrees: number): number;
|
|
102
146
|
export declare function defaultStylePalette(): StylePalette;
|
|
147
|
+
/**
|
|
148
|
+
* Fill any missing font fields on a text shape with defaults. Defensive
|
|
149
|
+
* against partial literals (tests) and stale undo snapshots from a prior dev
|
|
150
|
+
* build during hot reload — shapes are never persisted, so this is a safety
|
|
151
|
+
* net, not a schema migration.
|
|
152
|
+
*/
|
|
153
|
+
export declare function normalizeTextShape(shape: TextShape): TextShape;
|
|
103
154
|
export interface InitialAnnotateStateInput {
|
|
104
155
|
readonly imageSize: {
|
|
105
156
|
readonly width: number;
|
|
@@ -158,7 +209,7 @@ export declare function transformShapes(state: AnnotateState, transformer: (shap
|
|
|
158
209
|
* Kinds placeable from the keyboard. Freehand / highlight are excluded;
|
|
159
210
|
* a "default at centre" instance has no honest shape for those.
|
|
160
211
|
*/
|
|
161
|
-
export type KeyboardPlaceableKind = 'text' | 'rect' | 'ellipse' | 'arrow';
|
|
212
|
+
export type KeyboardPlaceableKind = 'text' | 'rect' | 'ellipse' | 'arrow' | 'emoji';
|
|
162
213
|
export declare const KEYBOARD_PLACEABLE_KINDS: ReadonlyArray<KeyboardPlaceableKind>;
|
|
163
214
|
export declare function isKeyboardPlaceableKind(kind: ShapeKind): kind is KeyboardPlaceableKind;
|
|
164
215
|
export interface CreateCenteredShapeContext {
|
|
@@ -169,8 +220,8 @@ export interface CreateCenteredShapeContext {
|
|
|
169
220
|
readonly style: StylePalette;
|
|
170
221
|
readonly id: string;
|
|
171
222
|
}
|
|
172
|
-
/** A `Shape` whose kind is keyboard-placeable (rect / ellipse / arrow / text). */
|
|
173
|
-
export type KeyboardPlaceableShape = TextShape | RectShape | EllipseShape | ArrowShape;
|
|
223
|
+
/** A `Shape` whose kind is keyboard-placeable (rect / ellipse / arrow / text / emoji). */
|
|
224
|
+
export type KeyboardPlaceableShape = TextShape | RectShape | EllipseShape | ArrowShape | EmojiShape;
|
|
174
225
|
export declare function createCenteredShape(kind: KeyboardPlaceableKind, ctx: CreateCenteredShapeContext): KeyboardPlaceableShape;
|
|
175
226
|
export {};
|
|
176
227
|
//# sourceMappingURL=state.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../../src/plugins/annotate/state.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,wBAAwB,CAAC;AAEpD,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG,MAAM,GAAG,SAAS,GAAG,OAAO,GAAG,UAAU,GAAG,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../../src/plugins/annotate/state.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Text measurement for the text annotation tool. Pure and framework-agnostic
|
|
3
|
+
* so the live canvas preview, the bake, and the geometry (selection outline /
|
|
4
|
+
* hit-test) all share one notion of a text shape's extent.
|
|
5
|
+
*
|
|
6
|
+
* Text is anchor-based and does NOT wrap: lines are split on explicit `\n`
|
|
7
|
+
* only, and the shape's width is its widest line. The line-measuring function
|
|
8
|
+
* is injected so the same code works with real canvas metrics (browser
|
|
9
|
+
* preview + bake) and with a heuristic estimate in headless/jsdom contexts
|
|
10
|
+
* where `measureText` returns 0.
|
|
11
|
+
*/
|
|
12
|
+
import type { TextShape } from './state.js';
|
|
13
|
+
/** Line-height multiple of the font size. Shared by layout and bake. */
|
|
14
|
+
export declare const TEXT_LINE_HEIGHT = 1.2;
|
|
15
|
+
/** Measures the rendered width of a single line of text, in image-space px. */
|
|
16
|
+
export type MeasureLine = (line: string) => number;
|
|
17
|
+
/** Split text into rendered lines. Empty text yields one empty line (caret height). */
|
|
18
|
+
export declare function textLines(text: string): string[];
|
|
19
|
+
export interface TextLayout {
|
|
20
|
+
readonly lines: string[];
|
|
21
|
+
readonly width: number;
|
|
22
|
+
readonly height: number;
|
|
23
|
+
}
|
|
24
|
+
/** Measure a text shape's natural extent: widest line × line count. */
|
|
25
|
+
export declare function layoutTextLines(shape: TextShape, measure: MeasureLine): TextLayout;
|
|
26
|
+
/**
|
|
27
|
+
* Heuristic line-width estimate for headless contexts where canvas
|
|
28
|
+
* `measureText` returns 0. Assumes ~0.55em mean Latin glyph advance — close
|
|
29
|
+
* enough for the selection outline; the real renderer measures at paint time.
|
|
30
|
+
*/
|
|
31
|
+
export declare function estimateLineWidth(line: string, fontSize: number): number;
|
|
32
|
+
/**
|
|
33
|
+
* Horizontal offset of a line within a left-origin text block, given the
|
|
34
|
+
* block's width (widest line) and this line's width. `textAlign` justifies the
|
|
35
|
+
* line *within* the block — it never moves the block's origin. Shared by the
|
|
36
|
+
* canvas paint and (conceptually) the editor's CSS `text-align`, so both place
|
|
37
|
+
* glyphs identically.
|
|
38
|
+
*/
|
|
39
|
+
export declare function lineOffset(blockWidth: number, lineWidth: number, align: 'left' | 'center' | 'right'): number;
|
|
40
|
+
//# sourceMappingURL=text-layout.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"text-layout.d.ts","sourceRoot":"","sources":["../../../src/plugins/annotate/text-layout.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAE5C,wEAAwE;AACxE,eAAO,MAAM,gBAAgB,MAAM,CAAC;AAEpC,+EAA+E;AAC/E,MAAM,MAAM,WAAW,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;AAEnD,uFAAuF;AACvF,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAEhD;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,uEAAuE;AACvE,wBAAgB,eAAe,CAAC,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,WAAW,GAAG,UAAU,CAclF;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAExE;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CACxB,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,GAAG,QAAQ,GAAG,OAAO,GACjC,MAAM,CASR"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@magicpages/kalotyp-core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Framework-agnostic editor engine for Kalotyp — an open-source image editor for Ghost CMS.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Jannis Fedoruk-Betschki <jannis@magicpages.co>",
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
"access": "public"
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|
|
38
|
-
"@types/node": "^
|
|
38
|
+
"@types/node": "^25.9.3",
|
|
39
39
|
"typescript": "6.0.3",
|
|
40
40
|
"vite": "8.0.16",
|
|
41
41
|
"vite-plugin-dts": "5.0.2",
|