@pallasoft/ps-core-components 2.47.1 → 2.49.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 (32) hide show
  1. package/dist/components/ps-form-page-skeleton.d.ts +5 -1
  2. package/dist/components/ps-form-page-skeleton.js +1 -1
  3. package/dist/components/ps-link-preview-card.d.ts +15 -0
  4. package/dist/components/ps-link-preview-card.js +34 -0
  5. package/dist/components/ps-metric-grid-skeleton.js +5 -1
  6. package/dist/components/ps-page-header.d.ts +2 -1
  7. package/dist/components/ps-page-header.js +1 -1
  8. package/dist/components/ps-page-skeleton.d.ts +2 -1
  9. package/dist/components/ps-page-skeleton.js +4 -1
  10. package/dist/components/ps-section-header.js +1 -1
  11. package/dist/components/ps-section-panel-skeleton.d.ts +2 -1
  12. package/dist/components/ps-section-panel-skeleton.js +4 -1
  13. package/dist/constants/ps-link-preview-config.d.ts +20 -0
  14. package/dist/constants/ps-link-preview-config.js +23 -0
  15. package/dist/constants/ps-link-preview-size.d.ts +4 -0
  16. package/dist/constants/ps-link-preview-size.js +8 -0
  17. package/dist/esm/components/ps-form-page-skeleton.js +1 -1
  18. package/dist/esm/components/ps-link-preview-card.js +30 -0
  19. package/dist/esm/components/ps-metric-grid-skeleton.js +5 -1
  20. package/dist/esm/components/ps-page-header.js +1 -1
  21. package/dist/esm/components/ps-page-skeleton.js +4 -1
  22. package/dist/esm/components/ps-section-header.js +1 -1
  23. package/dist/esm/components/ps-section-panel-skeleton.js +4 -1
  24. package/dist/esm/constants/ps-link-preview-config.js +20 -0
  25. package/dist/esm/constants/ps-link-preview-size.js +5 -0
  26. package/dist/esm/index.js +4 -0
  27. package/dist/esm/services/ps-link-preview-service.js +19 -0
  28. package/dist/index.d.ts +4 -0
  29. package/dist/index.js +4 -0
  30. package/dist/services/ps-link-preview-service.d.ts +4 -0
  31. package/dist/services/ps-link-preview-service.js +23 -0
  32. package/package.json +2 -2
@@ -1,5 +1,9 @@
1
1
  export interface PsFormPageSkeletonProps {
2
+ hasActions?: boolean;
3
+ hasBackLink?: boolean;
4
+ isNarrow?: boolean;
2
5
  loadingLabel: string;
3
6
  title?: string;
7
+ variant?: 'bordered' | 'card' | 'plain';
4
8
  }
