├── bunfig.toml ├── .husky ├── pre-commit └── commit-msg ├── .lintstagedrc ├── src ├── lib │ ├── types │ │ ├── storybook │ │ │ ├── index.ts │ │ │ └── Tags.enum.ts │ │ ├── index.ts │ │ ├── Nullable.type.ts │ │ └── AssignJSXStyleProps.type.ts │ ├── theme │ │ ├── presets │ │ │ └── index.ts │ │ ├── index.ts │ │ ├── extensions │ │ │ ├── layerStyles.theme.ts │ │ │ ├── index.ts │ │ │ ├── tokens │ │ │ │ ├── assets.tokens.ts │ │ │ │ ├── cursor.tokens.ts │ │ │ │ ├── opacity.tokens.ts │ │ │ │ ├── shadows.tokens.ts │ │ │ │ ├── gradients.tokens.ts │ │ │ │ ├── borderWidths.tokens.ts │ │ │ │ ├── borders.tokens.ts │ │ │ │ ├── containerNames.tokens.ts │ │ │ │ ├── blurs.tokens.ts │ │ │ │ ├── lineHeights.tokens.ts │ │ │ │ ├── aspectRatios.tokens.ts │ │ │ │ ├── durations.tokens.ts │ │ │ │ ├── letterSpacings.tokens.ts │ │ │ │ ├── fontWeights.tokens.ts │ │ │ │ ├── radii.tokens.ts │ │ │ │ ├── easings.tokens.ts │ │ │ │ ├── fontSizes.tokens.ts │ │ │ │ ├── zIndex.tokens.ts │ │ │ │ ├── sizes.tokens.ts │ │ │ │ ├── index.ts │ │ │ │ ├── fonts.tokens.ts │ │ │ │ ├── spacing.tokens.ts │ │ │ │ └── animations.tokens.ts │ │ │ ├── semanticTokens │ │ │ │ ├── cursor.semantic.ts │ │ │ │ ├── blurs.semantic.ts │ │ │ │ ├── radii.semantic.ts │ │ │ │ ├── sizes.semantic.ts │ │ │ │ ├── assets.semantic.ts │ │ │ │ ├── zIndex.semantic.ts │ │ │ │ ├── borders.semantic.ts │ │ │ │ ├── easings.semantic.ts │ │ │ │ ├── opacity.semantic.ts │ │ │ │ ├── spacing.semantic.ts │ │ │ │ ├── animations.semantic.ts │ │ │ │ ├── durations.semantic.ts │ │ │ │ ├── gradients.semantic.ts │ │ │ │ ├── fontSizes.semantic.ts │ │ │ │ ├── fontWeights.semantic.ts │ │ │ │ ├── lineHeights.semantic.ts │ │ │ │ ├── containerNames.semantic.ts │ │ │ │ ├── borderWidths.semantic.ts │ │ │ │ ├── letterSpacings.semantic.ts │ │ │ │ ├── fonts.semantic.ts │ │ │ │ ├── aspectRatios.semantic.ts │ │ │ │ ├── index.ts │ │ │ │ └── shadows.semantic.ts │ │ │ ├── breakpoints.theme.ts │ │ │ ├── slotRecipes │ │ │ │ ├── clipboard.slotRecipe.ts │ │ │ │ ├── editable.slotRecipe.ts │ │ │ │ ├── collapsible.slotRecipe.ts │ │ │ │ ├── tooltip.slotRecipe.ts │ │ │ │ ├── pagination.slotRecipe.ts │ │ │ │ ├── card.slotRecipe.ts │ │ │ │ ├── splitter.slotRecipe.ts │ │ │ │ ├── popover.slotRecipe.ts │ │ │ │ ├── dialog.slotRecipe.ts │ │ │ │ ├── pinInput.slotRecipe.ts │ │ │ │ ├── carousel.slotRecipe.ts │ │ │ │ ├── accordion.slotRecipe.ts │ │ │ │ ├── progress.slotRecipe.ts │ │ │ │ ├── rating.slotRecipe.ts │ │ │ │ ├── fileUpload.slotRecipe.ts │ │ │ │ ├── index.ts │ │ │ │ ├── toast.slotRecipe.ts │ │ │ │ ├── tagsInput.slotRecipe.ts │ │ │ │ ├── table.slotRecipe.ts │ │ │ │ └── segmentGroup.slotRecipe.ts │ │ │ ├── recipes │ │ │ │ ├── index.ts │ │ │ │ ├── skeleton.recipe.ts │ │ │ │ ├── label.recipe.ts │ │ │ │ ├── icon.recipe.ts │ │ │ │ ├── link.recipe.ts │ │ │ │ ├── code.recipe.ts │ │ │ │ ├── textarea.recipe.ts │ │ │ │ ├── keyboard.recipe.ts │ │ │ │ ├── text.recipe.ts │ │ │ │ ├── input.recipe.ts │ │ │ │ └── badge.recipe.ts │ │ │ ├── textStyles.theme.ts │ │ │ └── keyframes.theme.ts │ │ ├── conditions.theme.ts │ │ └── globalCss.theme.ts │ ├── config │ │ ├── index.ts │ │ ├── env.config.ts │ │ └── app.config.ts │ ├── assets │ │ └── fonts │ │ │ ├── assistant-variable.ttf │ │ │ └── fira-code-variable.ttf │ ├── util │ │ ├── index.ts │ │ ├── emToPx.ts │ │ └── hexToRgba.ts │ ├── hooks │ │ ├── index.ts │ │ ├── useDisclosure │ │ │ ├── useDisclosure.stories.tsx │ │ │ └── useDisclosure.tsx │ │ ├── useBreakpoint │ │ │ ├── useBreakpoint.stories.tsx │ │ │ └── useBreakpoint.tsx │ │ └── useBreakpointValue │ │ │ ├── useBreakpointValue.stories.tsx │ │ │ └── useBreakpointValue.tsx │ └── styles │ │ └── main.css ├── components │ ├── index.ts │ ├── typography │ │ ├── index.ts │ │ ├── Code │ │ │ ├── Code.tsx │ │ │ └── Code.stories.tsx │ │ ├── Keyboard │ │ │ ├── Keyboard.tsx │ │ │ └── Keyboard.stories.tsx │ │ └── Text │ │ │ └── Text.tsx │ └── core │ │ ├── Label │ │ ├── Label.stories.tsx │ │ └── Label.tsx │ │ ├── Icon │ │ ├── Icon.tsx │ │ └── Icon.stories.tsx │ │ ├── Badge │ │ ├── Badge.tsx │ │ └── Badge.stories.tsx │ │ ├── Input │ │ ├── Input.tsx │ │ └── Input.stories.tsx │ │ ├── Button │ │ ├── Button.tsx │ │ └── Button.stories.tsx │ │ ├── Textarea │ │ ├── Textarea.tsx │ │ └── Textarea.stories.tsx │ │ ├── Clipboard │ │ └── Clipboard.stories.tsx │ │ ├── Splitter │ │ └── Splitter.stories.tsx │ │ ├── Editable │ │ └── Editable.stories.tsx │ │ ├── Switch │ │ ├── Switch.stories.tsx │ │ └── Switch.tsx │ │ ├── Collapsible │ │ ├── Collapsible.stories.tsx │ │ └── Collapsible.tsx │ │ ├── Link │ │ └── Link.tsx │ │ ├── SegmentGroup │ │ └── SegmentGroup.stories.tsx │ │ ├── TagsInput │ │ └── TagsInput.stories.tsx │ │ ├── Card │ │ └── Card.stories.tsx │ │ ├── Rating │ │ └── Rating.stories.tsx │ │ ├── Skeleton │ │ ├── Skeleton.tsx │ │ └── Skeleton.stories.tsx │ │ ├── ToggleGroup │ │ ├── ToggleGroup.tsx │ │ └── ToggleGroup.stories.tsx │ │ ├── NumberInput │ │ └── NumberInput.stories.tsx │ │ ├── FileUpload │ │ └── FileUpload.stories.tsx │ │ ├── ColorPicker │ │ └── ColorPicker.stories.tsx │ │ ├── Pagination │ │ └── Pagination.stories.tsx │ │ ├── DatePicker │ │ └── DatePicker.stories.tsx │ │ ├── Checkbox │ │ └── Checkbox.stories.tsx │ │ ├── Slider │ │ └── Slider.stories.tsx │ │ ├── Popover │ │ └── Popover.stories.tsx │ │ ├── PINInput │ │ └── PINInput.stories.tsx │ │ ├── index.ts │ │ ├── Alert │ │ └── Alert.stories.tsx │ │ ├── Tabs │ │ └── Tabs.tsx │ │ ├── TreeView │ │ └── TreeView.stories.tsx │ │ ├── Dialog │ │ └── Dialog.stories.tsx │ │ ├── Accordion │ │ └── Accordion.stories.tsx │ │ └── Drawer │ │ └── Drawer.stories.tsx ├── stories │ ├── data │ │ ├── index.ts │ │ └── FruitBasket.tsx │ ├── layout │ │ ├── Circle.stories.tsx │ │ ├── Square.stories.tsx │ │ ├── Spacer.stories.tsx │ │ ├── Box.stories.tsx │ │ ├── Flex.stories.tsx │ │ ├── HStack.stories.tsx │ │ ├── VStack.stories.tsx │ │ ├── VisuallyHidden.stories.tsx │ │ ├── Stack.stories.tsx │ │ ├── Wrap.stories.tsx │ │ ├── Container.stories.tsx │ │ ├── Divider.stories.tsx │ │ ├── Center.stories.tsx │ │ ├── Bleed.stories.tsx │ │ ├── AspectRatio.stories.tsx │ │ ├── Grid.stories.tsx │ │ └── Float.stories.tsx │ └── introduction.mdx ├── index.ts └── scripts │ └── build.ts ├── public └── img │ ├── beach.jpg │ ├── aurora.jpg │ ├── glacier.jpg │ ├── valley.jpg │ ├── elon-musk.jpg │ ├── jellyfish.jpg │ ├── donald-glover.jpg │ └── logo-gradient.png ├── .env.local.template ├── .gitignore ├── .prettierrc ├── .renovaterc ├── .prettierignore ├── .storybook ├── manager.ts ├── test-runner.ts ├── theme.ts ├── preview.tsx └── main.ts ├── CONTRIBUTING.md ├── postcss.config.cjs ├── .editorconfig ├── .changeset └── config.json ├── turbo └── generators │ └── templates │ ├── component │ ├── {{ pascalCase name }}.tsx.hbs │ └── {{ pascalCase name }}.stories.tsx.hbs │ └── recipe │ ├── recipe.ts.hbs │ └── slotRecipe.ts.hbs ├── test-runner-jest.config.js ├── tsconfig.build.json ├── .github └── workflows │ ├── test.yml │ ├── release.yml │ └── publish.yml ├── knip.config.ts ├── LICENSE.md ├── tsconfig.json ├── panda.config.ts ├── commitlint.config.ts └── README.md /bunfig.toml: -------------------------------------------------------------------------------- 1 | telemetry = false 2 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | bun lint-staged 2 | -------------------------------------------------------------------------------- /.husky/commit-msg: -------------------------------------------------------------------------------- 1 | bun commitlint --edit $1 2 | -------------------------------------------------------------------------------- /.lintstagedrc: -------------------------------------------------------------------------------- 1 | { 2 | "*.{ts,tsx}": ["bun format", "bun lint"] 3 | } 4 | -------------------------------------------------------------------------------- /src/lib/types/storybook/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Tags } from "./Tags.enum"; 2 | -------------------------------------------------------------------------------- /src/components/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./core"; 2 | export * from "./typography"; 3 | -------------------------------------------------------------------------------- /public/img/beach.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omnidotdev/sigil/HEAD/public/img/beach.jpg -------------------------------------------------------------------------------- /src/lib/theme/presets/index.ts: -------------------------------------------------------------------------------- 1 | export { default as sigilPreset } from "./sigil.preset"; 2 | -------------------------------------------------------------------------------- /public/img/aurora.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omnidotdev/sigil/HEAD/public/img/aurora.jpg -------------------------------------------------------------------------------- /public/img/glacier.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omnidotdev/sigil/HEAD/public/img/glacier.jpg -------------------------------------------------------------------------------- /public/img/valley.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omnidotdev/sigil/HEAD/public/img/valley.jpg -------------------------------------------------------------------------------- /src/stories/data/index.ts: -------------------------------------------------------------------------------- 1 | export { default as FruitBasket, fruitBasket } from "./FruitBasket"; 2 | -------------------------------------------------------------------------------- /.env.local.template: -------------------------------------------------------------------------------- 1 | # whether to pregenerate static CSS with Panda 2 | PREGENERATE_STATIC_CSS=true 3 | -------------------------------------------------------------------------------- /public/img/elon-musk.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omnidotdev/sigil/HEAD/public/img/elon-musk.jpg -------------------------------------------------------------------------------- /public/img/jellyfish.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omnidotdev/sigil/HEAD/public/img/jellyfish.jpg -------------------------------------------------------------------------------- /public/img/donald-glover.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omnidotdev/sigil/HEAD/public/img/donald-glover.jpg -------------------------------------------------------------------------------- /public/img/logo-gradient.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omnidotdev/sigil/HEAD/public/img/logo-gradient.png -------------------------------------------------------------------------------- /src/lib/config/index.ts: -------------------------------------------------------------------------------- 1 | export { default as app } from "./app.config"; 2 | export * from "./env.config"; 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | build 3 | coverage 4 | generated 5 | storybook-static 6 | 7 | .env* 8 | !.env*.template 9 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "arrowParens": "always", 3 | "printWidth": 80, 4 | "semi": true, 5 | "singleQuote": false 6 | } 7 | -------------------------------------------------------------------------------- /src/lib/config/env.config.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Environment variables. 3 | */ 4 | export const { PREGENERATE_STATIC_CSS } = process.env; 5 | -------------------------------------------------------------------------------- /src/lib/assets/fonts/assistant-variable.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omnidotdev/sigil/HEAD/src/lib/assets/fonts/assistant-variable.ttf -------------------------------------------------------------------------------- /src/lib/assets/fonts/fira-code-variable.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omnidotdev/sigil/HEAD/src/lib/assets/fonts/fira-code-variable.ttf -------------------------------------------------------------------------------- /.renovaterc: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": [ 4 | "config:base" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /src/lib/theme/index.ts: -------------------------------------------------------------------------------- 1 | export { default as conditions } from "./conditions.theme"; 2 | export { default as globalCss } from "./globalCss.theme"; 3 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | # node_modules ignored by default 2 | build 3 | coverage 4 | generated 5 | examples 6 | tsconfig.json 7 | storybook-static 8 | *.hbs 9 | -------------------------------------------------------------------------------- /src/components/typography/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./Code/Code"; 2 | 3 | export * from "./Keyboard/Keyboard"; 4 | 5 | export * from "./Text/Text"; 6 | -------------------------------------------------------------------------------- /src/lib/types/index.ts: -------------------------------------------------------------------------------- 1 | export type { default as AssignJSXStyleProps } from "./AssignJSXStyleProps.type"; 2 | export type { default as Nullable } from "./Nullable.type"; 3 | -------------------------------------------------------------------------------- /.storybook/manager.ts: -------------------------------------------------------------------------------- 1 | import { addons } from "@storybook/manager-api"; 2 | 3 | import theme from "./theme"; 4 | 5 | // apply custom Storybook theme 6 | addons.setConfig({ theme }); 7 | -------------------------------------------------------------------------------- /src/lib/util/index.ts: -------------------------------------------------------------------------------- 1 | export { default as createStyleContext } from "./createStyleContext"; 2 | export { default as emToPx } from "./emToPx"; 3 | export { default as hexToRgba } from "./hexToRgba"; 4 | -------------------------------------------------------------------------------- /src/lib/types/Nullable.type.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Container type that represents a value that can be null. 3 | * @template T Type of value. 4 | */ 5 | type Nullable = T | null; 6 | 7 | export default Nullable; 8 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Follow the [Omni changesets documentation](https://docs.omni.dev/contributing/changesets) for guidelines on how to create changesets, which describe changes you've created. 4 | -------------------------------------------------------------------------------- /postcss.config.cjs: -------------------------------------------------------------------------------- 1 | // Lightning CSS automatically picks up this PostCSS config (https://lightningcss.dev/docs.html#with-parcel) 2 | module.exports = { 3 | plugins: { 4 | "@pandacss/dev/postcss": {}, 5 | }, 6 | }; 7 | -------------------------------------------------------------------------------- /src/lib/theme/extensions/layerStyles.theme.ts: -------------------------------------------------------------------------------- 1 | import { defineLayerStyles } from "@pandacss/dev"; 2 | 3 | /** 4 | * Layer styles. 5 | */ 6 | const layerStyles = defineLayerStyles({}); 7 | 8 | export default layerStyles; 9 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # editorconfig.org 2 | 3 | root = true 4 | 5 | [*] 6 | charset = utf-8 7 | # indentation 8 | indent_style = space 9 | indent_size = 2 10 | trim_trailing_whitespace = true 11 | insert_final_newline = true 12 | max_line_length = 80 13 | -------------------------------------------------------------------------------- /.changeset/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://unpkg.com/@changesets/config@2.3.1/schema.json", 3 | "access": "public", 4 | "baseBranch": "master", 5 | "changelog": ["@changesets/changelog-github", { "repo": "omnidotdev/sigil" }], 6 | "commit": false 7 | } 8 | -------------------------------------------------------------------------------- /src/lib/theme/extensions/index.ts: -------------------------------------------------------------------------------- 1 | export { default as breakpoints } from "./breakpoints.theme"; 2 | export { default as keyframes } from "./keyframes.theme"; 3 | export { default as layerStyles } from "./layerStyles.theme"; 4 | export { default as textStyles } from "./textStyles.theme"; 5 | -------------------------------------------------------------------------------- /src/lib/theme/extensions/tokens/assets.tokens.ts: -------------------------------------------------------------------------------- 1 | import { defineTokens } from "@pandacss/dev"; 2 | 3 | import type { Tokens } from "@pandacss/dev"; 4 | 5 | /** 6 | * Asset tokens. 7 | */ 8 | const assets: Tokens["assets"] = defineTokens.assets({}); 9 | 10 | export default assets; 11 | -------------------------------------------------------------------------------- /src/lib/theme/extensions/tokens/cursor.tokens.ts: -------------------------------------------------------------------------------- 1 | import { defineTokens } from "@pandacss/dev"; 2 | 3 | import type { Tokens } from "@pandacss/dev"; 4 | 5 | /** 6 | * Cursor tokens. 7 | */ 8 | const cursor: Tokens["cursor"] = defineTokens.cursor({}); 9 | 10 | export default cursor; 11 | -------------------------------------------------------------------------------- /src/lib/theme/extensions/tokens/opacity.tokens.ts: -------------------------------------------------------------------------------- 1 | import { defineTokens } from "@pandacss/dev"; 2 | 3 | import type { Tokens } from "@pandacss/dev"; 4 | 5 | /** 6 | * Opacity tokens. 7 | */ 8 | const opacity: Tokens["opacity"] = defineTokens.opacity({}); 9 | 10 | export default opacity; 11 | -------------------------------------------------------------------------------- /src/lib/theme/extensions/tokens/shadows.tokens.ts: -------------------------------------------------------------------------------- 1 | import { defineTokens } from "@pandacss/dev"; 2 | 3 | import type { Tokens } from "@pandacss/dev"; 4 | 5 | /** 6 | * Shadow tokens. 7 | */ 8 | const shadows: Tokens["shadows"] = defineTokens.shadows({}); 9 | 10 | export default shadows; 11 | -------------------------------------------------------------------------------- /src/lib/theme/extensions/tokens/gradients.tokens.ts: -------------------------------------------------------------------------------- 1 | import { defineTokens } from "@pandacss/dev"; 2 | 3 | import type { Tokens } from "@pandacss/dev"; 4 | 5 | /** 6 | * Gradient tokens. 7 | */ 8 | const gradients: Tokens["gradients"] = defineTokens.gradients({}); 9 | 10 | export default gradients; 11 | -------------------------------------------------------------------------------- /src/lib/theme/extensions/semanticTokens/cursor.semantic.ts: -------------------------------------------------------------------------------- 1 | import { defineSemanticTokens } from "@pandacss/dev"; 2 | 3 | import type { Tokens } from "@pandacss/dev"; 4 | 5 | /** 6 | * Cursor semantic tokens. 7 | */ 8 | const cursor: Tokens["cursor"] = defineSemanticTokens.cursor({}); 9 | 10 | export default cursor; 11 | -------------------------------------------------------------------------------- /src/lib/theme/extensions/tokens/borderWidths.tokens.ts: -------------------------------------------------------------------------------- 1 | import { defineTokens } from "@pandacss/dev"; 2 | 3 | import type { Tokens } from "@pandacss/dev"; 4 | 5 | /** 6 | * Border width tokens. 7 | */ 8 | const borderWidths: Tokens["borderWidths"] = defineTokens.borderWidths({}); 9 | 10 | export default borderWidths; 11 | -------------------------------------------------------------------------------- /src/lib/theme/extensions/tokens/borders.tokens.ts: -------------------------------------------------------------------------------- 1 | import { defineTokens } from "@pandacss/dev"; 2 | 3 | import type { Tokens } from "@pandacss/dev"; 4 | 5 | /** 6 | * Border tokens. 7 | */ 8 | const borders: Tokens["borders"] = defineTokens.borders({ 9 | none: { value: "none" }, 10 | }); 11 | 12 | export default borders; 13 | -------------------------------------------------------------------------------- /src/lib/theme/extensions/semanticTokens/blurs.semantic.ts: -------------------------------------------------------------------------------- 1 | import { defineSemanticTokens } from "@pandacss/dev"; 2 | 3 | import type { SemanticTokens } from "@pandacss/dev"; 4 | 5 | /** 6 | * Blur semantic tokens. 7 | */ 8 | const blurs: SemanticTokens["blurs"] = defineSemanticTokens.blurs({}); 9 | 10 | export default blurs; 11 | -------------------------------------------------------------------------------- /src/lib/theme/extensions/semanticTokens/radii.semantic.ts: -------------------------------------------------------------------------------- 1 | import { defineSemanticTokens } from "@pandacss/dev"; 2 | 3 | import type { SemanticTokens } from "@pandacss/dev"; 4 | 5 | /** 6 | * Radii semantic tokens. 7 | */ 8 | const radii: SemanticTokens["radii"] = defineSemanticTokens.radii({}); 9 | 10 | export default radii; 11 | -------------------------------------------------------------------------------- /src/lib/theme/extensions/semanticTokens/sizes.semantic.ts: -------------------------------------------------------------------------------- 1 | import { defineSemanticTokens } from "@pandacss/dev"; 2 | 3 | import type { SemanticTokens } from "@pandacss/dev"; 4 | 5 | /** 6 | * Size semantic tokens. 7 | */ 8 | const sizes: SemanticTokens["sizes"] = defineSemanticTokens.sizes({}); 9 | 10 | export default sizes; 11 | -------------------------------------------------------------------------------- /turbo/generators/templates/component/{{ pascalCase name }}.tsx.hbs: -------------------------------------------------------------------------------- 1 | export interface {{ pascalName }}Props { 2 | // TODO add props 3 | } 4 | 5 | /** 6 | * {{ pascalName }}. 7 | */ 8 | const {{ pascalName }} = () => ( 9 |
10 |

{{ pascalName }}

11 |
12 | ); 13 | 14 | export default {{ pascalName }}; 15 | -------------------------------------------------------------------------------- /src/lib/theme/extensions/semanticTokens/assets.semantic.ts: -------------------------------------------------------------------------------- 1 | import { defineSemanticTokens } from "@pandacss/dev"; 2 | 3 | import type { SemanticTokens } from "@pandacss/dev"; 4 | 5 | /** 6 | * Asset semantic tokens. 7 | */ 8 | const assets: SemanticTokens["assets"] = defineSemanticTokens.assets({}); 9 | 10 | export default assets; 11 | -------------------------------------------------------------------------------- /src/lib/theme/extensions/semanticTokens/zIndex.semantic.ts: -------------------------------------------------------------------------------- 1 | import { defineSemanticTokens } from "@pandacss/dev"; 2 | 3 | import type { SemanticTokens } from "@pandacss/dev"; 4 | 5 | /** 6 | * Z-index semantic tokens. 7 | */ 8 | const zIndex: SemanticTokens["zIndex"] = defineSemanticTokens.zIndex({}); 9 | 10 | export default zIndex; 11 | -------------------------------------------------------------------------------- /src/lib/theme/extensions/semanticTokens/borders.semantic.ts: -------------------------------------------------------------------------------- 1 | import { defineSemanticTokens } from "@pandacss/dev"; 2 | 3 | import type { SemanticTokens } from "@pandacss/dev"; 4 | 5 | /** 6 | * Border semantic tokens. 7 | */ 8 | const borders: SemanticTokens["borders"] = defineSemanticTokens.borders({}); 9 | 10 | export default borders; 11 | -------------------------------------------------------------------------------- /src/lib/theme/extensions/semanticTokens/easings.semantic.ts: -------------------------------------------------------------------------------- 1 | import { defineSemanticTokens } from "@pandacss/dev"; 2 | 3 | import type { SemanticTokens } from "@pandacss/dev"; 4 | 5 | /** 6 | * Easing semantic tokens. 7 | */ 8 | const easings: SemanticTokens["easings"] = defineSemanticTokens.easings({}); 9 | 10 | export default easings; 11 | -------------------------------------------------------------------------------- /src/lib/theme/extensions/semanticTokens/opacity.semantic.ts: -------------------------------------------------------------------------------- 1 | import { defineSemanticTokens } from "@pandacss/dev"; 2 | 3 | import type { SemanticTokens } from "@pandacss/dev"; 4 | 5 | /** 6 | * Opacity semantic tokens. 7 | */ 8 | const opacity: SemanticTokens["opacity"] = defineSemanticTokens.opacity({}); 9 | 10 | export default opacity; 11 | -------------------------------------------------------------------------------- /src/lib/theme/extensions/semanticTokens/spacing.semantic.ts: -------------------------------------------------------------------------------- 1 | import { defineSemanticTokens } from "@pandacss/dev"; 2 | 3 | import type { SemanticTokens } from "@pandacss/dev"; 4 | 5 | /** 6 | * Spacing semantic tokens. 7 | */ 8 | const spacing: SemanticTokens["spacing"] = defineSemanticTokens.spacing({}); 9 | 10 | export default spacing; 11 | -------------------------------------------------------------------------------- /src/lib/theme/extensions/tokens/containerNames.tokens.ts: -------------------------------------------------------------------------------- 1 | import { defineTokens } from "@pandacss/dev"; 2 | 3 | import type { Tokens } from "@pandacss/dev"; 4 | 5 | /** 6 | * Container name tokens. 7 | */ 8 | const containerNames: Tokens["containerNames"] = defineTokens.containerNames( 9 | {}, 10 | ); 11 | 12 | export default containerNames; 13 | -------------------------------------------------------------------------------- /src/lib/types/AssignJSXStyleProps.type.ts: -------------------------------------------------------------------------------- 1 | import type { 2 | Assign, 3 | JsxStyleProps as JSXStyleProps, 4 | } from "generated/panda/types"; 5 | 6 | /** 7 | * Assign Panda JSX style props to component props. 8 | * @template P Component props. 9 | */ 10 | type AssignJSXStyleProps

