@weasel-js/text-dom 0.0.0-stage → 1.10.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/LICENSE +21 -0
- package/README.md +31 -2
- package/dist/index.d.ts +315 -0
- package/dist/index.js +1322 -0
- package/dist/index.js.map +1 -0
- package/package.json +50 -4
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 orochi235
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,32 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @weasel-js/text-dom
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
In-place text editing over a canvas: a `contenteditable` overlay that reads and
|
|
4
|
+
writes styled runs.
|
|
5
|
+
|
|
6
|
+
Part of [weasel](https://github.com/orochi235/weasel), a domain-agnostic 2D
|
|
7
|
+
scene-graph canvas kit for React. See the
|
|
8
|
+
[API reference](https://orochi235.github.io/weasel/api/).
|
|
9
|
+
|
|
10
|
+
```sh
|
|
11
|
+
npm install @weasel-js/text-dom
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
`useTextEdit` mounts an editable element over a box on screen, set in the same
|
|
15
|
+
face, size, and alignment the canvas draws the text in, and hands back the
|
|
16
|
+
edited text as `StyledRun`s from `@weasel-js/text` when the edit commits. It
|
|
17
|
+
takes a screen pose and a `TextStyle`; it does not know about a scene graph or
|
|
18
|
+
a renderer. `useSceneTextEdit` in `@weasel-js/core` is this hook wired to a
|
|
19
|
+
scene node.
|
|
20
|
+
|
|
21
|
+
While an edit is open the hook reports the selection's shared style
|
|
22
|
+
(`MIXED` where the selected runs disagree) and applies a style or a flag such
|
|
23
|
+
as bold to the selected range.
|
|
24
|
+
|
|
25
|
+
A paste or a drop goes in as runs, never as the clipboard's markup: its blocks
|
|
26
|
+
become lines, its table cells are set apart by tabs, and it keeps its bold,
|
|
27
|
+
italic, underline, strikethrough, overline, and super- and subscript. Face,
|
|
28
|
+
size, and color come from the text it lands in.
|
|
29
|
+
|
|
30
|
+
`runsToDom` and `domToRuns` are the conversion between runs and the overlay's
|
|
31
|
+
DOM, and `charOffsetToDomPosition` / `domPositionToCharOffset` map a character
|
|
32
|
+
offset in the text to a DOM position and back.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
import { FlagKey, StyledRun, TextStyle, TextVerticalAlign, TextPaint, RangeStyle, RunStylePatch, ResolvedTextStyle } from '@weasel-js/text';
|
|
2
|
+
|
|
3
|
+
/** The option, return, and pose types of `useTextEdit`. */
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* A styling a shortcut or a control toggles. The additive booleans, plus the
|
|
7
|
+
* two `script` values — which are exclusive rather than additive, so they
|
|
8
|
+
* toggle against one enum rather than each owning a boolean.
|
|
9
|
+
*/
|
|
10
|
+
type StyleToggle = FlagKey | 'super' | 'sub';
|
|
11
|
+
/**
|
|
12
|
+
* The caret's character range within the text being edited. Half-open
|
|
13
|
+
* `[start, end)` over the concatenated run text, normalized so `start <= end`
|
|
14
|
+
* regardless of which way the user dragged. `start === end` is a collapsed
|
|
15
|
+
* caret — a real position, not the absence of one, which is why the hook
|
|
16
|
+
* reports `null` rather than a zero-width range when there is no caret.
|
|
17
|
+
*/
|
|
18
|
+
interface TextEditSelection {
|
|
19
|
+
start: number;
|
|
20
|
+
end: number;
|
|
21
|
+
}
|
|
22
|
+
/** Screen-space pose passed to `useTextEdit` so the overlay can be placed and sized in CSS pixels. */
|
|
23
|
+
interface TextEditScreenPose {
|
|
24
|
+
/** Top-left in CSS pixels relative to `container`. Always screen pixels,
|
|
25
|
+
* including when `zoom` is set — the scale is anchored at this point, not
|
|
26
|
+
* translated by it. */
|
|
27
|
+
x: number;
|
|
28
|
+
y: number;
|
|
29
|
+
/** Pre-scale — CSS pixels, or world units when `zoom` is set. */
|
|
30
|
+
width: number;
|
|
31
|
+
height: number;
|
|
32
|
+
/** Pre-scale font size: `style.fontSize * zoom` when `zoom` is omitted, the
|
|
33
|
+
* world-unit `style.fontSize` when it is set. */
|
|
34
|
+
fontSize: number;
|
|
35
|
+
/** Effective on-screen line height multiplier (defaults to style.lineHeight). */
|
|
36
|
+
lineHeight?: number;
|
|
37
|
+
/**
|
|
38
|
+
* Where the text sits within `height`, as the canvas places it. `'center'`
|
|
39
|
+
* and `'bottom'` size the overlay to its own content and offset it by the
|
|
40
|
+
* slack, re-measured as typing changes the line count. Default `'top'`.
|
|
41
|
+
*/
|
|
42
|
+
verticalAlign?: TextVerticalAlign;
|
|
43
|
+
/**
|
|
44
|
+
* CSS scale applied to the overlay (`transform: scale(zoom)`, anchored at
|
|
45
|
+
* its top-left). Every other size on this pose, and every typographic
|
|
46
|
+
* metric the hook writes, is then **pre-scale** — pass world units and the
|
|
47
|
+
* transform does the world→screen conversion.
|
|
48
|
+
*
|
|
49
|
+
* This is the only way run-level typography can be correct at a zoom other
|
|
50
|
+
* than 1. Omit it (the default, `1`) and the pose is plain screen pixels —
|
|
51
|
+
* the hook then infers the world→screen factor from
|
|
52
|
+
* `fontSize / style.fontSize` to scale node-level `letterSpacing`, and
|
|
53
|
+
* run-level overrides are left unscaled.
|
|
54
|
+
*/
|
|
55
|
+
zoom?: number;
|
|
56
|
+
/**
|
|
57
|
+
* The frame the text is drawn in, when its box is turned or skewed: the
|
|
58
|
+
* linear part `[a, b, c, d]` (`x' = a·x + c·y`, `y' = b·x + d·y`) applied
|
|
59
|
+
* about the box's center. `x`, `y`, `width`, and `height` stay those of
|
|
60
|
+
* the box before it. Absent is the identity.
|
|
61
|
+
*/
|
|
62
|
+
frame?: readonly [a: number, b: number, c: number, d: number];
|
|
63
|
+
}
|
|
64
|
+
/** A box in CSS pixels relative to `useTextEdit`'s `container`. */
|
|
65
|
+
interface TextEditClipRect {
|
|
66
|
+
x: number;
|
|
67
|
+
y: number;
|
|
68
|
+
width: number;
|
|
69
|
+
height: number;
|
|
70
|
+
}
|
|
71
|
+
/** What one edit session changed, as `UseTextEditOptions.commit` receives it. */
|
|
72
|
+
interface TextEditCommit {
|
|
73
|
+
text: string;
|
|
74
|
+
runs?: StyledRun[];
|
|
75
|
+
style?: TextStyle;
|
|
76
|
+
}
|
|
77
|
+
/** Options for `useTextEdit`. */
|
|
78
|
+
interface UseTextEditOptions {
|
|
79
|
+
/** Element the overlay is appended to. Must be `position: relative`/absolute. */
|
|
80
|
+
container: HTMLElement | null;
|
|
81
|
+
/** Read the current text for `id`. */
|
|
82
|
+
getText: (id: string) => string;
|
|
83
|
+
/** Read style for `id` (used for font setup on the overlay). */
|
|
84
|
+
getStyle: (id: string) => TextStyle | undefined;
|
|
85
|
+
/**
|
|
86
|
+
* Read the node's paint for `id` — its `data.fill` / `data.stroke`. The
|
|
87
|
+
* overlay paints its text and caret from the fill, so omitting this
|
|
88
|
+
* renders every node's editor in the default black however the node
|
|
89
|
+
* itself is painted.
|
|
90
|
+
*/
|
|
91
|
+
getPaint?: (id: string) => TextPaint | undefined;
|
|
92
|
+
/**
|
|
93
|
+
* Write style back for `id`. Optional; needed only to turn a flag **off**
|
|
94
|
+
* inside a node whose own `TextStyle` sets it. Run flags are additive, so
|
|
95
|
+
* that edit is expressed by lowering the node flag and raising it on the
|
|
96
|
+
* runs outside the selection — which needs somewhere to put the new node
|
|
97
|
+
* style. Without this or `commit`, such a toggle is declined and nothing
|
|
98
|
+
* changes. See `flagRange` in `@weasel-js/text`.
|
|
99
|
+
*
|
|
100
|
+
* Called when the edit commits, never during it: the session holds the
|
|
101
|
+
* rewritten style until then (see `UseTextEditReturn.nodeStyle`), so a
|
|
102
|
+
* canceled edit writes nothing.
|
|
103
|
+
*/
|
|
104
|
+
setStyle?: (id: string, style: TextStyle) => void;
|
|
105
|
+
/** Read screen-space pose for `id`. Called per frame while editing. */
|
|
106
|
+
getScreenPose: (id: string) => TextEditScreenPose | null;
|
|
107
|
+
/**
|
|
108
|
+
* The box, in CSS pixels relative to `container`, the overlay is visible
|
|
109
|
+
* within — where the canvas clips the glyphs the overlay stands in for.
|
|
110
|
+
* Re-read every frame. Omit it, or return `null`, to clip nothing.
|
|
111
|
+
*
|
|
112
|
+
* The clip cannot scroll, so a caret moving past its edge leaves the page
|
|
113
|
+
* where it is; a scrollable container would drag the canvas after the caret.
|
|
114
|
+
*/
|
|
115
|
+
getClipRect?: () => TextEditClipRect | null;
|
|
116
|
+
/** Commit text. Caller wraps in op/undo. Required unless `commit` is given. */
|
|
117
|
+
setText?: (id: string, text: string) => void;
|
|
118
|
+
/**
|
|
119
|
+
* Take the whole edit in one call, so the caller can make it one write and
|
|
120
|
+
* one undo step. When given, it replaces `setText`, `setRuns`, and
|
|
121
|
+
* `setStyle`, none of which is called. `runs` is present when runs are in
|
|
122
|
+
* play (see `setRuns`), `style` when the edit rewrote the node's own style
|
|
123
|
+
* (see `setStyle`).
|
|
124
|
+
*/
|
|
125
|
+
commit?: (id: string, edit: TextEditCommit) => void;
|
|
126
|
+
/**
|
|
127
|
+
* Optional: read the current rich-text runs for `id`. When provided AND
|
|
128
|
+
* returns a non-empty array, the overlay renders the runs as styled
|
|
129
|
+
* `<span data-run>` elements; otherwise the overlay is seeded with plain
|
|
130
|
+
* text via `getText`.
|
|
131
|
+
*/
|
|
132
|
+
getRuns?: (id: string) => readonly StyledRun[] | undefined;
|
|
133
|
+
/**
|
|
134
|
+
* Optional: commit rich-text runs back to the node. When omitted, only
|
|
135
|
+
* `setText` is called with the plain-text form on commit. When provided,
|
|
136
|
+
* commit calls both `setText` (with `runsToPlainText(runs)`) and
|
|
137
|
+
* `setRuns(id, runs)` — but only when runs are actually in play: the node
|
|
138
|
+
* already had some, or the edit produced styling. A plain-text edit of a
|
|
139
|
+
* plain-text node still calls `setText` alone.
|
|
140
|
+
*/
|
|
141
|
+
setRuns?: (id: string, runs: StyledRun[]) => void;
|
|
142
|
+
/**
|
|
143
|
+
* Is `el` part of the editor's own chrome — a character-options bar, a
|
|
144
|
+
* color popover, anything whose whole purpose is to style the text being
|
|
145
|
+
* edited? Focus moving into one does not end the edit.
|
|
146
|
+
*
|
|
147
|
+
* Without this, clicking a size field blurs the overlay, blur commits, and
|
|
148
|
+
* the caret the control was about to act on is gone. Toggle buttons can
|
|
149
|
+
* dodge it by `preventDefault()`-ing their own mousedown, but a field the
|
|
150
|
+
* user has to type into cannot.
|
|
151
|
+
*
|
|
152
|
+
* Chrome focus does not disturb the reported `selection` either — see
|
|
153
|
+
* `UseTextEditReturn.selection`.
|
|
154
|
+
*/
|
|
155
|
+
isEditorChrome?: (el: Element) => boolean;
|
|
156
|
+
/** What Escape does to the edit: `'cancel'` (the default) drops it,
|
|
157
|
+
* `'commit'` keeps the text as Enter would. */
|
|
158
|
+
escape?: 'cancel' | 'commit';
|
|
159
|
+
/**
|
|
160
|
+
* How long, in ms, an edit opening waits for the overlay's face before
|
|
161
|
+
* showing the text in the fallback. Defaults to {@link TEXT_EDIT_FONT_HOLD}.
|
|
162
|
+
*
|
|
163
|
+
* The overlay stands in for canvas text the host has hidden, so the wait
|
|
164
|
+
* shows nothing at all; past it, the fallback shows and reflows to the real
|
|
165
|
+
* face when that lands. A face already loaded shows at once. `0` never waits.
|
|
166
|
+
*/
|
|
167
|
+
fontHold?: number;
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* The default {@link UseTextEditOptions.fontHold}: at 100ms a blank edit
|
|
171
|
+
* still reads as an instant response, and it is the block period CSS gives
|
|
172
|
+
* `font-display: fallback` for the same trade.
|
|
173
|
+
*/
|
|
174
|
+
declare const TEXT_EDIT_FONT_HOLD = 100;
|
|
175
|
+
/** Options for `useTextEdit().startEdit`. */
|
|
176
|
+
interface StartEditOptions {
|
|
177
|
+
/** Where to place the caret on edit start. Number = caret offset (0..text.length);
|
|
178
|
+
* `'all'` selects the whole text (default). */
|
|
179
|
+
caret?: number | 'all';
|
|
180
|
+
}
|
|
181
|
+
/** Return shape of `useTextEdit`. */
|
|
182
|
+
interface UseTextEditReturn {
|
|
183
|
+
editingId: string | null;
|
|
184
|
+
startEdit: (id: string, opts?: StartEditOptions) => void;
|
|
185
|
+
cancelEdit: () => void;
|
|
186
|
+
/** End the edit and write it. An edit that leaves the text, the runs, and
|
|
187
|
+
* the node's style as it found them writes nothing. */
|
|
188
|
+
commit: () => void;
|
|
189
|
+
isEditing: (id: string) => boolean;
|
|
190
|
+
/**
|
|
191
|
+
* The node-wide style this edit has rewritten and not yet written back, or
|
|
192
|
+
* `null` when it has rewritten none (the node's own style stands) or
|
|
193
|
+
* nothing is being edited. Lowering a flag the node sets rewrites it; the
|
|
194
|
+
* write waits for the commit. A control showing the node's style during an
|
|
195
|
+
* edit reads this first.
|
|
196
|
+
*/
|
|
197
|
+
nodeStyle: TextStyle | null;
|
|
198
|
+
/**
|
|
199
|
+
* The caret's character range, or `null` when nothing is being edited. A
|
|
200
|
+
* collapsed caret reports `{ start: n, end: n }`, so `null` and "caret at
|
|
201
|
+
* n" stay distinguishable — a styling written at a collapsed caret arms
|
|
202
|
+
* {@link UseTextEditReturn.pendingStyle} instead of restyling a range.
|
|
203
|
+
*
|
|
204
|
+
* Follows the DOM selection, which browsers report from a task
|
|
205
|
+
* rather than synchronously; anything this hook writes itself updates it
|
|
206
|
+
* synchronously. A DOM selection that leaves the overlay does **not** clear
|
|
207
|
+
* it: that is what happens when the user clicks a styling control, and
|
|
208
|
+
* reporting `null` there would read as "collapsed caret" and send the
|
|
209
|
+
* control's patch to the node instead of to the range. It is cleared on
|
|
210
|
+
* `startEdit` and when the edit ends.
|
|
211
|
+
*/
|
|
212
|
+
selection: TextEditSelection | null;
|
|
213
|
+
/**
|
|
214
|
+
* The styling shared by every run in `selection` — a concrete value where
|
|
215
|
+
* the range agrees, `MIXED` where it doesn't. `null` exactly when
|
|
216
|
+
* `selection` is `null`. A collapsed caret reports the styling *at* the
|
|
217
|
+
* caret (the run to its left, or the run to its right at offset 0), which
|
|
218
|
+
* is what the next typed character inherits.
|
|
219
|
+
*
|
|
220
|
+
* This does not include {@link UseTextEditReturn.pendingStyle}. A control
|
|
221
|
+
* showing what the next character will look like wants both, merged in
|
|
222
|
+
* that order; one showing what is already written wants only this.
|
|
223
|
+
*/
|
|
224
|
+
rangeStyle: RangeStyle | null;
|
|
225
|
+
/**
|
|
226
|
+
* Styling armed at a collapsed caret, applied to the next character typed
|
|
227
|
+
* and then dropped. `{}` when nothing is armed — which is always the case
|
|
228
|
+
* while `selection` covers a real range, since a range is styled directly.
|
|
229
|
+
* Moving the caret abandons it.
|
|
230
|
+
*/
|
|
231
|
+
pendingStyle: RunStylePatch;
|
|
232
|
+
/**
|
|
233
|
+
* What a styling control shows during an edit: the node's own style and
|
|
234
|
+
* paint, `rangeStyle` over it, and `pendingStyle` last — what the user
|
|
235
|
+
* will see themselves type. `null` when nothing is being edited.
|
|
236
|
+
*/
|
|
237
|
+
effectiveStyle: RangeStyle | null;
|
|
238
|
+
/**
|
|
239
|
+
* Write `patch` over `selection`. A no-op with no active edit or an empty
|
|
240
|
+
* patch. Over a real range this restyles the runs under it; at a collapsed
|
|
241
|
+
* caret it merges into `pendingStyle` instead, so the styling lands on
|
|
242
|
+
* what gets typed next rather than on text the user didn't select.
|
|
243
|
+
*
|
|
244
|
+
* Lowering a flag the *node* sets is neither of those — a run cannot say
|
|
245
|
+
* "not italic" — so it rewrites instead: the node flag is cleared and raised
|
|
246
|
+
* on every run outside the range. Bold is spared that: a run's own
|
|
247
|
+
* `fontWeight` can say "regular", so it is written over the range.
|
|
248
|
+
*
|
|
249
|
+
* The caret survives, so a second style can be applied without
|
|
250
|
+
* re-selecting, and `rangeStyle` reflects the write before this returns.
|
|
251
|
+
*/
|
|
252
|
+
applyStyleToSelection: (patch: RunStylePatch) => void;
|
|
253
|
+
/** Toggle one styling over `selection` — set it if the range doesn't
|
|
254
|
+
* uniformly carry it, clear it if it does. */
|
|
255
|
+
toggleStyle: (toggle: StyleToggle) => void;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* In-place text editing via a contenteditable overlay positioned over the
|
|
260
|
+
* text node's screen-space pose. Enter / blur commit; Shift+Enter inserts a
|
|
261
|
+
* newline. The text layer should hide the node it's currently editing
|
|
262
|
+
* (`isHidden: (n) => n.id === editingId`) so the overlay isn't drawn twice.
|
|
263
|
+
*/
|
|
264
|
+
|
|
265
|
+
/** In-place text editing via a contenteditable overlay positioned over the text node's screen-space pose. */
|
|
266
|
+
declare function useTextEdit(opts: UseTextEditOptions): UseTextEditReturn;
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* The DOM position of plain-text character position `offset`: a text node
|
|
270
|
+
* and an offset into it wherever one holds the position, otherwise an element
|
|
271
|
+
* and a child index (just past a `<br>` that ends the text). Offsets beyond
|
|
272
|
+
* the text clamp to its end. Returns `{ node: parent, offset: 0 }` for an
|
|
273
|
+
* overlay with no text.
|
|
274
|
+
*/
|
|
275
|
+
declare function charOffsetToDomPosition(parent: HTMLElement, offset: number): {
|
|
276
|
+
node: Node;
|
|
277
|
+
offset: number;
|
|
278
|
+
} | null;
|
|
279
|
+
/**
|
|
280
|
+
* Inverse of `charOffsetToDomPosition`: the characters that precede the DOM
|
|
281
|
+
* position `(node, offset)`.
|
|
282
|
+
*
|
|
283
|
+
* When `node` is an element the DOM offset indexes *child nodes*, not
|
|
284
|
+
* characters — `(overlay, 0)` is the start of the text and `(overlay,
|
|
285
|
+
* childNodes.length)` its end. That shape is not exotic: `Range.
|
|
286
|
+
* selectNodeContents`, which `useTextEdit` uses for its select-all caret,
|
|
287
|
+
* produces exactly it. So an element position is resolved by counting the
|
|
288
|
+
* pieces that end at or before the boundary point.
|
|
289
|
+
*/
|
|
290
|
+
declare function domPositionToCharOffset(parent: HTMLElement, node: Node, offset: number): number;
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* DOM ↔ `StyledRun[]` serializers for the contenteditable overlay: a flat
|
|
294
|
+
* sequence of `<span data-run>` elements, one per run. The browser breaks at
|
|
295
|
+
* `\n` and at no other UAX #14 hard break, so each of those is written as a
|
|
296
|
+
* `<span data-break>` holding a `\n` in its place — one character for one,
|
|
297
|
+
* which keeps DOM offsets equal to source offsets.
|
|
298
|
+
*
|
|
299
|
+
* A small-caps run's lowercase letters sit in `<span data-small-caps>` pieces,
|
|
300
|
+
* uppercased and sized at the scale the canvas draws them with, since a
|
|
301
|
+
* browser's own synthesis uses a fixed factor of its own.
|
|
302
|
+
*/
|
|
303
|
+
|
|
304
|
+
/** Walk an overlay tree and emit a coalesced `StyledRun[]`. */
|
|
305
|
+
declare function domToRuns(parent: HTMLElement): StyledRun[];
|
|
306
|
+
/** What a run inherits from its node, for the overlay's small caps: which
|
|
307
|
+
* runs have it, and the face and transform that decide their pieces. */
|
|
308
|
+
type OverlayRunBase = Pick<ResolvedTextStyle, 'fontFamily' | 'fontWeight' | 'fontStyle' | 'textTransform' | 'fontVariantCaps'>;
|
|
309
|
+
/**
|
|
310
|
+
* Replace `parent`'s children with one `<span data-run>` per run. `base` is
|
|
311
|
+
* the node's style, which a run inheriting small caps is split by.
|
|
312
|
+
*/
|
|
313
|
+
declare function runsToDom(runs: readonly StyledRun[], parent: HTMLElement, base?: OverlayRunBase): void;
|
|
314
|
+
|
|
315
|
+
export { type OverlayRunBase, type StartEditOptions, type StyleToggle, TEXT_EDIT_FONT_HOLD, type TextEditClipRect, type TextEditCommit, type TextEditScreenPose, type TextEditSelection, type UseTextEditOptions, type UseTextEditReturn, charOffsetToDomPosition, domPositionToCharOffset, domToRuns, runsToDom, useTextEdit };
|