@threadlabs/looma 0.16.0 → 0.16.1
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/components/shared/icons.js +1 -0
- package/components/ui-badge/ui-badge.html +3 -8
- package/components/ui-icon/ui-icon.html +1 -0
- package/dist/index.js +1 -1
- package/editor/chunks/extensions.js +124 -4
- package/editor/extensions/chip.d.ts +26 -0
- package/editor/extensions/index.d.ts +1 -0
- package/editor/extensions/index.js +2 -2
- package/editor/extensions/slash-command.d.ts +2 -1
- package/editor/icons.d.ts +1 -0
- package/editor/index.js +4 -3
- package/package.json +1 -1
- package/styles/ui-badge.css +3 -8
- package/vanilla/UiIcon.js +1 -1
- package/vue/UiBadge.vue +7 -8
- package/vue/UiIcon.vue +4 -0
- package/vue/chunks/UiBadge.js +1 -1
- package/vue/chunks/UiIcon.js +11 -1
- package/vue/components.css +140 -38
- package/vue/editor/index.js +115 -2
package/vue/UiIcon.vue
CHANGED
|
@@ -281,6 +281,10 @@ const shapes = computed(() =>
|
|
|
281
281
|
tag: 'path',
|
|
282
282
|
d: 'M9 3H5a2 2 0 0 0-2 2v4m6-6h10a2 2 0 0 1 2 2v4M9 3v18m0 0h10a2 2 0 0 0 2-2V9M9 21H5a2 2 0 0 1-2-2V9m0 0h18',
|
|
283
283
|
}],
|
|
284
|
+
tag: [{
|
|
285
|
+
tag: 'path',
|
|
286
|
+
d: 'M12.586 2.586A2 2 0 0 0 11.172 2H4a2 2 0 0 0-2 2v7.172a2 2 0 0 0 .586 1.414l8.704 8.704a2.426 2.426 0 0 0 3.42 0l6.58-6.58a2.426 2.426 0 0 0 0-3.42z',
|
|
287
|
+
}, { tag: 'circle', cx: '7.5', cy: '7.5', r: '.5', fill: 'currentColor' }],
|
|
284
288
|
trash: [
|
|
285
289
|
{ tag: 'path', d: 'M10 11v6' },
|
|
286
290
|
{ tag: 'path', d: 'M14 11v6' },
|
package/vue/chunks/UiBadge.js
CHANGED
|
@@ -24,6 +24,6 @@ var UiBadge_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE
|
|
|
24
24
|
return openBlock(), createElementBlock("span", mergeProps({ "data-component": "ui-badge" }, _ctx.$attrs, { "data-ui-badge-state": hostState.value || void 0 }), [renderSlot(_ctx.$slots, "default", {}, void 0, true)], 16, _hoisted_1);
|
|
25
25
|
};
|
|
26
26
|
}
|
|
27
|
-
}), [["__scopeId", "data-v-
|
|
27
|
+
}), [["__scopeId", "data-v-bea7b3f9"]]);
|
|
28
28
|
//#endregion
|
|
29
29
|
export { UiBadge_default as t };
|
package/vue/chunks/UiIcon.js
CHANGED
|
@@ -879,6 +879,16 @@ var UiIcon_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE_
|
|
|
879
879
|
tag: "path",
|
|
880
880
|
d: "M9 3H5a2 2 0 0 0-2 2v4m6-6h10a2 2 0 0 1 2 2v4M9 3v18m0 0h10a2 2 0 0 0 2-2V9M9 21H5a2 2 0 0 1-2-2V9m0 0h18"
|
|
881
881
|
}],
|
|
882
|
+
tag: [{
|
|
883
|
+
tag: "path",
|
|
884
|
+
d: "M12.586 2.586A2 2 0 0 0 11.172 2H4a2 2 0 0 0-2 2v7.172a2 2 0 0 0 .586 1.414l8.704 8.704a2.426 2.426 0 0 0 3.42 0l6.58-6.58a2.426 2.426 0 0 0 0-3.42z"
|
|
885
|
+
}, {
|
|
886
|
+
tag: "circle",
|
|
887
|
+
cx: "7.5",
|
|
888
|
+
cy: "7.5",
|
|
889
|
+
r: ".5",
|
|
890
|
+
fill: "currentColor"
|
|
891
|
+
}],
|
|
882
892
|
trash: [
|
|
883
893
|
{
|
|
884
894
|
tag: "path",
|
|
@@ -1042,6 +1052,6 @@ var UiIcon_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE_
|
|
|
1042
1052
|
}), 128))]))], 16);
|
|
1043
1053
|
};
|
|
1044
1054
|
}
|
|
1045
|
-
}), [["__scopeId", "data-v-
|
|
1055
|
+
}), [["__scopeId", "data-v-988c6eae"]]);
|
|
1046
1056
|
//#endregion
|
|
1047
1057
|
export { UiIcon_default as t };
|
package/vue/components.css
CHANGED
|
@@ -92,7 +92,7 @@
|
|
|
92
92
|
syntax: "*";
|
|
93
93
|
inherits: false;
|
|
94
94
|
}
|
|
95
|
-
[data-component~="ui-icon"][data-v-
|
|
95
|
+
[data-component~="ui-icon"][data-v-988c6eae] {
|
|
96
96
|
/* Hooks do not inherit, so the svg reads the stroke from the root. A Looma component that
|
|
97
97
|
sizes the icons it renders sets --_ui-default-icon-*, which the icon's own hooks override. */
|
|
98
98
|
--_ui-icon-stroke-width: var(--ui-icon-stroke-width, var(--_ui-default-icon-stroke-width));
|
|
@@ -102,14 +102,14 @@
|
|
|
102
102
|
inline-size: var(--ui-icon-size, var(--_ui-default-icon-size, 1em));
|
|
103
103
|
block-size: var(--ui-icon-size, var(--_ui-default-icon-size, 1em));
|
|
104
104
|
}
|
|
105
|
-
svg[data-v-
|
|
105
|
+
svg[data-v-988c6eae] {
|
|
106
106
|
inline-size: 100%;
|
|
107
107
|
block-size: 100%;
|
|
108
108
|
stroke-width: var(--_ui-icon-stroke-width, 2);
|
|
109
109
|
}
|
|
110
110
|
|
|
111
111
|
/* A component that sets its display still honours the hidden attribute on its root. */
|
|
112
|
-
[data-component~="ui-icon"][hidden][data-v-
|
|
112
|
+
[data-component~="ui-icon"][hidden][data-v-988c6eae] {
|
|
113
113
|
display: none;
|
|
114
114
|
}
|
|
115
115
|
|
|
@@ -314,11 +314,11 @@ svg[data-v-50d3f581] {
|
|
|
314
314
|
syntax: "*";
|
|
315
315
|
inherits: false;
|
|
316
316
|
}
|
|
317
|
-
[data-component~="ui-badge"][data-v-
|
|
317
|
+
[data-component~="ui-badge"][data-v-bea7b3f9] {
|
|
318
318
|
--_badge-surface: var(--ui-surface-subtle);
|
|
319
319
|
--_badge-text: var(--ui-text-secondary);
|
|
320
|
-
/*
|
|
321
|
-
--_badge-border: var(--
|
|
320
|
+
/* Sit between the soft fill and its stronger theme ink. */
|
|
321
|
+
--_badge-border: color-mix(in srgb, var(--_badge-surface) 75%, var(--_badge-text) 25%);
|
|
322
322
|
/* --ui-badge-color derives a wash and an ink from one colour, between the tone and the explicit
|
|
323
323
|
surface, text, and border hooks. Each value is invalid, so the tone shows, while it is unset. The
|
|
324
324
|
mixes keep 4.5:1 text contrast for any colour, in a light theme or a dark one. */
|
|
@@ -326,7 +326,11 @@ svg[data-v-50d3f581] {
|
|
|
326
326
|
--_badge-color-wash: color-mix(in oklab, var(--_ui-badge-color) 15%, var(--ui-surface-default));
|
|
327
327
|
--_badge-color-ink: color-mix(in oklab, var(--_ui-badge-color) 35%, var(--ui-text-primary));
|
|
328
328
|
--_badge-color-surface: var(--_badge-color-wash);
|
|
329
|
-
--_badge-color-border:
|
|
329
|
+
--_badge-color-border: color-mix(
|
|
330
|
+
in srgb,
|
|
331
|
+
var(--_badge-color-wash) 75%,
|
|
332
|
+
var(--_badge-color-ink) 25%
|
|
333
|
+
);
|
|
330
334
|
--_badge-color-text: var(--_badge-color-ink);
|
|
331
335
|
--_badge-outline-surface: var(
|
|
332
336
|
--ui-badge-surface,
|
|
@@ -354,7 +358,7 @@ svg[data-v-50d3f581] {
|
|
|
354
358
|
* Trimming applies to block containers; an inline-block is one and, like the inline-flex it
|
|
355
359
|
* replaces, still sizes to its label rather than filling its container. */
|
|
356
360
|
@supports (text-box-trim: trim-both) {
|
|
357
|
-
[data-component~="ui-badge"][data-v-
|
|
361
|
+
[data-component~="ui-badge"][data-v-bea7b3f9] {
|
|
358
362
|
display: inline-block;
|
|
359
363
|
min-block-size: var(--ui-badge-min-block-size, 1.5rem);
|
|
360
364
|
text-align: center;
|
|
@@ -363,65 +367,60 @@ svg[data-v-50d3f581] {
|
|
|
363
367
|
text-box-edge: cap alphabetic;
|
|
364
368
|
}
|
|
365
369
|
}
|
|
366
|
-
[data-component~="ui-badge"][data-ui-badge-state~="tone=accent"][data-v-
|
|
370
|
+
[data-component~="ui-badge"][data-ui-badge-state~="tone=accent"][data-v-bea7b3f9] {
|
|
367
371
|
--_badge-surface: var(--ui-accent-strong-surface, var(--ui-accent-solid));
|
|
368
372
|
--_badge-border: var(--ui-accent-strong-surface, var(--ui-accent-solid));
|
|
369
373
|
--_badge-text: var(--ui-accent-on-strong, var(--ui-text-on-accent));
|
|
370
374
|
}
|
|
371
|
-
[data-component~="ui-badge"][data-ui-badge-state~="tone=danger"][data-v-
|
|
375
|
+
[data-component~="ui-badge"][data-ui-badge-state~="tone=danger"][data-v-bea7b3f9] {
|
|
372
376
|
--_badge-surface: var(--ui-danger-strong-surface, var(--ui-danger-solid));
|
|
373
377
|
--_badge-border: var(--ui-danger-strong-surface, var(--ui-danger-solid));
|
|
374
378
|
--_badge-text: var(--ui-danger-on-strong, var(--ui-text-on-accent));
|
|
375
379
|
}
|
|
376
|
-
[data-component~="ui-badge"][data-ui-badge-state~="tone=success"][data-v-
|
|
380
|
+
[data-component~="ui-badge"][data-ui-badge-state~="tone=success"][data-v-bea7b3f9] {
|
|
377
381
|
--_badge-surface: var(--ui-success-strong-surface, var(--ui-success-solid));
|
|
378
382
|
--_badge-border: var(--ui-success-strong-surface, var(--ui-success-solid));
|
|
379
383
|
--_badge-text: var(--ui-success-on-strong, var(--ui-text-on-accent));
|
|
380
384
|
}
|
|
381
|
-
[data-component~="ui-badge"][data-ui-badge-state~="tone=warning"][data-v-
|
|
385
|
+
[data-component~="ui-badge"][data-ui-badge-state~="tone=warning"][data-v-bea7b3f9] {
|
|
382
386
|
--_badge-surface: var(--ui-warning-strong-surface, var(--ui-warning-solid));
|
|
383
387
|
--_badge-border: var(--ui-warning-strong-surface, var(--ui-warning-solid));
|
|
384
388
|
--_badge-text: var(--ui-warning-on-strong, var(--ui-text-on-accent));
|
|
385
389
|
}
|
|
386
|
-
[data-component~="ui-badge"][data-ui-badge-state~="tone=info"][data-v-
|
|
390
|
+
[data-component~="ui-badge"][data-ui-badge-state~="tone=info"][data-v-bea7b3f9] {
|
|
387
391
|
--_badge-surface: var(--ui-info-strong-surface, var(--ui-info-solid));
|
|
388
392
|
--_badge-border: var(--ui-info-strong-surface, var(--ui-info-solid));
|
|
389
393
|
--_badge-text: var(--ui-info-on-strong, var(--ui-text-on-accent));
|
|
390
394
|
}
|
|
391
|
-
[data-component~="ui-badge"][data-ui-badge-state~="variant=subtle"][data-ui-badge-state~="tone=accent"][data-v-
|
|
395
|
+
[data-component~="ui-badge"][data-ui-badge-state~="variant=subtle"][data-ui-badge-state~="tone=accent"][data-v-bea7b3f9] {
|
|
392
396
|
--_badge-surface: var(--ui-accent-soft);
|
|
393
|
-
--_badge-border: var(--ui-accent-soft);
|
|
394
397
|
--_badge-text: var(--ui-accent-subtle-text, var(--ui-accent-solid));
|
|
395
398
|
}
|
|
396
|
-
[data-component~="ui-badge"][data-ui-badge-state~="variant=subtle"][data-ui-badge-state~="tone=danger"][data-v-
|
|
399
|
+
[data-component~="ui-badge"][data-ui-badge-state~="variant=subtle"][data-ui-badge-state~="tone=danger"][data-v-bea7b3f9] {
|
|
397
400
|
--_badge-surface: var(--ui-danger-soft);
|
|
398
|
-
--_badge-border: var(--ui-danger-soft);
|
|
399
401
|
--_badge-text: var(--ui-danger-subtle-text, var(--ui-danger-solid));
|
|
400
402
|
}
|
|
401
|
-
[data-component~="ui-badge"][data-ui-badge-state~="variant=subtle"][data-ui-badge-state~="tone=success"][data-v-
|
|
403
|
+
[data-component~="ui-badge"][data-ui-badge-state~="variant=subtle"][data-ui-badge-state~="tone=success"][data-v-bea7b3f9] {
|
|
402
404
|
--_badge-surface: var(--ui-success-soft);
|
|
403
|
-
--_badge-border: var(--ui-success-soft);
|
|
404
405
|
--_badge-text: var(--ui-success-subtle-text, var(--ui-success-solid));
|
|
405
406
|
}
|
|
406
|
-
[data-component~="ui-badge"][data-ui-badge-state~="variant=subtle"][data-ui-badge-state~="tone=warning"][data-v-
|
|
407
|
+
[data-component~="ui-badge"][data-ui-badge-state~="variant=subtle"][data-ui-badge-state~="tone=warning"][data-v-bea7b3f9] {
|
|
407
408
|
--_badge-surface: var(--ui-warning-soft);
|
|
408
|
-
--_badge-border: var(--ui-warning-soft);
|
|
409
409
|
--_badge-text: var(--ui-warning-subtle-text, var(--ui-warning-solid));
|
|
410
410
|
}
|
|
411
|
-
[data-component~="ui-badge"][data-ui-badge-state~="variant=subtle"][data-ui-badge-state~="tone=info"][data-v-
|
|
411
|
+
[data-component~="ui-badge"][data-ui-badge-state~="variant=subtle"][data-ui-badge-state~="tone=info"][data-v-bea7b3f9] {
|
|
412
412
|
--_badge-surface: var(--ui-info-soft);
|
|
413
|
-
--_badge-border: var(--ui-info-soft);
|
|
414
413
|
--_badge-text: var(--ui-info-subtle-text, var(--ui-info-solid));
|
|
415
414
|
}
|
|
416
415
|
|
|
417
416
|
/* A solid colour fills with the ink. Its text is the page surface, mixed at 0% only so that it too is
|
|
418
417
|
invalid while the hook is unset. */
|
|
419
|
-
[data-component~="ui-badge"][data-ui-badge-state~="variant=solid"][data-v-
|
|
418
|
+
[data-component~="ui-badge"][data-ui-badge-state~="variant=solid"][data-v-bea7b3f9] {
|
|
420
419
|
--_badge-color-surface: var(--_badge-color-ink);
|
|
421
420
|
--_badge-color-border: var(--_badge-color-ink);
|
|
422
421
|
--_badge-color-text: color-mix(in oklab, var(--_ui-badge-color) 0%, var(--ui-surface-default));
|
|
423
422
|
}
|
|
424
|
-
[data-component~="ui-badge"][data-ui-badge-state~="variant=outline"][data-v-
|
|
423
|
+
[data-component~="ui-badge"][data-ui-badge-state~="variant=outline"][data-v-bea7b3f9] {
|
|
425
424
|
--_badge-surface: var(--ui-surface-default);
|
|
426
425
|
--_badge-border: var(--ui-border-strong);
|
|
427
426
|
--_badge-text: var(--ui-text-secondary);
|
|
@@ -429,23 +428,23 @@ svg[data-v-50d3f581] {
|
|
|
429
428
|
--_badge-color-surface: initial;
|
|
430
429
|
--_badge-color-border: var(--_badge-color-ink);
|
|
431
430
|
}
|
|
432
|
-
[data-component~="ui-badge"][data-ui-badge-state~="variant=outline"][data-ui-badge-state~="tone=accent"][data-v-
|
|
431
|
+
[data-component~="ui-badge"][data-ui-badge-state~="variant=outline"][data-ui-badge-state~="tone=accent"][data-v-bea7b3f9] {
|
|
433
432
|
--_badge-border: var(--ui-accent-solid);
|
|
434
433
|
--_badge-text: var(--ui-accent-subtle-text, var(--ui-accent-solid));
|
|
435
434
|
}
|
|
436
|
-
[data-component~="ui-badge"][data-ui-badge-state~="variant=outline"][data-ui-badge-state~="tone=danger"][data-v-
|
|
435
|
+
[data-component~="ui-badge"][data-ui-badge-state~="variant=outline"][data-ui-badge-state~="tone=danger"][data-v-bea7b3f9] {
|
|
437
436
|
--_badge-border: var(--ui-danger-solid);
|
|
438
437
|
--_badge-text: var(--ui-danger-subtle-text, var(--ui-danger-solid));
|
|
439
438
|
}
|
|
440
|
-
[data-component~="ui-badge"][data-ui-badge-state~="variant=outline"][data-ui-badge-state~="tone=success"][data-v-
|
|
439
|
+
[data-component~="ui-badge"][data-ui-badge-state~="variant=outline"][data-ui-badge-state~="tone=success"][data-v-bea7b3f9] {
|
|
441
440
|
--_badge-border: var(--ui-success-solid);
|
|
442
441
|
--_badge-text: var(--ui-success-subtle-text, var(--ui-success-solid));
|
|
443
442
|
}
|
|
444
|
-
[data-component~="ui-badge"][data-ui-badge-state~="variant=outline"][data-ui-badge-state~="tone=warning"][data-v-
|
|
443
|
+
[data-component~="ui-badge"][data-ui-badge-state~="variant=outline"][data-ui-badge-state~="tone=warning"][data-v-bea7b3f9] {
|
|
445
444
|
--_badge-border: var(--ui-warning-solid);
|
|
446
445
|
--_badge-text: var(--ui-warning-subtle-text, var(--ui-warning-solid));
|
|
447
446
|
}
|
|
448
|
-
[data-component~="ui-badge"][data-ui-badge-state~="variant=outline"][data-ui-badge-state~="tone=info"][data-v-
|
|
447
|
+
[data-component~="ui-badge"][data-ui-badge-state~="variant=outline"][data-ui-badge-state~="tone=info"][data-v-bea7b3f9] {
|
|
449
448
|
--_badge-border: var(--ui-info-solid);
|
|
450
449
|
--_badge-text: var(--ui-info-subtle-text, var(--ui-info-solid));
|
|
451
450
|
}
|
|
@@ -453,7 +452,7 @@ svg[data-v-50d3f581] {
|
|
|
453
452
|
/* A tag is flat at the start and points at the end. The point is cut from the box, so it has no
|
|
454
453
|
outline to follow: the edge is the fill. The end padding grows by the point's depth so the
|
|
455
454
|
label never runs into it. */
|
|
456
|
-
[data-component~="ui-badge"][data-ui-badge-state~="shape=tag"][data-v-
|
|
455
|
+
[data-component~="ui-badge"][data-ui-badge-state~="shape=tag"][data-v-bea7b3f9] {
|
|
457
456
|
--_badge-point: var(--ui-badge-point, var(--ui-space-2));
|
|
458
457
|
|
|
459
458
|
border-color: transparent;
|
|
@@ -467,7 +466,7 @@ svg[data-v-50d3f581] {
|
|
|
467
466
|
0 100%
|
|
468
467
|
);
|
|
469
468
|
}
|
|
470
|
-
[data-component~="ui-badge"][data-ui-badge-state~="shape=tag"][data-v-
|
|
469
|
+
[data-component~="ui-badge"][data-ui-badge-state~="shape=tag"][data-v-bea7b3f9]:dir(rtl) {
|
|
471
470
|
padding-inline-end: var(--ui-badge-padding-inline, var(--ui-space-2));
|
|
472
471
|
padding-inline-start: calc(
|
|
473
472
|
var(--ui-badge-padding-inline, var(--ui-space-2)) + var(--_badge-point)
|
|
@@ -477,12 +476,12 @@ svg[data-v-50d3f581] {
|
|
|
477
476
|
|
|
478
477
|
/* The tag clips its point, including the native border. Draw the outer shape in the border
|
|
479
478
|
colour and an inset inner shape in the surface colour to keep a visible diagonal edge. */
|
|
480
|
-
[data-component~="ui-badge"][data-ui-badge-state~="variant=outline"][data-ui-badge-state~="shape=tag"][data-v-
|
|
479
|
+
[data-component~="ui-badge"][data-ui-badge-state~="variant=outline"][data-ui-badge-state~="shape=tag"][data-v-bea7b3f9] {
|
|
481
480
|
position: relative;
|
|
482
481
|
isolation: isolate;
|
|
483
482
|
background: var(--ui-badge-border, var(--_badge-color-border, var(--_badge-border)));
|
|
484
483
|
}
|
|
485
|
-
[data-component~="ui-badge"][data-ui-badge-state~="variant=outline"][data-ui-badge-state~="shape=tag"][data-v-
|
|
484
|
+
[data-component~="ui-badge"][data-ui-badge-state~="variant=outline"][data-ui-badge-state~="shape=tag"][data-v-bea7b3f9]::before {
|
|
486
485
|
content: "";
|
|
487
486
|
position: absolute;
|
|
488
487
|
inset: 1px;
|
|
@@ -497,22 +496,22 @@ svg[data-v-50d3f581] {
|
|
|
497
496
|
);
|
|
498
497
|
pointer-events: none;
|
|
499
498
|
}
|
|
500
|
-
[data-component~="ui-badge"][data-ui-badge-state~="variant=outline"][data-ui-badge-state~="shape=tag"][data-v-
|
|
499
|
+
[data-component~="ui-badge"][data-ui-badge-state~="variant=outline"][data-ui-badge-state~="shape=tag"][data-v-bea7b3f9]:dir(rtl)::before {
|
|
501
500
|
clip-path: polygon(var(--_badge-point) 0, 100% 0, 100% 100%, var(--_badge-point) 100%, 0 50%);
|
|
502
501
|
}
|
|
503
502
|
@media (forced-colors: active) {
|
|
504
|
-
[data-component~="ui-badge"][data-ui-badge-state~="variant=outline"][data-ui-badge-state~="shape=tag"][data-v-
|
|
503
|
+
[data-component~="ui-badge"][data-ui-badge-state~="variant=outline"][data-ui-badge-state~="shape=tag"][data-v-bea7b3f9] {
|
|
505
504
|
forced-color-adjust: none;
|
|
506
505
|
background: CanvasText;
|
|
507
506
|
color: CanvasText;
|
|
508
507
|
}
|
|
509
|
-
[data-component~="ui-badge"][data-ui-badge-state~="variant=outline"][data-ui-badge-state~="shape=tag"][data-v-
|
|
508
|
+
[data-component~="ui-badge"][data-ui-badge-state~="variant=outline"][data-ui-badge-state~="shape=tag"][data-v-bea7b3f9]::before {
|
|
510
509
|
background: Canvas;
|
|
511
510
|
}
|
|
512
511
|
}
|
|
513
512
|
|
|
514
513
|
/* A component that sets its display still honours the hidden attribute on its root. */
|
|
515
|
-
[data-component~="ui-badge"][hidden][data-v-
|
|
514
|
+
[data-component~="ui-badge"][hidden][data-v-bea7b3f9] {
|
|
516
515
|
display: none;
|
|
517
516
|
}
|
|
518
517
|
|
|
@@ -8577,6 +8576,7 @@ html[data-ui-input-modality="touch"]
|
|
|
8577
8576
|
|
|
8578
8577
|
.looma-editor__table-picker-popover,
|
|
8579
8578
|
.looma-editor__link-popover,
|
|
8579
|
+
.looma-editor__chip-popover,
|
|
8580
8580
|
.looma-editor__table-toolbar-shell,
|
|
8581
8581
|
.looma-editor__table-menu-shell {
|
|
8582
8582
|
z-index: var(--ui-editor-popover-z-index, 300);
|
|
@@ -8593,6 +8593,55 @@ html[data-ui-input-modality="touch"]
|
|
|
8593
8593
|
inline-size: min(22rem, calc(100vw - 2rem));
|
|
8594
8594
|
}
|
|
8595
8595
|
|
|
8596
|
+
.looma-editor__chip-popover {
|
|
8597
|
+
inline-size: min(15rem, calc(100vw - 2rem));
|
|
8598
|
+
}
|
|
8599
|
+
|
|
8600
|
+
.looma-editor__chip-form {
|
|
8601
|
+
display: flex;
|
|
8602
|
+
flex-direction: column;
|
|
8603
|
+
gap: var(--ui-space-3);
|
|
8604
|
+
}
|
|
8605
|
+
|
|
8606
|
+
.looma-editor__chip-form input {
|
|
8607
|
+
box-sizing: border-box;
|
|
8608
|
+
width: 100%;
|
|
8609
|
+
min-height: var(--ui-control-min-block-size);
|
|
8610
|
+
padding: var(--ui-space-2);
|
|
8611
|
+
border: 1px solid var(--ui-control-border);
|
|
8612
|
+
border-radius: var(--ui-field-radius, var(--ui-radius-md));
|
|
8613
|
+
background: var(--ui-control-surface);
|
|
8614
|
+
color: var(--ui-text-primary);
|
|
8615
|
+
font: inherit;
|
|
8616
|
+
}
|
|
8617
|
+
|
|
8618
|
+
.looma-editor__chip-colors {
|
|
8619
|
+
display: flex;
|
|
8620
|
+
justify-content: space-between;
|
|
8621
|
+
gap: var(--ui-space-1);
|
|
8622
|
+
}
|
|
8623
|
+
|
|
8624
|
+
.looma-editor__chip-color {
|
|
8625
|
+
display: grid;
|
|
8626
|
+
place-items: center;
|
|
8627
|
+
width: 1.65rem;
|
|
8628
|
+
height: 1.65rem;
|
|
8629
|
+
padding: 0;
|
|
8630
|
+
border: 1px solid var(--_chip-border);
|
|
8631
|
+
border-radius: 50%;
|
|
8632
|
+
background: var(--_chip-surface);
|
|
8633
|
+
color: var(--_chip-text);
|
|
8634
|
+
font: inherit;
|
|
8635
|
+
font-size: var(--ui-font-size-xs);
|
|
8636
|
+
cursor: pointer;
|
|
8637
|
+
}
|
|
8638
|
+
|
|
8639
|
+
.looma-editor__chip-form :is(input, button):focus-visible,
|
|
8640
|
+
.looma-editor .ProseMirror [data-looma-chip]:focus-visible {
|
|
8641
|
+
outline: 2px solid var(--ui-focus-ring);
|
|
8642
|
+
outline-offset: 2px;
|
|
8643
|
+
}
|
|
8644
|
+
|
|
8596
8645
|
.looma-editor__link-form,
|
|
8597
8646
|
.looma-editor__link-form label {
|
|
8598
8647
|
display: flex;
|
|
@@ -8741,6 +8790,59 @@ html[data-ui-input-modality="touch"]
|
|
|
8741
8790
|
white-space: nowrap;
|
|
8742
8791
|
}
|
|
8743
8792
|
|
|
8793
|
+
.looma-editor .ProseMirror [data-looma-chip],
|
|
8794
|
+
.looma-editor__chip-color {
|
|
8795
|
+
--_chip-tone-surface: var(--ui-surface-subtle);
|
|
8796
|
+
--_chip-tone-text: var(--ui-text-secondary);
|
|
8797
|
+
--_chip-surface: var(--ui-editor-chip-surface, var(--_chip-tone-surface));
|
|
8798
|
+
--_chip-text: var(--ui-editor-chip-text, var(--_chip-tone-text));
|
|
8799
|
+
--_chip-border: var(--ui-editor-chip-border, color-mix(in srgb, var(--_chip-surface) 75%, var(--_chip-text) 25%));
|
|
8800
|
+
}
|
|
8801
|
+
|
|
8802
|
+
.looma-editor .ProseMirror [data-looma-chip][data-color="blue"],
|
|
8803
|
+
.looma-editor__chip-color[data-color="blue"] {
|
|
8804
|
+
--_chip-tone-surface: var(--ui-info-soft);
|
|
8805
|
+
--_chip-tone-text: var(--ui-info-subtle-text);
|
|
8806
|
+
}
|
|
8807
|
+
|
|
8808
|
+
.looma-editor .ProseMirror [data-looma-chip][data-color="green"],
|
|
8809
|
+
.looma-editor__chip-color[data-color="green"] {
|
|
8810
|
+
--_chip-tone-surface: var(--ui-success-soft);
|
|
8811
|
+
--_chip-tone-text: var(--ui-success-subtle-text);
|
|
8812
|
+
}
|
|
8813
|
+
|
|
8814
|
+
.looma-editor .ProseMirror [data-looma-chip][data-color="yellow"],
|
|
8815
|
+
.looma-editor__chip-color[data-color="yellow"] {
|
|
8816
|
+
--_chip-tone-surface: var(--ui-warning-soft);
|
|
8817
|
+
--_chip-tone-text: var(--ui-warning-subtle-text);
|
|
8818
|
+
}
|
|
8819
|
+
|
|
8820
|
+
.looma-editor .ProseMirror [data-looma-chip][data-color="red"],
|
|
8821
|
+
.looma-editor__chip-color[data-color="red"] {
|
|
8822
|
+
--_chip-tone-surface: var(--ui-danger-soft);
|
|
8823
|
+
--_chip-tone-text: var(--ui-danger-subtle-text);
|
|
8824
|
+
}
|
|
8825
|
+
|
|
8826
|
+
.looma-editor .ProseMirror [data-looma-chip][data-color="purple"],
|
|
8827
|
+
.looma-editor__chip-color[data-color="purple"] {
|
|
8828
|
+
--_chip-tone-surface: var(--ui-accent-soft);
|
|
8829
|
+
--_chip-tone-text: var(--ui-accent-subtle-text);
|
|
8830
|
+
}
|
|
8831
|
+
|
|
8832
|
+
.looma-editor .ProseMirror [data-looma-chip] {
|
|
8833
|
+
padding: 0.08em 0.45em;
|
|
8834
|
+
border: 1px solid var(--_chip-border);
|
|
8835
|
+
border-radius: var(--ui-radius-round);
|
|
8836
|
+
background: var(--_chip-surface);
|
|
8837
|
+
color: var(--_chip-text);
|
|
8838
|
+
font-size: var(--ui-editor-chip-font-size, var(--ui-font-size-sm));
|
|
8839
|
+
font-weight: var(--ui-font-medium);
|
|
8840
|
+
line-height: var(--ui-line-height-tight);
|
|
8841
|
+
-webkit-box-decoration-break: clone;
|
|
8842
|
+
box-decoration-break: clone;
|
|
8843
|
+
cursor: pointer;
|
|
8844
|
+
}
|
|
8845
|
+
|
|
8744
8846
|
.ProseMirror .tableWrapper {
|
|
8745
8847
|
max-width: 100%;
|
|
8746
8848
|
overflow-x: auto;
|
package/vue/editor/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { defineComponent, h, nextTick, onBeforeUnmount, onMounted, reactive, ref, useId, watch } from "vue";
|
|
2
|
-
import { DEFAULT_MENTION_RESULT_LIMIT, LOOMA_ICONS, createLoomaMentionExtension, createLoomaSlashCommandExtension, getActiveTableUiState, getDefaultEditorExtensions, getVisualViewportRect, handleTableAction, handleTableOverlayAction, measureTableOverlayGeometry, normalizeActiveTableColumnWidths, resolveTableCellAt, shouldShowTextFormattingToolbar } from "@threadlabs/looma/editor";
|
|
2
|
+
import { DEFAULT_MENTION_RESULT_LIMIT, LOOMA_CHIP_COLORS, LOOMA_ICONS, createLoomaMentionExtension, createLoomaSlashCommandExtension, getActiveTableUiState, getDefaultEditorExtensions, getVisualViewportRect, handleTableAction, handleTableOverlayAction, measureTableOverlayGeometry, normalizeActiveTableColumnWidths, normalizeLoomaChipColor, resolveTableCellAt, shouldShowTextFormattingToolbar } from "@threadlabs/looma/editor";
|
|
3
3
|
import { EditorInsertTableGrid, EditorMentionMenu, EditorSlashMenu, EditorTableContextMenu, EditorTableOverlay, EditorTableToolbar, EditorToolbar, IconButton, Menu, MenuItem, Popover, Tooltip } from "@threadlabs/looma/vue";
|
|
4
4
|
import { BubbleMenu, EditorContent, useEditor } from "@tiptap/vue-3";
|
|
5
5
|
import { Plugin, PluginKey, TextSelection } from "@tiptap/pm/state";
|
|
@@ -353,6 +353,11 @@ var LoomaEditor = defineComponent({
|
|
|
353
353
|
const linkText = ref("");
|
|
354
354
|
const linkNewTab = ref(true);
|
|
355
355
|
const linkError = ref("");
|
|
356
|
+
const chipAnchorId = `looma-editor-chip-${useId().replace(/[^a-zA-Z0-9_-]/g, "")}`;
|
|
357
|
+
const chipInput = ref(null);
|
|
358
|
+
const chipOpen = ref(false);
|
|
359
|
+
const chipLabel = ref("");
|
|
360
|
+
const chipColor = ref("neutral");
|
|
356
361
|
let linkSelection = null;
|
|
357
362
|
const toolbarScope = `looma-editor-tool-${useId().replace(/[^a-zA-Z0-9_-]/g, "")}`;
|
|
358
363
|
const tooltipFor = ref("");
|
|
@@ -435,8 +440,43 @@ var LoomaEditor = defineComponent({
|
|
|
435
440
|
menuStyle: {},
|
|
436
441
|
capabilities: { ...EMPTY_CAPABILITIES }
|
|
437
442
|
});
|
|
443
|
+
const openChipEditor = (instance, position) => {
|
|
444
|
+
if (!props.editable) return;
|
|
445
|
+
const node = instance.state.doc.nodeAt(position);
|
|
446
|
+
const element = instance.view.nodeDOM(position);
|
|
447
|
+
if (node?.type.name !== "loomaChip" || !(element instanceof HTMLElement)) return;
|
|
448
|
+
root.value?.querySelector(`#${chipAnchorId}`)?.removeAttribute("id");
|
|
449
|
+
element.id = chipAnchorId;
|
|
450
|
+
chipLabel.value = String(node.attrs.label ?? "");
|
|
451
|
+
chipColor.value = normalizeLoomaChipColor(node.attrs.color);
|
|
452
|
+
chipOpen.value = true;
|
|
453
|
+
nextTick(() => chipInput.value?.focus());
|
|
454
|
+
};
|
|
455
|
+
const changeChip = (changes) => {
|
|
456
|
+
const instance = editor.value;
|
|
457
|
+
const element = root.value?.querySelector(`#${chipAnchorId}`);
|
|
458
|
+
if (!instance || !element) {
|
|
459
|
+
chipOpen.value = false;
|
|
460
|
+
return;
|
|
461
|
+
}
|
|
462
|
+
const position = instance.view.posAtDOM(element, 0);
|
|
463
|
+
const node = instance.state.doc.nodeAt(position);
|
|
464
|
+
if (node?.type.name !== "loomaChip") {
|
|
465
|
+
chipOpen.value = false;
|
|
466
|
+
return;
|
|
467
|
+
}
|
|
468
|
+
instance.view.dispatch(instance.state.tr.setNodeMarkup(position, void 0, {
|
|
469
|
+
...node.attrs,
|
|
470
|
+
...changes
|
|
471
|
+
}));
|
|
472
|
+
};
|
|
473
|
+
const closeChip = (focusChip = false) => {
|
|
474
|
+
chipOpen.value = false;
|
|
475
|
+
if (focusChip) root.value?.querySelector(`#${chipAnchorId}`)?.focus();
|
|
476
|
+
};
|
|
438
477
|
const slashExtension = createLoomaSlashCommandExtension({
|
|
439
478
|
onOpenImagePicker: () => fileInput.value?.click(),
|
|
479
|
+
onOpenChipEditor: openChipEditor,
|
|
440
480
|
onStateChange: (state) => {
|
|
441
481
|
Object.assign(slash, state);
|
|
442
482
|
}
|
|
@@ -602,7 +642,13 @@ var LoomaEditor = defineComponent({
|
|
|
602
642
|
instance.view.dispatch(transaction);
|
|
603
643
|
instance.commands.focus();
|
|
604
644
|
};
|
|
605
|
-
watch(() => props.editable, (editable) =>
|
|
645
|
+
watch(() => props.editable, (editable) => {
|
|
646
|
+
editor.value?.setEditable(editable);
|
|
647
|
+
root.value?.querySelectorAll("[data-looma-chip]").forEach((chip) => {
|
|
648
|
+
chip.setAttribute("aria-disabled", String(!editable));
|
|
649
|
+
});
|
|
650
|
+
if (!editable) chipOpen.value = false;
|
|
651
|
+
});
|
|
606
652
|
watch(() => props.label, (label) => {
|
|
607
653
|
editor.value?.setOptions({ editorProps: { attributes: {
|
|
608
654
|
role: "textbox",
|
|
@@ -796,6 +842,18 @@ var LoomaEditor = defineComponent({
|
|
|
796
842
|
trigger
|
|
797
843
|
});
|
|
798
844
|
};
|
|
845
|
+
const chipElementForEvent = (event) => {
|
|
846
|
+
const element = event.target instanceof Element ? event.target.closest("[data-looma-chip]") : null;
|
|
847
|
+
return element && root.value?.contains(element) ? element : null;
|
|
848
|
+
};
|
|
849
|
+
const onChipClickCapture = (event) => {
|
|
850
|
+
const chip = chipElementForEvent(event);
|
|
851
|
+
if (chip && editor.value && props.editable) {
|
|
852
|
+
event.preventDefault();
|
|
853
|
+
event.stopPropagation();
|
|
854
|
+
openChipEditor(editor.value, editor.value.view.posAtDOM(chip, 0));
|
|
855
|
+
}
|
|
856
|
+
};
|
|
799
857
|
const onImageClick = (event) => {
|
|
800
858
|
const element = imageElementForEvent(event);
|
|
801
859
|
if (element && !props.editable) activateImage(element, "pointer");
|
|
@@ -806,6 +864,12 @@ var LoomaEditor = defineComponent({
|
|
|
806
864
|
};
|
|
807
865
|
const onImageKeyDown = (event) => {
|
|
808
866
|
if (event.key !== "Enter" && event.key !== " ") return;
|
|
867
|
+
const chip = chipElementForEvent(event);
|
|
868
|
+
if (chip && editor.value && props.editable) {
|
|
869
|
+
event.preventDefault();
|
|
870
|
+
openChipEditor(editor.value, editor.value.view.posAtDOM(chip, 0));
|
|
871
|
+
return;
|
|
872
|
+
}
|
|
809
873
|
const element = imageElementForEvent(event);
|
|
810
874
|
if (!element) return;
|
|
811
875
|
event.preventDefault();
|
|
@@ -1149,6 +1213,7 @@ var LoomaEditor = defineComponent({
|
|
|
1149
1213
|
}, 100);
|
|
1150
1214
|
},
|
|
1151
1215
|
onDrop,
|
|
1216
|
+
onClickCapture: onChipClickCapture,
|
|
1152
1217
|
onClick: onImageClick,
|
|
1153
1218
|
onDblclick: onImageDoubleClick,
|
|
1154
1219
|
onKeydown: onImageKeyDown
|
|
@@ -1213,6 +1278,54 @@ var LoomaEditor = defineComponent({
|
|
|
1213
1278
|
class: "looma-editor__drop-overlay",
|
|
1214
1279
|
"aria-hidden": "true"
|
|
1215
1280
|
}, [loomaIcon("image"), h("span", "Drop image to upload")]) : null,
|
|
1281
|
+
h(Popover, {
|
|
1282
|
+
class: "looma-editor__chip-popover",
|
|
1283
|
+
open: chipOpen.value,
|
|
1284
|
+
for: chipAnchorId,
|
|
1285
|
+
placement: mobile.value ? "top-start" : "bottom-start",
|
|
1286
|
+
onClose: () => {
|
|
1287
|
+
chipOpen.value = false;
|
|
1288
|
+
}
|
|
1289
|
+
}, () => h("div", {
|
|
1290
|
+
class: "looma-editor__chip-form",
|
|
1291
|
+
role: "dialog",
|
|
1292
|
+
"aria-label": "Edit chip"
|
|
1293
|
+
}, [h("input", {
|
|
1294
|
+
ref: chipInput,
|
|
1295
|
+
type: "text",
|
|
1296
|
+
value: chipLabel.value,
|
|
1297
|
+
placeholder: "Set a label",
|
|
1298
|
+
"aria-label": "Chip text",
|
|
1299
|
+
onInput: (event) => {
|
|
1300
|
+
chipLabel.value = event.target.value;
|
|
1301
|
+
changeChip({ label: chipLabel.value });
|
|
1302
|
+
},
|
|
1303
|
+
onKeydown: (event) => {
|
|
1304
|
+
if (event.key === "Enter" || event.key === "Escape") {
|
|
1305
|
+
event.preventDefault();
|
|
1306
|
+
closeChip(true);
|
|
1307
|
+
}
|
|
1308
|
+
}
|
|
1309
|
+
}), h("div", {
|
|
1310
|
+
class: "looma-editor__chip-colors",
|
|
1311
|
+
role: "group",
|
|
1312
|
+
"aria-label": "Chip color"
|
|
1313
|
+
}, LOOMA_CHIP_COLORS.map((color) => h("button", {
|
|
1314
|
+
type: "button",
|
|
1315
|
+
class: "looma-editor__chip-color",
|
|
1316
|
+
"data-color": color,
|
|
1317
|
+
"aria-label": `${color[0].toUpperCase()}${color.slice(1)} chip`,
|
|
1318
|
+
"aria-pressed": chipColor.value === color,
|
|
1319
|
+
onClick: () => {
|
|
1320
|
+
if (chipColor.value === color) {
|
|
1321
|
+
chipInput.value?.focus();
|
|
1322
|
+
return;
|
|
1323
|
+
}
|
|
1324
|
+
chipColor.value = color;
|
|
1325
|
+
changeChip({ color });
|
|
1326
|
+
chipInput.value?.focus();
|
|
1327
|
+
}
|
|
1328
|
+
}, chipColor.value === color ? "✓" : "")))])),
|
|
1216
1329
|
h(Popover, {
|
|
1217
1330
|
class: "looma-editor__link-popover",
|
|
1218
1331
|
open: linkOpen.value,
|