5
- export declare const PsFormPageSkeleton: ({ loadingLabel, title }: PsFormPageSkeletonProps) => import("react").JSX.Element;
9
+ export declare const PsFormPageSkeleton: ({ hasActions, hasBackLink, isNarrow, loadingLabel, title, variant, }: PsFormPageSkeletonProps) => import("react").JSX.Element;
@@ -6,5 +6,5 @@ const ps_page_skeleton_config_1 = require("../constants/ps-page-skeleton-config"
6
6
  const ps_form_fields_skeleton_1 = require("./ps-form-fields-skeleton");
7
7
  const ps_page_skeleton_1 = require("./ps-page-skeleton");
8
8
  const ps_section_panel_skeleton_1 = require("./ps-section-panel-skeleton");
9
- const PsFormPageSkeleton = ({ loadingLabel, title }) => ((0, jsx_runtime_1.jsx)(ps_page_skeleton_1.PsPageSkeleton, { hasActions: true, loadingLabel: loadingLabel, title: title, children: ps_page_skeleton_config_1.PsPageSkeletonConfig.formSections.map((section) => ((0, jsx_runtime_1.jsx)(ps_section_panel_skeleton_1.PsSectionPanelSkeleton, { children: (0, jsx_runtime_1.jsx)(ps_form_fields_skeleton_1.PsFormFieldsSkeleton, {}) }, section))) }));
9
+ const PsFormPageSkeleton = ({ hasActions = true, hasBackLink = false, isNarrow = false, loadingLabel, title, variant = 'plain', }) => ((0, jsx_runtime_1.jsx)(ps_page_skeleton_1.PsPageSkeleton, { hasActions: hasActions, hasBackLink: hasBackLink, isNarrow: isNarrow, loadingLabel: loadingLabel, title: title, children: ps_page_skeleton_config_1.PsPageSkeletonConfig.formSections.map((section) => ((0, jsx_runtime_1.jsx)(ps_section_panel_skeleton_1.PsSectionPanelSkeleton, { variant: variant, children: (0, jsx_runtime_1.jsx)(ps_form_fields_skeleton_1.PsFormFieldsSkeleton, {}) }, section))) }));
10
10
  exports.PsFormPageSkeleton = PsFormPageSkeleton;
@@ -0,0 +1,15 @@
1
+ import { PsLinkPreviewSize } from '../constants/ps-link-preview-size';
2
+ export interface PsLinkPreviewCardProps {
3
+ className?: string;
4
+ description?: string | null;
5
+ faviconSrc?: string | null;
6
+ href: string;
7
+ imageSrc?: string | null;
8
+ isLoading?: boolean;
9
+ loadingLabel?: string;
10
+ opensInNewTabLabel?: string;
11
+ siteName?: string | null;
12
+ size?: PsLinkPreviewSize | 'compact' | 'full';
13
+ title?: string | null;
14
+ }
15
+ export declare const PsLinkPreviewCard: ({ className, description, faviconSrc, href, imageSrc, isLoading, loadingLabel, opensInNewTabLabel, siteName, size, title, }: PsLinkPreviewCardProps) => import("react").JSX.Element | null;
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PsLinkPreviewCard = 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_icons_1 = require("@pallasoft/ps-icons");
7
+ const ps_link_preview_config_1 = require("../constants/ps-link-preview-config");
8
+ const ps_link_preview_size_1 = require("../constants/ps-link-preview-size");
9
+ const ps_skeleton_shape_1 = require("../constants/ps-skeleton-shape");
10
+ const ps_link_preview_service_1 = require("../services/ps-link-preview-service");
11
+ const ps_image_1 = require("./ps-image");
12
+ const ps_skeleton_1 = require("./ps-skeleton");
13
+ const ps_skeleton_group_1 = require("./ps-skeleton-group");
14
+ const PsLinkPreviewCard = ({ className, description, faviconSrc, href, imageSrc, isLoading = false, loadingLabel, opensInNewTabLabel, siteName, size = ps_link_preview_size_1.PsLinkPreviewSize.Full, title, }) => {
15
+ const isCompact = size === ps_link_preview_size_1.PsLinkPreviewSize.Compact;
16
+ const domain = ps_link_preview_service_1.PsLinkPreviewService.domain(href);
17
+ const hasTitle = title !== null && title !== undefined && title.trim() !== '';
18
+ const hasSite = siteName !== null && siteName !== undefined && siteName.trim() !== '';
19
+ const hasDescription = description !== null && description !== undefined && description.trim() !== '';
20
+ const hasImage = imageSrc !== null && imageSrc !== undefined && imageSrc !== '';
21
+ const hasFavicon = faviconSrc !== null && faviconSrc !== undefined && faviconSrc !== '';
22
+ if (!ps_link_preview_service_1.PsLinkPreviewService.isWebAddress(href))
23
+ return null;
24
+ if (isLoading)
25
+ return ((0, jsx_runtime_1.jsxs)(ps_skeleton_group_1.PsSkeletonGroup, { className: ps_design_system_1.PallasoftClassNameService.merge('ps-card min-w-0 overflow-hidden rounded-ps-card', className), direction: isCompact ? 'row' : 'column', gap: 'gap-0', label: loadingLabel, children: [isCompact ? ((0, jsx_runtime_1.jsx)(ps_skeleton_1.PsSkeleton, { className: 'h-20 w-24 shrink-0', shape: ps_skeleton_shape_1.PsSkeletonShape.Block, radius: '0' })) : ((0, jsx_runtime_1.jsx)(ps_skeleton_1.PsSkeleton, { aspect: '1.91 / 1', className: 'w-full', shape: ps_skeleton_shape_1.PsSkeletonShape.Block, radius: '0' })), (0, jsx_runtime_1.jsxs)("span", { className: isCompact ? 'flex flex-1 flex-col gap-2 p-3' : 'flex flex-col gap-2 p-4', children: [(0, jsx_runtime_1.jsx)(ps_skeleton_1.PsSkeleton, { className: 'h-3 w-24' }), (0, jsx_runtime_1.jsx)(ps_skeleton_1.PsSkeleton, { className: 'h-4 w-3/4' }), isCompact ? null : (0, jsx_runtime_1.jsx)(ps_skeleton_1.PsSkeleton, { className: 'h-3 w-full' })] })] }));
26
+ const favicon = hasFavicon ? ((0, jsx_runtime_1.jsx)(ps_image_1.PsImage, { alt: '', className: ps_link_preview_config_1.PsLinkPreviewConfig.faviconClassName, errorFallback: (0, jsx_runtime_1.jsx)(ps_icons_1.PsIcon, { className: ps_link_preview_config_1.PsLinkPreviewConfig.globeIconClassName, iconKey: ps_icons_1.PsIconKey.Globe }), height: 16, loading: 'lazy', src: faviconSrc, width: 16 })) : ((0, jsx_runtime_1.jsx)(ps_icons_1.PsIcon, { className: ps_link_preview_config_1.PsLinkPreviewConfig.globeIconClassName, iconKey: ps_icons_1.PsIconKey.Globe }));
27
+ const meta = ((0, jsx_runtime_1.jsxs)("span", { className: ps_link_preview_config_1.PsLinkPreviewConfig.metaRowClassName, children: [favicon, (0, jsx_runtime_1.jsx)("span", { className: ps_link_preview_config_1.PsLinkPreviewConfig.siteClassName, children: hasSite ? siteName : domain }), (0, jsx_runtime_1.jsx)(ps_icons_1.PsIcon, { className: ps_link_preview_config_1.PsLinkPreviewConfig.externalIconClassName, iconKey: ps_icons_1.PsIconKey.ExternalLink })] }));
28
+ const text = ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [meta, hasTitle ? ((0, jsx_runtime_1.jsx)("span", { className: ps_link_preview_config_1.PsLinkPreviewConfig.titleClassName, children: title })) : ((0, jsx_runtime_1.jsx)("span", { className: ps_link_preview_config_1.PsLinkPreviewConfig.urlClassName, children: href })), hasDescription && !isCompact ? ((0, jsx_runtime_1.jsx)("span", { className: ps_link_preview_config_1.PsLinkPreviewConfig.descriptionClassName, children: description })) : null, opensInNewTabLabel === undefined ? null : ((0, jsx_runtime_1.jsx)("span", { className: 'sr-only', children: opensInNewTabLabel }))] }));
29
+ const media = hasImage ? ((0, jsx_runtime_1.jsx)(ps_image_1.PsImage, { alt: '', className: isCompact
30
+ ? ps_link_preview_config_1.PsLinkPreviewConfig.compactImageClassName
31
+ : ps_link_preview_config_1.PsLinkPreviewConfig.fullImageClassName, errorFallback: null, loading: 'lazy', src: imageSrc })) : null;
32
+ return ((0, jsx_runtime_1.jsx)("a", { className: ps_design_system_1.PallasoftClassNameService.merge(ps_link_preview_config_1.PsLinkPreviewConfig.anchorClassName, className), href: href, rel: ps_link_preview_config_1.PsLinkPreviewConfig.rel, target: ps_link_preview_config_1.PsLinkPreviewConfig.target, children: isCompact ? ((0, jsx_runtime_1.jsxs)("span", { className: ps_link_preview_config_1.PsLinkPreviewConfig.compactRowClassName, children: [media === null ? null : ((0, jsx_runtime_1.jsx)("span", { className: ps_link_preview_config_1.PsLinkPreviewConfig.compactMediaClassName, children: media })), (0, jsx_runtime_1.jsx)("span", { className: ps_link_preview_config_1.PsLinkPreviewConfig.compactBodyClassName, children: text })] })) : ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [media === null ? null : ((0, jsx_runtime_1.jsx)("span", { className: ps_link_preview_config_1.PsLinkPreviewConfig.fullMediaClassName, children: media })), (0, jsx_runtime_1.jsx)("span", { className: ps_link_preview_config_1.PsLinkPreviewConfig.fullBodyClassName, children: text })] })) }));
33
+ };
34
+ exports.PsLinkPreviewCard = PsLinkPreviewCard;
@@ -2,6 +2,10 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.PsMetricGridSkeleton = void 0;
4
4
  const jsx_runtime_1 = require("react/jsx-runtime");
5
+ const ps_metric_grid_config_1 = require("../constants/ps-metric-grid-config");
5
6
  const ps_metric_card_1 = require("./ps-metric-card");
