@antadesign/anta 0.1.1-dev.8 → 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.
Files changed (43) hide show
  1. package/README.md +2 -2
  2. package/dist/components/Button.js +4 -3
  3. package/dist/components/Menu.d.ts +61 -0
  4. package/dist/components/Menu.js +34 -0
  5. package/dist/components/MenuGroup.d.ts +24 -0
  6. package/dist/components/MenuGroup.js +19 -0
  7. package/dist/components/MenuItem.d.ts +49 -0
  8. package/dist/components/MenuItem.js +40 -0
  9. package/dist/components/MenuSeparator.d.ts +14 -0
  10. package/dist/components/MenuSeparator.js +7 -0
  11. package/dist/components/Tag.d.ts +55 -0
  12. package/dist/components/Tag.js +40 -0
  13. package/dist/components/Text.d.ts +4 -2
  14. package/dist/components/Tooltip.d.ts +4 -2
  15. package/dist/elements/a-button.css +31 -8
  16. package/dist/elements/a-icon.shapes.css +4 -0
  17. package/dist/elements/a-icon.shapes.d.ts +2 -1
  18. package/dist/elements/a-icon.shapes.js +3 -1
  19. package/dist/elements/a-menu-group.css +21 -0
  20. package/dist/elements/a-menu-group.d.ts +13 -0
  21. package/dist/elements/a-menu-group.js +15 -0
  22. package/dist/elements/a-menu-item.css +162 -0
  23. package/dist/elements/a-menu-item.d.ts +27 -0
  24. package/dist/elements/a-menu-item.js +29 -0
  25. package/dist/elements/a-menu-separator.css +15 -0
  26. package/dist/elements/a-menu-separator.d.ts +12 -0
  27. package/dist/elements/a-menu-separator.js +15 -0
  28. package/dist/elements/a-menu.css +34 -0
  29. package/dist/elements/a-menu.d.ts +120 -0
  30. package/dist/elements/a-menu.js +649 -0
  31. package/dist/elements/a-tag.css +196 -0
  32. package/dist/elements/a-text.css +17 -13
  33. package/dist/elements/a-tooltip.css +21 -1
  34. package/dist/elements/a-tooltip.d.ts +7 -0
  35. package/dist/elements/a-tooltip.js +96 -19
  36. package/dist/elements/index.d.ts +2 -4
  37. package/dist/elements/index.js +1 -6
  38. package/dist/general_types.d.ts +15 -35
  39. package/dist/index.d.ts +2 -4
  40. package/dist/index.js +2 -4
  41. package/dist/jsx-runtime.d.ts +6 -5
  42. package/dist/reset.css +11 -7
  43. package/package.json +13 -15
package/README.md CHANGED
@@ -36,7 +36,7 @@ Anta exposes four independent imports. Tokens + elements + the JSX layer are the
36
36
 
37
37
  The chain matters: the per-element CSS that ships with `/elements` references variables like `var(--text-1)` and `var(--bg-2)`. Those variables are *only defined* by `tokens.css`. Skip the tokens import and the components render with whatever the surrounding cascade provides — usually nothing styled at all.
38
38
 
39
- `@antadesign/anta/elements` registers **all** elements — convenient, but it includes every element's code (and deps). To keep your bundle lean, import only the elements you use from their per-element entry points instead: `import '@antadesign/anta/elements/a-tooltip'` registers just `<a-tooltip>` **and loads just its CSS**. Unused elements — and their dependencies, e.g. `lottie-web` (needed only by `<a-sticker-animated>`) — then never enter your bundle. See [Registering elements](#registering-elements).
39
+ `@antadesign/anta/elements` registers **all** elements — convenient, but it includes every element's code (and deps). To keep your bundle lean, import only the elements you use from their per-element entry points instead: `import '@antadesign/anta/elements/a-tooltip'` registers just `<a-tooltip>` **and loads just its CSS**. Unused elements — and any dependencies they pull in — then never enter your bundle. See [Registering elements](#registering-elements).
40
40
 
41
41
  ### Cascade layers
42
42
 
@@ -79,7 +79,7 @@ import '@antadesign/anta/elements/a-tooltip' // only <a-tooltip> + its CSS
79
79
  import '@antadesign/anta/elements/a-button' // only <a-button> + its CSS
