├── .npmrc ├── src ├── hooks │ ├── Readme.md │ ├── useInterval │ │ ├── Readme.md │ │ └── index.js │ ├── usePrevious │ │ ├── Readme.md │ │ └── index.js │ ├── useTimeout │ │ ├── Readme.md │ │ └── index.js │ ├── useComponentSize │ │ ├── Readme.md │ │ └── index.js │ ├── useEventListener │ │ ├── Readme.md │ │ └── index.js │ └── index.js ├── utils │ ├── formik │ │ ├── styleguidist-example.js │ │ └── Readme.md │ ├── config │ │ └── config.js │ └── debounce │ │ ├── index.js │ │ ├── Readme.md │ │ └── styleguidist-example.js ├── form │ ├── Readme.md │ ├── components │ │ ├── Textarea │ │ │ ├── Textarea.css │ │ │ └── Readme.md │ │ ├── Combobox2 │ │ │ └── .DS_Store │ │ ├── Dropdown │ │ │ └── dropdown-context.js │ │ ├── Toggle │ │ │ └── js │ │ │ │ ├── ToggleContext.js │ │ │ │ └── ToggleItemWrapper.js │ │ ├── Multiselect │ │ │ └── js │ │ │ │ └── MultiselectContext.js │ │ ├── Pagination │ │ │ ├── Readme.md │ │ │ └── Pagination.css │ │ ├── Select │ │ │ ├── Select.css │ │ │ └── images │ │ │ │ └── arrow_down.svg │ │ ├── Dropdown2 │ │ │ ├── useDrodpownContext.js │ │ │ ├── Dropdown.css │ │ │ ├── DropdownItem.js │ │ │ ├── useDropdown.js │ │ │ ├── DropdownListWrapper.js │ │ │ ├── Readme.md │ │ │ └── DropdownTrigger.js │ │ ├── EditableList2 │ │ │ ├── validate-values.js │ │ │ ├── Header.js │ │ │ ├── test-data.js │ │ │ ├── ListHeader.js │ │ │ └── with-validation.js │ │ ├── FileInput │ │ │ ├── FileInput.css │ │ │ └── Readme.md │ │ ├── Radio │ │ │ ├── Radio.css │ │ │ └── Readme.md │ │ ├── Checkbox │ │ │ ├── Readme.md │ │ │ ├── Checkbox.css │ │ │ └── Checkbox.test.js │ │ ├── SelectableList │ │ │ ├── SelectableList.css │ │ │ └── Readme.md │ │ └── DatePicker │ │ │ └── DatePicker.css │ ├── redux-form │ │ ├── FieldCombobox2 │ │ │ ├── .DS_Store │ │ │ └── index.js │ │ ├── FieldPagination │ │ │ └── index.js │ │ ├── FieldToggle │ │ │ └── index.js │ │ ├── FieldInput │ │ │ └── index.js │ │ ├── FieldFileInput │ │ │ └── index.js │ │ ├── FieldSelectableList │ │ │ └── index.js │ │ ├── FieldDropdown │ │ │ └── index.js │ │ ├── FieldDatePicker │ │ │ └── index.js │ │ ├── FieldCodeEditor │ │ │ └── index.js │ │ ├── FieldEditableList │ │ │ └── index.js │ │ ├── FieldCombobox │ │ │ └── index.js │ │ ├── FieldMultiselect │ │ │ └── index.js │ │ └── FieldSelect │ │ │ └── index.js │ └── formik │ │ ├── FormikInput2 │ │ └── index.js │ │ ├── FormikToggle │ │ └── index.js │ │ ├── FormikCombobox │ │ └── index.js │ │ ├── FormikTextarea │ │ └── index.js │ │ ├── FormikCodeEditor │ │ └── index.js │ │ ├── FormikCombobox2 │ │ └── index.js │ │ ├── FormikDatePicker │ │ └── index.js │ │ ├── FormikFileInput │ │ └── index.js │ │ ├── FormikMultiselect │ │ └── index.js │ │ ├── FormikInput │ │ └── index.js │ │ ├── FormikSelect │ │ └── index.js │ │ ├── FormikEditableList2 │ │ └── index.js │ │ ├── FormikSelectableList │ │ └── index.js │ │ ├── FormikCheckbox │ │ └── index.js │ │ ├── FormikEditableList │ │ └── index.js │ │ └── FormikRadio │ │ └── index.js ├── components │ ├── InfoNote │ │ ├── Readme.md │ │ ├── index.js │ │ └── InfoNote.test.js │ ├── Tabs │ │ ├── js │ │ │ ├── TabContext.js │ │ │ └── Tab.js │ │ ├── tabs-context.js │ │ └── Tabs.css │ ├── Icon │ │ ├── Icon.css │ │ ├── index.js │ │ └── Icon.test.js │ ├── Table │ │ ├── tableContext.js │ │ └── js │ │ │ ├── body.js │ │ │ ├── cell.js │ │ │ ├── header-cell.js │ │ │ ├── row.js │ │ │ └── header.js │ ├── Panel │ │ ├── panel-context.js │ │ └── js │ │ │ ├── PanelFooter.js │ │ │ ├── PanelBody.js │ │ │ └── PanelHeader.js │ ├── TextEllipsis │ │ ├── Readme.md │ │ ├── index.js │ │ └── TextEllipsis.test.js │ ├── CopyToClipboard │ │ ├── CopyToClipboard.css │ │ ├── Readme.md │ │ ├── CopyToClipboard.test.js │ │ └── index.js │ ├── Accordion │ │ ├── js │ │ │ ├── AccordionContext.js │ │ │ ├── AccordionItemContext.js │ │ │ ├── AccordionItemContent.js │ │ │ ├── AccordionItemTrigger.js │ │ │ ├── AccordionItemContent.test.js │ │ │ ├── AccordionItemTrigger.test.js │ │ │ ├── AccordionItemHeader.test.js │ │ │ ├── AccordionItemHeader.js │ │ │ └── AccordionItem.js │ │ ├── Readme.md │ │ ├── Accordion.test.js │ │ ├── index.js │ │ └── Accordion.css │ ├── Chart │ │ ├── Chart.css │ │ └── Readme.md │ ├── FloatingContainer │ │ └── FloatingContainer.css │ ├── Navigation │ │ ├── Readme.md │ │ ├── js │ │ │ └── NavigationItem.js │ │ ├── index.js │ │ ├── Navigation.test.js │ │ └── Navigation.css │ ├── InfiniteScroller │ │ ├── InfiniteScroller.css │ │ └── InfiniteScroller.test.js │ ├── Modal │ │ └── js │ │ │ ├── ModalTitle.js │ │ │ ├── ModalBody.js │ │ │ ├── ModalFooter.js │ │ │ └── ModalHeader.js │ ├── Stepper │ │ ├── StepperContext.js │ │ └── js │ │ │ ├── Step.js │ │ │ ├── StepNumber.js │ │ │ ├── StepList.js │ │ │ ├── StepperButtons.js │ │ │ └── Buttons.js │ ├── Card │ │ ├── CardFooter.js │ │ ├── CardSubTitle.js │ │ ├── CardTitleIcon.js │ │ ├── CardTitleGroup.js │ │ ├── CardTitle.js │ │ ├── CardBody.js │ │ ├── CardSummary.js │ │ ├── CardHeader.js │ │ └── index.js │ ├── Confirm │ │ └── Readme.md │ ├── FixedWrapper │ │ ├── FixedWrapper.css │ │ ├── FixedWrapper.test.js │ │ └── index.js │ ├── Collapsible │ │ ├── Collapsible.css │ │ └── Readme.md │ ├── Sidebar │ │ └── Sidebar.css │ ├── RevealPanel │ │ ├── RevealPanel.test.js │ │ ├── images │ │ │ └── drag.svg │ │ ├── Readme.md │ │ └── RevealPanel.css │ ├── CollapsibleList │ │ ├── js │ │ │ └── CollapsibleListItem.js │ │ ├── CollapsibleList.css │ │ └── index.js │ ├── List │ │ ├── js │ │ │ └── ListItem.js │ │ ├── List.test.js │ │ ├── Readme.md │ │ └── index.js │ ├── Toast │ │ ├── Toast.css │ │ ├── Readme.md │ │ ├── js │ │ │ ├── ToastMessage.js │ │ │ └── ToastContainer.js │ │ └── index.js │ ├── ButtonGroup │ │ ├── index.js │ │ ├── ButtonGroup.test.js │ │ └── ButtonGroup.css │ ├── Pill │ │ └── index.js │ ├── Loader │ │ ├── Readme.md │ │ └── index.js │ ├── Tooltip │ │ └── Tooltip.css │ ├── NavBar │ │ └── index.js │ └── Message │ │ └── Message.test.js ├── common │ ├── fonts │ │ ├── tykon.eot │ │ ├── tykon.otf │ │ ├── tykon.ttf │ │ ├── tykon.woff │ │ ├── tykon.woff2 │ │ ├── inter │ │ │ ├── Inter-Bold.eot │ │ │ ├── Inter-Bold.ttf │ │ │ ├── Inter-Bold.woff │ │ │ ├── Inter-Bold.woff2 │ │ │ ├── Inter-Light.eot │ │ │ ├── Inter-Light.ttf │ │ │ ├── Inter-Light.woff │ │ │ ├── Inter-Light.woff2 │ │ │ ├── Inter-Medium.eot │ │ │ ├── Inter-Medium.ttf │ │ │ ├── Inter-Medium.woff │ │ │ ├── Inter-Regular.eot │ │ │ ├── Inter-Regular.ttf │ │ │ ├── Inter-Medium.woff2 │ │ │ ├── Inter-Regular.woff │ │ │ ├── Inter-Regular.woff2 │ │ │ ├── Inter-SemiBold.eot │ │ │ ├── Inter-SemiBold.ttf │ │ │ ├── Inter-SemiBold.woff │ │ │ └── Inter-SemiBold.woff2 │ │ └── fontawesome │ │ │ ├── fa-light-300.ttf │ │ │ ├── fa-solid-900.ttf │ │ │ ├── fa-light-300.woff2 │ │ │ ├── fa-regular-400.ttf │ │ │ ├── fa-solid-900.woff2 │ │ │ └── fa-regular-400.woff2 │ ├── css │ │ ├── texts.css │ │ ├── fontawesome │ │ │ ├── light.css │ │ │ ├── solid.css │ │ │ └── regular.css │ │ ├── layout.css │ │ ├── reset.css │ │ └── fonts.css │ ├── sass │ │ └── mixins.scss │ └── images │ │ ├── drag.svg │ │ └── arrow-down.svg ├── index.css ├── layout │ ├── Row │ │ ├── index.js │ │ ├── Row.test.js │ │ └── Readme.md │ └── Column │ │ ├── Readme.md │ │ ├── index.js │ │ └── Column.test.js └── typography │ └── Readme.md ├── docs ├── Fonts.md ├── Theming.md ├── Globals.md ├── PublishingGuide.md ├── Contributing.md └── GettingStarted.md ├── lib ├── fonts │ ├── tykon.woff │ ├── tykon.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 │ └── fontawesome │ │ ├── fa-light-300.ttf │ │ ├── fa-light-300.woff2 │ │ ├── fa-regular-400.ttf │ │ ├── fa-solid-900.ttf │ │ ├── fa-solid-900.woff2 │ │ └── fa-regular-400.woff2 ├── index.js.LICENSE.txt ├── tyk-ui.js.LICENSE.txt ├── images │ ├── arrow_down.svg │ └── drag.svg └── sass │ └── common │ └── sass │ └── mixins.scss ├── .gitignore ├── cypress ├── fixtures │ └── example.json └── support │ ├── component-index.html │ ├── commands.js │ └── component.js ├── logo └── index.js ├── .github └── workflows │ ├── jira-pr-validator.yaml │ ├── README.md │ ├── visor.yaml │ └── build-and-publish.yml ├── cypress.config.js ├── .stylelintrc.js ├── webpack.component.js └── README.md /.npmrc: -------------------------------------------------------------------------------- 1 | save-prefix="" -------------------------------------------------------------------------------- /src/hooks/Readme.md: -------------------------------------------------------------------------------- 1 | hooks docs (wip) -------------------------------------------------------------------------------- /src/utils/formik/styleguidist-example.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/form/Readme.md: -------------------------------------------------------------------------------- 1 | form components docs (wip) -------------------------------------------------------------------------------- /docs/Fonts.md: -------------------------------------------------------------------------------- 1 | - Default fonts and how to override them -------------------------------------------------------------------------------- /docs/Theming.md: -------------------------------------------------------------------------------- 1 | - How to use/override tyk-ui themes -------------------------------------------------------------------------------- /src/hooks/useInterval/Readme.md: -------------------------------------------------------------------------------- 1 | useInterval docs 2 | -------------------------------------------------------------------------------- /src/hooks/usePrevious/Readme.md: -------------------------------------------------------------------------------- 1 | usePrevious docs 2 | -------------------------------------------------------------------------------- /src/hooks/useTimeout/Readme.md: -------------------------------------------------------------------------------- 1 | useTimeout docs 2 | -------------------------------------------------------------------------------- /docs/Globals.md: -------------------------------------------------------------------------------- 1 | - tyk-ui global variables documentation -------------------------------------------------------------------------------- /src/hooks/useComponentSize/Readme.md: -------------------------------------------------------------------------------- 1 | useComponentSize docs 2 | -------------------------------------------------------------------------------- /src/hooks/useEventListener/Readme.md: -------------------------------------------------------------------------------- 1 | useEventListener docs 2 | -------------------------------------------------------------------------------- /lib/fonts/tykon.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/tyk-ui/HEAD/lib/fonts/tykon.woff -------------------------------------------------------------------------------- /lib/fonts/tykon.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/tyk-ui/HEAD/lib/fonts/tykon.woff2 -------------------------------------------------------------------------------- /src/form/components/Textarea/Textarea.css: -------------------------------------------------------------------------------- 1 | textarea.tyk-form-control { 2 | block-size: auto; 3 | } 4 | -------------------------------------------------------------------------------- /src/components/InfoNote/Readme.md: -------------------------------------------------------------------------------- 1 | *Themes* 2 | ```js 3 | Default InfoNote 4 | ``` 5 | -------------------------------------------------------------------------------- /src/common/fonts/tykon.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/tyk-ui/HEAD/src/common/fonts/tykon.eot -------------------------------------------------------------------------------- /src/common/fonts/tykon.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/tyk-ui/HEAD/src/common/fonts/tykon.otf -------------------------------------------------------------------------------- /src/common/fonts/tykon.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/tyk-ui/HEAD/src/common/fonts/tykon.ttf -------------------------------------------------------------------------------- /src/common/fonts/tykon.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/tyk-ui/HEAD/src/common/fonts/tykon.woff -------------------------------------------------------------------------------- /src/common/fonts/tykon.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/tyk-ui/HEAD/src/common/fonts/tykon.woff2 -------------------------------------------------------------------------------- /lib/fonts/inter/Inter-Bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/tyk-ui/HEAD/lib/fonts/inter/Inter-Bold.woff -------------------------------------------------------------------------------- /lib/fonts/inter/Inter-Bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/tyk-ui/HEAD/lib/fonts/inter/Inter-Bold.woff2 -------------------------------------------------------------------------------- /lib/fonts/inter/Inter-Light.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/tyk-ui/HEAD/lib/fonts/inter/Inter-Light.woff -------------------------------------------------------------------------------- /src/components/Tabs/js/TabContext.js: -------------------------------------------------------------------------------- 1 | import { createContext } from 'react'; 2 | 3 | export default createContext(); 4 | -------------------------------------------------------------------------------- /lib/fonts/inter/Inter-Light.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/tyk-ui/HEAD/lib/fonts/inter/Inter-Light.woff2 -------------------------------------------------------------------------------- /lib/fonts/inter/Inter-Medium.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/tyk-ui/HEAD/lib/fonts/inter/Inter-Medium.woff -------------------------------------------------------------------------------- /lib/fonts/inter/Inter-Medium.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/tyk-ui/HEAD/lib/fonts/inter/Inter-Medium.woff2 -------------------------------------------------------------------------------- /lib/fonts/inter/Inter-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/tyk-ui/HEAD/lib/fonts/inter/Inter-Regular.woff -------------------------------------------------------------------------------- /lib/fonts/inter/Inter-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/tyk-ui/HEAD/lib/fonts/inter/Inter-Regular.woff2 -------------------------------------------------------------------------------- /lib/fonts/inter/Inter-SemiBold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/tyk-ui/HEAD/lib/fonts/inter/Inter-SemiBold.woff -------------------------------------------------------------------------------- /src/components/Icon/Icon.css: -------------------------------------------------------------------------------- 1 | .tyk-icon { 2 | + .tyk-icon { 3 | margin-inline-start: var(--spacing-sm); 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /lib/fonts/inter/Inter-SemiBold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/tyk-ui/HEAD/lib/fonts/inter/Inter-SemiBold.woff2 -------------------------------------------------------------------------------- /src/common/fonts/inter/Inter-Bold.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/tyk-ui/HEAD/src/common/fonts/inter/Inter-Bold.eot -------------------------------------------------------------------------------- /src/common/fonts/inter/Inter-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/tyk-ui/HEAD/src/common/fonts/inter/Inter-Bold.ttf -------------------------------------------------------------------------------- /src/components/Table/tableContext.js: -------------------------------------------------------------------------------- 1 | import { createContext } from 'react'; 2 | 3 | export const tableContext = createContext(); 4 | -------------------------------------------------------------------------------- /src/components/Tabs/tabs-context.js: -------------------------------------------------------------------------------- 1 | import { createContext } from 'react'; 2 | 3 | export const TabsContext = createContext(); 4 | -------------------------------------------------------------------------------- /lib/fonts/fontawesome/fa-light-300.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/tyk-ui/HEAD/lib/fonts/fontawesome/fa-light-300.ttf -------------------------------------------------------------------------------- /lib/fonts/fontawesome/fa-light-300.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/tyk-ui/HEAD/lib/fonts/fontawesome/fa-light-300.woff2 -------------------------------------------------------------------------------- /lib/fonts/fontawesome/fa-regular-400.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/tyk-ui/HEAD/lib/fonts/fontawesome/fa-regular-400.ttf -------------------------------------------------------------------------------- /lib/fonts/fontawesome/fa-solid-900.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/tyk-ui/HEAD/lib/fonts/fontawesome/fa-solid-900.ttf -------------------------------------------------------------------------------- /lib/fonts/fontawesome/fa-solid-900.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/tyk-ui/HEAD/lib/fonts/fontawesome/fa-solid-900.woff2 -------------------------------------------------------------------------------- /src/common/fonts/inter/Inter-Bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/tyk-ui/HEAD/src/common/fonts/inter/Inter-Bold.woff -------------------------------------------------------------------------------- /src/common/fonts/inter/Inter-Bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/tyk-ui/HEAD/src/common/fonts/inter/Inter-Bold.woff2 -------------------------------------------------------------------------------- /src/common/fonts/inter/Inter-Light.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/tyk-ui/HEAD/src/common/fonts/inter/Inter-Light.eot -------------------------------------------------------------------------------- /src/common/fonts/inter/Inter-Light.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/tyk-ui/HEAD/src/common/fonts/inter/Inter-Light.ttf -------------------------------------------------------------------------------- /src/common/fonts/inter/Inter-Light.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/tyk-ui/HEAD/src/common/fonts/inter/Inter-Light.woff -------------------------------------------------------------------------------- /src/common/fonts/inter/Inter-Light.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/tyk-ui/HEAD/src/common/fonts/inter/Inter-Light.woff2 -------------------------------------------------------------------------------- /src/common/fonts/inter/Inter-Medium.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/tyk-ui/HEAD/src/common/fonts/inter/Inter-Medium.eot -------------------------------------------------------------------------------- /src/common/fonts/inter/Inter-Medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/tyk-ui/HEAD/src/common/fonts/inter/Inter-Medium.ttf -------------------------------------------------------------------------------- /src/common/fonts/inter/Inter-Medium.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/tyk-ui/HEAD/src/common/fonts/inter/Inter-Medium.woff -------------------------------------------------------------------------------- /src/common/fonts/inter/Inter-Regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/tyk-ui/HEAD/src/common/fonts/inter/Inter-Regular.eot -------------------------------------------------------------------------------- /src/common/fonts/inter/Inter-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/tyk-ui/HEAD/src/common/fonts/inter/Inter-Regular.ttf -------------------------------------------------------------------------------- /src/components/Panel/panel-context.js: -------------------------------------------------------------------------------- 1 | import { createContext } from 'react'; 2 | 3 | export const PortalContext = createContext(); 4 | -------------------------------------------------------------------------------- /src/form/components/Combobox2/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/tyk-ui/HEAD/src/form/components/Combobox2/.DS_Store -------------------------------------------------------------------------------- /lib/fonts/fontawesome/fa-regular-400.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/tyk-ui/HEAD/lib/fonts/fontawesome/fa-regular-400.woff2 -------------------------------------------------------------------------------- /src/common/fonts/inter/Inter-Medium.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/tyk-ui/HEAD/src/common/fonts/inter/Inter-Medium.woff2 -------------------------------------------------------------------------------- /src/common/fonts/inter/Inter-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/tyk-ui/HEAD/src/common/fonts/inter/Inter-Regular.woff -------------------------------------------------------------------------------- /src/common/fonts/inter/Inter-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/tyk-ui/HEAD/src/common/fonts/inter/Inter-Regular.woff2 -------------------------------------------------------------------------------- /src/common/fonts/inter/Inter-SemiBold.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/tyk-ui/HEAD/src/common/fonts/inter/Inter-SemiBold.eot -------------------------------------------------------------------------------- /src/common/fonts/inter/Inter-SemiBold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/tyk-ui/HEAD/src/common/fonts/inter/Inter-SemiBold.ttf -------------------------------------------------------------------------------- /src/common/fonts/inter/Inter-SemiBold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/tyk-ui/HEAD/src/common/fonts/inter/Inter-SemiBold.woff -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | tyk-ui-styleguide 3 | coverage 4 | .nyc_output 5 | *DS_Store 6 | cypress/screenshots 7 | .vscode 8 | .scannerwork 9 | -------------------------------------------------------------------------------- /src/common/fonts/fontawesome/fa-light-300.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/tyk-ui/HEAD/src/common/fonts/fontawesome/fa-light-300.ttf -------------------------------------------------------------------------------- /src/common/fonts/fontawesome/fa-solid-900.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/tyk-ui/HEAD/src/common/fonts/fontawesome/fa-solid-900.ttf -------------------------------------------------------------------------------- /src/common/fonts/inter/Inter-SemiBold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/tyk-ui/HEAD/src/common/fonts/inter/Inter-SemiBold.woff2 -------------------------------------------------------------------------------- /src/form/components/Dropdown/dropdown-context.js: -------------------------------------------------------------------------------- 1 | import { createContext } from 'react'; 2 | 3 | export const DropdownContext = createContext(); 4 | -------------------------------------------------------------------------------- /src/form/redux-form/FieldCombobox2/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/tyk-ui/HEAD/src/form/redux-form/FieldCombobox2/.DS_Store -------------------------------------------------------------------------------- /src/common/fonts/fontawesome/fa-light-300.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/tyk-ui/HEAD/src/common/fonts/fontawesome/fa-light-300.woff2 -------------------------------------------------------------------------------- /src/common/fonts/fontawesome/fa-regular-400.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/tyk-ui/HEAD/src/common/fonts/fontawesome/fa-regular-400.ttf -------------------------------------------------------------------------------- /src/common/fonts/fontawesome/fa-solid-900.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/tyk-ui/HEAD/src/common/fonts/fontawesome/fa-solid-900.woff2 -------------------------------------------------------------------------------- /src/components/TextEllipsis/Readme.md: -------------------------------------------------------------------------------- 1 | ```js 2 | 6 | ``` -------------------------------------------------------------------------------- /src/common/fonts/fontawesome/fa-regular-400.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TykTechnologies/tyk-ui/HEAD/src/common/fonts/fontawesome/fa-regular-400.woff2 -------------------------------------------------------------------------------- /src/utils/formik/Readme.md: -------------------------------------------------------------------------------- 1 | This wrapper is used to make a normal input a field component in order to use with Formik 2 | 3 | ### Syntax 4 | `wrapper(Toggle)` -------------------------------------------------------------------------------- /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/components/CopyToClipboard/CopyToClipboard.css: -------------------------------------------------------------------------------- 1 | .tyk-copy-to-clipboard { 2 | position: absolute; 3 | inset-inline-start: -1000px; 4 | inset-block-start: -1000px; 5 | } -------------------------------------------------------------------------------- /src/form/components/Toggle/js/ToggleContext.js: -------------------------------------------------------------------------------- 1 | import { createContext } from 'react'; 2 | 3 | const ToggleContext = createContext(); 4 | 5 | export default ToggleContext; 6 | -------------------------------------------------------------------------------- /src/form/formik/FormikInput2/index.js: -------------------------------------------------------------------------------- 1 | import wrapper from '../../../utils/formik'; 2 | import Input2 from '../../components/Input2'; 3 | 4 | export default wrapper(Input2); 5 | -------------------------------------------------------------------------------- /src/form/formik/FormikToggle/index.js: -------------------------------------------------------------------------------- 1 | import wrapper from '../../../utils/formik'; 2 | import Toggle from '../../components/Toggle'; 3 | 4 | export default wrapper(Toggle); 5 | -------------------------------------------------------------------------------- /src/components/Accordion/js/AccordionContext.js: -------------------------------------------------------------------------------- 1 | import { createContext } from 'react'; 2 | 3 | const AccordionContext = createContext(); 4 | 5 | export default AccordionContext; 6 | -------------------------------------------------------------------------------- /src/form/formik/FormikCombobox/index.js: -------------------------------------------------------------------------------- 1 | import wrapper from '../../../utils/formik'; 2 | import Combobox from '../../components/Combobox'; 3 | 4 | export default wrapper(Combobox); 5 | -------------------------------------------------------------------------------- /src/form/formik/FormikTextarea/index.js: -------------------------------------------------------------------------------- 1 | import wrapper from '../../../utils/formik'; 2 | import Textarea from '../../components/Textarea'; 3 | 4 | export default wrapper(Textarea); 5 | -------------------------------------------------------------------------------- /src/form/formik/FormikCodeEditor/index.js: -------------------------------------------------------------------------------- 1 | import wrapper from '../../../utils/formik'; 2 | import CodeEditor from '../../components/CodeEditor'; 3 | 4 | export default wrapper(CodeEditor); 5 | -------------------------------------------------------------------------------- /src/form/formik/FormikCombobox2/index.js: -------------------------------------------------------------------------------- 1 | import wrapper from '../../../utils/formik'; 2 | import Combobox2 from '../../components/Combobox2'; 3 | 4 | export default wrapper(Combobox2); 5 | -------------------------------------------------------------------------------- /src/form/formik/FormikDatePicker/index.js: -------------------------------------------------------------------------------- 1 | import wrapper from '../../../utils/formik'; 2 | import DatePicker from '../../components/DatePicker'; 3 | 4 | export default wrapper(DatePicker); 5 | -------------------------------------------------------------------------------- /src/form/formik/FormikFileInput/index.js: -------------------------------------------------------------------------------- 1 | import wrapper from '../../../utils/formik'; 2 | import FileInput from '../../components/FileInput'; 3 | 4 | export default wrapper(FileInput); 5 | -------------------------------------------------------------------------------- /src/components/Accordion/js/AccordionItemContext.js: -------------------------------------------------------------------------------- 1 | import { createContext } from 'react'; 2 | 3 | const AccordionItemContext = createContext(); 4 | 5 | export default AccordionItemContext; 6 | -------------------------------------------------------------------------------- /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/form/components/Multiselect/js/MultiselectContext.js: -------------------------------------------------------------------------------- 1 | import { createContext } from 'react'; 2 | 3 | const MultiselectContext = createContext(); 4 | 5 | export default MultiselectContext; 6 | -------------------------------------------------------------------------------- /src/form/formik/FormikMultiselect/index.js: -------------------------------------------------------------------------------- 1 | import wrapper from '../../../utils/formik'; 2 | import MultiSelect from '../../components/Multiselect'; 3 | 4 | export default wrapper(MultiSelect); 5 | -------------------------------------------------------------------------------- /src/form/formik/FormikInput/index.js: -------------------------------------------------------------------------------- 1 | import wrapper from '../../../utils/formik'; 2 | import Input from '../../components/Input'; 3 | 4 | export default wrapper(Input, { hasIsFieldProp: true }); 5 | -------------------------------------------------------------------------------- /src/form/formik/FormikSelect/index.js: -------------------------------------------------------------------------------- 1 | import wrapper from '../../../utils/formik'; 2 | import Select from '../../components/Select'; 3 | 4 | export default wrapper(Select, { hasIsFieldProp: true }); 5 | -------------------------------------------------------------------------------- /src/utils/config/config.js: -------------------------------------------------------------------------------- 1 | const config = { 2 | FORM_DEBOUNCE: 200, 3 | }; 4 | 5 | export function setConfig(key, val) { 6 | config[key] = val; 7 | } 8 | 9 | export default config; 10 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /src/form/components/Pagination/Readme.md: -------------------------------------------------------------------------------- 1 | ```js 2 | { console.log(pageNr); }} 7 | /> 8 | ``` 9 | -------------------------------------------------------------------------------- /src/form/formik/FormikEditableList2/index.js: -------------------------------------------------------------------------------- 1 | import wrapper from '../../../utils/formik'; 2 | import EditableList2 from '../../components/EditableList2'; 3 | 4 | export default wrapper(EditableList2); 5 | -------------------------------------------------------------------------------- /src/form/formik/FormikSelectableList/index.js: -------------------------------------------------------------------------------- 1 | import wrapper from '../../../utils/formik'; 2 | import SelectableList from '../../components/SelectableList'; 3 | 4 | export default wrapper(SelectableList); 5 | -------------------------------------------------------------------------------- /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/formik/FormikCheckbox/index.js: -------------------------------------------------------------------------------- 1 | import wrapper from '../../../utils/formik'; 2 | import Checkbox from '../../components/Checkbox'; 3 | 4 | export default wrapper(Checkbox, { 5 | getOnChangeProps: (value) => ({ 6 | checked: value, 7 | }), 8 | }); 9 | -------------------------------------------------------------------------------- /src/form/formik/FormikEditableList/index.js: -------------------------------------------------------------------------------- 1 | import wrapper from '../../../utils/formik'; 2 | import EditableList from '../../components/EditableList'; 3 | 4 | export default wrapper(EditableList, { 5 | getOnChangeProps: (value) => ({ value: value || [] }), 6 | }); 7 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /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/form/components/Dropdown2/useDrodpownContext.js: -------------------------------------------------------------------------------- 1 | import { createContext, useContext } from 'react'; 2 | 3 | export const DropdownContext = createContext(); 4 | 5 | function useDropdowContext() { 6 | return useContext(DropdownContext); 7 | } 8 | 9 | export default useDropdowContext; 10 | -------------------------------------------------------------------------------- /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/hooks/usePrevious/index.js: -------------------------------------------------------------------------------- 1 | import { useEffect, useRef } from 'react'; 2 | 3 | const usePrevious = (value) => { 4 | const ref = useRef(); 5 | useEffect(() => { 6 | ref.current = value; 7 | }, [value]); 8 | return ref.current; 9 | }; 10 | 11 | /** @component */ 12 | export default usePrevious; 13 | -------------------------------------------------------------------------------- /src/hooks/index.js: -------------------------------------------------------------------------------- 1 | export { default as usePrevious } from './usePrevious'; 2 | export { default as useTimeout } from './useTimeout'; 3 | export { default as useInterval } from './useInterval'; 4 | export { default as useEventListener } from './useEventListener'; 5 | export { default as useComponentSize } from './useComponentSize'; 6 | -------------------------------------------------------------------------------- /src/form/formik/FormikRadio/index.js: -------------------------------------------------------------------------------- 1 | import wrapper from '../../../utils/formik'; 2 | import Radio from '../../components/Radio'; 3 | 4 | export default wrapper(Radio, { 5 | getOnChangeProps: (value, field, form, properties) => ({ 6 | checked: value === properties.value, 7 | value: properties.value, 8 | }), 9 | }); 10 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /cypress/support/component-index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Components App 8 | 9 | 10 |
11 | 12 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /lib/images/arrow_down.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /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/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/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/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/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/form/components/Select/images/arrow_down.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /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 | } -------------------------------------------------------------------------------- /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/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/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/form/components/Radio/Readme.md: -------------------------------------------------------------------------------- 1 | *Themes* 2 | ```js 3 | 8 | 12 | ``` 13 | 14 | ```js 15 | 21 | 26 | ``` 27 | -------------------------------------------------------------------------------- /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/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/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/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/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/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/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 | -------------------------------------------------------------------------------- /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/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/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/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/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/utils/debounce/index.js: -------------------------------------------------------------------------------- 1 | export default (func, wait, immediate) => { 2 | let timeout; 3 | return function debouncer(...args) { 4 | const context = this; 5 | const later = () => { 6 | timeout = null; 7 | if (!immediate) { 8 | func.apply(context, args); 9 | } 10 | }; 11 | const callNow = immediate && !timeout; 12 | clearTimeout(timeout); 13 | timeout = setTimeout(later, wait); 14 | if (callNow) { 15 | func.apply(context, args); 16 | } 17 | }; 18 | }; 19 | -------------------------------------------------------------------------------- /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/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/components/Chart/Readme.md: -------------------------------------------------------------------------------- 1 | ```js 2 | 22 | ``` 23 | -------------------------------------------------------------------------------- /src/form/redux-form/FieldPagination/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | 4 | import Pagination from '../../components/Pagination'; 5 | 6 | function FieldPagination(props) { 7 | const { input, ...rest } = props; 8 | 9 | return ( 10 | 16 | ); 17 | } 18 | 19 | FieldPagination.propTypes = { 20 | input: PropTypes.instanceOf(Object), 21 | }; 22 | 23 | export default FieldPagination; 24 | -------------------------------------------------------------------------------- /src/hooks/useInterval/index.js: -------------------------------------------------------------------------------- 1 | import { useEffect, useRef } from 'react'; 2 | 3 | /** @component */ 4 | export default function useInterval(callback, delay, ...args) { 5 | const savedCallback = useRef(); 6 | 7 | useEffect(() => { 8 | savedCallback.current = callback; 9 | }, [callback]); 10 | 11 | useEffect(() => { 12 | function tick() { 13 | savedCallback.current(...args); 14 | } 15 | if (delay !== null && delay !== undefined) { 16 | const id = setInterval(tick, delay); 17 | return () => clearInterval(id); 18 | } 19 | }, [delay]); 20 | } 21 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | ``` -------------------------------------------------------------------------------- /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/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/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 | -------------------------------------------------------------------------------- /.github/workflows/jira-pr-validator.yaml: -------------------------------------------------------------------------------- 1 | name: Validate PR against Jira 2 | 3 | on: 4 | pull_request: 5 | types: [opened, synchronize, reopened, edited] 6 | 7 | concurrency: 8 | group: jira-validator-${{ github.event.pull_request.number }} 9 | cancel-in-progress: true 10 | 11 | jobs: 12 | validate: 13 | if: ${{ !github.event.pull_request.draft }} 14 | runs-on: ubuntu-latest 15 | steps: 16 | - name: Validate Jira ticket 17 | uses: TykTechnologies/jira-linter@main 18 | with: 19 | jira-base-url: 'https://tyktech.atlassian.net' 20 | jira-api-token: ${{ secrets.JIRA_TOKEN }} 21 | 22 | -------------------------------------------------------------------------------- /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/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/index.css: -------------------------------------------------------------------------------- 1 | @import './common/css/reset.css'; 2 | @import './common/css/variables.css'; 3 | @import './common/css/grid.css'; 4 | @import './common/css/fonts.css'; 5 | @import './common/css/fontawesome/light.css'; 6 | @import './common/css/fontawesome/regular.css'; 7 | @import './common/css/fontawesome/solid.css'; 8 | @import './common/css/fontawesome/fontawesome.css'; 9 | @import './common/css/tykon.css'; 10 | @import './common/css/typography.css'; 11 | @import './common/css/form.css'; 12 | @import './common/css/components.css'; 13 | @import './common/css/layout.css'; 14 | @import './common/css/texts.css'; 15 | @import './utils/css-helpers/helpers.css'; 16 | -------------------------------------------------------------------------------- /src/utils/debounce/Readme.md: -------------------------------------------------------------------------------- 1 | `debounce` "postpones" the execution of a callback after the specified amount of time in milliseconds. 2 | 3 | ```js static 4 | debounce(callback, wait, immediate) 5 | ``` 6 | 7 | If you type in the text input below its value will be logged to the console. 8 | 9 | ```js 10 | import DebounceExample from './styleguidist-example'; 11 | 12 | const [wait, setWait] = React.useState(1000); 13 | <> 14 | 18 | 19 | 20 | ``` -------------------------------------------------------------------------------- /lib/images/drag.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/common/images/drag.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /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/hooks/useTimeout/index.js: -------------------------------------------------------------------------------- 1 | import { useEffect, useRef } from 'react'; 2 | 3 | const useTimeout = (callback, delay) => { 4 | const savedCallback = useRef(); 5 | 6 | useEffect( 7 | () => { 8 | savedCallback.current = callback; 9 | }, 10 | [callback], 11 | ); 12 | 13 | useEffect( 14 | () => { 15 | function tick() { 16 | savedCallback.current(); 17 | } 18 | if (delay !== null) { 19 | const id = setTimeout(tick, delay); 20 | return () => clearTimeout(id); 21 | } 22 | 23 | return () => {}; 24 | }, 25 | [delay], 26 | ); 27 | }; 28 | 29 | /** @component */ 30 | export default useTimeout; 31 | -------------------------------------------------------------------------------- /src/components/RevealPanel/images/drag.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/components/CollapsibleList/js/CollapsibleListItem.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | 4 | function CollapsibleListItem(props) { 5 | const { 6 | className = '', 7 | children, 8 | } = props; 9 | 10 | return ( 11 |
  • 12 | {children} 13 |
  • 14 | ); 15 | } 16 | 17 | CollapsibleListItem.propTypes = { 18 | children: PropTypes.oneOfType([ 19 | PropTypes.arrayOf(PropTypes.node), 20 | PropTypes.node, 21 | PropTypes.element, 22 | PropTypes.string, 23 | ]), 24 | className: PropTypes.string, 25 | }; 26 | 27 | export default CollapsibleListItem; 28 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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/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/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/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/utils/debounce/styleguidist-example.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | 4 | import debounce from './index'; 5 | 6 | function Debounce({ func, wait, immediate }) { 7 | const cbb = (e) => { 8 | console.log(`Debounced log after ${wait}ms:`, e.target.value); 9 | }; 10 | return ( 11 |
    12 | 16 |
    17 | ); 18 | } 19 | 20 | Debounce.propTypes = { 21 | func: PropTypes.func, 22 | wait: PropTypes.number, 23 | immediate: PropTypes.bool, 24 | }; 25 | 26 | export default Debounce; 27 | -------------------------------------------------------------------------------- /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/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/hooks/useEventListener/index.js: -------------------------------------------------------------------------------- 1 | import { useEffect, useRef } from 'react'; 2 | 3 | const useEventListener = (eventName, handler, element) => { 4 | const savedHandler = useRef(); 5 | useEffect(() => { 6 | savedHandler.current = handler; 7 | }, [handler]); 8 | 9 | useEffect(() => { 10 | const isSupported = element?.addEventListener; 11 | if (!isSupported) { 12 | return; 13 | } 14 | 15 | const eventListener = (event) => savedHandler.current(event); 16 | element.addEventListener(eventName, eventListener); 17 | 18 | return () => { 19 | element.removeEventListener(eventName, eventListener); 20 | }; 21 | }, [eventName, element]); 22 | }; 23 | 24 | /** @component */ 25 | export default useEventListener; 26 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /.github/workflows/visor.yaml: -------------------------------------------------------------------------------- 1 | name: Visor 2 | 3 | on: 4 | pull_request: 5 | types: [opened, synchronize] 6 | issues: 7 | types: [opened] 8 | issue_comment: 9 | types: [created] 10 | 11 | permissions: 12 | contents: read 13 | pull-requests: write 14 | issues: write 15 | checks: write 16 | 17 | jobs: 18 | visor: 19 | runs-on: ubuntu-latest 20 | steps: 21 | - name: Checkout code 22 | uses: actions/checkout@v4 23 | - uses: probelabs/visor@main 24 | with: 25 | app-id: ${{ secrets.PROBE_APP_ID }} 26 | private-key: ${{ secrets.PROBE_APP_PRIVATE_KEY }} 27 | installation-id: ${{ secrets.PROBE_APP_INSTALLATION_ID }} 28 | env: 29 | GOOGLE_API_KEY: ${{ secrets.GOOGLE_API_KEY }} 30 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/Toggle/js/ToggleItemWrapper.js: -------------------------------------------------------------------------------- 1 | import React, { forwardRef } from 'react'; 2 | import PropTypes from 'prop-types'; 3 | 4 | import ToggleContext from './ToggleContext'; 5 | import ToggleItem from './ToggleItem'; 6 | 7 | const ToggleItemWrapper = forwardRef(function ToggleItemWrapper({ children, ...rest }, ref) { 8 | return ( 9 | 10 | {(context) => ( 11 | 12 | {children} 13 | 14 | )} 15 | 16 | ); 17 | }); 18 | 19 | ToggleItemWrapper.propTypes = { 20 | children: PropTypes.oneOfType([ 21 | PropTypes.arrayOf(PropTypes.node), 22 | PropTypes.node, 23 | PropTypes.element, 24 | PropTypes.string, 25 | ]), 26 | }; 27 | 28 | export default ToggleItemWrapper; 29 | -------------------------------------------------------------------------------- /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/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/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/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/layout/Row/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | 4 | /** Row component which must be always present as a wrapper for Columns */ 5 | function Row({ 6 | className, 7 | nogutters, 8 | children, 9 | ...rest 10 | }) { 11 | const classes = [ 12 | 'tyk-row', 13 | className, 14 | nogutters && 'no-gutters', 15 | nogutters && 'tyk-row--gutterless', 16 | ].filter(Boolean).join(' '); 17 | 18 | return ( 19 |
    20 | { children } 21 |
    22 | ); 23 | } 24 | 25 | Row.propTypes = { 26 | children: PropTypes.oneOfType([ 27 | PropTypes.element, 28 | PropTypes.node, 29 | ]), 30 | /** Css classes that can be passed to the Row element */ 31 | className: PropTypes.string, 32 | /** Removes all the spaces between column */ 33 | nogutters: PropTypes.bool, 34 | }; 35 | 36 | export default Row; 37 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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/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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/form/components/EditableList2/Header.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | 4 | import Button from '../../../components/Button'; 5 | 6 | function Header({ 7 | label, addButtonName, onAddRow, disabled, readOnly, 8 | }) { 9 | return ( 10 |
    11 | { 12 | label 13 | ? 14 | : null 15 | } 16 | {!disabled && !readOnly && ( 17 | 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/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/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 | } -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /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/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/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/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/form/redux-form/FieldToggle/index.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import { fromJS } from 'immutable'; 4 | 5 | import Toggle from '../../components/Toggle'; 6 | 7 | class FieldToggle extends Component { 8 | constructor(props) { 9 | super(props); 10 | 11 | this.handleOnChange = this.handleOnChange.bind(this); 12 | } 13 | 14 | handleOnChange(value) { 15 | const { input } = this.props; 16 | 17 | input.onChange(fromJS(value)); 18 | } 19 | 20 | render() { 21 | const { children, ...props } = this.props; 22 | 23 | return ( 24 | 29 | {children} 30 | 31 | ); 32 | } 33 | } 34 | 35 | FieldToggle.propTypes = { 36 | children: PropTypes.oneOfType([ 37 | PropTypes.node, 38 | ]), 39 | onChange: PropTypes.func, 40 | input: PropTypes.instanceOf(Object), 41 | }; 42 | 43 | export default FieldToggle; 44 | -------------------------------------------------------------------------------- /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/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/hooks/useComponentSize/index.js: -------------------------------------------------------------------------------- 1 | import { useCallback, useState, useLayoutEffect } from 'react'; 2 | 3 | const getSize = (el) => { 4 | if (!el) { 5 | return { 6 | width: 0, 7 | height: 0, 8 | }; 9 | } 10 | 11 | return { 12 | width: el.offsetWidth, 13 | height: el.offsetHeight, 14 | }; 15 | }; 16 | 17 | const useComponentSize = (ref) => { 18 | const [componentSize, setComponentSize] = useState(getSize(ref ? ref.current : {})); 19 | const handleResize = useCallback(() => { 20 | if (ref.current) { 21 | setComponentSize(getSize(ref.current)); 22 | } 23 | }, [ref]); 24 | 25 | useLayoutEffect(() => { 26 | handleResize(); 27 | 28 | let resizeObserver = new ResizeObserver(() => { 29 | handleResize(); 30 | }); 31 | resizeObserver.observe(ref.current); 32 | 33 | return () => { 34 | resizeObserver.disconnect(ref.current); 35 | resizeObserver = null; 36 | }; 37 | }, [ref.current]); 38 | 39 | return componentSize; 40 | }; 41 | 42 | /** @component */ 43 | export default useComponentSize; 44 | -------------------------------------------------------------------------------- /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/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/form/redux-form/FieldInput/index.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import PropTypes from 'prop-types'; 3 | 4 | import Input from '../../components/Input'; 5 | 6 | class FieldInput extends Component { 7 | getInputError() { 8 | const { meta, validationmessages } = this.props; 9 | const { touched, error, warning } = meta; 10 | let message = null; 11 | 12 | if (touched && error && validationmessages[error]) { 13 | message = validationmessages[error]; 14 | } else if (touched && warning) { 15 | message = 'warning'; 16 | } 17 | 18 | return message; 19 | } 20 | 21 | render() { 22 | const { input, ...rest } = this.props; 23 | 24 | return ( 25 | 31 | ); 32 | } 33 | } 34 | 35 | FieldInput.propTypes = { 36 | meta: PropTypes.instanceOf(Object), 37 | input: PropTypes.instanceOf(Object), 38 | validationmessages: PropTypes.instanceOf(Object), 39 | }; 40 | 41 | export default FieldInput; 42 | -------------------------------------------------------------------------------- /src/typography/Readme.md: -------------------------------------------------------------------------------- 1 | - 2 | 3 | **Headings** 4 | ```js 5 |

    Heading one

    6 |

    Heading two

    7 |

    Heading three

    8 |

    Heading four

    9 |
    Heading five
    10 | ``` 11 | **Colors** 12 | ```js 13 |

    Heading three

    14 |

    Heading three

    15 |

    Heading three

    16 |

    Heading three

    17 |

    Heading three

    18 | ``` 19 | **Dashboard Usage** 20 | ```js 21 |

    H1. Product Page Header

    22 |

    H2. Form Section Header

    23 |

    H3. Name panel header

    24 |

    H4. Sub Panel Header

    25 |
    H5. Titles
    26 |

    p.regular Regular font family paragraph

    27 |

    p.medium Medium font family paragraph

    28 | link medium 29 |
    30 | link bold 31 |
    32 |
    33 |

    Section title

    34 |

    Sub Section title

    35 |
    Section Group title
    36 | ``` -------------------------------------------------------------------------------- /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/form/redux-form/FieldFileInput/index.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import PropTypes from 'prop-types'; 3 | 4 | import FileInput from '../../components/FileInput'; 5 | 6 | class FieldFileInput extends Component { 7 | getInputError() { 8 | const { meta, validationmessages } = this.props; 9 | const { touched, error, warning } = meta; 10 | let message = null; 11 | 12 | if (touched && error && validationmessages[error]) { 13 | message = validationmessages[error]; 14 | } else if (touched && warning) { 15 | message = 'warning'; 16 | } 17 | 18 | return message; 19 | } 20 | 21 | render() { 22 | const { input, ...rest } = this.props; 23 | 24 | return ( 25 | 30 | ); 31 | } 32 | } 33 | 34 | FieldFileInput.propTypes = { 35 | input: PropTypes.instanceOf(Object), 36 | meta: PropTypes.instanceOf(Object), 37 | validationmessages: PropTypes.instanceOf(Object), 38 | }; 39 | 40 | export default FieldFileInput; 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/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/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/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/redux-form/FieldSelectableList/index.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import { fromJS } from 'immutable'; 4 | 5 | import SelectableList from '../../components/SelectableList'; 6 | 7 | class FieldSelectableList extends Component { 8 | constructor(props) { 9 | super(props); 10 | 11 | this.handleOnChange = this.handleOnChange.bind(this); 12 | } 13 | 14 | handleOnChange(value) { 15 | const { input } = this.props; 16 | 17 | input.onChange(fromJS(value)); 18 | } 19 | 20 | render() { 21 | // eslint-disable-next-line no-unused-vars 22 | const { children, ...props } = this.props; 23 | 24 | return ( 25 | 30 | ); 31 | } 32 | } 33 | 34 | FieldSelectableList.propTypes = { 35 | children: PropTypes.oneOfType([ 36 | PropTypes.node, 37 | ]), 38 | onChange: PropTypes.func, 39 | input: PropTypes.instanceOf(Object), 40 | }; 41 | 42 | export default FieldSelectableList; 43 | -------------------------------------------------------------------------------- /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/form/components/Dropdown2/useDropdown.js: -------------------------------------------------------------------------------- 1 | import { 2 | useState, useRef, useCallback, useEffect, 3 | } from 'react'; 4 | 5 | const useDropdown = ({ 6 | splitTrigger, 7 | }) => { 8 | const [isOpen, setIsOpen] = useState(false); 9 | const dropdownRef = useRef(null); 10 | const dropdownListRef = useRef(null); 11 | 12 | const toggle = () => setIsOpen(!isOpen); 13 | 14 | const handleOutsideClick = useCallback((e) => { 15 | const triggerElement = !splitTrigger 16 | ? dropdownRef.current 17 | : dropdownRef.current.querySelector('.dropdown__trigger'); 18 | if ( 19 | isOpen 20 | && !triggerElement.contains(e.target) 21 | && !dropdownListRef.current.contains(e.target) 22 | ) { 23 | setIsOpen(false); 24 | } 25 | }, [isOpen]); 26 | 27 | useEffect(() => { 28 | document.addEventListener('mousedown', handleOutsideClick); 29 | return () => { 30 | document.removeEventListener('mousedown', handleOutsideClick); 31 | }; 32 | }, [handleOutsideClick]); 33 | 34 | return { 35 | isOpen, 36 | toggle, 37 | dropdownRef, 38 | dropdownListRef, 39 | }; 40 | }; 41 | 42 | export default useDropdown; 43 | -------------------------------------------------------------------------------- /src/components/CollapsibleList/CollapsibleList.css: -------------------------------------------------------------------------------- 1 | .tyk-collapsible-list { 2 | width: 100%; 3 | } 4 | 5 | .tyk-collapsible-list__list { 6 | list-style: none; 7 | margin: 0; 8 | padding: 0; 9 | } 10 | 11 | .tyk-collapsible-list__item { 12 | padding: 0; 13 | margin: 0; 14 | } 15 | 16 | .tyk-collapsible-list__item-wrapper { 17 | overflow: hidden; 18 | transition: max-height 0.3s ease-in-out, opacity 0.3s ease-in-out, margin 0.3s ease-in-out; 19 | } 20 | 21 | .tyk-collapsible-list__item-wrapper--visible { 22 | max-height: 1000px; 23 | opacity: 1; 24 | margin-bottom: 0; 25 | } 26 | 27 | .tyk-collapsible-list__item-wrapper--hidden { 28 | max-height: 0; 29 | opacity: 0; 30 | margin-bottom: 0; 31 | pointer-events: none; 32 | } 33 | 34 | .tyk-collapsible-list__item-wrapper--animated.tyk-collapsible-list__item-wrapper--visible { 35 | animation: tykCollapsibleListSlideDown 0.3s ease-in-out; 36 | } 37 | 38 | @keyframes tykCollapsibleListSlideDown { 39 | from { 40 | max-height: 0; 41 | opacity: 0; 42 | transform: translateY(-10px); 43 | } 44 | to { 45 | max-height: 1000px; 46 | opacity: 1; 47 | transform: translateY(0); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/layout/Row/Row.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Row from './index'; 3 | 4 | const classes = { 5 | noGutter: 'no-gutters', 6 | gutterless: 'tyk-row--gutterless', 7 | }; 8 | 9 | const selectors = { 10 | component: '.tyk-row', 11 | }; 12 | 13 | describe('Row', () => { 14 | it('renders the component', () => { 15 | cy.mount() 16 | .get(selectors.component) 17 | .should('exist'); 18 | }); 19 | 20 | it('can have custom class names', () => { 21 | const customClass = 'custom-class'; 22 | cy.mount() 23 | .get(selectors.component) 24 | .should('have.class', customClass); 25 | }); 26 | 27 | it('adds classes that remove gutters', () => { 28 | cy.mount() 29 | .get(selectors.component) 30 | .should('have.class', classes.noGutter) 31 | .and('have.class', classes.gutterless); 32 | }); 33 | 34 | it('renders its children', () => { 35 | const content =
    custom content
    ; 36 | cy.mount({content}) 37 | .get(selectors.component) 38 | .find('#custom-content') 39 | .should('exist'); 40 | }); 41 | }); 42 | -------------------------------------------------------------------------------- /src/form/redux-form/FieldDropdown/index.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import { fromJS } from 'immutable'; 4 | 5 | import Dropdown from '../../components/Dropdown'; 6 | 7 | class FieldDropdown extends Component { 8 | constructor(props) { 9 | super(props); 10 | 11 | this.handleOnChange = this.handleOnChange.bind(this); 12 | } 13 | 14 | handleOnChange(value) { 15 | const { input } = this.props; 16 | const { onChange } = input; 17 | 18 | onChange(fromJS(value)); 19 | } 20 | 21 | render() { 22 | const { 23 | children, 24 | input, 25 | ...rest 26 | } = this.props; 27 | 28 | return ( 29 | 34 | {children} 35 | 36 | ); 37 | } 38 | } 39 | 40 | FieldDropdown.propTypes = { 41 | children: PropTypes.oneOfType([ 42 | PropTypes.arrayOf(PropTypes.node), 43 | PropTypes.node, 44 | PropTypes.element, 45 | PropTypes.string, 46 | ]), 47 | input: PropTypes.instanceOf(Object), 48 | }; 49 | 50 | export default FieldDropdown; 51 | -------------------------------------------------------------------------------- /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/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/form/redux-form/FieldDatePicker/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import { fromJS } from 'immutable'; 4 | 5 | import DatePicker from '../../components/DatePicker'; 6 | 7 | function FormDatePicker(props) { 8 | const { 9 | input, 10 | meta, 11 | validationmessages, 12 | ...rest 13 | } = props; 14 | 15 | const getDatePickerError = () => { 16 | const { touched, error } = meta; 17 | let message = null; 18 | 19 | if (touched && error && validationmessages[error]) { 20 | message = validationmessages[error]; 21 | } 22 | 23 | return message; 24 | }; 25 | 26 | const handleOnChange = (value) => { 27 | const { onChange } = input; 28 | 29 | onChange(fromJS(value)); 30 | }; 31 | 32 | return ( 33 | 39 | ); 40 | } 41 | 42 | FormDatePicker.propTypes = { 43 | meta: PropTypes.instanceOf(Object), 44 | input: PropTypes.instanceOf(Object), 45 | validationmessages: PropTypes.instanceOf(Object), 46 | }; 47 | 48 | export default FormDatePicker; 49 | -------------------------------------------------------------------------------- /src/form/redux-form/FieldCombobox2/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import { fromJS } from 'immutable'; 4 | 5 | import Combobox2 from '../../components/Combobox2'; 6 | 7 | function FieldCombobox2(props) { 8 | const { input, meta, validationmessages } = props; 9 | 10 | const getComboboxError = () => { 11 | const { touched, error, warning } = meta; 12 | let message = null; 13 | 14 | if (touched && error && validationmessages[error]) { 15 | message = validationmessages[error]; 16 | } else if (touched && warning) { 17 | message = 'warning'; 18 | } 19 | return message; 20 | }; 21 | 22 | const handleOnChange = (value) => { 23 | const { onChange } = input; 24 | onChange(fromJS(value)); 25 | }; 26 | 27 | return ( 28 | 34 | ); 35 | } 36 | 37 | FieldCombobox2.propTypes = { 38 | meta: PropTypes.instanceOf(Object), 39 | input: PropTypes.instanceOf(Object), 40 | validationmessages: PropTypes.instanceOf(Object), 41 | }; 42 | 43 | export default FieldCombobox2; 44 | -------------------------------------------------------------------------------- /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/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/layout/Column/Readme.md: -------------------------------------------------------------------------------- 1 | Example of a column that has size 6 (which is half of Row width) 2 | ```jsx 3 | import React from 'react'; 4 | import Column from './index'; 5 | import Row from '../Row'; 6 | 7 | const containerStyle = { 8 | backgroundColor: '#F0F0F0', 9 | }; 10 | const rowStyle = { 11 | marginTop: '20px', 12 | }; 13 | const columnStyle = { 14 | backgroundColor: '#ccc', 15 | padding: '10px', 16 | width: '100%', 17 | }; 18 | 19 | 22 | 25 |
    26 | Content of a column 27 |
    28 |
    29 |
    30 | 31 | ``` 32 | Column that has size 6 and a left gap of 3 33 | ```jsx 34 | import React from 'react'; 35 | import Column from './index'; 36 | import Row from '../Row'; 37 | 38 | const containerStyle = { 39 | backgroundColor: '#F0F0F0', 40 | }; 41 | const rowStyle = { 42 | marginTop: '20px', 43 | }; 44 | const columnStyle = { 45 | backgroundColor: '#ccc', 46 | padding: '10px', 47 | width: '100%', 48 | }; 49 | 50 | 53 | 56 |
    57 | Content of a column 58 |
    59 |
    60 |
    61 | 62 | ``` -------------------------------------------------------------------------------- /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/components/Dropdown2/Readme.md: -------------------------------------------------------------------------------- 1 | Basic Drodpown2: 2 | It has an onChange method that returns the value of the selected item. 3 | 4 | 5 | ```js 6 | console.log(value)}> 7 | Item 1 Item 1 Item 1 Item 1 8 | Item 2 9 | 10 | ``` 11 | 12 | Split Dropdown2 13 | It displays the Dropdown2 trigger as 2 buttons, one for the title and the other for the caret. It has an onChange method that returns the value of the selected item. 14 | 15 | ```js 16 | console.log(value)}> 17 | Item 1 18 | Item 2 19 | 20 | ``` 21 | 22 | Split Dropdown2 23 | It calls onTriggerClick function in case splitTrigger is true, by sending the dropdown value as parameter. 24 | 25 | ```js 26 | console.log(value)} onChange={(value) => console.log(value)}> 27 | Item 1 28 | Item 2 29 | 30 | ``` -------------------------------------------------------------------------------- /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/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/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/layout/Column/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | 4 | function Column({ 5 | children, 6 | align, 7 | className, 8 | offset, 9 | size, 10 | ...rest 11 | }) { 12 | const classes = [ 13 | 'tyk-col', 14 | className, 15 | align && `tyk-col--align-${align}`, 16 | ...size.split(' ').map((cSize) => `tyk-col--${cSize}`), 17 | ...(offset ? offset.split(' ') : []).map((cOffset) => `tyk-col--offset-${cOffset}`), 18 | ].filter(Boolean).join(' '); 19 | 20 | return ( 21 |
    22 | { children } 23 |
    24 | ); 25 | } 26 | 27 | Column.propTypes = { 28 | /** 29 | * This property describes how the column element will be aligned vertically 30 | * within a Row: bottom, center, top 31 | */ 32 | align: PropTypes.string, 33 | /** Css classes that can be passed to the column element */ 34 | className: PropTypes.string, 35 | /** 36 | * Specifies the size of the column within a Row (values must be between 1 - 12) 37 | */ 38 | size: PropTypes.string.isRequired, 39 | /** 40 | * Specifies the left gap a column can have within a Row (values must be between 1 - 12) 41 | */ 42 | offset: PropTypes.string, 43 | children: PropTypes.oneOfType([ 44 | PropTypes.element, 45 | PropTypes.string, 46 | PropTypes.object, 47 | PropTypes.node, 48 | ]), 49 | }; 50 | 51 | export default Column; 52 | -------------------------------------------------------------------------------- /src/form/redux-form/FieldCodeEditor/index.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import { fromJS } from 'immutable'; 4 | 5 | import CodeEditor from '../../components/CodeEditor'; 6 | 7 | class FieldCodeEditor extends Component { 8 | constructor(props) { 9 | super(props); 10 | 11 | this.handleOnChange = this.handleOnChange.bind(this); 12 | } 13 | 14 | handleOnChange(value) { 15 | const { input } = this.prop; 16 | const { onChange } = input; 17 | 18 | onChange(fromJS(value)); 19 | } 20 | 21 | getInputError() { 22 | const { meta, validationmessages } = this.props; 23 | const { touched, error, warning } = meta; 24 | let message = null; 25 | 26 | if (touched && error && validationmessages[error]) { 27 | message = validationmessages[error]; 28 | } else if (touched && warning) { 29 | message = 'warning'; 30 | } 31 | 32 | return message; 33 | } 34 | 35 | render() { 36 | const { input, ...rest } = this.props; 37 | 38 | return ( 39 | 44 | ); 45 | } 46 | } 47 | 48 | FieldCodeEditor.propTypes = { 49 | input: PropTypes.instanceOf(Object), 50 | meta: PropTypes.instanceOf(Object), 51 | validationmessages: PropTypes.instanceOf(Object), 52 | }; 53 | 54 | export default FieldCodeEditor; 55 | -------------------------------------------------------------------------------- /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/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/form/redux-form/FieldEditableList/index.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import { fromJS } from 'immutable'; 4 | 5 | import EditableList from '../../components/EditableList'; 6 | 7 | class FieldEditableList extends Component { 8 | constructor(props) { 9 | super(props); 10 | 11 | this.handleOnChange = this.handleOnChange.bind(this); 12 | } 13 | 14 | handleOnChange(value) { 15 | const { input } = this.props; 16 | const { onChange } = input; 17 | 18 | onChange(fromJS(value)); 19 | } 20 | 21 | getEditableListError() { 22 | const { meta, validationmessages } = this.props; 23 | const { touched, error } = meta; 24 | let message = null; 25 | 26 | if (touched && error && validationmessages[error]) { 27 | message = validationmessages[error]; 28 | } 29 | 30 | return message; 31 | } 32 | 33 | render() { 34 | const { ...props } = this.props; 35 | 36 | return ( 37 | 43 | ); 44 | } 45 | } 46 | 47 | FieldEditableList.propTypes = { 48 | input: PropTypes.instanceOf(Object), 49 | meta: PropTypes.instanceOf(Object), 50 | validationmessages: PropTypes.instanceOf(Object), 51 | }; 52 | 53 | export default FieldEditableList; 54 | -------------------------------------------------------------------------------- /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/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/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 | -------------------------------------------------------------------------------- /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 | ``` -------------------------------------------------------------------------------- /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/form/redux-form/FieldCombobox/index.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import { fromJS } from 'immutable'; 4 | 5 | import Combobox from '../../components/Combobox'; 6 | 7 | class FieldCombobox extends Component { 8 | constructor(props) { 9 | super(props); 10 | 11 | this.handleOnChange = this.handleOnChange.bind(this); 12 | } 13 | 14 | handleOnChange(value) { 15 | const { input } = this.props; 16 | const { onChange } = input; 17 | 18 | onChange(fromJS(value)); 19 | } 20 | 21 | getComboboxError() { 22 | const { meta, validationmessages } = this.props; 23 | const { touched, error, warning } = meta; 24 | let message = null; 25 | 26 | if (touched && error && validationmessages[error]) { 27 | message = validationmessages[error]; 28 | } else if (touched && warning) { 29 | message = 'warning'; 30 | } 31 | 32 | return message; 33 | } 34 | 35 | render() { 36 | const { ...props } = this.props; 37 | 38 | return ( 39 | 45 | ); 46 | } 47 | } 48 | 49 | FieldCombobox.propTypes = { 50 | meta: PropTypes.instanceOf(Object), 51 | input: PropTypes.instanceOf(Object), 52 | validationmessages: PropTypes.instanceOf(Object), 53 | }; 54 | 55 | export default FieldCombobox; 56 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /webpack.component.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | 3 | module.exports = { 4 | output: { 5 | path: path.resolve(__dirname, './'), 6 | filename: '[name].js', 7 | }, 8 | module: { 9 | rules: [ 10 | { 11 | test: /\.js?$/, 12 | include: [ 13 | path.resolve(__dirname, 'src'), 14 | ], 15 | exclude: /node_modules/, 16 | use: [ 17 | '@jsdevtools/coverage-istanbul-loader', 18 | { 19 | loader: 'esbuild-loader', 20 | options: { 21 | loader: 'jsx', 22 | target: 'es2015', 23 | }, 24 | }, 25 | ], 26 | }, 27 | { 28 | test: /\.css$/, 29 | use: [ 30 | 'style-loader', 31 | 'css-loader', 32 | ], 33 | }, 34 | { 35 | test: /\.(ttf|otf|eot|svg|woff(2)?)(\?[a-z0-9]+)?$/, 36 | exclude: [/images/], 37 | type: 'asset/resource', 38 | generator: { 39 | filename: 'fonts/[name][ext]', 40 | }, 41 | }, 42 | { 43 | test: /\.(png|svg|jpg|gif)$/, 44 | type: 'asset/resource', 45 | generator: { 46 | filename: 'images/[name][ext]', 47 | }, 48 | }, 49 | { 50 | test: /worker-.*\.js/, 51 | include: [/node_modules\/ace-build/], 52 | type: 'asset/resource', 53 | }, 54 | ], 55 | }, 56 | devtool: 'source-map', 57 | devServer: { 58 | client: { 59 | overlay: false, 60 | }, 61 | }, 62 | }; 63 | -------------------------------------------------------------------------------- /src/form/redux-form/FieldMultiselect/index.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import { fromJS } from 'immutable'; 4 | 5 | import Multiselect from '../../components/Multiselect'; 6 | 7 | class FieldMultiselect extends Component { 8 | constructor(props) { 9 | super(props); 10 | 11 | this.handleOnChange = this.handleOnChange.bind(this); 12 | } 13 | 14 | handleOnChange(value) { 15 | const { input } = this.props; 16 | const { onChange } = input; 17 | 18 | onChange(fromJS(value)); 19 | } 20 | 21 | getMultiselectError() { 22 | const { meta, validationmessages } = this.props; 23 | const { touched, error, warning } = meta; 24 | let message = null; 25 | 26 | if (touched && error && validationmessages[error]) { 27 | message = validationmessages[error]; 28 | } else if (touched && warning) { 29 | message = 'warning'; 30 | } 31 | 32 | return message; 33 | } 34 | 35 | render() { 36 | const { ...props } = this.props; 37 | 38 | return ( 39 | 45 | ); 46 | } 47 | } 48 | 49 | FieldMultiselect.propTypes = { 50 | input: PropTypes.instanceOf(Object), 51 | meta: PropTypes.instanceOf(Object), 52 | validationmessages: PropTypes.instanceOf(Object), 53 | }; 54 | 55 | export default FieldMultiselect; 56 | -------------------------------------------------------------------------------- /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/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/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/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/form/redux-form/FieldSelect/index.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import { fromJS } from 'immutable'; 4 | 5 | import Select from '../../components/Select'; 6 | 7 | class FieldSelect extends Component { 8 | constructor(props) { 9 | super(props); 10 | 11 | this.handleEvent = this.handleEvent.bind(this); 12 | } 13 | 14 | handleEvent(selectValue) { 15 | const { input } = this.props; 16 | const { onChange, value } = input; 17 | 18 | onChange(fromJS(selectValue !== undefined ? selectValue : value)); 19 | } 20 | 21 | getSelectError() { 22 | const { meta, validationmessages } = this.props; 23 | const { touched, error, warning } = meta; 24 | let message = null; 25 | 26 | if (touched && error && validationmessages[error]) { 27 | message = validationmessages[error]; 28 | } else if (touched && warning) { 29 | message = 'warning'; 30 | } 31 | 32 | return message; 33 | } 34 | 35 | render() { 36 | const { input, ...rest } = this.props; 37 | 38 | return ( 39 | 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/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/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/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/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/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/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/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/form/components/Textarea/Readme.md: -------------------------------------------------------------------------------- 1 | ```js 2 |