6
- const PsMetricGridSkeleton = ({ count }) => ((0, jsx_runtime_1.jsx)("div", { className: 'grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-4', children: Array.from({ length: count }, (_, index) => ((0, jsx_runtime_1.jsx)(ps_metric_card_1.PsMetricCard, { isLoading: true, label: '', value: '' }, index))) }));
7
+ const PsMetricGridSkeleton = ({ count }) => {
8
+ const columns = ps_metric_grid_config_1.PsMetricGridColumns[Math.min(count, ps_metric_grid_config_1.PsMetricGridConfig.maxColumns)];
9
+ return ((0, jsx_runtime_1.jsx)("div", { className: `grid grid-cols-1 gap-3 ${columns === undefined ? ps_metric_grid_config_1.PsMetricGridColumns[ps_metric_grid_config_1.PsMetricGridConfig.defaultColumns] : columns}`, children: Array.from({ length: count }, (_, index) => ((0, jsx_runtime_1.jsx)(ps_metric_card_1.PsMetricCard, { isLoading: true, label: '', value: '' }, index))) }));
10
+ };
7
11
  exports.PsMetricGridSkeleton = PsMetricGridSkeleton;
@@ -3,6 +3,7 @@ import { type PsBackLinkProps } from './ps-back-link';
3
3
  export interface PsPageHeaderProps {
4
4
  actions?: ReactNode;
5
5
  backLink?: PsBackLinkProps;
6
+ leading?: ReactNode;
6
7
  title: string;
7
8
  }
8
- export declare const PsPageHeader: ({ actions, backLink, title }: PsPageHeaderProps) => import("react").JSX.Element;
9
+ export declare const PsPageHeader: ({ actions, backLink, leading, title }: PsPageHeaderProps) => import("react").JSX.Element;
@@ -4,5 +4,5 @@ exports.PsPageHeader = void 0;
4
4
  const jsx_runtime_1 = require("react/jsx-runtime");
5
5
  const ps_back_link_1 = require("./ps-back-link");
6
6
  const ps_section_header_1 = require("./ps-section-header");
7
- const PsPageHeader = ({ actions, backLink, title }) => ((0, jsx_runtime_1.jsx)(ps_section_header_1.PsSectionHeader, { leading: backLink ? (0, jsx_runtime_1.jsx)(ps_back_link_1.PsBackLink, { ...backLink }) : undefined, title: title, trailing: actions ? ((0, jsx_runtime_1.jsx)("div", { className: 'flex flex-wrap items-center justify-end gap-2', children: actions })) : undefined }));
7
+ const PsPageHeader = ({ actions, backLink, leading, title }) => ((0, jsx_runtime_1.jsx)(ps_section_header_1.PsSectionHeader, { leading: backLink ? (0, jsx_runtime_1.jsx)(ps_back_link_1.PsBackLink, { ...backLink }) : leading, title: title, trailing: actions ? ((0, jsx_runtime_1.jsx)("div", { className: 'flex flex-wrap items-center justify-end gap-2', children: actions })) : undefined }));
8
8
  exports.PsPageHeader = PsPageHeader;
@@ -3,8 +3,9 @@ export interface PsPageSkeletonProps {
3
3
  actions?: ReactNode;
4
4
  children: ReactNode;
5
5
  hasActions?: boolean;
6
+ hasBackLink?: boolean;
6
7
  isNarrow?: boolean;
7
8
  loadingLabel: string;
8
9
  title?: string;
9
10
  }
10
- export declare const PsPageSkeleton: ({ actions, children, hasActions, isNarrow, loadingLabel, title, }: PsPageSkeletonProps) => import("react").JSX.Element;
11
+ export declare const PsPageSkeleton: ({ actions, children, hasActions, hasBackLink, isNarrow, loadingLabel, title, }: PsPageSkeletonProps) => import("react").JSX.Element;
@@ -8,5 +8,8 @@ const ps_page_layout_1 = require("./ps-page-layout");
8
8
  const ps_page_stack_1 = require("./ps-page-stack");
9
9
  const ps_section_header_1 = require("./ps-section-header");
10
10
  const ps_skeleton_1 = require("./ps-skeleton");
11
- const PsPageSkeleton = ({ actions, children, hasActions = false, isNarrow = false, loadingLabel, title, }) => ((0, jsx_runtime_1.jsx)(ps_page_layout_1.PsPageLayout, { isNarrow: isNarrow, children: (0, jsx_runtime_1.jsxs)(ps_page_stack_1.PsPageStack, { children: [title === undefined ? ((0, jsx_runtime_1.jsx)(ps_section_header_1.PsSectionHeader, { isLoading: true, title: loadingLabel, trailing: hasActions })) : ((0, jsx_runtime_1.jsx)(ps_page_header_1.PsPageHeader, { actions: actions !== undefined ? (actions) : hasActions ? ((0, jsx_runtime_1.jsx)(ps_skeleton_1.PsSkeleton, { shape: ps_skeleton_shape_1.PsSkeletonShape.Button })) : undefined, title: title })), children] }) }));
11
+ const PsPageSkeleton = ({ actions, children, hasActions = false, hasBackLink = false, isNarrow = false, loadingLabel, title, }) => {
12
+ const backLink = hasBackLink ? (0, jsx_runtime_1.jsx)(ps_skeleton_1.PsSkeleton, { className: 'h-5 w-32' }) : undefined;
13
+ return ((0, jsx_runtime_1.jsx)(ps_page_layout_1.PsPageLayout, { isNarrow: isNarrow, children: (0, jsx_runtime_1.jsxs)(ps_page_stack_1.PsPageStack, { children: [title === undefined ? ((0, jsx_runtime_1.jsx)(ps_section_header_1.PsSectionHeader, { isLoading: true, leading: backLink, title: loadingLabel, trailing: hasActions })) : ((0, jsx_runtime_1.jsx)(ps_page_header_1.PsPageHeader, { actions: actions !== undefined ? (actions) : hasActions ? ((0, jsx_runtime_1.jsx)(ps_skeleton_1.PsSkeleton, { shape: ps_skeleton_shape_1.PsSkeletonShape.Button })) : undefined, leading: backLink, title: title })), children] }) }));
14
+ };
12
15
  exports.PsPageSkeleton = PsPageSkeleton;
@@ -5,5 +5,5 @@ const jsx_runtime_1 = require("react/jsx-runtime");
5
5
  const ps_skeleton_shape_1 = require("../constants/ps-skeleton-shape");
6
6
  const ps_skeleton_1 = require("./ps-skeleton");
7
7
  const ps_skeleton_group_1 = require("./ps-skeleton-group");
