diff --git a/.storybook/preview.js b/.storybook/preview.js index 3cd9d11353..29e8227b00 100644 --- a/.storybook/preview.js +++ b/.storybook/preview.js @@ -3,7 +3,7 @@ import { QueryClient, QueryClientProvider } from 'react-query'; import { CoreUiThemeProvider } from '../src/lib/next'; import { brand, coreUIAvailableThemes } from '../src/lib/style/theme'; import { Wrapper } from '../stories/common'; -import { ToastProvider } from '../src/lib'; +import { ScrollbarWrapper, ToastProvider } from '../src/lib'; export const globalTypes = { theme: { @@ -12,27 +12,47 @@ export const globalTypes = { defaultValue: 'darkRebrand', toolbar: { title: 'Preview Theme', - dynamicTitle: false, + dynamicTitle: true, // array of plain string values or MenuItem shape (see below) items: [ - { value: 'darkRebrand', title: 'Dark', icon: 'moon' }, - { value: 'artescaLight', title: 'Light', icon: 'sun' }, - { value: 'ring9dark', title: 'Ring Dark', icon: 'moon' }, + { value: 'darkRebrand', title: ' A-Dark', icon: 'moon' }, + { value: 'artescaLight', title: 'A-Light', icon: 'sun' }, + { value: 'ring9dark', title: 'R-Dark', icon: 'moon' }, ], }, }, + background: { + name: 'Background Level', + description: 'Background for the wrapper', + toolbar: { + title: 'Background Level', + items: [ + { value: 'backgroundLevel1', title: 'backgroundLevel 1' }, + { value: 'backgroundLevel2', title: 'backgroundLevel 2' }, + { value: 'backgroundLevel3', title: 'backgroundLevel 3' }, + { value: 'backgroundLevel4', title: 'backgroundLevel 4' }, + ], + dynamicTitle: true, + }, + }, }; - const withThemeProvider = (Story, context) => { const theme = coreUIAvailableThemes[context.globals.theme]; + const { background } = context.globals; const { viewMode } = context; return ( {/* Wrapper to make the stories take the full screen but not in docs */} -
+
- + diff --git a/src/lib/components/constrainedtext/Constrainedtext.component.tsx b/src/lib/components/constrainedtext/Constrainedtext.component.tsx index fa02f596ad..60c0220c57 100644 --- a/src/lib/components/constrainedtext/Constrainedtext.component.tsx +++ b/src/lib/components/constrainedtext/Constrainedtext.component.tsx @@ -28,10 +28,7 @@ const ConstrainedTextContainer = styled.div` overflow-wrap: break-word; ` : `overflow-wrap: break-word; - white-space: nowrap;`} -} - -; + white-space: nowrap;`}; `; const BlockTooltip = styled.div` width: stretch; diff --git a/src/lib/components/emptystate/Emptystate.component.tsx b/src/lib/components/emptystate/Emptystate.component.tsx index 12f3aaaa54..aad25aaff8 100644 --- a/src/lib/components/emptystate/Emptystate.component.tsx +++ b/src/lib/components/emptystate/Emptystate.component.tsx @@ -4,17 +4,30 @@ import { spacing } from '../../spacing'; import { Button } from '../buttonv2/Buttonv2.component'; import { Icon, IconName } from '../icon/Icon.component'; import { LargeText } from '../text/Text.component'; +import { CoreUITheme } from '../../style/theme'; type Props = { - label: string; + listedResource: { + singular: string; + plural: string; + }; icon: IconName; link?: string; history?: Record; + backgroundColor?: keyof CoreUITheme; + /** + * The resource to create before browsing the listed resource + * Only used when resource to create is different from listed resource + */ + resourceToCreate?: string; }; -const EmptystateContainer = styled.div` +const EmptystateContainer = styled.div<{ backgroundColor?: keyof CoreUITheme }>` ${(props) => { - const brand = props.theme; + const { theme, backgroundColor } = props; return css` - color: ${brand.textSecondary}; + color: ${theme.textSecondary}; + background-color: ${backgroundColor + ? theme[backgroundColor] + : 'transparent'}; `; }} display: flex; @@ -33,25 +46,36 @@ export const ActionWrapper = styled.div` `; function EmptyState(props: Props) { - const { icon, label, link, history } = props; + const { + icon, + listedResource, + link, + history, + resourceToCreate, + backgroundColor, + } = props; return ( - + - A list of {`${label}s`} will appear here. + {`A list of ${listedResource.plural} will appear here.`} - There are no {`${label}s`} created yet, let's create your first{' '} - {label}. + {!resourceToCreate + ? `There are no ${listedResource.plural} created yet, let's create your first ${listedResource.singular}.` + : `Before browsing your ${listedResource.plural}, create your first ${resourceToCreate}.`} {history && (
- {typeof children === 'function' ? ( - children( - , - ) - ) : rows.length ? ( - - ) : ( - {translations[locale].noResult} - )} + {isLoadingMoreItems && ( void; value?: string; - /** - * @deprecated - * All the Table should display the Total Number of Entity. - */ - displayTotalOf?: boolean; - displayedName: DisplayedName; locale?: TableLocalType; totalCount?: number; } & Omit; @@ -72,37 +66,32 @@ export const TableItemCount = ({ }; export function TableSearch(props: SearchProps) { + const { onChange, value = '', locale = 'en', totalCount, ...rest } = props; const { - onChange, - value = '', - displayTotalOf = true, - displayedName, - locale = 'en', - totalCount, - ...rest - } = props; - const { setGlobalFilter, rows, preGlobalFilteredRows } = useTableContext(); + setGlobalFilter, + rows, + preGlobalFilteredRows, + entityName = { en: { singular: 'result', plural: 'results' } }, + } = useTableContext(); const totalDispayedRows = totalCount ? totalCount : rows.length; React.useEffect(() => { setGlobalFilter(value); }, [value, setGlobalFilter, preGlobalFilteredRows]); return ( - {displayTotalOf && ( - - )} + + { if (typeof onChange === 'function') { - // @ts-ignore onChange(evt.target.value); } }} diff --git a/src/lib/components/tablev2/SingleSelectableContent.tsx b/src/lib/components/tablev2/SingleSelectableContent.tsx index a00bba1625..016773467d 100644 --- a/src/lib/components/tablev2/SingleSelectableContent.tsx +++ b/src/lib/components/tablev2/SingleSelectableContent.tsx @@ -1,4 +1,4 @@ -import { memo, CSSProperties, useEffect } from 'react'; +import React, { memo, useEffect } from 'react'; import { areEqual } from 'react-window'; import { Row } from 'react-table'; import { useTableContext } from './Tablev2.component'; @@ -7,7 +7,6 @@ import { TableRow, TableBody, TableHeader, - NoResult, SortCaret, } from './Tablestyle'; import { @@ -15,7 +14,7 @@ import { TableLocalType, TableVariantType, } from './TableUtils'; -import { useTableScrollbar, VirtualizedRows } from './TableCommon'; +import { RenderRowType, TableRows, useTableScrollbar } from './TableCommon'; import useSyncedScroll from './useSyncedScroll'; import { Loader } from '../loader/Loader.component'; import { Box } from '../box/Box'; @@ -26,28 +25,14 @@ export type SingleSelectableContentProps< > = { rowHeight: TableHeightKeyType; separationLineVariant: TableVariantType; - backgroundVariant: TableVariantType; + onRowSelected?: (row: Row) => void; selectedId?: string; locale?: TableLocalType; - customItemKey?: (index: Number, data: DATA_ROW) => string; + customItemKey?: (index: number, data: DATA_ROW) => string; hasScrollbar?: boolean; isLoadingMoreItems?: boolean; - children?: (rows: JSX.Element) => JSX.Element; -}; - -const translations = { - en: { - noResult: 'No results found', - }, - fr: { - noResult: `Aucun résultat`, - }, -}; - -type RenderRowType = { - index: number; - style: CSSProperties; + children?: (rows: React.JSX.Element) => React.JSX.Element; }; export function SingleSelectableContent< @@ -55,7 +40,7 @@ export function SingleSelectableContent< >({ rowHeight = 'h40', separationLineVariant = 'backgroundLevel3', - backgroundVariant = 'backgroundLevel1', + locale = 'en', selectedId, isLoadingMoreItems, @@ -67,15 +52,9 @@ export function SingleSelectableContent< console.error('Please specify the onRowSelected function.'); } - const { bodyRef, headerRef } = useSyncedScroll(); - const { - headerGroups, - prepareRow, - rows, - onBottom, - onBottomOffset, - setRowHeight, - } = useTableContext(); + const { headerRef } = useSyncedScroll(); + const { headerGroups, prepareRow, rows, setRowHeight } = + useTableContext(); useEffect(() => { setRowHeight(rowHeight); @@ -120,7 +99,6 @@ export function SingleSelectableContent< isSelected={selectedId === row.id} aria-selected={selectedId === row.id ? 'true' : 'false'} separationLineVariant={separationLineVariant} - backgroundVariant={backgroundVariant} selectedId={selectedId} className="tr" > @@ -146,20 +124,9 @@ export function SingleSelectableContent< ); }, areEqual); - const { - hasScrollbar, - setHasScrollbar, - scrollBarWidth, - handleScrollbarWidth, - } = useTableScrollbar(); - - function itemKey(index, data) { - if (typeof customItemKey === 'function') { - return customItemKey(index, data); - } + const { hasScrollbar, scrollBarWidth, handleScrollbarWidth } = + useTableScrollbar(); - return index; - } return ( <>
@@ -167,6 +134,7 @@ export function SingleSelectableContent< - {typeof children === 'function' ? ( - children( - , - ) - ) : rows.length ? ( - - ) : ( - {translations[locale].noResult} - )} + {isLoadingMoreItems && ( = Record, @@ -100,3 +109,93 @@ export const useTableScrollbar = () => { handleScrollbarWidth, }; }; + +export type RenderRowType = { + index: number; + style: CSSProperties; +}; + +type TableRowsProps< + DATA_ROW extends Record = Record, +> = { + locale?: TableLocalType; + children?: (children: JSX.Element) => JSX.Element; + customItemKey?: (index: number, data: DATA_ROW) => string; + RenderRow: React.MemoExoticComponent< + ({ index, style }: RenderRowType) => JSX.Element + >; +}; +export function TableRows< + DATA_ROW extends Record = Record, +>({ locale, children, customItemKey, RenderRow }: TableRowsProps) { + const { setHasScrollbar } = useTableScrollbar(); + const { rows, status, entityName, rowHeight, onBottom, onBottomOffset } = + useTableContext(); + const { bodyRef } = useSyncedScroll(); + + function itemKey(index, data) { + if (typeof customItemKey === 'function') { + return customItemKey(index, data); + } + + return index; + } + + if (status === 'idle' || status === 'loading') { + return ( + + + + {translatedMessages('loading', entityName, locale)} + + + ); + } + if (status === 'error') { + return ( + + + + {translatedMessages('error', entityName, locale)} + + + ); + } + if (status === 'success' || status === undefined) { + if (typeof children === 'function') { + return children( + , + ); + } else if (rows.length) { + return ( + + ); + } else { + return ( + + {translatedMessages('noResult', entityName, locale)} + + ); + } + } + + return null; +} diff --git a/src/lib/components/tablev2/TableUtils.ts b/src/lib/components/tablev2/TableUtils.ts index 78df3edd48..ce0e752f0c 100644 --- a/src/lib/components/tablev2/TableUtils.ts +++ b/src/lib/components/tablev2/TableUtils.ts @@ -58,3 +58,40 @@ export const tableRowHeight = { h48: '3.428', //2 line h64: '4.572', //3 line }; + +type TableMessagesType = 'error' | 'loading' | 'noResult'; + +export const translatedMessages = ( + type: TableMessagesType, + entityName?: { + en: { singular: string; plural: string }; + fr?: { singular: string; plural: string }; + }, + locale?: TableLocalType, +) => { + if (type === 'error') { + if (locale === 'fr') { + return `Erreur lors du chargement des ${ + entityName?.fr?.plural || 'données' + }, veuillez rafraîchir la page.`; + } + return `An error occurred while loading ${ + entityName ? `the ${entityName.en.plural}` : 'data' + }, please refresh the + page.`; + } + if (type === 'loading') { + if (locale === 'fr') { + return `Chargement des ${entityName?.fr?.plural || 'données'}...`; + } + return `Loading ${entityName?.en.plural || 'data'}...`; + } + if (type === 'noResult') { + if (locale === 'fr') { + return `Aucun ${entityName?.fr?.singular || 'résultat'} trouvé`; + } + return `No ${entityName?.en.plural || 'results'} found`; + } + + return ''; +}; diff --git a/src/lib/components/tablev2/Tablestyle.tsx b/src/lib/components/tablev2/Tablestyle.tsx index ceb33d1f50..4bed1d618d 100644 --- a/src/lib/components/tablev2/Tablestyle.tsx +++ b/src/lib/components/tablev2/Tablestyle.tsx @@ -1,6 +1,4 @@ import styled, { css } from 'styled-components'; - -import { spacing } from '../../style/theme'; import { TableHeightKeyType, tableRowHeight, @@ -9,6 +7,8 @@ import { import { HeaderGroup } from 'react-table'; import { Icon } from '../icon/Icon.component'; import { FocusVisibleStyle } from '../buttonv2/Buttonv2.component'; +import { spacing } from '../../spacing'; +import { Box } from '../box/Box'; const borderSize = '4px'; export const SortIncentive = styled.span` @@ -16,7 +16,7 @@ export const SortIncentive = styled.span` display: none; `; export const SortCaretWrapper = styled.span` - padding-left: ${spacing.sp4}; + padding-left: ${spacing.r4}; position: absolute; `; export const TableHeader = styled.div<{ @@ -45,11 +45,14 @@ type HeadRowType = { hasScrollBar: boolean; scrollBarWidth: number; rowHeight: TableHeightKeyType; + separationLineVariant: TableVariantType; }; export const HeadRow = styled.div` + box-sizing: border-box; display: flex; align-items: center; + gap: ${spacing.r16}; height: 2.286rem; width: ${(props) => props.hasScrollBar @@ -60,23 +63,26 @@ export const HeadRow = styled.div` color: ${(props) => props.theme.textPrimary}; font-weight: bold; overflow: hidden; + border-bottom: 1px solid + ${(props) => props.theme[props.separationLineVariant]}; + padding-right: ${borderSize}; + padding-left: ${spacing.r16}; `; type TableRowType = { isSelected: boolean; selectedId?: string; separationLineVariant: TableVariantType; - backgroundVariant: TableVariantType; }; export const TableRow = styled.div` color: ${(props) => props.theme.textPrimary}; - border-top: 1px solid ${(props) => props.theme[props.separationLineVariant]}; - :last-child { - border-bottom: 1px solid - ${(props) => props.theme[props.separationLineVariant]}; - } + gap: ${spacing.r16}; + border-bottom: 1px solid + ${(props) => props.theme[props.separationLineVariant]}; cursor: default; box-sizing: border-box; + padding-left: ${spacing.r16}; + padding-right: ${borderSize}; // single selectable case ${(props) => { @@ -101,11 +107,6 @@ export const TableRow = styled.div` background-color: ${props.theme.highlight}; border-right: ${borderSize} solid ${props.theme.selectedActive}; `; - } else { - const color = props.theme[props.backgroundVariant]; - return css` - border-right: ${borderSize} solid ${color}; - `; } }} `; @@ -113,41 +114,32 @@ export const TableRow = styled.div` type TableRowMultiSelectableType = { isSelected: boolean; separationLineVariant: TableVariantType; - backgroundVariant: TableVariantType; }; export const TableRowMultiSelectable = styled.div` color: ${(props) => props.theme.textPrimary}; - border-top: 1px solid ${(props) => props.theme[props.separationLineVariant]}; - :last-child { - border-bottom: 1px solid - ${(props) => props.theme[props.separationLineVariant]}; - } - + border-bottom: 1px solid + ${(props) => props.theme[props.separationLineVariant]}; box-sizing: border-box; - - &:hover, - &:focus { - background-color: ${(props) => props.theme.highlight}; - outline: none; - cursor: pointer; - } - ${(props) => { if (props.isSelected) { return css` background-color: ${(props) => props.theme.highlight}; border-right: ${borderSize} solid ${props.theme.selectedActive}; `; - } else { - const color = props.theme[props.backgroundVariant]; - return css` - border-right: ${borderSize} solid ${color}; - `; } }} + padding-right: ${borderSize}; + padding-left: ${spacing.r16}; + &:hover, + &:focus { + background-color: ${(props) => props.theme.highlight}; + outline: none; + cursor: pointer; + } `; export const TableBody = styled.div` + box-sizing: border-box; display: block; flex-grow: 1; height: 100%; @@ -164,12 +156,13 @@ export const TooltipContent = styled.div` min-width: 60px; `; -export const NoResult = styled.div` +export const NoResult = styled(Box)<{ rowHeight: TableHeightKeyType }>` display: flex; justify-content: center; + align-items: center; color: ${(props) => props.theme.textSecondary}; - padding-top: ${spacing.sp8}; - border-top: 1px solid ${(props) => props.theme.backgroundLevel3}; + height: ${(props) => tableRowHeight[props.rowHeight]}rem; + gap: ${spacing.r8}; `; export const SortCaret = < diff --git a/src/lib/components/tablev2/Tablev2.component.tsx b/src/lib/components/tablev2/Tablev2.component.tsx index 85f210309a..6c6694c032 100644 --- a/src/lib/components/tablev2/Tablev2.component.tsx +++ b/src/lib/components/tablev2/Tablev2.component.tsx @@ -67,6 +67,11 @@ export type TableProps< onBottom?: (rowLength: number) => void; onBottomOffset?: number; allFilters?: { id: string; value: string }[]; + status?: 'idle' | 'loading' | 'error' | 'success'; + entityName?: { + en: { singular: string; plural: string }; + fr?: { singular: string; plural: string }; + }; initiallySelectedRowsIds?: Set; //To call it from the Cell renderer to update the original data } & UpdateTableData; @@ -95,6 +100,11 @@ type TableContextType< setHiddenColumns: (param: string[] | setHiddenColumnFuncType) => void; isAllRowsSelected?: boolean; toggleAllRowsSelected: (value?: boolean) => void; + status?: 'idle' | 'loading' | 'error' | 'success'; + entityName?: { + en: { singular: string; plural: string }; + fr?: { singular: string; plural: string }; + }; }; const TableContext = React.createContext(null); @@ -168,6 +178,8 @@ function Table< onBottomOffset = 10, initiallySelectedRowsIds, updateTableData, + status, + entityName, }: TableProps) { sortTypes = { health: (row1, row2) => { @@ -296,6 +308,8 @@ function Table< setHiddenColumns, isAllRowsSelected, toggleAllRowsSelected, + status, + entityName, }; return ( {
@@ -92,7 +91,6 @@ describe('TableV2', () => {
@@ -117,7 +115,6 @@ describe('TableV2', () => { diff --git a/src/lib/components/tabsv2/StyledTabs.ts b/src/lib/components/tabsv2/StyledTabs.ts index 768e81ebf9..15e6d24054 100644 --- a/src/lib/components/tabsv2/StyledTabs.ts +++ b/src/lib/components/tabsv2/StyledTabs.ts @@ -1,9 +1,11 @@ import styled from 'styled-components'; -import { spacing } from '../../style/theme'; + import { getThemePropSelector } from '../../utils'; +import { spacing } from '../../spacing'; + export const TabBar = styled.div` display: flex; - height: ${spacing.sp40}; + height: ${spacing.r40}; `; export const TabItem = styled.div<{ selected?: boolean; @@ -14,15 +16,15 @@ export const TabItem = styled.div<{ }>` display: flex; align-items: center; - padding: 0 ${spacing.sp24} 0 ${spacing.sp24}; - border-radius: ${spacing.sp4} ${spacing.sp4} 0 0; - border: ${spacing.sp1} solid transparent; + padding: 0 ${spacing.r24} 0 ${spacing.r24}; + border-radius: ${spacing.r4} ${spacing.r4} 0 0; + border: ${spacing.r1} solid transparent; min-width: 5rem; &:focus-visible { outline: 0; position: relative; - border: ${spacing.sp1} dashed ${getThemePropSelector('selectedActive')}; + border: ${spacing.r1} dashed ${getThemePropSelector('selectedActive')}; } &:focus-within { @@ -39,19 +41,19 @@ export const TabItem = styled.div<{ content: ""; background: ${props.activeTabSeparator || selectedActive}; position: absolute; - border-radius: ${spacing.sp2} ${spacing.sp2} 0 0; + border-radius: ${spacing.r2} ${spacing.r2} 0 0; bottom: 0; right: 0; - left: calc(50% - ${spacing.sp16}); - height: ${spacing.sp2}; - width: ${spacing.sp32}; + left: calc(50% - ${spacing.r16}); + height: ${spacing.r2}; + width: ${spacing.r32}; } ` : ` background-color: ${props.inactiveTabColor || backgroundLevel3}; &:hover { cursor: pointer; - border: ${spacing.sp1} solid ${props.tabHoverColor || highlight}; + border: ${spacing.r1} solid ${props.tabHoverColor || highlight}; } `; }} @@ -73,16 +75,16 @@ export const TabsContainer = styled.div<{ } & ${TabItem}::before { - content: ""; + content: ''; background: ${(props) => props.separatorColor || props.theme.infoSecondary}; position: absolute; bottom: 25%; right: 0; - height: ${spacing.sp16}; + height: ${spacing.r16}; width: 1px; margin-right: -1px; } -}`; +`; export const TabContent = styled.div<{ tabContentColor?: string }>` margin: 0; padding: 0; diff --git a/src/lib/organisms/attachments/AttachmentConfirmationModal.tsx b/src/lib/organisms/attachments/AttachmentConfirmationModal.tsx index 624903b2bc..313f611894 100644 --- a/src/lib/organisms/attachments/AttachmentConfirmationModal.tsx +++ b/src/lib/organisms/attachments/AttachmentConfirmationModal.tsx @@ -259,7 +259,6 @@ export function AttachmentConfirmationModal({ { return <>{Rows}; }} diff --git a/src/lib/organisms/attachments/AttachmentTable.tsx b/src/lib/organisms/attachments/AttachmentTable.tsx index 5704a5b949..b7cc878dca 100644 --- a/src/lib/organisms/attachments/AttachmentTable.tsx +++ b/src/lib/organisms/attachments/AttachmentTable.tsx @@ -32,6 +32,7 @@ import { } from './AttachmentTypes'; import { useQuery, UseQueryOptions } from 'react-query'; import { EmptyCell } from '../../components/tablev2/Tablev2.component'; +import { tableRowHeight } from '../../components/tablev2/TableUtils'; type AttachableEntityWithPendingStatus = { isPending?: boolean; @@ -104,11 +105,7 @@ const MenuContainer = styled.ul<{ `; const SearchBoxContainer = styled.div` - margin-bottom: ${spacing.r24}; - width: 78%; - .sc-tooltip { - width: 100%; - } + padding: ${spacing.r16}; `; const StyledSearchInput = styled(SearchInput)` @@ -134,6 +131,7 @@ const StyledTable = styled.div` const CenterredSecondaryText = styled(SecondaryText)` display: block; text-align: center; + line-height: ${tableRowHeight[rowHeight]}rem; `; const PrivateAttachmentContext = createContext<{ @@ -477,8 +475,12 @@ export const AttachmentTable = ({ { - if (element) { - setSearchWidth(element.getBoundingClientRect().width - 2 + 'px'); + if (element?.firstElementChild) { + setSearchWidth( + element.firstElementChild.getBoundingClientRect().width - + 2 + + 'px', + ); } }, }} @@ -489,7 +491,7 @@ export const AttachmentTable = ({ <>We failed to load the entities, hence search is disabled } > - + ({ disabled={filteredEntities.status === 'error'} /> - + ) : ( ({ Name, + Header: 'Name', accessor: 'name', cellStyle: { flex: 1.5, @@ -639,7 +641,7 @@ export const AttachmentTable = ({ }, }, { - Header: Attachment status, + Header: 'Attachment', accessor: 'isPending', cellStyle: { flex: 0.5, @@ -690,7 +692,6 @@ export const AttachmentTable = ({ defaultSortingKey="name" > @@ -698,7 +699,7 @@ export const AttachmentTable = ({ <> {initiallyAttachedEntitiesStatus === 'idle' || initiallyAttachedEntitiesStatus === 'loading' ? ( - +

@@ -707,9 +708,17 @@ export const AttachmentTable = ({

) : initiallyAttachedEntitiesStatus === 'error' ? ( - - Failed to load {entityName.plural} - + + + + Failed to load attached {entityName.plural}. + + ) : ( desiredAttachedEntities.length === 0 && ( diff --git a/stories/attachment.stories.tsx b/stories/attachment.stories.tsx new file mode 100644 index 0000000000..0762d73ff8 --- /dev/null +++ b/stories/attachment.stories.tsx @@ -0,0 +1,78 @@ +import { action } from '@storybook/addon-actions'; +import React from 'react'; +import { + AttachmentProvider, + AttachmentTable, +} from '../src/lib/organisms/attachments/AttachmentTable'; + +import { Box } from '../src/lib/next'; +import { useTheme } from 'styled-components'; + +export default { + title: 'Components/AttachmentTable', + component: AttachmentTable, +}; + +export const Playground = { + render: () => { + const theme = useTheme(); + return ( + + + { + console.log('changed'); + }} + /> + + + ); + }, +}; + +export const FailToLoad = { + render: () => { + const theme = useTheme(); + return ( + + + { + console.log('changed'); + }} + /> + + + ); + }, +}; diff --git a/stories/common.tsx b/stories/common.tsx index 4e9fcc8838..115b3675c5 100644 --- a/stories/common.tsx +++ b/stories/common.tsx @@ -1,12 +1,18 @@ import React from 'react'; -import styled from 'styled-components'; +import styled, { css } from 'styled-components'; import { getThemePropSelector } from '../src/lib/utils'; const StyledWrapper = styled.div` - padding: 3rem; - height: 100%; - background-color: ${(props) => props.theme.backgroundLevel1}; - color: ${(props) => props.theme.textPrimary}; - box-sizing: border-box; + ${(props) => { + const { style, theme } = props; + return css` + padding: 3rem; + height: 100%; + background-color: ${theme[style?.backgroundColor || 'backgroundLevel3']}; + color: ${theme.textPrimary}; + box-sizing: border-box; + overflow: scroll; + `; + }} `; const StyledTitle = styled.h3` color: ${getThemePropSelector('textPrimary')}; diff --git a/stories/emptystate.stories.tsx b/stories/emptystate.stories.tsx index 6c284bf78c..2b74ebdcb7 100644 --- a/stories/emptystate.stories.tsx +++ b/stories/emptystate.stories.tsx @@ -1,6 +1,5 @@ -import React from 'react'; import { EmptyState } from '../src/lib/components/emptystate/Emptystate.component'; -import { Wrapper } from './common'; + export default { title: 'Components/Data Display/EmptyState', component: EmptyState, diff --git a/stories/form.stories.tsx b/stories/form.stories.tsx index 61ba2e9a5f..c2b2689eb4 100644 --- a/stories/form.stories.tsx +++ b/stories/form.stories.tsx @@ -236,9 +236,7 @@ export const AllRequiredPageForm = { export const TabForm = { ...PageForm, args: { - layout: { - kind: 'tab', - }, + kind: 'tab', }, }; diff --git a/stories/modal.stories.tsx b/stories/modal.stories.tsx index 8b38ad2492..825267a4e8 100644 --- a/stories/modal.stories.tsx +++ b/stories/modal.stories.tsx @@ -1,4 +1,3 @@ -import React, { useState } from 'react'; import { Modal } from '../src/lib/components/modal/Modal.component'; import { action } from '@storybook/addon-actions'; import { Wrapper } from './common'; @@ -164,7 +163,6 @@ export const WithinTable = {
diff --git a/stories/tablev2.stories.tsx b/stories/tablev2.stories.tsx index 050380b5bc..bbe66e91af 100644 --- a/stories/tablev2.stories.tsx +++ b/stories/tablev2.stories.tsx @@ -5,7 +5,7 @@ import { EmptyCell, Table, } from '../src/lib/components/tablev2/Tablev2.component'; -import { Wrapper, Title } from './common'; +import { Title } from './common'; import { BrowserRouter, BrowserRouter as Router, @@ -65,51 +65,49 @@ type Entry = { health: string; }; +const columns: Column[] = [ + { + Header: 'First Name', + accessor: 'firstName', + cellStyle: { + textAlign: 'left', + }, + Cell: ({ value }) => { + if (value) return <>{value}; + return ; + }, + }, + { + Header: 'Last Name', + accessor: 'lastName', + cellStyle: { + textAlign: 'left', + }, + // disable the sorting on this column + disableSortBy: true, + }, + { + Header: 'Age', + accessor: 'age', + cellStyle: { + width: '50px', + textAlign: 'left', + }, + }, + { + Header: 'Health', + accessor: 'health', + sortType: 'health', + cellStyle: { + textAlign: 'left', + }, + }, +]; +const getRowId = (row: Entry, relativeIndex: number) => { + return row.lastName + ' ' + row.firstName; +}; export const SimpleContentTable = { render: ({}) => { - const columns: Column[] = [ - { - Header: 'First Name', - accessor: 'firstName', - cellStyle: { - textAlign: 'left', - }, - Cell: ({ value }) => { - if (value) return <>{value}; - return ; - }, - }, - { - Header: 'Last Name', - accessor: 'lastName', - cellStyle: { - textAlign: 'left', - }, - // disable the sorting on this column - disableSortBy: true, - }, - { - Header: 'Age', - accessor: 'age', - cellStyle: { - width: '50px', - textAlign: 'left', - }, - }, - { - Header: 'Health', - accessor: 'health', - sortType: 'health', - cellStyle: { - textAlign: 'left', - }, - }, - ]; - - const getRowId = (row: Entry, relativeIndex: number) => { - return row.lastName + ' ' + row.firstName; - }; - const TableWithQueryParams = ({}) => { const location = useLocation(); return ( @@ -148,7 +146,7 @@ export const SimpleContentTable = { }; return ( - + <> Non Selectable Table
-
+ ); }, }; @@ -320,7 +319,7 @@ export const asyncTable = { ]; return ( - + <> async cell Table
-
+ ); }, }; @@ -384,7 +383,7 @@ export const OnBottomCallback = { }; return ( - + <> async cell Table
-
+ ); }, }; @@ -492,7 +491,7 @@ export const MultiTable = { }; return ( - + <> Several Multiselect @@ -546,7 +545,87 @@ export const MultiTable = { - + + ); + }, +}; + +export const EmptyTable = { + render: (args) => { + const { background } = args; + return ( + + +
+ ); + }, + argTypes: { + background: { + control: { + type: 'select', + description: 'Background color', + defaultValue: 'backgroundLevel3', + }, + options: [ + 'backgroundLevel1', + 'backgroundLevel2', + 'backgroundLevel3', + 'backgroundLevel4', + ], + }, + }, +}; + +export const LoadingTable = { + render: ({}) => { + return ( + + + +
+
+ ); + }, +}; + +export const ErrorTable = { + render: ({}) => { + return ( + + + +
+
); }, };