@olundot/ui 0.12.0 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,93 @@
1
1
  # @olundot/ui
2
2
 
3
+ ## 0.13.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 0f4ad55: Card: promote `interactive` from a variant to an orthogonal boolean prop (breaking)
8
+
9
+ `interactive` is removed from the `variant` enum and becomes a standalone `interactive?: boolean` prop. A clickable card can now combine with any resting surface — `default`, `elevated`, or `notice` — whereas the old `variant="interactive"` was mutually exclusive with those.
10
+
11
+ - **Before:** `<Card variant="interactive">`
12
+ - **After:** `<Card interactive>` (and now also `<Card variant="notice" interactive>`, `<Card variant="elevated" interactive>`).
13
+
14
+ Interactive hover lifts the shadow one step above the variant's resting depth: default/notice rest at `--shadow-2` → hover `--shadow-4`; elevated rests at `--shadow-4` → hover `--shadow-8`. The pointer cursor, hover border (`--border-strong`) / background (`--action-hover`), and neutral focus-ring (`--focus-ring`) are unchanged. `selected` / `disabled` relationships are unchanged.
15
+
16
+ `notice`'s accent border is retained; it is now documented under accent rationing role ③ (read-only emphasis context only), not treated as an exception.
17
+
18
+ - 8a0bfe3: Align Card with the v0.14 flattened surface model (breaking-visual)
19
+
20
+ After v0.14 flattening (card fill == page background), Card was the one component still leaning on removed lift affordances. Its rest/selected/focus handoff is now brought back in line. Public API (`variant`, `surface`, `selected`, `disabled`, slots) is unchanged — only rendered classes/visuals change.
21
+
22
+ - **Rest edge/radius:** base border `--border-subtle` → `--border` (0.10 alpha) and corner `--radius-md` (8px) → `--radius-lg` (12px, the "cards" radius). The `default` variant now carries a resting `--shadow-2` so a flat card still reads as a bounded surface.
23
+ - **Elevated:** `--shadow-2` → `--shadow-4`, keeping its meaning as the more-raised card now that `default` owns `--shadow-2`.
24
+ - **Selected:** fill `--bg-canvas` (a lift that vanished under flattening) → `--action-selected`, the same neutral surface-lift used by DataTable/TreeView selected rows; `--border-strong` retained.
25
+ - **Focus:** `interactive` focus drops the accent border + lime glow (`--border-accent` + `--glow-sm`) for the house neutral focus-ring convention (`--focus-ring` border + `0 0 0 1px --focus-ring` ring), matching Input. The dark `hover` accent glow is also removed (hover = `--border-strong` + `--shadow-2`), honoring accent rationing (accent is never used for action/focus surfaces).
26
+
27
+ `notice` (accent border) is unchanged.
28
+
29
+ - dca4628: Remove DataTable's built-in selection bar; consolidate bulk actions on BulkActionBar (breaking)
30
+
31
+ DataTable now exposes a single bulk-action surface. The internal top selection strip is deleted and all bulk actions move to the floating bottom `BulkActionBar` — matching the "one batch-action surface, no persistent chrome" baseline.
32
+
33
+ **Breaking — DataTable:**
34
+
35
+ - Removed the `selectionBar` (`'top' | 'none'`) and `bulkActions` props, the `DataTableBulkAction` type/export, and the built-in `data-slot="data-table-selection-bar"` strip (which always reserved a 48px row and showed a "선택된 행 없음" placeholder).
36
+ - **Kept** the selection mechanism: `selectable`, `selectedIds`, `onSelectionChange`, header select-all (indeterminate) + per-row checkboxes. The selected-count announcement is preserved as a visually-hidden `aria-live` region (`data-slot="data-table-selection-status"`), so there is no accessibility regression.
37
+ - Migration: drop `bulkActions`/`selectionBar` and render a sibling `<BulkActionBar count={selectedIds.size} onClear={…} actions={…} />`. See `docs/MIGRATION-0.13.0-to-0.14.0.md` §5.
38
+
39
+ **BulkActionBar hardening:**
40
+
41
+ - Bottom offset now respects the iOS safe area: `bottom: calc(var(--space-4) + env(safe-area-inset-bottom))`.
42
+ - Subtle entrance motion when it appears (`olun-bulk-action-bar-in`: translateY 8px + fade, `var(--dur-fast) var(--ease-out)`), opted out under `prefers-reduced-motion` via `motion-reduce:animate-none` + the global reduced-motion guard.
43
+ - Do not use on the same screen as `ActionFooter` — both occupy the bottom and overlap at `z-index` 1100 (documented, not enforced in code).
44
+
45
+ - 676476c: Align internal token references to v0.14 canonical names
46
+
47
+ `@olundot/ui` now references the canonical v0.14 token names directly instead of the pre-v0.14 aliases that survive in `@olundot/tokens`' compat layer. Public component APIs are unchanged; only the token names emitted in class strings/styles change.
48
+
49
+ - **Accent:** `--accent-fg` → `--accent`, `--accent-solid` → `--accent-pop`, `--accent-on-solid` → `--accent-on-fill` (button, chip, icon-button); two-tier-badge's legacy `text-accent-fg` utility class → `text-[var(--accent)]`.
50
+ - **Elevation:** `shadow-[var(--elevation-{1,2,4})]` → `shadow-[var(--shadow-{1,2,4})]` (card, confirm-dialog, form-modal, info-modal, mode-toggle, popover, sheet-drawer, toast, theme-fab); legacy `shadow-elevation-{2,8}` utility classes → `shadow-{2,8}` (dropdown-menu, dialog).
51
+ - **Motion:** `--duration-fast` → `--dur-fast` and `theme.ts`'s `var(--duration-${d})` template → an explicit `--dur-*`/literal mapping (mode-toggle, tabs, tree-view, `lib/theme.ts`). Sheet's public `easing` prop keeps its `standard/decel/accel/sharp/bounce` surface; its internal map now uses canonical `--ease-standard/--ease-in/--ease-out`, with `decel`/`sharp` still referencing the compat-frozen `--easing-decel`/`--easing-sharp` beziers (no canonical equivalent).
52
+ - **Semantic:** the `tokens.css` `@theme` block maps `--color-semantic-*` off `--semantic-*-fg` (was `--semantic-*`).
53
+
54
+ The canonical motion tokens carry the intended v0.14 re-tuning (fast/base/slow 150/200/300 → 120/180/260ms), so transition timings shift accordingly.
55
+
56
+ - 52714f9: Rewrite TwoTierBadge to the handoff horizontal-pill model (breaking)
57
+
58
+ TwoTierBadge moves from a vertical two-box stack with dual independent intents to the design-canonical **horizontal two-segment pill**: a `primary` lead segment and an optional `secondary` qualifier split by a hairline vertical divider, clipped to a full-round pill. It now shares the Badge/StatusBadge/Chip grammar.
59
+
60
+ **Breaking API change:**
61
+
62
+ - **Removed:** `primaryIntent`, `secondaryIntent`, `align`, `primaryClassName`, `secondaryClassName`, the `brand`/`muted` intents, and the `twoTierBadgeVariants` / `twoTierBadgeLineVariants` / `TwoTierBadgeIntent` exports.
63
+ - **Added:** a single `tone` axis (`neutral` · `info` · `success` · `warning` · `error`) that colors the **lead segment only** — the qualifier always stays neutral, and the brand lime is never spent here (accent rationing). Plus `emphasis` (`subtle`/`strong`, mirrors StatusBadge), `size` (`xs`/`sm`/`md`), and `showDot`. New type exports: `TwoTierBadgeTone`, `TwoTierBadgeEmphasis`, `TwoTierBadgeSize`.
64
+ - The root element is now a `<span>` (was `<div>`); `data-slot` names are unchanged (`two-tier-badge` / `-primary` / `-secondary`).
65
+
66
+ ### Before
67
+
68
+ ```tsx
69
+ <TwoTierBadge
70
+ primary="예약"
71
+ secondary="검토 필요"
72
+ primaryIntent="brand"
73
+ secondaryIntent="warning"
74
+ />
75
+ ```
76
+
77
+ ### After
78
+
79
+ ```tsx
80
+ <TwoTierBadge primary="예약" tone="info" secondary="검토 필요" />
81
+ <TwoTierBadge primary="반려" tone="error" emphasis="strong" secondary="중복 문항" />
82
+ ```
83
+
84
+ Map old intents to tone: `brand`→(drop, use `info`/neutral — lime is never used), `muted`→`neutral`, `danger`→`error`, `success`/`warning`/`info` unchanged. The old `secondaryIntent` has no equivalent — the qualifier is always neutral by design.
85
+
86
+ ### Patch Changes
87
+
88
+ - Updated dependencies [966c3f6]
89
+ - @olundot/tokens@0.14.0
90
+
3
91
  ## 0.12.0
4
92
 
5
93
  ### Minor Changes
package/README.md CHANGED
@@ -36,4 +36,4 @@ This beta package is extracted from the OLUN CBT/LMS shared UI implementation. A
36
36
 
37
37
  ## Accent Contract
38
38
 