8
- const PsSectionHeader = ({ description, eyebrow, isLoading = false, leading, title, trailing, }) => isLoading ? ((0, jsx_runtime_1.jsxs)(ps_skeleton_group_1.PsSkeletonGroup, { className: 'flex flex-wrap items-end justify-between gap-x-4 gap-y-3', label: title, children: [(0, jsx_runtime_1.jsxs)("div", { className: 'flex min-w-0 flex-1 basis-auto flex-col gap-2', children: [eyebrow ? (0, jsx_runtime_1.jsx)(ps_skeleton_1.PsSkeleton, { className: 'h-2.5 w-24' }) : null, (0, jsx_runtime_1.jsx)(ps_skeleton_1.PsSkeleton, { className: 'h-6 w-52' }), description ? (0, jsx_runtime_1.jsx)(ps_skeleton_1.PsSkeleton, { className: 'h-3 w-72' }) : null] }), trailing ? (0, jsx_runtime_1.jsx)(ps_skeleton_1.PsSkeleton, { shape: ps_skeleton_shape_1.PsSkeletonShape.Button }) : null] })) : ((0, jsx_runtime_1.jsxs)("div", { className: 'flex flex-wrap items-end justify-between gap-x-4 gap-y-3', children: [(0, jsx_runtime_1.jsxs)("div", { className: 'flex min-w-0 flex-1 basis-auto flex-col gap-2', children: [leading, eyebrow ? ((0, jsx_runtime_1.jsx)("p", { className: 'text-[0.68rem] font-semibold uppercase tracking-[0.22em] text-ink/50', children: eyebrow })) : null, (0, jsx_runtime_1.jsx)("h1", { className: 'break-words text-xl font-extrabold text-ink sm:text-2xl', children: title }), description ? ((0, jsx_runtime_1.jsx)("p", { className: 'max-w-3xl text-sm leading-6 text-ink/60', children: description })) : null] }), trailing ? ((0, jsx_runtime_1.jsx)("div", { className: 'flex w-full shrink-0 items-center justify-end sm:ml-auto sm:w-auto', children: trailing })) : null] }));
8
+ const PsSectionHeader = ({ description, eyebrow, isLoading = false, leading, title, trailing, }) => isLoading ? ((0, jsx_runtime_1.jsxs)(ps_skeleton_group_1.PsSkeletonGroup, { className: 'flex flex-wrap items-end justify-between gap-x-4 gap-y-3', label: title, children: [(0, jsx_runtime_1.jsxs)("div", { className: 'flex min-w-0 flex-1 basis-auto flex-col gap-2', children: [leading, eyebrow ? (0, jsx_runtime_1.jsx)(ps_skeleton_1.PsSkeleton, { className: 'h-2.5 w-24' }) : null, (0, jsx_runtime_1.jsx)(ps_skeleton_1.PsSkeleton, { className: 'h-6 w-52' }), description ? (0, jsx_runtime_1.jsx)(ps_skeleton_1.PsSkeleton, { className: 'h-3 w-72' }) : null] }), trailing ? (0, jsx_runtime_1.jsx)(ps_skeleton_1.PsSkeleton, { shape: ps_skeleton_shape_1.PsSkeletonShape.Button }) : null] })) : ((0, jsx_runtime_1.jsxs)("div", { className: 'flex flex-wrap items-end justify-between gap-x-4 gap-y-3', children: [(0, jsx_runtime_1.jsxs)("div", { className: 'flex min-w-0 flex-1 basis-auto flex-col gap-2', children: [leading, eyebrow ? ((0, jsx_runtime_1.jsx)("p", { className: 'text-[0.68rem] font-semibold uppercase tracking-[0.22em] text-ink/50', children: eyebrow })) : null, (0, jsx_runtime_1.jsx)("h1", { className: 'break-words text-xl font-extrabold text-ink sm:text-2xl', children: title }), description ? ((0, jsx_runtime_1.jsx)("p", { className: 'max-w-3xl text-sm leading-6 text-ink/60', children: description })) : null] }), trailing ? ((0, jsx_runtime_1.jsx)("div", { className: 'flex w-full shrink-0 items-center justify-end sm:ml-auto sm:w-auto', children: trailing })) : null] }));
9
9
  exports.PsSectionHeader = PsSectionHeader;
@@ -2,5 +2,6 @@ import type { ReactNode } from 'react';
2
2
  export interface PsSectionPanelSkeletonProps {
3
3
  children: ReactNode;
4
4
  title?: string;
5
+ variant?: 'bordered' | 'card' | 'plain';
5
6
  }
6
- export declare const PsSectionPanelSkeleton: ({ children, title }: PsSectionPanelSkeletonProps) => import("react").JSX.Element;
7
+ export declare const PsSectionPanelSkeleton: ({ children, title, variant, }: PsSectionPanelSkeletonProps) => import("react").JSX.Element;
@@ -3,5 +3,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.PsSectionPanelSkeleton = void 0;
4
4
  const jsx_runtime_1 = require("react/jsx-runtime");
5
5
  const ps_skeleton_1 = require("./ps-skeleton");
6
- const PsSectionPanelSkeleton = ({ children, title }) => ((0, jsx_runtime_1.jsxs)("section", { className: 'ps-section', children: [(0, jsx_runtime_1.jsx)("div", { className: 'flex min-h-10 items-center', children: title === undefined ? ((0, jsx_runtime_1.jsx)(ps_skeleton_1.PsSkeleton, { className: 'h-4 w-44' })) : ((0, jsx_runtime_1.jsx)("h2", { className: 'text-base font-semibold text-ink', children: title })) }), (0, jsx_runtime_1.jsx)("div", { className: 'flex min-w-0 flex-col gap-4', children: children })] }));
6
+ const PsSectionPanelSkeleton = ({ children, title, variant = 'plain', }) => {
7
+ const heading = title === undefined ? ((0, jsx_runtime_1.jsx)(ps_skeleton_1.PsSkeleton, { className: 'h-4 w-44' })) : ((0, jsx_runtime_1.jsx)("h2", { className: 'text-base font-semibold text-ink', children: title }));
8
+ return variant === 'bordered' ? ((0, jsx_runtime_1.jsxs)("section", { className: 'rounded-ps-panel border border-line bg-surface', children: [(0, jsx_runtime_1.jsx)("header", { className: 'flex min-h-14 items-center justify-between gap-3 border-b border-line px-5 py-3', children: (0, jsx_runtime_1.jsx)("div", { className: 'flex min-w-0 flex-col', children: heading }) }), (0, jsx_runtime_1.jsx)("div", { className: 'flex flex-col gap-4 p-5', children: children })] })) : variant === 'card' ? ((0, jsx_runtime_1.jsxs)("section", { className: 'rounded-ps-panel border border-line bg-surface p-5', children: [(0, jsx_runtime_1.jsx)("div", { className: 'mb-3', children: heading }), children] })) : ((0, jsx_runtime_1.jsxs)("section", { className: 'ps-section', children: [(0, jsx_runtime_1.jsx)("div", { className: 'flex min-h-10 items-center', children: heading }), (0, jsx_runtime_1.jsx)("div", { className: 'flex min-w-0 flex-col gap-4', children: children })] }));
9
+ };
7
10
  exports.PsSectionPanelSkeleton = PsSectionPanelSkeleton;
