From 93149415dbd9d4b0d0528e99c1cba73da2459e49 Mon Sep 17 00:00:00 2001 From: Sebastian Florek Date: Mon, 7 Oct 2024 16:27:11 +0200 Subject: [PATCH] feat: upgrade storybook and vite (#651) Co-authored-by: Jake Laderman --- .storybook/main.ts | 17 +- .storybook/manager.ts | 2 +- .storybook/preview.ts | 44 +- .storybook/theme.ts | 8 +- package.json | 41 +- src/components/TagMultiSelect.tsx | 58 +- .../PricingCalculatorExtended.tsx | 9 +- src/stories/TagMultiselectTemplate.tsx | 9 +- src/theme/boxShadows.ts | 4 +- vite.config.ts | 6 + yarn.lock | 5051 ++++------------- 11 files changed, 1132 insertions(+), 4117 deletions(-) diff --git a/.storybook/main.ts b/.storybook/main.ts index a9146e584..61a4b7ca7 100644 --- a/.storybook/main.ts +++ b/.storybook/main.ts @@ -1,13 +1,22 @@ import { type StorybookConfig } from '@storybook/react-vite' -const config: StorybookConfig = { - stories: ['../src/**/*.stories.mdx', '../src/**/*.stories.@(js|jsx|ts|tsx)'], +export default { + stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|ts|tsx)'], + addons: [ '@storybook/addon-links', '@storybook/addon-essentials', '@storybook/addon-interactions', ], + + core: { + builder: '@storybook/builder-vite', + }, + framework: '@storybook/react-vite', -} -export default config + // TODO: Enable if we need autodocs. Causes a CJS warning in vite + // typescript: { + // reactDocgen: 'react-docgen-typescript', + // }, +} as StorybookConfig diff --git a/.storybook/manager.ts b/.storybook/manager.ts index 8e192da00..29a4a34ba 100644 --- a/.storybook/manager.ts +++ b/.storybook/manager.ts @@ -1,4 +1,4 @@ -import { addons } from '@storybook/addons' +import { addons } from '@storybook/manager-api' import theme from './theme' diff --git a/.storybook/preview.ts b/.storybook/preview.ts index b27892f9f..64428a6da 100644 --- a/.storybook/preview.ts +++ b/.storybook/preview.ts @@ -1,45 +1,73 @@ -import * as jest from 'jest-mock' - import { type Preview } from '@storybook/react' +import { fn } from '@storybook/test' +import { themes } from '@storybook/theming' +import { DEFAULT_COLOR_MODE } from '../src/theme' import themeDecorator from '../src/ThemeDecorator' -import { COLOR_MODES, DEFAULT_COLOR_MODE } from '../src/theme' -// @ts-expect-error -window.jest = jest +// Copied from https://github.com/storybookjs/storybook/blob/v8.2.5/code/core/src/theming/utils.ts +const { window: globalWindow } = global + +export const getPreferredColorScheme = () => { + if (!globalWindow || !globalWindow.matchMedia) return 'light' + + const isDarkThemePreferred = globalWindow.matchMedia( + '(prefers-color-scheme: dark)' + ).matches + + if (isDarkThemePreferred) return 'dark' + + return 'light' +} const preview: Preview = { parameters: { layout: 'fullscreen', - actions: { argTypesRegex: '^on[A-Z].*' }, + actions: { onClick: fn }, controls: { matchers: { color: /(background|color)$/i, date: /Date$/, }, }, + docs: { + theme: themes.dark, + }, options: { storySort: { order: ['Semantic System', '*'], }, }, }, + globalTypes: { theme: { + name: 'Toggle theme', description: 'Global theme for components', - defaultValue: DEFAULT_COLOR_MODE, toolbar: { // The label to show for this toolbar item title: 'Theme', icon: 'circlehollow', // Array of plain string values or MenuItem shape (see below) - items: COLOR_MODES, + items: [ + { value: 'light', icon: 'circlehollow', title: 'Light' }, + { value: 'dark', icon: 'circle', title: 'Dark' }, + ], // Change title based on selected value dynamicTitle: true, + showName: true, }, }, }, + + initialGlobals: { + theme: DEFAULT_COLOR_MODE, + }, + decorators: [themeDecorator], + + // TODO: Enable if we need autodocs + // tags: ['autodocs'], } export default preview diff --git a/.storybook/theme.ts b/.storybook/theme.ts index 8ea09e0a3..acceaedc3 100644 --- a/.storybook/theme.ts +++ b/.storybook/theme.ts @@ -1,4 +1,4 @@ -import { create } from '@storybook/theming/create' +import { create } from '@storybook/theming' export default create({ base: 'dark', @@ -27,9 +27,9 @@ export default create({ textMutedColor: 'grey', // Toolbar default and active colors - barTextColor: 'white', - barSelectedColor: '#293EFF', - barBg: '#2A2E37', + barTextColor: '#73828C', + barSelectedColor: '#73828C', + barBg: '#1E2229', // Form colors inputBg: '#1E2229', diff --git a/package.json b/package.json index 30fea1bf8..34d602265 100644 --- a/package.json +++ b/package.json @@ -3,13 +3,14 @@ "version": "0.1.0", "description": "Pluralsh Design System", "main": "dist/index.js", + "type": "module", "files": [ "dist/**/*", "src/**/*" ], "scripts": { - "start": "storybook dev -p 6006 -s public", - "build:storybook": "yarn clean && storybook build -s public && yarn build:fix:storybook", + "start": "storybook dev -p 6006", + "build:storybook": "yarn clean && storybook build && yarn build:fix:storybook", "build:fix:storybook": "perl -pi -w -e 's/%40/@/g;' storybook-static/index.html", "storybook:serve-static": "yarn build:storybook && http-server storybook-static", "build": "npx tsc --declaration", @@ -75,17 +76,16 @@ "@emotion/styled": "11.11.0", "@pluralsh/eslint-config-typescript": "2.5.147", "@react-types/shared": "3.22.0", - "@storybook/addon-actions": "7.6.5", - "@storybook/addon-docs": "7.6.5", - "@storybook/addon-essentials": "7.6.5", - "@storybook/addon-interactions": "7.6.5", - "@storybook/addon-links": "7.6.5", - "@storybook/addons": "7.6.17", - "@storybook/builder-vite": "7.6.5", - "@storybook/node-logger": "7.6.5", - "@storybook/react": "7.6.5", - "@storybook/react-vite": "7.6.5", - "@storybook/testing-library": "0.2.2", + "@storybook/addon-actions": "8.3.5", + "@storybook/addon-docs": "8.3.5", + "@storybook/addon-essentials": "8.3.5", + "@storybook/addon-interactions": "8.3.5", + "@storybook/addon-links": "8.3.5", + "@storybook/builder-vite": "8.3.5", + "@storybook/node-logger": "8.3.5", + "@storybook/react": "8.3.5", + "@storybook/react-vite": "8.3.5", + "@storybook/theming": "8.3.5", "@testing-library/jest-dom": "5.17.0", "@types/chroma-js": "2.4.3", "@types/lodash-es": "4.17.12", @@ -94,6 +94,7 @@ "@types/react-transition-group": "4.4.10", "@typescript-eslint/eslint-plugin": "6.14.0", "@typescript-eslint/parser": "6.14.0", + "@vitejs/plugin-react": "4.3.2", "@vitest/coverage-v8": "1.0.4", "@vitest/ui": "1.0.4", "babel-loader": "9.1.3", @@ -103,7 +104,7 @@ "eslint-plugin-import": "2.29.1", "eslint-plugin-import-newlines": "1.3.4", "eslint-plugin-jsx-a11y": "6.8.0", - "eslint-plugin-prettier": "^5.1.3", + "eslint-plugin-prettier": "5.1.3", "eslint-plugin-react": "7.33.2", "eslint-plugin-react-hooks": "4.6.0", "eslint-plugin-storybook": "0.6.15", @@ -118,15 +119,15 @@ "lint-staged": "15.2.0", "npm-run-all": "4.1.5", "prettier": "3.0.3", - "react": "^18.3.1", - "react-dom": "^18.3.1", + "react": "18.3.1", + "react-dom": "18.3.1", "react-transition-group": "4.4.5", "rimraf": "5.0.5", - "storybook": "7.6.5", + "storybook": "8.3.5", "styled-components": "6.1.13", "typescript": "5.6.2", - "vite": "5.0.10", - "vitest": "1.0.4" + "vite": "5.4.8", + "vitest": "2.1.2" }, "peerDependencies": { "@emotion/react": ">=11.11.0", @@ -136,7 +137,7 @@ "react": ">=18.3.1", "react-dom": ">=18.3.1", "react-transition-group": ">=4.4.5", - "styled-components": ">=5.3.11" + "styled-components": ">=6.1.13" }, "packageManager": "yarn@3.3.1", "resolutions": { diff --git a/src/components/TagMultiSelect.tsx b/src/components/TagMultiSelect.tsx index 7dc7834b8..2d6954d26 100644 --- a/src/components/TagMultiSelect.tsx +++ b/src/components/TagMultiSelect.tsx @@ -1,5 +1,4 @@ import { type ComponentProps, type Key, useMemo, useState } from 'react' - import styled, { useTheme } from 'styled-components' import { @@ -12,14 +11,8 @@ import { SelectButton, type SelectPropsSingle, } from '..' - import { isNonNullable } from '../utils/isNonNullable' -export type MultiSelectTag = { - name: string - value: string -} - const matchOptions = [ { label: 'All', value: 'AND' }, { label: 'Any', value: 'OR' }, @@ -28,11 +21,11 @@ const matchOptions = [ type TagMultiSelectProps = { options: string[] loading: boolean + selectedTagKeys: Set + setSelectedTagKeys: (keys: Set) => void + inputValue: string + setInputValue: (value: string) => void innerChips?: boolean - selectedTagKeys?: Set - setSelectedTagKeys?: (keys: Set) => void - inputValue?: string - setInputValue?: (value: string) => void selectedMatchType?: 'AND' | 'OR' onSelectedTagsChange?: (keys: Set) => void onFilterChange?: (value: string) => void @@ -41,7 +34,21 @@ type TagMultiSelectProps = { selectProps?: Omit } -function TagMultiSelect({ +const MultiSelectMatchButtonContainer = styled.div` + > div { + border-top-right-radius: 0; + border-bottom-right-radius: 0; + border-right: none; + } +` + +const TagMultiSelect = styled(TagMultiSelectUnstyled)(({ theme }) => ({ + display: 'flex', + flexDirection: 'column', + gap: theme.spacing.xsmall, +})) + +function TagMultiSelectUnstyled({ options, loading, innerChips = true, @@ -56,7 +63,10 @@ function TagMultiSelect({ ...props }: TagMultiSelectProps & ComponentProps<'div'>) { const theme = useTheme() - const selectedTagArr = useMemo(() => [...selectedTagKeys], [selectedTagKeys]) + const selectedTagArr = useMemo( + () => [...(selectedTagKeys ?? [])], + [selectedTagKeys] + ) const [isOpen, setIsOpen] = useState(false) const [searchLogic, setSearchLogic] = useState( selectedMatchType || matchOptions[0].value @@ -72,7 +82,7 @@ function TagMultiSelect({ } return ( - +