From 827f024928a2711f66f3644a8e48d9b475fd4241 Mon Sep 17 00:00:00 2001 From: k6sdevbob Date: Thu, 25 May 2023 11:51:41 +0800 Subject: [PATCH 1/2] feat(): pagination, divider Co-Authored-By: kyusho --- .../src/components/divider/index.tsx | 16 ++ .../src/components/pagination/components.tsx | 198 ++++++++++++++++ .../src/components/pagination/hooks.tsx | 212 ++++++++++++++++++ .../src/components/pagination/index.tsx | 120 ++++++++++ .../collection/collectionView/cardView.tsx | 11 +- .../collection/collectionView/listView.tsx | 11 +- .../src/pages/dashboard/renderer/index.tsx | 2 +- .../rath-client/src/pages/dashboard/tools.tsx | 2 +- .../megaAutomation/association/index.tsx | 4 +- .../src/pages/megaAutomation/index.tsx | 2 +- .../pages/megaAutomation/vizPagination.tsx | 4 +- 11 files changed, 562 insertions(+), 20 deletions(-) create mode 100644 packages/rath-client/src/components/divider/index.tsx create mode 100644 packages/rath-client/src/components/pagination/components.tsx create mode 100644 packages/rath-client/src/components/pagination/hooks.tsx create mode 100644 packages/rath-client/src/components/pagination/index.tsx diff --git a/packages/rath-client/src/components/divider/index.tsx b/packages/rath-client/src/components/divider/index.tsx new file mode 100644 index 000000000..8a7351f0d --- /dev/null +++ b/packages/rath-client/src/components/divider/index.tsx @@ -0,0 +1,16 @@ +import styled from "styled-components"; + + +const Divider = styled.hr` + margin: 0; + flex-shrink: 0; + border-width: 0; + border-top-width: thin; + border-color: inherit; + opacity: 0.12; + border-style: solid; + color: inherit; +`; + + +export default Divider; diff --git a/packages/rath-client/src/components/pagination/components.tsx b/packages/rath-client/src/components/pagination/components.tsx new file mode 100644 index 000000000..fb4de443c --- /dev/null +++ b/packages/rath-client/src/components/pagination/components.tsx @@ -0,0 +1,198 @@ +import styled from "styled-components"; + + +const Container = styled.div` + margin-block: 1.75rem; + display: flex; + align-items: center; + justify-content: space-between; +`; + +const ContentSm = styled.div` + flex-grow: 1; + flex-shrink: 1; + display: flex; + align-items: center; + justify-content: space-between; + @media (min-width: 1024px) { + display: none; + } +`; + +const ContentLg = styled.div` + flex-grow: 1; + flex-shrink: 1; + display: none; + @media (min-width: 1024px) { + display: flex; + } + align-items: center; + justify-content: space-between; + overflow: hidden; + > * + * { + margin-left: -1px; + } +`; + +const Description = styled.div` + flex-grow: 1; + flex-shrink: 1; + min-width: 0; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + > p { + font-size: 0.875rem; + line-height: 1.25rem; + color: #4b5563; + opacity: 0.6; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } +`; + +const TabList = styled.div` + flex-grow: 0; + flex-shrink: 0; + display: inline-flex; + position: relative; + padding: 2px; + :not(:first-child) { + margin-left: 1rem; + } +`; + +const CurrentTab = styled.div` + flex-grow: 0; + flex-shrink: 0; + width: max-content; + min-width: 2em; + cursor: default; + padding: 0.75rem 1rem; + font-size: 1rem; + font-weight: 600; + line-height: 1.25rem; + letter-spacing: 0.025em; + text-align: center; + white-space: break-all; + display: flex; + align-items: center; + justify-content: center; +`; + +const Tab = styled.div` + flex-grow: 0; + flex-shrink: 0; + width: max-content; + min-width: 2em; + cursor: pointer; + padding: 0.75rem 1rem; + font-size: 1rem; + font-weight: 600; + line-height: 1.25rem; + letter-spacing: 0.025em; + text-align: center; + white-space: break-all; + display: flex; + align-items: center; + justify-content: center; + opacity: 0.75; + &:hover { + opacity: 1; + color: #6366f1; + } + &:focus { + opacity: 1; + color: #6366f1; + outline: 2px solid transparent; + outline-offset: 2px; + box-shadow: 0 0 0 3px rgba(99, 102, 241, 0.5); + } +`; + +const Ellipsis = styled.div` + flex-grow: 0; + flex-shrink: 0; + width: max-content; + min-width: 2em; + cursor: default; + padding: 0.75rem 1rem; + font-size: 1rem; + font-weight: 600; + line-height: 1.25rem; + letter-spacing: 0.025em; + text-align: center; + white-space: break-all; + display: flex; + align-items: center; + justify-content: center; + opacity: 0.75; +`; + +const Button = styled.div` + flex-grow: 0; + flex-shrink: 0; + width: max-content; + min-width: 2em; + cursor: pointer; + padding: 0.75rem 1rem; + font-size: 1rem; + font-weight: 600; + line-height: 1.25rem; + letter-spacing: 0.025em; + text-align: center; + white-space: break-all; + display: flex; + align-items: center; + justify-content: center; + opacity: 0.75; + &[aria-disabled="false"]:hover { + opacity: 1; + color: #6366f1; + } + &[aria-disabled="false"]:focus { + opacity: 1; + color: #6366f1; + outline: 2px solid transparent; + outline-offset: 2px; + box-shadow: 0 0 0 3px rgba(99, 102, 241, 0.5); + } + &[aria-disabled="true"] { + cursor: default; + } + > * + * { + margin-left: 0.5rem; + } + > span { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: nowrap; + border-width: 0; + } + > i { + width: 1.25rem; + height: 1.25rem; + } +`; + + +const PaginationComponents = { + Container, + ContentSm, + ContentLg, + Description, + TabList, + CurrentTab, + Tab, + Ellipsis, + Button, +}; + + +export default PaginationComponents; diff --git a/packages/rath-client/src/components/pagination/hooks.tsx b/packages/rath-client/src/components/pagination/hooks.tsx new file mode 100644 index 000000000..6b23fa496 --- /dev/null +++ b/packages/rath-client/src/components/pagination/hooks.tsx @@ -0,0 +1,212 @@ +import { type ReactEventHandler, type ChangeEvent, useMemo, useRef } from "react"; + + +export interface UsePaginationParams { + /** + * Number of always visible pages at the beginning and end. + * @default 1 + */ + boundaryCount?: number; + /** + * The total number of pages. + * @default 1 + */ + count?: number; + /** + * If `true`, the component is disabled. + * @default false + */ + disabled?: boolean; + /** + * If `true`, hide the next-page button. + * @default false + */ + hideNextButton?: boolean; + /** + * If `true`, hide the previous-page button. + * @default false + */ + hidePrevButton?: boolean; + /** + * Callback fired when the page is changed. + * + * @param {ChangeEvent} event The event source of the callback. + * @param {number} page The page selected. + */ + onChange?: (event: ChangeEvent, page: number) => void; + /** + * The current page, starting from 1. + */ + page?: number; + /** + * Number of always visible pages before and after the current page. + * @default 1 + */ + siblingCount?: number; +} + +export interface UsePaginationItem { + onClick: ReactEventHandler; + type: 'page' | 'next' | 'previous' | 'start-ellipsis' | 'end-ellipsis'; + page: number; + selected: boolean; + disabled: boolean; +} + +export interface UsePaginationResult { + items: readonly UsePaginationItem[]; + isFallback: boolean; +} + +export const usePagination = (params: UsePaginationParams): UsePaginationResult => { + const { + boundaryCount = 1, + count = 1, + disabled = false, + hideNextButton = false, + hidePrevButton = false, + onChange, + page = 1, + siblingCount = 1, + } = params; + + const isPageIdxValid = Number.isFinite(page) && Math.floor(page!) === page && page >= 1 && page <= count; + const prevPageEnabled = isPageIdxValid && page > 1; + const nextPageEnabled = isPageIdxValid && page + 1 <= count; + + const onChangeRef = useRef(onChange); + onChangeRef.current = onChange; + + const items = useMemo(() => { + const MAX_CENTER_ITEMS = 1 + siblingCount * 2; + if (!isPageIdxValid) { + const items: UsePaginationItem[] = []; + for (let i = 1; i <= Math.min(count, boundaryCount * 2 + MAX_CENTER_ITEMS); i += 1) { + items.push({ + type: 'page', + page: i, + selected: false, + disabled, + onClick: event => { + if (disabled) { + return; + } + onChangeRef.current?.(event, i); + }, + }); + } + return items; + } + const leftPartMax = boundaryCount; + const rightPartMin = Math.max(0, count + 1 - boundaryCount); + const centerPartMin = Math.max(leftPartMax + 1, page - MAX_CENTER_ITEMS); + const centerPartMax = Math.min(page + MAX_CENTER_ITEMS, rightPartMin - 1); + let centerItems: number[] = []; + for (let i = centerPartMin; i <= centerPartMax; i += 1) { + centerItems.push(i); + } + centerItems = centerItems.sort((a, b) => Math.abs(a - page) - Math.abs(b - page)).slice(0, MAX_CENTER_ITEMS).sort((a, b) => a - b); + const items: UsePaginationItem[] = []; + for (let i = 1; i <= leftPartMax; i += 1) { + items.push({ + type: 'page', + page: i, + selected: i === page, + disabled, + onClick: event => { + if (disabled || i === page) { + return; + } + onChangeRef.current?.(event, i); + }, + }); + } + if ((centerItems.at(0) ?? -1) > leftPartMax + 1) { + items.push({ + type: 'start-ellipsis', + page: -1, + selected: false, + disabled, + onClick: () => {}, + }); + } + for (const idx of centerItems) { + items.push({ + type: 'page', + page: idx, + selected: idx === page, + disabled, + onClick: event => { + if (disabled || idx === page) { + return; + } + onChangeRef.current?.(event, idx); + }, + }); + } + if ((centerItems.at(-1) ?? Infinity) < rightPartMin - 1) { + items.push({ + type: 'end-ellipsis', + page: -1, + selected: false, + disabled, + onClick: () => {}, + }); + } + for (let i = rightPartMin; i <= count; i += 1) { + if (items.some(item => item.page === i)) { + continue; + } + items.push({ + type: 'page', + page: i, + selected: i === page, + disabled, + onClick: event => { + if (disabled || i === page) { + return; + } + onChangeRef.current?.(event, i); + }, + }); + } + + if (!hidePrevButton) { + items.unshift({ + type: 'previous', + page: page - 1, + selected: false, + disabled: disabled || !prevPageEnabled, + onClick: event => { + if (disabled || !prevPageEnabled) { + return; + } + onChangeRef.current?.(event, page - 1); + }, + }); + } + if (!hideNextButton) { + items.push({ + type: 'next', + page: page + 1, + selected: false, + disabled: disabled || !nextPageEnabled, + onClick: event => { + if (disabled || !nextPageEnabled) { + return; + } + onChangeRef.current?.(event, page + 1); + }, + }); + } + + return items; + }, [siblingCount, isPageIdxValid, count, page, disabled, hidePrevButton, hideNextButton, boundaryCount, prevPageEnabled, nextPageEnabled]); + + return useMemo(() => { + return { + items, + isFallback: !isPageIdxValid, + }; + }, [items, isPageIdxValid]); +}; diff --git a/packages/rath-client/src/components/pagination/index.tsx b/packages/rath-client/src/components/pagination/index.tsx new file mode 100644 index 000000000..6b5d40bf8 --- /dev/null +++ b/packages/rath-client/src/components/pagination/index.tsx @@ -0,0 +1,120 @@ +import { Icon } from "@fluentui/react"; +import { Fragment, type HTMLAttributes, memo } from "react"; +import P from './components'; +import { type UsePaginationItem, usePagination } from "./hooks"; + + +export interface IPaginationProps { + pageCount: number; + /** starting from 1, show only the head if not given */ + pageIdx?: number; + onChange?: (idx: number) => void; + description?: string; + prevBtnText?: string; + nextBtnText?: string; +} + +const Pagination = memo, keyof IPaginationProps>>(function Pagination ({ + pageCount, pageIdx, onChange, description, prevBtnText = 'Prev', nextBtnText = 'Next', ...attrs +}) { + const { items, isFallback } = usePagination({ + count: pageCount, + page: pageIdx, + onChange: (_, page) => onChange?.(page), + }); + + const renderCurrentPage = (item: UsePaginationItem & { type: 'page' }) => ( + + {item.page} + + ); + + const renderTab = (item: UsePaginationItem & { type: 'page' }) => ( + + {item.page} + + ); + + const renderEllipsis = () => ( + + ... + + ); + + const renderButton = (item: UsePaginationItem & { type: 'next' | 'previous' }) => ( + + + ); + + if (isFallback) { + return ( + + + + {items.map((item, i) => ( + + {item.type === 'page' && renderTab(item as UsePaginationItem & { type: "page" })} + {item.type.match(/ellipse/) && renderEllipsis()} + + ))} + + + + ); + } + + return ( + + + {items.filter(item => item.type === 'previous' || item.type === 'next').map(item => ( + + {renderButton(item as UsePaginationItem & { type: "next" | "previous" })} + + ))} + + + {description && ( + +

{description}

+
+ )} + + {items.map((item, i) => ( + + {(item.type === 'previous' || item.type === 'next') && renderButton(item as UsePaginationItem & { type: "next" | "previous" })} + {item.type === 'page' && item.selected && renderCurrentPage(item as UsePaginationItem & { type: "page" })} + {item.type === 'page' && !item.selected && renderTab(item as UsePaginationItem & { type: "page" })} + {item.type.match(/ellipse/) && renderEllipsis()} + + ))} + +
+
+ ); +}); + + +export default Pagination; diff --git a/packages/rath-client/src/pages/collection/collectionView/cardView.tsx b/packages/rath-client/src/pages/collection/collectionView/cardView.tsx index 540a6bb57..ba3fafa04 100644 --- a/packages/rath-client/src/pages/collection/collectionView/cardView.tsx +++ b/packages/rath-client/src/pages/collection/collectionView/cardView.tsx @@ -1,13 +1,14 @@ import { applyFilters } from '@kanaries/loa'; import React, { useState } from 'react'; import styled from 'styled-components'; -import { Divider, Pagination } from '@material-ui/core'; import ReactVega from '../../../components/react-vega'; import ViewInfo from '../../../components/viewInfo/textInfo'; import { IFieldMeta, IInsightVizView, IRow } from '../../../interfaces'; import VisErrorBoundary from '../../../components/visErrorBoundary'; import { changeVisSize, VIEW_NUM_IN_PAGE } from '../utils'; import { VegaThemeConfig } from '../../../queries/themes/config'; +import Pagination from '../../../components/pagination'; +import Divider from '../../../components/divider'; const CollectContainer = styled.div` display: flex; @@ -56,11 +57,9 @@ const CardView: React.FC = (props) => {
{ + pageCount={Math.ceil(views.length / VIEW_NUM_IN_PAGE)} + pageIdx={pageIndex + 1} + onChange={v => { setPageIndex(v - 1); }} /> diff --git a/packages/rath-client/src/pages/collection/collectionView/listView.tsx b/packages/rath-client/src/pages/collection/collectionView/listView.tsx index d95226feb..7d2bb3154 100644 --- a/packages/rath-client/src/pages/collection/collectionView/listView.tsx +++ b/packages/rath-client/src/pages/collection/collectionView/listView.tsx @@ -1,13 +1,14 @@ import React, { useState } from 'react'; import styled from 'styled-components'; import { applyFilters } from '@kanaries/loa'; -import { Divider, Pagination } from '@material-ui/core'; import ReactVega from '../../../components/react-vega'; import VisErrorBoundary from '../../../components/visErrorBoundary'; import { IFieldMeta, IInsightVizView, IRow } from '../../../interfaces'; import { changeVisSize, VIEW_NUM_IN_PAGE } from '../utils'; import ViewInfo from '../../../components/viewInfo/pillInfo'; import { VegaThemeConfig } from '../../../queries/themes/config'; +import Pagination from '../../../components/pagination'; +import Divider from '../../../components/divider'; const CollectContainer = styled.div` .seg-header { @@ -49,11 +50,9 @@ const ListView: React.FC = (props) => {
{ + pageCount={Math.ceil(views.length / VIEW_NUM_IN_PAGE)} + pageIdx={pageIndex + 1} + onChange={v => { setPageIndex(v - 1); }} /> diff --git a/packages/rath-client/src/pages/dashboard/renderer/index.tsx b/packages/rath-client/src/pages/dashboard/renderer/index.tsx index c9399de5b..e2e12e380 100644 --- a/packages/rath-client/src/pages/dashboard/renderer/index.tsx +++ b/packages/rath-client/src/pages/dashboard/renderer/index.tsx @@ -1,4 +1,4 @@ -import useId from '@material-ui/core/utils/useId'; +import { useId } from '@fluentui/react-hooks'; import { observer } from 'mobx-react-lite'; import { forwardRef, useEffect } from 'react'; import styled, { StyledComponentProps } from 'styled-components'; diff --git a/packages/rath-client/src/pages/dashboard/tools.tsx b/packages/rath-client/src/pages/dashboard/tools.tsx index 29785aff6..40f5d7527 100644 --- a/packages/rath-client/src/pages/dashboard/tools.tsx +++ b/packages/rath-client/src/pages/dashboard/tools.tsx @@ -1,8 +1,8 @@ import styled from 'styled-components'; import { useCallback, forwardRef } from 'react'; import { IconButton } from '@fluentui/react'; -import { Divider } from '@material-ui/core'; import type { DashboardCard } from '../../store/dashboardStore'; +import Divider from '../../components/divider'; const ToolGroup = styled.div` margin: 0 0 0 0.6em; diff --git a/packages/rath-client/src/pages/megaAutomation/association/index.tsx b/packages/rath-client/src/pages/megaAutomation/association/index.tsx index bded5795f..ed6138867 100644 --- a/packages/rath-client/src/pages/megaAutomation/association/index.tsx +++ b/packages/rath-client/src/pages/megaAutomation/association/index.tsx @@ -3,8 +3,8 @@ import { observer } from 'mobx-react-lite'; import React, { useState, useEffect } from 'react'; import { Pivot, PivotItem } from '@fluentui/react' import intl from 'react-intl-universal'; -import { Pagination } from '@material-ui/core'; import { useGlobalStore } from '../../../store'; +import Pagination from '../../../components/pagination'; import Association from './assCharts'; const PAGE_SIZE = 7; @@ -34,7 +34,7 @@ const ObservableAssociation: React.FC = props => { - { + { setAssoIndex(Math.max(v - 1, 0)); }} /> ` /* width: 140px; */ @@ -123,8 +123,6 @@ const VizPagination: React.FC = (props) => { const { items } = usePagination({ count: searchedInsightViews.length, - showFirstButton: false, - showLastButton: false, siblingCount: 1, page: pageIndex + 1, onChange: updatePage, From 11885b7d3f616218df9de14d3175cd9a7e0e4f93 Mon Sep 17 00:00:00 2001 From: k6sdevbob Date: Thu, 25 May 2023 15:22:02 +0800 Subject: [PATCH 2/2] feat(): stepper; remove mui Co-Authored-By: kyusho --- packages/rath-client/package.json | 3 - .../src/components/connectionStatus.tsx | 32 ++- .../src/components/stepper/components.tsx | 114 +++++++++ .../src/components/stepper/index.tsx | 80 ++++++ .../pages/dataConnection/database/index.tsx | 239 +---------------- .../dataConnection/database/progress.tsx | 125 --------- yarn.lock | 240 +----------------- 7 files changed, 223 insertions(+), 610 deletions(-) create mode 100644 packages/rath-client/src/components/stepper/components.tsx create mode 100644 packages/rath-client/src/components/stepper/index.tsx delete mode 100644 packages/rath-client/src/pages/dataConnection/database/progress.tsx diff --git a/packages/rath-client/package.json b/packages/rath-client/package.json index 10a202725..eea937e2a 100644 --- a/packages/rath-client/package.json +++ b/packages/rath-client/package.json @@ -11,8 +11,6 @@ "dependencies": { "@antv/g6": "^4.8.4", "@babel/parser": "^7.19.6", - "@emotion/react": "^11.10.4", - "@emotion/styled": "^11.10.4", "@fluentui/font-icons-mdl2": "^8.5.4", "@fluentui/react": "^8.94.4", "@fluentui/react-components": "^9.19.0", @@ -22,7 +20,6 @@ "@kanaries/graphic-walker": "^0.2.18", "@kanaries/loa": "^0.0.16", "@kanaries/web-data-loader": "0.1.7", - "@material-ui/core": "^5.0.0-beta.5", "@vercel/analytics": "^1.0.0", "@zip.js/zip.js": "^2.6.60", "airtable": "^0.11.4", diff --git a/packages/rath-client/src/components/connectionStatus.tsx b/packages/rath-client/src/components/connectionStatus.tsx index 946f5f30c..7687e10a3 100644 --- a/packages/rath-client/src/components/connectionStatus.tsx +++ b/packages/rath-client/src/components/connectionStatus.tsx @@ -1,7 +1,7 @@ import React from 'react'; -import { Box, Step, StepLabel, Stepper } from '@material-ui/core'; import { IECStatus } from '../interfaces'; import { ENGINE_CONNECTION_STAGES } from '../constants'; +import Stepper from './stepper'; interface ConnectionStatusProps { status: IECStatus; @@ -9,18 +9,24 @@ interface ConnectionStatusProps { const ConnectionStatus: React.FC = props => { const { status } = props; return
- - - {ENGINE_CONNECTION_STAGES.map((stage) => { - const currentStage = ENGINE_CONNECTION_STAGES.findIndex((s) => s.name === status); - return = stage.stage} active={currentStage >= stage.stage} style={{ textAlign: 'center'}}> - {stage.name} -

{stage.description}

-
- } - )} -
-
+ + + {ENGINE_CONNECTION_STAGES.map((stage) => { + const currentStage = ENGINE_CONNECTION_STAGES.findIndex((s) => s.name === status); + return ( + = stage.stage} + active={currentStage >= stage.stage} + style={{ textAlign: 'center' }} + > + {stage.name} +

{stage.description}

+
+ ); + })} +
+
} diff --git a/packages/rath-client/src/components/stepper/components.tsx b/packages/rath-client/src/components/stepper/components.tsx new file mode 100644 index 000000000..e98c462c9 --- /dev/null +++ b/packages/rath-client/src/components/stepper/components.tsx @@ -0,0 +1,114 @@ +import styled from "styled-components"; + + +const Box = styled.div` + width: 100%; +`; + +const Root = styled.div` + display: flex; + flex-direction: row; + align-items: flex-start; + counter-reset: step 0; +`; + +const Item = styled.div` + padding-inline: 0.5em; + flex: 1; + position: relative; + counter-increment: step; + :first-child .connector { + display: none; + } +`; + +const Connector = styled.div` + flex: 1 1 auto; + position: absolute; + top: 1em; + left: calc(-50% + 1.5em); + right: calc(50% + 1.5em); + transform: translateY(-100%); + > span { + display: block; + border-color: #bdbdbd; + border-top-style: solid; + border-top-width: 1px; + } +`; + +const Label = styled.span` + display: flex; + flex-direction: column; + align-items: center; + > .icon { + flex-shrink: 0; + display: flex; + > * { + user-select: none; + width: 1em; + height: 1em; + fill: currentColor; + flex-shrink: 0; + font-size: 1.5rem; + transition: color 200ms cubic-bezier(0.4, 0, 0.2, 1) 0ms; + border-radius: 50%; + overflow: hidden; + background-color: #a2a2a2; + fill: #fff; + color: #fff; + display: none; + &.uncompleted { + display: inline-flex; + align-items: center; + justify-content: center; + ::before { + display: inline-block; + content: counter(step); + font-size: 0.8rem; + } + } + &.completed { + background-color: #3b82f6; + } + } + } + *.completed > & > .icon > .completed { + display: inline-block; + } + *.completed > & > .icon > .uncompleted { + display: none; + } + > .label { + width: 100%; + color: #000000aa; + > span { + text-align: center; + margin-top: 1.2em; + font-size: 0.875rem; + font-weight: 400; + line-height: 1.43; + letter-spacing: 0.01071em; + display: block; + } + } + *.active > & > .label > span { + color: #000000d4; + font-weight: 600 !important; + } + *.completed > & > .label > span { + color: #000000d4; + font-weight: 500; + } +`; + +const StepperComponents = { + Box, + Root, + Item, + Connector, + Label, +}; + + +export default StepperComponents diff --git a/packages/rath-client/src/components/stepper/index.tsx b/packages/rath-client/src/components/stepper/index.tsx new file mode 100644 index 000000000..7f2f3f7a8 --- /dev/null +++ b/packages/rath-client/src/components/stepper/index.tsx @@ -0,0 +1,80 @@ +import { type HTMLAttributes, type FC } from "react"; +import S from './components'; + + +export interface IStepperProps {} + +const Stepper: FC = ({ children }) => { + return ( + + {children} + + ); +}; + +export interface IBoxProps {} + +const Box: FC = ({ children }) => { + return ( + + {children} + + ); +}; + +export interface IStepProps { + completed: boolean; + active: boolean; +} + +const Step: FC, keyof IStepProps>> = ({ completed, active, children, className = '', ...attrs }) => { + return ( + + + + + {children} + + ); +}; + +export interface IStepLabelProps {} + +const StepLabel: FC, keyof IStepLabelProps>> = ({ children, ...attrs }) => { + return ( + + + +