@viraui/react 2026.2.17 → 2026.3.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 (39) hide show
  1. package/dist/catalog.json +6 -0
  2. package/dist/components/autocomplete/autocomplete-item.js +1 -1
  3. package/dist/components/autocomplete/autocomplete.js +1 -1
  4. package/dist/components/breakpoints/breakpoints-provider.d.ts +28 -0
  5. package/dist/components/breakpoints/breakpoints-provider.js +93 -0
  6. package/dist/components/breakpoints/breakpoints.guide.json +40 -0
  7. package/dist/components/breakpoints/index.d.ts +3 -0
  8. package/dist/components/breakpoints/use-breakpoints.d.ts +2 -0
  9. package/dist/components/breakpoints/use-breakpoints.js +33 -0
  10. package/dist/components/button/button-link.d.ts +9 -9
  11. package/dist/components/button/button-link.js +45 -28
  12. package/dist/components/button/button.css +1 -1
  13. package/dist/components/button/button.d.ts +9 -7
  14. package/dist/components/button/button.js +41 -78
  15. package/dist/components/dialog/dialog-sheet.js +3 -3
  16. package/dist/components/fieldset/fieldset.js +1 -1
  17. package/dist/components/index.d.ts +1 -0
  18. package/dist/components/menu/menu-item-row.js +1 -1
  19. package/dist/components/menu/menu-link-item.js +1 -1
  20. package/dist/components/popover/popover-sheet.js +1 -1
  21. package/dist/components/select/select-option.js +2 -2
  22. package/dist/components/select/select.js +2 -2
  23. package/dist/components/stack/stack.css +1 -1
  24. package/dist/components/stack/stack.d.ts +15 -3
  25. package/dist/components/stack/stack.guide.json +14 -7
  26. package/dist/components/stack/stack.js +3 -2
  27. package/dist/components/switch/switch.js +1 -1
  28. package/dist/components/tabs/tabs-list.js +9 -10
  29. package/dist/components/tabs/tabs.css +1 -1
  30. package/dist/components/tabs/tabs.module.js +3 -3
  31. package/dist/components/textarea/textarea.js +1 -1
  32. package/dist/components/textfield/textfield.js +1 -1
  33. package/dist/index.js +3 -1
  34. package/dist/preflight-surface.json +6 -6
  35. package/dist/preflight.css +1 -1
  36. package/package.json +3 -3
  37. package/dist/components/button/button-chrome.d.ts +0 -37
  38. package/dist/components/button/button-chrome.js +0 -48
  39. package/dist/internal/chrome-icons/chrome-icons.self-check.d.ts +0 -1
package/dist/catalog.json CHANGED
@@ -50,6 +50,12 @@
50
50
  "summary": "Layout utility that pulls content past inline padding using negative margins or full viewport bleed.",
51
51
  "guidePath": "./components/bleed/bleed.guide.json"
52
52
  },
