@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.
- package/LICENSE +21 -21
- package/README.md +21 -21
- package/package.json +71 -71
- package/src/blocks/BlockAboutTimeline.tsx +46 -46
- package/src/blocks/BlockAppHeader.tsx +52 -52
- package/src/blocks/BlockAppShell.tsx +56 -56
- package/src/blocks/BlockAuth.tsx +53 -53
- package/src/blocks/BlockAuthSplit.tsx +84 -84
- package/src/blocks/BlockContactGrid.tsx +71 -71
- package/src/blocks/BlockCta.tsx +23 -23
- package/src/blocks/BlockDataTable.tsx +57 -57
- package/src/blocks/BlockFaq.tsx +55 -55
- package/src/blocks/BlockFeatures.tsx +38 -38
- package/src/blocks/BlockFooter.tsx +50 -50
- package/src/blocks/BlockFormPage.tsx +26 -26
- package/src/blocks/BlockHero.tsx +27 -27
- package/src/blocks/BlockHeroCode.tsx +63 -63
- package/src/blocks/BlockHeroOrbit.tsx +73 -73
- package/src/blocks/BlockHeroSplit.tsx +28 -28
- package/src/blocks/BlockModuleHeader.tsx +34 -34
- package/src/blocks/BlockPageHero.tsx +25 -25
- package/src/blocks/BlockPortfolioGrid.tsx +50 -50
- package/src/blocks/BlockPricing.tsx +62 -62
- package/src/blocks/BlockProcess.tsx +50 -50
- package/src/blocks/BlockProductGrid.tsx +54 -54
- package/src/blocks/BlockProfileHeader.tsx +57 -57
- package/src/blocks/BlockShowcase.tsx +58 -58
- package/src/blocks/BlockSiteFooter.tsx +60 -60
- package/src/blocks/BlockSiteHeader.tsx +42 -42
- package/src/blocks/BlockSpotlight.tsx +58 -58
- package/src/blocks/BlockStats.tsx +26 -26
- package/src/blocks/BlockStatsCounter.tsx +31 -31
- package/src/blocks/BlockTeamList.tsx +48 -48
- package/src/blocks/BlockTwoFactor.tsx +57 -57
- package/src/blocks/BlockWizardDialog.tsx +101 -101
- package/src/components/Accordion.tsx +31 -31
- package/src/components/AccordionAccent.tsx +39 -39
- package/src/components/AffixInput.tsx +47 -47
- package/src/components/Alert.tsx +24 -24
- package/src/components/AlertDialog.tsx +60 -60
- package/src/components/AlphaTabs.tsx +63 -63
- package/src/components/Attachment.tsx +140 -140
- package/src/components/Avatar.tsx +32 -32
- package/src/components/BackLink.tsx +11 -11
- package/src/components/Badge.tsx +14 -14
- package/src/components/BarcodeInput.tsx +64 -64
- package/src/components/Breadcrumb.tsx +32 -32
- package/src/components/BrowserFrame.tsx +48 -48
- package/src/components/BusyOverlay.tsx +52 -52
- package/src/components/Button.tsx +49 -49
- package/src/components/Card.tsx +27 -27
- package/src/components/ChartLine.tsx +119 -119
- package/src/components/ChatComposer.tsx +73 -73
- package/src/components/Checkbox.tsx +14 -14
- package/src/components/Checklist.tsx +45 -45
- package/src/components/ChipFilter.tsx +60 -60
- package/src/components/Collapsible.tsx +43 -43
- package/src/components/ColorField.tsx +48 -48
- package/src/components/ColorSelect.tsx +49 -49
- package/src/components/ColumnMenu.tsx +66 -66
- package/src/components/Command.tsx +113 -113
- package/src/components/ConfirmDialog.tsx +95 -95
- package/src/components/CookieConsent.tsx +137 -137
- package/src/components/CopyField.tsx +44 -44
- package/src/components/Counter.tsx +21 -21
- package/src/components/DataTable.tsx +201 -201
- package/src/components/DecimalInput.tsx +87 -87
- package/src/components/DefinitionList.tsx +38 -38
- package/src/components/DocViewer.tsx +110 -110
- package/src/components/Dropdown.tsx +52 -52
- package/src/components/Dropzone.tsx +46 -46
- package/src/components/EmojiPicker.tsx +72 -72
- package/src/components/EmptyState.tsx +27 -27
- package/src/components/EntityCard.tsx +56 -56
- package/src/components/FactList.tsx +43 -43
- package/src/components/FilterCounts.tsx +50 -50
- package/src/components/FlipCard.tsx +55 -55
- package/src/components/FormField.tsx +54 -54
- package/src/components/Greeting.tsx +63 -63
- package/src/components/Heading.tsx +27 -27
- package/src/components/Icon.tsx +25 -25
- package/src/components/ImageZoom.tsx +51 -51
- package/src/components/Input.tsx +21 -21
- package/src/components/InputGroup.tsx +24 -24
- package/src/components/LanguageSelect.tsx +64 -64
- package/src/components/LauncherCard.tsx +50 -50
- package/src/components/Lightbox.tsx +83 -83
- package/src/components/LinkArrow.tsx +27 -27
- package/src/components/ListToolbar.tsx +67 -67
- package/src/components/Marquee.tsx +38 -38
- package/src/components/MediaCard.tsx +47 -47
- package/src/components/MediaRow.tsx +53 -53
- package/src/components/MediaThumb.tsx +49 -49
- package/src/components/Message.tsx +171 -171
- package/src/components/MessageThread.tsx +177 -177
- package/src/components/Modal.tsx +81 -81
- package/src/components/Navmenu.tsx +62 -62
- package/src/components/NextTeaser.tsx +29 -29
- package/src/components/NumberInput.tsx +64 -64
- package/src/components/OtpInput.tsx +48 -48
- package/src/components/PageHeader.tsx +43 -43
- package/src/components/Pagination.tsx +42 -42
- package/src/components/PasswordInput.tsx +36 -36
- package/src/components/PasswordRequirements.tsx +46 -46
- package/src/components/PhoneInput.tsx +93 -93
- package/src/components/Popover.tsx +34 -34
- package/src/components/PriceCard.tsx +83 -83
- package/src/components/ProductMark.tsx +35 -35
- package/src/components/Progress.tsx +32 -32
- package/src/components/ProjectCard.tsx +46 -46
- package/src/components/Prose.tsx +79 -79
- package/src/components/RecoveryCodes.tsx +65 -65
- package/src/components/Segmented.tsx +47 -47
- package/src/components/Select.tsx +27 -27
- package/src/components/SeverityCard.tsx +53 -53
- package/src/components/Sheet.tsx +62 -62
- package/src/components/Skeleton.tsx +12 -12
- package/src/components/SortableRow.tsx +46 -46
- package/src/components/StackCard.tsx +40 -40
- package/src/components/StackList.tsx +42 -42
- package/src/components/StatCard.tsx +49 -49
- package/src/components/Stepper.tsx +54 -54
- package/src/components/Switch.tsx +18 -18
- package/src/components/Table.tsx +75 -75
- package/src/components/TableActions.tsx +54 -54
- package/src/components/TableCompact.tsx +61 -61
- package/src/components/Tabs.tsx +45 -45
- package/src/components/TagInput.tsx +73 -73
- package/src/components/TerminalLog.tsx +63 -63
- package/src/components/Textarea.tsx +19 -19
- package/src/components/ThemeSwitch.tsx +45 -45
- package/src/components/TimeInput.tsx +76 -76
- package/src/components/Timeline.tsx +45 -45
- package/src/components/Toast.tsx +138 -138
- package/src/components/ToggleField.tsx +39 -39
- package/src/components/Tooltip.tsx +14 -14
- package/src/components/TopProgress.tsx +54 -54
- package/src/components/Tree.tsx +97 -97
- package/src/components/UpgradeBanner.tsx +62 -62
- package/src/components/User.tsx +31 -31
- package/src/components/VersionBanner.tsx +41 -41
- package/src/hooks.tsx +141 -141
- package/src/utils.ts +25 -25
|
@@ -1,27 +1,27 @@
|
|
|
1
|
-
import { forwardRef } from "react";
|
|
2
|
-
import type { ReactNode, SelectHTMLAttributes } from "react";
|
|
3
|
-
import { cx } from "../utils";
|
|
4
|
-
|
|
5
|
-
export interface SelectOption {
|
|
6
|
-
value: string;
|
|
7
|
-
label: ReactNode;
|
|
8
|
-
disabled?: boolean;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export interface SelectProps extends SelectHTMLAttributes<HTMLSelectElement> {
|
|
12
|
-
/** Shortcut for `<option>` children. */
|
|
13
|
-
options?: Array<SelectOption | string>;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
/** `<select class="oc-select">` */
|
|
17
|
-
export const Select = forwardRef<HTMLSelectElement, SelectProps>(function Select({ options, className, children, ...rest }, ref) {
|
|
18
|
-
return (
|
|
19
|
-
<select ref={ref} className={cx("oc-select", className)} {...rest}>
|
|
20
|
-
{options?.map((o) => {
|
|
21
|
-
const opt = typeof o === "string" ? { value: o, label: o } : o;
|
|
22
|
-
return <option key={opt.value} value={opt.value} disabled={opt.disabled}>{opt.label}</option>;
|
|
23
|
-
})}
|
|
24
|
-
{children}
|
|
25
|
-
</select>
|
|
26
|
-
);
|
|
27
|
-
});
|
|
1
|
+
import { forwardRef } from "react";
|
|
2
|
+
import type { ReactNode, SelectHTMLAttributes } from "react";
|
|
3
|
+
import { cx } from "../utils";
|
|
4
|
+
|
|
5
|
+
export interface SelectOption {
|
|
6
|
+
value: string;
|
|
7
|
+
label: ReactNode;
|
|
8
|
+
disabled?: boolean;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface SelectProps extends SelectHTMLAttributes<HTMLSelectElement> {
|
|
12
|
+
/** Shortcut for `<option>` children. */
|
|
13
|
+
options?: Array<SelectOption | string>;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/** `<select class="oc-select">` */
|
|
17
|
+
export const Select = forwardRef<HTMLSelectElement, SelectProps>(function Select({ options, className, children, ...rest }, ref) {
|
|
18
|
+
return (
|
|
19
|
+
<select ref={ref} className={cx("oc-select", className)} {...rest}>
|
|
20
|
+
{options?.map((o) => {
|
|
21
|
+
const opt = typeof o === "string" ? { value: o, label: o } : o;
|
|
22
|
+
return <option key={opt.value} value={opt.value} disabled={opt.disabled}>{opt.label}</option>;
|
|
23
|
+
})}
|
|
24
|
+
{children}
|
|
25
|
+
</select>
|
|
26
|
+
);
|
|
27
|
+
});
|
|
@@ -1,53 +1,53 @@
|
|
|
1
|
-
// File: packages/react/src/components/SeverityCard.tsx
|
|
2
|
-
// Map: SeverityCard = details -> summary head (icon, title + tags, level badge) -> body (children) -> actions
|
|
3
|
-
// Native <details>: opens without JavaScript. Cards with the same `name` open one at a time.
|
|
4
|
-
import { forwardRef } from "react";
|
|
5
|
-
import type { DetailsHTMLAttributes, ReactNode } from "react";
|
|
6
|
-
import { cx } from "../utils";
|
|
7
|
-
|
|
8
|
-
export type SeverityLevel = "low" | "medium" | "high" | "critical";
|
|
9
|
-
|
|
10
|
-
const LEVEL_TEXT: Record<SeverityLevel, string> = { low: "Low", medium: "Medium", high: "High", critical: "Critical" };
|
|
11
|
-
|
|
12
|
-
export interface SeverityCardProps extends Omit<DetailsHTMLAttributes<HTMLDetailsElement>, "title"> {
|
|
13
|
-
level: SeverityLevel;
|
|
14
|
-
title: ReactNode;
|
|
15
|
-
/** Small tags under the title, e.g. ["email", "password"]. */
|
|
16
|
-
tags?: ReactNode[];
|
|
17
|
-
/** Badge text; default the level name ("High"). */
|
|
18
|
-
levelLabel?: ReactNode;
|
|
19
|
-
icon?: ReactNode;
|
|
20
|
-
/** Neutral colors (the finding is handled). */
|
|
21
|
-
resolved?: boolean;
|
|
22
|
-
actions?: ReactNode;
|
|
23
|
-
/** Exclusive group: cards with the same name open one at a time. */
|
|
24
|
-
name?: string;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
/** `details.oc-severity-card`: expandable card colored by risk level. */
|
|
28
|
-
export const SeverityCard = forwardRef<HTMLDetailsElement, SeverityCardProps>(function SeverityCard(
|
|
29
|
-
{ level, title, tags, levelLabel, icon, resolved, actions, className, children, ...rest },
|
|
30
|
-
ref,
|
|
31
|
-
) {
|
|
32
|
-
const cls = cx("oc-severity-card", `oc-severity-card--${level}`, resolved && "is-resolved", className);
|
|
33
|
-
return (
|
|
34
|
-
<details ref={ref} className={cls} {...(rest as object)}>
|
|
35
|
-
<summary className="oc-severity-card-head">
|
|
36
|
-
{icon != null && <span className="oc-severity-card-icon" aria-hidden="true">{icon}</span>}
|
|
37
|
-
<span className="oc-severity-card-main">
|
|
38
|
-
<span className="oc-severity-card-title">{title}</span>
|
|
39
|
-
{tags && tags.length > 0 && (
|
|
40
|
-
<span className="oc-severity-card-tags">
|
|
41
|
-
{tags.map((t, i) => <span className="oc-severity-card-tag" key={i}>{t}</span>)}
|
|
42
|
-
</span>
|
|
43
|
-
)}
|
|
44
|
-
</span>
|
|
45
|
-
<span className="oc-severity-card-level">{levelLabel ?? LEVEL_TEXT[level]}</span>
|
|
46
|
-
</summary>
|
|
47
|
-
<div className="oc-severity-card-body">
|
|
48
|
-
{children}
|
|
49
|
-
{actions != null && <div className="oc-severity-card-actions">{actions}</div>}
|
|
50
|
-
</div>
|
|
51
|
-
</details>
|
|
52
|
-
);
|
|
53
|
-
});
|
|
1
|
+
// File: packages/react/src/components/SeverityCard.tsx
|
|
2
|
+
// Map: SeverityCard = details -> summary head (icon, title + tags, level badge) -> body (children) -> actions
|
|
3
|
+
// Native <details>: opens without JavaScript. Cards with the same `name` open one at a time.
|
|
4
|
+
import { forwardRef } from "react";
|
|
5
|
+
import type { DetailsHTMLAttributes, ReactNode } from "react";
|
|
6
|
+
import { cx } from "../utils";
|
|
7
|
+
|
|
8
|
+
export type SeverityLevel = "low" | "medium" | "high" | "critical";
|
|
9
|
+
|
|
10
|
+
const LEVEL_TEXT: Record<SeverityLevel, string> = { low: "Low", medium: "Medium", high: "High", critical: "Critical" };
|
|
11
|
+
|
|
12
|
+
export interface SeverityCardProps extends Omit<DetailsHTMLAttributes<HTMLDetailsElement>, "title"> {
|
|
13
|
+
level: SeverityLevel;
|
|
14
|
+
title: ReactNode;
|
|
15
|
+
/** Small tags under the title, e.g. ["email", "password"]. */
|
|
16
|
+
tags?: ReactNode[];
|
|
17
|
+
/** Badge text; default the level name ("High"). */
|
|
18
|
+
levelLabel?: ReactNode;
|
|
19
|
+
icon?: ReactNode;
|
|
20
|
+
/** Neutral colors (the finding is handled). */
|
|
21
|
+
resolved?: boolean;
|
|
22
|
+
actions?: ReactNode;
|
|
23
|
+
/** Exclusive group: cards with the same name open one at a time. */
|
|
24
|
+
name?: string;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** `details.oc-severity-card`: expandable card colored by risk level. */
|
|
28
|
+
export const SeverityCard = forwardRef<HTMLDetailsElement, SeverityCardProps>(function SeverityCard(
|
|
29
|
+
{ level, title, tags, levelLabel, icon, resolved, actions, className, children, ...rest },
|
|
30
|
+
ref,
|
|
31
|
+
) {
|
|
32
|
+
const cls = cx("oc-severity-card", `oc-severity-card--${level}`, resolved && "is-resolved", className);
|
|
33
|
+
return (
|
|
34
|
+
<details ref={ref} className={cls} {...(rest as object)}>
|
|
35
|
+
<summary className="oc-severity-card-head">
|
|
36
|
+
{icon != null && <span className="oc-severity-card-icon" aria-hidden="true">{icon}</span>}
|
|
37
|
+
<span className="oc-severity-card-main">
|
|
38
|
+
<span className="oc-severity-card-title">{title}</span>
|
|
39
|
+
{tags && tags.length > 0 && (
|
|
40
|
+
<span className="oc-severity-card-tags">
|
|
41
|
+
{tags.map((t, i) => <span className="oc-severity-card-tag" key={i}>{t}</span>)}
|
|
42
|
+
</span>
|
|
43
|
+
)}
|
|
44
|
+
</span>
|
|
45
|
+
<span className="oc-severity-card-level">{levelLabel ?? LEVEL_TEXT[level]}</span>
|
|
46
|
+
</summary>
|
|
47
|
+
<div className="oc-severity-card-body">
|
|
48
|
+
{children}
|
|
49
|
+
{actions != null && <div className="oc-severity-card-actions">{actions}</div>}
|
|
50
|
+
</div>
|
|
51
|
+
</details>
|
|
52
|
+
);
|
|
53
|
+
});
|
package/src/components/Sheet.tsx
CHANGED
|
@@ -1,62 +1,62 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
|
|
3
|
-
import { forwardRef, useId, useRef } from "react";
|
|
4
|
-
import type { DialogHTMLAttributes, MouseEvent, ReactNode } from "react";
|
|
5
|
-
import { attrs, cx } from "../utils";
|
|
6
|
-
import { DialogContext, useDialog, useMergedRef } from "../hooks";
|
|
7
|
-
import type { DialogState } from "../hooks";
|
|
8
|
-
|
|
9
|
-
export type SheetSide = "right" | "left" | "top" | "bottom";
|
|
10
|
-
|
|
11
|
-
export interface SheetProps extends Omit<DialogHTMLAttributes<HTMLDialogElement>, "title" | "open" | "onClose">, DialogState {
|
|
12
|
-
/** Edge the panel slides from (default `right`). */
|
|
13
|
-
side?: SheetSide;
|
|
14
|
-
/** Wider panel (`oc-sheet-content--wide`). */
|
|
15
|
-
wide?: boolean;
|
|
16
|
-
title?: ReactNode;
|
|
17
|
-
description?: ReactNode;
|
|
18
|
-
/** Action row (`oc-sheet-footer`). */
|
|
19
|
-
footer?: ReactNode;
|
|
20
|
-
/** Accessible name of the close button. */
|
|
21
|
-
closeLabel?: string;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
/** Side panel on `<dialog class="oc-sheet">`. */
|
|
25
|
-
export const Sheet = forwardRef<HTMLDialogElement, SheetProps>(function Sheet(
|
|
26
|
-
{ open, defaultOpen, onOpenChange, side = "right", wide, title, description, footer, closeLabel = "Close", className, children, ...rest },
|
|
27
|
-
forwardedRef,
|
|
28
|
-
) {
|
|
29
|
-
const inner = useRef<HTMLDialogElement>(null);
|
|
30
|
-
const ref = useMergedRef(inner, forwardedRef);
|
|
31
|
-
const titleId = useId();
|
|
32
|
-
const dlg = useDialog(inner, { open, defaultOpen, onOpenChange });
|
|
33
|
-
const onClick = (e: MouseEvent<HTMLDialogElement>) => {
|
|
34
|
-
rest.onClick?.(e);
|
|
35
|
-
if (e.target === e.currentTarget) dlg.close();
|
|
36
|
-
};
|
|
37
|
-
return (
|
|
38
|
-
<dialog
|
|
39
|
-
ref={ref}
|
|
40
|
-
className={cx("oc-sheet", side !== "right" && `oc-sheet--${side}`, className)}
|
|
41
|
-
aria-labelledby={title != null ? titleId : undefined}
|
|
42
|
-
{...attrs({ closedby: "any" })}
|
|
43
|
-
{...rest}
|
|
44
|
-
onClick={onClick}
|
|
45
|
-
onClose={dlg.onClose}
|
|
46
|
-
>
|
|
47
|
-
<DialogContext.Provider value={{ close: dlg.close }}>
|
|
48
|
-
<div className={cx("oc-sheet-content", wide && "oc-sheet-content--wide")}>
|
|
49
|
-
<button className="oc-sheet-close" type="button" aria-label={closeLabel} onClick={dlg.close}>×</button>
|
|
50
|
-
{(title != null || description != null) && (
|
|
51
|
-
<div className="oc-sheet-header">
|
|
52
|
-
{title != null && <h2 className="oc-sheet-title" id={titleId}>{title}</h2>}
|
|
53
|
-
{description != null && <p className="oc-sheet-description">{description}</p>}
|
|
54
|
-
</div>
|
|
55
|
-
)}
|
|
56
|
-
<div className="oc-sheet-body">{children}</div>
|
|
57
|
-
{footer != null && <div className="oc-sheet-footer">{footer}</div>}
|
|
58
|
-
</div>
|
|
59
|
-
</DialogContext.Provider>
|
|
60
|
-
</dialog>
|
|
61
|
-
);
|
|
62
|
-
});
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { forwardRef, useId, useRef } from "react";
|
|
4
|
+
import type { DialogHTMLAttributes, MouseEvent, ReactNode } from "react";
|
|
5
|
+
import { attrs, cx } from "../utils";
|
|
6
|
+
import { DialogContext, useDialog, useMergedRef } from "../hooks";
|
|
7
|
+
import type { DialogState } from "../hooks";
|
|
8
|
+
|
|
9
|
+
export type SheetSide = "right" | "left" | "top" | "bottom";
|
|
10
|
+
|
|
11
|
+
export interface SheetProps extends Omit<DialogHTMLAttributes<HTMLDialogElement>, "title" | "open" | "onClose">, DialogState {
|
|
12
|
+
/** Edge the panel slides from (default `right`). */
|
|
13
|
+
side?: SheetSide;
|
|
14
|
+
/** Wider panel (`oc-sheet-content--wide`). */
|
|
15
|
+
wide?: boolean;
|
|
16
|
+
title?: ReactNode;
|
|
17
|
+
description?: ReactNode;
|
|
18
|
+
/** Action row (`oc-sheet-footer`). */
|
|
19
|
+
footer?: ReactNode;
|
|
20
|
+
/** Accessible name of the close button. */
|
|
21
|
+
closeLabel?: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** Side panel on `<dialog class="oc-sheet">`. */
|
|
25
|
+
export const Sheet = forwardRef<HTMLDialogElement, SheetProps>(function Sheet(
|
|
26
|
+
{ open, defaultOpen, onOpenChange, side = "right", wide, title, description, footer, closeLabel = "Close", className, children, ...rest },
|
|
27
|
+
forwardedRef,
|
|
28
|
+
) {
|
|
29
|
+
const inner = useRef<HTMLDialogElement>(null);
|
|
30
|
+
const ref = useMergedRef(inner, forwardedRef);
|
|
31
|
+
const titleId = useId();
|
|
32
|
+
const dlg = useDialog(inner, { open, defaultOpen, onOpenChange });
|
|
33
|
+
const onClick = (e: MouseEvent<HTMLDialogElement>) => {
|
|
34
|
+
rest.onClick?.(e);
|
|
35
|
+
if (e.target === e.currentTarget) dlg.close();
|
|
36
|
+
};
|
|
37
|
+
return (
|
|
38
|
+
<dialog
|
|
39
|
+
ref={ref}
|
|
40
|
+
className={cx("oc-sheet", side !== "right" && `oc-sheet--${side}`, className)}
|
|
41
|
+
aria-labelledby={title != null ? titleId : undefined}
|
|
42
|
+
{...attrs({ closedby: "any" })}
|
|
43
|
+
{...rest}
|
|
44
|
+
onClick={onClick}
|
|
45
|
+
onClose={dlg.onClose}
|
|
46
|
+
>
|
|
47
|
+
<DialogContext.Provider value={{ close: dlg.close }}>
|
|
48
|
+
<div className={cx("oc-sheet-content", wide && "oc-sheet-content--wide")}>
|
|
49
|
+
<button className="oc-sheet-close" type="button" aria-label={closeLabel} onClick={dlg.close}>×</button>
|
|
50
|
+
{(title != null || description != null) && (
|
|
51
|
+
<div className="oc-sheet-header">
|
|
52
|
+
{title != null && <h2 className="oc-sheet-title" id={titleId}>{title}</h2>}
|
|
53
|
+
{description != null && <p className="oc-sheet-description">{description}</p>}
|
|
54
|
+
</div>
|
|
55
|
+
)}
|
|
56
|
+
<div className="oc-sheet-body">{children}</div>
|
|
57
|
+
{footer != null && <div className="oc-sheet-footer">{footer}</div>}
|
|
58
|
+
</div>
|
|
59
|
+
</DialogContext.Provider>
|
|
60
|
+
</dialog>
|
|
61
|
+
);
|
|
62
|
+
});
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import { forwardRef } from "react";
|
|
2
|
-
import type { HTMLAttributes } from "react";
|
|
3
|
-
import { cx } from "../utils";
|
|
4
|
-
|
|
5
|
-
export interface SkeletonProps extends HTMLAttributes<HTMLDivElement> {
|
|
6
|
-
variant?: "circle" | "title" | "text" | "rect";
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
/** `<div class="oc-skeleton oc-skeleton--{variant}">` */
|
|
10
|
-
export const Skeleton = forwardRef<HTMLDivElement, SkeletonProps>(function Skeleton({ variant, className, ...rest }, ref) {
|
|
11
|
-
return <div ref={ref} className={cx("oc-skeleton", variant && `oc-skeleton--${variant}`, className)} {...rest} />;
|
|
12
|
-
});
|
|
1
|
+
import { forwardRef } from "react";
|
|
2
|
+
import type { HTMLAttributes } from "react";
|
|
3
|
+
import { cx } from "../utils";
|
|
4
|
+
|
|
5
|
+
export interface SkeletonProps extends HTMLAttributes<HTMLDivElement> {
|
|
6
|
+
variant?: "circle" | "title" | "text" | "rect";
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/** `<div class="oc-skeleton oc-skeleton--{variant}">` */
|
|
10
|
+
export const Skeleton = forwardRef<HTMLDivElement, SkeletonProps>(function Skeleton({ variant, className, ...rest }, ref) {
|
|
11
|
+
return <div ref={ref} className={cx("oc-skeleton", variant && `oc-skeleton--${variant}`, className)} {...rest} />;
|
|
12
|
+
});
|
|
@@ -1,46 +1,46 @@
|
|
|
1
|
-
// File: packages/react/src/components/SortableRow.tsx
|
|
2
|
-
// Map: SortableRow = tr.oc-sortable-row -> grip cell (button) -> your cells
|
|
3
|
-
// Styling only: your code handles the drag events (they are passed through on the row)
|
|
4
|
-
// and sets `dragging` / `drop` to show the states.
|
|
5
|
-
import { forwardRef } from "react";
|
|
6
|
-
import type { HTMLAttributes, ReactNode } from "react";
|
|
7
|
-
import { cx } from "../utils";
|
|
8
|
-
|
|
9
|
-
export interface SortableRowProps extends HTMLAttributes<HTMLTableRowElement> {
|
|
10
|
-
/** Accessible name of the grip, e.g. "Move Install". */
|
|
11
|
-
gripLabel: string;
|
|
12
|
-
/** This row is being moved (`.is-dragging`). */
|
|
13
|
-
dragging?: boolean;
|
|
14
|
-
/** Show the drop line above or below this row. */
|
|
15
|
-
drop?: "before" | "after" | null;
|
|
16
|
-
/** Locked row: no dragging, grip disabled. */
|
|
17
|
-
locked?: boolean;
|
|
18
|
-
/** Picked up with the keyboard (grip `aria-pressed`). */
|
|
19
|
-
grabbed?: boolean;
|
|
20
|
-
/** Keyboard handler for the grip (e.g. ArrowUp / ArrowDown to move). */
|
|
21
|
-
onGripKeyDown?: (e: React.KeyboardEvent<HTMLButtonElement>) => void;
|
|
22
|
-
children: ReactNode;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/** `tr.oc-sortable-row[draggable]` with a `button.oc-sortable-row-grip` in the first cell. */
|
|
26
|
-
export const SortableRow = forwardRef<HTMLTableRowElement, SortableRowProps>(function SortableRow(
|
|
27
|
-
{ gripLabel, dragging, drop, locked, grabbed, onGripKeyDown, className, children, ...rest },
|
|
28
|
-
ref,
|
|
29
|
-
) {
|
|
30
|
-
const cls = cx("oc-sortable-row", dragging && "is-dragging", drop && `is-drop-${drop}`, className);
|
|
31
|
-
return (
|
|
32
|
-
<tr ref={ref} className={cls} draggable={locked ? undefined : true} {...rest}>
|
|
33
|
-
<td className="oc-sortable-row-grip-cell">
|
|
34
|
-
<button
|
|
35
|
-
className="oc-sortable-row-grip"
|
|
36
|
-
type="button"
|
|
37
|
-
aria-label={gripLabel}
|
|
38
|
-
aria-pressed={grabbed === undefined ? undefined : grabbed}
|
|
39
|
-
disabled={locked}
|
|
40
|
-
onKeyDown={onGripKeyDown}
|
|
41
|
-
/>
|
|
42
|
-
</td>
|
|
43
|
-
{children}
|
|
44
|
-
</tr>
|
|
45
|
-
);
|
|
46
|
-
});
|
|
1
|
+
// File: packages/react/src/components/SortableRow.tsx
|
|
2
|
+
// Map: SortableRow = tr.oc-sortable-row -> grip cell (button) -> your cells
|
|
3
|
+
// Styling only: your code handles the drag events (they are passed through on the row)
|
|
4
|
+
// and sets `dragging` / `drop` to show the states.
|
|
5
|
+
import { forwardRef } from "react";
|
|
6
|
+
import type { HTMLAttributes, ReactNode } from "react";
|
|
7
|
+
import { cx } from "../utils";
|
|
8
|
+
|
|
9
|
+
export interface SortableRowProps extends HTMLAttributes<HTMLTableRowElement> {
|
|
10
|
+
/** Accessible name of the grip, e.g. "Move Install". */
|
|
11
|
+
gripLabel: string;
|
|
12
|
+
/** This row is being moved (`.is-dragging`). */
|
|
13
|
+
dragging?: boolean;
|
|
14
|
+
/** Show the drop line above or below this row. */
|
|
15
|
+
drop?: "before" | "after" | null;
|
|
16
|
+
/** Locked row: no dragging, grip disabled. */
|
|
17
|
+
locked?: boolean;
|
|
18
|
+
/** Picked up with the keyboard (grip `aria-pressed`). */
|
|
19
|
+
grabbed?: boolean;
|
|
20
|
+
/** Keyboard handler for the grip (e.g. ArrowUp / ArrowDown to move). */
|
|
21
|
+
onGripKeyDown?: (e: React.KeyboardEvent<HTMLButtonElement>) => void;
|
|
22
|
+
children: ReactNode;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/** `tr.oc-sortable-row[draggable]` with a `button.oc-sortable-row-grip` in the first cell. */
|
|
26
|
+
export const SortableRow = forwardRef<HTMLTableRowElement, SortableRowProps>(function SortableRow(
|
|
27
|
+
{ gripLabel, dragging, drop, locked, grabbed, onGripKeyDown, className, children, ...rest },
|
|
28
|
+
ref,
|
|
29
|
+
) {
|
|
30
|
+
const cls = cx("oc-sortable-row", dragging && "is-dragging", drop && `is-drop-${drop}`, className);
|
|
31
|
+
return (
|
|
32
|
+
<tr ref={ref} className={cls} draggable={locked ? undefined : true} {...rest}>
|
|
33
|
+
<td className="oc-sortable-row-grip-cell">
|
|
34
|
+
<button
|
|
35
|
+
className="oc-sortable-row-grip"
|
|
36
|
+
type="button"
|
|
37
|
+
aria-label={gripLabel}
|
|
38
|
+
aria-pressed={grabbed === undefined ? undefined : grabbed}
|
|
39
|
+
disabled={locked}
|
|
40
|
+
onKeyDown={onGripKeyDown}
|
|
41
|
+
/>
|
|
42
|
+
</td>
|
|
43
|
+
{children}
|
|
44
|
+
</tr>
|
|
45
|
+
);
|
|
46
|
+
});
|
|
@@ -1,40 +1,40 @@
|
|
|
1
|
-
// File: packages/react/src/components/StackCard.tsx
|
|
2
|
-
// Map: props -> StackCard (deck: MediaThumb cover + count badge -> title link + meta)
|
|
3
|
-
// Same markup as packages/ui/snippets/stack-card.html.
|
|
4
|
-
import { forwardRef } from "react";
|
|
5
|
-
import type { HTMLAttributes, ReactNode } from "react";
|
|
6
|
-
import { cx } from "../utils";
|
|
7
|
-
import { MediaThumb } from "./MediaThumb";
|
|
8
|
-
import type { MediaThumbProps } from "./MediaThumb";
|
|
9
|
-
|
|
10
|
-
export interface StackCardProps extends Omit<HTMLAttributes<HTMLElement>, "title"> {
|
|
11
|
-
title: ReactNode;
|
|
12
|
-
/** Link of the title; it covers the whole card. */
|
|
13
|
-
href: string;
|
|
14
|
-
meta?: ReactNode;
|
|
15
|
-
/** Badge text, e.g. "12 videos". */
|
|
16
|
-
count?: ReactNode;
|
|
17
|
-
/** Show the count as a side panel (`--panel`). */
|
|
18
|
-
panel?: boolean;
|
|
19
|
-
/** Props for the cover (MediaThumb). */
|
|
20
|
-
thumb?: MediaThumbProps;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
/** `article.oc-stack-card`: cover with two layers behind it and a count badge. */
|
|
24
|
-
export const StackCard = forwardRef<HTMLElement, StackCardProps>(function StackCard(
|
|
25
|
-
{ title, href, meta, count, panel, thumb, className, ...rest },
|
|
26
|
-
ref,
|
|
27
|
-
) {
|
|
28
|
-
return (
|
|
29
|
-
<article ref={ref} className={cx("oc-stack-card", panel && "oc-stack-card--panel", className)} {...rest}>
|
|
30
|
-
<div className="oc-stack-card__deck">
|
|
31
|
-
<MediaThumb {...thumb} />
|
|
32
|
-
{count != null && <span className="oc-stack-card__count">{count}</span>}
|
|
33
|
-
</div>
|
|
34
|
-
<div>
|
|
35
|
-
<h3 className="oc-stack-card__title"><a href={href}>{title}</a></h3>
|
|
36
|
-
{meta != null && <p className="oc-stack-card__meta">{meta}</p>}
|
|
37
|
-
</div>
|
|
38
|
-
</article>
|
|
39
|
-
);
|
|
40
|
-
});
|
|
1
|
+
// File: packages/react/src/components/StackCard.tsx
|
|
2
|
+
// Map: props -> StackCard (deck: MediaThumb cover + count badge -> title link + meta)
|
|
3
|
+
// Same markup as packages/ui/snippets/stack-card.html.
|
|
4
|
+
import { forwardRef } from "react";
|
|
5
|
+
import type { HTMLAttributes, ReactNode } from "react";
|
|
6
|
+
import { cx } from "../utils";
|
|
7
|
+
import { MediaThumb } from "./MediaThumb";
|
|
8
|
+
import type { MediaThumbProps } from "./MediaThumb";
|
|
9
|
+
|
|
10
|
+
export interface StackCardProps extends Omit<HTMLAttributes<HTMLElement>, "title"> {
|
|
11
|
+
title: ReactNode;
|
|
12
|
+
/** Link of the title; it covers the whole card. */
|
|
13
|
+
href: string;
|
|
14
|
+
meta?: ReactNode;
|
|
15
|
+
/** Badge text, e.g. "12 videos". */
|
|
16
|
+
count?: ReactNode;
|
|
17
|
+
/** Show the count as a side panel (`--panel`). */
|
|
18
|
+
panel?: boolean;
|
|
19
|
+
/** Props for the cover (MediaThumb). */
|
|
20
|
+
thumb?: MediaThumbProps;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** `article.oc-stack-card`: cover with two layers behind it and a count badge. */
|
|
24
|
+
export const StackCard = forwardRef<HTMLElement, StackCardProps>(function StackCard(
|
|
25
|
+
{ title, href, meta, count, panel, thumb, className, ...rest },
|
|
26
|
+
ref,
|
|
27
|
+
) {
|
|
28
|
+
return (
|
|
29
|
+
<article ref={ref} className={cx("oc-stack-card", panel && "oc-stack-card--panel", className)} {...rest}>
|
|
30
|
+
<div className="oc-stack-card__deck">
|
|
31
|
+
<MediaThumb {...thumb} />
|
|
32
|
+
{count != null && <span className="oc-stack-card__count">{count}</span>}
|
|
33
|
+
</div>
|
|
34
|
+
<div>
|
|
35
|
+
<h3 className="oc-stack-card__title"><a href={href}>{title}</a></h3>
|
|
36
|
+
{meta != null && <p className="oc-stack-card__meta">{meta}</p>}
|
|
37
|
+
</div>
|
|
38
|
+
</article>
|
|
39
|
+
);
|
|
40
|
+
});
|
|
@@ -1,42 +1,42 @@
|
|
|
1
|
-
// File: packages/react/src/components/StackList.tsx | Map: types -> StackList (ul.oc-stack-list -> li pills)
|
|
2
|
-
import { forwardRef } from "react";
|
|
3
|
-
import type { HTMLAttributes, ReactNode } from "react";
|
|
4
|
-
import { cx } from "../utils";
|
|
5
|
-
|
|
6
|
-
export interface StackListItem {
|
|
7
|
-
label: ReactNode;
|
|
8
|
-
/** Optional glyph or SVG before the label (decorative). */
|
|
9
|
-
icon?: ReactNode;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export interface StackListProps extends HTMLAttributes<HTMLUListElement> {
|
|
13
|
-
/** Strings, or objects with an icon. */
|
|
14
|
-
items: Array<ReactNode | StackListItem>;
|
|
15
|
-
neutral?: boolean;
|
|
16
|
-
size?: "default" | "sm";
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
const isItem = (v: unknown): v is StackListItem => typeof v === "object" && v !== null && "label" in v;
|
|
20
|
-
|
|
21
|
-
/** `<ul class="oc-stack-list">`: technology pills. Set an accent with `className="oc-accent--violet"`. */
|
|
22
|
-
export const StackList = forwardRef<HTMLUListElement, StackListProps>(function StackList(
|
|
23
|
-
{ items, neutral = false, size = "default", className, ...rest },
|
|
24
|
-
ref,
|
|
25
|
-
) {
|
|
26
|
-
return (
|
|
27
|
-
<ul ref={ref} className={cx("oc-stack-list", neutral && "oc-stack-list--neutral", size === "sm" && "oc-stack-list--sm", className)} {...rest}>
|
|
28
|
-
{items.map((item, i) => (
|
|
29
|
-
<li className="oc-stack-list__item" key={i}>
|
|
30
|
-
{isItem(item) ? (
|
|
31
|
-
<>
|
|
32
|
-
{item.icon != null && <span className="oc-stack-list__icon" aria-hidden="true">{item.icon}</span>}
|
|
33
|
-
{item.label}
|
|
34
|
-
</>
|
|
35
|
-
) : (
|
|
36
|
-
item
|
|
37
|
-
)}
|
|
38
|
-
</li>
|
|
39
|
-
))}
|
|
40
|
-
</ul>
|
|
41
|
-
);
|
|
42
|
-
});
|
|
1
|
+
// File: packages/react/src/components/StackList.tsx | Map: types -> StackList (ul.oc-stack-list -> li pills)
|
|
2
|
+
import { forwardRef } from "react";
|
|
3
|
+
import type { HTMLAttributes, ReactNode } from "react";
|
|
4
|
+
import { cx } from "../utils";
|
|
5
|
+
|
|
6
|
+
export interface StackListItem {
|
|
7
|
+
label: ReactNode;
|
|
8
|
+
/** Optional glyph or SVG before the label (decorative). */
|
|
9
|
+
icon?: ReactNode;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface StackListProps extends HTMLAttributes<HTMLUListElement> {
|
|
13
|
+
/** Strings, or objects with an icon. */
|
|
14
|
+
items: Array<ReactNode | StackListItem>;
|
|
15
|
+
neutral?: boolean;
|
|
16
|
+
size?: "default" | "sm";
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const isItem = (v: unknown): v is StackListItem => typeof v === "object" && v !== null && "label" in v;
|
|
20
|
+
|
|
21
|
+
/** `<ul class="oc-stack-list">`: technology pills. Set an accent with `className="oc-accent--violet"`. */
|
|
22
|
+
export const StackList = forwardRef<HTMLUListElement, StackListProps>(function StackList(
|
|
23
|
+
{ items, neutral = false, size = "default", className, ...rest },
|
|
24
|
+
ref,
|
|
25
|
+
) {
|
|
26
|
+
return (
|
|
27
|
+
<ul ref={ref} className={cx("oc-stack-list", neutral && "oc-stack-list--neutral", size === "sm" && "oc-stack-list--sm", className)} {...rest}>
|
|
28
|
+
{items.map((item, i) => (
|
|
29
|
+
<li className="oc-stack-list__item" key={i}>
|
|
30
|
+
{isItem(item) ? (
|
|
31
|
+
<>
|
|
32
|
+
{item.icon != null && <span className="oc-stack-list__icon" aria-hidden="true">{item.icon}</span>}
|
|
33
|
+
{item.label}
|
|
34
|
+
</>
|
|
35
|
+
) : (
|
|
36
|
+
item
|
|
37
|
+
)}
|
|
38
|
+
</li>
|
|
39
|
+
))}
|
|
40
|
+
</ul>
|
|
41
|
+
);
|
|
42
|
+
});
|