├── .github └── workflows │ ├── README.md │ ├── build-and-publish.yml │ ├── run-tests.yml │ └── sonarcloud.yml ├── .gitignore ├── .npmrc ├── .stylelintrc.js ├── README.md ├── cypress.config.js ├── cypress ├── fixtures │ └── example.json └── support │ ├── commands.js │ ├── component-index.html │ └── component.js ├── docs ├── Contributing.md ├── Fonts.md ├── GettingStarted.md ├── Globals.md ├── PublishingGuide.md └── Theming.md ├── eslint.config.mjs ├── lib ├── 0b35f29d15f855f60fa8.js ├── ee385296b124aae4e5d9.js ├── fonts │ ├── fontawesome │ │ ├── fa-light-300.ttf │ │ ├── fa-light-300.woff2 │ │ ├── fa-regular-400.ttf │ │ ├── fa-regular-400.woff2 │ │ ├── fa-solid-900.ttf │ │ └── fa-solid-900.woff2 │ ├── inter │ │ ├── Inter-Bold.woff │ │ ├── Inter-Bold.woff2 │ │ ├── Inter-Light.woff │ │ ├── Inter-Light.woff2 │ │ ├── Inter-Medium.woff │ │ ├── Inter-Medium.woff2 │ │ ├── Inter-Regular.woff │ │ ├── Inter-Regular.woff2 │ │ ├── Inter-SemiBold.woff │ │ └── Inter-SemiBold.woff2 │ ├── tykon.woff │ └── tykon.woff2 ├── images │ ├── arrow_down.svg │ └── drag.svg ├── index.css ├── index.css.map ├── index.js ├── index.js.LICENSE.txt ├── index.js.map ├── sass │ ├── common │ │ └── sass │ │ │ ├── mixins.scss │ │ │ └── variables.scss │ └── index.scss ├── tyk-ui.css ├── tyk-ui.css.map ├── tyk-ui.js ├── tyk-ui.js.LICENSE.txt └── tyk-ui.js.map ├── logo └── index.js ├── package-lock.json ├── package.json ├── src ├── common │ ├── css │ │ ├── components.css │ │ ├── fontawesome │ │ │ ├── fontawesome.css │ │ │ ├── light.css │ │ │ ├── regular.css │ │ │ └── solid.css │ │ ├── fonts.css │ │ ├── form.css │ │ ├── grid.css │ │ ├── layout.css │ │ ├── reset.css │ │ ├── texts.css │ │ ├── tykon.css │ │ ├── typography.css │ │ └── variables.css │ ├── fonts │ │ ├── fontawesome │ │ │ ├── fa-light-300.ttf │ │ │ ├── fa-light-300.woff2 │ │ │ ├── fa-regular-400.ttf │ │ │ ├── fa-regular-400.woff2 │ │ │ ├── fa-solid-900.ttf │ │ │ └── fa-solid-900.woff2 │ │ ├── inter │ │ │ ├── Inter-Bold.eot │ │ │ ├── Inter-Bold.svg │ │ │ ├── Inter-Bold.ttf │ │ │ ├── Inter-Bold.woff │ │ │ ├── Inter-Bold.woff2 │ │ │ ├── Inter-Light.eot │ │ │ ├── Inter-Light.svg │ │ │ ├── Inter-Light.ttf │ │ │ ├── Inter-Light.woff │ │ │ ├── Inter-Light.woff2 │ │ │ ├── Inter-Medium.eot │ │ │ ├── Inter-Medium.svg │ │ │ ├── Inter-Medium.ttf │ │ │ ├── Inter-Medium.woff │ │ │ ├── Inter-Medium.woff2 │ │ │ ├── Inter-Regular.eot │ │ │ ├── Inter-Regular.svg │ │ │ ├── Inter-Regular.ttf │ │ │ ├── Inter-Regular.woff │ │ │ ├── Inter-Regular.woff2 │ │ │ ├── Inter-SemiBold.eot │ │ │ ├── Inter-SemiBold.svg │ │ │ ├── Inter-SemiBold.ttf │ │ │ ├── Inter-SemiBold.woff │ │ │ └── Inter-SemiBold.woff2 │ │ ├── tykon.eot │ │ ├── tykon.otf │ │ ├── tykon.svg │ │ ├── tykon.ttf │ │ ├── tykon.woff │ │ └── tykon.woff2 │ ├── images │ │ ├── arrow-down.svg │ │ └── drag.svg │ └── sass │ │ ├── mixins.scss │ │ └── variables.scss ├── components │ ├── Accordion │ │ ├── Accordion.css │ │ ├── Accordion.test.js │ │ ├── Readme.md │ │ ├── index.js │ │ └── js │ │ │ ├── AccordionContext.js │ │ │ ├── AccordionItem.js │ │ │ ├── AccordionItem.test.js │ │ │ ├── AccordionItemContent.js │ │ │ ├── AccordionItemContent.test.js │ │ │ ├── AccordionItemContext.js │ │ │ ├── AccordionItemHeader.js │ │ │ ├── AccordionItemHeader.test.js │ │ │ ├── AccordionItemTrigger.js │ │ │ └── AccordionItemTrigger.test.js │ ├── Button │ │ ├── Button.css │ │ ├── Button.test.js │ │ ├── Readme.md │ │ └── index.js │ ├── ButtonGroup │ │ ├── ButtonGroup.css │ │ ├── ButtonGroup.test.js │ │ ├── Readme.md │ │ └── index.js │ ├── Card │ │ ├── Card.css │ │ ├── Card.test.js │ │ ├── CardBody.js │ │ ├── CardFooter.js │ │ ├── CardHeader.js │ │ ├── CardSubTitle.js │ │ ├── CardSummary.js │ │ ├── CardTitle.js │ │ ├── CardTitleGroup.js │ │ ├── CardTitleIcon.js │ │ ├── Readme.md │ │ └── index.js │ ├── Chart │ │ ├── Chart.css │ │ ├── Chart.test.js │ │ ├── Readme.md │ │ ├── index.js │ │ └── maps │ │ │ └── world.json │ ├── Collapsible │ │ ├── Collapsible.css │ │ ├── Collapsible.test.js │ │ ├── Readme.md │ │ └── index.js │ ├── Confirm │ │ ├── Confirm.test.js │ │ ├── Readme.md │ │ └── index.js │ ├── CopyToClipboard │ │ ├── CopyToClipboard.css │ │ ├── CopyToClipboard.test.js │ │ ├── Readme.md │ │ └── index.js │ ├── FixedWrapper │ │ ├── FixedWrapper.css │ │ ├── FixedWrapper.test.js │ │ └── index.js │ ├── FloatingContainer │ │ ├── FloatingContainer.css │ │ ├── FloatingContainer.test.js │ │ ├── Readme.md │ │ └── index.js │ ├── Icon │ │ ├── Icon.css │ │ ├── Icon.test.js │ │ ├── Readme.md │ │ └── index.js │ ├── InfiniteScroller │ │ ├── InfiniteScroller.css │ │ ├── InfiniteScroller.test.js │ │ └── index.js │ ├── InfoNote │ │ ├── InfoNote.test.js │ │ ├── Readme.md │ │ └── index.js │ ├── List │ │ ├── List.css │ │ ├── List.test.js │ │ ├── Readme.md │ │ ├── index.js │ │ └── js │ │ │ └── ListItem.js │ ├── Loader │ │ ├── Loader.css │ │ ├── Loader.test.js │ │ ├── Readme.md │ │ └── index.js │ ├── Message │ │ ├── Message.css │ │ ├── Message.test.js │ │ ├── Readme.md │ │ └── index.js │ ├── Modal │ │ ├── Modal.css │ │ ├── Modal.test.js │ │ ├── Readme.md │ │ ├── index.js │ │ └── js │ │ │ ├── ModalBody.js │ │ │ ├── ModalFooter.js │ │ │ ├── ModalHeader.js │ │ │ └── ModalTitle.js │ ├── NavBar │ │ ├── NavBar.css │ │ ├── NavBar.test.js │ │ ├── Readme.md │ │ └── index.js │ ├── Navigation │ │ ├── Navigation.css │ │ ├── Navigation.test.js │ │ ├── Readme.md │ │ ├── index.js │ │ └── js │ │ │ └── NavigationItem.js │ ├── Panel │ │ ├── Panel.css │ │ ├── Panel.test.js │ │ ├── Readme.md │ │ ├── index.js │ │ ├── js │ │ │ ├── PanelBody.js │ │ │ ├── PanelFooter.js │ │ │ └── PanelHeader.js │ │ └── panel-context.js │ ├── Pill │ │ ├── Pill.css │ │ ├── Pill.test.js │ │ ├── Readme.md │ │ └── index.js │ ├── ProgressBar │ │ ├── ProgressBar.css │ │ ├── ProgressBar.test.js │ │ ├── Readme.md │ │ └── index.js │ ├── RevealPanel │ │ ├── Readme.md │ │ ├── RevealPanel.css │ │ ├── RevealPanel.test.js │ │ ├── images │ │ │ └── drag.svg │ │ ├── index.js │ │ └── js │ │ │ └── RevealPanelService.js │ ├── Sidebar │ │ └── Sidebar.css │ ├── Stepper │ │ ├── Readme.md │ │ ├── Stepper.test.js │ │ ├── StepperContext.js │ │ ├── index.js │ │ ├── js │ │ │ ├── Buttons.js │ │ │ ├── Step.js │ │ │ ├── StepItem.js │ │ │ ├── StepList.js │ │ │ ├── StepNumber.js │ │ │ └── StepperButtons.js │ │ └── stepper.css │ ├── Table │ │ ├── Readme.md │ │ ├── Table.css │ │ ├── Table.test.js │ │ ├── index.js │ │ ├── js │ │ │ ├── body.js │ │ │ ├── cell.js │ │ │ ├── header-cell.js │ │ │ ├── header.js │ │ │ └── row.js │ │ └── tableContext.js │ ├── Tabs │ │ ├── Readme.md │ │ ├── Tabs.css │ │ ├── Tabs.test.js │ │ ├── index.js │ │ ├── js │ │ │ ├── Tab.js │ │ │ ├── TabContent.js │ │ │ └── TabContext.js │ │ └── tabs-context.js │ ├── TextEllipsis │ │ ├── Readme.md │ │ ├── TextEllipsis.test.js │ │ └── index.js │ ├── Toast │ │ ├── Readme.md │ │ ├── Toast.css │ │ ├── Toast.test.js │ │ ├── index.js │ │ └── js │ │ │ ├── ToastContainer.js │ │ │ └── ToastMessage.js │ └── Tooltip │ │ ├── Readme.md │ │ ├── Tooltip.css │ │ ├── Tooltip.test.js │ │ └── index.js ├── form │ ├── Readme.md │ ├── components │ │ ├── Checkbox │ │ │ ├── Checkbox.css │ │ │ ├── Checkbox.test.js │ │ │ ├── Readme.md │ │ │ └── index.js │ │ ├── CodeEditor │ │ │ ├── CodeEditor.test.js │ │ │ ├── Readme.md │ │ │ └── index.js │ │ ├── Combobox │ │ │ ├── Combobox.css │ │ │ ├── Readme.md │ │ │ └── index.js │ │ ├── Combobox2 │ │ │ ├── .DS_Store │ │ │ ├── Combobox.css │ │ │ ├── Combobox2.test.js │ │ │ ├── Readme.md │ │ │ ├── index.js │ │ │ └── js │ │ │ │ ├── List.js │ │ │ │ └── Value.js │ │ ├── DatePicker │ │ │ ├── DatePicker.css │ │ │ ├── DatePicker.test.js │ │ │ ├── Readme.md │ │ │ └── index.js │ │ ├── Dropdown │ │ │ ├── Dropdown.css │ │ │ ├── Dropdown.test.js │ │ │ ├── Readme.md │ │ │ ├── dropdown-context.js │ │ │ ├── index.js │ │ │ └── js │ │ │ │ └── DropdownItem.js │ │ ├── Dropdown2 │ │ │ ├── Dropdown.css │ │ │ ├── Dropdown.test.js │ │ │ ├── DropdownItem.js │ │ │ ├── DropdownListWrapper.js │ │ │ ├── DropdownTrigger.js │ │ │ ├── Readme.md │ │ │ ├── index.js │ │ │ ├── useDrodpownContext.js │ │ │ └── useDropdown.js │ │ ├── EditableList │ │ │ ├── EditableList.css │ │ │ ├── Readme.md │ │ │ ├── index.js │ │ │ └── js │ │ │ │ └── EditableListForm.js │ │ ├── EditableList2 │ │ │ ├── EditableList2.css │ │ │ ├── EditableList2.test.js │ │ │ ├── FieldsList.js │ │ │ ├── Header.js │ │ │ ├── ListHeader.js │ │ │ ├── Readme.md │ │ │ ├── index.js │ │ │ ├── test-data.js │ │ │ ├── validate-values.js │ │ │ └── with-validation.js │ │ ├── FileInput │ │ │ ├── FileInput.css │ │ │ ├── FileInput.test.js │ │ │ ├── Readme.md │ │ │ └── index.js │ │ ├── Input │ │ │ ├── Readme.md │ │ │ └── index.js │ │ ├── Input2 │ │ │ ├── Input2.test.js │ │ │ ├── Readme.md │ │ │ └── index.js │ │ ├── Multiselect │ │ │ ├── Multiselect.css │ │ │ ├── Multiselect.test.js │ │ │ ├── Readme.md │ │ │ ├── index.js │ │ │ └── js │ │ │ │ ├── MultiselectContext.js │ │ │ │ ├── MultiselectItem.js │ │ │ │ └── MultiselectPanel.js │ │ ├── Pagination │ │ │ ├── Pagination.css │ │ │ ├── Pagination.test.js │ │ │ ├── Readme.md │ │ │ └── index.js │ │ ├── Radio │ │ │ ├── Radio.css │ │ │ ├── Radio.test.js │ │ │ ├── Readme.md │ │ │ └── index.js │ │ ├── Select │ │ │ ├── Readme.md │ │ │ ├── Select.css │ │ │ ├── Select.test.js │ │ │ ├── images │ │ │ │ └── arrow_down.svg │ │ │ └── index.js │ │ ├── SelectableList │ │ │ ├── Readme.md │ │ │ ├── SelectableList.css │ │ │ ├── SelectableList.test.js │ │ │ └── index.js │ │ ├── Textarea │ │ │ ├── Readme.md │ │ │ ├── Textarea.css │ │ │ ├── Textarea.test.js │ │ │ └── index.js │ │ └── Toggle │ │ │ ├── Readme.md │ │ │ ├── Toggle.css │ │ │ ├── Toggle.test.js │ │ │ ├── index.js │ │ │ └── js │ │ │ ├── ToggleContext.js │ │ │ ├── ToggleItem.js │ │ │ └── ToggleItemWrapper.js │ ├── formik │ │ ├── FormikCheckbox │ │ │ └── index.js │ │ ├── FormikCodeEditor │ │ │ └── index.js │ │ ├── FormikCombobox │ │ │ └── index.js │ │ ├── FormikCombobox2 │ │ │ └── index.js │ │ ├── FormikDatePicker │ │ │ └── index.js │ │ ├── FormikEditableList │ │ │ └── index.js │ │ ├── FormikEditableList2 │ │ │ └── index.js │ │ ├── FormikFileInput │ │ │ └── index.js │ │ ├── FormikInput │ │ │ └── index.js │ │ ├── FormikInput2 │ │ │ └── index.js │ │ ├── FormikMultiselect │ │ │ └── index.js │ │ ├── FormikRadio │ │ │ └── index.js │ │ ├── FormikSelect │ │ │ └── index.js │ │ ├── FormikSelectableList │ │ │ └── index.js │ │ ├── FormikTextarea │ │ │ └── index.js │ │ └── FormikToggle │ │ │ └── index.js │ └── redux-form │ │ ├── FieldCodeEditor │ │ └── index.js │ │ ├── FieldCombobox │ │ └── index.js │ │ ├── FieldCombobox2 │ │ ├── .DS_Store │ │ └── index.js │ │ ├── FieldDatePicker │ │ └── index.js │ │ ├── FieldDropdown │ │ └── index.js │ │ ├── FieldEditableList │ │ └── index.js │ │ ├── FieldFileInput │ │ └── index.js │ │ ├── FieldInput │ │ └── index.js │ │ ├── FieldMultiselect │ │ └── index.js │ │ ├── FieldPagination │ │ └── index.js │ │ ├── FieldSelect │ │ └── index.js │ │ ├── FieldSelectableList │ │ └── index.js │ │ └── FieldToggle │ │ └── index.js ├── hooks │ ├── Readme.md │ ├── index.js │ ├── useComponentSize │ │ ├── Readme.md │ │ └── index.js │ ├── useEventListener │ │ ├── Readme.md │ │ └── index.js │ ├── useInterval │ │ ├── Readme.md │ │ └── index.js │ ├── usePrevious │ │ ├── Readme.md │ │ └── index.js │ └── useTimeout │ │ ├── Readme.md │ │ └── index.js ├── index.css ├── index.js ├── index.scss ├── layout │ ├── Column │ │ ├── Column.test.js │ │ ├── Readme.md │ │ └── index.js │ ├── Readme.md │ └── Row │ │ ├── Readme.md │ │ ├── Row.test.js │ │ └── index.js ├── typography │ └── Readme.md └── utils │ ├── config │ └── config.js │ ├── css-helpers │ ├── Readme.md │ └── helpers.css │ ├── debounce │ ├── Readme.md │ ├── index.js │ └── styleguidist-example.js │ └── formik │ ├── Readme.md │ ├── index.js │ └── styleguidist-example.js ├── styleguide.config.js ├── styleguide.styles.js ├── webpack.component.js └── webpack.config.js /.github/workflows/README.md: -------------------------------------------------------------------------------- 1 | # GitHub Actions 2 | 3 | ## build-and-publish.yml 4 | 5 | Builds the lib directory and publishes the new version to npm. 6 | 7 | ## run-tests.yml 8 | 9 | Runs the unit tests for the current repo. 10 | 11 | ## sonarcloud.yml 12 | 13 | Scans the source code using sonar. 14 | 15 | ## Documentation 16 | 17 | [Workflow reference](https://help.github.com/en/actions/reference/workflow-syntax-for-github-actions). 18 | 19 | [Triggers](https://help.github.com/en/actions/reference/events-that-trigger-workflows) for workflows. 20 | 21 | [repository-dispatch]: https://help.github.com/en/actions/reference/events-that-trigger-workflows#external-events-repository_dispatch 22 | -------------------------------------------------------------------------------- /.github/workflows/build-and-publish.yml: -------------------------------------------------------------------------------- 1 | name: Build and Publish 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | 8 | jobs: 9 | build-lib: 10 | runs-on: ${{ matrix.os }} 11 | 12 | strategy: 13 | matrix: 14 | os: [ubuntu-latest] 15 | node-version: [16.x] 16 | 17 | steps: 18 | - name: Checkout repo 19 | uses: actions/checkout@v3 20 | with: 21 | fetch-depth: 0 22 | token: ${{ secrets.TYK_UI_TOKEN }} 23 | - name: Use node ${{ matrix.node-version }} 24 | uses: actions/setup-node@v3 25 | with: 26 | node-version: ${{ matrix.node-version }} 27 | - name: Install dependencies 28 | run: | 29 | npm config set //registry.npmjs.org/:_authToken "${{ secrets.NPM_TOKEN }}" && npm ci 30 | - name: Run production build 31 | run: | 32 | npm run build-prod 33 | - name: Generate package-lock.json 34 | run: | 35 | npm i --package-lock-only 36 | - name: get-npm-version 37 | id: package-version 38 | uses: martinbeentjes/npm-get-version-action@master 39 | - name: Push changes 40 | run: | 41 | git config --local user.email "tyk-ui-bot@tyk.io" 42 | git config --local user.name "tyk-ui bot" 43 | git add . 44 | git commit -m "Update lib to version ${{ steps.package-version.outputs.current-version}}" 45 | git push 46 | - name: Publish lib to npm 47 | uses: JS-DevTools/npm-publish@v1 48 | with: 49 | token: ${{ secrets.NPM_PUBLISH_TOKEN }} 50 | 51 | env: 52 | CI: true 53 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 54 | -------------------------------------------------------------------------------- /.github/workflows/sonarcloud.yml: -------------------------------------------------------------------------------- 1 | name: SonarCloud 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | jobs: 8 | sonarcloud: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v4 12 | with: 13 | fetch-depth: 0 14 | - name: install 15 | run: npm config set //registry.npmjs.org/:_authToken "${{ secrets. NPM_TOKEN }}" && npm install 16 | - name: test 17 | run: npm test 18 | - name: SonarCloud Scan 19 | uses: sonarsource/sonarcloud-github-action@master 20 | with: 21 | projectBaseDir: . 22 | args: > 23 | -Dsonar.organization=tyktechnologies 24 | -Dsonar.projectKey=TykTechnologies_tyk-ui 25 | -Dsonar.sources=./src 26 | -Dsonar.exclusions=src/common/sass/fontawesome.scss,src/common/sass/tykon.scss 27 | -Dsonar.coverage.exclusions=cypress/**/*.js,**/*.test.js,src/form/components/Combobox/**/*.js,src/form/components/Input/**/*.js,src/form/components/EditableList/**/*.js,src/form/redux-form/**/*.js,src/hooks/**/*,src/utils/**/* 28 | -Dsonar.cpd.exclusions=**/*.test.js,src/form/redux-form/**/*,src/common/fonts/**/*,src/form/components/Combobox/*.js,src/form/components/Input/*.js,src/form/components/EditableList/**/*.js,src/form/redux-form/**/*.js,src/hooks/**/*,src/utils/**/* 29 | -Dsonar.test.inclusions=**/*.test.js 30 | -Dsonar.tests=./src 31 | -Dsonar.javascript.lcov.reportPaths=coverage/lcov.info 32 | -Dsonar.eslint.eslintconfigpath=.eslintrc 33 | -Dsonar.issue.ignore.multicriteria=S6847,S6819,S3358 34 | -Dsonar.issue.ignore.multicriteria.S6847.ruleKey=javascript:S6847 35 | -Dsonar.issue.ignore.multicriteria.S6847.resourceKey=**/* 36 | -Dsonar.issue.ignore.multicriteria.S6819.ruleKey=javascript:S6819 37 | -Dsonar.issue.ignore.multicriteria.S6819.resourceKey=**/* 38 | -Dsonar.issue.ignore.multicriteria.S3358.ruleKey=javascript:S3358 39 | -Dsonar.issue.ignore.multicriteria.S3358.resourceKey=**/* 40 | env: 41 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 42 | SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | tyk-ui-styleguide 3 | coverage 4 | .nyc_output 5 | *DS_Store 6 | cypress/screenshots 7 | .vscode 8 | .scannerwork 9 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | save-prefix="" -------------------------------------------------------------------------------- /.stylelintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: 'stylelint-config-standard', 3 | plugins: [ 4 | 'stylelint-use-logical-spec', 5 | 'stylelint-declaration-block-no-ignored-properties' 6 | ], 7 | ignoreFiles: [ 8 | 'src/common/css/fontawesome.css', 9 | 'src/common/css/tykon.css' 10 | ], 11 | rules: { 12 | 'color-function-notation': ['modern', { ignore: ['with-var-inside'] }], 13 | 'color-hex-length': null, 14 | 'custom-property-empty-line-before': null, 15 | 'declaration-block-no-redundant-longhand-properties': null, 16 | 'import-notation': 'string', 17 | 'liberty/use-logical-spec': true, 18 | 'no-descending-specificity': null, 19 | 'plugin/declaration-block-no-ignored-properties': true, 20 | 'property-no-vendor-prefix': [true, { ignoreProperties: ['full-screen', 'mask', 'mask-size', 'user-select'] }], 21 | 'selector-class-pattern': null, 22 | 'selector-no-vendor-prefix': [true, { ignoreSelectors: [':-webkit-full-screen', ':-ms-input-placeholder'] }], 23 | } 24 | }; 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Tyk-ui is our library of reusable presentational UI components. The full list of components and their documentation can be checked here: 2 | https://nifty-johnson-6002dd.netlify.app/ 3 | 4 | *Installation* 5 | ```javascript 6 | npm install --save @tyk-technologies/tyk-ui 7 | ``` 8 | 9 | **Loading tyk-ui into the project** 10 | 11 | *Import the css before any other styles from your main js file* 12 | ```javascript static 13 | import '@tyk-technologies/tyk-ui/src/index.css'; 14 | ``` 15 | 16 | *Loading SASS files (only if your project uses SASS)* 17 | ```scss 18 | @import '~@tyk-technologies/tyk-ui/lib/sass/index'; 19 | ``` 20 | *NOTE*: 21 | For projects that don't use SASS but just pure css we are also exposing the compiled styles. 22 | ```html 23 | 24 | ``` 25 | 26 | *Loading React components* 27 | ```javascript static 28 | import { 29 | Button, 30 | Column, 31 | Dropdown, 32 | Icon, 33 | InfoNote, 34 | Message, 35 | Modal, 36 | Panel, 37 | Row 38 | } from '@tyk-technologies/tyk-ui'; 39 | ``` 40 | 41 | *Note*: for the projects that don't have React this is not usable, and we can use just the styling. 42 | 43 | ## Build tyk-ui project 44 | Contributions to the current library are welcome, so please follow these steps each time you want to make a change: 45 | 46 | - Create a GH issue, describing the necessary change 47 | - Raise a PR with the change 48 | 49 | *In order to publish the changes, please do the following* 50 | - After PR merge, run `npm run build-prod` which generates prod code of the library 51 | - Increase the library version in `package.json` 52 | - Run `npm i` to regenerate the `package-lock.json` file 53 | - Commit and Push changes 54 | - Run `npm publish` 55 | -------------------------------------------------------------------------------- /cypress.config.js: -------------------------------------------------------------------------------- 1 | const { defineConfig } = require('cypress'); 2 | const cypressCoverageTask = require('@cypress/code-coverage/task'); 3 | 4 | const webpackConfig = require('./webpack.component'); 5 | 6 | module.exports = defineConfig({ 7 | includeShadowDom: true, 8 | video: false, 9 | viewportWidth: 1024, 10 | viewportHeight: 768, 11 | component: { 12 | specPattern: 'src/**/*.test.js', 13 | supportFile: 'cypress/support/component.js', 14 | devServer: { 15 | framework: 'react', 16 | bundler: 'webpack', 17 | webpackConfig, 18 | }, 19 | setupNodeEvents(on, config) { 20 | cypressCoverageTask(on, config); 21 | return config; 22 | }, 23 | }, 24 | }); 25 | -------------------------------------------------------------------------------- /cypress/fixtures/example.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Using fixtures to represent data", 3 | "email": "hello@cypress.io", 4 | "body": "Fixtures are a great way to mock data for responses to routes" 5 | } 6 | -------------------------------------------------------------------------------- /cypress/support/commands.js: -------------------------------------------------------------------------------- 1 | // *********************************************** 2 | // This example commands.js shows you how to 3 | // create various custom commands and overwrite 4 | // existing commands. 5 | // 6 | // For more comprehensive examples of custom 7 | // commands please read more here: 8 | // https://on.cypress.io/custom-commands 9 | // *********************************************** 10 | // 11 | // 12 | // -- This is a parent command -- 13 | // Cypress.Commands.add('login', (email, password) => { ... }) 14 | // 15 | // 16 | // -- This is a child command -- 17 | // Cypress.Commands.add('drag', { prevSubject: 'element'}, (subject, options) => { ... }) 18 | // 19 | // 20 | // -- This is a dual command -- 21 | // Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... }) 22 | // 23 | // 24 | // -- This will overwrite an existing command -- 25 | // Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... }) 26 | -------------------------------------------------------------------------------- /cypress/support/component-index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Components App 8 | 9 | 10 |
11 | 12 | -------------------------------------------------------------------------------- /cypress/support/component.js: -------------------------------------------------------------------------------- 1 | // *********************************************************** 2 | // This example support/component.js is processed and 3 | // loaded automatically before your test files. 4 | // 5 | // This is a great place to put global configuration and 6 | // behavior that modifies Cypress. 7 | // 8 | // You can change the location of this file or turn off 9 | // automatically serving support files with the 10 | // 'supportFile' configuration option. 11 | // 12 | // You can read more here: 13 | // https://on.cypress.io/configuration 14 | // *********************************************************** 15 | 16 | // Import commands.js using ES2015 syntax: 17 | import './commands'; 18 | 19 | import '@cypress/code-coverage/support'; 20 | 21 | // Alternatively you can use CommonJS syntax: 22 | // require('./commands') 23 | 24 | import { mount } from 'cypress/react18'; 25 | import '../../src/index.css'; 26 | 27 | Cypress.Commands.add('mount', mount); 28 | 29 | // Example use: 30 | // cy.mount() 31 | -------------------------------------------------------------------------------- /docs/Contributing.md: -------------------------------------------------------------------------------- 1 | Contributions to the current library are welcome, so please follow these steps each time you want to make a change: 2 | 3 | - Create a GH issue / RFC, describing the necessary changes [here](https://github.com/TykTechnologies/tyk-ui/issues/new). 4 | - Create a component 5 | - Raise a PR for approval with initial documentation 6 | - Write a unit test 7 | - Document a component in the following format 8 | 9 | ```md 10 | 1. Description. 11 | 2. Usage with different combinations of examples. 12 | 3. Best practices. 13 | 4. Documents the proptypes for the component. 14 | 5. References if any 15 | ``` 16 | 17 | ```md 18 | For internal component and proptypes documentation follow the guide here 19 | - https://react-styleguidist.js.org/docs/documenting/ 20 | ``` 21 | -------------------------------------------------------------------------------- /docs/Fonts.md: -------------------------------------------------------------------------------- 1 | - Default fonts and how to override them -------------------------------------------------------------------------------- /docs/GettingStarted.md: -------------------------------------------------------------------------------- 1 | Tyk-ui is library of reusable presentational UI components. 2 | 3 | ### **Installation** 4 | 5 | ```html 6 | npm install --save @tyk-technologies/tyk-ui 7 | ``` 8 | 9 | ### **Loading tyk-ui into the project** 10 | 11 | 12 | - *Loading React components* 13 | 14 | ```jsx static 15 | import { 16 | Button, 17 | Column, 18 | Dropdown, 19 | Icon, 20 | InfoNote, 21 | Message, 22 | Modal, 23 | Panel, 24 | Row 25 | } from '@tyk-technologies/tyk-ui'; 26 | ``` 27 | 28 | ```md 29 | *Note*: for the projects that don't have React this is not usable, and we can use just the styling. 30 | ``` 31 | 32 | - *Import the css before any other styles from your main js file* 33 | ```javascript static 34 | import '@tyk-technologies/tyk-ui/src/index.css'; 35 | ``` 36 | 37 | - *Loading SASS files (only if your project uses SASS)* 38 | 39 | ```scss 40 | @import '~@tyk-technologies/tyk-ui/lib/sass/index'; 41 | ``` 42 | 43 | ```html 44 | 45 | ``` 46 | 47 | ```md 48 | NOTE : For projects that don't SASS but just pure css we are also exposing the compiled styles. 49 | ``` 50 | ### Testing on local 51 | 52 | - You can test the changes on your local dev environment by replacing the your `@tyk-technologies/tyk-ui/lib` with newly built lib 53 | 54 | eg 55 | ```md 56 | cp -a lib/. /Users/me/go/src/github.com/TykTechnologies/tyk-analytics/webclient/node_modules/@tyk-technologies/tyk-ui/lib 57 | ``` -------------------------------------------------------------------------------- /docs/Globals.md: -------------------------------------------------------------------------------- 1 | - tyk-ui global variables documentation -------------------------------------------------------------------------------- /docs/PublishingGuide.md: -------------------------------------------------------------------------------- 1 | *In order to publish the changes, please do the following* 2 | - After PR merge, make a new build and generates prod code of the library 3 | 4 | ```shell static 5 | npm run build-prod 6 | ``` 7 | 8 | - Increase the library version in `package.json` 9 | 10 | - Regenerate the `package-lock.json` file 11 | 12 | ```shell static 13 | npm i 14 | ``` 15 | 16 | ```shell static 17 | git add . 18 | ``` 19 | 20 | - Commit and Push changes 21 | ```shell static 22 | git commit -m "bump version" 23 | ``` 24 | 25 | - Publish the package to npm 26 | ```shell static 27 | npm publish 28 | ``` -------------------------------------------------------------------------------- /docs/Theming.md: -------------------------------------------------------------------------------- 1 | - How to use/override tyk-ui themes -------------------------------------------------------------------------------- /lib/fonts/fontawesome/fa-light-300.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/tyk-ui/ca095e717455a87e51a2236c0110aef2fa921023/lib/fonts/fontawesome/fa-light-300.ttf -------------------------------------------------------------------------------- /lib/fonts/fontawesome/fa-light-300.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/tyk-ui/ca095e717455a87e51a2236c0110aef2fa921023/lib/fonts/fontawesome/fa-light-300.woff2 -------------------------------------------------------------------------------- /lib/fonts/fontawesome/fa-regular-400.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/tyk-ui/ca095e717455a87e51a2236c0110aef2fa921023/lib/fonts/fontawesome/fa-regular-400.ttf -------------------------------------------------------------------------------- /lib/fonts/fontawesome/fa-regular-400.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/tyk-ui/ca095e717455a87e51a2236c0110aef2fa921023/lib/fonts/fontawesome/fa-regular-400.woff2 -------------------------------------------------------------------------------- /lib/fonts/fontawesome/fa-solid-900.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/tyk-ui/ca095e717455a87e51a2236c0110aef2fa921023/lib/fonts/fontawesome/fa-solid-900.ttf -------------------------------------------------------------------------------- /lib/fonts/fontawesome/fa-solid-900.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/tyk-ui/ca095e717455a87e51a2236c0110aef2fa921023/lib/fonts/fontawesome/fa-solid-900.woff2 -------------------------------------------------------------------------------- /lib/fonts/inter/Inter-Bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/tyk-ui/ca095e717455a87e51a2236c0110aef2fa921023/lib/fonts/inter/Inter-Bold.woff -------------------------------------------------------------------------------- /lib/fonts/inter/Inter-Bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/tyk-ui/ca095e717455a87e51a2236c0110aef2fa921023/lib/fonts/inter/Inter-Bold.woff2 -------------------------------------------------------------------------------- /lib/fonts/inter/Inter-Light.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/tyk-ui/ca095e717455a87e51a2236c0110aef2fa921023/lib/fonts/inter/Inter-Light.woff -------------------------------------------------------------------------------- /lib/fonts/inter/Inter-Light.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/tyk-ui/ca095e717455a87e51a2236c0110aef2fa921023/lib/fonts/inter/Inter-Light.woff2 -------------------------------------------------------------------------------- /lib/fonts/inter/Inter-Medium.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/tyk-ui/ca095e717455a87e51a2236c0110aef2fa921023/lib/fonts/inter/Inter-Medium.woff -------------------------------------------------------------------------------- /lib/fonts/inter/Inter-Medium.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/tyk-ui/ca095e717455a87e51a2236c0110aef2fa921023/lib/fonts/inter/Inter-Medium.woff2 -------------------------------------------------------------------------------- /lib/fonts/inter/Inter-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/tyk-ui/ca095e717455a87e51a2236c0110aef2fa921023/lib/fonts/inter/Inter-Regular.woff -------------------------------------------------------------------------------- /lib/fonts/inter/Inter-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/tyk-ui/ca095e717455a87e51a2236c0110aef2fa921023/lib/fonts/inter/Inter-Regular.woff2 -------------------------------------------------------------------------------- /lib/fonts/inter/Inter-SemiBold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/tyk-ui/ca095e717455a87e51a2236c0110aef2fa921023/lib/fonts/inter/Inter-SemiBold.woff -------------------------------------------------------------------------------- /lib/fonts/inter/Inter-SemiBold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/tyk-ui/ca095e717455a87e51a2236c0110aef2fa921023/lib/fonts/inter/Inter-SemiBold.woff2 -------------------------------------------------------------------------------- /lib/fonts/tykon.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/tyk-ui/ca095e717455a87e51a2236c0110aef2fa921023/lib/fonts/tykon.woff -------------------------------------------------------------------------------- /lib/fonts/tykon.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/tyk-ui/ca095e717455a87e51a2236c0110aef2fa921023/lib/fonts/tykon.woff2 -------------------------------------------------------------------------------- /lib/images/arrow_down.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lib/images/drag.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /lib/index.js.LICENSE.txt: -------------------------------------------------------------------------------- 1 | /* 2 | * based on code from: 3 | * 4 | * @license RequireJS text 0.25.0 Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. 5 | * Available via the MIT or new BSD license. 6 | * see: http://github.com/jrburke/requirejs for details 7 | */ 8 | -------------------------------------------------------------------------------- /lib/sass/common/sass/mixins.scss: -------------------------------------------------------------------------------- 1 | @use 'sass:map'; 2 | 3 | @function theme-color($key: 'primary', $variant: 'base') { 4 | $map: map.get($theme-colors, $key); 5 | 6 | @return map.get($map, $variant); 7 | } 8 | 9 | @function text-scale($level) { 10 | @return map.get(map.get($text-settings, $level), 'font-size'); 11 | } 12 | 13 | @function line-height($level) { 14 | @return map.get(map.get($text-settings, $level), 'line-height'); 15 | } -------------------------------------------------------------------------------- /lib/tyk-ui.js.LICENSE.txt: -------------------------------------------------------------------------------- 1 | /* 2 | * based on code from: 3 | * 4 | * @license RequireJS text 0.25.0 Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. 5 | * Available via the MIT or new BSD license. 6 | * see: http://github.com/jrburke/requirejs for details 7 | */ 8 | -------------------------------------------------------------------------------- /logo/index.js: -------------------------------------------------------------------------------- 1 | const React = require('react') 2 | const { version } = require('../package.json') 3 | 4 | const Logo = () => { 5 | return ( 6 | 11 | 12 | v.{version} 13 | 14 | ); 15 | }; 16 | 17 | module.exports = Logo -------------------------------------------------------------------------------- /src/common/css/fontawesome/light.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Font Awesome Pro 6.5.2 by @fontawesome - https://fontawesome.com 3 | * License - https://fontawesome.com/license (Commercial License) 4 | * Copyright 2024 Fonticons, Inc. 5 | */ 6 | :root, :host { 7 | --fa-style-family-classic: 'Font Awesome 6 Pro'; 8 | --fa-font-light: normal 300 1em/1 'Font Awesome 6 Pro'; } 9 | 10 | @font-face { 11 | font-family: 'Font Awesome 6 Pro'; 12 | font-style: normal; 13 | font-weight: 300; 14 | font-display: block; 15 | src: url("../../fonts/fontawesome/fa-light-300.woff2") format("woff2"), url("../../fonts/fontawesome/fa-light-300.ttf") format("truetype"); } 16 | 17 | .fal, 18 | .fa-light { 19 | font-weight: 300; } 20 | -------------------------------------------------------------------------------- /src/common/css/fontawesome/regular.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Font Awesome Pro 6.5.2 by @fontawesome - https://fontawesome.com 3 | * License - https://fontawesome.com/license (Commercial License) 4 | * Copyright 2024 Fonticons, Inc. 5 | */ 6 | :root, :host { 7 | --fa-style-family-classic: 'Font Awesome 6 Pro'; 8 | --fa-font-regular: normal 400 1em/1 'Font Awesome 6 Pro'; } 9 | 10 | @font-face { 11 | font-family: 'Font Awesome 6 Pro'; 12 | font-style: normal; 13 | font-weight: 400; 14 | font-display: block; 15 | src: url("../../fonts/fontawesome/fa-regular-400.woff2") format("woff2"), url("../../fonts/fontawesome/fa-regular-400.ttf") format("truetype"); } 16 | 17 | .far, 18 | .fa-regular { 19 | font-weight: 400; } 20 | -------------------------------------------------------------------------------- /src/common/css/fontawesome/solid.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Font Awesome Pro 6.5.2 by @fontawesome - https://fontawesome.com 3 | * License - https://fontawesome.com/license (Commercial License) 4 | * Copyright 2024 Fonticons, Inc. 5 | */ 6 | :root, :host { 7 | --fa-style-family-classic: 'Font Awesome 6 Pro'; 8 | --fa-font-solid: normal 900 1em/1 'Font Awesome 6 Pro'; } 9 | 10 | @font-face { 11 | font-family: 'Font Awesome 6 Pro'; 12 | font-style: normal; 13 | font-weight: 900; 14 | font-display: block; 15 | src: url("../../fonts/fontawesome/fa-solid-900.woff2") format("woff2"), url("../../fonts/fontawesome/fa-solid-900.ttf") format("truetype"); } 16 | 17 | .fas, 18 | .fa-solid { 19 | font-weight: 900; } 20 | -------------------------------------------------------------------------------- /src/common/css/fonts.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: Inter-Bold; 3 | src: url('../fonts/inter/Inter-Bold.woff2') format('woff2'), 4 | url('../fonts/inter/Inter-Bold.woff') format('woff'); 5 | font-weight: normal; 6 | font-style: normal; 7 | } 8 | 9 | @font-face { 10 | font-family: Inter-Light; 11 | src: url('../fonts/inter/Inter-Light.woff2') format('woff2'), 12 | url('../fonts/inter/Inter-Light.woff') format('woff'); 13 | font-weight: normal; 14 | font-style: normal; 15 | } 16 | 17 | @font-face { 18 | font-family: Inter-Medium; 19 | src: url('../fonts/inter/Inter-Medium.woff2') format('woff2'), 20 | url('../fonts/inter/Inter-Medium.woff') format('woff'); 21 | font-weight: normal; 22 | font-style: normal; 23 | } 24 | 25 | @font-face { 26 | font-family: Inter-Regular; 27 | src: url('../fonts/inter/Inter-Regular.woff2') format('woff2'), 28 | url('../fonts/inter/Inter-Regular.woff') format('woff'); 29 | font-weight: normal; 30 | font-style: normal; 31 | } 32 | 33 | @font-face { 34 | font-family: Inter-SemiBold; 35 | src: url('../fonts/inter/Inter-SemiBold.woff2') format('woff2'), 36 | url('../fonts/inter/Inter-SemiBold.woff') format('woff'); 37 | font-weight: normal; 38 | font-style: normal; 39 | } 40 | 41 | @font-face { 42 | font-family: tykon; 43 | src: url('../fonts/tykon.woff2') format('woff2'), 44 | url('../fonts/tykon.woff') format('woff'); 45 | font-weight: normal; 46 | font-style: normal; 47 | } 48 | -------------------------------------------------------------------------------- /src/common/css/layout.css: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; 3 | } 4 | 5 | body { 6 | background-color: var(--color-background); 7 | color: var(--text-color); 8 | font-size: var(--sm-font-size); 9 | line-height: var(--sm-line-height); 10 | font-family: var(--font-family-regular); 11 | } 12 | 13 | .tyk-main-wrapper { 14 | display: flex; 15 | flex-wrap: nowrap; 16 | } 17 | 18 | .tyk-main-content-wrapper { 19 | flex: 1; 20 | } 21 | 22 | .well { 23 | background: transparent; 24 | border: var(--general-border-width) solid var(--color-secondary-dark); 25 | border-radius: var(--general-border-radius); 26 | box-shadow: none; 27 | 28 | &.has-error { 29 | border-color: var(--color-danger-base); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/common/css/reset.css: -------------------------------------------------------------------------------- 1 | html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, article, aside, canvas, details, embed, figure, figcaption, footer, header, hgroup, menu, nav, output, ruby, section, summary, time, mark, audio, video { 2 | margin: 0; 3 | padding: 0; 4 | border: 0; 5 | font: inherit; 6 | font-size: 100%; 7 | vertical-align: baseline; 8 | } 9 | 10 | /* HTML5 display-role reset for older browsers */ 11 | 12 | article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav, section { 13 | display: block; } 14 | 15 | body { 16 | line-height: 1; } 17 | 18 | ol, ul { 19 | list-style: none; } 20 | 21 | blockquote, q { 22 | quotes: none; } 23 | 24 | blockquote { 25 | &::before, &::after { 26 | content: ''; 27 | content: none; } } 28 | 29 | q { 30 | &::before, &::after { 31 | content: ''; 32 | content: none; } } 33 | 34 | table { 35 | border-collapse: collapse; 36 | border-spacing: 0; } 37 | -------------------------------------------------------------------------------- /src/common/css/texts.css: -------------------------------------------------------------------------------- 1 | .title-medium { 2 | font-family: var(--font-family-medium); 3 | color: var(--label-color); 4 | font-size: var(--title-medium-font-size); 5 | } -------------------------------------------------------------------------------- /src/common/fonts/fontawesome/fa-light-300.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/tyk-ui/ca095e717455a87e51a2236c0110aef2fa921023/src/common/fonts/fontawesome/fa-light-300.ttf -------------------------------------------------------------------------------- /src/common/fonts/fontawesome/fa-light-300.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/tyk-ui/ca095e717455a87e51a2236c0110aef2fa921023/src/common/fonts/fontawesome/fa-light-300.woff2 -------------------------------------------------------------------------------- /src/common/fonts/fontawesome/fa-regular-400.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/tyk-ui/ca095e717455a87e51a2236c0110aef2fa921023/src/common/fonts/fontawesome/fa-regular-400.ttf -------------------------------------------------------------------------------- /src/common/fonts/fontawesome/fa-regular-400.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/tyk-ui/ca095e717455a87e51a2236c0110aef2fa921023/src/common/fonts/fontawesome/fa-regular-400.woff2 -------------------------------------------------------------------------------- /src/common/fonts/fontawesome/fa-solid-900.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/tyk-ui/ca095e717455a87e51a2236c0110aef2fa921023/src/common/fonts/fontawesome/fa-solid-900.ttf -------------------------------------------------------------------------------- /src/common/fonts/fontawesome/fa-solid-900.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/tyk-ui/ca095e717455a87e51a2236c0110aef2fa921023/src/common/fonts/fontawesome/fa-solid-900.woff2 -------------------------------------------------------------------------------- /src/common/fonts/inter/Inter-Bold.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/tyk-ui/ca095e717455a87e51a2236c0110aef2fa921023/src/common/fonts/inter/Inter-Bold.eot -------------------------------------------------------------------------------- /src/common/fonts/inter/Inter-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/tyk-ui/ca095e717455a87e51a2236c0110aef2fa921023/src/common/fonts/inter/Inter-Bold.ttf -------------------------------------------------------------------------------- /src/common/fonts/inter/Inter-Bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/tyk-ui/ca095e717455a87e51a2236c0110aef2fa921023/src/common/fonts/inter/Inter-Bold.woff -------------------------------------------------------------------------------- /src/common/fonts/inter/Inter-Bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/tyk-ui/ca095e717455a87e51a2236c0110aef2fa921023/src/common/fonts/inter/Inter-Bold.woff2 -------------------------------------------------------------------------------- /src/common/fonts/inter/Inter-Light.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/tyk-ui/ca095e717455a87e51a2236c0110aef2fa921023/src/common/fonts/inter/Inter-Light.eot -------------------------------------------------------------------------------- /src/common/fonts/inter/Inter-Light.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/tyk-ui/ca095e717455a87e51a2236c0110aef2fa921023/src/common/fonts/inter/Inter-Light.ttf -------------------------------------------------------------------------------- /src/common/fonts/inter/Inter-Light.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/tyk-ui/ca095e717455a87e51a2236c0110aef2fa921023/src/common/fonts/inter/Inter-Light.woff -------------------------------------------------------------------------------- /src/common/fonts/inter/Inter-Light.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/tyk-ui/ca095e717455a87e51a2236c0110aef2fa921023/src/common/fonts/inter/Inter-Light.woff2 -------------------------------------------------------------------------------- /src/common/fonts/inter/Inter-Medium.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/tyk-ui/ca095e717455a87e51a2236c0110aef2fa921023/src/common/fonts/inter/Inter-Medium.eot -------------------------------------------------------------------------------- /src/common/fonts/inter/Inter-Medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/tyk-ui/ca095e717455a87e51a2236c0110aef2fa921023/src/common/fonts/inter/Inter-Medium.ttf -------------------------------------------------------------------------------- /src/common/fonts/inter/Inter-Medium.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/tyk-ui/ca095e717455a87e51a2236c0110aef2fa921023/src/common/fonts/inter/Inter-Medium.woff -------------------------------------------------------------------------------- /src/common/fonts/inter/Inter-Medium.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/tyk-ui/ca095e717455a87e51a2236c0110aef2fa921023/src/common/fonts/inter/Inter-Medium.woff2 -------------------------------------------------------------------------------- /src/common/fonts/inter/Inter-Regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/tyk-ui/ca095e717455a87e51a2236c0110aef2fa921023/src/common/fonts/inter/Inter-Regular.eot -------------------------------------------------------------------------------- /src/common/fonts/inter/Inter-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/tyk-ui/ca095e717455a87e51a2236c0110aef2fa921023/src/common/fonts/inter/Inter-Regular.ttf -------------------------------------------------------------------------------- /src/common/fonts/inter/Inter-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/tyk-ui/ca095e717455a87e51a2236c0110aef2fa921023/src/common/fonts/inter/Inter-Regular.woff -------------------------------------------------------------------------------- /src/common/fonts/inter/Inter-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/tyk-ui/ca095e717455a87e51a2236c0110aef2fa921023/src/common/fonts/inter/Inter-Regular.woff2 -------------------------------------------------------------------------------- /src/common/fonts/inter/Inter-SemiBold.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/tyk-ui/ca095e717455a87e51a2236c0110aef2fa921023/src/common/fonts/inter/Inter-SemiBold.eot -------------------------------------------------------------------------------- /src/common/fonts/inter/Inter-SemiBold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/tyk-ui/ca095e717455a87e51a2236c0110aef2fa921023/src/common/fonts/inter/Inter-SemiBold.ttf -------------------------------------------------------------------------------- /src/common/fonts/inter/Inter-SemiBold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/tyk-ui/ca095e717455a87e51a2236c0110aef2fa921023/src/common/fonts/inter/Inter-SemiBold.woff -------------------------------------------------------------------------------- /src/common/fonts/inter/Inter-SemiBold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/tyk-ui/ca095e717455a87e51a2236c0110aef2fa921023/src/common/fonts/inter/Inter-SemiBold.woff2 -------------------------------------------------------------------------------- /src/common/fonts/tykon.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/tyk-ui/ca095e717455a87e51a2236c0110aef2fa921023/src/common/fonts/tykon.eot -------------------------------------------------------------------------------- /src/common/fonts/tykon.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/tyk-ui/ca095e717455a87e51a2236c0110aef2fa921023/src/common/fonts/tykon.otf -------------------------------------------------------------------------------- /src/common/fonts/tykon.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/tyk-ui/ca095e717455a87e51a2236c0110aef2fa921023/src/common/fonts/tykon.ttf -------------------------------------------------------------------------------- /src/common/fonts/tykon.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/tyk-ui/ca095e717455a87e51a2236c0110aef2fa921023/src/common/fonts/tykon.woff -------------------------------------------------------------------------------- /src/common/fonts/tykon.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/tyk-ui/ca095e717455a87e51a2236c0110aef2fa921023/src/common/fonts/tykon.woff2 -------------------------------------------------------------------------------- /src/common/images/arrow-down.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 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 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /src/common/images/drag.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/common/sass/mixins.scss: -------------------------------------------------------------------------------- 1 | @use 'sass:map'; 2 | 3 | @function theme-color($key: 'primary', $variant: 'base') { 4 | $map: map.get($theme-colors, $key); 5 | 6 | @return map.get($map, $variant); 7 | } 8 | 9 | @function text-scale($level) { 10 | @return map.get(map.get($text-settings, $level), 'font-size'); 11 | } 12 | 13 | @function line-height($level) { 14 | @return map.get(map.get($text-settings, $level), 'line-height'); 15 | } -------------------------------------------------------------------------------- /src/components/Accordion/Accordion.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --accordion-item-header-padding-y: var(--spacing-base); 3 | --accordion-item-header-padding-x: var(--spacing-base); 4 | --accordion-item-header-font-size: var(--base-font-size); 5 | --accordion-item-outside-trigger-width: var(--spacing-xxl); 6 | } 7 | 8 | .tyk-accordion__item { 9 | display: grid; 10 | } 11 | 12 | .tyk-accordion__item--trigger-position-left { 13 | grid-template-columns: var(--accordion-item-outside-trigger-width) auto; 14 | grid-template-areas: 15 | "trigger header" 16 | "trigger content"; 17 | } 18 | 19 | .tyk-accordion__item--trigger-position-right { 20 | grid-template-columns: auto var(--accordion-item-outside-trigger-width); 21 | grid-template-areas: 22 | "header trigger" 23 | "content trigger"; 24 | } 25 | 26 | .tyk-accordion__item--trigger-in-header { 27 | grid-template-columns: auto; 28 | grid-template-areas: 29 | "header" 30 | "content"; 31 | } 32 | 33 | .tyk-accordion__trigger-wrapper { 34 | grid-area: trigger; 35 | display: flex; 36 | align-items: flex-start; 37 | justify-content: center; 38 | 39 | .tyk-icon { 40 | margin-inline: auto; 41 | } 42 | } 43 | 44 | .tyk-accordion__trigger, 45 | .tyk-accordion__item-header > button { 46 | background: none; 47 | border: none; 48 | cursor: pointer; 49 | display: flex; 50 | font-size: var(--accordion-item-header-font-size); 51 | outline: none; 52 | padding-inline: var(--accordion-item-header-padding-x); 53 | padding-block: var(--accordion-item-header-padding-y); 54 | inline-size: 100%; 55 | 56 | .tyk-icon { 57 | margin-inline-start: auto; 58 | } 59 | } 60 | 61 | .tyk-accordion__item-header { 62 | grid-area: header; 63 | } 64 | 65 | .tyk-accordion__trigger--disabled { 66 | color: var(--color-text-light); 67 | } 68 | 69 | .tyk-accordion__item-header.tyk-accordion__arrow-trigger { 70 | align-items: center; 71 | display: flex; 72 | 73 | > div { 74 | flex: 1; 75 | } 76 | 77 | > button { 78 | margin-inline-start: auto; 79 | inline-size: auto; 80 | } 81 | } 82 | 83 | .tyk-accordion__item-content { 84 | grid-area: content; 85 | } 86 | -------------------------------------------------------------------------------- /src/components/Accordion/Accordion.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import Accordion from './index'; 4 | 5 | describe('Accordion', () => { 6 | const selectors = { 7 | accordion: '.tyk-accordion', 8 | }; 9 | 10 | it('renders an accordion', () => { 11 | cy 12 | .mount( 13 | 18 | 19 | 20 | Header 1 21 | 22 | 23 | Content 1 24 | 25 | 26 | 27 | 28 | Header 2 29 | 30 | 31 | Content 2 32 | 33 | 34 | 35 | 36 | Header 3 37 | 38 | 39 | Content 3 40 | 41 | 42 | , 43 | ) 44 | .get(selectors.accordion) 45 | .should('exist'); 46 | }); 47 | }); 48 | -------------------------------------------------------------------------------- /src/components/Accordion/Readme.md: -------------------------------------------------------------------------------- 1 | ```js 2 | 7 | 8 | 9 | Header 1 10 | 11 | 12 | Content 1 13 | 14 | 15 | 16 | 17 | Header 2 18 | 19 | 20 | Content 2 21 | 22 | 23 | 24 | 25 | Header 3 26 | 27 | 28 | Content 3 29 | 30 | 31 | 32 | ``` 33 | -------------------------------------------------------------------------------- /src/components/Accordion/index.js: -------------------------------------------------------------------------------- 1 | import React, { useMemo } from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import AccordionItem from './js/AccordionItem'; 4 | import AccordionItemHeader from './js/AccordionItemHeader'; 5 | import AccordionItemContent from './js/AccordionItemContent'; 6 | import AccordionContext from './js/AccordionContext'; 7 | 8 | function Accordion({ 9 | className, 10 | children, 11 | usearrowastrigger = false, 12 | arrow = { position: 'right', expandToContent: false }, 13 | }) { 14 | const classes = [ 15 | 'tyk-accordion', 16 | className, 17 | ].filter(Boolean).join(' '); 18 | 19 | const contextValue = useMemo(() => ({ 20 | usearrowastrigger, 21 | arrow, 22 | }), [usearrowastrigger, arrow]); 23 | 24 | return ( 25 |
26 | 27 | {children} 28 | 29 |
30 | ); 31 | } 32 | 33 | Accordion.propTypes = { 34 | children: PropTypes.oneOfType([ 35 | PropTypes.arrayOf(PropTypes.node), 36 | PropTypes.node, 37 | PropTypes.element, 38 | PropTypes.string, 39 | ]), 40 | className: PropTypes.string, 41 | usearrowastrigger: PropTypes.bool, 42 | arrow: PropTypes.shape({ 43 | position: PropTypes.oneOf(['left', 'right']), 44 | expandToContent: PropTypes.bool, 45 | }), 46 | }; 47 | 48 | // For Readme.md : Start 49 | Accordion.Item = AccordionItem; 50 | Accordion.Item.Header = AccordionItemHeader; 51 | Accordion.Item.Content = AccordionItemContent; 52 | // For Readme.md : End 53 | 54 | export default Accordion; 55 | -------------------------------------------------------------------------------- /src/components/Accordion/js/AccordionContext.js: -------------------------------------------------------------------------------- 1 | import { createContext } from 'react'; 2 | 3 | const AccordionContext = createContext(); 4 | 5 | export default AccordionContext; 6 | -------------------------------------------------------------------------------- /src/components/Accordion/js/AccordionItem.js: -------------------------------------------------------------------------------- 1 | import React, { 2 | useMemo, useState, useContext, forwardRef, 3 | } from 'react'; 4 | import PropTypes from 'prop-types'; 5 | 6 | import AccordionContext from './AccordionContext'; 7 | import AccordionItemContext from './AccordionItemContext'; 8 | import ItemTrigger from './AccordionItemTrigger'; 9 | 10 | const AccordionItem = forwardRef(function AccordionItem ( 11 | { 12 | collapsed: collapsedProp = false, 13 | children, 14 | className, 15 | disabled, 16 | }, 17 | ref, 18 | ) { 19 | const { arrow } = useContext(AccordionContext); 20 | const [collapsed, setCollapsed] = useState(collapsedProp); 21 | 22 | const toggleChange = () => { 23 | if (disabled) { 24 | return; 25 | } 26 | 27 | setCollapsed(!collapsed); 28 | }; 29 | 30 | const classes = useMemo(() => [ 31 | 'tyk-accordion__item', 32 | arrow.expandToContent 33 | ? `tyk-accordion__item--trigger-position-${arrow.position}` 34 | : 'tyk-accordion__item--trigger-in-header', 35 | className, 36 | collapsed === false && 'tyk-accordion__item--active', 37 | ].filter(Boolean).join(' '), [arrow, className, collapsed]); 38 | 39 | const contextValue = useMemo(() => ({ 40 | collapsed, 41 | disabled, 42 | toggleChange, 43 | }), [collapsed, disabled, toggleChange]); 44 | 45 | return ( 46 |
47 | 48 | {arrow.expandToContent && ( 49 | 50 | )} 51 | {children} 52 | 53 |
54 | ); 55 | }); 56 | 57 | AccordionItem.propTypes = { 58 | children: PropTypes.oneOfType([ 59 | PropTypes.arrayOf(PropTypes.node), 60 | PropTypes.node, 61 | PropTypes.element, 62 | PropTypes.string, 63 | ]), 64 | collapsed: PropTypes.bool, 65 | className: PropTypes.string, 66 | disabled: PropTypes.bool, 67 | }; 68 | 69 | export default AccordionItem; 70 | -------------------------------------------------------------------------------- /src/components/Accordion/js/AccordionItemContent.js: -------------------------------------------------------------------------------- 1 | import React, { useContext } from 'react'; 2 | import PropTypes from 'prop-types'; 3 | 4 | import Collapsible from '../../Collapsible'; 5 | import AccordionItemContext from './AccordionItemContext'; 6 | 7 | function AccordionItemContent({ children, className }) { 8 | const { collapsed } = useContext(AccordionItemContext); 9 | 10 | const classes = [ 11 | 'tyk-accordion__item-content', 12 | className, 13 | ].filter(Boolean).join(' '); 14 | 15 | return ( 16 |
17 | 18 | { children } 19 | 20 |
21 | ); 22 | } 23 | 24 | AccordionItemContent.propTypes = { 25 | children: PropTypes.oneOfType([ 26 | PropTypes.arrayOf(PropTypes.node), 27 | PropTypes.node, 28 | PropTypes.element, 29 | PropTypes.string, 30 | ]), 31 | className: PropTypes.string, 32 | }; 33 | 34 | export default AccordionItemContent; 35 | -------------------------------------------------------------------------------- /src/components/Accordion/js/AccordionItemContent.test.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable react/prop-types */ 2 | import React from 'react'; 3 | 4 | import AccordionContext from './AccordionContext'; 5 | import AccordionItemContext from './AccordionItemContext'; 6 | import AccordionItemContent from './AccordionItemContent'; 7 | 8 | function Component({ 9 | usearrowastrigger = false, 10 | arrow = { position: 'right', expandToContent: false }, 11 | collapsed = false, 12 | disabled = false, 13 | className, 14 | children, 15 | }) { 16 | return ( 17 | 18 | {} }}> 19 | 20 | {children} 21 | 22 | 23 | 24 | ); 25 | } 26 | 27 | describe('AccordionItemContent', () => { 28 | const selectors = { 29 | collapseWrapper: '.collapse-wrapper', 30 | }; 31 | 32 | it('renders content inside a collapsible component', () => { 33 | const content = 'My Content'; 34 | cy 35 | .mount({content}) 36 | .get(selectors.collapseWrapper) 37 | .contains(content) 38 | .should('exist'); 39 | }); 40 | }); 41 | -------------------------------------------------------------------------------- /src/components/Accordion/js/AccordionItemContext.js: -------------------------------------------------------------------------------- 1 | import { createContext } from 'react'; 2 | 3 | const AccordionItemContext = createContext(); 4 | 5 | export default AccordionItemContext; 6 | -------------------------------------------------------------------------------- /src/components/Accordion/js/AccordionItemHeader.js: -------------------------------------------------------------------------------- 1 | import React, { useContext } from 'react'; 2 | import PropTypes from 'prop-types'; 3 | 4 | import Icon from '../../Icon'; 5 | import AccordionContext from './AccordionContext'; 6 | import AccordionItemContext from './AccordionItemContext'; 7 | import ItemTrigger from './AccordionItemTrigger'; 8 | 9 | function AccordionItemHeader({ className, children }) { 10 | const { collapsed, disabled, toggleChange } = useContext(AccordionItemContext); 11 | const { usearrowastrigger, arrow } = useContext(AccordionContext); 12 | const iconType = collapsed ? 'chevron-down' : 'chevron-up'; 13 | const classes = [ 14 | 'tyk-accordion__item-header', 15 | usearrowastrigger && 'tyk-accordion__arrow-trigger', 16 | className, 17 | ].filter(Boolean).join(' '); 18 | 19 | return ( 20 |
21 | { 22 | !usearrowastrigger 23 | ? ( 24 | 32 | ) 33 | : ( 34 | <> 35 | {!arrow.expandToContent && arrow.position === 'left' && ( 36 | 37 | )} 38 |
{children}
39 | {!arrow.expandToContent && arrow.position === 'right' && ( 40 | 41 | )} 42 | 43 | ) 44 | } 45 |
46 | ); 47 | } 48 | 49 | AccordionItemHeader.propTypes = { 50 | children: PropTypes.oneOfType([ 51 | PropTypes.arrayOf(PropTypes.node), 52 | PropTypes.node, 53 | PropTypes.element, 54 | PropTypes.string, 55 | ]), 56 | className: PropTypes.string, 57 | }; 58 | 59 | export default AccordionItemHeader; 60 | -------------------------------------------------------------------------------- /src/components/Accordion/js/AccordionItemHeader.test.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable react/prop-types */ 2 | import React from 'react'; 3 | 4 | import AccordionContext from './AccordionContext'; 5 | import AccordionItemContext from './AccordionItemContext'; 6 | import AccordionItemHeader from './AccordionItemHeader'; 7 | 8 | function Component({ 9 | usearrowastrigger = false, 10 | arrow = { position: 'right', expandToContent: false }, 11 | collapsed = false, 12 | disabled = false, 13 | className, 14 | children, 15 | }) { 16 | return ( 17 | 18 | {} }}> 19 | 20 | {children} 21 | 22 | 23 | 24 | ); 25 | } 26 | 27 | describe('AccordionItemHeader', () => { 28 | const selectors = { 29 | header: '.tyk-accordion__item-header', 30 | arrowAsTrigger: '.tyk-accordion__arrow-trigger', 31 | trigger: '.tyk-accordion__trigger', 32 | }; 33 | 34 | it('renders an element as the header of the accordion item', () => { 35 | cy 36 | .mount(My Item) 37 | .get(selectors.header) 38 | .should('exist'); 39 | }); 40 | 41 | it('renders an arrow as trigger if usearrowastrigger is true', () => { 42 | cy 43 | .mount(My Item) 44 | .get(selectors.arrowAsTrigger) 45 | .should('exist'); 46 | }); 47 | 48 | it('can render the trigger on the left side', () => { 49 | cy 50 | .mount(My Item) 51 | .get(`${selectors.trigger} + div`) 52 | .should('exist'); 53 | }); 54 | }); 55 | -------------------------------------------------------------------------------- /src/components/Accordion/js/AccordionItemTrigger.js: -------------------------------------------------------------------------------- 1 | import React, { useContext } from 'react'; 2 | import PropTypes from 'prop-types'; 3 | 4 | import Icon from '../../Icon'; 5 | import AccordionItemContext from './AccordionItemContext'; 6 | 7 | function ItemTrigger({ wrap }) { 8 | const { collapsed, disabled, toggleChange } = useContext(AccordionItemContext); 9 | 10 | const iconType = collapsed ? 'chevron-down' : 'chevron-up'; 11 | const classes = [ 12 | 'tyk-accordion__trigger', 13 | disabled && 'tyk-accordion__trigger--disabled', 14 | ].filter(Boolean).join(' '); 15 | const trigger = ( 16 | 24 | ); 25 | 26 | return wrap 27 | ?
{trigger}
28 | : trigger; 29 | } 30 | 31 | ItemTrigger.propTypes = { 32 | wrap: PropTypes.bool, 33 | }; 34 | 35 | export default ItemTrigger; 36 | -------------------------------------------------------------------------------- /src/components/Accordion/js/AccordionItemTrigger.test.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable react/prop-types */ 2 | import React from 'react'; 3 | 4 | import AccordionItemContext from './AccordionItemContext'; 5 | import ItemTrigger from './AccordionItemTrigger'; 6 | 7 | function Component({ 8 | collapsed = false, 9 | disabled = false, 10 | wrap = false, 11 | }) { 12 | return ( 13 | {} }}> 14 | 15 | 16 | ); 17 | } 18 | 19 | describe('ItemTrigger', () => { 20 | const selectors = { 21 | trigger: '.tyk-accordion__trigger', 22 | triggerWrapper: '.tyk-accordion__trigger-wrapper', 23 | iconCollapsed: '.fa-chevron-down', 24 | iconExpanded: '.fa-chevron-up', 25 | }; 26 | 27 | it('renders an element to trigger the change of the collapsed state', () => { 28 | cy 29 | .mount() 30 | .get(selectors.trigger) 31 | .should('exist'); 32 | }); 33 | 34 | it('renders different icons based on the collapsed state', () => { 35 | cy 36 | .mount() 37 | .get(selectors.trigger) 38 | .find(selectors.iconExpanded) 39 | .should('exist'); 40 | 41 | cy 42 | .mount() 43 | .get(selectors.trigger) 44 | .find(selectors.iconCollapsed) 45 | .should('exist'); 46 | }); 47 | 48 | it('can render a wrapper around it', () => { 49 | cy 50 | .mount() 51 | .get(selectors.triggerWrapper) 52 | .should('exist'); 53 | }); 54 | }); 55 | -------------------------------------------------------------------------------- /src/components/ButtonGroup/ButtonGroup.css: -------------------------------------------------------------------------------- 1 | .tyk-button-group__wrapper { 2 | display: inline-block; 3 | position: relative; 4 | vertical-align: middle; 5 | 6 | label { 7 | font-family: var(--font-family-bold); 8 | } 9 | 10 | + .tyk-button, 11 | + .tyk-dropdown, 12 | + .tyk-toggle, 13 | + .tyk-button-group__wrapper { 14 | margin-inline-start: var(--spacing-sm); 15 | } 16 | 17 | .tyk-button-group { 18 | display: flex; 19 | 20 | > .tyk-button-group:not(:first-child) { 21 | > .tyk-button { 22 | border-start-start-radius: 0; 23 | border-end-start-radius: 0; 24 | } 25 | } 26 | 27 | > .tyk-button-group:not(:last-child) { 28 | > .tyk-button { 29 | border-start-end-radius: 0; 30 | border-end-end-radius: 0; 31 | } 32 | } 33 | 34 | .tyk-button { 35 | border-radius: 0; 36 | 37 | &:hover { 38 | z-index: 10; 39 | } 40 | 41 | + .tyk-button { 42 | margin-inline-start: calc(-1 * var(--general-border-width)); 43 | } 44 | 45 | + .tyk-dropdown { 46 | margin-inline-start: calc(-1 * var(--general-border-width)); 47 | } 48 | 49 | &:last-child { 50 | border-start-end-radius: var(--spacing-md); 51 | border-end-end-radius: var(--spacing-md); 52 | 53 | &.tyk-button--icon-only { 54 | inline-size: 42px; 55 | } 56 | } 57 | 58 | &:first-child { 59 | border-start-start-radius: var(--spacing-md); 60 | border-end-start-radius: var(--spacing-md); 61 | } 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/components/ButtonGroup/ButtonGroup.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ButtonGroup from './index'; 3 | import Button from '../Button'; 4 | 5 | describe('ButtonGroup', () => { 6 | const wrapperSelector = '.tyk-button-group__wrapper'; 7 | 8 | it('renders the component with proper classes', () => { 9 | cy 10 | .mount( 11 | 12 | 13 | 14 | , 15 | ) 16 | .get(wrapperSelector) 17 | .should('have.class', 'foo') 18 | .and('have.class', 'bar'); 19 | }); 20 | 21 | it('can have a label', () => { 22 | const labelText = 'My Label'; 23 | 24 | cy 25 | .mount( 26 | 27 | 28 | 29 | , 30 | ) 31 | .get(wrapperSelector) 32 | .find('label') 33 | .should('exist') 34 | .and('have.text', labelText); 35 | }); 36 | }); 37 | -------------------------------------------------------------------------------- /src/components/ButtonGroup/index.js: -------------------------------------------------------------------------------- 1 | import React, { forwardRef } from 'react'; 2 | import PropTypes from 'prop-types'; 3 | 4 | const ButtonGroup = forwardRef(function ButtonGroup({ className, children, label }, ref) { 5 | return ( 6 |
7 | {Boolean(label) && } 8 |
{children}
9 |
10 | ); 11 | }); 12 | 13 | ButtonGroup.propTypes = { 14 | children: PropTypes.oneOfType([ 15 | PropTypes.arrayOf(PropTypes.node), 16 | PropTypes.node, 17 | PropTypes.element, 18 | PropTypes.string, 19 | ]), 20 | className: PropTypes.string, 21 | label: PropTypes.string, 22 | }; 23 | 24 | export default ButtonGroup; 25 | -------------------------------------------------------------------------------- /src/components/Card/CardBody.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | 4 | function CardBody({ 5 | align = 'top', 6 | children, 7 | }) { 8 | return ( 9 |
10 |
11 | {children} 12 |
13 |
14 | ); 15 | } 16 | 17 | CardBody.propTypes = { 18 | align: PropTypes.oneOf(['top', 'center', 'bottom']), 19 | children: PropTypes.oneOfType([ 20 | PropTypes.element, 21 | PropTypes.node, 22 | PropTypes.string, 23 | ]), 24 | }; 25 | 26 | export default CardBody; 27 | -------------------------------------------------------------------------------- /src/components/Card/CardFooter.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | 4 | function CardFooter({ children }) { 5 | return ( 6 |
7 | {children} 8 |
9 | ); 10 | } 11 | 12 | CardFooter.propTypes = { 13 | children: PropTypes.oneOfType([ 14 | PropTypes.element, 15 | PropTypes.node, 16 | PropTypes.string, 17 | ]), 18 | }; 19 | 20 | export default CardFooter; 21 | -------------------------------------------------------------------------------- /src/components/Card/CardHeader.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | 4 | function CardHeader({ 5 | right = null, 6 | children, 7 | }) { 8 | return ( 9 |
10 | {children &&
{children}
} 11 | {right &&
{right}
} 12 |
13 | ); 14 | } 15 | 16 | CardHeader.propTypes = { 17 | right: PropTypes.oneOfType([ 18 | PropTypes.element, 19 | PropTypes.node, 20 | PropTypes.string, 21 | ]), 22 | children: PropTypes.oneOfType([ 23 | PropTypes.element, 24 | PropTypes.node, 25 | PropTypes.string, 26 | ]), 27 | }; 28 | 29 | export default CardHeader; 30 | -------------------------------------------------------------------------------- /src/components/Card/CardSubTitle.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | 4 | function CardSubTitle({ 5 | children, 6 | }) { 7 | return ( 8 |
9 | {children} 10 |
11 | ); 12 | } 13 | 14 | CardSubTitle.propTypes = { 15 | children: PropTypes.oneOfType([ 16 | PropTypes.element, 17 | PropTypes.node, 18 | PropTypes.string, 19 | ]), 20 | }; 21 | 22 | export default CardSubTitle; 23 | -------------------------------------------------------------------------------- /src/components/Card/CardSummary.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | 4 | function CardSummary({ 5 | maxLines = 2, // accepted values: 1, 2, 3, 4, 5 6 | children, 7 | }) { 8 | return ( 9 |

10 | {children} 11 |

12 | ); 13 | } 14 | 15 | CardSummary.propTypes = { 16 | maxLines: PropTypes.oneOfType([ 17 | PropTypes.number, 18 | PropTypes.string, 19 | ]), 20 | children: PropTypes.oneOfType([ 21 | PropTypes.element, 22 | PropTypes.node, 23 | PropTypes.string, 24 | ]), 25 | }; 26 | 27 | export default CardSummary; 28 | -------------------------------------------------------------------------------- /src/components/Card/CardTitle.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | 4 | function CardTitle({ 5 | maxLines = 1, // accepted values: 1, 2 6 | children, 7 | }) { 8 | return ( 9 |

10 | {children} 11 |

12 | ); 13 | } 14 | 15 | CardTitle.propTypes = { 16 | maxLines: PropTypes.number, 17 | children: PropTypes.oneOfType([ 18 | PropTypes.element, 19 | PropTypes.node, 20 | PropTypes.string, 21 | ]), 22 | }; 23 | 24 | export default CardTitle; 25 | -------------------------------------------------------------------------------- /src/components/Card/CardTitleGroup.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | 4 | function CardTitleGroup({ 5 | children, 6 | }) { 7 | return ( 8 |
9 | {children} 10 |
11 | ); 12 | } 13 | 14 | CardTitleGroup.propTypes = { 15 | children: PropTypes.oneOfType([ 16 | PropTypes.element, 17 | PropTypes.node, 18 | PropTypes.string, 19 | ]), 20 | }; 21 | 22 | export default CardTitleGroup; 23 | -------------------------------------------------------------------------------- /src/components/Card/CardTitleIcon.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | 4 | function CardTitleIcon({ 5 | children, 6 | }) { 7 | return ( 8 |
9 | {children} 10 |
11 | ); 12 | } 13 | 14 | CardTitleIcon.propTypes = { 15 | children: PropTypes.oneOfType([ 16 | PropTypes.element, 17 | PropTypes.node, 18 | PropTypes.string, 19 | ]), 20 | }; 21 | 22 | export default CardTitleIcon; 23 | -------------------------------------------------------------------------------- /src/components/Card/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import CardHeader from './CardHeader'; 4 | import CardBody from './CardBody'; 5 | import CardFooter from './CardFooter'; 6 | import CardTitle from './CardTitle'; 7 | import CardTitleGroup from './CardTitleGroup'; 8 | import CardSubTitle from './CardSubTitle'; 9 | import CardSummary from './CardSummary'; 10 | import CardTitleIcon from './CardTitleIcon'; 11 | 12 | function Card({ 13 | className = '', 14 | height = 'auto', 15 | onSelect, 16 | selected, 17 | children, 18 | }) { 19 | 20 | return ( 21 |
31 | {children} 32 |
33 | ); 34 | } 35 | 36 | Card.propTypes = { 37 | className: PropTypes.string, 38 | height: PropTypes.oneOfType([ 39 | PropTypes.number, 40 | PropTypes.string, 41 | ]), 42 | children: PropTypes.oneOfType([ 43 | PropTypes.element, 44 | PropTypes.node, 45 | PropTypes.string, 46 | ]), 47 | }; 48 | 49 | Card.Header = CardHeader; 50 | Card.Body = CardBody; 51 | Card.Footer = CardFooter; 52 | Card.Title = CardTitle; 53 | Card.TitleGroup = CardTitleGroup; 54 | Card.Icon = CardTitleIcon; 55 | Card.SubTitle = CardSubTitle; 56 | Card.Summary = CardSummary; 57 | 58 | export default Card; 59 | -------------------------------------------------------------------------------- /src/components/Chart/Chart.css: -------------------------------------------------------------------------------- 1 | .tyk-chart__wrapper { 2 | position: relative; 3 | } 4 | 5 | .tyk-chart--no-data, 6 | .tyk-chart--loading-chart { 7 | filter: blur(var(--spacing-sm)); 8 | } 9 | -------------------------------------------------------------------------------- /src/components/Chart/Readme.md: -------------------------------------------------------------------------------- 1 | ```js 2 | 22 | ``` 23 | -------------------------------------------------------------------------------- /src/components/Collapsible/Collapsible.css: -------------------------------------------------------------------------------- 1 | .collapse-exit, 2 | .collapse-exit-active, 3 | .collapse-exit-done { 4 | block-size: 0; 5 | } 6 | 7 | .collapse-wrapper { 8 | overflow: hidden; 9 | transition: all .2s; 10 | } 11 | 12 | .collapse-horizontal-exit, 13 | .collapse-horizontal-exit-active, 14 | .collapse-horizontal-exit-done { 15 | inline-size: 0; 16 | } 17 | 18 | .collapse-horizontal-enter, 19 | .collapse-horizontal-enter-active, 20 | .collapse-horizontal-enter-done { 21 | inline-size: 100%; 22 | } 23 | -------------------------------------------------------------------------------- /src/components/Collapsible/Readme.md: -------------------------------------------------------------------------------- 1 | 2 | Collapsible component usage example 3 | ```jsx 4 | import React, {useState} from 'react'; 5 | import Button from '../Button'; 6 | 7 | const [toggle, setToggle] = useState(false); 8 | 9 | <> 10 | 11 | 14 | Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum. 15 | 16 | 17 | ``` -------------------------------------------------------------------------------- /src/components/Confirm/Readme.md: -------------------------------------------------------------------------------- 1 | ### Confirm before console 2 | ```js 3 | import Button from '../Button'; 4 | 8 | { 9 | (confirm) => ( 10 | 16 | ) 17 | } 18 | 19 | ``` -------------------------------------------------------------------------------- /src/components/CopyToClipboard/CopyToClipboard.css: -------------------------------------------------------------------------------- 1 | .tyk-copy-to-clipboard { 2 | position: absolute; 3 | inset-inline-start: -1000px; 4 | inset-block-start: -1000px; 5 | } -------------------------------------------------------------------------------- /src/components/CopyToClipboard/CopyToClipboard.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import CopyToClipboard from './index'; 3 | import Button from '../Button'; 4 | 5 | describe('CoopyToClipboard', () => { 6 | it('Test component rendering and Test copy functionality', () => { 7 | const textToCopy = 'boooo'; 8 | const displayText = 'BUTTON_TEST_NAME'; 9 | cy.mount( 10 |
11 | { 17 | document.querySelector('.dummy').innerText = textToCopy; 18 | }} 19 | /> 20 | PLACEHOLDER 21 |
, 22 | ); 23 | cy.get('span.dummy').invoke('text').should('eq', 'PLACEHOLDER'); 24 | cy.contains(textToCopy).should('not.exist'); 25 | cy.contains(displayText).should('exist').click(); 26 | cy.get('span.dummy').invoke('text').should('eq', textToCopy); 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /src/components/CopyToClipboard/Readme.md: -------------------------------------------------------------------------------- 1 | ### Copy using Button 2 | ```js 3 | import Button from '../Button'; 4 | {console.log('copied');}} 6 | copy="Copied by Button!" 7 | display="charlie" 8 | theme="primary" 9 | element={Button} 10 | /> 11 | ``` 12 | 13 | ### Copy by Span 14 | ```js 15 | 20 | ``` 21 | 22 | ### Copy with custom message 23 | ```js 24 | -------------------------------------------------------------------------------- /src/components/CopyToClipboard/index.js: -------------------------------------------------------------------------------- 1 | import React, { createRef, useCallback } from 'react'; 2 | import PropTypes from 'prop-types'; 3 | 4 | import toast from '../Toast'; 5 | 6 | /** 7 | * - CopyToClipboard is used to copy string for a user. 8 | * - Can be used normally with a text or a custom components (Eg. Button, Icon, etc) 9 | */ 10 | 11 | function CopyToClipboard(props) { 12 | const { 13 | display, copy, children, onCopy, message = 'copied', 14 | } = props; 15 | const txtRef = createRef(); 16 | const handleClick = useCallback(() => { 17 | if (onCopy) { 18 | onCopy(); 19 | } 20 | 21 | if (!window.navigator.clipboard) { 22 | txtRef.current.select(); 23 | document.execCommand('copy'); 24 | toast.success(message); 25 | return; 26 | } 27 | window.navigator.clipboard.writeText(copy); 28 | toast.success(message); 29 | }, [onCopy, txtRef]); 30 | 31 | return ( 32 | <> 33 | 34 | {children || display} 35 | 36 | {!window.navigator.clipboard ? ( 37 | 40 | ) : null} 41 | 42 | ); 43 | } 44 | 45 | CopyToClipboard.propTypes = { 46 | /** Message to be displayed after text is copied */ 47 | message: PropTypes.string, 48 | /** Callback function executed after text is copied */ 49 | onCopy: PropTypes.func, 50 | /** Text to be copied */ 51 | copy: PropTypes.string.isRequired, 52 | /** Text to be displayed */ 53 | display: PropTypes.string, 54 | /** Children of custom element if you are using any custom element */ 55 | children: PropTypes.oneOfType([ 56 | PropTypes.element, 57 | PropTypes.string, 58 | PropTypes.object, 59 | PropTypes.node, 60 | ]), 61 | }; 62 | 63 | export default CopyToClipboard; 64 | -------------------------------------------------------------------------------- /src/components/FixedWrapper/FixedWrapper.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --fixed-wrapper-top: 0; 3 | --fixed-wrapper-left: 0; 4 | --fixed-wrapper-right: 0; 5 | } 6 | 7 | .tyk-fixed-wrapper { 8 | inset-inline-start: var(--fixed-wrapper-left); 9 | inset-inline-end: var(--fixed-wrapper-right); 10 | position: sticky; 11 | inset-block-start: var(--fixed-wrapper-top); 12 | z-index: 8; 13 | } 14 | 15 | .tyk-fixed-wrapper--scrolled { 16 | box-shadow: 2px 2px 5px rgba(0 0 0 / 10%); 17 | } 18 | -------------------------------------------------------------------------------- /src/components/FixedWrapper/FixedWrapper.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import FixedWrapper from './index'; 3 | 4 | describe('FixedWrapper', () => { 5 | const selectors = { 6 | wrapper: '.tyk-fixed-wrapper', 7 | scrolled: '.tyk-fixed-wrapper--scrolled', 8 | }; 9 | 10 | it('renders the component with proper classes based on props', () => { 11 | cy 12 | .mount( 13 | 14 |

The Content

15 |
, 16 | ) 17 | .get(selectors.wrapper) 18 | .should('have.class', 'foo') 19 | .and('have.class', 'bar') 20 | .and('be.visible'); 21 | }); 22 | 23 | it('adds another class when the page is scrolled if the "showShadow" prop is true and removes it when scroll back to 0', () => { 24 | cy 25 | .mount( 26 |
27 | 28 |

The Content

29 |
30 |
, 31 | ) 32 | .get(selectors.scrolled) 33 | .should('not.exist'); 34 | 35 | cy.scrollTo(0, 500); 36 | cy.get(selectors.scrolled) 37 | .should('exist'); 38 | 39 | cy.scrollTo(0, 0); 40 | cy.get(selectors.scrolled) 41 | .should('not.exist'); 42 | }); 43 | }); 44 | -------------------------------------------------------------------------------- /src/components/FixedWrapper/index.js: -------------------------------------------------------------------------------- 1 | import React, { useCallback, useEffect, useRef } from 'react'; 2 | import PropTypes from 'prop-types'; 3 | 4 | import debounce from '../../utils/debounce'; 5 | 6 | /** 7 | * FixedWrapper component, keeps all its children in a fix position on the page, 8 | * even if the scroll position changes 9 | * i.e: The top navigation bar of a page sits within FixedWrapper component 10 | */ 11 | function FixedWrapper({ children, className = '', showShadow }) { 12 | const fixedWrapperRef = useRef(null); 13 | 14 | const attachShadow = useCallback(() => { 15 | const element = fixedWrapperRef.current; 16 | 17 | if (!element) { 18 | return; 19 | } 20 | 21 | if (window.scrollY) { 22 | element.classList.add('tyk-fixed-wrapper--scrolled'); 23 | } else { 24 | element.classList.remove('tyk-fixed-wrapper--scrolled'); 25 | } 26 | }, [fixedWrapperRef.current]); 27 | 28 | const debouncedAttachShadow = useCallback(debounce(attachShadow, 100), [attachShadow]); 29 | 30 | useEffect(() => { 31 | if (showShadow) { 32 | window.addEventListener('scroll', debouncedAttachShadow); 33 | } 34 | 35 | return () => { 36 | window.removeEventListener('scroll', debouncedAttachShadow); 37 | }; 38 | }, [debouncedAttachShadow, showShadow]); 39 | 40 | return ( 41 |
42 | { children } 43 |
44 | ); 45 | } 46 | 47 | FixedWrapper.propTypes = { 48 | children: PropTypes.oneOfType([ 49 | PropTypes.element, 50 | PropTypes.node, 51 | PropTypes.string, 52 | ]), 53 | /** Css classes that can be passed to the FixedWraper element */ 54 | className: PropTypes.string, 55 | /** If true, bottom shadow on the FixedWrapper component 56 | * is being displayed when scroll happens 57 | */ 58 | showShadow: PropTypes.bool, 59 | }; 60 | 61 | export default FixedWrapper; 62 | -------------------------------------------------------------------------------- /src/components/FloatingContainer/FloatingContainer.css: -------------------------------------------------------------------------------- 1 | .floating-container { 2 | position: fixed; 3 | inset-block-start: -9999px; 4 | overflow: auto; 5 | z-index: var(--modal-z-index, 1080); 6 | } 7 | 8 | .floating-container__content-wrapper { 9 | block-size: 100%; 10 | } -------------------------------------------------------------------------------- /src/components/Icon/Icon.css: -------------------------------------------------------------------------------- 1 | .tyk-icon { 2 | + .tyk-icon { 3 | margin-inline-start: var(--spacing-sm); 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /src/components/Icon/Icon.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Icon from './index'; 3 | 4 | describe('Icon', () => { 5 | const faFamily = 'fa-regular'; 6 | const faFamilySolid = 'fa-solid'; 7 | const tykonFamily = 'tykon'; 8 | const selectors = { 9 | icon: '.tyk-icon', 10 | }; 11 | 12 | it('renders an icon and the default family is "fa-regular"', () => { 13 | cy.mount() 14 | .get(selectors.icon) 15 | .should('exist') 16 | .and('have.class', faFamily); 17 | }); 18 | 19 | it('renders an icon and weight for fontawesome icons can be set', () => { 20 | cy.mount() 21 | .get(selectors.icon) 22 | .should('exist') 23 | .and('have.class', faFamilySolid); 24 | }); 25 | 26 | it('a different icon family can be specified', () => { 27 | cy.mount() 28 | .get(selectors.icon) 29 | .should('have.class', tykonFamily); 30 | }); 31 | 32 | it('the icon is determined by the family and the type by constructing a class', () => { 33 | const family = 'foo'; 34 | const type = 'bar'; 35 | cy.mount() 36 | .get(selectors.icon) 37 | .should('have.class', `${family}-${type}`); 38 | }); 39 | 40 | it('we can add custom classes', () => { 41 | const myClass = 'foo'; 42 | cy.mount() 43 | .get(selectors.icon) 44 | .should('have.class', myClass); 45 | }); 46 | 47 | it('other props will be added as attributes on the icon', () => { 48 | cy.mount() 49 | .get(selectors.icon) 50 | .should('have.attr', 'data-foo', 'bar'); 51 | }); 52 | }); 53 | -------------------------------------------------------------------------------- /src/components/Icon/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | 4 | function Icon({ 5 | className, 6 | family, 7 | type, 8 | weight, 9 | ...rest 10 | }) { 11 | function getCSSClasses() { 12 | const fontFamily = family || 'fa'; 13 | const fontWeight = fontFamily === 'fa' ? `fa-${weight || 'regular'}` : ''; 14 | 15 | return [ 16 | 'tyk-icon', 17 | fontFamily !== 'fa' && fontFamily, 18 | `${fontFamily}-${type}`, 19 | fontWeight, 20 | className, 21 | ].filter(Boolean).join(' '); 22 | } 23 | 24 | return ; 25 | } 26 | 27 | Icon.propTypes = { 28 | // Additional CSS classes to apply 29 | className: PropTypes.string, 30 | // Font family to use. Default is 'fa'. 31 | family: PropTypes.string, 32 | // Icon type to use 33 | type: PropTypes.string.isRequired, 34 | // Icon weight to use. Only applicable for Font Awesome icons. Default is 'regular'. Also supports 'light' and 'solid' 35 | weight: PropTypes.string 36 | }; 37 | 38 | export default Icon; 39 | -------------------------------------------------------------------------------- /src/components/InfiniteScroller/InfiniteScroller.css: -------------------------------------------------------------------------------- 1 | .tyk-infinite-scroller { 2 | block-size: 100%; 3 | overflow: hidden; 4 | position: relative; 5 | 6 | .loading.absolute { 7 | inset-block-end: 5px; 8 | inset-block-start: auto; 9 | } 10 | } 11 | 12 | .tyk-infinite-scroller__wrapper { 13 | block-size: 100%; 14 | overflow-y: auto; 15 | } 16 | -------------------------------------------------------------------------------- /src/components/InfiniteScroller/InfiniteScroller.test.js: -------------------------------------------------------------------------------- 1 | import React, { useRef } from 'react'; 2 | import InfiniteScroller from './index'; 3 | 4 | // eslint-disable-next-line react/prop-types 5 | function Component({ content, ...rest }) { 6 | const refChild = useRef(); 7 | 8 | return ( 9 |
10 | 11 |
12 | { content ??

The Content

} 13 |
14 |
15 |
16 | ); 17 | } 18 | 19 | describe('InfiniteScroller', () => { 20 | const selectors = { 21 | scroller: '.tyk-infinite-scroller', 22 | wrapper: '.tyk-infinite-scroller__wrapper', 23 | loader: '.loading', 24 | }; 25 | 26 | it('renders content inside the component', () => { 27 | cy.mount() 28 | .get(selectors.scroller) 29 | .find('h1') 30 | .should('have.text', 'The Content'); 31 | }); 32 | 33 | it('if it is the initial load calls the loadMore callback', () => { 34 | const loadMore = cy.stub(); 35 | cy.mount() 36 | .then(() => { 37 | expect(loadMore).to.be.called; 38 | }); 39 | }); 40 | 41 | it('scrolling to the bottom loads the next page', () => { 42 | const loadMore = cy.stub().as('loadMore'); 43 | const content = ( 44 | <> 45 | {[...Array(50)].map((_, index) => ( 46 |
{`Item ${index}`}
47 | ))} 48 | 49 | ); 50 | 51 | cy.mount() 52 | .get(selectors.wrapper) 53 | .scrollTo(0, 10); 54 | 55 | cy.wait(500) 56 | .get('@loadMore') 57 | .should('not.be.called'); 58 | 59 | cy.get(selectors.wrapper) 60 | .scrollTo('bottom'); 61 | 62 | cy.wait(500) 63 | .get('@loadMore') 64 | .should('be.called'); 65 | }); 66 | }); 67 | -------------------------------------------------------------------------------- /src/components/InfoNote/InfoNote.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import InfoNote from './index'; 3 | 4 | describe('InfoNote', () => { 5 | const selectors = { 6 | message: '.tyk-message', 7 | }; 8 | 9 | it('renders a Message component with the info theme', () => { 10 | const content = 'The Content'; 11 | cy 12 | .mount( 13 | 14 | {content} 15 | , 16 | ) 17 | .get(selectors.message) 18 | .should('have.class', 'tyk-message--info') 19 | .and('have.text', content); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /src/components/InfoNote/Readme.md: -------------------------------------------------------------------------------- 1 | *Themes* 2 | ```js 3 | Default InfoNote 4 | ``` 5 | -------------------------------------------------------------------------------- /src/components/InfoNote/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | 4 | import Message from '../Message'; 5 | 6 | function InfoNote({ children }) { 7 | return ( 8 | 9 | { children } 10 | 11 | ); 12 | } 13 | 14 | InfoNote.propTypes = { 15 | children: PropTypes.oneOfType([ 16 | PropTypes.element, 17 | PropTypes.node, 18 | PropTypes.string, 19 | ]), 20 | }; 21 | 22 | export default InfoNote; 23 | -------------------------------------------------------------------------------- /src/components/List/List.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import List from './index'; 3 | 4 | describe('List', () => { 5 | it('test list is rendered with items in primary theme', () => { 6 | cy.mount( 7 | 11 | Alpha 12 | Bravo 13 | Charlie 14 | Delta 15 | , 16 | ); 17 | 18 | cy.get('.tyk-list__wrapper') 19 | .get('ul') 20 | .should('have.class', 'tyk-list'); 21 | 22 | cy.contains('LABEL').should('exist'); 23 | cy.contains('Alpha').should('exist'); 24 | cy.contains('Bravo').should('exist'); 25 | cy.contains('Charlie').should('exist'); 26 | cy.contains('Delta').should('exist'); 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /src/components/List/Readme.md: -------------------------------------------------------------------------------- 1 | ```js 2 | 3 | item 1 4 | item 2 5 | item 3 6 | item 4 7 | 8 | ``` 9 | *Inline list* 10 | ```js 11 |
    12 |
  • 13 | Item 1 14 |
  • 15 |
  • 16 | Item 2 17 |
  • 18 |
  • 19 | Item 3 20 |
  • 21 |
  • 22 | Item 4 23 |
  • 24 |
25 | ``` 26 | *Inline list with separator* 27 | ```js 28 |
    29 |
  • 30 | Item 1 31 |
  • 32 |
  • 33 | Item 2 34 |
  • 35 |
  • 36 | Item 3 37 |
  • 38 |
  • 39 | Item 4 40 |
  • 41 |
42 |
    43 |
  • 44 | Item 1 45 |
  • 46 |
  • 47 | Item 2 48 |
  • 49 |
  • 50 | Item 3 51 |
  • 52 |
  • 53 | Item 4 54 |
  • 55 |
56 | ``` 57 | -------------------------------------------------------------------------------- /src/components/List/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import ListItem from './js/ListItem'; 4 | 5 | function List(props) { 6 | const { 7 | className, 8 | children, 9 | label, 10 | labelwidth, 11 | theme = 'secondary', 12 | style = {}, 13 | } = props; 14 | 15 | const getCssClasses = () => { 16 | let cssClasses = ['tyk-list']; 17 | 18 | if (theme) { 19 | cssClasses.push(`tyk-list--${theme}`); 20 | } 21 | 22 | if (className) { 23 | cssClasses = cssClasses.concat(className.split(' ')); 24 | } 25 | 26 | return cssClasses.join(' '); 27 | }; 28 | 29 | const getListStyle = () => { 30 | const styleCopy = structuredClone(style); 31 | if (labelwidth) { 32 | styleCopy.flexBasis = `calc(100% - ${labelwidth} - 20px)`; 33 | } 34 | 35 | return styleCopy; 36 | }; 37 | 38 | return ( 39 |
40 | { 41 | label !== undefined 42 | ? ( 43 | 49 | ) 50 | : null 51 | } 52 |
    53 | {children} 54 |
55 |
56 | ); 57 | } 58 | 59 | List.propTypes = { 60 | children: PropTypes.oneOfType([ 61 | PropTypes.arrayOf(PropTypes.node), 62 | PropTypes.node, 63 | PropTypes.element, 64 | PropTypes.string, 65 | ]), 66 | className: PropTypes.string, 67 | label: PropTypes.string, 68 | labelwidth: PropTypes.string, 69 | theme: PropTypes.string, 70 | style: PropTypes.instanceOf(Object), 71 | }; 72 | 73 | List.Item = ListItem; 74 | 75 | export default List; 76 | -------------------------------------------------------------------------------- /src/components/List/js/ListItem.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | 4 | function ListItem(props) { 5 | const { 6 | className = '', 7 | children, 8 | selected, 9 | } = props; 10 | 11 | return ( 12 |
  • 13 | {children} 14 |
  • 15 | ); 16 | } 17 | 18 | ListItem.propTypes = { 19 | children: PropTypes.oneOfType([ 20 | PropTypes.arrayOf(PropTypes.node), 21 | PropTypes.node, 22 | PropTypes.element, 23 | PropTypes.string, 24 | ]), 25 | className: PropTypes.string, 26 | selected: PropTypes.bool, 27 | }; 28 | 29 | export default ListItem; 30 | -------------------------------------------------------------------------------- /src/components/Loader/Readme.md: -------------------------------------------------------------------------------- 1 | **Circular loader** 2 | ```js 3 | 4 | ``` 5 | **Circular loader size small** 6 | ```js 7 | 8 | ``` 9 | **Circular loader custom size** 10 | ```js 11 | 12 | ``` 13 | A custom size can also be added from css. Just add a css class to the component (e.g. ``) and overwrite the `--loader-size` variable for that class. 14 | ```css 15 | .loader-type-circular.my-loader { 16 | --loader-size: 100px; 17 | } 18 | ``` 19 | **Loader with background** 20 | ```js 21 |
    22 |

    Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

    23 | 24 |
    25 | ``` 26 | 27 | **Linear loader** 28 | ```js 29 | 30 | ``` 31 | **Linear loader in the loaded state** 32 | ```js 33 | 34 | ``` 35 | -------------------------------------------------------------------------------- /src/components/Loader/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | 4 | function Loader({ 5 | className, type = 'circular', size = 'big', position = 'relative', withbackground = false, isLoaded = false, 6 | }) { 7 | const isKeywordSize = ['big', 'small'].includes(size); 8 | const classes = [ 9 | 'loading', 10 | `loader-type-${type}`, 11 | isKeywordSize && `loader-size-${size}`, 12 | position, 13 | className, 14 | isLoaded && 'is-loaded', 15 | ].filter(Boolean).join(' '); 16 | 17 | const loader =
    ; 18 | 19 | return withbackground 20 | ?
    {loader}
    21 | : loader; 22 | } 23 | 24 | Loader.propTypes = { 25 | /** Add a class to loader */ 26 | className: PropTypes.string, 27 | /** The type of the loader (linear || circular || brand) */ 28 | type: PropTypes.string, 29 | /** The size of the loader (small || big). Only applicable to the circular loader. */ 30 | size: PropTypes.string, 31 | /** Position of the loader (absolute || relative) */ 32 | position: PropTypes.string, 33 | /** Defines whether loader should be rendered with or without background */ 34 | withbackground: PropTypes.bool, 35 | /** Only applicable to the linear loader. Stops the animation and fills the entire bar. */ 36 | isLoaded: PropTypes.bool, 37 | }; 38 | 39 | export default Loader; 40 | -------------------------------------------------------------------------------- /src/components/Message/Message.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Message from './index'; 3 | 4 | function Component(props) { 5 | return ( 6 | 7 | lorem ipsum 8 | 9 | ); 10 | } 11 | 12 | describe('Message', () => { 13 | const infoThemeClass = 'tyk-message--info'; 14 | const successThemeClass = 'tyk-message--success'; 15 | const noMarginClass = 'no-margin'; 16 | const selectors = { 17 | message: '.tyk-message', 18 | closeIcon: '.tyk-icon.fa-xmark', 19 | title: '.tyk-message__title', 20 | }; 21 | 22 | it('renders the component with the info theme by default', () => { 23 | cy.mount() 24 | .get(selectors.message) 25 | .should('exist') 26 | .and('have.class', infoThemeClass); 27 | }); 28 | 29 | it('can be rendered with a different theme', () => { 30 | cy.mount() 31 | .get(selectors.message) 32 | .should('have.class', successThemeClass); 33 | }); 34 | 35 | it('can be rendered with a title', () => { 36 | const title = 'Banner title'; 37 | cy.mount() 38 | .get(selectors.title) 39 | .should('exist'); 40 | }); 41 | 42 | it('can be rendered with no margins', () => { 43 | cy.mount() 44 | .get(selectors.message) 45 | .should('have.class', noMarginClass); 46 | }); 47 | 48 | it('can have custom classes', () => { 49 | const myClass = 'foo'; 50 | cy.mount() 51 | .get(selectors.message) 52 | .should('have.class', myClass); 53 | }); 54 | 55 | it('renders an icon that calls the onClose callback when clicked', () => { 56 | const onClose = cy.stub().as('onClose'); 57 | cy.mount() 58 | .get(selectors.closeIcon) 59 | .click(); 60 | 61 | cy.get('@onClose') 62 | .should('be.called'); 63 | }); 64 | }); 65 | -------------------------------------------------------------------------------- /src/components/Modal/js/ModalBody.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | 4 | function ModalBody({ children }) { 5 | return ( 6 |
    7 | { children } 8 |
    9 | ); 10 | } 11 | 12 | ModalBody.propTypes = { 13 | children: PropTypes.oneOfType([ 14 | PropTypes.element, 15 | PropTypes.node, 16 | PropTypes.string, 17 | ]), 18 | }; 19 | 20 | export default ModalBody; 21 | -------------------------------------------------------------------------------- /src/components/Modal/js/ModalFooter.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | 4 | function ModalFooter({ children }) { 5 | return ( 6 |
    7 | { children } 8 |
    9 | ); 10 | } 11 | 12 | ModalFooter.propTypes = { 13 | children: PropTypes.oneOfType([ 14 | PropTypes.element, 15 | PropTypes.node, 16 | PropTypes.string, 17 | ]), 18 | }; 19 | 20 | export default ModalFooter; 21 | -------------------------------------------------------------------------------- /src/components/Modal/js/ModalHeader.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | 4 | function ModalHeader({ children }) { 5 | return ( 6 |
    7 | { children } 8 |
    9 | ); 10 | } 11 | 12 | ModalHeader.propTypes = { 13 | children: PropTypes.oneOfType([ 14 | PropTypes.arrayOf(PropTypes.node), 15 | PropTypes.element, 16 | PropTypes.node, 17 | PropTypes.string, 18 | ]), 19 | }; 20 | 21 | export default ModalHeader; 22 | -------------------------------------------------------------------------------- /src/components/Modal/js/ModalTitle.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | 4 | function ModalTitle({ children }) { 5 | return ( 6 |
    7 | { children } 8 |
    9 | ); 10 | } 11 | 12 | ModalTitle.propTypes = { 13 | children: PropTypes.element, 14 | }; 15 | 16 | export default ModalTitle; 17 | -------------------------------------------------------------------------------- /src/components/NavBar/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | 4 | function NavBar({ 5 | align = 'center', 6 | children, 7 | left, 8 | right, 9 | title, 10 | pre, 11 | subtitle, 12 | withTabs, 13 | }) { 14 | const subtitleContent = subtitle ?

    { subtitle }

    : null; 15 | return ( 16 |
    17 |
    18 | {pre && ( 19 |
    {pre}
    20 | )} 21 | { 22 | title 23 | ? ( 24 |
    25 |

    { title }

    26 | { subtitleContent } 27 |
    28 | ) 29 | : subtitleContent 30 | } 31 |
    32 | {left && ( 33 |
    { left }
    34 | )} 35 | {right && ( 36 |
    { right }
    37 | )} 38 |
    39 |
    40 | { children } 41 |
    42 | ); 43 | } 44 | 45 | NavBar.propTypes = { 46 | align: PropTypes.string, 47 | children: PropTypes.oneOfType([ 48 | PropTypes.arrayOf(PropTypes.node), 49 | PropTypes.node, 50 | PropTypes.element, 51 | PropTypes.string, 52 | ]), 53 | title: PropTypes.string, 54 | subtitle: PropTypes.string, 55 | pre: PropTypes.oneOfType([ 56 | PropTypes.element, 57 | PropTypes.node, 58 | ]), 59 | left: PropTypes.oneOfType([ 60 | PropTypes.element, 61 | PropTypes.node, 62 | ]), 63 | right: PropTypes.oneOfType([ 64 | PropTypes.element, 65 | PropTypes.node, 66 | ]), 67 | withTabs: PropTypes.bool, 68 | }; 69 | 70 | export default NavBar; 71 | -------------------------------------------------------------------------------- /src/components/Navigation/Navigation.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --navigation-background-color: white; 3 | --navigation-item-padding-y: var(--spacing-sm); 4 | --navigation-item-padding-x: var(--spacing-md); 5 | --navigation-item-background-color: white; 6 | --navigation-item-color: var(--text-color); 7 | --navigation-item-hover-background-color: var(--color-primary-base); 8 | --navigation-item-hover-color: white; 9 | --navigation-item-active-background-color: var(--color-primary-dark); 10 | --navigation-item-active-color: white; 11 | --navigation-padding: 0; 12 | } 13 | 14 | .tyk-navigation { 15 | background-color: var(--navigation-background-color); 16 | block-size: 100%; 17 | overflow: auto; 18 | padding: var(--navigation-padding); 19 | inline-size: 100%; 20 | 21 | .tyk-navigation-item { 22 | inline-size: 100%; 23 | 24 | a { 25 | color: var(--navigation-item-color); 26 | display: flex; 27 | padding-block: var(--navigation-item-padding-y); 28 | padding-inline: var(--navigation-item-padding-x); 29 | text-decoration: none; 30 | transition: all .2s ease; 31 | 32 | &:hover { 33 | background-color: var(--navigation-item-hover-background-color); 34 | color: var(--navigation-item-hover-color); 35 | } 36 | 37 | &.active { 38 | background-color: var(--navigation-item-active-background-color); 39 | color: var(--navigation-item-active-color); 40 | } 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/components/Navigation/Navigation.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Navigation from './index'; 3 | 4 | describe('Navigation', () => { 5 | const selectors = { 6 | navigation: '.tyk-navigation', 7 | item: '.tyk-navigation-item', 8 | }; 9 | 10 | it('renders the component', () => { 11 | cy.mount() 12 | .get(selectors.navigation) 13 | .should('exist'); 14 | }); 15 | 16 | it('can have navigation items as children', () => { 17 | cy.mount( 18 | 19 | item 1 20 | item 2 21 | , 22 | ) 23 | .get(selectors.item) 24 | .should('have.length', 2); 25 | }); 26 | }); 27 | -------------------------------------------------------------------------------- /src/components/Navigation/Readme.md: -------------------------------------------------------------------------------- 1 | ```js 2 | 3 | 4 | Link 1 5 | 6 | 7 | Link 2 8 | 9 | 10 | Link 3 11 | 12 | 13 | ``` 14 | -------------------------------------------------------------------------------- /src/components/Navigation/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import NavigationItem from './js/NavigationItem'; 4 | 5 | function Navigation({ children }) { 6 | return ( 7 |
      8 | {children} 9 |
    10 | ); 11 | } 12 | 13 | Navigation.propTypes = { 14 | children: PropTypes.oneOfType([ 15 | PropTypes.arrayOf(PropTypes.node), 16 | PropTypes.node, 17 | PropTypes.element, 18 | PropTypes.string, 19 | ]), 20 | }; 21 | 22 | Navigation.Item = NavigationItem; 23 | 24 | export default Navigation; 25 | -------------------------------------------------------------------------------- /src/components/Navigation/js/NavigationItem.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | 4 | function NavigationItem({ children }) { 5 | return ( 6 |
  • 7 | {children} 8 |
  • 9 | ); 10 | } 11 | 12 | NavigationItem.propTypes = { 13 | children: PropTypes.oneOfType([ 14 | PropTypes.arrayOf(PropTypes.node), 15 | PropTypes.node, 16 | PropTypes.element, 17 | PropTypes.string, 18 | ]), 19 | }; 20 | 21 | export default NavigationItem; 22 | -------------------------------------------------------------------------------- /src/components/Panel/js/PanelBody.js: -------------------------------------------------------------------------------- 1 | import React, { useCallback } from 'react'; 2 | import PropTypes from 'prop-types'; 3 | 4 | import Collapsible from '../../Collapsible'; 5 | import { PortalContext } from '../panel-context'; 6 | 7 | function PanelBody({ 8 | children, 9 | noPadding, 10 | className, 11 | ...rest 12 | }) { 13 | const getCssClasses = useCallback( 14 | () => [ 15 | 'tyk-panel__body', 16 | className, 17 | noPadding && 'no-padding', 18 | ].filter(Boolean).join(' '), 19 | [className, noPadding], 20 | ); 21 | 22 | return ( 23 | 24 | { 25 | (portalContext) => ( 26 | portalContext.collapsable 27 | ? ( 28 | 33 | { children } 34 | 35 | ) 36 | : ( 37 |
    41 | { children } 42 |
    43 | ) 44 | ) 45 | } 46 |
    47 | ); 48 | } 49 | 50 | PanelBody.propTypes = { 51 | children: PropTypes.oneOfType([ 52 | PropTypes.element, 53 | PropTypes.node, 54 | PropTypes.string, 55 | ]), 56 | noPadding: PropTypes.bool, 57 | className: PropTypes.string, 58 | }; 59 | 60 | export default PanelBody; 61 | -------------------------------------------------------------------------------- /src/components/Panel/js/PanelFooter.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | 4 | function PanelFooter(props) { 5 | const { children } = props; 6 | return ( 7 |
    8 | { children } 9 |
    10 | ); 11 | } 12 | 13 | PanelFooter.propTypes = { 14 | children: PropTypes.oneOfType([ 15 | PropTypes.element, 16 | PropTypes.node, 17 | PropTypes.string, 18 | ]), 19 | }; 20 | 21 | export default PanelFooter; 22 | -------------------------------------------------------------------------------- /src/components/Panel/js/PanelHeader.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import PropTypes from 'prop-types'; 3 | 4 | import Icon from '../../Icon'; 5 | import { PortalContext } from '../panel-context'; 6 | 7 | class PanelHeader extends Component { 8 | getCssClasses(props) { 9 | const { className } = this.props; 10 | let cssClasses = ['tyk-panel__header']; 11 | 12 | if (props.collapsable) { 13 | cssClasses.push('collapsable'); 14 | } 15 | 16 | if (className) { 17 | cssClasses = cssClasses.concat(className.split(' ')); 18 | } 19 | 20 | return cssClasses.join(' '); 21 | } 22 | 23 | render() { 24 | const { 25 | children, 26 | } = this.props; 27 | 28 | return ( 29 | 30 | { 31 | (portalContext) => { 32 | const HeaderTag = portalContext.theme === 'blank' ? 'h3' : 'div'; 33 | const iconType = portalContext.collapsed ? 'chevron-down' : 'chevron-up'; 34 | 35 | return ( 36 | 40 | { children } 41 | { 42 | portalContext.collapsable 43 | ?
    44 | : null 45 | } 46 |
    47 | ); 48 | } 49 | } 50 |
    51 | ); 52 | } 53 | } 54 | 55 | PanelHeader.propTypes = { 56 | children: PropTypes.oneOfType([ 57 | PropTypes.element, 58 | PropTypes.node, 59 | PropTypes.string, 60 | ]).isRequired, 61 | className: PropTypes.string, 62 | }; 63 | 64 | export default PanelHeader; 65 | -------------------------------------------------------------------------------- /src/components/Panel/panel-context.js: -------------------------------------------------------------------------------- 1 | import { createContext } from 'react'; 2 | 3 | export const PortalContext = createContext(); 4 | -------------------------------------------------------------------------------- /src/components/Pill/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | 4 | /** 5 | * Pill 6 | */ 7 | function Pill(props) { 8 | const { 9 | children, 10 | className, 11 | theme = 'default', 12 | } = props; 13 | 14 | const getCssClasses = () => { 15 | let cssClasses = ['tyk-pill', ...theme.split(' ').map((t) => `tyk-pill--${t}`)]; 16 | 17 | if (className) { 18 | cssClasses = cssClasses.concat(className); 19 | } 20 | 21 | return cssClasses.join(' '); 22 | }; 23 | 24 | return ( 25 |
    26 | {children} 27 |
    28 | ); 29 | } 30 | 31 | Pill.propTypes = { 32 | children: PropTypes.oneOfType([ 33 | PropTypes.arrayOf(PropTypes.node), 34 | PropTypes.node, 35 | PropTypes.element, 36 | PropTypes.string, 37 | ]), 38 | /** Css classes that can be passed to the Pill element */ 39 | className: PropTypes.string, 40 | /** Theme that can be applied to a Pill */ 41 | theme: PropTypes.string, 42 | }; 43 | 44 | export default Pill; 45 | -------------------------------------------------------------------------------- /src/components/RevealPanel/Readme.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ```js 4 | import { useCallback, useRef, useState } from "react"; 5 | import RevealPanel from "./index"; 6 |
    7 | e and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including vers 8 | e and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including vers 9 | 10 | e and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including verse and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including vers 11 | eeee 12 |
    13 | 14 | ``` -------------------------------------------------------------------------------- /src/components/RevealPanel/RevealPanel.css: -------------------------------------------------------------------------------- 1 | .tyk-ui-reveal-wrapper { 2 | display: flex; 3 | flex-direction: column; 4 | justify-content: flex-end; 5 | align-items: stretch; 6 | inline-size: 100%; 7 | block-size: 100%; 8 | z-index: 1000; 9 | position: absolute; 10 | inset-block-end: 0; 11 | inset-inline-start: 0; 12 | pointer-events: none; 13 | } 14 | 15 | .tyk-ui-reveal-wrapper__panel { 16 | max-block-size: calc(100% - 2rem); 17 | background-color: white; 18 | padding: 0; 19 | margin: 0; 20 | display: flex; 21 | flex-direction: column; 22 | pointer-events: all; 23 | flex-shrink: 0; 24 | overflow: auto; 25 | } 26 | 27 | .tyk-ui-reveal-wrapper__hole { 28 | flex-grow: 1; 29 | opacity: 0; 30 | inline-size: 100%; 31 | background-color: green; 32 | -webkit-user-select: none; 33 | user-select: none; 34 | pointer-events: none; 35 | z-index: -1; 36 | } 37 | 38 | .tyk-ui-reveal-wrapper__gutter { 39 | block-size: 2rem; 40 | inline-size: 100%; 41 | cursor: row-resize; 42 | display: flex; 43 | background-color: var(--color-primary-base); 44 | z-index: 2; 45 | pointer-events: all; 46 | justify-content: space-between; 47 | align-items: stretch; 48 | position: relative; 49 | box-shadow: 0 5px 10px rgba(0 0 0 / 30%); 50 | } 51 | 52 | .tyk-ui-reveal-wrapper__gutter__headerleft, 53 | .tyk-ui-reveal-wrapper__gutter__headerright { 54 | display: flex; 55 | align-items: center; 56 | flex: 1; 57 | } 58 | 59 | .tyk-ui-reveal-wrapper__gutter__headerleft { 60 | justify-content: flex-start; 61 | } 62 | 63 | .tyk-ui-reveal-wrapper__gutter__headerright { 64 | justify-content: flex-end; 65 | } 66 | 67 | .tyk-ui-reveal-wrapper__gutter__logo { 68 | inline-size: 1rem; 69 | block-size: 1rem; 70 | -webkit-user-select: none; 71 | user-select: none; 72 | pointer-events: none; 73 | padding: 0.2rem; 74 | z-index: 2; 75 | background-image: url('./images/drag.svg'); 76 | align-self: center; 77 | 78 | &:hover { 79 | border: dashed; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/components/RevealPanel/RevealPanel.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import RevealPanel from './index'; 3 | 4 | function Component() { 5 | return ( 6 |
    7 | e and scrambled it to make a type specimen book. 8 | It has survived not only five centuries, but also 9 | 10 | Panel content to make a type specimen book. 11 | 12 |
    13 | ); 14 | } 15 | 16 | describe('RevealPanel.test.js', () => { 17 | it('renders RevealPanel component', () => { 18 | cy.mount(); 19 | }); 20 | }); 21 | -------------------------------------------------------------------------------- /src/components/RevealPanel/images/drag.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/components/Sidebar/Sidebar.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --sidebar-background-color: white; 3 | --sidebar-top: 58px; 4 | --sidebar-height: calc(100vh - 58px); 5 | --sidebar-width: 280px; 6 | --sidebar-padding: 0; 7 | } 8 | 9 | .tyk-sidebar { 10 | background-color: var(--sidebar-background-color); 11 | block-size: var(--sidebar-height); 12 | flex: 0 0 var(--sidebar-width); 13 | padding: var(--sidebar-padding); 14 | position: sticky; 15 | overflow: auto; 16 | inset-block-start: var(--sidebar-top); 17 | } 18 | -------------------------------------------------------------------------------- /src/components/Stepper/StepperContext.js: -------------------------------------------------------------------------------- 1 | import { createContext, useContext } from 'react'; 2 | 3 | const StepperContext = createContext(); 4 | 5 | export const StepperProvider = StepperContext.Provider; 6 | 7 | export const useStepper = () => { 8 | const context = useContext(StepperContext); 9 | if (!context) { 10 | throw new Error('useStepper must be used within a Stepper component'); 11 | } 12 | return context; 13 | }; -------------------------------------------------------------------------------- /src/components/Stepper/js/Buttons.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import PropTypes from "prop-types"; 3 | import { useStepper } from "../StepperContext"; 4 | 5 | const Buttons = ({ children }) => { 6 | const { 7 | activeStep, 8 | steps, 9 | setActiveStep, 10 | setErrors, 11 | onFinish, 12 | onChange, 13 | onSkip, 14 | stepValidator, 15 | stepErrMessage, 16 | setValidationAttempted, 17 | } = useStepper(); 18 | 19 | const isLastStep = activeStep === steps.length - 1; 20 | 21 | const goToNextStep = async () => { 22 | setValidationAttempted(true); 23 | const isNextStepAllowed = await stepValidator(steps[activeStep]?.props?.id); 24 | 25 | if (isNextStepAllowed) { 26 | if (activeStep < steps.length - 1) { 27 | setActiveStep((prev) => prev + 1); 28 | setErrors((prev) => ({ ...prev, [activeStep]: null })); 29 | onChange(steps[activeStep]?.props?.id); 30 | } else if (activeStep === steps.length - 1) { 31 | onFinish(); 32 | } 33 | setValidationAttempted(false); 34 | } else { 35 | setErrors((prev) => ({ 36 | ...prev, 37 | [activeStep]: stepErrMessage, 38 | })); 39 | } 40 | }; 41 | 42 | const goToPreviousStep = () => { 43 | if (activeStep > 0) { 44 | setActiveStep((prev) => prev - 1); 45 | setValidationAttempted(false); 46 | onChange(steps[activeStep]?.props?.id); 47 | } 48 | }; 49 | 50 | const onSkipStep = () => { 51 | onSkip(steps[activeStep]?.props?.id); 52 | }; 53 | 54 | return ( 55 |
    56 | {children({ 57 | goToNextStep, 58 | goToPreviousStep, 59 | onSkipStep, 60 | isLastStep, 61 | activeStep, 62 | stepId: steps[activeStep]?.props?.id || "", 63 | })} 64 |
    65 | ); 66 | }; 67 | 68 | Buttons.displayName = "StepperButtons"; 69 | Buttons.propTypes = { 70 | children: PropTypes.func.isRequired, 71 | }; 72 | 73 | export default Buttons; 74 | -------------------------------------------------------------------------------- /src/components/Stepper/js/Step.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import PropTypes from "prop-types"; 3 | 4 | const Step = ({ children }) => { 5 | return <>{children}; 6 | }; 7 | 8 | Step.displayName = "StepperStep"; 9 | 10 | Step.propTypes = { 11 | children: PropTypes.node.isRequired, 12 | title: PropTypes.string, 13 | description: PropTypes.string, 14 | id: PropTypes.string, 15 | }; 16 | 17 | export default Step; 18 | -------------------------------------------------------------------------------- /src/components/Stepper/js/StepList.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { useStepper } from "../StepperContext"; 3 | import StepItem from "./StepItem"; 4 | 5 | const StepList = () => { 6 | const { steps, activeStep, errors, orientation } = useStepper(); 7 | 8 | return ( 9 |
    10 | {steps.map((step, index) => ( 11 |
    18 | 27 |
    28 | ))} 29 |
    30 | ); 31 | }; 32 | 33 | export default StepList; -------------------------------------------------------------------------------- /src/components/Stepper/js/StepNumber.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | 4 | const StepNumber = ({ number, isCompleted, isActive, hasError }) => { 5 | const classNames = [ 6 | 'step-number', 7 | isCompleted ? 'completed' : '', 8 | isActive ? 'active' : '', 9 | hasError ? 'error' : '' 10 | ].filter(Boolean).join(' '); 11 | 12 | return ( 13 |
    14 | {hasError ? '!' : number} 15 |
    16 | ); 17 | }; 18 | 19 | StepNumber.propTypes = { 20 | number: PropTypes.number, 21 | isCompleted: PropTypes.bool, 22 | isActive: PropTypes.bool, 23 | hasError: PropTypes.bool 24 | }; 25 | 26 | export default StepNumber; -------------------------------------------------------------------------------- /src/components/Stepper/js/StepperButtons.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import PropTypes from "prop-types"; 3 | import Button from "../../Button"; 4 | import { useStepper } from "../StepperContext"; 5 | import Buttons from "./Buttons"; 6 | 7 | export const DefaultButtons = ({ 8 | nextBtnTxt, 9 | finishBtnTxt, 10 | backBtnTxt, 11 | skipBtnTxt, 12 | }) => { 13 | const { onSkip } = useStepper(); 14 | 15 | return ( 16 | 17 | {({ 18 | goToNextStep, 19 | goToPreviousStep, 20 | onSkipStep, 21 | isLastStep, 22 | activeStep, 23 | }) => ( 24 | <> 25 | {onSkip && ( 26 |
    27 | 30 |
    31 | )} 32 | {activeStep > 0 && ( 33 | 36 | )} 37 | 40 | 41 | )} 42 |
    43 | ); 44 | }; 45 | 46 | DefaultButtons.propTypes = { 47 | nextBtnTxt: PropTypes.string.isRequired, 48 | finishBtnTxt: PropTypes.string.isRequired, 49 | backBtnTxt: PropTypes.string.isRequired, 50 | skipBtnTxt: PropTypes.string.isRequired, 51 | }; 52 | -------------------------------------------------------------------------------- /src/components/Table/js/body.js: -------------------------------------------------------------------------------- 1 | import React, { useContext } from 'react'; 2 | import { tableContext } from '../tableContext'; 3 | import { Row } from './row'; 4 | 5 | export function Body() { 6 | const { state } = useContext(tableContext); 7 | const { rows } = state; 8 | 9 | return ( 10 | 11 | { 12 | rows.map((row, i) => ) 13 | } 14 | 15 | ); 16 | } 17 | -------------------------------------------------------------------------------- /src/components/Table/js/cell.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | 4 | export function Cell({ col, row }) { 5 | if (!row.values[col.id]) { 6 | return ; 7 | } 8 | 9 | if (col.type === 'string') { 10 | return ( 11 | 15 | {row.values[col.id]?.value} 16 | 17 | ); 18 | } 19 | const Component = col.type; 20 | return ( 21 | 25 | 28 | {row.values[col.id].children ? row.values[col.id].children : null} 29 | 30 | 31 | ); 32 | } 33 | 34 | Cell.propTypes = { 35 | col: PropTypes.instanceOf(Object), 36 | row: PropTypes.instanceOf(Object), 37 | index: PropTypes.number, 38 | }; 39 | -------------------------------------------------------------------------------- /src/components/Table/js/header-cell.js: -------------------------------------------------------------------------------- 1 | import React, { useState, useContext } from 'react'; 2 | import PropTypes from 'prop-types'; 3 | 4 | import { tableContext } from '../tableContext'; 5 | import Icon from '../../Icon'; 6 | 7 | export function HeaderCell({ column }) { 8 | const { sortable } = column; 9 | const [sortOrder, setSortOrder] = useState(sortable?.default || 'ASC'); 10 | const { state, sendMessage } = useContext(tableContext); 11 | return ( 12 | { 15 | sendMessage('sort', { column, sortOrder }); 16 | setSortOrder(sortOrder === 'ASC' ? 'DESC' : 'ASC'); 17 | } : null} 18 | className={state.maxHeight ? 'fixed-header' : ''} 19 | > 20 | {column.name} 21 | {column.sortable && ( 22 | 23 | 24 | 25 | )} 26 | 27 | ); 28 | } 29 | 30 | HeaderCell.propTypes = { 31 | column: PropTypes.instanceOf(Object), 32 | }; 33 | -------------------------------------------------------------------------------- /src/components/Table/js/header.js: -------------------------------------------------------------------------------- 1 | import React, { useContext } from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import { HeaderCell } from './header-cell'; 4 | import { tableContext } from '../tableContext'; 5 | 6 | export function Header({ allRowsSelected }) { 7 | const { state, sendMessage } = useContext(tableContext); 8 | const { columns, selectable } = state; 9 | 10 | const generateHeaders = () => columns.map((column) => ( 11 | 15 | )); 16 | 17 | const generateSelectable = () => { 18 | const Component = selectable.type; 19 | return ( 20 | 23 | {selectable?.allowSelectAll ? ( 24 |
    25 | { 29 | const isCheckbox = v?.target?.tagName.toLowerCase() === 'input' && v?.target?.type.toLowerCase() === 'checkbox'; 30 | sendMessage('header.selectAll.change', isCheckbox ? v.target.checked : Boolean(v)); 31 | }} 32 | > 33 | {selectable.values?.value} 34 | 35 |
    36 | ) : ( 37 | selectable.name || 'Select' 38 | )} 39 | 40 | ); 41 | }; 42 | 43 | return ( 44 | 45 | 46 | {selectable?.position === 'LEFT' && generateSelectable()} 47 | {generateHeaders()} 48 | {selectable?.position === 'RIGHT' && generateSelectable()} 49 | 50 | 51 | ); 52 | } 53 | 54 | Header.propTypes = { 55 | allRowsSelected: PropTypes.bool, 56 | }; 57 | -------------------------------------------------------------------------------- /src/components/Table/js/row.js: -------------------------------------------------------------------------------- 1 | import React, { useCallback, useContext } from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import Checkbox from '../../../form/components/Checkbox'; 4 | import { Cell } from './cell'; 5 | import { tableContext } from '../tableContext'; 6 | 7 | export function Row({ row, index }) { 8 | const { state, sendMessage } = useContext(tableContext); 9 | const { columns, selectable } = state; 10 | 11 | const SelectableCheckbox = useCallback(() => ( 12 | 13 | sendMessage('row.selected', { index, selected: v.target.checked })} 16 | /> 17 | 18 | ), [row.selected, index]); 19 | 20 | return ( 21 | 25 | {selectable && selectable.position === 'LEFT' && SelectableCheckbox()} 26 | {columns.map((col) => ( 27 | 28 | ))} 29 | {selectable && selectable.position === 'RIGHT' && SelectableCheckbox()} 30 | 31 | ); 32 | } 33 | 34 | Row.propTypes = { 35 | row: PropTypes.instanceOf(Object), 36 | index: PropTypes.number, 37 | }; 38 | -------------------------------------------------------------------------------- /src/components/Table/tableContext.js: -------------------------------------------------------------------------------- 1 | import { createContext } from 'react'; 2 | 3 | export const tableContext = createContext(); 4 | -------------------------------------------------------------------------------- /src/components/Tabs/Tabs.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --tabs-default-content-padding: 25px; 3 | --tab-button-padding: var(--spacing-sm) 2px 3px 2px; 4 | --tab-button-margin: 0; 5 | --tabs-font-familly: var(--font-family-regular); 6 | --tabs-font-familly-active: var(--font-family-regular); 7 | --tab-border-color: var(--color-primary-base); 8 | --tab-active-color: var(--color-primary-base); 9 | --tab-hover-color: var(--color-text-dark); 10 | } 11 | 12 | .tyk-tabs--default { 13 | > ul { 14 | display: flex; 15 | list-style-type: none; 16 | margin: 0; 17 | padding: 0; 18 | overflow: auto; 19 | 20 | li { 21 | display: flex; 22 | white-space: nowrap; 23 | margin-inline-end: var(--tab-button-margin); 24 | 25 | &:last-child { 26 | margin-inline-end: 0; 27 | } 28 | 29 | &.active button { 30 | border-block-end-color: var(--tab-border-color); 31 | color: var(--tab-active-color); 32 | font-family: var(--tabs-font-familly-active); 33 | opacity: 1; 34 | 35 | &:hover { 36 | color: var(--tab-active-color); 37 | } 38 | } 39 | 40 | button:hover { 41 | color: var(--tab-hover-color); 42 | font-family: var(--tabs-font-familly-active); 43 | opacity: 1; 44 | } 45 | 46 | button { 47 | background: none; 48 | border: none; 49 | border-block-end: 1px solid transparent; 50 | color: var(--text-color); 51 | cursor: pointer; 52 | font-size: var(--xs-font-size); 53 | font-family: var(--tabs-font-familly); 54 | padding: var(--tab-button-padding); 55 | margin-inline-end: var(--spacing-md); 56 | transition: all .2s linear; 57 | opacity: 0.7; 58 | 59 | &:focus { 60 | outline: none; 61 | } 62 | } 63 | } 64 | } 65 | } 66 | 67 | .tyk-tab__content { 68 | padding: var(--tabs-default-content-padding); 69 | } 70 | -------------------------------------------------------------------------------- /src/components/Tabs/js/Tab.js: -------------------------------------------------------------------------------- 1 | import React, { 2 | useContext, useEffect, useState, 3 | } from 'react'; 4 | import PropTypes from 'prop-types'; 5 | import { TabsContext } from '../tabs-context'; 6 | import TabContext from './TabContext'; 7 | import TabContent from './TabContent'; 8 | 9 | function Tab(props) { 10 | const { id } = props; 11 | const tabsContext = useContext(TabsContext); 12 | const tabContext = useContext(TabContext); 13 | const { 14 | tabExists, 15 | selectedPath, 16 | addTab, 17 | updateTab, 18 | hideTab, 19 | showTab, 20 | rendered, 21 | hideTabContent, 22 | tabs, 23 | } = tabsContext; 24 | const { 25 | children, 26 | } = props; 27 | const [path, setPath] = useState(''); 28 | 29 | useEffect(() => { 30 | let tempPath; 31 | if (tabContext && path) { 32 | if (tabContext.tabsId === tabsContext.id) { 33 | tempPath = tabContext.path.concat([id]); 34 | } else { 35 | tempPath = [id]; 36 | } 37 | } else { 38 | tempPath = [id]; 39 | } 40 | setPath(tempPath); 41 | }, [tabContext]); 42 | 43 | if (!path) { 44 | return null; 45 | } 46 | 47 | return ( 48 | 62 | {children} 63 | 64 | ); 65 | } 66 | 67 | Tab.propTypes = { 68 | children: PropTypes.oneOfType([ 69 | PropTypes.arrayOf(PropTypes.node), 70 | PropTypes.node, 71 | PropTypes.element, 72 | PropTypes.string, 73 | ]), 74 | id: PropTypes.string, 75 | }; 76 | 77 | export default Tab; 78 | -------------------------------------------------------------------------------- /src/components/Tabs/js/TabContext.js: -------------------------------------------------------------------------------- 1 | import { createContext } from 'react'; 2 | 3 | export default createContext(); 4 | -------------------------------------------------------------------------------- /src/components/Tabs/tabs-context.js: -------------------------------------------------------------------------------- 1 | import { createContext } from 'react'; 2 | 3 | export const TabsContext = createContext(); 4 | -------------------------------------------------------------------------------- /src/components/TextEllipsis/Readme.md: -------------------------------------------------------------------------------- 1 | ```js 2 | 6 | ``` -------------------------------------------------------------------------------- /src/components/TextEllipsis/TextEllipsis.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import TextEllipsis from './index'; 3 | 4 | function Component() { 5 | return ( 6 |
    7 | 11 |
    12 | ); 13 | } 14 | 15 | describe('TextEllipsis', () => { 16 | const classes = { 17 | floatingContainer: 'floating-container', 18 | }; 19 | it('should show just first 10 chars followed by "..."', () => { 20 | cy.mount() 21 | .get('.text-ellipsis') 22 | .should('have.text', 'alpha, bra...'); 23 | }); 24 | it('when hovering the shrinked texts, shows the tooltip with full text', () => { 25 | cy.mount(); 26 | cy.get(`.${classes.floatingContainer}`) 27 | .should('not.exist') 28 | .get('.text-ellipsis') 29 | .trigger('mouseover'); 30 | 31 | cy.get(`.${classes.floatingContainer}`) 32 | .should('exist'); 33 | }); 34 | }); 35 | -------------------------------------------------------------------------------- /src/components/TextEllipsis/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import Tooltip from '../Tooltip'; 4 | /** 5 | * TextEllipsis component helps you to hide a part of a text, 6 | * but displaying it when it's being hovered. 7 | * The entire text is displayed with the help of Tooltip component 8 | */ 9 | 10 | function TextEllipsis({ text, limit, position }) { 11 | return ( 12 | text.length > limit 13 | ? ( 14 | 15 | {text.substring(0, limit)} 16 | ... 17 | 18 | ) 19 | : text 20 | ); 21 | } 22 | 23 | TextEllipsis.propTypes = { 24 | /** Text to be shrinked by TextEllipsis */ 25 | text: PropTypes.string, 26 | /** Number of characters that TextEllipsis would leave visible */ 27 | limit: PropTypes.number, 28 | /** tooltip position */ 29 | position: PropTypes.string, 30 | }; 31 | 32 | export default TextEllipsis; 33 | -------------------------------------------------------------------------------- /src/components/Toast/Readme.md: -------------------------------------------------------------------------------- 1 | Toast is a service that displays dialogs on the bottom right part of the screen. 2 | 3 | The dialogs can have one of the Tyk UI themes, so that it would match it's purpose (i.e success message, error message) 4 | 5 | Toast service exposes the `notify` method, which should be called when you want to display the dialog. 6 | 7 | It also exposes alias methods that you can call for specific themes. 8 | For example calling **`toast.notify('message', { theme: 'success' })`** and **`toast.success('message')`** are equivalent. 9 | ```js 10 | import toast from './index.js' 11 | const TestToast = () => ( 12 | <> 13 | 14 | 15 | 16 | 17 | 18 | ); 19 | 20 | ``` 21 | -------------------------------------------------------------------------------- /src/components/Toast/Toast.css: -------------------------------------------------------------------------------- 1 | .tyk-toast__container { 2 | inset-block-end: 0; 3 | min-inline-size: 300px; 4 | position: fixed; 5 | inset-inline-end: var(--spacing-md); 6 | z-index: 11; 7 | } 8 | 9 | .tyk-toast__message { 10 | position: relative; 11 | } 12 | 13 | .tyk-toast-message__button { 14 | color: var(--text-color); 15 | block-size: var(--spacing-md); 16 | line-height: 1; 17 | padding: var(--spacing-xs); 18 | position: absolute; 19 | inset-inline-end: var(--spacing-xs); 20 | inset-block-start: var(--spacing-xs); 21 | inline-size: var(--spacing-md); 22 | 23 | &:hover { 24 | background: rgba(255 255 255 / 30%); 25 | color: var(--text-color); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/components/Toast/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { createRoot } from 'react-dom/client'; 3 | import ToastContainer from './js/ToastContainer'; 4 | 5 | /** 6 | * Toast is a service that displays dialogs 7 | * on the bottom right part of the screen. 8 | * 9 | * The dialogs can have one of the Tyk UI themes, so that 10 | * it would match it's purpose (i.e success message, error message) 11 | * 12 | */ 13 | class ToastCreator { 14 | constructor() { 15 | const el = document.createElement('div'); 16 | el.className = 'tyk-toast'; 17 | document.body.appendChild(el); 18 | const root = createRoot(el); 19 | root.render(); 20 | } 21 | 22 | bindNotify = (fn) => { 23 | this.createNotification = fn; 24 | }; 25 | 26 | notify(message, options) { 27 | if (this.createNotification) { 28 | this.createNotification(message, options); 29 | } 30 | } 31 | 32 | danger(message, options) { 33 | this.notify(message, { ...options, theme: 'danger' }); 34 | } 35 | 36 | success(message, options) { 37 | this.notify(message, { ...options, theme: 'success' }); 38 | } 39 | 40 | warning(message, options) { 41 | this.notify(message, { ...options, theme: 'warning' }); 42 | } 43 | 44 | info(message, options) { 45 | this.notify(message, { ...options, theme: 'info' }); 46 | } 47 | } 48 | 49 | const toast = new ToastCreator(); 50 | 51 | export default toast; 52 | -------------------------------------------------------------------------------- /src/components/Toast/js/ToastContainer.js: -------------------------------------------------------------------------------- 1 | import React, { 2 | useEffect, useState, 3 | } from 'react'; 4 | import PropTypes from 'prop-types'; 5 | 6 | import ToastMessage from './ToastMessage'; 7 | 8 | function ToastContainer(props) { 9 | const [messages, setMessages] = useState({}); 10 | const { 11 | notify, 12 | } = props; 13 | 14 | const updateNotifications = (message, options) => { 15 | const msgID = Math.floor(Math.random() * 1000000); 16 | 17 | setMessages((prevMessages) => ({ 18 | ...prevMessages, 19 | [msgID]: { 20 | message, 21 | options, 22 | }, 23 | })); 24 | }; 25 | 26 | useEffect(() => { 27 | notify(updateNotifications); 28 | }, [messages]); 29 | 30 | const onMessageClosed = (index) => { 31 | const tempMessages = { ...messages }; 32 | delete tempMessages[index]; 33 | setMessages((prevMessages) => { 34 | const newMessages = { ...prevMessages }; 35 | delete newMessages[index]; 36 | return newMessages; 37 | }); 38 | }; 39 | 40 | return ( 41 |
    42 | { 43 | Object.keys(messages).map((msgID) => ( 44 | messages[msgID] 45 | ? ( 46 | 52 | {messages[msgID].message} 53 | 54 | ) 55 | : null 56 | )) 57 | } 58 |
    59 | ); 60 | } 61 | 62 | ToastContainer.propTypes = { 63 | notify: PropTypes.func, 64 | }; 65 | 66 | export default ToastContainer; 67 | -------------------------------------------------------------------------------- /src/components/Toast/js/ToastMessage.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | 4 | import Message from '../../Message'; 5 | import { useTimeout } from '../../../hooks'; 6 | 7 | function ToastMessage(props) { 8 | const { 9 | children, 10 | options, 11 | onClose, 12 | index, 13 | } = props; 14 | const opts = { 15 | theme: 'success', 16 | delay: 3000, 17 | ...options, 18 | }; 19 | let timer; 20 | 21 | const handleClose = (itemIndex) => { 22 | onClose(itemIndex); 23 | clearTimeout(timer); 24 | }; 25 | 26 | useTimeout(() => handleClose(index), opts.delay); 27 | 28 | return ( 29 | handleClose(index)} 33 | > 34 | {children} 35 | 36 | ); 37 | } 38 | 39 | ToastMessage.propTypes = { 40 | children: PropTypes.oneOfType([ 41 | PropTypes.element, 42 | PropTypes.node, 43 | PropTypes.string, 44 | ]), 45 | options: PropTypes.instanceOf(Object), 46 | onClose: PropTypes.func, 47 | index: PropTypes.number, 48 | }; 49 | 50 | export default ToastMessage; 51 | -------------------------------------------------------------------------------- /src/components/Tooltip/Tooltip.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --tooltip-max-width: 450px; 3 | } 4 | 5 | .tyk-tooltip { 6 | display: flex; 7 | align-items: center; 8 | background-color: var(--color-secondary-extra-dark1); 9 | border: var(--general-border-width) solid var(--color-secondary-dark); 10 | border-radius: var(--general-border-radius); 11 | color: white; 12 | font-size: var(--font-size-xs); 13 | line-height: var(--line-height-sm); 14 | max-inline-size: var(--tooltip-max-width); 15 | padding: var(--spacing-md); 16 | 17 | > .tyk-icon:first-child { 18 | inline-size: 32px; 19 | block-size: 32px; 20 | border-radius: 50%; 21 | color: white; 22 | background-color: var(--color-text-light); 23 | 24 | &::before { 25 | display: flex; 26 | inline-size: 100%; 27 | block-size: 100%; 28 | align-items: center; 29 | justify-content: center; 30 | } 31 | } 32 | 33 | > .tyk-icon + .tyk-tooltip__content { 34 | margin-inline-start: var(--spacing-md); 35 | } 36 | 37 | > .tyk-icon:last-child { 38 | cursor: pointer; 39 | } 40 | } 41 | 42 | .tyk-tooltip__content { 43 | color: white; 44 | word-break: break-word; 45 | word-wrap: break-word; 46 | 47 | + .tyk-icon { 48 | margin-inline-start: var(--spacing-md); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/form/Readme.md: -------------------------------------------------------------------------------- 1 | form components docs (wip) -------------------------------------------------------------------------------- /src/form/components/Checkbox/Checkbox.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --tyk-checkbox-theme-light-label-color: white; 3 | --tyk-checkbox-theme-light-label-disabled-color: white; 4 | --tyk-checkbox-theme-dark-label-color: var(--text-color); 5 | --tyk-checkbox-theme-dark-label-disabled-color: var(--text-color); 6 | } 7 | 8 | .tyk-checkbox { 9 | label { 10 | --label-indent: 20px; 11 | 12 | display: flex; 13 | align-items: flex-start; 14 | padding-inline-start: var(--label-indent); 15 | 16 | input { 17 | margin-inline-start: calc(-1 * var(--label-indent)); 18 | margin-block-start: 5px; 19 | } 20 | } 21 | } 22 | 23 | .tyk-checkbox--theme-light { 24 | label { 25 | color: var(--tyk-checkbox-theme-light-label-color); 26 | } 27 | 28 | &.tyk-checkbox--is-disabled { 29 | label { 30 | color: var(--tyk-checkbox-theme-light-label-disabled-color); 31 | } 32 | } 33 | } 34 | 35 | .tyk-checkbox--is-disabled { 36 | label, p { 37 | cursor: not-allowed; 38 | opacity: 0.5; 39 | } 40 | } -------------------------------------------------------------------------------- /src/form/components/Checkbox/Checkbox.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Checkbox from './index'; 3 | 4 | describe('Checkbox', () => { 5 | it('Checkbox : with error', () => { 6 | const label = 'This is a checkbox'; 7 | const error = 'Please fix the error'; 8 | cy.mount( 9 | , 14 | ); 15 | 16 | cy.contains(label).should('exist'); 17 | cy.contains(error).should('exist'); 18 | cy.get('#testCheckbox').should('not.be.checked'); 19 | cy.contains(label).should('exist').click(); 20 | cy.get('#testCheckbox').should('be.checked'); 21 | }); 22 | 23 | it('Checkbox : with disabled checked', () => { 24 | const label = 'This is a checkbox'; 25 | cy.mount(); 30 | 31 | cy.contains(label).should('exist'); 32 | cy.get('#testCheckbox').should('not.be.checked'); 33 | cy.contains(label).should('exist').click(); 34 | cy.get('#testCheckbox').should('not.be.checked'); 35 | }); 36 | }); 37 | -------------------------------------------------------------------------------- /src/form/components/Checkbox/Readme.md: -------------------------------------------------------------------------------- 1 | *Themes* 2 | ```js 3 | 7 | ``` 8 | ```js 9 | 14 | ``` 15 | ```js 16 | 21 | ``` 22 | ```js 23 | 27 | ``` 28 | ```js 29 | 32 | ``` 33 | -------------------------------------------------------------------------------- /src/form/components/Combobox2/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/tyk-ui/ca095e717455a87e51a2236c0110aef2fa921023/src/form/components/Combobox2/.DS_Store -------------------------------------------------------------------------------- /src/form/components/DatePicker/DatePicker.css: -------------------------------------------------------------------------------- 1 | @import 'flatpickr/dist/flatpickr.min.css'; 2 | 3 | .flatpickr-day.selected, 4 | .flatpickr-day.startRange, 5 | .flatpickr-day.endRange, 6 | .flatpickr-day.selected.inRange, 7 | .flatpickr-day.startRange.inRange, 8 | .flatpickr-day.endRange.inRange, 9 | .flatpickr-day.selected:focus, 10 | .flatpickr-day.startRange:focus, 11 | .flatpickr-day.endRange:focus, 12 | .flatpickr-day.selected:hover, 13 | .flatpickr-day.startRange:hover, 14 | .flatpickr-day.endRange:hover, 15 | .flatpickr-day.selected.prevMonthDay, 16 | .flatpickr-day.startRange.prevMonthDay, 17 | .flatpickr-day.endRange.prevMonthDay, 18 | .flatpickr-day.selected.nextMonthDay, 19 | .flatpickr-day.startRange.nextMonthDay, 20 | .flatpickr-day.endRange.nextMonthDay { 21 | background: var(--color-primary-base) !important; 22 | border-color: var(--color-primary-base) !important; 23 | } 24 | 25 | .flatpickr-day.inRange, .flatpickr-day.prevMonthDay.inRange, .flatpickr-day.nextMonthDay.inRange, .flatpickr-day.today.inRange, .flatpickr-day.prevMonthDay.today.inRange, .flatpickr-day.nextMonthDay.today.inRange, .flatpickr-day:hover, .flatpickr-day.prevMonthDay:hover, .flatpickr-day.nextMonthDay:hover, .flatpickr-day:focus, .flatpickr-day.prevMonthDay:focus, .flatpickr-day.nextMonthDay:focus { 26 | background: var(--color-primary-light) !important; 27 | border-color: var(--color-primary-light) !important; 28 | } 29 | 30 | .flatpickr-day.inRange { 31 | box-shadow: -5px 0 0 var(--color-primary-light),5px 0 0 var(--color-primary-light) !important; 32 | } -------------------------------------------------------------------------------- /src/form/components/Dropdown/dropdown-context.js: -------------------------------------------------------------------------------- 1 | import { createContext } from 'react'; 2 | 3 | export const DropdownContext = createContext(); 4 | -------------------------------------------------------------------------------- /src/form/components/Dropdown2/Dropdown.css: -------------------------------------------------------------------------------- 1 | .dropdown__menu { 2 | .tyk-list { 3 | background: white; 4 | max-block-size: none; 5 | 6 | li { 7 | padding: 0; 8 | 9 | &:hover { 10 | background-color: var(--color-secondary-extra-light); 11 | } 12 | 13 | a { 14 | color: var(--text-color); 15 | cursor: pointer; 16 | display: block; 17 | padding-block: 10px; 18 | padding-inline: 20px; 19 | text-decoration: none; 20 | } 21 | } 22 | } 23 | } -------------------------------------------------------------------------------- /src/form/components/Dropdown2/DropdownItem.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import List from '../../../components/List'; 4 | import useDropdowContext from './useDrodpownContext'; 5 | 6 | function DropdownItem({ 7 | children, 8 | value, 9 | }) { 10 | const { onChange, value: dropdownValue } = useDropdowContext(); 11 | return ( 12 | 15 | onChange(value) }} 17 | > 18 | { children } 19 | 20 | 21 | ); 22 | } 23 | 24 | DropdownItem.propTypes = { 25 | children: PropTypes.node, 26 | value: PropTypes.any, 27 | }; 28 | 29 | export default DropdownItem; 30 | -------------------------------------------------------------------------------- /src/form/components/Dropdown2/DropdownListWrapper.js: -------------------------------------------------------------------------------- 1 | import React, { forwardRef } from 'react'; 2 | import PropTypes from 'prop-types'; 3 | 4 | import FloatingContainer from '../../../components/FloatingContainer'; 5 | import List from '../../../components/List'; 6 | 7 | const DropdownListWrapper = forwardRef(function DropdownListWrapper({ 8 | children, 9 | element, 10 | maxWidth, 11 | }, ref) { 12 | return ( 13 | 22 | 27 | { children } 28 | 29 | 30 | ); 31 | }); 32 | 33 | DropdownListWrapper.propTypes = { 34 | element: PropTypes.shape({ 35 | current: PropTypes.instanceOf(Element), 36 | }), 37 | children: PropTypes.oneOfType([ 38 | PropTypes.arrayOf(PropTypes.node), 39 | PropTypes.node, 40 | PropTypes.element, 41 | PropTypes.string, 42 | ]), 43 | maxWidth: PropTypes.string, 44 | }; 45 | 46 | export default DropdownListWrapper; 47 | -------------------------------------------------------------------------------- /src/form/components/Dropdown2/DropdownTrigger.js: -------------------------------------------------------------------------------- 1 | import React, { forwardRef } from 'react'; 2 | import PropTypes from 'prop-types'; 3 | 4 | import Button from '../../../components/Button'; 5 | import ButtonGroup from '../../../components/ButtonGroup'; 6 | 7 | const DropdownTrigger = forwardRef(function DropdownTrigger({ 8 | title, 9 | theme = 'primary', 10 | splitTrigger, 11 | toggle, 12 | onTriggerClick, 13 | value, 14 | }, ref) { 15 | return ( 16 | !splitTrigger ? ( 17 | 27 | ) : ( 28 | 29 | 35 | 23 | )} 24 |
    25 | ); 26 | } 27 | 28 | Header.propTypes = { 29 | disabled: PropTypes.bool, 30 | readOnly: PropTypes.bool, 31 | onAddRow: PropTypes.func, 32 | addButtonName: PropTypes.string, 33 | label: PropTypes.oneOfType([ 34 | PropTypes.string, 35 | PropTypes.element, 36 | PropTypes.node, 37 | ]), 38 | }; 39 | 40 | export default Header; 41 | -------------------------------------------------------------------------------- /src/form/components/EditableList2/ListHeader.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | 4 | function ListHeader({ 5 | fields, 6 | readOnly, 7 | }) { 8 | return ( 9 |
  • 10 | { 11 | fields.map((field, index) => { 12 | const key = typeof field === 'function' 13 | ? field?.(0, index).props.key 14 | : field?.props?.label || JSON.stringify(field); 15 | 16 | return ( 17 |
    21 | {field?.props?.label} 22 |
    23 | ); 24 | }) 25 | } 26 |
    Delete
    27 |
  • 28 | ); 29 | } 30 | 31 | ListHeader.propTypes = { 32 | fields: PropTypes.instanceOf(Array), 33 | readOnly: PropTypes.bool, 34 | }; 35 | 36 | export default ListHeader; 37 | -------------------------------------------------------------------------------- /src/form/components/EditableList2/test-data.js: -------------------------------------------------------------------------------- 1 | import Input2 from '../Input2'; 2 | import Combobox2 from '../Combobox2'; 3 | 4 | export const editableListProps = { 5 | label: 'Editable List', 6 | addButtonName: 'Add Item', 7 | readOnly: false, 8 | disabled: false, 9 | error: '', 10 | fields: [ 11 | { 12 | component: Input2, 13 | size: 6, 14 | props: { 15 | name: 'input1', 16 | label: 'Field 1', 17 | theme: 'default rounded-corners', 18 | placeholder: 'Enter Field 1', 19 | value: '', 20 | }, 21 | }, 22 | { 23 | component: Combobox2, 24 | size: 6, 25 | props: { 26 | name: 'combobox1', 27 | label: 'Field 2', 28 | theme: 'default rounded-corners', 29 | placeholder: 'Select Field 2', 30 | values: [], 31 | }, 32 | }, 33 | ], 34 | value: [ 35 | [ 36 | '123', 37 | { id: '456', name: '456' }, 38 | ], 39 | ], 40 | hideOnEmpty: true, 41 | wrapperClassName: 'custom-wrapper-class', 42 | }; 43 | -------------------------------------------------------------------------------- /src/form/components/EditableList2/validate-values.js: -------------------------------------------------------------------------------- 1 | const validateValues = (fields, rowValues) => (rowValues || [[undefined, undefined]])?.map( 2 | (colValue) => colValue?.map( 3 | (value, index) => fields[index].props.validate?.(value), 4 | ), 5 | ); 6 | 7 | export default validateValues; 8 | -------------------------------------------------------------------------------- /src/form/components/EditableList2/with-validation.js: -------------------------------------------------------------------------------- 1 | import React, { useCallback, useState } from 'react'; 2 | 3 | /* eslint-disable-next-line react/display-name */ 4 | const withValidation = (Component) => ({ 5 | onChange, // eslint-disable-line react/prop-types 6 | validate, // eslint-disable-line react/prop-types 7 | error, // eslint-disable-line react/prop-types 8 | ...rest 9 | }) => { 10 | const [internalError, setInternalError] = useState(null); 11 | const onFieldChange = useCallback((event) => { 12 | const value = event?.target 13 | ? ['radio', 'checkbox'].includes(event.target.type) 14 | ? event.target.checked 15 | : event?.target.value 16 | : event; 17 | 18 | let isValid = true; 19 | if (validate && typeof validate === 'function') { 20 | const errorMsg = validate(value); 21 | isValid = !errorMsg; 22 | setInternalError(errorMsg); 23 | } 24 | 25 | onChange(value, isValid); 26 | }, [validate, onChange]); 27 | 28 | return ; 29 | }; 30 | 31 | export default withValidation; 32 | -------------------------------------------------------------------------------- /src/form/components/FileInput/FileInput.css: -------------------------------------------------------------------------------- 1 | .tyk-file-input__wrapper { 2 | position: relative; 3 | 4 | > input { 5 | padding-block: 6px; 6 | padding-inline: var(--spacing-md); 7 | } 8 | 9 | > button { 10 | background: none; 11 | border: none; 12 | cursor: pointer; 13 | position: absolute; 14 | inset-inline-end: var(--spacing-base); 15 | inset-block-start: 9px; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/form/components/FileInput/Readme.md: -------------------------------------------------------------------------------- 1 | ```js 2 | { console.log(e); }} 10 | /> 11 | ``` 12 | ```js 13 | { console.log(e); }} 21 | /> 22 | ``` 23 | ```js 24 | { console.log(e); }} 33 | /> 34 | ``` 35 | ```js 36 | 37 | { console.log(e); }} 46 | /> 47 | 48 | ``` 49 | ```js 50 | { console.log(e); }} 57 | /> 58 | 59 | ``` 60 | -------------------------------------------------------------------------------- /src/form/components/Multiselect/js/MultiselectContext.js: -------------------------------------------------------------------------------- 1 | import { createContext } from 'react'; 2 | 3 | const MultiselectContext = createContext(); 4 | 5 | export default MultiselectContext; 6 | -------------------------------------------------------------------------------- /src/form/components/Pagination/Pagination.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --pagination-border-radius: var(--general-border-radius); 3 | --pagination-button-padding: var(--spacing-sm) var(--spacing-base); 4 | } 5 | 6 | .tyk-pagination { 7 | display: flex; 8 | list-style-type: none; 9 | margin-block: var(--spacing-sm); 10 | margin-inline: 0; 11 | padding: 0; 12 | 13 | li { 14 | align-items: center; 15 | display: flex; 16 | } 17 | 18 | li:first-child button { 19 | border-start-start-radius: var(--pagination-border-radius); 20 | border-end-start-radius: var(--pagination-border-radius); 21 | } 22 | 23 | li:last-child button { 24 | border-start-end-radius: var(--pagination-border-radius); 25 | border-end-end-radius: var(--pagination-border-radius); 26 | } 27 | 28 | span { 29 | margin-block: 0; 30 | margin-inline: var(--spacing-sm); 31 | } 32 | 33 | button { 34 | background: white; 35 | border: none; 36 | font-size: var(--sm-font-size); 37 | font-family: var(--font-family-bold); 38 | cursor: pointer; 39 | color: var(--color-text-dark); 40 | margin-inline-start: -1px; 41 | padding: var(--pagination-button-padding); 42 | 43 | &:hover { 44 | background-color: var(--color-primary-light); 45 | } 46 | } 47 | 48 | .active button { 49 | background-color: var(--color-primary-base); 50 | color: white; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/form/components/Pagination/Readme.md: -------------------------------------------------------------------------------- 1 | ```js 2 | { console.log(pageNr); }} 7 | /> 8 | ``` 9 | -------------------------------------------------------------------------------- /src/form/components/Radio/Radio.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --radio-description-text-padding: 0 0 0 20px; 3 | } 4 | 5 | .tyk-radio { 6 | label { 7 | align-items: center; 8 | display: flex; 9 | } 10 | } 11 | 12 | .tyk-radio--is-disabled { 13 | label, p { 14 | cursor: not-allowed; 15 | opacity: 0.5; 16 | } 17 | } 18 | 19 | .tyk-radio__description-text { 20 | padding: var(--radio-description-text-padding); 21 | } -------------------------------------------------------------------------------- /src/form/components/Radio/Readme.md: -------------------------------------------------------------------------------- 1 | *Themes* 2 | ```js 3 | 8 | 12 | ``` 13 | 14 | ```js 15 | 21 | 26 | ``` 27 | -------------------------------------------------------------------------------- /src/form/components/Select/Select.css: -------------------------------------------------------------------------------- 1 | .tyk-select { 2 | background: transparent url('./images/arrow_down.svg') no-repeat calc(100% - 15px) center; 3 | background-size: var(--spacing-base) var(--spacing-base); 4 | } -------------------------------------------------------------------------------- /src/form/components/Select/images/arrow_down.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/form/components/SelectableList/Readme.md: -------------------------------------------------------------------------------- 1 | ```js 2 | { console.log(selectedItems); }} 12 | style={{ 13 | maxHeight: '100px' 14 | }} 15 | label="super cool list" 16 | labelwidth="25%" 17 | /> 18 | ``` 19 | 20 | ```js 21 | { console.log(selectedItems); }} 32 | style={{ 33 | maxHeight: '100px' 34 | }} 35 | label="super cool list" 36 | labelwidth="25%" 37 | /> 38 | ``` 39 | -------------------------------------------------------------------------------- /src/form/components/SelectableList/SelectableList.css: -------------------------------------------------------------------------------- 1 | .tyk-selectable-list { 2 | margin-block-end: var(--spacing-md); 3 | inline-size: 100%; 4 | 5 | li:not(.tyk-selectable-list__no-items-message) { 6 | font-family: var(--font-family-medium); 7 | padding: 0; 8 | 9 | .tyk-message { 10 | margin-block-end: 0; 11 | } 12 | 13 | label { 14 | font-family: var(--font-family-bold); 15 | margin: 0; 16 | } 17 | 18 | > label { 19 | align-items: center; 20 | cursor: pointer; 21 | display: flex; 22 | padding-block: var(--spacing-sm); 23 | padding-inline: var(--spacing-md); 24 | 25 | input[type="checkbox"] { 26 | margin-inline-start: auto; 27 | } 28 | } 29 | } 30 | } 31 | 32 | .tyk-selectable-list__item--with-icon { 33 | & input[type="checkbox"] { 34 | visibility: hidden; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/form/components/Textarea/Readme.md: -------------------------------------------------------------------------------- 1 | ```js 2 |