@aortl/admin-react 0.12.0 → 0.13.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.
@@ -12,5 +12,5 @@ export interface AdminRootProps extends ComponentProps<"div"> {
12
12
  */
13
13
  systemAccent?: string;
14
14
  }
15
- export declare function AdminRoot({ className, theme, systemAccent, style, ...rest }: AdminRootProps): import("react/jsx-runtime").JSX.Element;
15
+ export declare function AdminRoot({ className, theme, systemAccent, style, ref, ...rest }: AdminRootProps): import("react/jsx-runtime").JSX.Element;
16
16
  //# sourceMappingURL=AdminRoot.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"AdminRoot.d.ts","sourceRoot":"","sources":["../src/AdminRoot.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAiB,cAAc,EAAE,MAAM,OAAO,CAAC;AAG3D,MAAM,WAAW,cAAe,SAAQ,cAAc,CAAC,KAAK,CAAC;IAC3D;;;OAGG;IACH,KAAK,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IACzB;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,wBAAgB,SAAS,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,GAAG,IAAI,EAAE,EAAE,cAAc,2CAc3F"}
1
+ {"version":3,"file":"AdminRoot.d.ts","sourceRoot":"","sources":["../src/AdminRoot.tsx"],"names":[],"mappings":"AAAA,OAAO,EAA2C,KAAK,cAAc,EAAE,MAAM,OAAO,CAAC;AAIrF,MAAM,WAAW,cAAe,SAAQ,cAAc,CAAC,KAAK,CAAC;IAC3D;;;OAGG;IACH,KAAK,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IACzB;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,wBAAgB,SAAS,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,IAAI,EAAE,EAAE,cAAc,2CAgChG"}
package/dist/Button.d.ts CHANGED
@@ -15,13 +15,14 @@ export interface ButtonProps extends ComponentProps<typeof BaseButton> {
15
15
  /** Trailing icon. Pass a component (`iconTrailing={IconArrowRight}`) or an element. */
16
16
  iconTrailing?: IconProp;
17
17
  /**
18
- * Keyboard shortcut bound to this button. Pressing the chord invokes the
19
- * button's `onClick` handler not a real DOM click, so `type="submit"`
20
- * form submission and other native side effects only happen if `onClick`
21
- * triggers them itself. Same syntax as `useHotkey`. Pass an array for
22
- * alternatives — only the first is rendered as a visual chip.
18
+ * Keyboard shortcut bound to this button. Pressing the chord dispatches a
19
+ * native click on the underlying element, so `onClick` fires, `type="submit"`
20
+ * submits the form, and an anchor-rendered button (`render={<a href>}`)
21
+ * navigates all the native side effects of a real click. Same syntax as
22
+ * `useHotkey`. Pass an array for alternatives — only the first is rendered as
23
+ * a visual chip.
23
24
  */
24
25
  hotkey?: string | readonly string[];
25
26
  }
26
- export declare function Button({ variant, size, fullWidth, loading, icon, iconTrailing, hotkey, className, type, disabled, children, onClick, ...rest }: ButtonProps): import("react/jsx-runtime").JSX.Element;
27
+ export declare function Button({ variant, size, fullWidth, loading, icon, iconTrailing, hotkey, className, type, disabled, children, onClick, ref, ...rest }: ButtonProps): import("react/jsx-runtime").JSX.Element;
27
28
  //# sourceMappingURL=Button.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Button.d.ts","sourceRoot":"","sources":["../src/Button.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,OAAO,CAAC;AAE5C,OAAO,EAAc,KAAK,QAAQ,EAAE,MAAM,QAAQ,CAAC;AAInD,MAAM,MAAM,aAAa,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,GAAG,QAAQ,CAAC;AACvE,MAAM,MAAM,UAAU,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AAE5C,MAAM,WAAW,WAAY,SAAQ,cAAc,CAAC,OAAO,UAAU,CAAC;IACpE,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;uEACmE;IACnE,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,wEAAwE;IACxE,IAAI,CAAC,EAAE,QAAQ,CAAC;IAChB,uFAAuF;IACvF,YAAY,CAAC,EAAE,QAAQ,CAAC;IACxB;;;;;;OAMG;IACH,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAAC;CACrC;AAED,wBAAgB,MAAM,CAAC,EACrB,OAAmB,EACnB,IAAW,EACX,SAAS,EACT,OAAO,EACP,IAAI,EACJ,YAAY,EACZ,MAAM,EACN,SAAS,EACT,IAAe,EACf,QAAQ,EACR,QAAQ,EACR,OAAO,EACP,GAAG,IAAI,EACR,EAAE,WAAW,2CAoCb"}
