@birdycom/omniaui-react 0.11.0 → 0.11.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
@@ -1,45 +1,45 @@
1
- // File: packages/react/src/components/Timeline.tsx | Map: types -> Timeline (ol.oc-timeline -> li.oc-timeline__item)
2
- import { forwardRef } from "react";
3
- import type { HTMLAttributes, ReactNode } from "react";
4
- import { cx } from "../utils";
5
-
6
- export interface TimelineEntry {
7
- /** Year or date label. */
8
- date: ReactNode;
9
- /** Machine-readable date; renders a <time> when set. */
10
- dateTime?: string;
11
- title?: ReactNode;
12
- text?: ReactNode;
13
- /** Marks the latest entry (filled dot). */
14
- current?: boolean;
15
- }
16
-
17
- export interface TimelineProps extends HTMLAttributes<HTMLOListElement> {
18
- items: TimelineEntry[];
19
- /** More space between entries. */
20
- size?: "default" | "lg";
21
- /** Line in the accent color. */
22
- accent?: boolean;
23
- }
24
-
25
- /** `<ol class="oc-timeline">` with dated entries. Use `className="oc-accent--green"` for another accent. */
26
- export const Timeline = forwardRef<HTMLOListElement, TimelineProps>(function Timeline(
27
- { items, size = "default", accent = false, className, ...rest },
28
- ref,
29
- ) {
30
- return (
31
- <ol ref={ref} className={cx("oc-timeline", size === "lg" && "oc-timeline--lg", accent && "oc-timeline--accent", className)} {...rest}>
32
- {items.map((item, i) => (
33
- <li key={i} className={cx("oc-timeline__item", item.current && "oc-timeline__item--current")}>
34
- {item.dateTime ? (
35
- <time className="oc-timeline__date" dateTime={item.dateTime}>{item.date}</time>
36
- ) : (
37
- <span className="oc-timeline__date">{item.date}</span>
38
- )}
39
- {item.title != null && <h3 className="oc-timeline__title">{item.title}</h3>}
40
- {item.text != null && <p className="oc-timeline__text">{item.text}</p>}
41
- </li>
42
- ))}
43
- </ol>
44
- );
45
- });
1
+ // File: packages/react/src/components/Timeline.tsx | Map: types -> Timeline (ol.oc-timeline -> li.oc-timeline__item)
2
+ import { forwardRef } from "react";
3
+ import type { HTMLAttributes, ReactNode } from "react";
4
+ import { cx } from "../utils";
5
+
6
+ export interface TimelineEntry {
7
+ /** Year or date label. */
8
+ date: ReactNode;
9
+ /** Machine-readable date; renders a <time> when set. */
10
+ dateTime?: string;
11
+ title?: ReactNode;
12
+ text?: ReactNode;
13
+ /** Marks the latest entry (filled dot). */
14
+ current?: boolean;
15
+ }
16
+
17
+ export interface TimelineProps extends HTMLAttributes<HTMLOListElement> {
18
+ items: TimelineEntry[];
19
+ /** More space between entries. */
20
+ size?: "default" | "lg";
21
+ /** Line in the accent color. */
22
+ accent?: boolean;
23
+ }
24
+
25
+ /** `<ol class="oc-timeline">` with dated entries. Use `className="oc-accent--green"` for another accent. */
26
+ export const Timeline = forwardRef<HTMLOListElement, TimelineProps>(function Timeline(
27
+ { items, size = "default", accent = false, className, ...rest },
28
+ ref,
29
+ ) {
30
+ return (
31
+ <ol ref={ref} className={cx("oc-timeline", size === "lg" && "oc-timeline--lg", accent && "oc-timeline--accent", className)} {...rest}>
32
+ {items.map((item, i) => (
33
+ <li key={i} className={cx("oc-timeline__item", item.current && "oc-timeline__item--current")}>
34
+ {item.dateTime ? (
35
+ <time className="oc-timeline__date" dateTime={item.dateTime}>{item.date}</time>
36
+ ) : (
37
+ <span className="oc-timeline__date">{item.date}</span>
38
+ )}
39
+ {item.title != null && <h3 className="oc-timeline__title">{item.title}</h3>}
40
+ {item.text != null && <p className="oc-timeline__text">{item.text}</p>}
41
+ </li>
42
+ ))}
43
+ </ol>
44
+ );
45
+ });
@@ -1,138 +1,138 @@
1
- "use client";
2
-
3
- import { createContext, forwardRef, useCallback, useContext, useEffect, useMemo, useRef, useState } from "react";
4
- import type { HTMLAttributes, ReactNode } from "react";
5
- import { cx } from "../utils";
6
-
7
- export type ToastVariant = "success" | "error" | "warning" | "info";
8
-
9
- const GLYPHS: Record<ToastVariant, string> = { success: "✓", error: "!", warning: "!", info: "i" };
10
-
11
- export interface ToastProps extends Omit<HTMLAttributes<HTMLDivElement>, "title"> {
12
- variant?: ToastVariant;
13
- title: ReactNode;
14
- description?: ReactNode;
15
- /** Custom status glyph (defaults per variant). */
16
- icon?: ReactNode;
17
- /** Shows the dismiss button. */
18
- onDismiss?: () => void;
19
- dismissLabel?: string;
20
- }
21
-
22
- /** One `.oc-toast` notification (`role="alert"` for errors, `status` otherwise). */
23
- export const Toast = forwardRef<HTMLDivElement, ToastProps>(function Toast(
24
- { variant = "info", title, description, icon, onDismiss, dismissLabel = "Dismiss", className, ...rest },
25
- ref,
26
- ) {
27
- return (
28
- <div ref={ref} className={cx("oc-toast", `oc-toast--${variant}`, className)} role={variant === "error" ? "alert" : "status"} {...rest}>
29
- <span className="oc-toast-icon" aria-hidden="true">{icon ?? GLYPHS[variant]}</span>
30
- <div className="oc-toast-body">
31
- <p className="oc-toast-title">{title}</p>
32
- {description != null && <p className="oc-toast-description">{description}</p>}
33
- </div>
34
- {onDismiss && (
35
- <button className="oc-toast-close" type="button" aria-label={dismissLabel} onClick={onDismiss}>&times;</button>
36
- )}
37
- </div>
38
- );
39
- });
40
-
41
- /** `.oc-toast-container` (fixed bottom right; `top` or `static` for in-flow). */
42
- export const ToastContainer = forwardRef<HTMLDivElement, HTMLAttributes<HTMLDivElement> & { top?: boolean; static?: boolean }>(function ToastContainer(
43
- { top, static: isStatic, className, ...rest },
44
- ref,
45
- ) {
46
- return (
47
- <div
48
- ref={ref}
49
- className={cx("oc-toast-container", top && "oc-toast-container--top", isStatic && "oc-toast-container--static", className)}
50
- {...rest}
51
- />
52
- );
53
- });
54
-
55
- export interface ToastOptions {
56
- variant?: ToastVariant;
57
- title: ReactNode;
58
- description?: ReactNode;
59
- /** Auto-dismiss after ms (default 5000). Use 0 to keep the toast until dismissed. */
60
- duration?: number;
61
- }
62
-
63
- interface ToastEntry extends ToastOptions {
64
- id: number;
65
- }
66
-
67
- interface ToastApi {
68
- /** Queue a toast; returns its id. */
69
- toast: (options: ToastOptions) => number;
70
- dismiss: (id?: number) => void;
71
- }
72
-
73
- const ToastContext = createContext<ToastApi | null>(null);
74
-
75
- export interface ToastProviderProps {
76
- children?: ReactNode;
77
- /** Stack at the top instead of the bottom. */
78
- top?: boolean;
79
- /** Default auto-dismiss in ms (default 5000). */
80
- duration?: number;
81
- /** Maximum toasts shown at once (oldest are dropped; default 5). */
82
- limit?: number;
83
- }
84
-
85
- /** Holds the toast queue and renders the fixed `.oc-toast-container`. Use `useToast()` below it. */
86
- export function ToastProvider({ children, top, duration = 5000, limit = 5 }: ToastProviderProps) {
87
- const [items, setItems] = useState<ToastEntry[]>([]);
88
- const nextId = useRef(1);
89
- const timers = useRef(new Map<number, ReturnType<typeof setTimeout>>());
90
-
91
- const dismiss = useCallback((id?: number) => {
92
- if (id === undefined) {
93
- timers.current.forEach(clearTimeout);
94
- timers.current.clear();
95
- setItems([]);
96
- return;
97
- }
98
- clearTimeout(timers.current.get(id));
99
- timers.current.delete(id);
100
- setItems((list) => list.filter((t) => t.id !== id));
101
- }, []);
102
-
103
- const toast = useCallback(
104
- (options: ToastOptions) => {
105
- const id = nextId.current++;
106
- setItems((list) => [...list, { ...options, id }].slice(-limit));
107
- const ms = options.duration ?? duration;
108
- if (ms > 0) timers.current.set(id, setTimeout(() => dismiss(id), ms));
109
- return id;
110
- },
111
- [dismiss, duration, limit],
112
- );
113
-
114
- useEffect(() => {
115
- const map = timers.current;
116
- return () => map.forEach(clearTimeout);
117
- }, []);
118
-
119
- const api = useMemo(() => ({ toast, dismiss }), [toast, dismiss]);
120
-
121
- return (
122
- <ToastContext.Provider value={api}>
123
- {children}
124
- <ToastContainer top={top} aria-live="polite">
125
- {items.map((t) => (
126
- <Toast key={t.id} variant={t.variant} title={t.title} description={t.description} onDismiss={() => dismiss(t.id)} />
127
- ))}
128
- </ToastContainer>
129
- </ToastContext.Provider>
130
- );
131
- }
132
-
133
- /** `const { toast, dismiss } = useToast()`: needs a surrounding `<ToastProvider>`. */
134
- export function useToast(): ToastApi {
135
- const ctx = useContext(ToastContext);
136
- if (!ctx) throw new Error("useToast must be used inside <ToastProvider>");
137
- return ctx;
138
- }
1
+ "use client";
2
+
3
+ import { createContext, forwardRef, useCallback, useContext, useEffect, useMemo, useRef, useState } from "react";
4
+ import type { HTMLAttributes, ReactNode } from "react";
5
+ import { cx } from "../utils";
6
+
7
+ export type ToastVariant = "success" | "error" | "warning" | "info";
8
+
9
+ const GLYPHS: Record<ToastVariant, string> = { success: "✓", error: "!", warning: "!", info: "i" };
10
+
11
+ export interface ToastProps extends Omit<HTMLAttributes<HTMLDivElement>, "title"> {
12
+ variant?: ToastVariant;
13
+ title: ReactNode;
14
+ description?: ReactNode;
15
+ /** Custom status glyph (defaults per variant). */
16
+ icon?: ReactNode;
17
+ /** Shows the dismiss button. */
18
+ onDismiss?: () => void;
19
+ dismissLabel?: string;
20
+ }
21
+
22
+ /** One `.oc-toast` notification (`role="alert"` for errors, `status` otherwise). */
23
+ export const Toast = forwardRef<HTMLDivElement, ToastProps>(function Toast(
24
+ { variant = "info", title, description, icon, onDismiss, dismissLabel = "Dismiss", className, ...rest },
25
+ ref,
26
+ ) {
27
+ return (
28
+ <div ref={ref} className={cx("oc-toast", `oc-toast--${variant}`, className)} role={variant === "error" ? "alert" : "status"} {...rest}>
29
+ <span className="oc-toast-icon" aria-hidden="true">{icon ?? GLYPHS[variant]}</span>
30
+ <div className="oc-toast-body">
31
+ <p className="oc-toast-title">{title}</p>
32
+ {description != null && <p className="oc-toast-description">{description}</p>}
33
+ </div>
34
+ {onDismiss && (
35
+ <button className="oc-toast-close" type="button" aria-label={dismissLabel} onClick={onDismiss}>&times;</button>
36
+ )}
37
+ </div>
38
+ );
39
+ });
40
+
41
+ /** `.oc-toast-container` (fixed bottom right; `top` or `static` for in-flow). */
42
+ export const ToastContainer = forwardRef<HTMLDivElement, HTMLAttributes<HTMLDivElement> & { top?: boolean; static?: boolean }>(function ToastContainer(
43
+ { top, static: isStatic, className, ...rest },
44
+ ref,
45
+ ) {
46
+ return (
47
+ <div
48
+ ref={ref}
49
+ className={cx("oc-toast-container", top && "oc-toast-container--top", isStatic && "oc-toast-container--static", className)}
50
+ {...rest}
51
+ />
52
+ );
53
+ });
54
+
55
+ export interface ToastOptions {
56
+ variant?: ToastVariant;
57
+ title: ReactNode;
58
+ description?: ReactNode;
59
+ /** Auto-dismiss after ms (default 5000). Use 0 to keep the toast until dismissed. */
60
+ duration?: number;
61
+ }
62
+
63
+ interface ToastEntry extends ToastOptions {
64
+ id: number;
65
+ }
66
+
67
+ interface ToastApi {
68
+ /** Queue a toast; returns its id. */
69
+ toast: (options: ToastOptions) => number;
70
+ dismiss: (id?: number) => void;
71
+ }
72
+
73
+ const ToastContext = createContext<ToastApi | null>(null);
74
+
75
+ export interface ToastProviderProps {
76
+ children?: ReactNode;
77
+ /** Stack at the top instead of the bottom. */
78
+ top?: boolean;
79
+ /** Default auto-dismiss in ms (default 5000). */
80
+ duration?: number;
81
+ /** Maximum toasts shown at once (oldest are dropped; default 5). */
82
+ limit?: number;
83
+ }
84
+
85
+ /** Holds the toast queue and renders the fixed `.oc-toast-container`. Use `useToast()` below it. */
86
+ export function ToastProvider({ children, top, duration = 5000, limit = 5 }: ToastProviderProps) {
87
+ const [items, setItems] = useState<ToastEntry[]>([]);
88
+ const nextId = useRef(1);
89
+ const timers = useRef(new Map<number, ReturnType<typeof setTimeout>>());
90
+
91
+ const dismiss = useCallback((id?: number) => {
92
+ if (id === undefined) {
93
+ timers.current.forEach(clearTimeout);
94
+ timers.current.clear();
95
+ setItems([]);
96
+ return;
97
+ }
98
+ clearTimeout(timers.current.get(id));
99
+ timers.current.delete(id);
100
+ setItems((list) => list.filter((t) => t.id !== id));
101
+ }, []);
102
+
103
+ const toast = useCallback(
104
+ (options: ToastOptions) => {
105
+ const id = nextId.current++;
106
+ setItems((list) => [...list, { ...options, id }].slice(-limit));
107
+ const ms = options.duration ?? duration;
108
+ if (ms > 0) timers.current.set(id, setTimeout(() => dismiss(id), ms));
109
+ return id;
110
+ },
111
+ [dismiss, duration, limit],
112
+ );
113
+
114
+ useEffect(() => {
115
+ const map = timers.current;
116
+ return () => map.forEach(clearTimeout);
117
+ }, []);
118
+
119
+ const api = useMemo(() => ({ toast, dismiss }), [toast, dismiss]);
120
+
121
+ return (
122
+ <ToastContext.Provider value={api}>
123
+ {children}
124
+ <ToastContainer top={top} aria-live="polite">
125
+ {items.map((t) => (
126
+ <Toast key={t.id} variant={t.variant} title={t.title} description={t.description} onDismiss={() => dismiss(t.id)} />
127
+ ))}
128
+ </ToastContainer>
129
+ </ToastContext.Provider>
130
+ );
131
+ }
132
+
133
+ /** `const { toast, dismiss } = useToast()`: needs a surrounding `<ToastProvider>`. */
134
+ export function useToast(): ToastApi {
135
+ const ctx = useContext(ToastContext);
136
+ if (!ctx) throw new Error("useToast must be used inside <ToastProvider>");
137
+ return ctx;
138
+ }
@@ -1,39 +1,39 @@
1
- // File: packages/react/src/components/ToggleField.tsx
2
- // Map: props -> component (label row: text block + span.oc-switch with checkbox)
3
- // Same markup as packages/ui/snippets/toggle-field.html. Works controlled (checked) or uncontrolled.
4
- "use client";
5
-
6
- import { forwardRef, useId } from "react";
7
- import type { InputHTMLAttributes, ReactNode } from "react";
8
- import { cx } from "../utils";
9
-
10
- export interface ToggleFieldProps extends Omit<InputHTMLAttributes<HTMLInputElement>, "type" | "role"> {
11
- label: ReactNode;
12
- description?: ReactNode;
13
- /** Bordered box. */
14
- card?: boolean;
15
- /** Switch first, text after it. */
16
- reverse?: boolean;
17
- /** Class for the row (`className` goes to the input). */
18
- fieldClassName?: string;
19
- }
20
-
21
- /** `.oc-toggle-field`: the whole row is the label, so clicking the text flips the switch. */
22
- export const ToggleField = forwardRef<HTMLInputElement, ToggleFieldProps>(function ToggleField(
23
- { label, description, card, reverse, fieldClassName, className, ...rest },
24
- ref,
25
- ) {
26
- const descId = `oc-toggle-field-${useId().replace(/:/g, "")}`;
27
- return (
28
- <label className={cx("oc-toggle-field", card && "oc-toggle-field--card", reverse && "oc-toggle-field--reverse", fieldClassName)}>
29
- <span className="oc-toggle-field-text">
30
- <span className="oc-toggle-field-label">{label}</span>
31
- {description != null && <span className="oc-toggle-field-description" id={descId}>{description}</span>}
32
- </span>
33
- <span className="oc-switch">
34
- <input ref={ref} type="checkbox" role="switch" className={className} aria-describedby={description != null ? descId : undefined} {...rest} />
35
- <span className="oc-switch-track" />
36
- </span>
37
- </label>
38
- );
39
- });
1
+ // File: packages/react/src/components/ToggleField.tsx
2
+ // Map: props -> component (label row: text block + span.oc-switch with checkbox)
3
+ // Same markup as packages/ui/snippets/toggle-field.html. Works controlled (checked) or uncontrolled.
4
+ "use client";
5
+
6
+ import { forwardRef, useId } from "react";
7
+ import type { InputHTMLAttributes, ReactNode } from "react";
8
+ import { cx } from "../utils";
9
+
10
+ export interface ToggleFieldProps extends Omit<InputHTMLAttributes<HTMLInputElement>, "type" | "role"> {
11
+ label: ReactNode;
12
+ description?: ReactNode;
13
+ /** Bordered box. */
14
+ card?: boolean;
15
+ /** Switch first, text after it. */
16
+ reverse?: boolean;
17
+ /** Class for the row (`className` goes to the input). */
18
+ fieldClassName?: string;
19
+ }
20
+
21
+ /** `.oc-toggle-field`: the whole row is the label, so clicking the text flips the switch. */
22
+ export const ToggleField = forwardRef<HTMLInputElement, ToggleFieldProps>(function ToggleField(
23
+ { label, description, card, reverse, fieldClassName, className, ...rest },
24
+ ref,
25
+ ) {
26
+ const descId = `oc-toggle-field-${useId().replace(/:/g, "")}`;
27
+ return (
28
+ <label className={cx("oc-toggle-field", card && "oc-toggle-field--card", reverse && "oc-toggle-field--reverse", fieldClassName)}>
29
+ <span className="oc-toggle-field-text">
30
+ <span className="oc-toggle-field-label">{label}</span>
31
+ {description != null && <span className="oc-toggle-field-description" id={descId}>{description}</span>}
32
+ </span>
33
+ <span className="oc-switch">
34
+ <input ref={ref} type="checkbox" role="switch" className={className} aria-describedby={description != null ? descId : undefined} {...rest} />
35
+ <span className="oc-switch-track" />
36
+ </span>
37
+ </label>
38
+ );
39
+ });
@@ -1,14 +1,14 @@
1
- import { forwardRef } from "react";
2
- import type { HTMLAttributes, ReactNode } from "react";
3
- import { cx } from "../utils";
4
-
5
- export interface TooltipProps extends Omit<HTMLAttributes<HTMLSpanElement>, "content"> {
6
- /** Tooltip text (`data-tooltip`). */
7
- content: string;
8
- children: ReactNode;
9
- }
10
-
11
- /** `<span class="oc-tooltip" data-tooltip>`: CSS-only tooltip around its children. */
12
- export const Tooltip = forwardRef<HTMLSpanElement, TooltipProps>(function Tooltip({ content, className, ...rest }, ref) {
13
- return <span ref={ref} className={cx("oc-tooltip", className)} data-tooltip={content} {...rest} />;
14
- });
1
+ import { forwardRef } from "react";
2
+ import type { HTMLAttributes, ReactNode } from "react";
3
+ import { cx } from "../utils";
4
+
5
+ export interface TooltipProps extends Omit<HTMLAttributes<HTMLSpanElement>, "content"> {
6
+ /** Tooltip text (`data-tooltip`). */
7
+ content: string;
8
+ children: ReactNode;
9
+ }
10
+
11
+ /** `<span class="oc-tooltip" data-tooltip>`: CSS-only tooltip around its children. */
12
+ export const Tooltip = forwardRef<HTMLSpanElement, TooltipProps>(function Tooltip({ content, className, ...rest }, ref) {
13
+ return <span ref={ref} className={cx("oc-tooltip", className)} data-tooltip={content} {...rest} />;
14
+ });
@@ -1,54 +1,54 @@
1
- // File: packages/react/src/components/TopProgress.tsx
2
- // Map: TopProgress = progress.oc-top-progress -> phase state (hidden / active / done) -> fade-out timer
3
- // `active` true shows the bar. When it turns false the bar gets `.is-done` (fades out),
4
- // and after the fade it is hidden again. Without `value` the bar is indeterminate.
5
- "use client";
6
-
7
- import { forwardRef, useEffect, useState } from "react";
8
- import type { ProgressHTMLAttributes } from "react";
9
- import { cx } from "../utils";
10
-
11
- export type TopProgressTone = "default" | "success" | "warning" | "danger" | "brand";
12
-
13
- export interface TopProgressProps extends ProgressHTMLAttributes<HTMLProgressElement> {
14
- /** Show the bar (a request or page load is running). Default true. */
15
- active?: boolean;
16
- tone?: TopProgressTone;
17
- /** 4px instead of 2px. */
18
- large?: boolean;
19
- /** In the normal flow (e.g. inside a card) instead of fixed at the top. */
20
- static?: boolean;
21
- /** Fade-out time in ms before the bar is hidden. */
22
- fadeMs?: number;
23
- }
24
-
25
- type Phase = "hidden" | "active" | "done";
26
-
27
- /** `progress.oc-top-progress`: thin loading bar at the top of the page. */
28
- export const TopProgress = forwardRef<HTMLProgressElement, TopProgressProps>(function TopProgress(
29
- { active = true, tone = "default", large, static: inFlow, fadeMs = 400, className, ...rest },
30
- ref,
31
- ) {
32
- const [phase, setPhase] = useState<Phase>(active ? "active" : "hidden");
33
-
34
- useEffect(() => {
35
- if (active) {
36
- setPhase("active");
37
- return;
38
- }
39
- // Only fade out when the bar was visible; keep it hidden otherwise.
40
- setPhase((p) => (p === "hidden" ? "hidden" : "done"));
41
- const timer = setTimeout(() => setPhase("hidden"), fadeMs);
42
- return () => clearTimeout(timer);
43
- }, [active, fadeMs]);
44
-
45
- const cls = cx(
46
- "oc-top-progress",
47
- tone !== "default" && `oc-top-progress--${tone}`,
48
- large && "oc-top-progress--lg",
49
- inFlow && "oc-top-progress--static",
50
- phase === "done" && "is-done",
51
- className,
52
- );
53
- return <progress ref={ref} className={cls} hidden={phase === "hidden"} {...rest} />;
54
- });
1
+ // File: packages/react/src/components/TopProgress.tsx
2
+ // Map: TopProgress = progress.oc-top-progress -> phase state (hidden / active / done) -> fade-out timer
3
+ // `active` true shows the bar. When it turns false the bar gets `.is-done` (fades out),
4
+ // and after the fade it is hidden again. Without `value` the bar is indeterminate.
5
+ "use client";
6
+
7
+ import { forwardRef, useEffect, useState } from "react";
8
+ import type { ProgressHTMLAttributes } from "react";
9
+ import { cx } from "../utils";
10
+
11
+ export type TopProgressTone = "default" | "success" | "warning" | "danger" | "brand";
12
+
13
+ export interface TopProgressProps extends ProgressHTMLAttributes<HTMLProgressElement> {
14
+ /** Show the bar (a request or page load is running). Default true. */
15
+ active?: boolean;
16
+ tone?: TopProgressTone;
17
+ /** 4px instead of 2px. */
18
+ large?: boolean;
19
+ /** In the normal flow (e.g. inside a card) instead of fixed at the top. */
20
+ static?: boolean;
21
+ /** Fade-out time in ms before the bar is hidden. */
22
+ fadeMs?: number;
23
+ }
24
+
25
+ type Phase = "hidden" | "active" | "done";
26
+
27
+ /** `progress.oc-top-progress`: thin loading bar at the top of the page. */
28
+ export const TopProgress = forwardRef<HTMLProgressElement, TopProgressProps>(function TopProgress(
29
+ { active = true, tone = "default", large, static: inFlow, fadeMs = 400, className, ...rest },
30
+ ref,
31
+ ) {
32
+ const [phase, setPhase] = useState<Phase>(active ? "active" : "hidden");
33
+
34
+ useEffect(() => {
35
+ if (active) {
36
+ setPhase("active");
37
+ return;
38
+ }
39
+ // Only fade out when the bar was visible; keep it hidden otherwise.
40
+ setPhase((p) => (p === "hidden" ? "hidden" : "done"));
41
+ const timer = setTimeout(() => setPhase("hidden"), fadeMs);
42
+ return () => clearTimeout(timer);
43
+ }, [active, fadeMs]);
44
+
45
+ const cls = cx(
46
+ "oc-top-progress",
47
+ tone !== "default" && `oc-top-progress--${tone}`,
48
+ large && "oc-top-progress--lg",
49
+ inFlow && "oc-top-progress--static",
50
+ phase === "done" && "is-done",
51
+ className,
52
+ );
53
+ return <progress ref={ref} className={cls} hidden={phase === "hidden"} {...rest} />;
54
+ });