Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 16 additions & 1 deletion .storybook/main.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -73,14 +73,29 @@ const config = {

config.module.rules.push({
test: /\.scss$/,
use: ['style-loader', 'css-loader', 'sass-loader']
use: [
'style-loader',
'css-loader',
{
loader: 'sass-loader',
options: {
sassOptions: {
includePaths: [path.resolve(__dirname, '..')]
}
}
}
]
});

config.resolve.alias = {
...config.resolve.alias,
'~': path.resolve(__dirname, '../src'),
'~/components': path.resolve(__dirname, '../src/components')
};
config.resolve.modules = [
...(config.resolve.modules ?? []),
path.resolve(__dirname, '..')
];
return config;
},
framework: {
Expand Down
10 changes: 8 additions & 2 deletions .storybook/preview.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import '../main.tailwind.css';
import '../src/design-systems/clarity/default.scss';
import '../src/design-systems/baremetal/default.scss';

/** @type { import('@storybook/react-webpack5').Preview } */
const preview = {
Expand All @@ -15,8 +16,13 @@ const preview = {
},

decorators: [
// Adds theme switching support.
// NOTE: requires setting "darkMode" to "class" in your tailwind config
(Story) => {
if (typeof document !== 'undefined') {
document.body.setAttribute('data-rad-ui-design-system', 'clarity');
}

return Story();
}
]
};

Expand Down
13 changes: 13 additions & 0 deletions agents/development/sync-storybook-releases.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Sync Storybook Component Release Status

This document contains instuctions on how to sync the component release status on storybook.

For more details on how Rad UI components and their lifecyles works check out [Rad UI Component Lifecycle](knowledge/releases/how-rad-ui-releases-are-made.md).
Comment thread
kotAPI marked this conversation as resolved.

## Syncing
In Storybook, we care only about 2 categories to keep things simple

1. WIP - All the components that arent released yet fall in this bucket
2. Components - All the components that are released fall in this bucket

Sync storybook by making sure that the components are placed in the correct category.
31 changes: 31 additions & 0 deletions knowledge/releases/how-rad-ui-releases-are-made.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Rad UI Release stages

## Phase 1 - WIP
These components are work in progress and are not ready for production use.

## Phase 2 - Beta
These components are packaged and are bundled in the production build, but are not publicly announced regarding its availability. It is available for use if the consumer knows about it but at their own risk. These are generally meant for the library authors to test them out in internal experiments and apps before making them public.

## Phase 3 - Preview
These are released to the public, ideally gearing up for production release, but use with caution as they are still subject to change.

## Phase 4 - Stable
These are released and officially documented on the docs website. These components are production ready and can be used in production applications.

# Other release types

## Deprecated
These components will be removed in a future release. They are still available for use but are not recommended for use.

## Removed
These components have been removed from the library and are no longer available for use.



# Workflow

On Storybook, non stable components are put inside "WIP" category, until they are released they stay there. Once they are released they are placed inside "Components" category.
Comment thread
kotAPI marked this conversation as resolved.

What defines a released component?
1. The component name is part of scripts/RELEASED_COMPONENTS.cjs
2. The component is documented on the docs website
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"types": "./dist/index.d.ts"
},
"./themes/default.css": "./dist/themes/default.css",
"./themes/baremetal.css": "./dist/themes/baremetal.css",
"./themes/tailwind-presets/default.js": "./dist/themes/tailwind-presets/default.js",
"./Accordion": {
"import": "./dist/components/Accordion.js",
Expand Down Expand Up @@ -451,4 +452,4 @@
"eslint": "$eslint"
}
}
}
}
14 changes: 9 additions & 5 deletions rollup-css.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,12 @@ import postcss from 'rollup-plugin-postcss';
import path from 'path';
import { fileURLToPath } from 'url';

// Get the directory name of the current module
const __dirname = path.dirname(fileURLToPath(import.meta.url));

export default {
input: 'src/design-systems/clarity/default.scss',
const createThemeConfig = (input, file) => ({
input,
output: {
file: 'dist/themes/default.css'
file
},
onwarn(warning, warn) {
// Suppress CSS file overwrite warnings
Expand Down Expand Up @@ -38,4 +37,9 @@ export default {
}
})
]
};
});

