@threadlabs/looma 0.34.0 → 0.35.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/components/ui-badge/ui-badge.html +11 -3
- package/components/ui-button/ui-button.html +29 -4
- package/components/ui-card/ui-card.html +15 -13
- package/components/ui-checkbox/ui-checkbox.html +4 -2
- package/components/ui-dialog/ui-dialog.html +2 -0
- package/components/ui-icon-button/ui-icon-button.html +22 -8
- package/components/ui-input/ui-input.html +2 -1
- package/components/ui-input-group/ui-input-group.html +4 -1
- package/components/ui-light-editor/ui-light-editor.html +45 -0
- package/components/ui-light-editor/ui-light-editor.js +53 -0
- package/components/ui-menu/ui-menu.html +2 -0
- package/components/ui-number-input/ui-number-input.html +2 -1
- package/components/ui-number-input/ui-number-input.js +6 -3
- package/components/ui-popover/ui-popover.html +2 -0
- package/components/ui-reel/ui-reel.html +2 -1
- package/components/ui-select/ui-select.html +9 -7
- package/components/ui-switch/ui-switch.html +3 -0
- package/components/ui-tabs/ui-tabs.html +2 -3
- package/components/ui-tabs/ui-tabs.js +0 -9
- package/components/ui-textarea/ui-textarea.html +2 -1
- package/components/ui-tooltip/ui-tooltip.html +2 -1
- package/dist/index.js +24 -23
- package/docs/README.md +29 -3
- package/docs/card.html +7 -6
- package/docs/catalog-view.mjs +2 -1
- package/docs/catalog.json +575 -53
- package/docs/customizer-render.mjs +31 -16
- package/docs/customizer.js +72 -19
- package/docs/index.d.ts +4 -1
- package/docs/index.mjs +1 -1
- package/docs/render.mjs +1 -1
- package/docs/site.mjs +33 -22
- package/docs/theme-session.mjs +4 -2
- package/docs/theme.mjs +61 -7
- package/package.json +2 -2
- package/styles/ui-badge.css +11 -6
- package/styles/ui-button.css +29 -4
- package/styles/ui-card.css +9 -9
- package/styles/ui-checkbox.css +4 -2
- package/styles/ui-dialog.css +4 -0
- package/styles/ui-icon-button.css +22 -8
- package/styles/ui-input-group.css +4 -1
- package/styles/ui-input.css +2 -1
- package/styles/ui-light-editor.css +28 -0
- package/styles/ui-menu.css +2 -0
- package/styles/ui-popover.css +2 -0
- package/styles/ui-select.css +9 -7
- package/styles/ui-switch.css +3 -0
- package/styles/ui-tabs.css +2 -3
- package/styles/ui-textarea.css +2 -1
- package/styles/ui-tooltip.css +2 -1
- package/theme-light.css +1 -0
- package/theme-system.css +43 -7
- package/tokens.css +5 -1
- package/vanilla/UiCard.d.ts +2 -1
- package/vanilla/UiCard.js +12 -12
- package/vanilla/UiLightEditor.d.ts +29 -0
- package/vanilla/UiLightEditor.js +102 -0
- package/vanilla/UiNumberInput.js +27 -20
- package/vanilla/index.js +1 -0
- package/vue/UiBadge.vue +29 -4
- package/vue/UiButton.vue +33 -4
- package/vue/UiCard.d.ts +8 -2
- package/vue/UiCard.vue +41 -17
- package/vue/UiCheckbox.vue +4 -2
- package/vue/UiDialog.vue +4 -0
- package/vue/UiIconButton.vue +26 -11
- package/vue/UiInput.vue +2 -1
- package/vue/UiInputGroup.vue +4 -1
- package/vue/UiLightEditor.d.ts +75 -0
- package/vue/UiLightEditor.js +2 -0
- package/vue/UiLightEditor.vue +402 -0
- package/vue/UiMenu.vue +2 -0
- package/vue/UiNumberInput.vue +32 -3
- package/vue/UiPopover.vue +2 -0
- package/vue/UiReel.vue +1 -1
- package/vue/UiSelect.vue +16 -10
- package/vue/UiSwitch.vue +3 -0
- package/vue/UiTabs.vue +2 -3
- package/vue/UiTextarea.vue +2 -1
- package/vue/UiTooltip.vue +2 -1
- package/vue/chunks/UiBadge.js +1 -1
- package/vue/chunks/UiButton.js +1 -1
- package/vue/chunks/UiCard.js +33 -5
- package/vue/chunks/UiCheckbox.js +1 -1
- package/vue/chunks/UiDialog.js +1 -1
- package/vue/chunks/UiIconButton.js +1 -1
- package/vue/chunks/UiInput.js +1 -1
- package/vue/chunks/UiInputGroup.js +1 -1
- package/vue/chunks/UiLightEditor.js +347 -0
- package/vue/chunks/UiMenu.js +1 -1
- package/vue/chunks/UiNumberInput.js +21 -8
- package/vue/chunks/UiPopover.js +1 -1
- package/vue/chunks/UiReel.js +2 -2
- package/vue/chunks/UiSelect.js +1 -1
- package/vue/chunks/UiSwitch.js +1 -1
- package/vue/chunks/UiTabs.js +1 -1
- package/vue/chunks/UiTextarea.js +1 -1
- package/vue/chunks/UiTooltip.js +1 -1
- package/vue/components.css +312 -71
- package/vue/index.d.ts +1 -0
- package/vue/index.js +2 -1
package/docs/theme.mjs
CHANGED
|
@@ -27,6 +27,12 @@ export const themeFields = [
|
|
|
27
27
|
['Material', 'surface-separation', 'Surface separation', '--ui-surface-separation', 'fraction', '0', 'One material offset, scaled by popup purpose and actual size: quiet tooltips through substantial dialogs.'],
|
|
28
28
|
['Material', 'translucency', 'Overlay translucency', '--ui-overlay-translucency', 'fraction', '0', 'How much background comes through floating surfaces.'],
|
|
29
29
|
['Material', 'edge-light', 'Edge light', '--ui-edge-light', 'fraction', '0', 'Light caught by surface edges, independent of depth.'],
|
|
30
|
+
['Material', 'finish', 'Finish', '--ui-finish', 'fraction', '0', 'Matte through polished: how strongly the material catches a reflection.'],
|
|
31
|
+
['Material', 'glow', 'Glow', '--ui-glow', 'fraction', '0', 'Soft reflected light beyond a surface, derived from its tone.'],
|
|
32
|
+
['Material', 'light-x', 'Light horizontal position', '--ui-light-x', 'fraction', '0.5', 'The light source from left to right, relative to each surface.'],
|
|
33
|
+
['Material', 'light-y', 'Light vertical position', '--ui-light-y', 'fraction', '0', 'The light source from top to bottom, relative to each surface.'],
|
|
34
|
+
['Material', 'light-spread', 'Light spread', '--ui-light-spread', 'fraction', '0.5', 'A concentrated spot through broad illumination.'],
|
|
35
|
+
['Material', 'light-strength', 'Light strength', '--ui-light-strength', 'fraction', '0.65', 'Shared illumination; each material and component role determines its response.'],
|
|
30
36
|
['Motion', 'response-time', 'Response time', '--ui-motion-fast', 'time', '120ms', 'Shared feedback pace; floating transitions take proportionally longer.'],
|
|
31
37
|
['Motion', 'response-curve', 'Response curve', '--ui-motion-ease', 'easing', 'cubic-bezier(0.2,0,0.2,1)', 'How movement accelerates and settles.'],
|
|
32
38
|
].map(([family, id, label, property, type, defaultValue, description]) => Object.freeze({ family, id, label, property, type, defaultValue, description, ...(bounds[id] ? { min: bounds[id][0], max: bounds[id][1] } : type === 'fraction' ? { min: 0, max: 1 } : {}) }));
|
|
@@ -35,14 +41,12 @@ export const defaultRecipe = () => ({ schemaVersion: 1, values: Object.fromEntri
|
|
|
35
41
|
const starting = values => ({ schemaVersion: 1, values: { ...defaultRecipe().values, ...values } });
|
|
36
42
|
export const startingPoints = {
|
|
37
43
|
clear: defaultRecipe(),
|
|
38
|
-
bookish: starting({ action: '#2e1228', canvas: '#f7f7f5', surface: '#fffefd', text: '#0d0c0c', 'body-font': 'Arial, sans-serif', 'display-font': 'Georgia, serif', 'text-weight': '400', 'control-size': '42px', 'scale-contrast': '1.18', 'outer-depth': '1', 'inner-depth': '1', glassiness: '0.8', 'surface-separation': '0.65', translucency: '0.18', 'edge-light': '1', 'response-time': '150ms', 'response-curve': 'ease' }),
|
|
44
|
+
bookish: starting({ action: '#2e1228', canvas: '#f7f7f5', surface: '#fffefd', text: '#0d0c0c', 'body-font': 'Arial, sans-serif', 'display-font': 'Georgia, serif', 'text-weight': '400', 'control-size': '42px', 'scale-contrast': '1.18', 'outer-depth': '1', 'inner-depth': '1', glassiness: '0.8', 'surface-separation': '0.65', translucency: '0.18', 'edge-light': '1', finish: '0.85', glow: '0.3', 'light-spread': '0.3', 'light-strength': '0.9', 'response-time': '150ms', 'response-curve': 'ease' }),
|
|
39
45
|
wiki: starting({ action: '#4f46e5', canvas: '#ffffff', surface: '#ffffff', text: '#1a1a1a', 'control-size': '34px', density: '0.85', 'scale-contrast': '1.15', 'corner-roundness': '6px', 'outer-depth': '0.35', 'inner-depth': '0', 'response-time': '110ms' }),
|
|
40
46
|
editorial: starting({ action: '#182c24', canvas: '#eee9dc', surface: '#fffdf5', text: '#182c24', 'corner-roundness': '0px', 'outer-depth': '0', 'inner-depth': '0', 'body-font': 'Georgia, serif', 'display-font': 'Georgia, serif', 'text-weight': '400', 'line-weight': '2px', 'response-time': '90ms', 'response-curve': 'linear' }),
|
|
41
47
|
night: starting({ action: '#a7b8ff', canvas: '#11141c', surface: '#202634', text: '#edf1fb', 'corner-roundness': '12px', 'outer-depth': '1.4', 'inner-depth': '0.45', translucency: '0.2', 'edge-light': '0.65', 'response-time': '210ms', 'response-curve': 'cubic-bezier(0.2,0.8,0.2,1)' }),
|
|
42
48
|
garden: starting({ action: '#256342', canvas: '#eef5e7', surface: '#fcfff6', text: '#173121', 'corner-roundness': '22px', 'outer-depth': '0.35', 'inner-depth': '0', 'edge-light': '0.2', 'control-size': '46px', 'scale-contrast': '1.24', density: '1.05', 'response-time': '180ms', 'response-curve': 'cubic-bezier(0.16,1,0.3,1)' }),
|
|
43
49
|
};
|
|
44
|
-
// Preserve the public historical startingPoints.library import without a duplicate UI preset.
|
|
45
|
-
Object.defineProperty(startingPoints, 'library', { value: startingPoints.bookish });
|
|
46
50
|
export const startingPointLabels = { clear: 'Clear', bookish: 'Bookish', wiki: 'Wiki', editorial: 'Editorial', night: 'Night', garden: 'Garden' };
|
|
47
51
|
const paletteKeys = ['action', 'canvas', 'surface', 'text'];
|
|
48
52
|
// Palette choices move only the shared color seeds; size, material and motion stay independent.
|
|
@@ -51,6 +55,33 @@ export const themePalettes = Object.fromEntries([
|
|
|
51
55
|
['editorial', 'Ink & parchment'], ['night', 'Midnight'], ['garden', 'Forest & cream'],
|
|
52
56
|
].map(([id, label]) => [id, { label, values: Object.fromEntries(paletteKeys.map(key => [key, startingPoints[id].values[key]])) }]));
|
|
53
57
|
|
|
58
|
+
const materialKeys = themeFields.filter(field => field.family === 'Material').map(field => field.id);
|
|
59
|
+
const materialDefaults = defaultRecipe().values;
|
|
60
|
+
const material = (label, overrides) => ({ label, values: Object.fromEntries(materialKeys.map(key => [key, overrides[key] ?? materialDefaults[key]])) });
|
|
61
|
+
export const materialPresets = {
|
|
62
|
+
matte: material('Matte', { 'outer-depth': '0', 'inner-depth': '0' }),
|
|
63
|
+
soft: material('Soft', { 'outer-depth': '0.6', 'inner-depth': '0.3', 'edge-light': '0.3', finish: '0.2', 'light-spread': '0.8' }),
|
|
64
|
+
polished: material('Polished', { 'outer-depth': '1', 'inner-depth': '1', 'edge-light': '1', finish: '0.85', glow: '0.3', 'light-spread': '0.3', 'light-strength': '0.9' }),
|
|
65
|
+
glass: material('Frosted glass', startingPoints.bookish.values),
|
|
66
|
+
};
|
|
67
|
+
const refinementPresets = family => family === 'material' ? materialPresets : family === 'palette' ? themePalettes : undefined;
|
|
68
|
+
|
|
69
|
+
/** Preset provenance is optional recipe data, never a second source of theme values. */
|
|
70
|
+
export function refinementState(input, family) {
|
|
71
|
+
const recipe = validateRecipe(input), presets = refinementPresets(family);
|
|
72
|
+
if (!presets) throw new Error('Unknown refinement family.');
|
|
73
|
+
const matches = preset => Object.entries(preset.values).every(([key, value]) => recipe.values[key] === value);
|
|
74
|
+
const id = recipe.presets?.[family] ?? Object.keys(presets).find(id => matches(presets[id])) ?? 'custom';
|
|
75
|
+
return { id, customized: id !== 'custom' && !matches(presets[id]) };
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/** Apply or restore one family without changing the rest of the design system. */
|
|
79
|
+
export function applyRefinement(input, family, id) {
|
|
80
|
+
const recipe = validateRecipe(input), preset = refinementPresets(family)?.[id];
|
|
81
|
+
if (!preset) throw new Error('Unknown refinement preset.');
|
|
82
|
+
return validateRecipe({ ...recipe, values: { ...recipe.values, ...preset.values }, presets: { ...recipe.presets, [family]: id } });
|
|
83
|
+
}
|
|
84
|
+
|
|
54
85
|
/** Identify a coordinated palette without coupling it to the rest of a recipe. */
|
|
55
86
|
export function paletteFor(input) {
|
|
56
87
|
const { values } = validateRecipe(input);
|
|
@@ -111,19 +142,28 @@ export function validateRecipe(input) {
|
|
|
111
142
|
if (number !== undefined && (number < min || number > max)) throw new Error(`${field.label}: choose a value between ${min} and ${max}${field.type.includes('length') ? 'px (or equivalent)' : field.type === 'time' ? 'ms' : ''}.`);
|
|
112
143
|
}
|
|
113
144
|
}
|
|
114
|
-
|
|
145
|
+
if (input.presets !== undefined && (!input.presets || typeof input.presets !== 'object' || Array.isArray(input.presets) || Object.entries(input.presets).some(([family, id]) => !Object.hasOwn(refinementPresets(family) ?? {}, id)))) throw new Error('Unknown refinement preset.');
|
|
146
|
+
return { schemaVersion: 1, values, ...(input.presets === undefined ? {} : { presets: { ...input.presets } }) };
|
|
115
147
|
}
|
|
116
148
|
|
|
117
149
|
/** Match presets by their complete semantic recipe, including locally saved themes. */
|
|
118
150
|
export function startingPointFor(input) {
|
|
119
|
-
const recipe = JSON.stringify(validateRecipe(input));
|
|
120
|
-
return Object.entries(startingPoints).find(([, value]) => JSON.stringify(value) === recipe)?.[0] ?? 'custom';
|
|
151
|
+
const recipe = JSON.stringify(validateRecipe(input).values);
|
|
152
|
+
return Object.entries(startingPoints).find(([, value]) => JSON.stringify(value.values) === recipe)?.[0] ?? 'custom';
|
|
121
153
|
}
|
|
122
154
|
|
|
123
155
|
const rgb = hex => [1, 3, 5].map(i => parseInt(hex.slice(i, i + 2), 16));
|
|
124
156
|
const mix = (a, b, weight) => '#' + rgb(a).map((n, i) => Math.round(n * weight + rgb(b)[i] * (1 - weight)).toString(16).padStart(2, '0')).join('');
|
|
125
157
|
const luminance = hex => rgb(hex).map(n => { const s = n / 255; return s <= .04045 ? s / 12.92 : ((s + .055) / 1.055) ** 2.4; }).reduce((sum, n, i) => sum + n * [.2126, .7152, .0722][i], 0);
|
|
126
158
|
const contrast = (a, b) => (Math.max(luminance(a), luminance(b)) + .05) / (Math.min(luminance(a), luminance(b)) + .05);
|
|
159
|
+
// The brightest reflection stop is itself readable. Interpolating it over a readable
|
|
160
|
+
// fill cannot wash out the label, even at maximum finish and light strength.
|
|
161
|
+
function reflection(fill, text) {
|
|
162
|
+
const labels = Array.isArray(text) ? text : [text];
|
|
163
|
+
let amount = .32;
|
|
164
|
+
while (amount > 0 && labels.some(label => contrast(mix('#ffffff', fill, amount), label) < 4.5)) amount = Math.max(0, amount - .005);
|
|
165
|
+
return mix('#ffffff', fill, amount);
|
|
166
|
+
}
|
|
127
167
|
const foreground = (fill, light, dark) => [light, dark, '#ffffff', '#000000'].sort((a, b) => contrast(fill, b) - contrast(fill, a))[0];
|
|
128
168
|
|
|
129
169
|
/** Find the nearest mixture with a known readable endpoint, including every supplied surface. */
|
|
@@ -164,6 +204,7 @@ export function deriveTheme(input, { mode } = {}) {
|
|
|
164
204
|
tokens[`--ui-${tone}`] = fill;
|
|
165
205
|
tokens[`--ui-on-${tone}`] = foreground(fill, '#ffffff', '#000000');
|
|
166
206
|
tokens[`--ui-${tone}-on-strong`] = tokens[`--ui-on-${tone}`];
|
|
207
|
+
tokens[`--ui-${tone}-reflection`] = reflection(fill, tokens[`--ui-on-${tone}`]);
|
|
167
208
|
tokens[`--ui-${tone}-hover`] = mix(fill, ink, .86);
|
|
168
209
|
tokens[`--ui-${tone}-active`] = mix(fill, ink, .74);
|
|
169
210
|
tokens[`--ui-${tone}-soft`] = mix(fill, tokens['--ui-surface-raised'], .08);
|
|
@@ -177,10 +218,17 @@ export function deriveTheme(input, { mode } = {}) {
|
|
|
177
218
|
tokens['--ui-text'] = readableColour(textSeed, readingSurfaces, 4.5, ink);
|
|
178
219
|
tokens['--ui-text-secondary'] = readableColour(mix(tokens['--ui-text'], tokens['--ui-surface-raised'], .72), readingSurfaces, 4.5, ink);
|
|
179
220
|
tokens['--ui-text-muted'] = tokens['--ui-text-secondary'];
|
|
221
|
+
for (const [state, amount] of [['surface', .06], ['hover', .1], ['active', .14]]) {
|
|
222
|
+
tokens[`--ui-neutral-${state}`] = readableColour(mix(tokens['--ui-text'], tokens['--ui-surface-raised'], amount), [tokens['--ui-text']], 4.5, paper);
|
|
223
|
+
}
|
|
224
|
+
tokens['--ui-surface-reflection'] = reflection(tokens['--ui-surface-raised'], [tokens['--ui-text'], tokens['--ui-text-secondary'], ...Object.keys(tones).map(tone => tokens[`--ui-${tone}-subtle-text`])]);
|
|
225
|
+
tokens['--ui-neutral-reflection'] = reflection(tokens['--ui-neutral-surface'], tokens['--ui-text']);
|
|
180
226
|
tokens['--ui-selection-surface'] = mix(tokens['--ui-accent'], tokens['--ui-surface-raised'], .1);
|
|
181
227
|
tokens['--ui-selection-text'] = tokens['--ui-accent-subtle-text'];
|
|
182
228
|
tokens['--ui-selection-border'] = mix(tokens['--ui-accent'], tokens['--ui-surface-raised'], .2);
|
|
183
229
|
tokens['--ui-control-surface'] = tokens['--ui-surface-raised'];
|
|
230
|
+
// A hint is quieter than body copy; resolve it against its field, not every tinted content surface.
|
|
231
|
+
tokens['--ui-control-placeholder'] = readableColour(mix(tokens['--ui-text'], tokens['--ui-control-surface'], .5), [tokens['--ui-control-surface']], 4.5, ink);
|
|
184
232
|
tokens['--ui-control-border'] = readableColour(mix(tokens['--ui-text'], tokens['--ui-surface-raised'], .43), readingSurfaces, 3, ink);
|
|
185
233
|
tokens['--ui-control-border-hover'] = tokens['--ui-control-border'];
|
|
186
234
|
tokens['--ui-border-strong'] = tokens['--ui-control-border'];
|
|
@@ -212,8 +260,14 @@ export function themeCSS(input, systemCSS = '', { scope = 'portable' } = {}) {
|
|
|
212
260
|
else geometry.push(` ${name}: ${value};`);
|
|
213
261
|
}
|
|
214
262
|
const geometrySelector = scope === 'documentation' ? ':root[data-looma-documentation-theme]' : ':root';
|
|
263
|
+
const chevron = color => `url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='${color.replace('#', '%23')}' stroke-width='2.25' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E")`;
|
|
264
|
+
const boundary = mode => scope === 'documentation'
|
|
265
|
+
? `:root[data-looma-documentation-theme][data-theme="${mode}"], :root[data-looma-documentation-theme] [data-theme="${mode}"]`
|
|
266
|
+
: `[data-theme="${mode}"]`;
|
|
267
|
+
const chevrons = `${geometrySelector} { --ui-select-chevron: ${chevron(light['--ui-text-secondary'])}; }\n@media (prefers-color-scheme: dark) { ${geometrySelector}:not([data-theme]) { --ui-select-chevron: ${chevron(dark['--ui-text-secondary'])}; } }\n${boundary('light')} { --ui-select-chevron: ${chevron(light['--ui-text-secondary'])}; }\n${boundary('dark')} { --ui-select-chevron: ${chevron(dark['--ui-text-secondary'])}; }`;
|
|
268
|
+
|
|
215
269
|
// Resolve colors at their point of use, so a nearer mode boundary wins independently
|
|
216
270
|
// of the selector specificity needed to restore an early documentation theme.
|
|
217
271
|
// Keep the first comment stable: the local writer recognizes its generated files by this marker.
|
|
218
|
-
return `/* Looma shared semantic theme. */\n/* Always includes light and dark.\n Set data-theme="light" or "dark" on any element to fix that subtree's mode.\n Leave the root attribute unset to follow the system; a switch can set/remove it. */\n${systemCSS}\n${geometrySelector} {\n${geometry.join('\n')}\n}\n${selector} {\n${palette.join('\n')}\n}\n:root:not([data-theme]) { color-scheme: light dark; }\n[data-theme="light"] { color-scheme: light; }\n[data-theme="dark"] { color-scheme: dark; }\n@media (prefers-reduced-motion: reduce) {\n ${selector} { --ui-motion-fast: 0ms; --ui-motion-base: 0ms; --ui-motion-press: 0ms; --ui-press-scale: 1; }\n}\n`;
|
|
272
|
+
return `/* Looma shared semantic theme. */\n/* Always includes light and dark.\n Set data-theme="light" or "dark" on any element to fix that subtree's mode.\n Leave the root attribute unset to follow the system; a switch can set/remove it. */\n${systemCSS}\n${geometrySelector} {\n${geometry.join('\n')}\n}\n${selector} {\n${palette.join('\n')}\n}\n${chevrons}\n:root:not([data-theme]) { color-scheme: light dark; }\n[data-theme="light"] { color-scheme: light; }\n[data-theme="dark"] { color-scheme: dark; }\n@media (prefers-reduced-motion: reduce) {\n ${selector} { --ui-motion-fast: 0ms; --ui-motion-base: 0ms; --ui-motion-press: 0ms; --ui-press-scale: 1; }\n}\n@media (prefers-reduced-transparency: reduce), (forced-colors: active) {\n ${selector} { --ui-finish: 0; --ui-glow: 0; }\n}\n`;
|
|
219
273
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@threadlabs/looma",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.35.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Looma components as HTML, Vue, and plain DOM, with design tokens.",
|
|
6
6
|
"license": "MIT",
|
|
@@ -127,7 +127,7 @@
|
|
|
127
127
|
"@tiptap/pm": ">=2 <3",
|
|
128
128
|
"@tiptap/vue-3": ">=2 <3",
|
|
129
129
|
"vue": "^3.5.43",
|
|
130
|
-
"markupress": "^0.8.
|
|
130
|
+
"markupress": "^0.8.5",
|
|
131
131
|
"@nextwebwg/htmlkit": "1.0.0-alpha.69",
|
|
132
132
|
"vite": "^8.3.4"
|
|
133
133
|
},
|
package/styles/ui-badge.css
CHANGED
|
@@ -295,10 +295,18 @@
|
|
|
295
295
|
box-shadow: none;
|
|
296
296
|
}
|
|
297
297
|
|
|
298
|
-
/* Neutral reverses a subtle surface/ink pair rather than a strong tone. Keep its original
|
|
299
|
-
surface ink: moving it toward dark-theme primary text would reduce overlay contrast. */
|
|
300
298
|
:scope:where([data-component~="ui-badge"])[data-ui-badge-state~="variant=inverse"][data-ui-badge-state~="tone=neutral"] {
|
|
301
|
-
|
|
299
|
+
--_badge-outline-surface: var(--ui-badge-surface, var(--_badge-color-surface, color-mix(in srgb, var(--ui-surface-raised) 88%, transparent)));
|
|
300
|
+
color: var(--ui-badge-text, var(--_badge-color-text, var(--ui-text-primary)));
|
|
301
|
+
}
|
|
302
|
+
:scope:where([data-component~="ui-badge"])[data-ui-badge-state~="variant=inverse"][data-ui-badge-state~="tone=neutral"]:not([data-ui-badge-state~="shape=circle"]) {
|
|
303
|
+
border-color: var(--ui-badge-border, var(--_badge-color-border, var(--_badge-outline-surface)));
|
|
304
|
+
}
|
|
305
|
+
:scope:where([data-component~="ui-badge"])[data-ui-badge-state~="variant=inverse"][data-ui-badge-state~="tone=neutral"][data-ui-badge-state~="shape=circle"] {
|
|
306
|
+
--_badge-outline-surface: var(--ui-badge-surface, var(--_badge-color-surface, light-dark(
|
|
307
|
+
color-mix(in srgb, var(--ui-surface-raised) var(--ui-badge-circle-opacity, 66%), transparent),
|
|
308
|
+
color-mix(in srgb, var(--ui-surface-raised) var(--ui-badge-circle-opacity, 56%), transparent)
|
|
309
|
+
)));
|
|
302
310
|
}
|
|
303
311
|
|
|
304
312
|
:scope:where([data-component~="ui-badge"])[data-ui-badge-state~="variant=outline"] {
|
|
@@ -542,9 +550,6 @@
|
|
|
542
550
|
/* A count can keep its containing control's contrasting ink instead of reversing it.
|
|
543
551
|
The faint fill preserves text contrast; a quiet boundary separates the count from its control. */
|
|
544
552
|
|
|
545
|
-
/* Neutral reverses a subtle surface/ink pair rather than a strong tone. Keep its original
|
|
546
|
-
surface ink: moving it toward dark-theme primary text would reduce overlay contrast. */
|
|
547
|
-
|
|
548
553
|
/* An icon mark keeps the existing tone recipe and follows the global spacing and radius. */
|
|
549
554
|
|
|
550
555
|
:scope:where([data-component~="ui-badge"])[data-ui-badge-state~="shape=square"] .label :where([data-slotted], [data-slotted] *):is(svg) {
|
package/styles/ui-button.css
CHANGED
|
@@ -84,7 +84,7 @@
|
|
|
84
84
|
:scope:where([data-component~="ui-button"]) {
|
|
85
85
|
/* Optional inherited action-group values keep text and icon actions under the same light.
|
|
86
86
|
One fine top/start highlight follows the bottom/end lowlight at a joined action seam.
|
|
87
|
-
|
|
87
|
+
The shared theme supplies reflections and glow independently of the resting lift. */
|
|
88
88
|
--_ui-action-start: 1px;
|
|
89
89
|
--_ui-action-edge: var(
|
|
90
90
|
--ui-action-edge,
|
|
@@ -92,6 +92,8 @@
|
|
|
92
92
|
inset calc(-1 * var(--_ui-action-start)) -1px 0 light-dark(rgb(0 0 0 / 0.08), rgb(0 0 0 / 0.08))
|
|
93
93
|
);
|
|
94
94
|
--_ui-action-shadow: var(--_ui-action-edge), 0 1px 2px light-dark(rgb(0 0 0 / 0.10), rgb(0 0 0 / 0.20));
|
|
95
|
+
--_tone-highlight: var(--ui-accent-highlight, none);
|
|
96
|
+
--_tone-glow: var(--ui-accent-glow, 0 0 transparent);
|
|
95
97
|
--_hue: var(--ui-accent);
|
|
96
98
|
--_hue-hover: var(--ui-accent-hover);
|
|
97
99
|
--_hue-active: var(--ui-accent-active);
|
|
@@ -142,8 +144,8 @@
|
|
|
142
144
|
white-space: var(--ui-button-white-space, inherit);
|
|
143
145
|
line-height: var(--ui-line-height-tight);
|
|
144
146
|
padding: var(--ui-control-inset-block-md, var(--ui-space-2)) var(--ui-action-inset-md, var(--ui-space-3)) !important;
|
|
145
|
-
background-image: none;
|
|
146
|
-
box-shadow: var(--ui-button-shadow, var(--ui-action-shadow, var(--_ui-action-shadow)));
|
|
147
|
+
background-image: var(--ui-surface-highlight, none);
|
|
148
|
+
box-shadow: var(--ui-button-shadow, var(--ui-action-shadow, var(--_ui-action-shadow))), var(--_tone-glow);
|
|
147
149
|
cursor: pointer;
|
|
148
150
|
transition:
|
|
149
151
|
scale var(--ui-motion-press, var(--ui-motion-fast)) var(--ui-motion-ease),
|
|
@@ -275,7 +277,8 @@
|
|
|
275
277
|
border-color: var(--_tone);
|
|
276
278
|
background-color: var(--_tone);
|
|
277
279
|
color: var(--_on-tone);
|
|
278
|
-
|
|
280
|
+
background-image: var(--_tone-highlight);
|
|
281
|
+
box-shadow: var(--ui-button-solid-shadow, var(--ui-action-shadow, var(--_ui-action-shadow))), var(--_tone-glow);
|
|
279
282
|
}
|
|
280
283
|
|
|
281
284
|
:is(:scope:where([data-component~="ui-button"])[data-appearance="solid"], :scope:where([data-component~="ui-button"])[data-appearance="danger"]):hover:not(:disabled, [aria-disabled="true"]) {
|
|
@@ -293,6 +296,8 @@
|
|
|
293
296
|
/* Tone is the colour, variant is the volume. Every pairing works: a danger outline is a
|
|
294
297
|
destructive secondary action, not a special case. */
|
|
295
298
|
:scope:where([data-component~="ui-button"])[data-tone="neutral"] {
|
|
299
|
+
--_tone-highlight: var(--ui-neutral-highlight, none);
|
|
300
|
+
--_tone-glow: var(--ui-neutral-glow, 0 0 transparent);
|
|
296
301
|
--_hue: var(--ui-text);
|
|
297
302
|
--_hue-hover: var(--ui-text);
|
|
298
303
|
--_hue-active: var(--ui-text);
|
|
@@ -300,7 +305,21 @@
|
|
|
300
305
|
--_on-hue: var(--ui-surface);
|
|
301
306
|
}
|
|
302
307
|
|
|
308
|
+
:scope:where([data-component~="ui-button"])[data-tone="neutral"][data-appearance="solid"] {
|
|
309
|
+
border-color: var(--ui-button-border, var(--ui-control-border));
|
|
310
|
+
background-color: var(--ui-button-surface, var(--ui-neutral-surface));
|
|
311
|
+
color: var(--ui-button-text, var(--ui-text));
|
|
312
|
+
}
|
|
313
|
+
:scope:where([data-component~="ui-button"])[data-tone="neutral"][data-appearance="solid"]:hover:not(:disabled, [aria-disabled="true"]) {
|
|
314
|
+
background-color: var(--ui-button-hover-surface, var(--ui-neutral-hover));
|
|
315
|
+
}
|
|
316
|
+
:scope:where([data-component~="ui-button"])[data-tone="neutral"][data-appearance="solid"]:active:not(:disabled, [aria-disabled="true"]) {
|
|
317
|
+
background-color: var(--ui-button-active-surface, var(--ui-neutral-active));
|
|
318
|
+
}
|
|
319
|
+
|
|
303
320
|
:scope:where([data-component~="ui-button"])[data-tone="danger"], :scope:where([data-component~="ui-button"])[data-appearance="danger"] {
|
|
321
|
+
--_tone-highlight: var(--ui-danger-highlight, none);
|
|
322
|
+
--_tone-glow: var(--ui-danger-glow, 0 0 transparent);
|
|
304
323
|
--_hue: var(--ui-danger);
|
|
305
324
|
--_hue-hover: var(--ui-danger-hover);
|
|
306
325
|
--_hue-active: var(--ui-danger-active, var(--ui-danger-hover));
|
|
@@ -309,6 +328,8 @@
|
|
|
309
328
|
}
|
|
310
329
|
|
|
311
330
|
:scope:where([data-component~="ui-button"])[data-tone="success"] {
|
|
331
|
+
--_tone-highlight: var(--ui-success-highlight, none);
|
|
332
|
+
--_tone-glow: var(--ui-success-glow, 0 0 transparent);
|
|
312
333
|
--_hue: var(--ui-success);
|
|
313
334
|
--_hue-hover: var(--ui-success-hover);
|
|
314
335
|
--_hue-active: var(--ui-success-active);
|
|
@@ -317,6 +338,8 @@
|
|
|
317
338
|
}
|
|
318
339
|
|
|
319
340
|
:scope:where([data-component~="ui-button"])[data-tone="warning"] {
|
|
341
|
+
--_tone-highlight: var(--ui-warning-highlight, none);
|
|
342
|
+
--_tone-glow: var(--ui-warning-glow, 0 0 transparent);
|
|
320
343
|
--_hue: var(--ui-warning);
|
|
321
344
|
--_hue-hover: var(--ui-warning-hover);
|
|
322
345
|
--_hue-active: var(--ui-warning-active);
|
|
@@ -325,6 +348,8 @@
|
|
|
325
348
|
}
|
|
326
349
|
|
|
327
350
|
:scope:where([data-component~="ui-button"])[data-tone="info"] {
|
|
351
|
+
--_tone-highlight: var(--ui-info-highlight, none);
|
|
352
|
+
--_tone-glow: var(--ui-info-glow, 0 0 transparent);
|
|
328
353
|
--_hue: var(--ui-info);
|
|
329
354
|
--_hue-hover: var(--ui-info-hover);
|
|
330
355
|
--_hue-active: var(--ui-info-active);
|
package/styles/ui-card.css
CHANGED
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
needs no layout of its own. */
|
|
12
12
|
:scope:where([data-component~="ui-card"]) {
|
|
13
13
|
--_ui-card-surface: var(--ui-surface-raised);
|
|
14
|
+
--_ui-card-elevation: 0 0 0 transparent;
|
|
14
15
|
--_ui-selection-context-surface: initial;
|
|
15
16
|
--_ui-selection-context-border: initial;
|
|
16
17
|
--_ui-selection-context-text: initial;
|
|
@@ -45,33 +46,36 @@
|
|
|
45
46
|
}
|
|
46
47
|
|
|
47
48
|
:scope:where([data-component~="ui-card"])[data-ui-card-state~="variant=elevated"] {
|
|
49
|
+
--_ui-card-elevation: var(--ui-shadow-lg);
|
|
48
50
|
border-color: var(--ui-border-subtle);
|
|
49
51
|
box-shadow: var(--ui-shadow-lg);
|
|
50
52
|
}
|
|
51
53
|
|
|
52
|
-
:scope:where([data-component~="ui-card"])[data-ui-card-state~="
|
|
54
|
+
:scope:where([data-component~="ui-card"])[data-ui-card-state~="treatment=expressive"] {
|
|
53
55
|
--_ui-panel-glass: clamp(0, var(--ui-glassiness, 0), 1);
|
|
54
56
|
--_ui-panel-separation: clamp(0, var(--ui-surface-separation, 0), 1);
|
|
55
57
|
--_ui-panel-rim: calc((var(--_ui-panel-separation) + var(--_ui-panel-glass) * 0.25) * 0.65 * 8px);
|
|
56
58
|
border-width: calc(var(--ui-border-width) + var(--_ui-panel-rim));
|
|
57
59
|
border-color: transparent;
|
|
58
60
|
background:
|
|
61
|
+
var(--ui-surface-highlight, linear-gradient(transparent, transparent)) padding-box,
|
|
59
62
|
linear-gradient(var(--_ui-card-surface), var(--_ui-card-surface)) padding-box,
|
|
60
63
|
linear-gradient(var(--ui-material-glass, var(--ui-surface-raised)), var(--ui-material-glass, var(--ui-surface-raised))) border-box,
|
|
61
64
|
var(--_ui-card-surface) padding-box;
|
|
62
65
|
box-shadow:
|
|
63
|
-
var(--
|
|
66
|
+
var(--_ui-card-elevation),
|
|
67
|
+
var(--ui-material-glow, 0 0 transparent),
|
|
64
68
|
inset 0 0 0 var(--ui-border-width) var(--ui-material-edge, var(--ui-border-strong));
|
|
65
69
|
backdrop-filter: blur(calc(var(--_ui-panel-glass) * 0.65 * 18px)) saturate(calc(1 + var(--_ui-panel-glass) * 0.65 * 0.18));
|
|
66
70
|
-webkit-backdrop-filter: blur(calc(var(--_ui-panel-glass) * 0.65 * 18px)) saturate(calc(1 + var(--_ui-panel-glass) * 0.65 * 0.18));
|
|
67
71
|
}
|
|
68
72
|
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
|
|
69
|
-
:scope:where([data-component~="ui-card"])[data-ui-card-state~="
|
|
73
|
+
:scope:where([data-component~="ui-card"])[data-ui-card-state~="treatment=expressive"] {
|
|
70
74
|
background: var(--_ui-card-surface);
|
|
71
75
|
}
|
|
72
76
|
}
|
|
73
77
|
@media (prefers-reduced-transparency: reduce) {
|
|
74
|
-
:scope:where([data-component~="ui-card"])[data-ui-card-state~="
|
|
78
|
+
:scope:where([data-component~="ui-card"])[data-ui-card-state~="treatment=expressive"] {
|
|
75
79
|
background: var(--_ui-card-surface);
|
|
76
80
|
border-width: var(--ui-border-width);
|
|
77
81
|
border-color: var(--ui-border-strong);
|
|
@@ -80,7 +84,7 @@
|
|
|
80
84
|
}
|
|
81
85
|
}
|
|
82
86
|
@media (forced-colors: active) {
|
|
83
|
-
:scope:where([data-component~="ui-card"])[data-ui-card-state~="
|
|
87
|
+
:scope:where([data-component~="ui-card"])[data-ui-card-state~="treatment=expressive"] {
|
|
84
88
|
background: Canvas;
|
|
85
89
|
color: CanvasText;
|
|
86
90
|
border: var(--ui-border-width) solid CanvasText;
|
|
@@ -116,10 +120,6 @@
|
|
|
116
120
|
|
|
117
121
|
:scope:where([data-component~="ui-card"])[data-ui-card-state~="tone=danger"] {
|
|
118
122
|
border-color: color-mix(in srgb, var(--ui-danger) 45%, var(--ui-border-default));
|
|
119
|
-
border-inline-start: var(--ui-accent-line-width) solid var(--ui-danger);
|
|
120
|
-
/* An accent edge keeps the corners on its side straight. */
|
|
121
|
-
border-start-start-radius: 0;
|
|
122
|
-
border-end-start-radius: 0;
|
|
123
123
|
--_ui-card-surface: var(--ui-danger-soft);
|
|
124
124
|
}
|
|
125
125
|
|
package/styles/ui-checkbox.css
CHANGED
|
@@ -91,7 +91,8 @@
|
|
|
91
91
|
margin: max(0px, calc((1lh - var(--_ui-checkbox-size, 1.125rem)) / 2)) 0 0 !important;
|
|
92
92
|
border: var(--ui-border-width) solid var(--ui-control-border, var(--ui-border-strong));
|
|
93
93
|
border-radius: min(var(--ui-radius-sm), calc(var(--_ui-checkbox-size, 1.125rem) / 4));
|
|
94
|
-
background: var(--ui-control-surface, var(--ui-surface-default));
|
|
94
|
+
background-color: var(--ui-control-surface, var(--ui-surface-default));
|
|
95
|
+
background-image: var(--ui-surface-highlight, none);
|
|
95
96
|
box-shadow: var(--ui-control-inset);
|
|
96
97
|
cursor: pointer;
|
|
97
98
|
transition:
|
|
@@ -110,7 +111,8 @@
|
|
|
110
111
|
input:checked,
|
|
111
112
|
input:indeterminate {
|
|
112
113
|
border-color: var(--ui-accent-solid);
|
|
113
|
-
background: var(--ui-accent-solid);
|
|
114
|
+
background-color: var(--ui-accent-solid);
|
|
115
|
+
background-image: var(--ui-accent-highlight, none);
|
|
114
116
|
box-shadow: var(--ui-control-inset);
|
|
115
117
|
}
|
|
116
118
|
|
package/styles/ui-dialog.css
CHANGED
|
@@ -81,6 +81,7 @@
|
|
|
81
81
|
--_ui-material-content-color: var(--ui-dialog-surface, var(--ui-material-content, var(--ui-overlay-surface, var(--ui-surface-elevated))));
|
|
82
82
|
--_ui-material-rim-color: color-mix(in srgb, var(--ui-material-glass, var(--ui-surface-elevated)) calc(var(--_ui-material-active) * 100%), transparent);
|
|
83
83
|
background:
|
|
84
|
+
var(--ui-surface-highlight, linear-gradient(transparent, transparent)) padding-box,
|
|
84
85
|
linear-gradient(var(--_ui-material-content-color), var(--_ui-material-content-color)) padding-box,
|
|
85
86
|
linear-gradient(var(--_ui-material-rim-color), var(--_ui-material-rim-color)) border-box,
|
|
86
87
|
var(--_ui-material-content-color) padding-box;
|
|
@@ -96,6 +97,7 @@
|
|
|
96
97
|
0 calc(var(--_ui-material-separation) * var(--_ui-material-scale, 1) * 8px) calc(
|
|
97
98
|
var(--_ui-material-separation) * var(--_ui-material-scale, 1) * 24px
|
|
98
99
|
) color-mix(in oklab, var(--ui-text-primary) 15%, transparent),
|
|
100
|
+
var(--ui-material-glow, 0 0 transparent),
|
|
99
101
|
inset 0 0 0 calc(var(--_ui-material-active) * var(--ui-border-width)) var(--ui-material-edge, var(--ui-border-strong)),
|
|
100
102
|
var(--ui-elevation-dialog, var(--ui-shadow-xl))
|
|
101
103
|
)
|
|
@@ -400,6 +402,7 @@
|
|
|
400
402
|
--_ui-material-content-color: var(--ui-dialog-surface, var(--ui-material-content, var(--ui-overlay-surface, var(--ui-surface-elevated))));
|
|
401
403
|
--_ui-material-rim-color: color-mix(in srgb, var(--ui-material-glass, var(--ui-surface-elevated)) calc(var(--_ui-material-active) * 100%), transparent);
|
|
402
404
|
background:
|
|
405
|
+
var(--ui-surface-highlight, linear-gradient(transparent, transparent)) padding-box,
|
|
403
406
|
linear-gradient(var(--_ui-material-content-color), var(--_ui-material-content-color)) padding-box,
|
|
404
407
|
linear-gradient(var(--_ui-material-rim-color), var(--_ui-material-rim-color)) border-box,
|
|
405
408
|
var(--_ui-material-content-color) padding-box;
|
|
@@ -415,6 +418,7 @@
|
|
|
415
418
|
0 calc(var(--_ui-material-separation) * var(--_ui-material-scale, 1) * 8px) calc(
|
|
416
419
|
var(--_ui-material-separation) * var(--_ui-material-scale, 1) * 24px
|
|
417
420
|
) color-mix(in oklab, var(--ui-text-primary) 15%, transparent),
|
|
421
|
+
var(--ui-material-glow, 0 0 transparent),
|
|
418
422
|
inset 0 0 0 calc(var(--_ui-material-active) * var(--ui-border-width)) var(--ui-material-edge, var(--ui-border-strong)),
|
|
419
423
|
var(--ui-elevation-dialog, var(--ui-shadow-xl))
|
|
420
424
|
)
|
|
@@ -88,7 +88,9 @@
|
|
|
88
88
|
:scope:where([data-component~="ui-icon-button"]) {
|
|
89
89
|
/* Optional inherited action-group values keep text and icon actions under the same light.
|
|
90
90
|
One fine top/start highlight follows the bottom/end lowlight at a joined action seam.
|
|
91
|
-
|
|
91
|
+
The shared theme supplies reflections and glow independently of the resting lift. */
|
|
92
|
+
--_tone-highlight: var(--ui-accent-highlight, none);
|
|
93
|
+
--_tone-glow: var(--ui-accent-glow, 0 0 transparent);
|
|
92
94
|
--_ui-action-start: 1px;
|
|
93
95
|
--_ui-action-edge: var(
|
|
94
96
|
--ui-action-edge,
|
|
@@ -109,6 +111,8 @@
|
|
|
109
111
|
}
|
|
110
112
|
|
|
111
113
|
:scope:where([data-component~="ui-icon-button"])[data-tone="accent"] {
|
|
114
|
+
--_tone-highlight: var(--ui-accent-highlight, none);
|
|
115
|
+
--_tone-glow: var(--ui-accent-glow, 0 0 transparent);
|
|
112
116
|
--_icon-button-border: var(--ui-accent-solid);
|
|
113
117
|
--_icon-button-hover-border: var(--ui-accent-hover);
|
|
114
118
|
--_icon-button-text: var(--ui-accent-subtle-text, var(--ui-accent-solid));
|
|
@@ -117,6 +121,8 @@
|
|
|
117
121
|
}
|
|
118
122
|
|
|
119
123
|
:scope:where([data-component~="ui-icon-button"])[data-tone="danger"] {
|
|
124
|
+
--_tone-highlight: var(--ui-danger-highlight, none);
|
|
125
|
+
--_tone-glow: var(--ui-danger-glow, 0 0 transparent);
|
|
120
126
|
--_icon-button-border: var(--ui-danger);
|
|
121
127
|
--_icon-button-hover-border: var(--ui-danger-hover);
|
|
122
128
|
--_icon-button-text: var(--ui-danger-subtle-text);
|
|
@@ -128,6 +134,8 @@
|
|
|
128
134
|
}
|
|
129
135
|
|
|
130
136
|
:scope:where([data-component~="ui-icon-button"])[data-tone="success"] {
|
|
137
|
+
--_tone-highlight: var(--ui-success-highlight, none);
|
|
138
|
+
--_tone-glow: var(--ui-success-glow, 0 0 transparent);
|
|
131
139
|
--_icon-button-border: var(--ui-success);
|
|
132
140
|
--_icon-button-hover-border: var(--ui-success-hover);
|
|
133
141
|
--_icon-button-text: var(--ui-success-subtle-text);
|
|
@@ -139,6 +147,8 @@
|
|
|
139
147
|
}
|
|
140
148
|
|
|
141
149
|
:scope:where([data-component~="ui-icon-button"])[data-tone="warning"] {
|
|
150
|
+
--_tone-highlight: var(--ui-warning-highlight, none);
|
|
151
|
+
--_tone-glow: var(--ui-warning-glow, 0 0 transparent);
|
|
142
152
|
--_icon-button-border: var(--ui-warning);
|
|
143
153
|
--_icon-button-hover-border: var(--ui-warning-hover);
|
|
144
154
|
--_icon-button-text: var(--ui-warning-subtle-text);
|
|
@@ -150,6 +160,8 @@
|
|
|
150
160
|
}
|
|
151
161
|
|
|
152
162
|
:scope:where([data-component~="ui-icon-button"])[data-tone="info"] {
|
|
163
|
+
--_tone-highlight: var(--ui-info-highlight, none);
|
|
164
|
+
--_tone-glow: var(--ui-info-glow, 0 0 transparent);
|
|
153
165
|
--_icon-button-border: var(--ui-info);
|
|
154
166
|
--_icon-button-hover-border: var(--ui-info-hover);
|
|
155
167
|
--_icon-button-text: var(--ui-info-subtle-text);
|
|
@@ -162,9 +174,11 @@
|
|
|
162
174
|
|
|
163
175
|
/* Omitted tone retains the existing accent solid; explicit neutral is additive. */
|
|
164
176
|
:scope:where([data-component~="ui-icon-button"])[data-tone="neutral"] {
|
|
165
|
-
--
|
|
166
|
-
--
|
|
167
|
-
--_icon-button-solid-
|
|
177
|
+
--_tone-highlight: var(--ui-neutral-highlight, none);
|
|
178
|
+
--_tone-glow: var(--ui-neutral-glow, 0 0 transparent);
|
|
179
|
+
--_icon-button-solid-surface: var(--ui-neutral-surface);
|
|
180
|
+
--_icon-button-solid-hover-surface: var(--ui-neutral-hover);
|
|
181
|
+
--_icon-button-solid-text: var(--ui-text);
|
|
168
182
|
}
|
|
169
183
|
|
|
170
184
|
:scope:where([data-component~="ui-icon-button"])[data-ui-icon-button-state~="anticipatory"] {
|
|
@@ -332,16 +346,16 @@
|
|
|
332
346
|
:scope:where([data-component~="ui-icon-button"])[data-appearance="outline"] {
|
|
333
347
|
border-color: var(--ui-icon-button-border, var(--_icon-button-border, var(--ui-control-border, var(--ui-border-strong))));
|
|
334
348
|
background-color: var(--ui-icon-button-outline-surface, var(--_icon-button-outline-surface, var(--ui-surface-default)));
|
|
335
|
-
background-image: none;
|
|
349
|
+
background-image: var(--ui-surface-highlight, none);
|
|
336
350
|
color: var(--ui-icon-button-outline-text, var(--_icon-button-text, var(--ui-text-primary)));
|
|
337
|
-
box-shadow: var(--ui-action-shadow, var(--_ui-action-shadow));
|
|
351
|
+
box-shadow: var(--ui-action-shadow, var(--_ui-action-shadow)), var(--_tone-glow);
|
|
338
352
|
}
|
|
339
353
|
|
|
340
354
|
:scope:where([data-component~="ui-icon-button"])[data-appearance="solid"] {
|
|
341
355
|
background-color: var(--ui-icon-button-solid-surface, var(--_icon-button-solid-surface, var(--ui-accent-solid)));
|
|
342
|
-
background-image:
|
|
356
|
+
background-image: var(--_tone-highlight);
|
|
343
357
|
color: var(--ui-icon-button-solid-text, var(--_icon-button-solid-text, var(--ui-text-on-accent)));
|
|
344
|
-
box-shadow: var(--ui-icon-button-solid-shadow, var(--ui-action-shadow, var(--_ui-action-shadow)));
|
|
358
|
+
box-shadow: var(--ui-icon-button-solid-shadow, var(--ui-action-shadow, var(--_ui-action-shadow))), var(--_tone-glow);
|
|
345
359
|
}
|
|
346
360
|
|
|
347
361
|
:scope:where([data-component~="ui-icon-button"]):hover:enabled:not([aria-disabled="true"]) {
|
|
@@ -42,6 +42,7 @@
|
|
|
42
42
|
--_ui-default-input-focus-outline: none;
|
|
43
43
|
--_ui-default-input-radius: 0;
|
|
44
44
|
--_ui-default-input-surface: transparent;
|
|
45
|
+
--_ui-default-input-highlight: none;
|
|
45
46
|
--_ui-default-textarea-border-width: 0;
|
|
46
47
|
--_ui-default-textarea-border: transparent;
|
|
47
48
|
--_ui-default-textarea-border-hover: transparent;
|
|
@@ -53,6 +54,7 @@
|
|
|
53
54
|
--_ui-default-textarea-focus-outline: none;
|
|
54
55
|
--_ui-default-textarea-radius: 0;
|
|
55
56
|
--_ui-default-textarea-surface: transparent;
|
|
57
|
+
--_ui-default-textarea-highlight: none;
|
|
56
58
|
|
|
57
59
|
display: flex !important;
|
|
58
60
|
align-items: stretch !important;
|
|
@@ -63,7 +65,8 @@
|
|
|
63
65
|
/* The frame reads the shared control tokens with a lone Input's fallbacks, so the two match. */
|
|
64
66
|
border: var(--ui-border-width) solid var(--ui-control-border, var(--ui-border-strong));
|
|
65
67
|
border-radius: var(--ui-input-group-radius, var(--ui-field-radius, var(--ui-radius-md)));
|
|
66
|
-
background: var(--ui-control-surface, var(--ui-surface-elevated));
|
|
68
|
+
background-color: var(--ui-control-surface, var(--ui-surface-elevated));
|
|
69
|
+
background-image: var(--ui-surface-highlight, none);
|
|
67
70
|
box-shadow: var(--ui-control-inset);
|
|
68
71
|
overflow: hidden;
|
|
69
72
|
/* A press anywhere in the frame focuses the input. */
|
package/styles/ui-input.css
CHANGED
|
@@ -75,7 +75,8 @@
|
|
|
75
75
|
border: var(--ui-input-border-width, var(--_ui-default-input-border-width, var(--ui-border-width))) solid
|
|
76
76
|
var(--ui-input-border, var(--_ui-default-input-border, var(--ui-control-border, var(--ui-border-strong))));
|
|
77
77
|
border-radius: var(--ui-input-radius, var(--_ui-default-input-radius, var(--ui-field-radius, var(--ui-radius-md))));
|
|
78
|
-
background: var(--ui-input-surface, var(--_ui-default-input-surface, var(--ui-control-surface, var(--ui-surface-elevated))));
|
|
78
|
+
background-color: var(--ui-input-surface, var(--_ui-default-input-surface, var(--ui-control-surface, var(--ui-surface-elevated))));
|
|
79
|
+
background-image: var(--_ui-default-input-highlight, var(--ui-surface-highlight, none));
|
|
79
80
|
color: var(--ui-text-primary);
|
|
80
81
|
font: inherit;
|
|
81
82
|
line-height: var(--ui-line-height-tight);
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/* Generated by HTML Next 1.0.0-alpha.69. Do not edit. */
|
|
2
|
+
@supports (-moz-appearance: none) {
|
|
3
|
+
:where([data-component], [data-slotted]) { --html-next-scope-owner: boundary; }
|
|
4
|
+
:where([data-slotted]:not([data-component])) { --html-next-scope-owner: projected !important; }
|
|
5
|
+
}
|
|
6
|
+
@supports (-moz-appearance: none) {
|
|
7
|
+
[data-component~="ui-light-editor"] { --html-next-scope-owner: "ui-light-editor" !important; }
|
|
8
|
+
}
|
|
9
|
+
@scope ([data-component~="ui-light-editor"]) to ([data-component], [data-slotted]) {
|
|
10
|
+
:scope:where([data-component~="ui-light-editor"]) { display: grid !important; gap: var(--ui-space-3) !important; min-inline-size: 0; padding: 0 !important; margin: 0 !important; }
|
|
11
|
+
.stage { box-sizing: border-box !important; display: block !important; block-size: 13rem; padding: calc(var(--ui-control-min-block-size) / 2) !important; border: var(--ui-border-width) solid var(--ui-control-border); border-radius: var(--ui-field-radius, var(--ui-radius-md)); background: var(--ui-neutral-surface, var(--ui-surface)); }
|
|
12
|
+
.plane { position: relative; display: block !important; inline-size: 100%; block-size: 100%; }
|
|
13
|
+
svg { inline-size: 100%; block-size: 100%; overflow: visible; }
|
|
14
|
+
path { fill: none; stroke: var(--ui-border); stroke-width: 1; vector-effect: non-scaling-stroke; }
|
|
15
|
+
.specimen { position: absolute; inset: 0; display: grid !important; place-items: center !important; }
|
|
16
|
+
.source { position: absolute; left: 50%; top: 0; translate: -50% -50%; display: grid !important; place-items: center !important; inline-size: max(2rem, var(--ui-control-min-block-size)); block-size: max(2rem, var(--ui-control-min-block-size)); padding: 0 !important; margin: 0 !important; border: 0; border-radius: 50%; background: transparent; cursor: grab; touch-action: none; }
|
|
17
|
+
.source:where(:not([data-component], [data-slotted]))::after { content: ""; inline-size: 1rem; block-size: 1rem; border: var(--ui-border-width) solid var(--ui-accent); border-radius: 50%; background: var(--ui-surface-raised); box-shadow: 0 0 0 var(--ui-space-2) color-mix(in srgb, var(--ui-accent) 12%, transparent), var(--ui-shadow-sm); }
|
|
18
|
+
.source:active { cursor: grabbing; }
|
|
19
|
+
.source:focus-visible { outline: var(--ui-focus-width) solid var(--ui-focus-ring); outline-offset: var(--ui-space-1); }
|
|
20
|
+
.source:disabled { cursor: not-allowed; }
|
|
21
|
+
.source:disabled:where(:not([data-component], [data-slotted]))::after { background: var(--ui-disabled-surface); border-color: var(--ui-disabled-border); box-shadow: none; }
|
|
22
|
+
.coordinates { display: grid !important; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: var(--ui-space-2) !important; }
|
|
23
|
+
.hint { font-size: var(--ui-font-size-sm); color: var(--ui-text-secondary); }
|
|
24
|
+
@media (forced-colors: active) { .source:where(:not([data-component], [data-slotted]))::after { background: Canvas; border-color: CanvasText; } .source:focus-visible { outline-color: Highlight; } }
|
|
25
|
+
}
|
|
26
|
+
@scope ([data-component~="ui-light-editor"]) to ([data-component]) {
|
|
27
|
+
@media (forced-colors: active) { }
|
|
28
|
+
}
|
package/styles/ui-menu.css
CHANGED
|
@@ -110,6 +110,7 @@
|
|
|
110
110
|
--_ui-material-content-color: var(--_ui-menu-surface, var(--ui-material-content, var(--ui-overlay-surface, var(--ui-surface-elevated))));
|
|
111
111
|
--_ui-material-rim-color: color-mix(in srgb, var(--ui-material-glass, var(--ui-surface-elevated)) calc(var(--_ui-material-active) * 100%), transparent);
|
|
112
112
|
background:
|
|
113
|
+
var(--ui-surface-highlight, linear-gradient(transparent, transparent)) padding-box,
|
|
113
114
|
linear-gradient(var(--_ui-material-content-color), var(--_ui-material-content-color)) padding-box,
|
|
114
115
|
linear-gradient(var(--_ui-material-rim-color), var(--_ui-material-rim-color)) border-box,
|
|
115
116
|
var(--_ui-material-content-color) padding-box;
|
|
@@ -125,6 +126,7 @@
|
|
|
125
126
|
0 calc(var(--_ui-material-separation) * var(--_ui-material-scale, 0.28) * 8px) calc(
|
|
126
127
|
var(--_ui-material-separation) * var(--_ui-material-scale, 0.28) * 24px
|
|
127
128
|
) color-mix(in oklab, var(--ui-text-primary) 15%, transparent),
|
|
129
|
+
var(--ui-material-glow, 0 0 transparent),
|
|
128
130
|
inset 0 0 0 calc(var(--_ui-material-active) * var(--ui-border-width)) var(--ui-material-edge, var(--ui-border-strong)),
|
|
129
131
|
var(--ui-elevation-overlay, var(--ui-shadow-lg))
|
|
130
132
|
)
|
package/styles/ui-popover.css
CHANGED
|
@@ -81,6 +81,7 @@
|
|
|
81
81
|
--_ui-material-content-color: var(--_ui-popover-surface, var(--ui-material-content, var(--ui-overlay-surface, var(--ui-surface-elevated))));
|
|
82
82
|
--_ui-material-rim-color: color-mix(in srgb, var(--ui-material-glass, var(--ui-surface-elevated)) calc(var(--_ui-material-active) * 100%), transparent);
|
|
83
83
|
background:
|
|
84
|
+
var(--ui-surface-highlight, linear-gradient(transparent, transparent)) padding-box,
|
|
84
85
|
linear-gradient(var(--_ui-material-content-color), var(--_ui-material-content-color)) padding-box,
|
|
85
86
|
linear-gradient(var(--_ui-material-rim-color), var(--_ui-material-rim-color)) border-box,
|
|
86
87
|
var(--_ui-material-content-color) padding-box;
|
|
@@ -96,6 +97,7 @@
|
|
|
96
97
|
0 calc(var(--_ui-material-separation) * var(--_ui-material-scale, 0.55) * 8px) calc(
|
|
97
98
|
var(--_ui-material-separation) * var(--_ui-material-scale, 0.55) * 24px
|
|
98
99
|
) color-mix(in oklab, var(--ui-text-primary) 15%, transparent),
|
|
100
|
+
var(--ui-material-glow, 0 0 transparent),
|
|
99
101
|
inset 0 0 0 calc(var(--_ui-material-active) * var(--ui-border-width)) var(--ui-material-edge, var(--ui-border-strong)),
|
|
100
102
|
var(--ui-elevation-overlay, var(--ui-shadow-lg))
|
|
101
103
|
)
|