beez-ui 0.6.2 → 0.8.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/CHANGELOG.md +150 -96
- package/README.md +33 -6
- package/dist/components/account-menu.d.ts +53 -0
- package/dist/components/account-menu.js +405 -0
- package/dist/components/alert.js +1 -1
- package/dist/components/animated-collapse.d.ts +19 -0
- package/dist/components/animated-collapse.js +81 -0
- package/dist/components/animated-count.d.ts +13 -0
- package/dist/components/animated-count.js +105 -0
- package/dist/components/animated-list-item.d.ts +25 -0
- package/dist/components/animated-list-item.js +132 -0
- package/dist/components/avatar.d.ts +2 -1
- package/dist/components/avatar.js +4 -3
- package/dist/components/bouncing-dots-loader.d.ts +19 -0
- package/dist/components/bouncing-dots-loader.js +47 -0
- package/dist/components/calendar.js +102 -0
- package/dist/components/carousel.js +61 -48
- package/dist/components/checkbox.js +1 -1
- package/dist/components/confirm-delete-button.d.ts +29 -0
- package/dist/components/confirm-delete-button.js +254 -0
- package/dist/components/data-table.js +34 -4
- package/dist/components/dropdown-menu.js +5 -2
- package/dist/components/empty-state.d.ts +24 -0
- package/dist/components/empty-state.js +37 -0
- package/dist/components/error-state.d.ts +20 -0
- package/dist/components/error-state.js +145 -0
- package/dist/components/external-browser-handoff.d.ts +27 -0
- package/dist/components/external-browser-handoff.js +306 -0
- package/dist/components/file-upload.d.ts +78 -0
- package/dist/components/file-upload.js +678 -0
- package/dist/components/filter-query-bar.js +11 -6
- package/dist/components/form.d.ts +5 -0
- package/dist/components/form.js +11 -9
- package/dist/components/info-popover.d.ts +23 -0
- package/dist/components/info-popover.js +158 -0
- package/dist/components/input-group.js +1 -1
- package/dist/components/input.js +1 -1
- package/dist/components/month-calendar-header.d.ts +65 -0
- package/dist/components/month-calendar-header.js +337 -0
- package/dist/components/month-grid.d.ts +59 -0
- package/dist/components/month-grid.js +301 -0
- package/dist/components/notification-bell.d.ts +50 -0
- package/dist/components/notification-bell.js +338 -0
- package/dist/components/notification-panel.d.ts +56 -0
- package/dist/components/notification-panel.js +281 -0
- package/dist/components/open-in-browser-cta.d.ts +22 -0
- package/dist/components/open-in-browser-cta.js +61 -0
- package/dist/components/pagination.d.ts +1 -0
- package/dist/components/pagination.js +9 -4
- package/dist/components/presence-swap.d.ts +22 -0
- package/dist/components/presence-swap.js +162 -0
- package/dist/components/progress-ring.d.ts +20 -0
- package/dist/components/progress-ring.js +53 -0
- package/dist/components/pwa-update-control.d.ts +18 -0
- package/dist/components/pwa-update-control.js +119 -0
- package/dist/components/radio-group.js +1 -1
- package/dist/components/reaction-button.d.ts +26 -0
- package/dist/components/reaction-button.js +114 -0
- package/dist/components/rich-link-editor.d.ts +25 -0
- package/dist/components/rich-link-editor.js +320 -0
- package/dist/components/rich-markdown-content.d.ts +10 -0
- package/dist/components/rich-markdown-content.js +56 -0
- package/dist/components/rich-text-content.d.ts +19 -0
- package/dist/components/rich-text-content.js +26 -0
- package/dist/components/select.js +1 -1
- package/dist/components/sheet.js +12 -9
- package/dist/components/sidebar.js +9 -5
- package/dist/components/skeleton.d.ts +6 -0
- package/dist/components/skeleton.js +7 -1
- package/dist/components/switch.js +1 -1
- package/dist/components/textarea.js +1 -1
- package/dist/components/typing-animation.js +42 -15
- package/dist/emoji-picker.d.ts +27 -0
- package/dist/emoji-picker.js +283 -0
- package/dist/hooks/use-horizontal-swipe.d.ts +23 -0
- package/dist/hooks/use-horizontal-swipe.js +80 -0
- package/dist/hooks/use-is-hydrated.d.ts +6 -0
- package/dist/hooks/use-is-hydrated.js +20 -0
- package/dist/hooks/use-minute-clock.d.ts +23 -0
- package/dist/hooks/use-minute-clock.js +147 -0
- package/dist/hooks/use-month-transition-direction.d.ts +21 -0
- package/dist/hooks/use-month-transition-direction.js +110 -0
- package/dist/hooks/use-rich-link-editor.d.ts +55 -0
- package/dist/hooks/use-rich-link-editor.js +515 -0
- package/dist/hooks/use-viewer-time-zone.d.ts +6 -0
- package/dist/hooks/use-viewer-time-zone.js +20 -0
- package/dist/index.d.ts +44 -0
- package/dist/index.js +43 -0
- package/dist/lib/browser-clipboard.d.ts +13 -0
- package/dist/lib/browser-clipboard.js +48 -0
- package/dist/lib/browser-navigation.d.ts +21 -0
- package/dist/lib/browser-navigation.js +42 -0
- package/dist/lib/column-filter-value.d.ts +12 -0
- package/dist/lib/column-filter-value.js +52 -0
- package/dist/lib/file-acceptance.d.ts +43 -0
- package/dist/lib/file-acceptance.js +107 -0
- package/dist/lib/format-file-size.d.ts +16 -0
- package/dist/lib/format-file-size.js +34 -0
- package/dist/lib/fuzzy-search.d.ts +17 -0
- package/dist/lib/fuzzy-search.js +183 -0
- package/dist/lib/horizontal-swipe.d.ts +23 -0
- package/dist/lib/horizontal-swipe.js +29 -0
- package/dist/lib/in-app-browser.d.ts +35 -0
- package/dist/lib/in-app-browser.js +80 -0
- package/dist/lib/month-grid.d.ts +42 -0
- package/dist/lib/month-grid.js +74 -0
- package/dist/lib/name-initials.d.ts +7 -0
- package/dist/lib/name-initials.js +11 -0
- package/dist/lib/rich-text/link-markdown-constants.d.ts +147 -0
- package/dist/lib/rich-text/link-markdown-constants.js +458 -0
- package/dist/lib/rich-text/link-markdown-types.d.ts +53 -0
- package/dist/lib/rich-text/link-markdown-types.js +1 -0
- package/dist/lib/rich-text/link-markdown.d.ts +193 -0
- package/dist/lib/rich-text/link-markdown.js +592 -0
- package/dist/lib/rich-text/rich-markdown.d.ts +41 -0
- package/dist/lib/rich-text/rich-markdown.js +105 -0
- package/dist/lib/rich-text/rich-text-editor-dom.d.ts +26 -0
- package/dist/lib/rich-text/rich-text-editor-dom.js +79 -0
- package/dist/motion/glide-indicator.d.ts +37 -3
- package/dist/motion/glide-indicator.js +37 -3
- package/dist/motion/motion-slot.js +47 -18
- package/dist/motion/surface-keyframes.js +18 -6
- package/dist/motion/tokens.d.ts +41 -2
- package/dist/motion/tokens.js +40 -1
- package/dist/providers/beez-ui-provider.js +49 -17
- package/dist/styles.css +1 -1
- package/package.json +212 -2
|
@@ -0,0 +1,458 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared constants for the rich-text link layer.
|
|
3
|
+
*
|
|
4
|
+
* These values back both the read-only renderer (`RichTextContent`) and the
|
|
5
|
+
* rich link editor (`RichLinkEditor` / `useRichLinkEditor`). They are framework
|
|
6
|
+
* safe and free of business rules, so they live under `lib` and can be reused by
|
|
7
|
+
* any feature that needs autolinking plus `[text](url)` markdown support.
|
|
8
|
+
*/
|
|
9
|
+
/** URL protocols accepted when normalizing a markdown link target. */
|
|
10
|
+
export const LINK_MARKDOWN_ALLOWED_PROTOCOL = {
|
|
11
|
+
http: "http:",
|
|
12
|
+
https: "https:"
|
|
13
|
+
};
|
|
14
|
+
/** Protocol prepended to bare domains that lack an explicit scheme. */
|
|
15
|
+
export const LINK_PROTOCOL_PREFIX = { default: "https://" };
|
|
16
|
+
/** Tokens used to assemble and recognize `[text](url)` markdown links. */
|
|
17
|
+
export const LINK_MARKDOWN_FORMAT = {
|
|
18
|
+
closeLabel: "]",
|
|
19
|
+
closeUrl: ")",
|
|
20
|
+
openLabel: "[",
|
|
21
|
+
openUrl: "](",
|
|
22
|
+
suppressedUrl: "#"
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* Parentheses that the `[text](url)` markdown URL group cannot represent
|
|
26
|
+
* unescaped, paired with their percent-encoded equivalents. The URL group only
|
|
27
|
+
* accepts balanced single-level `(...)` pairs, so any other paren must be
|
|
28
|
+
* encoded when serializing a link target; browsers decode `%28`/`%29` back to
|
|
29
|
+
* the literal character when the link is opened.
|
|
30
|
+
*/
|
|
31
|
+
export const LINK_MARKDOWN_URL_PAREN = {
|
|
32
|
+
close: ")",
|
|
33
|
+
encodedClose: "%29",
|
|
34
|
+
encodedOpen: "%28",
|
|
35
|
+
open: "("
|
|
36
|
+
};
|
|
37
|
+
/** Patterns matching characters that must be escaped inside link label text. */
|
|
38
|
+
export const LINK_MARKDOWN_ESCAPE_PATTERN = {
|
|
39
|
+
backslash: /\\/g,
|
|
40
|
+
closeLabel: /\]/g,
|
|
41
|
+
lineBreak: /\n/g,
|
|
42
|
+
openLabel: /\[/g
|
|
43
|
+
};
|
|
44
|
+
/** Escape sequences paired with `LINK_MARKDOWN_ESCAPE_PATTERN`. */
|
|
45
|
+
export const LINK_MARKDOWN_ESCAPE_VALUE = {
|
|
46
|
+
backslash: "\\",
|
|
47
|
+
escapedBackslash: "\\\\",
|
|
48
|
+
escapedCloseLabel: "\\]",
|
|
49
|
+
escapedLineBreak: "\\n",
|
|
50
|
+
escapedOpenLabel: "\\[",
|
|
51
|
+
lineBreakToken: "n"
|
|
52
|
+
};
|
|
53
|
+
/** Discriminant for the parsed rich-text segments (plain text vs. link). */
|
|
54
|
+
export const RICH_TEXT_SEGMENT_TYPE = {
|
|
55
|
+
link: "link",
|
|
56
|
+
text: "text"
|
|
57
|
+
};
|
|
58
|
+
/** Whether an editor link is explicit (`[text](url)`) or a suppressed autolink. */
|
|
59
|
+
export const RICH_LINK_KIND = {
|
|
60
|
+
explicit: "explicit",
|
|
61
|
+
suppressed: "suppressed"
|
|
62
|
+
};
|
|
63
|
+
/** Origin of a preview link segment: auto-detected URL vs. explicit link. */
|
|
64
|
+
export const RICH_PREVIEW_LINK_SOURCE = {
|
|
65
|
+
automatic: "automatic",
|
|
66
|
+
explicit: "explicit"
|
|
67
|
+
};
|
|
68
|
+
/** Editing modes of the link popover. */
|
|
69
|
+
export const RICH_LINK_POPOVER_MODE = {
|
|
70
|
+
actions: "actions",
|
|
71
|
+
edit: "edit"
|
|
72
|
+
};
|
|
73
|
+
/**
|
|
74
|
+
* Regular expressions used to detect links in plain text.
|
|
75
|
+
*
|
|
76
|
+
* The URL character classes exclude both `)` and `]` so a URL wrapped in
|
|
77
|
+
* brackets or parentheses (`[https://example.com/path]`) stops at the closing
|
|
78
|
+
* delimiter instead of swallowing it into the link target. Balanced `(...)`
|
|
79
|
+
* inside the URL is still matched through the dedicated paren-balancing group.
|
|
80
|
+
*/
|
|
81
|
+
export const LINK_PATTERN = {
|
|
82
|
+
bareDomain: /^(?:[a-zA-Z0-9-]+\.)+[a-zA-Z]{2,}[^\s<>)\]]*$/,
|
|
83
|
+
containsWhitespace: /\s/,
|
|
84
|
+
bareUrl: /(?:https?:\/\/[^\s<>)\]]*(?:\([^\s<>()]*\)[^\s<>)\]]*)*|(?:[a-zA-Z0-9-]+\.)+[a-zA-Z]{2,}[^\s<>)\]]*(?:\([^\s<>()]*\)[^\s<>)\]]*)*)/g,
|
|
85
|
+
hostBoundary: /[/?#:]/,
|
|
86
|
+
markdown: /\[((?:\\[\s\S]|[^\]\\])+)\]\(((?:[^()\s]+|\([^()\s]*\))+)\)/g,
|
|
87
|
+
protocolPrefix: /^https?:\/\//i,
|
|
88
|
+
trailingPunctuation: /[.,!?;:]+$/,
|
|
89
|
+
whitespace: /^\s+$/
|
|
90
|
+
};
|
|
91
|
+
/**
|
|
92
|
+
* Public top-level domains recognized when auto-linking a scheme-less bare
|
|
93
|
+
* domain found in prose. `new URL()` accepts any syntactically valid hostname,
|
|
94
|
+
* so without this allowlist Spanish abbreviations like `EE.UU.` or
|
|
95
|
+
* end-of-sentence transitions like `China.Por` would resolve to bogus hosts and
|
|
96
|
+
* become clickable links. It covers the common gTLDs plus every assigned
|
|
97
|
+
* two-letter ccTLD; unknown suffixes such as `uu` or `por` are intentionally
|
|
98
|
+
* absent. This gates only the automatic detection path: explicit `http(s)://`
|
|
99
|
+
* URLs and links the user pastes deliberately bypass it and stay permissive.
|
|
100
|
+
*/
|
|
101
|
+
export const KNOWN_TOP_LEVEL_DOMAINS = new Set([
|
|
102
|
+
"com",
|
|
103
|
+
"net",
|
|
104
|
+
"org",
|
|
105
|
+
"info",
|
|
106
|
+
"biz",
|
|
107
|
+
"name",
|
|
108
|
+
"pro",
|
|
109
|
+
"int",
|
|
110
|
+
"edu",
|
|
111
|
+
"gov",
|
|
112
|
+
"mil",
|
|
113
|
+
"app",
|
|
114
|
+
"dev",
|
|
115
|
+
"io",
|
|
116
|
+
"co",
|
|
117
|
+
"ai",
|
|
118
|
+
"xyz",
|
|
119
|
+
"online",
|
|
120
|
+
"site",
|
|
121
|
+
"tech",
|
|
122
|
+
"store",
|
|
123
|
+
"shop",
|
|
124
|
+
"blog",
|
|
125
|
+
"me",
|
|
126
|
+
"tv",
|
|
127
|
+
"cc",
|
|
128
|
+
"live",
|
|
129
|
+
"life",
|
|
130
|
+
"world",
|
|
131
|
+
"fun",
|
|
132
|
+
"space",
|
|
133
|
+
"website",
|
|
134
|
+
"page",
|
|
135
|
+
"web",
|
|
136
|
+
"link",
|
|
137
|
+
"click",
|
|
138
|
+
"news",
|
|
139
|
+
"media",
|
|
140
|
+
"studio",
|
|
141
|
+
"design",
|
|
142
|
+
"art",
|
|
143
|
+
"email",
|
|
144
|
+
"cloud",
|
|
145
|
+
"digital",
|
|
146
|
+
"network",
|
|
147
|
+
"agency",
|
|
148
|
+
"company",
|
|
149
|
+
"group",
|
|
150
|
+
"team",
|
|
151
|
+
"work",
|
|
152
|
+
"works",
|
|
153
|
+
"today",
|
|
154
|
+
"ltd",
|
|
155
|
+
"inc",
|
|
156
|
+
"llc",
|
|
157
|
+
"academy",
|
|
158
|
+
"school",
|
|
159
|
+
"courses",
|
|
160
|
+
"education",
|
|
161
|
+
"events",
|
|
162
|
+
"social",
|
|
163
|
+
"chat",
|
|
164
|
+
"video",
|
|
165
|
+
"photo",
|
|
166
|
+
"photos",
|
|
167
|
+
"games",
|
|
168
|
+
"game",
|
|
169
|
+
"finance",
|
|
170
|
+
"money",
|
|
171
|
+
"health",
|
|
172
|
+
"fit",
|
|
173
|
+
"run",
|
|
174
|
+
"travel",
|
|
175
|
+
"tours",
|
|
176
|
+
"global",
|
|
177
|
+
"international",
|
|
178
|
+
"solutions",
|
|
179
|
+
"systems",
|
|
180
|
+
"consulting",
|
|
181
|
+
"marketing",
|
|
182
|
+
"software",
|
|
183
|
+
"host",
|
|
184
|
+
"hosting",
|
|
185
|
+
"wiki",
|
|
186
|
+
"ac",
|
|
187
|
+
"ad",
|
|
188
|
+
"ae",
|
|
189
|
+
"af",
|
|
190
|
+
"ag",
|
|
191
|
+
"al",
|
|
192
|
+
"am",
|
|
193
|
+
"ao",
|
|
194
|
+
"aq",
|
|
195
|
+
"ar",
|
|
196
|
+
"as",
|
|
197
|
+
"at",
|
|
198
|
+
"au",
|
|
199
|
+
"aw",
|
|
200
|
+
"ax",
|
|
201
|
+
"az",
|
|
202
|
+
"ba",
|
|
203
|
+
"bb",
|
|
204
|
+
"bd",
|
|
205
|
+
"be",
|
|
206
|
+
"bf",
|
|
207
|
+
"bg",
|
|
208
|
+
"bh",
|
|
209
|
+
"bi",
|
|
210
|
+
"bj",
|
|
211
|
+
"bm",
|
|
212
|
+
"bn",
|
|
213
|
+
"bo",
|
|
214
|
+
"br",
|
|
215
|
+
"bs",
|
|
216
|
+
"bt",
|
|
217
|
+
"bw",
|
|
218
|
+
"by",
|
|
219
|
+
"bz",
|
|
220
|
+
"ca",
|
|
221
|
+
"cd",
|
|
222
|
+
"cf",
|
|
223
|
+
"cg",
|
|
224
|
+
"ch",
|
|
225
|
+
"ci",
|
|
226
|
+
"ck",
|
|
227
|
+
"cl",
|
|
228
|
+
"cm",
|
|
229
|
+
"cn",
|
|
230
|
+
"cr",
|
|
231
|
+
"cu",
|
|
232
|
+
"cv",
|
|
233
|
+
"cw",
|
|
234
|
+
"cx",
|
|
235
|
+
"cy",
|
|
236
|
+
"cz",
|
|
237
|
+
"de",
|
|
238
|
+
"dj",
|
|
239
|
+
"dk",
|
|
240
|
+
"dm",
|
|
241
|
+
"do",
|
|
242
|
+
"dz",
|
|
243
|
+
"ec",
|
|
244
|
+
"ee",
|
|
245
|
+
"eg",
|
|
246
|
+
"er",
|
|
247
|
+
"es",
|
|
248
|
+
"et",
|
|
249
|
+
"eu",
|
|
250
|
+
"fi",
|
|
251
|
+
"fj",
|
|
252
|
+
"fk",
|
|
253
|
+
"fm",
|
|
254
|
+
"fo",
|
|
255
|
+
"fr",
|
|
256
|
+
"ga",
|
|
257
|
+
"gd",
|
|
258
|
+
"ge",
|
|
259
|
+
"gf",
|
|
260
|
+
"gg",
|
|
261
|
+
"gh",
|
|
262
|
+
"gi",
|
|
263
|
+
"gl",
|
|
264
|
+
"gm",
|
|
265
|
+
"gn",
|
|
266
|
+
"gp",
|
|
267
|
+
"gq",
|
|
268
|
+
"gr",
|
|
269
|
+
"gs",
|
|
270
|
+
"gt",
|
|
271
|
+
"gu",
|
|
272
|
+
"gw",
|
|
273
|
+
"gy",
|
|
274
|
+
"hk",
|
|
275
|
+
"hm",
|
|
276
|
+
"hn",
|
|
277
|
+
"hr",
|
|
278
|
+
"ht",
|
|
279
|
+
"hu",
|
|
280
|
+
"id",
|
|
281
|
+
"ie",
|
|
282
|
+
"il",
|
|
283
|
+
"im",
|
|
284
|
+
"in",
|
|
285
|
+
"iq",
|
|
286
|
+
"ir",
|
|
287
|
+
"is",
|
|
288
|
+
"it",
|
|
289
|
+
"je",
|
|
290
|
+
"jm",
|
|
291
|
+
"jo",
|
|
292
|
+
"jp",
|
|
293
|
+
"ke",
|
|
294
|
+
"kg",
|
|
295
|
+
"kh",
|
|
296
|
+
"ki",
|
|
297
|
+
"km",
|
|
298
|
+
"kn",
|
|
299
|
+
"kp",
|
|
300
|
+
"kr",
|
|
301
|
+
"kw",
|
|
302
|
+
"ky",
|
|
303
|
+
"kz",
|
|
304
|
+
"la",
|
|
305
|
+
"lb",
|
|
306
|
+
"lc",
|
|
307
|
+
"li",
|
|
308
|
+
"lk",
|
|
309
|
+
"lr",
|
|
310
|
+
"ls",
|
|
311
|
+
"lt",
|
|
312
|
+
"lu",
|
|
313
|
+
"lv",
|
|
314
|
+
"ly",
|
|
315
|
+
"ma",
|
|
316
|
+
"mc",
|
|
317
|
+
"md",
|
|
318
|
+
"mg",
|
|
319
|
+
"mh",
|
|
320
|
+
"mk",
|
|
321
|
+
"ml",
|
|
322
|
+
"mm",
|
|
323
|
+
"mn",
|
|
324
|
+
"mo",
|
|
325
|
+
"mp",
|
|
326
|
+
"mq",
|
|
327
|
+
"mr",
|
|
328
|
+
"ms",
|
|
329
|
+
"mt",
|
|
330
|
+
"mu",
|
|
331
|
+
"mv",
|
|
332
|
+
"mw",
|
|
333
|
+
"mx",
|
|
334
|
+
"my",
|
|
335
|
+
"mz",
|
|
336
|
+
"na",
|
|
337
|
+
"nc",
|
|
338
|
+
"ne",
|
|
339
|
+
"nf",
|
|
340
|
+
"ng",
|
|
341
|
+
"ni",
|
|
342
|
+
"nl",
|
|
343
|
+
"no",
|
|
344
|
+
"np",
|
|
345
|
+
"nr",
|
|
346
|
+
"nu",
|
|
347
|
+
"nz",
|
|
348
|
+
"om",
|
|
349
|
+
"pa",
|
|
350
|
+
"pe",
|
|
351
|
+
"pf",
|
|
352
|
+
"pg",
|
|
353
|
+
"ph",
|
|
354
|
+
"pk",
|
|
355
|
+
"pl",
|
|
356
|
+
"pm",
|
|
357
|
+
"pn",
|
|
358
|
+
"pr",
|
|
359
|
+
"ps",
|
|
360
|
+
"pt",
|
|
361
|
+
"pw",
|
|
362
|
+
"py",
|
|
363
|
+
"qa",
|
|
364
|
+
"re",
|
|
365
|
+
"ro",
|
|
366
|
+
"rs",
|
|
367
|
+
"ru",
|
|
368
|
+
"rw",
|
|
369
|
+
"sa",
|
|
370
|
+
"sb",
|
|
371
|
+
"sc",
|
|
372
|
+
"sd",
|
|
373
|
+
"se",
|
|
374
|
+
"sg",
|
|
375
|
+
"sh",
|
|
376
|
+
"si",
|
|
377
|
+
"sk",
|
|
378
|
+
"sl",
|
|
379
|
+
"sm",
|
|
380
|
+
"sn",
|
|
381
|
+
"so",
|
|
382
|
+
"sr",
|
|
383
|
+
"ss",
|
|
384
|
+
"st",
|
|
385
|
+
"sv",
|
|
386
|
+
"sx",
|
|
387
|
+
"sy",
|
|
388
|
+
"sz",
|
|
389
|
+
"tc",
|
|
390
|
+
"td",
|
|
391
|
+
"tf",
|
|
392
|
+
"tg",
|
|
393
|
+
"th",
|
|
394
|
+
"tj",
|
|
395
|
+
"tk",
|
|
396
|
+
"tl",
|
|
397
|
+
"tm",
|
|
398
|
+
"tn",
|
|
399
|
+
"to",
|
|
400
|
+
"tr",
|
|
401
|
+
"tt",
|
|
402
|
+
"tw",
|
|
403
|
+
"tz",
|
|
404
|
+
"ua",
|
|
405
|
+
"ug",
|
|
406
|
+
"uk",
|
|
407
|
+
"us",
|
|
408
|
+
"uy",
|
|
409
|
+
"uz",
|
|
410
|
+
"va",
|
|
411
|
+
"vc",
|
|
412
|
+
"ve",
|
|
413
|
+
"vg",
|
|
414
|
+
"vi",
|
|
415
|
+
"vn",
|
|
416
|
+
"vu",
|
|
417
|
+
"wf",
|
|
418
|
+
"ws",
|
|
419
|
+
"ye",
|
|
420
|
+
"yt",
|
|
421
|
+
"za",
|
|
422
|
+
"zm",
|
|
423
|
+
"zw"
|
|
424
|
+
]);
|
|
425
|
+
/** Capture group indexes of `LINK_PATTERN.markdown`. */
|
|
426
|
+
export const LINK_MARKDOWN_MATCH_GROUP = {
|
|
427
|
+
text: 1,
|
|
428
|
+
url: 2
|
|
429
|
+
};
|
|
430
|
+
/** Sentinel returned by the text diff when no change is found. */
|
|
431
|
+
export const TEXT_DIFF_FALLBACK_INDEX = { notFound: -1 };
|
|
432
|
+
/** Separator used to build a stable key for preview link segments. */
|
|
433
|
+
export const PREVIEW_LINK_KEY_SEPARATOR = { value: ":" };
|
|
434
|
+
/** Clipboard data type read on paste inside the editor. */
|
|
435
|
+
export const RICH_TEXT_CLIPBOARD_DATA_TYPE = { plainText: "text/plain" };
|
|
436
|
+
/** `InputEvent.inputType` values handled by the editor's `beforeInput`. */
|
|
437
|
+
export const RICH_TEXT_EDITOR_INPUT_TYPE = {
|
|
438
|
+
deleteContentBackward: "deleteContentBackward",
|
|
439
|
+
deleteContentForward: "deleteContentForward",
|
|
440
|
+
insertLineBreak: "insertLineBreak",
|
|
441
|
+
insertParagraph: "insertParagraph",
|
|
442
|
+
insertText: "insertText"
|
|
443
|
+
};
|
|
444
|
+
/** Keyboard keys handled by the editor's `keydown`. */
|
|
445
|
+
export const RICH_TEXT_EDITOR_KEY = {
|
|
446
|
+
backspace: "Backspace",
|
|
447
|
+
delete: "Delete",
|
|
448
|
+
enter: "Enter"
|
|
449
|
+
};
|
|
450
|
+
/** Direction of a word-wise deletion. */
|
|
451
|
+
export const RICH_TEXT_EDITOR_WORD_DIRECTION = {
|
|
452
|
+
backward: "backward",
|
|
453
|
+
forward: "forward"
|
|
454
|
+
};
|
|
455
|
+
/** Length of a single editable character. */
|
|
456
|
+
export const RICH_TEXT_EDITOR_KEY_LENGTH = { character: 1 };
|
|
457
|
+
/** Literal text tokens used by the editor. */
|
|
458
|
+
export const RICH_TEXT_EDITOR_TEXT = { lineBreak: "\n" };
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared types for the rich-text link layer.
|
|
3
|
+
*/
|
|
4
|
+
import type { RICH_LINK_KIND, RICH_PREVIEW_LINK_SOURCE, RICH_TEXT_SEGMENT_TYPE } from "./link-markdown-constants.js";
|
|
5
|
+
/** A parsed piece of rendered content: either plain text or a link. */
|
|
6
|
+
export type RichTextSegment = {
|
|
7
|
+
text: string;
|
|
8
|
+
type: typeof RICH_TEXT_SEGMENT_TYPE.text;
|
|
9
|
+
} | {
|
|
10
|
+
text: string;
|
|
11
|
+
type: typeof RICH_TEXT_SEGMENT_TYPE.link;
|
|
12
|
+
url: string;
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* A link tracked by the editor over its plain-text content. Explicit links carry
|
|
16
|
+
* a target URL; suppressed links mark an auto-detected URL the author removed.
|
|
17
|
+
*/
|
|
18
|
+
export type RichLink = {
|
|
19
|
+
end: number;
|
|
20
|
+
id: string;
|
|
21
|
+
isSynced: boolean;
|
|
22
|
+
kind: typeof RICH_LINK_KIND.explicit;
|
|
23
|
+
start: number;
|
|
24
|
+
url: string;
|
|
25
|
+
} | {
|
|
26
|
+
end: number;
|
|
27
|
+
id: string;
|
|
28
|
+
kind: typeof RICH_LINK_KIND.suppressed;
|
|
29
|
+
start: number;
|
|
30
|
+
};
|
|
31
|
+
/** A segment of the editor preview: plain text or an interactive link. */
|
|
32
|
+
export type RichPreviewSegment = {
|
|
33
|
+
text: string;
|
|
34
|
+
type: typeof RICH_TEXT_SEGMENT_TYPE.text;
|
|
35
|
+
} | {
|
|
36
|
+
end: number;
|
|
37
|
+
id?: string;
|
|
38
|
+
key: string;
|
|
39
|
+
source: typeof RICH_PREVIEW_LINK_SOURCE.automatic | typeof RICH_PREVIEW_LINK_SOURCE.explicit;
|
|
40
|
+
start: number;
|
|
41
|
+
text: string;
|
|
42
|
+
type: typeof RICH_TEXT_SEGMENT_TYPE.link;
|
|
43
|
+
url: string;
|
|
44
|
+
};
|
|
45
|
+
/** The link variant of a preview segment, used when editing a link. */
|
|
46
|
+
export type ActiveRichPreviewLink = Extract<RichPreviewSegment, {
|
|
47
|
+
type: typeof RICH_TEXT_SEGMENT_TYPE.link;
|
|
48
|
+
}>;
|
|
49
|
+
/** A character offset range within the editor's plain-text content. */
|
|
50
|
+
export type RichTextSelectionRange = {
|
|
51
|
+
end: number;
|
|
52
|
+
start: number;
|
|
53
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure helpers for the rich-text link layer: URL normalization, markdown
|
|
3
|
+
* link (de)serialization, plain-text autolink parsing, and editor link
|
|
4
|
+
* bookkeeping. None of these touch the DOM, so they are unit-testable in
|
|
5
|
+
* isolation and shared by the renderer, the editor hook, and persistence.
|
|
6
|
+
*/
|
|
7
|
+
import { RICH_PREVIEW_LINK_SOURCE, RICH_TEXT_EDITOR_WORD_DIRECTION } from "./link-markdown-constants.js";
|
|
8
|
+
import type { RichLink, RichPreviewSegment, RichTextSegment, RichTextSelectionRange } from "./link-markdown-types.js";
|
|
9
|
+
/**
|
|
10
|
+
* Normalizes a raw markdown URL into a safe absolute `http(s)` URL, or `null`
|
|
11
|
+
* when it is not a usable web link. Bare domains gain an `https://` prefix.
|
|
12
|
+
*
|
|
13
|
+
* A candidate that contains whitespace is returned as its parsed `href`, which
|
|
14
|
+
* percent-encodes those characters. The renderer's `LINK_PATTERN.markdown` URL
|
|
15
|
+
* group forbids whitespace, so persisting the raw candidate would serialize a
|
|
16
|
+
* `[text](url with space)` link that cannot be read back and renders as broken
|
|
17
|
+
* markdown. Whitespace-free candidates are returned verbatim to preserve their
|
|
18
|
+
* exact form (no trailing slash, stable synchronization checks).
|
|
19
|
+
*
|
|
20
|
+
* A scheme-less candidate that parses into userinfo (`john.doe@example.com`) is
|
|
21
|
+
* rejected: the `bareDomain` pattern allows `@` in its trailing class, so an
|
|
22
|
+
* email or literal slips through and prepending `https://` would yield
|
|
23
|
+
* `https://john.doe@example.com`, where the browser reads `john.doe` as
|
|
24
|
+
* credentials for `example.com`. That turns the value into a misleading
|
|
25
|
+
* outbound link, against the convention that email addresses are not linked.
|
|
26
|
+
* The check uses the parsed `username`/`password` rather than a naive `@` scan
|
|
27
|
+
* so a legitimate `@` past the authority (a path or query) still links.
|
|
28
|
+
*/
|
|
29
|
+
export declare function normalizeMarkdownUrl(rawUrl: string | null | undefined): string | null;
|
|
30
|
+
/**
|
|
31
|
+
* Extracts the top-level domain (the last dot-separated label of the host) from
|
|
32
|
+
* a bare or scheme-prefixed candidate, lowercased, or `null` when the candidate
|
|
33
|
+
* has no host label past a dot. The host ends at the first path, query,
|
|
34
|
+
* fragment, or port boundary so a path segment is never mistaken for the TLD.
|
|
35
|
+
*/
|
|
36
|
+
export declare function getCandidateTopLevelDomain(candidate: string): string | null;
|
|
37
|
+
/**
|
|
38
|
+
* Normalizes a candidate for the automatic detection path. Scheme-prefixed URLs
|
|
39
|
+
* are trusted and normalized as-is; a scheme-less bare domain is only accepted
|
|
40
|
+
* when its TLD is a recognized public suffix, so prose abbreviations such as
|
|
41
|
+
* `EE.UU.` or `China.Por` stay plain text instead of resolving to bogus hosts.
|
|
42
|
+
* Explicit paste-as-link flows keep using `normalizeMarkdownUrl` directly and
|
|
43
|
+
* stay permissive.
|
|
44
|
+
*/
|
|
45
|
+
export declare function normalizeAutolinkUrl(candidate: string): string | null;
|
|
46
|
+
/** Strips the `http(s)://` prefix from a value for synchronization checks. */
|
|
47
|
+
export declare function removeLinkProtocolPrefix(value: string): string;
|
|
48
|
+
/** Whether a link's visible text matches its URL ignoring the protocol. */
|
|
49
|
+
export declare function isLinkSynchronized(text: string, url: string): boolean;
|
|
50
|
+
/** Returns the protocol prefix of a URL, defaulting to `https://`. */
|
|
51
|
+
export declare function getLinkProtocolPrefix(url: string): string;
|
|
52
|
+
/**
|
|
53
|
+
* Rebuilds the URL of a synchronized link after its visible text changed, so a
|
|
54
|
+
* link whose label is the URL keeps tracking the edited text.
|
|
55
|
+
*/
|
|
56
|
+
export declare function getSynchronizedLinkUrl(text: string, currentUrl: string): string | null;
|
|
57
|
+
/** Whether the value contains only whitespace. */
|
|
58
|
+
export declare function isWhitespaceOnly(value: string): boolean;
|
|
59
|
+
/**
|
|
60
|
+
* Computes the range a word-wise deletion (Ctrl/Alt+Backspace/Delete) should
|
|
61
|
+
* remove from a collapsed caret, mirroring native word deletion.
|
|
62
|
+
*/
|
|
63
|
+
export declare function getWordDeletionRange(input: {
|
|
64
|
+
direction: typeof RICH_TEXT_EDITOR_WORD_DIRECTION.backward | typeof RICH_TEXT_EDITOR_WORD_DIRECTION.forward;
|
|
65
|
+
selectionRange: RichTextSelectionRange;
|
|
66
|
+
text: string;
|
|
67
|
+
}): RichTextSelectionRange;
|
|
68
|
+
/**
|
|
69
|
+
* Percent-encodes the parentheses a URL cannot keep literal inside a
|
|
70
|
+
* `[text](url)` target, so an explicit link whose URL contains an unmatched or
|
|
71
|
+
* nested `(`/`)` (for example `https://example.com/a)b`) serializes to markdown
|
|
72
|
+
* that `LINK_PATTERN.markdown` reads back as the same link instead of truncating
|
|
73
|
+
* the target at the stray paren and spilling the rest into plain text.
|
|
74
|
+
*
|
|
75
|
+
* The URL group only matches balanced single-level `(...)` pairs, so those are
|
|
76
|
+
* preserved verbatim (keeping links like `.../Foo_(bar)` intact); every other
|
|
77
|
+
* paren becomes `%28`/`%29`, which is decoded back to the literal character when
|
|
78
|
+
* the link is opened.
|
|
79
|
+
*/
|
|
80
|
+
export declare function escapeMarkdownLinkUrl(url: string): string;
|
|
81
|
+
/** Builds a `[text](url)` markdown link, escaping the label and the URL. */
|
|
82
|
+
export declare function buildMarkdownLinkFromSelection(text: string, url: string): string;
|
|
83
|
+
/** Escapes characters that would break a markdown link label. */
|
|
84
|
+
export declare function escapeMarkdownLinkText(text: string): string;
|
|
85
|
+
/** Reverses `escapeMarkdownLinkText`, restoring line breaks and literals. */
|
|
86
|
+
export declare function unescapeMarkdownLinkText(text: string): string;
|
|
87
|
+
/** Builds a stable React key for a preview link segment. */
|
|
88
|
+
export declare function buildPreviewLinkKey(segment: {
|
|
89
|
+
id?: string;
|
|
90
|
+
source: typeof RICH_PREVIEW_LINK_SOURCE.automatic | typeof RICH_PREVIEW_LINK_SOURCE.explicit;
|
|
91
|
+
start: number;
|
|
92
|
+
url: string;
|
|
93
|
+
}): string;
|
|
94
|
+
/** Creates a plain-text rendered segment. */
|
|
95
|
+
export declare function createTextSegment(text: string): RichTextSegment;
|
|
96
|
+
/** Creates a link rendered segment. */
|
|
97
|
+
export declare function createLinkSegment(text: string, url: string): RichTextSegment;
|
|
98
|
+
/** Creates a plain-text editor preview segment. */
|
|
99
|
+
export declare function createTextPreviewSegment(text: string): RichPreviewSegment;
|
|
100
|
+
/** Creates a link editor preview segment with a stable key. */
|
|
101
|
+
export declare function createLinkPreviewSegment(input: {
|
|
102
|
+
end: number;
|
|
103
|
+
id?: string;
|
|
104
|
+
source: typeof RICH_PREVIEW_LINK_SOURCE.automatic | typeof RICH_PREVIEW_LINK_SOURCE.explicit;
|
|
105
|
+
start: number;
|
|
106
|
+
text: string;
|
|
107
|
+
url: string;
|
|
108
|
+
}): RichPreviewSegment;
|
|
109
|
+
/** Splits a matched bare URL from any trailing sentence punctuation. */
|
|
110
|
+
export declare function splitBareUrlMatch(matchedUrl: string): {
|
|
111
|
+
trailingText: string;
|
|
112
|
+
urlText: string;
|
|
113
|
+
};
|
|
114
|
+
/** Whether two `[start, end)` ranges overlap. */
|
|
115
|
+
export declare function rangesOverlap(firstRange: {
|
|
116
|
+
end: number;
|
|
117
|
+
start: number;
|
|
118
|
+
}, secondRange: {
|
|
119
|
+
end: number;
|
|
120
|
+
start: number;
|
|
121
|
+
}): boolean;
|
|
122
|
+
/** Whether a matched bare URL is actually part of an email address. */
|
|
123
|
+
export declare function isBareUrlMatchInsideEmail(input: {
|
|
124
|
+
content: string;
|
|
125
|
+
matchedIndex: number;
|
|
126
|
+
matchedUrl: string;
|
|
127
|
+
}): boolean;
|
|
128
|
+
/** Parses plain text into rendered segments, auto-linking bare URLs. */
|
|
129
|
+
export declare function parseBareUrlSegments(content: string): RichTextSegment[];
|
|
130
|
+
/** Parses plain text into editor preview segments, auto-linking bare URLs. */
|
|
131
|
+
export declare function parseBareUrlPreviewSegments(content: string, offset: number, suppressedLinks: RichLink[]): RichPreviewSegment[];
|
|
132
|
+
/**
|
|
133
|
+
* Parses the editor's plain-text content plus its tracked links into preview
|
|
134
|
+
* segments, layering explicit links over auto-detected bare URLs.
|
|
135
|
+
*/
|
|
136
|
+
export declare function parsePreviewSegments(content: string, links: RichLink[]): RichPreviewSegment[];
|
|
137
|
+
/**
|
|
138
|
+
* Whether a markdown link whose URL is not a safe web link is a genuine
|
|
139
|
+
* suppressed autolink (`[some-url.com](#)`) produced by the editor, rather than
|
|
140
|
+
* literal text that merely looks like a markdown link (`[PDF](pendiente)`).
|
|
141
|
+
*
|
|
142
|
+
* Suppression only applies when the label itself is a normalizable URL, which
|
|
143
|
+
* mirrors `serializeEditorContent`. Any other `[text](url)` whose URL cannot be
|
|
144
|
+
* normalized is treated as authored plain text and preserved verbatim.
|
|
145
|
+
*/
|
|
146
|
+
export declare function isSuppressedAutolinkMarkdown(linkText: string, linkUrl: string): boolean;
|
|
147
|
+
/**
|
|
148
|
+
* Parses persisted content (markdown links plus bare URLs) into rendered
|
|
149
|
+
* segments for read-only display.
|
|
150
|
+
*/
|
|
151
|
+
export declare function parseRichTextSegments(content: string): RichTextSegment[];
|
|
152
|
+
/**
|
|
153
|
+
* Converts persisted markdown into the editor's plain-text content plus the
|
|
154
|
+
* tracked links (explicit and suppressed) needed to re-render it for editing.
|
|
155
|
+
*/
|
|
156
|
+
export declare function deserializeMarkdownForEditor(content: string): {
|
|
157
|
+
content: string;
|
|
158
|
+
links: RichLink[];
|
|
159
|
+
};
|
|
160
|
+
/**
|
|
161
|
+
* Serializes the editor's plain-text content plus tracked links back into
|
|
162
|
+
* persisted markdown, emitting `[text](url)` for explicit links and
|
|
163
|
+
* `[text](#)` for suppressed auto-detected URLs.
|
|
164
|
+
*/
|
|
165
|
+
export declare function serializeEditorContent(content: string, links: RichLink[]): string;
|
|
166
|
+
/**
|
|
167
|
+
* Computes the minimal changed range between two strings: the common prefix
|
|
168
|
+
* end (`start`), the changed-region ends in each string, and the length delta.
|
|
169
|
+
*/
|
|
170
|
+
export declare function getTextDiff(input: {
|
|
171
|
+
nextText: string;
|
|
172
|
+
previousText: string;
|
|
173
|
+
}): {
|
|
174
|
+
delta: number;
|
|
175
|
+
endInNextText: number;
|
|
176
|
+
endInPreviousText: number;
|
|
177
|
+
start: number;
|
|
178
|
+
};
|
|
179
|
+
/**
|
|
180
|
+
* Adjusts tracked link ranges after the editor's plain text changed, shifting,
|
|
181
|
+
* shrinking, or dropping links and keeping synchronized links in step with
|
|
182
|
+
* their visible text.
|
|
183
|
+
*
|
|
184
|
+
* A suppressed autolink is dropped once its visible text is no longer a
|
|
185
|
+
* normalizable URL, mirroring `isSuppressedAutolinkMarkdown`: with nothing left
|
|
186
|
+
* to suppress, the edited text serializes as plain text instead of `[text](#)`,
|
|
187
|
+
* which would otherwise be rendered back as literal markdown.
|
|
188
|
+
*/
|
|
189
|
+
export declare function getLinksAfterTextChange(input: {
|
|
190
|
+
links: RichLink[];
|
|
191
|
+
nextText: string;
|
|
192
|
+
previousText: string;
|
|
193
|
+
}): RichLink[];
|