@aznabee/freehand-ui 0.1.1 → 0.1.3
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 +96 -14
- package/dist/freehand-ui.cjs +296 -132
- package/dist/freehand-ui.js +296 -132
- package/dist/index.d.ts +32 -3
- package/dist/react.cjs +305 -133
- package/dist/react.js +305 -133
- 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
|
|
@@ -140,11 +180,34 @@ doodle(".cta", {
|
|
|
140
180
|
|
|
141
181
|
Positions: `top`, `top-right`, `right`, `bottom-right`, `bottom`, `bottom-left`, `left`, `top-left`. Same names apply to `arrow.from`/`arrow.to`.
|
|
142
182
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
183
|
+
Notes are measured from their real glyph metrics and laid out so they never sit
|
|
184
|
+
on top of the element. The underline is drawn to the measured text width; set
|
|
185
|
+
`underline: false` for plain handwriting.
|
|
186
|
+
|
|
187
|
+
**The side you ask for is the side you get.** When a note runs past the edge of
|
|
188
|
+
the viewport it slides horizontally by exactly the amount it overhangs, so a
|
|
189
|
+
narrowing viewport walks it gradually inward instead of snapping it to the
|
|
190
|
+
opposite side. The only limit is the element itself: a note level with it stops
|
|
191
|
+
once they meet, rather than sliding across it.
|
|
192
|
+
|
|
193
|
+
Vertical placement is fixed relative to the element and does not react to
|
|
194
|
+
scrolling, so a note stays pinned to what it annotates instead of crawling back
|
|
195
|
+
into view as the page moves. A note beside an element that is itself jammed
|
|
196
|
+
against the viewport edge has nowhere to slide, so it may sit partly off screen
|
|
197
|
+
— use a different `position` or an `offset` there.
|
|
198
|
+
|
|
199
|
+
Nudge a note off its computed spot with `offset`:
|
|
200
|
+
|
|
201
|
+
```javascript
|
|
202
|
+
doodle(".cta", {
|
|
203
|
+
note: { text: "start chat", position: "top", offset: { x: 40, y: -12 } },
|
|
204
|
+
});
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
The offset moves the note from the spot `position` chose, and staying in view is
|
|
208
|
+
judged from there — so a large offset slides back into the viewport rather than
|
|
209
|
+
carrying the note off screen. Vertical offsets are always applied verbatim,
|
|
210
|
+
since vertical placement never reacts to the viewport.
|
|
148
211
|
|
|
149
212
|
## Arrows
|
|
150
213
|
|
|
@@ -153,17 +216,36 @@ doodle(".cta", { arrow: true });
|
|
|
153
216
|
|
|
154
217
|
doodle(".cta", {
|
|
155
218
|
arrow: {
|
|
156
|
-
from: "top-right",
|
|
219
|
+
from: "top-right", // note | any position name
|
|
157
220
|
to: "center",
|
|
158
|
-
style: "curved",
|
|
221
|
+
style: "curved", // curved | straight | dotted | looped
|
|
159
222
|
},
|
|
160
223
|
});
|
|
161
224
|
```
|
|
162
225
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
226
|
+
`looped` ties a curl into the middle of the sweep — the hand-drawn flourish that
|
|
227
|
+
doubles back on itself before reaching the tip.
|
|
228
|
+
|
|
229
|
+
`from` decides where the arrow leaves. **With a note it names a side of the
|
|
230
|
+
note** — where the pen lifts off the handwriting — and the arrow then travels to
|
|
231
|
+
the element wherever that is:
|
|
232
|
+
|
|
233
|
+
```javascript
|
|
234
|
+
doodle(".cta", {
|
|
235
|
+
note: { text: "start chat", position: "top-right" },
|
|
236
|
+
arrow: { from: "bottom-left" }, // leaves the note's bottom-left corner
|
|
237
|
+
});
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
`"note"` is the default and picks the side of the note facing the element. A
|
|
241
|
+
callout always departs from its note, so moving the note with `offset` takes the
|
|
242
|
+
arrow with it rather than leaving it stranded by the element.
|
|
243
|
+
|
|
244
|
+
Without a note there is no handwriting to leave from, so `from` falls back to
|
|
245
|
+
naming a side of the element itself.
|
|
246
|
+
|
|
247
|
+
`to: "edge"` (the default) lands the tip just *outside* the frame; `to: "center"`
|
|
248
|
+
is the one setting that deliberately points into the element.
|
|
167
249
|
|
|
168
250
|
## Decorations
|
|
169
251
|
|