@arbidocs/blocks 0.5.22 → 0.5.24
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/{WorkspaceTableView-6JVHGDUB.cjs → WorkspaceTableView-GIDGNGBW.cjs} +6 -6
- package/dist/{WorkspaceTableView-6JVHGDUB.cjs.map → WorkspaceTableView-GIDGNGBW.cjs.map} +1 -1
- package/dist/{WorkspaceTableView-ECPHGWHF.js → WorkspaceTableView-S2PTTVHL.js} +4 -4
- package/dist/{WorkspaceTableView-ECPHGWHF.js.map → WorkspaceTableView-S2PTTVHL.js.map} +1 -1
- package/dist/auth/index.cjs +47 -47
- package/dist/auth/index.js +2 -2
- package/dist/{chunk-7DDMF3DZ.cjs → chunk-53T2FY4Z.cjs} +5 -31
- package/dist/chunk-53T2FY4Z.cjs.map +1 -0
- package/dist/chunk-5ZBXFHZW.js +434 -0
- package/dist/chunk-5ZBXFHZW.js.map +1 -0
- package/dist/{chunk-K237IYOD.cjs → chunk-BYJUI4AT.cjs} +54 -2
- package/dist/chunk-BYJUI4AT.cjs.map +1 -0
- package/dist/{chunk-O4EQYPLO.cjs → chunk-C2SZQKX2.cjs} +169 -27
- package/dist/chunk-C2SZQKX2.cjs.map +1 -0
- package/dist/{chunk-MSPNYW6Z.cjs → chunk-DTLVC6MN.cjs} +2 -53
- package/dist/chunk-DTLVC6MN.cjs.map +1 -0
- package/dist/{chunk-RVKVGS72.js → chunk-FDUQQNDT.js} +2 -2
- package/dist/{chunk-RVKVGS72.js.map → chunk-FDUQQNDT.js.map} +1 -1
- package/dist/{chunk-TTJGCJWX.cjs → chunk-H3XAHVDT.cjs} +42 -2
- package/dist/chunk-H3XAHVDT.cjs.map +1 -0
- package/dist/{chunk-XL55UDLO.js → chunk-IJJKUTKM.js} +5 -30
- package/dist/chunk-IJJKUTKM.js.map +1 -0
- package/dist/{chunk-ZX663X3X.cjs → chunk-KNRAKOCO.cjs} +6 -428
- package/dist/chunk-KNRAKOCO.cjs.map +1 -0
- package/dist/chunk-KUQOHPKP.cjs +443 -0
- package/dist/chunk-KUQOHPKP.cjs.map +1 -0
- package/dist/{chunk-F2BYURQZ.cjs → chunk-LYF47OXX.cjs} +5 -5
- package/dist/{chunk-F2BYURQZ.cjs.map → chunk-LYF47OXX.cjs.map} +1 -1
- package/dist/{chunk-PZRTRYPD.js → chunk-MKTEVOC3.js} +44 -5
- package/dist/chunk-MKTEVOC3.js.map +1 -0
- package/dist/{chunk-6XW3CMU4.js → chunk-N3KNAQ55.js} +144 -4
- package/dist/chunk-N3KNAQ55.js.map +1 -0
- package/dist/{chunk-KL6XOSEN.js → chunk-PLAGIVFF.js} +4 -52
- package/dist/chunk-PLAGIVFF.js.map +1 -0
- package/dist/{chunk-FZVAJFRH.cjs → chunk-RHKFCSFC.cjs} +2 -2
- package/dist/{chunk-FZVAJFRH.cjs.map → chunk-RHKFCSFC.cjs.map} +1 -1
- package/dist/{chunk-NVRJ6WTR.js → chunk-RTAYJUQM.js} +3 -3
- package/dist/{chunk-NVRJ6WTR.js.map → chunk-RTAYJUQM.js.map} +1 -1
- package/dist/{chunk-IXBJEQH5.js → chunk-VN4FSGBR.js} +53 -4
- package/dist/chunk-VN4FSGBR.js.map +1 -0
- package/dist/{chunk-SLRVI2YU.js → chunk-X6U6L6BG.js} +29 -4
- package/dist/chunk-X6U6L6BG.js.map +1 -0
- package/dist/{chunk-SQ5F5BFW.cjs → chunk-XDU3HHUU.cjs} +32 -6
- package/dist/chunk-XDU3HHUU.cjs.map +1 -0
- package/dist/{chunk-SKVVOEMX.js → chunk-XXUPUXBF.js} +8 -423
- package/dist/chunk-XXUPUXBF.js.map +1 -0
- package/dist/connect/index.cjs +1203 -624
- package/dist/connect/index.cjs.map +1 -1
- package/dist/connect/index.js +770 -197
- package/dist/connect/index.js.map +1 -1
- package/dist/connection/auth/CompactLogin.d.ts +26 -0
- package/dist/connection/auth/ConnectedLoginPage.d.ts +9 -1
- package/dist/connection/auth/index.d.ts +3 -1
- package/dist/connection/auth/sso-popup.d.ts +13 -0
- package/dist/connection/auth/sso-sign-in.d.ts +38 -0
- package/dist/connection/auth/support.d.ts +17 -0
- package/dist/connection/auth/useLoginActions.d.ts +9 -2
- package/dist/connection/billing/ConnectedQuotaDialog.d.ts +5 -13
- package/dist/connection/billing/index.d.ts +1 -1
- package/dist/connection/connectors/ConnectedSharePointAdminConsentPage.d.ts +26 -0
- package/dist/connection/connectors/index.d.ts +1 -0
- package/dist/connection/projects/ConnectedProjectsPanel.d.ts +9 -1
- package/dist/connection/projects/ProjectsListPage.d.ts +40 -0
- package/dist/connection/projects/index.d.ts +1 -0
- package/dist/connection/settings-page/ConnectedAccountSettings.d.ts +2 -1
- package/dist/connection/settings-page/ConnectedBoxPortalSection.d.ts +6 -0
- package/dist/connection/settings-page/appearanceSection.d.ts +30 -0
- package/dist/connection/settings-page/index.d.ts +1 -0
- package/dist/index.cjs +209 -237
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +11 -50
- package/dist/index.js.map +1 -1
- package/dist/settings/AppearanceSettings.d.ts +1 -2
- package/dist/settings/index.cjs +153 -153
- package/dist/settings/index.d.ts +2 -1
- package/dist/settings/index.js +1 -1
- package/dist/site/index.cjs +82 -74
- package/dist/site/index.d.ts +2 -0
- package/dist/site/index.js +3 -3
- package/dist/studio/index.cjs +73 -73
- package/dist/studio/index.js +5 -5
- package/dist/theme/appearance.d.ts +47 -0
- package/dist/theme/fromCss.d.ts +33 -0
- package/node_modules/@arbidocs/coedit/package.json +1 -1
- package/package.json +5 -5
- package/dist/chunk-6XW3CMU4.js.map +0 -1
- package/dist/chunk-7DDMF3DZ.cjs.map +0 -1
- package/dist/chunk-AMTWY22T.js +0 -11
- package/dist/chunk-AMTWY22T.js.map +0 -1
- package/dist/chunk-IXBJEQH5.js.map +0 -1
- package/dist/chunk-K237IYOD.cjs.map +0 -1
- package/dist/chunk-KL6XOSEN.js.map +0 -1
- package/dist/chunk-MSPNYW6Z.cjs.map +0 -1
- package/dist/chunk-O4EQYPLO.cjs.map +0 -1
- package/dist/chunk-PZRTRYPD.js.map +0 -1
- package/dist/chunk-SKVVOEMX.js.map +0 -1
- package/dist/chunk-SLRVI2YU.js.map +0 -1
- package/dist/chunk-SQ5F5BFW.cjs.map +0 -1
- package/dist/chunk-TTJGCJWX.cjs.map +0 -1
- package/dist/chunk-XL55UDLO.js.map +0 -1
- package/dist/chunk-ZU2B2RZK.cjs +0 -13
- package/dist/chunk-ZU2B2RZK.cjs.map +0 -1
- package/dist/chunk-ZX663X3X.cjs.map +0 -1
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
|
-
var
|
|
4
|
+
var chunkXDU3HHUU_cjs = require('./chunk-XDU3HHUU.cjs');
|
|
5
5
|
var chunkQW3SVHGM_cjs = require('./chunk-QW3SVHGM.cjs');
|
|
6
6
|
var jsxRuntime = require('react/jsx-runtime');
|
|
7
|
-
var ui = require('@arbidocs/react/ui');
|
|
8
7
|
var lucideReact = require('lucide-react');
|
|
8
|
+
var ui = require('@arbidocs/react/ui');
|
|
9
9
|
|
|
10
10
|
function DataTableBlock({ columns, rows, caption, emptyText, testId }) {
|
|
11
11
|
const area = testId ?? "data-table-block";
|
|
@@ -26,7 +26,7 @@ function DataTableBlock({ columns, rows, caption, emptyText, testId }) {
|
|
|
26
26
|
}
|
|
27
27
|
) : null,
|
|
28
28
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
29
|
-
|
|
29
|
+
chunkXDU3HHUU_cjs.DataTable,
|
|
30
30
|
{
|
|
31
31
|
columns: tableColumns,
|
|
32
32
|
rows: tableRows,
|
|
@@ -37,31 +37,6 @@ function DataTableBlock({ columns, rows, caption, emptyText, testId }) {
|
|
|
37
37
|
)
|
|
38
38
|
] });
|
|
39
39
|
}
|
|
40
|
-
function PageHeader({
|
|
41
|
-
title,
|
|
42
|
-
eyebrow,
|
|
43
|
-
description,
|
|
44
|
-
leading,
|
|
45
|
-
actions,
|
|
46
|
-
tabs,
|
|
47
|
-
className,
|
|
48
|
-
testId
|
|
49
|
-
}) {
|
|
50
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ui.cn("flex flex-col gap-3", className), "data-testid": testId, children: [
|
|
51
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-3 sm:flex-row sm:items-end sm:justify-between", children: [
|
|
52
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-w-0 items-center gap-3", children: [
|
|
53
|
-
leading && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "shrink-0", "data-slot": "page-header-leading", children: leading }),
|
|
54
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0", children: [
|
|
55
|
-
eyebrow && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mb-1 text-xs font-semibold uppercase tracking-wider text-muted-foreground", children: eyebrow }),
|
|
56
|
-
/* @__PURE__ */ jsxRuntime.jsx("h1", { className: "font-display text-2xl font-semibold tracking-tight text-foreground", children: title }),
|
|
57
|
-
description && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1 max-w-2xl text-sm text-muted-foreground", children: description })
|
|
58
|
-
] })
|
|
59
|
-
] }),
|
|
60
|
-
actions && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex shrink-0 items-center gap-2", children: actions })
|
|
61
|
-
] }),
|
|
62
|
-
tabs && /* @__PURE__ */ jsxRuntime.jsx("div", { "data-slot": "page-header-tabs", children: tabs })
|
|
63
|
-
] });
|
|
64
|
-
}
|
|
65
40
|
function MetricCard({
|
|
66
41
|
label,
|
|
67
42
|
value,
|
|
@@ -154,7 +129,6 @@ function StatGroup({ items, testId }) {
|
|
|
154
129
|
|
|
155
130
|
exports.DataTableBlock = DataTableBlock;
|
|
156
131
|
exports.MetricCard = MetricCard;
|
|
157
|
-
exports.PageHeader = PageHeader;
|
|
158
132
|
exports.StatGroup = StatGroup;
|
|
159
|
-
//# sourceMappingURL=chunk-
|
|
160
|
-
//# sourceMappingURL=chunk-
|
|
133
|
+
//# sourceMappingURL=chunk-53T2FY4Z.cjs.map
|
|
134
|
+
//# sourceMappingURL=chunk-53T2FY4Z.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/DataTableBlock.tsx","../src/components/MetricCard.tsx","../src/components/StatGroup.tsx"],"names":["jsxs","jsx","DataTable","Card","cn","ArrowUpRight","ArrowDownRight","ActionLink"],"mappings":"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","file":"chunk-53T2FY4Z.cjs","sourcesContent":["/**\n * A **serializable** data table for the Puck builder.\n *\n * The library's developer-facing {@link DataTable} is driven by `Column<T>` whose\n * `header`/`render` are React nodes and functions — powerful, but non-serializable,\n * so it can never be a Puck block. `DataTableBlock` closes that gap with a flat,\n * JSON-safe schema (string headers, string field keys, string cells) and rebuilds\n * the non-serializable `Column<Row>[]` internally, rendering through the very same\n * {@link DataTable} so it inherits the library's markup and tokens verbatim.\n */\nimport { DataTable, type Column } from './DataTable'\n\nexport interface DataTableBlockColumn {\n /** Column heading text. */\n header: string\n /** Key used to look a cell up in each row record. */\n field: string\n /** Cell/heading alignment. */\n align?: 'left' | 'right' | 'center'\n}\n\nexport interface DataTableBlockProps {\n /** Serializable column schema. */\n columns: DataTableBlockColumn[]\n /** One record per row; cells are looked up by each column's `field`. */\n rows: Array<Record<string, string>>\n /** Optional caption rendered above the table. */\n caption?: string\n /** Empty-state title shown when there are no rows. */\n emptyText?: string\n /** testid area prefix; also set on the wrapper element. */\n testId?: string\n}\n\n/** A row wrapper so {@link DataTable} gets a stable id without polluting the record. */\ninterface TableRowData {\n __id: string\n cells: Record<string, string>\n}\n\n/**\n * Renders a {@link DataTable} from a flat, serializable schema. Columns are mapped\n * to `Column<TableRowData>[]` (header string, positional-stable key, alignment) and\n * each cell is resolved by `field`; rows carry a synthetic id for React keys/testids.\n */\nexport function DataTableBlock({ columns, rows, caption, emptyText, testId }: DataTableBlockProps) {\n const area = testId ?? 'data-table-block'\n\n const tableColumns: Column<TableRowData>[] = columns.map((col, index) => ({\n key: col.field || `col-${index}`,\n header: col.header,\n align: col.align,\n render: (row) => row.cells[col.field] ?? '',\n }))\n\n const tableRows: TableRowData[] = rows.map((cells, index) => ({ __id: String(index), cells }))\n\n return (\n <div data-testid={testId}>\n {caption ? (\n <p\n className=\"mb-2 text-sm text-muted-foreground\"\n data-testid={testId ? `${testId}-caption` : undefined}\n >\n {caption}\n </p>\n ) : null}\n <DataTable\n columns={tableColumns}\n rows={tableRows}\n getRowId={(row) => row.__id}\n area={area}\n emptyTitle={emptyText}\n />\n </div>\n )\n}\n","import type { ReactNode } from 'react'\nimport type { LucideIcon } from 'lucide-react'\nimport { ArrowDownRight, ArrowUpRight } from 'lucide-react'\nimport { Card, cn } from '@arbidocs/react/ui'\nimport { ActionLink } from './ActionLink'\n\nexport interface MetricCardProps {\n label: ReactNode\n value: ReactNode\n icon?: LucideIcon\n hint?: ReactNode\n delta?: { value: string; direction: 'up' | 'down'; good?: boolean }\n /**\n * Icon accent as a theme colour-token key (e.g. `primary`, `success`, or the host's own brand\n * token). Resolved to `var(--color-<accent>)` at render. `'default'` inherits `foreground`.\n */\n accent?: string\n /** Show a placeholder instead of the value (the figure is still being fetched). */\n isLoading?: boolean\n /** Makes the tile a real link (ctrl/cmd-click works). */\n href?: string\n /** Click handler; with `href`, a plain click calls it instead of navigating. */\n onSelect?: () => void\n className?: string\n testId?: string\n}\n\n/** The one true KPI tile. Used across every dashboard and module header. */\nexport function MetricCard({\n label,\n value,\n icon: Icon,\n hint,\n delta,\n accent = 'default',\n isLoading = false,\n href,\n onSelect,\n className,\n testId,\n}: MetricCardProps) {\n const accentStyle =\n accent && accent !== 'default' ? { color: `var(--color-${accent})` } : undefined\n const deltaGood = delta?.good ?? delta?.direction === 'up'\n const isInteractive = Boolean(href || onSelect)\n const card = (\n <Card\n variant=\"elevated\"\n className={cn('card-hover min-w-0 rounded-xl p-5', className)}\n data-testid={isInteractive ? undefined : testId}\n aria-busy={isLoading || undefined}\n >\n <div className=\"flex items-start justify-between gap-3\">\n <p className=\"min-w-0 text-xs font-medium uppercase tracking-wide text-muted-foreground\">\n {label}\n </p>\n {Icon && <Icon className=\"size-4 shrink-0\" style={accentStyle} />}\n </div>\n {isLoading ? (\n <div\n className=\"mt-2 h-8 w-20 animate-pulse rounded bg-muted\"\n data-slot=\"metric-card-skeleton\"\n />\n ) : (\n <p\n className=\"mt-2 font-display text-2xl font-semibold tracking-tight [overflow-wrap:anywhere]\"\n data-testid={testId && `${testId}-value`}\n >\n {value}\n </p>\n )}\n <div className=\"mt-1 flex items-center gap-2\">\n {delta && !isLoading && (\n <span\n className={cn(\n 'inline-flex items-center gap-0.5 text-xs font-medium',\n deltaGood ? 'text-success' : 'text-destructive'\n )}\n >\n {delta.direction === 'up' ? (\n <ArrowUpRight className=\"size-3\" />\n ) : (\n <ArrowDownRight className=\"size-3\" />\n )}\n {delta.value}\n </span>\n )}\n {hint && <span className=\"text-xs text-muted-foreground\">{hint}</span>}\n </div>\n </Card>\n )\n if (!isInteractive) return card\n return (\n <ActionLink\n href={href}\n onSelect={onSelect}\n className=\"block rounded-xl text-left focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n data-testid={testId}\n >\n {card}\n </ActionLink>\n )\n}\n","import { cn } from '@arbidocs/react/ui'\n\nexport interface StatItem {\n value: string\n label: string\n /** Optional caption under the label (e.g. a qualifier or unit). */\n sub?: string\n}\n\nexport interface StatGroupProps {\n items: StatItem[]\n testId?: string\n}\n\nconst GRID: Record<number, string> = {\n 1: 'grid-cols-1',\n 2: 'grid-cols-2',\n 3: 'grid-cols-2 sm:grid-cols-3',\n 4: 'grid-cols-2 lg:grid-cols-4',\n}\n\n/** Big-number stat group — headline metrics with captions. */\nexport function StatGroup({ items, testId }: StatGroupProps) {\n const list = items ?? []\n const cols = GRID[Math.min(list.length, 4)] ?? GRID[4]\n return (\n <dl className={cn('grid gap-8', cols)} data-testid={testId}>\n {list.map((item, i) => (\n <div key={i} className=\"min-w-0 text-center\" data-testid={testId && `${testId}-item-${i}`}>\n <dt className=\"sr-only\">{item.label}</dt>\n <dd className=\"text-4xl font-semibold tracking-tight [overflow-wrap:anywhere] sm:text-5xl\">\n {item.value}\n </dd>\n <p className=\"mt-2 text-sm text-muted-foreground\">{item.label}</p>\n {item.sub && <p className=\"mt-1 text-xs text-muted-foreground/80\">{item.sub}</p>}\n </div>\n ))}\n </dl>\n )\n}\n"]}
|
|
@@ -0,0 +1,434 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { matchFontPairing, FONT_PAIRINGS } from './chunk-NHZK64TQ.js';
|
|
3
|
+
import { useState, useEffect } from 'react';
|
|
4
|
+
import { RotateCcw, ChevronDown, Palette, Check, Save } from 'lucide-react';
|
|
5
|
+
import { Input, Card, CardHeader, CardTitle, CardContent } from '@arbidocs/react/ui';
|
|
6
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
7
|
+
|
|
8
|
+
// src/theme/tokens.ts
|
|
9
|
+
var THEME_STYLE_ID = "arbi-theme-vars";
|
|
10
|
+
var TRIPLET_RE = /^-?\d+(?:\.\d+)?\s+-?\d+(?:\.\d+)?%\s+-?\d+(?:\.\d+)?%$/;
|
|
11
|
+
function parseRgb(color) {
|
|
12
|
+
if (color.startsWith("#")) {
|
|
13
|
+
let hex = color.slice(1);
|
|
14
|
+
if (hex.length === 3) {
|
|
15
|
+
hex = hex.split("").map((ch) => ch + ch).join("");
|
|
16
|
+
}
|
|
17
|
+
if (hex.length === 6 && /^[0-9a-fA-F]{6}$/.test(hex)) {
|
|
18
|
+
return {
|
|
19
|
+
r: parseInt(hex.slice(0, 2), 16),
|
|
20
|
+
g: parseInt(hex.slice(2, 4), 16),
|
|
21
|
+
b: parseInt(hex.slice(4, 6), 16)
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
const m = color.match(/^rgba?\(\s*([\d.]+)[\s,]+([\d.]+)[\s,]+([\d.]+)/i);
|
|
27
|
+
if (m) return { r: Number(m[1]), g: Number(m[2]), b: Number(m[3]) };
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
function rgbToHslTriplet(r, g, b) {
|
|
31
|
+
const rn = r / 255;
|
|
32
|
+
const gn = g / 255;
|
|
33
|
+
const bn = b / 255;
|
|
34
|
+
const max = Math.max(rn, gn, bn);
|
|
35
|
+
const min = Math.min(rn, gn, bn);
|
|
36
|
+
const l = (max + min) / 2;
|
|
37
|
+
const d = max - min;
|
|
38
|
+
let h = 0;
|
|
39
|
+
let s = 0;
|
|
40
|
+
if (d !== 0) {
|
|
41
|
+
s = d / (1 - Math.abs(2 * l - 1));
|
|
42
|
+
switch (max) {
|
|
43
|
+
case rn:
|
|
44
|
+
h = 60 * ((gn - bn) / d % 6);
|
|
45
|
+
break;
|
|
46
|
+
case gn:
|
|
47
|
+
h = 60 * ((bn - rn) / d + 2);
|
|
48
|
+
break;
|
|
49
|
+
default:
|
|
50
|
+
h = 60 * ((rn - gn) / d + 4);
|
|
51
|
+
break;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
if (h < 0) h += 360;
|
|
55
|
+
return `${Math.round(h)} ${Math.round(s * 100)}% ${Math.round(l * 100)}%`;
|
|
56
|
+
}
|
|
57
|
+
function toHslTriplet(color) {
|
|
58
|
+
const c = color.trim();
|
|
59
|
+
if (TRIPLET_RE.test(c)) return c;
|
|
60
|
+
const rgb = parseRgb(c);
|
|
61
|
+
if (!rgb) return c;
|
|
62
|
+
return rgbToHslTriplet(rgb.r, rgb.g, rgb.b);
|
|
63
|
+
}
|
|
64
|
+
function renderTripletBlock(colors) {
|
|
65
|
+
return Object.entries(colors).map(([key, value]) => ` --${key}: ${toHslTriplet(value)};`).join("\n");
|
|
66
|
+
}
|
|
67
|
+
function emitCssVars(theme, dark) {
|
|
68
|
+
if (typeof document === "undefined") return;
|
|
69
|
+
const meta = [
|
|
70
|
+
` --font-display: ${theme.fonts.display};`,
|
|
71
|
+
` --font-sans: ${theme.fonts.sans};`,
|
|
72
|
+
` --radius: ${theme.radius}rem;`
|
|
73
|
+
].join("\n");
|
|
74
|
+
let css = `:root {
|
|
75
|
+
${renderTripletBlock(theme.colors)}
|
|
76
|
+
${meta}
|
|
77
|
+
}`;
|
|
78
|
+
if (dark) {
|
|
79
|
+
css += `
|
|
80
|
+
:root.dark {
|
|
81
|
+
${renderTripletBlock(dark)}
|
|
82
|
+
}`;
|
|
83
|
+
}
|
|
84
|
+
let style = document.getElementById(THEME_STYLE_ID);
|
|
85
|
+
if (!style) {
|
|
86
|
+
style = document.createElement("style");
|
|
87
|
+
style.id = THEME_STYLE_ID;
|
|
88
|
+
document.head.appendChild(style);
|
|
89
|
+
}
|
|
90
|
+
style.textContent = css;
|
|
91
|
+
}
|
|
92
|
+
function removeCssVars() {
|
|
93
|
+
if (typeof document === "undefined") return;
|
|
94
|
+
document.getElementById(THEME_STYLE_ID)?.remove();
|
|
95
|
+
}
|
|
96
|
+
function normalizeOptions(optionsOrRoot) {
|
|
97
|
+
if (typeof HTMLElement !== "undefined" && optionsOrRoot instanceof HTMLElement) {
|
|
98
|
+
return { root: optionsOrRoot };
|
|
99
|
+
}
|
|
100
|
+
return optionsOrRoot;
|
|
101
|
+
}
|
|
102
|
+
function applyThemeVars(theme, optionsOrRoot = {}) {
|
|
103
|
+
const { mode = "flat", dark, root = document.documentElement } = normalizeOptions(optionsOrRoot);
|
|
104
|
+
if (mode === "cssVars") {
|
|
105
|
+
emitCssVars(theme, dark);
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
for (const [key, value] of Object.entries(theme.colors)) {
|
|
109
|
+
root.style.setProperty(`--color-${key}`, value);
|
|
110
|
+
}
|
|
111
|
+
root.style.setProperty("--font-display", theme.fonts.display);
|
|
112
|
+
root.style.setProperty("--font-sans", theme.fonts.sans);
|
|
113
|
+
root.style.setProperty("--radius", `${theme.radius}rem`);
|
|
114
|
+
}
|
|
115
|
+
function applyFontVars(fonts, root = document.documentElement) {
|
|
116
|
+
root.style.setProperty("--font-display", fonts.display);
|
|
117
|
+
root.style.setProperty("--font-sans", fonts.sans);
|
|
118
|
+
}
|
|
119
|
+
function clearFontVars(root = document.documentElement) {
|
|
120
|
+
root.style.removeProperty("--font-display");
|
|
121
|
+
root.style.removeProperty("--font-sans");
|
|
122
|
+
}
|
|
123
|
+
function clearThemeVars(theme, optionsOrRoot = {}) {
|
|
124
|
+
const { mode = "flat", root = document.documentElement } = normalizeOptions(optionsOrRoot);
|
|
125
|
+
if (mode === "cssVars") {
|
|
126
|
+
removeCssVars();
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
for (const key of Object.keys(theme.colors)) {
|
|
130
|
+
root.style.removeProperty(`--color-${key}`);
|
|
131
|
+
}
|
|
132
|
+
root.style.removeProperty("--font-display");
|
|
133
|
+
root.style.removeProperty("--font-sans");
|
|
134
|
+
root.style.removeProperty("--radius");
|
|
135
|
+
}
|
|
136
|
+
function ThemeEditor({
|
|
137
|
+
bundle,
|
|
138
|
+
variant = "panel",
|
|
139
|
+
preview,
|
|
140
|
+
onSave,
|
|
141
|
+
testIdPrefix = "theme",
|
|
142
|
+
defaultOpen = false
|
|
143
|
+
}) {
|
|
144
|
+
const { useStore, tokens, presets, groupLabels, mode, darkColors } = bundle;
|
|
145
|
+
const colors = useStore((s) => s.colors);
|
|
146
|
+
const fonts = useStore((s) => s.fonts);
|
|
147
|
+
const radius = useStore((s) => s.radius);
|
|
148
|
+
const activePresetId = useStore((s) => s.activePresetId);
|
|
149
|
+
const setColor = useStore((s) => s.setColor);
|
|
150
|
+
const setFont = useStore((s) => s.setFont);
|
|
151
|
+
const setFontPairing = useStore((s) => s.setFontPairing);
|
|
152
|
+
const setRadius = useStore((s) => s.setRadius);
|
|
153
|
+
const applyPreset = useStore((s) => s.applyPreset);
|
|
154
|
+
const reset = useStore((s) => s.reset);
|
|
155
|
+
const [open, setOpen] = useState(defaultOpen);
|
|
156
|
+
const [saving, setSaving] = useState(false);
|
|
157
|
+
const [savedVia, setSavedVia] = useState(null);
|
|
158
|
+
useEffect(() => {
|
|
159
|
+
applyThemeVars({ colors, fonts, radius }, { mode, dark: darkColors });
|
|
160
|
+
}, [colors, fonts, radius, mode, darkColors]);
|
|
161
|
+
const tid2 = (suffix) => `${testIdPrefix}-${suffix}`;
|
|
162
|
+
const groups = [...new Set(tokens.map((t) => t.group))];
|
|
163
|
+
const save = async () => {
|
|
164
|
+
if (!onSave) return;
|
|
165
|
+
setSaving(true);
|
|
166
|
+
try {
|
|
167
|
+
const via = await onSave();
|
|
168
|
+
setSavedVia(typeof via === "string" ? via : "saved");
|
|
169
|
+
} catch {
|
|
170
|
+
setSavedVia(null);
|
|
171
|
+
} finally {
|
|
172
|
+
setSaving(false);
|
|
173
|
+
}
|
|
174
|
+
};
|
|
175
|
+
const Presets = /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [
|
|
176
|
+
presets.map((p) => /* @__PURE__ */ jsx(
|
|
177
|
+
"button",
|
|
178
|
+
{
|
|
179
|
+
type: "button",
|
|
180
|
+
onClick: () => applyPreset(p.id),
|
|
181
|
+
className: `rounded-full border px-3 py-1 text-xs font-medium transition-colors ${activePresetId === p.id ? "border-primary bg-primary text-primary-foreground" : "border-border text-foreground hover:border-primary"}`,
|
|
182
|
+
"data-testid": tid2(`preset-${p.id}`),
|
|
183
|
+
children: p.label
|
|
184
|
+
},
|
|
185
|
+
p.id
|
|
186
|
+
)),
|
|
187
|
+
/* @__PURE__ */ jsxs(
|
|
188
|
+
"button",
|
|
189
|
+
{
|
|
190
|
+
type: "button",
|
|
191
|
+
onClick: reset,
|
|
192
|
+
className: "ml-auto inline-flex items-center gap-1.5 text-xs font-medium text-muted-foreground hover:text-foreground",
|
|
193
|
+
"data-testid": tid2("reset"),
|
|
194
|
+
children: [
|
|
195
|
+
/* @__PURE__ */ jsx(RotateCcw, { className: "size-3" }),
|
|
196
|
+
" Reset"
|
|
197
|
+
]
|
|
198
|
+
}
|
|
199
|
+
)
|
|
200
|
+
] });
|
|
201
|
+
const colorRow = (k, label) => /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
|
|
202
|
+
/* @__PURE__ */ jsx(
|
|
203
|
+
"input",
|
|
204
|
+
{
|
|
205
|
+
type: "color",
|
|
206
|
+
value: colors[k] ?? "#000000",
|
|
207
|
+
onChange: (e) => setColor(k, e.target.value),
|
|
208
|
+
className: "size-9 shrink-0 cursor-pointer rounded-md border border-border bg-transparent",
|
|
209
|
+
"aria-label": label,
|
|
210
|
+
"data-testid": tid2(`color-${k}`)
|
|
211
|
+
}
|
|
212
|
+
),
|
|
213
|
+
/* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
|
|
214
|
+
/* @__PURE__ */ jsx("span", { className: "block text-xs text-muted-foreground", children: label }),
|
|
215
|
+
/* @__PURE__ */ jsx(
|
|
216
|
+
Input,
|
|
217
|
+
{
|
|
218
|
+
value: colors[k] ?? "",
|
|
219
|
+
onChange: (e) => setColor(k, e.target.value),
|
|
220
|
+
"aria-label": `${label} hex value`,
|
|
221
|
+
className: "bg-card placeholder:text-muted-foreground focus-visible:border-ring/60 focus-visible:ring-2 focus-visible:ring-ring h-7 font-mono text-xs",
|
|
222
|
+
"data-testid": tid2(`hex-${k}`)
|
|
223
|
+
}
|
|
224
|
+
)
|
|
225
|
+
] })
|
|
226
|
+
] }, k);
|
|
227
|
+
const activePairing = matchFontPairing(fonts);
|
|
228
|
+
const Typography = /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
|
|
229
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
230
|
+
/* @__PURE__ */ jsx("span", { className: "block text-xs text-muted-foreground", children: "Typeface" }),
|
|
231
|
+
/* @__PURE__ */ jsxs(
|
|
232
|
+
"select",
|
|
233
|
+
{
|
|
234
|
+
value: activePairing?.id ?? "",
|
|
235
|
+
onChange: (e) => setFontPairing(e.target.value),
|
|
236
|
+
"aria-label": "Typeface",
|
|
237
|
+
className: "mt-1 h-8 w-full rounded-md border border-border bg-card px-2 text-xs text-foreground focus-visible:border-ring/60 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
|
238
|
+
"data-testid": tid2("font-pairing"),
|
|
239
|
+
children: [
|
|
240
|
+
!activePairing && /* @__PURE__ */ jsx("option", { value: "", children: "Custom" }),
|
|
241
|
+
FONT_PAIRINGS.map((pairing) => /* @__PURE__ */ jsx("option", { value: pairing.id, children: pairing.label }, pairing.id))
|
|
242
|
+
]
|
|
243
|
+
}
|
|
244
|
+
),
|
|
245
|
+
/* @__PURE__ */ jsx("p", { className: "mt-1 text-xs text-muted-foreground", children: activePairing?.description ?? "Hand-edited font stacks." })
|
|
246
|
+
] }),
|
|
247
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
248
|
+
/* @__PURE__ */ jsx("span", { className: "block text-xs text-muted-foreground", children: "Display font stack" }),
|
|
249
|
+
/* @__PURE__ */ jsx(
|
|
250
|
+
Input,
|
|
251
|
+
{
|
|
252
|
+
value: fonts.display,
|
|
253
|
+
onChange: (e) => setFont("display", e.target.value),
|
|
254
|
+
"aria-label": "Display font stack",
|
|
255
|
+
className: "bg-card placeholder:text-muted-foreground focus-visible:border-ring/60 focus-visible:ring-2 focus-visible:ring-ring mt-1 font-mono text-xs",
|
|
256
|
+
"data-testid": tid2("font-display")
|
|
257
|
+
}
|
|
258
|
+
)
|
|
259
|
+
] }),
|
|
260
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
261
|
+
/* @__PURE__ */ jsx("span", { className: "block text-xs text-muted-foreground", children: "Body font stack" }),
|
|
262
|
+
/* @__PURE__ */ jsx(
|
|
263
|
+
Input,
|
|
264
|
+
{
|
|
265
|
+
value: fonts.sans,
|
|
266
|
+
onChange: (e) => setFont("sans", e.target.value),
|
|
267
|
+
"aria-label": "Body font stack",
|
|
268
|
+
className: "bg-card placeholder:text-muted-foreground focus-visible:border-ring/60 focus-visible:ring-2 focus-visible:ring-ring mt-1 font-mono text-xs",
|
|
269
|
+
"data-testid": tid2("font-sans")
|
|
270
|
+
}
|
|
271
|
+
)
|
|
272
|
+
] }),
|
|
273
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
274
|
+
/* @__PURE__ */ jsxs("span", { className: "block text-xs text-muted-foreground", children: [
|
|
275
|
+
"Base radius \u2014 ",
|
|
276
|
+
radius,
|
|
277
|
+
"rem"
|
|
278
|
+
] }),
|
|
279
|
+
/* @__PURE__ */ jsx(
|
|
280
|
+
"input",
|
|
281
|
+
{
|
|
282
|
+
type: "range",
|
|
283
|
+
min: 0,
|
|
284
|
+
max: 1.5,
|
|
285
|
+
step: 0.125,
|
|
286
|
+
value: radius,
|
|
287
|
+
onChange: (e) => setRadius(Number(e.target.value)),
|
|
288
|
+
"aria-label": "Base radius",
|
|
289
|
+
className: "mt-2 w-full accent-[color:var(--color-primary)]",
|
|
290
|
+
"data-testid": tid2("radius")
|
|
291
|
+
}
|
|
292
|
+
)
|
|
293
|
+
] })
|
|
294
|
+
] });
|
|
295
|
+
const Preview = /* @__PURE__ */ jsxs(Card, { variant: "elevated", className: "rounded-lg", "data-testid": tid2("preview"), children: [
|
|
296
|
+
/* @__PURE__ */ jsx(CardHeader, { children: /* @__PURE__ */ jsx(CardTitle, { className: "text-base", children: "Live preview" }) }),
|
|
297
|
+
/* @__PURE__ */ jsxs(CardContent, { className: "space-y-3", children: [
|
|
298
|
+
/* @__PURE__ */ jsxs("div", { className: "rounded-[var(--radius)] bg-primary p-4 text-primary-foreground", children: [
|
|
299
|
+
/* @__PURE__ */ jsx("p", { className: "font-display text-lg font-semibold", children: preview?.title ?? "Preview" }),
|
|
300
|
+
preview?.subtitle && /* @__PURE__ */ jsx("p", { className: "text-xs opacity-80", children: preview.subtitle })
|
|
301
|
+
] }),
|
|
302
|
+
/* @__PURE__ */ jsx("div", { className: "grid grid-cols-6 gap-1.5", children: tokens.map((t) => /* @__PURE__ */ jsx(
|
|
303
|
+
"div",
|
|
304
|
+
{
|
|
305
|
+
title: t.label,
|
|
306
|
+
className: "aspect-square rounded-md border border-border",
|
|
307
|
+
style: { background: `var(--color-${t.key})` }
|
|
308
|
+
},
|
|
309
|
+
t.key
|
|
310
|
+
)) }),
|
|
311
|
+
/* @__PURE__ */ jsxs("div", { className: "rounded-[var(--radius)] border border-border bg-[color:var(--color-ai-accent-soft,var(--color-accent))] p-3", children: [
|
|
312
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-[color:var(--color-ai-accent,var(--color-primary))]", children: "AI action surface" }),
|
|
313
|
+
/* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: "Themed by the AI-kit accent tokens." })
|
|
314
|
+
] })
|
|
315
|
+
] })
|
|
316
|
+
] });
|
|
317
|
+
const SaveBar = onSave && /* @__PURE__ */ jsxs("div", { className: "mt-6 flex items-center gap-3", children: [
|
|
318
|
+
/* @__PURE__ */ jsxs(
|
|
319
|
+
"button",
|
|
320
|
+
{
|
|
321
|
+
type: "button",
|
|
322
|
+
onClick: () => void save(),
|
|
323
|
+
disabled: saving,
|
|
324
|
+
className: "inline-flex items-center gap-1.5 rounded-md bg-primary px-3 py-2 text-sm font-medium text-primary-foreground hover:opacity-90 disabled:opacity-60",
|
|
325
|
+
"data-testid": tid2("save"),
|
|
326
|
+
children: [
|
|
327
|
+
savedVia ? /* @__PURE__ */ jsx(Check, { className: "size-4" }) : /* @__PURE__ */ jsx(Save, { className: "size-4" }),
|
|
328
|
+
saving ? "Saving\u2026" : savedVia ? "Saved" : "Save theme"
|
|
329
|
+
]
|
|
330
|
+
}
|
|
331
|
+
),
|
|
332
|
+
savedVia && /* @__PURE__ */ jsxs("span", { className: "text-xs text-muted-foreground", "data-testid": tid2("via"), children: [
|
|
333
|
+
"stored via ",
|
|
334
|
+
savedVia
|
|
335
|
+
] })
|
|
336
|
+
] });
|
|
337
|
+
if (variant === "collapsed") {
|
|
338
|
+
const controlsId = `${testIdPrefix}-controls`;
|
|
339
|
+
return /* @__PURE__ */ jsxs("div", { className: "space-y-3", "data-testid": testIdPrefix, children: [
|
|
340
|
+
Presets,
|
|
341
|
+
/* @__PURE__ */ jsx("div", { className: "grid grid-cols-8 gap-1.5 @xl:grid-cols-12", "aria-hidden": "true", children: tokens.slice(0, 12).map((t) => /* @__PURE__ */ jsx(
|
|
342
|
+
"div",
|
|
343
|
+
{
|
|
344
|
+
title: t.label,
|
|
345
|
+
className: "aspect-square rounded-md border border-border",
|
|
346
|
+
style: { background: `var(--color-${t.key})` }
|
|
347
|
+
},
|
|
348
|
+
t.key
|
|
349
|
+
)) }),
|
|
350
|
+
/* @__PURE__ */ jsxs(
|
|
351
|
+
"button",
|
|
352
|
+
{
|
|
353
|
+
type: "button",
|
|
354
|
+
onClick: () => setOpen((o) => !o),
|
|
355
|
+
"aria-expanded": open,
|
|
356
|
+
"aria-controls": controlsId,
|
|
357
|
+
className: "inline-flex items-center gap-1.5 text-sm font-medium text-foreground hover:text-primary",
|
|
358
|
+
"data-testid": tid2("customize"),
|
|
359
|
+
children: [
|
|
360
|
+
/* @__PURE__ */ jsx(ChevronDown, { className: `size-4 transition-transform ${open ? "rotate-180" : ""}` }),
|
|
361
|
+
"Customize colours and type"
|
|
362
|
+
]
|
|
363
|
+
}
|
|
364
|
+
),
|
|
365
|
+
open && /* @__PURE__ */ jsxs(
|
|
366
|
+
"div",
|
|
367
|
+
{
|
|
368
|
+
id: controlsId,
|
|
369
|
+
className: "max-h-[28rem] overflow-y-auto rounded-md border border-border bg-card p-4",
|
|
370
|
+
"data-testid": tid2("controls"),
|
|
371
|
+
children: [
|
|
372
|
+
/* @__PURE__ */ jsx("p", { className: "mb-2 text-xs font-semibold uppercase tracking-[0.14em] text-muted-foreground", children: "Colours" }),
|
|
373
|
+
/* @__PURE__ */ jsx("div", { className: "grid gap-3 @xl:grid-cols-2", children: tokens.map((t) => colorRow(t.key, t.label)) }),
|
|
374
|
+
/* @__PURE__ */ jsx("p", { className: "mt-6 mb-2 text-xs font-semibold uppercase tracking-[0.14em] text-muted-foreground", children: "Typography & shape" }),
|
|
375
|
+
Typography
|
|
376
|
+
]
|
|
377
|
+
}
|
|
378
|
+
),
|
|
379
|
+
SaveBar
|
|
380
|
+
] });
|
|
381
|
+
}
|
|
382
|
+
if (variant === "drawer") {
|
|
383
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex h-full flex-col overflow-y-auto bg-card p-5", "data-testid": testIdPrefix, children: [
|
|
384
|
+
/* @__PURE__ */ jsx("div", { className: "mb-4 flex items-center justify-between", children: /* @__PURE__ */ jsx("h2", { className: "font-display text-lg font-semibold text-foreground", children: "Theme" }) }),
|
|
385
|
+
Presets,
|
|
386
|
+
/* @__PURE__ */ jsx("p", { className: "mt-5 mb-2 text-xs font-semibold uppercase tracking-[0.14em] text-muted-foreground", children: "Colours" }),
|
|
387
|
+
/* @__PURE__ */ jsx("div", { className: "space-y-3", children: tokens.map((t) => colorRow(t.key, t.label)) }),
|
|
388
|
+
/* @__PURE__ */ jsx("p", { className: "mt-6 mb-2 text-xs font-semibold uppercase tracking-[0.14em] text-muted-foreground", children: "Typography & shape" }),
|
|
389
|
+
Typography,
|
|
390
|
+
SaveBar
|
|
391
|
+
] });
|
|
392
|
+
}
|
|
393
|
+
return /* @__PURE__ */ jsxs("div", { className: "grid gap-6 lg:grid-cols-[1fr_320px]", "data-testid": testIdPrefix, children: [
|
|
394
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-6", children: [
|
|
395
|
+
/* @__PURE__ */ jsxs(Card, { variant: "elevated", className: "rounded-lg", children: [
|
|
396
|
+
/* @__PURE__ */ jsx(CardHeader, { children: /* @__PURE__ */ jsxs(CardTitle, { className: "flex items-center gap-2 text-base", children: [
|
|
397
|
+
/* @__PURE__ */ jsx(Palette, { className: "size-4 text-[color:var(--color-primary)]" }),
|
|
398
|
+
" Presets"
|
|
399
|
+
] }) }),
|
|
400
|
+
/* @__PURE__ */ jsx(CardContent, { children: Presets })
|
|
401
|
+
] }),
|
|
402
|
+
groups.map((group) => /* @__PURE__ */ jsxs(
|
|
403
|
+
Card,
|
|
404
|
+
{
|
|
405
|
+
variant: "elevated",
|
|
406
|
+
className: "rounded-lg",
|
|
407
|
+
"data-testid": tid2(`group-${group}`),
|
|
408
|
+
children: [
|
|
409
|
+
/* @__PURE__ */ jsx(CardHeader, { children: /* @__PURE__ */ jsx(CardTitle, { className: "text-base", children: groupLabels[group] ?? group }) }),
|
|
410
|
+
/* @__PURE__ */ jsx(CardContent, { className: "grid gap-3 @xl:grid-cols-2", children: tokens.filter((t) => t.group === group).map((t) => colorRow(t.key, t.label)) })
|
|
411
|
+
]
|
|
412
|
+
},
|
|
413
|
+
group
|
|
414
|
+
)),
|
|
415
|
+
/* @__PURE__ */ jsxs(Card, { variant: "elevated", className: "rounded-lg", children: [
|
|
416
|
+
/* @__PURE__ */ jsx(CardHeader, { children: /* @__PURE__ */ jsx(CardTitle, { className: "text-base", children: "Typography & shape" }) }),
|
|
417
|
+
/* @__PURE__ */ jsx(CardContent, { children: Typography })
|
|
418
|
+
] }),
|
|
419
|
+
SaveBar
|
|
420
|
+
] }),
|
|
421
|
+
/* @__PURE__ */ jsx("div", { className: "lg:sticky lg:top-4 lg:self-start", children: Preview })
|
|
422
|
+
] });
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
// src/lib/testid.ts
|
|
426
|
+
function tid(...parts) {
|
|
427
|
+
return parts.filter((p) => p !== void 0 && p !== false && p !== "").map(
|
|
428
|
+
(p) => String(p).trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "")
|
|
429
|
+
).join("-");
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
export { THEME_STYLE_ID, ThemeEditor, applyFontVars, applyThemeVars, clearFontVars, clearThemeVars, tid, toHslTriplet };
|
|
433
|
+
//# sourceMappingURL=chunk-5ZBXFHZW.js.map
|
|
434
|
+
//# sourceMappingURL=chunk-5ZBXFHZW.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/theme/tokens.ts","../src/theme/ThemeEditor.tsx","../src/lib/testid.ts"],"names":["tid"],"mappings":"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","file":"chunk-5ZBXFHZW.js","sourcesContent":["/**\n * The theme-token model. Firm-agnostic: the token *catalog*, default values and\n * presets are supplied by the consuming app (via {@link createThemeStore}); this\n * module owns the shared types and the logic for writing tokens onto the live\n * document.\n *\n * There are two emit models, selected per-app by {@link ThemeEmitMode}:\n *\n * - `'flat'` (default): each colour key is written as an inline `--color-<key>`\n * custom property on `<html>`, plus `--font-*` / `--radius`. Inline styles\n * override the compiled `@theme` defaults, so an edit previews live across the\n * whole app (and the @arbidocs AI kit) and reverts cleanly. Apps whose CSS sets\n * `--color-*` HEX directly rely on this.\n *\n * - `'cssVars'`: each colour key is written as a raw\n * HSL-triplet custom property (`--<key>: <h s l>`) into an injected\n * `<style id=\"arbi-theme-vars\">` appended to `<head>`. The monolith's source\n * of truth is HSL triplets wrapped as `hsl(var(--x))`, with a real `.dark`\n * variant; writing resolved hex inline would pin the colour and defeat both\n * the indirection and the dark-class swap. The injected sheet is *unlayered*,\n * so it wins over the monolith's `@layer base` `colors.css` at equal\n * specificity, and a `:root { light } / :root.dark { dark }` structure keeps\n * the dark cascade alive.\n */\n\nexport interface ColorToken {\n /** Key without the `--color-` prefix, e.g. \"primary\" → `--color-primary`. */\n key: string\n label: string\n /** Grouping id for the panel layout (e.g. \"shadcn\" | \"brand\" | \"ai\"). */\n group: string\n}\n\nexport interface ThemeFonts {\n display: string\n sans: string\n}\n\nexport interface ThemeTokens {\n /** Colour values keyed by token key (hex). */\n colors: Record<string, string>\n fonts: ThemeFonts\n /** Base radius in rem. */\n radius: number\n}\n\nexport interface ThemePreset {\n id: string\n label: string\n tokens: ThemeTokens\n}\n\n/** How a theme is written onto the document. See the module doc for the models. */\nexport type ThemeEmitMode = 'flat' | 'cssVars'\n\nexport interface ApplyThemeOptions {\n /** Emit model. Defaults to `'flat'`. */\n mode?: ThemeEmitMode\n /**\n * `cssVars` mode only: dark-variant colour values keyed by token key. Emitted\n * under `:root.dark`. When omitted, only `:root` is emitted — note that an\n * overridden light token then also applies in dark (the injected `:root` is\n * unlayered and beats the app's own `.dark` rules), so a host with a dark mode\n * MUST supply this for every editable token to keep dark mode intact.\n */\n dark?: Record<string, string>\n /** `flat` mode only: target element. Defaults to `document.documentElement`. */\n root?: HTMLElement\n}\n\n/** Id of the injected `<style>` that carries the `cssVars`-mode custom properties. */\nexport const THEME_STYLE_ID = 'arbi-theme-vars'\n\nconst TRIPLET_RE = /^-?\\d+(?:\\.\\d+)?\\s+-?\\d+(?:\\.\\d+)?%\\s+-?\\d+(?:\\.\\d+)?%$/\n\nfunction parseRgb(color: string): { r: number; g: number; b: number } | null {\n if (color.startsWith('#')) {\n let hex = color.slice(1)\n if (hex.length === 3) {\n hex = hex\n .split('')\n .map((ch) => ch + ch)\n .join('')\n }\n if (hex.length === 6 && /^[0-9a-fA-F]{6}$/.test(hex)) {\n return {\n r: parseInt(hex.slice(0, 2), 16),\n g: parseInt(hex.slice(2, 4), 16),\n b: parseInt(hex.slice(4, 6), 16),\n }\n }\n return null\n }\n const m = color.match(/^rgba?\\(\\s*([\\d.]+)[\\s,]+([\\d.]+)[\\s,]+([\\d.]+)/i)\n if (m) return { r: Number(m[1]), g: Number(m[2]), b: Number(m[3]) }\n return null\n}\n\nfunction rgbToHslTriplet(r: number, g: number, b: number): string {\n const rn = r / 255\n const gn = g / 255\n const bn = b / 255\n const max = Math.max(rn, gn, bn)\n const min = Math.min(rn, gn, bn)\n const l = (max + min) / 2\n const d = max - min\n let h = 0\n let s = 0\n if (d !== 0) {\n s = d / (1 - Math.abs(2 * l - 1))\n switch (max) {\n case rn:\n h = 60 * (((gn - bn) / d) % 6)\n break\n case gn:\n h = 60 * ((bn - rn) / d + 2)\n break\n default:\n h = 60 * ((rn - gn) / d + 4)\n break\n }\n }\n if (h < 0) h += 360\n return `${Math.round(h)} ${Math.round(s * 100)}% ${Math.round(l * 100)}%`\n}\n\n/**\n * Convert a colour to the monolith's `H S% L%` HSL-triplet format.\n *\n * Handles `#rgb` / `#rrggbb`, `rgb()` / `rgba()`, and passes an existing triplet\n * through untouched (so a host can seed exact `colors.css` triplets for a\n * byte-identical no-op). Values it cannot parse — notably `oklch(...)`, which the\n * status tokens use — are returned unchanged so they remain usable as a raw\n * custom-property value; converting those cleanly is out of scope.\n */\nexport function toHslTriplet(color: string): string {\n const c = color.trim()\n if (TRIPLET_RE.test(c)) return c\n const rgb = parseRgb(c)\n if (!rgb) return c\n return rgbToHslTriplet(rgb.r, rgb.g, rgb.b)\n}\n\nfunction renderTripletBlock(colors: Record<string, string>): string {\n return Object.entries(colors)\n .map(([key, value]) => ` --${key}: ${toHslTriplet(value)};`)\n .join('\\n')\n}\n\nfunction emitCssVars(theme: ThemeTokens, dark?: Record<string, string>): void {\n if (typeof document === 'undefined') return\n const meta = [\n ` --font-display: ${theme.fonts.display};`,\n ` --font-sans: ${theme.fonts.sans};`,\n ` --radius: ${theme.radius}rem;`,\n ].join('\\n')\n let css = `:root {\\n${renderTripletBlock(theme.colors)}\\n${meta}\\n}`\n if (dark) {\n css += `\\n:root.dark {\\n${renderTripletBlock(dark)}\\n}`\n }\n let style = document.getElementById(THEME_STYLE_ID) as HTMLStyleElement | null\n if (!style) {\n style = document.createElement('style')\n style.id = THEME_STYLE_ID\n document.head.appendChild(style)\n }\n style.textContent = css\n}\n\nfunction removeCssVars(): void {\n if (typeof document === 'undefined') return\n document.getElementById(THEME_STYLE_ID)?.remove()\n}\n\nfunction normalizeOptions(optionsOrRoot: ApplyThemeOptions | HTMLElement): ApplyThemeOptions {\n if (typeof HTMLElement !== 'undefined' && optionsOrRoot instanceof HTMLElement) {\n return { root: optionsOrRoot }\n }\n return optionsOrRoot as ApplyThemeOptions\n}\n\n/**\n * Write a theme onto the live document.\n *\n * In `flat` mode (default) writes inline `--color-<key>` / `--font-*` / `--radius`\n * on `document.documentElement` (or a supplied root). In `cssVars` mode writes\n * raw HSL-triplet vars into an injected `<style#arbi-theme-vars>` (see the module\n * doc). The legacy `applyThemeVars(theme, rootElement)` call form still works.\n */\nexport function applyThemeVars(\n theme: ThemeTokens,\n optionsOrRoot: ApplyThemeOptions | HTMLElement = {}\n): void {\n const { mode = 'flat', dark, root = document.documentElement } = normalizeOptions(optionsOrRoot)\n\n if (mode === 'cssVars') {\n emitCssVars(theme, dark)\n return\n }\n\n for (const [key, value] of Object.entries(theme.colors)) {\n root.style.setProperty(`--color-${key}`, value)\n }\n root.style.setProperty('--font-display', theme.fonts.display)\n root.style.setProperty('--font-sans', theme.fonts.sans)\n root.style.setProperty('--radius', `${theme.radius}rem`)\n}\n\n/**\n * Set ONLY the typography vars, as inline styles on the root element.\n *\n * Typography is often chosen independently of colour — an app may let a reader\n * pick a typeface while its palette is owned elsewhere. Writing the two vars\n * inline (rather than through `applyThemeVars`) keeps this orthogonal in two\n * ways: it touches no colour or radius token, and an inline style outranks any\n * selector, so a font choice survives a `cssVars`-mode theme that emits its own\n * `:root` block (the ARBI studio's theme editor does exactly that).\n */\nexport function applyFontVars(\n fonts: ThemeFonts,\n root: HTMLElement = document.documentElement\n): void {\n root.style.setProperty('--font-display', fonts.display)\n root.style.setProperty('--font-sans', fonts.sans)\n}\n\n/** Undo {@link applyFontVars}, reverting to the stylesheet's own font tokens. */\nexport function clearFontVars(root: HTMLElement = document.documentElement): void {\n root.style.removeProperty('--font-display')\n root.style.removeProperty('--font-sans')\n}\n\n/**\n * Remove a theme's overrides, reverting to the stylesheet defaults.\n *\n * In `flat` mode removes the inline overrides for the theme's keys. In `cssVars`\n * mode removes the injected `<style#arbi-theme-vars>` in full (restoring the\n * app's own `colors.css` exactly).\n */\nexport function clearThemeVars(\n theme: ThemeTokens,\n optionsOrRoot: ApplyThemeOptions | HTMLElement = {}\n): void {\n const { mode = 'flat', root = document.documentElement } = normalizeOptions(optionsOrRoot)\n\n if (mode === 'cssVars') {\n removeCssVars()\n return\n }\n\n for (const key of Object.keys(theme.colors)) {\n root.style.removeProperty(`--color-${key}`)\n }\n root.style.removeProperty('--font-display')\n root.style.removeProperty('--font-sans')\n root.style.removeProperty('--radius')\n}\n","/**\n * The one theme editor, shared by every surface. `variant=\"panel\"` is the roomy\n * back-office layout (grouped token cards + a live preview); `variant=\"drawer\"`\n * is the compact slide-over beside the studio canvas; `variant=\"collapsed\"` is\n * the settings-page form: presets and a swatch strip always visible, the colour\n * and typography controls behind a \"Customize\" disclosure in a bounded scroller\n * (the full editor is very tall). All drive the same\n * {@link ThemeBundle} store, so there is a single token model, preset list and\n * apply path. Firm-agnostic: chrome uses only universal surface tokens and the\n * preview renders the theme's own swatches, so it needs no brand-specific\n * component variants.\n */\nimport { useEffect, useState } from 'react'\nimport { RotateCcw, Palette, Save, Check, ChevronDown } from 'lucide-react'\nimport { Card, CardHeader, CardTitle, CardContent, Input } from '@arbidocs/react/ui'\nimport { applyThemeVars } from './tokens'\nimport { FONT_PAIRINGS, matchFontPairing } from './fontPairings'\nimport type { ThemeBundle } from './store'\n\nexport interface ThemeEditorProps {\n /** The host's theme store bundle (from createThemeStore). */\n bundle: ThemeBundle\n variant?: 'panel' | 'drawer' | 'collapsed'\n /** Firm identity shown in the panel's live-preview header. */\n preview?: { title: string; subtitle?: string }\n /** Optional persistence side-channel (e.g. save theme to ARBI); returns a \"via\" label. */\n onSave?: () => Promise<string | void>\n /** Stable testid namespace, e.g. \"builder-theme\" | \"studio-theme\". */\n testIdPrefix?: string\n /** `collapsed` only: start with the controls open. */\n defaultOpen?: boolean\n}\n\nexport function ThemeEditor({\n bundle,\n variant = 'panel',\n preview,\n onSave,\n testIdPrefix = 'theme',\n defaultOpen = false,\n}: ThemeEditorProps) {\n const { useStore, tokens, presets, groupLabels, mode, darkColors } = bundle\n const colors = useStore((s) => s.colors)\n const fonts = useStore((s) => s.fonts)\n const radius = useStore((s) => s.radius)\n const activePresetId = useStore((s) => s.activePresetId)\n const setColor = useStore((s) => s.setColor)\n const setFont = useStore((s) => s.setFont)\n const setFontPairing = useStore((s) => s.setFontPairing)\n const setRadius = useStore((s) => s.setRadius)\n const applyPreset = useStore((s) => s.applyPreset)\n const reset = useStore((s) => s.reset)\n\n const [open, setOpen] = useState(defaultOpen)\n const [saving, setSaving] = useState(false)\n const [savedVia, setSavedVia] = useState<string | null>(null)\n\n // Live preview: reflect every token change onto the running app, using the\n // host's emit mode (flat inline vars, or injected HSL-triplet cssVars).\n useEffect(() => {\n applyThemeVars({ colors, fonts, radius }, { mode, dark: darkColors })\n }, [colors, fonts, radius, mode, darkColors])\n\n const tid = (suffix: string) => `${testIdPrefix}-${suffix}`\n const groups = [...new Set(tokens.map((t) => t.group))]\n\n const save = async () => {\n if (!onSave) return\n setSaving(true)\n try {\n const via = await onSave()\n setSavedVia(typeof via === 'string' ? via : 'saved')\n } catch {\n // The host's onSave reports the failure (notify); never show a false \"saved\".\n setSavedVia(null)\n } finally {\n setSaving(false)\n }\n }\n\n // ── Presets row ────────────────────────────────────────────────────────────\n const Presets = (\n <div className=\"flex flex-wrap items-center gap-2\">\n {presets.map((p) => (\n <button\n key={p.id}\n type=\"button\"\n onClick={() => applyPreset(p.id)}\n className={`rounded-full border px-3 py-1 text-xs font-medium transition-colors ${\n activePresetId === p.id\n ? 'border-primary bg-primary text-primary-foreground'\n : 'border-border text-foreground hover:border-primary'\n }`}\n data-testid={tid(`preset-${p.id}`)}\n >\n {p.label}\n </button>\n ))}\n <button\n type=\"button\"\n onClick={reset}\n className=\"ml-auto inline-flex items-center gap-1.5 text-xs font-medium text-muted-foreground hover:text-foreground\"\n data-testid={tid('reset')}\n >\n <RotateCcw className=\"size-3\" /> Reset\n </button>\n </div>\n )\n\n // ── A single colour control ─────────────────────────────────────────────────\n // A plain function (not a component) so it inlines into the parent tree: this\n // avoids remounting the inputs on every keystroke (which would drop focus).\n const colorRow = (k: string, label: string) => (\n <div key={k} className=\"flex items-center gap-3\">\n <input\n type=\"color\"\n value={colors[k] ?? '#000000'}\n onChange={(e) => setColor(k, e.target.value)}\n className=\"size-9 shrink-0 cursor-pointer rounded-md border border-border bg-transparent\"\n aria-label={label}\n data-testid={tid(`color-${k}`)}\n />\n <div className=\"min-w-0 flex-1\">\n <span className=\"block text-xs text-muted-foreground\">{label}</span>\n <Input\n value={colors[k] ?? ''}\n onChange={(e) => setColor(k, e.target.value)}\n aria-label={`${label} hex value`}\n className=\"bg-card placeholder:text-muted-foreground focus-visible:border-ring/60 focus-visible:ring-2 focus-visible:ring-ring h-7 font-mono text-xs\"\n data-testid={tid(`hex-${k}`)}\n />\n </div>\n </div>\n )\n\n // ── Typography + radius ─────────────────────────────────────────────────────\n // The pairing picker is the primary control; the raw stacks below stay for\n // anyone who needs a face the catalog doesn't carry. Editing a stack by hand\n // drops the selection to \"Custom\" rather than silently mismatching.\n const activePairing = matchFontPairing(fonts)\n const Typography = (\n <div className=\"space-y-4\">\n <div>\n <span className=\"block text-xs text-muted-foreground\">Typeface</span>\n <select\n value={activePairing?.id ?? ''}\n onChange={(e) => setFontPairing(e.target.value)}\n aria-label=\"Typeface\"\n className=\"mt-1 h-8 w-full rounded-md border border-border bg-card px-2 text-xs text-foreground focus-visible:border-ring/60 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n data-testid={tid('font-pairing')}\n >\n {!activePairing && <option value=\"\">Custom</option>}\n {FONT_PAIRINGS.map((pairing) => (\n <option key={pairing.id} value={pairing.id}>\n {pairing.label}\n </option>\n ))}\n </select>\n <p className=\"mt-1 text-xs text-muted-foreground\">\n {activePairing?.description ?? 'Hand-edited font stacks.'}\n </p>\n </div>\n <div>\n <span className=\"block text-xs text-muted-foreground\">Display font stack</span>\n <Input\n value={fonts.display}\n onChange={(e) => setFont('display', e.target.value)}\n aria-label=\"Display font stack\"\n className=\"bg-card placeholder:text-muted-foreground focus-visible:border-ring/60 focus-visible:ring-2 focus-visible:ring-ring mt-1 font-mono text-xs\"\n data-testid={tid('font-display')}\n />\n </div>\n <div>\n <span className=\"block text-xs text-muted-foreground\">Body font stack</span>\n <Input\n value={fonts.sans}\n onChange={(e) => setFont('sans', e.target.value)}\n aria-label=\"Body font stack\"\n className=\"bg-card placeholder:text-muted-foreground focus-visible:border-ring/60 focus-visible:ring-2 focus-visible:ring-ring mt-1 font-mono text-xs\"\n data-testid={tid('font-sans')}\n />\n </div>\n <div>\n <span className=\"block text-xs text-muted-foreground\">Base radius — {radius}rem</span>\n <input\n type=\"range\"\n min={0}\n max={1.5}\n step={0.125}\n value={radius}\n onChange={(e) => setRadius(Number(e.target.value))}\n aria-label=\"Base radius\"\n className=\"mt-2 w-full accent-[color:var(--color-primary)]\"\n data-testid={tid('radius')}\n />\n </div>\n </div>\n )\n\n // ── Live preview (panel only) — renders the theme's own swatches ────────────\n const Preview = (\n <Card variant=\"elevated\" className=\"rounded-lg\" data-testid={tid('preview')}>\n <CardHeader>\n <CardTitle className=\"text-base\">Live preview</CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-3\">\n <div className=\"rounded-[var(--radius)] bg-primary p-4 text-primary-foreground\">\n <p className=\"font-display text-lg font-semibold\">{preview?.title ?? 'Preview'}</p>\n {preview?.subtitle && <p className=\"text-xs opacity-80\">{preview.subtitle}</p>}\n </div>\n <div className=\"grid grid-cols-6 gap-1.5\">\n {tokens.map((t) => (\n <div\n key={t.key}\n title={t.label}\n className=\"aspect-square rounded-md border border-border\"\n style={{ background: `var(--color-${t.key})` }}\n />\n ))}\n </div>\n <div className=\"rounded-[var(--radius)] border border-border bg-[color:var(--color-ai-accent-soft,var(--color-accent))] p-3\">\n <p className=\"text-sm font-medium text-[color:var(--color-ai-accent,var(--color-primary))]\">\n AI action surface\n </p>\n <p className=\"text-xs text-muted-foreground\">Themed by the AI-kit accent tokens.</p>\n </div>\n </CardContent>\n </Card>\n )\n\n const SaveBar = onSave && (\n <div className=\"mt-6 flex items-center gap-3\">\n <button\n type=\"button\"\n onClick={() => void save()}\n disabled={saving}\n className=\"inline-flex items-center gap-1.5 rounded-md bg-primary px-3 py-2 text-sm font-medium text-primary-foreground hover:opacity-90 disabled:opacity-60\"\n data-testid={tid('save')}\n >\n {savedVia ? <Check className=\"size-4\" /> : <Save className=\"size-4\" />}\n {saving ? 'Saving…' : savedVia ? 'Saved' : 'Save theme'}\n </button>\n {savedVia && (\n <span className=\"text-xs text-muted-foreground\" data-testid={tid('via')}>\n stored via {savedVia}\n </span>\n )}\n </div>\n )\n\n // ── Collapsed layout — settings pages ───────────────────────────────────────\n if (variant === 'collapsed') {\n const controlsId = `${testIdPrefix}-controls`\n return (\n <div className=\"space-y-3\" data-testid={testIdPrefix}>\n {Presets}\n <div className=\"grid grid-cols-8 gap-1.5 @xl:grid-cols-12\" aria-hidden=\"true\">\n {tokens.slice(0, 12).map((t) => (\n <div\n key={t.key}\n title={t.label}\n className=\"aspect-square rounded-md border border-border\"\n style={{ background: `var(--color-${t.key})` }}\n />\n ))}\n </div>\n <button\n type=\"button\"\n onClick={() => setOpen((o) => !o)}\n aria-expanded={open}\n aria-controls={controlsId}\n className=\"inline-flex items-center gap-1.5 text-sm font-medium text-foreground hover:text-primary\"\n data-testid={tid('customize')}\n >\n <ChevronDown className={`size-4 transition-transform ${open ? 'rotate-180' : ''}`} />\n Customize colours and type\n </button>\n {open && (\n <div\n id={controlsId}\n className=\"max-h-[28rem] overflow-y-auto rounded-md border border-border bg-card p-4\"\n data-testid={tid('controls')}\n >\n <p className=\"mb-2 text-xs font-semibold uppercase tracking-[0.14em] text-muted-foreground\">\n Colours\n </p>\n <div className=\"grid gap-3 @xl:grid-cols-2\">\n {tokens.map((t) => colorRow(t.key, t.label))}\n </div>\n <p className=\"mt-6 mb-2 text-xs font-semibold uppercase tracking-[0.14em] text-muted-foreground\">\n Typography & shape\n </p>\n {Typography}\n </div>\n )}\n {SaveBar}\n </div>\n )\n }\n\n // ── Drawer layout — compact, single column ──────────────────────────────────\n if (variant === 'drawer') {\n return (\n <div className=\"flex h-full flex-col overflow-y-auto bg-card p-5\" data-testid={testIdPrefix}>\n <div className=\"mb-4 flex items-center justify-between\">\n <h2 className=\"font-display text-lg font-semibold text-foreground\">Theme</h2>\n </div>\n {Presets}\n <p className=\"mt-5 mb-2 text-xs font-semibold uppercase tracking-[0.14em] text-muted-foreground\">\n Colours\n </p>\n <div className=\"space-y-3\">{tokens.map((t) => colorRow(t.key, t.label))}</div>\n <p className=\"mt-6 mb-2 text-xs font-semibold uppercase tracking-[0.14em] text-muted-foreground\">\n Typography & shape\n </p>\n {Typography}\n {SaveBar}\n </div>\n )\n }\n\n // ── Panel layout — grouped cards + live preview ─────────────────────────────\n return (\n <div className=\"grid gap-6 lg:grid-cols-[1fr_320px]\" data-testid={testIdPrefix}>\n <div className=\"space-y-6\">\n <Card variant=\"elevated\" className=\"rounded-lg\">\n <CardHeader>\n <CardTitle className=\"flex items-center gap-2 text-base\">\n <Palette className=\"size-4 text-[color:var(--color-primary)]\" /> Presets\n </CardTitle>\n </CardHeader>\n <CardContent>{Presets}</CardContent>\n </Card>\n\n {groups.map((group) => (\n <Card\n key={group}\n variant=\"elevated\"\n className=\"rounded-lg\"\n data-testid={tid(`group-${group}`)}\n >\n <CardHeader>\n <CardTitle className=\"text-base\">{groupLabels[group] ?? group}</CardTitle>\n </CardHeader>\n <CardContent className=\"grid gap-3 @xl:grid-cols-2\">\n {tokens.filter((t) => t.group === group).map((t) => colorRow(t.key, t.label))}\n </CardContent>\n </Card>\n ))}\n\n <Card variant=\"elevated\" className=\"rounded-lg\">\n <CardHeader>\n <CardTitle className=\"text-base\">Typography & shape</CardTitle>\n </CardHeader>\n <CardContent>{Typography}</CardContent>\n </Card>\n {SaveBar}\n </div>\n\n <div className=\"lg:sticky lg:top-4 lg:self-start\">{Preview}</div>\n </div>\n )\n}\n","/**\n * Compose a stable, kebab-case data-testid from parts.\n * Convention: {area}-{element}[-{qualifier}...]\n * tid(\"orders\", \"row\", \"CLM-2026-0042\") -> \"orders-row-clm-2026-0042\"\n * Keeps Playwright selectors predictable across a host app.\n */\nexport function tid(...parts: Array<string | number | undefined | false>): string {\n return parts\n .filter((p): p is string | number => p !== undefined && p !== false && p !== '')\n .map((p) =>\n String(p)\n .trim()\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '')\n )\n .join('-')\n}\n"]}
|