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
20 changes: 20 additions & 0 deletions packages/storybook-addons/src/addons/color-scheme/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,26 @@ registerColorSchemeAddon({
});
```

### Вариант 3: Комбинированный (пресет + кастомизация)

Добавьте пресет в `.storybook/main.ts` для авторегистрации, а конфигурацию задайте в `.storybook/manager.ts`:

**.storybook/main.ts:**
```ts
addons: [
'@vkontakte/storybook-addons/color-scheme',
];
```

**.storybook/manager.ts:**
```ts
import { setColorSchemeConfig } from '@vkontakte/storybook-addons';

setColorSchemeConfig({
parameterName: 'myColorScheme',
});
```

## Конфигурация

```ts
Expand Down
8 changes: 6 additions & 2 deletions packages/storybook-addons/src/addons/color-scheme/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,13 @@ export interface ColorSchemeConfig {
parameterName: string;
}

const config: ColorSchemeConfig = {
const GLOBAL_KEY = '__VKUI_COLOR_SCHEME_CONFIG__';

const getDefaultConfig = (): ColorSchemeConfig => ({
parameterName: DEFAULT_PARAM_KEY,
};
});

const config: ColorSchemeConfig = ((window as any)[GLOBAL_KEY] ??= getDefaultConfig());

export const getColorSchemeConfig = () => config;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,38 @@ registerLiveCodeEditorAddon({
});
```

> При использовании программной регистрации не нужно добавлять пресет в `main.ts`.
### Вариант 3: Комбинированный (пресет + кастомизация)

Добавьте пресет в `.storybook/main.ts` для авторегистрации, а конфигурацию задайте в `.storybook/manager.ts`:

**.storybook/main.ts:**
```ts
const addons = [
'@vkontakte/storybook-addons/live-code-editor',
];
```

**.storybook/manager.ts:**
```ts
import { setLiveCodeEditorConfig } from '@vkontakte/storybook-addons';

setLiveCodeEditorConfig({
format: async (code) => {
const prettier = await import('prettier/standalone');
const prettierPluginTS = await import('prettier/plugins/typescript');
const prettierPluginEstree = await import('prettier/plugins/estree');
return prettier.format(code, {
parser: 'typescript',
plugins: [prettierPluginTS, prettierPluginEstree],
singleQuote: true,
trailingComma: 'all',
printWidth: 110,
bracketSpacing: true,
semi: true,
});
},
});
```

## Конфигурация

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,13 @@ export interface LiveCodeEditorConfig {
format: ((code: string) => Promise<string>) | undefined;
}

const config: LiveCodeEditorConfig = {
const GLOBAL_KEY = '__VKUI_LIVE_CODE_EDITOR_CONFIG__';

const getDefaultConfig = (): LiveCodeEditorConfig => ({
format: undefined,
};
});

const config: LiveCodeEditorConfig = ((window as any)[GLOBAL_KEY] ??= getDefaultConfig());

export const getLiveCodeEditorConfig = () => config;

Expand Down
36 changes: 36 additions & 0 deletions packages/storybook-addons/src/addons/source-button/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,20 @@

## Установка

### Вариант 1: Через пресет (авторегистрация)

Добавьте пресет в `.storybook/main.ts`:

```ts
addons: [
'@vkontakte/storybook-addons/source-button',
];
```

Аддон зарегистрируется автоматически со стандартными значениями. Кнопка не отображается, пока не задан `baseUrl`.

### Вариант 2: Программная регистрация

Зарегистрируйте аддон в `.storybook/manager.ts` с конфигурацией:

```ts
Expand All @@ -19,6 +33,28 @@ registerSourceButtonAddon({
});
```

### Вариант 3: Комбинированный (пресет + кастомизация)

Добавьте пресет в `.storybook/main.ts` для авторегистрации, а конфигурацию задайте в `.storybook/manager.ts`:

**.storybook/main.ts:**
```ts
addons: [
'@vkontakte/storybook-addons/source-button',
];
```

**.storybook/manager.ts:**
```ts
import { setSourceButtonConfig } from '@vkontakte/storybook-addons';

setSourceButtonConfig({
baseUrl: 'https://github.com/VKCOM/VKUI',
label: 'Исходный код',
title: 'Открыть исходный код на GitHub',
});
```

## Конфигурация

```ts
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { registerSourceButtonAddon } from './register';

