@pallasoft/ps-core-components 2.3.1 → 2.5.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 (85) hide show
  1. package/dist/components/ps-draggable-grid.d.ts +9 -12
  2. package/dist/components/ps-draggable-grid.js +72 -45
  3. package/dist/components/ps-navigation-progress.d.ts +3 -2
  4. package/dist/components/ps-navigation-progress.js +13 -22
  5. package/dist/components/ps-section-header.js +1 -1
  6. package/dist/components/ps-skeleton-card.d.ts +4 -0
  7. package/dist/components/ps-skeleton-card.js +9 -0
  8. package/dist/components/ps-skeleton-group.d.ts +7 -0
  9. package/dist/components/ps-skeleton-group.js +6 -0
  10. package/dist/components/ps-skeleton-list.d.ts +8 -0
  11. package/dist/components/ps-skeleton-list.js +10 -0
  12. package/dist/components/ps-skeleton-table.d.ts +7 -0
  13. package/dist/components/ps-skeleton-table.js +15 -0
  14. package/dist/components/ps-skeleton-text.d.ts +5 -0
  15. package/dist/components/ps-skeleton-text.js +12 -0
  16. package/dist/components/ps-skeleton.d.ts +3 -1
  17. package/dist/components/ps-skeleton.js +6 -1
  18. package/dist/constants/ps-draggable-grid.d.ts +17 -0
  19. package/dist/constants/ps-draggable-grid.js +26 -0
  20. package/dist/constants/ps-navigation-progress-config.d.ts +5 -0
  21. package/dist/constants/ps-navigation-progress-config.js +5 -0
  22. package/dist/constants/ps-skeleton-config.d.ts +3 -0
  23. package/dist/constants/ps-skeleton-config.js +6 -0
  24. package/dist/esm/components/ps-accordion.js +5 -0
  25. package/dist/esm/components/ps-action-tile.js +7 -0
  26. package/dist/esm/components/ps-audio-spectrum.js +9 -0
  27. package/dist/esm/components/ps-badge.js +10 -0
  28. package/dist/esm/components/ps-button.js +16 -0
  29. package/dist/esm/components/ps-card.js +14 -0
  30. package/dist/esm/components/ps-draggable-grid.js +80 -0
  31. package/dist/esm/components/ps-empty-state.js +28 -0
  32. package/dist/esm/components/ps-fab.js +9 -0
  33. package/dist/esm/components/ps-infinite-scroll.js +5 -0
  34. package/dist/esm/components/ps-layer.js +3 -0
  35. package/dist/esm/components/ps-list-tile.js +11 -0
  36. package/dist/esm/components/ps-metric-card.js +3 -0
  37. package/dist/esm/components/ps-navigation-progress.js +21 -0
  38. package/dist/esm/components/ps-pill.js +10 -0
  39. package/dist/esm/components/ps-portable-text.js +34 -0
  40. package/dist/esm/components/ps-reflective-app-shell.js +13 -0
  41. package/dist/esm/components/ps-section-header.js +2 -0
  42. package/dist/esm/components/ps-site-header.js +11 -0
  43. package/dist/esm/components/ps-skeleton-card.js +5 -0
  44. package/dist/esm/components/ps-skeleton-group.js +2 -0
  45. package/dist/esm/components/ps-skeleton-list.js +6 -0
  46. package/dist/esm/components/ps-skeleton-table.js +11 -0
  47. package/dist/esm/components/ps-skeleton-text.js +8 -0
  48. package/dist/esm/components/ps-skeleton.js +8 -0
  49. package/dist/esm/components/ps-spinner.js +12 -0
  50. package/dist/esm/components/ps-theme-toggle.js +7 -0
  51. package/dist/esm/components/ps-voice-orb.js +100 -0
  52. package/dist/esm/constants/ps-draggable-grid.js +23 -0
  53. package/dist/esm/constants/ps-navigation-progress-config.js +12 -0
  54. package/dist/esm/constants/ps-skeleton-config.js +3 -0
  55. package/dist/esm/constants/ps-voice-orb.js +85 -0
  56. package/dist/esm/contexts/ps-layer-context.js +2 -0
  57. package/dist/esm/hooks/use-ps-audio-spectrum.js +65 -0
  58. package/dist/esm/hooks/use-ps-exit-transition.js +29 -0
  59. package/dist/esm/hooks/use-ps-hide-on-scroll.js +25 -0
  60. package/dist/esm/hooks/use-ps-invisible-recaptcha.js +90 -0
  61. package/dist/esm/hooks/use-ps-layer-z-index.js +4 -0
  62. package/dist/esm/hooks/use-ps-navigation-progress.js +41 -0
  63. package/dist/esm/hooks/use-ps-route-loader-data.js +12 -0
  64. package/dist/esm/hooks/use-ps-viewport.js +18 -0
  65. package/dist/esm/index.js +43 -0
  66. package/dist/esm/interfaces/ps-component-props.js +1 -0
  67. package/dist/esm/models/ps-draggable-grid.js +1 -0
  68. package/dist/esm/models/ps-navigation-progress.js +1 -0
  69. package/dist/esm/models/ps-recaptcha-pending-request.js +1 -0
  70. package/dist/esm/models/ps-remix-react-module.js +1 -0
  71. package/dist/esm/models/ps-voice-orb.js +1 -0
  72. package/dist/hooks/use-ps-exit-transition.js +0 -1
  73. package/dist/hooks/use-ps-navigation-progress.d.ts +2 -0
  74. package/dist/hooks/use-ps-navigation-progress.js +45 -0
  75. package/dist/index.d.ts +9 -0
  76. package/dist/index.js +9 -0
  77. package/dist/models/ps-draggable-grid.d.ts +19 -0
  78. package/dist/models/ps-draggable-grid.js +2 -0
  79. package/dist/models/ps-navigation-progress.d.ts +5 -0
  80. package/dist/models/ps-navigation-progress.js +2 -0
  81. package/dist/models/ps-recaptcha-pending-request.d.ts +4 -0
  82. package/dist/models/ps-recaptcha-pending-request.js +2 -0
  83. package/dist/models/ps-remix-react-module.d.ts +3 -0
  84. package/dist/models/ps-remix-react-module.js +2 -0
  85. package/package.json +11 -3
