@aznabee/freehand-ui 0.1.1 → 0.1.2
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/README.md +43 -3
- package/dist/freehand-ui.cjs +47 -6
- package/dist/freehand-ui.js +47 -6
- package/dist/index.d.ts +13 -0
- package/dist/react.cjs +56 -7
- package/dist/react.js +56 -7
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -84,6 +84,8 @@ function Card() {
|
|
|
84
84
|
|
|
85
85
|
- Inline object props (`note={{ text: "hi" }}`) are compared by value, so a
|
|
86
86
|
re-render does not tear down and redraw the overlay with a new random seed.
|
|
87
|
+
- The handwriting font is fetched automatically — see [Handwriting
|
|
88
|
+
font](#handwriting-font) to use `next/font` or self-host instead.
|
|
87
89
|
- `disabled` skips drawing entirely — useful behind a reduced-motion check or a
|
|
88
90
|
feature flag.
|
|
89
91
|
- TypeScript definitions ship with the package for both entry points.
|
|
@@ -96,13 +98,51 @@ doodle(".card", {
|
|
|
96
98
|
color: "#ffffff",
|
|
97
99
|
strokeWidth: 1.5,
|
|
98
100
|
roughness: 1.5,
|
|
99
|
-
padding:
|
|
100
|
-
radius: 20,
|
|
101
|
+
padding: 0, // gap between the element's edge and the frame
|
|
102
|
+
radius: 20, // optional override; auto-detected from CSS when omitted
|
|
101
103
|
opacity: 0.9,
|
|
102
|
-
addBreaks: false,
|
|
104
|
+
addBreaks: false, // lift the pen at random points around the outline
|
|
105
|
+
fontFamily: null, // override the handwriting stack
|
|
106
|
+
autoLoadFont: true,
|
|
103
107
|
});
|
|
104
108
|
```
|
|
105
109
|
|
|
110
|
+
The frame traces the element's own edge by default. Raise `padding` to stand it
|
|
111
|
+
off — `padding: 8` leaves a comfortable margin around a card.
|
|
112
|
+
|
|
113
|
+
## Handwriting font
|
|
114
|
+
|
|
115
|
+
Notes are set in [Caveat](https://fonts.google.com/specimen/Caveat). The library
|
|
116
|
+
loads it for you the first time a note is drawn, so the handwriting looks right
|
|
117
|
+
in a plain app with no font setup of its own — without it the text falls back to
|
|
118
|
+
the generic `cursive` family, which on macOS is a calligraphic serif rather than
|
|
119
|
+
anything handwritten.
|
|
120
|
+
|
|
121
|
+
It skips the request when the page already provides the family, and only ever
|
|
122
|
+
requests it once. To take over:
|
|
123
|
+
|
|
124
|
+
```javascript
|
|
125
|
+
// self-hosted, or already loaded elsewhere on the page
|
|
126
|
+
doodle(".card", { note: "hi", autoLoadFont: false });
|
|
127
|
+
|
|
128
|
+
// your own family — a next/font CSS variable, for instance
|
|
129
|
+
doodle(".card", { note: "hi", fontFamily: "var(--font-caveat)" });
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
```jsx
|
|
133
|
+
import { Caveat } from "next/font/google";
|
|
134
|
+
const caveat = Caveat({ subsets: ["latin"], variable: "--font-caveat" });
|
|
135
|
+
|
|
136
|
+
<Doodle note="start chat" fontFamily="var(--font-caveat)" autoLoadFont={false}>
|
|
137
|
+
<Button />
|
|
138
|
+
</Doodle>;
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
Setting `autoLoadFont: false` without a `fontFamily` falls back to whatever
|
|
142
|
+
handwriting faces the system has (Bradley Hand, Segoe Script, Comic Sans MS).
|
|
143
|
+
Notes are re-measured when a font finishes loading, so the underline always
|
|
144
|
+
matches the final glyph widths.
|
|
145
|
+
|
|
106
146
|
## Broken outlines
|
|
107
147
|
|
|
108
148
|
`addBreaks` cuts randomly sized gaps into the border, so it reads as a few
|
package/dist/freehand-ui.cjs
CHANGED
|
@@ -29,14 +29,19 @@ var DEFAULT_OPTIONS = {
|
|
|
29
29
|
color: "#ffffff",
|
|
30
30
|
strokeWidth: 1.5,
|
|
31
31
|
roughness: 1.5,
|
|
32
|
-
|
|
32
|
+
// The frame traces the element's own edge. Raise this to stand it off.
|
|
33
|
+
padding: 0,
|
|
33
34
|
radius: null,
|
|
34
35
|
opacity: 0.9,
|
|
35
36
|
children: null,
|
|
36
37
|
note: null,
|
|
37
38
|
arrow: false,
|
|
38
39
|
decorations: false,
|
|
39
|
-
addBreaks: false
|
|
40
|
+
addBreaks: false,
|
|
41
|
+
/** Override the handwriting stack, e.g. a next/font CSS variable. */
|
|
42
|
+
fontFamily: null,
|
|
43
|
+
/** Fetch Caveat when the page has not provided it. */
|
|
44
|
+
autoLoadFont: true
|
|
40
45
|
};
|
|
41
46
|
function resolveElement(target) {
|
|
42
47
|
if (!target) return null;
|
|
@@ -262,7 +267,7 @@ function annotationAnchor(position, rect, offset = 12) {
|
|
|
262
267
|
|
|
263
268
|
// src/renderer.js
|
|
264
269
|
var SVG_NS = "http://www.w3.org/2000/svg";
|
|
265
|
-
var HANDWRITTEN_FONT = '"Caveat", "Kalam", "Patrick Hand", cursive';
|
|
270
|
+
var HANDWRITTEN_FONT = '"Caveat", "Kalam", "Patrick Hand", "Bradley Hand", "Segoe Script", "Comic Sans MS", cursive';
|
|
266
271
|
var NOTE_FONT_SIZE = 19;
|
|
267
272
|
function clearSvg(svg) {
|
|
268
273
|
while (svg.firstChild) {
|
|
@@ -741,7 +746,7 @@ function createNoteText(svg, text, style) {
|
|
|
741
746
|
textEl.setAttribute("fill", style.color);
|
|
742
747
|
textEl.setAttribute("opacity", String(style.opacity));
|
|
743
748
|
textEl.setAttribute("font-size", String(fontSize));
|
|
744
|
-
textEl.setAttribute("font-family", HANDWRITTEN_FONT);
|
|
749
|
+
textEl.setAttribute("font-family", style.fontFamily || HANDWRITTEN_FONT);
|
|
745
750
|
textEl.setAttribute("font-weight", "600");
|
|
746
751
|
textEl.setAttribute("letter-spacing", "0.4");
|
|
747
752
|
textEl.setAttribute("text-anchor", "start");
|
|
@@ -1314,6 +1319,27 @@ function renderDecorations(svg, rect, decorationOptions, style, seed, context =
|
|
|
1314
1319
|
}
|
|
1315
1320
|
}
|
|
1316
1321
|
|
|
1322
|
+
// src/fonts.js
|
|
1323
|
+
var FONT_NAME = "Caveat";
|
|
1324
|
+
var FONT_HREF = "https://fonts.googleapis.com/css2?family=Caveat:wght@400;600&display=swap";
|
|
1325
|
+
var MARKER = "data-freehand-font";
|
|
1326
|
+
var requested = false;
|
|
1327
|
+
function ensureHandwrittenFont() {
|
|
1328
|
+
if (requested) return;
|
|
1329
|
+
if (typeof document === "undefined" || !document.head) return;
|
|
1330
|
+
requested = true;
|
|
1331
|
+
try {
|
|
1332
|
+
if (document.fonts?.check?.(`600 19px "${FONT_NAME}"`)) return;
|
|
1333
|
+
} catch {
|
|
1334
|
+
}
|
|
1335
|
+
if (document.querySelector(`link[${MARKER}]`)) return;
|
|
1336
|
+
const link = document.createElement("link");
|
|
1337
|
+
link.rel = "stylesheet";
|
|
1338
|
+
link.href = FONT_HREF;
|
|
1339
|
+
link.setAttribute(MARKER, "");
|
|
1340
|
+
document.head.appendChild(link);
|
|
1341
|
+
}
|
|
1342
|
+
|
|
1317
1343
|
// src/doodle.js
|
|
1318
1344
|
var instances = /* @__PURE__ */ new WeakMap();
|
|
1319
1345
|
function localViewport(overlayRect, inset = 8) {
|
|
@@ -1365,7 +1391,12 @@ var DoodleOverlay = class {
|
|
|
1365
1391
|
}
|
|
1366
1392
|
window.addEventListener("resize", this.onResize, { passive: true });
|
|
1367
1393
|
this.scrollTargets.push({ target: window, type: "resize" });
|
|
1368
|
-
|
|
1394
|
+
if (this.options.note && this.options.autoLoadFont && !this.options.fontFamily) {
|
|
1395
|
+
ensureHandwrittenFont();
|
|
1396
|
+
}
|
|
1397
|
+
this.onFontsLoaded = () => this.scheduleUpdate();
|
|
1398
|
+
document.fonts?.addEventListener?.("loadingdone", this.onFontsLoaded);
|
|
1399
|
+
document.fonts?.ready?.then(this.onFontsLoaded).catch(() => {
|
|
1369
1400
|
});
|
|
1370
1401
|
this.update();
|
|
1371
1402
|
}
|
|
@@ -1408,7 +1439,13 @@ var DoodleOverlay = class {
|
|
|
1408
1439
|
this.svg.style.width = `${overlayRect.width}px`;
|
|
1409
1440
|
this.svg.style.height = `${overlayRect.height}px`;
|
|
1410
1441
|
const strokeStyle = { color, strokeWidth, roughness, opacity };
|
|
1411
|
-
const noteStyle = {
|
|
1442
|
+
const noteStyle = {
|
|
1443
|
+
color,
|
|
1444
|
+
opacity,
|
|
1445
|
+
strokeWidth,
|
|
1446
|
+
roughness,
|
|
1447
|
+
fontFamily: this.options.fontFamily
|
|
1448
|
+
};
|
|
1412
1449
|
const noteGroups = [];
|
|
1413
1450
|
const noteLayout = {
|
|
1414
1451
|
viewport: localViewport(overlayRect),
|
|
@@ -1483,6 +1520,10 @@ var DoodleOverlay = class {
|
|
|
1483
1520
|
this.mutationObserver.disconnect();
|
|
1484
1521
|
this.mutationObserver = null;
|
|
1485
1522
|
}
|
|
1523
|
+
if (this.onFontsLoaded) {
|
|
1524
|
+
document.fonts?.removeEventListener?.("loadingdone", this.onFontsLoaded);
|
|
1525
|
+
this.onFontsLoaded = null;
|
|
1526
|
+
}
|
|
1486
1527
|
for (const { target, type } of this.scrollTargets) {
|
|
1487
1528
|
target.removeEventListener(type, type === "scroll" ? this.onScroll : this.onResize);
|
|
1488
1529
|
}
|
package/dist/freehand-ui.js
CHANGED
|
@@ -4,14 +4,19 @@ var DEFAULT_OPTIONS = {
|
|
|
4
4
|
color: "#ffffff",
|
|
5
5
|
strokeWidth: 1.5,
|
|
6
6
|
roughness: 1.5,
|
|
7
|
-
|
|
7
|
+
// The frame traces the element's own edge. Raise this to stand it off.
|
|
8
|
+
padding: 0,
|
|
8
9
|
radius: null,
|
|
9
10
|
opacity: 0.9,
|
|
10
11
|
children: null,
|
|
11
12
|
note: null,
|
|
12
13
|
arrow: false,
|
|
13
14
|
decorations: false,
|
|
14
|
-
addBreaks: false
|
|
15
|
+
addBreaks: false,
|
|
16
|
+
/** Override the handwriting stack, e.g. a next/font CSS variable. */
|
|
17
|
+
fontFamily: null,
|
|
18
|
+
/** Fetch Caveat when the page has not provided it. */
|
|
19
|
+
autoLoadFont: true
|
|
15
20
|
};
|
|
16
21
|
function resolveElement(target) {
|
|
17
22
|
if (!target) return null;
|
|
@@ -237,7 +242,7 @@ function annotationAnchor(position, rect, offset = 12) {
|
|
|
237
242
|
|
|
238
243
|
// src/renderer.js
|
|
239
244
|
var SVG_NS = "http://www.w3.org/2000/svg";
|
|
240
|
-
var HANDWRITTEN_FONT = '"Caveat", "Kalam", "Patrick Hand", cursive';
|
|
245
|
+
var HANDWRITTEN_FONT = '"Caveat", "Kalam", "Patrick Hand", "Bradley Hand", "Segoe Script", "Comic Sans MS", cursive';
|
|
241
246
|
var NOTE_FONT_SIZE = 19;
|
|
242
247
|
function clearSvg(svg) {
|
|
243
248
|
while (svg.firstChild) {
|
|
@@ -716,7 +721,7 @@ function createNoteText(svg, text, style) {
|
|
|
716
721
|
textEl.setAttribute("fill", style.color);
|
|
717
722
|
textEl.setAttribute("opacity", String(style.opacity));
|
|
718
723
|
textEl.setAttribute("font-size", String(fontSize));
|
|
719
|
-
textEl.setAttribute("font-family", HANDWRITTEN_FONT);
|
|
724
|
+
textEl.setAttribute("font-family", style.fontFamily || HANDWRITTEN_FONT);
|
|
720
725
|
textEl.setAttribute("font-weight", "600");
|
|
721
726
|
textEl.setAttribute("letter-spacing", "0.4");
|
|
722
727
|
textEl.setAttribute("text-anchor", "start");
|
|
@@ -1289,6 +1294,27 @@ function renderDecorations(svg, rect, decorationOptions, style, seed, context =
|
|
|
1289
1294
|
}
|
|
1290
1295
|
}
|
|
1291
1296
|
|
|
1297
|
+
// src/fonts.js
|
|
1298
|
+
var FONT_NAME = "Caveat";
|
|
1299
|
+
var FONT_HREF = "https://fonts.googleapis.com/css2?family=Caveat:wght@400;600&display=swap";
|
|
1300
|
+
var MARKER = "data-freehand-font";
|
|
1301
|
+
var requested = false;
|
|
1302
|
+
function ensureHandwrittenFont() {
|
|
1303
|
+
if (requested) return;
|
|
1304
|
+
if (typeof document === "undefined" || !document.head) return;
|
|
1305
|
+
requested = true;
|
|
1306
|
+
try {
|
|
1307
|
+
if (document.fonts?.check?.(`600 19px "${FONT_NAME}"`)) return;
|
|
1308
|
+
} catch {
|
|
1309
|
+
}
|
|
1310
|
+
if (document.querySelector(`link[${MARKER}]`)) return;
|
|
1311
|
+
const link = document.createElement("link");
|
|
1312
|
+
link.rel = "stylesheet";
|
|
1313
|
+
link.href = FONT_HREF;
|
|
1314
|
+
link.setAttribute(MARKER, "");
|
|
1315
|
+
document.head.appendChild(link);
|
|
1316
|
+
}
|
|
1317
|
+
|
|
1292
1318
|
// src/doodle.js
|
|
1293
1319
|
var instances = /* @__PURE__ */ new WeakMap();
|
|
1294
1320
|
function localViewport(overlayRect, inset = 8) {
|
|
@@ -1340,7 +1366,12 @@ var DoodleOverlay = class {
|
|
|
1340
1366
|
}
|
|
1341
1367
|
window.addEventListener("resize", this.onResize, { passive: true });
|
|
1342
1368
|
this.scrollTargets.push({ target: window, type: "resize" });
|
|
1343
|
-
|
|
1369
|
+
if (this.options.note && this.options.autoLoadFont && !this.options.fontFamily) {
|
|
1370
|
+
ensureHandwrittenFont();
|
|
1371
|
+
}
|
|
1372
|
+
this.onFontsLoaded = () => this.scheduleUpdate();
|
|
1373
|
+
document.fonts?.addEventListener?.("loadingdone", this.onFontsLoaded);
|
|
1374
|
+
document.fonts?.ready?.then(this.onFontsLoaded).catch(() => {
|
|
1344
1375
|
});
|
|
1345
1376
|
this.update();
|
|
1346
1377
|
}
|
|
@@ -1383,7 +1414,13 @@ var DoodleOverlay = class {
|
|
|
1383
1414
|
this.svg.style.width = `${overlayRect.width}px`;
|
|
1384
1415
|
this.svg.style.height = `${overlayRect.height}px`;
|
|
1385
1416
|
const strokeStyle = { color, strokeWidth, roughness, opacity };
|
|
1386
|
-
const noteStyle = {
|
|
1417
|
+
const noteStyle = {
|
|
1418
|
+
color,
|
|
1419
|
+
opacity,
|
|
1420
|
+
strokeWidth,
|
|
1421
|
+
roughness,
|
|
1422
|
+
fontFamily: this.options.fontFamily
|
|
1423
|
+
};
|
|
1387
1424
|
const noteGroups = [];
|
|
1388
1425
|
const noteLayout = {
|
|
1389
1426
|
viewport: localViewport(overlayRect),
|
|
@@ -1458,6 +1495,10 @@ var DoodleOverlay = class {
|
|
|
1458
1495
|
this.mutationObserver.disconnect();
|
|
1459
1496
|
this.mutationObserver = null;
|
|
1460
1497
|
}
|
|
1498
|
+
if (this.onFontsLoaded) {
|
|
1499
|
+
document.fonts?.removeEventListener?.("loadingdone", this.onFontsLoaded);
|
|
1500
|
+
this.onFontsLoaded = null;
|
|
1501
|
+
}
|
|
1461
1502
|
for (const { target, type } of this.scrollTargets) {
|
|
1462
1503
|
target.removeEventListener(type, type === "scroll" ? this.onScroll : this.onResize);
|
|
1463
1504
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -59,6 +59,7 @@ export interface DoodleOptions {
|
|
|
59
59
|
color?: string;
|
|
60
60
|
strokeWidth?: number;
|
|
61
61
|
roughness?: number;
|
|
62
|
+
/** Gap between the element's edge and the frame. Default `0`. */
|
|
62
63
|
padding?: number;
|
|
63
64
|
/** Auto-detected from CSS when omitted. */
|
|
64
65
|
radius?: number | null;
|
|
@@ -70,6 +71,18 @@ export interface DoodleOptions {
|
|
|
70
71
|
decorations?: boolean | DecorationOptions;
|
|
71
72
|
/** Lift the pen at random points around the outline. */
|
|
72
73
|
addBreaks?: boolean | number | BreakOptions;
|
|
74
|
+
/**
|
|
75
|
+
* Font stack for handwritten notes. Point this at your own family — a
|
|
76
|
+
* `next/font` CSS variable, for instance — to take over from the built-in one.
|
|
77
|
+
*/
|
|
78
|
+
fontFamily?: string | null;
|
|
79
|
+
/**
|
|
80
|
+
* Fetch the Caveat webfont when the page has not already provided it.
|
|
81
|
+
* Default `true`. Set `false` if a strict CSP blocks Google Fonts, or if you
|
|
82
|
+
* self-host the family; the notes then use `fontFamily` or the system
|
|
83
|
+
* handwriting fallbacks.
|
|
84
|
+
*/
|
|
85
|
+
autoLoadFont?: boolean;
|
|
73
86
|
}
|
|
74
87
|
|
|
75
88
|
export interface DoodleInstance {
|
package/dist/react.cjs
CHANGED
|
@@ -34,14 +34,19 @@ var DEFAULT_OPTIONS = {
|
|
|
34
34
|
color: "#ffffff",
|
|
35
35
|
strokeWidth: 1.5,
|
|
36
36
|
roughness: 1.5,
|
|
37
|
-
|
|
37
|
+
// The frame traces the element's own edge. Raise this to stand it off.
|
|
38
|
+
padding: 0,
|
|
38
39
|
radius: null,
|
|
39
40
|
opacity: 0.9,
|
|
40
41
|
children: null,
|
|
41
42
|
note: null,
|
|
42
43
|
arrow: false,
|
|
43
44
|
decorations: false,
|
|
44
|
-
addBreaks: false
|
|
45
|
+
addBreaks: false,
|
|
46
|
+
/** Override the handwriting stack, e.g. a next/font CSS variable. */
|
|
47
|
+
fontFamily: null,
|
|
48
|
+
/** Fetch Caveat when the page has not provided it. */
|
|
49
|
+
autoLoadFont: true
|
|
45
50
|
};
|
|
46
51
|
function resolveElement(target) {
|
|
47
52
|
if (!target) return null;
|
|
@@ -267,7 +272,7 @@ function annotationAnchor(position, rect, offset = 12) {
|
|
|
267
272
|
|
|
268
273
|
// src/renderer.js
|
|
269
274
|
var SVG_NS = "http://www.w3.org/2000/svg";
|
|
270
|
-
var HANDWRITTEN_FONT = '"Caveat", "Kalam", "Patrick Hand", cursive';
|
|
275
|
+
var HANDWRITTEN_FONT = '"Caveat", "Kalam", "Patrick Hand", "Bradley Hand", "Segoe Script", "Comic Sans MS", cursive';
|
|
271
276
|
var NOTE_FONT_SIZE = 19;
|
|
272
277
|
function clearSvg(svg) {
|
|
273
278
|
while (svg.firstChild) {
|
|
@@ -746,7 +751,7 @@ function createNoteText(svg, text, style) {
|
|
|
746
751
|
textEl.setAttribute("fill", style.color);
|
|
747
752
|
textEl.setAttribute("opacity", String(style.opacity));
|
|
748
753
|
textEl.setAttribute("font-size", String(fontSize));
|
|
749
|
-
textEl.setAttribute("font-family", HANDWRITTEN_FONT);
|
|
754
|
+
textEl.setAttribute("font-family", style.fontFamily || HANDWRITTEN_FONT);
|
|
750
755
|
textEl.setAttribute("font-weight", "600");
|
|
751
756
|
textEl.setAttribute("letter-spacing", "0.4");
|
|
752
757
|
textEl.setAttribute("text-anchor", "start");
|
|
@@ -1319,6 +1324,27 @@ function renderDecorations(svg, rect, decorationOptions, style, seed, context =
|
|
|
1319
1324
|
}
|
|
1320
1325
|
}
|
|
1321
1326
|
|
|
1327
|
+
// src/fonts.js
|
|
1328
|
+
var FONT_NAME = "Caveat";
|
|
1329
|
+
var FONT_HREF = "https://fonts.googleapis.com/css2?family=Caveat:wght@400;600&display=swap";
|
|
1330
|
+
var MARKER = "data-freehand-font";
|
|
1331
|
+
var requested = false;
|
|
1332
|
+
function ensureHandwrittenFont() {
|
|
1333
|
+
if (requested) return;
|
|
1334
|
+
if (typeof document === "undefined" || !document.head) return;
|
|
1335
|
+
requested = true;
|
|
1336
|
+
try {
|
|
1337
|
+
if (document.fonts?.check?.(`600 19px "${FONT_NAME}"`)) return;
|
|
1338
|
+
} catch {
|
|
1339
|
+
}
|
|
1340
|
+
if (document.querySelector(`link[${MARKER}]`)) return;
|
|
1341
|
+
const link = document.createElement("link");
|
|
1342
|
+
link.rel = "stylesheet";
|
|
1343
|
+
link.href = FONT_HREF;
|
|
1344
|
+
link.setAttribute(MARKER, "");
|
|
1345
|
+
document.head.appendChild(link);
|
|
1346
|
+
}
|
|
1347
|
+
|
|
1322
1348
|
// src/doodle.js
|
|
1323
1349
|
var instances = /* @__PURE__ */ new WeakMap();
|
|
1324
1350
|
function localViewport(overlayRect, inset = 8) {
|
|
@@ -1370,7 +1396,12 @@ var DoodleOverlay = class {
|
|
|
1370
1396
|
}
|
|
1371
1397
|
window.addEventListener("resize", this.onResize, { passive: true });
|
|
1372
1398
|
this.scrollTargets.push({ target: window, type: "resize" });
|
|
1373
|
-
|
|
1399
|
+
if (this.options.note && this.options.autoLoadFont && !this.options.fontFamily) {
|
|
1400
|
+
ensureHandwrittenFont();
|
|
1401
|
+
}
|
|
1402
|
+
this.onFontsLoaded = () => this.scheduleUpdate();
|
|
1403
|
+
document.fonts?.addEventListener?.("loadingdone", this.onFontsLoaded);
|
|
1404
|
+
document.fonts?.ready?.then(this.onFontsLoaded).catch(() => {
|
|
1374
1405
|
});
|
|
1375
1406
|
this.update();
|
|
1376
1407
|
}
|
|
@@ -1413,7 +1444,13 @@ var DoodleOverlay = class {
|
|
|
1413
1444
|
this.svg.style.width = `${overlayRect.width}px`;
|
|
1414
1445
|
this.svg.style.height = `${overlayRect.height}px`;
|
|
1415
1446
|
const strokeStyle = { color, strokeWidth, roughness, opacity };
|
|
1416
|
-
const noteStyle = {
|
|
1447
|
+
const noteStyle = {
|
|
1448
|
+
color,
|
|
1449
|
+
opacity,
|
|
1450
|
+
strokeWidth,
|
|
1451
|
+
roughness,
|
|
1452
|
+
fontFamily: this.options.fontFamily
|
|
1453
|
+
};
|
|
1417
1454
|
const noteGroups = [];
|
|
1418
1455
|
const noteLayout = {
|
|
1419
1456
|
viewport: localViewport(overlayRect),
|
|
@@ -1488,6 +1525,10 @@ var DoodleOverlay = class {
|
|
|
1488
1525
|
this.mutationObserver.disconnect();
|
|
1489
1526
|
this.mutationObserver = null;
|
|
1490
1527
|
}
|
|
1528
|
+
if (this.onFontsLoaded) {
|
|
1529
|
+
document.fonts?.removeEventListener?.("loadingdone", this.onFontsLoaded);
|
|
1530
|
+
this.onFontsLoaded = null;
|
|
1531
|
+
}
|
|
1491
1532
|
for (const { target, type } of this.scrollTargets) {
|
|
1492
1533
|
target.removeEventListener(type, type === "scroll" ? this.onScroll : this.onResize);
|
|
1493
1534
|
}
|
|
@@ -1530,7 +1571,9 @@ var OPTION_KEYS = [
|
|
|
1530
1571
|
"note",
|
|
1531
1572
|
"arrow",
|
|
1532
1573
|
"decorations",
|
|
1533
|
-
"addBreaks"
|
|
1574
|
+
"addBreaks",
|
|
1575
|
+
"fontFamily",
|
|
1576
|
+
"autoLoadFont"
|
|
1534
1577
|
];
|
|
1535
1578
|
function collectOptions(props) {
|
|
1536
1579
|
const options = {};
|
|
@@ -1580,6 +1623,8 @@ var Doodle = (0, import_react.forwardRef)(function Doodle2(props, forwardedRef)
|
|
|
1580
1623
|
arrow,
|
|
1581
1624
|
decorations,
|
|
1582
1625
|
addBreaks,
|
|
1626
|
+
fontFamily,
|
|
1627
|
+
autoLoadFont,
|
|
1583
1628
|
childSelector,
|
|
1584
1629
|
...rest
|
|
1585
1630
|
} = props;
|
|
@@ -1597,6 +1642,8 @@ var Doodle = (0, import_react.forwardRef)(function Doodle2(props, forwardedRef)
|
|
|
1597
1642
|
arrow,
|
|
1598
1643
|
decorations,
|
|
1599
1644
|
addBreaks,
|
|
1645
|
+
fontFamily,
|
|
1646
|
+
autoLoadFont,
|
|
1600
1647
|
childSelector
|
|
1601
1648
|
}),
|
|
1602
1649
|
[
|
|
@@ -1612,6 +1659,8 @@ var Doodle = (0, import_react.forwardRef)(function Doodle2(props, forwardedRef)
|
|
|
1612
1659
|
JSON.stringify(arrow ?? null),
|
|
1613
1660
|
JSON.stringify(decorations ?? null),
|
|
1614
1661
|
JSON.stringify(addBreaks ?? null),
|
|
1662
|
+
fontFamily,
|
|
1663
|
+
autoLoadFont,
|
|
1615
1664
|
childSelector
|
|
1616
1665
|
]
|
|
1617
1666
|
);
|
package/dist/react.js
CHANGED
|
@@ -17,14 +17,19 @@ var DEFAULT_OPTIONS = {
|
|
|
17
17
|
color: "#ffffff",
|
|
18
18
|
strokeWidth: 1.5,
|
|
19
19
|
roughness: 1.5,
|
|
20
|
-
|
|
20
|
+
// The frame traces the element's own edge. Raise this to stand it off.
|
|
21
|
+
padding: 0,
|
|
21
22
|
radius: null,
|
|
22
23
|
opacity: 0.9,
|
|
23
24
|
children: null,
|
|
24
25
|
note: null,
|
|
25
26
|
arrow: false,
|
|
26
27
|
decorations: false,
|
|
27
|
-
addBreaks: false
|
|
28
|
+
addBreaks: false,
|
|
29
|
+
/** Override the handwriting stack, e.g. a next/font CSS variable. */
|
|
30
|
+
fontFamily: null,
|
|
31
|
+
/** Fetch Caveat when the page has not provided it. */
|
|
32
|
+
autoLoadFont: true
|
|
28
33
|
};
|
|
29
34
|
function resolveElement(target) {
|
|
30
35
|
if (!target) return null;
|
|
@@ -250,7 +255,7 @@ function annotationAnchor(position, rect, offset = 12) {
|
|
|
250
255
|
|
|
251
256
|
// src/renderer.js
|
|
252
257
|
var SVG_NS = "http://www.w3.org/2000/svg";
|
|
253
|
-
var HANDWRITTEN_FONT = '"Caveat", "Kalam", "Patrick Hand", cursive';
|
|
258
|
+
var HANDWRITTEN_FONT = '"Caveat", "Kalam", "Patrick Hand", "Bradley Hand", "Segoe Script", "Comic Sans MS", cursive';
|
|
254
259
|
var NOTE_FONT_SIZE = 19;
|
|
255
260
|
function clearSvg(svg) {
|
|
256
261
|
while (svg.firstChild) {
|
|
@@ -729,7 +734,7 @@ function createNoteText(svg, text, style) {
|
|
|
729
734
|
textEl.setAttribute("fill", style.color);
|
|
730
735
|
textEl.setAttribute("opacity", String(style.opacity));
|
|
731
736
|
textEl.setAttribute("font-size", String(fontSize));
|
|
732
|
-
textEl.setAttribute("font-family", HANDWRITTEN_FONT);
|
|
737
|
+
textEl.setAttribute("font-family", style.fontFamily || HANDWRITTEN_FONT);
|
|
733
738
|
textEl.setAttribute("font-weight", "600");
|
|
734
739
|
textEl.setAttribute("letter-spacing", "0.4");
|
|
735
740
|
textEl.setAttribute("text-anchor", "start");
|
|
@@ -1302,6 +1307,27 @@ function renderDecorations(svg, rect, decorationOptions, style, seed, context =
|
|
|
1302
1307
|
}
|
|
1303
1308
|
}
|
|
1304
1309
|
|
|
1310
|
+
// src/fonts.js
|
|
1311
|
+
var FONT_NAME = "Caveat";
|
|
1312
|
+
var FONT_HREF = "https://fonts.googleapis.com/css2?family=Caveat:wght@400;600&display=swap";
|
|
1313
|
+
var MARKER = "data-freehand-font";
|
|
1314
|
+
var requested = false;
|
|
1315
|
+
function ensureHandwrittenFont() {
|
|
1316
|
+
if (requested) return;
|
|
1317
|
+
if (typeof document === "undefined" || !document.head) return;
|
|
1318
|
+
requested = true;
|
|
1319
|
+
try {
|
|
1320
|
+
if (document.fonts?.check?.(`600 19px "${FONT_NAME}"`)) return;
|
|
1321
|
+
} catch {
|
|
1322
|
+
}
|
|
1323
|
+
if (document.querySelector(`link[${MARKER}]`)) return;
|
|
1324
|
+
const link = document.createElement("link");
|
|
1325
|
+
link.rel = "stylesheet";
|
|
1326
|
+
link.href = FONT_HREF;
|
|
1327
|
+
link.setAttribute(MARKER, "");
|
|
1328
|
+
document.head.appendChild(link);
|
|
1329
|
+
}
|
|
1330
|
+
|
|
1305
1331
|
// src/doodle.js
|
|
1306
1332
|
var instances = /* @__PURE__ */ new WeakMap();
|
|
1307
1333
|
function localViewport(overlayRect, inset = 8) {
|
|
@@ -1353,7 +1379,12 @@ var DoodleOverlay = class {
|
|
|
1353
1379
|
}
|
|
1354
1380
|
window.addEventListener("resize", this.onResize, { passive: true });
|
|
1355
1381
|
this.scrollTargets.push({ target: window, type: "resize" });
|
|
1356
|
-
|
|
1382
|
+
if (this.options.note && this.options.autoLoadFont && !this.options.fontFamily) {
|
|
1383
|
+
ensureHandwrittenFont();
|
|
1384
|
+
}
|
|
1385
|
+
this.onFontsLoaded = () => this.scheduleUpdate();
|
|
1386
|
+
document.fonts?.addEventListener?.("loadingdone", this.onFontsLoaded);
|
|
1387
|
+
document.fonts?.ready?.then(this.onFontsLoaded).catch(() => {
|
|
1357
1388
|
});
|
|
1358
1389
|
this.update();
|
|
1359
1390
|
}
|
|
@@ -1396,7 +1427,13 @@ var DoodleOverlay = class {
|
|
|
1396
1427
|
this.svg.style.width = `${overlayRect.width}px`;
|
|
1397
1428
|
this.svg.style.height = `${overlayRect.height}px`;
|
|
1398
1429
|
const strokeStyle = { color, strokeWidth, roughness, opacity };
|
|
1399
|
-
const noteStyle = {
|
|
1430
|
+
const noteStyle = {
|
|
1431
|
+
color,
|
|
1432
|
+
opacity,
|
|
1433
|
+
strokeWidth,
|
|
1434
|
+
roughness,
|
|
1435
|
+
fontFamily: this.options.fontFamily
|
|
1436
|
+
};
|
|
1400
1437
|
const noteGroups = [];
|
|
1401
1438
|
const noteLayout = {
|
|
1402
1439
|
viewport: localViewport(overlayRect),
|
|
@@ -1471,6 +1508,10 @@ var DoodleOverlay = class {
|
|
|
1471
1508
|
this.mutationObserver.disconnect();
|
|
1472
1509
|
this.mutationObserver = null;
|
|
1473
1510
|
}
|
|
1511
|
+
if (this.onFontsLoaded) {
|
|
1512
|
+
document.fonts?.removeEventListener?.("loadingdone", this.onFontsLoaded);
|
|
1513
|
+
this.onFontsLoaded = null;
|
|
1514
|
+
}
|
|
1474
1515
|
for (const { target, type } of this.scrollTargets) {
|
|
1475
1516
|
target.removeEventListener(type, type === "scroll" ? this.onScroll : this.onResize);
|
|
1476
1517
|
}
|
|
@@ -1513,7 +1554,9 @@ var OPTION_KEYS = [
|
|
|
1513
1554
|
"note",
|
|
1514
1555
|
"arrow",
|
|
1515
1556
|
"decorations",
|
|
1516
|
-
"addBreaks"
|
|
1557
|
+
"addBreaks",
|
|
1558
|
+
"fontFamily",
|
|
1559
|
+
"autoLoadFont"
|
|
1517
1560
|
];
|
|
1518
1561
|
function collectOptions(props) {
|
|
1519
1562
|
const options = {};
|
|
@@ -1563,6 +1606,8 @@ var Doodle = forwardRef(function Doodle2(props, forwardedRef) {
|
|
|
1563
1606
|
arrow,
|
|
1564
1607
|
decorations,
|
|
1565
1608
|
addBreaks,
|
|
1609
|
+
fontFamily,
|
|
1610
|
+
autoLoadFont,
|
|
1566
1611
|
childSelector,
|
|
1567
1612
|
...rest
|
|
1568
1613
|
} = props;
|
|
@@ -1580,6 +1625,8 @@ var Doodle = forwardRef(function Doodle2(props, forwardedRef) {
|
|
|
1580
1625
|
arrow,
|
|
1581
1626
|
decorations,
|
|
1582
1627
|
addBreaks,
|
|
1628
|
+
fontFamily,
|
|
1629
|
+
autoLoadFont,
|
|
1583
1630
|
childSelector
|
|
1584
1631
|
}),
|
|
1585
1632
|
[
|
|
@@ -1595,6 +1642,8 @@ var Doodle = forwardRef(function Doodle2(props, forwardedRef) {
|
|
|
1595
1642
|
JSON.stringify(arrow ?? null),
|
|
1596
1643
|
JSON.stringify(decorations ?? null),
|
|
1597
1644
|
JSON.stringify(addBreaks ?? null),
|
|
1645
|
+
fontFamily,
|
|
1646
|
+
autoLoadFont,
|
|
1598
1647
|
childSelector
|
|
1599
1648
|
]
|
|
1600
1649
|
);
|
package/package.json
CHANGED