= Assign; 11 | 12 | export default AssignJSXStyleProps; 13 | -------------------------------------------------------------------------------- /src/lib/theme/extensions/semanticTokens/animations.semantic.ts: -------------------------------------------------------------------------------- 1 | import { defineSemanticTokens } from "@pandacss/dev"; 2 | 3 | import type { SemanticTokens } from "@pandacss/dev"; 4 | 5 | /** 6 | * Animation semantic tokens. 7 | */ 8 | const animations: SemanticTokens["animations"] = 9 | defineSemanticTokens.animations({}); 10 | 11 | export default animations; 12 | -------------------------------------------------------------------------------- /src/lib/theme/extensions/semanticTokens/durations.semantic.ts: -------------------------------------------------------------------------------- 1 | import { defineSemanticTokens } from "@pandacss/dev"; 2 | 3 | import type { SemanticTokens } from "@pandacss/dev"; 4 | 5 | /** 6 | * Duration semantic tokens. 7 | */ 8 | const durations: SemanticTokens["durations"] = defineSemanticTokens.durations( 9 | {}, 10 | ); 11 | 12 | export default durations; 13 | -------------------------------------------------------------------------------- /src/lib/theme/extensions/semanticTokens/gradients.semantic.ts: -------------------------------------------------------------------------------- 1 | import { defineSemanticTokens } from "@pandacss/dev"; 2 | 3 | import type { SemanticTokens } from "@pandacss/dev"; 4 | 5 | /** 6 | * Gradient semantic tokens. 7 | */ 8 | const gradients: SemanticTokens["gradients"] = defineSemanticTokens.gradients( 9 | {}, 10 | ); 11 | 12 | export default gradients; 13 | -------------------------------------------------------------------------------- /src/lib/theme/extensions/breakpoints.theme.ts: -------------------------------------------------------------------------------- 1 | import type { Theme } from "@pandacss/types"; 2 | 3 | /** 4 | * Device breakpoints for responsive design. 5 | */ 6 | const breakpoints: Theme["breakpoints"] = { 7 | base: "0em", 8 | sm: "40em", 9 | md: "48em", 10 | lg: "64em", 11 | xl: "80em", 12 | "2xl": "96em", 13 | }; 14 | 15 | export default breakpoints; 16 | -------------------------------------------------------------------------------- /src/lib/theme/extensions/semanticTokens/fontSizes.semantic.ts: -------------------------------------------------------------------------------- 1 | import { defineSemanticTokens } from "@pandacss/dev"; 2 | 3 | import type { SemanticTokens } from "@pandacss/dev"; 4 | 5 | /** 6 | * Font size semantic tokens. 7 | */ 8 | const fontSizes: SemanticTokens["fontSizes"] = defineSemanticTokens.fontSizes( 9 | {}, 10 | ); 11 | 12 | export default fontSizes; 13 | -------------------------------------------------------------------------------- /src/lib/theme/extensions/semanticTokens/fontWeights.semantic.ts: -------------------------------------------------------------------------------- 1 | import { defineSemanticTokens } from "@pandacss/dev"; 2 | 3 | import type { SemanticTokens } from "@pandacss/dev"; 4 | 5 | /** 6 | * Font weight semantic tokens. 7 | */ 8 | const fontWeights: SemanticTokens["fontWeights"] = 9 | defineSemanticTokens.fontWeights({}); 10 | 11 | export default fontWeights; 12 | -------------------------------------------------------------------------------- /src/lib/theme/extensions/semanticTokens/lineHeights.semantic.ts: -------------------------------------------------------------------------------- 1 | import { defineSemanticTokens } from "@pandacss/dev"; 2 | 3 | import type { SemanticTokens } from "@pandacss/dev"; 4 | 5 | /** 6 | * Line height semantic tokens. 7 | */ 8 | const lineHeights: SemanticTokens["lineHeights"] = 9 | defineSemanticTokens.lineHeights({}); 10 | 11 | export default lineHeights; 12 | -------------------------------------------------------------------------------- /src/lib/theme/extensions/semanticTokens/containerNames.semantic.ts: -------------------------------------------------------------------------------- 1 | import { defineSemanticTokens } from "@pandacss/dev"; 2 | 3 | import type { Tokens } from "@pandacss/dev"; 4 | 5 | /** 6 | * Container name semantic tokens. 7 | */ 8 | const containerNames: Tokens["containerNames"] = 9 | defineSemanticTokens.containerNames({}); 10 | 11 | export default containerNames; 12 | -------------------------------------------------------------------------------- /src/lib/theme/extensions/semanticTokens/borderWidths.semantic.ts: -------------------------------------------------------------------------------- 1 | import { defineSemanticTokens } from "@pandacss/dev"; 2 | 3 | import type { SemanticTokens } from "@pandacss/dev"; 4 | 5 | /** 6 | * Border width semantic tokens. 7 | */ 8 | const borderWidths: SemanticTokens["borderWidths"] = 9 | defineSemanticTokens.borderWidths({}); 10 | 11 | export default borderWidths; 12 | -------------------------------------------------------------------------------- /src/lib/util/emToPx.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Convert a relative `em` value to a pixel (`px`) value. 3 | * @param em The `em` value to convert. 4 | * @param base The base pixel value to use for the conversion. Defaults to `16px`. 5 | * @returns The converted `px` value. 6 | */ 7 | const emToPx = (em: `${number}em`, base = 16) => +em.split("em")[0] * base; 8 | 9 | export default emToPx; 10 | -------------------------------------------------------------------------------- /src/lib/config/app.config.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Application config. 3 | */ 4 | const app = { 5 | name: { short: "Sigil", full: "Omni Sigil" }, 6 | // TODO extract to `omni/common` repo (JSON) 7 | organization: { 8 | name: "Omni", 9 | url: "https://omni.dev", 10 | x: { handle: "@omnidotdev", url: "https://x.com/omnidotdev" }, 11 | }, 12 | }; 13 | 14 | export default app; 15 | -------------------------------------------------------------------------------- /src/lib/theme/extensions/semanticTokens/letterSpacings.semantic.ts: -------------------------------------------------------------------------------- 1 | import { defineSemanticTokens } from "@pandacss/dev"; 2 | 3 | import type { SemanticTokens } from "@pandacss/dev"; 4 | 5 | /** 6 | * Letter spacing semantic tokens. 7 | */ 8 | const letterSpacings: SemanticTokens["letterSpacings"] = 9 | defineSemanticTokens.letterSpacings({}); 10 | 11 | export default letterSpacings; 12 | -------------------------------------------------------------------------------- /src/stories/data/FruitBasket.tsx: -------------------------------------------------------------------------------- 1 | import { Box } from "generated/panda/jsx"; 2 | 3 | export const fruitBasket = [ 4 | { name: "Apple", icon: "🍎" }, 5 | { name: "Banana", icon: "🍌" }, 6 | { name: "Orange", icon: "🍊" }, 7 | { name: "Grape", icon: "🍇" }, 8 | ]; 9 | 10 | const FruitBasket = () => 11 | fruitBasket.map(({ icon: fruit }) => {fruit}); 12 | 13 | export default FruitBasket; 14 | -------------------------------------------------------------------------------- /test-runner-jest.config.js: -------------------------------------------------------------------------------- 1 | import { getJestConfig } from "@storybook/test-runner"; 2 | 3 | /** 4 | * Storybook test runner Jest configuration. 5 | * @see https://github.com/storybookjs/test-runner#jest-options 6 | * @type {import('@jest/types').Config.InitialOptions} 7 | */ 8 | export default { 9 | // default configuration from `@storybook/test-runner` 10 | ...getJestConfig(), 11 | // set test timeout (default is 15s) 12 | testTimeout: 30000, 13 | }; 14 | -------------------------------------------------------------------------------- /src/components/core/Label/Label.stories.tsx: -------------------------------------------------------------------------------- 1 | import { Label } from "components"; 2 | 3 | import type { Meta, StoryObj } from "@storybook/react"; 4 | 5 | type Story = StoryObj; 6 | 7 | const meta = { 8 | title: "Components/Core/Label", 9 | component: Label, 10 | tags: ["autodocs"], 11 | } satisfies Meta; 12 | 13 | export const Default: Story = { 14 | args: { 15 | children: <>I'm a label, 16 | }, 17 | }; 18 | 19 | export default meta; 20 | -------------------------------------------------------------------------------- /turbo/generators/templates/component/{{ pascalCase name }}.stories.tsx.hbs: -------------------------------------------------------------------------------- 1 | import { {{ pascalName }} } from "components"; 2 | 3 | import type { Meta, StoryObj } from "@storybook/react"; 4 | 5 | type Story = StoryObj; 6 | 7 | const meta = { 8 | title: "Components/{{ pascalCase category }}/{{ pascalName }}", 9 | component: {{ pascalName }}, 10 | tags: ["autodocs"], 11 | } satisfies Meta; 12 | 13 | export const Default: Story = {}; 14 | 15 | export default meta; 16 | -------------------------------------------------------------------------------- /src/lib/theme/extensions/tokens/blurs.tokens.ts: -------------------------------------------------------------------------------- 1 | import { defineTokens } from "@pandacss/dev"; 2 | 3 | import type { Tokens } from "@pandacss/dev"; 4 | 5 | /** 6 | * Blur tokens. 7 | */ 8 | const blurs: Tokens["blurs"] = defineTokens.blurs({ 9 | sm: { value: "4px" }, 10 | base: { value: "8px" }, 11 | md: { value: "12px" }, 12 | lg: { value: "16px" }, 13 | xl: { value: "24px" }, 14 | "2xl": { value: "40px" }, 15 | "3xl": { value: "64px" }, 16 | }); 17 | 18 | export default blurs; 19 | -------------------------------------------------------------------------------- /src/lib/theme/extensions/tokens/lineHeights.tokens.ts: -------------------------------------------------------------------------------- 1 | import { defineTokens } from "@pandacss/dev"; 2 | 3 | import type { Tokens } from "@pandacss/dev"; 4 | 5 | /** 6 | * Line height tokens. 7 | */ 8 | const lineHeights: Tokens["lineHeights"] = defineTokens.lineHeights({ 9 | none: { value: 1 }, 10 | tight: { value: 1.25 }, 11 | snug: { value: 1.375 }, 12 | normal: { value: 1.5 }, 13 | relaxed: { value: 1.75 }, 14 | loose: { value: 2 }, 15 | }); 16 | 17 | export default lineHeights; 18 | -------------------------------------------------------------------------------- /tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "noEmit": false, 5 | // TODO https://linear.app/omnidev/issue/OMNI-242/use-isolated-declarations-for-type-output-and-remove-tsup 6 | // "isolatedDeclarations": true, 7 | "declaration": true, 8 | "emitDeclarationOnly": true, 9 | "declarationMap": true, 10 | "noImplicitAny": false 11 | }, 12 | // overwrite include from composed `tsconfig` 13 | "include": [], 14 | "files": ["src/index.ts"] 15 | } 16 | -------------------------------------------------------------------------------- /.storybook/test-runner.ts: -------------------------------------------------------------------------------- 1 | import type { TestRunnerConfig } from "@storybook/test-runner"; 2 | 3 | const config: TestRunnerConfig = { 4 | /* Hook to execute before a story is initially visited before being rendered in the browser. 5 | * The page argument is Playwright's page object for the story. 6 | * The context argument is a Storybook object containing the story's ID, title, and name. 7 | */ 8 | async preVisit(page, _context) { 9 | await page.content(); 10 | }, 11 | }; 12 | 13 | export default config; 14 | -------------------------------------------------------------------------------- /turbo/generators/templates/recipe/recipe.ts.hbs: -------------------------------------------------------------------------------- 1 | import { defineRecipe } from "@pandacss/dev"; 2 | 3 | /** 4 | * {{ pascalName }} recipe. 5 | */ 6 | const {{ camelName }} = defineRecipe({ 7 | className: "{{ camelName }}", 8 | description: "{{ pascalName }} style recipes", 9 | base: { 10 | // TODO add base styles here 11 | }, 12 | defaultVariants: { 13 | // TODO add default variants here 14 | }, 15 | variants: { 16 | // TODO add variants here 17 | }, 18 | }); 19 | 20 | export default {{ camelName }}; 21 | -------------------------------------------------------------------------------- /src/lib/theme/extensions/tokens/aspectRatios.tokens.ts: -------------------------------------------------------------------------------- 1 | import { defineTokens } from "@pandacss/dev"; 2 | 3 | import type { Tokens } from "@pandacss/dev"; 4 | 5 | /** 6 | * Aspect ratio tokens. 7 | */ 8 | const aspectRatios: Tokens["aspectRatios"] = defineTokens.aspectRatios({ 9 | "1:1": { value: "1" }, 10 | "4:3": { value: "4 / 3" }, 11 | "3:4": { value: "3 / 4" }, 12 | "16:9": { value: "16 / 9" }, 13 | "18:5": { value: "18 / 5" }, 14 | "1.618:1": { value: "1.618 / 1" }, 15 | }); 16 | 17 | export default aspectRatios; 18 | -------------------------------------------------------------------------------- /src/lib/hooks/index.ts: -------------------------------------------------------------------------------- 1 | export { default as useBreakpoint } from "./useBreakpoint/useBreakpoint"; 2 | export type { Options as UseBreakpointOptions } from "./useBreakpoint/useBreakpoint"; 3 | 4 | export { default as useBreakpointValue } from "./useBreakpointValue/useBreakpointValue"; 5 | export type { Options as UseBreakpointValueOptions } from "./useBreakpointValue/useBreakpointValue"; 6 | 7 | export { default as useDisclosure } from "./useDisclosure/useDisclosure"; 8 | export type { Options as UseDisclosureOptions } from "./useDisclosure/useDisclosure"; 9 | -------------------------------------------------------------------------------- /src/lib/theme/extensions/tokens/durations.tokens.ts: -------------------------------------------------------------------------------- 1 | import { defineTokens } from "@pandacss/dev"; 2 | 3 | import type { Tokens } from "@pandacss/dev"; 4 | 5 | /** 6 | * Duration tokens. 7 | */ 8 | const durations: Tokens["durations"] = defineTokens.durations({ 9 | fastest: { value: "50ms" }, 10 | faster: { value: "100ms" }, 11 | fast: { value: "150ms" }, 12 | normal: { value: "200ms" }, 13 | slow: { value: "300ms" }, 14 | slower: { value: "400ms" }, 15 | slowest: { value: "500ms" }, 16 | }); 17 | 18 | export default durations; 19 | -------------------------------------------------------------------------------- /src/lib/theme/extensions/tokens/letterSpacings.tokens.ts: -------------------------------------------------------------------------------- 1 | import { defineTokens } from "@pandacss/dev"; 2 | 3 | import type { Tokens } from "@pandacss/dev"; 4 | 5 | /** 6 | * Letter spacing tokens. 7 | */ 8 | const letterSpacings: Tokens["letterSpacings"] = defineTokens.letterSpacings({ 9 | tighter: { value: "-0.05em" }, 10 | tight: { value: "-0.025em" }, 11 | normal: { value: "0em" }, 12 | wide: { value: "0.025em" }, 13 | wider: { value: "0.05em" }, 14 | widest: { value: "0.1em" }, 15 | }); 16 | 17 | export default letterSpacings; 18 | -------------------------------------------------------------------------------- /src/components/core/Icon/Icon.tsx: -------------------------------------------------------------------------------- 1 | import { styled } from "generated/panda/jsx"; 2 | import { icon } from "generated/panda/recipes"; 3 | 4 | import type { ComponentProps } from "generated/panda/types"; 5 | import type { ElementType } from "react"; 6 | 7 | export interface IconProps extends ComponentProps { 8 | /** Source. */ 9 | src: ElementType; 10 | } 11 | 12 | const StyledIcon = styled("svg", icon); 13 | 14 | /** 15 | * Icon. 16 | */ 17 | export const Icon = ({ src, ...rest }: IconProps) => ( 18 | 19 | ); 20 | -------------------------------------------------------------------------------- /src/stories/layout/Circle.stories.tsx: -------------------------------------------------------------------------------- 1 | import { Circle } from "generated/panda/jsx"; 2 | 3 | import type { Meta, StoryObj } from "@storybook/react"; 4 | 5 | type Story = StoryObj; 6 | 7 | /** 8 | * Circle shape. 9 | */ 10 | const meta = { 11 | title: "Components/Layout/Circle", 12 | component: Circle, 13 | tags: ["autodocs"], 14 | } satisfies Meta; 15 | 16 | export const Default: Story = { 17 | render: () => ( 18 | 19 | 🐼 20 | 21 | ), 22 | }; 23 | 24 | export default meta; 25 | -------------------------------------------------------------------------------- /src/stories/layout/Square.stories.tsx: -------------------------------------------------------------------------------- 1 | import { Square } from "generated/panda/jsx"; 2 | 3 | import type { Meta, StoryObj } from "@storybook/react"; 4 | 5 | type Story = StoryObj; 6 | 7 | /** 8 | * Square shape. 9 | */ 10 | const meta = { 11 | title: "Components/Layout/Square", 12 | component: Square, 13 | tags: ["autodocs"], 14 | } satisfies Meta; 15 | 16 | export const Default: Story = { 17 | render: () => ( 18 | 19 | 🦒 20 | 21 | ), 22 | }; 23 | 24 | export default meta; 25 | -------------------------------------------------------------------------------- /src/lib/theme/extensions/semanticTokens/fonts.semantic.ts: -------------------------------------------------------------------------------- 1 | import { defineSemanticTokens } from "@pandacss/dev"; 2 | 3 | import type { SemanticTokens } from "@pandacss/dev"; 4 | 5 | /** 6 | * Font semantic tokens. 7 | */ 8 | const fonts: SemanticTokens["fonts"] = defineSemanticTokens.fonts({ 9 | primary: { 10 | value: `var(--font-primary), "Helvetica Neue", Helvetica, Arial, sans-serif`, 11 | description: "Primary font", 12 | }, 13 | code: { 14 | value: "var(--font-code), monospace", 15 | description: "Code font", 16 | }, 17 | }); 18 | 19 | export default fonts; 20 | -------------------------------------------------------------------------------- /src/stories/layout/Spacer.stories.tsx: -------------------------------------------------------------------------------- 1 | import { Spacer } from "generated/panda/jsx"; 2 | 3 | import type { Meta, StoryObj } from "@storybook/react"; 4 | 5 | type Story = StoryObj; 6 | 7 | /** 8 | * Stretched flex container. 9 | */ 10 | const meta = { 11 | title: "Components/Layout/Spacer", 12 | component: Spacer, 13 | tags: ["autodocs"], 14 | } satisfies Meta; 15 | 16 | export const Default: Story = { 17 | render: () => ( 18 | 19 | I am a spacer 20 | 21 | ), 22 | }; 23 | 24 | export default meta; 25 | -------------------------------------------------------------------------------- /src/components/core/Badge/Badge.tsx: -------------------------------------------------------------------------------- 1 | import { ark } from "@ark-ui/react"; 2 | 3 | import { styled } from "generated/panda/jsx"; 4 | import { badge } from "generated/panda/recipes"; 5 | 6 | import type { BadgeVariantProps } from "generated/panda/recipes"; 7 | import type { ComponentProps } from "generated/panda/types"; 8 | import type { AssignJSXStyleProps } from "lib/types"; 9 | 10 | export interface BadgeProps 11 | extends AssignJSXStyleProps>, 12 | BadgeVariantProps {} 13 | 14 | /** 15 | * Badge. 16 | */ 17 | export const Badge = styled(ark.div, badge); 18 | -------------------------------------------------------------------------------- /src/components/core/Label/Label.tsx: -------------------------------------------------------------------------------- 1 | import { ark } from "@ark-ui/react"; 2 | 3 | import { styled } from "generated/panda/jsx"; 4 | import { label } from "generated/panda/recipes"; 5 | 6 | import type { LabelVariantProps } from "generated/panda/recipes"; 7 | import type { ComponentProps } from "generated/panda/types"; 8 | import type { AssignJSXStyleProps } from "lib/types"; 9 | 10 | export interface LabelProps 11 | extends AssignJSXStyleProps>, 12 | LabelVariantProps {} 13 | 14 | /** 15 | * Label. 16 | */ 17 | export const Label = styled(ark.label, label); 18 | -------------------------------------------------------------------------------- /src/lib/theme/extensions/tokens/fontWeights.tokens.ts: -------------------------------------------------------------------------------- 1 | import { defineTokens } from "@pandacss/dev"; 2 | 3 | import type { Tokens } from "@pandacss/dev"; 4 | 5 | /** 6 | * Font weight tokens. 7 | */ 8 | const fontWeights: Tokens["fontWeights"] = defineTokens.fontWeights({ 9 | thin: { value: 100 }, 10 | extralight: { value: 200 }, 11 | light: { value: 300 }, 12 | normal: { value: 400 }, 13 | medium: { value: 500 }, 14 | semibold: { value: 600 }, 15 | bold: { value: 700 }, 16 | extrabold: { value: 800 }, 17 | black: { value: 900 }, 18 | }); 19 | 20 | export default fontWeights; 21 | -------------------------------------------------------------------------------- /src/lib/types/storybook/Tags.enum.ts: -------------------------------------------------------------------------------- 1 | // ! not in use due to CSF failing to process, track https://github.com/storybookjs/storybook/discussions/24192. 2 | 3 | /** 4 | * Story tags. Note that [CSF](https://storybook.js.org/docs/react/api/csf) requires that tags be statically-analyzable string literals, however this enum cannot be used directly as a value in a tag nor as a narrowing type annotation. See warning above. 5 | */ 6 | enum Tags { 7 | /** Enable [autodocs](https://storybook.js.org/docs/react/writing-docs/autodocs). */ 8 | AUTODOCS = "autodocs", 9 | } 10 | 11 | export default Tags; 12 | -------------------------------------------------------------------------------- /src/components/core/Input/Input.tsx: -------------------------------------------------------------------------------- 1 | import { ark } from "@ark-ui/react"; 2 | 3 | import { styled } from "generated/panda/jsx"; 4 | import { input } from "generated/panda/recipes"; 5 | 6 | import type { InputVariantProps } from "generated/panda/recipes"; 7 | import type { ComponentProps } from "generated/panda/types"; 8 | import type { AssignJSXStyleProps } from "lib/types"; 9 | 10 | export interface InputProps 11 | extends AssignJSXStyleProps>, 12 | InputVariantProps {} 13 | 14 | /** 15 | * Interactive input. 16 | */ 17 | export const Input = styled(ark.input, input); 18 | -------------------------------------------------------------------------------- /src/components/typography/Code/Code.tsx: -------------------------------------------------------------------------------- 1 | import { ark } from "@ark-ui/react"; 2 | 3 | import { styled } from "generated/panda/jsx"; 4 | import { code } from "generated/panda/recipes"; 5 | 6 | import type { CodeVariantProps } from "generated/panda/recipes"; 7 | import type { ComponentProps } from "generated/panda/types"; 8 | import type { AssignJSXStyleProps } from "lib/types"; 9 | 10 | export interface CodeProps 11 | extends AssignJSXStyleProps>, 12 | CodeVariantProps {} 13 | 14 | /** 15 | * Code text representation. 16 | */ 17 | export const Code = styled(ark.code, code); 18 | -------------------------------------------------------------------------------- /src/lib/theme/extensions/semanticTokens/aspectRatios.semantic.ts: -------------------------------------------------------------------------------- 1 | import { defineSemanticTokens } from "@pandacss/dev"; 2 | 3 | import type { SemanticTokens } from "@pandacss/dev"; 4 | 5 | /** 6 | * Aspect ratio semantic tokens. 7 | */ 8 | const aspectRatios: SemanticTokens["aspectRatios"] = 9 | defineSemanticTokens.aspectRatios({ 10 | square: { value: "1 / 1" }, 11 | landscape: { value: "4 / 3" }, 12 | portrait: { value: "3 / 4" }, 13 | wide: { value: "16 / 9" }, 14 | ultrawide: { value: "18 / 5" }, 15 | golden: { value: "1.618 / 1" }, 16 | }); 17 | 18 | export default aspectRatios; 19 | -------------------------------------------------------------------------------- /src/lib/theme/extensions/tokens/radii.tokens.ts: -------------------------------------------------------------------------------- 1 | import { defineTokens } from "@pandacss/dev"; 2 | 3 | import type { Tokens } from "@pandacss/dev"; 4 | 5 | /** 6 | * Radii tokens. 7 | */ 8 | const radii: Tokens["radii"] = defineTokens.radii({ 9 | none: { value: "0" }, 10 | "2xs": { value: "0.0625rem" }, 11 | xs: { value: "0.125rem" }, 12 | sm: { value: "0.25rem" }, 13 | md: { value: "0.375rem" }, 14 | lg: { value: "0.5rem" }, 15 | xl: { value: "0.75rem" }, 16 | "2xl": { value: "1rem" }, 17 | "3xl": { value: "1.5rem" }, 18 | full: { value: "9999px" }, 19 | }); 20 | 21 | export default radii; 22 | -------------------------------------------------------------------------------- /src/components/core/Button/Button.tsx: -------------------------------------------------------------------------------- 1 | import { ark } from "@ark-ui/react"; 2 | 3 | import { styled } from "generated/panda/jsx"; 4 | import { button } from "generated/panda/recipes"; 5 | 6 | import type { ButtonVariantProps } from "generated/panda/recipes"; 7 | import type { ComponentProps } from "generated/panda/types"; 8 | import type { AssignJSXStyleProps } from "lib/types"; 9 | 10 | export interface ButtonProps 11 | extends AssignJSXStyleProps>, 12 | ButtonVariantProps {} 13 | 14 | /** 15 | * Interactive action button. 16 | */ 17 | export const Button = styled(ark.button, button); 18 | -------------------------------------------------------------------------------- /src/lib/theme/extensions/slotRecipes/clipboard.slotRecipe.ts: -------------------------------------------------------------------------------- 1 | import { clipboardAnatomy } from "@ark-ui/anatomy"; 2 | import { defineSlotRecipe } from "@pandacss/dev"; 3 | 4 | /** 5 | * Clipboard recipe. 6 | */ 7 | const clipboard = defineSlotRecipe({ 8 | className: "clipboard", 9 | description: "Clipboard style recipes", 10 | slots: clipboardAnatomy.keys(), 11 | base: { 12 | root: { 13 | display: "flex", 14 | flexDirection: "column", 15 | gap: 1.5, 16 | }, 17 | control: { 18 | display: "flex", 19 | gap: 3, 20 | }, 21 | }, 22 | }); 23 | 24 | export default clipboard; 25 | -------------------------------------------------------------------------------- /src/components/core/Textarea/Textarea.tsx: -------------------------------------------------------------------------------- 1 | import { ark } from "@ark-ui/react"; 2 | 3 | import { styled } from "generated/panda/jsx"; 4 | import { textarea } from "generated/panda/recipes"; 5 | 6 | import type { TextareaVariantProps } from "generated/panda/recipes"; 7 | import type { ComponentProps } from "generated/panda/types"; 8 | import type { AssignJSXStyleProps } from "lib/types"; 9 | 10 | export interface TextareaProps 11 | extends AssignJSXStyleProps>, 12 | TextareaVariantProps {} 13 | 14 | /** 15 | * Textarea. 16 | */ 17 | export const Textarea = styled(ark.textarea, textarea); 18 | -------------------------------------------------------------------------------- /src/components/typography/Code/Code.stories.tsx: -------------------------------------------------------------------------------- 1 | import pkg from "../../../../package.json"; 2 | import { Code } from "components"; 3 | 4 | import type { Meta, StoryObj } from "@storybook/react"; 5 | 6 | type Story = StoryObj; 7 | 8 | const meta = { 9 | title: "Components/Typography/Code", 10 | component: Code, 11 | tags: ["autodocs"], 12 | } satisfies Meta; 13 | 14 | export const Default: Story = { 15 | args: { 16 | children: pkg.name, 17 | }, 18 | }; 19 | 20 | export const Ghost: Story = { 21 | args: { 22 | ...Default.args, 23 | variant: "ghost", 24 | }, 25 | }; 26 | 27 | export default meta; 28 | -------------------------------------------------------------------------------- /src/lib/theme/extensions/slotRecipes/editable.slotRecipe.ts: -------------------------------------------------------------------------------- 1 | import { editableAnatomy } from "@ark-ui/anatomy"; 2 | import { defineSlotRecipe } from "@pandacss/dev"; 3 | 4 | /** 5 | * Editable recipe. 6 | */ 7 | const editable = defineSlotRecipe({ 8 | className: "editable", 9 | description: "Editable style recipes", 10 | slots: editableAnatomy.keys(), 11 | base: { 12 | root: { 13 | display: "flex", 14 | flexDirection: "column", 15 | gap: 1.5, 16 | width: "100%", 17 | }, 18 | control: { 19 | display: "flex", 20 | gap: 2, 21 | }, 22 | }, 23 | }); 24 | 25 | export default editable; 26 | -------------------------------------------------------------------------------- /src/components/typography/Keyboard/Keyboard.tsx: -------------------------------------------------------------------------------- 1 | import { ark } from "@ark-ui/react"; 2 | 3 | import { styled } from "generated/panda/jsx"; 4 | import { keyboard } from "generated/panda/recipes"; 5 | 6 | import type { KeyboardVariantProps } from "generated/panda/recipes"; 7 | import type { ComponentProps } from "generated/panda/types"; 8 | import type { AssignJSXStyleProps } from "lib/types"; 9 | 10 | export interface KeyboardProps 11 | extends AssignJSXStyleProps>, 12 | KeyboardVariantProps {} 13 | 14 | /** 15 | * Keyboard text representation. 16 | */ 17 | export const Keyboard = styled(ark.kbd, keyboard); 18 | -------------------------------------------------------------------------------- /src/lib/theme/extensions/recipes/index.ts: -------------------------------------------------------------------------------- 1 | export { default as badge } from "./badge.recipe"; 2 | export { default as button } from "./button.recipe"; 3 | export { default as code } from "./code.recipe"; 4 | export { default as icon } from "./icon.recipe"; 5 | export { default as input } from "./input.recipe"; 6 | export { default as keyboard } from "./keyboard.recipe"; 7 | export { default as label } from "./label.recipe"; 8 | export { default as link } from "./link.recipe"; 9 | export { default as skeleton } from "./skeleton.recipe"; 10 | export { default as text } from "./text.recipe"; 11 | export { default as textarea } from "./textarea.recipe"; 12 | -------------------------------------------------------------------------------- /src/stories/layout/Box.stories.tsx: -------------------------------------------------------------------------------- 1 | import { Text } from "components"; 2 | import { Box } from "generated/panda/jsx"; 3 | 4 | import type { Meta, StoryObj } from "@storybook/react"; 5 | 6 | type Story = StoryObj; 7 | 8 | /** 9 | * General box container. Renders a `div`. 10 | */ 11 | const meta = { 12 | title: "Components/Layout/Box", 13 | component: Box, 14 | tags: ["autodocs"], 15 | } satisfies Meta; 16 | 17 | export const Default: Story = { 18 | render: () => ( 19 | 20 | Hello! 21 | 22 | ), 23 | }; 24 | 25 | export default meta; 26 | -------------------------------------------------------------------------------- /src/components/core/Clipboard/Clipboard.stories.tsx: -------------------------------------------------------------------------------- 1 | import { Clipboard } from "components"; 2 | import { app } from "lib/config"; 3 | 4 | import type { Meta, StoryObj } from "@storybook/react"; 5 | 6 | type Story = StoryObj; 7 | 8 | const meta = { 9 | title: "Components/Core/Clipboard", 10 | component: Clipboard, 11 | tags: ["autodocs"], 12 | } satisfies Meta; 13 | 14 | export const Default: Story = { 15 | args: { 16 | value: app.organization.url, 17 | }, 18 | }; 19 | 20 | export const WithLabel: Story = { 21 | args: { 22 | ...Default.args, 23 | label: "Copy link", 24 | }, 25 | }; 26 | 27 | export default meta; 28 | -------------------------------------------------------------------------------- /src/stories/layout/Flex.stories.tsx: -------------------------------------------------------------------------------- 1 | import { Flex } from "generated/panda/jsx"; 2 | import { FruitBasket } from "stories/data"; 3 | 4 | import type { Meta, StoryObj } from "@storybook/react"; 5 | 6 | type Story = StoryObj; 7 | 8 | /** 9 | * General flex container. Renders a `div` with `display: flex`. 10 | */ 11 | const meta = { 12 | title: "Components/Layout/Flex", 13 | component: Flex, 14 | tags: ["autodocs"], 15 | } satisfies Meta; 16 | 17 | export const Default: Story = { 18 | args: { 19 | children: , 20 | align: "center", 21 | justify: "center", 22 | }, 23 | }; 24 | 25 | export default meta; 26 | -------------------------------------------------------------------------------- /src/lib/theme/extensions/recipes/skeleton.recipe.ts: -------------------------------------------------------------------------------- 1 | import { defineRecipe } from "@pandacss/dev"; 2 | 3 | /** 4 | * Skeleton recipe. 5 | */ 6 | const skeleton = defineRecipe({ 7 | className: "skeleton", 8 | description: "Skeleton style recipes", 9 | base: { 10 | animation: "skeleton-pulse", 11 | bgClip: "padding-box", 12 | bgColor: "background.emphasized", 13 | borderRadius: "md", 14 | color: "transparent", 15 | cursor: "default", 16 | pointerEvents: "none", 17 | userSelect: "none", 18 | "&::before, &::after, *": { 19 | visibility: "hidden", 20 | }, 21 | }, 22 | }); 23 | 24 | export default skeleton; 25 | -------------------------------------------------------------------------------- /src/stories/layout/HStack.stories.tsx: -------------------------------------------------------------------------------- 1 | import { HStack } from "generated/panda/jsx"; 2 | import { FruitBasket } from "stories/data"; 3 | 4 | import type { Meta, StoryObj } from "@storybook/react"; 5 | 6 | type Story = StoryObj; 7 | 8 | /** 9 | * Horizontally stack elements, and center them vertically. Wraps [Stack](?path=/docs/components-layout-stack--docs). 10 | */ 11 | const meta = { 12 | title: "Components/Layout/HStack", 13 | component: HStack, 14 | tags: ["autodocs"], 15 | } satisfies Meta; 16 | 17 | export const Default: Story = { 18 | args: { 19 | children: , 20 | gap: 4, 21 | }, 22 | }; 23 | 24 | export default meta; 25 | -------------------------------------------------------------------------------- /src/stories/layout/VStack.stories.tsx: -------------------------------------------------------------------------------- 1 | import { VStack } from "generated/panda/jsx"; 2 | import { FruitBasket } from "stories/data"; 3 | 4 | import type { Meta, StoryObj } from "@storybook/react"; 5 | 6 | type Story = StoryObj; 7 | 8 | /** 9 | * Vertically stack elements, and center them horizontally. Wraps [Stack](?path=/docs/components-layout-stack--docs). 10 | */ 11 | const meta = { 12 | title: "Components/Layout/VStack", 13 | component: VStack, 14 | tags: ["autodocs"], 15 | } satisfies Meta; 16 | 17 | export const Default: Story = { 18 | args: { 19 | children: , 20 | gap: 4, 21 | }, 22 | }; 23 | 24 | export default meta; 25 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | // inject root cascade layers 2 | import "lib/styles/main.css"; 3 | 4 | export * from "components"; 5 | export * from "lib/hooks"; 6 | 7 | // 🐼 export backfill of Panda components 8 | export * from "generated/panda/css"; 9 | export * from "generated/panda/jsx"; 10 | 11 | export type { JsxStyleProps } from "generated/panda/types"; 12 | 13 | // NB: `jsxFactory` in Panda config can be specified to customize the styled factory export name, however the default (`styled`) is intended, and this alias is exported as well 14 | export { styled as sigil } from "generated/panda/jsx"; 15 | 16 | // export Panda presets (to be used in downstream Panda configurations) 17 | export { sigilPreset } from "lib/theme/presets"; 18 | -------------------------------------------------------------------------------- /src/lib/theme/extensions/recipes/label.recipe.ts: -------------------------------------------------------------------------------- 1 | import { defineRecipe } from "@pandacss/dev"; 2 | 3 | /** 4 | * Label recipe. 5 | */ 6 | const label = defineRecipe({ 7 | className: "label", 8 | description: "Label style recipes", 9 | base: { 10 | color: "foreground.default", 11 | fontWeight: "medium", 12 | }, 13 | defaultVariants: { 14 | size: "md", 15 | }, 16 | variants: { 17 | size: { 18 | sm: { 19 | textStyle: "sm", 20 | }, 21 | md: { 22 | textStyle: "sm", 23 | }, 24 | lg: { 25 | textStyle: "sm", 26 | }, 27 | xl: { 28 | textStyle: "md", 29 | }, 30 | }, 31 | }, 32 | }); 33 | 34 | export default label; 35 | -------------------------------------------------------------------------------- /turbo/generators/templates/recipe/slotRecipe.ts.hbs: -------------------------------------------------------------------------------- 1 | import { defineSlotRecipe } from "@pandacss/dev"; 2 | 3 | /** 4 | * {{ pascalName }} recipe. 5 | */ 6 | const {{ camelName }} = defineSlotRecipe({ 7 | className: "{{ camelName }}", 8 | description: "{{ pascalName }} style recipes", 9 | slots: [ 10 | // TODO add slots here; if applicable, make sure to use and extend Ark anatomy slots (e.g. `{{ camelName }}Anatomy.extendWith("customSlot").keys()`) 11 | ], 12 | base: { 13 | // TODO add base styles here 14 | }, 15 | defaultVariants: { 16 | // TODO add default variants here 17 | }, 18 | variants: { 19 | // TODO add variants here 20 | }, 21 | }); 22 | 23 | export default {{ camelName }}; 24 | -------------------------------------------------------------------------------- /src/lib/theme/extensions/tokens/easings.tokens.ts: -------------------------------------------------------------------------------- 1 | import { defineTokens } from "@pandacss/dev"; 2 | 3 | import type { Tokens } from "@pandacss/dev"; 4 | 5 | /** 6 | * Easing function tokens. 7 | */ 8 | const easings: Tokens["easings"] = defineTokens.easings({ 9 | default: { value: "cubic-bezier(0.4, 0, 0.2, 1)" }, 10 | linear: { value: "linear" }, 11 | pulse: { value: "cubic-bezier(0.4, 0.0, 0.6, 1.0)" }, 12 | in: { value: "cubic-bezier(0.4, 0, 1, 1)" }, 13 | out: { value: "cubic-bezier(0, 0, 0.2, 1)" }, 14 | "in-out": { value: "cubic-bezier(0.4, 0, 0.2, 1)" }, 15 | "emphasized-in": { value: "cubic-bezier(0.05, 0.7, 0.1, 1)" }, 16 | "emphasized-out": { value: "cubic-bezier(0.3, 0, 0.8, 0.15)" }, 17 | }); 18 | 19 | export default easings; 20 | -------------------------------------------------------------------------------- /src/stories/layout/VisuallyHidden.stories.tsx: -------------------------------------------------------------------------------- 1 | import { VisuallyHidden } from "generated/panda/jsx"; 2 | 3 | import type { Meta, StoryObj } from "@storybook/react"; 4 | 5 | type Story = StoryObj; 6 | 7 | /** 8 | * Visually hide content, but keep it accessible to screen readers. Useful for a11y and SEO. 9 | */ 10 | const meta = { 11 | title: "Components/Layout/VisuallyHidden", 12 | component: VisuallyHidden, 13 | tags: ["autodocs"], 14 | } satisfies Meta; 15 | 16 | export const Default: Story = { 17 | render: () => ( 18 | <> 19 | Below is a visually-hidden title. 20 | 21 | Hidden title 22 | 23 | 24 | ), 25 | }; 26 | 27 | export default meta; 28 | -------------------------------------------------------------------------------- /src/stories/layout/Stack.stories.tsx: -------------------------------------------------------------------------------- 1 | import { Stack } from "generated/panda/jsx"; 2 | import { FruitBasket } from "stories/data"; 3 | 4 | import type { Meta, StoryObj } from "@storybook/react"; 5 | 6 | type Story = StoryObj; 7 | 8 | /** 9 | * Lay elements out vertically or horizontally. 10 | */ 11 | const meta = { 12 | title: "Components/Layout/Stack", 13 | component: Stack, 14 | tags: ["autodocs"], 15 | } satisfies Meta; 16 | 17 | export const Default: Story = { 18 | name: "Vertical (Default)", 19 | args: { 20 | children: , 21 | gap: 4, 22 | }, 23 | }; 24 | 25 | export const Horizontal: Story = { 26 | args: { 27 | ...Default.args, 28 | direction: "horizontal", 29 | }, 30 | }; 31 | 32 | export default meta; 33 | -------------------------------------------------------------------------------- /src/stories/layout/Wrap.stories.tsx: -------------------------------------------------------------------------------- 1 | import { Wrap } from "generated/panda/jsx"; 2 | import { FruitBasket } from "stories/data"; 3 | 4 | import type { Meta, StoryObj } from "@storybook/react"; 5 | 6 | type Story = StoryObj; 7 | 8 | /** 9 | * Add space between elements, and automatically wrap if there isn't enough space. 10 | */ 11 | const meta = { 12 | title: "Components/Layout/Wrap", 13 | component: Wrap, 14 | tags: ["autodocs"], 15 | } satisfies Meta; 16 | 17 | export const Default: Story = { 18 | render: () => ( 19 | 20 | {Array(30) 21 | .fill(null) 22 | .map((i) => ( 23 | 24 | ))} 25 | 26 | ), 27 | }; 28 | 29 | export default meta; 30 | -------------------------------------------------------------------------------- /src/lib/theme/extensions/tokens/fontSizes.tokens.ts: -------------------------------------------------------------------------------- 1 | import { defineTokens } from "@pandacss/dev"; 2 | 3 | import type { Tokens } from "@pandacss/dev"; 4 | 5 | /** 6 | * Font size tokens. 7 | */ 8 | const fontSizes: Tokens["fontSizes"] = defineTokens.fontSizes({ 9 | "2xs": { value: "0.5rem" }, 10 | xs: { value: "0.75rem" }, 11 | sm: { value: "0.875rem" }, 12 | md: { value: "1rem" }, 13 | lg: { value: "1.125rem" }, 14 | xl: { value: "1.25rem" }, 15 | "2xl": { value: "1.5rem" }, 16 | "3xl": { value: "1.875rem" }, 17 | "4xl": { value: "2.25rem" }, 18 | "5xl": { value: "3rem" }, 19 | "6xl": { value: "3.75rem" }, 20 | "7xl": { value: "4.5rem" }, 21 | "8xl": { value: "6rem" }, 22 | "9xl": { value: "8rem" }, 23 | }); 24 | 25 | export default fontSizes; 26 | -------------------------------------------------------------------------------- /src/components/core/Splitter/Splitter.stories.tsx: -------------------------------------------------------------------------------- 1 | import { Splitter } from "components"; 2 | 3 | import type { Meta, StoryObj } from "@storybook/react"; 4 | 5 | type Story = StoryObj; 6 | 7 | const meta = { 8 | title: "Components/Core/Splitter", 9 | component: Splitter, 10 | tags: ["autodocs"], 11 | } satisfies Meta; 12 | 13 | // TODO add multiple orientations of panels & splitters in a single story 14 | export const Default: Story = { 15 | args: { 16 | orientation: "horizontal", 17 | sections: [ 18 | { sectionType: "panel", id: "a", content: "A", minSize: 20 }, 19 | { sectionType: "resizeTrigger", id: "a:b" }, 20 | { sectionType: "panel", id: "b", content: "B", minSize: 20 }, 21 | ], 22 | }, 23 | }; 24 | 25 | export default meta; 26 | -------------------------------------------------------------------------------- /src/lib/styles/main.css: -------------------------------------------------------------------------------- 1 | /* https://panda-css.com/docs/concepts/cascade-layers */ 2 | @layer reset, base, tokens, recipes, utilities; 3 | 4 | /* TODO move below styles to panda.config */ 5 | 6 | :root { 7 | /* alias fonts to CSS variables */ 8 | --font-assistant: "Assistant", sans-serif; 9 | --font-fira-code: "Fira Code", monospace; 10 | 11 | /* semantic */ 12 | --font-primary: var(--font-assistant); 13 | --font-code: var(--font-fira-code); 14 | } 15 | 16 | @font-face { 17 | font-family: "Assistant"; 18 | src: url("../assets/fonts/assistant-variable.ttf") format("truetype"); 19 | font-display: swap; 20 | } 21 | 22 | @font-face { 23 | font-family: "Fira Code"; 24 | src: url("../assets/fonts/fira-code-variable.ttf") format("truetype"); 25 | font-display: swap; 26 | } 27 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Test 🧪 2 | 3 | on: 4 | push: 5 | branches: [master] 6 | pull_request: 7 | branches: [master] 8 | 9 | jobs: 10 | test: 11 | name: Run Storybook tests 🃏 12 | timeout-minutes: 60 13 | # TODO update to `ubuntu-latest`; "Install Playwright" step fails 14 | runs-on: ubuntu-24.04 15 | steps: 16 | - uses: actions/checkout@v4 17 | - uses: oven-sh/setup-bun@v2 18 | - name: Install dependencies 19 | run: bun i 20 | - name: Install Playwright 21 | run: bunx playwright install --with-deps 22 | - name: Build Storybook 23 | # https://github.com/storybookjs/storybook/issues/6408 24 | run: bun storybook:build --quiet 25 | - name: Serve Storybook and run tests 26 | run: bun test:ci 27 | -------------------------------------------------------------------------------- /src/components/typography/Text/Text.tsx: -------------------------------------------------------------------------------- 1 | import { styled } from "generated/panda/jsx"; 2 | import { text, type TextVariantProps } from "generated/panda/recipes"; 3 | 4 | import type { HTMLStyledProps, StyledComponent } from "generated/panda/jsx"; 5 | 6 | export type TagVariants = 7 | | "h1" 8 | | "h2" 9 | | "h3" 10 | | "h4" 11 | | "h5" 12 | | "h6" 13 | | "p" 14 | | "span"; 15 | 16 | export type TextProps = { 17 | /** HTML text tag to render, affecting semantic markup. */ 18 | as?: TagVariants; 19 | } & TextVariantProps & 20 | HTMLStyledProps; 21 | 22 | /** 23 | * Text. 24 | */ 25 | export const Text = ({ as = "p", ...rest }: TextProps) => { 26 | const StyledText = styled(as, text) as StyledComponent; 27 | 28 | return ; 29 | }; 30 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 🏗️ 2 | 3 | on: 4 | push: 5 | branches: [master] 6 | 7 | concurrency: ${{ github.workflow }}-${{ github.ref }} 8 | 9 | jobs: 10 | release: 11 | name: Handle release 🦋 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v4 15 | - uses: oven-sh/setup-bun@v2 16 | - name: Install dependencies 17 | run: bun i 18 | - name: Create release PR or publish package 19 | id: changesets 20 | uses: changesets/action@v1 21 | with: 22 | publish: bun release 23 | title: "feature(release): version packages" 24 | commit: "ci(changesets): version packages" 25 | env: 26 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 27 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }} 28 | -------------------------------------------------------------------------------- /src/lib/theme/extensions/slotRecipes/collapsible.slotRecipe.ts: -------------------------------------------------------------------------------- 1 | import { collapsibleAnatomy } from "@ark-ui/anatomy"; 2 | import { defineSlotRecipe } from "@pandacss/dev"; 3 | 4 | /** 5 | * Collapsible recipe. 6 | */ 7 | const collapsible = defineSlotRecipe({ 8 | className: "collapsible", 9 | description: "Collapsible style recipes", 10 | slots: collapsibleAnatomy.keys(), 11 | base: { 12 | root: { 13 | alignItems: "flex-start", 14 | display: "flex", 15 | flexDirection: "column", 16 | width: "full", 17 | }, 18 | content: { 19 | overflow: "hidden", 20 | width: "full", 21 | _open: { 22 | animation: "collapse-in", 23 | }, 24 | _closed: { 25 | animation: "collapse-out", 26 | }, 27 | }, 28 | }, 29 | }); 30 | 31 | export default collapsible; 32 | -------------------------------------------------------------------------------- /src/components/core/Editable/Editable.stories.tsx: -------------------------------------------------------------------------------- 1 | import { Editable } from "components"; 2 | 3 | import type { Meta, StoryObj } from "@storybook/react"; 4 | type Story = StoryObj; 5 | 6 | const meta = { 7 | title: "Components/Core/Editable", 8 | component: Editable, 9 | tags: ["autodocs"], 10 | } satisfies Meta; 11 | 12 | export const Default: Story = { 13 | args: { 14 | placeholder: "Enter your name...", 15 | defaultValue: "Click here to edit", 16 | }, 17 | }; 18 | 19 | export const DoubleClick: Story = { 20 | args: { 21 | ...Default.args, 22 | activationMode: "dblclick", 23 | defaultValue: "Double click here to edit", 24 | }, 25 | }; 26 | 27 | export const WithLabel: Story = { 28 | args: { 29 | ...Default.args, 30 | label: "Name", 31 | }, 32 | }; 33 | 34 | export default meta; 35 | -------------------------------------------------------------------------------- /src/components/core/Switch/Switch.stories.tsx: -------------------------------------------------------------------------------- 1 | import { Switch } from "components"; 2 | 3 | import type { Meta, StoryObj } from "@storybook/react"; 4 | 5 | type Story = StoryObj; 6 | 7 | const meta = { 8 | title: "Components/Core/Switch", 9 | component: Switch, 10 | tags: ["autodocs"], 11 | } satisfies Meta; 12 | 13 | export const Default: Story = { 14 | args: { 15 | label: "Label", 16 | }, 17 | }; 18 | 19 | export const DefaultChecked: Story = { 20 | args: { 21 | ...Default.args, 22 | defaultChecked: true, 23 | }, 24 | }; 25 | 26 | /** 27 | * A custom color palette can be applied to atomically modify the base color. 28 | */ 29 | export const CustomColorPalette: Story = { 30 | args: { 31 | ...DefaultChecked.args, 32 | colorPalette: "lime", 33 | }, 34 | }; 35 | 36 | export default meta; 37 | -------------------------------------------------------------------------------- /src/stories/layout/Container.stories.tsx: -------------------------------------------------------------------------------- 1 | import { Container } from "generated/panda/jsx"; 2 | 3 | import type { Meta, StoryObj } from "@storybook/react"; 4 | 5 | type Story = StoryObj; 6 | 7 | /** 8 | * Max-width, centered container designed for page content. 9 | */ 10 | const meta = { 11 | title: "Components/Layout/Container", 12 | component: Container, 13 | tags: ["autodocs"], 14 | } satisfies Meta; 15 | 16 | export const Default: Story = { 17 | render: () => ( 18 | 19 | Lorem ipsum dolor sit amet, consectetur adipisicing elit. Fugiat veritatis 20 | ullam tenetur? Ipsam aut nulla eius eaque molestiae doloribus, dolor 21 | repudiandae consectetur harum quibusdam fuga doloremque corporis nisi odio 22 | earum! 23 | 24 | ), 25 | }; 26 | 27 | export default meta; 28 | -------------------------------------------------------------------------------- /src/lib/theme/conditions.theme.ts: -------------------------------------------------------------------------------- 1 | import type { Preset } from "@pandacss/types"; 2 | 3 | /** 4 | * Conditions. 5 | * @see https://panda-css.com/docs/concepts/conditional-styles#reference for all available condition keys. 6 | */ 7 | const conditions: Preset["conditions"] = { 8 | extend: { 9 | current: "&:is([data-current])", 10 | hidden: "&:is([hidden])", 11 | hover: [ 12 | "@media (hover: hover) and (pointer: fine)", 13 | "&:is(:hover, [data-hover])", 14 | ], 15 | indeterminate: 16 | "&:is(:indeterminate, [data-indeterminate], [aria-checked=mixed], [data-state=indeterminate])", 17 | off: '&:is([data-state="off"])', 18 | on: '&:is([data-state="on"])', 19 | today: "&:is([data-today])", 20 | underValue: '&:is([data-state="under-value"])', 21 | }, 22 | }; 23 | 24 | export default conditions; 25 | -------------------------------------------------------------------------------- /src/stories/layout/Divider.stories.tsx: -------------------------------------------------------------------------------- 1 | import { Center, Divider } from "generated/panda/jsx"; 2 | 3 | import type { Meta, StoryObj } from "@storybook/react"; 4 | 5 | type Story = StoryObj; 6 | 7 | const dividerProps = { 8 | color: "brand.primary", 9 | thickness: "2", 10 | }; 11 | 12 | /** 13 | * Horizontal or vertical divider. 14 | */ 15 | const meta = { 16 | title: "Components/Layout/Divider", 17 | component: Divider, 18 | tags: ["autodocs"], 19 | } satisfies Meta; 20 | 21 | export const Default: Story = { 22 | name: "Horizontal (Default)", 23 | render: () => , 24 | }; 25 | 26 | export const Vertical: Story = { 27 | render: () => ( 28 |

29 | 30 |
31 | ), 32 | }; 33 | 34 | export default meta; 35 | -------------------------------------------------------------------------------- /src/stories/layout/Center.stories.tsx: -------------------------------------------------------------------------------- 1 | import { Center } from "generated/panda/jsx"; 2 | import { FruitBasket } from "stories/data"; 3 | 4 | import type { Meta, StoryObj } from "@storybook/react"; 5 | 6 | type Story = StoryObj; 7 | 8 | /** 9 | * Container for centering elements. 10 | */ 11 | const meta = { 12 | title: "Components/Layout/Center", 13 | component: Center, 14 | tags: ["autodocs"], 15 | } satisfies Meta; 16 | 17 | /** 18 | * Center elements both vertically and horizontally. 19 | */ 20 | export const Default: Story = { 21 | render: () => ( 22 |
23 | 24 |
25 | ), 26 | }; 27 | 28 | /** 29 | * `inline-flex` display. 30 | */ 31 | export const Inline: Story = { 32 | render: () => ( 33 |
34 | 35 |
36 | ), 37 | }; 38 | 39 | export default meta; 40 | -------------------------------------------------------------------------------- /src/lib/util/hexToRgba.ts: -------------------------------------------------------------------------------- 1 | interface Params { 2 | /** Input hexadecimal string. */ 3 | hex: `#${string}`; 4 | /** Alpha (transparency) value (clamp to 0-1). Defaults to 1. */ 5 | alpha?: number; 6 | /** Optional function to apply to each component (r, g, b). */ 7 | componentFactory?: (component: number) => number; 8 | } 9 | 10 | /** 11 | * Convert a hexadecimal value (e.g. color code) to its `rgba` equivalent. 12 | * Note that shorthand hex values are unsupported; input hex must be 6 characters long. 13 | */ 14 | const hexToRgba = ({ 15 | hex, 16 | alpha = 1, 17 | componentFactory = (component) => component, 18 | }: Params) => { 19 | const [r, g, b] = hex.match(/\w\w/g)!.map((x) => parseInt(x, 16)); 20 | 21 | return `rgba(${componentFactory(r)}, ${componentFactory( 22 | g, 23 | )}, ${componentFactory(b)}, ${alpha})`; 24 | }; 25 | 26 | export default hexToRgba; 27 | -------------------------------------------------------------------------------- /src/components/typography/Keyboard/Keyboard.stories.tsx: -------------------------------------------------------------------------------- 1 | import { Keyboard } from "components"; 2 | import { Flex } from "generated/panda/jsx"; 3 | 4 | import type { Meta, StoryObj } from "@storybook/react"; 5 | 6 | type Story = StoryObj; 7 | 8 | const meta = { 9 | title: "Components/Typography/Keyboard", 10 | component: Keyboard, 11 | tags: ["autodocs"], 12 | } satisfies Meta; 13 | 14 | export const Default: Story = { 15 | args: { 16 | children: "Ctrl + Shift + P", 17 | }, 18 | }; 19 | 20 | export const MultipleKeys: Story = { 21 | render: () => ( 22 | 23 | Ctrl 24 | Shift 25 | P 26 | 27 | ), 28 | }; 29 | 30 | export const Ghost: Story = { 31 | args: { 32 | ...Default.args, 33 | variant: "ghost", 34 | }, 35 | }; 36 | 37 | export default meta; 38 | -------------------------------------------------------------------------------- /src/lib/theme/extensions/tokens/zIndex.tokens.ts: -------------------------------------------------------------------------------- 1 | import { defineTokens } from "@pandacss/dev"; 2 | 3 | import type { Tokens } from "@pandacss/dev"; 4 | 5 | /** 6 | * Z-index tokens. 7 | */ 8 | const zIndex: Tokens["zIndex"] = defineTokens.zIndex({ 9 | hide: { 10 | value: -1, 11 | }, 12 | base: { 13 | value: 0, 14 | }, 15 | foreground: { 16 | value: 1, 17 | }, 18 | docked: { 19 | value: 10, 20 | }, 21 | dropdown: { 22 | value: 1000, 23 | }, 24 | sticky: { 25 | value: 1100, 26 | }, 27 | banner: { 28 | value: 1200, 29 | }, 30 | overlay: { 31 | value: 1300, 32 | }, 33 | dialog: { 34 | value: 1400, 35 | }, 36 | popover: { 37 | value: 1500, 38 | }, 39 | skipLink: { 40 | value: 1600, 41 | }, 42 | toast: { 43 | value: 1700, 44 | }, 45 | tooltip: { 46 | value: 1800, 47 | }, 48 | }); 49 | 50 | export default zIndex; 51 | -------------------------------------------------------------------------------- /src/lib/theme/extensions/recipes/icon.recipe.ts: -------------------------------------------------------------------------------- 1 | import { defineRecipe } from "@pandacss/dev"; 2 | 3 | /** 4 | * Icon recipe. 5 | */ 6 | const icon = defineRecipe({ 7 | className: "icon", 8 | description: "Icon style recipes", 9 | base: { 10 | display: "inline-block", 11 | flexShrink: 0, 12 | verticalAlign: "middle", 13 | lineHeight: "1em", 14 | }, 15 | defaultVariants: { 16 | size: "md", 17 | }, 18 | variants: { 19 | size: { 20 | xs: { 21 | w: 3, 22 | h: 3, 23 | }, 24 | sm: { 25 | w: 4, 26 | h: 4, 27 | }, 28 | md: { 29 | w: 5, 30 | h: 5, 31 | }, 32 | lg: { 33 | w: 6, 34 | h: 6, 35 | }, 36 | xl: { 37 | w: 7, 38 | h: 7, 39 | }, 40 | "2xl": { 41 | w: 8, 42 | h: 8, 43 | }, 44 | }, 45 | }, 46 | }); 47 | 48 | export default icon; 49 | -------------------------------------------------------------------------------- /knip.config.ts: -------------------------------------------------------------------------------- 1 | import type { KnipConfig } from "knip"; 2 | 3 | // TODO integrate `knip` into CI 4 | 5 | /** 6 | * Knip configuration. 7 | * @see https://knip.dev/overview/configuration 8 | */ 9 | const knipConfig: KnipConfig = { 10 | ignoreDependencies: [ 11 | // used for local packaging 12 | "@omnidev/knit", 13 | // used in MDX 14 | "@storybook/addon-docs", 15 | // used in MDX 16 | "@storybook/blocks", 17 | // used in Storybook test CI 18 | "http-server", 19 | ], 20 | ignore: [ 21 | "panda.config.ts", 22 | "*.config.*", 23 | ".github/**", 24 | "examples/**", 25 | // `ComponentVariants` marked as unused, but it is required for downstream type mapping 26 | "src/lib/util/createStyleContext.tsx", 27 | // theme extensions are used in barrels 28 | "src/lib/theme/extensions/**", 29 | "src/lib/config/env.config.ts", 30 | ], 31 | }; 32 | 33 | export default knipConfig; 34 | -------------------------------------------------------------------------------- /src/components/core/Collapsible/Collapsible.stories.tsx: -------------------------------------------------------------------------------- 1 | import { Button, Collapsible } from "components"; 2 | import { Box } from "generated/panda/jsx"; 3 | 4 | import type { Meta, StoryObj } from "@storybook/react"; 5 | 6 | type Story = StoryObj; 7 | 8 | const meta = { 9 | title: "Components/Core/Collapsible", 10 | component: Collapsible, 11 | tags: ["autodocs"], 12 | } satisfies Meta; 13 | 14 | export const Default: Story = { 15 | args: { 16 | trigger: , 17 | children: ( 18 | 25 | Hey there! 26 | 27 | ), 28 | }, 29 | }; 30 | 31 | export const DefaultOpen: Story = { 32 | args: { 33 | ...Default.args, 34 | defaultOpen: true, 35 | }, 36 | }; 37 | 38 | export default meta; 39 | -------------------------------------------------------------------------------- /.storybook/theme.ts: -------------------------------------------------------------------------------- 1 | import { create as createStorybookTheme } from "@storybook/theming"; 2 | 3 | import { app } from "../src/lib/config"; 4 | import { fonts } from "../src/lib/theme/extensions/semanticTokens"; 5 | 6 | import type { ThemeVars } from "@storybook/theming"; 7 | 8 | const typography: Pick = { 9 | fontBase: fonts!["primary"].value as string, 10 | fontCode: fonts!["code"].value as string, 11 | }; 12 | 13 | /** 14 | * Custom Storybook theme. 15 | */ 16 | const storybookTheme = createStorybookTheme({ 17 | ...typography, 18 | // set dark theme default 19 | base: "dark", 20 | brandUrl: app.organization.url, 21 | brandTitle: `
${app.organization.name} ${app.name.short}
`, 22 | brandTarget: "_self", 23 | }); 24 | 25 | export default storybookTheme; 26 | -------------------------------------------------------------------------------- /src/components/core/Link/Link.tsx: -------------------------------------------------------------------------------- 1 | import { ark } from "@ark-ui/react"; 2 | 3 | import { styled } from "generated/panda/jsx"; 4 | import { link } from "generated/panda/recipes"; 5 | 6 | import type { LinkVariantProps } from "generated/panda/recipes"; 7 | import type { ComponentProps } from "generated/panda/types"; 8 | import type { AssignJSXStyleProps } from "lib/types"; 9 | 10 | const LinkRoot = styled(ark.a, link); 11 | export interface LinkRootProps 12 | extends AssignJSXStyleProps>, 13 | LinkVariantProps {} 14 | 15 | export interface LinkProps extends LinkRootProps { 16 | isExternal?: boolean; 17 | } 18 | 19 | /** 20 | * External link props. 21 | */ 22 | const externalLinkProps = { 23 | target: "_blank", 24 | rel: "noopener noreferrer", 25 | }; 26 | 27 | /** 28 | * Hyperlink. 29 | */ 30 | export const Link = ({ isExternal = false, ...rest }: LinkProps) => ( 31 | 32 | ); 33 | -------------------------------------------------------------------------------- /src/lib/theme/extensions/tokens/sizes.tokens.ts: -------------------------------------------------------------------------------- 1 | import { defineTokens } from "@pandacss/dev"; 2 | 3 | import spacing from "./spacing.tokens"; 4 | 5 | import type { Tokens } from "@pandacss/dev"; 6 | 7 | /** 8 | * Size tokens. 9 | */ 10 | const sizes: Tokens["sizes"] = defineTokens.sizes({ 11 | // enable parity with spacing tokens 12 | ...spacing, 13 | full: { value: "100%" }, 14 | min: { value: "min-content" }, 15 | max: { value: "max-content" }, 16 | fit: { value: "fit-content" }, 17 | prose: { value: "65ch" }, 18 | "2xs": { value: "16rem" }, 19 | xs: { value: "20rem" }, 20 | sm: { value: "24rem" }, 21 | md: { value: "28rem" }, 22 | lg: { value: "32rem" }, 23 | xl: { value: "36rem" }, 24 | "2xl": { value: "42rem" }, 25 | "3xl": { value: "48rem" }, 26 | "4xl": { value: "56rem" }, 27 | "5xl": { value: "64rem" }, 28 | "6xl": { value: "72rem" }, 29 | "7xl": { value: "80rem" }, 30 | "8xl": { value: "90rem" }, 31 | }); 32 | 33 | export default sizes; 34 | -------------------------------------------------------------------------------- /src/components/core/Input/Input.stories.tsx: -------------------------------------------------------------------------------- 1 | import { Input, Label } from "components"; 2 | import { Stack } from "generated/panda/jsx"; 3 | 4 | import type { Meta, StoryObj } from "@storybook/react"; 5 | 6 | type Story = StoryObj; 7 | 8 | const meta = { 9 | title: "Components/Core/Input", 10 | component: Input, 11 | tags: ["autodocs"], 12 | } satisfies Meta; 13 | 14 | export const Default: Story = { 15 | render: () => ( 16 | 17 | 18 | 19 | 20 | ), 21 | }; 22 | 23 | /** 24 | * A custom color palette can be applied to atomically modify the base color. 25 | */ 26 | export const CustomColorPalette: Story = { 27 | render: () => ( 28 | 29 | 30 | 31 | 32 | ), 33 | }; 34 | 35 | export default meta; 36 | -------------------------------------------------------------------------------- /src/lib/theme/extensions/recipes/link.recipe.ts: -------------------------------------------------------------------------------- 1 | import { defineRecipe } from "@pandacss/dev"; 2 | 3 | /** 4 | * Link recipe. 5 | */ 6 | const link = defineRecipe({ 7 | className: "link", 8 | description: "Link style recipes", 9 | base: { 10 | alignItems: "center", 11 | // ? only color this if text? see https://github.com/cschroeter/park-ui/issues/118#issuecomment-1856872877 12 | color: "colorPalette.default", 13 | colorPalette: "accent", 14 | cursor: "pointer", 15 | display: "inline-flex", 16 | fontWeight: "medium", 17 | gap: 2, 18 | textDecoration: "underline 0.1em transparent", 19 | textUnderlineOffset: "0.125em", 20 | transitionDuration: "normal", 21 | transitionProperty: "text-decoration-color", 22 | transitionTimingFunction: "default", 23 | _hover: { 24 | textDecorationColor: "colorPalette.default", 25 | }, 26 | "& svg": { 27 | width: "1em", 28 | height: "1em", 29 | }, 30 | }, 31 | }); 32 | 33 | export default link; 34 | -------------------------------------------------------------------------------- /src/lib/theme/extensions/slotRecipes/tooltip.slotRecipe.ts: -------------------------------------------------------------------------------- 1 | import { tooltipAnatomy } from "@ark-ui/anatomy"; 2 | import { defineSlotRecipe } from "@pandacss/dev"; 3 | 4 | // TODO size variants 5 | 6 | /** 7 | * Tooltip recipe. 8 | */ 9 | const tooltip = defineSlotRecipe({ 10 | className: "tooltip", 11 | description: "Tooltip style recipes", 12 | slots: tooltipAnatomy.extendWith("root").keys(), 13 | base: { 14 | content: { 15 | "--tooltip-background": "colors.background.muted", 16 | bgColor: "var(--tooltip-background)", 17 | borderRadius: "md", 18 | boxShadow: "lg", 19 | maxW: 80, 20 | p: 2, 21 | position: "relative", 22 | _open: { 23 | animation: "fadeIn 0.25s ease-out", 24 | }, 25 | _closed: { 26 | animation: "fadeOut 0.2s ease-out", 27 | }, 28 | }, 29 | arrow: { 30 | "--arrow-size": "12px", 31 | "--arrow-background": "var(--tooltip-background)", 32 | }, 33 | }, 34 | }); 35 | 36 | export default tooltip; 37 | -------------------------------------------------------------------------------- /src/components/core/Textarea/Textarea.stories.tsx: -------------------------------------------------------------------------------- 1 | import { Label, Textarea } from "components"; 2 | import { Stack } from "generated/panda/jsx"; 3 | 4 | import type { Meta, StoryObj } from "@storybook/react"; 5 | 6 | type Story = StoryObj; 7 | 8 | const meta = { 9 | title: "Components/Core/Textarea", 10 | component: Textarea, 11 | tags: ["autodocs"], 12 | } satisfies Meta; 13 | 14 | export const Default: Story = { 15 | render: () => ( 16 | 17 | 18 |