@threadlabs/looma 0.7.3 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/components/ui-avatar/ui-avatar.html +1 -1
  2. package/components/ui-avatar-group/ui-avatar-group.html +1 -1
  3. package/components/ui-badge/ui-badge.html +20 -0
  4. package/components/ui-button/ui-button.html +38 -15
  5. package/components/ui-combobox/ui-combobox.html +1 -1
  6. package/components/ui-editor-slash-menu/ui-editor-slash-menu.html +1 -1
  7. package/components/ui-editor-table-context-menu/ui-editor-table-context-menu.html +1 -1
  8. package/components/ui-editor-table-toolbar/ui-editor-table-toolbar.html +1 -1
  9. package/components/ui-form-field/ui-form-field.html +3 -3
  10. package/components/ui-tree-item/ui-tree-item.html +1 -1
  11. package/dist/index.js +1 -1
  12. package/package.json +1 -1
  13. package/styles/ui-avatar-group.css +1 -1
  14. package/styles/ui-avatar.css +1 -1
  15. package/styles/ui-badge.css +22 -0
  16. package/styles/ui-button.css +20 -14
  17. package/styles/ui-combobox.css +1 -1
  18. package/styles/ui-editor-slash-menu.css +1 -1
  19. package/styles/ui-editor-table-context-menu.css +1 -1
  20. package/styles/ui-editor-table-toolbar.css +1 -1
  21. package/styles/ui-form-field.css +3 -3
  22. package/styles/ui-tree-item.css +1 -1
  23. package/tokens.css +2 -3
  24. package/vanilla/UiBadge.d.ts +1 -0
  25. package/vanilla/UiBadge.js +4 -2
  26. package/vanilla/UiButton.d.ts +5 -0
  27. package/vanilla/UiButton.js +8 -6
  28. package/vue/UiAvatar.vue +1 -1
  29. package/vue/UiAvatarGroup.vue +1 -1
  30. package/vue/UiBadge.d.ts +2 -0
  31. package/vue/UiBadge.vue +29 -0
  32. package/vue/UiButton.d.ts +9 -2
  33. package/vue/UiButton.vue +48 -18
  34. package/vue/UiCombobox.vue +1 -1
  35. package/vue/UiEditorSlashMenu.vue +1 -1
  36. package/vue/UiEditorTableContextMenu.vue +1 -1
  37. package/vue/UiEditorTableToolbar.vue +1 -1
  38. package/vue/UiFormField.vue +3 -3
  39. package/vue/UiTreeItem.vue +1 -1
  40. package/vue/chunks/UiAvatar.js +1 -1
  41. package/vue/chunks/UiAvatarGroup.js +1 -1
  42. package/vue/chunks/UiBadge.js +7 -2
  43. package/vue/chunks/UiButton.js +52 -10
  44. package/vue/chunks/UiCombobox.js +1 -1
  45. package/vue/chunks/UiEditorSlashMenu.js +1 -1
  46. package/vue/chunks/UiEditorTableContextMenu.js +1 -1
  47. package/vue/chunks/UiEditorTableToolbar.js +1 -1
  48. package/vue/chunks/UiFormField.js +1 -1
  49. package/vue/chunks/UiTreeItem.js +1 -1
  50. package/vue/components.css +270 -241
@@ -25,7 +25,7 @@
25
25
  background: var(--ui-avatar-surface, var(--ui-accent-soft));
26
26
  color: var(--ui-avatar-text, var(--ui-accent-solid));
27
27
  font: inherit;
28
- font-size: 0.875rem;
28
+ font-size: var(--ui-font-size-sm);
29
29
  font-weight: 600;
30
30
  text-transform: uppercase;
31
31
  }
@@ -50,7 +50,7 @@
50
50
  var(--ui-avatar-group-overlap-shadow, var(--_overlap-shadow)),
51
51
  var(--ui-avatar-group-edge-ring, var(--_edge-ring));
52
52
  font: inherit;
53
- font-size: 0.75rem;
53
+ font-size: var(--ui-font-size-xs);
54
54
  font-weight: 600;
55
55
  flex-shrink: 0;
56
56
  }
@@ -2,6 +2,8 @@
2
2
  <defs>
3
3
  <prop name="variant" type="solid | subtle" default="subtle">variant token.</prop>
4
4
  <prop name="tone" type="neutral | accent | info | success | warning | danger" default="neutral">tone token.</prop>
