feat(ui): expose grouped component entrypoints
This commit is contained in:
parent
cb446e2a6e
commit
6a0c57e93c
7 changed files with 105 additions and 0 deletions
20
package.json
20
package.json
|
|
@ -10,6 +10,26 @@
|
||||||
"development": "./src/index.ts",
|
"development": "./src/index.ts",
|
||||||
"default": "./dist/index.js"
|
"default": "./dist/index.js"
|
||||||
},
|
},
|
||||||
|
"./foundation": {
|
||||||
|
"types": "./dist/components/foundation/index.d.ts",
|
||||||
|
"development": "./src/components/foundation/index.ts",
|
||||||
|
"default": "./dist/components/foundation/index.js"
|
||||||
|
},
|
||||||
|
"./frames": {
|
||||||
|
"types": "./dist/components/frames/index.d.ts",
|
||||||
|
"development": "./src/components/frames/index.ts",
|
||||||
|
"default": "./dist/components/frames/index.js"
|
||||||
|
},
|
||||||
|
"./operations": {
|
||||||
|
"types": "./dist/components/operations/index.d.ts",
|
||||||
|
"development": "./src/components/operations/index.ts",
|
||||||
|
"default": "./dist/components/operations/index.js"
|
||||||
|
},
|
||||||
|
"./telemetry": {
|
||||||
|
"types": "./dist/components/telemetry/index.d.ts",
|
||||||
|
"development": "./src/components/telemetry/index.ts",
|
||||||
|
"default": "./dist/components/telemetry/index.js"
|
||||||
|
},
|
||||||
"./styles.css": {
|
"./styles.css": {
|
||||||
"development": "./src/styles.css",
|
"development": "./src/styles.css",
|
||||||
"default": "./dist/styles.css"
|
"default": "./dist/styles.css"
|
||||||
|
|
|
||||||
8
src/components/foundation/index.ts
Normal file
8
src/components/foundation/index.ts
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
export { Badge } from "./Badge";
|
||||||
|
export { Button } from "./Button";
|
||||||
|
export { IconButton } from "./IconButton";
|
||||||
|
export { IconGlyph } from "./IconGlyph";
|
||||||
|
export { ProgressMeter } from "./ProgressMeter";
|
||||||
|
export { Separator } from "./Separator";
|
||||||
|
export { StatusBadge } from "./StatusBadge";
|
||||||
|
export { ThemeToggle } from "./ThemeToggle";
|
||||||
10
src/components/frames/index.ts
Normal file
10
src/components/frames/index.ts
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
export { CornerBracketFrame } from "./CornerBracketFrame";
|
||||||
|
export { DashboardFrame } from "./DashboardFrame";
|
||||||
|
export { DashboardHeader } from "./DashboardHeader";
|
||||||
|
export { DiagonalStripeField } from "./DiagonalStripeField";
|
||||||
|
export { FooterCell } from "./FooterCell";
|
||||||
|
export { FooterStatusCell } from "./FooterStatusCell";
|
||||||
|
export { GridFrame } from "./GridFrame";
|
||||||
|
export { ModuleCard } from "./ModuleCard";
|
||||||
|
export { Panel } from "./Panel";
|
||||||
|
export { ScanlineField } from "./ScanlineField";
|
||||||
6
src/components/operations/index.ts
Normal file
6
src/components/operations/index.ts
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
export { ServiceGroupPanel } from "./ServiceGroupPanel";
|
||||||
|
export { ServicePanel } from "./ServicePanel";
|
||||||
|
export { ServiceRow } from "./ServiceRow";
|
||||||
|
export { StatusStrip } from "./StatusStrip";
|
||||||
|
export { SystemState } from "./SystemState";
|
||||||
|
export { WeatherModule } from "./WeatherModule";
|
||||||
6
src/components/telemetry/index.ts
Normal file
6
src/components/telemetry/index.ts
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
export { LineChart } from "./LineChart";
|
||||||
|
export { SignalTrace } from "./SignalTrace";
|
||||||
|
export { Sparkline } from "./Sparkline";
|
||||||
|
export { TelemetryCard } from "./TelemetryCard";
|
||||||
|
export { TelemetryGrid } from "./TelemetryGrid";
|
||||||
|
export { TelemetryStrip } from "./TelemetryStrip";
|
||||||
|
|
@ -1,3 +1,7 @@
|
||||||
|
export * from "./components/foundation";
|
||||||
|
export * from "./components/frames";
|
||||||
|
export * from "./components/operations";
|
||||||
|
export * from "./components/telemetry";
|
||||||
export { Badge } from "./components/foundation/Badge";
|
export { Badge } from "./components/foundation/Badge";
|
||||||
export { Button } from "./components/foundation/Button";
|
export { Button } from "./components/foundation/Button";
|
||||||
export { IconGlyph } from "./components/foundation/IconGlyph";
|
export { IconGlyph } from "./components/foundation/IconGlyph";
|
||||||
|
|
|
||||||
|
|
@ -100,6 +100,43 @@ describe("Storybook inventory", () => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("exposes grouped package entrypoints for each component domain", () => {
|
||||||
|
const packageJson = JSON.parse(readFileSync(join(packageRoot, "package.json"), "utf8")) as {
|
||||||
|
exports?: Record<string, WorkspacePackageExport>;
|
||||||
|
};
|
||||||
|
const rootIndexSource = readFileSync(join(packageRoot, "src/index.ts"), "utf8");
|
||||||
|
const componentsByDomain = new Map<(typeof allowedComponentDomains)[number], string[]>();
|
||||||
|
|
||||||
|
for (const domain of allowedComponentDomains) {
|
||||||
|
componentsByDomain.set(domain, []);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const component of componentInventory()) {
|
||||||
|
componentsByDomain.get(component.domain)?.push(component.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const domain of allowedComponentDomains) {
|
||||||
|
const domainIndexPath = join(componentsDir, domain, "index.ts");
|
||||||
|
const domainIndexSource = existsSync(domainIndexPath)
|
||||||
|
? readFileSync(domainIndexPath, "utf8")
|
||||||
|
: "";
|
||||||
|
|
||||||
|
expect(existsSync(domainIndexPath), `${domain} index is missing`).toBe(true);
|
||||||
|
expect(rootIndexSource).toContain(`export * from "./components/${domain}";`);
|
||||||
|
expect(packageJson.exports?.[`./${domain}`]).toMatchObject({
|
||||||
|
types: `./dist/components/${domain}/index.d.ts`,
|
||||||
|
development: `./src/components/${domain}/index.ts`,
|
||||||
|
default: `./dist/components/${domain}/index.js`,
|
||||||
|
});
|
||||||
|
|
||||||
|
for (const componentName of componentsByDomain.get(domain) ?? []) {
|
||||||
|
expect(domainIndexSource).toContain(
|
||||||
|
`export { ${componentName} } from "./${componentName}";`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
test("keeps Storybook fixtures generic and content-free", () => {
|
test("keeps Storybook fixtures generic and content-free", () => {
|
||||||
const storyText = readdirSync(storiesDir)
|
const storyText = readdirSync(storiesDir)
|
||||||
.filter((filename) => filename.endsWith(".tsx") || filename.endsWith(".ts"))
|
.filter((filename) => filename.endsWith(".tsx") || filename.endsWith(".ts"))
|
||||||
|
|
@ -174,12 +211,21 @@ function requiredComponentPath(component: string): string {
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ComponentInventoryItem {
|
interface ComponentInventoryItem {
|
||||||
|
domain: (typeof allowedComponentDomains)[number];
|
||||||
name: string;
|
name: string;
|
||||||
path: string;
|
path: string;
|
||||||
relativeExportPath: string;
|
relativeExportPath: string;
|
||||||
storyFile: string;
|
storyFile: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type WorkspacePackageExport =
|
||||||
|
| string
|
||||||
|
| {
|
||||||
|
types?: string;
|
||||||
|
development?: string;
|
||||||
|
default?: string;
|
||||||
|
};
|
||||||
|
|
||||||
function componentInventory(): ComponentInventoryItem[] {
|
function componentInventory(): ComponentInventoryItem[] {
|
||||||
const components = allowedComponentDomains
|
const components = allowedComponentDomains
|
||||||
.flatMap((domain) => collectComponentFiles(join(componentsDir, domain)))
|
.flatMap((domain) => collectComponentFiles(join(componentsDir, domain)))
|
||||||
|
|
@ -208,12 +254,17 @@ function collectComponentFiles(directory: string): ComponentInventoryItem[] {
|
||||||
}
|
}
|
||||||
|
|
||||||
const name = basename(entry.name, ".tsx");
|
const name = basename(entry.name, ".tsx");
|
||||||
|
const relativeComponentPath = relative(componentsDir, entryPath).replace(/\\/g, "/");
|
||||||
|
const domain = relativeComponentPath.split(
|
||||||
|
"/",
|
||||||
|
)[0] as (typeof allowedComponentDomains)[number];
|
||||||
const relativeExportPath = `./${relative(join(packageRoot, "src"), entryPath)
|
const relativeExportPath = `./${relative(join(packageRoot, "src"), entryPath)
|
||||||
.replace(/\\/g, "/")
|
.replace(/\\/g, "/")
|
||||||
.replace(/\.tsx$/, "")}`;
|
.replace(/\.tsx$/, "")}`;
|
||||||
|
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
|
domain,
|
||||||
name,
|
name,
|
||||||
path: entryPath,
|
path: entryPath,
|
||||||
relativeExportPath,
|
relativeExportPath,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue