@olundot/ui 0.20.0 → 0.20.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,22 @@
1
1
  # @olundot/ui
2
2
 
3
+ ## 0.20.1
4
+
5
+ ### Patch Changes
6
+
7
+ - 0ab7288: 구조형 `Dialog`에 `hideTitle`과 목록 영역(`list`, `listHeight`, `listFit`, `listLabel`)을 더했다.
8
+
9
+ - `hideTitle`: 제목을 화면에서 숨기고(`sr-only`) 다이얼로그의 접근 이름으로 둔다. 머리에는 닫기 버튼만 남는다. 상자 윗선에서 본문 첫 줄까지 간격, 닫기 버튼 자리, 1024px 미만의 머리 끌어내리기, 첫 포커스 규칙은 그대로다. `description`과 함께 줄 수 없다(타입 오류).
10
+ - `list`: 본문 아래, 푸터 위의 목록 영역. 목록 영역만 스크롤하고 본문은 고정된다. 안개는 본문과 같은 방식으로 목록 영역 위·아래 끝에 그린다. 폼 모드에서도 `form` 안에 있다. 목록 안 입력도 첫 포커스 대상이다.
11
+ - `listHeight`: 항목 부분 높이 `"sm"` 216px, `"md"` 460px(기본), `"lg"` 628px. 화면이 낮으면 상자 최대 높이 안에서 줄어들되 항목 부분은 112px(목록 영역 124px)에서 멈추고, 더 낮으면 본문이 스크롤한다. 머리와 푸터는 늘 상자 안에 있다.
12
+ - `listFit`: `"max"`(기본)는 항목만큼 커지다가 `listHeight`에서 멈추고, `"fixed"`는 항목 수와 관계없이 `listHeight`다.
13
+ - `listLabel`: 목록 안에 포커스 받는 요소가 없을 때 영역이 `tabIndex={0}`인 `region`이 되며 붙는 이름. 기본값은 `title`.
14
+ - 타입 `DialogListHeight`, `DialogListFit`을 내보낸다. `DialogProps`는 `hideTitle`과 `description`을 나누려고 interface에서 type으로 바뀌었다. `interface X extends DialogProps`로 확장하던 코드는 `type X = DialogProps & …`로 바꾼다.
15
+ - 첫 포커스는 탭으로 닿는 입력만 고른다. 숨겨지거나(`hidden`, `inert`, `aria-hidden` 조상) 비활성이거나 `tabIndex`가 음수인 입력은 건너뛴다. 폼 안 `Checkbox`가 남기는 전달용 입력이 여기에 든다. Dialog, Sheet, AlertDialog에 함께 적용된다.
16
+ - `hideTitle`과 `list` 없이 쓰는 Dialog의 모양은 그대로다. 동작은 위 첫 포커스 규칙만 바뀐다.
17
+
18
+ - e695c9d: `IconButton`에 `done`과 `tooltip`을 더했다. `done`은 이미 끝난 동작을 `success` 아이콘과 ✓ 배지로 보이고, 초점은 받지만 `onClick`을 부르지 않는다. `tooltip`은 아이콘만 있는 버튼에 말풍선을 붙인다. Provider가 없어도 되고 `title`을 대신한다. 배지 색에 `success`를 더했다.
19
+
3
20
  ## 0.20.0
4
21
 
5
22
  ### Minor Changes
