@pallasoft/ps-core-components 2.36.0 → 2.38.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 (43) hide show
  1. package/dist/components/ps-action-tile-content.d.ts +8 -0
  2. package/dist/components/ps-action-tile-content.js +7 -0
  3. package/dist/components/ps-action-tile-link.d.ts +10 -0
  4. package/dist/components/ps-action-tile-link.js +16 -0
  5. package/dist/components/ps-action-tile.js +2 -1
  6. package/dist/components/ps-capped-list.js +2 -2
  7. package/dist/components/ps-detail-pane.d.ts +11 -0
  8. package/dist/components/ps-detail-pane.js +7 -0
  9. package/dist/components/ps-document-row.d.ts +2 -1
  10. package/dist/components/ps-document-row.js +11 -6
  11. package/dist/components/ps-form-footer.d.ts +5 -2
  12. package/dist/components/ps-form-footer.js +2 -1
  13. package/dist/components/ps-split-view.d.ts +6 -0
  14. package/dist/components/ps-split-view.js +13 -0
  15. package/dist/components/ps-text-link.d.ts +12 -0
  16. package/dist/components/ps-text-link.js +13 -0
  17. package/dist/constants/ps-button-classes.js +2 -2
  18. package/dist/constants/ps-split-view-config.d.ts +4 -0
  19. package/dist/constants/ps-split-view-config.js +7 -0
  20. package/dist/constants/ps-text-link-classes.d.ts +5 -0
  21. package/dist/constants/ps-text-link-classes.js +8 -0
  22. package/dist/esm/components/ps-action-tile-content.js +3 -0
  23. package/dist/esm/components/ps-action-tile-link.js +12 -0
  24. package/dist/esm/components/ps-action-tile.js +3 -2
  25. package/dist/esm/components/ps-capped-list.js +2 -2
  26. package/dist/esm/components/ps-detail-pane.js +3 -0
  27. package/dist/esm/components/ps-document-row.js +11 -6
  28. package/dist/esm/components/ps-form-footer.js +2 -1
  29. package/dist/esm/components/ps-split-view.js +9 -0
  30. package/dist/esm/components/ps-text-link.js +9 -0
  31. package/dist/esm/constants/ps-button-classes.js +2 -2
  32. package/dist/esm/constants/ps-split-view-config.js +4 -0
  33. package/dist/esm/constants/ps-text-link-classes.js +5 -0
  34. package/dist/esm/hooks/use-ps-fill-height.js +20 -0
  35. package/dist/esm/index.js +5 -0
  36. package/dist/esm/services/ps-fill-height-service.js +33 -0
  37. package/dist/hooks/use-ps-fill-height.d.ts +4 -0
  38. package/dist/hooks/use-ps-fill-height.js +24 -0
  39. package/dist/index.d.ts +5 -0
  40. package/dist/index.js +5 -0
  41. package/dist/services/ps-fill-height-service.d.ts +5 -0
  42. package/dist/services/ps-fill-height-service.js +37 -0
  43. package/package.json +1 -1
@@ -0,0 +1,8 @@
1
+ import type { ReactNode } from 'react';
2
+ export interface PsActionTileContentProps {
3
+ description?: string;
4
+ icon?: ReactNode;
5
+ label: string;
6
+ variant: 'default' | 'primary';
7
+ }
8
+ export declare const PsActionTileContent: ({ description, icon, label, variant, }: PsActionTileContentProps) => import("react").JSX.Element;
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PsActionTileContent = void 0;
4
+ const jsx_runtime_1 = require("react/jsx-runtime");
5
+ const ps_design_system_1 = require("@pallasoft/ps-design-system");
6
+ const PsActionTileContent = ({ description, icon, label, variant, }) => ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsxs)("span", { className: 'min-w-0', children: [(0, jsx_runtime_1.jsx)("span", { className: 'block break-words', children: label }), description ? ((0, jsx_runtime_1.jsx)("span", { className: ps_design_system_1.PallasoftClassNameService.merge('mt-0.5 block text-xs font-medium leading-5', variant === 'primary' ? 'text-white/75' : 'text-ink/50'), children: description })) : null] }), icon ? ((0, jsx_runtime_1.jsx)("span", { className: ps_design_system_1.PallasoftClassNameService.merge('flex h-9 w-9 shrink-0 items-center justify-center rounded-lg', variant === 'primary' ? 'bg-white/15 text-white' : 'ps-icon-surface'), children: icon })) : null] }));
7
+ exports.PsActionTileContent = PsActionTileContent;
@@ -0,0 +1,10 @@
1
+ import type { AnchorHTMLAttributes, ElementType, ReactNode } from 'react';
2
+ export interface PsActionTileLinkProps extends AnchorHTMLAttributes<HTMLAnchorElement> {
3
+ description?: string;
4
+ href: string;
5
+ icon?: ReactNode;
6
+ label: string;
7
+ LinkComponent?: ElementType;
8
+ variant?: 'default' | 'primary';
9
+ }
10
+ export declare const PsActionTileLink: ({ className, description, href, icon, label, LinkComponent, variant, ...props }: PsActionTileLinkProps) => import("react").JSX.Element;
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PsActionTileLink = void 0;
4
+ const jsx_runtime_1 = require("react/jsx-runtime");
5
+ const ps_design_system_1 = require("@pallasoft/ps-design-system");
6
+ const ps_action_tile_content_1 = require("./ps-action-tile-content");
7
+ const variantClassNames = {
8
+ default: 'ps-action-tile',
9
+ primary: 'ps-action-tile ps-action-tile-primary',
10
+ };
11
+ const PsActionTileLink = ({ className, description, href, icon, label, LinkComponent, variant = 'default', ...props }) => {
12
+ const linkClassName = ps_design_system_1.PallasoftClassNameService.merge('ps-focus-ring w-full', variantClassNames[variant], className);
13
+ const content = ((0, jsx_runtime_1.jsx)(ps_action_tile_content_1.PsActionTileContent, { description: description, icon: icon, label: label, variant: variant }));
14
+ return LinkComponent ? ((0, jsx_runtime_1.jsx)(LinkComponent, { className: linkClassName, prefetch: 'intent', to: href, ...props, children: content })) : ((0, jsx_runtime_1.jsx)("a", { className: linkClassName, href: href, ...props, children: content }));
15
+ };
16
+ exports.PsActionTileLink = PsActionTileLink;
@@ -4,10 +4,11 @@ exports.PsActionTile = void 0;
4
4
  const jsx_runtime_1 = require("react/jsx-runtime");
5
5
  const ps_design_system_1 = require("@pallasoft/ps-design-system");
6
6
  const ps_skeleton_shape_1 = require("../constants/ps-skeleton-shape");
7
+ const ps_action_tile_content_1 = require("./ps-action-tile-content");
7
8
  const ps_skeleton_1 = require("./ps-skeleton");
8
9
  const variantClassNames = {
9
10
  default: 'ps-action-tile',
10
11
  primary: 'ps-action-tile ps-action-tile-primary',
11
12
  };
