@burtson-labs/ui 0.8.1 → 0.9.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/README.md +1 -1
- package/dist/components/context-menu.d.ts +30 -0
- package/dist/components/context-menu.js +131 -0
- package/dist/components/context-menu.js.map +1 -0
- package/dist/components/dropdown-menu.js +5 -6
- package/dist/components/dropdown-menu.js.map +1 -1
- package/dist/components/editor-tabs.d.ts +43 -0
- package/dist/components/editor-tabs.js +178 -0
- package/dist/components/editor-tabs.js.map +1 -0
- package/dist/components/menubar.d.ts +30 -0
- package/dist/components/menubar.js +140 -0
- package/dist/components/menubar.js.map +1 -0
- package/dist/components/onboarding-checklist.d.ts +26 -0
- package/dist/components/onboarding-checklist.js +106 -0
- package/dist/components/onboarding-checklist.js.map +1 -0
- package/dist/components/popover.d.ts +2 -0
- package/dist/components/popover.js +3 -1
- package/dist/components/popover.js.map +1 -1
- package/dist/components/resizable.d.ts +33 -0
- package/dist/components/resizable.js +54 -0
- package/dist/components/resizable.js.map +1 -0
- package/dist/components/tour.d.ts +96 -0
- package/dist/components/tour.js +367 -0
- package/dist/components/tour.js.map +1 -0
- package/dist/components/tree-view.d.ts +61 -0
- package/dist/components/tree-view.js +278 -0
- package/dist/components/tree-view.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +10 -3
- package/dist/styles.css +1 -1
- package/package.json +2 -1
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { cn } from "../lib/utils.js";
|
|
2
|
+
import { menuItemClasses, surfaceClasses } from "./popover.js";
|
|
3
|
+
import { Menubar } from "radix-ui";
|
|
4
|
+
import "react";
|
|
5
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
6
|
+
import ChevronRight from "@burtson-labs/icons/react/chevron-right";
|
|
7
|
+
import Check from "@burtson-labs/icons/react/check";
|
|
8
|
+
//#region src/components/menubar.tsx
|
|
9
|
+
/**
|
|
10
|
+
* An application menu bar (File, Edit, View). Left/Right move between menus,
|
|
11
|
+
* Down opens one, and an open menu follows the pointer across triggers. Rows
|
|
12
|
+
* match DropdownMenu and ContextMenu.
|
|
13
|
+
*/
|
|
14
|
+
function Menubar$1({ className, ...props }) {
|
|
15
|
+
return /* @__PURE__ */ jsx(Menubar.Root, {
|
|
16
|
+
"data-slot": "menubar",
|
|
17
|
+
className: cn("flex h-8 items-center gap-0.5 rounded-md border bg-surface p-0.5", className),
|
|
18
|
+
...props
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
function MenubarMenu(props) {
|
|
22
|
+
return /* @__PURE__ */ jsx(Menubar.Menu, {
|
|
23
|
+
"data-slot": "menubar-menu",
|
|
24
|
+
...props
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
function MenubarTrigger({ className, ...props }) {
|
|
28
|
+
return /* @__PURE__ */ jsx(Menubar.Trigger, {
|
|
29
|
+
"data-slot": "menubar-trigger",
|
|
30
|
+
className: cn("flex h-7 items-center rounded-sm px-2.5 text-[13px] font-medium outline-none select-none hover:bg-muted focus-visible:shadow-[inset_0_0_0_1px_var(--ring)] data-[state=open]:bg-muted", className),
|
|
31
|
+
...props
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
function MenubarGroup(props) {
|
|
35
|
+
return /* @__PURE__ */ jsx(Menubar.Group, {
|
|
36
|
+
"data-slot": "menubar-group",
|
|
37
|
+
...props
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
function MenubarContent({ className, align = "start", sideOffset = 4, ...props }) {
|
|
41
|
+
return /* @__PURE__ */ jsx(Menubar.Portal, { children: /* @__PURE__ */ jsx(Menubar.Content, {
|
|
42
|
+
"data-slot": "menubar-content",
|
|
43
|
+
align,
|
|
44
|
+
sideOffset,
|
|
45
|
+
className: cn(surfaceClasses, "max-h-(--radix-menubar-content-available-height) min-w-[8rem] origin-(--radix-menubar-content-transform-origin) overflow-x-hidden overflow-y-auto p-1", className),
|
|
46
|
+
...props
|
|
47
|
+
}) });
|
|
48
|
+
}
|
|
49
|
+
function MenubarItem({ className, inset, variant = "default", ...props }) {
|
|
50
|
+
return /* @__PURE__ */ jsx(Menubar.Item, {
|
|
51
|
+
"data-slot": "menubar-item",
|
|
52
|
+
"data-inset": inset || void 0,
|
|
53
|
+
"data-variant": variant,
|
|
54
|
+
className: cn(menuItemClasses, "data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 data-[variant=destructive]:*:[svg]:!text-destructive", className),
|
|
55
|
+
...props
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
function MenubarCheckboxItem({ className, children, checked, ...props }) {
|
|
59
|
+
return /* @__PURE__ */ jsxs(Menubar.CheckboxItem, {
|
|
60
|
+
"data-slot": "menubar-checkbox-item",
|
|
61
|
+
className: cn(menuItemClasses, "pl-8", className),
|
|
62
|
+
checked,
|
|
63
|
+
...props,
|
|
64
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
65
|
+
className: "pointer-events-none absolute left-2 flex size-3.5 items-center justify-center",
|
|
66
|
+
children: /* @__PURE__ */ jsx(Menubar.ItemIndicator, { children: /* @__PURE__ */ jsx(Check, {
|
|
67
|
+
className: "size-4 text-foreground",
|
|
68
|
+
"aria-hidden": true
|
|
69
|
+
}) })
|
|
70
|
+
}), children]
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
function MenubarRadioGroup(props) {
|
|
74
|
+
return /* @__PURE__ */ jsx(Menubar.RadioGroup, {
|
|
75
|
+
"data-slot": "menubar-radio-group",
|
|
76
|
+
...props
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
function MenubarRadioItem({ className, children, ...props }) {
|
|
80
|
+
return /* @__PURE__ */ jsxs(Menubar.RadioItem, {
|
|
81
|
+
"data-slot": "menubar-radio-item",
|
|
82
|
+
className: cn(menuItemClasses, "pl-8", className),
|
|
83
|
+
...props,
|
|
84
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
85
|
+
className: "pointer-events-none absolute left-2 flex size-3.5 items-center justify-center",
|
|
86
|
+
children: /* @__PURE__ */ jsx(Menubar.ItemIndicator, { children: /* @__PURE__ */ jsx("span", { className: "block size-2 rounded-full bg-foreground" }) })
|
|
87
|
+
}), children]
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
function MenubarLabel({ className, inset, ...props }) {
|
|
91
|
+
return /* @__PURE__ */ jsx(Menubar.Label, {
|
|
92
|
+
"data-slot": "menubar-label",
|
|
93
|
+
"data-inset": inset || void 0,
|
|
94
|
+
className: cn("px-2 pt-2 pb-1 text-[11px] font-semibold tracking-[0.08em] text-muted-foreground uppercase data-[inset]:pl-8", className),
|
|
95
|
+
...props
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
function MenubarSeparator({ className, ...props }) {
|
|
99
|
+
return /* @__PURE__ */ jsx(Menubar.Separator, {
|
|
100
|
+
"data-slot": "menubar-separator",
|
|
101
|
+
className: cn("-mx-1 my-1 h-px bg-border", className),
|
|
102
|
+
...props
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
function MenubarShortcut({ className, ...props }) {
|
|
106
|
+
return /* @__PURE__ */ jsx("span", {
|
|
107
|
+
"data-slot": "menubar-shortcut",
|
|
108
|
+
className: cn("ml-auto text-xs tracking-widest text-muted-foreground", className),
|
|
109
|
+
...props
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
function MenubarSub(props) {
|
|
113
|
+
return /* @__PURE__ */ jsx(Menubar.Sub, {
|
|
114
|
+
"data-slot": "menubar-sub",
|
|
115
|
+
...props
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
function MenubarSubTrigger({ className, inset, children, ...props }) {
|
|
119
|
+
return /* @__PURE__ */ jsxs(Menubar.SubTrigger, {
|
|
120
|
+
"data-slot": "menubar-sub-trigger",
|
|
121
|
+
"data-inset": inset || void 0,
|
|
122
|
+
className: cn(menuItemClasses, "data-[state=open]:bg-muted", className),
|
|
123
|
+
...props,
|
|
124
|
+
children: [children, /* @__PURE__ */ jsx(ChevronRight, {
|
|
125
|
+
className: "ml-auto size-4",
|
|
126
|
+
"aria-hidden": true
|
|
127
|
+
})]
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
function MenubarSubContent({ className, ...props }) {
|
|
131
|
+
return /* @__PURE__ */ jsx(Menubar.Portal, { children: /* @__PURE__ */ jsx(Menubar.SubContent, {
|
|
132
|
+
"data-slot": "menubar-sub-content",
|
|
133
|
+
className: cn(surfaceClasses, "min-w-[8rem] origin-(--radix-menubar-content-transform-origin) overflow-hidden p-1", className),
|
|
134
|
+
...props
|
|
135
|
+
}) });
|
|
136
|
+
}
|
|
137
|
+
//#endregion
|
|
138
|
+
export { Menubar$1 as Menubar, MenubarCheckboxItem, MenubarContent, MenubarGroup, MenubarItem, MenubarLabel, MenubarMenu, MenubarRadioGroup, MenubarRadioItem, MenubarSeparator, MenubarShortcut, MenubarSub, MenubarSubContent, MenubarSubTrigger, MenubarTrigger };
|
|
139
|
+
|
|
140
|
+
//# sourceMappingURL=menubar.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"menubar.js","names":["Menubar","MenubarPrimitive","itemClasses"],"sources":["../../src/components/menubar.tsx"],"sourcesContent":["import Check from '@burtson-labs/icons/react/check';\nimport ChevronRight from '@burtson-labs/icons/react/chevron-right';\nimport { Menubar as MenubarPrimitive } from 'radix-ui';\nimport * as React from 'react';\n\nimport { cn } from '../lib/utils';\n\nimport { menuItemClasses as itemClasses, surfaceClasses } from './popover';\n\n/**\n * An application menu bar (File, Edit, View). Left/Right move between menus,\n * Down opens one, and an open menu follows the pointer across triggers. Rows\n * match DropdownMenu and ContextMenu.\n */\nfunction Menubar({ className, ...props }: React.ComponentProps<typeof MenubarPrimitive.Root>) {\n return (\n <MenubarPrimitive.Root\n data-slot=\"menubar\"\n className={cn('flex h-8 items-center gap-0.5 rounded-md border bg-surface p-0.5', className)}\n {...props}\n />\n );\n}\n\nfunction MenubarMenu(props: React.ComponentProps<typeof MenubarPrimitive.Menu>) {\n return <MenubarPrimitive.Menu data-slot=\"menubar-menu\" {...props} />;\n}\n\nfunction MenubarTrigger({\n className,\n ...props\n}: React.ComponentProps<typeof MenubarPrimitive.Trigger>) {\n return (\n <MenubarPrimitive.Trigger\n data-slot=\"menubar-trigger\"\n className={cn(\n 'flex h-7 items-center rounded-sm px-2.5 text-[13px] font-medium outline-none select-none hover:bg-muted focus-visible:shadow-[inset_0_0_0_1px_var(--ring)] data-[state=open]:bg-muted',\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction MenubarGroup(props: React.ComponentProps<typeof MenubarPrimitive.Group>) {\n return <MenubarPrimitive.Group data-slot=\"menubar-group\" {...props} />;\n}\n\nfunction MenubarContent({\n className,\n align = 'start',\n sideOffset = 4,\n ...props\n}: React.ComponentProps<typeof MenubarPrimitive.Content>) {\n return (\n <MenubarPrimitive.Portal>\n <MenubarPrimitive.Content\n data-slot=\"menubar-content\"\n align={align}\n sideOffset={sideOffset}\n className={cn(\n surfaceClasses,\n 'max-h-(--radix-menubar-content-available-height) min-w-[8rem] origin-(--radix-menubar-content-transform-origin) overflow-x-hidden overflow-y-auto p-1',\n className,\n )}\n {...props}\n />\n </MenubarPrimitive.Portal>\n );\n}\n\nfunction MenubarItem({\n className,\n inset,\n variant = 'default',\n ...props\n}: React.ComponentProps<typeof MenubarPrimitive.Item> & {\n inset?: boolean;\n variant?: 'default' | 'destructive';\n}) {\n return (\n <MenubarPrimitive.Item\n data-slot=\"menubar-item\"\n data-inset={inset || undefined}\n data-variant={variant}\n className={cn(\n itemClasses,\n 'data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 data-[variant=destructive]:*:[svg]:!text-destructive',\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction MenubarCheckboxItem({\n className,\n children,\n checked,\n ...props\n}: React.ComponentProps<typeof MenubarPrimitive.CheckboxItem>) {\n return (\n <MenubarPrimitive.CheckboxItem\n data-slot=\"menubar-checkbox-item\"\n className={cn(itemClasses, 'pl-8', className)}\n checked={checked}\n {...props}\n >\n <span className=\"pointer-events-none absolute left-2 flex size-3.5 items-center justify-center\">\n <MenubarPrimitive.ItemIndicator>\n <Check className=\"size-4 text-foreground\" aria-hidden />\n </MenubarPrimitive.ItemIndicator>\n </span>\n {children}\n </MenubarPrimitive.CheckboxItem>\n );\n}\n\nfunction MenubarRadioGroup(props: React.ComponentProps<typeof MenubarPrimitive.RadioGroup>) {\n return <MenubarPrimitive.RadioGroup data-slot=\"menubar-radio-group\" {...props} />;\n}\n\nfunction MenubarRadioItem({\n className,\n children,\n ...props\n}: React.ComponentProps<typeof MenubarPrimitive.RadioItem>) {\n return (\n <MenubarPrimitive.RadioItem\n data-slot=\"menubar-radio-item\"\n className={cn(itemClasses, 'pl-8', className)}\n {...props}\n >\n <span className=\"pointer-events-none absolute left-2 flex size-3.5 items-center justify-center\">\n <MenubarPrimitive.ItemIndicator>\n <span className=\"block size-2 rounded-full bg-foreground\" />\n </MenubarPrimitive.ItemIndicator>\n </span>\n {children}\n </MenubarPrimitive.RadioItem>\n );\n}\n\nfunction MenubarLabel({\n className,\n inset,\n ...props\n}: React.ComponentProps<typeof MenubarPrimitive.Label> & { inset?: boolean }) {\n return (\n <MenubarPrimitive.Label\n data-slot=\"menubar-label\"\n data-inset={inset || undefined}\n className={cn(\n 'px-2 pt-2 pb-1 text-[11px] font-semibold tracking-[0.08em] text-muted-foreground uppercase data-[inset]:pl-8',\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction MenubarSeparator({\n className,\n ...props\n}: React.ComponentProps<typeof MenubarPrimitive.Separator>) {\n return (\n <MenubarPrimitive.Separator\n data-slot=\"menubar-separator\"\n className={cn('-mx-1 my-1 h-px bg-border', className)}\n {...props}\n />\n );\n}\n\nfunction MenubarShortcut({ className, ...props }: React.ComponentProps<'span'>) {\n return (\n <span\n data-slot=\"menubar-shortcut\"\n className={cn('ml-auto text-xs tracking-widest text-muted-foreground', className)}\n {...props}\n />\n );\n}\n\nfunction MenubarSub(props: React.ComponentProps<typeof MenubarPrimitive.Sub>) {\n return <MenubarPrimitive.Sub data-slot=\"menubar-sub\" {...props} />;\n}\n\nfunction MenubarSubTrigger({\n className,\n inset,\n children,\n ...props\n}: React.ComponentProps<typeof MenubarPrimitive.SubTrigger> & { inset?: boolean }) {\n return (\n <MenubarPrimitive.SubTrigger\n data-slot=\"menubar-sub-trigger\"\n data-inset={inset || undefined}\n className={cn(itemClasses, 'data-[state=open]:bg-muted', className)}\n {...props}\n >\n {children}\n <ChevronRight className=\"ml-auto size-4\" aria-hidden />\n </MenubarPrimitive.SubTrigger>\n );\n}\n\nfunction MenubarSubContent({\n className,\n ...props\n}: React.ComponentProps<typeof MenubarPrimitive.SubContent>) {\n return (\n <MenubarPrimitive.Portal>\n <MenubarPrimitive.SubContent\n data-slot=\"menubar-sub-content\"\n className={cn(\n surfaceClasses,\n 'min-w-[8rem] origin-(--radix-menubar-content-transform-origin) overflow-hidden p-1',\n className,\n )}\n {...props}\n />\n </MenubarPrimitive.Portal>\n );\n}\n\nexport {\n Menubar,\n MenubarMenu,\n MenubarCheckboxItem,\n MenubarContent,\n MenubarGroup,\n MenubarItem,\n MenubarLabel,\n MenubarRadioGroup,\n MenubarRadioItem,\n MenubarSeparator,\n MenubarShortcut,\n MenubarSub,\n MenubarSubContent,\n MenubarSubTrigger,\n MenubarTrigger,\n};\n"],"mappings":";;;;;;;;;;;;;AAcA,SAASA,UAAQ,EAAE,WAAW,GAAG,SAA6D;CAC5F,OACE,oBAACC,QAAiB,MAAlB;EACE,aAAU;EACV,WAAW,GAAG,oEAAoE,SAAS;EAC3F,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,YAAY,OAA2D;CAC9E,OAAO,oBAACA,QAAiB,MAAlB;EAAuB,aAAU;EAAe,GAAI;CAAQ,CAAA;AACrE;AAEA,SAAS,eAAe,EACtB,WACA,GAAG,SACqD;CACxD,OACE,oBAACA,QAAiB,SAAlB;EACE,aAAU;EACV,WAAW,GACT,yLACA,SACF;EACA,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,aAAa,OAA4D;CAChF,OAAO,oBAACA,QAAiB,OAAlB;EAAwB,aAAU;EAAgB,GAAI;CAAQ,CAAA;AACvE;AAEA,SAAS,eAAe,EACtB,WACA,QAAQ,SACR,aAAa,GACb,GAAG,SACqD;CACxD,OACE,oBAACA,QAAiB,QAAlB,EAAA,UACE,oBAACA,QAAiB,SAAlB;EACE,aAAU;EACH;EACK;EACZ,WAAW,GACT,gBACA,yJACA,SACF;EACA,GAAI;CACL,CAAA,EACsB,CAAA;AAE7B;AAEA,SAAS,YAAY,EACnB,WACA,OACA,UAAU,WACV,GAAG,SAIF;CACD,OACE,oBAACA,QAAiB,MAAlB;EACE,aAAU;EACV,cAAY,SAAS,KAAA;EACrB,gBAAc;EACd,WAAW,GACTC,iBACA,uJACA,SACF;EACA,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,oBAAoB,EAC3B,WACA,UACA,SACA,GAAG,SAC0D;CAC7D,OACE,qBAACD,QAAiB,cAAlB;EACE,aAAU;EACV,WAAW,GAAGC,iBAAa,QAAQ,SAAS;EACnC;EACT,GAAI;EAJN,UAAA,CAME,oBAAC,QAAD;GAAM,WAAU;GACd,UAAA,oBAACD,QAAiB,eAAlB,EAAA,UACE,oBAAC,OAAD;IAAO,WAAU;IAAyB,eAAA;GAAa,CAAA,EACzB,CAAA;EAC5B,CAAA,GACL,QAC4B;;AAEnC;AAEA,SAAS,kBAAkB,OAAiE;CAC1F,OAAO,oBAACA,QAAiB,YAAlB;EAA6B,aAAU;EAAsB,GAAI;CAAQ,CAAA;AAClF;AAEA,SAAS,iBAAiB,EACxB,WACA,UACA,GAAG,SACuD;CAC1D,OACE,qBAACA,QAAiB,WAAlB;EACE,aAAU;EACV,WAAW,GAAGC,iBAAa,QAAQ,SAAS;EAC5C,GAAI;EAHN,UAAA,CAKE,oBAAC,QAAD;GAAM,WAAU;GACd,UAAA,oBAACD,QAAiB,eAAlB,EAAA,UACE,oBAAC,QAAD,EAAM,WAAU,0CAA2C,CAAA,EAC7B,CAAA;EAC5B,CAAA,GACL,QACyB;;AAEhC;AAEA,SAAS,aAAa,EACpB,WACA,OACA,GAAG,SACyE;CAC5E,OACE,oBAACA,QAAiB,OAAlB;EACE,aAAU;EACV,cAAY,SAAS,KAAA;EACrB,WAAW,GACT,gHACA,SACF;EACA,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,iBAAiB,EACxB,WACA,GAAG,SACuD;CAC1D,OACE,oBAACA,QAAiB,WAAlB;EACE,aAAU;EACV,WAAW,GAAG,6BAA6B,SAAS;EACpD,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,gBAAgB,EAAE,WAAW,GAAG,SAAuC;CAC9E,OACE,oBAAC,QAAD;EACE,aAAU;EACV,WAAW,GAAG,yDAAyD,SAAS;EAChF,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,WAAW,OAA0D;CAC5E,OAAO,oBAACA,QAAiB,KAAlB;EAAsB,aAAU;EAAc,GAAI;CAAQ,CAAA;AACnE;AAEA,SAAS,kBAAkB,EACzB,WACA,OACA,UACA,GAAG,SAC8E;CACjF,OACE,qBAACA,QAAiB,YAAlB;EACE,aAAU;EACV,cAAY,SAAS,KAAA;EACrB,WAAW,GAAGC,iBAAa,8BAA8B,SAAS;EAClE,GAAI;EAJN,UAAA,CAMG,UACD,oBAAC,cAAD;GAAc,WAAU;GAAiB,eAAA;EAAa,CAAA,CAC3B;;AAEjC;AAEA,SAAS,kBAAkB,EACzB,WACA,GAAG,SACwD;CAC3D,OACE,oBAACD,QAAiB,QAAlB,EAAA,UACE,oBAACA,QAAiB,YAAlB;EACE,aAAU;EACV,WAAW,GACT,gBACA,sFACA,SACF;EACA,GAAI;CACL,CAAA,EACsB,CAAA;AAE7B"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
export interface ChecklistItem {
|
|
3
|
+
id: string;
|
|
4
|
+
title: React.ReactNode;
|
|
5
|
+
description?: React.ReactNode;
|
|
6
|
+
/** Set from real app events (a repo opened, a provider tested), never from a click on the list. */
|
|
7
|
+
done: boolean;
|
|
8
|
+
/** A button or link that starts the task. Hidden once done. */
|
|
9
|
+
action?: React.ReactNode;
|
|
10
|
+
}
|
|
11
|
+
export interface OnboardingChecklistProps extends Omit<React.ComponentProps<'section'>, 'title'> {
|
|
12
|
+
title: React.ReactNode;
|
|
13
|
+
description?: React.ReactNode;
|
|
14
|
+
items: ChecklistItem[];
|
|
15
|
+
/** Shows a close button. Persist the dismissal yourself. */
|
|
16
|
+
onDismiss?: () => void;
|
|
17
|
+
dismissLabel?: string;
|
|
18
|
+
/** Replaces the list once every item is done. */
|
|
19
|
+
complete?: React.ReactNode;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* A short list of first tasks with progress. The app decides when each task
|
|
23
|
+
* is done and whether the list shows at all; this renders it.
|
|
24
|
+
*/
|
|
25
|
+
declare function OnboardingChecklist({ title, description, items, onDismiss, dismissLabel, complete, className, ...props }: OnboardingChecklistProps): React.JSX.Element;
|
|
26
|
+
export { OnboardingChecklist };
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { cn } from "../lib/utils.js";
|
|
2
|
+
import { Progress } from "./progress.js";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
5
|
+
import X from "@burtson-labs/icons/react/x";
|
|
6
|
+
import CheckCircle from "@burtson-labs/icons/react/check-circle";
|
|
7
|
+
import CircleDashed from "@burtson-labs/icons/react/circle-dashed";
|
|
8
|
+
//#region src/components/onboarding-checklist.tsx
|
|
9
|
+
/**
|
|
10
|
+
* A short list of first tasks with progress. The app decides when each task
|
|
11
|
+
* is done and whether the list shows at all; this renders it.
|
|
12
|
+
*/
|
|
13
|
+
function OnboardingChecklist({ title, description, items, onDismiss, dismissLabel = "Dismiss checklist", complete, className, ...props }) {
|
|
14
|
+
const titleId = React.useId();
|
|
15
|
+
const done = items.filter((i) => i.done).length;
|
|
16
|
+
const allDone = items.length > 0 && done === items.length;
|
|
17
|
+
return /* @__PURE__ */ jsxs("section", {
|
|
18
|
+
"data-slot": "onboarding-checklist",
|
|
19
|
+
"aria-labelledby": titleId,
|
|
20
|
+
className: cn("rounded-lg border bg-card p-4 text-[13px] text-card-foreground", className),
|
|
21
|
+
...props,
|
|
22
|
+
children: [
|
|
23
|
+
/* @__PURE__ */ jsxs("div", {
|
|
24
|
+
className: "flex items-start gap-3",
|
|
25
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
26
|
+
className: "min-w-0 flex-1",
|
|
27
|
+
children: [/* @__PURE__ */ jsx("h2", {
|
|
28
|
+
id: titleId,
|
|
29
|
+
className: "text-sm font-semibold",
|
|
30
|
+
children: title
|
|
31
|
+
}), description && /* @__PURE__ */ jsx("p", {
|
|
32
|
+
className: "mt-0.5 text-muted-foreground",
|
|
33
|
+
children: description
|
|
34
|
+
})]
|
|
35
|
+
}), onDismiss && /* @__PURE__ */ jsx("button", {
|
|
36
|
+
type: "button",
|
|
37
|
+
"aria-label": dismissLabel,
|
|
38
|
+
onClick: onDismiss,
|
|
39
|
+
className: "-me-1 -mt-1 flex size-7 shrink-0 items-center justify-center rounded-sm text-muted-foreground outline-none hover:bg-muted hover:text-foreground focus-visible:shadow-[inset_0_0_0_1px_var(--ring)]",
|
|
40
|
+
children: /* @__PURE__ */ jsx(X, {
|
|
41
|
+
"aria-hidden": true,
|
|
42
|
+
className: "size-4"
|
|
43
|
+
})
|
|
44
|
+
})]
|
|
45
|
+
}),
|
|
46
|
+
/* @__PURE__ */ jsxs("div", {
|
|
47
|
+
className: "mt-3 flex items-center gap-3",
|
|
48
|
+
children: [/* @__PURE__ */ jsx(Progress, {
|
|
49
|
+
value: done,
|
|
50
|
+
max: Math.max(items.length, 1),
|
|
51
|
+
"aria-label": `${done} of ${items.length} done`,
|
|
52
|
+
className: "flex-1"
|
|
53
|
+
}), /* @__PURE__ */ jsxs("span", {
|
|
54
|
+
className: "shrink-0 text-xs text-muted-foreground tabular-nums",
|
|
55
|
+
"aria-hidden": true,
|
|
56
|
+
children: [
|
|
57
|
+
done,
|
|
58
|
+
"/",
|
|
59
|
+
items.length
|
|
60
|
+
]
|
|
61
|
+
})]
|
|
62
|
+
}),
|
|
63
|
+
allDone && complete ? /* @__PURE__ */ jsx("div", {
|
|
64
|
+
className: "mt-3",
|
|
65
|
+
children: complete
|
|
66
|
+
}) : /* @__PURE__ */ jsx("ul", {
|
|
67
|
+
className: "mt-3 flex flex-col gap-1",
|
|
68
|
+
children: items.map((item) => /* @__PURE__ */ jsxs("li", {
|
|
69
|
+
"data-slot": "onboarding-checklist-item",
|
|
70
|
+
"data-state": item.done ? "done" : "todo",
|
|
71
|
+
className: "flex items-start gap-2.5 rounded-md px-1 py-1.5",
|
|
72
|
+
children: [
|
|
73
|
+
item.done ? /* @__PURE__ */ jsx(CheckCircle, {
|
|
74
|
+
"aria-hidden": true,
|
|
75
|
+
className: "mt-px size-4 shrink-0 text-success"
|
|
76
|
+
}) : /* @__PURE__ */ jsx(CircleDashed, {
|
|
77
|
+
"aria-hidden": true,
|
|
78
|
+
className: "mt-px size-4 shrink-0 text-muted-foreground"
|
|
79
|
+
}),
|
|
80
|
+
/* @__PURE__ */ jsxs("div", {
|
|
81
|
+
className: "min-w-0 flex-1",
|
|
82
|
+
children: [/* @__PURE__ */ jsxs("p", {
|
|
83
|
+
className: cn("font-medium", item.done && "text-muted-foreground line-through"),
|
|
84
|
+
children: [item.title, /* @__PURE__ */ jsx("span", {
|
|
85
|
+
className: "sr-only",
|
|
86
|
+
children: item.done ? ", done" : ", not done"
|
|
87
|
+
})]
|
|
88
|
+
}), item.description && !item.done && /* @__PURE__ */ jsx("p", {
|
|
89
|
+
className: "mt-0.5 text-muted-foreground",
|
|
90
|
+
children: item.description
|
|
91
|
+
})]
|
|
92
|
+
}),
|
|
93
|
+
item.action && !item.done && /* @__PURE__ */ jsx("div", {
|
|
94
|
+
className: "shrink-0",
|
|
95
|
+
children: item.action
|
|
96
|
+
})
|
|
97
|
+
]
|
|
98
|
+
}, item.id))
|
|
99
|
+
})
|
|
100
|
+
]
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
//#endregion
|
|
104
|
+
export { OnboardingChecklist };
|
|
105
|
+
|
|
106
|
+
//# sourceMappingURL=onboarding-checklist.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"onboarding-checklist.js","names":[],"sources":["../../src/components/onboarding-checklist.tsx"],"sourcesContent":["import CheckCircle from '@burtson-labs/icons/react/check-circle';\nimport CircleDashed from '@burtson-labs/icons/react/circle-dashed';\nimport X from '@burtson-labs/icons/react/x';\nimport * as React from 'react';\n\nimport { cn } from '../lib/utils';\n\nimport { Progress } from './progress';\n\nexport interface ChecklistItem {\n id: string;\n title: React.ReactNode;\n description?: React.ReactNode;\n /** Set from real app events (a repo opened, a provider tested), never from a click on the list. */\n done: boolean;\n /** A button or link that starts the task. Hidden once done. */\n action?: React.ReactNode;\n}\n\nexport interface OnboardingChecklistProps extends Omit<React.ComponentProps<'section'>, 'title'> {\n title: React.ReactNode;\n description?: React.ReactNode;\n items: ChecklistItem[];\n /** Shows a close button. Persist the dismissal yourself. */\n onDismiss?: () => void;\n dismissLabel?: string;\n /** Replaces the list once every item is done. */\n complete?: React.ReactNode;\n}\n\n/**\n * A short list of first tasks with progress. The app decides when each task\n * is done and whether the list shows at all; this renders it.\n */\nfunction OnboardingChecklist({\n title,\n description,\n items,\n onDismiss,\n dismissLabel = 'Dismiss checklist',\n complete,\n className,\n ...props\n}: OnboardingChecklistProps) {\n const titleId = React.useId();\n const done = items.filter((i) => i.done).length;\n const allDone = items.length > 0 && done === items.length;\n return (\n <section\n data-slot=\"onboarding-checklist\"\n aria-labelledby={titleId}\n className={cn('rounded-lg border bg-card p-4 text-[13px] text-card-foreground', className)}\n {...props}\n >\n <div className=\"flex items-start gap-3\">\n <div className=\"min-w-0 flex-1\">\n <h2 id={titleId} className=\"text-sm font-semibold\">\n {title}\n </h2>\n {description && <p className=\"mt-0.5 text-muted-foreground\">{description}</p>}\n </div>\n {onDismiss && (\n <button\n type=\"button\"\n aria-label={dismissLabel}\n onClick={onDismiss}\n className=\"-me-1 -mt-1 flex size-7 shrink-0 items-center justify-center rounded-sm text-muted-foreground outline-none hover:bg-muted hover:text-foreground focus-visible:shadow-[inset_0_0_0_1px_var(--ring)]\"\n >\n <X aria-hidden className=\"size-4\" />\n </button>\n )}\n </div>\n <div className=\"mt-3 flex items-center gap-3\">\n <Progress\n value={done}\n max={Math.max(items.length, 1)}\n aria-label={`${done} of ${items.length} done`}\n className=\"flex-1\"\n />\n <span className=\"shrink-0 text-xs text-muted-foreground tabular-nums\" aria-hidden>\n {done}/{items.length}\n </span>\n </div>\n {allDone && complete ? (\n <div className=\"mt-3\">{complete}</div>\n ) : (\n <ul className=\"mt-3 flex flex-col gap-1\">\n {items.map((item) => (\n <li\n key={item.id}\n data-slot=\"onboarding-checklist-item\"\n data-state={item.done ? 'done' : 'todo'}\n className=\"flex items-start gap-2.5 rounded-md px-1 py-1.5\"\n >\n {item.done ? (\n <CheckCircle aria-hidden className=\"mt-px size-4 shrink-0 text-success\" />\n ) : (\n <CircleDashed aria-hidden className=\"mt-px size-4 shrink-0 text-muted-foreground\" />\n )}\n <div className=\"min-w-0 flex-1\">\n <p className={cn('font-medium', item.done && 'text-muted-foreground line-through')}>\n {item.title}\n <span className=\"sr-only\">{item.done ? ', done' : ', not done'}</span>\n </p>\n {item.description && !item.done && (\n <p className=\"mt-0.5 text-muted-foreground\">{item.description}</p>\n )}\n </div>\n {item.action && !item.done && <div className=\"shrink-0\">{item.action}</div>}\n </li>\n ))}\n </ul>\n )}\n </section>\n );\n}\n\nexport { OnboardingChecklist };\n"],"mappings":";;;;;;;;;;;;AAkCA,SAAS,oBAAoB,EAC3B,OACA,aACA,OACA,WACA,eAAe,qBACf,UACA,WACA,GAAG,SACwB;CAC3B,MAAM,UAAU,MAAM,MAAM;CAC5B,MAAM,OAAO,MAAM,QAAQ,MAAM,EAAE,IAAI,CAAC,CAAC;CACzC,MAAM,UAAU,MAAM,SAAS,KAAK,SAAS,MAAM;CACnD,OACE,qBAAC,WAAD;EACE,aAAU;EACV,mBAAiB;EACjB,WAAW,GAAG,kEAAkE,SAAS;EACzF,GAAI;EAJN,UAAA;GAME,qBAAC,OAAD;IAAK,WAAU;IAAf,UAAA,CACE,qBAAC,OAAD;KAAK,WAAU;KAAf,UAAA,CACE,oBAAC,MAAD;MAAI,IAAI;MAAS,WAAU;MACxB,UAAA;KACC,CAAA,GACH,eAAe,oBAAC,KAAD;MAAG,WAAU;MAAgC,UAAA;KAAe,CAAA,CACzE;IACJ,CAAA,GAAA,aACC,oBAAC,UAAD;KACE,MAAK;KACL,cAAY;KACZ,SAAS;KACT,WAAU;KAEV,UAAA,oBAAC,GAAD;MAAG,eAAA;MAAY,WAAU;KAAU,CAAA;IAC7B,CAAA,CAEP;;GACL,qBAAC,OAAD;IAAK,WAAU;IAAf,UAAA,CACE,oBAAC,UAAD;KACE,OAAO;KACP,KAAK,KAAK,IAAI,MAAM,QAAQ,CAAC;KAC7B,cAAY,GAAG,KAAK,MAAM,MAAM,OAAO;KACvC,WAAU;IACX,CAAA,GACD,qBAAC,QAAD;KAAM,WAAU;KAAsD,eAAA;KAAtE,UAAA;MACG;MAAK;MAAE,MAAM;KACV;IACH,CAAA,CAAA;;GACJ,WAAW,WACV,oBAAC,OAAD;IAAK,WAAU;IAAQ,UAAA;GAAc,CAAA,IAErC,oBAAC,MAAD;IAAI,WAAU;IACX,UAAA,MAAM,KAAK,SACV,qBAAC,MAAD;KAEE,aAAU;KACV,cAAY,KAAK,OAAO,SAAS;KACjC,WAAU;KAJZ,UAAA;MAMG,KAAK,OACJ,oBAAC,aAAD;OAAa,eAAA;OAAY,WAAU;MAAsC,CAAA,IAEzE,oBAAC,cAAD;OAAc,eAAA;OAAY,WAAU;MAA+C,CAAA;MAErF,qBAAC,OAAD;OAAK,WAAU;OAAf,UAAA,CACE,qBAAC,KAAD;QAAG,WAAW,GAAG,eAAe,KAAK,QAAQ,oCAAoC;QAAjF,UAAA,CACG,KAAK,OACN,oBAAC,QAAD;SAAM,WAAU;SAAW,UAAA,KAAK,OAAO,WAAW;QAAmB,CAAA,CACpE;OACF,CAAA,GAAA,KAAK,eAAe,CAAC,KAAK,QACzB,oBAAC,KAAD;QAAG,WAAU;QAAgC,UAAA,KAAK;OAAe,CAAA,CAEhE;;MACJ,KAAK,UAAU,CAAC,KAAK,QAAQ,oBAAC,OAAD;OAAK,WAAU;OAAY,UAAA,KAAK;MAAY,CAAA;KACxE;IApBG,GAAA,KAAK,EAoBR,CACL;GACC,CAAA;EAEC;;AAEb"}
|
|
@@ -5,6 +5,8 @@ import * as React from 'react';
|
|
|
5
5
|
* with a strong border, and the one place a heavy shadow is allowed.
|
|
6
6
|
*/
|
|
7
7
|
export declare const surfaceClasses = "z-50 animate-in rounded-lg border border-border-strong bg-surface-raised text-popover-foreground shadow-[0_16px_48px_rgb(0_0_0_/_0.18)] data-[state=closed]:animate-out data-[side=bottom]:[--bl-ty:-6px] data-[side=top]:[--bl-ty:6px] data-[side=left]:[--bl-tx:6px] data-[side=right]:[--bl-tx:-6px]";
|
|
8
|
+
/** A menu row: 32px, 8px radius; the focused row is a quiet fill, like an active tab. */
|
|
9
|
+
export declare const menuItemClasses = "relative flex min-h-8 cursor-default items-center gap-2 rounded-sm px-2 text-[13px] outline-hidden select-none focus:bg-muted focus:text-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='text-'])]:text-muted-foreground";
|
|
8
10
|
declare function Popover(props: React.ComponentProps<typeof PopoverPrimitive.Root>): React.JSX.Element;
|
|
9
11
|
declare function PopoverTrigger(props: React.ComponentProps<typeof PopoverPrimitive.Trigger>): React.JSX.Element;
|
|
10
12
|
declare function PopoverAnchor(props: React.ComponentProps<typeof PopoverPrimitive.Anchor>): React.JSX.Element;
|
|
@@ -8,6 +8,8 @@ import { jsx } from "react/jsx-runtime";
|
|
|
8
8
|
* with a strong border, and the one place a heavy shadow is allowed.
|
|
9
9
|
*/
|
|
10
10
|
var surfaceClasses = "z-50 animate-in rounded-lg border border-border-strong bg-surface-raised text-popover-foreground shadow-[0_16px_48px_rgb(0_0_0_/_0.18)] data-[state=closed]:animate-out data-[side=bottom]:[--bl-ty:-6px] data-[side=top]:[--bl-ty:6px] data-[side=left]:[--bl-tx:6px] data-[side=right]:[--bl-tx:-6px]";
|
|
11
|
+
/** A menu row: 32px, 8px radius; the focused row is a quiet fill, like an active tab. */
|
|
12
|
+
var menuItemClasses = "relative flex min-h-8 cursor-default items-center gap-2 rounded-sm px-2 text-[13px] outline-hidden select-none focus:bg-muted focus:text-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='text-'])]:text-muted-foreground";
|
|
11
13
|
function Popover$1(props) {
|
|
12
14
|
return /* @__PURE__ */ jsx(Popover.Root, {
|
|
13
15
|
"data-slot": "popover",
|
|
@@ -36,6 +38,6 @@ function PopoverContent({ className, align = "center", sideOffset = 6, ...props
|
|
|
36
38
|
}) });
|
|
37
39
|
}
|
|
38
40
|
//#endregion
|
|
39
|
-
export { Popover$1 as Popover, PopoverAnchor, PopoverContent, PopoverTrigger, surfaceClasses };
|
|
41
|
+
export { Popover$1 as Popover, PopoverAnchor, PopoverContent, PopoverTrigger, menuItemClasses, surfaceClasses };
|
|
40
42
|
|
|
41
43
|
//# sourceMappingURL=popover.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"popover.js","names":["Popover","PopoverPrimitive"],"sources":["../../src/components/popover.tsx"],"sourcesContent":["import { Popover as PopoverPrimitive } from 'radix-ui';\nimport * as React from 'react';\n\nimport { cn } from '../lib/utils';\n\n/**\n * The floating surface shared by popovers, menus and select lists: raised,\n * with a strong border, and the one place a heavy shadow is allowed.\n */\nexport const surfaceClasses =\n 'z-50 animate-in rounded-lg border border-border-strong bg-surface-raised text-popover-foreground shadow-[0_16px_48px_rgb(0_0_0_/_0.18)] data-[state=closed]:animate-out data-[side=bottom]:[--bl-ty:-6px] data-[side=top]:[--bl-ty:6px] data-[side=left]:[--bl-tx:6px] data-[side=right]:[--bl-tx:-6px]';\n\nfunction Popover(props: React.ComponentProps<typeof PopoverPrimitive.Root>) {\n return <PopoverPrimitive.Root data-slot=\"popover\" {...props} />;\n}\n\nfunction PopoverTrigger(props: React.ComponentProps<typeof PopoverPrimitive.Trigger>) {\n return <PopoverPrimitive.Trigger data-slot=\"popover-trigger\" {...props} />;\n}\n\nfunction PopoverAnchor(props: React.ComponentProps<typeof PopoverPrimitive.Anchor>) {\n return <PopoverPrimitive.Anchor data-slot=\"popover-anchor\" {...props} />;\n}\n\nfunction PopoverContent({\n className,\n align = 'center',\n sideOffset = 6,\n ...props\n}: React.ComponentProps<typeof PopoverPrimitive.Content>) {\n return (\n <PopoverPrimitive.Portal>\n <PopoverPrimitive.Content\n data-slot=\"popover-content\"\n align={align}\n sideOffset={sideOffset}\n className={cn(\n surfaceClasses,\n 'w-72 max-w-[calc(100vw-2rem)] max-h-(--radix-popover-content-available-height) overflow-y-auto origin-(--radix-popover-content-transform-origin) p-4 outline-hidden',\n className,\n )}\n {...props}\n />\n </PopoverPrimitive.Portal>\n );\n}\n\nexport { Popover, PopoverAnchor, PopoverContent, PopoverTrigger };\n"],"mappings":";;;;;;;;;AASA,IAAa,iBACX;AAEF,SAASA,UAAQ,OAA2D;CAC1E,OAAO,oBAACC,QAAiB,MAAlB;EAAuB,aAAU;EAAU,GAAI;CAAQ,CAAA;AAChE;AAEA,SAAS,eAAe,OAA8D;CACpF,OAAO,oBAACA,QAAiB,SAAlB;EAA0B,aAAU;EAAkB,GAAI;CAAQ,CAAA;AAC3E;AAEA,SAAS,cAAc,OAA6D;CAClF,OAAO,oBAACA,QAAiB,QAAlB;EAAyB,aAAU;EAAiB,GAAI;CAAQ,CAAA;AACzE;AAEA,SAAS,eAAe,EACtB,WACA,QAAQ,UACR,aAAa,GACb,GAAG,SACqD;CACxD,OACE,oBAACA,QAAiB,QAAlB,EAAA,UACE,oBAACA,QAAiB,SAAlB;EACE,aAAU;EACH;EACK;EACZ,WAAW,GACT,gBACA,uKACA,SACF;EACA,GAAI;CACL,CAAA,EACsB,CAAA;AAE7B"}
|
|
1
|
+
{"version":3,"file":"popover.js","names":["Popover","PopoverPrimitive"],"sources":["../../src/components/popover.tsx"],"sourcesContent":["import { Popover as PopoverPrimitive } from 'radix-ui';\nimport * as React from 'react';\n\nimport { cn } from '../lib/utils';\n\n/**\n * The floating surface shared by popovers, menus and select lists: raised,\n * with a strong border, and the one place a heavy shadow is allowed.\n */\nexport const surfaceClasses =\n 'z-50 animate-in rounded-lg border border-border-strong bg-surface-raised text-popover-foreground shadow-[0_16px_48px_rgb(0_0_0_/_0.18)] data-[state=closed]:animate-out data-[side=bottom]:[--bl-ty:-6px] data-[side=top]:[--bl-ty:6px] data-[side=left]:[--bl-tx:6px] data-[side=right]:[--bl-tx:-6px]';\n\n/** A menu row: 32px, 8px radius; the focused row is a quiet fill, like an active tab. */\nexport const menuItemClasses =\n \"relative flex min-h-8 cursor-default items-center gap-2 rounded-sm px-2 text-[13px] outline-hidden select-none focus:bg-muted focus:text-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='text-'])]:text-muted-foreground\";\n\nfunction Popover(props: React.ComponentProps<typeof PopoverPrimitive.Root>) {\n return <PopoverPrimitive.Root data-slot=\"popover\" {...props} />;\n}\n\nfunction PopoverTrigger(props: React.ComponentProps<typeof PopoverPrimitive.Trigger>) {\n return <PopoverPrimitive.Trigger data-slot=\"popover-trigger\" {...props} />;\n}\n\nfunction PopoverAnchor(props: React.ComponentProps<typeof PopoverPrimitive.Anchor>) {\n return <PopoverPrimitive.Anchor data-slot=\"popover-anchor\" {...props} />;\n}\n\nfunction PopoverContent({\n className,\n align = 'center',\n sideOffset = 6,\n ...props\n}: React.ComponentProps<typeof PopoverPrimitive.Content>) {\n return (\n <PopoverPrimitive.Portal>\n <PopoverPrimitive.Content\n data-slot=\"popover-content\"\n align={align}\n sideOffset={sideOffset}\n className={cn(\n surfaceClasses,\n 'w-72 max-w-[calc(100vw-2rem)] max-h-(--radix-popover-content-available-height) overflow-y-auto origin-(--radix-popover-content-transform-origin) p-4 outline-hidden',\n className,\n )}\n {...props}\n />\n </PopoverPrimitive.Portal>\n );\n}\n\nexport { Popover, PopoverAnchor, PopoverContent, PopoverTrigger };\n"],"mappings":";;;;;;;;;AASA,IAAa,iBACX;;AAGF,IAAa,kBACX;AAEF,SAASA,UAAQ,OAA2D;CAC1E,OAAO,oBAACC,QAAiB,MAAlB;EAAuB,aAAU;EAAU,GAAI;CAAQ,CAAA;AAChE;AAEA,SAAS,eAAe,OAA8D;CACpF,OAAO,oBAACA,QAAiB,SAAlB;EAA0B,aAAU;EAAkB,GAAI;CAAQ,CAAA;AAC3E;AAEA,SAAS,cAAc,OAA6D;CAClF,OAAO,oBAACA,QAAiB,QAAlB;EAAyB,aAAU;EAAiB,GAAI;CAAQ,CAAA;AACzE;AAEA,SAAS,eAAe,EACtB,WACA,QAAQ,UACR,aAAa,GACb,GAAG,SACqD;CACxD,OACE,oBAACA,QAAiB,QAAlB,EAAA,UACE,oBAACA,QAAiB,SAAlB;EACE,aAAU;EACH;EACK;EACZ,WAAW,GACT,gBACA,uKACA,SACF;EACA,GAAI;CACL,CAAA,EACsB,CAAA;AAE7B"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { Group, Panel, Separator, type Layout, type LayoutChangedMeta } from 'react-resizable-panels';
|
|
3
|
+
export type ResizableLayout = Layout;
|
|
4
|
+
export interface ResizablePanelGroupProps extends Omit<React.ComponentProps<typeof Group>, 'defaultLayout' | 'onLayoutChange' | 'onLayoutChanged'> {
|
|
5
|
+
/**
|
|
6
|
+
* Controlled sizes: panel id → percentage (0..100). Pass it with
|
|
7
|
+
* onLayoutChange, or onLayoutChanged if you only need the settled value.
|
|
8
|
+
* The group re-applies it whenever it differs from what is on screen.
|
|
9
|
+
*/
|
|
10
|
+
layout?: ResizableLayout;
|
|
11
|
+
/** Initial sizes when uncontrolled, e.g. restored from storage. */
|
|
12
|
+
defaultLayout?: ResizableLayout;
|
|
13
|
+
/** Every change, including each pointer move while dragging. */
|
|
14
|
+
onLayoutChange?: (layout: ResizableLayout) => void;
|
|
15
|
+
/** After a drag ends or a key resizes; the one to persist. */
|
|
16
|
+
onLayoutChanged?: (layout: ResizableLayout, meta: LayoutChangedMeta) => void;
|
|
17
|
+
}
|
|
18
|
+
declare function ResizablePanelGroup({ className, layout, defaultLayout, groupRef: groupRefProp, orientation, ...props }: ResizablePanelGroupProps): React.JSX.Element;
|
|
19
|
+
declare function ResizablePanel({ className, ...props }: React.ComponentProps<typeof Panel>): React.JSX.Element;
|
|
20
|
+
export interface ResizeHandleProps extends React.ComponentProps<typeof Separator> {
|
|
21
|
+
/** Show a small grip in the middle of the line. */
|
|
22
|
+
withHandle?: boolean;
|
|
23
|
+
/** What the handle resizes, e.g. "Resize explorer". Required for screen readers. */
|
|
24
|
+
'aria-label': string;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* The separator between two panels. It is a 1px line with an 8px hit area;
|
|
28
|
+
* hover and drag tint it, keyboard focus draws it in the brand colour.
|
|
29
|
+
*/
|
|
30
|
+
declare function ResizeHandle({ className, withHandle, ...props }: ResizeHandleProps): React.JSX.Element;
|
|
31
|
+
export { usePanelRef, useGroupRef } from 'react-resizable-panels';
|
|
32
|
+
export type { GroupImperativeHandle as ResizablePanelGroupHandle, PanelImperativeHandle as ResizablePanelHandle, } from 'react-resizable-panels';
|
|
33
|
+
export { ResizablePanelGroup, ResizablePanel, ResizeHandle };
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { cn } from "../lib/utils.js";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import { jsx } from "react/jsx-runtime";
|
|
4
|
+
import { Group, Panel, Separator, useGroupRef, usePanelRef } from "react-resizable-panels";
|
|
5
|
+
//#region src/components/resizable.tsx
|
|
6
|
+
var sameLayout = (a, b) => {
|
|
7
|
+
const keys = Object.keys(a);
|
|
8
|
+
return keys.length === Object.keys(b).length && keys.every((k) => b[k] !== void 0 && Math.abs((a[k] ?? 0) - (b[k] ?? 0)) < .01);
|
|
9
|
+
};
|
|
10
|
+
function ResizablePanelGroup({ className, layout, defaultLayout, groupRef: groupRefProp, orientation = "horizontal", ...props }) {
|
|
11
|
+
const groupRef = React.useRef(null);
|
|
12
|
+
React.useImperativeHandle(groupRefProp, () => groupRef.current, []);
|
|
13
|
+
React.useEffect(() => {
|
|
14
|
+
const group = groupRef.current;
|
|
15
|
+
if (!layout || !group) return;
|
|
16
|
+
if (!sameLayout(group.getLayout(), layout)) group.setLayout(layout);
|
|
17
|
+
}, [layout]);
|
|
18
|
+
return /* @__PURE__ */ jsx(Group, {
|
|
19
|
+
"data-slot": "resizable-panel-group",
|
|
20
|
+
"data-orientation": orientation,
|
|
21
|
+
orientation,
|
|
22
|
+
groupRef,
|
|
23
|
+
defaultLayout: layout ?? defaultLayout,
|
|
24
|
+
className: cn("flex h-full w-full data-[orientation=vertical]:flex-col", className),
|
|
25
|
+
...props
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
function ResizablePanel({ className, ...props }) {
|
|
29
|
+
return /* @__PURE__ */ jsx(Panel, {
|
|
30
|
+
"data-slot": "resizable-panel",
|
|
31
|
+
className: cn("min-h-0 min-w-0", className),
|
|
32
|
+
...props
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* The separator between two panels. It is a 1px line with an 8px hit area;
|
|
37
|
+
* hover and drag tint it, keyboard focus draws it in the brand colour.
|
|
38
|
+
*/
|
|
39
|
+
function ResizeHandle({ className, withHandle, ...props }) {
|
|
40
|
+
return /* @__PURE__ */ jsx(Separator, {
|
|
41
|
+
"data-slot": "resize-handle",
|
|
42
|
+
className: cn("group/handle relative flex shrink-0 items-center justify-center bg-border outline-none", "after:absolute after:content-[\"\"]", "aria-[orientation=vertical]:w-px aria-[orientation=vertical]:after:inset-y-0 aria-[orientation=vertical]:after:-inset-x-1", "aria-[orientation=horizontal]:h-px aria-[orientation=horizontal]:after:inset-x-0 aria-[orientation=horizontal]:after:-inset-y-1", "transition-colors data-[separator=hover]:bg-border-strong data-[separator=active]:bg-brand", "focus-visible:outline-none data-[separator=focus]:bg-ring data-[separator=focus]:shadow-[0_0_0_1px_var(--ring)]", "data-[separator=disabled]:opacity-50", className),
|
|
43
|
+
...props,
|
|
44
|
+
children: withHandle && /* @__PURE__ */ jsx("span", {
|
|
45
|
+
"aria-hidden": true,
|
|
46
|
+
className: "z-10 flex items-center justify-center rounded-xs border bg-surface group-aria-[orientation=vertical]/handle:h-6 group-aria-[orientation=vertical]/handle:w-2 group-aria-[orientation=horizontal]/handle:h-2 group-aria-[orientation=horizontal]/handle:w-6",
|
|
47
|
+
children: /* @__PURE__ */ jsx("span", { className: "rounded-full bg-muted-foreground/60 group-aria-[orientation=vertical]/handle:h-3 group-aria-[orientation=vertical]/handle:w-px group-aria-[orientation=horizontal]/handle:h-px group-aria-[orientation=horizontal]/handle:w-3" })
|
|
48
|
+
})
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
//#endregion
|
|
52
|
+
export { ResizablePanel, ResizablePanelGroup, ResizeHandle, useGroupRef, usePanelRef };
|
|
53
|
+
|
|
54
|
+
//# sourceMappingURL=resizable.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resizable.js","names":[],"sources":["../../src/components/resizable.tsx"],"sourcesContent":["import * as React from 'react';\nimport {\n Group,\n Panel,\n Separator,\n type GroupImperativeHandle,\n type Layout,\n type LayoutChangedMeta,\n} from 'react-resizable-panels';\n\nimport { cn } from '../lib/utils';\n\n// Resizing is react-resizable-panels: it implements the WAI-ARIA window\n// splitter (arrow keys, Home/End, Enter to collapse), captures the pointer so\n// a drag over an iframe or terminal keeps tracking, and enforces min/max and\n// collapse. This file adds the Burtson look and a controlled `layout` prop.\n\nexport type ResizableLayout = Layout;\n\nexport interface ResizablePanelGroupProps extends Omit<\n React.ComponentProps<typeof Group>,\n 'defaultLayout' | 'onLayoutChange' | 'onLayoutChanged'\n> {\n /**\n * Controlled sizes: panel id → percentage (0..100). Pass it with\n * onLayoutChange, or onLayoutChanged if you only need the settled value.\n * The group re-applies it whenever it differs from what is on screen.\n */\n layout?: ResizableLayout;\n /** Initial sizes when uncontrolled, e.g. restored from storage. */\n defaultLayout?: ResizableLayout;\n /** Every change, including each pointer move while dragging. */\n onLayoutChange?: (layout: ResizableLayout) => void;\n /** After a drag ends or a key resizes; the one to persist. */\n onLayoutChanged?: (layout: ResizableLayout, meta: LayoutChangedMeta) => void;\n}\n\nconst sameLayout = (a: ResizableLayout, b: ResizableLayout) => {\n const keys = Object.keys(a);\n return (\n keys.length === Object.keys(b).length &&\n keys.every((k) => b[k] !== undefined && Math.abs((a[k] ?? 0) - (b[k] ?? 0)) < 0.01)\n );\n};\n\nfunction ResizablePanelGroup({\n className,\n layout,\n defaultLayout,\n groupRef: groupRefProp,\n orientation = 'horizontal',\n ...props\n}: ResizablePanelGroupProps) {\n const groupRef = React.useRef<GroupImperativeHandle | null>(null);\n React.useImperativeHandle(groupRefProp, () => groupRef.current as GroupImperativeHandle, []);\n\n React.useEffect(() => {\n const group = groupRef.current;\n if (!layout || !group) return;\n if (!sameLayout(group.getLayout(), layout)) group.setLayout(layout);\n }, [layout]);\n\n return (\n <Group\n data-slot=\"resizable-panel-group\"\n data-orientation={orientation}\n orientation={orientation}\n groupRef={groupRef}\n defaultLayout={layout ?? defaultLayout}\n className={cn('flex h-full w-full data-[orientation=vertical]:flex-col', className)}\n {...props}\n />\n );\n}\n\nfunction ResizablePanel({ className, ...props }: React.ComponentProps<typeof Panel>) {\n return (\n <Panel data-slot=\"resizable-panel\" className={cn('min-h-0 min-w-0', className)} {...props} />\n );\n}\n\nexport interface ResizeHandleProps extends React.ComponentProps<typeof Separator> {\n /** Show a small grip in the middle of the line. */\n withHandle?: boolean;\n /** What the handle resizes, e.g. \"Resize explorer\". Required for screen readers. */\n 'aria-label': string;\n}\n\n/**\n * The separator between two panels. It is a 1px line with an 8px hit area;\n * hover and drag tint it, keyboard focus draws it in the brand colour.\n */\nfunction ResizeHandle({ className, withHandle, ...props }: ResizeHandleProps) {\n return (\n <Separator\n data-slot=\"resize-handle\"\n className={cn(\n 'group/handle relative flex shrink-0 items-center justify-center bg-border outline-none',\n // Hit area wider than the line, on the axis being dragged.\n 'after:absolute after:content-[\"\"]',\n // The library sets aria-orientation on the line itself: a horizontal\n // group has vertical separators. Nested groups stay independent.\n 'aria-[orientation=vertical]:w-px aria-[orientation=vertical]:after:inset-y-0 aria-[orientation=vertical]:after:-inset-x-1',\n 'aria-[orientation=horizontal]:h-px aria-[orientation=horizontal]:after:inset-x-0 aria-[orientation=horizontal]:after:-inset-y-1',\n 'transition-colors data-[separator=hover]:bg-border-strong data-[separator=active]:bg-brand',\n 'focus-visible:outline-none data-[separator=focus]:bg-ring data-[separator=focus]:shadow-[0_0_0_1px_var(--ring)]',\n 'data-[separator=disabled]:opacity-50',\n className,\n )}\n {...props}\n >\n {withHandle && (\n <span\n aria-hidden\n className=\"z-10 flex items-center justify-center rounded-xs border bg-surface group-aria-[orientation=vertical]/handle:h-6 group-aria-[orientation=vertical]/handle:w-2 group-aria-[orientation=horizontal]/handle:h-2 group-aria-[orientation=horizontal]/handle:w-6\"\n >\n <span className=\"rounded-full bg-muted-foreground/60 group-aria-[orientation=vertical]/handle:h-3 group-aria-[orientation=vertical]/handle:w-px group-aria-[orientation=horizontal]/handle:h-px group-aria-[orientation=horizontal]/handle:w-3\" />\n </span>\n )}\n </Separator>\n );\n}\n\nexport { usePanelRef, useGroupRef } from 'react-resizable-panels';\nexport type {\n GroupImperativeHandle as ResizablePanelGroupHandle,\n PanelImperativeHandle as ResizablePanelHandle,\n} from 'react-resizable-panels';\nexport { ResizablePanelGroup, ResizablePanel, ResizeHandle };\n"],"mappings":";;;;;AAqCA,IAAM,cAAc,GAAoB,MAAuB;CAC7D,MAAM,OAAO,OAAO,KAAK,CAAC;CAC1B,OACE,KAAK,WAAW,OAAO,KAAK,CAAC,CAAC,CAAC,UAC/B,KAAK,OAAO,MAAM,EAAE,OAAO,KAAA,KAAa,KAAK,KAAK,EAAE,MAAM,MAAM,EAAE,MAAM,EAAE,IAAI,GAAI;AAEtF;AAEA,SAAS,oBAAoB,EAC3B,WACA,QACA,eACA,UAAU,cACV,cAAc,cACd,GAAG,SACwB;CAC3B,MAAM,WAAW,MAAM,OAAqC,IAAI;CAChE,MAAM,oBAAoB,oBAAoB,SAAS,SAAkC,CAAC,CAAC;CAE3F,MAAM,gBAAgB;EACpB,MAAM,QAAQ,SAAS;EACvB,IAAI,CAAC,UAAU,CAAC,OAAO;EACvB,IAAI,CAAC,WAAW,MAAM,UAAU,GAAG,MAAM,GAAG,MAAM,UAAU,MAAM;CACpE,GAAG,CAAC,MAAM,CAAC;CAEX,OACE,oBAAC,OAAD;EACE,aAAU;EACV,oBAAkB;EACL;EACH;EACV,eAAe,UAAU;EACzB,WAAW,GAAG,2DAA2D,SAAS;EAClF,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,eAAe,EAAE,WAAW,GAAG,SAA6C;CACnF,OACE,oBAAC,OAAD;EAAO,aAAU;EAAkB,WAAW,GAAG,mBAAmB,SAAS;EAAG,GAAI;CAAQ,CAAA;AAEhG;;;;;AAaA,SAAS,aAAa,EAAE,WAAW,YAAY,GAAG,SAA4B;CAC5E,OACE,oBAAC,WAAD;EACE,aAAU;EACV,WAAW,GACT,0FAEA,uCAGA,6HACA,mIACA,8FACA,mHACA,wCACA,SACF;EACA,GAAI;EAEH,UAAA,cACC,oBAAC,QAAD;GACE,eAAA;GACA,WAAU;GAEV,UAAA,oBAAC,QAAD,EAAM,WAAU,gOAAiO,CAAA;EAC7O,CAAA;CAEC,CAAA;AAEf"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* A registered target id (see TourAnchor), or a function returning the
|
|
4
|
+
* element. Ids are stable; never target generated class names or nth-child.
|
|
5
|
+
*/
|
|
6
|
+
export type TourTarget = string | (() => Element | null);
|
|
7
|
+
/** Marks an element as a tour target. Merges onto its one child. */
|
|
8
|
+
declare function TourAnchor({ id, children }: {
|
|
9
|
+
id: string;
|
|
10
|
+
children: React.ReactElement;
|
|
11
|
+
}): React.JSX.Element;
|
|
12
|
+
/** The same marker as TourAnchor, for elements you render yourself. */
|
|
13
|
+
export declare const tourTarget: (id: string) => {
|
|
14
|
+
'data-tour-target': string;
|
|
15
|
+
};
|
|
16
|
+
export declare function findTourTarget(target: TourTarget | undefined): Element | null;
|
|
17
|
+
/**
|
|
18
|
+
* Resolves when the target is mounted and visible, or with null after
|
|
19
|
+
* `timeoutMs` or when `signal` aborts. Handles targets that render late
|
|
20
|
+
* (lazy panels, async data) without polling forever.
|
|
21
|
+
*/
|
|
22
|
+
export declare function waitForTourTarget(target: TourTarget | undefined, timeoutMs: number, signal: AbortSignal): Promise<Element | null>;
|
|
23
|
+
export interface TourStep {
|
|
24
|
+
id: string;
|
|
25
|
+
/** Omit for a centred step with no anchor. */
|
|
26
|
+
target?: TourTarget;
|
|
27
|
+
title: React.ReactNode;
|
|
28
|
+
content: React.ReactNode;
|
|
29
|
+
side?: 'top' | 'right' | 'bottom' | 'left';
|
|
30
|
+
align?: 'start' | 'center' | 'end';
|
|
31
|
+
/**
|
|
32
|
+
* Reveal what the step points at (open a panel, switch a route) before it
|
|
33
|
+
* shows. Aborted if the person leaves the step first; a rejection shows the
|
|
34
|
+
* step centred rather than stranding the tour.
|
|
35
|
+
*/
|
|
36
|
+
prepare?: (signal: AbortSignal) => void | Promise<void>;
|
|
37
|
+
}
|
|
38
|
+
export type TourEndReason = 'complete' | 'skip' | 'close' | 'escape';
|
|
39
|
+
export interface TourLabels {
|
|
40
|
+
next: string;
|
|
41
|
+
back: string;
|
|
42
|
+
skip: string;
|
|
43
|
+
done: string;
|
|
44
|
+
close: string;
|
|
45
|
+
progress: (step: number, total: number) => string;
|
|
46
|
+
}
|
|
47
|
+
export interface TourProps {
|
|
48
|
+
steps: TourStep[];
|
|
49
|
+
open: boolean;
|
|
50
|
+
/** Controlled, zero-based. */
|
|
51
|
+
step: number;
|
|
52
|
+
onStepChange: (step: number) => void;
|
|
53
|
+
/** The tour is over. Store dismissal or completion yourself, keyed by tour id and revision. */
|
|
54
|
+
onEnd: (reason: TourEndReason, step: number) => void;
|
|
55
|
+
/** `center` (default) shows a step whose target never appears in the middle; `skip` moves past it. */
|
|
56
|
+
missingTarget?: 'center' | 'skip';
|
|
57
|
+
/** How long to wait for a late target. Default 2000ms. */
|
|
58
|
+
waitMs?: number;
|
|
59
|
+
/** Dim the page outside the target. Default true. */
|
|
60
|
+
dim?: boolean;
|
|
61
|
+
labels?: Partial<TourLabels>;
|
|
62
|
+
/** Where focus goes if the element that started the tour is gone. */
|
|
63
|
+
fallbackFocus?: () => HTMLElement | null;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* A guided sequence of anchored steps. It is non-modal: the page stays
|
|
67
|
+
* usable and outside clicks do not end it. Focus moves into each step,
|
|
68
|
+
* Escape ends the tour (unless the person is typing in a field or editor
|
|
69
|
+
* outside it), and focus returns to where it was when the tour started.
|
|
70
|
+
* The app owns the copy, the eligibility rules and what it persists.
|
|
71
|
+
*/
|
|
72
|
+
declare function Tour({ steps, open, step, onStepChange, onEnd, missingTarget, waitMs, dim, labels: labelOverrides, fallbackFocus, }: TourProps): React.JSX.Element | null;
|
|
73
|
+
export interface SpotlightProps {
|
|
74
|
+
target: TourTarget;
|
|
75
|
+
open: boolean;
|
|
76
|
+
onDismiss: (reason: 'dismiss' | 'escape') => void;
|
|
77
|
+
title: React.ReactNode;
|
|
78
|
+
children: React.ReactNode;
|
|
79
|
+
side?: 'top' | 'right' | 'bottom' | 'left';
|
|
80
|
+
align?: 'start' | 'center' | 'end';
|
|
81
|
+
/** Default "Got it". */
|
|
82
|
+
dismissLabel?: string;
|
|
83
|
+
/** An extra button, e.g. "Add a provider". */
|
|
84
|
+
action?: React.ReactNode;
|
|
85
|
+
/** Ring the target. Default true. */
|
|
86
|
+
highlight?: boolean;
|
|
87
|
+
className?: string;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* One contextual hint beside a target: a new feature, a setup nudge. It is
|
|
91
|
+
* informational, so it does not take focus or block the page. Escape (unless
|
|
92
|
+
* the person is typing elsewhere) or the dismiss button closes it. If the target is
|
|
93
|
+
* not on screen, nothing renders.
|
|
94
|
+
*/
|
|
95
|
+
declare function Spotlight({ target, open, onDismiss, title, children, side, align, dismissLabel, action, highlight, className, }: SpotlightProps): React.JSX.Element | null;
|
|
96
|
+
export { Spotlight, Tour, TourAnchor };
|