@@ -0,0 +1,20 @@
1
+ export declare const PsLinkPreviewConfig: {
2
+ readonly anchorClassName: "ps-card ps-focus-ring group block min-w-0 overflow-hidden rounded-ps-card text-left no-underline transition hover:border-primary/60";
3
+ readonly compactBodyClassName: "flex min-w-0 flex-1 flex-col gap-0.5 p-3";
4
+ readonly compactImageClassName: "h-full w-full object-cover";
5
+ readonly compactMediaClassName: "relative block w-20 shrink-0 self-stretch overflow-hidden bg-ink/5 empty:hidden sm:w-24 [&>span]:block [&>span]:h-full [&>span]:w-full";
6
+ readonly compactRowClassName: "flex min-w-0 items-stretch";
7
+ readonly descriptionClassName: "line-clamp-2 break-words text-sm text-ink/70";
8
+ readonly externalIconClassName: "h-4 w-4 shrink-0 text-ink/50 transition group-hover:text-primary";
9
+ readonly faviconClassName: "h-4 w-4 shrink-0 rounded-sm object-contain";
10
+ readonly fullBodyClassName: "flex min-w-0 flex-col gap-1 p-4";
11
+ readonly fullImageClassName: "h-full w-full object-cover";
12
+ readonly fullMediaClassName: "relative block aspect-[1.91/1] w-full overflow-hidden bg-ink/5 empty:hidden [&>span]:block [&>span]:h-full [&>span]:w-full";
13
+ readonly globeIconClassName: "h-4 w-4 shrink-0 text-ink/50";
14
+ readonly metaRowClassName: "flex min-w-0 items-center gap-2 text-xs font-medium text-ink/60";
15
+ readonly rel: "noopener noreferrer";
16
+ readonly siteClassName: "min-w-0 flex-1 truncate";
17
+ readonly target: "_blank";
18
+ readonly titleClassName: "line-clamp-2 break-words text-sm font-bold text-ink transition group-hover:text-primary";
19
+ readonly urlClassName: "truncate text-xs text-ink/60";
20
+ };
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PsLinkPreviewConfig = void 0;
4
+ exports.PsLinkPreviewConfig = {
5
+ anchorClassName: 'ps-card ps-focus-ring group block min-w-0 overflow-hidden rounded-ps-card text-left no-underline transition hover:border-primary/60',
6
+ compactBodyClassName: 'flex min-w-0 flex-1 flex-col gap-0.5 p-3',
7
+ compactImageClassName: 'h-full w-full object-cover',
8
+ compactMediaClassName: 'relative block w-20 shrink-0 self-stretch overflow-hidden bg-ink/5 empty:hidden sm:w-24 [&>span]:block [&>span]:h-full [&>span]:w-full',
9
+ compactRowClassName: 'flex min-w-0 items-stretch',
10
+ descriptionClassName: 'line-clamp-2 break-words text-sm text-ink/70',
11
+ externalIconClassName: 'h-4 w-4 shrink-0 text-ink/50 transition group-hover:text-primary',
12
+ faviconClassName: 'h-4 w-4 shrink-0 rounded-sm object-contain',
13
+ fullBodyClassName: 'flex min-w-0 flex-col gap-1 p-4',
14
+ fullImageClassName: 'h-full w-full object-cover',
15
+ fullMediaClassName: 'relative block aspect-[1.91/1] w-full overflow-hidden bg-ink/5 empty:hidden [&>span]:block [&>span]:h-full [&>span]:w-full',
16
+ globeIconClassName: 'h-4 w-4 shrink-0 text-ink/50',
17
+ metaRowClassName: 'flex min-w-0 items-center gap-2 text-xs font-medium text-ink/60',
18
+ rel: 'noopener noreferrer',
19
+ siteClassName: 'min-w-0 flex-1 truncate',
20
+ target: '_blank',
21
+ titleClassName: 'line-clamp-2 break-words text-sm font-bold text-ink transition group-hover:text-primary',
22
+ urlClassName: 'truncate text-xs text-ink/60',
23
+ };
@@ -0,0 +1,4 @@
1
+ export declare enum PsLinkPreviewSize {
2
+ Compact = "compact",
3
+ Full = "full"
4
+ }
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PsLinkPreviewSize = void 0;
4
+ var PsLinkPreviewSize;
5
+ (function (PsLinkPreviewSize) {
6
+ PsLinkPreviewSize["Compact"] = "compact";
7
+ PsLinkPreviewSize["Full"] = "full";
8
+ })(PsLinkPreviewSize || (exports.PsLinkPreviewSize = PsLinkPreviewSize = {}));
@@ -3,4 +3,4 @@ import { PsPageSkeletonConfig } from '../constants/ps-page-skeleton-config.js';
3
3
  import { PsFormFieldsSkeleton } from './ps-form-fields-skeleton.js';
4
4
  import { PsPageSkeleton } from './ps-page-skeleton.js';
5
5
  import { PsSectionPanelSkeleton } from './ps-section-panel-skeleton.js';