export default [
createThemeConfig('src/design-systems/clarity/default.scss', 'dist/themes/default.css'),
createThemeConfig('src/design-systems/baremetal/default.scss', 'dist/themes/baremetal.css')
];
1 change: 1 addition & 0 deletions scripts/generate-exports.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ exportsMap['.'] = {

// Add theme exports
exportsMap['./themes/default.css'] = './dist/themes/default.css';
exportsMap['./themes/baremetal.css'] = './dist/themes/baremetal.css';
exportsMap['./themes/tailwind-presets/default.js'] = './dist/themes/tailwind-presets/default.js';

const notReleasedComponents = [];
Expand Down
179 changes: 108 additions & 71 deletions src/components/tools/SandboxEditor/SandboxEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,18 +43,26 @@ const ColorSelect = ({ color, isDarkMode, isSelected }: ColorSelectProps) => {
};

type SandboxProps = { className?: string } & PropsWithChildren
type DesignSystem = 'clarity' | 'baremetal'

const SandboxEditor = ({ children, className }: SandboxProps) => {
const [isDarkMode, setIsDarkMode] = useState(false);
const [isCondensed, setIsCondensed] = useState(false);
const [designSystem, setDesignSystem] = useState<DesignSystem>('clarity');

type AvailableColors = keyof typeof colors

const [colorName, setColorName] = useState<AvailableColors>('gray');

useEffect(() => {
const isDarkMode = localStorage.getItem('isDarkMode') === 'true';
const savedDesignSystem = localStorage.getItem('radUiDesignSystem');

setIsDarkMode(isDarkMode);

if (savedDesignSystem === 'clarity' || savedDesignSystem === 'baremetal') {
setDesignSystem(savedDesignSystem);
}
}, []);

useEffect(() => {
Expand All @@ -73,85 +81,114 @@ const SandboxEditor = ({ children, className }: SandboxProps) => {
setIsDarkMode(!isDarkMode);
};

return <Theme
appearance={isDarkMode ? 'dark' : 'light'}
accentColor={colorName}>
<div className='min-h-screen border border-gray-300 bg-gray-50 p-3 shadow-sm text-gray-900 sm:p-4'>
<div
className={`sticky top-0 z-20 mb-2 ${isCondensed ? 'pb-2' : ''}`.trim()}
>
const updateDesignSystem = (value: string) => {
if (value !== 'clarity' && value !== 'baremetal') {
return;
}

localStorage.setItem('radUiDesignSystem', value);
setDesignSystem(value);
};

return <div data-rad-ui-design-system={designSystem}>
<Theme
appearance={isDarkMode ? 'dark' : 'light'}
accentColor={colorName}>
<div className='min-h-screen border border-gray-300 bg-gray-50 p-3 shadow-sm text-gray-900 sm:p-4'>
<div
className={`rounded-xl border border-transparent bg-[color:color-mix(in_oklab,var(--rad-ui-surface-canvas)_82%,transparent)] backdrop-blur supports-[backdrop-filter]:bg-[color:color-mix(in_oklab,var(--rad-ui-surface-canvas)_72%,transparent)] ${isCondensed ? 'px-3 py-2 shadow-sm' : 'px-0 py-0 shadow-none'}`.trim()}
className={`sticky top-0 z-20 mb-2 ${isCondensed ? 'pb-2' : ''}`.trim()}
>
<div className='flex items-start justify-between gap-2'>
<div className='flex min-w-0 items-center space-x-3'>
<div className='text-gray-1000 shrink-0'>
<RadUILogo/>
<div
className={`rounded-xl border border-transparent bg-[color:color-mix(in_oklab,var(--rad-ui-surface-canvas)_82%,transparent)] backdrop-blur supports-[backdrop-filter]:bg-[color:color-mix(in_oklab,var(--rad-ui-surface-canvas)_72%,transparent)] ${isCondensed ? 'px-3 py-2 shadow-sm' : 'px-0 py-0 shadow-none'}`.trim()}
>
<div className='flex items-start justify-between gap-2'>
<div className='flex min-w-0 items-center space-x-3'>
<div className='text-gray-1000 shrink-0'>
<RadUILogo/>
</div>
<Separator orientation='vertical' className={isCondensed ? 'opacity-60' : 'opacity-100'} />
<div className='min-w-0'>
<Heading as='h1' className={`font-semibold leading-none tracking-tight text-gray-1000 ${isCondensed ? 'text-xl sm:text-2xl' : 'text-3xl sm:text-4xl'}`.trim()}>
Sandbox Editor
</Heading>
<Text className={`mt-0.5 font-normal leading-tight text-gray-950 ${isCondensed ? 'hidden' : 'text-sm'}`.trim()}>
Preview Rad UI components with theme and accent controls.
</Text>
</div>
</div>
<Button
variant="solid"
aria-label={`Switch to ${isDarkMode ? 'light' : 'dark'} mode`}
onClick={toggleDarkMode}
>
{isDarkMode ? <SunIcon/> : <MoonIcon/>}
</Button>
</div>
<Separator orientation='vertical' className={isCondensed ? 'opacity-60' : 'opacity-100'} />
<div className='min-w-0'>
<Heading as='h1' className={`font-semibold leading-none tracking-tight text-gray-1000 ${isCondensed ? 'text-xl sm:text-2xl' : 'text-3xl sm:text-4xl'}`.trim()}>
Sandbox Editor
</Heading>
<Text className={`mt-0.5 font-normal leading-tight text-gray-950 ${isCondensed ? 'hidden' : 'text-sm'}`.trim()}>
Preview Rad UI components with theme and accent controls.
</Text>
<Separator className={isCondensed ? 'opacity-70' : 'opacity-100'} />
<div className={`grid gap-2 sm:grid-cols-2 sm:items-end ${isCondensed ? 'py-0.5' : 'py-1.5'}`.trim()}>
<div className='grid gap-1'>
<Text as='span' className='text-sm text-gray-950 leading-none'>
Design system
</Text>
<Select.Root value={designSystem} onValueChange={updateDesignSystem}>
<Select.Trigger aria-label='Design system'>
<span className='capitalize'>{designSystem}</span>
</Select.Trigger>
<Select.Portal>
<Select.Content>
<Select.Group>
<Select.Item value='clarity'>Clarity</Select.Item>
<Select.Item value='baremetal'>Baremetal</Select.Item>
</Select.Group>
</Select.Content>
</Select.Portal>
</Select.Root>
</div>
<div className='grid gap-1'>
<Text as='span' className='text-sm text-gray-950 leading-none'>
Accent: <span className='capitalize'>{colorName}</span>
</Text>
<Select.Root value={colorName} onValueChange={(value) => setColorName(value as AvailableColors)}>
<Select.Trigger aria-label='Accent color'>
<span className='flex items-center gap-2'>
<ColorSelect
color={colors[colorName]}
isDarkMode={isDarkMode}
isSelected={true}
/>
<span className='capitalize'>{colorName}</span>
</span>
</Select.Trigger>
<Select.Portal>
<Select.Content>
<Select.Group>
{Object.entries(colors).map(([availableColorName, color]) => (
<Select.Item key={availableColorName} value={availableColorName}>
<span className='flex items-center gap-2'>
<ColorSelect
color={color}
isDarkMode={isDarkMode}
isSelected={availableColorName === colorName}
/>
<span className='capitalize'>{availableColorName}</span>
</span>
</Select.Item>
))}
</Select.Group>
</Select.Content>
</Select.Portal>
</Select.Root>
</div>
</div>
</div>
<Button
variant="solid"
aria-label={`Switch to ${isDarkMode ? 'light' : 'dark'} mode`}
onClick={toggleDarkMode}
>
{isDarkMode ? <SunIcon/> : <MoonIcon/>}
</Button>
</div>
<Separator className={isCondensed ? 'opacity-70' : 'opacity-100'} />
<div className={`flex flex-col gap-1.5 sm:flex-row sm:items-center sm:justify-between ${isCondensed ? 'py-0.5' : 'py-1.5'}`.trim()}>
<Text as='span' className='text-sm text-gray-950 leading-none'>
Accent: <span className='capitalize'>{colorName}</span>
</Text>
<div className={`w-full sm:w-[220px] ${isCondensed ? 'sm:w-[200px]' : ''}`.trim()}>
<Select.Root value={colorName} onValueChange={(value) => setColorName(value as AvailableColors)}>
<Select.Trigger aria-label='Accent color'>
<span className='flex items-center gap-2'>
<ColorSelect
color={colors[colorName]}
isDarkMode={isDarkMode}
isSelected={true}
/>
<span className='capitalize'>{colorName}</span>
</span>
</Select.Trigger>
<Select.Portal>
<Select.Content>
<Select.Group>
{Object.entries(colors).map(([availableColorName, color]) => (
<Select.Item key={availableColorName} value={availableColorName}>
<span className='flex items-center gap-2'>
<ColorSelect
color={color}
isDarkMode={isDarkMode}
isSelected={availableColorName === colorName}
/>
<span className='capitalize'>{availableColorName}</span>
</span>
</Select.Item>
))}
</Select.Group>
</Select.Content>
</Select.Portal>
</Select.Root>
</div>
</div>
<Separator/>
<div className={`pt-2.5 ${className ?? ''}`.trim()} >
{children}
</div>
</div>
<Separator/>
<div className={`pt-2.5 ${className ?? ''}`.trim()} >
{children}
</div>
</div>
</Theme>;
</Theme>
</div>;
};

export default SandboxEditor;
5 changes: 5 additions & 0 deletions src/components/ui/Accordion/accordion.baremetal.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/* stylelint-disable at-rule-no-unknown */
@use "src/design-systems/baremetal/scope" as baremetal;

#{baremetal.$theme-root} :where(.rad-ui-accordion-root) { @include baremetal.surface; }
#{baremetal.$theme-root} :where(.rad-ui-accordion-trigger) { @include baremetal.option-item; }
9 changes: 9 additions & 0 deletions src/components/ui/AlertDialog/alert-dialog.baremetal.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/* stylelint-disable at-rule-no-unknown */
@use "src/design-systems/baremetal/scope" as baremetal;

#{baremetal.$theme-root} :where(.rad-ui-alert-dialog-trigger, .rad-ui-alert-dialog-action, .rad-ui-alert-dialog-cancel) { @include baremetal.button-like; }
#{baremetal.$theme-root} :where(.rad-ui-alert-dialog-content) { @include baremetal.surface; padding: 1.5rem; }
#{baremetal.$theme-root} :where(.rad-ui-alert-dialog-title) { @include baremetal.title-text; }
#{baremetal.$theme-root} :where(.rad-ui-alert-dialog-description) { @include baremetal.body-text; }
#{baremetal.$theme-root} :where(.rad-ui-alert-dialog-footer) { border-color: var(--rad-ui-baremetal-black) !important; background: var(--rad-ui-baremetal-white) !important; }
#{baremetal.$theme-root} :where(.rad-ui-alert-dialog-overlay) { background: rgb(255, 255, 255, 0.72); backdrop-filter: none; }
4 changes: 4 additions & 0 deletions src/components/ui/Avatar/avatar.baremetal.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/* stylelint-disable at-rule-no-unknown */
@use "src/design-systems/baremetal/scope" as baremetal;

#{baremetal.$theme-root} :where(.rad-ui-avatar, .rad-ui-avatar-fallback) { @include baremetal.chip-like; }
4 changes: 4 additions & 0 deletions src/components/ui/AvatarGroup/avatar-group.baremetal.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/* stylelint-disable at-rule-no-unknown */
@use "src/design-systems/baremetal/scope" as baremetal;

#{baremetal.$theme-root} :where(.rad-ui-avatar-group-fallback) { @include baremetal.chip-like; }
4 changes: 4 additions & 0 deletions src/components/ui/Badge/badge.baremetal.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/* stylelint-disable at-rule-no-unknown */
@use "src/design-systems/baremetal/scope" as baremetal;

#{baremetal.$theme-root} :where(.rad-ui-badge) { @include baremetal.chip-like; }
Loading
Loading