├── .babelrc ├── .github ├── ISSUE_TEMPLATE │ ├── BUG_REPORT.yml │ └── FEATURE_REQUEST.yml ├── release-drafter-v0.x.yml ├── release-drafter.yml └── workflows │ ├── npm-publish.yml │ ├── release-drafter.yml │ ├── storybook.yml │ └── tests.yml ├── .gitignore ├── .npmignore ├── .prettierrc ├── .storybook ├── DocsPage.tsx ├── TableOfContent.tsx ├── doc-root.css ├── main.ts ├── manager-head.html └── preview.tsx ├── .vim └── coc-settings.json ├── .vscode ├── extensions.json ├── launch.json └── settings.json ├── .yarn ├── plugins │ └── @yarnpkg │ │ └── plugin-workspace-tools.cjs ├── releases │ └── yarn-4.5.1.cjs ├── sdks │ ├── eslint │ │ ├── bin │ │ │ └── eslint.js │ │ ├── lib │ │ │ ├── api.js │ │ │ ├── types │ │ │ │ ├── index.d.ts │ │ │ │ ├── rules │ │ │ │ │ └── index.d.ts │ │ │ │ ├── universal.d.ts │ │ │ │ └── use-at-your-own-risk.d.ts │ │ │ ├── universal.js │ │ │ └── unsupported-api.js │ │ └── package.json │ ├── integrations.yml │ ├── prettier │ │ ├── bin │ │ │ └── prettier.cjs │ │ ├── index.cjs │ │ └── package.json │ └── typescript │ │ ├── bin │ │ ├── tsc │ │ └── tsserver │ │ ├── lib │ │ ├── tsc.js │ │ ├── tsserver.js │ │ ├── tsserverlibrary.js │ │ └── typescript.js │ │ └── package.json └── versions │ └── 9085f262.yml ├── .yarnrc.yml ├── LICENSE ├── README.md ├── eslint.config.mjs ├── package.json ├── public ├── favicon.ico ├── faviconGlobe.ico ├── faviconReact.ico └── faviconTS.ico ├── src ├── __mocks__ │ └── fileMock.js ├── components │ ├── assets │ │ └── img │ │ │ ├── forbidden.png │ │ │ ├── logo.png │ │ │ ├── miniLogo.png │ │ │ └── notFound.png │ ├── buttons │ │ ├── BackToButton │ │ │ ├── BackToButton.test.tsx │ │ │ ├── BackToButton.tsx │ │ │ ├── index.ts │ │ │ └── types.ts │ │ ├── Button │ │ │ ├── Button.test.tsx │ │ │ ├── Button.tsx │ │ │ ├── ButtonStyles.ts │ │ │ ├── index.ts │ │ │ └── types.ts │ │ ├── IconButton │ │ │ ├── IconButton.test.tsx │ │ │ ├── IconButton.tsx │ │ │ ├── IconButtonStyles.ts │ │ │ ├── index.ts │ │ │ └── types.ts │ │ └── UploadButton │ │ │ ├── UploadButton.test.tsx │ │ │ ├── UploadButton.tsx │ │ │ ├── index.ts │ │ │ ├── types.ts │ │ │ └── uploadButtonValidators.ts │ ├── charts │ │ ├── DeprecatedChart │ │ │ ├── DeprecatedChart.tsx │ │ │ ├── index.ts │ │ │ └── types.ts │ │ └── DeprecatedStatsChart │ │ │ ├── DeprecatedStatsChart.tsx │ │ │ ├── DeprecatedStatsChartStyles.ts │ │ │ ├── index.ts │ │ │ └── types.ts │ ├── dataDisplay │ │ ├── ExpandingText │ │ │ ├── ExpandingText.test.tsx │ │ │ ├── ExpandingText.tsx │ │ │ ├── ExpandingTextStyles.ts │ │ │ ├── index.ts │ │ │ └── types.ts │ │ ├── FavIcon │ │ │ ├── FavIcon.tsx │ │ │ ├── index.ts │ │ │ └── types.ts │ │ ├── StatsChart │ │ │ ├── Chart.tsx │ │ │ ├── StatsChart.test.tsx │ │ │ ├── StatsChart.tsx │ │ │ ├── StatsChartStyles.ts │ │ │ ├── index.ts │ │ │ └── types.ts │ │ └── Typography │ │ │ ├── Typography.test.tsx │ │ │ ├── Typography.tsx │ │ │ ├── TypographyStyles.ts │ │ │ ├── index.ts │ │ │ └── types.ts │ ├── feedback │ │ ├── Dialog │ │ │ ├── Dialog.test.tsx │ │ │ ├── Dialog.tsx │ │ │ ├── DialogStyles.ts │ │ │ ├── index.ts │ │ │ └── types.ts │ │ ├── FakeText │ │ │ ├── FakeText.test.tsx │ │ │ ├── FakeText.tsx │ │ │ ├── index.ts │ │ │ └── types.ts │ │ ├── Forbidden │ │ │ ├── Forbidden.test.tsx │ │ │ ├── Forbidden.tsx │ │ │ ├── index.ts │ │ │ └── types.ts │ │ ├── LinearProgress │ │ │ ├── LinearProgress.test.tsx │ │ │ ├── LinearProgress.tsx │ │ │ ├── LinearProgressStyles.ts │ │ │ ├── index.ts │ │ │ └── types.ts │ │ ├── NotFound │ │ │ ├── NotFound.test.tsx │ │ │ ├── NotFound.tsx │ │ │ ├── NotFoundStyles.ts │ │ │ ├── index.ts │ │ │ └── types.ts │ │ └── Toast │ │ │ ├── Toast.test.tsx │ │ │ ├── ToastContainer.tsx │ │ │ ├── ToastStyles.ts │ │ │ ├── index.ts │ │ │ ├── types.ts │ │ │ ├── usePromiseToast.ts │ │ │ ├── useToast.tsx │ │ │ └── utils.tsx │ ├── index.ts │ ├── inputs │ │ ├── Autocomplete │ │ │ ├── Autocomplete.test.tsx │ │ │ ├── Autocomplete.tsx │ │ │ ├── Option.tsx │ │ │ ├── index.ts │ │ │ ├── types.ts │ │ │ └── utils.ts │ │ ├── DateTime │ │ │ ├── DateTime.test.tsx │ │ │ ├── DateTime.tsx │ │ │ ├── index.ts │ │ │ └── types.ts │ │ ├── DeprecatedAutocomplete │ │ │ ├── DeprecatedAutocomplete.test.tsx │ │ │ ├── DeprecatedAutocomplete.tsx │ │ │ ├── DeprecatedAutocompleteStyles.ts │ │ │ ├── Option.tsx │ │ │ ├── index.ts │ │ │ ├── types.ts │ │ │ └── utils.ts │ │ ├── DynamicField │ │ │ ├── DynamicField.test.tsx │ │ │ ├── DynamicField.tsx │ │ │ ├── index.ts │ │ │ └── types.ts │ │ ├── PasswordField │ │ │ ├── PasswordField.test.tsx │ │ │ ├── PasswordField.tsx │ │ │ └── index.ts │ │ ├── Slider │ │ │ ├── Slider.test.tsx │ │ │ ├── Slider.tsx │ │ │ ├── SliderStyles.ts │ │ │ ├── index.ts │ │ │ └── types.ts │ │ ├── Tags │ │ │ ├── DisplayTags.tsx │ │ │ ├── Tags.test.tsx │ │ │ ├── TagsInput.tsx │ │ │ ├── index.ts │ │ │ └── types.ts │ │ └── TextField │ │ │ ├── TextField.test.tsx │ │ │ ├── TextField.tsx │ │ │ ├── TextFieldStyles.ts │ │ │ ├── index.ts │ │ │ └── types.ts │ ├── navigation │ │ ├── NavPills │ │ │ ├── NavPills.test.tsx │ │ │ ├── NavPills.tsx │ │ │ ├── NavPillsStyles.ts │ │ │ ├── index.ts │ │ │ └── types.ts │ │ ├── Pagination │ │ │ ├── Pagination.test.tsx │ │ │ ├── Pagination.tsx │ │ │ ├── PaginationStyles.ts │ │ │ ├── index.ts │ │ │ └── types.ts │ │ └── SideMenu │ │ │ ├── SideMenu.test.tsx │ │ │ ├── SideMenu.tsx │ │ │ ├── SideMenuStyles.ts │ │ │ ├── index.ts │ │ │ └── types.ts │ ├── surfaces │ │ ├── Accordion │ │ │ ├── Accordion.test.tsx │ │ │ ├── Accordion.tsx │ │ │ ├── AccordionStyles.ts │ │ │ ├── index.ts │ │ │ └── types.ts │ │ ├── Card │ │ │ ├── Card.test.tsx │ │ │ ├── Card.tsx │ │ │ ├── CardActions │ │ │ │ ├── CardActions.test.tsx │ │ │ │ ├── CardActions.tsx │ │ │ │ ├── CardActionsStyles.ts │ │ │ │ └── index.ts │ │ │ ├── CardHeader │ │ │ │ ├── CardHeader.test.tsx │ │ │ │ ├── CardHeader.tsx │ │ │ │ ├── CardHeaderStyles.ts │ │ │ │ └── index.ts │ │ │ ├── CardStyles.ts │ │ │ ├── index.ts │ │ │ └── types.ts │ │ ├── CollapseCard │ │ │ ├── CollapseCard.test.tsx │ │ │ ├── CollapseCard.tsx │ │ │ ├── index.ts │ │ │ └── types.ts │ │ └── StatsCard │ │ │ ├── StatsCard.test.tsx │ │ │ ├── StatsCard.tsx │ │ │ ├── StatsCardStyles.ts │ │ │ ├── _mocks.ts │ │ │ ├── index.ts │ │ │ └── types.ts │ ├── themes │ │ ├── blueTheme.ts │ │ ├── common │ │ │ ├── overrides │ │ │ │ ├── Autocomplete.ts │ │ │ │ ├── Button.ts │ │ │ │ ├── Card.ts │ │ │ │ ├── Chip.ts │ │ │ │ ├── Divider.ts │ │ │ │ ├── TextField.ts │ │ │ │ └── index.ts │ │ │ ├── palette │ │ │ │ ├── basicColors.ts │ │ │ │ └── index.ts │ │ │ ├── shadows.ts │ │ │ ├── table.ts │ │ │ └── typography.ts │ │ ├── defaultTheme.ts │ │ ├── greenTheme.ts │ │ ├── index.ts │ │ ├── lightBlueTheme.ts │ │ ├── orangeTheme.ts │ │ ├── redTheme.ts │ │ ├── types.ts │ │ └── vividOrangeTheme.ts │ ├── types.ts │ └── utils │ │ ├── constants.ts │ │ └── useDebouncedCallback.ts ├── global.d.ts ├── setupTests.ts ├── stories │ ├── Introduction.stories.tsx │ ├── _introduction │ │ ├── about │ │ │ ├── AboutContainer.tsx │ │ │ └── AboutStyles.ts │ │ ├── constants │ │ │ └── orbits.ts │ │ └── orbits │ │ │ ├── OrbitContainer.tsx │ │ │ ├── OrbitStyles.ts │ │ │ └── OrbitSwitch.tsx │ ├── assets │ │ ├── audio │ │ │ └── rain-ambient.mp3 │ │ ├── img │ │ │ ├── robot.png │ │ │ ├── rocket.png │ │ │ ├── satellite.png │ │ │ └── spaceship.png │ │ └── storyImg │ │ │ ├── code-brackets.svg │ │ │ ├── colors.svg │ │ │ ├── comments.svg │ │ │ ├── direction.svg │ │ │ ├── flow.svg │ │ │ ├── plugin.svg │ │ │ ├── repo.svg │ │ │ └── stackalt.svg │ ├── buttons │ │ ├── BackToButton │ │ │ └── BackToButton.stories.tsx │ │ ├── Button │ │ │ ├── Button.stories.tsx │ │ │ ├── ColorsPreview.tsx │ │ │ ├── LoadingPreview.tsx │ │ │ ├── SizesPreview.tsx │ │ │ └── WithIconPreview.tsx │ │ ├── IconButton │ │ │ ├── ColorsPreview.tsx │ │ │ ├── IconButton.stories.tsx │ │ │ ├── LoadingPreview.tsx │ │ │ ├── SizesPreview.tsx │ │ │ └── TypesPreview.tsx │ │ └── UploadButton │ │ │ ├── CustomIconsPreview.tsx │ │ │ ├── IconPropsPreview.tsx │ │ │ ├── InputTypesPreview.tsx │ │ │ ├── MobileCapturePreview.tsx │ │ │ ├── MultipleSelectionPreview.tsx │ │ │ ├── SizesPreview.tsx │ │ │ └── UploadButton.stories.tsx │ ├── charts │ │ ├── DeprecatedChart │ │ │ ├── DeprecatedChart.stories.tsx │ │ │ └── _mocks.ts │ │ └── DeprecatedStatsChart │ │ │ ├── BarPreview.tsx │ │ │ ├── DeprecatedStatsChart.stories.tsx │ │ │ ├── LinePreview.tsx │ │ │ └── _mocks.ts │ ├── dataDisplay │ │ ├── ExpandingText │ │ │ ├── DisplayPreview.tsx │ │ │ └── ExpandingText.stories.tsx │ │ ├── FavIcon │ │ │ └── FavIcon.stories.tsx │ │ ├── StatsChart │ │ │ └── StatsChart.stories.tsx │ │ └── Typography │ │ │ ├── ColorsPreview.tsx │ │ │ ├── ExtraStylingPreview.tsx │ │ │ ├── Typography.stories.tsx │ │ │ └── VariantsPreview.tsx │ ├── feedback │ │ ├── Dialog │ │ │ ├── ActionsPreview.tsx │ │ │ ├── DefaultPreview.tsx │ │ │ ├── Dialog.stories.tsx │ │ │ └── _mocks.tsx │ │ ├── FakeText │ │ │ ├── AnimationsPreview.tsx │ │ │ ├── FakeText.stories.tsx │ │ │ └── VariantsPreview.tsx │ │ ├── Forbidden │ │ │ └── Forbidden.stories.tsx │ │ ├── LinearProgress │ │ │ ├── ColorsPreview.tsx │ │ │ ├── GlobalPreview.tsx │ │ │ ├── LinearProgress.stories.tsx │ │ │ └── VariantsPreview.tsx │ │ ├── NotFound │ │ │ └── NotFound.stories.tsx │ │ └── Toast │ │ │ ├── ActionsPreview.tsx │ │ │ ├── PositionsPreview.tsx │ │ │ ├── TextSizePreview.tsx │ │ │ ├── Toast.stories.tsx │ │ │ ├── TransitionsPreview.tsx │ │ │ └── VariantsPreview.tsx │ ├── inputs │ │ ├── Autocomplete │ │ │ ├── Autocomplete.stories.tsx │ │ │ ├── CreatablePreview.tsx │ │ │ ├── CustomOptionPreview.tsx │ │ │ ├── DefaultPreview.tsx │ │ │ ├── GroupedPreview.tsx │ │ │ ├── MultipleSelectionPreview.tsx │ │ │ ├── OptionTypesPreview.tsx │ │ │ ├── RequiredPreview.tsx │ │ │ ├── _mocks.ts │ │ │ └── components │ │ │ │ ├── ColumnHeader.tsx │ │ │ │ ├── ControlledCheckBox.tsx │ │ │ │ └── FormattedJson.tsx │ │ ├── DateTime │ │ │ ├── ClearablePreview.tsx │ │ │ ├── DateTime.stories.tsx │ │ │ ├── DisabledPreview.tsx │ │ │ ├── ErrorHelperTextPreview.tsx │ │ │ └── FormatPreview.tsx │ │ ├── DeprecatedAutocomplete │ │ │ ├── CheckboxesPreview.tsx │ │ │ ├── CreatablePreview.tsx │ │ │ ├── CustomOptionPreview.tsx │ │ │ ├── DefaultPreview.tsx │ │ │ ├── DeprecatedAutocomplete.stories.tsx │ │ │ ├── GroupedPreview.tsx │ │ │ ├── MultipleSelectionPreview.tsx │ │ │ ├── OptionTypesPreview.tsx │ │ │ ├── RequiredPreview.tsx │ │ │ ├── StylingPreview.tsx │ │ │ ├── _mocks.ts │ │ │ └── components │ │ │ │ ├── ColumnHeader.tsx │ │ │ │ ├── ControlledCheckBox.tsx │ │ │ │ └── FormattedJson.tsx │ │ ├── DynamicField │ │ │ ├── ControlPreview.tsx │ │ │ ├── DynamicControlPreview.tsx │ │ │ ├── DynamicField.stories.tsx │ │ │ ├── _hooks.ts │ │ │ └── _mocks.ts │ │ ├── PasswordField │ │ │ ├── PasswordField.stories.tsx │ │ │ ├── StatesPreview.tsx │ │ │ └── VariantsPreview.tsx │ │ ├── Slider │ │ │ └── Slider.stories.tsx │ │ ├── Tags │ │ │ ├── ColorsPreview.tsx │ │ │ ├── DefaultPreview.tsx │ │ │ ├── Tags.stories.tsx │ │ │ └── VariantsPreview.tsx │ │ └── TextField │ │ │ ├── ClearablePreview.tsx │ │ │ ├── FormPropsPreview.tsx │ │ │ ├── NumericPreview.tsx │ │ │ ├── StepperPreview.tsx │ │ │ ├── TextField.stories.tsx │ │ │ ├── ValidationPreview.tsx │ │ │ └── VariantsPreview.tsx │ ├── navigation │ │ ├── NavPills │ │ │ ├── ControlledPreview.tsx │ │ │ ├── FilledPreview.tsx │ │ │ ├── NavPills.stories.tsx │ │ │ ├── OrientationPreview.tsx │ │ │ ├── WithActionsPreview.tsx │ │ │ ├── WithIconsPreview.tsx │ │ │ └── _options.tsx │ │ ├── Pagination │ │ │ ├── DefaultPreview.tsx │ │ │ ├── Pagination.stories.tsx │ │ │ ├── WithFirstAndLastPreview.tsx │ │ │ └── WithNoCountPreview.tsx │ │ └── SideMenu │ │ │ ├── DefaultPreview.tsx │ │ │ └── SideMenu.stories.tsx │ └── surfaces │ │ ├── Accordion │ │ ├── Accordion.stories.tsx │ │ ├── ActionsPreview.tsx │ │ ├── ControlledPreview.tsx │ │ └── _mocks.tsx │ │ ├── Card │ │ ├── BasicCardsPreview.tsx │ │ ├── Card.stories.tsx │ │ ├── FilledPreview.tsx │ │ └── MediaPreview.tsx │ │ ├── CollapseCard │ │ ├── CollapseCard.stories.tsx │ │ ├── ControlledPreview.tsx │ │ └── FilledPreview.tsx │ │ └── StatsCard │ │ └── StatsCard.stories.tsx └── testingUtils │ ├── TestingWrapper.tsx │ ├── index.ts │ └── mocks.ts ├── tsconfig.build.json ├── tsconfig.json └── yarn.lock /.babelrc: -------------------------------------------------------------------------------- 1 | {"presets": ["@nrwl/js/babel"]} -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/FEATURE_REQUEST.yml: -------------------------------------------------------------------------------- 1 | name: Feature Request 🎇 2 | description: Suggest a new feature for Rocket-UI library. 3 | labels: [enhancement] 4 | body: 5 | - type: markdown 6 | attributes: 7 | value: | 8 | Thanks for contributing! 9 | - type: checkboxes 10 | attributes: 11 | label: Latest version 12 | description: We roll bug fixes, performance enhancements, and other improvements into new releases. 13 | options: 14 | - label: I have tested the latest version 15 | required: true 16 | - type: textarea 17 | id: feature-description 18 | attributes: 19 | label: Description 20 | description: Describe the new feature. How it should work. 21 | validations: 22 | required: true 23 | - type: textarea 24 | id: examples 25 | attributes: 26 | label: Examples 27 | description: Provide screenshots, examples of the expected behavior. 28 | -------------------------------------------------------------------------------- /.github/release-drafter-v0.x.yml: -------------------------------------------------------------------------------- 1 | name-template: v$NEXT_PATCH_VERSION 2 | tag-template: v$NEXT_PATCH_VERSION 3 | categories: 4 | - title: 🚀 Features 5 | label: feature 6 | - title: 🐛 Bug Fixes 7 | label: fix 8 | - title: 🛠️ Maintenance 9 | label: chore 10 | change-template: '- $TITLE @$AUTHOR (#$NUMBER)' 11 | commitish: 'support/0.x' 12 | filter-by-commitish: true 13 | template: | 14 | ## Changes 15 | $CHANGES 16 | -------------------------------------------------------------------------------- /.github/release-drafter.yml: -------------------------------------------------------------------------------- 1 | name-template: v$NEXT_PATCH_VERSION 2 | tag-template: v$NEXT_PATCH_VERSION 3 | categories: 4 | - title: 🚀 Features 5 | label: feature 6 | - title: 🐛 Bug Fixes 7 | label: fix 8 | - title: 🛠️ Maintenance 9 | label: chore 10 | change-template: '- $TITLE @$AUTHOR (#$NUMBER)' 11 | template: | 12 | ## Changes 13 | $CHANGES -------------------------------------------------------------------------------- /.github/workflows/npm-publish.yml: -------------------------------------------------------------------------------- 1 | # This workflow will run tests using node and then publish a package to NPM when a release is created 2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/publishing-nodejs-packages 3 | 4 | name: npm-publish 5 | 6 | on: 7 | release: 8 | types: [published] 9 | 10 | concurrency: 11 | group: build-test-publish 12 | 13 | jobs: 14 | build-n-publish: 15 | runs-on: ubuntu-latest 16 | steps: 17 | - name: Checkout Repo 18 | uses: actions/checkout@master 19 | with: 20 | fetch-depth: 0 21 | - uses: actions/setup-node@v3 22 | with: 23 | node-version: 18.x 24 | registry-url: https://registry.npmjs.org/ 25 | scope: '@totalsoft' 26 | - run: yarn -v 27 | - name: Install Dependencies 28 | run: yarn install 29 | - name: Build 30 | run: yarn build 31 | - name: Bump version 32 | run: yarn run version 33 | - name: Set npm authToken from env 34 | env: 35 | NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} 36 | run: | 37 | yarn config && 38 | yarn config set npmScopes.totalsoft.npmRegistryServer "https://registry.npmjs.org/" && 39 | yarn config set npmScopes.totalsoft.npmAlwaysAuth true && 40 | yarn config set npmScopes.totalsoft.npmAuthToken $NODE_AUTH_TOKEN 41 | - run: yarn publish 42 | -------------------------------------------------------------------------------- /.github/workflows/release-drafter.yml: -------------------------------------------------------------------------------- 1 | name: Release Drafter 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | workflow_dispatch: 8 | inputs: 9 | 10 | jobs: 11 | update_release_draft: 12 | runs-on: ubuntu-latest 13 | steps: 14 | # Drafts your next Release notes as Pull Requests are merged into "master" 15 | - uses: release-drafter/release-drafter@v5 16 | env: 17 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 18 | -------------------------------------------------------------------------------- /.github/workflows/storybook.yml: -------------------------------------------------------------------------------- 1 | # Copyright (c) TotalSoft. 2 | # This source code is licensed under the MIT license. 3 | 4 | name: Build and Deploy Storybook 5 | on: 6 | push: 7 | branches: 8 | - master 9 | paths: ['src/stories/**', 'src/components/**'] # Trigger the action only when files change in the folders defined here 10 | workflow_dispatch: 11 | permissions: 12 | contents: write 13 | jobs: 14 | storybook-build-and-deploy: 15 | runs-on: ubuntu-latest 16 | steps: 17 | - name: Checkout 🛎️ 18 | uses: actions/checkout@v3 19 | with: 20 | persist-credentials: false 21 | - name: Install 🔧 22 | run: yarn install 23 | - name: Run tests ⚠️ 24 | run: yarn test 25 | - name: Build 🔧 26 | run: yarn run build-storybook 27 | - name: Deploy 🚀 28 | uses: JamesIves/github-pages-deploy-action@3.6.2 29 | with: 30 | GITHUB_TOKEN: ${{ secrets.STORYBOOK_TOKEN }} 31 | BRANCH: gh-pages 32 | FOLDER: storybuild # The folder that the build-storybook script generates files. 33 | CLEAN: true # Automatically remove deleted files from the deploy branch 34 | -------------------------------------------------------------------------------- /.github/workflows/tests.yml: -------------------------------------------------------------------------------- 1 | # This workflow will run tests using node and then publish a package to NPM when a release is created 2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/publishing-nodejs-packages 3 | 4 | name: run-tests 5 | 6 | on: 7 | pull_request: 8 | branches: [master] 9 | 10 | concurrency: 11 | group: build-test-publish 12 | 13 | jobs: 14 | release: 15 | runs-on: ubuntu-latest 16 | steps: 17 | - name: Checkout Repo 18 | uses: actions/checkout@master 19 | - name: Set Node.js 18.x 20 | uses: actions/setup-node@v3 21 | with: 22 | node-version: 18.x 23 | - name: Install Dependencies 24 | run: yarn install 25 | - name: Run tests 26 | run: yarn test 27 | - name: Run build test 28 | run: yarn run build-test 29 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .pnp.* 2 | .yarn/* 3 | !.yarn/patches 4 | !.yarn/plugins 5 | !.yarn/releases 6 | !.yarn/sdks 7 | !.yarn/versions 8 | 9 | **/node_modules 10 | **/package-lock.json 11 | 12 | # Swap the comments on the following lines if you don't wish to use zero-installs 13 | # Documentation here: https://yarnpkg.com/features/zero-installs 14 | .yarn/cache 15 | .pnp.* 16 | **/dist 17 | **/coverage 18 | totalsoft-rocket-ui-*.tgz -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | coverage 3 | tsconfig.json 4 | tsconfig.build.json 5 | .storybook 6 | .github 7 | __tests__ 8 | __mocks__ 9 | .babelrc 10 | eslint.config.mjs 11 | .gitignore 12 | .yarn 13 | .vscode 14 | .vim 15 | public 16 | .prettierrc 17 | src/testingUtils 18 | src/stories -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 125, 3 | "tabWidth": 2, 4 | "singleQuote": true, 5 | "semi": false, 6 | "trailingComma": "none", 7 | "arrowParens": "avoid" 8 | } 9 | -------------------------------------------------------------------------------- /.storybook/DocsPage.tsx: -------------------------------------------------------------------------------- 1 | // Copyright (c) TotalSoft. 2 | // This source code is licensed under the MIT license. 3 | import * as React from 'react' 4 | import { Controls, Description, DocsContext, Primary, Stories, Subtitle, Title } from '@storybook/blocks' 5 | import { makeStyles } from 'tss-react/mui' 6 | import { TableOfContent } from './TableOfContent' 7 | 8 | const useStyles = makeStyles()({ 9 | wrapper: { 10 | display: 'flex' 11 | }, 12 | toc: { 13 | flexBasis: '200px', 14 | flexShrink: 0, 15 | ['@media screen and (max-width: 1300px)']: { 16 | display: 'none' 17 | } 18 | }, 19 | container: { 20 | width: '200px', 21 | flexGrow: 1 22 | } 23 | }) 24 | 25 | export const DocsPage = () => { 26 | const context = React.useContext(DocsContext) 27 | const stories = context.componentStories() 28 | const { classes } = useStyles() 29 | 30 | return ( 31 | <> 32 | 33 | <div className={classes.wrapper}> 34 | <div className={classes.container}> 35 | <Subtitle /> 36 | <Description /> 37 | <Primary /> 38 | <Controls /> 39 | <Stories /> 40 | </div> 41 | <div className={classes.toc}> 42 | <TableOfContent stories={stories} /> 43 | </div> 44 | </div> 45 | </> 46 | ) 47 | } 48 | -------------------------------------------------------------------------------- /.storybook/doc-root.css: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) TotalSoft. 3 | * This source code is licensed under the MIT license. 4 | */ 5 | .sbdocs .sbdocs-content { 6 | max-width: 1300px; 7 | } 8 | -------------------------------------------------------------------------------- /.storybook/main.ts: -------------------------------------------------------------------------------- 1 | import { dirname, join } from 'path' 2 | import type { StorybookConfig } from '@storybook/react-webpack5' 3 | import TsconfigPathsPlugin from 'tsconfig-paths-webpack-plugin' 4 | 5 | const config: StorybookConfig = { 6 | stories: ['../src/**/*.stories.@(js|jsx|ts|tsx)'], 7 | addons: [ 8 | getAbsolutePath('@storybook/addon-essentials'), 9 | getAbsolutePath('@storybook/addon-links'), 10 | getAbsolutePath('@storybook/addon-interactions'), 11 | getAbsolutePath('@storybook/preview-api'), 12 | getAbsolutePath('@storybook/addon-webpack5-compiler-swc') 13 | ], 14 | staticDirs: ['../public'], 15 | framework: { 16 | name: getAbsolutePath('@storybook/react-webpack5'), 17 | options: {} 18 | }, 19 | core: { 20 | builder: getAbsolutePath('@storybook/builder-webpack5') 21 | }, 22 | typescript: { 23 | reactDocgen: 'react-docgen', 24 | check: false 25 | }, 26 | webpackFinal: async (config: any) => { 27 | config.resolve.plugins = [new TsconfigPathsPlugin()] 28 | return config 29 | } 30 | } 31 | export default config 32 | 33 | function getAbsolutePath(value: string): any { 34 | return dirname(require.resolve(join(value, 'package.json'))) 35 | } 36 | -------------------------------------------------------------------------------- /.storybook/manager-head.html: -------------------------------------------------------------------------------- 1 | <!-- 2 | Copyright (c) TotalSoft. 3 | This source code is licensed under the MIT license. 4 | --> 5 | 6 | <link rel="shortcut icon" id="favicon" href="/favicon.ico"> -------------------------------------------------------------------------------- /.storybook/preview.tsx: -------------------------------------------------------------------------------- 1 | import './doc-root.css' 2 | import React from 'react' 3 | import type { Preview } from '@storybook/react' 4 | import { ThemeProvider } from '@mui/material/styles' 5 | import { ToastContainer } from '../src/components/feedback/Toast' 6 | import getTheme from '../src/components/themes/index' 7 | import { DocsPage } from './DocsPage' 8 | 9 | const withThemeProvider = (Story, context) => { 10 | const theme = getTheme(context) 11 | return ( 12 | <ThemeProvider theme={theme}> 13 | <ToastContainer /> 14 | <Story /> 15 | </ThemeProvider> 16 | ) 17 | } 18 | 19 | const preview: Preview = { 20 | parameters: { 21 | controls: { 22 | expanded: true 23 | }, 24 | docs: { 25 | page: DocsPage, 26 | source: { 27 | language: 'tsx', 28 | excludeDecorators: true 29 | } 30 | } 31 | }, 32 | globalTypes: { 33 | theme: { 34 | name: 'Theme', 35 | description: 'Global theme for components', 36 | defaultValue: 'default', 37 | toolbar: { 38 | icon: 'circlehollow', 39 | items: ['default', 'green', 'blue', 'orange', 'red', 'vividOrange', 'lightBlue'], 40 | title: 'Theme', 41 | dynamicTitle: true 42 | } 43 | } 44 | }, 45 | decorators: [withThemeProvider], 46 | tags: ['autodocs'] 47 | } 48 | 49 | export default preview 50 | -------------------------------------------------------------------------------- /.vim/coc-settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "eslint.packageManager": "yarn", 3 | "eslint.nodePath": ".yarn/sdks", 4 | "workspace.workspaceFolderCheckCwd": false, 5 | "tsserver.tsdk": ".yarn/sdks/typescript/lib" 6 | } 7 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "arcanis.vscode-zipfs", 4 | "dbaeumer.vscode-eslint", 5 | "esbenp.prettier-vscode" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "configurations": [ 3 | { 4 | "name": "Storybook Debug", 5 | "type": "node-terminal", 6 | "request": "launch", 7 | "command": "yarn storybook", 8 | "internalConsoleOptions": "openOnFirstSessionStart", 9 | "serverReadyAction": { 10 | "pattern": "Local:.+(https?://[^:]+:[0-9]+)", 11 | "uriFormat": "%s", 12 | "action": "debugWithChrome" 13 | } 14 | }, 15 | { 16 | "type": "node", 17 | "name": "vscode-jest-tests", 18 | "request": "launch", 19 | "runtimeExecutable": "yarn", 20 | "runtimeArgs": ["run", "test"], 21 | "args": ["--runInBand"], 22 | "cwd": "${workspaceFolder}", 23 | "console": "integratedTerminal", 24 | "internalConsoleOptions": "neverOpen" 25 | }, 26 | { 27 | "type": "node", 28 | "name": "Jest current file", 29 | "request": "launch", 30 | "runtimeExecutable": "yarn", 31 | "runtimeArgs": ["run", "test"], 32 | "args": ["--verbose", "-i", "--no-cache", "--testPathPattern", "/${fileBasename}"], 33 | "cwd": "${fileDirname}", 34 | "console": "integratedTerminal", 35 | "internalConsoleOptions": "neverOpen" 36 | } 37 | ] 38 | } 39 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "search.exclude": { 3 | "**/.yarn": true, 4 | "**/.pnp.*": true 5 | }, 6 | "prettier.prettierPath": ".yarn/sdks/prettier/index.cjs", 7 | "editor.defaultFormatter": "esbenp.prettier-vscode", 8 | "eslint.nodePath": ".yarn/sdks/eslint", 9 | "eslint.useFlatConfig": true, 10 | "typescript.tsdk": ".yarn/sdks/typescript/lib", 11 | "typescript.enablePromptUseWorkspaceTsdk": true, 12 | "typescript.updateImportsOnFileMove.enabled": "always", 13 | "typescript.tsserver.log": "verbose", 14 | "npm.packageManager": "yarn", 15 | "cSpell.words": [ 16 | "autodocs", 17 | "commitish", 18 | "copyfiles", 19 | "rsbuild", 20 | "storybuild", 21 | "Toastify", 22 | "Totalsoft", 23 | "uuidv" 24 | ], 25 | "licenser.license": "Custom", 26 | "licenser.author": "TotalSoft", 27 | "licenser.customHeader": "Copyright (c) @AUTHOR@.\nThis source code is licensed under the MIT license." 28 | } 29 | -------------------------------------------------------------------------------- /.yarn/sdks/eslint/bin/eslint.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const {existsSync} = require(`fs`); 4 | const {createRequire, register} = require(`module`); 5 | const {resolve} = require(`path`); 6 | const {pathToFileURL} = require(`url`); 7 | 8 | const relPnpApiPath = "../../../../.pnp.cjs"; 9 | 10 | const absPnpApiPath = resolve(__dirname, relPnpApiPath); 11 | const absUserWrapperPath = resolve(__dirname, `./sdk.user.cjs`); 12 | const absRequire = createRequire(absPnpApiPath); 13 | 14 | const absPnpLoaderPath = resolve(absPnpApiPath, `../.pnp.loader.mjs`); 15 | const isPnpLoaderEnabled = existsSync(absPnpLoaderPath); 16 | 17 | if (existsSync(absPnpApiPath)) { 18 | if (!process.versions.pnp) { 19 | // Setup the environment to be able to require eslint/bin/eslint.js 20 | require(absPnpApiPath).setup(); 21 | if (isPnpLoaderEnabled && register) { 22 | register(pathToFileURL(absPnpLoaderPath)); 23 | } 24 | } 25 | } 26 | 27 | const wrapWithUserWrapper = existsSync(absUserWrapperPath) 28 | ? exports => absRequire(absUserWrapperPath)(exports) 29 | : exports => exports; 30 | 31 | // Defer to the real eslint/bin/eslint.js your application uses 32 | module.exports = wrapWithUserWrapper(absRequire(`eslint/bin/eslint.js`)); 33 | -------------------------------------------------------------------------------- /.yarn/sdks/eslint/lib/api.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const {existsSync} = require(`fs`); 4 | const {createRequire, register} = require(`module`); 5 | const {resolve} = require(`path`); 6 | const {pathToFileURL} = require(`url`); 7 | 8 | const relPnpApiPath = "../../../../.pnp.cjs"; 9 | 10 | const absPnpApiPath = resolve(__dirname, relPnpApiPath); 11 | const absUserWrapperPath = resolve(__dirname, `./sdk.user.cjs`); 12 | const absRequire = createRequire(absPnpApiPath); 13 | 14 | const absPnpLoaderPath = resolve(absPnpApiPath, `../.pnp.loader.mjs`); 15 | const isPnpLoaderEnabled = existsSync(absPnpLoaderPath); 16 | 17 | if (existsSync(absPnpApiPath)) { 18 | if (!process.versions.pnp) { 19 | // Setup the environment to be able to require eslint 20 | require(absPnpApiPath).setup(); 21 | if (isPnpLoaderEnabled && register) { 22 | register(pathToFileURL(absPnpLoaderPath)); 23 | } 24 | } 25 | } 26 | 27 | const wrapWithUserWrapper = existsSync(absUserWrapperPath) 28 | ? exports => absRequire(absUserWrapperPath)(exports) 29 | : exports => exports; 30 | 31 | // Defer to the real eslint your application uses 32 | module.exports = wrapWithUserWrapper(absRequire(`eslint`)); 33 | -------------------------------------------------------------------------------- /.yarn/sdks/eslint/lib/types/index.d.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const {existsSync} = require(`fs`); 4 | const {createRequire, register} = require(`module`); 5 | const {resolve} = require(`path`); 6 | const {pathToFileURL} = require(`url`); 7 | 8 | const relPnpApiPath = "../../../../../.pnp.cjs"; 9 | 10 | const absPnpApiPath = resolve(__dirname, relPnpApiPath); 11 | const absUserWrapperPath = resolve(__dirname, `./sdk.user.cjs`); 12 | const absRequire = createRequire(absPnpApiPath); 13 | 14 | const absPnpLoaderPath = resolve(absPnpApiPath, `../.pnp.loader.mjs`); 15 | const isPnpLoaderEnabled = existsSync(absPnpLoaderPath); 16 | 17 | if (existsSync(absPnpApiPath)) { 18 | if (!process.versions.pnp) { 19 | // Setup the environment to be able to require eslint 20 | require(absPnpApiPath).setup(); 21 | if (isPnpLoaderEnabled && register) { 22 | register(pathToFileURL(absPnpLoaderPath)); 23 | } 24 | } 25 | } 26 | 27 | const wrapWithUserWrapper = existsSync(absUserWrapperPath) 28 | ? exports => absRequire(absUserWrapperPath)(exports) 29 | : exports => exports; 30 | 31 | // Defer to the real eslint your application uses 32 | module.exports = wrapWithUserWrapper(absRequire(`eslint`)); 33 | -------------------------------------------------------------------------------- /.yarn/sdks/eslint/lib/types/rules/index.d.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const {existsSync} = require(`fs`); 4 | const {createRequire, register} = require(`module`); 5 | const {resolve} = require(`path`); 6 | const {pathToFileURL} = require(`url`); 7 | 8 | const relPnpApiPath = "../../../../../../.pnp.cjs"; 9 | 10 | const absPnpApiPath = resolve(__dirname, relPnpApiPath); 11 | const absUserWrapperPath = resolve(__dirname, `./sdk.user.cjs`); 12 | const absRequire = createRequire(absPnpApiPath); 13 | 14 | const absPnpLoaderPath = resolve(absPnpApiPath, `../.pnp.loader.mjs`); 15 | const isPnpLoaderEnabled = existsSync(absPnpLoaderPath); 16 | 17 | if (existsSync(absPnpApiPath)) { 18 | if (!process.versions.pnp) { 19 | // Setup the environment to be able to require eslint/rules 20 | require(absPnpApiPath).setup(); 21 | if (isPnpLoaderEnabled && register) { 22 | register(pathToFileURL(absPnpLoaderPath)); 23 | } 24 | } 25 | } 26 | 27 | const wrapWithUserWrapper = existsSync(absUserWrapperPath) 28 | ? exports => absRequire(absUserWrapperPath)(exports) 29 | : exports => exports; 30 | 31 | // Defer to the real eslint/rules your application uses 32 | module.exports = wrapWithUserWrapper(absRequire(`eslint/rules`)); 33 | -------------------------------------------------------------------------------- /.yarn/sdks/eslint/lib/types/universal.d.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const {existsSync} = require(`fs`); 4 | const {createRequire, register} = require(`module`); 5 | const {resolve} = require(`path`); 6 | const {pathToFileURL} = require(`url`); 7 | 8 | const relPnpApiPath = "../../../../../.pnp.cjs"; 9 | 10 | const absPnpApiPath = resolve(__dirname, relPnpApiPath); 11 | const absUserWrapperPath = resolve(__dirname, `./sdk.user.cjs`); 12 | const absRequire = createRequire(absPnpApiPath); 13 | 14 | const absPnpLoaderPath = resolve(absPnpApiPath, `../.pnp.loader.mjs`); 15 | const isPnpLoaderEnabled = existsSync(absPnpLoaderPath); 16 | 17 | if (existsSync(absPnpApiPath)) { 18 | if (!process.versions.pnp) { 19 | // Setup the environment to be able to require eslint/universal 20 | require(absPnpApiPath).setup(); 21 | if (isPnpLoaderEnabled && register) { 22 | register(pathToFileURL(absPnpLoaderPath)); 23 | } 24 | } 25 | } 26 | 27 | const wrapWithUserWrapper = existsSync(absUserWrapperPath) 28 | ? exports => absRequire(absUserWrapperPath)(exports) 29 | : exports => exports; 30 | 31 | // Defer to the real eslint/universal your application uses 32 | module.exports = wrapWithUserWrapper(absRequire(`eslint/universal`)); 33 | -------------------------------------------------------------------------------- /.yarn/sdks/eslint/lib/types/use-at-your-own-risk.d.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const {existsSync} = require(`fs`); 4 | const {createRequire, register} = require(`module`); 5 | const {resolve} = require(`path`); 6 | const {pathToFileURL} = require(`url`); 7 | 8 | const relPnpApiPath = "../../../../../.pnp.cjs"; 9 | 10 | const absPnpApiPath = resolve(__dirname, relPnpApiPath); 11 | const absUserWrapperPath = resolve(__dirname, `./sdk.user.cjs`); 12 | const absRequire = createRequire(absPnpApiPath); 13 | 14 | const absPnpLoaderPath = resolve(absPnpApiPath, `../.pnp.loader.mjs`); 15 | const isPnpLoaderEnabled = existsSync(absPnpLoaderPath); 16 | 17 | if (existsSync(absPnpApiPath)) { 18 | if (!process.versions.pnp) { 19 | // Setup the environment to be able to require eslint/use-at-your-own-risk 20 | require(absPnpApiPath).setup(); 21 | if (isPnpLoaderEnabled && register) { 22 | register(pathToFileURL(absPnpLoaderPath)); 23 | } 24 | } 25 | } 26 | 27 | const wrapWithUserWrapper = existsSync(absUserWrapperPath) 28 | ? exports => absRequire(absUserWrapperPath)(exports) 29 | : exports => exports; 30 | 31 | // Defer to the real eslint/use-at-your-own-risk your application uses 32 | module.exports = wrapWithUserWrapper(absRequire(`eslint/use-at-your-own-risk`)); 33 | -------------------------------------------------------------------------------- /.yarn/sdks/eslint/lib/universal.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const {existsSync} = require(`fs`); 4 | const {createRequire, register} = require(`module`); 5 | const {resolve} = require(`path`); 6 | const {pathToFileURL} = require(`url`); 7 | 8 | const relPnpApiPath = "../../../../.pnp.cjs"; 9 | 10 | const absPnpApiPath = resolve(__dirname, relPnpApiPath); 11 | const absUserWrapperPath = resolve(__dirname, `./sdk.user.cjs`); 12 | const absRequire = createRequire(absPnpApiPath); 13 | 14 | const absPnpLoaderPath = resolve(absPnpApiPath, `../.pnp.loader.mjs`); 15 | const isPnpLoaderEnabled = existsSync(absPnpLoaderPath); 16 | 17 | if (existsSync(absPnpApiPath)) { 18 | if (!process.versions.pnp) { 19 | // Setup the environment to be able to require eslint/universal 20 | require(absPnpApiPath).setup(); 21 | if (isPnpLoaderEnabled && register) { 22 | register(pathToFileURL(absPnpLoaderPath)); 23 | } 24 | } 25 | } 26 | 27 | const wrapWithUserWrapper = existsSync(absUserWrapperPath) 28 | ? exports => absRequire(absUserWrapperPath)(exports) 29 | : exports => exports; 30 | 31 | // Defer to the real eslint/universal your application uses 32 | module.exports = wrapWithUserWrapper(absRequire(`eslint/universal`)); 33 | -------------------------------------------------------------------------------- /.yarn/sdks/eslint/lib/unsupported-api.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const {existsSync} = require(`fs`); 4 | const {createRequire, register} = require(`module`); 5 | const {resolve} = require(`path`); 6 | const {pathToFileURL} = require(`url`); 7 | 8 | const relPnpApiPath = "../../../../.pnp.cjs"; 9 | 10 | const absPnpApiPath = resolve(__dirname, relPnpApiPath); 11 | const absUserWrapperPath = resolve(__dirname, `./sdk.user.cjs`); 12 | const absRequire = createRequire(absPnpApiPath); 13 | 14 | const absPnpLoaderPath = resolve(absPnpApiPath, `../.pnp.loader.mjs`); 15 | const isPnpLoaderEnabled = existsSync(absPnpLoaderPath); 16 | 17 | if (existsSync(absPnpApiPath)) { 18 | if (!process.versions.pnp) { 19 | // Setup the environment to be able to require eslint/use-at-your-own-risk 20 | require(absPnpApiPath).setup(); 21 | if (isPnpLoaderEnabled && register) { 22 | register(pathToFileURL(absPnpLoaderPath)); 23 | } 24 | } 25 | } 26 | 27 | const wrapWithUserWrapper = existsSync(absUserWrapperPath) 28 | ? exports => absRequire(absUserWrapperPath)(exports) 29 | : exports => exports; 30 | 31 | // Defer to the real eslint/use-at-your-own-risk your application uses 32 | module.exports = wrapWithUserWrapper(absRequire(`eslint/use-at-your-own-risk`)); 33 | -------------------------------------------------------------------------------- /.yarn/sdks/eslint/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "eslint", 3 | "version": "9.14.0-sdk", 4 | "main": "./lib/api.js", 5 | "type": "commonjs", 6 | "bin": { 7 | "eslint": "./bin/eslint.js" 8 | }, 9 | "exports": { 10 | ".": { 11 | "types": "./lib/types/index.d.ts", 12 | "default": "./lib/api.js" 13 | }, 14 | "./package.json": "./package.json", 15 | "./use-at-your-own-risk": { 16 | "types": "./lib/types/use-at-your-own-risk.d.ts", 17 | "default": "./lib/unsupported-api.js" 18 | }, 19 | "./rules": { 20 | "types": "./lib/types/rules/index.d.ts" 21 | }, 22 | "./universal": { 23 | "types": "./lib/types/universal.d.ts", 24 | "default": "./lib/universal.js" 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /.yarn/sdks/integrations.yml: -------------------------------------------------------------------------------- 1 | # This file is automatically generated by @yarnpkg/sdks. 2 | # Manual changes might be lost! 3 | 4 | integrations: 5 | - vim 6 | - vscode 7 | -------------------------------------------------------------------------------- /.yarn/sdks/prettier/bin/prettier.cjs: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const {existsSync} = require(`fs`); 4 | const {createRequire, register} = require(`module`); 5 | const {resolve} = require(`path`); 6 | const {pathToFileURL} = require(`url`); 7 | 8 | const relPnpApiPath = "../../../../.pnp.cjs"; 9 | 10 | const absPnpApiPath = resolve(__dirname, relPnpApiPath); 11 | const absUserWrapperPath = resolve(__dirname, `./sdk.user.cjs`); 12 | const absRequire = createRequire(absPnpApiPath); 13 | 14 | const absPnpLoaderPath = resolve(absPnpApiPath, `../.pnp.loader.mjs`); 15 | const isPnpLoaderEnabled = existsSync(absPnpLoaderPath); 16 | 17 | if (existsSync(absPnpApiPath)) { 18 | if (!process.versions.pnp) { 19 | // Setup the environment to be able to require prettier/bin/prettier.cjs 20 | require(absPnpApiPath).setup(); 21 | if (isPnpLoaderEnabled && register) { 22 | register(pathToFileURL(absPnpLoaderPath)); 23 | } 24 | } 25 | } 26 | 27 | const wrapWithUserWrapper = existsSync(absUserWrapperPath) 28 | ? exports => absRequire(absUserWrapperPath)(exports) 29 | : exports => exports; 30 | 31 | // Defer to the real prettier/bin/prettier.cjs your application uses 32 | module.exports = wrapWithUserWrapper(absRequire(`prettier/bin/prettier.cjs`)); 33 | -------------------------------------------------------------------------------- /.yarn/sdks/prettier/index.cjs: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const {existsSync} = require(`fs`); 4 | const {createRequire, register} = require(`module`); 5 | const {resolve} = require(`path`); 6 | const {pathToFileURL} = require(`url`); 7 | 8 | const relPnpApiPath = "../../../.pnp.cjs"; 9 | 10 | const absPnpApiPath = resolve(__dirname, relPnpApiPath); 11 | const absUserWrapperPath = resolve(__dirname, `./sdk.user.cjs`); 12 | const absRequire = createRequire(absPnpApiPath); 13 | 14 | const absPnpLoaderPath = resolve(absPnpApiPath, `../.pnp.loader.mjs`); 15 | const isPnpLoaderEnabled = existsSync(absPnpLoaderPath); 16 | 17 | if (existsSync(absPnpApiPath)) { 18 | if (!process.versions.pnp) { 19 | // Setup the environment to be able to require prettier 20 | require(absPnpApiPath).setup(); 21 | if (isPnpLoaderEnabled && register) { 22 | register(pathToFileURL(absPnpLoaderPath)); 23 | } 24 | } 25 | } 26 | 27 | const wrapWithUserWrapper = existsSync(absUserWrapperPath) 28 | ? exports => absRequire(absUserWrapperPath)(exports) 29 | : exports => exports; 30 | 31 | // Defer to the real prettier your application uses 32 | module.exports = wrapWithUserWrapper(absRequire(`prettier`)); 33 | -------------------------------------------------------------------------------- /.yarn/sdks/prettier/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "prettier", 3 | "version": "3.3.3-sdk", 4 | "main": "./index.cjs", 5 | "type": "commonjs", 6 | "bin": "./bin/prettier.cjs" 7 | } 8 | -------------------------------------------------------------------------------- /.yarn/sdks/typescript/bin/tsc: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const {existsSync} = require(`fs`); 4 | const {createRequire, register} = require(`module`); 5 | const {resolve} = require(`path`); 6 | const {pathToFileURL} = require(`url`); 7 | 8 | const relPnpApiPath = "../../../../.pnp.cjs"; 9 | 10 | const absPnpApiPath = resolve(__dirname, relPnpApiPath); 11 | const absUserWrapperPath = resolve(__dirname, `./sdk.user.cjs`); 12 | const absRequire = createRequire(absPnpApiPath); 13 | 14 | const absPnpLoaderPath = resolve(absPnpApiPath, `../.pnp.loader.mjs`); 15 | const isPnpLoaderEnabled = existsSync(absPnpLoaderPath); 16 | 17 | if (existsSync(absPnpApiPath)) { 18 | if (!process.versions.pnp) { 19 | // Setup the environment to be able to require typescript/bin/tsc 20 | require(absPnpApiPath).setup(); 21 | if (isPnpLoaderEnabled && register) { 22 | register(pathToFileURL(absPnpLoaderPath)); 23 | } 24 | } 25 | } 26 | 27 | const wrapWithUserWrapper = existsSync(absUserWrapperPath) 28 | ? exports => absRequire(absUserWrapperPath)(exports) 29 | : exports => exports; 30 | 31 | // Defer to the real typescript/bin/tsc your application uses 32 | module.exports = wrapWithUserWrapper(absRequire(`typescript/bin/tsc`)); 33 | -------------------------------------------------------------------------------- /.yarn/sdks/typescript/bin/tsserver: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const {existsSync} = require(`fs`); 4 | const {createRequire, register} = require(`module`); 5 | const {resolve} = require(`path`); 6 | const {pathToFileURL} = require(`url`); 7 | 8 | const relPnpApiPath = "../../../../.pnp.cjs"; 9 | 10 | const absPnpApiPath = resolve(__dirname, relPnpApiPath); 11 | const absUserWrapperPath = resolve(__dirname, `./sdk.user.cjs`); 12 | const absRequire = createRequire(absPnpApiPath); 13 | 14 | const absPnpLoaderPath = resolve(absPnpApiPath, `../.pnp.loader.mjs`); 15 | const isPnpLoaderEnabled = existsSync(absPnpLoaderPath); 16 | 17 | if (existsSync(absPnpApiPath)) { 18 | if (!process.versions.pnp) { 19 | // Setup the environment to be able to require typescript/bin/tsserver 20 | require(absPnpApiPath).setup(); 21 | if (isPnpLoaderEnabled && register) { 22 | register(pathToFileURL(absPnpLoaderPath)); 23 | } 24 | } 25 | } 26 | 27 | const wrapWithUserWrapper = existsSync(absUserWrapperPath) 28 | ? exports => absRequire(absUserWrapperPath)(exports) 29 | : exports => exports; 30 | 31 | // Defer to the real typescript/bin/tsserver your application uses 32 | module.exports = wrapWithUserWrapper(absRequire(`typescript/bin/tsserver`)); 33 | -------------------------------------------------------------------------------- /.yarn/sdks/typescript/lib/tsc.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const {existsSync} = require(`fs`); 4 | const {createRequire, register} = require(`module`); 5 | const {resolve} = require(`path`); 6 | const {pathToFileURL} = require(`url`); 7 | 8 | const relPnpApiPath = "../../../../.pnp.cjs"; 9 | 10 | const absPnpApiPath = resolve(__dirname, relPnpApiPath); 11 | const absUserWrapperPath = resolve(__dirname, `./sdk.user.cjs`); 12 | const absRequire = createRequire(absPnpApiPath); 13 | 14 | const absPnpLoaderPath = resolve(absPnpApiPath, `../.pnp.loader.mjs`); 15 | const isPnpLoaderEnabled = existsSync(absPnpLoaderPath); 16 | 17 | if (existsSync(absPnpApiPath)) { 18 | if (!process.versions.pnp) { 19 | // Setup the environment to be able to require typescript/lib/tsc.js 20 | require(absPnpApiPath).setup(); 21 | if (isPnpLoaderEnabled && register) { 22 | register(pathToFileURL(absPnpLoaderPath)); 23 | } 24 | } 25 | } 26 | 27 | const wrapWithUserWrapper = existsSync(absUserWrapperPath) 28 | ? exports => absRequire(absUserWrapperPath)(exports) 29 | : exports => exports; 30 | 31 | // Defer to the real typescript/lib/tsc.js your application uses 32 | module.exports = wrapWithUserWrapper(absRequire(`typescript/lib/tsc.js`)); 33 | -------------------------------------------------------------------------------- /.yarn/sdks/typescript/lib/typescript.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const {existsSync} = require(`fs`); 4 | const {createRequire, register} = require(`module`); 5 | const {resolve} = require(`path`); 6 | const {pathToFileURL} = require(`url`); 7 | 8 | const relPnpApiPath = "../../../../.pnp.cjs"; 9 | 10 | const absPnpApiPath = resolve(__dirname, relPnpApiPath); 11 | const absUserWrapperPath = resolve(__dirname, `./sdk.user.cjs`); 12 | const absRequire = createRequire(absPnpApiPath); 13 | 14 | const absPnpLoaderPath = resolve(absPnpApiPath, `../.pnp.loader.mjs`); 15 | const isPnpLoaderEnabled = existsSync(absPnpLoaderPath); 16 | 17 | if (existsSync(absPnpApiPath)) { 18 | if (!process.versions.pnp) { 19 | // Setup the environment to be able to require typescript 20 | require(absPnpApiPath).setup(); 21 | if (isPnpLoaderEnabled && register) { 22 | register(pathToFileURL(absPnpLoaderPath)); 23 | } 24 | } 25 | } 26 | 27 | const wrapWithUserWrapper = existsSync(absUserWrapperPath) 28 | ? exports => absRequire(absUserWrapperPath)(exports) 29 | : exports => exports; 30 | 31 | // Defer to the real typescript your application uses 32 | module.exports = wrapWithUserWrapper(absRequire(`typescript`)); 33 | -------------------------------------------------------------------------------- /.yarn/sdks/typescript/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "typescript", 3 | "version": "5.6.3-sdk", 4 | "main": "./lib/typescript.js", 5 | "type": "commonjs", 6 | "bin": { 7 | "tsc": "./bin/tsc", 8 | "tsserver": "./bin/tsserver" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /.yarn/versions/9085f262.yml: -------------------------------------------------------------------------------- 1 | # Copyright (c) TotalSoft. 2 | # This source code is licensed under the MIT license. 3 | 4 | -------------------------------------------------------------------------------- /.yarnrc.yml: -------------------------------------------------------------------------------- 1 | yarnPath: .yarn/releases/yarn-4.5.1.cjs 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 osstotalsoft 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/osstotalsoft/rocket-ui-ts/80feca8180b7ce5d2767a81eaa53475aab999793/public/favicon.ico -------------------------------------------------------------------------------- /public/faviconGlobe.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/osstotalsoft/rocket-ui-ts/80feca8180b7ce5d2767a81eaa53475aab999793/public/faviconGlobe.ico -------------------------------------------------------------------------------- /public/faviconReact.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/osstotalsoft/rocket-ui-ts/80feca8180b7ce5d2767a81eaa53475aab999793/public/faviconReact.ico -------------------------------------------------------------------------------- /public/faviconTS.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/osstotalsoft/rocket-ui-ts/80feca8180b7ce5d2767a81eaa53475aab999793/public/faviconTS.ico -------------------------------------------------------------------------------- /src/__mocks__/fileMock.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) TotalSoft. 2 | // This source code is licensed under the MIT license. 3 | 4 | -------------------------------------------------------------------------------- /src/components/assets/img/forbidden.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/osstotalsoft/rocket-ui-ts/80feca8180b7ce5d2767a81eaa53475aab999793/src/components/assets/img/forbidden.png -------------------------------------------------------------------------------- /src/components/assets/img/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/osstotalsoft/rocket-ui-ts/80feca8180b7ce5d2767a81eaa53475aab999793/src/components/assets/img/logo.png -------------------------------------------------------------------------------- /src/components/assets/img/miniLogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/osstotalsoft/rocket-ui-ts/80feca8180b7ce5d2767a81eaa53475aab999793/src/components/assets/img/miniLogo.png -------------------------------------------------------------------------------- /src/components/assets/img/notFound.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/osstotalsoft/rocket-ui-ts/80feca8180b7ce5d2767a81eaa53475aab999793/src/components/assets/img/notFound.png -------------------------------------------------------------------------------- /src/components/buttons/BackToButton/BackToButton.test.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { BrowserRouter, Route, Routes } from 'react-router' 3 | import BackToButton from './BackToButton' 4 | import { render, userClick, waitFor, screen, act } from '../../../testingUtils' 5 | 6 | describe('BackToButton', () => { 7 | test('redirects to the path received', async () => { 8 | render( 9 | <BrowserRouter> 10 | <BackToButton path="/back" /> 11 | <Routes> 12 | <Route path="/back" element={<div>{'redirected'}</div>}></Route> 13 | </Routes> 14 | </BrowserRouter> 15 | ) 16 | act(() => userClick(screen.getByRole('button'))) 17 | await waitFor(() => { 18 | expect(screen.getByText('redirected')).toBeInTheDocument() 19 | }) 20 | }) 21 | }) 22 | -------------------------------------------------------------------------------- /src/components/buttons/BackToButton/index.ts: -------------------------------------------------------------------------------- 1 | export * from './types' 2 | import BackToButton from './BackToButton' 3 | export default BackToButton 4 | -------------------------------------------------------------------------------- /src/components/buttons/BackToButton/types.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) TotalSoft. 2 | // This source code is licensed under the MIT license. 3 | 4 | import { NavigateOptions } from 'react-router' 5 | import { IconButtonProps } from '../IconButton/types' 6 | 7 | export interface BackToButtonProps extends Omit<IconButtonProps, 'type'> { 8 | /** 9 | * Path where browser will be directed to when the button is clicked. 10 | */ 11 | path: string | number 12 | /** 13 | * Navigation options. 14 | * flushSync?: boolean; 15 | * preventScrollReset?: boolean; 16 | * relative?: RelativeRoutingType; 17 | * replace?: boolean; 18 | * state?: any; 19 | * viewTransition?: boolean; 20 | */ 21 | options?: NavigateOptions 22 | } 23 | -------------------------------------------------------------------------------- /src/components/buttons/Button/index.ts: -------------------------------------------------------------------------------- 1 | export * from './types' 2 | import Button from './Button' 3 | export default Button 4 | -------------------------------------------------------------------------------- /src/components/buttons/Button/types.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) TotalSoft. 2 | // This source code is licensed under the MIT license. 3 | import { ButtonProps as MuiButtonProps } from '@mui/material' 4 | import { Color, Size } from '../../types' 5 | 6 | export type ButtonVariant = 'outlined' | 'text' | 'contained' 7 | 8 | export interface ButtonProps extends Omit<MuiButtonProps, 'color' | 'size' | 'variant' | 'component'> { 9 | variant?: ButtonVariant 10 | /** 11 | * The color of the button. 12 | */ 13 | color?: Color 14 | /** 15 | * The size of the button. 16 | */ 17 | size?: Size 18 | /** 19 | * The tooltip of the button. 20 | */ 21 | tooltip?: string 22 | /** 23 | * If true, rounded corners are enabled. 24 | */ 25 | round?: boolean 26 | /** 27 | * If true, the button will float to the right. 28 | */ 29 | right?: boolean 30 | /** 31 | * If true, the button will be smaller. 32 | */ 33 | justIcon?: boolean 34 | /** 35 | * If true, button is in loading state. 36 | */ 37 | loading?: boolean 38 | /** 39 | * If true, the button's min width will be set to 160px. 40 | */ 41 | wd?: boolean 42 | /** 43 | * If true, a gradient background is applied. 44 | */ 45 | gradient?: boolean 46 | /** 47 | * @default true 48 | * If true, button text is capitalized. 49 | */ 50 | capitalize?: boolean 51 | /** 52 | * Used for upload 53 | */ 54 | component?: string 55 | } 56 | -------------------------------------------------------------------------------- /src/components/buttons/IconButton/IconButtonStyles.ts: -------------------------------------------------------------------------------- 1 | import { styled } from '@mui/material/styles' 2 | import Button from '../Button' 3 | 4 | const IconButton = styled(Button)(() => ({ 5 | alignItems: 'center', 6 | justifyContent: 'center', 7 | position: 'relative', 8 | display: 'inline-flex', 9 | borderRadius: '50%', 10 | minWidth: '0px', 11 | '&.MuiButton-sizeSmall': { 12 | padding: '0px', 13 | width: '40px', 14 | height: '40px' 15 | }, 16 | '&.MuiButton-sizeMedium': { 17 | padding: '11px', 18 | width: '48px', 19 | height: '48px' 20 | }, 21 | '&.MuiButton-sizeLarge': { 22 | padding: '15px', 23 | width: '52px', 24 | height: '52px' 25 | } 26 | })) 27 | 28 | export default IconButton 29 | -------------------------------------------------------------------------------- /src/components/buttons/IconButton/index.ts: -------------------------------------------------------------------------------- 1 | export * from './types' 2 | import IconButton from './IconButton' 3 | export default IconButton 4 | -------------------------------------------------------------------------------- /src/components/buttons/UploadButton/index.ts: -------------------------------------------------------------------------------- 1 | export * from './types' 2 | import UploadButton from './UploadButton' 3 | export default UploadButton 4 | -------------------------------------------------------------------------------- /src/components/charts/DeprecatedChart/index.ts: -------------------------------------------------------------------------------- 1 | export * from './types' 2 | import DeprecatedChart from './DeprecatedChart' 3 | export default DeprecatedChart 4 | -------------------------------------------------------------------------------- /src/components/charts/DeprecatedChart/types.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) TotalSoft. 2 | // This source code is licensed under the MIT license. 3 | 4 | import { SvgIconComponent } from '@mui/icons-material' 5 | import { CardProps } from '../..' 6 | import { ChartProps } from 'react-chartjs-2' 7 | 8 | export interface DeprecatedChartProps extends Omit<ChartProps, 'title'> { 9 | /** 10 | * Chart subtitle. 11 | */ 12 | subheader?: React.ReactNode 13 | /** 14 | * Chart icon. 15 | */ 16 | Icon?: SvgIconComponent 17 | /** 18 | * Chart icon color. 19 | */ 20 | iconColor?: string 21 | /** 22 | * Content of the title. 23 | */ 24 | title?: React.ReactNode 25 | cardProps?: CardProps 26 | } 27 | -------------------------------------------------------------------------------- /src/components/charts/DeprecatedStatsChart/index.ts: -------------------------------------------------------------------------------- 1 | export * from './types' 2 | import DeprecatedStatsChart from './DeprecatedStatsChart' 3 | export default DeprecatedStatsChart 4 | -------------------------------------------------------------------------------- /src/components/charts/DeprecatedStatsChart/types.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) TotalSoft. 2 | // This source code is licensed under the MIT license. 3 | 4 | import { SvgIconComponent } from '@mui/icons-material' 5 | import { ChartProps } from 'react-chartjs-2' 6 | import { Color } from '../../types' 7 | 8 | export interface DataSetsChart { 9 | data: number[] 10 | label: string 11 | backgroundColor: string 12 | borderColor: string 13 | } 14 | 15 | export type DeprecatedStatsIconColor = Exclude<Color, 'default' | 'white' | 'transparent' | 'dark' | 'rose'> 16 | 17 | export interface DeprecatedStatsChartProps extends Omit<ChartProps, 'type' | 'data'> { 18 | /** 19 | * Chart type. 20 | */ 21 | type?: 'line' | 'bar' 22 | /** 23 | * The text content of chart. 24 | */ 25 | text?: string 26 | /** 27 | * Chart icon. 28 | */ 29 | StatIcon?: SvgIconComponent 30 | /** 31 | * @default 'grey' 32 | * Chart icon color. 33 | */ 34 | iconColor?: DeprecatedStatsIconColor 35 | /** 36 | * @default 'info' 37 | * Chart color. 38 | */ 39 | chartColor?: Color 40 | /** 41 | * Chart status text. 42 | */ 43 | statText?: React.ReactNode 44 | /** 45 | * Chart data. 46 | */ 47 | data: { 48 | labels: string[] 49 | datasets: DataSetsChart[] 50 | } 51 | /** 52 | * Action to be displayed in the right corner of the card. 53 | */ 54 | statAction?: React.ReactNode 55 | } 56 | -------------------------------------------------------------------------------- /src/components/dataDisplay/ExpandingText/ExpandingTextStyles.ts: -------------------------------------------------------------------------------- 1 | import { styled } from '@mui/material/styles' 2 | import Typography from '../Typography' 3 | 4 | const ExpandAction = styled(Typography)(({ theme }) => ({ 5 | color: theme?.palette.link.main, 6 | cursor: 'pointer' 7 | })) 8 | 9 | export default ExpandAction 10 | -------------------------------------------------------------------------------- /src/components/dataDisplay/ExpandingText/index.ts: -------------------------------------------------------------------------------- 1 | export * from './types' 2 | import ExpandingText from './ExpandingText' 3 | export default ExpandingText 4 | -------------------------------------------------------------------------------- /src/components/dataDisplay/ExpandingText/types.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) TotalSoft. 2 | // This source code is licensed under the MIT license. 3 | 4 | import { TypographyProps } from '../Typography/types' 5 | 6 | export type DisplayType = 'inline' | 'block' | 'inline-block' | 'flex' | 'inline-flex' | 'none' 7 | 8 | export interface ExpandingTextProps extends TypographyProps { 9 | /** 10 | * Text to be displayed. 11 | */ 12 | text: string 13 | /** 14 | * Length of text to be displayed. 15 | */ 16 | minLength?: number 17 | /** 18 | * @default 'Show less' 19 | * Text of `showLess` button. 20 | */ 21 | showLessText?: React.ReactNode 22 | /** 23 | * @default 'Show more' 24 | * Text of `showMore` button. 25 | */ 26 | showMoreText?: React.ReactNode 27 | /** 28 | * @default 'block' 29 | * CSS `display` prop applied to the text. 30 | */ 31 | display?: DisplayType 32 | /** 33 | * Props applied to the text. 34 | */ 35 | textProps?: TypographyProps 36 | /** 37 | * Props applied to the ShowLess/ShowMore component. 38 | */ 39 | expandingActionProps?: TypographyProps 40 | /** 41 | * @default false 42 | * Expanded state of the text. 43 | */ 44 | expanded?: boolean 45 | } 46 | -------------------------------------------------------------------------------- /src/components/dataDisplay/FavIcon/FavIcon.tsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useCallback } from 'react' 2 | import PropTypes from 'prop-types' 3 | import { FavIconProps } from './types' 4 | import { is } from 'ramda' 5 | /** 6 | * The FavIcon component sets the favicon displayed by the browser on the website's tab 7 | * The html <link> of the icon must have an id attribute of 'favicon' 8 | */ 9 | const FavIcon: React.FC<FavIconProps> = ({ favIconSource, defaultFavIcon }) => { 10 | const onError = useCallback( 11 | (event: string | Event, favicon: HTMLLinkElement) => { 12 | favicon.href = defaultFavIcon || '#' 13 | if (is(String, event)) return 14 | const target = event.target as HTMLImageElement 15 | target.onerror = null 16 | }, 17 | [defaultFavIcon] 18 | ) 19 | 20 | const setFavIcon = useCallback( 21 | (source: string) => { 22 | const favicon = document.getElementById('favicon') as HTMLLinkElement || top.document.getElementById('favicon') as HTMLLinkElement 23 | const img = new Image() 24 | img.onerror = (event: string | Event) => onError(event, favicon) 25 | img.onload = () => (favicon.href = source || '#') 26 | img.src = source 27 | }, 28 | [onError] 29 | ) 30 | 31 | useEffect(() => { 32 | setFavIcon(favIconSource) 33 | }, [favIconSource, setFavIcon]) 34 | 35 | return <></> 36 | } 37 | 38 | FavIcon.propTypes = { 39 | /** 40 | * URL of the favicon image 41 | */ 42 | favIconSource: PropTypes.string, 43 | /** 44 | * URL of the fallback image. This will be used when the onerror event occurs 45 | */ 46 | defaultFavIcon: PropTypes.string 47 | } 48 | 49 | export default FavIcon 50 | -------------------------------------------------------------------------------- /src/components/dataDisplay/FavIcon/index.ts: -------------------------------------------------------------------------------- 1 | export * from './types' 2 | import FavIcon from './FavIcon' 3 | export default FavIcon 4 | -------------------------------------------------------------------------------- /src/components/dataDisplay/FavIcon/types.ts: -------------------------------------------------------------------------------- 1 | export interface FavIconProps { 2 | /** 3 | * Path to the image 4 | */ 5 | favIconSource?: string 6 | /** 7 | * Path to the fallback image. This will be used when the onerror event occurs 8 | */ 9 | defaultFavIcon?: string 10 | } -------------------------------------------------------------------------------- /src/components/dataDisplay/StatsChart/Chart.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { 3 | BarChart, 4 | BarChartProps, 5 | Gauge, 6 | GaugeContainerProps, 7 | LineChart, 8 | LineChartProps, 9 | PieChart, 10 | PieChartProps, 11 | ScatterChart, 12 | ScatterChartProps 13 | } from '@mui/x-charts' 14 | import { ChartProps } from './types' 15 | 16 | /** 17 | * The Chart component serves as a unified interface for rendering all available chart types in MUI X, 18 | * providing flexibility and simplicity in chart selection. 19 | */ 20 | const Chart: React.FC<ChartProps> = ({ type, ...props }) => { 21 | switch (type) { 22 | case 'line': 23 | return <LineChart data-testid="line-chart" {...(props as LineChartProps)} /> 24 | case 'bar': 25 | return <BarChart data-testid="bar-chart" {...(props as BarChartProps)} /> 26 | case 'pie': 27 | return <PieChart data-testid="pie-chart" {...(props as PieChartProps)} /> 28 | case 'scatter': 29 | return <ScatterChart data-testid="scatter-chart" {...(props as ScatterChartProps)} /> 30 | case 'gauge': 31 | return <Gauge data-testid="gauge-chart" {...(props as GaugeContainerProps)} /> 32 | default: 33 | return <p>Unsupported chart type</p> 34 | } 35 | } 36 | 37 | export default Chart 38 | -------------------------------------------------------------------------------- /src/components/dataDisplay/StatsChart/StatsChart.test.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { render, screen } from '../../../testingUtils' 3 | import StatsChart from './StatsChart' 4 | import { 5 | barChartOptions, 6 | gaugeChartOptions, 7 | lineChartOptions, 8 | pieChartOptions, 9 | scatterChartOptions 10 | } from 'components/surfaces/StatsCard/_mocks' 11 | import { ChartProps } from './types' 12 | 13 | type ChartOption = { 14 | chartOptions: ChartProps 15 | testId: string 16 | text: string 17 | } 18 | const chartOptionsArray: ChartOption[] = [ 19 | { 20 | chartOptions: { type: 'line', ...lineChartOptions }, 21 | testId: 'line-chart', 22 | text: 'This is a line chart' 23 | }, 24 | { 25 | chartOptions: { type: 'bar', ...barChartOptions }, 26 | testId: 'bar-chart', 27 | text: 'This is a bar chart' 28 | }, 29 | { 30 | chartOptions: { type: 'pie', ...pieChartOptions }, 31 | testId: 'pie-chart', 32 | text: 'This is a pie chart' 33 | }, 34 | { 35 | chartOptions: { type: 'scatter', ...scatterChartOptions }, 36 | testId: 'scatter-chart', 37 | text: 'This is a scatter chart' 38 | }, 39 | { 40 | chartOptions: { type: 'gauge', ...gaugeChartOptions }, 41 | testId: 'gauge-chart', 42 | text: 'This is a gauge chart' 43 | } 44 | ] 45 | 46 | describe('Stats Chart tests', () => { 47 | it.each(chartOptionsArray)('renders the correct type of chart', ({ text, chartOptions, testId }) => { 48 | // arrange 49 | render(<StatsChart title={text} text={text} chart={chartOptions} />) 50 | // act 51 | const element = screen.getByTestId(testId) 52 | // assert 53 | expect(element).toBeInTheDocument() 54 | }) 55 | }) 56 | -------------------------------------------------------------------------------- /src/components/dataDisplay/StatsChart/index.ts: -------------------------------------------------------------------------------- 1 | export * from './types' 2 | import StatsChart from './StatsChart' 3 | export default StatsChart 4 | -------------------------------------------------------------------------------- /src/components/dataDisplay/StatsChart/types.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) TotalSoft. 2 | // This source code is licensed under the MIT license. 3 | 4 | import { SvgIconComponent } from '@mui/icons-material' 5 | 6 | import { BarChartProps, GaugeContainerProps, LineChartProps, PieChartProps, ScatterChartProps } from '@mui/x-charts' 7 | import { Color } from 'components/types' 8 | 9 | //ChartType defines the chart types that can be used with the Chart component. 10 | export type ChartType = 'line' | 'bar' | 'pie' | 'scatter' | 'gauge' 11 | 12 | //ChartProps defines a discriminated union for handling multiple chart types. 13 | export type ChartProps = 14 | | ({ type: 'line' } & LineChartProps) 15 | | ({ type: 'bar' } & BarChartProps) 16 | | ({ type: 'pie' } & PieChartProps) 17 | | ({ type: 'scatter' } & ScatterChartProps) 18 | | ({ type: 'gauge' } & GaugeContainerProps) 19 | 20 | export type StatsChartProps = { 21 | chartColor?: Color 22 | iconColor?: StatsIconColor 23 | title: string 24 | text: string 25 | StatIcon?: SvgIconComponent 26 | statText?: string 27 | statAction?: React.ReactNode 28 | chart: ChartProps 29 | } 30 | 31 | export type StatsIconColor = Exclude<Color, 'default' | 'white' | 'transparent' | 'dark' | 'rose'> 32 | -------------------------------------------------------------------------------- /src/components/dataDisplay/Typography/TypographyStyles.ts: -------------------------------------------------------------------------------- 1 | import BaseTypography from '@mui/material/Typography' 2 | import { styled } from '@mui/material/styles' 3 | import { includes } from 'ramda' 4 | 5 | const Typography = styled(BaseTypography)(({ theme, variant }) => ({ 6 | fontFamily: theme.typography.fontFamily, 7 | textTransform: includes(variant, ['overline', 'button']) ? 'uppercase' : 'none' 8 | })) 9 | 10 | export default Typography 11 | -------------------------------------------------------------------------------- /src/components/dataDisplay/Typography/index.ts: -------------------------------------------------------------------------------- 1 | export * from './types' 2 | import Typography from './Typography' 3 | export default Typography 4 | -------------------------------------------------------------------------------- /src/components/dataDisplay/Typography/types.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) TotalSoft. 2 | // This source code is licensed under the MIT license. 3 | import { TypographyProps as MuiTypographyProps } from '@mui/material' 4 | 5 | /** 6 | * The color of the text. 7 | */ 8 | export type TypographyColor = 9 | | 'initial' 10 | | 'inherit' 11 | | 'primary' 12 | | 'secondary' 13 | | 'textPrimary' 14 | | 'textSecondary' 15 | | 'error' 16 | | string 17 | 18 | /** 19 | * Controls the text emphasis. Different font styles can be used individually or in combination. 20 | */ 21 | export type Emphasis = 'bold' | 'italic' | 'underline' | 'line-through' | 'overline' 22 | 23 | export interface TypographyProps extends MuiTypographyProps { 24 | /** 25 | * The color of the text 26 | */ 27 | color?: TypographyColor 28 | /** 29 | * If provided, a text will appear on hover. 30 | */ 31 | tooltip?: React.ReactNode 32 | /** 33 | * Controls the text emphasis. Different font styles can be used individually or in combination 34 | */ 35 | emphasis?: Emphasis | Emphasis[] 36 | } 37 | -------------------------------------------------------------------------------- /src/components/feedback/Dialog/DialogStyles.ts: -------------------------------------------------------------------------------- 1 | import MuiDialogContent from '@mui/material/DialogContent' 2 | import MuiDialogTitle from '@mui/material/DialogTitle' 3 | import Backdrop from '@mui/material/Backdrop' 4 | import { styled } from '@mui/material/styles' 5 | 6 | export const justifyRight = { 7 | position: 'absolute', 8 | top: 'auto', 9 | right: 14 10 | } 11 | 12 | export const DialogContent = styled(MuiDialogContent)(({ theme }) => ({ 13 | fontFamily: theme.typography.defaultFont.fontFamily, 14 | fontSize: theme.typography.defaultFont.fontSize 15 | })) 16 | 17 | export const DialogTitle = styled(MuiDialogTitle)(({ theme }) => ({ 18 | fontFamily: theme.typography.defaultFont.fontFamily, 19 | padding: 0 20 | })) 21 | 22 | export const TransparentBackdrop = styled(Backdrop)(() => ({ 23 | backgroundColor: 'transparent' 24 | })) 25 | -------------------------------------------------------------------------------- /src/components/feedback/Dialog/index.ts: -------------------------------------------------------------------------------- 1 | import Dialog from './Dialog' 2 | export default Dialog 3 | export * from './types' 4 | -------------------------------------------------------------------------------- /src/components/feedback/FakeText/index.ts: -------------------------------------------------------------------------------- 1 | export * from './types' 2 | import FakeText from './FakeText' 3 | export default FakeText 4 | -------------------------------------------------------------------------------- /src/components/feedback/FakeText/types.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) TotalSoft. 2 | // This source code is licensed under the MIT license. 3 | import { SkeletonProps } from '@mui/material/Skeleton' 4 | 5 | export interface FakeTextProps extends Omit<SkeletonProps, 'animation'> { 6 | /** 7 | * @default 'wave' 8 | * The animation. If false, the animation effect is disabled 9 | */ 10 | animation?: 'pulse' | 'wave' | false 11 | /** 12 | * @default 1 13 | * The number of fake line texts that will be rendered 14 | */ 15 | lines?: number 16 | /** 17 | * @default false 18 | * If set to true, the fake text will render on a Paper component 19 | */ 20 | onPaper?: boolean 21 | } 22 | -------------------------------------------------------------------------------- /src/components/feedback/Forbidden/Forbidden.test.tsx: -------------------------------------------------------------------------------- 1 | // Copyright (c) TotalSoft. 2 | // This source code is licensed under the MIT license. 3 | 4 | import React from 'react' 5 | import Forbidden from './Forbidden' 6 | import { render, screen } from 'testingUtils' 7 | 8 | const forbiddenTextValue = 'You are banned from viewing this page!' 9 | const forbiddenTextDefault = 'Not allowed to see this page!' 10 | const forbiddenButtonTextValue = 'Go to page' 11 | const forbiddenButtonTextDefault = 'Go to main page' 12 | 13 | describe('Forbidden', () => { 14 | test('displays the text received through the forbiddenText prop', () => { 15 | render(<Forbidden forbiddenText={forbiddenTextValue} />) 16 | 17 | expect(screen.getByText(forbiddenTextValue)).toBeInTheDocument() 18 | }) 19 | 20 | test('displays the text received through the forbiddenButtonText prop', () => { 21 | render(<Forbidden forbiddenButtonText={forbiddenButtonTextValue} />) 22 | 23 | expect(screen.getByText(forbiddenButtonTextValue)).toBeInTheDocument() 24 | }) 25 | 26 | test('default text and default text of the button are in screen', async () => { 27 | render(<Forbidden />) 28 | const forbiddenText = await screen.findByText(forbiddenTextDefault) 29 | const forbiddenButtonText = await screen.findByText(forbiddenButtonTextDefault) 30 | 31 | expect(forbiddenText).toBeInTheDocument() 32 | expect(forbiddenButtonText).toBeInTheDocument() 33 | }) 34 | 35 | test('displays image on the screen', async () => { 36 | render(<Forbidden />) 37 | const forbiddenImage = screen.getByRole('img') 38 | 39 | expect(forbiddenImage).toHaveAttribute('alt', 'ForbiddenImage') 40 | }) 41 | }) 42 | -------------------------------------------------------------------------------- /src/components/feedback/Forbidden/Forbidden.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PropTypes from 'prop-types' 3 | import Grid from '@mui/material/Grid2' 4 | import forbidden from '../../assets/img/forbidden.png' 5 | import Typography from '../../dataDisplay/Typography' 6 | import Button from '../../buttons/Button' 7 | import { ForbiddenProps } from './types' 8 | 9 | /** 10 | * Used when users don't have access to certain page due to insufficient rights. 11 | */ 12 | 13 | const Forbidden: React.FC<ForbiddenProps> = ({ 14 | forbiddenText = 'Not allowed to see this page!', 15 | forbiddenButtonText = 'Go to main page' 16 | }) => { 17 | return ( 18 | <Grid container direction="column" justifyContent="center" alignItems="center" spacing={2}> 19 | <Grid> 20 | <img src={forbidden} alt="ForbiddenImage" /> 21 | </Grid> 22 | <Grid> 23 | <Typography variant={'h5'} emphasis="bold"> 24 | {forbiddenText} 25 | </Typography> 26 | </Grid> 27 | <Grid> 28 | <Button size={'small'} color={'primary'} href={'/'}> 29 | {forbiddenButtonText} 30 | </Button> 31 | </Grid> 32 | </Grid> 33 | ) 34 | } 35 | 36 | Forbidden.propTypes = { 37 | /** 38 | * @default 'Not allowed to see this page!' 39 | * Text to be displayed 40 | */ 41 | forbiddenText: PropTypes.string, 42 | /** 43 | * @default 'Go to main page' 44 | * Text to be displayed on button 45 | */ 46 | forbiddenButtonText: PropTypes.string 47 | } 48 | 49 | export default Forbidden 50 | -------------------------------------------------------------------------------- /src/components/feedback/Forbidden/index.ts: -------------------------------------------------------------------------------- 1 | export * from './types' 2 | import Forbidden from './Forbidden' 3 | export default Forbidden 4 | -------------------------------------------------------------------------------- /src/components/feedback/Forbidden/types.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) TotalSoft. 2 | // This source code is licensed under the MIT license. 3 | 4 | export interface ForbiddenProps { 5 | /** 6 | * @default "Not allowed to see this page!" 7 | * Text to be displayed 8 | */ 9 | forbiddenText?: string 10 | /** 11 | * @default "Go to main page" 12 | * Text to be displayed on button 13 | */ 14 | forbiddenButtonText?: string 15 | } 16 | -------------------------------------------------------------------------------- /src/components/feedback/LinearProgress/LinearProgress.test.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { render, screen } from 'testingUtils' 3 | import { LinearProgress } from 'components' 4 | 5 | describe('LinearProgress', () => { 6 | it('renders the label', () => { 7 | render(<LinearProgress value={80} showLabel={true} />) 8 | expect(screen.getByText('80%')).toBeInTheDocument() 9 | }) 10 | }) 11 | -------------------------------------------------------------------------------- /src/components/feedback/LinearProgress/LinearProgressStyles.ts: -------------------------------------------------------------------------------- 1 | import { LinearProgress as MuiLinearProgress, Box } from '@mui/material' 2 | import { styled } from '@mui/material/styles' 3 | import Typography from '../../dataDisplay/Typography' 4 | import { includes } from 'ramda' 5 | 6 | export const LinearProgress: any = styled(MuiLinearProgress, { 7 | shouldForwardProp: prop => !includes(prop, ['showLabel', 'labelProps']) 8 | })(() => ({ 9 | '&.MuiLinearProgress-bar': { 10 | height: '4px' 11 | }, 12 | '&.MuiLinearProgress-root': { 13 | height: '4px', 14 | overflow: 'hidden' 15 | } 16 | })) 17 | 18 | export const Label = styled(Typography)(() => ({ 19 | marginTop: '-21px' 20 | })) 21 | 22 | type ContainerComponentProps = { 23 | global?: boolean 24 | } 25 | 26 | export const ComponentContainer = styled(Box, { shouldForwardProp: prop => prop !== 'global' })<ContainerComponentProps>( 27 | ({ global }) => ({ 28 | display: 'flex', 29 | alignItems: 'center', 30 | ...(global && { 31 | position: 'fixed', 32 | zIndex: 9999, 33 | top: 0, 34 | left: 0, 35 | right: 0, 36 | overflow: 'hidden' 37 | }) 38 | }) 39 | ) 40 | 41 | type LinearProgressContainerProps = { 42 | hasLabel?: boolean 43 | } 44 | 45 | export const LinearProgressContainer = styled(Box, { 46 | shouldForwardProp: prop => prop !== 'hasLabel' 47 | })<LinearProgressContainerProps>(({ hasLabel, theme }) => ({ 48 | width: '100%', 49 | ...(hasLabel && { 50 | marginRight: theme.spacing(1) 51 | }) 52 | })) 53 | 54 | export default LinearProgress 55 | -------------------------------------------------------------------------------- /src/components/feedback/LinearProgress/index.ts: -------------------------------------------------------------------------------- 1 | import LinearProgress from './LinearProgress' 2 | export default LinearProgress 3 | export * from './types' 4 | -------------------------------------------------------------------------------- /src/components/feedback/LinearProgress/types.ts: -------------------------------------------------------------------------------- 1 | import { LinearProgressProps as MuiLinearProgressProps } from '@mui/material' 2 | import { TypographyProps } from '../../dataDisplay/Typography' 3 | import { Color } from '../../types' 4 | 5 | type ProgressColor = Exclude<Color, 'default' | 'white' | 'transparent' | 'inherit'> | 'grey' 6 | 7 | export interface LinearProgressProps extends Omit<MuiLinearProgressProps, 'color'> { 8 | /** 9 | * @default "grey" 10 | * Color of the component. 11 | */ 12 | color?: ProgressColor 13 | /** 14 | * Props applied to the label. 15 | */ 16 | labelProps?: TypographyProps 17 | /** 18 | * If true it shows the progress indicator value (%). 19 | */ 20 | showLabel?: boolean 21 | /** 22 | * If true, the bar is shown at the top of the page, spanning the entire width 23 | */ 24 | global?: boolean 25 | } 26 | -------------------------------------------------------------------------------- /src/components/feedback/NotFound/NotFound.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PropTypes from 'prop-types' 3 | import { NotFoundImage, NotFoundText } from './NotFoundStyles' 4 | import notFound from '../../assets/img/notFound.png' 5 | import Grid from '@mui/material/Grid2' 6 | import { NotFoundProps } from './types' 7 | 8 | /** 9 | * Used when a page cannot be found. 10 | */ 11 | 12 | const NotFound: React.FC<NotFoundProps> = ({ 13 | text = 'Not Found', 14 | details = 'The resource requested could not be found on this server!' 15 | }) => { 16 | return ( 17 | <Grid> 18 | <NotFoundImage> 19 | <img src={notFound} alt="notFoundImage" /> 20 | </NotFoundImage> 21 | <NotFoundText variant={'h5'}>{text}</NotFoundText> 22 | <NotFoundText variant={'h5'}>{details}</NotFoundText> 23 | </Grid> 24 | ) 25 | } 26 | 27 | NotFound.propTypes = { 28 | /** 29 | * @default 'Not Found' 30 | * The text to be displayed when this component is rendered 31 | */ 32 | text: PropTypes.string, 33 | /** 34 | * @default 'The resource requested could not be found on this server!' 35 | * The details to be displayed when this component is rendered 36 | */ 37 | details: PropTypes.string 38 | } 39 | 40 | export default NotFound 41 | -------------------------------------------------------------------------------- /src/components/feedback/NotFound/NotFoundStyles.ts: -------------------------------------------------------------------------------- 1 | import Typography from '@mui/material/Typography' 2 | import { styled } from '@mui/material/styles' 3 | 4 | export const NotFoundText = styled(Typography)(({ theme }) => ({ 5 | textAlign: 'center', 6 | fontWeight: 'bold', 7 | fontFamily: theme.typography.defaultFont.fontFamily 8 | })) 9 | 10 | export const NotFoundImage = styled('div')(() => ({ 11 | marginBottom: '30px', 12 | marginTop: '50px', 13 | textAlign: 'center' 14 | })) 15 | 16 | export default NotFoundText 17 | -------------------------------------------------------------------------------- /src/components/feedback/NotFound/index.ts: -------------------------------------------------------------------------------- 1 | export * from './types' 2 | import NotFound from './NotFound' 3 | export default NotFound 4 | -------------------------------------------------------------------------------- /src/components/feedback/NotFound/types.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) TotalSoft. 2 | // This source code is licensed under the MIT license. 3 | 4 | export interface NotFoundProps { 5 | /** 6 | * @default "Not Found" 7 | * The text to be displayed when this component is rendered 8 | */ 9 | text?: string 10 | /** 11 | * @default "The resource requested could not be found on this server!" 12 | * The details to be displayed when this component is rendered 13 | */ 14 | details?: string 15 | } 16 | -------------------------------------------------------------------------------- /src/components/feedback/Toast/index.ts: -------------------------------------------------------------------------------- 1 | export * from './types' 2 | export { default as ToastContainer } from './ToastContainer' 3 | export { default as useToast } from './useToast' 4 | export { default as usePromiseToast } from './usePromiseToast' -------------------------------------------------------------------------------- /src/components/feedback/Toast/types.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) TotalSoft. 2 | // This source code is licensed under the MIT license. 3 | import { always, cond, equals, T } from 'ramda' 4 | import { Bounce, Flip, ToastOptions as ToastOptionsBase, ToastContainerProps as ToastContainerPropsBase, Slide, Zoom } from 'react-toastify' 5 | 6 | export type TextFontSize = 'small' | 'medium' | 'large' 7 | 8 | export interface ToastContainerProps extends Omit<ToastContainerPropsBase, 'transition' | 'textSize'> { 9 | /** 10 | * The appearance effect. 11 | * @default Slide 12 | */ 13 | transitionType?: 'Slide' | 'Bounce' | 'Zoom' | 'Flip', 14 | /** 15 | * The size of the toast content text. 16 | * @default 'small' 17 | */ 18 | textSize?: TextFontSize 19 | } 20 | 21 | export type ToastOptions = Omit<ToastOptionsBase, 'transition'> & { 22 | transitionType?: 'Slide' | 'Bounce' | 'Zoom' | 'Flip', 23 | actions?: React.ReactNode 24 | } 25 | 26 | export const getTransitionType = cond([ 27 | [equals('Slide'), always(Slide)], 28 | [equals('Bounce'), always(Bounce)], 29 | [equals('Flip'), always(Flip)], 30 | [equals('Zoom'), always(Zoom)], 31 | [T, always(Slide)] 32 | ]) -------------------------------------------------------------------------------- /src/components/inputs/Autocomplete/index.ts: -------------------------------------------------------------------------------- 1 | import Autocomplete from './Autocomplete' 2 | export default Autocomplete 3 | export * from './types' 4 | -------------------------------------------------------------------------------- /src/components/inputs/Autocomplete/utils.ts: -------------------------------------------------------------------------------- 1 | import { emptyString } from '../../utils/constants' 2 | import { any, curry, either, equals, find, head, isEmpty, isNil, prop, type } from 'ramda' 3 | 4 | export const isNilOrEmpty = either(isNil, isEmpty) 5 | 6 | export const extractFirstValue = curry((fns, obj) => { 7 | for (let i = 0; i < fns.length; ++i) { 8 | const result = fns[i](obj) 9 | if (!isNilOrEmpty(result)) return result.toString() 10 | } 11 | return emptyString 12 | }) 13 | 14 | export const internalLabel = prop('__internalDisplay') 15 | export const internalValue = prop('__internalInputValue') 16 | 17 | const sameJsType = curry((a, b) => { 18 | if (any(isNil, [a, b])) return true 19 | return equals(type(a), type(b)) 20 | }) 21 | 22 | export const convertValueToOption = curry((value, options = [], getValue) => { 23 | if (isEmpty(options)) return value 24 | if (sameJsType(value, head(options))) return value 25 | const converted = find(option => getValue(option) == value, options) 26 | return isNil(converted) ? value : converted 27 | }) 28 | -------------------------------------------------------------------------------- /src/components/inputs/DateTime/index.ts: -------------------------------------------------------------------------------- 1 | export * from './types' 2 | import DateTime from './DateTime' 3 | export default DateTime 4 | -------------------------------------------------------------------------------- /src/components/inputs/DeprecatedAutocomplete/index.ts: -------------------------------------------------------------------------------- 1 | import DeprecatedAutocomplete from './DeprecatedAutocomplete' 2 | export default DeprecatedAutocomplete 3 | export * from './types' 4 | -------------------------------------------------------------------------------- /src/components/inputs/DynamicField/index.ts: -------------------------------------------------------------------------------- 1 | export * from './types' 2 | import DynamicField from './DynamicField' 3 | export default DynamicField 4 | -------------------------------------------------------------------------------- /src/components/inputs/DynamicField/types.ts: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { LoadOptions } from '../Autocomplete' 3 | 4 | export enum ControlType { 5 | Text = 'Text', 6 | Integer = 'Integer', 7 | Numeric = 'Numeric', 8 | Date = 'Date', 9 | Checkbox = 'Checkbox', 10 | Autocomplete = 'Autocomplete', 11 | Custom = 'Custom' 12 | } 13 | 14 | export type DynamicFieldProps<TCustomComponentProps extends object = any, TAutocompleteOptions = unknown> = { 15 | controlType: ControlType 16 | id?: string 17 | value?: unknown 18 | label?: string 19 | onChange?: (value: unknown) => void 20 | options?: readonly TAutocompleteOptions[] 21 | loadOptions?: LoadOptions<TAutocompleteOptions> 22 | isPaginated?: boolean 23 | error?: boolean 24 | helperText?: React.ReactNode 25 | required?: boolean 26 | readOnly?: boolean 27 | disabled?: boolean 28 | CustomComponent?: (props: TCustomComponentProps) => JSX.Element 29 | customComponentProps?: TCustomComponentProps 30 | [key: string]: any 31 | } 32 | -------------------------------------------------------------------------------- /src/components/inputs/PasswordField/PasswordField.test.tsx: -------------------------------------------------------------------------------- 1 | // Copyright (c) TotalSoft. 2 | // This source code is licensed under the MIT license. 3 | 4 | import React from 'react' 5 | import PasswordField from './PasswordField' 6 | import { render, userClick, waitFor, screen, act } from '../../../testingUtils' 7 | 8 | describe('PasswordField', () => { 9 | test('toggles show/hide icons', async () => { 10 | render(<PasswordField />) 11 | expect(screen.getByTestId('VisibilityOffIcon')).toBeInTheDocument() 12 | act(() => userClick(screen.getByRole('button'))) 13 | await waitFor(() => expect(screen.getByTestId('VisibilityIcon')).toBeInTheDocument()) 14 | }) 15 | 16 | test('hides/displays text when toggling the show button', async () => { 17 | const text = 'password' 18 | render(<PasswordField value={text} />) 19 | const input = screen.getByDisplayValue(text) 20 | expect(input).toHaveAttribute('type', 'password') 21 | act(() => userClick(screen.getByRole('button'))) 22 | await waitFor(() => expect(input).toHaveAttribute('type', 'text')) 23 | }) 24 | }) 25 | -------------------------------------------------------------------------------- /src/components/inputs/PasswordField/index.ts: -------------------------------------------------------------------------------- 1 | import PasswordField from './PasswordField' 2 | export default PasswordField 3 | -------------------------------------------------------------------------------- /src/components/inputs/Slider/SliderStyles.ts: -------------------------------------------------------------------------------- 1 | import MuiSlider from '@mui/material/Slider' 2 | import MuiFormControl from '@mui/material/FormControl' 3 | import MuiFormHelperText from '@mui/material/FormHelperText' 4 | import { styled } from '@mui/material/styles' 5 | import TextField from '../TextField' 6 | 7 | export const StyledSlider: any = styled(MuiSlider)(() => ({ 8 | ['&.MuiSlider-root']: { 9 | top: '-1px', 10 | margin: 0, 11 | ['& .MuiSlider-markLabel']: { 12 | top: '20px', 13 | fontSize: '14px', 14 | lineHeight: '1.5em' 15 | } 16 | } 17 | })) 18 | 19 | export const StyledTextField = styled(TextField)(() => ({ 20 | margin: '-14px 0' 21 | })) 22 | 23 | export const FormControl = styled(MuiFormControl)(() => ({ 24 | overflow: 'visible', // fix for mobile horizontal scroll 25 | marginLeft: 0 26 | })) 27 | 28 | export const FormHelperText = styled(MuiFormHelperText)(() => ({ 29 | marginLeft: 0 30 | })) 31 | -------------------------------------------------------------------------------- /src/components/inputs/Slider/index.ts: -------------------------------------------------------------------------------- 1 | export * from './types' 2 | import Slider from './Slider' 3 | export default Slider 4 | -------------------------------------------------------------------------------- /src/components/inputs/Tags/DisplayTags.tsx: -------------------------------------------------------------------------------- 1 | import React, { ReactElement } from 'react' 2 | import { TagProps } from './types' 3 | import { map } from 'ramda' 4 | import { Chip } from '@mui/material' 5 | 6 | /** 7 | * Renders the tags as chips. 8 | * 9 | * @param value The array of tags to be displayed. 10 | * @param size The size of the chips (default: 'small'). 11 | * @param rest Additional props to be passed to the chips. 12 | * @returns The rendered tags as chips. 13 | */ 14 | const DisplayTags: React.FC<TagProps> = ({ value, size = 'small', ...rest }) => ( 15 | <> 16 | {map( 17 | (tag: string): ReactElement => ( 18 | <Chip data-testid={`tag-chip-${tag}`} key={tag} label={tag} size={size} {...rest} /> 19 | ), 20 | value 21 | )} 22 | </> 23 | ) 24 | 25 | export default DisplayTags 26 | -------------------------------------------------------------------------------- /src/components/inputs/Tags/index.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) TotalSoft. 2 | // This source code is licensed under the MIT license. 3 | 4 | export { default as DisplayTags } from './DisplayTags' 5 | export { default as TagsInput } from './TagsInput' 6 | export * from './types' 7 | -------------------------------------------------------------------------------- /src/components/inputs/Tags/types.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) TotalSoft. 2 | // This source code is licensed under the MIT license. 3 | 4 | import { ChipProps as MuiChipPops } from '@mui/material' 5 | import { TextFieldProps } from '../TextField' 6 | 7 | export interface TagsInputProps extends Omit<MuiChipPops, 'value' | 'onChange'> { 8 | onChange: (selectedItems: string[]) => void 9 | value?: string[] 10 | placeholder?: string 11 | textFieldProps?: TextFieldProps 12 | } 13 | 14 | export type TagProps = MuiChipPops & { 15 | value: string[] 16 | } 17 | -------------------------------------------------------------------------------- /src/components/inputs/TextField/TextFieldStyles.ts: -------------------------------------------------------------------------------- 1 | import MuiTextField from '@mui/material/TextField' 2 | import Button from '@mui/material/Button' 3 | import { styled } from '@mui/material/styles' 4 | 5 | const PREFIX = 'StyledTextField' 6 | export const classes = { 7 | label: `${PREFIX}-label`, 8 | input: `${PREFIX}-input`, 9 | stepperFixedWidth: `${PREFIX}-stepper` 10 | } 11 | 12 | export const TextField = styled(MuiTextField)(({ theme }) => ({ 13 | [`& .${classes.input}`]: { 14 | '&,&::placeholder': { 15 | ...theme.typography.defaultFont, 16 | fontWeight: '400' 17 | } 18 | }, 19 | [`& .${classes.stepperFixedWidth}`]: { 20 | width: '120px' 21 | } 22 | })) 23 | 24 | export const StepButton = styled(Button)(({ theme }) => ({ 25 | fontFamily: theme.typography.fontFamily, 26 | minWidth: '28px', 27 | height: '28px', 28 | fontSize: '22px', 29 | fontWeight: 'bold', 30 | borderRadius: 'unset' 31 | })) 32 | -------------------------------------------------------------------------------- /src/components/inputs/TextField/index.ts: -------------------------------------------------------------------------------- 1 | export * from './types' 2 | import TextField from './TextField' 3 | export default TextField 4 | -------------------------------------------------------------------------------- /src/components/navigation/NavPills/index.ts: -------------------------------------------------------------------------------- 1 | export * from './types' 2 | import NavPills from './NavPills' 3 | export default NavPills 4 | -------------------------------------------------------------------------------- /src/components/navigation/Pagination/Pagination.test.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { render, userClick } from '../../../testingUtils' 3 | import { screen } from '@testing-library/react' 4 | import Pagination from './Pagination' 5 | 6 | const paginationProps = { 7 | count: 100, 8 | pageSize: 10, 9 | page: 0, 10 | rowsPerPageOptions: [10, 20], 11 | onPageChange: jest.fn(), 12 | onRowsPerPageChange: jest.fn() 13 | } 14 | 15 | describe('Pagination', () => { 16 | it('renders default rowsPerPageText', () => { 17 | render(<Pagination {...paginationProps} />) 18 | expect(screen.getByText('Rows per page:')).toBeInTheDocument() 19 | }) 20 | 21 | it('onRefresh is called', () => { 22 | const mockRefresh = jest.fn() 23 | render(<Pagination {...paginationProps} onRefresh={mockRefresh} />) 24 | const refreshButton = screen.getByTestId('RefreshIcon').parentElement 25 | userClick(refreshButton) 26 | expect(mockRefresh).toHaveBeenCalledTimes(1) 27 | }) 28 | 29 | it('renders refresh button', () => { 30 | const mockRefresh = jest.fn() 31 | render(<Pagination {...paginationProps} onRefresh={mockRefresh} />) 32 | expect(screen.getByTestId('RefreshIcon')).toBeInTheDocument() 33 | }) 34 | }) 35 | -------------------------------------------------------------------------------- /src/components/navigation/Pagination/PaginationStyles.ts: -------------------------------------------------------------------------------- 1 | import { styled } from '@mui/material/styles' 2 | 3 | export const RefreshButtonContainer = styled('div')(() => ({ 4 | marginRight: '-15px', 5 | lineHeight: 'normal' 6 | })) 7 | -------------------------------------------------------------------------------- /src/components/navigation/Pagination/index.ts: -------------------------------------------------------------------------------- 1 | import Pagination from './Pagination' 2 | export default Pagination 3 | export * from './types' -------------------------------------------------------------------------------- /src/components/navigation/SideMenu/SideMenu.test.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { act, render, screen, userClick, waitFor } from 'testingUtils' 3 | import SideMenu from './SideMenu' 4 | 5 | const content = 'content' 6 | 7 | describe('SideMenu', () => { 8 | it('doesn\'t display content by default', () => { 9 | render(<SideMenu content={content} />) 10 | expect(screen.getByText(content)).not.toBeVisible() 11 | }) 12 | 13 | it('display content when the button is clicked', async () => { 14 | render(<SideMenu content={content} />) 15 | act(() => userClick(screen.getByTestId('MenuOpenIcon').parentElement)) 16 | await waitFor(() => expect(screen.getByText(content)).toBeVisible()) 17 | }) 18 | 19 | it('hides content when clicked outside', async () => { 20 | render(<SideMenu content={content} />) 21 | const button = screen.getByTestId('MenuOpenIcon').parentElement 22 | act(() => userClick(button)) 23 | await waitFor(() => expect(screen.getByText(content)).toBeVisible()) 24 | act(() => userClick(button.parentElement.parentElement)) 25 | await waitFor(() => expect(screen.getByText(content)).not.toBeVisible()) 26 | }) 27 | }) 28 | -------------------------------------------------------------------------------- /src/components/navigation/SideMenu/index.ts: -------------------------------------------------------------------------------- 1 | import SideMenu from './SideMenu' 2 | export default SideMenu 3 | export * from './types' 4 | -------------------------------------------------------------------------------- /src/components/navigation/SideMenu/types.ts: -------------------------------------------------------------------------------- 1 | import { SvgIconComponent } from '@mui/icons-material' 2 | import { SvgIconProps } from '@mui/material' 3 | import { IconButtonProps } from 'components/buttons/IconButton' 4 | import { HTMLAttributes } from 'react' 5 | 6 | export interface SideMenuProps { 7 | /** 8 | * Content of the menu 9 | */ 10 | content?: React.ReactNode 11 | /** 12 | * @default MenuOpenIcon 13 | * Icon to be displayed on the button 14 | */ 15 | icon?: SvgIconComponent 16 | /** 17 | * Props applied to the button 18 | */ 19 | buttonProps?: IconButtonProps 20 | /** 21 | * Props applied to the content 22 | */ 23 | contentProps?: HTMLAttributes<HTMLDivElement> 24 | /** 25 | * Props applied to the icon 26 | */ 27 | iconProps?: SvgIconProps 28 | } 29 | -------------------------------------------------------------------------------- /src/components/surfaces/Accordion/Accordion.test.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { render, screen } from 'testingUtils' 3 | import Accordion from './index' 4 | 5 | const mockedContent = { title: 'Title', content: 'Details of the content' } 6 | 7 | describe('Accordion', () => { 8 | it('renders title content', () => { 9 | render(<Accordion title={mockedContent.title} expanded />) 10 | expect(screen.getByText(mockedContent.title)).toBeInTheDocument() 11 | }) 12 | 13 | it('renders details content', () => { 14 | render(<Accordion content={mockedContent.content} expanded />) 15 | expect(screen.getByText(mockedContent.content)).toBeInTheDocument() 16 | }) 17 | 18 | it('renders expand more icon', () => { 19 | render(<Accordion />) 20 | expect(screen.getByTestId('ExpandMoreIcon')).toBeInTheDocument() 21 | }) 22 | }) 23 | 24 | const mockedArrayContent = [{ title: 'Title', content: 'Details of the content' }] as { 25 | title?: string 26 | content?: string 27 | }[] 28 | 29 | describe('Accordion List', () => { 30 | it('renders title content', () => { 31 | render(<Accordion content={mockedArrayContent} canExpandAll />) 32 | expect(screen.getByText(mockedArrayContent[0].title)).toBeInTheDocument() 33 | }) 34 | 35 | it('renders details content', () => { 36 | render(<Accordion content={mockedArrayContent} defaultExpanded={0} />) 37 | expect(screen.getByText(mockedArrayContent[0].content)).toBeInTheDocument() 38 | }) 39 | }) 40 | -------------------------------------------------------------------------------- /src/components/surfaces/Accordion/AccordionStyles.ts: -------------------------------------------------------------------------------- 1 | import MuiAccordionSummary from '@mui/material/AccordionSummary' 2 | import { styled } from '@mui/material/styles' 3 | import { includes } from 'ramda' 4 | import { AccordionSummaryProps } from './types' 5 | import { Theme } from '@mui/material' 6 | 7 | type StyledProps = { theme: Theme } & AccordionSummaryProps 8 | 9 | export const AccordionSummary = styled(MuiAccordionSummary, { 10 | shouldForwardProp: prop => !includes(prop, ['variant']) 11 | })(({ theme, variant }: StyledProps) => ({ 12 | ...(variant === 'filled' && { backgroundColor: theme.palette.grey[200] }) 13 | })) 14 | -------------------------------------------------------------------------------- /src/components/surfaces/Accordion/index.ts: -------------------------------------------------------------------------------- 1 | import Accordion from './Accordion' 2 | export default Accordion 3 | export * from './types' 4 | -------------------------------------------------------------------------------- /src/components/surfaces/Card/CardActions/CardActions.test.tsx: -------------------------------------------------------------------------------- 1 | import getTheme from '../../../themes' 2 | import React from 'react' 3 | import { render, screen } from 'testingUtils' 4 | import CardActions from './CardActions' 5 | import Button from '../../../buttons/Button' 6 | 7 | const theme = getTheme() 8 | 9 | describe('CardActions', () => { 10 | it('when `filled` property is set, teh card has a grey background color', () => { 11 | render( 12 | <CardActions filled> 13 | <Button>ok</Button> 14 | </CardActions> 15 | ) 16 | expect(screen.getByRole('button').parentElement).toHaveStyle(`background-color: ${theme.palette.grey[200]}`) 17 | }) 18 | 19 | it('has `standard` variant by default', () => { 20 | render( 21 | <CardActions> 22 | <Button>ok</Button> 23 | </CardActions> 24 | ) 25 | expect(screen.getByRole('button').parentElement).not.toHaveStyle(`background-color: ${theme.palette.grey[200]}`) 26 | }) 27 | 28 | it('displays actions on the left by default', () => { 29 | render( 30 | <CardActions> 31 | <Button>ok</Button> 32 | </CardActions> 33 | ) 34 | expect(screen.getByRole('button').parentElement).toHaveStyle('justify-content: unset') 35 | }) 36 | 37 | it('displays actions on the right when `align` is set to `right`', () => { 38 | render( 39 | <CardActions align="right"> 40 | <Button>ok</Button> 41 | </CardActions> 42 | ) 43 | expect(screen.getByRole('button').parentElement).toHaveStyle('justify-content: flex-end') 44 | }) 45 | }) 46 | -------------------------------------------------------------------------------- /src/components/surfaces/Card/CardActions/CardActions.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PropTypes from 'prop-types' 3 | import MuiCardActions from './CardActionsStyles' 4 | import { CardActionsProps } from '../types' 5 | 6 | const CardActions: React.FC<CardActionsProps> = props => { 7 | return <MuiCardActions {...props} /> 8 | } 9 | 10 | CardActions.propTypes = { 11 | /** 12 | * If 'true', the card footer will be filled with a grayish color 13 | * @default false 14 | */ 15 | filled: PropTypes.bool, 16 | /** 17 | * Align actions. 18 | * @default 'left' 19 | */ 20 | align: PropTypes.oneOf(['left', 'right', 'center']) 21 | } 22 | 23 | export default CardActions 24 | -------------------------------------------------------------------------------- /src/components/surfaces/Card/CardActions/CardActionsStyles.ts: -------------------------------------------------------------------------------- 1 | import { Theme } from '@mui/material' 2 | import MuiCardActions from '@mui/material/CardActions' 3 | import { styled } from '@mui/material/styles' 4 | import { T, always, cond, equals, includes } from 'ramda' 5 | import { ActionAlign } from '../types' 6 | 7 | type StyledProps = { theme: Theme; filled: boolean; align: ActionAlign } 8 | 9 | const contentAlignment = cond([ 10 | [equals('left'), always('flex-start')], 11 | [equals('right'), always('flex-end')], 12 | [equals('center'), always('center')], 13 | [T, always('unset')] 14 | ]) 15 | 16 | const CardActions = styled(MuiCardActions, { 17 | shouldForwardProp: prop => !includes(prop, ['align', 'filled']) 18 | })(({ theme, filled, align }: Partial<StyledProps>) => ({ 19 | ...(filled && { 20 | backgroundColor: theme?.palette.grey[200], 21 | minHeight: '48px', 22 | padding: theme?.spacing(2, 3) 23 | }), 24 | justifyContent: contentAlignment(align) 25 | })) 26 | 27 | export default CardActions 28 | -------------------------------------------------------------------------------- /src/components/surfaces/Card/CardActions/index.ts: -------------------------------------------------------------------------------- 1 | import CardActions from './CardActions' 2 | export default CardActions 3 | -------------------------------------------------------------------------------- /src/components/surfaces/Card/CardHeader/CardHeader.test.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { render, screen } from 'testingUtils' 3 | import CardHeader from './CardHeader' 4 | import getTheme from '../../../themes' 5 | import Button from '../../../buttons/Button' 6 | 7 | const theme = getTheme() 8 | 9 | const title = 'Title' 10 | 11 | describe('CardHeader', () => { 12 | it('when `filled` property is set, the card has a grey background color', () => { 13 | render(<CardHeader filled title={title} />) 14 | expect(screen.getByText(title)?.parentElement?.parentElement?.parentElement).toHaveStyle( 15 | `background-color: ${theme.palette.grey[200]}` 16 | ) 17 | }) 18 | 19 | it('has `elevation` variant by default', () => { 20 | render(<CardHeader title={title} />) 21 | expect(screen.getByText(title)?.parentElement?.parentElement).not.toHaveStyle( 22 | `background-color: ${theme.palette.grey[200]}` 23 | ) 24 | }) 25 | 26 | it('when `actions` is not an array, renders the node as it is', () => { 27 | render(<CardHeader actions={<Button key={1}>one</Button>} />) 28 | expect(screen.getByRole('button')).toBeInTheDocument() 29 | }) 30 | }) 31 | -------------------------------------------------------------------------------- /src/components/surfaces/Card/CardHeader/CardHeader.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PropTypes from 'prop-types' 3 | import MuiCardHeader from './CardHeaderStyles' 4 | import { isValidElement } from 'react' 5 | import Typography from '../../../dataDisplay/Typography' 6 | import { CardHeaderProps } from '../types' 7 | 8 | const CardHeader: React.FC<CardHeaderProps> = ({ actions, title, ...rest }) => { 9 | return ( 10 | <MuiCardHeader 11 | action={actions} 12 | title={ 13 | title ? ( 14 | isValidElement(title) ? ( 15 | title 16 | ) : ( 17 | <Typography variant="subtitle1" emphasis="bold"> 18 | {title} 19 | </Typography> 20 | ) 21 | ) : undefined 22 | } 23 | {...rest} 24 | /> 25 | ) 26 | } 27 | 28 | CardHeader.propTypes = { 29 | /** 30 | * Actions to be displayed in the right corner of the card. If an array, will display all items with spacing between them. 31 | */ 32 | actions: PropTypes.node, 33 | /** 34 | * Card title 35 | */ 36 | title: PropTypes.node, 37 | /** 38 | * Indicates if the parent Card component contains an icon element or not 39 | */ 40 | hasIcon: PropTypes.bool, 41 | /** 42 | * @default 'secondary' 43 | * Icon color. 44 | */ 45 | iconColor: PropTypes.oneOf(['primary', 'secondary', 'info', 'success', 'warning', 'error', 'rose']), 46 | /** 47 | * If 'true', the card header will be filled with a grayish color 48 | * @default false 49 | */ 50 | filled: PropTypes.bool 51 | } 52 | 53 | export default CardHeader 54 | -------------------------------------------------------------------------------- /src/components/surfaces/Card/CardHeader/CardHeaderStyles.ts: -------------------------------------------------------------------------------- 1 | import { Palette, Theme } from '@mui/material' 2 | import MuiCardHeader from '@mui/material/CardHeader' 3 | import { styled } from '@mui/material/styles' 4 | import { includes } from 'ramda' 5 | import { CardColor } from '../types' 6 | 7 | type StyledProps = { 8 | theme: Theme 9 | filled: boolean 10 | hasIcon: boolean 11 | iconColor: CardColor 12 | avatarProps: any 13 | headerContentProps: any 14 | } 15 | 16 | const CardHeader = styled(MuiCardHeader, { 17 | shouldForwardProp: prop => 18 | !includes(prop, ['variant', 'hasIcon', 'iconColor', 'filled', 'avatarProps', 'headerContentProps']) 19 | })( 20 | ({ 21 | theme, 22 | filled, 23 | hasIcon, 24 | iconColor = 'secondary' as CardColor & keyof Palette, 25 | avatarProps, 26 | headerContentProps 27 | }: Partial<StyledProps>) => ({ 28 | ['&.MuiCardHeader-root']: { 29 | ...(filled && { backgroundColor: theme?.palette.grey[200], minHeight: '48px' }) 30 | }, 31 | ['& .MuiCardHeader-avatar']: { 32 | ...(hasIcon && { 33 | width: '3rem', 34 | height: '3rem', 35 | borderRadius: '0.75rem', 36 | background: `linear-gradient(195deg, ${theme?.palette[iconColor].light}, ${theme?.palette[iconColor].main})`, 37 | position: 'absolute', 38 | top: '-20px', 39 | ...avatarProps 40 | }) 41 | }, 42 | ['& .MuiCardHeader-content']: { 43 | ...(hasIcon && { 44 | paddingLeft: '80px' 45 | }), 46 | ...headerContentProps 47 | }, 48 | ['& .MuiCardHeader-action']: { 49 | gap: '0.5rem', 50 | display: 'flex', 51 | flex: '0 1 auto', 52 | flexWrap: 'wrap', 53 | justifyContent: 'flex-end' 54 | } 55 | }) 56 | ) 57 | 58 | export default CardHeader 59 | -------------------------------------------------------------------------------- /src/components/surfaces/Card/CardHeader/index.ts: -------------------------------------------------------------------------------- 1 | import CardHeader from './CardHeader' 2 | export default CardHeader 3 | -------------------------------------------------------------------------------- /src/components/surfaces/Card/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Card } from './Card' 2 | export { default as CardActions } from './CardActions' 3 | export { default as CardHeader } from './CardHeader' 4 | export * from './types' 5 | -------------------------------------------------------------------------------- /src/components/surfaces/CollapseCard/index.ts: -------------------------------------------------------------------------------- 1 | export * from './types' 2 | import CollapseCard from './CollapseCard' 3 | export default CollapseCard 4 | -------------------------------------------------------------------------------- /src/components/surfaces/CollapseCard/types.ts: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { CardProps } from '../Card' 3 | 4 | export interface CollapseCardProps extends Omit<CardProps, 'content' | 'onToggle'> { 5 | /** 6 | * Content of the component. 7 | */ 8 | content?: React.ReactNode 9 | /** 10 | * Content of the subheader. 11 | */ 12 | subheader?: React.ReactNode 13 | /** 14 | * If true, the card will be expanded by default. 15 | * @default false 16 | */ 17 | defaultExpanded?: boolean 18 | /** 19 | * If true, the card will be expanded. 20 | */ 21 | expanded?: boolean 22 | /** 23 | * If true, the card can be expanded. 24 | * @deprecated Use `Card` component instead 25 | */ 26 | canExpand?: boolean 27 | /** 28 | * Callback fired on toggle. 29 | */ 30 | onToggle?: (event: React.SyntheticEvent, expanded: boolean) => void 31 | /** 32 | * If true, the subheader will be hidden when the card is expanded. 33 | */ 34 | hideSubheaderOnExpand?: boolean 35 | /** 36 | * If true, the card will toggle when clicking on the whole header, not just the expand button. 37 | */ 38 | toggleOnHeaderClick?: boolean 39 | } 40 | -------------------------------------------------------------------------------- /src/components/surfaces/StatsCard/StatsCard.test.tsx: -------------------------------------------------------------------------------- 1 | import { Button, StatsCard, getTheme } from '../../index' 2 | import React from 'react' 3 | import { render, screen } from 'testingUtils' 4 | import AttachMoneyIcon from '@mui/icons-material/AttachMoney' 5 | 6 | const theme = getTheme() 7 | 8 | describe('StatsCard', () => { 9 | it('renders footer', () => { 10 | render(<StatsCard footer={<Button />} />) 11 | expect(screen.getByRole('button')).toBeInTheDocument() 12 | }) 13 | 14 | it('renders card header', () => { 15 | const title = 'StatsCard title' 16 | const description = 'StatsCard description' 17 | 18 | render(<StatsCard title={title} description={description} />) 19 | 20 | expect(screen.getByText(title)).toBeInTheDocument() 21 | expect(screen.getByText(description)).toBeInTheDocument() 22 | }) 23 | 24 | it('when `icon` is received, applies a background of `iconColor`', () => { 25 | const iconColor = 'warning' 26 | render(<StatsCard icon={AttachMoneyIcon} />) 27 | expect(screen.getByTestId('AttachMoneyIcon').parentElement).toHaveStyle( 28 | `background: linear-gradient(195deg, ${theme.palette[iconColor].light}, ${theme.palette[iconColor].main})` 29 | ) 30 | }) 31 | 32 | it('has `standard` variant by default', () => { 33 | render(<StatsCard footer={<Button>ok</Button>} />) 34 | expect(screen.getByRole('button').parentElement).not.toHaveStyle(`background-color: ${theme.palette.grey[200]}`) 35 | }) 36 | 37 | it('has iconColor set to info by default', () => { 38 | render(<StatsCard icon={AttachMoneyIcon} />) 39 | expect(screen.getByTestId('AttachMoneyIcon').parentElement).toHaveStyle( 40 | `background: linear-gradient(195deg, ${theme.palette['info'].light}, ${theme.palette['info'].main})` 41 | ) 42 | }) 43 | }) 44 | -------------------------------------------------------------------------------- /src/components/surfaces/StatsCard/StatsCardStyles.ts: -------------------------------------------------------------------------------- 1 | import MuiCardContent from '@mui/material/CardContent' 2 | import { styled } from '@mui/material/styles' 3 | import { Card, CardActions, CardHeader, Typography } from '../../index' 4 | 5 | export const StyledCard = styled(Card)(({ theme }) => ({ 6 | display: 'inline-block', 7 | position: 'relative', 8 | width: '100%', 9 | minWidth: '150%', 10 | margin: '25px 0', 11 | boxShadow: '0 1px 4px 0 rgba(0, 0, 0, 0.14)', 12 | borderRadius: '6px', 13 | color: theme.palette.primary.main, 14 | background: '#fff', 15 | overflow: 'visible' 16 | })) 17 | 18 | export const StyledCardHeader = styled(CardHeader)(() => ({ 19 | paddingTop: '5px' 20 | })) 21 | 22 | export const CardContent = styled(MuiCardContent)(() => ({ 23 | textAlign: 'right', 24 | fontSize: '10px', 25 | paddingTop: '10px', 26 | padding: '2px 10px' 27 | })) 28 | 29 | export const StyledCardActions = styled(CardActions)(({ theme }) => ({ 30 | margin: '0 20px 10px', 31 | height: 'auto', 32 | padding: '2px 0 0 0', 33 | ...theme.typography.defaultFont 34 | })) 35 | 36 | export const CardTitle = styled(Typography)(({ theme }) => ({ 37 | marginBottom: '0', 38 | color: theme.palette.grey[500], 39 | margin: '0 0 5px' 40 | })) 41 | 42 | export const CardDescription = styled(Typography)(() => ({ 43 | margin: '0' 44 | })) 45 | 46 | export const iconStyle = { 47 | color: '#FFFFFF', 48 | width: '2.5rem', 49 | height: '2.5rem', 50 | margin: 'auto', 51 | padding: '2px' 52 | } 53 | -------------------------------------------------------------------------------- /src/components/surfaces/StatsCard/index.ts: -------------------------------------------------------------------------------- 1 | export * from './types' 2 | import StatsCard from './StatsCard' 3 | export default StatsCard 4 | -------------------------------------------------------------------------------- /src/components/surfaces/StatsCard/types.ts: -------------------------------------------------------------------------------- 1 | import { SvgIconComponent } from '@mui/icons-material' 2 | import type { CardActionsProps, CardColor, CardHeaderProps, CardVariant } from '../../index' 3 | 4 | export interface StatsCardProps { 5 | /** 6 | * Icon to be displayed. 7 | */ 8 | icon?: SvgIconComponent 9 | /** 10 | * @default 'info' 11 | * Icon color. 12 | */ 13 | iconColor?: CardColor 14 | /** 15 | * Content of the title. 16 | */ 17 | title?: React.ReactNode 18 | /** 19 | * Content of the description. 20 | */ 21 | description?: React.ReactNode 22 | /** 23 | * Footer to be displayed at the bottom of the card. 24 | */ 25 | footer?: React.ReactNode 26 | /** 27 | * @default 'elevation' 28 | * Variant to use. 29 | */ 30 | variant?: CardVariant 31 | /** 32 | * Shadow depth, corresponds to `dp` in the spec. 33 | * It accepts values between 0 and 24 inclusive. 34 | * @default 1 35 | */ 36 | elevation?: number 37 | /** 38 | * Props applied to the CardActions component. 39 | */ 40 | footerProps?: CardActionsProps 41 | /** 42 | * @default {} 43 | * Props applied to the CardHeader component. 44 | */ 45 | headerProps?: CardHeaderProps 46 | } 47 | -------------------------------------------------------------------------------- /src/components/themes/blueTheme.ts: -------------------------------------------------------------------------------- 1 | import { PaletteOptions, Theme, ThemeOptions, createTheme } from '@mui/material' 2 | import componentsOverride from './common/overrides' 3 | import generatePalette from './common/palette' 4 | import { generateTypography } from './common/typography' 5 | import { generateShadows, generateCustomShadows } from './common/shadows' 6 | import table from './common/table' 7 | 8 | const palette = generatePalette({ 9 | primary: { 10 | lighter: '#81b8f8', 11 | light: '#4c88c5', 12 | main: '#00497b', 13 | dark: '#003266', 14 | darker: '#000a3b', 15 | contrastText: '#fff', 16 | rgba: 'rgba(0, 91, 148, 1)' 17 | }, 18 | secondary: { 19 | lighter: '#99c0ed', 20 | light: '#66a1e5', 21 | main: '#3382DC', 22 | dark: '#1e61ad', 23 | darker: '#144174', 24 | contrastText: '#fff', 25 | rgba: 'rgba(51, 130, 220, 1)' 26 | }, 27 | background: { 28 | default: '#F5F8FA', 29 | paper: '#fff' 30 | }, 31 | sideMenu: { 32 | bgColor: '#BCE4FA', 33 | color: '#00385F', 34 | hoverBgColor: '#DFF2FD', 35 | hoverTextColor: '#00385F', 36 | bgOpacity: '1', 37 | activeBgColor: '#00497b' 38 | } 39 | } as PaletteOptions) 40 | 41 | const blueTheme: Theme = createTheme({ 42 | palette, 43 | shape: { borderRadius: 8 }, 44 | typography: generateTypography(palette), 45 | table, 46 | shadows: generateShadows(palette), 47 | customShadows: generateCustomShadows(palette) 48 | } as ThemeOptions) 49 | 50 | blueTheme.components = componentsOverride(blueTheme) 51 | 52 | export default blueTheme 53 | -------------------------------------------------------------------------------- /src/components/themes/common/overrides/Autocomplete.ts: -------------------------------------------------------------------------------- 1 | import { Theme } from '@mui/material/styles' 2 | import { CustomComponents } from '../../types' 3 | 4 | export default function Autocomplete(theme: Theme): CustomComponents { 5 | return { 6 | MuiAutocomplete: { 7 | styleOverrides: { 8 | inputRoot: (props: any) => 9 | !props.ownerState.multiple && { 10 | '& .MuiAutocomplete-input': { 11 | width: 'fit-content', 12 | minWidth: 'fit-content' 13 | } 14 | }, 15 | input: { 16 | display: 'flex', 17 | whiteSpace: 'nowrap' 18 | }, 19 | noOptions: { 20 | ...theme.typography.defaultFont, 21 | padding: `${theme.spacing()}px ${theme.spacing(2)}px`, 22 | color: 'textSecondary' 23 | }, 24 | option: { 25 | div: { 26 | ...theme.typography.defaultFont, 27 | display: 'block', 28 | whiteSpace: 'nowrap', 29 | overflow: 'hidden', 30 | textOverflow: 'ellipsis', 31 | width: '100%' 32 | } 33 | } 34 | } 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/components/themes/common/overrides/Button.ts: -------------------------------------------------------------------------------- 1 | import { Theme } from '@mui/material' 2 | import { CustomComponents } from '../../types' 3 | 4 | export default function Button({ palette, customShadows }: Theme): CustomComponents { 5 | return { 6 | MuiButton: { 7 | styleOverrides: { 8 | root: { 9 | borderRadius: '8px', 10 | '&:hover': { 11 | boxShadow: 'none' 12 | } 13 | }, 14 | sizeTiny: {}, // adds the 'tiny' size prop type which is not present in MUI 15 | sizeLarge: { 16 | height: 48 17 | }, 18 | containedInherit: { 19 | color: palette.grey[800], 20 | boxShadow: customShadows.z8, 21 | '&:hover': { 22 | backgroundColor: palette.grey[400] 23 | } 24 | }, 25 | outlinedInherit: { 26 | border: `1px solid ${palette.grey[500_32]}`, 27 | '&:hover': { 28 | backgroundColor: palette.action.hover 29 | } 30 | }, 31 | textInherit: { 32 | '&:hover': { 33 | backgroundColor: palette.action.hover 34 | } 35 | } 36 | } 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/components/themes/common/overrides/Card.ts: -------------------------------------------------------------------------------- 1 | import { Theme } from '@mui/material' 2 | import { CustomComponents } from '../../types' 3 | 4 | export default function Card(theme: Theme): CustomComponents { 5 | return { 6 | MuiCard: { 7 | styleOverrides: { 8 | root: { 9 | boxShadow: theme.shadows[5], 10 | borderRadius: Number(theme.shape.borderRadius) * 2, 11 | position: 'relative', 12 | zIndex: 0 // Fix Safari overflow: hidden with border radius 13 | } 14 | } 15 | }, 16 | MuiCardHeader: { 17 | defaultProps: { 18 | titleTypographyProps: { variant: 'h6' }, 19 | subheaderTypographyProps: { variant: 'body2' } 20 | }, 21 | styleOverrides: { 22 | root: { 23 | padding: theme.spacing(2, 3) 24 | }, 25 | content: { 26 | maxWidth: `calc(100% - ${theme.spacing(4)})` 27 | }, 28 | title: { 29 | whiteSpace: 'nowrap', 30 | overflow: 'hidden', 31 | textOverflow: 'ellipsis' 32 | } 33 | } 34 | }, 35 | MuiCardContent: { 36 | styleOverrides: { 37 | root: { 38 | padding: theme.spacing(1, 3, 3, 3) 39 | } 40 | } 41 | }, 42 | MuiCardActions: { 43 | styleOverrides: { 44 | root: { 45 | padding: theme.spacing(0, 3, 3) 46 | } 47 | } 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/components/themes/common/overrides/Chip.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) TotalSoft. 2 | // This source code is licensed under the MIT license. 3 | 4 | import { Theme } from '@mui/material' 5 | import { CustomComponents } from '../../types' 6 | 7 | export default function Chip(theme: Theme): CustomComponents { 8 | return { 9 | MuiChip: { 10 | styleOverrides: { 11 | root: { 12 | margin: theme.spacing(0.5, 0.25) 13 | }, 14 | deleteIcon: { 15 | variants: [ 16 | { 17 | props: { variant: 'filled' }, 18 | style: { 19 | color: 'white' 20 | } 21 | }, 22 | { 23 | props: { variant: 'filled', color: 'default' }, 24 | style: { 25 | color: theme.palette.grey[700], 26 | ':hover': { color: theme.palette.grey[900] } 27 | } 28 | } 29 | ] 30 | } 31 | }, 32 | variants: [ 33 | { 34 | props: { variant: 'filled', color: 'default' }, 35 | style: { 36 | color: theme.palette.grey[900], 37 | backgroundColor: theme.palette.grey[300] 38 | } 39 | } 40 | ] 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/components/themes/common/overrides/Divider.ts: -------------------------------------------------------------------------------- 1 | import { CustomComponents } from '../../types' 2 | 3 | export default function Divider(): CustomComponents { 4 | return { 5 | MuiDivider: { 6 | styleOverrides: { 7 | root: { 8 | borderTop: '0px solid rgba(0, 0, 0, 0.12)', 9 | borderRight: '0px solid rgba(0, 0, 0, 0.12)', 10 | borderLeft: '0px solid rgba(0, 0, 0, 0.12)', 11 | borderBottom: 'none', 12 | margin: '1rem 0px', 13 | height: '0.0625rem', 14 | width: '100%', 15 | backgroundColor: 'transparent', 16 | backgroundImage: 'linear-gradient(to right, rgba(52, 71, 103, 0), rgba(52, 71, 103, 0.4), rgba(52, 71, 103, 0))', 17 | opacity: '0.45' 18 | }, 19 | vertical: { 20 | borderTop: '0px solid rgba(0, 0, 0, 0.12)', 21 | borderRight: '0px solid rgba(0, 0, 0, 0.12)', 22 | borderLeft: '0px solid rgba(0, 0, 0, 0.12)', 23 | borderBottom: 'none', 24 | margin: '0px 1rem', 25 | width: '0.0625rem', 26 | height: '100%', 27 | backgroundColor: 'transparent', 28 | backgroundImage: 'linear-gradient(rgba(52, 71, 103, 0), rgba(52, 71, 103, 0.4), rgba(52, 71, 103, 0))', 29 | opacity: '0.45' 30 | } 31 | } 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/components/themes/common/overrides/TextField.ts: -------------------------------------------------------------------------------- 1 | import { Theme } from '@mui/material/styles' 2 | import { CustomComponents } from '../../types' 3 | 4 | export default function TextField(theme: Theme): CustomComponents { 5 | return { 6 | MuiFormHelperText: { 7 | styleOverrides: { 8 | root: { 9 | '&.Mui-error': { 10 | marginTop: 0, 11 | lineHeight: 1 12 | } 13 | } 14 | } 15 | }, 16 | MuiTextField: { 17 | defaultProps: { 18 | variant: 'standard' 19 | }, 20 | styleOverrides: { 21 | root: { 22 | ...theme.typography.defaultFont 23 | } 24 | } 25 | }, 26 | MuiInput: { 27 | styleOverrides: { 28 | root: { 29 | ...theme.typography.defaultFont, 30 | fontWeight: '400' 31 | } 32 | } 33 | }, 34 | MuiInputLabel: { 35 | styleOverrides: { 36 | root: { 37 | ...theme.typography.defaultFont, 38 | fontWeight: '400', 39 | lineHeight: '1.42857' 40 | } 41 | } 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/components/themes/common/overrides/index.ts: -------------------------------------------------------------------------------- 1 | import Card from './Card' 2 | import Button from './Button' 3 | import Divider from './Divider' 4 | import TextField from './TextField' 5 | import { Theme } from '@mui/material' 6 | import { CustomComponents } from '../../types' 7 | import Autocomplete from './Autocomplete' 8 | import Chip from './Chip' 9 | 10 | const componentsOverride = (theme: Theme): CustomComponents => ({ 11 | ...Card(theme), 12 | ...Button(theme), 13 | ...Divider(), 14 | ...TextField(theme), 15 | ...Autocomplete(theme), 16 | ...Chip(theme) 17 | }) 18 | export default componentsOverride 19 | -------------------------------------------------------------------------------- /src/components/themes/common/table.ts: -------------------------------------------------------------------------------- 1 | const table = { 2 | main: { 3 | marginTop: '15px', 4 | marginBottom: '15px', 5 | borderSpacing: 0 6 | }, 7 | tableHeader: { 8 | textAlign: 'left', 9 | backgroundColor: '#00497b', 10 | padding: '10px', 11 | borderBottom: '1px solid #ddd', 12 | color: 'white' 13 | }, 14 | tableContent: { 15 | textAlign: 'left', 16 | padding: '10px ', 17 | borderBottom: '1px solid #eee' 18 | }, 19 | itemSelected: { 20 | background: '#c1c1c1', 21 | color: 'white' 22 | } 23 | } 24 | 25 | export default table 26 | -------------------------------------------------------------------------------- /src/components/themes/common/typography.ts: -------------------------------------------------------------------------------- 1 | import { PaletteOptions } from '@mui/material' 2 | import { TypographyOptions } from '@mui/material/styles/createTypography' 3 | 4 | export const defaultFont = { 5 | fontFamily: 'Source Sans Pro', 6 | fontSize: 14, 7 | lineHeight: '1.5em', 8 | fontWeight: '300', 9 | letterSpacing: '0.02857em' 10 | } 11 | 12 | export const generateTypography = (palette: PaletteOptions) => 13 | ({ 14 | ...defaultFont, 15 | defaultFont, 16 | useNextVariants: true, 17 | htmlFontSize: 14, 18 | fontWeightMedium: 300, 19 | button: { 20 | ...defaultFont, 21 | textAlign: 'center', 22 | fontStretch: 'normal', 23 | fontStyle: 'normal' 24 | }, 25 | body: defaultFont, 26 | header: { 27 | title: { 28 | borderRadius: '3px', 29 | textTransform: 'none', 30 | fontWeight: 'bold', 31 | color: palette.primary.main, 32 | '&:hover,&:focus': { 33 | background: 'transparent' 34 | } 35 | } 36 | } 37 | } as TypographyOptions) 38 | -------------------------------------------------------------------------------- /src/components/themes/defaultTheme.ts: -------------------------------------------------------------------------------- 1 | import { PaletteOptions, Theme, ThemeOptions, createTheme } from '@mui/material' 2 | import componentsOverride from './common/overrides' 3 | import generatePalette from './common/palette' 4 | import { generateTypography } from './common/typography' 5 | import { generateShadows, generateCustomShadows } from './common/shadows' 6 | import table from './common/table' 7 | 8 | const palette = generatePalette({ 9 | primary: { 10 | lighter: '#b0b0b0', 11 | light: '#818181', 12 | main: '#555555', 13 | dark: '#2c2c2c', 14 | darker: '#000000', 15 | contrastText: '#fff', 16 | rgba: 'rgba(85, 85, 85, 1)' 17 | }, 18 | secondary: { 19 | lighter: '#a8ffff', 20 | light: '#6ff9ff', 21 | main: '#26C6DA', 22 | dark: '#0095a8', 23 | darker: '#006779', 24 | contrastText: '#fff', 25 | rgba: 'rgba(38, 198, 218, 1)' 26 | }, 27 | background: { 28 | default: '#fff', 29 | paper: '#fff' 30 | }, 31 | sideMenu: { 32 | bgColor: '#000000d9', 33 | color: '#fff', 34 | hoverBgColor: 'rgba(200, 200, 200, 0.2)', 35 | hoverTextColor: '#fff', 36 | bgOpacity: '0.8', 37 | activeBgColor: '#26C6DA' 38 | } 39 | } as PaletteOptions) 40 | 41 | const defaultTheme: Theme = createTheme({ 42 | palette, 43 | shape: { borderRadius: 8 }, 44 | typography: generateTypography(palette), 45 | table, 46 | shadows: generateShadows(palette), 47 | customShadows: generateCustomShadows(palette) 48 | } as ThemeOptions) 49 | 50 | defaultTheme.components = componentsOverride(defaultTheme) 51 | 52 | export default defaultTheme 53 | -------------------------------------------------------------------------------- /src/components/themes/greenTheme.ts: -------------------------------------------------------------------------------- 1 | import { PaletteOptions, Theme, ThemeOptions, createTheme } from '@mui/material' 2 | import componentsOverride from './common/overrides' 3 | import generatePalette from './common/palette' 4 | import { generateTypography } from './common/typography' 5 | import { generateShadows, generateCustomShadows } from './common/shadows' 6 | import table from './common/table' 7 | 8 | const palette = generatePalette({ 9 | primary: { 10 | lighter: '#9dffd4', 11 | light: '#67eaa2', 12 | main: '#005604', 13 | dark: '#008647', 14 | darker: '#00581e', 15 | contrastText: '#fff', 16 | rgba: 'rgba(38, 198, 218, 1)' 17 | }, 18 | secondary: { 19 | lighter: '#6db45f', 20 | light: '#3d8433', 21 | main: '#2ab773', 22 | dark: '#002c00', 23 | darker: '#003000', 24 | contrastText: '#fff', 25 | rgba: 'rgb(39 108 37)' 26 | }, 27 | background: { 28 | default: '#eff7f0', 29 | paper: '#fff' 30 | }, 31 | sideMenu: { 32 | bgColor: '#7eb58b', 33 | color: '#005604', 34 | hoverBgColor: 'rgb(239,247,240, 0.5)', 35 | hoverTextColor: '#005604', 36 | bgOpacity: '0.8', 37 | focusBgColor: '#2a912f', 38 | activeBgColor: '#005604' 39 | } 40 | } as PaletteOptions) 41 | 42 | const greenTheme: Theme = createTheme({ 43 | palette, 44 | shape: { borderRadius: 8 }, 45 | typography: generateTypography(palette), 46 | table, 47 | shadows: generateShadows(palette), 48 | customShadows: generateCustomShadows(palette) 49 | } as ThemeOptions) 50 | 51 | greenTheme.components = componentsOverride(greenTheme) 52 | 53 | export default greenTheme 54 | -------------------------------------------------------------------------------- /src/components/themes/index.ts: -------------------------------------------------------------------------------- 1 | import defaultTheme from './defaultTheme' 2 | import blueTheme from './blueTheme' 3 | import greenTheme from './greenTheme' 4 | import lightBlueTheme from './lightBlueTheme' 5 | import orangeTheme from './orangeTheme' 6 | import redTheme from './redTheme' 7 | import vividOrangeTheme from './vividOrangeTheme' 8 | import { Theme } from '@mui/material' 9 | 10 | const defaultCtx = { globals: { theme: 'default' } } 11 | const getTheme = (context = defaultCtx): Theme => { 12 | switch (context.globals.theme) { 13 | case 'green': 14 | return greenTheme 15 | case 'blue': 16 | return blueTheme 17 | case 'orange': 18 | return orangeTheme 19 | case 'red': 20 | return redTheme 21 | case 'vividOrange': 22 | return vividOrangeTheme 23 | case 'lightBlue': 24 | return lightBlueTheme 25 | default: 26 | return defaultTheme 27 | } 28 | } 29 | 30 | export default getTheme 31 | export { defaultTheme, blueTheme, greenTheme, lightBlueTheme, orangeTheme, redTheme, vividOrangeTheme } 32 | -------------------------------------------------------------------------------- /src/components/themes/lightBlueTheme.ts: -------------------------------------------------------------------------------- 1 | import { PaletteOptions, Theme, ThemeOptions, createTheme } from '@mui/material' 2 | import componentsOverride from './common/overrides' 3 | import generatePalette from './common/palette' 4 | import { generateTypography } from './common/typography' 5 | import { generateShadows, generateCustomShadows } from './common/shadows' 6 | import table from './common/table' 7 | 8 | const palette = generatePalette({ 9 | primary: { 10 | lighter: '#86adff', 11 | light: '#507ed1', 12 | main: '#00529f', 13 | dark: '#002b70', 14 | darker: '#000044', 15 | contrastText: '#fff', 16 | rgba: 'rgba(0, 82, 159, 1)' 17 | }, 18 | secondary: { 19 | lighter: '#99bffb', 20 | light: '#669ff9', 21 | main: '#337FF7', 22 | dark: '#0859d7', 23 | darker: '#063a8d', 24 | contrastText: '#fff', 25 | rgba: 'rgba(51, 127, 247, 1)' 26 | }, 27 | background: { 28 | default: '#efeff8', 29 | paper: '#fff' 30 | }, 31 | sideMenu: { 32 | bgColor: '#fff', 33 | color: '#00529f', 34 | hoverBgColor: '#DFF2FD', 35 | hoverTextColor: '#00529f', 36 | bgOpacity: '1', 37 | activeBgColor: '#00529f' 38 | } 39 | } as PaletteOptions) 40 | 41 | const lightBlueTheme: Theme = createTheme({ 42 | palette, 43 | shape: { borderRadius: 8 }, 44 | typography: generateTypography(palette), 45 | table, 46 | shadows: generateShadows(palette), 47 | customShadows: generateCustomShadows(palette) 48 | } as ThemeOptions) 49 | 50 | lightBlueTheme.components = componentsOverride(lightBlueTheme) 51 | 52 | export default lightBlueTheme 53 | -------------------------------------------------------------------------------- /src/components/themes/orangeTheme.ts: -------------------------------------------------------------------------------- 1 | import { PaletteOptions, Theme, ThemeOptions, createTheme } from '@mui/material' 2 | import componentsOverride from './common/overrides' 3 | import generatePalette from './common/palette' 4 | import { generateTypography } from './common/typography' 5 | import { generateShadows, generateCustomShadows } from './common/shadows' 6 | import table from './common/table' 7 | 8 | const palette = generatePalette({ 9 | primary: { 10 | lighter: '#b0b0b0', 11 | light: '#818181', 12 | main: '#555555', 13 | dark: '#2c2c2c', 14 | darker: '#000000', 15 | contrastText: '#fff', 16 | rgba: 'rgba(85, 85, 85, 1)' 17 | }, 18 | secondary: { 19 | lighter: '#ffd170', 20 | light: '#ffa040', 21 | main: '#FF6F00', 22 | dark: '#c43e00', 23 | darker: '#8c0000', 24 | contrastText: '#fff', 25 | rgba: 'rgba(255, 111, 0)' 26 | }, 27 | background: { 28 | default: '#fff', 29 | paper: '#fff' 30 | }, 31 | sideMenu: { 32 | bgColor: '#000000d9', 33 | color: '#fff', 34 | hoverBgColor: 'rgba(200, 200, 200, 0.2)', 35 | hoverTextColor: '#fff', 36 | bgOpacity: '0.8', 37 | activeBgColor: '#FF6F00' 38 | } 39 | } as PaletteOptions) 40 | 41 | const orangeTheme: Theme = createTheme({ 42 | palette, 43 | shape: { borderRadius: 8 }, 44 | typography: generateTypography(palette), 45 | table, 46 | shadows: generateShadows(palette), 47 | customShadows: generateCustomShadows(palette) 48 | } as ThemeOptions) 49 | 50 | orangeTheme.components = componentsOverride(orangeTheme) 51 | 52 | export default orangeTheme 53 | -------------------------------------------------------------------------------- /src/components/themes/redTheme.ts: -------------------------------------------------------------------------------- 1 | import { PaletteOptions, Theme, ThemeOptions, createTheme } from '@mui/material' 2 | import componentsOverride from './common/overrides' 3 | import generatePalette from './common/palette' 4 | import { generateTypography } from './common/typography' 5 | import { generateShadows, generateCustomShadows } from './common/shadows' 6 | import table from './common/table' 7 | 8 | const palette = generatePalette({ 9 | primary: { 10 | lighter: '#9d9d9d', 11 | light: '#6f6f6f', 12 | main: '#444444', 13 | dark: '#1d1d1d', 14 | darker: '#000000', 15 | contrastText: '#fff', 16 | rgba: 'rgba(68, 68, 68, 1)' 17 | }, 18 | secondary: { 19 | lighter: '#ff8d62', 20 | light: '#ff5a36', 21 | main: '#ff0000', 22 | dark: '#c20000', 23 | darker: '#890000', 24 | contrastText: '#fff', 25 | rgba: 'rgba(225, 25, 50, 1)' 26 | }, 27 | background: { 28 | default: '#ddd8d3', 29 | paper: '#fff' 30 | }, 31 | sideMenu: { 32 | bgColor: '#fff', 33 | color: '#444444', 34 | hoverBgColor: 'transparent', 35 | hoverTextColor: '#ff0000', 36 | bgOpacity: '0.8', 37 | activeBgColor: '#ff0000' 38 | } 39 | } as PaletteOptions) 40 | 41 | const redTheme: Theme = createTheme({ 42 | palette, 43 | shape: { borderRadius: 8 }, 44 | typography: generateTypography(palette), 45 | table, 46 | shadows: generateShadows(palette), 47 | customShadows: generateCustomShadows(palette) 48 | } as ThemeOptions) 49 | 50 | redTheme.components = componentsOverride(redTheme) 51 | 52 | export default redTheme 53 | -------------------------------------------------------------------------------- /src/components/themes/vividOrangeTheme.ts: -------------------------------------------------------------------------------- 1 | import { Theme } from '@mui/material' 2 | import orangeTheme from './orangeTheme' 3 | 4 | const vividOrangeTheme: Theme = { 5 | ...orangeTheme, 6 | palette: { 7 | ...orangeTheme.palette, 8 | background: { 9 | default: '#eee', 10 | paper: '#fff' 11 | } 12 | } 13 | } 14 | 15 | export default vividOrangeTheme 16 | -------------------------------------------------------------------------------- /src/components/types.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) TotalSoft. 2 | // This source code is licensed under the MIT license. 3 | 4 | // Available theme color options. 5 | export type Color = 6 | | 'primary' 7 | | 'secondary' 8 | | 'info' 9 | | 'success' 10 | | 'warning' 11 | | 'error' 12 | | 'rose' 13 | | 'default' 14 | | 'white' 15 | | 'dark' 16 | | 'transparent' 17 | 18 | // Available gradient color options. 19 | export type Gradient = Exclude<Color, 'transparent' | 'white'> 20 | 21 | // Available size options. 22 | export type Size = 'tiny' | 'small' | 'medium' | 'large' 23 | -------------------------------------------------------------------------------- /src/components/utils/constants.ts: -------------------------------------------------------------------------------- 1 | export const sidebarWrapperHeight = Object.freeze('calc(100vh - 115px)') 2 | export const emptyArray: readonly unknown[] = Object.freeze([]) 3 | export const emptyObject = Object.freeze({}) 4 | export const emptyString = Object.freeze('') 5 | export const emptyFunction = Object.freeze(() => {}) 6 | -------------------------------------------------------------------------------- /src/components/utils/useDebouncedCallback.ts: -------------------------------------------------------------------------------- 1 | import debounce from 'lodash/debounce' 2 | import { useMemo, useRef } from 'react' 3 | 4 | const useDebouncedCallback = (callback: (...args: any[]) => any, debounceBy: number) => { 5 | const debouncedCallbackRef = useRef<any>(undefined) 6 | 7 | const debouncedCallback = useMemo(() => { 8 | if (debounceBy) { 9 | if (debouncedCallbackRef?.current?.cancel && typeof debouncedCallbackRef.current.cancel === 'function') 10 | debouncedCallbackRef.current.cancel() 11 | const debounced = debounce(callback, debounceBy) 12 | debouncedCallbackRef.current = debounced 13 | return debounced 14 | } 15 | return callback 16 | }, [callback, debounceBy]) 17 | 18 | return debouncedCallback 19 | } 20 | 21 | export default useDebouncedCallback 22 | -------------------------------------------------------------------------------- /src/global.d.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) TotalSoft. 2 | // This source code is licensed under the MIT license. 3 | 4 | declare module '*.jpg' 5 | declare module '*.png' 6 | declare module '*.svg' 7 | declare module '*.mp3' 8 | -------------------------------------------------------------------------------- /src/setupTests.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) TotalSoft. 2 | // This source code is licensed under the MIT license. 3 | 4 | // jest-dom adds custom jest matchers for asserting on DOM nodes. 5 | // allows you to do things like: 6 | // expect(element).toHaveTextContent(/react/i) 7 | // learn more: https://github.com/testing-library/jest-dom 8 | import '@testing-library/jest-dom' 9 | import { TextEncoder } from 'util' 10 | 11 | global.TextEncoder = TextEncoder 12 | -------------------------------------------------------------------------------- /src/stories/Introduction.stories.tsx: -------------------------------------------------------------------------------- 1 | import React, { useState } from 'react' 2 | import OrbitContainer from './_introduction/orbits/OrbitContainer' 3 | import AboutContainer from './_introduction/about/AboutContainer' 4 | import Grid from '@mui/material/Grid2' 5 | import type { Meta, StoryObj } from '@storybook/react' 6 | 7 | const LandingPage = () => { 8 | const [activeItem, setActiveItem] = useState(0) 9 | 10 | return ( 11 | <Grid container alignItems="stretch" justifyContent="center"> 12 | <Grid size={{ xs: 12, md: 6 }}> 13 | <OrbitContainer setActiveItem={setActiveItem} /> 14 | </Grid> 15 | <Grid size={{ xs: 12, md: 6 }}> 16 | <AboutContainer activeItem={activeItem} /> 17 | </Grid> 18 | </Grid> 19 | ) 20 | } 21 | 22 | const meta: Meta<typeof LandingPage> = { 23 | title: 'Introduction', 24 | component: LandingPage, 25 | tags: ['!autodocs'], 26 | parameters: { 27 | options: { 28 | showPanel: false 29 | } 30 | } 31 | } satisfies Meta<typeof LandingPage> 32 | 33 | export default meta 34 | type Story = StoryObj<typeof LandingPage> 35 | 36 | export const Introduction: Story = { 37 | render: () => <LandingPage /> 38 | } 39 | -------------------------------------------------------------------------------- /src/stories/_introduction/about/AboutContainer.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Title } from './AboutStyles' 3 | import Grid from '@mui/material/Grid2' 4 | import { orbits, homeData } from '../constants/orbits' 5 | import { Typography } from 'components' 6 | 7 | const AboutContainer = ({ activeItem = 0 }: any) => { 8 | const data = [homeData, ...orbits].find(o => o.id === activeItem) 9 | return ( 10 | <Grid container rowSpacing={2}> 11 | <Grid size={{ xs: 12 }}> 12 | <Title variant="h1">{data.name} 13 | 14 | 15 | 16 | {data.heading} 17 | 18 | 19 | 20 | 21 | {data.description} 22 | 23 | 24 | 25 | ) 26 | } 27 | 28 | export default AboutContainer 29 | -------------------------------------------------------------------------------- /src/stories/_introduction/about/AboutStyles.ts: -------------------------------------------------------------------------------- 1 | import styled from '@emotion/styled' 2 | import { Typography } from 'components' 3 | 4 | export const Title = styled(Typography)` 5 | font-size: 2.5rem; 6 | text-transform: uppercase; 7 | font-weight: 600; 8 | letter-spacing: -0.056rem; 9 | 10 | @media (min-width: 900px) { 11 | font-size: 3rem; 12 | margin-top: 150px; 13 | } 14 | 15 | @media (min-width: 768px) { 16 | font-size: 3rem; 17 | } 18 | 19 | @media (min-width: 1025px) { 20 | font-size: 5rem; 21 | } 22 | ` 23 | -------------------------------------------------------------------------------- /src/stories/_introduction/constants/orbits.ts: -------------------------------------------------------------------------------- 1 | export const orbits = [ 2 | { 3 | id: 1, 4 | name: 'Material-UI', 5 | website: 'https://mui.com/', 6 | heading: 'The engine of our rocket.', 7 | description: 8 | 'This library represents our core, on top of which we design custom behaviors and styles. Besides that, it is one of our major benchmarks in terms of best development practices and conventions.', 9 | orbitColor: 'hsl(194, 48%, 49%)' 10 | }, 11 | { 12 | id: 2, 13 | name: 'Github repository', 14 | website: 'https://github.com/osstotalsoft/rocket-ui-ts', 15 | heading: 'Feel free to join us as a rocket engineer anytime you want.', 16 | description: 17 | 'Have a look over our source code, create issues and contribute, so we can all have a safer and smoother flight.', 18 | orbitColor: 'hsl(33, 82%, 61%)' 19 | }, 20 | { 21 | id: 3, 22 | name: 'npm Registry', 23 | website: 'https://www.npmjs.com/package/@totalsoft/rocket-ui', 24 | heading: 'Our rocket launch site.', 25 | description: 26 | 'We are building and publishing on npm public registry, the world`s largest software registry. Inside our scope, you can find codesandbox-style demos and source-code for all our rocket parts.', 27 | orbitColor: 'hsl(10, 63%, 51%)' 28 | } 29 | ] 30 | 31 | export const homeData = { 32 | id: 0, 33 | name: 'Rocket-UI', 34 | heading: 'Our modular, flexible and collaborative product.', 35 | description: 'An open-source and community-driven project to provide a consistent user interface across web applications.' 36 | } 37 | 38 | export default orbits 39 | -------------------------------------------------------------------------------- /src/stories/_introduction/orbits/OrbitContainer.tsx: -------------------------------------------------------------------------------- 1 | import React, { useCallback } from 'react' 2 | import PropTypes from 'prop-types' 3 | import { Rocket, Container } from './OrbitStyles' 4 | import OrbitSwitch from './OrbitSwitch' 5 | import { orbits } from '../constants/orbits' 6 | 7 | const OrbitContainer = ({ setActiveItem }: any) => { 8 | const handleRocketHover = useCallback(() => setActiveItem(0), [setActiveItem]) 9 | 10 | return ( 11 | 12 | 13 | {orbits.map(orbit => ( 14 | 15 | ))} 16 | 17 | ) 18 | } 19 | 20 | OrbitContainer.propTypes = { 21 | setActiveItem: PropTypes.func.isRequired 22 | } 23 | 24 | export default OrbitContainer 25 | -------------------------------------------------------------------------------- /src/stories/_introduction/orbits/OrbitSwitch.tsx: -------------------------------------------------------------------------------- 1 | import React, { useCallback } from 'react' 2 | import PropTypes from 'prop-types' 3 | import { MaterialOrbit, GitHubOrbit, BitOrbit } from './OrbitStyles' 4 | 5 | const OrbitSwitch = ({ data, setActiveItem }: any) => { 6 | const { id, website, orbitColor } = data 7 | 8 | const handleOrbitHover = useCallback(() => setActiveItem(id), [id, setActiveItem]) 9 | 10 | const orbitProps = { 11 | href: website, 12 | orbitColor, 13 | target: '_blank', 14 | onMouseOver: handleOrbitHover 15 | } 16 | 17 | const orbitSwitch = () => { 18 | switch (data.id) { 19 | case 1: 20 | return 21 | case 2: 22 | return 23 | case 3: 24 | return 25 | } 26 | } 27 | 28 | return <>{orbitSwitch()} 29 | } 30 | 31 | OrbitSwitch.propTypes = { 32 | data: PropTypes.object.isRequired, 33 | setActiveItem: PropTypes.func.isRequired 34 | } 35 | 36 | export default OrbitSwitch 37 | -------------------------------------------------------------------------------- /src/stories/assets/audio/rain-ambient.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/osstotalsoft/rocket-ui-ts/80feca8180b7ce5d2767a81eaa53475aab999793/src/stories/assets/audio/rain-ambient.mp3 -------------------------------------------------------------------------------- /src/stories/assets/img/robot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/osstotalsoft/rocket-ui-ts/80feca8180b7ce5d2767a81eaa53475aab999793/src/stories/assets/img/robot.png -------------------------------------------------------------------------------- /src/stories/assets/img/rocket.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/osstotalsoft/rocket-ui-ts/80feca8180b7ce5d2767a81eaa53475aab999793/src/stories/assets/img/rocket.png -------------------------------------------------------------------------------- /src/stories/assets/img/satellite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/osstotalsoft/rocket-ui-ts/80feca8180b7ce5d2767a81eaa53475aab999793/src/stories/assets/img/satellite.png -------------------------------------------------------------------------------- /src/stories/assets/img/spaceship.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/osstotalsoft/rocket-ui-ts/80feca8180b7ce5d2767a81eaa53475aab999793/src/stories/assets/img/spaceship.png -------------------------------------------------------------------------------- /src/stories/assets/storyImg/code-brackets.svg: -------------------------------------------------------------------------------- 1 | illustration/code-brackets -------------------------------------------------------------------------------- /src/stories/assets/storyImg/comments.svg: -------------------------------------------------------------------------------- 1 | illustration/comments -------------------------------------------------------------------------------- /src/stories/assets/storyImg/direction.svg: -------------------------------------------------------------------------------- 1 | illustration/direction -------------------------------------------------------------------------------- /src/stories/assets/storyImg/flow.svg: -------------------------------------------------------------------------------- 1 | illustration/flow -------------------------------------------------------------------------------- /src/stories/assets/storyImg/repo.svg: -------------------------------------------------------------------------------- 1 | illustration/repo -------------------------------------------------------------------------------- /src/stories/buttons/Button/LoadingPreview.tsx: -------------------------------------------------------------------------------- 1 | // Copyright (c) TotalSoft. 2 | // This source code is licensed under the MIT license. 3 | 4 | import React, { useCallback, useState } from 'react' 5 | import { Button } from '../../../components' 6 | import { Box, FormControlLabel, Switch } from '@mui/material' 7 | 8 | export const LoadingPreview: React.FunctionComponent = () => { 9 | const [loading, setLoading] = useState(false) 10 | const toggleLoading = useCallback(() => setLoading(current => !current), []) 11 | 12 | return ( 13 | <> 14 | } 16 | label="Loading" 17 | sx={{ mb: '15px' }} 18 | /> 19 | 20 | 23 | 26 | 29 | 30 | 31 | ) 32 | } 33 | -------------------------------------------------------------------------------- /src/stories/buttons/Button/WithIconPreview.tsx: -------------------------------------------------------------------------------- 1 | // Copyright (c) TotalSoft. 2 | // This source code is licensed under the MIT license. 3 | 4 | import React from 'react' 5 | import { Button } from '../../../components' 6 | import RocketIcon from '@mui/icons-material/Rocket' 7 | 8 | export const WithIconPreview: React.FunctionComponent = () => ( 9 | <> 10 | 13 | 16 | 19 | 22 | 25 | 28 | 31 | 34 | 35 | ) 36 | -------------------------------------------------------------------------------- /src/stories/buttons/IconButton/LoadingPreview.tsx: -------------------------------------------------------------------------------- 1 | import React, { useCallback, useState } from 'react' 2 | import { Box, FormControlLabel, Switch } from '@mui/material' 3 | import RocketIcon from '@mui/icons-material/Rocket' 4 | import { IconButton } from 'components' 5 | 6 | export const LoadingPreview: React.FunctionComponent = () => { 7 | const [loading, setLoading] = useState(false) 8 | const toggleLoading = useCallback(() => setLoading(current => !current), []) 9 | 10 | return ( 11 | <> 12 | } 14 | label="Loading" 15 | sx={{ mb: '15px' }} 16 | /> 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | ) 30 | } 31 | -------------------------------------------------------------------------------- /src/stories/buttons/IconButton/SizesPreview.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import Grid from '@mui/material/Grid2' 3 | import RocketIcon from '@mui/icons-material/Rocket' 4 | import { IconButton } from 'components' 5 | 6 | export const SizesPreview: React.FunctionComponent = () => ( 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | ) 32 | -------------------------------------------------------------------------------- /src/stories/buttons/IconButton/TypesPreview.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import Grid from '@mui/material/Grid2' 3 | import { IconButton, IconButtonProps } from 'components' 4 | 5 | const sizeProps = { size: 'small', fontSize: 'medium' } satisfies IconButtonProps 6 | 7 | export const TypesPreview: React.FunctionComponent = () => ( 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | ) 44 | -------------------------------------------------------------------------------- /src/stories/buttons/UploadButton/CustomIconsPreview.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import BrowserUpdatedIcon from '@mui/icons-material/BrowserUpdated' 3 | import ImageSearchIcon from '@mui/icons-material/ImageSearch' 4 | import DriveFolderUploadIcon from '@mui/icons-material/DriveFolderUpload' 5 | import { Box } from '@mui/system' 6 | import { UploadButton } from 'components' 7 | 8 | export const CustomIconsPreview = () => { 9 | return ( 10 | 11 | 12 | 13 | 14 | 15 | 16 | ) 17 | } 18 | -------------------------------------------------------------------------------- /src/stories/buttons/UploadButton/IconPropsPreview.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Box } from '@mui/system' 3 | import { UploadButton } from 'components' 4 | 5 | export const IconPropsPreview = () => { 6 | return ( 7 | <> 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | ) 22 | } 23 | -------------------------------------------------------------------------------- /src/stories/buttons/UploadButton/InputTypesPreview.tsx: -------------------------------------------------------------------------------- 1 | import React, { useCallback, useState } from 'react' 2 | import { Box } from '@mui/material' 3 | import { Typography, UploadButton } from 'components' 4 | 5 | export const InputTypesPreview: React.FC = () => { 6 | const [error, setError] = useState() 7 | const handleError = useCallback((err: any) => setError(err), []) 8 | const handleChoice = useCallback(() => setError(undefined), []) 9 | 10 | return ( 11 | <> 12 | 13 | 14 | 15 | 16 | 22 | 23 | 24 | 25 | {error?.message} 26 | 27 | 28 | {error?.files?.[0]?.name} 29 | 30 | 31 | 32 | ) 33 | } 34 | -------------------------------------------------------------------------------- /src/stories/buttons/UploadButton/MobileCapturePreview.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Box } from '@mui/material' 3 | import { Typography, UploadButton } from 'components' 4 | 5 | export const MobileCapturePreview = () => { 6 | return ( 7 | <> 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | Note these work better on mobile devices; If your device is a desktop computer, you'll likely get a typical 17 | file picker. 18 | 19 | 20 | 21 | ) 22 | } 23 | -------------------------------------------------------------------------------- /src/stories/buttons/UploadButton/MultipleSelectionPreview.tsx: -------------------------------------------------------------------------------- 1 | import React, { useState, useCallback } from 'react' 2 | import { head, join, prop, map } from 'ramda' 3 | import { Box } from '@mui/system' 4 | import { Typography, UploadButton } from 'components' 5 | 6 | export const MultipleSelectionPreview = () => { 7 | const [file, setFile] = useState('') 8 | const [files, setFiles] = useState('') 9 | 10 | const handleFileSelected = useCallback((files: FileList) => setFile(prop('name', head([...files])) as string), []) 11 | const handleFilesSelected = useCallback( 12 | (files: FileList) => 13 | setFiles( 14 | join( 15 | '; ', 16 | map((file: File) => file.name, [...files]) 17 | ) 18 | ), 19 | [] 20 | ) 21 | 22 | return ( 23 | <> 24 | 25 | 26 | {file} 27 | 28 | 29 | 30 | {files} 31 | 32 | 33 | ) 34 | } 35 | -------------------------------------------------------------------------------- /src/stories/charts/DeprecatedStatsChart/BarPreview.tsx: -------------------------------------------------------------------------------- 1 | // Copyright (c) TotalSoft. 2 | // This source code is licensed under the MIT license. 3 | 4 | import React from 'react' 5 | import { Button, DeprecatedStatsChart } from 'components' 6 | import AccessTime from '@mui/icons-material/AccessTime' 7 | import Grid from '@mui/material/Grid2' 8 | import { statsChartData, statsChartOptions } from './_mocks' 9 | 10 | const BarPreview = () => { 11 | return ( 12 | 13 | 14 | 23 | 24 | 25 | Ok} 34 | iconColor="info" 35 | /> 36 | 37 | 38 | ) 39 | } 40 | 41 | export default BarPreview 42 | -------------------------------------------------------------------------------- /src/stories/charts/DeprecatedStatsChart/LinePreview.tsx: -------------------------------------------------------------------------------- 1 | // Copyright (c) TotalSoft. 2 | // This source code is licensed under the MIT license. 3 | 4 | import React from 'react' 5 | import { Button, DeprecatedStatsChart } from 'components' 6 | import AccessTime from '@mui/icons-material/AccessTime' 7 | import Grid from '@mui/material/Grid2' 8 | import { statsChartData, statsChartOptions } from './_mocks' 9 | 10 | const LinePreview = () => { 11 | return ( 12 | 13 | 14 | 24 | 25 | 26 | Ok} 35 | /> 36 | 37 | 38 | ) 39 | } 40 | 41 | export default LinePreview 42 | -------------------------------------------------------------------------------- /src/stories/dataDisplay/ExpandingText/DisplayPreview.tsx: -------------------------------------------------------------------------------- 1 | // Copyright (c) TotalSoft. 2 | // This source code is licensed under the MIT license. 3 | 4 | import React from 'react' 5 | import Grid from '@mui/material/Grid2' 6 | import { ExpandingText, Typography } from 'components' 7 | 8 | const text = 9 | 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris viverra in neque non euismod. Nunc convallis ornare sem vel iaculis. Sed in condimentum sapien. Morbi viverra, dolor sed sollicitudin tristique, dui sem pretium odio, nec bibendum nibh velit vel turpis. Maecenas elit velit, molestie quis cursus eu, dignissim a elit. Etiam accumsan cursus ipsum, sit amet semper arcu faucibus sed. Donec aliquam fermentum ligula, a cursus lacus finibus non. Fusce id sollicitudin dui. Suspendisse malesuada lorem enim, at euismod neque tincidunt pellentesque.' 10 | 11 | export const DisplayPreview: React.FunctionComponent = () => ( 12 | 13 | 14 | 15 | display: inline-block 16 | 17 | 18 | 19 | 20 | 21 | display: block 22 | 23 | 24 | 25 | 26 | 27 | display: flex; justify-content: flex-end 28 | 29 | 30 | 31 | 32 | ) 33 | -------------------------------------------------------------------------------- /src/stories/dataDisplay/FavIcon/FavIcon.stories.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import type { Meta, StoryObj } from '@storybook/react' 3 | import { FavIcon } from 'components' 4 | 5 | const meta: Meta = { 6 | title: 'Components/DataDisplay/FavIcon', 7 | component: FavIcon, 8 | argTypes: { 9 | favIconSource: { 10 | control: { type: 'radio' }, 11 | options: ['/favicon.ico', '/faviconGlobe.ico', '/faviconReact.ico', '/faviconTS.ico'] 12 | } 13 | }, 14 | decorators: [ 15 | (Story, {args}) => ( 16 | <> 17 | 18 | 19 | 20 | ) 21 | ] 22 | } satisfies Meta 23 | 24 | export default meta 25 | type Story = StoryObj 26 | 27 | /** 28 | * Some predefined icon examples are provided through the documentation controls of the favIconSource prop 29 | */ 30 | 31 | export const Default: Story = { 32 | args: { 33 | favIconSource: '/faviconGlobe.ico', 34 | defaultFavIcon: '/favicon.ico' 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/stories/dataDisplay/Typography/ColorsPreview.tsx: -------------------------------------------------------------------------------- 1 | // Copyright (c) TotalSoft. 2 | // This source code is licensed under the MIT license. 3 | 4 | import { Typography } from 'components' 5 | import React from 'react' 6 | 7 | export const ColorsPreview: React.FunctionComponent = () => ( 8 | <> 9 | 10 | Initial 11 | 12 | 13 | Error 14 | 15 | 16 | Primary 17 | 18 | 19 | Secondary 20 | 21 | 22 | Text Primary 23 | 24 | 25 | Text Secondary 26 | 27 | 28 | ) 29 | -------------------------------------------------------------------------------- /src/stories/dataDisplay/Typography/ExtraStylingPreview.tsx: -------------------------------------------------------------------------------- 1 | // Copyright (c) TotalSoft. 2 | // This source code is licensed under the MIT license. 3 | 4 | import { Typography } from 'components' 5 | import React from 'react' 6 | 7 | export const ExtraStylingPreview: React.FunctionComponent = () => ( 8 | <> 9 | 10 | Primary and bold - hover me to see a tooltip 11 | 12 | 13 | Secondary and italic 14 | 15 | 16 | Text primary and underline 17 | 18 | 19 | Text secondary and line-through 20 | 21 | 22 | Error and overline 23 | 24 | 25 | ) 26 | -------------------------------------------------------------------------------- /src/stories/feedback/Dialog/ActionsPreview.tsx: -------------------------------------------------------------------------------- 1 | import Grid from '@mui/material/Grid2' 2 | import { Button, Dialog, TextField } from 'components' 3 | import React, { useCallback, useState } from 'react' 4 | 5 | const ActionsPreview = ({ button, ...props }: any) => { 6 | const [open, setOpen] = useState(false) 7 | const toggle = useCallback(() => setOpen(current => !current), []) 8 | 9 | return ( 10 | <> 11 | 35 | 38 | 39 | } 40 | /> 41 | 42 | ) 43 | } 44 | 45 | export default ActionsPreview 46 | -------------------------------------------------------------------------------- /src/stories/feedback/Dialog/DefaultPreview.tsx: -------------------------------------------------------------------------------- 1 | import { Button, Dialog } from 'components' 2 | import React, { useCallback, useState } from 'react' 3 | 4 | const DefaultPreview = ({ button, ...props }: any) => { 5 | const [open, setOpen] = useState(false) 6 | const toggle = useCallback(() => setOpen(current => !current), []) 7 | 8 | return ( 9 | <> 10 | 12 | 13 | ) 14 | } 15 | 16 | export default GlobalPreview 17 | -------------------------------------------------------------------------------- /src/stories/feedback/NotFound/NotFound.stories.tsx: -------------------------------------------------------------------------------- 1 | // Copyright (c) TotalSoft. 2 | // This source code is licensed under the MIT license. 3 | 4 | // Copyright (c) TotalSoft. 5 | // This source code is licensed under the MIT license. 6 | 7 | import type { Meta, StoryObj } from '@storybook/react' 8 | import { NotFound } from 'components' 9 | 10 | const meta: Meta = { 11 | title: 'Components/Feedback/NotFound', 12 | component: NotFound, 13 | } satisfies Meta 14 | 15 | export default meta 16 | type Story = StoryObj 17 | 18 | export const Default: Story = {} 19 | -------------------------------------------------------------------------------- /src/stories/feedback/Toast/ActionsPreview.tsx: -------------------------------------------------------------------------------- 1 | // Copyright (c) TotalSoft. 2 | // This source code is licensed under the MIT license. 3 | 4 | import React from 'react' 5 | import { Button, Typography, useToast } from '../../../components/index' 6 | import { emptyFunction } from '../../../components/utils/constants' 7 | import { Stack } from '@mui/material' 8 | 9 | const ActionsPreview = (args: any) => { 10 | const addToast = useToast() 11 | 12 | const CustomMessageWithActions = () => ( 13 | 14 | 17 | 20 | 21 | ) 22 | 23 | return ( 24 | 33 | ) 34 | } 35 | 36 | export default ActionsPreview 37 | -------------------------------------------------------------------------------- /src/stories/feedback/Toast/TextSizePreview.tsx: -------------------------------------------------------------------------------- 1 | // Copyright (c) TotalSoft. 2 | // This source code is licensed under the MIT license. 3 | 4 | import React from 'react' 5 | import { Button, ToastContainer, useToast } from 'components' 6 | import Grid from '@mui/material/Grid2' 7 | 8 | const TextSizePreview = (args: any) => { 9 | const addToast = useToast() 10 | 11 | return ( 12 | 13 | 14 | 25 | 26 | ) 27 | } 28 | 29 | export default TextSizePreview 30 | -------------------------------------------------------------------------------- /src/stories/feedback/Toast/TransitionsPreview.tsx: -------------------------------------------------------------------------------- 1 | // Copyright (c) TotalSoft. 2 | // This source code is licensed under the MIT license. 3 | 4 | import React from 'react' 5 | import Grid from '@mui/material/Grid2' 6 | import { Button, useToast } from 'components' 7 | 8 | const TransitionsPreview = (args: any) => { 9 | const addToast = useToast() 10 | 11 | return ( 12 | 13 | 14 | 21 | 22 | 23 | 30 | 31 | 32 | 39 | 40 | 41 | 48 | 49 | 50 | ) 51 | } 52 | 53 | export default TransitionsPreview 54 | -------------------------------------------------------------------------------- /src/stories/inputs/Autocomplete/DefaultPreview.tsx: -------------------------------------------------------------------------------- 1 | // Copyright (c) TotalSoft. 2 | // This source code is licensed under the MIT license. 3 | 4 | import React, { useState } from 'react' 5 | import { Autocomplete, Typography } from 'components' 6 | import { Stack } from '@mui/material' 7 | 8 | export const DefaultPreview = (props: any) => { 9 | const [value, setValue] = useState(props?.value || null) 10 | 11 | return ( 12 | 13 | 14 | {`Selected value: ${JSON.stringify(value)}`} 15 | 16 | ) 17 | } 18 | -------------------------------------------------------------------------------- /src/stories/inputs/Autocomplete/GroupedPreview.tsx: -------------------------------------------------------------------------------- 1 | // Copyright (c) TotalSoft. 2 | // This source code is licensed under the MIT license. 3 | 4 | import React, { useCallback, useState } from 'react' 5 | import { Autocomplete } from 'components' 6 | import { emptyArray } from 'components/utils/constants' 7 | import { groupedOptions } from './_mocks' 8 | import { styled } from '@mui/material' 9 | 10 | const GroupHeader = styled('div')(({ theme }) => ({ 11 | ...theme.typography.defaultFont, 12 | padding: '4px 10px', 13 | fontWeight: 'bold' 14 | })) 15 | 16 | const GroupItems = styled('ul')(({ theme }) => ({ 17 | ...theme.typography.defaultFont, 18 | paddingLeft:'5px' 19 | })) 20 | 21 | export const GroupedPreview = (props: any) => { 22 | const [value, setValue] = useState(emptyArray) 23 | 24 | const groupBy = useCallback((option: any) => option.category?.name, []) 25 | 26 | const renderGroup = useCallback( 27 | (params: any) => ( 28 |
  • 29 | {params.group} 30 | {params.children} 31 |
  • 32 | ), 33 | [] 34 | ) 35 | 36 | return ( 37 | 46 | ) 47 | } 48 | -------------------------------------------------------------------------------- /src/stories/inputs/Autocomplete/RequiredPreview.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import Grid from '@mui/material/Grid2' 3 | import { options } from './_mocks' 4 | import { Autocomplete } from 'components' 5 | 6 | export const RequiredPreview = () => { 7 | return ( 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | ) 25 | } 26 | -------------------------------------------------------------------------------- /src/stories/inputs/Autocomplete/components/ColumnHeader.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PropTypes from 'prop-types' 3 | import { Typography } from 'components' 4 | 5 | const ColumnHeader = ({ children }: { children: React.ReactNode }) => ( 6 | 7 | {children} 8 | 9 | ) 10 | ColumnHeader.propTypes = { 11 | children: PropTypes.node 12 | } 13 | 14 | export default ColumnHeader 15 | -------------------------------------------------------------------------------- /src/stories/inputs/Autocomplete/components/ControlledCheckBox.tsx: -------------------------------------------------------------------------------- 1 | import React, { useCallback } from 'react' 2 | import PropTypes from 'prop-types' 3 | import FormControlLabel from '@mui/material/FormControlLabel' 4 | import Checkbox from '@mui/material/Checkbox' 5 | import { Typography } from 'components' 6 | 7 | const ControlledCheckbox = ({ value, onChange, label }: { value: boolean; onChange: any; label: string }) => { 8 | const handleChange = useCallback((e: React.ChangeEvent) => onChange(e.target.checked), [onChange]) 9 | 10 | return ( 11 | } 13 | disableTypography 14 | label={ 15 | 16 | {label} 17 | 18 | } 19 | /> 20 | ) 21 | } 22 | 23 | ControlledCheckbox.propTypes = { 24 | value: PropTypes.bool, 25 | onChange: PropTypes.func, 26 | label: PropTypes.string.isRequired 27 | } 28 | 29 | export default ControlledCheckbox 30 | -------------------------------------------------------------------------------- /src/stories/inputs/Autocomplete/components/FormattedJson.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PropTypes from 'prop-types' 3 | 4 | const FormattedJson = ({ children }: { children: React.ReactNode }) => ( 5 |
    {JSON.stringify(children, null, 3)}
    6 | ) 7 | 8 | FormattedJson.propTypes = { 9 | children: PropTypes.oneOfType([PropTypes.array, PropTypes.object, PropTypes.number, PropTypes.string]) 10 | } 11 | 12 | export default FormattedJson 13 | -------------------------------------------------------------------------------- /src/stories/inputs/DateTime/ClearablePreview.tsx: -------------------------------------------------------------------------------- 1 | // Copyright (c) TotalSoft. 2 | // This source code is licensed under the MIT license. 3 | 4 | import React from 'react' 5 | import Grid from '@mui/material/Grid2' 6 | import { DateTime } from 'components' 7 | 8 | const ClearablePreview = () => { 9 | return ( 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | ) 22 | } 23 | 24 | export default ClearablePreview 25 | -------------------------------------------------------------------------------- /src/stories/inputs/DateTime/DisabledPreview.tsx: -------------------------------------------------------------------------------- 1 | // Copyright (c) TotalSoft. 2 | // This source code is licensed under the MIT license. 3 | 4 | import React from 'react' 5 | import Grid from '@mui/material/Grid2' 6 | import { DateTime } from 'components' 7 | 8 | const value = new Date() 9 | 10 | const DisabledPreview = () => { 11 | return ( 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | ) 24 | } 25 | 26 | export default DisabledPreview 27 | -------------------------------------------------------------------------------- /src/stories/inputs/DateTime/FormatPreview.tsx: -------------------------------------------------------------------------------- 1 | // Copyright (c) TotalSoft. 2 | // This source code is licensed under the MIT license. 3 | 4 | import React, { useCallback, useState } from 'react' 5 | import { Grid2 as Grid, ToggleButton, ToggleButtonGroup } from '@mui/material' 6 | import { DateTime, DateTimeProps } from 'components' 7 | 8 | const formatMap = ['fr', 'en-US', 'ro', 'de'] 9 | 10 | const FormatPreview = () => { 11 | const [format, setFormat] = useState['localeFormat']>('en-US') 12 | 13 | const handleClick = useCallback((e: any) => { 14 | setFormat(e.target.value) 15 | }, []) 16 | 17 | return ( 18 | 19 | 20 | 21 | {formatMap.map(localeItem => ( 22 | 23 | {localeItem} 24 | 25 | ))} 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | ) 39 | } 40 | 41 | export default FormatPreview 42 | -------------------------------------------------------------------------------- /src/stories/inputs/DeprecatedAutocomplete/CheckboxesPreview.tsx: -------------------------------------------------------------------------------- 1 | // Copyright (c) TotalSoft. 2 | // This source code is licensed under the MIT license. 3 | 4 | import React, { useState } from 'react' 5 | import { DeprecatedAutocomplete } from 'components' 6 | import { emptyArray } from 'components/utils/constants' 7 | 8 | export const CheckboxesPreview = (props: any) => { 9 | const [value, setValue] = useState(emptyArray) 10 | 11 | return 12 | } 13 | -------------------------------------------------------------------------------- /src/stories/inputs/DeprecatedAutocomplete/CustomOptionPreview.tsx: -------------------------------------------------------------------------------- 1 | // Copyright (c) TotalSoft. 2 | // This source code is licensed under the MIT license. 3 | 4 | import React, { useState } from 'react' 5 | import { DeprecatedAutocomplete, Typography } from 'components' 6 | import Box from '@mui/material/Box' 7 | 8 | export const CustomOptionPreview = (props: any) => { 9 | const [value, setValue] = useState() 10 | 11 | return ( 12 | ( 17 |
  • 18 | 19 | 20 | {option.name} 21 | 22 | {option.description} 23 | 24 | 25 |
  • 26 | )} 27 | /> 28 | ) 29 | } 30 | -------------------------------------------------------------------------------- /src/stories/inputs/DeprecatedAutocomplete/DefaultPreview.tsx: -------------------------------------------------------------------------------- 1 | // Copyright (c) TotalSoft. 2 | // This source code is licensed under the MIT license. 3 | 4 | import React, { useState } from 'react' 5 | import { DeprecatedAutocomplete, Typography } from 'components' 6 | import { Stack } from '@mui/material' 7 | 8 | export const DefaultPreview = (props: any) => { 9 | const [value, setValue] = useState(props?.value) 10 | 11 | return ( 12 | 13 | 14 | {`Selected value: ${JSON.stringify(value)}`} 15 | 16 | ) 17 | } 18 | -------------------------------------------------------------------------------- /src/stories/inputs/DeprecatedAutocomplete/GroupedPreview.tsx: -------------------------------------------------------------------------------- 1 | // Copyright (c) TotalSoft. 2 | // This source code is licensed under the MIT license. 3 | 4 | import React, { useCallback, useState } from 'react' 5 | import { DeprecatedAutocomplete } from 'components' 6 | import { emptyArray } from 'components/utils/constants' 7 | import { groupedOptions } from './_mocks' 8 | import { styled } from '@mui/material' 9 | 10 | const GroupHeader = styled('div')(({ theme }) => ({ 11 | ...theme.typography.defaultFont, 12 | padding: '4px 10px', 13 | fontWeight: 'bold' 14 | })) 15 | 16 | const GroupItems = styled('ul')(({ theme }) => ({ 17 | ...theme.typography.defaultFont, 18 | paddingLeft:'5px' 19 | })) 20 | 21 | export const GroupedPreview = (props: any) => { 22 | const [value, setValue] = useState(emptyArray) 23 | 24 | const groupBy = useCallback((option: any) => option.category?.name, []) 25 | 26 | const renderGroup = useCallback( 27 | (params: any) => ( 28 |
  • 29 | {params.group} 30 | {params.children} 31 |
  • 32 | ), 33 | [] 34 | ) 35 | 36 | return ( 37 | 46 | ) 47 | } 48 | -------------------------------------------------------------------------------- /src/stories/inputs/DeprecatedAutocomplete/RequiredPreview.tsx: -------------------------------------------------------------------------------- 1 | import React, { useState } from 'react' 2 | import Grid from '@mui/material/Grid2' 3 | import { options } from './_mocks' 4 | import { DeprecatedAutocomplete } from 'components' 5 | 6 | export const RequiredPreview = () => { 7 | const [requiredValue, setRequiredValue] = useState() 8 | const [errorValue, setErrorValue] = useState() 9 | const [helperValue, setHelperValue] = useState() 10 | 11 | return ( 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 28 | 29 | 30 | 37 | 38 | 39 | 40 | ) 41 | } 42 | -------------------------------------------------------------------------------- /src/stories/inputs/DeprecatedAutocomplete/components/ColumnHeader.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PropTypes from 'prop-types' 3 | import { Typography } from 'components' 4 | 5 | const ColumnHeader = ({ children }: { children: React.ReactNode }) => ( 6 | 7 | {children} 8 | 9 | ) 10 | ColumnHeader.propTypes = { 11 | children: PropTypes.node 12 | } 13 | 14 | export default ColumnHeader 15 | -------------------------------------------------------------------------------- /src/stories/inputs/DeprecatedAutocomplete/components/ControlledCheckBox.tsx: -------------------------------------------------------------------------------- 1 | import React, { useCallback } from 'react' 2 | import PropTypes from 'prop-types' 3 | import FormControlLabel from '@mui/material/FormControlLabel' 4 | import Checkbox from '@mui/material/Checkbox' 5 | import { Typography } from 'components' 6 | 7 | const ControlledCheckbox = ({ value, onChange, label }: { value: boolean; onChange: any; label: string }) => { 8 | const handleChange = useCallback((e: React.ChangeEvent) => onChange(e.target.checked), [onChange]) 9 | 10 | return ( 11 | } 13 | disableTypography 14 | label={ 15 | 16 | {label} 17 | 18 | } 19 | /> 20 | ) 21 | } 22 | 23 | ControlledCheckbox.propTypes = { 24 | value: PropTypes.bool, 25 | onChange: PropTypes.func, 26 | label: PropTypes.string.isRequired 27 | } 28 | 29 | export default ControlledCheckbox 30 | -------------------------------------------------------------------------------- /src/stories/inputs/DeprecatedAutocomplete/components/FormattedJson.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PropTypes from 'prop-types' 3 | 4 | const FormattedJson = ({ children }: { children: React.ReactNode }) => ( 5 |
    {JSON.stringify(children, null, 3)}
    6 | ) 7 | 8 | FormattedJson.propTypes = { 9 | children: PropTypes.oneOfType([PropTypes.array, PropTypes.object, PropTypes.number, PropTypes.string]) 10 | } 11 | 12 | export default FormattedJson 13 | -------------------------------------------------------------------------------- /src/stories/inputs/PasswordField/StatesPreview.tsx: -------------------------------------------------------------------------------- 1 | // Copyright (c) TotalSoft. 2 | // This source code is licensed under the MIT license. 3 | 4 | import React from 'react' 5 | import Grid from '@mui/material/Grid2' 6 | import { PasswordField } from 'components' 7 | 8 | const StatesPreview = () => { 9 | return ( 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | ) 24 | } 25 | 26 | export default StatesPreview 27 | -------------------------------------------------------------------------------- /src/stories/inputs/PasswordField/VariantsPreview.tsx: -------------------------------------------------------------------------------- 1 | // Copyright (c) TotalSoft. 2 | // This source code is licensed under the MIT license. 3 | 4 | import React from 'react' 5 | import Grid from '@mui/material/Grid2' 6 | import { PasswordField } from 'components' 7 | 8 | const VariantsPreview = () => { 9 | return ( 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | ) 24 | } 25 | 26 | export default VariantsPreview 27 | -------------------------------------------------------------------------------- /src/stories/inputs/Tags/DefaultPreview.tsx: -------------------------------------------------------------------------------- 1 | import React, { useState } from 'react' 2 | import Grid from '@mui/material/Grid2' 3 | import TagsInput from 'components/inputs/Tags/TagsInput' 4 | import DisplayTags from 'components/inputs/Tags/DisplayTags' 5 | 6 | const DefaultPreview = (args: any) => { 7 | const [inputValue, setInputValue] = useState(['test']) 8 | return ( 9 | 10 | 11 | 18 | 19 | 20 | 21 | 22 | 23 | ) 24 | } 25 | 26 | export default DefaultPreview 27 | -------------------------------------------------------------------------------- /src/stories/inputs/TextField/NumericPreview.tsx: -------------------------------------------------------------------------------- 1 | // Copyright (c) TotalSoft. 2 | // This source code is licensed under the MIT license. 3 | 4 | import React, { useState } from 'react' 5 | import { TextField } from 'components' 6 | import Grid from '@mui/material/Grid2' 7 | 8 | const NumericPreview = () => { 9 | const [numberValue, setNumberValue] = useState() 10 | const [internationalValue, setInternationalValue] = useState(50) 11 | 12 | const handleValue = (value: any) => { 13 | setNumberValue(value) 14 | } 15 | 16 | const handleInternationalValue = (value: any) => { 17 | setInternationalValue(value) 18 | } 19 | 20 | return ( 21 | 22 | 23 | 32 | 33 | 34 | 42 | 43 | 44 | 53 | 54 | 55 | ) 56 | } 57 | 58 | export default NumericPreview 59 | -------------------------------------------------------------------------------- /src/stories/inputs/TextField/ValidationPreview.tsx: -------------------------------------------------------------------------------- 1 | // Copyright (c) TotalSoft. 2 | // This source code is licensed under the MIT license. 3 | import React from 'react' 4 | import Grid from '@mui/material/Grid2' 5 | import { TextField } from 'components' 6 | 7 | const ValidationPreview = () => { 8 | return ( 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | ) 30 | } 31 | 32 | export default ValidationPreview 33 | -------------------------------------------------------------------------------- /src/stories/inputs/TextField/VariantsPreview.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { TextField } from 'components' 3 | import Grid from '@mui/material/Grid2' 4 | 5 | const VariantsPreview = () => { 6 | return ( 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | ) 19 | } 20 | 21 | export default VariantsPreview 22 | -------------------------------------------------------------------------------- /src/stories/navigation/NavPills/ControlledPreview.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import Grid from '@mui/material/Grid2' 3 | import { NavPills } from 'components' 4 | import { tabs } from './_options' 5 | import SyntaxHighlighter from 'react-syntax-highlighter' 6 | import { github } from 'react-syntax-highlighter/dist/esm/styles/hljs' 7 | 8 | const controlled = `function ControlledNavPills({tabs}) { 9 | const [active, setActive] = useState(0) 10 | 11 | const handleChange = (event, newValue) => { 12 | setActive(newValue) 13 | } 14 | 15 | return( 16 | 21 | ) 22 | ` 23 | 24 | const uncontrolled = `function UncontrolledNavPills({tabs}) { 25 | return( 26 | 29 | ) 30 | ` 31 | 32 | const ControlledPreview = () => { 33 | return ( 34 | 35 | 36 | 37 | 38 | 39 | 40 | {controlled} 41 | 42 | 43 | 44 | 45 | {uncontrolled} 46 | 47 | 48 | 49 | ) 50 | } 51 | 52 | export default ControlledPreview 53 | -------------------------------------------------------------------------------- /src/stories/navigation/NavPills/FilledPreview.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import Grid from '@mui/material/Grid2' 3 | import { tabs } from './_options' 4 | import { NavPills } from 'components' 5 | import SyntaxHighlighter from 'react-syntax-highlighter' 6 | import { github } from 'react-syntax-highlighter/dist/esm/styles/hljs' 7 | 8 | const FilledPreview = () => { 9 | return ( 10 | 11 | 12 | 13 | {''} 14 | 15 | 16 | 17 | 18 | 19 | {''} 20 | 21 | 22 | 23 | 24 | 25 | {''} 26 | 27 | 28 | 29 | 30 | ) 31 | } 32 | 33 | export default FilledPreview 34 | -------------------------------------------------------------------------------- /src/stories/navigation/NavPills/OrientationPreview.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import Grid from '@mui/material/Grid2' 3 | import { tabs } from './_options' 4 | import { NavPills } from 'components' 5 | 6 | const OrientationPreview = () => { 7 | return ( 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | ) 17 | } 18 | 19 | export default OrientationPreview 20 | -------------------------------------------------------------------------------- /src/stories/navigation/NavPills/WithActionsPreview.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import Grid from '@mui/material/Grid2' 3 | import { tabs } from './_options' 4 | import { IconButton, NavPills } from 'components' 5 | 6 | const WithActionsPreview = () => { 7 | const actions = [ 8 | , 9 | , 10 | 11 | ] 12 | 13 | return ( 14 | 15 | 16 | 17 | 18 | 19 | ) 20 | } 21 | 22 | export default WithActionsPreview 23 | -------------------------------------------------------------------------------- /src/stories/navigation/NavPills/WithIconsPreview.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import Grid from '@mui/material/Grid2' 3 | import { tabs } from './_options' 4 | import { NavPills } from 'components' 5 | 6 | const WithIconsPreview = () => { 7 | return ( 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | ) 23 | } 24 | 25 | export default WithIconsPreview 26 | -------------------------------------------------------------------------------- /src/stories/navigation/NavPills/_options.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Typography } from '@mui/material' 3 | import CarRepair from '@mui/icons-material/CarRepair' 4 | import Phone from '@mui/icons-material/Phone' 5 | import Rocket from '@mui/icons-material/Rocket' 6 | import ShieldMoonSharp from '@mui/icons-material/ShieldMoonSharp' 7 | 8 | export const tabs = (withIcons: boolean, withText: boolean) => [ 9 | { 10 | label: withText && 'Item one', 11 | icon: withIcons ? : undefined, 12 | content: {'Content 1'} 13 | }, 14 | { 15 | label: withText && 'Item two', 16 | icon: withIcons ? : undefined, 17 | content: {'Content 2'} 18 | }, 19 | { 20 | label: withText && 'Item three', 21 | icon: withIcons ? : undefined, 22 | content: {'Content 3'} 23 | }, 24 | { 25 | label: withText && 'Item four', 26 | icon: withIcons ? : undefined, 27 | content: {'Content 4'} 28 | } 29 | ] 30 | -------------------------------------------------------------------------------- /src/stories/navigation/Pagination/DefaultPreview.tsx: -------------------------------------------------------------------------------- 1 | import { Pagination } from 'components' 2 | import React, { useCallback, useState } from 'react' 3 | 4 | const DefaultPreview = (args: any) => { 5 | const [page, setPage] = useState(0) 6 | const [pageSize, setPageSize] = useState(10) 7 | 8 | const handleChangePage = useCallback((value: number) => { 9 | setPage(value) 10 | }, []) 11 | 12 | const handleChangeRowsPerPage = useCallback((value: number) => { 13 | setPageSize(value) 14 | setPage(0) 15 | }, []) 16 | 17 | return ( 18 | 25 | ) 26 | } 27 | 28 | export default DefaultPreview 29 | -------------------------------------------------------------------------------- /src/stories/navigation/Pagination/WithFirstAndLastPreview.tsx: -------------------------------------------------------------------------------- 1 | import { Pagination } from 'components' 2 | import React, { useCallback, useState } from 'react' 3 | 4 | const WithFirstAndLastPreview = () => { 5 | const [page, setPage] = useState(0) 6 | const [pageSize, setPageSize] = useState(10) 7 | 8 | const handleChangePage = useCallback((value: number) => { 9 | setPage(value) 10 | }, []) 11 | 12 | const handleChangeRowsPerPage = useCallback((value: number) => { 13 | setPageSize(value) 14 | setPage(0) 15 | }, []) 16 | 17 | return ( 18 | 27 | ) 28 | } 29 | 30 | export default WithFirstAndLastPreview 31 | -------------------------------------------------------------------------------- /src/stories/navigation/Pagination/WithNoCountPreview.tsx: -------------------------------------------------------------------------------- 1 | import { Pagination } from 'components' 2 | import React, { useCallback, useState } from 'react' 3 | 4 | const WithNoCountPreview = () => { 5 | const [page, setPage] = useState(0) 6 | const [pageSize, setPageSize] = useState(10) 7 | const hasNextPage = page >= 0 8 | const hasPreviousPage = page > 0 9 | 10 | const handleChangePage = useCallback((value: number) => { 11 | setPage(value) 12 | }, []) 13 | 14 | const handleChangeRowsPerPage = useCallback((value: number) => { 15 | setPageSize(value) 16 | setPage(0) 17 | }, []) 18 | 19 | return ( 20 | 28 | ) 29 | } 30 | 31 | export default WithNoCountPreview 32 | -------------------------------------------------------------------------------- /src/stories/surfaces/Accordion/ActionsPreview.tsx: -------------------------------------------------------------------------------- 1 | import React, { useCallback, useState } from 'react' 2 | import Grid from '@mui/material/Grid2' 3 | import { Accordion, Autocomplete, IconButton, Typography } from 'components' 4 | import { mockedAccordionContent } from './_mocks' 5 | import { options } from 'stories/inputs/Autocomplete/_mocks' 6 | 7 | const { content } = mockedAccordionContent 8 | 9 | const ActionsPreview = () => { 10 | const [value, setValue] = useState() 11 | 12 | const handleChange = useCallback((val: any) => { 13 | setValue(val) 14 | }, []) 15 | 16 | const handleDelete = useCallback((event: any) => { 17 | event.stopPropagation() 18 | }, []) 19 | 20 | return ( 21 | 24 | 25 | 26 | {'Accordion Title'} 27 | 28 | 29 | 30 | 37 | {`Selected value: ${JSON.stringify(value)}`} 38 | 39 | 40 | 41 | 42 | 43 | } 44 | content={content} 45 | /> 46 | ) 47 | } 48 | 49 | export default ActionsPreview 50 | -------------------------------------------------------------------------------- /src/stories/surfaces/Card/FilledPreview.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Card, Button, IconButton, Typography } from 'components' 3 | import QuestionMark from '@mui/icons-material/QuestionMark' 4 | import { Grid2 as Grid, TextField } from '@mui/material' 5 | 6 | const FilledPreview = () => { 7 | return ( 8 | 13 | SUBMIT 14 | 15 | } 16 | actions={ 17 | 18 | 19 | 20 | } 21 | > 22 | 23 | 24 | Please, fill in with your personal information. 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | ) 41 | } 42 | 43 | export default FilledPreview 44 | -------------------------------------------------------------------------------- /src/stories/surfaces/CollapseCard/FilledPreview.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Button, IconButton, Typography, CollapseCard } from 'components' 3 | import QuestionMark from '@mui/icons-material/QuestionMark' 4 | import { Grid2 as Grid, TextField } from '@mui/material' 5 | 6 | const FilledPreview = (args: any) => { 7 | return ( 8 | 13 | SUBMIT 14 | 15 | } 16 | actions={ 17 | 18 | 19 | 20 | } 21 | {...args} 22 | > 23 | 24 | 25 | Please, fill in with your personal information. 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | ) 42 | } 43 | 44 | export default FilledPreview 45 | -------------------------------------------------------------------------------- /src/testingUtils/TestingWrapper.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PropTypes from 'prop-types' 3 | import { ThemeProvider } from '@mui/material/styles' 4 | import defaultTheme from '../components/themes/defaultTheme' 5 | import { ToastContainer } from 'components' 6 | 7 | const TestingWrapper = ({ children }: any) => { 8 | return ( 9 | 10 | 11 | {children} 12 | 13 | ) 14 | } 15 | 16 | TestingWrapper.propTypes = { 17 | children: PropTypes.node 18 | } 19 | 20 | export default TestingWrapper 21 | -------------------------------------------------------------------------------- /src/testingUtils/index.ts: -------------------------------------------------------------------------------- 1 | import { render, fireEvent, renderHook, RenderOptions, RenderHookOptions } from '@testing-library/react' 2 | import TestingWrapper from './TestingWrapper' 3 | 4 | const customRender = (ui: JSX.Element, options?: RenderOptions | undefined) => 5 | render(ui, { wrapper: TestingWrapper, ...options }) 6 | const customRenderHook = ( 7 | hook: (initialProps: unknown) => unknown, 8 | options?: RenderHookOptions | undefined 9 | ) => renderHook(hook, { wrapper: TestingWrapper, ...options }) 10 | 11 | // more comprehensive simulation of a user click (mousedown + click) 12 | const userClick = (element: any) => { 13 | fireEvent.mouseDown(element) 14 | fireEvent.mouseUp(element) 15 | element.click() 16 | } 17 | 18 | export * from '@testing-library/react' 19 | export { customRender as render, userClick, customRenderHook as renderHook } 20 | -------------------------------------------------------------------------------- /tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig", 3 | "exclude": [ 4 | "**/*.test.*", 5 | "**/__mocks__/*", 6 | "**/src/stories/*", 7 | "**/.storybook/*", 8 | "**/src/setupTests.ts", 9 | "**/src/testingUtils/*" 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "lib": ["dom", "dom.iterable", "esnext"], 5 | "allowJs": true, 6 | "allowSyntheticDefaultImports": true, 7 | "module": "esnext", 8 | "moduleResolution": "node", 9 | "resolveJsonModule": true, 10 | "isolatedModules": true, 11 | "noEmit": false, 12 | "declaration": true, 13 | "sourceMap": true, 14 | "rootDir": "./src", 15 | "outDir": "./dist", 16 | "strict": true, 17 | "noImplicitReturns": false, 18 | "noFallthroughCasesInSwitch": true, 19 | "noUnusedLocals": true, 20 | "noUnusedParameters": true, 21 | "jsx": "react", 22 | "esModuleInterop": true, 23 | "skipLibCheck": true, 24 | "forceConsistentCasingInFileNames": true, 25 | "baseUrl": "src", 26 | "strictNullChecks": false 27 | }, 28 | "include": ["src"], 29 | "exclude": ["dist", "node_modules"] 30 | } 31 | --------------------------------------------------------------------------------