@pantheon-systems/pds-toolkit-react 2.0.0-beta.6 → 2.0.0-beta.7

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.
@@ -39,12 +39,14 @@ export type DetailPanelContext = {
39
39
  export interface TableColumn {
40
40
  /**
41
41
  * When true, this column's cell content is shown on the compact card
42
- * rendered at mobile widths, in addition to the full detail view. The
43
- * first card-visible column reads as the card's title; any further ones
44
- * render as a secondary line. Columns without this flag are omitted from
45
- * the card front but still appear in the full detail view (the row's
46
- * `renderDetailPanel` content, or the auto-generated one — see
47
- * `hasMobileDetailSheet`). Has no effect above the mobile breakpoint.
42
+ * rendered at mobile widths, in addition to the full detail view. With
43
+ * the default `cardLayout="stacked"`, the first card-visible column reads
44
+ * as the card's title and any further ones render as a secondary line
45
+ * below it; with `cardLayout="inline"` every card-visible column is a
46
+ * peer in one row instead (see `cardLayout`). Columns without this flag
47
+ * are omitted from the card front but still appear in the full detail
48
+ * view (the row's `renderDetailPanel` content, or the auto-generated one
49
+ * — see `hasMobileDetailSheet`). Has no effect above the mobile breakpoint.
48
50
  */
49
51
  cardVisible?: boolean;
50
52
  /**
@@ -76,6 +78,16 @@ export interface TableColumn {
76
78
  sortKey?: string;
77
79
  }
78
80
  export interface TableProps extends ComponentPropsWithoutRef<'table'> {
81
+ /**
82
+ * Layout of a mobile card's `cardVisible` columns (see `hasMobileCards`).
83
+ * `'stacked'` (default) gives the first one a bold title treatment with
84
+ * the rest in a smaller secondary line below it. `'inline'` drops that
85
+ * distinction and lays out every `cardVisible` column as an equal peer in
86
+ * one row — for a card whose "title" is really a visual chip (a card
87
+ * network logo, an avatar) rather than a name, where forcing a
88
+ * title/subtext hierarchy onto it doesn't make sense.
89
+ */
90
+ cardLayout?: 'stacked' | 'inline';
79
91
  /** Additional class names */
80
92
  className?: string;
81
93
  /**
@@ -130,6 +142,11 @@ export interface TableProps extends ComponentPropsWithoutRef<'table'> {
130
142
  * When provided, takes precedence over `emptyStateHeading` and `emptyStateMessage`.
131
143
  */
132
144
  emptyState?: ReactNode;
145
+ /**
146
+ * Optional action (e.g. a Button or link) rendered below the message in
147
+ * the default empty state. Ignored when `emptyState` is provided.
148
+ */
149
+ emptyStateAction?: ReactNode;
133
150
  /**
134
151
  * Heading text for the default empty state. Defaults to `"No results found."`
135
152
  * Override for translation or context-specific messaging.
@@ -393,4 +410,4 @@ export interface TableProps extends ComponentPropsWithoutRef<'table'> {
393
410
  */
394
411
  totalItemCount?: number;
395
412
  }
396
- export declare const Table: ({ className, closeDetailPanelLabel, columns, currentPage, defaultSortKey, defaultSortOrder, density, detailPanelNav, detailPanelTitle, detailPanelWidth, emptyState, emptyStateHeading, emptyStateMessage, footer, getDetailPanelPositionLabel, getPageSizeLabel, getRowClassName, getRowId, getRowSelectDisabledReason, getSelectRowLabel, getSortLabel, hasDesktopDetailPanel, hasMobileCards, hasMobileDetailSheet, hasPanel, inspectedRowId, isLoading, isRowSelectable, itemsPerPage, loadingRowCount, maxHeight, minHeight, nextDetailPanelRowLabel, onDetailPanelNext, onDetailPanelPrev, onPageChange, onPageSizeChange, onRowInspect, onRowSelectionChange, onSort, pageSizeOptions, pageSizeSelectLabel, paginationLabels, prevDetailPanelRowLabel, renderDetailPanel, renderDetailPanelFooter, rowData, selectAllLabel, selectedRows, sortKey, sortOrder, totalItemCount, ...props }: TableProps) => import("react/jsx-runtime").JSX.Element;
413
+ export declare const Table: ({ cardLayout, className, closeDetailPanelLabel, columns, currentPage, defaultSortKey, defaultSortOrder, density, detailPanelNav, detailPanelTitle, detailPanelWidth, emptyState, emptyStateAction, emptyStateHeading, emptyStateMessage, footer, getDetailPanelPositionLabel, getPageSizeLabel, getRowClassName, getRowId, getRowSelectDisabledReason, getSelectRowLabel, getSortLabel, hasDesktopDetailPanel, hasMobileCards, hasMobileDetailSheet, hasPanel, inspectedRowId, isLoading, isRowSelectable, itemsPerPage, loadingRowCount, maxHeight, minHeight, nextDetailPanelRowLabel, onDetailPanelNext, onDetailPanelPrev, onPageChange, onPageSizeChange, onRowInspect, onRowSelectionChange, onSort, pageSizeOptions, pageSizeSelectLabel, paginationLabels, prevDetailPanelRowLabel, renderDetailPanel, renderDetailPanelFooter, rowData, selectAllLabel, selectedRows, sortKey, sortOrder, totalItemCount, ...props }: TableProps) => import("react/jsx-runtime").JSX.Element;
@@ -1,5 +1,6 @@
1
1
  import { ComponentPropsWithoutRef, ReactNode } from 'react';
2
2
  import { HeadingLevel } from '../../../libs/types/custom-types';
3
+ import { PDSIllustration } from '../../media/Illustration/Illustration';
3
4
  import './vertical-empty-state.css';
4
5
  /**
5
6
  * Prop types for VerticalEmptyState
@@ -14,6 +15,20 @@ export interface VerticalEmptyStateProps extends ComponentPropsWithoutRef<'div'>
14
15
  * This should be a Button, ButtonLink, or two items wrapped in a `pds-button-group` div.
15
16
  */
16
17
  ctaRegion?: ReactNode;
18
+ /**
19
+ * Grows this component to fill its parent's available height and
20
+ * vertically centers its content within it — for a full-page empty state
21
+ * (404, access denied, etc.) that should sit centered in the remaining
22
+ * viewport rather than top-aligned.
23
+ *
24
+ * Only takes effect when the immediate parent is itself a flex container
25
+ * with room to grow into (e.g. `AppLayout`'s `main-inner`) — otherwise
26
+ * `flex: 1` has nothing to act on and this is a no-op. Prefer this over
27
+ * hand-rolled centering CSS (a guessed `height`/`min-height` calc, or
28
+ * wrapping in `FlexContainer`), which breaks whenever real content grows
29
+ * taller than the guess.
30
+ */
31
+ fillHeight?: boolean;
17
32
  /**
18
33
  * heading to explain the empty state.
19
34
  */
@@ -23,20 +38,43 @@ export interface VerticalEmptyStateProps extends ComponentPropsWithoutRef<'div'>
23
38
  */
24
39
  headingLevel?: HeadingLevel;
25
40
  /**
26
- * PDS illustration image to display above the heading.
27
- * Can be a string (a link to an SVG file, either from Brandfolder or
28
- * local) or a React node (e.g. a Spinner, for in-progress empty states).
29
- * See full documentation for details.
41
+ * Which illustration to show above the heading, using the toolkit's
42
+ * `Illustration` component — the preferred way to provide media here.
43
+ * Decorative (no accessible name). Takes precedence over `image` if both
44
+ * are set.
45
+ */
46
+ illustration?: PDSIllustration;
47
+ /**
48
+ * Width of `illustration` (CSS value). Height follows automatically from
49
+ * its aspect ratio.
50
+ */
51
+ illustrationWidth?: string;
52
+ /**
53
+ * Media to display above the heading. Can be a string (a link to an SVG
54
+ * file, either from Brandfolder or local) or a React node, such as
55
+ * `Picture` for a raster image. Prefer `illustration`/`isLoading` for a
56
+ * new illustration or loading state — `image` is a legacy fallback for
57
+ * anything else, slated for eventual deprecation.
58
+ *
59
+ * `imageWidth`/`imageHeight` size the container a string `image` renders
60
+ * into; it fills that container's height, scaling width proportionally.
61
+ * Any React node is responsible for its own sizing within it (pass
62
+ * matching `width`/`height` if you want it to fill the container).
30
63
  */
31
64
  image?: string | ReactNode;
32
65
  /**
33
- * Height of the image (CSS value like '200px', '50%', etc.)
66
+ * Height of the image container (CSS value like '120px', '50%', etc.)
34
67
  */
35
68
  imageHeight?: string;
36
69
  /**
37
- * Width of the image (CSS value like '200px', '50%', etc.)
70
+ * Width of the image container (CSS value like '200px', '50%', etc.)
38
71
  */
39
72
  imageWidth?: string;
73
+ /**
74
+ * Shows a loading spinner instead of `illustration`/`image`, for an
75
+ * in-progress empty state. Takes precedence over both.
76
+ */
77
+ isLoading?: boolean;
40
78
  /**
41
79
  * Message to display below the heading.
42
80
  */
@@ -45,4 +83,4 @@ export interface VerticalEmptyStateProps extends ComponentPropsWithoutRef<'div'>
45
83
  /**
46
84
  * VerticalEmptyState UI component
47
85
  */
48
- export declare const VerticalEmptyState: ({ className, ctaRegion, heading, headingLevel, image, imageHeight, imageWidth, message, ...props }: VerticalEmptyStateProps) => import("react/jsx-runtime").JSX.Element;
86
+ export declare const VerticalEmptyState: ({ className, ctaRegion, fillHeight, heading, headingLevel, illustration, illustrationWidth, image, imageHeight, imageWidth, isLoading, message, ...props }: VerticalEmptyStateProps) => import("react/jsx-runtime").JSX.Element;
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * Generated by: npm run generate:icon-data
5
5
  * Source: icon-registry.ts + Font Awesome packages + custom-icons.tsx
6
- * Generated: 2026-10-02T19:35:35.857Z
6
+ * Generated: 2026-10-05T22:37:57.616Z
7
7
  */
8
8
  import { customIcons } from './custom-icons';
9
9
  export { customIcons };
@@ -0,0 +1,37 @@
1
+ import { ComponentPropsWithoutRef } from 'react';
2
+ import { type PDSIllustrationName } from './generated-illustration-data';
3
+ import './illustration.css';
4
+ export type PDSIllustration = PDSIllustrationName;
5
+ /**
6
+ * Prop types for Illustration
7
+ */
8
+ export interface IllustrationProps extends ComponentPropsWithoutRef<'svg'> {
9
+ /**
10
+ * Accessible name for the illustration. Defaults to '' (decorative,
11
+ * hidden from assistive tech). When provided, renders an SVG <title>
12
+ * and exposes the illustration as role="img" with that accessible name.
13
+ */
14
+ alt?: string;
15
+ /**
16
+ * Additional class names
17
+ */
18
+ className?: string;
19
+ /**
20
+ * Optional height (CSS value). If not provided, the illustration is
21
+ * sized by its intrinsic viewBox, same as Picture.
22
+ */
23
+ height?: string | number;
24
+ /**
25
+ * Which illustration to render.
26
+ */
27
+ name: PDSIllustration;
28
+ /**
29
+ * Optional width (CSS value). If not provided, the illustration is
30
+ * sized by its intrinsic viewBox, same as Picture.
31
+ */
32
+ width?: string | number;
33
+ }
34
+ /**
35
+ * Illustration UI component
36
+ */
37
+ export declare const Illustration: ({ alt, className, height, name, width, ...props }: IllustrationProps) => import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Auto-generated illustration data - DO NOT EDIT MANUALLY
3
+ *
4
+ * Generated by: npm run generate:illustration-data
5
+ * Source: illustration-registry.ts + illustrations/*.svg
6
+ * Generated: 2026-10-05T22:37:58.277Z
7
+ */
8
+ import React from 'react';
9
+ export interface IllustrationData {
10
+ height: number;
11
+ render: () => React.ReactNode;
12
+ width: number;
13
+ }
14
+ export declare const illustrationData: Record<string, IllustrationData>;
15
+ export declare const illustrationList: readonly ["createEnvLive", "createEnvTest", "underConstruction"];
16
+ export type PDSIllustrationName = (typeof illustrationList)[number];
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Illustration Registry - Source of truth for PDS illustration mappings.
3
+ *
4
+ * Maps PDS camelCase illustration names to their raw SVG source file.
5
+ *
6
+ * To add an illustration:
7
+ * 1. Export the polished SVG from Figma into illustrations/<kebab-case-name>.svg
8
+ * 2. Run: npm run generate:illustration
9
+ * (prompts for a PDS name — suggests one from the filename — adds the
10
+ * entry below, and runs generate:illustration-data for you)
11
+ * 3. Commit the SVG, this file, and generated-illustration-data.tsx
12
+ *
13
+ * To add an entry manually instead: add it below, then run
14
+ * npm run generate:illustration-data yourself.
15
+ */
16
+ export interface IllustrationRegistryEntry {
17
+ file: string;
18
+ }
19
+ export declare const illustrationRegistry: Record<string, IllustrationRegistryEntry>;
@@ -1 +1 @@
1
- @layer pds-v1, pds-v2;@layer pds-v2{.pds-horizontal-empty-state{color:var(--pds-color-foreground-default);display:flex;font-family:var(--pds-typography-ff-default);gap:var(--pds-spacing-xl);width:100%}.pds-horizontal-empty-state--top{align-items:flex-start}.pds-horizontal-empty-state--center{align-items:center}.pds-horizontal-empty-state__content{display:flex;flex-direction:column;padding-inline-end:var(--pds-spacing-l);row-gap:var(--pds-spacing-xl);width:60%}.pds-horizontal-empty-state__heading{margin-block-end:0}.pds-horizontal-empty-state__message{margin-block-start:0}.pds-horizontal-empty-state__message :where(:not(.visually-hidden))+:where(:not(p,ul,ol,li)){margin-block-start:var(--pds-spacing-2xl)}.pds-horizontal-empty-state__media{width:40%}.pds-horizontal-empty-state__image{height:auto;width:100%}.pds-horizontal-empty-state--indented-content .pds-horizontal-empty-state__content{padding-inline-start:var(--pds-spacing-xl)}.pds-horizontal-empty-state--video .pds-horizontal-empty-state__content,.pds-horizontal-empty-state--video .pds-horizontal-empty-state__media{width:50%}.pds-horizontal-empty-state__media--video .pds-video-embed{border-radius:var(--pds-border-radius-panel)}[data-pds-mobile] .pds-horizontal-empty-state{flex-direction:column}[data-pds-mobile] .pds-horizontal-empty-state .pds-horizontal-empty-state__content,[data-pds-mobile] .pds-horizontal-empty-state .pds-horizontal-empty-state__media{width:100%}[data-pds-mobile] .pds-horizontal-empty-state .pds-horizontal-empty-state__content{padding-inline-end:0}[data-pds-mobile] .pds-horizontal-empty-state .pds-horizontal-empty-state__media--image{display:none}[data-pds-mobile] .pds-horizontal-empty-state .pds-horizontal-empty-state__media--video{order:-1}}
1
+ @layer pds-v1, pds-v2;@layer pds-v2{.pds-horizontal-empty-state{color:var(--pds-color-foreground-default);display:flex;font-family:var(--pds-typography-ff-default);gap:var(--pds-spacing-xl);width:100%}.pds-horizontal-empty-state--top{align-items:flex-start}.pds-horizontal-empty-state--center{align-items:center}.pds-horizontal-empty-state__content{display:flex;flex-direction:column;padding-inline-end:var(--pds-spacing-l);row-gap:var(--pds-spacing-xl);width:60%}.pds-horizontal-empty-state__heading{margin-block-end:0}.pds-horizontal-empty-state__message{margin-block-start:0}.pds-horizontal-empty-state__message :where(:not(.visually-hidden))+:where(:not(p,ul,ol,li)){margin-block-start:var(--pds-spacing-2xl)}.pds-horizontal-empty-state__cta .pds-button{--button-font-size:var(--pds-typography-size-m);--button-gap-inline:var(--pds-spacing-button-gap-inline-m);--button-height:var(--pds-spacing-button-height-m);--button-padding-inline:var(--pds-spacing-button-padding-inline-m)}.pds-horizontal-empty-state__media{width:40%}.pds-horizontal-empty-state__image{height:auto;width:100%}.pds-horizontal-empty-state--indented-content .pds-horizontal-empty-state__content{padding-inline-start:var(--pds-spacing-xl)}.pds-horizontal-empty-state--video .pds-horizontal-empty-state__content,.pds-horizontal-empty-state--video .pds-horizontal-empty-state__media{width:50%}.pds-horizontal-empty-state__media--video .pds-video-embed{border-radius:var(--pds-border-radius-panel)}[data-pds-mobile] .pds-horizontal-empty-state{flex-direction:column}[data-pds-mobile] .pds-horizontal-empty-state .pds-horizontal-empty-state__content,[data-pds-mobile] .pds-horizontal-empty-state .pds-horizontal-empty-state__media{width:100%}[data-pds-mobile] .pds-horizontal-empty-state .pds-horizontal-empty-state__content{padding-inline-end:0}[data-pds-mobile] .pds-horizontal-empty-state .pds-horizontal-empty-state__media--image{display:none}[data-pds-mobile] .pds-horizontal-empty-state .pds-horizontal-empty-state__media--video{order:-1}}
@@ -0,0 +1 @@
1
+ @layer pds-v1, pds-v2;@layer pds-v2{.pds-illustration{display:inline-block;height:auto;max-width:100%}}