12
- const PsActionTile = ({ className, description, icon, isLoading = false, label, type = 'button', variant = 'default', ...props }) => isLoading ? ((0, jsx_runtime_1.jsx)(ps_skeleton_1.PsSkeleton, { className: ps_design_system_1.PallasoftClassNameService.merge('h-16', className), shape: ps_skeleton_shape_1.PsSkeletonShape.Card })) : ((0, jsx_runtime_1.jsxs)("button", { className: ps_design_system_1.PallasoftClassNameService.merge('ps-focus-ring w-full', variantClassNames[variant], className), type: type, ...props, children: [(0, jsx_runtime_1.jsxs)("span", { className: 'min-w-0', children: [(0, jsx_runtime_1.jsx)("span", { className: 'block break-words', children: label }), description ? ((0, jsx_runtime_1.jsx)("span", { className: ps_design_system_1.PallasoftClassNameService.merge('mt-0.5 block text-xs font-medium leading-5', variant === 'primary' ? 'text-white/75' : 'text-ink/50'), children: description })) : null] }), icon ? ((0, jsx_runtime_1.jsx)("span", { className: ps_design_system_1.PallasoftClassNameService.merge('flex h-9 w-9 shrink-0 items-center justify-center rounded-lg', variant === 'primary' ? 'bg-white/15 text-white' : 'ps-icon-surface'), children: icon })) : null] }));
13
+ const PsActionTile = ({ className, description, icon, isLoading = false, label, type = 'button', variant = 'default', ...props }) => isLoading ? ((0, jsx_runtime_1.jsx)(ps_skeleton_1.PsSkeleton, { className: ps_design_system_1.PallasoftClassNameService.merge('h-16', className), shape: ps_skeleton_shape_1.PsSkeletonShape.Card })) : ((0, jsx_runtime_1.jsx)("button", { className: ps_design_system_1.PallasoftClassNameService.merge('ps-focus-ring w-full', variantClassNames[variant], className), type: type, ...props, children: (0, jsx_runtime_1.jsx)(ps_action_tile_content_1.PsActionTileContent, { description: description, icon: icon, label: label, variant: variant }) }));
13
14
  exports.PsActionTile = PsActionTile;
@@ -4,11 +4,11 @@ exports.PsCappedList = void 0;
4
4
  const jsx_runtime_1 = require("react/jsx-runtime");
5
5
  const react_1 = require("react");
6
6
  const ps_capped_list_config_1 = require("../constants/ps-capped-list-config");
7
- const ps_button_1 = require("./ps-button");
7
+ const ps_text_link_1 = require("./ps-text-link");
8
8
  const PsCappedList = ({ getKey, items, renderItem, showAllLabel, visibleRows = ps_capped_list_config_1.PsCappedListConfig.defaultVisibleRows, }) => {
9
9
  const [isExpanded, setIsExpanded] = (0, react_1.useState)(false);
10
10
  const isCapped = !isExpanded && items.length > visibleRows;
11
11
  const shown = isCapped ? items.slice(0, visibleRows) : items;
12
- return ((0, jsx_runtime_1.jsxs)("div", { className: 'flex flex-col gap-2', children: [(0, jsx_runtime_1.jsx)("ul", { className: '-my-2 flex flex-col divide-y divide-line', children: shown.map((item) => ((0, jsx_runtime_1.jsx)("li", { children: renderItem(item) }, getKey(item)))) }), isCapped ? ((0, jsx_runtime_1.jsx)(ps_button_1.PsButton, { className: 'self-start', onClick: () => setIsExpanded(true), size: 'compact', variant: 'ghost', children: showAllLabel })) : null] }));
12
+ return ((0, jsx_runtime_1.jsxs)("div", { className: 'flex flex-col gap-2', children: [(0, jsx_runtime_1.jsx)("ul", { className: '-my-2 flex flex-col divide-y divide-line', children: shown.map((item) => ((0, jsx_runtime_1.jsx)("li", { children: renderItem(item) }, getKey(item)))) }), isCapped ? ((0, jsx_runtime_1.jsx)(ps_text_link_1.PsTextLink, { className: 'self-start', onClick: () => setIsExpanded(true), size: 'compact', children: showAllLabel })) : null] }));
13
13
  };
14
14
  exports.PsCappedList = PsCappedList;
