@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,97 +1,97 @@
1
- // File: packages/react/src/components/Tree.tsx
2
- // Map: Tree = box -> optional head row -> list -> TreeNode (folder = details/summary, leaf = div row) -> nested list
3
- // Folders open and close natively (<details>), so there is no state here.
4
- import { forwardRef } from "react";
5
- import type { HTMLAttributes, ReactNode } from "react";
6
- import { cx } from "../utils";
7
-
8
- export interface TreeItem {
9
- label: ReactNode;
10
- /** Leaf link target (renders the label as `a.oc-tree-label`). */
11
- href?: string;
12
- icon?: ReactNode;
13
- count?: ReactNode;
14
- actions?: ReactNode;
15
- /** Child items: makes this item a folder. */
16
- children?: TreeItem[];
17
- /** Folder starts open. */
18
- open?: boolean;
19
- /** Current / selected item. */
20
- current?: boolean;
21
- muted?: boolean;
22
- }
23
-
24
- export interface TreeProps extends HTMLAttributes<HTMLDivElement> {
25
- items: TreeItem[];
26
- /** Sticky root row content (label), with optional `headActions`. */
27
- head?: ReactNode;
28
- headActions?: ReactNode;
29
- /** Actions only show on hover / focus. */
30
- quiet?: boolean;
31
- /** No card frame. */
32
- flush?: boolean;
33
- }
34
-
35
- /** The row content: icon, label (link or text), count, actions. */
36
- function RowContent({ item }: { item: TreeItem }) {
37
- const isLink = item.href !== undefined;
38
- return (
39
- <>
40
- {item.icon != null && <span className="oc-tree-icon" aria-hidden="true">{item.icon}</span>}
41
- {isLink ? (
42
- <a className="oc-tree-label" href={item.href} aria-current={item.current ? "true" : undefined}>{item.label}</a>
43
- ) : (
44
- <span className="oc-tree-label">{item.label}</span>
45
- )}
46
- {item.count != null && <span className="oc-tree-count">{item.count}</span>}
47
- {item.actions != null && <span className="oc-tree-actions">{item.actions}</span>}
48
- </>
49
- );
50
- }
51
-
52
- function TreeNode({ item }: { item: TreeItem }) {
53
- // aria-current on the row only when the label is not a link (a link carries it itself).
54
- const rowCurrent = item.current && item.href === undefined ? "true" : undefined;
55
- const rowCls = cx("oc-tree-row", item.muted && "is-muted");
56
- if (!item.children?.length) {
57
- return (
58
- <li>
59
- <div className={rowCls} aria-current={rowCurrent}><RowContent item={item} /></div>
60
- </li>
61
- );
62
- }
63
- return (
64
- <li>
65
- <details className="oc-tree-node" open={item.open}>
66
- <summary className={rowCls} aria-current={rowCurrent}><RowContent item={item} /></summary>
67
- <TreeList items={item.children} />
68
- </details>
69
- </li>
70
- );
71
- }
72
-
73
- function TreeList({ items }: { items: TreeItem[] }) {
74
- return (
75
- <ul className="oc-tree-list">
76
- {items.map((item, i) => <TreeNode item={item} key={i} />)}
77
- </ul>
78
- );
79
- }
80
-
81
- /** `.oc-tree`: nested tree list with a sticky action column. */
82
- export const Tree = forwardRef<HTMLDivElement, TreeProps>(function Tree(
83
- { items, head, headActions, quiet, flush, className, ...rest },
84
- ref,
85
- ) {
86
- return (
87
- <div ref={ref} className={cx("oc-tree", quiet && "oc-tree--quiet", flush && "oc-tree--flush", className)} {...rest}>
88
- {head != null && (
89
- <div className="oc-tree-row oc-tree-head">
90
- <span className="oc-tree-label">{head}</span>
91
- {headActions != null && <span className="oc-tree-actions">{headActions}</span>}
92
- </div>
93
- )}
94
- <TreeList items={items} />
95
- </div>
96
- );
97
- });
1
+ // File: packages/react/src/components/Tree.tsx
2
+ // Map: Tree = box -> optional head row -> list -> TreeNode (folder = details/summary, leaf = div row) -> nested list
3
+ // Folders open and close natively (<details>), so there is no state here.
4
+ import { forwardRef } from "react";
5
+ import type { HTMLAttributes, ReactNode } from "react";
6
+ import { cx } from "../utils";
7
+
8
+ export interface TreeItem {
9
+ label: ReactNode;
10
+ /** Leaf link target (renders the label as `a.oc-tree-label`). */
11
+ href?: string;
12
+ icon?: ReactNode;
13
+ count?: ReactNode;
14
+ actions?: ReactNode;
15
+ /** Child items: makes this item a folder. */
16
+ children?: TreeItem[];
17
+ /** Folder starts open. */
18
+ open?: boolean;
19
+ /** Current / selected item. */
20
+ current?: boolean;
21
+ muted?: boolean;
22
+ }
23
+
24
+ export interface TreeProps extends HTMLAttributes<HTMLDivElement> {
25
+ items: TreeItem[];
26
+ /** Sticky root row content (label), with optional `headActions`. */
27
+ head?: ReactNode;
28
+ headActions?: ReactNode;
29
+ /** Actions only show on hover / focus. */
30
+ quiet?: boolean;
31
+ /** No card frame. */
32
+ flush?: boolean;
33
+ }
34
+
35
+ /** The row content: icon, label (link or text), count, actions. */
36
+ function RowContent({ item }: { item: TreeItem }) {
37
+ const isLink = item.href !== undefined;
38
+ return (
39
+ <>
40
+ {item.icon != null && <span className="oc-tree-icon" aria-hidden="true">{item.icon}</span>}
41
+ {isLink ? (
42
+ <a className="oc-tree-label" href={item.href} aria-current={item.current ? "true" : undefined}>{item.label}</a>
43
+ ) : (
44
+ <span className="oc-tree-label">{item.label}</span>
45
+ )}
46
+ {item.count != null && <span className="oc-tree-count">{item.count}</span>}
47
+ {item.actions != null && <span className="oc-tree-actions">{item.actions}</span>}
48
+ </>
49
+ );
50
+ }
51
+
52
+ function TreeNode({ item }: { item: TreeItem }) {
53
+ // aria-current on the row only when the label is not a link (a link carries it itself).
54
+ const rowCurrent = item.current && item.href === undefined ? "true" : undefined;
55
+ const rowCls = cx("oc-tree-row", item.muted && "is-muted");
56
+ if (!item.children?.length) {
57
+ return (
58
+ <li>
59
+ <div className={rowCls} aria-current={rowCurrent}><RowContent item={item} /></div>
60
+ </li>
61
+ );
62
+ }
63
+ return (
64
+ <li>
65
+ <details className="oc-tree-node" open={item.open}>
66
+ <summary className={rowCls} aria-current={rowCurrent}><RowContent item={item} /></summary>
67
+ <TreeList items={item.children} />
68
+ </details>
69
+ </li>
70
+ );
71
+ }
72
+
73
+ function TreeList({ items }: { items: TreeItem[] }) {
74
+ return (
75
+ <ul className="oc-tree-list">
76
+ {items.map((item, i) => <TreeNode item={item} key={i} />)}
77
+ </ul>
78
+ );
79
+ }
80
+
81
+ /** `.oc-tree`: nested tree list with a sticky action column. */
82
+ export const Tree = forwardRef<HTMLDivElement, TreeProps>(function Tree(
83
+ { items, head, headActions, quiet, flush, className, ...rest },
84
+ ref,
85
+ ) {
86
+ return (
87
+ <div ref={ref} className={cx("oc-tree", quiet && "oc-tree--quiet", flush && "oc-tree--flush", className)} {...rest}>
88
+ {head != null && (
89
+ <div className="oc-tree-row oc-tree-head">
90
+ <span className="oc-tree-label">{head}</span>
91
+ {headActions != null && <span className="oc-tree-actions">{headActions}</span>}
92
+ </div>
93
+ )}
94
+ <TreeList items={items} />
95
+ </div>
96
+ );
97
+ });
@@ -1,62 +1,62 @@
1
- // File: packages/react/src/components/UpgradeBanner.tsx
2
- // Map: UpgradeBanner = aside -> icon -> body (title + plan pill, text, usage meter) -> actions -> dismiss button
3
- // The dismiss button only shows when `onDismiss` is given; your app then hides or removes the banner.
4
- import { forwardRef } from "react";
5
- import type { HTMLAttributes, ReactNode } from "react";
6
- import { cx } from "../utils";
7
-
8
- export interface UpgradeBannerUsage {
9
- label: ReactNode;
10
- value: number;
11
- max: number;
12
- }
13
-
14
- export interface UpgradeBannerProps extends Omit<HTMLAttributes<HTMLElement>, "title"> {
15
- title: ReactNode;
16
- /** Plan pill next to the title, e.g. "Free". */
17
- plan?: ReactNode;
18
- /** Explanation; also accepted as children. */
19
- text?: ReactNode;
20
- usage?: UpgradeBannerUsage;
21
- icon?: ReactNode;
22
- actions?: ReactNode;
23
- premium?: boolean;
24
- compact?: boolean;
25
- onDismiss?: () => void;
26
- dismissLabel?: string;
27
- }
28
-
29
- /** `.oc-upgrade-banner`: free-plan limits callout with an upgrade action. */
30
- export const UpgradeBanner = forwardRef<HTMLElement, UpgradeBannerProps>(function UpgradeBanner(
31
- { title, plan, text, usage, icon, actions, premium, compact, onDismiss, dismissLabel = "Dismiss", className, children, ...rest },
32
- ref,
33
- ) {
34
- const cls = cx("oc-upgrade-banner", premium && "oc-upgrade-banner--premium", compact && "oc-upgrade-banner--compact", className);
35
- const body = text ?? children;
36
- return (
37
- <aside ref={ref} className={cls} {...rest}>
38
- {icon != null && <span className="oc-upgrade-banner-icon" aria-hidden="true">{icon}</span>}
39
- <div className="oc-upgrade-banner-body">
40
- <p className="oc-upgrade-banner-title">
41
- {title}
42
- {plan != null && <> <span className="oc-upgrade-banner-plan">{plan}</span></>}
43
- </p>
44
- {body != null && <p className="oc-upgrade-banner-text">{body}</p>}
45
- {usage && (
46
- <div className="oc-upgrade-banner-usage">
47
- <span>{usage.label}</span>
48
- {/* low / high make the meter turn "less good" near the limit. */}
49
- <meter className="oc-upgrade-banner-meter" min={0} max={usage.max} low={usage.max * 0.6} high={usage.max * 0.8} optimum={0} value={usage.value}>
50
- {usage.value} of {usage.max}
51
- </meter>
52
- <span>{usage.value} / {usage.max}</span>
53
- </div>
54
- )}
55
- </div>
56
- {actions != null && <div className="oc-upgrade-banner-actions">{actions}</div>}
57
- {onDismiss && (
58
- <button className="oc-upgrade-banner-dismiss" type="button" aria-label={dismissLabel} onClick={onDismiss}>×</button>
59
- )}
60
- </aside>
61
- );
62
- });
1
+ // File: packages/react/src/components/UpgradeBanner.tsx
2
+ // Map: UpgradeBanner = aside -> icon -> body (title + plan pill, text, usage meter) -> actions -> dismiss button
3
+ // The dismiss button only shows when `onDismiss` is given; your app then hides or removes the banner.
4
+ import { forwardRef } from "react";
5
+ import type { HTMLAttributes, ReactNode } from "react";
6
+ import { cx } from "../utils";
7
+
8
+ export interface UpgradeBannerUsage {
9
+ label: ReactNode;
10
+ value: number;
11
+ max: number;
12
+ }
13
+
14
+ export interface UpgradeBannerProps extends Omit<HTMLAttributes<HTMLElement>, "title"> {
15
+ title: ReactNode;
16
+ /** Plan pill next to the title, e.g. "Free". */
17
+ plan?: ReactNode;
18
+ /** Explanation; also accepted as children. */
19
+ text?: ReactNode;
20
+ usage?: UpgradeBannerUsage;
21
+ icon?: ReactNode;
22
+ actions?: ReactNode;
23
+ premium?: boolean;
24
+ compact?: boolean;
25
+ onDismiss?: () => void;
26
+ dismissLabel?: string;
27
+ }
28
+
29
+ /** `.oc-upgrade-banner`: free-plan limits callout with an upgrade action. */
30
+ export const UpgradeBanner = forwardRef<HTMLElement, UpgradeBannerProps>(function UpgradeBanner(
31
+ { title, plan, text, usage, icon, actions, premium, compact, onDismiss, dismissLabel = "Dismiss", className, children, ...rest },
32
+ ref,
33
+ ) {
34
+ const cls = cx("oc-upgrade-banner", premium && "oc-upgrade-banner--premium", compact && "oc-upgrade-banner--compact", className);
35
+ const body = text ?? children;
36
+ return (
37
+ <aside ref={ref} className={cls} {...rest}>
38
+ {icon != null && <span className="oc-upgrade-banner-icon" aria-hidden="true">{icon}</span>}
39
+ <div className="oc-upgrade-banner-body">
40
+ <p className="oc-upgrade-banner-title">
41
+ {title}
42
+ {plan != null && <> <span className="oc-upgrade-banner-plan">{plan}</span></>}
43
+ </p>
44
+ {body != null && <p className="oc-upgrade-banner-text">{body}</p>}
45
+ {usage && (
46
+ <div className="oc-upgrade-banner-usage">
47
+ <span>{usage.label}</span>
48
+ {/* low / high make the meter turn "less good" near the limit. */}
49
+ <meter className="oc-upgrade-banner-meter" min={0} max={usage.max} low={usage.max * 0.6} high={usage.max * 0.8} optimum={0} value={usage.value}>
50
+ {usage.value} of {usage.max}
51
+ </meter>
52
+ <span>{usage.value} / {usage.max}</span>
53
+ </div>
54
+ )}
55
+ </div>
56
+ {actions != null && <div className="oc-upgrade-banner-actions">{actions}</div>}
57
+ {onDismiss && (
58
+ <button className="oc-upgrade-banner-dismiss" type="button" aria-label={dismissLabel} onClick={onDismiss}>×</button>
59
+ )}
60
+ </aside>
61
+ );
62
+ });
@@ -1,31 +1,31 @@
1
- import { forwardRef } from "react";
2
- import type { HTMLAttributes, ReactNode } from "react";
3
- import { cx } from "../utils";
4
- import { Avatar } from "./Avatar";
5
- import type { AvatarSize } from "./Avatar";
6
-
7
- export interface UserProps extends HTMLAttributes<HTMLDivElement> {
8
- name: ReactNode;
9
- email?: ReactNode;
10
- /** Initials shown in the avatar. */
11
- initials?: string;
12
- /** Avatar image URL (wins over initials). */
13
- avatarSrc?: string;
14
- avatarSize?: AvatarSize;
15
- }
16
-
17
- /** `.oc-user`: avatar with name and e-mail. */
18
- export const User = forwardRef<HTMLDivElement, UserProps>(function User(
19
- { name, email, initials, avatarSrc, avatarSize = "md", className, ...rest },
20
- ref,
21
- ) {
22
- return (
23
- <div ref={ref} className={cx("oc-user", className)} {...rest}>
24
- <Avatar size={avatarSize} src={avatarSrc}>{initials}</Avatar>
25
- <span className="oc-user-text">
26
- <span className="oc-user-name">{name}</span>
27
- {email != null && <span className="oc-user-email">{email}</span>}
28
- </span>
29
- </div>
30
- );
31
- });
1
+ import { forwardRef } from "react";
2
+ import type { HTMLAttributes, ReactNode } from "react";
3
+ import { cx } from "../utils";
4
+ import { Avatar } from "./Avatar";
5
+ import type { AvatarSize } from "./Avatar";
6
+
7
+ export interface UserProps extends HTMLAttributes<HTMLDivElement> {
8
+ name: ReactNode;
9
+ email?: ReactNode;
10
+ /** Initials shown in the avatar. */
11
+ initials?: string;
12
+ /** Avatar image URL (wins over initials). */
13
+ avatarSrc?: string;
14
+ avatarSize?: AvatarSize;
15
+ }
16
+
17
+ /** `.oc-user`: avatar with name and e-mail. */
18
+ export const User = forwardRef<HTMLDivElement, UserProps>(function User(
19
+ { name, email, initials, avatarSrc, avatarSize = "md", className, ...rest },
20
+ ref,
21
+ ) {
22
+ return (
23
+ <div ref={ref} className={cx("oc-user", className)} {...rest}>
24
+ <Avatar size={avatarSize} src={avatarSrc}>{initials}</Avatar>
25
+ <span className="oc-user-text">
26
+ <span className="oc-user-name">{name}</span>
27
+ {email != null && <span className="oc-user-email">{email}</span>}
28
+ </span>
29
+ </div>
30
+ );
31
+ });
@@ -1,41 +1,41 @@
1
- // File: packages/react/src/components/VersionBanner.tsx
2
- // Map: VersionBanner = chip (role=status) -> dot -> long text -> short text -> reload action
3
- // Renders nothing while `version` is empty. Your app sets `version` when it sees a newer build.
4
- import { forwardRef } from "react";
5
- import type { HTMLAttributes, ReactNode } from "react";
6
- import { cx } from "../utils";
7
-
8
- export interface VersionBannerProps extends HTMLAttributes<HTMLDivElement> {
9
- /** The new version, e.g. "v0.6.0". Empty = no banner. */
10
- version?: string | null;
11
- /** Long text; default "New version (vX) available - reload the page". */
12
- text?: ReactNode;
13
- /** Short text below 40rem; default "New version". */
14
- short?: ReactNode;
15
- actionLabel?: ReactNode;
16
- /** Custom reload; without it the action is a plain link to the current page. */
17
- onReload?: () => void;
18
- tone?: "warning" | "info" | "success";
19
- floating?: boolean;
20
- }
21
-
22
- /** `.oc-version-banner`: "new version available - reload" chip. */
23
- export const VersionBanner = forwardRef<HTMLDivElement, VersionBannerProps>(function VersionBanner(
24
- { version, text, short = "New version", actionLabel = "Reload", onReload, tone = "warning", floating, className, ...rest },
25
- ref,
26
- ) {
27
- if (!version) return null;
28
- const cls = cx("oc-version-banner", tone !== "warning" && `oc-version-banner--${tone}`, floating && "oc-version-banner--floating", className);
29
- return (
30
- <div ref={ref} className={cls} role="status" {...rest}>
31
- <span className="oc-version-banner-dot" aria-hidden="true" />
32
- <span className="oc-version-banner-text">{text ?? `New version (${version}) available - reload the page`}</span>
33
- <span className="oc-version-banner-short">{short}</span>
34
- {onReload ? (
35
- <button className="oc-version-banner-action" type="button" onClick={onReload}>{actionLabel}</button>
36
- ) : (
37
- <a className="oc-version-banner-action" href="">{actionLabel}</a>
38
- )}
39
- </div>
40
- );
41
- });
1
+ // File: packages/react/src/components/VersionBanner.tsx
2
+ // Map: VersionBanner = chip (role=status) -> dot -> long text -> short text -> reload action
3
+ // Renders nothing while `version` is empty. Your app sets `version` when it sees a newer build.
4
+ import { forwardRef } from "react";
5
+ import type { HTMLAttributes, ReactNode } from "react";
6
+ import { cx } from "../utils";
7
+
8
+ export interface VersionBannerProps extends HTMLAttributes<HTMLDivElement> {
9
+ /** The new version, e.g. "v0.6.0". Empty = no banner. */
10
+ version?: string | null;
11
+ /** Long text; default "New version (vX) available - reload the page". */
12
+ text?: ReactNode;
13
+ /** Short text below 40rem; default "New version". */
14
+ short?: ReactNode;
15
+ actionLabel?: ReactNode;
16
+ /** Custom reload; without it the action is a plain link to the current page. */
17
+ onReload?: () => void;
18
+ tone?: "warning" | "info" | "success";
19
+ floating?: boolean;
20
+ }
21
+
22
+ /** `.oc-version-banner`: "new version available - reload" chip. */
23
+ export const VersionBanner = forwardRef<HTMLDivElement, VersionBannerProps>(function VersionBanner(
24
+ { version, text, short = "New version", actionLabel = "Reload", onReload, tone = "warning", floating, className, ...rest },
25
+ ref,
26
+ ) {
27
+ if (!version) return null;
28
+ const cls = cx("oc-version-banner", tone !== "warning" && `oc-version-banner--${tone}`, floating && "oc-version-banner--floating", className);
29
+ return (
30
+ <div ref={ref} className={cls} role="status" {...rest}>
31
+ <span className="oc-version-banner-dot" aria-hidden="true" />
32
+ <span className="oc-version-banner-text">{text ?? `New version (${version}) available - reload the page`}</span>
33
+ <span className="oc-version-banner-short">{short}</span>
34
+ {onReload ? (
35
+ <button className="oc-version-banner-action" type="button" onClick={onReload}>{actionLabel}</button>
36
+ ) : (
37
+ <a className="oc-version-banner-action" href="">{actionLabel}</a>
38
+ )}
39
+ </div>
40
+ );
41
+ });