6
- export const PsFormPageSkeleton = ({ loadingLabel, title }) => (_jsx(PsPageSkeleton, { hasActions: true, loadingLabel: loadingLabel, title: title, children: PsPageSkeletonConfig.formSections.map((section) => (_jsx(PsSectionPanelSkeleton, { children: _jsx(PsFormFieldsSkeleton, {}) }, section))) }));
6
+ export const PsFormPageSkeleton = ({ hasActions = true, hasBackLink = false, isNarrow = false, loadingLabel, title, variant = 'plain', }) => (_jsx(PsPageSkeleton, { hasActions: hasActions, hasBackLink: hasBackLink, isNarrow: isNarrow, loadingLabel: loadingLabel, title: title, children: PsPageSkeletonConfig.formSections.map((section) => (_jsx(PsSectionPanelSkeleton, { variant: variant, children: _jsx(PsFormFieldsSkeleton, {}) }, section))) }));
@@ -0,0 +1,30 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { PallasoftClassNameService } from '@pallasoft/ps-design-system';
3
+ import { PsIcon, PsIconKey } from '@pallasoft/ps-icons';
4
+ import { PsLinkPreviewConfig } from '../constants/ps-link-preview-config.js';
5
+ import { PsLinkPreviewSize } from '../constants/ps-link-preview-size.js';
6
+ import { PsSkeletonShape } from '../constants/ps-skeleton-shape.js';
7
+ import { PsLinkPreviewService } from '../services/ps-link-preview-service.js';
8
+ import { PsImage } from './ps-image.js';
9
+ import { PsSkeleton } from './ps-skeleton.js';
10
+ import { PsSkeletonGroup } from './ps-skeleton-group.js';
11
+ export const PsLinkPreviewCard = ({ className, description, faviconSrc, href, imageSrc, isLoading = false, loadingLabel, opensInNewTabLabel, siteName, size = PsLinkPreviewSize.Full, title, }) => {
12
+ const isCompact = size === PsLinkPreviewSize.Compact;
13
+ const domain = PsLinkPreviewService.domain(href);
14
+ const hasTitle = title !== null && title !== undefined && title.trim() !== '';
15
+ const hasSite = siteName !== null && siteName !== undefined && siteName.trim() !== '';
16
+ const hasDescription = description !== null && description !== undefined && description.trim() !== '';
17
+ const hasImage = imageSrc !== null && imageSrc !== undefined && imageSrc !== '';
18
+ const hasFavicon = faviconSrc !== null && faviconSrc !== undefined && faviconSrc !== '';
19
+ if (!PsLinkPreviewService.isWebAddress(href))
20
+ return null;
21
+ if (isLoading)
22
+ return (_jsxs(PsSkeletonGroup, { className: PallasoftClassNameService.merge('ps-card min-w-0 overflow-hidden rounded-ps-card', className), direction: isCompact ? 'row' : 'column', gap: 'gap-0', label: loadingLabel, children: [isCompact ? (_jsx(PsSkeleton, { className: 'h-20 w-24 shrink-0', shape: PsSkeletonShape.Block, radius: '0' })) : (_jsx(PsSkeleton, { aspect: '1.91 / 1', className: 'w-full', shape: PsSkeletonShape.Block, radius: '0' })), _jsxs("span", { className: isCompact ? 'flex flex-1 flex-col gap-2 p-3' : 'flex flex-col gap-2 p-4', children: [_jsx(PsSkeleton, { className: 'h-3 w-24' }), _jsx(PsSkeleton, { className: 'h-4 w-3/4' }), isCompact ? null : _jsx(PsSkeleton, { className: 'h-3 w-full' })] })] }));
23
+ const favicon = hasFavicon ? (_jsx(PsImage, { alt: '', className: PsLinkPreviewConfig.faviconClassName, errorFallback: _jsx(PsIcon, { className: PsLinkPreviewConfig.globeIconClassName, iconKey: PsIconKey.Globe }), height: 16, loading: 'lazy', src: faviconSrc, width: 16 })) : (_jsx(PsIcon, { className: PsLinkPreviewConfig.globeIconClassName, iconKey: PsIconKey.Globe }));
24
+ const meta = (_jsxs("span", { className: PsLinkPreviewConfig.metaRowClassName, children: [favicon, _jsx("span", { className: PsLinkPreviewConfig.siteClassName, children: hasSite ? siteName : domain }), _jsx(PsIcon, { className: PsLinkPreviewConfig.externalIconClassName, iconKey: PsIconKey.ExternalLink })] }));
25
+ const text = (_jsxs(_Fragment, { children: [meta, hasTitle ? (_jsx("span", { className: PsLinkPreviewConfig.titleClassName, children: title })) : (_jsx("span", { className: PsLinkPreviewConfig.urlClassName, children: href })), hasDescription && !isCompact ? (_jsx("span", { className: PsLinkPreviewConfig.descriptionClassName, children: description })) : null, opensInNewTabLabel === undefined ? null : (_jsx("span", { className: 'sr-only', children: opensInNewTabLabel }))] }));
26
+ const media = hasImage ? (_jsx(PsImage, { alt: '', className: isCompact
27
+ ? PsLinkPreviewConfig.compactImageClassName
28
+ : PsLinkPreviewConfig.fullImageClassName, errorFallback: null, loading: 'lazy', src: imageSrc })) : null;
29
+ return (_jsx("a", { className: PallasoftClassNameService.merge(PsLinkPreviewConfig.anchorClassName, className), href: href, rel: PsLinkPreviewConfig.rel, target: PsLinkPreviewConfig.target, children: isCompact ? (_jsxs("span", { className: PsLinkPreviewConfig.compactRowClassName, children: [media === null ? null : (_jsx("span", { className: PsLinkPreviewConfig.compactMediaClassName, children: media })), _jsx("span", { className: PsLinkPreviewConfig.compactBodyClassName, children: text })] })) : (_jsxs(_Fragment, { children: [media === null ? null : (_jsx("span", { className: PsLinkPreviewConfig.fullMediaClassName, children: media })), _jsx("span", { className: PsLinkPreviewConfig.fullBodyClassName, children: text })] })) }));
30
+ };
@@ -1,3 +1,7 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { PsMetricGridColumns, PsMetricGridConfig } from '../constants/ps-metric-grid-config.js';
2
3
  import { PsMetricCard } from './ps-metric-card.js';
3
- export const PsMetricGridSkeleton = ({ count }) => (_jsx("div", { className: 'grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-4', children: Array.from({ length: count }, (_, index) => (_jsx(PsMetricCard, { isLoading: true, label: '', value: '' }, index))) }));
4
+ export const PsMetricGridSkeleton = ({ count }) => {
5
+ const columns = PsMetricGridColumns[Math.min(count, PsMetricGridConfig.maxColumns)];
6
+ return (_jsx("div", { className: `grid grid-cols-1 gap-3 ${columns === undefined ? PsMetricGridColumns[PsMetricGridConfig.defaultColumns] : columns}`, children: Array.from({ length: count }, (_, index) => (_jsx(PsMetricCard, { isLoading: true, label: '', value: '' }, index))) }));
7
+ };
@@ -1,4 +1,4 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { PsBackLink } from './ps-back-link.js';
3
3
  import { PsSectionHeader } from './ps-section-header.js';
4
- export const PsPageHeader = ({ actions, backLink, title }) => (_jsx(PsSectionHeader, { leading: backLink ? _jsx(PsBackLink, { ...backLink }) : undefined, title: title, trailing: actions ? (_jsx("div", { className: 'flex flex-wrap items-center justify-end gap-2', children: actions })) : undefined }));
4
+ export const PsPageHeader = ({ actions, backLink, leading, title }) => (_jsx(PsSectionHeader, { leading: backLink ? _jsx(PsBackLink, { ...backLink }) : leading, title: title, trailing: actions ? (_jsx("div", { className: 'flex flex-wrap items-center justify-end gap-2', children: actions })) : undefined }));
@@ -5,4 +5,7 @@ import { PsPageLayout } from './ps-page-layout.js';
5
5
  import { PsPageStack } from './ps-page-stack.js';
