@olundot/ui 0.4.0 → 0.6.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,36 @@
1
1
  # @olundot/ui
2
2
 
3
+ ## 0.6.0
4
+
5
+ ### Minor Changes
6
+
7
+ - de4b5fe: Add `TreeView` — a WAI-ARIA tree (APG tree pattern, single-select) for hierarchical navigation such as folder/classification browsers.
8
+
9
+ - Data-driven `nodes` with a `renderItem` render-prop so consumers own item content (icon + label/link) while the DS owns tree semantics.
10
+ - Generic over `T extends TreeNode`; controlled `selectedId` and controlled/uncontrolled expansion (`expandedIds` / `defaultExpandedIds` + `onExpandedChange`), `onSelect`.
11
+ - Optional `selectionAriaCurrent` puts `aria-current` (e.g. `"page"`) on the selected node for navigation trees, alongside `aria-selected`.
12
+ - Full keyboard support: ArrowUp/Down move, ArrowRight/Left expand·collapse·move, Home/End, Enter selects, Space toggles a parent's expansion (selects a leaf), with roving tabindex (one Tab stop).
13
+ - Roles `tree`/`treeitem`/`group`, `aria-expanded`/`aria-selected`/`aria-level`, required `aria-label`; token-driven hover/selected (subtle fill)/focus with token-based depth indentation; light + dark.
14
+ - Works when item content contains a focusable link (give inner links `tabIndex={-1}`; activation preserved on pointer).
15
+
16
+ Scope (v1): single-select + expand/collapse + keyboard + a11y. Multi-select, async/lazy loading, drag-drop and inline rename are intentionally out of scope and can be added without breaking the API.
17
+
18
+ New exports: `TreeView`, `treeViewVariants`, `treeItemRowVariants`, `TreeNode`, `TreeItemState`, `TreeViewProps`, `TreeItemRowVariantProps`.
19
+
20
+ ## 0.5.0
21
+
22
+ ### Minor Changes
23
+
24
+ - Add the shared OLUN theme transition contract and theme helper API.
25
+
26
+ - `@olundot/tokens` now exposes a 300ms default theme transition token contract.
27
+ - `@olundot/ui` now exports `getOlunThemeState`, `setOlunTheme`, and `useOlunTheme` for synchronized light/dark theme controls.
28
+
29
+ ### Patch Changes
30
+
31
+ - Updated dependencies
32
+ - @olundot/tokens@0.10.0
33
+
3
34
  ## 0.4.0
4
35
 
5
36
  ### Minor Changes
package/dist/index.d.ts CHANGED
@@ -9,10 +9,30 @@ import * as react_jsx_runtime from 'react/jsx-runtime';
9
9
 
10
10
  declare function cn(...inputs: ClassValue[]): string;
11
11
 
12
+ type OlunTheme = "light" | "dark";
13
+ type OlunThemeDuration = "instant" | "fast" | "base" | "slow" | "slower" | "slowest";
14
+ interface OlunThemeState {
15
+ theme: OlunTheme;
16
+ resolvedTheme: OlunTheme;
17
+ storedTheme: OlunTheme | null;
18
+ source: "attribute" | "stored" | "system" | "default";
19
+ }
20
+ interface SetOlunThemeOptions {
21
+ duration?: OlunThemeDuration;
22
+ }
23
+ interface UseOlunThemeValue extends OlunThemeState {
24
+ mounted: boolean;
25
+ setTheme: (nextTheme: OlunTheme, options?: SetOlunThemeOptions) => void;
26
+ toggleTheme: (options?: SetOlunThemeOptions) => void;
27
+ }
28
+ declare function getOlunThemeState(): OlunThemeState;
29
+ declare function setOlunTheme(nextTheme: OlunTheme, options?: SetOlunThemeOptions): void;
30
+ declare function useOlunTheme(): UseOlunThemeValue;
31
+
12
32
  type SurfaceLevel = "surface" | "canvas" | "raised";
13
33
 
14
34
  declare const buttonVariants: (props?: ({
15
- variant?: "primary" | "secondary" | "destructive" | "outline" | "ghost" | "danger" | "emergency" | "subtle" | "default" | "link" | null | undefined;
35
+ variant?: "primary" | "secondary" | "destructive" | "default" | "outline" | "ghost" | "danger" | "emergency" | "subtle" | "link" | null | undefined;
16
36
  size?: "xs" | "sm" | "md" | "lg" | "xl" | "default" | "icon" | "icon-xs" | null | undefined;
17
37
  } & class_variance_authority_types.ClassProp) | undefined) => string;
18
38
  type ButtonVariant = NonNullable<VariantProps<typeof buttonVariants>['variant']>;
@@ -1301,6 +1321,56 @@ interface ProgressProps extends React.HTMLAttributes<HTMLDivElement> {
1301
1321
  }
1302
1322
  declare function Progress({ value, max, status, width, height, className, style, ...props }: ProgressProps): react_jsx_runtime.JSX.Element;
1303
1323
 