1
+ {"version":3,"file":"Button.d.ts","sourceRoot":"","sources":["../src/Button.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,EAAuB,KAAK,cAAc,EAAE,MAAM,OAAO,CAAC;AAEjE,OAAO,EAAc,KAAK,QAAQ,EAAE,MAAM,QAAQ,CAAC;AAInD,MAAM,MAAM,aAAa,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,GAAG,QAAQ,CAAC;AACvE,MAAM,MAAM,UAAU,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AAE5C,MAAM,WAAW,WAAY,SAAQ,cAAc,CAAC,OAAO,UAAU,CAAC;IACpE,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;uEACmE;IACnE,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,wEAAwE;IACxE,IAAI,CAAC,EAAE,QAAQ,CAAC;IAChB,uFAAuF;IACvF,YAAY,CAAC,EAAE,QAAQ,CAAC;IACxB;;;;;;;OAOG;IACH,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAAC;CACrC;AAED,wBAAgB,MAAM,CAAC,EACrB,OAAmB,EACnB,IAAW,EACX,SAAS,EACT,OAAO,EACP,IAAI,EACJ,YAAY,EACZ,MAAM,EACN,SAAS,EACT,IAAe,EACf,QAAQ,EACR,QAAQ,EACR,OAAO,EACP,GAAG,EACH,GAAG,IAAI,EACR,EAAE,WAAW,2CA+Cb"}
@@ -2,6 +2,12 @@ import { ComponentProps } from 'react';
2
2
  export type ButtonGroupOrientation = "horizontal" | "vertical";
3
3
  export interface ButtonGroupProps extends ComponentProps<"div"> {
4
4
  orientation?: ButtonGroupOrientation;
5
+ /**
6
+ * Stretch the group across its container. Horizontal groups split the row
7
+ * evenly so every button is the same width; vertical groups fill the
8
+ * container width.
9
+ */
10
+ fullWidth?: boolean;
5
11
  }
6
- export declare function ButtonGroup({ orientation, role, className, ...rest }: ButtonGroupProps): import("react/jsx-runtime").JSX.Element;
12
+ export declare function ButtonGroup({ orientation, fullWidth, role, className, ...rest }: ButtonGroupProps): import("react/jsx-runtime").JSX.Element;
7
13
  //# sourceMappingURL=ButtonGroup.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ButtonGroup.d.ts","sourceRoot":"","sources":["../src/ButtonGroup.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,OAAO,CAAC;AAG5C,MAAM,MAAM,sBAAsB,GAAG,YAAY,GAAG,UAAU,CAAC;AAE/D,MAAM,WAAW,gBAAiB,SAAQ,cAAc,CAAC,KAAK,CAAC;IAC7D,WAAW,CAAC,EAAE,sBAAsB,CAAC;CACtC;AAED,wBAAgB,WAAW,CAAC,EAC1B,WAA0B,EAC1B,IAAc,EACd,SAAS,EACT,GAAG,IAAI,EACR,EAAE,gBAAgB,2CAQlB"}
1
+ {"version":3,"file":"ButtonGroup.d.ts","sourceRoot":"","sources":["../src/ButtonGroup.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,OAAO,CAAC;AAG5C,MAAM,MAAM,sBAAsB,GAAG,YAAY,GAAG,UAAU,CAAC;AAE/D,MAAM,WAAW,gBAAiB,SAAQ,cAAc,CAAC,KAAK,CAAC;IAC7D,WAAW,CAAC,EAAE,sBAAsB,CAAC;IACrC;;;;OAIG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,wBAAgB,WAAW,CAAC,EAC1B,WAA0B,EAC1B,SAAiB,EACjB,IAAc,EACd,SAAS,EACT,GAAG,IAAI,EACR,EAAE,gBAAgB,2CAelB"}
package/dist/Input.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { Input as BaseInput } from '@base-ui/react/input';
2
2
  import { ComponentProps } from 'react';
3
- export type InputVariant = "bordered" | "ghost" | "danger";
3
+ export type InputVariant = "bordered" | "ghost" | "danger" | "info" | "success" | "warning";
4
4
  export type InputSize = "sm" | "md" | "lg";
5
5
  type BaseInputProps = Omit<ComponentProps<typeof BaseInput>, "size">;
6
6
  export interface InputProps extends BaseInputProps {
@@ -1 +1 @@
1
- {"version":3,"file":"Input.d.ts","sourceRoot":"","sources":["../src/Input.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,IAAI,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,OAAO,CAAC;AAG5C,MAAM,MAAM,YAAY,GAAG,UAAU,GAAG,OAAO,GAAG,QAAQ,CAAC;AAC3D,MAAM,MAAM,SAAS,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AAE3C,KAAK,cAAc,GAAG,IAAI,CAAC,cAAc,CAAC,OAAO,SAAS,CAAC,EAAE,MAAM,CAAC,CAAC;AAErE,MAAM,WAAW,UAAW,SAAQ,cAAc;IAChD,OAAO,CAAC,EAAE,YAAY,CAAC;IACvB,SAAS,CAAC,EAAE,SAAS,CAAC;CACvB;AAED,wBAAgB,KAAK,CAAC,EACpB,OAAoB,EACpB,SAAgB,EAChB,SAAS,EACT,IAAa,EACb,GAAG,IAAI,EACR,EAAE,UAAU,2CAeZ"}
1
+ {"version":3,"file":"Input.d.ts","sourceRoot":"","sources":["../src/Input.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,IAAI,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,OAAO,CAAC;AAG5C,MAAM,MAAM,YAAY,GAAG,UAAU,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,GAAG,SAAS,GAAG,SAAS,CAAC;AAC5F,MAAM,MAAM,SAAS,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AAE3C,KAAK,cAAc,GAAG,IAAI,CAAC,cAAc,CAAC,OAAO,SAAS,CAAC,EAAE,MAAM,CAAC,CAAC;AAErE,MAAM,WAAW,UAAW,SAAQ,cAAc;IAChD,OAAO,CAAC,EAAE,YAAY,CAAC;IACvB,SAAS,CAAC,EAAE,SAAS,CAAC;CACvB;AAED,wBAAgB,KAAK,CAAC,EACpB,OAAoB,EACpB,SAAgB,EAChB,SAAS,EACT,IAAa,EACb,GAAG,IAAI,EACR,EAAE,UAAU,2CAeZ"}
package/dist/Link.d.ts ADDED
@@ -0,0 +1,21 @@
1
+ import { ComponentProps } from 'react';
2
+ import { IconProp } from './icon';
3
+ export interface LinkProps extends ComponentProps<"a"> {
4
+ /**
5
+ * Marks the link as leaving the app: renders a trailing ↗ affordance and
6
+ * defaults `target="_blank"` + `rel="noopener noreferrer"`. Explicit
7
+ * `target`/`rel` props win, so you can keep the icon while overriding either.
8
+ */
9
+ external?: boolean;
10
+ /** Leading icon. Pass a component (`icon={IconHome}`) or an element. */
11
+ icon?: IconProp;
12
+ /** Trailing icon. Independent of `external`'s ↗ affordance. */
13
+ iconTrailing?: IconProp;
14
+ }
15
+ /**
16
+ * A text link — a plain `<a>` with the design system's link styling: primary
17
+ * color, hover shift, underline, and a focus-visible ring. Pass `external` for
18
+ * the new-tab affordance.
19
+ */
20
+ export declare function Link({ external, icon, iconTrailing, className, target, rel, children, ...rest }: LinkProps): import("react/jsx-runtime").JSX.Element;
21
+ //# sourceMappingURL=Link.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Link.d.ts","sourceRoot":"","sources":["../src/Link.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,OAAO,CAAC;AAE5C,OAAO,EAAc,KAAK,QAAQ,EAAE,MAAM,QAAQ,CAAC;AAEnD,MAAM,WAAW,SAAU,SAAQ,cAAc,CAAC,GAAG,CAAC;IACpD;;;;OAIG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,wEAAwE;IACxE,IAAI,CAAC,EAAE,QAAQ,CAAC;IAChB,+DAA+D;IAC/D,YAAY,CAAC,EAAE,QAAQ,CAAC;CACzB;AAED;;;;GAIG;AACH,wBAAgB,IAAI,CAAC,EACnB,QAAQ,EACR,IAAI,EACJ,YAAY,EACZ,SAAS,EACT,MAAM,EACN,GAAG,EACH,QAAQ,EACR,GAAG,IAAI,EACR,EAAE,SAAS,2CAaX"}
@@ -1,9 +1,22 @@
1
1
  import { ComponentProps } from 'react';
2
- export type TextareaVariant = "bordered" | "ghost" | "danger";
2
+ export type TextareaVariant = "bordered" | "ghost" | "danger" | "info" | "success" | "warning";
3
3
  export type TextareaSize = "sm" | "md" | "lg";
4
4
  export interface TextareaProps extends Omit<ComponentProps<"textarea">, "size"> {
5
5
  variant?: TextareaVariant;
6
6
  textareaSize?: TextareaSize;
7
+ /**
8
+ * Height tracks content via CSS `field-sizing` (Chromium-only today; other
9
+ * browsers keep a fixed, resizable box). `rows`/min-height is the floor —
10
+ * set `max-height` via `className`/`style` for a ceiling.
11
+ */
12
+ autoResize?: boolean;
7
13
  }
8
- export declare function Textarea({ variant, textareaSize, className, ...rest }: TextareaProps): import("react/jsx-runtime").JSX.Element;
14
+ /**
15
+ * Multi-line text input. Rendered through Base UI's `Field.Control` with a
16
+ * `<textarea>` swapped in for the default `<input>`, so inside a `<Field>` it
17
+ * gets the same wiring as `<Input>`: a generated id, label `htmlFor`
18
+ * association, and validity-driven `:user-valid` / `<Field.Error>`. Works
19
+ * standalone too — `Field.Control` falls back to a default context.
20
+ */
21
+ export declare function Textarea({ variant, textareaSize, autoResize, className, ...rest }: TextareaProps): import("react/jsx-runtime").JSX.Element;
9
22
  //# sourceMappingURL=Textarea.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Textarea.d.ts","sourceRoot":"","sources":["../src/Textarea.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,OAAO,CAAC;AAG5C,MAAM,MAAM,eAAe,GAAG,UAAU,GAAG,OAAO,GAAG,QAAQ,CAAC;AAC9D,MAAM,MAAM,YAAY,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AAE9C,MAAM,WAAW,aAAc,SAAQ,IAAI,CAAC,cAAc,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7E,OAAO,CAAC,EAAE,eAAe,CAAC;IAC1B,YAAY,CAAC,EAAE,YAAY,CAAC;CAC7B;AAED,wBAAgB,QAAQ,CAAC,EACvB,OAAoB,EACpB,YAAmB,EACnB,SAAS,EACT,GAAG,IAAI,EACR,EAAE,aAAa,2CAcf"}
1
+ {"version":3,"file":"Textarea.d.ts","sourceRoot":"","sources":["../src/Textarea.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,OAAO,CAAC;AAG5C,MAAM,MAAM,eAAe,GAAG,UAAU,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,GAAG,SAAS,GAAG,SAAS,CAAC;AAC/F,MAAM,MAAM,YAAY,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AAE9C,MAAM,WAAW,aAAc,SAAQ,IAAI,CAAC,cAAc,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7E,OAAO,CAAC,EAAE,eAAe,CAAC;IAC1B,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B;;;;OAIG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED;;;;;;GAMG;AACH,wBAAgB,QAAQ,CAAC,EACvB,OAAoB,EACpB,YAAmB,EACnB,UAAU,EACV,SAAS,EACT,GAAG,IAAI,EACR,EAAE,aAAa,2CAmBf"}
@@ -1617,6 +1617,57 @@
1617
1617
  border-top-color: color-mix(in srgb, currentColor 25%, transparent);
1618
1618
  }
1619
1619
  }
1620
+ :scope._ao-btn-group-full-width:not(._ao-btn-group-vertical), :scope ._ao-btn-group-full-width:not(._ao-btn-group-vertical) {
1621
+ display: flex;
1622
+ width: 100%;
1623
+ }
1624
+ :scope._ao-btn-group-full-width:not(._ao-btn-group-vertical) > ._ao-btn, :scope ._ao-btn-group-full-width:not(._ao-btn-group-vertical) > ._ao-btn, :scope._ao-btn-group-full-width:not(._ao-btn-group-vertical) > ._ao-menu, :scope ._ao-btn-group-full-width:not(._ao-btn-group-vertical) > ._ao-menu {
1625
+ flex: 1;
1626
+ }
1627
+ :scope._ao-btn-group-full-width._ao-btn-group-vertical, :scope ._ao-btn-group-full-width._ao-btn-group-vertical {
1628
+ width: 100%;
1629
+ }
1630
+ :scope._ao-link, :scope ._ao-link {
1631
+ display: inline-flex;
1632
+ align-items: center;
1633
+ gap: calc(var(--spacing) * 1);
1634
+ border-radius: var(--radius-sm);
1635
+ color: var(--color-primary);
1636
+ text-decoration-line: underline;
1637
+ text-underline-offset: 2px;
1638
+ transition-property: color, background-color, border-color, outline-color, text-decoration-color, fill, stroke, --tw-gradient-from, --tw-gradient-via, --tw-gradient-to;
1639
+ transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));
1640
+ transition-duration: var(--tw-duration, var(--default-transition-duration));
1641
+ --tw-duration: 150ms;
1642
+ transition-duration: 150ms;
1643
+ &:hover {
1644
+ @media (hover: hover) {
1645
+ color: var(--color-primary-hover);
1646
+ }
1647
+ }
1648
+ &:focus-visible {
1649
+ outline-style: var(--tw-outline-style);
1650
+ outline-width: 2px;
1651
+ }
1652
+ &:focus-visible {
1653
+ outline-offset: 2px;
1654
+ }
1655
+ &:focus-visible {
1656
+ outline-color: var(--color-primary);
1657
+ }
1658
+ }
1659
+ :scope._ao-link-external, :scope ._ao-link-external {
1660
+ --link-external-arrow: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M17 7 7 17'/%3E%3Cpath d='M8 7h9v9'/%3E%3C/svg%3E");
1661
+ }
1662
+ :scope._ao-link-external::after, :scope ._ao-link-external::after {
1663
+ content: "";
1664
+ flex: none;
1665
+ width: 0.85em;
1666
+ height: 0.85em;
1667
+ background-color: currentColor;
1668
+ -webkit-mask: var(--link-external-arrow) center / contain no-repeat;
1669
+ mask: var(--link-external-arrow) center / contain no-repeat;
1670
+ }
1620
1671
  :scope._ao-input, :scope ._ao-input {
1621
1672
  display: inline-flex;
1622
1673
  width: 100%;
@@ -1688,6 +1739,39 @@
1688
1739
  outline-color: var(--color-danger);
1689
1740
  }
1690
1741
  }
1742
+ :scope._ao-input-info, :scope ._ao-input-info {
1743
+ border-color: var(--color-info);
1744
+ &:hover {
1745
+ @media (hover: hover) {
1746
+ border-color: var(--color-info);
1747
+ }
1748
+ }
1749
+ &:focus-visible {
1750
+ outline-color: var(--color-info);
1751
+ }
1752
+ }
1753
+ :scope._ao-input-success, :scope ._ao-input-success {
1754
+ border-color: var(--color-success);
1755
+ &:hover {
1756
+ @media (hover: hover) {
1757
+ border-color: var(--color-success);
1758
+ }
1759
+ }
1760
+ &:focus-visible {
1761
+ outline-color: var(--color-success);
1762
+ }
1763
+ }
1764
+ :scope._ao-input-warning, :scope ._ao-input-warning {
1765
+ border-color: var(--color-warning);
1766
+ &:hover {
1767
+ @media (hover: hover) {
1768
+ border-color: var(--color-warning);
1769
+ }
1770
+ }
1771
+ &:focus-visible {
1772
+ outline-color: var(--color-warning);
1773
+ }
1774
+ }
1691
1775
  :scope._ao-input-sm, :scope ._ao-input-sm {
1692
1776
  padding-inline: calc(var(--spacing) * 2.5);
1693
1777
  padding-block: calc(var(--spacing) * 1.5);
@@ -1816,6 +1900,43 @@
1816
1900
  outline-color: var(--color-danger);
1817
1901
  }
1818
1902
  }