@@ -0,0 +1,11 @@
1
+ import type { ReactNode } from 'react';
2
+ export interface PsDetailPaneProps {
3
+ children: ReactNode;
4
+ className?: string;
5
+ footer?: ReactNode;
6
+ footerStart?: ReactNode;
7
+ headerActions?: ReactNode;
8
+ subtitle?: ReactNode;
9
+ title: string;
10
+ }
11
+ export declare const PsDetailPane: ({ children, className, footer, footerStart, headerActions, subtitle, title, }: PsDetailPaneProps) => import("react").JSX.Element;
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PsDetailPane = void 0;
4
+ const jsx_runtime_1 = require("react/jsx-runtime");
5
+ const ps_design_system_1 = require("@pallasoft/ps-design-system");
6
+ const PsDetailPane = ({ children, className, footer, footerStart, headerActions, subtitle, title, }) => ((0, jsx_runtime_1.jsxs)("section", { "aria-label": title, className: ps_design_system_1.PallasoftClassNameService.merge('ps-card flex h-full min-h-0 min-w-0 flex-col overflow-hidden rounded-ps-card', className), children: [(0, jsx_runtime_1.jsxs)("header", { className: 'flex shrink-0 items-start justify-between gap-3 border-b border-line/80 px-4 py-3.5 sm:px-5', children: [(0, jsx_runtime_1.jsxs)("div", { className: 'flex min-w-0 flex-col gap-0.5', children: [(0, jsx_runtime_1.jsx)("h2", { className: 'truncate text-lg font-semibold leading-tight text-ink', children: title }), subtitle ? (0, jsx_runtime_1.jsx)("p", { className: 'truncate text-xs text-ink/55', children: subtitle }) : null] }), headerActions ? ((0, jsx_runtime_1.jsx)("div", { className: 'flex shrink-0 items-center gap-2', children: headerActions })) : null] }), (0, jsx_runtime_1.jsx)("div", { className: 'ps-scrollbar-hidden min-h-0 flex-1 overflow-y-auto px-4 py-4 sm:px-5', children: children }), footer || footerStart ? ((0, jsx_runtime_1.jsxs)("footer", { className: 'flex shrink-0 flex-wrap items-center justify-between gap-2 border-t border-line/80 px-4 py-3 sm:px-5', children: [footerStart ? (0, jsx_runtime_1.jsx)("div", { className: 'flex min-w-0 items-center gap-2', children: footerStart }) : null, (0, jsx_runtime_1.jsx)("div", { className: 'ml-auto flex flex-wrap items-center justify-end gap-2', children: footer })] })) : null] }));
7
+ exports.PsDetailPane = PsDetailPane;
@@ -5,6 +5,7 @@ export interface PsDocumentRowProps {
5
5
  badges?: ReactNode;
6
6
  className?: string;
7
7
  date?: string;
8
+ isActive?: boolean;
8
9
  isSelected?: boolean;
9
10
  note?: ReactNode;
10
11
  onOpen?: () => void;
@@ -16,4 +17,4 @@ export interface PsDocumentRowProps {
16
17
  thumbnailSrc?: string | null;
17
18
  title: string;
18
19
  }
19
- export declare const PsDocumentRow: ({ actions, amount, badges, className, date, isSelected, note, onOpen, onPrefetch, select, subtitle, thumbnailAlt, thumbnailFallback, thumbnailSrc, title, }: PsDocumentRowProps) => import("react").JSX.Element;
20
+ export declare const PsDocumentRow: ({ actions, amount, badges, className, date, isActive, isSelected, note, onOpen, onPrefetch, select, subtitle, thumbnailAlt, thumbnailFallback, thumbnailSrc, title, }: PsDocumentRowProps) => import("react").JSX.Element;
@@ -3,14 +3,19 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.PsDocumentRow = void 0;
4
4
  const jsx_runtime_1 = require("react/jsx-runtime");
5
5
  const ps_design_system_1 = require("@pallasoft/ps-design-system");
6
- const PsDocumentRow = ({ actions, amount, badges, className, date, isSelected = false, note, onOpen, onPrefetch, select, subtitle, thumbnailAlt = '', thumbnailFallback, thumbnailSrc, title, }) => {
6
+ const PsDocumentRow = ({ actions, amount, badges, className, date, isActive = false, isSelected = false, note, onOpen, onPrefetch, select, subtitle, thumbnailAlt = '', thumbnailFallback, thumbnailSrc, title, }) => {
7
7
  const Main = onOpen ? 'button' : 'div';
8
- return ((0, jsx_runtime_1.jsxs)("div", { className: ps_design_system_1.PallasoftClassNameService.merge('flex min-w-0 flex-wrap items-center gap-x-3 gap-y-2 border-b border-line/70 px-3 py-3 transition-colors last:border-b-0 sm:flex-nowrap', isSelected ? 'bg-primary/5' : 'hover:bg-mist/40', className), children: [select ? (0, jsx_runtime_1.jsx)("span", { className: 'flex shrink-0 items-center', children: select }) : null, (0, jsx_runtime_1.jsxs)(Main, { className: 'ps-focus-ring grid min-w-0 flex-1 basis-0 grid-cols-[auto_minmax(0,1fr)] items-center gap-x-3 gap-y-1 rounded-ps-control text-left sm:grid-cols-[auto_minmax(0,1fr)_auto]', ...(onOpen
8
+ return ((0, jsx_runtime_1.jsxs)("div", { className: ps_design_system_1.PallasoftClassNameService.merge('flex min-w-0 flex-wrap items-center gap-x-3 gap-y-2 border-b border-line/70 px-3 py-3 transition-colors last:border-b-0 sm:flex-nowrap', isActive
9
+ ? 'bg-primary/8 shadow-[inset_3px_0_0_rgb(var(--ps-color-primary-rgb))]'
10
+ : isSelected
11
+ ? 'bg-primary/5'
12
+ : 'hover:bg-mist/40', className), children: [select ? (0, jsx_runtime_1.jsx)("span", { className: 'flex shrink-0 items-center', children: select }) : null, (0, jsx_runtime_1.jsxs)(Main, { className: 'ps-focus-ring grid min-w-0 flex-1 basis-0 grid-cols-[auto_minmax(0,1fr)] items-center gap-x-3 gap-y-1 rounded-ps-control text-left sm:grid-cols-[auto_minmax(0,1fr)_auto]', ...(onOpen
9
13
  ? {
10
- onClick: onOpen,
11
- onFocus: onPrefetch,
12
- onPointerEnter: onPrefetch,
13
- type: 'button',
14
+ 'aria-current': isActive ? 'true' : undefined,
15
+ 'onClick': onOpen,
16
+ 'onFocus': onPrefetch,
17
+ 'onPointerEnter': onPrefetch,
18
+ 'type': 'button',
14
19
  }
15
20
  : {}), children: [(0, jsx_runtime_1.jsx)("span", { className: 'row-span-2 flex h-14 w-11 shrink-0 items-center justify-center overflow-hidden rounded-ps-control border border-line/60 bg-mist/40 sm:row-span-1', children: thumbnailSrc ? ((0, jsx_runtime_1.jsx)("img", { alt: thumbnailAlt, className: 'h-full w-full object-cover object-top', decoding: 'async', loading: 'lazy', src: thumbnailSrc })) : (thumbnailFallback) }), (0, jsx_runtime_1.jsxs)("span", { className: 'flex min-w-0 flex-col gap-0.5', children: [(0, jsx_runtime_1.jsx)("span", { className: 'truncate text-sm font-semibold text-ink', children: title }), subtitle ? (0, jsx_runtime_1.jsx)("span", { className: 'truncate text-xs text-ink/55', children: subtitle }) : null, badges ? ((0, jsx_runtime_1.jsx)("span", { className: 'flex flex-wrap items-center gap-1.5 pt-1', children: badges })) : null, note ? ((0, jsx_runtime_1.jsx)("span", { className: 'line-clamp-2 break-words pt-0.5 text-xs text-ink/70', children: note })) : null] }), amount || date ? ((0, jsx_runtime_1.jsxs)("span", { className: 'col-start-2 flex items-baseline gap-2 sm:col-start-3 sm:flex-col sm:items-end sm:gap-0.5', children: [amount ? ((0, jsx_runtime_1.jsx)("span", { className: 'text-sm font-semibold tabular-nums text-ink', children: amount })) : null, date ? (0, jsx_runtime_1.jsx)("span", { className: 'text-xs tabular-nums text-ink/55', children: date }) : null] })) : null] }), actions ? ((0, jsx_runtime_1.jsx)("div", { className: 'flex w-full shrink-0 items-center justify-end gap-2 sm:w-auto', children: actions })) : null] }));
16
21
  };
@@ -1,10 +1,13 @@
1
+ import type { ElementType } from 'react';
1
2
  export interface PsFormFooterProps {
2
3
  isSaving: boolean;
3
4
  isSecondaryVisible?: boolean;
4
5
  isSubmitDisabled: boolean;
5
- onSecondary: () => void;
6
+ LinkComponent?: ElementType;
7
+ onSecondary?: () => void;
6
8
  savingLabel: string;
9
+ secondaryHref?: string;
7
10
  secondaryLabel: string;
8
11
  submitLabel: string;
9
12
  }
10
- export declare const PsFormFooter: ({ isSaving, isSecondaryVisible, isSubmitDisabled, onSecondary, savingLabel, secondaryLabel, submitLabel, }: PsFormFooterProps) => import("react").JSX.Element;
13
+ export declare const PsFormFooter: ({ isSaving, isSecondaryVisible, isSubmitDisabled, LinkComponent, onSecondary, savingLabel, secondaryHref, secondaryLabel, submitLabel, }: PsFormFooterProps) => import("react").JSX.Element;
@@ -3,5 +3,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.PsFormFooter = void 0;
4
4
  const jsx_runtime_1 = require("react/jsx-runtime");
5
5
  const ps_button_1 = require("./ps-button");
6
- const PsFormFooter = ({ isSaving, isSecondaryVisible = true, isSubmitDisabled, onSecondary, savingLabel, secondaryLabel, submitLabel, }) => ((0, jsx_runtime_1.jsxs)("div", { className: 'sticky bottom-0 z-docked -mx-4 flex justify-end gap-2 border-t border-line bg-surface/90 px-4 py-3 backdrop-blur sm:bottom-4 sm:mx-0 sm:border-0 sm:bg-transparent sm:px-0 sm:py-0 sm:backdrop-blur-none', children: [isSecondaryVisible ? ((0, jsx_runtime_1.jsx)(ps_button_1.PsButton, { disabled: isSaving, onClick: onSecondary, type: 'button', variant: 'surface', children: secondaryLabel })) : null, (0, jsx_runtime_1.jsx)(ps_button_1.PsButton, { disabled: isSubmitDisabled || isSaving, isLoading: isSaving, loadingLabel: savingLabel, type: 'submit', variant: 'primary', children: submitLabel })] }));
6
+ const ps_link_button_1 = require("./ps-link-button");
7
+ const PsFormFooter = ({ isSaving, isSecondaryVisible = true, isSubmitDisabled, LinkComponent, onSecondary, savingLabel, secondaryHref, secondaryLabel, submitLabel, }) => ((0, jsx_runtime_1.jsxs)("div", { className: 'sticky bottom-0 z-docked -mx-4 flex justify-end gap-2 border-t border-line bg-surface/90 px-4 py-3 backdrop-blur sm:bottom-4 sm:mx-0 sm:border-0 sm:bg-transparent sm:px-0 sm:py-0 sm:backdrop-blur-none', children: [!isSecondaryVisible ? null : secondaryHref === undefined ? ((0, jsx_runtime_1.jsx)(ps_button_1.PsButton, { disabled: isSaving, onClick: onSecondary, type: 'button', variant: 'surface', children: secondaryLabel })) : ((0, jsx_runtime_1.jsx)(ps_link_button_1.PsLinkButton, { href: secondaryHref, LinkComponent: LinkComponent, variant: 'surface', children: secondaryLabel })), (0, jsx_runtime_1.jsx)(ps_button_1.PsButton, { disabled: isSubmitDisabled || isSaving, isLoading: isSaving, loadingLabel: savingLabel, type: 'submit', variant: 'primary', children: submitLabel })] }));
7
8
  exports.PsFormFooter = PsFormFooter;
@@ -0,0 +1,6 @@
1
+ import type { ReactNode } from 'react';
2
+ export interface PsSplitViewProps {
3
+ detail: ReactNode;
4
+ list: ReactNode;
5
+ }
6
+ export declare const PsSplitView: ({ detail, list }: PsSplitViewProps) => import("react").JSX.Element;
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PsSplitView = void 0;
4
+ const jsx_runtime_1 = require("react/jsx-runtime");
5
+ const use_ps_fill_height_1 = require("../hooks/use-ps-fill-height");
6
+ const PsSplitView = ({ detail, list }) => {
7
+ const isSplit = detail !== null && detail !== undefined && detail !== false;
8
+ const { height, ref } = (0, use_ps_fill_height_1.usePsFillHeight)(isSplit);
9
+ if (!isSplit)
10
+ return (0, jsx_runtime_1.jsx)("div", { className: 'min-w-0', children: list });
11
+ return ((0, jsx_runtime_1.jsxs)("div", { className: 'min-w-0 xl:grid xl:h-[var(--ps-split-height,calc(100dvh-14rem))] xl:grid-cols-[minmax(0,1fr)_minmax(26rem,34rem)] xl:gap-4', ref: ref, style: height === null ? undefined : { '--ps-split-height': `${height}px` }, children: [(0, jsx_runtime_1.jsx)("div", { className: 'ps-scrollbar-hidden min-h-0 min-w-0 xl:overflow-y-auto', children: list }), (0, jsx_runtime_1.jsx)("div", { className: 'hidden min-h-0 min-w-0 xl:block', children: detail })] }));
12
+ };
13
+ exports.PsSplitView = PsSplitView;
@@ -0,0 +1,12 @@
1
+ import type { ElementType, ReactNode } from 'react';
2
+ export interface PsTextLinkProps {
3
+ 'aria-label'?: string;
4
+ 'children': ReactNode;
5
+ 'className'?: string;
6
+ 'href'?: string;
7
+ 'id'?: string;
8
+ 'LinkComponent'?: ElementType;
9
+ 'onClick'?: () => void;
10
+ 'size'?: 'compact' | 'default';
11
+ }
12
+ export declare const PsTextLink: ({ children, className, href, LinkComponent, onClick, size, ...props }: PsTextLinkProps) => import("react").JSX.Element;
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PsTextLink = void 0;
4
+ const jsx_runtime_1 = require("react/jsx-runtime");
5
+ const ps_design_system_1 = require("@pallasoft/ps-design-system");
6
+ const ps_text_link_classes_1 = require("../constants/ps-text-link-classes");
7
+ const PsTextLink = ({ children, className, href, LinkComponent, onClick, size = 'default', ...props }) => {
8
+ const linkClassName = ps_design_system_1.PallasoftClassNameService.merge(ps_text_link_classes_1.PsTextLinkClassName, ps_text_link_classes_1.PsTextLinkSizeClassNames[size], className);
9
+ if (href === undefined)
10
+ return ((0, jsx_runtime_1.jsx)("button", { className: linkClassName, onClick: onClick, type: 'button', ...props, children: children }));
11
+ return LinkComponent ? ((0, jsx_runtime_1.jsx)(LinkComponent, { className: linkClassName, onClick: onClick, prefetch: 'intent', to: href, ...props, children: children })) : ((0, jsx_runtime_1.jsx)("a", { className: linkClassName, href: href, onClick: onClick, ...props, children: children }));
12
+ };
13
+ exports.PsTextLink = PsTextLink;
@@ -9,14 +9,14 @@ exports.PsButtonSizeClassNames = {
9
9
  };
10
10
  exports.PsButtonVariantClassNames = {
11
11
  danger: 'border-danger bg-danger text-white enabled:hover:opacity-90',
12
- ghost: 'border-transparent bg-transparent text-ink/60 enabled:hover:text-ink',
12
+ ghost: 'ps-liquid ps-liquid-control bg-white/72 text-ink enabled:hover:border-primary/30 dark:border-white/16 dark:bg-white/12',
13
13
  primary: 'border-primary bg-primary text-[color:var(--ps-color-primary-contrast)] enabled:hover:border-primary-dark enabled:hover:bg-primary-dark',
14
14
  secondary: 'ps-liquid ps-liquid-control bg-white/72 text-ink enabled:hover:border-primary/30 enabled:hover:text-primary dark:border-white/16 dark:bg-white/12 dark:enabled:hover:text-white',
15
15
  surface: 'ps-liquid ps-liquid-control bg-white/72 text-ink enabled:hover:border-primary/30 dark:border-white/16 dark:bg-white/12',
16
16
  };
17
17
  exports.PsLinkButtonVariantClassNames = {
18
18
  danger: 'border-danger bg-danger text-white hover:opacity-90',
19
- ghost: 'border-transparent bg-transparent text-ink/60 hover:text-ink',
19
+ ghost: 'ps-liquid ps-liquid-control bg-white/72 text-ink hover:border-primary/30 dark:border-white/16 dark:bg-white/12',
20
20
  primary: 'border-primary bg-primary text-[color:var(--ps-color-primary-contrast)] hover:border-primary-dark hover:bg-primary-dark',
21
21
  secondary: 'ps-liquid ps-liquid-control bg-white/72 text-ink hover:border-primary/30 hover:text-primary dark:border-white/16 dark:bg-white/12 dark:hover:text-white',
22
22
  surface: 'ps-liquid ps-liquid-control bg-white/72 text-ink hover:border-primary/30 dark:border-white/16 dark:bg-white/12',
@@ -0,0 +1,4 @@
1
+ export declare const PsSplitViewConfig: {
2
+ readonly minHeight: 448;
3
+ readonly scrollableOverflow: RegExp;
4
+ };
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PsSplitViewConfig = void 0;
4
+ exports.PsSplitViewConfig = {
5
+ minHeight: 448,
6
+ scrollableOverflow: /(auto|scroll)/,
7
+ };
@@ -0,0 +1,5 @@
1
+ export declare const PsTextLinkClassName = "ps-focus-ring inline-flex max-w-full items-center gap-1 rounded-sm font-semibold text-primary underline-offset-4 transition-colors hover:underline";
2
+ export declare const PsTextLinkSizeClassNames: {
3
+ compact: string;
4
+ default: string;
5
+ };
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PsTextLinkSizeClassNames = exports.PsTextLinkClassName = void 0;
4
+ exports.PsTextLinkClassName = 'ps-focus-ring inline-flex max-w-full items-center gap-1 rounded-sm font-semibold text-primary underline-offset-4 transition-colors hover:underline';
5
+ exports.PsTextLinkSizeClassNames = {
6
+ compact: 'text-xs',
7
+ default: 'text-sm',
8
+ };
@@ -0,0 +1,3 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { PallasoftClassNameService } from '@pallasoft/ps-design-system';
3
+ export const PsActionTileContent = ({ description, icon, label, variant, }) => (_jsxs(_Fragment, { children: [_jsxs("span", { className: 'min-w-0', children: [_jsx("span", { className: 'block break-words', children: label }), description ? (_jsx("span", { className: PallasoftClassNameService.merge('mt-0.5 block text-xs font-medium leading-5', variant === 'primary' ? 'text-white/75' : 'text-ink/50'), children: description })) : null] }), icon ? (_jsx("span", { className: PallasoftClassNameService.merge('flex h-9 w-9 shrink-0 items-center justify-center rounded-lg', variant === 'primary' ? 'bg-white/15 text-white' : 'ps-icon-surface'), children: icon })) : null] }));
@@ -0,0 +1,12 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { PallasoftClassNameService } from '@pallasoft/ps-design-system';
3
+ import { PsActionTileContent } from './ps-action-tile-content.js';
4
+ const variantClassNames = {
5
+ default: 'ps-action-tile',
6
+ primary: 'ps-action-tile ps-action-tile-primary',
7
+ };
8
+ export const PsActionTileLink = ({ className, description, href, icon, label, LinkComponent, variant = 'default', ...props }) => {
9
+ const linkClassName = PallasoftClassNameService.merge('ps-focus-ring w-full', variantClassNames[variant], className);
10
+ const content = (_jsx(PsActionTileContent, { description: description, icon: icon, label: label, variant: variant }));
11
+ return LinkComponent ? (_jsx(LinkComponent, { className: linkClassName, prefetch: 'intent', to: href, ...props, children: content })) : (_jsx("a", { className: linkClassName, href: href, ...props, children: content }));
12
+ };
@@ -1,9 +1,10 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { PallasoftClassNameService } from '@pallasoft/ps-design-system';
3
3
  import { PsSkeletonShape } from '../constants/ps-skeleton-shape.js';
4
+ import { PsActionTileContent } from './ps-action-tile-content.js';
4
5
  import { PsSkeleton } from './ps-skeleton.js';
5
6
  const variantClassNames = {
6
7
  default: 'ps-action-tile',
7
8
  primary: 'ps-action-tile ps-action-tile-primary',
8
9
  };
9
- export const PsActionTile = ({ className, description, icon, isLoading = false, label, type = 'button', variant = 'default', ...props }) => isLoading ? (_jsx(PsSkeleton, { className: PallasoftClassNameService.merge('h-16', className), shape: PsSkeletonShape.Card })) : (_jsxs("button", { className: PallasoftClassNameService.merge('ps-focus-ring w-full', variantClassNames[variant], className), type: type, ...props, children: [_jsxs("span", { className: 'min-w-0', children: [_jsx("span", { className: 'block break-words', children: label }), description ? (_jsx("span", { className: PallasoftClassNameService.merge('mt-0.5 block text-xs font-medium leading-5', variant === 'primary' ? 'text-white/75' : 'text-ink/50'), children: description })) : null] }), icon ? (_jsx("span", { className: PallasoftClassNameService.merge('flex h-9 w-9 shrink-0 items-center justify-center rounded-lg', variant === 'primary' ? 'bg-white/15 text-white' : 'ps-icon-surface'), children: icon })) : null] }));
10
+ export const PsActionTile = ({ className, description, icon, isLoading = false, label, type = 'button', variant = 'default', ...props }) => isLoading ? (_jsx(PsSkeleton, { className: PallasoftClassNameService.merge('h-16', className), shape: PsSkeletonShape.Card })) : (_jsx("button", { className: PallasoftClassNameService.merge('ps-focus-ring w-full', variantClassNames[variant], className), type: type, ...props, children: _jsx(PsActionTileContent, { description: description, icon: icon, label: label, variant: variant }) }));
@@ -1,10 +1,10 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useState } from 'react';
3
3
  import { PsCappedListConfig } from '../constants/ps-capped-list-config.js';
4
- import { PsButton } from './ps-button.js';
4
+ import { PsTextLink } from './ps-text-link.js';
5
5
  export const PsCappedList = ({ getKey, items, renderItem, showAllLabel, visibleRows = PsCappedListConfig.defaultVisibleRows, }) => {
6
6
  const [isExpanded, setIsExpanded] = useState(false);
7
7
  const isCapped = !isExpanded && items.length > visibleRows;
8
8
  const shown = isCapped ? items.slice(0, visibleRows) : items;
9
- return (_jsxs("div", { className: 'flex flex-col gap-2', children: [_jsx("ul", { className: '-my-2 flex flex-col divide-y divide-line', children: shown.map((item) => (_jsx("li", { children: renderItem(item) }, getKey(item)))) }), isCapped ? (_jsx(PsButton, { className: 'self-start', onClick: () => setIsExpanded(true), size: 'compact', variant: 'ghost', children: showAllLabel })) : null] }));
9
+ return (_jsxs("div", { className: 'flex flex-col gap-2', children: [_jsx("ul", { className: '-my-2 flex flex-col divide-y divide-line', children: shown.map((item) => (_jsx("li", { children: renderItem(item) }, getKey(item)))) }), isCapped ? (_jsx(PsTextLink, { className: 'self-start', onClick: () => setIsExpanded(true), size: 'compact', children: showAllLabel })) : null] }));
10
10
  };
@@ -0,0 +1,3 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { PallasoftClassNameService } from '@pallasoft/ps-design-system';
3
+ export const PsDetailPane = ({ children, className, footer, footerStart, headerActions, subtitle, title, }) => (_jsxs("section", { "aria-label": title, className: PallasoftClassNameService.merge('ps-card flex h-full min-h-0 min-w-0 flex-col overflow-hidden rounded-ps-card', className), children: [_jsxs("header", { className: 'flex shrink-0 items-start justify-between gap-3 border-b border-line/80 px-4 py-3.5 sm:px-5', children: [_jsxs("div", { className: 'flex min-w-0 flex-col gap-0.5', children: [_jsx("h2", { className: 'truncate text-lg font-semibold leading-tight text-ink', children: title }), subtitle ? _jsx("p", { className: 'truncate text-xs text-ink/55', children: subtitle }) : null] }), headerActions ? (_jsx("div", { className: 'flex shrink-0 items-center gap-2', children: headerActions })) : null] }), _jsx("div", { className: 'ps-scrollbar-hidden min-h-0 flex-1 overflow-y-auto px-4 py-4 sm:px-5', children: children }), footer || footerStart ? (_jsxs("footer", { className: 'flex shrink-0 flex-wrap items-center justify-between gap-2 border-t border-line/80 px-4 py-3 sm:px-5', children: [footerStart ? _jsx("div", { className: 'flex min-w-0 items-center gap-2', children: footerStart }) : null, _jsx("div", { className: 'ml-auto flex flex-wrap items-center justify-end gap-2', children: footer })] })) : null] }));
@@ -1,13 +1,18 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { PallasoftClassNameService } from '@pallasoft/ps-design-system';
3
- export const PsDocumentRow = ({ actions, amount, badges, className, date, isSelected = false, note, onOpen, onPrefetch, select, subtitle, thumbnailAlt = '', thumbnailFallback, thumbnailSrc, title, }) => {
3
+ export const PsDocumentRow = ({ actions, amount, badges, className, date, isActive = false, isSelected = false, note, onOpen, onPrefetch, select, subtitle, thumbnailAlt = '', thumbnailFallback, thumbnailSrc, title, }) => {
4
4
  const Main = onOpen ? 'button' : 'div';
5
- return (_jsxs("div", { className: PallasoftClassNameService.merge('flex min-w-0 flex-wrap items-center gap-x-3 gap-y-2 border-b border-line/70 px-3 py-3 transition-colors last:border-b-0 sm:flex-nowrap', isSelected ? 'bg-primary/5' : 'hover:bg-mist/40', className), children: [select ? _jsx("span", { className: 'flex shrink-0 items-center', children: select }) : null, _jsxs(Main, { className: 'ps-focus-ring grid min-w-0 flex-1 basis-0 grid-cols-[auto_minmax(0,1fr)] items-center gap-x-3 gap-y-1 rounded-ps-control text-left sm:grid-cols-[auto_minmax(0,1fr)_auto]', ...(onOpen
5
+ return (_jsxs("div", { className: PallasoftClassNameService.merge('flex min-w-0 flex-wrap items-center gap-x-3 gap-y-2 border-b border-line/70 px-3 py-3 transition-colors last:border-b-0 sm:flex-nowrap', isActive
6
+ ? 'bg-primary/8 shadow-[inset_3px_0_0_rgb(var(--ps-color-primary-rgb))]'
7
+ : isSelected
8
+ ? 'bg-primary/5'
9
+ : 'hover:bg-mist/40', className), children: [select ? _jsx("span", { className: 'flex shrink-0 items-center', children: select }) : null, _jsxs(Main, { className: 'ps-focus-ring grid min-w-0 flex-1 basis-0 grid-cols-[auto_minmax(0,1fr)] items-center gap-x-3 gap-y-1 rounded-ps-control text-left sm:grid-cols-[auto_minmax(0,1fr)_auto]', ...(onOpen
6
10
  ? {
7
- onClick: onOpen,
8
- onFocus: onPrefetch,
9
- onPointerEnter: onPrefetch,
10
- type: 'button',
11
+ 'aria-current': isActive ? 'true' : undefined,
12
+ 'onClick': onOpen,
13
+ 'onFocus': onPrefetch,
14
+ 'onPointerEnter': onPrefetch,
15
+ 'type': 'button',
11
16
  }
12
17
  : {}), children: [_jsx("span", { className: 'row-span-2 flex h-14 w-11 shrink-0 items-center justify-center overflow-hidden rounded-ps-control border border-line/60 bg-mist/40 sm:row-span-1', children: thumbnailSrc ? (_jsx("img", { alt: thumbnailAlt, className: 'h-full w-full object-cover object-top', decoding: 'async', loading: 'lazy', src: thumbnailSrc })) : (thumbnailFallback) }), _jsxs("span", { className: 'flex min-w-0 flex-col gap-0.5', children: [_jsx("span", { className: 'truncate text-sm font-semibold text-ink', children: title }), subtitle ? _jsx("span", { className: 'truncate text-xs text-ink/55', children: subtitle }) : null, badges ? (_jsx("span", { className: 'flex flex-wrap items-center gap-1.5 pt-1', children: badges })) : null, note ? (_jsx("span", { className: 'line-clamp-2 break-words pt-0.5 text-xs text-ink/70', children: note })) : null] }), amount || date ? (_jsxs("span", { className: 'col-start-2 flex items-baseline gap-2 sm:col-start-3 sm:flex-col sm:items-end sm:gap-0.5', children: [amount ? (_jsx("span", { className: 'text-sm font-semibold tabular-nums text-ink', children: amount })) : null, date ? _jsx("span", { className: 'text-xs tabular-nums text-ink/55', children: date }) : null] })) : null] }), actions ? (_jsx("div", { className: 'flex w-full shrink-0 items-center justify-end gap-2 sm:w-auto', children: actions })) : null] }));
13
18
  };
@@ -1,3 +1,4 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { PsButton } from './ps-button.js';
3
- export const PsFormFooter = ({ isSaving, isSecondaryVisible = true, isSubmitDisabled, onSecondary, savingLabel, secondaryLabel, submitLabel, }) => (_jsxs("div", { className: 'sticky bottom-0 z-docked -mx-4 flex justify-end gap-2 border-t border-line bg-surface/90 px-4 py-3 backdrop-blur sm:bottom-4 sm:mx-0 sm:border-0 sm:bg-transparent sm:px-0 sm:py-0 sm:backdrop-blur-none', children: [isSecondaryVisible ? (_jsx(PsButton, { disabled: isSaving, onClick: onSecondary, type: 'button', variant: 'surface', children: secondaryLabel })) : null, _jsx(PsButton, { disabled: isSubmitDisabled || isSaving, isLoading: isSaving, loadingLabel: savingLabel, type: 'submit', variant: 'primary', children: submitLabel })] }));
3
+ import { PsLinkButton } from './ps-link-button.js';
4
+ export const PsFormFooter = ({ isSaving, isSecondaryVisible = true, isSubmitDisabled, LinkComponent, onSecondary, savingLabel, secondaryHref, secondaryLabel, submitLabel, }) => (_jsxs("div", { className: 'sticky bottom-0 z-docked -mx-4 flex justify-end gap-2 border-t border-line bg-surface/90 px-4 py-3 backdrop-blur sm:bottom-4 sm:mx-0 sm:border-0 sm:bg-transparent sm:px-0 sm:py-0 sm:backdrop-blur-none', children: [!isSecondaryVisible ? null : secondaryHref === undefined ? (_jsx(PsButton, { disabled: isSaving, onClick: onSecondary, type: 'button', variant: 'surface', children: secondaryLabel })) : (_jsx(PsLinkButton, { href: secondaryHref, LinkComponent: LinkComponent, variant: 'surface', children: secondaryLabel })), _jsx(PsButton, { disabled: isSubmitDisabled || isSaving, isLoading: isSaving, loadingLabel: savingLabel, type: 'submit', variant: 'primary', children: submitLabel })] }));
@@ -0,0 +1,9 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { usePsFillHeight } from '../hooks/use-ps-fill-height.js';
3
+ export const PsSplitView = ({ detail, list }) => {
4
+ const isSplit = detail !== null && detail !== undefined && detail !== false;
5
+ const { height, ref } = usePsFillHeight(isSplit);
6
+ if (!isSplit)
7
+ return _jsx("div", { className: 'min-w-0', children: list });
8
+ return (_jsxs("div", { className: 'min-w-0 xl:grid xl:h-[var(--ps-split-height,calc(100dvh-14rem))] xl:grid-cols-[minmax(0,1fr)_minmax(26rem,34rem)] xl:gap-4', ref: ref, style: height === null ? undefined : { '--ps-split-height': `${height}px` }, children: [_jsx("div", { className: 'ps-scrollbar-hidden min-h-0 min-w-0 xl:overflow-y-auto', children: list }), _jsx("div", { className: 'hidden min-h-0 min-w-0 xl:block', children: detail })] }));
9
+ };
@@ -0,0 +1,9 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { PallasoftClassNameService } from '@pallasoft/ps-design-system';
3
+ import { PsTextLinkClassName, PsTextLinkSizeClassNames } from '../constants/ps-text-link-classes.js';
4
+ export const PsTextLink = ({ children, className, href, LinkComponent, onClick, size = 'default', ...props }) => {
5
+ const linkClassName = PallasoftClassNameService.merge(PsTextLinkClassName, PsTextLinkSizeClassNames[size], className);
6
+ if (href === undefined)
7
+ return (_jsx("button", { className: linkClassName, onClick: onClick, type: 'button', ...props, children: children }));
8
+ return LinkComponent ? (_jsx(LinkComponent, { className: linkClassName, onClick: onClick, prefetch: 'intent', to: href, ...props, children: children })) : (_jsx("a", { className: linkClassName, href: href, onClick: onClick, ...props, children: children }));
9
+ };
@@ -6,14 +6,14 @@ export const PsButtonSizeClassNames = {
6
6
  };
7
7
  export const PsButtonVariantClassNames = {
8
8
  danger: 'border-danger bg-danger text-white enabled:hover:opacity-90',
9
- ghost: 'border-transparent bg-transparent text-ink/60 enabled:hover:text-ink',
9
+ ghost: 'ps-liquid ps-liquid-control bg-white/72 text-ink enabled:hover:border-primary/30 dark:border-white/16 dark:bg-white/12',
10
10
  primary: 'border-primary bg-primary text-[color:var(--ps-color-primary-contrast)] enabled:hover:border-primary-dark enabled:hover:bg-primary-dark',
11
11
  secondary: 'ps-liquid ps-liquid-control bg-white/72 text-ink enabled:hover:border-primary/30 enabled:hover:text-primary dark:border-white/16 dark:bg-white/12 dark:enabled:hover:text-white',
12
12
  surface: 'ps-liquid ps-liquid-control bg-white/72 text-ink enabled:hover:border-primary/30 dark:border-white/16 dark:bg-white/12',
13
13
  };
14
14
  export const PsLinkButtonVariantClassNames = {
15
15
  danger: 'border-danger bg-danger text-white hover:opacity-90',
16
- ghost: 'border-transparent bg-transparent text-ink/60 hover:text-ink',
16
+ ghost: 'ps-liquid ps-liquid-control bg-white/72 text-ink hover:border-primary/30 dark:border-white/16 dark:bg-white/12',
17
17
  primary: 'border-primary bg-primary text-[color:var(--ps-color-primary-contrast)] hover:border-primary-dark hover:bg-primary-dark',
18
18
  secondary: 'ps-liquid ps-liquid-control bg-white/72 text-ink hover:border-primary/30 hover:text-primary dark:border-white/16 dark:bg-white/12 dark:hover:text-white',
19
19
  surface: 'ps-liquid ps-liquid-control bg-white/72 text-ink hover:border-primary/30 dark:border-white/16 dark:bg-white/12',
@@ -0,0 +1,4 @@
1
+ export const PsSplitViewConfig = {
2
+ minHeight: 448,
3
+ scrollableOverflow: /(auto|scroll)/,
4
+ };
@@ -0,0 +1,5 @@
1
+ export const PsTextLinkClassName = 'ps-focus-ring inline-flex max-w-full items-center gap-1 rounded-sm font-semibold text-primary underline-offset-4 transition-colors hover:underline';
2
+ export const PsTextLinkSizeClassNames = {
3
+ compact: 'text-xs',
4
+ default: 'text-sm',
5
+ };
@@ -0,0 +1,20 @@
1
+ import { useLayoutEffect, useRef, useState } from 'react';
2
+ import { PsFillHeightService } from '../services/ps-fill-height-service.js';
3
+ export const usePsFillHeight = (isActive) => {
4
+ const ref = useRef(null);
5
+ const [height, setHeight] = useState(null);
6
+ useLayoutEffect(() => {
7
+ const element = ref.current;
8
+ if (!isActive || element === null)
9
+ return;
10
+ const scroller = PsFillHeightService.scroller(element);
11
+ const measure = () => setHeight(PsFillHeightService.height(element, scroller));
12
+ const observer = new ResizeObserver(measure);
13
+ measure();
14
+ observer.observe(scroller);
15
+ if (element.parentElement !== null)
16
+ observer.observe(element.parentElement);
17
+ return () => observer.disconnect();
18
+ }, [isActive]);
19
+ return { height, ref };
20
+ };
package/dist/esm/index.js CHANGED
@@ -1,11 +1,13 @@
1
1
  export * from './components/ps-layer.js';
2
2
  export * from './components/ps-accordion.js';
3
3
  export * from './components/ps-action-tile.js';
4
+ export * from './components/ps-action-tile-link.js';
4
5
  export * from './components/ps-audio-spectrum.js';
5
6
  export * from './constants/ps-audio-spectrum-config.js';
6
7
  export * from './components/ps-badge.js';
7
8
  export * from './components/ps-button.js';
8
9
  export * from './components/ps-link-button.js';
10
+ export * from './components/ps-text-link.js';
9
11
  export * from './components/ps-pallasoft-mark.js';
10
12
  export * from './components/ps-pallasoft-sign-in-button.js';
11
13
  export * from './components/ps-store-badge.js';
@@ -69,6 +71,7 @@ export * from './hooks/use-ps-element-size.js';
69
71
  export * from './hooks/use-ps-hydrated.js';
70
72
  export * from './hooks/use-ps-viewport.js';
71
73
  export * from './hooks/use-ps-media-query.js';
74
+ export * from './hooks/use-ps-fill-height.js';
72
75
  export * from './interfaces/ps-component-props.js';
73
76
  export * from './models/ps-element-size.js';
74
77
  export * from './models/ps-voice-orb.js';
@@ -153,6 +156,8 @@ export * from './models/ps-theme-mode-state.js';
153
156
  export * from './models/ps-tool-card-data.js';
154
157
  export * from './components/ps-capped-list.js';
155
158
  export * from './components/ps-detail-list.js';
159
+ export * from './components/ps-detail-pane.js';
160
+ export * from './components/ps-split-view.js';
156
161
  export * from './components/ps-overview-card.js';
157
162
  export * from './components/ps-form-footer.js';
158
163
  export * from './components/ps-start-highlight.js';
@@ -0,0 +1,33 @@
1
+ import { PsSplitViewConfig } from '../constants/ps-split-view-config.js';
2
+ export class PsFillHeightService {
3
+ static scroller(element) {
4
+ let parent = element.parentElement;
5
+ while (parent !== null) {
6
+ if (PsSplitViewConfig.scrollableOverflow.test(getComputedStyle(parent).overflowY))
7
+ return parent;
8
+ parent = parent.parentElement;
9
+ }
10
+ return document.documentElement;
11
+ }
12
+ static height(element, scroller) {
13
+ const isPage = scroller === document.documentElement;
14
+ const frameTop = isPage ? 0 : scroller.getBoundingClientRect().top;
15
+ const frameHeight = isPage ? window.innerHeight : scroller.clientHeight;
16
+ const scrolled = isPage ? window.scrollY : scroller.scrollTop;
17
+ const box = element.getBoundingClientRect();
18
+ const top = box.top - frameTop + scrolled;
19
+ const below = PsFillHeightService.below(element, scroller);
20
+ return Math.max(PsSplitViewConfig.minHeight, Math.floor(frameHeight - top - below));
21
+ }
22
+ static below(element, scroller) {
23
+ let node = element;
24
+ let parent = element.parentElement;
25
+ let total = parseFloat(getComputedStyle(scroller).paddingBottom);
26
+ while (parent !== null && parent !== scroller && parent !== document.body) {
27
+ total += Math.max(0, parent.getBoundingClientRect().bottom - node.getBoundingClientRect().bottom);
28
+ node = parent;
29
+ parent = parent.parentElement;
30
+ }
31
+ return total;
32
+ }
33
+ }
@@ -0,0 +1,4 @@
1
+ export declare const usePsFillHeight: <Element extends HTMLElement>(isActive: boolean) => {
2
+ height: number | null;
3
+ ref: import("react").RefObject<Element>;
4
+ };
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.usePsFillHeight = void 0;
4
+ const react_1 = require("react");
5
+ const ps_fill_height_service_1 = require("../services/ps-fill-height-service");
6
+ const usePsFillHeight = (isActive) => {
7
+ const ref = (0, react_1.useRef)(null);
8
+ const [height, setHeight] = (0, react_1.useState)(null);
9
+ (0, react_1.useLayoutEffect)(() => {
10
+ const element = ref.current;
11
+ if (!isActive || element === null)
12
+ return;
13
+ const scroller = ps_fill_height_service_1.PsFillHeightService.scroller(element);
14
+ const measure = () => setHeight(ps_fill_height_service_1.PsFillHeightService.height(element, scroller));
15
+ const observer = new ResizeObserver(measure);
16
+ measure();
17
+ observer.observe(scroller);
18
+ if (element.parentElement !== null)
19
+ observer.observe(element.parentElement);
20
+ return () => observer.disconnect();
21
+ }, [isActive]);
22
+ return { height, ref };
23
+ };
24
+ exports.usePsFillHeight = usePsFillHeight;
package/dist/index.d.ts CHANGED
@@ -1,11 +1,13 @@
1
1
  export * from './components/ps-layer';
2
2
  export * from './components/ps-accordion';
3
3
  export * from './components/ps-action-tile';
4
+ export * from './components/ps-action-tile-link';
4
5
  export * from './components/ps-audio-spectrum';
5
6
  export * from './constants/ps-audio-spectrum-config';
6
7
  export * from './components/ps-badge';
7
8
  export * from './components/ps-button';
8
9
  export * from './components/ps-link-button';
10
+ export * from './components/ps-text-link';
9
11
  export * from './components/ps-pallasoft-mark';
10
12
  export * from './components/ps-pallasoft-sign-in-button';
11
13
  export * from './components/ps-store-badge';
@@ -69,6 +71,7 @@ export * from './hooks/use-ps-element-size';
69
71
  export * from './hooks/use-ps-hydrated';
70
72
  export * from './hooks/use-ps-viewport';
71
73
  export * from './hooks/use-ps-media-query';
74
+ export * from './hooks/use-ps-fill-height';
72
75
  export * from './interfaces/ps-component-props';
73
76
  export * from './models/ps-element-size';
74
77
  export * from './models/ps-voice-orb';
@@ -153,6 +156,8 @@ export * from './models/ps-theme-mode-state';
153
156
  export * from './models/ps-tool-card-data';
154
157
  export * from './components/ps-capped-list';
155
158
  export * from './components/ps-detail-list';
159
+ export * from './components/ps-detail-pane';
160
+ export * from './components/ps-split-view';
156
161
  export * from './components/ps-overview-card';
157
162
  export * from './components/ps-form-footer';
158
163
  export * from './components/ps-start-highlight';
package/dist/index.js CHANGED
@@ -17,11 +17,13 @@ Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("./components/ps-layer"), exports);
18
18
  __exportStar(require("./components/ps-accordion"), exports);
19
19
  __exportStar(require("./components/ps-action-tile"), exports);
20
+ __exportStar(require("./components/ps-action-tile-link"), exports);
20
21
  __exportStar(require("./components/ps-audio-spectrum"), exports);
21
22
  __exportStar(require("./constants/ps-audio-spectrum-config"), exports);
22
23
  __exportStar(require("./components/ps-badge"), exports);
23
24
  __exportStar(require("./components/ps-button"), exports);
24
25
  __exportStar(require("./components/ps-link-button"), exports);
26
+ __exportStar(require("./components/ps-text-link"), exports);
25
27
  __exportStar(require("./components/ps-pallasoft-mark"), exports);
26
28
  __exportStar(require("./components/ps-pallasoft-sign-in-button"), exports);
27
29
  __exportStar(require("./components/ps-store-badge"), exports);
@@ -85,6 +87,7 @@ __exportStar(require("./hooks/use-ps-element-size"), exports);
85
87
  __exportStar(require("./hooks/use-ps-hydrated"), exports);
86
88
  __exportStar(require("./hooks/use-ps-viewport"), exports);
87
89
  __exportStar(require("./hooks/use-ps-media-query"), exports);
90
+ __exportStar(require("./hooks/use-ps-fill-height"), exports);
88
91
  __exportStar(require("./interfaces/ps-component-props"), exports);
89
92
  __exportStar(require("./models/ps-element-size"), exports);
90
93
  __exportStar(require("./models/ps-voice-orb"), exports);
@@ -169,6 +172,8 @@ __exportStar(require("./models/ps-theme-mode-state"), exports);
169
172
  __exportStar(require("./models/ps-tool-card-data"), exports);
170
173
  __exportStar(require("./components/ps-capped-list"), exports);
171
174
  __exportStar(require("./components/ps-detail-list"), exports);
175
+ __exportStar(require("./components/ps-detail-pane"), exports);
176
+ __exportStar(require("./components/ps-split-view"), exports);
172
177
  __exportStar(require("./components/ps-overview-card"), exports);
173
178
  __exportStar(require("./components/ps-form-footer"), exports);
174
179
  __exportStar(require("./components/ps-start-highlight"), exports);
@@ -0,0 +1,5 @@
1
+ export declare class PsFillHeightService {
2
+ static scroller(element: HTMLElement): HTMLElement;
3
+ static height(element: HTMLElement, scroller: HTMLElement): number;
4
+ private static below;
5
+ }
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PsFillHeightService = void 0;
4
+ const ps_split_view_config_1 = require("../constants/ps-split-view-config");
5
+ class PsFillHeightService {
6
+ static scroller(element) {
7
+ let parent = element.parentElement;
8
+ while (parent !== null) {
9
+ if (ps_split_view_config_1.PsSplitViewConfig.scrollableOverflow.test(getComputedStyle(parent).overflowY))
10
+ return parent;
11
+ parent = parent.parentElement;
12
+ }
13
+ return document.documentElement;
14
+ }
15
+ static height(element, scroller) {
16
+ const isPage = scroller === document.documentElement;
17
+ const frameTop = isPage ? 0 : scroller.getBoundingClientRect().top;
18
+ const frameHeight = isPage ? window.innerHeight : scroller.clientHeight;
19
+ const scrolled = isPage ? window.scrollY : scroller.scrollTop;
20
+ const box = element.getBoundingClientRect();
21
+ const top = box.top - frameTop + scrolled;
22
+ const below = PsFillHeightService.below(element, scroller);
23
+ return Math.max(ps_split_view_config_1.PsSplitViewConfig.minHeight, Math.floor(frameHeight - top - below));
24
+ }
25
+ static below(element, scroller) {
26
+ let node = element;
27
+ let parent = element.parentElement;
28
+ let total = parseFloat(getComputedStyle(scroller).paddingBottom);
29
+ while (parent !== null && parent !== scroller && parent !== document.body) {
30
+ total += Math.max(0, parent.getBoundingClientRect().bottom - node.getBoundingClientRect().bottom);
31
+ node = parent;
32
+ parent = parent.parentElement;
33
+ }
34
+ return total;
35
+ }
36
+ }
37
+ exports.PsFillHeightService = PsFillHeightService;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pallasoft/ps-core-components",
3
- "version": "2.36.0",
3
+ "version": "2.38.0",
4
4
  "private": false,
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/esm/index.js",