├── .github
├── CODEOWNERS
├── ISSUE_TEMPLATE
│ ├── bug_report.yml
│ └── feature_request.yml
└── workflows
│ ├── notify-new-issue.yml
│ ├── notify-reviewers.yml
│ ├── publish-canary.yml
│ ├── publish-next.yml
│ ├── publish.yml
│ └── pull-request.yml
├── .gitignore
├── .storybook
├── .babelrc
├── assets
│ ├── __logo.svg
│ ├── _logo.svg
│ ├── arrow-down.svg
│ ├── browsers-support.svg
│ ├── building-blocks-illustration.svg
│ ├── deprecated.svg
│ ├── experimental.svg
│ ├── logo.svg
│ ├── screen-rotation-icon.svg
│ └── tablet-telephone.svg
├── components
│ ├── DocContainer.jsx
│ └── SidebarLabelWrapper
│ │ ├── SidebarLabelWrapper.js
│ │ └── index.css
├── decorators.js
├── main.js
├── manager-head.html
├── manager.js
├── preview.js
├── public
│ └── favicon.ico
├── softConstructThem.js
├── storybookReset.scss
└── style.css
├── .vscode
└── settings.json
├── CHANGELOG.md
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── configs
├── .babelrc
├── .eslintignore
├── .eslintrc.json
├── .lintstagedrc.json
├── .prettierignore
├── .prettierrc
├── .releaserc.json
├── .stylelintrc.json
├── changelog.config.js
├── commitlint.config.js
├── jest.config.js
├── rollup.config.js
└── tsconfig.json
├── index.js
├── package-lock.json
├── package.json
├── scripts
├── analyzeBundleSize.js
├── build.js
├── copyFiles.js
├── createComponent.js
├── findComponentUsage.js
├── postPublish.js
├── testReport.js
└── utils.js
├── src
├── assets
│ ├── media
│ │ ├── empty-state
│ │ │ ├── greyscale
│ │ │ │ ├── data.svg
│ │ │ │ ├── image.svg
│ │ │ │ ├── message.svg
│ │ │ │ └── search.svg
│ │ │ ├── transparent
│ │ │ │ ├── data.svg
│ │ │ │ ├── image.svg
│ │ │ │ ├── message.svg
│ │ │ │ └── search.svg
│ │ │ ├── with-circles
│ │ │ │ ├── data.svg
│ │ │ │ ├── image.svg
│ │ │ │ └── search.svg
│ │ │ └── without-circles
│ │ │ │ ├── data.svg
│ │ │ │ ├── image.svg
│ │ │ │ ├── message.svg
│ │ │ │ └── search.svg
│ │ └── export
│ │ │ ├── csv.svg
│ │ │ └── xls.svg
│ └── styles
│ │ ├── checkboxRadioSwitcher.scss
│ │ ├── globalStyling.scss
│ │ ├── mixinsAndFunctions.scss
│ │ ├── rangeAndSlider.scss
│ │ ├── rtl.scss
│ │ ├── sharedStyles.scss
│ │ └── variables.scss
├── configs.js
├── hooks
│ ├── index.ts
│ ├── useBodyScroll.js
│ ├── useClick.js
│ ├── useClickOutside.js
│ ├── useDebounce.js
│ ├── useDeviceType.js
│ ├── useDidMount.js
│ ├── useEllipsisDetection
│ │ ├── index.ts
│ │ ├── useEllipsisDetection.mdx
│ │ ├── useEllipsisDetection.test.tsx
│ │ └── useEllipsisDetection.ts
│ ├── useForceUpdate.js
│ ├── useHover.js
│ ├── useImgDownload.js
│ ├── useKeyDown.js
│ ├── useMount.js
│ ├── useMutationObserver.js
│ ├── usePrevious.js
│ ├── useThrottle.js
│ ├── useToggle.js
│ ├── useUpdatableRef.js
│ ├── useUpdate.js
│ ├── useWidth.js
│ └── useWindowSize.js
├── index.mobile.ts
├── index.ts
├── lib
│ ├── atoms
│ │ ├── Avatar
│ │ │ ├── Avatar.scss
│ │ │ ├── Avatar.stories.tsx
│ │ │ ├── Avatar.test.tsx
│ │ │ ├── Avatar.tsx
│ │ │ └── index.tsx
│ │ ├── Badge
│ │ │ ├── Badge.scss
│ │ │ ├── Badge.stories.tsx
│ │ │ ├── Badge.test.tsx
│ │ │ ├── Badge.tsx
│ │ │ └── index.tsx
│ │ ├── BusyLoader
│ │ │ ├── BusyLoader.scss
│ │ │ ├── BusyLoader.stories.tsx
│ │ │ ├── BusyLoader.test.tsx
│ │ │ ├── BusyLoader.tsx
│ │ │ ├── BusyLoaderHolderHOC.tsx
│ │ │ └── index.tsx
│ │ ├── Button
│ │ │ ├── Button.scss
│ │ │ ├── Button.stories.tsx
│ │ │ ├── Button.test.tsx
│ │ │ ├── Button.tsx
│ │ │ └── index.tsx
│ │ ├── Divider
│ │ │ ├── Divider.scss
│ │ │ ├── Divider.stories.tsx
│ │ │ ├── Divider.test.tsx
│ │ │ ├── Divider.tsx
│ │ │ └── index.tsx
│ │ ├── Empty
│ │ │ ├── Empty.scss
│ │ │ ├── Empty.stories.tsx
│ │ │ ├── Empty.test.tsx
│ │ │ ├── Empty.tsx
│ │ │ ├── index.tsx
│ │ │ └── utils.ts
│ │ ├── Icon
│ │ │ ├── index.js
│ │ │ ├── index.mobile.js
│ │ │ └── index.scss
│ │ ├── Image
│ │ │ ├── Image.scss
│ │ │ ├── Image.stories.tsx
│ │ │ ├── Image.test.tsx
│ │ │ ├── Image.tsx
│ │ │ └── index.tsx
│ │ ├── ImagePreview
│ │ │ ├── ImagePreview.scss
│ │ │ ├── ImagePreview.stories.tsx
│ │ │ ├── ImagePreview.test.tsx
│ │ │ ├── ImagePreview.tsx
│ │ │ ├── ImagePreviewHOC.tsx
│ │ │ ├── Magnifier.tsx
│ │ │ └── index.tsx
│ │ ├── KeyValue
│ │ │ ├── KeyValue.scss
│ │ │ ├── KeyValue.stories.tsx
│ │ │ ├── KeyValue.test.tsx
│ │ │ ├── KeyValue.tsx
│ │ │ └── index.tsx
│ │ ├── Label
│ │ │ ├── index.js
│ │ │ ├── index.mobile.js
│ │ │ └── index.scss
│ │ ├── LinkButton
│ │ │ ├── LinkButton.scss
│ │ │ ├── LinkButton.stories.tsx
│ │ │ ├── LinkButton.test.tsx
│ │ │ ├── LinkButton.tsx
│ │ │ └── index.tsx
│ │ ├── ModuleTitle
│ │ │ ├── index.js
│ │ │ └── index.scss
│ │ ├── Option
│ │ │ ├── index.js
│ │ │ └── index.scss
│ │ ├── Paper
│ │ │ ├── index.js
│ │ │ └── index.scss
│ │ ├── Popover
│ │ │ ├── index.js
│ │ │ └── index.scss
│ │ ├── PopoverV2
│ │ │ ├── index.js
│ │ │ └── index.scss
│ │ ├── Portal
│ │ │ └── index.js
│ │ ├── QRCode
│ │ │ └── index.js
│ │ ├── Radio
│ │ │ ├── index.js
│ │ │ └── index.mobile.js
│ │ ├── Rating
│ │ │ ├── DefaultSvg.tsx
│ │ │ ├── Rating.scss
│ │ │ ├── Rating.stories.tsx
│ │ │ ├── Rating.test.tsx
│ │ │ ├── Rating.tsx
│ │ │ └── index.tsx
│ │ ├── Scrollbar
│ │ │ ├── index.js
│ │ │ └── index.scss
│ │ ├── SkeletonLoader
│ │ │ ├── index.js
│ │ │ └── index.scss
│ │ ├── Switcher
│ │ │ ├── index.js
│ │ │ ├── index.mobile.js
│ │ │ └── index.scss
│ │ ├── TextLink
│ │ │ └── index.js
│ │ ├── Time
│ │ │ ├── index.js
│ │ │ └── index.scss
│ │ └── Title
│ │ │ ├── index.js
│ │ │ └── index.scss
│ ├── molecules
│ │ ├── AdvancedSearch
│ │ │ ├── Content.js
│ │ │ ├── FilterList.js
│ │ │ ├── ListElementWithCheckbox.js
│ │ │ ├── SearchResult.js
│ │ │ ├── SearchResultRow.js
│ │ │ ├── SkeletonSet.js
│ │ │ ├── index.js
│ │ │ └── index.scss
│ │ ├── Alert
│ │ │ ├── index.js
│ │ │ ├── index.mobile.js
│ │ │ └── index.scss
│ │ ├── Breadcrumb
│ │ │ ├── index.js
│ │ │ ├── index.scss
│ │ │ └── item.js
│ │ ├── Card
│ │ │ ├── Col.js
│ │ │ ├── Menu.js
│ │ │ ├── index.js
│ │ │ └── index.scss
│ │ ├── Charts
│ │ │ ├── AreaChart
│ │ │ │ ├── index.js
│ │ │ │ └── index.scss
│ │ │ ├── BarChart
│ │ │ │ ├── index.js
│ │ │ │ └── index.scss
│ │ │ ├── ColumnChart
│ │ │ │ ├── index.js
│ │ │ │ └── index.scss
│ │ │ ├── ColumnRangeChart
│ │ │ │ ├── index.js
│ │ │ │ └── style.scss
│ │ │ ├── DalColumnChart
│ │ │ │ ├── index.js
│ │ │ │ └── index.scss
│ │ │ ├── DonutChart
│ │ │ │ ├── index.js
│ │ │ │ └── index.scss
│ │ │ ├── FunnelChart
│ │ │ │ ├── index.js
│ │ │ │ └── index.scss
│ │ │ ├── HeatMapChart
│ │ │ │ ├── index.js
│ │ │ │ └── index.scss
│ │ │ ├── Legend
│ │ │ │ ├── index.js
│ │ │ │ └── styles.scss
│ │ │ ├── LineChart
│ │ │ │ ├── index.js
│ │ │ │ └── index.scss
│ │ │ ├── MapChart
│ │ │ │ ├── IconButton.js
│ │ │ │ ├── index.js
│ │ │ │ └── index.scss
│ │ │ ├── PieChart
│ │ │ │ ├── index.js
│ │ │ │ └── index.scss
│ │ │ ├── ScatterChart
│ │ │ │ ├── index.js
│ │ │ │ └── index.scss
│ │ │ ├── StackedBarChart
│ │ │ │ ├── index.js
│ │ │ │ └── index.scss
│ │ │ ├── StackedColumnChart
│ │ │ │ ├── index.js
│ │ │ │ └── index.scss
│ │ │ ├── TreeMapChart
│ │ │ │ ├── index.js
│ │ │ │ └── index.scss
│ │ │ ├── index.js
│ │ │ └── index.scss
│ │ ├── Checkbox
│ │ │ ├── index.js
│ │ │ └── index.mobile.js
│ │ ├── Collapse
│ │ │ ├── Collapse.js
│ │ │ ├── Panel.js
│ │ │ ├── index.js
│ │ │ ├── index.scss
│ │ │ └── utils.js
│ │ ├── ColorPicker
│ │ │ ├── index.js
│ │ │ └── index.scss
│ │ ├── ComboBox
│ │ │ ├── TagWrapper
│ │ │ │ ├── index.js
│ │ │ │ └── index.scss
│ │ │ ├── config.js
│ │ │ ├── index.js
│ │ │ └── index.scss
│ │ ├── Copy
│ │ │ ├── Copy.scss
│ │ │ ├── Copy.stories.tsx
│ │ │ ├── Copy.test.tsx
│ │ │ ├── Copy.tsx
│ │ │ └── index.tsx
│ │ ├── Counter
│ │ │ ├── index.js
│ │ │ ├── index.mobile.js
│ │ │ └── index.scss
│ │ ├── DatePickerInput
│ │ │ ├── DateInput.js
│ │ │ ├── DateRangeInput.js
│ │ │ ├── index.js
│ │ │ └── index.scss
│ │ ├── ExtendedInput
│ │ │ ├── index.js
│ │ │ ├── index.mobile.js
│ │ │ └── index.scss
│ │ ├── Grid
│ │ │ ├── col.js
│ │ │ ├── index.js
│ │ │ ├── index.mobile.js
│ │ │ ├── index.scss
│ │ │ ├── row.js
│ │ │ └── utils.js
│ │ ├── Holder
│ │ │ ├── index.js
│ │ │ └── index.scss
│ │ ├── InteractiveWidget
│ │ │ ├── InteractiveWidget.scss
│ │ │ ├── InteractiveWidget.stories.tsx
│ │ │ ├── InteractiveWidget.test.tsx
│ │ │ ├── InteractiveWidget.tsx
│ │ │ ├── InteractiveWidgetIcon.tsx
│ │ │ └── index.tsx
│ │ ├── Menu
│ │ │ ├── index.js
│ │ │ ├── index.scss
│ │ │ ├── item.js
│ │ │ └── utils.js
│ │ ├── MobileNavigation
│ │ │ ├── index.js
│ │ │ └── index.scss
│ │ ├── MobilePopup
│ │ │ ├── Menu.js
│ │ │ ├── index.js
│ │ │ └── index.scss
│ │ ├── Modal
│ │ │ ├── index.js
│ │ │ └── index.scss
│ │ ├── NavigationMenu
│ │ │ ├── Content.js
│ │ │ ├── index.js
│ │ │ ├── index.scss
│ │ │ └── utils.js
│ │ ├── Notification
│ │ │ ├── index.js
│ │ │ ├── index.mobile.js
│ │ │ └── index.scss
│ │ ├── Overlay
│ │ │ ├── index.js
│ │ │ └── index.scss
│ │ ├── Pagination
│ │ │ ├── index.js
│ │ │ ├── index.mobile.js
│ │ │ └── index.scss
│ │ ├── Products
│ │ │ ├── index.js
│ │ │ └── index.scss
│ │ ├── Profile
│ │ │ ├── Languages
│ │ │ │ ├── flags
│ │ │ │ │ ├── de.svg
│ │ │ │ │ ├── en.svg
│ │ │ │ │ ├── es.svg
│ │ │ │ │ ├── flagsIcons.js
│ │ │ │ │ ├── fr.svg
│ │ │ │ │ ├── hi.svg
│ │ │ │ │ ├── ko.svg
│ │ │ │ │ ├── pt.svg
│ │ │ │ │ ├── ro.svg
│ │ │ │ │ ├── ru.svg
│ │ │ │ │ ├── tr.svg
│ │ │ │ │ └── zh.svg
│ │ │ │ └── languagesDataModel.js
│ │ │ ├── Partners.js
│ │ │ ├── ProfileModule.js
│ │ │ ├── index.js
│ │ │ └── index.scss
│ │ ├── Progress
│ │ │ ├── index.js
│ │ │ └── index.scss
│ │ ├── RadioGroup
│ │ │ ├── index.js
│ │ │ └── index.mobile.js
│ │ ├── Range
│ │ │ └── index.js
│ │ ├── Search
│ │ │ └── index.js
│ │ ├── Section
│ │ │ ├── index.js
│ │ │ └── index.scss
│ │ ├── Slider
│ │ │ └── index.js
│ │ ├── Status
│ │ │ ├── index.js
│ │ │ └── index.scss
│ │ ├── Steps
│ │ │ ├── DetailedView.js
│ │ │ ├── Step.js
│ │ │ ├── Steps.js
│ │ │ ├── index.js
│ │ │ └── index.scss
│ │ ├── SuggestionList
│ │ │ ├── detectPosition.js
│ │ │ ├── index.js
│ │ │ └── index.scss
│ │ ├── Tabs
│ │ │ ├── Tab.js
│ │ │ ├── Tabs.js
│ │ │ ├── index.js
│ │ │ └── index.scss
│ │ ├── Tag
│ │ │ ├── index.js
│ │ │ └── index.scss
│ │ ├── Textarea
│ │ │ ├── index.js
│ │ │ └── index.scss
│ │ ├── TimePicker
│ │ │ ├── Popover
│ │ │ │ └── index.js
│ │ │ ├── index.js
│ │ │ └── index.scss
│ │ ├── Timeline
│ │ │ ├── index.js
│ │ │ ├── index.scss
│ │ │ ├── item.js
│ │ │ └── item.scss
│ │ ├── Tooltip
│ │ │ ├── Tooltip.scss
│ │ │ ├── Tooltip.stories.tsx
│ │ │ ├── Tooltip.test.tsx
│ │ │ ├── Tooltip.tsx
│ │ │ └── index.tsx
│ │ ├── Uploader
│ │ │ ├── index.js
│ │ │ ├── index.scss
│ │ │ ├── uploadUtils.js
│ │ │ ├── uploadView
│ │ │ │ ├── index.js
│ │ │ │ └── index.scss
│ │ │ └── uploadedItem
│ │ │ │ ├── Preview
│ │ │ │ ├── index.js
│ │ │ │ └── index.scss
│ │ │ │ ├── index.js
│ │ │ │ └── index.scss
│ │ ├── ValidatableElements
│ │ │ ├── Elements
│ │ │ │ ├── ValidatableCheckbox.js
│ │ │ │ ├── ValidatableDatePicker.js
│ │ │ │ ├── ValidatableDropdown.js
│ │ │ │ ├── ValidatableMultiSelectDropdown.js
│ │ │ │ ├── ValidatableNumberInput.js
│ │ │ │ ├── ValidatableRadio.js
│ │ │ │ ├── ValidatableSwitcher.js
│ │ │ │ ├── ValidatableTextInput.js
│ │ │ │ ├── ValidatableTimeInput.js
│ │ │ │ ├── ValidatableUploader.js
│ │ │ │ └── index.mobile.js
│ │ │ └── index.js
│ │ └── Widget
│ │ │ ├── index.js
│ │ │ └── index.scss
│ ├── organisms
│ │ ├── ActionableList
│ │ │ ├── Row.js
│ │ │ ├── RowContent.js
│ │ │ ├── config.js
│ │ │ ├── index.js
│ │ │ └── index.scss
│ │ ├── CardList
│ │ │ ├── DefaultCardList
│ │ │ │ ├── index.js
│ │ │ │ └── index.scss
│ │ │ ├── WrappedCardList
│ │ │ │ ├── PaperWrapper
│ │ │ │ │ └── index.js
│ │ │ │ ├── WithTitle
│ │ │ │ │ └── index.js
│ │ │ │ └── index.js
│ │ │ └── index.js
│ │ ├── CheckboxGroup
│ │ │ ├── index.js
│ │ │ └── index.mobile.js
│ │ ├── CheckboxGroupWithSearch
│ │ │ ├── index.js
│ │ │ └── index.scss
│ │ ├── DateFilter
│ │ │ ├── index.js
│ │ │ └── index.scss
│ │ ├── DatePicker
│ │ │ ├── Calendar
│ │ │ │ ├── Body.js
│ │ │ │ ├── Footer.js
│ │ │ │ ├── Header.js
│ │ │ │ └── index.js
│ │ │ ├── Context
│ │ │ │ ├── configs.js
│ │ │ │ └── index.js
│ │ │ ├── DatePicker.js
│ │ │ ├── Days
│ │ │ │ ├── Day.js
│ │ │ │ ├── Days.js
│ │ │ │ └── index.js
│ │ │ ├── MonthPicker.js
│ │ │ ├── Months
│ │ │ │ └── index.js
│ │ │ ├── RangeOptions
│ │ │ │ ├── RangeOptions.js
│ │ │ │ ├── index.js
│ │ │ │ └── options.js
│ │ │ ├── RangePicker.js
│ │ │ ├── TimeInput
│ │ │ │ └── index.js
│ │ │ ├── WeekPicker.js
│ │ │ ├── Years
│ │ │ │ └── index.js
│ │ │ ├── index.js
│ │ │ ├── index.scss
│ │ │ └── utils
│ │ │ │ ├── addTime.js
│ │ │ │ ├── disableUtils.js
│ │ │ │ ├── getCalendarDays.js
│ │ │ │ ├── getCalendarMonths.js
│ │ │ │ ├── getCalendarYears.js
│ │ │ │ ├── getRange.js
│ │ │ │ └── index.js
│ │ ├── Drawer
│ │ │ ├── index.js
│ │ │ └── index.scss
│ │ ├── Dropdown
│ │ │ ├── MultipleSelect.js
│ │ │ ├── SingleSelect.js
│ │ │ ├── index.js
│ │ │ └── index.scss
│ │ ├── Editor
│ │ │ ├── emojis.js
│ │ │ ├── index.js
│ │ │ ├── index.scss
│ │ │ └── toolbarConfig.js
│ │ ├── Form
│ │ │ ├── FormableHOC.js
│ │ │ ├── Formables
│ │ │ │ ├── FormContainer.js
│ │ │ │ ├── FormableCheckbox.js
│ │ │ │ ├── FormableDatePicker.js
│ │ │ │ ├── FormableDropdown.js
│ │ │ │ ├── FormableEditor.js
│ │ │ │ ├── FormableMultiSelectDropdown.js
│ │ │ │ ├── FormableNumberInput.js
│ │ │ │ ├── FormableRadio.js
│ │ │ │ ├── FormableSwitcher.js
│ │ │ │ ├── FormableTextInput.js
│ │ │ │ └── FormableUploader.js
│ │ │ ├── index.js
│ │ │ ├── index.scss
│ │ │ └── utils
│ │ │ │ └── context
│ │ │ │ └── index.js
│ │ ├── Overspread
│ │ │ ├── index.js
│ │ │ └── index.scss
│ │ ├── RichEditor
│ │ │ ├── RichEditor.js
│ │ │ ├── config.js
│ │ │ ├── index.js
│ │ │ └── index.scss
│ │ ├── SearchWithDropdown
│ │ │ ├── index.js
│ │ │ └── index.scss
│ │ ├── Table
│ │ │ ├── Footer
│ │ │ │ ├── index.js
│ │ │ │ ├── index.scss
│ │ │ │ └── item.js
│ │ │ ├── Header
│ │ │ │ ├── index.js
│ │ │ │ ├── index.scss
│ │ │ │ ├── item.js
│ │ │ │ └── resize.js
│ │ │ ├── Row
│ │ │ │ ├── Nested
│ │ │ │ │ ├── body.js
│ │ │ │ │ ├── header.js
│ │ │ │ │ ├── index.js
│ │ │ │ │ └── index.scss
│ │ │ │ ├── actionBar.js
│ │ │ │ ├── actionsWrapper.js
│ │ │ │ ├── col.js
│ │ │ │ └── index.js
│ │ │ ├── index.js
│ │ │ ├── index.scss
│ │ │ └── utils
│ │ │ │ ├── arrayReorder.js
│ │ │ │ ├── getColumnInfo.js
│ │ │ │ ├── getOffsetValues.js
│ │ │ │ ├── hasStickyElemens.js
│ │ │ │ ├── index.js
│ │ │ │ ├── itemTypes.js
│ │ │ │ ├── observeElementResize.js
│ │ │ │ ├── sortHandler.js
│ │ │ │ ├── stickyInfo.js
│ │ │ │ └── useSortConfigs.js
│ │ ├── TableCompositions
│ │ │ ├── Combo
│ │ │ │ ├── index.js
│ │ │ │ └── index.scss
│ │ │ ├── Export
│ │ │ │ ├── Item.js
│ │ │ │ ├── index.js
│ │ │ │ └── index.scss
│ │ │ ├── Header
│ │ │ │ ├── index.js
│ │ │ │ └── index.scss
│ │ │ ├── Pagination
│ │ │ │ ├── index.js
│ │ │ │ └── index.scss
│ │ │ ├── Title
│ │ │ │ └── index.js
│ │ │ ├── Wrapped
│ │ │ │ ├── container.js
│ │ │ │ ├── header.js
│ │ │ │ ├── index.js
│ │ │ │ ├── pagination.js
│ │ │ │ └── title.js
│ │ │ ├── index.js
│ │ │ └── utils
│ │ │ │ ├── Export
│ │ │ │ └── index.js
│ │ │ │ ├── PaginationSelector
│ │ │ │ ├── index.js
│ │ │ │ └── index.scss
│ │ │ │ ├── PaperWrapper
│ │ │ │ └── index.js
│ │ │ │ ├── WithHeader
│ │ │ │ ├── index.js
│ │ │ │ └── index.scss
│ │ │ │ ├── WithTitle
│ │ │ │ └── index.js
│ │ │ │ └── index.js
│ │ ├── Toaster
│ │ │ ├── index.js
│ │ │ └── index.scss
│ │ └── TransferList
│ │ │ ├── Container
│ │ │ ├── Buttons.js
│ │ │ ├── Item.js
│ │ │ ├── index.js
│ │ │ └── index.scss
│ │ │ ├── Element
│ │ │ ├── index.js
│ │ │ └── index.scss
│ │ │ ├── constants.js
│ │ │ ├── index.js
│ │ │ ├── index.scss
│ │ │ └── utils.js
│ └── providers
│ │ └── GeneUIProvider
│ │ └── index.js
├── types
│ └── index.ts
├── utils
│ ├── callAfterDelay.js
│ ├── checkTimeValidation.js
│ ├── configs
│ │ └── tableConfigs.js
│ ├── copyToClipboard.js
│ ├── dateFormatChecker.js
│ ├── dateValidation.js
│ ├── debounce.js
│ ├── guid.js
│ ├── index.js
│ ├── indexof.js
│ ├── localization.js
│ ├── logger.js
│ └── timeValidation.js
└── wrappers
│ ├── dayjsWithPlugins.js
│ └── index.js
├── stories
├── assets
│ └── storybook.globals.js
├── atoms
│ ├── Icon
│ │ ├── Icon.stories.jsx
│ │ └── Icon.stories.scss
│ ├── Label
│ │ └── LabelValue.stories.jsx
│ ├── ModuleTitle
│ │ ├── ModuleTitle.stories.jsx
│ │ └── data.js
│ ├── Option
│ │ └── Option.stories.jsx
│ ├── Paper
│ │ ├── Paper.stories.jsx
│ │ └── index.scss
│ ├── Popover
│ │ └── Popover.stories.jsx
│ ├── QRCode
│ │ └── QRCode.stories.jsx
│ ├── Radio
│ │ └── Radio.stories.jsx
│ ├── Scrollbar
│ │ └── Scrollbar.stories.jsx
│ ├── Skeleton
│ │ ├── Skeleton.stories.jsx
│ │ └── index.scss
│ ├── Switcher
│ │ └── Switcher.stories.jsx
│ ├── TextLink
│ │ └── TextLink.stories.jsx
│ ├── Time
│ │ └── Time.stories.jsx
│ └── Title
│ │ └── Title.stories.jsx
├── changelog.mdx
├── charts
│ ├── AreaChart.stories.jsx
│ ├── BarChart.stories.jsx
│ ├── ColumnChart.stories.jsx
│ ├── ColumnRange.stories.jsx
│ ├── DalColumnChart.stories.jsx
│ ├── DonutChart.stories.jsx
│ ├── FunnelChart.stories.jsx
│ ├── HeatMapChart.stories.jsx
│ ├── LineChart.stories.jsx
│ ├── Map
│ │ ├── data.js
│ │ ├── regionData.js
│ │ └── woldMapData.js
│ ├── MapChart.stories.jsx
│ ├── PieChart.stories.jsx
│ ├── ScatterChart.stories.jsx
│ ├── StackedBarChart.stories.jsx
│ ├── StackedColumnChart.stories.jsx
│ ├── TreeMapChart.stories.jsx
│ ├── data.js
│ └── treeMapData.js
├── gettingStarted.mdx
├── index.stories.js
├── introduction.mdx
├── molecules
│ ├── AdvancedSearch
│ │ ├── AdvancedSearch.stories.jsx
│ │ └── data.js
│ ├── Alert
│ │ └── Alert.stories.jsx
│ ├── Breadcrumb
│ │ ├── Breadcrumb.stories.jsx
│ │ └── data.js
│ ├── Card
│ │ └── Card.stories.jsx
│ ├── Checkbox
│ │ └── Checkbox.stories.jsx
│ ├── Collapse
│ │ └── Collapse.stories.jsx
│ ├── ColorPicker
│ │ └── ColorPicker.stories.jsx
│ ├── ComboBox
│ │ ├── ComboBox.stories.jsx
│ │ └── data.js
│ ├── Counter
│ │ └── Counter.stories.jsx
│ ├── DatePickerInput
│ │ └── DatePicker.stories.jsx
│ ├── ExtendedInput
│ │ └── ExtendedInput.stories.jsx
│ ├── FileUpload
│ │ └── FileUpload.stories.jsx
│ ├── Grid
│ │ ├── Grid.stories.jsx
│ │ └── index.scss
│ ├── Holder
│ │ ├── Holder.stories.jsx
│ │ └── index.scss
│ ├── ImageUpload
│ │ └── ImageUpload.stories.jsx
│ ├── Menu
│ │ ├── Menu.stories.jsx
│ │ └── data.js
│ ├── MobileNavigation
│ │ ├── MobileNavigation.stories.jsx
│ │ └── data.js
│ ├── MobilePopup
│ │ ├── MobilePopup.stories.jsx
│ │ └── data.js
│ ├── Modal
│ │ └── Modal.stories.jsx
│ ├── NavigationMenu
│ │ ├── NavigationMenu.stories.jsx
│ │ └── data.js
│ ├── Notification
│ │ └── Notification.stories.jsx
│ ├── Overlay
│ │ └── Overlay.stories.jsx
│ ├── Pagination
│ │ └── Pagination.stories.jsx
│ ├── Products
│ │ ├── Products.stories.jsx
│ │ └── data.js
│ ├── Profile
│ │ ├── Profile.stories.jsx
│ │ ├── br.svg
│ │ └── data.js
│ ├── Progress
│ │ └── Progress.stories.jsx
│ ├── RadioGroup
│ │ ├── RadioGroup.stories.jsx
│ │ └── data.js
│ ├── Range
│ │ └── Range.stories.jsx
│ ├── Search
│ │ └── Search.stories.jsx
│ ├── Section
│ │ └── Section.stories.jsx
│ ├── Slider
│ │ └── Slider.stories.jsx
│ ├── Status
│ │ └── Status.stories.jsx
│ ├── Steps
│ │ └── Steps.stories.jsx
│ ├── Tabs
│ │ ├── Tabs.stories.jsx
│ │ └── index.scss
│ ├── Tag
│ │ └── Tag.stories.jsx
│ ├── Textarea
│ │ ├── TextArea.stories.jsx
│ │ └── data.js
│ ├── TimePicker
│ │ └── TimePicker.stories.jsx
│ ├── Timeline
│ │ └── Timeline.stories.jsx
│ ├── ValidatableElements
│ │ └── ValidatableElements.stories.jsx
│ └── Widget
│ │ └── Widget.stories.jsx
├── organisms
│ ├── ActionableList
│ │ ├── ActionableList.stories.jsx
│ │ └── data.js
│ ├── CardList
│ │ ├── CardList.stories.jsx
│ │ └── data.js
│ ├── CheckboxGroup
│ │ └── CheckboxGroup.stories.jsx
│ ├── CheckboxGroupWithSearch
│ │ └── CheckboxGroupWithSearch.stories.jsx
│ ├── DateFilter
│ │ ├── DataFilter.stories.jsx
│ │ └── style.scss
│ ├── DatePicker
│ │ └── DatePicker.stories.jsx
│ ├── Drawer
│ │ ├── Drawer.stories.jsx
│ │ └── data.js
│ ├── Dropdown
│ │ ├── Dropdown.stories.jsx
│ │ └── data.js
│ ├── Editor
│ │ └── Editor.stories.jsx
│ ├── Form
│ │ ├── Form.stories.jsx
│ │ └── style.scss
│ ├── Overspread
│ │ └── Overspread.stories.jsx
│ ├── RichEditor
│ │ ├── RichEditor.stories.jsx
│ │ └── store.js
│ ├── SearchWithDropdown
│ │ └── SearchWithDropdown.stories.jsx
│ ├── Table
│ │ ├── Table.stories.jsx
│ │ ├── example.js
│ │ └── example2.js
│ ├── Toaster
│ │ └── Toaster.stories.jsx
│ └── TransferList
│ │ └── TransferList.stories.jsx
└── utils
│ ├── ChartAnimation.js
│ ├── assets
│ └── prism-custom-theme.scss
│ ├── index.js
│ ├── knobs.js
│ └── propTables
│ ├── ButtonProp.js
│ ├── CardProp.js
│ ├── CheckboxProp.js
│ ├── ComboTableProp.js
│ ├── DateMonthPickerProp.js
│ ├── DatePickerProp.js
│ ├── DateRangePickerProp.js
│ ├── DateWeekPickerProp.js
│ ├── ExtendedInputProp.js
│ ├── HeaderTableProp.js
│ ├── MenuProp.js
│ ├── PaperProp.js
│ ├── PopoverProp.js
│ ├── RadioProp.js
│ ├── ScrollbarProp.js
│ ├── StepsProp.js
│ ├── SwitcherProp.js
│ ├── TitleTableProp.js
│ ├── ToasterProp.js
│ ├── index.js
│ └── validateElements
│ ├── ValidableDatePickerProp.js
│ ├── ValidatableCheckbox.js
│ ├── ValidatableNumberinput.js
│ ├── ValidatableRadio.js
│ └── ValidatableTextInputProp.js
└── tests
├── __mocks__
└── svg.js
├── helpers.ts
└── setup.ts
/.github/CODEOWNERS:
--------------------------------------------------------------------------------
1 | # This file is define code owners of the repository, more details about the GitHub feature here https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners
2 |
3 | * @hamikhambardzumyan @GaroGabrielyan @AregSoft @NairaMisakyan @NarekArshakyan
4 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.yml:
--------------------------------------------------------------------------------
1 | name: Feature request 💡
2 | description: >-
3 | Use this template to propose new features.
4 | title: '[Feat]: '
5 | labels:
6 | - phase / exploring
7 | - type / feature
8 | body:
9 | - type: input
10 | id: component
11 | attributes:
12 | label: Component
13 | description: Write the component name issue is related with.
14 | - type: textarea
15 | id: problem
16 | attributes:
17 | label: Is your feature request related to a problem? Please describe.
18 | description: >-
19 | A clear and concise description of the problem. E.g. I'm always
20 | frustrated when [...]
21 | - type: textarea
22 | id: describe
23 | attributes:
24 | label: Describe the solution you'd like
25 | description: A clear and concise description of what you want to happen.
26 | validations:
27 | required: true
28 | - type: textarea
29 | id: alternatives
30 | attributes:
31 | label: Describe alternatives you've considered
32 | description: Any alternative solutions or features you've considered.
33 | - type: dropdown
34 | id: help
35 | attributes:
36 | label: Are you able to assist to bring the feature to reality?
37 | options:
38 | - 'no'
39 | - 'yes'
40 | validations:
41 | required: true
42 | - type: textarea
43 | id: context
44 | attributes:
45 | label: Additional context
46 | description: Add any other context, screenshots, or already existing solutions about the feature request here.
47 |
--------------------------------------------------------------------------------
/.github/workflows/notify-new-issue.yml:
--------------------------------------------------------------------------------
1 | name: Notify New Issue Opened
2 | on:
3 | issues:
4 | types:
5 | - opened
6 | jobs:
7 | send_notification:
8 | runs-on: ubuntu-latest
9 | steps:
10 | - name: 🔔 Send Notification
11 | env:
12 | INTERNAL_NOTIFICATION_CHANNEL_API_ENDPOINT: ${{ secrets.INTERNAL_NOTIFICATION_CHANNEL_API_ENDPOINT }}
13 | run: |
14 | ISSUE_TITLE="${{ github.event.issue.title }}"
15 | ISSUE_LINK=${{ github.event.issue.html_url }}
16 | ISSUE_AUTHOR=${{ github.event.issue.user.login }}
17 |
18 | MESSAGE="@channel\n**New Issue Opened**\nAuthor: $ISSUE_AUTHOR\nTitle: $ISSUE_TITLE\nLink: $ISSUE_LINK"
19 |
20 | curl -X POST -H "Content-Type: application/json" -d "{\"text\": \"$MESSAGE\", \"username\": \"GitHub\", \"icon_url\": \"https://github.githubassets.com/favicons/favicon.png\"}" $INTERNAL_NOTIFICATION_CHANNEL_API_ENDPOINT
21 |
--------------------------------------------------------------------------------
/.github/workflows/notify-reviewers.yml:
--------------------------------------------------------------------------------
1 | name: Notify Reviewers
2 | on:
3 | pull_request:
4 | branches: ["release/*"]
5 | jobs:
6 | send_notification:
7 | runs-on: ubuntu-latest
8 | steps:
9 | - name: Send Notification
10 | env:
11 | INTERNAL_NOTIFICATION_CHANNEL_API_ENDPOINT: ${{ secrets.INTERNAL_NOTIFICATION_CHANNEL_API_ENDPOINT }}
12 | run: |
13 | PR_ID=${{ github.event.pull_request.number }}
14 | PR_URL=${{ github.event.pull_request.html_url }}
15 | PR_AUTHOR=${{ github.event.pull_request.user.login }}
16 | REVIEWERS="${{ join(github.event.pull_request.requested_reviewers.*.login, ', ') }}"
17 |
18 | MESSAGE="@channel\nPull Request: [#$PR_ID]($PR_URL) by @$PR_AUTHOR\nRequested Reviewers: $REVIEWERS"
19 |
20 | curl -X POST -H "Content-Type: application/json" -d "{\"text\": \"$MESSAGE\", \"username\": \"GitHub\", \"icon_url\": \"https://github.githubassets.com/favicons/favicon.png\"}" $INTERNAL_NOTIFICATION_CHANNEL_API_ENDPOINT
21 |
22 |
--------------------------------------------------------------------------------
/.github/workflows/publish.yml:
--------------------------------------------------------------------------------
1 | name: Publish to NPM
2 | on:
3 | pull_request:
4 | types:
5 | - closed
6 | branches:
7 | - main
8 | jobs:
9 | build:
10 | runs-on: ubuntu-latest
11 | steps:
12 | - name: Checkout
13 | uses: actions/checkout@v2
14 | - name: Setup Node
15 | uses: actions/setup-node@v2
16 | with:
17 | node-version: '16.x'
18 | registry-url: 'https://registry.npmjs.org'
19 | - name: 📥 Install dependencies
20 | run: npm install
21 | - name: 🔧 Build
22 | run: npm run build
23 | - name: 📦 Publish package on NPM
24 | run: cd dist && npm publish --access public
25 | env:
26 | NODE_AUTH_TOKEN: ${{ secrets.NPM_AUTOMATION_ACCESS_TOKEN }}
27 | - name: 🚀 Run bump up commit
28 | run: |
29 | git config --global user.name "Hamik Hambardzumyan"
30 | git config --global user.email "hamik.hambardzumyan@softconstruct.com"
31 | npm run bump-up-commit
32 |
--------------------------------------------------------------------------------
/.github/workflows/pull-request.yml:
--------------------------------------------------------------------------------
1 | name: Pull Request CI
2 | on:
3 | pull_request:
4 | branches: ["release/*", "main"]
5 | jobs:
6 | build:
7 | runs-on: ubuntu-latest
8 | steps:
9 | - name: Checkout
10 | uses: actions/checkout@v2
11 | - name: Setup Node
12 | uses: actions/setup-node@v2
13 | with:
14 | node-version: '16.x'
15 | registry-url: 'https://registry.npmjs.org'
16 | - name: 📥 Install dependencies
17 | run: npm install
18 | - name: 🔧 Pure build
19 | run: npm run build -- --pure
20 | - name: 🧪 Run tests
21 | run: npm run test
22 | - name: 🧑💻 Linting source code
23 | run: npm run lint-styles && npm run lint-scripts
24 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | node_modules
5 |
6 | # builds
7 | build
8 | dist
9 | stats
10 | .rpt2_cache
11 | styleguide
12 | storybook-static
13 |
14 | # misc
15 | .DS_Store
16 | .env
17 | .env.local
18 | .env.development.local
19 | .env.test.local
20 | .env.production.local
21 |
22 | # Coverage directory used by tools like istanbul
23 | coverage
24 | jest-coverage
25 |
26 | # Logs
27 | npm-debug.log*
28 | yarn-debug.log*
29 | yarn-error.log*
30 |
31 | #IDE metadata
32 | *.iml
33 | *.ipr
34 | *.idea
35 | *.iws
36 | *.map
37 | *.orig
38 | *.project
39 | *.settings/*
40 |
--------------------------------------------------------------------------------
/.storybook/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../configs/.babelrc",
3 | "presets": ["@babel/preset-env", "@babel/preset-react", "@babel/preset-typescript"]
4 | }
--------------------------------------------------------------------------------
/.storybook/assets/arrow-down.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/.storybook/assets/deprecated.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/.storybook/assets/experimental.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/.storybook/assets/screen-rotation-icon.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/.storybook/components/DocContainer.jsx:
--------------------------------------------------------------------------------
1 | import React, { useMemo } from 'react';
2 | import { DocsContainer as BaseContainer } from '@storybook/blocks';
3 | import { useDarkMode } from 'storybook-dark-mode';
4 | import { themes } from '@storybook/theming';
5 |
6 | export const DocsContainer = ({ children, context }) => {
7 | let contextTitle = context?.primaryStory?.title;
8 |
9 | const title = useMemo(() => {
10 | if (contextTitle) {
11 | return contextTitle[contextTitle.length - 2] === '-'
12 | ? contextTitle.replace(contextTitle.slice(-2), '')
13 | : contextTitle;
14 | }
15 | }, [contextTitle]);
16 |
17 | if (contextTitle) context.primaryStory.title = title;
18 | return (
19 |
20 | {children}
21 |
22 | );
23 | };
24 |
--------------------------------------------------------------------------------
/.storybook/components/SidebarLabelWrapper/SidebarLabelWrapper.js:
--------------------------------------------------------------------------------
1 | import React, { useMemo } from 'react';
2 | import experimental from '../../assets/experimental.svg';
3 | import deprecated from '../../assets/deprecated.svg';
4 | import './index.css';
5 |
6 | const cmpStages = {
7 | '-e': {
8 | src: experimental,
9 | alt: 'The component is experimental'
10 | },
11 | '-d': {
12 | src: deprecated,
13 | alt: 'The component is deprecated'
14 | }
15 | };
16 |
17 | const SidebarLabelWrapper = ({ item }) => {
18 | const stage = useMemo(() => (item.id[item.id.length - 2] === '-' ? item.name.slice(-2) : null), []);
19 | const name = useMemo(() => (stage ? item.name.replace(stage, '') : item.name), []);
20 |
21 | return (
22 |
23 |
{name}
24 | {stage && (
25 |
![{cmpStages[stage].alt} {cmpStages[stage].alt}]({cmpStages[stage].src})
31 | )}
32 |
33 | );
34 | };
35 |
36 | export default SidebarLabelWrapper;
37 |
--------------------------------------------------------------------------------
/.storybook/manager-head.html:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/.storybook/manager.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { addons } from '@storybook/addons';
3 | import { themes } from '@storybook/theming';
4 | import SidebarLabelWrapper from './components/SidebarLabelWrapper/SidebarLabelWrapper';
5 |
6 | addons.setConfig({
7 | isFullscreen: false,
8 | showNav: true,
9 | showPanel: 'right',
10 | panelPosition: 'right',
11 | enableShortcuts: true,
12 | showToolbar: true,
13 | theme: themes.dark,
14 | selectedPanel: undefined,
15 | initialActive: 'sidebar',
16 | sidebar: {
17 | showRoots: true,
18 | collapsedRoots: ['other'],
19 | renderLabel: (item) => {
20 | return ;
21 | }
22 | },
23 | toolbar: {
24 | title: { hidden: false },
25 | zoom: { hidden: false },
26 | eject: { hidden: false },
27 | copy: { hidden: false },
28 | fullscreen: { hidden: false }
29 | },
30 | previewTabs: {
31 | canvas: 'Playground'
32 | }
33 | });
34 |
--------------------------------------------------------------------------------
/.storybook/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/softconstruct/gene-ui-components/ab23d640aa07d2bc6c328037647402a515d6165f/.storybook/public/favicon.ico
--------------------------------------------------------------------------------
/.storybook/softConstructThem.js:
--------------------------------------------------------------------------------
1 | import logo from './assets/logo.svg';
2 | const colorPrimary = `#E90789`;
3 |
4 | //for all theming adjustable features visit -> https://storybook.js.org/docs/react/configure/theming
5 | const baseConfig = {
6 | // Typography
7 | fontBase: '"Open Sans", sans-serif',
8 | fontCode: 'monospace',
9 |
10 | brandTitle: 'Gene UI by SoftConstruct',
11 | barSelectedColor: colorPrimary,
12 | colorSecondary: colorPrimary,
13 | brandImage: logo
14 | };
15 |
16 | export const softConstructThem = {
17 | dark: { ...baseConfig },
18 | light: { ...baseConfig }
19 | };
20 |
--------------------------------------------------------------------------------
/.storybook/style.css:
--------------------------------------------------------------------------------
1 | html {
2 | padding: 4px;
3 | }
4 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "prettier.configPath": "./configs/.prettierrc",
3 | "prettier.ignorePath": "./configs/.prettierignore",
4 | "editor.formatOnSave": true,
5 |
6 | "stylelint.enable": true,
7 | "stylelint.configFile": "./configs/.stylelintrc.json",
8 | "stylelint.validate": ["css", "scss"],
9 |
10 | "eslint.enable": true,
11 | "eslint.options": {
12 | "configFile": "./configs/.eslintrc.json",
13 | "ignorePatterns": [
14 | ".git/",
15 | ".github/",
16 | "node_modules/",
17 | "dist/",
18 | "stats/",
19 | "coverage/",
20 | "docs/"
21 | ]
22 | },
23 |
24 | "cSpell.words": [
25 | "geneui"
26 | ]
27 | }
28 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2023 SoftConstruct
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/configs/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "plugins": [
3 | "@babel/plugin-proposal-export-default-from",
4 | "@babel/plugin-proposal-optional-chaining",
5 | "@babel/plugin-proposal-class-properties",
6 | "@babel/plugin-transform-react-jsx",
7 | "@babel/plugin-syntax-jsx",
8 | "@babel/plugin-proposal-nullish-coalescing-operator"
9 | ],
10 | "presets": ["@babel/preset-env", "@babel/preset-react"]
11 | }
12 |
--------------------------------------------------------------------------------
/configs/.eslintignore:
--------------------------------------------------------------------------------
1 | .git
2 | .github
3 | node_modules
4 |
5 | # Ignore artifacts:
6 | dist
7 | stats
8 |
9 | coverage
10 | docs
--------------------------------------------------------------------------------
/configs/.lintstagedrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "*": ["prettier --config ./configs/.prettierrc --ignore-path ./configs/.prettierignore --write"],
3 | "*.js": ["eslint --config ./configs/.eslintrc.json --ignore-path ./configs/.eslintignore --fix"],
4 | "*.scss": ["stylelint **/*.{css,scss,sass} --config ./configs/.stylelintrc.json --fix"]
5 | }
6 |
--------------------------------------------------------------------------------
/configs/.prettierignore:
--------------------------------------------------------------------------------
1 | .git
2 | .github
3 |
4 | node_modules
5 |
6 | # Ignore artifacts:
7 | dist
8 | stats
9 |
10 | coverage
11 | docs
12 |
13 | **/.prettierignore
14 |
15 | **/*.svg
16 |
17 | **/*.mdx
18 | **/*.md
19 |
20 | **/*.ico
21 |
--------------------------------------------------------------------------------
/configs/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "singleQuote": true,
3 | "printWidth": 120,
4 | "proseWrap": "always",
5 | "tabWidth": 4,
6 | "useTabs": false,
7 | "trailingComma": "none",
8 | "bracketSpacing": true,
9 | "semi": true
10 | }
11 |
--------------------------------------------------------------------------------
/configs/.releaserc.json:
--------------------------------------------------------------------------------
1 | {
2 | "branches": ["main"],
3 | "plugins": [
4 | [
5 | "@semantic-release/commit-analyzer",
6 | {
7 | "preset": "angular",
8 | "releaseRules": [
9 | { "type": "fix", "release": "patch" },
10 | { "type": "feat", "release": "minor" }
11 | ]
12 | }
13 | ],
14 | "@semantic-release/release-notes-generator",
15 | [
16 | "@semantic-release/changelog",
17 | {
18 | "changelogFile": "CHANGELOG.md",
19 | "changelogTitle": "# Changelog"
20 | }
21 | ],
22 | [
23 | "@semantic-release/npm",
24 | {
25 | "npmPublish": false
26 | }
27 | ]
28 | ],
29 | "repositoryUrl": "https://github.com/softconstruct/gene-ui-components.git"
30 | }
31 |
--------------------------------------------------------------------------------
/configs/.stylelintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": ["stylelint-config-standard-scss", "stylelint-config-prettier"],
3 | "rules": {
4 | "no-empty-source": null,
5 | "no-descending-specificity": null,
6 | "font-family-no-missing-generic-family-keyword": null,
7 | "declaration-block-no-shorthand-property-overrides": null,
8 | "declaration-block-no-redundant-longhand-properties": null,
9 | "custom-property-pattern": null,
10 | "keyframes-name-pattern": null,
11 | "no-duplicate-selectors": null,
12 | "declaration-block-no-duplicate-properties": null,
13 | "keyframe-block-no-duplicate-selectors": null,
14 | "selector-pseudo-class-no-unknown": null,
15 | "selector-pseudo-element-no-unknown": null,
16 | "selector-class-pattern": null,
17 | "media-feature-name-no-unknown": null,
18 | "max-line-length": null,
19 | "scss/dollar-variable-pattern": null,
20 | "scss/no-global-function-names": null,
21 | "scss/at-mixin-pattern": null,
22 | "scss/at-if-no-null": null,
23 | "scss/double-slash-comment-whitespace-inside": null,
24 | "scss/operator-no-unspaced": null,
25 | "scss/operator-no-newline-after": null,
26 | "color-function-notation": "legacy",
27 | "value-no-vendor-prefix": null
28 | },
29 | "ignoreFiles": ["../coverage/**/*.css", "../storybook-static/**/*.css"]
30 | }
31 |
--------------------------------------------------------------------------------
/configs/commitlint.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | extends: ['@commitlint/config-conventional'],
3 | /*
4 | * Any rules defined here will override rules from @commitlint/config-conventional
5 | */
6 | rules: {
7 | 'scope-case': [0, 'always', ['pascal-case', 'lower-case']]
8 | }
9 | };
10 |
--------------------------------------------------------------------------------
/configs/jest.config.js:
--------------------------------------------------------------------------------
1 | // jest.config.js
2 | module.exports = {
3 | preset: 'ts-jest',
4 | transform: {
5 | '^.+\\.tsx?$': [
6 | 'ts-jest',
7 | {
8 | tsconfig: './configs/tsconfig.json'
9 | }
10 | ],
11 | '^.+\\.js$': [
12 | 'babel-jest',
13 | {
14 | configFile: './configs/.babelrc'
15 | }
16 | ]
17 | },
18 | testEnvironment: 'jsdom',
19 | moduleNameMapper: {
20 | '\\.(css|scss)$': 'identity-obj-proxy',
21 | '.svg': '/tests/__mocks__/svg.js',
22 | '^src': '/src',
23 | '^utils$': '/src/utils/',
24 | '^wrappers$': '/src/wrappers/',
25 | '^configs$': '/src/configs.js',
26 | '^hooks$': '/src/hooks/',
27 | '^components$': '/src/index.ts'
28 | },
29 | setupFilesAfterEnv: ['/tests/setup.ts'],
30 | testMatch: ['**/?(*.)+(test).tsx'], // TODO add .ts also for helpers
31 | collectCoverageFrom: [
32 | 'src/**/*.tsx',
33 | 'src/hooks/**/*.ts',
34 | '!src/hooks/index.ts',
35 | '!src/**/*.d.ts',
36 | '!src/**/*.stories.tsx'
37 | ], // TODO add .ts also for helpers
38 | coveragePathIgnorePatterns: ['/node_modules/', '/dist/'],
39 | transformIgnorePatterns: ['/node_modules/(?!react-dnd|dnd-core|@react-dnd)'],
40 | modulePathIgnorePatterns: ['node_modules', 'jest-test-results.json']
41 | };
42 |
--------------------------------------------------------------------------------
/configs/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "baseUrl": "../src",
4 | "paths": {
5 | "src": ["./"],
6 | "components": ["./index.ts"],
7 | "utils": ["./utils/index.js"],
8 | "wrappers": ["./wrappers/index.js"],
9 | "configs": ["./configs.js"],
10 | "hooks": ["./hooks/index.js"]
11 | },
12 | "outDir": "../dist",
13 | "target": "es6",
14 | "module": "esnext",
15 | "declaration": true,
16 | "emitDeclarationOnly": true,
17 | "moduleResolution": "node",
18 | "jsx": "react",
19 | "esModuleInterop": true,
20 | "skipLibCheck": true,
21 | "forceConsistentCasingInFileNames": true,
22 | "strict": true,
23 | "noImplicitAny": false // TODO remove after typescript migration
24 | },
25 | "include": ["../src/**/*.ts", "../src/**/index.tsx"]
26 | }
27 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | module.exports =
2 | process.env.REACT_APP_CORE_PLATFORM === 'mobile' ? require('./src/index.mobile') : require('./src/index');
3 |
--------------------------------------------------------------------------------
/scripts/copyFiles.js:
--------------------------------------------------------------------------------
1 | import { copyStaticFilesToDist } from './utils';
2 |
3 | copyStaticFilesToDist();
4 |
--------------------------------------------------------------------------------
/scripts/postPublish.js:
--------------------------------------------------------------------------------
1 | import { execCommand } from './utils';
2 | import pgk from '../package.json';
3 |
4 | const filesToCommit = 'package.json package-lock.json CHANGELOG.md';
5 | const commitMessage = `Bump up library version to ${pgk.version}`;
6 | const tagName = `v${pgk.version}`;
7 | const defaultBranch = 'main';
8 |
9 | // First, remove the current milestone tag as the semantic-release
10 | // plugin does not have an API to disable the push of the generated tag
11 | execCommand(`git push --delete origin ${tagName}`);
12 |
13 | execCommand(
14 | `git add ${filesToCommit} && git commit --no-verify -m '${commitMessage}' && git push origin ${defaultBranch}`
15 | );
16 | execCommand(`git tag ${tagName} && git push origin ${tagName}`);
17 |
--------------------------------------------------------------------------------
/src/assets/media/empty-state/transparent/message.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/assets/styles/rtl.scss:
--------------------------------------------------------------------------------
1 | @mixin rtl($type, $v1, $v2) {
2 | #{$type}: #{$v1};
3 |
4 | html[dir='rtl'] & {
5 | #{$type}: #{$v2};
6 | }
7 | }
8 |
9 | @mixin rtls($type, $v, $side, $suffix: '') {
10 | @if $suffix != '' {
11 | $suffix: '-' + $suffix;
12 | }
13 |
14 | html:not([dir='rtl']) & {
15 | #{$type + '-' + $side + $suffix}: #{$v};
16 | }
17 |
18 | html[dir='rtl'] & {
19 | @if $side == left {
20 | $type: $type + '-right';
21 | } @else if $side == right {
22 | $type: $type + '-left';
23 | }
24 |
25 | #{$type + $suffix}: #{$v};
26 | }
27 | }
28 | @mixin rtlp($type1, $type2, $v) {
29 | html:not([dir='rtl']) & {
30 | #{$type1}: #{$v};
31 | }
32 |
33 | html[dir='rtl'] & {
34 | #{$type2}: #{$v};
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/assets/styles/variables.scss:
--------------------------------------------------------------------------------
1 | @import 'rtl';
2 | @import 'sharedStyles';
3 | @import 'mixinsAndFunctions';
4 |
5 | $c: (
6 | hero: #1473e6,
7 | confirm: #2bc784,
8 | warning: #e6af57,
9 | danger: #e64e48,
10 | note: #fdc625,
11 | message: #8bd779,
12 | background: #fff,
13 | foreground: #3d3d5f
14 | );
15 |
16 | @each $name, $color in $c {
17 | $c: map-merge($c, (#{$name + '-hover'}: darken($color, 5)));
18 | $c: map-merge($c, (#{$name + '-sc'}: set-color($color)));
19 | $c: map-merge($c, (#{$name + '-rgb'}: #{red($color), green($color), blue($color)}));
20 | $c: map-merge(
21 | $c,
22 | (#{$name + '-sc-rgb'}: #{red(set-color($color)), green(set-color($color)), blue(set-color($color))})
23 | );
24 | }
25 |
26 | $f: var(--font-family);
27 | $zIndex: (
28 | 'loader': 100,
29 | 'header': 200,
30 | 'holder': 200,
31 | 'navigation': 200,
32 | 'modal': 300,
33 | 'overlay': 300,
34 | 'overspread': 300,
35 | 'popover': 400,
36 | 'tooltip': 500,
37 | 'toaster': 500,
38 | 'preview': 500,
39 | 'tableSticky': 10,
40 | 'tableStickyOver': 11,
41 | 'tableStickyOverPlus': 12
42 | );
43 | $tableTransition: 300ms;
44 | $scrollbar: (
45 | 'size': var(--scrollbar-size, 16px),
46 | 'thumbSize': var(--scrollbar-thumbSize, 8px),
47 | 'gutter': var(--scrollbar-gutter, 10px),
48 | 'space': var(--scrollbar-space, 4px),
49 | 'thumbBackground': sc(b, 0.05),
50 | 'thumbActiveBackground': sc(b, 0.1)
51 | );
52 | $popoverClassName: '.popover-positioner';
53 |
--------------------------------------------------------------------------------
/src/hooks/index.ts:
--------------------------------------------------------------------------------
1 | export { default as useWidth } from './useWidth';
2 | export { default as useMount } from './useMount';
3 | export { default as useClick } from './useClick';
4 | export { default as useToggle } from './useToggle';
5 | export { default as useUpdate } from './useUpdate';
6 | export { default as usePrevious } from './usePrevious';
7 | export { default as useKeyDown } from './useKeyDown';
8 | export { default as useForceUpdate } from './useForceUpdate';
9 | export { default as useDeviceType } from './useDeviceType';
10 | export { default as useWindowSize } from './useWindowSize';
11 | export { default as useClickOutside } from './useClickOutside';
12 | export { default as useDebounce } from './useDebounce';
13 | export { default as useThrottle } from './useThrottle';
14 | export { default as useMutationObserver } from './useMutationObserver';
15 | export { default as useUpdatableRef } from './useUpdatableRef';
16 | export { default as useDidMount } from './useDidMount';
17 | export { default as useBodyScroll } from './useBodyScroll';
18 | export { default as useImgDownload } from './useImgDownload';
19 | export { default as useEllipsisDetection } from './useEllipsisDetection';
20 | export { default as useHover } from './useHover';
21 |
--------------------------------------------------------------------------------
/src/hooks/useBodyScroll.js:
--------------------------------------------------------------------------------
1 | import { useCallback } from 'react';
2 |
3 | function useBodyScroll() {
4 | const lock = useCallback(() => {
5 | document.body.style.overflow = 'hidden';
6 | }, []);
7 |
8 | const unlock = useCallback(() => {
9 | document.body.style.overflow = 'auto';
10 | }, []);
11 |
12 | return {
13 | lock,
14 | unlock
15 | };
16 | }
17 |
18 | export default useBodyScroll;
19 |
--------------------------------------------------------------------------------
/src/hooks/useClick.js:
--------------------------------------------------------------------------------
1 | import { useRef, useCallback, useEffect } from 'react';
2 |
3 | function useClick(callback) {
4 | const ref = useRef();
5 |
6 | const handleClick = useCallback(
7 | (e) => {
8 | if (ref.current && ref.current.contains(e.target)) {
9 | callback && callback(e);
10 | }
11 | },
12 | [ref.current, callback]
13 | );
14 |
15 | useEffect(() => {
16 | document.addEventListener('mousedown', handleClick);
17 | return () => document.removeEventListener('mousedown', handleClick);
18 | }, [handleClick]);
19 |
20 | const setRef = (node) => (ref.current = node);
21 |
22 | return setRef;
23 | }
24 |
25 | export default useClick;
26 |
--------------------------------------------------------------------------------
/src/hooks/useClickOutside.js:
--------------------------------------------------------------------------------
1 | import { useRef, useCallback, useEffect } from 'react';
2 |
3 | function useClickOutside(callback, relativeElements) {
4 | const ref = useRef();
5 |
6 | const handleClickOutside = useCallback(
7 | (e) => {
8 | const { target } = e;
9 | const isNotRelativeTarget =
10 | Array.isArray(relativeElements) && relativeElements.length
11 | ? relativeElements?.find((relativeRef) => !relativeRef.current?.contains(target))
12 | : true;
13 |
14 | if (ref.current && !ref.current?.contains(target) && isNotRelativeTarget) {
15 | callback && callback(e);
16 | }
17 | },
18 | [ref.current, callback, relativeElements]
19 | );
20 |
21 | useEffect(() => {
22 | document.addEventListener('mousedown', handleClickOutside);
23 | return () => document.removeEventListener('mousedown', handleClickOutside);
24 | }, [handleClickOutside]);
25 |
26 | return (node) => (ref.current = node);
27 | }
28 |
29 | export default useClickOutside;
30 |
--------------------------------------------------------------------------------
/src/hooks/useDebounce.js:
--------------------------------------------------------------------------------
1 | import { useState, useEffect } from 'react';
2 |
3 | const useDebounce = (value, delay) => {
4 | if (value === undefined) {
5 | let timeoutId;
6 |
7 | const debounceCallback = (value, delay) => {
8 | clearTimeout(timeoutId);
9 | timeoutId = setTimeout(value, delay);
10 | };
11 |
12 | const clearDebounce = () => clearTimeout(timeoutId);
13 |
14 | return { debounceCallback, clearDebounce };
15 | }
16 |
17 | const [debouncedValue, setDebouncedValue] = useState(value);
18 |
19 | useEffect(() => {
20 | const handler = setTimeout(() => {
21 | setDebouncedValue(value);
22 | }, delay);
23 |
24 | return () => {
25 | clearTimeout(handler);
26 | };
27 | }, [delay, value]);
28 |
29 | return debouncedValue;
30 | };
31 |
32 | export default useDebounce;
33 |
--------------------------------------------------------------------------------
/src/hooks/useDeviceType.js:
--------------------------------------------------------------------------------
1 | import { clientConfigs, mobileScreenSize } from 'configs';
2 | import useWindowSize from './useWindowSize';
3 |
4 | function useDeviceType(screenType) {
5 | const { width } = useWindowSize();
6 |
7 | const type =
8 | screenType ||
9 | (clientConfigs.isMobile
10 | ? clientConfigs.isMobile()
11 | ? 'mobile'
12 | : 'desktop'
13 | : width < mobileScreenSize
14 | ? 'mobile'
15 | : 'desktop');
16 |
17 | return { type, isMobile: type === 'mobile' };
18 | }
19 |
20 | export default useDeviceType;
21 |
--------------------------------------------------------------------------------
/src/hooks/useDidMount.js:
--------------------------------------------------------------------------------
1 | import { useRef, useEffect } from 'react';
2 |
3 | const useDidMount = (callback = () => {}, deps = []) => {
4 | const _isFirstUpdate = useRef(true);
5 |
6 | useEffect(() => {
7 | if (!_isFirstUpdate.current) {
8 | callback();
9 | }
10 | _isFirstUpdate.current = false;
11 | }, deps);
12 | };
13 |
14 | export default useDidMount;
15 |
--------------------------------------------------------------------------------
/src/hooks/useEllipsisDetection/index.ts:
--------------------------------------------------------------------------------
1 | export { default as default } from './useEllipsisDetection';
2 |
--------------------------------------------------------------------------------
/src/hooks/useEllipsisDetection/useEllipsisDetection.test.tsx:
--------------------------------------------------------------------------------
1 | import React, { RefObject } from 'react';
2 | import { mount } from 'enzyme';
3 | import useEllipsisDetection from './useEllipsisDetection';
4 |
5 | describe('useEllipsisDetection', () => {
6 | it('should return false if text is not truncated', () => {
7 | const ref = {
8 | current: { scrollWidth: 100, clientWidth: 200, scrollHeight: 50, clientHeight: 100 }
9 | } as RefObject;
10 |
11 | const Component = () => {
12 | const isTruncated = useEllipsisDetection(ref);
13 | return {isTruncated ? 'Truncated' : 'Not Truncated'}
;
14 | };
15 |
16 | const wrapper = mount();
17 | expect(wrapper.text()).toBe('Not Truncated');
18 | });
19 |
20 | it('should return true if text is truncated', () => {
21 | const ref = {
22 | current: { scrollWidth: 300, clientWidth: 200, scrollHeight: 150, clientHeight: 100 }
23 | } as RefObject;
24 |
25 | const Component = () => {
26 | const isTruncated = useEllipsisDetection(ref);
27 | return {isTruncated ? 'Truncated' : 'Not Truncated'}
;
28 | };
29 |
30 | const wrapper = mount();
31 | expect(wrapper.text()).toBe('Truncated');
32 | });
33 |
34 | // TODO: need to add resize test case
35 | });
36 |
--------------------------------------------------------------------------------
/src/hooks/useEllipsisDetection/useEllipsisDetection.ts:
--------------------------------------------------------------------------------
1 | import { useEffect, useState, RefObject } from 'react';
2 | import useDebounce from '../useDebounce';
3 |
4 | const EQUAL_HEIGHT_DIFF = 3;
5 |
6 | interface IUseEllipsisDetection {
7 | (ref: RefObject, externalDependencies?: any[]): boolean;
8 | }
9 |
10 | const useEllipsisDetection: IUseEllipsisDetection = (ref, externalDependencies = []) => {
11 | const [isTruncated, setIsTruncated] = useState(false);
12 |
13 | const { debounceCallback, clearDebounce } = useDebounce();
14 |
15 | const handleResize = () => {
16 | if (!ref.current) return;
17 | const { scrollWidth, clientWidth, scrollHeight, clientHeight } = ref.current;
18 | setIsTruncated(scrollWidth > clientWidth || scrollHeight > clientHeight + EQUAL_HEIGHT_DIFF);
19 | };
20 |
21 | useEffect(() => handleResize(), []);
22 |
23 | useEffect(() => {
24 | const debounce = () => debounceCallback(handleResize, 100);
25 | window.addEventListener('resize', debounce);
26 |
27 | return () => {
28 | clearDebounce();
29 | window.removeEventListener('resize', debounce);
30 | };
31 | }, [
32 | ref,
33 | ref?.current?.scrollWidth,
34 | ref?.current?.clientWidth,
35 | ref?.current?.scrollHeight,
36 | ref?.current?.clientHeight,
37 | ...externalDependencies
38 | ]);
39 |
40 | return isTruncated;
41 | };
42 |
43 | export default useEllipsisDetection;
44 |
--------------------------------------------------------------------------------
/src/hooks/useForceUpdate.js:
--------------------------------------------------------------------------------
1 | import { useReducer } from 'react';
2 |
3 | const useForceUpdate = () => {
4 | const [ignored, forceUpdate] = useReducer((x) => x + 1, 0);
5 | return forceUpdate;
6 | };
7 |
8 | export default useForceUpdate;
9 |
--------------------------------------------------------------------------------
/src/hooks/useHover.js:
--------------------------------------------------------------------------------
1 | import { useState, useEffect } from 'react';
2 |
3 | const useHover = (ref) => {
4 | const [isHovered, setIsHovered] = useState(false);
5 |
6 | const handleMouseEnter = () => setIsHovered(true);
7 | const handleMouseLeave = () => setIsHovered(false);
8 |
9 | useEffect(() => {
10 | const node = ref.current;
11 |
12 | if (!node) return;
13 |
14 | node.addEventListener('mouseenter', handleMouseEnter);
15 | node.addEventListener('mouseleave', handleMouseLeave);
16 | return () => {
17 | node.removeEventListener('mouseenter', handleMouseEnter);
18 | node.removeEventListener('mouseleave', handleMouseLeave);
19 | };
20 | }, [ref]);
21 |
22 | return isHovered;
23 | };
24 |
25 | export default useHover;
26 |
--------------------------------------------------------------------------------
/src/hooks/useImgDownload.js:
--------------------------------------------------------------------------------
1 | import { useCallback } from 'react';
2 |
3 | const useImgDownload = () =>
4 | useCallback((url, name, customHeaders = {}) => {
5 | fetch(url, { headers: { ...customHeaders } })
6 | .then((response) => response.blob())
7 | .then((blob) => {
8 | const blobURL = URL.createObjectURL(blob);
9 | const a = document.createElement('a');
10 | a.href = blobURL;
11 | a.download = name && name.length ? name : 'download';
12 | a.click();
13 | })
14 | .catch((error) => console.log(error));
15 | }, []);
16 |
17 | export default useImgDownload;
18 |
--------------------------------------------------------------------------------
/src/hooks/useKeyDown.js:
--------------------------------------------------------------------------------
1 | import { useCallback, useEffect } from 'react';
2 |
3 | const useKeyDown = (callback, deps, ref, keys = []) => {
4 | const handleKeyDown = useCallback(
5 | (e) => {
6 | if (!keys.length || keys.includes(e.key)) {
7 | callback(e);
8 | }
9 | },
10 | [...keys, ...deps]
11 | );
12 |
13 | useEffect(() => {
14 | if (ref && ref.current) {
15 | ref.current.addEventListener('keydown', handleKeyDown);
16 | return () => ref?.current?.removeEventListener('keydown', handleKeyDown);
17 | }
18 | }, [handleKeyDown, ref.current]);
19 | };
20 |
21 | export default useKeyDown;
22 |
--------------------------------------------------------------------------------
/src/hooks/useMount.js:
--------------------------------------------------------------------------------
1 | import { useEffect } from 'react';
2 |
3 | import { noop } from 'utils';
4 |
5 | const useMount = (onMount = noop) => useEffect(onMount, []);
6 |
7 | export default useMount;
8 |
--------------------------------------------------------------------------------
/src/hooks/useMutationObserver.js:
--------------------------------------------------------------------------------
1 | import { useEffect } from 'react';
2 |
3 | const defaultOptions = { attributes: true, childList: true, subtree: true };
4 |
5 | const useMutationObserver = (ref, callback, options = defaultOptions) => {
6 | useEffect(() => {
7 | if (ref.current) {
8 | const observer = new MutationObserver(callback);
9 |
10 | observer.observe(ref.current, options);
11 | return () => {
12 | observer.disconnect();
13 | };
14 | }
15 | }, [callback, options]);
16 | };
17 |
18 | export default useMutationObserver;
19 |
--------------------------------------------------------------------------------
/src/hooks/usePrevious.js:
--------------------------------------------------------------------------------
1 | import { useRef, useMemo } from 'react';
2 |
3 | const usePrevious = (callback, deps) => {
4 | const previous = useRef();
5 |
6 | const value = useMemo(() => callback(previous.current), deps);
7 | previous.current = value;
8 |
9 | return value;
10 | };
11 |
12 | export default usePrevious;
13 |
--------------------------------------------------------------------------------
/src/hooks/useThrottle.js:
--------------------------------------------------------------------------------
1 | import { useCallback, useRef } from 'react';
2 |
3 | const useThrottle = (callback, delay) => {
4 | const ref = useRef(null);
5 |
6 | return useCallback(
7 | (...args) => {
8 | clearTimeout(ref.current);
9 |
10 | ref.current = setTimeout(() => {
11 | callback(...args);
12 | }, delay);
13 | },
14 | [callback, delay]
15 | );
16 | };
17 |
18 | export default useThrottle;
19 |
--------------------------------------------------------------------------------
/src/hooks/useToggle.js:
--------------------------------------------------------------------------------
1 | import { useState, useCallback } from 'react';
2 |
3 | function useToggle(defaultValue) {
4 | const [state, setState] = useState(!!defaultValue);
5 |
6 | const toggle = useCallback((value) => {
7 | setState((prev) => (typeof value === 'undefined' ? !prev : !!value));
8 | }, []);
9 |
10 | return [state, toggle];
11 | }
12 |
13 | export default useToggle;
14 |
--------------------------------------------------------------------------------
/src/hooks/useUpdatableRef.js:
--------------------------------------------------------------------------------
1 | import { useRef, useCallback } from 'react';
2 |
3 | import useForceUpdate from './useForceUpdate';
4 |
5 | const useUpdatableRef = (initial) => {
6 | const ref = useRef(initial);
7 | const forceUpdate = useForceUpdate();
8 |
9 | const update = useCallback((value) => {
10 | if (ref.current !== value) forceUpdate();
11 | ref.current = value;
12 | }, []);
13 |
14 | return [ref, update];
15 | };
16 |
17 | export default useUpdatableRef;
18 |
--------------------------------------------------------------------------------
/src/hooks/useUpdate.js:
--------------------------------------------------------------------------------
1 | import { useRef, useEffect } from 'react';
2 |
3 | function useUpdate(callback, dependencies) {
4 | const initial = useRef(true);
5 | useEffect(
6 | initial.current
7 | ? () => {
8 | initial.current = false;
9 | }
10 | : callback,
11 | dependencies
12 | );
13 | }
14 |
15 | export default useUpdate;
16 |
--------------------------------------------------------------------------------
/src/hooks/useWidth.js:
--------------------------------------------------------------------------------
1 | import { useState, useEffect } from 'react';
2 | import useWindowSize from './useWindowSize';
3 |
4 | function useWidth(ref) {
5 | const [width, setWidth] = useState(null);
6 |
7 | const { width: windowWidth } = useWindowSize();
8 |
9 | useEffect(() => {
10 | setWidth(ref.current.clientWidth);
11 | }, [ref.current, windowWidth]);
12 |
13 | return width;
14 | }
15 |
16 | export default useWidth;
17 |
--------------------------------------------------------------------------------
/src/hooks/useWindowSize.js:
--------------------------------------------------------------------------------
1 | import { useState, useEffect } from 'react';
2 | import useDebounce from './useDebounce';
3 |
4 | function useWindowSize() {
5 | const w = window;
6 | const { innerHeight, innerWidth } = w;
7 | const [width, setWindowWidth] = useState(innerWidth);
8 | const [height, setWindowHeight] = useState(innerHeight);
9 | const { debounceCallback, clearDebounce } = useDebounce();
10 |
11 | const handleResize = () => {
12 | const { innerHeight, innerWidth } = w;
13 | setWindowWidth(innerWidth);
14 | setWindowHeight(innerHeight);
15 | };
16 |
17 | const debounce = () => debounceCallback(handleResize, 100);
18 |
19 | useEffect(() => {
20 | w.addEventListener('resize', debounce);
21 | w.addEventListener('orientationChange', debounce);
22 |
23 | return () => {
24 | w.removeEventListener('resize', debounce);
25 | w.removeEventListener('orientationChange', debounce);
26 | clearDebounce();
27 | };
28 | }, []);
29 |
30 | return {
31 | width,
32 | height
33 | };
34 | }
35 |
36 | export default useWindowSize;
37 |
--------------------------------------------------------------------------------
/src/index.mobile.ts:
--------------------------------------------------------------------------------
1 | // Atoms
2 | export * from './lib/atoms/Button/index.mobile';
3 | export * from './lib/atoms/Divider/index.mobile';
4 | export * from './lib/atoms/Icon/index.mobile';
5 | export * from './lib/atoms/Label/index.mobile';
6 | export * from './lib/atoms/Radio/index.mobile';
7 | export * from './lib/atoms/Switcher/index.mobile';
8 |
9 | // Molecules
10 | export * from './lib/molecules/Alert/index.mobile';
11 | export * from './lib/molecules/Checkbox/index.mobile';
12 | export * from './lib/molecules/ExtendedInput/index.mobile';
13 | export * from './lib/molecules/Grid/index.mobile';
14 | export * from './lib/molecules/Notification/index.mobile';
15 | export * from './lib/molecules/Pagination/index.mobile';
16 | export * from './lib/molecules/RadioGroup/index.mobile';
17 | export * from './lib/molecules/ValidatableElements/Elements/index.mobile';
18 | export * from './lib/molecules/Counter/index.mobile';
19 |
20 | // Organisms
21 | export * from './lib/organisms/CheckboxGroup/index.mobile';
22 |
--------------------------------------------------------------------------------
/src/lib/atoms/Avatar/Avatar.test.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { shallow } from 'enzyme';
3 | import Avatar from './index';
4 |
5 | describe('Avatar Component', () => {
6 | it('renders without crashing', () => {
7 | const wrapper = shallow();
8 | expect(wrapper.exists()).toBeTruthy();
9 | });
10 |
11 | it('renders with an image when src prop is provided', () => {
12 | const wrapper = shallow();
13 | expect(wrapper.find('.user-avatar-c').prop('style')).toHaveProperty('backgroundImage', 'url(test-image.jpg)');
14 | });
15 |
16 | it('renders with an icon when icon prop is provided', () => {
17 | const wrapper = shallow();
18 | expect(wrapper.find('.user-avatar-c').hasClass('icon-test')).toBeTruthy();
19 | });
20 |
21 | it('renders with initials when children prop is provided', () => {
22 | const wrapper = shallow();
23 | expect(wrapper.text()).toBe('JD'); // Assuming getInitials returns 'JD'
24 | });
25 |
26 | it('calls onClick prop when clicked', () => {
27 | const onClickMock = jest.fn();
28 | const wrapper = shallow();
29 | wrapper.simulate('click');
30 | expect(onClickMock).toHaveBeenCalled();
31 | });
32 | });
33 |
--------------------------------------------------------------------------------
/src/lib/atoms/Avatar/index.tsx:
--------------------------------------------------------------------------------
1 | export { IAvatarProps, default as default } from './Avatar';
2 |
--------------------------------------------------------------------------------
/src/lib/atoms/Badge/index.tsx:
--------------------------------------------------------------------------------
1 | export { IBadgeProps, default as default } from './Badge';
2 |
--------------------------------------------------------------------------------
/src/lib/atoms/BusyLoader/BusyLoaderHolderHOC.tsx:
--------------------------------------------------------------------------------
1 | import React, { FC, ReactNode } from 'react';
2 | import classnames from 'classnames';
3 |
4 | interface IBusyLoaderHolderHOC {
5 | children?: ReactNode;
6 | loadingText?: string;
7 | className?: string;
8 | }
9 |
10 | const BusyLoaderHolderHOC: FC = ({ children, loadingText, className }) => {
11 | return (
12 |
13 | {children}
14 | {loadingText &&
{loadingText}
}
15 |
16 | );
17 | };
18 |
19 | export default BusyLoaderHolderHOC;
20 |
--------------------------------------------------------------------------------
/src/lib/atoms/BusyLoader/index.tsx:
--------------------------------------------------------------------------------
1 | export { IBusyLoaderProps, default as default } from './BusyLoader';
2 |
--------------------------------------------------------------------------------
/src/lib/atoms/Button/index.tsx:
--------------------------------------------------------------------------------
1 | export { IButtonProps, default as default } from './Button';
2 |
--------------------------------------------------------------------------------
/src/lib/atoms/Divider/Divider.scss:
--------------------------------------------------------------------------------
1 | @import 'src/assets/styles/variables';
2 |
3 | .divider {
4 | width: rem(1);
5 | height: rem(26);
6 | background: sc(b, 0.05);
7 |
8 | &:not(&-withNoSpace) {
9 | margin: 0 rem(15);
10 |
11 | &.type-horizontal {
12 | margin: rem(15) 0;
13 | }
14 | }
15 |
16 | &.type-horizontal {
17 | width: rem(26);
18 | height: rem(1);
19 |
20 | &.full-width {
21 | width: 100%;
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/lib/atoms/Divider/Divider.stories.tsx:
--------------------------------------------------------------------------------
1 | import React, { FC } from 'react';
2 | import { Meta } from '@storybook/react';
3 | import { args, propCategory } from '../../../../stories/assets/storybook.globals';
4 |
5 | // Components
6 | import DividerComponent, { IDividerProps } from './index';
7 |
8 | const meta: Meta = {
9 | title: 'Atoms/Divider',
10 | component: DividerComponent,
11 | argTypes: {
12 | type: args({ control: 'select', ...propCategory.appearance }),
13 | size: args({ control: 'text', ...propCategory.appearance }),
14 | withSpace: args({ control: 'boolean', ...propCategory.appearance }),
15 | className: args({ control: false, ...propCategory.others })
16 | },
17 | args: {
18 | size: '50px',
19 | withSpace: true
20 | }
21 | };
22 |
23 | export default meta;
24 |
25 | const Template: FC = ({ ...args }) => ;
26 |
27 | export const Default = Template.bind({});
28 | Default.args = {
29 | type: 'horizontal'
30 | };
31 |
32 | export const Vertical = Template.bind({});
33 | Vertical.args = {
34 | type: 'vertical'
35 | };
36 |
--------------------------------------------------------------------------------
/src/lib/atoms/Divider/index.tsx:
--------------------------------------------------------------------------------
1 | export { IDividerProps, default as default } from './Divider';
2 |
--------------------------------------------------------------------------------
/src/lib/atoms/Empty/Empty.scss:
--------------------------------------------------------------------------------
1 | @import 'src/assets/styles/variables';
2 |
3 | .empty-state-holder {
4 | display: flex;
5 | flex-direction: column;
6 | align-items: center;
7 | justify-content: center;
8 | text-align: center;
9 |
10 | &.absolute {
11 | position: absolute;
12 | top: 50%;
13 | left: 50%;
14 | transform: translate(-50%, -50%);
15 | }
16 | }
17 |
18 | .empty-state-image {
19 | img {
20 | height: rem(166);
21 | max-width: inherit;
22 | }
23 |
24 | .s-small > & {
25 | img {
26 | height: rem(66);
27 | }
28 | }
29 |
30 | .s-medium > & {
31 | img {
32 | height: rem(120);
33 | }
34 | }
35 | }
36 |
37 | .empty-state-title {
38 | font: 600 rem(16) / rem(20) $f;
39 |
40 | &:not(:last-child) {
41 | margin: 0 0 rem(10);
42 | }
43 |
44 | .s-medium > & {
45 | font-size: rem(14);
46 | }
47 |
48 | .s-small > & {
49 | font-size: rem(12);
50 | }
51 | }
52 |
53 | .empty-state-subtitle {
54 | font: rem(14) / 1.36 $f;
55 | max-width: rem(238);
56 |
57 | .s-small > & {
58 | font-size: rem(10);
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/src/lib/atoms/Empty/Empty.stories.tsx:
--------------------------------------------------------------------------------
1 | import React, { FC } from 'react';
2 | import { Meta } from '@storybook/react';
3 |
4 | // Helpers
5 | import { args, propCategory } from '../../../../stories/assets/storybook.globals';
6 |
7 | // Components
8 | import Empty, { IEmptyProps } from './index';
9 |
10 | const meta: Meta = {
11 | title: 'Atoms/Empty',
12 | component: Empty,
13 | argTypes: {
14 | appearance: args({ control: 'select', ...propCategory.appearance }),
15 | type: args({ control: 'select', ...propCategory.appearance }),
16 | size: args({ control: 'select', ...propCategory.appearance }),
17 | title: args({ control: 'text', ...propCategory.content }),
18 | subTitle: args({ control: 'text', ...propCategory.content }),
19 | className: args({ control: false, ...propCategory.others }),
20 | withImage: args({ control: 'boolean', ...propCategory.functionality })
21 | },
22 | args: {
23 | appearance: 'with-circles',
24 | size: 'big',
25 | type: 'data',
26 | withImage: true,
27 | title: 'No Data to Display',
28 | subTitle: 'Subtitle text can bes some descriptive information.'
29 | }
30 | };
31 |
32 | export default meta;
33 |
34 | const Template: FC = (args) => ;
35 |
36 | export const Default = Template.bind({});
37 |
38 | export const WithNoImage = Template.bind({});
39 |
40 | WithNoImage.args = {
41 | type: 'message',
42 | withImage: false
43 | } as IEmptyProps;
44 |
--------------------------------------------------------------------------------
/src/lib/atoms/Empty/index.tsx:
--------------------------------------------------------------------------------
1 | export { IEmptyProps, default as default } from './Empty';
2 |
--------------------------------------------------------------------------------
/src/lib/atoms/Icon/index.mobile.js:
--------------------------------------------------------------------------------
1 | export * from './index';
2 |
--------------------------------------------------------------------------------
/src/lib/atoms/Image/index.tsx:
--------------------------------------------------------------------------------
1 | export { IImageProps, default as default } from './Image';
2 |
--------------------------------------------------------------------------------
/src/lib/atoms/ImagePreview/ImagePreviewHOC.tsx:
--------------------------------------------------------------------------------
1 | import React, { FC } from 'react';
2 |
3 | // Components
4 | import Portal from '../Portal';
5 | import ImagePreview, { IImagePreviewProps } from './ImagePreview';
6 |
7 | const ImagePreviewHOC: FC = ({ withModal, ...restProps }) => {
8 | return withModal ? (
9 | // @ts-ignore
10 |
11 |
12 |
13 | ) : (
14 |
15 | );
16 | };
17 |
18 | export { IImagePreviewProps, ImagePreviewHOC as default };
19 |
--------------------------------------------------------------------------------
/src/lib/atoms/ImagePreview/index.tsx:
--------------------------------------------------------------------------------
1 | export { IImagePreviewProps, default as default } from './ImagePreviewHOC';
2 |
--------------------------------------------------------------------------------
/src/lib/atoms/KeyValue/KeyValue.stories.tsx:
--------------------------------------------------------------------------------
1 | import React, { FC } from 'react';
2 | import { Meta } from '@storybook/react';
3 | import { args, propCategory } from '../../../../stories/assets/storybook.globals';
4 |
5 | // Components
6 | import KeyValueComponent from '.';
7 |
8 | // Types
9 | import { IKeyValueProps } from '.';
10 |
11 | const appearance = ['horizontal', 'vertical'] as const;
12 |
13 | const meta: Meta = {
14 | title: 'Atoms/KeyValue',
15 | component: KeyValueComponent,
16 | argTypes: {
17 | label: args({ control: 'text', ...propCategory.content }),
18 | value: args({ control: 'text', ...propCategory.content }),
19 | className: args({ control: false, ...propCategory.others }),
20 | appearance: args({
21 | control: 'select',
22 | defaultValue: appearance[0],
23 | options: appearance,
24 | ...propCategory.appearance
25 | }),
26 | icon: args({ control: 'text', ...propCategory.content })
27 | },
28 | args: {
29 | label: 'Some label',
30 | value: 'Some value',
31 | icon: 'bc-icon-info',
32 | appearance: appearance[0]
33 | }
34 | };
35 |
36 | export default meta;
37 |
38 | const Template: FC = ({ ...args }) => ;
39 |
40 | export const Default = Template.bind({});
41 |
42 | export const Vertical = Template.bind({});
43 | Vertical.args = {
44 | appearance: appearance[1]
45 | };
46 |
--------------------------------------------------------------------------------
/src/lib/atoms/KeyValue/index.tsx:
--------------------------------------------------------------------------------
1 | export { IKeyValueProps, default as default } from './KeyValue';
2 |
--------------------------------------------------------------------------------
/src/lib/atoms/Label/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import classnames from 'classnames';
4 |
5 | // Styles
6 | import './index.scss';
7 |
8 | const labels = {
9 | headingExtraLarge: 'h1',
10 | headingLarge: 'h1',
11 | headingBig: 'h2',
12 | heading: 'h3',
13 | bodyBig: 'h4',
14 | body: 'h5',
15 | bodySmall: 'h6',
16 | content: 'p'
17 | };
18 |
19 | function Label({ children, className, size, font, ...restProps }) {
20 | return React.createElement(
21 | labels[size],
22 | {
23 | className: classnames('label', className, font, {
24 | large: size === 'headingExtraLarge'
25 | }),
26 | ...restProps
27 | },
28 | children
29 | );
30 | }
31 |
32 | Label.propTypes = {
33 | /**
34 | * Any valid React node.
35 | */
36 | children: PropTypes.string.isRequired,
37 | /**
38 | * Label sizing
39 | */
40 | size: PropTypes.oneOf([
41 | 'headingExtraLarge',
42 | 'headingLarge',
43 | 'headingBig',
44 | 'heading',
45 | 'bodyBig',
46 | 'body',
47 | 'bodySmall',
48 | 'content'
49 | ]),
50 | /**
51 | * Label font to be used
52 | */
53 | font: PropTypes.oneOf(['regular', 'semiBold', 'bold']),
54 | /**
55 | * Addional className
56 | */
57 | className: PropTypes.string
58 | };
59 |
60 | Label.defaultProps = {
61 | size: 'content',
62 | font: 'regular'
63 | };
64 |
65 | export default Label;
66 |
--------------------------------------------------------------------------------
/src/lib/atoms/Label/index.mobile.js:
--------------------------------------------------------------------------------
1 | export * from './index';
2 |
--------------------------------------------------------------------------------
/src/lib/atoms/Label/index.scss:
--------------------------------------------------------------------------------
1 | .label {
2 | display: inline-block;
3 | vertical-align: top;
4 | max-width: 100%;
5 | white-space: nowrap;
6 | text-overflow: ellipsis;
7 | overflow: hidden;
8 | font-weight: normal;
9 |
10 | &.bold {
11 | font-weight: bolder;
12 | }
13 |
14 | &.semiBold {
15 | font-weight: bold;
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/lib/atoms/LinkButton/LinkButton.scss:
--------------------------------------------------------------------------------
1 | @import 'src/assets/styles/variables';
2 |
3 | .linkButton {
4 | cursor: pointer;
5 | display: flex;
6 | align-items: center;
7 | max-width: fit-content;
8 | color: var(--hero);
9 | padding: 0 rem(8);
10 | @include focus-visible;
11 |
12 | &__icon {
13 | display: inline-block;
14 | }
15 |
16 | &-disable {
17 | opacity: 0.3;
18 | pointer-events: none;
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/lib/atoms/LinkButton/LinkButton.stories.tsx:
--------------------------------------------------------------------------------
1 | import { Meta, StoryObj } from '@storybook/react';
2 | import LinkButton from './index';
3 | import { args, category } from '../../../../stories/assets/storybook.globals';
4 |
5 | const meta = {
6 | component: LinkButton,
7 | title: 'Atoms/LinkButton',
8 | argTypes: {
9 | href: args({ control: 'text', category: category.content }),
10 | onClick: args({ control: false, category: category.action }),
11 | className: args({ control: false, category: category.others }),
12 | children: args({ control: 'text', category: category.content }),
13 | ariaLabel: args({ control: 'text', category: category.others }),
14 | onMouseDown: args({ control: false, category: category.action }),
15 | iconAfter: args({ control: 'text', category: category.content }),
16 | iconBefore: args({ control: 'text', category: category.content }),
17 | isDisabled: args({ control: 'boolean', category: category.states })
18 | }
19 | } satisfies Meta;
20 |
21 | export default meta;
22 |
23 | type Story = StoryObj;
24 |
25 | export const Default: Story = {};
26 |
27 | export const WithIcon: Story = {
28 | args: {
29 | iconAfter: 'bc-icon-arrow-right'
30 | }
31 | };
32 |
--------------------------------------------------------------------------------
/src/lib/atoms/LinkButton/index.tsx:
--------------------------------------------------------------------------------
1 | export { ILinkButtonProps, default as default } from './LinkButton';
2 |
--------------------------------------------------------------------------------
/src/lib/atoms/QRCode/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import { QRCodeSVG } from 'qrcode.react';
4 |
5 | const QRConfig = {
6 | levels: {
7 | L: 'L',
8 | M: 'M',
9 | Q: 'Q',
10 | H: 'H'
11 | }
12 | };
13 |
14 | function QRCode({ value, level, maxSize }) {
15 | return (
16 |
24 | );
25 | }
26 |
27 | QRCode.propTypes = {
28 | /**
29 | * If you'd like to apply styles to the single container div that your popover content is rendered within via stylesheets
30 | */
31 | value: PropTypes.string.isRequired,
32 | /**
33 | * Specifies the maximum size of QRCode component in pixels.
34 | * The component behaves adaptively and listens to the parent wrapper.
35 | */
36 | maxSize: PropTypes.number,
37 | /**
38 | * Level L (Low) 7% of data bytes can be restored.
39 | * Level M (Medium) 15% of data bytes can be restored.
40 | * Level Q (Quartile)[76] 25% of data bytes can be restored.
41 | * Level H (High) 30% of data bytes can be restored.
42 | */
43 | level: PropTypes.oneOf(Object.keys(QRConfig.levels))
44 | };
45 |
46 | QRCode.defaultProps = {
47 | maxSize: 400,
48 | level: QRConfig.levels.M
49 | };
50 |
51 | export default QRCode;
52 |
--------------------------------------------------------------------------------
/src/lib/atoms/Radio/index.mobile.js:
--------------------------------------------------------------------------------
1 | export * from './index';
2 |
--------------------------------------------------------------------------------
/src/lib/atoms/Rating/DefaultSvg.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 |
3 | function SvgSquareMajor(props) {
4 | return React.createElement(
5 | 'svg',
6 | {
7 | xmlns: 'http://www.w3.org/2000/svg',
8 | width: 24,
9 | height: 24,
10 | viewBox: '0 0 24 24',
11 | strokeLinecap: 'round',
12 | strokeLinejoin: 'round'
13 | },
14 | props,
15 | React.createElement('rect', {
16 | width: 18,
17 | height: 18,
18 | x: 3,
19 | y: 3,
20 | rx: 2
21 | })
22 | );
23 | }
24 |
25 | export default SvgSquareMajor;
26 |
--------------------------------------------------------------------------------
/src/lib/atoms/Rating/index.tsx:
--------------------------------------------------------------------------------
1 | export { IRatingProps, default as default } from './Rating';
2 |
--------------------------------------------------------------------------------
/src/lib/atoms/SkeletonLoader/index.scss:
--------------------------------------------------------------------------------
1 | @import 'src/assets/styles/variables';
2 |
3 | .skeleton-holder {
4 | max-width: 100%;
5 | display: block;
6 |
7 | .react-loading-skeleton {
8 | background-color: var(--background-hover);
9 | background-image: linear-gradient(90deg, var(--background-hover), var(--background), var(--background-hover));
10 | }
11 |
12 | span {
13 | display: block;
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/lib/atoms/Switcher/index.mobile.js:
--------------------------------------------------------------------------------
1 | export * from './index';
2 |
--------------------------------------------------------------------------------
/src/lib/atoms/TextLink/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | function TextLink({ children, ...props }) {
5 | return {children};
6 | }
7 |
8 | TextLink.propTypes = {
9 | /**
10 | * Any valid React node
11 | */
12 | children: PropTypes.string.isRequired,
13 | /**
14 | * Additional className
15 | */
16 | className: PropTypes.string
17 | };
18 |
19 | export default TextLink;
20 |
--------------------------------------------------------------------------------
/src/lib/atoms/Time/index.scss:
--------------------------------------------------------------------------------
1 | @import 'src/assets/styles/variables';
2 |
3 | .time-holder {
4 | display: flex;
5 | align-items: center;
6 | font-weight: 600;
7 | white-space: nowrap;
8 | line-height: rem(32);
9 |
10 | > * + * {
11 | @include rtl(margin, 0 0 0 rem(3), 0 rem(3) 0 0);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/lib/atoms/Title/index.scss:
--------------------------------------------------------------------------------
1 | @import 'src/assets/styles/variables';
2 |
3 | .title-holder {
4 | display: flex;
5 | width: 100%;
6 | align-items: center;
7 | font: 600 rem(14) / rem(18) $f;
8 | min-height: rem(32);
9 |
10 | &.c-hero {
11 | .title-text {
12 | color: c(hero);
13 | }
14 | }
15 |
16 | > li {
17 | flex-shrink: 0;
18 | display: flex;
19 | align-items: center;
20 |
21 | &.line {
22 | flex: auto;
23 |
24 | i {
25 | display: block;
26 | width: 100%;
27 | height: rem(1);
28 | background: sc(b, 0.1);
29 | }
30 | }
31 |
32 | ~ li {
33 | @include rtl(margin, 0 0 0 rem(10), 0 rem(10) 0 0);
34 | }
35 | }
36 |
37 | .divider {
38 | margin: 0 rem(10);
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/lib/molecules/AdvancedSearch/SkeletonSet.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import SkeletonLoader from '../../atoms/SkeletonLoader';
3 |
4 | function SkeletonSet({ count, searchResult }) {
5 | return searchResult ? (
6 |
7 | {Array(count || 1)
8 | .fill('')
9 | .map((_, i) => (
10 | -
11 |
12 |
13 | ))}
14 |
15 | ) : (
16 |
17 | {Array(count || 1)
18 | .fill('')
19 | .map((_, i) => (
20 | -
21 |
22 |
23 |
29 |
30 | ))}
31 |
32 | );
33 | }
34 |
35 | SkeletonSet.defaultProps = {};
36 |
37 | SkeletonSet.propTypes = {};
38 |
39 | export default SkeletonSet;
40 |
--------------------------------------------------------------------------------
/src/lib/molecules/Alert/index.mobile.js:
--------------------------------------------------------------------------------
1 | export * from './index';
2 |
--------------------------------------------------------------------------------
/src/lib/molecules/Breadcrumb/index.scss:
--------------------------------------------------------------------------------
1 | @import 'src/assets/styles/variables';
2 |
3 | .bread-crumbs-holder {
4 | display: flex;
5 | align-items: center;
6 | justify-content: flex-start;
7 | width: 100%;
8 | font-weight: 600;
9 | min-height: rem(36);
10 |
11 | > * {
12 | + *:not(button) {
13 | @include rtl(margin, 0 0 0 rem(10), 0 rem(10) 0 0);
14 | }
15 | }
16 |
17 | > button {
18 | margin: 0 rem(4);
19 |
20 | + .icon {
21 | @include rtl(margin, 0, 0);
22 | }
23 | }
24 | }
25 |
26 | .breadcrumbs-link {
27 | color: inherit;
28 | cursor: pointer;
29 | @include hover-active {
30 | color: c(hero);
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/lib/molecules/Breadcrumb/item.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import classnames from 'classnames';
3 |
4 | function BreadcrumbItem({ data, active, onClick }) {
5 | return (
6 |
9 | );
10 | }
11 |
12 | export default BreadcrumbItem;
13 |
--------------------------------------------------------------------------------
/src/lib/molecules/Charts/BarChart/index.scss:
--------------------------------------------------------------------------------
1 | @import 'src/assets/styles/variables';
2 |
3 | .bar-chart {
4 | min-height: rem(480);
5 | background-color: var(--background);
6 | }
7 |
8 | .bar-chart-proxy-content {
9 | min-height: rem(480);
10 |
11 | > .icon {
12 | margin: auto;
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/lib/molecules/Charts/ColumnChart/index.scss:
--------------------------------------------------------------------------------
1 | @import 'src/assets/styles/variables';
2 |
3 | .chart-overflow-holder.column-chart {
4 | .highcharts-series-0 {
5 | .highcharts-point {
6 | y: 0;
7 | height: 100%;
8 | }
9 | }
10 |
11 | min-height: rem(480);
12 | background-color: var(--background);
13 | }
14 |
15 | .column-chart-proxy-content {
16 | min-height: rem(480);
17 |
18 | > .icon {
19 | margin: auto;
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/lib/molecules/Charts/ColumnRangeChart/style.scss:
--------------------------------------------------------------------------------
1 | @import 'src/assets/styles/variables';
2 |
3 | .columnRangeChart {
4 | &__formatter {
5 | color: rgba(0, 0, 0, 80%);
6 | font-weight: 700;
7 | font-size: 10px;
8 | }
9 | }
10 |
11 | .column-range-chart {
12 | min-height: 440px;
13 | background-color: var(--background);
14 | }
15 |
16 | .column-range-proxy-content {
17 | min-height: 440px;
18 |
19 | > .icon {
20 | margin: auto;
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/lib/molecules/Charts/DalColumnChart/index.scss:
--------------------------------------------------------------------------------
1 | @import 'src/assets/styles/variables';
2 |
3 | .highcharts-drillup-button {
4 | rect {
5 | display: none;
6 | }
7 |
8 | &.highcharts-button {
9 | text {
10 | font-size: rem(14) !important;
11 | font-weight: 600 !important;
12 | fill: #3c4043 !important;
13 | }
14 |
15 | &:hover {
16 | text {
17 | fill: c(hero) !important;
18 | }
19 | }
20 | }
21 | }
22 |
23 | .dal-chart {
24 | min-height: rem(550);
25 | background-color: var(--background);
26 | }
27 |
28 | .dal-chart-proxy-content {
29 | min-height: rem(550);
30 |
31 | > .icon {
32 | margin: auto;
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/lib/molecules/Charts/DonutChart/index.scss:
--------------------------------------------------------------------------------
1 | @import 'src/assets/styles/variables';
2 |
3 | .charts-donut-chart {
4 | overflow: hidden;
5 | min-height: rem(550);
6 | background-color: var(--background);
7 |
8 | &.direction-row {
9 | .chart-wrapper {
10 | width: calc(100% - 30rem);
11 | }
12 | }
13 |
14 | .highcharts-title {
15 | white-space: normal !important;
16 | }
17 |
18 | .highcharts-container {
19 | width: 100% !important;
20 | }
21 |
22 | .highcharts-label-box {
23 | fill: none !important;
24 | }
25 |
26 | .highcharts-root {
27 | max-width: 100%;
28 | margin: 0 auto;
29 | }
30 |
31 | .hs-tooltip {
32 | background: rgba(0, 0, 0, 70%);
33 | padding: 10px;
34 | border-radius: 2px;
35 | }
36 | }
37 |
38 | .donut-chart-proxy-content {
39 | min-height: rem(550);
40 |
41 | > .icon {
42 | margin: auto;
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/lib/molecules/Charts/FunnelChart/index.scss:
--------------------------------------------------------------------------------
1 | @import 'src/assets/styles/variables';
2 |
3 | .funnel-chart {
4 | min-height: rem(480);
5 | background-color: var(--background);
6 | }
7 |
8 | .funnel-chart-proxy-content {
9 | min-height: rem(480);
10 |
11 | > .icon {
12 | margin: auto;
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/lib/molecules/Charts/HeatMapChart/index.scss:
--------------------------------------------------------------------------------
1 | @import 'src/assets/styles/variables';
2 |
3 | .high-chart {
4 | min-height: rem(700);
5 | background-color: var(--background);
6 | }
7 |
8 | .highchart-proxy-content {
9 | min-height: rem(700);
10 |
11 | > .icon {
12 | margin: auto;
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/lib/molecules/Charts/LineChart/index.scss:
--------------------------------------------------------------------------------
1 | @import 'src/assets/styles/variables';
2 |
3 | .line-chart {
4 | min-height: rem(480);
5 | background-color: var(--background);
6 | }
7 |
8 | .line-chart-proxy-content {
9 | min-height: rem(480);
10 |
11 | > .icon {
12 | margin: auto;
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/lib/molecules/Charts/MapChart/IconButton.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import classnames from 'classnames';
3 |
4 | // Components
5 | import Icon from '../../../atoms/Icon';
6 |
7 | function MapChartIconButton({ disabled, name, onClick }) {
8 | return (
9 |
17 | );
18 | }
19 |
20 | export default MapChartIconButton;
21 |
--------------------------------------------------------------------------------
/src/lib/molecules/Charts/PieChart/index.scss:
--------------------------------------------------------------------------------
1 | @import 'src/assets/styles/variables';
2 |
3 | .charts-pie-chart {
4 | overflow: hidden;
5 | min-height: rem(480);
6 | background-color: var(--background);
7 |
8 | &.vertical-legend {
9 | width: 100%;
10 | display: flex;
11 | align-items: center;
12 | }
13 | }
14 |
15 | .pie-chart-proxy-content {
16 | min-height: rem(480);
17 |
18 | > .icon {
19 | margin: auto;
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/lib/molecules/Charts/ScatterChart/index.scss:
--------------------------------------------------------------------------------
1 | @import 'src/assets/styles/variables';
2 |
3 | .scatter-chart-holder {
4 | height: rem(1000);
5 | min-height: rem(480);
6 | background-color: var(--background);
7 |
8 | .chart-overflow-header {
9 | display: flex;
10 | align-items: center;
11 | justify-content: space-between;
12 | margin: 10px 0;
13 | padding: 0 10px 0 50px;
14 | height: 40px;
15 |
16 | .chart-label {
17 | display: flex;
18 | align-items: center;
19 |
20 | .label {
21 | max-width: 200px;
22 | color: #3c4043;
23 | }
24 |
25 | .static-title-holder {
26 | margin-left: 10px;
27 |
28 | .tag-c {
29 | color: white;
30 | background: rgba(20, 115, 230, 50%);
31 | }
32 | }
33 | }
34 | }
35 |
36 | .highcharts-selection-marker {
37 | stroke-width: 0.5;
38 | stroke: c(hero);
39 | stroke-linecap: round;
40 | stroke-dasharray: 1, 3;
41 | }
42 |
43 | .highcharts-button {
44 | path,
45 | rect {
46 | fill: c(hero) !important;
47 |
48 | &:hover {
49 | fill: c(hero-hover) !important;
50 | }
51 | }
52 | }
53 | }
54 |
55 | .scatter-chart-proxy-content {
56 | min-height: rem(480);
57 |
58 | > .icon {
59 | margin: auto;
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/src/lib/molecules/Charts/StackedBarChart/index.scss:
--------------------------------------------------------------------------------
1 | @import 'src/assets/styles/variables';
2 |
3 | .stacked-chart {
4 | min-height: rem(550);
5 | background-color: var(--background);
6 | }
7 |
8 | .stacked-chart-proxy-content {
9 | min-height: rem(550);
10 |
11 | > .icon {
12 | margin: auto;
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/lib/molecules/Charts/StackedColumnChart/index.scss:
--------------------------------------------------------------------------------
1 | @import 'src/assets/styles/variables';
2 |
3 | .stacked-column-chart {
4 | min-height: rem(480);
5 | background-color: var(--background);
6 | }
7 |
8 | .stacked-column-chart-proxy-content {
9 | min-height: rem(480);
10 |
11 | > .icon {
12 | margin: auto;
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/lib/molecules/Charts/TreeMapChart/index.scss:
--------------------------------------------------------------------------------
1 | @import 'src/assets/styles/variables';
2 |
3 | .whiteDrillDown {
4 | .highcharts-drillup-button {
5 | &.highcharts-button:not(:hover) {
6 | text {
7 | fill: white !important;
8 | }
9 | }
10 | }
11 | }
12 |
13 | .tree-map-chart {
14 | min-height: rem(480);
15 | background-color: var(--background);
16 | }
17 |
18 | .tree-map-chart-proxy-content {
19 | min-height: rem(480);
20 |
21 | > .icon {
22 | margin: auto;
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/lib/molecules/Charts/index.js:
--------------------------------------------------------------------------------
1 | import './index.scss';
2 |
3 | export { default as LineChart } from './LineChart';
4 | export { default as FunnelChart } from './FunnelChart';
5 | export { default as MapChart } from './MapChart';
6 | export { default as TreeMapChart } from './TreeMapChart';
7 | export { default as BarChart } from './BarChart';
8 | export { default as ColumnChart } from './ColumnChart';
9 | export { default as DalColumnChart } from './DalColumnChart';
10 | export { default as StackedBarChart } from './StackedBarChart';
11 | export { default as StackedColumnChart } from './StackedColumnChart';
12 | export { default as AreaChart } from './AreaChart';
13 | export { default as PieChart } from './PieChart';
14 | export { default as DonutChart } from './DonutChart';
15 | export { default as ScatterChart } from './ScatterChart';
16 | export { default as HeatMapChart } from './HeatMapChart';
17 | export { default as ColumnRangeChart } from './ColumnRangeChart';
18 |
--------------------------------------------------------------------------------
/src/lib/molecules/Checkbox/index.mobile.js:
--------------------------------------------------------------------------------
1 | export * from './index';
2 |
--------------------------------------------------------------------------------
/src/lib/molecules/Collapse/index.js:
--------------------------------------------------------------------------------
1 | import Collapse from './Collapse';
2 | import Panel from './Panel';
3 |
4 | export { Collapse, Panel };
5 |
--------------------------------------------------------------------------------
/src/lib/molecules/Collapse/utils.js:
--------------------------------------------------------------------------------
1 | import PropTypes from 'prop-types';
2 |
3 | // Local components
4 | import Panel from './Panel';
5 |
6 | const deepCheck = (children) => {
7 | Array.from(children).every((child) => {
8 | Array.isArray(child) && deepCheck(child);
9 |
10 | return PropTypes.shape({
11 | type: PropTypes.instanceOf(Panel)
12 | });
13 | });
14 | };
15 |
16 | export default deepCheck;
17 |
--------------------------------------------------------------------------------
/src/lib/molecules/ComboBox/TagWrapper/index.scss:
--------------------------------------------------------------------------------
1 | .tag-wrapper {
2 | max-width: 100%;
3 | display: flex;
4 | align-items: center;
5 |
6 | &.flex-basis {
7 | flex-basis: 20px;
8 | align-self: center;
9 | }
10 |
11 | .input {
12 | margin: 1px 0;
13 | width: 100%;
14 | color: var(--background-sc);
15 | -webkit-box-flex: 1;
16 | flex: 1 1;
17 | border: none;
18 | outline: none;
19 | padding: 0;
20 | background: transparent;
21 | caret-color: var(--background-sc);
22 | }
23 |
24 | span {
25 | align-self: flex-start;
26 | height: 0;
27 | visibility: hidden;
28 | white-space: pre;
29 | display: flex;
30 | background: #fff;
31 | color: black;
32 | -webkit-box-flex: 1;
33 | flex: 1 1;
34 | border: none;
35 | outline: none;
36 | padding: 0;
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/lib/molecules/ComboBox/config.js:
--------------------------------------------------------------------------------
1 | export const actionTypes = {
2 | add: 'add',
3 | edit: 'edit',
4 | delete: 'delete'
5 | };
6 |
7 | export const keyDownKeys = {
8 | space: ' ',
9 | enter: 'Enter',
10 | escape: 'Escape',
11 | arrowDown: 'ArrowDown',
12 | arrowUp: 'ArrowUp',
13 | arrowLeft: 'ArrowLeft',
14 | arrowRight: 'ArrowRight',
15 | backspace: 'Backspace',
16 | delete: 'Delete',
17 | tab: 'Tab'
18 | };
19 |
20 | export const SPACE_HEIGHT = 8;
21 |
--------------------------------------------------------------------------------
/src/lib/molecules/Copy/Copy.scss:
--------------------------------------------------------------------------------
1 | @import 'src/assets/styles/variables';
2 |
3 | .copy {
4 | cursor: pointer;
5 | max-width: fit-content;
6 | max-height: fit-content;
7 |
8 | &-controlVisibility {
9 | visibility: hidden;
10 | }
11 |
12 | &-pointerNon {
13 | cursor: initial;
14 | }
15 |
16 | &-isVisible {
17 | visibility: visible;
18 | }
19 |
20 | &__showOnHover {
21 | visibility: hidden;
22 |
23 | &-show {
24 | visibility: visible;
25 | }
26 | }
27 |
28 | &__icon {
29 | max-width: fit-content;
30 | max-height: fit-content;
31 |
32 | &-big {
33 | font-size: rem(32);
34 | }
35 |
36 | &-small {
37 | font-size: rem(14);
38 | }
39 | }
40 |
41 | &:hover {
42 | visibility: visible;
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/lib/molecules/Copy/Copy.test.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { shallow, ShallowWrapper } from 'enzyme';
3 | import Copy, { ICopyProps } from './Copy';
4 |
5 | describe('Copy Component', () => {
6 | const defaultProps: ICopyProps = {
7 | size: 'medium',
8 | showOnHover: false,
9 | copyTooltipText: 'Copy',
10 | copiedTooltipText: 'Copied!'
11 | };
12 |
13 | const setup = (props?: ICopyProps): ShallowWrapper => {
14 | const finalProps = { ...defaultProps, ...props };
15 | return shallow();
16 | };
17 |
18 | const wrapper = setup();
19 | it('renders without crashing', () => {
20 | expect(wrapper.exists()).toBeTruthy();
21 | });
22 |
23 | it('renders the copy icon', () => {
24 | expect(wrapper.find('.copy__icon').exists()).toBeTruthy();
25 | });
26 |
27 | it('renders the correct tooltip text', () => {
28 | expect(wrapper.find('Tooltip').prop('title')).toBe(defaultProps.copyTooltipText);
29 | });
30 |
31 | it('renders the copy icon with displayOnHover', () => {
32 | const wrapper = setup({ showOnHover: true });
33 | expect(wrapper.find('.copy__showOnHover').exists()).toBeTruthy();
34 | });
35 | });
36 |
--------------------------------------------------------------------------------
/src/lib/molecules/Copy/index.tsx:
--------------------------------------------------------------------------------
1 | export { ICopyProps, default as default } from './Copy';
2 |
--------------------------------------------------------------------------------
/src/lib/molecules/Counter/index.mobile.js:
--------------------------------------------------------------------------------
1 | export * from './index';
2 |
--------------------------------------------------------------------------------
/src/lib/molecules/DatePickerInput/index.js:
--------------------------------------------------------------------------------
1 | // Styles
2 | import './index.scss';
3 |
4 | // Local components
5 | import DatePickerInput from './DateInput';
6 | import DateRangeInput from './DateRangeInput';
7 |
8 | DatePickerInput.WithRange = DateRangeInput;
9 |
10 | export default DatePickerInput;
11 |
--------------------------------------------------------------------------------
/src/lib/molecules/ExtendedInput/index.mobile.js:
--------------------------------------------------------------------------------
1 | export * from './index';
2 |
--------------------------------------------------------------------------------
/src/lib/molecules/Grid/index.js:
--------------------------------------------------------------------------------
1 | export { default as Row } from './row';
2 | export { default as Col } from './col';
3 |
--------------------------------------------------------------------------------
/src/lib/molecules/Grid/index.mobile.js:
--------------------------------------------------------------------------------
1 | export * from './index';
2 |
--------------------------------------------------------------------------------
/src/lib/molecules/Grid/index.scss:
--------------------------------------------------------------------------------
1 | @import 'src/assets/styles/variables';
2 |
3 | .grid-holder {
4 | width: 100%;
5 | }
6 |
7 | .grid-items-group {
8 | width: 100%;
9 | display: flex;
10 | flex-wrap: wrap;
11 | }
12 |
13 | .grid-child {
14 | display: flex;
15 | }
16 |
--------------------------------------------------------------------------------
/src/lib/molecules/Grid/utils.js:
--------------------------------------------------------------------------------
1 | /* Recognizing screen size by configuration.
2 | * Now we have 5 supported screen sizes.
3 | */
4 |
5 | const getPartsByWindowSize = (size, options) => {
6 | let screenKey = 'xxl';
7 | let screenSize = options[screenKey];
8 |
9 | for (const key in options) {
10 | const value = options[key];
11 | // find value closest to our window size
12 | if (size <= value && value < screenSize) {
13 | screenKey = key;
14 | screenSize = value;
15 | }
16 | }
17 | return screenKey;
18 | };
19 |
20 | export { getPartsByWindowSize };
21 |
--------------------------------------------------------------------------------
/src/lib/molecules/InteractiveWidget/InteractiveWidgetIcon.tsx:
--------------------------------------------------------------------------------
1 | import React, { CSSProperties, FC, PropsWithChildren } from 'react';
2 | import classNames from 'classnames';
3 |
4 | //Components
5 | import Icon from '../../atoms/Icon';
6 |
7 | interface IInteractiveWidgetIconProps extends PropsWithChildren {
8 | appearance?: 'default' | 'compact';
9 | iconColor?: string;
10 | iconBackground?: boolean;
11 | }
12 |
13 | const InteractiveWidgetIcon: FC = ({
14 | children,
15 | iconColor,
16 | appearance,
17 | iconBackground
18 | }) => {
19 | return (
20 |
24 | {iconBackground &&
}
25 | {typeof children === 'string' ? (
26 | // @ts-ignore
27 |
28 | ) : (
29 | children
30 | )}
31 |
32 | );
33 | };
34 |
35 | export default InteractiveWidgetIcon;
36 |
--------------------------------------------------------------------------------
/src/lib/molecules/InteractiveWidget/index.tsx:
--------------------------------------------------------------------------------
1 | export { IInteractiveWidgetProps, default as default } from './InteractiveWidget';
2 |
--------------------------------------------------------------------------------
/src/lib/molecules/Menu/utils.js:
--------------------------------------------------------------------------------
1 | export const findDeep = (data, indexStack, index = 0) =>
2 | index < indexStack.length ? findDeep(data[indexStack[index]].children, indexStack, index + 1) : data;
3 |
--------------------------------------------------------------------------------
/src/lib/molecules/NavigationMenu/utils.js:
--------------------------------------------------------------------------------
1 | const getTitle = (id, data) => {
2 | if (data) {
3 | const matchedDatum = data.find((datum) => datum.id === id);
4 |
5 | return matchedDatum && matchedDatum.title
6 | ? matchedDatum
7 | : data.map((datum) => getTitle(id, datum.data)).filter(Boolean)[0];
8 | }
9 | };
10 |
11 | export const getTitlesArray = (ids, data) => ids.map((id) => getTitle(id, data)).filter(Boolean);
12 |
13 | export const navigationOptionsToMenu = (navigationOptions, optionId) =>
14 | navigationOptions.map(({ data, ...rest }) => ({
15 | ...rest,
16 | active: optionId?.toString() === rest.id.toString(),
17 | ...(data ? { children: navigationOptionsToMenu(data, optionId) } : {})
18 | }));
19 |
20 | export const indexStackFromItems = (stack, items, selectedItemId) => {
21 | if (!items?.length) {
22 | return [];
23 | }
24 |
25 | for (const itemIndex in items) {
26 | const item = items[itemIndex];
27 | if (item.id === selectedItemId) {
28 | return stack;
29 | }
30 |
31 | if (item.children) {
32 | const currentIndexStack = indexStackFromItems([...stack, Number(itemIndex)], item.children, selectedItemId);
33 | if (currentIndexStack.length) {
34 | return currentIndexStack;
35 | }
36 | }
37 | }
38 | return [];
39 | };
40 |
--------------------------------------------------------------------------------
/src/lib/molecules/Notification/index.mobile.js:
--------------------------------------------------------------------------------
1 | export * from './index';
2 |
--------------------------------------------------------------------------------
/src/lib/molecules/Pagination/index.mobile.js:
--------------------------------------------------------------------------------
1 | export * from './index';
2 |
--------------------------------------------------------------------------------
/src/lib/molecules/Pagination/index.scss:
--------------------------------------------------------------------------------
1 | .pagination-holder {
2 | display: flex;
3 | align-items: center;
4 |
5 | .icon {
6 | cursor: pointer;
7 | }
8 |
9 | .defaultCursor {
10 | cursor: default;
11 | }
12 |
13 | .input-element {
14 | text-align: center;
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/lib/molecules/Products/index.scss:
--------------------------------------------------------------------------------
1 | @import 'src/assets/styles/variables';
2 |
3 | .products-switcher-holder {
4 | display: flex;
5 | flex-wrap: wrap;
6 | width: 100%;
7 | padding: rem(5) rem(20);
8 | justify-content: flex-start;
9 | text-align: center;
10 |
11 | .divider {
12 | margin-left: auto;
13 | margin-right: auto;
14 | }
15 | }
16 |
17 | .product-item {
18 | display: flex;
19 | flex-wrap: wrap;
20 | justify-content: center;
21 | text-align: center;
22 | border: rem(1) solid transparent;
23 | padding: rem(10) rem(5);
24 | width: calc(100% / 3);
25 | border-radius: rem(10);
26 | font: 600 rem(12) / 1.42 $f;
27 | cursor: pointer;
28 | margin: rem(5) 0;
29 |
30 | .icon {
31 | display: flex;
32 | justify-content: center;
33 | align-items: center;
34 | width: rem(50);
35 | height: rem(50);
36 | margin: 0 0 rem(5);
37 | background: sc(b, 0.05);
38 | border-radius: 100%;
39 | transition: 200ms color, 200ms background;
40 | }
41 |
42 | p {
43 | width: 100%;
44 | }
45 | @include hover-active {
46 | .icon {
47 | color: sc(hero);
48 | background: c(hero);
49 | }
50 | }
51 |
52 | &.active {
53 | pointer-events: none;
54 | }
55 | @include hover {
56 | border-color: sc(b, 0.11);
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/src/lib/molecules/Profile/Languages/flags/de.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/src/lib/molecules/Profile/Languages/flags/en.svg:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------
/src/lib/molecules/Profile/Languages/flags/flagsIcons.js:
--------------------------------------------------------------------------------
1 | import en from './en.svg';
2 | import de from './de.svg';
3 | import es from './es.svg';
4 | import fr from './fr.svg';
5 | import hi from './hi.svg';
6 | import ko from './ko.svg';
7 | import pt from './pt.svg';
8 | import ro from './ro.svg';
9 | import ru from './ru.svg';
10 | import tr from './tr.svg';
11 | import zh from './zh.svg';
12 |
13 | const flagSVGs = { en, de, es, fr, hi, ko, pt, ro, ru, tr, zh };
14 |
15 | export default flagSVGs;
16 |
--------------------------------------------------------------------------------
/src/lib/molecules/Profile/Languages/flags/fr.svg:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------
/src/lib/molecules/Profile/Languages/flags/hi.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/lib/molecules/Profile/Languages/flags/ro.svg:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------
/src/lib/molecules/Profile/Languages/flags/ru.svg:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------
/src/lib/molecules/Profile/Languages/flags/tr.svg:
--------------------------------------------------------------------------------
1 |
9 |
--------------------------------------------------------------------------------
/src/lib/molecules/Profile/Languages/flags/zh.svg:
--------------------------------------------------------------------------------
1 |
12 |
--------------------------------------------------------------------------------
/src/lib/molecules/Profile/Languages/languagesDataModel.js:
--------------------------------------------------------------------------------
1 | const languagesDataModel = {
2 | en: {
3 | id: 'en',
4 | title: 'English'
5 | },
6 | ru: {
7 | id: 'ru',
8 | title: 'Russian'
9 | },
10 | es: {
11 | id: 'es',
12 | title: 'Spanish'
13 | },
14 | tr: {
15 | id: 'tr',
16 | title: 'Turkish'
17 | },
18 | zh: {
19 | id: 'zh',
20 | title: 'Chinese'
21 | },
22 | ko: {
23 | id: 'ko',
24 | title: 'Korean'
25 | },
26 | de: {
27 | id: 'de',
28 | title: 'German'
29 | },
30 | fr: {
31 | id: 'fr',
32 | title: 'France'
33 | },
34 | ro: {
35 | id: 'ro',
36 | title: 'Romanian'
37 | },
38 | pt: {
39 | id: 'pt',
40 | title: 'Portuguese'
41 | },
42 | hi: {
43 | id: 'hi',
44 | title: 'Hindi'
45 | }
46 | };
47 |
48 | export default languagesDataModel;
49 |
--------------------------------------------------------------------------------
/src/lib/molecules/Profile/ProfileModule.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | // Components
4 | import Avatar from '../../atoms/Avatar';
5 | import Divider from '../../atoms/Divider';
6 |
7 | // Styles
8 | import './index.scss';
9 |
10 | function ProfileModule({ username, email, avatarProps }) {
11 | return (
12 | <>
13 |
14 | -
15 |
16 |
17 | -
18 |
{username}
19 | {email}
20 |
21 |
22 |
23 | >
24 | );
25 | }
26 |
27 | export default ProfileModule;
28 |
--------------------------------------------------------------------------------
/src/lib/molecules/RadioGroup/index.mobile.js:
--------------------------------------------------------------------------------
1 | export * from './index';
2 |
--------------------------------------------------------------------------------
/src/lib/molecules/Section/index.scss:
--------------------------------------------------------------------------------
1 | @import 'src/assets/styles/variables';
2 |
3 | .section-holder {
4 | width: 100%;
5 | background: c(b);
6 | border: rem(1) solid sc(b, 0.1);
7 | border-radius: rem(20);
8 | padding: 0 rem(20) rem(20);
9 |
10 | & + & {
11 | margin: rem(13) 0 0;
12 | }
13 | }
14 |
15 | .section-head {
16 | display: flex;
17 | align-items: center;
18 | width: 100%;
19 | height: rem(54);
20 | }
21 |
22 | .section-body {
23 | display: flex;
24 | flex-direction: column;
25 | align-items: stretch;
26 | }
27 |
28 | .section-sub-group {
29 | width: 100%;
30 |
31 | &:not(:last-child) {
32 | margin-bottom: rem(14);
33 | }
34 |
35 | &:not(:first-child) {
36 | margin-top: rem(7);
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/lib/molecules/Steps/index.js:
--------------------------------------------------------------------------------
1 | export { default as Step } from './Step';
2 | export { default as Steps } from './Steps';
3 |
--------------------------------------------------------------------------------
/src/lib/molecules/SuggestionList/index.scss:
--------------------------------------------------------------------------------
1 | @import 'src/assets/styles/variables';
2 |
3 | .suggestion-list {
4 | overflow: hidden;
5 | position: fixed;
6 | background: c(b);
7 | border-radius: 1rem;
8 | box-shadow: 0 0.2rem 0.4rem 0 rgba(0, 0, 0, 5%), 0 0 0 1px rgba(#fff, 0.08);
9 | border: 1px solid rgba(0, 0, 0, 5%);
10 | z-index: 400;
11 | width: 200px;
12 |
13 | .suggestion-rows {
14 | width: 100%;
15 | font: 600 rem(14) / rem(18) $f;
16 |
17 | ul {
18 | width: 100%;
19 |
20 | li {
21 | width: 100%;
22 | display: flex;
23 | padding-left: 16px;
24 | align-items: center;
25 | height: rem(40);
26 | cursor: pointer;
27 | transition: 400ms background, 400ms color;
28 |
29 | &.hover {
30 | background: sc(b, 0.05);
31 | }
32 | }
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/lib/molecules/Tabs/index.js:
--------------------------------------------------------------------------------
1 | export { default as Tab } from './Tab';
2 | export { default as Tabs } from './Tabs';
3 |
--------------------------------------------------------------------------------
/src/lib/molecules/Textarea/index.scss:
--------------------------------------------------------------------------------
1 | @import 'src/assets/styles/variables';
2 |
--------------------------------------------------------------------------------
/src/lib/molecules/Timeline/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import classnames from 'classnames';
4 |
5 | // Helpers
6 | import { childrenOf } from 'utils';
7 |
8 | // Local components
9 | import TimelineItem, { timelineColors, timelineAppearances } from './item';
10 |
11 | // Styles
12 | import './index.scss';
13 |
14 | function Timeline(props) {
15 | const { children, className, ...restProps } = props;
16 |
17 | return (
18 |
19 | {children}
20 |
21 | );
22 | }
23 |
24 | Timeline.propTypes = {
25 | /**
26 | * External/Additional className
27 | */
28 | className: PropTypes.string,
29 | /**
30 | * Any valid React node.
31 | */
32 | children: childrenOf([TimelineItem])
33 | };
34 |
35 | export { Timeline, TimelineItem, timelineColors, timelineAppearances };
36 |
--------------------------------------------------------------------------------
/src/lib/molecules/Timeline/index.scss:
--------------------------------------------------------------------------------
1 | @import 'src/assets/styles/variables';
2 |
3 | .timeline-holder {
4 | display: flex;
5 | flex-direction: column;
6 | }
7 |
--------------------------------------------------------------------------------
/src/lib/molecules/Tooltip/Tooltip.scss:
--------------------------------------------------------------------------------
1 | @import 'src/assets/styles/variables';
2 |
3 | .tooltip {
4 | &-c-p {
5 | pointer-events: none;
6 | z-index: 10;
7 |
8 | .s-small & {
9 | padding: rem(15);
10 | }
11 | }
12 |
13 | &-wrapper {
14 | max-width: inherit;
15 | }
16 |
17 | &-content {
18 | border-radius: rem(4);
19 | padding: rem(6) rem(10);
20 | font: 600 rem(12) / rem(16) $f;
21 | background: sc(b, 0.6);
22 | color: c(b, 0.7);
23 | max-width: rem(200);
24 | word-break: break-word;
25 |
26 | > * + * {
27 | margin: rem(2) 0 0;
28 | }
29 |
30 | .s-small & {
31 | padding: rem(6) rem(8);
32 | font: 600 rem(10) / rem(14) $f;
33 | }
34 | }
35 |
36 | &-title {
37 | color: c(b);
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/lib/molecules/Tooltip/index.tsx:
--------------------------------------------------------------------------------
1 | export { ITooltipProps, default as default } from './Tooltip';
2 |
--------------------------------------------------------------------------------
/src/lib/molecules/Uploader/index.scss:
--------------------------------------------------------------------------------
1 | @import 'src/assets/styles/variables';
2 |
3 | .uploader-holder {
4 | width: 100%;
5 | display: flex;
6 | flex-direction: column;
7 | align-items: flex-start;
8 |
9 | .grid-child {
10 | position: relative;
11 | min-height: rem(28);
12 | }
13 | }
14 |
15 | .uploader-header {
16 | width: 100%;
17 | display: flex;
18 | flex-direction: column;
19 | align-items: flex-start;
20 |
21 | &:not(.only-child) {
22 | margin: 0 0 rem(14);
23 | }
24 | }
25 |
26 | .uploader-footer {
27 | width: 100%;
28 | display: flex;
29 | flex-direction: column;
30 | align-items: flex-start;
31 |
32 | .ua-cloud > & {
33 | align-items: center;
34 | }
35 |
36 | .ua-input > & {
37 | padding: 0 rem(20);
38 | }
39 |
40 | .uploader-footer-button {
41 | margin: rem(18) 0 0;
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/lib/molecules/Uploader/uploadedItem/Preview/index.scss:
--------------------------------------------------------------------------------
1 | @import 'src/assets/styles/variables';
2 |
3 | .media-preview-holder {
4 | position: fixed;
5 | top: 0;
6 | left: 0;
7 | width: 100%;
8 | height: 100%;
9 | background-color: rgba(0, 0, 0, 80%);
10 | color: white;
11 | display: flex;
12 | @include zIndex(preview);
13 |
14 | .bc-icon-close {
15 | position: absolute;
16 | top: rem(22);
17 | right: rem(22);
18 | cursor: pointer;
19 | }
20 | }
21 |
22 | .media-preview {
23 | margin: auto;
24 | display: flex;
25 | flex-direction: column;
26 | position: relative;
27 | padding: rem(30) 0 0;
28 |
29 | .mp-title {
30 | font: 600 rem(14) / rem(18) $f;
31 | position: absolute;
32 | top: 0;
33 | left: 0;
34 | width: 100%;
35 | }
36 | }
37 |
38 | .mp-details {
39 | margin: rem(5) 0 0;
40 | font: 600 rem(14) / rem(20) $f;
41 |
42 | > li {
43 | margin: rem(10) 0 0;
44 | }
45 |
46 | span {
47 | opacity: 0.7;
48 | }
49 | }
50 |
51 | .mp-element {
52 | width: auto;
53 | height: auto;
54 | max-width: 100%;
55 | max-height: calc(100vh - #{rem(200)});
56 | }
57 |
--------------------------------------------------------------------------------
/src/lib/molecules/ValidatableElements/Elements/index.mobile.js:
--------------------------------------------------------------------------------
1 | export * from '../index';
2 |
--------------------------------------------------------------------------------
/src/lib/molecules/ValidatableElements/index.js:
--------------------------------------------------------------------------------
1 | export { default as ValidatableDropdown } from './Elements/ValidatableDropdown';
2 | export { default as MultiSelectDropdownField } from './Elements/ValidatableMultiSelectDropdown';
3 | export { default as ValidatableEditor } from '../../organisms/Editor';
4 |
5 | export { default as ValidatableUploader } from './Elements/ValidatableUploader';
6 | export { default as ValidatableRadio } from './Elements/ValidatableRadio';
7 | export { default as ValidatableCheckbox } from './Elements/ValidatableCheckbox';
8 | export { default as ValidatableSwitcher } from './Elements/ValidatableSwitcher';
9 |
10 | export { default as ValidatableNumberInput } from './Elements/ValidatableNumberInput';
11 | export { default as ValidatableTextInput } from './Elements/ValidatableTextInput';
12 | export { default as ValidatableDatePicker } from './Elements/ValidatableDatePicker';
13 |
--------------------------------------------------------------------------------
/src/lib/organisms/ActionableList/config.js:
--------------------------------------------------------------------------------
1 | // @TODO think about internalization give possibilities to
2 | // pass tooltip texts via props refactor code duplications
3 | export const searchMethods = {
4 | like: {
5 | value: 'like',
6 | tooltipText:
7 | 'Your typed text will be applied to the last level of the data and will use the "like search" algorithm.'
8 | },
9 | startsWith: {
10 | value: 'startsWith',
11 | tooltipText:
12 | 'Your typed text will be applied to the last level of the data and will use the "starts with search" algorithm.'
13 | },
14 | endsWith: {
15 | value: 'endsWith',
16 | tooltipText:
17 | 'Your typed text will be applied to the last level of the data and will use the "ends with search" algorithm.'
18 | }
19 | };
20 |
21 | export const searchFunctions = {
22 | [searchMethods.like.value]: (label, searchKey) => `${label}`.toLowerCase().includes(searchKey.toLowerCase()),
23 | [searchMethods.startsWith.value]: (label, searchKey) => label.toLowerCase().startsWith(searchKey.toLowerCase()),
24 | [searchMethods.endsWith.value]: (label, searchKey) => label.toLowerCase().endsWith(searchKey.toLowerCase())
25 | };
26 |
--------------------------------------------------------------------------------
/src/lib/organisms/CardList/WrappedCardList/PaperWrapper/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | // Components
5 | import Paper from '../../../../atoms/Paper';
6 |
7 | function PaperWrapper({ paperDirection, cornerRadius, className, children, shadow, ...restProps }) {
8 | return (
9 |
16 | {children}
17 |
18 | );
19 | }
20 |
21 | PaperWrapper.propTypes = {
22 | className: PropTypes.string,
23 | children: PropTypes.node.isRequired,
24 | cornerRadius: PropTypes.string,
25 | shadow: PropTypes.bool,
26 | ...Paper.propTypes
27 | };
28 |
29 | PaperWrapper.defaultProps = {
30 | shadow: false,
31 | cornerRadius: 'full-radius',
32 | paperDirection: 'column'
33 | };
34 |
35 | export default PaperWrapper;
36 |
--------------------------------------------------------------------------------
/src/lib/organisms/CardList/WrappedCardList/WithTitle/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | // Components
5 | import ModuleTitle from '../../../../atoms/ModuleTitle';
6 |
7 | function WithTitle({ name, actions, children, ...restProps }) {
8 | return (
9 | <>
10 |
11 | {actions}
12 |
13 | {children}
14 | >
15 | );
16 | }
17 |
18 | WithTitle.propTypes = {
19 | name: PropTypes.oneOfType([PropTypes.string, PropTypes.node]).isRequired,
20 | actions: PropTypes.node,
21 | children: PropTypes.node
22 | };
23 |
24 | export default WithTitle;
25 |
--------------------------------------------------------------------------------
/src/lib/organisms/CardList/index.js:
--------------------------------------------------------------------------------
1 | export { default as WrappedCardList } from './WrappedCardList';
2 | export { default as CardList } from './DefaultCardList';
3 |
--------------------------------------------------------------------------------
/src/lib/organisms/CheckboxGroup/index.mobile.js:
--------------------------------------------------------------------------------
1 | export * from './index';
2 |
--------------------------------------------------------------------------------
/src/lib/organisms/CheckboxGroupWithSearch/index.scss:
--------------------------------------------------------------------------------
1 | @import 'src/assets/styles/variables';
2 |
3 | .checkbox-group-with-search-holder {
4 | width: 100%;
5 | background: c(b);
6 | }
7 |
8 | .empty-data-holder {
9 | width: 100%;
10 | height: rem(190);
11 | display: flex;
12 | justify-content: center;
13 | align-items: center;
14 | }
15 |
16 | .c-g-w-s-content {
17 | display: flex;
18 | flex-direction: column;
19 | width: 100%;
20 | background: sc(b, 0.01);
21 |
22 | > li {
23 | width: 100%;
24 | display: flex;
25 | }
26 | }
27 |
28 | .c-g-w-s-head {
29 | padding: rem(15);
30 | border-bottom: rem(1) solid sc(b, 0.1);
31 | }
32 |
33 | .c-g-w-s-footer {
34 | padding: rem(15) 0;
35 | display: flex;
36 | justify-content: center;
37 | border-top: rem(1) solid sc(b, 0.1);
38 |
39 | > * {
40 | + * {
41 | margin-inline-start: rem(10);
42 | }
43 | }
44 | }
45 |
46 | .c-g-w-s-body-content {
47 | width: 100%;
48 | padding: rem(15) 0;
49 | max-height: rem((15 * 2) + (40 * 7));
50 | }
51 |
52 | .grouped-checkbox-with-search {
53 | flex-direction: column;
54 |
55 | > div {
56 | padding: 1rem !important;
57 | }
58 | }
59 |
60 | .checkbox-group-with-search-holder {
61 | .crs-holder.active {
62 | @media (hover: hover) {
63 | background: sc(b, 0.05);
64 | }
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/src/lib/organisms/DateFilter/index.scss:
--------------------------------------------------------------------------------
1 | @import 'src/assets/styles/variables';
2 |
3 | .date-filters-holder {
4 | display: flex;
5 | align-items: center;
6 | width: 100%;
7 | justify-content: flex-end;
8 |
9 | > *:not(:last-child) {
10 | flex-shrink: 0;
11 | }
12 | }
13 |
14 | .date-filter-input {
15 | margin-inline-start: rem(10);
16 |
17 | .input-structure {
18 | @include rtlp(padding-right, padding-left, 0);
19 | }
20 |
21 | .icon {
22 | width: rem(36);
23 | height: rem(36);
24 | border-radius: var(--input-element-border-radius, 100%);
25 | @include rtl(margin, 0 0 0 rem(5), 0 rem(5) 0 0);
26 | }
27 |
28 | &.active {
29 | .icon {
30 | background: c(hero);
31 | color: sc(hero);
32 | }
33 |
34 | .input-element-back {
35 | background: transparent;
36 | border-color: c(hero);
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/lib/organisms/DatePicker/Context/configs.js:
--------------------------------------------------------------------------------
1 | const configs = {
2 | weekdays: ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'],
3 | months: [
4 | 'January',
5 | 'February',
6 | 'March',
7 | 'April',
8 | 'May',
9 | 'June',
10 | 'July',
11 | 'August',
12 | 'September',
13 | 'October',
14 | 'November',
15 | 'December'
16 | ],
17 | weekdaysSlice: 1,
18 | monthsSlice: 3,
19 | weekStart: 1,
20 | buttons: {
21 | today: 'Today',
22 | apply: 'Apply',
23 | thisMonth: 'This Month',
24 | thisWeek: 'This Week'
25 | },
26 | actions: {
27 | today: 'Today',
28 | yesterday: 'Yesterday',
29 | last7Days: 'Last 7 days',
30 | last30Days: 'Last 30 days',
31 | thisMonth: 'This Month',
32 | custom: 'Custom'
33 | }
34 | };
35 |
36 | export default configs;
37 |
--------------------------------------------------------------------------------
/src/lib/organisms/DatePicker/Context/index.js:
--------------------------------------------------------------------------------
1 | import React, { createContext, useState, useCallback, useContext } from 'react';
2 | import defaultConfigs from './configs';
3 |
4 | const Context = createContext([defaultConfigs]);
5 |
6 | function Provider({ children }) {
7 | const [state, setState] = useState(defaultConfigs);
8 |
9 | const setter = useCallback((next) => {
10 | setState({ ...defaultConfigs, ...next });
11 | }, []);
12 |
13 | return {children};
14 | }
15 |
16 | const useDatePickerContext = () => {
17 | const [configs, setConfigs] = useContext(Context);
18 | return [configs, setConfigs];
19 | };
20 |
21 | export { Provider, useDatePickerContext };
22 | export default Context;
23 |
--------------------------------------------------------------------------------
/src/lib/organisms/DatePicker/Days/index.js:
--------------------------------------------------------------------------------
1 | import Days from './Days';
2 |
3 | export default Days;
4 |
--------------------------------------------------------------------------------
/src/lib/organisms/DatePicker/RangeOptions/index.js:
--------------------------------------------------------------------------------
1 | export RangeOptions from './RangeOptions';
2 |
--------------------------------------------------------------------------------
/src/lib/organisms/DatePicker/RangeOptions/options.js:
--------------------------------------------------------------------------------
1 | import dayjs from 'dayjs';
2 |
3 | // Helpers
4 | import { addTime } from '../utils';
5 |
6 | const getDefaultOptions = ([startTime, endTime], actionsTextes = {}) => [
7 | {
8 | name: actionsTextes.today,
9 | start: addTime(dayjs().startOf('d'), startTime),
10 | end: addTime(dayjs().add(1, 'd').startOf('d'), endTime)
11 | },
12 | {
13 | name: actionsTextes.yesterday,
14 | start: addTime(dayjs().subtract(1, 'd').startOf('d'), startTime),
15 | end: addTime(dayjs().startOf('d'), endTime)
16 | },
17 | {
18 | name: actionsTextes.last7Days,
19 | start: addTime(dayjs().subtract(6, 'd').startOf('d'), startTime),
20 | end: addTime(dayjs().endOf('d'), endTime)
21 | },
22 | {
23 | name: actionsTextes.last30Days,
24 | start: addTime(dayjs().subtract(29, 'd').startOf('d'), startTime),
25 | end: addTime(dayjs().startOf('d'), endTime)
26 | },
27 | {
28 | name: actionsTextes.thisMonth,
29 | start: addTime(dayjs().startOf('M').startOf('d'), startTime),
30 | end: addTime(dayjs().endOf('M').startOf('d'), endTime)
31 | }
32 | ];
33 |
34 | const getOptionIndex = (rangeStart, rangeEnd, options) =>
35 | options.findIndex(
36 | ({ start, end }) => rangeStart && rangeEnd && start.isSame(rangeStart, 'd') && end.isSame(rangeEnd, 'd')
37 | );
38 |
39 | export { getDefaultOptions, getOptionIndex };
40 |
--------------------------------------------------------------------------------
/src/lib/organisms/DatePicker/index.js:
--------------------------------------------------------------------------------
1 | // Styles
2 | import './index.scss';
3 |
4 | // Local components
5 | import DatePicker from './DatePicker';
6 | import WeekPicker from './WeekPicker';
7 | import MonthPicker from './MonthPicker';
8 | import RangePicker from './RangePicker';
9 | import Context, { Provider, useDatePickerContext } from './Context';
10 |
11 | DatePicker.WeekPicker = WeekPicker;
12 | DatePicker.MonthPicker = MonthPicker;
13 | DatePicker.RangePicker = RangePicker;
14 | DatePicker.Context = Context;
15 | DatePicker.Provider = Provider;
16 | DatePicker.useDatePickerContext = useDatePickerContext;
17 |
18 | export default DatePicker;
19 |
--------------------------------------------------------------------------------
/src/lib/organisms/DatePicker/utils/addTime.js:
--------------------------------------------------------------------------------
1 | const addTime = (date, [hour, minute, second]) => date.hour(hour).minute(minute).second(second);
2 |
3 | export default addTime;
4 |
--------------------------------------------------------------------------------
/src/lib/organisms/DatePicker/utils/disableUtils.js:
--------------------------------------------------------------------------------
1 | const nextMonthAvailable = (date, max) => !max || date.add(1, 'M').isBefore(max, 'M');
2 | const prevMonthAvailable = (date, min) => !min || date.subtract(1, 'M').isAfter(min, 'M');
3 |
4 | export { nextMonthAvailable, prevMonthAvailable };
5 |
--------------------------------------------------------------------------------
/src/lib/organisms/DatePicker/utils/getCalendarDays.js:
--------------------------------------------------------------------------------
1 | const DAYS_TO_SHOW = 6 * 7;
2 |
3 | function getCalendarDays(startOfMonth) {
4 | const firstWeekDay = startOfMonth.day();
5 | // Because of using Monday as week start
6 | const startDiff = firstWeekDay === 0 ? 6 : firstWeekDay - 1;
7 | const first = startOfMonth.subtract(startDiff, 'days');
8 |
9 | const days = Array(DAYS_TO_SHOW)
10 | .fill()
11 | .map((_, i) => first.add(i, 'd'));
12 |
13 | return days;
14 | }
15 |
16 | export default getCalendarDays;
17 |
--------------------------------------------------------------------------------
/src/lib/organisms/DatePicker/utils/getCalendarMonths.js:
--------------------------------------------------------------------------------
1 | function getCalendarMonths(startOfYear) {
2 | const end = startOfYear.endOf('y');
3 |
4 | let pointer = startOfYear;
5 | const months = [];
6 |
7 | while (pointer.isBefore(end)) {
8 | months.push(pointer);
9 | pointer = pointer.add(1, 'M');
10 | }
11 |
12 | return months;
13 | }
14 |
15 | export default getCalendarMonths;
16 |
--------------------------------------------------------------------------------
/src/lib/organisms/DatePicker/utils/getCalendarYears.js:
--------------------------------------------------------------------------------
1 | const getCalendarYears = (startYear) =>
2 | Array(12)
3 | .fill(startYear - 1)
4 | .map((item, i) => item + i);
5 |
6 | const getStartOfDecade = (year) => Math.floor(year / 10) * 10;
7 |
8 | const nextDecade = (date) => date.set('y', getStartOfDecade(date.year()) + 10).startOf('y');
9 | const prevDecade = (date) => date.set('y', getStartOfDecade(date.year()) - 10).startOf('y');
10 |
11 | export { getCalendarYears, getStartOfDecade, nextDecade, prevDecade };
12 |
--------------------------------------------------------------------------------
/src/lib/organisms/DatePicker/utils/getRange.js:
--------------------------------------------------------------------------------
1 | function getRange(rangeStart, rangeEnd, selected) {
2 | return !rangeStart || rangeEnd
3 | ? [selected, null]
4 | : selected.isBefore(rangeStart)
5 | ? [selected, rangeStart]
6 | : [rangeStart, selected];
7 | }
8 |
9 | export default getRange;
10 |
--------------------------------------------------------------------------------
/src/lib/organisms/DatePicker/utils/index.js:
--------------------------------------------------------------------------------
1 | export getRange from './getRange';
2 | export addTime from './addTime';
3 | export getCalendarDays from './getCalendarDays';
4 | export getCalendarMonths from './getCalendarMonths';
5 | export * from './getCalendarYears';
6 | export * from './disableUtils';
7 |
--------------------------------------------------------------------------------
/src/lib/organisms/Form/Formables/FormableCheckbox.js:
--------------------------------------------------------------------------------
1 | import CheckboxField from '../FormableHOC';
2 | import ValidatableCheckbox from '../../../molecules/ValidatableElements/Elements/ValidatableCheckbox';
3 |
4 | export default CheckboxField(ValidatableCheckbox);
5 |
--------------------------------------------------------------------------------
/src/lib/organisms/Form/Formables/FormableDatePicker.js:
--------------------------------------------------------------------------------
1 | import DatePicker from '../FormableHOC';
2 | import ValidatableDatePicker from '../../../molecules/ValidatableElements/Elements/ValidatableDatePicker';
3 |
4 | export default DatePicker(ValidatableDatePicker);
5 |
--------------------------------------------------------------------------------
/src/lib/organisms/Form/Formables/FormableDropdown.js:
--------------------------------------------------------------------------------
1 | import DropdownField from '../FormableHOC';
2 | import ValidatableDropdown from '../../../molecules/ValidatableElements/Elements/ValidatableDropdown';
3 |
4 | export default DropdownField(ValidatableDropdown);
5 |
--------------------------------------------------------------------------------
/src/lib/organisms/Form/Formables/FormableEditor.js:
--------------------------------------------------------------------------------
1 | import Editor from '../FormableHOC';
2 | import ValidatableEditor from '../../Editor';
3 |
4 | export default Editor(ValidatableEditor);
5 |
--------------------------------------------------------------------------------
/src/lib/organisms/Form/Formables/FormableMultiSelectDropdown.js:
--------------------------------------------------------------------------------
1 | import FormableHOC from '../FormableHOC';
2 | import MultiSelectDropdownField from '../../../molecules/ValidatableElements/Elements/ValidatableMultiSelectDropdown';
3 |
4 | export default FormableHOC(MultiSelectDropdownField);
5 |
--------------------------------------------------------------------------------
/src/lib/organisms/Form/Formables/FormableNumberInput.js:
--------------------------------------------------------------------------------
1 | import NumberInput from '../FormableHOC';
2 | import ValidatableNumberInput from '../../../molecules/ValidatableElements/Elements/ValidatableNumberInput';
3 |
4 | export default NumberInput(ValidatableNumberInput);
5 |
--------------------------------------------------------------------------------
/src/lib/organisms/Form/Formables/FormableRadio.js:
--------------------------------------------------------------------------------
1 | import Radio from '../FormableHOC';
2 | import ValidatableRadio from '../../../molecules/ValidatableElements/Elements/ValidatableRadio';
3 |
4 | export default Radio(ValidatableRadio);
5 |
--------------------------------------------------------------------------------
/src/lib/organisms/Form/Formables/FormableSwitcher.js:
--------------------------------------------------------------------------------
1 | import SwitcherElement from '../FormableHOC';
2 | import ValidatableSwitcher from '../../../molecules/ValidatableElements/Elements/ValidatableSwitcher';
3 |
4 | export default SwitcherElement(ValidatableSwitcher);
5 |
--------------------------------------------------------------------------------
/src/lib/organisms/Form/Formables/FormableTextInput.js:
--------------------------------------------------------------------------------
1 | import TextInput from '../FormableHOC';
2 | import ValidatableTextInput from '../../../molecules/ValidatableElements/Elements/ValidatableTextInput';
3 |
4 | export default TextInput(ValidatableTextInput);
5 |
--------------------------------------------------------------------------------
/src/lib/organisms/Form/Formables/FormableUploader.js:
--------------------------------------------------------------------------------
1 | import UploaderField from '../FormableHOC';
2 | import ValidatableUploader from '../../../molecules/ValidatableElements/Elements/ValidatableUploader';
3 |
4 | export default UploaderField(ValidatableUploader);
5 |
--------------------------------------------------------------------------------
/src/lib/organisms/Form/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | import FormContainer from './Formables/FormContainer';
5 |
6 | export FormableMultiSelectDropdown from './Formables/FormableMultiSelectDropdown';
7 | export FormableNumberInput from './Formables/FormableNumberInput';
8 | export FormableDatePicker from './Formables/FormableDatePicker';
9 | export FormableTextInput from './Formables/FormableTextInput';
10 | export FormableDropdown from './Formables/FormableDropdown';
11 | export FormableCheckbox from './Formables/FormableCheckbox';
12 | export FormableUploader from './Formables/FormableUploader';
13 | export FormableSwitcher from './Formables/FormableSwitcher';
14 | export FormableEditor from './Formables/FormableEditor';
15 | export FormableRadio from './Formables/FormableRadio';
16 | export FormableHOC from './FormableHOC';
17 |
18 | export default FormContainer;
19 |
--------------------------------------------------------------------------------
/src/lib/organisms/Form/index.scss:
--------------------------------------------------------------------------------
1 | @import 'src/assets/styles/variables';
2 |
3 | .form-buttons {
4 | margin: rem(20) 0 0;
5 |
6 | > * {
7 | + * {
8 | margin-inline-start: rem(10);
9 | }
10 | }
11 | }
12 |
13 | form {
14 | width: 100%;
15 | }
16 |
--------------------------------------------------------------------------------
/src/lib/organisms/RichEditor/index.js:
--------------------------------------------------------------------------------
1 | import RichEditor from './RichEditor';
2 |
3 | export default RichEditor;
4 |
--------------------------------------------------------------------------------
/src/lib/organisms/Table/Footer/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import classnames from 'classnames';
3 |
4 | // Local components
5 | import FooterItem from './item';
6 | import ActionBar from '../Row/actionBar';
7 |
8 | // Styles
9 | import './index.scss';
10 |
11 | function Footer({ values, orders, withRightCorner, withLeftCorners, stickyLeftExist, ...rest }) {
12 | return (
13 |
14 | {withLeftCorners.map(
15 | (item, index) =>
16 | item && (
17 |
23 | )
24 | )}
25 | {orders.map(({ id }, index) => (
26 |
27 | ))}
28 | {withRightCorner &&
}
29 |
30 | );
31 | }
32 |
33 | Footer.defaultProps = {
34 | values: {},
35 | withLeftCorners: []
36 | };
37 |
38 | export default Footer;
39 |
--------------------------------------------------------------------------------
/src/lib/organisms/Table/Footer/index.scss:
--------------------------------------------------------------------------------
1 | @import 'src/assets/styles/variables';
2 |
3 | .ta-footer {
4 | .ellipsis-text {
5 | user-select: all;
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/src/lib/organisms/Table/Row/Nested/body.js:
--------------------------------------------------------------------------------
1 | import React, { memo } from 'react';
2 | import isEqual from 'react-fast-compare';
3 |
4 | const Body = ({ rows, columns, isEditActive }) =>
5 | rows.length &&
6 | rows.map((row, index) =>
7 | row.render ? (
8 | row.render(row, index, columns.dataKey)
9 | ) : (
10 |
11 | {columns.map((column, index) => (
12 |
13 | {typeof row.data[column.dataKey] === 'function'
14 | ? row.data[column.dataKey](isEditActive, index, column.dataKey)
15 | : row.data[column.dataKey]}
16 |
17 | ))}
18 |
19 | )
20 | );
21 |
22 | export default memo(Body, isEqual);
23 |
--------------------------------------------------------------------------------
/src/lib/organisms/Table/Row/Nested/header.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | function Header({ columns }) {
4 | return (
5 |
6 | {columns.map((column, index) => {
7 | const { render, text } = column;
8 | const children = render ? render(column, index) : text;
9 |
10 | return (
11 |
14 | );
15 | })}
16 |
17 | );
18 | }
19 |
20 | export default Header;
21 |
--------------------------------------------------------------------------------
/src/lib/organisms/Table/Row/Nested/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | // Local components
4 | import Header from './header';
5 | import Body from './body';
6 |
7 | // Styles
8 | import './index.scss';
9 |
10 | function Nested({ rows, columns, isEditActive, ...restProps }) {
11 | return (
12 |
13 |
14 |
15 |
16 | );
17 | }
18 |
19 | Nested.defaultProps = {
20 | columns: [],
21 | rows: []
22 | };
23 |
24 | export default Nested;
25 |
--------------------------------------------------------------------------------
/src/lib/organisms/Table/Row/Nested/index.scss:
--------------------------------------------------------------------------------
1 | @import 'src/assets/styles/variables';
2 |
3 | .nested-table {
4 | width: 100%;
5 | display: flex;
6 | flex-direction: column;
7 | border-radius: rem(4);
8 | border: solid rem(1) sc(b, 0.1);
9 | font: 600 rem(14) / rem(20) $f;
10 | overflow: hidden;
11 | }
12 |
13 | .nt-row {
14 | width: 100%;
15 | display: flex;
16 |
17 | & ~ & {
18 | border-top: solid rem(1) sc(b, 0.1);
19 | }
20 | }
21 |
22 | .nt-head {
23 | background: sc(b, 0.04);
24 | font-weight: 700;
25 | }
26 |
27 | .nt-cell {
28 | padding: rem(11) rem(20);
29 | position: relative;
30 | width: 100%;
31 | display: flex;
32 | overflow: hidden;
33 | word-break: break-word;
34 |
35 | & ~ & {
36 | &::before {
37 | content: '';
38 | display: block;
39 | position: absolute;
40 | top: rem(10);
41 | bottom: rem(10);
42 | background: c(b);
43 | border-right: rem(1) solid sc(b, 0.15);
44 | @include rtlp(left, right, 0);
45 | }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/lib/organisms/Table/Row/actionBar.js:
--------------------------------------------------------------------------------
1 | import React, { memo } from 'react';
2 | import isEqual from 'react-fast-compare';
3 | import classnames from 'classnames';
4 |
5 | // Local components
6 | import ActionsWrapper from './actionsWrapper';
7 |
8 | function ActionBar({ children, lastColRef, stickyRightExist }) {
9 | return (
10 |
16 | {children &&
{children}}
17 |
18 | );
19 | }
20 |
21 | export default memo(ActionBar, isEqual);
22 |
--------------------------------------------------------------------------------
/src/lib/organisms/Table/Row/actionsWrapper.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { isFragment } from 'react-is';
3 |
4 | // Components
5 | import Button from '../../../atoms/Button';
6 |
7 | function ActionsWrapper({ children }) {
8 | return isFragment(children) || Array.isArray(children) ? (
9 | <>
10 |
15 |
18 | >
19 | ) : (
20 |
23 | );
24 | }
25 |
26 | export default ActionsWrapper;
27 |
--------------------------------------------------------------------------------
/src/lib/organisms/Table/utils/arrayReorder.js:
--------------------------------------------------------------------------------
1 | const arrayReorder = (array, from, to) => {
2 | const arrayCopy = [...array];
3 | const [removed] = arrayCopy.splice(from, 1);
4 |
5 | arrayCopy.splice(to, 0, removed);
6 | return arrayCopy;
7 | };
8 |
9 | export default arrayReorder;
10 |
--------------------------------------------------------------------------------
/src/lib/organisms/Table/utils/getOffsetValues.js:
--------------------------------------------------------------------------------
1 | export const getOffsetValuesAndSubscriptions = (
2 | state,
3 | index,
4 | updatedState,
5 | offsetLeft = 0,
6 | offSetRight = 0,
7 | subscribe,
8 | container,
9 | eventName
10 | ) => {
11 | const offset = Object.keys(updatedState)
12 | .map(Number)
13 | .reduce(
14 | (offsetCalc, item) => {
15 | if (index > item) {
16 | offsetCalc.left += updatedState[item].target.clientWidth;
17 | } else if (index < item) {
18 | offsetCalc.right += updatedState[item].target.clientWidth;
19 | }
20 | return offsetCalc;
21 | },
22 | {
23 | left: offsetLeft,
24 | right: offSetRight
25 | }
26 | );
27 |
28 | const subscriptions = subscribe(
29 | container,
30 | {
31 | left: updatedState[index].left,
32 | right: updatedState[index].right
33 | },
34 | eventName,
35 | { index, offset }
36 | );
37 |
38 | return {
39 | ...state,
40 | [index]: {
41 | ...updatedState[index],
42 | offset,
43 | subscriptions
44 | }
45 | };
46 | };
47 |
48 | export default getOffsetValuesAndSubscriptions;
49 |
--------------------------------------------------------------------------------
/src/lib/organisms/Table/utils/hasStickyElemens.js:
--------------------------------------------------------------------------------
1 | const hasStickyElements = (columnsObject) => {
2 | const keys = Object.keys(columnsObject);
3 | const stickyLeftExist = keys.some((column) => columnsObject[column].isStickyLeft);
4 | const stickyRightExist = keys.some((column) => columnsObject[column].isStickyRight);
5 |
6 | return {
7 | stickyLeftExist,
8 | stickyRightExist
9 | };
10 | };
11 |
12 | export default hasStickyElements;
13 |
--------------------------------------------------------------------------------
/src/lib/organisms/Table/utils/index.js:
--------------------------------------------------------------------------------
1 | export { default as observeStickyInfo } from './stickyInfo';
2 | export { default as useGetColsInfo } from './getColumnInfo';
3 | export { default as arrayReorder } from './arrayReorder';
4 | export { default as itemTypes } from './itemTypes';
5 | export { default as getOffsetValuesAndSubscriptions } from './getOffsetValues';
6 | export { default as hasStickyElements } from './hasStickyElemens';
7 | export { default as observeElementResize } from './observeElementResize';
8 | export { default as sortHandler } from './sortHandler';
9 | export { default as useSortConfigs } from './useSortConfigs';
10 |
--------------------------------------------------------------------------------
/src/lib/organisms/Table/utils/itemTypes.js:
--------------------------------------------------------------------------------
1 | const itemTypes = {
2 | th: 'TH',
3 | tr: 'TR'
4 | };
5 |
6 | export default itemTypes;
7 |
--------------------------------------------------------------------------------
/src/lib/organisms/Table/utils/observeElementResize.js:
--------------------------------------------------------------------------------
1 | import ResizeObserver from 'resize-observer-polyfill';
2 |
3 | const observeElementResize = (element, callback) => {
4 | const resizeObserver = new ResizeObserver(callback);
5 |
6 | if (element) {
7 | resizeObserver.observe(element);
8 | return {
9 | unobserve: () => resizeObserver.unobserve(element)
10 | };
11 | }
12 | };
13 |
14 | export default observeElementResize;
15 |
--------------------------------------------------------------------------------
/src/lib/organisms/Table/utils/sortHandler.js:
--------------------------------------------------------------------------------
1 | const sortHandler = (nextSortObject, setSortObject, onSortChange, sortableColumns, currentSortState) => {
2 | const { id, column, dataKey, index } = nextSortObject;
3 | const isSortable = typeof column.sortable === 'boolean' ? column.sortable : sortableColumns;
4 | const { id: currId, type: currType } = currentSortState;
5 |
6 | const type = id !== currId || !currType ? 'asc' : currType === 'asc' ? 'desc' : null;
7 |
8 | if (isSortable) {
9 | setSortObject({
10 | id,
11 | type,
12 | index
13 | });
14 | onSortChange(isSortable, id, index, dataKey, column, type);
15 | }
16 | };
17 |
18 | export default sortHandler;
19 |
--------------------------------------------------------------------------------
/src/lib/organisms/TableCompositions/Combo/index.scss:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/softconstruct/gene-ui-components/ab23d640aa07d2bc6c328037647402a515d6165f/src/lib/organisms/TableCompositions/Combo/index.scss
--------------------------------------------------------------------------------
/src/lib/organisms/TableCompositions/Export/index.scss:
--------------------------------------------------------------------------------
1 | @import 'src/assets/styles/variables';
2 |
3 | .export-holder {
4 | display: flex;
5 | align-items: center;
6 | height: rem(28);
7 | padding-inline-end: rem(3);
8 | color: c(hero);
9 | user-select: none;
10 | transition: 400ms opacity;
11 |
12 | &.disabled {
13 | opacity: 0.5;
14 | pointer-events: none;
15 | }
16 |
17 | p {
18 | font-weight: 600;
19 | }
20 |
21 | .export-icon-holder {
22 | display: flex;
23 | align-items: center;
24 | justify-content: center;
25 | width: rem(24);
26 | height: rem(24);
27 | margin: 0 rem(5);
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/lib/organisms/TableCompositions/Header/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | // Helpers
5 | import { WithHeader } from '../utils';
6 |
7 | // Components
8 | import Table from '../../Table';
9 |
10 | // Styles
11 | import './index.scss';
12 |
13 | function TableHeader({
14 | columns,
15 | withSearch,
16 | actions,
17 | handleSearch,
18 | checkAllText,
19 | leftHeaderActions,
20 | hideSearchDropdown,
21 | ...tableProps
22 | }) {
23 | return (
24 |
33 |
34 |
35 | );
36 | }
37 |
38 | TableHeader.propTypes = {
39 | /**
40 | * Define is search bar will shown or no
41 | */
42 | withSearch: PropTypes.bool,
43 | /**
44 | * Any valid react node
45 | */
46 | headerActions: PropTypes.node
47 | };
48 |
49 | export default TableHeader;
50 |
--------------------------------------------------------------------------------
/src/lib/organisms/TableCompositions/Header/index.scss:
--------------------------------------------------------------------------------
1 | @import 'src/assets/styles/variables';
2 |
3 | .table-actions {
4 | padding: rem(10);
5 | display: flex;
6 | align-items: center;
7 |
8 | > li {
9 | padding: rem(10);
10 | }
11 |
12 | .table-left-actions {
13 | flex: auto;
14 | }
15 |
16 | .table-right-actions {
17 | flex-shrink: 0;
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/lib/organisms/TableCompositions/Pagination/index.scss:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/softconstruct/gene-ui-components/ab23d640aa07d2bc6c328037647402a515d6165f/src/lib/organisms/TableCompositions/Pagination/index.scss
--------------------------------------------------------------------------------
/src/lib/organisms/TableCompositions/Title/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | // Helpers
5 | import { WithTitle } from '../utils';
6 |
7 | // Components
8 | import Table from '../../Table';
9 |
10 | function TableTitle({ name, titleActions, ...tableProps }) {
11 | return (
12 |
13 |
14 |
15 | );
16 | }
17 |
18 | TableTitle.propTypes = {
19 | /**
20 | * Any valid react node
21 | */
22 | titleActions: PropTypes.node,
23 | /**
24 | * Value for title
25 | */
26 | name: PropTypes.string.isRequired,
27 | /**
28 | * Callback for refresh icon click
29 | */
30 | onRefreshClick: PropTypes.func
31 | };
32 |
33 | export default TableTitle;
34 |
--------------------------------------------------------------------------------
/src/lib/organisms/TableCompositions/Wrapped/container.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import classnames from 'classnames';
4 |
5 | // Helpers
6 | import { PaperWrapper, WithTitle } from '../utils';
7 |
8 | // Local components
9 | import Header from '../Header';
10 |
11 | function WrapperTableContainer({ name, titleActions, headerActions, className, paperProps, ...headerProps }) {
12 | return (
13 |
19 |
20 |
21 |
22 |
23 | );
24 | }
25 |
26 | WrapperTableContainer.propTypes = {
27 | name: PropTypes.string.isRequired,
28 | titleActions: PropTypes.node,
29 | headerActions: PropTypes.node,
30 | ...Header.propTypes
31 | };
32 |
33 | export default WrapperTableContainer;
34 |
--------------------------------------------------------------------------------
/src/lib/organisms/TableCompositions/Wrapped/header.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import classnames from 'classnames';
3 |
4 | // Helpers
5 | import { PaperWrapper } from '../utils';
6 |
7 | // Local components
8 | import Header from '../Header';
9 |
10 | function WrapperTableWithHeader({ paperProps, ...props }) {
11 | return (
12 |
13 |
14 |
15 | );
16 | }
17 |
18 | export default WrapperTableWithHeader;
19 |
--------------------------------------------------------------------------------
/src/lib/organisms/TableCompositions/Wrapped/index.js:
--------------------------------------------------------------------------------
1 | export { default as TableHeader } from './header';
2 | export { default as TableTitle } from './title';
3 | export { default as TablePagination } from './pagination';
4 | export { default as TableContainer } from './container';
5 |
--------------------------------------------------------------------------------
/src/lib/organisms/TableCompositions/Wrapped/pagination.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import classnames from 'classnames';
3 |
4 | // Helpers
5 | import { PaperWrapper } from '../utils';
6 |
7 | // Local components
8 | import Pagination from '../Pagination';
9 |
10 | function WrapperTablePagination({ paperProps, ...props }) {
11 | return (
12 |
13 |
14 |
15 | );
16 | }
17 |
18 | export default WrapperTablePagination;
19 |
--------------------------------------------------------------------------------
/src/lib/organisms/TableCompositions/Wrapped/title.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import classnames from 'classnames';
3 |
4 | // Helpers
5 | import { PaperWrapper } from '../utils';
6 |
7 | // Local components
8 | import Title from '../Title';
9 |
10 | function WrapperTableTitle({ paperProps, ...props }) {
11 | return (
12 |
13 |
14 |
15 | );
16 | }
17 |
18 | export default WrapperTableTitle;
19 |
--------------------------------------------------------------------------------
/src/lib/organisms/TableCompositions/index.js:
--------------------------------------------------------------------------------
1 | export { TableHeader, TableTitle, TablePagination, TableContainer } from './Wrapped';
2 | export { WithTitle, WithHeader, PaperWrapper, PaginationSelector } from './utils';
3 | export { default as ComboTable } from './Combo';
4 |
--------------------------------------------------------------------------------
/src/lib/organisms/TableCompositions/utils/PaginationSelector/index.scss:
--------------------------------------------------------------------------------
1 | @import 'src/assets/styles/variables';
2 |
3 | .pagination-drop {
4 | display: flex;
5 | align-items: center;
6 |
7 | > {
8 | * + * {
9 | @include rtlp(margin-left, margin-right, rem(20));
10 | }
11 |
12 | p {
13 | font-weight: 600;
14 | }
15 | }
16 | }
17 |
18 | .ta-pagination-holder {
19 | width: 100%;
20 | padding: rem(10);
21 | display: flex;
22 | align-items: center;
23 | flex-shrink: 0;
24 | border-top: rem(1) solid sc(b, 0.1);
25 | flex-wrap: wrap;
26 | justify-content: flex-end;
27 |
28 | > li {
29 | padding: rem(10);
30 |
31 | &:first-child {
32 | flex: auto;
33 | }
34 |
35 | &:last-child {
36 | flex-shrink: 0;
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/lib/organisms/TableCompositions/utils/PaperWrapper/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import classnames from 'classnames';
4 |
5 | // Components
6 | import Paper from '../../../../atoms/Paper';
7 |
8 | function PaperWrapper({ className, shadow, cornerRadius, paperDirection, children, ...restProps }) {
9 | return (
10 |
17 | {children}
18 |
19 | );
20 | }
21 |
22 | PaperWrapper.propTypes = {
23 | className: PropTypes.string,
24 | children: PropTypes.node.isRequired,
25 | cornerRadius: PropTypes.string,
26 | shadow: PropTypes.bool
27 | };
28 |
29 | PaperWrapper.defaultProps = {
30 | shadow: true,
31 | cornerRadius: 'full-radius',
32 | paperDirection: 'column'
33 | };
34 |
35 | export default PaperWrapper;
36 |
--------------------------------------------------------------------------------
/src/lib/organisms/TableCompositions/utils/WithHeader/index.scss:
--------------------------------------------------------------------------------
1 | @import 'src/assets/styles/variables';
2 |
3 | .paper-actions {
4 | display: flex;
5 | align-items: center;
6 | flex-shrink: 0;
7 |
8 | > li {
9 | padding: rem(20);
10 | display: flex;
11 | align-items: center;
12 | }
13 |
14 | .paper-left-actions {
15 | flex: auto;
16 |
17 | > {
18 | .input-holder,
19 | .dropdown-holder {
20 | max-width: rem(255);
21 | }
22 | }
23 |
24 | > * {
25 | + * {
26 | @include rtlp(margin-left, margin-right, rem(20));
27 | }
28 | }
29 | }
30 |
31 | .paper-right-actions {
32 | flex-shrink: 0;
33 |
34 | > *:not(.btn) + *:not(.btn) {
35 | @include rtlp(margin-left, margin-right, rem(16));
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/lib/organisms/TableCompositions/utils/WithTitle/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | // Components
5 | import ModuleTitle from '../../../../atoms/ModuleTitle';
6 |
7 | function WithTitle({ name, actions, children, ...restProps }) {
8 | return (
9 | <>
10 | {(!!name || !!actions) && (
11 |
12 | {actions}
13 |
14 | )}
15 | {children}
16 | >
17 | );
18 | }
19 |
20 | WithTitle.propTypes = {
21 | name: PropTypes.oneOfType([PropTypes.string, PropTypes.node]).isRequired,
22 | actions: PropTypes.node,
23 | children: PropTypes.node
24 | };
25 |
26 | export default WithTitle;
27 |
--------------------------------------------------------------------------------
/src/lib/organisms/TableCompositions/utils/index.js:
--------------------------------------------------------------------------------
1 | export { default as WithTitle } from './WithTitle';
2 | export { default as WithHeader } from './WithHeader';
3 | export { default as PaperWrapper } from './PaperWrapper';
4 | export { default as PaginationSelector } from './PaginationSelector';
5 |
--------------------------------------------------------------------------------
/src/lib/organisms/Toaster/index.scss:
--------------------------------------------------------------------------------
1 | @import 'src/assets/styles/variables';
2 |
3 | .toaster-holder {
4 | position: fixed;
5 | padding: rem(15);
6 | max-width: rem(380);
7 | width: 100%;
8 | @include zIndex(toaster);
9 |
10 | > * + * {
11 | margin: rem(20) 0 0;
12 | }
13 |
14 | &.left-top {
15 | left: 0;
16 | top: var(--header-height, 0);
17 | }
18 |
19 | &.left-bottom {
20 | left: 0;
21 | bottom: 0;
22 | }
23 |
24 | &.right-top {
25 | right: 0;
26 | top: var(--header-height, 0);
27 | }
28 |
29 | &.right-bottom {
30 | right: 0;
31 | bottom: 0;
32 | }
33 |
34 | &.top,
35 | &.bottom {
36 | left: 50%;
37 | transform: translate3d(-50%, 0, 0);
38 | }
39 |
40 | &.top {
41 | top: var(--header-height, 0);
42 | }
43 |
44 | &.center {
45 | top: 50%;
46 | left: 50%;
47 | transform: translate3d(-50%, -50%, 0);
48 | }
49 |
50 | &.bottom {
51 | bottom: 0;
52 | }
53 | @include mobile {
54 | width: 100%;
55 | transform: none;
56 |
57 | &:not(.top, .bottom) {
58 | padding: 0;
59 | }
60 |
61 | &.center:not(.top, .bottom) {
62 | padding: 0 rem(15);
63 | }
64 | }
65 |
66 | &:empty {
67 | pointer-events: none;
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/src/lib/organisms/TransferList/Container/Buttons.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | // Components
4 | import Button from '../../../atoms/Button';
5 | import Tooltip from '../../../molecules/Tooltip';
6 |
7 | function TransferListButtons({ onTransmit, send, receive, readOnly }) {
8 | const handleReceive = () => onTransmit(send.id, receive.id);
9 | const handleSend = () => onTransmit(receive.id, send.id);
10 |
11 | return (
12 |
13 |
14 |
20 |
21 |
22 |
28 |
29 |
30 | );
31 | }
32 |
33 | export default TransferListButtons;
34 |
--------------------------------------------------------------------------------
/src/lib/organisms/TransferList/Element/index.js:
--------------------------------------------------------------------------------
1 | import React, { forwardRef } from 'react';
2 | import classnames from 'classnames';
3 |
4 | // Components
5 | import Icon from '../../../atoms/Icon';
6 | import Checkbox from '../../../molecules/Checkbox';
7 |
8 | // Styles
9 | import './index.scss';
10 |
11 | const TransferElement = forwardRef(
12 | ({ disabled, hovered, dragged, checked, label, onClick, readOnly, minimalistic, indeterminate }, ref) => (
13 |
24 |
25 | {!readOnly && !minimalistic && }
26 |
27 | )
28 | );
29 |
30 | export default TransferElement;
31 |
--------------------------------------------------------------------------------
/src/lib/organisms/TransferList/constants.js:
--------------------------------------------------------------------------------
1 | export const DEFAULT_TRANSLATE_MESSAGE = {
2 | empty: 'No data',
3 | dropHere: 'Drop Element Here',
4 | multiSelectText: 'Elements',
5 | moveTo: 'Move to'
6 | };
7 |
8 | export const DEFAULT_DATA_ERROR_MESSAGE =
9 | 'TransferList: Be sure to send the defaultDate according to the documentation standard';
10 |
--------------------------------------------------------------------------------
/src/lib/organisms/TransferList/index.scss:
--------------------------------------------------------------------------------
1 | @import 'src/assets/styles/variables';
2 |
3 | .bc-transfer-list {
4 | --transfer-container-border-color: #{sc(b, 0.1)};
5 | --transfer-container-content-height: #{rem(334)};
6 |
7 | width: 100%;
8 | display: flex;
9 | background: c(b);
10 | grid-template-columns: 1fr auto 1fr;
11 | box-shadow: 0 0 0 rem(1) var(--transfer-container-border-color);
12 | user-select: none;
13 |
14 | .scroll-holder {
15 | .scroll-content {
16 | z-index: inherit;
17 | }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/types/index.ts:
--------------------------------------------------------------------------------
1 | import { HTMLAttributes } from 'react';
2 |
3 | export interface IHTMLDivElementAttributes extends Omit, 'onKeyDown'> {}
4 |
--------------------------------------------------------------------------------
/src/utils/callAfterDelay.js:
--------------------------------------------------------------------------------
1 | import ReactDOM from 'react-dom';
2 |
3 | const callAfterDelay = (callBack, time) => {
4 | const timerId = setTimeout(() => {
5 | clearTimeout(timerId);
6 | ReactDOM.unstable_batchedUpdates(() => {
7 | callBack();
8 | });
9 | }, time);
10 | };
11 |
12 | export default callAfterDelay;
13 |
--------------------------------------------------------------------------------
/src/utils/checkTimeValidation.js:
--------------------------------------------------------------------------------
1 | const meridiemValues = ['am', 'pm'];
2 |
3 | export const checkTimeValidation = ({ hour, minute, second, meridiem }) => {
4 | const isHourValid = !hour.format || (meridiem ? hour.value < 12 : hour.value < 24);
5 |
6 | const isMinuteValid = !minute.format || (minute.value >= 0 && minute.value < 60);
7 |
8 | const isSecondValid = !second.format || (second.value >= 0 && second.value < 60);
9 |
10 | const isMeridiemValid =
11 | !meridiem || !meridiem.format || !meridiem.value || meridiemValues.includes(meridiem.value.toLowerCase());
12 |
13 | return isHourValid && isMinuteValid && isSecondValid && isMeridiemValid;
14 | };
15 |
--------------------------------------------------------------------------------
/src/utils/configs/tableConfigs.js:
--------------------------------------------------------------------------------
1 | export const searchConfigs = {
2 | types: ['text', 'select'],
3 | typeEnum: {
4 | text: 'text',
5 | select: 'select'
6 | }
7 | };
8 |
9 | export const resizeConfigs = {
10 | typeEnum: {
11 | resize: 'resize',
12 | autoSize: 'autoSize'
13 | }
14 | };
15 |
--------------------------------------------------------------------------------
/src/utils/copyToClipboard.js:
--------------------------------------------------------------------------------
1 | const copyToClipboard = (str) => {
2 | const el = document.createElement('textarea');
3 | el.value = str;
4 | document.body.appendChild(el);
5 | el.select();
6 | document.execCommand('copy');
7 | document.body.removeChild(el);
8 | };
9 |
10 | export default copyToClipboard;
11 |
--------------------------------------------------------------------------------
/src/utils/dateFormatChecker.js:
--------------------------------------------------------------------------------
1 | const nonLettersRegex = /[\W_]+/g;
2 |
3 | const dateFormats = ['YY', 'YYYY', 'M', 'MM', 'MMM', 'MMMM', 'D', 'DD'];
4 | const timeFormats = ['H', 'HH', 'h', 'hh', 'm', 'mm', 's', 'ss'];
5 |
6 | const getFormatSeparator = (format) => format[format.search(nonLettersRegex)];
7 |
8 | export const checkFormat = (format) => {
9 | const [dateFormatOnly, timeFormatOnly] = format.split(' ');
10 |
11 | const dateFormatSeparator = getFormatSeparator(dateFormatOnly);
12 | const timeFormatSeparator = timeFormatOnly && getFormatSeparator(timeFormatOnly);
13 | const isDateFormatValid = dateFormatOnly.split(dateFormatSeparator).every((part) => dateFormats.includes(part));
14 | const isTimeFormatValid =
15 | !timeFormatOnly || timeFormatOnly.split(timeFormatSeparator).every((part) => timeFormats.includes(part));
16 |
17 | return isDateFormatValid && isTimeFormatValid;
18 | };
19 |
--------------------------------------------------------------------------------
/src/utils/debounce.js:
--------------------------------------------------------------------------------
1 | export default function debounce(callback, wait, immediate) {
2 | let timeout;
3 |
4 | return function func() {
5 | const context = this;
6 | const args = arguments;
7 |
8 | const later = function () {
9 | timeout = null;
10 | if (!immediate) callback.apply(context, args);
11 | };
12 |
13 | const callNow = immediate && !timeout;
14 |
15 | clearTimeout(timeout);
16 |
17 | timeout = setTimeout(later, wait);
18 |
19 | if (callNow) callback.apply(context, args);
20 | };
21 | }
22 |
--------------------------------------------------------------------------------
/src/utils/guid.js:
--------------------------------------------------------------------------------
1 | /** UUID generator
2 | * Function provides "unique" id.
3 | * Must be used with React iterable components.
4 | */
5 |
6 | const hash = () =>
7 | Math.floor((1 + Math.random()) * 0x10000)
8 | .toString(16)
9 | .substring(1);
10 |
11 | /** @function guid
12 | * @description
13 | * The function generates uuid. It can be used as `key`-s needed for
14 | * React iterated components
15 | */
16 |
17 | const guid = () => `${hash() + hash()}-${hash()}-${hash()}-${hash()}-${hash()}${hash()}${hash()}`;
18 |
19 | export default guid;
20 |
--------------------------------------------------------------------------------
/src/utils/indexof.js:
--------------------------------------------------------------------------------
1 | // this file existance is
2 | // related with rc-slider package issue
3 |
4 | export default function (arr, obj) {
5 | if (arr.indexOf) return arr.indexOf(obj);
6 | for (let i = 0; i < arr.length; ++i) {
7 | if (arr[i] === obj) return i;
8 | }
9 | return -1;
10 | }
11 |
--------------------------------------------------------------------------------
/src/utils/logger.js:
--------------------------------------------------------------------------------
1 | class Logger {
2 | success(message) {
3 | console.log(`%c${message}`, 'color: green');
4 | }
5 |
6 | warning(message) {
7 | console.warn(message);
8 | }
9 |
10 | error(message) {
11 | console.error(message);
12 | }
13 |
14 | deprecate(message) {
15 | console.warn(`DEPRECATION WARNING(gene-ui): ${message}`);
16 | }
17 | }
18 |
19 | export default new Logger();
20 |
--------------------------------------------------------------------------------
/src/wrappers/dayjsWithPlugins.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Setup dayjs plugin.
3 | */
4 | import dayjs from 'dayjs';
5 | import customParseFormat from 'dayjs/plugin/customParseFormat';
6 | import isSameOrBefore from 'dayjs/plugin/isSameOrBefore';
7 | import isSameOrAfter from 'dayjs/plugin/isSameOrAfter';
8 | import isLeapYear from 'dayjs/plugin/isLeapYear';
9 | import isBetween from 'dayjs/plugin/isBetween';
10 |
11 | dayjs.extend(customParseFormat);
12 | dayjs.extend(isSameOrBefore);
13 | dayjs.extend(isSameOrAfter);
14 | dayjs.extend(isLeapYear);
15 | dayjs.extend(isBetween);
16 |
17 | export const dayjsWithPlugins = dayjs;
18 |
--------------------------------------------------------------------------------
/src/wrappers/index.js:
--------------------------------------------------------------------------------
1 | export * from './dayjsWithPlugins';
2 |
--------------------------------------------------------------------------------
/stories/atoms/Icon/Icon.stories.scss:
--------------------------------------------------------------------------------
1 | #docs-root {
2 | .iconsSearch {
3 | display: none;
4 | }
5 | }
6 |
7 | .iconsSearch {
8 | position: fixed;
9 | z-index: 10;
10 | top: 0;
11 | left: 0;
12 | background: rgba(var(--background-rgb), 1);
13 | width: 100%;
14 | padding: 10px 15px;
15 | }
16 |
17 | .iconsWrapper {
18 | display: flex;
19 | flex-wrap: wrap;
20 | margin-top: 50px;
21 | }
22 |
23 | .iconButton {
24 | width: calc(25% - 10px);
25 | display: flex;
26 | align-items: center;
27 | padding: 10px;
28 | margin: 5px;
29 | cursor: pointer;
30 | border-radius: var(--button-external-border-radius, 0.4rem);
31 | background: rgba(var(--background-rgb), 0.8);
32 | border-left: 3px solid transparent;
33 |
34 | &:hover {
35 | border-left: 3px solid #e90789;
36 | }
37 |
38 | &_name {
39 | max-width: 100%;
40 | }
41 |
42 | &_svg {
43 | margin-right: 5px;
44 | }
45 | }
46 |
47 | .noData_empty {
48 | position: relative;
49 | left: 50%;
50 | transform: translateX(-50%);
51 | }
52 |
53 | .icons_loader {
54 | margin-top: 80px;
55 | }
56 |
57 | .icon_loader {
58 | align-items: flex-start;
59 | }
60 |
--------------------------------------------------------------------------------
/stories/atoms/Label/LabelValue.stories.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import LabelComponent from 'src/lib/atoms/Label/index';
4 | import { args, category } from '../../assets/storybook.globals';
5 |
6 | export default {
7 | title: 'Atoms/Label',
8 | component: LabelComponent,
9 | argTypes: {
10 | font: args({ control: 'select', category: category.appearance }),
11 | children: args({ control: 'text', category: category.content }),
12 | size: args({ control: 'select', category: category.appearance }),
13 | className: args({ control: false, category: category.others })
14 | }
15 | };
16 |
17 | const Template = ({ children, ...args }) => {children};
18 |
19 | export const Label = Template.bind({});
20 | Label.args = {
21 | size: 'content',
22 | font: 'semiBold',
23 | children: 'Some Label'
24 | };
25 |
--------------------------------------------------------------------------------
/stories/atoms/ModuleTitle/data.js:
--------------------------------------------------------------------------------
1 | export const data = [
2 | {
3 | title: 'Title 1',
4 | slug: 'title1'
5 | },
6 | {
7 | title: 'Title 2',
8 | slug: 'title2'
9 | },
10 | {
11 | title: 'Title 3',
12 | slug: 'title3'
13 | },
14 | {
15 | title: 'Title 4',
16 | slug: 'title4'
17 | },
18 | {
19 | title: 'Title 5',
20 | slug: 'title5'
21 | },
22 | {
23 | title: 'Title 6',
24 | slug: 'title6'
25 | }
26 | ];
27 |
--------------------------------------------------------------------------------
/stories/atoms/Paper/index.scss:
--------------------------------------------------------------------------------
1 | @import 'src/assets/styles/variables';
2 |
3 | .fake-paper-placeholder {
4 | margin: rem(10);
5 | border-radius: rem(4);
6 | border: rem(1) solid sc(b, 0.1);
7 | font: 600 rem(14) / rem(46) $f;
8 | padding: 0 rem(36);
9 | }
10 |
--------------------------------------------------------------------------------
/stories/atoms/QRCode/QRCode.stories.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import QRCodeComponent from 'src/lib/atoms/QRCode';
4 | import { args, category } from '../../assets/storybook.globals';
5 |
6 | const QRConfig = {
7 | level: ['L', 'M', 'Q', 'H']
8 | };
9 | export default {
10 | title: 'Atoms/QRCode',
11 | component: QRCodeComponent,
12 | darkMode: {
13 | stylePreview: true
14 | },
15 | // src, icon, size, color, shape, onClick, children
16 | argTypes: {
17 | value: args({ control: 'text', category: category.content }),
18 | maxSize: args({ control: 'number', category: category.appearance }),
19 | level: args({ control: 'select', category: category.appearance })
20 | },
21 | args: {
22 | value: 'https://en.wikipedia.org/wiki/QR_code',
23 | maxSize: 400,
24 | level: QRConfig.level[0]
25 | }
26 | };
27 |
28 | export let QRCode = ({ ...args }) => ;
29 |
--------------------------------------------------------------------------------
/stories/atoms/Skeleton/index.scss:
--------------------------------------------------------------------------------
1 | .skeleton-story-wrapper {
2 | background: var(--background);
3 | padding: 20px;
4 | }
5 |
--------------------------------------------------------------------------------
/stories/atoms/TextLink/TextLink.stories.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import TextLinkComponent from 'src/lib/atoms/TextLink/index';
4 | import { args, category, componentStage } from '../../assets/storybook.globals';
5 |
6 | export default {
7 | title: 'Atoms/TextLink-d',
8 | component: TextLinkComponent,
9 | argTypes: {
10 | className: args({ control: false, category: category.others }),
11 | children: args({ control: 'text', category: category.content })
12 | },
13 | args: {
14 | componentStage: {
15 | type: componentStage.deprecated
16 | }
17 | }
18 | };
19 |
20 | const Template = ({ children, ...args }) => {children};
21 |
22 | export const TextLink = Template.bind({});
23 | TextLink.args = {
24 | children: 'Some link'
25 | };
26 |
--------------------------------------------------------------------------------
/stories/atoms/Time/Time.stories.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import TimeComponent from 'src/lib/atoms/Time/index';
4 | import { args, category } from '../../assets/storybook.globals';
5 |
6 | export default {
7 | title: 'Atoms/Time',
8 | component: TimeComponent,
9 | argTypes: {
10 | showIcon: args({ control: 'boolean', category: category.content }),
11 | format: args({ control: 'text', category: category.functionality }),
12 | startDate: args({ control: false, category: category.functionality }),
13 | showSeconds: args({ control: 'boolean', category: category.functionality })
14 | },
15 | args: {
16 | showIcon: true
17 | }
18 | };
19 |
20 | const Template = ({ ...args }) => ;
21 |
22 | export const DateAndTime = Template.bind({});
23 | DateAndTime.args = {
24 | format: 'DD/MM/YYYY HH:mm:ss',
25 | showSeconds: true
26 | };
27 | DateAndTime.argTypes = {
28 | showSeconds: args({
29 | table: {
30 | disable: true
31 | }
32 | })
33 | };
34 | export const TimeWithFormat = Template.bind({});
35 | TimeWithFormat.args = {
36 | showSeconds: false
37 | };
38 |
--------------------------------------------------------------------------------
/stories/atoms/Title/Title.stories.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import TitleComponent from 'src/lib/atoms/Title/index';
4 | import { args, category } from '../../assets/storybook.globals';
5 |
6 | import { titleConfig } from 'configs';
7 |
8 | export default {
9 | title: 'Atoms/Title',
10 | component: TitleComponent,
11 | argTypes: {
12 | text: args({ control: 'text', category: category.content }),
13 | icon: args({ control: 'text', category: category.content }),
14 | actions: args({ control: 'text', category: category.content }),
15 | color: args({
16 | control: 'select',
17 | defaultValue: titleConfig.color[0],
18 | options: titleConfig.color,
19 | category: category.appearance
20 | }),
21 | withLine: args({ control: 'boolean', category: category.appearance }),
22 | className: args({ control: false, category: category.others })
23 | },
24 | args: {
25 | actions: 'Text'
26 | }
27 | };
28 |
29 | const Template = ({ text, ...args }) => ;
30 |
31 | export const Title = Template.bind({});
32 | Title.args = {
33 | text: 'Some Text',
34 | icon: 'bc-icon-align-center',
35 | color: titleConfig.color[0],
36 | withLine: true
37 | };
38 |
--------------------------------------------------------------------------------
/stories/changelog.mdx:
--------------------------------------------------------------------------------
1 | import { Markdown , Meta} from '@storybook/blocks';
2 | import ChangelogMD from '../CHANGELOG.md';
3 |
4 |
5 |
6 |
7 | {ChangelogMD}
8 |
9 |
--------------------------------------------------------------------------------
/stories/gettingStarted.mdx:
--------------------------------------------------------------------------------
1 | import { Meta, Source } from '@storybook/blocks';
2 |
3 |
4 |
5 |
6 | # Getting started with
Gene UI components package
7 |
8 |
9 |
10 |
11 | ## Package installation
12 |
13 | Go to your project directory and run one of the following commands in your terminal
14 |
15 |
16 |
17 |
18 | If your favorite package manager is `Yarn`
19 |
20 |
21 |
22 |
23 |
24 | ## Usage
25 |
26 |
27 | At first you need to import the provider in your main component e.g. in the `App.js` file.
28 |
29 |
30 |
31 |
32 | Then you need to wrap your main component with provider
33 |
34 |
36 |
37 | `}
38 | language="jsx"
39 | />
40 |
41 |
42 | Now you can start use any components available in the package. Happy coding.
43 |
44 |
45 |
--------------------------------------------------------------------------------
/stories/index.stories.js:
--------------------------------------------------------------------------------
1 | import './atoms';
2 | import './molecules';
3 | import './organisms';
4 |
--------------------------------------------------------------------------------
/stories/molecules/Breadcrumb/Breadcrumb.stories.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import BreadcrumbComponent from 'src/lib/molecules/Breadcrumb';
4 | import { args, category } from '../../assets/storybook.globals';
5 | import { data } from './data';
6 |
7 | export default {
8 | title: 'Molecules/Breadcrumb',
9 | component: BreadcrumbComponent,
10 | argTypes: {
11 | data: args({ control: 'object', category: category.content }),
12 | className: args({ control: false, category: category.others }),
13 | onClick: args({ action: 'onClick', category: category.action }),
14 | separator: args({ control: 'text', category: category.content }),
15 | collapsed: args({ control: 'boolean', category: category.states })
16 | },
17 | args: {
18 | data: data,
19 | separator: '>',
20 | collapsed: true
21 | }
22 | };
23 |
24 | export const Breadcrumb = ({ ...args }) => ;
25 |
--------------------------------------------------------------------------------
/stories/molecules/Breadcrumb/data.js:
--------------------------------------------------------------------------------
1 | export const data = [
2 | {
3 | title: 'Title 1',
4 | slug: 'title1'
5 | },
6 | {
7 | title: 'Title 2',
8 | slug: 'title2'
9 | },
10 | {
11 | title: 'Title 3',
12 | slug: 'title3'
13 | },
14 | {
15 | title: 'Title 4',
16 | slug: 'title4'
17 | },
18 | {
19 | title: 'Title 5',
20 | slug: 'title5'
21 | },
22 | {
23 | title: 'Title 6',
24 | slug: 'title6'
25 | }
26 | ];
27 |
--------------------------------------------------------------------------------
/stories/molecules/ComboBox/data.js:
--------------------------------------------------------------------------------
1 | import { faker } from '@faker-js/faker';
2 |
3 | export const emails = [];
4 |
5 | export function createEmails() {
6 | return {
7 | label: faker.internet.email()
8 | };
9 | }
10 |
11 | Array.from({ length: 5 }).forEach(() => {
12 | emails.push(createEmails());
13 | });
14 |
15 | export default emails;
16 |
--------------------------------------------------------------------------------
/stories/molecules/Grid/index.scss:
--------------------------------------------------------------------------------
1 | @import 'src/assets/styles/variables';
2 |
3 | .grid-item {
4 | text-align: center;
5 | font: rem(10) / rem(14) $f;
6 | text-transform: uppercase;
7 | display: flex;
8 | align-items: center;
9 | justify-content: center;
10 | height: rem(100);
11 | border-radius: rem(20);
12 | color: c(hero);
13 | background: c(hero, 0.24);
14 | overflow: hidden;
15 | width: 100%;
16 | }
17 |
--------------------------------------------------------------------------------
/stories/molecules/Holder/index.scss:
--------------------------------------------------------------------------------
1 | .holder-left {
2 | height: 500px;
3 | }
4 |
--------------------------------------------------------------------------------
/stories/molecules/Menu/Menu.stories.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react';
2 |
3 | import MenuComponent from 'src/lib/molecules/Menu';
4 | import { data } from './data';
5 | import { screenTypes } from '../../../src/configs';
6 | import { args, category } from '../../assets/storybook.globals';
7 |
8 | export default {
9 | title: 'Molecules/Menu',
10 | component: MenuComponent,
11 | argTypes: {
12 | onNext: args({ control: false, category: category.action }),
13 | onSelect: args({ control: false, category: category.action }),
14 | data: args({ control: 'object', category: category.content }),
15 | onBack: args({ control: false, action: 'onBack', category: category.action }),
16 | scrollToActiveElement: args({ control: 'boolean', category: category.functionality }),
17 | screenType: args({ control: 'select', options: screenTypes, category: category.appearance })
18 | },
19 | args: {
20 | data,
21 | scrollToActiveElement: true,
22 | screenType: args({ control: 'select', options: screenTypes, category: category.appearance }),
23 | initialIndexStack: []
24 | }
25 | };
26 |
27 | export const Menu = ({ ...args }) => {
28 | return ;
29 | };
30 |
--------------------------------------------------------------------------------
/stories/molecules/MobileNavigation/MobileNavigation.stories.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react';
2 |
3 | import MobileNavigationComponent from 'src/lib/molecules/MobileNavigation';
4 |
5 | import { args, category } from '../../assets/storybook.globals';
6 | import { list } from './data';
7 |
8 | export default {
9 | title: 'Molecules/MobileNavigation',
10 | component: MobileNavigationComponent,
11 | argTypes: {
12 | list: args({ control: 'object', category: category.content }),
13 | onChange: args({ control: false, category: category.action }),
14 | className: args({ control: false, category: category.others }),
15 | activeSlug: args({ control: 'text', category: category.content })
16 | },
17 | args: {
18 | activeSlug: list[1].slug,
19 | list: list
20 | }
21 | };
22 |
23 | export let MobileNavigation = ({ ...args }) => {
24 | const [selectedSlug, setSelectedSlug] = useState(args.activeSlug);
25 | return (
26 | {
29 | setSelectedSlug(e.slug);
30 | }}
31 | activeSlug={selectedSlug}
32 | />
33 | );
34 | };
35 |
--------------------------------------------------------------------------------
/stories/molecules/MobileNavigation/data.js:
--------------------------------------------------------------------------------
1 | export const list = [
2 | {
3 | title: 'Filters',
4 | slug: 'filters',
5 | icon: 'bc-icon-apps',
6 | disabled: true
7 | },
8 | {
9 | title: 'Products',
10 | slug: 'products',
11 | icon: 'bc-icon-apps',
12 | badge: {
13 | count: 30,
14 | maxCount: 20,
15 | position: 'right'
16 | }
17 | },
18 | {
19 | title: 'Profile',
20 | slug: 'profile',
21 | icon: 'bc-icon-apps'
22 | }
23 | ];
24 |
--------------------------------------------------------------------------------
/stories/molecules/MobilePopup/MobilePopup.stories.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import MobilePopupComponent from 'src/lib/molecules/MobilePopup';
4 | import { leftAction, rightAction } from './data';
5 | import { args, category } from '../../assets/storybook.globals';
6 |
7 | export default {
8 | title: 'Molecules/MobilePopup',
9 | component: MobilePopupComponent,
10 | argTypes: {
11 | title: args({ control: 'text', category: category.content }),
12 | children: args({ control: 'text', category: category.content }),
13 | className: args({ control: false, category: category.content }),
14 | isOpened: args({ control: 'boolean', category: category.states }),
15 | portalContainer: args({ control: false, category: category.content }),
16 | rightAction: args({ control: 'object', category: category.functionality }),
17 | leftAction: args({ control: 'object', action: 'leftAction', category: category.functionality }),
18 | leftActionClick: args({ control: false, action: 'leftActionClick', category: category.action }),
19 | onBackdropClick: args({ control: false, action: 'onBackdropClick', category: category.action }),
20 | rightActionClick: args({ control: false, action: 'rightActionClick', category: category.action })
21 | },
22 | args: {
23 | leftAction,
24 | rightAction,
25 | title: 'Title',
26 | isOpened: true
27 | }
28 | };
29 |
30 | export const MobilePopup = ({ ...args }) => ;
31 |
--------------------------------------------------------------------------------
/stories/molecules/MobilePopup/data.js:
--------------------------------------------------------------------------------
1 | export const rightAction = {
2 | iconType: 'bc-icon-more-horizontal',
3 | menuOptions: [
4 | {
5 | title: 'Menu 1',
6 | icon: 'bc-icon-report',
7 | color: 'hero'
8 | },
9 | {
10 | title: 'Menu 2',
11 | icon: 'bc-icon-average-coefficient',
12 | color: 'hero'
13 | }
14 | ]
15 | };
16 |
17 | export const leftAction = {
18 | iconType: 'bc-icon-arrow-back',
19 | text: 'Back'
20 | };
21 |
--------------------------------------------------------------------------------
/stories/molecules/Pagination/Pagination.stories.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import PaginationComponent from 'src/lib/molecules/Pagination';
4 | import { args, category } from '../../assets/storybook.globals';
5 |
6 | export default {
7 | title: 'Molecules/Pagination',
8 | component: PaginationComponent,
9 | argTypes: {
10 | onChange: args({ control: false, category: category.action }),
11 | count: args({ control: 'number', category: category.states }),
12 | errorText: args({ control: 'text', category: category.content }),
13 | selected: args({ control: 'number', category: category.states }),
14 | autoFocus: args({ control: 'boolean', category: category.states }),
15 | defaultSelected: args({ control: 'number', category: category.states }),
16 | supportedKeyCodes: args({ control: 'number', category: category.states }),
17 | nextIconTooltipText: args({ control: 'text', category: category.content }),
18 | previousIconTooltipText: args({ control: 'text', category: category.content })
19 | },
20 | args: {
21 | count: 50,
22 | autoFocus: false,
23 | defaultSelected: 1
24 | }
25 | };
26 |
27 | export const Pagination = ({ ...args }) => ;
28 |
--------------------------------------------------------------------------------
/stories/molecules/Products/Products.stories.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react';
2 |
3 | import ProductsComponent from 'src/lib/molecules/Products';
4 |
5 | const screenTypes = ['desktop', 'mobile'];
6 | import { list, favoritesList } from './data';
7 | import { args, category } from '../../assets/storybook.globals';
8 |
9 | export default {
10 | title: 'Molecules/Products',
11 | component: ProductsComponent,
12 | argTypes: {
13 | onClick: args({ control: false, category: category.action }),
14 | list: args({ control: 'array', category: category.content }),
15 | className: args({ control: false, category: category.others }),
16 | activeSlug: args({ control: false, category: category.states }),
17 | favorites: args({ control: 'object', category: category.content }),
18 | screenType: args({ control: false, options: screenTypes, category: category.states })
19 | },
20 | args: {
21 | list,
22 | favorites: favoritesList
23 | }
24 | };
25 |
26 | export const Products = ({ ...args }) => {
27 | const [activeSlug, setActiveSlug] = useState(list[0].slug);
28 |
29 | const onChange = (item) => {
30 | setActiveSlug(item.slug);
31 | };
32 | return ;
33 | };
34 |
--------------------------------------------------------------------------------
/stories/molecules/Products/data.js:
--------------------------------------------------------------------------------
1 | export const list = Array(12)
2 | .fill({})
3 | .map((_, i) => ({
4 | title: `Product ${i}`,
5 | slug: `product-${i}`,
6 | icon: 'bc-icon-apps'
7 | }));
8 |
9 | export const favoritesList = Array(3)
10 | .fill({})
11 | .map((_, i) => ({
12 | title: `Product ${i}`,
13 | slug: `product-${i}`,
14 | icon: 'bc-icon-apps'
15 | }));
16 |
--------------------------------------------------------------------------------
/stories/molecules/RadioGroup/RadioGroup.stories.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import RadioGroupComponent from 'src/lib/molecules/RadioGroup';
3 | import { optionsWithDisabled } from './data';
4 | import { args, category } from '../../assets/storybook.globals';
5 |
6 | const type = ['default', 'tab'];
7 |
8 | export default {
9 | title: 'Molecules/RadioGroup',
10 | component: RadioGroupComponent,
11 | argTypes: {
12 | name: args({ control: 'text', category: category.content }),
13 | value: args({ control: 'object', category: category.content }),
14 | options: args({ control: 'object', category: category.content }),
15 | required: args({ control: 'boolean', category: category.states }),
16 | disabled: args({ control: 'boolean', category: category.states }),
17 | descriptionKey: args({ control: 'text', category: category.content }),
18 | defaultValue: args({ control: 'number', category: category.content }),
19 | type: args({ control: 'select', options: type, category: category.appearance }),
20 | onChange: args({ control: 'object', action: 'onChange', category: category.action })
21 | },
22 | args: {
23 | type: type[0],
24 | defaultValue: 1,
25 | disabled: false,
26 | descriptionKey: 'info',
27 | options: optionsWithDisabled
28 | }
29 | };
30 |
31 | export const RadioGroup = ({ ...args }) => ;
32 |
--------------------------------------------------------------------------------
/stories/molecules/RadioGroup/data.js:
--------------------------------------------------------------------------------
1 | export const optionsWithDisabled = [
2 | { label: 'Option 1', value: 1, info: 'description1' },
3 | { label: 'Option 2', value: 2, info: 'description2' },
4 | { label: 'Option 3', value: 3, disabled: true, info: 'description3' }
5 | ];
6 |
--------------------------------------------------------------------------------
/stories/molecules/Search/Search.stories.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import SearchComponent from 'src/lib/molecules/Search';
4 | import { args, category } from '../../assets/storybook.globals';
5 |
6 | export default {
7 | title: 'Molecules/Search',
8 | component: SearchComponent,
9 | argTypes: {
10 | onChange: args({ control: false, category: category.action }),
11 | className: args({ control: false, category: category.others }),
12 | canClear: args({ control: 'boolean', category: category.states }),
13 | placeholder: args({ control: 'text', category: category.content }),
14 | defaultValue: args({ control: 'text', category: category.content })
15 | },
16 | args: {
17 | canClear: false,
18 | defaultValue: 'search',
19 | placeholder: 'Some placeholder'
20 | }
21 | };
22 |
23 | export const Search = ({ ...args }) => ;
24 |
--------------------------------------------------------------------------------
/stories/molecules/Status/Status.stories.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import StatusComponent, { statusIconTypes } from 'src/lib/molecules/Status';
4 | import { args, category } from '../../assets/storybook.globals';
5 |
6 | export default {
7 | title: 'Molecules/Status',
8 | component: StatusComponent,
9 | argTypes: {
10 | title: args({ control: 'text', category: category.content }),
11 | label: args({ control: 'text', category: category.content }),
12 | onClick: args({ control: 'text', category: category.action }),
13 | className: args({ control: false, category: category.others }),
14 | color: args({ control: 'color', category: category.appearance }),
15 | hoverTitle: args({ control: 'text', category: category.content }),
16 | tooltipText: args({ control: 'text', category: category.content }),
17 | iconType: args({ control: 'select', options: statusIconTypes, category: category.appearance })
18 | },
19 | args: {
20 | label: '',
21 | color: '',
22 | title: 'In Progress',
23 | hoverTitle: 'Hover Title',
24 | tooltipText: 'Some tooltip',
25 | iconType: statusIconTypes[0]
26 | }
27 | };
28 |
29 | export const Status = ({ ...args }) => ;
30 |
--------------------------------------------------------------------------------
/stories/molecules/Tabs/index.scss:
--------------------------------------------------------------------------------
1 | @import 'src/assets/styles/variables';
2 |
3 | .tabs-content-holder {
4 | min-height: rem(250);
5 | }
6 |
--------------------------------------------------------------------------------
/stories/molecules/Textarea/data.js:
--------------------------------------------------------------------------------
1 | export const suggestionData = [
2 | {
3 | key: '@',
4 | data: [
5 | {
6 | label: 'test1',
7 | value: 'test1'
8 | },
9 | {
10 | label: 'test2',
11 | value: 'test2'
12 | },
13 | {
14 | label: 'test3',
15 | value: 'test3'
16 | }
17 | ]
18 | },
19 | {
20 | key: ':',
21 | data: [
22 | {
23 | label: 'test1',
24 | value: 'test1'
25 | }
26 | ]
27 | }
28 | ];
29 |
--------------------------------------------------------------------------------
/stories/molecules/Timeline/Timeline.stories.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import {
4 | Timeline as TimelineComponent,
5 | TimelineItem,
6 | timelineColors,
7 | timelineAppearances
8 | } from 'src/lib/molecules/Timeline/index';
9 | import { args, category } from '../../assets/storybook.globals';
10 |
11 | export default {
12 | title: 'Molecules/Timeline',
13 | component: TimelineComponent,
14 | argTypes: {
15 | title: args({ control: 'text', category: category.content }),
16 | className: args({ control: false, category: category.others }),
17 | children: args({ control: 'text', category: category.content }),
18 | description: args({ control: 'text', category: category.content }),
19 | isLoading: args({ control: 'boolean', category: category.states }),
20 | color: args({ control: 'select', options: timelineColors, category: category.appearance }),
21 | appearance: args({ control: 'select', options: timelineAppearances, category: category.appearance })
22 | },
23 | args: {
24 | isLoading: false,
25 | title: 'Some title',
26 | color: timelineColors[0],
27 | description: 'Some description',
28 | appearance: timelineAppearances[0]
29 | }
30 | };
31 |
32 | export const Timeline = ({ ...args }) => {
33 | return (
34 |
35 |
36 |
37 |
38 | );
39 | };
40 |
--------------------------------------------------------------------------------
/stories/organisms/DateFilter/style.scss:
--------------------------------------------------------------------------------
1 | .dateFilterWrapper {
2 | width: 100%;
3 | }
4 |
--------------------------------------------------------------------------------
/stories/organisms/Drawer/data.js:
--------------------------------------------------------------------------------
1 | export const menuData = [
2 | {
3 | icon: 'bc-icon-crm-standart-report',
4 | id: 'item-1',
5 | title: 'Menu Item 1'
6 | },
7 | {
8 | id: 'item-2',
9 | icon: 'bc-icon-test-48',
10 | title: 'Menu Item 2',
11 | disabled: true
12 | },
13 | {
14 | id: 'item-3',
15 | icon: 'bc-icon-sent-outline',
16 | title: 'Menu Item 3'
17 | },
18 | {
19 | id: 'item-4',
20 | icon: 'bc-icon-list-border',
21 | title: 'Menu Item 4',
22 | nested: [
23 | {
24 | id: 'section-1',
25 | title: 'Section 1'
26 | },
27 | {
28 | id: 'section-2',
29 | title: 'Section 2'
30 | }
31 | ]
32 | },
33 | {
34 | id: 'item-5',
35 | icon: 'bc-icon-pages',
36 | title: 'Menu Item 5',
37 | nested: [
38 | {
39 | id: 'section-3',
40 | title: 'Section 3'
41 | },
42 | {
43 | id: 'section-4',
44 | title: 'Section 4'
45 | }
46 | ]
47 | }
48 | ];
49 |
--------------------------------------------------------------------------------
/stories/organisms/Form/style.scss:
--------------------------------------------------------------------------------
1 | .sb_form {
2 | background: var(--background);
3 | padding: 10px;
4 | }
5 |
--------------------------------------------------------------------------------
/stories/organisms/SearchWithDropdown/SearchWithDropdown.stories.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import SearchWithDropdownComponent from 'src/lib/organisms/SearchWithDropdown';
4 | import { args, category } from '../../assets/storybook.globals';
5 |
6 | const data = [
7 | { label: 'Option 1', value: 1 },
8 | { label: 'Option 2', value: 2 },
9 | { label: 'Option 3', value: 3 }
10 | ];
11 |
12 | export default {
13 | title: 'Organisms/SearchWithDropdown',
14 | component: SearchWithDropdownComponent,
15 | argTypes: {
16 | onChange: args({ control: false, category: category.action }),
17 | dataKey: args({ control: 'text', category: category.others }),
18 | searchProps: args({ control: 'object', category: category.others }),
19 | dropdownProps: args({ control: 'object', category: category.others }),
20 | flexibility: args({ control: 'select', category: category.appearance }),
21 | hideDropdown: args({ control: 'boolean', category: category.functionality })
22 | },
23 | args: {
24 | hideDropdown: false
25 | }
26 | };
27 |
28 | export const SearchWithDropdown = ({ ...args }) => (
29 |
37 | );
38 |
39 | SearchWithDropdown.args = {};
40 |
--------------------------------------------------------------------------------
/stories/utils/ChartAnimation.js:
--------------------------------------------------------------------------------
1 | const easeOutBounce = (pos) => {
2 | if (pos < 1 / 2.75) {
3 | return 7.5625 * pos * pos;
4 | }
5 | if (pos < 2 / 2.75) {
6 | return 7.5625 * (pos -= 1.5 / 2.75) * pos + 0.75;
7 | }
8 | if (pos < 2.5 / 2.75) {
9 | return 7.5625 * (pos -= 2.25 / 2.75) * pos + 0.9375;
10 | }
11 | return 7.5625 * (pos -= 2.625 / 2.75) * pos + 0.984375;
12 | };
13 |
14 | Math.easeOutBounce = easeOutBounce;
15 |
--------------------------------------------------------------------------------
/stories/utils/index.js:
--------------------------------------------------------------------------------
1 | export ChartAnimation from './ChartAnimation';
2 | export * from './propTables';
3 |
--------------------------------------------------------------------------------
/stories/utils/knobs.js:
--------------------------------------------------------------------------------
1 | import { date } from '@storybook/addon-knobs';
2 |
3 | function dateKnob(name, defaultValue) {
4 | const stringTimestamp = date(name, defaultValue);
5 | return new Date(stringTimestamp);
6 | }
7 |
8 | export { dateKnob };
9 |
--------------------------------------------------------------------------------
/stories/utils/propTables/DateMonthPickerProp.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import dayjs from 'dayjs';
4 |
5 | const DateMonthPickerProp = (props) => ;
6 |
7 | DateMonthPickerProp.name = 'DateMonthPicker';
8 |
9 | DateMonthPickerProp.propTypes = {
10 | /**
11 | * Fires event when user changes datepicker value
12 | * ([startDate: date endDate: date]) => void
13 | */
14 | onChange: PropTypes.func,
15 | /**
16 | * Initial value for start date
17 | */
18 | rangeStartDefault: PropTypes.oneOfType([
19 | PropTypes.instanceOf(dayjs),
20 | PropTypes.instanceOf(Date),
21 | PropTypes.string,
22 | PropTypes.number
23 | ]),
24 | /**
25 | * Initial value for end date
26 | */
27 | rangeEndDefault: PropTypes.oneOfType([
28 | PropTypes.instanceOf(dayjs),
29 | PropTypes.instanceOf(Date),
30 | PropTypes.string,
31 | PropTypes.number
32 | ]),
33 | /**
34 | * Additional classname which will apply to datepicker holder ul element
35 | */
36 | className: PropTypes.string,
37 | /**
38 | * Custom text for this month button inside footer.
39 | * Default value is `This Month`
40 | */
41 | thisMonthText: PropTypes.string
42 | };
43 |
44 | export default DateMonthPickerProp;
45 |
--------------------------------------------------------------------------------
/stories/utils/propTables/DatePickerProp.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import dayjs from 'dayjs';
4 |
5 | const DatePickerProp = (props) => ;
6 |
7 | DatePickerProp.propTypes = {
8 | /**
9 | * Initial datepicker value.
10 | */
11 | defaultValue: PropTypes.oneOfType([
12 | PropTypes.instanceOf(dayjs),
13 | PropTypes.instanceOf(Date),
14 | PropTypes.string,
15 | PropTypes.number
16 | ]),
17 | /**
18 | * Initial value for datepicker preview
19 | */
20 | defaultPreview: PropTypes.oneOfType([
21 | PropTypes.instanceOf(dayjs),
22 | PropTypes.instanceOf(Date),
23 | PropTypes.string,
24 | PropTypes.number
25 | ]),
26 | /**
27 | * Max specifies the maximum value allowed for datepicker
28 | */
29 | max: PropTypes.instanceOf(dayjs),
30 | /**
31 | * Min specifies the minimum value allowed for datepicker
32 | */
33 | min: PropTypes.instanceOf(dayjs),
34 | /**
35 | * Fires event when user changes date[icker value
36 | * (date: Date) => void
37 | */
38 | onChange: PropTypes.func,
39 | /**
40 | * Additional classname which will apply to datepicker holder ul element
41 | */
42 | className: PropTypes.string,
43 | /**
44 | * Custom text for today button inside footer.
45 | * Default value is `Today`
46 | */
47 | todayText: PropTypes.string
48 | };
49 |
50 | export default DatePickerProp;
51 |
--------------------------------------------------------------------------------
/stories/utils/propTables/DateWeekPickerProp.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import dayjs from 'dayjs';
4 |
5 | const DateWeekPickerProp = (props) => ;
6 |
7 | DateWeekPickerProp.propTypes = {
8 | /**
9 | * Fires event when user changes datepicker value
10 | * ([startDate: Date, endDate: Date]) => void
11 | */
12 | onChange: PropTypes.func,
13 | /**
14 | * Initial value for start date
15 | */
16 | rangeStartDefault: PropTypes.oneOfType([
17 | PropTypes.instanceOf(dayjs),
18 | PropTypes.instanceOf(Date),
19 | PropTypes.string,
20 | PropTypes.number
21 | ]),
22 | /**
23 | * Initial value for end date
24 | */
25 | rangeEndDefault: PropTypes.oneOfType([
26 | PropTypes.instanceOf(dayjs),
27 | PropTypes.instanceOf(Date),
28 | PropTypes.string,
29 | PropTypes.number
30 | ]),
31 | /**
32 | * Additional classname which will apply to datepicker holder ul element
33 | */
34 | className: PropTypes.string,
35 | /**
36 | * Custom text for this week button inside footer.
37 | * Default value is `This Week`
38 | */
39 | thisWeekText: PropTypes.string
40 | };
41 |
42 | export default DateWeekPickerProp;
43 |
--------------------------------------------------------------------------------
/stories/utils/propTables/HeaderTableProp.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | const HeaderTableProp = (props) => ;
5 |
6 | HeaderTableProp.propTypes = {
7 | /**
8 | * Define is search bar will shown or no
9 | */
10 | withSearch: PropTypes.bool,
11 | /**
12 | * Any valid react node
13 | */
14 | headerActions: PropTypes.node,
15 | /**
16 | * All props from Table component
17 | */
18 | '': PropTypes.any
19 | };
20 |
21 | export default HeaderTableProp;
22 |
--------------------------------------------------------------------------------
/stories/utils/propTables/MenuProp.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | const MenuProp = (props) => ;
5 |
6 | MenuProp.counter = 0;
7 |
8 | MenuProp.propTypes = {
9 | /**
10 | * Menu items data
11 | */
12 | data: PropTypes.arrayOf(
13 | PropTypes.shape({
14 | /**
15 | * Title for menu item
16 | */
17 | title: PropTypes.string,
18 | /**
19 | * Divider between menu items
20 | */
21 | divider: PropTypes.shape({
22 | /**
23 | * Controls width of divider
24 | */
25 | hasFullWidth: PropTypes.bool
26 | }),
27 | /**
28 | * Fires event when user click on one of the menu items;
29 | * (event: Event, item: Object) => void
30 | */
31 | onClick: PropTypes.func,
32 | /**
33 | * Text value inside menu item
34 | */
35 | description: PropTypes.string,
36 | /**
37 | * Children elements data for menu item
38 | */
39 | children: PropTypes.any
40 | })
41 | ),
42 | /**
43 | * Fires event when user click on header elements;
44 | * (event: Event, item: Object) => void
45 | */
46 | onBack: PropTypes.func
47 | };
48 |
49 | export default MenuProp;
50 |
--------------------------------------------------------------------------------
/stories/utils/propTables/ScrollbarProp.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | const CustomScrollbarProp = (props) => ;
5 |
6 | CustomScrollbarProp.propTypes = {
7 | /**
8 | * Any valid React node
9 | */
10 | children: PropTypes.node.isRequired,
11 | /**
12 | * Enable auto-height mode. When true container grows with content.
13 | */
14 | autoHeight: PropTypes.bool,
15 | /**
16 | * Set a minimum height for auto-height mode.
17 | */
18 | autoHeightMin: PropTypes.number,
19 | /**
20 | * Set a maximum height for auto-height mode
21 | */
22 | autoHeightMax: PropTypes.number
23 | };
24 |
25 | export default CustomScrollbarProp;
26 |
--------------------------------------------------------------------------------
/stories/utils/propTables/TitleTableProp.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | const TitleTableProp = (props) => ;
5 |
6 | TitleTableProp.propTypes = {
7 | /**
8 | * Any valid react node
9 | */
10 | titleActions: PropTypes.node,
11 | /**
12 | * Value for title
13 | */
14 | name: PropTypes.string.isRequired,
15 | /**
16 | * Callback for refresh icon click
17 | */
18 | onRefreshClick: PropTypes.func,
19 | /**
20 | * All props from Table component
21 | */
22 | '': PropTypes.any
23 | };
24 |
25 | export default TitleTableProp;
26 |
--------------------------------------------------------------------------------
/stories/utils/propTables/ToasterProp.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | const ToasterProp = (props) => ;
5 |
6 | ToasterProp.propTypes = {
7 | defaultDuration: PropTypes.number,
8 | toasterPosition: PropTypes.string,
9 | notificationPosition: PropTypes.string
10 | };
11 |
12 | ToasterProp.defaultProps = {
13 | defaultDuration: 4000,
14 | toasterPosition: 'right-top',
15 | notificationPosition: 'right-top'
16 | };
17 |
18 | export default ToasterProp;
19 |
--------------------------------------------------------------------------------
/stories/utils/propTables/index.js:
--------------------------------------------------------------------------------
1 | export PaperProp from './PaperProp';
2 | export CardProp from './CardProp';
3 | export ButtonProp from './ButtonProp';
4 | export RadioProp from './RadioProp';
5 | export ScrollbarProp from './ScrollbarProp';
6 | export SwitcherProp from './SwitcherProp';
7 | export PopoverProp from './PopoverProp';
8 | export ExtendedInputProp from './ExtendedInputProp';
9 | export CheckboxProp from './CheckboxProp';
10 | export DatePickerProp from './DatePickerProp';
11 | export DateMonthPickerProp from './DateMonthPickerProp';
12 | export DateRangePickerProp from './DateRangePickerProp';
13 | export DateWeekPickerProp from './DateWeekPickerProp';
14 | export ComboTableProp from './ComboTableProp';
15 | export TitleTableProp from './TitleTableProp';
16 | export HeaderTableProp from './HeaderTableProp';
17 | export { StepProp, StepsProp } from './StepsProp';
18 | export MenuProp from './MenuProp';
19 | export ToasterProp from './ToasterProp';
20 | export ValidatableNumberInputProp from './validateElements/ValidatableNumberinput';
21 | export ValidatableRadioProp from './validateElements/ValidatableRadio';
22 | export ValidatableCheckboxProp from './validateElements/ValidatableCheckbox';
23 | export ValidatableDatePickerProp from './validateElements/ValidableDatePickerProp';
24 | export ValidatableTextInputProp from './validateElements/ValidatableTextInputProp';
25 |
--------------------------------------------------------------------------------
/stories/utils/propTables/validateElements/ValidatableCheckbox.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | import { noop } from 'utils';
5 |
6 | const ValidatableCheckboxProp = (props) => ;
7 |
8 | ValidatableCheckboxProp.propTypes = {
9 | /**
10 | * Value for checkbox
11 | */
12 | value: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),
13 | /**
14 | * Callback fires when checkbox changes
15 | */
16 | onChange: PropTypes.func,
17 | /**
18 | * Define is field required or no.
19 | */
20 | required: PropTypes.bool,
21 | /**
22 | * Callback fires when field validation state changes
23 | */
24 | isFieldValid: PropTypes.func,
25 | /**
26 | * Additional validation state
27 | */
28 | isValid: PropTypes.bool,
29 | /**
30 | * Allow validation without onBlur, validate field when mount
31 | */
32 | forceAllowValidation: PropTypes.bool
33 | };
34 |
35 | ValidatableCheckboxProp.defaultProps = {
36 | isValid: true,
37 | isFieldValid: noop,
38 | onChange: noop
39 | };
40 |
41 | export default ValidatableCheckboxProp;
42 |
--------------------------------------------------------------------------------
/stories/utils/propTables/validateElements/ValidatableNumberinput.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | import { noop } from 'utils';
5 |
6 | const ValidatableNumberInputProp = (props) => ;
7 |
8 | ValidatableNumberInputProp.propTypes = {
9 | /**
10 | * Maximum value
11 | */
12 | min: PropTypes.number,
13 | /**
14 | * Minimum value
15 | */
16 | max: PropTypes.number,
17 | /**
18 | * Value for number field
19 | */
20 | value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
21 | /**
22 | * Callback fires when field changes
23 | */
24 | onChange: PropTypes.func,
25 | /**
26 | * Callback fires when field validation state changes
27 | */
28 | isFieldValid: PropTypes.func,
29 | /**
30 | * Additional validation state
31 | */
32 | isValid: PropTypes.bool,
33 | /**
34 | * Allow validation without onBlur, validate field when mount
35 | */
36 | forceAllowValidation: PropTypes.bool
37 | };
38 |
39 | ValidatableNumberInputProp.defaultProps = {
40 | isValid: true,
41 | isFieldValid: noop
42 | };
43 |
44 | export default ValidatableNumberInputProp;
45 |
--------------------------------------------------------------------------------
/stories/utils/propTables/validateElements/ValidatableRadio.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | import { noop } from 'utils';
5 |
6 | const ValidatableRadioProp = (props) => ;
7 |
8 | ValidatableRadioProp.propTypes = {
9 | /**
10 | * Value for radio field
11 | */
12 | value: PropTypes.string,
13 | /**
14 | * Callback fires when radio field changes
15 | */
16 | onChange: PropTypes.func,
17 | /**
18 | * Define is field required or no.
19 | */
20 | required: PropTypes.bool,
21 | /**
22 | * Callback fires when field validation state changes
23 | */
24 | isFieldValid: PropTypes.func,
25 | /**
26 | * Additional validation state
27 | */
28 | isValid: PropTypes.bool,
29 | /**
30 | * Allow validation without onBlur, validate field when mount
31 | */
32 | forceAllowValidation: PropTypes.bool
33 | };
34 |
35 | ValidatableRadioProp.defaultProps = {
36 | isValid: true,
37 | isFieldValid: noop,
38 | onChange: noop
39 | };
40 |
41 | export default ValidatableRadioProp;
42 |
--------------------------------------------------------------------------------
/stories/utils/propTables/validateElements/ValidatableTextInputProp.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | import { noop } from 'utils';
5 |
6 | const ValidatableTextInputProp = (props) => ;
7 |
8 | ValidatableTextInputProp.propTypes = {
9 | /**
10 | * Value for text input
11 | */
12 | value: PropTypes.string,
13 | /**
14 | * Callback fires when field changes
15 | */
16 | onChange: PropTypes.func,
17 | /**
18 | * Define is field required or no.
19 | */
20 | required: PropTypes.bool,
21 | /**
22 | * Is field accept only email or no
23 | */
24 | isEmail: PropTypes.bool,
25 | /**
26 | * Maximum length of value
27 | */
28 | maxLength: PropTypes.number,
29 | /**
30 | * Minimum length of value
31 | */
32 | minLength: PropTypes.number,
33 | /**
34 | * Callback fires when field validation state changes
35 | */
36 | isFieldValid: PropTypes.func,
37 | /**
38 | * Additional validation state
39 | */
40 | isValid: PropTypes.bool,
41 | /**
42 | * Allow validation without onBlur, validate field when mount
43 | */
44 | forceAllowValidation: PropTypes.bool
45 | };
46 |
47 | ValidatableTextInputProp.defaultProps = {
48 | isValid: true,
49 | isFieldValid: noop
50 | };
51 |
52 | export default ValidatableTextInputProp;
53 |
--------------------------------------------------------------------------------
/tests/__mocks__/svg.js:
--------------------------------------------------------------------------------
1 | export default 'SvgrURL';
2 | export const ReactComponent = 'div';
3 |
--------------------------------------------------------------------------------
/tests/helpers.ts:
--------------------------------------------------------------------------------
1 | // The module for testing helper functions
2 |
3 | export {};
4 |
--------------------------------------------------------------------------------
/tests/setup.ts:
--------------------------------------------------------------------------------
1 | import { configure } from 'enzyme';
2 | import Adapter from 'enzyme-adapter-react-16';
3 |
4 | configure({ adapter: new Adapter() });
5 |
--------------------------------------------------------------------------------