@m7kni/ui 0.1.1 → 0.2.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/dist/components/blocks/app-shell.d.ts +38 -0
- package/dist/components/blocks/app-shell.js +8 -0
- package/dist/components/blocks/list-page.d.ts +39 -0
- package/dist/components/blocks/list-page.js +33 -0
- package/dist/components/ui/alert.d.ts +10 -0
- package/dist/components/ui/alert.js +29 -0
- package/dist/components/ui/sonner.d.ts +4 -0
- package/dist/components/ui/sonner.js +43 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +7 -3
- package/dist/theme.css +23 -0
- package/package.json +5 -4
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
export interface AppShellNavItem {
|
|
3
|
+
label: string;
|
|
4
|
+
href: string;
|
|
5
|
+
icon?: React.ReactNode;
|
|
6
|
+
count?: number;
|
|
7
|
+
active?: boolean;
|
|
8
|
+
}
|
|
9
|
+
export interface AppShellSavedView {
|
|
10
|
+
label: string;
|
|
11
|
+
href: string;
|
|
12
|
+
}
|
|
13
|
+
export interface AppShellProps extends React.ComponentProps<"div"> {
|
|
14
|
+
/** Product mark, rendered ~20px in the brand row. */
|
|
15
|
+
mark?: React.ReactNode;
|
|
16
|
+
productName: string;
|
|
17
|
+
version?: string;
|
|
18
|
+
nav: AppShellNavItem[];
|
|
19
|
+
savedViews?: AppShellSavedView[];
|
|
20
|
+
/** Pinned to the sidebar's bottom edge — sync/health, mono. */
|
|
21
|
+
syncStatus?: React.ReactNode;
|
|
22
|
+
/** Page title in the top bar. */
|
|
23
|
+
title: string;
|
|
24
|
+
/** Mono breadcrumb/context beside the title. */
|
|
25
|
+
context?: string;
|
|
26
|
+
/** Right side of the top bar: meta + actions. One accent button maximum. */
|
|
27
|
+
actions?: React.ReactNode;
|
|
28
|
+
/** Renders pinned to the bottom edge when rows are selected. */
|
|
29
|
+
bulkBar?: React.ReactNode;
|
|
30
|
+
}
|
|
31
|
+
export declare function AppShell({ mark, productName, version, nav, savedViews, syncStatus, title, context, actions, bulkBar, className, children, ...props }: AppShellProps): React.JSX.Element;
|
|
32
|
+
export interface BulkActionBarProps extends React.ComponentProps<"div"> {
|
|
33
|
+
/** e.g. "3 devices selected" */
|
|
34
|
+
count: string;
|
|
35
|
+
/** Plain-language consequence summary — say what is safe. */
|
|
36
|
+
consequence?: string;
|
|
37
|
+
}
|
|
38
|
+
export declare function BulkActionBar({ count, consequence, className, children, ...props }: BulkActionBarProps): React.JSX.Element;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { cn } from "../../lib/utils.js";
|
|
3
|
+
export function AppShell({ mark, productName, version, nav, savedViews, syncStatus, title, context, actions, bulkBar, className, children, ...props }) {
|
|
4
|
+
return (_jsxs("div", { "data-slot": "app-shell", className: cn("flex h-screen overflow-hidden bg-canvas text-ink", className), ...props, children: [_jsxs("aside", { className: "flex w-[200px] shrink-0 flex-col border-r border-border bg-surface", children: [_jsxs("div", { className: "flex items-center gap-2 px-4 py-3", children: [mark, _jsx("span", { className: "text-md font-semibold", children: productName }), version ? (_jsx("span", { className: "ml-auto font-mono text-2xs text-ink-faint", children: version })) : null] }), _jsxs("nav", { className: "flex-1 overflow-y-auto py-2", children: [_jsx("div", { className: "px-4 pb-1 font-mono text-2xs font-medium tracking-label text-ink-muted uppercase", children: "Views" }), _jsx("ul", { children: nav.map((item) => (_jsx("li", { children: _jsxs("a", { href: item.href, "aria-current": item.active ? "page" : undefined, className: cn("flex items-center gap-2 border-l-2 border-transparent px-4 py-1.5 text-sm text-ink-soft hover:bg-hover", item.active && "border-primary bg-selected text-ink"), children: [item.icon, _jsx("span", { children: item.label }), item.count !== undefined ? (_jsx("span", { className: "ml-auto font-mono text-xs tabular-nums text-ink-muted", children: item.count })) : null] }) }, item.href))) }), savedViews?.length ? (_jsxs(_Fragment, { children: [_jsx("div", { className: "px-4 pt-4 pb-1 font-mono text-2xs font-medium tracking-label text-ink-muted uppercase", children: "Saved views" }), _jsx("ul", { children: savedViews.map((view) => (_jsx("li", { children: _jsx("a", { href: view.href, className: "block border-l-2 border-transparent px-4 py-1.5 text-sm text-ink-soft hover:bg-hover", children: view.label }) }, view.href))) })] })) : null] }), syncStatus ? (_jsx("div", { className: "border-t border-border px-4 py-2 font-mono text-xs text-ink-muted", children: syncStatus })) : null] }), _jsxs("div", { className: "flex min-w-0 flex-1 flex-col", children: [_jsxs("header", { className: "flex items-center gap-3 border-b border-border bg-surface px-6 py-3", children: [_jsx("h1", { className: "text-lg font-semibold", children: title }), context ? (_jsx("span", { className: "font-mono text-xs text-ink-muted", children: context })) : null, _jsx("div", { className: "ml-auto flex items-center gap-3", children: actions })] }), _jsx("main", { className: "min-h-0 flex-1 overflow-y-auto", children: children }), bulkBar] })] }));
|
|
5
|
+
}
|
|
6
|
+
export function BulkActionBar({ count, consequence, className, children, ...props }) {
|
|
7
|
+
return (_jsxs("div", { "data-slot": "bulk-action-bar", className: cn("flex items-center gap-4 bg-inverse px-6 py-2.5 text-sm text-on-inverse", className), ...props, children: [_jsx("span", { className: "font-mono text-xs tabular-nums", children: count }), consequence ? _jsx("span", { className: "text-on-inverse/80", children: consequence }) : null, _jsx("div", { className: "ml-auto flex items-center gap-2", children: children })] }));
|
|
8
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
export interface StatCell {
|
|
3
|
+
label: string;
|
|
4
|
+
value: string;
|
|
5
|
+
note?: string;
|
|
6
|
+
href?: string;
|
|
7
|
+
}
|
|
8
|
+
export declare function StatStrip({ stats, className, ...props }: React.ComponentProps<"div"> & {
|
|
9
|
+
stats: StatCell[];
|
|
10
|
+
}): React.JSX.Element;
|
|
11
|
+
export interface ListRow {
|
|
12
|
+
id: string;
|
|
13
|
+
/** Mono identifier, e.g. a hostname. */
|
|
14
|
+
identifier: string;
|
|
15
|
+
online: boolean;
|
|
16
|
+
/** Human column with inline secondary detail. */
|
|
17
|
+
owner: string;
|
|
18
|
+
ownerDetail?: string;
|
|
19
|
+
/** Magnitude with an inline meter. */
|
|
20
|
+
outdated: number;
|
|
21
|
+
outdatedMax: number;
|
|
22
|
+
/** Relative time, mono. */
|
|
23
|
+
lastSeen: string;
|
|
24
|
+
status: "ok" | "warn" | "fail";
|
|
25
|
+
/** Plain-language note beside a non-OK status ("FileVault off"). */
|
|
26
|
+
statusNote?: string;
|
|
27
|
+
}
|
|
28
|
+
export interface ListPageProps extends React.ComponentProps<"div"> {
|
|
29
|
+
stats: StatCell[];
|
|
30
|
+
rows: ListRow[];
|
|
31
|
+
searchPlaceholder?: string;
|
|
32
|
+
/** Segmented state filter labels, 4–5 maximum, first is "All". */
|
|
33
|
+
segments?: string[];
|
|
34
|
+
/** Mono result count + freshness, e.g. "148 devices · polled 41s ago". */
|
|
35
|
+
resultSummary?: string;
|
|
36
|
+
selected?: Set<string>;
|
|
37
|
+
onSelectedChange?: (selected: Set<string>) => void;
|
|
38
|
+
}
|
|
39
|
+
export declare function ListPage({ stats, rows, searchPlaceholder, segments, resultSummary, selected, onSelectedChange, className, ...props }: ListPageProps): React.JSX.Element;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import { MagnifyingGlassIcon } from "@phosphor-icons/react";
|
|
4
|
+
import { cn } from "../../lib/utils.js";
|
|
5
|
+
import { Checkbox } from "../ui/checkbox.js";
|
|
6
|
+
import { Input } from "../ui/input.js";
|
|
7
|
+
import { Meter } from "../ui/meter.js";
|
|
8
|
+
import { StatusWord } from "../ui/status-word.js";
|
|
9
|
+
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "../ui/table.js";
|
|
10
|
+
import { Tabs, TabsList, TabsTrigger } from "../ui/tabs.js";
|
|
11
|
+
export function StatStrip({ stats, className, ...props }) {
|
|
12
|
+
return (_jsx("div", { "data-slot": "stat-strip", className: cn("flex divide-x divide-border border-b border-border bg-surface", className), ...props, children: stats.map((stat) => (_jsxs("a", { href: stat.href, className: "flex-1 px-6 py-3 hover:bg-hover", children: [_jsx("div", { className: "font-mono text-2xs font-medium tracking-label text-ink-muted uppercase", children: stat.label }), _jsx("div", { className: "text-2xl font-semibold tabular-nums", children: stat.value }), stat.note ? (_jsx("div", { className: "font-mono text-xs text-ink-muted", children: stat.note })) : null] }, stat.label))) }));
|
|
13
|
+
}
|
|
14
|
+
export function ListPage({ stats, rows, searchPlaceholder = "Search hostnames… /", segments = ["All", "Issues"], resultSummary, selected, onSelectedChange, className, ...props }) {
|
|
15
|
+
const [internalSelected, setInternalSelected] = React.useState(new Set());
|
|
16
|
+
const isControlled = selected !== undefined;
|
|
17
|
+
const selection = isControlled ? selected : internalSelected;
|
|
18
|
+
const setSelection = (next) => {
|
|
19
|
+
if (!isControlled)
|
|
20
|
+
setInternalSelected(next);
|
|
21
|
+
onSelectedChange?.(next);
|
|
22
|
+
};
|
|
23
|
+
const toggle = (id, checked) => {
|
|
24
|
+
const next = new Set(selection);
|
|
25
|
+
if (checked)
|
|
26
|
+
next.add(id);
|
|
27
|
+
else
|
|
28
|
+
next.delete(id);
|
|
29
|
+
setSelection(next);
|
|
30
|
+
};
|
|
31
|
+
const allChecked = rows.length > 0 && rows.every((row) => selection.has(row.id));
|
|
32
|
+
return (_jsxs("div", { "data-slot": "list-page", className: cn("flex h-full flex-col", className), ...props, children: [_jsx(StatStrip, { stats: stats }), _jsxs("div", { className: "flex items-center gap-3 border-b border-border bg-surface px-6 py-2", children: [_jsxs("div", { className: "relative w-64", children: [_jsx(MagnifyingGlassIcon, { className: "absolute top-1/2 left-2 size-3.5 -translate-y-1/2 text-ink-faint" }), _jsx(Input, { className: "pl-7 font-mono text-xs", placeholder: searchPlaceholder })] }), _jsx(Tabs, { defaultValue: segments[0], children: _jsx(TabsList, { children: segments.map((segment) => (_jsx(TabsTrigger, { value: segment, children: segment }, segment))) }) }), resultSummary ? (_jsx("span", { className: "ml-auto font-mono text-xs text-ink-muted", children: resultSummary })) : null] }), _jsx("div", { className: "min-h-0 flex-1 overflow-y-auto", children: _jsxs(Table, { children: [_jsx(TableHeader, { className: "sticky top-0 z-10 bg-surface", children: _jsxs(TableRow, { children: [_jsx(TableHead, { className: "w-10", children: _jsx(Checkbox, { "aria-label": "Select all rows", checked: allChecked, onCheckedChange: (checked) => setSelection(checked ? new Set(rows.map((row) => row.id)) : new Set()) }) }), _jsx(TableHead, { children: "Device" }), _jsx(TableHead, { children: "Owner" }), _jsx(TableHead, { className: "text-right", children: "Outdated" }), _jsx(TableHead, { children: "Last seen" }), _jsx(TableHead, { children: "Status" })] }) }), _jsx(TableBody, { children: rows.map((row) => (_jsxs(TableRow, { "data-state": selection.has(row.id) ? "selected" : undefined, className: cn("h-(--row-table)", selection.has(row.id) && "shadow-[inset_2px_0_0_var(--color-bg-accent)]"), children: [_jsx(TableCell, { children: _jsx(Checkbox, { "aria-label": `Select ${row.identifier}`, checked: selection.has(row.id), onCheckedChange: (checked) => toggle(row.id, checked === true) }) }), _jsxs(TableCell, { className: "font-mono text-sm font-medium", children: [_jsx("span", { "aria-hidden": true, className: cn("mr-2 inline-block size-1.5 rounded-full align-middle", row.online ? "bg-ok" : "bg-strong") }), row.identifier] }), _jsxs(TableCell, { children: [row.owner, row.ownerDetail ? (_jsx("span", { className: "ml-1.5 text-ink-faint", children: row.ownerDetail })) : null] }), _jsx(TableCell, { className: "text-right", children: _jsx(Meter, { className: "w-20 align-middle", value: row.outdated, max: row.outdatedMax, failAt: Math.ceil(row.outdatedMax * 0.6) }) }), _jsx(TableCell, { className: "font-mono text-xs text-ink-muted", children: row.lastSeen }), _jsx(TableCell, { children: _jsx(StatusWord, { status: row.status, note: row.statusNote }) })] }, row.id))) })] }) })] }));
|
|
33
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { type VariantProps } from "class-variance-authority";
|
|
3
|
+
declare const alertVariants: (props?: ({
|
|
4
|
+
variant?: "default" | "destructive" | "ok" | "warn" | null | undefined;
|
|
5
|
+
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
6
|
+
declare function Alert({ className, variant, ...props }: React.ComponentProps<"div"> & VariantProps<typeof alertVariants>): React.JSX.Element;
|
|
7
|
+
declare function AlertTitle({ className, ...props }: React.ComponentProps<"div">): React.JSX.Element;
|
|
8
|
+
declare function AlertDescription({ className, ...props }: React.ComponentProps<"div">): React.JSX.Element;
|
|
9
|
+
declare function AlertAction({ className, ...props }: React.ComponentProps<"div">): React.JSX.Element;
|
|
10
|
+
export { Alert, AlertTitle, AlertDescription, AlertAction };
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { cva } from "class-variance-authority";
|
|
3
|
+
import { cn } from "../../lib/utils.js";
|
|
4
|
+
const alertVariants = cva("group/alert relative grid w-full gap-0.5 rounded-sm border px-2.5 py-2 text-left text-sm has-data-[slot=alert-action]:relative has-data-[slot=alert-action]:pr-18 has-[>svg]:grid-cols-[auto_1fr] has-[>svg]:gap-x-2 *:[svg]:row-span-2 *:[svg]:translate-y-0.5 *:[svg]:text-current *:[svg:not([class*='size-'])]:size-4", {
|
|
5
|
+
variants: {
|
|
6
|
+
variant: {
|
|
7
|
+
default: "border-border bg-card text-card-foreground",
|
|
8
|
+
ok: "bg-card text-ok *:data-[slot=alert-description]:text-ok/90 *:[svg]:text-current",
|
|
9
|
+
warn: "bg-card text-warn *:data-[slot=alert-description]:text-warn/90 *:[svg]:text-current",
|
|
10
|
+
destructive: "bg-card text-destructive *:data-[slot=alert-description]:text-destructive/90 *:[svg]:text-current",
|
|
11
|
+
},
|
|
12
|
+
},
|
|
13
|
+
defaultVariants: {
|
|
14
|
+
variant: "default",
|
|
15
|
+
},
|
|
16
|
+
});
|
|
17
|
+
function Alert({ className, variant, ...props }) {
|
|
18
|
+
return (_jsx("div", { "data-slot": "alert", role: "alert", className: cn(alertVariants({ variant }), className), ...props }));
|
|
19
|
+
}
|
|
20
|
+
function AlertTitle({ className, ...props }) {
|
|
21
|
+
return (_jsx("div", { "data-slot": "alert-title", className: cn("font-medium group-has-[>svg]/alert:col-start-2 [&_a]:underline [&_a]:underline-offset-3 [&_a]:hover:text-foreground", className), ...props }));
|
|
22
|
+
}
|
|
23
|
+
function AlertDescription({ className, ...props }) {
|
|
24
|
+
return (_jsx("div", { "data-slot": "alert-description", className: cn("text-sm text-balance text-muted-foreground md:text-pretty [&_a]:underline [&_a]:underline-offset-3 [&_a]:hover:text-foreground [&_p:not(:last-child)]:mb-4", className), ...props }));
|
|
25
|
+
}
|
|
26
|
+
function AlertAction({ className, ...props }) {
|
|
27
|
+
return (_jsx("div", { "data-slot": "alert-action", className: cn("absolute top-2 right-2", className), ...props }));
|
|
28
|
+
}
|
|
29
|
+
export { Alert, AlertTitle, AlertDescription, AlertAction };
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import { Toaster as Sonner } from "sonner";
|
|
4
|
+
import { CheckCircleIcon, InfoIcon, WarningIcon, XCircleIcon, SpinnerIcon, } from "@phosphor-icons/react";
|
|
5
|
+
// Apps set the theme with [data-theme] on <html> (see theme.css). Sonner wants
|
|
6
|
+
// the theme as a prop, so observe the attribute — no next-themes dependency.
|
|
7
|
+
function useDocumentTheme() {
|
|
8
|
+
const [theme, setTheme] = React.useState(() => typeof document !== "undefined" &&
|
|
9
|
+
document.documentElement.dataset.theme === "dark"
|
|
10
|
+
? "dark"
|
|
11
|
+
: "light");
|
|
12
|
+
React.useEffect(() => {
|
|
13
|
+
const root = document.documentElement;
|
|
14
|
+
const update = () => setTheme(root.dataset.theme === "dark" ? "dark" : "light");
|
|
15
|
+
const observer = new MutationObserver(update);
|
|
16
|
+
observer.observe(root, { attributes: true, attributeFilter: ["data-theme"] });
|
|
17
|
+
update();
|
|
18
|
+
return () => observer.disconnect();
|
|
19
|
+
}, []);
|
|
20
|
+
return theme;
|
|
21
|
+
}
|
|
22
|
+
const Toaster = ({ ...props }) => {
|
|
23
|
+
const theme = useDocumentTheme();
|
|
24
|
+
return (_jsx(Sonner, { theme: theme, className: "toaster group", icons: {
|
|
25
|
+
success: _jsx(CheckCircleIcon, { className: "size-4" }),
|
|
26
|
+
info: _jsx(InfoIcon, { className: "size-4" }),
|
|
27
|
+
warning: _jsx(WarningIcon, { className: "size-4" }),
|
|
28
|
+
error: _jsx(XCircleIcon, { className: "size-4" }),
|
|
29
|
+
loading: _jsx(SpinnerIcon, { className: "size-4 animate-spin" }),
|
|
30
|
+
}, style: {
|
|
31
|
+
// theme.css uses @theme inline, so the bridge names never exist as
|
|
32
|
+
// runtime custom properties — reference the tokens directly.
|
|
33
|
+
"--normal-bg": "var(--color-bg-raised)",
|
|
34
|
+
"--normal-text": "var(--color-fg-default)",
|
|
35
|
+
"--normal-border": "var(--color-border-default)",
|
|
36
|
+
"--border-radius": "var(--radius-overlay)",
|
|
37
|
+
}, toastOptions: {
|
|
38
|
+
classNames: {
|
|
39
|
+
toast: "cn-toast",
|
|
40
|
+
},
|
|
41
|
+
}, ...props }));
|
|
42
|
+
};
|
|
43
|
+
export { Toaster };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
export * from "./components/ui/alert.js";
|
|
1
2
|
export * from "./components/ui/badge.js";
|
|
2
3
|
export * from "./components/ui/button.js";
|
|
3
4
|
export * from "./components/ui/checkbox.js";
|
|
@@ -14,10 +15,13 @@ export * from "./components/ui/select.js";
|
|
|
14
15
|
export * from "./components/ui/separator.js";
|
|
15
16
|
export * from "./components/ui/sheet.js";
|
|
16
17
|
export * from "./components/ui/skeleton.js";
|
|
18
|
+
export * from "./components/ui/sonner.js";
|
|
17
19
|
export * from "./components/ui/status-word.js";
|
|
18
20
|
export * from "./components/ui/switch.js";
|
|
19
21
|
export * from "./components/ui/table.js";
|
|
20
22
|
export * from "./components/ui/tabs.js";
|
|
21
23
|
export * from "./components/ui/textarea.js";
|
|
22
24
|
export * from "./components/ui/tooltip.js";
|
|
25
|
+
export * from "./components/blocks/app-shell.js";
|
|
26
|
+
export * from "./components/blocks/list-page.js";
|
|
23
27
|
export { cn } from "./lib/utils.js";
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
// Generated barrel — every component plus the cn helper. Regenerate
|
|
2
|
-
// when adding a component (scripts-build-registry.mjs derives the
|
|
3
|
-
// from the same directory
|
|
1
|
+
// Generated barrel — every component and block plus the cn helper. Regenerate
|
|
2
|
+
// by hand when adding a component (scripts-build-registry.mjs derives the
|
|
3
|
+
// registry from the same directory listings).
|
|
4
|
+
export * from "./components/ui/alert.js";
|
|
4
5
|
export * from "./components/ui/badge.js";
|
|
5
6
|
export * from "./components/ui/button.js";
|
|
6
7
|
export * from "./components/ui/checkbox.js";
|
|
@@ -17,10 +18,13 @@ export * from "./components/ui/select.js";
|
|
|
17
18
|
export * from "./components/ui/separator.js";
|
|
18
19
|
export * from "./components/ui/sheet.js";
|
|
19
20
|
export * from "./components/ui/skeleton.js";
|
|
21
|
+
export * from "./components/ui/sonner.js";
|
|
20
22
|
export * from "./components/ui/status-word.js";
|
|
21
23
|
export * from "./components/ui/switch.js";
|
|
22
24
|
export * from "./components/ui/table.js";
|
|
23
25
|
export * from "./components/ui/tabs.js";
|
|
24
26
|
export * from "./components/ui/textarea.js";
|
|
25
27
|
export * from "./components/ui/tooltip.js";
|
|
28
|
+
export * from "./components/blocks/app-shell.js";
|
|
29
|
+
export * from "./components/blocks/list-page.js";
|
|
26
30
|
export { cn } from "./lib/utils.js";
|
package/dist/theme.css
CHANGED
|
@@ -53,6 +53,29 @@
|
|
|
53
53
|
--color-input: var(--color-border-strong);
|
|
54
54
|
--color-ring: var(--color-bg-accent);
|
|
55
55
|
|
|
56
|
+
/* type scale: Tailwind's stock text-* sizes are re-pointed onto the token
|
|
57
|
+
scale so `text-sm` means the system's 12.5px, not Tailwind's 14px.
|
|
58
|
+
text-md is the 13.5px body size. */
|
|
59
|
+
--text-2xs: var(--font-size-2xs);
|
|
60
|
+
--text-2xs--line-height: 1.4;
|
|
61
|
+
--text-xs: var(--font-size-xs);
|
|
62
|
+
--text-xs--line-height: 1.45;
|
|
63
|
+
--text-sm: var(--font-size-sm);
|
|
64
|
+
--text-sm--line-height: 1.5;
|
|
65
|
+
--text-md: var(--font-size-md);
|
|
66
|
+
--text-md--line-height: 1.5;
|
|
67
|
+
--text-base: var(--font-size-md);
|
|
68
|
+
--text-base--line-height: 1.55;
|
|
69
|
+
--text-lg: var(--font-size-lg);
|
|
70
|
+
--text-lg--line-height: 1.5;
|
|
71
|
+
--text-xl: var(--font-size-xl);
|
|
72
|
+
--text-xl--line-height: 1.4;
|
|
73
|
+
--text-2xl: var(--font-size-2xl);
|
|
74
|
+
--text-2xl--line-height: 1.3;
|
|
75
|
+
|
|
76
|
+
/* micro-label tracking (inline: the utility resolves the token at runtime) */
|
|
77
|
+
--tracking-label: var(--tracking-label);
|
|
78
|
+
|
|
56
79
|
/* radius: precise. Controls 3px, containers square, overlays 6px. */
|
|
57
80
|
--radius-sm: var(--radius-control);
|
|
58
81
|
--radius-md: var(--radius-control);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@m7kni/ui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"typecheck": "tsc --noEmit",
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
"class-variance-authority": "^0.7.1",
|
|
13
13
|
"clsx": "^2.1.1",
|
|
14
14
|
"cmdk": "^1.1.1",
|
|
15
|
+
"sonner": "^2.0.8",
|
|
15
16
|
"tailwind-merge": "^3.6.0"
|
|
16
17
|
},
|
|
17
18
|
"devDependencies": {
|
|
@@ -22,13 +23,13 @@
|
|
|
22
23
|
"@types/react": "^19.2.18",
|
|
23
24
|
"@types/react-dom": "^19.2.5",
|
|
24
25
|
"@vitejs/plugin-react": "^6.1.1",
|
|
26
|
+
"react": "^19.2.8",
|
|
27
|
+
"react-dom": "^19.2.8",
|
|
25
28
|
"shadcn": "^4.19.0",
|
|
26
29
|
"storybook": "^10.5.10",
|
|
27
30
|
"tailwindcss": "^4.3.3",
|
|
28
31
|
"typescript": "^7.0.2",
|
|
29
|
-
"vite": "^8.2.2"
|
|
30
|
-
"react": "^19.2.8",
|
|
31
|
-
"react-dom": "^19.2.8"
|
|
32
|
+
"vite": "^8.2.2"
|
|
32
33
|
},
|
|
33
34
|
"allowScripts": {
|
|
34
35
|
"esbuild@0.28.2": true
|