diff --git a/.babelrc b/.babelrc new file mode 100644 index 000000000..36385d4e7 --- /dev/null +++ b/.babelrc @@ -0,0 +1 @@ +{"presets":[["@babel/preset-env",{"bugfixes":true,"debug":false}],["@babel/preset-react"]]} \ No newline at end of file diff --git a/.eslintignore b/.eslintignore index 588b068f4..fa159c22a 100644 --- a/.eslintignore +++ b/.eslintignore @@ -4,7 +4,8 @@ full/** lib/** node_modules reports -*.test.js **/*.d.ts documentation/** -.coverage \ No newline at end of file +.coverage +esm +cjs \ No newline at end of file diff --git a/.eslintrc b/.eslintrc deleted file mode 100644 index 7402bf12a..000000000 --- a/.eslintrc +++ /dev/null @@ -1,59 +0,0 @@ -{ - "extends": [ - "airbnb", - "prettier" - ], - "parser": "babel-eslint", - "parserOptions": { - "ecmaFeatures": { - "jsx": true - } - }, - "globals": { - "document": true, - "window": true - }, - "env": { - "jest": true - }, - "plugins": [ - "jest", - "prettier" - ], - "settings": { - "react": { - "pragma": "React", - "version": "16.3" - } - }, - "rules": { - "prettier/prettier": "error", - "arrow-body-style": [2, "always"], - "no-console": 0, - "no-param-reassign": 0, - "react/jsx-filename-extension": 0, - "import/no-extraneous-dependencies": 0, - "global-require": 0, - "jsx-a11y/media-has-caption": 0, - "import/prefer-default-export": 0, - "react/forbid-prop-types": 0, - "max-len": 0, - "jsx-a11y/accessible-emoji": 0, - "jsx-a11y/href-no-hash": 0, - "jest/no-disabled-tests": "warn", - "jest/no-focused-tests": "error", - "jest/no-identical-title": "error", - "jest/valid-expect": "error", - "no-underscore-dangle": 0, - "react/jsx-one-expression-per-line": 0, - "jsx-a11y/click-events-have-key-events": 0, - "react/jsx-props-no-spreading": 0, - "react/forbid-foreign-prop-types": 0, - "jsx-a11y/anchor-is-valid": 0, - "react/destructuring-assignment": 0, - "jsx-a11y/label-has-associated-control": 0, - "react/require-default-props": 0, - "react/default-props-match-prop-types": 0, - "react/prop-types": 0 - } -} \ No newline at end of file diff --git a/.eslintrc.cjs b/.eslintrc.cjs new file mode 100644 index 000000000..6253f2c93 --- /dev/null +++ b/.eslintrc.cjs @@ -0,0 +1,45 @@ +module.exports = { + extends: ['airbnb', 'plugin:react-hooks/recommended', 'prettier'], + parserOptions: { + ecmaVersion: 2022, + }, + globals: { + window: true, + document: true, + }, + env: { + es2022: true, + browser: true, + node: true, + jest: true, + }, + plugins: ['prettier', 'import'], + rules: { + 'react/prop-types': 0, + 'react/jsx-filename-extension': 0, + 'react/jsx-props-no-spreading': 0, + 'jsx-a11y/click-events-have-key-events': 0, + 'jsx-a11y/anchor-is-valid': 0, + 'jsx-a11y/label-has-associated-control': 0, + 'react/forbid-prop-types': 0, + 'react/function-component-definition': [ + 2, + { + namedComponents: 'arrow-function', + unnamedComponents: 'arrow-function', + }, + ], + 'react/require-default-props': 0, + 'prettier/prettier': 2, + 'no-console': 0, + 'no-param-reassign': 0, + 'import/no-extraneous-dependencies': 0, + 'global-require': 0, + 'import/prefer-default-export': 0, + 'max-len': 0, + 'no-underscore-dangle': 0, + 'class-methods-use-this': 0, + 'arrow-body-style': [2, 'always'], + 'import/no-dynamic-require': 0, + }, +}; diff --git a/.github/actions/npm-install/action.yaml b/.github/actions/npm-install/action.yaml new file mode 100644 index 000000000..5583b9501 --- /dev/null +++ b/.github/actions/npm-install/action.yaml @@ -0,0 +1,37 @@ +name: 'Install dependencies' +description: 'Install dependencies and cache' +author: 'GDM BX UI Tools' +inputs: + install-options: + description: 'Install options' + required: false + default: '--ignore-scripts --no-audit' + working-directory: + description: 'Working directory' + required: false + default: '.' +runs: + using: 'composite' + steps: + - name: 'node_modules cache' + id: cache-npm + uses: actions/cache@v3 + env: + cache-name: cache-node-modules + with: + # npm cache files are stored in `~/.npm` on Linux/macOS + path: | + ~/.npm + **/node_modules + key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }} + restore-keys: | + ${{ runner.os }}-build-${{ env.cache-name }}- + ${{ runner.os }}-build- + ${{ runner.os }}- + - name: Install Dependencies + if: steps.cache-npm.outputs.cache-hit != 'true' + shell: bash + working-directory: ${{ inputs.working-directory }} + env: + NODE_ENV: development + run: npm ci ${{ inputs.install-options }} diff --git a/.github/actions/parse-info/action.yaml b/.github/actions/parse-info/action.yaml new file mode 100644 index 000000000..33f372b91 --- /dev/null +++ b/.github/actions/parse-info/action.yaml @@ -0,0 +1,49 @@ +name: 'Parse Git Information' +description: 'Parse git information for tags, version, commit message' +outputs: + tag: + description: 'latest for master, pr-X for pr instances otherwise undefined' + value: ${{ steps.parse.outputs.tag }} + version: + description: 'Current Version' + value: ${{ steps.parse.outputs.version }} + branch: + description: 'Current Branch' + value: ${{ steps.parse.outputs.branch }} + message: + description: 'Current commit message' + value: ${{ steps.parse.outputs.message }} + updateType: + description: 'Parse commit message to get the release type [pre|major,minot,path,release]' + value: ${{ steps.parse.outputs.updateType }} + +runs: + using: 'composite' + steps: + - name: 'Parse GIT Information' + shell: bash + id: parse + run: | + declare -A TAGS_MAP + TAGS_MAP=(["master"]="latest") + VERSION=$(git describe --tags --always) + BRANCH=$(git rev-parse --abbrev-ref HEAD | sed -r "s/\//\-/g") + TAG=${TAGS_MAP[$BRANCH]} + if [ -d $TAG ]; then + TAG=pr-${{ github.event.number }} + fi + commit_message=$(git log --format=%B -n 1 ${{ github.sha }}) + echo "MESSAGE<> $GITHUB_ENV + echo "${commit_message}" >> $GITHUB_ENV + echo "EOF" >> $GITHUB_ENV + echo "version=$VERSION" >> $GITHUB_OUTPUT + echo "tag=$TAG" >> $GITHUB_OUTPUT + echo "branch=$BRANCH" >> $GITHUB_OUTPUT + echo "message=$(echo \"${commit_message}\")" >> $GITHUB_OUTPUT + regex='\[((pre)?(minor|patch|major|release))\]' + if [[ $commit_message =~ $regex ]]; then + echo "updateType=$(echo ${BASH_REMATCH[1]})" >> $GITHUB_OUTPUT + fi + echo "----- output ------" + cat $GITHUB_OUTPUT + echo "-------------------" diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml new file mode 100644 index 000000000..d2ef901aa --- /dev/null +++ b/.github/workflows/continuous-integration.yml @@ -0,0 +1,47 @@ +name: Continuous Integration +on: + pull_request: + branches: + - master + - next + +concurrency: + group: ${{ github.ref }} + cancel-in-progress: true + +jobs: + lint: + runs-on: ubuntu-latest + name: Linter + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Install dependencies + uses: ./.github/actions/npm-install + - name: Run eslint + run: npm run eslint + test: + runs-on: ubuntu-latest + name: Tests + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Install dependencies + uses: ./.github/actions/npm-install + - name: Run Test + run: npm run test:cov + - name: Code Coverage Report + uses: irongut/CodeCoverageSummary@v1.3.0 + with: + filename: .coverage/cobertura-coverage.xml + badge: true + format: markdown + hide_branch_rate: false + hide_complexity: true + output: both + - name: Add Coverage PR Comment + uses: marocchino/sticky-pull-request-comment@v2 + if: github.event_name == 'pull_request' + with: + recreate: true + path: code-coverage-results.md \ No newline at end of file diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 000000000..71a404f94 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,99 @@ +name: Release +on: + push: + branches: + - master + +permissions: + contents: write + packages: write + id-token: write + +concurrency: + group: ${{ github.ref }} + cancel-in-progress: true + +jobs: + setup: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Setup base + id: parse + uses: ./.github/actions/parse-info + - name: Version to bump + id: bump + env: + MESSAGE: ${{ steps.parse.outputs.message }} + run: | + regex='\[((pre)?(minor|patch|major|release))\]' + if [[ $MESSAGE =~ $regex ]]; then + echo "updateType=${BASH_REMATCH[1]}" >> $GITHUB_OUTPUT + fi + outputs: + updateType: ${{ steps.bump.outputs.updateType }} + test: + runs-on: ubuntu-latest + name: Lint & Tests + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Install dependencies + uses: ./.github/actions/npm-install + - name: Run Test + run: npm run test + release: + runs-on: ubuntu-latest + name: Publish + needs: [setup, test] + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + persist-credentials: false + - name: Install dependencies + uses: ./.github/actions/npm-install + - name: 'Generate new version' + id: updatedVersion + if: ${{ needs.setup.outputs.updateType }} + env: + TYPE: ${{ needs.setup.outputs.updateType }} + run: | + git config --global user.name "${{ github.actor }}" + git config --global user.email "${{ github.actor }}@users.noreply.github.com" + npm version $(echo ${TYPE}) -m "v%s - [skip ci]" + echo "version=$(echo $(git describe))" >> $GITHUB_OUTPUT + git diff HEAD~ HEAD + - name: Build + shell: bash + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + echo "//registry.npmjs.org/:_authToken=${NPM_TOKEN}" > ~/.npmrc + NODE_ENV=production npm run build + - name: Push changes + uses: ad-./.github-push-action@master + if: ${{ needs.setup.outputs.updateType }} + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + branch: ${{ github.ref }} + tags: true + atomic: true + - name: Generate Release + uses: octokit/request-action@v2.x + if: ${{ needs.setup.outputs.updateType }} + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + route: POST /repos/:repository/releases + repository: ${{ github.repository }} + tag_name: ${{ steps.updatedVersion.outputs.version }} + generate_release_notes: true + - name: Deploy packages + if: ${{ needs.setup.outputs.updateType }} + run: | + npm publish diff --git a/.gitignore b/.gitignore index 32c30e4c5..658a661eb 100644 --- a/.gitignore +++ b/.gitignore @@ -43,6 +43,7 @@ jspm_packages/ # Typescript v1 declaration files typings/ +dist # Optional npm cache directory .npm @@ -72,4 +73,6 @@ out* /cjs .coverage .vscode -.cache \ No newline at end of file +.cache +*storybook.log +storybook-static diff --git a/.npmignore b/.npmignore index 83209f407..284023d6e 100644 --- a/.npmignore +++ b/.npmignore @@ -1,18 +1,2 @@ -.coverage -.storybook -docs -node_modules -.babelrc -.eslint* -.git* -README.md -webpack.config.js -yarn* -.npmignore -reports -**/__mocks__ -.coveralls.yml -.travis.yml -.yarnclean -jest.json -**/__test__ \ No newline at end of file +* +!dist \ No newline at end of file diff --git a/.storybook/main.js b/.storybook/main.js index 51de7edae..91f7bf643 100644 --- a/.storybook/main.js +++ b/.storybook/main.js @@ -1,32 +1,36 @@ -const path = require('path'); -const { DefinePlugin } = require('webpack'); - -module.exports = { - stories: ['../src/**/*.story.mdx'], +/** @type { import('@storybook/react-vite').StorybookConfig } */ +const config = { + stories: ['../src/**/*.stories.js'], addons: [ + '@storybook/addon-onboarding', + '@storybook/addon-links', '@storybook/addon-essentials', - { - name: '@storybook/addon-storysource', - options: { - rule: { - test: [/\.story\.js?$/], + '@storybook/addon-interactions', + ], + framework: { + name: '@storybook/react-vite', + }, + async viteFinal(config) { + // Merge custom configuration into the default config + const { mergeConfig } = await import('vite'); + return mergeConfig(config, { + // Add dependencies to pre-optimization + optimizeDeps: { + esbuildOptions: { + loader: { + '.js': 'jsx', + }, }, }, - }, - '@storybook/addon-knobs', - '@storybook/addon-links', - '@storybook/addon-events', - '@storybook/addon-viewport', - '@storybook/addon-postcss', - 'storybook-addon-react-docgen', - '@storybook/preset-scss', - ], - webpackFinal: (config) => { - config.resolve.modules.push('node_modules', 'src'); - config.resolve.alias['react-bulma-components'] = path.resolve( - __dirname, - '../src', - ); - return config; + esbuild: { + include: /\.js$/, + exclude: [], + loader: 'jsx', + }, + }); + }, + docs: { + autodocs: 'tag', }, }; +export default config; diff --git a/.storybook/manager.js b/.storybook/manager.js deleted file mode 100644 index 6d6534f28..000000000 --- a/.storybook/manager.js +++ /dev/null @@ -1,6 +0,0 @@ -import { addons } from '@storybook/addons'; -import theme from './theme'; - -addons.setConfig({ - theme, -}); diff --git a/.storybook/package.json b/.storybook/package.json deleted file mode 100644 index c9a442261..000000000 --- a/.storybook/package.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "type": "commonjs" -} \ No newline at end of file diff --git a/.storybook/preview.js b/.storybook/preview.js index 46af94c8e..9d1c8ee49 100644 --- a/.storybook/preview.js +++ b/.storybook/preview.js @@ -1,60 +1,15 @@ -import { addDecorator } from '@storybook/react'; -import { withPropsTable } from 'storybook-addon-react-docgen'; -import { MINIMAL_VIEWPORTS} from '@storybook/addon-viewport'; +import 'bulma/css/bulma.min.css'; -import test from './rewrites.scss' -import '@fortawesome/fontawesome-free/css/all.min.css'; - -console.log(test); - -addDecorator(withPropsTable); - -export const parameters = { - layout: 'padded', - viewMode: 'docs', - viewport: { - viewports: { - ...MINIMAL_VIEWPORTS, - "tablet": { - "name": "Tablet", - "styles": { - "width": "1023px", - "height": "963px" - }, - "type": "tablet" - }, - "desktop": { - "name": "Desktop", - "styles": { - "width": "1215px", - "height": "100%" - }, - "type": "desktop" +/** @type { import('@storybook/react').Preview } */ +const preview = { + parameters: { + controls: { + matchers: { + color: /(background|color)$/i, + date: /Date$/i, }, - "widescreen": { - "name": "Widescreen", - "styles": { - "width": "1407px", - "height": "100%" - }, - "type": "desktop" - }, - "fullhd": { - "name": "Fullhd", - "styles": { - "width": "1920px", - "height": "100%" - }, - "type": "desktop" - }, - } - }, - options: { - storySort: { - order: ['Welcome', 'Changelog', 'Core Component', 'Columns', 'Elements', 'Components', 'Form', 'Layout'], }, }, - previewTabs: { - 'storybook/docs/panel': { index: 0, default: true }, - } }; + +export default preview; diff --git a/.storybook/rewrites.scss b/.storybook/rewrites.scss deleted file mode 100644 index eb6857c56..000000000 --- a/.storybook/rewrites.scss +++ /dev/null @@ -1,33 +0,0 @@ - -pre code { - color: currentColor; -} - -pre code .tag.token { - background-color: unset; - border-radius: unset; - display: unset; - font-size: 1em; - height: unset; - padding-left: unset; - padding-right: unset; - white-space: unset; -} -pre code .number.token { - margin-right: unset; -} - -pre code .plain-text { - color: #da1039; -} - -pre code .number{ - padding: unset; - min-width: unset; - font-size: unset; - height: unset; -} - -$custom-colors: ("brand": (#8A4D76, #FFF), "custom": (#f88fa1,#000)); - -@import "~bulma/bulma.sass"; \ No newline at end of file diff --git a/.storybook/theme.js b/.storybook/theme.js deleted file mode 100644 index 0cd9f1b9e..000000000 --- a/.storybook/theme.js +++ /dev/null @@ -1,10 +0,0 @@ -import { create } from '@storybook/theming/create'; - -export default create({ - base: 'light', - brandTitle: 'React Bulma Components', - brandUrl: 'https://www.github.com/couds/react-bulma-components', - - colorPrimary: '#00D6B1', - colorSecondary: '#00D6B1', -}); diff --git a/CHANGELOG.md b/CHANGELOG.md index 26e90e86b..6318f6fa2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ # Changelog +## 5.0.0 +- **[Breaking Change]** `` now became a controlled component instead of simulating a `Select/Combobox`. +- Rename Library from `React Bulma Component` to `React Bulma` under `@couds` scope +- Refactror how Types are defined to better type checking +- Add Skeleton utility +- Add Color Mode prop +- Add Typescript Util `BulmaComponentPropsType` to get the props any Bulma Component `type props = BulmaComponentPropsType + + + + ); + }, + args: {}, +}; diff --git a/src/components/box/box.story.js b/src/components/box/box.story.js deleted file mode 100644 index 93752307f..000000000 --- a/src/components/box/box.story.js +++ /dev/null @@ -1,30 +0,0 @@ -import React from 'react'; - -import { Box, Form, Button } from '../..'; - -export const Default = () => { - return ( - -
- - Email - - - - - - Password - - - - - - - -
-
- ); -}; diff --git a/src/components/box/box.story.mdx b/src/components/box/box.story.mdx deleted file mode 100644 index 4cb20d1d4..000000000 --- a/src/components/box/box.story.mdx +++ /dev/null @@ -1,23 +0,0 @@ -import { Meta, Story, Canvas, ArgsTable } from '@storybook/addon-docs/blocks'; -import * as stories from './box.story'; -import { Box } from '../..' -import CommonProps from '../../../.storybook/common-props'; - - - -# Box - -A white box element to contain other elements - - - - - -## Example - - - - -## Related - -- [Official documentation](https://bulma.io/documentation/elements/box) diff --git a/src/components/box/index.d.ts b/src/components/box/index.d.ts index a328ac497..d2aa3b203 100644 --- a/src/components/box/index.d.ts +++ b/src/components/box/index.d.ts @@ -1,5 +1,3 @@ import { BulmaComponent } from '..'; -declare const Box: BulmaComponent<{}, 'div'>; - -export default Box; \ No newline at end of file +export declare const Box: BulmaComponent; diff --git a/src/components/box/index.js b/src/components/box/index.js index 0819ce514..bbe978994 100644 --- a/src/components/box/index.js +++ b/src/components/box/index.js @@ -1,3 +1 @@ -import Box from './box'; - -export default Box; +export * from './box'; diff --git a/src/components/breadcrumb/__test__/__snapshots__/breadcrumb.test.js.snap b/src/components/breadcrumb/__test__/__snapshots__/breadcrumb.test.js.snap index 1cb136b07..13d2d5297 100644 --- a/src/components/breadcrumb/__test__/__snapshots__/breadcrumb.test.js.snap +++ b/src/components/breadcrumb/__test__/__snapshots__/breadcrumb.test.js.snap @@ -1,232 +1,246 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Breadcrumb component Breadcrumb.Item component should have is-active class 1`] = ` -
  • - active item -
  • + +
  • + active item +
  • +
    `; exports[`Breadcrumb component Breadcrumb.Item component should render
  • 1`] = ` -
  • - item -
  • + +
  • + item +
  • +
    `; exports[`Breadcrumb component Should be a Breadcrumb 1`] = ` - + + + `; exports[`Breadcrumb component Should use inline style and custom size 1`] = ` - + + + `; exports[`Breadcrumb component should use separator arrow 1`] = ` - + + + `; exports[`Breadcrumb component should use separator bullet 1`] = ` - + + + `; exports[`Breadcrumb component should use separator dot 1`] = ` - + + + `; exports[`Breadcrumb component should use separator null 1`] = ` - + + + `; exports[`Breadcrumb component should use separator succeeds 1`] = ` - + + + `; diff --git a/src/components/breadcrumb/__test__/breadcrumb.test.js b/src/components/breadcrumb/__test__/breadcrumb.test.js index 642416a65..6df2623dc 100644 --- a/src/components/breadcrumb/__test__/breadcrumb.test.js +++ b/src/components/breadcrumb/__test__/breadcrumb.test.js @@ -1,26 +1,24 @@ import React from 'react'; -import renderer from 'react-test-renderer'; -import Breadcrumb from '..'; +import { render } from '@testing-library/react'; +import { Breadcrumb } from '..'; describe('Breadcrumb component', () => { describe('Breadcrumb.Item component', () => { it('should render
  • ', () => { - const component = renderer.create( - item, - ); - expect(component.toJSON()).toMatchSnapshot(); + const component = render(item); + expect(component.asFragment()).toMatchSnapshot(); }); it('should have is-active class', () => { - const component = renderer.create( + const component = render( active item, ); - expect(component.toJSON()).toMatchSnapshot(); + expect(component.asFragment()).toMatchSnapshot(); }); }); it('Should be a Breadcrumb', () => { - const component = renderer.create( + const component = render( Home @@ -33,12 +31,12 @@ describe('Breadcrumb component', () => { , ); - expect(component.toJSON()).toMatchSnapshot(); + expect(component.asFragment()).toMatchSnapshot(); }); - [null, 'arrow', 'dot', 'bullet', 'succeeds'].map((separator) => - it(`should use separator ${separator}`, () => { - const component = renderer.create( + [null, 'arrow', 'dot', 'bullet', 'succeeds'].map((separator) => { + return it(`should use separator ${separator}`, () => { + const component = render( Storybook @@ -51,12 +49,12 @@ describe('Breadcrumb component', () => { , ); - expect(component.toJSON()).toMatchSnapshot(); - }), - ); + expect(component.asFragment()).toMatchSnapshot(); + }); + }); it('Should use inline style and custom size', () => { - const component = renderer.create( + const component = render( Home @@ -69,6 +67,6 @@ describe('Breadcrumb component', () => { , ); - expect(component.toJSON()).toMatchSnapshot(); + expect(component.asFragment()).toMatchSnapshot(); }); }); diff --git a/src/components/breadcrumb/breadcrumb.js b/src/components/breadcrumb/breadcrumb.js index fbe0c830a..c47a284c0 100644 --- a/src/components/breadcrumb/breadcrumb.js +++ b/src/components/breadcrumb/breadcrumb.js @@ -1,10 +1,13 @@ import React from 'react'; -import PropTypes from 'prop-types'; -import classnames from 'classnames'; -import Element from '../element'; +import clsx from 'clsx'; +import { Element } from '../element'; import BreadcrumbItem from './components/item'; -const Breadcrumb = ({ +/** + * + * @type {typeof import('.').Breadcrumb} + */ +export const Breadcrumb = ({ className, separator, size, @@ -14,8 +17,9 @@ const Breadcrumb = ({ }) => { return ( { + return ( +
    + + + + Storybook + + + Breadcrumb + + + Details + + + +
    + ); + }, + argTypes: { + separator: { + control: { + type: 'select', + }, + options: ['arrow', 'dot', 'bullet', 'succeeds'], + }, + align: { + control: { + type: 'select', + }, + options: ['left', 'right'], + }, + size: { + control: { + type: 'select', + }, + options: ['default', 'small', 'medium', 'large'], + }, + }, +}; diff --git a/src/components/breadcrumb/breadcrumb.story.js b/src/components/breadcrumb/breadcrumb.story.js deleted file mode 100644 index a37a26f66..000000000 --- a/src/components/breadcrumb/breadcrumb.story.js +++ /dev/null @@ -1,44 +0,0 @@ -import React from 'react'; - -import { Box, Breadcrumb } from '../..'; - -export const Default = (args) => { - return ( -
    - - - - Storybook - - - Breadcrumb - - - Details - - - -
    - ); -}; - -Default.argTypes = { - separator: { - control: { - type: 'select', - options: ['arrow', 'dot', 'bullet', 'succeeds'], - }, - }, - align: { - control: { - type: 'select', - options: ['center', 'right'], - }, - }, - size: { - control: { - type: 'select', - options: ['default', 'small', 'medium', 'large'], - }, - }, -}; diff --git a/src/components/breadcrumb/breadcrumb.story.mdx b/src/components/breadcrumb/breadcrumb.story.mdx deleted file mode 100644 index 6c2582a49..000000000 --- a/src/components/breadcrumb/breadcrumb.story.mdx +++ /dev/null @@ -1,34 +0,0 @@ -import { Canvas, Meta, Story, ArgsTable } from '@storybook/addon-docs/blocks'; -import * as stories from './breadcrumb.story'; -import Breadcrumb from './breadcrumb'; -import CommonProps from '../../../.storybook/common-props'; - - - -# Breadcrumb - -A simple navigation component with a customizable separator. Suitable for hierarchical navigations. - -You can inform the current page using the active props in `Breadcrumb.Item` component. It will disable the navigation of inner links. - -## Props - -### Breadcrumb - - - -### Breadcrumb.Item - - - - - -## Example - - - - - -## Related - -- [Official documentation](https://bulma.io/documentation/components/breadcrumb) diff --git a/src/components/breadcrumb/components/item.js b/src/components/breadcrumb/components/item.js index 1c62a9568..86be4c774 100644 --- a/src/components/breadcrumb/components/item.js +++ b/src/components/breadcrumb/components/item.js @@ -1,14 +1,14 @@ import React from 'react'; -import PropTypes from 'prop-types'; -import classNames from 'classnames'; +import clsx from 'clsx'; -import Element from '../../element'; +import { Element } from '../../element'; const BreadcrumbItem = ({ className, active, children, ...props }) => { return ( @@ -17,17 +17,6 @@ const BreadcrumbItem = ({ className, active, children, ...props }) => { ); }; -BreadcrumbItem.propTypes = { - active: PropTypes.bool, - renderAs: PropTypes.oneOfType([ - PropTypes.func, - PropTypes.string, - PropTypes.object, - ]), -}; - -BreadcrumbItem.defaultProps = { - renderAs: 'li', -}; +Element.setDisplayName(BreadcrumbItem, 'Breadcrumb.Item'); export default BreadcrumbItem; diff --git a/src/components/breadcrumb/index.d.ts b/src/components/breadcrumb/index.d.ts index 8c7c63c42..b2c586aaf 100644 --- a/src/components/breadcrumb/index.d.ts +++ b/src/components/breadcrumb/index.d.ts @@ -1,18 +1,18 @@ import { BulmaComponent } from '..'; import { Size } from '..'; -interface BreadcrumbProps { +/** + * @parent Breadcrumb + * @name Breadcrumb.Item + */ +export declare const BreadcrumbItem: BulmaComponent<{ + active?: boolean; +}, 'li'>; + +export declare const Breadcrumb: BulmaComponent<{ separator?: 'arrow' | 'bullet' | 'dot' | 'succeeds'; size?: Size; align?: 'right' | 'center'; -} - -interface BreadcrumbItemProps { - active?: boolean; -} - -declare const Breadcrumb: BulmaComponent & { - Item: BulmaComponent; -}; - -export default Breadcrumb; +}, 'nav', { + Item: typeof BreadcrumbItem; +}>; diff --git a/src/components/breadcrumb/index.js b/src/components/breadcrumb/index.js index c604936f5..e10b05199 100644 --- a/src/components/breadcrumb/index.js +++ b/src/components/breadcrumb/index.js @@ -1,3 +1 @@ -import Breadcrumb from './breadcrumb'; - -export default Breadcrumb; +export * from './breadcrumb'; diff --git a/src/components/button/__test__/__snapshots__/button.test.js.snap b/src/components/button/__test__/__snapshots__/button.test.js.snap index b6e2d3e3c..0dfaed843 100644 --- a/src/components/button/__test__/__snapshots__/button.test.js.snap +++ b/src/components/button/__test__/__snapshots__/button.test.js.snap @@ -1,143 +1,219 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Button component Button Group component Should align to the right 1`] = ` -
    - - -
    + + + + `; exports[`Button component Button Group component Should be a default list of buttons 1`] = ` -
    - - -
    +{ + "asFragment": [Function], + "baseElement": +
    +
    + + +
    +
    + , + "container":
    +
    + + +
    +
    , + "debug": [Function], + "findAllByAltText": [Function], + "findAllByDisplayValue": [Function], + "findAllByLabelText": [Function], + "findAllByPlaceholderText": [Function], + "findAllByRole": [Function], + "findAllByTestId": [Function], + "findAllByText": [Function], + "findAllByTitle": [Function], + "findByAltText": [Function], + "findByDisplayValue": [Function], + "findByLabelText": [Function], + "findByPlaceholderText": [Function], + "findByRole": [Function], + "findByTestId": [Function], + "findByText": [Function], + "findByTitle": [Function], + "getAllByAltText": [Function], + "getAllByDisplayValue": [Function], + "getAllByLabelText": [Function], + "getAllByPlaceholderText": [Function], + "getAllByRole": [Function], + "getAllByTestId": [Function], + "getAllByText": [Function], + "getAllByTitle": [Function], + "getByAltText": [Function], + "getByDisplayValue": [Function], + "getByLabelText": [Function], + "getByPlaceholderText": [Function], + "getByRole": [Function], + "getByTestId": [Function], + "getByText": [Function], + "getByTitle": [Function], + "queryAllByAltText": [Function], + "queryAllByDisplayValue": [Function], + "queryAllByLabelText": [Function], + "queryAllByPlaceholderText": [Function], + "queryAllByRole": [Function], + "queryAllByTestId": [Function], + "queryAllByText": [Function], + "queryAllByTitle": [Function], + "queryByAltText": [Function], + "queryByDisplayValue": [Function], + "queryByLabelText": [Function], + "queryByPlaceholderText": [Function], + "queryByRole": [Function], + "queryByTestId": [Function], + "queryByText": [Function], + "queryByTitle": [Function], + "rerender": [Function], + "unmount": [Function], +} `; exports[`Button component Button Group component Should be centered 1`] = ` -
    - - -
    + + + + `; exports[`Button component Button Group component Should concat class names in props with Bulma class name 1`] = ` -
    - - -
    + + + + `; exports[`Button component Button Group component Should group buttons together 1`] = ` -
    - - -
    + + + + `; exports[`Button component Should be a Large Primary Button 1`] = ` -, ); - expect(component.toJSON()).toMatchSnapshot(); + expect(component.asFragment()).toMatchSnapshot(); }); it('Should render be disabled', () => { - const component = renderer.create(); + await user.click(screen.getByText('click')); expect(onClick).toHaveBeenCalledTimes(1); }); - it('Should have no dispatch click handler if disabled', () => { + it('Should have no dispatch click handler if disabled', async () => { const onClick = jest.fn(); - const component = shallow(, + ); + await user.click(screen.getByText('click')); expect(onClick).toHaveBeenCalledTimes(0); }); - it('Should forward ref', () => { - const testRef = React.createRef(); - mount( @@ -113,40 +100,40 @@ describe('Button component', () => { expect(component).toMatchSnapshot(); }); it('Should concat class names in props with Bulma class name', () => { - const component = renderer.create( + const component = render( , ); - expect(component.toJSON()).toMatchSnapshot(); + expect(component.asFragment()).toMatchSnapshot(); }); it('Should group buttons together', () => { - const component = renderer.create( + const component = render( , ); - expect(component.toJSON()).toMatchSnapshot(); + expect(component.asFragment()).toMatchSnapshot(); }); it('Should be centered', () => { - const component = renderer.create( + const component = render( , ); - expect(component.toJSON()).toMatchSnapshot(); + expect(component.asFragment()).toMatchSnapshot(); }); it('Should align to the right', () => { - const component = renderer.create( + const component = render( , ); - expect(component.toJSON()).toMatchSnapshot(); + expect(component.asFragment()).toMatchSnapshot(); }); }); }); diff --git a/src/components/button/button.js b/src/components/button/button.js index d1ed43f55..936c850a8 100644 --- a/src/components/button/button.js +++ b/src/components/button/button.js @@ -1,20 +1,16 @@ import React from 'react'; -import PropTypes from 'prop-types'; -import classnames from 'classnames'; +import clsx from 'clsx'; import ButtonGroup from './components/button-group'; -import Element from '../element'; +import { Element } from '../element'; import { normalizeStatus } from '../../services/normalizer'; -const Button = ({ +export const Button = ({ children, className, - renderAs, color, size, outlined, inverted, - submit, - reset, fullwidth, status, loading, @@ -25,37 +21,17 @@ const Button = ({ rounded, onClick, text, + contrast, ...props }) => { - let otherProps = {}; - if (submit) { - otherProps = { - type: 'submit', - renderAs: 'button', - }; - } - if (reset) { - otherProps = { - type: 'reset', - renderAs: 'button', - }; - } - - if (isStatic) { - otherProps = { - renderAs: 'span', - }; - } - return ( { - return ( - <> - - - - - - - - - - - - ); +export default { + title: 'Elements/Button', +}; + +export const Default = { + render: ({ hasAddons, groupSize, align, ...args }) => { + return ( + <> + + + + + + + + + + + + ); + }, }; Default.argTypes = { @@ -48,8 +54,8 @@ Default.argTypes = { }, control: { type: 'select', - options: ['default', 'center', 'right'], }, + options: ['default', 'center', 'right'], }, groupSize: { table: { @@ -57,8 +63,8 @@ Default.argTypes = { }, control: { type: 'select', - options: ['default', 'small', 'medium', 'large'], }, + options: ['default', 'small', 'medium', 'large'], }, remove: { table: { @@ -74,8 +80,8 @@ Default.argTypes = { }, control: { type: 'select', - options: ['default', 'small', 'medium', 'large'], }, + options: ['default', 'small', 'medium', 'large'], }, colorVariant: { table: { @@ -84,8 +90,8 @@ Default.argTypes = { description: 'Variant of the color scheme', control: { type: 'select', - options: Object.values(CONSTANTS.COLOR_VARIANT), }, + options: Object.values(CONSTANTS.COLOR_VARIANT), }, fullwidth: { table: { @@ -104,8 +110,8 @@ Default.argTypes = { defaultValue: '', control: { type: 'select', - options: Object.values(CONSTANTS.COLORS), }, + options: Object.values(CONSTANTS.COLORS), }, outlined: { table: { diff --git a/src/components/button/button.story.mdx b/src/components/button/button.story.mdx deleted file mode 100644 index 7a5eca190..000000000 --- a/src/components/button/button.story.mdx +++ /dev/null @@ -1,34 +0,0 @@ -import { ArgsTable, Canvas, Meta, Story } from '@storybook/addon-docs/blocks'; -import Button from '.'; -import * as stories from './button.story'; -import CommonProps from '../../../.storybook/common-props'; - - - -# Button - -A basic UI component that allows users to perform action. - -## Props - -Props that Button accepts, on top of modifier props. Go to canvas to play with the props. - - - -## Button group - -Multiple buttons can be grouped together to form a group, using the ` - - - -## Example - - - - - -## Related - -- [Official documentation](https://bulma.io/documentation/elements/button) \ No newline at end of file diff --git a/src/components/button/components/button-group.js b/src/components/button/components/button-group.js index 3e2e4af4d..218e5f613 100644 --- a/src/components/button/components/button-group.js +++ b/src/components/button/components/button-group.js @@ -1,14 +1,16 @@ import React from 'react'; -import PropTypes from 'prop-types'; -import classnames from 'classnames'; -import Element from '../../element'; +import clsx from 'clsx'; +import { Element } from '../../element'; import { normalizeAlign } from '../../../services/normalizer'; - +/** + * @type {typeof import('.').ButtonGroup} + */ const ButtonGroup = ({ className, hasAddons, align, size, ...props }) => { return ( { ); }; -ButtonGroup.propTypes = { - hasAddons: PropTypes.bool, - /** - * The size of *all* the buttons in the group. - */ - size: PropTypes.oneOf(['small', 'medium', 'large']), - /** - * Align of the group. By default, it is left-aligned. - */ - align: PropTypes.oneOf(['center', 'right']), - renderAs: PropTypes.oneOfType([ - PropTypes.func, - PropTypes.string, - PropTypes.object, - ]), -}; - -ButtonGroup.defaultProps = { - renderAs: 'div', -}; +Element.setDisplayName(ButtonGroup, 'Button.Group'); export default ButtonGroup; diff --git a/src/components/button/components/index.d.ts b/src/components/button/components/index.d.ts new file mode 100644 index 000000000..d3418320e --- /dev/null +++ b/src/components/button/components/index.d.ts @@ -0,0 +1,14 @@ +import { Size, BulmaComponent } from '../..'; + +type ButtonGroupProps = { + size?: Size; + hasAddons?: boolean; + align?: 'center' | 'right'; +}; + +/** + * Group 2 or more buttons + * @parent Button + * @name Button.Group + */ +export declare const ButtonGroup: BulmaComponent; \ No newline at end of file diff --git a/src/components/button/index.d.ts b/src/components/button/index.d.ts index 0c5100478..7766b35c1 100644 --- a/src/components/button/index.d.ts +++ b/src/components/button/index.d.ts @@ -1,22 +1,22 @@ import { BulmaComponent } from '..'; import { Color, Size } from '..'; +import { ButtonGroup } from './components'; -interface ButtonProps { +export type ButtonProps = { color?: Color - | 'ghost' - | 'black-bis' - | 'black-ter' - | 'white-bis' - | 'white-ter' - | 'grey-darker' - | 'grey-dark' - | 'grey-light' - | 'grey-lighter'; + | 'ghost'; + contrast?: 'light' | 'dark'; size?: Size; state?: 'hover' | 'focus' | 'active'; outlined?: boolean; inverted?: boolean; + /** + * @deprecated Use as="button" type="submit" instead + */ submit?: boolean; + /** + * @deprecated Use as="button" type="reset" instead + */ reset?: boolean; loading?: boolean; fullwidth?: boolean; @@ -28,14 +28,6 @@ interface ButtonProps { text?: boolean; } -interface ButtonGroupProps { - size?: Size; - hasAddons?: boolean; - align?: 'center' | 'right'; -} - -declare const Button: BulmaComponent & { - Group: BulmaComponent; -}; - -export default Button \ No newline at end of file +export declare const Button: BulmaComponent; diff --git a/src/components/button/index.js b/src/components/button/index.js index 7e524c5d6..eaf5eea7f 100644 --- a/src/components/button/index.js +++ b/src/components/button/index.js @@ -1,3 +1 @@ -import Button from './button'; - -export default Button; +export * from './button'; diff --git a/src/components/card/__test__/__snapshots__/card.test.js.snap b/src/components/card/__test__/__snapshots__/card.test.js.snap index ec39a05ad..606f33dcd 100644 --- a/src/components/card/__test__/__snapshots__/card.test.js.snap +++ b/src/components/card/__test__/__snapshots__/card.test.js.snap @@ -1,77 +1,86 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Card component Should have card classname 1`] = ` -
    - Card Content -
    + +
    + Card Content +
    +
    `; exports[`Card component Should have card-content classname 1`] = ` -
    - Content -
    + +
    + Content +
    +
    `; exports[`Card component Should have card-footer's classname 1`] = ` -
    +
    - Yes -
    -
    -
    + `; exports[`Card component Should have card-header's classname 1`] = ` -
    +
    - Title -
    -
    - +
    + Title +
    +
    + +
    -
    + `; exports[`Card component Should have card-image classname 1`] = ` -
    -
    +
    - -
    -
    +
    + +
    + + `; diff --git a/src/components/card/__test__/card.test.js b/src/components/card/__test__/card.test.js index 55c2ff038..09215a531 100644 --- a/src/components/card/__test__/card.test.js +++ b/src/components/card/__test__/card.test.js @@ -1,27 +1,27 @@ import React from 'react'; -import renderer from 'react-test-renderer'; -import Card from '..'; +import { render } from '@testing-library/react'; +import { Card } from '..'; describe('Card component', () => { it('Should have card classname', () => { - const component = renderer.create(Card Content); - expect(component.toJSON()).toMatchSnapshot(); + const component = render(Card Content); + expect(component.asFragment()).toMatchSnapshot(); }); it('Should have card-image classname', () => { - const component = renderer.create( + const component = render( , ); - expect(component.toJSON()).toMatchSnapshot(); + expect(component.asFragment()).toMatchSnapshot(); }); it('Should have card-content classname', () => { - const component = renderer.create(Content); - expect(component.toJSON()).toMatchSnapshot(); + const component = render(Content); + expect(component.asFragment()).toMatchSnapshot(); }); it("Should have card-header's classname", () => { - const component = renderer.create( + const component = render( Title @@ -31,10 +31,10 @@ describe('Card component', () => { , ); - expect(component.toJSON()).toMatchSnapshot(); + expect(component.asFragment()).toMatchSnapshot(); }); it("Should have card-footer's classname", () => { - const component = renderer.create( + const component = render( Yes @@ -42,6 +42,6 @@ describe('Card component', () => { , ); - expect(component.toJSON()).toMatchSnapshot(); + expect(component.asFragment()).toMatchSnapshot(); }); }); diff --git a/src/components/card/card.js b/src/components/card/card.js index 8e0f25971..29c65000d 100644 --- a/src/components/card/card.js +++ b/src/components/card/card.js @@ -1,31 +1,27 @@ import React from 'react'; -import classnames from 'classnames'; +import clsx from 'clsx'; import CardImage from './components/image'; import CardContent from './components/content'; import CardHeader from './components/header'; import CardFooter from './components/footer'; -import Element from '../element'; +import { Element } from '../element'; -const Card = ({ className, children, ...props }) => { +/** + * @type {typeof import('.').Card} + */ +export const Card = ({ className, children, ...props }) => { return ( - + {children} ); }; -Card.Image = CardImage; +Element.setDisplayName(Card, 'Card'); +Card.Image = CardImage; Card.Content = CardContent; - Card.Header = CardHeader; - Card.Footer = CardFooter; - -Card.propTypes = {}; - -Card.defaultProps = {}; - -export default Card; diff --git a/src/components/card/card.stories.js b/src/components/card/card.stories.js new file mode 100644 index 000000000..d7fad4919 --- /dev/null +++ b/src/components/card/card.stories.js @@ -0,0 +1,92 @@ +import React from 'react'; +import { Card, Media, Image, Content, Heading } from '../..'; + +export default { + title: 'Elements/Card', +}; + +export const Default = { + render: () => { + return ( + + + + + + 64x64 + + + John Smith + + @johnsmith + + + + + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus + nec iaculis mauris. @bulmaio. + #css #responsive +
    + +
    +
    +
    + ); + }, +}; + +export const FooterActions = { + render: () => { + return ( + + + Title + + + + + 64x64 + + + John Smith + + @johnsmith + + + + + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus + nec iaculis mauris. @bulmaio. + #css #responsive +
    + +
    +
    + + + Yes + + + No + + + Maybe + + +
    + ); + }, +}; + +FooterActions.storyName = 'With footer action'; diff --git a/src/components/card/card.story.js b/src/components/card/card.story.js deleted file mode 100644 index 9c5954902..000000000 --- a/src/components/card/card.story.js +++ /dev/null @@ -1,84 +0,0 @@ -import React from 'react'; -import { Card, Media, Image, Content, Heading } from '../..'; - -export const Default = () => { - return ( - - - - - - 64x64 - - - John Smith - - @johnsmith - - - - - Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus nec - iaculis mauris. @bulmaio.#css{' '} - #responsive -
    - -
    -
    -
    - ); -}; - -export const FooterActions = () => { - return ( - - - Title - - - - - 64x64 - - - John Smith - - @johnsmith - - - - - Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus nec - iaculis mauris. @bulmaio.#css{' '} - #responsive -
    - -
    -
    - - - Yes - - - No - - - Maybe - - -
    - ); -}; - -FooterActions.storyName = 'With footer action'; diff --git a/src/components/card/card.story.mdx b/src/components/card/card.story.mdx deleted file mode 100644 index f70e0969d..000000000 --- a/src/components/card/card.story.mdx +++ /dev/null @@ -1,84 +0,0 @@ -import { ArgsTable, Canvas, Meta, Story } from '@storybook/addon-docs/blocks'; -import Card from '.'; -import { Image } from '../..'; -import * as stories from './card.story'; -import CommonProps from '../../../.storybook/common-props'; - - - -# Card - -A composable component for displaying rich content. - -## Components - -- ``: Displays a horizontal header bar at the top, with drop shadow. - - `` : Displays a left-aligned header text in the header. - - ``: Displays an icon at the end of header. -- `` : Displays an image in card. Since it uses the `` component under the hood, -- ``: Displays the main content of the card. Can contain other components. -they share the same props. -- ``: Displays a horizontal list of controls at the bottom. - - ``: An item in the footer. - -## Props - - - -## Components - -The following components are available to compose card content. - -### `` - -Displays an image in card. Since it uses the `` component under the hood, Share the same props as `Image` - - - -### `` - -Displays the main content of the card. Can contain other components. - - - -### `` - -Displays a horizontal header bar at the top, with drop shadow. - - - -#### `` - -Displays a left-aligned header text in the header. - - - -#### `` - -Displays an icon at the end of header. - - - -### `` - -Displays a horizontal list of controls at the bottom. - - - -#### `` - -An item in the footer. - - - - - -## Examples - - - - - -## Related - -- [Official documentation](https://bulma.io/documentation/components/card) \ No newline at end of file diff --git a/src/components/card/components/content.js b/src/components/card/components/content.js index 6fd84403e..616e15ae9 100644 --- a/src/components/card/components/content.js +++ b/src/components/card/components/content.js @@ -1,16 +1,12 @@ import React from 'react'; -import classnames from 'classnames'; +import clsx from 'clsx'; -import Element from '../../element'; +import { Element } from '../../element'; const CardContent = ({ className, ...props }) => { - return ( - - ); + return ; }; -CardContent.propTypes = {}; - -CardContent.defaultProps = {}; +Element.setDisplayName(CardContent, 'Card.Content'); export default CardContent; diff --git a/src/components/card/components/footer/components/footer-item.js b/src/components/card/components/footer/components/footer-item.js index 3ea115782..15fe24233 100644 --- a/src/components/card/components/footer/components/footer-item.js +++ b/src/components/card/components/footer/components/footer-item.js @@ -1,15 +1,11 @@ import React from 'react'; -import classnames from 'classnames'; -import Element from '../../../../element'; +import clsx from 'clsx'; +import { Element } from '../../../../element'; const CardFooterItem = ({ className, ...props }) => { - return ( - - ); + return ; }; -CardFooterItem.propTypes = {}; - -CardFooterItem.defaultProps = {}; +Element.setDisplayName(CardFooterItem, 'Card.Footer.Item'); export default CardFooterItem; diff --git a/src/components/card/components/footer/footer.js b/src/components/card/components/footer/footer.js index f7c85713b..8792d309f 100644 --- a/src/components/card/components/footer/footer.js +++ b/src/components/card/components/footer/footer.js @@ -1,19 +1,15 @@ import React from 'react'; -import classnames from 'classnames'; +import clsx from 'clsx'; import CardFooterItem from './components/footer-item'; -import Element from '../../../element'; +import { Element } from '../../../element'; const CardFooter = ({ className, ...props }) => { - return ( - - ); + return ; }; -CardFooter.Item = CardFooterItem; - -CardFooter.propTypes = {}; +Element.setDisplayName(CardFooter, 'Card.Footer'); -CardFooter.defaultProps = {}; +CardFooter.Item = CardFooterItem; export default CardFooter; diff --git a/src/components/card/components/footer/index.js b/src/components/card/components/footer/index.js index 15ebc72eb..aa4b37a54 100644 --- a/src/components/card/components/footer/index.js +++ b/src/components/card/components/footer/index.js @@ -1 +1,3 @@ -export { default } from './footer'; +import CardFooter from './footer'; + +export default CardFooter; diff --git a/src/components/card/components/header/components/header-icon.js b/src/components/card/components/header/components/header-icon.js index 4a110e7a2..04d3a28f7 100644 --- a/src/components/card/components/header/components/header-icon.js +++ b/src/components/card/components/header/components/header-icon.js @@ -1,16 +1,12 @@ import React from 'react'; -import classnames from 'classnames'; +import clsx from 'clsx'; -import Element from '../../../../element'; +import { Element } from '../../../../element'; const CardHeaderIcon = ({ className, ...props }) => { - return ( - - ); + return ; }; -CardHeaderIcon.propTypes = {}; - -CardHeaderIcon.defaultProps = {}; +Element.setDisplayName(CardHeaderIcon, 'Card.Header.Icon'); export default CardHeaderIcon; diff --git a/src/components/card/components/header/components/header-title.js b/src/components/card/components/header/components/header-title.js index 389f11d2e..27bda42f4 100644 --- a/src/components/card/components/header/components/header-title.js +++ b/src/components/card/components/header/components/header-title.js @@ -1,19 +1,14 @@ import React from 'react'; -import classnames from 'classnames'; +import clsx from 'clsx'; -import Element from '../../../../element'; +import { Element } from '../../../../element'; const CardHeaderTitle = ({ className, ...props }) => { return ( - + ); }; -CardHeaderTitle.propTypes = {}; - -CardHeaderTitle.defaultProps = {}; +Element.setDisplayName(CardHeaderTitle, 'Card.Header.Title'); export default CardHeaderTitle; diff --git a/src/components/card/components/header/header.js b/src/components/card/components/header/header.js index ac5271bac..c9a161cc2 100644 --- a/src/components/card/components/header/header.js +++ b/src/components/card/components/header/header.js @@ -1,22 +1,17 @@ import React from 'react'; -import classnames from 'classnames'; +import clsx from 'clsx'; import CardHeaderTitle from './components/header-title'; import CardHeaderIcon from './components/header-icon'; -import Element from '../../../element'; +import { Element } from '../../../element'; const CardHeader = ({ className, ...props }) => { - return ( - - ); + return ; }; -CardHeader.Title = CardHeaderTitle; +Element.setDisplayName(CardHeader, 'Card.Header'); +CardHeader.Title = CardHeaderTitle; CardHeader.Icon = CardHeaderIcon; -CardHeader.propTypes = {}; - -CardHeader.defaultProps = {}; - export default CardHeader; diff --git a/src/components/card/components/header/index.js b/src/components/card/components/header/index.js index 77992c5af..d629e680c 100644 --- a/src/components/card/components/header/index.js +++ b/src/components/card/components/header/index.js @@ -1 +1,3 @@ -export { default } from './header'; +import CardHeader from './header'; + +export default CardHeader; diff --git a/src/components/card/components/image.js b/src/components/card/components/image.js index 36977ca88..4b58f9663 100644 --- a/src/components/card/components/image.js +++ b/src/components/card/components/image.js @@ -1,19 +1,17 @@ import React from 'react'; -import classnames from 'classnames'; -import Image from '../../image'; +import clsx from 'clsx'; +import { Image } from '../../image'; -import Element from '../../element'; +import { Element } from '../../element'; const CardImage = ({ className, domRef, ...props }) => { return ( - + ); }; -CardImage.propTypes = {}; - -CardImage.defaultProps = {}; +Element.setDisplayName(CardImage, 'Card.Image'); export default CardImage; diff --git a/src/components/card/index.d.ts b/src/components/card/index.d.ts index 203f5b160..28a3dbeae 100644 --- a/src/components/card/index.d.ts +++ b/src/components/card/index.d.ts @@ -1,16 +1,56 @@ import { BulmaComponent } from '..'; -import ImageProps from '../image'; - -declare const Card: BulmaComponent<{}, 'div'> & { - Image: BulmaComponent; - Content: BulmaComponent<{}, 'div'>; - Header: BulmaComponent<{}, 'div'> & { - Title: BulmaComponent<{}, 'div'>; - Icon: BulmaComponent<{}, 'div'>; - }; - Footer: BulmaComponent<{}, 'div'> & { - Item: BulmaComponent<{}, 'div'>; - }; -}; - -export default Card +import { Image } from '../image'; + +/** + * @parent Card.Header + * @name Card.Header.Title + */ +export declare const CardHeaderTitle: BulmaComponent; + +/** + * @parent Card.Header + * @name Card.Header.Icon + */ +export declare const CardHeaderIcon: BulmaComponent; + +/** + * @parent Card.Footer + * @name Card.Footer.Item + */ +export declare const CardFooterItem: BulmaComponent; + +/** + * @parent Card + * @name Card.Image + */ +export declare const CardImage: typeof Image; + +/** + * @parent Card + * @name Card.Content + */ +export declare const CardContent: BulmaComponent; + +/** + * @parent Card + * @name Card.Header + */ +export declare const CardHeader: BulmaComponent<{}, 'div', { + Title: typeof CardHeaderTitle; + Icon: typeof CardHeaderIcon; +}>; + +/** + * @parent Card + * @name Card.Footer + */ +export declare const CardFooter: BulmaComponent<{}, 'div', { + Item: typeof CardFooterItem; +}>; + +export declare const Card: BulmaComponent<{}, 'div', { + Image: typeof CardImage; + Content: typeof CardContent; + Header: typeof CardHeader; + Footer: typeof CardFooter; +}>; diff --git a/src/components/card/index.js b/src/components/card/index.js index a08e1cb09..cb5809fed 100644 --- a/src/components/card/index.js +++ b/src/components/card/index.js @@ -1,3 +1 @@ -import Card from './card'; - -export default Card; +export * from './card'; diff --git a/src/components/columns/__test__/__snapshots__/columns.test.js.snap b/src/components/columns/__test__/__snapshots__/columns.test.js.snap index b98f9dbcc..47a9c4426 100644 --- a/src/components/columns/__test__/__snapshots__/columns.test.js.snap +++ b/src/components/columns/__test__/__snapshots__/columns.test.js.snap @@ -1,104 +1,83 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Columns component Should have columns classname 1`] = ` -
    +
    - 1 +
    + 1 +
    +
    + 2 +
    +
    + 3 +
    -
    - 2 -
    -
    - 3 -
    -
    + `; exports[`Columns component Should have columns one column half width and 3 other as default 1`] = ` -
    -
    - 1 -
    -
    - 2 -
    -
    - 3 -
    +
    - 4 +
    + 1 +
    +
    + 2 +
    +
    + 3 +
    +
    + 4 +
    -
    + `; exports[`Columns component Should have columns one column half width, other narrow and 2 other as default 1`] = ` -
    +
    - 1 +
    + 1 +
    +
    + 2 +
    +
    + 3 +
    +
    + 4 +
    -
    - 2 -
    -
    - 3 -
    -
    - 4 -
    -
    -`; - -exports[`Columns component Should render as paragraph 1`] = ` -

    -

    - 1 -

    -

    - 2 -

    -

    - 3 -

    -

    - 4 -

    -

    + `; diff --git a/src/components/columns/__test__/columns.test.js b/src/components/columns/__test__/columns.test.js index 0257fdab8..cc1a0ee98 100644 --- a/src/components/columns/__test__/columns.test.js +++ b/src/components/columns/__test__/columns.test.js @@ -1,20 +1,20 @@ import React from 'react'; -import renderer from 'react-test-renderer'; -import Columns from '..'; +import { render } from '@testing-library/react'; +import { Columns } from '..'; describe('Columns component', () => { it('Should have columns classname', () => { - const component = renderer.create( + const component = render( 1 2 3 , ); - expect(component.toJSON()).toMatchSnapshot(); + expect(component.asFragment()).toMatchSnapshot(); }); it('Should have columns one column half width and 3 other as default', () => { - const component = renderer.create( + const component = render( 1 2 @@ -22,23 +22,10 @@ describe('Columns component', () => { 4 , ); - expect(component.toJSON()).toMatchSnapshot(); - }); - it('Should render as paragraph', () => { - const component = renderer.create( - - - 1 - - 2 - 3 - 4 - , - ); - expect(component.toJSON()).toMatchSnapshot(); + expect(component.asFragment()).toMatchSnapshot(); }); it('Should have columns one column half width, other narrow and 2 other as default', () => { - const component = renderer.create( + const component = render( 1 2 @@ -46,6 +33,6 @@ describe('Columns component', () => { 4 , ); - expect(component.toJSON()).toMatchSnapshot(); + expect(component.asFragment()).toMatchSnapshot(); }); }); diff --git a/src/components/columns/columns.js b/src/components/columns/columns.js index 10c0dd586..06f55baf1 100644 --- a/src/components/columns/columns.js +++ b/src/components/columns/columns.js @@ -1,12 +1,13 @@ import React from 'react'; -import PropTypes from 'prop-types'; -import classNames from 'classnames'; +import clsx from 'clsx'; import Column from './components/column'; -import COLUMN_CONSTANTS from './constants'; -import Element from '../element'; +import { Element } from '../element'; -const Columns = ({ +/** + * @type {typeof import('.').Columns} + */ +export const Columns = ({ className, breakpoint, gap, @@ -26,7 +27,7 @@ const Columns = ({ ` to stack on top of each other. - */ - breakpoint: PropTypes.oneOf([ - 'touch', - 'mobile', - 'tablet', - 'desktop', - 'widescreen', - 'fullhd', - ]), - /** - * Whether you want to add more column elements than would fit in a single row. - * [Official documentation](https://bulma.io/documentation/columns/options/#multiline). - */ - multiline: PropTypes.bool, - /** - * Whether columns should be **horizontally centered** inside `` - */ - centered: PropTypes.bool, - /** - * Whether columns should be **vertically centered** inside `` - */ - vCentered: PropTypes.bool, -}; +Element.setDisplayName(Column, 'Column'); -Columns.defaultProps = { - multiline: true, -}; - -export default Columns; +Columns.Column = Column; diff --git a/src/components/columns/columns.stories.js b/src/components/columns/columns.stories.js new file mode 100644 index 000000000..bfcee42e0 --- /dev/null +++ b/src/components/columns/columns.stories.js @@ -0,0 +1,338 @@ +/* eslint-disable react/prop-types */ +import React from 'react'; +import { Columns, Notification, Box, Message } from '../..'; +import GLOBAL_CONSTANTS from '../../constants'; + +export default { + title: 'Elements/Columns', +}; + +const message = ( + + + Try playing with the viewport option on the top and the breakpoint control + on the bottom in the Canvas Tab + + +); + +const options = { + sizes: ['default', 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], + breakpoints: ['default'].concat(Object.values(GLOBAL_CONSTANTS.BREAKPOINTS)), +}; + +export const Basic = { + render: () => { + return ( + + + First Column + + + Second Column + + + Third Column + + + Fourth Column + + + ); + }, +}; + +export const Sizes = { + render: ({ size, narrow, offset }) => { + return ( + <> + {message} + + + Size: {size} + + + Auto + + + + + 2 + + + {narrow ? 'Narrow' : 'Flexible'} + + + + + + size: 4 and offset {offset} + + + + + ); + }, +}; + +Sizes.args = { + narrow: false, +}; + +Sizes.argTypes = { + size: { + control: { + type: 'select', + }, + options: options.sizes, + defaultValue: 4, + }, + offset: { + control: { + type: 'select', + }, + options: options.sizes, + defaultValue: 4, + }, +}; + +export const Responsiveness = { + render: ({ mobile, tablet, desktop, widescreen, fullhd, breakpoint }) => { + return ( + <> + {message} + + with breakpoint="{breakpoint}" the columns will be + active on all sizes equal or greater than the breakpoint + + + + + +

    I'm responsive

    +
    +
    + + Auto + +
    +
    + + ); + }, +}; + +Responsiveness.args = { + breakpoint: 'tablet', + mobile: { + size: 8, + offset: 2, + narrow: false, + textAlign: 'center', + textSize: 3, + }, + tablet: { + size: 6, + offset: 3, + narrow: false, + }, + desktop: { + size: 4, + offset: 4, + narrow: false, + }, + widescreen: { + size: 2, + offset: 5, + narrow: false, + }, + fullhd: { + size: 3, + offset: 0, + narrow: false, + }, +}; + +Responsiveness.argTypes = { + breakpoint: { + control: { + type: 'select', + options: options.breakpoints, + }, + }, +}; + +export const Nesting = { + render: () => { + return ( + + + 0 + + + 1 + + + 2 + + + 2 + + + + + 1 + + + + + 0 + + + 1 + + + 1 + + + 1 + + + + + ); + }, +}; + +export const Gaps = { + render: ({ mobile, tablet, touch, desktop, widescreen, fullhd, ...args }) => { + return ( + <> + {message} + + + Size 3 + + + Size 3 + + + Size 3 + + + Size 3 + + + + ); + }, +}; + +Gaps.argTypes = { + gap: { + control: { + type: 'select', + options: [0, 1, 2, 3, 4, 5, 6, 7, 8], + }, + }, + mobile: { + control: { + type: 'select', + options: [0, 1, 2, 3, 4, 5, 6, 7, 8], + }, + }, + tablet: { + control: { + type: 'select', + options: [0, 1, 2, 3, 4, 5, 6, 7, 8], + }, + }, + desktop: { + control: { + type: 'select', + options: [0, 1, 2, 3, 4, 5, 6, 7, 8], + }, + }, + widescreen: { + control: { + type: 'select', + options: [0, 1, 2, 3, 4, 5, 6, 7, 8], + }, + }, + fullhd: { + control: { + type: 'select', + options: [0, 1, 2, 3, 4, 5, 6, 7, 8], + }, + }, +}; + +export const Options = { + render: ({ vCentered, centered, multiline }) => { + return ( + <> + {message} + + + +

    7

    +
    +
    + + +

    5

    +
    +
    + + 3 + + + 4 + + + 3 + + + Narrow Column + + + Narrow Column + + + Narrow Column + + + Narrow Column + + + 4 + +
    + + ); + }, +}; + +Options.args = { + vCentered: false, + centered: false, + multiline: true, +}; diff --git a/src/components/columns/components/column.js b/src/components/columns/components/column.js index 6c241508d..ad4aa2a41 100644 --- a/src/components/columns/components/column.js +++ b/src/components/columns/components/column.js @@ -1,10 +1,9 @@ import React from 'react'; -import PropTypes from 'prop-types'; -import classNames from 'classnames'; +import clsx from 'clsx'; -import Element from '../../element'; +import { Element } from '../../element'; -const Column = ({ +const ColumnsColumn = ({ children, className, size, @@ -22,7 +21,7 @@ const Column = ({ `. - * Possible values depends on the sizing method used. - * See [below](#offset) for more details. - */ - offset: PropTypes.oneOf([ - 'three-quarters', - 'two-thirds', - 'half', - 'one-third', - 'one-quarter', - 'one-fifth', - 'two-fifths', - 'three-fifths', - 'four-fifths', - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - ]), - /** - * If you want a column to only take the space it needs, use the narrow modifier. The other column(s) will fill up the remaining space. - */ - narrow: PropTypes.bool, - /** - * Size, Offset and Narrow props for touch devices (This props are merge with the default responsive props) - */ - touch: PropTypes.shape({ - size: PropTypes.oneOf([ - 'three-quarters', - 'two-thirds', - 'half', - 'one-third', - 'one-quarter', - 'one-fifth', - 'two-fifths', - 'three-fifths', - 'four-fifths', - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - ]), - offset: PropTypes.oneOf([ - 'three-quarters', - 'two-thirds', - 'half', - 'one-third', - 'one-quarter', - 'one-fifth', - 'two-fifths', - 'three-fifths', - 'four-fifths', - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - ]), - narrow: PropTypes.bool, - }), - /** - * Size, Offset and Narrow props for Mobile devices (This props are merge with the default responsive props) - */ - mobile: PropTypes.shape({ - size: PropTypes.oneOf([ - 'three-quarters', - 'two-thirds', - 'half', - 'one-third', - 'one-quarter', - 'one-fifth', - 'two-fifths', - 'three-fifths', - 'four-fifths', - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - ]), - offset: PropTypes.oneOf([ - 'three-quarters', - 'two-thirds', - 'half', - 'one-third', - 'one-quarter', - 'one-fifth', - 'two-fifths', - 'three-fifths', - 'four-fifths', - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - ]), - narrow: PropTypes.bool, - }), - /** - * Size, Offset and Narrow props for Tablet devices (This props are merge with the default responsive props) - */ - tablet: PropTypes.shape({ - size: PropTypes.oneOf([ - 'three-quarters', - 'two-thirds', - 'half', - 'one-third', - 'one-quarter', - 'one-fifth', - 'two-fifths', - 'three-fifths', - 'four-fifths', - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - ]), - offset: PropTypes.oneOf([ - 'three-quarters', - 'two-thirds', - 'half', - 'one-third', - 'one-quarter', - 'one-fifth', - 'two-fifths', - 'three-fifths', - 'four-fifths', - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - ]), - narrow: PropTypes.bool, - }), - /** - * Size, Offset and Narrow props for Desktop devices (This props are merge with the default responsive props) - */ - desktop: PropTypes.shape({ - size: PropTypes.oneOf([ - 'three-quarters', - 'two-thirds', - 'half', - 'one-third', - 'one-quarter', - 'one-fifth', - 'two-fifths', - 'three-fifths', - 'four-fifths', - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - ]), - offset: PropTypes.oneOf([ - 'three-quarters', - 'two-thirds', - 'half', - 'one-third', - 'one-quarter', - 'one-fifth', - 'two-fifths', - 'three-fifths', - 'four-fifths', - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - ]), - narrow: PropTypes.bool, - }), - /** - * Size, Offset and Narrow props for WideScreen devices (This props are merge with the default responsive props) - */ - widescreen: PropTypes.shape({ - size: PropTypes.oneOf([ - 'three-quarters', - 'two-thirds', - 'half', - 'one-third', - 'one-quarter', - 'one-fifth', - 'two-fifths', - 'three-fifths', - 'four-fifths', - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - ]), - offset: PropTypes.oneOf([ - 'three-quarters', - 'two-thirds', - 'half', - 'one-third', - 'one-quarter', - 'one-fifth', - 'two-fifths', - 'three-fifths', - 'four-fifths', - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - ]), - narrow: PropTypes.bool, - }), - /** - * Size, Offset and Narrow props for FullHD devices (This props are merge with the default responsive props) - */ - fullhd: PropTypes.shape({ - size: PropTypes.oneOf([ - 'three-quarters', - 'two-thirds', - 'half', - 'one-third', - 'one-quarter', - 'one-fifth', - 'two-fifths', - 'three-fifths', - 'four-fifths', - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - ]), - offset: PropTypes.oneOf([ - 'three-quarters', - 'two-thirds', - 'half', - 'one-third', - 'one-quarter', - 'one-fifth', - 'two-fifths', - 'three-fifths', - 'four-fifths', - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - ]), - narrow: PropTypes.bool, - }), -}; - -Column.defaultProps = {}; +Element.setDisplayName(ColumnsColumn, 'Columns.Column'); -export default Column; +export default ColumnsColumn; diff --git a/src/components/columns/constants.js b/src/components/columns/constants.js deleted file mode 100644 index 415c13151..000000000 --- a/src/components/columns/constants.js +++ /dev/null @@ -1,13 +0,0 @@ -export default { - SIZES: { - THREEQUARTERS: 'three-quarters', - TWOTHIRDS: 'two-thirds', - HALF: 'half', - ONETHIRD: 'one-third', - ONEQUARTER: 'one-quarter', - ONEFIFTH: 'one-fifth', - TWOFIFTHS: 'two-fifths', - THREEFIFTHS: 'three-fifths', - FOURFIFTHS: 'four-fifths', - }, -}; diff --git a/src/components/columns/index.d.ts b/src/components/columns/index.d.ts index 9361144b7..8b3eec5c4 100644 --- a/src/components/columns/index.d.ts +++ b/src/components/columns/index.d.ts @@ -1,11 +1,12 @@ import { BulmaComponent, Breakpoint, ResponsiveModifiers } from '..'; -type GapSize = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | String | Number; -interface GapProps { +export type GapSize = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | String | Number; + +type GapProps = { gap?: GapSize; } -interface ColumnGroupProps { +type ColumnGroupProps = { touch?: GapProps & ResponsiveModifiers; mobile?: GapProps & ResponsiveModifiers; tablet?: GapProps & ResponsiveModifiers; @@ -18,7 +19,7 @@ interface ColumnGroupProps { vCentered?: boolean; } -type ColumnSize = +export type ColumnSize = | 0 | 1 | 2 @@ -42,13 +43,13 @@ type ColumnSize = | 'three-fifths' | 'four-fifths'; -interface ColumnBreakpointConfiguration { + export type ColumnBreakpointConfiguration = { size?: ColumnSize; offset?: ColumnSize; narrow?: boolean; } -interface ColumnProps { +export type ColumnProps = { size?: ColumnSize; offset?: ColumnSize; narrow?: boolean; @@ -60,8 +61,13 @@ interface ColumnProps { fullhd?: ColumnBreakpointConfiguration & ResponsiveModifiers; } -declare const Columns: BulmaComponent & { - Column: BulmaComponent; -}; +/** + * @parent Columns + * @name Columns.Column + */ +export declare const ColumnsColumn: BulmaComponent; + +export declare const Columns: BulmaComponent; -export default Columns; diff --git a/src/components/columns/index.js b/src/components/columns/index.js index c7a08b027..a7f066b20 100644 --- a/src/components/columns/index.js +++ b/src/components/columns/index.js @@ -1,3 +1 @@ -import Columns from './columns'; - -export default Columns; +export * from './columns'; diff --git a/src/components/columns/stories/columns-1-basics.story.mdx b/src/components/columns/stories/columns-1-basics.story.mdx deleted file mode 100644 index d02c7b66a..000000000 --- a/src/components/columns/stories/columns-1-basics.story.mdx +++ /dev/null @@ -1,39 +0,0 @@ -import { ArgsTable, Canvas, Meta, Story } from '@storybook/addon-docs/blocks'; -import { Columns, Message, Notification } from '../../..'; -import CommonProps from '../../../../.storybook/common-props'; -import * as stories from './columns.story'; - - - -# Columns using Flexbox - -You can build columns very easily: - -1. Add a `` component -2. Put as many `` as you want inside it. - -Each column will have an equal width, no matter the number of columns. - -## Basic - - - - - -## Props - -
    - -### `Columns` - - - -### `Columns.Column` - - - - - -## Related - -- [Official documentation](https://bulma.io/documentation/columns/basics/) \ No newline at end of file diff --git a/src/components/columns/stories/columns-2-sizes.story.mdx b/src/components/columns/stories/columns-2-sizes.story.mdx deleted file mode 100644 index 5b06afcfc..000000000 --- a/src/components/columns/stories/columns-2-sizes.story.mdx +++ /dev/null @@ -1,45 +0,0 @@ -import { ArgsTable, Canvas, Meta, Story } from '@storybook/addon-docs/blocks'; -import { Columns, Message, Notification } from '../../..'; -import * as stories from './columns.story'; - - - -# Column sizes - -The grid is divided into 12 columns, and you can specify how many columns each column occupies with the `size` prop. - -For example, a column with `size={7}` will occupy 7 of the 12 columns. you can define the size of each column individually, you also define it using proportions - -If a column does not fix on the remaning space (for example 7 + 6) the second one will wrap to the next "row" - -If no size is specified the column will take the available space, if you want to change this you can pass the -`narrow` prop, Please take into account that if both size and narrow are passed the size take precedence - -### Proportions - -You can adjust the size of each column using proportions: - -- `"three-quarters"` -- `"two-thirds"` -- `"half"` -- `"one-third"` -- `"one-quarter"` -- `"full"` -- `"four-fifths"` -- `"three-fifths"` -- `"two-fifths"` -- `"one-fifth"` - -Just pass them to the `size` prop, and they will size themselves according to the given proportions. -For example, a column with `size` `"two-thirds"` will occupy two third of the available space. - -### Offset - -While you can use empty columns `` to create horizontal space between columns, you can also pass a size value to the prop `offset` - - - - -## Related - -- [Official documentation](https://bulma.io/documentation/columns/sizes/) \ No newline at end of file diff --git a/src/components/columns/stories/columns-3-responsiveness.story.mdx b/src/components/columns/stories/columns-3-responsiveness.story.mdx deleted file mode 100644 index ae12c9eb6..000000000 --- a/src/components/columns/stories/columns-3-responsiveness.story.mdx +++ /dev/null @@ -1,41 +0,0 @@ -import { ArgsTable, Canvas, Meta, Story } from '@storybook/addon-docs/blocks'; -import { Columns, Message, Notification } from '../../..'; -import * as stories from './columns.story'; - - - -# Responsiveness - -You can handle different column size/offseet for each breakpoint independently. - -## Mobile Columns - -You can use the `breakpoint` prop on the `Column` component to specify at what viewport size `Columns` -should be "activated", meaning it will display `Columns.Column` in a row. Any viewport smaller -than the specified viewport size will cause `Columns` to display `Columns.Column` -in a row. - -By default, the value is `'tablet'`. Any viewport smaller than `'tablet'` will cause `Columns` to stack -`Columns.Column` on top of each other. - -## Different column sizes/offsets/narrowness per breakpoint - -You can define this values for each viewport size passing a configuration object on a prop named as the -viewport you are targeting mobile, tablet, desktop, widescreen and fullhd). The configuration object looks like this - -Note that you can also use the common responsive props here (like `textAlign`, `textSize`) - -```javascript -{ - size: "ANY VALID SIZE", - offset: "ANY VALID SIZE", - narrow: Boolean -} -``` - - - - -## Related - -- [Official documentation](https://bulma.io/documentation/columns/responsiveness/) \ No newline at end of file diff --git a/src/components/columns/stories/columns-4-nesting.story.mdx b/src/components/columns/stories/columns-4-nesting.story.mdx deleted file mode 100644 index 09b8022a8..000000000 --- a/src/components/columns/stories/columns-4-nesting.story.mdx +++ /dev/null @@ -1,19 +0,0 @@ -import { ArgsTable, Canvas, Meta, Story } from '@storybook/addon-docs/blocks'; -import { Columns, Message, Notification } from '../../..'; -import * as stories from './columns.story'; - - - -# Nesting - -You can nest `Columns` inside any `Columns.Column` indefinitely to create more complex layout - -The difference with multiline columns is the order in the HTML code: all the blue columns appear before the red ones. Resize to a narrower viewport to see the result. - -In this example, the numbers represent the nesting level the `Columns.Column` is in. - - - -## Related - -- [Official documentation](https://bulma.io/documentation/columns/nesting/) \ No newline at end of file diff --git a/src/components/columns/stories/columns-5-gap.story.mdx b/src/components/columns/stories/columns-5-gap.story.mdx deleted file mode 100644 index 79e39ce86..000000000 --- a/src/components/columns/stories/columns-5-gap.story.mdx +++ /dev/null @@ -1,21 +0,0 @@ -import { ArgsTable, Canvas, Meta, Story } from '@storybook/addon-docs/blocks'; -import { Columns, Message, Notification } from '../../..'; -import * as stories from './columns.story'; - - - -# Colums gap - -You can customize the gaps between columns - -You can configure the gap between columns for all breakpoints with the `gap` prop, or specify per breakpoint using the responsive gap for each breakpoint (`mobile.gap`, `desktop.gap`, ...) - -## Example - - - - - -## Related - -- [Official documentation](https://bulma.io/documentation/columns/gap/) \ No newline at end of file diff --git a/src/components/columns/stories/columns-6-Options.story.mdx b/src/components/columns/stories/columns-6-Options.story.mdx deleted file mode 100644 index ead856d86..000000000 --- a/src/components/columns/stories/columns-6-Options.story.mdx +++ /dev/null @@ -1,26 +0,0 @@ -import { ArgsTable, Canvas, Meta, Story } from '@storybook/addon-docs/blocks'; -import { Columns, Message, Notification } from '../../..'; -import * as stories from './columns.story'; - - - -#Options - -Here you will find some other options that will help you to customize the behaviour of the columns - -## Columns Alignment - -You can center columns vertically, to do it add the vCentered prop to the `Column` component. Also you can center horizontaly adding the centered prop - -## Multiline - -By default, the columns will break into a new line when do not have enough space, you can disable this with `multiline={false}` - - - - - - -## Related - -- [Official documentation](https://bulma.io/documentation/columns/options/) \ No newline at end of file diff --git a/src/components/columns/stories/columns.story.js b/src/components/columns/stories/columns.story.js deleted file mode 100644 index 122e2abe2..000000000 --- a/src/components/columns/stories/columns.story.js +++ /dev/null @@ -1,338 +0,0 @@ -/* eslint-disable react/prop-types */ -import React from 'react'; -import { Columns, Notification } from '../../..'; -import Box from '../../box'; -import CONSTANTS from '../constants'; -import GLOBAL_CONSTANTS from '../../../constants'; -import Message from '../../message'; - -const message = ( - - - Try playing with the viewport option on the top and the breakpoint control - on the bottom in the Canvas Tab - - -); - -const options = { - sizes: ['default', 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12].concat( - Object.values(CONSTANTS.SIZES), - ), - breakpoints: ['default'].concat(Object.values(GLOBAL_CONSTANTS.BREAKPOINTS)), -}; - -export const Basic = () => { - return ( - - - First Column - - - Second Column - - - Third Column - - - Fourth Column - - - ); -}; - -export const Sizes = ({ size, narrow, offset }) => { - return ( - <> - {message} - - - Size: {size} - - - Auto - - - - - 2 - - - {narrow ? 'Narrow' : 'Flexible'} - - - - - - size: 4 and offset {offset} - - - - - ); -}; - -Sizes.args = { - narrow: false, -}; - -Sizes.argTypes = { - size: { - control: { - type: 'select', - options: options.sizes, - }, - defaultValue: 4, - }, - offset: { - control: { - type: 'select', - options: options.sizes, - }, - defaultValue: 4, - }, -}; - -export const Responsiveness = ({ - mobile, - tablet, - desktop, - widescreen, - fullhd, - breakpoint, -}) => { - return ( - <> - {message} - - with breakpoint="{breakpoint}" the columns will be - active on all sizes equal or greater than the breakpoint - - - - - -

    I'm responsive

    -
    -
    - - Auto - -
    -
    - - ); -}; - -Responsiveness.args = { - breakpoint: 'tablet', - mobile: { - size: 8, - offset: 2, - narrow: false, - textAlign: 'center', - textSize: 3, - }, - tablet: { - size: 6, - offset: 3, - narrow: false, - }, - desktop: { - size: 4, - offset: 4, - narrow: false, - }, - widescreen: { - size: 2, - offset: 5, - narrow: false, - }, - fullhd: { - size: 3, - offset: 0, - narrow: false, - }, -}; - -Responsiveness.argTypes = { - breakpoint: { - control: { - type: 'select', - options: options.breakpoints, - }, - }, -}; - -export const Nesting = () => { - return ( - - - 0 - - - 1 - - - 2 - - - 2 - - - - - 1 - - - - - 0 - - - 1 - - - 1 - - - 1 - - - - - ); -}; - -export const Gaps = ({ - mobile, - tablet, - touch, - desktop, - widescreen, - fullhd, - ...args -}) => { - return ( - <> - {message} - - - Size 3 - - - Size 3 - - - Size 3 - - - Size 3 - - - - ); -}; - -Gaps.argTypes = { - gap: { - control: { - type: 'select', - options: [0, 1, 2, 3, 4, 5, 6, 7, 8], - }, - }, - mobile: { - control: { - type: 'select', - options: [0, 1, 2, 3, 4, 5, 6, 7, 8], - }, - }, - tablet: { - control: { - type: 'select', - options: [0, 1, 2, 3, 4, 5, 6, 7, 8], - }, - }, - desktop: { - control: { - type: 'select', - options: [0, 1, 2, 3, 4, 5, 6, 7, 8], - }, - }, - widescreen: { - control: { - type: 'select', - options: [0, 1, 2, 3, 4, 5, 6, 7, 8], - }, - }, - fullhd: { - control: { - type: 'select', - options: [0, 1, 2, 3, 4, 5, 6, 7, 8], - }, - }, -}; - -export const Options = ({ vCentered, centered, multiline }) => { - return ( - <> - {message} - - - -

    7

    -
    -
    - - -

    5

    -
    -
    - - 3 - - - 4 - - - 3 - - - Narrow Column - - - Narrow Column - - - Narrow Column - - - Narrow Column - - - 4 - -
    - - ); -}; - -Options.args = { - vCentered: false, - centered: false, - multiline: true, -}; diff --git a/src/components/container/__test__/__snapshots__/container.test.js.snap b/src/components/container/__test__/__snapshots__/container.test.js.snap index 1282569eb..7582b5b31 100644 --- a/src/components/container/__test__/__snapshots__/container.test.js.snap +++ b/src/components/container/__test__/__snapshots__/container.test.js.snap @@ -1,52 +1,58 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Container component Should have container classname 1`] = ` -
    -

    +

    -

    - Default -

    -

    - Container -

    -

    -
    +
    +

    + Default +

    +

    + Container +

    +
    +
    + `; exports[`Container component Should ignore max prop on non desktop and non widescreen breakpoint 1`] = ` -
    -

    +

    -

    - Default -

    -

    - Container -

    -

    -
    +
    +

    + Default +

    +

    + Container +

    +
    +
    + `; exports[`Container component Should use max prop on desktop breakpoint 1`] = ` -
    -

    +

    -

    - Default -

    -

    - Container -

    -

    -
    +
    +

    + Default +

    +

    + Container +

    +
    +
    + `; diff --git a/src/components/container/__test__/container.test.js b/src/components/container/__test__/container.test.js index e0f7301a3..3c49385ab 100644 --- a/src/components/container/__test__/container.test.js +++ b/src/components/container/__test__/container.test.js @@ -1,39 +1,39 @@ import React from 'react'; -import renderer from 'react-test-renderer'; -import Container from '..'; +import { render } from '@testing-library/react'; +import { Container } from '..'; describe('Container component', () => { it('Should have container classname', () => { - const component = renderer.create( + const component = render( -

    +

    Default

    Container

    -

    +
    , ); - expect(component.toJSON()).toMatchSnapshot(); + expect(component.asFragment()).toMatchSnapshot(); }); it('Should use max prop on desktop breakpoint', () => { - const component = renderer.create( + const component = render( -

    +

    Default

    Container

    -

    +
    , ); - expect(component.toJSON()).toMatchSnapshot(); + expect(component.asFragment()).toMatchSnapshot(); }); it('Should ignore max prop on non desktop and non widescreen breakpoint', () => { - const component = renderer.create( + const component = render( -

    +

    Default

    Container

    -

    +
    , ); - expect(component.toJSON()).toMatchSnapshot(); + expect(component.asFragment()).toMatchSnapshot(); }); }); diff --git a/src/components/container/container.js b/src/components/container/container.js index 630a18a90..ec5d4c4d8 100644 --- a/src/components/container/container.js +++ b/src/components/container/container.js @@ -1,15 +1,23 @@ import React from 'react'; -import PropTypes from 'prop-types'; -import classnames from 'classnames'; +import clsx from 'clsx'; -import Element from '../element'; +import { Element } from '../element'; -const Container = ({ children, max, breakpoint, className, ...props }) => { +/** + * @type {typeof import('.').Container} + */ +export const Container = ({ + children, + max, + breakpoint, + className, + ...props +}) => { const canSetMax = ['desktop', 'widescreen'].includes(breakpoint); return ( @@ -18,24 +26,4 @@ const Container = ({ children, max, breakpoint, className, ...props }) => { ); }; -Container.propTypes = { - /** - * Specifies the breakpoint at which the container will stop being fullwidth. - */ - breakpoint: PropTypes.oneOf([ - 'mobile', - 'tablet', - 'desktop', - 'widescreen', - 'fullhd', - 'fluid', - ]), - /** - * Only work for `desktop` and `widescreen` breakpoints, Check the [bulma documentation](https://bulma.io/documentation/layout/container/#overview) - */ - max: PropTypes.bool, -}; - -Container.defaultProps = {}; - -export default Container; +Element.setDisplayName(Container, 'Container'); diff --git a/src/components/container/container.stories.js b/src/components/container/container.stories.js new file mode 100644 index 000000000..af656150e --- /dev/null +++ b/src/components/container/container.stories.js @@ -0,0 +1,34 @@ +import React from 'react'; + +import { Container, Notification } from '../..'; + +export default { + title: 'Elements/Container', +}; +export const Default = { + render: (args) => { + return ( +
    + + + This container will strech depending of the breakpoint you choose + + +
    + ); + }, +}; + +Default.argTypes = { + breakpoint: { + control: { + type: 'select', + }, + options: ['mobile', 'tablet', 'desktop', 'widescreen', 'fullhd', 'fluid'], + }, + max: { + control: { + type: 'boolean', + }, + }, +}; diff --git a/src/components/container/container.story.js b/src/components/container/container.story.js deleted file mode 100644 index d8db1f013..000000000 --- a/src/components/container/container.story.js +++ /dev/null @@ -1,29 +0,0 @@ -import React from 'react'; - -import { Container, Notification } from '../..'; - -export const ContainerExample = (args) => { - return ( -
    - - - This container will strech depending of the breakpoint you choose - - -
    - ); -}; - -ContainerExample.argTypes = { - breakpoint: { - control: { - type: 'select', - options: ['mobile', 'tablet', 'desktop', 'widescreen', 'fullhd', 'fluid'], - }, - }, - max: { - control: { - type: 'boolean', - }, - }, -}; diff --git a/src/components/container/container.story.mdx b/src/components/container/container.story.mdx deleted file mode 100644 index e80f60fb8..000000000 --- a/src/components/container/container.story.mdx +++ /dev/null @@ -1,110 +0,0 @@ -import { ArgsTable, Canvas, Meta, Story } from '@storybook/addon-docs/blocks'; -import { Message, Table, Element } from '../..'; -import Container from '.'; -import CommonProps from '../../../.storybook/common-props'; - -import * as stories from './container.story'; - - - -# Container - -The container component is a basic layout element that centers your contents horizontally. - - - - - - - - - - - - - - - max-width - - - - - - Full width - 960px - 1152px - 1344px - - - - - Full width - - 1152px - 1344px - - - - - Full width - - 1344px - - - - - Full width - 960px - - - - Full width - 960px - 1152px - - -
    - Below -
    - 1023px -
    - Desktop -
    - Between 1024px and 1215px -
    - Widescreen -
    - Between 1216px and 1407px -
    - FullHD -
    - 1408px and above -
    Breakpoint / Max
    default
    widescreen
    fullhd
    desktop / max
    widescreen / max
    - -By default, the container will only be activated from the desktop breakpoint. It will increase its max-width after reaching the widescreen and fullhd breakpoints. - -This is how the container will behave: - -- On desktop it will have a maximum width of `960px`. -- On widescreen it will have a maximum width of `1152px`. -- On fullhd it will have a maximum width of `1344px`. - -The values 960, 1152 and 1344 have been chosen because they are divisible by both 12 and 16. - -## Props - - - - - - - Resize the window to see what happens! - - - - - - -## Related - -- [Official documentation](https://bulma.io/documentation/layout/container) diff --git a/src/components/container/index.d.ts b/src/components/container/index.d.ts index 78677b159..bd469fa3c 100644 --- a/src/components/container/index.d.ts +++ b/src/components/container/index.d.ts @@ -1,11 +1,9 @@ import { BulmaComponent } from '..'; import { Breakpoint } from '..'; -interface ContainerProps { +type ContainerProps = { max?: boolean; breakpoint?: Breakpoint | 'fluid'; -} +}; -declare const Container: BulmaComponent; - -export default Container; \ No newline at end of file +export declare const Container: BulmaComponent; diff --git a/src/components/container/index.js b/src/components/container/index.js index 1c2fccb4b..85ee15b65 100644 --- a/src/components/container/index.js +++ b/src/components/container/index.js @@ -1,3 +1 @@ -import Container from './container'; - -export default Container; +export * from './container'; diff --git a/src/components/content/__test__/__snapshots__/content.test.js.snap b/src/components/content/__test__/__snapshots__/content.test.js.snap index cd6e3bf7a..94fa73108 100644 --- a/src/components/content/__test__/__snapshots__/content.test.js.snap +++ b/src/components/content/__test__/__snapshots__/content.test.js.snap @@ -1,18 +1,20 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Content component Should have content classname 1`] = ` -
    -

    +

    -

    - Default -

    -

    - Container -

    -

    -
    +
    +

    + Default +

    +

    + Container +

    +
    +
    + `; diff --git a/src/components/content/__test__/content.test.js b/src/components/content/__test__/content.test.js index f4514ace5..fce3eb8cb 100644 --- a/src/components/content/__test__/content.test.js +++ b/src/components/content/__test__/content.test.js @@ -1,17 +1,17 @@ import React from 'react'; -import renderer from 'react-test-renderer'; -import Content from '..'; +import { render } from '@testing-library/react'; +import { Content } from '..'; describe('Content component', () => { it('Should have content classname', () => { - const component = renderer.create( + const component = render( -

    +

    Default

    Container

    -

    +
    , ); - expect(component.toJSON()).toMatchSnapshot(); + expect(component.asFragment()).toMatchSnapshot(); }); }); diff --git a/src/components/content/content.js b/src/components/content/content.js index 16f43ca6c..e3f27dbfa 100644 --- a/src/components/content/content.js +++ b/src/components/content/content.js @@ -1,14 +1,16 @@ import React from 'react'; -import PropTypes from 'prop-types'; -import classnames from 'classnames'; +import clsx from 'clsx'; -import Element from '../element'; +import { Element } from '../element'; -const Content = ({ children, className, size, ...props }) => { +/** + * @type {typeof import('.').Content} + */ +export const Content = ({ children, className, size, ...props }) => { return ( @@ -17,13 +19,4 @@ const Content = ({ children, className, size, ...props }) => { ); }; -Content.propTypes = { - size: PropTypes.oneOfType([ - PropTypes.oneOf(['small', 'medium', 'large']), - PropTypes.string, - ]), -}; - -Content.defaultProps = {}; - -export default Content; +Element.setDisplayName(Content, 'Content'); diff --git a/src/components/content/content.stories.js b/src/components/content/content.stories.js new file mode 100644 index 000000000..3b797c15e --- /dev/null +++ b/src/components/content/content.stories.js @@ -0,0 +1,179 @@ +import React from 'react'; + +import { Content } from '.'; + +export default { title: 'Elements/Content' }; + +export const Default = { + render: (args) => { + return ( + +

    Hello World

    +

    + Lorem ipsum + + [1] + {' '} + dolor sit amet, consectetur adipiscing elit. Nulla accumsan, metus + ultrices eleifend gravida, nulla nunc varius lectus, nec rutrum justo + nibh eu lectus. Ut vulputate semper dui. Fusce erat odio, sollicitudin + vel erat vel, interdum mattis neque. Subscript works as + well! +

    +

    Second level

    +

    + Curabitur accumsan turpis pharetra augue tincidunt{' '} + blandit. Quisque condimentum maximus mi, sit amet commodo arcu rutrum + id. Proin pretium urna vel cursus venenatis. Suspendisse potenti. + Etiam mattis sem rhoncus lacus dapibus facilisis. Donec at dignissim + dui. Ut et neque nisl. +

    +
      +
    • In fermentum leo eu lectus mollis, quis dictum mi aliquet.
    • +
    • Morbi eu nulla lobortis, lobortis est in, fringilla felis.
    • +
    • + Aliquam nec felis in sapien venenatis viverra fermentum nec lectus. +
    • +
    • Ut non enim metus.
    • +
    +

    Third level

    +

    + Quisque ante lacus, malesuada ac auctor vitae, congue{' '} + non ante. Phasellus lacus ex, semper ac tortor + nec, fringilla condimentum orci. Fusce eu rutrum tellus. +

    +
      +
    1. Donec blandit a lorem id convallis.
    2. +
    3. Cras gravida arcu at diam gravida gravida.
    4. +
    5. Integer in volutpat libero.
    6. +
    7. Donec a diam tellus.
    8. +
    9. Aenean nec tortor orci.
    10. +
    11. Quisque aliquam cursus urna, non bibendum massa viverra eget.
    12. +
    13. Vivamus maximus ultricies pulvinar.
    14. +
    +
    + Ut venenatis, nisl scelerisque sollicitudin fermentum, quam libero + hendrerit ipsum, ut blandit est tellus sit amet turpis. +
    +

    + Quisque at semper enim, eu hendrerit odio. Etiam auctor nisl et{' '} + justo sodales elementum. Maecenas ultrices lacus quis neque + consectetur, et lobortis nisi molestie. +

    +

    + Sed sagittis enim ac tortor maximus rutrum. Nulla facilisi. Donec + mattis vulputate risus in luctus. Maecenas vestibulum interdum + commodo. +

    +
    +
    Web
    +
    The part of the Internet that contains websites and web pages
    +
    HTML
    +
    A markup language for creating web pages
    +
    CSS
    +
    A technology to make HTML look better
    +
    +

    + Suspendisse egestas sapien non felis placerat elementum. Morbi tortor + nisl, suscipit sed mi sit amet, mollis malesuada nulla. Nulla + facilisi. Nullam ac erat ante. +

    +

    Fourth level

    +

    + Nulla efficitur eleifend nisi, sit amet bibendum sapien fringilla ac. + Mauris euismod metus a tellus laoreet, at elementum ex efficitur. +

    +
    +          <!DOCTYPE html> <html> <head> <title>Hello
    +          World</title> </head> <body> <p>Lorem ipsum
    +          dolor sit amet, consectetur adipiscing elit. Donec viverra nec nulla
    +          vitae mollis.</p> </body> </html>
    +        
    +

    + Maecenas eleifend sollicitudin dui, faucibus sollicitudin augue cursus + non. Ut finibus eleifend arcu ut vehicula. Mauris eu est maximus est + porta condimentum in eu justo. Nulla id iaculis sapien. +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    OneTwo
    ThreeFour
    FiveSix
    SevenEight
    NineTen
    ElevenTwelve
    +

    + Phasellus porttitor enim id metus volutpat ultricies. Ut nisi nunc, + blandit sed dapibus at, vestibulum in felis. Etiam iaculis lorem ac + nibh bibendum rhoncus. Nam interdum efficitur ligula sit amet + ullamcorper. Etiam tristique, leo vitae porta faucibus, mi lacus + laoreet metus, at cursus leo est vel tellus. Sed ac posuere est. Nunc + ultricies nunc neque, vitae ultricies ex sodales quis. Aliquam eu nibh + in libero accumsan pulvinar. Nullam nec nisl placerat, pretium metus + vel, euismod ipsum. Proin tempor cursus nisl vel condimentum. Nam + pharetra varius metus non pellentesque. +

    +
    Fifth level
    +

    + Aliquam sagittis rhoncus vulputate. Cras non luctus sem, sed tincidunt + ligula. Vestibulum at nunc elit. Praesent aliquet ligula mi, in luctus + elit volutpat porta. Phasellus molestie diam vel nisi sodales, a + eleifend augue laoreet. Sed nec eleifend justo. Nam et sollicitudin + odio. +

    +
    + 256 + other +
    Figure 1: Some beautiful placeholders
    +
    +
    Sixth level
    +

    + Cras in nibh lacinia, venenatis nisi et, auctor urna. Donec pulvinar + lacus sed diam dignissim, ut eleifend eros accumsan. Phasellus non + tortor eros. Ut sed rutrum lacus. Etiam purus nunc, scelerisque quis + enim vitae, malesuada ultrices turpis. Nunc vitae maximus purus, nec + consectetur dui. Suspendisse euismod, elit vel rutrum commodo, ipsum + tortor maximus dui, sed varius sapien odio vitae est. Etiam at cursus + metus. +

    +
    + ); + }, +}; + +Default.argTypes = { + size: { + control: { + type: 'select', + options: ['default', 'small', 'medium', 'large'], + }, + }, +}; diff --git a/src/components/content/content.story.js b/src/components/content/content.story.js deleted file mode 100644 index a382ce465..000000000 --- a/src/components/content/content.story.js +++ /dev/null @@ -1,170 +0,0 @@ -import React from 'react'; - -import Content from '.'; - -export const Default = (args) => { - return ( - -

    Hello World

    -

    - Lorem ipsum - - [1] - {' '} - dolor sit amet, consectetur adipiscing elit. Nulla accumsan, metus - ultrices eleifend gravida, nulla nunc varius lectus, nec rutrum justo - nibh eu lectus. Ut vulputate semper dui. Fusce erat odio, sollicitudin - vel erat vel, interdum mattis neque. Subscript works as well! -

    -

    Second level

    -

    - Curabitur accumsan turpis pharetra augue tincidunt{' '} - blandit. Quisque condimentum maximus mi, sit amet commodo arcu rutrum - id. Proin pretium urna vel cursus venenatis. Suspendisse potenti. Etiam - mattis sem rhoncus lacus dapibus facilisis. Donec at dignissim dui. Ut - et neque nisl. -

    -
      -
    • In fermentum leo eu lectus mollis, quis dictum mi aliquet.
    • -
    • Morbi eu nulla lobortis, lobortis est in, fringilla felis.
    • -
    • - Aliquam nec felis in sapien venenatis viverra fermentum nec lectus. -
    • -
    • Ut non enim metus.
    • -
    -

    Third level

    -

    - Quisque ante lacus, malesuada ac auctor vitae, congue{' '} - non ante. Phasellus lacus ex, semper ac tortor nec, - fringilla condimentum orci. Fusce eu rutrum tellus. -

    -
      -
    1. Donec blandit a lorem id convallis.
    2. -
    3. Cras gravida arcu at diam gravida gravida.
    4. -
    5. Integer in volutpat libero.
    6. -
    7. Donec a diam tellus.
    8. -
    9. Aenean nec tortor orci.
    10. -
    11. Quisque aliquam cursus urna, non bibendum massa viverra eget.
    12. -
    13. Vivamus maximus ultricies pulvinar.
    14. -
    -
    - Ut venenatis, nisl scelerisque sollicitudin fermentum, quam libero - hendrerit ipsum, ut blandit est tellus sit amet turpis. -
    -

    - Quisque at semper enim, eu hendrerit odio. Etiam auctor nisl et{' '} - justo sodales elementum. Maecenas ultrices lacus quis neque - consectetur, et lobortis nisi molestie. -

    -

    - Sed sagittis enim ac tortor maximus rutrum. Nulla facilisi. Donec mattis - vulputate risus in luctus. Maecenas vestibulum interdum commodo. -

    -
    -
    Web
    -
    The part of the Internet that contains websites and web pages
    -
    HTML
    -
    A markup language for creating web pages
    -
    CSS
    -
    A technology to make HTML look better
    -
    -

    - Suspendisse egestas sapien non felis placerat elementum. Morbi tortor - nisl, suscipit sed mi sit amet, mollis malesuada nulla. Nulla facilisi. - Nullam ac erat ante. -

    -

    Fourth level

    -

    - Nulla efficitur eleifend nisi, sit amet bibendum sapien fringilla ac. - Mauris euismod metus a tellus laoreet, at elementum ex efficitur. -

    -
    -        <!DOCTYPE html> <html> <head> <title>Hello
    -        World</title> </head> <body> <p>Lorem ipsum
    -        dolor sit amet, consectetur adipiscing elit. Donec viverra nec nulla
    -        vitae mollis.</p> </body> </html>
    -      
    -

    - Maecenas eleifend sollicitudin dui, faucibus sollicitudin augue cursus - non. Ut finibus eleifend arcu ut vehicula. Mauris eu est maximus est - porta condimentum in eu justo. Nulla id iaculis sapien. -

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    OneTwo
    ThreeFour
    FiveSix
    SevenEight
    NineTen
    ElevenTwelve
    -

    - Phasellus porttitor enim id metus volutpat ultricies. Ut nisi nunc, - blandit sed dapibus at, vestibulum in felis. Etiam iaculis lorem ac nibh - bibendum rhoncus. Nam interdum efficitur ligula sit amet ullamcorper. - Etiam tristique, leo vitae porta faucibus, mi lacus laoreet metus, at - cursus leo est vel tellus. Sed ac posuere est. Nunc ultricies nunc - neque, vitae ultricies ex sodales quis. Aliquam eu nibh in libero - accumsan pulvinar. Nullam nec nisl placerat, pretium metus vel, euismod - ipsum. Proin tempor cursus nisl vel condimentum. Nam pharetra varius - metus non pellentesque. -

    -
    Fifth level
    -

    - Aliquam sagittis rhoncus vulputate. Cras non luctus sem, sed tincidunt - ligula. Vestibulum at nunc elit. Praesent aliquet ligula mi, in luctus - elit volutpat porta. Phasellus molestie diam vel nisi sodales, a - eleifend augue laoreet. Sed nec eleifend justo. Nam et sollicitudin - odio. -

    -
    - 256 - other -
    Figure 1: Some beautiful placeholders
    -
    -
    Sixth level
    -

    - Cras in nibh lacinia, venenatis nisi et, auctor urna. Donec pulvinar - lacus sed diam dignissim, ut eleifend eros accumsan. Phasellus non - tortor eros. Ut sed rutrum lacus. Etiam purus nunc, scelerisque quis - enim vitae, malesuada ultrices turpis. Nunc vitae maximus purus, nec - consectetur dui. Suspendisse euismod, elit vel rutrum commodo, ipsum - tortor maximus dui, sed varius sapien odio vitae est. Etiam at cursus - metus. -

    -
    - ); -}; - -Default.argTypes = { - size: { - control: { - type: 'select', - options: ['default', 'small', 'medium', 'large'], - }, - }, -}; diff --git a/src/components/content/content.story.mdx b/src/components/content/content.story.mdx deleted file mode 100644 index b44dd3131..000000000 --- a/src/components/content/content.story.mdx +++ /dev/null @@ -1,49 +0,0 @@ -import { ArgsTable, Canvas, Meta, Story } from '@storybook/addon-docs/blocks'; -import { Content } from '../..'; -import * as stories from './content.story'; -import CommonProps from '../../../.storybook/common-props'; - - - -# Content - -This component handles WYSIWYG/plain HTML content. -The example below demonstrates the formatting of different HTML elements. - - -## Props - - - - - -## Size - -You can adjust the size of the content with the `size` prop. -There are three sizes available: - -- `'small'` -- `'medium'` -- `'large'` - -## List styles - -Although this library does not provide components that let you change item markers of `
      ` inside ``, -you can still use the following Bulma classes via the `className` prop to do just that: - -- `is-lower-alpha` -- `is-lower-roman` -- `is-upper-alpha` -- `is-upper-roman` - -Alternatively, you can use the HTML `type` attribute of `
        ` to achieve the same effect. - -## Example - - - - - -## Related - -- [Official documentation](https://bulma.io/documentation/elements/content/) diff --git a/src/components/content/index.d.ts b/src/components/content/index.d.ts index 53e366e0c..a4260d7b3 100644 --- a/src/components/content/index.d.ts +++ b/src/components/content/index.d.ts @@ -1,10 +1,8 @@ import { BulmaComponent } from '..'; import { Size } from '..'; -interface ContentProps { +type ContentProps = { size?: Size; -} +}; -declare const Content: BulmaComponent; - -export default Content; \ No newline at end of file +export declare const Content: BulmaComponent; diff --git a/src/components/content/index.js b/src/components/content/index.js index 395ae0daf..7b367d146 100644 --- a/src/components/content/index.js +++ b/src/components/content/index.js @@ -1,3 +1 @@ -import Content from './content'; - -export default Content; +export * from './content'; diff --git a/src/components/delete/delete.story.mdx b/src/components/delete/delete.story.mdx deleted file mode 100644 index 6391ebe6e..000000000 --- a/src/components/delete/delete.story.mdx +++ /dev/null @@ -1,20 +0,0 @@ -import { Meta, Canvas, Story } from '@storybook/addon-docs/blocks'; -import { Button } from '../..'; - - - -# Delete - -A versatile delete cross, This is included inside the `Button` component passing the `remove` prop - -## Example - - - - - - - + `; exports[`Dropdown component Should be right-aligned when using "right" prop 1`] = ` -
        +
        - -
        - -
        + `; exports[`Dropdown component Should concat Bulma class with classes in props 1`] = ` -
        +
        - -
        - -
        + `; exports[`Dropdown component Should have custom inline styles 1`] = ` -
        -
        - -
        + -
        + `; exports[`Dropdown component Should have divider 1`] = ` -
        +
        - -
        - -
        + `; exports[`Dropdown component Should have dropdown classname 1`] = ` -
        +
        - -
        - -
        + `; -exports[`Dropdown component Should show custom label passed to the label prop 1`] = ` -
        -
        - -
        +exports[`Dropdown component Should pass specified ID to the menu component 1`] = ` + -
        + `; exports[`Dropdown component Should show the label of the first dropdown item when no custom label is passed 1`] = ` -
        -
        - -
        - +
        , + "debug": [Function], + "findAllByAltText": [Function], + "findAllByDisplayValue": [Function], + "findAllByLabelText": [Function], + "findAllByPlaceholderText": [Function], + "findAllByRole": [Function], + "findAllByTestId": [Function], + "findAllByText": [Function], + "findAllByTitle": [Function], + "findByAltText": [Function], + "findByDisplayValue": [Function], + "findByLabelText": [Function], + "findByPlaceholderText": [Function], + "findByRole": [Function], + "findByTestId": [Function], + "findByText": [Function], + "findByTitle": [Function], + "getAllByAltText": [Function], + "getAllByDisplayValue": [Function], + "getAllByLabelText": [Function], + "getAllByPlaceholderText": [Function], + "getAllByRole": [Function], + "getAllByTestId": [Function], + "getAllByText": [Function], + "getAllByTitle": [Function], + "getByAltText": [Function], + "getByDisplayValue": [Function], + "getByLabelText": [Function], + "getByPlaceholderText": [Function], + "getByRole": [Function], + "getByTestId": [Function], + "getByText": [Function], + "getByTitle": [Function], + "queryAllByAltText": [Function], + "queryAllByDisplayValue": [Function], + "queryAllByLabelText": [Function], + "queryAllByPlaceholderText": [Function], + "queryAllByRole": [Function], + "queryAllByTestId": [Function], + "queryAllByText": [Function], + "queryAllByTitle": [Function], + "queryByAltText": [Function], + "queryByDisplayValue": [Function], + "queryByLabelText": [Function], + "queryByPlaceholderText": [Function], + "queryByRole": [Function], + "queryByTestId": [Function], + "queryByText": [Function], + "queryByTitle": [Function], + "rerender": [Function], + "unmount": [Function], +} `; exports[`Dropdown component should also be right-aligned when using "align" prop 1`] = ` -
        +
        - -
        - -
        + `; diff --git a/src/components/dropdown/__test__/dropdown.test.js b/src/components/dropdown/__test__/dropdown.test.js index 623ab0f02..317d6c873 100644 --- a/src/components/dropdown/__test__/dropdown.test.js +++ b/src/components/dropdown/__test__/dropdown.test.js @@ -1,161 +1,106 @@ import React from 'react'; -import renderer from 'react-test-renderer'; -import { shallow, mount } from 'enzyme'; -import { JSDOM } from 'jsdom'; -import Dropdown from '..'; +import { render, screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import { Dropdown } from '..'; describe('Dropdown component', () => { - beforeEach(() => { - // eslint-disable-next-line - global.window = new JSDOM('
        ').window; - }); it('Should Exist', () => { expect(Dropdown).toMatchSnapshot(); }); it('Should have dropdown classname', () => { - const component = renderer.create( + const component = render( {}}> Item , ); - expect(component.toJSON()).toMatchSnapshot(); - }); - it('Should add listener do document on mount', () => { - const app = global.window.document.querySelector('#app-root'); - global.window.document.addEventListener = jest.fn(); - const component = mount( - {}}> - Item - , - { - attachTo: app, - }, - ); - expect(window.document.addEventListener).toHaveBeenCalled(); - component.unmount(); + expect(component.asFragment()).toMatchSnapshot(); }); it('Should concat Bulma class with classes in props', () => { - const component = renderer.create( + const component = render( {}}> Item , ); - expect(component.toJSON()).toMatchSnapshot(); + expect(component.asFragment()).toMatchSnapshot(); }); it('Should have custom inline styles', () => { - const component = renderer.create( + const component = render( {}}> Item , ); - expect(component.toJSON()).toMatchSnapshot(); + expect(component.asFragment()).toMatchSnapshot(); }); it('Should have divider', () => { - const component = renderer.create( + const component = render( {}}> Item Other , ); - expect(component.toJSON()).toMatchSnapshot(); + expect(component.asFragment()).toMatchSnapshot(); }); it('Should be right-aligned when using "right" prop', () => { - const component = renderer.create( + const component = render( Item Other , ); - expect(component.toJSON()).toMatchSnapshot(); + expect(component.asFragment()).toMatchSnapshot(); }); it('should also be right-aligned when using "align" prop', () => { - const component = renderer.create( + const component = render( Item Other , ); - expect(component.toJSON()).toMatchSnapshot(); + expect(component.asFragment()).toMatchSnapshot(); }); it('Should appear above the dropdown button', () => { - const component = renderer.create( + const component = render( Item Other , ); - expect(component.toJSON()).toMatchSnapshot(); - }); - it.skip('Should open the Dropdown', () => { - const component = shallow( - {}}> - Item - - Other - , - ); - expect(component.state('open')).toBe(false); - component.find('.dropdown-trigger').simulate('click'); - expect(component.state('open')).toBe(true); - }); - it.skip('Should open the Dropdown and prevent default event (not to navigate if a link is on the dropdown trigger)', () => { - const preventDefault = jest.fn(); - const component = shallow( - {}}> - Item - - Other - , - ); - expect(component.state('open')).toBe(false); - component.find('.dropdown-trigger').simulate('click', { preventDefault }); - expect(preventDefault).toHaveBeenCalled(); - expect(component.state('open')).toBe(true); - }); - it.skip('Should change the value', () => { - const onChange = jest.fn(); - const component = shallow( - - Item - , - ); - component.find('.dropdown-trigger').simulate('click'); - component.find(Dropdown.Item).simulate('click'); - expect(onChange).toHaveBeenCalledWith('value'); - expect(component.state('open')).toBe(false); - }); - it.skip('Should close on select', () => { - const component = mount( - - Item - , - ); - component.find('.dropdown-trigger').simulate('click'); - component.find(Dropdown.Item).simulate('click'); - expect(component.state('open')).toBe(false); + expect(component.asFragment()).toMatchSnapshot(); }); - it.skip('Should close the dropdown', () => { - const onChange = jest.fn(); - const component = mount( - - Item + it('Should open the Dropdown', async () => { + const user = userEvent.setup(); + const onOpen = jest.fn(); + render( + + Trigger + + Item + , ); - component.find('.dropdown-trigger').simulate('click'); - component.find(Dropdown.Item).simulate('click', { path: [] }); - expect(component.state('open')).toBe(false); + await user.click(screen.getByText('Trigger')); + expect(onOpen).toHaveBeenCalled(); }); - it('Should show custom label passed to the label prop', () => { - const component = renderer.create( - - Item + it('Should close on select', async () => { + const user = userEvent.setup(); + const onOpen = jest.fn(); + const onClose = jest.fn(); + render( + + Trigger + + Item + , ); - expect(component).toMatchSnapshot(); + await user.click(screen.getByText('Trigger')); + expect(onOpen).not.toHaveBeenCalled(); + expect(onClose).toHaveBeenCalled(); }); + it('Should show the label of the first dropdown item when no custom label is passed', () => { - const component = renderer.create( + const component = render( Item , @@ -163,27 +108,30 @@ describe('Dropdown component', () => { expect(component).toMatchSnapshot(); }); it('Should show custom label when active valued is undefined/empty', () => { - const component = shallow( - + render( + + test label Item , ); - expect(component.find('span').text()).toEqual('test label'); + expect(screen.getByText('test label')).toBeInTheDocument(); }); it('Should show the label of the dropdown item when value of it is the active value', () => { - const component = shallow( + render( + test label + Item Item , ); - expect(component.find('span').text()).toEqual('Item'); + expect(screen.queryAllByText('Item')).toHaveLength(2); }); it('Should pass specified ID to the menu component', () => { - const component = shallow( + const component = render( Item , ); - expect(component).toMatchSnapshot(); + expect(component.asFragment()).toMatchSnapshot(); }); }); diff --git a/src/components/dropdown/components/divider.js b/src/components/dropdown/components/divider.js index 943217014..73e4563f5 100644 --- a/src/components/dropdown/components/divider.js +++ b/src/components/dropdown/components/divider.js @@ -1,18 +1,18 @@ import React from 'react'; -import classnames from 'classnames'; +import clsx from 'clsx'; -import Element from '../../element'; +import { Element } from '../../element'; const DropdownDivider = ({ className, ...props }) => { return ( - + ); }; -DropdownDivider.propTypes = {}; - -DropdownDivider.defaultProps = { - renderAs: 'hr', -}; +Element.setDisplayName(DropdownDivider, 'Dropdown.Divider'); export default DropdownDivider; diff --git a/src/components/dropdown/components/item.js b/src/components/dropdown/components/item.js index b6179d91a..b29534351 100644 --- a/src/components/dropdown/components/item.js +++ b/src/components/dropdown/components/item.js @@ -1,15 +1,12 @@ import React from 'react'; -import PropTypes from 'prop-types'; -import classnames from 'classnames'; +import classnames from 'clsx'; -import Element from '../../element'; +import { Element } from '../../element'; -const DropdownItem = ({ active, children, value, className, ...props }) => { +const DropdownItem = ({ active, children, className, ...props }) => { return ( { ); }; -DropdownItem.propTypes = { - /** - * Whether this dropdown item is currently selected. - * Shows a highlighted effect if true. - * Note that the effect only works when this item is rendered as an anchor - * (``). - */ - active: PropTypes.bool, - /** - * The value this dropdown item holds. When this item is clicked, - * this value is passed to the onChange callback of ``. - * The value is used to determine if this item is active or not. - */ - value: PropTypes.any.isRequired, -}; - -DropdownItem.defaultProps = {}; +Element.setDisplayName(DropdownItem, 'Dropdown.Item'); export default DropdownItem; diff --git a/src/components/dropdown/components/trigger.js b/src/components/dropdown/components/trigger.js new file mode 100644 index 000000000..5f7bb3f9f --- /dev/null +++ b/src/components/dropdown/components/trigger.js @@ -0,0 +1,27 @@ +import React from 'react'; +import clsx from 'clsx'; + +import { Element } from '../../element'; + +const DropdownTrigger = ({ + children, + className, + open, + onOpen, + onClose, + ...props +}) => { + return ( + + {children} + + ); +}; + +Element.setDisplayName(DropdownTrigger, 'Dropdown.Trigger'); + +export default DropdownTrigger; diff --git a/src/components/dropdown/dropdown.js b/src/components/dropdown/dropdown.js index 87bcb50ce..e9d2fa17a 100644 --- a/src/components/dropdown/dropdown.js +++ b/src/components/dropdown/dropdown.js @@ -1,13 +1,14 @@ -import React, { useEffect, useRef, useState } from 'react'; -import PropTypes from 'prop-types'; -import classnames from 'classnames'; +import React, { useEffect, useRef } from 'react'; +import clsx from 'clsx'; import DropdownItem from './components/item'; import DropdownDivider from './components/divider'; -import Button from '../button'; +import DropdownTrigger from './components/trigger'; +import { Element } from '../element'; -import Element from '../element'; - -const Dropdown = ({ +/** + * @type {typeof import('.').Dropdown} + */ +export const Dropdown = ({ className, children, value, @@ -16,179 +17,76 @@ const Dropdown = ({ right, up, hoverable, - label, - onChange, - closeOnSelect, - icon, domRef, disabled, - menuId, + menuId = 'dropdown-menu', + open, + onOpen, + onClose, ...props }) => { const ref = useRef(domRef); - const [isOpen, setIsOpen] = useState(false); - const close = (evt) => { - // IDK yet how to test using the ref in enzime - // istanbul ignore if - if ( - hoverable || - (evt && ref && ref.current && ref.current.contains(evt.target)) - ) { - return; - } - if (ref.current) { - setIsOpen(false); - } - }; - const onSelect = (selectedValue) => { - return () => { - if (onChange) { - onChange(selectedValue); - } - if (closeOnSelect) { - close(); + const { trigger, child } = React.Children.toArray(children).reduce( + (acc, current) => { + if (current.type === DropdownTrigger) { + return { + ...acc, + trigger: React.cloneElement(current, { + open, + onOpen, + onClose, + }), + }; } - }; - }; + return { + ...acc, + child: acc.child.concat([current]), + }; + }, + { trigger: undefined, child: [] }, + ); useEffect(() => { + const close = (evt) => { + // istanbul ignore if + if ( + hoverable || + (evt && ref && ref.current && ref.current.contains(evt.target)) + ) { + return; + } + if (ref.current) { + onClose(evt); + } + }; window.addEventListener('click', close); return () => { window.removeEventListener('click', close); }; - }, []); - - let current = label; - - const childrenArray = React.Children.map(children, (child, i) => { - if ( - child.type === DropdownItem && - ((i === 0 && !label) || child.props.value === value) - ) { - current = child.props.children; - } - return React.cloneElement( - child, - child.type === DropdownItem - ? { - active: child.props.value === value, - onClick: onSelect(child.props.value), - } - : {}, - ); - }); + }, [hoverable, onClose]); return ( -
        { - if (disabled) { - return; - } - setIsOpen((open) => { - return !open; - }); - }} - > - -
        + {trigger}
        ); }; -Dropdown.Item = DropdownItem; +Element.setDisplayName(Dropdown, 'Dropdown'); +Dropdown.Trigger = DropdownTrigger; +Dropdown.Item = DropdownItem; Dropdown.Divider = DropdownDivider; - -Dropdown.propTypes = { - /** - * The value of the currently selected dropdown item. If this value match - * with the value passed to a Dropdown.item it will be used as label if the label prop its empty - */ - value: PropTypes.any, - /** - * Called when a dropdown item is selected. - */ - onChange: PropTypes.func, - /** - * The color of the dropdown button. - */ - color: PropTypes.oneOfType([ - PropTypes.oneOf([ - 'primary', - 'link', - 'info', - 'success', - 'warning', - 'danger', - 'dark', - 'text', - ]), - PropTypes.string, - ]), - disabled: PropTypes.bool, - /** - * Whether the dropdown should align to the right side. - */ - right: PropTypes.bool, - /** - * Whether the dropdown menu should appear above the dropdown button - * instead of below. - */ - up: PropTypes.bool, - /** - * Whether the dropdown menu can be activated when the cursor - * hovers above the button without clicking. - */ - hoverable: PropTypes.bool, - /** - * A string, or a react component that displays the label of the dropdown - * button. if not set it will be use the selected Dropdown.Item or the first one - * if there is no selected - */ - label: PropTypes.node, - /** - * Whether the dropdown menu should be closed when a dropdown item is selected. - */ - closeOnSelect: PropTypes.bool, - /** - * A react component that draws the icon of the dropdown button. - * Usually it is an arrow (or a chevron) pointing downwards (or upwards). - */ - icon: PropTypes.node, - /** - * Specify the id of the menu component. - * Default is "dropdown-menu". - */ - menuId: PropTypes.string, -}; - -Dropdown.defaultProps = { - closeOnSelect: true, - menuId: 'dropdown-menu', -}; - -export default Dropdown; diff --git a/src/components/dropdown/dropdown.stories.js b/src/components/dropdown/dropdown.stories.js new file mode 100644 index 000000000..94661a62a --- /dev/null +++ b/src/components/dropdown/dropdown.stories.js @@ -0,0 +1,138 @@ +/* eslint-disable react/prop-types */ +import React, { useState } from 'react'; + +import CONSTANTS from '../../constants'; +import { Box, Dropdown } from '../..'; + +export default { + title: 'Elements/Dropdown', +}; + +export const Overview = { + render: (args) => { + // eslint-disable-next-line react-hooks/rules-of-hooks + const [open, setOpen] = useState(false); + return ( + + { + setOpen(true); + }} + onClose={() => { + setOpen(false); + }} + color={args.color === 'default' ? '' : args.color} + > + Open + + Dropdown item + + + Other Dropdown item + + + Active Dropdown item + + + Other Dropdown item + + + + After divider + + + + ); + }, +}; + +Overview.argTypes = { + label: { + defaultValue: 'Dropdown label', + control: { + type: 'text', + }, + }, + color: { + defaultValue: '', + control: { + type: 'select', + }, + options: ['default', ...Object.values(CONSTANTS.COLORS)], + }, + hoverable: { + defaultValue: false, + control: { + type: 'boolean', + }, + }, + closeOnSelect: { + defaultValue: false, + control: { + type: 'boolean', + }, + }, + right: { + defaultValue: false, + control: { + type: 'boolean', + }, + }, + up: { + defaultValue: false, + control: { + type: 'boolean', + }, + }, + disabled: { + defaultValue: false, + control: { + type: 'boolean', + }, + }, +}; + +export const Controlled = { + render: (args) => { + // eslint-disable-next-line react-hooks/rules-of-hooks + const [selected, setSelected] = useState(''); + return ( + + + Dropdown item + + + Other Dropdown item + + + Active Dropdown item + + + Other Dropdown item + + + + With divider + + + ); + }, +}; + +Controlled.argTypes = { + hoverable: { + defaultValue: false, + control: { + type: 'boolean', + }, + }, +}; diff --git a/src/components/dropdown/dropdown.story.js b/src/components/dropdown/dropdown.story.js deleted file mode 100644 index d554f85d1..000000000 --- a/src/components/dropdown/dropdown.story.js +++ /dev/null @@ -1,127 +0,0 @@ -/* eslint-disable react/prop-types */ -import React, { useState } from 'react'; - -import CONSTANTS from '../../constants'; -import { Box, Dropdown } from '../..'; -import Icon from '../icon'; - -const icon = ( - -
        -``` - -and `Button` is rendered as: - -```jsx - - - My Notification - -``` - - - - - - - My Secondary Notification - \ No newline at end of file diff --git a/src/components/footer/__test__/__snapshots__/footer.test.js.snap b/src/components/footer/__test__/__snapshots__/footer.test.js.snap index 02720e6bc..db24f4574 100644 --- a/src/components/footer/__test__/__snapshots__/footer.test.js.snap +++ b/src/components/footer/__test__/__snapshots__/footer.test.js.snap @@ -1,18 +1,20 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Footer component Should have footer classname 1`] = ` -
        -

        +

        -

        - Default -

        -

        - Container -

        -

        -
        +
        +

        + Default +

        +

        + Container +

        +
        +
        + `; diff --git a/src/components/footer/__test__/footer.test.js b/src/components/footer/__test__/footer.test.js index 65825b5df..7af52260a 100644 --- a/src/components/footer/__test__/footer.test.js +++ b/src/components/footer/__test__/footer.test.js @@ -1,17 +1,17 @@ import React from 'react'; -import renderer from 'react-test-renderer'; -import Footer from '..'; +import { render } from '@testing-library/react'; +import { Footer } from '..'; describe('Footer component', () => { it('Should have footer classname', () => { - const component = renderer.create( + const component = render(
        -

        +

        Default

        Container

        -

        +
        , ); - expect(component.toJSON()).toMatchSnapshot(); + expect(component.asFragment()).toMatchSnapshot(); }); }); diff --git a/src/components/footer/footer.js b/src/components/footer/footer.js index 712ef56bd..faf059fce 100644 --- a/src/components/footer/footer.js +++ b/src/components/footer/footer.js @@ -1,23 +1,19 @@ import React from 'react'; -import PropTypes from 'prop-types'; -import classnames from 'classnames'; +import clsx from 'clsx'; -import Element from '../element'; +import { Element } from '../element'; -const Footer = ({ className, ...props }) => { - return ; +/** + * @type {typeof import('.').Footer} + */ +export const Footer = ({ className, ...props }) => { + return ( + + ); }; -Footer.propTypes = { - renderAs: PropTypes.oneOfType([ - PropTypes.func, - PropTypes.string, - PropTypes.object, - ]), -}; - -Footer.defaultProps = { - renderAs: 'footer', -}; - -export default Footer; +Element.setDisplayName(Footer, 'Footer'); diff --git a/src/components/footer/footer.stories.js b/src/components/footer/footer.stories.js new file mode 100644 index 000000000..44fd5b1b0 --- /dev/null +++ b/src/components/footer/footer.stories.js @@ -0,0 +1,42 @@ +import React from 'react'; + +import { Footer, Container, Content, Hero } from '../..'; + +export default { + title: 'Elements/Footer', +}; + +export const Default = { + render: () => { + return ( +
        + + + + + + + +
        + ); + }, +}; diff --git a/src/components/footer/footer.story.js b/src/components/footer/footer.story.js deleted file mode 100644 index f9d47978c..000000000 --- a/src/components/footer/footer.story.js +++ /dev/null @@ -1,36 +0,0 @@ -import React from 'react'; - -import { Footer, Container, Content, Hero } from '../..'; - -export const Default = () => { - return ( -
        - - - - - - - -
        - ); -}; diff --git a/src/components/footer/footer.story.mdx b/src/components/footer/footer.story.mdx deleted file mode 100644 index 8129ba56c..000000000 --- a/src/components/footer/footer.story.mdx +++ /dev/null @@ -1,26 +0,0 @@ -import { ArgsTable, Canvas, Meta, Story } from '@storybook/addon-docs/blocks'; -import Footer from '.'; -import CommonProps from '../../../.storybook/common-props'; -import * as stories from './footer.story'; - - - -# Footer - -A responsive footer that can contain other components. - -## Props - - - - - -## Example - - - - - -## Related - -- [Official documentation](https://bulma.io/documentation/layout/footer/) \ No newline at end of file diff --git a/src/components/footer/index.d.ts b/src/components/footer/index.d.ts index c8ddc966b..7ec9de1d6 100644 --- a/src/components/footer/index.d.ts +++ b/src/components/footer/index.d.ts @@ -1,5 +1,4 @@ import { BulmaComponent } from '..'; -declare const Footer: BulmaComponent<{}, 'div'>; +export declare const Footer: BulmaComponent<{}, 'div'>; -export default Footer; diff --git a/src/components/footer/index.js b/src/components/footer/index.js index 19e22f87c..a058eae01 100644 --- a/src/components/footer/index.js +++ b/src/components/footer/index.js @@ -1,3 +1 @@ -import Footer from './footer'; - -export default Footer; +export * from './footer'; diff --git a/src/components/form/__test__/__snapshots__/index.test.js.snap b/src/components/form/__test__/__snapshots__/index.test.js.snap index b2ec779e4..e0a575df2 100644 --- a/src/components/form/__test__/__snapshots__/index.test.js.snap +++ b/src/components/form/__test__/__snapshots__/index.test.js.snap @@ -1,7 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Form component Should expose all Form elements 1`] = ` -Object { +{ "Checkbox": [Function], "Control": [Function], "Field": [Function], diff --git a/src/components/form/all-components.d.ts b/src/components/form/all-components.d.ts new file mode 100644 index 000000000..11ac92c4e --- /dev/null +++ b/src/components/form/all-components.d.ts @@ -0,0 +1,10 @@ +export * from './components/field'; +export * from './components/control'; +export * from './components/input'; +export * from './components/label'; +export * from './components/textarea'; +export * from './components/select'; +export * from './components/checkbox'; +export * from './components/radio'; +export * from './components/help'; +export * from './components/input-file'; diff --git a/src/components/form/components/__test__/__snapshots__/checkbox.test.js.snap b/src/components/form/components/__test__/__snapshots__/checkbox.test.js.snap index 8045cf750..08d0956cc 100644 --- a/src/components/form/components/__test__/__snapshots__/checkbox.test.js.snap +++ b/src/components/form/components/__test__/__snapshots__/checkbox.test.js.snap @@ -3,13 +3,14 @@ exports[`Checkbox component Should Exists 1`] = `[Function]`; exports[`Checkbox component Should have checkbox classname 1`] = ` - + + + `; diff --git a/src/components/form/components/__test__/__snapshots__/control.test.js.snap b/src/components/form/components/__test__/__snapshots__/control.test.js.snap index 87ef05ff5..9bc81cb4a 100644 --- a/src/components/form/components/__test__/__snapshots__/control.test.js.snap +++ b/src/components/form/components/__test__/__snapshots__/control.test.js.snap @@ -1,55 +1,59 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Control component Should concat classname in props with Bulma classname 1`] = ` -
        -

        - Default -

        -
        + +
        +

        + Default +

        +
        +
        `; exports[`Control component Should exist 1`] = `[Function]`; exports[`Control component Should have control classname 1`] = ` -
        -

        +

        -

        - Default -

        -

        - Container -

        -

        -
        +
        +

        + Default +

        +

        + Container +

        +
        +
        + `; exports[`Control component Should render as a html section element 1`] = ` -
        -

        - Default -

        -
        + +
        +

        + Default +

        +
        +
        `; exports[`Control component Should use inline styles 1`] = ` -
        -

        - Default -

        -
        + +
        +

        + Default +

        +
        +
        `; diff --git a/src/components/form/components/__test__/__snapshots__/field.test.js.snap b/src/components/form/components/__test__/__snapshots__/field.test.js.snap index 3e068a349..232432e24 100644 --- a/src/components/form/components/__test__/__snapshots__/field.test.js.snap +++ b/src/components/form/components/__test__/__snapshots__/field.test.js.snap @@ -7,86 +7,96 @@ exports[`Field component Should export Label and Body as static properties 1`] = exports[`Field component Should export Label and Body as static properties 2`] = `[Function]`; exports[`Field component Should have field classname 1`] = ` -
        -

        +

        -

        - Default -

        -

        - Container -

        -

        -
        +
        +

        + Default +

        +

        + Container +

        +
        +
        + `; exports[`Field component Should have field classname with addons classname 1`] = ` -
        -

        +

        -

        - Default -

        -

        - Container -

        -

        -
        +
        +

        + Default +

        +

        + Container +

        +
        +
        + `; exports[`Field component Should have field classname with grouped classname 1`] = ` -
        -

        +

        -

        - Default -

        -

        - Container -

        -

        -
        +
        +

        + Default +

        +

        + Container +

        +
        +
        + `; exports[`Field component Should have field-body classname 1`] = ` -
        -

        +

        -

        - Default -

        -

        - Container -

        -

        -
        +
        +

        + Default +

        +

        + Container +

        +
        +
        + `; exports[`Field component Should have field-label classname 1`] = ` -
        -

        +

        -

        - Default -

        -

        - Container -

        -

        -
        +
        +

        + Default +

        +

        + Container +

        +
        +
        + `; diff --git a/src/components/form/components/__test__/__snapshots__/help.test.js.snap b/src/components/form/components/__test__/__snapshots__/help.test.js.snap index dd4fec12b..36ceddf46 100644 --- a/src/components/form/components/__test__/__snapshots__/help.test.js.snap +++ b/src/components/form/components/__test__/__snapshots__/help.test.js.snap @@ -1,55 +1,59 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Help component Should be displayed as a successful message 1`] = ` -

        -

        - Default -

        -

        + +
        +

        + Default +

        +
        +
        `; exports[`Help component Should concat classname in props with Bulma classname 1`] = ` -

        -

        - Default -

        -

        + +
        +

        + Default +

        +
        +
        `; exports[`Help component Should exist 1`] = `[Function]`; exports[`Help component Should have help classname 1`] = ` -

        -

        +

        -

        - Default -

        -

        - Container -

        -

        -

        +
        +

        + Default +

        +

        + Container +

        +
        +
        + `; exports[`Help component Should use inline styles 1`] = ` -

        -

        - Default -

        -

        + +
        +

        + Default +

        +
        +
        `; diff --git a/src/components/form/components/__test__/__snapshots__/input-file.test.js.snap b/src/components/form/components/__test__/__snapshots__/input-file.test.js.snap index 40fd660f5..74629a690 100644 --- a/src/components/form/components/__test__/__snapshots__/input-file.test.js.snap +++ b/src/components/form/components/__test__/__snapshots__/input-file.test.js.snap @@ -3,143 +3,149 @@ exports[`Dropdown component Should Exist 1`] = `[Function]`; exports[`Dropdown component Should be centered 1`] = ` -
        - +
        + `; exports[`Dropdown component Should render file input tree 1`] = ` -
        - +
        + `; exports[`Dropdown component should pass file attributes 1`] = ` -
        - +
        + `; exports[`Dropdown component should set filename text 1`] = ` -
        - +
        + `; exports[`Dropdown component should set filename text 2`] = ` -
        - +
        + `; diff --git a/src/components/form/components/__test__/__snapshots__/input.test.js.snap b/src/components/form/components/__test__/__snapshots__/input.test.js.snap index d0ee447d4..f5982b372 100644 --- a/src/components/form/components/__test__/__snapshots__/input.test.js.snap +++ b/src/components/form/components/__test__/__snapshots__/input.test.js.snap @@ -1,67 +1,81 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Input component Should be disabled with placeholder and value 1`] = ` - + + + `; exports[`Input component Should be large and readOnly 1`] = ` - + + + `; exports[`Input component Should be rounded 1`] = ` - + + + `; exports[`Input component Should be type email and a with success colors 1`] = ` - + + + `; exports[`Input component Should concat classname in props with Bulma classname 1`] = ` - + + + `; exports[`Input component Should exist 1`] = `[Function]`; exports[`Input component Should have input classname 1`] = ` - + + + `; exports[`Input component Should support focus state 1`] = ` - + + + `; exports[`Input component Should support hovered state 1`] = ` - + + + `; exports[`Input component Should use inline styles 1`] = ` - + + + `; diff --git a/src/components/form/components/__test__/__snapshots__/label.test.js.snap b/src/components/form/components/__test__/__snapshots__/label.test.js.snap index 84dda3b4a..7bcf117b5 100644 --- a/src/components/form/components/__test__/__snapshots__/label.test.js.snap +++ b/src/components/form/components/__test__/__snapshots__/label.test.js.snap @@ -1,39 +1,41 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Label component Should concat classname in props with Bulma classname 1`] = ` - + + + `; exports[`Label component Should exist 1`] = `[Function]`; exports[`Label component Should have label classname 1`] = ` - + + + `; exports[`Label component Should use inline styles 1`] = ` - + + + `; diff --git a/src/components/form/components/__test__/__snapshots__/radio.test.js.snap b/src/components/form/components/__test__/__snapshots__/radio.test.js.snap index 20d55766b..27c5faf6c 100644 --- a/src/components/form/components/__test__/__snapshots__/radio.test.js.snap +++ b/src/components/form/components/__test__/__snapshots__/radio.test.js.snap @@ -1,73 +1,79 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Radio component Should be disabled, checked and with value 1`] = ` - + + + `; exports[`Radio component Should concat classname in props with Bulma classname 1`] = ` - + + + `; exports[`Radio component Should exist 1`] = `[Function]`; exports[`Radio component Should have radio classname 1`] = ` - + + + `; exports[`Radio component Should use inline styles 1`] = ` - + + + `; diff --git a/src/components/form/components/__test__/__snapshots__/select.test.js.snap b/src/components/form/components/__test__/__snapshots__/select.test.js.snap index f73c33c1f..e07c5d465 100644 --- a/src/components/form/components/__test__/__snapshots__/select.test.js.snap +++ b/src/components/form/components/__test__/__snapshots__/select.test.js.snap @@ -1,159 +1,171 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Select component Should be focused 1`] = ` -
        - -
        + +