@langchain/macaw-components 1.0.0-beta.1 → 1.0.0-beta.6
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/dist/_chunks/{LoadingIndicator-DgtU9aqD.js → LoadingIndicator-CDcArsiM.js} +13 -12
- package/dist/_chunks/LoadingIndicator-CDcArsiM.js.map +1 -0
- package/dist/_chunks/render-attachment-icon-BWBEMxXZ.js +270 -0
- package/dist/_chunks/render-attachment-icon-BWBEMxXZ.js.map +1 -0
- package/dist/catalog.json +527 -408
- package/dist/components/Attachment/Attachment.d.ts +21 -0
- package/dist/components/Attachment/Attachment.js +165 -0
- package/dist/components/Attachment/Attachment.js.map +1 -0
- package/dist/components/Attachment/AttachmentList.d.ts +5 -0
- package/dist/components/Attachment/AttachmentList.js +32 -0
- package/dist/components/Attachment/AttachmentList.js.map +1 -0
- package/dist/components/Attachment/index.d.ts +4 -0
- package/dist/components/Attachment/index.js +3 -0
- package/dist/components/Attachment/render-attachment-icon.d.ts +3 -0
- package/dist/components/Attachment/render-attachment-icon.js +2 -0
- package/dist/components/Avatar/Avatar.js +2 -2
- package/dist/components/Badge/Badge.d.ts +2 -0
- package/dist/components/Badge/Badge.js +12 -1
- package/dist/components/Badge/Badge.js.map +1 -1
- package/dist/components/Banner/Banner.js +1 -1
- package/dist/components/Button/Button.js +1 -1
- package/dist/components/Button/constants.js +2 -2
- package/dist/components/Button/constants.js.map +1 -1
- package/dist/components/ChartCard/ChartCard.d.ts +1 -4
- package/dist/components/ChartCard/ChartCard.js +2 -2
- package/dist/components/ChartCard/ChartCard.js.map +1 -1
- package/dist/components/ChartCard/ChartCardSkeleton.d.ts +1 -1
- package/dist/components/ChartCard/ChartCardSkeleton.js +37 -0
- package/dist/components/ChartCard/ChartCardSkeleton.js.map +1 -1
- package/dist/components/ChartLegend/ChartLegend.js +2 -2
- package/dist/components/ChartLegend/ChartLegendItemRenderer.js +2 -2
- package/dist/components/ChartLegend/ChartLegendItemRenderer.js.map +1 -1
- package/dist/components/Code/Code.utils.d.ts +3 -2
- package/dist/components/Code/Code.utils.js +7 -3
- package/dist/components/Code/Code.utils.js.map +1 -1
- package/dist/components/Code/CodeLanguageSelect.d.ts +7 -0
- package/dist/components/Code/CodeLanguageSelect.js +29 -0
- package/dist/components/Code/CodeLanguageSelect.js.map +1 -0
- package/dist/components/Code/CodeLite.js +3 -0
- package/dist/components/Code/CodeLite.js.map +1 -1
- package/dist/components/Code/CodeToolbar.d.ts +7 -0
- package/dist/components/Code/CodeToolbar.js +19 -0
- package/dist/components/Code/CodeToolbar.js.map +1 -0
- package/dist/components/Code/codeLanguages.d.ts +7 -0
- package/dist/components/Code/codeLanguages.js +59 -0
- package/dist/components/Code/codeLanguages.js.map +1 -0
- package/dist/components/Code/index.d.ts +15 -2
- package/dist/components/Code/index.js +70 -50
- package/dist/components/Code/index.js.map +1 -1
- package/dist/components/Code/types.d.ts +1 -1
- package/dist/components/Command/Command.d.ts +10 -13
- package/dist/components/Command/Command.js +7 -2
- package/dist/components/Command/Command.js.map +1 -1
- package/dist/components/Command/CommandMenu.d.ts +7 -1
- package/dist/components/Command/CommandMenu.js +17 -9
- package/dist/components/Command/CommandMenu.js.map +1 -1
- package/dist/components/ContextMenu/ContextMenu.d.ts +6 -0
- package/dist/components/ContextMenu/ContextMenu.js +3 -2
- package/dist/components/ContextMenu/ContextMenu.js.map +1 -1
- package/dist/components/CopyButton/CopyButton.js +2 -2
- package/dist/components/Dialog/index.js +2 -2
- package/dist/components/DropdownMenu/DropdownMenu.d.ts +11 -0
- package/dist/components/DropdownMenu/DropdownMenu.js +5 -4
- package/dist/components/DropdownMenu/DropdownMenu.js.map +1 -1
- package/dist/components/ErrorMessage/ErrorMessage.js +1 -1
- package/dist/components/GroupedTabs/GroupedTabs.d.ts +5 -2
- package/dist/components/GroupedTabs/GroupedTabs.js +33 -26
- package/dist/components/GroupedTabs/GroupedTabs.js.map +1 -1
- package/dist/components/IconButton/IconButton.js +2 -2
- package/dist/components/Input/Input.js +1 -1
- package/dist/components/LineChart/LineChart.d.ts +2 -2
- package/dist/components/LineChart/LineChart.js +3 -1
- package/dist/components/LineChart/LineChart.js.map +1 -1
- package/dist/components/LineChart/LineChart.types.d.ts +16 -0
- package/dist/components/LineChart/LineChartPlot.d.ts +3 -2
- package/dist/components/LineChart/LineChartPlot.js +8 -1
- package/dist/components/LineChart/LineChartPlot.js.map +1 -1
- package/dist/components/LineChart/LineChartVerticalMarkers.d.ts +8 -0
- package/dist/components/LineChart/LineChartVerticalMarkers.js +47 -0
- package/dist/components/LineChart/LineChartVerticalMarkers.js.map +1 -0
- package/dist/components/LineChart/index.d.ts +1 -1
- package/dist/components/Logo/index.js +11 -6
- package/dist/components/Logo/index.js.map +1 -1
- package/dist/components/MetricChart/MetricChart.d.ts +2 -0
- package/dist/components/MetricChart/MetricChart.js +15 -4
- package/dist/components/MetricChart/MetricChart.js.map +1 -1
- package/dist/components/MetricChart/index.d.ts +1 -1
- package/dist/components/Pane/Pane.js +2 -2
- package/dist/components/SankeyChart/AnimatedSankeyLink.d.ts +17 -0
- package/dist/components/SankeyChart/AnimatedSankeyLink.js +44 -0
- package/dist/components/SankeyChart/AnimatedSankeyLink.js.map +1 -0
- package/dist/components/SankeyChart/AnimatedSankeyNode.d.ts +16 -0
- package/dist/components/SankeyChart/AnimatedSankeyNode.js +42 -0
- package/dist/components/SankeyChart/AnimatedSankeyNode.js.map +1 -0
- package/dist/components/SankeyChart/SankeyChart.d.ts +42 -0
- package/dist/components/SankeyChart/SankeyChart.js +185 -0
- package/dist/components/SankeyChart/SankeyChart.js.map +1 -0
- package/dist/components/SankeyChart/SankeyChart.types.d.ts +90 -0
- package/dist/components/SankeyChart/SankeyChart.types.js +0 -0
- package/dist/components/SankeyChart/SankeyChart.utils.d.ts +21 -0
- package/dist/components/SankeyChart/SankeyChart.utils.js +299 -0
- package/dist/components/SankeyChart/SankeyChart.utils.js.map +1 -0
- package/dist/components/SankeyChart/SankeyNodeLabel.d.ts +10 -0
- package/dist/components/SankeyChart/SankeyNodeLabel.js +30 -0
- package/dist/components/SankeyChart/SankeyNodeLabel.js.map +1 -0
- package/dist/components/SankeyChart/SankeyNodeLabel.utils.d.ts +9 -0
- package/dist/components/SankeyChart/SankeyNodeLabel.utils.js +29 -0
- package/dist/components/SankeyChart/SankeyNodeLabel.utils.js.map +1 -0
- package/dist/components/SankeyChart/constants.d.ts +22 -0
- package/dist/components/SankeyChart/constants.js +27 -0
- package/dist/components/SankeyChart/constants.js.map +1 -0
- package/dist/components/SankeyChart/index.d.ts +5 -0
- package/dist/components/SankeyChart/index.js +4 -0
- package/dist/components/Select/Select.js +5 -5
- package/dist/components/Select/Select.js.map +1 -1
- package/dist/components/Select/SelectPrimitive.d.ts +6 -0
- package/dist/components/Select/SelectPrimitive.js +3 -2
- package/dist/components/Select/SelectPrimitive.js.map +1 -1
- package/dist/components/Slider/Slider.js +10 -3
- package/dist/components/Slider/Slider.js.map +1 -1
- package/dist/components/SplitViewPane/SplitViewPane.d.ts +2 -1
- package/dist/components/SplitViewPane/SplitViewPane.js +113 -219
- package/dist/components/SplitViewPane/SplitViewPane.js.map +1 -1
- package/dist/components/SplitViewPane/SplitViewPaneHeader.js +2 -2
- package/dist/components/SplitViewPane/useShowChildren.d.ts +5 -0
- package/dist/components/SplitViewPane/useShowChildren.js +14 -0
- package/dist/components/SplitViewPane/useShowChildren.js.map +1 -0
- package/dist/components/SplitViewPane/useSplitViewPaneResize.d.ts +21 -0
- package/dist/components/SplitViewPane/useSplitViewPaneResize.js +145 -0
- package/dist/components/SplitViewPane/useSplitViewPaneResize.js.map +1 -0
- package/dist/components/Textarea/Textarea.d.ts +4 -3
- package/dist/components/Textarea/Textarea.js +7 -21
- package/dist/components/Textarea/Textarea.js.map +1 -1
- package/dist/components/ThinkingState/LoadingIndicator.d.ts +1 -0
- package/dist/components/ThinkingState/LoadingIndicator.js +1 -1
- package/dist/components/ThinkingState/ThinkingState.d.ts +1 -0
- package/dist/components/ThinkingState/ThinkingState.js +5 -4
- package/dist/components/ThinkingState/ThinkingState.js.map +1 -1
- package/dist/components/ThinkingState/index.js +1 -1
- package/dist/components/Toast/index.js +33 -28
- package/dist/components/Toast/index.js.map +1 -1
- package/dist/components/Tooltip/Tooltip.js +2 -2
- package/dist/components/Typeahead/Typeahead.js +18 -8
- package/dist/components/Typeahead/Typeahead.js.map +1 -1
- package/dist/components/Typeahead/Typeahead.types.d.ts +2 -0
- package/dist/components/Typeahead/TypeaheadParts.d.ts +3 -1
- package/dist/components/Typeahead/TypeaheadParts.js +7 -6
- package/dist/components/Typeahead/TypeaheadParts.js.map +1 -1
- package/dist/components/Typeahead/TypeaheadView.js +19 -13
- package/dist/components/Typeahead/TypeaheadView.js.map +1 -1
- package/dist/components/Typeahead/useTypeaheadDomSync.d.ts +1 -1
- package/dist/components/Typeahead/useTypeaheadDomSync.js +14 -8
- package/dist/components/Typeahead/useTypeaheadDomSync.js.map +1 -1
- package/dist/components/Typeahead/useTypeaheadUncontrolledInput.d.ts +2 -1
- package/dist/components/Typeahead/useTypeaheadUncontrolledInput.js +10 -9
- package/dist/components/Typeahead/useTypeaheadUncontrolledInput.js.map +1 -1
- package/dist/components/UnsavedChangesDialog.js +2 -2
- package/dist/components/index.d.ts +3 -1
- package/dist/components/index.js +7 -5
- package/dist/components.css +22 -18
- package/dist/hooks/useDebouncedCommit.d.ts +14 -0
- package/dist/hooks/useDebouncedCommit.js +35 -0
- package/dist/hooks/useDebouncedCommit.js.map +1 -0
- package/dist/icons/LongTailPhosphorIcons.js +1 -1
- package/dist/icons/PaddedPhosphorIcons.d.ts +1 -0
- package/dist/icons/PaddedPhosphorIcons.js +4 -2
- package/dist/icons/PaddedPhosphorIcons.js.map +1 -1
- package/dist/icons/WeightedPhosphorIcons.d.ts +1 -0
- package/dist/icons/WeightedPhosphorIcons.js +3 -1
- package/dist/icons/WeightedPhosphorIcons.js.map +1 -1
- package/dist/icons/index.js +3 -3
- package/dist/index.js +7 -5
- package/dist/utilities.css +1 -1
- package/dist/utils/chartColors.d.ts +2 -1
- package/dist/utils/chartColors.js +2 -1
- package/dist/utils/chartColors.js.map +1 -1
- package/dist/utils/componentSizes.d.ts +0 -1
- package/dist/utils/componentSizes.js.map +1 -1
- package/dist/utils/lazy-codemirror-loader.d.ts +0 -2
- package/dist/utils/lazy-codemirror-loader.js +1 -3
- package/dist/utils/lazy-codemirror-loader.js.map +1 -1
- package/docs/DESIGN.md +17 -0
- package/docs/STYLES.md +4 -1
- package/package.json +21 -8
- package/dist/_chunks/LoadingIndicator-DgtU9aqD.js.map +0 -1
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { ComponentPropsWithRef, ReactNode } from 'react';
|
|
2
|
+
import { type IconComponent } from '../Icon/index.js';
|
|
3
|
+
export interface AttachmentProps extends Omit<ComponentPropsWithRef<'div'>, 'children' | 'onClick'> {
|
|
4
|
+
name: string;
|
|
5
|
+
contentType?: string | null;
|
|
6
|
+
icon?: IconComponent;
|
|
7
|
+
/** Noninteractive thumbnail content. The consumer owns its source and lifecycle. */
|
|
8
|
+
preview?: ReactNode;
|
|
9
|
+
/** Secondary information, inline in compact rows and stacked in large rows. */
|
|
10
|
+
metadata?: ReactNode;
|
|
11
|
+
variant?: 'file' | 'thumbnail';
|
|
12
|
+
/** File-row height: sm=24px, md=32px, lg=48px. Thumbnails use larger tiles. */
|
|
13
|
+
size?: 'sm' | 'md' | 'lg';
|
|
14
|
+
status?: 'ready' | 'loading' | 'uploading' | 'error';
|
|
15
|
+
onOpen?: () => void;
|
|
16
|
+
openLabel?: string;
|
|
17
|
+
onRemove?: () => void;
|
|
18
|
+
/** Sibling controls; use xs/sm/md buttons or smaller for sm/md/lg rows. */
|
|
19
|
+
actions?: ReactNode;
|
|
20
|
+
}
|
|
21
|
+
export declare const Attachment: import("react").ForwardRefExoticComponent<Omit<AttachmentProps, "ref"> & import("react").RefAttributes<HTMLDivElement>>;
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import { cn } from "../../utils/cn.js";
|
|
2
|
+
import { CONTROL_SIZES, VISUAL_ELEMENT_SIZES } from "../../utils/componentSizes.js";
|
|
3
|
+
import { Text } from "../Text/Text.js";
|
|
4
|
+
import { SpinnerIcon } from "../Spinner/Spinner.js";
|
|
5
|
+
import { Button } from "../Button/Button.js";
|
|
6
|
+
import { Icon } from "../Icon/Icon.js";
|
|
7
|
+
import { IconButton } from "../IconButton/IconButton.js";
|
|
8
|
+
import { t as getAttachmentIcon } from "../../_chunks/render-attachment-icon-BWBEMxXZ.js";
|
|
9
|
+
import { forwardRef, useId } from "react";
|
|
10
|
+
import { FileIcon } from "@phosphor-icons/react/dist/ssr/File";
|
|
11
|
+
import { WarningCircleIcon } from "@phosphor-icons/react/dist/ssr/WarningCircle";
|
|
12
|
+
import { XIcon } from "@phosphor-icons/react/dist/ssr/X";
|
|
13
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
14
|
+
//#region packages/components/src/components/Attachment/Attachment.tsx
|
|
15
|
+
var SIZE_STYLES = {
|
|
16
|
+
sm: {
|
|
17
|
+
height: CONTROL_SIZES.sm.heightClassName,
|
|
18
|
+
padding: "px-space-1",
|
|
19
|
+
media: VISUAL_ELEMENT_SIZES.xs.className,
|
|
20
|
+
thumbnail: "w-24"
|
|
21
|
+
},
|
|
22
|
+
md: {
|
|
23
|
+
height: CONTROL_SIZES.md.heightClassName,
|
|
24
|
+
padding: "px-space-1",
|
|
25
|
+
media: VISUAL_ELEMENT_SIZES.sm.className,
|
|
26
|
+
thumbnail: "w-32"
|
|
27
|
+
},
|
|
28
|
+
lg: {
|
|
29
|
+
height: "h-12",
|
|
30
|
+
padding: "px-space-2",
|
|
31
|
+
media: "size-9",
|
|
32
|
+
thumbnail: "w-40"
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
var Attachment = forwardRef(function Attachment({ name, contentType, icon, preview, metadata, variant = "file", size = "md", status = "ready", onOpen, openLabel = `View ${name}`, onRemove, actions, className, ...props }, ref) {
|
|
36
|
+
const statusId = useId();
|
|
37
|
+
const sizeStyles = SIZE_STYLES[size];
|
|
38
|
+
const isThumbnail = variant === "thumbnail";
|
|
39
|
+
const hasMediaBackground = isThumbnail || size !== "sm";
|
|
40
|
+
const stackedText = isThumbnail || size === "lg";
|
|
41
|
+
const isBusy = status === "loading" || status === "uploading";
|
|
42
|
+
const hasPreview = preview != null && status === "ready";
|
|
43
|
+
const description = status === "uploading" ? "Uploading…" : status === "loading" ? "Loading attachment…" : status === "error" ? "Upload failed." : void 0;
|
|
44
|
+
const removeButton = onRemove ? /* @__PURE__ */ jsx(IconButton, {
|
|
45
|
+
type: "button",
|
|
46
|
+
icon: XIcon,
|
|
47
|
+
iconWeight: "regular",
|
|
48
|
+
iconClassName: isThumbnail ? size === "sm" ? "size-2.5" : "size-3" : size === "sm" ? "size-3" : "size-3.5",
|
|
49
|
+
label: `Remove ${name}`,
|
|
50
|
+
color: "secondary",
|
|
51
|
+
variant: isThumbnail ? "normal" : "plain",
|
|
52
|
+
round: isThumbnail,
|
|
53
|
+
className: cn(isThumbnail && [
|
|
54
|
+
"absolute right-0 top-0",
|
|
55
|
+
"border-0 shadow-none hover:bg-elevated-hover",
|
|
56
|
+
"transition-opacity duration-fast motion-reduce:transition-none",
|
|
57
|
+
"[@media(hover:hover)]:group-[:not(:is(:hover,:focus-within))]/attachment:pointer-events-none",
|
|
58
|
+
"[@media(hover:hover)]:group-[:not(:is(:hover,:focus-within))]/attachment:opacity-0"
|
|
59
|
+
]),
|
|
60
|
+
size: size === "sm" ? "xxs" : size === "md" ? "xs" : "sm",
|
|
61
|
+
onClick: (event) => {
|
|
62
|
+
event.stopPropagation();
|
|
63
|
+
onRemove();
|
|
64
|
+
}
|
|
65
|
+
}) : null;
|
|
66
|
+
const media = hasPreview ? preview : /* @__PURE__ */ jsx(Icon, {
|
|
67
|
+
"aria-hidden": true,
|
|
68
|
+
icon: isBusy ? SpinnerIcon : status === "error" ? WarningCircleIcon : icon ?? getAttachmentIcon(contentType ?? null) ?? FileIcon,
|
|
69
|
+
size,
|
|
70
|
+
weight: "regular",
|
|
71
|
+
color: status === "error" ? "error" : hasMediaBackground ? "neutral" : void 0,
|
|
72
|
+
className: cn("rounded-xs", size === "sm" && sizeStyles.media, !hasMediaBackground && "bg-transparent dark:bg-transparent", status !== "error" && ["text-icon-secondary", hasMediaBackground && "bg-surface-level-2"])
|
|
73
|
+
});
|
|
74
|
+
const content = /* @__PURE__ */ jsxs("span", {
|
|
75
|
+
className: cn("flex min-w-0 flex-1 items-center", size === "sm" && !isThumbnail ? "gap-space-1" : "gap-space-2", isThumbnail && "w-full max-w-full flex-none flex-col items-stretch"),
|
|
76
|
+
children: [hasPreview || isThumbnail ? /* @__PURE__ */ jsx("span", {
|
|
77
|
+
"aria-hidden": true,
|
|
78
|
+
className: cn("flex shrink-0 items-center justify-center overflow-hidden rounded-xs [&>img]:size-full [&>img]:object-cover", isThumbnail && status === "error" ? "bg-error-subtle dark:bg-error" : hasMediaBackground && "bg-surface-level-2", isThumbnail ? "relative aspect-square w-full [&>img]:absolute [&>img]:inset-0" : sizeStyles.media),
|
|
79
|
+
children: media
|
|
80
|
+
}) : media, /* @__PURE__ */ jsxs("span", {
|
|
81
|
+
className: cn("flex min-w-0 flex-1", stackedText ? "flex-col gap-space-1" : "items-baseline gap-space-2", isThumbnail && "w-full max-w-full flex-none"),
|
|
82
|
+
children: [
|
|
83
|
+
/* @__PURE__ */ jsx(Text, {
|
|
84
|
+
as: "span",
|
|
85
|
+
dir: "rtl",
|
|
86
|
+
variant: size === "sm" ? "xs" : size === "md" ? "sm" : "md",
|
|
87
|
+
className: cn("min-w-0 max-w-48 truncate text-left text-primary", isThumbnail && "w-full max-w-full"),
|
|
88
|
+
title: name,
|
|
89
|
+
children: /* @__PURE__ */ jsx("bdi", {
|
|
90
|
+
dir: "ltr",
|
|
91
|
+
children: name
|
|
92
|
+
})
|
|
93
|
+
}),
|
|
94
|
+
metadata != null && !description && /* @__PURE__ */ jsx(Text, {
|
|
95
|
+
as: "span",
|
|
96
|
+
variant: "xs",
|
|
97
|
+
color: "quaternary",
|
|
98
|
+
className: cn("min-w-0 max-w-48 truncate", isThumbnail && "w-full max-w-full"),
|
|
99
|
+
title: typeof metadata === "string" ? metadata : void 0,
|
|
100
|
+
children: metadata
|
|
101
|
+
}),
|
|
102
|
+
/* @__PURE__ */ jsx("span", {
|
|
103
|
+
id: statusId,
|
|
104
|
+
role: "status",
|
|
105
|
+
"aria-live": "polite",
|
|
106
|
+
"aria-atomic": "true",
|
|
107
|
+
className: cn(description ? "min-w-0 max-w-full" : "sr-only", description && status === "error" && !stackedText && "max-w-[75%] shrink-0 grow"),
|
|
108
|
+
children: description && /* @__PURE__ */ jsxs(Text, {
|
|
109
|
+
as: "span",
|
|
110
|
+
variant: "xs",
|
|
111
|
+
title: description,
|
|
112
|
+
className: cn("block truncate text-tertiary", status === "error" && "text-error-secondary"),
|
|
113
|
+
children: [/* @__PURE__ */ jsxs("span", {
|
|
114
|
+
className: "sr-only",
|
|
115
|
+
children: [name, ": "]
|
|
116
|
+
}), description]
|
|
117
|
+
})
|
|
118
|
+
})
|
|
119
|
+
]
|
|
120
|
+
})]
|
|
121
|
+
});
|
|
122
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
123
|
+
ref,
|
|
124
|
+
role: "group",
|
|
125
|
+
"aria-label": name,
|
|
126
|
+
...props,
|
|
127
|
+
onClick: (event) => {
|
|
128
|
+
if (onOpen && event.target === event.currentTarget) {
|
|
129
|
+
event.stopPropagation();
|
|
130
|
+
onOpen();
|
|
131
|
+
}
|
|
132
|
+
},
|
|
133
|
+
className: cn("box-border flex min-w-0 max-w-full shrink-0 items-center gap-space-2 rounded-xs border border-subtle bg-surface-level-1", isThumbnail ? [
|
|
134
|
+
sizeStyles.thumbnail,
|
|
135
|
+
"group/attachment relative flex-col items-stretch",
|
|
136
|
+
size === "sm" ? "p-space-1" : "p-space-2"
|
|
137
|
+
] : [sizeStyles.height, sizeStyles.padding], status === "error" && "border-error", onOpen && "cursor-pointer", className),
|
|
138
|
+
children: [
|
|
139
|
+
onOpen ? /* @__PURE__ */ jsx(Button, {
|
|
140
|
+
type: "button",
|
|
141
|
+
color: "secondary",
|
|
142
|
+
variant: "plain",
|
|
143
|
+
"aria-label": openLabel,
|
|
144
|
+
"aria-describedby": description ? statusId : void 0,
|
|
145
|
+
className: cn("min-w-0 flex-1 justify-start p-0 text-left", isThumbnail ? "h-auto w-full max-w-full flex-none whitespace-normal" : "h-full"),
|
|
146
|
+
onClick: (event) => {
|
|
147
|
+
event.stopPropagation();
|
|
148
|
+
onOpen();
|
|
149
|
+
},
|
|
150
|
+
children: content
|
|
151
|
+
}) : content,
|
|
152
|
+
isThumbnail && removeButton,
|
|
153
|
+
(actions != null || !isThumbnail && onRemove) && /* @__PURE__ */ jsxs("fieldset", {
|
|
154
|
+
"aria-label": `Actions for ${name}`,
|
|
155
|
+
className: cn("m-0 flex min-w-0 max-w-full shrink-0 items-center justify-end gap-space-1 border-0 p-0", isThumbnail && "flex-wrap"),
|
|
156
|
+
onClick: (event) => event.stopPropagation(),
|
|
157
|
+
children: [actions, !isThumbnail && removeButton]
|
|
158
|
+
})
|
|
159
|
+
]
|
|
160
|
+
});
|
|
161
|
+
});
|
|
162
|
+
//#endregion
|
|
163
|
+
export { Attachment };
|
|
164
|
+
|
|
165
|
+
//# sourceMappingURL=Attachment.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Attachment.js","names":[],"sources":["../../../src/components/Attachment/Attachment.tsx"],"sourcesContent":["import type { ComponentPropsWithRef, ReactNode } from 'react';\nimport { forwardRef, useId } from 'react';\n\nimport { FileIcon } from '@phosphor-icons/react/dist/ssr/File';\nimport { WarningCircleIcon } from '@phosphor-icons/react/dist/ssr/WarningCircle';\nimport { XIcon } from '@phosphor-icons/react/dist/ssr/X';\n\nimport { cn } from '../../utils/cn';\nimport {\n CONTROL_SIZES,\n VISUAL_ELEMENT_SIZES,\n} from '../../utils/componentSizes';\nimport { Button } from '../Button';\nimport { Icon, type IconComponent } from '../Icon';\nimport { IconButton } from '../IconButton';\nimport { SpinnerIcon } from '../Spinner';\nimport { Text } from '../Text';\nimport { getAttachmentIcon } from './render-attachment-icon';\n\nexport interface AttachmentProps extends Omit<\n ComponentPropsWithRef<'div'>,\n 'children' | 'onClick'\n> {\n name: string;\n contentType?: string | null;\n icon?: IconComponent;\n /** Noninteractive thumbnail content. The consumer owns its source and lifecycle. */\n preview?: ReactNode;\n /** Secondary information, inline in compact rows and stacked in large rows. */\n metadata?: ReactNode;\n variant?: 'file' | 'thumbnail';\n /** File-row height: sm=24px, md=32px, lg=48px. Thumbnails use larger tiles. */\n size?: 'sm' | 'md' | 'lg';\n status?: 'ready' | 'loading' | 'uploading' | 'error';\n onOpen?: () => void;\n openLabel?: string;\n onRemove?: () => void;\n /** Sibling controls; use xs/sm/md buttons or smaller for sm/md/lg rows. */\n actions?: ReactNode;\n}\n\nconst SIZE_STYLES = {\n sm: {\n height: CONTROL_SIZES.sm.heightClassName,\n padding: 'px-space-1',\n media: VISUAL_ELEMENT_SIZES.xs.className,\n thumbnail: 'w-24',\n },\n md: {\n height: CONTROL_SIZES.md.heightClassName,\n padding: 'px-space-1',\n media: VISUAL_ELEMENT_SIZES.sm.className,\n thumbnail: 'w-32',\n },\n lg: {\n height: 'h-12',\n padding: 'px-space-2',\n media: 'size-9',\n thumbnail: 'w-40',\n },\n};\n\nexport const Attachment = forwardRef<HTMLDivElement, AttachmentProps>(\n function Attachment(\n {\n name,\n contentType,\n icon,\n preview,\n metadata,\n variant = 'file',\n size = 'md',\n status = 'ready',\n onOpen,\n openLabel = `View ${name}`,\n onRemove,\n actions,\n className,\n ...props\n },\n ref\n ) {\n const statusId = useId();\n const sizeStyles = SIZE_STYLES[size];\n const isThumbnail = variant === 'thumbnail';\n const hasMediaBackground = isThumbnail || size !== 'sm';\n const stackedText = isThumbnail || size === 'lg';\n const isBusy = status === 'loading' || status === 'uploading';\n const hasPreview = preview != null && status === 'ready';\n const description =\n status === 'uploading'\n ? 'Uploading…'\n : status === 'loading'\n ? 'Loading attachment…'\n : status === 'error'\n ? 'Upload failed.'\n : undefined;\n const removeButton = onRemove ? (\n <IconButton\n type=\"button\"\n icon={XIcon}\n iconWeight=\"regular\"\n iconClassName={\n isThumbnail\n ? size === 'sm'\n ? 'size-2.5'\n : 'size-3'\n : size === 'sm'\n ? 'size-3'\n : 'size-3.5'\n }\n label={`Remove ${name}`}\n color=\"secondary\"\n variant={isThumbnail ? 'normal' : 'plain'}\n round={isThumbnail}\n className={cn(\n isThumbnail && [\n 'absolute right-0 top-0',\n 'border-0 shadow-none hover:bg-elevated-hover',\n 'transition-opacity duration-fast motion-reduce:transition-none',\n '[@media(hover:hover)]:group-[:not(:is(:hover,:focus-within))]/attachment:pointer-events-none',\n '[@media(hover:hover)]:group-[:not(:is(:hover,:focus-within))]/attachment:opacity-0',\n ]\n )}\n size={size === 'sm' ? 'xxs' : size === 'md' ? 'xs' : 'sm'}\n onClick={(event) => {\n event.stopPropagation();\n onRemove();\n }}\n />\n ) : null;\n const media = hasPreview ? (\n preview\n ) : (\n <Icon\n aria-hidden\n icon={\n isBusy\n ? SpinnerIcon\n : status === 'error'\n ? WarningCircleIcon\n : (icon ?? getAttachmentIcon(contentType ?? null) ?? FileIcon)\n }\n size={size}\n weight=\"regular\"\n color={\n status === 'error'\n ? 'error'\n : hasMediaBackground\n ? 'neutral'\n : undefined\n }\n className={cn(\n 'rounded-xs',\n size === 'sm' && sizeStyles.media,\n !hasMediaBackground && 'bg-transparent dark:bg-transparent',\n status !== 'error' && [\n 'text-icon-secondary',\n hasMediaBackground && 'bg-surface-level-2',\n ]\n )}\n />\n );\n const content = (\n <span\n className={cn(\n 'flex min-w-0 flex-1 items-center',\n size === 'sm' && !isThumbnail ? 'gap-space-1' : 'gap-space-2',\n isThumbnail && 'w-full max-w-full flex-none flex-col items-stretch'\n )}\n >\n {hasPreview || isThumbnail ? (\n <span\n aria-hidden\n className={cn(\n 'flex shrink-0 items-center justify-center overflow-hidden rounded-xs [&>img]:size-full [&>img]:object-cover',\n isThumbnail && status === 'error'\n ? 'bg-error-subtle dark:bg-error'\n : hasMediaBackground && 'bg-surface-level-2',\n isThumbnail\n ? 'relative aspect-square w-full [&>img]:absolute [&>img]:inset-0'\n : sizeStyles.media\n )}\n >\n {media}\n </span>\n ) : (\n media\n )}\n <span\n className={cn(\n 'flex min-w-0 flex-1',\n stackedText ? 'flex-col gap-space-1' : 'items-baseline gap-space-2',\n isThumbnail && 'w-full max-w-full flex-none'\n )}\n >\n <Text\n as=\"span\"\n dir=\"rtl\"\n variant={size === 'sm' ? 'xs' : size === 'md' ? 'sm' : 'md'}\n className={cn(\n 'min-w-0 max-w-48 truncate text-left text-primary',\n isThumbnail && 'w-full max-w-full'\n )}\n title={name}\n >\n <bdi dir=\"ltr\">{name}</bdi>\n </Text>\n {metadata != null && !description && (\n <Text\n as=\"span\"\n variant=\"xs\"\n color=\"quaternary\"\n className={cn(\n 'min-w-0 max-w-48 truncate',\n isThumbnail && 'w-full max-w-full'\n )}\n title={typeof metadata === 'string' ? metadata : undefined}\n >\n {metadata}\n </Text>\n )}\n <span\n id={statusId}\n role=\"status\"\n aria-live=\"polite\"\n aria-atomic=\"true\"\n className={cn(\n description ? 'min-w-0 max-w-full' : 'sr-only',\n description &&\n status === 'error' &&\n !stackedText &&\n 'max-w-[75%] shrink-0 grow'\n )}\n >\n {description && (\n <Text\n as=\"span\"\n variant=\"xs\"\n title={description}\n className={cn(\n 'block truncate text-tertiary',\n status === 'error' && 'text-error-secondary'\n )}\n >\n <span className=\"sr-only\">{name}: </span>\n {description}\n </Text>\n )}\n </span>\n </span>\n </span>\n );\n\n return (\n <div\n ref={ref}\n role=\"group\"\n aria-label={name}\n {...props}\n onClick={(event) => {\n // Extend the preview button to the card's padding and gaps only.\n if (onOpen && event.target === event.currentTarget) {\n event.stopPropagation();\n onOpen();\n }\n }}\n className={cn(\n 'box-border flex min-w-0 max-w-full shrink-0 items-center gap-space-2 rounded-xs border border-subtle bg-surface-level-1',\n isThumbnail\n ? [\n sizeStyles.thumbnail,\n 'group/attachment relative flex-col items-stretch',\n size === 'sm' ? 'p-space-1' : 'p-space-2',\n ]\n : [sizeStyles.height, sizeStyles.padding],\n status === 'error' && 'border-error',\n onOpen && 'cursor-pointer',\n className\n )}\n >\n {onOpen ? (\n <Button\n type=\"button\"\n color=\"secondary\"\n variant=\"plain\"\n aria-label={openLabel}\n aria-describedby={description ? statusId : undefined}\n className={cn(\n 'min-w-0 flex-1 justify-start p-0 text-left',\n isThumbnail\n ? 'h-auto w-full max-w-full flex-none whitespace-normal'\n : 'h-full'\n )}\n onClick={(event) => {\n event.stopPropagation();\n onOpen();\n }}\n >\n {content}\n </Button>\n ) : (\n content\n )}\n {isThumbnail && removeButton}\n {(actions != null || (!isThumbnail && onRemove)) && (\n <fieldset\n aria-label={`Actions for ${name}`}\n className={cn(\n 'm-0 flex min-w-0 max-w-full shrink-0 items-center justify-end gap-space-1 border-0 p-0',\n isThumbnail && 'flex-wrap'\n )}\n onClick={(event) => event.stopPropagation()}\n >\n {actions}\n {!isThumbnail && removeButton}\n </fieldset>\n )}\n </div>\n );\n }\n);\n"],"mappings":"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"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { ComponentPropsWithRef } from 'react';
|
|
2
|
+
export interface AttachmentListProps extends ComponentPropsWithRef<'ul'> {
|
|
3
|
+
layout?: 'wrap' | 'scroll' | 'stack';
|
|
4
|
+
}
|
|
5
|
+
export declare const AttachmentList: import("react").ForwardRefExoticComponent<Omit<AttachmentListProps, "ref"> & import("react").RefAttributes<HTMLUListElement>>;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { cn } from "../../utils/cn.js";
|
|
2
|
+
import { Children, Fragment, forwardRef, isValidElement } from "react";
|
|
3
|
+
import { jsx } from "react/jsx-runtime";
|
|
4
|
+
//#region packages/components/src/components/Attachment/AttachmentList.tsx
|
|
5
|
+
function flattenAttachments(children, parentKeys = []) {
|
|
6
|
+
return Children.toArray(children).flatMap((child, index) => {
|
|
7
|
+
const keys = [...parentKeys, isValidElement(child) && child.key != null ? String(child.key) : String(index)];
|
|
8
|
+
if (isValidElement(child) && child.type === Fragment) return flattenAttachments(child.props.children, keys);
|
|
9
|
+
return [{
|
|
10
|
+
key: JSON.stringify(keys),
|
|
11
|
+
child
|
|
12
|
+
}];
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
var AttachmentList = forwardRef(function AttachmentList({ children, layout = "wrap", className, "aria-label": ariaLabel = "Attachments", ...props }, ref) {
|
|
16
|
+
const items = flattenAttachments(children);
|
|
17
|
+
if (items.length === 0) return null;
|
|
18
|
+
return /* @__PURE__ */ jsx("ul", {
|
|
19
|
+
...props,
|
|
20
|
+
ref,
|
|
21
|
+
"aria-label": ariaLabel,
|
|
22
|
+
className: cn("m-0 flex min-w-0 list-none gap-space-2 p-0", layout === "wrap" && "flex-wrap", layout === "scroll" && "overflow-x-auto overscroll-x-contain", layout === "stack" && "flex-col", className),
|
|
23
|
+
children: items.map(({ key, child }) => /* @__PURE__ */ jsx("li", {
|
|
24
|
+
className: cn("min-w-0 max-w-full", layout === "scroll" && "shrink-0"),
|
|
25
|
+
children: child
|
|
26
|
+
}, key))
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
//#endregion
|
|
30
|
+
export { AttachmentList };
|
|
31
|
+
|
|
32
|
+
//# sourceMappingURL=AttachmentList.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AttachmentList.js","names":[],"sources":["../../../src/components/Attachment/AttachmentList.tsx"],"sourcesContent":["import type { ComponentPropsWithRef, ReactNode } from 'react';\nimport { Children, Fragment, forwardRef, isValidElement } from 'react';\n\nimport { cn } from '../../utils/cn';\n\nexport interface AttachmentListProps extends ComponentPropsWithRef<'ul'> {\n layout?: 'wrap' | 'scroll' | 'stack';\n}\n\nfunction flattenAttachments(\n children: ReactNode,\n parentKeys: string[] = []\n): { key: string; child: ReactNode }[] {\n return Children.toArray(children).flatMap((child, index) => {\n const keys = [\n ...parentKeys,\n isValidElement(child) && child.key != null\n ? String(child.key)\n : String(index),\n ];\n if (\n isValidElement<{ children?: ReactNode }>(child) &&\n child.type === Fragment\n ) {\n return flattenAttachments(child.props.children, keys);\n }\n\n // Keep keys scoped to their fragments, even when sibling keys repeat.\n return [{ key: JSON.stringify(keys), child }];\n });\n}\n\nexport const AttachmentList = forwardRef<HTMLUListElement, AttachmentListProps>(\n function AttachmentList(\n {\n children,\n layout = 'wrap',\n className,\n 'aria-label': ariaLabel = 'Attachments',\n ...props\n },\n ref\n ) {\n const items = flattenAttachments(children);\n if (items.length === 0) {\n return null;\n }\n\n return (\n <ul\n {...props}\n ref={ref}\n aria-label={ariaLabel}\n className={cn(\n 'm-0 flex min-w-0 list-none gap-space-2 p-0',\n layout === 'wrap' && 'flex-wrap',\n layout === 'scroll' && 'overflow-x-auto overscroll-x-contain',\n layout === 'stack' && 'flex-col',\n className\n )}\n >\n {items.map(({ key, child }) => (\n <li\n key={key}\n className={cn(\n 'min-w-0 max-w-full',\n layout === 'scroll' && 'shrink-0'\n )}\n >\n {child}\n </li>\n ))}\n </ul>\n );\n }\n);\n"],"mappings":";;;;AASA,SAAS,mBACP,UACA,aAAuB,CAAC,GACa;CACrC,OAAO,SAAS,QAAQ,QAAQ,CAAC,CAAC,SAAS,OAAO,UAAU;EAC1D,MAAM,OAAO,CACX,GAAG,YACH,eAAe,KAAK,KAAK,MAAM,OAAO,OAClC,OAAO,MAAM,GAAG,IAChB,OAAO,KAAK,CAClB;EACA,IACE,eAAyC,KAAK,KAC9C,MAAM,SAAS,UAEf,OAAO,mBAAmB,MAAM,MAAM,UAAU,IAAI;EAItD,OAAO,CAAC;GAAE,KAAK,KAAK,UAAU,IAAI;GAAG;EAAM,CAAC;CAC9C,CAAC;AACH;AAEA,IAAa,iBAAiB,WAC5B,SAAS,eACP,EACE,UACA,SAAS,QACT,WACA,cAAc,YAAY,eAC1B,GAAG,SAEL,KACA;CACA,MAAM,QAAQ,mBAAmB,QAAQ;CACzC,IAAI,MAAM,WAAW,GACnB,OAAO;CAGT,OACE,oBAAC,MAAD;EACE,GAAI;EACC;EACL,cAAY;EACZ,WAAW,GACT,8CACA,WAAW,UAAU,aACrB,WAAW,YAAY,wCACvB,WAAW,WAAW,YACtB,SACF;EAEC,UAAA,MAAM,KAAK,EAAE,KAAK,YACjB,oBAAC,MAAD;GAEE,WAAW,GACT,sBACA,WAAW,YAAY,UACzB;GAEC,UAAA;EACC,GAPG,GAOH,CACL;CACC,CAAA;AAER,CACF"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { IconComponent } from '../../utils/icon-types.js';
|
|
2
|
+
export declare const getAttachmentIcon: (contentType: string | null) => IconComponent | null;
|
|
3
|
+
export declare const renderAttachmentIcon: (contentType: string | null, size: "small" | "default") => import("react").JSX.Element | null;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { cn } from "../../utils/cn.js";
|
|
2
2
|
import { VISUAL_ELEMENT_SIZES } from "../../utils/componentSizes.js";
|
|
3
|
-
import { getColorByString } from "../../utils/get-color-by-string.js";
|
|
4
3
|
import { Tooltip } from "../Tooltip/Tooltip.js";
|
|
4
|
+
import { getColorByString } from "../../utils/get-color-by-string.js";
|
|
5
5
|
import { forwardRef } from "react";
|
|
6
|
-
import { sanitizeUrl } from "@braintree/sanitize-url";
|
|
7
6
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
7
|
+
import { sanitizeUrl } from "@braintree/sanitize-url";
|
|
8
8
|
//#region packages/components/src/components/Avatar/Avatar.tsx
|
|
9
9
|
var BOX_SIZE = {
|
|
10
10
|
xxs: VISUAL_ELEMENT_SIZES.xxs.className,
|
|
@@ -19,6 +19,8 @@ interface BadgeProps extends React.HTMLAttributes<HTMLSpanElement> {
|
|
|
19
19
|
children?: string | ReactElement<SVGSVGElement>;
|
|
20
20
|
/** Font weight of text content */
|
|
21
21
|
textWeight?: TextProps['weight'];
|
|
22
|
+
/** Muted, normal-weight text after the content, e.g. a count. */
|
|
23
|
+
suffix?: string;
|
|
22
24
|
}
|
|
23
25
|
declare const Badge: import("react").ForwardRefExoticComponent<BadgeProps & import("react").RefAttributes<HTMLSpanElement>>;
|
|
24
26
|
export { Badge };
|
|
@@ -28,7 +28,7 @@ var SIZE_ICON_CLASSES = {
|
|
|
28
28
|
sm: "size-3",
|
|
29
29
|
md: "size-4"
|
|
30
30
|
};
|
|
31
|
-
var Badge = forwardRef(({ variant = "default", color, size, rounded = "full", leftDecorator: LeftIcon, rightDecorator: RightIcon, iconWeight, className, children, textWeight, ...props }, ref) => {
|
|
31
|
+
var Badge = forwardRef(({ variant = "default", color, size, rounded = "full", leftDecorator: LeftIcon, rightDecorator: RightIcon, iconWeight, className, children, textWeight, suffix, ...props }, ref) => {
|
|
32
32
|
const isString = typeof children === "string";
|
|
33
33
|
const isManifestPreview = variant === "manifestPreview";
|
|
34
34
|
const resolvedColor = color ?? (isManifestPreview ? "plain" : "secondary");
|
|
@@ -67,6 +67,17 @@ var Badge = forwardRef(({ variant = "default", color, size, rounded = "full", le
|
|
|
67
67
|
className: "tracking-tight",
|
|
68
68
|
children
|
|
69
69
|
}) : children,
|
|
70
|
+
suffix && /* @__PURE__ */ jsx("span", {
|
|
71
|
+
className: "sr-only",
|
|
72
|
+
children: ", "
|
|
73
|
+
}),
|
|
74
|
+
suffix && /* @__PURE__ */ jsx(Text, {
|
|
75
|
+
as: "span",
|
|
76
|
+
variant: SIZE_TEXT_VARIANT[resolvedSize],
|
|
77
|
+
weight: "normal",
|
|
78
|
+
className: "tracking-tight text-tertiary",
|
|
79
|
+
children: suffix
|
|
80
|
+
}),
|
|
70
81
|
RightIcon && /* @__PURE__ */ jsx(RightIcon, {
|
|
71
82
|
"aria-hidden": true,
|
|
72
83
|
className: cn(SIZE_ICON_CLASSES[resolvedSize], "flex-shrink-0"),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Badge.js","names":[],"sources":["../../../src/components/Badge/Badge.tsx"],"sourcesContent":["import type { ReactElement } from 'react';\nimport { forwardRef } from 'react';\n\nimport { cn } from '../../utils/cn';\nimport type { IconComponent, IconWeight } from '../../utils/icon-types';\nimport { Text, type TextProps } from '../Text';\n\n// Only allow string or SVG icon as children\ninterface BadgeProps extends React.HTMLAttributes<HTMLSpanElement> {\n /** Badge style preset */\n variant?: 'default' | 'manifestPreview';\n rounded?: 'full' | 'none' | 'xs' | 'sm';\n /** Badge color scheme */\n color?:\n | 'primary'\n | 'secondary'\n | 'success'\n | 'error'\n | 'warning'\n | 'special'\n | 'plain';\n /** Text-label height. */\n size?: 'xxs' | 'xs' | 'sm' | 'md';\n /** Left decorator icon */\n leftDecorator?: IconComponent;\n\n /** Right decorator icon */\n rightDecorator?: IconComponent;\n\n /** Phosphor weight used for decorator icons. */\n iconWeight?: IconWeight;\n\n /** Badge content */\n children?: string | ReactElement<SVGSVGElement>;\n\n /** Font weight of text content */\n textWeight?: TextProps['weight'];\n}\n\ntype BadgeSize = NonNullable<BadgeProps['size']>;\n\n/** Exact outer heights: xxs/xs=16px, sm=20px, md=24px. */\nconst SIZE_BOX_CLASSES: Record<BadgeSize, string> = {\n xxs: 'h-4 gap-space-1 px-space-1',\n xs: 'h-4 gap-space-1 px-space-1',\n sm: 'h-5 gap-space-1 px-space-1',\n md: 'h-6 gap-space-1 px-space-2',\n};\n\nconst SIZE_TEXT_VARIANT: Record<BadgeSize, 'xs' | 'sm'> = {\n xxs: 'xs',\n xs: 'xs',\n sm: 'sm',\n md: 'sm',\n};\n\nconst SIZE_DEFAULT_WEIGHT: Record<\n BadgeSize,\n NonNullable<TextProps['weight']>\n> = {\n xxs: 'normal',\n xs: 'medium',\n sm: 'medium',\n md: 'medium',\n};\n\nconst SIZE_ICON_CLASSES: Record<BadgeSize, string> = {\n xxs: 'size-3',\n xs: 'size-3',\n sm: 'size-3',\n md: 'size-4',\n};\n\nconst Badge = forwardRef<HTMLSpanElement, BadgeProps>(\n (\n {\n variant = 'default',\n color,\n size,\n rounded = 'full',\n leftDecorator: LeftIcon,\n rightDecorator: RightIcon,\n iconWeight,\n className,\n children,\n textWeight,\n ...props\n },\n ref\n ) => {\n const isString = typeof children === 'string';\n const isManifestPreview = variant === 'manifestPreview';\n const resolvedColor = color ?? (isManifestPreview ? 'plain' : 'secondary');\n const resolvedSize = size ?? (isManifestPreview ? 'sm' : 'md');\n const resolvedTextWeight = textWeight ?? SIZE_DEFAULT_WEIGHT[resolvedSize];\n const baseStyles = cn(\n 'box-border inline-flex items-center justify-center border border-transparent',\n SIZE_BOX_CLASSES[resolvedSize],\n {\n // TODO: we're only going to have 2 variants for the rounded prop. need to remove/rename the rounded prop\n 'rounded-xs':\n rounded === 'xs' || rounded === 'sm' || rounded === 'none',\n 'rounded-full': rounded === 'full',\n border: resolvedColor === 'plain',\n }\n );\n\n const getColorStyles = () => {\n switch (resolvedColor) {\n case 'primary':\n return 'bg-brand-secondary text-brand-primary';\n case 'success':\n return 'bg-success-secondary text-success-secondary';\n case 'error':\n return 'bg-error-secondary text-error-secondary';\n case 'warning':\n return 'bg-warning-secondary text-warning-secondary';\n case 'special':\n return 'bg-ls-acid-50 text-ls-acid-700 dark:bg-ls-acid-200';\n case 'plain':\n return 'bg-primary text-primary border-secondary';\n case 'secondary':\n default:\n return 'bg-tertiary text-secondary';\n }\n };\n\n return (\n <span\n ref={ref}\n className={cn(\n baseStyles,\n getColorStyles(),\n isManifestPreview &&\n 'min-w-0 max-w-full overflow-hidden whitespace-nowrap [&>span]:truncate',\n isManifestPreview && color == null && 'bg-transparent text-secondary',\n className\n )}\n {...props}\n >\n {LeftIcon && (\n <LeftIcon\n aria-hidden\n className={cn(SIZE_ICON_CLASSES[resolvedSize], 'flex-shrink-0')}\n weight={iconWeight}\n />\n )}\n {isString ? (\n <Text\n as=\"span\"\n variant={SIZE_TEXT_VARIANT[resolvedSize]}\n weight={resolvedTextWeight}\n className=\"tracking-tight\"\n >\n {children}\n </Text>\n ) : (\n children\n )}\n {RightIcon && (\n <RightIcon\n aria-hidden\n className={cn(SIZE_ICON_CLASSES[resolvedSize], 'flex-shrink-0')}\n weight={iconWeight}\n />\n )}\n </span>\n );\n }\n);\n\nBadge.displayName = 'Badge';\n\nexport { Badge };\nexport type { BadgeProps };\n"],"mappings":";;;;;;
|
|
1
|
+
{"version":3,"file":"Badge.js","names":[],"sources":["../../../src/components/Badge/Badge.tsx"],"sourcesContent":["import type { ReactElement } from 'react';\nimport { forwardRef } from 'react';\n\nimport { cn } from '../../utils/cn';\nimport type { IconComponent, IconWeight } from '../../utils/icon-types';\nimport { Text, type TextProps } from '../Text';\n\n// Only allow string or SVG icon as children\ninterface BadgeProps extends React.HTMLAttributes<HTMLSpanElement> {\n /** Badge style preset */\n variant?: 'default' | 'manifestPreview';\n rounded?: 'full' | 'none' | 'xs' | 'sm';\n /** Badge color scheme */\n color?:\n | 'primary'\n | 'secondary'\n | 'success'\n | 'error'\n | 'warning'\n | 'special'\n | 'plain';\n /** Text-label height. */\n size?: 'xxs' | 'xs' | 'sm' | 'md';\n /** Left decorator icon */\n leftDecorator?: IconComponent;\n\n /** Right decorator icon */\n rightDecorator?: IconComponent;\n\n /** Phosphor weight used for decorator icons. */\n iconWeight?: IconWeight;\n\n /** Badge content */\n children?: string | ReactElement<SVGSVGElement>;\n\n /** Font weight of text content */\n textWeight?: TextProps['weight'];\n\n /** Muted, normal-weight text after the content, e.g. a count. */\n suffix?: string;\n}\n\ntype BadgeSize = NonNullable<BadgeProps['size']>;\n\n/** Exact outer heights: xxs/xs=16px, sm=20px, md=24px. */\nconst SIZE_BOX_CLASSES: Record<BadgeSize, string> = {\n xxs: 'h-4 gap-space-1 px-space-1',\n xs: 'h-4 gap-space-1 px-space-1',\n sm: 'h-5 gap-space-1 px-space-1',\n md: 'h-6 gap-space-1 px-space-2',\n};\n\nconst SIZE_TEXT_VARIANT: Record<BadgeSize, 'xs' | 'sm'> = {\n xxs: 'xs',\n xs: 'xs',\n sm: 'sm',\n md: 'sm',\n};\n\nconst SIZE_DEFAULT_WEIGHT: Record<\n BadgeSize,\n NonNullable<TextProps['weight']>\n> = {\n xxs: 'normal',\n xs: 'medium',\n sm: 'medium',\n md: 'medium',\n};\n\nconst SIZE_ICON_CLASSES: Record<BadgeSize, string> = {\n xxs: 'size-3',\n xs: 'size-3',\n sm: 'size-3',\n md: 'size-4',\n};\n\nconst Badge = forwardRef<HTMLSpanElement, BadgeProps>(\n (\n {\n variant = 'default',\n color,\n size,\n rounded = 'full',\n leftDecorator: LeftIcon,\n rightDecorator: RightIcon,\n iconWeight,\n className,\n children,\n textWeight,\n suffix,\n ...props\n },\n ref\n ) => {\n const isString = typeof children === 'string';\n const isManifestPreview = variant === 'manifestPreview';\n const resolvedColor = color ?? (isManifestPreview ? 'plain' : 'secondary');\n const resolvedSize = size ?? (isManifestPreview ? 'sm' : 'md');\n const resolvedTextWeight = textWeight ?? SIZE_DEFAULT_WEIGHT[resolvedSize];\n const baseStyles = cn(\n 'box-border inline-flex items-center justify-center border border-transparent',\n SIZE_BOX_CLASSES[resolvedSize],\n {\n // TODO: we're only going to have 2 variants for the rounded prop. need to remove/rename the rounded prop\n 'rounded-xs':\n rounded === 'xs' || rounded === 'sm' || rounded === 'none',\n 'rounded-full': rounded === 'full',\n border: resolvedColor === 'plain',\n }\n );\n\n const getColorStyles = () => {\n switch (resolvedColor) {\n case 'primary':\n return 'bg-brand-secondary text-brand-primary';\n case 'success':\n return 'bg-success-secondary text-success-secondary';\n case 'error':\n return 'bg-error-secondary text-error-secondary';\n case 'warning':\n return 'bg-warning-secondary text-warning-secondary';\n case 'special':\n return 'bg-ls-acid-50 text-ls-acid-700 dark:bg-ls-acid-200';\n case 'plain':\n return 'bg-primary text-primary border-secondary';\n case 'secondary':\n default:\n return 'bg-tertiary text-secondary';\n }\n };\n\n return (\n <span\n ref={ref}\n className={cn(\n baseStyles,\n getColorStyles(),\n isManifestPreview &&\n 'min-w-0 max-w-full overflow-hidden whitespace-nowrap [&>span]:truncate',\n isManifestPreview && color == null && 'bg-transparent text-secondary',\n className\n )}\n {...props}\n >\n {LeftIcon && (\n <LeftIcon\n aria-hidden\n className={cn(SIZE_ICON_CLASSES[resolvedSize], 'flex-shrink-0')}\n weight={iconWeight}\n />\n )}\n {isString ? (\n <Text\n as=\"span\"\n variant={SIZE_TEXT_VARIANT[resolvedSize]}\n weight={resolvedTextWeight}\n className=\"tracking-tight\"\n >\n {children}\n </Text>\n ) : (\n children\n )}\n {suffix && <span className=\"sr-only\">, </span>}\n {suffix && (\n <Text\n as=\"span\"\n variant={SIZE_TEXT_VARIANT[resolvedSize]}\n weight=\"normal\"\n className=\"tracking-tight text-tertiary\"\n >\n {suffix}\n </Text>\n )}\n {RightIcon && (\n <RightIcon\n aria-hidden\n className={cn(SIZE_ICON_CLASSES[resolvedSize], 'flex-shrink-0')}\n weight={iconWeight}\n />\n )}\n </span>\n );\n }\n);\n\nBadge.displayName = 'Badge';\n\nexport { Badge };\nexport type { BadgeProps };\n"],"mappings":";;;;;;AA6CA,IAAM,mBAA8C;CAClD,KAAK;CACL,IAAI;CACJ,IAAI;CACJ,IAAI;AACN;AAEA,IAAM,oBAAoD;CACxD,KAAK;CACL,IAAI;CACJ,IAAI;CACJ,IAAI;AACN;AAEA,IAAM,sBAGF;CACF,KAAK;CACL,IAAI;CACJ,IAAI;CACJ,IAAI;AACN;AAEA,IAAM,oBAA+C;CACnD,KAAK;CACL,IAAI;CACJ,IAAI;CACJ,IAAI;AACN;AAEA,IAAM,QAAQ,YAEV,EACE,UAAU,WACV,OACA,MACA,UAAU,QACV,eAAe,UACf,gBAAgB,WAChB,YACA,WACA,UACA,YACA,QACA,GAAG,SAEL,QACG;CACH,MAAM,WAAW,OAAO,aAAa;CACrC,MAAM,oBAAoB,YAAY;CACtC,MAAM,gBAAgB,UAAU,oBAAoB,UAAU;CAC9D,MAAM,eAAe,SAAS,oBAAoB,OAAO;CACzD,MAAM,qBAAqB,cAAc,oBAAoB;CAC7D,MAAM,aAAa,GACjB,gFACA,iBAAiB,eACjB;EAEE,cACE,YAAY,QAAQ,YAAY,QAAQ,YAAY;EACtD,gBAAgB,YAAY;EAC5B,QAAQ,kBAAkB;CAC5B,CACF;CAEA,MAAM,uBAAuB;EAC3B,QAAQ,eAAR;GACE,KAAK,WACH,OAAO;GACT,KAAK,WACH,OAAO;GACT,KAAK,SACH,OAAO;GACT,KAAK,WACH,OAAO;GACT,KAAK,WACH,OAAO;GACT,KAAK,SACH,OAAO;GAET,SACE,OAAO;EACX;CACF;CAEA,OACE,qBAAC,QAAD;EACO;EACL,WAAW,GACT,YACA,eAAe,GACf,qBACE,0EACF,qBAAqB,SAAS,QAAQ,iCACtC,SACF;EACA,GAAI;EAVN,UAAA;GAYG,YACC,oBAAC,UAAD;IACE,eAAA;IACA,WAAW,GAAG,kBAAkB,eAAe,eAAe;IAC9D,QAAQ;GACT,CAAA;GAEF,WACC,oBAAC,MAAD;IACE,IAAG;IACH,SAAS,kBAAkB;IAC3B,QAAQ;IACR,WAAU;IAET;GACG,CAAA,IAEN;GAED,UAAU,oBAAC,QAAD;IAAM,WAAU;IAAU,UAAA;GAAQ,CAAA;GAC5C,UACC,oBAAC,MAAD;IACE,IAAG;IACH,SAAS,kBAAkB;IAC3B,QAAO;IACP,WAAU;IAET,UAAA;GACG,CAAA;GAEP,aACC,oBAAC,WAAD;IACE,eAAA;IACA,WAAW,GAAG,kBAAkB,eAAe,eAAe;IAC9D,QAAQ;GACT,CAAA;EAEC;;AAEV,CACF;AAEA,MAAM,cAAc"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { cn } from "../../utils/cn.js";
|
|
2
2
|
import { Text } from "../Text/Text.js";
|
|
3
|
-
import { XIcon } from "../../icons/PaddedPhosphorIcons.js";
|
|
4
3
|
import { Icon } from "../Icon/Icon.js";
|
|
5
4
|
import { IconButton } from "../IconButton/IconButton.js";
|
|
5
|
+
import { XIcon } from "../../icons/PaddedPhosphorIcons.js";
|
|
6
6
|
import { useState } from "react";
|
|
7
7
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
8
8
|
import { CheckCircleIcon } from "@phosphor-icons/react/dist/ssr/CheckCircle";
|
|
@@ -2,8 +2,8 @@ import { cn } from "../../utils/cn.js";
|
|
|
2
2
|
import { CONTROL_SIZES } from "../../utils/componentSizes.js";
|
|
3
3
|
import { Text } from "../Text/Text.js";
|
|
4
4
|
import { Badge } from "../Badge/Badge.js";
|
|
5
|
-
import { buttonStyleMap } from "./constants.js";
|
|
6
5
|
import { Spinner } from "../Spinner/Spinner.js";
|
|
6
|
+
import { buttonStyleMap } from "./constants.js";
|
|
7
7
|
import { cloneElement, forwardRef, isValidElement } from "react";
|
|
8
8
|
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
9
9
|
//#region packages/components/src/components/Button/Button.tsx
|
|
@@ -8,8 +8,8 @@ var buttonStyleMap = {
|
|
|
8
8
|
"primary-outlined-disabled": "bg-brand-muted border border-transparent text-brand-disabled",
|
|
9
9
|
"primary-plain-disabled": "bg-brand-muted border border-transparent text-brand-disabled",
|
|
10
10
|
"primary-underlined-disabled": "bg-transparent text-brand-disabled border border-transparent",
|
|
11
|
-
"secondary-normal-enabled": "bg-elevated text-secondary border border-subtle
|
|
12
|
-
"secondary-outlined-enabled": "bg-elevated text-secondary border border-subtle
|
|
11
|
+
"secondary-normal-enabled": "bg-elevated text-secondary border border-subtle hover:bg-elevated-hover/80",
|
|
12
|
+
"secondary-outlined-enabled": "bg-elevated text-secondary border border-subtle hover:bg-elevated-hover/80",
|
|
13
13
|
"secondary-plain-enabled": "bg-transparent text-secondary border border-transparent hover:bg-elevated-hover/80 dark:hover:bg-elevated-hover/40",
|
|
14
14
|
"secondary-underlined-enabled": "text-secondary hover:text-secondary-hover border-b button-secondary-underlined-border hover:button-secondary-underlined-border-hover",
|
|
15
15
|
"secondary-normal-disabled": "bg-surface-level-1-hover dark:bg-disabled border border-transparent text-disabled",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.js","names":[],"sources":["../../../src/components/Button/constants.ts"],"sourcesContent":["// Define styles for each specific combination\nexport const buttonStyleMap = {\n // Primary variants - enabled\n 'primary-normal-enabled':\n 'button-primary-bg button-primary-foreground border button-primary-border hover:border-transparent hover:button-primary-bg-hover dark:hover:button-primary-bg-hover dark:hover:border-transparent',\n 'primary-outlined-enabled':\n 'bg-transparent text-brand-secondary border border-brand-strong hover:text-brand-primary hover:bg-brand-muted dark:border-brand dark:hover:bg-brand-subtle dark:hover:button-primary-border dark:hover:text-brand-primary',\n 'primary-plain-enabled':\n 'bg-transparent text-brand-400 dark:text-brand-700 border border-transparent hover:text-brand-secondary dark:hover:text-brand-primary hover:bg-brand-muted/80',\n 'primary-underlined-enabled':\n 'bg-transparent button-primary-underlined-foreground border-b button-primary-underlined-border hover:button-primary-underlined-border-hover hover:button-primary-underlined-foreground-hover',\n\n // Primary variants - disabled\n 'primary-normal-disabled':\n 'bg-brand-muted border border-brand-disabled text-brand-disabled',\n 'primary-outlined-disabled':\n 'bg-brand-muted border border-transparent text-brand-disabled',\n 'primary-plain-disabled':\n 'bg-brand-muted border border-transparent text-brand-disabled',\n 'primary-underlined-disabled':\n 'bg-transparent text-brand-disabled border border-transparent',\n\n // Secondary variants - enabled\n 'secondary-normal-enabled':\n 'bg-elevated text-secondary border border-subtle
|
|
1
|
+
{"version":3,"file":"constants.js","names":[],"sources":["../../../src/components/Button/constants.ts"],"sourcesContent":["// Define styles for each specific combination\nexport const buttonStyleMap = {\n // Primary variants - enabled\n 'primary-normal-enabled':\n 'button-primary-bg button-primary-foreground border button-primary-border hover:border-transparent hover:button-primary-bg-hover dark:hover:button-primary-bg-hover dark:hover:border-transparent',\n 'primary-outlined-enabled':\n 'bg-transparent text-brand-secondary border border-brand-strong hover:text-brand-primary hover:bg-brand-muted dark:border-brand dark:hover:bg-brand-subtle dark:hover:button-primary-border dark:hover:text-brand-primary',\n 'primary-plain-enabled':\n 'bg-transparent text-brand-400 dark:text-brand-700 border border-transparent hover:text-brand-secondary dark:hover:text-brand-primary hover:bg-brand-muted/80',\n 'primary-underlined-enabled':\n 'bg-transparent button-primary-underlined-foreground border-b button-primary-underlined-border hover:button-primary-underlined-border-hover hover:button-primary-underlined-foreground-hover',\n\n // Primary variants - disabled\n 'primary-normal-disabled':\n 'bg-brand-muted border border-brand-disabled text-brand-disabled',\n 'primary-outlined-disabled':\n 'bg-brand-muted border border-transparent text-brand-disabled',\n 'primary-plain-disabled':\n 'bg-brand-muted border border-transparent text-brand-disabled',\n 'primary-underlined-disabled':\n 'bg-transparent text-brand-disabled border border-transparent',\n\n // Secondary variants - enabled\n 'secondary-normal-enabled':\n 'bg-elevated text-secondary border border-subtle hover:bg-elevated-hover/80',\n 'secondary-outlined-enabled':\n 'bg-elevated text-secondary border border-subtle hover:bg-elevated-hover/80',\n 'secondary-plain-enabled':\n 'bg-transparent text-secondary border border-transparent hover:bg-elevated-hover/80 dark:hover:bg-elevated-hover/40',\n 'secondary-underlined-enabled':\n 'text-secondary hover:text-secondary-hover border-b button-secondary-underlined-border hover:button-secondary-underlined-border-hover',\n\n // Secondary variants - disabled\n 'secondary-normal-disabled':\n 'bg-surface-level-1-hover dark:bg-disabled border border-transparent text-disabled',\n 'secondary-outlined-disabled':\n 'bg-surface-level-1-hover dark:bg-disabled border border-transparent text-disabled',\n 'secondary-plain-disabled':\n 'bg-surface-level-1-hover dark:bg-disabled border border-transparent text-disabled',\n 'secondary-underlined-disabled': 'text-disabled border border-transparent',\n\n // Error variants - enabled\n 'error-normal-enabled':\n 'bg-error-strong dark:bg-error-secondary text-white border border-red-600 hover:bg-red-700 dark:hover:bg-error',\n 'error-outlined-enabled':\n 'bg-transparent text-error-secondary border border-red-700 hover:bg-error',\n 'error-plain-enabled':\n 'bg-transparent text-error-secondary border border-transparent hover:bg-error/80',\n 'error-underlined-enabled':\n 'bg-transparent text-error-secondary border-b button-error-underlined-border hover:button-error-underlined-border-hover hover:button-error-underlined-foreground-hover',\n\n // Error variants - disabled\n 'error-normal-disabled':\n 'bg-error border border-transparent button-error-disabled-foreground',\n 'error-outlined-disabled':\n 'bg-transparent button-error-disabled-foreground border button-error-disabled-border',\n 'error-plain-disabled':\n 'bg-transparent button-error-disabled-foreground border border-transparent',\n 'error-underlined-disabled':\n 'bg-transparent button-error-disabled-foreground border border-transparent',\n};\n"],"mappings":";AACA,IAAa,iBAAiB;CAE5B,0BACE;CACF,4BACE;CACF,yBACE;CACF,8BACE;CAGF,2BACE;CACF,6BACE;CACF,0BACE;CACF,+BACE;CAGF,4BACE;CACF,8BACE;CACF,2BACE;CACF,gCACE;CAGF,6BACE;CACF,+BACE;CACF,4BACE;CACF,iCAAiC;CAGjC,wBACE;CACF,0BACE;CACF,uBACE;CACF,4BACE;CAGF,yBACE;CACF,2BACE;CACF,wBACE;CACF,6BACE;AACJ"}
|
|
@@ -9,10 +9,7 @@ export type ChartCardState = 'ready' | 'loading' | 'error';
|
|
|
9
9
|
export interface ChartCardProps extends Omit<HTMLAttributes<HTMLElement>, 'title'> {
|
|
10
10
|
/** Visible chart title rendered in the card header. */
|
|
11
11
|
title: ReactNode;
|
|
12
|
-
/**
|
|
13
|
-
* Optional secondary text rendered beneath the title. Truncated to a single
|
|
14
|
-
* line to match the title's overflow behavior.
|
|
15
|
-
*/
|
|
12
|
+
/** Optional secondary text rendered beneath the title. */
|
|
16
13
|
description?: ReactNode;
|
|
17
14
|
/** Visual state of the card. Fetching and retry behavior remain external. */
|
|
18
15
|
state?: ChartCardState;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { cn } from "../../utils/cn.js";
|
|
2
2
|
import { Text } from "../Text/Text.js";
|
|
3
|
-
import { DotsSixVerticalIcon, XCloseIcon } from "../../icons/PaddedPhosphorIcons.js";
|
|
4
3
|
import { IconButton } from "../IconButton/IconButton.js";
|
|
4
|
+
import { DotsSixVerticalIcon, XCloseIcon } from "../../icons/PaddedPhosphorIcons.js";
|
|
5
5
|
import { DropdownMenu, DropdownMenuContent, DropdownMenuTrigger } from "../DropdownMenu/DropdownMenu.js";
|
|
6
6
|
import { EmptyState } from "../EmptyState/EmptyState.js";
|
|
7
7
|
import { Skeleton } from "../Skeleton/Skeleton.js";
|
|
@@ -97,7 +97,7 @@ var ChartCard = forwardRef(({ title, description, children, state = "ready", ske
|
|
|
97
97
|
}), description != null && description !== "" && /* @__PURE__ */ jsx(Text, {
|
|
98
98
|
variant: "xs",
|
|
99
99
|
color: "quaternary",
|
|
100
|
-
className: "min-w-0
|
|
100
|
+
className: "min-w-0 break-words",
|
|
101
101
|
children: description
|
|
102
102
|
})]
|
|
103
103
|
})]
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ChartCard.js","names":[],"sources":["../../../src/components/ChartCard/ChartCard.tsx"],"sourcesContent":["import {\n forwardRef,\n useId,\n type ButtonHTMLAttributes,\n type HTMLAttributes,\n type ReactNode,\n} from 'react';\n\nimport { ArrowsInSimpleIcon } from '@phosphor-icons/react/dist/ssr/ArrowsInSimple';\nimport { ArrowsOutSimpleIcon } from '@phosphor-icons/react/dist/ssr/ArrowsOutSimple';\nimport { DotsThreeVerticalIcon } from '@phosphor-icons/react/dist/ssr/DotsThreeVertical';\nimport { WarningIcon } from '@phosphor-icons/react/dist/ssr/Warning';\n\nimport {\n DotsSixVerticalIcon,\n XCloseIcon,\n} from '../../icons/PaddedPhosphorIcons';\nimport { cn } from '../../utils/cn';\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuTrigger,\n} from '../DropdownMenu';\nimport { EmptyState } from '../EmptyState';\nimport { IconButton } from '../IconButton';\nimport { Skeleton } from '../Skeleton';\nimport { Text } from '../Text';\nimport {\n ChartCardSkeleton,\n type ChartCardSkeletonVariant,\n} from './ChartCardSkeleton';\n\nexport interface ChartCardActionButtonProps extends Omit<\n ButtonHTMLAttributes<HTMLButtonElement>,\n 'children' | 'color'\n> {\n /** Accessible label and tooltip text. */\n label?: string;\n}\n\nexport type ChartCardVariant = 'default' | 'full-width';\n\nexport type ChartCardState = 'ready' | 'loading' | 'error';\n\nconst ChartCardLoadingState = () => (\n <div\n role=\"status\"\n className=\"flex min-h-[13.5rem] flex-1 flex-col gap-space-2\"\n >\n <div className=\"relative min-h-0 flex-1\">\n <Skeleton className=\"size-full rounded-md\" />\n <Text\n variant=\"sm\"\n color=\"placeholder\"\n className=\"absolute inset-0 flex items-center justify-center\"\n >\n Loading...\n </Text>\n </div>\n <div aria-hidden=\"true\" className=\"flex min-w-0 items-center gap-space-2\">\n <Skeleton className=\"h-4 w-20\" />\n <Skeleton className=\"h-4 w-24\" />\n <Skeleton className=\"h-4 w-40\" />\n <Skeleton className=\"h-4 w-12\" />\n </div>\n </div>\n);\n\nconst ChartCardErrorState = () => (\n <div role=\"alert\" className=\"flex min-h-0 flex-1 rounded-md\">\n <EmptyState\n icon={WarningIcon}\n iconWeight=\"fill\"\n title=\"There was an error while loading the chart.\"\n description=\"Refresh the page to try again.\"\n className=\"flex-1\"\n size=\"sm\"\n />\n </div>\n);\n\nexport interface ChartCardProps extends Omit<\n HTMLAttributes<HTMLElement>,\n 'title'\n> {\n /** Visible chart title rendered in the card header. */\n title: ReactNode;\n /**\n * Optional secondary text rendered beneath the title. Truncated to a single\n * line to match the title's overflow behavior.\n */\n description?: ReactNode;\n /** Visual state of the card. Fetching and retry behavior remain external. */\n state?: ChartCardState;\n /** Chart-shaped loading state. Omit for the generic placeholder. */\n skeletonVariant?: ChartCardSkeletonVariant;\n /** Size the loading plot to match a compact or fixed-height chart. */\n skeletonClassName?: string;\n /** Layout state for the card. Full-width cards hide their move handle. */\n variant?: ChartCardVariant;\n /** Whether to show the chart's move handle. Requires dragHandleProps. */\n isMovable?: boolean;\n /**\n * Props for the move handle. Pass the listeners and attributes from the\n * dashboard's drag-and-drop implementation; the card owns only the visual\n * affordance.\n */\n dragHandleProps?: ChartCardActionButtonProps;\n /** Props for the optional expand button. Expansion state remains external. */\n expandButtonProps?: ChartCardActionButtonProps;\n /** Props for the optional close button. Closing behavior remains external. */\n closeButtonProps?: ChartCardActionButtonProps;\n /** Feature-owned controls rendered in the top-right header action area. */\n headerActions?: ReactNode;\n /**\n * Feature-owned menu items rendered inside the card's overflow menu. The\n * card supplies the trigger, positioning, and menu surface.\n */\n menuItems?: ReactNode;\n /** Classes applied to the chart-and-legend content region. */\n contentClassName?: string;\n}\n\n/**\n * A lightweight, chart-library-agnostic container for dashboard\n * visualizations. ChartCard standardizes the shell and header actions while\n * leaving data fetching, chart rendering, drag behavior, and expansion\n * behavior to the consuming feature.\n */\nexport const ChartCard = forwardRef<HTMLElement, ChartCardProps>(\n (\n {\n title,\n description,\n children,\n state = 'ready',\n skeletonVariant,\n skeletonClassName,\n variant = 'default',\n isMovable = false,\n dragHandleProps,\n expandButtonProps,\n closeButtonProps,\n headerActions,\n menuItems,\n className,\n contentClassName,\n 'aria-labelledby': ariaLabelledBy,\n 'aria-busy': ariaBusy,\n ...props\n },\n ref\n ) => {\n const titleId = useId();\n const isFullWidth = variant === 'full-width';\n const isLoading = state === 'loading';\n const showDragHandle =\n isMovable && dragHandleProps != null && !isFullWidth && !isLoading;\n\n const {\n label: dragHandleLabel = 'Move chart',\n className: dragHandleClassName,\n onClick: onDragHandleClick,\n ...dragButtonProps\n } = dragHandleProps ?? {};\n const {\n label: expandButtonLabel = isFullWidth\n ? 'Minimize chart'\n : 'Expand chart',\n className: expandButtonClassName,\n onClick: onExpandClick,\n ...expandActionProps\n } = expandButtonProps ?? {};\n const {\n label: closeButtonLabel = 'Close chart',\n className: closeButtonClassName,\n onClick: onCloseClick,\n ...closeActionProps\n } = closeButtonProps ?? {};\n\n return (\n <section\n ref={ref}\n aria-labelledby={ariaLabelledBy ?? titleId}\n aria-busy={ariaBusy ?? (isLoading || undefined)}\n className={cn(\n 'flex min-w-0 flex-col overflow-hidden border border-muted bg-surface-level-1',\n isFullWidth && 'w-full',\n className\n )}\n {...props}\n >\n <div className=\"flex min-w-0 items-center justify-between gap-space-3 pl-space-3 pr-space-2 pt-space-2\">\n <div className=\"flex min-w-0 flex-1 items-center\">\n {showDragHandle && (\n <IconButton\n {...dragButtonProps}\n icon={DotsSixVerticalIcon}\n iconWeight=\"regular\"\n label={dragHandleLabel}\n size=\"xs\"\n variant=\"plain\"\n color=\"secondary\"\n iconClassName=\"size-4 text-icon-primary\"\n className={cn(\n 'cursor-grab touch-none active:cursor-grabbing',\n dragHandleClassName\n )}\n onClick={(event) => {\n event.stopPropagation();\n onDragHandleClick?.(event);\n }}\n />\n )}\n <div className=\"flex min-w-0 flex-1 flex-col gap-space-1\">\n <Text\n id={titleId}\n as=\"h3\"\n variant=\"sm\"\n weight=\"semibold\"\n className=\"min-w-0 truncate\"\n >\n {title}\n </Text>\n {description != null && description !== '' && (\n <Text\n variant=\"xs\"\n color=\"quaternary\"\n className=\"min-w-0 truncate\"\n >\n {description}\n </Text>\n )}\n </div>\n </div>\n\n {!isLoading && (\n <div\n className={cn(\n 'flex shrink-0 items-center',\n Boolean(headerActions) && 'gap-space-1'\n )}\n >\n {!!headerActions && (\n <div className=\"flex items-center pr-space-1\">\n {headerActions}\n </div>\n )}\n {expandButtonProps != null && (\n <IconButton\n {...expandActionProps}\n icon={isFullWidth ? ArrowsInSimpleIcon : ArrowsOutSimpleIcon}\n label={expandButtonLabel}\n size=\"xs\"\n variant=\"plain\"\n color=\"secondary\"\n iconClassName=\"size-4 text-icon-primary\"\n className={expandButtonClassName}\n onClick={(event) => {\n event.stopPropagation();\n onExpandClick?.(event);\n }}\n />\n )}\n {!!menuItems && (\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <IconButton\n icon={DotsThreeVerticalIcon}\n iconWeight=\"regular\"\n label=\"More chart actions\"\n size=\"xs\"\n variant=\"plain\"\n color=\"secondary\"\n iconClassName=\"size-4 text-icon-primary\"\n onClick={(event) => event.stopPropagation()}\n />\n </DropdownMenuTrigger>\n <DropdownMenuContent\n align=\"end\"\n preventClickThrough\n onClick={(event) => event.stopPropagation()}\n >\n {menuItems}\n </DropdownMenuContent>\n </DropdownMenu>\n )}\n {closeButtonProps != null && (\n <IconButton\n {...closeActionProps}\n icon={XCloseIcon}\n label={closeButtonLabel}\n size=\"xs\"\n variant=\"plain\"\n color=\"secondary\"\n iconClassName=\"text-icon-primary\"\n className={closeButtonClassName}\n onClick={(event) => {\n event.stopPropagation();\n onCloseClick?.(event);\n }}\n />\n )}\n </div>\n )}\n </div>\n\n <div\n className={cn(\n 'flex min-h-0 flex-1 flex-col gap-space-2 px-space-3 py-space-2',\n contentClassName\n )}\n >\n {state === 'loading' ? (\n skeletonVariant ? (\n <ChartCardSkeleton\n variant={skeletonVariant}\n className={skeletonClassName}\n />\n ) : (\n <ChartCardLoadingState />\n )\n ) : state === 'error' ? (\n <ChartCardErrorState />\n ) : (\n children\n )}\n </div>\n </section>\n );\n }\n);\n\nChartCard.displayName = 'ChartCard';\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ChartCard.js","names":[],"sources":["../../../src/components/ChartCard/ChartCard.tsx"],"sourcesContent":["import {\n forwardRef,\n useId,\n type ButtonHTMLAttributes,\n type HTMLAttributes,\n type ReactNode,\n} from 'react';\n\nimport { ArrowsInSimpleIcon } from '@phosphor-icons/react/dist/ssr/ArrowsInSimple';\nimport { ArrowsOutSimpleIcon } from '@phosphor-icons/react/dist/ssr/ArrowsOutSimple';\nimport { DotsThreeVerticalIcon } from '@phosphor-icons/react/dist/ssr/DotsThreeVertical';\nimport { WarningIcon } from '@phosphor-icons/react/dist/ssr/Warning';\n\nimport {\n DotsSixVerticalIcon,\n XCloseIcon,\n} from '../../icons/PaddedPhosphorIcons';\nimport { cn } from '../../utils/cn';\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuTrigger,\n} from '../DropdownMenu';\nimport { EmptyState } from '../EmptyState';\nimport { IconButton } from '../IconButton';\nimport { Skeleton } from '../Skeleton';\nimport { Text } from '../Text';\nimport {\n ChartCardSkeleton,\n type ChartCardSkeletonVariant,\n} from './ChartCardSkeleton';\n\nexport interface ChartCardActionButtonProps extends Omit<\n ButtonHTMLAttributes<HTMLButtonElement>,\n 'children' | 'color'\n> {\n /** Accessible label and tooltip text. */\n label?: string;\n}\n\nexport type ChartCardVariant = 'default' | 'full-width';\n\nexport type ChartCardState = 'ready' | 'loading' | 'error';\n\nconst ChartCardLoadingState = () => (\n <div\n role=\"status\"\n className=\"flex min-h-[13.5rem] flex-1 flex-col gap-space-2\"\n >\n <div className=\"relative min-h-0 flex-1\">\n <Skeleton className=\"size-full rounded-md\" />\n <Text\n variant=\"sm\"\n color=\"placeholder\"\n className=\"absolute inset-0 flex items-center justify-center\"\n >\n Loading...\n </Text>\n </div>\n <div aria-hidden=\"true\" className=\"flex min-w-0 items-center gap-space-2\">\n <Skeleton className=\"h-4 w-20\" />\n <Skeleton className=\"h-4 w-24\" />\n <Skeleton className=\"h-4 w-40\" />\n <Skeleton className=\"h-4 w-12\" />\n </div>\n </div>\n);\n\nconst ChartCardErrorState = () => (\n <div role=\"alert\" className=\"flex min-h-0 flex-1 rounded-md\">\n <EmptyState\n icon={WarningIcon}\n iconWeight=\"fill\"\n title=\"There was an error while loading the chart.\"\n description=\"Refresh the page to try again.\"\n className=\"flex-1\"\n size=\"sm\"\n />\n </div>\n);\n\nexport interface ChartCardProps extends Omit<\n HTMLAttributes<HTMLElement>,\n 'title'\n> {\n /** Visible chart title rendered in the card header. */\n title: ReactNode;\n /** Optional secondary text rendered beneath the title. */\n description?: ReactNode;\n /** Visual state of the card. Fetching and retry behavior remain external. */\n state?: ChartCardState;\n /** Chart-shaped loading state. Omit for the generic placeholder. */\n skeletonVariant?: ChartCardSkeletonVariant;\n /** Size the loading plot to match a compact or fixed-height chart. */\n skeletonClassName?: string;\n /** Layout state for the card. Full-width cards hide their move handle. */\n variant?: ChartCardVariant;\n /** Whether to show the chart's move handle. Requires dragHandleProps. */\n isMovable?: boolean;\n /**\n * Props for the move handle. Pass the listeners and attributes from the\n * dashboard's drag-and-drop implementation; the card owns only the visual\n * affordance.\n */\n dragHandleProps?: ChartCardActionButtonProps;\n /** Props for the optional expand button. Expansion state remains external. */\n expandButtonProps?: ChartCardActionButtonProps;\n /** Props for the optional close button. Closing behavior remains external. */\n closeButtonProps?: ChartCardActionButtonProps;\n /** Feature-owned controls rendered in the top-right header action area. */\n headerActions?: ReactNode;\n /**\n * Feature-owned menu items rendered inside the card's overflow menu. The\n * card supplies the trigger, positioning, and menu surface.\n */\n menuItems?: ReactNode;\n /** Classes applied to the chart-and-legend content region. */\n contentClassName?: string;\n}\n\n/**\n * A lightweight, chart-library-agnostic container for dashboard\n * visualizations. ChartCard standardizes the shell and header actions while\n * leaving data fetching, chart rendering, drag behavior, and expansion\n * behavior to the consuming feature.\n */\nexport const ChartCard = forwardRef<HTMLElement, ChartCardProps>(\n (\n {\n title,\n description,\n children,\n state = 'ready',\n skeletonVariant,\n skeletonClassName,\n variant = 'default',\n isMovable = false,\n dragHandleProps,\n expandButtonProps,\n closeButtonProps,\n headerActions,\n menuItems,\n className,\n contentClassName,\n 'aria-labelledby': ariaLabelledBy,\n 'aria-busy': ariaBusy,\n ...props\n },\n ref\n ) => {\n const titleId = useId();\n const isFullWidth = variant === 'full-width';\n const isLoading = state === 'loading';\n const showDragHandle =\n isMovable && dragHandleProps != null && !isFullWidth && !isLoading;\n\n const {\n label: dragHandleLabel = 'Move chart',\n className: dragHandleClassName,\n onClick: onDragHandleClick,\n ...dragButtonProps\n } = dragHandleProps ?? {};\n const {\n label: expandButtonLabel = isFullWidth\n ? 'Minimize chart'\n : 'Expand chart',\n className: expandButtonClassName,\n onClick: onExpandClick,\n ...expandActionProps\n } = expandButtonProps ?? {};\n const {\n label: closeButtonLabel = 'Close chart',\n className: closeButtonClassName,\n onClick: onCloseClick,\n ...closeActionProps\n } = closeButtonProps ?? {};\n\n return (\n <section\n ref={ref}\n aria-labelledby={ariaLabelledBy ?? titleId}\n aria-busy={ariaBusy ?? (isLoading || undefined)}\n className={cn(\n 'flex min-w-0 flex-col overflow-hidden border border-muted bg-surface-level-1',\n isFullWidth && 'w-full',\n className\n )}\n {...props}\n >\n <div className=\"flex min-w-0 items-center justify-between gap-space-3 pl-space-3 pr-space-2 pt-space-2\">\n <div className=\"flex min-w-0 flex-1 items-center\">\n {showDragHandle && (\n <IconButton\n {...dragButtonProps}\n icon={DotsSixVerticalIcon}\n iconWeight=\"regular\"\n label={dragHandleLabel}\n size=\"xs\"\n variant=\"plain\"\n color=\"secondary\"\n iconClassName=\"size-4 text-icon-primary\"\n className={cn(\n 'cursor-grab touch-none active:cursor-grabbing',\n dragHandleClassName\n )}\n onClick={(event) => {\n event.stopPropagation();\n onDragHandleClick?.(event);\n }}\n />\n )}\n <div className=\"flex min-w-0 flex-1 flex-col gap-space-1\">\n <Text\n id={titleId}\n as=\"h3\"\n variant=\"sm\"\n weight=\"semibold\"\n className=\"min-w-0 truncate\"\n >\n {title}\n </Text>\n {description != null && description !== '' && (\n <Text\n variant=\"xs\"\n color=\"quaternary\"\n className=\"min-w-0 break-words\"\n >\n {description}\n </Text>\n )}\n </div>\n </div>\n\n {!isLoading && (\n <div\n className={cn(\n 'flex shrink-0 items-center',\n Boolean(headerActions) && 'gap-space-1'\n )}\n >\n {!!headerActions && (\n <div className=\"flex items-center pr-space-1\">\n {headerActions}\n </div>\n )}\n {expandButtonProps != null && (\n <IconButton\n {...expandActionProps}\n icon={isFullWidth ? ArrowsInSimpleIcon : ArrowsOutSimpleIcon}\n label={expandButtonLabel}\n size=\"xs\"\n variant=\"plain\"\n color=\"secondary\"\n iconClassName=\"size-4 text-icon-primary\"\n className={expandButtonClassName}\n onClick={(event) => {\n event.stopPropagation();\n onExpandClick?.(event);\n }}\n />\n )}\n {!!menuItems && (\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <IconButton\n icon={DotsThreeVerticalIcon}\n iconWeight=\"regular\"\n label=\"More chart actions\"\n size=\"xs\"\n variant=\"plain\"\n color=\"secondary\"\n iconClassName=\"size-4 text-icon-primary\"\n onClick={(event) => event.stopPropagation()}\n />\n </DropdownMenuTrigger>\n <DropdownMenuContent\n align=\"end\"\n preventClickThrough\n onClick={(event) => event.stopPropagation()}\n >\n {menuItems}\n </DropdownMenuContent>\n </DropdownMenu>\n )}\n {closeButtonProps != null && (\n <IconButton\n {...closeActionProps}\n icon={XCloseIcon}\n label={closeButtonLabel}\n size=\"xs\"\n variant=\"plain\"\n color=\"secondary\"\n iconClassName=\"text-icon-primary\"\n className={closeButtonClassName}\n onClick={(event) => {\n event.stopPropagation();\n onCloseClick?.(event);\n }}\n />\n )}\n </div>\n )}\n </div>\n\n <div\n className={cn(\n 'flex min-h-0 flex-1 flex-col gap-space-2 px-space-3 py-space-2',\n contentClassName\n )}\n >\n {state === 'loading' ? (\n skeletonVariant ? (\n <ChartCardSkeleton\n variant={skeletonVariant}\n className={skeletonClassName}\n />\n ) : (\n <ChartCardLoadingState />\n )\n ) : state === 'error' ? (\n <ChartCardErrorState />\n ) : (\n children\n )}\n </div>\n </section>\n );\n }\n);\n\nChartCard.displayName = 'ChartCard';\n"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { CSSProperties } from 'react';
|
|
2
|
-
export type ChartCardSkeletonVariant = 'bar' | 'line' | 'donut' | 'metric' | 'sparkline';
|
|
2
|
+
export type ChartCardSkeletonVariant = 'bar' | 'line' | 'donut' | 'metric' | 'sparkline' | 'sankey';
|
|
3
3
|
export declare const ChartCardSkeleton: ({ variant, className, style, }: {
|
|
4
4
|
variant: ChartCardSkeletonVariant;
|
|
5
5
|
className?: string;
|
|
@@ -48,6 +48,43 @@ var ChartCardSkeleton = ({ variant, className, style }) => /* @__PURE__ */ jsxs(
|
|
|
48
48
|
className: "flex min-h-0 flex-1 items-center justify-center",
|
|
49
49
|
children: /* @__PURE__ */ jsx("div", { className: "size-32 animate-pulse rounded-full border-[1.5rem] border-muted motion-reduce:animate-none" })
|
|
50
50
|
}),
|
|
51
|
+
variant === "sankey" && /* @__PURE__ */ jsx("div", {
|
|
52
|
+
"aria-hidden": "true",
|
|
53
|
+
className: "relative min-h-0 flex-1",
|
|
54
|
+
children: /* @__PURE__ */ jsxs("svg", {
|
|
55
|
+
viewBox: "0 0 400 192",
|
|
56
|
+
preserveAspectRatio: "none",
|
|
57
|
+
focusable: "false",
|
|
58
|
+
fill: "var(--bg-surface-level-3)",
|
|
59
|
+
className: "absolute inset-0 size-full animate-pulse motion-reduce:animate-none",
|
|
60
|
+
children: [/* @__PURE__ */ jsx("g", {
|
|
61
|
+
opacity: .5,
|
|
62
|
+
children: [0, 184].map((offset) => /* @__PURE__ */ jsxs("g", {
|
|
63
|
+
transform: `translate(${offset} 0)`,
|
|
64
|
+
children: [
|
|
65
|
+
/* @__PURE__ */ jsx("path", { d: "M20 12H196V60H20Z" }),
|
|
66
|
+
/* @__PURE__ */ jsx("path", { d: "M20 60C108 60 108 108 196 108V132C108 132 108 84 20 84Z" }),
|
|
67
|
+
/* @__PURE__ */ jsx("path", { d: "M20 108C108 108 108 60 196 60V84C108 84 108 132 20 132Z" }),
|
|
68
|
+
/* @__PURE__ */ jsx("path", { d: "M20 132H196V180H20Z" })
|
|
69
|
+
]
|
|
70
|
+
}, offset))
|
|
71
|
+
}), [
|
|
72
|
+
12,
|
|
73
|
+
196,
|
|
74
|
+
380
|
|
75
|
+
].map((x) => /* @__PURE__ */ jsxs("g", { children: [/* @__PURE__ */ jsx("rect", {
|
|
76
|
+
x,
|
|
77
|
+
y: 12,
|
|
78
|
+
width: 8,
|
|
79
|
+
height: 72
|
|
80
|
+
}), /* @__PURE__ */ jsx("rect", {
|
|
81
|
+
x,
|
|
82
|
+
y: 108,
|
|
83
|
+
width: 8,
|
|
84
|
+
height: 72
|
|
85
|
+
})] }, x))]
|
|
86
|
+
})
|
|
87
|
+
}),
|
|
51
88
|
variant === "metric" && /* @__PURE__ */ jsxs("div", {
|
|
52
89
|
className: "flex min-h-0 flex-1 flex-col justify-center gap-space-2",
|
|
53
90
|
children: [/* @__PURE__ */ jsx(Skeleton, { className: "h-9 w-1/2 motion-reduce:animate-none" }), /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-2/3 motion-reduce:animate-none" })]
|