5
+ <prop name="shape" type="pill | tag" default="pill"
6
+ >Silhouette. pill is rounded at both ends; tag is a label: flat at the start and coming to a point at the end, for a tag or a chosen chip.</prop>
5
7
  </defs>
6
8
  <span><slot></slot></span>
7
9
  <style>
@@ -100,6 +102,24 @@
100
102
  --_badge-text: var(--ui-info-subtle-text, var(--ui-info-solid));
101
103
  }
102
104
 
105
+ /* A tag is flat at the start and points at the end. The point is cut from the box, so it has no
106
+ outline to follow: the edge is the fill. The end padding grows by the point's depth so the
107
+ label never runs into it. */
108
+ :host-state([shape="tag"]) {
109
+ --_badge-point: var(--ui-badge-point, var(--ui-space-2));
110
+
111
+ border-color: transparent;
112
+ border-radius: 0;
113
+ padding-inline-end: calc(var(--ui-badge-padding-inline, var(--ui-space-2)) + var(--_badge-point));
114
+ clip-path: polygon(0 0, calc(100% - var(--_badge-point)) 0, 100% 50%, calc(100% - var(--_badge-point)) 100%, 0 100%);
115
+ }
116
+
117
+ :host-state([shape="tag"]):dir(rtl) {
118
+ padding-inline-end: var(--ui-badge-padding-inline, var(--ui-space-2));
119
+ padding-inline-start: calc(var(--ui-badge-padding-inline, var(--ui-space-2)) + var(--_badge-point));
120
+ clip-path: polygon(var(--_badge-point) 0, 100% 0, 100% 100%, var(--_badge-point) 100%, 0 50%);
121
+ }
122
+
103
123
  /* A component that sets its display still honours the hidden attribute on its root. */
