@birdycom/omniaui-react 0.11.0 → 0.11.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (143) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +21 -21
  3. package/package.json +71 -71
  4. package/src/blocks/BlockAboutTimeline.tsx +46 -46
  5. package/src/blocks/BlockAppHeader.tsx +52 -52
  6. package/src/blocks/BlockAppShell.tsx +56 -56
  7. package/src/blocks/BlockAuth.tsx +53 -53
  8. package/src/blocks/BlockAuthSplit.tsx +84 -84
  9. package/src/blocks/BlockContactGrid.tsx +71 -71
  10. package/src/blocks/BlockCta.tsx +23 -23
  11. package/src/blocks/BlockDataTable.tsx +57 -57
  12. package/src/blocks/BlockFaq.tsx +55 -55
  13. package/src/blocks/BlockFeatures.tsx +38 -38
  14. package/src/blocks/BlockFooter.tsx +50 -50
  15. package/src/blocks/BlockFormPage.tsx +26 -26
  16. package/src/blocks/BlockHero.tsx +27 -27
  17. package/src/blocks/BlockHeroCode.tsx +63 -63
  18. package/src/blocks/BlockHeroOrbit.tsx +73 -73
  19. package/src/blocks/BlockHeroSplit.tsx +28 -28
  20. package/src/blocks/BlockModuleHeader.tsx +34 -34
  21. package/src/blocks/BlockPageHero.tsx +25 -25
  22. package/src/blocks/BlockPortfolioGrid.tsx +50 -50
  23. package/src/blocks/BlockPricing.tsx +62 -62
  24. package/src/blocks/BlockProcess.tsx +50 -50
  25. package/src/blocks/BlockProductGrid.tsx +54 -54
  26. package/src/blocks/BlockProfileHeader.tsx +57 -57
  27. package/src/blocks/BlockShowcase.tsx +58 -58
  28. package/src/blocks/BlockSiteFooter.tsx +60 -60
  29. package/src/blocks/BlockSiteHeader.tsx +42 -42
  30. package/src/blocks/BlockSpotlight.tsx +58 -58
  31. package/src/blocks/BlockStats.tsx +26 -26
  32. package/src/blocks/BlockStatsCounter.tsx +31 -31
  33. package/src/blocks/BlockTeamList.tsx +48 -48
  34. package/src/blocks/BlockTwoFactor.tsx +57 -57
  35. package/src/blocks/BlockWizardDialog.tsx +101 -101
  36. package/src/components/Accordion.tsx +31 -31
  37. package/src/components/AccordionAccent.tsx +39 -39
  38. package/src/components/AffixInput.tsx +47 -47
  39. package/src/components/Alert.tsx +24 -24
  40. package/src/components/AlertDialog.tsx +60 -60
  41. package/src/components/AlphaTabs.tsx +63 -63
  42. package/src/components/Attachment.tsx +140 -140
  43. package/src/components/Avatar.tsx +32 -32
  44. package/src/components/BackLink.tsx +11 -11
  45. package/src/components/Badge.tsx +14 -14
  46. package/src/components/BarcodeInput.tsx +64 -64
  47. package/src/components/Breadcrumb.tsx +32 -32
  48. package/src/components/BrowserFrame.tsx +48 -48
  49. package/src/components/BusyOverlay.tsx +52 -52
  50. package/src/components/Button.tsx +49 -49
  51. package/src/components/Card.tsx +27 -27
  52. package/src/components/ChartLine.tsx +119 -119
  53. package/src/components/ChatComposer.tsx +73 -73
  54. package/src/components/Checkbox.tsx +14 -14
  55. package/src/components/Checklist.tsx +45 -45
  56. package/src/components/ChipFilter.tsx +60 -60
  57. package/src/components/Collapsible.tsx +43 -43
  58. package/src/components/ColorField.tsx +48 -48
  59. package/src/components/ColorSelect.tsx +49 -49
  60. package/src/components/ColumnMenu.tsx +66 -66
  61. package/src/components/Command.tsx +113 -113
  62. package/src/components/ConfirmDialog.tsx +95 -95
  63. package/src/components/CookieConsent.tsx +137 -137
  64. package/src/components/CopyField.tsx +44 -44
  65. package/src/components/Counter.tsx +21 -21
  66. package/src/components/DataTable.tsx +201 -201
  67. package/src/components/DecimalInput.tsx +87 -87
  68. package/src/components/DefinitionList.tsx +38 -38
  69. package/src/components/DocViewer.tsx +110 -110
  70. package/src/components/Dropdown.tsx +52 -52
  71. package/src/components/Dropzone.tsx +46 -46
  72. package/src/components/EmojiPicker.tsx +72 -72
  73. package/src/components/EmptyState.tsx +27 -27
  74. package/src/components/EntityCard.tsx +56 -56
  75. package/src/components/FactList.tsx +43 -43
  76. package/src/components/FilterCounts.tsx +50 -50
  77. package/src/components/FlipCard.tsx +55 -55
  78. package/src/components/FormField.tsx +54 -54
  79. package/src/components/Greeting.tsx +63 -63
  80. package/src/components/Heading.tsx +27 -27
  81. package/src/components/Icon.tsx +25 -25
  82. package/src/components/ImageZoom.tsx +51 -51
  83. package/src/components/Input.tsx +21 -21
  84. package/src/components/InputGroup.tsx +24 -24
  85. package/src/components/LanguageSelect.tsx +64 -64
  86. package/src/components/LauncherCard.tsx +50 -50
  87. package/src/components/Lightbox.tsx +83 -83
  88. package/src/components/LinkArrow.tsx +27 -27
  89. package/src/components/ListToolbar.tsx +67 -67
  90. package/src/components/Marquee.tsx +38 -38
  91. package/src/components/MediaCard.tsx +47 -47
  92. package/src/components/MediaRow.tsx +53 -53
  93. package/src/components/MediaThumb.tsx +49 -49
  94. package/src/components/Message.tsx +171 -171
  95. package/src/components/MessageThread.tsx +177 -177
  96. package/src/components/Modal.tsx +81 -81
  97. package/src/components/Navmenu.tsx +62 -62
  98. package/src/components/NextTeaser.tsx +29 -29
  99. package/src/components/NumberInput.tsx +64 -64
  100. package/src/components/OtpInput.tsx +48 -48
  101. package/src/components/PageHeader.tsx +43 -43
  102. package/src/components/Pagination.tsx +42 -42
  103. package/src/components/PasswordInput.tsx +36 -36
  104. package/src/components/PasswordRequirements.tsx +46 -46
  105. package/src/components/PhoneInput.tsx +93 -93
  106. package/src/components/Popover.tsx +34 -34
  107. package/src/components/PriceCard.tsx +83 -83
  108. package/src/components/ProductMark.tsx +35 -35
  109. package/src/components/Progress.tsx +32 -32
  110. package/src/components/ProjectCard.tsx +46 -46
  111. package/src/components/Prose.tsx +79 -79
  112. package/src/components/RecoveryCodes.tsx +65 -65
  113. package/src/components/Segmented.tsx +47 -47
  114. package/src/components/Select.tsx +27 -27
  115. package/src/components/SeverityCard.tsx +53 -53
  116. package/src/components/Sheet.tsx +62 -62
  117. package/src/components/Skeleton.tsx +12 -12
  118. package/src/components/SortableRow.tsx +46 -46
  119. package/src/components/StackCard.tsx +40 -40
  120. package/src/components/StackList.tsx +42 -42
  121. package/src/components/StatCard.tsx +49 -49
  122. package/src/components/Stepper.tsx +54 -54
  123. package/src/components/Switch.tsx +18 -18
  124. package/src/components/Table.tsx +75 -75
  125. package/src/components/TableActions.tsx +54 -54
  126. package/src/components/TableCompact.tsx +61 -61
  127. package/src/components/Tabs.tsx +45 -45
  128. package/src/components/TagInput.tsx +73 -73
  129. package/src/components/TerminalLog.tsx +63 -63
  130. package/src/components/Textarea.tsx +19 -19
  131. package/src/components/ThemeSwitch.tsx +45 -45
  132. package/src/components/TimeInput.tsx +76 -76
  133. package/src/components/Timeline.tsx +45 -45
  134. package/src/components/Toast.tsx +138 -138
  135. package/src/components/ToggleField.tsx +39 -39
  136. package/src/components/Tooltip.tsx +14 -14
  137. package/src/components/TopProgress.tsx +54 -54
  138. package/src/components/Tree.tsx +97 -97
  139. package/src/components/UpgradeBanner.tsx +62 -62
  140. package/src/components/User.tsx +31 -31
  141. package/src/components/VersionBanner.tsx +41 -41
  142. package/src/hooks.tsx +141 -141
  143. package/src/utils.ts +25 -25
