luxen-ui 0.9.2 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cdn/chunks/picker.js +5 -0
- package/cdn/chunks/picker.js.map +1 -0
- package/cdn/custom-elements.json +73 -49
- package/cdn/elements/avatar/avatar.d.ts +1 -0
- package/cdn/elements/avatar/avatar.d.ts.map +1 -1
- package/cdn/elements/avatar/avatar.js +1 -1
- package/cdn/elements/avatar/avatar.js.map +1 -1
- package/cdn/elements/prose-editor/prose-editor.d.ts +39 -11
- package/cdn/elements/prose-editor/prose-editor.d.ts.map +1 -1
- package/cdn/elements/prose-editor/prose-editor.js +36 -36
- package/cdn/elements/prose-editor/prose-editor.js.map +1 -1
- package/cdn/elements/tree-item/tree-item.js +1 -1
- package/cdn/elements/tree-item/tree-item.js.map +1 -1
- package/cdn/standalone.js +1768 -4166
- package/cdn/standalone.js.map +1 -1
- package/dist/custom-elements.json +73 -49
- package/dist/elements/avatar/avatar.css +10 -10
- package/dist/elements/avatar/avatar.d.ts +1 -0
- package/dist/elements/avatar/avatar.d.ts.map +1 -1
- package/dist/elements/avatar/avatar.js +1 -0
- package/dist/elements/prose-editor/prose-editor.d.ts +39 -11
- package/dist/elements/prose-editor/prose-editor.d.ts.map +1 -1
- package/dist/elements/prose-editor/prose-editor.js +114 -38
- package/dist/elements/tree-item/tree-item.css +7 -1
- package/dist/metadata/avatar.json +5 -0
- package/dist/metadata/index.json +14 -1
- package/dist/metadata/prose-editor.json +8 -0
- package/dist/templates/elements/avatar.md +23 -0
- package/dist/templates/elements/prose-editor.md +11 -0
- package/package.json +2 -3
- package/cdn/chunks/module.js +0 -717
- package/cdn/chunks/module.js.map +0 -1
- package/cdn/chunks/native.js +0 -2
- package/cdn/chunks/native.js.map +0 -1
|
@@ -11,6 +11,11 @@
|
|
|
11
11
|
"description": "",
|
|
12
12
|
"name": "Avatar",
|
|
13
13
|
"cssProperties": [
|
|
14
|
+
{
|
|
15
|
+
"description": "Box size (any length). Set it inline (e.g. `style=\"--size: 20px\"`) for an arbitrary size beyond the `size` token scale; the font then follows proportionally. The `size` attribute sets it to the matching token.",
|
|
16
|
+
"name": "--size",
|
|
17
|
+
"default": "40px"
|
|
18
|
+
},
|
|
14
19
|
{
|
|
15
20
|
"description": "Background fill color for initials and the default icon.",
|
|
16
21
|
"name": "--color"
|
|
@@ -1144,6 +1149,55 @@
|
|
|
1144
1149
|
}
|
|
1145
1150
|
]
|
|
1146
1151
|
},
|
|
1152
|
+
{
|
|
1153
|
+
"kind": "javascript-module",
|
|
1154
|
+
"path": "src/html/elements/carousel-item/carousel-item.ts",
|
|
1155
|
+
"declarations": [
|
|
1156
|
+
{
|
|
1157
|
+
"kind": "class",
|
|
1158
|
+
"description": "A single slide inside an `<l-carousel>`.",
|
|
1159
|
+
"name": "CarouselItem",
|
|
1160
|
+
"cssProperties": [
|
|
1161
|
+
{
|
|
1162
|
+
"description": "Aspect ratio of the slide.",
|
|
1163
|
+
"name": "--aspect-ratio"
|
|
1164
|
+
}
|
|
1165
|
+
],
|
|
1166
|
+
"members": [],
|
|
1167
|
+
"superclass": {
|
|
1168
|
+
"name": "LuxenElement",
|
|
1169
|
+
"module": "/src/html/shared/luxen-element.js"
|
|
1170
|
+
},
|
|
1171
|
+
"tagName": "l-carousel-item",
|
|
1172
|
+
"customElement": true
|
|
1173
|
+
}
|
|
1174
|
+
],
|
|
1175
|
+
"exports": [
|
|
1176
|
+
{
|
|
1177
|
+
"kind": "js",
|
|
1178
|
+
"name": "CarouselItem",
|
|
1179
|
+
"declaration": {
|
|
1180
|
+
"name": "CarouselItem",
|
|
1181
|
+
"module": "src/html/elements/carousel-item/carousel-item.ts"
|
|
1182
|
+
}
|
|
1183
|
+
}
|
|
1184
|
+
]
|
|
1185
|
+
},
|
|
1186
|
+
{
|
|
1187
|
+
"kind": "javascript-module",
|
|
1188
|
+
"path": "src/html/elements/carousel-item/index.ts",
|
|
1189
|
+
"declarations": [],
|
|
1190
|
+
"exports": [
|
|
1191
|
+
{
|
|
1192
|
+
"kind": "js",
|
|
1193
|
+
"name": "*",
|
|
1194
|
+
"declaration": {
|
|
1195
|
+
"name": "*",
|
|
1196
|
+
"module": "src/html/elements/carousel-item/carousel-item.js"
|
|
1197
|
+
}
|
|
1198
|
+
}
|
|
1199
|
+
]
|
|
1200
|
+
},
|
|
1147
1201
|
{
|
|
1148
1202
|
"kind": "javascript-module",
|
|
1149
1203
|
"path": "src/html/elements/checkbox/checkbox.meta.ts",
|
|
@@ -1248,55 +1302,6 @@
|
|
|
1248
1302
|
}
|
|
1249
1303
|
]
|
|
1250
1304
|
},
|
|
1251
|
-
{
|
|
1252
|
-
"kind": "javascript-module",
|
|
1253
|
-
"path": "src/html/elements/carousel-item/carousel-item.ts",
|
|
1254
|
-
"declarations": [
|
|
1255
|
-
{
|
|
1256
|
-
"kind": "class",
|
|
1257
|
-
"description": "A single slide inside an `<l-carousel>`.",
|
|
1258
|
-
"name": "CarouselItem",
|
|
1259
|
-
"cssProperties": [
|
|
1260
|
-
{
|
|
1261
|
-
"description": "Aspect ratio of the slide.",
|
|
1262
|
-
"name": "--aspect-ratio"
|
|
1263
|
-
}
|
|
1264
|
-
],
|
|
1265
|
-
"members": [],
|
|
1266
|
-
"superclass": {
|
|
1267
|
-
"name": "LuxenElement",
|
|
1268
|
-
"module": "/src/html/shared/luxen-element.js"
|
|
1269
|
-
},
|
|
1270
|
-
"tagName": "l-carousel-item",
|
|
1271
|
-
"customElement": true
|
|
1272
|
-
}
|
|
1273
|
-
],
|
|
1274
|
-
"exports": [
|
|
1275
|
-
{
|
|
1276
|
-
"kind": "js",
|
|
1277
|
-
"name": "CarouselItem",
|
|
1278
|
-
"declaration": {
|
|
1279
|
-
"name": "CarouselItem",
|
|
1280
|
-
"module": "src/html/elements/carousel-item/carousel-item.ts"
|
|
1281
|
-
}
|
|
1282
|
-
}
|
|
1283
|
-
]
|
|
1284
|
-
},
|
|
1285
|
-
{
|
|
1286
|
-
"kind": "javascript-module",
|
|
1287
|
-
"path": "src/html/elements/carousel-item/index.ts",
|
|
1288
|
-
"declarations": [],
|
|
1289
|
-
"exports": [
|
|
1290
|
-
{
|
|
1291
|
-
"kind": "js",
|
|
1292
|
-
"name": "*",
|
|
1293
|
-
"declaration": {
|
|
1294
|
-
"name": "*",
|
|
1295
|
-
"module": "src/html/elements/carousel-item/carousel-item.js"
|
|
1296
|
-
}
|
|
1297
|
-
}
|
|
1298
|
-
]
|
|
1299
|
-
},
|
|
1300
1305
|
{
|
|
1301
1306
|
"kind": "javascript-module",
|
|
1302
1307
|
"path": "src/html/elements/close-button/close-button.meta.ts",
|
|
@@ -3803,6 +3808,16 @@
|
|
|
3803
3808
|
"description": "Placeholder shown when the editor is empty.",
|
|
3804
3809
|
"attribute": "placeholder"
|
|
3805
3810
|
},
|
|
3811
|
+
{
|
|
3812
|
+
"kind": "field",
|
|
3813
|
+
"name": "emojiDataSource",
|
|
3814
|
+
"type": {
|
|
3815
|
+
"text": "string"
|
|
3816
|
+
},
|
|
3817
|
+
"default": "''",
|
|
3818
|
+
"description": "URL the emoji picker fetches its data from. Point this at a locally served\n`emojibase-data` JSON to run fully offline (no CDN). Defaults to the\npicker's bundled CDN source.",
|
|
3819
|
+
"attribute": "emoji-data-source"
|
|
3820
|
+
},
|
|
3806
3821
|
{
|
|
3807
3822
|
"kind": "field",
|
|
3808
3823
|
"name": "validationTarget",
|
|
@@ -3997,6 +4012,15 @@
|
|
|
3997
4012
|
"default": "''",
|
|
3998
4013
|
"description": "Placeholder shown when the editor is empty.",
|
|
3999
4014
|
"fieldName": "placeholder"
|
|
4015
|
+
},
|
|
4016
|
+
{
|
|
4017
|
+
"name": "emoji-data-source",
|
|
4018
|
+
"type": {
|
|
4019
|
+
"text": "string"
|
|
4020
|
+
},
|
|
4021
|
+
"default": "''",
|
|
4022
|
+
"description": "URL the emoji picker fetches its data from. Point this at a locally served\n`emojibase-data` JSON to run fully offline (no CDN). Defaults to the\npicker's bundled CDN source.",
|
|
4023
|
+
"fieldName": "emojiDataSource"
|
|
4000
4024
|
}
|
|
4001
4025
|
],
|
|
4002
4026
|
"superclass": {
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
:host {
|
|
2
|
-
--
|
|
3
|
-
--_font-size:
|
|
2
|
+
--size: 40px;
|
|
3
|
+
--_font-size: calc(var(--size) * 0.4);
|
|
4
4
|
display: inline-flex;
|
|
5
5
|
align-items: center;
|
|
6
6
|
justify-content: center;
|
|
7
7
|
position: relative;
|
|
8
|
-
width: var(--
|
|
9
|
-
height: var(--
|
|
10
|
-
border-radius: calc(var(--
|
|
8
|
+
width: var(--size);
|
|
9
|
+
height: var(--size);
|
|
10
|
+
border-radius: calc(var(--size) * 0.15);
|
|
11
11
|
isolation: isolate;
|
|
12
12
|
vertical-align: middle;
|
|
13
13
|
flex-shrink: 0;
|
|
@@ -15,19 +15,19 @@
|
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
:host([size='xs']) {
|
|
18
|
-
--
|
|
18
|
+
--size: 24px;
|
|
19
19
|
--_font-size: 0.75rem;
|
|
20
20
|
}
|
|
21
21
|
:host([size='sm']) {
|
|
22
|
-
--
|
|
22
|
+
--size: 32px;
|
|
23
23
|
--_font-size: 0.875rem;
|
|
24
24
|
}
|
|
25
25
|
:host([size='lg']) {
|
|
26
|
-
--
|
|
26
|
+
--size: 48px;
|
|
27
27
|
--_font-size: 1.25rem;
|
|
28
28
|
}
|
|
29
29
|
:host([size='xl']) {
|
|
30
|
-
--
|
|
30
|
+
--size: 56px;
|
|
31
31
|
--_font-size: 1.25rem;
|
|
32
32
|
}
|
|
33
33
|
|
|
@@ -91,7 +91,7 @@ img {
|
|
|
91
91
|
width: 100%;
|
|
92
92
|
height: 100%;
|
|
93
93
|
border: none;
|
|
94
|
-
border-radius: calc(var(--
|
|
94
|
+
border-radius: calc(var(--size) * 0.15);
|
|
95
95
|
background-color: var(--color, var(--l-color-bg-fill-neutral-soft));
|
|
96
96
|
/*
|
|
97
97
|
* Text over --color, decided by the background's own luminance — never the
|
|
@@ -3,6 +3,7 @@ import { LuxenElement } from '../../shared/luxen-element.js';
|
|
|
3
3
|
* @summary An avatar component for displaying user images, initials, or a default icon.
|
|
4
4
|
* @customElement l-avatar
|
|
5
5
|
*
|
|
6
|
+
* @cssproperty [--size=40px] - Box size (any length). Set it inline (e.g. `style="--size: 20px"`) for an arbitrary size beyond the `size` token scale; the font then follows proportionally. The `size` attribute sets it to the matching token.
|
|
6
7
|
* @cssproperty --color - Background fill color for initials and the default icon.
|
|
7
8
|
* @cssproperty --text-color - Initials/icon color over `--color`. Defaults to an auto-derived readable color; set it to enforce a specific brand color (overrides the automatic choice).
|
|
8
9
|
* @cssproperty --appearance - Set to `circle` for a fully circular avatar (default is a rounded square).
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"avatar.d.ts","sourceRoot":"","sources":["../../../src/html/elements/avatar/avatar.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAqB7D
|
|
1
|
+
{"version":3,"file":"avatar.d.ts","sourceRoot":"","sources":["../../../src/html/elements/avatar/avatar.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAqB7D;;;;;;;;;;;;GAYG;AACH,qBAAa,MAAO,SAAQ,YAAY;IACtC,MAAM,CAAC,MAAM,4BAAwB;IAErC,qFAAqF;IAErF,GAAG,SAAM;IAET,6EAA6E;IAE7E,IAAI,SAAM;IAEV,8DAA8D;IAE9D,IAAI,SAAQ;IAEZ,4DAA4D;IAE5D,KAAK,SAAK;IAEV,+DAA+D;IAE/D,WAAW,UAAS;IAEX,OAAO,CAAC,SAAS,CAAS;IAEnC,UAAU,CAAC,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC;IAMxC,iBAAiB;IAOjB,OAAO;IASP,OAAO,KAAK,IAAI,GAEf;IAED,MAAM;IA6BN,OAAO,CAAC,QAAQ,CAEd;CACH"}
|
|
@@ -26,6 +26,7 @@ const defaultIcon = svg `<svg class="icon" viewBox="0 0 24 24" fill="currentColo
|
|
|
26
26
|
* @summary An avatar component for displaying user images, initials, or a default icon.
|
|
27
27
|
* @customElement l-avatar
|
|
28
28
|
*
|
|
29
|
+
* @cssproperty [--size=40px] - Box size (any length). Set it inline (e.g. `style="--size: 20px"`) for an arbitrary size beyond the `size` token scale; the font then follows proportionally. The `size` attribute sets it to the matching token.
|
|
29
30
|
* @cssproperty --color - Background fill color for initials and the default icon.
|
|
30
31
|
* @cssproperty --text-color - Initials/icon color over `--color`. Defaults to an auto-derived readable color; set it to enforce a specific brand color (overrides the automatic choice).
|
|
31
32
|
* @cssproperty --appearance - Set to `circle` for a fully circular avatar (default is a rounded square).
|
|
@@ -58,10 +58,17 @@ 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
|
+
/**
|
|
62
|
+
* URL the emoji picker fetches its data from. Point this at a locally served
|
|
63
|
+
* `emojibase-data` JSON to run fully offline (no CDN). Defaults to the
|
|
64
|
+
* picker's bundled CDN source.
|
|
65
|
+
*/
|
|
66
|
+
accessor emojiDataSource: string;
|
|
61
67
|
private _editorRoot?;
|
|
62
68
|
private _emojiPicker?;
|
|
63
69
|
private _emojiPickerPromise?;
|
|
64
70
|
private _emojiOpenAtPointerDown;
|
|
71
|
+
private _emojiAutoUpdateCleanup?;
|
|
65
72
|
get validationTarget(): HTMLElement | undefined;
|
|
66
73
|
private get _toolbar();
|
|
67
74
|
firstUpdated(): void;
|
|
@@ -105,23 +112,34 @@ export declare class ProseEditor extends LuxenFormAssociatedElement {
|
|
|
105
112
|
private _onFocus;
|
|
106
113
|
private _onKeyDown;
|
|
107
114
|
/**
|
|
108
|
-
*
|
|
109
|
-
*
|
|
110
|
-
*
|
|
111
|
-
*
|
|
112
|
-
*
|
|
113
|
-
*
|
|
115
|
+
* Capture-phase outside-click dismissal — the robust fallback the platform's
|
|
116
|
+
* native light-dismiss can't be trusted to provide (see `firstUpdated`).
|
|
117
|
+
* Dismiss when the picker is open and the pointer landed on neither the
|
|
118
|
+
* picker nor the emoji toolbar button (re-clicking the button is handled by
|
|
119
|
+
* the toggle in `_onEmojiButtonClick`). `composedPath()` crosses shadow
|
|
120
|
+
* boundaries, so a click inside the picker's shadow tree still resolves to
|
|
121
|
+
* the host element here.
|
|
122
|
+
*/
|
|
123
|
+
private _onDocumentPointerDown;
|
|
124
|
+
/**
|
|
125
|
+
* The picker is a `popover="auto"` parented into the top layer; outside-click
|
|
126
|
+
* dismissal is owned by `_onDocumentPointerDown` (capture phase), which
|
|
127
|
+
* survives `stopPropagation()`/`preventDefault()` from an ancestor (modal
|
|
128
|
+
* `<l-dialog>`, ProseMirror, Vue delegation). (`Escape` is handled by
|
|
129
|
+
* `_onKeyDown` instead — ProseMirror `preventDefault()`s it, which would
|
|
130
|
+
* cancel the native close.)
|
|
114
131
|
*
|
|
115
132
|
* We can't wire the button as a native popover invoker (`popoverTargetElement`
|
|
116
133
|
* / `popovertarget`) because the picker is parented into another shadow tree
|
|
117
134
|
* (the open `<dialog>` — see `_topLayerContainer`) while the button lives in
|
|
118
135
|
* this element's shadow root; a cross-tree invoker reference doesn't resolve.
|
|
119
136
|
* So the toggle is hand-rolled here. The catch: a pointer click on the button
|
|
120
|
-
* is "outside" the popover, so native light-dismiss
|
|
121
|
-
* picker by the time this `click` fires (light-dismiss
|
|
122
|
-
* We therefore read the open state captured at
|
|
123
|
-
* this click should re-open or stay closed.
|
|
124
|
-
* has no pointer light-dismiss, so it
|
|
137
|
+
* is "outside" the popover, so native light-dismiss (where it works) has
|
|
138
|
+
* already closed an open picker by the time this `click` fires (light-dismiss
|
|
139
|
+
* runs on `pointerup`). We therefore read the open state captured at
|
|
140
|
+
* `pointerdown` to know whether this click should re-open or stay closed.
|
|
141
|
+
* Keyboard activation (`detail === 0`) has no pointer light-dismiss, so it
|
|
142
|
+
* reads the live state and toggles directly.
|
|
125
143
|
*/
|
|
126
144
|
private _onEmojiButtonPointerDown;
|
|
127
145
|
private _onEmojiButtonClick;
|
|
@@ -135,6 +153,16 @@ export declare class ProseEditor extends LuxenFormAssociatedElement {
|
|
|
135
153
|
*/
|
|
136
154
|
private _topLayerContainer;
|
|
137
155
|
private get _emojiButton();
|
|
156
|
+
/**
|
|
157
|
+
* Keep the picker pinned to the emoji button while it is open. Floating UI's
|
|
158
|
+
* `autoUpdate` re-runs `_positionEmojiPicker` on scroll (including ancestor
|
|
159
|
+
* scroll), resize, and layout shifts, so the picker stays anchored to the
|
|
160
|
+
* button — the cross-tree equivalent of CSS anchor positioning, which can't be
|
|
161
|
+
* used here because the button lives in this element's shadow root while the
|
|
162
|
+
* picker is parented to the top-layer container (a different tree scope).
|
|
163
|
+
*/
|
|
164
|
+
private _startEmojiAutoUpdate;
|
|
165
|
+
private _stopEmojiAutoUpdate;
|
|
138
166
|
private _positionEmojiPicker;
|
|
139
167
|
private _renderButton;
|
|
140
168
|
private _renderToolbarItem;
|
|
@@ -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;IAE1B,OAAO,CAAC,WAAW,CAAC,CAAiB;IACrC,OAAO,CAAC,YAAY,CAAC,CAAc;IACnC,OAAO,CAAC,mBAAmB,CAAC,CAAuB;IACnD,OAAO,CAAC,uBAAuB,CAAS;
|
|
1
|
+
{"version":3,"file":"prose-editor.d.ts","sourceRoot":"","sources":["../../../src/html/elements/prose-editor/prose-editor.ts"],"names":[],"mappings":"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"}
|
|
@@ -15,14 +15,14 @@ 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, _ProseEditor_emojiDataSource_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
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
|
-
import { computePosition, flip, offset, shift } from '@floating-ui/dom';
|
|
25
|
+
import { autoUpdate, computePosition, flip, offset, shift } from '@floating-ui/dom';
|
|
26
26
|
import { Editor } from '@tiptap/core';
|
|
27
27
|
import StarterKit from '@tiptap/starter-kit';
|
|
28
28
|
import Highlight from '@tiptap/extension-highlight';
|
|
@@ -102,6 +102,7 @@ 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
|
+
_ProseEditor_emojiDataSource_accessor_storage.set(this, '');
|
|
105
106
|
this._emojiOpenAtPointerDown = false;
|
|
106
107
|
this._onFocus = () => {
|
|
107
108
|
if (!this.disabled && document.activeElement !== this.editor?.view.dom) {
|
|
@@ -116,25 +117,44 @@ export class ProseEditor extends LuxenFormAssociatedElement {
|
|
|
116
117
|
event.preventDefault();
|
|
117
118
|
event.stopPropagation();
|
|
118
119
|
};
|
|
120
|
+
/**
|
|
121
|
+
* Capture-phase outside-click dismissal — the robust fallback the platform's
|
|
122
|
+
* native light-dismiss can't be trusted to provide (see `firstUpdated`).
|
|
123
|
+
* Dismiss when the picker is open and the pointer landed on neither the
|
|
124
|
+
* picker nor the emoji toolbar button (re-clicking the button is handled by
|
|
125
|
+
* the toggle in `_onEmojiButtonClick`). `composedPath()` crosses shadow
|
|
126
|
+
* boundaries, so a click inside the picker's shadow tree still resolves to
|
|
127
|
+
* the host element here.
|
|
128
|
+
*/
|
|
129
|
+
this._onDocumentPointerDown = (event) => {
|
|
130
|
+
const picker = this._emojiPicker;
|
|
131
|
+
if (!picker?.matches(':popover-open'))
|
|
132
|
+
return;
|
|
133
|
+
const path = event.composedPath();
|
|
134
|
+
if (path.includes(picker) || (this._emojiButton && path.includes(this._emojiButton)))
|
|
135
|
+
return;
|
|
136
|
+
picker.hidePopover();
|
|
137
|
+
};
|
|
119
138
|
// --- Emoji picker (lazy-loaded) ---
|
|
120
139
|
/**
|
|
121
|
-
* The picker is a `popover="auto"
|
|
122
|
-
* dismissal
|
|
123
|
-
* `stopPropagation()` from an ancestor (modal
|
|
124
|
-
*
|
|
125
|
-
*
|
|
126
|
-
*
|
|
140
|
+
* The picker is a `popover="auto"` parented into the top layer; outside-click
|
|
141
|
+
* dismissal is owned by `_onDocumentPointerDown` (capture phase), which
|
|
142
|
+
* survives `stopPropagation()`/`preventDefault()` from an ancestor (modal
|
|
143
|
+
* `<l-dialog>`, ProseMirror, Vue delegation). (`Escape` is handled by
|
|
144
|
+
* `_onKeyDown` instead — ProseMirror `preventDefault()`s it, which would
|
|
145
|
+
* cancel the native close.)
|
|
127
146
|
*
|
|
128
147
|
* We can't wire the button as a native popover invoker (`popoverTargetElement`
|
|
129
148
|
* / `popovertarget`) because the picker is parented into another shadow tree
|
|
130
149
|
* (the open `<dialog>` — see `_topLayerContainer`) while the button lives in
|
|
131
150
|
* this element's shadow root; a cross-tree invoker reference doesn't resolve.
|
|
132
151
|
* So the toggle is hand-rolled here. The catch: a pointer click on the button
|
|
133
|
-
* is "outside" the popover, so native light-dismiss
|
|
134
|
-
* picker by the time this `click` fires (light-dismiss
|
|
135
|
-
* We therefore read the open state captured at
|
|
136
|
-
* this click should re-open or stay closed.
|
|
137
|
-
* has no pointer light-dismiss, so it
|
|
152
|
+
* is "outside" the popover, so native light-dismiss (where it works) has
|
|
153
|
+
* already closed an open picker by the time this `click` fires (light-dismiss
|
|
154
|
+
* runs on `pointerup`). We therefore read the open state captured at
|
|
155
|
+
* `pointerdown` to know whether this click should re-open or stay closed.
|
|
156
|
+
* Keyboard activation (`detail === 0`) has no pointer light-dismiss, so it
|
|
157
|
+
* reads the live state and toggles directly.
|
|
138
158
|
*/
|
|
139
159
|
this._onEmojiButtonPointerDown = () => {
|
|
140
160
|
this._emojiOpenAtPointerDown = !!this._emojiPicker?.matches(':popover-open');
|
|
@@ -164,6 +184,13 @@ export class ProseEditor extends LuxenFormAssociatedElement {
|
|
|
164
184
|
/** Placeholder shown when the editor is empty. */
|
|
165
185
|
get placeholder() { return __classPrivateFieldGet(this, _ProseEditor_placeholder_accessor_storage, "f"); }
|
|
166
186
|
set placeholder(value) { __classPrivateFieldSet(this, _ProseEditor_placeholder_accessor_storage, value, "f"); }
|
|
187
|
+
/**
|
|
188
|
+
* URL the emoji picker fetches its data from. Point this at a locally served
|
|
189
|
+
* `emojibase-data` JSON to run fully offline (no CDN). Defaults to the
|
|
190
|
+
* picker's bundled CDN source.
|
|
191
|
+
*/
|
|
192
|
+
get emojiDataSource() { return __classPrivateFieldGet(this, _ProseEditor_emojiDataSource_accessor_storage, "f"); }
|
|
193
|
+
set emojiDataSource(value) { __classPrivateFieldSet(this, _ProseEditor_emojiDataSource_accessor_storage, value, "f"); }
|
|
167
194
|
get validationTarget() {
|
|
168
195
|
return this._editorRoot;
|
|
169
196
|
}
|
|
@@ -199,6 +226,15 @@ export class ProseEditor extends LuxenFormAssociatedElement {
|
|
|
199
226
|
// `stopPropagation()`, and only needs the event to propagate — not its
|
|
200
227
|
// default action.
|
|
201
228
|
document.addEventListener('keydown', this._onKeyDown, true);
|
|
229
|
+
// Outside-click dismissal does NOT rely on native popover light-dismiss:
|
|
230
|
+
// at least one shipping Chromium skips light-dismiss when the underlying
|
|
231
|
+
// `pointerdown`'s default action is prevented — which ProseMirror does for
|
|
232
|
+
// every click inside the editor (it drives its own selection). A
|
|
233
|
+
// capture-phase `document` listener runs before any descendant
|
|
234
|
+
// `preventDefault()`/`stopPropagation()` and doesn't depend on the default
|
|
235
|
+
// action, so it dismisses on every browser, real or synthetic input, modal
|
|
236
|
+
// or page. Native light-dismiss then becomes a redundant enhancement.
|
|
237
|
+
document.addEventListener('pointerdown', this._onDocumentPointerDown, true);
|
|
202
238
|
this._syncValue();
|
|
203
239
|
this.requestUpdate();
|
|
204
240
|
}
|
|
@@ -211,6 +247,8 @@ export class ProseEditor extends LuxenFormAssociatedElement {
|
|
|
211
247
|
super.disconnectedCallback();
|
|
212
248
|
this.removeEventListener('focus', this._onFocus);
|
|
213
249
|
document.removeEventListener('keydown', this._onKeyDown, true);
|
|
250
|
+
document.removeEventListener('pointerdown', this._onDocumentPointerDown, true);
|
|
251
|
+
this._stopEmojiAutoUpdate();
|
|
214
252
|
this.editor?.destroy();
|
|
215
253
|
this._editorRoot?.remove();
|
|
216
254
|
this._emojiPicker?.remove();
|
|
@@ -347,28 +385,31 @@ export class ProseEditor extends LuxenFormAssociatedElement {
|
|
|
347
385
|
if (this._emojiPicker)
|
|
348
386
|
return Promise.resolve(this._emojiPicker);
|
|
349
387
|
return (this._emojiPickerPromise ?? (this._emojiPickerPromise = (async () => {
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
const
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
388
|
+
// `emoji-picker-element` is a framework-agnostic web component with no
|
|
389
|
+
// `document`-level click listener of its own to fight the platform.
|
|
390
|
+
// Importing it registers <emoji-picker> and gives us the constructor.
|
|
391
|
+
const { default: Picker } = await import('emoji-picker-element/picker.js');
|
|
392
|
+
const picker = new Picker(this.emojiDataSource ? { dataSource: this.emojiDataSource } : undefined);
|
|
393
|
+
// Theme follows the system color scheme automatically (the element ships
|
|
394
|
+
// a `prefers-color-scheme` media query); a `.light`/`.dark` class would
|
|
395
|
+
// only be needed to override that.
|
|
396
|
+
picker.addEventListener('emoji-click', (event) => {
|
|
397
|
+
const unicode = event.detail.unicode;
|
|
398
|
+
if (!unicode)
|
|
399
|
+
return;
|
|
400
|
+
this.editor.chain().focus().insertContent(unicode).run();
|
|
401
|
+
picker.hidePopover();
|
|
363
402
|
});
|
|
403
|
+
this._topLayerContainer().append(picker);
|
|
364
404
|
// A popover="auto" promotes the picker into the top-layer (so it paints
|
|
365
|
-
// above a modal <l-dialog> and escapes ancestor overflow clipping)
|
|
366
|
-
//
|
|
367
|
-
// Top-layer alone isn't enough
|
|
368
|
-
// makes everything outside the dialog's
|
|
369
|
-
// but unclickable), so the picker is
|
|
370
|
-
//
|
|
371
|
-
//
|
|
405
|
+
// above a modal <l-dialog> and escapes ancestor overflow clipping). Outside
|
|
406
|
+
// -click dismissal is driven by `_onDocumentPointerDown`, with native
|
|
407
|
+
// light-dismiss as a redundant enhancement. Top-layer alone isn't enough
|
|
408
|
+
// inside a modal: showModal() makes everything outside the dialog's
|
|
409
|
+
// flat-tree subtree inert (visible but unclickable), so the picker is
|
|
410
|
+
// parented to the nearest open <dialog> — see _topLayerContainer.
|
|
411
|
+
// Neutralize the UA popover box (the picker draws its own card in its
|
|
412
|
+
// shadow root); Floating UI drives the position in _positionEmojiPicker.
|
|
372
413
|
picker.setAttribute('popover', 'auto');
|
|
373
414
|
Object.assign(picker.style, {
|
|
374
415
|
position: 'fixed',
|
|
@@ -377,10 +418,22 @@ export class ProseEditor extends LuxenFormAssociatedElement {
|
|
|
377
418
|
padding: '0',
|
|
378
419
|
border: '0',
|
|
379
420
|
background: 'transparent',
|
|
421
|
+
// emoji-picker-element ships `:host { display: flex }` (author origin),
|
|
422
|
+
// which overrides the UA `[popover]:not(:popover-open) { display: none }`
|
|
423
|
+
// rule — so a *closed* popover would otherwise stay laid out and visible.
|
|
424
|
+
// Drive `display` from the popover state via inline style (which beats the
|
|
425
|
+
// shadow `:host` rule) so the picker is truly hidden when closed, on every
|
|
426
|
+
// dismissal path (light-dismiss, Escape, re-click, select).
|
|
427
|
+
display: 'none',
|
|
380
428
|
});
|
|
429
|
+
picker.style.setProperty('--border-radius', '0.5rem');
|
|
381
430
|
picker.addEventListener('toggle', (event) => {
|
|
382
|
-
|
|
383
|
-
|
|
431
|
+
const open = event.newState === 'open';
|
|
432
|
+
picker.style.display = open ? 'flex' : 'none';
|
|
433
|
+
if (open)
|
|
434
|
+
this._startEmojiAutoUpdate();
|
|
435
|
+
else
|
|
436
|
+
this._stopEmojiAutoUpdate();
|
|
384
437
|
});
|
|
385
438
|
this._emojiPicker = picker;
|
|
386
439
|
return picker;
|
|
@@ -413,11 +466,31 @@ export class ProseEditor extends LuxenFormAssociatedElement {
|
|
|
413
466
|
get _emojiButton() {
|
|
414
467
|
return this.shadowRoot?.querySelector('[data-command="emoji"]') ?? null;
|
|
415
468
|
}
|
|
469
|
+
/**
|
|
470
|
+
* Keep the picker pinned to the emoji button while it is open. Floating UI's
|
|
471
|
+
* `autoUpdate` re-runs `_positionEmojiPicker` on scroll (including ancestor
|
|
472
|
+
* scroll), resize, and layout shifts, so the picker stays anchored to the
|
|
473
|
+
* button — the cross-tree equivalent of CSS anchor positioning, which can't be
|
|
474
|
+
* used here because the button lives in this element's shadow root while the
|
|
475
|
+
* picker is parented to the top-layer container (a different tree scope).
|
|
476
|
+
*/
|
|
477
|
+
_startEmojiAutoUpdate() {
|
|
478
|
+
const button = this._emojiButton;
|
|
479
|
+
const picker = this._emojiPicker;
|
|
480
|
+
if (!button || !picker)
|
|
481
|
+
return;
|
|
482
|
+
this._stopEmojiAutoUpdate();
|
|
483
|
+
this._emojiAutoUpdateCleanup = autoUpdate(button, picker, () => void this._positionEmojiPicker());
|
|
484
|
+
}
|
|
485
|
+
_stopEmojiAutoUpdate() {
|
|
486
|
+
this._emojiAutoUpdateCleanup?.();
|
|
487
|
+
this._emojiAutoUpdateCleanup = undefined;
|
|
488
|
+
}
|
|
416
489
|
async _positionEmojiPicker() {
|
|
417
490
|
const button = this._emojiButton;
|
|
418
491
|
const picker = this._emojiPicker;
|
|
419
|
-
//
|
|
420
|
-
//
|
|
492
|
+
// Driven by `autoUpdate` while the picker is open, so it is already laid out
|
|
493
|
+
// in the top-layer and can be measured.
|
|
421
494
|
if (!button || !picker || !picker.matches(':popover-open'))
|
|
422
495
|
return;
|
|
423
496
|
const { x, y } = await computePosition(button, picker, {
|
|
@@ -520,7 +593,7 @@ export class ProseEditor extends LuxenFormAssociatedElement {
|
|
|
520
593
|
`;
|
|
521
594
|
}
|
|
522
595
|
}
|
|
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();
|
|
596
|
+
_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(), _ProseEditor_emojiDataSource_accessor_storage = new WeakMap();
|
|
524
597
|
ProseEditor.styles = [hostStyles, styles];
|
|
525
598
|
__decorate([
|
|
526
599
|
property({ attribute: 'initial-html' })
|
|
@@ -551,3 +624,6 @@ __decorate([
|
|
|
551
624
|
__decorate([
|
|
552
625
|
property()
|
|
553
626
|
], ProseEditor.prototype, "placeholder", null);
|
|
627
|
+
__decorate([
|
|
628
|
+
property({ attribute: 'emoji-data-source' })
|
|
629
|
+
], ProseEditor.prototype, "emojiDataSource", null);
|
|
@@ -86,7 +86,13 @@
|
|
|
86
86
|
display: flex;
|
|
87
87
|
align-items: center;
|
|
88
88
|
gap: 0.375rem;
|
|
89
|
-
|
|
89
|
+
/* `clip` (not `hidden`) so the label still truncates long text to an ellipsis
|
|
90
|
+
while `overflow-clip-margin` lets a slotted interactive control's hover/focus
|
|
91
|
+
decoration (a row-action button, an `<l-dropdown>` trigger) bleed past the
|
|
92
|
+
row-height label box instead of being cut on its top/bottom/left edges. The
|
|
93
|
+
margin is kept small so the bleed stays imperceptible for text. */
|
|
94
|
+
overflow: clip;
|
|
95
|
+
overflow-clip-margin: 0.375rem;
|
|
90
96
|
text-overflow: ellipsis;
|
|
91
97
|
white-space: nowrap;
|
|
92
98
|
}
|
|
@@ -72,6 +72,11 @@
|
|
|
72
72
|
}
|
|
73
73
|
],
|
|
74
74
|
"cssProperties": [
|
|
75
|
+
{
|
|
76
|
+
"name": "--size",
|
|
77
|
+
"default": "40px",
|
|
78
|
+
"description": "Box size (any length). Set it inline (e.g. `style=\"--size: 20px\"`) for an arbitrary size beyond the `size` token scale; the font then follows proportionally. The `size` attribute sets it to the matching token."
|
|
79
|
+
},
|
|
75
80
|
{
|
|
76
81
|
"name": "--color",
|
|
77
82
|
"default": null,
|
package/dist/metadata/index.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "0.
|
|
2
|
+
"version": "0.10.0",
|
|
3
3
|
"elements": [
|
|
4
4
|
{
|
|
5
5
|
"name": "avatar",
|
|
@@ -75,6 +75,11 @@
|
|
|
75
75
|
}
|
|
76
76
|
],
|
|
77
77
|
"cssProperties": [
|
|
78
|
+
{
|
|
79
|
+
"name": "--size",
|
|
80
|
+
"default": "40px",
|
|
81
|
+
"description": "Box size (any length). Set it inline (e.g. `style=\"--size: 20px\"`) for an arbitrary size beyond the `size` token scale; the font then follows proportionally. The `size` attribute sets it to the matching token."
|
|
82
|
+
},
|
|
78
83
|
{
|
|
79
84
|
"name": "--color",
|
|
80
85
|
"default": null,
|
|
@@ -2415,6 +2420,14 @@
|
|
|
2415
2420
|
"reflects": false,
|
|
2416
2421
|
"description": "Placeholder shown when the editor is empty."
|
|
2417
2422
|
},
|
|
2423
|
+
{
|
|
2424
|
+
"name": "emojiDataSource",
|
|
2425
|
+
"attribute": "emoji-data-source",
|
|
2426
|
+
"type": "string",
|
|
2427
|
+
"default": "''",
|
|
2428
|
+
"reflects": false,
|
|
2429
|
+
"description": "URL the emoji picker fetches its data from. Point this at a locally served\n`emojibase-data` JSON to run fully offline (no CDN). Defaults to the\npicker's bundled CDN source."
|
|
2430
|
+
},
|
|
2418
2431
|
{
|
|
2419
2432
|
"name": "validationTarget",
|
|
2420
2433
|
"attribute": null,
|