6
6
  import { PsSectionHeader } from './ps-section-header.js';
7
7
  import { PsSkeleton } from './ps-skeleton.js';
8
- export const PsPageSkeleton = ({ actions, children, hasActions = false, isNarrow = false, loadingLabel, title, }) => (_jsx(PsPageLayout, { isNarrow: isNarrow, children: _jsxs(PsPageStack, { children: [title === undefined ? (_jsx(PsSectionHeader, { isLoading: true, title: loadingLabel, trailing: hasActions })) : (_jsx(PsPageHeader, { actions: actions !== undefined ? (actions) : hasActions ? (_jsx(PsSkeleton, { shape: PsSkeletonShape.Button })) : undefined, title: title })), children] }) }));
8
+ export const PsPageSkeleton = ({ actions, children, hasActions = false, hasBackLink = false, isNarrow = false, loadingLabel, title, }) => {
9
+ const backLink = hasBackLink ? _jsx(PsSkeleton, { className: 'h-5 w-32' }) : undefined;
10
+ return (_jsx(PsPageLayout, { isNarrow: isNarrow, children: _jsxs(PsPageStack, { children: [title === undefined ? (_jsx(PsSectionHeader, { isLoading: true, leading: backLink, title: loadingLabel, trailing: hasActions })) : (_jsx(PsPageHeader, { actions: actions !== undefined ? (actions) : hasActions ? (_jsx(PsSkeleton, { shape: PsSkeletonShape.Button })) : undefined, leading: backLink, title: title })), children] }) }));
11
+ };
@@ -2,4 +2,4 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { PsSkeletonShape } from '../constants/ps-skeleton-shape.js';
3
3
  import { PsSkeleton } from './ps-skeleton.js';
4
4
  import { PsSkeletonGroup } from './ps-skeleton-group.js';
5
- export const PsSectionHeader = ({ description, eyebrow, isLoading = false, leading, title, trailing, }) => isLoading ? (_jsxs(PsSkeletonGroup, { className: 'flex flex-wrap items-end justify-between gap-x-4 gap-y-3', label: title, children: [_jsxs("div", { className: 'flex min-w-0 flex-1 basis-auto flex-col gap-2', children: [eyebrow ? _jsx(PsSkeleton, { className: 'h-2.5 w-24' }) : null, _jsx(PsSkeleton, { className: 'h-6 w-52' }), description ? _jsx(PsSkeleton, { className: 'h-3 w-72' }) : null] }), trailing ? _jsx(PsSkeleton, { shape: PsSkeletonShape.Button }) : null] })) : (_jsxs("div", { className: 'flex flex-wrap items-end justify-between gap-x-4 gap-y-3', children: [_jsxs("div", { className: 'flex min-w-0 flex-1 basis-auto flex-col gap-2', children: [leading, eyebrow ? (_jsx("p", { className: 'text-[0.68rem] font-semibold uppercase tracking-[0.22em] text-ink/50', children: eyebrow })) : null, _jsx("h1", { className: 'break-words text-xl font-extrabold text-ink sm:text-2xl', children: title }), description ? (_jsx("p", { className: 'max-w-3xl text-sm leading-6 text-ink/60', children: description })) : null] }), trailing ? (_jsx("div", { className: 'flex w-full shrink-0 items-center justify-end sm:ml-auto sm:w-auto', children: trailing })) : null] }));
5
+ export const PsSectionHeader = ({ description, eyebrow, isLoading = false, leading, title, trailing, }) => isLoading ? (_jsxs(PsSkeletonGroup, { className: 'flex flex-wrap items-end justify-between gap-x-4 gap-y-3', label: title, children: [_jsxs("div", { className: 'flex min-w-0 flex-1 basis-auto flex-col gap-2', children: [leading, eyebrow ? _jsx(PsSkeleton, { className: 'h-2.5 w-24' }) : null, _jsx(PsSkeleton, { className: 'h-6 w-52' }), description ? _jsx(PsSkeleton, { className: 'h-3 w-72' }) : null] }), trailing ? _jsx(PsSkeleton, { shape: PsSkeletonShape.Button }) : null] })) : (_jsxs("div", { className: 'flex flex-wrap items-end justify-between gap-x-4 gap-y-3', children: [_jsxs("div", { className: 'flex min-w-0 flex-1 basis-auto flex-col gap-2', children: [leading, eyebrow ? (_jsx("p", { className: 'text-[0.68rem] font-semibold uppercase tracking-[0.22em] text-ink/50', children: eyebrow })) : null, _jsx("h1", { className: 'break-words text-xl font-extrabold text-ink sm:text-2xl', children: title }), description ? (_jsx("p", { className: 'max-w-3xl text-sm leading-6 text-ink/60', children: description })) : null] }), trailing ? (_jsx("div", { className: 'flex w-full shrink-0 items-center justify-end sm:ml-auto sm:w-auto', children: trailing })) : null] }));
@@ -1,3 +1,6 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { PsSkeleton } from './ps-skeleton.js';
3
- export const PsSectionPanelSkeleton = ({ children, title }) => (_jsxs("section", { className: 'ps-section', children: [_jsx("div", { className: 'flex min-h-10 items-center', children: title === undefined ? (_jsx(PsSkeleton, { className: 'h-4 w-44' })) : (_jsx("h2", { className: 'text-base font-semibold text-ink', children: title })) }), _jsx("div", { className: 'flex min-w-0 flex-col gap-4', children: children })] }));
3
+ export const PsSectionPanelSkeleton = ({ children, title, variant = 'plain', }) => {
4
+ const heading = title === undefined ? (_jsx(PsSkeleton, { className: 'h-4 w-44' })) : (_jsx("h2", { className: 'text-base font-semibold text-ink', children: title }));
5
+ return variant === 'bordered' ? (_jsxs("section", { className: 'rounded-ps-panel border border-line bg-surface', children: [_jsx("header", { className: 'flex min-h-14 items-center justify-between gap-3 border-b border-line px-5 py-3', children: _jsx("div", { className: 'flex min-w-0 flex-col', children: heading }) }), _jsx("div", { className: 'flex flex-col gap-4 p-5', children: children })] })) : variant === 'card' ? (_jsxs("section", { className: 'rounded-ps-panel border border-line bg-surface p-5', children: [_jsx("div", { className: 'mb-3', children: heading }), children] })) : (_jsxs("section", { className: 'ps-section', children: [_jsx("div", { className: 'flex min-h-10 items-center', children: heading }), _jsx("div", { className: 'flex min-w-0 flex-col gap-4', children: children })] }));
6
+ };
@@ -0,0 +1,20 @@
1
+ export const PsLinkPreviewConfig = {
2
+ anchorClassName: 'ps-card ps-focus-ring group block min-w-0 overflow-hidden rounded-ps-card text-left no-underline transition hover:border-primary/60',
3
+ compactBodyClassName: 'flex min-w-0 flex-1 flex-col gap-0.5 p-3',
4
+ compactImageClassName: 'h-full w-full object-cover',
5
+ compactMediaClassName: 'relative block w-20 shrink-0 self-stretch overflow-hidden bg-ink/5 empty:hidden sm:w-24 [&>span]:block [&>span]:h-full [&>span]:w-full',
6
+ compactRowClassName: 'flex min-w-0 items-stretch',
7
+ descriptionClassName: 'line-clamp-2 break-words text-sm text-ink/70',
8
+ externalIconClassName: 'h-4 w-4 shrink-0 text-ink/50 transition group-hover:text-primary',
9
+ faviconClassName: 'h-4 w-4 shrink-0 rounded-sm object-contain',
10
+ fullBodyClassName: 'flex min-w-0 flex-col gap-1 p-4',
11
+ fullImageClassName: 'h-full w-full object-cover',
12
+ fullMediaClassName: 'relative block aspect-[1.91/1] w-full overflow-hidden bg-ink/5 empty:hidden [&>span]:block [&>span]:h-full [&>span]:w-full',
13
+ globeIconClassName: 'h-4 w-4 shrink-0 text-ink/50',
14
+ metaRowClassName: 'flex min-w-0 items-center gap-2 text-xs font-medium text-ink/60',
15
+ rel: 'noopener noreferrer',
16
+ siteClassName: 'min-w-0 flex-1 truncate',
17
+ target: '_blank',
18
+ titleClassName: 'line-clamp-2 break-words text-sm font-bold text-ink transition group-hover:text-primary',
19
+ urlClassName: 'truncate text-xs text-ink/60',
20
+ };
@@ -0,0 +1,5 @@
1
+ export var PsLinkPreviewSize;
2
+ (function (PsLinkPreviewSize) {
3
+ PsLinkPreviewSize["Compact"] = "compact";
4
+ PsLinkPreviewSize["Full"] = "full";
5
+ })(PsLinkPreviewSize || (PsLinkPreviewSize = {}));
package/dist/esm/index.js CHANGED
@@ -248,3 +248,7 @@ export * from './services/ps-image-service.js';
248
248
  export * from './components/ps-image.js';
