@adia-ai/web-components 0.8.9 → 0.8.11
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/CHANGELOG.md +34 -0
- package/MIGRATION.md +58 -0
- package/USAGE.md +5 -7
- package/components/adia-mark/adia-mark.a2ui.json +6 -6
- package/components/adia-mark/adia-mark.class.js +1 -1
- package/components/adia-mark/adia-mark.css +3 -4
- package/components/adia-mark/adia-mark.d.ts +1 -1
- package/components/adia-mark/adia-mark.examples.md +0 -2
- package/components/adia-mark/adia-mark.test.js +3 -3
- package/components/adia-mark/adia-mark.yaml +5 -4
- package/components/adia-wordmark/adia-wordmark.a2ui.json +108 -0
- package/components/adia-wordmark/adia-wordmark.class.js +60 -0
- package/components/adia-wordmark/adia-wordmark.css +45 -0
- package/components/adia-wordmark/adia-wordmark.d.ts +20 -0
- package/components/adia-wordmark/adia-wordmark.examples.md +23 -0
- package/components/adia-wordmark/adia-wordmark.js +17 -0
- package/components/adia-wordmark/adia-wordmark.test.js +69 -0
- package/components/adia-wordmark/adia-wordmark.yaml +102 -0
- package/components/avatar/avatar-group.a2ui.json +1 -1
- package/components/avatar/avatar-group.yaml +1 -1
- package/components/avatar/avatar.a2ui.json +2 -4
- package/components/avatar/avatar.css +16 -12
- package/components/avatar/avatar.d.ts +3 -3
- package/components/avatar/avatar.examples.md +1 -1
- package/components/avatar/avatar.yaml +1 -3
- package/components/badge/badge.a2ui.json +2 -4
- package/components/badge/badge.d.ts +2 -2
- package/components/badge/badge.yaml +1 -3
- package/components/button/button.a2ui.json +2 -4
- package/components/button/button.d.ts +2 -2
- package/components/button/button.yaml +1 -3
- package/components/calendar-grid/calendar-grid.class.js +44 -27
- package/components/calendar-grid/calendar-grid.css +1 -1
- package/components/calendar-picker/calendar-picker.class.js +2 -2
- package/components/calendar-picker/calendar-picker.css +1 -1
- package/components/card/card.css +1 -1
- package/components/chat-thread/chat-input.css +1 -1
- package/components/combobox/combobox.class.js +1 -1
- package/components/combobox/combobox.css +1 -1
- package/components/icon/icon.a2ui.json +1 -1
- package/components/icon/icon.class.js +5 -5
- package/components/icon/icon.css +7 -15
- package/components/icon/icon.d.ts +1 -1
- package/components/icon/icon.examples.md +1 -1
- package/components/icon/icon.yaml +10 -10
- package/components/index.js +1 -0
- package/components/input/input.class.js +2 -2
- package/components/modal/modal.a2ui.json +2 -3
- package/components/modal/modal.d.ts +2 -2
- package/components/modal/modal.yaml +1 -2
- package/components/select/select.class.js +4 -4
- package/components/select/select.css +12 -3
- package/components/swatch/swatch.css +1 -1
- package/components/switch/switch.a2ui.json +2 -4
- package/components/switch/switch.yaml +1 -3
- package/components/table/table.yaml +9 -3
- package/components/tag/tag.a2ui.json +2 -1
- package/components/tag/tag.class.js +1 -1
- package/components/tag/tag.css +31 -5
- package/components/tag/tag.d.ts +2 -2
- package/components/tag/tag.yaml +5 -1
- package/components/theme-provider/theme-provider.a2ui.json +11 -1
- package/components/theme-provider/theme-provider.class.js +27 -7
- package/components/theme-provider/theme-provider.d.ts +2 -2
- package/components/theme-provider/theme-provider.yaml +10 -1
- package/components/timeline/timeline.css +1 -1
- package/components/toggle-scheme/toggle-scheme.a2ui.json +2 -4
- package/components/toggle-scheme/toggle-scheme.d.ts +2 -2
- package/components/toggle-scheme/toggle-scheme.yaml +1 -3
- package/dist/host.min.css +1 -1
- package/dist/host.sheet.js +1 -1
- package/dist/scale.min.css +1 -0
- package/dist/scale.sheet.js +11 -0
- package/dist/theme-provider.min.js +8 -8
- package/dist/web-components.min.css +1 -1
- package/dist/web-components.min.js +94 -86
- package/dist/web-components.sheet.js +1 -1
- package/package.json +1 -1
- package/patterns/comments-and-collaboration/comments-and-collaboration.examples.html +4 -4
- package/patterns/kanban-board/kanban-board.examples.html +8 -8
- package/patterns/notifications-bell-and-digest/notifications-bell-and-digest.examples.html +2 -2
- package/patterns/profile-public-and-verification/profile-public-and-verification.examples.html +1 -1
- package/patterns/search-discovery/search-discovery.examples.html +4 -4
- package/styles/colors/semantics/aliases.css +16 -3
- package/styles/colors/semantics/features.css +10 -0
- package/styles/components.css +1 -0
- package/styles/prose.css +4 -0
- package/styles/scale.css +683 -0
- package/styles/verse.css +4 -0
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach } from 'vitest';
|
|
2
|
+
import '../../core/element.js';
|
|
3
|
+
import './adia-wordmark.js';
|
|
4
|
+
|
|
5
|
+
const tick = () => new Promise((r) => queueMicrotask(r));
|
|
6
|
+
|
|
7
|
+
function mount(html) {
|
|
8
|
+
const wrap = document.createElement('div');
|
|
9
|
+
wrap.innerHTML = html;
|
|
10
|
+
document.body.appendChild(wrap);
|
|
11
|
+
return wrap.firstElementChild;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
describe('adia-wordmark-ui', () => {
|
|
15
|
+
beforeEach(() => { document.body.innerHTML = ''; });
|
|
16
|
+
|
|
17
|
+
it('registers adia-wordmark-ui as a custom element', () => {
|
|
18
|
+
expect(customElements.get('adia-wordmark-ui')).toBeDefined();
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it('defaults to size="md"', async () => {
|
|
22
|
+
const el = mount('<adia-wordmark-ui></adia-wordmark-ui>');
|
|
23
|
+
await tick();
|
|
24
|
+
expect(el.size).toBe('md');
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it('reflects an explicit [size]', async () => {
|
|
28
|
+
const el = mount('<adia-wordmark-ui size="lg"></adia-wordmark-ui>');
|
|
29
|
+
await tick();
|
|
30
|
+
expect(el.size).toBe('lg');
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it('defaults to inline=false and reflects an explicit [inline]', async () => {
|
|
34
|
+
const a = mount('<adia-wordmark-ui></adia-wordmark-ui>');
|
|
35
|
+
const b = mount('<adia-wordmark-ui inline></adia-wordmark-ui>');
|
|
36
|
+
await tick();
|
|
37
|
+
expect(a.inline).toBe(false);
|
|
38
|
+
expect(b.inline).toBe(true);
|
|
39
|
+
expect(b.getAttribute('inline')).toBe('');
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it('sets role="img" and a default aria-label on connect', async () => {
|
|
43
|
+
const el = mount('<adia-wordmark-ui></adia-wordmark-ui>');
|
|
44
|
+
await tick();
|
|
45
|
+
expect(el.getAttribute('role')).toBe('img');
|
|
46
|
+
expect(el.getAttribute('aria-label')).toBe('Adia');
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it('does not overwrite a consumer-authored aria-label', async () => {
|
|
50
|
+
const el = mount('<adia-wordmark-ui aria-label="Adia — home"></adia-wordmark-ui>');
|
|
51
|
+
await tick();
|
|
52
|
+
expect(el.getAttribute('aria-label')).toBe('Adia — home');
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it('stamps the wordmark SVG with five glyph paths, no consumer-content conflict', async () => {
|
|
56
|
+
const el = mount('<adia-wordmark-ui></adia-wordmark-ui>');
|
|
57
|
+
await tick();
|
|
58
|
+
const svg = el.querySelector('svg');
|
|
59
|
+
expect(svg).toBeTruthy();
|
|
60
|
+
expect(el.querySelectorAll('[data-wordmark-glyph]').length).toBe(5);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it('renders identically regardless of size — static template, no interpolation', async () => {
|
|
64
|
+
const a = mount('<adia-wordmark-ui size="sm"></adia-wordmark-ui>');
|
|
65
|
+
const b = mount('<adia-wordmark-ui size="lg"></adia-wordmark-ui>');
|
|
66
|
+
await tick();
|
|
67
|
+
expect(a.innerHTML).toBe(b.innerHTML);
|
|
68
|
+
});
|
|
69
|
+
});
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
$schema: ../../../../scripts/schemas/component.yaml.schema.json
|
|
2
|
+
name: UIAdiaWordmark
|
|
3
|
+
tag: adia-wordmark-ui
|
|
4
|
+
status: stable
|
|
5
|
+
component: AdiaWordmark
|
|
6
|
+
category: display
|
|
7
|
+
version: 1
|
|
8
|
+
description: >-
|
|
9
|
+
The Adia wordmark — the "Adia" text logotype rendered as inline SVG.
|
|
10
|
+
Unlike `adia-mark-ui` (gh#283's fixed inverse-on-inverse square tile),
|
|
11
|
+
this is a standalone mark meant to sit directly on a surface: its fill
|
|
12
|
+
defaults to the current scheme's on-surface foreground token
|
|
13
|
+
(`--a-fg-strong`) rather than a fixed inverse pairing, so it reads
|
|
14
|
+
correctly wherever it's placed — a login header, a footer, a splash
|
|
15
|
+
screen — without needing a background chip (gh#390).
|
|
16
|
+
props:
|
|
17
|
+
size:
|
|
18
|
+
description: Height of the wordmark; width follows via the fixed aspect ratio. Matches adia-mark-ui's size ladder for visual consistency when the two sit side by side.
|
|
19
|
+
type: string
|
|
20
|
+
default: md
|
|
21
|
+
enum:
|
|
22
|
+
- sm
|
|
23
|
+
- md
|
|
24
|
+
- lg
|
|
25
|
+
reflect: true
|
|
26
|
+
inline:
|
|
27
|
+
description: Renders as `display:inline-block` instead of the block-level default (ADR-0037) — set this when the wordmark sits beside a text run rather than standing alone.
|
|
28
|
+
type: boolean
|
|
29
|
+
default: false
|
|
30
|
+
reflect: true
|
|
31
|
+
events: {}
|
|
32
|
+
slots: {}
|
|
33
|
+
states:
|
|
34
|
+
- name: default
|
|
35
|
+
description: The only state — a static, non-interactive wordmark.
|
|
36
|
+
traits: []
|
|
37
|
+
tokens:
|
|
38
|
+
--adia-wordmark-height:
|
|
39
|
+
description: Height of the wordmark; width follows via aspect-ratio.
|
|
40
|
+
default: 1.5rem
|
|
41
|
+
--adia-wordmark-fg:
|
|
42
|
+
description: Wordmark fill — defaults to the on-surface foreground token. Themeable (unlike adia-mark-ui's fixed inverse pairing), since this mark already sits directly on a surface rather than owning its own background chip.
|
|
43
|
+
default: var(--a-fg-strong)
|
|
44
|
+
a2ui:
|
|
45
|
+
rules:
|
|
46
|
+
- Use <AdiaWordmark> for the Adia text logotype standing alone directly on a surface — a login/marketing header, a footer, an about panel, a splash screen with no background chip. Use <AdiaMark> instead for the square icon/tile use (app-switcher slot, favicon-style avatar).
|
|
47
|
+
- Do not wrap <AdiaWordmark> in <Icon> or pass it a color/tone override tied to an inverse pairing — it has no [name] prop, always renders the same logotype path data, and its fill is meant to track the current surface's foreground token.
|
|
48
|
+
- Prefer <AdiaWordmark size="sm"> in a nav/topbar brand slot; reserve larger sizes (lg, xl) for splash or login screens. Set [inline] only when the wordmark sits directly inside a run of prose text, not inside a Row/flex layout (block-level children compose fine as flex items already).
|
|
49
|
+
anti_patterns:
|
|
50
|
+
- wrong: |
|
|
51
|
+
<icon-ui name="adia"></icon-ui>
|
|
52
|
+
why: |
|
|
53
|
+
icon-ui only resolves Phosphor glyph names from the registry; there
|
|
54
|
+
is no "adia" Phosphor icon, and registering one would misuse a
|
|
55
|
+
third-party glyph set for a proprietary wordmark.
|
|
56
|
+
fix: |
|
|
57
|
+
<adia-wordmark-ui size="sm"></adia-wordmark-ui>
|
|
58
|
+
- wrong: |
|
|
59
|
+
<adia-mark-ui size="sm"></adia-mark-ui>
|
|
60
|
+
why: |
|
|
61
|
+
adia-mark-ui is the fixed inverse-on-inverse SQUARE TILE (gh#283) —
|
|
62
|
+
always a background chip with the wordmark cut out, sized for an
|
|
63
|
+
app-switcher/favicon slot. It is not interchangeable with the
|
|
64
|
+
standalone text logotype meant to sit directly on a surface.
|
|
65
|
+
fix: |
|
|
66
|
+
<adia-wordmark-ui size="sm"></adia-wordmark-ui>
|
|
67
|
+
examples:
|
|
68
|
+
- name: login-header-wordmark
|
|
69
|
+
description: Standalone wordmark in a login/marketing header, no background chip needed.
|
|
70
|
+
a2ui: >-
|
|
71
|
+
[
|
|
72
|
+
{
|
|
73
|
+
"id": "brand-row",
|
|
74
|
+
"component": "Row",
|
|
75
|
+
"gap": "2",
|
|
76
|
+
"align": "center",
|
|
77
|
+
"children": ["wordmark"]
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
"id": "wordmark",
|
|
81
|
+
"component": "AdiaWordmark",
|
|
82
|
+
"size": "sm"
|
|
83
|
+
}
|
|
84
|
+
]
|
|
85
|
+
keywords:
|
|
86
|
+
- adia
|
|
87
|
+
- wordmark
|
|
88
|
+
- logotype
|
|
89
|
+
- text logo
|
|
90
|
+
- identity
|
|
91
|
+
synonyms:
|
|
92
|
+
wordmark:
|
|
93
|
+
- adia
|
|
94
|
+
- logotype
|
|
95
|
+
- text logo
|
|
96
|
+
logotype:
|
|
97
|
+
- adia
|
|
98
|
+
- wordmark
|
|
99
|
+
related:
|
|
100
|
+
- AdiaMark
|
|
101
|
+
- Icon
|
|
102
|
+
- Image
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"default": 5
|
|
23
23
|
},
|
|
24
24
|
"size": {
|
|
25
|
-
"description": "Forwards to each child <avatar-ui> (
|
|
25
|
+
"description": "Forwards to each child <avatar-ui> (sm|md|lg). Empty uses the per-avatar size. For denser or larger sets, set [scale] on an ancestor.",
|
|
26
26
|
"type": "string"
|
|
27
27
|
}
|
|
28
28
|
},
|
|
@@ -23,7 +23,7 @@ props:
|
|
|
23
23
|
type: number
|
|
24
24
|
default: 5
|
|
25
25
|
size:
|
|
26
|
-
description: Forwards to each child <avatar-ui> (
|
|
26
|
+
description: Forwards to each child <avatar-ui> (sm|md|lg). Empty uses the per-avatar size. For denser or larger sets, set [scale] on an ancestor.
|
|
27
27
|
type: string
|
|
28
28
|
|
|
29
29
|
keywords:
|
|
@@ -31,14 +31,12 @@
|
|
|
31
31
|
"default": "circle"
|
|
32
32
|
},
|
|
33
33
|
"size": {
|
|
34
|
-
"description": "Avatar size
|
|
34
|
+
"description": "Avatar size (sm/md/lg). The former xs/xl diameters are the ancestor-[scale] grid cells (scale=\"ui-sm\", size=\"sm\") / (scale=\"ui-lg\", size=\"lg\").",
|
|
35
35
|
"type": "string",
|
|
36
36
|
"enum": [
|
|
37
|
-
"xs",
|
|
38
37
|
"sm",
|
|
39
38
|
"md",
|
|
40
|
-
"lg"
|
|
41
|
-
"xl"
|
|
39
|
+
"lg"
|
|
42
40
|
],
|
|
43
41
|
"default": "md"
|
|
44
42
|
},
|
|
@@ -11,12 +11,12 @@
|
|
|
11
11
|
--avatar-font-size: var(--a-ui-sm);
|
|
12
12
|
--avatar-font-weight: var(--a-weight-medium);
|
|
13
13
|
|
|
14
|
-
/* Sizes
|
|
15
|
-
|
|
14
|
+
/* Sizes — sm/md/lg only; the removed xs/xl rows live on as the
|
|
15
|
+
ancestor-[scale] grid cells (ui-sm, sm) / (ui-lg, lg), which
|
|
16
|
+
re-table this family (styles/scale.css). */
|
|
16
17
|
--avatar-size-sm: 1.75rem;
|
|
17
18
|
--avatar-size-md: 2.5rem;
|
|
18
19
|
--avatar-size-lg: 3.5rem;
|
|
19
|
-
--avatar-size-xl: 4.5rem;
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
:scope {
|
|
@@ -59,11 +59,9 @@
|
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
/* ── Sizes ── */
|
|
62
|
-
:scope[size="xs"] { --avatar-size: var(--avatar-size-xs); --avatar-font-size: var(--a-ui-sm); }
|
|
63
62
|
:scope[size="sm"] { --avatar-size: var(--avatar-size-sm); --avatar-font-size: var(--a-ui-sm); }
|
|
64
63
|
:scope[size="md"] { --avatar-size: var(--avatar-size-md); --avatar-font-size: var(--a-ui-sm); }
|
|
65
64
|
:scope[size="lg"] { --avatar-size: var(--avatar-size-lg); --avatar-font-size: var(--a-ui-md); }
|
|
66
|
-
:scope[size="xl"] { --avatar-size: var(--avatar-size-xl); --avatar-font-size: var(--a-ui-lg); }
|
|
67
65
|
|
|
68
66
|
/* ── Shape ── */
|
|
69
67
|
:scope[shape="circle"] { --avatar-radius: var(--a-radius-full); }
|
|
@@ -84,11 +82,19 @@ avatar-group-ui:hover > [slot="overflow"] {
|
|
|
84
82
|
|
|
85
83
|
@scope (avatar-group-ui) {
|
|
86
84
|
:where(:scope) {
|
|
87
|
-
/* ── Layout
|
|
88
|
-
|
|
85
|
+
/* ── Layout — counter/overlap are 3-row families so the ancestor
|
|
86
|
+
[scale] tiers can re-table them (styles/scale.css), mirroring
|
|
87
|
+
the --avatar-size-* family. ── */
|
|
88
|
+
--avatar-group-counter-size-sm: 1.75rem;
|
|
89
|
+
--avatar-group-counter-size-md: 2rem;
|
|
90
|
+
--avatar-group-counter-size-lg: 3.5rem;
|
|
91
|
+
--avatar-group-overlap-sm: -0.4rem;
|
|
92
|
+
--avatar-group-overlap-md: -0.5rem;
|
|
93
|
+
--avatar-group-overlap-lg: -0.625rem;
|
|
94
|
+
--avatar-group-overlap: var(--avatar-group-overlap-md);
|
|
89
95
|
--avatar-group-spread: var(--a-space-0-5);
|
|
90
96
|
--avatar-group-overflow-px: var(--a-space-1);
|
|
91
|
-
--avatar-group-counter-size:
|
|
97
|
+
--avatar-group-counter-size: var(--avatar-group-counter-size-md);
|
|
92
98
|
|
|
93
99
|
/* ── Colors ── */
|
|
94
100
|
--avatar-group-border: 2px solid var(--md-sys-color-neutral-background);
|
|
@@ -151,8 +157,6 @@ avatar-group-ui:hover > [slot="overflow"] {
|
|
|
151
157
|
}
|
|
152
158
|
|
|
153
159
|
/* Size variants — adjust counter + overlap */
|
|
154
|
-
:scope[size="
|
|
155
|
-
:scope[size="
|
|
156
|
-
:scope[size="lg"] { --avatar-group-counter-size: 3.5rem; --avatar-group-overlap: -0.625rem; }
|
|
157
|
-
:scope[size="xl"] { --avatar-group-counter-size: 4.5rem; --avatar-group-overlap: -0.75rem; }
|
|
160
|
+
:scope[size="sm"] { --avatar-group-counter-size: var(--avatar-group-counter-size-sm); --avatar-group-overlap: var(--avatar-group-overlap-sm); }
|
|
161
|
+
:scope[size="lg"] { --avatar-group-counter-size: var(--avatar-group-counter-size-lg); --avatar-group-overlap: var(--avatar-group-overlap-lg); }
|
|
158
162
|
}
|
|
@@ -23,8 +23,8 @@ export class UIAvatar extends UIElement {
|
|
|
23
23
|
icon: string;
|
|
24
24
|
/** Avatar shape */
|
|
25
25
|
shape: 'circle' | 'square';
|
|
26
|
-
/** Avatar size
|
|
27
|
-
size: '
|
|
26
|
+
/** Avatar size (sm/md/lg). The former xs/xl diameters are the ancestor-[scale] grid cells (scale="ui-sm", size="sm") / (scale="ui-lg", size="lg"). */
|
|
27
|
+
size: 'sm' | 'md' | 'lg';
|
|
28
28
|
/** Image source URL. Falls back to initials on error. */
|
|
29
29
|
src: string;
|
|
30
30
|
/** Display string (full name or initials). Initials derive from spaces — first letter of each word, max 2. */
|
|
@@ -34,6 +34,6 @@ export class UIAvatar extends UIElement {
|
|
|
34
34
|
export class UIAvatarGroup extends UIElement {
|
|
35
35
|
/** Maximum avatars to show before the +N overflow indicator. */
|
|
36
36
|
max: number;
|
|
37
|
-
/** Forwards to each child <avatar-ui> (
|
|
37
|
+
/** Forwards to each child <avatar-ui> (sm|md|lg). Empty uses the per-avatar size. For denser or larger sets, set [scale] on an ancestor. */
|
|
38
38
|
size: string;
|
|
39
39
|
}
|
|
@@ -35,15 +35,13 @@ props:
|
|
|
35
35
|
- circle
|
|
36
36
|
- square
|
|
37
37
|
size:
|
|
38
|
-
description: Avatar size
|
|
38
|
+
description: Avatar size (sm/md/lg). The former xs/xl diameters are the ancestor-[scale] grid cells (scale="ui-sm", size="sm") / (scale="ui-lg", size="lg").
|
|
39
39
|
type: string
|
|
40
40
|
default: md
|
|
41
41
|
enum:
|
|
42
|
-
- xs
|
|
43
42
|
- sm
|
|
44
43
|
- md
|
|
45
44
|
- lg
|
|
46
|
-
- xl
|
|
47
45
|
src:
|
|
48
46
|
description: Image source URL. Falls back to initials on error.
|
|
49
47
|
type: string
|
|
@@ -22,14 +22,12 @@
|
|
|
22
22
|
"default": ""
|
|
23
23
|
},
|
|
24
24
|
"size": {
|
|
25
|
-
"description": "Badge size",
|
|
25
|
+
"description": "Badge size (sm/md/lg). For a denser or larger register, set [scale] on an ancestor.",
|
|
26
26
|
"type": "string",
|
|
27
27
|
"enum": [
|
|
28
|
-
"xs",
|
|
29
28
|
"sm",
|
|
30
29
|
"md",
|
|
31
|
-
"lg"
|
|
32
|
-
"xl"
|
|
30
|
+
"lg"
|
|
33
31
|
],
|
|
34
32
|
"default": "md"
|
|
35
33
|
},
|
|
@@ -21,8 +21,8 @@ import { UIElement } from '../../core/element.js';
|
|
|
21
21
|
export class UIBadge extends UIElement {
|
|
22
22
|
/** Optional leading icon (any registered name). Use icon="dot" for chart-legend / status-pip chips. Inherits the variant's foreground color so the dot matches the label. */
|
|
23
23
|
icon: string;
|
|
24
|
-
/** Badge size */
|
|
25
|
-
size: '
|
|
24
|
+
/** Badge size (sm/md/lg). For a denser or larger register, set [scale] on an ancestor. */
|
|
25
|
+
size: 'sm' | 'md' | 'lg';
|
|
26
26
|
/** Semantic status shorthand. Auto-maps to variant and sets text. `new` → success "New"; `updated` → info "Updated"; `deprecated` → warning "Deprecated"; `removed` → danger "Removed"; `beta` → accent "Beta". Use `variant` + `text` directly for custom chips. */
|
|
27
27
|
status: 'new' | 'updated' | 'deprecated' | 'removed' | 'beta';
|
|
28
28
|
/** Badge text content. Falls back to existing textContent. */
|
|
@@ -25,15 +25,13 @@ props:
|
|
|
25
25
|
type: string
|
|
26
26
|
default: ""
|
|
27
27
|
size:
|
|
28
|
-
description: Badge size
|
|
28
|
+
description: Badge size (sm/md/lg). For a denser or larger register, set [scale] on an ancestor.
|
|
29
29
|
type: string
|
|
30
30
|
default: md
|
|
31
31
|
enum:
|
|
32
|
-
- xs
|
|
33
32
|
- sm
|
|
34
33
|
- md
|
|
35
34
|
- lg
|
|
36
|
-
- xl
|
|
37
35
|
status:
|
|
38
36
|
description: Semantic status shorthand. Auto-maps to variant and sets text.
|
|
39
37
|
`new` → success "New"; `updated` → info "Updated"; `deprecated` → warning
|
|
@@ -54,14 +54,12 @@
|
|
|
54
54
|
"default": ""
|
|
55
55
|
},
|
|
56
56
|
"size": {
|
|
57
|
-
"description": "Sizing scale (
|
|
57
|
+
"description": "Sizing scale (sm/md/lg). For a denser or larger register, set [scale] on an ancestor (scale=\"ui-sm\" … \"content-lg\") — scale picks the table, size picks the row.",
|
|
58
58
|
"type": "string",
|
|
59
59
|
"enum": [
|
|
60
|
-
"xs",
|
|
61
60
|
"sm",
|
|
62
61
|
"md",
|
|
63
|
-
"lg"
|
|
64
|
-
"xl"
|
|
62
|
+
"lg"
|
|
65
63
|
],
|
|
66
64
|
"default": "md"
|
|
67
65
|
},
|
|
@@ -23,8 +23,8 @@ export class UIButton extends UIElement {
|
|
|
23
23
|
disabled: boolean;
|
|
24
24
|
/** Leading Phosphor icon name (rendered before text). */
|
|
25
25
|
icon: string;
|
|
26
|
-
/** Sizing scale (
|
|
27
|
-
size: '
|
|
26
|
+
/** Sizing scale (sm/md/lg). For a denser or larger register, set [scale] on an ancestor (scale="ui-sm" … "content-lg") — scale picks the table, size picks the row. */
|
|
27
|
+
size: 'sm' | 'md' | 'lg';
|
|
28
28
|
/** Makes the button stretch to fill the parent's width */
|
|
29
29
|
stretch: boolean;
|
|
30
30
|
/** Button text, rendered via CSS attr(text) on ::after */
|
|
@@ -42,15 +42,13 @@ props:
|
|
|
42
42
|
type: string
|
|
43
43
|
default: ""
|
|
44
44
|
size:
|
|
45
|
-
description: "Sizing scale (
|
|
45
|
+
description: "Sizing scale (sm/md/lg). For a denser or larger register, set [scale] on an ancestor (scale=\"ui-sm\" … \"content-lg\") — scale picks the table, size picks the row."
|
|
46
46
|
type: string
|
|
47
47
|
default: md
|
|
48
48
|
enum:
|
|
49
|
-
- xs
|
|
50
49
|
- sm
|
|
51
50
|
- md
|
|
52
51
|
- lg
|
|
53
|
-
- xl
|
|
54
52
|
text:
|
|
55
53
|
description: Button text, rendered via CSS attr(text) on ::after
|
|
56
54
|
type: string
|
|
@@ -168,9 +168,9 @@ export class UICalendarGrid extends UIElement {
|
|
|
168
168
|
// respects the consumer-authored tabindex="-1", so the nav carets stay
|
|
169
169
|
// out of the roving-tabindex day-grid's tab sequence exactly as before.
|
|
170
170
|
let h = `<div data-cal-header>
|
|
171
|
-
<button-ui variant="ghost" size="
|
|
171
|
+
<button-ui variant="ghost" size="sm" icon="caret-left" data-cal-prev aria-label="Previous month" tabindex="-1"></button-ui>
|
|
172
172
|
<span data-cal-title>${MONTHS_LONG[month]} ${year}</span>
|
|
173
|
-
<button-ui variant="ghost" size="
|
|
173
|
+
<button-ui variant="ghost" size="sm" icon="caret-right" data-cal-next aria-label="Next month" tabindex="-1"></button-ui>
|
|
174
174
|
</div>`;
|
|
175
175
|
|
|
176
176
|
// Day-of-week header
|
|
@@ -181,36 +181,39 @@ export class UICalendarGrid extends UIElement {
|
|
|
181
181
|
const daysInMonth = new Date(year, month + 1, 0).getDate();
|
|
182
182
|
const daysInPrev = new Date(year, month, 0).getDate();
|
|
183
183
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
//
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
//
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
const
|
|
199
|
-
const
|
|
184
|
+
// <button-ui variant="ghost" text="…"> (gh issue 276 wave 4) — the day
|
|
185
|
+
// number moves from element text content to the `text` attribute, which
|
|
186
|
+
// button-ui renders via CSS attr(text) on its ::after.
|
|
187
|
+
//
|
|
188
|
+
// Shared by all three day-loops (prev-month filler / current-month /
|
|
189
|
+
// next-month filler) so today/selected/in-range predicates stay
|
|
190
|
+
// consistent across a month boundary (gh#368) — a range spanning two
|
|
191
|
+
// months must show a continuous in-range band through the filler days
|
|
192
|
+
// representing the adjacent month, not just within each month's own
|
|
193
|
+
// cells. Filler days pass `outside: true`, which forces them
|
|
194
|
+
// disabled/unfocusable/unclickable regardless of the computed
|
|
195
|
+
// predicates — this only affects the highlight band's visual
|
|
196
|
+
// continuity, never selectability.
|
|
197
|
+
const dayCell = (date, day, outside) => {
|
|
198
|
+
const iso = toISO(date.getFullYear(), date.getMonth(), date.getDate());
|
|
199
|
+
const isToday = sameDay(date, today);
|
|
200
|
+
const isSelected = !!(selected && sameDay(date, selected));
|
|
200
201
|
// In-range: strictly between rangeStart and rangeEnd (endpoints
|
|
201
202
|
// themselves render as `[data-selected]` via the `value` prop;
|
|
202
203
|
// marking them in-range too would double-up the styling).
|
|
203
|
-
const isInRange
|
|
204
|
+
const isInRange = !!(rangeFrom && rangeTo
|
|
204
205
|
&& date > rangeFrom && date < rangeTo);
|
|
205
206
|
// Range endpoint flags — let CSS render the start/end cell with
|
|
206
|
-
// half-pill caps so the in-range strip reads as a continuous
|
|
207
|
-
//
|
|
207
|
+
// half-pill caps so the in-range strip reads as a continuous band
|
|
208
|
+
// when displayed next to the in-range cells.
|
|
208
209
|
const isRangeStart = !!(rangeFrom && sameDay(date, rangeFrom));
|
|
209
210
|
const isRangeEnd = !!(rangeTo && sameDay(date, rangeTo));
|
|
211
|
+
const isDisabled = outside || (minDate && date < minDate) || (maxDate && date > maxDate);
|
|
212
|
+
const isFocused = !outside && this.#focusedDay === day;
|
|
210
213
|
|
|
211
214
|
const attrs = [
|
|
212
215
|
'data-cal-day',
|
|
213
|
-
`data-date="${iso}"`,
|
|
216
|
+
outside ? 'data-outside' : `data-date="${iso}"`,
|
|
214
217
|
isToday ? 'data-today' : '',
|
|
215
218
|
isSelected ? 'data-selected' : '',
|
|
216
219
|
isInRange ? 'data-in-range' : '',
|
|
@@ -221,17 +224,31 @@ export class UICalendarGrid extends UIElement {
|
|
|
221
224
|
`tabindex="${isFocused ? '0' : '-1'}"`,
|
|
222
225
|
].filter(Boolean).join(' ');
|
|
223
226
|
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
227
|
+
return `<button-ui variant="ghost" ${attrs} text="${day}"></button-ui>`;
|
|
228
|
+
};
|
|
229
|
+
|
|
230
|
+
h += '<div data-cal-grid>';
|
|
231
|
+
|
|
232
|
+
// Previous-month trailing days (outside, disabled)
|
|
233
|
+
const prevMonth = month === 0 ? 11 : month - 1;
|
|
234
|
+
const prevYear = month === 0 ? year - 1 : year;
|
|
235
|
+
for (let i = firstDay - 1; i >= 0; i--) {
|
|
236
|
+
const day = daysInPrev - i;
|
|
237
|
+
h += dayCell(new Date(prevYear, prevMonth, day), day, true);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// Current-month days
|
|
241
|
+
for (let d = 1; d <= daysInMonth; d++) {
|
|
242
|
+
h += dayCell(new Date(year, month, d), d, false);
|
|
228
243
|
}
|
|
229
244
|
|
|
230
245
|
// Next-month leading days
|
|
231
246
|
const totalCells = firstDay + daysInMonth;
|
|
232
247
|
const remaining = (7 - (totalCells % 7)) % 7;
|
|
248
|
+
const nextMonth = month === 11 ? 0 : month + 1;
|
|
249
|
+
const nextYear = month === 11 ? year + 1 : year;
|
|
233
250
|
for (let d = 1; d <= remaining; d++) {
|
|
234
|
-
h +=
|
|
251
|
+
h += dayCell(new Date(nextYear, nextMonth, d), d, true);
|
|
235
252
|
}
|
|
236
253
|
|
|
237
254
|
h += '</div>';
|
|
@@ -115,7 +115,7 @@
|
|
|
115
115
|
color: var(--calendar-grid-title-fg);
|
|
116
116
|
}
|
|
117
117
|
|
|
118
|
-
/* Stamped <button-ui variant="ghost" size="
|
|
118
|
+
/* Stamped <button-ui variant="ghost" size="sm" icon="caret-…"> (gh issue
|
|
119
119
|
276 wave 4) — icon-only (no [text], no child text) so button-ui's own
|
|
120
120
|
[data-icon-only] rule already squares it to --button-height; pointing
|
|
121
121
|
--button-height at the nav size (not just literal width/height) avoids
|
|
@@ -196,9 +196,9 @@ export class UICalendarPicker extends UIFormElement {
|
|
|
196
196
|
// the default tab order (unlike calendar-grid-ui's, which are pulled out
|
|
197
197
|
// via tabindex="-1" for its inline roving-tabindex day grid).
|
|
198
198
|
let h = `<div data-cal-header>
|
|
199
|
-
<button-ui variant="ghost" size="
|
|
199
|
+
<button-ui variant="ghost" size="sm" icon="caret-left" data-cal-prev aria-label="Previous month"></button-ui>
|
|
200
200
|
<span data-cal-title>${MONTHS_LONG[month]} ${year}</span>
|
|
201
|
-
<button-ui variant="ghost" size="
|
|
201
|
+
<button-ui variant="ghost" size="sm" icon="caret-right" data-cal-next aria-label="Next month"></button-ui>
|
|
202
202
|
</div>`;
|
|
203
203
|
|
|
204
204
|
// Day-of-week header
|
|
@@ -232,7 +232,7 @@ calendar-picker-ui [data-cal-title] {
|
|
|
232
232
|
color: var(--calendar-picker-title-fg);
|
|
233
233
|
}
|
|
234
234
|
|
|
235
|
-
/* Stamped <button-ui variant="ghost" size="
|
|
235
|
+
/* Stamped <button-ui variant="ghost" size="sm" icon="caret-…"> (gh issue 276
|
|
236
236
|
wave 4) — icon-only (no [text], no child text) so button-ui's own
|
|
237
237
|
[data-icon-only] rule already squares it to --button-height; pointing
|
|
238
238
|
--button-height at the nav size (not just literal height below) avoids
|
package/components/card/card.css
CHANGED
|
@@ -241,7 +241,7 @@ chat-input-ui textarea-ui:not([disabled]) [slot="text"]:hover {
|
|
|
241
241
|
border: 1px solid var(--chat-input-image-border);
|
|
242
242
|
}
|
|
243
243
|
|
|
244
|
-
/* Attachment-remove — a stamped <button-ui variant="ghost" size="
|
|
244
|
+
/* Attachment-remove — a stamped <button-ui variant="ghost" size="sm"
|
|
245
245
|
icon="x"> (gh issue 276: no native <button> in stamped DOM); the
|
|
246
246
|
floating filled-circle look rides button token re-points. */
|
|
247
247
|
[slot="preview"] [data-preview-remove] {
|
|
@@ -241,7 +241,7 @@ export class UICombobox extends UIFormElement {
|
|
|
241
241
|
aria-controls="${listboxId}"
|
|
242
242
|
aria-labelledby="${labelId}"
|
|
243
243
|
data-placeholder="${escapeHTML(this.placeholder || '')}"></span>
|
|
244
|
-
<button-ui variant="ghost" size="
|
|
244
|
+
<button-ui variant="ghost" size="sm" data-clear aria-label="Clear" tabindex="-1" style="display:none"><icon-ui slot="icon" name="x-circle"></icon-ui></button-ui>
|
|
245
245
|
<span data-suffix>
|
|
246
246
|
<icon-ui name="caret-down"></icon-ui>
|
|
247
247
|
</span>
|
|
@@ -161,7 +161,7 @@
|
|
|
161
161
|
align-items: center;
|
|
162
162
|
}
|
|
163
163
|
|
|
164
|
-
/* Clear x — a stamped <button-ui variant="ghost" size="
|
|
164
|
+
/* Clear x — a stamped <button-ui variant="ghost" size="sm"> kept
|
|
165
165
|
mouse-only via tabindex="-1" (gh issue 276: no native <button> in
|
|
166
166
|
stamped DOM); colors/geometry ride button token re-points. */
|
|
167
167
|
[data-clear] {
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"default": ""
|
|
28
28
|
},
|
|
29
29
|
"size": {
|
|
30
|
-
"description": "Icon size.
|
|
30
|
+
"description": "Icon size. Named tiers `sm` 14px / `md` 16px / `lg` 20px ride the universal `[size]` system (`--a-icon-size`), which the ancestor `[scale]` tiers re-table. Anything beyond the row is a free-form pixel / rem / em / percent string (\"48\", \"3rem\", \"1.25em\", \"100%\" fills the parent box).",
|
|
31
31
|
"type": "string",
|
|
32
32
|
"default": ""
|
|
33
33
|
},
|
|
@@ -100,10 +100,10 @@ export class UIIcon extends UIElement {
|
|
|
100
100
|
// and is correctly NOT flagged here.
|
|
101
101
|
else if (this.name && !svg) warnIfIconRegistryUnwired();
|
|
102
102
|
|
|
103
|
-
// Pixel / rem / em passthrough — `size="48"` → 48px,
|
|
104
|
-
// `size="3.5rem"` → 3.5rem
|
|
105
|
-
//
|
|
106
|
-
//
|
|
103
|
+
// Pixel / rem / em / % passthrough — `size="48"` → 48px,
|
|
104
|
+
// `size="3.5rem"` → 3.5rem, `size="100%"` → fill the parent box.
|
|
105
|
+
// Named sm/md/lg ride the universal [size] system (--a-icon-size);
|
|
106
|
+
// we only set --icon-size inline for free-form values.
|
|
107
107
|
if (this.size && this.#isFreeFormSize(this.size)) {
|
|
108
108
|
this.style.setProperty('--icon-size', this.#normalizeSize(this.size));
|
|
109
109
|
} else if (this.style.getPropertyValue('--icon-size')) {
|
|
@@ -112,7 +112,7 @@ export class UIIcon extends UIElement {
|
|
|
112
112
|
}
|
|
113
113
|
|
|
114
114
|
#isFreeFormSize(s) {
|
|
115
|
-
return /^\d+(\.\d+)?(px|rem|em)?$/.test(s);
|
|
115
|
+
return /^\d+(\.\d+)?(px|rem|em|%)?$/.test(s);
|
|
116
116
|
}
|
|
117
117
|
|
|
118
118
|
#normalizeSize(s) {
|