diff --git a/.reports/embedded-react-sdk.api.md b/.reports/embedded-react-sdk.api.md index 38f10d4f66..7bb3e9f6be 100644 --- a/.reports/embedded-react-sdk.api.md +++ b/.reports/embedded-react-sdk.api.md @@ -5519,6 +5519,7 @@ export interface SwitchProps extends SharedHorizontalFieldLayoutProps, Pick diff --git a/src/components/Common/DataView/DataTable/DataTable.tsx b/src/components/Common/DataView/DataTable/DataTable.tsx index 9f2993f9be..ba50d3a519 100644 --- a/src/components/Common/DataView/DataTable/DataTable.tsx +++ b/src/components/Common/DataView/DataTable/DataTable.tsx @@ -108,6 +108,7 @@ export const DataTable = ({ ...columns.map((column, index) => ({ key: typeof column.key === 'string' ? column.key : `header-${index}`, content: withJustify(column.title, column.justify), + wrap: column.wrap, })), ...(itemMenu ? [ @@ -167,6 +168,7 @@ export const DataTable = ({ return { key: typeof column.key === 'string' ? column.key : `cell-${colIndex}`, content: withJustify(getCellContent(item, column), column.justify), + wrap: column.wrap, } }), ...(itemMenu diff --git a/src/components/Common/DataView/useDataView.ts b/src/components/Common/DataView/useDataView.ts index 7617f6e15f..18c2a481cf 100644 --- a/src/components/Common/DataView/useDataView.ts +++ b/src/components/Common/DataView/useDataView.ts @@ -10,12 +10,14 @@ type DataViewColumn = title: string | React.ReactNode render?: (item: T) => React.ReactNode justify?: 'start' | 'end' + wrap?: boolean } | { key?: string title: string | React.ReactNode render: (item: T) => React.ReactNode justify?: 'start' | 'end' + wrap?: boolean } type FooterKeys = keyof T | string diff --git a/src/components/Common/DocumentList/DocumentList.tsx b/src/components/Common/DocumentList/DocumentList.tsx index 715029fa52..975daa92d9 100644 --- a/src/components/Common/DocumentList/DocumentList.tsx +++ b/src/components/Common/DocumentList/DocumentList.tsx @@ -59,6 +59,7 @@ function DocumentList({ columns: [ { title: columnLabels.form, + wrap: true, render: (form: FormData) => ( <> diff --git a/src/components/Common/UI/Table/Table.module.scss b/src/components/Common/UI/Table/Table.module.scss index b1993314d7..2a6de4abda 100644 --- a/src/components/Common/UI/Table/Table.module.scss +++ b/src/components/Common/UI/Table/Table.module.scss @@ -1,9 +1,13 @@ .root { width: 100%; + overflow-x: auto; + background: var(--g-colorBody); + border: 1px solid var(--g-colorBorderSecondary); + border-radius: toRem(12); + box-shadow: var(--g-shadowResting); :global(.react-aria-Table) { background: var(--g-colorBody); - border: 1px solid var(--g-colorBorderSecondary); outline: none; border-spacing: 0; min-height: 100px; @@ -11,9 +15,7 @@ width: 100%; word-break: break-word; forced-color-adjust: none; - border-radius: toRem(12); border-collapse: separate; - box-shadow: var(--g-shadowResting); &[data-focus-visible] { outline: var(--g-focusRingWidth) solid var(--g-focusRingColor); @@ -27,14 +29,6 @@ background-color: var(--g-colorBodyAccent); color: var(--g-colorBodySubContent); border-bottom: 1px solid var(--g-colorBorderSecondary); - - &:first-child { - border-top-left-radius: toRem(12); - } - - &:last-child { - border-top-right-radius: toRem(12); - } } //Produces spacing between header and body @@ -101,6 +95,12 @@ text-align: left; outline: none; word-break: normal; + white-space: nowrap; + + &[data-wrap] { + white-space: normal; + max-width: toRem(320); + } &[data-focus-visible] { outline: var(--g-focusRingWidth) solid var(--g-focusRingColor); @@ -129,12 +129,12 @@ } :global(.react-aria-Column) { - padding-left: toRem(16); - padding-right: toRem(16); + padding-left: toRem(40); + padding-right: toRem(40); height: toRem(40); } :global(.react-aria-Cell) { - padding: toRem(14) toRem(16); + padding: toRem(14) toRem(40); transform: translateZ(0); border-bottom: 1px solid var(--g-colorBorderSecondary); vertical-align: middle; @@ -151,14 +151,6 @@ :global(.react-aria-Row[data-footer='true'] .react-aria-Cell) { background-color: var(--g-colorBodyAccent); - - &:first-child { - border-bottom-left-radius: toRem(12); - } - - &:last-child { - border-bottom-right-radius: toRem(12); - } } /* join selected items if :has selector is supported */ @@ -176,33 +168,13 @@ } &[data-within-box] { + border: none; + border-radius: 0; + box-shadow: none; + background: transparent; + :global(.react-aria-Table) { - border: none; - border-radius: 0; - box-shadow: none; background: transparent; - - :global(.react-aria-TableHeader) { - th { - &:first-child { - border-top-left-radius: 0; - } - - &:last-child { - border-top-right-radius: 0; - } - } - } - - :global(.react-aria-Row[data-footer='true'] .react-aria-Cell) { - &:first-child { - border-bottom-left-radius: 0; - } - - &:last-child { - border-bottom-right-radius: 0; - } - } } } } diff --git a/src/components/Common/UI/Table/Table.stories.tsx b/src/components/Common/UI/Table/Table.stories.tsx index 57ce8384be..7a63eb99b0 100644 --- a/src/components/Common/UI/Table/Table.stories.tsx +++ b/src/components/Common/UI/Table/Table.stories.tsx @@ -349,3 +349,78 @@ export const WithinBox = () => { return } + +export const HorizontalScroll = () => { + const { Table } = useComponentContext() + + const columnKeys = [ + 'ID', + 'First name', + 'Last name', + 'Email', + 'Department', + 'Job title', + 'Location', + 'Start date', + 'Manager', + 'Status', + ] + + const headers: TableData[] = columnKeys.map(key => ({ + key: `${key}-header`, + content: key, + })) + + const people = [ + [ + '1', + 'John', + 'Doe', + 'john@example.com', + 'Engineering', + 'Staff Engineer', + 'San Francisco, CA', + '2021-03-15', + 'Jane Smith', + 'Active', + ], + [ + '2', + 'Jane', + 'Smith', + 'jane@example.com', + 'Engineering', + 'Engineering Manager', + 'New York, NY', + '2019-07-01', + 'Bob Johnson', + 'Active', + ], + [ + '3', + 'Bob', + 'Johnson', + 'bob@example.com', + 'Design', + 'Principal Designer', + 'Remote', + '2020-11-20', + 'Jane Smith', + 'On leave', + ], + ] + + const rows: TableRow[] = people.map((person, rowIndex) => ({ + key: `row-${rowIndex}`, + data: person.map((value, colIndex) => ({ + key: `cell-${rowIndex}-${colIndex}`, + content: value, + })), + })) + + return ( +
+
+ + ) +} diff --git a/src/components/Common/UI/Table/Table.tsx b/src/components/Common/UI/Table/Table.tsx index 96d3f09ff6..8690aa8666 100644 --- a/src/components/Common/UI/Table/Table.tsx +++ b/src/components/Common/UI/Table/Table.tsx @@ -22,15 +22,43 @@ import { applyMissingDefaults } from '@/helpers/applyMissingDefaults' */ export function Table(rawProps: TableProps) { const resolvedProps = applyMissingDefaults(rawProps, TableDefaults) - const { className, headers, rows, footer, emptyState, isWithinBox, hasCheckboxColumn, ...props } = - resolvedProps + const { + className, + headers, + rows, + footer, + emptyState, + isWithinBox, + hasCheckboxColumn, + 'aria-label': ariaLabel, + 'aria-labelledby': ariaLabelledby, + ...props + } = resolvedProps return ( -
- +
+ {headers.map((header, index) => ( - + {header.content} @@ -47,7 +75,7 @@ export function Table(rawProps: TableProps) { rows.map(row => ( {row.data.map((cell, index) => ( - + ( {document.title ?? document.name ?? t('emptyPlaceholder')} @@ -79,6 +80,7 @@ function DocumentsCardContent({ contractorId, onEvent, LoaderComponent }: Docume { key: 'description', title: t('descriptionColumn'), + wrap: true, render: (document: Document) => ( {document.description ?? t('emptyPlaceholder')} diff --git a/src/components/Employee/Deductions/management/DeductionsCard/DeductionsCard.tsx b/src/components/Employee/Deductions/management/DeductionsCard/DeductionsCard.tsx index 634309cc10..ac981a3aca 100644 --- a/src/components/Employee/Deductions/management/DeductionsCard/DeductionsCard.tsx +++ b/src/components/Employee/Deductions/management/DeductionsCard/DeductionsCard.tsx @@ -103,6 +103,7 @@ function DeductionsCardContent({ employeeId, onEvent, LoaderComponent }: Deducti { key: 'description', title: t('columns.deduction'), + wrap: true, render: (garnishment: Garnishment) => garnishment.description || '-', }, { diff --git a/src/components/Employee/Deductions/onboarding/DeductionsList/DeductionsList.tsx b/src/components/Employee/Deductions/onboarding/DeductionsList/DeductionsList.tsx index d38d9210dd..9e9a6e06dc 100644 --- a/src/components/Employee/Deductions/onboarding/DeductionsList/DeductionsList.tsx +++ b/src/components/Employee/Deductions/onboarding/DeductionsList/DeductionsList.tsx @@ -49,6 +49,7 @@ export function DeductionsList({ { key: 'description', title: t('nameColumn'), + wrap: true, }, { key: 'recurring', diff --git a/src/components/Employee/Documents/management/DocumentsCard/DocumentsCard.tsx b/src/components/Employee/Documents/management/DocumentsCard/DocumentsCard.tsx index 6fc6088084..b86bea7d1d 100644 --- a/src/components/Employee/Documents/management/DocumentsCard/DocumentsCard.tsx +++ b/src/components/Employee/Documents/management/DocumentsCard/DocumentsCard.tsx @@ -61,6 +61,7 @@ function DocumentsCardContent({ employeeId, onEvent, LoaderComponent }: Document { key: 'title', title: t('columns.title'), + wrap: true, render: (form: Form) => form.title || '-', }, { diff --git a/src/components/Payroll/PayrollBlocker/components/PayrollBlockerList.tsx b/src/components/Payroll/PayrollBlocker/components/PayrollBlockerList.tsx index 9b95c3a21a..0dca0b2ae8 100644 --- a/src/components/Payroll/PayrollBlocker/components/PayrollBlockerList.tsx +++ b/src/components/Payroll/PayrollBlocker/components/PayrollBlockerList.tsx @@ -161,6 +161,7 @@ function Root({ className, companyId, dictionary, onEvent }: PayrollBlockerListP columns: [ { title: t('blockerSectionLabel'), + wrap: true, render: blocker => ( diff --git a/src/components/Payroll/PayrollEditEmployee/PayrollEditEmployeePresentation.tsx b/src/components/Payroll/PayrollEditEmployee/PayrollEditEmployeePresentation.tsx index 13a3dfa7de..b50bc7cf96 100644 --- a/src/components/Payroll/PayrollEditEmployee/PayrollEditEmployeePresentation.tsx +++ b/src/components/Payroll/PayrollEditEmployee/PayrollEditEmployeePresentation.tsx @@ -435,6 +435,7 @@ export const PayrollEditEmployeePresentation = ({ { key: 'description', title: t('reimbursementDescriptionColumn'), + wrap: true, render: row => row.description.trim() || t('reimbursementUnnamedFallback'), }, { diff --git a/src/components/Payroll/PayrollList/PayrollListPresentation.tsx b/src/components/Payroll/PayrollList/PayrollListPresentation.tsx index 3a68b49e3c..e028278560 100644 --- a/src/components/Payroll/PayrollList/PayrollListPresentation.tsx +++ b/src/components/Payroll/PayrollList/PayrollListPresentation.tsx @@ -100,7 +100,7 @@ export const PayrollListPresentation = ({ const dateFormatter = useDateFormatter() const containerRef = useRef(null) const breakpoints = useContainerBreakpoints({ ref: containerRef }) - const isDesktop = breakpoints.includes('large') + const isTableLayout = breakpoints.includes('small') const todayAtMidnight = useMemo(() => { const todayDateString = formatDateToStringDate(new Date()) @@ -269,7 +269,7 @@ export const PayrollListPresentation = ({ dateRangeFilter.isModified ? ( @@ -326,7 +326,7 @@ export const PayrollListPresentation = ({ return }, }, - ...(!isDesktop + ...(!isTableLayout ? [ { title: '', @@ -350,7 +350,7 @@ export const PayrollListPresentation = ({ const isProcessingSkipPayroll = skippingPayrollId === payrollUuid const isProcessingDeletePayroll = deletingPayrollId === payrollUuid - const button = isDesktop ? renderActionButton(payroll) : null + const button = isTableLayout ? renderActionButton(payroll) : null if (processed) { return ( diff --git a/src/components/Payroll/RecoveryCases/RecoveryCasesList/RecoveryCasesList.tsx b/src/components/Payroll/RecoveryCases/RecoveryCasesList/RecoveryCasesList.tsx index b1352d7368..eab7b0112b 100644 --- a/src/components/Payroll/RecoveryCases/RecoveryCasesList/RecoveryCasesList.tsx +++ b/src/components/Payroll/RecoveryCases/RecoveryCasesList/RecoveryCasesList.tsx @@ -154,6 +154,7 @@ function Root({ companyId, dictionary, onEvent }: RecoveryCasesListProps) { { key: 'latestErrorCode', title: t('columns.latestErrorCode'), + wrap: true, render: recoveryCase => , }, {