@uisatin/ui 0.0.0-stage → 0.1.0
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 -0
- package/README.md +67 -2
- package/chunk-2HKBZFIK.js +339 -0
- package/chunk-2HKBZFIK.js.map +1 -0
- package/chunk-2YEWSJD7.js +95 -0
- package/chunk-2YEWSJD7.js.map +1 -0
- package/chunk-3DINAQLL.js +153 -0
- package/chunk-3DINAQLL.js.map +1 -0
- package/chunk-3ERGAHKA.js +179 -0
- package/chunk-3ERGAHKA.js.map +1 -0
- package/chunk-6C7CGJX2.js +86 -0
- package/chunk-6C7CGJX2.js.map +1 -0
- package/chunk-6YXUBP27.js +474 -0
- package/chunk-6YXUBP27.js.map +1 -0
- package/chunk-72OCFAPT.js +175 -0
- package/chunk-72OCFAPT.js.map +1 -0
- package/chunk-7TXHCRAG.js +51 -0
- package/chunk-7TXHCRAG.js.map +1 -0
- package/chunk-A5XEM3GF.js +260 -0
- package/chunk-A5XEM3GF.js.map +1 -0
- package/chunk-AN2RNJLR.js +79 -0
- package/chunk-AN2RNJLR.js.map +1 -0
- package/chunk-B2K45IUR.js +36 -0
- package/chunk-B2K45IUR.js.map +1 -0
- package/chunk-B6V4VSGH.js +82 -0
- package/chunk-B6V4VSGH.js.map +1 -0
- package/chunk-BKZBWPUH.js +59 -0
- package/chunk-BKZBWPUH.js.map +1 -0
- package/chunk-BNTPPZCK.js +220 -0
- package/chunk-BNTPPZCK.js.map +1 -0
- package/chunk-BNZVTLHV.js +98 -0
- package/chunk-BNZVTLHV.js.map +1 -0
- package/chunk-CL2II6BX.js +89 -0
- package/chunk-CL2II6BX.js.map +1 -0
- package/chunk-DETGJAIC.js +147 -0
- package/chunk-DETGJAIC.js.map +1 -0
- package/chunk-DO3TBNSC.js +130 -0
- package/chunk-DO3TBNSC.js.map +1 -0
- package/chunk-ESC5JCVQ.js +90 -0
- package/chunk-ESC5JCVQ.js.map +1 -0
- package/chunk-FDKIX4DC.js +55 -0
- package/chunk-FDKIX4DC.js.map +1 -0
- package/chunk-GICKPMJU.js +239 -0
- package/chunk-GICKPMJU.js.map +1 -0
- package/chunk-GQA24FYG.js +57 -0
- package/chunk-GQA24FYG.js.map +1 -0
- package/chunk-H4NU7NPO.js +264 -0
- package/chunk-H4NU7NPO.js.map +1 -0
- package/chunk-H63FYCMY.js +11 -0
- package/chunk-H63FYCMY.js.map +1 -0
- package/chunk-HL42K2NH.js +76 -0
- package/chunk-HL42K2NH.js.map +1 -0
- package/chunk-HNQUX43Z.js +109 -0
- package/chunk-HNQUX43Z.js.map +1 -0
- package/chunk-HRKPV66B.js +32 -0
- package/chunk-HRKPV66B.js.map +1 -0
- package/chunk-J3NSDRVH.js +83 -0
- package/chunk-J3NSDRVH.js.map +1 -0
- package/chunk-JPNWHWAQ.js +151 -0
- package/chunk-JPNWHWAQ.js.map +1 -0
- package/chunk-KNUWZNFV.js +240 -0
- package/chunk-KNUWZNFV.js.map +1 -0
- package/chunk-L6NCCSIP.js +213 -0
- package/chunk-L6NCCSIP.js.map +1 -0
- package/chunk-LLHTVIM3.js +50 -0
- package/chunk-LLHTVIM3.js.map +1 -0
- package/chunk-LW3TRU5W.js +131 -0
- package/chunk-LW3TRU5W.js.map +1 -0
- package/chunk-LZMKSFCF.js +79 -0
- package/chunk-LZMKSFCF.js.map +1 -0
- package/chunk-MR3JDI7E.js +122 -0
- package/chunk-MR3JDI7E.js.map +1 -0
- package/chunk-NN6PKJWS.js +44 -0
- package/chunk-NN6PKJWS.js.map +1 -0
- package/chunk-NSRTTYQ4.js +252 -0
- package/chunk-NSRTTYQ4.js.map +1 -0
- package/chunk-O7F3CIDV.js +45 -0
- package/chunk-O7F3CIDV.js.map +1 -0
- package/chunk-P4O6TGDR.js +166 -0
- package/chunk-P4O6TGDR.js.map +1 -0
- package/chunk-PF3YBUKT.js +81 -0
- package/chunk-PF3YBUKT.js.map +1 -0
- package/chunk-PVOLDO4G.js +47 -0
- package/chunk-PVOLDO4G.js.map +1 -0
- package/chunk-QS4N4MNP.js +215 -0
- package/chunk-QS4N4MNP.js.map +1 -0
- package/chunk-QUF2IPOZ.js +98 -0
- package/chunk-QUF2IPOZ.js.map +1 -0
- package/chunk-RTJ76X5U.js +126 -0
- package/chunk-RTJ76X5U.js.map +1 -0
- package/chunk-SH6NG6VN.js +40 -0
- package/chunk-SH6NG6VN.js.map +1 -0
- package/chunk-SHDFUXYV.js +195 -0
- package/chunk-SHDFUXYV.js.map +1 -0
- package/chunk-TKO44NDI.js +84 -0
- package/chunk-TKO44NDI.js.map +1 -0
- package/chunk-TOMSU4S4.js +149 -0
- package/chunk-TOMSU4S4.js.map +1 -0
- package/chunk-TVLGZGYN.js +59 -0
- package/chunk-TVLGZGYN.js.map +1 -0
- package/chunk-TX3H3QMA.js +520 -0
- package/chunk-TX3H3QMA.js.map +1 -0
- package/chunk-UBNHSZSE.js +88 -0
- package/chunk-UBNHSZSE.js.map +1 -0
- package/chunk-UC3ZJWOD.js +73 -0
- package/chunk-UC3ZJWOD.js.map +1 -0
- package/chunk-UGRSWP6U.js +69 -0
- package/chunk-UGRSWP6U.js.map +1 -0
- package/chunk-VAGIAREV.js +214 -0
- package/chunk-VAGIAREV.js.map +1 -0
- package/chunk-WTMZT3IT.js +105 -0
- package/chunk-WTMZT3IT.js.map +1 -0
- package/chunk-WX6BP5ZP.js +39 -0
- package/chunk-WX6BP5ZP.js.map +1 -0
- package/chunk-X3PQANZO.js +255 -0
- package/chunk-X3PQANZO.js.map +1 -0
- package/chunk-XILQ7GXE.js +66 -0
- package/chunk-XILQ7GXE.js.map +1 -0
- package/chunk-XL75JRUA.js +130 -0
- package/chunk-XL75JRUA.js.map +1 -0
- package/chunk-XZNHT6MO.js +348 -0
- package/chunk-XZNHT6MO.js.map +1 -0
- package/chunk-Y5AYU7PK.js +44 -0
- package/chunk-Y5AYU7PK.js.map +1 -0
- package/chunk-YG7JOOLJ.js +28 -0
- package/chunk-YG7JOOLJ.js.map +1 -0
- package/chunk-YPJYW624.js +195 -0
- package/chunk-YPJYW624.js.map +1 -0
- package/chunk-YPNKBE5X.js +104 -0
- package/chunk-YPNKBE5X.js.map +1 -0
- package/components/accordion.d.ts +27 -0
- package/components/accordion.js +4 -0
- package/components/accordion.js.map +1 -0
- package/components/agent-loading.d.ts +65 -0
- package/components/agent-loading.js +4 -0
- package/components/agent-loading.js.map +1 -0
- package/components/agent-picker.d.ts +82 -0
- package/components/agent-picker.js +5 -0
- package/components/agent-picker.js.map +1 -0
- package/components/agent-suggestion.d.ts +69 -0
- package/components/agent-suggestion.js +6 -0
- package/components/agent-suggestion.js.map +1 -0
- package/components/announcement-bar.d.ts +39 -0
- package/components/announcement-bar.js +6 -0
- package/components/announcement-bar.js.map +1 -0
- package/components/attachment.d.ts +73 -0
- package/components/attachment.js +5 -0
- package/components/attachment.js.map +1 -0
- package/components/avatar.d.ts +34 -0
- package/components/avatar.js +6 -0
- package/components/avatar.js.map +1 -0
- package/components/badge.d.ts +19 -0
- package/components/badge.js +4 -0
- package/components/badge.js.map +1 -0
- package/components/banner.d.ts +54 -0
- package/components/banner.js +5 -0
- package/components/banner.js.map +1 -0
- package/components/bar-chart.d.ts +32 -0
- package/components/bar-chart.js +11 -0
- package/components/bar-chart.js.map +1 -0
- package/components/breadcrumb.d.ts +32 -0
- package/components/breadcrumb.js +6 -0
- package/components/breadcrumb.js.map +1 -0
- package/components/button.d.ts +32 -0
- package/components/button.js +4 -0
- package/components/button.js.map +1 -0
- package/components/card.d.ts +28 -0
- package/components/card.js +5 -0
- package/components/card.js.map +1 -0
- package/components/channel-chart.d.ts +14 -0
- package/components/channel-chart.js +11 -0
- package/components/channel-chart.js.map +1 -0
- package/components/chart.d.ts +88 -0
- package/components/chart.js +10 -0
- package/components/chart.js.map +1 -0
- package/components/checkbox.d.ts +17 -0
- package/components/checkbox.js +4 -0
- package/components/checkbox.js.map +1 -0
- package/components/chip.d.ts +54 -0
- package/components/chip.js +4 -0
- package/components/chip.js.map +1 -0
- package/components/citations.d.ts +37 -0
- package/components/citations.js +5 -0
- package/components/citations.js.map +1 -0
- package/components/code-block.d.ts +13 -0
- package/components/code-block.js +5 -0
- package/components/code-block.js.map +1 -0
- package/components/combobox.d.ts +58 -0
- package/components/combobox.js +10 -0
- package/components/combobox.js.map +1 -0
- package/components/command-menu.d.ts +54 -0
- package/components/command-menu.js +6 -0
- package/components/command-menu.js.map +1 -0
- package/components/context-menu.d.ts +46 -0
- package/components/context-menu.js +6 -0
- package/components/context-menu.js.map +1 -0
- package/components/cookie-consent.d.ts +26 -0
- package/components/cookie-consent.js +5 -0
- package/components/cookie-consent.js.map +1 -0
- package/components/date-picker.d.ts +112 -0
- package/components/date-picker.js +9 -0
- package/components/date-picker.js.map +1 -0
- package/components/decision-card.d.ts +65 -0
- package/components/decision-card.js +7 -0
- package/components/decision-card.js.map +1 -0
- package/components/dialog.d.ts +68 -0
- package/components/dialog.js +5 -0
- package/components/dialog.js.map +1 -0
- package/components/donut-chart.d.ts +20 -0
- package/components/donut-chart.js +11 -0
- package/components/donut-chart.js.map +1 -0
- package/components/dot.d.ts +21 -0
- package/components/dot.js +4 -0
- package/components/dot.js.map +1 -0
- package/components/dropdown.d.ts +74 -0
- package/components/dropdown.js +5 -0
- package/components/dropdown.js.map +1 -0
- package/components/empty-state.d.ts +25 -0
- package/components/empty-state.js +4 -0
- package/components/empty-state.js.map +1 -0
- package/components/file-upload.d.ts +78 -0
- package/components/file-upload.js +7 -0
- package/components/file-upload.js.map +1 -0
- package/components/floating.d.ts +30 -0
- package/components/floating.js +3 -0
- package/components/floating.js.map +1 -0
- package/components/form-field.d.ts +35 -0
- package/components/form-field.js +4 -0
- package/components/form-field.js.map +1 -0
- package/components/hover-card.d.ts +30 -0
- package/components/hover-card.js +4 -0
- package/components/hover-card.js.map +1 -0
- package/components/input-otp.d.ts +49 -0
- package/components/input-otp.js +8 -0
- package/components/input-otp.js.map +1 -0
- package/components/input.d.ts +28 -0
- package/components/input.js +5 -0
- package/components/input.js.map +1 -0
- package/components/kbd.d.ts +37 -0
- package/components/kbd.js +4 -0
- package/components/kbd.js.map +1 -0
- package/components/line-chart.d.ts +29 -0
- package/components/line-chart.js +12 -0
- package/components/line-chart.js.map +1 -0
- package/components/message-actions.d.ts +24 -0
- package/components/message-actions.js +5 -0
- package/components/message-actions.js.map +1 -0
- package/components/message.d.ts +40 -0
- package/components/message.js +8 -0
- package/components/message.js.map +1 -0
- package/components/number-input.d.ts +33 -0
- package/components/number-input.js +8 -0
- package/components/number-input.js.map +1 -0
- package/components/pagination.d.ts +45 -0
- package/components/pagination.js +6 -0
- package/components/pagination.js.map +1 -0
- package/components/popover.d.ts +44 -0
- package/components/popover.js +4 -0
- package/components/popover.js.map +1 -0
- package/components/progress.d.ts +24 -0
- package/components/progress.js +4 -0
- package/components/progress.js.map +1 -0
- package/components/prompt-bar.d.ts +63 -0
- package/components/prompt-bar.js +6 -0
- package/components/prompt-bar.js.map +1 -0
- package/components/radio.d.ts +27 -0
- package/components/radio.js +4 -0
- package/components/radio.js.map +1 -0
- package/components/search-bar.d.ts +20 -0
- package/components/search-bar.js +5 -0
- package/components/search-bar.js.map +1 -0
- package/components/segmented-control.d.ts +32 -0
- package/components/segmented-control.js +5 -0
- package/components/segmented-control.js.map +1 -0
- package/components/select.d.ts +97 -0
- package/components/select.js +7 -0
- package/components/select.js.map +1 -0
- package/components/sheet.d.ts +37 -0
- package/components/sheet.js +6 -0
- package/components/sheet.js.map +1 -0
- package/components/sidebar.d.ts +52 -0
- package/components/sidebar.js +4 -0
- package/components/sidebar.js.map +1 -0
- package/components/skeleton.d.ts +18 -0
- package/components/skeleton.js +4 -0
- package/components/skeleton.js.map +1 -0
- package/components/slider.d.ts +57 -0
- package/components/slider.js +8 -0
- package/components/slider.js.map +1 -0
- package/components/sliding-indicator.d.ts +23 -0
- package/components/sliding-indicator.js +3 -0
- package/components/sliding-indicator.js.map +1 -0
- package/components/streaming-text.d.ts +33 -0
- package/components/streaming-text.js +4 -0
- package/components/streaming-text.js.map +1 -0
- package/components/switch.d.ts +15 -0
- package/components/switch.js +4 -0
- package/components/switch.js.map +1 -0
- package/components/table.d.ts +57 -0
- package/components/table.js +5 -0
- package/components/table.js.map +1 -0
- package/components/tabs.d.ts +45 -0
- package/components/tabs.js +5 -0
- package/components/tabs.js.map +1 -0
- package/components/textarea.d.ts +30 -0
- package/components/textarea.js +5 -0
- package/components/textarea.js.map +1 -0
- package/components/thinking.d.ts +64 -0
- package/components/thinking.js +5 -0
- package/components/thinking.js.map +1 -0
- package/components/toast.d.ts +71 -0
- package/components/toast.js +5 -0
- package/components/toast.js.map +1 -0
- package/components/toggle.d.ts +30 -0
- package/components/toggle.js +4 -0
- package/components/toggle.js.map +1 -0
- package/components/tooltip.d.ts +35 -0
- package/components/tooltip.js +5 -0
- package/components/tooltip.js.map +1 -0
- package/index.d.ts +64 -0
- package/index.js +230 -0
- package/index.js.map +1 -0
- package/lib/utils.d.ts +3 -0
- package/lib/utils.js +3 -0
- package/lib/utils.js.map +1 -0
- package/package.json +54 -4
- package/styles.css +2 -0
- package/theme/create-theme.d.ts +44 -0
- package/theme/index.d.ts +1 -0
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import { useFormField } from './chunk-UBNHSZSE.js';
|
|
2
|
+
import { MenuItemContent, menuItemClass, menuGroupClass, menuGroupLabelClass, menuSurfaceClass } from './chunk-3DINAQLL.js';
|
|
3
|
+
import { cn } from './chunk-H63FYCMY.js';
|
|
4
|
+
import * as React from 'react';
|
|
5
|
+
import { Select as Select$1 } from 'radix-ui';
|
|
6
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
7
|
+
|
|
8
|
+
var isOptionGroups = (o) => o.length > 0 && typeof o[0] === "object" && o[0] !== null && "options" in o[0];
|
|
9
|
+
function useFieldChrome({
|
|
10
|
+
id,
|
|
11
|
+
disabled,
|
|
12
|
+
error,
|
|
13
|
+
hint
|
|
14
|
+
}) {
|
|
15
|
+
const field = useFormField();
|
|
16
|
+
const autoId = React.useId();
|
|
17
|
+
const controlId = id ?? field?.id ?? autoId;
|
|
18
|
+
const isError = typeof error === "string" || React.isValidElement(error);
|
|
19
|
+
const message = isError ? error : hint;
|
|
20
|
+
const messageId = message ? `${controlId}-hint` : void 0;
|
|
21
|
+
return {
|
|
22
|
+
controlId,
|
|
23
|
+
disabled: disabled ?? field?.disabled ?? false,
|
|
24
|
+
invalid: Boolean(error) || (field?.invalid ?? false),
|
|
25
|
+
required: field?.required,
|
|
26
|
+
describedBy: [field?.describedBy, messageId].filter(Boolean).join(" ") || void 0,
|
|
27
|
+
message,
|
|
28
|
+
messageId,
|
|
29
|
+
isError
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
function FieldChrome({
|
|
33
|
+
label,
|
|
34
|
+
action,
|
|
35
|
+
chrome,
|
|
36
|
+
className,
|
|
37
|
+
children
|
|
38
|
+
}) {
|
|
39
|
+
return /* @__PURE__ */ jsxs("div", { className: cn("grid w-full gap-2", className), children: [
|
|
40
|
+
label && // The row keeps the label's 18px whatever the action, so the field never moves.
|
|
41
|
+
/* @__PURE__ */ jsxs("div", { className: "flex h-[18px] items-center justify-between gap-2", children: [
|
|
42
|
+
/* @__PURE__ */ jsx("label", { htmlFor: chrome.controlId, className: "text-sm leading-[18px] font-medium text-text-default", children: label }),
|
|
43
|
+
action && /* @__PURE__ */ jsx("div", { className: "-my-[3px] flex shrink-0 items-center", children: action })
|
|
44
|
+
] }),
|
|
45
|
+
children,
|
|
46
|
+
chrome.message && /* @__PURE__ */ jsx("p", { id: chrome.messageId, className: cn("text-sm", chrome.isError ? "text-action-destructive-bg" : "text-text-muted"), children: chrome.message })
|
|
47
|
+
] });
|
|
48
|
+
}
|
|
49
|
+
function SelectChevron({ className }) {
|
|
50
|
+
return /* @__PURE__ */ jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", "aria-hidden": true, className: cn("satin-field-icon text-text-muted", className), children: /* @__PURE__ */ jsx("path", { d: "M4 6L8 10L12 6", stroke: "currentColor", strokeWidth: "1.25", strokeLinecap: "round", strokeLinejoin: "round" }) });
|
|
51
|
+
}
|
|
52
|
+
function Select({
|
|
53
|
+
options,
|
|
54
|
+
value,
|
|
55
|
+
defaultValue,
|
|
56
|
+
onValueChange,
|
|
57
|
+
placeholder = "Select\u2026",
|
|
58
|
+
label,
|
|
59
|
+
hint,
|
|
60
|
+
error,
|
|
61
|
+
size = "md",
|
|
62
|
+
leadingIcon,
|
|
63
|
+
layout = "inline",
|
|
64
|
+
iconSize = 16,
|
|
65
|
+
disabled,
|
|
66
|
+
required,
|
|
67
|
+
name,
|
|
68
|
+
id,
|
|
69
|
+
open,
|
|
70
|
+
defaultOpen,
|
|
71
|
+
onOpenChange,
|
|
72
|
+
container,
|
|
73
|
+
wrapperClassName,
|
|
74
|
+
className,
|
|
75
|
+
"data-force": force,
|
|
76
|
+
...props
|
|
77
|
+
}) {
|
|
78
|
+
const chrome = useFieldChrome({ id, disabled, error, hint });
|
|
79
|
+
const [uncontrolled, setUncontrolled] = React.useState(defaultValue);
|
|
80
|
+
const current = value ?? uncontrolled;
|
|
81
|
+
const groups = isOptionGroups(options) ? options : [{ options }];
|
|
82
|
+
const lead = leadingIcon ?? groups.flatMap((g) => g.options).find((o) => o.value === current)?.icon;
|
|
83
|
+
return /* @__PURE__ */ jsx(FieldChrome, { label, chrome, className: wrapperClassName, children: /* @__PURE__ */ jsxs(
|
|
84
|
+
Select$1.Root,
|
|
85
|
+
{
|
|
86
|
+
value,
|
|
87
|
+
defaultValue,
|
|
88
|
+
onValueChange: (v) => {
|
|
89
|
+
if (value == null) setUncontrolled(v);
|
|
90
|
+
onValueChange?.(v);
|
|
91
|
+
},
|
|
92
|
+
open,
|
|
93
|
+
defaultOpen,
|
|
94
|
+
onOpenChange,
|
|
95
|
+
disabled: chrome.disabled,
|
|
96
|
+
required: required ?? chrome.required,
|
|
97
|
+
name,
|
|
98
|
+
children: [
|
|
99
|
+
/* @__PURE__ */ jsxs(
|
|
100
|
+
Select$1.Trigger,
|
|
101
|
+
{
|
|
102
|
+
id: chrome.controlId,
|
|
103
|
+
"data-slot": "select-trigger",
|
|
104
|
+
"data-size": size,
|
|
105
|
+
"data-filled": current ? true : void 0,
|
|
106
|
+
"data-invalid": chrome.invalid || void 0,
|
|
107
|
+
"data-disabled": chrome.disabled || void 0,
|
|
108
|
+
"data-force": force,
|
|
109
|
+
"aria-invalid": chrome.invalid || void 0,
|
|
110
|
+
"aria-describedby": chrome.describedBy,
|
|
111
|
+
"aria-label": props["aria-label"],
|
|
112
|
+
className: cn("satin-field satin-select", className),
|
|
113
|
+
children: [
|
|
114
|
+
lead && /* @__PURE__ */ jsx("span", { className: "satin-field-icon", "aria-hidden": true, children: lead }),
|
|
115
|
+
/* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate text-text-default", children: /* @__PURE__ */ jsx(Select$1.Value, { placeholder: /* @__PURE__ */ jsx("span", { className: "text-text-muted", children: placeholder }) }) }),
|
|
116
|
+
/* @__PURE__ */ jsx(Select$1.Icon, { asChild: true, children: /* @__PURE__ */ jsx(SelectChevron, {}) })
|
|
117
|
+
]
|
|
118
|
+
}
|
|
119
|
+
),
|
|
120
|
+
/* @__PURE__ */ jsx(Select$1.Portal, { container, children: /* @__PURE__ */ jsx(
|
|
121
|
+
Select$1.Content,
|
|
122
|
+
{
|
|
123
|
+
"data-slot": "select-menu",
|
|
124
|
+
position: "popper",
|
|
125
|
+
side: "bottom",
|
|
126
|
+
align: "start",
|
|
127
|
+
sideOffset: 4,
|
|
128
|
+
collisionPadding: 8,
|
|
129
|
+
className: cn(
|
|
130
|
+
"pointer-events-auto z-50 max-w-[520px] min-w-(--radix-select-trigger-width) overflow-hidden",
|
|
131
|
+
"max-h-(--radix-select-content-available-height)",
|
|
132
|
+
menuSurfaceClass,
|
|
133
|
+
"origin-(--radix-select-content-transform-origin) outline-none",
|
|
134
|
+
"data-[state=open]:animate-[satin-enter_var(--duration-base)_var(--ease-out)]"
|
|
135
|
+
),
|
|
136
|
+
children: /* @__PURE__ */ jsx(Select$1.Viewport, { className: "flex flex-col gap-1 p-1", children: groups.map((g, gi) => {
|
|
137
|
+
const rows = g.options.map((o) => /* @__PURE__ */ jsx(
|
|
138
|
+
Select$1.Item,
|
|
139
|
+
{
|
|
140
|
+
value: o.value,
|
|
141
|
+
disabled: o.disabled,
|
|
142
|
+
textValue: o.label,
|
|
143
|
+
"data-slot": "select-item",
|
|
144
|
+
className: cn(menuItemClass, "data-[state=checked]:bg-bg-selected"),
|
|
145
|
+
children: /* @__PURE__ */ jsx(
|
|
146
|
+
MenuItemContent,
|
|
147
|
+
{
|
|
148
|
+
label: o.label,
|
|
149
|
+
description: o.description,
|
|
150
|
+
icon: o.icon,
|
|
151
|
+
iconSize,
|
|
152
|
+
layout,
|
|
153
|
+
shortcut: o.shortcut,
|
|
154
|
+
selected: o.value === current,
|
|
155
|
+
renderLabel: (l) => /* @__PURE__ */ jsx(Select$1.ItemText, { children: l })
|
|
156
|
+
}
|
|
157
|
+
)
|
|
158
|
+
},
|
|
159
|
+
o.value
|
|
160
|
+
));
|
|
161
|
+
return groups.length > 1 || g.label ? /* @__PURE__ */ jsxs(Select$1.Group, { className: menuGroupClass, children: [
|
|
162
|
+
g.label && /* @__PURE__ */ jsx(Select$1.Label, { className: menuGroupLabelClass, children: g.label }),
|
|
163
|
+
rows
|
|
164
|
+
] }, gi) : /* @__PURE__ */ jsx(React.Fragment, { children: rows }, gi);
|
|
165
|
+
}) })
|
|
166
|
+
}
|
|
167
|
+
) })
|
|
168
|
+
]
|
|
169
|
+
}
|
|
170
|
+
) });
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
export { FieldChrome, Select, SelectChevron, isOptionGroups, useFieldChrome };
|
|
174
|
+
//# sourceMappingURL=chunk-72OCFAPT.js.map
|
|
175
|
+
//# sourceMappingURL=chunk-72OCFAPT.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/select.tsx"],"names":["SelectPrimitive"],"mappings":"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","file":"chunk-72OCFAPT.js","sourcesContent":["'use client'\n\nimport * as React from 'react'\nimport { Select as SelectPrimitive } from 'radix-ui'\nimport { cn } from '../lib/utils'\nimport { MenuItemContent, menuGroupClass, menuGroupLabelClass, menuItemClass, menuSurfaceClass, type MenuItemContentProps } from './dropdown'\nimport { useFormField } from './form-field'\n\n/**\n * Select, 1:1 with the uiKit `Select` set (4022:3531): the field around it is Input's (a 13px\n * medium label 8px above, a 13px hint or error under it), the trigger is Input's skin with the\n * value and a 16px chevron (sm 28, md 32, lg 36; 12px in, 8px gaps), an optional 16px leading\n * icon (by default the picked option's own icon, when the options have icons). Placeholder is text/muted, a value text/default. While the list is open the trigger\n * keeps the focus border and ring.\n *\n * The list is the Dropdown menu: the same surface, rows, groups and options, so every option\n * takes what a `DropdownMenuItem` takes (icon, description, stacked or inline layout, 20px\n * icons, a shortcut) and the current one is marked with the check. It opens 4px under the\n * trigger, at least as wide.\n *\n * Built on the Radix Select: arrow keys, typeahead, Home/End, Escape, a native form value\n * (`name`), and focus back on the trigger. Inside a FormField, leave out `label`, `hint` and\n * `error`.\n */\nexport interface SelectOption extends Omit<MenuItemContentProps, 'label' | 'selected' | 'renderLabel' | 'layout' | 'iconSize'> {\n value: string\n label: string\n disabled?: boolean\n}\n\nexport interface SelectGroup {\n label?: React.ReactNode\n options: SelectOption[]\n}\n\nexport interface SelectProps {\n /** Options, or titled groups of options. */\n options: SelectOption[] | SelectGroup[]\n value?: string\n defaultValue?: string\n onValueChange?: (value: string) => void\n placeholder?: string\n label?: React.ReactNode\n hint?: React.ReactNode\n /** An error message (replaces the hint), or `true` to mark the field invalid without one. */\n error?: React.ReactNode | boolean\n size?: 'sm' | 'md' | 'lg'\n /** A 16px icon before the value. Left out, the picked option's own icon shows there. */\n leadingIcon?: React.ReactNode\n /** Row layout of every option: description under the label, or after it. */\n layout?: MenuItemContentProps['layout']\n /** Option icon size; 20 suits stacked two-line options. */\n iconSize?: MenuItemContentProps['iconSize']\n disabled?: boolean\n required?: boolean\n /** Form field name, for a native form submit. */\n name?: string\n id?: string\n open?: boolean\n defaultOpen?: boolean\n onOpenChange?: (open: boolean) => void\n /** Portal target. Defaults to `document.body`. */\n container?: HTMLElement | null\n 'aria-label'?: string\n /** Classes for the outer wrapper (label + field + hint). `className` styles the trigger. */\n wrapperClassName?: string\n className?: string\n /** Show a state without interacting, for state sheets. */\n 'data-force'?: 'hover' | 'focus'\n}\n\nexport const isOptionGroups = <T,>(o: T[] | { options: T[] }[]): o is { options: T[] }[] =>\n o.length > 0 && typeof o[0] === 'object' && o[0] !== null && 'options' in o[0]\n\n/** Ids and state for a field with a label, a hint or an error, inside or outside a FormField. */\nexport function useFieldChrome({\n id,\n disabled,\n error,\n hint,\n}: {\n id?: string\n disabled?: boolean\n error?: React.ReactNode | boolean\n hint?: React.ReactNode\n}) {\n const field = useFormField()\n const autoId = React.useId()\n const controlId = id ?? field?.id ?? autoId\n const isError = typeof error === 'string' || React.isValidElement(error)\n const message = isError ? (error as React.ReactNode) : hint\n const messageId = message ? `${controlId}-hint` : undefined\n return {\n controlId,\n disabled: disabled ?? field?.disabled ?? false,\n invalid: Boolean(error) || (field?.invalid ?? false),\n required: field?.required,\n describedBy: [field?.describedBy, messageId].filter(Boolean).join(' ') || undefined,\n message,\n messageId,\n isError,\n }\n}\n\n/** Label 8px above the control, hint or error 8px under it: Input's field, for Select and Combobox. */\nexport function FieldChrome({\n label,\n action,\n chrome,\n className,\n children,\n}: {\n label?: React.ReactNode\n /** On the label's line, at the field's right edge: the smallest button, e.g. Clear. */\n action?: React.ReactNode\n chrome: ReturnType<typeof useFieldChrome>\n className?: string\n children: React.ReactNode\n}) {\n return (\n <div className={cn('grid w-full gap-2', className)}>\n {label && (\n // The row keeps the label's 18px whatever the action, so the field never moves.\n <div className=\"flex h-[18px] items-center justify-between gap-2\">\n <label htmlFor={chrome.controlId} className=\"text-sm leading-[18px] font-medium text-text-default\">\n {label}\n </label>\n {action && <div className=\"-my-[3px] flex shrink-0 items-center\">{action}</div>}\n </div>\n )}\n {children}\n {chrome.message && (\n <p id={chrome.messageId} className={cn('text-sm', chrome.isError ? 'text-action-destructive-bg' : 'text-text-muted')}>\n {chrome.message}\n </p>\n )}\n </div>\n )\n}\n\n/** The trigger's chevron, 16px in the icon colour. */\nexport function SelectChevron({ className }: { className?: string }) {\n return (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" aria-hidden className={cn('satin-field-icon text-text-muted', className)}>\n <path d=\"M4 6L8 10L12 6\" stroke=\"currentColor\" strokeWidth=\"1.25\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n </svg>\n )\n}\n\nexport function Select({\n options,\n value,\n defaultValue,\n onValueChange,\n placeholder = 'Select…',\n label,\n hint,\n error,\n size = 'md',\n leadingIcon,\n layout = 'inline',\n iconSize = 16,\n disabled,\n required,\n name,\n id,\n open,\n defaultOpen,\n onOpenChange,\n container,\n wrapperClassName,\n className,\n 'data-force': force,\n ...props\n}: SelectProps) {\n const chrome = useFieldChrome({ id, disabled, error, hint })\n\n // Figma's `filled` and the check: track the value, controlled or not.\n const [uncontrolled, setUncontrolled] = React.useState(defaultValue)\n const current = value ?? uncontrolled\n const groups: SelectGroup[] = isOptionGroups(options) ? (options as SelectGroup[]) : [{ options: options as SelectOption[] }]\n const lead = leadingIcon ?? groups.flatMap((g) => g.options).find((o) => o.value === current)?.icon\n\n return (\n <FieldChrome label={label} chrome={chrome} className={wrapperClassName}>\n <SelectPrimitive.Root\n value={value}\n defaultValue={defaultValue}\n onValueChange={(v) => {\n if (value == null) setUncontrolled(v)\n onValueChange?.(v)\n }}\n open={open}\n defaultOpen={defaultOpen}\n onOpenChange={onOpenChange}\n disabled={chrome.disabled}\n required={required ?? chrome.required}\n name={name}\n >\n <SelectPrimitive.Trigger\n id={chrome.controlId}\n data-slot=\"select-trigger\"\n data-size={size}\n data-filled={current ? true : undefined}\n data-invalid={chrome.invalid || undefined}\n data-disabled={chrome.disabled || undefined}\n data-force={force}\n aria-invalid={chrome.invalid || undefined}\n aria-describedby={chrome.describedBy}\n aria-label={props['aria-label']}\n className={cn('satin-field satin-select', className)}\n >\n {lead && (\n <span className=\"satin-field-icon\" aria-hidden>\n {lead}\n </span>\n )}\n <span className=\"min-w-0 flex-1 truncate text-text-default\">\n <SelectPrimitive.Value placeholder={<span className=\"text-text-muted\">{placeholder}</span>} />\n </span>\n <SelectPrimitive.Icon asChild>\n <SelectChevron />\n </SelectPrimitive.Icon>\n </SelectPrimitive.Trigger>\n\n <SelectPrimitive.Portal container={container}>\n <SelectPrimitive.Content\n data-slot=\"select-menu\"\n position=\"popper\"\n side=\"bottom\"\n align=\"start\"\n sideOffset={4}\n collisionPadding={8}\n className={cn(\n 'pointer-events-auto z-50 max-w-[520px] min-w-(--radix-select-trigger-width) overflow-hidden',\n 'max-h-(--radix-select-content-available-height)',\n menuSurfaceClass,\n 'origin-(--radix-select-content-transform-origin) outline-none',\n 'data-[state=open]:animate-[satin-enter_var(--duration-base)_var(--ease-out)]',\n )}\n >\n <SelectPrimitive.Viewport className=\"flex flex-col gap-1 p-1\">\n {groups.map((g, gi) => {\n const rows = g.options.map((o) => (\n <SelectPrimitive.Item\n key={o.value}\n value={o.value}\n disabled={o.disabled}\n textValue={o.label}\n data-slot=\"select-item\"\n className={cn(menuItemClass, 'data-[state=checked]:bg-bg-selected')}\n >\n <MenuItemContent\n label={o.label}\n description={o.description}\n icon={o.icon}\n iconSize={iconSize}\n layout={layout}\n shortcut={o.shortcut}\n selected={o.value === current}\n renderLabel={(l) => <SelectPrimitive.ItemText>{l}</SelectPrimitive.ItemText>}\n />\n </SelectPrimitive.Item>\n ))\n return groups.length > 1 || g.label ? (\n <SelectPrimitive.Group key={gi} className={menuGroupClass}>\n {g.label && <SelectPrimitive.Label className={menuGroupLabelClass}>{g.label}</SelectPrimitive.Label>}\n {rows}\n </SelectPrimitive.Group>\n ) : (\n <React.Fragment key={gi}>{rows}</React.Fragment>\n )\n })}\n </SelectPrimitive.Viewport>\n </SelectPrimitive.Content>\n </SelectPrimitive.Portal>\n </SelectPrimitive.Root>\n </FieldChrome>\n )\n}\n"]}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { cn } from './chunk-H63FYCMY.js';
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
4
|
+
|
|
5
|
+
var percent = (value, max) => `${Math.round(value / max * 100)}%`;
|
|
6
|
+
function Progress({
|
|
7
|
+
value,
|
|
8
|
+
max = 100,
|
|
9
|
+
label,
|
|
10
|
+
showValue = true,
|
|
11
|
+
size = "sm",
|
|
12
|
+
formatValue = percent,
|
|
13
|
+
className,
|
|
14
|
+
"aria-label": ariaLabel,
|
|
15
|
+
...props
|
|
16
|
+
}) {
|
|
17
|
+
const labelId = React.useId();
|
|
18
|
+
const known = value != null;
|
|
19
|
+
const v = known ? Math.min(max, Math.max(0, value)) : 0;
|
|
20
|
+
const text = known ? formatValue(v, max) : void 0;
|
|
21
|
+
return /* @__PURE__ */ jsxs("div", { "data-slot": "progress", "data-size": size, className: cn("flex w-full flex-col gap-2", className), ...props, children: [
|
|
22
|
+
(label || showValue && known) && /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-3 text-sm leading-5", children: [
|
|
23
|
+
label ? /* @__PURE__ */ jsx("span", { id: labelId, className: "min-w-0 truncate font-medium text-text-default", children: label }) : /* @__PURE__ */ jsx("span", {}),
|
|
24
|
+
showValue && known && /* @__PURE__ */ jsx("span", { "aria-hidden": true, className: "shrink-0 text-text-muted tabular-nums", children: text })
|
|
25
|
+
] }),
|
|
26
|
+
/* @__PURE__ */ jsx(
|
|
27
|
+
"div",
|
|
28
|
+
{
|
|
29
|
+
role: "progressbar",
|
|
30
|
+
"aria-labelledby": label ? labelId : void 0,
|
|
31
|
+
"aria-label": label ? void 0 : ariaLabel,
|
|
32
|
+
"aria-valuemin": 0,
|
|
33
|
+
"aria-valuemax": max,
|
|
34
|
+
"aria-valuenow": known ? v : void 0,
|
|
35
|
+
"aria-valuetext": text,
|
|
36
|
+
className: cn("relative w-full overflow-hidden rounded-full bg-bg-muted", size === "md" ? "h-2" : "h-1"),
|
|
37
|
+
children: known ? /* @__PURE__ */ jsx(
|
|
38
|
+
"div",
|
|
39
|
+
{
|
|
40
|
+
className: "h-full rounded-full bg-action-primary-bg transition-[width] duration-300 ease-(--ease-out)",
|
|
41
|
+
style: { width: `${v / max * 100}%` }
|
|
42
|
+
}
|
|
43
|
+
) : /* @__PURE__ */ jsx("div", { className: "absolute inset-y-0 left-0 w-1/3 rounded-full bg-action-primary-bg animate-[satin-progress-indeterminate_1.4s_var(--ease-in-out)_infinite]" })
|
|
44
|
+
}
|
|
45
|
+
)
|
|
46
|
+
] });
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export { Progress };
|
|
50
|
+
//# sourceMappingURL=chunk-7TXHCRAG.js.map
|
|
51
|
+
//# sourceMappingURL=chunk-7TXHCRAG.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/progress.tsx"],"names":[],"mappings":";;;;AA4BA,IAAM,OAAA,GAAU,CAAC,KAAA,EAAe,GAAA,KAAgB,CAAA,EAAG,KAAK,KAAA,CAAO,KAAA,GAAQ,GAAA,GAAO,GAAG,CAAC,CAAA,CAAA,CAAA;AAE3E,SAAS,QAAA,CAAS;AAAA,EACvB,KAAA;AAAA,EACA,GAAA,GAAM,GAAA;AAAA,EACN,KAAA;AAAA,EACA,SAAA,GAAY,IAAA;AAAA,EACZ,IAAA,GAAO,IAAA;AAAA,EACP,WAAA,GAAc,OAAA;AAAA,EACd,SAAA;AAAA,EACA,YAAA,EAAc,SAAA;AAAA,EACd,GAAG;AACL,CAAA,EAAkB;AAChB,EAAA,MAAM,UAAgB,KAAA,CAAA,KAAA,EAAM;AAC5B,EAAA,MAAM,QAAQ,KAAA,IAAS,IAAA;AACvB,EAAA,MAAM,CAAA,GAAI,KAAA,GAAQ,IAAA,CAAK,GAAA,CAAI,GAAA,EAAK,KAAK,GAAA,CAAI,CAAA,EAAG,KAAK,CAAC,CAAA,GAAI,CAAA;AACtD,EAAA,MAAM,IAAA,GAAO,KAAA,GAAQ,WAAA,CAAY,CAAA,EAAG,GAAG,CAAA,GAAI,MAAA;AAE3C,EAAA,uBACE,IAAA,CAAC,KAAA,EAAA,EAAI,WAAA,EAAU,UAAA,EAAW,WAAA,EAAW,IAAA,EAAM,SAAA,EAAW,EAAA,CAAG,4BAAA,EAA8B,SAAS,CAAA,EAAI,GAAG,KAAA,EACnG,QAAA,EAAA;AAAA,IAAA,CAAA,KAAA,IAAU,SAAA,IAAa,KAAA,qBACvB,IAAA,CAAC,KAAA,EAAA,EAAI,WAAU,2DAAA,EACZ,QAAA,EAAA;AAAA,MAAA,KAAA,mBACC,GAAA,CAAC,UAAK,EAAA,EAAI,OAAA,EAAS,WAAU,gDAAA,EAC1B,QAAA,EAAA,KAAA,EACH,CAAA,mBAEA,GAAA,CAAC,MAAA,EAAA,EAAK,CAAA;AAAA,MAEP,SAAA,IAAa,yBACZ,GAAA,CAAC,MAAA,EAAA,EAAK,eAAW,IAAA,EAAC,SAAA,EAAU,yCACzB,QAAA,EAAA,IAAA,EACH;AAAA,KAAA,EAEJ,CAAA;AAAA,oBAEF,GAAA;AAAA,MAAC,KAAA;AAAA,MAAA;AAAA,QACC,IAAA,EAAK,aAAA;AAAA,QACL,iBAAA,EAAiB,QAAQ,OAAA,GAAU,MAAA;AAAA,QACnC,YAAA,EAAY,QAAQ,MAAA,GAAY,SAAA;AAAA,QAChC,eAAA,EAAe,CAAA;AAAA,QACf,eAAA,EAAe,GAAA;AAAA,QACf,eAAA,EAAe,QAAQ,CAAA,GAAI,MAAA;AAAA,QAC3B,gBAAA,EAAgB,IAAA;AAAA,QAChB,WAAW,EAAA,CAAG,0DAAA,EAA4D,IAAA,KAAS,IAAA,GAAO,QAAQ,KAAK,CAAA;AAAA,QAEtG,QAAA,EAAA,KAAA,mBACC,GAAA;AAAA,UAAC,KAAA;AAAA,UAAA;AAAA,YACC,SAAA,EAAU,4FAAA;AAAA,YACV,OAAO,EAAE,KAAA,EAAO,GAAI,CAAA,GAAI,GAAA,GAAO,GAAG,CAAA,CAAA,CAAA;AAAI;AAAA,SACxC,mBAEA,GAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,2IAAA,EAA4I;AAAA;AAAA;AAE/J,GAAA,EACF,CAAA;AAEJ","file":"chunk-7TXHCRAG.js","sourcesContent":["'use client'\n\nimport * as React from 'react'\nimport { cn } from '../lib/utils'\n\n/**\n * Progress, 1:1 with the uiKit `Progress` set (4025:3851): a bg/muted track, 4px (sm) or 8px\n * (md), fully rounded, with the done part in action/primary/bg. Above it, optionally, a label\n * row 8px up: the label (13px medium, text/default) on the left and the percentage (13px,\n * text/muted) on the right.\n *\n * Leave `value` out while the amount is unknown: a third of the track then slides across.\n * The bar moves to a new value over 300 ms on ease-out.\n *\n * A `progressbar` with aria-valuenow (and the label as its name) when there is a value.\n */\nexport interface ProgressProps extends Omit<React.ComponentProps<'div'>, 'children'> {\n /** 0 to `max`; left out, the bar is indeterminate. */\n value?: number | null\n max?: number\n label?: React.ReactNode\n /** The percentage at the right of the label row. */\n showValue?: boolean\n size?: 'sm' | 'md'\n /** How the value reads on the right and to screen readers. Defaults to a whole percentage. */\n formatValue?: (value: number, max: number) => string\n}\n\nconst percent = (value: number, max: number) => `${Math.round((value / max) * 100)}%`\n\nexport function Progress({\n value,\n max = 100,\n label,\n showValue = true,\n size = 'sm',\n formatValue = percent,\n className,\n 'aria-label': ariaLabel,\n ...props\n}: ProgressProps) {\n const labelId = React.useId()\n const known = value != null\n const v = known ? Math.min(max, Math.max(0, value)) : 0\n const text = known ? formatValue(v, max) : undefined\n\n return (\n <div data-slot=\"progress\" data-size={size} className={cn('flex w-full flex-col gap-2', className)} {...props}>\n {(label || (showValue && known)) && (\n <div className=\"flex items-center justify-between gap-3 text-sm leading-5\">\n {label ? (\n <span id={labelId} className=\"min-w-0 truncate font-medium text-text-default\">\n {label}\n </span>\n ) : (\n <span />\n )}\n {showValue && known && (\n <span aria-hidden className=\"shrink-0 text-text-muted tabular-nums\">\n {text}\n </span>\n )}\n </div>\n )}\n <div\n role=\"progressbar\"\n aria-labelledby={label ? labelId : undefined}\n aria-label={label ? undefined : ariaLabel}\n aria-valuemin={0}\n aria-valuemax={max}\n aria-valuenow={known ? v : undefined}\n aria-valuetext={text}\n className={cn('relative w-full overflow-hidden rounded-full bg-bg-muted', size === 'md' ? 'h-2' : 'h-1')}\n >\n {known ? (\n <div\n className=\"h-full rounded-full bg-action-primary-bg transition-[width] duration-300 ease-(--ease-out)\"\n style={{ width: `${(v / max) * 100}%` }}\n />\n ) : (\n <div className=\"absolute inset-y-0 left-0 w-1/3 rounded-full bg-action-primary-bg animate-[satin-progress-indeterminate_1.4s_var(--ease-in-out)_infinite]\" />\n )}\n </div>\n </div>\n )\n}\n"]}
|
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
import { Button } from './chunk-HNQUX43Z.js';
|
|
2
|
+
import { cn } from './chunk-H63FYCMY.js';
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
import { Check, Copy } from 'iconoir-react';
|
|
5
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
6
|
+
|
|
7
|
+
var tokenClass = {
|
|
8
|
+
plain: "text-[var(--code-plain,#18181b)] dark:text-[var(--code-plain,#fafafa)]",
|
|
9
|
+
keyword: "text-[var(--code-keyword,#dc2626)] dark:text-[var(--code-keyword,#f87171)]",
|
|
10
|
+
string: "text-[var(--code-string,#0369a1)] dark:text-[var(--code-string,#7dd3fc)]",
|
|
11
|
+
function: "text-[var(--code-function,#8b5cf6)] dark:text-[var(--code-function,#a78bfa)]",
|
|
12
|
+
parameter: "text-[var(--code-parameter,#b45309)] dark:text-[var(--code-parameter,#fcd34d)]",
|
|
13
|
+
variable: "text-[var(--code-variable,#0284c7)] dark:text-[var(--code-variable,#38bdf8)]",
|
|
14
|
+
// No comment colour in Figma: comments take the line-number grey.
|
|
15
|
+
comment: "text-[var(--code-line-number,#a1a1aa)] dark:text-[var(--code-line-number,#71717a)]"
|
|
16
|
+
};
|
|
17
|
+
var lineNumberClass = "text-[var(--code-line-number,#a1a1aa)] dark:text-[var(--code-line-number,#71717a)]";
|
|
18
|
+
var highlightClass = "bg-[var(--code-line-highlight,rgba(0,0,0,0.05))] dark:bg-[var(--code-line-highlight,rgba(255,255,255,0.06))]";
|
|
19
|
+
var KEYWORDS = /* @__PURE__ */ new Set([
|
|
20
|
+
"import",
|
|
21
|
+
"from",
|
|
22
|
+
"export",
|
|
23
|
+
"default",
|
|
24
|
+
"async",
|
|
25
|
+
"await",
|
|
26
|
+
"function",
|
|
27
|
+
"return",
|
|
28
|
+
"const",
|
|
29
|
+
"let",
|
|
30
|
+
"var",
|
|
31
|
+
"if",
|
|
32
|
+
"else",
|
|
33
|
+
"for",
|
|
34
|
+
"while",
|
|
35
|
+
"do",
|
|
36
|
+
"switch",
|
|
37
|
+
"case",
|
|
38
|
+
"break",
|
|
39
|
+
"continue",
|
|
40
|
+
"new",
|
|
41
|
+
"class",
|
|
42
|
+
"extends",
|
|
43
|
+
"try",
|
|
44
|
+
"catch",
|
|
45
|
+
"finally",
|
|
46
|
+
"throw",
|
|
47
|
+
"typeof",
|
|
48
|
+
"instanceof",
|
|
49
|
+
"in",
|
|
50
|
+
"of",
|
|
51
|
+
"type",
|
|
52
|
+
"interface",
|
|
53
|
+
"as",
|
|
54
|
+
"true",
|
|
55
|
+
"false",
|
|
56
|
+
"null",
|
|
57
|
+
"undefined",
|
|
58
|
+
"this",
|
|
59
|
+
"yield",
|
|
60
|
+
"void",
|
|
61
|
+
"delete",
|
|
62
|
+
"static",
|
|
63
|
+
"public",
|
|
64
|
+
"private"
|
|
65
|
+
]);
|
|
66
|
+
function tokenize(line) {
|
|
67
|
+
const out = [];
|
|
68
|
+
const re = /(\/\/.*$)|("(?:[^"\\]|\\.)*"?|'(?:[^'\\]|\\.)*'?|`(?:[^`\\]|\\.)*`?)|([A-Za-z_$][\w$]*)|(=>|===|!==|==|=)|(\s+)|(.)/g;
|
|
69
|
+
let declaring = false;
|
|
70
|
+
let params = false;
|
|
71
|
+
let depth = 0;
|
|
72
|
+
let afterFunction = false;
|
|
73
|
+
let m;
|
|
74
|
+
while (m = re.exec(line)) {
|
|
75
|
+
const [text, comment, str, ident, op, space] = m;
|
|
76
|
+
if (comment) out.push({ text, kind: "comment" });
|
|
77
|
+
else if (str) out.push({ text, kind: "string" });
|
|
78
|
+
else if (space) out.push({ text, kind: "plain" });
|
|
79
|
+
else if (op) {
|
|
80
|
+
if (op === "=") declaring = false;
|
|
81
|
+
out.push({ text, kind: "keyword" });
|
|
82
|
+
} else if (ident) {
|
|
83
|
+
const rest = line.slice(re.lastIndex);
|
|
84
|
+
if (KEYWORDS.has(ident)) {
|
|
85
|
+
if (ident === "const" || ident === "let" || ident === "var") declaring = true;
|
|
86
|
+
if (ident === "function") afterFunction = true;
|
|
87
|
+
out.push({ text, kind: "keyword" });
|
|
88
|
+
} else if (params && /^\s*[:,)=?]/.test(rest)) out.push({ text, kind: "parameter" });
|
|
89
|
+
else if (/^\s*\(/.test(rest) || /^[A-Z]/.test(ident)) {
|
|
90
|
+
if (afterFunction) params = true;
|
|
91
|
+
afterFunction = false;
|
|
92
|
+
out.push({ text, kind: "function" });
|
|
93
|
+
} else if (declaring) out.push({ text, kind: "variable" });
|
|
94
|
+
else out.push({ text, kind: "plain" });
|
|
95
|
+
} else {
|
|
96
|
+
if (params && text === "(") depth++;
|
|
97
|
+
if (params && text === ")" && --depth <= 0) params = false;
|
|
98
|
+
out.push({ text, kind: "plain" });
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return out.reduce((acc, t) => {
|
|
102
|
+
const last = acc[acc.length - 1];
|
|
103
|
+
if (last && last.kind === t.kind) last.text += t.text;
|
|
104
|
+
else acc.push({ ...t });
|
|
105
|
+
return acc;
|
|
106
|
+
}, []);
|
|
107
|
+
}
|
|
108
|
+
function parse(code, view, highlightLines) {
|
|
109
|
+
const raw = code.replace(/\n$/, "").split("\n");
|
|
110
|
+
if (view === "code") {
|
|
111
|
+
return raw.map((text, i) => ({
|
|
112
|
+
text,
|
|
113
|
+
number: i + 1,
|
|
114
|
+
kind: highlightLines.includes(i + 1) ? "highlighted" : "default"
|
|
115
|
+
}));
|
|
116
|
+
}
|
|
117
|
+
let n = 1;
|
|
118
|
+
return raw.map((line) => {
|
|
119
|
+
const sign = line[0];
|
|
120
|
+
const text = line.slice(1);
|
|
121
|
+
if (sign === "-") return { text, number: n, kind: "removed" };
|
|
122
|
+
if (sign === "+") return { text, number: n++, kind: "added" };
|
|
123
|
+
return { text: sign === " " ? text : line, number: n++, kind: "context" };
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
function FileCodeIcon() {
|
|
127
|
+
return /* @__PURE__ */ jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", "aria-hidden": true, className: "shrink-0 text-text-muted", children: /* @__PURE__ */ jsx(
|
|
128
|
+
"path",
|
|
129
|
+
{
|
|
130
|
+
d: "M13.333 5.333L9.333 1.333H4C3.264 1.333 2.667 1.93 2.667 2.667V13.333C2.667 14.07 3.264 14.667 4 14.667H12C12.736 14.667 13.333 14.07 13.333 13.333V5.333ZM9.333 1.333V5.333H13.333M6.667 8.333L5.333 9.667L6.667 11M9.333 8.333L10.667 9.667L9.333 11",
|
|
131
|
+
stroke: "currentColor",
|
|
132
|
+
strokeWidth: "1.25",
|
|
133
|
+
strokeLinecap: "round",
|
|
134
|
+
strokeLinejoin: "round"
|
|
135
|
+
}
|
|
136
|
+
) });
|
|
137
|
+
}
|
|
138
|
+
function CodeBlock({
|
|
139
|
+
code,
|
|
140
|
+
filename,
|
|
141
|
+
view = "code",
|
|
142
|
+
showHeader = true,
|
|
143
|
+
showActions = true,
|
|
144
|
+
highlightLines = [],
|
|
145
|
+
highlight = true,
|
|
146
|
+
className,
|
|
147
|
+
...props
|
|
148
|
+
}) {
|
|
149
|
+
const lines = React.useMemo(() => parse(code, view, highlightLines), [code, view, highlightLines]);
|
|
150
|
+
const [copied, setCopied] = React.useState(false);
|
|
151
|
+
const timer = React.useRef(void 0);
|
|
152
|
+
React.useEffect(() => () => clearTimeout(timer.current), []);
|
|
153
|
+
const added = lines.filter((l) => l.kind === "added").length;
|
|
154
|
+
const removed = lines.filter((l) => l.kind === "removed").length;
|
|
155
|
+
const copy = async () => {
|
|
156
|
+
const text = lines.filter((l) => l.kind !== "removed").map((l) => l.text).join("\n");
|
|
157
|
+
try {
|
|
158
|
+
await navigator.clipboard.writeText(text);
|
|
159
|
+
setCopied(true);
|
|
160
|
+
clearTimeout(timer.current);
|
|
161
|
+
timer.current = setTimeout(() => setCopied(false), 1500);
|
|
162
|
+
} catch {
|
|
163
|
+
setCopied(false);
|
|
164
|
+
}
|
|
165
|
+
};
|
|
166
|
+
const diff = view === "diff";
|
|
167
|
+
return /* @__PURE__ */ jsxs(
|
|
168
|
+
"div",
|
|
169
|
+
{
|
|
170
|
+
"data-slot": "code-block",
|
|
171
|
+
"data-view": view,
|
|
172
|
+
className: cn(
|
|
173
|
+
"flex flex-col overflow-hidden rounded-2xl border border-border-default bg-bg-card pb-3",
|
|
174
|
+
className
|
|
175
|
+
),
|
|
176
|
+
...props,
|
|
177
|
+
children: [
|
|
178
|
+
showHeader && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 pt-2 pr-2 pb-1 pl-4", children: [
|
|
179
|
+
/* @__PURE__ */ jsx(FileCodeIcon, {}),
|
|
180
|
+
/* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate text-sm leading-[18px] font-medium text-text-default", children: filename }),
|
|
181
|
+
diff && /* @__PURE__ */ jsxs("span", { className: "flex shrink-0 items-center gap-1.5 font-mono text-sm leading-(--text-sm--line-height) tracking-normal", children: [
|
|
182
|
+
/* @__PURE__ */ jsxs("span", { className: "text-status-green-fg", children: [
|
|
183
|
+
"+",
|
|
184
|
+
added
|
|
185
|
+
] }),
|
|
186
|
+
/* @__PURE__ */ jsxs("span", { className: "text-status-red-fg", children: [
|
|
187
|
+
"\u2212",
|
|
188
|
+
removed
|
|
189
|
+
] })
|
|
190
|
+
] }),
|
|
191
|
+
showActions && /* @__PURE__ */ jsxs(Button, { variant: "tertiary", size: "xs", onClick: copy, className: "text-text-default", children: [
|
|
192
|
+
copied ? /* @__PURE__ */ jsx(Check, {}) : /* @__PURE__ */ jsx(Copy, {}),
|
|
193
|
+
/* @__PURE__ */ jsx("span", { "aria-live": "polite", children: copied ? "Copied" : "Copy" })
|
|
194
|
+
] })
|
|
195
|
+
] }),
|
|
196
|
+
/* @__PURE__ */ jsx(
|
|
197
|
+
"pre",
|
|
198
|
+
{
|
|
199
|
+
tabIndex: 0,
|
|
200
|
+
role: "region",
|
|
201
|
+
"aria-label": filename ? `${filename} code` : "Code",
|
|
202
|
+
className: cn(
|
|
203
|
+
"outline-none focus-visible:[box-shadow:inset_0_0_0_2px_var(--action-focus-ring)]",
|
|
204
|
+
"overflow-x-auto font-mono text-sm leading-(--text-sm--line-height) font-normal tracking-normal",
|
|
205
|
+
// Without the header the code sits in the middle: 12px above, as below.
|
|
206
|
+
showHeader ? "pt-1" : "pt-3",
|
|
207
|
+
tokenClass.plain
|
|
208
|
+
),
|
|
209
|
+
children: /* @__PURE__ */ jsx("code", { className: "block w-max min-w-full", children: lines.map((line, i) => /* @__PURE__ */ jsxs(
|
|
210
|
+
"span",
|
|
211
|
+
{
|
|
212
|
+
"data-line": line.kind,
|
|
213
|
+
className: cn(
|
|
214
|
+
"flex h-6 items-center px-4",
|
|
215
|
+
diff ? "gap-2" : "gap-4",
|
|
216
|
+
line.kind === "highlighted" && highlightClass,
|
|
217
|
+
line.kind === "added" && "bg-status-green-bg",
|
|
218
|
+
line.kind === "removed" && "bg-status-red-bg"
|
|
219
|
+
),
|
|
220
|
+
children: [
|
|
221
|
+
/* @__PURE__ */ jsx(
|
|
222
|
+
"span",
|
|
223
|
+
{
|
|
224
|
+
"aria-hidden": true,
|
|
225
|
+
className: cn(
|
|
226
|
+
"w-5 shrink-0 text-right select-none",
|
|
227
|
+
line.kind === "added" ? "text-status-green-fg" : line.kind === "removed" ? "text-status-red-fg" : lineNumberClass
|
|
228
|
+
),
|
|
229
|
+
children: line.number
|
|
230
|
+
}
|
|
231
|
+
),
|
|
232
|
+
diff && /* @__PURE__ */ jsxs(
|
|
233
|
+
"span",
|
|
234
|
+
{
|
|
235
|
+
className: cn(
|
|
236
|
+
"w-2 shrink-0 text-center select-none",
|
|
237
|
+
line.kind === "added" ? "text-status-green-fg" : line.kind === "removed" ? "text-status-red-fg" : lineNumberClass
|
|
238
|
+
),
|
|
239
|
+
children: [
|
|
240
|
+
line.kind === "added" ? "+" : line.kind === "removed" ? "\u2212" : " ",
|
|
241
|
+
line.kind === "added" && /* @__PURE__ */ jsx("span", { className: "sr-only", children: " added" }),
|
|
242
|
+
line.kind === "removed" && /* @__PURE__ */ jsx("span", { className: "sr-only", children: " removed" })
|
|
243
|
+
]
|
|
244
|
+
}
|
|
245
|
+
),
|
|
246
|
+
/* @__PURE__ */ jsx("span", { className: "whitespace-pre", children: line.text === "" ? "\u200B" : highlight ? tokenize(line.text).map((t, j) => /* @__PURE__ */ jsx("span", { className: t.kind === "plain" ? void 0 : tokenClass[t.kind], children: t.text }, j)) : line.text })
|
|
247
|
+
]
|
|
248
|
+
},
|
|
249
|
+
i
|
|
250
|
+
)) })
|
|
251
|
+
}
|
|
252
|
+
)
|
|
253
|
+
]
|
|
254
|
+
}
|
|
255
|
+
);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
export { CodeBlock };
|
|
259
|
+
//# sourceMappingURL=chunk-A5XEM3GF.js.map
|
|
260
|
+
//# sourceMappingURL=chunk-A5XEM3GF.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/code-block.tsx"],"names":[],"mappings":"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","file":"chunk-A5XEM3GF.js","sourcesContent":["'use client'\n\nimport * as React from 'react'\nimport { Check, Copy } from 'iconoir-react'\nimport { cn } from '../lib/utils'\nimport { Button } from './button'\n\n/**\n * CodeBlock, 1:1 with the uiKit `CodeBlock` set (3179:20414) and its `CodeLine` rows\n * (3124:20131): a card-surface block, 1px border-default, radius-2xl, 12px bottom padding.\n * The header holds the file icon, the filename (medium 13/18), diff stats in a diff, and a\n * tertiary xs Copy button that reads \"Copied\" with a check for 1.5 s. Lines are Geist Mono\n * 13/19.5, 24 high, 16px side padding, a 20px right-aligned number column 16px from the\n * code (8px, plus an 8px sign column, in a diff).\n *\n * Line types: highlighted (code/line-highlight fill), added (status green bg, green number\n * and +), removed (status red bg, red number and −).\n *\n * `code` is plain text. In `view=\"diff\"` each line starts with \"+\", \"-\" or a space, like a\n * unified diff. Highlighting is a small JS/TS tokenizer: keyword, string, function, parameter\n * and variable, in the `code/*` colours.\n *\n * The `code/*` variables exist only in Figma so far, not in theme.css, so each colour is\n * `var(--code-…, <Figma light value>)` with the Figma dark value under `dark:`. Once the\n * theme defines them, the variables take over.\n */\n\ntype LineKind = 'default' | 'highlighted' | 'added' | 'removed' | 'context'\ntype TokenKind = 'plain' | 'keyword' | 'string' | 'function' | 'parameter' | 'variable' | 'comment'\n\nconst tokenClass: Record<TokenKind, string> = {\n plain: 'text-[var(--code-plain,#18181b)] dark:text-[var(--code-plain,#fafafa)]',\n keyword: 'text-[var(--code-keyword,#dc2626)] dark:text-[var(--code-keyword,#f87171)]',\n string: 'text-[var(--code-string,#0369a1)] dark:text-[var(--code-string,#7dd3fc)]',\n function: 'text-[var(--code-function,#8b5cf6)] dark:text-[var(--code-function,#a78bfa)]',\n parameter: 'text-[var(--code-parameter,#b45309)] dark:text-[var(--code-parameter,#fcd34d)]',\n variable: 'text-[var(--code-variable,#0284c7)] dark:text-[var(--code-variable,#38bdf8)]',\n // No comment colour in Figma: comments take the line-number grey.\n comment: 'text-[var(--code-line-number,#a1a1aa)] dark:text-[var(--code-line-number,#71717a)]',\n}\n\nconst lineNumberClass = 'text-[var(--code-line-number,#a1a1aa)] dark:text-[var(--code-line-number,#71717a)]'\nconst highlightClass = 'bg-[var(--code-line-highlight,rgba(0,0,0,0.05))] dark:bg-[var(--code-line-highlight,rgba(255,255,255,0.06))]'\n\nconst KEYWORDS = new Set([\n 'import', 'from', 'export', 'default', 'async', 'await', 'function', 'return', 'const', 'let', 'var',\n 'if', 'else', 'for', 'while', 'do', 'switch', 'case', 'break', 'continue', 'new', 'class', 'extends',\n 'try', 'catch', 'finally', 'throw', 'typeof', 'instanceof', 'in', 'of', 'type', 'interface', 'as',\n 'true', 'false', 'null', 'undefined', 'this', 'yield', 'void', 'delete', 'static', 'public', 'private',\n])\n\ntype Token = { text: string; kind: TokenKind }\n\n/** A deliberately small tokenizer for JS/TS-like code, one line at a time. */\nfunction tokenize(line: string): Token[] {\n const out: Token[] = []\n const re = /(\\/\\/.*$)|(\"(?:[^\"\\\\]|\\\\.)*\"?|'(?:[^'\\\\]|\\\\.)*'?|`(?:[^`\\\\]|\\\\.)*`?)|([A-Za-z_$][\\w$]*)|(=>|===|!==|==|=)|(\\s+)|(.)/g\n let declaring = false // after const / let / var, until \"=\"\n let params = false // inside a function's parameter list\n let depth = 0\n let afterFunction = false\n let m: RegExpExecArray | null\n while ((m = re.exec(line))) {\n const [text, comment, str, ident, op, space] = m\n if (comment) out.push({ text, kind: 'comment' })\n else if (str) out.push({ text, kind: 'string' })\n else if (space) out.push({ text, kind: 'plain' })\n else if (op) {\n if (op === '=') declaring = false\n out.push({ text, kind: 'keyword' })\n } else if (ident) {\n const rest = line.slice(re.lastIndex)\n if (KEYWORDS.has(ident)) {\n if (ident === 'const' || ident === 'let' || ident === 'var') declaring = true\n if (ident === 'function') afterFunction = true\n out.push({ text, kind: 'keyword' })\n } else if (params && /^\\s*[:,)=?]/.test(rest)) out.push({ text, kind: 'parameter' })\n else if (/^\\s*\\(/.test(rest) || /^[A-Z]/.test(ident)) {\n // Calls and PascalCase names (types, components) take the function colour, as in Figma.\n if (afterFunction) params = true\n afterFunction = false\n out.push({ text, kind: 'function' })\n } else if (declaring) out.push({ text, kind: 'variable' })\n else out.push({ text, kind: 'plain' })\n } else {\n if (params && text === '(') depth++\n if (params && text === ')' && --depth <= 0) params = false\n out.push({ text, kind: 'plain' })\n }\n }\n // Merge neighbours of the same kind so the DOM stays small.\n return out.reduce<Token[]>((acc, t) => {\n const last = acc[acc.length - 1]\n if (last && last.kind === t.kind) last.text += t.text\n else acc.push({ ...t })\n return acc\n }, [])\n}\n\ntype Line = { kind: LineKind; number: number; text: string }\n\nfunction parse(code: string, view: 'code' | 'diff', highlightLines: number[]): Line[] {\n const raw = code.replace(/\\n$/, '').split('\\n')\n if (view === 'code') {\n return raw.map((text, i) => ({\n text,\n number: i + 1,\n kind: highlightLines.includes(i + 1) ? 'highlighted' : 'default',\n }))\n }\n // Diff: a removed line shows the number the next line will take; added and context count up.\n let n = 1\n return raw.map((line) => {\n const sign = line[0]\n const text = line.slice(1)\n if (sign === '-') return { text, number: n, kind: 'removed' as const }\n if (sign === '+') return { text, number: n++, kind: 'added' as const }\n return { text: sign === ' ' ? text : line, number: n++, kind: 'context' as const }\n })\n}\n\n/** The file icon from Figma (fileCode, 16 at 1.25). */\nfunction FileCodeIcon() {\n return (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" aria-hidden className=\"shrink-0 text-text-muted\">\n <path\n d=\"M13.333 5.333L9.333 1.333H4C3.264 1.333 2.667 1.93 2.667 2.667V13.333C2.667 14.07 3.264 14.667 4 14.667H12C12.736 14.667 13.333 14.07 13.333 13.333V5.333ZM9.333 1.333V5.333H13.333M6.667 8.333L5.333 9.667L6.667 11M9.333 8.333L10.667 9.667L9.333 11\"\n stroke=\"currentColor\"\n strokeWidth=\"1.25\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n )\n}\n\nexport interface CodeBlockProps extends Omit<React.ComponentProps<'div'>, 'children'> {\n code: string\n filename?: string\n view?: 'code' | 'diff'\n showHeader?: boolean\n showActions?: boolean\n /** 1-based line numbers to mark (code view). */\n highlightLines?: number[]\n /** Turn syntax colours off for plain output such as logs. */\n highlight?: boolean\n}\n\nexport function CodeBlock({\n code,\n filename,\n view = 'code',\n showHeader = true,\n showActions = true,\n highlightLines = [],\n highlight = true,\n className,\n ...props\n}: CodeBlockProps) {\n const lines = React.useMemo(() => parse(code, view, highlightLines), [code, view, highlightLines])\n const [copied, setCopied] = React.useState(false)\n const timer = React.useRef<ReturnType<typeof setTimeout> | undefined>(undefined)\n React.useEffect(() => () => clearTimeout(timer.current), [])\n\n const added = lines.filter((l) => l.kind === 'added').length\n const removed = lines.filter((l) => l.kind === 'removed').length\n\n const copy = async () => {\n // A diff copies the new version of the file.\n const text = lines.filter((l) => l.kind !== 'removed').map((l) => l.text).join('\\n')\n try {\n await navigator.clipboard.writeText(text)\n setCopied(true)\n clearTimeout(timer.current)\n timer.current = setTimeout(() => setCopied(false), 1500)\n } catch {\n setCopied(false)\n }\n }\n\n const diff = view === 'diff'\n\n return (\n <div\n data-slot=\"code-block\"\n data-view={view}\n className={cn(\n 'flex flex-col overflow-hidden rounded-2xl border border-border-default bg-bg-card pb-3',\n className,\n )}\n {...props}\n >\n {showHeader && (\n <div className=\"flex items-center gap-2 pt-2 pr-2 pb-1 pl-4\">\n <FileCodeIcon />\n <span className=\"min-w-0 flex-1 truncate text-sm leading-[18px] font-medium text-text-default\">{filename}</span>\n {diff && (\n <span className=\"flex shrink-0 items-center gap-1.5 font-mono text-sm leading-(--text-sm--line-height) tracking-normal\">\n <span className=\"text-status-green-fg\">+{added}</span>\n <span className=\"text-status-red-fg\">−{removed}</span>\n </span>\n )}\n {showActions && (\n <Button variant=\"tertiary\" size=\"xs\" onClick={copy} className=\"text-text-default\">\n {copied ? <Check /> : <Copy />}\n <span aria-live=\"polite\">{copied ? 'Copied' : 'Copy'}</span>\n </Button>\n )}\n </div>\n )}\n {/* Long lines scroll sideways, so the code is a focusable region keyboard users can scroll. */}\n <pre\n tabIndex={0}\n role=\"region\"\n aria-label={filename ? `${filename} code` : 'Code'}\n className={cn(\n 'outline-none focus-visible:[box-shadow:inset_0_0_0_2px_var(--action-focus-ring)]',\n 'overflow-x-auto font-mono text-sm leading-(--text-sm--line-height) font-normal tracking-normal',\n // Without the header the code sits in the middle: 12px above, as below.\n showHeader ? 'pt-1' : 'pt-3',\n tokenClass.plain,\n )}\n >\n <code className=\"block w-max min-w-full\">\n {lines.map((line, i) => (\n <span\n key={i}\n data-line={line.kind}\n className={cn(\n 'flex h-6 items-center px-4',\n diff ? 'gap-2' : 'gap-4',\n line.kind === 'highlighted' && highlightClass,\n line.kind === 'added' && 'bg-status-green-bg',\n line.kind === 'removed' && 'bg-status-red-bg',\n )}\n >\n <span\n aria-hidden\n className={cn(\n 'w-5 shrink-0 text-right select-none',\n line.kind === 'added' ? 'text-status-green-fg' : line.kind === 'removed' ? 'text-status-red-fg' : lineNumberClass,\n )}\n >\n {line.number}\n </span>\n {diff && (\n <span\n className={cn(\n 'w-2 shrink-0 text-center select-none',\n line.kind === 'added' ? 'text-status-green-fg' : line.kind === 'removed' ? 'text-status-red-fg' : lineNumberClass,\n )}\n >\n {line.kind === 'added' ? '+' : line.kind === 'removed' ? '−' : ' '}\n {/* Screen readers hear the change, not the glyph. */}\n {line.kind === 'added' && <span className=\"sr-only\"> added</span>}\n {line.kind === 'removed' && <span className=\"sr-only\"> removed</span>}\n </span>\n )}\n <span className=\"whitespace-pre\">\n {line.text === ''\n ? ''\n : highlight\n ? tokenize(line.text).map((t, j) => (\n <span key={j} className={t.kind === 'plain' ? undefined : tokenClass[t.kind]}>\n {t.text}\n </span>\n ))\n : line.text}\n </span>\n </span>\n ))}\n </code>\n </pre>\n </div>\n )\n}\n"]}
|