1903
+ :scope._ao-textarea-info, :scope ._ao-textarea-info {
1904
+ border-color: var(--color-info);
1905
+ &:hover {
1906
+ @media (hover: hover) {
1907
+ border-color: var(--color-info);
1908
+ }
1909
+ }
1910
+ &:focus-visible {
1911
+ outline-color: var(--color-info);
1912
+ }
1913
+ }
1914
+ :scope._ao-textarea-success, :scope ._ao-textarea-success {
1915
+ border-color: var(--color-success);
1916
+ &:hover {
1917
+ @media (hover: hover) {
1918
+ border-color: var(--color-success);
1919
+ }
1920
+ }
1921
+ &:focus-visible {
1922
+ outline-color: var(--color-success);
1923
+ }
1924
+ }
1925
+ :scope._ao-textarea-warning, :scope ._ao-textarea-warning {
1926
+ border-color: var(--color-warning);
1927
+ &:hover {
1928
+ @media (hover: hover) {
1929
+ border-color: var(--color-warning);
1930
+ }
1931
+ }
1932
+ &:focus-visible {
1933
+ outline-color: var(--color-warning);
1934
+ }
1935
+ }
1936
+ :scope._ao-textarea-autosize, :scope ._ao-textarea-autosize {
1937
+ field-sizing: content;
1938
+ resize: none;
1939
+ }
1819
1940
  :scope._ao-textarea-sm, :scope ._ao-textarea-sm {
1820
1941
  min-height: calc(var(--spacing) * 16);
1821
1942
  padding-inline: calc(var(--spacing) * 2.5);
@@ -2291,7 +2412,7 @@
2291
2412
  border-style: var(--tw-border-style);
2292
2413
  border-width: 1px;
2293
2414
  border-color: var(--color-border);
2294
- background-color: var(--color-surface-strong);
2415
+ background-color: var(--color-surface-muted);
2295
2416
  color: var(--color-text);
2296
2417
  --tw-shadow: 0 1px 2px 0 var(--tw-shadow-color, rgb(0 0 0 / 0.05));
2297
2418
  box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
@@ -1,13 +1,16 @@
1
1
  /**
2
2
  * Pure helpers for the hotkey system. Chord syntax: `<mod>+<mod>+…+<key>`
3
3
  *
4
- * Examples: `mod+s`, `shift+?`, `escape`, `mod+shift+k`, `arrowup`.
4
+ * Examples: `mod+s`, `?`, `escape`, `mod+shift+k`, `arrowup`.
5
5
  *
6
- * Modifiers are case-insensitive. `mod` is an alias for `ctrl` on every
7
- * platformdisplay and binding both render as `Ctrl`. The key is whatever
8
- * `KeyboardEvent.key` produces, lowercased. So pressing `shift+/` (which
9
- * yields `event.key === "?"`) is canonically `shift+?` match it by
10
- * binding either `"shift+?"`.
6
+ * Modifiers are case-insensitive. `mod` resolves to the platform's primary
7
+ * command modifier (`meta`) on Apple platforms, `Ctrl` elsewhere so
8
+ * `mod+s` fires on the OS-native gesture (Cmd+S on macOS, Ctrl+S otherwise)
9
+ * and the `<Kbd>` chip follows suit. The key is whatever
10
+ * `KeyboardEvent.key` produces, lowercased. A shifted printable symbol already
11
+ * encodes Shift in the character it produces, so bind `"?"` (not `"shift+?"`)
12
+ * to catch `shift+/`; `shift` stays explicit for letters and named keys, so
13
+ * `shift+a` and `shift+tab` remain distinct chords.
11
14
  */
12
15
  export type Modifier = "ctrl" | "shift" | "alt" | "meta";
13
16
  export interface ParsedChord {
@@ -1 +1 @@
1
- {"version":3,"file":"hotkey-parse.d.ts","sourceRoot":"","sources":["../src/hotkey-parse.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG,OAAO,GAAG,KAAK,GAAG,MAAM,CAAC;AAEzD,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,WAAW,CAAC,QAAQ,CAAC,CAAC;IAC5B,GAAG,EAAE,MAAM,CAAC;CACb;AAqBD,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,WAAW,CA2BrD;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,GAAG,WAAW,EAAE,CAGzE;AAED,6DAA6D;AAC7D,wBAAgB,YAAY,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,CAOvD;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,aAAa,GAAG,MAAM,GAAG,IAAI,CAW9D;AAyBD,2EAA2E;AAC3E,wBAAgB,WAAW,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,EAAE,CAcxD;AAkBD;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,SAAS,WAAW,EAAE,GAAG,MAAM,CAEzE"}
1
+ {"version":3,"file":"hotkey-parse.d.ts","sourceRoot":"","sources":["../src/hotkey-parse.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG,OAAO,GAAG,KAAK,GAAG,MAAM,CAAC;AAEzD,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,WAAW,CAAC,QAAQ,CAAC,CAAC;IAC5B,GAAG,EAAE,MAAM,CAAC;CACb;AAsCD,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,WAAW,CA2BrD;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,GAAG,WAAW,EAAE,CAGzE;AAED,6DAA6D;AAC7D,wBAAgB,YAAY,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,CAOvD;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,aAAa,GAAG,MAAM,GAAG,IAAI,CAgB9D;AA4BD,2EAA2E;AAC3E,wBAAgB,WAAW,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,EAAE,CAcxD;AAkBD;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,SAAS,WAAW,EAAE,GAAG,MAAM,CAEzE"}
@@ -4,11 +4,12 @@ import { RefObject } from 'react';
4
4
  * attached on first registration and detached when the registry empties.
5
5
  *
6
6
  * On keydown:
7
- * 1. Normalize the event to a canonical chord string.
8
- * 2. Look up the bucket. Skip if empty.
9
- * 3. Apply input suppression bare-key chords are skipped while focus is
7
+ * 1. Ignore OS autorepeat (`e.repeat`) so a held chord fires once, not per tick.
8
+ * 2. Normalize the event to a canonical chord string.
9
+ * 3. Look up the bucket. Skip if empty.
10
+ * 4. Apply input suppression — bare-key chords are skipped while focus is
10
11
  * in an editable element, except for `escape`.
11
- * 4. `preventDefault()`, then invoke every surviving handler (bag semantics).
12
+ * 5. `preventDefault()`, then invoke every surviving handler (bag semantics).
12
13
  */
13
14
  export type HotkeyHandler = (e: KeyboardEvent) => void;
14
15
  export interface HotkeyEntry {
@@ -1 +1 @@
1
- {"version":3,"file":"hotkey-registry.d.ts","sourceRoot":"","sources":["../src/hotkey-registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAGvC;;;;;;;;;;GAUG;AAEH,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,EAAE,aAAa,KAAK,IAAI,CAAC;AAEvD,MAAM,WAAW,WAAW;IAC1B,UAAU,EAAE,SAAS,CAAC,aAAa,CAAC,CAAC;CACtC;AA0CD;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,eAAe,EAAE,SAAS,MAAM,EAAE,EAAE,KAAK,EAAE,WAAW,GAAG,MAAM,IAAI,CAmB3F;AAED,6DAA6D;AAC7D,wBAAgB,eAAe,IAAI,IAAI,CAGtC"}
1
+ {"version":3,"file":"hotkey-registry.d.ts","sourceRoot":"","sources":["../src/hotkey-registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAGvC;;;;;;;;;;;GAWG;AAEH,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,EAAE,aAAa,KAAK,IAAI,CAAC;AAEvD,MAAM,WAAW,WAAW;IAC1B,UAAU,EAAE,SAAS,CAAC,aAAa,CAAC,CAAC;CACtC;AA6CD;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,eAAe,EAAE,SAAS,MAAM,EAAE,EAAE,KAAK,EAAE,WAAW,GAAG,MAAM,IAAI,CAmB3F;AAED,6DAA6D;AAC7D,wBAAgB,eAAe,IAAI,IAAI,CAGtC"}
package/dist/index.cjs CHANGED
@@ -4,12 +4,12 @@ let react_jsx_runtime = require("react/jsx-runtime");
4
4
  let react = require("react");
5
5
  let _base_ui_react_button = require("@base-ui/react/button");
6
6
  let _base_ui_react_input = require("@base-ui/react/input");
7
+ let _base_ui_react_field = require("@base-ui/react/field");
7
8
  let _base_ui_react_checkbox = require("@base-ui/react/checkbox");
8
9
  let _base_ui_react_radio = require("@base-ui/react/radio");
9
10
  let _base_ui_react_radio_group = require("@base-ui/react/radio-group");
10
11
  let _base_ui_react_switch = require("@base-ui/react/switch");
11
12
  let _base_ui_react_select = require("@base-ui/react/select");
12
- let _base_ui_react_field = require("@base-ui/react/field");
13
13
  let _base_ui_react_tabs = require("@base-ui/react/tabs");
14
14
  let _base_ui_react_tooltip = require("@base-ui/react/tooltip");
15
15
  let _base_ui_react_dialog = require("@base-ui/react/dialog");
@@ -65,17 +65,40 @@ var Accordion = Object.assign(AccordionRoot, {
65
65
  Content: AccordionContent
66
66
  });
67
67
  //#endregion
68
+ //#region src/portal-context.ts
69
+ /**
70
+ * Container that Base UI popups (Select, Tooltip, etc.) should portal into.
71
+ * `<AdminRoot>` publishes its own element here so popups render inside the
72
+ * scoped subtree and match the `@scope (._ao-admin-root)` CSS — without it
73
+ * they portal to `document.body`, outside the scope, and render unstyled. A
74
+ * `<Dialog>` ancestor overrides it with its own `<dialog>` element so popups
75
+ * join the top layer, painting above the backdrop and escaping its
76
+ * `overflow: hidden`. With no provider the context is null and popups fall
77
+ * back to `document.body`.
78
+ */
79
+ var PortalContainerContext = (0, react.createContext)(null);
80
+ //#endregion
68
81
  //#region src/AdminRoot.tsx
69
- function AdminRoot({ className, theme, systemAccent, style, ...rest }) {
82
+ function AdminRoot({ className, theme, systemAccent, style, ref, ...rest }) {
70
83
  const rootStyle = systemAccent !== void 0 ? {
71
84
  ...style,
72
85
  "--color-system-accent": systemAccent
73
86
  } : style;
74
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
75
- className: cn("admin-root", className),
76
- style: rootStyle,
77
- ...rest,
78
- ...theme !== void 0 && { "data-theme": theme }
87
+ const portalRef = (0, react.useRef)(null);
88
+ const setRef = (0, react.useCallback)((node) => {
89
+ portalRef.current = node;
90
+ if (typeof ref === "function") ref(node);
91
+ else if (ref) ref.current = node;
92
+ }, [ref]);
93
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PortalContainerContext.Provider, {
94
+ value: portalRef,
95
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
96
+ ref: setRef,
97
+ className: cn("admin-root", className),
98
+ style: rootStyle,
99
+ ...rest,
100
+ ...theme !== void 0 && { "data-theme": theme }
101
+ })
79
102
  });
80
103
  }
81
104
  //#endregion
@@ -208,9 +231,22 @@ var MOD_ORDER = [
208
231
  "alt",
209
232
  "meta"
210
233
  ];
234
+ /**
235
+ * Resolve the modifier `mod` aliases to. Apple platforms use ⌘ (`meta`) as the
236
+ * primary command modifier; everywhere else it's Ctrl. Detected once at module
237
+ * load (SSR-safe — the registry never dispatches server-side) and shared by the
238
+ * parse and display layers so the binding and its `<Kbd>` chip always agree.
239
+ */
240
+ function detectApplePlatform() {
241
+ if (typeof navigator === "undefined") return false;
242
+ const platform = navigator.userAgentData?.platform || navigator.platform || "";
243
+ return /^(mac|iphone|ipad|ipod)/i.test(platform);
244
+ }
245
+ var IS_APPLE = detectApplePlatform();
246
+ var MOD_TARGET = IS_APPLE ? "meta" : "ctrl";
211
247
  function tokenToMod(token) {
212
248
  switch (token) {
213
- case "mod":
249
+ case "mod": return MOD_TARGET;
214
250
  case "ctrl":
215
251
  case "control": return "ctrl";
216
252
  case "shift": return "shift";
@@ -259,7 +295,7 @@ function normalizeEvent(e) {
259
295
  if (key === "control" || key === "shift" || key === "alt" || key === "meta") return null;
260
296
  const mods = /* @__PURE__ */ new Set();
261
297
  if (e.ctrlKey) mods.add("ctrl");
262
- if (e.shiftKey) mods.add("shift");
298
+ if (e.shiftKey && !isShiftedSymbol(key)) mods.add("shift");
263
299
  if (e.altKey) mods.add("alt");
264
300
  if (e.metaKey) mods.add("meta");
265
301
  return canonicalize({
@@ -267,6 +303,10 @@ function normalizeEvent(e) {
267
303
  key
268
304
  });
269
305
  }
306
+ /** A single printable symbol (`?`, `+`, `:`, …) — not a letter, digit, or named key. */
307
+ function isShiftedSymbol(key) {
308
+ return key.length === 1 && !/[a-z0-9]/.test(key);
309
+ }
270
310
  var SPECIAL_KEY_LABELS = {
271
311
  escape: "Esc",
272
312
  esc: "Esc",
@@ -282,7 +322,12 @@ var SPECIAL_KEY_LABELS = {
282
322
  backspace: "Backspace",
283
323
  delete: "Del"
284
324
  };
285
- var MOD_LABELS = {
325
+ var MOD_LABELS = IS_APPLE ? {
326
+ ctrl: "⌃",
327
+ shift: "⇧",
328
+ alt: "⌥",
329
+ meta: "⌘"
330
+ } : {
286
331
  ctrl: "Ctrl",
287
332
  shift: "Shift",
288
333
  alt: "Alt",
@@ -372,6 +417,7 @@ function isEditableTarget(target) {
372
417
  return tag === "INPUT" || tag === "TEXTAREA";
373
418
  }
374
419
  function dispatch(e) {
420
+ if (e.repeat) return;
375
421
  const chord = normalizeEvent(e);
376
422
  if (chord === null) return;
377
423
  const bucket = registry.get(chord);
@@ -447,10 +493,17 @@ function useHotkey(keys, handler, options) {
447
493
  }
448
494
  //#endregion
449
495
  //#region src/Button.tsx
450
- function Button({ variant = "default", size = "md", fullWidth, loading, icon, iconTrailing, hotkey, className, type = "button", disabled, children, onClick, ...rest }) {
451
- const { ariaKeyShortcuts, primaryChord } = useHotkey(hotkey, (e) => onClick?.(e), { enabled: !disabled && !loading });
496
+ function Button({ variant = "default", size = "md", fullWidth, loading, icon, iconTrailing, hotkey, className, type = "button", disabled, children, onClick, ref, ...rest }) {
497
+ const elementRef = (0, react.useRef)(null);
498
+ const setRef = (0, react.useCallback)((node) => {
499
+ elementRef.current = node;
500
+ if (typeof ref === "function") ref(node);
501
+ else if (ref) ref.current = node;
502
+ }, [ref]);
503
+ const { ariaKeyShortcuts, primaryChord } = useHotkey(hotkey, () => elementRef.current?.click(), { enabled: !disabled && !loading });
452
504
  const iconOnly = children == null && (icon != null || iconTrailing != null);
453
505
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_base_ui_react_button.Button, {
506
+ ref: setRef,
454
507
  onClick,
455
508
  type,
456
509
  disabled: disabled || loading,
@@ -475,10 +528,14 @@ function Button({ variant = "default", size = "md", fullWidth, loading, icon, ic
475
528
  }
476
529
  //#endregion
477
530
  //#region src/ButtonGroup.tsx
478
- function ButtonGroup({ orientation = "horizontal", role = "group", className, ...rest }) {
531
+ function ButtonGroup({ orientation = "horizontal", fullWidth = false, role = "group", className, ...rest }) {
479
532
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
480
533
  role,
481
- className: cn(["btn-group", orientation === "vertical" && "btn-group-vertical"], className),
534
+ className: cn([
535
+ "btn-group",
536
+ orientation === "vertical" && "btn-group-vertical",
537
+ fullWidth && "btn-group-full-width"
538
+ ], className),
482
539
  ...rest
483
540
  });
484
541
  }
@@ -598,6 +655,26 @@ function Indicator({ label, variant = "neutral", size = "sm", icon, placement =
598
655
  });
599
656
  }
600
657
  //#endregion
658
+ //#region src/Link.tsx
659
+ /**
660
+ * A text link — a plain `<a>` with the design system's link styling: primary
661
+ * color, hover shift, underline, and a focus-visible ring. Pass `external` for
662
+ * the new-tab affordance.
663
+ */
664
+ function Link({ external, icon, iconTrailing, className, target, rel, children, ...rest }) {
665
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("a", {
666
+ target: target ?? (external ? "_blank" : void 0),
667
+ rel: rel ?? (external ? "noopener noreferrer" : void 0),
668
+ className: cn(["link", external && "link-external"], className),
669
+ ...rest,
670
+ children: [
671
+ renderIcon(icon),
672
+ children,
673
+ renderIcon(iconTrailing)
674
+ ]
675
+ });
676
+ }
677
+ //#endregion
601
678
  //#region src/Pagination.tsx
602
679
  /**
603
680
  * Compute the items to render for a given `page` / `total`. Always returns:
@@ -759,12 +836,21 @@ function defaultRender(item, onPageChange, prev, next) {
759
836
  }
760
837
  //#endregion
761
838
  //#region src/Textarea.tsx
762
- function Textarea({ variant = "bordered", textareaSize = "md", className, ...rest }) {
763
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("textarea", {
839
+ /**
840
+ * Multi-line text input. Rendered through Base UI's `Field.Control` with a
841
+ * `<textarea>` swapped in for the default `<input>`, so inside a `<Field>` it
842
+ * gets the same wiring as `<Input>`: a generated id, label `htmlFor`
843
+ * association, and validity-driven `:user-valid` / `<Field.Error>`. Works
844
+ * standalone too — `Field.Control` falls back to a default context.
845
+ */
846
+ function Textarea({ variant = "bordered", textareaSize = "md", autoResize, className, ...rest }) {
847
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_base_ui_react_field.Field.Control, {
848
+ render: (props) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("textarea", { ...props }),
764
849
  className: cn([
765
850
  "textarea",
766
851
  variant !== "bordered" && `textarea-${variant}`,
767
- textareaSize !== "md" && `textarea-${textareaSize}`
852
+ textareaSize !== "md" && `textarea-${textareaSize}`,
853
+ autoResize && "textarea-autosize"
768
854
  ], className),
769
855
  ...rest
770
856
  });
@@ -861,16 +947,6 @@ function SwitchThumb({ className, ...rest }) {
861
947
  }
862
948
  var Switch = Object.assign(SwitchRoot, { Thumb: SwitchThumb });
863
949
  //#endregion
864
- //#region src/portal-context.ts
865
- /**
866
- * Container that Base UI popups (Select, Tooltip, etc.) should portal into.
867
- * When a `<Dialog>` ancestor publishes its `<dialog>` element through this
868
- * context, popups render inside that top-layer dialog so they paint above
869
- * the backdrop and escape its `overflow: hidden`. Outside a dialog the
870
- * context is null and popups portal to `document.body` as before.
871
- */
872
- var PortalContainerContext = (0, react.createContext)(null);
873
- //#endregion
874
950
  //#region src/Select.tsx
875
951
  function SelectRoot(props) {
876
952
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_base_ui_react_select.Select.Root, { ...props });
@@ -1952,6 +2028,7 @@ exports.Indicator = Indicator;
1952
2028
  exports.Input = Input;
1953
2029
  exports.InputGroup = InputGroup;
1954
2030
  exports.Kbd = Kbd;
2031
+ exports.Link = Link;
1955
2032
  exports.Menu = Menu;
1956
2033
  exports.Navbar = Navbar;
1957
2034
  exports.Pagination = Pagination;