104
124
  :host[hidden] {
105
125
  display: none;
@@ -11,8 +11,28 @@
11
11
  <prop name="align" type="center | start" default="center"
12
12
  >Content alignment. start lays the content out like a list option: from the start edge, with start-aligned text.</prop>
13
13
  <prop name="stretch" type="boolean" default="false">Fills the inline size of its container.</prop>
14
+ <prop name="type" type="button | submit | reset" default="button"
15
+ >The button's type, as on a native button. button by default, so it never submits a form by accident. A link has no type.</prop>
16
+ <prop name="href" type="string"
17
+ >The link's destination. Pair it with as="a" so the button renders as a real link that navigates. A disabled link drops its href and states
18
+ aria-disabled="true", so it cannot be followed.</prop>
19
+ <prop name="target" type="string">Where a link opens, as on a native link. Only meaningful with as="a".</prop>
20
+ <prop name="rel" type="string">The link's relationship to its destination, as on a native link. Only meaningful with as="a".</prop>
21
+ <!-- One root, a button or a link (as="a"). The language has no conditional expression, so a table keyed
22
+ by a boolean's text picks each value, and null leaves the attribute off: a link never carries type or
23
+ disabled, and a disabled link loses its href and states aria-disabled instead. -->
14
24
  </defs>
15
- <button type="button" :disabled="disabled"><slot></slot></button>
25
+ <button
26
+ as="button|a"
27
+ :type="{ true: type, false: null }[format('%s', not href)]"
28
+ :disabled="{ true: true, false: null }[format('%s', disabled and not href)]"
29
+ :href="{ true: null, false: href }[format('%s', disabled)]"
30
+ :target="target"
31
+ :rel="rel"
32
+ :aria-disabled="{ true: 'true', false: null }[format('%s', disabled and href)]"
33
+ >
34
+ <slot></slot>
35
+ </button>
16
36
  <style>
17
37
  :host {
18
38
  --_hue: var(--ui-accent);
@@ -55,6 +75,7 @@
55
75
  color: var(--ui-button-text, var(--_tone-text));
56
76
  font: inherit;
57
77
  font-weight: var(--ui-font-medium);
78
+ text-decoration: none;
58
79
  line-height: var(--ui-line-height-tight);
59
80
  padding: var(--ui-space-2) var(--ui-space-3);
60
81
  background-image: var(--ui-raised-highlight);
@@ -78,22 +99,24 @@
78
99
  :host-state([size="sm"]) {
79
100
  min-block-size: var(--ui-control-size-sm);
80
101
  padding: var(--ui-space-1) var(--ui-space-2);
81
- font-size: 0.875rem;
102
+ font-size: var(--ui-font-size-sm);
82
103
  }
83
104
 
84
105
  :host-state([size="lg"]) {
85
106
  min-block-size: var(--ui-control-size-lg);
86
107
  padding: var(--ui-space-3) var(--ui-space-4);
87
- font-size: 1rem;
108
+ font-size: var(--ui-font-size-md);
88
109
  }
89
110
 
90
- :host:hover:enabled {
111
+ /* A link is never :enabled, so interactive states test "not unavailable" instead: for a button that
112
+ is exactly :enabled, at the same specificity, and it also matches a link that can be followed. */
113
+ :host:hover:not(:disabled, [aria-disabled="true"]) {
91
114
  border-color: var(--ui-button-hover-border, var(--_tone-hover));
92
115
  background-color: var(--ui-button-hover-surface, oklch(from var(--_tone) l c h / 12%));
93
116
  }
94
117
 
95
118
  /* Pressed reads as pressed in: the highlight goes, and the shadow moves inside. */
96
- :host:active:enabled {
119
+ :host:active:not(:disabled, [aria-disabled="true"]) {
97
120
  background-color: var(--ui-button-active-surface, oklch(from var(--_tone) l c h / 18%));
98
121
  background-image: none;
99
122
  box-shadow: var(--ui-pressed);
@@ -106,12 +129,12 @@
106
129
  box-shadow: var(--ui-button-solid-shadow, var(--ui-raised));
107
130
  }
108
131
 
109
- :is(:host-state([variant="solid"]), :host-state([variant="danger"])):hover:enabled {
132
+ :is(:host-state([variant="solid"]), :host-state([variant="danger"])):hover:not(:disabled, [aria-disabled="true"]) {
110
133
  background-color: var(--_tone-hover);
111
134
  border-color: var(--_tone-hover);
112
135
  }
113
136
 
114
- :is(:host-state([variant="solid"]), :host-state([variant="danger"])):active:enabled {
137
+ :is(:host-state([variant="solid"]), :host-state([variant="danger"])):active:not(:disabled, [aria-disabled="true"]) {
115
138
  background-color: var(--_tone-active);
116
139
  border-color: var(--_tone-active);
117
140
  background-image: none;
@@ -168,12 +191,12 @@
168
191
  }
169
192
 
170
193
  /* Tints derive from the text colour, not a surface token, so hover and press show on any background. */
171
- :host-state([variant="ghost"]):hover:enabled {
194
+ :host-state([variant="ghost"]):hover:not(:disabled, [aria-disabled="true"]) {
172
195
  background-color: var(--ui-button-ghost-hover-surface, oklch(from var(--_tone) l c h / 10%));
173
196
  border-color: transparent;
174
197
  }
175
198
 
176
- :host-state([variant="ghost"]):active:enabled {
199
+ :host-state([variant="ghost"]):active:not(:disabled, [aria-disabled="true"]) {
177
200
  background-color: var(--ui-button-ghost-active-surface, oklch(from var(--_tone) l c h / 16%));
178
201
  border-color: transparent;
179
202
  box-shadow: var(--ui-pressed);
@@ -197,7 +220,7 @@
197
220
  disabled outline is still an outline and a disabled ghost still has no edge. Intent goes — an
198
221
  unavailable action says "unavailable", not "unavailable, and destructive" — and so do the
199
222
  highlight and shadow, because nothing that cannot be pressed should look raised. */
200
- :host:disabled {
223
+ :host:is(:disabled, [aria-disabled="true"]) {
201
224
  /* Derived from the tone itself, not from a separate disabled palette: faded toward the
202
225
  page, which desaturates it at the same time. Toward the page rather than toward white,
203
226
  so a dark theme dims where a light one lightens — the same rule, both schemes. */
@@ -214,7 +237,7 @@
214
237
  }
215
238
 
216
239
  /* A filled button keeps its fill, faded further so its text stays legible on it. */
217
- :is(:host-state([variant="solid"]), :host-state([variant="danger"])):disabled {
240
+ :is(:host-state([variant="solid"]), :host-state([variant="danger"])):is(:disabled, [aria-disabled="true"]) {
218
241
  --_tone: color-mix(in oklab, var(--_hue) 34%, var(--ui-surface));
219
242
  }
220
243
 
@@ -222,7 +245,7 @@
222
245
  it takes a surface rather than reading as plain text. The surface is a wash of the faded tone,
223
246
  the way hover washes the live one, so it stays light in every tone. An opaque mix toward the
224
247
  hue came out a mid-grey slab for neutral, whose hue is the ink: louder than the enabled button. */
225
- :host-state([variant="ghost"]):disabled {
248
+ :host-state([variant="ghost"]):is(:disabled, [aria-disabled="true"]) {
226
249
  background-color: oklch(from var(--_tone) l c h / 14%);
227
250
  border-color: transparent;
228
251
  }
@@ -252,19 +275,19 @@
252
275
  transition: color var(--ui-motion-fast) var(--ui-motion-ease), text-decoration-color var(--ui-motion-fast) var(--ui-motion-ease);
253
276
  }
254
277
 
255
- :host-state([variant="link"]):hover:enabled {
278
+ :host-state([variant="link"]):hover:not(:disabled, [aria-disabled="true"]) {
256
279
  color: var(--ui-button-link-hover-text, var(--ui-text-primary));
257
280
  text-decoration-color: currentColor;
258
281
  background: none;
259
282
  transform: none;
260
283
  }
261
284
 
262
- :host-state([variant="link"]):active:enabled {
285
+ :host-state([variant="link"]):active:not(:disabled, [aria-disabled="true"]) {
263
286
  background: none;
264
287
  transform: none;
265
288
  }
266
289
 
267
- :host-state([variant="link"]):disabled {
290
+ :host-state([variant="link"]):is(:disabled, [aria-disabled="true"]) {
268
291
  background: none;
269
292
  border-color: transparent;
270
293
  color: var(--ui-button-disabled-text, var(--ui-disabled-text));
@@ -212,7 +212,7 @@
212
212
  }
213
213
  label {
214
214
  color: var(--ui-combobox-label-text, var(--ui-text-primary));
215
- font-size: var(--ui-combobox-label-font-size, 0.875rem);
215
+ font-size: var(--ui-combobox-label-font-size, var(--ui-font-size-sm));
216
216
  font-weight: 500;
217
217
  }
218
218
  /* The field and anything that annotates it sit on one row; the help button is beside the box,
@@ -182,7 +182,7 @@
182
182
  align-items: center;
183
183
  justify-content: center;
184
184
  font-family: var(--ui-font-family-mono, ui-monospace, monospace);
185
- font-size: 10px;
185
+ font-size: var(--ui-font-size-2xs);
186
186
  background: var(--ui-surface-hover);
187
187
  border: 1px solid var(--ui-border);
188
188
  border-radius: 3px;
@@ -150,7 +150,7 @@
150
150
 
151
151
  .heading {
152
152
  padding: var(--ui-space-1) var(--ui-space-2);
153
- font-size: 0.6875rem;
153
+ font-size: var(--ui-font-size-2xs);
154
154
  font-weight: 700;
155
155
  letter-spacing: 0.05em;
156
156
  text-transform: uppercase;
@@ -224,7 +224,7 @@
224
224
 
225
225
  .menu-heading {
226
226
  padding: var(--ui-space-1) var(--ui-space-2);
227
- font-size: 0.6875rem;
227
+ font-size: var(--ui-font-size-2xs);
228
228
  font-weight: 700;
229
229
  letter-spacing: 0.05em;
230
230
  text-transform: uppercase;
@@ -29,12 +29,12 @@
29
29
 
30
30
  .label {
31
31
  color: var(--ui-text-secondary);
32
- font-size: 0.95rem;
32
+ font-size: var(--ui-font-size-sm);
33
33
  }
34
34
 
35
35
  .help {
36
36
  color: var(--ui-text-muted);
37
- font-size: 0.875rem;
37
+ font-size: var(--ui-font-size-sm);
38
38
  line-height: var(--ui-line-height-md);
39
39
  }
40
40
 
@@ -45,7 +45,7 @@
45
45
  .error,
46
46
  :slotted([role="alert"]) {
47
47
  color: var(--ui-accent-active);
48
- font-size: 0.875rem;
48
+ font-size: var(--ui-font-size-sm);
49
49
  }
50
50
 
51
51
  /* A component that sets its display still honours the hidden attribute on its root. */
@@ -87,7 +87,7 @@
87
87
  align-items: center;
88
88
  min-block-size: var(--ui-tree-item-min-block-size, var(--_tree-row-min-height));
89
89
  min-inline-size: 0;
90
- font-size: var(--ui-tree-item-font-size, var(--ui-font-size-ui));
90
+ font-size: var(--ui-tree-item-font-size, var(--ui-font-size-sm));
91
91
  border-radius: var(--ui-radius-md);
92
92
  color: var(--ui-text-secondary);
93
93
  transition: