@threadlabs/looma 0.25.3 → 0.25.5
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/ui-badge/ui-badge.html +59 -3
- package/components/ui-button/ui-button.html +1 -1
- package/components/ui-card/ui-card.html +27 -2
- package/components/ui-cluster/ui-cluster.html +30 -0
- package/components/ui-editor-surface/ui-editor-surface.html +23 -0
- package/components/ui-scroll-area/ui-scroll-area.html +5 -0
- package/components/ui-stack/ui-stack.html +17 -1
- package/components/ui-text/ui-text.html +5 -0
- package/components/ui-textarea/ui-textarea.html +7 -0
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/styles/ui-badge.css +61 -4
- package/styles/ui-button.css +1 -1
- package/styles/ui-card.css +24 -0
- package/styles/ui-cluster.css +25 -0
- package/styles/ui-editor-surface.css +19 -0
- package/styles/ui-scroll-area.css +4 -0
- package/styles/ui-stack.css +13 -0
- package/styles/ui-text.css +4 -0
- package/styles/ui-textarea.css +4 -0
- package/vanilla/UiBadge.js +16 -3
- package/vanilla/UiCard.d.ts +1 -1
- package/vanilla/UiCard.js +1 -1
- package/vanilla/UiCluster.d.ts +3 -0
- package/vanilla/UiCluster.js +9 -3
- package/vanilla/UiEditorSurface.d.ts +14 -0
- package/vanilla/UiEditorSurface.js +27 -0
- package/vanilla/UiScrollArea.d.ts +1 -0
- package/vanilla/UiScrollArea.js +1 -1
- package/vanilla/UiStack.d.ts +2 -0
- package/vanilla/UiStack.js +8 -9
- package/vanilla/UiText.d.ts +1 -0
- package/vanilla/UiText.js +1 -1
- package/vanilla/UiTextarea.d.ts +1 -0
- package/vanilla/UiTextarea.js +4 -1
- package/vanilla/index.js +1 -0
- package/vue/UiBadge.d.ts +4 -2
- package/vue/UiBadge.vue +57 -3
- package/vue/UiButton.vue +1 -1
- package/vue/UiCard.d.ts +3 -3
- package/vue/UiCard.vue +34 -5
- package/vue/UiCluster.d.ts +27 -0
- package/vue/UiCluster.vue +95 -1
- package/vue/UiEditorSlashMenuItem.d.ts +1 -1
- package/vue/UiEditorSurface.d.ts +26 -0
- package/vue/UiEditorSurface.js +2 -0
- package/vue/UiEditorSurface.vue +129 -0
- package/vue/UiScrollArea.d.ts +9 -0
- package/vue/UiScrollArea.vue +28 -2
- package/vue/UiStack.d.ts +18 -0
- package/vue/UiStack.vue +58 -1
- package/vue/UiText.d.ts +9 -0
- package/vue/UiText.vue +33 -0
- package/vue/UiTextarea.d.ts +9 -0
- package/vue/UiTextarea.vue +37 -2
- package/vue/chunks/UiBadge.js +7 -3
- package/vue/chunks/UiButton.js +1 -1
- package/vue/chunks/UiCard.js +10 -3
- package/vue/chunks/UiCluster.js +82 -1
- package/vue/chunks/UiEditorSurface.js +71 -0
- package/vue/chunks/UiScrollArea.js +28 -2
- package/vue/chunks/UiStack.js +46 -1
- package/vue/chunks/UiText.js +43 -1
- package/vue/chunks/UiTextarea.js +28 -2
- package/vue/components.css +321 -190
- package/vue/editor/LoomaEditor.d.ts +12 -0
- package/vue/editor/index.js +7 -2
- package/vue/index.d.ts +1 -0
- package/vue/index.js +2 -1
|
@@ -14,7 +14,10 @@
|
|
|
14
14
|
<prop name="size" type="keyword" values="xs, md" default="md"
|
|
15
15
|
>Scale. xs is a compact count beside small controls; md is the usual text badge. A square is 24px at xs and 32px at md with default spacing.</prop>
|
|
16
16
|
</defs>
|
|
17
|
-
<span
|
|
17
|
+
<span>
|
|
18
|
+
<span class="icon" aria-hidden="true"><slot name="icon"></slot></span>
|
|
19
|
+
<span class="label"><slot></slot></span>
|
|
20
|
+
</span>
|
|
18
21
|
<style>
|
|
19
22
|
/* This component's hooks style the element they are set on, and never a nested one. */
|
|
20
23
|
@property --ui-badge-border {
|
|
@@ -89,6 +92,7 @@
|
|
|
89
92
|
display: inline-flex;
|
|
90
93
|
align-items: center;
|
|
91
94
|
justify-content: center;
|
|
95
|
+
gap: var(--ui-space-1);
|
|
92
96
|
box-sizing: border-box;
|
|
93
97
|
min-inline-size: 0;
|
|
94
98
|
max-inline-size: 100%;
|
|
@@ -113,8 +117,43 @@
|
|
|
113
117
|
text-overflow: ellipsis;
|
|
114
118
|
}
|
|
115
119
|
|
|
116
|
-
|
|
117
|
-
|
|
120
|
+
.label:empty {
|
|
121
|
+
display: none;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/* Icon content has its own flex item so label ellipsis never clips its strokes. */
|
|
125
|
+
.icon {
|
|
126
|
+
display: inline-flex;
|
|
127
|
+
align-items: center;
|
|
128
|
+
justify-content: center;
|
|
129
|
+
flex: none;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
.icon:empty {
|
|
133
|
+
display: none;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
.icon :slotted(svg) {
|
|
137
|
+
display: block;
|
|
138
|
+
inline-size: 1em;
|
|
139
|
+
block-size: 1em;
|
|
140
|
+
flex: none;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/* Ordinary icon-plus-text children keep inline ellipsis, with explicit glyph spacing. */
|
|
144
|
+
.label :slotted(svg) {
|
|
145
|
+
inline-size: 1em;
|
|
146
|
+
block-size: 1em;
|
|
147
|
+
vertical-align: middle;
|
|
148
|
+
margin-inline-end: var(--ui-space-1);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
.label:has(svg) {
|
|
152
|
+
text-box-trim: none;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/* Text-only badges retain their trimmed inline baseline. Icon content needs a flex row;
|
|
156
|
+
trimming its label separately keeps the glyph centered without changing adjacent lines. */
|
|
118
157
|
@supports (text-box-trim: trim-both) {
|
|
119
158
|
:host {
|
|
120
159
|
display: inline-block;
|
|
@@ -124,6 +163,15 @@
|
|
|
124
163
|
text-box-trim: trim-both;
|
|
125
164
|
text-box-edge: text;
|
|
126
165
|
}
|
|
166
|
+
:host:has(.icon:not(:empty)),
|
|
167
|
+
:host:has(.label svg) {
|
|
168
|
+
display: inline-flex;
|
|
169
|
+
text-box-trim: none;
|
|
170
|
+
}
|
|
171
|
+
:host:has(.icon:not(:empty)) .label {
|
|
172
|
+
text-box-trim: trim-both;
|
|
173
|
+
text-box-edge: text;
|
|
174
|
+
}
|
|
127
175
|
}
|
|
128
176
|
|
|
129
177
|
:host([size="xs"]) {
|
|
@@ -262,6 +310,14 @@
|
|
|
262
310
|
justify-content: center;
|
|
263
311
|
}
|
|
264
312
|
|
|
313
|
+
:host([shape="square"]) .label :slotted(svg) {
|
|
314
|
+
margin-inline-end: 0;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
:host([shape="square"]) .label:empty {
|
|
318
|
+
display: none;
|
|
319
|
+
}
|
|
320
|
+
|
|
265
321
|
/* A dot uses the badge's tone recipe; only its silhouette and visible label change. */
|
|
266
322
|
:host([shape="dot"]) {
|
|
267
323
|
position: relative;
|
|
@@ -181,6 +181,7 @@
|
|
|
181
181
|
display: inline-flex;
|
|
182
182
|
align-items: center;
|
|
183
183
|
justify-content: center;
|
|
184
|
+
column-gap: var(--ui-space-2);
|
|
184
185
|
vertical-align: middle;
|
|
185
186
|
color: var(--_tone-text);
|
|
186
187
|
}
|
|
@@ -230,7 +231,6 @@
|
|
|
230
231
|
.spinner-wrap {
|
|
231
232
|
display: inline-flex;
|
|
232
233
|
flex: none;
|
|
233
|
-
margin-inline-end: var(--ui-space-2);
|
|
234
234
|
vertical-align: middle;
|
|
235
235
|
}
|
|
236
236
|
|
|
@@ -7,8 +7,9 @@
|
|
|
7
7
|
elevated floats above the page with a shadow, for a view's one card, such as sign-in.</prop>
|
|
8
8
|
<prop name="padding" type="keyword" values="xs, sm, md, lg" default="md"
|
|
9
9
|
>The space inside the card: xs is compact (0.5rem), sm is snug (0.75rem), md is the default (1.5rem), and lg is roomy (2rem).</prop>
|
|
10
|
-
<prop name="tone" type="keyword" values="neutral, danger" default="neutral"
|
|
11
|
-
>
|
|
10
|
+
<prop name="tone" type="keyword" values="neutral, accent, info, success, warning, danger" default="neutral"
|
|
11
|
+
>accent, info, success and warning add a quiet semantic surface. danger retains its strong leading edge for consequential content. Tone never changes child
|
|
12
|
+
controls.</prop>
|
|
12
13
|
<prop name="as" type="keyword" values="div, section, article, aside" default="div"
|
|
13
14
|
>The native element the card renders. Choose the one that names the content: a section of a page, a self-contained article, or an aside.</prop>
|
|
14
15
|
</defs>
|
|
@@ -57,6 +58,30 @@
|
|
|
57
58
|
box-shadow: var(--ui-shadow-lg);
|
|
58
59
|
}
|
|
59
60
|
|
|
61
|
+
:host([tone="accent"]) {
|
|
62
|
+
border-color: color-mix(in srgb, var(--ui-accent) 25%, var(--ui-border-default));
|
|
63
|
+
background: color-mix(in srgb, var(--ui-accent) 6%, var(--ui-surface-default));
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
:host([tone="info"]) {
|
|
67
|
+
border-color: color-mix(in srgb, var(--ui-info) 25%, var(--ui-border-default));
|
|
68
|
+
background: color-mix(in srgb, var(--ui-info) 6%, var(--ui-surface-default));
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
:host([tone="success"]) {
|
|
72
|
+
border-color: color-mix(in srgb, var(--ui-success) 25%, var(--ui-border-default));
|
|
73
|
+
background: color-mix(in srgb, var(--ui-success) 6%, var(--ui-surface-default));
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
:host([tone="warning"]) {
|
|
77
|
+
border-color: color-mix(in srgb, var(--ui-warning) 25%, var(--ui-border-default));
|
|
78
|
+
background: color-mix(in srgb, var(--ui-warning) 6%, var(--ui-surface-default));
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
:host([variant="subtle"]:is([tone="accent"], [tone="info"], [tone="success"], [tone="warning"])) {
|
|
82
|
+
border-color: transparent;
|
|
83
|
+
}
|
|
84
|
+
|
|
60
85
|
:host([tone="danger"]) {
|
|
61
86
|
border-color: color-mix(in srgb, var(--ui-danger) 45%, var(--ui-border-default));
|
|
62
87
|
border-inline-start: var(--ui-accent-line-width) solid var(--ui-danger);
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
<template component="ui-cluster">
|
|
2
2
|
<defs>
|
|
3
|
+
<prop name="padding" type="keyword" values="none, s, m, l" default="none"
|
|
4
|
+
>Optional internal space for an action group, using the shared spacing scale.</prop>
|
|
5
|
+
<prop name="paddingEnd" type="keyword" values="none, s, m, l, xl" default="none"
|
|
6
|
+
>Optional extra space at the inline end, such as clearance beside another control. xl is 4rem.</prop>
|
|
7
|
+
<prop name="fixed" type="boolean" default="false">Keeps this group at its content size inside a flex layout.</prop>
|
|
3
8
|
<prop name="gap" type="keyword" values="xs, s, m, l, xl"
|
|
4
9
|
>Space between items, on the spacing scale: xs is 0.5rem, s 0.75rem (also the default), m 1rem, l 1.5rem, and xl 2rem. The --ui-cluster-gap custom property,
|
|
5
10
|
set on the cluster itself, overrides it; set on an ancestor, it does nothing.</prop>
|
|
@@ -33,6 +38,31 @@
|
|
|
33
38
|
margin: 0;
|
|
34
39
|
}
|
|
35
40
|
|
|
41
|
+
:host([fixed]) {
|
|
42
|
+
flex: none;
|
|
43
|
+
}
|
|
44
|
+
:host([padding="s"]) {
|
|
45
|
+
padding: var(--ui-space-2);
|
|
46
|
+
}
|
|
47
|
+
:host([padding="m"]) {
|
|
48
|
+
padding: var(--ui-space-3);
|
|
49
|
+
}
|
|
50
|
+
:host([padding="l"]) {
|
|
51
|
+
padding: var(--ui-space-4);
|
|
52
|
+
}
|
|
53
|
+
:host([paddingEnd="s"]) {
|
|
54
|
+
padding-inline-end: var(--ui-space-2);
|
|
55
|
+
}
|
|
56
|
+
:host([paddingEnd="m"]) {
|
|
57
|
+
padding-inline-end: var(--ui-space-3);
|
|
58
|
+
}
|
|
59
|
+
:host([paddingEnd="l"]) {
|
|
60
|
+
padding-inline-end: var(--ui-space-4);
|
|
61
|
+
}
|
|
62
|
+
:host([paddingEnd="xl"]) {
|
|
63
|
+
padding-inline-end: calc(var(--ui-space-4) * 4);
|
|
64
|
+
}
|
|
65
|
+
|
|
36
66
|
:host([gap="xs"]) {
|
|
37
67
|
--_layout-gap: var(--ui-space-2);
|
|
38
68
|
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
<template component="ui-editor-surface">
|
|
2
|
+
<defs>
|
|
3
|
+
<prop name="density" type="keyword" values="comfortable, compact" default="comfortable"
|
|
4
|
+
>The document canvas. comfortable preserves the editor's normal room and mobile toolbar clearance. compact fits a read-only excerpt to its content without
|
|
5
|
+
outer padding.</prop>
|
|
6
|
+
</defs>
|
|
7
|
+
<div><slot></slot></div>
|
|
8
|
+
<style>
|
|
9
|
+
:host {
|
|
10
|
+
display: flex;
|
|
11
|
+
flex-direction: column;
|
|
12
|
+
min-inline-size: 0;
|
|
13
|
+
max-inline-size: 100%;
|
|
14
|
+
}
|
|
15
|
+
/* The document renderer consumes these inherited surface settings. They do not style controls. */
|
|
16
|
+
:host([density="compact"]) {
|
|
17
|
+
--_ui-editor-content-min-height: 0px;
|
|
18
|
+
--_ui-editor-content-padding-block: 0px;
|
|
19
|
+
--_ui-editor-content-padding-inline: 0px;
|
|
20
|
+
--_ui-editor-mobile-bottom-space: 0px;
|
|
21
|
+
}
|
|
22
|
+
</style>
|
|
23
|
+
</template>
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<template component="ui-scroll-area" controller="./ui-scroll-area.js">
|
|
2
2
|
<defs>
|
|
3
|
+
<prop name="fill" type="boolean" default="false">Grows into remaining space within a flex layout while keeping content independently scrollable.</prop>
|
|
3
4
|
<prop name="size" type="keyword" values="content, sm, md, lg" default="content"
|
|
4
5
|
>Optional height preset. content keeps intrinsic sizing; sm fits three compact 3.125rem result rows before the overflow fade, md is 20rem, and lg is
|
|
5
6
|
30rem.</prop>
|
|
@@ -12,6 +13,10 @@
|
|
|
12
13
|
/* The controller sets each fade length from overflow and scroll position. The mask blends
|
|
13
14
|
into whatever is behind the area without needing to know its colour. Before upgrade, its
|
|
14
15
|
zero-length defaults leave the authored scroll area fully visible. */
|
|
16
|
+
:host([fill]) {
|
|
17
|
+
flex: 1;
|
|
18
|
+
}
|
|
19
|
+
|
|
15
20
|
:host {
|
|
16
21
|
display: block;
|
|
17
22
|
box-sizing: border-box;
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
<template component="ui-stack">
|
|
2
2
|
<defs>
|
|
3
|
+
<prop name="fill" type="boolean" default="false">Grows into the remaining space of a flex layout and allows its scrolling children to shrink.</prop>
|
|
4
|
+
<prop name="height" type="number">An optional measured height in CSS pixels, for a viewport-bounded composition. Omit it to retain intrinsic sizing.</prop>
|
|
3
5
|
<prop name="gap" type="keyword" values="none, xs, s, m, l, xl"
|
|
4
6
|
>Space between items, on the spacing scale: none is zero, xs is 0.5rem, s 0.75rem, m 1rem (also the default), l 1.5rem, and xl 2rem. The --ui-stack-gap
|
|
5
7
|
custom property, set on the stack itself, overrides it; set on an ancestor, it does nothing.</prop>
|
|
@@ -10,9 +12,14 @@
|
|
|
10
12
|
>Where items sit along a stack that is taller than its content: start (the default), center, end, or between, which spreads the spare space between items.
|
|
11
13
|
It has no effect unless the stack is given a height or stretched to one.</prop>
|
|
12
14
|
</defs>
|
|
13
|
-
<div><slot></slot></div>
|
|
15
|
+
<div style:--ui-stack-height="height"><slot></slot></div>
|
|
14
16
|
<style>
|
|
15
17
|
/* This component's hooks style the element they are set on, and never a nested one. */
|
|
18
|
+
@property --ui-stack-height {
|
|
19
|
+
syntax: "*";
|
|
20
|
+
inherits: false;
|
|
21
|
+
}
|
|
22
|
+
|
|
16
23
|
@property --ui-stack-gap {
|
|
17
24
|
syntax: "*";
|
|
18
25
|
inherits: false;
|
|
@@ -29,6 +36,15 @@
|
|
|
29
36
|
margin: 0;
|
|
30
37
|
}
|
|
31
38
|
|
|
39
|
+
:host([fill]) {
|
|
40
|
+
flex: 1;
|
|
41
|
+
min-block-size: 0;
|
|
42
|
+
}
|
|
43
|
+
:host([height]) {
|
|
44
|
+
block-size: calc(var(--ui-stack-height, 0) * 1px);
|
|
45
|
+
min-block-size: 0;
|
|
46
|
+
}
|
|
47
|
+
|
|
32
48
|
:host([gap="none"]) {
|
|
33
49
|
--_layout-gap: 0px;
|
|
34
50
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<template component="ui-text">
|
|
2
2
|
<defs>
|
|
3
|
+
<prop name="grow" type="boolean" default="false">Lets this text use remaining inline space in a flex row, including when truncated.</prop>
|
|
3
4
|
<prop name="font" type="keyword" values="inherit, sans" default="inherit"
|
|
4
5
|
>Use sans for UI text rendered outside its original font context; inherit preserves the surrounding typeface.</prop>
|
|
5
6
|
<prop name="wrap" type="keyword" values="normal, anywhere" default="normal"
|
|
@@ -39,6 +40,10 @@
|
|
|
39
40
|
/* Running text, set on the type scale and in a tone that says what it is, so a view never styles
|
|
40
41
|
text of its own. The root is a paragraph unless as= names a span, div, small, strong, label, or
|
|
41
42
|
heading. */
|
|
43
|
+
:host([grow]) {
|
|
44
|
+
flex: 1;
|
|
45
|
+
}
|
|
46
|
+
|
|
42
47
|
:host {
|
|
43
48
|
margin: 0;
|
|
44
49
|
min-inline-size: 0;
|
|
@@ -8,6 +8,8 @@
|
|
|
8
8
|
<prop name="readonly" type="boolean" default="false">Allows selection without allowing edits.</prop>
|
|
9
9
|
<prop name="required" type="boolean" default="false">Marks the control as required for form validation.</prop>
|
|
10
10
|
<prop name="rows" type="integer" default="4">Initial number of visible text rows.</prop>
|
|
11
|
+
<prop name="maxRows" type="integer"
|
|
12
|
+
>Optional maximum visible rows, for a growing field in a bounded layout. Extra text scrolls inside the field. Omit it to retain unbounded growth.</prop>
|
|
11
13
|
<prop name="autosize" type="boolean" default="false"
|
|
12
14
|
>Grow with the text while keeping rows as the minimum visible height. Uses CSS field sizing where supported; other browsers keep the native rows
|
|
13
15
|
behavior.</prop>
|
|
@@ -23,6 +25,7 @@
|
|
|
23
25
|
from:aria-invalid="invalid"
|
|
24
26
|
from:rows="rows"
|
|
25
27
|
style:--_rows="rows"
|
|
28
|
+
style:--_max-rows="maxRows"
|
|
26
29
|
></textarea>
|
|
27
30
|
<style>
|
|
28
31
|
/* This component's hooks style the element they are set on, and never a nested one. */
|
|
@@ -164,6 +167,10 @@
|
|
|
164
167
|
font-size: var(--ui-font-size-md);
|
|
165
168
|
}
|
|
166
169
|
|
|
170
|
+
:host([maxRows]) {
|
|
171
|
+
max-block-size: calc(max(var(--_rows), var(--_max-rows)) * 1lh + var(--_padding-block) + var(--_padding-block) + 2px);
|
|
172
|
+
}
|
|
173
|
+
|
|
167
174
|
@supports (field-sizing: content) {
|
|
168
175
|
:host([autosize]) {
|
|
169
176
|
field-sizing: content;
|