package/dist/index.d.ts CHANGED
@@ -66,7 +66,7 @@ type GhostDefaultActionStyle = {
66
66
  declare const buttonCva: (props?: ({
67
67
  appearance?: "filled" | "outline" | "ghost" | "link" | null | undefined;
68
68
  tone?: "primary" | "neutral" | "danger" | null | undefined;
69
- size?: "xs" | "sm" | "md" | "lg" | "xl" | "default" | null | undefined;
69
+ size?: "default" | "md" | "xs" | "sm" | "lg" | "xl" | null | undefined;
70
70
  } & class_variance_authority_types.ClassProp) | undefined) => string;
71
71
  type ButtonVariantsOptions = Parameters<typeof buttonCva>[0];
72
72
  declare function buttonVariants(options?: ButtonVariantsOptions): string;
@@ -101,13 +101,13 @@ type CopyButtonProps = Omit<ButtonProps, 'appearance' | 'children' | 'loading' |
101
101
  declare const CopyButton: React.ForwardRefExoticComponent<CopyButtonProps & React.RefAttributes<HTMLButtonElement>>;
102
102
 
103
103
  declare const inputVariants: (props?: ({
104
- size?: "sm" | "md" | "lg" | null | undefined;
104
+ size?: "md" | "sm" | "lg" | null | undefined;
105
105
  fullWidth?: boolean | null | undefined;
106
106
  surface?: SurfaceLevel | null | undefined;
107
107
  } & class_variance_authority_types.ClassProp) | undefined) => string;
108
108
  declare const inputMessageVariants: (props?: ({
109
- state?: "error" | "success" | "default" | null | undefined;
110
- size?: "sm" | "md" | "lg" | null | undefined;
109
+ state?: "default" | "error" | "success" | null | undefined;
110
+ size?: "md" | "sm" | "lg" | null | undefined;
111
111
  } & class_variance_authority_types.ClassProp) | undefined) => string;
112
112
  type InputState = NonNullable<VariantProps<typeof inputMessageVariants>["state"]>;
113
113
  /** Canonical size type (0.2.0+). Use `size` prop with these values. */
@@ -155,11 +155,11 @@ interface InputProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, "
155
155
  declare const Input: React.ForwardRefExoticComponent<InputProps & React.RefAttributes<HTMLInputElement>>;
156
156
 
157
157
  declare const fileUploadZoneVariants: (props?: ({
158
- size?: "compact" | "default" | null | undefined;
158
+ size?: "default" | "compact" | null | undefined;
159
159
  surface?: SurfaceLevel | null | undefined;
160
160
  } & class_variance_authority_types.ClassProp) | undefined) => string;
161
161
  declare const fileUploadIconVariants: (props?: ({
162
- size?: "compact" | "default" | null | undefined;
162
+ size?: "default" | "compact" | null | undefined;
163
163
  } & class_variance_authority_types.ClassProp) | undefined) => string;
164
164
  interface FileUploadZoneProps extends Omit<React.LabelHTMLAttributes<HTMLLabelElement>, "onChange">, VariantProps<typeof fileUploadZoneVariants> {
165
165
  accept?: string;
@@ -203,12 +203,12 @@ interface InlineAlertProps extends Omit<HTMLAttributes<HTMLDivElement>, 'childre
203
203
  declare const InlineAlert: React.ForwardRefExoticComponent<InlineAlertProps & React.RefAttributes<HTMLDivElement>>;
204
204
 
205
205
  declare const textareaVariants: (props?: ({
206
- size?: "sm" | "md" | "lg" | null | undefined;
206
+ size?: "md" | "sm" | "lg" | null | undefined;
207
207
  fullWidth?: boolean | null | undefined;
208
208
  surface?: SurfaceLevel | null | undefined;
209
209
  } & class_variance_authority_types.ClassProp) | undefined) => string;
210
210
  declare const textareaMessageVariants: (props?: ({
211
- state?: "error" | "success" | "default" | null | undefined;
211
+ state?: "default" | "error" | "success" | null | undefined;
212
212
  } & class_variance_authority_types.ClassProp) | undefined) => string;
213
213
  type TextareaState = NonNullable<VariantProps<typeof textareaMessageVariants>["state"]>;
214
214
  /** Canonical size type (0.2.0+). Use `size` prop with these values. */
@@ -257,14 +257,14 @@ interface TextareaProps extends Omit<React.TextareaHTMLAttributes<HTMLTextAreaEl
257
257
  declare const Textarea: React.ForwardRefExoticComponent<TextareaProps & React.RefAttributes<HTMLTextAreaElement>>;
258
258
 
259
259
  declare const selectVariants: (props?: ({
260
- size?: "sm" | "md" | "lg" | null | undefined;
260
+ size?: "md" | "sm" | "lg" | null | undefined;
261
261
  fullWidth?: boolean | null | undefined;
262
262
  appearance?: "inline" | "field" | null | undefined;
263
263
  surface?: SurfaceLevel | null | undefined;
264
264
  } & class_variance_authority_types.ClassProp) | undefined) => string;
265
265
  declare const selectMessageVariants: (props?: ({
266
- state?: "error" | "success" | "default" | null | undefined;
267
- size?: "sm" | "md" | "lg" | null | undefined;
266
+ state?: "default" | "error" | "success" | null | undefined;
267
+ size?: "md" | "sm" | "lg" | null | undefined;
268
268
  } & class_variance_authority_types.ClassProp) | undefined) => string;
269
269
  type SelectState = NonNullable<VariantProps<typeof selectMessageVariants>["state"]>;
270
270
  /** Canonical size type (0.2.0+). Use `size` prop with these values. */
@@ -700,6 +700,10 @@ declare const FormLayout: React.ForwardRefExoticComponent<FormLayoutProps & Reac
700
700
  * blur (`--scrim-blur`). Without a preset (no prop, no `<html data-scrim>`) the scrim is `--scrim`.
701
701
  */
702
702
  type OverlayScrim = "blur" | "dim";
703
+ /** List area height preset (Dialog `listHeight`). */
704
+ type OverlayListHeight = "sm" | "md" | "lg";
705
+ /** `"max"`: as tall as the items, up to the preset. `"fixed"`: the preset whatever the item count. */
706
+ type OverlayListFit = "max" | "fixed";
703
707
 
704
708
  /**
705
709
  * @deprecated The structured Dialog (`title`) is a bottom sheet below 1024px on its own.
@@ -713,25 +717,36 @@ type OverlayScrim = "blur" | "dim";
713
717
  type DialogMobilePresentation = "center" | "sheet";
714
718
  /** Structured Dialog width: 420 · 560 · 720 · 960. */
715
719
  type DialogSize = "sm" | "md" | "lg" | "xl";
716
- /**
717
- * Structured Dialog (spec §3.2): a center window for forms, pickers and long content. X + footer,
718
- * outside click does not close, Escape does (not while submitting), the body scrolls inside the max
719
- * height, a bottom sheet below 1024px (OVERLAY_POLICY.dialog).
720
- */
721
- interface DialogProps {
720
+ /** List area height (`listHeight`): items up to 216 · 460 · 628px. */
721
+ type DialogListHeight = OverlayListHeight;
722
+ /** List area height mode (`listFit`). */
723
+ type DialogListFit = OverlayListFit;
724
+ interface DialogBaseProps {
722
725
  open: boolean;
723
726
  onOpenChange: (open: boolean) => void;
724
727
  /** Heading, also the dialog's accessible name. Its presence selects the structured mode. */
725
728
  title: string;
726
- /** Line under the title, also the accessible description. */
727
- description?: string;
728
729
  /**
729
730
  * Box width: 420 · 560 · 720 · 960. Default `"md"`. `"xl"` is for content 720 cannot hold, such as
730
731
  * two columns. Other widths are not supported.
731
732
  */
732
733
  size?: DialogSize;
733
- /** Body. Scrolls inside the box's max height. */
734
+ /** Body. Scrolls inside the box's max height; with `list` it stays still above the list area. */
734
735
  children: React.ReactNode;
736
+ /**
737
+ * List area under the body and above the footer, for items to pick from. Only this area scrolls;
738
+ * the body above it (filters, search, select all) stays still. Empty and loading states go here too.
739
+ */
740
+ list?: React.ReactNode;
741
+ /** List area height preset: items up to 216 · 460 · 628px. Default `"md"`. A low screen shrinks it inside the box max height. */
742
+ listHeight?: DialogListHeight;
743
+ /**
744
+ * `"max"` (default): as tall as the items, up to `listHeight`. `"fixed"`: `listHeight` whatever the
745
+ * item count, for lists a search or filter resizes.
746
+ */
747
+ listFit?: DialogListFit;
748
+ /** Accessible name of the list area, used when nothing inside takes focus. Default: `title`. */
749
+ listLabel?: string;
735
750
  /** Footer content (buttons). Ignored in form mode, which renders `[cancel][submit]`. */
736
751
  footer?: React.ReactNode;
737
752
  /**
@@ -754,6 +769,24 @@ interface DialogProps {
754
769
  /** Layout of the body content only. It never reaches the box: width comes from `size`. */
755
770
  className?: string;
756
771
  }
772
+ /**
773
+ * Structured Dialog (spec §3.2): a center window for forms, pickers and long content. X + footer,
774
+ * outside click does not close, Escape does (not while submitting), the body scrolls inside the max
775
+ * height, a bottom sheet below 1024px (OVERLAY_POLICY.dialog).
776
+ */
777
+ type DialogProps = DialogBaseProps & ({
778
+ /** Shows the title in the header. Default. */
779
+ hideTitle?: false;
780
+ /** Line under the title, also the accessible description. */
781
+ description?: string;
782
+ } | {
783
+ /**
784
+ * Hides the title on screen and keeps it as the accessible name; the header shows the X only.
785
+ * Use it only when the body's first line says what the dialog is about.
786
+ */
787
+ hideTitle: true;
788
+ description?: never;
789
+ });
757
790
  /** Legacy root: the Radix Dialog Root for `DialogContent` composition (no `title`). */
758
791
  type DialogRootProps = React.ComponentProps<typeof Dialog$1.Root> & {
759
792
  title?: never;
@@ -1678,7 +1711,7 @@ interface StatusDotProps extends Omit<React.HTMLAttributes<HTMLSpanElement>, 'ch
1678
1711
  declare const StatusDot: React.ForwardRefExoticComponent<StatusDotProps & React.RefAttributes<HTMLSpanElement>>;
1679
1712
 
1680
1713
  declare const notificationBadgeVariants: (props?: ({
1681
- size?: "sm" | "md" | null | undefined;
1714
+ size?: "md" | "sm" | null | undefined;
1682
1715
  placement?: "none" | "inline" | "corner" | null | undefined;
1683
1716
  } & class_variance_authority_types.ClassProp) | undefined) => string;
1684
1717
  type NotificationBadgeSize = NonNullable<VariantProps<typeof notificationBadgeVariants>['size']>;
@@ -1691,13 +1724,13 @@ declare const NotificationBadge: React.ForwardRefExoticComponent<NotificationBad
1691
1724
 
1692
1725
  declare const chipVariants: (props?: ({
1693
1726
  variant?: "filter" | "choice" | "removable" | "status-filter" | null | undefined;
1694
- tone?: "muted" | "accent" | "warning" | "success" | "neutral" | "danger" | null | undefined;
1695
- size?: "sm" | "md" | "lg" | null | undefined;
1727
+ tone?: "accent" | "neutral" | "danger" | "success" | "warning" | "muted" | null | undefined;
1728
+ size?: "md" | "sm" | "lg" | null | undefined;
1696
1729
  pressed?: boolean | null | undefined;
1697
1730
  } & class_variance_authority_types.ClassProp) | undefined) => string;
1698
1731
  declare const chipCountVariants: (props?: ({
1699
- tone?: "muted" | "accent" | "warning" | "success" | "neutral" | "danger" | null | undefined;
1700
- size?: "sm" | "md" | "lg" | null | undefined;
1732
+ tone?: "accent" | "neutral" | "danger" | "success" | "warning" | "muted" | null | undefined;
1733
+ size?: "md" | "sm" | "lg" | null | undefined;
1701
1734
  } & class_variance_authority_types.ClassProp) | undefined) => string;
1702
1735
  type ChipVariant = NonNullable<VariantProps<typeof chipVariants>["variant"]>;
1703
1736
  type ChipTone = NonNullable<VariantProps<typeof chipVariants>["tone"]>;
@@ -1711,7 +1744,7 @@ interface ChipProps extends Omit<React.ButtonHTMLAttributes<HTMLButtonElement>,
1711
1744
  declare const Chip: React.ForwardRefExoticComponent<ChipProps & React.RefAttributes<HTMLButtonElement>>;
1712
1745
 
1713
1746
  declare const emptyStateBaseVariants: (props?: ({
1714
- size?: "sm" | "md" | "lg" | null | undefined;
1747
+ size?: "md" | "sm" | "lg" | null | undefined;
1715
1748
  bordered?: boolean | null | undefined;
1716
1749
  } & class_variance_authority_types.ClassProp) | undefined) => string;
1717
1750
  type EmptyStateTone = "neutral" | "muted" | "raised";
@@ -1723,7 +1756,7 @@ interface EmptyStateVariantOptions extends VariantProps<typeof emptyStateBaseVar
1723
1756
  }
1724
1757
  declare function emptyStateVariants({ size, tone, surface, bordered, className, }?: EmptyStateVariantOptions): string;
1725
1758
  declare const emptyStateIconVariants: (props?: ({
1726
- size?: "sm" | "md" | "lg" | null | undefined;
1759
+ size?: "md" | "sm" | "lg" | null | undefined;
1727
1760
  } & class_variance_authority_types.ClassProp) | undefined) => string;
1728
1761
  type EmptyStateSize = NonNullable<VariantProps<typeof emptyStateBaseVariants>["size"]>;
1729
1762
  interface EmptyStateProps extends Omit<React.HTMLAttributes<HTMLDivElement>, "title">, VariantProps<typeof emptyStateBaseVariants> {
@@ -1749,7 +1782,7 @@ interface EmptyStateProps extends Omit<React.HTMLAttributes<HTMLDivElement>, "ti
1749
1782
  declare const EmptyState: React.ForwardRefExoticComponent<EmptyStateProps & React.RefAttributes<HTMLDivElement>>;
1750
1783
 
1751
1784
  declare const errorStateVariants: (props?: ({
1752
- size?: "sm" | "md" | "lg" | null | undefined;
1785
+ size?: "md" | "sm" | "lg" | null | undefined;
1753
1786
  surface?: SurfaceLevel | null | undefined;
1754
1787
  } & class_variance_authority_types.ClassProp) | undefined) => string;
1755
1788
  interface ErrorStateProps extends Omit<React.HTMLAttributes<HTMLDivElement>, "title">, VariantProps<typeof errorStateVariants> {
@@ -1769,7 +1802,7 @@ declare const skeletonVariants: (props?: ({
1769
1802
  shape?: "text" | "block" | "circle" | null | undefined;
1770
1803
  } & class_variance_authority_types.ClassProp) | undefined) => string;
1771
1804
  declare const spinnerVariants: (props?: ({
1772
- size?: "sm" | "md" | "lg" | 16 | 24 | 32 | null | undefined;
1805
+ size?: "md" | "sm" | "lg" | 16 | 24 | 32 | null | undefined;
1773
1806
  } & class_variance_authority_types.ClassProp) | undefined) => string;
1774
1807
  interface SkeletonProps extends React.HTMLAttributes<HTMLDivElement>, VariantProps<typeof skeletonVariants> {
1775
1808
  }
@@ -1802,7 +1835,7 @@ interface SpinnerProps extends React.HTMLAttributes<HTMLSpanElement> {
1802
1835
  declare const Spinner: React.ForwardRefExoticComponent<SpinnerProps & React.RefAttributes<HTMLSpanElement>>;
1803
1836
 
1804
1837
  declare const iconButtonCva: (props?: ({
1805
- size?: "xs" | "sm" | "md" | "lg" | "xl" | null | undefined;
1838
+ size?: "md" | "xs" | "sm" | "lg" | "xl" | null | undefined;
1806
1839
  pressed?: boolean | null | undefined;
1807
1840
  appearance?: "filled" | "outline" | "ghost" | null | undefined;
1808
1841
  tone?: "primary" | "neutral" | "danger" | null | undefined;
@@ -1811,7 +1844,7 @@ type IconButtonSize = NonNullable<VariantProps<typeof iconButtonCva>["size"]>;
1811
1844
  type IconButtonVariantsOptions = NonNullable<Parameters<typeof iconButtonCva>[0]>;
1812
1845
  declare function iconButtonVariants(options?: IconButtonVariantsOptions): string;
1813
1846
  declare const iconButtonBadgeVariants: (props?: ({
1814
- tone?: "error" | "info" | null | undefined;
1847
+ tone?: "error" | "success" | "info" | null | undefined;
1815
1848
  } & class_variance_authority_types.ClassProp) | undefined) => string;
1816
1849
  type IconButtonBadgeTone = NonNullable<VariantProps<typeof iconButtonBadgeVariants>["tone"]>;
1817
1850
  type IconButtonIcon = React.ComponentType<React.SVGProps<SVGSVGElement> & {
@@ -1836,17 +1869,41 @@ type IconButtonTextEnd = {
1836
1869
  iconPosition?: "start";
1837
1870
  menuIndicator: true;
1838
1871
  };
1872
+ type IconButtonTooltipSide = "top" | "bottom";
1873
+ type IconButtonTooltipOn = {
1874
+ /**
1875
+ * Icon only. A tooltip on pointer hover and keyboard focus, in place of `title`: `true` shows the
1876
+ * string `aria-label`, a string shows that string. No Provider needed.
1877
+ */
1878
+ tooltip: true | string;
1879
+ /** Tooltip side. Default `top`. */
1880
+ tooltipSide?: IconButtonTooltipSide;
1881
+ title?: never;
1882
+ };
1883
+ type IconButtonTooltip = {
1884
+ tooltip?: undefined;
1885
+ tooltipSide?: never;
1886
+ } | (IconButtonTooltipOn & {
1887
+ tooltip: string;
1888
+ }) | (IconButtonTooltipOn & {
1889
+ tooltip: true;
1890
+ "aria-label": string;
1891
+ });
1892
+ type IconButtonNoTooltip = {
1893
+ tooltip?: never;
1894
+ tooltipSide?: never;
1895
+ };
1839
1896
  type IconButtonContent = (IconButtonAccessibleName & {
1840
1897
  label?: never;
1841
1898
  children?: never;
1842
1899
  menuIndicator?: never;
1843
- }) | (IconButtonOptionalName & {
1900
+ } & IconButtonTooltip) | (IconButtonOptionalName & {
1844
1901
  label: React.ReactNode;
1845
1902
  children?: never;
1846
- } & IconButtonTextEnd) | (IconButtonOptionalName & {
1903
+ } & IconButtonTextEnd & IconButtonNoTooltip) | (IconButtonOptionalName & {
1847
1904
  children: React.ReactNode;
1848
1905
  label?: never;
1849
- } & IconButtonTextEnd);
1906
+ } & IconButtonTextEnd & IconButtonNoTooltip);
1850
1907
  type IconButtonStyleProps = GhostDefaultActionStyle & {
1851
1908
  /** Button's scale: `xs` 28 · `sm` 30 · `md` 32 · `lg` 36 · `xl` 40. */
1852
1909
  size?: IconButtonSize | null;
@@ -1860,6 +1917,12 @@ type IconButtonProps = Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, "aria
1860
1917
  iconPosition?: "start" | "end";
1861
1918
  /** Like Button: the spinner takes the icon's place and the button is disabled. */
1862
1919
  loading?: boolean;
1920
+ /**
1921
+ * The action is already done: success icon, and a ✓ badge unless `badge` is given. Keeps
1922
+ * focus but never calls `onClick`. The accessible name says it is done. `disabled` and
1923
+ * `loading` win over it; it wins over `pressed`.
1924
+ */
1925
+ done?: boolean;
1863
1926
  /**
1864
1927
  * Trailing ▾ for a menu trigger, with text and a start icon only. The trigger (DropdownMenu
1865
1928
  * etc.) supplies `aria-haspopup`.
@@ -2018,7 +2081,7 @@ interface ActionFooterProps extends Omit<React.HTMLAttributes<HTMLDivElement>, '
2018
2081
  declare const ActionFooter: React.ForwardRefExoticComponent<ActionFooterProps & React.RefAttributes<HTMLDivElement>>;
2019
2082
 
2020
2083
  declare const toastVariants: (props?: ({
2021
- variant?: "error" | "warning" | "info" | "success" | "default" | null | undefined;
2084
+ variant?: "default" | "error" | "success" | "info" | "warning" | null | undefined;
2022
2085
  } & class_variance_authority_types.ClassProp) | undefined) => string;
2023
2086
  declare const toastViewportVariants: (props?: class_variance_authority_types.ClassProp | undefined) => string;
2024
2087
  type ToastVariant = NonNullable<VariantProps<typeof toastVariants>['variant']>;
@@ -2072,19 +2135,19 @@ interface ToastProviderProps extends React.HTMLAttributes<HTMLDivElement> {
2072
2135
  declare function ToastProvider({ children, maxToasts, className, ...props }: ToastProviderProps): react_jsx_runtime.JSX.Element;
2073
2136
 
2074
2137
  declare const otpFieldVariants: (props?: ({
2075
- size?: "compact" | "default" | null | undefined;
2138
+ size?: "default" | "compact" | null | undefined;
2076
2139
  } & class_variance_authority_types.ClassProp) | undefined) => string;
2077
2140
  declare const otpFieldGroupVariants: (props?: ({
2078
- size?: "compact" | "default" | null | undefined;
2141
+ size?: "default" | "compact" | null | undefined;
2079
2142
  fluid?: boolean | null | undefined;
2080
2143
  } & class_variance_authority_types.ClassProp) | undefined) => string;
2081
2144
  declare const otpCellVariants: (props?: ({
2082
- size?: "compact" | "default" | null | undefined;
2145
+ size?: "default" | "compact" | null | undefined;
2083
2146
  fluid?: boolean | null | undefined;
2084
2147
  surface?: SurfaceLevel | null | undefined;
2085
2148
  } & class_variance_authority_types.ClassProp) | undefined) => string;
2086
2149
  declare const otpFieldMessageVariants: (props?: ({
2087
- state?: "error" | "default" | null | undefined;
2150
+ state?: "default" | "error" | null | undefined;
2088
2151
  } & class_variance_authority_types.ClassProp) | undefined) => string;
2089
2152
  type OTPFieldSize = NonNullable<VariantProps<typeof otpCellVariants>["size"]>;
2090
2153
  interface OTPFieldProps extends Omit<React.FieldsetHTMLAttributes<HTMLFieldSetElement>, "onChange" | "children" | "defaultValue" | "value">, VariantProps<typeof otpFieldVariants> {
@@ -2111,10 +2174,10 @@ interface OTPFieldProps extends Omit<React.FieldsetHTMLAttributes<HTMLFieldSetEl
2111
2174
  declare const OTPField: React.ForwardRefExoticComponent<OTPFieldProps & React.RefAttributes<HTMLFieldSetElement>>;
2112
2175
 
2113
2176
  declare const searchFieldVariants: (props?: ({
2114
- size?: "sm" | "md" | "lg" | null | undefined;
2177
+ size?: "md" | "sm" | "lg" | null | undefined;
2115
2178
  } & class_variance_authority_types.ClassProp) | undefined) => string;
2116
2179
  declare const searchFieldInputVariants: (props?: ({
2117
- size?: "sm" | "md" | "lg" | null | undefined;
2180
+ size?: "md" | "sm" | "lg" | null | undefined;
2118
2181
  hasClear?: boolean | null | undefined;
2119
2182
  surface?: SurfaceLevel | null | undefined;
2120
2183
  } & class_variance_authority_types.ClassProp) | undefined) => string;
@@ -2138,7 +2201,7 @@ declare const checkboxVariants: (props?: ({
2138
2201
  } & class_variance_authority_types.ClassProp) | undefined) => string;
2139
2202
  declare const checkboxRootVariants: (props?: class_variance_authority_types.ClassProp | undefined) => string;
2140
2203
  declare const checkboxBoxVariants: (props?: ({
2141
- size?: "sm" | "md" | null | undefined;
2204
+ size?: "md" | "sm" | null | undefined;
2142
2205
  } & class_variance_authority_types.ClassProp) | undefined) => string;
2143
2206
  declare const checkboxGroupItemVariants: (props?: ({
2144
2207
  appearance?: "card" | "plain" | null | undefined;
@@ -2345,4 +2408,4 @@ interface OrganizationLogoProps extends Omit<SVGProps<SVGSVGElement>, "width" |
2345
2408
  }
2346
2409
  declare function OrganizationLogo({ organization, size, className, style, role, "aria-label": ariaLabel, "aria-hidden": ariaHidden, ...props }: OrganizationLogoProps): react_jsx_runtime.JSX.Element;
2347
2410
 
2348
- export { ActionFooter, type ActionFooterAction, type ActionFooterProps, type ActionFooterStatus, ActionMenu, type ActionMenuGroup, type ActionMenuItem, type ActionMenuProps, ActionSheet, type ActionSheetIconProps, type ActionSheetItem, type ActionSheetProps, Alert, AlertDialog, type AlertDialogProps, type AlertDialogTone, type AlertEmphasis, type AlertMarker, type AlertProps, type AlertVariant, Avatar, AvatarFallback, type AvatarFallbackProps, AvatarImage, Badge, type BadgeProps, type BadgeTone, Breadcrumb, type BreadcrumbItem, type BreadcrumbProps, BulkActionBar, type BulkActionBarAction, type BulkActionBarProps, Button, type ButtonProps, type ButtonSize, Card, CardContent, CardDescription, CardFooter, CardHeader, type CardProps, CardProse, CardTitle, type CardVariant, type CardVariantOptions, Checkbox, type CheckboxCheckedState, CheckboxGroup, type CheckboxGroupAppearance, type CheckboxGroupColumns, CheckboxGroupContext, type CheckboxGroupContextValue, type CheckboxGroupDensity, type CheckboxGroupOrientation, type CheckboxGroupProps, type CheckboxProps, type CheckboxSize, Chip, type ChipProps, type ChipSize, type ChipTone, type ChipVariant, ConfirmDialog, type ConfirmDialogProps, ContextMenu, type ContextMenuPosition, type ContextMenuProps, CopyButton, type CopyButtonProps, DataLayout, type DataLayoutProps, DataTable, type DataTableColumn, type DataTableLinkProps, type DataTableMobileCardContent, type DataTableMobileMetaLine, type DataTableProps, type DataTableRowActions, type DataTableSort, type DataTableVirtualHandle, type DataTableVirtualOptions, type DataTableVirtualRange, DetailLayout, type DetailLayoutProps, Dialog, DialogClose, DialogContent, DialogDescription, DialogEyebrow, DialogFooter, DialogHeader, type DialogMobilePresentation, DialogOverlay, DialogPortal, type DialogProps, DialogRawContent, type DialogSize, DialogTitle, DialogTrigger, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, EmptyState, type EmptyStateLayout, type EmptyStateProps, type EmptyStateSize, type EmptyStateTone, type EmptyStateVariantOptions, ErrorState, type ErrorStateProps, FileUploadZone, type FileUploadZoneProps, FilterToolbar, type FilterToolbarAppliedFilter, type FilterToolbarCollapseBelow, type FilterToolbarLayout, type FilterToolbarProps, FormField, type FormFieldProps, type FormFieldRenderProps, FormLayout, type FormLayoutProps, type FormLayoutSection, FormModal, type FormModalProps, IconButton, type IconButtonBadgeTone, type IconButtonProps, type IconButtonSize, InfoModal, type InfoModalProps, InlineAlert, type InlineAlertProps, Input, type InputProps, type InputSize, type InputSizeLegacy, type InputState, Label, type LabelProps, ListCard, type ListCardActions, type ListCardProps, ModeToggle, type ModeToggleOption, type ModeToggleProps, NotificationBadge, type NotificationBadgePlacement, type NotificationBadgeProps, type NotificationBadgeSize, OTPField, type OTPFieldProps, type OTPFieldSize, OlunLogo, OlunSymbol, type OlunTheme, type OlunThemeDuration, type OlunThemeState, OrganizationLogo, type OrganizationLogoId, type OrganizationLogoProps, type OverlayScrim, PageHeader, type PageHeaderProps, PageSizeSelect, type PageSizeSelectProps, type PageSizeSelectSize, Pagination, type PaginationProps, type PaginationSize, PermissionContext, type PermissionEvaluator, type PermissionFallback, PermissionGuard, type PermissionGuardProps, PermissionProvider, type PermissionProviderProps, type PermissionScope, type PermissionState, Popover, PopoverAnchor, PopoverArrow, PopoverClose, PopoverContent, type PopoverContentProps, type PopoverProps, PopoverTrigger, Progress, type ProgressProps, type ProgressStatus, Radio, RadioGroup, type RadioGroupAppearance, type RadioGroupColumns, type RadioGroupDensity, type RadioGroupOrientation, type RadioGroupProps, type RadioProps, ScrollArea, ScrollBar, SearchField, type SearchFieldProps, type SearchFieldSize, Select, type SelectAppearance, type SelectOption, type SelectProps, type SelectSize, type SelectState, type SelectVariant, type SemanticRole, Separator, type SetOlunThemeOptions, Sheet, SheetBody, SheetClose, SheetContent, SheetDescription, SheetDrawer, type SheetDrawerProps, SheetFooter, SheetHeader, type SheetMotionConfig, type SheetMotionDuration, type SheetMotionEasing, type SheetMotionType, type SheetProps, type SheetSize, SheetTitle, SheetTrigger, Skeleton, type SkeletonProps, SkeletonRow, type SkeletonRowColumn, type SkeletonRowProps, SkeletonText, type SkeletonTextProps, Spinner, type SpinnerProps, StatusBadge, type StatusBadgeEmphasis, type StatusBadgeProps, type StatusBadgeSize, type StatusBadgeStatus, StatusDot, type StatusDotProps, type StatusDotTone, type SurfaceLevel, Switch, type SwitchProps, TABLE_PAGE_SIZE_OPTIONS, type TabItem, TablePagination, type TablePaginationProps, type TablePaginationVisibility, Tabs, TabsContent, type TabsProps, type TabsVariant, Textarea, type TextareaProps, type TextareaSize, type TextareaSizeLegacy, type TextareaState, ThemeFab, type ThemeFabProps, ThemeToggle, Toast, type ToastAction, type ToastItem, type ToastOptions, ToastProvider, ToastRoot, type ToastVariant, ToastViewport, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, type TreeItemRowVariantProps, type TreeItemState, type TreeNode, TreeView, type TreeViewProps, TwoTierBadge, type TwoTierBadgeEmphasis, type TwoTierBadgeProps, type TwoTierBadgeSize, type TwoTierBadgeTone, type UseOlunThemeValue, WizardLayout, type WizardLayoutProps, type WizardStep, type WizardStepState, actionFooterStatusVariants, actionFooterVariants, buttonVariants, cardVariants, checkboxBoxVariants, checkboxFieldVariants, checkboxGroupBoxVariants, checkboxGroupItemVariants, checkboxGroupVariants, checkboxRootVariants, checkboxVariants, chipCountVariants, chipVariants, cn, dataTableRowVariants, dataTableVariants, emptyStateIconVariants, emptyStateVariants, errorStateVariants, evaluatePermission, fileUploadIconVariants, fileUploadZoneVariants, formFieldControlStackClassName, formFieldDescriptionClassName, formFieldErrorClassName, formFieldLabelClassName, formFieldRequiredClassName, formFieldVariants, getOlunThemeState, getToastDuration, iconButtonBadgeVariants, iconButtonVariants, inputMessageVariants, inputVariants, limitToasts, modeToggleItemVariants, modeToggleVariants, notificationBadgeVariants, otpCellVariants, otpFieldGroupVariants, otpFieldMessageVariants, otpFieldVariants, paginationControlVariants, paginationVariants, radioControlVariants, radioGroupVariants, radioVariants, searchFieldInputVariants, searchFieldVariants, selectMessageVariants, selectVariants, setOlunTheme, shouldHideTablePagination, skeletonVariants, spinnerVariants, tabsBadgeVariants, tabsListVariants, tabsRootVariants, tabsTriggerVariants, textareaMessageVariants, textareaVariants, toast, toastVariants, toastViewportVariants, treeItemRowVariants, treeViewVariants, useOlunTheme, usePermission };
2411
+ export { ActionFooter, type ActionFooterAction, type ActionFooterProps, type ActionFooterStatus, ActionMenu, type ActionMenuGroup, type ActionMenuItem, type ActionMenuProps, ActionSheet, type ActionSheetIconProps, type ActionSheetItem, type ActionSheetProps, Alert, AlertDialog, type AlertDialogProps, type AlertDialogTone, type AlertEmphasis, type AlertMarker, type AlertProps, type AlertVariant, Avatar, AvatarFallback, type AvatarFallbackProps, AvatarImage, Badge, type BadgeProps, type BadgeTone, Breadcrumb, type BreadcrumbItem, type BreadcrumbProps, BulkActionBar, type BulkActionBarAction, type BulkActionBarProps, Button, type ButtonProps, type ButtonSize, Card, CardContent, CardDescription, CardFooter, CardHeader, type CardProps, CardProse, CardTitle, type CardVariant, type CardVariantOptions, Checkbox, type CheckboxCheckedState, CheckboxGroup, type CheckboxGroupAppearance, type CheckboxGroupColumns, CheckboxGroupContext, type CheckboxGroupContextValue, type CheckboxGroupDensity, type CheckboxGroupOrientation, type CheckboxGroupProps, type CheckboxProps, type CheckboxSize, Chip, type ChipProps, type ChipSize, type ChipTone, type ChipVariant, ConfirmDialog, type ConfirmDialogProps, ContextMenu, type ContextMenuPosition, type ContextMenuProps, CopyButton, type CopyButtonProps, DataLayout, type DataLayoutProps, DataTable, type DataTableColumn, type DataTableLinkProps, type DataTableMobileCardContent, type DataTableMobileMetaLine, type DataTableProps, type DataTableRowActions, type DataTableSort, type DataTableVirtualHandle, type DataTableVirtualOptions, type DataTableVirtualRange, DetailLayout, type DetailLayoutProps, Dialog, DialogClose, DialogContent, DialogDescription, DialogEyebrow, DialogFooter, DialogHeader, type DialogListFit, type DialogListHeight, type DialogMobilePresentation, DialogOverlay, DialogPortal, type DialogProps, DialogRawContent, type DialogSize, DialogTitle, DialogTrigger, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, EmptyState, type EmptyStateLayout, type EmptyStateProps, type EmptyStateSize, type EmptyStateTone, type EmptyStateVariantOptions, ErrorState, type ErrorStateProps, FileUploadZone, type FileUploadZoneProps, FilterToolbar, type FilterToolbarAppliedFilter, type FilterToolbarCollapseBelow, type FilterToolbarLayout, type FilterToolbarProps, FormField, type FormFieldProps, type FormFieldRenderProps, FormLayout, type FormLayoutProps, type FormLayoutSection, FormModal, type FormModalProps, IconButton, type IconButtonBadgeTone, type IconButtonProps, type IconButtonSize, InfoModal, type InfoModalProps, InlineAlert, type InlineAlertProps, Input, type InputProps, type InputSize, type InputSizeLegacy, type InputState, Label, type LabelProps, ListCard, type ListCardActions, type ListCardProps, ModeToggle, type ModeToggleOption, type ModeToggleProps, NotificationBadge, type NotificationBadgePlacement, type NotificationBadgeProps, type NotificationBadgeSize, OTPField, type OTPFieldProps, type OTPFieldSize, OlunLogo, OlunSymbol, type OlunTheme, type OlunThemeDuration, type OlunThemeState, OrganizationLogo, type OrganizationLogoId, type OrganizationLogoProps, type OverlayScrim, PageHeader, type PageHeaderProps, PageSizeSelect, type PageSizeSelectProps, type PageSizeSelectSize, Pagination, type PaginationProps, type PaginationSize, PermissionContext, type PermissionEvaluator, type PermissionFallback, PermissionGuard, type PermissionGuardProps, PermissionProvider, type PermissionProviderProps, type PermissionScope, type PermissionState, Popover, PopoverAnchor, PopoverArrow, PopoverClose, PopoverContent, type PopoverContentProps, type PopoverProps, PopoverTrigger, Progress, type ProgressProps, type ProgressStatus, Radio, RadioGroup, type RadioGroupAppearance, type RadioGroupColumns, type RadioGroupDensity, type RadioGroupOrientation, type RadioGroupProps, type RadioProps, ScrollArea, ScrollBar, SearchField, type SearchFieldProps, type SearchFieldSize, Select, type SelectAppearance, type SelectOption, type SelectProps, type SelectSize, type SelectState, type SelectVariant, type SemanticRole, Separator, type SetOlunThemeOptions, Sheet, SheetBody, SheetClose, SheetContent, SheetDescription, SheetDrawer, type SheetDrawerProps, SheetFooter, SheetHeader, type SheetMotionConfig, type SheetMotionDuration, type SheetMotionEasing, type SheetMotionType, type SheetProps, type SheetSize, SheetTitle, SheetTrigger, Skeleton, type SkeletonProps, SkeletonRow, type SkeletonRowColumn, type SkeletonRowProps, SkeletonText, type SkeletonTextProps, Spinner, type SpinnerProps, StatusBadge, type StatusBadgeEmphasis, type StatusBadgeProps, type StatusBadgeSize, type StatusBadgeStatus, StatusDot, type StatusDotProps, type StatusDotTone, type SurfaceLevel, Switch, type SwitchProps, TABLE_PAGE_SIZE_OPTIONS, type TabItem, TablePagination, type TablePaginationProps, type TablePaginationVisibility, Tabs, TabsContent, type TabsProps, type TabsVariant, Textarea, type TextareaProps, type TextareaSize, type TextareaSizeLegacy, type TextareaState, ThemeFab, type ThemeFabProps, ThemeToggle, Toast, type ToastAction, type ToastItem, type ToastOptions, ToastProvider, ToastRoot, type ToastVariant, ToastViewport, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, type TreeItemRowVariantProps, type TreeItemState, type TreeNode, TreeView, type TreeViewProps, TwoTierBadge, type TwoTierBadgeEmphasis, type TwoTierBadgeProps, type TwoTierBadgeSize, type TwoTierBadgeTone, type UseOlunThemeValue, WizardLayout, type WizardLayoutProps, type WizardStep, type WizardStepState, actionFooterStatusVariants, actionFooterVariants, buttonVariants, cardVariants, checkboxBoxVariants, checkboxFieldVariants, checkboxGroupBoxVariants, checkboxGroupItemVariants, checkboxGroupVariants, checkboxRootVariants, checkboxVariants, chipCountVariants, chipVariants, cn, dataTableRowVariants, dataTableVariants, emptyStateIconVariants, emptyStateVariants, errorStateVariants, evaluatePermission, fileUploadIconVariants, fileUploadZoneVariants, formFieldControlStackClassName, formFieldDescriptionClassName, formFieldErrorClassName, formFieldLabelClassName, formFieldRequiredClassName, formFieldVariants, getOlunThemeState, getToastDuration, iconButtonBadgeVariants, iconButtonVariants, inputMessageVariants, inputVariants, limitToasts, modeToggleItemVariants, modeToggleVariants, notificationBadgeVariants, otpCellVariants, otpFieldGroupVariants, otpFieldMessageVariants, otpFieldVariants, paginationControlVariants, paginationVariants, radioControlVariants, radioGroupVariants, radioVariants, searchFieldInputVariants, searchFieldVariants, selectMessageVariants, selectVariants, setOlunTheme, shouldHideTablePagination, skeletonVariants, spinnerVariants, tabsBadgeVariants, tabsListVariants, tabsRootVariants, tabsTriggerVariants, textareaMessageVariants, textareaVariants, toast, toastVariants, toastViewportVariants, treeItemRowVariants, treeViewVariants, useOlunTheme, usePermission };
package/dist/index.js CHANGED
@@ -4053,9 +4053,31 @@ import { Dialog as DialogPrimitive } from "radix-ui";
4053
4053
  // src/components/ui/icon-button.tsx
4054
4054
  import * as React25 from "react";
4055
4055
  import { cva as cva10 } from "class-variance-authority";
4056
- import { ChevronDown as ChevronDown4, Loader2 as Loader23 } from "lucide-react";
4056
+ import { Check as Check3, ChevronDown as ChevronDown4, Loader2 as Loader23 } from "lucide-react";
4057
4057
  import { jsx as jsx22, jsxs as jsxs20 } from "react/jsx-runtime";
4058
4058
  var pressedNeutralClassName = "border-[var(--border-strong)] bg-[var(--action-selected)] text-foreground";
4059
+ var doneClassName = "cursor-default text-[var(--success)]";
4060
+ var doneRestPaint = (classes) => classes.split(" ").filter(
4061
+ (name) => !name.startsWith("hover:") && (!name.startsWith("aria-disabled:") || name.startsWith("aria-disabled:active:"))
4062
+ ).join(" ");
4063
+ var tabbing = false;
4064
+ var tabListeners = 0;
4065
+ var markTab = (event) => {
4066
+ if (event.key !== "Tab") return;
4067
+ tabbing = true;
4068
+ setTimeout(() => {
4069
+ tabbing = false;
4070
+ }, 0);
4071
+ };
4072
+ function useTabMark(enabled) {
4073
+ React25.useEffect(() => {
4074
+ if (!enabled) return;
4075
+ if (tabListeners++ === 0) document.addEventListener("keydown", markTab, true);
4076
+ return () => {
4077
+ if (--tabListeners === 0) document.removeEventListener("keydown", markTab, true);
4078
+ };
4079
+ }, [enabled]);
4080
+ }
4059
4081
  var iconButtonCva = cva10(
4060
4082
  [
4061
4083
  "olun-icon-button relative inline-flex cursor-pointer shrink-0 items-center justify-center before:absolute before:content-['']",
@@ -4123,7 +4145,8 @@ var iconButtonBadgeVariants = cva10(
4123
4145
  variants: {
4124
4146
  tone: {
4125
4147
  info: "bg-[var(--accent-pop)] text-[var(--accent-on-fill)]",
4126
- error: "bg-[var(--error)] text-[var(--error-contrast)]"
4148
+ error: "bg-[var(--error)] text-[var(--error-contrast)]",
4149
+ success: "bg-[var(--success)] text-[var(--success-contrast)]"
4127
4150
  }
4128
4151
  },
4129
4152
  defaultVariants: {
@@ -4145,21 +4168,35 @@ var IconButton = React25.forwardRef(
4145
4168
  title,
4146
4169
  "aria-label": ariaLabel,
4147
4170
  "aria-labelledby": ariaLabelledBy,
4171
+ "aria-describedby": ariaDescribedBy,
4148
4172
  iconPosition = "start",
4149
4173
  loading,
4174
+ done,
4150
4175
  menuIndicator,
4151
4176
  disabled,
4152
4177
  label,
4153
4178
  children,
4179
+ tooltip,
4180
+ tooltipSide = "top",
4181
+ onClick,
4154
4182
  ...props
4155
4183
  }, ref) => {
4156
4184
  const resolvedSize = size ?? "md";
4157
- const isToggle = pressed !== void 0;
4158
- const isPressed = pressed === true;
4159
- const hoverTitle = title ?? (typeof ariaLabel === "string" ? ariaLabel : void 0);
4185
+ const isDisabled = disabled || loading;
4186
+ const isDone = done === true && !isDisabled;
4187
+ const isToggle = pressed !== void 0 && !isDone;
4188
+ const isPressed = pressed === true && !isDone;
4189
+ const tooltipText = tooltip === true ? ariaLabel : tooltip;
4190
+ const hoverTitle = tooltip !== void 0 ? void 0 : title ?? (typeof ariaLabel === "string" ? ariaLabel : void 0);
4160
4191
  const text = label ?? children;
4161
4192
  const hasText = text !== void 0 && text !== null && text !== false;
4162
- const isDisabled = disabled || loading;
4193
+ const resolvedBadge = badge === void 0 && isDone ? /* @__PURE__ */ jsx22(Check3, { strokeWidth: 3 }) : badge;
4194
+ const resolvedBadgeTone = badge === void 0 && isDone ? "success" : badgeTone;
4195
+ const [tooltipOpen, setTooltipOpen] = React25.useState(false);
4196
+ useTabMark(tooltip !== void 0);
4197
+ React25.useEffect(() => {
4198
+ if (isDisabled) setTooltipOpen(false);
4199
+ }, [isDisabled]);
4163
4200
  const style = resolveActionStyle(appearance, tone, "ghost");
4164
4201
  const icon = loading ? /* @__PURE__ */ jsx22(
4165
4202
  Loader23,
@@ -4179,7 +4216,14 @@ var IconButton = React25.forwardRef(
4179
4216
  strokeWidth: axisIcon[resolvedSize].strokeWidth
4180
4217
  }
4181
4218
  );
4182
- return /* @__PURE__ */ jsxs20(
4219
+ const paint = hasText ? [
4220
+ "olun-icon-button",
4221
+ buttonVariants({ ...style, size: resolvedSize }),
4222
+ isPressed && style.tone === "neutral" && pressedNeutralClassName,
4223
+ // The badge sits on the corner; Button xs/sm are already relative.
4224
+ resolvedBadge !== void 0 && "relative"
4225
+ ] : iconButtonVariants({ appearance, tone, size: resolvedSize, pressed: isPressed });
4226
+ const button = /* @__PURE__ */ jsxs20(
4183
4227
  "button",
4184
4228
  {
4185
4229
  ref,
@@ -4191,24 +4235,24 @@ var IconButton = React25.forwardRef(
4191
4235
  "data-icon-position": hasText ? iconPosition : void 0,
4192
4236
  "data-pressed": isToggle ? String(isPressed) : void 0,
4193
4237
  "data-loading": loading ? "true" : void 0,
4238
+ "data-done": isDone ? "true" : void 0,
4194
4239
  "aria-busy": loading ? true : void 0,
4195
- "aria-disabled": isDisabled ? true : void 0,
4240
+ "aria-disabled": isDisabled || isDone ? true : void 0,
4196
4241
  disabled: isDisabled,
4197
4242
  "aria-label": ariaLabel,
4198
4243
  "aria-labelledby": ariaLabelledBy,
4244
+ "aria-describedby": ariaDescribedBy,
4199
4245
  "aria-pressed": isToggle ? isPressed : void 0,
4200
4246
  title: hoverTitle,
4201
- className: cn(
4202
- hasText ? [
4203
- "olun-icon-button",
4204
- buttonVariants({ ...style, size: resolvedSize }),
4205
- isPressed && style.tone === "neutral" && pressedNeutralClassName,
4206
- // The badge sits on the corner; Button xs/sm are already relative.
4207
- badge !== void 0 && "relative"
4208
- ] : iconButtonVariants({ appearance, tone, size: resolvedSize, pressed: isPressed }),
4209
- className
4210
- ),
4247
+ className: cn(isDone ? [doneRestPaint(cn(paint)), doneClassName] : paint, className),
4211
4248
  type: type ?? "button",
4249
+ onClick: (event) => {
4250
+ if (isDone) {
4251
+ event.preventDefault();
4252
+ return;
4253
+ }
4254
+ onClick?.(event);
4255
+ },
4212
4256
  children: [
4213
4257
  hasText && iconPosition === "end" ? null : icon,
4214
4258
  hasText ? text : null,
@@ -4222,19 +4266,41 @@ var IconButton = React25.forwardRef(
4222
4266
  strokeWidth: axisIcon[resolvedSize].strokeWidth
4223
4267
  }
4224
4268
  ) : null,
4225
- badge !== void 0 ? /* @__PURE__ */ jsx22(
4269
+ resolvedBadge !== void 0 ? /* @__PURE__ */ jsx22(
4226
4270
  "span",
4227
4271
  {
4228
4272
  "aria-hidden": "true",
4229
4273
  "data-slot": "icon-button-badge",
4230
- "data-badge-tone": badgeTone,
4231
- className: iconButtonBadgeVariants({ tone: badgeTone }),
4232
- children: badge
4274
+ "data-badge-tone": resolvedBadgeTone,
4275
+ className: iconButtonBadgeVariants({ tone: resolvedBadgeTone }),
4276
+ children: resolvedBadge
4233
4277
  }
4234
4278
  ) : null
4235
4279
  ]
4236
4280
  }
4237
4281
  );
4282
+ if (tooltip === void 0) return button;
4283
+ return /* @__PURE__ */ jsx22(TooltipProvider, { children: /* @__PURE__ */ jsxs20(
4284
+ Tooltip,
4285
+ {
4286
+ open: tooltipOpen && !isDisabled,
4287
+ onOpenChange: (open) => setTooltipOpen(open && !isDisabled),
4288
+ children: [
4289
+ /* @__PURE__ */ jsx22(
4290
+ TooltipTrigger,
4291
+ {
4292
+ asChild: true,
4293
+ onFocus: (event) => {
4294
+ const root = event.currentTarget.getRootNode();
4295
+ if (!tabbing || root.activeElement !== event.currentTarget) event.preventDefault();
4296
+ },
4297
+ children: button
4298
+ }
4299
+ ),
4300
+ /* @__PURE__ */ jsx22(TooltipContent, { side: tooltipSide, children: tooltipText })
4301
+ ]
4302
+ }
4303
+ ) });
4238
4304
  }
4239
4305
  );
4240
4306
  IconButton.displayName = "IconButton";
@@ -4362,14 +4428,32 @@ var OverlayScrimLayer = React26.forwardRef(
4362
4428
  }
4363
4429
  );
4364
4430
  OverlayScrimLayer.displayName = "OverlayScrimLayer";
4431
+ var TABBABLE_CANDIDATE = 'a[href], button, input, select, textarea, [tabindex], [contenteditable]:not([contenteditable="false"])';
4432
+ var INPUT_CANDIDATE = "input, textarea, select";
4433
+ function isTabbable(element) {
4434
+ if (element.matches(":disabled") || element instanceof HTMLInputElement && element.type === "hidden") return false;
4435
+ if (element.hasAttribute("tabindex") && element.tabIndex < 0) return false;
4436
+ if (element.closest('[hidden], [inert], [aria-hidden="true"]')) return false;
4437
+ if (typeof element.checkVisibility === "function") return element.checkVisibility({ visibilityProperty: true });
4438
+ const view = element.ownerDocument.defaultView;
4439
+ if (!view) return true;
4440
+ if (["hidden", "collapse"].includes(view.getComputedStyle(element).visibility)) return false;
4441
+ for (let node = element; node; node = node.parentElement) {
4442
+ if (view.getComputedStyle(node).display === "none") return false;
4443
+ }
4444
+ return true;
4445
+ }
4446
+ var firstTabbable = (root, selector) => [...root.querySelectorAll(selector)].find(isTabbable);
4365
4447
  function focusBodyInput(event) {
4366
4448
  const surface = event.target instanceof HTMLElement ? event.target : null;
4367
- const input = surface?.querySelector(
4368
- '[data-slot="overlay-body"] :is(input, textarea, select):not([disabled]):not([type="hidden"])'
4369
- );
4370
- if (input) {
4371
- event.preventDefault();
4449
+ if (!surface) return;
4450
+ for (const input of surface.querySelectorAll(`:is([data-slot="overlay-body"], [data-slot="overlay-list"]) :is(${INPUT_CANDIDATE})`)) {
4451
+ if (!isTabbable(input)) continue;
4372
4452
  input.focus();
4453
+ if (input.ownerDocument.activeElement === input) {
4454
+ event.preventDefault();
4455
+ return;
4456
+ }
4373
4457
  }
4374
4458
  }
4375
4459
  var headingClassName = {
@@ -4387,6 +4471,7 @@ function OverlayHeader({
4387
4471
  caption,
4388
4472
  actions,
4389
4473
  closeLabel = "\uB2EB\uAE30",
4474
+ titleHidden = false,
4390
4475
  dragHandleProps,
4391
4476
  id,
4392
4477
  className
@@ -4410,7 +4495,7 @@ function OverlayHeader({
4410
4495
  children: [
4411
4496
  /* @__PURE__ */ jsxs21("div", { className: "flex min-w-0 flex-1 flex-col gap-[var(--space-2)]", children: [
4412
4497
  caption != null ? /* @__PURE__ */ jsx24("div", { "data-slot": "overlay-caption", className: "flex flex-wrap items-center gap-[var(--space-2)]", children: caption }) : null,
4413
- /* @__PURE__ */ jsx24(Title, { "data-slot": "overlay-title", className: headingClassName[policy.heading], children: title }),
4498
+ /* @__PURE__ */ jsx24(Title, { "data-slot": "overlay-title", className: cn(headingClassName[policy.heading], titleHidden && "sr-only"), children: title }),
4414
4499
  description != null ? /* @__PURE__ */ jsx24(Description, { "data-slot": "overlay-description", className: descriptionClassName[policy.heading], children: description }) : null
4415
4500
  ] }),
4416
4501
  actions != null || policy.closeButton === "visible" ? /* @__PURE__ */ jsxs21("div", { "data-slot": "overlay-header-actions", className: "flex shrink-0 items-center gap-[var(--space-1)]", children: [
@@ -4439,28 +4524,18 @@ var fogClassName = cn(
4439
4524
  "pointer-events-none sticky z-[1] block h-[var(--space-6)] shrink-0 opacity-0",
4440
4525
  "from-[var(--bg-raised)] to-transparent"
4441
4526
  );
4442
- function OverlayBody({ kind, className, children, ...props }) {
4443
- const { scroll } = OVERLAY_POLICY[kind];
4444
- if (scroll !== "body") {
4445
- return /* @__PURE__ */ jsx24(
4446
- "div",
4447
- {
4448
- "data-slot": "overlay-body",
4449
- className: cn(
4450
- "min-w-0 px-[var(--space-6)] pt-[var(--space-4)] text-[14px] leading-relaxed text-text-secondary",
4451
- scroll === "list" && "min-h-0 flex-1 overflow-y-auto px-0",
4452
- className
4453
- ),
4454
- ...props,
4455
- children
4456
- }
4457
- );
4458
- }
4527
+ function FogScroller({
4528
+ scrollerRef,
4529
+ className,
4530
+ contentClassName,
4531
+ children,
4532
+ ...props
4533
+ }) {
4459
4534
  return /* @__PURE__ */ jsxs21(
4460
4535
  "div",
4461
4536
  {
4462
- "data-slot": "overlay-body",
4463
- className: "relative flex min-h-0 flex-1 flex-col overflow-y-auto [container-type:scroll-state]",
4537
+ ref: scrollerRef,
4538
+ className: cn("relative flex min-h-0 flex-col overflow-y-auto [container-type:scroll-state]", className),
4464
4539
  ...props,
4465
4540
  children: [
4466
4541
  /* @__PURE__ */ jsx24(
@@ -4471,7 +4546,7 @@ function OverlayBody({ kind, className, children, ...props }) {
4471
4546
  className: cn(fogClassName, "top-0 -mb-[var(--space-6)] bg-linear-to-b", "[@container_scroll-state(scrollable:top)]:opacity-100")
4472
4547
  }
4473
4548
  ),
4474
- /* @__PURE__ */ jsx24("div", { className: cn("min-w-0 px-[var(--space-6)] py-[var(--space-4)]", className), children }),
4549
+ /* @__PURE__ */ jsx24("div", { className: contentClassName, children }),
4475
4550
  /* @__PURE__ */ jsx24(
4476
4551
  "span",
4477
4552
  {
@@ -4484,6 +4559,90 @@ function OverlayBody({ kind, className, children, ...props }) {
4484
4559
  }
4485
4560
  );
4486
4561
  }
4562
+ function OverlayBody({ kind, fixed = false, className, children, ...props }) {
4563
+ const { scroll } = OVERLAY_POLICY[kind];
4564
+ if (fixed) {
4565
+ return /* @__PURE__ */ jsx24(
4566
+ "div",
4567
+ {
4568
+ "data-slot": "overlay-body",
4569
+ className: cn(
4570
+ "relative z-[2] -mb-[var(--space-1)] min-h-0 min-w-0 shrink overflow-y-auto px-[var(--space-6)] pt-[var(--space-4)] pb-[var(--space-1)]",
4571
+ className
4572
+ ),
4573
+ ...props,
4574
+ children
4575
+ }
4576
+ );
4577
+ }
4578
+ if (scroll !== "body") {
4579
+ return /* @__PURE__ */ jsx24(
4580
+ "div",
4581
+ {
4582
+ "data-slot": "overlay-body",
4583
+ className: cn(
4584
+ "min-w-0 px-[var(--space-6)] pt-[var(--space-4)] text-[14px] leading-relaxed text-text-secondary",
4585
+ scroll === "list" && "min-h-0 flex-1 overflow-y-auto px-0",
4586
+ className
4587
+ ),
4588
+ ...props,
4589
+ children
4590
+ }
4591
+ );
4592
+ }
4593
+ return /* @__PURE__ */ jsx24(FogScroller, { "data-slot": "overlay-body", className: "flex-1", contentClassName: cn("min-w-0 px-[var(--space-6)] py-[var(--space-4)]", className), ...props, children });
4594
+ }
4595
+ var listBoxClassName = {
4596
+ max: {
4597
+ sm: "basis-[content] max-h-[calc(216px+var(--space-3)+var(--space-4))]",
4598
+ md: "basis-[content] max-h-[calc(460px+var(--space-3)+var(--space-4))]",
4599
+ lg: "basis-[content] max-h-[calc(628px+var(--space-3)+var(--space-4))]"
4600
+ },
4601
+ fixed: {
4602
+ sm: "basis-[calc(216px+var(--space-3)+var(--space-4))]",
4603
+ md: "basis-[calc(460px+var(--space-3)+var(--space-4))]",
4604
+ lg: "basis-[calc(628px+var(--space-3)+var(--space-4))]"
4605
+ }
4606
+ };
4607
+ var listFloorClassName = "h-[calc(112px+var(--space-3))]";
4608
+ function OverlayList({ height = "md", fit = "max", label, children }) {
4609
+ const ref = React26.useRef(null);
4610
+ const [hasFocusable, setHasFocusable] = React26.useState(true);
4611
+ React26.useLayoutEffect(() => {
4612
+ const node = ref.current;
4613
+ if (!node) return;
4614
+ const check = () => setHasFocusable(firstTabbable(node, TABBABLE_CANDIDATE) != null);
4615
+ check();
4616
+ let frame = 0;
4617
+ const observer = new MutationObserver(() => {
4618
+ frame ||= requestAnimationFrame(() => {
4619
+ frame = 0;
4620
+ check();
4621
+ });
4622
+ });
4623
+ observer.observe(node, {
4624
+ childList: true,
4625
+ subtree: true,
4626
+ attributes: true,
4627
+ attributeFilter: ["aria-hidden", "class", "contenteditable", "disabled", "hidden", "href", "inert", "style", "tabindex", "type"]
4628
+ });
4629
+ return () => {
4630
+ observer.disconnect();
4631
+ cancelAnimationFrame(frame);
4632
+ };
4633
+ }, []);
4634
+ return /* @__PURE__ */ jsx24("div", { "data-slot": "overlay-list-box", className: cn("flex shrink-[10000] flex-col", listFloorClassName, listBoxClassName[fit][height]), children: /* @__PURE__ */ jsx24(
4635
+ FogScroller,
4636
+ {
4637
+ scrollerRef: ref,
4638
+ "data-slot": "overlay-list",
4639
+ className: "flex-auto outline-none focus-visible:inset-ring-2 focus-visible:inset-ring-[var(--focus-ring)]",
4640
+ contentClassName: "min-w-0 px-[var(--space-6)] pt-[var(--space-3)] pb-[var(--space-4)]",
4641
+ ...!hasFocusable && { tabIndex: 0, role: "region", "aria-label": label },
4642
+ children
4643
+ }
4644
+ ) });
4645
+ }
4487
4646
  function OverlayFooter({ kind, className, ...props }) {
4488
4647
  const { footerDivider } = OVERLAY_POLICY[kind];
4489
4648
  return /* @__PURE__ */ jsx24(
@@ -4840,8 +4999,13 @@ function StructuredDialog({
4840
4999
  onOpenChange,
4841
5000
  title,
4842
5001
  description,
5002
+ hideTitle = false,
4843
5003
  size = "md",
4844
5004
  children,
5005
+ list,
5006
+ listHeight = "md",
5007
+ listFit = "max",
5008
+ listLabel = title,
4845
5009
  footer,
4846
5010
  onSubmit,
4847
5011
  onError,
@@ -4863,7 +5027,13 @@ function StructuredDialog({
4863
5027
  const returnFocus = useReturnFocus();
4864
5028
  const surfaceRef = React28.useRef(null);
4865
5029
  const swipe = useSwipeDismiss({ enabled: policy.swipe, onDismiss: () => guardOpenChange(false), surfaceRef });
4866
- const body = /* @__PURE__ */ jsx26(OverlayBody, { kind: "dialog", className, children });
5030
+ const body = list != null ? (
5031
+ // Scrolls only on a screen too low for the body's 16 and the list floor; the footer stays.
5032
+ /* @__PURE__ */ jsxs23("div", { "data-slot": "overlay-list-frame", className: "flex min-h-0 flex-col overflow-y-auto", children: [
5033
+ /* @__PURE__ */ jsx26(OverlayBody, { kind: "dialog", fixed: true, className, children }),
5034
+ /* @__PURE__ */ jsx26(OverlayList, { height: listHeight, fit: listFit, label: listLabel, children: list })
5035
+ ] })
5036
+ ) : /* @__PURE__ */ jsx26(OverlayBody, { kind: "dialog", className, children });
4867
5037
  const footerRow = formMode ? /* @__PURE__ */ jsxs23(OverlayFooter, { kind: "dialog", children: [
4868
5038
  /* @__PURE__ */ jsx26(
4869
5039
  Button,
@@ -4902,6 +5072,7 @@ function StructuredDialog({
4902
5072
  kind: "dialog",
4903
5073
  title,
4904
5074
  description,
5075
+ titleHidden: hideTitle,
4905
5076
  closeLabel,
4906
5077
  dragHandleProps: swipe.handleProps
4907
5078
  }
@@ -6473,7 +6644,7 @@ function ActionMenu({
6473
6644
  // src/components/ui/checkbox.tsx
6474
6645
  import * as React33 from "react";
6475
6646
  import { cva as cva12 } from "class-variance-authority";
6476
- import { Check as Check3, Minus } from "lucide-react";
6647
+ import { Check as Check4, Minus } from "lucide-react";
6477
6648
  import { Checkbox as CheckboxPrimitive } from "radix-ui";
6478
6649
  import { jsx as jsx35, jsxs as jsxs31 } from "react/jsx-runtime";
6479
6650
  var checkboxFieldVariants = cva12(
@@ -6667,7 +6838,7 @@ var Checkbox = React33.forwardRef(
6667
6838
  {
6668
6839
  "data-slot": "checkbox-indicator",
6669
6840
  className: "flex items-center justify-center",
6670
- children: resolvedChecked === "indeterminate" ? /* @__PURE__ */ jsx35(Minus, { "aria-hidden": "true", size: 14, strokeWidth: 2.5 }) : /* @__PURE__ */ jsx35(Check3, { "aria-hidden": "true", size: 14, strokeWidth: 2.5 })
6841
+ children: resolvedChecked === "indeterminate" ? /* @__PURE__ */ jsx35(Minus, { "aria-hidden": "true", size: 14, strokeWidth: 2.5 }) : /* @__PURE__ */ jsx35(Check4, { "aria-hidden": "true", size: 14, strokeWidth: 2.5 })
6671
6842
  }
6672
6843
  )
6673
6844
  }
@@ -6756,7 +6927,7 @@ var Checkbox = React33.forwardRef(
6756
6927
  {
6757
6928
  "data-slot": "checkbox-indicator",
6758
6929
  className: "flex items-center justify-center",
6759
- children: resolvedChecked === "indeterminate" ? /* @__PURE__ */ jsx35(Minus, { "aria-hidden": "true", size: 14, strokeWidth: 2.5 }) : /* @__PURE__ */ jsx35(Check3, { "aria-hidden": "true", size: 14, strokeWidth: 2.5 })
6930
+ children: resolvedChecked === "indeterminate" ? /* @__PURE__ */ jsx35(Minus, { "aria-hidden": "true", size: 14, strokeWidth: 2.5 }) : /* @__PURE__ */ jsx35(Check4, { "aria-hidden": "true", size: 14, strokeWidth: 2.5 })
6760
6931
  }
6761
6932
  )
6762
6933
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@olundot/ui",
3
- "version": "0.20.0",
3
+ "version": "0.20.1",
4
4
  "description": "OLUN. shared React UI components built on OLUN design tokens",
5
5
  "license": "MIT",
6
6
  "keywords": [