diff --git a/.storybook/preview.tsx b/.storybook/preview.tsx index e7bd037..bb1a461 100644 --- a/.storybook/preview.tsx +++ b/.storybook/preview.tsx @@ -2,7 +2,7 @@ import React from 'react'; import type { Preview } from '@storybook/react'; import { Title, Subtitle, Description, Primary, Controls, Stories, DocsContainer, Unstyled } from '@storybook/blocks'; -import RedbackUiThemeProvider from '../src/providers/RedbackUiThemeProvider/RedbackUiThemeProvider'; +import { RedbackUiThemeProvider } from '../src/providers/RedbackUiThemeProvider/RedbackUiThemeProvider'; import { themes } from '../src/themes'; const preview: Preview = { diff --git a/docs/Contributing.mdx b/docs/Contributing.mdx index f1a54d5..821d7e2 100644 --- a/docs/Contributing.mdx +++ b/docs/Contributing.mdx @@ -74,6 +74,8 @@ A new folder named with your component name will be created in the `src/componen - `ComponentName.stories.tsx`: the [Storybook](https://storybook.js.org/) file used to see, test, and document the component - `ComponentName.test.tsx`: the unit test file. A basic example is included. Please add further tests as relevant to your component. +**Important!** To enable your component to be used by other apps or websites using the short `import { YourComponent } from '@redbackops/redback-ui'` syntax, you will need to export it from `src/index.ts`. Please add it to the list following the same format as the other components, and in alphabetical order. + ### Theme and design tokens Design tokens are used to maintain consistency across the design system and applications that use it. The tokens are defined in a JavaScript object. @@ -106,17 +108,45 @@ npx generate-react-cli component ComponentName --type=doc ## Before submitting your change -Test the built version of Storybook to make sure everything works as expected, so that when your PR is approved and merged into the main branch you can be confident that you haven't introduced any errors such as incorrect file paths. +1. Test the built version of Storybook to make sure everything works as expected, so that when your PR is approved and merged into the main branch you can be confident that you haven't introduced any errors such as incorrect file paths. + + - Build Storybook + ```bash + npm run build + ``` + - Preview the built version locally + ```bash + npm run preview + ``` + +2. Run ESLint to check for any formatting or quality issues in your code according to the project's ESLint configuration. -1. Build Storybook ```bash - npm run build + npm run lint ``` -2. Preview the built version locally + + Some issues can be fixed automatically: + ```bash + npm run lint:fix + ``` + + It is recommended to enable running ESLint on save in your IDE to catch issues and reformat code as you work. + + If you would like to add or edit a rule in the ESLint configuration, please raise a pull request with your change and include the reasoning in the description. + + +3. Ensure your files follow the expected structure + ```bash - npm run preview + npm run lint:structure ``` + _**Note**: This will also run the general ESLint checks from step 2, so it's a good idea to run that first so you can fix any issues before running the structure check._ + +4. If you created a new component, ensure it is exported by opening `src/index.ts` and add your component to the list following the same format as the other components, and in alphabetical order. + +5. Bump the version number in `package.json` according to the [Semantic Versioning](https://semver.org/) guidelines. + ## Submitting your change 1. Stage your changes @@ -137,7 +167,7 @@ Test the built version of Storybook to make sure everything works as expected, s ```bash git push ``` -4. Create a pull request on GitHub, ensuring your include a clear description of your changes and any relevant context for reviewers. +4. Create a pull request on GitHub, in [the main Redback UI repository](https://github.com/Redback-Operations/redback-ui), ensuring your include a clear description of your changes and any relevant context for reviewers. ## Video tutorials 1. [Local setup](https://www.loom.com/share/d77050ce968e4c3690f1760988318de3?sid=d2426caa-3dbf-4477-97a3-0e6beb4391d9) (5 minutes) diff --git a/package.json b/package.json index 0bb29ed..c1c17c0 100644 --- a/package.json +++ b/package.json @@ -3,14 +3,17 @@ "version": "0.0.1", "type": "module", "license": "MIT", + "exports": "./dist/index.js", "scripts": { "dev": "storybook dev --port 6006", "lint": "eslint ./src --ext ts,tsx --report-unused-disable-directives --max-warnings 0", + "lint:fix": "eslint ./src --ext ts,tsx --report-unused-disable-directives --max-warnings 0 --fix", "lint:structure": "eslint --parser ./node_modules/eslint-plugin-project-structure/dist/parser.js --rule project-structure/file-structure:error --ext .js,.jsx,.ts,.tsx,.html,.css,.svg,.png,.jpg,.json,.md .", - "test:unit": "jest ./src/components/**/*.test.tsx", + "test:unit": "jest --modulePathIgnorePatterns=dist ./src/components/**/*.test.tsx", "storybook": "storybook dev --port 6006", "build": "storybook build", - "preview": "npx http-server ./storybook-static" + "preview": "npx http-server ./storybook-static", + "package": "tsc -p tsconfig.dist.json" }, "dependencies": { "@storybook/addon-docs": "^8.0.5", @@ -48,6 +51,7 @@ "@typescript-eslint/parser": "^7.2.0", "@vitejs/plugin-react": "^4.2.1", "babel-jest": "^29.7.0", + "babel-plugin-styled-components": "^2.1.4", "eslint": "^8.57.0", "eslint-plugin-project-structure": "^1.4.7", "eslint-plugin-react-hooks": "^4.6.0", diff --git a/project-structure.json b/project-structure.json index 970dd01..693a01c 100644 --- a/project-structure.json +++ b/project-structure.json @@ -88,6 +88,10 @@ "extension": ["ts"] } ] + }, + { + "name": "index", + "extension": ["ts"] } ] }, @@ -151,6 +155,7 @@ } ] }, + {"name": "dist"}, { "name": "test-mocks", "children": [] @@ -212,7 +217,11 @@ "extension": ["json"] }, { - "name": "tsconfig.node", + "name": "tsconfig.dev", + "extension": ["json"] + }, + { + "name": "tsconfig.dist", "extension": ["json"] }, { diff --git a/src/components/Alert/Alert.stories.ts b/src/components/Alert/Alert.stories.ts index a49f055..eb3f7de 100644 --- a/src/components/Alert/Alert.stories.ts +++ b/src/components/Alert/Alert.stories.ts @@ -1,4 +1,4 @@ -import Alert from './Alert'; +import { Alert } from './Alert'; import type { Meta, StoryObj } from '@storybook/react'; const meta = { diff --git a/src/components/Alert/Alert.tsx b/src/components/Alert/Alert.tsx index d70c042..26850e0 100644 --- a/src/components/Alert/Alert.tsx +++ b/src/components/Alert/Alert.tsx @@ -5,12 +5,10 @@ type AlertProps = { type?: 'success' | 'info' | 'warning' | 'error'; } -const Alert: FC> = ({ type, children }) => { +export const Alert: FC> = ({ type, children }) => { return ( {children} ); }; - -export default Alert; diff --git a/src/components/Button/Button.stories.ts b/src/components/Button/Button.stories.ts index 1232bad..8ca5125 100644 --- a/src/components/Button/Button.stories.ts +++ b/src/components/Button/Button.stories.ts @@ -1,7 +1,7 @@ -import Button from './Button'; +import { Button } from './Button'; import { fn } from '@storybook/test'; import type { Meta, StoryObj } from '@storybook/react'; -import { themeColorSubset } from '../../types.ts'; +import { themeColorSubset } from '../../types'; const meta = { title: 'Components/Button', diff --git a/src/components/Button/Button.style.ts b/src/components/Button/Button.style.ts index 2c78450..62afca1 100644 --- a/src/components/Button/Button.style.ts +++ b/src/components/Button/Button.style.ts @@ -1,5 +1,5 @@ import styled from 'styled-components'; -import { ThemeColor, ThemeElementAppearance, ThemeElementSize } from '../../types.ts'; +import { ThemeColor, ThemeElementAppearance, ThemeElementSize } from '../../types'; import { readableColor, shade } from 'polished'; type StyledButtonProps = { diff --git a/src/components/Button/Button.tsx b/src/components/Button/Button.tsx index 8df9ac3..c3c2da2 100644 --- a/src/components/Button/Button.tsx +++ b/src/components/Button/Button.tsx @@ -1,6 +1,6 @@ import { FC } from 'react'; -import { StyledButton } from './Button.style.ts'; -import { ThemeColor, ThemeElementAppearance, ThemeElementSize } from '../../types.ts'; +import { StyledButton } from './Button.style'; +import { ThemeColor, ThemeElementAppearance, ThemeElementSize } from '../../types'; type ButtonProps = { label: string; @@ -10,7 +10,7 @@ type ButtonProps = { size?: ThemeElementSize; } -const Button: FC = ({ +export const Button: FC = ({ label, color = 'primary', onClick, @@ -23,5 +23,3 @@ const Button: FC = ({ ); }; - -export default Button; diff --git a/src/components/Label/Label.stories.ts b/src/components/Label/Label.stories.ts index 81a6c5c..915cab9 100644 --- a/src/components/Label/Label.stories.ts +++ b/src/components/Label/Label.stories.ts @@ -1,4 +1,4 @@ -import Label from './Label'; +import { Label } from './Label'; import type { Meta, StoryObj } from '@storybook/react'; const meta = { diff --git a/src/components/Label/Label.tsx b/src/components/Label/Label.tsx index 347c331..ac00da6 100644 --- a/src/components/Label/Label.tsx +++ b/src/components/Label/Label.tsx @@ -6,12 +6,10 @@ type LabelProps = { text: string; } -const Label: FC = ({ type, text }: LabelProps) => { +export const Label: FC = ({ type, text }: LabelProps) => { return ( {text} ); }; - -export default Label; diff --git a/src/components/LinkButton/LinkButton.stories.ts b/src/components/LinkButton/LinkButton.stories.ts index 18d8725..cd5cfd5 100644 --- a/src/components/LinkButton/LinkButton.stories.ts +++ b/src/components/LinkButton/LinkButton.stories.ts @@ -1,6 +1,6 @@ -import LinkButton from './LinkButton'; +import { LinkButton } from './LinkButton'; import type { Meta, StoryObj } from '@storybook/react'; -import { themeColorSubset } from '../../types.ts'; +import { themeColorSubset } from '../../types'; const meta = { title: 'Components/LinkButton', diff --git a/src/components/LinkButton/LinkButton.style.ts b/src/components/LinkButton/LinkButton.style.ts index 63c4c34..40a24e1 100644 --- a/src/components/LinkButton/LinkButton.style.ts +++ b/src/components/LinkButton/LinkButton.style.ts @@ -1,3 +1,3 @@ import styled from 'styled-components'; -import { StyledButton } from '../Button/Button.style.ts'; +import { StyledButton } from '../Button/Button.style'; export const StyledLinkButton = styled(StyledButton).attrs({ as: 'a' })``; diff --git a/src/components/LinkButton/LinkButton.tsx b/src/components/LinkButton/LinkButton.tsx index 1b2e633..802d0c9 100644 --- a/src/components/LinkButton/LinkButton.tsx +++ b/src/components/LinkButton/LinkButton.tsx @@ -1,6 +1,6 @@ import { FC } from 'react'; import { StyledLinkButton } from './LinkButton.style'; -import { ThemeColor, ThemeElementAppearance, ThemeElementSize } from '../../types.ts'; +import { ThemeColor, ThemeElementAppearance, ThemeElementSize } from '../../types'; type LinkButtonProps = { label: string; @@ -11,7 +11,7 @@ type LinkButtonProps = { target?: '_blank'; } -const LinkButton: FC = ({ +export const LinkButton: FC = ({ label, color = 'primary', href = '#', @@ -25,5 +25,3 @@ const LinkButton: FC = ({ ); }; - -export default LinkButton; diff --git a/src/components/Table/Table.stories.ts b/src/components/Table/Table.stories.ts index f386ddb..fa0346f 100644 --- a/src/components/Table/Table.stories.ts +++ b/src/components/Table/Table.stories.ts @@ -1,4 +1,4 @@ -import Table from './Table'; +import { Table } from './Table'; import type { Meta, StoryObj } from '@storybook/react'; const meta = { diff --git a/src/components/Table/Table.tsx b/src/components/Table/Table.tsx index bfccbac..cce917f 100644 --- a/src/components/Table/Table.tsx +++ b/src/components/Table/Table.tsx @@ -1,12 +1,10 @@ import { FC, PropsWithChildren } from 'react'; import { StyledTable } from './Table.style'; -const Table: FC = ({ children }) => { +export const Table: FC = ({ children }) => { return ( {children} ); }; - -export default Table; diff --git a/src/components/TruncatedText/TruncatedText.stories.ts b/src/components/TruncatedText/TruncatedText.stories.ts index 27eed78..2dcbbf6 100644 --- a/src/components/TruncatedText/TruncatedText.stories.ts +++ b/src/components/TruncatedText/TruncatedText.stories.ts @@ -1,4 +1,4 @@ -import TruncatedText from './TruncatedText'; +import { TruncatedText } from './TruncatedText'; import type { Meta, StoryObj } from '@storybook/react'; const meta = { diff --git a/src/components/TruncatedText/TruncatedText.tsx b/src/components/TruncatedText/TruncatedText.tsx index 7c93aa9..d5299e0 100644 --- a/src/components/TruncatedText/TruncatedText.tsx +++ b/src/components/TruncatedText/TruncatedText.tsx @@ -6,12 +6,10 @@ type TruncatedTextProps = { lines: number; } -const TruncatedText: FC> = ({ lines, text }) => { +export const TruncatedText: FC> = ({ lines, text }) => { return ( {text} ); }; - -export default TruncatedText; diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 0000000..62fc5ab --- /dev/null +++ b/src/index.ts @@ -0,0 +1,8 @@ +export * from './providers/RedbackUiThemeProvider/RedbackUiThemeProvider'; +export * from './themes'; +export * from './components/Alert/Alert'; +export * from './components/Button/Button'; +export * from './components/Label/Label'; +export * from './components/LinkButton/LinkButton'; +export * from './components/Table/Table'; +export * from './components/TruncatedText/TruncatedText'; diff --git a/src/providers/RedbackUiThemeProvider/GlobalStyle.tsx b/src/providers/RedbackUiThemeProvider/GlobalStyle.tsx index 4a85438..c314aef 100644 --- a/src/providers/RedbackUiThemeProvider/GlobalStyle.tsx +++ b/src/providers/RedbackUiThemeProvider/GlobalStyle.tsx @@ -3,6 +3,8 @@ import { rgba } from 'polished'; import './fonts.css'; export const GlobalStyle = createGlobalStyle` + @import 'https://fonts.googleapis.com/css2?family=Inter+Tight:ital,wght@0,100..900;1,100..900&display=swap'; + body { margin: 0; padding: 0; diff --git a/src/providers/RedbackUiThemeProvider/RedbackUiThemeProvider.test.tsx b/src/providers/RedbackUiThemeProvider/RedbackUiThemeProvider.test.tsx index 4d9d7ce..614aabe 100644 --- a/src/providers/RedbackUiThemeProvider/RedbackUiThemeProvider.test.tsx +++ b/src/providers/RedbackUiThemeProvider/RedbackUiThemeProvider.test.tsx @@ -1,5 +1,5 @@ import { render, screen } from '@testing-library/react'; -import RedbackUiThemeProvider from './RedbackUiThemeProvider'; +import { RedbackUiThemeProvider } from './RedbackUiThemeProvider'; import { themes } from '../../themes'; describe('', () => { diff --git a/src/providers/RedbackUiThemeProvider/RedbackUiThemeProvider.tsx b/src/providers/RedbackUiThemeProvider/RedbackUiThemeProvider.tsx index 2761dba..2db28d5 100644 --- a/src/providers/RedbackUiThemeProvider/RedbackUiThemeProvider.tsx +++ b/src/providers/RedbackUiThemeProvider/RedbackUiThemeProvider.tsx @@ -1,15 +1,15 @@ import { FC, PropsWithChildren, ReactNode } from 'react'; -import { RedbackUiWrapper } from './RedbackUiThemeProvider.style.ts'; -import { RedbackUiTheme } from '../../types.ts'; +import { RedbackUiWrapper } from './RedbackUiThemeProvider.style'; +import { RedbackUiTheme } from '../../types'; import { ThemeProvider } from 'styled-components'; -import { GlobalStyle } from './GlobalStyle.tsx'; +import { GlobalStyle } from './GlobalStyle'; type RedbackUiThemeProviderProps = { theme: RedbackUiTheme; children: ReactNode; } -const RedbackUiThemeProvider: FC> = ({ +export const RedbackUiThemeProvider: FC> = ({ theme, children }) => { @@ -21,6 +21,4 @@ const RedbackUiThemeProvider: FC> ); -}; - -export default RedbackUiThemeProvider; +}; \ No newline at end of file diff --git a/src/providers/RedbackUiThemeProvider/fonts.css b/src/providers/RedbackUiThemeProvider/fonts.css deleted file mode 100644 index 70fbb8a..0000000 --- a/src/providers/RedbackUiThemeProvider/fonts.css +++ /dev/null @@ -1 +0,0 @@ -@import 'https://fonts.googleapis.com/css2?family=Inter+Tight:ital,wght@0,100..900;1,100..900&display=swap'; diff --git a/templates/TemplateName.stories.ts b/templates/TemplateName.stories.ts index cbf860e..aa5320d 100644 --- a/templates/TemplateName.stories.ts +++ b/templates/TemplateName.stories.ts @@ -1,4 +1,4 @@ -import TemplateName from './TemplateName'; +import { TemplateName } from './TemplateName'; import type { Meta, StoryObj } from '@storybook/react'; const meta = { diff --git a/templates/TemplateName.tsx b/templates/TemplateName.tsx index 6d318eb..6aaf1c5 100644 --- a/templates/TemplateName.tsx +++ b/templates/TemplateName.tsx @@ -3,12 +3,10 @@ import { StyledTemplateName } from './TemplateName.style'; type TemplateNameProps = {} -const TemplateName: FC = () => { +export const TemplateName: FC = () => { return ( TemplateName Component ); }; - -export default TemplateName; diff --git a/tsconfig.dev.json b/tsconfig.dev.json new file mode 100644 index 0000000..9dc5ffa --- /dev/null +++ b/tsconfig.dev.json @@ -0,0 +1,8 @@ +{ + "extends": "./tsconfig.json", + "root": false, + "compilerOptions": { + "types": ["@testing-library/jest-dom"] + }, + "include": ["src", "templates"] +} diff --git a/tsconfig.dist.json b/tsconfig.dist.json new file mode 100644 index 0000000..d3f9b8e --- /dev/null +++ b/tsconfig.dist.json @@ -0,0 +1,10 @@ +{ + "extends": "./tsconfig.json", + "root": false, + "compilerOptions": { + "outDir": "dist", + "declaration": true, + }, + "include": ["src/**/*.ts", "src/**/*.tsx"], + "exclude": ["**/*.test.ts", "**/*.test.tsx", "**/*.stories.tsx", "**/*.stories.ts"] +} \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index d4c55fc..0a2cde1 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -8,23 +8,14 @@ "esModuleInterop": true, /* Bundler mode */ "moduleResolution": "bundler", - "allowImportingTsExtensions": true, + "allowSyntheticDefaultImports": true, "resolveJsonModule": true, "isolatedModules": true, - "noEmit": true, "jsx": "react-jsx", /* Linting */ "strict": true, "noUnusedLocals": true, "noUnusedParameters": true, - "noFallthroughCasesInSwitch": true, - /* Other */ - "types": ["@testing-library/jest-dom"] - }, - "include": ["src", "templates"], - "references": [ - { - "path": "./tsconfig.node.json" - } - ] + "noFallthroughCasesInSwitch": true + } } diff --git a/tsconfig.node.json b/tsconfig.node.json deleted file mode 100644 index 1caabef..0000000 --- a/tsconfig.node.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "compilerOptions": { - "composite": true, - "skipLibCheck": true, - "module": "ESNext", - "moduleResolution": "bundler", - "allowSyntheticDefaultImports": true, - "strict": true - }, - "include": ["vite.config.ts"] -}