@blurrow/ui 0.2.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +48 -36
- package/dist/Accordion.d.ts +17 -0
- package/dist/Accordion.js +138 -0
- package/dist/Accordion.js.map +1 -0
- package/dist/Alert.d.ts +13 -0
- package/dist/Alert.js +69 -0
- package/dist/Alert.js.map +1 -0
- package/dist/AuthorCard.d.ts +12 -0
- package/dist/AuthorCard.js +57 -0
- package/dist/AuthorCard.js.map +1 -0
- package/dist/Avatar.d.ts +21 -0
- package/dist/Avatar.js +96 -0
- package/dist/Avatar.js.map +1 -0
- package/dist/Badge.d.ts +12 -0
- package/dist/Badge.js +46 -0
- package/dist/Badge.js.map +1 -0
- package/dist/Banner.d.ts +15 -0
- package/dist/Banner.js +68 -0
- package/dist/Banner.js.map +1 -0
- package/dist/Breadcrumb.d.ts +13 -0
- package/dist/Breadcrumb.js +45 -0
- package/dist/Breadcrumb.js.map +1 -0
- package/dist/Button.d.ts +19 -0
- package/dist/Button.js +282 -0
- package/dist/Button.js.map +1 -0
- package/dist/ButtonGroup.d.ts +19 -0
- package/dist/ButtonGroup.js +62 -0
- package/dist/ButtonGroup.js.map +1 -0
- package/dist/Card.d.ts +40 -0
- package/dist/Card.js +175 -0
- package/dist/Card.js.map +1 -0
- package/dist/CardShell.d.ts +18 -0
- package/dist/CardShell.js +58 -0
- package/dist/CardShell.js.map +1 -0
- package/dist/Carousel.d.ts +22 -0
- package/dist/Carousel.js +247 -0
- package/dist/Carousel.js.map +1 -0
- package/dist/Checkbox.d.ts +15 -0
- package/dist/Checkbox.js +84 -0
- package/dist/Checkbox.js.map +1 -0
- package/dist/CloseButton.d.ts +12 -0
- package/dist/CloseButton.js +63 -0
- package/dist/CloseButton.js.map +1 -0
- package/dist/CodeBlock.d.ts +12 -0
- package/dist/CodeBlock.js +221 -0
- package/dist/CodeBlock.js.map +1 -0
- package/dist/ColorPicker.d.ts +24 -0
- package/dist/ColorPicker.js +366 -0
- package/dist/ColorPicker.js.map +1 -0
- package/dist/Combobox.d.ts +34 -0
- package/dist/Combobox.js +255 -0
- package/dist/Combobox.js.map +1 -0
- package/dist/CommandPalette.d.ts +25 -0
- package/dist/CommandPalette.js +304 -0
- package/dist/CommandPalette.js.map +1 -0
- package/dist/ContextMenu.d.ts +16 -0
- package/dist/ContextMenu.js +209 -0
- package/dist/ContextMenu.js.map +1 -0
- package/dist/DataList.d.ts +15 -0
- package/dist/DataList.js +42 -0
- package/dist/DataList.js.map +1 -0
- package/dist/DatePicker.d.ts +65 -0
- package/dist/DatePicker.js +391 -0
- package/dist/DatePicker.js.map +1 -0
- package/dist/DateRangePicker.d.ts +34 -0
- package/dist/DateRangePicker.js +180 -0
- package/dist/DateRangePicker.js.map +1 -0
- package/dist/Drawer.d.ts +17 -0
- package/dist/Drawer.js +132 -0
- package/dist/Drawer.js.map +1 -0
- package/dist/DropdownMenu.d.ts +23 -0
- package/dist/DropdownMenu.js +185 -0
- package/dist/DropdownMenu.js.map +1 -0
- package/dist/EmptyState.d.ts +13 -0
- package/dist/EmptyState.js +55 -0
- package/dist/EmptyState.js.map +1 -0
- package/dist/FieldMessage.d.ts +26 -0
- package/dist/FieldMessage.js +95 -0
- package/dist/FieldMessage.js.map +1 -0
- package/dist/FileUpload.d.ts +32 -0
- package/dist/FileUpload.js +253 -0
- package/dist/FileUpload.js.map +1 -0
- package/dist/Floating.d.ts +32 -0
- package/dist/Floating.js +95 -0
- package/dist/Floating.js.map +1 -0
- package/dist/HoverCard.d.ts +18 -0
- package/dist/HoverCard.js +90 -0
- package/dist/HoverCard.js.map +1 -0
- package/dist/Input.d.ts +17 -0
- package/dist/Input.js +96 -0
- package/dist/Input.js.map +1 -0
- package/dist/Kbd.d.ts +9 -0
- package/dist/Kbd.js +24 -0
- package/dist/Kbd.js.map +1 -0
- package/dist/Modal.d.ts +15 -0
- package/dist/Modal.js +109 -0
- package/dist/Modal.js.map +1 -0
- package/dist/NumberInput.d.ts +23 -0
- package/dist/NumberInput.js +162 -0
- package/dist/NumberInput.js.map +1 -0
- package/dist/OtpInput.d.ts +26 -0
- package/dist/OtpInput.js +173 -0
- package/dist/OtpInput.js.map +1 -0
- package/dist/Pagination.d.ts +11 -0
- package/dist/Pagination.js +148 -0
- package/dist/Pagination.js.map +1 -0
- package/dist/Popover.d.ts +13 -0
- package/dist/Popover.js +98 -0
- package/dist/Popover.js.map +1 -0
- package/dist/Progress.d.ts +12 -0
- package/dist/Progress.js +61 -0
- package/dist/Progress.js.map +1 -0
- package/dist/QuoteCard.d.ts +13 -0
- package/dist/QuoteCard.js +92 -0
- package/dist/QuoteCard.js.map +1 -0
- package/dist/Radio.d.ts +19 -0
- package/dist/Radio.js +161 -0
- package/dist/Radio.js.map +1 -0
- package/dist/RadioCards.d.ts +27 -0
- package/dist/RadioCards.js +205 -0
- package/dist/RadioCards.js.map +1 -0
- package/dist/ReactionBar.d.ts +15 -0
- package/dist/ReactionBar.js +92 -0
- package/dist/ReactionBar.js.map +1 -0
- package/dist/ReadingProgress.d.ts +8 -0
- package/dist/ReadingProgress.js +51 -0
- package/dist/ReadingProgress.js.map +1 -0
- package/dist/ReadingTime.d.ts +9 -0
- package/dist/ReadingTime.js +39 -0
- package/dist/ReadingTime.js.map +1 -0
- package/dist/Select.d.ts +20 -0
- package/dist/Select.js +244 -0
- package/dist/Select.js.map +1 -0
- package/dist/Separator.d.ts +14 -0
- package/dist/Separator.js +33 -0
- package/dist/Separator.js.map +1 -0
- package/dist/ShareButtons.d.ts +10 -0
- package/dist/ShareButtons.js +107 -0
- package/dist/ShareButtons.js.map +1 -0
- package/dist/Sidebar.d.ts +30 -0
- package/dist/Sidebar.js +140 -0
- package/dist/Sidebar.js.map +1 -0
- package/dist/Skeleton.d.ts +15 -0
- package/dist/Skeleton.js +67 -0
- package/dist/Skeleton.js.map +1 -0
- package/dist/Slider.d.ts +27 -0
- package/dist/Slider.js +182 -0
- package/dist/Slider.js.map +1 -0
- package/dist/Spinner.d.ts +12 -0
- package/dist/Spinner.js +24 -0
- package/dist/Spinner.js.map +1 -0
- package/dist/SpotlightCard.d.ts +17 -0
- package/dist/SpotlightCard.js +87 -0
- package/dist/SpotlightCard.js.map +1 -0
- package/dist/Stat.d.ts +19 -0
- package/dist/Stat.js +71 -0
- package/dist/Stat.js.map +1 -0
- package/dist/StatCard.d.ts +24 -0
- package/dist/StatCard.js +212 -0
- package/dist/StatCard.js.map +1 -0
- package/dist/Steps.d.ts +14 -0
- package/dist/Steps.js +94 -0
- package/dist/Steps.js.map +1 -0
- package/dist/Table.d.ts +21 -0
- package/dist/Table.js +93 -0
- package/dist/Table.js.map +1 -0
- package/dist/TableOfContents.d.ts +17 -0
- package/dist/TableOfContents.js +92 -0
- package/dist/TableOfContents.js.map +1 -0
- package/dist/Tabs.d.ts +17 -0
- package/dist/Tabs.js +123 -0
- package/dist/Tabs.js.map +1 -0
- package/dist/TagInput.d.ts +16 -0
- package/dist/TagInput.js +169 -0
- package/dist/TagInput.js.map +1 -0
- package/dist/Textarea.d.ts +13 -0
- package/dist/Textarea.js +74 -0
- package/dist/Textarea.js.map +1 -0
- package/dist/TimePicker.d.ts +28 -0
- package/dist/TimePicker.js +264 -0
- package/dist/TimePicker.js.map +1 -0
- package/dist/Timeline.d.ts +19 -0
- package/dist/Timeline.js +76 -0
- package/dist/Timeline.js.map +1 -0
- package/dist/Toast.d.ts +18 -0
- package/dist/Toast.js +318 -0
- package/dist/Toast.js.map +1 -0
- package/dist/Toggle.d.ts +13 -0
- package/dist/Toggle.js +84 -0
- package/dist/Toggle.js.map +1 -0
- package/dist/Tooltip.d.ts +13 -0
- package/dist/Tooltip.js +138 -0
- package/dist/Tooltip.js.map +1 -0
- package/dist/cli.js +172 -5
- package/dist/index.d.ts +68 -631
- package/dist/index.js +67 -5558
- package/dist/index.js.map +1 -1
- package/dist/registry/Accordion.tsx +6 -6
- package/dist/registry/Alert.tsx +13 -10
- package/dist/registry/AuthorCard.tsx +7 -7
- package/dist/registry/Avatar.tsx +5 -5
- package/dist/registry/Badge.tsx +12 -15
- package/dist/registry/Banner.tsx +15 -18
- package/dist/registry/Breadcrumb.tsx +3 -3
- package/dist/registry/Button.tsx +58 -69
- package/dist/registry/ButtonGroup.tsx +9 -9
- package/dist/registry/Card.tsx +15 -15
- package/dist/registry/CardShell.tsx +6 -6
- package/dist/registry/Carousel.tsx +19 -15
- package/dist/registry/Checkbox.tsx +14 -9
- package/dist/registry/CloseButton.tsx +2 -2
- package/dist/registry/CodeBlock.tsx +15 -15
- package/dist/registry/ColorPicker.tsx +404 -0
- package/dist/registry/Combobox.tsx +318 -0
- package/dist/registry/CommandPalette.tsx +31 -24
- package/dist/registry/ContextMenu.tsx +241 -0
- package/dist/registry/DataList.tsx +4 -4
- package/dist/registry/DatePicker.tsx +494 -0
- package/dist/registry/DateRangePicker.tsx +232 -0
- package/dist/registry/Drawer.tsx +17 -15
- package/dist/registry/DropdownMenu.tsx +39 -77
- package/dist/registry/EmptyState.tsx +8 -8
- package/dist/registry/FieldMessage.tsx +123 -0
- package/dist/registry/FileUpload.tsx +318 -0
- package/dist/registry/Floating.tsx +134 -0
- package/dist/registry/HoverCard.tsx +113 -0
- package/dist/registry/Input.tsx +54 -43
- package/dist/registry/Kbd.tsx +4 -5
- package/dist/registry/Modal.tsx +17 -15
- package/dist/registry/NumberInput.tsx +183 -0
- package/dist/registry/OtpInput.tsx +219 -0
- package/dist/registry/Pagination.tsx +15 -18
- package/dist/registry/Popover.tsx +40 -45
- package/dist/registry/Progress.tsx +4 -4
- package/dist/registry/QuoteCard.tsx +7 -7
- package/dist/registry/Radio.tsx +24 -21
- package/dist/registry/RadioCards.tsx +247 -0
- package/dist/registry/ReactionBar.tsx +5 -5
- package/dist/registry/ReadingProgress.tsx +2 -2
- package/dist/registry/ReadingTime.tsx +2 -2
- package/dist/registry/Select.tsx +28 -53
- package/dist/registry/Separator.tsx +52 -0
- package/dist/registry/ShareButtons.tsx +2 -2
- package/dist/registry/Sidebar.tsx +18 -18
- package/dist/registry/Skeleton.tsx +1 -1
- package/dist/registry/Slider.tsx +229 -0
- package/dist/registry/Spinner.tsx +32 -0
- package/dist/registry/SpotlightCard.tsx +6 -6
- package/dist/registry/Stat.tsx +4 -4
- package/dist/registry/StatCard.tsx +19 -19
- package/dist/registry/Steps.tsx +7 -7
- package/dist/registry/Table.tsx +12 -10
- package/dist/registry/TableOfContents.tsx +8 -8
- package/dist/registry/Tabs.tsx +6 -6
- package/dist/registry/TagInput.tsx +9 -9
- package/dist/registry/Textarea.tsx +5 -5
- package/dist/registry/TimePicker.tsx +315 -0
- package/dist/registry/Timeline.tsx +14 -14
- package/dist/registry/Toast.tsx +15 -12
- package/dist/registry/Toggle.tsx +7 -10
- package/dist/registry/Tooltip.tsx +21 -73
- package/dist/registry/styles.css +868 -62
- package/dist/registry/useFloatingPanel.ts +112 -0
- package/dist/styles.css +868 -62
- package/dist/useFloatingPanel.d.ts +24 -0
- package/dist/useFloatingPanel.js +89 -0
- package/dist/useFloatingPanel.js.map +1 -0
- package/dist/useModalBehavior.d.ts +15 -0
- package/dist/useModalBehavior.js +57 -0
- package/dist/useModalBehavior.js.map +1 -0
- package/package.json +1 -1
package/dist/Checkbox.js
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
// ../../components/ui/Checkbox.tsx
|
|
4
|
+
import { useState, useId } from "react";
|
|
5
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
6
|
+
function Checkbox({
|
|
7
|
+
checked,
|
|
8
|
+
defaultChecked = false,
|
|
9
|
+
onChange,
|
|
10
|
+
label,
|
|
11
|
+
description,
|
|
12
|
+
disabled = false,
|
|
13
|
+
indeterminate = false,
|
|
14
|
+
className = ""
|
|
15
|
+
}) {
|
|
16
|
+
const [internal, setInternal] = useState(defaultChecked);
|
|
17
|
+
const uid = useId();
|
|
18
|
+
const isChecked = checked !== void 0 ? checked : internal;
|
|
19
|
+
const toggle = () => {
|
|
20
|
+
if (disabled) return;
|
|
21
|
+
const next = !isChecked;
|
|
22
|
+
setInternal(next);
|
|
23
|
+
onChange?.(next);
|
|
24
|
+
};
|
|
25
|
+
const active = isChecked || indeterminate;
|
|
26
|
+
return /* @__PURE__ */ jsxs(
|
|
27
|
+
"div",
|
|
28
|
+
{
|
|
29
|
+
className: [
|
|
30
|
+
"flex items-center justify-between gap-4 select-none",
|
|
31
|
+
disabled ? "opacity-40 pointer-events-none" : "cursor-pointer group/checkbox",
|
|
32
|
+
className
|
|
33
|
+
].join(" "),
|
|
34
|
+
onClick: toggle,
|
|
35
|
+
children: [
|
|
36
|
+
(label || description) && /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-0.5 min-w-0", children: [
|
|
37
|
+
label && /* @__PURE__ */ jsx("span", { id: `${uid}-label`, className: "text-[13px] font-medium text-ink leading-snug", children: label }),
|
|
38
|
+
description && /* @__PURE__ */ jsx("span", { id: `${uid}-desc`, className: "text-[12px] text-ink-muted leading-relaxed", children: description })
|
|
39
|
+
] }),
|
|
40
|
+
/* @__PURE__ */ jsx(
|
|
41
|
+
"button",
|
|
42
|
+
{
|
|
43
|
+
type: "button",
|
|
44
|
+
role: "checkbox",
|
|
45
|
+
"aria-checked": indeterminate ? "mixed" : isChecked,
|
|
46
|
+
"aria-labelledby": label ? `${uid}-label` : void 0,
|
|
47
|
+
"aria-describedby": description ? `${uid}-desc` : void 0,
|
|
48
|
+
disabled,
|
|
49
|
+
className: [
|
|
50
|
+
"shrink-0 w-[22px] h-[22px] rounded-[7px] flex items-center justify-center cursor-pointer text-ink-inverse",
|
|
51
|
+
"transition-[box-shadow,transform,scale] duration-200 ease-out active:scale-90",
|
|
52
|
+
"focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ink",
|
|
53
|
+
// an empty box answers the pointer like any other field
|
|
54
|
+
active ? "" : "group-hover/checkbox:[box-shadow:var(--field-shadow-hover)]"
|
|
55
|
+
].join(" "),
|
|
56
|
+
style: {
|
|
57
|
+
background: active ? "var(--face-inverse)" : "var(--field)",
|
|
58
|
+
boxShadow: active ? "var(--face-inverse-shadow)" : "var(--field-shadow)"
|
|
59
|
+
},
|
|
60
|
+
children: active && (indeterminate ? /* @__PURE__ */ jsx("span", { className: "animate-checkbox-in", children: /* @__PURE__ */ jsx("svg", { width: "10", height: "2", viewBox: "0 0 10 2", fill: "none", children: /* @__PURE__ */ jsx("rect", { width: "10", height: "2", rx: "1", fill: "currentColor" }) }) }) : (
|
|
61
|
+
/* The mark is pressed into the face: it takes the inverse ink, so it
|
|
62
|
+
reads on the dark face in light mode and the pale one in dark */
|
|
63
|
+
/* @__PURE__ */ jsx("svg", { width: "13", height: "10", viewBox: "0 0 13 10", fill: "none", style: { filter: "drop-shadow(var(--emboss-inverse))" }, children: /* @__PURE__ */ jsx(
|
|
64
|
+
"path",
|
|
65
|
+
{
|
|
66
|
+
d: "M1.5 5l3.5 3.5L11.5 1",
|
|
67
|
+
stroke: "currentColor",
|
|
68
|
+
strokeWidth: "2",
|
|
69
|
+
strokeLinecap: "round",
|
|
70
|
+
strokeLinejoin: "round",
|
|
71
|
+
className: "animate-draw-check"
|
|
72
|
+
}
|
|
73
|
+
) })
|
|
74
|
+
))
|
|
75
|
+
}
|
|
76
|
+
)
|
|
77
|
+
]
|
|
78
|
+
}
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
export {
|
|
82
|
+
Checkbox
|
|
83
|
+
};
|
|
84
|
+
//# sourceMappingURL=Checkbox.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../components/ui/Checkbox.tsx"],"sourcesContent":["\"use client\";\n\nimport React, { useState, useId } from \"react\";\n\ninterface CheckboxProps {\n checked?: boolean;\n defaultChecked?: boolean;\n onChange?: (checked: boolean) => void;\n label?: string;\n description?: string;\n disabled?: boolean;\n indeterminate?: boolean;\n className?: string;\n}\n\nexport function Checkbox({\n checked,\n defaultChecked = false,\n onChange,\n label,\n description,\n disabled = false,\n indeterminate = false,\n className = \"\",\n}: CheckboxProps) {\n const [internal, setInternal] = useState(defaultChecked);\n const uid = useId();\n const isChecked = checked !== undefined ? checked : internal;\n\n const toggle = () => {\n if (disabled) return;\n const next = !isChecked;\n setInternal(next);\n onChange?.(next);\n };\n\n const active = isChecked || indeterminate;\n\n return (\n <div\n className={[\n \"flex items-center justify-between gap-4 select-none\",\n disabled ? \"opacity-40 pointer-events-none\" : \"cursor-pointer group/checkbox\",\n className,\n ].join(\" \")}\n onClick={toggle}\n >\n {(label || description) && (\n <div className=\"flex flex-col gap-0.5 min-w-0\">\n {label && (\n <span id={`${uid}-label`} className=\"text-[13px] font-medium text-ink leading-snug\">{label}</span>\n )}\n {description && (\n <span id={`${uid}-desc`} className=\"text-[12px] text-ink-muted leading-relaxed\">{description}</span>\n )}\n </div>\n )}\n\n {/* Clicks bubble to the row, so the control itself has no onClick */}\n <button\n type=\"button\"\n role=\"checkbox\"\n aria-checked={indeterminate ? \"mixed\" : isChecked}\n aria-labelledby={label ? `${uid}-label` : undefined}\n aria-describedby={description ? `${uid}-desc` : undefined}\n disabled={disabled}\n className={[\n \"shrink-0 w-[22px] h-[22px] rounded-[7px] flex items-center justify-center cursor-pointer text-ink-inverse\",\n \"transition-[box-shadow,transform,scale] duration-200 ease-out active:scale-90\",\n \"focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ink\",\n // an empty box answers the pointer like any other field\n active ? \"\" : \"group-hover/checkbox:[box-shadow:var(--field-shadow-hover)]\",\n ].join(\" \")}\n style={{\n background: active ? \"var(--face-inverse)\" : \"var(--field)\",\n boxShadow: active ? \"var(--face-inverse-shadow)\" : \"var(--field-shadow)\",\n }}\n >\n {active && (\n indeterminate ? (\n <span className=\"animate-checkbox-in\">\n <svg width=\"10\" height=\"2\" viewBox=\"0 0 10 2\" fill=\"none\">\n <rect width=\"10\" height=\"2\" rx=\"1\" fill=\"currentColor\" />\n </svg>\n </span>\n ) : (\n /* The mark is pressed into the face: it takes the inverse ink, so it\n reads on the dark face in light mode and the pale one in dark */\n <svg width=\"13\" height=\"10\" viewBox=\"0 0 13 10\" fill=\"none\" style={{ filter: \"drop-shadow(var(--emboss-inverse))\" }}>\n <path\n d=\"M1.5 5l3.5 3.5L11.5 1\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className=\"animate-draw-check\"\n />\n </svg>\n )\n )}\n </button>\n </div>\n );\n}\n"],"mappings":";;;AAEA,SAAgB,UAAU,aAAa;AA8C/B,SAEI,KAFJ;AAjCD,SAAS,SAAS;AAAA,EACvB;AAAA,EACA,iBAAiB;AAAA,EACjB;AAAA,EACA;AAAA,EACA;AAAA,EACA,WAAW;AAAA,EACX,gBAAgB;AAAA,EAChB,YAAY;AACd,GAAkB;AAChB,QAAM,CAAC,UAAU,WAAW,IAAI,SAAS,cAAc;AACvD,QAAM,MAAM,MAAM;AAClB,QAAM,YAAY,YAAY,SAAY,UAAU;AAEpD,QAAM,SAAS,MAAM;AACnB,QAAI,SAAU;AACd,UAAM,OAAO,CAAC;AACd,gBAAY,IAAI;AAChB,eAAW,IAAI;AAAA,EACjB;AAEA,QAAM,SAAS,aAAa;AAE5B,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAW;AAAA,QACT;AAAA,QACA,WAAW,mCAAmC;AAAA,QAC9C;AAAA,MACF,EAAE,KAAK,GAAG;AAAA,MACV,SAAS;AAAA,MAEP;AAAA,kBAAS,gBACT,qBAAC,SAAI,WAAU,iCACZ;AAAA,mBACC,oBAAC,UAAK,IAAI,GAAG,GAAG,UAAU,WAAU,iDAAiD,iBAAM;AAAA,UAE5F,eACC,oBAAC,UAAK,IAAI,GAAG,GAAG,SAAS,WAAU,8CAA8C,uBAAY;AAAA,WAEjG;AAAA,QAIF;AAAA,UAAC;AAAA;AAAA,YACC,MAAK;AAAA,YACL,MAAK;AAAA,YACL,gBAAc,gBAAgB,UAAU;AAAA,YACxC,mBAAiB,QAAQ,GAAG,GAAG,WAAW;AAAA,YAC1C,oBAAkB,cAAc,GAAG,GAAG,UAAU;AAAA,YAChD;AAAA,YACA,WAAW;AAAA,cACT;AAAA,cACA;AAAA,cACA;AAAA;AAAA,cAEA,SAAS,KAAK;AAAA,YAChB,EAAE,KAAK,GAAG;AAAA,YACV,OAAO;AAAA,cACL,YAAY,SAAS,wBAAwB;AAAA,cAC7C,WAAW,SAAS,+BAA+B;AAAA,YACrD;AAAA,YAEC,qBACC,gBACE,oBAAC,UAAK,WAAU,uBACd,8BAAC,SAAI,OAAM,MAAK,QAAO,KAAI,SAAQ,YAAW,MAAK,QACjD,8BAAC,UAAK,OAAM,MAAK,QAAO,KAAI,IAAG,KAAI,MAAK,gBAAe,GACzD,GACF;AAAA;AAAA;AAAA,cAIA,oBAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,OAAO,EAAE,QAAQ,qCAAqC,GAChH;AAAA,gBAAC;AAAA;AAAA,kBACC,GAAE;AAAA,kBACF,QAAO;AAAA,kBACP,aAAY;AAAA,kBACZ,eAAc;AAAA,kBACd,gBAAe;AAAA,kBACf,WAAU;AAAA;AAAA,cACZ,GACF;AAAA;AAAA;AAAA,QAGN;AAAA;AAAA;AAAA,EACF;AAEJ;","names":[]}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
|
|
3
|
+
interface CloseButtonProps {
|
|
4
|
+
onClick?: () => void;
|
|
5
|
+
label?: string;
|
|
6
|
+
size?: "sm" | "md";
|
|
7
|
+
tone?: "light" | "dark";
|
|
8
|
+
className?: string;
|
|
9
|
+
}
|
|
10
|
+
declare function CloseButton({ onClick, label, size, tone, className, }: CloseButtonProps): react_jsx_runtime.JSX.Element;
|
|
11
|
+
|
|
12
|
+
export { CloseButton };
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
// ../../components/ui/CloseButton.tsx
|
|
4
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
5
|
+
var sizes = {
|
|
6
|
+
sm: { box: "w-6 h-6 rounded-[7px]", icon: 9 },
|
|
7
|
+
md: { box: "w-7 h-7 rounded-[8px]", icon: 10 }
|
|
8
|
+
};
|
|
9
|
+
function CloseButton({
|
|
10
|
+
onClick,
|
|
11
|
+
label = "Close",
|
|
12
|
+
size = "md",
|
|
13
|
+
tone = "light",
|
|
14
|
+
className = ""
|
|
15
|
+
}) {
|
|
16
|
+
const dark = tone === "dark";
|
|
17
|
+
const s = sizes[size];
|
|
18
|
+
return /* @__PURE__ */ jsxs(
|
|
19
|
+
"button",
|
|
20
|
+
{
|
|
21
|
+
type: "button",
|
|
22
|
+
onClick,
|
|
23
|
+
"aria-label": label,
|
|
24
|
+
className: [
|
|
25
|
+
"group/close relative shrink-0 flex items-center justify-center cursor-pointer",
|
|
26
|
+
"transition-[color,background,scale] duration-150 active:scale-95",
|
|
27
|
+
"focus-visible:outline-2 focus-visible:outline-offset-2",
|
|
28
|
+
dark ? "text-white/45 hover:text-white focus-visible:outline-white" : "text-ink-faint hover:text-ink focus-visible:outline-ink",
|
|
29
|
+
s.box,
|
|
30
|
+
className
|
|
31
|
+
].join(" "),
|
|
32
|
+
children: [
|
|
33
|
+
/* @__PURE__ */ jsx(
|
|
34
|
+
"span",
|
|
35
|
+
{
|
|
36
|
+
"aria-hidden": true,
|
|
37
|
+
className: [
|
|
38
|
+
"absolute inset-0 rounded-[inherit] opacity-0 group-hover/close:opacity-100 transition-opacity duration-150",
|
|
39
|
+
dark ? "[background:var(--tile-dark)] [box-shadow:var(--tile-dark-shadow)]" : "[background:var(--face)] [box-shadow:var(--face-shadow)]"
|
|
40
|
+
].join(" ")
|
|
41
|
+
}
|
|
42
|
+
),
|
|
43
|
+
/* @__PURE__ */ jsx(
|
|
44
|
+
"svg",
|
|
45
|
+
{
|
|
46
|
+
className: "relative",
|
|
47
|
+
width: s.icon,
|
|
48
|
+
height: s.icon,
|
|
49
|
+
fill: "none",
|
|
50
|
+
stroke: "currentColor",
|
|
51
|
+
strokeWidth: "2.5",
|
|
52
|
+
viewBox: "0 0 24 24",
|
|
53
|
+
children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M6 18L18 6M6 6l12 12" })
|
|
54
|
+
}
|
|
55
|
+
)
|
|
56
|
+
]
|
|
57
|
+
}
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
export {
|
|
61
|
+
CloseButton
|
|
62
|
+
};
|
|
63
|
+
//# sourceMappingURL=CloseButton.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../components/ui/CloseButton.tsx"],"sourcesContent":["\"use client\";\n\nimport React from \"react\";\n\ninterface CloseButtonProps {\n onClick?: () => void;\n label?: string;\n size?: \"sm\" | \"md\";\n tone?: \"light\" | \"dark\";\n className?: string;\n}\n\nconst sizes = {\n sm: { box: \"w-6 h-6 rounded-[7px]\", icon: 9 },\n md: { box: \"w-7 h-7 rounded-[8px]\", icon: 10 },\n};\n\n/* Quiet until hovered, then it rises into a raised face like every other\n pressable thing — so it reads as a control, not decoration. */\nexport function CloseButton({\n onClick,\n label = \"Close\",\n size = \"md\",\n tone = \"light\",\n className = \"\",\n}: CloseButtonProps) {\n const dark = tone === \"dark\";\n const s = sizes[size];\n\n return (\n <button\n type=\"button\"\n onClick={onClick}\n aria-label={label}\n className={[\n \"group/close relative shrink-0 flex items-center justify-center cursor-pointer\",\n \"transition-[color,background,scale] duration-150 active:scale-95\",\n \"focus-visible:outline-2 focus-visible:outline-offset-2\",\n dark\n ? \"text-white/45 hover:text-white focus-visible:outline-white\"\n : \"text-ink-faint hover:text-ink focus-visible:outline-ink\",\n s.box,\n className,\n ].join(\" \")}\n >\n <span\n aria-hidden\n className={[\n \"absolute inset-0 rounded-[inherit] opacity-0 group-hover/close:opacity-100 transition-opacity duration-150\",\n dark\n ? \"[background:var(--tile-dark)] [box-shadow:var(--tile-dark-shadow)]\"\n : \"[background:var(--face)] [box-shadow:var(--face-shadow)]\",\n ].join(\" \")}\n />\n <svg\n className=\"relative\"\n width={s.icon}\n height={s.icon}\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2.5\"\n viewBox=\"0 0 24 24\"\n >\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n </button>\n );\n}\n"],"mappings":";;;AA8BI,SAeE,KAfF;AAlBJ,IAAM,QAAQ;AAAA,EACZ,IAAI,EAAE,KAAK,yBAAyB,MAAM,EAAE;AAAA,EAC5C,IAAI,EAAE,KAAK,yBAAyB,MAAM,GAAG;AAC/C;AAIO,SAAS,YAAY;AAAA,EAC1B;AAAA,EACA,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,OAAO;AAAA,EACP,YAAY;AACd,GAAqB;AACnB,QAAM,OAAO,SAAS;AACtB,QAAM,IAAI,MAAM,IAAI;AAEpB,SACE;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL;AAAA,MACA,cAAY;AAAA,MACZ,WAAW;AAAA,QACT;AAAA,QACA;AAAA,QACA;AAAA,QACA,OACI,+DACA;AAAA,QACJ,EAAE;AAAA,QACF;AAAA,MACF,EAAE,KAAK,GAAG;AAAA,MAEV;AAAA;AAAA,UAAC;AAAA;AAAA,YACC,eAAW;AAAA,YACX,WAAW;AAAA,cACT;AAAA,cACA,OACI,uEACA;AAAA,YACN,EAAE,KAAK,GAAG;AAAA;AAAA,QACZ;AAAA,QACA;AAAA,UAAC;AAAA;AAAA,YACC,WAAU;AAAA,YACV,OAAO,EAAE;AAAA,YACT,QAAQ,EAAE;AAAA,YACV,MAAK;AAAA,YACL,QAAO;AAAA,YACP,aAAY;AAAA,YACZ,SAAQ;AAAA,YAER,8BAAC,UAAK,eAAc,SAAQ,gBAAe,SAAQ,GAAE,wBAAuB;AAAA;AAAA,QAC9E;AAAA;AAAA;AAAA,EACF;AAEJ;","names":[]}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
|
|
3
|
+
interface CodeBlockProps {
|
|
4
|
+
code: string;
|
|
5
|
+
language?: string;
|
|
6
|
+
showLineNumbers?: boolean;
|
|
7
|
+
title?: string;
|
|
8
|
+
className?: string;
|
|
9
|
+
}
|
|
10
|
+
declare function CodeBlock({ code, language, showLineNumbers, title, className, }: CodeBlockProps): react_jsx_runtime.JSX.Element;
|
|
11
|
+
|
|
12
|
+
export { CodeBlock };
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
// ../../components/ui/CodeBlock.tsx
|
|
4
|
+
import { useState, useCallback, useMemo, useRef } from "react";
|
|
5
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
6
|
+
var KEYWORDS = /* @__PURE__ */ new Set([
|
|
7
|
+
"import",
|
|
8
|
+
"from",
|
|
9
|
+
"export",
|
|
10
|
+
"default",
|
|
11
|
+
"function",
|
|
12
|
+
"return",
|
|
13
|
+
"const",
|
|
14
|
+
"let",
|
|
15
|
+
"var",
|
|
16
|
+
"if",
|
|
17
|
+
"else",
|
|
18
|
+
"for",
|
|
19
|
+
"while",
|
|
20
|
+
"do",
|
|
21
|
+
"class",
|
|
22
|
+
"extends",
|
|
23
|
+
"new",
|
|
24
|
+
"typeof",
|
|
25
|
+
"instanceof",
|
|
26
|
+
"null",
|
|
27
|
+
"undefined",
|
|
28
|
+
"true",
|
|
29
|
+
"false",
|
|
30
|
+
"async",
|
|
31
|
+
"await",
|
|
32
|
+
"try",
|
|
33
|
+
"catch",
|
|
34
|
+
"throw",
|
|
35
|
+
"finally",
|
|
36
|
+
"interface",
|
|
37
|
+
"type",
|
|
38
|
+
"enum",
|
|
39
|
+
"as",
|
|
40
|
+
"in",
|
|
41
|
+
"of",
|
|
42
|
+
"switch",
|
|
43
|
+
"case",
|
|
44
|
+
"break",
|
|
45
|
+
"continue",
|
|
46
|
+
"void",
|
|
47
|
+
"never",
|
|
48
|
+
"any",
|
|
49
|
+
"string",
|
|
50
|
+
"number",
|
|
51
|
+
"boolean",
|
|
52
|
+
"public",
|
|
53
|
+
"private",
|
|
54
|
+
"protected",
|
|
55
|
+
"static",
|
|
56
|
+
"abstract",
|
|
57
|
+
"readonly"
|
|
58
|
+
]);
|
|
59
|
+
var TOKEN_RE = /(\/\/.*$|"(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*'|`(?:[^`\\]|\\.)*`|<\/?\s*[A-Z][a-zA-Z0-9.]*|<\/?\s*[a-z][a-zA-Z0-9-]*|=>|\b\d+(?:\.\d+)?\b|\b[a-zA-Z_$][a-zA-Z0-9_$]*\b)/;
|
|
60
|
+
var TOKEN_STYLES = {
|
|
61
|
+
keyword: "text-code-keyword",
|
|
62
|
+
string: "text-code-string",
|
|
63
|
+
comment: "text-ink-faint italic",
|
|
64
|
+
tag: "text-code-tag",
|
|
65
|
+
number: "text-code-number"
|
|
66
|
+
};
|
|
67
|
+
function classifyToken(val) {
|
|
68
|
+
if (val.startsWith("//")) return "comment";
|
|
69
|
+
if (val[0] === '"' || val[0] === "'" || val[0] === "`") return "string";
|
|
70
|
+
if (val[0] === "<") return "tag";
|
|
71
|
+
if (val === "=>") return "keyword";
|
|
72
|
+
if (/^\d/.test(val)) return "number";
|
|
73
|
+
if (KEYWORDS.has(val)) return "keyword";
|
|
74
|
+
return "plain";
|
|
75
|
+
}
|
|
76
|
+
function tokenizeLine(line) {
|
|
77
|
+
const tokens = [];
|
|
78
|
+
const re = new RegExp(TOKEN_RE.source, "g");
|
|
79
|
+
let lastIndex = 0;
|
|
80
|
+
let match;
|
|
81
|
+
while ((match = re.exec(line)) !== null) {
|
|
82
|
+
if (match.index > lastIndex) {
|
|
83
|
+
tokens.push({ type: "plain", value: line.slice(lastIndex, match.index) });
|
|
84
|
+
}
|
|
85
|
+
tokens.push({ type: classifyToken(match[0]), value: match[0] });
|
|
86
|
+
lastIndex = re.lastIndex;
|
|
87
|
+
}
|
|
88
|
+
if (lastIndex < line.length) {
|
|
89
|
+
tokens.push({ type: "plain", value: line.slice(lastIndex) });
|
|
90
|
+
}
|
|
91
|
+
return tokens;
|
|
92
|
+
}
|
|
93
|
+
var HIGHLIGHTABLE = /* @__PURE__ */ new Set(["js", "jsx", "ts", "tsx", "javascript", "typescript"]);
|
|
94
|
+
function CodeBlock({
|
|
95
|
+
code,
|
|
96
|
+
language,
|
|
97
|
+
showLineNumbers = false,
|
|
98
|
+
title,
|
|
99
|
+
className = ""
|
|
100
|
+
}) {
|
|
101
|
+
const [copied, setCopied] = useState(false);
|
|
102
|
+
const timer = useRef(null);
|
|
103
|
+
const handleCopy = useCallback(() => {
|
|
104
|
+
navigator.clipboard.writeText(code).then(() => {
|
|
105
|
+
setCopied(true);
|
|
106
|
+
if (timer.current) clearTimeout(timer.current);
|
|
107
|
+
timer.current = setTimeout(() => setCopied(false), 2e3);
|
|
108
|
+
});
|
|
109
|
+
}, [code]);
|
|
110
|
+
const highlight = language ? HIGHLIGHTABLE.has(language.toLowerCase()) : false;
|
|
111
|
+
const lines = useMemo(() => code.split("\n"), [code]);
|
|
112
|
+
const tokenized = useMemo(
|
|
113
|
+
() => highlight ? lines.map((line) => tokenizeLine(line)) : null,
|
|
114
|
+
[lines, highlight]
|
|
115
|
+
);
|
|
116
|
+
return (
|
|
117
|
+
/* The header lives in the bezel and the code sits on the raised face,
|
|
118
|
+
so the filename reads as a label on the object, not part of it. */
|
|
119
|
+
/* @__PURE__ */ jsxs(
|
|
120
|
+
"figure",
|
|
121
|
+
{
|
|
122
|
+
className: ["rounded-[18px] p-1.5 pt-0 m-0", className].filter(Boolean).join(" "),
|
|
123
|
+
style: { background: "var(--panel-bezel)", boxShadow: "var(--panel-shadow)" },
|
|
124
|
+
children: [
|
|
125
|
+
/* @__PURE__ */ jsxs("figcaption", { className: "flex items-center justify-between gap-3 pl-3 pr-0.5 h-10", children: [
|
|
126
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 min-w-0", children: [
|
|
127
|
+
title && /* @__PURE__ */ jsx("span", { className: "text-[12px] font-medium text-ink-label truncate", children: title }),
|
|
128
|
+
language && /* @__PURE__ */ jsx(
|
|
129
|
+
"span",
|
|
130
|
+
{
|
|
131
|
+
className: "text-[11px] font-semibold text-ink-muted lowercase px-1.5 py-0.5 rounded-[5px]",
|
|
132
|
+
style: { background: "var(--well)", boxShadow: "var(--well-shadow)" },
|
|
133
|
+
children: language
|
|
134
|
+
}
|
|
135
|
+
)
|
|
136
|
+
] }),
|
|
137
|
+
/* @__PURE__ */ jsx(
|
|
138
|
+
"button",
|
|
139
|
+
{
|
|
140
|
+
type: "button",
|
|
141
|
+
onClick: handleCopy,
|
|
142
|
+
"aria-label": copied ? "copied to clipboard" : "copy code",
|
|
143
|
+
className: "inline-flex items-center h-7 px-2.5 rounded-[8px] text-[11.5px] font-medium cursor-pointer transition-[color,transform,scale] duration-150 active:scale-95 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ink",
|
|
144
|
+
style: {
|
|
145
|
+
background: "var(--face)",
|
|
146
|
+
boxShadow: "var(--face-shadow)",
|
|
147
|
+
color: copied ? "var(--success-strong)" : void 0
|
|
148
|
+
},
|
|
149
|
+
children: /* @__PURE__ */ jsxs("span", { className: "grid overflow-hidden text-ink-body", style: { color: "inherit" }, children: [
|
|
150
|
+
/* @__PURE__ */ jsxs(
|
|
151
|
+
"span",
|
|
152
|
+
{
|
|
153
|
+
"aria-hidden": true,
|
|
154
|
+
className: "[grid-area:1/1] inline-flex items-center justify-center gap-1.5",
|
|
155
|
+
style: {
|
|
156
|
+
transform: copied ? "translateY(-110%)" : "none",
|
|
157
|
+
opacity: copied ? 0 : 1,
|
|
158
|
+
filter: copied ? "blur(2px)" : "none",
|
|
159
|
+
transition: "transform 320ms var(--ease-out-soft), opacity 220ms ease, filter 220ms ease"
|
|
160
|
+
},
|
|
161
|
+
children: [
|
|
162
|
+
/* @__PURE__ */ jsxs("svg", { width: "12", height: "12", fill: "none", stroke: "currentColor", strokeWidth: "2", viewBox: "0 0 24 24", children: [
|
|
163
|
+
/* @__PURE__ */ jsx("rect", { x: "9", y: "9", width: "13", height: "13", rx: "2" }),
|
|
164
|
+
/* @__PURE__ */ jsx("path", { d: "M5 15H4a2 2 0 01-2-2V4a2 2 0 012-2h9a2 2 0 012 2v1" })
|
|
165
|
+
] }),
|
|
166
|
+
"copy"
|
|
167
|
+
]
|
|
168
|
+
}
|
|
169
|
+
),
|
|
170
|
+
/* @__PURE__ */ jsxs(
|
|
171
|
+
"span",
|
|
172
|
+
{
|
|
173
|
+
"aria-hidden": true,
|
|
174
|
+
className: "[grid-area:1/1] inline-flex items-center justify-center gap-1.5",
|
|
175
|
+
style: {
|
|
176
|
+
transform: copied ? "none" : "translateY(110%)",
|
|
177
|
+
opacity: copied ? 1 : 0,
|
|
178
|
+
filter: copied ? "none" : "blur(2px)",
|
|
179
|
+
transition: "transform 380ms var(--ease-spring), opacity 220ms ease, filter 220ms ease"
|
|
180
|
+
},
|
|
181
|
+
children: [
|
|
182
|
+
/* @__PURE__ */ jsx("svg", { width: "12", height: "12", fill: "none", stroke: "currentColor", strokeWidth: "2.25", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx(
|
|
183
|
+
"path",
|
|
184
|
+
{
|
|
185
|
+
strokeLinecap: "round",
|
|
186
|
+
strokeLinejoin: "round",
|
|
187
|
+
d: "M5 13l4 4L19 7",
|
|
188
|
+
pathLength: 15,
|
|
189
|
+
className: copied ? "animate-draw-check" : ""
|
|
190
|
+
},
|
|
191
|
+
String(copied)
|
|
192
|
+
) }),
|
|
193
|
+
"copied"
|
|
194
|
+
]
|
|
195
|
+
}
|
|
196
|
+
)
|
|
197
|
+
] })
|
|
198
|
+
}
|
|
199
|
+
),
|
|
200
|
+
/* @__PURE__ */ jsx("span", { "aria-live": "polite", className: "sr-only", children: copied ? "copied to clipboard" : "" })
|
|
201
|
+
] }),
|
|
202
|
+
/* @__PURE__ */ jsx(
|
|
203
|
+
"div",
|
|
204
|
+
{
|
|
205
|
+
className: "bg-panel-face rounded-[13px] overflow-x-auto scroll-thin",
|
|
206
|
+
style: { boxShadow: "var(--panel-face-shadow)" },
|
|
207
|
+
children: /* @__PURE__ */ jsx("pre", { className: "py-4 px-4 text-[13px] leading-[1.7] font-mono text-ink-soft", children: /* @__PURE__ */ jsx("code", { children: lines.map((line, i) => /* @__PURE__ */ jsxs("div", { className: "flex", children: [
|
|
208
|
+
showLineNumbers && /* @__PURE__ */ jsx("span", { "aria-hidden": true, className: "select-none w-8 shrink-0 text-right pr-4 text-ink-ghost tabular-nums", children: i + 1 }),
|
|
209
|
+
/* @__PURE__ */ jsx("span", { className: "flex-1", children: tokenized && tokenized[i].length ? tokenized[i].map((tok, j) => /* @__PURE__ */ jsx("span", { className: TOKEN_STYLES[tok.type] || "", children: tok.value }, j)) : line || "\n" })
|
|
210
|
+
] }, i)) }) })
|
|
211
|
+
}
|
|
212
|
+
)
|
|
213
|
+
]
|
|
214
|
+
}
|
|
215
|
+
)
|
|
216
|
+
);
|
|
217
|
+
}
|
|
218
|
+
export {
|
|
219
|
+
CodeBlock
|
|
220
|
+
};
|
|
221
|
+
//# sourceMappingURL=CodeBlock.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../components/ui/CodeBlock.tsx"],"sourcesContent":["\"use client\";\n\nimport React, { useState, useCallback, useMemo, useRef } from \"react\";\n\ninterface CodeBlockProps {\n code: string;\n language?: string;\n showLineNumbers?: boolean;\n title?: string;\n className?: string;\n}\n\nconst KEYWORDS = new Set([\n \"import\", \"from\", \"export\", \"default\", \"function\", \"return\",\n \"const\", \"let\", \"var\", \"if\", \"else\", \"for\", \"while\", \"do\",\n \"class\", \"extends\", \"new\", \"typeof\", \"instanceof\",\n \"null\", \"undefined\", \"true\", \"false\",\n \"async\", \"await\", \"try\", \"catch\", \"throw\", \"finally\",\n \"interface\", \"type\", \"enum\", \"as\", \"in\", \"of\",\n \"switch\", \"case\", \"break\", \"continue\",\n \"void\", \"never\", \"any\", \"string\", \"number\", \"boolean\",\n \"public\", \"private\", \"protected\", \"static\", \"abstract\", \"readonly\",\n]);\n\nconst TOKEN_RE = /(\\/\\/.*$|\"(?:[^\"\\\\]|\\\\.)*\"|'(?:[^'\\\\]|\\\\.)*'|`(?:[^`\\\\]|\\\\.)*`|<\\/?\\s*[A-Z][a-zA-Z0-9.]*|<\\/?\\s*[a-z][a-zA-Z0-9-]*|=>|\\b\\d+(?:\\.\\d+)?\\b|\\b[a-zA-Z_$][a-zA-Z0-9_$]*\\b)/;\n\nconst TOKEN_STYLES: Record<string, string> = {\n keyword: \"text-code-keyword\",\n string: \"text-code-string\",\n comment: \"text-ink-faint italic\",\n tag: \"text-code-tag\",\n number: \"text-code-number\",\n};\n\nfunction classifyToken(val: string): string {\n if (val.startsWith(\"//\")) return \"comment\";\n if (val[0] === '\"' || val[0] === \"'\" || val[0] === \"`\") return \"string\";\n if (val[0] === \"<\") return \"tag\";\n if (val === \"=>\") return \"keyword\";\n if (/^\\d/.test(val)) return \"number\";\n if (KEYWORDS.has(val)) return \"keyword\";\n return \"plain\";\n}\n\nfunction tokenizeLine(line: string): { type: string; value: string }[] {\n const tokens: { type: string; value: string }[] = [];\n const re = new RegExp(TOKEN_RE.source, \"g\");\n let lastIndex = 0;\n let match;\n\n while ((match = re.exec(line)) !== null) {\n if (match.index > lastIndex) {\n tokens.push({ type: \"plain\", value: line.slice(lastIndex, match.index) });\n }\n tokens.push({ type: classifyToken(match[0]), value: match[0] });\n lastIndex = re.lastIndex;\n }\n\n if (lastIndex < line.length) {\n tokens.push({ type: \"plain\", value: line.slice(lastIndex) });\n }\n\n return tokens;\n}\n\nconst HIGHLIGHTABLE = new Set([\"js\", \"jsx\", \"ts\", \"tsx\", \"javascript\", \"typescript\"]);\n\nexport function CodeBlock({\n code,\n language,\n showLineNumbers = false,\n title,\n className = \"\",\n}: CodeBlockProps) {\n const [copied, setCopied] = useState(false);\n const timer = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n const handleCopy = useCallback(() => {\n navigator.clipboard.writeText(code).then(() => {\n setCopied(true);\n if (timer.current) clearTimeout(timer.current);\n timer.current = setTimeout(() => setCopied(false), 2000);\n });\n }, [code]);\n\n const highlight = language ? HIGHLIGHTABLE.has(language.toLowerCase()) : false;\n\n const lines = useMemo(() => code.split(\"\\n\"), [code]);\n const tokenized = useMemo(\n () => (highlight ? lines.map((line) => tokenizeLine(line)) : null),\n [lines, highlight],\n );\n\n return (\n /* The header lives in the bezel and the code sits on the raised face,\n so the filename reads as a label on the object, not part of it. */\n <figure\n className={[\"rounded-[18px] p-1.5 pt-0 m-0\", className].filter(Boolean).join(\" \")}\n style={{ background: \"var(--panel-bezel)\", boxShadow: \"var(--panel-shadow)\" }}\n >\n <figcaption className=\"flex items-center justify-between gap-3 pl-3 pr-0.5 h-10\">\n <div className=\"flex items-center gap-2 min-w-0\">\n {title && (\n <span className=\"text-[12px] font-medium text-ink-label truncate\">{title}</span>\n )}\n {language && (\n <span\n className=\"text-[11px] font-semibold text-ink-muted lowercase px-1.5 py-0.5 rounded-[5px]\"\n style={{ background: \"var(--well)\", boxShadow: \"var(--well-shadow)\" }}\n >\n {language}\n </span>\n )}\n </div>\n {/* Both labels share one grid cell, so the key is always as wide as\n the longer one and never jumps. Swapping rolls the old label up\n and out of a small window while the new one rolls in beneath\n it; the check draws itself as it arrives. */}\n <button\n type=\"button\"\n onClick={handleCopy}\n aria-label={copied ? \"copied to clipboard\" : \"copy code\"}\n className=\"inline-flex items-center h-7 px-2.5 rounded-[8px] text-[11.5px] font-medium cursor-pointer transition-[color,transform,scale] duration-150 active:scale-95 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ink\"\n style={{\n background: \"var(--face)\",\n boxShadow: \"var(--face-shadow)\",\n color: copied ? \"var(--success-strong)\" : undefined,\n }}\n >\n <span className=\"grid overflow-hidden text-ink-body\" style={{ color: \"inherit\" }}>\n <span\n aria-hidden\n className=\"[grid-area:1/1] inline-flex items-center justify-center gap-1.5\"\n style={{\n transform: copied ? \"translateY(-110%)\" : \"none\",\n opacity: copied ? 0 : 1,\n filter: copied ? \"blur(2px)\" : \"none\",\n transition: \"transform 320ms var(--ease-out-soft), opacity 220ms ease, filter 220ms ease\",\n }}\n >\n <svg width=\"12\" height=\"12\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" viewBox=\"0 0 24 24\">\n <rect x=\"9\" y=\"9\" width=\"13\" height=\"13\" rx=\"2\" />\n <path d=\"M5 15H4a2 2 0 01-2-2V4a2 2 0 012-2h9a2 2 0 012 2v1\" />\n </svg>\n copy\n </span>\n <span\n aria-hidden\n className=\"[grid-area:1/1] inline-flex items-center justify-center gap-1.5\"\n style={{\n transform: copied ? \"none\" : \"translateY(110%)\",\n opacity: copied ? 1 : 0,\n filter: copied ? \"none\" : \"blur(2px)\",\n transition: \"transform 380ms var(--ease-spring), opacity 220ms ease, filter 220ms ease\",\n }}\n >\n <svg width=\"12\" height=\"12\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.25\" viewBox=\"0 0 24 24\">\n <path\n key={String(copied)}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n d=\"M5 13l4 4L19 7\"\n pathLength={15}\n className={copied ? \"animate-draw-check\" : \"\"}\n />\n </svg>\n copied\n </span>\n </span>\n </button>\n <span aria-live=\"polite\" className=\"sr-only\">{copied ? \"copied to clipboard\" : \"\"}</span>\n </figcaption>\n <div\n className=\"bg-panel-face rounded-[13px] overflow-x-auto scroll-thin\"\n style={{ boxShadow: \"var(--panel-face-shadow)\" }}\n >\n <pre className=\"py-4 px-4 text-[13px] leading-[1.7] font-mono text-ink-soft\">\n <code>\n {lines.map((line, i) => (\n <div key={i} className=\"flex\">\n {showLineNumbers && (\n <span aria-hidden className=\"select-none w-8 shrink-0 text-right pr-4 text-ink-ghost tabular-nums\">\n {i + 1}\n </span>\n )}\n <span className=\"flex-1\">\n {tokenized && tokenized[i].length\n ? tokenized[i].map((tok, j) => (\n <span key={j} className={TOKEN_STYLES[tok.type] || \"\"}>\n {tok.value}\n </span>\n ))\n : (line || \"\\n\")}\n </span>\n </div>\n ))}\n </code>\n </pre>\n </div>\n </figure>\n );\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
|
|
3
|
+
/** Accepts #rgb, #rrggbb, with or without the hash. Returns #rrggbb or null */
|
|
4
|
+
declare function normalizeHex(input: string): string | null;
|
|
5
|
+
interface ColorPickerProps {
|
|
6
|
+
/** A hex colour, like "#2563eb" */
|
|
7
|
+
value?: string;
|
|
8
|
+
defaultValue?: string;
|
|
9
|
+
onChange?: (hex: string) => void;
|
|
10
|
+
label?: string;
|
|
11
|
+
hint?: string;
|
|
12
|
+
/** Preset colours under the picker; pass [] to hide them */
|
|
13
|
+
swatches?: string[];
|
|
14
|
+
/** Render the panel straight onto the page instead of behind a field */
|
|
15
|
+
inline?: boolean;
|
|
16
|
+
/** Submit the colour with a form */
|
|
17
|
+
name?: string;
|
|
18
|
+
disabled?: boolean;
|
|
19
|
+
fullWidth?: boolean;
|
|
20
|
+
className?: string;
|
|
21
|
+
}
|
|
22
|
+
declare function ColorPicker({ value, defaultValue, onChange, label, hint, swatches, inline, name, disabled, fullWidth, className, }: ColorPickerProps): react_jsx_runtime.JSX.Element;
|
|
23
|
+
|
|
24
|
+
export { ColorPicker, normalizeHex };
|