@canonical/maas-react-components 2.0.4 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. package/dist/@canonical/maas-react-components.es.js +2196 -1861
  2. package/dist/@canonical/maas-react-components.umd.js +16 -16
  3. package/dist/maas-react-components.css +1 -1
  4. package/dist/src/lib/components/GenericTable/GenericTable.d.ts +20 -29
  5. package/dist/src/lib/components/GenericTable/GenericTable.stories.d.ts +2 -0
  6. package/dist/src/lib/components/GenericTable/{PaginationBar → components/PaginationBar}/ControlsBar/ControlsBar.d.ts +4 -1
  7. package/dist/src/lib/components/GenericTable/hooks/useTableExpansion.d.ts +9 -0
  8. package/dist/src/lib/components/GenericTable/hooks/useTableGrouping.d.ts +11 -0
  9. package/dist/src/lib/components/GenericTable/hooks/useTableKeyboardNavigation.d.ts +8 -0
  10. package/dist/src/lib/components/GenericTable/hooks/useTableScrollHeight.d.ts +11 -0
  11. package/dist/src/lib/components/GenericTable/hooks/useTableSorting.d.ts +17 -0
  12. package/dist/src/lib/components/GenericTable/index.d.ts +2 -1
  13. package/dist/src/lib/components/GenericTable/types.d.ts +27 -0
  14. package/dist/src/lib/components/GenericTable/utils/processColumnDefs.d.ts +11 -0
  15. package/dist/src/lib/components/GenericTable/utils/renderDataRows.d.ts +11 -0
  16. package/dist/src/lib/components/GenericTable/utils/renderLoadingRows.d.ts +9 -0
  17. package/dist/src/lib/components/Pagination/Pagination.d.ts +4 -4
  18. package/dist/src/lib/elements/Placeholder/Placeholder.d.ts +39 -9
  19. package/dist/src/lib/elements/Placeholder/Placeholder.stories.d.ts +7 -2
  20. package/package.json +1 -1
  21. /package/dist/src/lib/components/GenericTable/{ColumnHeader → components/ColumnHeader}/ColumnHeader.d.ts +0 -0
  22. /package/dist/src/lib/components/GenericTable/{ColumnHeader → components/ColumnHeader}/index.d.ts +0 -0
  23. /package/dist/src/lib/components/GenericTable/{PaginationBar → components/PaginationBar}/ControlsBar/index.d.ts +0 -0
  24. /package/dist/src/lib/components/GenericTable/{PaginationBar → components/PaginationBar}/PaginationBar.d.ts +0 -0
  25. /package/dist/src/lib/components/GenericTable/{PaginationBar → components/PaginationBar}/index.d.ts +0 -0
  26. /package/dist/src/lib/components/GenericTable/{SortingIndicator → components/SortingIndicator}/SortingIndicator.d.ts +0 -0
  27. /package/dist/src/lib/components/GenericTable/{SortingIndicator → components/SortingIndicator}/index.d.ts +0 -0
  28. /package/dist/src/lib/components/GenericTable/{TableCheckbox → components/TableCheckbox}/TableCheckbox.d.ts +0 -0
  29. /package/dist/src/lib/components/GenericTable/{TableCheckbox → components/TableCheckbox}/TableCheckbox.test.d.ts +0 -0
  30. /package/dist/src/lib/components/GenericTable/{TableCheckbox → components/TableCheckbox}/index.d.ts +0 -0
@@ -1,18 +1,9 @@
1
1
  import { DetailedHTMLProps, Dispatch, HTMLAttributes, ReactElement, ReactNode, RefObject, SetStateAction } from 'react';
