efficient-shell 5.6.0 → 6.4.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/README.md +189 -46
- package/THIRD_PARTY_NOTICES.md +212 -0
- package/dist/Browser-USPZWDYH.js +43 -0
- package/dist/Calculator-FP5HUWCW.js +29 -0
- package/dist/ConfirmDialog-3TIHKJRT.js +1 -0
- package/dist/{CurrencyConverter-YJ47A3L5.js → CurrencyConverter-XD5LYOCD.js} +7 -7
- package/dist/Documents-ADFEHEUW.js +52 -0
- package/dist/Files-BVUVRNC5.js +87 -0
- package/dist/Notepad-WJI5ODGS.js +25 -0
- package/dist/PdfViewer-226I3LSD.js +1 -0
- package/dist/PomodoroTimer-GEMQHIPJ.js +91 -0
- package/dist/Preview-HNSEYNZL.js +182 -0
- package/dist/Sidebar-PVHZPNIY.js +44 -0
- package/dist/{Spreadsheet-INXG5UMI.js → Spreadsheet-6Z5ACGTT.js} +14 -14
- package/dist/{Stock-CBQN2IJF.js → Stock-X3LIU4ZX.js} +4 -4
- package/dist/{Weather-2EVUTIXX.js → Weather-BLO354GM.js} +18 -18
- package/dist/{WorldClock-TZUF7MOB.js → WorldClock-BAH7QFRG.js} +7 -7
- package/dist/apps/index.js +1 -1
- package/dist/bin/ui-check.js +1 -1
- package/dist/brand.css +1 -1
- package/dist/chunk-2SSRFEOZ.js +91 -0
- package/dist/{chunk-TFETN2GI.js → chunk-4JZZLUGG.js} +1 -1
- package/dist/{chunk-GG7AE6OC.js → chunk-5K76RQML.js} +1 -1
- package/dist/chunk-5LUN632W.js +5 -0
- package/dist/chunk-5MDQNFOG.js +9 -0
- package/dist/chunk-7IQ3B77H.js +1 -0
- package/dist/{chunk-SKB6L53D.js → chunk-7PGHRG6J.js} +9 -9
- package/dist/chunk-CXJQ42XT.js +21 -0
- package/dist/chunk-DBXZS7OA.js +29 -0
- package/dist/{chunk-X4FJ54PP.js → chunk-FIEA5CGB.js} +1 -1
- package/dist/chunk-GJ37JCC2.js +1 -0
- package/dist/{chunk-KXAUDC3A.js → chunk-GWDVD3VQ.js} +27 -27
- package/dist/chunk-HQLAISFX.js +11 -0
- package/dist/chunk-I2H2CKID.js +3 -0
- package/dist/{chunk-MLYC5VQI.js → chunk-I534M65N.js} +2 -2
- package/dist/{chunk-R4XSSHDI.js → chunk-IHZL3GJU.js} +1 -1
- package/dist/chunk-K6DKX55N.js +1 -0
- package/dist/chunk-KNUR2UEG.js +1 -0
- package/dist/{chunk-JXAAZGLJ.js → chunk-MORDXCV6.js} +1 -1
- package/dist/chunk-PFKMIPZH.js +1028 -0
- package/dist/chunk-PJPK2ADX.js +1 -0
- package/dist/chunk-Q5O5UMJY.js +6 -0
- package/dist/chunk-QJHWLDEN.js +108 -0
- package/dist/chunk-R5VRLW5Z.js +1 -0
- package/dist/chunk-S3LGKIZ3.js +12 -0
- package/dist/chunk-SBF5A6XV.js +1 -0
- package/dist/chunk-SK5DL6JX.js +24 -0
- package/dist/{chunk-CLPJDJH4.js → chunk-UUYPUKP7.js} +1 -1
- package/dist/{chunk-AFYQTVZO.js → chunk-UVBK6YSR.js} +1 -1
- package/dist/chunk-VR6TR575.js +13 -0
- package/dist/{chunk-PKEQ7XOH.js → chunk-XO2AMGVU.js} +1 -1
- package/dist/{chunk-N3A3GWJI.js → chunk-YX2IMURA.js} +12 -12
- package/dist/chunk-ZEIKSMFR.js +10 -0
- package/dist/client-DLm3Fvbc.d.ts +65 -0
- package/dist/file-intake/index.js +1 -1
- package/dist/i18n/index.d.ts +1 -1
- package/dist/icons/efficient-looks.d.ts +1 -1
- package/dist/icons/efficient.d.ts +1 -1
- package/dist/icons/index.d.ts +12 -12
- package/dist/icons/index.js +1 -1
- package/dist/{index-BgM75MC6.d.ts → index-D5bms_uA.d.ts} +188 -76
- package/dist/index.d.ts +6 -4
- package/dist/index.js +639 -639
- package/dist/locales/zh-Hans.d.ts +1 -1
- package/dist/locales/zh-Hans.js +1 -1
- package/dist/map/index.js +22 -22
- package/dist/markdown/index.js +6 -6
- package/dist/markup/index.d.ts +460 -36
- package/dist/markup/index.js +1 -1
- package/dist/page-tabs/index.js +5 -5
- package/dist/pdf/index.js +1 -1
- package/dist/{registry-J-TU7zKx.d.ts → registry-Dw6QO2Ch.d.ts} +12 -9
- package/dist/{strings-BVB64Nck.d.ts → strings-fYzxZPn4.d.ts} +5 -0
- package/dist/telemetry/index.d.ts +39 -0
- package/dist/telemetry/index.js +1 -0
- package/dist/ui/index.d.ts +4 -3
- package/dist/ui/index.js +1 -1
- package/dist/ui.css +62 -21
- package/package.json +7 -21
- package/dist/Browser-6QB2QTO7.js +0 -43
- package/dist/Calculator-KOWRV2VK.js +0 -29
- package/dist/ConfirmDialog-32NLLK4K.js +0 -1
- package/dist/Documents-TGGI2QBV.js +0 -52
- package/dist/Files-KSDK3EO4.js +0 -87
- package/dist/Notepad-EKB6FJPR.js +0 -25
- package/dist/PdfViewer-KW5B44AX.js +0 -1
- package/dist/PomodoroTimer-RD5GRRA5.js +0 -91
- package/dist/Preview-AQVXKT2I.js +0 -182
- package/dist/Sidebar-VYXN5YIJ.js +0 -44
- package/dist/chunk-3GPU3JOW.js +0 -24
- package/dist/chunk-3HJTOINK.js +0 -1
- package/dist/chunk-4SWPNARR.js +0 -5
- package/dist/chunk-6LTDJKIL.js +0 -138
- package/dist/chunk-FROOMUJ7.js +0 -11
- package/dist/chunk-HRLPFUPB.js +0 -3
- package/dist/chunk-HZZNJHRH.js +0 -1
- package/dist/chunk-JEM73E4C.js +0 -21
- package/dist/chunk-L5XA5MLK.js +0 -108
- package/dist/chunk-OGXU7QFW.js +0 -12
- package/dist/chunk-RCHCT7AO.js +0 -6
- package/dist/chunk-RDQ7OXUA.js +0 -1026
- package/dist/chunk-RL626E7Q.js +0 -13
- package/dist/chunk-RMJZOKHY.js +0 -10
- package/dist/chunk-TNBCUZVE.js +0 -1
- package/dist/chunk-WRBXEZFN.js +0 -1
- package/dist/chunk-XWSWYMGM.js +0 -2
- package/dist/chunk-Z2353HNE.js +0 -9
- package/dist/chunk-ZUCYJAQH.js +0 -29
- package/dist/icons/heroicons.d.ts +0 -6
- package/dist/icons/heroicons.js +0 -1
- package/dist/icons/lucide.d.ts +0 -6
- package/dist/icons/lucide.js +0 -1
package/dist/markup/index.d.ts
CHANGED
|
@@ -1,31 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MOVED HERE FROM efficient-easel (`src/markup/index.ts` at
|
|
3
|
+
* 6d31d5df9646afd0d826394292a84b9c002f7355) — Lewis, 2026-10-12, decision D1:
|
|
4
|
+
* this grammar is THE one grammar, and it lives in efficient-shell as
|
|
5
|
+
* `efficient-shell/markup`. It replaces the shell's older, smaller grammar
|
|
6
|
+
* (the 405-line `src/markup/index.ts` of efficient-shell 5.0.0). The file below
|
|
7
|
+
* is easel's byte for byte, header included, so its history reads as written
|
|
8
|
+
* (the "WHO OWNS IT" paragraph is easel's own history, now closed: the shell
|
|
9
|
+
* owns the rule again, and easel, the admin portal and the web builder import
|
|
10
|
+
* it from here).
|
|
11
|
+
*
|
|
12
|
+
* ONE logic change from easel's copy: the read-only `++phrase++` Strong rule
|
|
13
|
+
* opens only at a WORD START — not right after a letter or a digit — so
|
|
14
|
+
* `A++ rated tyres, A++ service` stays plain text, while `++20%++` is still
|
|
15
|
+
* Strong (Lewis, 2026-10-12). See {@link InlineRule.wordStart}.
|
|
16
|
+
*
|
|
17
|
+
* Still FRAMEWORK-FREE: no React, no DOM, no imports at all. `efficient-shell/markup`
|
|
18
|
+
* is its own tsup entry, and the one subpath whose `exports` entry carries a
|
|
19
|
+
* `default` condition beside `import`, because build scripts reach it through
|
|
20
|
+
* Node's CJS loader (`tsx`) as well as through bundlers.
|
|
21
|
+
*/
|
|
1
22
|
/**
|
|
2
23
|
* The editorial markup rule — ONE grammar, shared by every product that lets a
|
|
3
24
|
* human type formatted copy into a plain text box.
|
|
4
25
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
* WHAT IS SHARED IS THE RULE, NOT THE RENDERING. Each product renders the token
|
|
25
|
-
* list its own way, because it must: the web uses CSS classes bound to theme
|
|
26
|
-
* tokens, email must inline every style (mail clients drop classes). Two
|
|
27
|
-
* renderers, one grammar, one writer ({@link applyMark}) — so a toolbar button
|
|
28
|
-
* and a parser can never disagree about what a delimiter means.
|
|
26
|
+
* WHO OWNS IT. This package does (efficient-easel; `efficient-editor` until 0.95.0, `editor-shell` until 0.66.0), since 2026-09-28. Until then the rule lived in
|
|
27
|
+
* `efficient-shell/markup`, a package Victor owns, and this package only imported
|
|
28
|
+
* it. Lewis decided to keep our own copy rather than wait on upstream for the
|
|
29
|
+
* rich text box: "Two copies is fine. We use our own independent one." This
|
|
30
|
+
* file started from efficient-shell 4.121.0 (the same file as the 4.101.0 and
|
|
31
|
+
* 4.120.0 the apps pin, bar one spelling) and grows here from now on. The two
|
|
32
|
+
* copies are expected to drift; nothing in either product reads both.
|
|
33
|
+
*
|
|
34
|
+
* FRAMEWORK-FREE, behind its own subpath (`efficient-easel/markup`): no React, no
|
|
35
|
+
* JSX, no DOM, no imports at all. The public storefront reads it, and the
|
|
36
|
+
* backend's banner renderer may one day port it, so it must stay a few hundred
|
|
37
|
+
* bytes of plain code that any bundler or resolver can load.
|
|
38
|
+
*
|
|
39
|
+
* WHAT IS SHARED IS THE RULE, NOT THE RENDERING. Each product renders the tree
|
|
40
|
+
* its own way, because it must: the web uses CSS classes bound to theme tokens,
|
|
41
|
+
* email must inline every style (mail clients drop classes). Two renderers, one
|
|
42
|
+
* grammar, one writer ({@link applyMark}) — so a toolbar button and a parser
|
|
43
|
+
* can never disagree about what a delimiter means.
|
|
29
44
|
*
|
|
30
45
|
* ## The delimiters
|
|
31
46
|
*
|
|
@@ -35,6 +50,55 @@
|
|
|
35
50
|
* _phrase_ italic
|
|
36
51
|
* ~~phrase~~ strikethrough
|
|
37
52
|
* ==phrase== highlight — the brand accent colour, applied to a selection
|
|
53
|
+
* ^^phrase^^ quiet — smaller and softer
|
|
54
|
+
*
|
|
55
|
+
* THE THREE NAMES a merchant sees ({@link MARK_NAMES}, owner-approved
|
|
56
|
+
* 2026-09-28) sit on these marks: Strong is `**`, Emphasis is `==`, Quiet is
|
|
57
|
+
* `^^`. The storefront once had separate word-style marks for Emphasis and
|
|
58
|
+
* Strong, `@@phrase@@` and `++phrase++`. Production holds none of them, and no
|
|
59
|
+
* button writes them any more, but they are still READ — as Emphasis and Strong
|
|
60
|
+
* — so a string somebody pasted never prints its delimiters.
|
|
61
|
+
*
|
|
62
|
+
* And, read by {@link parseMarkup} (the tree a rich text box and a renderer
|
|
63
|
+
* use), in every product:
|
|
64
|
+
*
|
|
65
|
+
* [words](href) a link — safe addresses only ({@link isSafeLinkHref})
|
|
66
|
+
* - words a bullet line, one level
|
|
67
|
+
* 1. words a numbered line, one level: 1-3 digits, ". ", words
|
|
68
|
+
* **a _b_ a** one run inside another, up to four levels
|
|
69
|
+
*
|
|
70
|
+
* [words]{underline} underline
|
|
71
|
+
* [words]{sup} superscript
|
|
72
|
+
* [words]{sub} subscript
|
|
73
|
+
* [words]{color=name} a theme colour, by NAME ({@link isColorName})
|
|
74
|
+
* [words]{color=#rrggbb} any colour, six hex digits ({@link isColorValue})
|
|
75
|
+
*
|
|
76
|
+
* THE SPANS AND THE NUMBERED LINE (plan step E1, approved by GG 2026-10-06)
|
|
77
|
+
* are the final text box's marks. One shape for all four, so one reading rule:
|
|
78
|
+
* `[`, words, `]`, then EXACTLY one of those blocks. Anything else after the
|
|
79
|
+
* `]` — `{foo}`, `{color=#f00}`, a merge tag's `{{` — is not a span, and the
|
|
80
|
+
* whole thing stays as typed. Two marks on the same words nest
|
|
81
|
+
* (`[[x]{sup}]{color=accent}`); one block never holds two.
|
|
82
|
+
*
|
|
83
|
+
* Why these cannot clash with an old mark: no old rule closes on `]{` (a link
|
|
84
|
+
* needs `](`), and the campaign's legacy `[phrase]` italic steps back from a
|
|
85
|
+
* span block, the way it steps back from a link (`notBeforeBlock`). No inline
|
|
86
|
+
* rule opens on a digit. Production held neither shape when they were chosen:
|
|
87
|
+
* 0 of 24,233 text values contained `]{`, and none had a line starting with a
|
|
88
|
+
* number and `.` or `)`.
|
|
89
|
+
*
|
|
90
|
+
* Not chosen: `^x^` / `~x~` (one character from Quiet `^^` and strike `~~`,
|
|
91
|
+
* and `~20 min` is ordinary copy), `__x__` (pinned as italic below, and
|
|
92
|
+
* CommonMark's bold) and `++x++` (the old Strong).
|
|
93
|
+
*
|
|
94
|
+
* Only the tree ({@link parseMarkup}) reads them. The flat
|
|
95
|
+
* {@link tokenizeInline} — the old renderers' reading — keeps them as text, as
|
|
96
|
+
* it keeps links: an email or a page drawn before its renderer learns them
|
|
97
|
+
* prints the delimiters. No toolbar button writes them yet.
|
|
98
|
+
*
|
|
99
|
+
* EVERY READING IS LINE BY LINE: a run never crosses a line break. The email
|
|
100
|
+
* always read this way; the editor's painter and the storefront used to read
|
|
101
|
+
* the whole string, so the same saved text drew differently in each.
|
|
38
102
|
*
|
|
39
103
|
* Plus a per-product LEGACY set ({@link STOREFRONT_MARKUP} /
|
|
40
104
|
* {@link CAMPAIGN_MARKUP}) that keeps already-published copy rendering exactly
|
|
@@ -72,15 +136,44 @@
|
|
|
72
136
|
* and the form to reach for. Pinned by a test, so it stays a decision rather
|
|
73
137
|
* than becoming a discovery.
|
|
74
138
|
*/
|
|
75
|
-
/** A style a toolbar button can apply. The first
|
|
76
|
-
*
|
|
77
|
-
*
|
|
78
|
-
|
|
139
|
+
/** A style a toolbar button can apply. The first six are inline marks; then
|
|
140
|
+
* the composer-only affordances (a link and the three line prefixes), which
|
|
141
|
+
* only a renderer that draws block content can honour; `clear`, which
|
|
142
|
+
* writes no mark at all — it takes them off ({@link clearMarks}); and the
|
|
143
|
+
* three spans of the final text box (E1), which no button in
|
|
144
|
+
* {@link MARKUP_TOOLS} offers yet. A colour carries a name, so it is written
|
|
145
|
+
* by {@link applyColor}, not here. */
|
|
146
|
+
type MarkStyle = 'bold' | 'italic' | 'strike' | 'code' | 'highlight' | 'quiet' | 'link' | 'bullet' | 'number' | 'quote' | 'clear' | 'underline' | 'sup' | 'sub';
|
|
147
|
+
/** What a span means: `[words]{underline}`, `{sup}`, `{sub}` or
|
|
148
|
+
* `{color=name}`. Only the tree reads these; {@link InlineKind} is the flat
|
|
149
|
+
* reading's, which never makes one. */
|
|
150
|
+
type SpanKind = 'underline' | 'sup' | 'sub' | 'color';
|
|
79
151
|
/** What a parsed run MEANS. `accent` is the storefront/campaign brand colour —
|
|
80
152
|
* the legacy `*phrase*` — and `highlight` is its standard-markdown successor;
|
|
81
153
|
* both resolve to the same paint, which is what makes converting stored copy
|
|
82
154
|
* from one to the other invisible. */
|
|
83
|
-
type InlineKind = 'text' | 'bold' | 'italic' | 'strike' | 'code' | 'highlight' | 'accent';
|
|
155
|
+
type InlineKind = 'text' | 'bold' | 'italic' | 'strike' | 'code' | 'highlight' | 'accent' | 'quiet';
|
|
156
|
+
/** A theme colour's name as a span saves it: lowercase letters, digits and
|
|
157
|
+
* `-`, starting with a letter (`accent`, `brand-2`). A name is the theme's,
|
|
158
|
+
* so changing the theme recolours the words. Never a hex — that is the other
|
|
159
|
+
* kind of colour value ({@link isColorValue}). */
|
|
160
|
+
declare function isColorName(name: string): boolean;
|
|
161
|
+
/** A colour a span may carry: a theme NAME ({@link isColorName}), or "any
|
|
162
|
+
* colour" as EXACTLY six hex digits after a `#` (`#0b5cff`). Either case
|
|
163
|
+
* reads; the writers save lowercase ({@link colorValue}). Nothing else —
|
|
164
|
+
* `#f00`, `rgb()`, a typo — is a colour, so it stays plain text.
|
|
165
|
+
*
|
|
166
|
+
* WIDENS E1 (GG 2026-10-06): the final design draws "Any color", and a
|
|
167
|
+
* feature is never cut to fit. A hex does not follow the theme; a name does. */
|
|
168
|
+
declare function isColorValue(value: string): boolean;
|
|
169
|
+
/**
|
|
170
|
+
* The words a press WRITES when nothing is selected — `**bold text**`, left
|
|
171
|
+
* selected so the next keystroke replaces it. English unless the caller of
|
|
172
|
+
* {@link applyMark} hands in its own (0.95.0: a host in another language).
|
|
173
|
+
* They are words put in the box, not rules: nothing here changes what parses.
|
|
174
|
+
*/
|
|
175
|
+
type MarkPlaceholders = Record<'bold' | 'italic' | 'strike' | 'code' | 'highlight' | 'quiet' | 'link', string> & Partial<Record<'underline' | 'sup' | 'sub' | 'color', string>>;
|
|
176
|
+
declare const MARK_PLACEHOLDERS: MarkPlaceholders;
|
|
84
177
|
interface WrapResult {
|
|
85
178
|
text: string;
|
|
86
179
|
/** Where the caret should land — inside the new marks, or after them. */
|
|
@@ -96,18 +189,93 @@ interface WrapResult {
|
|
|
96
189
|
* also unwrapped `*phrase*` would silently strip an accent run in the storefront
|
|
97
190
|
* and the campaign designer, where the asterisk means colour, not slant.
|
|
98
191
|
*/
|
|
99
|
-
declare function applyMark(text: string, start: number, end: number, style: MarkStyle): WrapResult;
|
|
100
|
-
/**
|
|
101
|
-
*
|
|
102
|
-
*
|
|
192
|
+
declare function applyMark(text: string, start: number, end: number, style: MarkStyle, rules?: readonly InlineRule[], placeholders?: MarkPlaceholders): WrapResult;
|
|
193
|
+
/**
|
|
194
|
+
* Colour `text[start:end]` with `name` — a theme colour name or a 6-digit hex
|
|
195
|
+
* ({@link isColorValue}; a hex is saved lowercase) — writing
|
|
196
|
+
* `[words]{color=name}` and leaving the words selected. On words that are
|
|
197
|
+
* already exactly one colour span it changes the colour; `null` takes it
|
|
198
|
+
* off. A value {@link isColorValue} refuses changes nothing — `#f00` or a typo
|
|
199
|
+
* is never saved as a block the reader would print as text.
|
|
200
|
+
*
|
|
201
|
+
* Separate from {@link applyMark} because a colour carries a value, as a link
|
|
202
|
+
* does ({@link writeLink}).
|
|
203
|
+
*/
|
|
204
|
+
declare function applyColor(text: string, start: number, end: number, name: string | null, placeholders?: MarkPlaceholders): WrapResult;
|
|
205
|
+
/**
|
|
206
|
+
* True when `text[start:end]` is ALREADY wrapped in `style`'s own fence — the
|
|
207
|
+
* very test {@link applyMark} uses to decide that a press unwraps. So a button
|
|
208
|
+
* drawn as pressed is exactly a button whose press takes the mark off; the two
|
|
209
|
+
* cannot disagree. False for a style with no fence (a link, a line prefix).
|
|
210
|
+
*/
|
|
211
|
+
declare function markedAt(text: string, start: number, end: number, style: MarkStyle): boolean;
|
|
212
|
+
/** A link as it sits in authored text: where it starts and ends, its words and
|
|
213
|
+
* its address. */
|
|
214
|
+
interface LinkSpan {
|
|
215
|
+
start: number;
|
|
216
|
+
end: number;
|
|
217
|
+
label: string;
|
|
218
|
+
href: string;
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* The link the caret or selection sits in — `[words](href)` covering all of
|
|
222
|
+
* `start..end` — or null. What the link button opens on: inside a link it edits
|
|
223
|
+
* that link, anywhere else it makes a new one.
|
|
224
|
+
*
|
|
225
|
+
* Read with the parser's own rule ({@link linkAt}), so a span this returns is
|
|
226
|
+
* exactly one the renderers draw as a link — an unsafe address is not a link
|
|
227
|
+
* and is not offered for editing as one.
|
|
228
|
+
*/
|
|
229
|
+
declare function findLink(text: string, start: number, end: number): LinkSpan | null;
|
|
230
|
+
/**
|
|
231
|
+
* Make `text[start:end]` a link to `href`, or re-point the link it sits in.
|
|
232
|
+
* The caret lands after the link, selecting nothing: the link is finished.
|
|
233
|
+
*
|
|
234
|
+
* The words are the selection, or — with nothing selected — the address
|
|
235
|
+
* itself, so a merchant who pastes an address and presses Apply gets a link
|
|
236
|
+
* that reads as that address rather than a placeholder to type over.
|
|
237
|
+
*
|
|
238
|
+
* ⚠️ The address is the CALLER'S to check ({@link isSafeLinkHref}): one that
|
|
239
|
+
* fails would be written as plain text the renderers never draw as a link.
|
|
240
|
+
*/
|
|
241
|
+
declare function writeLink(text: string, start: number, end: number, href: string): WrapResult;
|
|
242
|
+
/** Take a link off, keeping its words — selected, so a second press of the
|
|
243
|
+
* link button puts it straight back. */
|
|
244
|
+
declare function removeLink(text: string, link: LinkSpan): WrapResult;
|
|
245
|
+
/**
|
|
246
|
+
* One toolbar button.
|
|
247
|
+
*
|
|
248
|
+
* - `label` is a text glyph, never a word, for a host that draws type (the
|
|
249
|
+
* message composer). The copy box draws the icon set's glyph instead.
|
|
250
|
+
* - `name` is what the button is CALLED: its accessible name, and the first
|
|
251
|
+
* word of its tooltip. Approved 2026-10-02: no word is drawn ON a button,
|
|
252
|
+
* so a name lives here and in `title` and nowhere a merchant reads it as
|
|
253
|
+
* part of the bar.
|
|
254
|
+
* - `title` is the tooltip: the name, what the mark writes, and the shortcut.
|
|
255
|
+
* - `shortcut` is the key the host combines with its platform modifier: a bare
|
|
256
|
+
* letter (`'b'`), or `'shift+'` and a letter.
|
|
257
|
+
*/
|
|
103
258
|
interface MarkupTool {
|
|
104
259
|
style: MarkStyle;
|
|
105
260
|
label: string;
|
|
106
261
|
title: string;
|
|
262
|
+
name?: string;
|
|
107
263
|
shortcut?: string;
|
|
108
264
|
}
|
|
109
|
-
/** Every button, in the order a writer reaches for them.
|
|
265
|
+
/** Every button, in the order a writer reaches for them. Clear is last: it
|
|
266
|
+
* acts on every mark before it. */
|
|
110
267
|
declare const MARKUP_TOOLS: readonly MarkupTool[];
|
|
268
|
+
/**
|
|
269
|
+
* The names a merchant sees for the three styles that carry one, in both
|
|
270
|
+
* editors (owner-approved 2026-09-28). One word per idea: Strong IS bold
|
|
271
|
+
* (`**`, ⌘B) and Emphasis IS the highlight (`==`), so a toolbar that shows the
|
|
272
|
+
* names shows no separate B or ◆ beside them.
|
|
273
|
+
*/
|
|
274
|
+
declare const MARK_NAMES: {
|
|
275
|
+
readonly bold: "Strong";
|
|
276
|
+
readonly highlight: "Emphasis";
|
|
277
|
+
readonly quiet: "Quiet";
|
|
278
|
+
};
|
|
111
279
|
/** The tools a host shows, resolved to descriptors in {@link MARKUP_TOOLS}
|
|
112
280
|
* order. Keeps a host from hand-rebuilding a descriptor (and drifting on a
|
|
113
281
|
* tooltip) just to pick a subset. */
|
|
@@ -141,6 +309,23 @@ interface InlineRule {
|
|
|
141
309
|
* more rule field and no new branch in {@link tokenizeInline}.
|
|
142
310
|
*/
|
|
143
311
|
readonly notBefore?: string;
|
|
312
|
+
/**
|
|
313
|
+
* True when the run may not close right before a span block (`{sup}`,
|
|
314
|
+
* `{color=accent}`, …). The campaign's legacy `[phrase]` needs it for the
|
|
315
|
+
* reason it needs `notBefore: '('`: without it `[x]{sup}` would read as an
|
|
316
|
+
* italic `x` followed by a printed `{sup}`. Only the four exact blocks count,
|
|
317
|
+
* so `[x]{{first_name}}` and `[x]{foo}` read as they always did.
|
|
318
|
+
*/
|
|
319
|
+
readonly notBeforeBlock?: boolean;
|
|
320
|
+
/**
|
|
321
|
+
* True when the run may only OPEN at a word start: the open may not follow a
|
|
322
|
+
* letter or a digit (any script). The read-only `++` Strong needs it, because
|
|
323
|
+
* `++` is ordinary copy after a word — "A++ rated tyres, A++ service" would
|
|
324
|
+
* otherwise read as one Strong run from the first `A++` to the second. Only
|
|
325
|
+
* the open is checked, so "Save ++20%++ today" is still Strong. Lewis,
|
|
326
|
+
* 2026-10-12 (D1).
|
|
327
|
+
*/
|
|
328
|
+
readonly wordStart?: boolean;
|
|
144
329
|
}
|
|
145
330
|
/**
|
|
146
331
|
* The standard-markdown marks, shared by every product.
|
|
@@ -154,6 +339,14 @@ interface InlineRule {
|
|
|
154
339
|
* what actually does the work.
|
|
155
340
|
*/
|
|
156
341
|
declare const STANDARD_MARKUP: readonly InlineRule[];
|
|
342
|
+
/**
|
|
343
|
+
* Marks the copy box no longer OFFERS (E5a, 2026-10-06: Lewis dropped
|
|
344
|
+
* Emphasis `==` and Quiet `^^` from the final design). They are still read,
|
|
345
|
+
* drawn and written back byte for byte — saved copy wears them — but no bar
|
|
346
|
+
* button writes them, and `CopyBox` draws none for them even when a host asks.
|
|
347
|
+
* Declared before {@link COPY_FIELD_TOOLS} reads it at module load.
|
|
348
|
+
*/
|
|
349
|
+
declare const RETIRED_MARKS: readonly MarkStyle[];
|
|
157
350
|
/**
|
|
158
351
|
* The buttons a COPY FIELD offers — a storefront section's copy box and a
|
|
159
352
|
* campaign block's copy box show exactly these, so a merchant meets one toolbar
|
|
@@ -167,7 +360,7 @@ declare const STANDARD_MARKUP: readonly InlineRule[];
|
|
|
167
360
|
* parser read as something else. Now a style with no rule cannot appear here,
|
|
168
361
|
* whatever anyone types into the array.
|
|
169
362
|
*
|
|
170
|
-
* It resolves to bold, italic, strike and
|
|
363
|
+
* It resolves to bold, italic, strike, highlight and quiet. `code` is the one that
|
|
171
364
|
* surprises: it is an inline mark and it has a fence, but no rule reads a
|
|
172
365
|
* backtick, so a copy field would print `` `word` `` verbatim — and a button
|
|
173
366
|
* whose output the renderer draws as literal text is worse than no button.
|
|
@@ -231,5 +424,236 @@ declare function tokenizeInline(value: string, rules: readonly InlineRule[]): In
|
|
|
231
424
|
* visitor actually sees.
|
|
232
425
|
*/
|
|
233
426
|
declare function stripInline(value: string, rules: readonly InlineRule[]): string;
|
|
427
|
+
/** Plain words. */
|
|
428
|
+
interface MarkupText {
|
|
429
|
+
kind: 'text';
|
|
430
|
+
text: string;
|
|
431
|
+
}
|
|
432
|
+
/** A delimited run. `open` and `close` are the delimiters that were actually
|
|
433
|
+
* saved — `#` for a legacy campaign bold, `**` for the standard one, `[` and
|
|
434
|
+
* `]{sup}` for a span — so the tree writes back the same bytes it was read
|
|
435
|
+
* from. `color` is the theme colour's name, on a `color` span only. */
|
|
436
|
+
interface MarkupRun {
|
|
437
|
+
kind: InlineRule['kind'] | SpanKind;
|
|
438
|
+
open: string;
|
|
439
|
+
close: string;
|
|
440
|
+
color?: string;
|
|
441
|
+
children: MarkupNode[];
|
|
442
|
+
}
|
|
443
|
+
/** `[words](href)`. Only made when {@link isSafeLinkHref} passes. */
|
|
444
|
+
interface MarkupLink {
|
|
445
|
+
kind: 'link';
|
|
446
|
+
href: string;
|
|
447
|
+
children: MarkupNode[];
|
|
448
|
+
}
|
|
449
|
+
type MarkupNode = MarkupText | MarkupRun | MarkupLink;
|
|
450
|
+
/** One line of the saved string. `bullet` means it was saved as `- words`;
|
|
451
|
+
* `number` holds the digits of a line saved as `12. words`, as typed (`01`
|
|
452
|
+
* stays `01`), and is null on every other line. `children` hold what follows
|
|
453
|
+
* the prefix. A line built by hand may leave `number` out: it means null. */
|
|
454
|
+
interface MarkupLine {
|
|
455
|
+
bullet: boolean;
|
|
456
|
+
number?: string | null;
|
|
457
|
+
children: MarkupNode[];
|
|
458
|
+
}
|
|
459
|
+
/**
|
|
460
|
+
* True for an address a link may carry: `http`, `https`, `mailto` or `tel`, or
|
|
461
|
+
* one with no scheme at all (`/tyres`, `#top`, `terms.html`, `//cdn…`).
|
|
462
|
+
* Anything else — `javascript:`, `data:`, `file:` — is refused, and so is an
|
|
463
|
+
* address with any space or control character in it, because browsers drop
|
|
464
|
+
* those before they read the scheme (`java\tscript:` runs as `javascript:`).
|
|
465
|
+
*
|
|
466
|
+
* Renderers call this too, before they write an `href`, so the rule has one
|
|
467
|
+
* home.
|
|
468
|
+
*/
|
|
469
|
+
declare function isSafeLinkHref(href: string): boolean;
|
|
470
|
+
/**
|
|
471
|
+
* Read authored text into lines of nodes — the whole grammar, for a rich text
|
|
472
|
+
* box and for the renderers that draw links and bullets.
|
|
473
|
+
*
|
|
474
|
+
* - A run never crosses a line break.
|
|
475
|
+
* - A line that starts with `- ` and has words after it is a bullet. One level
|
|
476
|
+
* only: an indented ` - ` is plain text.
|
|
477
|
+
* - A line that starts with 1-3 digits, `. ` and words is numbered, the digits
|
|
478
|
+
* kept as typed. One level only, as bullets.
|
|
479
|
+
* - `[words](href)` is a link when {@link isSafeLinkHref} passes; otherwise the
|
|
480
|
+
* whole thing stays plain text.
|
|
481
|
+
* - `[words]{underline}`, `{sup}`, `{sub}` and `{color=name}` are spans; any
|
|
482
|
+
* other block stays plain text.
|
|
483
|
+
* - A run's words are read again, so `**bold _with italic_**` is italic inside
|
|
484
|
+
* bold. Four levels: a fifth stays as typed.
|
|
485
|
+
*
|
|
486
|
+
* Nothing is lost: {@link serializeMarkup} writes back the exact bytes.
|
|
487
|
+
*/
|
|
488
|
+
declare function parseMarkup(value: string, rules: readonly InlineRule[]): MarkupLine[];
|
|
489
|
+
/** Write lines back to authored text: the inverse of {@link parseMarkup}. */
|
|
490
|
+
declare function serializeMarkup(lines: readonly MarkupLine[]): string;
|
|
491
|
+
/**
|
|
492
|
+
* One run a character sits in. `id` says WHICH run: two characters with the
|
|
493
|
+
* same id are in one run, so `**a****b**` (two bold runs, back to back) is told
|
|
494
|
+
* apart from `**ab**` (one) and is written back as it was saved.
|
|
495
|
+
*
|
|
496
|
+
* `open` and `close` are the delimiters that were saved (`#` for a legacy
|
|
497
|
+
* campaign bold), or, for a run made in the editor, the toolbar's own fence.
|
|
498
|
+
* A link's `close` is `](href)`, a span's `]{sup}` or `]{color=name}`.
|
|
499
|
+
*/
|
|
500
|
+
interface MarkSpan {
|
|
501
|
+
id: number;
|
|
502
|
+
kind: InlineRule['kind'] | SpanKind | 'link';
|
|
503
|
+
open: string;
|
|
504
|
+
close: string;
|
|
505
|
+
href?: string;
|
|
506
|
+
color?: string;
|
|
507
|
+
}
|
|
508
|
+
/**
|
|
509
|
+
* A NEW run, as the toolbar writes it: `**` for bold, `_` for italic, and so on
|
|
510
|
+
* ({@link applyMark}'s own fences), a link to `value`, or a colour span of
|
|
511
|
+
* `value` — a theme name or a 6-digit hex, saved lowercase ({@link isColorValue}). Null for a style that writes no run (a line
|
|
512
|
+
* prefix, clear) and for a link or colour with no usable value. A paste filter
|
|
513
|
+
* or an editor making a run asks here, so no delimiter is spelled outside this
|
|
514
|
+
* module (E8).
|
|
515
|
+
*/
|
|
516
|
+
declare function spanFor(id: number, style: MarkStyle | 'color', value?: string): MarkSpan | null;
|
|
517
|
+
/** One character of the words — never a delimiter — with the runs it sits in,
|
|
518
|
+
* outside first, and its offset in the saved string. */
|
|
519
|
+
interface MarkedChar {
|
|
520
|
+
ch: string;
|
|
521
|
+
marks: readonly MarkSpan[];
|
|
522
|
+
at: number;
|
|
523
|
+
}
|
|
524
|
+
/** One line: its bullet flag or its number (the `- ` and the `12. ` are not
|
|
525
|
+
* characters) and its words. `number` left out means null, as on
|
|
526
|
+
* {@link MarkupLine}. */
|
|
527
|
+
interface MarkedLine {
|
|
528
|
+
bullet: boolean;
|
|
529
|
+
number?: string | null;
|
|
530
|
+
chars: MarkedChar[];
|
|
531
|
+
}
|
|
532
|
+
/**
|
|
533
|
+
* Read authored text as characters, each carrying its runs — what an editor
|
|
534
|
+
* that hides the delimiters edits, and what {@link clearMarks} splits runs on.
|
|
535
|
+
*
|
|
536
|
+
* Built on {@link parseMarkup}, so it is the same reading, character by
|
|
537
|
+
* character. A character is a code point (an emoji is one, two UTF-16 units
|
|
538
|
+
* long); `at` counts UTF-16 units, as a text box's selection does.
|
|
539
|
+
*
|
|
540
|
+
* {@link writeMarkedLines} writes it back byte for byte.
|
|
541
|
+
*/
|
|
542
|
+
declare function markedLines(value: string, rules: readonly InlineRule[]): MarkedLine[];
|
|
543
|
+
/**
|
|
544
|
+
* Write characters back to authored text: the inverse of {@link markedLines}.
|
|
545
|
+
* Returns where each character landed (`at[line][char]`), so a selection can be
|
|
546
|
+
* carried across the write.
|
|
547
|
+
*
|
|
548
|
+
* Runs are opened and closed as the characters ask: a character outside a run
|
|
549
|
+
* that its neighbours are in closes it, and the run's next character opens it
|
|
550
|
+
* again. That is how a run is SPLIT — clear the middle of `**abcd**` and it is
|
|
551
|
+
* written `**a**bc**d**`. Whether the result reads back as written is the
|
|
552
|
+
* caller's to check ({@link sameMarks}): `_` cannot close against a letter.
|
|
553
|
+
*/
|
|
554
|
+
declare function writeMarkedLines(lines: readonly MarkedLine[]): {
|
|
555
|
+
text: string;
|
|
556
|
+
at: number[][];
|
|
557
|
+
};
|
|
558
|
+
/** True when two readings hold the same words wearing the same marks — the
|
|
559
|
+
* kinds, addresses, colours and list numbers, not which run or which
|
|
560
|
+
* delimiter. */
|
|
561
|
+
declare function sameMarks(a: readonly MarkedLine[], b: readonly MarkedLine[]): boolean;
|
|
562
|
+
/**
|
|
563
|
+
* Take every mark off `text[start:end]`, keeping the words and any link (a
|
|
564
|
+
* link has its own Remove). A run the selection only partly covers is split,
|
|
565
|
+
* so the rest of it keeps its mark. Bullets and numbers stay: they are lines,
|
|
566
|
+
* not marks.
|
|
567
|
+
*
|
|
568
|
+
* With nothing selected, the runs the caret touches — the characters either
|
|
569
|
+
* side of it — come off whole.
|
|
570
|
+
*
|
|
571
|
+
* A split the grammar cannot hold comes off whole instead: the middle of
|
|
572
|
+
* `_word_` would leave an underscore against a letter, which reads as a
|
|
573
|
+
* literal underscore. And if even that would not read back, nothing changes.
|
|
574
|
+
*/
|
|
575
|
+
declare function clearMarks(text: string, start: number, end: number, rules?: readonly InlineRule[]): WrapResult;
|
|
576
|
+
/**
|
|
577
|
+
* The final toolbar's Clear style (owner ruling, 2026-10-07): take EVERY mark
|
|
578
|
+
* off the WORDS in `text[start:end]` but a link, keeping the words selected —
|
|
579
|
+
* the bar's (bold, italic, underline, strikethrough, colour, superscript,
|
|
580
|
+
* subscript) and the retired ones it no longer offers (Emphasis, Quiet, the
|
|
581
|
+
* legacy accent), so the words come back plain (GG, 2026-10-07). A link is
|
|
582
|
+
* content, not style; a line's bullet or number is a line, not a mark.
|
|
583
|
+
*
|
|
584
|
+
* A run the selection only partly covers is split, so the rest of it keeps
|
|
585
|
+
* its mark; a split the grammar cannot hold (the middle of `_word_`) takes the
|
|
586
|
+
* run off whole; and if even that would not read back, nothing changes.
|
|
587
|
+
*
|
|
588
|
+
* With nothing selected nothing changes: the button is disabled then, so a
|
|
589
|
+
* press can never wipe a whole paragraph. Unlike {@link clearMarks} (the 0.94
|
|
590
|
+
* bar's Clear marks), which with a caret takes off the runs it touches.
|
|
591
|
+
*/
|
|
592
|
+
declare function clearStyle(text: string, start: number, end: number, rules?: readonly InlineRule[]): WrapResult;
|
|
593
|
+
/**
|
|
594
|
+
* Press `style` on the WORDS in `text[start:end]`, whichever runs they sit in —
|
|
595
|
+
* what a view that hides the delimiters needs, where `applyMark` (which wraps
|
|
596
|
+
* exactly the characters selected) would cross or strand a delimiter.
|
|
597
|
+
*
|
|
598
|
+
* - Every selected word already wears the mark: it comes off them. Part of a
|
|
599
|
+
* run is split off; the rest keeps the mark.
|
|
600
|
+
* - Otherwise the mark goes on, as ONE run over the words and any run of the
|
|
601
|
+
* same mark they touch (`**half** off` → `**half off**`).
|
|
602
|
+
* - Nothing is written that would not read back: a third level of nesting,
|
|
603
|
+
* or `_` inside a word, leaves the text as it was.
|
|
604
|
+
* - With nothing selected it is {@link applyMark}: a selected placeholder.
|
|
605
|
+
*
|
|
606
|
+
* Offsets are the saved string's, before and after.
|
|
607
|
+
*/
|
|
608
|
+
declare function toggleMark(text: string, start: number, end: number, style: MarkStyle, rules?: readonly InlineRule[]): WrapResult;
|
|
609
|
+
/**
|
|
610
|
+
* The marks every word in `text[start:end]` wears — `bold`, `link`, a legacy
|
|
611
|
+
* `accent` … — or, with nothing selected, the marks of the word just before the
|
|
612
|
+
* caret on its line: what typing there would continue. What a toolbar draws
|
|
613
|
+
* as pressed in a view without delimiters.
|
|
614
|
+
*/
|
|
615
|
+
declare function marksIn(text: string, start: number, end: number, rules?: readonly InlineRule[]): Set<string>;
|
|
616
|
+
/**
|
|
617
|
+
* Link the WORDS in `text[start:end]` to `href`, nesting with any run they
|
|
618
|
+
* sit in rather than crossing it: words inside a bold run become a link inside
|
|
619
|
+
* it (`**Book [a fitting](/book)**`), a whole bold run goes inside the link.
|
|
620
|
+
*
|
|
621
|
+
* With nothing selected, inside a link it re-points that link; anywhere else
|
|
622
|
+
* it writes the address as its own words ({@link writeLink}). The caret lands
|
|
623
|
+
* after the link. ⚠️ The address is the caller's to check ({@link isSafeLinkHref}).
|
|
624
|
+
*/
|
|
625
|
+
declare function linkOver(text: string, start: number, end: number, href: string, rules?: readonly InlineRule[]): WrapResult;
|
|
626
|
+
/** Take off the link the caret or selection touches, keeping its words —
|
|
627
|
+
* selected, so a second press of the link button puts it straight back. */
|
|
628
|
+
declare function unlinkAt(text: string, start: number, end: number, rules?: readonly InlineRule[]): WrapResult;
|
|
629
|
+
/**
|
|
630
|
+
* Colour the WORDS in `text[start:end]` with `name` — a theme colour name or
|
|
631
|
+
* a 6-digit hex, saved lowercase (`[words]{color=name}`), nesting with any run they sit in rather than
|
|
632
|
+
* crossing it — the colour window's write, as {@link linkOver} is the link
|
|
633
|
+
* window's. A colour the words already wear is replaced; `null` takes the
|
|
634
|
+
* colour off them, splitting a run that only partly covers them.
|
|
635
|
+
*
|
|
636
|
+
* A value {@link isColorValue} refuses (`#f00`, a word with a space) changes
|
|
637
|
+
* nothing: a block the reader would print as text is never written. With
|
|
638
|
+
* nothing selected nothing changes either — the box keeps a pending colour
|
|
639
|
+
* for the words typed next instead.
|
|
640
|
+
*/
|
|
641
|
+
declare function colorOver(text: string, start: number, end: number, name: string | null, rules?: readonly InlineRule[]): WrapResult;
|
|
642
|
+
/** The ONE colour every word in `text[start:end]` wears — or, with nothing
|
|
643
|
+
* selected, the word before the caret on its line — or null. What the colour
|
|
644
|
+
* window draws as chosen, and the colour under the A. */
|
|
645
|
+
declare function colorIn(text: string, start: number, end: number, rules?: readonly InlineRule[]): string | null;
|
|
646
|
+
/**
|
|
647
|
+
* Make every line `text[start:end]` touches (the caret's line, with nothing
|
|
648
|
+
* selected) a bulleted list, a numbered list, or — `null` — no list. The
|
|
649
|
+
* words and their marks keep their bytes; only the line prefixes change. A
|
|
650
|
+
* numbered list counts on from a numbered line just above it, else from 1.
|
|
651
|
+
* An empty line becomes an empty list line (`- `), which the rich view draws
|
|
652
|
+
* as a bullet with nothing after it yet. The selection keeps its words.
|
|
653
|
+
*/
|
|
654
|
+
declare function setList(text: string, start: number, end: number, kind: 'bullet' | 'number' | null, rules?: readonly InlineRule[]): WrapResult;
|
|
655
|
+
/** `bullet` or `number` when every line `text[start:end]` touches is that
|
|
656
|
+
* kind of list line, else null — what the list buttons draw as pressed. */
|
|
657
|
+
declare function listIn(text: string, start: number, end: number, rules?: readonly InlineRule[]): 'bullet' | 'number' | null;
|
|
234
658
|
|
|
235
|
-
export { CAMPAIGN_MARKUP, COPY_FIELD_TOOLS, type InlineKind, type InlineRule, type InlineToken, MARKUP_TOOLS, type MarkStyle, type MarkupTool, STANDARD_MARKUP, STOREFRONT_MARKUP, type WrapResult, applyMark, markupTools, stripInline, tokenizeInline };
|
|
659
|
+
export { CAMPAIGN_MARKUP, COPY_FIELD_TOOLS, type InlineKind, type InlineRule, type InlineToken, type LinkSpan, MARKUP_TOOLS, MARK_NAMES, MARK_PLACEHOLDERS, type MarkPlaceholders, type MarkSpan, type MarkStyle, type MarkedChar, type MarkedLine, type MarkupLine, type MarkupLink, type MarkupNode, type MarkupRun, type MarkupText, type MarkupTool, RETIRED_MARKS, STANDARD_MARKUP, STOREFRONT_MARKUP, type SpanKind, type WrapResult, applyColor, applyMark, clearMarks, clearStyle, colorIn, colorOver, findLink, isColorName, isColorValue, isSafeLinkHref, linkOver, listIn, markedAt, markedLines, marksIn, markupTools, parseMarkup, removeLink, sameMarks, serializeMarkup, setList, spanFor, stripInline, toggleMark, tokenizeInline, unlinkAt, writeLink, writeMarkedLines };
|
package/dist/markup/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
export{CAMPAIGN_MARKUP,COPY_FIELD_TOOLS,MARKUP_TOOLS,MARK_NAMES,MARK_PLACEHOLDERS,RETIRED_MARKS,STANDARD_MARKUP,STOREFRONT_MARKUP,applyColor,applyMark,clearMarks,clearStyle,colorIn,colorOver,findLink,isColorName,isColorValue,isSafeLinkHref,linkOver,listIn,markedAt,markedLines,marksIn,markupTools,parseMarkup,removeLink,sameMarks,serializeMarkup,setList,spanFor,stripInline,toggleMark,tokenizeInline,unlinkAt,writeLink,writeMarkedLines}from"../chunk-PJPK2ADX.js";
|