39
- Filled accent buttons must pair `--accent-solid` for the background/border with `--accent-on-solid` for text and icons. `--accent-on-fill` remains a backward-compatible alias only and is not allowed in new `Button` source.
39
+ Primary and default buttons are monochrome: pair `--primary` for the background and border with `--primary-fg` for text and icons. Brand and opt-in accent fills use the canonical `--accent-pop` + `--accent-on-fill` pair. The pre-v0.14 names `--accent-solid` and `--accent-on-solid` remain deprecated compatibility aliases and must not be used in new component source.
package/dist/index.d.ts CHANGED
@@ -416,14 +416,15 @@ declare function evaluatePermission(permission: string, state?: PermissionEvalua
416
416
  declare function PermissionGuard({ permission, children, fallback, scope, permissions, disabledReason, }: PermissionGuardProps): react_jsx_runtime.JSX.Element | null;
417
417
 
418
418
  declare const cardBaseVariants: (props?: ({
419
- variant?: "default" | "elevated" | "notice" | "interactive" | null | undefined;
419
+ variant?: "default" | "elevated" | "notice" | null | undefined;
420
+ interactive?: boolean | null | undefined;
420
421
  } & class_variance_authority_types.ClassProp) | undefined) => string;
421
422
  type CardVariant = NonNullable<VariantProps<typeof cardBaseVariants>["variant"]>;
422
423
  interface CardVariantOptions extends VariantProps<typeof cardBaseVariants> {
423
424
  surface?: SurfaceLevel;
424
425
  className?: string;
425
426
  }
426
- declare function cardVariants({ variant, surface, className }?: CardVariantOptions): string;
427
+ declare function cardVariants({ variant, surface, interactive, className }?: CardVariantOptions): string;
427
428
  interface CardProps extends React.HTMLAttributes<HTMLDivElement>, VariantProps<typeof cardBaseVariants> {
428
429
  /**
429
430
  * Background level for the card surface. When omitted, `variant` chooses the
@@ -431,6 +432,12 @@ interface CardProps extends React.HTMLAttributes<HTMLDivElement>, VariantProps<t
431
432
  * Selected and disabled states take precedence.
432
433
  */
433
434
  surface?: SurfaceLevel;
435
+ /**
436
+ * Clickable affordance — orthogonal to `variant`. Adds hover lift (shadow +
437
+ * border-strong), a pointer cursor and the neutral focus-ring. Combine with
438
+ * any `variant` (default/elevated/notice).
439
+ */
440
+ interactive?: boolean;
434
441
  selected?: boolean;
435
442
  disabled?: boolean;
436
443
  }
@@ -691,11 +698,6 @@ interface DataTableSort {
691
698
  key: string;
692
699
  dir: 'asc' | 'desc';
693
700
  }
694
- interface DataTableBulkAction {
695
- label: React.ReactNode;
696
- onClick: (ids: Set<string>) => void;
697
- variant?: 'default' | 'destructive';
698
- }
699
701
  interface DataTableProps<T> extends Omit<React.HTMLAttributes<HTMLDivElement>, 'children'>, VariantProps<typeof dataTableVariants> {
700
702
  columns: DataTableColumn<T>[];
701
703
  data: T[];
@@ -703,19 +705,17 @@ interface DataTableProps<T> extends Omit<React.HTMLAttributes<HTMLDivElement>, '
703
705
  selectable?: boolean;
704
706
  selectedIds?: Set<string>;
705
707
  onSelectionChange?: (ids: Set<string>) => void;
706
- selectionBar?: 'top' | 'none';
707
708
  activeRowId?: string;
708
709
  onRowContextMenu?: (rowId: string, event: React.MouseEvent) => void;
709
710
  sortBy?: DataTableSort;
710
711
  onSortChange?: (key: string, dir: 'asc' | 'desc' | null) => void;
711
712
  loading?: boolean;
712
713
  emptyState?: React.ReactNode;
713
- bulkActions?: DataTableBulkAction[];
714
714
  rowHref?: (row: T) => string;
715
715
  skeletonRowCount?: number;
716
716
  /**
717
- * Background level for the table container. Header, selected rows, active
718
- * selection bars, loading, and empty states keep their own state styling.
717
+ * Background level for the table container. Header, selected rows, loading,
718
+ * and empty states keep their own state styling.
719
719
  */
720
720
  surface?: SurfaceLevel;
721
721
  }
@@ -794,7 +794,7 @@ interface BulkActionBarProps extends React.HTMLAttributes<HTMLDivElement> {
794
794
  * { key: "del", label: "삭제", variant: "destructive", onClick: confirmDelete },
795
795
  * ]} />
796
796
  */
797
- declare function BulkActionBar({ count, actions, onClear, emptyHint, style, ...props }: BulkActionBarProps): react_jsx_runtime.JSX.Element | null;
797
+ declare function BulkActionBar({ count, actions, onClear, emptyHint, className, style, ...props }: BulkActionBarProps): react_jsx_runtime.JSX.Element | null;
798
798
 
799
799
  declare const Dialog: React.FC<Dialog$1.DialogProps>;
800
800
  declare const DialogTrigger: React.ForwardRefExoticComponent<Dialog$1.DialogTriggerProps & React.RefAttributes<HTMLButtonElement>>;
@@ -953,23 +953,38 @@ interface BadgeProps extends React.HTMLAttributes<HTMLSpanElement> {
953
953
  }
954
954
  declare const Badge: React.ForwardRefExoticComponent<BadgeProps & React.RefAttributes<HTMLSpanElement>>;
955
955
 
