import { type Meta, type StoryObj } from '@storybook/react-vite' import React, { useCallback, useMemo, useState } from 'react' import { isEqual } from 'lodash' import { DocsTemplate } from '../../../.storybook' import { type ActiveFilterProps } from '../SortColumn/SortColumn' import FormLabel from '../FormLabel/FormLabel' import { hasValue, notEmpty } from '../../services/HelperServiceTyped' import Picker from '../Picker/Picker' import Switch from '../Switch/Switch' import Tag from '../Tag/Tag' import Tiles from '../Tiles/Tiles/Tiles' import Tooltip from '../Tooltip/Tooltip' import MdashCheck from '../Mdash/MdashCheck' import { toast } from '../Toast/Toast' import StandardTable from './StandardTable' import { TableDocs } from './TableStoryHelper' import { tableHeaderStoryArgs } from './TableHeader/TableHeaderStoryHelper' import { extraTableSampleData, generateRandomSampleData, generateTableConfig, groupAccordionSampleData, multiNestedTableSampleData, nestedRowStylingData, nestedTableSampleData, standardTableSampleData, tableConfig, type TableObjectType, } from './StandardTableStoryHelpers' import { NESTED_PARENT_KEY } from './helperCheckboxFunctions' import { type ActiveTableFilterObj } from './TableFilter/TableFilter' import { generateTiles } from '../Tiles/tile-stories-helper' const meta: Meta = { title: 'Components/Tables/StandardTable', component: StandardTable, parameters: { layout: 'padded', design: { type: 'figma', url: 'https://www.figma.com/design/RvhKD82948FMQnh5MyCi0o/Web-Design-System?node-id=121-349&t=CdMnrLNv0lNFwXr0-0', }, docs: { page: () => ( } /> ), }, }, } export default meta type Story = StoryObj // Common sorting hook for the table components function useSortableData( initialData: TableObjectType[], initialSort: { prop: string; flip: boolean }, activeFilter?: ActiveFilterProps, ) { const [sort, setSort] = useState(initialSort) const setSortBy = (sortObj: { activeColumn: string; direction: boolean }) => { setSort({ prop: sortObj.activeColumn, flip: sortObj.direction, }) } const data = useMemo(() => { let filteredRecords = [...initialData] if (activeFilter && Object.keys(activeFilter).length > 0) { Object.values(activeFilter).forEach( ({ text: symbol, actualValue, value, keyField }) => { const filterValue = actualValue ? Number(actualValue.toString()) : Number(value.toString()) filteredRecords = filteredRecords.filter((record) => { const value = record[keyField] const finalValue = value.toString().includes('$') ? value.replace('$', '').trim() : value const recordValue = Number(finalValue) switch (symbol) { case '>': return recordValue > filterValue case '≥': return recordValue >= filterValue case '<': return recordValue < filterValue case '≤': return recordValue <= filterValue default: return true } }) }, ) } filteredRecords.sort((a, b) => { const aVal = a[sort.prop] const bVal = b[sort.prop] if (aVal < bVal) { return sort.flip ? -1 : 1 } if (aVal > bVal) { return sort.flip ? 1 : -1 } return 0 }) return filteredRecords }, [activeFilter, initialData, sort.flip, sort.prop]) return { data, sort, setSortBy } } // Common column selection hook for table components function useSelectionList(defaultColumns: string[]) { const [selectionList, setSelectionList] = useState(defaultColumns) const resetSelectionList = () => setSelectionList(defaultColumns) return { selectionList, setSelectionList, resetSelectionList } } // Custom column settings for the table interface SettingsProps { selectionList: string[] defaultColumns: string[] setSelectionList: (selectionList: string[]) => void resetSelectionList: () => void topChildren?: React.ReactNode bottomChildren?: React.ReactNode isColumnsReorderable?: boolean getSecondaryOption?: (label: string) => React.ReactNode } const tableSettings = ({ selectionList, defaultColumns, setSelectionList, resetSelectionList, topChildren, bottomChildren, isColumnsReorderable, getSecondaryOption, }: SettingsProps) => ({ title: 'Table Settings', selected: selectionList, list: defaultColumns, callout: setSelectionList, setToDefaultCallout: resetSelectionList, topChildren, bottomChildren, cancelCallout: () => toast({ type: 'success', message: 'Canceled modified settings.', }), isColumnsReorderable, getSecondaryOption, }) const defaultColumns = [ 'Tag', 'Number', 'Decimal', 'Percent', 'Currency', 'String', 'Availability', 'Traffic', 'Conversion', 'Price', 'Loyalty', ] const HandleStandardTable = (args) => { const { data, sort, setSortBy } = useSortableData(args.data, { prop: 'name', flip: true, }) const { selectionList, setSelectionList, resetSelectionList } = useSelectionList(defaultColumns) const options = [ { id: 1, text: 'Option 1', value: 'option-1', }, { id: 2, text: 'Option 2', value: 'option-2', }, { id: 3, text: 'Option 3', value: 'option-3', }, ] const [toggleState, setToggleState] = useState(false) const [active, setActive] = useState(options[0]) const updateSelected = (value: string) => { const activeOption = options.find((item) => item.value === value) setActive(activeOption || options[0]) toast({ type: 'success', message: `${activeOption?.text} Selected`, }) } const TopSettings = () => (
{ setToggleState(!toggleState) toast({ type: 'success', message: `${ !toggleState ? 'Settings Enabled' : 'Settings Disabled' }`, }) }} />
) const BottomSettings = () => (
{ updateSelected(value) }} options={options} state={active} stateName='value' />
) // Used to demo the table with expandable rows. const [activeRowId, setActiveRowId] = useState(null) const [tiles, setTiles] = useState(generateTiles(4)) return ( selectionList.includes(c.label) || c.label === 'Name', )} customColumnProps={tableSettings({ selectionList, defaultColumns, setSelectionList, resetSelectionList, topChildren: TopSettings(), bottomChildren: BottomSettings(), })} {...(args.noSort ? { noSort: true } : { sort: setSortBy, sortBy: sort })} data={data} {...(args.hasExpandableContent ? { hasExpandableContent: true, expandedAccordionContent: { id: activeRowId, isLoading: false, content: ( setTiles(newTiles)} /> ), callout: (id: string | number) => { setActiveRowId(id) }, }, } : {})} /> ) } const Template: Story = { render: ({ ...args }) => { return }, } const HandleStandardTableWithHeader = (args) => { const [activeFilters, setActiveFilters] = useState({}) const { data, sort, setSortBy } = useSortableData( args.data, { prop: 'name', flip: true, }, activeFilters, ) const { selectionList, setSelectionList, resetSelectionList } = useSelectionList(args.tableHeaderProps?.customColumnProps?.list) const remove = (filter?: ActiveTableFilterObj & { keyField: string }) => { if (filter) { setActiveFilters((prevState) => { const prevStateCopy = { ...prevState } Object.keys(prevStateCopy).forEach((key) => { if (prevStateCopy[key].keyField === filter.keyField) { delete prevStateCopy[key] } }) return prevStateCopy }) } else { setActiveFilters({}) } } return ( <> args.config?.filter((item) => item.label === text)?.[0], ) .filter((item) => hasValue(item)), ] : args.config.reduce((acc, c) => { if (selectionList.includes(c.label) || c.label === 'Name') { const column = notEmpty(c.filter) ? { ...c, filter: { ...c.filter, callout: ( _: string, selectedColumnFilter: ActiveFilterProps, ) => { if (notEmpty(selectedColumnFilter[c.label].value)) { setActiveFilters((prev) => ({ ...prev, ...selectedColumnFilter, })) } }, }, } : c acc.push(column) } return acc }, []) } {...(args.tableHeaderProps ? { tableHeaderProps: { ...args.tableHeaderProps, customColumnProps: tableSettings({ selectionList, defaultColumns: args.tableHeaderProps?.customColumnProps?.list, setSelectionList, resetSelectionList, isColumnsReorderable: args.tableHeaderProps?.customColumnProps ?.isColumnsReorderable, getSecondaryOption: args.tableHeaderProps?.customColumnProps ?.getSecondaryOption, }), columnFilterProps: { activeFilters, remove, }, }, } : {})} sortBy={sort} sort={setSortBy} data={data} /> ) } const TemplateWithHeader: Story = { render: ({ ...args }) => { return }, } const storyConfig = { data: standardTableSampleData, config: tableConfig, dataKey: 'name', hasData: true, hasMore: false, successStatus: true, loading: false, tableId: 'unique_table_string', noDataFields: { primaryText: 'No Data Available', secondaryText: 'There has been a problem with the data file. Please restart your computer.', }, getData: () => undefined, } const { config, loading } = storyConfig export const basicTable = { ...Template, args: storyConfig, parameters: { docs: { source: { code: ``, }, }, }, } const tableHeaderColumns = generateTableConfig( ['Name', ...defaultColumns], false, true, ) export const tableHeader = { ...TemplateWithHeader, args: { ...storyConfig, config: tableHeaderColumns, tableHeaderProps: { ...tableHeaderStoryArgs, customColumnProps: { list: defaultColumns, }, }, }, parameters: { docs: { source: { code: ``, }, }, }, } const customColumns = (isLongTooltip?: boolean) => generateTableConfig(['Name', ...defaultColumns], false, false, isLongTooltip) const showCheckedItemsToast = (checkedItems: any[]) => { const items = checkedItems.map((item) => item?.name).join(', ') toast({ type: 'info', message: checkedItems.length > 0 ? `Checked rows: ${items}` : 'No rows checked!', }) } export const customizeColumns = { ...Template, args: { ...storyConfig, config: customColumns(true), customColumnProps: true, }, parameters: { docs: { source: { code: ``, }, }, }, } customizeColumns.storyName = 'Customize Columns (Desktop only)' export const rowStyling = { ...Template, args: { ...storyConfig, data: standardTableSampleData.map((item: TableObjectType) => { // Create alternating pattern with multiple color variations if (item.number === 1 || item.number === 2) { return { ...item, rowClassName: 'bgc-light-red' } } if (item.number === 10) { return { ...item, rowClassName: 'bgc-light-yellow' } } if (item.number === 11 || item.number === 12) { return { ...item, rowClassName: 'bgc-light-green' } } if (item.number === 14) { return { ...item, rowStyle: { fontWeight: 'bold', backgroundColor: 'var(--light-purple)', }, } } return item }), }, } export const rowStylingWithCheckboxes = { ...Template, args: { ...storyConfig, hasCheckboxes: true, handleCheckedBoxes: (checkedItems: TableObjectType[]) => { showCheckedItemsToast(checkedItems) }, data: standardTableSampleData.map((item: TableObjectType) => { // Highlight rows with checkbox column also styled if (item.number === 1 || item.number === 10) { return { ...item, rowClassName: 'bgc-light-red' } } if (item.number === 13 || item.number === 14) { return { ...item, rowClassName: 'bgc-light-yellow' } } return item }), }, } rowStylingWithCheckboxes.storyName = 'Row Styling with Checkboxes' export const cellOverrideRow = { ...Template, args: { ...storyConfig, data: standardTableSampleData.map((item: TableObjectType) => { if (item.number === 1) { return { ...item, rowClassName: 'bgc-light-red', } } if (item.number === 2) { return { ...item, rowStyle: { backgroundColor: 'var(--light-yellow)' }, } } if (item.number === 3) { return { ...item, rowClassName: 'bgc-light-green', } } if (item.number === 4) { return { ...item, rowStyle: { backgroundColor: 'var(--light-red)' }, } } return item }), config: storyConfig.config.map((configItem, index) => { if (index === 1) { return { ...configItem, cell: { ...configItem.cell, className: (data: TableObjectType) => { if (data.number === 1) { return 'bgc-light-blue' } return '' }, }, } } if (index === 2) { return { ...configItem, cell: { ...configItem.cell, style: (data: TableObjectType) => { if (data.number === 1) { return { backgroundColor: 'var(--light-blue)' } } if (data.number === 2) { return { backgroundColor: 'var(--light-purple)' } } if (data.number === 3) { return { backgroundColor: 'var(--light-orange)' } } return {} }, }, } } return configItem }), }, } cellOverrideRow.storyName = 'Cell Styling' export const rowStylingWithNestedRows = { ...Template, args: { ...storyConfig, nestedDataKey: 'id', data: standardTableSampleData.map((item: TableObjectType) => { if (item.number === 1) return { ...item, rowClassName: 'bgc-light-red' } if (item.number === 2) return { ...item, rowClassName: 'bgc-light-yellow' } if (item.number === 3) return { ...item, rowClassName: 'bgc-light-green' } return item }), nestedRowProps: { nestedData: nestedRowStylingData, getNestedData: () => undefined, showCaret: (dataItem: TableObjectType) => [1, 2, 3].includes(dataItem?.id), }, }, } rowStylingWithNestedRows.storyName = 'Row Styling with Nested Rows' export const checkboxTable = { ...Template, args: { ...storyConfig, hasCheckboxes: true, disableCheckboxes: (item: TableObjectType) => item.number === 3, handleCheckedBoxes: (checkedItems: TableObjectType[]) => { showCheckedItemsToast(checkedItems) }, disableCheckAll: false, }, parameters: { docs: { source: { code: ` item.number === 3} handleCheckedBoxes={(checkedItems) => { // Handle checked items }} />`, }, }, }, } export const DisabledCheckAll = { ...Template, args: { ...storyConfig, hasCheckboxes: true, disableCheckboxes: (item) => item.number === 3, handleCheckedBoxes: (checkedItems) => { showCheckedItemsToast(checkedItems) }, disableCheckAll: true, }, parameters: { docs: { source: { code: ` item.number === 3} handleCheckedBoxes={(checkedItems) => { // Handle checked items }} />`, }, }, }, } export const checkboxTableWithSelectOptions = { ...Template, args: { ...storyConfig, hasCheckboxes: true, handleCheckedBoxes: (checkedItems) => { showCheckedItemsToast(checkedItems) }, checkboxSelectOptions: { options: [ { name: 'option1', label: 'Option 1' }, { name: 'option2', label: 'Option 2' }, { name: 'option3', label: 'Option 3' }, ], callout: (option) => { toast({ type: 'success', message: `You clicked on ${option.label}!`, }) }, }, }, parameters: { docs: { source: { code: ` { // Handle checked items }} checkboxSelectOptions={{ options: [ { name: 'option1', label: 'Option 1' }, { name: 'option2', label: 'Option 2' }, { name: 'option3', label: 'Option 3' } ], callout: (option) => { // Handle option selection } }} />`, }, }, }, } export const reorderableColumns = { ...TemplateWithHeader, args: { ...storyConfig, config: customColumns, tableHeaderProps: { ...tableHeaderStoryArgs, customColumnProps: { list: defaultColumns, isColumnsReorderable: true, }, }, }, parameters: { docs: { source: { code: ``, }, }, }, } export const customizeColumnsWithSecondaryOption = { ...TemplateWithHeader, args: { ...storyConfig, config: customColumns, tableHeaderProps: { ...tableHeaderStoryArgs, customColumnProps: { list: defaultColumns, isColumnsReorderable: true, getSecondaryOption: (label: string) => { const secondaryMap: Record = { Tag: 'Secondary Text', Number: 'Secondary Text', Percent: 'Secondary Text', Currency: 'Secondary Text', } return secondaryMap[label] ? ( {secondaryMap[label]} ) : null }, }, }, }, parameters: { docs: { source: { code: ` { const secondaryMap = { Tag: 'Secondary Text', Number: 'Secondary Text', Percent: 'Secondary Text', Currency: 'Secondary Text', }; return {secondaryMap[label]} } } }} />`, }, }, }, } export const checkedAllCheckboxTable = { ...Template, args: { ...storyConfig, hasCheckboxes: true, handleCheckedBoxes: (checkedItems) => { showCheckedItemsToast(checkedItems) }, isDefaultCheckedAll: true, }, } checkedAllCheckboxTable.storyName = 'Check All Enabled (Desktop only)' export const groups = { ...Template, args: { ...storyConfig, getData: () => undefined, showGroups: true, groups: [ { groupHeader: (
flag Group 1 - under 3
), tooltipContent: Description of the header group 1 , check: (item) => item.number < 3, }, { groupHeader: 'Group 2 - over 3', tooltipContent: Description of the header group 2 , check: (item) => item.number > 3, }, ], }, parameters: { docs: { source: { code: `Group 1 - under 3, tooltipContent: Description of the header group 1, check: (item) => item.number < 3 }, { groupHeader: "Group 2 - over 3", tooltipContent: Description of the header group 2, check: (item) => item.number > 3 } ]} />`, }, }, }, } export const AlwaysShowGroups = { ...Template, args: { ...storyConfig, showGroups: true, hasCheckboxes: true, handleCheckedBoxes: (checkedItems) => { showCheckedItemsToast(checkedItems) }, groups: [ { groupHeader: 'Group 1 - Default Gray', check: (item: { number: number }) => item.number < 3, alwaysShowGroups: true, }, { groupHeader: 'Group 2 - Red', check: (item: { number: number }) => item.number >= 3 && item.number < 6, type: 'red', alwaysShowGroups: true, }, { groupHeader: 'Group 3 - Blue', check: (item: { number: number }) => item.number > 6, type: 'blue', alwaysShowGroups: true, }, ], }, } export const groupColorVariation = { ...Template, args: { ...storyConfig, showGroups: true, groups: [ { groupHeader: 'Group 1 - Default Gray', check: (item) => item.number < 3, }, { groupHeader: 'Group 2 - Red', check: (item) => item.number > 3 && item.number < 6, type: 'red', }, { groupHeader: 'Group 3 - Blue', check: (item) => item.number > 6 && item.number < 9, type: 'blue', }, { groupHeader: 'Group 4 - Yellow', check: (item) => item.number > 9 && item.number < 12, type: 'yellow', }, { groupHeader: 'Group 5 - Green', check: (item) => item.number > 12 && item.number < 15, type: 'green', }, ], }, } export const groupAccordion = { ...Template, args: { ...storyConfig, data: groupAccordionSampleData, showGroups: true, groups: [ { groupHeader: 'Group 1', check: (item) => item.phaseKey === 'name1', groupAccordion: { isCollapsed: true, groupKey: 'name1', }, }, { groupHeader: 'Group 2', check: (item) => item.phaseKey === 'name2', groupAccordion: { isCollapsed: false, groupKey: 'name2', }, }, ], }, } groupAccordion.storyName = 'Group Accordion (Desktop only)' export const headerDetails = { ...Template, args: { ...storyConfig, data: [...standardTableSampleData, ...extraTableSampleData], showGroups: true, groups: [ { groupHeader: 'Group 1 - under 3', check: (item) => item.number < 3 }, { groupHeader: 'Group 2 - over 3', check: (item) => item.number > 3 }, ], }, } headerDetails.storyName = 'Group Header Details (Desktop only)' export const checkboxGroups = { ...Template, args: { ...storyConfig, hasCheckboxes: true, handleCheckedBoxes: (checkedItems) => { showCheckedItemsToast(checkedItems) }, showGroups: true, groups: [ { groupHeader: 'Group 1 - under 3', check: (item) => item.number < 3 }, { groupHeader: 'Group 2 - over 3', check: (item) => item.number > 3 }, ], }, } checkboxGroups.storyName = 'Checkbox & Groups (Desktop only)' const HandleSimpleTable = (args) => { const [allData, setAllData] = useState( generateRandomSampleData(), ) const [data, setData] = useState( allData.slice(0, 20), ) const [sort, setSort] = useState({ prop: 'name', flip: false }) const sortData = useCallback( (dataArray: typeof standardTableSampleData) => { const sortedData = [...dataArray] sortedData.sort((a, b) => { const aValue = a[sort.prop] const bValue = b[sort.prop] if (aValue < bValue) { return sort.flip ? 1 : -1 } if (aValue > bValue) { return sort.flip ? -1 : 1 } return 0 }) setAllData((prev) => { const isSame = isEqual(prev, sortedData) if (isSame) { return prev } else { setData(sortedData.slice(0, 20)) return sortedData } }) }, [sort.flip, sort.prop], ) const handleSort = (sortObj) => { setSort((prevState) => ({ ...prevState, prop: sortObj.activeColumn, flip: sortObj.direction, })) setTimeout(() => sortData(allData)) } const sortConfig = (args.config ?? tableConfig).map((configBase) => { delete configBase.noSort return { ...configBase, sort: handleSort, sortBy: sort, } }) let newDataCount = 20 const getData = () => { const newData = [...data] newData.push( ...standardTableSampleData.slice(newDataCount, newDataCount + 20), ) newDataCount += 20 setTimeout(() => setData(newData), 1000) } return ( ) } const CheckboxTemplate: Story = { render: ({ ...args }) => { return }, } export const checkboxGroupsNewCheckAll = { ...CheckboxTemplate, args: { dataKey: 'name', successStatus: true, loading: false, tableId: 'checkbox_table_with_checkAll_banner', noDataFields: { primaryText: 'No Data Available', secondaryText: 'There has been a problem with the data file. Please restart your computer.', }, hasCheckboxes: true, handleCheckedBoxes: (checkedItems, checkAll) => { if (checkAll) { toast({ type: 'info', message: 'ALL OPTIONS SELECTED (included options not yet loaded).', }) } else { showCheckedItemsToast(checkedItems) } }, enableCheckAll: true, totalCheckboxOptions: 100, }, } checkboxGroupsNewCheckAll.storyName = 'New Checkbox Experience (checkAll Banner)' const HandleNestedCheckboxTable = (args) => { const { data, sort, setSortBy } = useSortableData(args.data.slice(0, 2), { prop: 'name', flip: true, }) const [checkedCount, setCheckedCount] = useState(0) const showChildCheckboxes = args.nestedRowProps?.showCheckboxes !== false const handleCheckedBoxes = (items: TableObjectType[]) => { if (!showChildCheckboxes) { // showCheckboxes: false — count parent rows only (no _nestedParentKey) setCheckedCount( items.filter( (item) => (item as Record)[NESTED_PARENT_KEY] === undefined, ).length, ) } else { // showCheckboxes: true — count child rows only (have _nestedParentKey) // also count parent rows that have no children (leaf-level) const parentKeysWithChildren = new Set( Object.keys(args.nestedRowProps?.nestedData ?? {}).filter( (k) => args.nestedRowProps?.nestedData[k]?.length > 0, ), ) setCheckedCount( items.filter((item) => { const parentKey = (item as Record)[NESTED_PARENT_KEY] if (parentKey !== undefined) return true // child row return !parentKeysWithChildren.has(String(item.id)) // parent with no children }).length, ) } args.handleCheckedBoxes?.(items) } return (
{showChildCheckboxes ? 'Child rows' : 'Parent rows'} selected:{' '} {checkedCount}
) } export const nestedRows = { ...Template, args: { ...storyConfig, nestedDataKey: 'id', nestedRowProps: { nestedData: nestedTableSampleData, getNestedData: () => undefined, showCaret: (dataItem) => { return !!nestedTableSampleData[dataItem?.id] }, initiallyExpandedRows: [1], }, }, parameters: { docs: { source: { code: ` !!nestedData[dataItem?.id], initiallyExpandedRows: [1] }} />`, }, }, }, } const multiParentData = [ { id: 999, name: `Parent Row Example`, tag: `Tag 0`, number: 54, decimal: 3.27, percent: 0.75, currency: 3546, }, ...standardTableSampleData, ] export const multiNestedRows = { ...Template, args: { ...storyConfig, data: multiParentData, nestedDataKey: 'id', nestedRowProps: { nestedData: multiNestedTableSampleData, getNestedData: () => undefined, showCaret: (dataItem) => { return !!multiNestedTableSampleData[dataItem?.id] }, subRowDataKey: 'subCategory', }, }, } export const expandableRows = { ...Template, args: { ...storyConfig, hasExpandableContent: true, }, parameters: { docs: { source: { code: `, callout: (id) => setActiveRowId(id) }} />`, }, }, }, } export const loadingTable = { ...Template, args: { data: [], config, loading: true, shortListLoading: true, customHeight: 'auto', }, parameters: { docs: { source: { code: ``, }, }, }, } export const noDataTable = { ...Template, args: { data: [], config, loading, shortListLoading: true, noDataFields: { primaryText: 'No Data Available', secondaryText: 'There has been a problem with the data file. Please restart your computer.', buttonProps: { children: 'Primary Button', onClick: () => { toast({ type: 'success', message: 'You clicked the Primary button!', }) }, }, icon: 'sellers', }, customHeight: 'auto', }, parameters: { docs: { source: { code: ` handleButtonClick() }, icon: "sellers" }} customHeight="auto" />`, }, }, }, } const newConfig = [...tableConfig] const configChange = [ { label: 'Percent', name: 'percent', noSort: true, columnHeaderSubContent: (
View Details
), cell: { children: (d) => { return ( {`${(d?.percent * 100).toFixed(0)}%`} ) }, }, }, ] newConfig.splice(4, 1, ...configChange) export const customColumnHeader = { ...Template, args: { ...storyConfig, config: newConfig, }, } export const twoLineLabel = { ...CheckboxTemplate, args: { ...storyConfig, config: tableConfig.map((col) => { if (col.name === 'tag') { return { ...col, label: 'Column Tag Label', } } if (col.name === 'number') { return { ...col, label: 'A Very Long Label Value for the Number Column', } } if (col.name === 'decimal') { return { ...col, label: 'AVeryLongSingleWordThatShouldNotFitInTheColumnWidth', } } if (col.name === 'percent') { return { ...col, label: 'Standard Percent Column Values', } } return col }), twoLineLabel: true, }, } twoLineLabel.storyName = 'Two Line Label (Desktop only)' export const noSort = { ...Template, args: { ...storyConfig, noSort: true, config, }, } export const columnBadges = { ...Template, args: { ...storyConfig, config: tableConfig.map((col) => { // Show beta prop (backward compatibility) if (col.name === 'tag') { return { ...col, beta: true, } } // Show badgeProps with different colors if (col.name === 'number') { return { ...col, badgeProps: { children: 'New', color: 'dark-green', }, } } if (col.name === 'decimal') { return { ...col, badgeProps: { children: 'Updated', color: 'black', }, } } if (col.name === 'percent') { return { ...col, badgeProps: { children: 'Beta', color: 'lavender', }, } } return col }), }, } columnBadges.storyName = 'Column Badges' export const columnTags = { ...Template, args: { ...storyConfig, config: tableConfig.map((col) => { if (col.name === 'tag') { return { ...col, beta: true, } } if (col.name === 'number') { return { ...col, tagProps: { children: 'Live', color: 'green', }, } } return col }), }, } columnTags.storyName = 'Column Tags' export const nestedRowCheckboxes = { render: ({ ...args }) => , args: { ...storyConfig, dataKey: 'id', hasCheckboxes: true, nestedDataKey: 'id', disableCheckboxes: (item: TableObjectType) => item.number === 3, handleCheckedBoxes: (checkedItems: TableObjectType[]) => { showCheckedItemsToast(checkedItems) }, nestedRowProps: { nestedData: nestedTableSampleData, getNestedData: () => undefined, showCaret: (dataItem: TableObjectType) => !!nestedTableSampleData[dataItem?.id], showCheckboxes: true, initiallyExpandedRows: [1, 2], }, }, parameters: { docs: { source: { code: ` item.number === 3} handleCheckedBoxes={(checkedItems) => { /* handle selection */ }} nestedRowProps={{ nestedData: nestedData, getNestedData: () => undefined, showCaret: (dataItem) => !!nestedData[dataItem?.id], showCheckboxes: true, initiallyExpandedRows: [1, 2], }} />`, }, }, }, } export const parentRowCheckboxesOnly = { render: ({ ...args }) => , args: { ...storyConfig, dataKey: 'id', hasCheckboxes: true, nestedDataKey: 'id', disableCheckboxes: (item: TableObjectType) => item.number === 3, handleCheckedBoxes: (checkedItems: TableObjectType[]) => { showCheckedItemsToast(checkedItems) }, nestedRowProps: { nestedData: nestedTableSampleData, getNestedData: () => undefined, showCaret: (dataItem: TableObjectType) => !!nestedTableSampleData[dataItem?.id], initiallyExpandedRows: [1, 2], showCheckboxes: false, }, }, parameters: { docs: { source: { code: ` item.number === 3} handleCheckedBoxes={(checkedItems) => { /* handle selection */ }} nestedRowProps={{ nestedData: nestedData, getNestedData: () => undefined, showCaret: (dataItem) => !!nestedData[dataItem?.id], showCheckboxes: false, initiallyExpandedRows: [1, 2], }} />`, }, }, }, } const HandleGroupNestedCheckboxTable = (args) => { const { data, sort, setSortBy } = useSortableData(args.data, { prop: 'name', flip: true, }) const [checkedCount, setCheckedCount] = useState(0) const handleCheckedBoxes = (items: TableObjectType[]) => { // showCheckboxes: false — only count parent rows (no _nestedParentKey) setCheckedCount( items.filter( (item) => (item as Record)[NESTED_PARENT_KEY] === undefined, ).length, ) args.handleCheckedBoxes?.(items) } return (
Parent rows selected:{' '} {checkedCount}
) } export const groupWithNestedRowCheckboxes = { render: ({ ...args }) => , args: { ...storyConfig, data: standardTableSampleData.slice(0, 4), dataKey: 'id', tableId: 'group_nested_checkbox_table', hasCheckboxes: true, nestedDataKey: 'id', handleCheckedBoxes: (checkedItems: TableObjectType[]) => { showCheckedItemsToast(checkedItems) }, showGroups: true, groups: [ { groupHeader: 'Group A', check: (item: TableObjectType) => item.id <= 2, alwaysShowGroups: true, groupAccordion: { isCollapsed: false, groupKey: 'group-a', }, }, { groupHeader: 'Group B', check: (item: TableObjectType) => item.id > 2 && item.id <= 4, alwaysShowGroups: true, groupAccordion: { isCollapsed: false, groupKey: 'group-b', }, }, ], nestedRowProps: { nestedData: nestedTableSampleData, getNestedData: () => undefined, showCaret: (dataItem: TableObjectType) => !!nestedTableSampleData[dataItem?.id], showCheckboxes: false, initiallyExpandedRows: [1, 2], }, }, parameters: { docs: { source: { code: ` { /* handle selection */ }} groups={[ { groupHeader: 'Group A', check: (item) => item.id <= 2, alwaysShowGroups: true, groupAccordion: { isCollapsed: false, groupKey: 'group-a' }, }, { groupHeader: 'Group B', check: (item) => item.id > 2 && item.id <= 4, alwaysShowGroups: true, groupAccordion: { isCollapsed: false, groupKey: 'group-b' }, }, ]} nestedRowProps={{ nestedData: nestedData, getNestedData: () => undefined, showCaret: (dataItem) => !!nestedData[dataItem?.id], showCheckboxes: false, initiallyExpandedRows: [1, 2], }} />`, }, }, }, } groupWithNestedRowCheckboxes.storyName = 'Groups + Nested Row Checkboxes'