1324
+ /**
1325
+ * A single node in a TreeView. Consumers extend this shape with their own
1326
+ * fields (title, href, icon, …) and make the component generic over that type.
1327
+ * Only `id` (stable, unique within the tree) is required by the DS; children
1328
+ * are read through `getChildren` (default: `node.children`).
1329
+ */
1330
+ interface TreeNode {
1331
+ id: string;
1332
+ children?: TreeNode[];
1333
+ }
1334
+ /** State handed to `renderItem` so the consumer can reflect tree status. */
1335
+ interface TreeItemState {
1336
+ expanded: boolean;
1337
+ selected: boolean;
1338
+ /** 1-based ARIA level (roots are level 1). */
1339
+ depth: number;
1340
+ hasChildren: boolean;
1341
+ }
1342
+ interface TreeViewProps<T extends TreeNode> extends Omit<React.HTMLAttributes<HTMLUListElement>, "onSelect" | "role"> {
1343
+ /** Root nodes of the tree. */
1344
+ nodes: T[];
1345
+ /** Controlled "current" node (single-select). */
1346
+ selectedId?: string;
1347
+ /** When set, the selected node also carries this `aria-current` value. Use
1348
+ * `"page"` for navigation trees so assistive tech announces the current
1349
+ * location (e.g. the open folder). Default: no `aria-current`. */
1350
+ selectionAriaCurrent?: React.AriaAttributes["aria-current"];
1351
+ /** Initial expanded node ids (uncontrolled expansion). */
1352
+ defaultExpandedIds?: string[];
1353
+ /** Controlled expanded node ids. When set, expansion is fully controlled. */
1354
+ expandedIds?: string[];
1355
+ /** Fires whenever the expanded set changes (controlled or uncontrolled). */
1356
+ onExpandedChange?: (ids: string[]) => void;
1357
+ /** Fires when a node is activated (Enter/Space or click). */
1358
+ onSelect?: (id: string, node: T) => void;
1359
+ /** Render the item's content (icon + label/link). Receives node state. */
1360
+ renderItem: (node: T, state: TreeItemState) => React.ReactNode;
1361
+ /** Read a node's children. Default: `node.children`. */
1362
+ getChildren?: (node: T) => T[] | undefined;
1363
+ /** Required: the tree must be labelled (WAI-ARIA tree). */
1364
+ "aria-label": string;
1365
+ className?: string;
1366
+ }
1367
+ declare const treeViewVariants: (props?: class_variance_authority_types.ClassProp | undefined) => string;
1368
+ declare const treeItemRowVariants: (props?: ({
1369
+ selected?: boolean | null | undefined;
1370
+ } & class_variance_authority_types.ClassProp) | undefined) => string;
1371
+ type TreeItemRowVariantProps = VariantProps<typeof treeItemRowVariants>;
1372
+ declare function TreeView<T extends TreeNode>({ nodes, selectedId, selectionAriaCurrent, defaultExpandedIds, expandedIds, onExpandedChange, onSelect, renderItem, getChildren, className, "aria-label": ariaLabel, ...rest }: TreeViewProps<T>): react_jsx_runtime.JSX.Element;
1373
+
1304
1374
  /**
1305
1375
  * OLUN 브랜드 로고.
1306
1376
  *
@@ -1349,4 +1419,4 @@ interface OrganizationLogoProps extends Omit<SVGProps<SVGSVGElement>, "width" |
1349
1419
  }
1350
1420
  declare function OrganizationLogo({ organization, size, className, style, role, "aria-label": ariaLabel, "aria-hidden": ariaHidden, ...props }: OrganizationLogoProps): react_jsx_runtime.JSX.Element;
1351
1421
 
1352
- export { ActionFooter, type ActionFooterAction, type ActionFooterProps, type ActionFooterStatus, Alert, type AlertProps, type AlertVariant, Avatar, AvatarFallback, type AvatarFallbackProps, AvatarImage, Badge, type BadgeProps, type BadgeSize, type BadgeTone, type BadgeVariant, 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, CopyButton, type CopyButtonProps, DataTable, type DataTableBulkAction, type DataTableColumn, type DataTableProps, type DataTableSort, DetailLayout, type DetailLayoutProps, Dialog, DialogClose, DialogContent, DialogDescription, 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, 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, OrganizationLogo, type OrganizationLogoId, type OrganizationLogoProps, PageHeader, type PageHeaderProps, 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, Separator, Sheet, 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 StatusBadgeProps, 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, type ToastAction, type ToastItem, type ToastOptions, ToastProvider, ToastRoot, type ToastVariant, ToastViewport, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, TwoTierBadge, type TwoTierBadgeIntent, type TwoTierBadgeProps, WizardLayout, type WizardLayoutProps, type WizardStep, type WizardStepState, actionFooterStatusVariants, actionFooterVariants, alertVariants, badgeDotVariants, badgeVariants, 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, getToastDuration, iconButtonBadgeVariants, iconButtonVariants, inlineAlertVariants, inputMessageVariants, inputVariants, limitToasts, modeToggleItemVariants, modeToggleVariants, notificationBadgeVariants, otpCellVariants, otpFieldGroupVariants, otpFieldMessageVariants, otpFieldVariants, paginationControlVariants, paginationVariants, radioControlVariants, radioGroupVariants, radioVariants, searchFieldInputVariants, searchFieldVariants, selectMessageVariants, selectVariants, skeletonVariants, spinnerVariants, statusBadgeDotVariants, statusBadgeVariants, tabsBadgeVariants, tabsListVariants, tabsRootVariants, tabsTriggerVariants, textareaMessageVariants, textareaVariants, toast, toastVariants, toastViewportVariants, twoTierBadgeLineVariants, twoTierBadgeVariants, usePermission };
1422
+ export { ActionFooter, type ActionFooterAction, type ActionFooterProps, type ActionFooterStatus, Alert, type AlertProps, type AlertVariant, Avatar, AvatarFallback, type AvatarFallbackProps, AvatarImage, Badge, type BadgeProps, type BadgeSize, type BadgeTone, type BadgeVariant, 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, CopyButton, type CopyButtonProps, DataTable, type DataTableBulkAction, type DataTableColumn, type DataTableProps, type DataTableSort, DetailLayout, type DetailLayoutProps, Dialog, DialogClose, DialogContent, DialogDescription, 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, 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, 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, Separator, type SetOlunThemeOptions, Sheet, 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 StatusBadgeProps, 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, 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, alertVariants, badgeDotVariants, badgeVariants, 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, inlineAlertVariants, inputMessageVariants, inputVariants, limitToasts, modeToggleItemVariants, modeToggleVariants, notificationBadgeVariants, otpCellVariants, otpFieldGroupVariants, otpFieldMessageVariants, otpFieldVariants, paginationControlVariants, paginationVariants, radioControlVariants, radioGroupVariants, radioVariants, searchFieldInputVariants, searchFieldVariants, selectMessageVariants, selectVariants, setOlunTheme, skeletonVariants, spinnerVariants, statusBadgeDotVariants, statusBadgeVariants, tabsBadgeVariants, tabsListVariants, tabsRootVariants, tabsTriggerVariants, textareaMessageVariants, textareaVariants, toast, toastVariants, toastViewportVariants, treeItemRowVariants, treeViewVariants, twoTierBadgeLineVariants, twoTierBadgeVariants, useOlunTheme, usePermission };
package/dist/index.js CHANGED
@@ -14,6 +14,165 @@ function cn(...inputs) {
14
14
  return twMerge(clsx(inputs));
15
15
  }
16
16
 
17
+ // src/lib/theme.ts
18
+ import { useCallback, useEffect, useState } from "react";
19
+ var STORAGE_KEY = "olun-theme";
20
+ var LEGACY_STORAGE_KEY = "olun-theme-mode";
21
+ var TRANSITION_ATTR = "olunThemeTransition";
22
+ var TRANSITION_DURATION_PROPERTY = "--olun-theme-transition-duration";
23
+ var durationMsByToken = {
24
+ instant: 0,
25
+ fast: 150,
26
+ base: 200,
27
+ slow: 300,
28
+ slower: 400,
29
+ slowest: 600
30
+ };
31
+ var transitionCleanupTimer;
32
+ var defaultThemeState = {
33
+ theme: "light",
34
+ resolvedTheme: "light",
35
+ storedTheme: null,
36
+ source: "default"
37
+ };
38
+ function isOlunTheme(value) {
39
+ return value === "light" || value === "dark";
40
+ }
41
+ function readStoredTheme() {
42
+ if (typeof window === "undefined") return null;
43
+ try {
44
+ const saved = window.localStorage.getItem(STORAGE_KEY);
45
+ if (isOlunTheme(saved)) return saved;
46
+ const legacy = window.localStorage.getItem(LEGACY_STORAGE_KEY);
47
+ return isOlunTheme(legacy) ? legacy : null;
48
+ } catch {
49
+ return null;
50
+ }
51
+ }
52
+ function resolveSystemTheme() {
53
+ if (typeof window === "undefined" || typeof window.matchMedia !== "function") {
54
+ return "light";
55
+ }
56
+ return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
57
+ }
58
+ function getReducedMotionDurationMs(duration) {
59
+ if (typeof window !== "undefined" && typeof window.matchMedia === "function" && window.matchMedia("(prefers-reduced-motion: reduce)").matches) {
60
+ return durationMsByToken.fast;
61
+ }
62
+ return durationMsByToken[duration];
63
+ }
64
+ function getOlunThemeState() {
65
+ if (typeof document !== "undefined") {
66
+ const attr = document.documentElement.getAttribute("data-theme");
67
+ if (isOlunTheme(attr)) {
68
+ return {
69
+ theme: attr,
70
+ resolvedTheme: attr,
71
+ storedTheme: readStoredTheme(),
72
+ source: "attribute"
73
+ };
74
+ }
75
+ }
76
+ const storedTheme = readStoredTheme();
77
+ if (storedTheme) {
78
+ return {
79
+ theme: storedTheme,
80
+ resolvedTheme: storedTheme,
81
+ storedTheme,
82
+ source: "stored"
83
+ };
84
+ }
85
+ if (typeof window !== "undefined") {
86
+ const systemTheme = resolveSystemTheme();
87
+ return {
88
+ theme: systemTheme,
89
+ resolvedTheme: systemTheme,
90
+ storedTheme: null,
91
+ source: "system"
92
+ };
93
+ }
94
+ return defaultThemeState;
95
+ }
96
+ function setOlunTheme(nextTheme, options = {}) {
97
+ if (typeof document === "undefined") return;
98
+ const duration = options.duration ?? "slow";
99
+ const root = document.documentElement;
100
+ if (transitionCleanupTimer !== void 0) {
101
+ window.clearTimeout(transitionCleanupTimer);
102
+ transitionCleanupTimer = void 0;
103
+ }
104
+ if (duration !== "instant") {
105
+ root.dataset[TRANSITION_ATTR] = "true";
106
+ root.style.setProperty(
107
+ TRANSITION_DURATION_PROPERTY,
108
+ `var(--duration-${duration})`
109
+ );
110
+ void root.offsetWidth;
111
+ }
112
+ root.setAttribute("data-theme", nextTheme);
113
+ root.setAttribute("data-theme-mode", nextTheme);
114
+ try {
115
+ window.localStorage.setItem(STORAGE_KEY, nextTheme);
116
+ window.localStorage.removeItem(LEGACY_STORAGE_KEY);
117
+ } catch {
118
+ }
119
+ if (duration !== "instant") {
120
+ const cleanupDelay = getReducedMotionDurationMs(duration) + 80;
121
+ transitionCleanupTimer = window.setTimeout(() => {
122
+ delete root.dataset[TRANSITION_ATTR];
123
+ root.style.removeProperty(TRANSITION_DURATION_PROPERTY);
124
+ transitionCleanupTimer = void 0;
125
+ }, cleanupDelay);
126
+ }
127
+ }
128
+ function useOlunTheme() {
129
+ const [state, setState] = useState(defaultThemeState);
130
+ const [mounted, setMounted] = useState(false);
131
+ useEffect(() => {
132
+ setMounted(true);
133
+ const sync = () => setState(getOlunThemeState());
134
+ sync();
135
+ const observer = new MutationObserver(sync);
136
+ observer.observe(document.documentElement, {
137
+ attributes: true,
138
+ attributeFilter: ["data-theme"]
139
+ });
140
+ const onStorage = (event) => {
141
+ if (event.key === STORAGE_KEY || event.key === LEGACY_STORAGE_KEY) sync();
142
+ };
143
+ window.addEventListener("storage", onStorage);
144
+ return () => {
145
+ observer.disconnect();
146
+ window.removeEventListener("storage", onStorage);
147
+ };
148
+ }, []);
149
+ const setTheme = useCallback(
150
+ (nextTheme, options) => {
151
+ setState((current) => ({
152
+ theme: nextTheme,
153
+ resolvedTheme: nextTheme,
154
+ storedTheme: nextTheme,
155
+ source: "attribute"
156
+ }));
157
+ setOlunTheme(nextTheme, options);
158
+ },
159
+ []
160
+ );
161
+ const toggleTheme = useCallback(
162
+ (options) => {
163
+ const nextTheme = state.resolvedTheme === "dark" ? "light" : "dark";
164
+ setTheme(nextTheme, options);
165
+ },
166
+ [setTheme, state.resolvedTheme]
167
+ );
168
+ return {
169
+ ...state,
170
+ mounted,
171
+ setTheme,
172
+ toggleTheme
173
+ };
174
+ }
175
+
17
176
  // src/components/ui/button.tsx
18
177
  import * as React from "react";
19
178
  import { cva } from "class-variance-authority";
@@ -7728,10 +7887,275 @@ function Progress({
7728
7887
  );
7729
7888
  }
7730
7889
 
7731
- // src/components/branding/olun-logo.tsx
7890
+ // src/components/ui/tree-view.tsx
7891
+ import * as React41 from "react";
7892
+ import { ChevronRight as ChevronRight2 } from "lucide-react";
7893
+ import { cva as cva29 } from "class-variance-authority";
7732
7894
  import { jsx as jsx51, jsxs as jsxs44 } from "react/jsx-runtime";
7895
+ var treeViewVariants = cva29(
7896
+ "m-0 list-none p-[var(--space-0-5)] text-body-sm text-foreground"
7897
+ );
7898
+ var treeItemRowVariants = cva29(
7899
+ [
7900
+ "flex min-h-[var(--touch-target-min)] w-full cursor-pointer select-none items-center gap-[var(--space-1)]",
7901
+ "rounded-[var(--radius-sm)] py-[var(--space-1)] pr-[var(--space-1-5)]",
7902
+ "text-text-secondary transition-colors duration-[var(--duration-fast)] ease-[var(--ease-standard)] motion-reduce:transition-none",
7903
+ "hover:bg-[var(--action-hover)] hover:text-foreground",
7904
+ // Roving focus lives on the treeitem <li> (named group/treeitem); the ring is
7905
+ // painted on the visual row so it never wraps the nested child group.
7906
+ "group-focus-visible/treeitem:outline-none group-focus-visible/treeitem:ring-2 group-focus-visible/treeitem:ring-inset group-focus-visible/treeitem:ring-[var(--focus-ring)]"
7907
+ ].join(" "),
7908
+ {
7909
+ variants: {
7910
+ selected: {
7911
+ // Selected = subtle fill (action-selected), matching nav selected state.
7912
+ // Never a left border (OLUN selected-state doctrine).
7913
+ true: "bg-[var(--action-selected)] font-medium text-foreground",
7914
+ false: ""
7915
+ }
7916
+ },
7917
+ defaultVariants: {
7918
+ selected: false
7919
+ }
7920
+ }
7921
+ );
7922
+ function defaultGetChildren(node) {
7923
+ return node.children;
7924
+ }
7925
+ function flattenVisibleNodes(nodes, getChildren, expandedSet, depth = 1, parentId = null, acc = []) {
7926
+ for (const node of nodes) {
7927
+ const children = getChildren(node);
7928
+ const hasChildren = Array.isArray(children) && children.length > 0;
7929
+ const expanded = hasChildren && expandedSet.has(node.id);
7930
+ acc.push({ node, id: node.id, depth, hasChildren, expanded, parentId });
7931
+ if (expanded && children) {
7932
+ flattenVisibleNodes(children, getChildren, expandedSet, depth + 1, node.id, acc);
7933
+ }
7934
+ }
7935
+ return acc;
7936
+ }
7937
+ function getTreeViewKeyAction(key, items, activeId) {
7938
+ if (items.length === 0 || activeId === null) return null;
7939
+ const index = items.findIndex((item) => item.id === activeId);
7940
+ if (index === -1) return null;
7941
+ const current = items[index];
7942
+ switch (key) {
7943
+ case "ArrowDown": {
7944
+ const next = items[index + 1];
7945
+ return next ? { type: "focus", id: next.id } : null;
7946
+ }
7947
+ case "ArrowUp": {
7948
+ const prev = items[index - 1];
7949
+ return prev ? { type: "focus", id: prev.id } : null;
7950
+ }
7951
+ case "Home":
7952
+ return { type: "focus", id: items[0].id };
7953
+ case "End":
7954
+ return { type: "focus", id: items[items.length - 1].id };
7955
+ case "ArrowRight": {
7956
+ if (current.hasChildren && !current.expanded) {
7957
+ return { type: "expand", id: current.id };
7958
+ }
7959
+ if (current.hasChildren && current.expanded) {
7960
+ const child = items[index + 1];
7961
+ return child && child.parentId === current.id ? { type: "focus", id: child.id } : null;
7962
+ }
7963
+ return null;
7964
+ }
7965
+ case "ArrowLeft": {
7966
+ if (current.hasChildren && current.expanded) {
7967
+ return { type: "collapse", id: current.id };
7968
+ }
7969
+ return current.parentId ? { type: "focus", id: current.parentId } : null;
7970
+ }
7971
+ case "Enter":
7972
+ return { type: "select", id: current.id };
7973
+ case " ":
7974
+ if (current.hasChildren) {
7975
+ return current.expanded ? { type: "collapse", id: current.id } : { type: "expand", id: current.id };
7976
+ }
7977
+ return { type: "select", id: current.id };
7978
+ default:
7979
+ return null;
7980
+ }
7981
+ }
7982
+ function TreeView({
7983
+ nodes,
7984
+ selectedId,
7985
+ selectionAriaCurrent,
7986
+ defaultExpandedIds,
7987
+ expandedIds,
7988
+ onExpandedChange,
7989
+ onSelect,
7990
+ renderItem,
7991
+ getChildren = defaultGetChildren,
7992
+ className,
7993
+ "aria-label": ariaLabel,
7994
+ ...rest
7995
+ }) {
7996
+ const isExpandedControlled = expandedIds !== void 0;
7997
+ const [internalExpanded, setInternalExpanded] = React41.useState(
7998
+ () => defaultExpandedIds ?? []
7999
+ );
8000
+ const expandedList = isExpandedControlled ? expandedIds : internalExpanded;
8001
+ const expandedSet = React41.useMemo(() => new Set(expandedList), [expandedList]);
8002
+ const items = React41.useMemo(
8003
+ () => flattenVisibleNodes(nodes, getChildren, expandedSet),
8004
+ [nodes, getChildren, expandedSet]
8005
+ );
8006
+ const [focusedId, setFocusedId] = React41.useState(null);
8007
+ const visibleIds = items.map((item) => item.id);
8008
+ const activeId = focusedId && visibleIds.includes(focusedId) ? focusedId : selectedId && visibleIds.includes(selectedId) ? selectedId : visibleIds[0] ?? null;
8009
+ const itemRefs = React41.useRef(/* @__PURE__ */ new Map());
8010
+ const commitExpanded = React41.useCallback(
8011
+ (next) => {
8012
+ if (!isExpandedControlled) setInternalExpanded(next);
8013
+ onExpandedChange?.(next);
8014
+ },
8015
+ [isExpandedControlled, onExpandedChange]
8016
+ );
8017
+ const setExpanded = React41.useCallback(
8018
+ (id, expand) => {
8019
+ const has = expandedSet.has(id);
8020
+ if (expand && !has) {
8021
+ commitExpanded([...expandedList, id]);
8022
+ } else if (!expand && has) {
8023
+ commitExpanded(expandedList.filter((value) => value !== id));
8024
+ }
8025
+ },
8026
+ [commitExpanded, expandedList, expandedSet]
8027
+ );
8028
+ const focusItem = React41.useCallback((id) => {
8029
+ setFocusedId(id);
8030
+ itemRefs.current.get(id)?.focus();
8031
+ }, []);
8032
+ const handleKeyDown = (event) => {
8033
+ const target = event.target;
8034
+ if (target.getAttribute("role") !== "treeitem") return;
8035
+ const targetId = target.getAttribute("data-id") ?? activeId;
8036
+ const action = getTreeViewKeyAction(event.key, items, targetId);
8037
+ if (!action) return;
8038
+ event.preventDefault();
8039
+ switch (action.type) {
8040
+ case "focus":
8041
+ focusItem(action.id);
8042
+ break;
8043
+ case "expand":
8044
+ setExpanded(action.id, true);
8045
+ break;
8046
+ case "collapse":
8047
+ setExpanded(action.id, false);
8048
+ break;
8049
+ case "select": {
8050
+ const item = items.find((entry) => entry.id === action.id);
8051
+ if (item) onSelect?.(item.id, item.node);
8052
+ break;
8053
+ }
8054
+ }
8055
+ };
8056
+ function renderLevel(levelNodes, depth) {
8057
+ return levelNodes.map((node) => {
8058
+ const children = getChildren(node);
8059
+ const hasChildren = Array.isArray(children) && children.length > 0;
8060
+ const expanded = hasChildren && expandedSet.has(node.id);
8061
+ const selected = node.id === selectedId;
8062
+ const isActive = node.id === activeId;
8063
+ const itemState = { expanded, selected, depth, hasChildren };
8064
+ return /* @__PURE__ */ jsxs44(
8065
+ "li",
8066
+ {
8067
+ ref: (element) => {
8068
+ if (element) itemRefs.current.set(node.id, element);
8069
+ else itemRefs.current.delete(node.id);
8070
+ },
8071
+ role: "treeitem",
8072
+ "data-slot": "treeitem",
8073
+ "data-id": node.id,
8074
+ "aria-level": depth,
8075
+ "aria-expanded": hasChildren ? expanded : void 0,
8076
+ "aria-selected": selected ? true : void 0,
8077
+ "aria-current": selected && selectionAriaCurrent ? selectionAriaCurrent : void 0,
8078
+ "data-selected": selected ? "true" : void 0,
8079
+ tabIndex: isActive ? 0 : -1,
8080
+ className: "group/treeitem block outline-none",
8081
+ onFocus: (event) => {
8082
+ if (event.target === event.currentTarget) setFocusedId(node.id);
8083
+ },
8084
+ onClick: (event) => {
8085
+ event.stopPropagation();
8086
+ onSelect?.(node.id, node);
8087
+ },
8088
+ children: [
8089
+ /* @__PURE__ */ jsxs44(
8090
+ "span",
8091
+ {
8092
+ "data-slot": "treeitem-row",
8093
+ style: {
8094
+ paddingInlineStart: `calc(var(--space-1) + var(--space-2) * ${depth - 1})`
8095
+ },
8096
+ className: treeItemRowVariants({ selected }),
8097
+ children: [
8098
+ hasChildren ? /* @__PURE__ */ jsx51(
8099
+ "span",
8100
+ {
8101
+ "data-slot": "treeitem-toggle",
8102
+ "aria-hidden": "true",
8103
+ onClick: (event) => {
8104
+ event.stopPropagation();
8105
+ setExpanded(node.id, !expanded);
8106
+ },
8107
+ className: "flex size-[var(--space-2)] shrink-0 items-center justify-center text-text-tertiary",
8108
+ children: /* @__PURE__ */ jsx51(
8109
+ ChevronRight2,
8110
+ {
8111
+ "aria-hidden": "true",
8112
+ "data-slot": "treeitem-chevron",
8113
+ className: cn(
8114
+ "size-[16px] transition-transform duration-[var(--duration-fast)] ease-[var(--ease-standard)] motion-reduce:transition-none",
8115
+ expanded && "rotate-90"
8116
+ ),
8117
+ strokeWidth: 2
8118
+ }
8119
+ )
8120
+ }
8121
+ ) : /* @__PURE__ */ jsx51(
8122
+ "span",
8123
+ {
8124
+ "data-slot": "treeitem-spacer",
8125
+ "aria-hidden": "true",
8126
+ className: "size-[var(--space-2)] shrink-0"
8127
+ }
8128
+ ),
8129
+ /* @__PURE__ */ jsx51("span", { className: "flex min-w-0 flex-1 items-center gap-[var(--space-1)]", children: renderItem(node, itemState) })
8130
+ ]
8131
+ }
8132
+ ),
8133
+ hasChildren && expanded && children ? /* @__PURE__ */ jsx51("ul", { role: "group", "data-slot": "tree-group", className: "m-0 list-none p-0", children: renderLevel(children, depth + 1) }) : null
8134
+ ]
8135
+ },
8136
+ node.id
8137
+ );
8138
+ });
8139
+ }
8140
+ return /* @__PURE__ */ jsx51(
8141
+ "ul",
8142
+ {
8143
+ role: "tree",
8144
+ "data-slot": "tree",
8145
+ "aria-label": ariaLabel,
8146
+ "aria-multiselectable": false,
8147
+ className: cn(treeViewVariants(), className),
8148
+ onKeyDown: handleKeyDown,
8149
+ ...rest,
8150
+ children: renderLevel(nodes, 1)
8151
+ }
8152
+ );
8153
+ }
8154
+
8155
+ // src/components/branding/olun-logo.tsx
8156
+ import { jsx as jsx52, jsxs as jsxs45 } from "react/jsx-runtime";
7733
8157
  function OlunSymbol({ size = 28, className }) {
7734
- return /* @__PURE__ */ jsxs44(
8158
+ return /* @__PURE__ */ jsxs45(
7735
8159
  "svg",
7736
8160
  {
7737
8161
  width: size,
@@ -7742,7 +8166,7 @@ function OlunSymbol({ size = 28, className }) {
7742
8166
  className,
7743
8167
  "aria-hidden": "true",
7744
8168
  children: [
7745
- /* @__PURE__ */ jsx51(
8169
+ /* @__PURE__ */ jsx52(
7746
8170
  "circle",
7747
8171
  {
7748
8172
  cx: "108",
@@ -7754,7 +8178,7 @@ function OlunSymbol({ size = 28, className }) {
7754
8178
  style: { color: "var(--text-primary)" }
7755
8179
  }
7756
8180
  ),
7757
- /* @__PURE__ */ jsx51("circle", { cx: "185", cy: "175", r: "22", fill: "var(--accent-solid)" })
8181
+ /* @__PURE__ */ jsx52("circle", { cx: "185", cy: "175", r: "22", fill: "var(--accent-solid)" })
7758
8182
  ]
7759
8183
  }
7760
8184
  );
@@ -7765,7 +8189,7 @@ function OlunLogo({
7765
8189
  showSymbol = true,
7766
8190
  className
7767
8191
  }) {
7768
- return /* @__PURE__ */ jsxs44(
8192
+ return /* @__PURE__ */ jsxs45(
7769
8193
  "div",
7770
8194
  {
7771
8195
  className,
@@ -7775,8 +8199,8 @@ function OlunLogo({
7775
8199
  gap: "var(--space-1-5)"
7776
8200
  },
7777
8201
  children: [
7778
- showSymbol && /* @__PURE__ */ jsx51(OlunSymbol, { size: symbolSize }),
7779
- /* @__PURE__ */ jsxs44(
8202
+ showSymbol && /* @__PURE__ */ jsx52(OlunSymbol, { size: symbolSize }),
8203
+ /* @__PURE__ */ jsxs45(
7780
8204
  "span",
7781
8205
  {
7782
8206
  style: {
@@ -7788,7 +8212,7 @@ function OlunLogo({
7788
8212
  },
7789
8213
  children: [
7790
8214
  "OLUN",
7791
- /* @__PURE__ */ jsx51("span", { style: { color: "var(--accent-fg)" }, children: "." })
8215
+ /* @__PURE__ */ jsx52("span", { style: { color: "var(--accent-fg)" }, children: "." })
7792
8216
  ]
7793
8217
  }
7794
8218
  )
@@ -7798,46 +8222,15 @@ function OlunLogo({
7798
8222
  }
7799
8223
 
7800
8224
  // src/components/branding/theme-toggle.tsx
7801
- import { useEffect as useEffect4, useState as useState13 } from "react";
7802
8225
  import { Sun, Moon } from "lucide-react";
7803
- import { jsx as jsx52 } from "react/jsx-runtime";
8226
+ import { jsx as jsx53 } from "react/jsx-runtime";
7804
8227
  function ThemeToggle({ className }) {
7805
- const [theme, setTheme] = useState13("light");
7806
- useEffect4(() => {
7807
- const resolve = () => {
7808
- const attr = document.documentElement.getAttribute("data-theme");
7809
- if (attr === "light" || attr === "dark") return attr;
7810
- const stored = localStorage.getItem("olun-theme");
7811
- if (stored === "light" || stored === "dark") return stored;
7812
- return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
7813
- };
7814
- setTheme(resolve());
7815
- const sync = () => setTheme(resolve());
7816
- const observer = new MutationObserver(sync);
7817
- observer.observe(document.documentElement, {
7818
- attributes: true,
7819
- attributeFilter: ["data-theme"]
7820
- });
7821
- const onStorage = (e) => {
7822
- if (e.key === "olun-theme") sync();
7823
- };
7824
- window.addEventListener("storage", onStorage);
7825
- return () => {
7826
- observer.disconnect();
7827
- window.removeEventListener("storage", onStorage);
7828
- };
7829
- }, []);
7830
- function toggle() {
7831
- const next = theme === "dark" ? "light" : "dark";
7832
- setTheme(next);
7833
- document.documentElement.setAttribute("data-theme", next);
7834
- localStorage.setItem("olun-theme", next);
7835
- }
7836
- const Icon = theme === "dark" ? Moon : Sun;
7837
- return /* @__PURE__ */ jsx52(
8228
+ const { resolvedTheme, toggleTheme } = useOlunTheme();
8229
+ const Icon = resolvedTheme === "dark" ? Moon : Sun;
8230
+ return /* @__PURE__ */ jsx53(
7838
8231
  "button",
7839
8232
  {
7840
- onClick: toggle,
8233
+ onClick: () => toggleTheme(),
7841
8234
  className: cn(
7842
8235
  "inline-flex size-[36px] items-center justify-center rounded-sm",
7843
8236
  "text-text-secondary hover:bg-[var(--action-hover)] hover:text-foreground",
@@ -7845,54 +8238,21 @@ function ThemeToggle({ className }) {
7845
8238
  className
7846
8239
  ),
7847
8240
  "aria-label": "\uD14C\uB9C8 \uC804\uD658",
7848
- title: theme === "dark" ? "\uB77C\uC774\uD2B8 \uBAA8\uB4DC\uB85C" : "\uB2E4\uD06C \uBAA8\uB4DC\uB85C",
7849
- children: /* @__PURE__ */ jsx52(Icon, { className: "size-[18px]", strokeWidth: 1.75 })
8241
+ title: resolvedTheme === "dark" ? "\uB77C\uC774\uD2B8 \uBAA8\uB4DC\uB85C" : "\uB2E4\uD06C \uBAA8\uB4DC\uB85C",
8242
+ children: /* @__PURE__ */ jsx53(Icon, { className: "size-[18px]", strokeWidth: 1.75 })
7850
8243
  }
7851
8244
  );
7852
8245
  }
7853
8246
 
7854
8247
  // src/components/branding/theme-fab.tsx
7855
- import { useEffect as useEffect5, useState as useState14 } from "react";
7856
8248
  import { Sun as Sun2, Moon as Moon2 } from "lucide-react";
7857
- import { jsx as jsx53 } from "react/jsx-runtime";
8249
+ import { jsx as jsx54 } from "react/jsx-runtime";
7858
8250
  function ThemeFab({ variant = "square" } = {}) {
7859
- const [theme, setTheme] = useState14("light");
7860
- const [mounted, setMounted] = useState14(false);
7861
- useEffect5(() => {
7862
- setMounted(true);
7863
- const resolve = () => {
7864
- const attr = document.documentElement.getAttribute("data-theme");
7865
- if (attr === "light" || attr === "dark") return attr;
7866
- const stored = localStorage.getItem("olun-theme");
7867
- if (stored === "light" || stored === "dark") return stored;
7868
- return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
7869
- };
7870
- setTheme(resolve());
7871
- const sync = () => setTheme(resolve());
7872
- const observer = new MutationObserver(sync);
7873
- observer.observe(document.documentElement, {
7874
- attributes: true,
7875
- attributeFilter: ["data-theme"]
7876
- });
7877
- const onStorage = (e) => {
7878
- if (e.key === "olun-theme") sync();
7879
- };
7880
- window.addEventListener("storage", onStorage);
7881
- return () => {
7882
- observer.disconnect();
7883
- window.removeEventListener("storage", onStorage);
7884
- };
7885
- }, []);
7886
- function toggle() {
7887
- const next = theme === "dark" ? "light" : "dark";
7888
- setTheme(next);
7889
- document.documentElement.setAttribute("data-theme", next);
7890
- localStorage.setItem("olun-theme", next);
7891
- }
8251
+ const { mounted, resolvedTheme, toggleTheme } = useOlunTheme();
7892
8252
  if (!mounted) {
7893
8253
  return null;
7894
8254
  }
7895
- const Icon = theme === "dark" ? Moon2 : Sun2;
8255
+ const Icon = resolvedTheme === "dark" ? Moon2 : Sun2;
7896
8256
  const isCircle = variant === "circle";
7897
8257
  const baseStyle = {
7898
8258
  position: "fixed",
@@ -7926,13 +8286,13 @@ function ThemeFab({ variant = "square" } = {}) {
7926
8286
  WebkitBackdropFilter: "blur(16px)",
7927
8287
  zIndex: 9999
7928
8288
  };
7929
- return /* @__PURE__ */ jsx53(
8289
+ return /* @__PURE__ */ jsx54(
7930
8290
  "button",
7931
8291
  {
7932
- onClick: toggle,
8292
+ onClick: () => toggleTheme(),
7933
8293
  "aria-label": "\uD14C\uB9C8 \uC804\uD658",
7934
- "aria-pressed": theme === "light",
7935
- title: theme === "dark" ? "\uB77C\uC774\uD2B8 \uBAA8\uB4DC\uB85C" : "\uB2E4\uD06C \uBAA8\uB4DC\uB85C",
8294
+ "aria-pressed": resolvedTheme === "light",
8295
+ title: resolvedTheme === "dark" ? "\uB77C\uC774\uD2B8 \uBAA8\uB4DC\uB85C" : "\uB2E4\uD06C \uBAA8\uB4DC\uB85C",
7936
8296
  className: "transition-colors motion-reduce:transition-none",
7937
8297
  style: { ...baseStyle, ...isCircle ? circleStyle : squareStyle },
7938
8298
  onMouseEnter: (e) => {
@@ -7951,7 +8311,7 @@ function ThemeFab({ variant = "square" } = {}) {
7951
8311
  e.currentTarget.style.color = "var(--text-secondary)";
7952
8312
  }
7953
8313
  },
7954
- children: /* @__PURE__ */ jsx53(
8314
+ children: /* @__PURE__ */ jsx54(
7955
8315
  Icon,
7956
8316
  {
7957
8317
  size: isCircle ? 22 : 16,
@@ -7963,7 +8323,7 @@ function ThemeFab({ variant = "square" } = {}) {
7963
8323
  }
7964
8324
 
7965
8325
  // src/components/logos/organization-logo.tsx
7966
- import { jsx as jsx54 } from "react/jsx-runtime";
8326
+ import { jsx as jsx55 } from "react/jsx-runtime";
7967
8327
  var organizationLogoRegistry = {
7968
8328
  jbnu: {
7969
8329
  label: "\uC804\uBD81\uB300\uD559\uAD50 \uC5E0\uBE14\uB7FC",
@@ -7992,7 +8352,7 @@ function OrganizationLogo({
7992
8352
  }) {
7993
8353
  const asset = organizationLogoRegistry[organization];
7994
8354
  const isDecorative = ariaHidden === true || ariaHidden === "true";
7995
- return /* @__PURE__ */ jsx54(
8355
+ return /* @__PURE__ */ jsx55(
7996
8356
  "svg",
7997
8357
  {
7998
8358
  viewBox: asset.viewBox,
@@ -8010,7 +8370,7 @@ function OrganizationLogo({
8010
8370
  ...style
8011
8371
  },
8012
8372
  ...props,
8013
- children: asset.paths.map((path) => /* @__PURE__ */ jsx54("path", { d: path }, path))
8373
+ children: asset.paths.map((path) => /* @__PURE__ */ jsx55("path", { d: path }, path))
8014
8374
  }
8015
8375
  );
8016
8376
  }
@@ -8127,6 +8487,7 @@ export {
8127
8487
  TooltipContent,
8128
8488
  TooltipProvider,
8129
8489
  TooltipTrigger,
8490
+ TreeView,
8130
8491
  TwoTierBadge,
8131
8492
  WizardLayout,
8132
8493
  actionFooterStatusVariants,
@@ -8160,6 +8521,7 @@ export {
8160
8521
  formFieldLabelClassName,
8161
8522
  formFieldRequiredClassName,
8162
8523
  formFieldVariants,
8524
+ getOlunThemeState,
8163
8525
  getToastDuration,
8164
8526
  iconButtonBadgeVariants,
8165
8527
  iconButtonVariants,
@@ -8183,6 +8545,7 @@ export {
8183
8545
  searchFieldVariants,
8184
8546
  selectMessageVariants,
8185
8547
  selectVariants,
8548
+ setOlunTheme,
8186
8549
  skeletonVariants,
8187
8550
  spinnerVariants,
8188
8551
  statusBadgeDotVariants,
@@ -8196,7 +8559,10 @@ export {
8196
8559
  toast,
8197
8560
  toastVariants,
8198
8561
  toastViewportVariants,
8562
+ treeItemRowVariants,
8563
+ treeViewVariants,
8199
8564
  twoTierBadgeLineVariants,
8200
8565
  twoTierBadgeVariants,
8566
+ useOlunTheme,
8201
8567
  usePermission
8202
8568
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@olundot/ui",
3
- "version": "0.4.0",
3
+ "version": "0.6.0",
4
4
  "description": "OLUN. shared React UI components built on OLUN design tokens",
5
5
  "license": "MIT",
6
6
  "keywords": [
@@ -14,7 +14,7 @@
14
14
  "homepage": "https://olun-design-system.vercel.app",
15
15
  "repository": {
16
16
  "type": "git",
17
- "url": "https://github.com/armedical-dev/olun-design-system",
17
+ "url": "https://github.com/olundot/olun-design-system",
18
18
  "directory": "packages/ui"
19
19
  },
20
20
  "type": "module",
@@ -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.9.0"
47
+ "@olundot/tokens": "^0.10.0"
48
48
  },
49
49
  "peerDependencies": {
50
50
  "react": ">=18",