2
- import { Column, ColumnDef, ColumnSort, Header, Row, RowSelectionState, SortingState } from '@tanstack/react-table';
3
- import { PaginationBarProps } from './PaginationBar';
4
- type SelectionProps<T extends {
5
- id: number | string;
6
- }> = {
7
- filterSelectable?: (row: Row<T>) => boolean;
8
- disabledSelectionTooltip?: string | ((row: Row<T>) => string);
9
- rowSelectionLabelKey?: keyof T;
10
- rowSelection?: RowSelectionState;
11
- setRowSelection?: Dispatch<SetStateAction<RowSelectionState>>;
12
- };
13
- type GenericTableProps<T extends {
14
- id: number | string;
15
- }> = {
2
+ import { Column, ColumnDef, ColumnSort, Header, Row, SortingState } from '@tanstack/react-table';
3
+ import { PaginationBarProps } from './components/PaginationBar';
4
+ import { SelectionProps, GenericTableData } from './types';
5
+ type GenericTableProps<T extends GenericTableData> = {
6
+ "aria-label"?: string;
16
7
  className?: string;
17
8
  columns: ColumnDef<T, Partial<T>>[];
18
9
  containerRef?: RefObject<HTMLElement | null>;
@@ -22,6 +13,8 @@ type GenericTableProps<T extends {
22
13
  getSubRows?: (originalRow: T, index: number) => T[] | undefined;
23
14
  groupBy?: string[];
24
15
  isLoading: boolean;
16
+ loadingVariant?: "spinner" | "skeleton";
17
+ skeletonRowCount?: number;
25
18
  noData?: ReactNode;
26
19
  pagination?: PaginationBarProps;
27
20
  pinGroup?: {
@@ -53,17 +46,15 @@ type GenericTableProps<T extends {
53
46
  * @param {(originalRow: T, index: number) => T[] | undefined} [props.getSubRows] - Function that returns the T.prop that contains nested T data
54
47
  * @param {string[]} [props.groupBy] - Column IDs to group rows by
55
48
  * @param {boolean} props.isLoading - Loading state to display placeholder content
49
+ * @param {"spinner" | "skeleton"} [props.loadingVariant="spinner"] - Loading display style; "spinner" shows a single spinner row, "skeleton" renders skeletonRowCount pulsing skeleton rows using meta.skeleton per column when defined, falling back to a default Placeholder block
50
+ * @param {number} [props.skeletonRowCount=10] - Number of skeleton rows to render when loadingVariant="skeleton"
56
51
  * @param {ReactNode} [props.noData] - Content to display when no data is available
57
52
  * @param {PaginationBarProps} [props.pagination] - Pagination configuration
58
53
  * @param {{ value: string; isTop: boolean }[]} [props.pinGroup] - Group pinning configuration
59
- * @param {ColumnSort[]} [props.sorting] - Initial sort configuration
60
- * @param {Dispatch<SetStateAction<SortingState>>} [props.setSorting] - Sorting state setter
61
- * @param {SelectionProps} [props.selection] - Selection configuration
62
- * @param {((row: Row<T>) => boolean)} [props.selection.filterSelectable] - Function to filter which rows should be selectable
63
- * @param {string | ((row: Row<T>) => string)} [props.selection.disabledSelectionTooltip] - Tooltip message or constructor on disabled checkboxes
64
- * @param {RowSelectionState} [props.selection.rowSelection] - Selected rows state
65
- * @param {keyof T} [props.selection.rowSelectionLabelKey] - Key of T to use as aria-labels for row checkboxes (e.g. "select {keyof T}")
66
- * @param {Dispatch<SetStateAction<RowSelectionState>>} [props.selection.setRowSelection] - Selection state setter
54
+ * @param {ColumnSort[]} [props.sorting] - Controlled sort state; changes to this prop are synced into the table after mount
55
+ * @param {Dispatch<SetStateAction<SortingState>>} [props.setSorting] - Sorting state setter called on user interaction
56
+ * @param {SelectionProps} [props.selection] - Row selection configuration. See {@link SelectionProps} for all sub-options
57
+ * (filterSelectable, disabledSelectionTooltip, rowSelection, rowSelectionLabelKey, setRowSelection).
67
58
  * @param {boolean} [props.showChevron=false] - Show group row expansion state chevrons
68
59
  * @param {"full-height" | "regular"} [props.variant="full-height"] - Table layout variant
69
60
  *
@@ -71,23 +62,23 @@ type GenericTableProps<T extends {
71
62
  *
72
63
  * @example
73
64
  * <GenericTable
65
+ * aria-label="Products"
74
66
  * columns={columns}
75
67
  * data={products}
76
68
  * isLoading={isLoading}
77
- * canSelect={true}
78
69
  * groupBy={["category"]}
79
- * rowSelection={selectedRows}
80
- * setRowSelection={setSelectedRows}
70
+ * selection={{
71
+ * rowSelection: selectedRows,
72
+ * setRowSelection: setSelectedRows,
73
+ * }}
81
74
  * pagination={{
82
75
  * currentPage: page,
83
76
  * setCurrentPage: setPage,
84
77
  * itemsPerPage: pageSize,
85
78
  * totalItems: totalCount,
86
- * handlePageSizeChange: handlePageSizeChange
79
+ * handlePageSizeChange: handlePageSizeChange,
87
80
  * }}
88
81
  * />
89
82
  */
90
- export declare const GenericTable: <T extends {
91
- id: number | string;
92
- } & Record<string, unknown>>({ className, columns: initialColumns, containerRef, data: initialData, filterCells, filterHeaders, getSubRows, groupBy, isLoading, noData, pagination, pinGroup, sorting, selection, setSorting, showChevron, variant, ...props }: GenericTableProps<T>) => ReactElement;
83
+ export declare const GenericTable: <T extends GenericTableData>({ "aria-label": tableAriaLabel, className, columns: initialColumns, containerRef, data: initialData, filterCells, filterHeaders, getSubRows, groupBy, isLoading, loadingVariant, skeletonRowCount, noData, pagination, pinGroup, sorting: externalSorting, selection, setSorting: setExternalSorting, showChevron, variant, ...divProps }: GenericTableProps<T>) => ReactElement;
93
84
  export {};
@@ -14,6 +14,8 @@ export default meta;
14
14
  type Story = StoryObj<typeof GenericTable<Machine>>;
15
15
  export declare const Default: Story;
16
16
  export declare const Loading: Story;
17
+ export declare const LoadingDefaultSkeleton: Story;
18
+ export declare const LoadingCustomSkeleton: Story;
17
19
  export declare const Empty: Story;
18
20
  export declare const Selectable: Story;
19
21
  export declare const ConditionallySelectable: Story;
@@ -1,6 +1,9 @@
1
1
  import { PropsWithChildren, ReactElement } from 'react';
2
+ type ControlsBarProps = PropsWithChildren<{
3
+ "aria-label"?: string;
4
+ }>;
2
5
  declare const ControlsBar: {
3
- ({ children }: PropsWithChildren<object>): ReactElement;
6
+ ({ children, "aria-label": ariaLabel, }: ControlsBarProps): ReactElement;
4
7
  Left: ({ children }: PropsWithChildren<object>) => import("react/jsx-runtime").JSX.Element;
5
8
  Right: ({ children }: PropsWithChildren<object>) => import("react/jsx-runtime").JSX.Element;
6
9
  };
@@ -0,0 +1,9 @@
1
+ import { ExpandedState, GroupingState } from '@tanstack/react-table';
2
+ import { GenericTableData } from '../types';
3
+ export declare const useTableExpansion: <T extends GenericTableData>({ grouping, initialData, }: {
4
+ grouping: GroupingState;
5
+ initialData: T[];
6
+ }) => {
7
+ expanded: ExpandedState;
8
+ setExpanded: (updater: ExpandedState | ((prev: ExpandedState) => ExpandedState)) => void;
9
+ };
@@ -0,0 +1,11 @@
1
+ import { Dispatch, SetStateAction } from 'react';
2
+ import { GroupingState } from '@tanstack/react-table';
3
+ import { GenericTableData } from '../types';
4
+ export declare const useTableGrouping: <T extends GenericTableData>({ groupBy, initialData, }: {
5
+ groupBy: string[] | undefined;
6
+ initialData: T[];
7
+ }) => {
8
+ grouping: GroupingState;
9
+ setGrouping: Dispatch<SetStateAction<GroupingState>>;
10
+ groupedData: T[];
11
+ };
@@ -0,0 +1,8 @@
1
+ import { RefObject, KeyboardEvent, FocusEvent } from 'react';
2
+ export declare const useTableKeyboardNavigation: ({ isLoading, }: {
3
+ isLoading: boolean;
4
+ }) => {
5
+ tableRef: RefObject<HTMLTableElement | null>;
6
+ handleTableFocus: (e: FocusEvent<HTMLTableElement>) => void;
7
+ handleTableKeyDown: (e: KeyboardEvent<HTMLTableElement>) => void;
8
+ };
@@ -0,0 +1,11 @@
1
+ import { RefObject } from 'react';
2
+ export declare const useTableScrollHeight: ({ containerRef, variant, length, isLoading, }: {
3
+ containerRef?: RefObject<HTMLElement | null>;
4
+ variant: "full-height" | "regular";
5
+ length: number;
6
+ isLoading: boolean;
7
+ }) => {
8
+ tableBodyRef: RefObject<HTMLTableSectionElement | null>;
9
+ maxHeight: string;
10
+ effectiveVariant: "full-height" | "regular";
11
+ };
@@ -0,0 +1,17 @@
1
+ import { Dispatch, SetStateAction } from 'react';
2
+ import { ColumnSort, GroupingState, SortingState } from '@tanstack/react-table';
3
+ import { GenericTableData } from '../types';
4
+ export declare const useTableSorting: <T extends GenericTableData>({ externalSorting, setExternalSorting, grouping, groupedData, pinGroup, }: {
5
+ externalSorting: ColumnSort[] | undefined;
6
+ setExternalSorting: Dispatch<SetStateAction<SortingState>> | undefined;
7
+ grouping: GroupingState;
8
+ groupedData: T[];
9
+ pinGroup: {
10
+ value: string;
11
+ isTop: boolean;
12
+ }[] | undefined;
13
+ }) => {
14
+ sorting: SortingState;
15
+ setSorting: (updaterOrValue: SortingState | ((prev: SortingState) => SortingState)) => void;
16
+ sortedData: T[];
17
+ };
@@ -1 +1,2 @@
1
- export * from './GenericTable';
1
+ export { GenericTable } from './GenericTable';
2
+ export type { GenericTableData, SelectionProps } from './types';
@@ -0,0 +1,27 @@
1
+ import { Dispatch, ReactNode, SetStateAction } from 'react';
2
+ import { Row, RowData, RowSelectionState } from '@tanstack/react-table';
3
+ declare module "@tanstack/react-table" {
4
+ interface ColumnMeta<TData extends RowData, TValue = unknown> {
5
+ /** Custom loading skeleton renderer. Overrides the default shimmer for this column. */
6
+ skeleton?: () => ReactNode;
7
+ /** Returns an aria-label for a data cell. Use for icon-only, stacked, or badge cells. */
8
+ cellAriaLabel?: (row: Row<TData>) => string;
9
+ /** Set true when the header contains an interactive element to skip the sort-button wrapper. */
10
+ isInteractiveHeader?: boolean;
11
+ /** aria-label for the <th> — use for non-text headers such as checkboxes. */
12
+ headerAriaLabel?: string;
13
+ /** Set true to hide the header cell from assistive technology. */
14
+ headerAriaHidden?: boolean;
15
+ }
16
+ }
17
+ /** Base constraint for all GenericTable row data: must have an `id` and be string-indexable. */
18
+ export type GenericTableData = {
19
+ id: number | string;
20
+ } & Record<string, unknown>;
21
+ export type SelectionProps<T extends GenericTableData> = {
22
+ filterSelectable?: (row: Row<T>) => boolean;
23
+ disabledSelectionTooltip?: string | ((row: Row<T>) => string);
24
+ rowSelectionLabelKey?: keyof T;
25
+ rowSelection?: RowSelectionState;
26
+ setRowSelection?: Dispatch<SetStateAction<RowSelectionState>>;
27
+ };
@@ -0,0 +1,11 @@
1
+ import { ColumnDef } from '@tanstack/react-table';
2
+ import { SelectionProps, GenericTableData } from '../types';
3
+ export declare const processColumnDefs: <T extends GenericTableData>({ canSelect, initialColumns, isLoading, groupBy, getSubRows, selection, showChevron, }: {
4
+ canSelect: boolean;
5
+ initialColumns: ColumnDef<T, Partial<T>>[];
6
+ isLoading: boolean;
7
+ groupBy: string[] | undefined;
8
+ getSubRows?: (originalRow: T, index: number) => T[] | undefined;
9
+ selection?: SelectionProps<T>;
10
+ showChevron: boolean;
11
+ }) => ColumnDef<T, Partial<T>>[];
@@ -0,0 +1,11 @@
1
+ import { ReactNode } from 'react';
2
+ import { Column, ColumnDef, Row, Table } from '@tanstack/react-table';
3
+ import { SelectionProps, GenericTableData } from '../types';
4
+ export declare const renderDataRows: <T extends GenericTableData>({ table, columns, filterCells, getSubRows, noData, selection, }: {
5
+ table: Table<T>;
6
+ columns: ColumnDef<T, Partial<T>>[];
7
+ filterCells: (row: Row<T>, column: Column<T>) => boolean;
8
+ getSubRows?: (originalRow: T, index: number) => T[] | undefined;
9
+ noData: ReactNode;
10
+ selection?: SelectionProps<T>;
11
+ }) => import("react/jsx-runtime").JSX.Element | import("react/jsx-runtime").JSX.Element[];
@@ -0,0 +1,9 @@
1
+ import { ColumnDef, Header, Table } from '@tanstack/react-table';
2
+ import { GenericTableData } from '../types';
3
+ export declare const renderLoadingRows: <T extends GenericTableData>({ table, columns, filterHeaders, loadingVariant, skeletonRowCount, }: {
4
+ table: Table<T>;
5
+ columns: ColumnDef<T, Partial<T>>[];
6
+ filterHeaders: (header: Header<T, unknown>) => boolean;
7
+ loadingVariant?: "skeleton" | "spinner";
8
+ skeletonRowCount: number;
9
+ }) => import("react/jsx-runtime").JSX.Element | import("react/jsx-runtime").JSX.Element[];
@@ -1,5 +1,5 @@
1
- import { ChangeEvent } from 'react';
2
- export interface PaginationProps extends React.AriaAttributes {
1
+ import { AriaAttributes, ChangeEvent, FC } from 'react';
2
+ export interface PaginationProps extends AriaAttributes {
3
3
  className?: string;
4
4
  currentPage: number | undefined;
5
5
  error?: string;
@@ -10,11 +10,11 @@ export interface PaginationProps extends React.AriaAttributes {
10
10
  onPreviousClick: () => void;
11
11
  totalPages: number;
12
12
  }
13
- export declare const Pagination: React.FC<PaginationProps>;
13
+ export declare const Pagination: FC<PaginationProps>;
14
14
  export interface PaginationContainerProps {
15
15
  currentPage: PaginationProps["currentPage"];
16
16
  disabled: PaginationProps["disabled"];
17
17
  paginate: (page: number) => void;
18
18
  totalPages: PaginationProps["totalPages"];
19
19
  }
20
- export declare const PaginationContainer: React.FC<PaginationContainerProps>;
20
+ export declare const PaginationContainer: FC<PaginationContainerProps>;
@@ -1,12 +1,42 @@
1
- import { ReactNode } from 'react';
2
- export type PlaceholderProps = {
1
+ import { CSSProperties, HTMLAttributes, ReactElement, ReactNode } from 'react';
2
+ type PlaceholderProps = {
3
3
  className?: string;
4
+ width?: CSSProperties["width"];
5
+ height?: CSSProperties["height"];
6
+ /** @deprecated */
4
7
  isPending?: boolean;
5
- } & ({
6
- text?: never;
7
- children?: ReactNode;
8
- } | {
8
+ /** @deprecated */
9
9
  text?: string;
10
- children?: never;
11
- });
12
- export declare const Placeholder: ({ text, children, className, isPending, }: PlaceholderProps) => import("react/jsx-runtime").JSX.Element;
10
+ /** @deprecated */
11
+ children?: ReactNode;
12
+ variant?: "block" | "text";
13
+ } & Omit<HTMLAttributes<HTMLDivElement>, "children">;
14
+ /**
15
+ * Placeholder - A pulsing skeleton block used to represent loading content
16
+ *
17
+ * Renders a rectangular block with a pulse animation that matches the dimensions
18
+ * of the content it is replacing. Use `width` and `height` to control the size
19
+ * explicitly, or rely on the default block layout for full-width skeletons.
20
+ *
21
+ * @param {Object} props - Component props
22
+ * @param {string} [props.className] - Additional CSS class names applied to the root element
23
+ * @param {CSSProperties["width"]} [props.width] - Width of the skeleton block; accepts any valid CSS value (e.g. "200px", "100%", "12rem"). When omitted the block stretches to fill its container
24
+ * @param {CSSProperties["height"]} [props.height] - Height of the skeleton block; accepts any valid CSS value (e.g. "1rem", "48px", "3em"). When omitted the block collapses unless content or a sizer provides height
25
+ * @param {"block" | "text"} [props.variant="text"] - Rendering variant. `"block"` renders a standalone skeleton div; `"text"` is the legacy variant that requires `isPending` to be set
26
+ * @param {HTMLAttributes<HTMLDivElement>} [props.style] - Any HTML div attributes (e.g. `style`, `data-*`, `aria-*`) are forwarded to the root element. `style` is merged with the component's internal width/height styles, with consumer values taking precedence
27
+ * @param {boolean} [props.isPending] - @deprecated Use conditional rendering at the call-site instead. When `true` the skeleton is shown; when `false` the `children` are rendered. Will be removed in a future major version
28
+ * @param {string} [props.text] - @deprecated Width is now controlled via the `width` prop. When provided the text is rendered in a visually-hidden sizer span that gives the block its natural content width. Will be removed in a future major version
29
+ * @param {ReactNode} [props.children] - @deprecated Pass children outside the Placeholder and control visibility at the call-site. Will be removed in a future major version
30
+ *
31
+ * @returns {ReactElement} The rendered skeleton block, or the children when `isPending` is `false`
32
+ *
33
+ * @example
34
+ * // Standalone skeleton block
35
+ * <Placeholder width="200px" height="1rem" />
36
+ *
37
+ * @example
38
+ * // Composed loading state
39
+ * {isLoading ? <Placeholder width="100%" height="1.5rem" /> : <p>{content}</p>}
40
+ */
41
+ export declare const Placeholder: ({ className, width, height, isPending, text, children, variant, style, ...divProps }: PlaceholderProps) => ReactElement;
42
+ export {};
@@ -2,5 +2,10 @@ import { Meta, StoryObj } from '@storybook/react';
2
2
  import { Placeholder } from './Placeholder';
3
3
  declare const meta: Meta<typeof Placeholder>;
4
4
  export default meta;
5
- export declare const TextExample: StoryObj<typeof Placeholder>;
6
- export declare const ComponentExample: StoryObj<typeof Placeholder>;
5
+ type Story = StoryObj<typeof Placeholder>;
6
+ export declare const TextLine: Story;
7
+ export declare const Paragraph: Story;
8
+ export declare const Block: Story;
9
+ export declare const Complex: Story;
10
+ export declare const LegacyTextProp: Story;
11
+ export declare const LegacyChildrenProp: Story;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@canonical/maas-react-components",
3
3
  "description": "React components for use in MAAS UI projects.",
4
- "version": "2.0.4",
4
+ "version": "2.2.0",
5
5
  "repository": {
6
6
  "type": "git",
7
7
  "url": "git+https://github.com/canonical/maas-react-components.git"