@threadlabs/looma 0.26.1 → 0.26.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/components/ui-badge/ui-badge.html +42 -3
- package/components/ui-container/ui-container.html +11 -0
- package/components/ui-icon-button/ui-icon-button.html +58 -12
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/styles/ui-badge.css +40 -0
- package/styles/ui-container.css +8 -0
- package/styles/ui-icon-button.css +62 -12
- package/vanilla/UiBadge.d.ts +1 -1
- package/vanilla/UiBadge.js +1 -1
- package/vanilla/UiContainer.d.ts +1 -0
- package/vanilla/UiContainer.js +5 -5
- package/vanilla/UiIconButton.d.ts +1 -0
- package/vanilla/UiIconButton.js +4 -4
- package/vue/UiBadge.d.ts +3 -3
- package/vue/UiBadge.vue +44 -6
- package/vue/UiContainer.d.ts +9 -0
- package/vue/UiContainer.vue +27 -1
- package/vue/UiIconButton.d.ts +9 -0
- package/vue/UiIconButton.vue +95 -12
- package/vue/chunks/UiBadge.js +5 -4
- package/vue/chunks/UiContainer.js +23 -1
- package/vue/chunks/UiIconButton.js +25 -1
- package/vue/components.css +202 -102
package/package.json
CHANGED
package/styles/ui-badge.css
CHANGED
|
@@ -7,6 +7,10 @@
|
|
|
7
7
|
syntax: "*";
|
|
8
8
|
inherits: false;
|
|
9
9
|
}
|
|
10
|
+
@property --ui-badge-circle-size {
|
|
11
|
+
syntax: "*";
|
|
12
|
+
inherits: false;
|
|
13
|
+
}
|
|
10
14
|
@property --ui-badge-dot-size {
|
|
11
15
|
syntax: "*";
|
|
12
16
|
inherits: false;
|
|
@@ -282,6 +286,36 @@
|
|
|
282
286
|
display: none;
|
|
283
287
|
}
|
|
284
288
|
|
|
289
|
+
/* A visible glyph needs fixed geometry, unlike a content-sized pill or a hidden-label dot. */
|
|
290
|
+
:scope[data-ui-badge-state~="shape=circle"] {
|
|
291
|
+
--_badge-circle-size: var(--ui-badge-circle-size, calc(var(--ui-space-3) * 2));
|
|
292
|
+
display: inline-flex;
|
|
293
|
+
flex: none;
|
|
294
|
+
inline-size: var(--_badge-circle-size);
|
|
295
|
+
block-size: var(--_badge-circle-size);
|
|
296
|
+
min-inline-size: var(--_badge-circle-size);
|
|
297
|
+
min-block-size: var(--_badge-circle-size);
|
|
298
|
+
padding: 0;
|
|
299
|
+
border-radius: var(--ui-radius-round);
|
|
300
|
+
text-box-trim: none;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
:scope[data-ui-badge-state~="shape=circle"][data-ui-badge-state~="size=xs"] {
|
|
304
|
+
--_badge-circle-size: var(--ui-badge-circle-size, var(--ui-space-4));
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
:scope[data-ui-badge-state~="shape=circle"] .label {
|
|
308
|
+
display: inline-flex;
|
|
309
|
+
align-items: center;
|
|
310
|
+
justify-content: center;
|
|
311
|
+
line-height: 1;
|
|
312
|
+
text-box-trim: none;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
:scope[data-ui-badge-state~="shape=circle"] .label:empty {
|
|
316
|
+
display: none;
|
|
317
|
+
}
|
|
318
|
+
|
|
285
319
|
/* A dot uses the badge's tone recipe; only its silhouette and visible label change. */
|
|
286
320
|
:scope[data-ui-badge-state~="shape=dot"] {
|
|
287
321
|
position: relative;
|
|
@@ -399,6 +433,12 @@
|
|
|
399
433
|
margin-inline-end: 0;
|
|
400
434
|
}
|
|
401
435
|
|
|
436
|
+
/* A visible glyph needs fixed geometry, unlike a content-sized pill or a hidden-label dot. */
|
|
437
|
+
|
|
438
|
+
:scope[data-ui-badge-state~="shape=circle"] .label :where([data-slotted], [data-slotted] *):is(svg) {
|
|
439
|
+
margin-inline-end: 0;
|
|
440
|
+
}
|
|
441
|
+
|
|
402
442
|
/* A dot uses the badge's tone recipe; only its silhouette and visible label change. */
|
|
403
443
|
|
|
404
444
|
/* The clipped point needs an inset surface over an outer border-colour shape: a native border
|
package/styles/ui-container.css
CHANGED
|
@@ -23,6 +23,14 @@
|
|
|
23
23
|
:scope[data-ui-container-state~="measure=narrow"] {
|
|
24
24
|
--_container-measure: 45ch;
|
|
25
25
|
}
|
|
26
|
+
:scope[data-ui-container-state~="fill"] {
|
|
27
|
+
box-sizing: border-box;
|
|
28
|
+
display: flex;
|
|
29
|
+
flex-direction: column;
|
|
30
|
+
flex: 1;
|
|
31
|
+
min-inline-size: 0;
|
|
32
|
+
min-block-size: 0;
|
|
33
|
+
}
|
|
26
34
|
:scope[data-ui-container-state~="measure=wide"] {
|
|
27
35
|
--_container-measure: 80ch;
|
|
28
36
|
}
|
|
@@ -87,6 +87,21 @@
|
|
|
87
87
|
color: var(--ui-text-secondary);
|
|
88
88
|
}
|
|
89
89
|
|
|
90
|
+
:scope[data-ui-icon-button-state~="tone=accent"] {
|
|
91
|
+
--_icon-button-border: var(--ui-accent-solid);
|
|
92
|
+
--_icon-button-hover-border: var(--ui-accent-hover);
|
|
93
|
+
--_icon-button-text: var(--ui-accent-subtle-text, var(--ui-accent-solid));
|
|
94
|
+
--_icon-button-outline-surface: color-mix(in srgb, var(--ui-accent-solid) 5%, var(--ui-surface-default));
|
|
95
|
+
color: var(--_icon-button-text);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/* Omitted tone retains the existing accent solid; explicit neutral is additive. */
|
|
99
|
+
:scope[data-ui-icon-button-state~="tone=neutral"] {
|
|
100
|
+
--_icon-button-solid-surface: var(--ui-text-primary);
|
|
101
|
+
--_icon-button-solid-hover-surface: var(--ui-text-primary);
|
|
102
|
+
--_icon-button-solid-text: var(--ui-surface-default);
|
|
103
|
+
}
|
|
104
|
+
|
|
90
105
|
:scope[data-ui-icon-button-state~="anticipatory"] {
|
|
91
106
|
position: relative;
|
|
92
107
|
}
|
|
@@ -119,13 +134,13 @@
|
|
|
119
134
|
}
|
|
120
135
|
|
|
121
136
|
@media (hover: hover) and (pointer: fine) {
|
|
122
|
-
:scope[data-ui-icon-button-state~="anticipatory"]:not(:scope[data-ui-icon-button-state~="variant=solid"], :scope[data-ui-icon-button-state~="loading"], :scope[data-ui-icon-button-state~="pending"], :disabled, [data-ui-proximity="near"], :hover, :focus-visible) {
|
|
137
|
+
:scope[data-ui-icon-button-state~="anticipatory"]:not(:scope[data-ui-icon-button-state~="variant=solid"], :scope[data-ui-icon-button-state~="loading"], :scope[data-ui-icon-button-state~="pending"], :disabled, [aria-pressed="true"], [data-ui-proximity="near"], :hover, :focus-visible) {
|
|
123
138
|
border-color: transparent;
|
|
124
139
|
background-color: transparent;
|
|
125
140
|
box-shadow: none;
|
|
126
141
|
}
|
|
127
142
|
|
|
128
|
-
:scope[data-ui-icon-button-state~="anticipatory"]:not(:scope[data-ui-icon-button-state~="variant=solid"], :scope[data-ui-icon-button-state~="loading"], :scope[data-ui-icon-button-state~="pending"], :disabled, [data-ui-proximity="near"], :hover, :focus-visible)
|
|
143
|
+
:scope[data-ui-icon-button-state~="anticipatory"]:not(:scope[data-ui-icon-button-state~="variant=solid"], :scope[data-ui-icon-button-state~="loading"], :scope[data-ui-icon-button-state~="pending"], :disabled, [aria-pressed="true"], [data-ui-proximity="near"], :hover, :focus-visible)
|
|
129
144
|
.content {
|
|
130
145
|
opacity: 0;
|
|
131
146
|
transform: scale(0.65);
|
|
@@ -133,7 +148,7 @@
|
|
|
133
148
|
}
|
|
134
149
|
}
|
|
135
150
|
|
|
136
|
-
:scope[data-ui-icon-button-state~="anticipatory"]:is(:scope[data-ui-icon-button-state~="variant=solid"], [data-ui-proximity="near"], :hover, :focus-visible)::before {
|
|
151
|
+
:scope[data-ui-icon-button-state~="anticipatory"]:is(:scope[data-ui-icon-button-state~="variant=solid"], [aria-pressed="true"], [data-ui-proximity="near"], :hover, :focus-visible)::before {
|
|
137
152
|
opacity: 0;
|
|
138
153
|
}
|
|
139
154
|
|
|
@@ -243,17 +258,17 @@
|
|
|
243
258
|
}
|
|
244
259
|
|
|
245
260
|
:scope[data-ui-icon-button-state~="variant=outline"] {
|
|
246
|
-
border-color: var(--ui-icon-button-border, var(--ui-control-border, var(--ui-border-strong)));
|
|
247
|
-
background-color: var(--ui-icon-button-outline-surface, var(--ui-surface-default));
|
|
261
|
+
border-color: var(--ui-icon-button-border, var(--_icon-button-border, var(--ui-control-border, var(--ui-border-strong))));
|
|
262
|
+
background-color: var(--ui-icon-button-outline-surface, var(--_icon-button-outline-surface, var(--ui-surface-default)));
|
|
248
263
|
background-image: var(--ui-raised-highlight);
|
|
249
|
-
color: var(--ui-icon-button-outline-text, var(--ui-text-primary));
|
|
264
|
+
color: var(--ui-icon-button-outline-text, var(--_icon-button-text, var(--ui-text-primary)));
|
|
250
265
|
box-shadow: var(--ui-raised);
|
|
251
266
|
}
|
|
252
267
|
|
|
253
268
|
:scope[data-ui-icon-button-state~="variant=solid"] {
|
|
254
|
-
background-color: var(--ui-icon-button-solid-surface, var(--ui-accent-solid));
|
|
269
|
+
background-color: var(--ui-icon-button-solid-surface, var(--_icon-button-solid-surface, var(--ui-accent-solid)));
|
|
255
270
|
background-image: var(--ui-raised-highlight);
|
|
256
|
-
color: var(--ui-icon-button-solid-text, var(--ui-text-on-accent));
|
|
271
|
+
color: var(--ui-icon-button-solid-text, var(--_icon-button-solid-text, var(--ui-text-on-accent)));
|
|
257
272
|
box-shadow: var(
|
|
258
273
|
--ui-icon-button-solid-shadow,
|
|
259
274
|
0 1px 2px color-mix(in srgb, var(--ui-accent-solid) 18%, transparent)
|
|
@@ -263,20 +278,32 @@
|
|
|
263
278
|
:scope:hover:enabled:not([aria-disabled="true"]) {
|
|
264
279
|
/* Derived from the text colour so the ghost hover shows on any background. */
|
|
265
280
|
background-color: var(--ui-icon-button-hover-surface, color-mix(in srgb, currentColor 8%, transparent));
|
|
266
|
-
color: var(--ui-icon-button-hover-text, var(--ui-text-primary));
|
|
281
|
+
color: var(--ui-icon-button-hover-text, var(--_icon-button-text, var(--ui-text-primary)));
|
|
267
282
|
}
|
|
268
283
|
|
|
269
284
|
:scope[data-ui-icon-button-state~="variant=outline"]:hover:enabled:not([aria-disabled="true"]) {
|
|
270
|
-
border-color: var(--ui-icon-button-hover-border, var(--ui-control-border-hover, var(--ui-control-border)));
|
|
285
|
+
border-color: var(--ui-icon-button-hover-border, var(--_icon-button-hover-border, var(--ui-control-border-hover, var(--ui-control-border))));
|
|
271
286
|
}
|
|
272
287
|
|
|
273
288
|
:scope[data-ui-icon-button-state~="variant=solid"]:hover:enabled:not([aria-disabled="true"]) {
|
|
274
|
-
background-color: var(--ui-icon-button-solid-hover-surface, var(--ui-accent-hover));
|
|
289
|
+
background-color: var(--ui-icon-button-solid-hover-surface, var(--_icon-button-solid-hover-surface, var(--ui-accent-hover)));
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
:scope[data-ui-icon-button-state~="variant=solid"][data-ui-icon-button-state~="tone=accent"]:hover:enabled:not([aria-disabled="true"]),
|
|
293
|
+
:scope[data-ui-icon-button-state~="variant=solid"][data-ui-icon-button-state~="tone=neutral"]:hover:enabled:not([aria-disabled="true"]) {
|
|
294
|
+
color: var(--ui-icon-button-solid-text, var(--_icon-button-solid-text, var(--ui-text-on-accent)));
|
|
275
295
|
}
|
|
276
296
|
|
|
277
297
|
:scope[data-ui-icon-button-state~="variant=ghost"][aria-expanded="true"]:enabled:not([aria-disabled="true"]) {
|
|
278
298
|
background-color: var(--ui-icon-button-active-surface, color-mix(in srgb, currentColor 16%, transparent));
|
|
279
|
-
color: var(--ui-icon-button-hover-text, var(--ui-text-primary));
|
|
299
|
+
color: var(--ui-icon-button-hover-text, var(--_icon-button-text, var(--ui-text-primary)));
|
|
300
|
+
box-shadow: var(--ui-pressed);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
/* Native toggle state persists after pointer release, including during loading. */
|
|
304
|
+
:scope[data-ui-icon-button-state~="variant=outline"][aria-pressed="true"]:enabled {
|
|
305
|
+
background-color: var(--ui-icon-button-active-surface, color-mix(in srgb, currentColor 12%, var(--ui-surface-default)));
|
|
306
|
+
background-image: none;
|
|
280
307
|
box-shadow: var(--ui-pressed);
|
|
281
308
|
}
|
|
282
309
|
|
|
@@ -309,6 +336,22 @@
|
|
|
309
336
|
box-shadow: var(--ui-focus-halo);
|
|
310
337
|
}
|
|
311
338
|
|
|
339
|
+
:scope[data-ui-icon-button-state~="variant=outline"][aria-pressed="true"]:enabled:focus-visible {
|
|
340
|
+
box-shadow:
|
|
341
|
+
var(--ui-pressed),
|
|
342
|
+
var(--ui-focus-halo);
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
@media (forced-colors: active) {
|
|
346
|
+
:scope[data-ui-icon-button-state~="variant=outline"][aria-pressed="true"]:enabled {
|
|
347
|
+
outline: var(--ui-focus-width) solid Highlight;
|
|
348
|
+
outline-offset: calc(-2 * var(--ui-focus-width));
|
|
349
|
+
}
|
|
350
|
+
:scope[data-ui-icon-button-state~="variant=outline"][aria-pressed="true"]:enabled:focus-visible {
|
|
351
|
+
outline-offset: var(--ui-focus-width);
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
|
|
312
355
|
/* Disabled is a flat neutral control, independent of the active variant's tone. */
|
|
313
356
|
:scope:disabled {
|
|
314
357
|
border-color: var(--ui-disabled-border);
|
|
@@ -349,6 +392,8 @@
|
|
|
349
392
|
@scope ([data-component~="ui-icon-button"]) to ([data-component]) {
|
|
350
393
|
/* This component's hooks style the element they are set on, and never a nested one. */
|
|
351
394
|
|
|
395
|
+
/* Omitted tone retains the existing accent solid; explicit neutral is additive. */
|
|
396
|
+
|
|
352
397
|
/* At rest an anticipatory button shows only its guide dot. The icon grows into place when
|
|
353
398
|
proximity, hover, or focus reveals it; the button's hit area and guide remain stable. */
|
|
354
399
|
|
|
@@ -368,9 +413,14 @@
|
|
|
368
413
|
@media (pointer: coarse) {
|
|
369
414
|
}
|
|
370
415
|
|
|
416
|
+
/* Native toggle state persists after pointer release, including during loading. */
|
|
417
|
+
|
|
371
418
|
@media (prefers-reduced-motion: reduce) {
|
|
372
419
|
}
|
|
373
420
|
|
|
421
|
+
@media (forced-colors: active) {
|
|
422
|
+
}
|
|
423
|
+
|
|
374
424
|
/* Disabled is a flat neutral control, independent of the active variant's tone. */
|
|
375
425
|
|
|
376
426
|
:where([data-slotted], [data-slotted] *):is(svg) {
|
package/vanilla/UiBadge.d.ts
CHANGED
|
@@ -6,7 +6,7 @@ export interface UiBadgeElement extends HTMLSpanElement {
|
|
|
6
6
|
removeEventListener<K extends keyof UiBadgeEventMap>(type: K, listener: (this: UiBadgeElement, event: UiBadgeEventMap[K]) => unknown, options?: boolean | EventListenerOptions): void;
|
|
7
7
|
}
|
|
8
8
|
export interface UiBadgeProps {
|
|
9
|
-
shape?: "pill" | "tag" | "dot" | "square" | null;
|
|
9
|
+
shape?: "pill" | "tag" | "dot" | "square" | "circle" | null;
|
|
10
10
|
size?: "xs" | "md" | null;
|
|
11
11
|
tone?: "neutral" | "accent" | "info" | "success" | "warning" | "danger" | null;
|
|
12
12
|
variant?: "solid" | "subtle" | "outline" | null;
|
package/vanilla/UiBadge.js
CHANGED
|
@@ -7,7 +7,7 @@ const T1 = ["",[]];
|
|
|
7
7
|
const T2 = ["",[]];
|
|
8
8
|
let P0, P1, P2;
|
|
9
9
|
const S = { n: [], t: [], f: import.meta.url, g: "ui-badge" };
|
|
10
|
-
const D = { props: { "shape": { "required":false,"values":["pill","tag","dot","square"],"default":"pill", c: checkFormat("keyword", keywordFormat), t: "keyword", j: 0, m: ["p",formatOf(keywordFormat),false] }, "size": { "required":false,"values":["xs","md"],"default":"md", c: checkFormat("keyword", keywordFormat), t: "keyword", j: 0, m: ["p",formatOf(keywordFormat),false] }, "tone": { "required":false,"values":["neutral","accent","info","success","warning","danger"],"default":"neutral", c: checkFormat("keyword", keywordFormat), t: "keyword", j: 0, m: ["p",formatOf(keywordFormat),false] }, "variant": { "required":false,"values":["solid","subtle","outline"],"default":"subtle", c: checkFormat("keyword", keywordFormat), t: "keyword", j: 0, m: ["p",formatOf(keywordFormat),false] } } };
|
|
10
|
+
const D = { props: { "shape": { "required":false,"values":["pill","tag","dot","square","circle"],"default":"pill", c: checkFormat("keyword", keywordFormat), t: "keyword", j: 0, m: ["p",formatOf(keywordFormat),false] }, "size": { "required":false,"values":["xs","md"],"default":"md", c: checkFormat("keyword", keywordFormat), t: "keyword", j: 0, m: ["p",formatOf(keywordFormat),false] }, "tone": { "required":false,"values":["neutral","accent","info","success","warning","danger"],"default":"neutral", c: checkFormat("keyword", keywordFormat), t: "keyword", j: 0, m: ["p",formatOf(keywordFormat),false] }, "variant": { "required":false,"values":["solid","subtle","outline"],"default":"subtle", c: checkFormat("keyword", keywordFormat), t: "keyword", j: 0, m: ["p",formatOf(keywordFormat),false] } } };
|
|
11
11
|
|
|
12
12
|
export function createUiBadge(options = {}, html) {
|
|
13
13
|
const { attributes = {}, children = [], slots = {}, ...componentProps } = options;
|
package/vanilla/UiContainer.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ export interface UiContainerElement extends HTMLDivElement {
|
|
|
6
6
|
removeEventListener<K extends keyof UiContainerEventMap>(type: K, listener: (this: UiContainerElement, event: UiContainerEventMap[K]) => unknown, options?: boolean | EventListenerOptions): void;
|
|
7
7
|
}
|
|
8
8
|
export interface UiContainerProps {
|
|
9
|
+
fill?: boolean | null;
|
|
9
10
|
gutters?: "s" | "m" | "l" | null;
|
|
10
11
|
measure?: "narrow" | "wide" | null;
|
|
11
12
|
attributes?: Readonly<Record<string, string | number | boolean | null | undefined>>;
|
package/vanilla/UiContainer.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
// Generated by HTML Next 1.0.0-alpha.35 for Vanilla DOM. Do not edit.
|
|
2
|
-
import { attachGeneratedController, buildTemplate, writeAttribute, dispose, formatOf, keywordFormat, hostState, acceptProps, manageProps, project, fillSlot, checkFormat } from "@nextwebwg/html-next/generated-runtime";
|
|
2
|
+
import { attachGeneratedController, buildTemplate, writeAttribute, dispose, formatOf, keywordFormat, hostState, acceptProps, manageProps, project, fillSlot, checkBoolean, checkFormat } from "@nextwebwg/html-next/generated-runtime";
|
|
3
3
|
import "../styles/ui-container.css";
|
|
4
4
|
|
|
5
5
|
const T0 = ["",[],4];
|
|
6
6
|
const T1 = ["",[]];
|
|
7
7
|
let P0, P1;
|
|
8
8
|
const S = { n: [], t: [], f: import.meta.url, g: "ui-container" };
|
|
9
|
-
const D = { props: { "gutters": { "required":false,"values":["s","m","l"], c: checkFormat("keyword", keywordFormat), t: "keyword", j: 0, m: ["p",formatOf(keywordFormat),false] }, "measure": { "required":false,"values":["narrow","wide"], c: checkFormat("keyword", keywordFormat), t: "keyword", j: 0, m: ["p",formatOf(keywordFormat),false] } } };
|
|
9
|
+
const D = { props: { "fill": { "required":false,"default":false, c: checkBoolean, t: "boolean", j: 0, m: "b" }, "gutters": { "required":false,"values":["s","m","l"], c: checkFormat("keyword", keywordFormat), t: "keyword", j: 0, m: ["p",formatOf(keywordFormat),false] }, "measure": { "required":false,"values":["narrow","wide"], c: checkFormat("keyword", keywordFormat), t: "keyword", j: 0, m: ["p",formatOf(keywordFormat),false] } } };
|
|
10
10
|
|
|
11
11
|
export function createUiContainer(options = {}, html) {
|
|
12
12
|
const { attributes = {}, children = [], slots = {}, ...componentProps } = options;
|
|
@@ -17,7 +17,7 @@ export function createUiContainer(options = {}, html) {
|
|
|
17
17
|
}
|
|
18
18
|
element.setAttribute("data-component", "ui-container");
|
|
19
19
|
element.append((P0 ??= buildTemplate(T0)).cloneNode(true));
|
|
20
|
-
const v = [null, null];
|
|
20
|
+
const v = [null, null, null];
|
|
21
21
|
const B = acceptProps(element, D, S.n, v, componentProps, [], html);
|
|
22
22
|
const m1 = (d) => {
|
|
23
23
|
const n = (P1 ??= buildTemplate(T1)).cloneNode(true);
|
|
@@ -28,8 +28,8 @@ export function createUiContainer(options = {}, html) {
|
|
|
28
28
|
const p1 = (r, c, d) => {
|
|
29
29
|
};
|
|
30
30
|
const p0 = (r, c, d) => {
|
|
31
|
-
if (c &
|
|
32
|
-
const x0 = hostState(["measure","gutters"], [v[
|
|
31
|
+
if (c & 7) {
|
|
32
|
+
const x0 = hostState(["measure","fill","gutters"], [v[2], v[0], v[1]]);
|
|
33
33
|
const s0 = x0;
|
|
34
34
|
if (s0 !== r.v0) writeAttribute(r.n, "data-ui-container-state", (r.v0 = s0) === "" ? null : s0);
|
|
35
35
|
}
|
|
@@ -14,6 +14,7 @@ export interface UiIconButtonProps {
|
|
|
14
14
|
pending?: boolean | null;
|
|
15
15
|
round?: boolean | null;
|
|
16
16
|
size?: "sm" | "md" | "lg" | null;
|
|
17
|
+
tone?: "accent" | "neutral" | null;
|
|
17
18
|
variant?: "ghost" | "outline" | "solid" | null;
|
|
18
19
|
attributes?: Readonly<Record<string, string | number | boolean | null | undefined>>;
|
|
19
20
|
children?: readonly (string | Node)[];
|
package/vanilla/UiIconButton.js
CHANGED
|
@@ -8,7 +8,7 @@ const T1 = ["ui-spinner",["size","sm"]];
|
|
|
8
8
|
const T2 = ["",[]];
|
|
9
9
|
let P0, P1, P2;
|
|
10
10
|
const S = { n: [], t: [], f: import.meta.url, g: "ui-icon-button" };
|
|
11
|
-
const D = { props: { "anticipatory": { "required":false,"default":false, c: checkBoolean, t: "boolean", j: 0, m: "b" }, "disabled": { "required":false,"default":false, c: checkBoolean, t: "boolean", j: 0, m: "b" }, "label": { "required":false, c: checkString, t: "string", j: 0, m: "s" }, "loading": { "required":false,"default":false, c: checkBoolean, t: "boolean", j: 0, m: "b" }, "matchButton": { "required":false,"default":false, c: checkBoolean, t: "boolean", j: 0, m: "b" }, "pending": { "required":false,"default":false, c: checkBoolean, t: "boolean", j: 0, m: "b" }, "round": { "required":false,"default":false, c: checkBoolean, t: "boolean", j: 0, m: "b" }, "size": { "required":false,"values":["sm","md","lg"],"default":"md", c: checkFormat("keyword", keywordFormat), t: "keyword", j: 0, m: ["p",formatOf(keywordFormat),false] }, "variant": { "required":false,"values":["ghost","outline","solid"],"default":"ghost", c: checkFormat("keyword", keywordFormat), t: "keyword", j: 0, m: ["p",formatOf(keywordFormat),false] } } };
|
|
11
|
+
const D = { props: { "anticipatory": { "required":false,"default":false, c: checkBoolean, t: "boolean", j: 0, m: "b" }, "disabled": { "required":false,"default":false, c: checkBoolean, t: "boolean", j: 0, m: "b" }, "label": { "required":false, c: checkString, t: "string", j: 0, m: "s" }, "loading": { "required":false,"default":false, c: checkBoolean, t: "boolean", j: 0, m: "b" }, "matchButton": { "required":false,"default":false, c: checkBoolean, t: "boolean", j: 0, m: "b" }, "pending": { "required":false,"default":false, c: checkBoolean, t: "boolean", j: 0, m: "b" }, "round": { "required":false,"default":false, c: checkBoolean, t: "boolean", j: 0, m: "b" }, "size": { "required":false,"values":["sm","md","lg"],"default":"md", c: checkFormat("keyword", keywordFormat), t: "keyword", j: 0, m: ["p",formatOf(keywordFormat),false] }, "tone": { "required":false,"values":["accent","neutral"], c: checkFormat("keyword", keywordFormat), t: "keyword", j: 0, m: ["p",formatOf(keywordFormat),false] }, "variant": { "required":false,"values":["ghost","outline","solid"],"default":"ghost", c: checkFormat("keyword", keywordFormat), t: "keyword", j: 0, m: ["p",formatOf(keywordFormat),false] } } };
|
|
12
12
|
const C = (host) => controller.default(host);
|
|
13
13
|
|
|
14
14
|
export function createUiIconButton(options = {}, html) {
|
|
@@ -21,7 +21,7 @@ export function createUiIconButton(options = {}, html) {
|
|
|
21
21
|
if (!element.hasAttribute("type")) element.setAttribute("type", "button");
|
|
22
22
|
element.setAttribute("data-component", "ui-icon-button");
|
|
23
23
|
element.append((P0 ??= buildTemplate(T0)).cloneNode(true));
|
|
24
|
-
const v = [null, null, null, null, null, null, null, null, null];
|
|
24
|
+
const v = [null, null, null, null, null, null, null, null, null, null];
|
|
25
25
|
const B = acceptProps(element, D, S.n, v, componentProps, ["matchButton"], html);
|
|
26
26
|
const m1 = (d) => {
|
|
27
27
|
const n = (P1 ??= buildTemplate(T1)).cloneNode(true);
|
|
@@ -67,8 +67,8 @@ export function createUiIconButton(options = {}, html) {
|
|
|
67
67
|
const s4 = toAttribute(x4, "aria-busy");
|
|
68
68
|
if (s4 !== r.v4) writeAttribute(r.n, "aria-busy", r.v4 = s4);
|
|
69
69
|
}
|
|
70
|
-
if (c &
|
|
71
|
-
const x5 = hostState(["anticipatory","variant","loading","pending","size","matchButton","round"], [v[0], v[
|
|
70
|
+
if (c & 1017) {
|
|
71
|
+
const x5 = hostState(["tone","anticipatory","variant","loading","pending","size","matchButton","round"], [v[8], v[0], v[9], v[3], v[5], v[7], v[4], v[6]]);
|
|
72
72
|
const s5 = x5;
|
|
73
73
|
if (s5 !== r.v5) writeAttribute(r.n, "data-ui-icon-button-state", (r.v5 = s5) === "" ? null : s5);
|
|
74
74
|
}
|
package/vue/UiBadge.d.ts
CHANGED
|
@@ -7,7 +7,7 @@ type __VLS_Slots = {} & {
|
|
|
7
7
|
};
|
|
8
8
|
declare const __VLS_base: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
|
9
9
|
shape: {
|
|
10
|
-
type: PropType<"pill" | "tag" | "dot" | "square" | null>;
|
|
10
|
+
type: PropType<"pill" | "tag" | "dot" | "square" | "circle" | null>;
|
|
11
11
|
default: string;
|
|
12
12
|
};
|
|
13
13
|
size: {
|
|
@@ -24,7 +24,7 @@ declare const __VLS_base: import("vue").DefineComponent<import("vue").ExtractPro
|
|
|
24
24
|
};
|
|
25
25
|
}>, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
|
26
26
|
shape: {
|
|
27
|
-
type: PropType<"pill" | "tag" | "dot" | "square" | null>;
|
|
27
|
+
type: PropType<"pill" | "tag" | "dot" | "square" | "circle" | null>;
|
|
28
28
|
default: string;
|
|
29
29
|
};
|
|
30
30
|
size: {
|
|
@@ -40,7 +40,7 @@ declare const __VLS_base: import("vue").DefineComponent<import("vue").ExtractPro
|
|
|
40
40
|
default: string;
|
|
41
41
|
};
|
|
42
42
|
}>> & Readonly<{}>, {
|
|
43
|
-
shape: "dot" | "tag" | "square" | "pill" | null;
|
|
43
|
+
shape: "circle" | "dot" | "tag" | "square" | "pill" | null;
|
|
44
44
|
size: "xs" | "md" | null;
|
|
45
45
|
tone: "info" | "neutral" | "accent" | "success" | "warning" | "danger" | null;
|
|
46
46
|
variant: "solid" | "subtle" | "outline" | null;
|
package/vue/UiBadge.vue
CHANGED
|
@@ -13,8 +13,8 @@ const propValidityContract = {
|
|
|
13
13
|
required: false,
|
|
14
14
|
target: { attribute: 'shape' },
|
|
15
15
|
description:
|
|
16
|
-
'Silhouette. pill is rounded at both ends; tag is a pointed label. dot is a compact circular signal with visually hidden text: include a state label, or set\n aria-hidden when the surrounding control already names that state. square is a fixed rounded square for an icon or single glyph beside a heading; hide a\n decorative icon when adjacent words name it.',
|
|
17
|
-
values: ['pill', 'tag', 'dot', 'square'],
|
|
16
|
+
'Silhouette. pill is rounded at both ends; tag is a pointed label. dot is a compact circular signal with visually hidden text: include a state label, or set\n aria-hidden when the surrounding control already names that state. square is a fixed rounded square for an icon or single glyph beside a heading; hide a\n decorative icon when adjacent words name it. circle frames a visible single glyph or icon in a fixed circle, centered in both directions.',
|
|
17
|
+
values: ['pill', 'tag', 'dot', 'square', 'circle'],
|
|
18
18
|
default: 'pill',
|
|
19
19
|
},
|
|
20
20
|
size: {
|
|
@@ -22,7 +22,7 @@ const propValidityContract = {
|
|
|
22
22
|
required: false,
|
|
23
23
|
target: { attribute: 'size' },
|
|
24
24
|
description:
|
|
25
|
-
'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.',
|
|
25
|
+
'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. A circle is\n 16px at xs and 24px at md.',
|
|
26
26
|
values: ['xs', 'md'],
|
|
27
27
|
default: 'md',
|
|
28
28
|
},
|
|
@@ -48,7 +48,7 @@ const propValidityContract = {
|
|
|
48
48
|
} as const
|
|
49
49
|
const props = defineProps({
|
|
50
50
|
shape: {
|
|
51
|
-
type: null as unknown as PropType<'pill' | 'tag' | 'dot' | 'square' | null>,
|
|
51
|
+
type: null as unknown as PropType<'pill' | 'tag' | 'dot' | 'square' | 'circle' | null>,
|
|
52
52
|
default: 'pill',
|
|
53
53
|
},
|
|
54
54
|
size: { type: null as unknown as PropType<'xs' | 'md' | null>, default: 'md' },
|
|
@@ -70,13 +70,13 @@ const acceptedProps: Record<string, unknown> = {
|
|
|
70
70
|
variant: 'subtle',
|
|
71
71
|
}
|
|
72
72
|
const checkedProps = computed(() => ({
|
|
73
|
-
shape: checkedProp<'pill' | 'tag' | 'dot' | 'square'>(
|
|
73
|
+
shape: checkedProp<'pill' | 'tag' | 'dot' | 'square' | 'circle'>(
|
|
74
74
|
props['shape'],
|
|
75
75
|
{ kind: 'terminal', name: 'keyword' },
|
|
76
76
|
false,
|
|
77
77
|
'shape',
|
|
78
78
|
acceptedProps,
|
|
79
|
-
) as 'pill' | 'tag' | 'dot' | 'square',
|
|
79
|
+
) as 'pill' | 'tag' | 'dot' | 'square' | 'circle',
|
|
80
80
|
size: checkedProp<'xs' | 'md'>(
|
|
81
81
|
props['size'],
|
|
82
82
|
{ kind: 'terminal', name: 'keyword' },
|
|
@@ -191,6 +191,10 @@ const hostState = computed(() =>
|
|
|
191
191
|
syntax: "*";
|
|
192
192
|
inherits: false;
|
|
193
193
|
}
|
|
194
|
+
@property --ui-badge-circle-size {
|
|
195
|
+
syntax: "*";
|
|
196
|
+
inherits: false;
|
|
197
|
+
}
|
|
194
198
|
@property --ui-badge-dot-size {
|
|
195
199
|
syntax: "*";
|
|
196
200
|
inherits: false;
|
|
@@ -490,6 +494,40 @@ const hostState = computed(() =>
|
|
|
490
494
|
display: none;
|
|
491
495
|
}
|
|
492
496
|
|
|
497
|
+
/* A visible glyph needs fixed geometry, unlike a content-sized pill or a hidden-label dot. */
|
|
498
|
+
[data-component~="ui-badge"][data-ui-badge-state~="shape=circle"] {
|
|
499
|
+
--_badge-circle-size: var(--ui-badge-circle-size, calc(var(--ui-space-3) * 2));
|
|
500
|
+
display: inline-flex;
|
|
501
|
+
flex: none;
|
|
502
|
+
inline-size: var(--_badge-circle-size);
|
|
503
|
+
block-size: var(--_badge-circle-size);
|
|
504
|
+
min-inline-size: var(--_badge-circle-size);
|
|
505
|
+
min-block-size: var(--_badge-circle-size);
|
|
506
|
+
padding: 0;
|
|
507
|
+
border-radius: var(--ui-radius-round);
|
|
508
|
+
text-box-trim: none;
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
[data-component~="ui-badge"][data-ui-badge-state~="shape=circle"][data-ui-badge-state~="size=xs"] {
|
|
512
|
+
--_badge-circle-size: var(--ui-badge-circle-size, var(--ui-space-4));
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
[data-component~="ui-badge"][data-ui-badge-state~="shape=circle"] .label {
|
|
516
|
+
display: inline-flex;
|
|
517
|
+
align-items: center;
|
|
518
|
+
justify-content: center;
|
|
519
|
+
line-height: 1;
|
|
520
|
+
text-box-trim: none;
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
[data-component~="ui-badge"][data-ui-badge-state~="shape=circle"] .label :slotted(svg) {
|
|
524
|
+
margin-inline-end: 0;
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
[data-component~="ui-badge"][data-ui-badge-state~="shape=circle"] .label:empty {
|
|
528
|
+
display: none;
|
|
529
|
+
}
|
|
530
|
+
|
|
493
531
|
/* A dot uses the badge's tone recipe; only its silhouette and visible label change. */
|
|
494
532
|
[data-component~="ui-badge"][data-ui-badge-state~="shape=dot"] {
|
|
495
533
|
position: relative;
|
package/vue/UiContainer.d.ts
CHANGED
|
@@ -4,6 +4,10 @@ type __VLS_Slots = {} & {
|
|
|
4
4
|
default?: (props: typeof __VLS_1) => any;
|
|
5
5
|
};
|
|
6
6
|
declare const __VLS_base: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
|
7
|
+
fill: {
|
|
8
|
+
type: PropType<boolean | null>;
|
|
9
|
+
default: boolean;
|
|
10
|
+
};
|
|
7
11
|
gutters: {
|
|
8
12
|
type: PropType<"s" | "m" | "l" | null>;
|
|
9
13
|
default: null;
|
|
@@ -13,6 +17,10 @@ declare const __VLS_base: import("vue").DefineComponent<import("vue").ExtractPro
|
|
|
13
17
|
default: null;
|
|
14
18
|
};
|
|
15
19
|
}>, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
|
20
|
+
fill: {
|
|
21
|
+
type: PropType<boolean | null>;
|
|
22
|
+
default: boolean;
|
|
23
|
+
};
|
|
16
24
|
gutters: {
|
|
17
25
|
type: PropType<"s" | "m" | "l" | null>;
|
|
18
26
|
default: null;
|
|
@@ -22,6 +30,7 @@ declare const __VLS_base: import("vue").DefineComponent<import("vue").ExtractPro
|
|
|
22
30
|
default: null;
|
|
23
31
|
};
|
|
24
32
|
}>> & Readonly<{}>, {
|
|
33
|
+
fill: boolean | null;
|
|
25
34
|
gutters: "s" | "m" | "l" | null;
|
|
26
35
|
measure: "narrow" | "wide" | null;
|
|
27
36
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
package/vue/UiContainer.vue
CHANGED
|
@@ -8,6 +8,14 @@ defineOptions({ inheritAttrs: false })
|
|
|
8
8
|
|
|
9
9
|
const propValidityContract = {
|
|
10
10
|
props: {
|
|
11
|
+
fill: {
|
|
12
|
+
type: { kind: 'terminal', name: 'boolean' },
|
|
13
|
+
required: false,
|
|
14
|
+
target: { attribute: 'fill' },
|
|
15
|
+
description:
|
|
16
|
+
'Keeps the readable width while filling available layout space. Uses a flex column so scrolling children can shrink inside a bounded flex or grid parent.\n Omit it to keep the usual block layout.',
|
|
17
|
+
default: false,
|
|
18
|
+
},
|
|
11
19
|
gutters: {
|
|
12
20
|
type: { kind: 'terminal', name: 'keyword' },
|
|
13
21
|
required: false,
|
|
@@ -27,11 +35,19 @@ const propValidityContract = {
|
|
|
27
35
|
},
|
|
28
36
|
} as const
|
|
29
37
|
const props = defineProps({
|
|
38
|
+
fill: { type: null as unknown as PropType<boolean | null>, default: false },
|
|
30
39
|
gutters: { type: null as unknown as PropType<'s' | 'm' | 'l' | null>, default: null },
|
|
31
40
|
measure: { type: null as unknown as PropType<'narrow' | 'wide' | null>, default: null },
|
|
32
41
|
})
|
|
33
|
-
const acceptedProps: Record<string, unknown> = { gutters: null, measure: null }
|
|
42
|
+
const acceptedProps: Record<string, unknown> = { fill: false, gutters: null, measure: null }
|
|
34
43
|
const checkedProps = computed(() => ({
|
|
44
|
+
fill: checkedProp<boolean>(
|
|
45
|
+
props['fill'],
|
|
46
|
+
{ kind: 'terminal', name: 'boolean' },
|
|
47
|
+
false,
|
|
48
|
+
'fill',
|
|
49
|
+
acceptedProps,
|
|
50
|
+
) as boolean,
|
|
35
51
|
gutters: checkedProp<'s' | 'm' | 'l'>(
|
|
36
52
|
props['gutters'],
|
|
37
53
|
{ kind: 'terminal', name: 'keyword' },
|
|
@@ -108,6 +124,7 @@ const hostState = computed(() =>
|
|
|
108
124
|
checkedProps.value.measure && 'measure',
|
|
109
125
|
checkedProps.value.measure != null
|
|
110
126
|
&& `measure=${encodeURIComponent(checkedProps.value.measure)}`,
|
|
127
|
+
checkedProps.value.fill && 'fill',
|
|
111
128
|
checkedProps.value.gutters && 'gutters',
|
|
112
129
|
checkedProps.value.gutters != null
|
|
113
130
|
&& `gutters=${encodeURIComponent(checkedProps.value.gutters)}`,
|
|
@@ -120,6 +137,7 @@ const hostState = computed(() =>
|
|
|
120
137
|
data-component="ui-container"
|
|
121
138
|
v-bind="nativeAttrs($attrs)"
|
|
122
139
|
v-prop-validity="{ contract: propValidityContract, values: { ...props } }"
|
|
140
|
+
:data-fill="reflectedProp('fill', 'fill', checkedProps.fill, undefined, false)"
|
|
123
141
|
:data-gutters="reflectedProp('gutters', 'gutters', checkedProps.gutters, undefined, false)"
|
|
124
142
|
:data-measure="reflectedProp('measure', 'measure', checkedProps.measure, undefined, false)"
|
|
125
143
|
:data-ui-container-state="hostState || undefined"
|
|
@@ -152,6 +170,14 @@ const hostState = computed(() =>
|
|
|
152
170
|
[data-component~="ui-container"][data-ui-container-state~="measure=narrow"] {
|
|
153
171
|
--_container-measure: 45ch;
|
|
154
172
|
}
|
|
173
|
+
[data-component~="ui-container"][data-ui-container-state~="fill"] {
|
|
174
|
+
box-sizing: border-box;
|
|
175
|
+
display: flex;
|
|
176
|
+
flex-direction: column;
|
|
177
|
+
flex: 1;
|
|
178
|
+
min-inline-size: 0;
|
|
179
|
+
min-block-size: 0;
|
|
180
|
+
}
|
|
155
181
|
[data-component~="ui-container"][data-ui-container-state~="measure=wide"] {
|
|
156
182
|
--_container-measure: 80ch;
|
|
157
183
|
}
|
package/vue/UiIconButton.d.ts
CHANGED
|
@@ -36,6 +36,10 @@ declare const __VLS_base: import("vue").DefineComponent<import("vue").ExtractPro
|
|
|
36
36
|
type: PropType<"sm" | "md" | "lg" | null>;
|
|
37
37
|
default: string;
|
|
38
38
|
};
|
|
39
|
+
tone: {
|
|
40
|
+
type: PropType<"accent" | "neutral" | null>;
|
|
41
|
+
default: null;
|
|
42
|
+
};
|
|
39
43
|
variant: {
|
|
40
44
|
type: PropType<"ghost" | "outline" | "solid" | null>;
|
|
41
45
|
default: string;
|
|
@@ -73,6 +77,10 @@ declare const __VLS_base: import("vue").DefineComponent<import("vue").ExtractPro
|
|
|
73
77
|
type: PropType<"sm" | "md" | "lg" | null>;
|
|
74
78
|
default: string;
|
|
75
79
|
};
|
|
80
|
+
tone: {
|
|
81
|
+
type: PropType<"accent" | "neutral" | null>;
|
|
82
|
+
default: null;
|
|
83
|
+
};
|
|
76
84
|
variant: {
|
|
77
85
|
type: PropType<"ghost" | "outline" | "solid" | null>;
|
|
78
86
|
default: string;
|
|
@@ -81,6 +89,7 @@ declare const __VLS_base: import("vue").DefineComponent<import("vue").ExtractPro
|
|
|
81
89
|
label: string | null;
|
|
82
90
|
round: boolean | null;
|
|
83
91
|
size: "sm" | "md" | "lg" | null;
|
|
92
|
+
tone: "neutral" | "accent" | null;
|
|
84
93
|
variant: "solid" | "outline" | "ghost" | null;
|
|
85
94
|
disabled: boolean | null;
|
|
86
95
|
loading: boolean | null;
|