Skip to content
Draft
Show file tree
Hide file tree
Changes from 8 commits
Commits
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
6 changes: 6 additions & 0 deletions .changeset/evil-drinks-sink.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@seed-design/react": patch
"@seed-design/css": patch
---

`ActionButton`에서 `overrides` prop을 통해 배경 색상을 오버라이드할 수 있도록 합니다.
1 change: 1 addition & 0 deletions bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

26 changes: 26 additions & 0 deletions docs/components/example/action-button-overriding.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { ActionButton } from "seed-design/ui/action-button";
import { vars } from "@seed-design/css/vars";
import { HStack } from "@seed-design/react";

export default function ActionButtonOverriding() {
return (
<HStack gap="x3">
<ActionButton
overrides={{
"--seed-action-button-enabled-background": vars.$color.bg.informativeSolid,
"--seed-action-button-active-background": vars.$color.bg.informativeSolidPressed,
}}
>
라벨
</ActionButton>
<ActionButton
overrides={{
"--seed-action-button-enabled-background": `linear-gradient(135deg, ${vars.$color.palette.purple400} 0%, ${vars.$color.palette.purple800} 100%)`,
"--seed-action-button-active-background": `linear-gradient(135deg, ${vars.$color.palette.purple500} 0%, ${vars.$color.palette.purple900} 100%)`,
}}
>
라벨
</ActionButton>
</HStack>
);
}
51 changes: 51 additions & 0 deletions docs/components/type-table/get-union-literals.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { Project } from "ts-morph";
import * as path from "node:path";

export interface UnionLiteralTableProps {
path: string;
name: string;
}

export interface UnionLiteralResult {
name: string;
literals: string[];
}

const project = new Project({ skipAddingFilesFromTsConfig: true });

export async function getUnionLiterals({
path: filePath,
name,
}: UnionLiteralTableProps): Promise<UnionLiteralResult> {
const resolvedPath = resolveTypePath(filePath);
const sourceFile = project.addSourceFileAtPath(resolvedPath);

const typeAlias = sourceFile.getTypeAlias(name);

if (!typeAlias) throw new Error(`Type "${name}" not found in ${filePath}`);

const type = typeAlias.getType();
if (!type) throw new Error(`Type "${name}" not found in ${filePath}`);

const literals = (type.isUnion() ? type.getUnionTypes() : [type])
.map((t) => t.getText())
.filter((v): v is string => !!v);

return { name, literals };
}

// TODO: do this better with require.resolve or something
// import.meta.resolve will work but not currently supported in Next.js
function resolveTypePath(filePath: string): string {
if (filePath.startsWith("@seed-design/")) {
const packagePath = filePath.replace("@seed-design/", "");

return path.join(process.cwd(), "../packages", `${packagePath}.d.ts`);
}

if (filePath.startsWith("./") || filePath.startsWith("../")) {
return path.resolve(process.cwd(), filePath);
}

return filePath;
}
1 change: 0 additions & 1 deletion docs/components/type-table/react-type-table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@ async function renderMarkdown(md: string): Promise<React.ReactElement> {
Fragment: runtime.Fragment,
jsx: runtime.jsx as Jsx,
jsxs: runtime.jsxs as Jsx,
// @ts-ignore
components: { ...defaultMdxComponents, img: undefined },
}) as React.ReactElement;
}
5 changes: 3 additions & 2 deletions docs/components/type-table/remark-react-type-table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import type { MdxJsxAttribute, MdxJsxFlowElement } from "mdast-util-mdx-jsx";
import { dirname } from "node:path";
import { print } from "recast";
import type { Transformer } from "unified";
import { visit } from "unist-util-visit";
import { visit, SKIP } from "unist-util-visit";
import { getReactTypeTableOutput, type ReactTypeTableProps } from "./get-react-type-table";

function expressionToAttribute(key: string, value: Expression): MdxJsxAttribute {
Expand Down Expand Up @@ -179,7 +179,8 @@ export function remarkReactTypeTable({
}

queue.push(run());
return "skip";

return SKIP;
});

await Promise.all(queue);
Expand Down
85 changes: 85 additions & 0 deletions docs/components/type-table/remark-union-literal-table.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import type { Root } from "mdast";
import type { Transformer } from "unified";
import { visit, SKIP } from "unist-util-visit";
import { getUnionLiterals } from "./get-union-literals";

export interface RemarkUnionLiteralTableOptions {
/**
* @defaultValue 'union-literal-table'
*/
name?: string;
}

