@antadesign/anta 0.3.12 → 0.3.14
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 +31 -36
- package/dist/anta_helpers.d.ts +10 -2
- package/dist/anta_helpers.js +5 -0
- package/dist/components/Banner.d.ts +79 -0
- package/dist/components/Banner.js +69 -0
- package/dist/components/Button.d.ts +17 -4
- package/dist/components/Button.js +8 -0
- package/dist/components/InputDate.d.ts +9 -1
- package/dist/components/InputDate.js +4 -1
- package/dist/components/Menu.d.ts +6 -5
- package/dist/components/Select.d.ts +81 -51
- package/dist/components/Select.js +21 -9
- package/dist/components/SelectFaceted.d.ts +21 -16
- package/dist/components/SelectFaceted.js +4 -4
- package/dist/components/SelectFaceted.module.css +1 -1
- package/dist/components/Text.d.ts +2 -2
- package/dist/components/Title.d.ts +2 -2
- package/dist/components/Toaster.d.ts +48 -0
- package/dist/components/Toaster.js +56 -0
- package/dist/components/Tooltip.d.ts +1 -1
- package/dist/components/select-options.d.ts +10 -5
- package/dist/components/select-options.js +1 -1
- package/dist/elements/a-banner.css +1 -0
- package/dist/elements/a-banner.d.ts +10 -0
- package/dist/elements/a-banner.js +141 -0
- package/dist/elements/a-button.css +1 -1
- package/dist/elements/a-checkbox.css +1 -1
- package/dist/elements/a-expander.css +1 -1
- package/dist/elements/a-expander.js +1 -0
- package/dist/elements/a-input-time.css +1 -1
- package/dist/elements/a-input.css +1 -1
- package/dist/elements/a-input.js +2 -2
- package/dist/elements/a-menu-item.css +1 -1
- package/dist/elements/a-menu-item.js +6 -1
- package/dist/elements/a-menu.css +1 -1
- package/dist/elements/a-menu.d.ts +6 -2
- package/dist/elements/a-menu.js +67 -28
- package/dist/elements/a-radio-group.css +1 -1
- package/dist/elements/a-radio-group.d.ts +1 -0
- package/dist/elements/a-radio-group.js +11 -2
- package/dist/elements/a-radio.css +1 -1
- package/dist/elements/a-tabs.css +1 -1
- package/dist/elements/a-tabs.d.ts +1 -0
- package/dist/elements/a-tabs.js +35 -6
- package/dist/elements/a-tag.css +1 -1
- package/dist/elements/a-text.css +1 -1
- package/dist/elements/a-title.css +1 -1
- package/dist/elements/a-toast.css +1 -0
- package/dist/elements/a-toast.d.ts +70 -0
- package/dist/elements/a-toast.js +283 -0
- package/dist/elements/a-toaster.css +1 -0
- package/dist/elements/a-toaster.d.ts +30 -0
- package/dist/elements/a-toaster.js +98 -0
- package/dist/elements/a-tooltip.js +1 -1
- package/dist/elements/index.d.ts +1 -0
- package/dist/elements/index.js +3 -0
- package/dist/general_types.d.ts +52 -9
- package/dist/index.d.ts +3 -1
- package/dist/index.js +2 -0
- package/dist/jsx-runtime.d.ts +3 -1
- package/dist/reset.css +1 -1
- package/dist/theme-anta.css +1 -0
- package/dist/toaster.d.ts +99 -0
- package/dist/toaster.js +100 -0
- package/dist/tokens.css +1 -1
- package/package.json +2 -1
- package/dist/components/Card.module.css +0 -35
- package/dist/components/Progress.module.css +0 -0
- package/dist/components/Radio.d.ts +0 -37
- package/dist/components/Radio.js +0 -33
- package/dist/components/Tab.d.ts +0 -37
- package/dist/components/Tab.js +0 -5
- package/dist/components/Tabs.module.css +0 -1
- package/dist/components/Text.module.css +0 -0
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
import { HTMLElementBase, installDismissTrigger } from "../anta_helpers";
|
|
2
|
+
import "./a-toast.css";
|
|
3
|
+
const EXIT_MS = 220;
|
|
4
|
+
const DEFAULT_DURATION = 5e3;
|
|
5
|
+
const DISMISS_ATTR = "data-toast-dismiss";
|
|
6
|
+
class AToastElement extends HTMLElementBase {
|
|
7
|
+
// `leaving` triggers the exit; `rev` (bumped on an in-place update) restarts
|
|
8
|
+
// the timer. `duration` is read on demand, not observed.
|
|
9
|
+
static observedAttributes = ["leaving", "rev"];
|
|
10
|
+
/** Off-DOM state channel — drives `:state(leaving)` for the exit fade. */
|
|
11
|
+
#internals;
|
|
12
|
+
/** The content slot. Also the element the `--toast-remaining` countdown
|
|
13
|
+
* animates on, so slotted content can inherit the value (see SHADOW_STYLE). */
|
|
14
|
+
#slot;
|
|
15
|
+
/** A DOM node handed in via the `content` property (the wrapper's DOM-node
|
|
16
|
+
* branch). String / JSX content arrives as slotted children instead. */
|
|
17
|
+
#content;
|
|
18
|
+
/** The content node we last slotted, so an in-place update can swap or clear it
|
|
19
|
+
* without touching the reconciler's own children. */
|
|
20
|
+
#slotted;
|
|
21
|
+
#timer;
|
|
22
|
+
#exitTimer;
|
|
23
|
+
/** Time left on the auto-dismiss timer (ms), tracked across pause/resume. */
|
|
24
|
+
#remaining = 0;
|
|
25
|
+
/** When the current run started, for computing remaining on pause. */
|
|
26
|
+
#startedAt = 0;
|
|
27
|
+
#leaving = false;
|
|
28
|
+
// Independent pause holds — the countdown runs only when BOTH are false.
|
|
29
|
+
#hovered = false;
|
|
30
|
+
#focused = false;
|
|
31
|
+
constructor() {
|
|
32
|
+
super();
|
|
33
|
+
try {
|
|
34
|
+
this.#internals = this.attachInternals?.();
|
|
35
|
+
} catch (err) {
|
|
36
|
+
console.warn("a-toast: ElementInternals unavailable \u2014 exit fade disabled.", err);
|
|
37
|
+
}
|
|
38
|
+
const shadow = this.attachShadow({ mode: "open" });
|
|
39
|
+
const style = document.createElement("style");
|
|
40
|
+
style.textContent = SHADOW_STYLE;
|
|
41
|
+
this.#slot = document.createElement("slot");
|
|
42
|
+
shadow.append(style, this.#slot);
|
|
43
|
+
installDismissTrigger(this, DISMISS_ATTR, () => this.dismiss());
|
|
44
|
+
}
|
|
45
|
+
connectedCallback() {
|
|
46
|
+
this.#applyContent();
|
|
47
|
+
this.addEventListener("pointerenter", this.#onPointerEnter);
|
|
48
|
+
this.addEventListener("pointerleave", this.#onPointerLeave);
|
|
49
|
+
this.addEventListener("focusin", this.#onFocusIn);
|
|
50
|
+
this.addEventListener("focusout", this.#onFocusOut);
|
|
51
|
+
if (this.hasAttribute("leaving")) {
|
|
52
|
+
this.dismiss();
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
this.#startTimer();
|
|
56
|
+
}
|
|
57
|
+
disconnectedCallback() {
|
|
58
|
+
this.#clearTimer();
|
|
59
|
+
if (this.#exitTimer != null) {
|
|
60
|
+
this.view.clearTimeout(this.#exitTimer);
|
|
61
|
+
this.#exitTimer = void 0;
|
|
62
|
+
}
|
|
63
|
+
this.removeEventListener("pointerenter", this.#onPointerEnter);
|
|
64
|
+
this.removeEventListener("pointerleave", this.#onPointerLeave);
|
|
65
|
+
this.removeEventListener("focusin", this.#onFocusIn);
|
|
66
|
+
this.removeEventListener("focusout", this.#onFocusOut);
|
|
67
|
+
}
|
|
68
|
+
attributeChangedCallback(name) {
|
|
69
|
+
if (name === "leaving") {
|
|
70
|
+
if (this.hasAttribute("leaving")) {
|
|
71
|
+
if (this.isConnected) this.dismiss();
|
|
72
|
+
} else if (this.#leaving) {
|
|
73
|
+
this.#revive();
|
|
74
|
+
}
|
|
75
|
+
} else if (name === "rev") {
|
|
76
|
+
if (this.isConnected) this.restart();
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
/** Cancel a pending exit and bring the toast back (an upsert landed during the
|
|
80
|
+
* exit window). */
|
|
81
|
+
#revive() {
|
|
82
|
+
if (this.#exitTimer != null) {
|
|
83
|
+
this.view.clearTimeout(this.#exitTimer);
|
|
84
|
+
this.#exitTimer = void 0;
|
|
85
|
+
}
|
|
86
|
+
this.#leaving = false;
|
|
87
|
+
this.#internals?.states.delete("leaving");
|
|
88
|
+
this.#startTimer();
|
|
89
|
+
}
|
|
90
|
+
/** A live DOM node to show as the content (set by the wrapper's DOM-node
|
|
91
|
+
* branch). Paired getter/setter so React 19's property assignment works. */
|
|
92
|
+
get content() {
|
|
93
|
+
return this.#content ?? null;
|
|
94
|
+
}
|
|
95
|
+
set content(node) {
|
|
96
|
+
this.#content = node ?? void 0;
|
|
97
|
+
this.#applyContent();
|
|
98
|
+
}
|
|
99
|
+
/** Slot the content node into our own light DOM. Only ever touches the node WE
|
|
100
|
+
* slotted (tracked in `#slotted`), never the reconciler's children: it removes
|
|
101
|
+
* the previous node and appends the new one, or removes it when `content` goes
|
|
102
|
+
* null (an in-place update swapping DOM-node content for a string / JSX — else
|
|
103
|
+
* the stale node would stack under the new content). String / JSX content
|
|
104
|
+
* arrives as reconciler-owned children, so `#content` is undefined and this
|
|
105
|
+
* only clears any node we had slotted. */
|
|
106
|
+
#applyContent() {
|
|
107
|
+
if (this.#content === this.#slotted) return;
|
|
108
|
+
if (this.#slotted?.parentNode === this) this.removeChild(this.#slotted);
|
|
109
|
+
this.#slotted = this.#content;
|
|
110
|
+
if (this.#content) this.append(this.#content);
|
|
111
|
+
}
|
|
112
|
+
/** Auto-dismiss delay in ms. Empty / non-positive falls back to the 5000ms
|
|
113
|
+
* default; `Infinity` is sticky (never auto-dismisses). */
|
|
114
|
+
get #duration() {
|
|
115
|
+
const a = this.getAttribute("duration");
|
|
116
|
+
if (a == null) return DEFAULT_DURATION;
|
|
117
|
+
const n = Number(a);
|
|
118
|
+
if (n === Infinity) return Infinity;
|
|
119
|
+
return Number.isFinite(n) && n > 0 ? n : DEFAULT_DURATION;
|
|
120
|
+
}
|
|
121
|
+
/** Paused while either hold is active. */
|
|
122
|
+
get #paused() {
|
|
123
|
+
return this.#hovered || this.#focused;
|
|
124
|
+
}
|
|
125
|
+
#startTimer() {
|
|
126
|
+
this.#remaining = this.#duration;
|
|
127
|
+
this.#startCountdown();
|
|
128
|
+
this.#armIfActive();
|
|
129
|
+
}
|
|
130
|
+
/** Set up (or restart) the display countdown that drives `--toast-remaining`
|
|
131
|
+
* 1 → 0 on the slot over `duration`; slotted content inherits it. It's display
|
|
132
|
+
* only — the auto-dismiss above is the real JS timer — so it degrades to a
|
|
133
|
+
* static full bar where custom-property animation is unsupported. Sticky
|
|
134
|
+
* (`Infinity` duration) runs no countdown; the var stays at its initial 1. */
|
|
135
|
+
#startCountdown() {
|
|
136
|
+
if (Number.isFinite(this.#duration)) {
|
|
137
|
+
this.#slot.style.animation = `toast-remaining ${this.#duration}ms linear forwards`;
|
|
138
|
+
this.#eachCountdown((a) => {
|
|
139
|
+
a.currentTime = 0;
|
|
140
|
+
});
|
|
141
|
+
if (this.#paused || this.#leaving) this.#pauseCountdown();
|
|
142
|
+
} else {
|
|
143
|
+
this.#slot.style.animation = "";
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
/** Run `fn` for the `--toast-remaining` animation on the slot, if present.
|
|
147
|
+
* Guarded — `getAnimations` / animation control may be absent in a partial
|
|
148
|
+
* runtime, and the countdown is non-essential (never let it break the toast). */
|
|
149
|
+
#eachCountdown(fn) {
|
|
150
|
+
try {
|
|
151
|
+
for (const a of this.#slot.getAnimations?.() ?? []) {
|
|
152
|
+
if (a.animationName === "toast-remaining") fn(a);
|
|
153
|
+
}
|
|
154
|
+
} catch {
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
#pauseCountdown() {
|
|
158
|
+
this.#eachCountdown((a) => a.pause());
|
|
159
|
+
}
|
|
160
|
+
#playCountdown() {
|
|
161
|
+
this.#eachCountdown((a) => a.play());
|
|
162
|
+
}
|
|
163
|
+
/** Start (or resume) the dismiss timer only when it should be running: a finite
|
|
164
|
+
* duration (a non-finite one is sticky), not leaving, not paused, not already
|
|
165
|
+
* running. */
|
|
166
|
+
#armIfActive() {
|
|
167
|
+
if (this.#timer != null || this.#leaving || this.#paused || !Number.isFinite(this.#duration)) return;
|
|
168
|
+
if (this.#remaining <= 0) {
|
|
169
|
+
this.dismiss();
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
this.#startedAt = Date.now();
|
|
173
|
+
this.#timer = this.view.setTimeout(() => {
|
|
174
|
+
this.#timer = void 0;
|
|
175
|
+
this.dismiss();
|
|
176
|
+
}, this.#remaining);
|
|
177
|
+
this.#playCountdown();
|
|
178
|
+
}
|
|
179
|
+
#clearTimer() {
|
|
180
|
+
if (this.#timer != null) {
|
|
181
|
+
this.view.clearTimeout(this.#timer);
|
|
182
|
+
this.#timer = void 0;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
/** Freeze the timer, banking the time left, and freeze the display countdown
|
|
186
|
+
* with it. Idempotent. */
|
|
187
|
+
#pause() {
|
|
188
|
+
if (this.#timer == null) return;
|
|
189
|
+
this.#remaining -= Date.now() - this.#startedAt;
|
|
190
|
+
this.#clearTimer();
|
|
191
|
+
this.#pauseCountdown();
|
|
192
|
+
}
|
|
193
|
+
#onPointerEnter = () => {
|
|
194
|
+
this.#hovered = true;
|
|
195
|
+
this.#pause();
|
|
196
|
+
};
|
|
197
|
+
#onPointerLeave = () => {
|
|
198
|
+
this.#hovered = false;
|
|
199
|
+
this.#armIfActive();
|
|
200
|
+
};
|
|
201
|
+
#onFocusIn = () => {
|
|
202
|
+
this.#focused = true;
|
|
203
|
+
this.#pause();
|
|
204
|
+
};
|
|
205
|
+
#onFocusOut = () => {
|
|
206
|
+
this.#focused = false;
|
|
207
|
+
this.#armIfActive();
|
|
208
|
+
};
|
|
209
|
+
#reducedMotion() {
|
|
210
|
+
return this.view.matchMedia?.("(prefers-reduced-motion: reduce)").matches ?? false;
|
|
211
|
+
}
|
|
212
|
+
/** How long to wait after starting the exit before emitting `dismiss` (node
|
|
213
|
+
* removal). Read from the computed `--toast-dur` token so it tracks a consumer
|
|
214
|
+
* override and the removal fires exactly when the fade ends — instead of a
|
|
215
|
+
* fixed 220ms that desyncs from a changed `--toast-dur`. 0 under reduced motion
|
|
216
|
+
* (the shadow transition is gated off there); `EXIT_MS` if it can't be read. */
|
|
217
|
+
#exitDuration() {
|
|
218
|
+
if (this.#reducedMotion()) return 0;
|
|
219
|
+
const raw = this.view.getComputedStyle?.(this).getPropertyValue("--toast-dur").trim();
|
|
220
|
+
if (raw) {
|
|
221
|
+
const n = parseFloat(raw);
|
|
222
|
+
if (Number.isFinite(n)) return raw.endsWith("ms") ? n : n * 1e3;
|
|
223
|
+
}
|
|
224
|
+
return EXIT_MS;
|
|
225
|
+
}
|
|
226
|
+
/** Restart the auto-dismiss timer from the current `duration` (an in-place
|
|
227
|
+
* update). If the toast is currently paused, the fresh time is banked and the
|
|
228
|
+
* countdown stays paused until hover / focus releases. */
|
|
229
|
+
restart() {
|
|
230
|
+
if (this.#leaving) return;
|
|
231
|
+
this.#clearTimer();
|
|
232
|
+
this.#startTimer();
|
|
233
|
+
}
|
|
234
|
+
/** Play the exit (shadow only), then emit a bubbling `dismiss`. The owner
|
|
235
|
+
* removes the node on that event — the element never removes itself.
|
|
236
|
+
* Idempotent. */
|
|
237
|
+
dismiss() {
|
|
238
|
+
if (this.#leaving) return;
|
|
239
|
+
this.#leaving = true;
|
|
240
|
+
this.#clearTimer();
|
|
241
|
+
this.#pauseCountdown();
|
|
242
|
+
this.#internals?.states.add("leaving");
|
|
243
|
+
const wait = this.#exitDuration();
|
|
244
|
+
this.#exitTimer = this.view.setTimeout(() => {
|
|
245
|
+
this.#exitTimer = void 0;
|
|
246
|
+
this.dispatchEvent(new CustomEvent("dismiss", { bubbles: true, composed: true }));
|
|
247
|
+
}, wait);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
const SHADOW_STYLE = `
|
|
251
|
+
:host { display: block; opacity: 1; translate: 0 0; }
|
|
252
|
+
:host(:state(leaving)) { opacity: 0; }
|
|
253
|
+
|
|
254
|
+
@starting-style {
|
|
255
|
+
:host { opacity: 0; translate: 0 12px; }
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
259
|
+
:host {
|
|
260
|
+
transition:
|
|
261
|
+
opacity var(--toast-dur, 220ms) ease,
|
|
262
|
+
translate var(--toast-dur, 220ms) ease;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
slot { display: block; }
|
|
267
|
+
|
|
268
|
+
@keyframes toast-remaining {
|
|
269
|
+
from { --toast-remaining: 1; }
|
|
270
|
+
to { --toast-remaining: 0; }
|
|
271
|
+
}
|
|
272
|
+
`;
|
|
273
|
+
function register_a_toast() {
|
|
274
|
+
if (typeof customElements === "undefined") return;
|
|
275
|
+
if (!customElements.get("a-toast")) {
|
|
276
|
+
customElements.define("a-toast", AToastElement);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
register_a_toast();
|
|
280
|
+
export {
|
|
281
|
+
AToastElement,
|
|
282
|
+
register_a_toast
|
|
283
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@layer anta{a-toaster{--toaster-inset: 16px;--toaster-gap: 12px;--toaster-width: 380px}a-toaster:not(:defined){display:none}}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { HTMLElementBase } from '../anta_helpers';
|
|
2
|
+
import './a-toaster.css';
|
|
3
|
+
/**
|
|
4
|
+
* `<a-toaster>` — a viewport-anchored notification region. One instance hosts all
|
|
5
|
+
* six placement zones; each `<a-toast>` routes to a corner/edge by its `slot`
|
|
6
|
+
* attribute (`slot="bottom-right"`, …). The `<Toaster>` wrapper keeps it mounted
|
|
7
|
+
* and renders its `<a-toast>` children through the reconciler; this element only
|
|
8
|
+
* lays them out — it touches its own shadow and reads its children, never a host
|
|
9
|
+
* or light-DOM write.
|
|
10
|
+
*
|
|
11
|
+
* Shadow structure:
|
|
12
|
+
*
|
|
13
|
+
* <div part="region" popover="manual"> ← top-layer, viewport-covering, click-through
|
|
14
|
+
* <slot name="top-left"> … ← one flex column per zone, pinned to its edge
|
|
15
|
+
* <slot name="bottom-right"> …
|
|
16
|
+
*
|
|
17
|
+
* The region is a `popover` so it renders in the top layer and escapes any
|
|
18
|
+
* transformed / clipping ancestor of wherever `<Toaster>` is mounted. It's shown
|
|
19
|
+
* only while it holds at least one toast (`showPopover`) and hidden when empty
|
|
20
|
+
* (`hidePopover`), so it never sits in the top layer for nothing. Natural
|
|
21
|
+
* top-layer ordering stands: a dialog or menu opened afterward can cover it (by
|
|
22
|
+
* design — toasts don't force themselves above modals).
|
|
23
|
+
*/
|
|
24
|
+
export declare class AToasterElement extends HTMLElementBase {
|
|
25
|
+
#private;
|
|
26
|
+
constructor();
|
|
27
|
+
connectedCallback(): void;
|
|
28
|
+
disconnectedCallback(): void;
|
|
29
|
+
}
|
|
30
|
+
export declare function register_a_toaster(): void;
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { HTMLElementBase } from "../anta_helpers";
|
|
2
|
+
import { TOAST_PLACEMENTS } from "../toaster";
|
|
3
|
+
import "./a-toaster.css";
|
|
4
|
+
const ZONES = TOAST_PLACEMENTS;
|
|
5
|
+
class AToasterElement extends HTMLElementBase {
|
|
6
|
+
#region;
|
|
7
|
+
#shown = false;
|
|
8
|
+
constructor() {
|
|
9
|
+
super();
|
|
10
|
+
const shadow = this.attachShadow({ mode: "open" });
|
|
11
|
+
const style = document.createElement("style");
|
|
12
|
+
style.textContent = SHADOW_STYLE;
|
|
13
|
+
this.#region = document.createElement("div");
|
|
14
|
+
this.#region.className = "region";
|
|
15
|
+
this.#region.setAttribute("part", "region");
|
|
16
|
+
this.#region.setAttribute("popover", "manual");
|
|
17
|
+
for (const zone of ZONES) {
|
|
18
|
+
const slot = document.createElement("slot");
|
|
19
|
+
slot.name = zone;
|
|
20
|
+
this.#region.append(slot);
|
|
21
|
+
}
|
|
22
|
+
this.#region.addEventListener("slotchange", this.#syncVisibility);
|
|
23
|
+
shadow.append(style, this.#region);
|
|
24
|
+
}
|
|
25
|
+
connectedCallback() {
|
|
26
|
+
this.#syncVisibility();
|
|
27
|
+
}
|
|
28
|
+
disconnectedCallback() {
|
|
29
|
+
this.#shown = false;
|
|
30
|
+
}
|
|
31
|
+
/** Show the region while it holds a toast, hide it when empty. A child count
|
|
32
|
+
* read + a shadow popover toggle — no host or light-DOM mutation. */
|
|
33
|
+
#syncVisibility = () => {
|
|
34
|
+
const region = this.#region;
|
|
35
|
+
if (typeof region.showPopover !== "function") return;
|
|
36
|
+
const has = this.childElementCount > 0;
|
|
37
|
+
if (has && !this.#shown) {
|
|
38
|
+
if (!this.isConnected) return;
|
|
39
|
+
try {
|
|
40
|
+
region.showPopover();
|
|
41
|
+
this.#shown = true;
|
|
42
|
+
} catch {
|
|
43
|
+
}
|
|
44
|
+
} else if (!has && this.#shown) {
|
|
45
|
+
try {
|
|
46
|
+
if (region.matches(":popover-open")) region.hidePopover();
|
|
47
|
+
} catch {
|
|
48
|
+
}
|
|
49
|
+
this.#shown = false;
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
const SHADOW_STYLE = `
|
|
54
|
+
:host { display: contents; }
|
|
55
|
+
|
|
56
|
+
.region {
|
|
57
|
+
position: fixed;
|
|
58
|
+
inset: 0;
|
|
59
|
+
margin: 0;
|
|
60
|
+
padding: 0;
|
|
61
|
+
border: 0;
|
|
62
|
+
background: transparent;
|
|
63
|
+
overflow: visible;
|
|
64
|
+
pointer-events: none;
|
|
65
|
+
width: auto;
|
|
66
|
+
height: auto;
|
|
67
|
+
}
|
|
68
|
+
.region:popover-open { display: block; }
|
|
69
|
+
|
|
70
|
+
slot {
|
|
71
|
+
position: absolute;
|
|
72
|
+
display: flex;
|
|
73
|
+
flex-direction: column;
|
|
74
|
+
gap: var(--toaster-gap, 12px);
|
|
75
|
+
width: min(var(--toaster-width, 380px), calc(100vw - 2 * var(--toaster-inset, 16px)));
|
|
76
|
+
box-sizing: border-box;
|
|
77
|
+
pointer-events: none;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
::slotted(*) { pointer-events: auto; }
|
|
81
|
+
|
|
82
|
+
slot[name^="top-"] { top: var(--toaster-inset, 16px); flex-direction: column-reverse; }
|
|
83
|
+
slot[name^="bottom-"] { bottom: var(--toaster-inset, 16px); flex-direction: column; }
|
|
84
|
+
slot[name$="-left"] { left: var(--toaster-inset, 16px); }
|
|
85
|
+
slot[name$="-right"] { right: var(--toaster-inset, 16px); }
|
|
86
|
+
slot[name$="-center"] { left: 50%; transform: translateX(-50%); }
|
|
87
|
+
`;
|
|
88
|
+
function register_a_toaster() {
|
|
89
|
+
if (typeof customElements === "undefined") return;
|
|
90
|
+
if (!customElements.get("a-toaster")) {
|
|
91
|
+
customElements.define("a-toaster", AToasterElement);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
register_a_toaster();
|
|
95
|
+
export {
|
|
96
|
+
AToasterElement,
|
|
97
|
+
register_a_toaster
|
|
98
|
+
};
|
package/dist/elements/index.d.ts
CHANGED
|
@@ -35,5 +35,6 @@ export { ATabsElement, register_a_tabs } from './a-tabs';
|
|
|
35
35
|
export { ATabPanelElement, register_a_tabpanel } from './a-tabpanel';
|
|
36
36
|
export { ADialogElement, register_a_dialog } from './a-dialog';
|
|
37
37
|
export { ACardElement, register_a_card } from './a-card';
|
|
38
|
+
export { ABannerElement, register_a_banner } from './a-banner';
|
|
38
39
|
import './a-title.css';
|
|
39
40
|
import './a-tag.css';
|
package/dist/elements/index.js
CHANGED
|
@@ -20,9 +20,11 @@ import { ATabsElement, register_a_tabs } from "./a-tabs";
|
|
|
20
20
|
import { ATabPanelElement, register_a_tabpanel } from "./a-tabpanel";
|
|
21
21
|
import { ADialogElement, register_a_dialog } from "./a-dialog";
|
|
22
22
|
import { ACardElement, register_a_card } from "./a-card";
|
|
23
|
+
import { ABannerElement, register_a_banner } from "./a-banner";
|
|
23
24
|
import "./a-title.css";
|
|
24
25
|
import "./a-tag.css";
|
|
25
26
|
export {
|
|
27
|
+
ABannerElement,
|
|
26
28
|
AButtonElement,
|
|
27
29
|
ACalendarElement,
|
|
28
30
|
ACardElement,
|
|
@@ -45,6 +47,7 @@ export {
|
|
|
45
47
|
ATabsElement,
|
|
46
48
|
ATextElement,
|
|
47
49
|
ATooltipElement,
|
|
50
|
+
register_a_banner,
|
|
48
51
|
register_a_button,
|
|
49
52
|
register_a_calendar,
|
|
50
53
|
register_a_card,
|
package/dist/general_types.d.ts
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import type { IconShape } from './elements/a-icon.shapes';
|
|
2
2
|
/** Common props for JSX component wrappers. */
|
|
3
3
|
export interface BaseProps {
|
|
4
|
-
/** CSS class
|
|
4
|
+
/** CSS class on the component's root element (merged with the component's own
|
|
5
|
+
* classes). Use it directly for layout and positioning — grid/flex placement,
|
|
6
|
+
* margins, alignment — rather than wrapping the component in a `<div>`/`<span>`. */
|
|
5
7
|
className?: string;
|
|
6
|
-
/** Inline styles
|
|
8
|
+
/** Inline styles on the component's root element. Set layout/positioning here
|
|
9
|
+
* (or via `className`) directly on the component instead of adding a wrapper. */
|
|
7
10
|
style?: React.CSSProperties;
|
|
8
11
|
/** Child elements. When provided, replaces the component's default label/content. */
|
|
9
12
|
children?: React.ReactNode;
|
|
@@ -172,8 +175,8 @@ export interface AProgressAttributes extends BaseAttributes {
|
|
|
172
175
|
* from `@antadesign/anta`.
|
|
173
176
|
*/
|
|
174
177
|
export interface ATextAttributes extends BaseAttributes {
|
|
175
|
-
/** Visual priority. Maps to text-1..text-
|
|
176
|
-
priority?: 'primary' | 'secondary' | 'tertiary' | 'quaternary'
|
|
178
|
+
/** Visual priority. Maps to text-1..text-4. */
|
|
179
|
+
priority?: 'primary' | 'secondary' | 'tertiary' | 'quaternary';
|
|
177
180
|
/** Color tint. `neutral` (default) is the untinted `--text-{N}` scale; a named
|
|
178
181
|
* tone applies the matching `--text-{N}-{tone}` palette; any literal CSS color
|
|
179
182
|
* is a custom tone (hue kept, lightness/chroma pinned per priority in oklch). */
|
|
@@ -207,8 +210,8 @@ export interface ATextAttributes extends BaseAttributes {
|
|
|
207
210
|
export interface ATitleAttributes extends BaseAttributes {
|
|
208
211
|
/** Heading level as a string attribute, '1'-'6'. */
|
|
209
212
|
level?: string;
|
|
210
|
-
/** Visual priority. Maps to text-1..text-
|
|
211
|
-
priority?: 'primary' | 'secondary' | 'tertiary' | 'quaternary'
|
|
213
|
+
/** Visual priority. Maps to text-1..text-4. */
|
|
214
|
+
priority?: 'primary' | 'secondary' | 'tertiary' | 'quaternary';
|
|
212
215
|
/** Color tint. `neutral` (default) is the untinted `--text-{N}` scale; a named
|
|
213
216
|
* tone applies the matching `--text-{N}-{tone}` palette; any literal CSS color
|
|
214
217
|
* is a custom tone (hue kept, lightness/chroma pinned per priority in oklch). */
|
|
@@ -374,7 +377,7 @@ export interface AIconAttributes extends BaseAttributes {
|
|
|
374
377
|
* `Tooltip` from `@antadesign/anta`.
|
|
375
378
|
*/
|
|
376
379
|
export interface ATooltipAttributes extends BaseAttributes {
|
|
377
|
-
/** Show delay in milliseconds. Never use `0` — use ~`50`. Defaults to
|
|
380
|
+
/** Show delay in milliseconds. Never use `0` — use ~`50`. Defaults to 300. */
|
|
378
381
|
delay?: number | string;
|
|
379
382
|
/** Preferred side; auto-flips when there's no room. Defaults to `'bottom'`. */
|
|
380
383
|
placement?: 'top' | 'bottom';
|
|
@@ -635,8 +638,8 @@ export interface ACalendarAttributes extends BaseAttributes {
|
|
|
635
638
|
*/
|
|
636
639
|
export interface AMenuAttributes extends BaseAttributes {
|
|
637
640
|
/** Preferred placement relative to the trigger; auto-flips / clamps.
|
|
638
|
-
* Defaults to `'bottom-start'`. */
|
|
639
|
-
placement?: 'bottom-start' | 'bottom-end' | 'top-start' | 'top-end' | 'bottom' | 'top';
|
|
641
|
+
* Defaults to `'bottom-start'`. `right` / `left` place the menu beside the trigger. */
|
|
642
|
+
placement?: 'bottom-start' | 'bottom-end' | 'top-start' | 'top-end' | 'bottom' | 'top' | 'right-start' | 'right-end' | 'left-start' | 'left-end' | 'right' | 'left';
|
|
640
643
|
/** Open on right-click of the trigger region, positioned at the pointer.
|
|
641
644
|
* Presence-based (`''` on, omit off). */
|
|
642
645
|
context?: boolean | '';
|
|
@@ -1078,3 +1081,43 @@ export interface ACardAttributes extends BaseAttributes {
|
|
|
1078
1081
|
* chain the element derives in link mode. */
|
|
1079
1082
|
'aria-label'?: string;
|
|
1080
1083
|
}
|
|
1084
|
+
/**
|
|
1085
|
+
* Attributes for the `<a-banner>` custom element — a full-width, dismissible
|
|
1086
|
+
* message strip (borderless by default; opt into a rule via `border-bottom-width` /
|
|
1087
|
+
* `border-width`, the Progress pattern). Slots (light-DOM children): `message`
|
|
1088
|
+
* (leading), the default slot (middle content), `actions` (trailing), and `close`
|
|
1089
|
+
* (the ✕ button). The element exposes `::part(message | content | actions | close)`,
|
|
1090
|
+
* and `:state(open)` / `:state(closed)` as visibility hooks (the external
|
|
1091
|
+
* sheet collapses the host on `:state(closed)`). Low-level attributes; for the
|
|
1092
|
+
* typed JSX wrapper use `Banner` from `@antadesign/anta`.
|
|
1093
|
+
*/
|
|
1094
|
+
export interface ABannerAttributes extends BaseAttributes {
|
|
1095
|
+
/** Controlled visibility (`'open'` / `'closed'`). Present → controlled: the
|
|
1096
|
+
* attribute is the source of truth, the ✕ dismiss only dispatches the cancelable
|
|
1097
|
+
* `statechange` event, and the consumer answers by updating it. Absent →
|
|
1098
|
+
* uncontrolled (use `default-state`). The `<Banner>` wrapper presents this as
|
|
1099
|
+
* `dismissed` (closed = dismissed). See STATEFUL-COMPONENTS.md. */
|
|
1100
|
+
state?: 'open' | 'closed';
|
|
1101
|
+
/** Initial visibility for the uncontrolled mode (`'open'` / `'closed'`), read
|
|
1102
|
+
* once at connect. A banner is shown by default, so omit / `'open'` shows it;
|
|
1103
|
+
* `'closed'` starts it dismissed. */
|
|
1104
|
+
'default-state'?: 'open' | 'closed';
|
|
1105
|
+
/** Semantic tone, or any literal CSS color for a one-off custom tone. Named tones
|
|
1106
|
+
* re-point the surface + text + border colour (used if you opt into a border); a
|
|
1107
|
+
* custom color keeps its hue with lightness/chroma pinned. `'neutral'` is the
|
|
1108
|
+
* default (same as omitting it). */
|
|
1109
|
+
tone?: 'neutral' | 'brand' | 'info' | 'success' | 'warning' | 'critical' | (string & {});
|
|
1110
|
+
/** Rounded corners for a standalone banner — `border-radius: 999px` (clamps to a
|
|
1111
|
+
* stadium), or a custom radius via a length value (`round="12px"`). Borderless
|
|
1112
|
+
* like the default. Presence-based for the boolean form. */
|
|
1113
|
+
round?: boolean | number | string;
|
|
1114
|
+
/** Fires before visibility changes — the element dispatches a `cancelable`
|
|
1115
|
+
* `statechange` `CustomEvent` whose `detail` is `{ next, prev }` in the
|
|
1116
|
+
* `'open'|'closed'` vocabulary (a dismiss is always `next: 'closed'`).
|
|
1117
|
+
* Uncontrolled, `preventDefault()` vetoes the transition. All-lowercase so both
|
|
1118
|
+
* renderers bind it (React 19 keeps the case after `on`; Preact lowercases). */
|
|
1119
|
+
onstatechange?: (e: CustomEvent<{
|
|
1120
|
+
next: 'open' | 'closed';
|
|
1121
|
+
prev: 'open' | 'closed';
|
|
1122
|
+
}>) => void;
|
|
1123
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -63,7 +63,7 @@ export type { CalendarDay, CalendarWeekday, CalendarMonth, BuildMonthOptions, Pa
|
|
|
63
63
|
export { RadioGroup } from './components/RadioGroup';
|
|
64
64
|
export type { RadioGroupProps, RadioOption } from './components/RadioGroup';
|
|
65
65
|
export { Select, optionsWithSelection } from './components/Select';
|
|
66
|
-
export type { SelectProps, SelectCommonProps, SelectOption, SelectGroup, SelectSubmenu, SelectItem, SelectChangeAttrs, OptionState, TriggerState, EmptyState, SelectionState, SelectedOption, SelectedGroup, SelectedSubmenu, SelectedItem, } from './components/Select';
|
|
66
|
+
export type { SelectProps, SelectCommonProps, OptionValue, SelectOption, SelectGroup, SelectSubmenu, SelectItem, SelectChangeAttrs, OptionState, TriggerState, EmptyState, SelectionState, SelectedOption, SelectedGroup, SelectedSubmenu, SelectedItem, } from './components/Select';
|
|
67
67
|
export { SelectFaceted } from './components/SelectFaceted';
|
|
68
68
|
export type { SelectFacetedProps, SelectFacet, SelectFacetSingle, SelectFacetMultiple, SelectFacetText, SelectFacetCustom, SelectFacetCustomContext, SelectFacetedValue, SelectFacetedChangeAttrs, SelectFacetedTriggerState, } from './components/SelectFaceted';
|
|
69
69
|
export { Tabs } from './components/Tabs';
|
|
@@ -74,6 +74,8 @@ export { Dialog } from './components/Dialog';
|
|
|
74
74
|
export type { DialogProps } from './components/Dialog';
|
|
75
75
|
export { Card } from './components/Card';
|
|
76
76
|
export type { CardProps } from './components/Card';
|
|
77
|
+
export { Banner } from './components/Banner';
|
|
78
|
+
export type { BannerProps } from './components/Banner';
|
|
77
79
|
export type { BaseProps, BaseAttributes } from './general_types';
|
|
78
80
|
export { configure } from './jsx-runtime';
|
|
79
81
|
export type { AntaIntrinsicElements } from './jsx-runtime';
|
package/dist/index.js
CHANGED
|
@@ -42,8 +42,10 @@ import { Tabs } from "./components/Tabs";
|
|
|
42
42
|
import { TabPanel } from "./components/TabPanel";
|
|
43
43
|
import { Dialog } from "./components/Dialog";
|
|
44
44
|
import { Card } from "./components/Card";
|
|
45
|
+
import { Banner } from "./components/Banner";
|
|
45
46
|
import { configure } from "./jsx-runtime";
|
|
46
47
|
export {
|
|
48
|
+
Banner,
|
|
47
49
|
Button,
|
|
48
50
|
ButtonCopy,
|
|
49
51
|
Calendar,
|
package/dist/jsx-runtime.d.ts
CHANGED
|
@@ -41,7 +41,7 @@ export declare function useMemo<T>(factory: () => T, deps: unknown[]): T;
|
|
|
41
41
|
export declare function jsx(type: ComponentType, props: Record<string, unknown> | null, key?: string | number): unknown;
|
|
42
42
|
export declare function jsxs(type: ComponentType, props: Record<string, unknown> | null, key?: string | number): unknown;
|
|
43
43
|
export { _Fragment as Fragment };
|
|
44
|
-
import type { AProgressAttributes, ATextAttributes, ATitleAttributes, ATagAttributes, AExpanderAttributes, AIconAttributes, AButtonAttributes, ACopyAttributes, ACheckboxAttributes, ATooltipAttributes, AInputAttributes, AInputTimeAttributes, ACalendarAttributes, ARadioAttributes, ARadioGroupAttributes, AMenuAttributes, AMenuItemAttributes, AMenuGroupAttributes, ATabsAttributes, ATabAttributes, ATabpanelAttributes, ADialogAttributes, ACardAttributes, BaseAttributes } from './general_types';
|
|
44
|
+
import type { AProgressAttributes, ATextAttributes, ATitleAttributes, ATagAttributes, AExpanderAttributes, AIconAttributes, AButtonAttributes, ACopyAttributes, ACheckboxAttributes, ATooltipAttributes, AInputAttributes, AInputTimeAttributes, ACalendarAttributes, ARadioAttributes, ARadioGroupAttributes, AMenuAttributes, AMenuItemAttributes, AMenuGroupAttributes, ATabsAttributes, ATabAttributes, ATabpanelAttributes, ADialogAttributes, ACardAttributes, ABannerAttributes, BaseAttributes } from './general_types';
|
|
45
45
|
export declare namespace JSX {
|
|
46
46
|
interface IntrinsicElements extends React.JSX.IntrinsicElements, AntaIntrinsicElements {
|
|
47
47
|
}
|
|
@@ -94,4 +94,6 @@ export interface AntaIntrinsicElements {
|
|
|
94
94
|
'a-tabpanel': ATabpanelAttributes;
|
|
95
95
|
'a-dialog': ADialogAttributes;
|
|
96
96
|
'a-card': ACardAttributes;
|
|
97
|
+
'a-banner': ABannerAttributes;
|
|
98
|
+
'a-banner-message': BaseAttributes;
|
|
97
99
|
}
|
package/dist/reset.css
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
@layer anta{*,*:before,*:after{box-sizing:border-box}*{margin:0}img,picture,video,canvas,svg{display:block;max-width:100%}input,button,textarea,select{font:inherit}p,h1,h2,h3,h4,h5,h6{overflow-wrap:break-word}p{text-wrap:pretty}h1,h2,h3,h4,h5,h6{text-wrap:balance}h1,h2,h3,h4,h5,h6{color:var(--text-1);font-weight:584.62;letter-spacing:0}h1{font-size:28px;line-height:32px;margin-block:0 16px}h2{font-size:24px;line-height:28px;margin-block:32px 12px}h3{font-size:20px;line-height:24px;margin-block:24px 12px}h4{font-size:17px;line-height:20px;margin-block:20px 8px}h5{font-size:15px;line-height:20px;margin-block:16px 8px}h6{font-size:13px;line-height:16px;margin-block:16px 4px}strong{font-weight:600}code{line-height:1em}code,kbd,samp,pre{letter-spacing:0}ul,ol{padding-left:3ch}:is(ul,ol)>li{margin-bottom:.5em}:is(ul,ol)>li::marker{color:var(--text-5)}menu{list-style:none;padding:0;margin:0}menu>li{margin:0}a:not(:where([role=button])),a:not(:where([role=button])):link,a:not(:where([role=button])):visited{color:var(--link-color);text-decoration:underline;text-decoration-style:solid;text-decoration-color:color-mix(in srgb,currentColor 75%,transparent);text-decoration-thickness:.5px;text-underline-offset:3px}@media(hover:hover)and (pointer:fine){a:not(:where([role=button])):hover{color:var(--link-color-hover);text-decoration-thickness:1px}}a:not(:where([role=button])):active{text-decoration-color:color-mix(in srgb,currentColor 75%,transparent)}::selection{background:color-mix(in oklch,var(--focus-ring) 20%,transparent)}.dark ::selection{background:color-mix(in oklch,var(--focus-ring) 30%,transparent)}table{border-collapse:collapse;font-variant-numeric:lining-nums tabular-nums}caption{text-align:left;color:var(--text-3);padding-left:10px;margin-bottom:.25em}th,td{padding:5px 10px;text-align:left;vertical-align:top;border-bottom:1px solid var(--border-4)}thead th{font-weight:600}tfoot tr:last-child>:is(th,td),table:not(:has(tfoot)) tbody tr:last-child>:is(th,td){border-bottom:none}table[data-bordered]{border-collapse:separate;border-spacing:0;border:1px solid var(--border-4);border-radius:3px}table[data-bordered] :is(th,td){border-right:1px solid var(--border-4)}table[data-bordered] tr>:is(th,td):last-child{border-right:0}}
|
|
1
|
+
@layer anta{*,*:before,*:after{box-sizing:border-box}*{margin:0}img,picture,video,canvas,svg{display:block;max-width:100%}input,button,textarea,select{font:inherit}p,h1,h2,h3,h4,h5,h6{overflow-wrap:break-word}p{text-wrap:pretty}h1,h2,h3,h4,h5,h6{text-wrap:balance}h1,h2,h3,h4,h5,h6{color:var(--text-1);font-weight:584.62;letter-spacing:0}h1{font-size:28px;line-height:32px;margin-block:0 16px}h2{font-size:24px;line-height:28px;margin-block:32px 12px}h3{font-size:20px;line-height:24px;margin-block:24px 12px}h4{font-size:17px;line-height:20px;margin-block:20px 8px}h5{font-size:15px;line-height:20px;margin-block:16px 8px}h6{font-size:13px;line-height:16px;margin-block:16px 4px}strong{font-weight:600}dfn{font-style:normal;text-decoration:underline dotted;text-underline-offset:3px;text-decoration-color:color-mix(in oklch,currentColor 50%,transparent)}code{line-height:1em}code,kbd,samp,pre{letter-spacing:0}ul,ol{padding-left:3ch}:is(ul,ol)>li{margin-bottom:.5em}:is(ul,ol)>li::marker{color:var(--text-5)}menu{list-style:none;padding:0;margin:0}menu>li{margin:0}a:not(:where([role=button])),a:not(:where([role=button])):link,a:not(:where([role=button])):visited{color:var(--link-color);text-decoration:underline;text-decoration-style:solid;text-decoration-color:color-mix(in srgb,currentColor 75%,transparent);text-decoration-thickness:.5px;text-underline-offset:3px}@media(hover:hover)and (pointer:fine){a:not(:where([role=button])):hover{color:var(--link-color-hover);text-decoration-thickness:1px}}a:not(:where([role=button])):active{text-decoration-color:color-mix(in srgb,currentColor 75%,transparent)}::selection{background:color-mix(in oklch,var(--focus-ring) 20%,transparent)}.dark ::selection{background:color-mix(in oklch,var(--focus-ring) 30%,transparent)}table{border-collapse:collapse;font-variant-numeric:lining-nums tabular-nums}caption{text-align:left;color:var(--text-3);padding-left:10px;margin-bottom:.25em}th,td{padding:5px 10px;text-align:left;vertical-align:top;border-bottom:1px solid var(--border-4)}thead th{font-weight:600}tfoot tr:last-child>:is(th,td),table:not(:has(tfoot)) tbody tr:last-child>:is(th,td){border-bottom:none}table[data-bordered]{border-collapse:separate;border-spacing:0;border:1px solid var(--border-4);border-radius:3px}table[data-bordered] :is(th,td){border-right:1px solid var(--border-4)}table[data-bordered] tr>:is(th,td):last-child{border-right:0}}
|