@@ -1,19 +1,16 @@
1
- import type { JSX } from 'react';
2
- export interface PsDraggableGridItem {
3
- id: string;
1
+ import { type JSX } from 'react';
2
+ import { useSortable } from '@dnd-kit/sortable';
3
+ import { PsDraggableGridItem, PsDraggableGridProps, PsDraggableGridRenderOptions } from '../models/ps-draggable-grid';
4
+ export interface PsDraggableGridHandleProps {
4
5
  label: string;
6
+ listeners?: ReturnType<typeof useSortable>['listeners'];
7
+ attributes?: ReturnType<typeof useSortable>['attributes'];
8
+ setActivatorNodeRef?: (element: HTMLElement | null) => void;
5
9
  }
6
- export interface PsDraggableGridRenderOptions<TItem extends PsDraggableGridItem> {
7
- handle: JSX.Element;
10
+ export interface PsSortableGridItemProps<TItem extends PsDraggableGridItem> {
11
+ className: string;
8
12
  index: number;
9
- isDragging: boolean;
10
13
  item: TItem;
11
- }
12
- export interface PsDraggableGridProps<TItem extends PsDraggableGridItem> {
13
- getItemClassName?: (item: TItem) => string;
14
- items: TItem[];
15
- onReorder: (items: TItem[]) => void;
16
- onReorderEnd?: (items: TItem[]) => void;
17
14
  renderItem: (options: PsDraggableGridRenderOptions<TItem>) => JSX.Element | null;
18
15
  }
19
16
  export declare const PsDraggableGrid: <TItem extends PsDraggableGridItem>({ getItemClassName, items, onReorder, onReorderEnd, renderItem, }: PsDraggableGridProps<TItem>) => JSX.Element;
@@ -2,56 +2,83 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.PsDraggableGrid = void 0;
4
4
  const jsx_runtime_1 = require("react/jsx-runtime");
5
- const moveItem = (items, fromIndex, toIndex) => {
6
- const nextItems = [...items];
7
- const [movingItem] = nextItems.splice(fromIndex, 1);
8
- nextItems.splice(toIndex, 0, movingItem);
9
- return nextItems;
5
+ const react_1 = require("react");
6
+ const core_1 = require("@dnd-kit/core");
7
+ const sortable_1 = require("@dnd-kit/sortable");
8
+ const utilities_1 = require("@dnd-kit/utilities");
9
+ const react_dom_1 = require("react-dom");
10
+ const ps_draggable_grid_1 = require("../constants/ps-draggable-grid");
11
+ const liftCard = (element) => {
12
+ if (element === null)
13
+ return;
14
+ element.animate(ps_draggable_grid_1.PsDraggableGridLiftFrames, {
15
+ duration: ps_draggable_grid_1.PsDraggableGridConfig.liftDuration,
16
+ easing: ps_draggable_grid_1.PsDraggableGridConfig.liftEasing,
17
+ fill: 'forwards',
18
+ });
19
+ };
20
+ const dropAnimation = {
21
+ duration: ps_draggable_grid_1.PsDraggableGridConfig.dropDuration,
22
+ easing: ps_draggable_grid_1.PsDraggableGridConfig.dropEasing,
23
+ sideEffects: (0, core_1.defaultDropAnimationSideEffects)({
24
+ styles: { active: { opacity: ps_draggable_grid_1.PsDraggableGridConfig.placeholderOpacity } },
25
+ }),
26
+ };
27
+ const DragHandleIcon = () => ((0, jsx_runtime_1.jsx)("span", { "aria-hidden": 'true', className: 'grid grid-cols-2 gap-[0.1875rem]', children: Array.from({ length: 6 }).map((_, index) => ((0, jsx_runtime_1.jsx)("span", { className: 'h-[3px] w-[3px] rounded-full bg-current' }, index))) }));
28
+ const PsDraggableGridHandle = ({ attributes, label, listeners, setActivatorNodeRef, }) => ((0, jsx_runtime_1.jsx)("button", { ...attributes, ...listeners, "aria-label": `Move ${label}`, className: ps_draggable_grid_1.PsDraggableGridClasses.handle, ref: setActivatorNodeRef, title: `Move ${label}`, type: 'button', children: (0, jsx_runtime_1.jsx)(DragHandleIcon, {}) }));
29
+ const PsSortableGridItem = ({ className, index, item, renderItem, }) => {
30
+ const { attributes, isDragging, listeners, setActivatorNodeRef, setNodeRef, transform, transition, } = (0, sortable_1.useSortable)({ id: item.id });
31
+ const rendered = renderItem({
32
+ handle: ((0, jsx_runtime_1.jsx)(PsDraggableGridHandle, { attributes: attributes, label: item.label, listeners: listeners, setActivatorNodeRef: setActivatorNodeRef })),
33
+ index,
34
+ isDragging,
35
+ isOverlay: false,
36
+ item,
37
+ });
38
+ if (!rendered)
39
+ return null;
40
+ return ((0, jsx_runtime_1.jsx)("div", { className: `${ps_draggable_grid_1.PsDraggableGridClasses.item} ${className} ${isDragging ? ps_draggable_grid_1.PsDraggableGridClasses.placeholder : ''}`, ref: setNodeRef, style: {
41
+ opacity: isDragging ? ps_draggable_grid_1.PsDraggableGridConfig.placeholderOpacity : undefined,
42
+ transform: utilities_1.CSS.Translate.toString(transform),
43
+ transition,
44
+ }, children: rendered }));
10
45
  };
11
- let draggedItemId;
12
- let latestItems = [];
13
- const DragHandleIcon = () => ((0, jsx_runtime_1.jsx)("span", { "aria-hidden": 'true', className: 'grid grid-cols-2 gap-[0.1875rem]', children: Array.from({ length: 6 }).map((_, index) => ((0, jsx_runtime_1.jsx)("span", { className: 'h-0.5 w-0.5 rounded-full bg-current' }, index))) }));
14
46
  const PsDraggableGrid = ({ getItemClassName, items, onReorder, onReorderEnd, renderItem, }) => {
15
- latestItems = items;
16
- const finishDrag = () => {
17
- if (!draggedItemId)
18
- return;
19
- draggedItemId = undefined;
20
- onReorderEnd?.(latestItems);
21
- };
22
- const moveDraggedItemTo = (targetItemId) => {
23
- if (!draggedItemId || draggedItemId === targetItemId)
47
+ const [activeId, setActiveId] = (0, react_1.useState)(null);
48
+ const [isMounted, setIsMounted] = (0, react_1.useState)(false);
49
+ (0, react_1.useEffect)(() => setIsMounted(true), []);
50
+ const sensors = (0, core_1.useSensors)((0, core_1.useSensor)(core_1.MouseSensor, {
51
+ activationConstraint: { distance: ps_draggable_grid_1.PsDraggableGridConfig.activationDistance },
52
+ }), (0, core_1.useSensor)(core_1.TouchSensor, {
53
+ activationConstraint: {
54
+ delay: ps_draggable_grid_1.PsDraggableGridConfig.touchDelay,
55
+ tolerance: ps_draggable_grid_1.PsDraggableGridConfig.touchTolerance,
56
+ },
57
+ }), (0, core_1.useSensor)(core_1.KeyboardSensor, { coordinateGetter: sortable_1.sortableKeyboardCoordinates }));
58
+ const className = (item) => getItemClassName !== undefined ? getItemClassName(item) : '';
59
+ const activeIndex = items.findIndex((item) => item.id === activeId);
60
+ const activeItem = activeIndex >= 0 ? items[activeIndex] : null;
61
+ const handleDragEnd = (event) => {
62
+ setActiveId(null);
63
+ if (event.over === null || event.active.id === event.over.id)
24
64
  return;
25
- const currentItems = latestItems;
26
- const fromIndex = currentItems.findIndex((item) => item.id === draggedItemId);
27
- const toIndex = currentItems.findIndex((item) => item.id === targetItemId);
28
- if (fromIndex < 0 || toIndex < 0 || fromIndex === toIndex)
65
+ const fromIndex = items.findIndex((item) => item.id === event.active.id);
66
+ const toIndex = items.findIndex((item) => item.id === event.over?.id);
67
+ if (fromIndex < 0 || toIndex < 0)
29
68
  return;
30
- const nextItems = moveItem(currentItems, fromIndex, toIndex);
31
- latestItems = nextItems;
69
+ const nextItems = (0, sortable_1.arrayMove)(items, fromIndex, toIndex);
32
70
  onReorder(nextItems);
71
+ if (onReorderEnd !== undefined)
72
+ onReorderEnd(nextItems);
33
73
  };
34
- return ((0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: items.map((item, index) => {
35
- const isDragging = false;
36
- const handle = ((0, jsx_runtime_1.jsx)("button", { "aria-label": `Move ${item.label}`, className: 'ps-focus-ring inline-flex h-6 w-6 shrink-0 cursor-grab items-center justify-center rounded-full text-slate-400/55 opacity-45 transition hover:bg-white/36 hover:text-slate-600 hover:opacity-90 active:cursor-grabbing dark:text-slate-300/45 dark:hover:bg-white/8 dark:hover:text-slate-100', draggable: true, onDragEnd: finishDrag, onDragStart: (event) => {
37
- event.dataTransfer.effectAllowed = 'move';
38
- event.dataTransfer.setData('text/plain', item.id);
39
- draggedItemId = item.id;
40
- }, title: `Move ${item.label}`, type: 'button', children: (0, jsx_runtime_1.jsx)(DragHandleIcon, {}) }));
41
- const renderedItem = renderItem({ handle, index, isDragging, item });
42
- const itemClassName = getItemClassName?.(item);
43
- if (!renderedItem)
44
- return null;
45
- return ((0, jsx_runtime_1.jsx)("div", { className: `ps-page-enter min-w-0 rounded-[1.7rem] transition ${itemClassName !== null && itemClassName !== undefined ? itemClassName : ''} ${isDragging ? 'scale-[0.985] opacity-70' : ''}`, onDragOver: (event) => {
46
- if (!draggedItemId)
47
- return;
48
- event.preventDefault();
49
- event.dataTransfer.dropEffect = 'move';
50
- moveDraggedItemTo(item.id);
51
- }, onDrop: (event) => {
52
- event.preventDefault();
53
- finishDrag();
54
- }, children: renderedItem }, item.id));
55
- }) }));
74
+ return ((0, jsx_runtime_1.jsxs)(core_1.DndContext, { collisionDetection: core_1.closestCenter, onDragCancel: () => setActiveId(null), onDragEnd: handleDragEnd, onDragStart: (event) => setActiveId(String(event.active.id)), sensors: sensors, children: [(0, jsx_runtime_1.jsx)(sortable_1.SortableContext, { items: items.map((item) => item.id), strategy: sortable_1.rectSortingStrategy, children: items.map((item, index) => ((0, jsx_runtime_1.jsx)(PsSortableGridItem, { className: className(item), index: index, item: item, renderItem: renderItem }, item.id))) }), isMounted
75
+ ? (0, react_dom_1.createPortal)((0, jsx_runtime_1.jsx)(core_1.DragOverlay, { dropAnimation: dropAnimation, children: activeItem !== null ? ((0, jsx_runtime_1.jsx)("div", { className: ps_draggable_grid_1.PsDraggableGridClasses.lifted, ref: liftCard, children: renderItem({
76
+ handle: (0, jsx_runtime_1.jsx)(PsDraggableGridHandle, { label: activeItem.label }),
77
+ index: activeIndex,
78
+ isDragging: true,
79
+ isOverlay: true,
80
+ item: activeItem,
81
+ }) })) : null }), document.body)
82
+ : null] }));
56
83
  };
57
84
  exports.PsDraggableGrid = PsDraggableGrid;
@@ -2,8 +2,9 @@ export interface PsNavigationProgressProps {
2
2
  className?: string;
3
3
  color?: string;
4
4
  height?: number;
5
+ isLoading?: boolean;
5
6
  label?: string;
6
- progress: number;
7
+ progress?: number;
7
8
  shadow?: boolean;
8
9
  }
9
- export declare const PsNavigationProgress: ({ className, color, height, label, progress, shadow, }: PsNavigationProgressProps) => import("react").JSX.Element;
10
+ export declare const PsNavigationProgress: ({ className, color, height, isLoading, label, progress, shadow, }: PsNavigationProgressProps) => import("react").JSX.Element;
@@ -2,33 +2,24 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.PsNavigationProgress = void 0;
4
4
  const jsx_runtime_1 = require("react/jsx-runtime");
5
- const react_1 = require("react");
6
5
  const ps_design_system_1 = require("@pallasoft/ps-design-system");
7
6
  const ps_navigation_progress_config_1 = require("../constants/ps-navigation-progress-config");
8
- const PsNavigationProgress = ({ className, color = ps_navigation_progress_config_1.PsNavigationProgressConfig.defaultColor, height = ps_navigation_progress_config_1.PsNavigationProgressConfig.defaultHeight, label = ps_navigation_progress_config_1.PsNavigationProgressConfig.defaultLabel, progress, shadow = true, }) => {
9
- const [isVisible, setIsVisible] = (0, react_1.useState)(false);
10
- const hideTimer = (0, react_1.useRef)(null);
11
- (0, react_1.useEffect)(() => {
12
- if (typeof window === 'undefined')
13
- return;
14
- if (hideTimer.current !== null)
15
- window.clearTimeout(hideTimer.current);
16
- if (progress > 0 && progress < 100) {
17
- setIsVisible(true);
18
- return;
19
- }
20
- hideTimer.current = window.setTimeout(() => setIsVisible(false), ps_navigation_progress_config_1.PsNavigationProgressConfig.fadeMs);
21
- return () => {
22
- if (hideTimer.current !== null)
23
- window.clearTimeout(hideTimer.current);
24
- };
25
- }, [progress]);
26
- return ((0, jsx_runtime_1.jsx)("div", { "aria-hidden": isVisible ? undefined : 'true', "aria-label": label, "aria-valuemax": 100, "aria-valuemin": 0, "aria-valuenow": Math.round(progress), className: ps_design_system_1.PallasoftClassNameService.merge('pointer-events-none fixed inset-x-0 top-0', className), role: 'progressbar', style: { height, zIndex: ps_design_system_1.PallasoftZIndex.Toast }, children: (0, jsx_runtime_1.jsx)("div", { className: 'h-full origin-left transition-[width,opacity] ease-out', style: {
7
+ const use_ps_navigation_progress_1 = require("../hooks/use-ps-navigation-progress");
8
+ const PsNavigationProgress = ({ className, color = ps_navigation_progress_config_1.PsNavigationProgressConfig.defaultColor, height = ps_navigation_progress_config_1.PsNavigationProgressConfig.defaultHeight, isLoading, label = ps_navigation_progress_config_1.PsNavigationProgressConfig.defaultLabel, progress, shadow = true, }) => {
9
+ const { isAnimated, isVisible, width } = (0, use_ps_navigation_progress_1.usePsNavigationProgress)(isLoading !== undefined
10
+ ? isLoading
11
+ : progress !== undefined &&
12
+ progress > 0 &&
13
+ progress < ps_navigation_progress_config_1.PsNavigationProgressConfig.completeWidth);
14
+ return ((0, jsx_runtime_1.jsx)("div", { "aria-hidden": isVisible ? undefined : 'true', "aria-label": label, "aria-valuemax": 100, "aria-valuemin": 0, "aria-valuenow": Math.round(width), className: ps_design_system_1.PallasoftClassNameService.merge('pointer-events-none fixed inset-x-0 top-0', className), role: 'progressbar', style: { height, zIndex: ps_design_system_1.PallasoftZIndex.Toast }, children: (0, jsx_runtime_1.jsx)("div", { className: 'h-full origin-left ease-out', style: {
27
15
  backgroundColor: color,
28
16
  boxShadow: shadow ? `0 0 10px ${color}, 0 0 5px ${color}` : undefined,
29
17
  opacity: isVisible ? 1 : 0,
30
- transitionDuration: `${ps_navigation_progress_config_1.PsNavigationProgressConfig.transitionMs}ms`,
31
- width: `${Math.min(Math.max(progress, 0), 100)}%`,
18
+ transitionDuration: isAnimated
19
+ ? `${ps_navigation_progress_config_1.PsNavigationProgressConfig.transitionMs}ms, ${ps_navigation_progress_config_1.PsNavigationProgressConfig.fadeMs}ms`
20
+ : '0ms',
21
+ transitionProperty: 'width, opacity',
22
+ width: `${Math.min(Math.max(width, 0), 100)}%`,
32
23
  } }) }));
33
24
  };
34
25
  exports.PsNavigationProgress = PsNavigationProgress;
@@ -2,5 +2,5 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.PsSectionHeader = void 0;
4
4
  const jsx_runtime_1 = require("react/jsx-runtime");
5
- const PsSectionHeader = ({ description, eyebrow, leading, title, trailing, }) => ((0, jsx_runtime_1.jsxs)("div", { className: 'flex flex-col justify-between gap-3 lg:flex-row lg:items-end', children: [(0, jsx_runtime_1.jsxs)("div", { className: 'flex min-w-0 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: 'text-2xl font-extrabold text-ink', children: title }), description ? ((0, jsx_runtime_1.jsx)("p", { className: 'max-w-3xl text-sm leading-6 text-ink/60', children: description })) : null] }), trailing] }));
5
+ const PsSectionHeader = ({ description, eyebrow, leading, title, trailing, }) => ((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: 'ml-auto flex shrink-0 items-center', children: trailing }) : null] }));
6
6
  exports.PsSectionHeader = PsSectionHeader;
@@ -0,0 +1,4 @@
1
+ export interface PsSkeletonCardProps {
2
+ className?: string;
3
+ }
4
+ export declare const PsSkeletonCard: ({ className }: PsSkeletonCardProps) => import("react").JSX.Element;
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PsSkeletonCard = 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_skeleton_1 = require("./ps-skeleton");
7
+ const ps_skeleton_group_1 = require("./ps-skeleton-group");
8
+ const PsSkeletonCard = ({ className }) => ((0, jsx_runtime_1.jsxs)(ps_skeleton_group_1.PsSkeletonGroup, { className: ps_design_system_1.PallasoftClassNameService.merge('flex flex-col gap-3 rounded-[1.25rem] border border-line bg-surface p-5', className), children: [(0, jsx_runtime_1.jsx)(ps_skeleton_1.PsSkeleton, { className: 'h-2.5 w-24' }), (0, jsx_runtime_1.jsx)(ps_skeleton_1.PsSkeleton, { className: 'h-6 w-32' })] }));
9
+ exports.PsSkeletonCard = PsSkeletonCard;
@@ -0,0 +1,7 @@
1
+ import type { ReactNode } from 'react';
2
+ export interface PsSkeletonGroupProps {
3
+ children: ReactNode;
4
+ className?: string;
5
+ label?: string;
6
+ }
7
+ export declare const PsSkeletonGroup: ({ children, className, label, }: PsSkeletonGroupProps) => import("react").JSX.Element;
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PsSkeletonGroup = void 0;
4
+ const jsx_runtime_1 = require("react/jsx-runtime");
5
+ const PsSkeletonGroup = ({ children, className, label = 'Loading', }) => ((0, jsx_runtime_1.jsxs)("div", { "aria-busy": 'true', className: className, role: 'status', children: [(0, jsx_runtime_1.jsx)("span", { className: 'sr-only', children: label }), children] }));
6
+ exports.PsSkeletonGroup = PsSkeletonGroup;
@@ -0,0 +1,8 @@
1
+ export interface PsSkeletonListProps {
2
+ className?: string;
3
+ hasLeading?: boolean;
4
+ hasTrailing?: boolean;
5
+ rows?: number;
6
+ title?: boolean;
7
+ }
8
+ export declare const PsSkeletonList: ({ className, hasLeading, hasTrailing, rows, title, }: PsSkeletonListProps) => import("react").JSX.Element;
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PsSkeletonList = 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_skeleton_config_1 = require("../constants/ps-skeleton-config");
7
+ const ps_skeleton_1 = require("./ps-skeleton");
8
+ const ps_skeleton_group_1 = require("./ps-skeleton-group");
9
+ const PsSkeletonList = ({ className, hasLeading = false, hasTrailing = true, rows = 4, title = false, }) => ((0, jsx_runtime_1.jsxs)(ps_skeleton_group_1.PsSkeletonGroup, { className: ps_design_system_1.PallasoftClassNameService.merge('flex flex-col', className), children: [title ? (0, jsx_runtime_1.jsx)(ps_skeleton_1.PsSkeleton, { className: 'mx-3 mb-3 h-2.5 w-24' }) : null, Array.from({ length: rows }, (_, index) => ((0, jsx_runtime_1.jsxs)("div", { className: 'flex min-h-11 items-center gap-3 px-3 py-2.5', children: [hasLeading ? (0, jsx_runtime_1.jsx)(ps_skeleton_1.PsSkeleton, { shape: 'circle' }) : null, (0, jsx_runtime_1.jsx)(ps_skeleton_1.PsSkeleton, { className: ps_skeleton_config_1.PsSkeletonConfig.lineWidths[index % ps_skeleton_config_1.PsSkeletonConfig.lineWidths.length] }), hasTrailing ? (0, jsx_runtime_1.jsx)(ps_skeleton_1.PsSkeleton, { className: 'ml-auto h-2.5 w-20 shrink-0' }) : null] }, index)))] }));
10
+ exports.PsSkeletonList = PsSkeletonList;
@@ -0,0 +1,7 @@
1
+ export interface PsSkeletonTableProps {
2
+ className?: string;
3
+ columns?: number;
4
+ hasToolbar?: boolean;
5
+ rows?: number;
6
+ }
7
+ export declare const PsSkeletonTable: ({ className, columns, hasToolbar, rows, }: PsSkeletonTableProps) => import("react").JSX.Element;
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PsSkeletonTable = 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_skeleton_config_1 = require("../constants/ps-skeleton-config");
7
+ const ps_skeleton_1 = require("./ps-skeleton");
8
+ const ps_skeleton_group_1 = require("./ps-skeleton-group");
9
+ const PsSkeletonTable = ({ className, columns = 4, hasToolbar = false, rows = 6, }) => {
10
+ const gridTemplateColumns = `minmax(0, 2fr) repeat(${Math.max(columns - 1, 0)}, minmax(0, 1fr))`;
11
+ return ((0, jsx_runtime_1.jsxs)(ps_skeleton_group_1.PsSkeletonGroup, { className: ps_design_system_1.PallasoftClassNameService.merge('flex flex-col gap-3', className), children: [hasToolbar ? ((0, jsx_runtime_1.jsxs)("div", { className: 'flex items-center gap-3', children: [(0, jsx_runtime_1.jsx)(ps_skeleton_1.PsSkeleton, { className: 'max-w-sm', shape: 'block' }), (0, jsx_runtime_1.jsx)(ps_skeleton_1.PsSkeleton, { className: 'ml-auto w-24', shape: 'block' })] })) : null, (0, jsx_runtime_1.jsxs)("div", { className: 'overflow-hidden rounded-[1.25rem] border border-line bg-surface', children: [(0, jsx_runtime_1.jsx)("div", { className: 'grid gap-4 bg-mist/70 px-5 py-4', style: { gridTemplateColumns }, children: Array.from({ length: columns }, (_, index) => ((0, jsx_runtime_1.jsx)(ps_skeleton_1.PsSkeleton, { className: 'h-2.5 w-16' }, index))) }), Array.from({ length: rows }, (_, rowIndex) => ((0, jsx_runtime_1.jsx)("div", { className: 'grid items-center gap-4 border-t border-line px-5 py-4', style: { gridTemplateColumns }, children: Array.from({ length: columns }, (__, columnIndex) => ((0, jsx_runtime_1.jsx)(ps_skeleton_1.PsSkeleton, { className: columnIndex === columns - 1 && columns > 1
12
+ ? 'ml-auto w-16'
13
+ : ps_skeleton_config_1.PsSkeletonConfig.lineWidths[(rowIndex + columnIndex) % ps_skeleton_config_1.PsSkeletonConfig.lineWidths.length] }, columnIndex))) }, rowIndex)))] })] }));
14
+ };
15
+ exports.PsSkeletonTable = PsSkeletonTable;
@@ -0,0 +1,5 @@
1
+ export interface PsSkeletonTextProps {
2
+ className?: string;
3
+ lines?: number;
4
+ }
5
+ export declare const PsSkeletonText: ({ className, lines }: PsSkeletonTextProps) => import("react").JSX.Element;
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PsSkeletonText = 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_skeleton_config_1 = require("../constants/ps-skeleton-config");
7
+ const ps_skeleton_1 = require("./ps-skeleton");
8
+ const ps_skeleton_group_1 = require("./ps-skeleton-group");
9
+ const PsSkeletonText = ({ className, lines = 3 }) => ((0, jsx_runtime_1.jsx)(ps_skeleton_group_1.PsSkeletonGroup, { className: ps_design_system_1.PallasoftClassNameService.merge('flex flex-col gap-2.5', className), children: Array.from({ length: lines }, (_, index) => ((0, jsx_runtime_1.jsx)(ps_skeleton_1.PsSkeleton, { className: index === lines - 1 && lines > 1
10
+ ? 'w-2/3'
11
+ : ps_skeleton_config_1.PsSkeletonConfig.lineWidths[index % ps_skeleton_config_1.PsSkeletonConfig.lineWidths.length] }, index))) }));
12
+ exports.PsSkeletonText = PsSkeletonText;
@@ -1,4 +1,6 @@
1
+ export type PsSkeletonShape = 'block' | 'circle' | 'line';
1
2
  export interface PsSkeletonProps {
2
3
  className?: string;
4
+ shape?: PsSkeletonShape;
3
5
  }
4
- export declare const PsSkeleton: ({ className }: PsSkeletonProps) => import("react").JSX.Element;
6
+ export declare const PsSkeleton: ({ className, shape }: PsSkeletonProps) => import("react").JSX.Element;
@@ -3,5 +3,10 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.PsSkeleton = 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 PsSkeleton = ({ className }) => ((0, jsx_runtime_1.jsx)("div", { className: ps_design_system_1.PallasoftClassNameService.merge('animate-pulse rounded-full bg-mist', className) }));
6
+ const shapeClassNames = {
7
+ block: 'h-11 w-full rounded-ps-control',
8
+ circle: 'h-9 w-9 shrink-0 rounded-full',
9
+ line: 'h-3 w-full rounded-full',
10
+ };
11
+ const PsSkeleton = ({ className, shape = 'line' }) => ((0, jsx_runtime_1.jsx)("span", { "aria-hidden": 'true', className: ps_design_system_1.PallasoftClassNameService.merge('ps-skeleton', shapeClassNames[shape], className) }));
7
12
  exports.PsSkeleton = PsSkeleton;
@@ -0,0 +1,17 @@
1
+ export declare const PsDraggableGridConfig: {
2
+ readonly activationDistance: 6;
3
+ readonly dropDuration: 220;
4
+ readonly dropEasing: "cubic-bezier(0.2, 0.8, 0.2, 1)";
5
+ readonly liftDuration: 200;
6
+ readonly liftEasing: "cubic-bezier(0.2, 0.9, 0.3, 1.2)";
7
+ readonly placeholderOpacity: "0.4";
8
+ readonly touchDelay: 180;
9
+ readonly touchTolerance: 6;
10
+ };
11
+ export declare const PsDraggableGridClasses: {
12
+ readonly handle: "ps-focus-ring inline-flex h-7 w-7 shrink-0 cursor-grab touch-none items-center justify-center rounded-full text-slate-400/70 transition hover:bg-white/36 hover:text-slate-600 active:cursor-grabbing dark:text-slate-300/55 dark:hover:bg-white/8 dark:hover:text-slate-100";
13
+ readonly item: "min-w-0 rounded-[1.7rem]";
14
+ readonly lifted: "cursor-grabbing rounded-[1.7rem] ring-1 ring-primary/30";
15
+ readonly placeholder: "rounded-[1.7rem] outline-dashed outline-2 outline-offset-[-2px] outline-primary/35";
16
+ };
17
+ export declare const PsDraggableGridLiftFrames: Keyframe[];
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PsDraggableGridLiftFrames = exports.PsDraggableGridClasses = exports.PsDraggableGridConfig = void 0;
4
+ exports.PsDraggableGridConfig = {
5
+ activationDistance: 6,
6
+ dropDuration: 220,
7
+ dropEasing: 'cubic-bezier(0.2, 0.8, 0.2, 1)',
8
+ liftDuration: 200,
9
+ liftEasing: 'cubic-bezier(0.2, 0.9, 0.3, 1.2)',
10
+ placeholderOpacity: '0.4',
11
+ touchDelay: 180,
12
+ touchTolerance: 6,
13
+ };
14
+ exports.PsDraggableGridClasses = {
15
+ handle: 'ps-focus-ring inline-flex h-7 w-7 shrink-0 cursor-grab touch-none items-center justify-center rounded-full text-slate-400/70 transition hover:bg-white/36 hover:text-slate-600 active:cursor-grabbing dark:text-slate-300/55 dark:hover:bg-white/8 dark:hover:text-slate-100',
16
+ item: 'min-w-0 rounded-[1.7rem]',
17
+ lifted: 'cursor-grabbing rounded-[1.7rem] ring-1 ring-primary/30',
18
+ placeholder: 'rounded-[1.7rem] outline-dashed outline-2 outline-offset-[-2px] outline-primary/35',
19
+ };
20
+ exports.PsDraggableGridLiftFrames = [
21
+ { boxShadow: '0 0 0 0 rgb(15 23 42 / 0)', transform: 'scale(1) rotate(0deg)' },
22
+ {
23
+ boxShadow: '0 28px 64px -18px rgb(15 23 42 / 0.5)',
24
+ transform: 'scale(1.035) rotate(-1.2deg)',
25
+ },
26
+ ];
@@ -1,7 +1,12 @@
1
1
  export declare const PsNavigationProgressConfig: {
2
+ readonly completeWidth: 100;
2
3
  readonly defaultColor: "rgb(var(--ps-color-primary-rgb))";
3
4
  readonly defaultHeight: 3;
4
5
  readonly defaultLabel: "Page loading";
5
6
  readonly fadeMs: 320;
7
+ readonly startWidth: 12;
6
8
  readonly transitionMs: 240;
9
+ readonly trickleFactor: 0.14;
10
+ readonly trickleMax: 90;
11
+ readonly trickleMs: 260;
7
12
  };
@@ -2,9 +2,14 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.PsNavigationProgressConfig = void 0;
4
4
  exports.PsNavigationProgressConfig = {
5
+ completeWidth: 100,
5
6
  defaultColor: 'rgb(var(--ps-color-primary-rgb))',
6
7
  defaultHeight: 3,
7
8
  defaultLabel: 'Page loading',
8
9
  fadeMs: 320,
10
+ startWidth: 12,
9
11
  transitionMs: 240,
12
+ trickleFactor: 0.14,
13
+ trickleMax: 90,
14
+ trickleMs: 260,
10
15
  };
@@ -0,0 +1,3 @@
1
+ export declare const PsSkeletonConfig: {
2
+ readonly lineWidths: readonly ["w-3/4", "w-1/2", "w-5/6", "w-2/3"];
3
+ };
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PsSkeletonConfig = void 0;
4
+ exports.PsSkeletonConfig = {
5
+ lineWidths: ['w-3/4', 'w-1/2', 'w-5/6', 'w-2/3'],
6
+ };
@@ -0,0 +1,5 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { PallasoftClassNameService } from '@pallasoft/ps-design-system';
3
+ import { PsIcon, PsIconKey } from '@pallasoft/ps-icons';
4
+ import * as AccordionPrimitive from '@radix-ui/react-accordion';
5
+ export const PsAccordion = ({ children, className, isOpen, label, onToggle, trailing, }) => (_jsx(AccordionPrimitive.Root, { type: 'single', collapsible: true, value: isOpen ? 'open' : '', onValueChange: onToggle, className: PallasoftClassNameService.merge('overflow-hidden rounded-ps-card border border-line/70 bg-surface/60 transition-colors duration-200', isOpen ? 'border-primary/25 bg-surface' : 'hover:border-line hover:bg-surface/90', className), children: _jsxs(AccordionPrimitive.Item, { value: 'open', children: [_jsx(AccordionPrimitive.Header, { children: _jsxs(AccordionPrimitive.Trigger, { className: 'ps-focus-ring flex w-full items-center justify-between gap-3 px-4 py-3.5 text-left', children: [_jsx("span", { className: 'text-body-2 font-semibold text-ink', children: label }), _jsxs("span", { className: 'flex shrink-0 items-center gap-2', children: [trailing, _jsx(PsIcon, { iconKey: PsIconKey.ChevronRight, className: PallasoftClassNameService.merge('h-4 w-4 text-ink/40 transition-transform duration-200', isOpen ? 'rotate-90 text-primary' : '') })] })] }) }), _jsx(AccordionPrimitive.Content, { className: 'ps-accordion-content', children: _jsx("div", { className: 'border-t border-line/70 p-4', children: children }) })] }) }));
@@ -0,0 +1,7 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { PallasoftClassNameService } from '@pallasoft/ps-design-system';
3
+ const variantClassNames = {
4
+ default: 'ps-action-tile',
5
+ primary: 'ps-action-tile ps-action-tile-primary',
6
+ };
7
+ export const PsActionTile = ({ className, description, icon, label, type = 'button', variant = 'default', ...props }) => (_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] }));
@@ -0,0 +1,9 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { PallasoftClassNameService } from '@pallasoft/ps-design-system';
3
+ const MinBarHeightPercent = 10;
4
+ export const PsAudioSpectrum = (props) => {
5
+ return (_jsx("div", { className: PallasoftClassNameService.merge('flex h-full w-full items-end gap-2', props.className), children: props.levels.map((level, index) => {
6
+ const heightPercent = MinBarHeightPercent + Math.max(0, Math.min(1, level)) * (100 - MinBarHeightPercent);
7
+ return (_jsx("span", { className: 'min-w-0 flex-1 rounded-full bg-[linear-gradient(180deg,_rgb(var(--ps-color-primary-rgb)/0.25)_0%,_rgb(var(--ps-color-primary-rgb))_100%)] transition-[height] duration-100 ease-out', style: { height: `${heightPercent}%` } }, index));
8
+ }) }));
9
+ };
@@ -0,0 +1,10 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { PallasoftClassNameService } from '@pallasoft/ps-design-system';
3
+ const toneClassNames = {
4
+ danger: 'bg-danger-soft text-danger dark:bg-rose-500/18 dark:text-rose-100',
5
+ neutral: 'bg-slate-100 text-slate-700 dark:bg-white/10 dark:text-slate-100',
6
+ primary: 'bg-primary-soft text-ink dark:bg-primary/22 dark:text-white',
7
+ success: 'bg-success-soft text-emerald-700 dark:bg-emerald-400/18 dark:text-emerald-50',
8
+ warning: 'bg-warning-soft text-amber-800 dark:bg-amber-400/18 dark:text-amber-50',
9
+ };
10
+ export const PsBadge = ({ children, className, tone = 'neutral' }) => (_jsx("span", { className: PallasoftClassNameService.merge('inline-flex min-h-7 w-fit items-center justify-center whitespace-nowrap rounded-full px-3 py-0.5 text-center text-xs font-semibold capitalize', toneClassNames[tone], className), children: children }));
@@ -0,0 +1,16 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { PallasoftClassNameService } from '@pallasoft/ps-design-system';
3
+ import { PsSpinner } from './ps-spinner';
4
+ const sizeClassNames = {
5
+ compact: 'min-h-9 px-3 py-2 text-sm',
6
+ default: 'min-h-10 px-4 py-2.5 text-sm',
7
+ large: 'min-h-11 px-5 py-3 text-sm',
8
+ };
9
+ const variantClassNames = {
10
+ danger: 'border-danger bg-danger text-white enabled:hover:opacity-90',
11
+ ghost: 'border-transparent bg-transparent text-ink/60 enabled:hover:text-ink',
12
+ primary: 'border-primary bg-primary text-[color:var(--ps-color-primary-contrast)] enabled:hover:border-primary-dark enabled:hover:bg-primary-dark',
13
+ 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',
14
+ surface: 'ps-liquid ps-liquid-control bg-white/72 text-ink enabled:hover:border-primary/30 dark:border-white/16 dark:bg-white/12',
15
+ };
16
+ export const PsButton = ({ children, className, disabled, isLoading = false, leadingIcon, loadingLabel, size = 'default', trailingIcon, type = 'button', variant = 'secondary', ...props }) => (_jsxs("button", { className: PallasoftClassNameService.merge('ps-focus-ring relative inline-flex max-w-full items-center justify-center gap-2 rounded-full border text-center font-semibold disabled:cursor-not-allowed disabled:opacity-50', sizeClassNames[size], variantClassNames[variant], className), "aria-busy": isLoading || undefined, disabled: disabled || isLoading, type: type, ...props, children: [isLoading ? (_jsx(PsSpinner, { className: 'absolute inset-0 m-auto', color: 'current', label: loadingLabel !== null && loadingLabel !== undefined ? loadingLabel : 'Loading', size: 'small' })) : null, _jsxs("span", { "aria-hidden": isLoading || undefined, className: PallasoftClassNameService.merge('inline-flex min-w-0 items-center gap-2', isLoading ? 'invisible' : ''), children: [leadingIcon ? _jsx("span", { className: 'shrink-0', children: leadingIcon }) : null, _jsx("span", { className: 'truncate', children: children }), trailingIcon ? _jsx("span", { className: 'shrink-0', children: trailingIcon }) : null] })] }));
@@ -0,0 +1,14 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { PallasoftClassNameService } from '@pallasoft/ps-design-system';
3
+ const densityClassNames = {
4
+ compact: 'p-3',
5
+ normal: 'p-4',
6
+ spacious: 'p-5',
7
+ };
8
+ const variantClassNames = {
9
+ default: 'ps-card',
10
+ elevated: 'ps-card',
11
+ glass: 'ps-glass',
12
+ muted: 'ps-card-muted',
13
+ };
14
+ export const PsCard = ({ children, className, density = 'normal', eyebrow, title, trailing, variant = 'default', }) => (_jsxs("section", { className: PallasoftClassNameService.merge('min-w-0 overflow-hidden rounded-ps-card', variantClassNames[variant], densityClassNames[density], className), children: [title ? (_jsxs("div", { className: 'mb-3 flex min-w-0 items-start justify-between gap-3', children: [_jsxs("div", { className: 'min-w-0', children: [eyebrow ? _jsx("p", { className: 'ps-eyebrow break-words', children: eyebrow }) : null, _jsx("h2", { className: 'mt-1 break-words text-base font-bold text-ink', children: title })] }), trailing ? _jsx("div", { className: 'shrink-0', children: trailing }) : null] })) : null, children] }));
@@ -0,0 +1,80 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useEffect, useState } from 'react';
3
+ import { DndContext, DragOverlay, KeyboardSensor, MouseSensor, TouchSensor, closestCenter, defaultDropAnimationSideEffects, useSensor, useSensors, } from '@dnd-kit/core';
4
+ import { SortableContext, arrayMove, rectSortingStrategy, sortableKeyboardCoordinates, useSortable, } from '@dnd-kit/sortable';
5
+ import { CSS } from '@dnd-kit/utilities';
6
+ import { createPortal } from 'react-dom';
7
+ import { PsDraggableGridClasses, PsDraggableGridConfig, PsDraggableGridLiftFrames, } from '../constants/ps-draggable-grid';
8
+ const liftCard = (element) => {
9
+ if (element === null)
10
+ return;
11
+ element.animate(PsDraggableGridLiftFrames, {
12
+ duration: PsDraggableGridConfig.liftDuration,
13
+ easing: PsDraggableGridConfig.liftEasing,
14
+ fill: 'forwards',
15
+ });
16
+ };
17
+ const dropAnimation = {
18
+ duration: PsDraggableGridConfig.dropDuration,
19
+ easing: PsDraggableGridConfig.dropEasing,
20
+ sideEffects: defaultDropAnimationSideEffects({
21
+ styles: { active: { opacity: PsDraggableGridConfig.placeholderOpacity } },
22
+ }),
23
+ };
24
+ const DragHandleIcon = () => (_jsx("span", { "aria-hidden": 'true', className: 'grid grid-cols-2 gap-[0.1875rem]', children: Array.from({ length: 6 }).map((_, index) => (_jsx("span", { className: 'h-[3px] w-[3px] rounded-full bg-current' }, index))) }));
25
+ const PsDraggableGridHandle = ({ attributes, label, listeners, setActivatorNodeRef, }) => (_jsx("button", { ...attributes, ...listeners, "aria-label": `Move ${label}`, className: PsDraggableGridClasses.handle, ref: setActivatorNodeRef, title: `Move ${label}`, type: 'button', children: _jsx(DragHandleIcon, {}) }));
26
+ const PsSortableGridItem = ({ className, index, item, renderItem, }) => {
27
+ const { attributes, isDragging, listeners, setActivatorNodeRef, setNodeRef, transform, transition, } = useSortable({ id: item.id });
28
+ const rendered = renderItem({
29
+ handle: (_jsx(PsDraggableGridHandle, { attributes: attributes, label: item.label, listeners: listeners, setActivatorNodeRef: setActivatorNodeRef })),
30
+ index,
31
+ isDragging,
32
+ isOverlay: false,
33
+ item,
34
+ });
35
+ if (!rendered)
36
+ return null;
37
+ return (_jsx("div", { className: `${PsDraggableGridClasses.item} ${className} ${isDragging ? PsDraggableGridClasses.placeholder : ''}`, ref: setNodeRef, style: {
38
+ opacity: isDragging ? PsDraggableGridConfig.placeholderOpacity : undefined,
39
+ transform: CSS.Translate.toString(transform),
40
+ transition,
41
+ }, children: rendered }));
42
+ };
43
+ export const PsDraggableGrid = ({ getItemClassName, items, onReorder, onReorderEnd, renderItem, }) => {
44
+ const [activeId, setActiveId] = useState(null);
45
+ const [isMounted, setIsMounted] = useState(false);
46
+ useEffect(() => setIsMounted(true), []);
47
+ const sensors = useSensors(useSensor(MouseSensor, {
48
+ activationConstraint: { distance: PsDraggableGridConfig.activationDistance },
49
+ }), useSensor(TouchSensor, {
50
+ activationConstraint: {
51
+ delay: PsDraggableGridConfig.touchDelay,
52
+ tolerance: PsDraggableGridConfig.touchTolerance,
53
+ },
54
+ }), useSensor(KeyboardSensor, { coordinateGetter: sortableKeyboardCoordinates }));
55
+ const className = (item) => getItemClassName !== undefined ? getItemClassName(item) : '';
56
+ const activeIndex = items.findIndex((item) => item.id === activeId);
57
+ const activeItem = activeIndex >= 0 ? items[activeIndex] : null;
58
+ const handleDragEnd = (event) => {
59
+ setActiveId(null);
60
+ if (event.over === null || event.active.id === event.over.id)
61
+ return;
62
+ const fromIndex = items.findIndex((item) => item.id === event.active.id);
63
+ const toIndex = items.findIndex((item) => item.id === event.over?.id);
64
+ if (fromIndex < 0 || toIndex < 0)
65
+ return;
66
+ const nextItems = arrayMove(items, fromIndex, toIndex);
67
+ onReorder(nextItems);
68
+ if (onReorderEnd !== undefined)
69
+ onReorderEnd(nextItems);
70
+ };
71
+ return (_jsxs(DndContext, { collisionDetection: closestCenter, onDragCancel: () => setActiveId(null), onDragEnd: handleDragEnd, onDragStart: (event) => setActiveId(String(event.active.id)), sensors: sensors, children: [_jsx(SortableContext, { items: items.map((item) => item.id), strategy: rectSortingStrategy, children: items.map((item, index) => (_jsx(PsSortableGridItem, { className: className(item), index: index, item: item, renderItem: renderItem }, item.id))) }), isMounted
72
+ ? createPortal(_jsx(DragOverlay, { dropAnimation: dropAnimation, children: activeItem !== null ? (_jsx("div", { className: PsDraggableGridClasses.lifted, ref: liftCard, children: renderItem({
73
+ handle: _jsx(PsDraggableGridHandle, { label: activeItem.label }),
74
+ index: activeIndex,
75
+ isDragging: true,
76
+ isOverlay: true,
77
+ item: activeItem,
78
+ }) })) : null }), document.body)
79
+ : null] }));
80
+ };