package/src/hooks.tsx CHANGED
@@ -1,141 +1,141 @@
1
- "use client";
2
-
3
- import { createContext, useCallback, useContext, useEffect, useRef, useState } from "react";
4
- import type { RefObject, SyntheticEvent } from "react";
5
-
6
- /** Merge several refs into one callback ref. */
7
- export function useMergedRef<T>(...refs: Array<React.Ref<T> | undefined>) {
8
- return useCallback((node: T | null) => {
9
- for (const ref of refs) {
10
- if (typeof ref === "function") ref(node);
11
- else if (ref) (ref as React.MutableRefObject<T | null>).current = node;
12
- }
13
- // eslint-disable-next-line react-hooks/exhaustive-deps
14
- }, refs);
15
- }
16
-
17
- /** Controlled + uncontrolled value in one hook. */
18
- export function useControllable<T>(value: T | undefined, defaultValue: T, onChange?: (v: T) => void) {
19
- const [inner, setInner] = useState<T>(defaultValue);
20
- const controlled = value !== undefined;
21
- const current = controlled ? (value as T) : inner;
22
- const set = useCallback(
23
- (next: T) => {
24
- if (!controlled) setInner(next);
25
- onChange?.(next);
26
- },
27
- [controlled, onChange],
28
- );
29
- return [current, set] as const;
30
- }
31
-
32
- export interface DialogState {
33
- open?: boolean;
34
- defaultOpen?: boolean;
35
- onOpenChange?: (open: boolean) => void;
36
- }
37
-
38
- export const DialogContext = createContext<{ close: () => void } | null>(null);
39
- export const useDialogContext = () => useContext(DialogContext);
40
-
41
- /**
42
- * Keeps a native <dialog> in sync with an `open` prop: showModal() / close() in an effect,
43
- * and reports native closes (Escape, backdrop, form method=dialog) through onOpenChange.
44
- */
45
- export function useDialog(ref: RefObject<HTMLDialogElement | null>, { open, defaultOpen, onOpenChange }: DialogState) {
46
- const [isOpen, setOpen] = useControllable<boolean>(open, defaultOpen ?? false, onOpenChange);
47
- const openRef = useRef(isOpen);
48
- openRef.current = isOpen;
49
-
50
- useEffect(() => {
51
- const dialog = ref.current;
52
- if (!dialog) return;
53
- if (isOpen && !dialog.open) dialog.showModal?.();
54
- else if (!isOpen && dialog.open) dialog.close?.();
55
- }, [isOpen, ref]);
56
-
57
- const onClose = useCallback(
58
- (e: SyntheticEvent<HTMLDialogElement>) => {
59
- e.stopPropagation();
60
- if (openRef.current) setOpen(false);
61
- },
62
- [setOpen],
63
- );
64
- const close = useCallback(() => setOpen(false), [setOpen]);
65
- return { open: isOpen, setOpen, close, onClose };
66
- }
67
-
68
- /* ---------------------------------------------------------------------------------------------
69
- * Menu keyboard helpers (shared by DropdownMenu, Menubar and ContextMenu)
70
- * ------------------------------------------------------------------------------------------- */
71
-
72
- /** Focusable items that belong directly to a `[role=menu]` (sub-menu triggers included, sub-menu items excluded). */
73
- export function menuItems(menu: Element): HTMLElement[] {
74
- const out: HTMLElement[] = [];
75
- for (const child of Array.from(menu.children)) {
76
- if (child.matches('[role^="menuitem"]')) out.push(child as HTMLElement);
77
- else if (child.classList.contains("oc-dropdown-sub") && child.firstElementChild) out.push(child.firstElementChild as HTMLElement);
78
- }
79
- return out.filter((el) => el.getAttribute("aria-disabled") !== "true" && !(el as HTMLButtonElement).disabled);
80
- }
81
-
82
- /**
83
- * Roving focus inside an `.oc-dropdown-menu[role=menu]`: ArrowDown / ArrowUp (wrapping), Home, End,
84
- * ArrowRight on a sub-menu trigger enters the sub-menu, ArrowLeft inside a sub-menu returns to its trigger.
85
- * Returns `true` (and calls preventDefault) when the key was handled.
86
- */
87
- export function handleMenuKeyDown(e: React.KeyboardEvent<HTMLElement>): boolean {
88
- const item = (e.target as HTMLElement).closest<HTMLElement>('[role^="menuitem"]');
89
- const menu = item?.closest<HTMLElement>('[role="menu"]');
90
- if (!item || !menu) return false;
91
- const items = menuItems(menu);
92
- const at = items.indexOf(item);
93
- let next: HTMLElement | undefined;
94
- switch (e.key) {
95
- case "ArrowDown":
96
- next = items[(at + 1) % items.length];
97
- break;
98
- case "ArrowUp":
99
- next = items[(at - 1 + items.length) % items.length];
100
- break;
101
- case "Home":
102
- next = items[0];
103
- break;
104
- case "End":
105
- next = items[items.length - 1];
106
- break;
107
- case "ArrowRight": {
108
- const sub = item.parentElement?.classList.contains("oc-dropdown-sub") ? item.parentElement.querySelector<HTMLElement>(".oc-dropdown-submenu") : null;
109
- next = sub ? menuItems(sub)[0] : undefined;
110
- break;
111
- }
112
- case "ArrowLeft":
113
- if (menu.classList.contains("oc-dropdown-submenu")) next = menu.parentElement?.firstElementChild as HTMLElement | undefined;
114
- break;
115
- default:
116
- return false;
117
- }
118
- if (!next) return false;
119
- e.preventDefault();
120
- e.stopPropagation();
121
- next.focus();
122
- return true;
123
- }
124
-
125
- /** Closes the popover a menu item lives in. */
126
- export function closeMenuOf(el: Element | null) {
127
- (el?.closest("[popover]") as (HTMLElement & { hidePopover?: () => void }) | null)?.hidePopover?.();
128
- }
129
-
130
- /** Focuses the first menu item whenever the popover opens (the native `toggle` event). */
131
- export function useMenuAutofocus(ref: RefObject<HTMLElement | null>) {
132
- useEffect(() => {
133
- const el = ref.current;
134
- if (!el) return;
135
- const onToggle = (e: Event) => {
136
- if ((e as Event & { newState?: string }).newState === "open") menuItems(el)[0]?.focus();
137
- };
138
- el.addEventListener("toggle", onToggle);
139
- return () => el.removeEventListener("toggle", onToggle);
140
- }, [ref]);
141
- }
1
+ "use client";
2
+
3
+ import { createContext, useCallback, useContext, useEffect, useRef, useState } from "react";
4
+ import type { RefObject, SyntheticEvent } from "react";
5
+
6
+ /** Merge several refs into one callback ref. */
7
+ export function useMergedRef<T>(...refs: Array<React.Ref<T> | undefined>) {
8
+ return useCallback((node: T | null) => {
9
+ for (const ref of refs) {
10
+ if (typeof ref === "function") ref(node);
11
+ else if (ref) (ref as React.MutableRefObject<T | null>).current = node;
12
+ }
13
+ // eslint-disable-next-line react-hooks/exhaustive-deps
14
+ }, refs);
15
+ }
16
+
17
+ /** Controlled + uncontrolled value in one hook. */
18
+ export function useControllable<T>(value: T | undefined, defaultValue: T, onChange?: (v: T) => void) {
19
+ const [inner, setInner] = useState<T>(defaultValue);
20
+ const controlled = value !== undefined;
21
+ const current = controlled ? (value as T) : inner;
22
+ const set = useCallback(
23
+ (next: T) => {
24
+ if (!controlled) setInner(next);
25
+ onChange?.(next);
26
+ },
27
+ [controlled, onChange],
28
+ );
29
+ return [current, set] as const;
30
+ }
31
+
32
+ export interface DialogState {
33
+ open?: boolean;
34
+ defaultOpen?: boolean;
35
+ onOpenChange?: (open: boolean) => void;
36
+ }
37
+
38
+ export const DialogContext = createContext<{ close: () => void } | null>(null);
39
+ export const useDialogContext = () => useContext(DialogContext);
40
+
41
+ /**
42
+ * Keeps a native <dialog> in sync with an `open` prop: showModal() / close() in an effect,
43
+ * and reports native closes (Escape, backdrop, form method=dialog) through onOpenChange.
44
+ */
45
+ export function useDialog(ref: RefObject<HTMLDialogElement | null>, { open, defaultOpen, onOpenChange }: DialogState) {
46
+ const [isOpen, setOpen] = useControllable<boolean>(open, defaultOpen ?? false, onOpenChange);
47
+ const openRef = useRef(isOpen);
48
+ openRef.current = isOpen;
49
+
50
+ useEffect(() => {
51
+ const dialog = ref.current;
52
+ if (!dialog) return;
53
+ if (isOpen && !dialog.open) dialog.showModal?.();
54
+ else if (!isOpen && dialog.open) dialog.close?.();
55
+ }, [isOpen, ref]);
56
+
57
+ const onClose = useCallback(
58
+ (e: SyntheticEvent<HTMLDialogElement>) => {
59
+ e.stopPropagation();
60
+ if (openRef.current) setOpen(false);
61
+ },
62
+ [setOpen],
63
+ );
64
+ const close = useCallback(() => setOpen(false), [setOpen]);
65
+ return { open: isOpen, setOpen, close, onClose };
66
+ }
67
+
68
+ /* ---------------------------------------------------------------------------------------------
69
+ * Menu keyboard helpers (shared by DropdownMenu, Menubar and ContextMenu)
70
+ * ------------------------------------------------------------------------------------------- */
71
+
72
+ /** Focusable items that belong directly to a `[role=menu]` (sub-menu triggers included, sub-menu items excluded). */
73
+ export function menuItems(menu: Element): HTMLElement[] {
74
+ const out: HTMLElement[] = [];
75
+ for (const child of Array.from(menu.children)) {
76
+ if (child.matches('[role^="menuitem"]')) out.push(child as HTMLElement);
77
+ else if (child.classList.contains("oc-dropdown-sub") && child.firstElementChild) out.push(child.firstElementChild as HTMLElement);
78
+ }
79
+ return out.filter((el) => el.getAttribute("aria-disabled") !== "true" && !(el as HTMLButtonElement).disabled);
80
+ }
81
+
82
+ /**
83
+ * Roving focus inside an `.oc-dropdown-menu[role=menu]`: ArrowDown / ArrowUp (wrapping), Home, End,
84
+ * ArrowRight on a sub-menu trigger enters the sub-menu, ArrowLeft inside a sub-menu returns to its trigger.
85
+ * Returns `true` (and calls preventDefault) when the key was handled.
86
+ */
87
+ export function handleMenuKeyDown(e: React.KeyboardEvent<HTMLElement>): boolean {
88
+ const item = (e.target as HTMLElement).closest<HTMLElement>('[role^="menuitem"]');
89
+ const menu = item?.closest<HTMLElement>('[role="menu"]');
90
+ if (!item || !menu) return false;
91
+ const items = menuItems(menu);
92
+ const at = items.indexOf(item);
93
+ let next: HTMLElement | undefined;
94
+ switch (e.key) {
95
+ case "ArrowDown":
96
+ next = items[(at + 1) % items.length];
97
+ break;
98
+ case "ArrowUp":
99
+ next = items[(at - 1 + items.length) % items.length];
100
+ break;
101
+ case "Home":
102
+ next = items[0];
103
+ break;
104
+ case "End":
105
+ next = items[items.length - 1];
106
+ break;
107
+ case "ArrowRight": {
108
+ const sub = item.parentElement?.classList.contains("oc-dropdown-sub") ? item.parentElement.querySelector<HTMLElement>(".oc-dropdown-submenu") : null;
109
+ next = sub ? menuItems(sub)[0] : undefined;
110
+ break;
111
+ }
112
+ case "ArrowLeft":
113
+ if (menu.classList.contains("oc-dropdown-submenu")) next = menu.parentElement?.firstElementChild as HTMLElement | undefined;
114
+ break;
115
+ default:
116
+ return false;
117
+ }
118
+ if (!next) return false;
119
+ e.preventDefault();
120
+ e.stopPropagation();
121
+ next.focus();
122
+ return true;
123
+ }
124
+
125
+ /** Closes the popover a menu item lives in. */
126
+ export function closeMenuOf(el: Element | null) {
127
+ (el?.closest("[popover]") as (HTMLElement & { hidePopover?: () => void }) | null)?.hidePopover?.();
128
+ }
129
+
130
+ /** Focuses the first menu item whenever the popover opens (the native `toggle` event). */
131
+ export function useMenuAutofocus(ref: RefObject<HTMLElement | null>) {
132
+ useEffect(() => {
133
+ const el = ref.current;
134
+ if (!el) return;
135
+ const onToggle = (e: Event) => {
136
+ if ((e as Event & { newState?: string }).newState === "open") menuItems(el)[0]?.focus();
137
+ };
138
+ el.addEventListener("toggle", onToggle);
139
+ return () => el.removeEventListener("toggle", onToggle);
140
+ }, [ref]);
141
+ }
package/src/utils.ts CHANGED
@@ -1,25 +1,25 @@
1
- import type { ReactNode } from "react";
2
-
3
- export type ClassValue = string | false | null | undefined;
4
-
5
- /** Join class names, skipping falsy values. */
6
- export function cx(...parts: ClassValue[]): string {
7
- return parts.filter(Boolean).join(" ");
8
- }
9
-
10
- /** `oc-btn` + `--secondary` -> `oc-btn oc-btn--secondary` (skips empty modifiers). */
11
- export function mod(base: string, ...modifiers: ClassValue[]): string {
12
- return cx(base, ...modifiers.map((m) => (m ? `${base}--${m}` : null)));
13
- }
14
-
15
- /** Attributes React's types do not know yet (popover, invoker commands, closedby). */
16
- export function attrs(record: Record<string, string | undefined>): object {
17
- return record;
18
- }
19
-
20
- export type Slot = ReactNode;
21
-
22
- /** Call a handler, then call another one. */
23
- export function callAll<E>(...fns: Array<((e: E) => void) | undefined>) {
24
- return (e: E) => fns.forEach((fn) => fn?.(e));
25
- }
1
+ import type { ReactNode } from "react";
2
+
3
+ export type ClassValue = string | false | null | undefined;
4
+
5
+ /** Join class names, skipping falsy values. */
6
+ export function cx(...parts: ClassValue[]): string {
7
+ return parts.filter(Boolean).join(" ");
8
+ }
9
+
10
+ /** `oc-btn` + `--secondary` -> `oc-btn oc-btn--secondary` (skips empty modifiers). */
11
+ export function mod(base: string, ...modifiers: ClassValue[]): string {
12
+ return cx(base, ...modifiers.map((m) => (m ? `${base}--${m}` : null)));
13
+ }
14
+
15
+ /** Attributes React's types do not know yet (popover, invoker commands, closedby). */
16
+ export function attrs(record: Record<string, string | undefined>): object {
17
+ return record;
18
+ }
19
+
20
+ export type Slot = ReactNode;
21
+
22
+ /** Call a handler, then call another one. */
23
+ export function callAll<E>(...fns: Array<((e: E) => void) | undefined>) {
24
+ return (e: E) => fns.forEach((fn) => fn?.(e));
25
+ }