@devfellowship/components 3.3.0 → 3.4.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/index.cjs +125 -11
- package/dist/index.d.cts +15 -2
- package/dist/index.d.ts +15 -2
- package/dist/index.js +117 -4
- package/dist/styles/theme-mappings.css +27 -0
- package/dist/styles/tokens.css +29 -0
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -244,6 +244,7 @@ __export(src_exports, {
|
|
|
244
244
|
ResizableHandle: () => ResizableHandle,
|
|
245
245
|
ResizablePanel: () => ResizablePanel,
|
|
246
246
|
ResizablePanelGroup: () => ResizablePanelGroup,
|
|
247
|
+
Roadmap: () => Roadmap,
|
|
247
248
|
ScrollArea: () => ScrollArea,
|
|
248
249
|
ScrollBar: () => ScrollBar,
|
|
249
250
|
Select: () => Select,
|
|
@@ -9104,17 +9105,129 @@ function firstFreeRow(taken, columns, from) {
|
|
|
9104
9105
|
return row;
|
|
9105
9106
|
}
|
|
9106
9107
|
|
|
9107
|
-
// src/
|
|
9108
|
+
// src/components/organisms/roadmap/Roadmap.tsx
|
|
9108
9109
|
var import_react7 = require("react");
|
|
9110
|
+
|
|
9111
|
+
// src/components/organisms/roadmap/RoadmapNode.tsx
|
|
9112
|
+
var import_class_variance_authority14 = require("class-variance-authority");
|
|
9113
|
+
|
|
9114
|
+
// src/components/organisms/roadmap/RoadmapLegend.tsx
|
|
9115
|
+
var import_lucide_react22 = require("lucide-react");
|
|
9116
|
+
|
|
9117
|
+
// src/components/organisms/roadmap/appearance.ts
|
|
9118
|
+
function toneStyle(tone) {
|
|
9119
|
+
return {
|
|
9120
|
+
"--c-roadmap-node-bg": `var(--c-roadmap-${tone}-bg)`,
|
|
9121
|
+
"--c-roadmap-node-fg": `var(--c-roadmap-${tone}-fg)`
|
|
9122
|
+
};
|
|
9123
|
+
}
|
|
9124
|
+
var focusClass = "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--c-roadmap-focus)] focus-visible:ring-offset-2 focus-visible:ring-offset-[var(--c-roadmap-surface)]";
|
|
9125
|
+
|
|
9126
|
+
// src/components/organisms/roadmap/RoadmapLegend.tsx
|
|
9127
|
+
var import_jsx_runtime65 = require("react/jsx-runtime");
|
|
9128
|
+
var glyphs = { check: import_lucide_react22.Check, globe: import_lucide_react22.Globe, lock: import_lucide_react22.Lock, star: import_lucide_react22.Star, "book-open": import_lucide_react22.BookOpen, play: import_lucide_react22.Play, circle: import_lucide_react22.Circle, clock: import_lucide_react22.Clock, link: import_lucide_react22.Link, "external-link": import_lucide_react22.ExternalLink };
|
|
9129
|
+
function RoadmapBadge({ name = "check", tone = "neutral", label, className = "" }) {
|
|
9130
|
+
const Glyph = glyphs[name] ?? import_lucide_react22.CircleHelp;
|
|
9131
|
+
return /* @__PURE__ */ (0, import_jsx_runtime65.jsx)("span", { "aria-label": label, "aria-hidden": label ? void 0 : true, style: toneStyle(tone), className: `inline-flex h-5 w-5 shrink-0 items-center justify-center rounded-full border-2 border-[var(--c-roadmap-border)] bg-[var(--c-roadmap-node-bg)] text-[var(--c-roadmap-node-fg)] ${className}`, children: /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(Glyph, { size: 12, "aria-hidden": "true" }) });
|
|
9132
|
+
}
|
|
9133
|
+
function RoadmapLegendView({ legend, testIdPrefix = "roadmap" }) {
|
|
9134
|
+
return /* @__PURE__ */ (0, import_jsx_runtime65.jsx)("aside", { "data-testid": `${testIdPrefix}-legend`, "aria-label": "Legend", className: "min-w-0 rounded-[var(--radius)] border-2 border-[var(--c-roadmap-border)] bg-[var(--c-roadmap-neutral-bg)] p-3 text-[var(--c-roadmap-neutral-fg)]", children: /* @__PURE__ */ (0, import_jsx_runtime65.jsx)("ul", { className: "m-0 flex list-none flex-wrap gap-3 p-0", children: legend.entries.map((entry) => /* @__PURE__ */ (0, import_jsx_runtime65.jsxs)("li", { className: "flex min-w-0 items-center gap-2 text-xs leading-normal", children: [
|
|
9135
|
+
/* @__PURE__ */ (0, import_jsx_runtime65.jsx)(RoadmapBadge, { name: entry.icon, tone: entry.tone }),
|
|
9136
|
+
/* @__PURE__ */ (0, import_jsx_runtime65.jsx)("span", { className: "[overflow-wrap:anywhere]", children: entry.label })
|
|
9137
|
+
] }, entry.id)) }) });
|
|
9138
|
+
}
|
|
9139
|
+
|
|
9140
|
+
// src/components/organisms/roadmap/RoadmapNode.tsx
|
|
9141
|
+
var import_jsx_runtime66 = require("react/jsx-runtime");
|
|
9142
|
+
var nodeVariants = (0, import_class_variance_authority14.cva)("relative flex min-w-0 flex-col justify-center rounded-[var(--radius)] border-2 px-2 py-3 text-center text-xs leading-normal md:px-4 md:text-base text-[var(--c-roadmap-node-fg)]", {
|
|
9143
|
+
variants: {
|
|
9144
|
+
kind: { topic: "min-h-[49px] border-[var(--c-roadmap-border)] bg-[var(--c-roadmap-node-bg)]", subtopic: "min-h-[49px] border-[var(--c-roadmap-border)] bg-[var(--c-roadmap-node-bg)]", button: "min-h-[49px] border-[var(--c-roadmap-border)] bg-[var(--c-roadmap-node-bg)]", label: "border-transparent bg-transparent", title: "border-transparent bg-transparent font-semibold md:text-[28px]", paragraph: "text-left border-[var(--c-roadmap-border)] bg-[var(--c-roadmap-node-bg)]", legend: "border-[var(--c-roadmap-border)] bg-[var(--c-roadmap-node-bg)]" },
|
|
9145
|
+
state: { todo: "", done: "[--c-roadmap-node-bg:var(--c-roadmap-done-bg)] [--c-roadmap-node-fg:var(--c-roadmap-done-fg)]", learning: "[--c-roadmap-node-bg:var(--c-roadmap-learning-bg)] [--c-roadmap-node-fg:var(--c-roadmap-learning-fg)]", skipped: "[--c-roadmap-node-bg:var(--c-roadmap-skipped-bg)] [--c-roadmap-node-fg:var(--c-roadmap-skipped-fg)]", locked: "opacity-60" }
|
|
9146
|
+
}
|
|
9147
|
+
});
|
|
9148
|
+
function RoadmapNodeView({ node, state, badge, testIdPrefix, onNodeClick, onAction }) {
|
|
9149
|
+
const locked = state === "locked";
|
|
9150
|
+
const nodeTone = resolveNodeTone(node);
|
|
9151
|
+
const label = /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("span", { "data-testid": `${testIdPrefix}-node-label`, className: `[overflow-wrap:anywhere] ${state === "done" ? "line-through" : state === "learning" ? "underline" : ""}`, children: node.label });
|
|
9152
|
+
const interactiveClass = `block w-full min-w-0 text-inherit ${focusClass}`;
|
|
9153
|
+
const wholeBox = !locked && !node.action && !node.links?.length;
|
|
9154
|
+
const Box = wholeBox && node.href ? "a" : wholeBox && onNodeClick ? "button" : "div";
|
|
9155
|
+
const primary = Box !== "div" ? label : node.href && !locked ? /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("a", { href: node.href, className: interactiveClass, onClick: () => onNodeClick?.(node), children: label }) : onNodeClick && !locked ? /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("button", { type: "button", className: interactiveClass, onClick: () => onNodeClick(node), children: label }) : label;
|
|
9156
|
+
const icon = node.icon ?? (badge ? { name: badge.icon ?? "check", side: "right", tone: badge.tone } : void 0);
|
|
9157
|
+
return /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("div", { style: toneStyle(nodeTone), className: "min-w-0", children: /* @__PURE__ */ (0, import_jsx_runtime66.jsxs)(Box, { "data-roadmap-node-box": node.id, href: Box === "a" ? node.href : void 0, type: Box === "button" ? "button" : void 0, onClick: Box !== "div" ? () => onNodeClick?.(node) : void 0, className: `${nodeVariants({ kind: node.kind, state })} w-full ${Box !== "div" ? focusClass : ""}`, "aria-disabled": locked || void 0, title: node.kind === "topic" || node.kind === "subtopic" ? node.description : void 0, children: [
|
|
9158
|
+
icon && /* @__PURE__ */ (0, import_jsx_runtime66.jsx)(RoadmapBadge, { name: icon.name, tone: icon.tone ?? nodeTone, label: badge?.label ?? icon.name, className: `absolute top-1/2 -translate-y-1/2 ${icon.side === "left" ? "left-0 -translate-x-1/2" : "right-0 translate-x-1/2"}` }),
|
|
9159
|
+
primary,
|
|
9160
|
+
node.description && node.kind === "paragraph" && /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("p", { className: "mt-2 [overflow-wrap:anywhere]", children: node.description }),
|
|
9161
|
+
node.links && /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("ul", { className: "mt-2 list-none space-y-2 p-0", children: node.links.map((link, index) => /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("li", { children: locked ? /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("span", { children: link.label }) : /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("a", { href: link.href, className: `underline [overflow-wrap:anywhere] ${focusClass}`, onClick: (e) => e.stopPropagation(), children: link.label }) }, index)) }),
|
|
9162
|
+
node.action && /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("div", { style: toneStyle(node.action.tone ?? "primary"), className: "mt-3 min-w-0", children: node.action.href && !locked ? /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("a", { href: node.action.href, className: `inline-block rounded px-2 py-2 bg-[var(--c-roadmap-node-bg)] text-[var(--c-roadmap-node-fg)] [overflow-wrap:anywhere] ${focusClass}`, children: node.action.label }) : /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("button", { type: "button", disabled: locked, className: `max-w-full rounded px-2 py-2 bg-[var(--c-roadmap-node-bg)] text-[var(--c-roadmap-node-fg)] [overflow-wrap:anywhere] ${focusClass}`, onClick: (e) => {
|
|
9163
|
+
e.stopPropagation();
|
|
9164
|
+
if (node.action?.actionId) onAction?.(node.action.actionId, node);
|
|
9165
|
+
}, children: node.action.label }) })
|
|
9166
|
+
] }) });
|
|
9167
|
+
}
|
|
9168
|
+
|
|
9169
|
+
// src/components/organisms/roadmap/RoadmapGroup.tsx
|
|
9170
|
+
var import_jsx_runtime67 = require("react/jsx-runtime");
|
|
9171
|
+
function RoadmapGroupView({ group, testIdPrefix }) {
|
|
9172
|
+
return /* @__PURE__ */ (0, import_jsx_runtime67.jsx)(import_jsx_runtime67.Fragment, { children: groupColumnRuns(group).map((run, index) => /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)(
|
|
9173
|
+
"div",
|
|
9174
|
+
{
|
|
9175
|
+
"data-testid": `${testIdPrefix}-group`,
|
|
9176
|
+
"data-group-id": group.id,
|
|
9177
|
+
style: { ...toneStyle(resolveGroupTone(group)), gridColumn: `${run.start} / span ${run.span}`, gridRow: `${group.from + 1} / span ${group.to - group.from + 1}` },
|
|
9178
|
+
className: "pointer-events-none relative z-0 min-w-0 self-stretch rounded-[var(--radius)] border-2 border-[var(--c-roadmap-border)] bg-[var(--c-roadmap-node-bg)] text-[var(--c-roadmap-node-fg)]",
|
|
9179
|
+
children: [
|
|
9180
|
+
index === 0 && group.title && /* @__PURE__ */ (0, import_jsx_runtime67.jsx)("span", { className: "absolute left-2 right-2 top-0 -translate-y-1/2 text-xs leading-normal", children: /* @__PURE__ */ (0, import_jsx_runtime67.jsx)("span", { className: "bg-[var(--c-roadmap-surface)] px-1 [overflow-wrap:anywhere]", children: group.title }) }),
|
|
9181
|
+
index === 0 && group.description && /* @__PURE__ */ (0, import_jsx_runtime67.jsx)("span", { className: "sr-only", children: group.description })
|
|
9182
|
+
]
|
|
9183
|
+
},
|
|
9184
|
+
run.start
|
|
9185
|
+
)) });
|
|
9186
|
+
}
|
|
9187
|
+
|
|
9188
|
+
// src/components/organisms/roadmap/Roadmap.tsx
|
|
9189
|
+
var import_jsx_runtime68 = require("react/jsx-runtime");
|
|
9190
|
+
function Roadmap({ document: document2, state, renderNode, onNodeClick, onAction, testIdPrefix = "roadmap", className = "", ariaLabel }) {
|
|
9191
|
+
const { placements } = (0, import_react7.useMemo)(() => placeNodes(document2), [document2]);
|
|
9192
|
+
const badges = (0, import_react7.useMemo)(() => new Map(document2.legend?.entries.map((entry) => [entry.id, entry])), [document2.legend]);
|
|
9193
|
+
const legendPlacement = document2.legend ? resolveLegendPlacement(document2.legend) : void 0;
|
|
9194
|
+
const legend = document2.legend && /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(RoadmapLegendView, { legend: document2.legend, testIdPrefix });
|
|
9195
|
+
return /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)("section", { "data-testid": testIdPrefix, "aria-label": ariaLabel ?? document2.title ?? "Roadmap", className: `min-w-0 bg-[var(--c-roadmap-surface)] p-3 text-[var(--c-roadmap-neutral-fg)] ${className}`, children: [
|
|
9196
|
+
legendPlacement === "top" && /* @__PURE__ */ (0, import_jsx_runtime68.jsx)("div", { className: "mb-6", children: legend }),
|
|
9197
|
+
/* @__PURE__ */ (0, import_jsx_runtime68.jsxs)("div", { "data-testid": `${testIdPrefix}-grid`, role: "list", "aria-label": "Roadmap nodes", className: "relative isolate grid min-w-0 grid-cols-3 items-center gap-x-3 gap-y-8 md:gap-x-8", children: [
|
|
9198
|
+
document2.groups.map((group) => /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(RoadmapGroupView, { group, testIdPrefix }, group.id)),
|
|
9199
|
+
placements.map(({ node, row, column }) => {
|
|
9200
|
+
const resolvedState = resolveNodeState(node, state);
|
|
9201
|
+
return /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(
|
|
9202
|
+
"div",
|
|
9203
|
+
{
|
|
9204
|
+
role: "listitem",
|
|
9205
|
+
"data-testid": `${testIdPrefix}-node`,
|
|
9206
|
+
"data-node-id": node.id,
|
|
9207
|
+
"data-state": resolvedState,
|
|
9208
|
+
style: { gridColumn: `${column.start} / span ${column.span}`, gridRow: `${row.start} / span 1` },
|
|
9209
|
+
className: "relative z-10 min-w-0 px-2 py-4",
|
|
9210
|
+
children: node.kind === "legend" ? legendPlacement === "inline" ? legend : null : renderNode ? renderNode(node, resolvedState) : /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(RoadmapNodeView, { node, state: resolvedState, badge: node.badge ? badges.get(node.badge) : void 0, onNodeClick, onAction, testIdPrefix })
|
|
9211
|
+
},
|
|
9212
|
+
node.id
|
|
9213
|
+
);
|
|
9214
|
+
})
|
|
9215
|
+
] }),
|
|
9216
|
+
legendPlacement === "bottom" && /* @__PURE__ */ (0, import_jsx_runtime68.jsx)("div", { className: "mt-6", children: legend })
|
|
9217
|
+
] });
|
|
9218
|
+
}
|
|
9219
|
+
|
|
9220
|
+
// src/hooks/use-iframe-auth.ts
|
|
9221
|
+
var import_react8 = require("react");
|
|
9109
9222
|
function useIframeAuth() {
|
|
9110
|
-
const ctx = (0,
|
|
9223
|
+
const ctx = (0, import_react8.useContext)(IframeContext);
|
|
9111
9224
|
return { token: ctx.token, userId: ctx.userId, ready: ctx.ready };
|
|
9112
9225
|
}
|
|
9113
9226
|
|
|
9114
9227
|
// src/hooks/use-iframe-navigate.ts
|
|
9115
|
-
var
|
|
9228
|
+
var import_react9 = require("react");
|
|
9116
9229
|
function useIframeNavigate() {
|
|
9117
|
-
return (0,
|
|
9230
|
+
return (0, import_react9.useCallback)((path) => {
|
|
9118
9231
|
if (!window.parent || window.parent === window) return;
|
|
9119
9232
|
window.parent.postMessage(
|
|
9120
9233
|
{ type: "DFL_NAVIGATE", path },
|
|
@@ -9124,9 +9237,9 @@ function useIframeNavigate() {
|
|
|
9124
9237
|
}
|
|
9125
9238
|
|
|
9126
9239
|
// src/providers/feature-flag-provider.tsx
|
|
9127
|
-
var
|
|
9128
|
-
var
|
|
9129
|
-
var FeatureFlagContext = (0,
|
|
9240
|
+
var import_react10 = require("react");
|
|
9241
|
+
var import_jsx_runtime69 = require("react/jsx-runtime");
|
|
9242
|
+
var FeatureFlagContext = (0, import_react10.createContext)({
|
|
9130
9243
|
flags: {},
|
|
9131
9244
|
isEnabled: () => false
|
|
9132
9245
|
});
|
|
@@ -9134,21 +9247,21 @@ var FeatureFlagProvider = ({
|
|
|
9134
9247
|
children,
|
|
9135
9248
|
flags
|
|
9136
9249
|
}) => {
|
|
9137
|
-
const value = (0,
|
|
9250
|
+
const value = (0, import_react10.useMemo)(
|
|
9138
9251
|
() => ({
|
|
9139
9252
|
flags,
|
|
9140
9253
|
isEnabled: (flag) => Boolean(flags[flag])
|
|
9141
9254
|
}),
|
|
9142
9255
|
[flags]
|
|
9143
9256
|
);
|
|
9144
|
-
return /* @__PURE__ */ (0,
|
|
9257
|
+
return /* @__PURE__ */ (0, import_jsx_runtime69.jsx)(FeatureFlagContext.Provider, { value, children });
|
|
9145
9258
|
};
|
|
9146
9259
|
var useFeatureFlag = (flag) => {
|
|
9147
|
-
const { isEnabled } = (0,
|
|
9260
|
+
const { isEnabled } = (0, import_react10.useContext)(FeatureFlagContext);
|
|
9148
9261
|
return isEnabled(flag);
|
|
9149
9262
|
};
|
|
9150
9263
|
var useFeatureFlags = () => {
|
|
9151
|
-
const { flags } = (0,
|
|
9264
|
+
const { flags } = (0, import_react10.useContext)(FeatureFlagContext);
|
|
9152
9265
|
return flags;
|
|
9153
9266
|
};
|
|
9154
9267
|
// Annotate the CommonJS export names for ESM import in node:
|
|
@@ -9367,6 +9480,7 @@ var useFeatureFlags = () => {
|
|
|
9367
9480
|
ResizableHandle,
|
|
9368
9481
|
ResizablePanel,
|
|
9369
9482
|
ResizablePanelGroup,
|
|
9483
|
+
Roadmap,
|
|
9370
9484
|
ScrollArea,
|
|
9371
9485
|
ScrollBar,
|
|
9372
9486
|
Select,
|
package/dist/index.d.cts
CHANGED
|
@@ -2219,7 +2219,7 @@ declare function PublishDrawer({ open, onOpenChange, supabase, videoUrl, transcr
|
|
|
2219
2219
|
*
|
|
2220
2220
|
* Colour is a TOKEN, never a hex (plan ADR-6). `tone` is one of eight names and
|
|
2221
2221
|
* the schema REJECTS any other string, `"#fdff00"` included. That closed
|
|
2222
|
-
* vocabulary is what keeps the dark design system
|
|
2222
|
+
* vocabulary is what keeps the dark design system and a
|
|
2223
2223
|
* downstream `--s-*` rebrand all working from one document.
|
|
2224
2224
|
*
|
|
2225
2225
|
* The live progress state does NOT live in the document (plan ADR-8). A document
|
|
@@ -3262,4 +3262,17 @@ declare function placeNodes(doc: Pick<RoadmapDocument, "nodes">): {
|
|
|
3262
3262
|
*/
|
|
3263
3263
|
declare function firstFreeRow(taken: ReadonlySet<string>, columns: readonly RoadmapColumn[], from: number): number;
|
|
3264
3264
|
|
|
3265
|
-
|
|
3265
|
+
interface RoadmapProps {
|
|
3266
|
+
document: RoadmapDocument;
|
|
3267
|
+
state?: RoadmapStateOverlay;
|
|
3268
|
+
renderNode?: (node: RoadmapNode, state: RoadmapNodeState) => ReactNode;
|
|
3269
|
+
onNodeClick?: (node: RoadmapNode) => void;
|
|
3270
|
+
onAction?: (actionId: string, node: RoadmapNode) => void;
|
|
3271
|
+
testIdPrefix?: string;
|
|
3272
|
+
className?: string;
|
|
3273
|
+
ariaLabel?: string;
|
|
3274
|
+
}
|
|
3275
|
+
/** Dark-only, ordinary document scroll. The JSON owns placement; CSS owns the pixels. */
|
|
3276
|
+
declare function Roadmap({ document, state, renderNode, onNodeClick, onAction, testIdPrefix, className, ariaLabel }: RoadmapProps): React__default.JSX.Element;
|
|
3277
|
+
|
|
3278
|
+
export { ALLOWED_ORIGINS, AVATAR_MEMBER_PALETTE_SIZE, Accordion, AccordionContent, AccordionItem, AccordionTrigger, Alert, AlertDescription, AlertDialog, AlertDialogAction, type AlertDialogActionProps, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, AlertTitle, AppNavbar, type AppNavbarProps, AppSidebar, type AppSidebarProps, AspectRatio, Avatar, AvatarFallback, AvatarGroup, AvatarImage, type AvatarSize, AvatarStatus, type AvatarStatusValue, type AvatarTone, Badge, type BadgeProps, Breadcrumb, BreadcrumbEllipsis, type BreadcrumbEntry, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator, Button, type ButtonProps, Calendar, type CalendarProps, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Carousel, type CarouselApi, CarouselContent, CarouselDots, CarouselItem, CarouselNext, CarouselPrevious, type ChartConfig, ChartContainer, ChartLegend, ChartLegendContent, ChartStyle, ChartTooltip, ChartTooltipContent, Checkbox, Collapsible, CollapsibleContent, CollapsibleHeader, CollapsibleItem, CollapsibleTrigger, Command, CommandDialog, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandSeparator, CommandShortcut, ConfirmDialog, type ConfirmDialogProps, ContextMenu, ContextMenuCheckboxItem, ContextMenuContent, ContextMenuGroup, ContextMenuItem, ContextMenuLabel, ContextMenuPortal, ContextMenuRadioGroup, ContextMenuRadioItem, ContextMenuSeparator, ContextMenuShortcut, ContextMenuSub, ContextMenuSubContent, ContextMenuSubTrigger, ContextMenuTrigger, DEFAULT_EDGE_ARROW, DEFAULT_EDGE_ROUTE, DEFAULT_EDGE_STYLE, DEFAULT_GROUP_TONE, DEFAULT_LEGEND_PLACEMENT, DEFAULT_NAME_COL_WIDTH, DEFAULT_NODE_SPAN, DEFAULT_NODE_STATE, type DflIframeMessage, type DflNavigateMessage, type DflReadyMessage, DflRemote, type DflRemoteProps, type DflResizeMessage, type DflSetTokenMessage, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, Drawer, DrawerClose, DrawerContent, DrawerDescription, DrawerFooter, DrawerHeader, DrawerOverlay, DrawerPortal, DrawerTitle, DrawerTrigger, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage, Gantt, type GanttDependency, type GanttMilestone, type GanttProps, type GanttStage, HoverCard, HoverCardContent, HoverCardTrigger, IconButton, type IconButtonProps, IframeAware, type IframeAwareProps, IframeContext, type IframeContextValue, type IframeMessageType, Input, InputOTP, InputOTPGroup, InputOTPSeparator, InputOTPSlot, Kbd, type KbdProps, Label, LoginPage, type LoginPageProps, LoginScreen, type LoginScreenProps, MEMBER_PALETTE_SIZE, Menubar, MenubarCheckboxItem, MenubarContent, MenubarGroup, MenubarItem, MenubarLabel, MenubarMenu, MenubarPortal, MenubarRadioGroup, MenubarRadioItem, MenubarSeparator, MenubarShortcut, MenubarSub, MenubarSubContent, MenubarSubTrigger, MenubarTrigger, NODE_KIND_DEFAULT_TONE, type NavGroup, type NavItem, type NavbarUserInfo, NavigationMenu, NavigationMenuContent, NavigationMenuIndicator, NavigationMenuItem, NavigationMenuLink, NavigationMenuList, NavigationMenuTrigger, NavigationMenuViewport, type OTPStatus, Pagination, PaginationContent, PaginationEllipsis, PaginationItem, PaginationLink, PaginationNext, PaginationPrevious, PasswordInput, type PasswordInputProps, Popover, PopoverAnchor, PopoverContent, PopoverTrigger, Progress, type ProgressProps, ProtectedRoute, type ProtectedRouteProps, PublishDrawer, type PublishDrawerProps, type PublishDrawerSupabase, type PublishResult, type PublishStatus, type PublisherAccount, ROADMAP_ARROWS, ROADMAP_COLUMNS, ROADMAP_EDGE_LABEL_MAX, ROADMAP_EDGE_ROUTES, ROADMAP_EDGE_STYLES, ROADMAP_LABEL_MAX, ROADMAP_LEGEND_PLACEMENTS, ROADMAP_NODE_ID_PATTERN, ROADMAP_NODE_KINDS, ROADMAP_NODE_STATES, ROADMAP_TONES, RadioGroup, RadioGroupItem, RadioGroupRow, ResizableHandle, ResizablePanel, ResizablePanelGroup, Roadmap, type RoadmapAction, type RoadmapArrow, type RoadmapColumn, type RoadmapDocument, type RoadmapEdge, type RoadmapEdgeRoute, type RoadmapEdgeStyle, type RoadmapGroup, type RoadmapGroupRange, type RoadmapIcon, type RoadmapLegend, type RoadmapLegendEntry, type RoadmapLegendPlacement, type RoadmapLink, type RoadmapNode, type RoadmapNodeKind, type RoadmapNodeState, type RoadmapOverlap, type RoadmapPlacement, type RoadmapProps, type RoadmapStateOverlay, type RoadmapTone, ScrollArea, type ScrollAreaScrollbars, ScrollBar, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, Separator, SeparatorWithLabel, Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetOverlay, SheetPortal, SheetTitle, SheetTrigger, Sidebar, SidebarContent, SidebarFooter, SidebarGroup, SidebarGroupAction, SidebarGroupContent, SidebarGroupLabel, SidebarHeader, SidebarInput, SidebarInset, SidebarMenu, SidebarMenuAction, SidebarMenuBadge, SidebarMenuButton, SidebarMenuItem, SidebarMenuSkeleton, SidebarMenuSub, SidebarMenuSubButton, SidebarMenuSubItem, SidebarProvider, SidebarRail, SidebarSeparator, SidebarTrigger, Skeleton, Slider, SonnerToaster, Switch, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, Textarea, type TextareaProps, Toast, ToastAction, type ToastActionElement, ToastClose, type ToastComponentProps, ToastDescription, ToastProvider, ToastTitle, ToastViewport, Toaster, Toggle, ToggleGroup, ToggleGroupItem, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, UserAvatar, type UserAvatarProps, type UserInfo, UserMenu, type UserMenuItem, type UserMenuProps, avatarMemberColor, badgeVariants, barGridColumn, buttonVariants, clampPct, columnIndex, columnsCovered, columnsUsed, filterPublishableAccounts, firstFreeRow, getInitials, gridColumnFor, groupColumnRuns, groupRanges, iconButtonVariants, isAllowedOrigin, kbdVariants, labelVariants, maxRowOf, memberHueIndex, memberHueVar, navigationMenuTriggerStyle, nodesByRow, parseRoadmapDocument, parseRoadmapStateOverlay, parseTags, placeNodes, resolveEdgeArrow, resolveEdgeRoute, resolveEdgeStyle, resolveGroupColumns, resolveGroupTone, resolveLegendPlacement, resolveNameColWidth, resolveNodeSpan, resolveNodeState, resolveNodeTone, resolveWeekCount, resolveWeekLabels, roadmapActionSchema, roadmapDocumentSchema, roadmapEdgeSchema, roadmapGroupSchema, roadmapIconSchema, roadmapLegendEntrySchema, roadmapLegendSchema, roadmapLinkSchema, roadmapNodeSchema, roadmapNodeStateSchema, roadmapStateOverlaySchema, roadmapStateSchema, rowsOf, safeParseRoadmapDocument, safeParseRoadmapStateOverlay, stageProgress, toggleVariants, useFormField, useSidebar, validateNoOverlap, validatePublishForm };
|
package/dist/index.d.ts
CHANGED
|
@@ -2219,7 +2219,7 @@ declare function PublishDrawer({ open, onOpenChange, supabase, videoUrl, transcr
|
|
|
2219
2219
|
*
|
|
2220
2220
|
* Colour is a TOKEN, never a hex (plan ADR-6). `tone` is one of eight names and
|
|
2221
2221
|
* the schema REJECTS any other string, `"#fdff00"` included. That closed
|
|
2222
|
-
* vocabulary is what keeps the dark design system
|
|
2222
|
+
* vocabulary is what keeps the dark design system and a
|
|
2223
2223
|
* downstream `--s-*` rebrand all working from one document.
|
|
2224
2224
|
*
|
|
2225
2225
|
* The live progress state does NOT live in the document (plan ADR-8). A document
|
|
@@ -3262,4 +3262,17 @@ declare function placeNodes(doc: Pick<RoadmapDocument, "nodes">): {
|
|
|
3262
3262
|
*/
|
|
3263
3263
|
declare function firstFreeRow(taken: ReadonlySet<string>, columns: readonly RoadmapColumn[], from: number): number;
|
|
3264
3264
|
|
|
3265
|
-
|
|
3265
|
+
interface RoadmapProps {
|
|
3266
|
+
document: RoadmapDocument;
|
|
3267
|
+
state?: RoadmapStateOverlay;
|
|
3268
|
+
renderNode?: (node: RoadmapNode, state: RoadmapNodeState) => ReactNode;
|
|
3269
|
+
onNodeClick?: (node: RoadmapNode) => void;
|
|
3270
|
+
onAction?: (actionId: string, node: RoadmapNode) => void;
|
|
3271
|
+
testIdPrefix?: string;
|
|
3272
|
+
className?: string;
|
|
3273
|
+
ariaLabel?: string;
|
|
3274
|
+
}
|
|
3275
|
+
/** Dark-only, ordinary document scroll. The JSON owns placement; CSS owns the pixels. */
|
|
3276
|
+
declare function Roadmap({ document, state, renderNode, onNodeClick, onAction, testIdPrefix, className, ariaLabel }: RoadmapProps): React__default.JSX.Element;
|
|
3277
|
+
|
|
3278
|
+
export { ALLOWED_ORIGINS, AVATAR_MEMBER_PALETTE_SIZE, Accordion, AccordionContent, AccordionItem, AccordionTrigger, Alert, AlertDescription, AlertDialog, AlertDialogAction, type AlertDialogActionProps, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, AlertTitle, AppNavbar, type AppNavbarProps, AppSidebar, type AppSidebarProps, AspectRatio, Avatar, AvatarFallback, AvatarGroup, AvatarImage, type AvatarSize, AvatarStatus, type AvatarStatusValue, type AvatarTone, Badge, type BadgeProps, Breadcrumb, BreadcrumbEllipsis, type BreadcrumbEntry, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator, Button, type ButtonProps, Calendar, type CalendarProps, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Carousel, type CarouselApi, CarouselContent, CarouselDots, CarouselItem, CarouselNext, CarouselPrevious, type ChartConfig, ChartContainer, ChartLegend, ChartLegendContent, ChartStyle, ChartTooltip, ChartTooltipContent, Checkbox, Collapsible, CollapsibleContent, CollapsibleHeader, CollapsibleItem, CollapsibleTrigger, Command, CommandDialog, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandSeparator, CommandShortcut, ConfirmDialog, type ConfirmDialogProps, ContextMenu, ContextMenuCheckboxItem, ContextMenuContent, ContextMenuGroup, ContextMenuItem, ContextMenuLabel, ContextMenuPortal, ContextMenuRadioGroup, ContextMenuRadioItem, ContextMenuSeparator, ContextMenuShortcut, ContextMenuSub, ContextMenuSubContent, ContextMenuSubTrigger, ContextMenuTrigger, DEFAULT_EDGE_ARROW, DEFAULT_EDGE_ROUTE, DEFAULT_EDGE_STYLE, DEFAULT_GROUP_TONE, DEFAULT_LEGEND_PLACEMENT, DEFAULT_NAME_COL_WIDTH, DEFAULT_NODE_SPAN, DEFAULT_NODE_STATE, type DflIframeMessage, type DflNavigateMessage, type DflReadyMessage, DflRemote, type DflRemoteProps, type DflResizeMessage, type DflSetTokenMessage, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, Drawer, DrawerClose, DrawerContent, DrawerDescription, DrawerFooter, DrawerHeader, DrawerOverlay, DrawerPortal, DrawerTitle, DrawerTrigger, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage, Gantt, type GanttDependency, type GanttMilestone, type GanttProps, type GanttStage, HoverCard, HoverCardContent, HoverCardTrigger, IconButton, type IconButtonProps, IframeAware, type IframeAwareProps, IframeContext, type IframeContextValue, type IframeMessageType, Input, InputOTP, InputOTPGroup, InputOTPSeparator, InputOTPSlot, Kbd, type KbdProps, Label, LoginPage, type LoginPageProps, LoginScreen, type LoginScreenProps, MEMBER_PALETTE_SIZE, Menubar, MenubarCheckboxItem, MenubarContent, MenubarGroup, MenubarItem, MenubarLabel, MenubarMenu, MenubarPortal, MenubarRadioGroup, MenubarRadioItem, MenubarSeparator, MenubarShortcut, MenubarSub, MenubarSubContent, MenubarSubTrigger, MenubarTrigger, NODE_KIND_DEFAULT_TONE, type NavGroup, type NavItem, type NavbarUserInfo, NavigationMenu, NavigationMenuContent, NavigationMenuIndicator, NavigationMenuItem, NavigationMenuLink, NavigationMenuList, NavigationMenuTrigger, NavigationMenuViewport, type OTPStatus, Pagination, PaginationContent, PaginationEllipsis, PaginationItem, PaginationLink, PaginationNext, PaginationPrevious, PasswordInput, type PasswordInputProps, Popover, PopoverAnchor, PopoverContent, PopoverTrigger, Progress, type ProgressProps, ProtectedRoute, type ProtectedRouteProps, PublishDrawer, type PublishDrawerProps, type PublishDrawerSupabase, type PublishResult, type PublishStatus, type PublisherAccount, ROADMAP_ARROWS, ROADMAP_COLUMNS, ROADMAP_EDGE_LABEL_MAX, ROADMAP_EDGE_ROUTES, ROADMAP_EDGE_STYLES, ROADMAP_LABEL_MAX, ROADMAP_LEGEND_PLACEMENTS, ROADMAP_NODE_ID_PATTERN, ROADMAP_NODE_KINDS, ROADMAP_NODE_STATES, ROADMAP_TONES, RadioGroup, RadioGroupItem, RadioGroupRow, ResizableHandle, ResizablePanel, ResizablePanelGroup, Roadmap, type RoadmapAction, type RoadmapArrow, type RoadmapColumn, type RoadmapDocument, type RoadmapEdge, type RoadmapEdgeRoute, type RoadmapEdgeStyle, type RoadmapGroup, type RoadmapGroupRange, type RoadmapIcon, type RoadmapLegend, type RoadmapLegendEntry, type RoadmapLegendPlacement, type RoadmapLink, type RoadmapNode, type RoadmapNodeKind, type RoadmapNodeState, type RoadmapOverlap, type RoadmapPlacement, type RoadmapProps, type RoadmapStateOverlay, type RoadmapTone, ScrollArea, type ScrollAreaScrollbars, ScrollBar, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, Separator, SeparatorWithLabel, Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetOverlay, SheetPortal, SheetTitle, SheetTrigger, Sidebar, SidebarContent, SidebarFooter, SidebarGroup, SidebarGroupAction, SidebarGroupContent, SidebarGroupLabel, SidebarHeader, SidebarInput, SidebarInset, SidebarMenu, SidebarMenuAction, SidebarMenuBadge, SidebarMenuButton, SidebarMenuItem, SidebarMenuSkeleton, SidebarMenuSub, SidebarMenuSubButton, SidebarMenuSubItem, SidebarProvider, SidebarRail, SidebarSeparator, SidebarTrigger, Skeleton, Slider, SonnerToaster, Switch, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, Textarea, type TextareaProps, Toast, ToastAction, type ToastActionElement, ToastClose, type ToastComponentProps, ToastDescription, ToastProvider, ToastTitle, ToastViewport, Toaster, Toggle, ToggleGroup, ToggleGroupItem, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, UserAvatar, type UserAvatarProps, type UserInfo, UserMenu, type UserMenuItem, type UserMenuProps, avatarMemberColor, badgeVariants, barGridColumn, buttonVariants, clampPct, columnIndex, columnsCovered, columnsUsed, filterPublishableAccounts, firstFreeRow, getInitials, gridColumnFor, groupColumnRuns, groupRanges, iconButtonVariants, isAllowedOrigin, kbdVariants, labelVariants, maxRowOf, memberHueIndex, memberHueVar, navigationMenuTriggerStyle, nodesByRow, parseRoadmapDocument, parseRoadmapStateOverlay, parseTags, placeNodes, resolveEdgeArrow, resolveEdgeRoute, resolveEdgeStyle, resolveGroupColumns, resolveGroupTone, resolveLegendPlacement, resolveNameColWidth, resolveNodeSpan, resolveNodeState, resolveNodeTone, resolveWeekCount, resolveWeekLabels, roadmapActionSchema, roadmapDocumentSchema, roadmapEdgeSchema, roadmapGroupSchema, roadmapIconSchema, roadmapLegendEntrySchema, roadmapLegendSchema, roadmapLinkSchema, roadmapNodeSchema, roadmapNodeStateSchema, roadmapStateOverlaySchema, roadmapStateSchema, rowsOf, safeParseRoadmapDocument, safeParseRoadmapStateOverlay, stageProgress, toggleVariants, useFormField, useSidebar, validateNoOverlap, validatePublishForm };
|
package/dist/index.js
CHANGED
|
@@ -8716,6 +8716,118 @@ function firstFreeRow(taken, columns, from) {
|
|
|
8716
8716
|
return row;
|
|
8717
8717
|
}
|
|
8718
8718
|
|
|
8719
|
+
// src/components/organisms/roadmap/Roadmap.tsx
|
|
8720
|
+
import { useMemo as useMemo5 } from "react";
|
|
8721
|
+
|
|
8722
|
+
// src/components/organisms/roadmap/RoadmapNode.tsx
|
|
8723
|
+
import { cva as cva14 } from "class-variance-authority";
|
|
8724
|
+
|
|
8725
|
+
// src/components/organisms/roadmap/RoadmapLegend.tsx
|
|
8726
|
+
import { Check as Check4, Globe, Lock, Star, BookOpen, Play, Circle as Circle2, CircleHelp, Clock, Link as Link2, ExternalLink } from "lucide-react";
|
|
8727
|
+
|
|
8728
|
+
// src/components/organisms/roadmap/appearance.ts
|
|
8729
|
+
function toneStyle(tone) {
|
|
8730
|
+
return {
|
|
8731
|
+
"--c-roadmap-node-bg": `var(--c-roadmap-${tone}-bg)`,
|
|
8732
|
+
"--c-roadmap-node-fg": `var(--c-roadmap-${tone}-fg)`
|
|
8733
|
+
};
|
|
8734
|
+
}
|
|
8735
|
+
var focusClass = "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--c-roadmap-focus)] focus-visible:ring-offset-2 focus-visible:ring-offset-[var(--c-roadmap-surface)]";
|
|
8736
|
+
|
|
8737
|
+
// src/components/organisms/roadmap/RoadmapLegend.tsx
|
|
8738
|
+
import { jsx as jsx65, jsxs as jsxs40 } from "react/jsx-runtime";
|
|
8739
|
+
var glyphs = { check: Check4, globe: Globe, lock: Lock, star: Star, "book-open": BookOpen, play: Play, circle: Circle2, clock: Clock, link: Link2, "external-link": ExternalLink };
|
|
8740
|
+
function RoadmapBadge({ name = "check", tone = "neutral", label, className = "" }) {
|
|
8741
|
+
const Glyph = glyphs[name] ?? CircleHelp;
|
|
8742
|
+
return /* @__PURE__ */ jsx65("span", { "aria-label": label, "aria-hidden": label ? void 0 : true, style: toneStyle(tone), className: `inline-flex h-5 w-5 shrink-0 items-center justify-center rounded-full border-2 border-[var(--c-roadmap-border)] bg-[var(--c-roadmap-node-bg)] text-[var(--c-roadmap-node-fg)] ${className}`, children: /* @__PURE__ */ jsx65(Glyph, { size: 12, "aria-hidden": "true" }) });
|
|
8743
|
+
}
|
|
8744
|
+
function RoadmapLegendView({ legend, testIdPrefix = "roadmap" }) {
|
|
8745
|
+
return /* @__PURE__ */ jsx65("aside", { "data-testid": `${testIdPrefix}-legend`, "aria-label": "Legend", className: "min-w-0 rounded-[var(--radius)] border-2 border-[var(--c-roadmap-border)] bg-[var(--c-roadmap-neutral-bg)] p-3 text-[var(--c-roadmap-neutral-fg)]", children: /* @__PURE__ */ jsx65("ul", { className: "m-0 flex list-none flex-wrap gap-3 p-0", children: legend.entries.map((entry) => /* @__PURE__ */ jsxs40("li", { className: "flex min-w-0 items-center gap-2 text-xs leading-normal", children: [
|
|
8746
|
+
/* @__PURE__ */ jsx65(RoadmapBadge, { name: entry.icon, tone: entry.tone }),
|
|
8747
|
+
/* @__PURE__ */ jsx65("span", { className: "[overflow-wrap:anywhere]", children: entry.label })
|
|
8748
|
+
] }, entry.id)) }) });
|
|
8749
|
+
}
|
|
8750
|
+
|
|
8751
|
+
// src/components/organisms/roadmap/RoadmapNode.tsx
|
|
8752
|
+
import { jsx as jsx66, jsxs as jsxs41 } from "react/jsx-runtime";
|
|
8753
|
+
var nodeVariants = cva14("relative flex min-w-0 flex-col justify-center rounded-[var(--radius)] border-2 px-2 py-3 text-center text-xs leading-normal md:px-4 md:text-base text-[var(--c-roadmap-node-fg)]", {
|
|
8754
|
+
variants: {
|
|
8755
|
+
kind: { topic: "min-h-[49px] border-[var(--c-roadmap-border)] bg-[var(--c-roadmap-node-bg)]", subtopic: "min-h-[49px] border-[var(--c-roadmap-border)] bg-[var(--c-roadmap-node-bg)]", button: "min-h-[49px] border-[var(--c-roadmap-border)] bg-[var(--c-roadmap-node-bg)]", label: "border-transparent bg-transparent", title: "border-transparent bg-transparent font-semibold md:text-[28px]", paragraph: "text-left border-[var(--c-roadmap-border)] bg-[var(--c-roadmap-node-bg)]", legend: "border-[var(--c-roadmap-border)] bg-[var(--c-roadmap-node-bg)]" },
|
|
8756
|
+
state: { todo: "", done: "[--c-roadmap-node-bg:var(--c-roadmap-done-bg)] [--c-roadmap-node-fg:var(--c-roadmap-done-fg)]", learning: "[--c-roadmap-node-bg:var(--c-roadmap-learning-bg)] [--c-roadmap-node-fg:var(--c-roadmap-learning-fg)]", skipped: "[--c-roadmap-node-bg:var(--c-roadmap-skipped-bg)] [--c-roadmap-node-fg:var(--c-roadmap-skipped-fg)]", locked: "opacity-60" }
|
|
8757
|
+
}
|
|
8758
|
+
});
|
|
8759
|
+
function RoadmapNodeView({ node, state, badge, testIdPrefix, onNodeClick, onAction }) {
|
|
8760
|
+
const locked = state === "locked";
|
|
8761
|
+
const nodeTone = resolveNodeTone(node);
|
|
8762
|
+
const label = /* @__PURE__ */ jsx66("span", { "data-testid": `${testIdPrefix}-node-label`, className: `[overflow-wrap:anywhere] ${state === "done" ? "line-through" : state === "learning" ? "underline" : ""}`, children: node.label });
|
|
8763
|
+
const interactiveClass = `block w-full min-w-0 text-inherit ${focusClass}`;
|
|
8764
|
+
const wholeBox = !locked && !node.action && !node.links?.length;
|
|
8765
|
+
const Box = wholeBox && node.href ? "a" : wholeBox && onNodeClick ? "button" : "div";
|
|
8766
|
+
const primary = Box !== "div" ? label : node.href && !locked ? /* @__PURE__ */ jsx66("a", { href: node.href, className: interactiveClass, onClick: () => onNodeClick?.(node), children: label }) : onNodeClick && !locked ? /* @__PURE__ */ jsx66("button", { type: "button", className: interactiveClass, onClick: () => onNodeClick(node), children: label }) : label;
|
|
8767
|
+
const icon = node.icon ?? (badge ? { name: badge.icon ?? "check", side: "right", tone: badge.tone } : void 0);
|
|
8768
|
+
return /* @__PURE__ */ jsx66("div", { style: toneStyle(nodeTone), className: "min-w-0", children: /* @__PURE__ */ jsxs41(Box, { "data-roadmap-node-box": node.id, href: Box === "a" ? node.href : void 0, type: Box === "button" ? "button" : void 0, onClick: Box !== "div" ? () => onNodeClick?.(node) : void 0, className: `${nodeVariants({ kind: node.kind, state })} w-full ${Box !== "div" ? focusClass : ""}`, "aria-disabled": locked || void 0, title: node.kind === "topic" || node.kind === "subtopic" ? node.description : void 0, children: [
|
|
8769
|
+
icon && /* @__PURE__ */ jsx66(RoadmapBadge, { name: icon.name, tone: icon.tone ?? nodeTone, label: badge?.label ?? icon.name, className: `absolute top-1/2 -translate-y-1/2 ${icon.side === "left" ? "left-0 -translate-x-1/2" : "right-0 translate-x-1/2"}` }),
|
|
8770
|
+
primary,
|
|
8771
|
+
node.description && node.kind === "paragraph" && /* @__PURE__ */ jsx66("p", { className: "mt-2 [overflow-wrap:anywhere]", children: node.description }),
|
|
8772
|
+
node.links && /* @__PURE__ */ jsx66("ul", { className: "mt-2 list-none space-y-2 p-0", children: node.links.map((link, index) => /* @__PURE__ */ jsx66("li", { children: locked ? /* @__PURE__ */ jsx66("span", { children: link.label }) : /* @__PURE__ */ jsx66("a", { href: link.href, className: `underline [overflow-wrap:anywhere] ${focusClass}`, onClick: (e) => e.stopPropagation(), children: link.label }) }, index)) }),
|
|
8773
|
+
node.action && /* @__PURE__ */ jsx66("div", { style: toneStyle(node.action.tone ?? "primary"), className: "mt-3 min-w-0", children: node.action.href && !locked ? /* @__PURE__ */ jsx66("a", { href: node.action.href, className: `inline-block rounded px-2 py-2 bg-[var(--c-roadmap-node-bg)] text-[var(--c-roadmap-node-fg)] [overflow-wrap:anywhere] ${focusClass}`, children: node.action.label }) : /* @__PURE__ */ jsx66("button", { type: "button", disabled: locked, className: `max-w-full rounded px-2 py-2 bg-[var(--c-roadmap-node-bg)] text-[var(--c-roadmap-node-fg)] [overflow-wrap:anywhere] ${focusClass}`, onClick: (e) => {
|
|
8774
|
+
e.stopPropagation();
|
|
8775
|
+
if (node.action?.actionId) onAction?.(node.action.actionId, node);
|
|
8776
|
+
}, children: node.action.label }) })
|
|
8777
|
+
] }) });
|
|
8778
|
+
}
|
|
8779
|
+
|
|
8780
|
+
// src/components/organisms/roadmap/RoadmapGroup.tsx
|
|
8781
|
+
import { Fragment as Fragment10, jsx as jsx67, jsxs as jsxs42 } from "react/jsx-runtime";
|
|
8782
|
+
function RoadmapGroupView({ group, testIdPrefix }) {
|
|
8783
|
+
return /* @__PURE__ */ jsx67(Fragment10, { children: groupColumnRuns(group).map((run, index) => /* @__PURE__ */ jsxs42(
|
|
8784
|
+
"div",
|
|
8785
|
+
{
|
|
8786
|
+
"data-testid": `${testIdPrefix}-group`,
|
|
8787
|
+
"data-group-id": group.id,
|
|
8788
|
+
style: { ...toneStyle(resolveGroupTone(group)), gridColumn: `${run.start} / span ${run.span}`, gridRow: `${group.from + 1} / span ${group.to - group.from + 1}` },
|
|
8789
|
+
className: "pointer-events-none relative z-0 min-w-0 self-stretch rounded-[var(--radius)] border-2 border-[var(--c-roadmap-border)] bg-[var(--c-roadmap-node-bg)] text-[var(--c-roadmap-node-fg)]",
|
|
8790
|
+
children: [
|
|
8791
|
+
index === 0 && group.title && /* @__PURE__ */ jsx67("span", { className: "absolute left-2 right-2 top-0 -translate-y-1/2 text-xs leading-normal", children: /* @__PURE__ */ jsx67("span", { className: "bg-[var(--c-roadmap-surface)] px-1 [overflow-wrap:anywhere]", children: group.title }) }),
|
|
8792
|
+
index === 0 && group.description && /* @__PURE__ */ jsx67("span", { className: "sr-only", children: group.description })
|
|
8793
|
+
]
|
|
8794
|
+
},
|
|
8795
|
+
run.start
|
|
8796
|
+
)) });
|
|
8797
|
+
}
|
|
8798
|
+
|
|
8799
|
+
// src/components/organisms/roadmap/Roadmap.tsx
|
|
8800
|
+
import { jsx as jsx68, jsxs as jsxs43 } from "react/jsx-runtime";
|
|
8801
|
+
function Roadmap({ document: document2, state, renderNode, onNodeClick, onAction, testIdPrefix = "roadmap", className = "", ariaLabel }) {
|
|
8802
|
+
const { placements } = useMemo5(() => placeNodes(document2), [document2]);
|
|
8803
|
+
const badges = useMemo5(() => new Map(document2.legend?.entries.map((entry) => [entry.id, entry])), [document2.legend]);
|
|
8804
|
+
const legendPlacement = document2.legend ? resolveLegendPlacement(document2.legend) : void 0;
|
|
8805
|
+
const legend = document2.legend && /* @__PURE__ */ jsx68(RoadmapLegendView, { legend: document2.legend, testIdPrefix });
|
|
8806
|
+
return /* @__PURE__ */ jsxs43("section", { "data-testid": testIdPrefix, "aria-label": ariaLabel ?? document2.title ?? "Roadmap", className: `min-w-0 bg-[var(--c-roadmap-surface)] p-3 text-[var(--c-roadmap-neutral-fg)] ${className}`, children: [
|
|
8807
|
+
legendPlacement === "top" && /* @__PURE__ */ jsx68("div", { className: "mb-6", children: legend }),
|
|
8808
|
+
/* @__PURE__ */ jsxs43("div", { "data-testid": `${testIdPrefix}-grid`, role: "list", "aria-label": "Roadmap nodes", className: "relative isolate grid min-w-0 grid-cols-3 items-center gap-x-3 gap-y-8 md:gap-x-8", children: [
|
|
8809
|
+
document2.groups.map((group) => /* @__PURE__ */ jsx68(RoadmapGroupView, { group, testIdPrefix }, group.id)),
|
|
8810
|
+
placements.map(({ node, row, column }) => {
|
|
8811
|
+
const resolvedState = resolveNodeState(node, state);
|
|
8812
|
+
return /* @__PURE__ */ jsx68(
|
|
8813
|
+
"div",
|
|
8814
|
+
{
|
|
8815
|
+
role: "listitem",
|
|
8816
|
+
"data-testid": `${testIdPrefix}-node`,
|
|
8817
|
+
"data-node-id": node.id,
|
|
8818
|
+
"data-state": resolvedState,
|
|
8819
|
+
style: { gridColumn: `${column.start} / span ${column.span}`, gridRow: `${row.start} / span 1` },
|
|
8820
|
+
className: "relative z-10 min-w-0 px-2 py-4",
|
|
8821
|
+
children: node.kind === "legend" ? legendPlacement === "inline" ? legend : null : renderNode ? renderNode(node, resolvedState) : /* @__PURE__ */ jsx68(RoadmapNodeView, { node, state: resolvedState, badge: node.badge ? badges.get(node.badge) : void 0, onNodeClick, onAction, testIdPrefix })
|
|
8822
|
+
},
|
|
8823
|
+
node.id
|
|
8824
|
+
);
|
|
8825
|
+
})
|
|
8826
|
+
] }),
|
|
8827
|
+
legendPlacement === "bottom" && /* @__PURE__ */ jsx68("div", { className: "mt-6", children: legend })
|
|
8828
|
+
] });
|
|
8829
|
+
}
|
|
8830
|
+
|
|
8719
8831
|
// src/hooks/use-iframe-auth.ts
|
|
8720
8832
|
import { useContext as useContext9 } from "react";
|
|
8721
8833
|
function useIframeAuth() {
|
|
@@ -8739,9 +8851,9 @@ function useIframeNavigate() {
|
|
|
8739
8851
|
import {
|
|
8740
8852
|
createContext as createContext10,
|
|
8741
8853
|
useContext as useContext10,
|
|
8742
|
-
useMemo as
|
|
8854
|
+
useMemo as useMemo6
|
|
8743
8855
|
} from "react";
|
|
8744
|
-
import { jsx as
|
|
8856
|
+
import { jsx as jsx69 } from "react/jsx-runtime";
|
|
8745
8857
|
var FeatureFlagContext = createContext10({
|
|
8746
8858
|
flags: {},
|
|
8747
8859
|
isEnabled: () => false
|
|
@@ -8750,14 +8862,14 @@ var FeatureFlagProvider = ({
|
|
|
8750
8862
|
children,
|
|
8751
8863
|
flags
|
|
8752
8864
|
}) => {
|
|
8753
|
-
const value =
|
|
8865
|
+
const value = useMemo6(
|
|
8754
8866
|
() => ({
|
|
8755
8867
|
flags,
|
|
8756
8868
|
isEnabled: (flag) => Boolean(flags[flag])
|
|
8757
8869
|
}),
|
|
8758
8870
|
[flags]
|
|
8759
8871
|
);
|
|
8760
|
-
return /* @__PURE__ */
|
|
8872
|
+
return /* @__PURE__ */ jsx69(FeatureFlagContext.Provider, { value, children });
|
|
8761
8873
|
};
|
|
8762
8874
|
var useFeatureFlag = (flag) => {
|
|
8763
8875
|
const { isEnabled } = useContext10(FeatureFlagContext);
|
|
@@ -8982,6 +9094,7 @@ export {
|
|
|
8982
9094
|
ResizableHandle,
|
|
8983
9095
|
ResizablePanel,
|
|
8984
9096
|
ResizablePanelGroup,
|
|
9097
|
+
Roadmap,
|
|
8985
9098
|
ScrollArea,
|
|
8986
9099
|
ScrollBar,
|
|
8987
9100
|
Select,
|
|
@@ -19,6 +19,33 @@
|
|
|
19
19
|
*/
|
|
20
20
|
|
|
21
21
|
@theme inline {
|
|
22
|
+
/* Origin: agent — Roadmap token mappings. */
|
|
23
|
+
--color-c-roadmap-surface: var(--c-roadmap-surface);
|
|
24
|
+
--color-c-roadmap-border: var(--c-roadmap-border);
|
|
25
|
+
--color-c-roadmap-focus: var(--c-roadmap-focus);
|
|
26
|
+
--color-c-roadmap-done-bg: var(--c-roadmap-done-bg);
|
|
27
|
+
--color-c-roadmap-done-fg: var(--c-roadmap-done-fg);
|
|
28
|
+
--color-c-roadmap-learning-bg: var(--c-roadmap-learning-bg);
|
|
29
|
+
--color-c-roadmap-learning-fg: var(--c-roadmap-learning-fg);
|
|
30
|
+
--color-c-roadmap-skipped-bg: var(--c-roadmap-skipped-bg);
|
|
31
|
+
--color-c-roadmap-skipped-fg: var(--c-roadmap-skipped-fg);
|
|
32
|
+
--color-c-roadmap-primary-bg: var(--c-roadmap-primary-bg);
|
|
33
|
+
--color-c-roadmap-primary-fg: var(--c-roadmap-primary-fg);
|
|
34
|
+
--color-c-roadmap-secondary-bg: var(--c-roadmap-secondary-bg);
|
|
35
|
+
--color-c-roadmap-secondary-fg: var(--c-roadmap-secondary-fg);
|
|
36
|
+
--color-c-roadmap-accent-bg: var(--c-roadmap-accent-bg);
|
|
37
|
+
--color-c-roadmap-accent-fg: var(--c-roadmap-accent-fg);
|
|
38
|
+
--color-c-roadmap-muted-bg: var(--c-roadmap-muted-bg);
|
|
39
|
+
--color-c-roadmap-muted-fg: var(--c-roadmap-muted-fg);
|
|
40
|
+
--color-c-roadmap-neutral-bg: var(--c-roadmap-neutral-bg);
|
|
41
|
+
--color-c-roadmap-neutral-fg: var(--c-roadmap-neutral-fg);
|
|
42
|
+
--color-c-roadmap-success-bg: var(--c-roadmap-success-bg);
|
|
43
|
+
--color-c-roadmap-success-fg: var(--c-roadmap-success-fg);
|
|
44
|
+
--color-c-roadmap-info-bg: var(--c-roadmap-info-bg);
|
|
45
|
+
--color-c-roadmap-info-fg: var(--c-roadmap-info-fg);
|
|
46
|
+
--color-c-roadmap-danger-bg: var(--c-roadmap-danger-bg);
|
|
47
|
+
--color-c-roadmap-danger-fg: var(--c-roadmap-danger-fg);
|
|
48
|
+
|
|
22
49
|
/* ─── Colours ──────────────────────────────────────────────────────────── */
|
|
23
50
|
--color-background: var(--background);
|
|
24
51
|
--color-foreground: var(--foreground);
|
package/dist/styles/tokens.css
CHANGED
|
@@ -1706,3 +1706,32 @@
|
|
|
1706
1706
|
box-shadow: var(--c-appshell-focus-ring);
|
|
1707
1707
|
transition: none;
|
|
1708
1708
|
}
|
|
1709
|
+
|
|
1710
|
+
/* Origin: agent — Roadmap. Q1: dark default and dark only. */
|
|
1711
|
+
:root {
|
|
1712
|
+
--c-roadmap-surface: var(--s-surface-page);
|
|
1713
|
+
--c-roadmap-border: var(--s-border-strong);
|
|
1714
|
+
--c-roadmap-focus: var(--s-border-focus);
|
|
1715
|
+
--c-roadmap-done-bg: var(--s-surface-raised);
|
|
1716
|
+
--c-roadmap-done-fg: var(--s-ink-secondary);
|
|
1717
|
+
--c-roadmap-learning-bg: var(--s-info-subtle);
|
|
1718
|
+
--c-roadmap-learning-fg: var(--s-info-fg);
|
|
1719
|
+
--c-roadmap-skipped-bg: var(--s-surface-elevated);
|
|
1720
|
+
--c-roadmap-skipped-fg: var(--s-ink-muted);
|
|
1721
|
+
--c-roadmap-primary-bg: var(--s-brand-solid);
|
|
1722
|
+
--c-roadmap-primary-fg: var(--s-ink-inverse);
|
|
1723
|
+
--c-roadmap-secondary-bg: var(--s-brand-subtle);
|
|
1724
|
+
--c-roadmap-secondary-fg: var(--s-ink-primary);
|
|
1725
|
+
--c-roadmap-accent-bg: var(--s-ink-primary);
|
|
1726
|
+
--c-roadmap-accent-fg: var(--s-ink-inverse);
|
|
1727
|
+
--c-roadmap-muted-bg: var(--s-surface-raised);
|
|
1728
|
+
--c-roadmap-muted-fg: var(--s-ink-muted);
|
|
1729
|
+
--c-roadmap-neutral-bg: var(--s-surface-panel);
|
|
1730
|
+
--c-roadmap-neutral-fg: var(--s-ink-primary);
|
|
1731
|
+
--c-roadmap-success-bg: var(--s-success-subtle);
|
|
1732
|
+
--c-roadmap-success-fg: var(--s-success-fg);
|
|
1733
|
+
--c-roadmap-info-bg: var(--s-info-subtle);
|
|
1734
|
+
--c-roadmap-info-fg: var(--s-info-fg);
|
|
1735
|
+
--c-roadmap-danger-bg: var(--s-danger-subtle);
|
|
1736
|
+
--c-roadmap-danger-fg: var(--s-danger-fg);
|
|
1737
|
+
}
|