/**
* Compile `union-literal-table` into a simple table at build time
*/
export function remarkUnionLiteralTable({
name = "union-literal-table",
}: RemarkUnionLiteralTableOptions = {}): Transformer<Root, Root> {
return async (tree) => {
const queue: Promise<void>[] = [];

visit(tree, "mdxJsxFlowElement", (node) => {
if (node.name !== name) return;

const props: Record<string, string> = {};

for (const attr of node.attributes) {
if (attr.type !== "mdxJsxAttribute" || typeof attr.value !== "string")
throw new Error("`union-literal-table` does not support non-string attributes");

props[attr.name] = attr.value;
}

async function run() {
const result = await getUnionLiterals({
path: props.path,
name: props.name,
});

// Create a proper markdown table AST structure
const tableNode = {
type: "table",
align: ["left"],
children: [
{
type: "tableRow",
children: [
{
type: "tableCell",
children: [
{
type: "text",
value: "Possible Values",
},
],
},
],
},
...result.literals.map((literal) => ({
type: "tableRow",
children: [
{
type: "tableCell",
children: [
{
type: "inlineCode",
value: literal,
},
],
},
],
})),
],
};

Object.assign(node, tableNode);
}

queue.push(run());
return SKIP;
});

await Promise.all(queue);
};
}
17 changes: 17 additions & 0 deletions docs/content/react/components/action-button.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -173,3 +173,20 @@ Ghost variant를 시각적으로 정렬해야 할 때 유용합니다.
}
```
</ComponentExample>

### Overriding CSS Variables

<ComponentExample name="action-button-overriding">
```json doc-gen:file
{
"file": "./components/example/action-button-overriding.tsx",
"codeblock": true
}
```
</ComponentExample>

#### Overridable CSS Variables

`overrides` prop을 통해 오버라이드할 수 있는 CSS 변수 목록입니다.

<union-literal-table path="@seed-design/css/recipes/action-button" name="ActionButtonOverridableVariable" />
3 changes: 2 additions & 1 deletion docs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,8 @@
"sanity": "3.99.0",
"shiki": "^3.4.2",
"simple-reveal": "^0.8.0",
"styled-components": "6"
"styled-components": "6",
"ts-morph": "^27.0.0"
},
"devDependencies": {
"@chromatic-com/storybook": "^4.0.1",
Expand Down
2 changes: 2 additions & 0 deletions docs/source.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { remarkNpm } from "fumadocs-core/mdx-plugins";
import { defineConfig, defineDocs, frontmatterSchema } from "fumadocs-mdx/config";
import { typeTableGenerator } from "./components/type-table/generator";
import { remarkReactTypeTable } from "./components/type-table/remark-react-type-table";
import { remarkUnionLiteralTable } from "./components/type-table/remark-union-literal-table";
import z from "zod";

export const docs = defineDocs({
Expand Down Expand Up @@ -49,6 +50,7 @@ export default defineConfig({
],
[remarkDocGen, { generators: [fileGenerator()] }],
[remarkReactTypeTable, { generator: typeTableGenerator }],
remarkUnionLiteralTable,
],
rehypeCodeOptions: {
lazy: true,
Expand Down
28 changes: 24 additions & 4 deletions ecosystem/qvism/core/src/dts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ export function generateRecipeDts(definition: RecipeDefinition<RecipeVariantReco
definition.defaultVariants,
);

return outdent`
const base = outdent`
declare interface ${capitalizedName}Variant {
${variantInterface}
}
Expand All @@ -81,7 +81,17 @@ export function generateRecipeDts(definition: RecipeDefinition<RecipeVariantReco
props: T,
) => [${capitalizedName}VariantProps, Omit<T, keyof ${capitalizedName}VariantProps>];
}
`;
`;

if (!definition.overridableVariables || definition.overridableVariables.length === 0) {
return base;
}

return outdent`${base}
export declare type ${capitalizedName}OverridableVariable = ${definition.overridableVariables
.map(stringLiteralType)
.join(" | ")};
`;
}

export function generateSlotRecipeDts(
Expand All @@ -95,7 +105,7 @@ export function generateSlotRecipeDts(
);
const slotNameType = definition.slots.map((slot) => `"${slot}"`).join(" | ");

return outdent`
const base = outdent`
declare interface ${capitalizedName}Variant {
${variantInterface}
}
Expand All @@ -117,7 +127,17 @@ export function generateSlotRecipeDts(
props: T,
) => [${capitalizedName}VariantProps, Omit<T, keyof ${capitalizedName}VariantProps>];
}
`;
`;

if (!definition.overridableVariables || definition.overridableVariables.length === 0) {
return base;
}

return outdent`${base}
export declare type ${capitalizedName}OverridableVariable = ${definition.overridableVariables
.map(stringLiteralType)
.join(" | ")};
`;
}

export function generateDts(definition: RecipeKindDefinition): string {
Expand Down
2 changes: 2 additions & 0 deletions ecosystem/qvism/core/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ export type RecipeCompoundVariant<T> = T & {

export interface RecipeDefinition<T extends RecipeVariantRecord = RecipeVariantRecord> {
name: string;
overridableVariables?: CssVarKey[];
base: StyleObject;
variants: T;
compoundVariants?: Pretty<RecipeCompoundVariant<RecipeCompoundSelection<T>>>[];
Expand All @@ -113,6 +114,7 @@ export interface SlotRecipeDefinition<
T extends SlotRecipeVariantRecord<S> = SlotRecipeVariantRecord<S>,
> {
name: string;
overridableVariables?: CssVarKey[];
slots: S[] | Readonly<S[]>;
base: SlotRecord<S, StyleObject>;
variants: T;
Expand Down
Loading