956
- declare const twoTierBadgeVariants: (props?: ({
957
- align?: "end" | "start" | "center" | null | undefined;
958
- } & class_variance_authority_types.ClassProp) | undefined) => string;
959
- declare const twoTierBadgeLineVariants: (props?: ({
960
- tier?: "primary" | "secondary" | null | undefined;
961
- intent?: "brand" | "muted" | "warning" | "success" | "neutral" | "danger" | null | undefined;
962
- } & class_variance_authority_types.ClassProp) | undefined) => string;
963
- type TwoTierBadgeIntent = NonNullable<VariantProps<typeof twoTierBadgeLineVariants>["intent"]>;
964
- interface TwoTierBadgeProps extends React.HTMLAttributes<HTMLDivElement>, VariantProps<typeof twoTierBadgeVariants> {
956
+ type TwoTierBadgeTone = 'neutral' | 'info' | 'success' | 'warning' | 'error';
957
+ type TwoTierBadgeEmphasis = 'subtle' | 'strong';
958
+ type TwoTierBadgeSize = 'xs' | 'sm' | 'md';
959
+ interface TwoTierBadgeProps extends React.HTMLAttributes<HTMLSpanElement> {
960
+ /** Lead facet — the headline segment (type, state, label). */
965
961
  primary: React.ReactNode;
962
+ /** Trailing qualifier segment (source, reason, count). Omit for a single-segment badge. */
966
963
  secondary?: React.ReactNode;
967
- primaryIntent?: TwoTierBadgeIntent;
968
- secondaryIntent?: TwoTierBadgeIntent;
969
- primaryClassName?: string;
970
- secondaryClassName?: string;
964
+ /** Semantic role — colors the LEAD segment only; the qualifier stays neutral. Brand lime is never used. */
965
+ tone?: TwoTierBadgeTone;
966
+ /** Weight axis (mirrors StatusBadge): `subtle` outlined pill, `strong` tinted lead fill. */
967
+ emphasis?: TwoTierBadgeEmphasis;
968
+ /** xs · sm (default) · md — padding + text + dot scale. */
969
+ size?: TwoTierBadgeSize;
970
+ /** Leading status dot on the lead segment (default false). Hollow ring for neutral. */
971
+ showDot?: boolean;
971
972
  }
972
- declare const TwoTierBadge: React.ForwardRefExoticComponent<TwoTierBadgeProps & React.RefAttributes<HTMLDivElement>>;
973
+ /**
974
+ * OLUN TwoTierBadge — carries TWO related facets in ONE horizontal pill: a
975
+ * `primary` lead segment and an optional `secondary` qualifier, split by a
976
+ * hairline vertical divider (유형│출처, 상태│사유, 완료│312명). Shares the
977
+ * Badge/StatusBadge/Chip grammar: full-pill shape, `--font-sans`, the same 5
978
+ * semantic roles (`tone`) and the `subtle`/`strong` emphasis axis. `tone` colors
979
+ * the lead segment only; the qualifier stays neutral and the brand lime is never
980
+ * spent here. With no `secondary` it degrades to a plain semantic pill — prefer
981
+ * StatusBadge for pure state. Forwards its ref.
982
+ *
983
+ * @example
984
+ * <TwoTierBadge primary="객관식" secondary="순환기내과" />
985
+ * <TwoTierBadge primary="반려" tone="error" emphasis="strong" secondary="중복 문항" />
986
+ */
987
+ declare const TwoTierBadge: React.ForwardRefExoticComponent<TwoTierBadgeProps & React.RefAttributes<HTMLSpanElement>>;
973
988
 
974
989
  type StatusBadgeStatus = 'active' | 'archived' | 'success' | 'warning' | 'error' | 'info' | 'pending';
975
990
  type StatusBadgeEmphasis = 'subtle' | 'strong';
@@ -1523,8 +1538,8 @@ declare function TreeView<T extends TreeNode>({ nodes, selectedId, selectionAria
1523
1538
  /**
1524
1539
  * OLUN 브랜드 로고.
1525
1540
  *
1526
- * - symbol: O 원형 테두리 + 우하단 accent-solid 작은 circle
1527
- * - wordmark: "OLUN" + 마지막 "." 은 accent-fg 색상
1541
+ * - symbol: O 원형 테두리 + 우하단 accent-pop 작은 circle
1542
+ * - wordmark: "OLUN" + 마지막 "." 은 accent 색상
1528
1543
  *
1529
1544
  * 레퍼런스: apps/web/docs/wireframes/ref/shell-wireframe.html Topbar 브랜드 영역.
1530
1545
  */
@@ -1568,4 +1583,4 @@ interface OrganizationLogoProps extends Omit<SVGProps<SVGSVGElement>, "width" |
1568
1583
  }
1569
1584
  declare function OrganizationLogo({ organization, size, className, style, role, "aria-label": ariaLabel, "aria-hidden": ariaHidden, ...props }: OrganizationLogoProps): react_jsx_runtime.JSX.Element;
1570
1585
 
1571
- export { ActionFooter, type ActionFooterAction, type ActionFooterProps, type ActionFooterStatus, Alert, type AlertEmphasis, 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, type ButtonVariant, 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 DataTableBulkAction, type DataTableColumn, type DataTableProps, type DataTableSort, DetailLayout, type DetailLayoutProps, Dialog, DialogClose, DialogContent, DialogDescription, DialogEyebrow, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogRawContent, DialogTitle, DialogTrigger, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, EmptyState, type EmptyStateProps, type EmptyStateSize, type EmptyStateTone, type EmptyStateVariantOptions, ErrorState, type ErrorStateProps, FileUploadZone, type FileUploadZoneProps, FilterToolbar, type FilterToolbarProps, FormField, type FormFieldProps, type FormFieldRenderProps, FormLayout, type FormLayoutProps, type FormLayoutSection, FormModal, type FormModalProps, IconButton, type IconButtonBadgeTone, type IconButtonProps, type IconButtonSize, type IconButtonVariant, InfoModal, type InfoModalProps, InlineAlert, type InlineAlertProps, type InlineAlertSurface, Input, type InputProps, type InputSize, type InputSizeLegacy, type InputState, Label, type LabelProps, 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, 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, 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, type SurfaceLevel, Switch, type SwitchProps, type TabItem, 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 TwoTierBadgeIntent, type TwoTierBadgeProps, 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, skeletonVariants, spinnerVariants, tabsBadgeVariants, tabsListVariants, tabsRootVariants, tabsTriggerVariants, textareaMessageVariants, textareaVariants, toast, toastVariants, toastViewportVariants, treeItemRowVariants, treeViewVariants, twoTierBadgeLineVariants, twoTierBadgeVariants, useOlunTheme, usePermission };
1586
+ export { ActionFooter, type ActionFooterAction, type ActionFooterProps, type ActionFooterStatus, Alert, type AlertEmphasis, 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, type ButtonVariant, 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 DataTableProps, type DataTableSort, DetailLayout, type DetailLayoutProps, Dialog, DialogClose, DialogContent, DialogDescription, DialogEyebrow, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogRawContent, DialogTitle, DialogTrigger, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, EmptyState, type EmptyStateProps, type EmptyStateSize, type EmptyStateTone, type EmptyStateVariantOptions, ErrorState, type ErrorStateProps, FileUploadZone, type FileUploadZoneProps, FilterToolbar, type FilterToolbarProps, FormField, type FormFieldProps, type FormFieldRenderProps, FormLayout, type FormLayoutProps, type FormLayoutSection, FormModal, type FormModalProps, IconButton, type IconButtonBadgeTone, type IconButtonProps, type IconButtonSize, type IconButtonVariant, InfoModal, type InfoModalProps, InlineAlert, type InlineAlertProps, type InlineAlertSurface, Input, type InputProps, type InputSize, type InputSizeLegacy, type InputState, Label, type LabelProps, 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, 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, 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, type SurfaceLevel, Switch, type SwitchProps, type TabItem, 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, skeletonVariants, spinnerVariants, tabsBadgeVariants, tabsListVariants, tabsRootVariants, tabsTriggerVariants, textareaMessageVariants, textareaVariants, toast, toastVariants, toastViewportVariants, treeItemRowVariants, treeViewVariants, useOlunTheme, usePermission };
package/dist/index.js CHANGED
@@ -28,6 +28,14 @@ var durationMsByToken = {
28
28
  slower: 400,
29
29
  slowest: 600
30
30
  };
31
+ var transitionDurationVarByToken = {
32
+ instant: "0ms",
33
+ fast: "var(--dur-fast)",
34
+ base: "var(--dur-base)",
35
+ slow: "var(--dur-slow)",
36
+ slower: "400ms",
37
+ slowest: "600ms"
38
+ };
31
39
  var transitionCleanupTimer;
32
40
  var defaultThemeState = {
33
41
  theme: "light",
@@ -105,7 +113,7 @@ function setOlunTheme(nextTheme, options = {}) {
105
113
  root.dataset[TRANSITION_ATTR] = "true";
106
114
  root.style.setProperty(
107
115
  TRANSITION_DURATION_PROPERTY,
108
- `var(--duration-${duration})`
116
+ transitionDurationVarByToken[duration]
109
117
  );
110
118
  void root.offsetWidth;
111
119
  }
@@ -201,7 +209,7 @@ var buttonVariants = cva(
201
209
  default: "border-[var(--primary)] bg-[var(--primary)] text-[var(--primary-fg)] hover:bg-[var(--primary-hover)] hover:border-[var(--primary-hover)]",
202
210
  destructive: "border-[var(--error)] bg-[var(--error)] text-[var(--error-contrast)] hover:bg-[var(--error-hover)] hover:border-[var(--error-hover)]",
203
211
  secondary: "border-[var(--border-subtle)] bg-[var(--bg-surface)] text-foreground hover:border-[var(--border)] hover:bg-[var(--action-hover)]",
204
- link: "border-transparent bg-transparent px-0 text-[var(--accent-fg)] underline-offset-4 hover:underline"
212
+ link: "border-transparent bg-transparent px-0 text-[var(--accent)] underline-offset-4 hover:underline"
205
213
  },
206
214
  size: {
207
215
  // Cross-control height map: Button sm/md/lg match field controls sm/md/lg (30/32/36px).
@@ -2168,43 +2176,54 @@ import { cva as cva7 } from "class-variance-authority";
2168
2176
  import { jsx as jsx13 } from "react/jsx-runtime";
2169
2177
  var cardBaseVariants = cva7(
2170
2178
  [
2171
- "rounded-[var(--radius-md)] border border-[var(--border-subtle)]",
2179
+ "rounded-[var(--radius-lg)] border border-[var(--border)]",
2172
2180
  "px-pad-roomy-x py-pad-roomy-y text-foreground"
2173
2181
  ].join(" "),
2174
2182
  {
2175
2183
  variants: {
2176
2184
  variant: {
2177
- default: "",
2178
- elevated: "shadow-[var(--elevation-2)]",
2179
- notice: "border-[var(--border-accent)]",
2180
- interactive: [
2185
+ default: "shadow-[var(--shadow-2)]",
2186
+ elevated: "shadow-[var(--shadow-4)]",
2187
+ notice: "border-[var(--border-accent)] shadow-[var(--shadow-2)]"
2188
+ },
2189
+ interactive: {
2190
+ true: [
2181
2191
  "cursor-pointer",
2182
2192
  "transition-[transform,border-color,box-shadow,background-color]",
2183
2193
  "motion-reduce:transition-none",
2184
2194
  "hover:-translate-y-[1px] motion-reduce:hover:translate-y-0",
2185
2195
  "hover:border-[var(--border-strong)]",
2186
2196
  "hover:bg-[var(--action-hover)]",
2187
- "hover:shadow-[var(--elevation-2)]",
2188
- "dark:hover:shadow-[var(--elevation-2),var(--glow-sm)]",
2189
2197
  "focus-visible:outline-none",
2190
- "focus-visible:border-[var(--border-accent)]",
2191
- "focus-visible:shadow-[var(--elevation-2),var(--glow-sm)]"
2192
- ].join(" ")
2198
+ "focus-visible:border-[var(--focus-ring)]",
2199
+ "focus-visible:shadow-[0_0_0_1px_var(--focus-ring)]"
2200
+ ].join(" "),
2201
+ false: ""
2193
2202
  }
2194
2203
  },
2195
- defaultVariants: { variant: "default" }
2204
+ // Interactive hover lifts the shadow one step above the variant's resting depth.
2205
+ compoundVariants: [
2206
+ { variant: "default", interactive: true, class: "hover:shadow-[var(--shadow-4)]" },
2207
+ { variant: "notice", interactive: true, class: "hover:shadow-[var(--shadow-4)]" },
2208
+ { variant: "elevated", interactive: true, class: "hover:shadow-[var(--shadow-8)]" }
2209
+ ],
2210
+ defaultVariants: { variant: "default", interactive: false }
2196
2211
  }
2197
2212
  );
2198
2213
  function getCardDefaultSurface(variant) {
2199
2214
  return variant === "elevated" ? "raised" : "surface";
2200
2215
  }
2201
- function cardVariants({ variant, surface, className } = {}) {
2216
+ function cardVariants({ variant, surface, interactive, className } = {}) {
2202
2217
  const resolvedVariant = variant ?? "default";
2203
2218
  const resolvedSurface = surface ?? getCardDefaultSurface(resolvedVariant);
2204
- return cn(cardBaseVariants({ variant: resolvedVariant }), surfaceClassNames[resolvedSurface], className);
2219
+ return cn(
2220
+ cardBaseVariants({ variant: resolvedVariant, interactive: interactive ?? false }),
2221
+ surfaceClassNames[resolvedSurface],
2222
+ className
2223
+ );
2205
2224
  }
2206
2225
  var Card = React12.forwardRef(
2207
- ({ className, variant, surface, selected, disabled, "aria-disabled": ariaDisabled, ...props }, ref) => /* @__PURE__ */ jsx13(
2226
+ ({ className, variant, surface, interactive, selected, disabled, "aria-disabled": ariaDisabled, ...props }, ref) => /* @__PURE__ */ jsx13(
2208
2227
  "div",
2209
2228
  {
2210
2229
  ref,
@@ -2214,8 +2233,8 @@ var Card = React12.forwardRef(
2214
2233
  "aria-disabled": disabled ? true : ariaDisabled,
2215
2234
  className: cn(
2216
2235
  "group/card",
2217
- cardVariants({ variant, surface }),
2218
- selected && "border-[var(--border-strong)] bg-[var(--bg-canvas)]",
2236
+ cardVariants({ variant, surface, interactive }),
2237
+ selected && "border-[var(--border-strong)] bg-[var(--action-selected)]",
2219
2238
  disabled && "pointer-events-none cursor-not-allowed border-[var(--border-subtle)] bg-[var(--action-disabled-bg)] text-text-disabled",
2220
2239
  className
2221
2240
  ),
@@ -2958,7 +2977,7 @@ var tabsTriggerVariants = cva8(
2958
2977
  "relative inline-flex shrink-0 cursor-pointer items-center gap-[var(--space-2)]",
2959
2978
  "px-0 py-pad-compact-y text-body-sm font-medium",
2960
2979
  "text-text-secondary transition-colors",
2961
- "duration-[var(--duration-fast)] ease-[var(--ease-standard)]",
2980
+ "duration-[var(--dur-fast)] ease-[var(--ease-standard)]",
2962
2981
  "hover:text-foreground",
2963
2982
  "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--focus-ring)]",
2964
2983
  "disabled:cursor-not-allowed disabled:pointer-events-auto disabled:text-text-disabled disabled:hover:text-text-disabled",
@@ -3384,9 +3403,9 @@ var DialogContent = React20.forwardRef(({ className, children, showCloseButton =
3384
3403
  // modal은 dim overlay 위 — 가장 밝은 DS surface(--bg-base #F1F3F5·여전히 tinted·순백 아님)로 깨끗하게.
3385
3404
  // arbitrary var 사용: 소비 site/app이 dist를 content-scan 안 해 `bg-base` 유틸이 purge될 수 있어 안전하게 var로.
3386
3405
  "bg-[var(--bg-base)] text-foreground",
3387
- // 2026: generic 무거운 그림자 대신 floating elevation-8 + 또렷한 중립 grey border(--border·16%) + radius-lg.
3406
+ // 2026: generic 무거운 그림자 대신 floating shadow-8 + 또렷한 중립 grey border(--border·16%) + radius-lg.
3388
3407
  // (border-subtle=8%는 너무 흐려 가장자리가 안 보였음 → border-border로 grey 또렷하게.)
3389
- "border border-border rounded-[var(--radius-lg)] shadow-elevation-8",
3408
+ "border border-border rounded-[var(--radius-lg)] shadow-8",
3390
3409
  "duration-200",
3391
3410
  "data-[state=open]:animate-in data-[state=closed]:animate-out",
3392
3411
  "data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
@@ -3497,7 +3516,7 @@ var formModalContentClassName = cn(
3497
3516
  "bg-[var(--bg-raised)]",
3498
3517
  "border-[var(--border-subtle)]",
3499
3518
  "rounded-[var(--radius-lg)]",
3500
- "shadow-[var(--elevation-4)]",
3519
+ "shadow-[var(--shadow-4)]",
3501
3520
  "text-foreground"
3502
3521
  );
3503
3522
  var formModalWideContentClassName = "max-w-[720px]";
@@ -3610,7 +3629,7 @@ var infoModalContentClassName = cn(
3610
3629
  "bg-[var(--bg-raised)]",
3611
3630
  "border border-[var(--border-subtle)]",
3612
3631
  "rounded-[var(--radius-lg)]",
3613
- "shadow-[var(--elevation-4)]",
3632
+ "shadow-[var(--shadow-4)]",
3614
3633
  "text-foreground"
3615
3634
  );
3616
3635
  var infoModalWideContentClassName = "max-w-[720px]";
@@ -4110,7 +4129,7 @@ var Checkbox = React23.forwardRef(
4110
4129
  Checkbox.displayName = "Checkbox";
4111
4130
 
4112
4131
  // src/components/ui/data-table.tsx
4113
- import { Fragment as Fragment7, jsx as jsx26, jsxs as jsxs25 } from "react/jsx-runtime";
4132
+ import { jsx as jsx26, jsxs as jsxs25 } from "react/jsx-runtime";
4114
4133
  var dataTableVariants = cva10(
4115
4134
  [
4116
4135
  "relative overflow-hidden rounded-[var(--radius-md)] border border-[var(--border-subtle)]",
@@ -4346,14 +4365,12 @@ function DataTableInner({
4346
4365
  selectable = false,
4347
4366
  selectedIds,
4348
4367
  onSelectionChange,
4349
- selectionBar = "top",
4350
4368
  activeRowId,
4351
4369
  onRowContextMenu,
4352
4370
  sortBy,
4353
4371
  onSortChange,
4354
4372
  loading = false,
4355
4373
  emptyState,
4356
- bulkActions = [],
4357
4374
  rowHref,
4358
4375
  skeletonRowCount = 8,
4359
4376
  "aria-label": ariaLabel = "\uB370\uC774\uD130 \uD14C\uC774\uBE14",
@@ -4396,44 +4413,13 @@ function DataTableInner({
4396
4413
  className: cn(dataTableVariants({ density, surface, className })),
4397
4414
  ...props,
4398
4415
  children: [
4399
- selectable && selectionBar === "top" ? /* @__PURE__ */ jsx26(
4416
+ selectable ? /* @__PURE__ */ jsx26(
4400
4417
  "div",
4401
4418
  {
4402
- "data-slot": "data-table-selection-bar",
4403
- "data-active": selectedCount > 0 ? "true" : "false",
4419
+ "data-slot": "data-table-selection-status",
4404
4420
  "aria-live": "polite",
4405
- className: cn(
4406
- "flex min-h-[48px] flex-wrap items-center justify-between gap-[var(--space-3)] border-b border-[var(--border-subtle)] px-[var(--space-4)] py-[var(--space-2)]",
4407
- "bg-[var(--bg-raised)]"
4408
- ),
4409
- children: selectedCount > 0 ? /* @__PURE__ */ jsxs25(Fragment7, { children: [
4410
- /* @__PURE__ */ jsxs25("div", { className: "text-sm font-medium text-foreground", children: [
4411
- selectedCount.toLocaleString("ko-KR"),
4412
- "\uAC1C \uC120\uD0DD\uB428"
4413
- ] }),
4414
- /* @__PURE__ */ jsxs25("div", { className: "flex flex-wrap items-center justify-end gap-[var(--space-2)]", children: [
4415
- bulkActions.map((action, index) => /* @__PURE__ */ jsx26(
4416
- Button,
4417
- {
4418
- size: "xs",
4419
- variant: action.variant === "destructive" ? "destructive" : "secondary",
4420
- onClick: () => action.onClick(new Set(resolvedSelectedIds)),
4421
- children: action.label
4422
- },
4423
- index
4424
- )),
4425
- /* @__PURE__ */ jsx26(
4426
- Button,
4427
- {
4428
- "aria-label": "\uC120\uD0DD \uCDE8\uC18C",
4429
- size: "xs",
4430
- variant: "ghost",
4431
- onClick: () => emitSelection(/* @__PURE__ */ new Set()),
4432
- children: "\uCDE8\uC18C"
4433
- }
4434
- )
4435
- ] })
4436
- ] }) : /* @__PURE__ */ jsx26("div", { className: "text-sm text-text-tertiary", children: "\uC120\uD0DD\uB41C \uD589 \uC5C6\uC74C" })
4421
+ className: "sr-only",
4422
+ children: selectedCount > 0 ? `${selectedCount.toLocaleString("ko-KR")}\uAC1C \uC120\uD0DD\uB428` : ""
4437
4423
  }
4438
4424
  ) : null,
4439
4425
  loading && data.length > 0 ? /* @__PURE__ */ jsx26(
@@ -4737,7 +4723,7 @@ function DropdownMenuContent({
4737
4723
  className: cn(
4738
4724
  "z-[var(--z-popover)] max-h-(--radix-dropdown-menu-content-available-height) min-w-[8rem]",
4739
4725
  "origin-(--radix-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto",
4740
- "rounded-sm border border-[var(--border)] bg-canvas p-[var(--space-1)] text-text-primary shadow-elevation-2",
4726
+ "rounded-sm border border-[var(--border)] bg-canvas p-[var(--space-1)] text-text-primary shadow-2",
4741
4727
  "data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2",
4742
4728
  "data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
4743
4729
  "data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95",
@@ -4936,7 +4922,7 @@ function DropdownMenuSubContent({
4936
4922
  "data-slot": "dropdown-menu-sub-content",
4937
4923
  className: cn(
4938
4924
  "z-[var(--z-popover)] min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-hidden",
4939
- "rounded-sm border border-[var(--border)] bg-canvas p-[var(--space-1)] text-text-primary shadow-elevation-2",
4925
+ "rounded-sm border border-[var(--border)] bg-canvas p-[var(--space-1)] text-text-primary shadow-2",
4940
4926
  "data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2",
4941
4927
  "data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
4942
4928
  "data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95",
@@ -5075,6 +5061,7 @@ function BulkActionBar({
5075
5061
  actions,
5076
5062
  onClear,
5077
5063
  emptyHint,
5064
+ className,
5078
5065
  style,
5079
5066
  ...props
5080
5067
  }) {
@@ -5087,9 +5074,15 @@ function BulkActionBar({
5087
5074
  role: "toolbar",
5088
5075
  "aria-label": "\uC120\uD0DD \uD56D\uBAA9 \uC77C\uAD04 \uC791\uC5C5",
5089
5076
  "data-slot": "bulk-action-bar",
5077
+ className: cn(
5078
+ // Subtle entrance when the bar appears (count>0). CSS animation runs once
5079
+ // on mount; reduced motion opts out via the global guard + this variant.
5080
+ "animate-[olun-bulk-action-bar-in_var(--dur-fast)_var(--ease-out)_both] motion-reduce:animate-none",
5081
+ className
5082
+ ),
5090
5083
  style: {
5091
5084
  position: "sticky",
5092
- bottom: "var(--space-4)",
5085
+ bottom: "calc(var(--space-4) + env(safe-area-inset-bottom))",
5093
5086
  zIndex: 1100,
5094
5087
  margin: "0 auto",
5095
5088
  display: "flex",
@@ -5149,14 +5142,14 @@ function BulkActionBar({
5149
5142
 
5150
5143
  // src/components/ui/confirm-dialog.tsx
5151
5144
  import * as React25 from "react";
5152
- import { Fragment as Fragment8, jsx as jsx30, jsxs as jsxs29 } from "react/jsx-runtime";
5145
+ import { Fragment as Fragment7, jsx as jsx30, jsxs as jsxs29 } from "react/jsx-runtime";
5153
5146
  var confirmDialogContentClassName = cn(
5154
5147
  "fixed left-1/2 top-1/2 z-[var(--z-modal)]",
5155
5148
  "-translate-x-1/2 -translate-y-1/2",
5156
5149
  "w-[calc(100vw-2rem)] max-w-[420px]",
5157
5150
  "flex flex-col gap-[var(--space-6)]",
5158
5151
  "bg-[var(--bg-raised)] border border-[var(--border-subtle)]",
5159
- "rounded-[var(--radius-lg)] p-[var(--space-6)] shadow-[var(--elevation-4)]",
5152
+ "rounded-[var(--radius-lg)] p-[var(--space-6)] shadow-[var(--shadow-4)]",
5160
5153
  "text-foreground"
5161
5154
  );
5162
5155
  var confirmDialogTitleClassName = cn(
@@ -5203,7 +5196,7 @@ function ConfirmDialog({
5203
5196
  setPending(false);
5204
5197
  }
5205
5198
  }, [loading, onConfirm, onOpenChange]);
5206
- const dialogBody = /* @__PURE__ */ jsxs29(Fragment8, { children: [
5199
+ const dialogBody = /* @__PURE__ */ jsxs29(Fragment7, { children: [
5207
5200
  /* @__PURE__ */ jsx30("div", { className: "flex items-start justify-between gap-[var(--space-4)]", children: /* @__PURE__ */ jsxs29("div", { className: "min-w-0 space-y-[var(--space-2)]", children: [
5208
5201
  /* @__PURE__ */ jsx30(
5209
5202
  DialogTitle,
@@ -5353,11 +5346,13 @@ var defaultSheetMotionConfig = {
5353
5346
  easing: "decel"
5354
5347
  };
5355
5348
  var sheetMotionEasingValue = {
5356
- standard: "var(--easing-standard)",
5349
+ standard: "var(--ease-standard)",
5350
+ // decel/sharp have no canonical --ease-* token; these compat beziers are frozen
5351
+ // specifically to back this public `easing` prop (see tokens/compat.css).
5357
5352
  decel: "var(--easing-decel)",
5358
- accel: "var(--easing-accel)",
5353
+ accel: "var(--ease-in)",
5359
5354
  sharp: "var(--easing-sharp)",
5360
- bounce: "var(--easing-bounce)"
5355
+ bounce: "var(--ease-out)"
5361
5356
  };
5362
5357
  function resolveSheetMotionConfig(motion) {
5363
5358
  if (motion === false) return false;
@@ -5560,7 +5555,7 @@ import { jsx as jsx34, jsxs as jsxs31 } from "react/jsx-runtime";
5560
5555
  var sheetDrawerContentClassName = cn(
5561
5556
  "gap-0 p-0",
5562
5557
  "bg-[var(--bg-surface)] text-foreground",
5563
- "border-[var(--border)] shadow-[var(--elevation-4)]",
5558
+ "border-[var(--border)] shadow-[var(--shadow-4)]",
5564
5559
  "min-[900px]:w-[480px] min-[900px]:max-w-[480px]",
5565
5560
  "max-[899px]:h-[min(85dvh,720px)] max-[899px]:max-h-[85dvh] max-[899px]:w-full max-[899px]:max-w-none",
5566
5561
  "max-[899px]:rounded-t-[var(--radius-lg)]"
@@ -5734,7 +5729,7 @@ var PopoverContent = React26.forwardRef(({ className, align = "center", sideOffs
5734
5729
  "z-[var(--z-popover)] w-[260px] outline-none",
5735
5730
  "rounded-[var(--radius-md)] border border-[var(--border)]",
5736
5731
  "bg-[var(--bg-raised)] p-[var(--space-4)] text-foreground",
5737
- "shadow-[var(--elevation-4)]",
5732
+ "shadow-[var(--shadow-4)]",
5738
5733
  "data-[state=open]:animate-in data-[state=closed]:animate-out",
5739
5734
  "data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
5740
5735
  "data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95",
@@ -5816,100 +5811,93 @@ Badge.displayName = "Badge";
5816
5811
 
5817
5812
  // src/components/ui/two-tier-badge.tsx
5818
5813
  import * as React28 from "react";
5819
- import { cva as cva11 } from "class-variance-authority";
5820
5814
  import { jsx as jsx37, jsxs as jsxs34 } from "react/jsx-runtime";
5821
- var twoTierBadgeVariants = cva11(
5822
- "inline-flex w-fit flex-col gap-[var(--space-1)]",
5823
- {
5824
- variants: {
5825
- align: {
5826
- start: "items-start text-left",
5827
- center: "items-center text-center",
5828
- end: "items-end text-right"
5829
- }
5830
- },
5831
- defaultVariants: {
5832
- align: "start"
5833
- }
5834
- }
5835
- );
5836
- var twoTierBadgeLineVariants = cva11(
5837
- [
5838
- "inline-flex w-fit shrink-0 items-center justify-center whitespace-nowrap",
5839
- "rounded-[var(--radius-xs)] border leading-none",
5840
- "transition-colors motion-reduce:transition-none"
5841
- ].join(" "),
5842
- {
5843
- variants: {
5844
- tier: {
5845
- primary: "px-[var(--space-2)] py-[calc(var(--space-1)/2)] text-xs font-medium",
5846
- secondary: "px-[var(--space-2)] py-[calc(var(--space-1)/2)] text-xs font-normal"
5847
- },
5848
- intent: {
5849
- neutral: "border-transparent bg-[var(--bg-raised)] text-foreground",
5850
- muted: "border-[var(--border-subtle)] bg-transparent text-text-tertiary",
5851
- brand: "border-[var(--border-accent)] bg-[var(--accent-bg-strong)] text-accent-fg",
5852
- success: "border-transparent bg-[var(--success-bg)] text-[var(--success)]",
5853
- warning: "border-transparent bg-[var(--warning-bg)] text-[var(--warning)]",
5854
- danger: "border-transparent bg-[var(--error-bg)] text-[var(--error)]"
5855
- }
5856
- },
5857
- defaultVariants: {
5858
- tier: "primary",
5859
- intent: "neutral"
5860
- }
5861
- }
5862
- );
5815
+ var FG = {
5816
+ neutral: "var(--text-secondary)",
5817
+ info: "var(--semantic-info-fg)",
5818
+ success: "var(--semantic-success-fg)",
5819
+ warning: "var(--semantic-warning-fg)",
5820
+ error: "var(--semantic-error-fg)"
5821
+ };
5822
+ var BG = {
5823
+ neutral: "var(--bg-inset)",
5824
+ info: "var(--semantic-info-bg)",
5825
+ success: "var(--semantic-success-bg)",
5826
+ warning: "var(--semantic-warning-bg)",
5827
+ error: "var(--semantic-error-bg)"
5828
+ };
5829
+ var SEGMENT = {
5830
+ xs: "gap-[5px] py-[2px] px-[var(--space-2)] text-[12px]",
5831
+ sm: "gap-[6px] py-[var(--space-1)] px-[var(--space-2)] text-[12px]",
5832
+ md: "gap-[7px] py-[var(--space-1)] px-[var(--space-3)] text-[14px]"
5833
+ };
5834
+ var DOT2 = { xs: 5, sm: 6, md: 7 };
5863
5835
  var TwoTierBadge = React28.forwardRef(
5864
- ({
5865
- className,
5866
- align,
5867
- primary,
5868
- secondary,
5869
- primaryIntent = "neutral",
5870
- secondaryIntent = "muted",
5871
- primaryClassName,
5872
- secondaryClassName,
5873
- ...props
5874
- }, ref) => /* @__PURE__ */ jsxs34(
5875
- "div",
5876
- {
5877
- ref,
5878
- "data-slot": "two-tier-badge",
5879
- className: cn(twoTierBadgeVariants({ align, className })),
5880
- ...props,
5881
- children: [
5882
- /* @__PURE__ */ jsx37(
5883
- "span",
5884
- {
5885
- "data-slot": "two-tier-badge-primary",
5886
- className: cn(
5887
- twoTierBadgeLineVariants({
5888
- tier: "primary",
5889
- intent: primaryIntent
5890
- }),
5891
- primaryClassName
5892
- ),
5893
- children: primary
5894
- }
5836
+ ({ primary, secondary, tone = "neutral", emphasis = "subtle", size = "sm", showDot = false, className, style, ...props }, ref) => {
5837
+ const strong = emphasis === "strong";
5838
+ const fg = FG[tone];
5839
+ const ringDot = tone === "neutral";
5840
+ const tinted = tone === "neutral" ? "var(--border)" : `color-mix(in srgb, ${fg} 26%, transparent)`;
5841
+ const frame = strong ? tinted : "var(--border-subtle)";
5842
+ const divider = strong ? tinted : "var(--border)";
5843
+ const dotSize = DOT2[size];
5844
+ return /* @__PURE__ */ jsxs34(
5845
+ "span",
5846
+ {
5847
+ ref,
5848
+ "data-slot": "two-tier-badge",
5849
+ "data-tone": tone,
5850
+ "data-emphasis": emphasis,
5851
+ className: cn(
5852
+ "inline-flex w-fit shrink-0 items-stretch overflow-hidden rounded-full border font-medium leading-none",
5853
+ className
5895
5854
  ),
5896
- secondary ? /* @__PURE__ */ jsx37(
5897
- "span",
5898
- {
5899
- "data-slot": "two-tier-badge-secondary",
5900
- className: cn(
5901
- twoTierBadgeLineVariants({
5902
- tier: "secondary",
5903
- intent: secondaryIntent
5904
- }),
5905
- secondaryClassName
5906
- ),
5907
- children: secondary
5908
- }
5909
- ) : null
5910
- ]
5911
- }
5912
- )
5855
+ style: { fontFamily: "var(--font-sans)", borderColor: frame, background: "transparent", ...style },
5856
+ ...props,
5857
+ children: [
5858
+ /* @__PURE__ */ jsxs34(
5859
+ "span",
5860
+ {
5861
+ "data-slot": "two-tier-badge-primary",
5862
+ className: cn("inline-flex items-center whitespace-nowrap font-semibold", SEGMENT[size]),
5863
+ style: { color: fg, background: strong ? BG[tone] : "transparent" },
5864
+ children: [
5865
+ showDot ? /* @__PURE__ */ jsx37(
5866
+ "span",
5867
+ {
5868
+ "aria-hidden": "true",
5869
+ "data-slot": "two-tier-badge-dot",
5870
+ "data-ring-dot": ringDot ? "true" : "false",
5871
+ className: "box-border shrink-0 rounded-full",
5872
+ style: {
5873
+ width: dotSize,
5874
+ height: dotSize,
5875
+ background: ringDot ? "transparent" : "currentColor",
5876
+ border: ringDot ? "1.5px solid currentColor" : "none"
5877
+ }
5878
+ }
5879
+ ) : null,
5880
+ /* @__PURE__ */ jsx37("span", { children: primary })
5881
+ ]
5882
+ }
5883
+ ),
5884
+ secondary != null ? /* @__PURE__ */ jsx37(
5885
+ "span",
5886
+ {
5887
+ "data-slot": "two-tier-badge-secondary",
5888
+ className: cn("inline-flex items-center whitespace-nowrap", SEGMENT[size]),
5889
+ style: {
5890
+ borderLeft: `1px solid ${divider}`,
5891
+ color: "var(--text-tertiary)",
5892
+ background: strong ? "var(--bg-inset)" : "transparent"
5893
+ },
5894
+ children: secondary
5895
+ }
5896
+ ) : null
5897
+ ]
5898
+ }
5899
+ );
5900
+ }
5913
5901
  );
5914
5902
  TwoTierBadge.displayName = "TwoTierBadge";
5915
5903
 
@@ -5925,14 +5913,14 @@ var ROLE = {
5925
5913
  success: "success",
5926
5914
  archived: "neutral"
5927
5915
  };
5928
- var FG = {
5916
+ var FG2 = {
5929
5917
  error: "var(--semantic-error-fg)",
5930
5918
  warning: "var(--semantic-warning-fg)",
5931
5919
  info: "var(--semantic-info-fg)",
5932
5920
  success: "var(--semantic-success-fg)",
5933
5921
  neutral: "var(--semantic-neutral-fg)"
5934
5922
  };
5935
- var BG = {
5923
+ var BG2 = {
5936
5924
  error: "var(--semantic-error-bg)",
5937
5925
  warning: "var(--semantic-warning-bg)",
5938
5926
  info: "var(--semantic-info-bg)",
@@ -5947,7 +5935,7 @@ var SIZE = {
5947
5935
  var StatusBadge = React29.forwardRef(
5948
5936
  ({ status = "active", emphasis = "subtle", size = "sm", showDot = true, pulse = true, className, children, style, ...props }, ref) => {
5949
5937
  const role = ROLE[status];
5950
- const fg = FG[role];
5938
+ const fg = FG2[role];
5951
5939
  const strong = emphasis === "strong";
5952
5940
  const ringDot = role === "neutral";
5953
5941
  return /* @__PURE__ */ jsxs35(
@@ -5961,7 +5949,7 @@ var StatusBadge = React29.forwardRef(
5961
5949
  className: cn("inline-flex w-fit shrink-0 items-center whitespace-nowrap rounded-full border font-medium leading-none", SIZE[size].cls, className),
5962
5950
  style: {
5963
5951
  fontFamily: "var(--font-sans)",
5964
- background: strong ? BG[role] : "transparent",
5952
+ background: strong ? BG2[role] : "transparent",
5965
5953
  borderColor: strong ? `color-mix(in srgb, ${fg} 26%, transparent)` : "var(--border-subtle)",
5966
5954
  color: fg,
5967
5955
  ...style
@@ -5996,9 +5984,9 @@ StatusBadge.displayName = "StatusBadge";
5996
5984
 
5997
5985
  // src/components/ui/notification-badge.tsx
5998
5986
  import * as React30 from "react";
5999
- import { cva as cva12 } from "class-variance-authority";
5987
+ import { cva as cva11 } from "class-variance-authority";
6000
5988
  import { jsx as jsx39 } from "react/jsx-runtime";
6001
- var notificationBadgeVariants = cva12(
5989
+ var notificationBadgeVariants = cva11(
6002
5990
  [
6003
5991
  "inline-flex shrink-0 items-center justify-center rounded-[var(--radius-full)]",
6004
5992
  "bg-[var(--semantic-error,var(--error))] text-[var(--error-contrast)]",
@@ -6062,11 +6050,11 @@ NotificationBadge.displayName = "NotificationBadge";
6062
6050
 
6063
6051
  // src/components/ui/chip.tsx
6064
6052
  import * as React31 from "react";
6065
- import { cva as cva13 } from "class-variance-authority";
6053
+ import { cva as cva12 } from "class-variance-authority";
6066
6054
  import { X as X3 } from "lucide-react";
6067
6055
  import { Slot as Slot2 } from "radix-ui";
6068
6056
  import { jsx as jsx40, jsxs as jsxs36 } from "react/jsx-runtime";
6069
- var chipVariants = cva13(
6057
+ var chipVariants = cva12(
6070
6058
  [
6071
6059
  "inline-flex w-fit shrink-0 items-center justify-center whitespace-nowrap",
6072
6060
  "rounded-[var(--radius-full)] border leading-none",
@@ -6087,7 +6075,7 @@ var chipVariants = cva13(
6087
6075
  },
6088
6076
  tone: {
6089
6077
  neutral: "border-[var(--border-subtle)] bg-[var(--bg-surface)] text-text-secondary hover:bg-[var(--action-hover)]",
6090
- accent: "border-[var(--border-accent)] bg-transparent text-[var(--accent-fg)] hover:bg-[var(--action-accent-hover)]",
6078
+ accent: "border-[var(--border-accent)] bg-transparent text-[var(--accent)] hover:bg-[var(--action-accent-hover)]",
6091
6079
  success: "border-transparent bg-[var(--success-bg)] text-[var(--success)] hover:bg-[var(--action-hover)]",
6092
6080
  warning: "border-transparent bg-[var(--warning-bg)] text-[var(--warning)] hover:bg-[var(--action-hover)]",
6093
6081
  danger: "border-transparent bg-[var(--error-bg)] text-[var(--error)] hover:bg-[var(--action-hover)]",
@@ -6110,10 +6098,10 @@ var chipVariants = cva13(
6110
6098
  className: "border-[var(--border-strong)] bg-[var(--action-selected)] text-foreground"
6111
6099
  },
6112
6100
  {
6113
- // R10 — wash 패턴 정합 (--accent-bg-strong deep olive wash / --accent-fg olive/lime text).
6101
+ // R10 — wash 패턴 정합 (--accent-bg-strong deep olive wash / --accent olive/lime text).
6114
6102
  pressed: true,
6115
6103
  tone: "accent",
6116
- className: "border-[var(--border-accent)] bg-[var(--accent-bg-strong)] text-[var(--accent-fg)]"
6104
+ className: "border-[var(--border-accent)] bg-[var(--accent-bg-strong)] text-[var(--accent)]"
6117
6105
  },
6118
6106
  {
6119
6107
  pressed: true,
@@ -6129,7 +6117,7 @@ var chipVariants = cva13(
6129
6117
  }
6130
6118
  }
6131
6119
  );
6132
- var chipCountVariants = cva13(
6120
+ var chipCountVariants = cva12(
6133
6121
  [
6134
6122
  "inline-flex min-w-[var(--space-4)] items-center justify-center",
6135
6123
  "rounded-[var(--radius-full)] px-[var(--space-1)]",
@@ -6139,7 +6127,7 @@ var chipCountVariants = cva13(
6139
6127
  variants: {
6140
6128
  tone: {
6141
6129
  neutral: "bg-[var(--bg-raised)] text-text-tertiary",
6142
- accent: "bg-[var(--accent-solid)] text-[var(--accent-on-solid)]",
6130
+ accent: "bg-[var(--accent-pop)] text-[var(--accent-on-fill)]",
6143
6131
  success: "bg-[var(--success)] text-[var(--success-contrast)]",
6144
6132
  warning: "bg-[var(--warning)] text-[var(--warning-contrast)]",
6145
6133
  danger: "bg-[var(--error)] text-[var(--error-contrast)]",
@@ -6254,9 +6242,9 @@ Chip.displayName = "Chip";
6254
6242
 
6255
6243
  // src/components/ui/empty-state.tsx
6256
6244
  import * as React32 from "react";
6257
- import { cva as cva14 } from "class-variance-authority";
6245
+ import { cva as cva13 } from "class-variance-authority";
6258
6246
  import { jsx as jsx41, jsxs as jsxs37 } from "react/jsx-runtime";
6259
- var emptyStateBaseVariants = cva14(
6247
+ var emptyStateBaseVariants = cva13(
6260
6248
  [
6261
6249
  "flex flex-col items-center justify-center text-center",
6262
6250
  "text-foreground"
@@ -6304,7 +6292,7 @@ function emptyStateVariants({
6304
6292
  className
6305
6293
  );
6306
6294
  }
6307
- var emptyStateIconVariants = cva14(
6295
+ var emptyStateIconVariants = cva13(
6308
6296
  [
6309
6297
  "inline-flex items-center justify-center rounded-[var(--radius-full)]",
6310
6298
  "border border-[var(--border-subtle)] bg-[var(--bg-raised)] text-text-tertiary"
@@ -6397,9 +6385,9 @@ EmptyState.displayName = "EmptyState";
6397
6385
  // src/components/ui/error-state.tsx
6398
6386
  import * as React33 from "react";
6399
6387
  import { AlertTriangle } from "lucide-react";
6400
- import { cva as cva15 } from "class-variance-authority";
6388
+ import { cva as cva14 } from "class-variance-authority";
6401
6389
  import { jsx as jsx42, jsxs as jsxs38 } from "react/jsx-runtime";
6402
- var errorStateVariants = cva15(
6390
+ var errorStateVariants = cva14(
6403
6391
  [
6404
6392
  "flex flex-col items-center justify-center text-center",
6405
6393
  "rounded-[var(--radius-md)] border border-[var(--border-subtle)]",
@@ -6484,9 +6472,9 @@ ErrorState.displayName = "ErrorState";
6484
6472
 
6485
6473
  // src/components/ui/skeleton.tsx
6486
6474
  import * as React34 from "react";
6487
- import { cva as cva16 } from "class-variance-authority";
6475
+ import { cva as cva15 } from "class-variance-authority";
6488
6476
  import { jsx as jsx43 } from "react/jsx-runtime";
6489
- var skeletonVariants = cva16(
6477
+ var skeletonVariants = cva15(
6490
6478
  [
6491
6479
  "animate-pulse rounded-[var(--radius-sm)] bg-[var(--bg-raised)]",
6492
6480
  "motion-reduce:animate-none motion-reduce:opacity-80"
@@ -6504,7 +6492,7 @@ var skeletonVariants = cva16(
6504
6492
  }
6505
6493
  }
6506
6494
  );
6507
- var spinnerVariants = cva16(
6495
+ var spinnerVariants = cva15(
6508
6496
  [
6509
6497
  "inline-block shrink-0 animate-spin rounded-[var(--radius-full)] border-2",
6510
6498
  "border-[var(--border-subtle)] border-t-[var(--primary)]",
@@ -6635,9 +6623,9 @@ Spinner.displayName = "Spinner";
6635
6623
 
6636
6624
  // src/components/ui/icon-button.tsx
6637
6625
  import * as React35 from "react";
6638
- import { cva as cva17 } from "class-variance-authority";
6626
+ import { cva as cva16 } from "class-variance-authority";
6639
6627
  import { jsx as jsx44, jsxs as jsxs39 } from "react/jsx-runtime";
6640
- var iconButtonVariants = cva17(
6628
+ var iconButtonVariants = cva16(
6641
6629
  [
6642
6630
  "olun-icon-button relative inline-flex cursor-pointer shrink-0 items-center justify-center",
6643
6631
  "rounded-[var(--radius-sm)] border font-medium",
@@ -6683,7 +6671,7 @@ var iconButtonVariants = cva17(
6683
6671
  }
6684
6672
  }
6685
6673
  );
6686
- var iconButtonBadgeVariants = cva17(
6674
+ var iconButtonBadgeVariants = cva16(
6687
6675
  [
6688
6676
  "pointer-events-none absolute right-0 top-0 inline-flex",
6689
6677
  "olun-icon-button__badge",
@@ -6695,7 +6683,7 @@ var iconButtonBadgeVariants = cva17(
6695
6683
  {
6696
6684
  variants: {
6697
6685
  tone: {
6698
- info: "bg-[var(--accent-solid)] text-[var(--accent-on-solid)]",
6686
+ info: "bg-[var(--accent-pop)] text-[var(--accent-on-fill)]",
6699
6687
  error: "bg-[var(--error)] text-[var(--error-contrast)]"
6700
6688
  }
6701
6689
  },
@@ -6780,7 +6768,7 @@ IconButton.displayName = "IconButton";
6780
6768
  // src/components/ui/pagination.tsx
6781
6769
  import * as React36 from "react";
6782
6770
  import { ChevronsLeft, ChevronLeft, ChevronRight as ChevronRight2, ChevronsRight } from "lucide-react";
6783
- import { cva as cva18 } from "class-variance-authority";
6771
+ import { cva as cva17 } from "class-variance-authority";
6784
6772
 
6785
6773
  // src/components/ui/page-size-select.tsx
6786
6774
  import { jsx as jsx45, jsxs as jsxs40 } from "react/jsx-runtime";
@@ -6835,7 +6823,7 @@ function PageSizeSelect({
6835
6823
 
6836
6824
  // src/components/ui/pagination.tsx
6837
6825
  import { jsx as jsx46, jsxs as jsxs41 } from "react/jsx-runtime";
6838
- var paginationVariants = cva18(
6826
+ var paginationVariants = cva17(
6839
6827
  [
6840
6828
  "flex w-full flex-col gap-[var(--space-3)]",
6841
6829
  "text-sm text-text-secondary",
@@ -6853,7 +6841,7 @@ var paginationVariants = cva18(
6853
6841
  }
6854
6842
  }
6855
6843
  );
6856
- var paginationControlVariants = cva18(
6844
+ var paginationControlVariants = cva17(
6857
6845
  [
6858
6846
  "inline-flex shrink-0 items-center justify-center rounded-[var(--radius-sm)] border",
6859
6847
  "border-transparent bg-transparent font-medium text-text-secondary",
@@ -7056,26 +7044,26 @@ var Pagination = React36.forwardRef(
7056
7044
  Pagination.displayName = "Pagination";
7057
7045
 
7058
7046
  // src/components/ui/mode-toggle.tsx
7059
- import { cva as cva19 } from "class-variance-authority";
7047
+ import { cva as cva18 } from "class-variance-authority";
7060
7048
  import { jsx as jsx47, jsxs as jsxs42 } from "react/jsx-runtime";
7061
- var modeToggleVariants = cva19(
7049
+ var modeToggleVariants = cva18(
7062
7050
  [
7063
7051
  "inline-flex items-center rounded-[var(--radius-sm)] border border-[var(--border-subtle)]",
7064
7052
  "bg-[var(--bg-raised)] p-[2px]"
7065
7053
  ].join(" ")
7066
7054
  );
7067
- var modeToggleItemVariants = cva19(
7055
+ var modeToggleItemVariants = cva18(
7068
7056
  [
7069
7057
  "inline-flex min-h-[28px] cursor-pointer items-center justify-center gap-[var(--space-1)]",
7070
7058
  "rounded-[calc(var(--radius-sm)_-_2px)] px-[var(--space-3)] py-[var(--space-1)]",
7071
7059
  "font-[family-name:var(--font-display)] text-xs font-medium leading-none",
7072
7060
  "text-text-secondary transition-[background-color,color,box-shadow]",
7073
- "duration-[var(--duration-fast)] ease-[var(--ease-standard)]",
7061
+ "duration-[var(--dur-fast)] ease-[var(--ease-standard)]",
7074
7062
  "hover:text-foreground",
7075
7063
  "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--focus-ring)]",
7076
7064
  "disabled:cursor-not-allowed disabled:text-text-disabled disabled:hover:text-text-disabled",
7077
7065
  "data-[state=active]:bg-[var(--bg-surface)] data-[state=active]:font-semibold",
7078
- "data-[state=active]:text-foreground data-[state=active]:shadow-[var(--elevation-1)]",
7066
+ "data-[state=active]:text-foreground data-[state=active]:shadow-[var(--shadow-1)]",
7079
7067
  "[&_svg]:pointer-events-none [&_svg]:size-[14px] [&_svg]:shrink-0 [&_svg]:stroke-[1.75]"
7080
7068
  ].join(" ")
7081
7069
  );
@@ -7126,9 +7114,9 @@ function ModeToggle({
7126
7114
 
7127
7115
  // src/components/ui/action-footer.tsx
7128
7116
  import * as React37 from "react";
7129
- import { cva as cva20 } from "class-variance-authority";
7117
+ import { cva as cva19 } from "class-variance-authority";
7130
7118
  import { jsx as jsx48, jsxs as jsxs43 } from "react/jsx-runtime";
7131
- var actionFooterVariants = cva20(
7119
+ var actionFooterVariants = cva19(
7132
7120
  [
7133
7121
  "flex flex-wrap items-center gap-[var(--space-4)] border-t border-[var(--border-subtle)]",
7134
7122
  "px-[var(--space-6)] py-[var(--space-4)]",
@@ -7150,7 +7138,7 @@ var actionFooterVariants = cva20(
7150
7138
  }
7151
7139
  }
7152
7140
  );
7153
- var actionFooterStatusVariants = cva20(
7141
+ var actionFooterStatusVariants = cva19(
7154
7142
  [
7155
7143
  "flex min-w-0 flex-1 items-center gap-[var(--space-2)]",
7156
7144
  "text-sm leading-snug text-text-tertiary"
@@ -7283,21 +7271,21 @@ ActionFooter.displayName = "ActionFooter";
7283
7271
 
7284
7272
  // src/components/ui/toast.tsx
7285
7273
  import * as React38 from "react";
7286
- import { cva as cva21 } from "class-variance-authority";
7274
+ import { cva as cva20 } from "class-variance-authority";
7287
7275
  import { jsx as jsx49, jsxs as jsxs44 } from "react/jsx-runtime";
7288
- var DOT2 = {
7276
+ var DOT3 = {
7289
7277
  default: "var(--neutral)",
7290
7278
  success: "var(--success)",
7291
7279
  warning: "var(--warning)",
7292
7280
  info: "var(--info)",
7293
7281
  error: "var(--error)"
7294
7282
  };
7295
- var toastVariants = cva21(
7283
+ var toastVariants = cva20(
7296
7284
  [
7297
7285
  "flex min-w-[280px] max-w-[420px] items-center",
7298
7286
  "gap-[11px] rounded-[10px] border border-[var(--border)]",
7299
7287
  "px-[14px] py-[11px]",
7300
- "shadow-[var(--elevation-4)]",
7288
+ "shadow-[var(--shadow-4)]",
7301
7289
  "pointer-events-auto",
7302
7290
  "motion-reduce:animate-none"
7303
7291
  ].join(" "),
@@ -7314,7 +7302,7 @@ var toastVariants = cva21(
7314
7302
  defaultVariants: { variant: "default" }
7315
7303
  }
7316
7304
  );
7317
- var toastViewportVariants = cva21(
7305
+ var toastViewportVariants = cva20(
7318
7306
  [
7319
7307
  "fixed bottom-[var(--space-6)] right-[var(--space-6)] z-[var(--z-toast,50)]",
7320
7308
  "flex w-[min(420px,calc(100vw-var(--space-12)))] list-none flex-col gap-[var(--space-2)]",
@@ -7465,7 +7453,7 @@ var ToastRoot = React38.forwardRef(
7465
7453
  "aria-hidden": "true",
7466
7454
  "data-slot": "toast-dot",
7467
7455
  className: "size-[7px] shrink-0 rounded-full",
7468
- style: { background: DOT2[variant] ?? DOT2.default }
7456
+ style: { background: DOT3[variant] ?? DOT3.default }
7469
7457
  }
7470
7458
  ),
7471
7459
  /* @__PURE__ */ jsxs44("div", { "data-slot": "toast-body", className: "min-w-0 flex-1", children: [
@@ -7545,10 +7533,10 @@ function ToastProvider({ children, maxToasts = 3, className, ...props }) {
7545
7533
 
7546
7534
  // src/components/ui/otp-field.tsx
7547
7535
  import * as React39 from "react";
7548
- import { cva as cva22 } from "class-variance-authority";
7536
+ import { cva as cva21 } from "class-variance-authority";
7549
7537
  import { AlertCircle as AlertCircle4 } from "lucide-react";
7550
- import { Fragment as Fragment9, jsx as jsx50, jsxs as jsxs45 } from "react/jsx-runtime";
7551
- var otpFieldVariants = cva22("flex w-full min-w-0 flex-col gap-[var(--space-3)]", {
7538
+ import { Fragment as Fragment8, jsx as jsx50, jsxs as jsxs45 } from "react/jsx-runtime";
7539
+ var otpFieldVariants = cva21("flex w-full min-w-0 flex-col gap-[var(--space-3)]", {
7552
7540
  variants: {
7553
7541
  size: {
7554
7542
  default: "",
@@ -7559,7 +7547,7 @@ var otpFieldVariants = cva22("flex w-full min-w-0 flex-col gap-[var(--space-3)]"
7559
7547
  size: "default"
7560
7548
  }
7561
7549
  });
7562
- var otpFieldGroupVariants = cva22("flex items-start gap-[var(--space-2)] pt-[var(--space-1)]", {
7550
+ var otpFieldGroupVariants = cva21("flex items-start gap-[var(--space-2)] pt-[var(--space-1)]", {
7563
7551
  variants: {
7564
7552
  size: {
7565
7553
  default: "",
@@ -7575,7 +7563,7 @@ var otpFieldGroupVariants = cva22("flex items-start gap-[var(--space-2)] pt-[var
7575
7563
  fluid: false
7576
7564
  }
7577
7565
  });
7578
- var otpCellVariants = cva22(
7566
+ var otpCellVariants = cva21(
7579
7567
  [
7580
7568
  "flex items-center justify-center rounded-[var(--radius-sm)] border",
7581
7569
  "border-[var(--border)] text-foreground",
@@ -7630,7 +7618,7 @@ var otpCellVariants = cva22(
7630
7618
  }
7631
7619
  }
7632
7620
  );
7633
- var otpFieldMessageVariants = cva22("flex items-start gap-[var(--space-1)] text-xs leading-snug", {
7621
+ var otpFieldMessageVariants = cva21("flex items-start gap-[var(--space-1)] text-xs leading-snug", {
7634
7622
  variants: {
7635
7623
  state: {
7636
7624
  default: "text-text-tertiary",
@@ -7869,7 +7857,7 @@ var OTPField = React39.forwardRef(
7869
7857
  "data-slot": "otp-field-message",
7870
7858
  "data-kind": errorText ? "error" : "helper",
7871
7859
  className: otpFieldMessageVariants({ state: resolvedState }),
7872
- children: errorText ? /* @__PURE__ */ jsxs45(Fragment9, { children: [
7860
+ children: errorText ? /* @__PURE__ */ jsxs45(Fragment8, { children: [
7873
7861
  /* @__PURE__ */ jsx50(
7874
7862
  AlertCircle4,
7875
7863
  {
@@ -7905,9 +7893,9 @@ OTPField.displayName = "OTPField";
7905
7893
  // src/components/ui/search-field.tsx
7906
7894
  import * as React40 from "react";
7907
7895
  import { Search, X as X4 } from "lucide-react";
7908
- import { cva as cva23 } from "class-variance-authority";
7896
+ import { cva as cva22 } from "class-variance-authority";
7909
7897
  import { jsx as jsx51, jsxs as jsxs46 } from "react/jsx-runtime";
7910
- var searchFieldVariants = cva23("relative flex w-full items-center", {
7898
+ var searchFieldVariants = cva22("relative flex w-full items-center", {
7911
7899
  variants: {
7912
7900
  size: {
7913
7901
  // Field-control scale follows Select: sm/md/lg = 30/32/36px. Pair with Button sm/md/lg.
@@ -7920,7 +7908,7 @@ var searchFieldVariants = cva23("relative flex w-full items-center", {
7920
7908
  size: "md"
7921
7909
  }
7922
7910
  });
7923
- var searchFieldInputVariants = cva23(
7911
+ var searchFieldInputVariants = cva22(
7924
7912
  [
7925
7913
  "h-full w-full rounded-[var(--radius-sm)] border",
7926
7914
  "border-[var(--border)]",
@@ -8063,9 +8051,9 @@ SearchField.displayName = "SearchField";
8063
8051
 
8064
8052
  // src/components/ui/checkbox-group.tsx
8065
8053
  import * as React41 from "react";
8066
- import { cva as cva24 } from "class-variance-authority";
8054
+ import { cva as cva23 } from "class-variance-authority";
8067
8055
  import { jsx as jsx52 } from "react/jsx-runtime";
8068
- var checkboxGroupVariants = cva24("gap-[var(--space-2)]", {
8056
+ var checkboxGroupVariants = cva23("gap-[var(--space-2)]", {
8069
8057
  variants: {
8070
8058
  appearance: {
8071
8059
  plain: "flex",
@@ -8165,11 +8153,11 @@ CheckboxGroup.displayName = "CheckboxGroup";
8165
8153
 
8166
8154
  // src/components/ui/radio-group.tsx
8167
8155
  import * as React42 from "react";
8168
- import { cva as cva25 } from "class-variance-authority";
8156
+ import { cva as cva24 } from "class-variance-authority";
8169
8157
  import { Circle } from "lucide-react";
8170
8158
  import { RadioGroup as RadioGroupPrimitive } from "radix-ui";
8171
8159
  import { jsx as jsx53, jsxs as jsxs47 } from "react/jsx-runtime";
8172
- var radioGroupVariants = cva25("gap-[var(--space-2)]", {
8160
+ var radioGroupVariants = cva24("gap-[var(--space-2)]", {
8173
8161
  variants: {
8174
8162
  appearance: {
8175
8163
  plain: "flex",
@@ -8194,7 +8182,7 @@ var radioGroupVariants = cva25("gap-[var(--space-2)]", {
8194
8182
  columns: "one"
8195
8183
  }
8196
8184
  });
8197
- var radioVariants = cva25(
8185
+ var radioVariants = cva24(
8198
8186
  [
8199
8187
  "group w-full cursor-pointer text-left transition-colors motion-reduce:transition-none",
8200
8188
  "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--focus-ring)] focus-visible:ring-offset-2 focus-visible:ring-offset-[var(--bg-base)]",
@@ -8236,7 +8224,7 @@ var radioVariants = cva25(
8236
8224
  }
8237
8225
  }
8238
8226
  );
8239
- var radioControlVariants = cva25(
8227
+ var radioControlVariants = cva24(
8240
8228
  [
8241
8229
  "flex size-[calc(var(--space-4)+var(--space-1))] shrink-0 items-center justify-center",
8242
8230
  "rounded-[var(--radius-full)] border border-[var(--border-strong)] bg-[var(--bg-surface)] text-transparent",
@@ -8471,16 +8459,16 @@ function Progress({
8471
8459
  // src/components/ui/tree-view.tsx
8472
8460
  import * as React43 from "react";
8473
8461
  import { ChevronRight as ChevronRight3 } from "lucide-react";
8474
- import { cva as cva26 } from "class-variance-authority";
8462
+ import { cva as cva25 } from "class-variance-authority";
8475
8463
  import { jsx as jsx56, jsxs as jsxs49 } from "react/jsx-runtime";
8476
- var treeViewVariants = cva26(
8464
+ var treeViewVariants = cva25(
8477
8465
  "m-0 list-none p-[var(--space-1)] text-body-sm text-foreground"
8478
8466
  );
8479
- var treeItemRowVariants = cva26(
8467
+ var treeItemRowVariants = cva25(
8480
8468
  [
8481
8469
  "flex min-h-[32px] w-full cursor-pointer select-none items-center gap-[var(--space-2)]",
8482
8470
  "rounded-[var(--radius-sm)] py-[var(--space-2)] pr-[var(--space-3)]",
8483
- "text-text-secondary transition-colors duration-[var(--duration-fast)] ease-[var(--ease-standard)] motion-reduce:transition-none",
8471
+ "text-text-secondary transition-colors duration-[var(--dur-fast)] ease-[var(--ease-standard)] motion-reduce:transition-none",
8484
8472
  "hover:bg-[var(--action-hover)] hover:text-foreground",
8485
8473
  // Roving focus lives on the treeitem <li> (named group/treeitem); the ring is
8486
8474
  // painted on the visual row so it never wraps the nested child group.
@@ -8692,7 +8680,7 @@ function TreeView({
8692
8680
  "aria-hidden": "true",
8693
8681
  "data-slot": "treeitem-chevron",
8694
8682
  className: cn(
8695
- "size-[16px] transition-transform duration-[var(--duration-fast)] ease-[var(--ease-standard)] motion-reduce:transition-none",
8683
+ "size-[16px] transition-transform duration-[var(--dur-fast)] ease-[var(--ease-standard)] motion-reduce:transition-none",
8696
8684
  expanded && "rotate-90"
8697
8685
  ),
8698
8686
  strokeWidth: 2
@@ -8759,7 +8747,7 @@ function OlunSymbol({ size = 28, className }) {
8759
8747
  style: { color: "var(--text-primary)" }
8760
8748
  }
8761
8749
  ),
8762
- /* @__PURE__ */ jsx57("circle", { cx: "185", cy: "175", r: "22", fill: "var(--accent-solid)" })
8750
+ /* @__PURE__ */ jsx57("circle", { cx: "185", cy: "175", r: "22", fill: "var(--accent-pop)" })
8763
8751
  ]
8764
8752
  }
8765
8753
  );
@@ -8793,7 +8781,7 @@ function OlunLogo({
8793
8781
  },
8794
8782
  children: [
8795
8783
  "OLUN",
8796
- /* @__PURE__ */ jsx57("span", { style: { color: "var(--accent-fg)" }, children: "." })
8784
+ /* @__PURE__ */ jsx57("span", { style: { color: "var(--accent)" }, children: "." })
8797
8785
  ]
8798
8786
  }
8799
8787
  )
@@ -8862,7 +8850,7 @@ function ThemeFab({ variant = "square" } = {}) {
8862
8850
  border: "1px solid var(--border-accent)",
8863
8851
  background: "var(--theme-fab-bg, var(--bg-surface))",
8864
8852
  color: "var(--theme-fab-icon, var(--text-primary))",
8865
- boxShadow: "var(--elevation-4)",
8853
+ boxShadow: "var(--shadow-4)",
8866
8854
  backdropFilter: "blur(16px)",
8867
8855
  WebkitBackdropFilter: "blur(16px)",
8868
8856
  zIndex: 9999
@@ -9144,8 +9132,6 @@ export {
9144
9132
  toastViewportVariants,
9145
9133
  treeItemRowVariants,
9146
9134
  treeViewVariants,
9147
- twoTierBadgeLineVariants,
9148
- twoTierBadgeVariants,
9149
9135
  useOlunTheme,
9150
9136
  usePermission
9151
9137
  };
package/dist/tokens.css CHANGED
@@ -37,10 +37,10 @@
37
37
  --color-action-active: var(--action-active);
38
38
 
39
39
  /* Semantic aliases exposed for component package utilities. */
40
- --color-semantic-error: var(--semantic-error);
41
- --color-semantic-success: var(--semantic-success);
42
- --color-semantic-warning: var(--semantic-warning);
43
- --color-semantic-info: var(--semantic-info);
40
+ --color-semantic-error: var(--semantic-error-fg);
41
+ --color-semantic-success: var(--semantic-success-fg);
42
+ --color-semantic-warning: var(--semantic-warning-fg);
43
+ --color-semantic-info: var(--semantic-info-fg);
44
44
 
45
45
  /* bg-base / text-base 충돌 방지용 alias.
46
46
  * Tailwind에서 `text-base`는 font-size 예약어 → `text-bg-base`로 노출.
@@ -58,6 +58,11 @@
58
58
  * unconditionally — removing the duplicate avoids cascade conflicts.
59
59
  */
60
60
 
61
+ @keyframes olun-bulk-action-bar-in {
62
+ from { opacity: 0; transform: translateY(8px); }
63
+ to { opacity: 1; transform: translateY(0); }
64
+ }
65
+
61
66
  @keyframes olun-sheet-fade-in {
62
67
  from { opacity: 0; }
63
68
  to { opacity: 1; }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@olundot/ui",
3
- "version": "0.12.0",
3
+ "version": "0.13.0",
4
4
  "description": "OLUN. shared React UI components built on OLUN design tokens",
5
5
  "license": "MIT",
6
6
  "keywords": [
@@ -44,7 +44,7 @@
44
44
  "lucide-react": "^1.8.0",
45
45
  "radix-ui": "^1.4.3",
46
46
  "tailwind-merge": "^3.5.0",
47
- "@olundot/tokens": "^0.13.0"
47
+ "@olundot/tokens": "^0.14.0"
48
48
  },
49
49
  "peerDependencies": {
50
50
  "react": ">=18",