@lessly/ui 1.6.0 → 2.0.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 +31 -14
- package/dist/chunk-F5RMHSPS.js +433 -0
- package/dist/index.d.ts +34 -104
- package/dist/index.js +1300 -1896
- package/dist/router.d.ts +101 -0
- package/dist/router.js +254 -0
- package/dist/styles-federated.css +105 -0
- package/dist/styles.css +106 -1
- package/dist/tailwind-preset.js +23 -1
- package/package.json +11 -3
package/dist/router.d.ts
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { LucideIcon } from 'lucide-react';
|
|
3
|
+
|
|
4
|
+
type ExtensionLinkUiMode = 'federation' | 'standalone';
|
|
5
|
+
interface ExtensionLinkProps extends Omit<React.AnchorHTMLAttributes<HTMLAnchorElement>, 'href'> {
|
|
6
|
+
/**
|
|
7
|
+
* 'federation' → the extension runs inside the workspace shell and navigates
|
|
8
|
+
* client-side via react-router's <Link>. 'standalone' → the extension is
|
|
9
|
+
* served full-page, so a plain <a href> triggers a normal document load.
|
|
10
|
+
*/
|
|
11
|
+
uiMode: ExtensionLinkUiMode;
|
|
12
|
+
/** Target route/href. */
|
|
13
|
+
to: string;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Federation-aware navigation link. Federation extensions are mounted in-shell
|
|
17
|
+
* and navigate client-side (react-router <Link>); standalone extensions load
|
|
18
|
+
* full-page (<a href>). Anchor props are forwarded to both variants — in
|
|
19
|
+
* particular onMouseEnter/onFocus, which hosts use to preload the target route.
|
|
20
|
+
*
|
|
21
|
+
* The federation branch renders a react-router <Link>, so it must be used
|
|
22
|
+
* within a Router context (the workspace shell / MemoryRouter in tests).
|
|
23
|
+
*/
|
|
24
|
+
declare function ExtensionLink({ uiMode, to, className, children, ...anchorProps }: ExtensionLinkProps): React.JSX.Element;
|
|
25
|
+
declare namespace ExtensionLink {
|
|
26
|
+
var displayName: string;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
interface NavItem {
|
|
30
|
+
label: string;
|
|
31
|
+
href: string;
|
|
32
|
+
icon?: LucideIcon;
|
|
33
|
+
exact?: boolean;
|
|
34
|
+
}
|
|
35
|
+
type NavLinkComponent = React.ComponentType<{
|
|
36
|
+
to: string;
|
|
37
|
+
className?: string;
|
|
38
|
+
children?: React.ReactNode;
|
|
39
|
+
} & Record<string, unknown>>;
|
|
40
|
+
interface SidebarNavLinkProps {
|
|
41
|
+
item: NavItem;
|
|
42
|
+
collapsed?: boolean;
|
|
43
|
+
active?: boolean;
|
|
44
|
+
basePath?: string;
|
|
45
|
+
LinkComponent?: NavLinkComponent;
|
|
46
|
+
className?: string;
|
|
47
|
+
}
|
|
48
|
+
declare function SidebarNavLink({ item, collapsed, active, basePath, LinkComponent, className, }: SidebarNavLinkProps): React.JSX.Element;
|
|
49
|
+
interface SidebarNavProps {
|
|
50
|
+
items: NavItem[];
|
|
51
|
+
collapsed?: boolean;
|
|
52
|
+
basePath?: string;
|
|
53
|
+
LinkComponent?: NavLinkComponent;
|
|
54
|
+
isItemActive?: (item: NavItem, pathname: string) => boolean;
|
|
55
|
+
className?: string;
|
|
56
|
+
}
|
|
57
|
+
declare function SidebarNav({ items, collapsed, basePath, LinkComponent, isItemActive, className, }: SidebarNavProps): React.JSX.Element;
|
|
58
|
+
|
|
59
|
+
interface AppSidebarProps {
|
|
60
|
+
items: NavItem[];
|
|
61
|
+
/** Expanded-slot mark/wordmark, rendered when `header` is absent. Also the collapsed-rail
|
|
62
|
+
* fallback when `logoCollapsed` isn't given, on a rail that isn't `collapsible` — see
|
|
63
|
+
* `logoCollapsed`. */
|
|
64
|
+
logo?: React.ReactNode;
|
|
65
|
+
/** Collapsed-rail identity — a small mark, for a rail that cannot be expanded from inside it.
|
|
66
|
+
* A `collapsible` rail shows the pin here instead and never reads this: the 52px rail holds
|
|
67
|
+
* one box, and the way back to expanded is what it holds. */
|
|
68
|
+
logoCollapsed?: React.ReactNode;
|
|
69
|
+
/** Identity slot above the rail — e.g. an <OrgProductSwitcher/> (#266). Falls back to `logo`.
|
|
70
|
+
* Expanded-only: rendering it in the 52px collapsed rail would overflow, so the collapsed
|
|
71
|
+
* branch never reads it. What stands in depends on `collapsible` — the pin when it is set,
|
|
72
|
+
* `logoCollapsed ?? logo` when it is not. */
|
|
73
|
+
header?: React.ReactNode;
|
|
74
|
+
/** Account slot below the rail — e.g. a <UserMenu/>. Its divider renders only with it. */
|
|
75
|
+
footer?: React.ReactNode;
|
|
76
|
+
/** Render the built-in collapse pin. Off by default: the shipped rail has none.
|
|
77
|
+
* `collapsed` is still honoured without it, for consumers driving collapse themselves. */
|
|
78
|
+
collapsible?: boolean;
|
|
79
|
+
collapsed?: boolean;
|
|
80
|
+
defaultCollapsed?: boolean;
|
|
81
|
+
onCollapsedChange?: (collapsed: boolean) => void;
|
|
82
|
+
basePath?: string;
|
|
83
|
+
LinkComponent?: NavLinkComponent;
|
|
84
|
+
isItemActive?: (item: NavItem, pathname: string) => boolean;
|
|
85
|
+
className?: string;
|
|
86
|
+
}
|
|
87
|
+
declare function AppSidebar({ items, logo, logoCollapsed, header, footer, collapsible, collapsed: controlled, defaultCollapsed, onCollapsedChange, basePath, LinkComponent, isItemActive, className, }: AppSidebarProps): React.JSX.Element;
|
|
88
|
+
|
|
89
|
+
interface AppShellProps {
|
|
90
|
+
/** The sidebar, typically an <AppSidebar/>. Rendered in the desktop rail and,
|
|
91
|
+
* on mobile, inside a Sheet (force-expanded via cloneElement collapsed=false). */
|
|
92
|
+
sidebar: React.ReactNode;
|
|
93
|
+
topBar?: React.ReactNode;
|
|
94
|
+
children?: React.ReactNode;
|
|
95
|
+
className?: string;
|
|
96
|
+
}
|
|
97
|
+
declare function AppShell({ sidebar, topBar, children, className }: AppShellProps): React.JSX.Element;
|
|
98
|
+
/** Alias of AppShell — reads better in app router files. */
|
|
99
|
+
declare const AuthenticatedLayout: typeof AppShell;
|
|
100
|
+
|
|
101
|
+
export { AppShell, type AppShellProps, AppSidebar, type AppSidebarProps, AuthenticatedLayout, ExtensionLink, type ExtensionLinkProps, type ExtensionLinkUiMode, type NavItem, type NavLinkComponent, SidebarNav, SidebarNavLink, type SidebarNavLinkProps, type SidebarNavProps };
|
package/dist/router.js
ADDED
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Button,
|
|
3
|
+
NavRow,
|
|
4
|
+
Sheet,
|
|
5
|
+
SheetContent,
|
|
6
|
+
SheetDescription,
|
|
7
|
+
SheetTitle,
|
|
8
|
+
SheetTrigger,
|
|
9
|
+
Tooltip,
|
|
10
|
+
TooltipContent,
|
|
11
|
+
TooltipProvider,
|
|
12
|
+
TooltipTrigger,
|
|
13
|
+
cn,
|
|
14
|
+
useIsMobile,
|
|
15
|
+
useSidebar
|
|
16
|
+
} from "./chunk-F5RMHSPS.js";
|
|
17
|
+
|
|
18
|
+
// src/components/extension-link.tsx
|
|
19
|
+
import { Link } from "react-router";
|
|
20
|
+
import { jsx } from "react/jsx-runtime";
|
|
21
|
+
function ExtensionLink({ uiMode, to, className, children, ...anchorProps }) {
|
|
22
|
+
if (uiMode === "federation") {
|
|
23
|
+
return /* @__PURE__ */ jsx(Link, { to, className, ...anchorProps, children });
|
|
24
|
+
}
|
|
25
|
+
return /* @__PURE__ */ jsx("a", { href: to, className, ...anchorProps, children });
|
|
26
|
+
}
|
|
27
|
+
ExtensionLink.displayName = "ExtensionLink";
|
|
28
|
+
|
|
29
|
+
// src/components/sidebar-nav.tsx
|
|
30
|
+
import { Link as Link2, useLocation } from "react-router";
|
|
31
|
+
import { jsx as jsx2, jsxs } from "react/jsx-runtime";
|
|
32
|
+
function isActivePath(pathname, full, exact) {
|
|
33
|
+
if (exact) return pathname === full;
|
|
34
|
+
return pathname === full || pathname.startsWith(`${full}/`);
|
|
35
|
+
}
|
|
36
|
+
function SidebarNavLink({
|
|
37
|
+
item,
|
|
38
|
+
collapsed = false,
|
|
39
|
+
active = false,
|
|
40
|
+
basePath = "",
|
|
41
|
+
LinkComponent,
|
|
42
|
+
className
|
|
43
|
+
}) {
|
|
44
|
+
const Comp = LinkComponent ?? Link2;
|
|
45
|
+
const to = `${basePath}${item.href}`;
|
|
46
|
+
const Icon = item.icon;
|
|
47
|
+
const link = /* @__PURE__ */ jsx2(
|
|
48
|
+
NavRow,
|
|
49
|
+
{
|
|
50
|
+
variant: "rail",
|
|
51
|
+
active,
|
|
52
|
+
label: item.label,
|
|
53
|
+
hideLabel: collapsed,
|
|
54
|
+
icon: Icon ? /* @__PURE__ */ jsx2(Icon, { "aria-hidden": "true" }) : void 0,
|
|
55
|
+
className: cn(collapsed && "size-9 justify-center px-0 py-0", className),
|
|
56
|
+
asChild: true,
|
|
57
|
+
children: /* @__PURE__ */ jsx2(Comp, { to, "aria-current": active ? "page" : void 0 })
|
|
58
|
+
}
|
|
59
|
+
);
|
|
60
|
+
if (!collapsed) return link;
|
|
61
|
+
return /* @__PURE__ */ jsxs(Tooltip, { children: [
|
|
62
|
+
/* @__PURE__ */ jsx2(TooltipTrigger, { asChild: true, children: link }),
|
|
63
|
+
/* @__PURE__ */ jsx2(TooltipContent, { side: "right", children: item.label })
|
|
64
|
+
] });
|
|
65
|
+
}
|
|
66
|
+
function SidebarNav({
|
|
67
|
+
items,
|
|
68
|
+
collapsed = false,
|
|
69
|
+
basePath = "",
|
|
70
|
+
LinkComponent,
|
|
71
|
+
isItemActive,
|
|
72
|
+
className
|
|
73
|
+
}) {
|
|
74
|
+
const { pathname } = useLocation();
|
|
75
|
+
const nav = /* @__PURE__ */ jsx2(
|
|
76
|
+
"nav",
|
|
77
|
+
{
|
|
78
|
+
className: cn(
|
|
79
|
+
"flex flex-col gap-2",
|
|
80
|
+
collapsed && "items-center",
|
|
81
|
+
className
|
|
82
|
+
),
|
|
83
|
+
children: items.map((item) => {
|
|
84
|
+
const full = `${basePath}${item.href}`;
|
|
85
|
+
const active = isItemActive ? isItemActive(item, pathname) : isActivePath(pathname, full, item.exact);
|
|
86
|
+
return /* @__PURE__ */ jsx2(
|
|
87
|
+
SidebarNavLink,
|
|
88
|
+
{
|
|
89
|
+
item,
|
|
90
|
+
active,
|
|
91
|
+
collapsed,
|
|
92
|
+
basePath,
|
|
93
|
+
LinkComponent
|
|
94
|
+
},
|
|
95
|
+
item.href
|
|
96
|
+
);
|
|
97
|
+
})
|
|
98
|
+
}
|
|
99
|
+
);
|
|
100
|
+
return collapsed ? /* @__PURE__ */ jsx2(TooltipProvider, { children: nav }) : nav;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// src/components/app-sidebar.tsx
|
|
104
|
+
import { PanelLeft } from "lucide-react";
|
|
105
|
+
import { Fragment, jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
106
|
+
function Divider({ collapsed, testId, className }) {
|
|
107
|
+
return /* @__PURE__ */ jsx3(
|
|
108
|
+
"div",
|
|
109
|
+
{
|
|
110
|
+
"data-testid": testId,
|
|
111
|
+
className: cn(
|
|
112
|
+
"h-px shrink-0 bg-border-subtle",
|
|
113
|
+
collapsed ? "ml-[6px] w-[40px]" : "ml-[14px] w-[220px]",
|
|
114
|
+
className
|
|
115
|
+
)
|
|
116
|
+
}
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
function AppSidebar({
|
|
120
|
+
items,
|
|
121
|
+
logo,
|
|
122
|
+
logoCollapsed,
|
|
123
|
+
header,
|
|
124
|
+
footer,
|
|
125
|
+
collapsible = false,
|
|
126
|
+
collapsed: controlled,
|
|
127
|
+
defaultCollapsed,
|
|
128
|
+
onCollapsedChange,
|
|
129
|
+
basePath,
|
|
130
|
+
LinkComponent,
|
|
131
|
+
isItemActive,
|
|
132
|
+
className
|
|
133
|
+
}) {
|
|
134
|
+
const { collapsed, toggle } = useSidebar({
|
|
135
|
+
collapsed: controlled,
|
|
136
|
+
defaultCollapsed,
|
|
137
|
+
onCollapsedChange
|
|
138
|
+
});
|
|
139
|
+
const pin = collapsible ? /* @__PURE__ */ jsx3(
|
|
140
|
+
"button",
|
|
141
|
+
{
|
|
142
|
+
type: "button",
|
|
143
|
+
onClick: toggle,
|
|
144
|
+
"aria-label": collapsed ? "Expand sidebar" : "Collapse sidebar",
|
|
145
|
+
"aria-expanded": !collapsed,
|
|
146
|
+
className: "flex size-6 shrink-0 items-center justify-center rounded-md text-text-secondary transition-colors hover:bg-[var(--hov-bg)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-focus",
|
|
147
|
+
children: /* @__PURE__ */ jsx3(PanelLeft, { className: "size-4", "aria-hidden": "true" })
|
|
148
|
+
}
|
|
149
|
+
) : null;
|
|
150
|
+
return /* @__PURE__ */ jsxs2(
|
|
151
|
+
"aside",
|
|
152
|
+
{
|
|
153
|
+
"data-collapsed": collapsed,
|
|
154
|
+
className: cn(
|
|
155
|
+
"flex h-full shrink-0 flex-col overflow-hidden transition-[width] duration-200 ease-in-out",
|
|
156
|
+
collapsed ? "w-[52px]" : "w-[248px]",
|
|
157
|
+
className
|
|
158
|
+
),
|
|
159
|
+
children: [
|
|
160
|
+
/* @__PURE__ */ jsx3("div", { className: cn("flex h-14 items-center gap-2", collapsed ? "justify-center px-1" : "px-3"), children: collapsed ? collapsible ? (
|
|
161
|
+
/* The 52px rail holds one 32px box, and the way back to expanded is what it holds.
|
|
162
|
+
The logo has the expanded band and the top bar; the pin has nowhere else, and a
|
|
163
|
+
pin hidden behind the mark is no pin at all on a device that cannot hover. */
|
|
164
|
+
/* @__PURE__ */ jsx3(
|
|
165
|
+
"button",
|
|
166
|
+
{
|
|
167
|
+
type: "button",
|
|
168
|
+
onClick: toggle,
|
|
169
|
+
"aria-label": "Expand sidebar",
|
|
170
|
+
"aria-expanded": false,
|
|
171
|
+
className: "flex size-8 shrink-0 items-center justify-center rounded-md text-text-secondary transition-colors hover:bg-[var(--hov-bg)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-focus",
|
|
172
|
+
children: /* @__PURE__ */ jsx3(PanelLeft, { className: "size-4", "aria-hidden": "true" })
|
|
173
|
+
}
|
|
174
|
+
)
|
|
175
|
+
) : logoCollapsed ?? logo : /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
176
|
+
header ?? logo,
|
|
177
|
+
pin
|
|
178
|
+
] }) }),
|
|
179
|
+
/* @__PURE__ */ jsx3(Divider, { collapsed, testId: "sidebar-divider-header" }),
|
|
180
|
+
/* @__PURE__ */ jsx3(
|
|
181
|
+
"div",
|
|
182
|
+
{
|
|
183
|
+
"data-testid": "sidebar-scroll",
|
|
184
|
+
className: cn(
|
|
185
|
+
"min-h-0 flex-1 overflow-y-auto overflow-x-hidden pt-3 pb-2",
|
|
186
|
+
collapsed ? "px-1" : "px-3"
|
|
187
|
+
),
|
|
188
|
+
children: /* @__PURE__ */ jsx3(SidebarNav, { items, collapsed, basePath, LinkComponent, isItemActive })
|
|
189
|
+
}
|
|
190
|
+
),
|
|
191
|
+
footer && /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
192
|
+
/* @__PURE__ */ jsx3(Divider, { collapsed, testId: "sidebar-divider-account" }),
|
|
193
|
+
/* @__PURE__ */ jsx3("div", { className: cn("py-2", collapsed ? "px-1" : "px-3"), children: footer })
|
|
194
|
+
] })
|
|
195
|
+
]
|
|
196
|
+
}
|
|
197
|
+
);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// src/components/app-shell.tsx
|
|
201
|
+
import * as React from "react";
|
|
202
|
+
import { Menu } from "lucide-react";
|
|
203
|
+
import { useLocation as useLocation2 } from "react-router";
|
|
204
|
+
import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
205
|
+
function expandedSidebar(sidebar) {
|
|
206
|
+
return React.isValidElement(sidebar) ? React.cloneElement(sidebar, { collapsed: false }) : sidebar;
|
|
207
|
+
}
|
|
208
|
+
function AppShell({ sidebar, topBar, children, className }) {
|
|
209
|
+
const { pathname } = useLocation2();
|
|
210
|
+
const [mobileOpen, setMobileOpen] = React.useState(false);
|
|
211
|
+
React.useEffect(() => {
|
|
212
|
+
setMobileOpen(false);
|
|
213
|
+
}, [pathname]);
|
|
214
|
+
const isMobile = useIsMobile();
|
|
215
|
+
if (isMobile) {
|
|
216
|
+
return /* @__PURE__ */ jsx4(TooltipProvider, { children: /* @__PURE__ */ jsxs3("div", { className: cn("flex min-h-screen flex-col bg-bg-surface", className), children: [
|
|
217
|
+
/* @__PURE__ */ jsxs3(
|
|
218
|
+
"header",
|
|
219
|
+
{
|
|
220
|
+
"data-slot": "app-shell-mobile-header",
|
|
221
|
+
className: "flex shrink-0 items-center justify-between border-b border-border-subtle bg-bg-surface px-4 py-3",
|
|
222
|
+
children: [
|
|
223
|
+
/* @__PURE__ */ jsxs3(Sheet, { open: mobileOpen, onOpenChange: setMobileOpen, children: [
|
|
224
|
+
/* @__PURE__ */ jsx4(SheetTrigger, { asChild: true, children: /* @__PURE__ */ jsx4(Button, { variant: "ghost", size: "icon", className: "size-8 text-text-secondary", "aria-label": "Open navigation", children: /* @__PURE__ */ jsx4(Menu, { className: "size-5" }) }) }),
|
|
225
|
+
/* @__PURE__ */ jsxs3(SheetContent, { side: "left", className: "w-[248px] bg-bg-surface p-0", children: [
|
|
226
|
+
/* @__PURE__ */ jsx4(SheetTitle, { className: "sr-only", children: "Navigation" }),
|
|
227
|
+
/* @__PURE__ */ jsx4(SheetDescription, { className: "sr-only", children: "Application navigation menu" }),
|
|
228
|
+
expandedSidebar(sidebar)
|
|
229
|
+
] })
|
|
230
|
+
] }),
|
|
231
|
+
/* @__PURE__ */ jsx4("div", { className: "flex items-center gap-2", children: topBar })
|
|
232
|
+
]
|
|
233
|
+
}
|
|
234
|
+
),
|
|
235
|
+
/* @__PURE__ */ jsx4("main", { className: "flex-1 overflow-auto px-4", children })
|
|
236
|
+
] }) });
|
|
237
|
+
}
|
|
238
|
+
return /* @__PURE__ */ jsx4(TooltipProvider, { children: /* @__PURE__ */ jsxs3("div", { className: cn("flex min-h-screen gap-3 bg-bg-surface p-4", className), children: [
|
|
239
|
+
/* @__PURE__ */ jsx4("div", { className: "sticky top-4 h-[calc(100vh-32px)] shrink-0", children: sidebar }),
|
|
240
|
+
/* @__PURE__ */ jsxs3("div", { className: "flex min-w-0 flex-1 flex-col overflow-hidden", children: [
|
|
241
|
+
topBar && /* @__PURE__ */ jsx4("div", { "data-slot": "app-shell-topbar", className: "flex h-14 shrink-0 items-center gap-2 px-6", children: topBar }),
|
|
242
|
+
/* @__PURE__ */ jsx4("main", { className: "flex-1 overflow-y-auto px-6", children })
|
|
243
|
+
] })
|
|
244
|
+
] }) });
|
|
245
|
+
}
|
|
246
|
+
var AuthenticatedLayout = AppShell;
|
|
247
|
+
export {
|
|
248
|
+
AppShell,
|
|
249
|
+
AppSidebar,
|
|
250
|
+
AuthenticatedLayout,
|
|
251
|
+
ExtensionLink,
|
|
252
|
+
SidebarNav,
|
|
253
|
+
SidebarNavLink
|
|
254
|
+
};
|
|
@@ -531,6 +531,17 @@
|
|
|
531
531
|
--spacing: 0.25rem;
|
|
532
532
|
}
|
|
533
533
|
:where(:root) {
|
|
534
|
+
/* === Translucent tints the kit paints (#701) === */
|
|
535
|
+
/* A semantic token is a whole colour with no `<alpha-value>` placeholder, so `bg-bg-secondary/50`
|
|
536
|
+
compiles to nothing on Tailwind 3 while Tailwind 4 answers it with color-mix. These are the
|
|
537
|
+
three alphas the kit writes, as variables the preset maps a colour name onto so both majors
|
|
538
|
+
and both consumption paths resolve them. Like --hov-bg below, the inner var() resolves at the
|
|
539
|
+
element that paints, so `.light` needs no override. Delete each the release @lessly/tokens
|
|
540
|
+
publishes its semantic colours with an `<alpha-value>` placeholder. */
|
|
541
|
+
--bg-secondary-a50: color-mix(in oklab, var(--bg-secondary) 50%, transparent);
|
|
542
|
+
--bg-secondary-a80: color-mix(in oklab, var(--bg-secondary) 80%, transparent);
|
|
543
|
+
--bg-danger-a90: color-mix(in oklab, var(--bg-danger) 90%, transparent);
|
|
544
|
+
|
|
534
545
|
/* === Nav / menu surfaces (0.3.0 sidebar) === */
|
|
535
546
|
/* The floating surface sits on the package's overlay pair: --menu-bg on
|
|
536
547
|
--bg-overlay, --menu-shadow on --shadow-overlay. theme.css re-resolves both
|
|
@@ -593,6 +604,15 @@
|
|
|
593
604
|
transition-timing-function: var(--motion-easing-standard);
|
|
594
605
|
}
|
|
595
606
|
|
|
607
|
+
/* === Layout === */
|
|
608
|
+
/* Backs the <PageColumn> primitive: the reading column, capped and centred in the well. A real class
|
|
609
|
+
rather than a Tailwind arbitrary utility, which the content scanner can drop for a newly-used
|
|
610
|
+
class. Horizontal padding is deliberately absent — AppShell owns the inset. */
|
|
611
|
+
.page-column {
|
|
612
|
+
max-width: 780px;
|
|
613
|
+
margin-inline: auto;
|
|
614
|
+
}
|
|
615
|
+
|
|
596
616
|
/* === Animation layer (tw-animate-css, compiled) — see scripts/build-styles.mjs === */
|
|
597
617
|
/*! tailwindcss v4.3.2 | MIT License | https://tailwindcss.com */
|
|
598
618
|
@layer properties;
|
|
@@ -935,3 +955,88 @@
|
|
|
935
955
|
}
|
|
936
956
|
}
|
|
937
957
|
}
|
|
958
|
+
|
|
959
|
+
/* === Tailwind v4 theme bridge — generated by scripts/build-styles.mjs === */
|
|
960
|
+
/* Colour utilities exist in v4 only for names in the `@theme` namespace; the deprecated
|
|
961
|
+
--color-* aliases above are :root properties, which is not the same thing. `inline` so a
|
|
962
|
+
utility substitutes the token at the element it paints rather than freezing it on :root,
|
|
963
|
+
which is what keeps a `.light` scope inside the page working. Permanent, and inert on
|
|
964
|
+
Tailwind 3. */
|
|
965
|
+
@theme inline {
|
|
966
|
+
--color-bg-brand: var(--bg-brand);
|
|
967
|
+
--color-bg-brand-bright: var(--bg-brand-bright);
|
|
968
|
+
--color-bg-brand-bright-hover: var(--bg-brand-bright-hover);
|
|
969
|
+
--color-bg-brand-hover: var(--bg-brand-hover);
|
|
970
|
+
--color-bg-brand-subtle: var(--bg-brand-subtle);
|
|
971
|
+
--color-bg-danger: var(--bg-danger);
|
|
972
|
+
--color-bg-danger-a90: var(--bg-danger-a90);
|
|
973
|
+
--color-bg-danger-subtle: var(--bg-danger-subtle);
|
|
974
|
+
--color-bg-elevated: var(--bg-elevated);
|
|
975
|
+
--color-bg-overlay: var(--bg-overlay);
|
|
976
|
+
--color-bg-primary: var(--bg-primary);
|
|
977
|
+
--color-bg-rose-subtle: var(--bg-rose-subtle);
|
|
978
|
+
--color-bg-secondary: var(--bg-secondary);
|
|
979
|
+
--color-bg-secondary-a50: var(--bg-secondary-a50);
|
|
980
|
+
--color-bg-secondary-a80: var(--bg-secondary-a80);
|
|
981
|
+
--color-bg-selected: var(--bg-selected);
|
|
982
|
+
--color-bg-success: var(--bg-success);
|
|
983
|
+
--color-bg-success-bright: var(--bg-success-bright);
|
|
984
|
+
--color-bg-success-subtle: var(--bg-success-subtle);
|
|
985
|
+
--color-bg-sunken: var(--bg-sunken);
|
|
986
|
+
--color-bg-surface: var(--bg-surface);
|
|
987
|
+
--color-bg-teal-subtle: var(--bg-teal-subtle);
|
|
988
|
+
--color-bg-violet-subtle: var(--bg-violet-subtle);
|
|
989
|
+
--color-bg-warning: var(--bg-warning);
|
|
990
|
+
--color-bg-warning-subtle: var(--bg-warning-subtle);
|
|
991
|
+
--color-border-brand: var(--border-brand);
|
|
992
|
+
--color-border-danger: var(--border-danger);
|
|
993
|
+
--color-border-default: var(--border-default);
|
|
994
|
+
--color-border-focus: var(--border-focus);
|
|
995
|
+
--color-border-selected: var(--border-selected);
|
|
996
|
+
--color-border-strong: var(--border-strong);
|
|
997
|
+
--color-border-subtle: var(--border-subtle);
|
|
998
|
+
--color-border-success: var(--border-success);
|
|
999
|
+
--color-border-warning: var(--border-warning);
|
|
1000
|
+
--color-field-bg: var(--field-bg);
|
|
1001
|
+
--color-field-bg-focus: var(--field-bg-focus);
|
|
1002
|
+
--color-field-bg-hover: var(--field-bg-hover);
|
|
1003
|
+
--color-field-bg-valid: var(--field-bg-valid);
|
|
1004
|
+
--color-field-border: var(--field-border);
|
|
1005
|
+
--color-field-border-error: var(--field-border-error);
|
|
1006
|
+
--color-field-border-filled: var(--field-border-filled);
|
|
1007
|
+
--color-field-border-focus: var(--field-border-focus);
|
|
1008
|
+
--color-field-border-hover: var(--field-border-hover);
|
|
1009
|
+
--color-field-border-success: var(--field-border-success);
|
|
1010
|
+
--color-field-ring-error: var(--field-ring-error);
|
|
1011
|
+
--color-field-ring-focus: var(--field-ring-focus);
|
|
1012
|
+
--color-field-ring-success: var(--field-ring-success);
|
|
1013
|
+
--color-icon-brand: var(--icon-brand);
|
|
1014
|
+
--color-icon-danger: var(--icon-danger);
|
|
1015
|
+
--color-icon-disabled: var(--icon-disabled);
|
|
1016
|
+
--color-icon-primary: var(--icon-primary);
|
|
1017
|
+
--color-icon-secondary: var(--icon-secondary);
|
|
1018
|
+
--color-icon-success: var(--icon-success);
|
|
1019
|
+
--color-icon-warning: var(--icon-warning);
|
|
1020
|
+
--color-overlay-backdrop: var(--overlay-backdrop);
|
|
1021
|
+
--color-overlay-modal-bg: var(--overlay-modal-bg);
|
|
1022
|
+
--color-overlay-scrim: var(--overlay-scrim);
|
|
1023
|
+
--color-text-brand: var(--text-brand);
|
|
1024
|
+
--color-text-danger: var(--text-danger);
|
|
1025
|
+
--color-text-disabled: var(--text-disabled);
|
|
1026
|
+
--color-text-inverse: var(--text-inverse);
|
|
1027
|
+
--color-text-link: var(--text-link);
|
|
1028
|
+
--color-text-link-hover: var(--text-link-hover);
|
|
1029
|
+
--color-text-on-brand: var(--text-on-brand);
|
|
1030
|
+
--color-text-on-danger: var(--text-on-danger);
|
|
1031
|
+
--color-text-on-success: var(--text-on-success);
|
|
1032
|
+
--color-text-on-success-bright: var(--text-on-success-bright);
|
|
1033
|
+
--color-text-on-warning: var(--text-on-warning);
|
|
1034
|
+
--color-text-primary: var(--text-primary);
|
|
1035
|
+
--color-text-rose: var(--text-rose);
|
|
1036
|
+
--color-text-secondary: var(--text-secondary);
|
|
1037
|
+
--color-text-success: var(--text-success);
|
|
1038
|
+
--color-text-teal: var(--text-teal);
|
|
1039
|
+
--color-text-tertiary: var(--text-tertiary);
|
|
1040
|
+
--color-text-violet: var(--text-violet);
|
|
1041
|
+
--color-text-warning: var(--text-warning);
|
|
1042
|
+
}
|
package/dist/styles.css
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/* === @lessly/ui styles — generated by scripts/build-styles.mjs === */
|
|
2
2
|
/* @lessly/tokens theme (composite .text-<style> classes stripped) + deprecated
|
|
3
|
-
--color-* aliases + ui pieces + animation layer */
|
|
3
|
+
--color-* aliases + ui pieces + animation layer + v4 @theme bridge */
|
|
4
4
|
|
|
5
5
|
/*
|
|
6
6
|
* Auto-generated by tokens/build.js — do not edit manually.
|
|
@@ -572,6 +572,17 @@
|
|
|
572
572
|
--spacing: 0.25rem;
|
|
573
573
|
}
|
|
574
574
|
:root {
|
|
575
|
+
/* === Translucent tints the kit paints (#701) === */
|
|
576
|
+
/* A semantic token is a whole colour with no `<alpha-value>` placeholder, so `bg-bg-secondary/50`
|
|
577
|
+
compiles to nothing on Tailwind 3 while Tailwind 4 answers it with color-mix. These are the
|
|
578
|
+
three alphas the kit writes, as variables the preset maps a colour name onto so both majors
|
|
579
|
+
and both consumption paths resolve them. Like --hov-bg below, the inner var() resolves at the
|
|
580
|
+
element that paints, so `.light` needs no override. Delete each the release @lessly/tokens
|
|
581
|
+
publishes its semantic colours with an `<alpha-value>` placeholder. */
|
|
582
|
+
--bg-secondary-a50: color-mix(in oklab, var(--bg-secondary) 50%, transparent);
|
|
583
|
+
--bg-secondary-a80: color-mix(in oklab, var(--bg-secondary) 80%, transparent);
|
|
584
|
+
--bg-danger-a90: color-mix(in oklab, var(--bg-danger) 90%, transparent);
|
|
585
|
+
|
|
575
586
|
/* === Nav / menu surfaces (0.3.0 sidebar) === */
|
|
576
587
|
/* The floating surface sits on the package's overlay pair: --menu-bg on
|
|
577
588
|
--bg-overlay, --menu-shadow on --shadow-overlay. theme.css re-resolves both
|
|
@@ -640,6 +651,15 @@
|
|
|
640
651
|
transition-timing-function: var(--motion-easing-standard);
|
|
641
652
|
}
|
|
642
653
|
|
|
654
|
+
/* === Layout === */
|
|
655
|
+
/* Backs the <PageColumn> primitive: the reading column, capped and centred in the well. A real class
|
|
656
|
+
rather than a Tailwind arbitrary utility, which the content scanner can drop for a newly-used
|
|
657
|
+
class. Horizontal padding is deliberately absent — AppShell owns the inset. */
|
|
658
|
+
.page-column {
|
|
659
|
+
max-width: 780px;
|
|
660
|
+
margin-inline: auto;
|
|
661
|
+
}
|
|
662
|
+
|
|
643
663
|
/* === Animation layer (tw-animate-css, compiled) — see scripts/build-styles.mjs === */
|
|
644
664
|
/*! tailwindcss v4.3.2 | MIT License | https://tailwindcss.com */
|
|
645
665
|
@layer properties;
|
|
@@ -982,3 +1002,88 @@
|
|
|
982
1002
|
}
|
|
983
1003
|
}
|
|
984
1004
|
}
|
|
1005
|
+
|
|
1006
|
+
/* === Tailwind v4 theme bridge — generated by scripts/build-styles.mjs === */
|
|
1007
|
+
/* Colour utilities exist in v4 only for names in the `@theme` namespace; the deprecated
|
|
1008
|
+
--color-* aliases above are :root properties, which is not the same thing. `inline` so a
|
|
1009
|
+
utility substitutes the token at the element it paints rather than freezing it on :root,
|
|
1010
|
+
which is what keeps a `.light` scope inside the page working. Permanent, and inert on
|
|
1011
|
+
Tailwind 3. */
|
|
1012
|
+
@theme inline {
|
|
1013
|
+
--color-bg-brand: var(--bg-brand);
|
|
1014
|
+
--color-bg-brand-bright: var(--bg-brand-bright);
|
|
1015
|
+
--color-bg-brand-bright-hover: var(--bg-brand-bright-hover);
|
|
1016
|
+
--color-bg-brand-hover: var(--bg-brand-hover);
|
|
1017
|
+
--color-bg-brand-subtle: var(--bg-brand-subtle);
|
|
1018
|
+
--color-bg-danger: var(--bg-danger);
|
|
1019
|
+
--color-bg-danger-a90: var(--bg-danger-a90);
|
|
1020
|
+
--color-bg-danger-subtle: var(--bg-danger-subtle);
|
|
1021
|
+
--color-bg-elevated: var(--bg-elevated);
|
|
1022
|
+
--color-bg-overlay: var(--bg-overlay);
|
|
1023
|
+
--color-bg-primary: var(--bg-primary);
|
|
1024
|
+
--color-bg-rose-subtle: var(--bg-rose-subtle);
|
|
1025
|
+
--color-bg-secondary: var(--bg-secondary);
|
|
1026
|
+
--color-bg-secondary-a50: var(--bg-secondary-a50);
|
|
1027
|
+
--color-bg-secondary-a80: var(--bg-secondary-a80);
|
|
1028
|
+
--color-bg-selected: var(--bg-selected);
|
|
1029
|
+
--color-bg-success: var(--bg-success);
|
|
1030
|
+
--color-bg-success-bright: var(--bg-success-bright);
|
|
1031
|
+
--color-bg-success-subtle: var(--bg-success-subtle);
|
|
1032
|
+
--color-bg-sunken: var(--bg-sunken);
|
|
1033
|
+
--color-bg-surface: var(--bg-surface);
|
|
1034
|
+
--color-bg-teal-subtle: var(--bg-teal-subtle);
|
|
1035
|
+
--color-bg-violet-subtle: var(--bg-violet-subtle);
|
|
1036
|
+
--color-bg-warning: var(--bg-warning);
|
|
1037
|
+
--color-bg-warning-subtle: var(--bg-warning-subtle);
|
|
1038
|
+
--color-border-brand: var(--border-brand);
|
|
1039
|
+
--color-border-danger: var(--border-danger);
|
|
1040
|
+
--color-border-default: var(--border-default);
|
|
1041
|
+
--color-border-focus: var(--border-focus);
|
|
1042
|
+
--color-border-selected: var(--border-selected);
|
|
1043
|
+
--color-border-strong: var(--border-strong);
|
|
1044
|
+
--color-border-subtle: var(--border-subtle);
|
|
1045
|
+
--color-border-success: var(--border-success);
|
|
1046
|
+
--color-border-warning: var(--border-warning);
|
|
1047
|
+
--color-field-bg: var(--field-bg);
|
|
1048
|
+
--color-field-bg-focus: var(--field-bg-focus);
|
|
1049
|
+
--color-field-bg-hover: var(--field-bg-hover);
|
|
1050
|
+
--color-field-bg-valid: var(--field-bg-valid);
|
|
1051
|
+
--color-field-border: var(--field-border);
|
|
1052
|
+
--color-field-border-error: var(--field-border-error);
|
|
1053
|
+
--color-field-border-filled: var(--field-border-filled);
|
|
1054
|
+
--color-field-border-focus: var(--field-border-focus);
|
|
1055
|
+
--color-field-border-hover: var(--field-border-hover);
|
|
1056
|
+
--color-field-border-success: var(--field-border-success);
|
|
1057
|
+
--color-field-ring-error: var(--field-ring-error);
|
|
1058
|
+
--color-field-ring-focus: var(--field-ring-focus);
|
|
1059
|
+
--color-field-ring-success: var(--field-ring-success);
|
|
1060
|
+
--color-icon-brand: var(--icon-brand);
|
|
1061
|
+
--color-icon-danger: var(--icon-danger);
|
|
1062
|
+
--color-icon-disabled: var(--icon-disabled);
|
|
1063
|
+
--color-icon-primary: var(--icon-primary);
|
|
1064
|
+
--color-icon-secondary: var(--icon-secondary);
|
|
1065
|
+
--color-icon-success: var(--icon-success);
|
|
1066
|
+
--color-icon-warning: var(--icon-warning);
|
|
1067
|
+
--color-overlay-backdrop: var(--overlay-backdrop);
|
|
1068
|
+
--color-overlay-modal-bg: var(--overlay-modal-bg);
|
|
1069
|
+
--color-overlay-scrim: var(--overlay-scrim);
|
|
1070
|
+
--color-text-brand: var(--text-brand);
|
|
1071
|
+
--color-text-danger: var(--text-danger);
|
|
1072
|
+
--color-text-disabled: var(--text-disabled);
|
|
1073
|
+
--color-text-inverse: var(--text-inverse);
|
|
1074
|
+
--color-text-link: var(--text-link);
|
|
1075
|
+
--color-text-link-hover: var(--text-link-hover);
|
|
1076
|
+
--color-text-on-brand: var(--text-on-brand);
|
|
1077
|
+
--color-text-on-danger: var(--text-on-danger);
|
|
1078
|
+
--color-text-on-success: var(--text-on-success);
|
|
1079
|
+
--color-text-on-success-bright: var(--text-on-success-bright);
|
|
1080
|
+
--color-text-on-warning: var(--text-on-warning);
|
|
1081
|
+
--color-text-primary: var(--text-primary);
|
|
1082
|
+
--color-text-rose: var(--text-rose);
|
|
1083
|
+
--color-text-secondary: var(--text-secondary);
|
|
1084
|
+
--color-text-success: var(--text-success);
|
|
1085
|
+
--color-text-teal: var(--text-teal);
|
|
1086
|
+
--color-text-tertiary: var(--text-tertiary);
|
|
1087
|
+
--color-text-violet: var(--text-violet);
|
|
1088
|
+
--color-text-warning: var(--text-warning);
|
|
1089
|
+
}
|
package/dist/tailwind-preset.js
CHANGED
|
@@ -37,7 +37,29 @@ var lesslyPreset = {
|
|
|
37
37
|
500: "500ms"
|
|
38
38
|
},
|
|
39
39
|
zIndex: { ...upstreamTheme.zIndex, 10: "10", 20: "20", 50: "50" },
|
|
40
|
-
boxShadow: { ...upstreamTheme.boxShadow, none: "none" }
|
|
40
|
+
boxShadow: { ...upstreamTheme.boxShadow, none: "none" },
|
|
41
|
+
extend: {
|
|
42
|
+
...upstreamTheme.extend,
|
|
43
|
+
// Colours *extend* rather than replace, so the missing-step rule above does not reach
|
|
44
|
+
// them — but an opacity modifier does. A semantic colour is `var(--bg-secondary)`, a
|
|
45
|
+
// whole colour with no `<alpha-value>` placeholder for Tailwind to substitute into, so
|
|
46
|
+
// `bg-bg-secondary/50` compiles to nothing at all on Tailwind 3 while Tailwind 4 answers
|
|
47
|
+
// it with `color-mix`. `bg-black/50` is a hex palette colour and survives both, which is
|
|
48
|
+
// why a `/90` never looked dangerous. These three name the alphas the kit writes; `a50`
|
|
49
|
+
// reads as alpha where a bare `50` would read as a lightness step. No solid token can
|
|
50
|
+
// stand in for them: in light `bg-secondary` at 50% over the ground is exactly
|
|
51
|
+
// `--bg-surface`, and in dark it lands below the ground while `--bg-surface` sits above
|
|
52
|
+
// it. Each maps onto a variable rather than carrying the colour itself, because that is
|
|
53
|
+
// the shape the v4 `@theme` bridge carries (scripts/build-styles.mjs) — the values live
|
|
54
|
+
// in src/styles.css. Delete each the day `@lessly/tokens` gives its colours an
|
|
55
|
+
// `<alpha-value>` placeholder.
|
|
56
|
+
colors: {
|
|
57
|
+
...upstreamTheme.extend.colors,
|
|
58
|
+
"bg-secondary-a50": "var(--bg-secondary-a50)",
|
|
59
|
+
"bg-secondary-a80": "var(--bg-secondary-a80)",
|
|
60
|
+
"bg-danger-a90": "var(--bg-danger-a90)"
|
|
61
|
+
}
|
|
62
|
+
}
|
|
41
63
|
},
|
|
42
64
|
darkMode: "class"
|
|
43
65
|
};
|