@threadlabs/looma 0.14.2 → 0.14.4
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-meter/ui-meter.html +83 -0
- package/components/ui-text/ui-text.html +11 -2
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/styles/ui-meter.css +90 -0
- package/styles/ui-text.css +10 -0
- package/vanilla/UiMeter.d.ts +1 -0
- package/vanilla/UiMeter.js +1 -1
- package/vanilla/UiText.d.ts +1 -1
- package/vanilla/UiText.js +1 -1
- package/vue/UiMeter.d.ts +2 -0
- package/vue/UiMeter.vue +85 -0
- package/vue/UiText.d.ts +2 -2
- package/vue/UiText.vue +9 -1
- package/vue/chunks/UiMeter.js +7 -1
- package/vue/chunks/UiText.js +1 -1
- package/vue/components.css +107 -29
package/package.json
CHANGED
package/styles/ui-meter.css
CHANGED
|
@@ -55,12 +55,90 @@
|
|
|
55
55
|
--_meter-fill: var(--ui-danger-solid);
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
+
/* Segments: the track and its fill show through a mask of equal segments with a gap between them.
|
|
59
|
+
A mask over the whole meter, rather than one element per segment, because the expression
|
|
60
|
+
language has no range to render N elements from, and one mask lines the fill up with the track
|
|
61
|
+
for free. Each period is a segment and the gap after it; N periods span the track plus one
|
|
62
|
+
trailing gap, so the segments sit symmetrically and right to left needs nothing of its own.
|
|
63
|
+
The count arrives as an attribute, not an inline custom property (which would add a style
|
|
64
|
+
attribute to every meter), so a continuous meter renders exactly as before, and the rules below
|
|
65
|
+
turn it into a number. That caps it at 12, until attr() with a type reads any count in every engine. */
|
|
66
|
+
:scope[data-ui-meter-segments="2"] {
|
|
67
|
+
--_segments: 2;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
:scope[data-ui-meter-segments="3"] {
|
|
71
|
+
--_segments: 3;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
:scope[data-ui-meter-segments="4"] {
|
|
75
|
+
--_segments: 4;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
:scope[data-ui-meter-segments="5"] {
|
|
79
|
+
--_segments: 5;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
:scope[data-ui-meter-segments="6"] {
|
|
83
|
+
--_segments: 6;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
:scope[data-ui-meter-segments="7"] {
|
|
87
|
+
--_segments: 7;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
:scope[data-ui-meter-segments="8"] {
|
|
91
|
+
--_segments: 8;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
:scope[data-ui-meter-segments="9"] {
|
|
95
|
+
--_segments: 9;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
:scope[data-ui-meter-segments="10"] {
|
|
99
|
+
--_segments: 10;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
:scope[data-ui-meter-segments="11"] {
|
|
103
|
+
--_segments: 11;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
:scope[data-ui-meter-segments="12"] {
|
|
107
|
+
--_segments: 12;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
:scope[data-ui-meter-segments] {
|
|
111
|
+
--_meter-gap: var(--ui-space-1);
|
|
112
|
+
--_meter-period: calc((100% + var(--_meter-gap)) / var(--_segments));
|
|
113
|
+
--_meter-segment: calc(var(--_meter-period) - var(--_meter-gap));
|
|
114
|
+
|
|
115
|
+
mask-image: repeating-linear-gradient(to right, #000 0 var(--_meter-segment), transparent 0 var(--_meter-period));
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
:scope[data-ui-meter-state~="size=sm"][data-ui-meter-segments] {
|
|
119
|
+
--_meter-gap: var(--ui-space-0-5);
|
|
120
|
+
}
|
|
121
|
+
|
|
58
122
|
/* Forced colours drop backgrounds: draw the fill in the text colour inside the outlined track. */
|
|
59
123
|
@media (forced-colors: active) {
|
|
60
124
|
.fill {
|
|
61
125
|
forced-color-adjust: none;
|
|
62
126
|
background: CanvasText;
|
|
63
127
|
}
|
|
128
|
+
|
|
129
|
+
/* The mask clips the track's outline, so each segment draws its own: the inset shadow draws the
|
|
130
|
+
top and bottom edges and the gradient the ends. */
|
|
131
|
+
:scope[data-ui-meter-segments] {
|
|
132
|
+
forced-color-adjust: none;
|
|
133
|
+
background: repeating-linear-gradient(
|
|
134
|
+
to right,
|
|
135
|
+
CanvasText 0 1px,
|
|
136
|
+
Canvas 0 calc(var(--_meter-segment) - 1px),
|
|
137
|
+
CanvasText 0 var(--_meter-segment),
|
|
138
|
+
transparent 0 var(--_meter-period)
|
|
139
|
+
);
|
|
140
|
+
box-shadow: inset 0 0 0 1px CanvasText;
|
|
141
|
+
}
|
|
64
142
|
}
|
|
65
143
|
|
|
66
144
|
/* A component that sets its display still honours the hidden attribute on its root. */
|
|
@@ -73,8 +151,20 @@
|
|
|
73
151
|
quiet border colour, so an empty meter still shows; every tone's fill keeps 3:1 against the
|
|
74
152
|
track and the page. */
|
|
75
153
|
|
|
154
|
+
/* Segments: the track and its fill show through a mask of equal segments with a gap between them.
|
|
155
|
+
A mask over the whole meter, rather than one element per segment, because the expression
|
|
156
|
+
language has no range to render N elements from, and one mask lines the fill up with the track
|
|
157
|
+
for free. Each period is a segment and the gap after it; N periods span the track plus one
|
|
158
|
+
trailing gap, so the segments sit symmetrically and right to left needs nothing of its own.
|
|
159
|
+
The count arrives as an attribute, not an inline custom property (which would add a style
|
|
160
|
+
attribute to every meter), so a continuous meter renders exactly as before, and the rules below
|
|
161
|
+
turn it into a number. That caps it at 12, until attr() with a type reads any count in every engine. */
|
|
162
|
+
|
|
76
163
|
/* Forced colours drop backgrounds: draw the fill in the text colour inside the outlined track. */
|
|
77
164
|
@media (forced-colors: active) {
|
|
165
|
+
|
|
166
|
+
/* The mask clips the track's outline, so each segment draws its own: the inset shadow draws the
|
|
167
|
+
top and bottom edges and the gradient the ends. */
|
|
78
168
|
}
|
|
79
169
|
|
|
80
170
|
/* A component that sets its display still honours the hidden attribute on its root. */
|
package/styles/ui-text.css
CHANGED
|
@@ -41,6 +41,14 @@
|
|
|
41
41
|
:scope[data-ui-text-state~="tone=success"] {
|
|
42
42
|
color: var(--ui-success);
|
|
43
43
|
}
|
|
44
|
+
/* The base info and warning colours fall short of 4.5:1 on sunken surfaces, so these use the
|
|
45
|
+
text-safe tokens a subtle badge sets its words in. */
|
|
46
|
+
:scope[data-ui-text-state~="tone=info"] {
|
|
47
|
+
color: var(--ui-info-subtle-text);
|
|
48
|
+
}
|
|
49
|
+
:scope[data-ui-text-state~="tone=warning"] {
|
|
50
|
+
color: var(--ui-warning-subtle-text);
|
|
51
|
+
}
|
|
44
52
|
|
|
45
53
|
:scope[data-ui-text-state~="weight=normal"] {
|
|
46
54
|
font-weight: var(--ui-font-normal);
|
|
@@ -83,6 +91,8 @@
|
|
|
83
91
|
@scope ([data-component~="ui-text"]) to ([data-component]) {
|
|
84
92
|
/* Running text, set on the type scale and in a tone that says what it is, so a view never styles
|
|
85
93
|
text of its own. The root is a paragraph unless as= names a span, div, small, strong, or label. */
|
|
94
|
+
/* The base info and warning colours fall short of 4.5:1 on sunken surfaces, so these use the
|
|
95
|
+
text-safe tokens a subtle badge sets its words in. */
|
|
86
96
|
|
|
87
97
|
/* A link in running text is underlined, so it stands apart from the words around it by more than
|
|
88
98
|
colour. */
|
package/vanilla/UiMeter.d.ts
CHANGED
|
@@ -8,6 +8,7 @@ export interface UiMeterElement extends HTMLSpanElement {
|
|
|
8
8
|
export interface UiMeterProps {
|
|
9
9
|
label?: string | null;
|
|
10
10
|
max?: number | null;
|
|
11
|
+
segments?: number | null;
|
|
11
12
|
size?: "sm" | "md" | null;
|
|
12
13
|
tone?: "neutral" | "accent" | "info" | "success" | "warning" | "danger" | null;
|
|
13
14
|
value?: number | null;
|
package/vanilla/UiMeter.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { manageComponentLifecycle } from "@nextwebwg/html-next/runtime";
|
|
3
3
|
import "../styles/ui-meter.css";
|
|
4
4
|
|
|
5
|
-
const definition = {...{"contract":{"tag":"ui-meter","props":{"label":{"type":"string","required":false,"target":{"attribute":"label"},"default":""},"max":{"type":"number","required":false,"target":{"attribute":"aria-valuemax"},"default":1},"size":{"type":{"enum":["sm","md"]},"required":false,"target":{"attribute":"size"},"default":"md"},"tone":{"type":{"enum":["neutral","accent","info","success","warning","danger"]},"required":false,"target":{"attribute":"tone"},"default":"neutral"},"value":{"type":"number","required":false,"target":{"attribute":"value"},"default":0},"valueText":{"type":"string","required":false,"target":{"attribute":"valuetext"},"default":""}}},"template":{"kind":"element","name":"span","attributes":[{"kind":"literal","name":"role","value":"meter"},{"kind":"literal","name":"aria-valuemin","value":"0"},{"kind":"attribute","name":"aria-valuemax","expression":"max","expressionPlan":{"source":"max","ast":{"kind":"id","name":"max"},"dependencies":["max"]}},{"kind":"attribute","name":"aria-valuenow","expression":"amount","expressionPlan":{"source":"amount","ast":{"kind":"id","name":"amount"},"dependencies":["amount"]}},{"kind":"attribute","name":"aria-valuetext","expression":"{ true: valueText, false: format('%s%', whole) }[format('%s', valueText != '')]","expressionPlan":{"source":"{ true: valueText, false: format('%s%', whole) }[format('%s', valueText != '')]","ast":{"kind":"index","object":{"kind":"object","pairs":[{"key":"true","value":{"kind":"id","name":"valueText"}},{"key":"false","value":{"kind":"call","fn":"format","args":[{"kind":"literal","value":"%s%"},{"kind":"id","name":"whole"}]}}]},"index":{"kind":"call","fn":"format","args":[{"kind":"literal","value":"%s"},{"kind":"binary","op":"!=","left":{"kind":"id","name":"valueText"},"right":{"kind":"literal","value":""}}]}},"dependencies":["valueText","whole"]}},{"kind":"attribute","name":"aria-label","expression":"{ true: label, false: null }[format('%s', label != '')]","expressionPlan":{"source":"{ true: label, false: null }[format('%s', label != '')]","ast":{"kind":"index","object":{"kind":"object","pairs":[{"key":"true","value":{"kind":"id","name":"label"}},{"key":"false","value":{"kind":"literal","value":null}}]},"index":{"kind":"call","fn":"format","args":[{"kind":"literal","value":"%s"},{"kind":"binary","op":"!=","left":{"kind":"id","name":"label"},"right":{"kind":"literal","value":""}}]}},"dependencies":["label"]}}],"children":[{"kind":"element","name":"span","attributes":[{"kind":"literal","name":"class","value":"fill"},{"kind":"attribute","name":"inline-size","expression":"format('%s%', percent)","expressionPlan":{"source":"format('%s%', percent)","ast":{"kind":"call","fn":"format","args":[{"kind":"literal","value":"%s%"},{"kind":"id","name":"percent"}]},"dependencies":["percent"]},"target":"style"}],"children":[]}]},"declarations":[{"kind":"computed","name":"amount","expression":{"source":"clamp(0, value, max)","ast":{"kind":"call","fn":"clamp","args":[{"kind":"literal","value":0},{"kind":"id","name":"value"},{"kind":"id","name":"max"}]},"dependencies":["max","value"]}},{"kind":"computed","name":"percent","expression":{"source":"{ true: amount / max * 100, false: 0 }[format('%s', max > 0)]","ast":{"kind":"index","object":{"kind":"object","pairs":[{"key":"true","value":{"kind":"binary","op":"*","left":{"kind":"binary","op":"/","left":{"kind":"id","name":"amount"},"right":{"kind":"id","name":"max"}},"right":{"kind":"literal","value":100}}},{"key":"false","value":{"kind":"literal","value":0}}]},"index":{"kind":"call","fn":"format","args":[{"kind":"literal","value":"%s"},{"kind":"binary","op":">","left":{"kind":"id","name":"max"},"right":{"kind":"literal","value":0}}]}},"dependencies":["amount","max"]}},{"kind":"computed","name":"whole","expression":{"source":"percent + 0.5 - (percent + 0.5) % 1","ast":{"kind":"binary","op":"-","left":{"kind":"binary","op":"+","left":{"kind":"id","name":"percent"},"right":{"kind":"literal","value":0.5}},"right":{"kind":"binary","op":"%","left":{"kind":"binary","op":"+","left":{"kind":"id","name":"percent"},"right":{"kind":"literal","value":0.5}},"right":{"kind":"literal","value":1}}},"dependencies":["percent"]}}],"root":{"kind":"native","element":"span","choices":["span"]}},source:{file:import.meta.url},css:""};
|
|
5
|
+
const definition = {...{"contract":{"tag":"ui-meter","props":{"label":{"type":"string","required":false,"target":{"attribute":"label"},"default":""},"max":{"type":"number","required":false,"target":{"attribute":"aria-valuemax"},"default":1},"segments":{"type":"number","required":false,"target":{"attribute":"segments"},"default":0},"size":{"type":{"enum":["sm","md"]},"required":false,"target":{"attribute":"size"},"default":"md"},"tone":{"type":{"enum":["neutral","accent","info","success","warning","danger"]},"required":false,"target":{"attribute":"tone"},"default":"neutral"},"value":{"type":"number","required":false,"target":{"attribute":"value"},"default":0},"valueText":{"type":"string","required":false,"target":{"attribute":"valuetext"},"default":""}}},"template":{"kind":"element","name":"span","attributes":[{"kind":"literal","name":"role","value":"meter"},{"kind":"literal","name":"aria-valuemin","value":"0"},{"kind":"attribute","name":"aria-valuemax","expression":"max","expressionPlan":{"source":"max","ast":{"kind":"id","name":"max"},"dependencies":["max"]}},{"kind":"attribute","name":"aria-valuenow","expression":"amount","expressionPlan":{"source":"amount","ast":{"kind":"id","name":"amount"},"dependencies":["amount"]}},{"kind":"attribute","name":"aria-valuetext","expression":"{ true: valueText, false: format('%s%', whole) }[format('%s', valueText != '')]","expressionPlan":{"source":"{ true: valueText, false: format('%s%', whole) }[format('%s', valueText != '')]","ast":{"kind":"index","object":{"kind":"object","pairs":[{"key":"true","value":{"kind":"id","name":"valueText"}},{"key":"false","value":{"kind":"call","fn":"format","args":[{"kind":"literal","value":"%s%"},{"kind":"id","name":"whole"}]}}]},"index":{"kind":"call","fn":"format","args":[{"kind":"literal","value":"%s"},{"kind":"binary","op":"!=","left":{"kind":"id","name":"valueText"},"right":{"kind":"literal","value":""}}]}},"dependencies":["valueText","whole"]}},{"kind":"attribute","name":"aria-label","expression":"{ true: label, false: null }[format('%s', label != '')]","expressionPlan":{"source":"{ true: label, false: null }[format('%s', label != '')]","ast":{"kind":"index","object":{"kind":"object","pairs":[{"key":"true","value":{"kind":"id","name":"label"}},{"key":"false","value":{"kind":"literal","value":null}}]},"index":{"kind":"call","fn":"format","args":[{"kind":"literal","value":"%s"},{"kind":"binary","op":"!=","left":{"kind":"id","name":"label"},"right":{"kind":"literal","value":""}}]}},"dependencies":["label"]}},{"kind":"attribute","name":"data-ui-meter-segments","expression":"{ true: segments, false: null }[format('%s', segments > 1)]","expressionPlan":{"source":"{ true: segments, false: null }[format('%s', segments > 1)]","ast":{"kind":"index","object":{"kind":"object","pairs":[{"key":"true","value":{"kind":"id","name":"segments"}},{"key":"false","value":{"kind":"literal","value":null}}]},"index":{"kind":"call","fn":"format","args":[{"kind":"literal","value":"%s"},{"kind":"binary","op":">","left":{"kind":"id","name":"segments"},"right":{"kind":"literal","value":1}}]}},"dependencies":["segments"]}}],"children":[{"kind":"element","name":"span","attributes":[{"kind":"literal","name":"class","value":"fill"},{"kind":"attribute","name":"inline-size","expression":"format('%s%', percent)","expressionPlan":{"source":"format('%s%', percent)","ast":{"kind":"call","fn":"format","args":[{"kind":"literal","value":"%s%"},{"kind":"id","name":"percent"}]},"dependencies":["percent"]},"target":"style"}],"children":[]}]},"declarations":[{"kind":"computed","name":"amount","expression":{"source":"clamp(0, value, max)","ast":{"kind":"call","fn":"clamp","args":[{"kind":"literal","value":0},{"kind":"id","name":"value"},{"kind":"id","name":"max"}]},"dependencies":["max","value"]}},{"kind":"computed","name":"percent","expression":{"source":"{ true: amount / max * 100, false: 0 }[format('%s', max > 0)]","ast":{"kind":"index","object":{"kind":"object","pairs":[{"key":"true","value":{"kind":"binary","op":"*","left":{"kind":"binary","op":"/","left":{"kind":"id","name":"amount"},"right":{"kind":"id","name":"max"}},"right":{"kind":"literal","value":100}}},{"key":"false","value":{"kind":"literal","value":0}}]},"index":{"kind":"call","fn":"format","args":[{"kind":"literal","value":"%s"},{"kind":"binary","op":">","left":{"kind":"id","name":"max"},"right":{"kind":"literal","value":0}}]}},"dependencies":["amount","max"]}},{"kind":"computed","name":"whole","expression":{"source":"percent + 0.5 - (percent + 0.5) % 1","ast":{"kind":"binary","op":"-","left":{"kind":"binary","op":"+","left":{"kind":"id","name":"percent"},"right":{"kind":"literal","value":0.5}},"right":{"kind":"binary","op":"%","left":{"kind":"binary","op":"+","left":{"kind":"id","name":"percent"},"right":{"kind":"literal","value":0.5}},"right":{"kind":"literal","value":1}}},"dependencies":["percent"]}}],"root":{"kind":"native","element":"span","choices":["span"]}},source:{file:import.meta.url},css:""};
|
|
6
6
|
|
|
7
7
|
export function createUiMeter(options = {}) {
|
|
8
8
|
const { attributes = {}, children = [], slots = {}, ...componentProps } = options;
|
package/vanilla/UiText.d.ts
CHANGED
|
@@ -9,7 +9,7 @@ export interface UiTextProps {
|
|
|
9
9
|
align?: "start" | "center" | null;
|
|
10
10
|
as?: "p" | "span" | "div" | "small" | "strong" | "label" | null;
|
|
11
11
|
size?: "inherit" | "xs" | "sm" | "md" | "lg" | null;
|
|
12
|
-
tone?: "default" | "secondary" | "muted" | "accent" | "danger" | "success" | null;
|
|
12
|
+
tone?: "default" | "secondary" | "muted" | "accent" | "danger" | "success" | "info" | "warning" | null;
|
|
13
13
|
truncate?: boolean | null;
|
|
14
14
|
variant?: "body" | "eyebrow" | "code" | null;
|
|
15
15
|
weight?: "inherit" | "normal" | "medium" | "semibold" | null;
|
package/vanilla/UiText.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { componentRootIndex, manageComponentLifecycle } from "@nextwebwg/html-next/runtime";
|
|
3
3
|
import "../styles/ui-text.css";
|
|
4
4
|
|
|
5
|
-
const definition = {...{"contract":{"tag":"ui-text","props":{"align":{"type":{"enum":["start","center"]},"required":false,"target":{"attribute":"align"},"default":"start"},"as":{"type":{"enum":["p","span","div","small","strong","label"]},"required":false,"target":{"attribute":"as"},"default":"p"},"size":{"type":{"enum":["inherit","xs","sm","md","lg"]},"required":false,"target":{"attribute":"size"},"default":"inherit"},"tone":{"type":{"enum":["default","secondary","muted","accent","danger","success"]},"required":false,"target":{"attribute":"tone"},"default":"default"},"truncate":{"type":"boolean","required":false,"target":{"attribute":"truncate"},"default":false},"variant":{"type":{"enum":["body","eyebrow","code"]},"required":false,"target":{"attribute":"variant"},"default":"body"},"weight":{"type":{"enum":["inherit","normal","medium","semibold"]},"required":false,"target":{"attribute":"weight"},"default":"inherit"}}},"template":{"kind":"element","name":"template","attributes":[],"children":[{"kind":"element","name":"span","attributes":[],"children":[{"kind":"slot"}],"flow":{"kind":"when","test":"as = 'span'","testPlan":{"source":"as = 'span'","ast":{"kind":"binary","op":"=","left":{"kind":"id","name":"as"},"right":{"kind":"literal","value":"span"}},"dependencies":["as"]}}},{"kind":"element","name":"div","attributes":[],"children":[{"kind":"slot"}],"flow":{"kind":"when","test":"as = 'div'","testPlan":{"source":"as = 'div'","ast":{"kind":"binary","op":"=","left":{"kind":"id","name":"as"},"right":{"kind":"literal","value":"div"}},"dependencies":["as"]}}},{"kind":"element","name":"small","attributes":[],"children":[{"kind":"slot"}],"flow":{"kind":"when","test":"as = 'small'","testPlan":{"source":"as = 'small'","ast":{"kind":"binary","op":"=","left":{"kind":"id","name":"as"},"right":{"kind":"literal","value":"small"}},"dependencies":["as"]}}},{"kind":"element","name":"strong","attributes":[],"children":[{"kind":"slot"}],"flow":{"kind":"when","test":"as = 'strong'","testPlan":{"source":"as = 'strong'","ast":{"kind":"binary","op":"=","left":{"kind":"id","name":"as"},"right":{"kind":"literal","value":"strong"}},"dependencies":["as"]}}},{"kind":"element","name":"label","attributes":[],"children":[{"kind":"slot"}],"flow":{"kind":"when","test":"as = 'label'","testPlan":{"source":"as = 'label'","ast":{"kind":"binary","op":"=","left":{"kind":"id","name":"as"},"right":{"kind":"literal","value":"label"}},"dependencies":["as"]}}},{"kind":"element","name":"p","attributes":[],"children":[{"kind":"slot"}],"flow":{"kind":"else"}}],"flow":{"kind":"match"}},"declarations":[],"root":{"kind":"native","element":"p","choices":["span","div","small","strong","label","p"]}},source:{file:import.meta.url},css:""};
|
|
5
|
+
const definition = {...{"contract":{"tag":"ui-text","props":{"align":{"type":{"enum":["start","center"]},"required":false,"target":{"attribute":"align"},"default":"start"},"as":{"type":{"enum":["p","span","div","small","strong","label"]},"required":false,"target":{"attribute":"as"},"default":"p"},"size":{"type":{"enum":["inherit","xs","sm","md","lg"]},"required":false,"target":{"attribute":"size"},"default":"inherit"},"tone":{"type":{"enum":["default","secondary","muted","accent","danger","success","info","warning"]},"required":false,"target":{"attribute":"tone"},"default":"default"},"truncate":{"type":"boolean","required":false,"target":{"attribute":"truncate"},"default":false},"variant":{"type":{"enum":["body","eyebrow","code"]},"required":false,"target":{"attribute":"variant"},"default":"body"},"weight":{"type":{"enum":["inherit","normal","medium","semibold"]},"required":false,"target":{"attribute":"weight"},"default":"inherit"}}},"template":{"kind":"element","name":"template","attributes":[],"children":[{"kind":"element","name":"span","attributes":[],"children":[{"kind":"slot"}],"flow":{"kind":"when","test":"as = 'span'","testPlan":{"source":"as = 'span'","ast":{"kind":"binary","op":"=","left":{"kind":"id","name":"as"},"right":{"kind":"literal","value":"span"}},"dependencies":["as"]}}},{"kind":"element","name":"div","attributes":[],"children":[{"kind":"slot"}],"flow":{"kind":"when","test":"as = 'div'","testPlan":{"source":"as = 'div'","ast":{"kind":"binary","op":"=","left":{"kind":"id","name":"as"},"right":{"kind":"literal","value":"div"}},"dependencies":["as"]}}},{"kind":"element","name":"small","attributes":[],"children":[{"kind":"slot"}],"flow":{"kind":"when","test":"as = 'small'","testPlan":{"source":"as = 'small'","ast":{"kind":"binary","op":"=","left":{"kind":"id","name":"as"},"right":{"kind":"literal","value":"small"}},"dependencies":["as"]}}},{"kind":"element","name":"strong","attributes":[],"children":[{"kind":"slot"}],"flow":{"kind":"when","test":"as = 'strong'","testPlan":{"source":"as = 'strong'","ast":{"kind":"binary","op":"=","left":{"kind":"id","name":"as"},"right":{"kind":"literal","value":"strong"}},"dependencies":["as"]}}},{"kind":"element","name":"label","attributes":[],"children":[{"kind":"slot"}],"flow":{"kind":"when","test":"as = 'label'","testPlan":{"source":"as = 'label'","ast":{"kind":"binary","op":"=","left":{"kind":"id","name":"as"},"right":{"kind":"literal","value":"label"}},"dependencies":["as"]}}},{"kind":"element","name":"p","attributes":[],"children":[{"kind":"slot"}],"flow":{"kind":"else"}}],"flow":{"kind":"match"}},"declarations":[],"root":{"kind":"native","element":"p","choices":["span","div","small","strong","label","p"]}},source:{file:import.meta.url},css:""};
|
|
6
6
|
|
|
7
7
|
export function createUiText(options = {}) {
|
|
8
8
|
const { attributes = {}, children = [], slots = {}, ...componentProps } = options;
|
package/vue/UiMeter.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
type __VLS_Props = {
|
|
2
2
|
label?: string;
|
|
3
3
|
max?: number;
|
|
4
|
+
segments?: number;
|
|
4
5
|
size?: 'sm' | 'md';
|
|
5
6
|
tone?: 'neutral' | 'accent' | 'info' | 'success' | 'warning' | 'danger';
|
|
6
7
|
value?: number;
|
|
@@ -12,6 +13,7 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {
|
|
|
12
13
|
value: number;
|
|
13
14
|
max: number;
|
|
14
15
|
tone: "neutral" | "accent" | "info" | "success" | "warning" | "danger";
|
|
16
|
+
segments: number;
|
|
15
17
|
valueText: string;
|
|
16
18
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
17
19
|
declare const _default: typeof __VLS_export;
|
package/vue/UiMeter.vue
CHANGED
|
@@ -8,6 +8,7 @@ const props = withDefaults(
|
|
|
8
8
|
defineProps<{
|
|
9
9
|
label?: string
|
|
10
10
|
max?: number
|
|
11
|
+
segments?: number
|
|
11
12
|
size?: 'sm' | 'md'
|
|
12
13
|
tone?: 'neutral' | 'accent' | 'info' | 'success' | 'warning' | 'danger'
|
|
13
14
|
value?: number
|
|
@@ -16,6 +17,7 @@ const props = withDefaults(
|
|
|
16
17
|
{
|
|
17
18
|
label: '',
|
|
18
19
|
max: 1,
|
|
20
|
+
segments: 0,
|
|
19
21
|
size: 'md',
|
|
20
22
|
tone: 'neutral',
|
|
21
23
|
value: 0,
|
|
@@ -119,6 +121,7 @@ function number(value: unknown): number | undefined {
|
|
|
119
121
|
:aria-label="typeof (({ true: label, false: null })[`${label !== ''}`]) === 'boolean'
|
|
120
122
|
? String(({ true: label, false: null })[`${label !== ''}`])
|
|
121
123
|
: attribute(({ true: label, false: null })[`${label !== ''}`])"
|
|
124
|
+
:data-ui-meter-segments="attribute(({ true: segments, false: null })[`${segments > 1}`])"
|
|
122
125
|
:data-ui-meter-state="hostState || undefined"
|
|
123
126
|
><span class="fill" :style="{ 'inline-size': `${text(percent)}%` }"></span></span>
|
|
124
127
|
</template>
|
|
@@ -179,12 +182,94 @@ function number(value: unknown): number | undefined {
|
|
|
179
182
|
--_meter-fill: var(--ui-danger-solid);
|
|
180
183
|
}
|
|
181
184
|
|
|
185
|
+
/* Segments: the track and its fill show through a mask of equal segments with a gap between them.
|
|
186
|
+
A mask over the whole meter, rather than one element per segment, because the expression
|
|
187
|
+
language has no range to render N elements from, and one mask lines the fill up with the track
|
|
188
|
+
for free. Each period is a segment and the gap after it; N periods span the track plus one
|
|
189
|
+
trailing gap, so the segments sit symmetrically and right to left needs nothing of its own.
|
|
190
|
+
The count arrives as an attribute, not an inline custom property (which would add a style
|
|
191
|
+
attribute to every meter), so a continuous meter renders exactly as before, and the rules below
|
|
192
|
+
turn it into a number. That caps it at 12, until attr() with a type reads any count in every engine. */
|
|
193
|
+
[data-component~="ui-meter"][data-ui-meter-segments="2"] {
|
|
194
|
+
--_segments: 2;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
[data-component~="ui-meter"][data-ui-meter-segments="3"] {
|
|
198
|
+
--_segments: 3;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
[data-component~="ui-meter"][data-ui-meter-segments="4"] {
|
|
202
|
+
--_segments: 4;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
[data-component~="ui-meter"][data-ui-meter-segments="5"] {
|
|
206
|
+
--_segments: 5;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
[data-component~="ui-meter"][data-ui-meter-segments="6"] {
|
|
210
|
+
--_segments: 6;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
[data-component~="ui-meter"][data-ui-meter-segments="7"] {
|
|
214
|
+
--_segments: 7;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
[data-component~="ui-meter"][data-ui-meter-segments="8"] {
|
|
218
|
+
--_segments: 8;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
[data-component~="ui-meter"][data-ui-meter-segments="9"] {
|
|
222
|
+
--_segments: 9;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
[data-component~="ui-meter"][data-ui-meter-segments="10"] {
|
|
226
|
+
--_segments: 10;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
[data-component~="ui-meter"][data-ui-meter-segments="11"] {
|
|
230
|
+
--_segments: 11;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
[data-component~="ui-meter"][data-ui-meter-segments="12"] {
|
|
234
|
+
--_segments: 12;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
[data-component~="ui-meter"][data-ui-meter-segments] {
|
|
238
|
+
--_meter-gap: var(--ui-space-1);
|
|
239
|
+
--_meter-period: calc((100% + var(--_meter-gap)) / var(--_segments));
|
|
240
|
+
--_meter-segment: calc(var(--_meter-period) - var(--_meter-gap));
|
|
241
|
+
|
|
242
|
+
mask-image: repeating-linear-gradient(
|
|
243
|
+
to right,
|
|
244
|
+
#000 0 var(--_meter-segment),
|
|
245
|
+
transparent 0 var(--_meter-period)
|
|
246
|
+
);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
[data-component~="ui-meter"][data-ui-meter-state~="size=sm"][data-ui-meter-segments] {
|
|
250
|
+
--_meter-gap: var(--ui-space-0-5);
|
|
251
|
+
}
|
|
252
|
+
|
|
182
253
|
/* Forced colours drop backgrounds: draw the fill in the text colour inside the outlined track. */
|
|
183
254
|
@media (forced-colors: active) {
|
|
184
255
|
.fill {
|
|
185
256
|
forced-color-adjust: none;
|
|
186
257
|
background: CanvasText;
|
|
187
258
|
}
|
|
259
|
+
|
|
260
|
+
/* The mask clips the track's outline, so each segment draws its own: the inset shadow draws the
|
|
261
|
+
top and bottom edges and the gradient the ends. */
|
|
262
|
+
[data-component~="ui-meter"][data-ui-meter-segments] {
|
|
263
|
+
forced-color-adjust: none;
|
|
264
|
+
background: repeating-linear-gradient(
|
|
265
|
+
to right,
|
|
266
|
+
CanvasText 0 1px,
|
|
267
|
+
Canvas 0 calc(var(--_meter-segment) - 1px),
|
|
268
|
+
CanvasText 0 var(--_meter-segment),
|
|
269
|
+
transparent 0 var(--_meter-period)
|
|
270
|
+
);
|
|
271
|
+
box-shadow: inset 0 0 0 1px CanvasText;
|
|
272
|
+
}
|
|
188
273
|
}
|
|
189
274
|
|
|
190
275
|
/* A component that sets its display still honours the hidden attribute on its root. */
|
package/vue/UiText.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ type __VLS_Props = {
|
|
|
2
2
|
align?: 'start' | 'center';
|
|
3
3
|
as?: 'p' | 'span' | 'div' | 'small' | 'strong' | 'label';
|
|
4
4
|
size?: 'inherit' | 'xs' | 'sm' | 'md' | 'lg';
|
|
5
|
-
tone?: 'default' | 'secondary' | 'muted' | 'accent' | 'danger' | 'success';
|
|
5
|
+
tone?: 'default' | 'secondary' | 'muted' | 'accent' | 'danger' | 'success' | 'info' | 'warning';
|
|
6
6
|
truncate?: boolean;
|
|
7
7
|
variant?: 'body' | 'eyebrow' | 'code';
|
|
8
8
|
weight?: 'inherit' | 'normal' | 'medium' | 'semibold';
|
|
@@ -23,7 +23,7 @@ type __VLS_Slots = {} & {
|
|
|
23
23
|
};
|
|
24
24
|
declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
|
|
25
25
|
size: "inherit" | "xs" | "sm" | "md" | "lg";
|
|
26
|
-
tone: "default" | "secondary" | "muted" | "accent" | "danger" | "success";
|
|
26
|
+
tone: "default" | "secondary" | "muted" | "accent" | "danger" | "success" | "info" | "warning";
|
|
27
27
|
variant: "body" | "eyebrow" | "code";
|
|
28
28
|
align: "start" | "center";
|
|
29
29
|
as: "p" | "span" | "div" | "small" | "strong" | "label";
|
package/vue/UiText.vue
CHANGED
|
@@ -9,7 +9,7 @@ const props = withDefaults(
|
|
|
9
9
|
align?: 'start' | 'center'
|
|
10
10
|
as?: 'p' | 'span' | 'div' | 'small' | 'strong' | 'label'
|
|
11
11
|
size?: 'inherit' | 'xs' | 'sm' | 'md' | 'lg'
|
|
12
|
-
tone?: 'default' | 'secondary' | 'muted' | 'accent' | 'danger' | 'success'
|
|
12
|
+
tone?: 'default' | 'secondary' | 'muted' | 'accent' | 'danger' | 'success' | 'info' | 'warning'
|
|
13
13
|
truncate?: boolean
|
|
14
14
|
variant?: 'body' | 'eyebrow' | 'code'
|
|
15
15
|
weight?: 'inherit' | 'normal' | 'medium' | 'semibold'
|
|
@@ -118,6 +118,14 @@ const hostState = computed(() =>
|
|
|
118
118
|
[data-component~="ui-text"][data-ui-text-state~="tone=success"] {
|
|
119
119
|
color: var(--ui-success);
|
|
120
120
|
}
|
|
121
|
+
/* The base info and warning colours fall short of 4.5:1 on sunken surfaces, so these use the
|
|
122
|
+
text-safe tokens a subtle badge sets its words in. */
|
|
123
|
+
[data-component~="ui-text"][data-ui-text-state~="tone=info"] {
|
|
124
|
+
color: var(--ui-info-subtle-text);
|
|
125
|
+
}
|
|
126
|
+
[data-component~="ui-text"][data-ui-text-state~="tone=warning"] {
|
|
127
|
+
color: var(--ui-warning-subtle-text);
|
|
128
|
+
}
|
|
121
129
|
|
|
122
130
|
[data-component~="ui-text"][data-ui-text-state~="weight=normal"] {
|
|
123
131
|
font-weight: var(--ui-font-normal);
|
package/vue/chunks/UiMeter.js
CHANGED
|
@@ -6,6 +6,7 @@ var _hoisted_1 = [
|
|
|
6
6
|
"aria-valuenow",
|
|
7
7
|
"aria-valuetext",
|
|
8
8
|
"aria-label",
|
|
9
|
+
"data-ui-meter-segments",
|
|
9
10
|
"data-ui-meter-state"
|
|
10
11
|
];
|
|
11
12
|
//#endregion
|
|
@@ -16,6 +17,7 @@ var UiMeter_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE
|
|
|
16
17
|
props: {
|
|
17
18
|
label: { default: "" },
|
|
18
19
|
max: { default: 1 },
|
|
20
|
+
segments: { default: 0 },
|
|
19
21
|
size: { default: "md" },
|
|
20
22
|
tone: { default: "neutral" },
|
|
21
23
|
value: { default: 0 },
|
|
@@ -70,6 +72,10 @@ var UiMeter_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE
|
|
|
70
72
|
true: __props.label,
|
|
71
73
|
false: null
|
|
72
74
|
}[`${__props.label !== ""}`]),
|
|
75
|
+
"data-ui-meter-segments": attribute({
|
|
76
|
+
true: __props.segments,
|
|
77
|
+
false: null
|
|
78
|
+
}[`${__props.segments > 1}`]),
|
|
73
79
|
"data-ui-meter-state": hostState.value || void 0
|
|
74
80
|
}), [createElementVNode("span", {
|
|
75
81
|
class: "fill",
|
|
@@ -77,6 +83,6 @@ var UiMeter_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE
|
|
|
77
83
|
}, null, 4)], 16, _hoisted_1);
|
|
78
84
|
};
|
|
79
85
|
}
|
|
80
|
-
}), [["__scopeId", "data-v-
|
|
86
|
+
}), [["__scopeId", "data-v-c0b7936e"]]);
|
|
81
87
|
//#endregion
|
|
82
88
|
export { UiMeter_default as t };
|
package/vue/chunks/UiText.js
CHANGED
|
@@ -57,6 +57,6 @@ var UiText_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE_
|
|
|
57
57
|
}, _ctx.$attrs, { "data-ui-text-state": hostState.value || void 0 }), [renderSlot(_ctx.$slots, "default")], 16, _hoisted_6));
|
|
58
58
|
};
|
|
59
59
|
}
|
|
60
|
-
}), [["__scopeId", "data-v-
|
|
60
|
+
}), [["__scopeId", "data-v-e15a75c1"]]);
|
|
61
61
|
//#endregion
|
|
62
62
|
export { UiText_default as t };
|