// Авто-регистрация при загрузке через preset (main.ts) — используются значения по умолчанию
registerSourceButtonAddon();
39 changes: 28 additions & 11 deletions packages/storybook-addons/src/addons/source-button/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,36 @@ export interface SourceButtonConfig {
title: string;
}

const config: SourceButtonConfig = {
getUrl: () => '',
const GLOBAL_KEY = '__VKUI_SOURCE_BUTTON_CONFIG__';

const getDefaultConfig = (): SourceButtonConfig => ({
getUrl: (baseUrl, importPath) => {
const cleanPath = importPath.replace(/^\.\//, '');
return `${baseUrl}/${cleanPath}`;
},
baseUrl: '',
label: '',
title: '',
};
label: 'Open source',
title: 'Source',
});

const config: SourceButtonConfig = ((window as any)[GLOBAL_KEY] ??= getDefaultConfig());

export const getSourceButtonConfig = () => config;

export const setSourceButtonConfig = (newConfig: SourceButtonConfig) => {
config.getUrl = newConfig.getUrl;
config.baseUrl = newConfig.baseUrl;
config.icon = newConfig.icon;
config.label = newConfig.label;
config.title = newConfig.title;
export const setSourceButtonConfig = (newConfig: Partial<SourceButtonConfig>) => {
if (newConfig.getUrl) {
config.getUrl = newConfig.getUrl;
}
if (newConfig.baseUrl) {
config.baseUrl = newConfig.baseUrl;
}
if (newConfig.icon) {
config.icon = newConfig.icon;
}
if (newConfig.label) {
config.label = newConfig.label;
}
if (newConfig.title) {
config.title = newConfig.title;
}
};
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { fileURLToPath } from 'node:url';

export function managerEntries(entry = []) {
return [...entry, fileURLToPath(import.meta.resolve('./register.ts'))];
return [...entry, fileURLToPath(import.meta.resolve('./auto-register.ts'))];
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@ import { setSourceButtonConfig } from './config';
import type { SourceButtonConfig } from './config';
import { ADDON_ID } from './constants';

export const registerSourceButtonAddon = (config: SourceButtonConfig) => {
setSourceButtonConfig(config);
export const registerSourceButtonAddon = (config?: Partial<SourceButtonConfig>) => {
if (config) {
setSourceButtonConfig(config);
}

addons.register(ADDON_ID, () => {
addons.add(ADDON_ID, {
title: config.title,
title: 'Source',
type: types.TOOL,
render: SourceButton,
});
Expand Down
22 changes: 22 additions & 0 deletions packages/storybook-addons/src/addons/storybook-theme/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,28 @@ registerStorybookThemeAddon({
});
```

### Вариант 3: Комбинированный (пресет + кастомизация)

Добавьте пресет в `.storybook/main.ts` для авторегистрации, а конфигурацию задайте в `.storybook/manager.ts`:

**.storybook/main.ts:**
```ts
addons: [
'@vkontakte/storybook-addons/storybook-theme',
];
```

**.storybook/manager.ts:**
```ts
import { setStorybookThemeConfig } from '@vkontakte/storybook-addons';
import { vkuiDarkTheme, vkuiLightTheme } from './vkuiThemes';

setStorybookThemeConfig({
lightTheme: vkuiLightTheme,
darkTheme: vkuiDarkTheme,
});
```

## Конфигурация

```ts
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { styled } from 'storybook/theming';
import { getColorSchemeConfig } from '../color-scheme/config';
import { getThemeConfig } from './config';
import { SET_STORYBOOK_THEME } from './constants';
import { updateLocalStorageValue } from './storage';

const SidebarSelect = styled(Select)(({ theme }) => ({
position: 'relative',
Expand All @@ -16,20 +17,10 @@ const SidebarSelect = styled(Select)(({ theme }) => ({
zIndex: 1,
}));

const STORAGE_KEY = 'sb-dark-theme';

const channel = addons.getChannel();

type Theme = 'light' | 'dark';

export const updateLocalStorageValue = (theme: Theme) => {
window.localStorage.setItem(STORAGE_KEY, theme);
};

export const getLocalStorageValue = (): Theme => {
return window.localStorage.getItem(STORAGE_KEY) as Theme;
};

export const StorybookTheme = () => {
const [globals, updateGlobals] = useGlobals();
const { once } = useStorybookApi();
Expand All @@ -49,7 +40,7 @@ export const StorybookTheme = () => {
);
updateLocalStorageValue(globalTheme);
},
[updateGlobals],
[updateGlobals, parameterName],
);

const handleChange: React.ComponentProps<typeof Select>['onChange'] = React.useCallback(
Expand All @@ -58,7 +49,7 @@ export const StorybookTheme = () => {
addons.setConfig({ theme: selectedOption === 'dark' ? darkTheme : lightTheme });
updateTheme(selectedOption, selectedOption);
},
[updateTheme],
[updateTheme, lightTheme, darkTheme],
);

React.useEffect(() => {
Expand Down
22 changes: 19 additions & 3 deletions packages/storybook-addons/src/addons/storybook-theme/config.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { addons } from 'storybook/manager-api';
import { create } from 'storybook/theming';
import type { ThemeVars } from 'storybook/theming';
import { DEFAULT_PARAM_KEY } from './constants';
import { getLocalStorageValue } from './storage';

export interface StorybookThemeConfig {
lightTheme: ThemeVars;
Expand All @@ -9,16 +11,20 @@ export interface StorybookThemeConfig {
defaultValue: 'light' | 'dark' | 'system';
}

const config: StorybookThemeConfig = {
const GLOBAL_KEY = '__VKUI_STORYBOOK_THEME_CONFIG__';

const getDefaultConfig = (): StorybookThemeConfig => ({
lightTheme: create({ base: 'light' }),
darkTheme: create({ base: 'dark' }),
parameterName: DEFAULT_PARAM_KEY,
defaultValue: 'system' as const,
};
});

const config: StorybookThemeConfig = ((window as any)[GLOBAL_KEY] ??= getDefaultConfig());

export const getThemeConfig = () => config;

export const setThemeConfig = (newConfig: Partial<StorybookThemeConfig>) => {
export const setStorybookThemeConfig = (newConfig: Partial<StorybookThemeConfig>) => {
if (newConfig.lightTheme) {
config.lightTheme = newConfig.lightTheme;
}
Expand All @@ -31,4 +37,14 @@ export const setThemeConfig = (newConfig: Partial<StorybookThemeConfig>) => {
if (newConfig.defaultValue) {
config.defaultValue = newConfig.defaultValue;
}

const systemTheme =
config.defaultValue === 'system' &&
((window.matchMedia?.('(prefers-color-scheme: dark)').matches && 'dark') || 'light');

const specificTheme = config.defaultValue === 'dark' ? 'dark' : 'light';

const initialTheme = getLocalStorageValue() || systemTheme || specificTheme || 'light';

addons.setConfig({ theme: initialTheme === 'dark' ? config.darkTheme : config.lightTheme });
};
Original file line number Diff line number Diff line change
@@ -1,23 +1,13 @@
import { addons, types } from 'storybook/manager-api';
import { getLocalStorageValue, StorybookTheme } from './StorybookTheme';
import { getThemeConfig, setThemeConfig } from './config';
import { StorybookTheme } from './StorybookTheme';
import { setStorybookThemeConfig } from './config';
import type { StorybookThemeConfig } from './config';
import { ADDON_ID } from './constants';

export const registerStorybookThemeAddon = (themeConfig?: Partial<StorybookThemeConfig>) => {
if (themeConfig) {
setThemeConfig(themeConfig);
setStorybookThemeConfig(themeConfig);
}
const { lightTheme, darkTheme, defaultValue } = getThemeConfig();

const systemTheme =
defaultValue === 'system' &&
((window.matchMedia?.('(prefers-color-scheme: dark)').matches && 'dark') || 'light');
const specificTheme = defaultValue === 'dark' ? 'dark' : 'light';

const initialTheme = getLocalStorageValue() || systemTheme || specificTheme || 'light';

addons.setConfig({ theme: initialTheme === 'dark' ? darkTheme : lightTheme });

addons.register(ADDON_ID, () => {
addons.add(ADDON_ID, {
Expand Down
11 changes: 11 additions & 0 deletions packages/storybook-addons/src/addons/storybook-theme/storage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
const STORAGE_KEY = 'sb-dark-theme';

type Theme = 'light' | 'dark';

export const updateLocalStorageValue = (theme: Theme) => {
window.localStorage.setItem(STORAGE_KEY, theme);
};

export const getLocalStorageValue = (): Theme => {
return window.localStorage.getItem(STORAGE_KEY) as Theme;
};
Loading