diff --git a/packages/blade/.storybook/react-native/storybook.requires.js b/packages/blade/.storybook/react-native/storybook.requires.js index 3b69f5b7359..8df2af037b8 100644 --- a/packages/blade/.storybook/react-native/storybook.requires.js +++ b/packages/blade/.storybook/react-native/storybook.requires.js @@ -102,7 +102,8 @@ const getStories = () => { './src/components/Spinner/Spinner/Spinner.stories.tsx': require('../../src/components/Spinner/Spinner/Spinner.stories.tsx'), './src/components/SpotlightPopoverTour/Tour.stories.tsx': require('../../src/components/SpotlightPopoverTour/Tour.stories.tsx'), './src/components/Switch/Switch.stories.tsx': require('../../src/components/Switch/Switch.stories.tsx'), - './src/components/Table/Table.stories.tsx': require('../../src/components/Table/Table.stories.tsx'), + './src/components/Table/docs/Table.stories.tsx': require('../../src/components/Table/docs/Table.stories.tsx'), + './src/components/Table/docs/TableExamples.stories.tsx': require('../../src/components/Table/docs/TableExamples.stories.tsx'), './src/components/Tabs/Tabs.stories.tsx': require('../../src/components/Tabs/Tabs.stories.tsx'), './src/components/Tag/Tag.stories.tsx': require('../../src/components/Tag/Tag.stories.tsx'), './src/components/Tooltip/Tooltip.stories.tsx': require('../../src/components/Tooltip/Tooltip.stories.tsx'), diff --git a/packages/blade/src/components/Table/Table.stories.tsx b/packages/blade/src/components/Table/Table.stories.tsx deleted file mode 100644 index 80a0473f4b3..00000000000 --- a/packages/blade/src/components/Table/Table.stories.tsx +++ /dev/null @@ -1,551 +0,0 @@ -import type { ComponentStory, Meta } from '@storybook/react'; -import type { TableProps } from './types'; -import { Table as TableComponent } from './Table'; -import { TableHeader, TableHeaderRow, TableHeaderCell } from './TableHeader'; -import { TableBody, TableRow, TableCell } from './TableBody'; -import { TableFooter, TableFooterRow, TableFooterCell } from './TableFooter'; -import { TablePagination } from './TablePagination'; -import { TableToolbarActions, TableToolbar } from './TableToolbar'; -import StoryPageWrapper from '~utils/storybook/StoryPageWrapper'; -import { Box } from '~components/Box'; -import { Button } from '~components/Button'; -import { useTheme } from '~utils'; -import { Amount } from '~components/Amount'; -import { Code } from '~components/Typography'; -import { Badge } from '~components/Badge'; -import { getStyledPropsArgTypes } from '~components/Box/BaseBox/storybookArgTypes'; - -export default { - title: 'Components/Table', - component: TableComponent, - args: { - selectionType: 'none', - rowDensity: 'normal', - }, - argTypes: { - ...getStyledPropsArgTypes(), - }, - parameters: { - docs: { - page: () => , - }, - }, -} as Meta>; - -// const nodes = [ -// { -// id: '23', -// name: 'Jest', -// deadline: new Date(2021, 10, 25), -// type: 'LEARN', -// isComplete: false, -// }, -// { -// id: '0', -// name: 'Operating System', -// deadline: new Date(2020, 1, 15), -// type: 'SETUP', -// isComplete: true, -// }, -// { -// id: '38', -// name: 'React Native', -// deadline: new Date(2023, 1, 25), -// type: 'LEARN', -// isComplete: false, -// }, -// { -// id: '34', -// name: 'Machine Learning', -// deadline: new Date(2022, 9, 15), -// type: 'LEARN', -// isComplete: false, -// }, -// { -// id: '19', -// name: 'TypeScript', -// deadline: new Date(2021, 6, 15), -// type: 'LEARN', -// isComplete: false, -// }, -// { -// id: '48', -// name: 'Swift', -// deadline: new Date(2023, 11, 5), -// type: 'LEARN', -// isComplete: false, -// }, -// { -// id: '11', -// name: 'Databases', -// deadline: new Date(2020, 11, 15), -// type: 'LEARN', -// isComplete: false, -// }, -// { -// id: '24', -// name: 'Testing Library', -// deadline: new Date(2021, 11, 5), -// type: 'LEARN', -// isComplete: false, -// }, -// { -// id: '2', -// name: 'JavaScript', -// deadline: new Date(2020, 2, 28), -// type: 'LEARN', -// isComplete: true, -// }, -// { -// id: '16', -// name: 'Angular', -// deadline: new Date(2021, 3, 15), -// type: 'LEARN', -// isComplete: false, -// }, -// { -// id: '31', -// name: 'Google Cloud Platform', -// deadline: new Date(2022, 6, 15), -// type: 'LEARN', -// isComplete: false, -// }, -// { -// id: '27', -// name: 'Scrum', -// deadline: new Date(2022, 2, 5), -// type: 'LEARN', -// isComplete: false, -// }, -// { -// id: '35', -// name: 'TensorFlow', -// deadline: new Date(2022, 10, 25), -// type: 'LEARN', -// isComplete: false, -// }, -// { -// id: '43', -// name: 'WebAssembly', -// deadline: new Date(2023, 6, 15), -// type: 'LEARN', -// isComplete: false, -// }, -// { -// id: '50', -// name: 'Go (Golang)', -// deadline: new Date(2024, 1, 25), -// type: 'LEARN', -// isComplete: false, -// }, -// { -// id: '8', -// name: 'CSS', -// deadline: new Date(2020, 8, 20), -// type: 'LEARN', -// isComplete: true, -// }, -// { -// id: '3', -// name: 'React', -// deadline: new Date(2020, 3, 8), -// type: 'LEARN', -// isComplete: false, -// }, -// { -// id: '47', -// name: 'AR/VR Development', -// deadline: new Date(2023, 10, 25), -// type: 'LEARN', -// isComplete: false, -// }, -// { -// id: '29', -// name: 'AWS', -// deadline: new Date(2022, 4, 25), -// type: 'LEARN', -// isComplete: false, -// }, -// { -// id: '6', -// name: 'GraphQL', -// deadline: new Date(2020, 6, 30), -// type: 'LEARN', -// isComplete: false, -// }, -// { -// id: '41', -// name: 'Ethical Hacking', -// deadline: new Date(2023, 4, 25), -// type: 'LEARN', -// isComplete: false, -// }, -// { -// id: '42', -// name: 'UX/UI Design', -// deadline: new Date(2023, 5, 5), -// type: 'LEARN', -// isComplete: false, -// }, -// { -// id: '12', -// name: 'SQL', -// deadline: new Date(2020, 11, 30), -// type: 'LEARN', -// isComplete: false, -// }, -// { -// id: '45', -// name: 'GraphQL Apollo Server', -// deadline: new Date(2023, 8, 5), -// type: 'LEARN', -// isComplete: false, -// }, -// { -// id: '39', -// name: 'Flutter', -// deadline: new Date(2023, 2, 5), -// type: 'LEARN', -// isComplete: false, -// }, -// { -// id: '36', -// name: 'PyTorch', -// deadline: new Date(2022, 11, 5), -// type: 'LEARN', -// isComplete: false, -// }, -// { -// id: '46', -// name: 'Raspberry Pi', -// deadline: new Date(2023, 9, 15), -// type: 'LEARN', -// isComplete: false, -// }, -// { -// id: '30', -// name: 'Azure', -// deadline: new Date(2022, 5, 5), -// type: 'LEARN', -// isComplete: false, -// }, -// { -// id: '14', -// name: 'Flask', -// deadline: new Date(2021, 1, 20), -// type: 'LEARN', -// isComplete: false, -// }, -// { -// id: '37', -// name: 'Data Science', -// deadline: new Date(2023, 0, 15), -// type: 'LEARN', -// isComplete: false, -// }, -// { -// id: '21', -// name: 'Docker', -// deadline: new Date(2021, 8, 5), -// type: 'SETUP', -// isComplete: false, -// }, -// { -// id: '33', -// name: 'Rust', -// deadline: new Date(2022, 8, 5), -// type: 'LEARN', -// isComplete: false, -// }, -// { -// id: '15', -// name: 'RESTful APIs', -// deadline: new Date(2021, 2, 5), -// type: 'LEARN', -// isComplete: false, -// }, -// { -// id: '18', -// name: 'Webpack', -// deadline: new Date(2021, 5, 5), -// type: 'LEARN', -// isComplete: false, -// }, -// { -// id: '44', -// name: 'Serverless Architecture', -// deadline: new Date(2023, 7, 25), -// type: 'LEARN', -// isComplete: false, -// }, -// { -// id: '4', -// name: 'Git', -// deadline: new Date(2020, 4, 28), -// type: 'SETUP', -// isComplete: false, -// }, -// { -// id: '26', -// name: 'Agile Methodology', -// deadline: new Date(2022, 1, 25), -// type: 'LEARN', -// isComplete: false, -// }, -// { -// id: '32', -// name: 'Blockchain', -// deadline: new Date(2022, 7, 25), -// type: 'LEARN', -// isComplete: false, -// }, -// { -// id: '22', -// name: 'Kubernetes', -// deadline: new Date(2021, 9, 15), -// type: 'LEARN', -// isComplete: false, -// }, -// { -// id: '49', -// name: 'Kotlin', -// deadline: new Date(2024, 0, 15), -// type: 'LEARN', -// isComplete: false, -// }, -// { -// id: '7', -// name: 'HTML', -// deadline: new Date(2020, 7, 15), -// type: 'LEARN', -// isComplete: true, -// }, -// { -// id: '25', -// name: 'CI/CD', -// deadline: new Date(2022, 0, 15), -// type: 'LEARN', -// isComplete: false, -// }, -// { -// id: '5', -// name: 'Node', -// deadline: new Date(2020, 5, 18), -// type: 'LEARN', -// isComplete: true, -// }, -// { -// id: '9', -// name: 'SASS', -// deadline: new Date(2020, 9, 25), -// type: 'LEARN', -// isComplete: false, -// }, -// { -// id: '17', -// name: 'Vue.js', -// deadline: new Date(2021, 4, 25), -// type: 'LEARN', -// isComplete: false, -// }, -// { -// id: '10', -// name: 'Responsive Design', -// deadline: new Date(2020, 10, 5), -// type: 'LEARN', -// isComplete: false, -// }, -// { -// id: '1', -// name: 'VSCode', -// deadline: new Date(2020, 1, 17), -// type: 'SETUP', -// isComplete: true, -// }, -// { -// id: '13', -// name: 'Python', -// deadline: new Date(2021, 0, 10), -// type: 'LEARN', -// isComplete: true, -// }, -// { -// id: '20', -// name: 'MongoDB', -// deadline: new Date(2021, 7, 25), -// type: 'LEARN', -// isComplete: false, -// }, -// { -// id: '28', -// name: 'DevOps', -// deadline: new Date(2022, 3, 15), -// type: 'LEARN', -// isComplete: false, -// }, -// { -// id: '40', -// name: 'Cybersecurity', -// deadline: new Date(2023, 3, 15), -// type: 'LEARN', -// isComplete: false, -// }, -// ]; - -const nodes: Item[] = [ - ...Array.from({ length: 200 }, (_, i) => ({ - id: (i + 1).toString(), - paymentId: `rzp${Math.floor(Math.random() * 1000000)}`, - amount: Number((Math.random() * 10000).toFixed(2)), - status: ['Completed', 'Pending', 'Failed'][Math.floor(Math.random() * 3)], - date: new Date(2021, Math.floor(Math.random() * 12), Math.floor(Math.random() * 28) + 1), - type: ['Payout', 'Refund'][Math.floor(Math.random() * 2)], - method: ['Bank Transfer', 'Credit Card', 'PayPal'][Math.floor(Math.random() * 3)], - bank: ['HDFC', 'ICICI', 'SBI'][Math.floor(Math.random() * 3)], - account: Math.floor(Math.random() * 1000000000).toString(), - name: [ - 'John Doe', - 'Jane Doe', - 'Bob Smith', - 'Alice Smith', - 'John Smith', - 'Jane Smith', - 'Bob Doe', - 'Alice Doe', - ][Math.floor(Math.random() * 8)], - })), -]; - -type Item = { - id: string; - paymentId: string; - amount: number; - status: string; - date: Date; - type: string; - method: string; - bank: string; - account: string; - name: string; -}; -const data: TableProps['data'] = { - nodes, -}; - -const TableTemplate: ComponentStory = ({ ...args }) => { - const { platform } = useTheme(); - const onMobile = platform === 'onMobile'; - return ( - - console.log('Selected Rows:', values)} - sortFunctions={{ - ID: (array) => array.sort((a, b) => Number(a.id) - Number(b.id)), - AMOUNT: (array) => array.sort((a, b) => a.amount - b.amount), - ACCOUNT: (array) => array.sort((a, b) => Number(a.account) - Number(b.account)), - PAYMENT_ID: (array) => array.sort((a, b) => a.paymentId.localeCompare(b.paymentId)), - DATE: (array) => array.sort((a, b) => a.date.getTime() - b.date.getTime()), - METHOD: (array) => array.sort((a, b) => a.method.localeCompare(b.method)), - STATUS: (array) => array.sort((a, b) => a.status.localeCompare(b.status)), - }} - onSortChange={({ sortKey, isSortReversed }) => - console.log('Sort Key:', sortKey, 'Sort Reversed:', isSortReversed) - } - toolbar={ - - - - - - - } - pagination={ - - } - > - {(tableData) => ( - <> - - - ID - Amount - Account - Date - Method - Status - - - - {tableData.map((tableItem, index) => ( - - - {tableItem.paymentId} - - - - - {tableItem.account} - - {tableItem.date?.toLocaleDateString('en-IN', { - year: 'numeric', - month: '2-digit', - day: '2-digit', - })} - - {tableItem.method} - - - {tableItem.status} - - - - ))} - - - - {args.selectionType === 'multiple' && -} - - - - - - - - - - - - - - - - )} - - - ); -}; - -export const Table = TableTemplate.bind({}); -// Need to do this because of storybook's weird naming convention, More details here: https://storybook.js.org/docs/react/writing-stories/naming-components-and-hierarchy#single-story-hoisting -Table.storyName = 'Default'; diff --git a/packages/blade/src/components/Table/docs/APIStories/TableAPI.stories.tsx b/packages/blade/src/components/Table/docs/APIStories/TableAPI.stories.tsx new file mode 100644 index 00000000000..a2beec9cf8a --- /dev/null +++ b/packages/blade/src/components/Table/docs/APIStories/TableAPI.stories.tsx @@ -0,0 +1,212 @@ +import type { ComponentStory, Meta } from '@storybook/react'; +import type { TableData, TableProps } from '../../Table'; +import { Table as TableComponent } from '../../Table'; +import { TableHeader, TableHeaderRow, TableHeaderCell } from '../../TableHeader'; +import { TableBody, TableRow, TableCell } from '../../TableBody'; +import { TableFooter, TableFooterRow, TableFooterCell } from '../../TableFooter'; +import { TablePagination } from '../../TablePagination'; +import { TableToolbarActions, TableToolbar } from '../../TableToolbar'; +import StoryPageWrapper from '~utils/storybook/StoryPageWrapper'; +import { Box } from '~components/Box'; +import { Button } from '~components/Button'; +import { useTheme } from '~utils'; +import { Amount } from '~components/Amount'; +import { Code } from '~components/Typography'; +import { Badge } from '~components/Badge'; +import { getStyledPropsArgTypes } from '~components/Box/BaseBox/storybookArgTypes'; + +export default { + title: 'Components/Table/API', + component: TableComponent, + args: { + selectionType: 'none', + rowDensity: 'normal', + }, + argTypes: { + ...getStyledPropsArgTypes(), + data: { + control: { + disable: true, + }, + }, + sortFunctions: { + control: { + disable: true, + }, + }, + toolbar: { + control: { + disable: true, + }, + }, + pagination: { + control: { + disable: true, + }, + }, + }, + parameters: { + docs: { + page: () => , + }, + }, +} as Meta>; + +const nodes: Item[] = [ + ...Array.from({ length: 200 }, (_, i) => ({ + id: (i + 1).toString(), + paymentId: `rzp${Math.floor(Math.random() * 1000000)}`, + amount: Number((Math.random() * 10000).toFixed(2)), + status: ['Completed', 'Pending', 'Failed'][Math.floor(Math.random() * 3)], + date: new Date(2021, Math.floor(Math.random() * 12), Math.floor(Math.random() * 28) + 1), + type: ['Payout', 'Refund'][Math.floor(Math.random() * 2)], + method: ['Bank Transfer', 'Credit Card', 'PayPal'][Math.floor(Math.random() * 3)], + bank: ['HDFC', 'ICICI', 'SBI'][Math.floor(Math.random() * 3)], + account: Math.floor(Math.random() * 1000000000).toString(), + name: [ + 'John Doe', + 'Jane Doe', + 'Bob Smith', + 'Alice Smith', + 'John Smith', + 'Jane Smith', + 'Bob Doe', + 'Alice Doe', + ][Math.floor(Math.random() * 8)], + })), +]; + +type Item = { + id: string; + paymentId: string; + amount: number; + status: string; + date: Date; + type: string; + method: string; + bank: string; + account: string; + name: string; +}; +const data: TableData = { + nodes, +}; + +const TableTemplate: ComponentStory = ({ ...args }) => { + const { platform } = useTheme(); + const onMobile = platform === 'onMobile'; + + return ( + + console.log('Selected Rows:', values)} + onSortChange={({ sortKey, isSortReversed }) => + console.log('Sort Key:', sortKey, 'Sort Reversed:', isSortReversed) + } + toolbar={ + + + + + + + } + pagination={ + + } + {...args} + data={data} + sortFunctions={{ + ID: (array) => array.sort((a, b) => Number(a.id) - Number(b.id)), + AMOUNT: (array) => array.sort((a, b) => a.amount - b.amount), + ACCOUNT: (array) => array.sort((a, b) => Number(a.account) - Number(b.account)), + PAYMENT_ID: (array) => array.sort((a, b) => a.paymentId.localeCompare(b.paymentId)), + DATE: (array) => array.sort((a, b) => a.date.getTime() - b.date.getTime()), + METHOD: (array) => array.sort((a, b) => a.method.localeCompare(b.method)), + STATUS: (array) => array.sort((a, b) => a.status.localeCompare(b.status)), + }} + > + {(tableData) => ( + <> + + + ID + Amount + Account + Date + Method + Status + + + + {tableData.map((tableItem, index) => ( + + + {tableItem.paymentId} + + + + + {tableItem.account} + + {tableItem.date?.toLocaleDateString('en-IN', { + year: 'numeric', + month: '2-digit', + day: '2-digit', + })} + + {tableItem.method} + + + {tableItem.status} + + + + ))} + + + + {args.selectionType === 'multiple' && -} + - + - + - + - + - + - + + + + )} + + + ); +}; + +export const Table = TableTemplate.bind({}); +// Need to do this because of storybook's weird naming convention, More details here: https://storybook.js.org/docs/react/writing-stories/naming-components-and-hierarchy#single-story-hoisting +Table.storyName = 'Table'; diff --git a/packages/blade/src/components/Table/docs/APIStories/TableBodyAPI.stories.tsx b/packages/blade/src/components/Table/docs/APIStories/TableBodyAPI.stories.tsx new file mode 100644 index 00000000000..e65054167c8 --- /dev/null +++ b/packages/blade/src/components/Table/docs/APIStories/TableBodyAPI.stories.tsx @@ -0,0 +1,148 @@ +import type { ComponentStory, Meta } from '@storybook/react'; +import type { TableData } from '../../Table'; +import { Table as TableComponent } from '../../Table'; +import { TableHeader, TableHeaderRow, TableHeaderCell } from '../../TableHeader'; +import { TableBody, TableRow, TableCell } from '../../TableBody'; +import { TableFooter, TableFooterRow, TableFooterCell } from '../../TableFooter'; +import StoryPageWrapper from '~utils/storybook/StoryPageWrapper'; +import { Box } from '~components/Box'; +import { Amount } from '~components/Amount'; +import { Code } from '~components/Typography'; +import { Badge } from '~components/Badge'; + +export default { + title: 'Components/Table/API', + component: TableBody, + args: {}, + argTypes: {}, + parameters: { + docs: { + page: () => ( + + ), + }, + }, +} as Meta; + +const nodes: Item[] = [ + ...Array.from({ length: 5 }, (_, i) => ({ + id: (i + 1).toString(), + paymentId: `rzp${Math.floor(Math.random() * 1000000)}`, + amount: Number((Math.random() * 10000).toFixed(2)), + status: ['Completed', 'Pending', 'Failed'][Math.floor(Math.random() * 3)], + date: new Date(2021, Math.floor(Math.random() * 12), Math.floor(Math.random() * 28) + 1), + type: ['Payout', 'Refund'][Math.floor(Math.random() * 2)], + method: ['Bank Transfer', 'Credit Card', 'PayPal'][Math.floor(Math.random() * 3)], + bank: ['HDFC', 'ICICI', 'SBI'][Math.floor(Math.random() * 3)], + account: Math.floor(Math.random() * 1000000000).toString(), + name: [ + 'John Doe', + 'Jane Doe', + 'Bob Smith', + 'Alice Smith', + 'John Smith', + 'Jane Smith', + 'Bob Doe', + 'Alice Doe', + ][Math.floor(Math.random() * 8)], + })), +]; + +type Item = { + id: string; + paymentId: string; + amount: number; + status: string; + date: Date; + type: string; + method: string; + bank: string; + account: string; + name: string; +}; +const data: TableData = { + nodes, +}; + +const TableTemplate: ComponentStory = ({ ...args }) => { + return ( + + + {(tableData) => ( + <> + + + ID + Amount + Account + Date + Method + Status + + + + {tableData.map((tableItem, index) => ( + + + {tableItem.paymentId} + + + + + {tableItem.account} + + {tableItem.date?.toLocaleDateString('en-IN', { + year: 'numeric', + month: '2-digit', + day: '2-digit', + })} + + {tableItem.method} + + + {tableItem.status} + + + + ))} + + + + - + - + - + - + - + - + + + + )} + + + ); +}; + +export const TableBodyStory = TableTemplate.bind({}); +// Need to do this because of storybook's weird naming convention, More details here: https://storybook.js.org/docs/react/writing-stories/naming-components-and-hierarchy#single-story-hoisting +TableBodyStory.storyName = 'TableBody'; diff --git a/packages/blade/src/components/Table/docs/APIStories/TableCellAPI.stories.tsx b/packages/blade/src/components/Table/docs/APIStories/TableCellAPI.stories.tsx new file mode 100644 index 00000000000..f01e111b56b --- /dev/null +++ b/packages/blade/src/components/Table/docs/APIStories/TableCellAPI.stories.tsx @@ -0,0 +1,154 @@ +import type { ComponentStory, Meta } from '@storybook/react'; +import type { TableData } from '../../Table'; +import { Table as TableComponent } from '../../Table'; +import { TableHeader, TableHeaderRow, TableHeaderCell } from '../../TableHeader'; +import { TableBody, TableRow, TableCell } from '../../TableBody'; +import { TableFooter, TableFooterRow, TableFooterCell } from '../../TableFooter'; +import StoryPageWrapper from '~utils/storybook/StoryPageWrapper'; +import { Box } from '~components/Box'; +import { Amount } from '~components/Amount'; +import { Code } from '~components/Typography'; +import { Badge } from '~components/Badge'; + +export default { + title: 'Components/Table/API', + component: TableCell, + args: {}, + argTypes: { + children: { + control: { + disable: true, + }, + }, + }, + parameters: { + docs: { + page: () => ( + + ), + }, + }, +} as Meta; + +const nodes: Item[] = [ + ...Array.from({ length: 5 }, (_, i) => ({ + id: (i + 1).toString(), + paymentId: `rzp${Math.floor(Math.random() * 1000000)}`, + amount: Number((Math.random() * 10000).toFixed(2)), + status: ['Completed', 'Pending', 'Failed'][Math.floor(Math.random() * 3)], + date: new Date(2021, Math.floor(Math.random() * 12), Math.floor(Math.random() * 28) + 1), + type: ['Payout', 'Refund'][Math.floor(Math.random() * 2)], + method: ['Bank Transfer', 'Credit Card', 'PayPal'][Math.floor(Math.random() * 3)], + bank: ['HDFC', 'ICICI', 'SBI'][Math.floor(Math.random() * 3)], + account: Math.floor(Math.random() * 1000000000).toString(), + name: [ + 'John Doe', + 'Jane Doe', + 'Bob Smith', + 'Alice Smith', + 'John Smith', + 'Jane Smith', + 'Bob Doe', + 'Alice Doe', + ][Math.floor(Math.random() * 8)], + })), +]; + +type Item = { + id: string; + paymentId: string; + amount: number; + status: string; + date: Date; + type: string; + method: string; + bank: string; + account: string; + name: string; +}; +const data: TableData = { + nodes, +}; + +const TableTemplate: ComponentStory = ({ ...args }) => { + return ( + + + {(tableData) => ( + <> + + + ID + Amount + Account + Date + Method + Status + + + + {tableData.map((tableItem, index) => ( + + + {tableItem.paymentId} + + + + + {tableItem.account} + + {tableItem.date?.toLocaleDateString('en-IN', { + year: 'numeric', + month: '2-digit', + day: '2-digit', + })} + + {tableItem.method} + + + {tableItem.status} + + + + ))} + + + + - + - + - + - + - + - + + + + )} + + + ); +}; + +export const TableCellStory = TableTemplate.bind({}); +// Need to do this because of storybook's weird naming convention, More details here: https://storybook.js.org/docs/react/writing-stories/naming-components-and-hierarchy#single-story-hoisting +TableCellStory.storyName = 'TableCell'; diff --git a/packages/blade/src/components/Table/docs/APIStories/TableFooterAPI.stories.tsx b/packages/blade/src/components/Table/docs/APIStories/TableFooterAPI.stories.tsx new file mode 100644 index 00000000000..eaecddef28f --- /dev/null +++ b/packages/blade/src/components/Table/docs/APIStories/TableFooterAPI.stories.tsx @@ -0,0 +1,154 @@ +import type { ComponentStory, Meta } from '@storybook/react'; +import type { TableData } from '../../Table'; +import { Table as TableComponent } from '../../Table'; +import { TableHeader, TableHeaderRow, TableHeaderCell } from '../../TableHeader'; +import { TableBody, TableRow, TableCell } from '../../TableBody'; +import { TableFooter, TableFooterRow, TableFooterCell } from '../../TableFooter'; +import StoryPageWrapper from '~utils/storybook/StoryPageWrapper'; +import { Box } from '~components/Box'; +import { Amount } from '~components/Amount'; +import { Code } from '~components/Typography'; +import { Badge } from '~components/Badge'; + +export default { + title: 'Components/Table/API', + component: TableFooter, + args: {}, + argTypes: { + children: { + control: { + disable: true, + }, + }, + }, + parameters: { + docs: { + page: () => ( + + ), + }, + }, +} as Meta; + +const nodes: Item[] = [ + ...Array.from({ length: 5 }, (_, i) => ({ + id: (i + 1).toString(), + paymentId: `rzp${Math.floor(Math.random() * 1000000)}`, + amount: Number((Math.random() * 10000).toFixed(2)), + status: ['Completed', 'Pending', 'Failed'][Math.floor(Math.random() * 3)], + date: new Date(2021, Math.floor(Math.random() * 12), Math.floor(Math.random() * 28) + 1), + type: ['Payout', 'Refund'][Math.floor(Math.random() * 2)], + method: ['Bank Transfer', 'Credit Card', 'PayPal'][Math.floor(Math.random() * 3)], + bank: ['HDFC', 'ICICI', 'SBI'][Math.floor(Math.random() * 3)], + account: Math.floor(Math.random() * 1000000000).toString(), + name: [ + 'John Doe', + 'Jane Doe', + 'Bob Smith', + 'Alice Smith', + 'John Smith', + 'Jane Smith', + 'Bob Doe', + 'Alice Doe', + ][Math.floor(Math.random() * 8)], + })), +]; + +type Item = { + id: string; + paymentId: string; + amount: number; + status: string; + date: Date; + type: string; + method: string; + bank: string; + account: string; + name: string; +}; +const data: TableData = { + nodes, +}; + +const TableTemplate: ComponentStory = ({ ...args }) => { + return ( + + + {(tableData) => ( + <> + + + ID + Amount + Account + Date + Method + Status + + + + {tableData.map((tableItem, index) => ( + + + {tableItem.paymentId} + + + + + {tableItem.account} + + {tableItem.date?.toLocaleDateString('en-IN', { + year: 'numeric', + month: '2-digit', + day: '2-digit', + })} + + {tableItem.method} + + + {tableItem.status} + + + + ))} + + + + - + - + - + - + - + - + + + + )} + + + ); +}; + +export const TableFooterStory = TableTemplate.bind({}); +// Need to do this because of storybook's weird naming convention, More details here: https://storybook.js.org/docs/react/writing-stories/naming-components-and-hierarchy#single-story-hoisting +TableFooterStory.storyName = 'TableFooter'; diff --git a/packages/blade/src/components/Table/docs/APIStories/TableFooterCellAPI.stories.tsx b/packages/blade/src/components/Table/docs/APIStories/TableFooterCellAPI.stories.tsx new file mode 100644 index 00000000000..3756c448055 --- /dev/null +++ b/packages/blade/src/components/Table/docs/APIStories/TableFooterCellAPI.stories.tsx @@ -0,0 +1,154 @@ +import type { ComponentStory, Meta } from '@storybook/react'; +import type { TableData } from '../../Table'; +import { Table as TableComponent } from '../../Table'; +import { TableHeader, TableHeaderRow, TableHeaderCell } from '../../TableHeader'; +import { TableBody, TableRow, TableCell } from '../../TableBody'; +import { TableFooter, TableFooterRow, TableFooterCell } from '../../TableFooter'; +import StoryPageWrapper from '~utils/storybook/StoryPageWrapper'; +import { Box } from '~components/Box'; +import { Amount } from '~components/Amount'; +import { Code } from '~components/Typography'; +import { Badge } from '~components/Badge'; + +export default { + title: 'Components/Table/API', + component: TableFooterCell, + args: {}, + argTypes: { + children: { + control: { + disable: true, + }, + }, + }, + parameters: { + docs: { + page: () => ( + + ), + }, + }, +} as Meta; + +const nodes: Item[] = [ + ...Array.from({ length: 5 }, (_, i) => ({ + id: (i + 1).toString(), + paymentId: `rzp${Math.floor(Math.random() * 1000000)}`, + amount: Number((Math.random() * 10000).toFixed(2)), + status: ['Completed', 'Pending', 'Failed'][Math.floor(Math.random() * 3)], + date: new Date(2021, Math.floor(Math.random() * 12), Math.floor(Math.random() * 28) + 1), + type: ['Payout', 'Refund'][Math.floor(Math.random() * 2)], + method: ['Bank Transfer', 'Credit Card', 'PayPal'][Math.floor(Math.random() * 3)], + bank: ['HDFC', 'ICICI', 'SBI'][Math.floor(Math.random() * 3)], + account: Math.floor(Math.random() * 1000000000).toString(), + name: [ + 'John Doe', + 'Jane Doe', + 'Bob Smith', + 'Alice Smith', + 'John Smith', + 'Jane Smith', + 'Bob Doe', + 'Alice Doe', + ][Math.floor(Math.random() * 8)], + })), +]; + +type Item = { + id: string; + paymentId: string; + amount: number; + status: string; + date: Date; + type: string; + method: string; + bank: string; + account: string; + name: string; +}; +const data: TableData = { + nodes, +}; + +const TableTemplate: ComponentStory = ({ ...args }) => { + return ( + + + {(tableData) => ( + <> + + + ID + Amount + Account + Date + Method + Status + + + + {tableData.map((tableItem, index) => ( + + + {tableItem.paymentId} + + + + + {tableItem.account} + + {tableItem.date?.toLocaleDateString('en-IN', { + year: 'numeric', + month: '2-digit', + day: '2-digit', + })} + + {tableItem.method} + + + {tableItem.status} + + + + ))} + + + + - + - + - + - + - + - + + + + )} + + + ); +}; + +export const TableFooterCellStory = TableTemplate.bind({}); +// Need to do this because of storybook's weird naming convention, More details here: https://storybook.js.org/docs/react/writing-stories/naming-components-and-hierarchy#single-story-hoisting +TableFooterCellStory.storyName = 'TableFooterCell'; diff --git a/packages/blade/src/components/Table/docs/APIStories/TableFooterRowAPI.stories.tsx b/packages/blade/src/components/Table/docs/APIStories/TableFooterRowAPI.stories.tsx new file mode 100644 index 00000000000..04d703fe3de --- /dev/null +++ b/packages/blade/src/components/Table/docs/APIStories/TableFooterRowAPI.stories.tsx @@ -0,0 +1,154 @@ +import type { ComponentStory, Meta } from '@storybook/react'; +import type { TableData } from '../../Table'; +import { Table as TableComponent } from '../../Table'; +import { TableHeader, TableHeaderRow, TableHeaderCell } from '../../TableHeader'; +import { TableBody, TableRow, TableCell } from '../../TableBody'; +import { TableFooter, TableFooterRow, TableFooterCell } from '../../TableFooter'; +import StoryPageWrapper from '~utils/storybook/StoryPageWrapper'; +import { Box } from '~components/Box'; +import { Amount } from '~components/Amount'; +import { Code } from '~components/Typography'; +import { Badge } from '~components/Badge'; + +export default { + title: 'Components/Table/API', + component: TableFooterRow, + args: {}, + argTypes: { + children: { + control: { + disable: true, + }, + }, + }, + parameters: { + docs: { + page: () => ( + + ), + }, + }, +} as Meta; + +const nodes: Item[] = [ + ...Array.from({ length: 5 }, (_, i) => ({ + id: (i + 1).toString(), + paymentId: `rzp${Math.floor(Math.random() * 1000000)}`, + amount: Number((Math.random() * 10000).toFixed(2)), + status: ['Completed', 'Pending', 'Failed'][Math.floor(Math.random() * 3)], + date: new Date(2021, Math.floor(Math.random() * 12), Math.floor(Math.random() * 28) + 1), + type: ['Payout', 'Refund'][Math.floor(Math.random() * 2)], + method: ['Bank Transfer', 'Credit Card', 'PayPal'][Math.floor(Math.random() * 3)], + bank: ['HDFC', 'ICICI', 'SBI'][Math.floor(Math.random() * 3)], + account: Math.floor(Math.random() * 1000000000).toString(), + name: [ + 'John Doe', + 'Jane Doe', + 'Bob Smith', + 'Alice Smith', + 'John Smith', + 'Jane Smith', + 'Bob Doe', + 'Alice Doe', + ][Math.floor(Math.random() * 8)], + })), +]; + +type Item = { + id: string; + paymentId: string; + amount: number; + status: string; + date: Date; + type: string; + method: string; + bank: string; + account: string; + name: string; +}; +const data: TableData = { + nodes, +}; + +const TableTemplate: ComponentStory = ({ ...args }) => { + return ( + + + {(tableData) => ( + <> + + + ID + Amount + Account + Date + Method + Status + + + + {tableData.map((tableItem, index) => ( + + + {tableItem.paymentId} + + + + + {tableItem.account} + + {tableItem.date?.toLocaleDateString('en-IN', { + year: 'numeric', + month: '2-digit', + day: '2-digit', + })} + + {tableItem.method} + + + {tableItem.status} + + + + ))} + + + + - + - + - + - + - + - + + + + )} + + + ); +}; + +export const TableFooterRowStory = TableTemplate.bind({}); +// Need to do this because of storybook's weird naming convention, More details here: https://storybook.js.org/docs/react/writing-stories/naming-components-and-hierarchy#single-story-hoisting +TableFooterRowStory.storyName = 'TableFooterRow'; diff --git a/packages/blade/src/components/Table/docs/APIStories/TableHeaderAPI.stories.tsx b/packages/blade/src/components/Table/docs/APIStories/TableHeaderAPI.stories.tsx new file mode 100644 index 00000000000..e561c87040c --- /dev/null +++ b/packages/blade/src/components/Table/docs/APIStories/TableHeaderAPI.stories.tsx @@ -0,0 +1,154 @@ +import type { ComponentStory, Meta } from '@storybook/react'; +import type { TableData } from '../../Table'; +import { Table as TableComponent } from '../../Table'; +import { TableHeader, TableHeaderRow, TableHeaderCell } from '../../TableHeader'; +import { TableBody, TableRow, TableCell } from '../../TableBody'; +import { TableFooter, TableFooterRow, TableFooterCell } from '../../TableFooter'; +import StoryPageWrapper from '~utils/storybook/StoryPageWrapper'; +import { Box } from '~components/Box'; +import { Amount } from '~components/Amount'; +import { Code } from '~components/Typography'; +import { Badge } from '~components/Badge'; + +export default { + title: 'Components/Table/API', + component: TableHeader, + args: {}, + argTypes: { + children: { + control: { + disable: true, + }, + }, + }, + parameters: { + docs: { + page: () => ( + + ), + }, + }, +} as Meta; + +const nodes: Item[] = [ + ...Array.from({ length: 5 }, (_, i) => ({ + id: (i + 1).toString(), + paymentId: `rzp${Math.floor(Math.random() * 1000000)}`, + amount: Number((Math.random() * 10000).toFixed(2)), + status: ['Completed', 'Pending', 'Failed'][Math.floor(Math.random() * 3)], + date: new Date(2021, Math.floor(Math.random() * 12), Math.floor(Math.random() * 28) + 1), + type: ['Payout', 'Refund'][Math.floor(Math.random() * 2)], + method: ['Bank Transfer', 'Credit Card', 'PayPal'][Math.floor(Math.random() * 3)], + bank: ['HDFC', 'ICICI', 'SBI'][Math.floor(Math.random() * 3)], + account: Math.floor(Math.random() * 1000000000).toString(), + name: [ + 'John Doe', + 'Jane Doe', + 'Bob Smith', + 'Alice Smith', + 'John Smith', + 'Jane Smith', + 'Bob Doe', + 'Alice Doe', + ][Math.floor(Math.random() * 8)], + })), +]; + +type Item = { + id: string; + paymentId: string; + amount: number; + status: string; + date: Date; + type: string; + method: string; + bank: string; + account: string; + name: string; +}; +const data: TableData = { + nodes, +}; + +const TableTemplate: ComponentStory = ({ ...args }) => { + return ( + + + {(tableData) => ( + <> + + + ID + Amount + Account + Date + Method + Status + + + + {tableData.map((tableItem, index) => ( + + + {tableItem.paymentId} + + + + + {tableItem.account} + + {tableItem.date?.toLocaleDateString('en-IN', { + year: 'numeric', + month: '2-digit', + day: '2-digit', + })} + + {tableItem.method} + + + {tableItem.status} + + + + ))} + + + + - + - + - + - + - + - + + + + )} + + + ); +}; + +export const TableHeaderStory = TableTemplate.bind({}); +// Need to do this because of storybook's weird naming convention, More details here: https://storybook.js.org/docs/react/writing-stories/naming-components-and-hierarchy#single-story-hoisting +TableHeaderStory.storyName = 'TableHeader'; diff --git a/packages/blade/src/components/Table/docs/APIStories/TableHeaderCellAPI.stories.tsx b/packages/blade/src/components/Table/docs/APIStories/TableHeaderCellAPI.stories.tsx new file mode 100644 index 00000000000..49de0e4ccd0 --- /dev/null +++ b/packages/blade/src/components/Table/docs/APIStories/TableHeaderCellAPI.stories.tsx @@ -0,0 +1,159 @@ +import type { ComponentStory, Meta } from '@storybook/react'; +import type { TableData } from '../../Table'; +import { Table as TableComponent } from '../../Table'; +import { TableHeader, TableHeaderRow, TableHeaderCell } from '../../TableHeader'; +import { TableBody, TableRow, TableCell } from '../../TableBody'; +import { TableFooter, TableFooterRow, TableFooterCell } from '../../TableFooter'; +import StoryPageWrapper from '~utils/storybook/StoryPageWrapper'; +import { Box } from '~components/Box'; +import { Amount } from '~components/Amount'; +import { Code } from '~components/Typography'; +import { Badge } from '~components/Badge'; + +export default { + title: 'Components/Table/API', + component: TableHeaderCell, + args: {}, + argTypes: { + children: { + control: { + disable: true, + }, + }, + headerKey: { + control: { + disable: true, + }, + }, + }, + parameters: { + docs: { + page: () => ( + + ), + }, + }, +} as Meta; + +const nodes: Item[] = [ + ...Array.from({ length: 5 }, (_, i) => ({ + id: (i + 1).toString(), + paymentId: `rzp${Math.floor(Math.random() * 1000000)}`, + amount: Number((Math.random() * 10000).toFixed(2)), + status: ['Completed', 'Pending', 'Failed'][Math.floor(Math.random() * 3)], + date: new Date(2021, Math.floor(Math.random() * 12), Math.floor(Math.random() * 28) + 1), + type: ['Payout', 'Refund'][Math.floor(Math.random() * 2)], + method: ['Bank Transfer', 'Credit Card', 'PayPal'][Math.floor(Math.random() * 3)], + bank: ['HDFC', 'ICICI', 'SBI'][Math.floor(Math.random() * 3)], + account: Math.floor(Math.random() * 1000000000).toString(), + name: [ + 'John Doe', + 'Jane Doe', + 'Bob Smith', + 'Alice Smith', + 'John Smith', + 'Jane Smith', + 'Bob Doe', + 'Alice Doe', + ][Math.floor(Math.random() * 8)], + })), +]; + +type Item = { + id: string; + paymentId: string; + amount: number; + status: string; + date: Date; + type: string; + method: string; + bank: string; + account: string; + name: string; +}; +const data: TableData = { + nodes, +}; + +const TableTemplate: ComponentStory = ({ ...args }) => { + return ( + + + {(tableData) => ( + <> + + + ID + Amount + Account + Date + Method + Status + + + + {tableData.map((tableItem, index) => ( + + + {tableItem.paymentId} + + + + + {tableItem.account} + + {tableItem.date?.toLocaleDateString('en-IN', { + year: 'numeric', + month: '2-digit', + day: '2-digit', + })} + + {tableItem.method} + + + {tableItem.status} + + + + ))} + + + + - + - + - + - + - + - + + + + )} + + + ); +}; + +export const TableHeaderCellStory = TableTemplate.bind({}); +// Need to do this because of storybook's weird naming convention, More details here: https://storybook.js.org/docs/react/writing-stories/naming-components-and-hierarchy#single-story-hoisting +TableHeaderCellStory.storyName = 'TableHeaderCell'; diff --git a/packages/blade/src/components/Table/docs/APIStories/TableHeaderRowAPI.stories.tsx b/packages/blade/src/components/Table/docs/APIStories/TableHeaderRowAPI.stories.tsx new file mode 100644 index 00000000000..6d14a87e8aa --- /dev/null +++ b/packages/blade/src/components/Table/docs/APIStories/TableHeaderRowAPI.stories.tsx @@ -0,0 +1,154 @@ +import type { ComponentStory, Meta } from '@storybook/react'; +import type { TableData } from '../../Table'; +import { Table as TableComponent } from '../../Table'; +import { TableHeader, TableHeaderRow, TableHeaderCell } from '../../TableHeader'; +import { TableBody, TableRow, TableCell } from '../../TableBody'; +import { TableFooter, TableFooterRow, TableFooterCell } from '../../TableFooter'; +import StoryPageWrapper from '~utils/storybook/StoryPageWrapper'; +import { Box } from '~components/Box'; +import { Amount } from '~components/Amount'; +import { Code } from '~components/Typography'; +import { Badge } from '~components/Badge'; + +export default { + title: 'Components/Table/API', + component: TableHeaderRow, + args: {}, + argTypes: { + children: { + control: { + disable: true, + }, + }, + }, + parameters: { + docs: { + page: () => ( + + ), + }, + }, +} as Meta; + +const nodes: Item[] = [ + ...Array.from({ length: 5 }, (_, i) => ({ + id: (i + 1).toString(), + paymentId: `rzp${Math.floor(Math.random() * 1000000)}`, + amount: Number((Math.random() * 10000).toFixed(2)), + status: ['Completed', 'Pending', 'Failed'][Math.floor(Math.random() * 3)], + date: new Date(2021, Math.floor(Math.random() * 12), Math.floor(Math.random() * 28) + 1), + type: ['Payout', 'Refund'][Math.floor(Math.random() * 2)], + method: ['Bank Transfer', 'Credit Card', 'PayPal'][Math.floor(Math.random() * 3)], + bank: ['HDFC', 'ICICI', 'SBI'][Math.floor(Math.random() * 3)], + account: Math.floor(Math.random() * 1000000000).toString(), + name: [ + 'John Doe', + 'Jane Doe', + 'Bob Smith', + 'Alice Smith', + 'John Smith', + 'Jane Smith', + 'Bob Doe', + 'Alice Doe', + ][Math.floor(Math.random() * 8)], + })), +]; + +type Item = { + id: string; + paymentId: string; + amount: number; + status: string; + date: Date; + type: string; + method: string; + bank: string; + account: string; + name: string; +}; +const data: TableData = { + nodes, +}; + +const TableTemplate: ComponentStory = ({ ...args }) => { + return ( + + + {(tableData) => ( + <> + + + ID + Amount + Account + Date + Method + Status + + + + {tableData.map((tableItem, index) => ( + + + {tableItem.paymentId} + + + + + {tableItem.account} + + {tableItem.date?.toLocaleDateString('en-IN', { + year: 'numeric', + month: '2-digit', + day: '2-digit', + })} + + {tableItem.method} + + + {tableItem.status} + + + + ))} + + + + - + - + - + - + - + - + + + + )} + + + ); +}; + +export const TableHeaderRowStory = TableTemplate.bind({}); +// Need to do this because of storybook's weird naming convention, More details here: https://storybook.js.org/docs/react/writing-stories/naming-components-and-hierarchy#single-story-hoisting +TableHeaderRowStory.storyName = 'TableHeaderRow'; diff --git a/packages/blade/src/components/Table/docs/APIStories/TablePaginationAPI.stories.tsx b/packages/blade/src/components/Table/docs/APIStories/TablePaginationAPI.stories.tsx new file mode 100644 index 00000000000..423cd7f6b59 --- /dev/null +++ b/packages/blade/src/components/Table/docs/APIStories/TablePaginationAPI.stories.tsx @@ -0,0 +1,190 @@ +import type { ComponentStory, Meta } from '@storybook/react'; +import type { TableData } from '../../Table'; +import { Table as TableComponent } from '../../Table'; +import { TableHeader, TableHeaderRow, TableHeaderCell } from '../../TableHeader'; +import { TableBody, TableRow, TableCell } from '../../TableBody'; +import { TableFooter, TableFooterRow, TableFooterCell } from '../../TableFooter'; +import { TablePagination } from '../../TablePagination'; +import { TableToolbarActions, TableToolbar } from '../../TableToolbar'; +import StoryPageWrapper from '~utils/storybook/StoryPageWrapper'; +import { Box } from '~components/Box'; +import { Button } from '~components/Button'; +import { useTheme } from '~utils'; +import { Amount } from '~components/Amount'; +import { Code } from '~components/Typography'; +import { Badge } from '~components/Badge'; + +export default { + title: 'Components/Table/API', + component: TablePagination, + parameters: { + docs: { + page: () => ( + + ), + }, + }, +} as Meta; + +const nodes: Item[] = [ + ...Array.from({ length: 100 }, (_, i) => ({ + id: (i + 1).toString(), + paymentId: `rzp${Math.floor(Math.random() * 1000000)}`, + amount: Number((Math.random() * 10000).toFixed(2)), + status: ['Completed', 'Pending', 'Failed'][Math.floor(Math.random() * 3)], + date: new Date(2021, Math.floor(Math.random() * 12), Math.floor(Math.random() * 28) + 1), + type: ['Payout', 'Refund'][Math.floor(Math.random() * 2)], + method: ['Bank Transfer', 'Credit Card', 'PayPal'][Math.floor(Math.random() * 3)], + bank: ['HDFC', 'ICICI', 'SBI'][Math.floor(Math.random() * 3)], + account: Math.floor(Math.random() * 1000000000).toString(), + name: [ + 'John Doe', + 'Jane Doe', + 'Bob Smith', + 'Alice Smith', + 'John Smith', + 'Jane Smith', + 'Bob Doe', + 'Alice Doe', + ][Math.floor(Math.random() * 8)], + })), +]; + +type Item = { + id: string; + paymentId: string; + amount: number; + status: string; + date: Date; + type: string; + method: string; + bank: string; + account: string; + name: string; +}; +const data: TableData = { + nodes, +}; + +const TableTemplate: ComponentStory = ({ ...args }) => { + const { platform } = useTheme(); + const onMobile = platform === 'onMobile'; + + return ( + + console.log('Selected Rows:', values)} + sortFunctions={{ + ID: (array) => array.sort((a, b) => Number(a.id) - Number(b.id)), + AMOUNT: (array) => array.sort((a, b) => a.amount - b.amount), + ACCOUNT: (array) => array.sort((a, b) => Number(a.account) - Number(b.account)), + PAYMENT_ID: (array) => array.sort((a, b) => a.paymentId.localeCompare(b.paymentId)), + DATE: (array) => array.sort((a, b) => a.date.getTime() - b.date.getTime()), + METHOD: (array) => array.sort((a, b) => a.method.localeCompare(b.method)), + STATUS: (array) => array.sort((a, b) => a.status.localeCompare(b.status)), + }} + onSortChange={({ sortKey, isSortReversed }) => + console.log('Sort Key:', sortKey, 'Sort Reversed:', isSortReversed) + } + toolbar={ + + + + + + + } + pagination={ + + } + > + {(tableData) => ( + <> + + + ID + Amount + Account + Date + Method + Status + + + + {tableData.map((tableItem, index) => ( + + + {tableItem.paymentId} + + + + + {tableItem.account} + + {tableItem.date?.toLocaleDateString('en-IN', { + year: 'numeric', + month: '2-digit', + day: '2-digit', + })} + + {tableItem.method} + + + {tableItem.status} + + + + ))} + + + + {args.selectionType === 'multiple' && -} + - + - + - + - + - + - + + + + )} + + + ); +}; + +export const TablePaginationStory = TableTemplate.bind({}); +// Need to do this because of storybook's weird naming convention, More details here: https://storybook.js.org/docs/react/writing-stories/naming-components-and-hierarchy#single-story-hoisting +TablePaginationStory.storyName = 'TablePagination'; diff --git a/packages/blade/src/components/Table/docs/APIStories/TableRowAPI.stories.tsx b/packages/blade/src/components/Table/docs/APIStories/TableRowAPI.stories.tsx new file mode 100644 index 00000000000..cd314e57893 --- /dev/null +++ b/packages/blade/src/components/Table/docs/APIStories/TableRowAPI.stories.tsx @@ -0,0 +1,144 @@ +import type { ComponentStory, Meta } from '@storybook/react'; +import type { TableData } from '../../Table'; +import { Table as TableComponent } from '../../Table'; +import { TableHeader, TableHeaderRow, TableHeaderCell } from '../../TableHeader'; +import { TableBody, TableRow, TableCell } from '../../TableBody'; +import StoryPageWrapper from '~utils/storybook/StoryPageWrapper'; +import { Box } from '~components/Box'; +import { Amount } from '~components/Amount'; +import { Code } from '~components/Typography'; +import { Link } from '~components/Link'; +import { CopyIcon, TrashIcon } from '~components/Icons'; + +export default { + title: 'Components/Table/API', + component: TableRow, + args: {}, + argTypes: { + children: { + control: { + disable: true, + }, + }, + item: { + control: { + disable: true, + }, + }, + }, + parameters: { + docs: { + page: () => ( + + ), + }, + }, +} as Meta; + +const nodes: Item[] = [ + ...Array.from({ length: 5 }, (_, i) => ({ + id: (i + 1).toString(), + paymentId: `rzp${Math.floor(Math.random() * 1000000)}`, + amount: Number((Math.random() * 10000).toFixed(2)), + status: ['Completed', 'Pending', 'Failed'][Math.floor(Math.random() * 3)], + date: new Date(2021, Math.floor(Math.random() * 12), Math.floor(Math.random() * 28) + 1), + type: ['Payout', 'Refund'][Math.floor(Math.random() * 2)], + method: ['Bank Transfer', 'Credit Card', 'PayPal'][Math.floor(Math.random() * 3)], + bank: ['HDFC', 'ICICI', 'SBI'][Math.floor(Math.random() * 3)], + account: Math.floor(Math.random() * 1000000000).toString(), + name: [ + 'John Doe', + 'Jane Doe', + 'Bob Smith', + 'Alice Smith', + 'John Smith', + 'Jane Smith', + 'Bob Doe', + 'Alice Doe', + ][Math.floor(Math.random() * 8)], + })), +]; + +type Item = { + id: string; + paymentId: string; + amount: number; + status: string; + date: Date; + type: string; + method: string; + bank: string; + account: string; + name: string; +}; +const data: TableData = { + nodes, +}; + +const TableTemplate: ComponentStory = ({ ...args }) => { + return ( + + + {(tableData) => ( + <> + + + ID + Amount + Action + + + + {tableData.map((tableItem, index) => { + return ( + + + {tableItem.paymentId} + + + + + + + + console.log('copy')} + isDisabled={args.isDisabled} + variant="button" + icon={CopyIcon} + > + Copy + + console.log('delete')} + isDisabled={args.isDisabled} + variant="button" + icon={TrashIcon} + > + Delete + + + + + ); + })} + + + )} + + + ); +}; + +export const TableRowStory = TableTemplate.bind({}); +// Need to do this because of storybook's weird naming convention, More details here: https://storybook.js.org/docs/react/writing-stories/naming-components-and-hierarchy#single-story-hoisting +TableRowStory.storyName = 'TableRow'; diff --git a/packages/blade/src/components/Table/docs/APIStories/TableToolbarAPI.stories.tsx b/packages/blade/src/components/Table/docs/APIStories/TableToolbarAPI.stories.tsx new file mode 100644 index 00000000000..0b3b8898dd7 --- /dev/null +++ b/packages/blade/src/components/Table/docs/APIStories/TableToolbarAPI.stories.tsx @@ -0,0 +1,178 @@ +import type { ComponentStory, Meta } from '@storybook/react'; +import type { TableData } from '../../Table'; +import { Table as TableComponent } from '../../Table'; +import { TableHeader, TableHeaderRow, TableHeaderCell } from '../../TableHeader'; +import { TableBody, TableRow, TableCell } from '../../TableBody'; +import { TableFooter, TableFooterRow, TableFooterCell } from '../../TableFooter'; +import { TablePagination } from '../../TablePagination'; +import { TableToolbarActions, TableToolbar } from '../../TableToolbar'; +import StoryPageWrapper from '~utils/storybook/StoryPageWrapper'; +import { Box } from '~components/Box'; +import { Button } from '~components/Button'; +import { useTheme } from '~utils'; +import { Amount } from '~components/Amount'; +import { Code } from '~components/Typography'; +import { Badge } from '~components/Badge'; + +export default { + title: 'Components/Table/API', + component: TableToolbar, + parameters: { + docs: { + page: () => ( + + ), + }, + }, +} as Meta; + +const nodes: Item[] = [ + ...Array.from({ length: 20 }, (_, i) => ({ + id: (i + 1).toString(), + paymentId: `rzp${Math.floor(Math.random() * 1000000)}`, + amount: Number((Math.random() * 10000).toFixed(2)), + status: ['Completed', 'Pending', 'Failed'][Math.floor(Math.random() * 3)], + date: new Date(2021, Math.floor(Math.random() * 12), Math.floor(Math.random() * 28) + 1), + type: ['Payout', 'Refund'][Math.floor(Math.random() * 2)], + method: ['Bank Transfer', 'Credit Card', 'PayPal'][Math.floor(Math.random() * 3)], + bank: ['HDFC', 'ICICI', 'SBI'][Math.floor(Math.random() * 3)], + account: Math.floor(Math.random() * 1000000000).toString(), + name: [ + 'John Doe', + 'Jane Doe', + 'Bob Smith', + 'Alice Smith', + 'John Smith', + 'Jane Smith', + 'Bob Doe', + 'Alice Doe', + ][Math.floor(Math.random() * 8)], + })), +]; + +type Item = { + id: string; + paymentId: string; + amount: number; + status: string; + date: Date; + type: string; + method: string; + bank: string; + account: string; + name: string; +}; +const data: TableData = { + nodes, +}; + +const TableTemplate: ComponentStory = ({ ...args }) => { + const { platform } = useTheme(); + const onMobile = platform === 'onMobile'; + + return ( + + console.log('Selected Rows:', values)} + sortFunctions={{ + ID: (array) => array.sort((a, b) => Number(a.id) - Number(b.id)), + AMOUNT: (array) => array.sort((a, b) => a.amount - b.amount), + ACCOUNT: (array) => array.sort((a, b) => Number(a.account) - Number(b.account)), + PAYMENT_ID: (array) => array.sort((a, b) => a.paymentId.localeCompare(b.paymentId)), + DATE: (array) => array.sort((a, b) => a.date.getTime() - b.date.getTime()), + METHOD: (array) => array.sort((a, b) => a.method.localeCompare(b.method)), + STATUS: (array) => array.sort((a, b) => a.status.localeCompare(b.status)), + }} + onSortChange={({ sortKey, isSortReversed }) => + console.log('Sort Key:', sortKey, 'Sort Reversed:', isSortReversed) + } + toolbar={ + + + + + + + } + pagination={ + + } + > + {(tableData) => ( + <> + + + ID + Amount + Account + Date + Method + Status + + + + {tableData.map((tableItem, index) => ( + + + {tableItem.paymentId} + + + + + {tableItem.account} + + {tableItem.date?.toLocaleDateString('en-IN', { + year: 'numeric', + month: '2-digit', + day: '2-digit', + })} + + {tableItem.method} + + + {tableItem.status} + + + + ))} + + + )} + + + ); +}; + +export const TableToolbarStory = TableTemplate.bind({}); +// Need to do this because of storybook's weird naming convention, More details here: https://storybook.js.org/docs/react/writing-stories/naming-components-and-hierarchy#single-story-hoisting +TableToolbarStory.storyName = 'TableToolbar'; diff --git a/packages/blade/src/components/Table/docs/APIStories/TableToolbarActionsAPI.stories.tsx b/packages/blade/src/components/Table/docs/APIStories/TableToolbarActionsAPI.stories.tsx new file mode 100644 index 00000000000..7ad2e1922a9 --- /dev/null +++ b/packages/blade/src/components/Table/docs/APIStories/TableToolbarActionsAPI.stories.tsx @@ -0,0 +1,182 @@ +import type { ComponentStory, Meta } from '@storybook/react'; +import type { TableData } from '../../Table'; +import { Table as TableComponent } from '../../Table'; +import { TableHeader, TableHeaderRow, TableHeaderCell } from '../../TableHeader'; +import { TableBody, TableRow, TableCell } from '../../TableBody'; +import { TableFooter, TableFooterRow, TableFooterCell } from '../../TableFooter'; +import { TablePagination } from '../../TablePagination'; +import { TableToolbarActions, TableToolbar } from '../../TableToolbar'; +import StoryPageWrapper from '~utils/storybook/StoryPageWrapper'; +import { Box } from '~components/Box'; +import { Button } from '~components/Button'; +import { useTheme } from '~utils'; +import { Amount } from '~components/Amount'; +import { Code } from '~components/Typography'; +import { Badge } from '~components/Badge'; +import { getStyledPropsArgTypes } from '~components/Box/BaseBox/storybookArgTypes'; + +export default { + title: 'Components/Table/API', + component: TableToolbarActions, + argTypes: { + ...getStyledPropsArgTypes(), + }, + parameters: { + docs: { + page: () => ( + + ), + }, + }, +} as Meta; + +const nodes: Item[] = [ + ...Array.from({ length: 20 }, (_, i) => ({ + id: (i + 1).toString(), + paymentId: `rzp${Math.floor(Math.random() * 1000000)}`, + amount: Number((Math.random() * 10000).toFixed(2)), + status: ['Completed', 'Pending', 'Failed'][Math.floor(Math.random() * 3)], + date: new Date(2021, Math.floor(Math.random() * 12), Math.floor(Math.random() * 28) + 1), + type: ['Payout', 'Refund'][Math.floor(Math.random() * 2)], + method: ['Bank Transfer', 'Credit Card', 'PayPal'][Math.floor(Math.random() * 3)], + bank: ['HDFC', 'ICICI', 'SBI'][Math.floor(Math.random() * 3)], + account: Math.floor(Math.random() * 1000000000).toString(), + name: [ + 'John Doe', + 'Jane Doe', + 'Bob Smith', + 'Alice Smith', + 'John Smith', + 'Jane Smith', + 'Bob Doe', + 'Alice Doe', + ][Math.floor(Math.random() * 8)], + })), +]; + +type Item = { + id: string; + paymentId: string; + amount: number; + status: string; + date: Date; + type: string; + method: string; + bank: string; + account: string; + name: string; +}; +const data: TableData = { + nodes, +}; + +const TableTemplate: ComponentStory = ({ ...args }) => { + const { platform } = useTheme(); + const onMobile = platform === 'onMobile'; + + return ( + + console.log('Selected Rows:', values)} + sortFunctions={{ + ID: (array) => array.sort((a, b) => Number(a.id) - Number(b.id)), + AMOUNT: (array) => array.sort((a, b) => a.amount - b.amount), + ACCOUNT: (array) => array.sort((a, b) => Number(a.account) - Number(b.account)), + PAYMENT_ID: (array) => array.sort((a, b) => a.paymentId.localeCompare(b.paymentId)), + DATE: (array) => array.sort((a, b) => a.date.getTime() - b.date.getTime()), + METHOD: (array) => array.sort((a, b) => a.method.localeCompare(b.method)), + STATUS: (array) => array.sort((a, b) => a.status.localeCompare(b.status)), + }} + onSortChange={({ sortKey, isSortReversed }) => + console.log('Sort Key:', sortKey, 'Sort Reversed:', isSortReversed) + } + toolbar={ + + + + + + + } + pagination={ + + } + > + {(tableData) => ( + <> + + + ID + Amount + Account + Date + Method + Status + + + + {tableData.map((tableItem, index) => ( + + + {tableItem.paymentId} + + + + + {tableItem.account} + + {tableItem.date?.toLocaleDateString('en-IN', { + year: 'numeric', + month: '2-digit', + day: '2-digit', + })} + + {tableItem.method} + + + {tableItem.status} + + + + ))} + + + )} + + + ); +}; + +export const TableToolbarActionsStory = TableTemplate.bind({}); +// Need to do this because of storybook's weird naming convention, More details here: https://storybook.js.org/docs/react/writing-stories/naming-components-and-hierarchy#single-story-hoisting +TableToolbarActionsStory.storyName = 'TableToolbarActions'; diff --git a/packages/blade/src/components/Table/docs/BasicTable.stories.tsx b/packages/blade/src/components/Table/docs/BasicTable.stories.tsx new file mode 100644 index 00000000000..b220a19ccf1 --- /dev/null +++ b/packages/blade/src/components/Table/docs/BasicTable.stories.tsx @@ -0,0 +1,157 @@ +import type { ComponentStory, Meta } from '@storybook/react'; +import type { TableData, TableProps } from '../Table'; +import { Table as TableComponent } from '../Table'; +import { TableHeader, TableHeaderRow, TableHeaderCell } from '../TableHeader'; +import { TableBody, TableRow, TableCell } from '../TableBody'; +import StoryPageWrapper from '~utils/storybook/StoryPageWrapper'; +import { Box } from '~components/Box'; +import { Amount } from '~components/Amount'; +import { Code } from '~components/Typography'; +import { Badge } from '~components/Badge'; +import { getStyledPropsArgTypes } from '~components/Box/BaseBox/storybookArgTypes'; + +export default { + title: 'Components/Table', + component: TableComponent, + args: { + selectionType: 'none', + rowDensity: 'normal', + }, + argTypes: { + ...getStyledPropsArgTypes(), + data: { + control: { + disable: true, + }, + }, + sortFunctions: { + control: { + disable: true, + }, + }, + toolbar: { + control: { + disable: true, + }, + }, + pagination: { + control: { + disable: true, + }, + }, + }, + parameters: { + docs: { + page: () => , + }, + }, +} as Meta>; + +const nodes: Item[] = [ + ...Array.from({ length: 5 }, (_, i) => ({ + id: (i + 1).toString(), + paymentId: `rzp${Math.floor(Math.random() * 1000000)}`, + amount: Number((Math.random() * 10000).toFixed(2)), + status: ['Completed', 'Pending', 'Failed'][Math.floor(Math.random() * 3)], + date: new Date(2021, Math.floor(Math.random() * 12), Math.floor(Math.random() * 28) + 1), + type: ['Payout', 'Refund'][Math.floor(Math.random() * 2)], + method: ['Bank Transfer', 'Credit Card', 'PayPal'][Math.floor(Math.random() * 3)], + bank: ['HDFC', 'ICICI', 'SBI'][Math.floor(Math.random() * 3)], + account: Math.floor(Math.random() * 1000000000).toString(), + name: [ + 'John Doe', + 'Jane Doe', + 'Bob Smith', + 'Alice Smith', + 'John Smith', + 'Jane Smith', + 'Bob Doe', + 'Alice Doe', + ][Math.floor(Math.random() * 8)], + })), +]; + +type Item = { + id: string; + paymentId: string; + amount: number; + status: string; + date: Date; + type: string; + method: string; + bank: string; + account: string; + name: string; +}; +const data: TableData = { + nodes, +}; + +const TableTemplate: ComponentStory = ({ ...args }) => { + return ( + + + {(tableData) => ( + <> + + + ID + Amount + Account + Date + Method + Status + + + + {tableData.map((tableItem, index) => ( + + + {tableItem.paymentId} + + + + + {tableItem.account} + + {tableItem.date?.toLocaleDateString('en-IN', { + year: 'numeric', + month: '2-digit', + day: '2-digit', + })} + + {tableItem.method} + + + {tableItem.status} + + + + ))} + + + )} + + + ); +}; + +export const Table = TableTemplate.bind({}); +// Need to do this because of storybook's weird naming convention, More details here: https://storybook.js.org/docs/react/writing-stories/naming-components-and-hierarchy#single-story-hoisting +Table.storyName = 'Basic Table'; diff --git a/packages/blade/src/components/Table/docs/TableExamples.stories.tsx b/packages/blade/src/components/Table/docs/TableExamples.stories.tsx new file mode 100644 index 00000000000..65b84af77dc --- /dev/null +++ b/packages/blade/src/components/Table/docs/TableExamples.stories.tsx @@ -0,0 +1,144 @@ +import React from 'react'; +import type { ComponentStory, Meta } from '@storybook/react'; +import { Table } from '../Table'; +import { + BasicTableStory, + TableWithCustomCellComponentsStory, + SortableTableStory, + SingleSelectableTableStory, + MultiSelectableWithToolbarTableStory, + MultiSelectableWithZebraStripesStory, + TableWithStickyHeaderAndFooterStory, + TableWithStickyFirstColumnStory, + TableWithPaginationStory, + TableWithDisabledRowsStory, + TableWithSurfaceLevelsStory, + TableWithIsLoadingStory, + TableWithIsRefreshingStory, +} from './stories'; +import { Sandbox } from '~utils/storybook/Sandbox'; + +const TableMeta: Meta = { + title: 'Components/Table/Examples', + component: Table, + parameters: { + viewMode: 'story', + options: { + showPanel: false, + }, + previewTabs: { + 'storybook/docs/panel': { + hidden: true, + }, + }, + chromatic: { disableSnapshot: true }, + }, +}; + +const TableTemplate: ComponentStory = () => { + return ( + + {BasicTableStory} + + ); +}; + +export const BasicTable = TableTemplate.bind({}); + +export const TableWithCustomCellComponents = (): React.ReactElement => { + return ( + + {TableWithCustomCellComponentsStory} + + ); +}; + +export const SortableTable = (): React.ReactElement => { + return ( + + {SortableTableStory} + + ); +}; + +export const TableWithStickyHeaderAndFooter = (): React.ReactElement => { + return ( + + {TableWithStickyHeaderAndFooterStory} + + ); +}; + +export const TableWithStickyFirstColumn = (): React.ReactElement => { + return ( + + {TableWithStickyFirstColumnStory} + + ); +}; + +export const SingleSelectableTable = (): React.ReactElement => { + return ( + + {SingleSelectableTableStory} + + ); +}; + +export const MultiSelectableTableWithToolbar = (): React.ReactElement => { + return ( + + {MultiSelectableWithToolbarTableStory} + + ); +}; + +export const MultiSelectableWithZebraStripes = (): React.ReactElement => { + return ( + + {MultiSelectableWithZebraStripesStory} + + ); +}; + +export const TableWithPagination = (): React.ReactElement => { + return ( + + {TableWithPaginationStory} + + ); +}; + +export const TableWithDisabledRows = (): React.ReactElement => { + return ( + + {TableWithDisabledRowsStory} + + ); +}; + +export const TableWithSurfaceLevels = (): React.ReactElement => { + return ( + + {TableWithSurfaceLevelsStory} + + ); +}; + +export const TableWithIsLoading = (): React.ReactElement => { + return ( + + {TableWithIsLoadingStory} + + ); +}; + +export const TableWithIsRefreshing = (): React.ReactElement => { + return ( + + {TableWithIsRefreshingStory} + + ); +}; + +export default TableMeta; diff --git a/packages/blade/src/components/Table/docs/stories.ts b/packages/blade/src/components/Table/docs/stories.ts new file mode 100644 index 00000000000..ee894f8a02e --- /dev/null +++ b/packages/blade/src/components/Table/docs/stories.ts @@ -0,0 +1,1834 @@ +const BasicTableStory = ` +import { + Table, + Heading, + Box, + TableHeader, + TableHeaderRow, + TableHeaderCell, + TableBody, + TableRow, + TableCell, +} from '@razorpay/blade/components'; +import type { TableData } from '@razorpay/blade/components'; +import React from 'react'; + +type Item = { + id: string; + paymentId: string; + amount: number; + date: Date; + method: string; +}; + +const nodes: Item[] = [ + ...Array.from({ length: 5 }, (_, i) => ({ + id: (i + 1).toString(), + paymentId: \`rzp\${Math.floor(Math.random() * 1000000)}\`, + amount: Number((Math.random() * 10000).toFixed(2)), + date: new Date( + 2021, + Math.floor(Math.random() * 12), + Math.floor(Math.random() * 28) + 1 + ), + method: ['Bank Transfer', 'Credit Card', 'PayPal'][ + Math.floor(Math.random() * 3) + ], + account: Math.floor(Math.random() * 1000000000).toString(), + })), +]; + +const data: TableData = { + nodes, +}; + +function App(): React.ReactElement { + return ( + + + Basic Table + + + {(tableData) => ( + <> + + + ID + Amount + Date + Method + + + + {tableData.map((tableItem, index) => ( + + {tableItem.paymentId} + {\`₹\${tableItem.amount.toString()}\`} + + {tableItem.date?.toLocaleDateString('en-IN', { + year: 'numeric', + month: '2-digit', + day: '2-digit', + })} + + {tableItem.method} + + ))} + + + )} +
+
+ ); +} + +export default App; +`; + +const TableWithCustomCellComponentsStory = ` +import { + Table, + Code, + Heading, + Box, + TableHeader, + TableHeaderRow, + TableHeaderCell, + TableBody, + TableRow, + TableCell, + Amount, + Badge, + Text, + InfoIcon, + IconButton, + Tooltip, +} from '@razorpay/blade/components'; +import type { TableData } from '@razorpay/blade/components'; +import React from 'react'; + +type Item = { + id: string; + paymentId: string; + amount: number; + date: Date; + status: string; +}; + +const nodes: Item[] = [ + ...Array.from({ length: 5 }, (_, i) => ({ + id: (i + 1).toString(), + paymentId: \`rzp\${Math.floor(Math.random() * 1000000)}\`, + amount: Number((Math.random() * 10000).toFixed(2)), + date: new Date( + 2021, + Math.floor(Math.random() * 12), + Math.floor(Math.random() * 28) + 1 + ), + status: ['Completed', 'Pending', 'Failed'][Math.floor(Math.random() * 3)], + account: Math.floor(Math.random() * 1000000000).toString(), + })), +]; + +const data: TableData = { + nodes, +}; + +function App(): React.ReactElement { + return ( + + + Table with Custom Cell Components + + + {(tableData) => ( + <> + + + + + ID + + console.log('info clicked')} + accessibilityLabel="info" + icon={InfoIcon} + /> + + + + + + Amount + + console.log('info clicked')} + accessibilityLabel="info" + icon={InfoIcon} + /> + + + + + + Date + + console.log('info clicked')} + accessibilityLabel="info" + icon={InfoIcon} + /> + + + + + + Status + + console.log('info clicked')} + accessibilityLabel="info" + icon={InfoIcon} + /> + + + + + + + {tableData.map((tableItem, index) => ( + + + {tableItem.paymentId} + + + + + + {tableItem.date?.toLocaleDateString('en-IN', { + year: 'numeric', + month: '2-digit', + day: '2-digit', + })} + + + + {tableItem.status} + + + + ))} + + + )} +
+
+ ); +} + +export default App; +`; + +const SortableTableStory = ` +import { + Table, + Code, + Heading, + Box, + TableHeader, + TableHeaderRow, + TableHeaderCell, + TableBody, + TableRow, + TableCell, + Amount, + Badge, +} from '@razorpay/blade/components'; +import type { TableData } from '@razorpay/blade/components'; +import React from 'react'; + +type Item = { + id: string; + paymentId: string; + amount: number; + date: Date; + status: string; +}; + +const nodes: Item[] = [ + ...Array.from({ length: 5 }, (_, i) => ({ + id: (i + 1).toString(), + paymentId: \`rzp\${Math.floor(Math.random() * 1000000)}\`, + amount: Number((Math.random() * 10000).toFixed(2)), + date: new Date( + 2021, + Math.floor(Math.random() * 12), + Math.floor(Math.random() * 28) + 1 + ), + status: ['Completed', 'Pending', 'Failed'][Math.floor(Math.random() * 3)], + account: Math.floor(Math.random() * 1000000000).toString(), + })), +]; + +const data: TableData = { + nodes, +}; + +function App(): React.ReactElement { + return ( + + + Sortable Table + + array.sort((a, b) => Number(a.id) - Number(b.id)), + AMOUNT: (array) => array.sort((a, b) => a.amount - b.amount), + PAYMENT_ID: (array) => + array.sort((a, b) => a.paymentId.localeCompare(b.paymentId)), + DATE: (array) => + array.sort((a, b) => a.date.getTime() - b.date.getTime()), + STATUS: (array) => + array.sort((a, b) => a.status.localeCompare(b.status)), + }} + > + {(tableData) => ( + <> + + + ID + Amount + Date + Method + + + + {tableData.map((tableItem, index) => ( + + + {tableItem.paymentId} + + + + + + {tableItem.date?.toLocaleDateString('en-IN', { + year: 'numeric', + month: '2-digit', + day: '2-digit', + })} + + + + {tableItem.status} + + + + ))} + + + )} +
+
+ ); +} + +export default App; +`; + +const SingleSelectableTableStory = ` +import { + Table, + Code, + Heading, + Box, + TableHeader, + TableHeaderRow, + TableHeaderCell, + TableBody, + TableRow, + TableCell, + Amount, + Badge, + Text, +} from '@razorpay/blade/components'; +import type { TableData } from '@razorpay/blade/components'; +import React, { useState } from 'react'; + +type Item = { + id: string; + paymentId: string; + amount: number; + date: Date; + status: string; +}; + +const nodes: Item[] = [ + ...Array.from({ length: 5 }, (_, i) => ({ + id: (i + 1).toString(), + paymentId: \`rzp\${Math.floor(Math.random() * 1000000)}\`, + amount: Number((Math.random() * 10000).toFixed(2)), + date: new Date( + 2021, + Math.floor(Math.random() * 12), + Math.floor(Math.random() * 28) + 1 + ), + status: ['Completed', 'Pending', 'Failed'][Math.floor(Math.random() * 3)], + account: Math.floor(Math.random() * 1000000000).toString(), + })), +]; + +const data: TableData = { + nodes, +}; + +function App(): React.ReactElement { + const [selectedItem, setSelectedItem] = useState(undefined); + return ( + + + Single Selectable Table + + setSelectedItem(values[0])} + > + {(tableData) => ( + <> + + + ID + Amount + Date + Method + + + + {tableData.map((tableItem, index) => ( + + + {tableItem.paymentId} + + + + + + {tableItem.date?.toLocaleDateString('en-IN', { + year: 'numeric', + month: '2-digit', + day: '2-digit', + })} + + + + {tableItem.status} + + + + ))} + + + )} +
+ + Selected Row ID: + {selectedItem?.paymentId} + +
+ ); +} + +export default App; +`; + +const MultiSelectableWithToolbarTableStory = ` +import { + Table, + Code, + Heading, + Box, + TableHeader, + TableHeaderRow, + TableHeaderCell, + TableBody, + TableRow, + TableCell, + Amount, + Badge, + TableToolbar, + TableToolbarActions, + Button, + useTheme, + Text, +} from '@razorpay/blade/components'; +import type { TableData } from '@razorpay/blade/components'; +import React, { useState } from 'react'; + +type Item = { + id: string; + paymentId: string; + amount: number; + date: Date; + status: string; +}; + +const nodes: Item[] = [ + ...Array.from({ length: 5 }, (_, i) => ({ + id: (i + 1).toString(), + paymentId: \`rzp\${Math.floor(Math.random() * 1000000)}\`, + amount: Number((Math.random() * 10000).toFixed(2)), + date: new Date( + 2021, + Math.floor(Math.random() * 12), + Math.floor(Math.random() * 28) + 1 + ), + status: ['Completed', 'Pending', 'Failed'][Math.floor(Math.random() * 3)], + account: Math.floor(Math.random() * 1000000000).toString(), + })), +]; + +const data: TableData = { + nodes, +}; + +function App(): React.ReactElement { + const [selectedItems, setSelectedItems] = useState([]); + const { platform } = useTheme(); + const onMobile = platform === 'onMobile'; + const selectedItemsLength = selectedItems.length; + return ( + + + Multi Selectable Table with Toolbar + (Tip: Expand screen Width to see layout changes in toolbar) + + setSelectedItems(values)} + toolbar={ + 1 ? 's' : '' + } Selected\`} + > + + + + + + } + > + {(tableData) => ( + <> + + + ID + Amount + Date + Method + + + + {tableData.map((tableItem, index) => ( + + + {tableItem.paymentId} + + + + + + {tableItem.date?.toLocaleDateString('en-IN', { + year: 'numeric', + month: '2-digit', + day: '2-digit', + })} + + + + {tableItem.status} + + + + ))} + + + )} +
+
+ ); +} + +export default App; +`; + +const MultiSelectableWithZebraStripesStory = ` +import { + Table, + Code, + Heading, + Box, + TableHeader, + TableHeaderRow, + TableHeaderCell, + TableBody, + TableRow, + TableCell, + Amount, + Badge, + TableToolbar, + TableToolbarActions, + Button, + useTheme, +} from '@razorpay/blade/components'; +import type { TableData } from '@razorpay/blade/components'; +import React from 'react'; + +type Item = { + id: string; + paymentId: string; + amount: number; + date: Date; + status: string; +}; + +const nodes: Item[] = [ + ...Array.from({ length: 5 }, (_, i) => ({ + id: (i + 1).toString(), + paymentId: \`rzp\${Math.floor(Math.random() * 1000000)}\`, + amount: Number((Math.random() * 10000).toFixed(2)), + date: new Date( + 2021, + Math.floor(Math.random() * 12), + Math.floor(Math.random() * 28) + 1 + ), + status: ['Completed', 'Pending', 'Failed'][Math.floor(Math.random() * 3)], + account: Math.floor(Math.random() * 1000000000).toString(), + })), +]; + +const data: TableData = { + nodes, +}; + +function App(): React.ReactElement { + const { platform } = useTheme(); + const onMobile = platform === 'onMobile'; + return ( + + + Multi Selectable Table with Zebra Stripes + + + + + + + + } + > + {(tableData) => ( + <> + + + ID + Amount + Date + Method + + + + {tableData.map((tableItem, index) => ( + + + {tableItem.paymentId} + + + + + + {tableItem.date?.toLocaleDateString('en-IN', { + year: 'numeric', + month: '2-digit', + day: '2-digit', + })} + + + + {tableItem.status} + + + + ))} + + + )} +
+
+ ); +} + +export default App; +`; + +const TableWithStickyHeaderAndFooterStory = ` +import { + Table, + Code, + Heading, + Box, + TableHeader, + TableHeaderRow, + TableHeaderCell, + TableBody, + TableRow, + TableCell, + Amount, + Badge, + TableFooter, + TableFooterRow, + TableFooterCell, +} from '@razorpay/blade/components'; +import type { TableData } from '@razorpay/blade/components'; +import React from 'react'; + +type Item = { + id: string; + paymentId: string; + amount: number; + date: Date; + status: string; +}; + +const nodes: Item[] = [ + ...Array.from({ length: 20 }, (_, i) => ({ + id: (i + 1).toString(), + paymentId: \`rzp\${Math.floor(Math.random() * 1000000)}\`, + amount: Number((Math.random() * 10000).toFixed(2)), + date: new Date( + 2021, + Math.floor(Math.random() * 12), + Math.floor(Math.random() * 28) + 1 + ), + status: ['Completed', 'Pending', 'Failed'][Math.floor(Math.random() * 3)], + account: Math.floor(Math.random() * 1000000000).toString(), + })), +]; + +const data: TableData = { + nodes, +}; + +function App(): React.ReactElement { + const totalAmount = nodes.reduce((acc, curr) => acc + curr.amount, 0); + + return ( + + + Table with Sticky Header & Sticky Footer + + + {(tableData) => ( + <> + + + ID + Date + Method + Amount + + + + {tableData.map((tableItem, index) => ( + + + {tableItem.paymentId} + + + + {tableItem.date?.toLocaleDateString('en-IN', { + year: 'numeric', + month: '2-digit', + day: '2-digit', + })} + + + + {tableItem.status} + + + + + + + ))} + + + + Total + - + - + + + + + + + )} +
+
+ ); +} + +export default App; +`; + +const TableWithStickyFirstColumnStory = ` +import { + Table, + Code, + Heading, + Box, + TableHeader, + TableHeaderRow, + TableHeaderCell, + TableBody, + TableRow, + TableCell, + Amount, + Badge, +} from '@razorpay/blade/components'; +import type { TableData } from '@razorpay/blade/components'; +import React from 'react'; + +type Item = { + id: string; + paymentId: string; + amount: number; + date: Date; + status: string; + account: string; + method: string; + name: string; +}; + +const nodes: Item[] = [ + ...Array.from({ length: 20 }, (_, i) => ({ + id: (i + 1).toString(), + paymentId: \`rzp\${Math.floor(Math.random() * 1000000)}\`, + amount: Number((Math.random() * 10000).toFixed(2)), + date: new Date( + 2021, + Math.floor(Math.random() * 12), + Math.floor(Math.random() * 28) + 1 + ), + status: ['Completed', 'Pending', 'Failed'][Math.floor(Math.random() * 3)], + account: Math.floor(Math.random() * 1000000000).toString(), + type: ['Payout', 'Refund'][Math.floor(Math.random() * 2)], + method: ['Bank Transfer', 'Credit Card', 'PayPal'][ + Math.floor(Math.random() * 3) + ], + name: [ + 'John Doe', + 'Jane Doe', + 'Bob Smith', + 'Alice Smith', + 'John Smith', + 'Jane Smith', + 'Bob Doe', + 'Alice Doe', + ][Math.floor(Math.random() * 8)], + })), +]; + +const data: TableData = { + nodes, +}; + +function App(): React.ReactElement { + return ( + + + Table with Sticky First Column + + + {(tableData) => ( + <> + + + ID + Name + Account + Method + Date + Method + Amount + + + + {tableData.map((tableItem, index) => ( + + + {tableItem.paymentId} + + {tableItem.name} + {tableItem.account} + {tableItem.method} + + {tableItem.date?.toLocaleDateString('en-IN', { + year: 'numeric', + month: '2-digit', + day: '2-digit', + })} + + + + {tableItem.status} + + + + + + + ))} + + + )} +
+
+ ); +} + +export default App; +`; + +const TableWithPaginationStory = ` +import { + Table, + Code, + Heading, + Box, + TableHeader, + TableHeaderRow, + TableHeaderCell, + TableBody, + TableRow, + TableCell, + Amount, + Badge, + TableToolbar, + TableToolbarActions, + Button, + useTheme, + TablePagination, + Text, +} from '@razorpay/blade/components'; +import type { TableData } from '@razorpay/blade/components'; +import React from 'react'; + +type Item = { + id: string; + paymentId: string; + amount: number; + date: Date; + status: string; +}; + +const nodes: Item[] = [ + ...Array.from({ length: 100 }, (_, i) => ({ + id: (i + 1).toString(), + paymentId: \`rzp\${Math.floor(Math.random() * 1000000)}\`, + amount: Number((Math.random() * 10000).toFixed(2)), + date: new Date( + 2021, + Math.floor(Math.random() * 12), + Math.floor(Math.random() * 28) + 1 + ), + status: ['Completed', 'Pending', 'Failed'][Math.floor(Math.random() * 3)], + account: Math.floor(Math.random() * 1000000000).toString(), + })), +]; + +const data: TableData = { + nodes, +}; + +function App(): React.ReactElement { + const { platform } = useTheme(); + const onMobile = platform === 'onMobile'; + + return ( + + + Multi Selectable Table with Zebra Stripes + + (Tip: Expand the window width. It shows a minimalistic version of + pagination on mWeb and a full fletched version on dWeb.) + + + + + + + + + } + pagination={ + + } + > + {(tableData) => ( + <> + + + ID + Amount + Date + Method + + + + {tableData.map((tableItem, index) => ( + + + {tableItem.paymentId} + + + + + + {tableItem.date?.toLocaleDateString('en-IN', { + year: 'numeric', + month: '2-digit', + day: '2-digit', + })} + + + + {tableItem.status} + + + + ))} + + + )} +
+
+ ); +} + +export default App; +`; + +const TableWithDisabledRowsStory = ` +import { + Table, + Code, + Heading, + Box, + TableHeader, + TableHeaderRow, + TableHeaderCell, + TableBody, + TableRow, + TableCell, + Amount, + TableToolbar, + TableToolbarActions, + Button, + useTheme, + Link, + TrashIcon, + CopyIcon, +} from '@razorpay/blade/components'; +import type { TableData } from '@razorpay/blade/components'; +import React from 'react'; + +type Item = { + id: string; + paymentId: string; + amount: number; + date: Date; + status: string; +}; + +const nodes: Item[] = [ + ...Array.from({ length: 10 }, (_, i) => ({ + id: (i + 1).toString(), + paymentId: \`rzp\${Math.floor(Math.random() * 1000000)}\`, + amount: Number((Math.random() * 10000).toFixed(2)), + date: new Date( + 2021, + Math.floor(Math.random() * 12), + Math.floor(Math.random() * 28) + 1 + ), + status: ['Completed', 'Pending', 'Failed'][Math.floor(Math.random() * 3)], + account: Math.floor(Math.random() * 1000000000).toString(), + })), +]; + +const data: TableData = { + nodes, +}; + +function App(): React.ReactElement { + const { platform } = useTheme(); + const onMobile = platform === 'onMobile'; + + return ( + + + Table with Disabled Rows + + + + + + + + } + > + {(tableData) => ( + <> + + + ID + Amount + Action + + + + {tableData.map((tableItem, index) => { + const isDisabled = ['0', '4', '10'].includes(tableItem.id); + return ( + + + {tableItem.paymentId} + + + + + + + + + Copy + + + Delete + + + + + ); + })} + + + )} +
+
+ ); +} + +export default App; +`; + +const TableWithSurfaceLevelsStory = ` +import { + Table, + Heading, + Box, + TableHeader, + TableHeaderRow, + TableHeaderCell, + TableBody, + TableRow, + TableCell, + RadioGroup, + Radio, + TableFooter, + TableFooterRow, + TableFooterCell, +} from '@razorpay/blade/components'; +import type { TableData } from '@razorpay/blade/components'; +import React, { useState } from 'react'; + +type Item = { + id: string; + paymentId: string; + amount: number; + date: Date; + method: string; +}; + +const nodes: Item[] = [ + ...Array.from({ length: 5 }, (_, i) => ({ + id: (i + 1).toString(), + paymentId: \`rzp\${Math.floor(Math.random() * 1000000)}\`, + amount: Number((Math.random() * 10000).toFixed(2)), + date: new Date( + 2021, + Math.floor(Math.random() * 12), + Math.floor(Math.random() * 28) + 1 + ), + method: ['Bank Transfer', 'Credit Card', 'PayPal'][ + Math.floor(Math.random() * 3) + ], + account: Math.floor(Math.random() * 1000000000).toString(), + })), +]; + +const data: TableData = { + nodes, +}; + +type SurfaceLevels = 1 | 2 | 3; + +function App(): React.ReactElement { + const [surfaceLevel, setSurfaceLevel] = useState(1); + return ( + + + + Table on various Surface Levels + + + setSurfaceLevel(Number(value) as SurfaceLevels) + } + value={\`\${surfaceLevel}\`} + > + 1 + 2 + 3 + + + + {(tableData) => ( + <> + + + ID + Amount + Date + Method + + + + {tableData.map((tableItem, index) => ( + + {tableItem.paymentId} + {\`₹\${tableItem.amount.toString()}\`} + + {tableItem.date?.toLocaleDateString('en-IN', { + year: 'numeric', + month: '2-digit', + day: '2-digit', + })} + + {tableItem.method} + + ))} + + + + - + - + - + - + - + + + + )} +
+
+ ); +} + +export default App; +`; + +const TableWithIsLoadingStory = ` +import { + Table, + Code, + Heading, + Box, + TableHeader, + TableHeaderRow, + TableHeaderCell, + TableBody, + TableRow, + TableCell, + Amount, + Badge, + TableToolbar, + TableToolbarActions, + Button, + useTheme, + TablePagination, + Link, +} from '@razorpay/blade/components'; +import type { TableData } from '@razorpay/blade/components'; +import React, { useEffect, useState } from 'react'; + +type Item = { + id: string; + paymentId: string; + amount: number; + date: Date; + status: string; +}; + +const nodes: Item[] = [ + ...Array.from({ length: 100 }, (_, i) => ({ + id: (i + 1).toString(), + paymentId: \`rzp\${Math.floor(Math.random() * 1000000)}\`, + amount: Number((Math.random() * 10000).toFixed(2)), + date: new Date( + 2021, + Math.floor(Math.random() * 12), + Math.floor(Math.random() * 28) + 1 + ), + status: ['Completed', 'Pending', 'Failed'][Math.floor(Math.random() * 3)], + account: Math.floor(Math.random() * 1000000000).toString(), + })), +]; + +function App(): React.ReactElement { + const { platform } = useTheme(); + const [showData, setShowData] = useState(false); + useEffect(() => { + setTimeout(() => { + if (!showData) setShowData(true); + }, 2000); + }, [showData]); + + const onMobile = platform === 'onMobile'; + const data: TableData = { + nodes: nodes, + }; + + return ( + + Table with initial isLoading state + { + setShowData(false); + }} + > + Refresh to show loader again + + + + + + + + + } + pagination={ + + } + isLoading={!showData} + > + {(tableData) => ( + <> + + + ID + Amount + Date + Method + + + + {tableData.map((tableItem, index) => ( + + + {tableItem.paymentId} + + + + + + {tableItem.date?.toLocaleDateString('en-IN', { + year: 'numeric', + month: '2-digit', + day: '2-digit', + })} + + + + {tableItem.status} + + + + ))} + + + )} +
+
+
+ ); +} + +export default App; +`; + +const TableWithIsRefreshingStory = ` +import { + Table, + Code, + Heading, + Box, + TableHeader, + TableHeaderRow, + TableHeaderCell, + TableBody, + TableRow, + TableCell, + Amount, + Badge, + TableToolbar, + TableToolbarActions, + Button, + useTheme, + TablePagination, + Text, + TableProps, +} from '@razorpay/blade/components'; +import React, { useState } from 'react'; + +type Item = { + id: string; + paymentId: string; + amount: number; + date: Date; + status: string; +}; + +const nodes: Item[] = [ + ...Array.from({ length: 100 }, (_, i) => ({ + id: (i + 1).toString(), + paymentId: \`rzp\${Math.floor(Math.random() * 1000000)}\`, + amount: Number((Math.random() * 10000).toFixed(2)), + date: new Date( + 2021, + Math.floor(Math.random() * 12), + Math.floor(Math.random() * 28) + 1 + ), + status: ['Completed', 'Pending', 'Failed'][Math.floor(Math.random() * 3)], + account: Math.floor(Math.random() * 1000000000).toString(), + })), +]; + +const data: TableProps['data'] = { + nodes, +}; + +function App(): React.ReactElement { + const { platform } = useTheme(); + const [currentPage, setCurrentPage] = useState(0); + const [isRefreshing, setIsRefreshing] = useState(false); + const onMobile = platform === 'onMobile'; + + const handlePageChange = ({ page }: { page: number }) => { + if (currentPage !== page) { + setIsRefreshing(true); + setTimeout(() => { + setCurrentPage(page); + setIsRefreshing(false); + }, 2000); + } + }; + + return ( + + + Table with isRefreshing state + + (Tip: Navigate to next page using the pagination buttons to see an + isRefreshing state.) + + + + + + + + + } + pagination={ + + } + > + {(tableData) => ( + <> + + + ID + Amount + Date + Method + + + + {tableData.map((tableItem, index) => ( + + + {tableItem.paymentId} + + + + + + {tableItem.date?.toLocaleDateString('en-IN', { + year: 'numeric', + month: '2-digit', + day: '2-digit', + })} + + + + {tableItem.status} + + + + ))} + + + )} +
+
+ ); +} + +export default App; +`; + +export { + BasicTableStory, + TableWithCustomCellComponentsStory, + SortableTableStory, + SingleSelectableTableStory, + MultiSelectableWithToolbarTableStory, + MultiSelectableWithZebraStripesStory, + TableWithStickyHeaderAndFooterStory, + TableWithStickyFirstColumnStory, + TableWithPaginationStory, + TableWithDisabledRowsStory, + TableWithSurfaceLevelsStory, + TableWithIsLoadingStory, + TableWithIsRefreshingStory, +}; diff --git a/packages/blade/src/components/Table/types.ts b/packages/blade/src/components/Table/types.ts index 87b868ce9a2..3c2b43ef0bd 100644 --- a/packages/blade/src/components/Table/types.ts +++ b/packages/blade/src/components/Table/types.ts @@ -178,7 +178,7 @@ type TableRowProps = { **/ children: React.ReactNode; /** - * The item prop is used to pass the item to the TableRow component. + * The item prop is used to pass the individual table item to the TableRow component. * @example * tableData.map((tableItem) => ( * diff --git a/packages/blade/src/utils/storybook/Sandbox/baseCode.ts b/packages/blade/src/utils/storybook/Sandbox/baseCode.ts index 15fa87cdb2d..5ca5665652f 100644 --- a/packages/blade/src/utils/storybook/Sandbox/baseCode.ts +++ b/packages/blade/src/utils/storybook/Sandbox/baseCode.ts @@ -85,7 +85,7 @@ export const vitePackageJSON = JSON.stringify( build: 'vite build', }, stackblitz: { - startCommand: 'pnpm install && pnpm dev', + startCommand: 'yarn install && yarn dev', installDependencies: false, }, ...getViteReactTSDependencies(), diff --git a/packages/blade/src/utils/storybook/StoryPageWrapper.tsx b/packages/blade/src/utils/storybook/StoryPageWrapper.tsx index 0e7956da6a5..a8c7e69d688 100644 --- a/packages/blade/src/utils/storybook/StoryPageWrapper.tsx +++ b/packages/blade/src/utils/storybook/StoryPageWrapper.tsx @@ -40,6 +40,10 @@ type StoryPageWrapperTypes = { * Use this to override default imports */ imports?: string; + /** + * Use this to override default API decision component name + */ + apiDecisionComponentName?: string; }; // Global Styles are not applied by default on `.mdx` pages of storybook. So just overriding few global styles here which are applied to both, stories and guide pages @@ -164,7 +168,7 @@ const StoryPageWrapper = (props: StoryPageWrapperTypes): React.ReactElement => { `https://github.com/razorpay/blade/blob/master/packages/blade/src/components/${props.componentName}/_decisions/decisions.md` } > - API Decisions for {props.componentName} + API Decisions for {props.apiDecisionComponentName ?? props.componentName} )}