53
+ {
54
+ "id": "breakpoints",
55
+ "name": "BreakpointsProvider",
56
+ "summary": "Client provider plus `useBreakpoints` for mobile-first viewport min-width matches. Defaults are hardcoded em thresholds, not theme tokens.",
57
+ "guidePath": "./components/breakpoints/breakpoints.guide.json"
58
+ },
53
59
  {
54
60
  "id": "button",
55
61
  "name": "Button",
@@ -19,7 +19,7 @@ var AutocompleteItemPart = ({ addon, addonAlign = "center", children, className,
19
19
  vAlign: addonAlign,
20
20
  vPadding: "small",
21
21
  children: [addon && /* @__PURE__ */ jsx(Stack, {
22
- fillChildren: true,
22
+ expandChildren: true,
23
23
  "aria-hidden": "true",
24
24
  "data-grow": "false",
25
25
  "data-shrink": "false",
@@ -36,7 +36,7 @@ function AutocompleteRootComponent({ children, className, container, description
36
36
  validationDebounceTime,
37
37
  validationMode,
38
38
  render: /* @__PURE__ */ jsx(Stack, {
39
- fillChildren: true,
39
+ expandChildren: true,
40
40
  rowGap: "small"
41
41
  }),
42
42
  children: [
@@ -0,0 +1,28 @@
1
+ import type * as React from 'react';
2
+ export type DefaultBreakpointName = 'extra-small' | 'small' | 'medium' | 'large' | 'extra-large';
3
+ /**
4
+ * Named min-width thresholds. Values are CSS lengths used in `(min-width: <value>)` queries.
5
+ */
6
+ export type BreakpointMap = Record<string, string>;
7
+ export type BreakpointsProviderProps = {
8
+ /**
9
+ * Replaces the entire default breakpoint map for this provider instance.
10
+ *
11
+ * @defaultValue Hardcoded extra-small 30em, small 48em, medium 60em, large 80em, extra-large 100em
12
+ */
13
+ breakpoints?: BreakpointMap;
14
+ /**
15
+ * Tree that may call `useBreakpoints`.
16
+ *
17
+ * @defaultValue No default. Consumers must provide children.
18
+ */
19
+ children: React.ReactNode;
20
+ };
21
+ export type BreakpointsStore = {
22
+ subscribe: (onStoreChange: () => void) => () => void;
23
+ getSnapshot: () => Record<string, boolean>;
24
+ getServerSnapshot: () => Record<string, boolean>;
25
+ dispose: () => void;
26
+ };
27
+ export declare const BreakpointsStoreContext: React.Context<BreakpointsStore | null>;
28
+ export declare const BreakpointsProvider: React.FC<BreakpointsProviderProps>;
@@ -0,0 +1,93 @@
1
+ "use client";
2
+ import { jsx } from "react/jsx-runtime";
3
+ import { createContext, useEffect, useMemo } from "react";
4
+ //#region src/components/breakpoints/breakpoints-provider.tsx
5
+ var defaultBreakpointMap = {
6
+ "extra-small": "30em",
7
+ small: "48em",
8
+ medium: "60em",
9
+ large: "80em",
10
+ "extra-large": "100em"
11
+ };
12
+ var BreakpointsStoreContext = createContext(null);
13
+ var matchesFromMap = (map, matched) => {
14
+ const next = {};
15
+ for (const name of Object.keys(map)) next[name] = matched;
16
+ return next;
17
+ };
18
+ var assertBreakpointMap = (map) => {
19
+ const names = Object.keys(map);
20
+ if (names.length === 0) throw new Error("BreakpointsProvider: `breakpoints` must be a non-empty map of name → CSS length.");
21
+ for (const name of names) {
22
+ const value = map[name];
23
+ if (name.trim() === "" || typeof value !== "string" || value.trim() === "") throw new Error(`BreakpointsProvider: invalid breakpoint "${name}". Each name and length must be a non-empty string.`);
24
+ }
25
+ };
26
+ var snapshotsEqual = (left, right) => {
27
+ const keys = Object.keys(left);
28
+ if (keys.length !== Object.keys(right).length) return false;
29
+ return keys.every((key) => left[key] === right[key]);
30
+ };
31
+ var canUseMatchMedia = () => typeof window !== "undefined" && typeof window.matchMedia === "function";
32
+ var readClientMatches = (map) => {
33
+ const next = {};
34
+ for (const name of Object.keys(map)) next[name] = window.matchMedia(`(min-width: ${map[name]})`).matches;
35
+ return next;
36
+ };
37
+ var createBreakpointsStore = (map) => {
38
+ assertBreakpointMap(map);
39
+ const serverSnapshot = matchesFromMap(map, false);
40
+ let snapshot = canUseMatchMedia() ? readClientMatches(map) : serverSnapshot;
41
+ const listeners = /* @__PURE__ */ new Set();
42
+ const mediaQueries = [];
43
+ const emitIfChanged = (next) => {
44
+ if (snapshotsEqual(snapshot, next)) return;
45
+ snapshot = next;
46
+ for (const listener of listeners) listener();
47
+ };
48
+ const startWatching = () => {
49
+ if (!canUseMatchMedia() || mediaQueries.length > 0) return;
50
+ snapshot = readClientMatches(map);
51
+ for (const name of Object.keys(map)) {
52
+ const mediaQueryList = window.matchMedia(`(min-width: ${map[name]})`);
53
+ const onChange = () => emitIfChanged(readClientMatches(map));
54
+ mediaQueryList.addEventListener("change", onChange);
55
+ mediaQueries.push({
56
+ mediaQueryList,
57
+ onChange
58
+ });
59
+ }
60
+ };
61
+ const stopWatching = () => {
62
+ for (const { mediaQueryList, onChange } of mediaQueries) mediaQueryList.removeEventListener("change", onChange);
63
+ mediaQueries.length = 0;
64
+ };
65
+ return {
66
+ subscribe: (onStoreChange) => {
67
+ listeners.add(onStoreChange);
68
+ if (listeners.size === 1) startWatching();
69
+ return () => {
70
+ listeners.delete(onStoreChange);
71
+ if (listeners.size === 0) stopWatching();
72
+ };
73
+ },
74
+ getSnapshot: () => snapshot,
75
+ getServerSnapshot: () => serverSnapshot,
76
+ dispose: () => {
77
+ stopWatching();
78
+ listeners.clear();
79
+ }
80
+ };
81
+ };
82
+ var BreakpointsProvider = ({ breakpoints = defaultBreakpointMap, children }) => {
83
+ const store = useMemo(() => createBreakpointsStore(breakpoints), [breakpoints]);
84
+ useEffect(() => () => {
85
+ store.dispose();
86
+ }, [store]);
87
+ return /* @__PURE__ */ jsx(BreakpointsStoreContext.Provider, {
88
+ value: store,
89
+ children
90
+ });
91
+ };
92
+ //#endregion
93
+ export { BreakpointsProvider, BreakpointsStoreContext };
@@ -0,0 +1,40 @@
1
+ {
2
+ "name": "BreakpointsProvider",
3
+ "structure": "<BreakpointsProvider>\n {children}\n</BreakpointsProvider>",
4
+ "summary": "Client provider plus `useBreakpoints` for mobile-first viewport min-width matches. Defaults are hardcoded em thresholds, not theme tokens.",
5
+ "whenToUse": [
6
+ "Swap or hide React markup when the viewport crosses named breakpoints",
7
+ "Read one flag with `useBreakpoints('small')` so unrelated breakpoint flips skip work",
8
+ "Override the full map with the `breakpoints` prop for product-specific thresholds"
9
+ ],
10
+ "whenNotToUse": [
11
+ "Layout that CSS `@media` or container queries can own without branching markup",
12
+ "Calling `useBreakpoints` outside this provider",
13
+ "Reading design-token CSS variables for breakpoint widths"
14
+ ],
15
+ "accessibility": [
16
+ "Match state is not an APG widget. Keep the same accessible name and semantics when swapping chrome",
17
+ "Do not rely on breakpoint-only visibility as the only way to reach essential actions on small viewports"
18
+ ],
19
+ "antiPatterns": [
20
+ "Using `useBreakpoints` without wrapping the tree in `BreakpointsProvider`",
21
+ "Merging a sparse custom map onto defaults — the `breakpoints` prop replaces the whole map",
22
+ "Putting the provider in a Server Component module — wrap it in a Client Component (`'use client'`)"
23
+ ],
24
+ "related": ["Stack", "Grid"],
25
+ "usage": [
26
+ "Place `BreakpointsProvider` in a Client Component (Next.js: same client providers module as overlays, or a nested client wrapper). Server Components may compose around that boundary.",
27
+ "On the server and before measure, every named breakpoint is unmatched (mobile-first base). After hydration, flags follow the real viewport; first paint may differ on wide screens — prefer CSS for chrome that must not flash.",
28
+ "Nested providers isolate subtrees. The innermost map wins."
29
+ ],
30
+ "properties": {
31
+ "react": {
32
+ "breakpoints": {
33
+ "description": "Replaces the entire default map (extra-small 30em, small 48em, medium 60em, large 80em, extra-large 100em). Values are CSS lengths used as mobile-first min-width queries."
34
+ },
35
+ "children": {
36
+ "description": "Tree that may call `useBreakpoints`. The hook returns all match flags, or `useBreakpoints(name)` for one boolean."
37
+ }
38
+ }
39
+ }
40
+ }
@@ -0,0 +1,3 @@
1
+ export { BreakpointsProvider } from './breakpoints-provider';
2
+ export type { BreakpointMap, BreakpointsProviderProps, DefaultBreakpointName } from './breakpoints-provider';
3
+ export { useBreakpoints } from './use-breakpoints';
@@ -0,0 +1,2 @@
1
+ export declare function useBreakpoints(): Record<string, boolean>;
2
+ export declare function useBreakpoints(name: string): boolean;
@@ -0,0 +1,33 @@
1
+ "use client";
2
+ import { BreakpointsStoreContext } from "./breakpoints-provider.js";
3
+ import { useCallback, useContext, useSyncExternalStore } from "react";
4
+ //#region src/components/breakpoints/use-breakpoints.ts
5
+ var noop = () => void 0;
6
+ var missingStore = {
7
+ subscribe: () => noop,
8
+ getSnapshot: () => {
9
+ throw new Error("useBreakpoints must be used within a BreakpointsProvider.");
10
+ },
11
+ getServerSnapshot: () => {
12
+ throw new Error("useBreakpoints must be used within a BreakpointsProvider.");
13
+ },
14
+ dispose: noop
15
+ };
16
+ function useBreakpoints(name) {
17
+ const store = useContext(BreakpointsStoreContext) ?? missingStore;
18
+ const getSnapshot = useCallback(() => {
19
+ const snapshot = store.getSnapshot();
20
+ if (name === void 0) return snapshot;
21
+ if (!(name in snapshot)) throw new Error(`useBreakpoints: unknown breakpoint "${name}".`);
22
+ return snapshot[name] === true;
23
+ }, [name, store]);
24
+ const getServerSnapshot = useCallback(() => {
25
+ const snapshot = store.getServerSnapshot();
26
+ if (name === void 0) return snapshot;
27
+ if (!(name in snapshot)) throw new Error(`useBreakpoints: unknown breakpoint "${name}".`);
28
+ return snapshot[name] === true;
29
+ }, [name, store]);
30
+ return useSyncExternalStore(store.subscribe, getSnapshot, getServerSnapshot);
31
+ }
32
+ //#endregion
33
+ export { useBreakpoints };
@@ -1,5 +1,5 @@
1
1
  import { useRender } from '@base-ui/react/use-render';
2
- import { ButtonAddonPosition, ButtonSize, ButtonVariant } from './button-chrome';
2
+ import { ButtonAddonPosition, ButtonSize, ButtonVariant } from './button';
3
3
  import { ReactNode } from 'react';
4
4
  import * as React from 'react';
5
5
  /**
@@ -14,49 +14,49 @@ export type ButtonLinkProps = Omit<React.ComponentPropsWithRef<'a'>, 'type'> & {
14
14
  /**
15
15
  * Replaces the default `a` root using Base UI render semantics (e.g. Next.js `Link`).
16
16
  *
17
- * @default The link renders an `a` root.
17
+ * @defaultValue The link renders an `a` root.
18
18
  */
19
19
  render?: useRender.RenderProp;
20
20
  /**
21
21
  * Controls the visual button size.
22
22
  *
23
- * @default 'medium'
23
+ * @defaultValue 'medium'
24
24
  */
25
25
  size?: ButtonSize;
26
26
  /**
27
27
  * Selects the visual treatment matching Button.
28
28
  *
29
- * @default 'primary'
29
+ * @defaultValue 'primary'
30
30
  */
31
31
  variant?: ButtonVariant;
32
32
  /**
33
33
  * Decorative addon rendered alongside the link label.
34
34
  *
35
- * @default No default; omit when the link has no addon.
35
+ * @defaultValue undefined
36
36
  */
37
37
  addon?: ReactNode;
38
38
  /**
39
39
  * Controls whether the addon appears before or after the label.
40
40
  *
41
- * @default 'start'
41
+ * @defaultValue 'start'
42
42
  */
43
43
  addonPosition?: ButtonAddonPosition;
44
44
  /**
45
45
  * Shows a centered spinner overlay while preserving the original content width.
46
46
  *
47
- * @default false
47
+ * @defaultValue false
48
48
  */
49
49
  loading?: boolean;
50
50
  /**
51
51
  * Applies a fully rounded pill shape.
52
52
  *
53
- * @default false
53
+ * @defaultValue false
54
54
  */
55
55
  pill?: boolean;
56
56
  /**
57
57
  * Marks the link inert via `aria-disabled` and prevents activation.
58
58
  *
59
- * @default false
59
+ * @defaultValue false
60
60
  */
61
61
  disabled?: boolean;
62
62
  };
@@ -1,43 +1,60 @@
1
- import { ButtonChromeChildren, getButtonChromeRootAttrs } from "./button-chrome.js";
2
- import { jsx } from "react/jsx-runtime";
1
+ import { clsx } from "../../core/clsx.js";
2
+ import { Spinner } from "../spinner/spinner.js";
3
+ import button_module_default from "./button.module.js";
4
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
5
  import "react";
4
6
  import { useRender } from "@base-ui/react/use-render";
5
7
  //#region src/components/button/button-link.tsx
6
8
  var ButtonLink = ({ children, className, disabled = false, addon, addonPosition = "start", loading = false, pill = false, size = "medium", variant = "primary", render, ref, onClick, ...otherProps }) => {
7
- const isDisabled = disabled || loading;
9
+ const isDisabled = Boolean(disabled || loading);
8
10
  const isIconOnly = Boolean(addon) && (children == null || children === "");
11
+ const loadingAttr = loading ? "true" : "false";
12
+ const spinnerSize = size === "large" ? "medium" : "small";
13
+ const handleClick = (event) => {
14
+ if (isDisabled) {
15
+ event.preventDefault();
16
+ return;
17
+ }
18
+ onClick?.(event);
19
+ };
9
20
  return useRender({
10
21
  defaultTagName: "a",
11
22
  render,
12
23
  ref,
13
24
  props: {
14
25
  ...otherProps,
15
- ...getButtonChromeRootAttrs({
16
- addon,
17
- addonPosition,
18
- className,
19
- isDisabled,
20
- isIconOnly,
21
- loading,
22
- pill,
23
- size,
24
- variant
25
- }),
26
- children: /* @__PURE__ */ jsx(ButtonChromeChildren, {
27
- addon,
28
- isIconOnly,
29
- loading,
30
- size,
26
+ "aria-busy": loading || void 0,
27
+ className: clsx(button_module_default.Button, className),
28
+ "data-loading": loadingAttr,
29
+ "data-pill": pill ? "true" : "false",
30
+ "data-size": size,
31
+ "data-icon-only": isIconOnly ? "true" : "false",
32
+ "data-addon-position": addon && !isIconOnly ? addonPosition : void 0,
33
+ "data-variant": variant,
34
+ onClick: handleClick,
35
+ ...isDisabled && { "aria-disabled": true },
36
+ children: /* @__PURE__ */ jsxs(Fragment, { children: [isIconOnly ? /* @__PURE__ */ jsx("span", {
37
+ "aria-hidden": "true",
38
+ className: button_module_default.Content,
39
+ "data-loading": loadingAttr,
40
+ children: addon
41
+ }) : /* @__PURE__ */ jsxs(Fragment, { children: [addon && /* @__PURE__ */ jsx("span", {
42
+ "aria-hidden": "true",
43
+ className: button_module_default.Content,
44
+ "data-loading": loadingAttr,
45
+ children: addon
46
+ }), /* @__PURE__ */ jsx("span", {
47
+ className: button_module_default.Content,
48
+ "data-loading": loadingAttr,
31
49
  children
32
- }),
33
- onClick: (event) => {
34
- if (isDisabled) {
35
- event.preventDefault();
36
- return;
37
- }
38
- onClick?.(event);
39
- },
40
- ...isDisabled && { "aria-disabled": true }
50
+ })] }), loading && /* @__PURE__ */ jsx("span", {
51
+ "aria-hidden": "true",
52
+ className: button_module_default.SpinnerOverlay,
53
+ children: /* @__PURE__ */ jsx(Spinner, {
54
+ variant: "dots",
55
+ size: spinnerSize
56
+ })
57
+ })] })
41
58
  }
42
59
  });
43
60
  };
@@ -1 +1 @@
1
- @layer viraui.preflight, viraui.components, viraui.overrides;@layer viraui.components{@property --vui-button-background{syntax:"<color>";inherits:false;initial-value:#0000}@property --vui-button-color{syntax:"<color>";inherits:false;initial-value:#0000}@property --vui-button-height{syntax:"<length>";inherits:false;initial-value:0}@property --vui-button-padding-inline{syntax:"<length>";inherits:false;initial-value:0}@property --vui-button-padding-block{syntax:"<length>";inherits:false;initial-value:0}@property --vui-button-spinner-color{syntax:"<color>";inherits:true;initial-value:#0000}@property --vui-button-icon-size{syntax:"<length>";inherits:true;initial-value:0}@property --vui-button-radius{syntax:"<length-percentage>";inherits:false;initial-value:0}.viraui__button-module__Button_oPhrP{--vui-button-background:var(--global-primary);--vui-button-color:var(--base-1);--vui-button-height:var(--space-2x-large);--vui-button-padding-inline:calc(var(--space-small) + var(--space-2x-small));--vui-button-padding-block:var(--space-small);--vui-button-icon-size:1.125em;--vui-button-spinner-color:currentColor;--vui-button-radius:var(--radius-medium);max-block-size:min-content;-webkit-user-select:none;user-select:none;margin:0;cursor:pointer;font-family:inherit;display:inline-flex;align-items:center;min-inline-size:fit-content;min-block-size:var(--vui-button-height);block-size:var(--vui-button-height);justify-content:center;text-decoration:none;white-space:nowrap;appearance:button;overflow:hidden;position:relative;padding:var(--vui-button-padding-block) var(--vui-button-padding-inline);font-weight:400;font-variation-settings:"wght" 400;gap:var(--space-small);border:1px solid #0000;background:var(--vui-button-background);color:var(--vui-button-color);font-size:var(--font-scale-body-medium);border-radius:var(--vui-button-radius);transition:translate var(--easing-elastic) var(--duration-instant);will-change:translate;&:not(:disabled){background-clip:padding-box}&:not(:disabled,[aria-disabled=true]):active{translate:0 1px}&[data-pill=true]{border-radius:var(--radius-infinite)}&[data-size=large]{--vui-button-height:calc(var(--space-2x-large) + var(--space-x-small));--vui-button-padding-inline:calc(var(--space-medium) + var(--space-2x-small));--vui-button-padding-block:var(--space-small);--vui-button-icon-size:1.125em;--vui-button-radius:var(--radius-medium)}&[data-size=small]{--vui-button-height:var(--space-x-large);--vui-button-padding-inline:var(--space-small);--vui-button-padding-block:var(--space-x-small);--vui-button-icon-size:1em;--vui-button-radius:var(--radius-small);gap:var(--space-x-small);font-size:var(--font-scale-body-small)}&[data-variant=primary]{--vui-button-background:var(--global-primary);--vui-button-color:contrast-color(var(--global-primary));&:hover{--vui-button-background:oklab(from var(--global-primary) calc(l + 0.05) a b)}}&[data-variant=secondary]{--vui-button-background:var(--global-contrast);--vui-button-color:var(--global-foreground);background-clip:unset;&:hover{--vui-button-background:oklab(from var(--global-contrast) l a b / calc(alpha + 0.03))}@container root style(--is-light-mode: black){--vui-button-background:oklab(from var(--global-contrast) l a b / 0.1)}}&[data-variant=flat]{--vui-button-background:#0000;--vui-button-color:var(--global-foreground);background-clip:unset;&:hover{--vui-button-background:var(--global-contrast);--vui-button-color:var(--base-7)}}&[data-variant=destructive]{--vui-button-background:oklab(from var(--highlight-red) l a b / 12%);--vui-button-color:var(--highlight-red);outline-color:var(--highlight-red);&:hover{--vui-button-background:oklab(from var(--highlight-red) l a b / 30%)}}&[data-addon-position=start]{flex-direction:row;padding-inline-end:calc(var(--vui-button-padding-inline) * 1.2)}&[data-addon-position=end]{flex-direction:row-reverse;padding-inline-start:calc(var(--vui-button-padding-inline) * 1.2)}&[data-icon-only=true]{gap:0;padding-block:var(--vui-button-padding-block);padding-inline:var(--vui-button-padding-block);inline-size:var(--vui-button-height);min-inline-size:var(--vui-button-height);max-inline-size:var(--vui-button-height);aspect-ratio:1/1}&:disabled,&:disabled:active,&:disabled:hover,&[aria-disabled=true],&[aria-disabled=true]:active,&[aria-disabled=true]:hover{--vui-button-background:var(--global-disabled-background);--vui-button-color:var(--global-disabled-foreground);cursor:not-allowed;box-shadow:none;translate:0}&[data-variant=flat]:is(:disabled,[aria-disabled=true]),&[data-variant=flat]:is(:disabled,[aria-disabled=true]):active,&[data-variant=flat]:is(:disabled,[aria-disabled=true]):hover{--vui-button-background:#0000}&[data-loading=true][data-disabled]{pointer-events:none;border:0;box-shadow:none;--vui-button-color:var(--base-7)}}.viraui__button-module__Content_w-pX-{display:inline-grid;place-items:center;&[data-loading=true]{opacity:0}&:first-child>svg{block-size:var(--vui-button-icon-size);inline-size:var(--vui-button-icon-size);flex-shrink:0}}.viraui__button-module__SpinnerOverlay_vKqw1{position:absolute;inset:0;display:grid;place-content:center;pointer-events:none;color:var(--vui-button-spinner-color)}}
1
+ @layer viraui.preflight, viraui.components, viraui.overrides;@layer viraui.components{@property --vui-button-background{syntax:"<color>";inherits:false;initial-value:#0000}@property --vui-button-color{syntax:"<color>";inherits:false;initial-value:#0000}@property --vui-button-height{syntax:"<length>";inherits:false;initial-value:0}@property --vui-button-padding-inline{syntax:"<length>";inherits:false;initial-value:0}@property --vui-button-padding-block{syntax:"<length>";inherits:false;initial-value:0}@property --vui-button-spinner-color{syntax:"<color>";inherits:true;initial-value:#0000}@property --vui-button-icon-size{syntax:"<length>";inherits:true;initial-value:0}@property --vui-button-radius{syntax:"<length-percentage>";inherits:false;initial-value:0}.viraui__button-module__Button_oPhrP{--vui-button-background:var(--global-primary);--vui-button-color:var(--base-1);--vui-button-height:var(--space-2x-large);--vui-button-padding-inline:calc(var(--space-small) + var(--space-2x-small));--vui-button-padding-block:var(--space-small);--vui-button-icon-size:1.125em;--vui-button-spinner-color:currentColor;--vui-button-radius:var(--radius-medium);max-block-size:min-content;-webkit-user-select:none;user-select:none;margin-block:0;margin-inline:0;cursor:pointer;font-family:inherit;display:inline-flex;align-items:center;min-inline-size:fit-content;min-block-size:var(--vui-button-height);block-size:var(--vui-button-height);justify-content:center;text-decoration:none;white-space:nowrap;appearance:button;overflow:hidden;position:relative;padding:var(--vui-button-padding-block) var(--vui-button-padding-inline);font-weight:400;font-variation-settings:"wght" 400;gap:var(--space-small);border:1px solid #0000;background:var(--vui-button-background);color:var(--vui-button-color);font-size:var(--font-scale-body-medium);border-radius:var(--vui-button-radius);transition:translate var(--easing-elastic) var(--duration-instant);will-change:translate;&:not(:disabled){background-clip:padding-box}&:not(:disabled,[aria-disabled=true]):active{translate:0 1px}&[data-pill=true]{border-radius:var(--radius-infinite)}&[data-size=large]{--vui-button-height:calc(var(--space-2x-large) + var(--space-x-small));--vui-button-padding-inline:calc(var(--space-medium) + var(--space-2x-small));--vui-button-padding-block:var(--space-small);--vui-button-icon-size:1.125em;--vui-button-radius:var(--radius-medium)}&[data-size=small]{--vui-button-height:var(--space-x-large);--vui-button-padding-inline:var(--space-small);--vui-button-padding-block:var(--space-x-small);--vui-button-icon-size:1em;--vui-button-radius:var(--radius-small);gap:var(--space-x-small);font-size:var(--font-scale-body-small)}&[data-variant=primary]{--vui-button-background:var(--global-primary);--vui-button-color:contrast-color(var(--global-primary));&:hover{--vui-button-background:oklab(from var(--global-primary) calc(l + 0.05) a b)}}&[data-variant=secondary]{--vui-button-background:var(--global-contrast);--vui-button-color:var(--global-foreground);background-clip:unset;&:hover{--vui-button-background:oklab(from var(--global-contrast) l a b / calc(alpha + 0.03))}@container root style(--is-light-mode: black){--vui-button-background:oklab(from var(--global-contrast) l a b / 0.1)}}&[data-variant=flat]{--vui-button-background:#0000;--vui-button-color:var(--global-foreground);background-clip:unset;&:hover{--vui-button-background:var(--global-contrast);--vui-button-color:var(--base-7)}}&[data-variant=destructive]{--vui-button-background:oklab(from var(--highlight-red) l a b / 12%);--vui-button-color:var(--highlight-red);outline-color:var(--highlight-red);&:hover{--vui-button-background:oklab(from var(--highlight-red) l a b / 30%)}}&[data-addon-position=start]{flex-direction:row;padding-inline-end:calc(var(--vui-button-padding-inline) * 1.2)}&[data-addon-position=end]{flex-direction:row-reverse;padding-inline-start:calc(var(--vui-button-padding-inline) * 1.2)}&[data-icon-only=true]{gap:0;padding-block:var(--vui-button-padding-block);padding-inline:var(--vui-button-padding-block);inline-size:var(--vui-button-height);min-inline-size:var(--vui-button-height);max-inline-size:var(--vui-button-height);aspect-ratio:1/1}&:disabled,&:disabled:active,&:disabled:hover,&[aria-disabled=true],&[aria-disabled=true]:active,&[aria-disabled=true]:hover{--vui-button-background:var(--global-disabled-background);--vui-button-color:var(--global-disabled-foreground);cursor:not-allowed;box-shadow:none;translate:0}&[data-variant=flat]:is(:disabled,[aria-disabled=true]),&[data-variant=flat]:is(:disabled,[aria-disabled=true]):active,&[data-variant=flat]:is(:disabled,[aria-disabled=true]):hover{--vui-button-background:#0000}&[data-loading=true]:is(:disabled,[data-disabled],[aria-disabled=true]){pointer-events:none;border:0;box-shadow:none;--vui-button-color:var(--base-7)}}.viraui__button-module__Content_w-pX-{display:inline-grid;place-items:center;&[data-loading=true]{opacity:0}&:first-child>svg{block-size:var(--vui-button-icon-size);inline-size:var(--vui-button-icon-size);flex-shrink:0}}.viraui__button-module__SpinnerOverlay_vKqw1{position:absolute;inset:0;display:grid;place-content:center;pointer-events:none;color:var(--vui-button-spinner-color)}}
@@ -1,7 +1,9 @@
1
1
  import { Button as PrimitiveButton } from '@base-ui/react/button';
2
- import { ButtonAddonPosition, ButtonSize, ButtonVariant } from './button-chrome';
3
2
  import { ReactNode } from 'react';
4
3
  import * as React from 'react';
4
+ export type ButtonSize = 'large' | 'medium' | 'small';
5
+ export type ButtonVariant = 'primary' | 'secondary' | 'flat' | 'destructive';
6
+ export type ButtonAddonPosition = 'start' | 'end';
5
7
  /**
6
8
  * Public Button props.
7
9
  *
@@ -14,38 +16,38 @@ export type ButtonProps = PrimitiveButton.Props & {
14
16
  /**
15
17
  * Controls the visual button size.
16
18
  *
17
- * @default 'medium'
19
+ * @defaultValue 'medium'
18
20
  */
19
21
  size?: ButtonSize;
20
22
  /**
21
23
  * Selects the visual treatment for the button.
22
24
  *
23
- * @default 'primary'
25
+ * @defaultValue 'primary'
24
26
  */
25
27
  variant?: ButtonVariant;
26
28
  /**
27
29
  * Decorative addon rendered alongside the button label.
28
30
  * Pass any React element; use a named icon from `@viraui/icons/react` or `<Chip />` for status chips.
29
31
  *
30
- * @default No default; omit when the button has no addon.
32
+ * @defaultValue undefined
31
33
  */
32
34
  addon?: ReactNode;
33
35
  /**
34
36
  * Controls whether the addon appears before or after the label.
35
37
  *
36
- * @default 'start'
38
+ * @defaultValue 'start'
37
39
  */
38
40
  addonPosition?: ButtonAddonPosition;
39
41
  /**
40
42
  * Shows a centered spinner overlay while preserving the original content width.
41
43
  *
42
- * @default false
44
+ * @defaultValue false
43
45
  */
44
46
  loading?: boolean;
45
47
  /**
46
48
  * Applies a fully rounded pill shape to the button.
47
49
  *
48
- * @default false
50
+ * @defaultValue false
49
51
  */
50
52
  pill?: boolean;
51
53
  };
@@ -1,88 +1,51 @@
1
1
  import './button.css';
2
- import { ButtonChromeChildren, getButtonChromeRootAttrs } from "./button-chrome.js";
3
- import { jsx } from "react/jsx-runtime";
4
- import * as React from "react";
5
- import { useRender } from "@base-ui/react/use-render";
2
+ import { clsx } from "../../core/clsx.js";
3
+ import { Spinner } from "../spinner/spinner.js";
4
+ import button_module_default from "./button.module.js";
5
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
6
+ import "react";
6
7
  import { Button } from "@base-ui/react/button";
7
8
  //#region src/components/button/button.tsx
8
- function usesButtonPrimitiveRender(render) {
9
- return render === void 0 || React.isValidElement(render) && render.type === "button";
10
- }
11
- var ButtonRenderRoot = ({ isDisabled, ref, render, rootProps }) => {
12
- const { onClick, ...restRootProps } = rootProps;
13
- return useRender({
14
- defaultTagName: "button",
15
- render,
16
- ref,
17
- state: { disabled: isDisabled },
18
- props: {
19
- ...restRootProps,
20
- onClick: (event) => {
21
- if (isDisabled) {
22
- event.preventDefault();
23
- return;
24
- }
25
- onClick?.(event);
26
- },
27
- ...isDisabled && { "aria-disabled": true }
28
- }
29
- });
30
- };
31
- var ButtonRoot = ({ children, className, isDisabled, isIconOnly, addon, addonPosition, loading, passThroughProps, pill, ref, render, size, variant }) => {
32
- const chromeAttrs = getButtonChromeRootAttrs({
33
- addon,
34
- addonPosition,
35
- className: typeof className === "string" ? className : void 0,
36
- isDisabled,
37
- isIconOnly,
38
- loading,
39
- pill,
40
- size,
41
- variant
42
- });
43
- const rootProps = {
44
- ...passThroughProps,
45
- ...chromeAttrs,
46
- className: typeof className === "function" ? className : chromeAttrs.className,
47
- children
48
- };
49
- if (usesButtonPrimitiveRender(render)) return /* @__PURE__ */ jsx(Button, {
50
- ...rootProps,
51
- render,
52
- ref,
53
- disabled: isDisabled
54
- });
55
- return /* @__PURE__ */ jsx(ButtonRenderRoot, {
56
- isDisabled,
57
- ref,
58
- render,
59
- rootProps
60
- });
61
- };
62
- var Button$1 = ({ children, className, disabled, addon, addonPosition = "start", loading = false, pill = false, size = "medium", variant = "primary", ...otherProps }) => {
63
- const isDisabled = disabled || loading;
9
+ var Button$1 = ({ children, className, disabled, addon, addonPosition = "start", loading = false, pill = false, size = "medium", variant = "primary", render, ref, ...otherProps }) => {
10
+ const isDisabled = Boolean(disabled || loading);
64
11
  const isIconOnly = Boolean(addon) && (children == null || children === "");
65
- const { render, ref, ...passThroughProps } = otherProps;
66
- return /* @__PURE__ */ jsx(ButtonRoot, {
67
- className,
68
- isDisabled,
69
- isIconOnly,
70
- addon,
71
- addonPosition,
72
- loading,
73
- passThroughProps,
74
- pill,
12
+ const loadingAttr = loading ? "true" : "false";
13
+ const spinnerSize = size === "large" ? "medium" : "small";
14
+ return /* @__PURE__ */ jsxs(Button, {
15
+ ...otherProps,
16
+ "aria-busy": loading || void 0,
17
+ className: typeof className === "function" ? className : clsx(button_module_default.Button, className),
18
+ "data-loading": loadingAttr,
19
+ "data-pill": pill ? "true" : "false",
20
+ "data-size": size,
21
+ "data-icon-only": isIconOnly ? "true" : "false",
22
+ "data-addon-position": addon && !isIconOnly ? addonPosition : void 0,
23
+ "data-variant": variant,
75
24
  ref,
76
25
  render,
77
- size,
78
- variant,
79
- children: /* @__PURE__ */ jsx(ButtonChromeChildren, {
80
- addon,
81
- isIconOnly,
82
- loading,
83
- size,
26
+ disabled: isDisabled,
27
+ children: [isIconOnly ? /* @__PURE__ */ jsx("span", {
28
+ "aria-hidden": "true",
29
+ className: button_module_default.Content,
30
+ "data-loading": loadingAttr,
31
+ children: addon
32
+ }) : /* @__PURE__ */ jsxs(Fragment, { children: [addon && /* @__PURE__ */ jsx("span", {
33
+ "aria-hidden": "true",
34
+ className: button_module_default.Content,
35
+ "data-loading": loadingAttr,
36
+ children: addon
37
+ }), /* @__PURE__ */ jsx("span", {
38
+ className: button_module_default.Content,
39
+ "data-loading": loadingAttr,
84
40
  children
85
- })
41
+ })] }), loading && /* @__PURE__ */ jsx("span", {
42
+ "aria-hidden": "true",
43
+ className: button_module_default.SpinnerOverlay,
44
+ children: /* @__PURE__ */ jsx(Spinner, {
45
+ variant: "dots",
46
+ size: spinnerSize
47
+ })
48
+ })]
86
49
  });
87
50
  };
88
51
  //#endregion
@@ -30,7 +30,7 @@ var DialogSheet = ({ children, description, title, showCloseButton = false, fitC
30
30
  render: /* @__PURE__ */ jsx(Surface, {
31
31
  border: "top",
32
32
  render: /* @__PURE__ */ jsx(Stack, {
33
- fillChildren: true,
33
+ expandChildren: true,
34
34
  hAlign: "center"
35
35
  }),
36
36
  color: 1,
@@ -39,7 +39,7 @@ var DialogSheet = ({ children, description, title, showCloseButton = false, fitC
39
39
  vPadding: ["medium", 0]
40
40
  }),
41
41
  children: [showHandle && /* @__PURE__ */ jsxs(Stack, {
42
- fillChildren: true,
42
+ expandChildren: true,
43
43
  inline: true,
44
44
  direction: "row",
45
45
  vPadding: [0, "medium"],
@@ -50,7 +50,7 @@ var DialogSheet = ({ children, description, title, showCloseButton = false, fitC
50
50
  /* @__PURE__ */ jsx("div", { className: dialog_module_default.HandleShape })
51
51
  ]
52
52
  }), /* @__PURE__ */ jsxs(Stack, {
53
- fillChildren: true,
53
+ expandChildren: true,
54
54
  maxWidth: maxContentWidth,
55
55
  rowGap: "large",
56
56
  className: dialog_module_default.Body,
@@ -9,7 +9,7 @@ var Fieldset$1 = ({ children, className, description, disabled, error, label, ..
9
9
  className,
10
10
  disabled,
11
11
  children: [(label || description || error) && /* @__PURE__ */ jsxs(Stack, {
12
- fillChildren: true,
12
+ expandChildren: true,
13
13
  vPadding: [0, "small"],
14
14
  rowGap: "small",
15
15
  children: [label && /* @__PURE__ */ jsx(Fieldset.Legend, {
@@ -6,6 +6,7 @@ export * from './avatar-group';
6
6
  export * from './badge';
7
7
  export * from './beam';
8
8
  export * from './bleed';
9
+ export * from './breakpoints';
9
10
  export * from './button';
10
11
  export * from './checkbox';
11
12
  export * from './chip';
@@ -17,7 +17,7 @@ var MenuItemRow = ({ addon, children, note, trailing }) => /* @__PURE__ */ jsxs(
17
17
  className: menu_module_default.ItemRow,
18
18
  children: [
19
19
  addon && /* @__PURE__ */ jsx(Stack, {
20
- fillChildren: true,
20
+ expandChildren: true,
21
21
  "aria-hidden": "true",
22
22
  "data-grow": "false",
23
23
  "data-shrink": "false",
@@ -13,7 +13,7 @@ var MenuLinkItem = ({ addon, children, className, note, sentiment, ...otherProps
13
13
  render: /* @__PURE__ */ jsx(Surface, {
14
14
  radius: "auto",
15
15
  render: /* @__PURE__ */ jsx(Stack, {
16
- fillChildren: true,
16
+ expandChildren: true,
17
17
  render: /* @__PURE__ */ jsx("a", {})
18
18
  })
19
19
  }),
@@ -39,7 +39,7 @@ var PopoverSheet = ({ unstyled, title, description, children, showCloseButton =
39
39
  }),
40
40
  children: [
41
41
  /* @__PURE__ */ jsxs(Stack, {
42
- fillChildren: true,
42
+ expandChildren: true,
43
43
  hAlign: headerAlign,
44
44
  rowGap: "small",
45
45
  vAlign: "start",
@@ -16,7 +16,7 @@ function SelectOption({ addon, addonAlign = "center", children, className, indic
16
16
  className: clsx(select_module_default.Option, className),
17
17
  render: /* @__PURE__ */ jsx(Surface, { radius: "auto" }),
18
18
  children: /* @__PURE__ */ jsxs(Stack, {
19
- fillChildren: true,
19
+ expandChildren: true,
20
20
  columnGap: "medium",
21
21
  direction: "row",
22
22
  hPadding: "small",
@@ -27,7 +27,7 @@ function SelectOption({ addon, addonAlign = "center", children, className, indic
27
27
  columnGap: "small",
28
28
  vAlign: addonAlign,
29
29
  children: [addon && /* @__PURE__ */ jsx(Stack, {
30
- fillChildren: true,
30
+ expandChildren: true,
31
31
  "aria-hidden": "true",
32
32
  "data-grow": "false",
33
33
  "data-shrink": "false",
@@ -36,7 +36,7 @@ function SelectRootComponent({ alignListWithTrigger = true, children, className,
36
36
  validationDebounceTime,
37
37
  validationMode,
38
38
  render: /* @__PURE__ */ jsx(Stack, {
39
- fillChildren: true,
39
+ expandChildren: true,
40
40
  rowGap: "small"
41
41
  }),
42
42
  children: [
@@ -56,7 +56,7 @@ function SelectRootComponent({ alignListWithTrigger = true, children, className,
56
56
  disabled,
57
57
  ref,
58
58
  children: /* @__PURE__ */ jsxs(Stack, {
59
- fillChildren: true,
59
+ expandChildren: true,
60
60
  className: select_module_default.Trigger,
61
61
  direction: "row",
62
62
  columnGap: "x-small",
@@ -1 +1 @@
1
- @layer viraui.preflight, viraui.components, viraui.overrides;@layer viraui.components{@property --vui-stack-row-gap{syntax:"<length>";inherits:false;initial-value:0}@property --vui-stack-column-gap{syntax:"<length>";inherits:false;initial-value:0}@property --vui-stack-h-align{syntax:"*";inherits:false;initial-value:initial}@property --vui-stack-v-align{syntax:"*";inherits:false;initial-value:initial}@property --vui-stack-padding-inline-start{syntax:"<length>";inherits:false;initial-value:0}@property --vui-stack-padding-inline-end{syntax:"<length>";inherits:false;initial-value:0}@property --vui-stack-padding-block-start{syntax:"<length>";inherits:false;initial-value:0}@property --vui-stack-padding-block-end{syntax:"<length>";inherits:false;initial-value:0}@property --vui-stack-max-width{syntax:"*";inherits:false;initial-value:none}@property --vui-stack-min-width{syntax:"*";inherits:false;initial-value:none}.viraui__stack-module__Stack_NR-Ey{display:flex;gap:var(--vui-stack-row-gap) var(--vui-stack-column-gap);flex-direction:column;align-items:var(--vui-stack-h-align);justify-content:var(--vui-stack-v-align);max-inline-size:var(--vui-stack-max-width);min-inline-size:var(--vui-stack-min-width);&[data-stack-direction=column-reverse]{flex-direction:column-reverse}&[data-stack-direction=row-reverse],&[data-stack-direction=row]{align-items:var(--vui-stack-v-align);justify-content:var(--vui-stack-h-align)}&[data-stack-direction=row]{flex-direction:row}&[data-stack-direction=row-reverse]{flex-direction:row-reverse}&[data-stack-inline=true]{display:inline-flex;flex-grow:0}:where(&[data-stack-wrap=true]){flex-wrap:wrap}:where(&[data-stack-has-padding=true]){padding:var(--vui-stack-padding-block-start) var(--vui-stack-padding-inline-end) var(--vui-stack-padding-block-end) var(--vui-stack-padding-inline-start)}:where(&[data-stack-fill-children=true]>*){flex-grow:var(--vira-flex-grow,1)}&[data-stack-container=true]{container:stack/inline-size}}}
1
+ @layer viraui.preflight, viraui.components, viraui.overrides;@layer viraui.components{@property --vui-stack-row-gap{syntax:"<length>";inherits:false;initial-value:0}@property --vui-stack-column-gap{syntax:"<length>";inherits:false;initial-value:0}@property --vui-stack-h-align{syntax:"*";inherits:false;initial-value:initial}@property --vui-stack-v-align{syntax:"*";inherits:false;initial-value:initial}@property --vui-stack-padding-inline-start{syntax:"<length>";inherits:false;initial-value:0}@property --vui-stack-padding-inline-end{syntax:"<length>";inherits:false;initial-value:0}@property --vui-stack-padding-block-start{syntax:"<length>";inherits:false;initial-value:0}@property --vui-stack-padding-block-end{syntax:"<length>";inherits:false;initial-value:0}@property --vui-stack-max-width{syntax:"*";inherits:false;initial-value:none}@property --vui-stack-min-width{syntax:"*";inherits:false;initial-value:none}.viraui__stack-module__Stack_NR-Ey{display:flex;gap:var(--vui-stack-row-gap) var(--vui-stack-column-gap);flex-direction:column;align-items:var(--vui-stack-h-align);justify-content:var(--vui-stack-v-align);max-inline-size:var(--vui-stack-max-width);min-inline-size:var(--vui-stack-min-width);&[data-stack-direction=column-reverse]{flex-direction:column-reverse}&[data-stack-direction=row-reverse],&[data-stack-direction=row]{align-items:var(--vui-stack-v-align);justify-content:var(--vui-stack-h-align)}&[data-stack-direction=row]{flex-direction:row}&[data-stack-direction=row-reverse]{flex-direction:row-reverse}&[data-stack-inline=true]{display:inline-flex;flex-grow:0}:where(&[data-stack-wrap=true]){flex-wrap:wrap}:where(&[data-stack-has-padding=true]){padding:var(--vui-stack-padding-block-start) var(--vui-stack-padding-inline-end) var(--vui-stack-padding-block-end) var(--vui-stack-padding-inline-start)}:where(&[data-stack-expand-children=true]>*){flex-grow:var(--vira-flex-grow,1)}&[data-stack-full-width=true]{inline-size:100%}&[data-stack-container=true]{container:stack/inline-size}}}
@@ -44,11 +44,23 @@ export type StackProps = React.ComponentPropsWithoutRef<'div'> & {
44
44
  */
45
45
  wrap?: boolean;
46
46
  /**
47
- * Makes direct children grow to fill the available space within the stack.
47
+ * Makes direct children grow along the flex main axis (`flex-grow`).
48
+ *
49
+ * Does not set the stack root's own inline size — use `fullWidth` when this stack must
50
+ * fill its parent width (e.g. centered shell with `maxWidth`).
51
+ *
52
+ * @default false
53
+ */
54
+ expandChildren?: boolean;
55
+ /**
56
+ * Sets `inline-size: 100%` on the stack root so it fills the parent's inline size.
57
+ *
58
+ * Use with `maxWidth` under a parent `hAlign="center"` for a fluid, capped, centered shell.
59
+ * Orthogonal to `expandChildren` (self size vs children grow).
48
60
  *
49
61
  * @default false
50
62
  */
51
- fillChildren?: boolean;
63
+ fullWidth?: boolean;
52
64
  /**
53
65
  * Sets the gap between flex rows using the Vira space token scale.
54
66
  *
@@ -94,7 +106,7 @@ export type StackProps = React.ComponentPropsWithoutRef<'div'> & {
94
106
  /**
95
107
  * Applies a minimum width value to the stack root.
96
108
  *
97
- * @default No min width constraint.
109
+ * @default No minimum width constraint.
98
110
  */
99
111
  minWidth?: string;
100
112
  /**
@@ -6,11 +6,13 @@
6
6
  "Column or row layouts with token gap and alignment",
7
7
  "Composing screens and component internals without custom flex CSS",
8
8
  "Custom native root through render while keeping data-stack hooks",
9
- "Style descendants with `@container stack` queries when layout, gap, or typography should respond to the Stack's own inline-size instead of the viewport (set `enableContainer` on the Stack you're querying)"
9
+ "Style descendants with `@container stack` queries when layout, gap, or typography should respond to the Stack's own inline-size instead of the viewport (set `enableContainer` on the Stack you're querying)",
10
+ "Centered max-width shells: parent `hAlign=\"center\"` + child `fullWidth` + `maxWidth`"
10
11
  ],
11
12
  "whenNotToUse": [
12
13
  "Cases where a single component already owns required flex chrome",
13
- "Expecting direct children to stretch without setting `fillChildren`",
14
+ "Expecting direct children to grow on the main axis without setting `expandChildren`",
15
+ "Expecting this stack to fill parent inline size under non-stretch alignment without `fullWidth` (or an explicit `inlineSize`)",
14
16
  "Using `enableContainer` inside complex masonry-like layouts when you don't need container queries (inline-size containment can change nested layout)"
15
17
  ],
16
18
  "accessibility": [
@@ -19,10 +21,12 @@
19
21
  "Do not use Stack alone to imply grouping; use landmarks or headings where needed"
20
22
  ],
21
23
  "antiPatterns": [
22
- "Assuming Stack stretches direct children by default — pass `fillChildren` when children should grow along the flex main axis",
23
- "Putting `data-grow=\"false\"` on an ancestor to control nested fillChildren — set it on the child that should not grow",
24
+ "Assuming Stack expands direct children by default — pass `expandChildren` when children should grow along the flex main axis",
25
+ "Using `expandChildren` to fill parent width under `hAlign=\"center\"` — that is `fullWidth` on the child stack (self `inline-size`), not child flex-grow",
26
+ "Putting `data-grow=\"false\"` on an ancestor to control nested expandChildren — set it on the child that should not grow",
24
27
  "Re-declaring primitive flex container rules in app CSS when Stack can own the layout",
25
- "Using viewport media queries when @container stack queries against the rendered Stack inline-size would match the design intent"
28
+ "Using viewport media queries when @container stack queries against the rendered Stack inline-size would match the design intent",
29
+ "Combining `fullWidth` with `inline` — prefer block flex when the root must fill parent inline size"
26
30
  ],
27
31
  "related": ["Surface", "Text", "Button"],
28
32
  "properties": {
@@ -36,8 +40,11 @@
36
40
  "direction": {
37
41
  "description": "Renders children across rows or columns using the chosen flex direction."
38
42
  },
39
- "fillChildren": {
40
- "description": "Makes direct children grow to fill the available space within the stack. Default `false`; opt in when layout needs equal flex growth on direct children. A child opts out with its own `data-grow=\"false\"`; ancestor `data-grow` does not inherit into nested stacks."
43
+ "expandChildren": {
44
+ "description": "Makes direct children grow along the flex main axis (`flex-grow`). Default `false`. Orthogonal to `fullWidth` (children grow vs this root's inline size). A child opts out with its own `data-grow=\"false\"`; ancestor `data-grow` does not inherit into nested stacks."
45
+ },
46
+ "fullWidth": {
47
+ "description": "Sets `inline-size: 100%` on the stack root so it fills the parent's inline size. Default `false`. Use with `maxWidth` under a parent `hAlign=\"center\"` for a fluid capped centered shell. Does not grow children — use `expandChildren` for that."
41
48
  },
42
49
  "hAlign": {
43
50
  "description": "Aligns content on the horizontal axis from the consumer point of view."
@@ -5,7 +5,7 @@ import { resolveAxisPadding } from "../../core/styles/resolve-axis-padding.js";
5
5
  import stack_module_default from "./stack.module.js";
6
6
  import { useRender } from "@base-ui/react/use-render";
7
7
  //#region src/components/stack/stack.tsx
8
- var Stack = ({ className, direction = "column", fillChildren = false, hAlign = "initial", hPadding, inline = false, maxWidth, minWidth, enableContainer, ref, render, rowGap, columnGap, style, vAlign = "initial", vPadding, wrap = false, ...otherProps }) => {
8
+ var Stack = ({ className, direction = "column", expandChildren = false, fullWidth = false, hAlign = "initial", hPadding, inline = false, maxWidth, minWidth, enableContainer, ref, render, rowGap, columnGap, style, vAlign = "initial", vPadding, wrap = false, ...otherProps }) => {
9
9
  const hasPadding = Boolean(hPadding || vPadding);
10
10
  const dynamicStyle = {
11
11
  "--vui-stack-row-gap": resolveThemeValue(rowGap, "space", 0),
@@ -28,7 +28,8 @@ var Stack = ({ className, direction = "column", fillChildren = false, hAlign = "
28
28
  ...enableContainer && { "data-stack-container": "true" },
29
29
  "data-stack-inline": inline ? "true" : "false",
30
30
  "data-stack-wrap": wrap ? "true" : "false",
31
- "data-stack-fill-children": fillChildren ? "true" : "false",
31
+ "data-stack-expand-children": expandChildren ? "true" : "false",
32
+ "data-stack-full-width": fullWidth ? "true" : "false",
32
33
  "data-stack-has-padding": hasPadding ? "true" : "false",
33
34
  className: clsx(stack_module_default.Stack, className),
34
35
  style: dynamicStyle
@@ -22,7 +22,7 @@ var Switch$1 = ({ className, description, dirty, disabled, error, invalid, label
22
22
  validationMode,
23
23
  render: /* @__PURE__ */ jsx(Stack, {
24
24
  direction: "row",
25
- fillChildren: true,
25
+ expandChildren: true,
26
26
  columnGap: size === "small" ? "small" : "medium",
27
27
  vAlign: hasTextDescription ? "start" : "center"
28
28
  }),
@@ -12,21 +12,20 @@ var TabsList = ({ children, className, activateOnFocus = true, ref, ...otherProp
12
12
  render: /* @__PURE__ */ jsx(Surface, {
13
13
  color: 1,
14
14
  border: "all",
15
- hPadding: "2x-small",
16
15
  radius: "medium",
17
16
  vPadding: "2x-small"
18
17
  }),
19
18
  ref,
20
19
  ...otherProps,
21
- children: [/* @__PURE__ */ jsx("div", {
22
- className: tabs_module_default.IndicatorLayer,
23
- children: /* @__PURE__ */ jsx(TabsIndicator, {})
24
- }), /* @__PURE__ */ jsx(Stack, {
25
- fillChildren: true,
26
- direction: "row",
27
- hAlign: "start",
28
- vAlign: "center",
29
- children
20
+ children: [/* @__PURE__ */ jsx(TabsIndicator, {}), /* @__PURE__ */ jsx("div", {
21
+ className: tabs_module_default.Track,
22
+ children: /* @__PURE__ */ jsx(Stack, {
23
+ expandChildren: true,
24
+ direction: "row",
25
+ hAlign: "start",
26
+ vAlign: "center",
27
+ children
28
+ })
30
29
  })]
31
30
  });
32
31
  //#endregion
@@ -1 +1 @@
1
- @layer viraui.preflight, viraui.components, viraui.overrides;@layer viraui.components{@property --vui-tabs-translate-amount{syntax:"<length>";inherits:true;initial-value:10px}.viraui__tabs-module__Tabs_AwbZZ{min-block-size:10rem}.viraui__tabs-module__Viewport_15X1I{display:grid;grid-template-columns:minmax(0,1fr);inline-size:100%}.viraui__tabs-module__Panel_vkCFI{grid-area:1/1;inline-size:100%;opacity:1;translate:0 0;transition:opacity var(--duration-fast) var(--easing-entrance),translate var(--duration-fast) var(--easing-entrance);&[data-ending-style]{pointer-events:none}&[data-ending-style],&[data-starting-style]{opacity:0}&[data-activation-direction=right][data-starting-style]{translate:var(--vui-tabs-translate-amount) 0}&[data-activation-direction=left][data-starting-style],&[data-activation-direction=right][data-ending-style]{translate:calc(var(--vui-tabs-translate-amount) * -1) 0}&[data-activation-direction=left][data-ending-style]{translate:var(--vui-tabs-translate-amount) 0}&[data-activation-direction=none][data-ending-style],&[data-activation-direction=none][data-starting-style]{translate:0 var(--vui-tabs-translate-amount)}&[hidden]{display:none}@media (prefers-reduced-motion:reduce){&[data-ending-style],&[data-starting-style]{opacity:1;translate:0 0}}}}@layer viraui.overrides{.viraui__tabs-module__List_XJorr{position:relative;max-inline-size:100%;min-inline-size:0;overflow-x:auto;overflow-y:clip}.viraui__tabs-module__IndicatorLayer_Ek8o3{position:absolute;inset:0;overflow:clip;pointer-events:none}.viraui__tabs-module__Indicator_UyNUn{position:absolute;pointer-events:none;inset-block-start:var(--active-tab-top);inset-inline-start:var(--active-tab-left);inline-size:var(--active-tab-width);block-size:var(--active-tab-height);transition:inset-inline-start var(--duration-fast) var(--easing-standard),inset-block-start var(--duration-fast) var(--easing-standard),inline-size var(--duration-fast) var(--easing-standard),block-size var(--duration-fast) var(--easing-standard)}.viraui__tabs-module__Item_XZ86Z{position:relative;flex-shrink:0;cursor:pointer;flex-basis:0;transition:none;will-change:auto;&[data-variant]:not(:disabled):active{translate:0 0}&:hover{background:#0000}&[data-disabled]{opacity:.5;background:#0000}&[data-active]{color:var(--global-foreground)}&:focus-visible{border-radius:var(--radius-small);outline-offset:0}}.viraui__tabs-module__Item_XZ86Z[data-active] .viraui__tabs-module__Label_5-8-Y{color:var(--global-foreground)}}
1
+ @layer viraui.preflight, viraui.components, viraui.overrides;@layer viraui.components{@property --vui-tabs-translate-amount{syntax:"<length>";inherits:true;initial-value:10px}.viraui__tabs-module__Tabs_AwbZZ{min-block-size:10rem}.viraui__tabs-module__Viewport_15X1I{display:grid;grid-template-columns:minmax(0,1fr);inline-size:100%}.viraui__tabs-module__Panel_vkCFI{grid-area:1/1;inline-size:100%;opacity:1;translate:0 0;transition:opacity var(--duration-fast) var(--easing-entrance),translate var(--duration-fast) var(--easing-entrance);&[data-ending-style]{pointer-events:none}&[data-ending-style],&[data-starting-style]{opacity:0}&[data-activation-direction=right][data-starting-style]{translate:var(--vui-tabs-translate-amount) 0}&[data-activation-direction=left][data-starting-style],&[data-activation-direction=right][data-ending-style]{translate:calc(var(--vui-tabs-translate-amount) * -1) 0}&[data-activation-direction=left][data-ending-style]{translate:var(--vui-tabs-translate-amount) 0}&[data-activation-direction=none][data-ending-style],&[data-activation-direction=none][data-starting-style]{translate:0 var(--vui-tabs-translate-amount)}&[hidden]{display:none}@media (prefers-reduced-motion:reduce){&[data-ending-style],&[data-starting-style]{opacity:1;translate:0 0}}}}@layer viraui.overrides{.viraui__tabs-module__List_XJorr{position:relative;max-inline-size:100%;overflow-x:auto;overflow-y:clip}.viraui__tabs-module__Track_Fet4f{display:inline-flex;min-inline-size:100%;box-sizing:border-box;padding-inline:var(--space-2x-small)}.viraui__tabs-module__Indicator_UyNUn{position:absolute;pointer-events:none;inset-block-start:0;inset-inline-start:0;inline-size:var(--active-tab-width);block-size:round(nearest,var(--active-tab-height),2px);translate:var(--active-tab-left) calc(var(--active-tab-top) + (var(--active-tab-height) - round(nearest, var(--active-tab-height), 2px)) / 2);transition:translate var(--duration-fast) var(--easing-standard),inline-size var(--duration-fast) var(--easing-standard),block-size var(--duration-fast) var(--easing-standard)}.viraui__tabs-module__Item_XZ86Z{position:relative;flex-shrink:0;cursor:pointer;flex-basis:0;transition:none;will-change:auto;&[data-variant]:not(:disabled):active{translate:0 0}&:hover{background:#0000}&[data-disabled]{opacity:.5;background:#0000}&[data-active] .viraui__tabs-module__Label_5-8-Y{color:var(--global-foreground)}&:focus-visible{border-radius:var(--radius-small);outline-offset:-2px}}}
@@ -3,7 +3,7 @@ var Tabs = "viraui__tabs-module__Tabs_AwbZZ";
3
3
  var Viewport = "viraui__tabs-module__Viewport_15X1I";
4
4
  var Panel = "viraui__tabs-module__Panel_vkCFI";
5
5
  var List = "viraui__tabs-module__List_XJorr";
6
- var IndicatorLayer = "viraui__tabs-module__IndicatorLayer_Ek8o3";
6
+ var Track = "viraui__tabs-module__Track_Fet4f";
7
7
  var Indicator = "viraui__tabs-module__Indicator_UyNUn";
8
8
  var Item = "viraui__tabs-module__Item_XZ86Z";
9
9
  var Label = "viraui__tabs-module__Label_5-8-Y";
@@ -12,10 +12,10 @@ var tabs_module_default = {
12
12
  Viewport,
13
13
  Panel,
14
14
  List,
15
- IndicatorLayer,
15
+ Track,
16
16
  Indicator,
17
17
  Item,
18
18
  Label
19
19
  };
20
20
  //#endregion
21
- export { Indicator, IndicatorLayer, Item, Label, List, Panel, Tabs, Viewport, tabs_module_default as default };
21
+ export { Indicator, Item, Label, List, Panel, Tabs, Track, Viewport, tabs_module_default as default };
@@ -19,7 +19,7 @@ var Textarea = ({ className, description, dirty, disabled, error, fitContent, in
19
19
  validationDebounceTime,
20
20
  validationMode,
21
21
  render: /* @__PURE__ */ jsx(Stack, {
22
- fillChildren: true,
22
+ expandChildren: true,
23
23
  rowGap: "small"
24
24
  }),
25
25
  children: [
@@ -22,7 +22,7 @@ var Textfield = ({ className, description, dirty, disabled, endAddon, error, fit
22
22
  validationMode,
23
23
  "data-fullwidth": fullWidth,
24
24
  render: /* @__PURE__ */ jsx(Stack, {
25
- fillChildren: true,
25
+ expandChildren: true,
26
26
  rowGap: "small"
27
27
  }),
28
28
  children: [
package/dist/index.js CHANGED
@@ -8,6 +8,8 @@ import { AvatarGroup } from "./components/avatar-group/avatar-group.js";
8
8
  import { Badge } from "./components/badge/badge.js";
9
9
  import { Beam } from "./components/beam/beam.js";
10
10
  import { Bleed } from "./components/bleed/bleed.js";
11
+ import { BreakpointsProvider } from "./components/breakpoints/breakpoints-provider.js";
12
+ import { useBreakpoints } from "./components/breakpoints/use-breakpoints.js";
11
13
  import { Spinner } from "./components/spinner/spinner.js";
12
14
  import { Button } from "./components/button/button.js";
13
15
  import { ButtonLink } from "./components/button/button-link.js";
@@ -66,4 +68,4 @@ import { ToggleGroup } from "./components/toggle-group/toggle-group.js";
66
68
  import { Typewriter } from "./components/typewriter/typewriter.js";
67
69
  import { TooltipContent } from "./components/tooltip/tooltip-content.js";
68
70
  import { Tooltip, TooltipProvider, TooltipTrigger } from "./components/tooltip/tooltip.js";
69
- export { Accordion, Annotate, Autocomplete, Avatar, AvatarGroup, Badge, Beam, Bleed, Button, ButtonLink, Checkbox, CheckboxGroup, Chip, ClampText, Dialog, DialogClose, DialogIndent, DialogIndentBackground, DialogSheet, DialogTrigger, ELEVATION_DEFAULTS, Elevator, Fieldset, FitText, Glow, Grid, IconButton, IconButtonLink, LinearProgress, Masonry, Menu, MenuCheckboxItem, MenuGroup, MenuItem, MenuLinkItem, MenuPopup, MenuRadioGroup, MenuRadioItem, MenuSeparator, MenuSubmenu, MenuSubmenuTrigger, MenuTrigger, Meter, Popover, PopoverClose, PopoverDescription, PopoverSheet, PopoverTitle, PopoverTrigger, ProgressiveBlur, Radio, RadioGroup, Select, Separator, Shimmer, Skeleton, Slider, Spinner, Stack, StaticNoise, Surface, Switch, Tabs, Text, Textarea, Textfield, Title, Toast, ToggleButton, ToggleGroup, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, Typewriter, getElevationProps };
71
+ export { Accordion, Annotate, Autocomplete, Avatar, AvatarGroup, Badge, Beam, Bleed, BreakpointsProvider, Button, ButtonLink, Checkbox, CheckboxGroup, Chip, ClampText, Dialog, DialogClose, DialogIndent, DialogIndentBackground, DialogSheet, DialogTrigger, ELEVATION_DEFAULTS, Elevator, Fieldset, FitText, Glow, Grid, IconButton, IconButtonLink, LinearProgress, Masonry, Menu, MenuCheckboxItem, MenuGroup, MenuItem, MenuLinkItem, MenuPopup, MenuRadioGroup, MenuRadioItem, MenuSeparator, MenuSubmenu, MenuSubmenuTrigger, MenuTrigger, Meter, Popover, PopoverClose, PopoverDescription, PopoverSheet, PopoverTitle, PopoverTrigger, ProgressiveBlur, Radio, RadioGroup, Select, Separator, Shimmer, Skeleton, Slider, Spinner, Stack, StaticNoise, Surface, Switch, Tabs, Text, Textarea, Textfield, Title, Toast, ToggleButton, ToggleGroup, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, Typewriter, getElevationProps, useBreakpoints };
@@ -114,14 +114,14 @@
114
114
  "module": "layout",
115
115
  "values": ["true", "false"],
116
116
  "presence": "optional; omit for default flex growth",
117
- "effect": "Affects only the element: true sets --vira-flex-grow: 1 and flex-grow: 1; false sets --vira-flex-grow: 0 and flex-grow: 0. Custom props are registered inherits: false so ancestors do not poison nested Stack fillChildren.",
117
+ "effect": "Affects only the element: true sets --vira-flex-grow: 1 and flex-grow: 1; false sets --vira-flex-grow: 0 and flex-grow: 0. Custom props are registered inherits: false so ancestors do not poison nested Stack expandChildren.",
118
118
  "whenToUse": [
119
- "Force grow or opt out on a fillChildren direct child",
119
+ "Force grow or opt out on an expandChildren direct child",
120
120
  "Fixed-width icons, indicators, or trailing slots (false)"
121
121
  ],
122
122
  "whenNotToUse": [
123
123
  "When default flex growth is already correct",
124
- "Expecting ancestor data-grow to change nested fillChildren children"
124
+ "Expecting ancestor data-grow to change nested expandChildren children"
125
125
  ],
126
126
  "related": ["Stack", "--vira-flex-grow"]
127
127
  },
@@ -198,8 +198,8 @@
198
198
  "name": "--vira-flex-grow",
199
199
  "module": "layout",
200
200
  "setBy": "data-grow=\"true\" or data-grow=\"false\"; registered in global-properties.css",
201
- "default": "1 (initial-value); inherits: false; Stack fillChildren uses var(--vira-flex-grow, 1)",
202
- "purpose": "Local grow signal for Stack fillChildren / child flex defaults; does not inherit so ancestor data-grow cannot poison nested stacks."
201
+ "default": "1 (initial-value); inherits: false; Stack expandChildren uses var(--vira-flex-grow, 1)",
202
+ "purpose": "Local grow signal for Stack expandChildren / child flex defaults; does not inherit so ancestor data-grow cannot poison nested stacks."
203
203
  },
204
204
  {
205
205
  "name": "--vira-flex-shrink",
@@ -216,7 +216,7 @@
216
216
  "Inventing backdrop-filter CSS instead of data-vibrant when vibrancy is desired",
217
217
  "Inventing box-shadow CSS instead of data-elevation when theme-gated shadows are desired",
218
218
  "Shipping a new consumer-facing data-* without updating preflight-surface.json and viraui-design/custom-attributes.md",
219
- "Relying on ancestor data-grow / data-shrink to control nested Stack fillChildren (props do not inherit)"
219
+ "Relying on ancestor data-grow / data-shrink to control nested Stack expandChildren (props do not inherit)"
220
220
  ],
221
221
  "discovery": {
222
222
  "consumption": "@viraui/react/consumption.json",
@@ -1 +1 @@
1
- @layer viraui.preflight, viraui.components, viraui.overrides;@layer viraui.preflight{@property --scrollbar-thumb{syntax:"<color>";initial-value:#0000;inherits:true}@property --scrollbar-track{syntax:"<color>";initial-value:#0000;inherits:true}@property --outline-offset{syntax:"<length>";initial-value:2px;inherits:true}@property --outline-color{syntax:"<color>";initial-value:currentcolor;inherits:true}@property --outline{syntax:"*";initial-value:2px solid currentcolor;inherits:true}@property --is-light-mode{syntax:"<color>";initial-value:#000;inherits:true}@property --vira-flex-grow{syntax:"<number>";initial-value:1;inherits:false}@property --vira-flex-shrink{syntax:"<number>";initial-value:1;inherits:false}}@layer viraui.preflight{html{--scrollbar-thumb:oklab(from var(--global-contrast) l a b / 0.3);--scrollbar-track:#0000;--outline-offset:2px;--outline-color:var(--global-outline);--outline:2px solid var(--outline-color);--is-light-mode:contrast-color(var(--global-background));font-size:var(--font-root-size);box-sizing:border-box;line-height:1.5;background-color:var(--global-background);color:var(--global-foreground);container:root/normal}*,:after,:before{margin:0;box-sizing:inherit;scrollbar-width:thin;scrollbar-color:var(--scrollbar-thumb) var(--scrollbar-track);@container root not style(--effect-corner-shape: initial){corner-shape:var(--corner-shape)}@media (prefers-reduced-motion:reduce){animation:none!important;transition:none!important}}:focus-visible{outline:var(--outline);outline-offset:var(--outline-offset)}body{color:var(--global-foreground);margin:0;font-size:var(--font-scale-body-medium);font-optical-sizing:auto;font-family:var(--font-family-body),system-ui,sans-serif;font-variation-settings:"wght" 400;font-variant-numeric:tabular-nums;@container root not style(--effect-holofoil: initial){&:after{content:"";position:fixed;inset:0;z-index:999;background-color:#99ffd8;pointer-events:none;mix-blend-mode:multiply;contain:strict;isolation:isolate;opacity:25%;background-image:radial-gradient(at 79% 56%,#70ade6 0,#0000 50%),radial-gradient(at 61% 80%,#ee909e 0,#0000 50%),radial-gradient(at 0 63%,#fdbc68 0,#0000 50%),radial-gradient(at 6% 50%,#e5cb8a 0,#0000 50%),radial-gradient(at 23% 10%,#e5db8f 0,#0000 50%),radial-gradient(at 36% 91%,#a0eea8 0,#0000 50%),radial-gradient(at 2% 80%,#e3a47d 0,#0000 50%);@container root style(--is-light-mode: white){mix-blend-mode:color;opacity:15%}}}}::selection{background-color:var(--global-primary);color:contrast-color(var(--global-primary));text-shadow:none}img{display:block;inline-size:100%;max-inline-size:100%}svg{display:inline-flex;vertical-align:middle;&:not([fill]){fill:currentcolor}}ol ul,ul ol{font-size:medium}table{border-spacing:0;inline-size:100%;border-collapse:collapse}table[data-layout-fixed]{table-layout:fixed}table thead{box-shadow:inset 0 -3px 0 var(--base-2)}table[data-table-separators] tr+tr{border-top:1px solid var(--base-2)}table th{white-space:nowrap;font-variation-settings:"wght" 800}table :is(td,th){border:none;text-align:left;font-size:medium;padding:calc(var(--space-x-small) + var(--space-2x-small)) var(--space-small)}button,fieldset{padding:0;margin:0;border:0}button{appearance:none;background:none;font-size:inherit;font-family:inherit;display:inline-flex;cursor:pointer;color:inherit}}@layer viraui.preflight{@container root not style(--effect-shadows: initial){[data-elevation]{--shadow-direction:1;--shadow-opacity-factor:0.16;--extra-shadow:0 0 0 1px #0000;--shadow-color:oklch(0% 0 0);transition-property:box-shadow;transition-duration:var(--elevation-transition-duration,.16s);transition-timing-function:var(--elevation-transition-easing,ease)}[data-elevation]:where([data-elevation-direction=bottom],[data-elevation-direction=right]){--shadow-direction:1}[data-elevation]:where([data-elevation-direction=top],[data-elevation-direction=left]){--shadow-direction:-1}[data-elevation-hover="0"]:hover,[data-elevation="0"]{--y1:0px;--x1:0px;box-shadow:calc(var(--x1) * var(--shadow-direction)) calc(var(--y1) * var(--shadow-direction)) 0 oklch(from var(--shadow-color) l c h/var(--shadow-opacity-factor)),0 0 0 color-mix(in oklch,var(--shadow-color),#0000 calc(94% - var(--shadow-opacity-factor))),0 0 0 oklch(from var(--shadow-color) l c h/var(--shadow-opacity-factor)),var(--extra-shadow)}[data-elevation-hover="1"]:hover,[data-elevation-hover="2"]:hover,[data-elevation-hover="3"]:hover,[data-elevation-hover="4"]:hover,[data-elevation="1"],[data-elevation="2"],[data-elevation="3"],[data-elevation="4"]{box-shadow:calc(var(--x1) * var(--shadow-direction)) calc(var(--y1) * var(--shadow-direction)) var(--shadow-blur-1) oklab(from var(--shadow-color) l a b/.1),calc(var(--x2) * var(--shadow-direction)) calc(var(--y2) * var(--shadow-direction)) var(--shadow-blur-2) oklab(from var(--shadow-color) l a b/.09),calc(var(--x3) * var(--shadow-direction)) calc(var(--y3) * var(--shadow-direction)) var(--shadow-blur-3) oklab(from var(--shadow-color) l a b/.05),calc(var(--x4) * var(--shadow-direction)) calc(var(--y4) * var(--shadow-direction)) var(--shadow-blur-4) oklab(from var(--shadow-color) l a b/.01),var(--extra-shadow)}[data-elevation-hover="1"]:hover,[data-elevation="1"]{--y1:0px;--y2:2px;--y3:4px;--y4:7px;--x1:0px;--x2:0px;--x3:0px;--x4:0px;--shadow-blur-1:1px;--shadow-blur-2:2px;--shadow-blur-3:2px;--shadow-blur-4:3px}[data-elevation-hover="1"]:where([data-elevation-direction=left],[data-elevation-direction=right]):hover,[data-elevation="1"]:where([data-elevation-direction=left],[data-elevation-direction=right]){--y1:0px;--y2:0px;--y3:0px;--y4:0px;--x1:0px;--x2:2px;--x3:4px;--x4:7px}[data-elevation-hover="2"]:hover,[data-elevation="2"]{--y1:1px;--y2:5px;--y3:11px;--y4:19px;--x1:0px;--x2:0px;--x3:0px;--x4:0px;--shadow-blur-1:3px;--shadow-blur-2:5px;--shadow-blur-3:6px;--shadow-blur-4:8px}[data-elevation-hover="2"]:where([data-elevation-direction=top],[data-elevation-direction=left]):hover,[data-elevation="2"]:where([data-elevation-direction=top],[data-elevation-direction=left]){--shadow-blur-3:7px}[data-elevation-hover="2"]:where([data-elevation-direction=left],[data-elevation-direction=right]):hover,[data-elevation="2"]:where([data-elevation-direction=left],[data-elevation-direction=right]){--y1:0px;--y2:0px;--y3:0px;--y4:0px;--x1:1px;--x2:5px;--x3:11px;--x4:19px}[data-elevation-hover="2"]:where([data-elevation-direction=right]):hover,[data-elevation="2"]:where([data-elevation-direction=right]){--shadow-blur-3:6px}[data-elevation-hover="3"]:hover,[data-elevation="3"]{--y1:2px;--y2:7px;--y3:16px;--y4:29px;--x1:0px;--x2:0px;--x3:0px;--x4:0px;--shadow-blur-1:4px;--shadow-blur-2:7px;--shadow-blur-3:10px;--shadow-blur-4:12px}[data-elevation-hover="3"]:where([data-elevation-direction=left],[data-elevation-direction=right]):hover,[data-elevation="3"]:where([data-elevation-direction=left],[data-elevation-direction=right]){--y1:0px;--y2:0px;--y3:0px;--y4:0px;--x1:2px;--x2:7px;--x3:16px;--x4:29px}[data-elevation-hover="3"]:where([data-elevation-direction=right]):hover,[data-elevation="3"]:where([data-elevation-direction=right]){--x2:10px;--x3:22px;--x4:39px;--shadow-blur-1:5px;--shadow-blur-2:10px;--shadow-blur-3:13px;--shadow-blur-4:15px}[data-elevation-hover="4"]:hover,[data-elevation="4"]{--y1:4px;--y2:14px;--y3:33px;--y4:58px;--x1:0px;--x2:0px;--x3:0px;--x4:0px;--shadow-blur-1:8px;--shadow-blur-2:14px;--shadow-blur-3:20px;--shadow-blur-4:23px}[data-elevation-hover="4"]:where([data-elevation-direction=top]):hover,[data-elevation="4"]:where([data-elevation-direction=top]){--y2:15px;--shadow-blur-2:15px}[data-elevation-hover="4"]:where([data-elevation-direction=left]):hover,[data-elevation="4"]:where([data-elevation-direction=left]){--y1:0px;--y2:0px;--y3:0px;--y4:0px;--x1:4px;--x2:15px;--x3:33px;--x4:58px;--shadow-blur-2:15px}[data-elevation-hover="4"]:where([data-elevation-direction=right]):hover,[data-elevation="4"]:where([data-elevation-direction=right]){--y1:0px;--y2:0px;--y3:0px;--y4:0px;--x1:4px;--x2:14px;--x3:33px;--x4:58px}}}@layer viraui.preflight{[data-grow=true]{--vira-flex-grow:1;flex-grow:1}[data-grow=false]{--vira-flex-grow:0;flex-grow:0}[data-shrink=true]{--vira-flex-shrink:1;flex-shrink:1}[data-shrink=false]{--vira-flex-shrink:0;flex-shrink:0}}@layer viraui.preflight{:where(p){line-height:1.5;min-block-size:.01vh;font-size:var(--font-scale-body-medium)}small{font-size:.7em}b,strong{font-variation-settings:"wght" 700}:where(a:any-link):not([data-no-link-style]){text-decoration:none;color:var(--global-interactive-text);word-break:break-word;&:not([class]){background:linear-gradient(currentcolor,currentcolor) no-repeat 0 100%;background-size:0 1px;transition:background-size var(--duration-fast) var(--easing-entrance);&:focus,&:hover{background-size:100% 1px}}}del{padding:0 .4em;margin:0 .2em;background-color:oklab(from var(--highlight-red) l a b/12%);color:var(--highlight-red);box-shadow:0 0 0 1px oklab(from var(--highlight-red) l a b/50%);border-radius:var(--radius-small)}ins{background-color:oklab(from var(--highlight-green) l a b/15%);color:var(--highlight-green);box-shadow:0 0 0 1px oklab(from var(--highlight-green) l a b/50%)}ins,mark{padding:0 .4em;margin:0 .2em;text-decoration:none;border-radius:var(--radius-small)}mark{background-color:oklab(from var(--highlight-yellow) l a b/15%);color:var(--highlight-yellow);box-shadow:0 0 0 1px oklab(from var(--highlight-yellow) l a b/50%)}address{font-style:normal;line-height:inherit}dt{font-variation-settings:"wght" 600}dd{margin:0;padding:0}ul{font-size:medium;padding-left:1rem;& li::marker{font-size:inherit;text-align:right;font-variation-settings:"wght" 400;min-inline-size:var(--space-x-large);color:oklab(from currentColor l a b/80%)}}ol{font-size:medium;& li::marker{font-size:inherit;font-variation-settings:"wght" 400;min-inline-size:var(--space-x-large);font-variant-numeric:tabular-nums;white-space:nowrap;color:oklab(from currentColor l a b/80%)}}kbd{padding:.2em .4em;border-radius:var(--radius-small);font-variation-settings:"wght" 600;box-shadow:var(--global-contrast);background:var(--global-contrast)}abbr{text-decoration:underline dashed var(--global-primary)}label,legend{font-size:inherit}code{font-size:1em;font-family:var(--font-family-mono);&:not(:where(pre &)){background-color:var(--global-contrast);border-radius:var(--radius-small);box-shadow:var(--global-contrast);padding:.2em .4em}}pre code{box-shadow:none}s{text-decoration:line-through;color:var(--global-disabled-foreground);text-decoration-color:oklab(from var(--global-foreground) l a b/50%)}:root{color-scheme:light dark}[data-mode=dark]{color:var(--global-foreground);color-scheme:dark}[data-mode=light]{color:var(--global-foreground);color-scheme:light}}@layer viraui.preflight{[data-mode=inverted]{color:var(--global-foreground);@container root style(--is-light-mode: black){color-scheme:dark}@container root style(--is-light-mode: white){color-scheme:light}}}@layer viraui.preflight{@container root not style(--effect-vibrancy: initial){[data-vibrant]{backdrop-filter:brightness(var(--vibrancy-brightness)) blur(calc(var(--vibrancy-blur) * 1px)) saturate(150%);@container root style(--is-light-mode: black){backdrop-filter:brightness(100%) blur(calc(var(--vibrancy-blur) * 1px)) saturate(150%)}}}}
1
+ @layer viraui.preflight, viraui.components, viraui.overrides;@layer viraui.preflight{@property --scrollbar-thumb{syntax:"<color>";initial-value:#0000;inherits:true}@property --scrollbar-track{syntax:"<color>";initial-value:#0000;inherits:true}@property --outline-offset{syntax:"<length>";initial-value:2px;inherits:true}@property --outline-color{syntax:"<color>";initial-value:currentcolor;inherits:true}@property --outline{syntax:"*";initial-value:2px solid currentcolor;inherits:true}@property --is-light-mode{syntax:"<color>";initial-value:#000;inherits:true}@property --vira-flex-grow{syntax:"<number>";initial-value:1;inherits:false}@property --vira-flex-shrink{syntax:"<number>";initial-value:1;inherits:false}}@layer viraui.preflight{html{--scrollbar-thumb:oklab(from var(--global-contrast) l a b / 0.3);--scrollbar-track:#0000;--outline-offset:2px;--outline-color:var(--global-outline);--outline:2px solid var(--outline-color);--is-light-mode:contrast-color(var(--global-background));font-size:var(--font-root-size);box-sizing:border-box;line-height:1.5;background-color:var(--global-background);color:var(--global-foreground);container:root/normal}*,:after,:before{margin:0;box-sizing:inherit;scrollbar-width:thin;scrollbar-color:var(--scrollbar-thumb) var(--scrollbar-track);@container root not style(--effect-corner-shape: initial){corner-shape:var(--corner-shape)}@media (prefers-reduced-motion:reduce){animation:none!important;transition:none!important}}:focus-visible{outline:var(--outline);outline-offset:var(--outline-offset)}body{color:var(--global-foreground);margin:0;font-size:var(--font-scale-body-medium);font-optical-sizing:auto;font-family:var(--font-family-body),system-ui,sans-serif;font-variation-settings:"wght" 400;font-variant-numeric:tabular-nums;@container root not style(--effect-holofoil: initial){&:after{content:"";position:fixed;inset:0;z-index:999;background-color:#99ffd8;pointer-events:none;mix-blend-mode:multiply;contain:strict;isolation:isolate;opacity:25%;background-image:radial-gradient(at 79% 56%,#70ade6 0,#0000 50%),radial-gradient(at 61% 80%,#ee909e 0,#0000 50%),radial-gradient(at 0 63%,#fdbc68 0,#0000 50%),radial-gradient(at 6% 50%,#e5cb8a 0,#0000 50%),radial-gradient(at 23% 10%,#e5db8f 0,#0000 50%),radial-gradient(at 36% 91%,#a0eea8 0,#0000 50%),radial-gradient(at 2% 80%,#e3a47d 0,#0000 50%);@container root style(--is-light-mode: white){mix-blend-mode:color;opacity:15%}}}}::selection{background-color:var(--global-primary);color:contrast-color(var(--global-primary));text-shadow:none}img{display:block;inline-size:100%;max-inline-size:100%}svg{display:inline-flex;vertical-align:middle;&:not([fill]){fill:currentcolor}}ol ul,ul ol{font-size:medium}table{border-spacing:0;inline-size:100%;border-collapse:collapse}table[data-layout-fixed]{table-layout:fixed}table thead{box-shadow:inset 0 -3px 0 var(--base-2)}table[data-table-separators] tr+tr{border-top:1px solid var(--base-2)}table th{white-space:nowrap;font-variation-settings:"wght" 800}table :is(td,th){border:none;text-align:left;font-size:medium;padding:calc(var(--space-x-small) + var(--space-2x-small)) var(--space-small)}button,fieldset{padding:0;margin:0;border:0}button{appearance:none;background:none;font-size:inherit;font-family:inherit;display:inline-flex;cursor:pointer;color:inherit}}@layer viraui.preflight{@container root not style(--effect-shadows: initial){[data-elevation]{--shadow-direction:1;--shadow-opacity-factor:0.16;--extra-shadow:0 0 0 1px #0000;--shadow-color:oklch(0% 0 0);transition-property:box-shadow;transition-duration:var(--elevation-transition-duration,.16s);transition-timing-function:var(--elevation-transition-easing,ease)}[data-elevation]:where([data-elevation-direction=bottom],[data-elevation-direction=right]){--shadow-direction:1}[data-elevation]:where([data-elevation-direction=top],[data-elevation-direction=left]){--shadow-direction:-1}[data-elevation-hover="0"]:hover,[data-elevation="0"]{--y1:0px;--x1:0px;box-shadow:calc(var(--x1) * var(--shadow-direction)) calc(var(--y1) * var(--shadow-direction)) 0 oklch(from var(--shadow-color) l c h/var(--shadow-opacity-factor)),0 0 0 color-mix(in oklch,var(--shadow-color),#0000 calc(94% - var(--shadow-opacity-factor))),0 0 0 oklch(from var(--shadow-color) l c h/var(--shadow-opacity-factor)),var(--extra-shadow)}[data-elevation-hover="1"]:hover,[data-elevation-hover="2"]:hover,[data-elevation-hover="3"]:hover,[data-elevation-hover="4"]:hover,[data-elevation="1"],[data-elevation="2"],[data-elevation="3"],[data-elevation="4"]{box-shadow:calc(var(--x1) * var(--shadow-direction)) calc(var(--y1) * var(--shadow-direction)) var(--shadow-blur-1) oklab(from var(--shadow-color) l a b/.1),calc(var(--x2) * var(--shadow-direction)) calc(var(--y2) * var(--shadow-direction)) var(--shadow-blur-2) oklab(from var(--shadow-color) l a b/.09),calc(var(--x3) * var(--shadow-direction)) calc(var(--y3) * var(--shadow-direction)) var(--shadow-blur-3) oklab(from var(--shadow-color) l a b/.05),calc(var(--x4) * var(--shadow-direction)) calc(var(--y4) * var(--shadow-direction)) var(--shadow-blur-4) oklab(from var(--shadow-color) l a b/.01),var(--extra-shadow)}[data-elevation-hover="1"]:hover,[data-elevation="1"]{--y1:0px;--y2:2px;--y3:4px;--y4:7px;--x1:0px;--x2:0px;--x3:0px;--x4:0px;--shadow-blur-1:1px;--shadow-blur-2:2px;--shadow-blur-3:2px;--shadow-blur-4:3px}[data-elevation-hover="1"]:where([data-elevation-direction=left],[data-elevation-direction=right]):hover,[data-elevation="1"]:where([data-elevation-direction=left],[data-elevation-direction=right]){--y1:0px;--y2:0px;--y3:0px;--y4:0px;--x1:0px;--x2:2px;--x3:4px;--x4:7px}[data-elevation-hover="2"]:hover,[data-elevation="2"]{--y1:1px;--y2:5px;--y3:11px;--y4:19px;--x1:0px;--x2:0px;--x3:0px;--x4:0px;--shadow-blur-1:3px;--shadow-blur-2:5px;--shadow-blur-3:6px;--shadow-blur-4:8px}[data-elevation-hover="2"]:where([data-elevation-direction=top],[data-elevation-direction=left]):hover,[data-elevation="2"]:where([data-elevation-direction=top],[data-elevation-direction=left]){--shadow-blur-3:7px}[data-elevation-hover="2"]:where([data-elevation-direction=left],[data-elevation-direction=right]):hover,[data-elevation="2"]:where([data-elevation-direction=left],[data-elevation-direction=right]){--y1:0px;--y2:0px;--y3:0px;--y4:0px;--x1:1px;--x2:5px;--x3:11px;--x4:19px}[data-elevation-hover="2"]:where([data-elevation-direction=right]):hover,[data-elevation="2"]:where([data-elevation-direction=right]){--shadow-blur-3:6px}[data-elevation-hover="3"]:hover,[data-elevation="3"]{--y1:2px;--y2:7px;--y3:16px;--y4:29px;--x1:0px;--x2:0px;--x3:0px;--x4:0px;--shadow-blur-1:4px;--shadow-blur-2:7px;--shadow-blur-3:10px;--shadow-blur-4:12px}[data-elevation-hover="3"]:where([data-elevation-direction=left],[data-elevation-direction=right]):hover,[data-elevation="3"]:where([data-elevation-direction=left],[data-elevation-direction=right]){--y1:0px;--y2:0px;--y3:0px;--y4:0px;--x1:2px;--x2:7px;--x3:16px;--x4:29px}[data-elevation-hover="3"]:where([data-elevation-direction=right]):hover,[data-elevation="3"]:where([data-elevation-direction=right]){--x2:10px;--x3:22px;--x4:39px;--shadow-blur-1:5px;--shadow-blur-2:10px;--shadow-blur-3:13px;--shadow-blur-4:15px}[data-elevation-hover="4"]:hover,[data-elevation="4"]{--y1:4px;--y2:14px;--y3:33px;--y4:58px;--x1:0px;--x2:0px;--x3:0px;--x4:0px;--shadow-blur-1:8px;--shadow-blur-2:14px;--shadow-blur-3:20px;--shadow-blur-4:23px}[data-elevation-hover="4"]:where([data-elevation-direction=top]):hover,[data-elevation="4"]:where([data-elevation-direction=top]){--y2:15px;--shadow-blur-2:15px}[data-elevation-hover="4"]:where([data-elevation-direction=left]):hover,[data-elevation="4"]:where([data-elevation-direction=left]){--y1:0px;--y2:0px;--y3:0px;--y4:0px;--x1:4px;--x2:15px;--x3:33px;--x4:58px;--shadow-blur-2:15px}[data-elevation-hover="4"]:where([data-elevation-direction=right]):hover,[data-elevation="4"]:where([data-elevation-direction=right]){--y1:0px;--y2:0px;--y3:0px;--y4:0px;--x1:4px;--x2:14px;--x3:33px;--x4:58px}}}@layer viraui.preflight{[data-grow=true]{--vira-flex-grow:1;flex-grow:1}[data-grow=false]{--vira-flex-grow:0;flex-grow:0}[data-shrink=true]{--vira-flex-shrink:1;flex-shrink:1}[data-shrink=false]{--vira-flex-shrink:0;flex-shrink:0}}@layer viraui.preflight{:where(p){line-height:1.5;min-block-size:.01vh;font-size:var(--font-scale-body-medium)}small{font-size:.7em}b,strong{font-variation-settings:"wght" 700}:where(a:any-link):not([data-no-link-style]){text-decoration:none;color:var(--global-interactive-text);word-break:break-word;&:not([class]){background:linear-gradient(currentcolor,currentcolor) no-repeat 0 100%;background-size:0 1px;transition:background-size var(--duration-fast) var(--easing-entrance);&:focus,&:hover{background-size:100% 1px}}}del{padding:0 .4em;margin:0 .2em;background-color:oklab(from var(--highlight-red) l a b/12%);color:var(--highlight-red);box-shadow:0 0 0 1px oklab(from var(--highlight-red) l a b/50%);border-radius:var(--radius-small)}ins{background-color:oklab(from var(--highlight-green) l a b/15%);color:var(--highlight-green);box-shadow:0 0 0 1px oklab(from var(--highlight-green) l a b/50%)}ins,mark{padding:0 .4em;margin:0 .2em;text-decoration:none;border-radius:var(--radius-small)}mark{background-color:oklab(from var(--highlight-yellow) l a b/15%);color:var(--highlight-yellow);box-shadow:0 0 0 1px oklab(from var(--highlight-yellow) l a b/50%)}address{font-style:normal;line-height:inherit}dt{font-variation-settings:"wght" 600}dd{margin:0;padding:0}ul{font-size:medium;padding-left:1rem;& li::marker{font-size:inherit;text-align:right;font-variation-settings:"wght" 400;min-inline-size:var(--space-x-large);color:oklab(from currentColor l a b/80%)}}ol{font-size:medium;& li::marker{font-size:inherit;font-variation-settings:"wght" 400;min-inline-size:var(--space-x-large);font-variant-numeric:tabular-nums;white-space:nowrap;color:oklab(from currentColor l a b/80%)}}kbd{padding:.2em .4em;border-radius:var(--radius-small);font-variation-settings:"wght" 600;box-shadow:var(--global-contrast);background:var(--global-contrast)}abbr{text-decoration:underline dashed var(--global-primary)}label,legend{font-size:inherit}code{font-size:1em;font-family:var(--font-family-mono);&:not(:where(pre &)){background-color:var(--global-contrast);border-radius:var(--radius-small);box-shadow:var(--global-contrast);padding:.2em .4em}}pre code{box-shadow:none}s{text-decoration:line-through;color:var(--global-disabled-foreground);text-decoration-color:oklab(from var(--global-foreground) l a b/50%)}:root{color-scheme:light dark}[data-mode=dark]{--is-light-mode:#fff;color:var(--global-foreground);color-scheme:dark}[data-mode=light]{--is-light-mode:#000;color:var(--global-foreground);color-scheme:light}}@layer viraui.preflight{[data-mode=inverted]{color:var(--global-foreground);@container root style(--is-light-mode: black){color-scheme:dark}@container root style(--is-light-mode: white){color-scheme:light}}}@layer viraui.preflight{@container root not style(--effect-vibrancy: initial){[data-vibrant]{backdrop-filter:brightness(var(--vibrancy-brightness)) blur(calc(var(--vibrancy-blur) * 1px)) saturate(150%);@container root style(--is-light-mode: black){backdrop-filter:brightness(100%) blur(calc(var(--vibrancy-blur) * 1px)) saturate(150%)}}}}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@viraui/react",
3
- "version": "2026.2.17",
3
+ "version": "2026.3.0",
4
4
  "private": false,
5
5
  "files": [
6
6
  "dist"
@@ -28,8 +28,8 @@
28
28
  },
29
29
  "devDependencies": {
30
30
  "@base-ui/react": ">=1.7.0",
31
- "@viraui/foundation": "2026.2.17",
32
- "@viraui/icons": "2026.0.2",
31
+ "@viraui/foundation": "2026.3.0",
32
+ "@viraui/icons": "2026.0.3",
33
33
  "@viraui/postcss-config": "2026.0.0",
34
34
  "@viraui/tsconfig": "2026.0.0",
35
35
  "postcss": "8.5.26",
@@ -1,37 +0,0 @@
1
- import { ReactNode } from 'react';
2
- import * as React from 'react';
3
- export type ButtonSize = 'large' | 'medium' | 'small';
4
- export type ButtonVariant = 'primary' | 'secondary' | 'flat' | 'destructive';
5
- export type ButtonAddonPosition = 'start' | 'end';
6
- export declare const spinnerDimensionsBySize: Record<ButtonSize, 'small' | 'medium'>;
7
- type ButtonChromeRootAttrsParams = {
8
- addon?: ReactNode;
9
- addonPosition: ButtonAddonPosition;
10
- className?: string;
11
- isDisabled: boolean;
12
- isIconOnly: boolean;
13
- loading: boolean;
14
- pill: boolean;
15
- size: ButtonSize;
16
- variant: ButtonVariant;
17
- };
18
- export declare function getButtonChromeRootAttrs({ addon, addonPosition, className, isDisabled, isIconOnly, loading, pill, size, variant, }: ButtonChromeRootAttrsParams): {
19
- 'data-disabled'?: "" | undefined;
20
- 'aria-busy': true | undefined;
21
- className: string;
22
- 'data-loading': string;
23
- 'data-pill': string | undefined;
24
- 'data-size': ButtonSize;
25
- 'data-icon-only': string | undefined;
26
- 'data-addon-position': ButtonAddonPosition | undefined;
27
- 'data-variant': ButtonVariant;
28
- };
29
- type ButtonChromeChildrenProps = {
30
- addon?: ReactNode;
31
- children?: ReactNode;
32
- isIconOnly: boolean;
33
- loading: boolean;
34
- size: ButtonSize;
35
- };
36
- export declare const ButtonChromeChildren: React.FC<ButtonChromeChildrenProps>;
37
- export {};
@@ -1,48 +0,0 @@
1
- import { clsx } from "../../core/clsx.js";
2
- import { Spinner } from "../spinner/spinner.js";
3
- import button_module_default from "./button.module.js";
4
- import { Fragment, jsx, jsxs } from "react/jsx-runtime";
5
- import "react";
6
- //#region src/components/button/button-chrome.tsx
7
- var spinnerDimensionsBySize = {
8
- small: "small",
9
- medium: "small",
10
- large: "medium"
11
- };
12
- function getButtonChromeRootAttrs({ addon, addonPosition, className, isDisabled, isIconOnly, loading, pill, size, variant }) {
13
- return {
14
- "aria-busy": loading || void 0,
15
- className: clsx(button_module_default.Button, className),
16
- "data-loading": loading ? "true" : "false",
17
- "data-pill": pill ? "true" : void 0,
18
- "data-size": size,
19
- "data-icon-only": isIconOnly ? "true" : void 0,
20
- "data-addon-position": addon && !isIconOnly ? addonPosition : void 0,
21
- "data-variant": variant,
22
- ...isDisabled && { "data-disabled": "" }
23
- };
24
- }
25
- var ButtonChromeChildren = ({ addon, children, isIconOnly, loading, size }) => /* @__PURE__ */ jsxs(Fragment, { children: [isIconOnly ? /* @__PURE__ */ jsx("span", {
26
- "aria-hidden": "true",
27
- className: button_module_default.Content,
28
- "data-loading": loading ? "true" : "false",
29
- children: addon
30
- }) : /* @__PURE__ */ jsxs(Fragment, { children: [addon && /* @__PURE__ */ jsx("span", {
31
- "aria-hidden": "true",
32
- className: button_module_default.Content,
33
- "data-loading": loading ? "true" : "false",
34
- children: addon
35
- }), /* @__PURE__ */ jsx("span", {
36
- className: button_module_default.Content,
37
- "data-loading": loading ? "true" : "false",
38
- children
39
- })] }), loading && /* @__PURE__ */ jsx("span", {
40
- "aria-hidden": "true",
41
- className: button_module_default.SpinnerOverlay,
42
- children: /* @__PURE__ */ jsx(Spinner, {
43
- variant: "dots",
44
- size: spinnerDimensionsBySize[size]
45
- })
46
- })] });
47
- //#endregion
48
- export { ButtonChromeChildren, getButtonChromeRootAttrs, spinnerDimensionsBySize };