luxen-ui 0.9.0 → 0.9.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cdn/custom-elements.json +148 -123
- package/cdn/elements/dropdown-item/dropdown-item.js +1 -1
- package/cdn/elements/dropdown-item/dropdown-item.js.map +1 -1
- package/cdn/elements/prose-editor/prose-editor.d.ts +24 -2
- package/cdn/elements/prose-editor/prose-editor.d.ts.map +1 -1
- package/cdn/elements/prose-editor/prose-editor.js +40 -39
- package/cdn/elements/prose-editor/prose-editor.js.map +1 -1
- package/cdn/elements/tree/tree.d.ts +11 -1
- package/cdn/elements/tree/tree.d.ts.map +1 -1
- package/cdn/elements/tree/tree.js +1 -3
- package/cdn/elements/tree/tree.js.map +1 -1
- package/cdn/elements/tree-item/tree-item.d.ts +17 -1
- package/cdn/elements/tree-item/tree-item.d.ts.map +1 -1
- package/cdn/elements/tree-item/tree-item.js +2 -1
- package/cdn/elements/tree-item/tree-item.js.map +1 -1
- package/cdn/standalone.css +4 -0
- package/cdn/standalone.js +99 -50
- package/cdn/standalone.js.map +1 -1
- package/cdn/styles/elements/button.css +4 -0
- package/dist/css/elements/button.css +4 -0
- package/dist/custom-elements.json +148 -123
- package/dist/elements/dropdown-item/dropdown-item.css +1 -0
- package/dist/elements/prose-editor/prose-editor.d.ts +24 -2
- package/dist/elements/prose-editor/prose-editor.d.ts.map +1 -1
- package/dist/elements/prose-editor/prose-editor.js +81 -48
- package/dist/elements/tree/tree.css +1 -1
- package/dist/elements/tree/tree.d.ts +11 -1
- package/dist/elements/tree/tree.d.ts.map +1 -1
- package/dist/elements/tree/tree.js +37 -11
- package/dist/elements/tree-item/tree-item.css +5 -1
- package/dist/elements/tree-item/tree-item.d.ts +17 -1
- package/dist/elements/tree-item/tree-item.d.ts.map +1 -1
- package/dist/elements/tree-item/tree-item.js +51 -10
- package/dist/metadata/index.json +22 -3
- package/dist/metadata/tree-item.json +20 -1
- package/dist/metadata/tree.json +1 -1
- package/dist/templates/elements/tree.md +18 -0
- package/package.json +4 -2
- package/postcss-plugin-prefix.js +43 -1
|
@@ -172,127 +172,6 @@
|
|
|
172
172
|
}
|
|
173
173
|
]
|
|
174
174
|
},
|
|
175
|
-
{
|
|
176
|
-
"kind": "javascript-module",
|
|
177
|
-
"path": "src/html/elements/badge/badge.ts",
|
|
178
|
-
"declarations": [
|
|
179
|
-
{
|
|
180
|
-
"kind": "class",
|
|
181
|
-
"description": "",
|
|
182
|
-
"name": "Badge",
|
|
183
|
-
"members": [
|
|
184
|
-
{
|
|
185
|
-
"kind": "field",
|
|
186
|
-
"name": "variant",
|
|
187
|
-
"type": {
|
|
188
|
-
"text": "BadgeVariant | undefined"
|
|
189
|
-
},
|
|
190
|
-
"description": "Style variant: `info`, `success`, `warning`, `danger`, or `neutral` (default)",
|
|
191
|
-
"attribute": "variant",
|
|
192
|
-
"reflects": true
|
|
193
|
-
},
|
|
194
|
-
{
|
|
195
|
-
"kind": "field",
|
|
196
|
-
"name": "pill",
|
|
197
|
-
"type": {
|
|
198
|
-
"text": "boolean"
|
|
199
|
-
},
|
|
200
|
-
"default": "false",
|
|
201
|
-
"description": "Display as pill shape",
|
|
202
|
-
"attribute": "pill",
|
|
203
|
-
"reflects": true
|
|
204
|
-
},
|
|
205
|
-
{
|
|
206
|
-
"kind": "field",
|
|
207
|
-
"name": "size",
|
|
208
|
-
"type": {
|
|
209
|
-
"text": "BadgeSize | undefined"
|
|
210
|
-
},
|
|
211
|
-
"description": "Badge size: `sm`, `lg`. Default is md.",
|
|
212
|
-
"attribute": "size",
|
|
213
|
-
"reflects": true
|
|
214
|
-
},
|
|
215
|
-
{
|
|
216
|
-
"kind": "field",
|
|
217
|
-
"name": "appearance",
|
|
218
|
-
"type": {
|
|
219
|
-
"text": "BadgeAppearance | undefined"
|
|
220
|
-
},
|
|
221
|
-
"description": "Visual appearance: `filled`, `filled-outlined`, `accent`. Default is outlined.",
|
|
222
|
-
"attribute": "appearance",
|
|
223
|
-
"reflects": true
|
|
224
|
-
}
|
|
225
|
-
],
|
|
226
|
-
"attributes": [
|
|
227
|
-
{
|
|
228
|
-
"name": "variant",
|
|
229
|
-
"type": {
|
|
230
|
-
"text": "BadgeVariant | undefined"
|
|
231
|
-
},
|
|
232
|
-
"description": "Style variant: `info`, `success`, `warning`, `danger`, or `neutral` (default)",
|
|
233
|
-
"fieldName": "variant"
|
|
234
|
-
},
|
|
235
|
-
{
|
|
236
|
-
"name": "pill",
|
|
237
|
-
"type": {
|
|
238
|
-
"text": "boolean"
|
|
239
|
-
},
|
|
240
|
-
"default": "false",
|
|
241
|
-
"description": "Display as pill shape",
|
|
242
|
-
"fieldName": "pill"
|
|
243
|
-
},
|
|
244
|
-
{
|
|
245
|
-
"name": "size",
|
|
246
|
-
"type": {
|
|
247
|
-
"text": "BadgeSize | undefined"
|
|
248
|
-
},
|
|
249
|
-
"description": "Badge size: `sm`, `lg`. Default is md.",
|
|
250
|
-
"fieldName": "size"
|
|
251
|
-
},
|
|
252
|
-
{
|
|
253
|
-
"name": "appearance",
|
|
254
|
-
"type": {
|
|
255
|
-
"text": "BadgeAppearance | undefined"
|
|
256
|
-
},
|
|
257
|
-
"description": "Visual appearance: `filled`, `filled-outlined`, `accent`. Default is outlined.",
|
|
258
|
-
"fieldName": "appearance"
|
|
259
|
-
}
|
|
260
|
-
],
|
|
261
|
-
"superclass": {
|
|
262
|
-
"name": "LuxenElement",
|
|
263
|
-
"module": "/src/html/shared/luxen-element.js"
|
|
264
|
-
},
|
|
265
|
-
"tagName": "l-badge",
|
|
266
|
-
"customElement": true,
|
|
267
|
-
"summary": "A badge component for displaying small status indicators."
|
|
268
|
-
}
|
|
269
|
-
],
|
|
270
|
-
"exports": [
|
|
271
|
-
{
|
|
272
|
-
"kind": "js",
|
|
273
|
-
"name": "Badge",
|
|
274
|
-
"declaration": {
|
|
275
|
-
"name": "Badge",
|
|
276
|
-
"module": "src/html/elements/badge/badge.ts"
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
]
|
|
280
|
-
},
|
|
281
|
-
{
|
|
282
|
-
"kind": "javascript-module",
|
|
283
|
-
"path": "src/html/elements/badge/index.ts",
|
|
284
|
-
"declarations": [],
|
|
285
|
-
"exports": [
|
|
286
|
-
{
|
|
287
|
-
"kind": "js",
|
|
288
|
-
"name": "*",
|
|
289
|
-
"declaration": {
|
|
290
|
-
"name": "*",
|
|
291
|
-
"module": "src/html/elements/badge/badge.js"
|
|
292
|
-
}
|
|
293
|
-
}
|
|
294
|
-
]
|
|
295
|
-
},
|
|
296
175
|
{
|
|
297
176
|
"kind": "javascript-module",
|
|
298
177
|
"path": "src/html/elements/button/button.meta.ts",
|
|
@@ -446,6 +325,127 @@
|
|
|
446
325
|
}
|
|
447
326
|
]
|
|
448
327
|
},
|
|
328
|
+
{
|
|
329
|
+
"kind": "javascript-module",
|
|
330
|
+
"path": "src/html/elements/badge/badge.ts",
|
|
331
|
+
"declarations": [
|
|
332
|
+
{
|
|
333
|
+
"kind": "class",
|
|
334
|
+
"description": "",
|
|
335
|
+
"name": "Badge",
|
|
336
|
+
"members": [
|
|
337
|
+
{
|
|
338
|
+
"kind": "field",
|
|
339
|
+
"name": "variant",
|
|
340
|
+
"type": {
|
|
341
|
+
"text": "BadgeVariant | undefined"
|
|
342
|
+
},
|
|
343
|
+
"description": "Style variant: `info`, `success`, `warning`, `danger`, or `neutral` (default)",
|
|
344
|
+
"attribute": "variant",
|
|
345
|
+
"reflects": true
|
|
346
|
+
},
|
|
347
|
+
{
|
|
348
|
+
"kind": "field",
|
|
349
|
+
"name": "pill",
|
|
350
|
+
"type": {
|
|
351
|
+
"text": "boolean"
|
|
352
|
+
},
|
|
353
|
+
"default": "false",
|
|
354
|
+
"description": "Display as pill shape",
|
|
355
|
+
"attribute": "pill",
|
|
356
|
+
"reflects": true
|
|
357
|
+
},
|
|
358
|
+
{
|
|
359
|
+
"kind": "field",
|
|
360
|
+
"name": "size",
|
|
361
|
+
"type": {
|
|
362
|
+
"text": "BadgeSize | undefined"
|
|
363
|
+
},
|
|
364
|
+
"description": "Badge size: `sm`, `lg`. Default is md.",
|
|
365
|
+
"attribute": "size",
|
|
366
|
+
"reflects": true
|
|
367
|
+
},
|
|
368
|
+
{
|
|
369
|
+
"kind": "field",
|
|
370
|
+
"name": "appearance",
|
|
371
|
+
"type": {
|
|
372
|
+
"text": "BadgeAppearance | undefined"
|
|
373
|
+
},
|
|
374
|
+
"description": "Visual appearance: `filled`, `filled-outlined`, `accent`. Default is outlined.",
|
|
375
|
+
"attribute": "appearance",
|
|
376
|
+
"reflects": true
|
|
377
|
+
}
|
|
378
|
+
],
|
|
379
|
+
"attributes": [
|
|
380
|
+
{
|
|
381
|
+
"name": "variant",
|
|
382
|
+
"type": {
|
|
383
|
+
"text": "BadgeVariant | undefined"
|
|
384
|
+
},
|
|
385
|
+
"description": "Style variant: `info`, `success`, `warning`, `danger`, or `neutral` (default)",
|
|
386
|
+
"fieldName": "variant"
|
|
387
|
+
},
|
|
388
|
+
{
|
|
389
|
+
"name": "pill",
|
|
390
|
+
"type": {
|
|
391
|
+
"text": "boolean"
|
|
392
|
+
},
|
|
393
|
+
"default": "false",
|
|
394
|
+
"description": "Display as pill shape",
|
|
395
|
+
"fieldName": "pill"
|
|
396
|
+
},
|
|
397
|
+
{
|
|
398
|
+
"name": "size",
|
|
399
|
+
"type": {
|
|
400
|
+
"text": "BadgeSize | undefined"
|
|
401
|
+
},
|
|
402
|
+
"description": "Badge size: `sm`, `lg`. Default is md.",
|
|
403
|
+
"fieldName": "size"
|
|
404
|
+
},
|
|
405
|
+
{
|
|
406
|
+
"name": "appearance",
|
|
407
|
+
"type": {
|
|
408
|
+
"text": "BadgeAppearance | undefined"
|
|
409
|
+
},
|
|
410
|
+
"description": "Visual appearance: `filled`, `filled-outlined`, `accent`. Default is outlined.",
|
|
411
|
+
"fieldName": "appearance"
|
|
412
|
+
}
|
|
413
|
+
],
|
|
414
|
+
"superclass": {
|
|
415
|
+
"name": "LuxenElement",
|
|
416
|
+
"module": "/src/html/shared/luxen-element.js"
|
|
417
|
+
},
|
|
418
|
+
"tagName": "l-badge",
|
|
419
|
+
"customElement": true,
|
|
420
|
+
"summary": "A badge component for displaying small status indicators."
|
|
421
|
+
}
|
|
422
|
+
],
|
|
423
|
+
"exports": [
|
|
424
|
+
{
|
|
425
|
+
"kind": "js",
|
|
426
|
+
"name": "Badge",
|
|
427
|
+
"declaration": {
|
|
428
|
+
"name": "Badge",
|
|
429
|
+
"module": "src/html/elements/badge/badge.ts"
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
]
|
|
433
|
+
},
|
|
434
|
+
{
|
|
435
|
+
"kind": "javascript-module",
|
|
436
|
+
"path": "src/html/elements/badge/index.ts",
|
|
437
|
+
"declarations": [],
|
|
438
|
+
"exports": [
|
|
439
|
+
{
|
|
440
|
+
"kind": "js",
|
|
441
|
+
"name": "*",
|
|
442
|
+
"declaration": {
|
|
443
|
+
"name": "*",
|
|
444
|
+
"module": "src/html/elements/badge/badge.js"
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
]
|
|
448
|
+
},
|
|
449
449
|
{
|
|
450
450
|
"kind": "javascript-module",
|
|
451
451
|
"path": "src/html/elements/button-group/button-group.ts",
|
|
@@ -6040,7 +6040,7 @@
|
|
|
6040
6040
|
"declarations": [
|
|
6041
6041
|
{
|
|
6042
6042
|
"kind": "class",
|
|
6043
|
-
"description": "A hierarchical tree view composed of `<l-tree-item>` children.",
|
|
6043
|
+
"description": "A hierarchical tree view composed of `<l-tree-item>` children.\n\nThe host carries `role=\"tree\"`, so give it an accessible name with\n`aria-label` or `aria-labelledby` (e.g. `<l-tree aria-label=\"Files\">`).",
|
|
6044
6044
|
"name": "Tree",
|
|
6045
6045
|
"cssProperties": [
|
|
6046
6046
|
{
|
|
@@ -6357,6 +6357,31 @@
|
|
|
6357
6357
|
"text": "number"
|
|
6358
6358
|
}
|
|
6359
6359
|
},
|
|
6360
|
+
{
|
|
6361
|
+
"kind": "method",
|
|
6362
|
+
"name": "setPosition",
|
|
6363
|
+
"parameters": [
|
|
6364
|
+
{
|
|
6365
|
+
"name": "level",
|
|
6366
|
+
"type": {
|
|
6367
|
+
"text": "number"
|
|
6368
|
+
}
|
|
6369
|
+
},
|
|
6370
|
+
{
|
|
6371
|
+
"name": "posInSet",
|
|
6372
|
+
"type": {
|
|
6373
|
+
"text": "number"
|
|
6374
|
+
}
|
|
6375
|
+
},
|
|
6376
|
+
{
|
|
6377
|
+
"name": "setSize",
|
|
6378
|
+
"type": {
|
|
6379
|
+
"text": "number"
|
|
6380
|
+
}
|
|
6381
|
+
}
|
|
6382
|
+
],
|
|
6383
|
+
"description": "Set by `<l-tree>`: ARIA position within the tree. `level` is 1-based depth,\n`posInSet`/`setSize` describe the item's rank among its siblings. These let\nscreen readers announce \"level 2, 3 of 5\" even when `lazy` children keep the\nfull set out of the DOM."
|
|
6384
|
+
},
|
|
6360
6385
|
{
|
|
6361
6386
|
"kind": "field",
|
|
6362
6387
|
"name": "hasChildren",
|
|
@@ -6405,7 +6430,7 @@
|
|
|
6405
6430
|
{
|
|
6406
6431
|
"kind": "method",
|
|
6407
6432
|
"name": "toggle",
|
|
6408
|
-
"description": "Toggle expand state.
|
|
6433
|
+
"description": "Toggle expand state. Opening a `lazy` item emits `lazy-load` (via `updated`)."
|
|
6409
6434
|
}
|
|
6410
6435
|
],
|
|
6411
6436
|
"events": [
|
|
@@ -58,9 +58,10 @@ export declare class ProseEditor extends LuxenFormAssociatedElement {
|
|
|
58
58
|
accessor autofocus: boolean;
|
|
59
59
|
/** Placeholder shown when the editor is empty. */
|
|
60
60
|
accessor placeholder: string;
|
|
61
|
-
accessor _emojiPickerActive: boolean;
|
|
62
61
|
private _editorRoot?;
|
|
63
62
|
private _emojiPicker?;
|
|
63
|
+
private _emojiPickerPromise?;
|
|
64
|
+
private _emojiOpenAtPointerDown;
|
|
64
65
|
get validationTarget(): HTMLElement | undefined;
|
|
65
66
|
private get _toolbar();
|
|
66
67
|
firstUpdated(): void;
|
|
@@ -103,7 +104,28 @@ export declare class ProseEditor extends LuxenFormAssociatedElement {
|
|
|
103
104
|
private _createEditorRoot;
|
|
104
105
|
private _onFocus;
|
|
105
106
|
private _onKeyDown;
|
|
106
|
-
|
|
107
|
+
/**
|
|
108
|
+
* The picker is a `popover="auto"`, so the platform owns outside-click
|
|
109
|
+
* dismissal: native light-dismiss in the top layer, which survives
|
|
110
|
+
* `stopPropagation()` from an ancestor (modal `<l-dialog>`, ProseMirror, Vue
|
|
111
|
+
* delegation), unlike emoji-mart's `document` click listener. (`Escape` is
|
|
112
|
+
* handled by `_onKeyDown` instead — ProseMirror `preventDefault()`s it, which
|
|
113
|
+
* would cancel the native close.)
|
|
114
|
+
*
|
|
115
|
+
* We can't wire the button as a native popover invoker (`popoverTargetElement`
|
|
116
|
+
* / `popovertarget`) because the picker is parented into another shadow tree
|
|
117
|
+
* (the open `<dialog>` — see `_topLayerContainer`) while the button lives in
|
|
118
|
+
* this element's shadow root; a cross-tree invoker reference doesn't resolve.
|
|
119
|
+
* So the toggle is hand-rolled here. The catch: a pointer click on the button
|
|
120
|
+
* is "outside" the popover, so native light-dismiss has already closed an open
|
|
121
|
+
* picker by the time this `click` fires (light-dismiss runs on `pointerup`).
|
|
122
|
+
* We therefore read the open state captured at `pointerdown` to know whether
|
|
123
|
+
* this click should re-open or stay closed. Keyboard activation (`detail === 0`)
|
|
124
|
+
* has no pointer light-dismiss, so it reads the live state and toggles directly.
|
|
125
|
+
*/
|
|
126
|
+
private _onEmojiButtonPointerDown;
|
|
127
|
+
private _onEmojiButtonClick;
|
|
128
|
+
private _ensureEmojiPicker;
|
|
107
129
|
/**
|
|
108
130
|
* The element the emoji picker is appended to. Inside a modal `<l-dialog>` the
|
|
109
131
|
* picker must live within the dialog's flat-tree subtree, otherwise the modal's
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prose-editor.d.ts","sourceRoot":"","sources":["../../../src/html/elements/prose-editor/prose-editor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,KAAK,cAAc,EAAE,KAAK,cAAc,EAAE,MAAM,KAAK,CAAC;AAO1E,OAAO,EAAE,MAAM,EAAE,KAAK,WAAW,EAAE,MAAM,cAAc,CAAC;AAIxD,OAAO,EAAE,0BAA0B,EAAE,MAAM,+CAA+C,CAAC;AAE3F,OAAO,kBAAkB,CAAC;AAK1B,KAAK,kBAAkB,GACnB,WAAW,GACX,WAAW,GACX,WAAW,GACX,MAAM,GACN,QAAQ,GACR,WAAW,GACX,QAAQ,GACR,WAAW,GACX,YAAY,GACZ,aAAa,GACb,YAAY,GACZ,YAAY,GACZ,iBAAiB,GACjB,MAAM,GACN,OAAO,GACP,YAAY,GACZ,MAAM,GACN,MAAM,GACN,SAAS,CAAC;AA2Bd;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,qBAAa,WAAY,SAAQ,0BAA0B;IACzD,OAAgB,MAAM,4BAAwB;IAE9C,oEAAoE;IACpE,MAAM,EAAG,MAAM,CAAC;IAEhB,4BAA4B;IAE5B,QAAQ,CAAC,WAAW,SAAM;IAE1B,+DAA+D;IAE/D,QAAQ,CAAC,WAAW,SAAM;IAE1B,mGAAmG;IAEnG,QAAQ,CAAC,WAAW,SAAW;IAE/B,8EAA8E;IAO9E,QAAQ,CAAC,OAAO,EAAE,kBAAkB,EAAE,CAAM;IAE5C,8DAA8D;IAE9D,QAAQ,CAAC,aAAa,EAAE,SAAS,GAAG,SAAS,CAAa;IAE1D,sDAAsD;IAEtD,QAAQ,CAAC,gBAAgB,EAAE,KAAK,GAAG,QAAQ,CAAS;IAEpD,oCAAoC;IAEpC,QAAQ,CAAC,SAAS,UAAS;IAE3B,kDAAkD;IAElD,QAAQ,CAAC,WAAW,SAAM;
|
|
1
|
+
{"version":3,"file":"prose-editor.d.ts","sourceRoot":"","sources":["../../../src/html/elements/prose-editor/prose-editor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,KAAK,cAAc,EAAE,KAAK,cAAc,EAAE,MAAM,KAAK,CAAC;AAO1E,OAAO,EAAE,MAAM,EAAE,KAAK,WAAW,EAAE,MAAM,cAAc,CAAC;AAIxD,OAAO,EAAE,0BAA0B,EAAE,MAAM,+CAA+C,CAAC;AAE3F,OAAO,kBAAkB,CAAC;AAK1B,KAAK,kBAAkB,GACnB,WAAW,GACX,WAAW,GACX,WAAW,GACX,MAAM,GACN,QAAQ,GACR,WAAW,GACX,QAAQ,GACR,WAAW,GACX,YAAY,GACZ,aAAa,GACb,YAAY,GACZ,YAAY,GACZ,iBAAiB,GACjB,MAAM,GACN,OAAO,GACP,YAAY,GACZ,MAAM,GACN,MAAM,GACN,SAAS,CAAC;AA2Bd;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,qBAAa,WAAY,SAAQ,0BAA0B;IACzD,OAAgB,MAAM,4BAAwB;IAE9C,oEAAoE;IACpE,MAAM,EAAG,MAAM,CAAC;IAEhB,4BAA4B;IAE5B,QAAQ,CAAC,WAAW,SAAM;IAE1B,+DAA+D;IAE/D,QAAQ,CAAC,WAAW,SAAM;IAE1B,mGAAmG;IAEnG,QAAQ,CAAC,WAAW,SAAW;IAE/B,8EAA8E;IAO9E,QAAQ,CAAC,OAAO,EAAE,kBAAkB,EAAE,CAAM;IAE5C,8DAA8D;IAE9D,QAAQ,CAAC,aAAa,EAAE,SAAS,GAAG,SAAS,CAAa;IAE1D,sDAAsD;IAEtD,QAAQ,CAAC,gBAAgB,EAAE,KAAK,GAAG,QAAQ,CAAS;IAEpD,oCAAoC;IAEpC,QAAQ,CAAC,SAAS,UAAS;IAE3B,kDAAkD;IAElD,QAAQ,CAAC,WAAW,SAAM;IAE1B,OAAO,CAAC,WAAW,CAAC,CAAiB;IACrC,OAAO,CAAC,YAAY,CAAC,CAAc;IACnC,OAAO,CAAC,mBAAmB,CAAC,CAAuB;IACnD,OAAO,CAAC,uBAAuB,CAAS;IAExC,IAAa,gBAAgB,IAAI,WAAW,GAAG,SAAS,CAEvD;IAED,OAAO,KAAK,QAAQ,GAEnB;IAEQ,YAAY;IAkCZ,OAAO,CAAC,OAAO,EAAE,cAAc,CAAC,IAAI,CAAC;IAMrC,oBAAoB;IAW7B,mFAAmF;IACnF,OAAO,IAAI,MAAM;IAMjB,mDAAmD;IACnD,OAAO,IAAI,WAAW;IAItB,0BAA0B;IAC1B,KAAK;IAII,KAAK;IAIL,IAAI;IAIb,UAAU;IAIV,YAAY;IAIZ,eAAe;IAIf,YAAY;IAIZ,eAAe;IAIf,aAAa,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC;IAI9B,gBAAgB;IAIhB,iBAAiB;IAIjB,gBAAgB;IAIhB,eAAe;IAIf,iBAAiB;IAIjB,IAAI;IAIJ,IAAI;IAIJ,UAAU;IAaD,iBAAiB;IAK1B,mFAAmF;IACnF,OAAO,CAAC,UAAU;IAalB,OAAO,CAAC,WAAW;IAQnB,OAAO,CAAC,eAAe;IAQvB;;;;;;OAMG;IACH,OAAO,CAAC,iBAAiB;IAQzB,OAAO,CAAC,QAAQ,CAId;IAEF,OAAO,CAAC,UAAU,CAMhB;IAIF;;;;;;;;;;;;;;;;;;OAkBG;IACH,OAAO,CAAC,yBAAyB,CAE/B;YAEY,mBAAmB;IAWjC,OAAO,CAAC,kBAAkB;IA0C1B;;;;;;OAMG;IACH,OAAO,CAAC,kBAAkB;IAe1B,OAAO,KAAK,YAAY,GAEvB;YAEa,oBAAoB;IAiBlC,OAAO,CAAC,aAAa;IA0BrB,OAAO,CAAC,kBAAkB;IA0IjB,MAAM;CAyBhB"}
|
|
@@ -15,11 +15,11 @@ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (
|
|
|
15
15
|
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
|
|
16
16
|
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
|
17
17
|
};
|
|
18
|
-
var _ProseEditor_initialHtml_accessor_storage, _ProseEditor_initialJson_accessor_storage, _ProseEditor_editorClass_accessor_storage, _ProseEditor_toolbar_accessor_storage, _ProseEditor_toolbarPreset_accessor_storage, _ProseEditor_toolbarPlacement_accessor_storage, _ProseEditor_autofocus_accessor_storage, _ProseEditor_placeholder_accessor_storage
|
|
18
|
+
var _ProseEditor_initialHtml_accessor_storage, _ProseEditor_initialJson_accessor_storage, _ProseEditor_editorClass_accessor_storage, _ProseEditor_toolbar_accessor_storage, _ProseEditor_toolbarPreset_accessor_storage, _ProseEditor_toolbarPlacement_accessor_storage, _ProseEditor_autofocus_accessor_storage, _ProseEditor_placeholder_accessor_storage;
|
|
19
19
|
import { unsafeCSS } from 'lit';
|
|
20
20
|
import { html } from 'lit/static-html.js';
|
|
21
21
|
import { staticTag } from '../../static-tag.js';
|
|
22
|
-
import { property
|
|
22
|
+
import { property } from 'lit/decorators.js';
|
|
23
23
|
import { classMap } from 'lit/directives/class-map.js';
|
|
24
24
|
import { map } from 'lit/directives/map.js';
|
|
25
25
|
import { computePosition, flip, offset, shift } from '@floating-ui/dom';
|
|
@@ -102,15 +102,42 @@ export class ProseEditor extends LuxenFormAssociatedElement {
|
|
|
102
102
|
_ProseEditor_toolbarPlacement_accessor_storage.set(this, 'top');
|
|
103
103
|
_ProseEditor_autofocus_accessor_storage.set(this, false);
|
|
104
104
|
_ProseEditor_placeholder_accessor_storage.set(this, '');
|
|
105
|
-
|
|
105
|
+
this._emojiOpenAtPointerDown = false;
|
|
106
106
|
this._onFocus = () => {
|
|
107
107
|
if (!this.disabled && document.activeElement !== this.editor?.view.dom) {
|
|
108
108
|
this.focus();
|
|
109
109
|
}
|
|
110
110
|
};
|
|
111
111
|
this._onKeyDown = (event) => {
|
|
112
|
-
if (event.key
|
|
113
|
-
|
|
112
|
+
if (event.key !== 'Escape' || !this._emojiPicker?.matches(':popover-open'))
|
|
113
|
+
return;
|
|
114
|
+
this._emojiPicker.hidePopover();
|
|
115
|
+
// Consume the Escape so it dismisses only the picker, not the host dialog.
|
|
116
|
+
event.preventDefault();
|
|
117
|
+
event.stopPropagation();
|
|
118
|
+
};
|
|
119
|
+
// --- Emoji picker (lazy-loaded) ---
|
|
120
|
+
/**
|
|
121
|
+
* The picker is a `popover="auto"`, so the platform owns outside-click
|
|
122
|
+
* dismissal: native light-dismiss in the top layer, which survives
|
|
123
|
+
* `stopPropagation()` from an ancestor (modal `<l-dialog>`, ProseMirror, Vue
|
|
124
|
+
* delegation), unlike emoji-mart's `document` click listener. (`Escape` is
|
|
125
|
+
* handled by `_onKeyDown` instead — ProseMirror `preventDefault()`s it, which
|
|
126
|
+
* would cancel the native close.)
|
|
127
|
+
*
|
|
128
|
+
* We can't wire the button as a native popover invoker (`popoverTargetElement`
|
|
129
|
+
* / `popovertarget`) because the picker is parented into another shadow tree
|
|
130
|
+
* (the open `<dialog>` — see `_topLayerContainer`) while the button lives in
|
|
131
|
+
* this element's shadow root; a cross-tree invoker reference doesn't resolve.
|
|
132
|
+
* So the toggle is hand-rolled here. The catch: a pointer click on the button
|
|
133
|
+
* is "outside" the popover, so native light-dismiss has already closed an open
|
|
134
|
+
* picker by the time this `click` fires (light-dismiss runs on `pointerup`).
|
|
135
|
+
* We therefore read the open state captured at `pointerdown` to know whether
|
|
136
|
+
* this click should re-open or stay closed. Keyboard activation (`detail === 0`)
|
|
137
|
+
* has no pointer light-dismiss, so it reads the live state and toggles directly.
|
|
138
|
+
*/
|
|
139
|
+
this._onEmojiButtonPointerDown = () => {
|
|
140
|
+
this._emojiOpenAtPointerDown = !!this._emojiPicker?.matches(':popover-open');
|
|
114
141
|
};
|
|
115
142
|
}
|
|
116
143
|
/** Initial HTML content. */
|
|
@@ -137,8 +164,6 @@ export class ProseEditor extends LuxenFormAssociatedElement {
|
|
|
137
164
|
/** Placeholder shown when the editor is empty. */
|
|
138
165
|
get placeholder() { return __classPrivateFieldGet(this, _ProseEditor_placeholder_accessor_storage, "f"); }
|
|
139
166
|
set placeholder(value) { __classPrivateFieldSet(this, _ProseEditor_placeholder_accessor_storage, value, "f"); }
|
|
140
|
-
get _emojiPickerActive() { return __classPrivateFieldGet(this, _ProseEditor__emojiPickerActive_accessor_storage, "f"); }
|
|
141
|
-
set _emojiPickerActive(value) { __classPrivateFieldSet(this, _ProseEditor__emojiPickerActive_accessor_storage, value, "f"); }
|
|
142
167
|
get validationTarget() {
|
|
143
168
|
return this._editorRoot;
|
|
144
169
|
}
|
|
@@ -166,8 +191,14 @@ export class ProseEditor extends LuxenFormAssociatedElement {
|
|
|
166
191
|
onTransaction: () => this.requestUpdate(),
|
|
167
192
|
onSelectionUpdate: () => this.requestUpdate(),
|
|
168
193
|
});
|
|
169
|
-
document.addEventListener('keydown', this._onKeyDown);
|
|
170
194
|
this.addEventListener('focus', this._onFocus);
|
|
195
|
+
// Escape is handled in JS, not by the popover's native close watcher:
|
|
196
|
+
// ProseMirror `preventDefault()`s Escape while the editor is focused, which
|
|
197
|
+
// cancels the native close (popover and dialog alike). Capture phase on
|
|
198
|
+
// `document` runs before that, can't be defeated by descendant
|
|
199
|
+
// `stopPropagation()`, and only needs the event to propagate — not its
|
|
200
|
+
// default action.
|
|
201
|
+
document.addEventListener('keydown', this._onKeyDown, true);
|
|
171
202
|
this._syncValue();
|
|
172
203
|
this.requestUpdate();
|
|
173
204
|
}
|
|
@@ -175,14 +206,11 @@ export class ProseEditor extends LuxenFormAssociatedElement {
|
|
|
175
206
|
if (changed.has('disabled') && this.editor) {
|
|
176
207
|
this.editor.setEditable(!this.disabled);
|
|
177
208
|
}
|
|
178
|
-
if (changed.has('_emojiPickerActive')) {
|
|
179
|
-
void this._positionEmojiPicker();
|
|
180
|
-
}
|
|
181
209
|
}
|
|
182
210
|
disconnectedCallback() {
|
|
183
211
|
super.disconnectedCallback();
|
|
184
|
-
document.removeEventListener('keydown', this._onKeyDown);
|
|
185
212
|
this.removeEventListener('focus', this._onFocus);
|
|
213
|
+
document.removeEventListener('keydown', this._onKeyDown, true);
|
|
186
214
|
this.editor?.destroy();
|
|
187
215
|
this._editorRoot?.remove();
|
|
188
216
|
this._emojiPicker?.remove();
|
|
@@ -304,36 +332,45 @@ export class ProseEditor extends LuxenFormAssociatedElement {
|
|
|
304
332
|
this._editorRoot = root;
|
|
305
333
|
return root;
|
|
306
334
|
}
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
335
|
+
async _onEmojiButtonClick(event) {
|
|
336
|
+
const picker = await this._ensureEmojiPicker();
|
|
337
|
+
const wasOpen = event.detail === 0 ? picker.matches(':popover-open') : this._emojiOpenAtPointerDown;
|
|
338
|
+
if (wasOpen) {
|
|
339
|
+
if (picker.matches(':popover-open'))
|
|
340
|
+
picker.hidePopover();
|
|
341
|
+
}
|
|
342
|
+
else if (!picker.matches(':popover-open')) {
|
|
343
|
+
picker.showPopover();
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
_ensureEmojiPicker() {
|
|
347
|
+
if (this._emojiPicker)
|
|
348
|
+
return Promise.resolve(this._emojiPicker);
|
|
349
|
+
return (this._emojiPickerPromise ?? (this._emojiPickerPromise = (async () => {
|
|
310
350
|
const [{ Picker }, { default: data }] = await Promise.all([
|
|
311
351
|
import('emoji-mart'),
|
|
312
352
|
import('@emoji-mart/data'),
|
|
313
353
|
]);
|
|
314
354
|
const dark = window.matchMedia('(prefers-color-scheme: dark)').matches;
|
|
315
|
-
|
|
355
|
+
const picker = new Picker({
|
|
316
356
|
parent: this._topLayerContainer(),
|
|
317
357
|
data,
|
|
318
358
|
theme: dark ? 'dark' : 'light',
|
|
319
359
|
onEmojiSelect: ({ native }) => {
|
|
320
360
|
this.editor.chain().focus().insertContent(native).run();
|
|
321
|
-
|
|
322
|
-
},
|
|
323
|
-
onClickOutside: (event) => {
|
|
324
|
-
if (!event.composedPath().includes(this._emojiButton)) {
|
|
325
|
-
this._emojiPickerActive = false;
|
|
326
|
-
}
|
|
361
|
+
picker.hidePopover();
|
|
327
362
|
},
|
|
328
363
|
});
|
|
329
|
-
// A popover promotes the picker into the top-layer
|
|
330
|
-
// modal <l-dialog> and escapes
|
|
331
|
-
//
|
|
332
|
-
//
|
|
333
|
-
//
|
|
334
|
-
//
|
|
335
|
-
|
|
336
|
-
|
|
364
|
+
// A popover="auto" promotes the picker into the top-layer (so it paints
|
|
365
|
+
// above a modal <l-dialog> and escapes ancestor overflow clipping) and
|
|
366
|
+
// hands outside-click dismissal to the platform's native light-dismiss.
|
|
367
|
+
// Top-layer alone isn't enough inside a modal: showModal()
|
|
368
|
+
// makes everything outside the dialog's flat-tree subtree inert (visible
|
|
369
|
+
// but unclickable), so the picker is parented to the nearest open <dialog>
|
|
370
|
+
// — see _topLayerContainer. Neutralize the UA popover box; Floating UI
|
|
371
|
+
// drives the position in _positionEmojiPicker.
|
|
372
|
+
picker.setAttribute('popover', 'auto');
|
|
373
|
+
Object.assign(picker.style, {
|
|
337
374
|
position: 'fixed',
|
|
338
375
|
inset: 'auto',
|
|
339
376
|
margin: '0',
|
|
@@ -341,8 +378,13 @@ export class ProseEditor extends LuxenFormAssociatedElement {
|
|
|
341
378
|
border: '0',
|
|
342
379
|
background: 'transparent',
|
|
343
380
|
});
|
|
344
|
-
|
|
345
|
-
|
|
381
|
+
picker.addEventListener('toggle', (event) => {
|
|
382
|
+
if (event.newState === 'open')
|
|
383
|
+
void this._positionEmojiPicker();
|
|
384
|
+
});
|
|
385
|
+
this._emojiPicker = picker;
|
|
386
|
+
return picker;
|
|
387
|
+
})()));
|
|
346
388
|
}
|
|
347
389
|
/**
|
|
348
390
|
* The element the emoji picker is appended to. Inside a modal `<l-dialog>` the
|
|
@@ -373,18 +415,11 @@ export class ProseEditor extends LuxenFormAssociatedElement {
|
|
|
373
415
|
}
|
|
374
416
|
async _positionEmojiPicker() {
|
|
375
417
|
const button = this._emojiButton;
|
|
376
|
-
if (!button || !this._emojiPicker)
|
|
377
|
-
return;
|
|
378
418
|
const picker = this._emojiPicker;
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
419
|
+
// Runs from the picker's `toggle` event once it is open, so it is already
|
|
420
|
+
// laid out in the top-layer and can be measured.
|
|
421
|
+
if (!button || !picker || !picker.matches(':popover-open'))
|
|
382
422
|
return;
|
|
383
|
-
}
|
|
384
|
-
// Show first so the picker is laid out (and in the top-layer) before we
|
|
385
|
-
// measure it; a closed popover is display:none and would size to 0.
|
|
386
|
-
if (!picker.matches(':popover-open'))
|
|
387
|
-
picker.showPopover();
|
|
388
423
|
const { x, y } = await computePosition(button, picker, {
|
|
389
424
|
strategy: 'fixed',
|
|
390
425
|
placement: 'bottom',
|
|
@@ -393,7 +428,7 @@ export class ProseEditor extends LuxenFormAssociatedElement {
|
|
|
393
428
|
Object.assign(picker.style, { left: `${x}px`, top: `${y}px` });
|
|
394
429
|
}
|
|
395
430
|
// --- Rendering ---
|
|
396
|
-
_renderButton(command, label, icon, onClick, active = false) {
|
|
431
|
+
_renderButton(command, label, icon, onClick, active = false, onPointerDown) {
|
|
397
432
|
const iconTag = staticTag('icon');
|
|
398
433
|
return html `
|
|
399
434
|
<button
|
|
@@ -404,6 +439,7 @@ export class ProseEditor extends LuxenFormAssociatedElement {
|
|
|
404
439
|
aria-label=${label}
|
|
405
440
|
aria-pressed=${active}
|
|
406
441
|
title=${label}
|
|
442
|
+
@pointerdown=${onPointerDown}
|
|
407
443
|
@click=${onClick}
|
|
408
444
|
>
|
|
409
445
|
<${iconTag} name=${icon}></${iconTag}>
|
|
@@ -447,7 +483,7 @@ export class ProseEditor extends LuxenFormAssociatedElement {
|
|
|
447
483
|
case 'link':
|
|
448
484
|
return this._renderButton('link', 'Link', 'ri:link', () => this.toggleLink(), editor.isActive('link'));
|
|
449
485
|
case 'emoji':
|
|
450
|
-
return this._renderButton('emoji', 'Emoji', 'ri:emotion-line', () => void this.
|
|
486
|
+
return this._renderButton('emoji', 'Emoji', 'ri:emotion-line', (event) => void this._onEmojiButtonClick(event), false, this._onEmojiButtonPointerDown);
|
|
451
487
|
case 'attachment':
|
|
452
488
|
return this._renderButton('attachment', 'Attach file', 'ri:attachment-2', () => this.emit('add-file'));
|
|
453
489
|
case 'undo':
|
|
@@ -484,7 +520,7 @@ export class ProseEditor extends LuxenFormAssociatedElement {
|
|
|
484
520
|
`;
|
|
485
521
|
}
|
|
486
522
|
}
|
|
487
|
-
_ProseEditor_initialHtml_accessor_storage = new WeakMap(), _ProseEditor_initialJson_accessor_storage = new WeakMap(), _ProseEditor_editorClass_accessor_storage = new WeakMap(), _ProseEditor_toolbar_accessor_storage = new WeakMap(), _ProseEditor_toolbarPreset_accessor_storage = new WeakMap(), _ProseEditor_toolbarPlacement_accessor_storage = new WeakMap(), _ProseEditor_autofocus_accessor_storage = new WeakMap(), _ProseEditor_placeholder_accessor_storage = new WeakMap()
|
|
523
|
+
_ProseEditor_initialHtml_accessor_storage = new WeakMap(), _ProseEditor_initialJson_accessor_storage = new WeakMap(), _ProseEditor_editorClass_accessor_storage = new WeakMap(), _ProseEditor_toolbar_accessor_storage = new WeakMap(), _ProseEditor_toolbarPreset_accessor_storage = new WeakMap(), _ProseEditor_toolbarPlacement_accessor_storage = new WeakMap(), _ProseEditor_autofocus_accessor_storage = new WeakMap(), _ProseEditor_placeholder_accessor_storage = new WeakMap();
|
|
488
524
|
ProseEditor.styles = [hostStyles, styles];
|
|
489
525
|
__decorate([
|
|
490
526
|
property({ attribute: 'initial-html' })
|
|
@@ -515,6 +551,3 @@ __decorate([
|
|
|
515
551
|
__decorate([
|
|
516
552
|
property()
|
|
517
553
|
], ProseEditor.prototype, "placeholder", null);
|
|
518
|
-
__decorate([
|
|
519
|
-
state()
|
|
520
|
-
], ProseEditor.prototype, "_emojiPickerActive", null);
|