Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions .changeset/kumo-fixes-for-matt.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
"@cloudflare/kumo": minor
"@cloudflare/kumo-docs-astro": minor
---

fix(cli): resolve broken doc/docs/ls commands by fixing registry path from catalog/ to ai/
fix(dialog): wrap sub-components to isolate @base-ui/react type references from downstream consumers
fix(label): render as `<label>` element with htmlFor support instead of `<span>`
feat(input): add Textarea alias for InputArea
feat(toast): add ToastProvider alias for Toasty
feat(button): require aria-label on icon-only buttons (shape="square" | "circle") via discriminated union
fix(docs): add Tailwind 4 @source directive to usage example, add confirmation dialog recipe, update Select basic example, document icon-only button aria-label pattern
16 changes: 14 additions & 2 deletions packages/kumo-docs-astro/astro.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { resolve } from "path";
import { fileURLToPath } from "url";
import { kumoColorsPlugin } from "./src/lib/vite-plugin-kumo-colors.js";
import { kumoRegistryPlugin } from "./src/lib/vite-plugin-kumo-registry.js";
import { kumoHmrPlugin } from "./src/lib/vite-plugin-kumo-hmr.js";

const __dirname = fileURLToPath(new URL(".", import.meta.url));

Expand Down Expand Up @@ -58,12 +59,23 @@ function getBuildInfo() {

const buildInfo = getBuildInfo();

// Detect dev mode: `astro dev` sets this in process.argv
const isDev = process.argv.includes("dev");

// https://astro.build/config
export default defineConfig({
integrations: [react()],
vite: {
// @ts-expect-error - Vite version mismatch between Astro and @tailwindcss/vite
plugins: [tailwindcss(), kumoColorsPlugin(), kumoRegistryPlugin()],
plugins: [
// @ts-expect-error - Vite version mismatch between Astro and @tailwindcss/vite
tailwindcss(),
kumoColorsPlugin(),
kumoRegistryPlugin(),
// In dev mode, resolve @cloudflare/kumo imports to raw source files
// for instant HMR. In production builds, the normal package.json
// exports (dist/) are used — preserving the real consumer experience.
...(isDev ? [kumoHmrPlugin()] : []),
],

define: {
__KUMO_VERSION__: JSON.stringify(buildInfo.kumoVersion),
Expand Down
21 changes: 18 additions & 3 deletions packages/kumo-docs-astro/src/components/demos/ButtonDemo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,12 @@ export function ButtonBasicDemo() {
return (
<div className="flex flex-wrap items-center gap-2">
<Button variant="secondary">Button</Button>
<Button variant="secondary" shape="square" icon={PlusIcon} />
<Button
variant="secondary"
shape="square"
icon={PlusIcon}
aria-label="Add"
/>
</div>
);
}
Expand Down Expand Up @@ -64,8 +69,18 @@ export function ButtonWithIconDemo() {
export function ButtonIconOnlyDemo() {
return (
<div className="flex flex-wrap items-center gap-3">
<Button variant="secondary" shape="square" icon={PlusIcon} />
<Button variant="secondary" shape="circle" icon={PlusIcon} />
<Button
variant="secondary"
shape="square"
icon={PlusIcon}
aria-label="Add item"
/>
<Button
variant="secondary"
shape="circle"
icon={PlusIcon}
aria-label="Add item"
/>
</div>
);
}
Expand Down
48 changes: 47 additions & 1 deletion packages/kumo-docs-astro/src/components/demos/DialogDemo.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Dialog, Button } from "@cloudflare/kumo";
import { X } from "@phosphor-icons/react";
import { Warning, X } from "@phosphor-icons/react";

export function DialogBasicDemo() {
return (
Expand All @@ -18,6 +18,7 @@ export function DialogBasicDemo() {
variant="secondary"
shape="square"
icon={<X />}
aria-label="Close"
/>
)}
/>
Expand Down Expand Up @@ -48,6 +49,7 @@ export function DialogWithActionsDemo() {
variant="secondary"
shape="square"
icon={<X />}
aria-label="Close"
/>
)}
/>
Expand Down Expand Up @@ -76,3 +78,47 @@ export function DialogWithActionsDemo() {
</Dialog.Root>
);
}

export function DialogConfirmationDemo() {
return (
<Dialog.Root disablePointerDismissal>
<Dialog.Trigger
render={(p) => (
<Button {...p} variant="destructive">
Delete Project
</Button>
)}
/>
<Dialog className="p-8">
<div className="mb-4 flex items-center gap-3">
<div className="flex h-10 w-10 items-center justify-center rounded-full bg-kumo-danger/20">
<Warning size={20} className="text-kumo-danger" />
</div>
<Dialog.Title className="text-xl font-semibold">
Delete Project?
</Dialog.Title>
</div>
<Dialog.Description className="text-kumo-subtle">
This action cannot be undone. This will permanently delete the project
and all associated data.
</Dialog.Description>
<div className="mt-8 flex justify-end gap-2">
<Dialog.Close
render={(props) => (
<Button variant="secondary" {...props}>
Cancel
</Button>
)}
/>
<Dialog.Close
render={(props) => (
<Button variant="destructive" {...props}>
Delete
</Button>
)}
/>
</div>
</Dialog>
</Dialog.Root>
);
}
8 changes: 6 additions & 2 deletions packages/kumo-docs-astro/src/components/demos/HomeGrid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -230,10 +230,14 @@ export function HomeGrid() {
<TooltipProvider>
<div className="flex gap-2">
<Tooltip content="Add" asChild open>
<Button shape="square" icon={PlusIcon} />
<Button shape="square" icon={PlusIcon} aria-label="Add" />
</Tooltip>
<Tooltip content="Change language" asChild>
<Button shape="square" icon={TranslateIcon} />
<Button
shape="square"
icon={TranslateIcon}
aria-label="Change language"
/>
</Tooltip>
</div>
</TooltipProvider>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,12 @@ export function LayerCardDemo() {
<LayerCard>
<LayerCard.Secondary className="flex items-center justify-between">
<div>Next Steps</div>
<Button variant="ghost" size="sm" shape="square">
<Button
variant="ghost"
size="sm"
shape="square"
aria-label="Go to next steps"
>
<ArrowRightIcon size={16} />
</Button>
</LayerCard.Secondary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ export function PopoverHeroDemo() {
return (
<Popover>
<Popover.Trigger asChild>
<Button shape="square" icon={BellIcon} />
<Button shape="square" icon={BellIcon} aria-label="Notifications" />
</Popover.Trigger>
<Popover.Content>
<Popover.Title>Notifications</Popover.Title>
Expand Down
12 changes: 6 additions & 6 deletions packages/kumo-docs-astro/src/components/demos/SelectDemo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,18 @@ import { useState, useEffect } from "react";
import { Select, Text } from "@cloudflare/kumo";

export function SelectBasicDemo() {
const [value, setValue] = useState("Apple");
const [value, setValue] = useState("apple");

return (
<Select
className="w-[200px]"
value={value}
onValueChange={(v) => setValue(v ?? "Apple")}
placeholder="Please select"
onValueChange={(v) => setValue(v ?? "apple")}
items={{ apple: "Apple", banana: "Banana", cherry: "Cherry" }}
>
<Select.Option value="Apple">Apple</Select.Option>
<Select.Option value="Banana">Banana</Select.Option>
<Select.Option value="Cherry">Cherry</Select.Option>
<Select.Option value="apple">Apple</Select.Option>
<Select.Option value="banana">Banana</Select.Option>
<Select.Option value="cherry">Cherry</Select.Option>
</Select>
);
}
Expand Down
12 changes: 8 additions & 4 deletions packages/kumo-docs-astro/src/components/demos/TooltipDemo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ export function TooltipHeroDemo() {
return (
<TooltipProvider>
<Tooltip content="Add new item" asChild>
<Button shape="square" icon={PlusIcon} />
<Button shape="square" icon={PlusIcon} aria-label="Add new item" />
</Tooltip>
</TooltipProvider>
);
Expand All @@ -15,7 +15,7 @@ export function TooltipBasicDemo() {
return (
<TooltipProvider>
<Tooltip content="Add" asChild>
<Button shape="square" icon={PlusIcon} />
<Button shape="square" icon={PlusIcon} aria-label="Add" />
</Tooltip>
</TooltipProvider>
);
Expand All @@ -26,10 +26,14 @@ export function TooltipMultipleDemo() {
<TooltipProvider>
<div className="flex gap-2">
<Tooltip content="Add" asChild>
<Button shape="square" icon={PlusIcon} />
<Button shape="square" icon={PlusIcon} aria-label="Add" />
</Tooltip>
<Tooltip content="Change language" asChild>
<Button shape="square" icon={TranslateIcon} />
<Button
shape="square"
icon={TranslateIcon}
aria-label="Change language"
/>
</Tooltip>
</div>
</TooltipProvider>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ export const kumoColors = ${JSON.stringify(colors, null, 2)};
};
moduleGraph: {
getModuleById: (id: string) => unknown;
invalidateModule: (mod: unknown) => void;
invalidateModule: (mod: any) => void;
};
ws: { send: (message: { type: string }) => void };
}) {
Expand Down
118 changes: 118 additions & 0 deletions packages/kumo-docs-astro/src/lib/vite-plugin-kumo-hmr.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
import { resolve, dirname } from "node:path";
import { fileURLToPath } from "node:url";

const __dirname = dirname(fileURLToPath(import.meta.url));

// Resolve once — points at the sibling kumo package root
const kumoRoot = resolve(__dirname, "../../../kumo");
const kumoSrc = resolve(kumoRoot, "src");

/**
* Map every `@cloudflare/kumo` sub-path export to its source equivalent.
*
* In dev mode Vite will resolve these to the raw .ts/.tsx source files,
* which means file-watcher-based HMR works instantly — no rebuild of
* the kumo package required.
*
* In production builds (astro build) this plugin is NOT loaded, so the
* normal package.json `exports` field is used (dist/), which validates
* the real consumer experience.
*/
const aliases: Record<string, string> = {
// Main barrel — resolves to source index.ts
"@cloudflare/kumo": resolve(kumoSrc, "index.ts"),

// CSS styles — resolve to source CSS
"@cloudflare/kumo/styles/tailwind": resolve(kumoSrc, "styles/kumo.css"),
"@cloudflare/kumo/styles/standalone": resolve(
kumoSrc,
"styles/kumo-standalone.css",
),
"@cloudflare/kumo/styles": resolve(kumoSrc, "styles/kumo.css"),

// JSON registry — these live outside src/ and are NOT built, so same
// path works in dev and prod. We alias anyway so Vite can resolve
// the workspace:* link correctly and watch the file.
"@cloudflare/kumo/ai/component-registry.json": resolve(
kumoRoot,
"ai/component-registry.json",
),
};

/**
* Vite plugin that rewires `@cloudflare/kumo` imports to the raw source
* files of the sibling package during `astro dev`.
*
* **Why not just use `resolve.alias`?**
* `resolve.alias` is a simple prefix match — it can't distinguish
* `@cloudflare/kumo` from `@cloudflare/kumo-figma` without a trailing
* slash, and it can't handle the overlapping sub-path exports cleanly.
* A plugin gives us exact-match control.
*/
export function kumoHmrPlugin() {
return {
name: "vite-plugin-kumo-hmr",
enforce: "pre" as const,

resolveId(source: string) {
// Exact match first (most imports)
if (aliases[source]) {
return aliases[source];
}

// Sub-path component imports: @cloudflare/kumo/components/button
// → packages/kumo/src/components/button/index.ts
if (source.startsWith("@cloudflare/kumo/components/")) {
const componentName = source.replace(
"@cloudflare/kumo/components/",
"",
);
return resolve(kumoSrc, `components/${componentName}/index.ts`);
}

// Primitives: @cloudflare/kumo/primitives/dialog
// → packages/kumo/src/primitives/dialog.ts
if (source.startsWith("@cloudflare/kumo/primitives/")) {
const primitiveName = source.replace(
"@cloudflare/kumo/primitives/",
"",
);
return resolve(kumoSrc, `primitives/${primitiveName}.ts`);
}
if (source === "@cloudflare/kumo/primitives") {
return resolve(kumoSrc, "primitives/index.ts");
}

// Utils barrel
if (source === "@cloudflare/kumo/utils") {
return resolve(kumoSrc, "utils/index.ts");
}

// Catalog barrel
if (source === "@cloudflare/kumo/catalog") {
return resolve(kumoSrc, "catalog/index.ts");
}

// Registry barrel
if (source === "@cloudflare/kumo/registry") {
return resolve(kumoSrc, "registry/index.ts");
}

// Catch-all for any other @cloudflare/kumo/styles/* CSS imports
if (source.startsWith("@cloudflare/kumo/styles/")) {
const styleName = source.replace("@cloudflare/kumo/styles/", "");
return resolve(kumoSrc, `styles/${styleName}.css`);
}

return undefined;
},

configResolved(config: { server: { fs: { allow: string[] } } }) {
// Append kumo source to the existing allow list rather than replacing it.
// Using config() would shallow-merge and override Astro/Vite defaults.
if (config.server?.fs?.allow) {
config.server.fs.allow.push(kumoRoot);
}
},
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ export const kumoRegistryJson = ${json};
};
moduleGraph: {
getModuleById: (id: string) => unknown;
invalidateModule: (mod: unknown) => void;
invalidateModule: (mod: any) => void;
};
ws: { send: (message: { type: string }) => void };
}) {
Expand Down
Loading
Loading