@cl-light-ds/ui 0.1.0 → 0.3.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/package.json +1 -1
- package/src/components/accordion/CHANGELOG.md +41 -41
- package/src/components/accordion/index.ts +4 -4
- package/src/components/alert/CHANGELOG.md +5 -5
- package/src/components/alert/index.ts +4 -4
- package/src/components/avatar/CHANGELOG.md +44 -44
- package/src/components/avatar/index.ts +6 -6
- package/src/components/badge/CHANGELOG.md +49 -49
- package/src/components/badge/index.ts +2 -2
- package/src/components/breadcrumb/CHANGELOG.md +24 -24
- package/src/components/breadcrumb/index.ts +5 -5
- package/src/components/button/CHANGELOG.md +41 -41
- package/src/components/button/index.ts +2 -2
- package/src/components/button-group/CHANGELOG.md +34 -34
- package/src/components/button-group/index.ts +3 -3
- package/src/components/card/CHANGELOG.md +162 -119
- package/src/components/card/Card.astro +23 -8
- package/src/components/card/CardContent.astro +1 -1
- package/src/components/card/CardDescription.astro +1 -1
- package/src/components/card/CardMedia.astro +1 -1
- package/src/components/card/CardMediaActions.astro +21 -0
- package/src/components/card/CardMediaSelect.astro +21 -0
- package/src/components/card/index.ts +12 -10
- package/src/components/carousel/CHANGELOG.md +5 -5
- package/src/components/carousel/index.ts +3 -3
- package/src/components/checkbox/CHANGELOG.md +58 -58
- package/src/components/checkbox/Checkbox.astro +2 -2
- package/src/components/checkbox/index.ts +1 -1
- package/src/components/collapsible/CHANGELOG.md +5 -5
- package/src/components/collapsible/index.ts +4 -4
- package/src/components/combobox/CHANGELOG.md +27 -27
- package/src/components/combobox/index.ts +11 -11
- package/src/components/date/CHANGELOG.md +18 -18
- package/src/components/date/index.ts +2 -2
- package/src/components/dialog/CHANGELOG.md +39 -39
- package/src/components/dialog/index.ts +9 -9
- package/src/components/dropdown-menu/CHANGELOG.md +194 -194
- package/src/components/dropdown-menu/DropdownMenuItemContent.astro +79 -79
- package/src/components/dropdown-menu/DropdownMenuPortal.astro +13 -13
- package/src/components/dropdown-menu/DropdownMenuRadioGroup.astro +13 -13
- package/src/components/dropdown-menu/dropdown-menu-item-variants.ts +24 -24
- package/src/components/dropdown-menu/index.ts +12 -12
- package/src/components/field/CHANGELOG.md +33 -33
- package/src/components/field/index.ts +10 -10
- package/src/components/hover-card/CHANGELOG.md +20 -20
- package/src/components/hover-card/index.ts +3 -3
- package/src/components/input/CHANGELOG.md +29 -29
- package/src/components/input/index.ts +2 -2
- package/src/components/input-group/CHANGELOG.md +49 -49
- package/src/components/input-group/controlClasses.ts +2 -2
- package/src/components/input-group/index.ts +6 -6
- package/src/components/item/CHANGELOG.md +27 -27
- package/src/components/item/index.ts +10 -10
- package/src/components/kbd/CHANGELOG.md +5 -5
- package/src/components/kbd/index.ts +2 -2
- package/src/components/label/CHANGELOG.md +28 -28
- package/src/components/label/index.ts +2 -2
- package/src/components/link-group/CHANGELOG.md +75 -75
- package/src/components/link-group/index.ts +5 -5
- package/src/components/link-group/link-group-list-variants.ts +15 -15
- package/src/components/marquee/CHANGELOG.md +5 -5
- package/src/components/marquee/index.ts +2 -2
- package/src/components/native-select/CHANGELOG.md +5 -5
- package/src/components/native-select/NativeSelectOption.astro +9 -9
- package/src/components/native-select/index.ts +3 -3
- package/src/components/navigation-menu/CHANGELOG.md +63 -63
- package/src/components/navigation-menu/index.ts +10 -10
- package/src/components/organisms/lightning-sidebar-nav/CHANGELOG.md +50 -0
- package/src/components/organisms/lightning-sidebar-nav/LightningSidebarNav.astro +176 -0
- package/src/components/organisms/lightning-sidebar-nav/SidebarNav.astro +50 -0
- package/src/components/organisms/lightning-sidebar-nav/SidebarNavGroup.astro +74 -0
- package/src/components/organisms/lightning-sidebar-nav/SidebarNavItem.astro +94 -0
- package/src/components/organisms/lightning-sidebar-nav/SidebarNavProBadge.astro +26 -0
- package/src/components/organisms/lightning-sidebar-nav/SidebarNavSection.astro +71 -0
- package/src/components/organisms/lightning-sidebar-nav/SidebarNavSkeleton.astro +67 -0
- package/src/components/organisms/lightning-sidebar-nav/SidebarNavSubItem.astro +69 -0
- package/src/components/organisms/lightning-sidebar-nav/SidebarNavUsage.astro +78 -0
- package/src/components/organisms/lightning-sidebar-nav/SidebarNavWorkspaceAvatar.astro +46 -0
- package/src/components/organisms/lightning-sidebar-nav/SidebarNavWorkspaceSwitcher.astro +130 -0
- package/src/components/organisms/lightning-sidebar-nav/icons.ts +46 -0
- package/src/components/organisms/lightning-sidebar-nav/index.ts +18 -0
- package/src/components/organisms/lightning-sidebar-nav/types.ts +77 -0
- package/src/components/popover/CHANGELOG.md +20 -5
- package/src/components/popover/Popover.astro +1 -0
- package/src/components/popover/PopoverContent.astro +6 -5
- package/src/components/popover/PopoverHeader.astro +1 -1
- package/src/components/popover/PopoverTrigger.astro +7 -1
- package/src/components/popover/index.ts +7 -7
- package/src/components/radio-group/CHANGELOG.md +31 -9
- package/src/components/radio-group/RadioGroup.astro +1 -1
- package/src/components/radio-group/RadioGroupItem.astro +12 -3
- package/src/components/radio-group/index.ts +3 -3
- package/src/components/select/CHANGELOG.md +39 -39
- package/src/components/select/index.ts +8 -8
- package/src/components/separator/CHANGELOG.md +5 -5
- package/src/components/separator/index.ts +2 -2
- package/src/components/skeleton/CHANGELOG.md +5 -5
- package/src/components/skeleton/index.ts +1 -1
- package/src/components/slider/CHANGELOG.md +5 -5
- package/src/components/slider/index.ts +1 -1
- package/src/components/spinner/CHANGELOG.md +18 -5
- package/src/components/spinner/Spinner.astro +3 -2
- package/src/components/spinner/index.ts +1 -1
- package/src/components/sticky-surface/CHANGELOG.md +5 -5
- package/src/components/sticky-surface/index.ts +2 -2
- package/src/components/switch/CHANGELOG.md +29 -9
- package/src/components/switch/Switch.astro +4 -4
- package/src/components/switch/index.ts +1 -1
- package/src/components/table/CHANGELOG.md +24 -5
- package/src/components/table/Table.astro +120 -12
- package/src/components/table/TableBody.astro +1 -2
- package/src/components/table/TableBulkToolbar.astro +37 -0
- package/src/components/table/TableCell.astro +25 -1
- package/src/components/table/TableCellText.astro +17 -0
- package/src/components/table/TableColumnMenu.astro +50 -0
- package/src/components/table/TableEditableCell.astro +287 -0
- package/src/components/table/TableEmpty.astro +17 -0
- package/src/components/table/TableFolderCell.astro +38 -0
- package/src/components/table/TableFooter.astro +1 -1
- package/src/components/table/TableHead.astro +71 -2
- package/src/components/table/TableHeader.astro +1 -1
- package/src/components/table/TablePagination.astro +57 -0
- package/src/components/table/TableRow.astro +32 -1
- package/src/components/table/TableSelectAllBanner.astro +34 -0
- package/src/components/table/TableSelectCell.astro +50 -0
- package/src/components/table/TableSkeletonRow.astro +21 -0
- package/src/components/table/index.ts +19 -9
- package/src/components/table/table-cell-variants.ts +29 -0
- package/src/components/tabs/CHANGELOG.md +5 -5
- package/src/components/tabs/index.ts +6 -6
- package/src/components/textarea/CHANGELOG.md +22 -5
- package/src/components/textarea/Textarea.astro +25 -3
- package/src/components/textarea/index.ts +2 -2
- package/src/components/toggle/CHANGELOG.md +23 -5
- package/src/components/toggle/Toggle.astro +13 -1
- package/src/components/toggle/index.ts +1 -1
- package/src/components/toggle-group/CHANGELOG.md +18 -5
- package/src/components/toggle-group/ToggleGroup.astro +14 -2
- package/src/components/toggle-group/index.ts +2 -2
- package/src/components/tooltip/CHANGELOG.md +22 -5
- package/src/components/tooltip/Tooltip.astro +26 -0
- package/src/components/tooltip/TooltipContent.astro +34 -9
- package/src/components/tooltip/index.ts +3 -3
- package/src/lib/table-controller.ts +1090 -0
- package/src/lib/toggle-group-controller.ts +113 -113
- package/src/lib/toggle-shared.ts +27 -26
- package/src/lib/utils.ts +6 -6
- package/src/styles/globals.css +197 -177
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
---
|
|
2
|
+
/**
|
|
3
|
+
* @component SidebarNavUsage
|
|
4
|
+
* @title Sidebar Nav Usage
|
|
5
|
+
* @description Plan usage rows (label … used / limit) and an optional full-width upgrade CTA, pinned to the bottom of the sidebar.
|
|
6
|
+
* @figmaUrl https://www.figma.com/design/qXkzdqZ3QPQqgckU3AwIAH/ClickLearn-Lightning-Design-Library?node-id=7514-198
|
|
7
|
+
*
|
|
8
|
+
* @usage
|
|
9
|
+
*
|
|
10
|
+
* ```astro nocollapse
|
|
11
|
+
* <SidebarNavUsage
|
|
12
|
+
* usage={[{ id: "recordings", label: "Recordings created", used: 5, limit: 5 }]}
|
|
13
|
+
* upgrade={{ label: "Upgrade to Pro", href: "/billing" }}
|
|
14
|
+
* />
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import { cn } from "@cl-light-ds/ui/lib/utils";
|
|
19
|
+
import { Button } from "../../button";
|
|
20
|
+
import { Separator } from "../../separator";
|
|
21
|
+
import type { SidebarNavUpgrade, SidebarNavUsageMetric } from "./types";
|
|
22
|
+
|
|
23
|
+
interface Props {
|
|
24
|
+
usage?: SidebarNavUsageMetric[];
|
|
25
|
+
upgrade?: SidebarNavUpgrade | null;
|
|
26
|
+
class?: string;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const {
|
|
30
|
+
usage = [],
|
|
31
|
+
upgrade = null,
|
|
32
|
+
class: className = "",
|
|
33
|
+
} = Astro.props as Props;
|
|
34
|
+
|
|
35
|
+
const formatValue = ({ used, limit }: SidebarNavUsageMetric) =>
|
|
36
|
+
limit === null ? `${used} / Unlimited` : `${used} / ${limit}`;
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
{
|
|
40
|
+
(usage.length > 0 || upgrade) && (
|
|
41
|
+
<div
|
|
42
|
+
data-slot="sidebar-nav-usage"
|
|
43
|
+
class={cn("flex flex-col gap-3", className)}
|
|
44
|
+
>
|
|
45
|
+
<Separator class="my-2" />
|
|
46
|
+
{usage.length > 0 && (
|
|
47
|
+
<dl class="flex flex-col gap-2 text-xs leading-4">
|
|
48
|
+
{usage.map((metric) => (
|
|
49
|
+
<div
|
|
50
|
+
data-slot="sidebar-nav-usage-metric"
|
|
51
|
+
data-at-limit={
|
|
52
|
+
metric.limit !== null && metric.used >= metric.limit
|
|
53
|
+
? ""
|
|
54
|
+
: undefined
|
|
55
|
+
}
|
|
56
|
+
class="flex items-baseline justify-between gap-2"
|
|
57
|
+
>
|
|
58
|
+
<dt class="text-muted-foreground truncate">{metric.label}</dt>
|
|
59
|
+
<dd class="text-foreground shrink-0 font-semibold whitespace-nowrap">
|
|
60
|
+
{formatValue(metric)}
|
|
61
|
+
</dd>
|
|
62
|
+
</div>
|
|
63
|
+
))}
|
|
64
|
+
</dl>
|
|
65
|
+
)}
|
|
66
|
+
{upgrade && (
|
|
67
|
+
<Button
|
|
68
|
+
as="a"
|
|
69
|
+
href={upgrade.href}
|
|
70
|
+
size="sm"
|
|
71
|
+
class="w-full font-semibold"
|
|
72
|
+
>
|
|
73
|
+
{upgrade.label}
|
|
74
|
+
</Button>
|
|
75
|
+
)}
|
|
76
|
+
</div>
|
|
77
|
+
)
|
|
78
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
---
|
|
2
|
+
/**
|
|
3
|
+
* @component SidebarNavWorkspaceAvatar
|
|
4
|
+
* @description 24px workspace avatar: image when `avatarUrl` is set, else initials, else the user-round icon on primary.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { UserRound } from "@lucide/astro";
|
|
8
|
+
import { cn } from "@cl-light-ds/ui/lib/utils";
|
|
9
|
+
import { Avatar, AvatarFallback, AvatarImage } from "../../avatar";
|
|
10
|
+
import type { SidebarNavWorkspace } from "./types";
|
|
11
|
+
|
|
12
|
+
interface Props {
|
|
13
|
+
workspace: SidebarNavWorkspace;
|
|
14
|
+
class?: string;
|
|
15
|
+
slot?: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const { workspace, class: className = "", ...rest } = Astro.props as Props;
|
|
19
|
+
|
|
20
|
+
const variant = workspace.avatarUrl
|
|
21
|
+
? "image"
|
|
22
|
+
: workspace.initials
|
|
23
|
+
? "initials"
|
|
24
|
+
: "icon";
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
<Avatar
|
|
28
|
+
{...rest}
|
|
29
|
+
size="sm"
|
|
30
|
+
variant={variant}
|
|
31
|
+
icon={variant === "icon" ? UserRound : undefined}
|
|
32
|
+
class={cn(
|
|
33
|
+
variant === "icon" &&
|
|
34
|
+
"bg-primary [&_[data-slot=avatar-icon]]:text-primary-foreground",
|
|
35
|
+
className,
|
|
36
|
+
)}
|
|
37
|
+
>
|
|
38
|
+
{workspace.avatarUrl && <AvatarImage src={workspace.avatarUrl} alt="" />}
|
|
39
|
+
{
|
|
40
|
+
!workspace.avatarUrl && workspace.initials && (
|
|
41
|
+
<AvatarFallback class="bg-primary text-primary-foreground">
|
|
42
|
+
{workspace.initials}
|
|
43
|
+
</AvatarFallback>
|
|
44
|
+
)
|
|
45
|
+
}
|
|
46
|
+
</Avatar>
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
---
|
|
2
|
+
/**
|
|
3
|
+
* @component SidebarNavWorkspaceSwitcher
|
|
4
|
+
* @title Sidebar Nav Workspace Switcher
|
|
5
|
+
* @description Current workspace (avatar + name) at the top of the sidebar. With `workspaces`, it opens a DropdownMenu to switch.
|
|
6
|
+
* @figmaUrl https://www.figma.com/design/qXkzdqZ3QPQqgckU3AwIAH/ClickLearn-Lightning-Design-Library?node-id=7514-183
|
|
7
|
+
*
|
|
8
|
+
* @usage
|
|
9
|
+
*
|
|
10
|
+
* ```astro nocollapse
|
|
11
|
+
* <SidebarNavWorkspaceSwitcher
|
|
12
|
+
* workspace={{ id: "nw", name: "Northwind Group" }}
|
|
13
|
+
* workspaces={[{ id: "nw", name: "Northwind Group" }, { id: "ct", name: "Contoso", href: "/w/ct" }]}
|
|
14
|
+
* />
|
|
15
|
+
* ```
|
|
16
|
+
*
|
|
17
|
+
* ### Events
|
|
18
|
+
*
|
|
19
|
+
* | Event | Detail | Description |
|
|
20
|
+
* |-------|--------|-------------|
|
|
21
|
+
* | `sidebar-nav:workspace-change` | `{ id: string }` | Bubbles, cancelable. Fired when a workspace is picked. If the workspace has an `href` and the event isn't cancelled, the browser navigates there. |
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
import { ChevronsUpDown } from "@lucide/astro";
|
|
25
|
+
import { cn } from "@cl-light-ds/ui/lib/utils";
|
|
26
|
+
import {
|
|
27
|
+
DropdownMenu,
|
|
28
|
+
DropdownMenuContent,
|
|
29
|
+
DropdownMenuLabel,
|
|
30
|
+
DropdownMenuRadioGroup,
|
|
31
|
+
DropdownMenuRadioItem,
|
|
32
|
+
DropdownMenuTrigger,
|
|
33
|
+
} from "../../dropdown-menu";
|
|
34
|
+
import { Separator } from "../../separator";
|
|
35
|
+
import type { SidebarNavWorkspace } from "./types";
|
|
36
|
+
import SidebarNavWorkspaceAvatar from "./SidebarNavWorkspaceAvatar.astro";
|
|
37
|
+
|
|
38
|
+
interface Props {
|
|
39
|
+
workspace: SidebarNavWorkspace;
|
|
40
|
+
/** Options in the switcher menu. Empty = static display, no menu. */
|
|
41
|
+
workspaces?: SidebarNavWorkspace[];
|
|
42
|
+
/** Heading shown at the top of the menu. */
|
|
43
|
+
menuLabel?: string;
|
|
44
|
+
class?: string;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const {
|
|
48
|
+
workspace,
|
|
49
|
+
workspaces = [],
|
|
50
|
+
menuLabel = "Workspaces",
|
|
51
|
+
class: className = "",
|
|
52
|
+
} = Astro.props as Props;
|
|
53
|
+
|
|
54
|
+
const hasMenu = workspaces.length > 0;
|
|
55
|
+
const rowClass =
|
|
56
|
+
"flex w-full items-center gap-2 overflow-hidden rounded-lg p-2 text-left text-sm leading-5 font-medium text-foreground";
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
<div data-slot="sidebar-nav-workspace" class={cn("flex flex-col", className)}>
|
|
60
|
+
{
|
|
61
|
+
hasMenu ? (
|
|
62
|
+
<DropdownMenu
|
|
63
|
+
class="block w-full"
|
|
64
|
+
defaultValue={workspace.id}
|
|
65
|
+
highlightItemOnHover
|
|
66
|
+
>
|
|
67
|
+
<DropdownMenuTrigger asChild class="flex w-full">
|
|
68
|
+
<button
|
|
69
|
+
type="button"
|
|
70
|
+
aria-label={`Switch workspace, current: ${workspace.name}`}
|
|
71
|
+
class={cn(
|
|
72
|
+
rowClass,
|
|
73
|
+
"outline-none transition-colors hover:bg-muted focus-visible:ring-1 focus-visible:ring-sidebar-ring focus-visible:ring-inset",
|
|
74
|
+
)}
|
|
75
|
+
>
|
|
76
|
+
<SidebarNavWorkspaceAvatar workspace={workspace} />
|
|
77
|
+
<span class="min-w-0 flex-1 truncate">{workspace.name}</span>
|
|
78
|
+
<ChevronsUpDown
|
|
79
|
+
aria-hidden="true"
|
|
80
|
+
class="text-foreground size-4 shrink-0"
|
|
81
|
+
/>
|
|
82
|
+
</button>
|
|
83
|
+
</DropdownMenuTrigger>
|
|
84
|
+
{/* --anchor-width isn't set by the runtime; match the 238px inner width of the 270px shell. */}
|
|
85
|
+
<DropdownMenuContent align="start" class="w-[238px]">
|
|
86
|
+
<DropdownMenuLabel>{menuLabel}</DropdownMenuLabel>
|
|
87
|
+
<DropdownMenuRadioGroup>
|
|
88
|
+
{workspaces.map((option) => (
|
|
89
|
+
<DropdownMenuRadioItem
|
|
90
|
+
value={option.id}
|
|
91
|
+
data-href={option.href}
|
|
92
|
+
avatar
|
|
93
|
+
>
|
|
94
|
+
<SidebarNavWorkspaceAvatar slot="avatar" workspace={option} />
|
|
95
|
+
{option.name}
|
|
96
|
+
</DropdownMenuRadioItem>
|
|
97
|
+
))}
|
|
98
|
+
</DropdownMenuRadioGroup>
|
|
99
|
+
</DropdownMenuContent>
|
|
100
|
+
</DropdownMenu>
|
|
101
|
+
) : (
|
|
102
|
+
<div class={rowClass}>
|
|
103
|
+
<SidebarNavWorkspaceAvatar workspace={workspace} />
|
|
104
|
+
<span class="min-w-0 flex-1 truncate">{workspace.name}</span>
|
|
105
|
+
</div>
|
|
106
|
+
)
|
|
107
|
+
}
|
|
108
|
+
<Separator class="my-2" />
|
|
109
|
+
</div>
|
|
110
|
+
|
|
111
|
+
<script>
|
|
112
|
+
document
|
|
113
|
+
.querySelectorAll<HTMLElement>('[data-slot="sidebar-nav-workspace"]')
|
|
114
|
+
.forEach((root) => {
|
|
115
|
+
root.addEventListener("dropdown-menu:select", (event) => {
|
|
116
|
+
const { value, item } = (
|
|
117
|
+
event as CustomEvent<{ value: string; item: HTMLElement | null }>
|
|
118
|
+
).detail;
|
|
119
|
+
const href = item?.dataset.href;
|
|
120
|
+
const proceed = root.dispatchEvent(
|
|
121
|
+
new CustomEvent("sidebar-nav:workspace-change", {
|
|
122
|
+
bubbles: true,
|
|
123
|
+
cancelable: true,
|
|
124
|
+
detail: { id: value },
|
|
125
|
+
}),
|
|
126
|
+
);
|
|
127
|
+
if (proceed && href) window.location.assign(href);
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
</script>
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import {
|
|
2
|
+
BookOpen,
|
|
3
|
+
ChartColumn,
|
|
4
|
+
CircleHelp,
|
|
5
|
+
FileText,
|
|
6
|
+
Folder,
|
|
7
|
+
House,
|
|
8
|
+
Library,
|
|
9
|
+
Palette,
|
|
10
|
+
Settings,
|
|
11
|
+
Trash2,
|
|
12
|
+
UserRound,
|
|
13
|
+
Users,
|
|
14
|
+
Video,
|
|
15
|
+
type AstroComponent,
|
|
16
|
+
} from "@lucide/astro";
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* String → Lucide icon registry, so backend data can name icons without
|
|
20
|
+
* importing components. Extend this map when a new destination needs an icon.
|
|
21
|
+
*/
|
|
22
|
+
export const sidebarNavIcons = {
|
|
23
|
+
"book-open": BookOpen,
|
|
24
|
+
"chart-column": ChartColumn,
|
|
25
|
+
"circle-help": CircleHelp,
|
|
26
|
+
"file-text": FileText,
|
|
27
|
+
folder: Folder,
|
|
28
|
+
house: House,
|
|
29
|
+
library: Library,
|
|
30
|
+
palette: Palette,
|
|
31
|
+
settings: Settings,
|
|
32
|
+
"trash-2": Trash2,
|
|
33
|
+
"user-round": UserRound,
|
|
34
|
+
users: Users,
|
|
35
|
+
video: Video,
|
|
36
|
+
} satisfies Record<string, AstroComponent>;
|
|
37
|
+
|
|
38
|
+
export type SidebarNavIconName = keyof typeof sidebarNavIcons;
|
|
39
|
+
|
|
40
|
+
export const resolveSidebarNavIcon = (
|
|
41
|
+
icon: SidebarNavIconName | AstroComponent | undefined,
|
|
42
|
+
): AstroComponent | undefined => {
|
|
43
|
+
if (!icon) return undefined;
|
|
44
|
+
if (typeof icon === "string") return sidebarNavIcons[icon];
|
|
45
|
+
return icon;
|
|
46
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export { default as LightningSidebarNav } from "./LightningSidebarNav.astro";
|
|
2
|
+
export { default as SidebarNav } from "./SidebarNav.astro";
|
|
3
|
+
export { default as SidebarNavGroup } from "./SidebarNavGroup.astro";
|
|
4
|
+
export { default as SidebarNavItem } from "./SidebarNavItem.astro";
|
|
5
|
+
export { sidebarNavItemVariants } from "./SidebarNavItem.astro";
|
|
6
|
+
export { default as SidebarNavProBadge } from "./SidebarNavProBadge.astro";
|
|
7
|
+
export { default as SidebarNavSection } from "./SidebarNavSection.astro";
|
|
8
|
+
export { default as SidebarNavSkeleton } from "./SidebarNavSkeleton.astro";
|
|
9
|
+
export { default as SidebarNavSubItem } from "./SidebarNavSubItem.astro";
|
|
10
|
+
export { default as SidebarNavUsage } from "./SidebarNavUsage.astro";
|
|
11
|
+
export { default as SidebarNavWorkspaceAvatar } from "./SidebarNavWorkspaceAvatar.astro";
|
|
12
|
+
export { default as SidebarNavWorkspaceSwitcher } from "./SidebarNavWorkspaceSwitcher.astro";
|
|
13
|
+
export {
|
|
14
|
+
resolveSidebarNavIcon,
|
|
15
|
+
sidebarNavIcons,
|
|
16
|
+
type SidebarNavIconName,
|
|
17
|
+
} from "./icons";
|
|
18
|
+
export * from "./types";
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import type { AstroComponent } from "@lucide/astro";
|
|
2
|
+
import type { SidebarNavIconName } from "./icons";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Backend contract for the Lightning Sidebar Nav.
|
|
6
|
+
* Everything except `AstroComponent` icons is JSON-serialisable, so a page can
|
|
7
|
+
* pass an API response straight into `<LightningSidebarNav />`.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/** Registry key (from backend data) or a Lucide component (hand-authored markup). */
|
|
11
|
+
export type SidebarNavIcon = SidebarNavIconName | AstroComponent;
|
|
12
|
+
|
|
13
|
+
/** A top-level destination (Figma: Group Item / Variant=Default). */
|
|
14
|
+
export interface SidebarNavLink {
|
|
15
|
+
id: string;
|
|
16
|
+
label: string;
|
|
17
|
+
href: string;
|
|
18
|
+
icon?: SidebarNavIcon;
|
|
19
|
+
/** Shows the Accent/Small "Pro" badge. The link still navigates. */
|
|
20
|
+
pro?: boolean;
|
|
21
|
+
disabled?: boolean;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** A destination nested under a group (Figma: Group item / .Nav Item). */
|
|
25
|
+
export interface SidebarNavSubLink {
|
|
26
|
+
id: string;
|
|
27
|
+
label: string;
|
|
28
|
+
href: string;
|
|
29
|
+
pro?: boolean;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** An expandable parent (Figma: Group Item / Variant=Collapsed | Expanded). */
|
|
33
|
+
export interface SidebarNavGroup {
|
|
34
|
+
id: string;
|
|
35
|
+
label: string;
|
|
36
|
+
icon?: SidebarNavIcon;
|
|
37
|
+
pro?: boolean;
|
|
38
|
+
children: SidebarNavSubLink[];
|
|
39
|
+
/** Force the initial open state. Groups with an active child open automatically. */
|
|
40
|
+
defaultOpen?: boolean;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export type SidebarNavEntry = SidebarNavLink | SidebarNavGroup;
|
|
44
|
+
|
|
45
|
+
/** A block of entries, optionally headed by a category label (Figma: Variant=Category). */
|
|
46
|
+
export interface SidebarNavSectionData {
|
|
47
|
+
id: string;
|
|
48
|
+
label?: string;
|
|
49
|
+
items: SidebarNavEntry[];
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export interface SidebarNavWorkspace {
|
|
53
|
+
id: string;
|
|
54
|
+
name: string;
|
|
55
|
+
avatarUrl?: string;
|
|
56
|
+
initials?: string;
|
|
57
|
+
/** When set, choosing this workspace navigates here. Otherwise `sidebar-nav:workspace-change` fires. */
|
|
58
|
+
href?: string;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export interface SidebarNavUsageMetric {
|
|
62
|
+
id: string;
|
|
63
|
+
label: string;
|
|
64
|
+
used: number;
|
|
65
|
+
/** `null` means unlimited. */
|
|
66
|
+
limit: number | null;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export interface SidebarNavUpgrade {
|
|
70
|
+
label: string;
|
|
71
|
+
href: string;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export const isSidebarNavGroup = (
|
|
75
|
+
entry: SidebarNavEntry,
|
|
76
|
+
): entry is SidebarNavGroup =>
|
|
77
|
+
Array.isArray((entry as SidebarNavGroup).children);
|
|
@@ -1,5 +1,20 @@
|
|
|
1
|
-
# Changelog
|
|
2
|
-
|
|
3
|
-
All notable changes to the `Popover` component
|
|
4
|
-
|
|
5
|
-
##
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to the `Popover` component family (`Popover`, `PopoverTrigger`, `PopoverContent`, `PopoverHeader`, `PopoverTitle`, `PopoverDescription`, `PopoverClose`) are documented in this file.
|
|
4
|
+
|
|
5
|
+
## 2026-09-18 — Figma alignment (ClickLearn Lightning Design Library, node `5548-11795`)
|
|
6
|
+
|
|
7
|
+
Figma documents Popover across two pages: Items (the trigger button's Default/Hover/Pressed/Focus/Disabled states) and the expanded popover (12 Side × Alignment combinations, all sharing the same panel styling).
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
- Added the missing `@figmaUrl` (this component never had one).
|
|
12
|
+
- `PopoverContent`: replaced the `ring-1 ring-foreground/10` border approximation with a real `border border-border`, and `shadow-md` → `shadow-lg` — matching Figma's tokens (`border` = `#e4e4e7`, a named `shadow-lg`), same category of fix already made to `DialogContent`/`HoverCardContent`.
|
|
13
|
+
- `PopoverContent`: removed a dead, redundant raw class string duplicating most of `contentVariants()` — same class of bug already fixed on `HoverCardContent`. It also carried two genuinely dead selectors, `data-[side=inline-start]:...`/`data-[side=inline-end]:...`, which the underlying `@data-slot/popover` behavior library never actually sets (confirmed by checking its source — it only ever sets physical `top`/`bottom`/`left`/`right`, matching the component's own `side` prop type). Also removed the dead `rounded-md` (a later `rounded-lg` always won anyway) and a `duration-100`/`duration-150` conflict (150ms was already winning).
|
|
14
|
+
- `PopoverHeader`: `gap-1` (4px) → `gap-0.5` (2px) between `PopoverTitle`/`PopoverDescription`, matching Figma's measured 2px gap.
|
|
15
|
+
- `PopoverTrigger`: now defaults to `variant="outline"` instead of inheriting `Button`'s own `default` (solid primary) variant — Figma's Default trigger state is a bordered/light button, matching outline exactly, and every existing usage example already passed `variant="outline"` explicitly. Visually a no-op for existing usages; makes new usages match the documented default without needing to repeat the prop.
|
|
16
|
+
|
|
17
|
+
### Notes
|
|
18
|
+
|
|
19
|
+
- The trigger's Hover/Pressed/Focus/Disabled states are entirely `Button`'s own responsibility (`PopoverTrigger` just renders a `Button`) — already verified correct in earlier passes, no changes needed here.
|
|
20
|
+
- `bg-popover`/`text-popover-foreground`, `p-4`, and `rounded-lg` already matched Figma's tokens exactly.
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
* @component Popover
|
|
4
4
|
* @title Popover
|
|
5
5
|
* @description A floating panel that appears on trigger click, useful for displaying rich content like forms or additional information.
|
|
6
|
+
* @figmaUrl https://www.figma.com/design/qXkzdqZ3QPQqgckU3AwIAH/ClickLearn-Lightning-Design-Library?node-id=5548-11795
|
|
6
7
|
*
|
|
7
8
|
* @preview
|
|
8
9
|
* <Popover>
|
|
@@ -21,11 +21,16 @@ const {
|
|
|
21
21
|
} = Astro.props as Props;
|
|
22
22
|
|
|
23
23
|
const contentVariants = cva([
|
|
24
|
+
// visibility
|
|
24
25
|
"z-50 duration-150 ease transition-discrete outline-hidden flex flex-col",
|
|
26
|
+
// animations
|
|
25
27
|
"data-[state=open]:animate-in data-[state=closed]:animate-out",
|
|
26
28
|
"data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
|
|
27
29
|
"data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95",
|
|
28
30
|
"data-[side=bottom]:slide-in-from-top-2 data-[side=top]:slide-in-from-bottom-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2",
|
|
31
|
+
// styles
|
|
32
|
+
"bg-popover text-popover-foreground gap-4 rounded-lg border border-border p-4 text-sm shadow-lg",
|
|
33
|
+
// origin from positioner
|
|
29
34
|
"origin-(--transform-origin) [--tw-animation-fill-mode:both]",
|
|
30
35
|
]);
|
|
31
36
|
---
|
|
@@ -39,11 +44,7 @@ const contentVariants = cva([
|
|
|
39
44
|
data-side={side}
|
|
40
45
|
data-side-offset={sideOffset}
|
|
41
46
|
style={`--side-offset: ${sideOffset}px`}
|
|
42
|
-
class={cn(
|
|
43
|
-
"bg-popover text-popover-foreground data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 data-closed:zoom-out-95 data-open:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 ring-foreground/10 flex flex-col gap-4 rounded-md p-4 text-sm shadow-md ring-1 duration-100 rounded-lg data-[side=inline-start]:slide-in-from-right-2 data-[side=inline-end]:slide-in-from-left-2",
|
|
44
|
-
contentVariants(),
|
|
45
|
-
className,
|
|
46
|
-
)}
|
|
47
|
+
class={cn(contentVariants(), className)}
|
|
47
48
|
>
|
|
48
49
|
<slot />
|
|
49
50
|
</div>
|
|
@@ -9,7 +9,12 @@ type Props = ButtonProps & {
|
|
|
9
9
|
asChild?: boolean;
|
|
10
10
|
};
|
|
11
11
|
|
|
12
|
-
const {
|
|
12
|
+
const {
|
|
13
|
+
class: className = "",
|
|
14
|
+
asChild = false,
|
|
15
|
+
variant = "outline",
|
|
16
|
+
...rest
|
|
17
|
+
} = Astro.props as Props;
|
|
13
18
|
---
|
|
14
19
|
|
|
15
20
|
{
|
|
@@ -20,6 +25,7 @@ const { class: className = "", asChild = false, ...rest } = Astro.props as Props
|
|
|
20
25
|
) : (
|
|
21
26
|
<Button
|
|
22
27
|
data-slot="popover-trigger"
|
|
28
|
+
variant={variant}
|
|
23
29
|
class={cn("", "inline-flex items-center", className)}
|
|
24
30
|
{...rest as any}
|
|
25
31
|
>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
export { default as Popover } from "./Popover.astro";
|
|
2
|
-
export { default as PopoverClose } from "./PopoverClose.astro";
|
|
3
|
-
export { default as PopoverContent } from "./PopoverContent.astro";
|
|
4
|
-
export { default as PopoverDescription } from "./PopoverDescription.astro";
|
|
5
|
-
export { default as PopoverHeader } from "./PopoverHeader.astro";
|
|
6
|
-
export { default as PopoverTitle } from "./PopoverTitle.astro";
|
|
7
|
-
export { default as PopoverTrigger } from "./PopoverTrigger.astro";
|
|
1
|
+
export { default as Popover } from "./Popover.astro";
|
|
2
|
+
export { default as PopoverClose } from "./PopoverClose.astro";
|
|
3
|
+
export { default as PopoverContent } from "./PopoverContent.astro";
|
|
4
|
+
export { default as PopoverDescription } from "./PopoverDescription.astro";
|
|
5
|
+
export { default as PopoverHeader } from "./PopoverHeader.astro";
|
|
6
|
+
export { default as PopoverTitle } from "./PopoverTitle.astro";
|
|
7
|
+
export { default as PopoverTrigger } from "./PopoverTrigger.astro";
|
|
@@ -1,9 +1,31 @@
|
|
|
1
|
-
# Changelog
|
|
2
|
-
|
|
3
|
-
All notable changes to the `RadioGroup` component
|
|
4
|
-
|
|
5
|
-
## Unreleased
|
|
6
|
-
|
|
7
|
-
### Fixed
|
|
8
|
-
|
|
9
|
-
- Restored interactivity: `@data-slot/radio-group` (already the correct import in `RadioGroup.astro`) was never added as a dependency and was aliased to a no-op stub so builds wouldn't crash, leaving RadioGroup fully static. Added the real package as a dependency and removed the stub alias.
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to the `RadioGroup` component family (`RadioGroup`, `RadioGroupItem`) are documented in this file.
|
|
4
|
+
|
|
5
|
+
## Unreleased
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
|
|
9
|
+
- Restored interactivity: `@data-slot/radio-group` (already the correct import in `RadioGroup.astro`) was never added as a dependency and was aliased to a no-op stub so builds wouldn't crash, leaving RadioGroup fully static. Added the real package as a dependency and removed the stub alias.
|
|
10
|
+
|
|
11
|
+
## 2026-09-18 — Figma alignment (ClickLearn Lightning Design Library, node `50-3604`)
|
|
12
|
+
|
|
13
|
+
Figma documents Radio across four pages: Variants (Default, Checked), States (Default, Hover, Focus, Disabled), Sizes (Small 16px, Large 20px), and Contents (Clean, Label, Label and Caption).
|
|
14
|
+
|
|
15
|
+
### Fixed
|
|
16
|
+
|
|
17
|
+
- Updated `@figmaUrl` from the old Bejamas file to the ClickLearn Lightning Design Library link.
|
|
18
|
+
- **Checked-state color was backwards** — the real, visually significant bug here. The code filled the whole circle with `bg-primary` + a white (`bg-primary-foreground`) center dot when checked. Figma shows the opposite: the circle stays white (`card`) with a `border-primary` ring, and only the small center dot is `bg-primary` — a standard bordered radio with a colored dot, not a filled disc. Fixed by removing `data-checked:bg-primary`/`data-checked:text-primary-foreground` and changing the indicator dot from `bg-primary-foreground` to `bg-primary`.
|
|
19
|
+
- Background: added an explicit, unconditional `bg-card` — previously the root only had `dark:bg-input/30` with nothing for light mode, same category of fix already made to `Input`/`InputGroup`/`DialogContent`.
|
|
20
|
+
- Added `size?: "default" | "lg"` to `RadioGroupItem` (16px / 20px, matching Figma's Small/Large) — previously hard-coded to `size-4` (16px) only. The indicator dot scales proportionally (8px / 10px, matching Figma's exact 0.5 dot-to-circle ratio at both sizes measured directly from the Figma node).
|
|
21
|
+
|
|
22
|
+
### Added
|
|
23
|
+
|
|
24
|
+
- Storybook examples for Sizes, "Label and caption" (via `Field`/`FieldLabel`/`FieldDescription`, matching Figma's third content variant — `RadioGroupItem` already carries the `data-slot="radio-group-item"` marker that `Field`'s alignment selector targets, from the earlier Checkbox alignment work, so no additional alignment fix was needed here), and Disabled — none of these were previously demonstrated.
|
|
25
|
+
|
|
26
|
+
### Notes
|
|
27
|
+
|
|
28
|
+
- Focus (`focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50`) and error/`aria-invalid` styling already matched Figma's tokens exactly (`ring` = `#5f9de6`) — no changes needed.
|
|
29
|
+
- Hover isn't implemented, per the standing project direction to skip hover states.
|
|
30
|
+
- Disabled's exact color treatment in Figma is ambiguous from the extracted tokens (bound to what look like incidental, non-muted swatch names at reduced opacity rather than a clear flat color swap like Checkbox/Input had) — left as the existing `disabled:opacity-50` fade rather than guessing a specific flat-color replacement.
|
|
31
|
+
- "Clean" and "Label" content variants were already fully supported (a bare `RadioGroupItem`, or paired with a sibling `Label`) — no changes needed.
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* @component RadioGroup
|
|
4
4
|
* @title Radio Group
|
|
5
5
|
* @description A group of options where users can select exactly one choice.
|
|
6
|
-
* @figmaUrl https://www.figma.com/design/
|
|
6
|
+
* @figmaUrl https://www.figma.com/design/qXkzdqZ3QPQqgckU3AwIAH/ClickLearn-Lightning-Design-Library?node-id=50-3604
|
|
7
7
|
*
|
|
8
8
|
* @preview
|
|
9
9
|
*
|
|
@@ -4,6 +4,7 @@ import type { HTMLAttributes } from "astro/types";
|
|
|
4
4
|
|
|
5
5
|
interface Props extends HTMLAttributes<"span"> {
|
|
6
6
|
value: string;
|
|
7
|
+
size?: "default" | "lg";
|
|
7
8
|
class?: string;
|
|
8
9
|
disabled?: boolean;
|
|
9
10
|
id?: string;
|
|
@@ -14,6 +15,7 @@ const {
|
|
|
14
15
|
class: className = "",
|
|
15
16
|
id = "",
|
|
16
17
|
value,
|
|
18
|
+
size = "default",
|
|
17
19
|
disabled = false,
|
|
18
20
|
"aria-invalid": ariaInvalid,
|
|
19
21
|
...rest
|
|
@@ -25,18 +27,25 @@ const {
|
|
|
25
27
|
id={id}
|
|
26
28
|
data-slot="radio-group-item"
|
|
27
29
|
data-value={value}
|
|
30
|
+
data-size={size}
|
|
28
31
|
data-disabled={disabled ? "true" : undefined}
|
|
29
32
|
aria-invalid={ariaInvalid}
|
|
30
33
|
class={cn(
|
|
31
|
-
"border-input
|
|
34
|
+
"border-input bg-card data-checked:border-primary aria-invalid:aria-checked:border-primary aria-invalid:border-destructive focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 dark:aria-invalid:border-destructive/50 flex rounded-full focus-visible:ring-3 aria-invalid:ring-3 group/radio-group-item peer relative aspect-square shrink-0 border outline-none after:absolute after:-inset-x-3 after:-inset-y-2 disabled:cursor-not-allowed disabled:opacity-50",
|
|
35
|
+
size === "lg" ? "size-5" : "size-4",
|
|
32
36
|
className,
|
|
33
37
|
)}
|
|
34
38
|
>
|
|
35
39
|
<span
|
|
36
40
|
aria-hidden="true"
|
|
37
41
|
data-slot="radio-group-indicator"
|
|
38
|
-
class="flex
|
|
42
|
+
class={cn("flex items-center justify-center data-unchecked:hidden", size === "lg" ? "size-5" : "size-4")}
|
|
39
43
|
>
|
|
40
|
-
<span
|
|
44
|
+
<span
|
|
45
|
+
class={cn(
|
|
46
|
+
"bg-primary absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 rounded-full",
|
|
47
|
+
size === "lg" ? "size-2.5" : "size-2",
|
|
48
|
+
)}
|
|
49
|
+
></span>
|
|
41
50
|
</span>
|
|
42
51
|
</span>
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { default as RadioGroup } from "./RadioGroup.astro";
|
|
2
|
-
export { default as RadioGroupItem } from "./RadioGroupItem.astro";
|
|
3
|
-
|
|
1
|
+
export { default as RadioGroup } from "./RadioGroup.astro";
|
|
2
|
+
export { default as RadioGroupItem } from "./RadioGroupItem.astro";
|
|
3
|
+
|