@antadesign/anta 0.1.1-dev.7 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -0
- package/dist/components/Button.js +4 -3
- package/dist/components/Menu.d.ts +61 -0
- package/dist/components/Menu.js +34 -0
- package/dist/components/MenuGroup.d.ts +24 -0
- package/dist/components/MenuGroup.js +19 -0
- package/dist/components/MenuItem.d.ts +49 -0
- package/dist/components/MenuItem.js +40 -0
- package/dist/components/MenuSeparator.d.ts +14 -0
- package/dist/components/MenuSeparator.js +7 -0
- package/dist/components/Tag.d.ts +55 -0
- package/dist/components/Tag.js +40 -0
- package/dist/components/Text.d.ts +4 -2
- package/dist/components/Tooltip.d.ts +57 -0
- package/dist/components/Tooltip.js +26 -0
- package/dist/elements/a-button.css +31 -8
- package/dist/elements/a-button.d.ts +1 -0
- package/dist/elements/a-button.js +2 -0
- package/dist/elements/a-icon.d.ts +2 -0
- package/dist/elements/a-icon.js +3 -0
- package/dist/elements/a-icon.shapes.css +4 -0
- package/dist/elements/a-icon.shapes.d.ts +2 -1
- package/dist/elements/a-icon.shapes.js +3 -1
- package/dist/elements/a-menu-group.css +21 -0
- package/dist/elements/a-menu-group.d.ts +13 -0
- package/dist/elements/a-menu-group.js +15 -0
- package/dist/elements/a-menu-item.css +162 -0
- package/dist/elements/a-menu-item.d.ts +27 -0
- package/dist/elements/a-menu-item.js +29 -0
- package/dist/elements/a-menu-separator.css +15 -0
- package/dist/elements/a-menu-separator.d.ts +12 -0
- package/dist/elements/a-menu-separator.js +15 -0
- package/dist/elements/a-menu.css +34 -0
- package/dist/elements/a-menu.d.ts +120 -0
- package/dist/elements/a-menu.js +649 -0
- package/dist/elements/a-progress.d.ts +1 -0
- package/dist/elements/a-progress.js +2 -0
- package/dist/elements/a-sticker-animated.d.ts +1 -0
- package/dist/elements/a-sticker-animated.js +2 -0
- package/dist/elements/a-sticker.d.ts +1 -0
- package/dist/elements/a-sticker.js +2 -0
- package/dist/elements/a-tag.css +196 -0
- package/dist/elements/a-text.css +17 -13
- package/dist/elements/a-text.d.ts +1 -0
- package/dist/elements/a-text.js +2 -0
- package/dist/elements/a-tooltip.css +62 -0
- package/dist/elements/a-tooltip.d.ts +68 -0
- package/dist/elements/a-tooltip.js +488 -0
- package/dist/elements/index.d.ts +18 -10
- package/dist/elements/index.js +12 -35
- package/dist/general_types.d.ts +40 -41
- package/dist/index.d.ts +4 -4
- package/dist/index.js +4 -4
- package/dist/jsx-runtime.d.ts +7 -5
- package/dist/reset.css +14 -5
- package/package.json +13 -14
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { HTMLElementBase } from "../anta_helpers";
|
|
2
|
+
import "./a-sticker.css";
|
|
2
3
|
class AStickerElement extends HTMLElementBase {
|
|
3
4
|
static observedAttributes = ["svg"];
|
|
4
5
|
container;
|
|
@@ -24,6 +25,7 @@ function register_a_sticker() {
|
|
|
24
25
|
customElements.define("a-sticker", AStickerElement);
|
|
25
26
|
}
|
|
26
27
|
}
|
|
28
|
+
register_a_sticker();
|
|
27
29
|
export {
|
|
28
30
|
AStickerElement,
|
|
29
31
|
register_a_sticker
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
@layer anta {
|
|
2
|
+
/* `<a-tag>` is intentionally CSS-only — no JS, no shadow DOM, no
|
|
3
|
+
`customElements.define`. It's a small uppercase pill / chip styled
|
|
4
|
+
purely from attributes; the `Tag` JSX wrapper composes its content
|
|
5
|
+
from `icon` / `label` / `value` / `iconTrailing` props (mirroring
|
|
6
|
+
`<a-button>`) into the light-DOM child elements styled below.
|
|
7
|
+
|
|
8
|
+
Sizing is intrinsic — no fixed height. Like `<a-button>`, the pill's
|
|
9
|
+
height falls out of `line-height` + `padding-block` + the border, so
|
|
10
|
+
the text is never clipped and a consumer can retune the padding
|
|
11
|
+
tokens without fighting a hard height.
|
|
12
|
+
|
|
13
|
+
Color comes from Anta's theme-aware semantic tokens (`--text-*`,
|
|
14
|
+
`--bg-*`), so the named tones need no `.dark` rules — the tokens
|
|
15
|
+
re-theme themselves. Only the custom-tone `oklch` knobs are re-tuned
|
|
16
|
+
for dark mode. The hairline border derives from `--tag-text`, so
|
|
17
|
+
every tone (named or custom) gets a matching edge. */
|
|
18
|
+
|
|
19
|
+
a-tag {
|
|
20
|
+
--tag-text: var(--text-3);
|
|
21
|
+
--tag-bg: var(--bg-4);
|
|
22
|
+
--tag-border: color-mix(in oklch, var(--tag-text) 9%, transparent);
|
|
23
|
+
--tag-separator: color-mix(in oklch, var(--tag-text) 30%, transparent);
|
|
24
|
+
|
|
25
|
+
/* 1.5px top/bottom — the extra 0.5px each side compensates for the
|
|
26
|
+
0.5px (vs 1px) border, keeping the pill at its original 20px height. */
|
|
27
|
+
--tag-padding-block: 1.5px;
|
|
28
|
+
--tag-padding-inline: 6.5px;
|
|
29
|
+
--tag-icon-size: 13px;
|
|
30
|
+
--tag-label-weight: 600;
|
|
31
|
+
--tag-gap: 0.6ch;
|
|
32
|
+
|
|
33
|
+
display: inline-flex;
|
|
34
|
+
align-items: center;
|
|
35
|
+
gap: var(--tag-gap);
|
|
36
|
+
box-sizing: border-box;
|
|
37
|
+
max-width: 100%;
|
|
38
|
+
vertical-align: middle;
|
|
39
|
+
overflow: hidden;
|
|
40
|
+
white-space: nowrap;
|
|
41
|
+
-webkit-user-drag: none;
|
|
42
|
+
|
|
43
|
+
color: var(--tag-text);
|
|
44
|
+
background: var(--tag-bg);
|
|
45
|
+
border: 0.5px solid var(--tag-border);
|
|
46
|
+
border-radius: 22px;
|
|
47
|
+
|
|
48
|
+
padding-block: var(--tag-padding-block);
|
|
49
|
+
padding-inline: var(--tag-padding-inline);
|
|
50
|
+
|
|
51
|
+
font-family: var(--sans-serif);
|
|
52
|
+
font-weight: 450;
|
|
53
|
+
font-size: 11px;
|
|
54
|
+
line-height: 16px;
|
|
55
|
+
text-transform: uppercase;
|
|
56
|
+
letter-spacing: 0.08ch;
|
|
57
|
+
/* Tabular figures are always on (so counts / versions / timers don't
|
|
58
|
+
reflow), plus `ss05` alternate numerals — both layered on top of
|
|
59
|
+
the default ss01 / case / calt set. */
|
|
60
|
+
font-feature-settings: 'tnum' 1, 'ss05' 1, 'ss01', 'case', 'calt';
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/* Icons scale to the pill (the default 16px a-icon is too big here) and
|
|
64
|
+
don't shrink in the flex row. */
|
|
65
|
+
a-tag a-icon {
|
|
66
|
+
--icon-size: var(--tag-icon-size);
|
|
67
|
+
flex: none;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/* label / value segments. Each ellipsizes independently if the pill is
|
|
71
|
+
width-constrained. */
|
|
72
|
+
a-tag a-tag-label,
|
|
73
|
+
a-tag a-tag-value {
|
|
74
|
+
display: inline-block;
|
|
75
|
+
min-width: 0;
|
|
76
|
+
overflow: hidden;
|
|
77
|
+
text-overflow: ellipsis;
|
|
78
|
+
white-space: nowrap;
|
|
79
|
+
}
|
|
80
|
+
/* `value` is the default, unmodified text — it just inherits the tag's
|
|
81
|
+
color and base weight. */
|
|
82
|
+
a-tag a-tag-value { font-weight: 450; }
|
|
83
|
+
/* `label` is the bold "key" placed before the value: same color, just
|
|
84
|
+
heavier (weight 600). It only renders as <a-tag-label> when paired
|
|
85
|
+
with a value — the JSX wrapper drops a lone label into <a-tag-value>
|
|
86
|
+
so a standalone tag keeps the default styling. No divider; the weight
|
|
87
|
+
contrast does the separating. */
|
|
88
|
+
a-tag a-tag-label { font-weight: var(--tag-label-weight); }
|
|
89
|
+
|
|
90
|
+
/* Optical edge padding: an icon at an edge needs less room than a text
|
|
91
|
+
edge, so trim ~2px on whichever side a leading / trailing icon sits.
|
|
92
|
+
`max(0px, …)` keeps it from going negative at small sizes. */
|
|
93
|
+
a-tag:has(> a-icon:first-child) { padding-inline-start: max(0px, var(--tag-padding-inline) - 2px); }
|
|
94
|
+
a-tag:has(> a-icon:last-child) { padding-inline-end: max(0px, var(--tag-padding-inline) - 2px); }
|
|
95
|
+
|
|
96
|
+
/* Segmented children — when raw children (not the structured label /
|
|
97
|
+
value) are passed, each segment after the first gets a hairline
|
|
98
|
+
divider, the legacy multi-part style. Icons and the label / value
|
|
99
|
+
elements are excluded, so `label` + `value` stay divider-less and a
|
|
100
|
+
leading / trailing icon sits flush. The flex `gap` sits to the left
|
|
101
|
+
of the border and `padding-left` balances it on the right. */
|
|
102
|
+
a-tag
|
|
103
|
+
> :not(a-icon, a-tag-label, a-tag-value)
|
|
104
|
+
~ :not(a-icon, a-tag-label, a-tag-value) {
|
|
105
|
+
padding-left: var(--tag-gap);
|
|
106
|
+
border-left: 0.5px solid var(--tag-separator);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/* Named tones — re-point text + bg only; the border re-derives, and
|
|
110
|
+
dark mode falls out of the semantic tokens for free. */
|
|
111
|
+
a-tag[tone="brand"] { --tag-text: var(--text-2-brand); --tag-bg: var(--bg-4-brand); }
|
|
112
|
+
a-tag[tone="info"] { --tag-text: var(--text-2-info); --tag-bg: var(--bg-4-info); }
|
|
113
|
+
a-tag[tone="success"] { --tag-text: var(--text-2-success); --tag-bg: var(--bg-4-success); }
|
|
114
|
+
a-tag[tone="warning"] { --tag-text: var(--text-2-warning); --tag-bg: var(--bg-4-warning); }
|
|
115
|
+
a-tag[tone="critical"] { --tag-text: var(--text-2-critical); --tag-bg: var(--bg-4-critical); }
|
|
116
|
+
|
|
117
|
+
/* Custom tone — any non-named `tone` value. Keep the source hue;
|
|
118
|
+
pin lightness/chroma so any input reads like a sibling of the named
|
|
119
|
+
tones. Knobs are the only numbers to tune; the dark block re-tunes
|
|
120
|
+
them and the formulas resolve against whichever value computes.
|
|
121
|
+
The JSX wrapper writes `--tag-tone-source` inline; the typed
|
|
122
|
+
`attr()` fallback picks up raw `<a-tag tone="…">` on modern engines.
|
|
123
|
+
(oklch relative color: Chrome 119+, Safari 16.4+, Firefox 128+.) */
|
|
124
|
+
a-tag[tone]:not(
|
|
125
|
+
[tone="neutral"],
|
|
126
|
+
[tone="brand"],
|
|
127
|
+
[tone="info"],
|
|
128
|
+
[tone="success"],
|
|
129
|
+
[tone="warning"],
|
|
130
|
+
[tone="critical"]
|
|
131
|
+
) {
|
|
132
|
+
--tag-tone-source: attr(tone type(<color>), currentColor);
|
|
133
|
+
|
|
134
|
+
--_tag-text-l: 0.46; /* fg lightness */
|
|
135
|
+
--_tag-text-c: 0.17; /* fg chroma */
|
|
136
|
+
--_tag-bg-l: 0.96; /* tinted-bg lightness — a hair above the named --bg-4 so the tint reads light */
|
|
137
|
+
--_tag-bg-c: 0.04; /* tinted-bg chroma — light pastel, like --bg-4-{tone} */
|
|
138
|
+
|
|
139
|
+
--tag-text: oklch(from var(--tag-tone-source) var(--_tag-text-l) var(--_tag-text-c) h);
|
|
140
|
+
--tag-bg: oklch(from var(--tag-tone-source) var(--_tag-bg-l) var(--_tag-bg-c) h);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/* Custom tone, dark mode — lighter fg; the tint sits a touch above the
|
|
144
|
+
dark --bg-4-{tone} lightness so it doesn't read pitch-black. */
|
|
145
|
+
.dark a-tag[tone]:not(
|
|
146
|
+
[tone="neutral"],
|
|
147
|
+
[tone="brand"],
|
|
148
|
+
[tone="info"],
|
|
149
|
+
[tone="success"],
|
|
150
|
+
[tone="warning"],
|
|
151
|
+
[tone="critical"]
|
|
152
|
+
) {
|
|
153
|
+
--_tag-text-l: 0.80;
|
|
154
|
+
--_tag-text-c: 0.11;
|
|
155
|
+
--_tag-bg-l: 0.21;
|
|
156
|
+
--_tag-bg-c: 0.05;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
a-tag[size="small"] {
|
|
160
|
+
--tag-padding-block: 0.5px;
|
|
161
|
+
--tag-padding-inline: 4.5px;
|
|
162
|
+
--tag-icon-size: 11px;
|
|
163
|
+
|
|
164
|
+
font-size: 10px;
|
|
165
|
+
line-height: 14px;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/* Large — 24px tall (line-height 18 + 2×2.5 padding + 2×0.5 border),
|
|
169
|
+
on par with Button's large. */
|
|
170
|
+
a-tag[size="large"] {
|
|
171
|
+
--tag-padding-block: 2.5px;
|
|
172
|
+
--tag-padding-inline: 8.5px;
|
|
173
|
+
--tag-icon-size: 15px;
|
|
174
|
+
|
|
175
|
+
font-size: 12px;
|
|
176
|
+
line-height: 18px;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/* Normal-case opt-out: drop the uppercase transform for proportional,
|
|
180
|
+
mixed-case text. Keep a small body-text tracking (Anta's 0.02ch)
|
|
181
|
+
rather than zero — uppercase just needs more (0.08ch). Tabular
|
|
182
|
+
figures + `ss05` stay on (only the case / stylistic-set extras
|
|
183
|
+
change). */
|
|
184
|
+
a-tag[nocaps] {
|
|
185
|
+
font-size: 12px;
|
|
186
|
+
text-transform: none;
|
|
187
|
+
letter-spacing: 0.02ch;
|
|
188
|
+
font-feature-settings: 'tnum' 1, 'ss05' 1, 'lnum', 'ss01', 'ss04', 'case', 'calt';
|
|
189
|
+
}
|
|
190
|
+
/* Large + nocaps reads larger too — bump to 13px (one over the 12px
|
|
191
|
+
uppercase large), keeping the same +1px over-uppercase relationship
|
|
192
|
+
medium has. Height is unchanged (driven by line-height + padding). */
|
|
193
|
+
a-tag[size="large"][nocaps] {
|
|
194
|
+
font-size: 13px;
|
|
195
|
+
}
|
|
196
|
+
}
|
package/dist/elements/a-text.css
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
@layer anta {
|
|
2
2
|
a-text {
|
|
3
|
-
|
|
3
|
+
/* Default (no `priority`) is the SECONDARY level — body text reads at
|
|
4
|
+
--text-2; `priority="primary"` opts into the strongest --text-1. */
|
|
5
|
+
--text-color: var(--text-2);
|
|
4
6
|
--text-link-color: var(--link-color);
|
|
5
7
|
--text-link-hover: var(--link-color-hover);
|
|
6
8
|
|
|
@@ -27,10 +29,12 @@
|
|
|
27
29
|
min-width: 0;
|
|
28
30
|
}
|
|
29
31
|
|
|
30
|
-
/* Neutral priority overrides.
|
|
32
|
+
/* Neutral priority overrides. The default (no `priority`) is the
|
|
33
|
+
secondary level (--text-2, on the base rule above); `primary` opts
|
|
34
|
+
into the strongest --text-1. Levels 1 & 2 keep the brand link color;
|
|
31
35
|
levels 3-5 mute the link to currentColor and step the hover up by one
|
|
32
36
|
level (3→2, 4→3, 5→4). */
|
|
33
|
-
a-text[priority="
|
|
37
|
+
a-text[priority="primary"] { --text-color: var(--text-1); }
|
|
34
38
|
a-text[priority="tertiary"] { --text-color: var(--text-3); --text-link-color: currentColor; --text-link-hover: var(--text-2); }
|
|
35
39
|
a-text[priority="quaternary"] { --text-color: var(--text-4); --text-link-color: currentColor; --text-link-hover: var(--text-3); }
|
|
36
40
|
a-text[priority="quinary"] { --text-color: var(--text-5); --text-link-color: currentColor; --text-link-hover: var(--text-4); }
|
|
@@ -39,32 +43,32 @@
|
|
|
39
43
|
muted (currentColor) and hover steps up one level of the same tint.
|
|
40
44
|
Level 1 has no level above; hover keeps the color, only the underline
|
|
41
45
|
alpha changes. */
|
|
42
|
-
a-text[tone="brand"] { --text-color: var(--text-
|
|
43
|
-
a-text[tone="brand"][priority="
|
|
46
|
+
a-text[tone="brand"] { --text-color: var(--text-2-brand); --text-link-color: currentColor; --text-link-hover: var(--text-1-brand); }
|
|
47
|
+
a-text[tone="brand"][priority="primary"] { --text-color: var(--text-1-brand); }
|
|
44
48
|
a-text[tone="brand"][priority="tertiary"] { --text-color: var(--text-3-brand); --text-link-hover: var(--text-2-brand); }
|
|
45
49
|
a-text[tone="brand"][priority="quaternary"] { --text-color: var(--text-4-brand); --text-link-hover: var(--text-3-brand); }
|
|
46
50
|
a-text[tone="brand"][priority="quinary"] { --text-color: var(--text-5-brand); --text-link-hover: var(--text-4-brand); }
|
|
47
51
|
|
|
48
|
-
a-text[tone="success"] { --text-color: var(--text-
|
|
49
|
-
a-text[tone="success"][priority="
|
|
52
|
+
a-text[tone="success"] { --text-color: var(--text-2-success); --text-link-color: currentColor; --text-link-hover: var(--text-1-success); }
|
|
53
|
+
a-text[tone="success"][priority="primary"] { --text-color: var(--text-1-success); }
|
|
50
54
|
a-text[tone="success"][priority="tertiary"] { --text-color: var(--text-3-success); --text-link-hover: var(--text-2-success); }
|
|
51
55
|
a-text[tone="success"][priority="quaternary"] { --text-color: var(--text-4-success); --text-link-hover: var(--text-3-success); }
|
|
52
56
|
a-text[tone="success"][priority="quinary"] { --text-color: var(--text-5-success); --text-link-hover: var(--text-4-success); }
|
|
53
57
|
|
|
54
|
-
a-text[tone="critical"] { --text-color: var(--text-
|
|
55
|
-
a-text[tone="critical"][priority="
|
|
58
|
+
a-text[tone="critical"] { --text-color: var(--text-2-critical); --text-link-color: currentColor; --text-link-hover: var(--text-1-critical); }
|
|
59
|
+
a-text[tone="critical"][priority="primary"] { --text-color: var(--text-1-critical); }
|
|
56
60
|
a-text[tone="critical"][priority="tertiary"] { --text-color: var(--text-3-critical); --text-link-hover: var(--text-2-critical); }
|
|
57
61
|
a-text[tone="critical"][priority="quaternary"] { --text-color: var(--text-4-critical); --text-link-hover: var(--text-3-critical); }
|
|
58
62
|
a-text[tone="critical"][priority="quinary"] { --text-color: var(--text-5-critical); --text-link-hover: var(--text-4-critical); }
|
|
59
63
|
|
|
60
|
-
a-text[tone="warning"] { --text-color: var(--text-
|
|
61
|
-
a-text[tone="warning"][priority="
|
|
64
|
+
a-text[tone="warning"] { --text-color: var(--text-2-warning); --text-link-color: currentColor; --text-link-hover: var(--text-1-warning); }
|
|
65
|
+
a-text[tone="warning"][priority="primary"] { --text-color: var(--text-1-warning); }
|
|
62
66
|
a-text[tone="warning"][priority="tertiary"] { --text-color: var(--text-3-warning); --text-link-hover: var(--text-2-warning); }
|
|
63
67
|
a-text[tone="warning"][priority="quaternary"] { --text-color: var(--text-4-warning); --text-link-hover: var(--text-3-warning); }
|
|
64
68
|
a-text[tone="warning"][priority="quinary"] { --text-color: var(--text-5-warning); --text-link-hover: var(--text-4-warning); }
|
|
65
69
|
|
|
66
|
-
a-text[tone="info"] { --text-color: var(--text-
|
|
67
|
-
a-text[tone="info"][priority="
|
|
70
|
+
a-text[tone="info"] { --text-color: var(--text-2-info); --text-link-color: currentColor; --text-link-hover: var(--text-1-info); }
|
|
71
|
+
a-text[tone="info"][priority="primary"] { --text-color: var(--text-1-info); }
|
|
68
72
|
a-text[tone="info"][priority="tertiary"] { --text-color: var(--text-3-info); --text-link-hover: var(--text-2-info); }
|
|
69
73
|
a-text[tone="info"][priority="quaternary"] { --text-color: var(--text-4-info); --text-link-hover: var(--text-3-info); }
|
|
70
74
|
a-text[tone="info"][priority="quinary"] { --text-color: var(--text-5-info); --text-link-hover: var(--text-4-info); }
|
package/dist/elements/a-text.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { HTMLElementBase } from "../anta_helpers";
|
|
2
|
+
import "./a-text.css";
|
|
2
3
|
const SHADOW_STYLE = `
|
|
3
4
|
:host {
|
|
4
5
|
display: block;
|
|
@@ -137,6 +138,7 @@ function register_a_text() {
|
|
|
137
138
|
customElements.define("a-text", ATextElement);
|
|
138
139
|
}
|
|
139
140
|
}
|
|
141
|
+
register_a_text();
|
|
140
142
|
export {
|
|
141
143
|
ATextElement,
|
|
142
144
|
register_a_text
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
@layer anta {
|
|
2
|
+
/* Before the custom element upgrades on the client, <a-tooltip> is an
|
|
3
|
+
unknown inline element and its content would flash *inside the anchor*.
|
|
4
|
+
Hide it until defined; once defined this stops matching and the shadow
|
|
5
|
+
`:host { display: contents }` governs (content renders only in the
|
|
6
|
+
popover via the slot). */
|
|
7
|
+
a-tooltip:not(:defined) {
|
|
8
|
+
display: none;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/* On touch devices, an anchor that owns a tooltip suppresses the long-press
|
|
12
|
+
text-selection and the iOS callout, so press-and-hold cleanly reveals the
|
|
13
|
+
bubble (see the long-press handling in a-tooltip.ts) instead of selecting
|
|
14
|
+
text or popping the system menu. Scoped to coarse/no-hover pointers, so
|
|
15
|
+
fine-pointer devices keep normal text selection. The anchor is always
|
|
16
|
+
<a-tooltip>'s direct parent (set in connectedCallback), so `:has(> …)`
|
|
17
|
+
targets exactly it; `:where()` keeps specificity at 0 for easy override. */
|
|
18
|
+
@media (hover: none) and (pointer: coarse) {
|
|
19
|
+
:where(:has(> a-tooltip)) {
|
|
20
|
+
-webkit-touch-callout: none;
|
|
21
|
+
user-select: none;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/* Tooltip exposes only the box "chrome" that lives inside the shadow
|
|
26
|
+
popover and is therefore impossible to reach with plain consumer CSS.
|
|
27
|
+
The bubble's content is slotted light DOM, so its font / colour / size
|
|
28
|
+
are already styleable from the page — those are intentionally NOT
|
|
29
|
+
tokens. These custom properties inherit across the shadow boundary
|
|
30
|
+
into the popover container (see a-tooltip.ts). The host itself draws
|
|
31
|
+
nothing and stays out of layout (`:host { display: contents }` in the
|
|
32
|
+
shadow style). */
|
|
33
|
+
a-tooltip {
|
|
34
|
+
/* Frosted translucent surface (matches the legacy look): a mostly-
|
|
35
|
+
opaque white that, paired with the container's `backdrop-filter:
|
|
36
|
+
blur(8px)`, reads as a frosted bubble over the page. --bg-1 is
|
|
37
|
+
#ffffff in light / #000000 in dark, so this flips to a dark frost
|
|
38
|
+
automatically (alpha is dialed down in the .dark override). */
|
|
39
|
+
--tooltip-bg: color-mix(in oklch, var(--bg-1) 80%, transparent);
|
|
40
|
+
--tooltip-shadow:
|
|
41
|
+
0 1px 8px color-mix(in oklch, var(--text-1) 15%, transparent),
|
|
42
|
+
0 0 1px color-mix(in oklch, var(--text-1) 50%, transparent);
|
|
43
|
+
--tooltip-radius: 3px;
|
|
44
|
+
--tooltip-max-width: min(calc(100vw - 20px), 80ch);
|
|
45
|
+
/* No real border by default — the hairline edge comes from --tooltip-shadow.
|
|
46
|
+
Set e.g. `1px solid var(--border-5)` for an actual border. */
|
|
47
|
+
--tooltip-border: none;
|
|
48
|
+
/* The frost. Set to `none` (with --tooltip-bg: transparent) for a fully
|
|
49
|
+
see-through bubble. */
|
|
50
|
+
--tooltip-backdrop-filter: blur(8px);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/* Dark: a slightly more transparent black frost. A solid black cast shadow
|
|
54
|
+
for lift, plus an inset 1px white ring so the bubble's edge stays crisp
|
|
55
|
+
against dark page content. */
|
|
56
|
+
.dark a-tooltip {
|
|
57
|
+
--tooltip-bg: color-mix(in oklch, var(--bg-1) 70%, transparent);
|
|
58
|
+
--tooltip-shadow:
|
|
59
|
+
0 2px 16px color-mix(in oklch, black 70%, transparent),
|
|
60
|
+
inset 0 0 0 1px color-mix(in oklch, white 15%, transparent);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { HTMLElementBase } from '../anta_helpers';
|
|
2
|
+
import './a-tooltip.css';
|
|
3
|
+
export declare class ATooltipElement extends HTMLElementBase {
|
|
4
|
+
static observedAttributes: string[];
|
|
5
|
+
/** Shadow-internal popover surface — the only thing we ever mutate. */
|
|
6
|
+
private container;
|
|
7
|
+
private anchor;
|
|
8
|
+
listening: boolean;
|
|
9
|
+
private shown;
|
|
10
|
+
/** True while the current open was triggered by a touch long-press. Such a
|
|
11
|
+
* bubble is pinned (never cursor-follows) and biases above the anchor so the
|
|
12
|
+
* fingertip doesn't cover it. */
|
|
13
|
+
private touchOpen;
|
|
14
|
+
private lastMouse?;
|
|
15
|
+
private debouncedShow?;
|
|
16
|
+
private teardown?;
|
|
17
|
+
private closeTimer?;
|
|
18
|
+
private fading;
|
|
19
|
+
private fadeTimer?;
|
|
20
|
+
private docMoveBound;
|
|
21
|
+
constructor();
|
|
22
|
+
connectedCallback(): void;
|
|
23
|
+
disconnectedCallback(): void;
|
|
24
|
+
attributeChangedCallback(name: string): void;
|
|
25
|
+
/** (Re)build the show debounce with the CURRENT `delay` (rebuilt when the
|
|
26
|
+
* `delay` attribute changes). Re-armed on each hover move (trailing), and
|
|
27
|
+
* fed the latest cursor event, so it shows at the cursor and so moving back
|
|
28
|
+
* onto an anchor after the tooltip was dismissed re-arms it. */
|
|
29
|
+
private makeDebouncedShow;
|
|
30
|
+
/** The element's OWN window / document. The class may be defined in a
|
|
31
|
+
* different realm than the element lives in (e.g. the docs playground
|
|
32
|
+
* renders into an iframe but reuses the parent page's element class), so
|
|
33
|
+
* the module-global `window`/`document` can point at the wrong frame.
|
|
34
|
+
* Everything viewport- or document-scoped (clamping, scroll/key/move
|
|
35
|
+
* listeners) must go through these so it's correct in any frame. */
|
|
36
|
+
private get view();
|
|
37
|
+
private get doc();
|
|
38
|
+
private get isInteractive();
|
|
39
|
+
/** Pinned under the anchor (no cursor-following). Interactive implies this —
|
|
40
|
+
* you can't move into a bubble that's chasing the cursor. */
|
|
41
|
+
private get isStatic();
|
|
42
|
+
/** Pinned to the anchor for any reason: the `static`/`interactive` attrs, or
|
|
43
|
+
* a touch long-press (a finger can't track a following bubble). */
|
|
44
|
+
private get isPinned();
|
|
45
|
+
private get prefersTop();
|
|
46
|
+
private get delay();
|
|
47
|
+
private positionToTarget;
|
|
48
|
+
private positionToMouse;
|
|
49
|
+
private position;
|
|
50
|
+
show: (e?: MouseEvent) => void;
|
|
51
|
+
hide: () => void;
|
|
52
|
+
/** While shown, track the cursor even after it has left the anchor (during
|
|
53
|
+
* the close delay). Cursor-following only — static/interactive bubbles
|
|
54
|
+
* stay pinned. */
|
|
55
|
+
private onDocMove;
|
|
56
|
+
/** Hide after CLOSE_DELAY unless something cancels it first (re-enter, or
|
|
57
|
+
* another tooltip claiming the slot). Lets the bubble bridge the gap to a
|
|
58
|
+
* neighbouring anchor — and survive the trip into an interactive bubble. */
|
|
59
|
+
private scheduleHide;
|
|
60
|
+
private cancelHide;
|
|
61
|
+
private onKeyDown;
|
|
62
|
+
/** Open now if another tooltip is hot (skip delay), else (re)arm the delayed
|
|
63
|
+
* show with the latest cursor event. */
|
|
64
|
+
private trigger;
|
|
65
|
+
setupListeners(): void;
|
|
66
|
+
teardownListeners(): void;
|
|
67
|
+
}
|
|
68
|
+
export declare function register_a_tooltip(): void;
|