249
249
  export { PsDeepEqualService, PsOptimisticConfig, PsOptimisticSaveService, } from '@pallasoft/ps-utilities';
250
250
  export { usePsChangeQueue, usePsDebouncedValue, usePsOptimisticRows, } from '@pallasoft/ps-utilities/react';
251
+ export * from './constants/ps-link-preview-size.js';
252
+ export * from './constants/ps-link-preview-config.js';
253
+ export * from './services/ps-link-preview-service.js';
254
+ export * from './components/ps-link-preview-card.js';
@@ -0,0 +1,19 @@
1
+ export class PsLinkPreviewService {
2
+ static isWebAddress(href) {
3
+ try {
4
+ const { protocol } = new URL(href);
5
+ return protocol === 'http:' || protocol === 'https:';
6
+ }
7
+ catch {
8
+ return false;
9
+ }
10
+ }
11
+ static domain(href) {
12
+ try {
13
+ return new URL(href).hostname.replace(/^www\./i, '');
14
+ }
15
+ catch {
16
+ return href;
17
+ }
18
+ }
19
+ }
package/dist/index.d.ts CHANGED
@@ -248,3 +248,7 @@ export * from './services/ps-image-service';
248
248
  export * from './components/ps-image';
249
249
  export { PsDeepEqualService, PsOptimisticConfig, PsOptimisticSaveService, type PsOptimisticFailureReason, type PsOptimisticSaveSpec, } from '@pallasoft/ps-utilities';
250
250
  export { usePsChangeQueue, usePsDebouncedValue, usePsOptimisticRows, type PsChangeQueueInput, type PsChangeQueueResult, type PsOptimisticRowsInput, type PsOptimisticRowsResult, } from '@pallasoft/ps-utilities/react';
251
+ export * from './constants/ps-link-preview-size';
252
+ export * from './constants/ps-link-preview-config';
253
+ export * from './services/ps-link-preview-service';
254
+ export * from './components/ps-link-preview-card';
package/dist/index.js CHANGED
@@ -271,3 +271,7 @@ var react_1 = require("@pallasoft/ps-utilities/react");
271
271
  Object.defineProperty(exports, "usePsChangeQueue", { enumerable: true, get: function () { return react_1.usePsChangeQueue; } });
272
272
  Object.defineProperty(exports, "usePsDebouncedValue", { enumerable: true, get: function () { return react_1.usePsDebouncedValue; } });
273
273
  Object.defineProperty(exports, "usePsOptimisticRows", { enumerable: true, get: function () { return react_1.usePsOptimisticRows; } });
274
+ __exportStar(require("./constants/ps-link-preview-size"), exports);
275
+ __exportStar(require("./constants/ps-link-preview-config"), exports);
276
+ __exportStar(require("./services/ps-link-preview-service"), exports);
277
+ __exportStar(require("./components/ps-link-preview-card"), exports);
@@ -0,0 +1,4 @@
1
+ export declare class PsLinkPreviewService {
2
+ static isWebAddress(href: string): boolean;
3
+ static domain(href: string): string;
4
+ }
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PsLinkPreviewService = void 0;
4
+ class PsLinkPreviewService {
5
+ static isWebAddress(href) {
6
+ try {
7
+ const { protocol } = new URL(href);
8
+ return protocol === 'http:' || protocol === 'https:';
9
+ }
10
+ catch {
11
+ return false;
12
+ }
13
+ }
14
+ static domain(href) {
15
+ try {
16
+ return new URL(href).hostname.replace(/^www\./i, '');
17
+ }
18
+ catch {
19
+ return href;
20
+ }
21
+ }
22
+ }
23
+ exports.PsLinkPreviewService = PsLinkPreviewService;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pallasoft/ps-core-components",
3
- "version": "2.47.1",
3
+ "version": "2.49.0",
4
4
  "private": false,
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/esm/index.js",
@@ -46,7 +46,7 @@
46
46
  "@dnd-kit/core": "^6.3.1",
47
47
  "@dnd-kit/sortable": "^10.0.0",
48
48
  "@dnd-kit/utilities": "^3.2.2",
49
- "@pallasoft/ps-icons": "^1.5.4",
49
+ "@pallasoft/ps-icons": "^1.12.0",
50
50
  "@pallasoft/ps-motion-components": "^1.2.2",
51
51
  "@pallasoft/ps-utilities": "^2.29.0",
52
52
  "@portabletext/react": "^3.2.4",