80
80
  ```
81
81
 
82
- Both styles are side-effect imports (the act of importing registers the element), and both are idempotent and SSR-safe. The granular form keeps unused elements — and their dependencies, e.g. `lottie-web`, which only `<a-sticker-animated>` pulls in — out of your bundle.
82
+ Both styles are side-effect imports (the act of importing registers the element), and both are idempotent and SSR-safe. The granular form keeps unused elements — and any dependencies they pull in — out of your bundle.
83
83
 
84
84
  The cleanest pattern is a **static, synchronous import at your app's entry file** — outside any component, outside any hook:
85
85
 
@@ -38,12 +38,13 @@ const Button = ({
38
38
  children,
39
39
  ...rest
40
40
  }) => {
41
- const isCustomTone = tone != null && !NAMED_TONES.has(tone);
42
- const computedStyle = isCustomTone ? { ...style, ["--button-tone-source"]: tone } : style;
41
+ const toneAttr = tone || void 0;
42
+ const isCustomTone = toneAttr != null && !NAMED_TONES.has(toneAttr);
43
+ const computedStyle = isCustomTone ? { ...style, ["--button-tone-source"]: toneAttr } : style;
43
44
  const isIconOnly = icon != null && label == null && children == null && iconTrailing == null;
44
45
  const sharedAttrs = {
45
46
  priority,
46
- tone,
47
+ tone: toneAttr,
47
48
  underline,
48
49
  // 'medium' (and unset) is the implicit default — emit no DOM attr.
49
50
  size: size && size !== "medium" ? size : void 0,
@@ -0,0 +1,61 @@
1
+ import type { BaseProps } from '../general_types';
2
+ export interface MenuProps extends BaseProps {
3
+ /** Preferred placement relative to the trigger. The cross-axis suffix
4
+ * (`-start` / `-end`) aligns the left / right edges; the menu auto-flips
5
+ * vertically and clamps horizontally when there isn't room.
6
+ * @defaultValue bottom-start */
7
+ placement?: 'bottom-start' | 'bottom-end' | 'top-start' | 'top-end';
8
+ /** Open on right-click (the `contextmenu` event) of the trigger region
9
+ * instead of a left click, positioned at the pointer. */
10
+ context?: boolean;
11
+ /** Open at the pointer coordinates rather than aligned to the trigger box.
12
+ * Pairs naturally with `context`; on its own it positions a left-click
13
+ * menu at the cursor. */
14
+ coord?: boolean;
15
+ /** Marks this menu as a submenu of the enclosing `MenuItem`. Set by passing
16
+ * it as a `MenuItem`'s `submenu`; rarely written by hand. */
17
+ submenu?: boolean;
18
+ /** For a submenu: also open it on hover (with intent timing), not only on
19
+ * click. No effect on a root menu. */
20
+ hover?: boolean;
21
+ /** Gap in pixels between the trigger and the menu.
22
+ * @defaultValue 4 */
23
+ offset?: number;
24
+ /** Controlled open state. Omit for the default **uncontrolled** menu (it
25
+ * opens/closes itself). Pass `'opened'` / `'closed'` to **control** it: the
26
+ * menu's visibility follows this value, and user dismiss (Esc, outside-click,
27
+ * select) fires `openchange` *without* self-closing — you update `state` in
28
+ * response. A string (not a boolean) so there's no `"false"`-as-truthy
29
+ * footgun. Submenus are always uncontrolled regardless of this. */
30
+ state?: 'opened' | 'closed';
31
+ /** The menu's contents: `MenuItem`, `MenuSeparator`, `MenuGroup`, or any
32
+ * custom element. */
33
+ children?: React.ReactNode;
34
+ }
35
+ /**
36
+ * Menu — a dropdown / context menu that anchors to any target and "just
37
+ * works". Place `<Menu>` immediately after the trigger element (a button,
38
+ * say); it opens on click by default. For a whole-area right-click menu, put
39
+ * it after the region and pass `context`.
40
+ *
41
+ * Open state is uncontrolled by default — listen for the `openchange` event
42
+ * (`detail: { open, previousState }`) to observe it, or pass `state` to control
43
+ * it. You can also grab a `ref` and call `.open()` / `.close()` / `.toggle()`.
44
+ * Selecting a `MenuItem` closes the menu;
45
+ * arbitrary injected content does not. Add `data-menu-open` to any item /
46
+ * container to keep it open, or `data-menu-close` to a custom element to let it
47
+ * close.
48
+ *
49
+ * Requires `@antadesign/anta/elements` to be imported (client-side only).
50
+ *
51
+ * @example Dropdown from a button
52
+ * ```tsx
53
+ * <a-button>Actions</a-button>
54
+ * <Menu>
55
+ * <MenuItem icon="edit" label="Edit" kbd="⌘E" onSelect={onEdit} />
56
+ * <MenuSeparator />
57
+ * <MenuItem tone="critical" icon="trash" label="Delete" onSelect={onDelete} />
58
+ * </Menu>
59
+ * ```
60
+ */
61
+ export declare const Menu: ({ placement, context, coord, submenu, hover, offset, state, className, children, ...rest }: MenuProps) => any;
@@ -0,0 +1,34 @@
1
+ import { jsx } from "@antadesign/anta/jsx-runtime";
2
+ const Menu = ({
3
+ placement,
4
+ context,
5
+ coord,
6
+ submenu,
7
+ hover,
8
+ offset,
9
+ state,
10
+ className,
11
+ children,
12
+ ...rest
13
+ }) => {
14
+ return /* @__PURE__ */ jsx(
15
+ "a-menu",
16
+ {
17
+ placement: placement && placement !== "bottom-start" ? placement : void 0,
18
+ context: context ? "" : void 0,
19
+ coord: coord ? "" : void 0,
20
+ submenu: submenu ? "" : void 0,
21
+ hover: hover ? "" : void 0,
22
+ offset: offset != null ? String(offset) : void 0,
23
+ state,
24
+ role: "menu",
25
+ "aria-orientation": "vertical",
26
+ class: className,
27
+ ...rest,
28
+ children
29
+ }
30
+ );
31
+ };
32
+ export {
33
+ Menu
34
+ };
@@ -0,0 +1,24 @@
1
+ import type { BaseProps } from '../general_types';
2
+ export interface MenuGroupProps extends BaseProps {
3
+ /** The section heading shown above the grouped items (also the group's
4
+ * accessible name). */
5
+ label?: string;
6
+ /** The grouped `MenuItem`s. */
7
+ children?: React.ReactNode;
8
+ }
9
+ /**
10
+ * MenuGroup — a titled section that organises related `MenuItem`s. Keyboard
11
+ * navigation flattens items across groups, skipping the heading.
12
+ *
13
+ * Add `data-menu-open` to keep the menu open after any item in the group is
14
+ * chosen (it forwards to the element).
15
+ *
16
+ * @example
17
+ * ```tsx
18
+ * <MenuGroup label="Edit">
19
+ * <MenuItem icon="copy" label="Copy" />
20
+ * <MenuItem icon="cut" label="Cut" />
21
+ * </MenuGroup>
22
+ * ```
23
+ */
24
+ export declare const MenuGroup: ({ label, className, children, ...rest }: MenuGroupProps) => any;
@@ -0,0 +1,19 @@
1
+ import { jsx, jsxs } from "@antadesign/anta/jsx-runtime";
2
+ const MenuGroup = ({ label, className, children, ...rest }) => {
3
+ return /* @__PURE__ */ jsxs(
4
+ "a-menu-group",
5
+ {
6
+ role: "group",
7
+ "aria-label": label,
8
+ class: className,
9
+ ...rest,
10
+ children: [
11
+ label != null && /* @__PURE__ */ jsx("a-menu-group-label", { "aria-hidden": "true", children: label }),
12
+ children
13
+ ]
14
+ }
15
+ );
16
+ };
17
+ export {
18
+ MenuGroup
19
+ };
@@ -0,0 +1,49 @@
1
+ import type { BaseProps } from '../general_types';
2
+ import type { IconShape } from '../elements/a-icon.shapes';
3
+ export interface MenuItemProps extends BaseProps {
4
+ /** Leading icon shape. */
5
+ icon?: IconShape;
6
+ /** The item's text. Omit and pass `children` for richer content. */
7
+ label?: string;
8
+ /** A trailing keyboard-shortcut hint, e.g. `"⌘E"`. */
9
+ kbd?: string;
10
+ /** A trailing icon (ignored when `submenu` is set — the chevron takes its
11
+ * place). */
12
+ iconTrailing?: IconShape;
13
+ /** Disable the item: greyed out, not focusable for activation, no close. */
14
+ disabled?: boolean;
15
+ /** Semantic tone — colors the label, icon, and hover tint. `critical` is the
16
+ * destructive action; `neutral` (the default) is the standard gray.
17
+ * @defaultValue neutral */
18
+ tone?: 'neutral' | 'brand' | 'info' | 'success' | 'warning' | 'critical';
19
+ /** Marks this item as a submenu parent: adds the trailing chevron and
20
+ * `aria-haspopup`. Nest the flyout as a `<Menu submenu>` child. */
21
+ submenu?: boolean;
22
+ /** Convenience activation handler — fires on click / Enter / Space unless
23
+ * the item is disabled. (Mapped to the underlying click.) */
24
+ onSelect?: (e: any) => void;
25
+ /** Item content. With `label` set, children are extra content — most
26
+ * notably the nested `<Menu submenu>` for a submenu parent. */
27
+ children?: React.ReactNode;
28
+ }
29
+ /**
30
+ * MenuItem — a single selectable row inside a `Menu`. Composes a leading
31
+ * `icon`, a `label` (or `children`), an optional trailing `kbd` hint, and an
32
+ * optional trailing icon. For a submenu, set `submenu` and nest a
33
+ * `<Menu submenu>` as a child — a chevron is added automatically.
34
+ *
35
+ * Selecting an item closes the menu; add `data-menu-open` to keep it open
36
+ * (toggles / multi-select) — it forwards to the element.
37
+ *
38
+ * @example
39
+ * ```tsx
40
+ * <MenuItem icon="copy" label="Duplicate" kbd="⌘D" onSelect={dup} />
41
+ * <MenuItem label="Word wrap" data-menu-open onSelect={toggleWrap} />
42
+ * <MenuItem label="Share" submenu>
43
+ * <Menu submenu hover>
44
+ * <MenuItem label="Copy link" onSelect={copyLink} />
45
+ * </Menu>
46
+ * </MenuItem>
47
+ * ```
48
+ */
49
+ export declare const MenuItem: ({ icon, label, kbd, iconTrailing, disabled, tone, submenu, onSelect, className, children, ...rest }: MenuItemProps) => any;
@@ -0,0 +1,40 @@
1
+ import { jsx, jsxs } from "@antadesign/anta/jsx-runtime";
2
+ const MenuItem = ({
3
+ icon,
4
+ label,
5
+ kbd,
6
+ iconTrailing,
7
+ disabled,
8
+ tone,
9
+ submenu,
10
+ onSelect,
11
+ className,
12
+ children,
13
+ ...rest
14
+ }) => {
15
+ return /* @__PURE__ */ jsxs(
16
+ "a-menu-item",
17
+ {
18
+ role: "menuitem",
19
+ tabIndex: 0,
20
+ disabled: disabled ? "" : void 0,
21
+ tone: tone && tone !== "neutral" ? tone : void 0,
22
+ submenu: submenu ? "" : void 0,
23
+ "aria-haspopup": submenu ? "menu" : void 0,
24
+ "aria-disabled": disabled ? "true" : void 0,
25
+ onClick: disabled ? void 0 : onSelect,
26
+ class: className,
27
+ ...rest,
28
+ children: [
29
+ icon && /* @__PURE__ */ jsx("a-icon", { shape: icon, "aria-hidden": "true" }),
30
+ label != null && /* @__PURE__ */ jsx("a-menu-item-label", { children: label }),
31
+ kbd && /* @__PURE__ */ jsx("kbd", { children: kbd }),
32
+ submenu ? /* @__PURE__ */ jsx("a-icon", { shape: "chevron-right", "aria-hidden": "true" }) : iconTrailing && /* @__PURE__ */ jsx("a-icon", { shape: iconTrailing, "aria-hidden": "true" }),
33
+ children
34
+ ]
35
+ }
36
+ );
37
+ };
38
+ export {
39
+ MenuItem
40
+ };
@@ -0,0 +1,14 @@
1
+ import type { BaseProps } from '../general_types';
2
+ export interface MenuSeparatorProps extends BaseProps {
3
+ }
4
+ /**
5
+ * MenuSeparator — a thin divider between groups of `MenuItem`s.
6
+ *
7
+ * @example
8
+ * ```tsx
9
+ * <MenuItem label="Edit" />
10
+ * <MenuSeparator />
11
+ * <MenuItem tone="critical" label="Delete" />
12
+ * ```
13
+ */
14
+ export declare const MenuSeparator: ({ className, ...rest }: MenuSeparatorProps) => any;
@@ -0,0 +1,7 @@
1
+ import { jsx } from "@antadesign/anta/jsx-runtime";
2
+ const MenuSeparator = ({ className, ...rest }) => {
3
+ return /* @__PURE__ */ jsx("a-menu-separator", { role: "separator", class: className, ...rest });
4
+ };
5
+ export {
6
+ MenuSeparator
7
+ };
@@ -0,0 +1,55 @@
1
+ import type { BaseProps } from "../general_types";
2
+ import type { IconShape } from '../elements/a-icon.shapes';
3
+ export interface TagProps extends BaseProps {
4
+ /** A short "key" shown before the value. When paired with `value` it
5
+ * renders bold (weight 600), same color. On its own (no `value`) it's
6
+ * treated as the tag's primary text and keeps the default styling. */
7
+ label?: string;
8
+ /** The tag's primary text — a status, count, version, duration, etc.
9
+ * Rendered in the default color and weight, with no divider from the
10
+ * label; the color + weight contrast does the separating. */
11
+ value?: string;
12
+ /** Semantic tone, or any literal CSS color (`'#ff1493'`, `'rebeccapurple'`)
13
+ * for a one-off custom tone. Named tones map to the `--text-2-{tone}` /
14
+ * `--bg-4-{tone}` palette; a custom color keeps its hue while lightness
15
+ * and chroma are pinned. `'neutral'` (the default) is the gray tag —
16
+ * the same as omitting `tone`.
17
+ * @defaultValue neutral */
18
+ tone?: 'neutral' | 'brand' | 'info' | 'success' | 'warning' | 'critical' | (string & {});
19
+ /** Size variant. `small` = 16px tall, `medium` = 20px, `large` = 24px
20
+ * (matching `Button`). Omit the attribute or pass `'medium'` for the
21
+ * default — both render identically and emit no DOM attribute.
22
+ * @defaultValue medium */
23
+ size?: 'small' | 'medium' | 'large';
24
+ /** Render in normal (mixed) case instead of the default uppercase
25
+ * (keeps Anta's small body-text letter-spacing; uppercase tracks wider). */
26
+ nocaps?: boolean;
27
+ /** Leading icon shape. Sits flush before the label, scaled to the pill. */
28
+ icon?: IconShape;
29
+ /** Trailing icon shape. Renders last, after the value. */
30
+ iconTrailing?: IconShape;
31
+ }
32
+ /**
33
+ * Compact pill / chip for status, labels, and metadata.
34
+ *
35
+ * Renders an `<a-tag>` styled tag (no JS, no shadow DOM) — color and size
36
+ * come entirely from attributes. Content is composed from `icon`, `label`,
37
+ * `value`, and `iconTrailing` (like `<Button>`): `value` is the primary
38
+ * text (default styling) and `label`, when paired with a value, renders as
39
+ * a bold "key" before it (same color, no divider). Tabular figures are
40
+ * always on, so counts / versions / timers don't reflow. For an arbitrary
41
+ * multi-part tag, pass `children` instead — each segment after the first
42
+ * gets a hairline divider (the `label` + `value` pair is the no-divider
43
+ * exception).
44
+ *
45
+ * Requires `@antadesign/anta/elements` to be imported (client-side only)
46
+ * so the CSS ships with the page.
47
+ *
48
+ * @example Basic usage
49
+ * ```tsx
50
+ * <Tag tone="success" label="Running" />
51
+ * <Tag tone="info" icon="hourglass" label="Build" value="2m 14s" />
52
+ * <Tag tone="brand" size="small" nocaps value="v2.1.0" />
53
+ * ```
54
+ */
55
+ export declare const Tag: ({ icon, iconTrailing, label, value, tone, size, nocaps, className, style, children, ...rest }: TagProps) => any;
@@ -0,0 +1,40 @@
1
+ import { jsx, jsxs } from "@antadesign/anta/jsx-runtime";
2
+ const NAMED_TONES = /* @__PURE__ */ new Set(["neutral", "brand", "info", "success", "warning", "critical"]);
3
+ const Tag = ({
4
+ icon,
5
+ iconTrailing,
6
+ label,
7
+ value,
8
+ tone,
9
+ size,
10
+ nocaps,
11
+ className,
12
+ style,
13
+ children,
14
+ ...rest
15
+ }) => {
16
+ const isCustomTone = tone != null && !NAMED_TONES.has(tone);
17
+ const computedStyle = isCustomTone ? { ...style, ["--tag-tone-source"]: tone } : style;
18
+ const hasValue = value != null;
19
+ return /* @__PURE__ */ jsxs(
20
+ "a-tag",
21
+ {
22
+ tone,
23
+ size: size && size !== "medium" ? size : void 0,
24
+ nocaps: nocaps ? "" : void 0,
25
+ class: className,
26
+ style: computedStyle,
27
+ ...rest,
28
+ children: [
29
+ icon && /* @__PURE__ */ jsx("a-icon", { shape: icon, "aria-hidden": "true" }),
30
+ label != null && (hasValue ? /* @__PURE__ */ jsx("a-tag-label", { children: label }) : /* @__PURE__ */ jsx("a-tag-value", { children: label })),
31
+ hasValue && /* @__PURE__ */ jsx("a-tag-value", { children: value }),
32
+ children,
33
+ iconTrailing && /* @__PURE__ */ jsx("a-icon", { shape: iconTrailing, "aria-hidden": "true" })
34
+ ]
35
+ }
36
+ );
37
+ };
38
+ export {
39
+ Tag
40
+ };
@@ -1,7 +1,9 @@
1
1
  import type { BaseProps } from "../general_types";
2
2
  export interface TextProps extends BaseProps {
3
- /** Visual priority. Maps to text-1..text-5 (`primary` = text-1).
4
- * @defaultValue primary */
3
+ /** Visual priority. Maps to text-1..text-5 (`primary` = text-1, the
4
+ * strongest). The default is `secondary` (text-2) — body text reads a
5
+ * step softer than the strongest foreground; pass `primary` for emphasis.
6
+ * @defaultValue secondary */
5
7
  priority?: 'primary' | 'secondary' | 'tertiary' | 'quaternary' | 'quinary';
6
8
  /** Color tint. Applies the matching `--text-{N}-{tone}` palette. */
7
9
  tone?: 'brand' | 'success' | 'critical' | 'warning' | 'info';
@@ -25,8 +25,10 @@ export interface TooltipProps extends BaseProps {
25
25
  * doesn't affect that element's layout.
26
26
  *
27
27
  * Shows on hover (after `delay`) and on keyboard focus; dismisses on mouse
28
- * leave, blur, Escape, or when the anchor scrolls away. Follows the cursor
29
- * by default pass `static` to pin it under the anchor instead.
28
+ * leave, blur, Escape, or when the anchor scrolls away. On touch devices it
29
+ * opens on press-and-hold (a tap never surfaces it) and lingers briefly after
30
+ * release. Follows the cursor by default — pass `static` to pin it under the
31
+ * anchor instead.
30
32
  *
31
33
  * Requires `@antadesign/anta/elements` to be imported (client-side only)
32
34
  * to register the underlying custom element.
@@ -36,6 +36,11 @@
36
36
  --button-bg-secondary-active: #44374b26;
37
37
  --button-fg-secondary-rest: #534c57;
38
38
  --button-fg-secondary-hover: #49424c;
39
+ /* Darken the rest-state secondary label by this much oklch lightness so
40
+ it reads a touch stronger. Applied dynamically at the --button-fg
41
+ wiring (below), so it covers every tone — named and custom alike.
42
+ Light mode only; the .dark block zeroes it. */
43
+ --button-fg-secondary-l-shift: 0.05;
39
44
 
40
45
  --button-fg-tertiary-rest: #635b65;
41
46
  --button-fg-tertiary-hover: #534c57;
@@ -192,6 +197,8 @@
192
197
  --button-bg-secondary-active: #e4d1ef2e;
193
198
  --button-fg-secondary-rest: #c1b9c1;
194
199
  --button-fg-secondary-hover: #d4ced4;
200
+ /* Dark-mode secondary labels are already tuned — no rest darkening. */
201
+ --button-fg-secondary-l-shift: 0;
195
202
 
196
203
  --button-fg-tertiary-rest: #afa9b1;
197
204
  --button-fg-tertiary-hover: #afa9b1;
@@ -323,6 +330,10 @@
323
330
  background-color: var(--button-bg);
324
331
  border-radius: 4px;
325
332
  text-decoration: none;
333
+ /* Secondary is the default priority — a 1px hairline in the current
334
+ fg tone (at 50% alpha) gives the chip a subtle edge. Primary,
335
+ tertiary, and quaternary cancel it in their own blocks below. */
336
+ box-shadow: 0 0 1px color-mix(in oklch, currentColor, transparent 50%);
326
337
 
327
338
  font-size: 15px;
328
339
  font-family: var(--sans-serif);
@@ -413,11 +424,6 @@
413
424
  outline-offset: 1px;
414
425
  }
415
426
 
416
- /* Selected gets a 0.5px inset ring in the current fg color. */
417
- &[selected] {
418
- box-shadow: inset 0 0 0 0.5px currentColor;
419
- }
420
-
421
427
  /* Quaternary: instant in every direction — hover-in, press, and
422
428
  return to rest all snap with no transition. */
423
429
  &[priority="quaternary"] {
@@ -559,6 +565,7 @@
559
565
  on Chrome 133+ / Safari 18.2+. (oklch relative color: Chrome 119+,
560
566
  Safari 16.4+, Firefox 128+.) */
561
567
  &[tone]:not(
568
+ [tone=""],
562
569
  [tone="brand"],
563
570
  [tone="neutral"],
564
571
  [tone="critical"],
@@ -609,6 +616,7 @@
609
616
  /* Custom tone, dark mode — same formulas, re-tuned knobs: lighter fg
610
617
  and heavier tint alphas to read against a dark page. */
611
618
  .dark &[tone]:not(
619
+ [tone=""],
612
620
  [tone="brand"],
613
621
  [tone="neutral"],
614
622
  [tone="critical"],
@@ -636,7 +644,7 @@
636
644
  tertiary, and quaternary match an explicit `[priority="…"]` attr
637
645
  and win on specificity (primary's constant fg beats the unscoped
638
646
  :hover on source order). */
639
- --button-fg: var(--button-fg-secondary-rest);
647
+ --button-fg: oklch(from var(--button-fg-secondary-rest) calc(l - var(--button-fg-secondary-l-shift)) c h);
640
648
  --button-bg: var(--button-bg-secondary-rest);
641
649
  /* Hover styling is gated to real-pointer devices so it doesn't stick
642
650
  after a tap on touch screens (where :hover lingers until the next
@@ -656,6 +664,8 @@
656
664
  &[priority="primary"] {
657
665
  --button-fg: var(--button-fg-primary-rest);
658
666
  --button-bg: var(--button-bg-primary-rest);
667
+ /* Solid fill carries its own edge — drop the secondary hairline. */
668
+ box-shadow: none;
659
669
  @media (hover: hover) and (pointer: fine) {
660
670
  &:hover {
661
671
  --button-bg: var(--button-bg-primary-hover);
@@ -669,6 +679,8 @@
669
679
  &[priority="tertiary"] {
670
680
  --button-fg: var(--button-fg-tertiary-rest);
671
681
  --button-bg: transparent;
682
+ /* Background-less — no hairline. */
683
+ box-shadow: none;
672
684
  @media (hover: hover) and (pointer: fine) {
673
685
  &:hover {
674
686
  --button-fg: var(--button-fg-tertiary-hover);
@@ -682,11 +694,14 @@
682
694
  }
683
695
  }
684
696
  &[priority="quaternary"] {
685
- /* Rest fg is the quaternary tone at 82% alpha — slightly faded, so a
697
+ /* Rest fg is the quaternary tone at 90% alpha — slightly faded, so a
686
698
  quaternary button reads as quieter than a (full-opacity) tertiary
687
699
  one. Hover / active restore full opacity. */
688
- --button-fg: color-mix(in oklch, var(--button-fg-quaternary-rest) 82%, transparent);
700
+ --button-fg: color-mix(in oklch, var(--button-fg-quaternary-rest) 90%, transparent);
689
701
  --button-bg: transparent;
702
+ /* Background-less — no hairline. */
703
+ box-shadow: none;
704
+ font-weight: 415;
690
705
  @media (hover: hover) and (pointer: fine) {
691
706
  &:hover {
692
707
  --button-fg: var(--button-fg-quaternary-hover);
@@ -707,6 +722,14 @@
707
722
  }
708
723
  }
709
724
 
725
+ /* Selected gets a 1px inset ring in the current fg color. Declared
726
+ after the priority blocks so it overrides their `box-shadow: none`
727
+ cancels — every selected button keeps its ring regardless of
728
+ priority. */
729
+ &[selected] {
730
+ box-shadow: inset 0 0 0 1px currentColor;
731
+ }
732
+
710
733
  /* Set bg/color directly (not the vars) so inline-style
711
734
  `--button-bg` overrides can't keep a disabled button alive.
712
735
  Secondary disabled is the default; other priorities override below. */
@@ -330,6 +330,10 @@
330
330
  --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M9 3H5a2 2 0 0 0-2 2v4m6-6h10a2 2 0 0 1 2 2v4M9 3v18m0 0h10a2 2 0 0 0 2-2V9M9 21H5a2 2 0 0 1-2-2V9m0 0h18'/%3E%3C/svg%3E%0A");
331
331
  }
332
332
 
333
+ a-icon[shape="tag"] {
334
+ --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12.586 2.586A2 2 0 0 0 11.172 2H4a2 2 0 0 0-2 2v7.172a2 2 0 0 0 .586 1.414l8.704 8.704a2.426 2.426 0 0 0 3.42 0l6.58-6.58a2.426 2.426 0 0 0 0-3.42z'/%3E%3Ccircle cx='7.5' cy='7.5' r='.5' fill='currentColor'/%3E%3C/svg%3E%0A");
335
+ }
336
+
333
337
  a-icon[shape="text-highlight"] {
334
338
  --icon: url("data:image/svg+xml,%3C%3Fxml version='1.0' encoding='utf-8'%3F%3E%0A%3C!-- Generator: Adobe Illustrator 18.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --%3E%0A%3Csvg version='1.1' id='Layer_1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px'%0A viewBox='0 0 16 16' enable-background='new 0 0 16 16' xml:space='preserve'%3E%0A%3Cg id='text_highlight_1_'%3E%0A %3Cg%3E%0A %3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M9,10H2V6h7V4H1C0.45,4,0,4.45,0,5v6c0,0.55,0.45,1,1,1h8V10z M13,13h-1V3h1%0A c0.55,0,1-0.45,1-1c0-0.55-0.45-1-1-1h-1c-0.37,0-0.7,0.11-1,0.28C10.7,1.11,10.37,1,10,1H9C8.45,1,8,1.45,8,2c0,0.55,0.45,1,1,1%0A h1v10H9c-0.55,0-1,0.45-1,1c0,0.55,0.45,1,1,1h1c0.37,0,0.7-0.11,1-0.28c0.3,0.17,0.63,0.28,1,0.28h1c0.55,0,1-0.45,1-1%0A C14,13.45,13.55,13,13,13z M15,4h-2v2h1v4h-1v2h2c0.55,0,1-0.45,1-1V5C16,4.45,15.55,4,15,4z'/%3E%0A %3C/g%3E%0A%3C/g%3E%0A%3C/svg%3E%0A");
335
339
  }
@@ -1,5 +1,5 @@
1
1
  import type { IconShapes } from '@antadesign/anta';
2
- export declare const ICON_SHAPES: readonly ["arrow-left-to-line", "arrow-left", "arrow-narrow-down", "arrow-narrow-up-down", "arrow-narrow-up", "arrow-right", "arrow-top-right", "asterisk", "book-open", "braces", "bug", "calendar", "case-sensitive", "chat", "check", "chevron-down", "chevron-left", "chevron-right", "chevron-up", "chevrons-right", "circle-check", "circle-large", "circle", "click", "clock", "cloud-upload", "copy", "corner-down-right", "cube", "dots-vertical", "download", "edit", "education-disk", "external-link", "file-down", "file", "filter", "folder-close", "folder-open", "folder-tree", "github-logo", "gitlab-logo", "hat-glasses", "heart-handshake", "help-disk", "history-tree", "history", "home", "hourglass", "info", "jira-logo", "linear-logo", "link", "list-detail-view", "maximize", "megaphone", "menu", "minimize", "minus", "moon", "more", "move-horizontal", "not-equal", "play", "plus", "pointer", "presentation", "refresh-ccw-dot", "refresh", "regex", "repeat", "rotate-ccw", "rss", "runs-history", "scroll-text", "search-check", "search", "send", "sparkles", "sun", "swatch-book", "table-2", "text-highlight", "text-initial", "timer", "trash", "trello-logo", "view", "warning-triangle", "webhook", "workflow", "x"];
2
+ export declare const ICON_SHAPES: readonly ["arrow-left-to-line", "arrow-left", "arrow-narrow-down", "arrow-narrow-up-down", "arrow-narrow-up", "arrow-right", "arrow-top-right", "asterisk", "book-open", "braces", "bug", "calendar", "case-sensitive", "chat", "check", "chevron-down", "chevron-left", "chevron-right", "chevron-up", "chevrons-right", "circle-check", "circle-large", "circle", "click", "clock", "cloud-upload", "copy", "corner-down-right", "cube", "dots-vertical", "download", "edit", "education-disk", "external-link", "file-down", "file", "filter", "folder-close", "folder-open", "folder-tree", "github-logo", "gitlab-logo", "hat-glasses", "heart-handshake", "help-disk", "history-tree", "history", "home", "hourglass", "info", "jira-logo", "linear-logo", "link", "list-detail-view", "maximize", "megaphone", "menu", "minimize", "minus", "moon", "more", "move-horizontal", "not-equal", "play", "plus", "pointer", "presentation", "refresh-ccw-dot", "refresh", "regex", "repeat", "rotate-ccw", "rss", "runs-history", "scroll-text", "search-check", "search", "send", "sparkles", "sun", "swatch-book", "table-2", "tag", "text-highlight", "text-initial", "timer", "trash", "trello-logo", "view", "warning-triangle", "webhook", "workflow", "x"];
3
3
  export declare const ICON_SYNONYMS: Readonly<Record<string, readonly string[]>>;
4
4
  declare module '@antadesign/anta' {
5
5
  interface IconShapes {
@@ -85,6 +85,7 @@ declare module '@antadesign/anta' {
85
85
  'sun': true;
86
86
  'swatch-book': true;
87
87
  'table-2': true;
88
+ 'tag': true;
88
89
  'text-highlight': true;
89
90
  'text-initial': true;
90
91
  'timer': true;
@@ -81,6 +81,7 @@ const ICON_SHAPES = [
81
81
  "sun",
82
82
  "swatch-book",
83
83
  "table-2",
84
+ "tag",
84
85
  "text-highlight",
85
86
  "text-initial",
86
87
  "timer",
@@ -178,7 +179,8 @@ const ICON_SYNONYMS = {
178
179
  "download": ["save", "import"],
179
180
  "cloud-upload": ["save", "sync", "upload", "send", "export"],
180
181
  "link": ["url", "href", "anchor"],
181
- "more": ["options", "extra"]
182
+ "more": ["options", "extra"],
183
+ "tag": ["label", "badge", "chip"]
182
184
  };
183
185
  export {
184
186
  ICON_SHAPES,
@@ -0,0 +1,21 @@
1
+ @layer anta {
2
+ a-menu-group:not(:defined) {
3
+ display: none;
4
+ }
5
+
6
+ a-menu-group {
7
+ display: block;
8
+ }
9
+
10
+ /* Non-focusable section heading. */
11
+ a-menu-group-label {
12
+ display: block;
13
+ padding: 6px 8px 2px;
14
+ color: var(--text-5);
15
+ font-size: 0.75em;
16
+ font-weight: 600;
17
+ letter-spacing: 0.06em;
18
+ text-transform: uppercase;
19
+ user-select: none;
20
+ }
21
+ }
@@ -0,0 +1,13 @@
1
+ import { HTMLElementBase } from '../anta_helpers';
2
+ import './a-menu-group.css';
3
+ /**
4
+ * `<a-menu-group>` — a titled section grouping related menu items.
5
+ * No JS / no shadow DOM; styled by `a-menu-group.css`. The group's heading
6
+ * is a non-focusable `<a-menu-group-label>` child rendered by the
7
+ * `MenuGroup` JSX wrapper; `role="group"` + `aria-label` are added there too.
8
+ * Keyboard navigation in `<a-menu>` flattens items across group boundaries,
9
+ * skipping the heading.
10
+ */
11
+ export declare class AMenuGroupElement extends HTMLElementBase {
12
+ }
13
+ export declare function register_a_menu_group(): void;
@@ -0,0 +1,15 @@
1
+ import { HTMLElementBase } from "../anta_helpers";
2
+ import "./a-menu-group.css";
3
+ class AMenuGroupElement extends HTMLElementBase {
4
+ }
5
+ function register_a_menu_group() {
6
+ if (typeof customElements === "undefined") return;
7
+ if (!customElements.get("a-menu-group")) {
8
+ customElements.define("a-menu-group", AMenuGroupElement);
9
+ }
10
+ }
11
+ register_a_menu_group();
12
+ export {
13
+ AMenuGroupElement,
14
+ register_a_menu_group
15
+ };