@lablup/ui-common 0.2.0-alpha.17 → 0.2.0-alpha.18

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 (97) hide show
  1. package/README.md +1 -0
  2. package/astryx/components/Board.doc.mjs +122 -0
  3. package/astryx/components/Board.tsx +3 -0
  4. package/astryx/docs/ui-common.doc.mjs +1 -1
  5. package/dist/assets/components/Board/Board.css +2 -0
  6. package/dist/components/Board/Board.d.ts +102 -0
  7. package/dist/components/Board/Board.messages.d.ts +62 -0
  8. package/dist/components/Board/Board.messages.js +68 -0
  9. package/dist/components/Board/Board.messages.js.map +1 -0
  10. package/dist/components/Board/Board2.js +607 -0
  11. package/dist/components/Board/Board2.js.map +1 -0
  12. package/dist/components/Board/engine.d.ts +60 -0
  13. package/dist/components/Board/engine.js +397 -0
  14. package/dist/components/Board/engine.js.map +1 -0
  15. package/dist/components/Board/index.d.ts +4 -0
  16. package/dist/components/Board/index.js +3 -0
  17. package/dist/components/Board/layout.d.ts +81 -0
  18. package/dist/components/Board/layout.js +67 -0
  19. package/dist/components/Board/layout.js.map +1 -0
  20. package/dist/components/Board/scroll.d.ts +38 -0
  21. package/dist/components/Board/scroll.js +42 -0
  22. package/dist/components/Board/scroll.js.map +1 -0
  23. package/dist/components/DataGrid/DataGrid2.js +128 -128
  24. package/dist/components/DataGrid/DataGrid2.js.map +1 -1
  25. package/dist/components/Form/FormItem.d.ts +1 -1
  26. package/dist/components/PageHeader/PageHeader2.js +4 -4
  27. package/dist/components/PagedSelector/PagedSelector2.js +37 -37
  28. package/dist/components/PagedSelector/PagedSelector2.js.map +1 -1
  29. package/dist/components/SelectionLabel/SelectionLabel.js +4 -4
  30. package/dist/i18n/catalog.js +27 -25
  31. package/dist/i18n/catalog.js.map +1 -1
  32. package/dist/i18n/locales/de-DE.js +60 -0
  33. package/dist/i18n/locales/de-DE.js.map +1 -1
  34. package/dist/i18n/locales/el-GR.js +60 -0
  35. package/dist/i18n/locales/el-GR.js.map +1 -1
  36. package/dist/i18n/locales/es-ES.js +60 -0
  37. package/dist/i18n/locales/es-ES.js.map +1 -1
  38. package/dist/i18n/locales/fi-FI.js +60 -0
  39. package/dist/i18n/locales/fi-FI.js.map +1 -1
  40. package/dist/i18n/locales/fr-FR.js +60 -0
  41. package/dist/i18n/locales/fr-FR.js.map +1 -1
  42. package/dist/i18n/locales/id-ID.js +60 -0
  43. package/dist/i18n/locales/id-ID.js.map +1 -1
  44. package/dist/i18n/locales/it-IT.js +60 -0
  45. package/dist/i18n/locales/it-IT.js.map +1 -1
  46. package/dist/i18n/locales/ja-JP.js +60 -0
  47. package/dist/i18n/locales/ja-JP.js.map +1 -1
  48. package/dist/i18n/locales/ko-KR.js +60 -0
  49. package/dist/i18n/locales/ko-KR.js.map +1 -1
  50. package/dist/i18n/locales/mn-MN.js +60 -0
  51. package/dist/i18n/locales/mn-MN.js.map +1 -1
  52. package/dist/i18n/locales/ms-MY.js +60 -0
  53. package/dist/i18n/locales/ms-MY.js.map +1 -1
  54. package/dist/i18n/locales/pl-PL.js +60 -0
  55. package/dist/i18n/locales/pl-PL.js.map +1 -1
  56. package/dist/i18n/locales/pt-BR.js +60 -0
  57. package/dist/i18n/locales/pt-BR.js.map +1 -1
  58. package/dist/i18n/locales/pt-PT.js +60 -0
  59. package/dist/i18n/locales/pt-PT.js.map +1 -1
  60. package/dist/i18n/locales/ru-RU.js +60 -0
  61. package/dist/i18n/locales/ru-RU.js.map +1 -1
  62. package/dist/i18n/locales/th-TH.js +60 -0
  63. package/dist/i18n/locales/th-TH.js.map +1 -1
  64. package/dist/i18n/locales/tr-TR.js +60 -0
  65. package/dist/i18n/locales/tr-TR.js.map +1 -1
  66. package/dist/i18n/locales/vi-VN.js +60 -0
  67. package/dist/i18n/locales/vi-VN.js.map +1 -1
  68. package/dist/i18n/locales/zh-CN.js +60 -0
  69. package/dist/i18n/locales/zh-CN.js.map +1 -1
  70. package/dist/i18n/locales/zh-TW.js +60 -0
  71. package/dist/i18n/locales/zh-TW.js.map +1 -1
  72. package/dist/index.d.ts +2 -0
  73. package/dist/index.js +61 -59
  74. package/dist/instance.js +1 -1
  75. package/dist/ui-common-locales/de-DE.json +60 -0
  76. package/dist/ui-common-locales/el-GR.json +60 -0
  77. package/dist/ui-common-locales/en.json +60 -0
  78. package/dist/ui-common-locales/es-ES.json +60 -0
  79. package/dist/ui-common-locales/fi-FI.json +60 -0
  80. package/dist/ui-common-locales/fr-FR.json +60 -0
  81. package/dist/ui-common-locales/id-ID.json +60 -0
  82. package/dist/ui-common-locales/it-IT.json +60 -0
  83. package/dist/ui-common-locales/ja-JP.json +60 -0
  84. package/dist/ui-common-locales/ko-KR.json +60 -0
  85. package/dist/ui-common-locales/mn-MN.json +60 -0
  86. package/dist/ui-common-locales/ms-MY.json +60 -0
  87. package/dist/ui-common-locales/pl-PL.json +60 -0
  88. package/dist/ui-common-locales/pt-BR.json +60 -0
  89. package/dist/ui-common-locales/pt-PT.json +60 -0
  90. package/dist/ui-common-locales/ru-RU.json +60 -0
  91. package/dist/ui-common-locales/th-TH.json +60 -0
  92. package/dist/ui-common-locales/tr-TR.json +60 -0
  93. package/dist/ui-common-locales/vi-VN.json +60 -0
  94. package/dist/ui-common-locales/zh-CN.json +60 -0
  95. package/dist/ui-common-locales/zh-TW.json +60 -0
  96. package/exports.customs.json +1 -0
  97. package/package.json +1 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Board2.js","names":[],"sources":["../../../src/components/Board/Board.tsx"],"sourcesContent":["/**\n * Board\n *\n * A dashboard grid of items the user can move and resize. The column count\n * follows the board's width; items persist as spans plus a column offset per\n * column count, the model `@cloudscape-design/board-components` used, so a\n * stored layout renders the same here (see `./layout.ts`). The board is\n * controlled: `onItemsChange` reports the whole board in its new order, and\n * what the parent passes back is what renders.\n *\n * A drag handle at an item's top-left corner moves it, a handle at the\n * bottom-right resizes it. Dragging a handle moves or resizes by pointer: the\n * item follows the pointer, the rest of the board previews where everything\n * lands, and releasing snaps to the grid. Clicking a handle, or pressing\n * Enter or Space on it, activates it instead: direction buttons appear around\n * it, and they or the arrow keys move or resize one cell at a time; Enter,\n * Space or leaving the handle commits, Escape discards. Neither handle renders\n * unless `isMovable` / `isResizable` says so. How the other items make room\n * is `./engine.ts`; every step is announced in a live region.\n *\n * @example\n * <Board\n * items={items}\n * isMovable\n * isResizable\n * variant=\"bordered\"\n * renderItem={(item) => <Panel {...item.data} />}\n * onItemsChange={({ items }) => setItems(items)}\n * />\n */\nimport {\n useEffect,\n useRef,\n useState,\n type CSSProperties,\n type HTMLAttributes,\n type KeyboardEvent,\n type PointerEvent,\n type ReactNode,\n} from \"react\";\nimport { IconButton } from \"@astryxdesign/core/IconButton\";\nimport { VisuallyHidden } from \"@astryxdesign/core/VisuallyHidden\";\n\nimport { useUicTranslator } from \"../../i18n/useUicTranslator\";\nimport {\n appendPath,\n LayoutEngine,\n removeItem as removeFromLayout,\n type Direction,\n type LayoutShift,\n type Position,\n type Rect,\n} from \"./engine\";\nimport {\n getMinColumnSpan,\n getMinRowSpan,\n interpretItems,\n transformItems,\n type BoardItem,\n type GridLayout,\n} from \"./layout\";\nimport {\n autoScrollStep,\n compensateForScroll,\n findScrollParent,\n scrollBounds,\n type Point,\n} from \"./scroll\";\nimport \"./Board.css\";\n\nexport type BoardOperation = \"move\" | \"resize\";\n\nexport interface BoardItemPlacement {\n /** Column, from 0. */\n x: number;\n /** Row, from 0. */\n y: number;\n width: number;\n height: number;\n}\n\nexport interface BoardDndDetail<D = unknown> {\n item: BoardItem<D>;\n /** Where the item is at this step. */\n placement: BoardItemPlacement;\n}\n\nexport interface BoardItemRemovedDetail<D = unknown> {\n item: BoardItem<D>;\n}\n\nexport interface BoardItemsChangeDetail<D = unknown> {\n /** The whole board in its new order, spans and column offsets updated. */\n items: ReadonlyArray<BoardItem<D>>;\n movedItem?: BoardItem<D>;\n resizedItem?: BoardItem<D>;\n removedItem?: BoardItem<D>;\n}\n\nexport interface BoardItemActions {\n /** Removes the item: `onItemsChange` fires with the rest, re-laid out. */\n removeItem: () => void;\n}\n\nexport interface BoardColumnBreakpoint {\n /** The least content width, in px, at which the board has `columns` columns. */\n minWidth: number;\n columns: number;\n}\n\n/** Cloudscape's: 1 column under 688px, 2 under 912px, 4 under 2100px, else 6. */\nexport const DEFAULT_BOARD_COLUMN_BREAKPOINTS: ReadonlyArray<BoardColumnBreakpoint> = [\n { minWidth: 0, columns: 1 },\n { minWidth: 688, columns: 2 },\n { minWidth: 912, columns: 4 },\n { minWidth: 2100, columns: 6 },\n];\n\n/** How far a pointer travels before a press on a handle is a drag, not a click. */\nexport const CLICK_DRAG_THRESHOLD_PX = 3;\n\nexport interface BoardProps<D = unknown> extends Omit<\n HTMLAttributes<HTMLDivElement>,\n \"children\" | \"onChange\"\n> {\n items: ReadonlyArray<BoardItem<D>>;\n /** An item's content. The board draws the surface, border and handles around it. */\n renderItem: (item: BoardItem<D>, actions: BoardItemActions) => ReactNode;\n /** Called when the user moves, resizes or removes an item. */\n onItemsChange: (detail: BoardItemsChangeDetail<D>) => void;\n /** Whether items have a drag handle and can be moved. @default false */\n isMovable?: boolean;\n /** Whether items have a resize handle and can be resized. @default false */\n isResizable?: boolean;\n /** `bordered` draws a border on each item. @default 'plain' */\n variant?: \"bordered\" | \"plain\";\n /** Rendered in place of the grid when there are no items. */\n emptyContent?: ReactNode;\n /** Content width to column count. @default DEFAULT_BOARD_COLUMN_BREAKPOINTS */\n columnBreakpoints?: ReadonlyArray<BoardColumnBreakpoint>;\n /** An extra class on each item's surface; a function gets the item. */\n itemClassName?: string | ((item: BoardItem<D>) => string | undefined);\n /** Glyph of the drag handle. @default a grip */\n dragHandleIcon?: ReactNode;\n /** Glyph of the resize handle. @default a corner grip */\n resizeHandleIcon?: ReactNode;\n /** Accessible name of the drag handle. Default: the catalog's `uic.Board.dragHandle` */\n dragHandleLabel?: string;\n /** Accessible name of the resize handle. Default: the catalog's `uic.Board.resizeHandle` */\n resizeHandleLabel?: string;\n /** Announced when a move or resize starts. Default: `uic.Board.moveStarted` / `resizeStarted` */\n liveAnnouncementDndStarted?: (operation: BoardOperation) => string;\n /** Announced at each step of a move. Default: `uic.Board.itemMoved` */\n liveAnnouncementDndItemMoved?: (detail: BoardDndDetail<D>) => string;\n /** Announced at each step of a resize. Default: `uic.Board.itemResized` */\n liveAnnouncementDndItemResized?: (detail: BoardDndDetail<D>) => string;\n /** Announced when a move or resize is committed. Default: `uic.Board.moveCommitted` / `resizeCommitted` */\n liveAnnouncementDndCommitted?: (operation: BoardOperation) => string;\n /** Announced when a move or resize is discarded. Default: `uic.Board.moveDiscarded` / `resizeDiscarded` */\n liveAnnouncementDndDiscarded?: (operation: BoardOperation) => string;\n /** Announced when an item is removed. Default: `uic.Board.itemRemoved` */\n liveAnnouncementItemRemoved?: (detail: BoardItemRemovedDetail<D>) => string;\n}\n\nexport interface BoardMetrics {\n cellWidth: number;\n cellHeight: number;\n gap: number;\n}\n\ninterface Box {\n left: number;\n top: number;\n right: number;\n bottom: number;\n}\n\ninterface PointerDrag {\n id: number;\n /** Where the pointer went down, and the grid's origin then. */\n start: Point;\n gridOrigin: Point;\n /** The last pointer position; re-applied when an ancestor scrolls. */\n last: Point;\n /** The item's box when the drag started, in px from the grid's origin. */\n itemBox: Box;\n /** The scroll-compensated travel, which a moved item translates by. */\n dx: number;\n dy: number;\n /** The live size of a resized item, in px. */\n size?: { width: number; height: number };\n}\n\ninterface Transition {\n operation: BoardOperation;\n interaction: \"pointer\" | \"keyboard\";\n itemId: string;\n /** The layout when the operation started; its column count is frozen. */\n base: GridLayout;\n engine: LayoutEngine;\n /** The active item's placement at the start. */\n origin: Rect;\n /** Cells the operation went through, one step at a time. */\n path: Position[];\n /** The board at the path's end; null before the first step, or off the grid. */\n shift: LayoutShift | null;\n /** The cells under the pointer, for the placeholders. */\n hovered: Rect | null;\n metrics: BoardMetrics;\n pointer?: PointerDrag;\n}\n\n/** A press on a handle that has not yet travelled far enough to be a drag. */\ninterface PendingPress {\n operation: BoardOperation;\n itemId: string;\n pointerId: number;\n start: Point;\n}\n\nconst gridOriginOf = (grid: HTMLElement | null): Point => {\n const rect = grid?.getBoundingClientRect();\n return { x: rect?.left ?? 0, y: rect?.top ?? 0 };\n};\n\nconst clamp = (value: number, min: number, max: number) =>\n Math.min(Math.max(value, min), Math.max(min, max));\n\nexport function columnsForWidth(\n width: number,\n breakpoints: ReadonlyArray<BoardColumnBreakpoint>,\n): number {\n let columns = 0;\n for (const bp of [...breakpoints].sort((a, b) => a.minWidth - b.minWidth)) {\n if (bp.minWidth <= width) columns = bp.columns;\n }\n return columns;\n}\n\nconst overlapArea = (a: Box, b: Box) =>\n Math.max(0, Math.min(a.right, b.right) - Math.max(a.left, b.left)) *\n Math.max(0, Math.min(a.bottom, b.bottom) - Math.max(a.top, b.top));\n\n/**\n * The cells a box covers, in grid units: each edge of the box snaps to the\n * nearest edge among the cells it touches, and the cells inside the snapped\n * bounds are hovered. Null when the box touches no cell.\n */\nexport function hoveredCells(\n box: Box,\n columns: number,\n rows: number,\n metrics: BoardMetrics,\n): Rect | null {\n const stepX = metrics.cellWidth + metrics.gap;\n const stepY = metrics.cellHeight + metrics.gap;\n const nearer = (min: number, current: number, edge: number) =>\n Math.abs(current - edge) < Math.abs(min - edge) ? current : min;\n const cellBox = (col: number, row: number): Box => ({\n left: col * stepX,\n top: row * stepY,\n right: col * stepX + metrics.cellWidth,\n bottom: row * stepY + metrics.cellHeight,\n });\n let bounds: Box = {\n left: Infinity,\n top: Infinity,\n right: Infinity,\n bottom: Infinity,\n };\n for (let row = 0; row < rows; row++) {\n for (let col = 0; col < columns; col++) {\n const cell = cellBox(col, row);\n if (overlapArea(cell, box) > 0) {\n bounds = {\n left: nearer(bounds.left, cell.left, box.left),\n top: nearer(bounds.top, cell.top, box.top),\n right: nearer(bounds.right, cell.right, box.right),\n bottom: nearer(bounds.bottom, cell.bottom, box.bottom),\n };\n }\n }\n }\n let rect: Rect | null = null;\n for (let row = 0; row < rows; row++) {\n for (let col = 0; col < columns; col++) {\n const cell = cellBox(col, row);\n const inside =\n cell.top >= bounds.top &&\n cell.left >= bounds.left &&\n cell.right <= bounds.right &&\n cell.bottom <= bounds.bottom;\n if (!inside) continue;\n if (!rect) {\n rect = { x: col, y: row, width: 1, height: 1 };\n } else {\n const x = Math.min(rect.x, col);\n const y = Math.min(rect.y, row);\n rect = {\n x,\n y,\n width: Math.max(rect.x + rect.width, col + 1) - x,\n height: Math.max(rect.y + rect.height, row + 1) - y,\n };\n }\n }\n }\n return rect;\n}\n\nfunction GripGlyph() {\n return (\n <svg\n width=\"1em\"\n height=\"1em\"\n viewBox=\"0 0 16 16\"\n fill=\"currentColor\"\n aria-hidden=\"true\"\n >\n <circle cx=\"6\" cy=\"3\" r=\"1.5\" />\n <circle cx=\"10\" cy=\"3\" r=\"1.5\" />\n <circle cx=\"6\" cy=\"8\" r=\"1.5\" />\n <circle cx=\"10\" cy=\"8\" r=\"1.5\" />\n <circle cx=\"6\" cy=\"13\" r=\"1.5\" />\n <circle cx=\"10\" cy=\"13\" r=\"1.5\" />\n </svg>\n );\n}\n\nfunction CornerGlyph() {\n return (\n <svg\n width=\"1em\"\n height=\"1em\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M13 8 8 13\" />\n <path d=\"M13 3 3 13\" />\n </svg>\n );\n}\n\nconst ARROW_PATHS: Record<Direction, string> = {\n up: \"M8 12V4M4 8l4-4 4 4\",\n down: \"M8 4v8M4 8l4 4 4-4\",\n left: \"M12 8H4M8 4 4 8l4 4\",\n right: \"M4 8h8M8 4l4 4-4 4\",\n};\n\nfunction ArrowGlyph({ direction }: { direction: Direction }) {\n return (\n <svg\n width=\"1em\"\n height=\"1em\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d={ARROW_PATHS[direction]} />\n </svg>\n );\n}\n\nconst DIRECTIONS: Direction[] = [\"up\", \"down\", \"left\", \"right\"];\n\nconst DIRECTION_LABEL_KEYS: Record<Direction, string> = {\n up: \"uic.Board.directionUp\",\n down: \"uic.Board.directionDown\",\n left: \"uic.Board.directionLeft\",\n right: \"uic.Board.directionRight\",\n};\n\nconst cx = (...names: Array<string | false | null | undefined>) =>\n names.filter(Boolean).join(\" \");\n\nexport function Board<D = unknown>({\n items,\n renderItem,\n onItemsChange,\n isMovable = false,\n isResizable = false,\n variant = \"plain\",\n emptyContent,\n columnBreakpoints = DEFAULT_BOARD_COLUMN_BREAKPOINTS,\n itemClassName,\n dragHandleIcon,\n resizeHandleIcon,\n dragHandleLabel,\n resizeHandleLabel,\n liveAnnouncementDndStarted,\n liveAnnouncementDndItemMoved,\n liveAnnouncementDndItemResized,\n liveAnnouncementDndCommitted,\n liveAnnouncementDndDiscarded,\n liveAnnouncementItemRemoved,\n className,\n ...divProps\n}: BoardProps<D>): ReactNode {\n const t = useUicTranslator();\n const rootRef = useRef<HTMLDivElement>(null);\n const gridRef = useRef<HTMLDivElement>(null);\n const shellRefs = useRef(new Map<string, HTMLDivElement>());\n const [width, setWidth] = useState<number | null>(null);\n const [transition, setTransitionState] = useState<Transition | null>(null);\n const [announcement, setAnnouncement] = useState(\"\");\n\n // Event handlers read the latest transition and items without re-binding.\n const transitionRef = useRef<Transition | null>(null);\n const setTransition = (next: Transition | null) => {\n transitionRef.current = next;\n setTransitionState(next);\n };\n const itemsRef = useRef(items);\n itemsRef.current = items;\n const pendingRef = useRef<PendingPress | null>(null);\n\n useEffect(() => {\n const root = rootRef.current;\n if (!root) return;\n if (typeof ResizeObserver === \"undefined\") {\n setWidth(root.clientWidth);\n return;\n }\n const observer = new ResizeObserver((entries) => {\n const entry = entries[0];\n setWidth(entry ? entry.contentRect.width : root.clientWidth);\n });\n observer.observe(root);\n return () => observer.disconnect();\n }, []);\n\n const measuredColumns =\n width === null ? 0 : columnsForWidth(width, columnBreakpoints);\n const columns = transition ? transition.base.columns : measuredColumns;\n const layout = interpretItems(items, columns);\n\n const announceStarted = (operation: BoardOperation) =>\n setAnnouncement(\n liveAnnouncementDndStarted?.(operation) ??\n t(operation === \"resize\" ? \"uic.Board.resizeStarted\" : \"uic.Board.moveStarted\"),\n );\n const announceStep = (tr: Transition, placement: Rect) => {\n const item = itemsRef.current.find((it) => it.id === tr.itemId);\n if (!item) return;\n const detail: BoardDndDetail<D> = { item, placement: { ...placement } };\n setAnnouncement(\n tr.operation === \"resize\"\n ? (liveAnnouncementDndItemResized?.(detail) ??\n t(\"uic.Board.itemResized\", {\n columns: placement.width,\n rows: placement.height,\n }))\n : (liveAnnouncementDndItemMoved?.(detail) ??\n t(\"uic.Board.itemMoved\", {\n column: placement.x + 1,\n row: placement.y + 1,\n })),\n );\n };\n const announceEnd = (operation: BoardOperation, committed: boolean) =>\n setAnnouncement(\n committed\n ? (liveAnnouncementDndCommitted?.(operation) ??\n t(\n operation === \"resize\"\n ? \"uic.Board.resizeCommitted\"\n : \"uic.Board.moveCommitted\",\n ))\n : (liveAnnouncementDndDiscarded?.(operation) ??\n t(\n operation === \"resize\"\n ? \"uic.Board.resizeDiscarded\"\n : \"uic.Board.moveDiscarded\",\n )),\n );\n\n /** Cell geometry from the grid's styles, else from the item's own box. */\n const measure = (cols: number, itemId: string, placed: Rect): BoardMetrics => {\n const grid = gridRef.current;\n if (!grid) return { cellWidth: 0, cellHeight: 0, gap: 0 };\n const style = getComputedStyle(grid);\n const gap = parseFloat(style.rowGap) || 0;\n const shell = shellRefs.current.get(itemId)?.getBoundingClientRect();\n const fromShell = (size: number | undefined, cells: number) =>\n size === undefined ? 0 : Math.max((size - gap * (cells - 1)) / cells, 0);\n const gridWidth = grid.getBoundingClientRect().width;\n const cellWidth =\n gridWidth > 0 && cols > 0\n ? Math.max((gridWidth - gap * (cols - 1)) / cols, 0)\n : fromShell(shell?.width, placed.width);\n const cellHeight =\n parseFloat(style.gridAutoRows) || fromShell(shell?.height, placed.height);\n return { cellWidth, cellHeight, gap };\n };\n\n /** The active item's placement at the path's end. */\n const placementOf = (tr: Transition): Rect => {\n const placed = (tr.shift?.next ?? tr.base).items.find((it) => it.id === tr.itemId);\n return placed\n ? { x: placed.x, y: placed.y, width: placed.width, height: placed.height }\n : tr.origin;\n };\n\n /** How many rows the placeholder lattice has during the operation. */\n const latticeRows = (tr: Transition): number => {\n const current = tr.shift?.next ?? tr.base;\n const placed = placementOf(tr);\n return tr.operation === \"resize\"\n ? Math.max(current.rows, placed.y + placed.height + 1)\n : Math.max(current.rows, tr.base.rows + placed.height);\n };\n\n const start = (\n operation: BoardOperation,\n interaction: Transition[\"interaction\"],\n itemId: string,\n pointer?: PointerDrag,\n ): Transition | null => {\n const base = interpretItems(itemsRef.current, columns);\n const placed = base.items.find((it) => it.id === itemId);\n if (!placed) return null;\n const origin: Rect = {\n x: placed.x,\n y: placed.y,\n width: placed.width,\n height: placed.height,\n };\n const next: Transition = {\n operation,\n interaction,\n itemId,\n base,\n engine: new LayoutEngine(base),\n origin,\n path:\n interaction === \"keyboard\"\n ? [\n operation === \"resize\"\n ? { x: origin.x + origin.width, y: origin.y + origin.height }\n : { x: origin.x, y: origin.y },\n ]\n : [],\n shift: null,\n hovered: null,\n metrics: measure(columns, itemId, origin),\n pointer,\n };\n setTransition(next);\n announceStarted(operation);\n return next;\n };\n\n /** The path extended to `position` and its shift; null when the engine refuses the step. */\n const stepTo = (\n tr: Transition,\n position: Position,\n ): { path: Position[]; shift: LayoutShift } | null => {\n const path = appendPath(tr.path, position);\n try {\n const shift =\n tr.operation === \"resize\"\n ? tr.engine.resize(tr.itemId, path)\n : tr.engine.move(tr.itemId, path);\n return { path, shift };\n } catch (error) {\n if (error instanceof RangeError) return null;\n throw error;\n }\n };\n\n // The handle that had focus when an operation ended. The commit may move\n // its item's node to a new place in the DOM, which drops focus; the handle\n // is focused again once the board has re-rendered.\n const refocusRef = useRef<{ itemId: string; operation: BoardOperation } | null>(null);\n\n const end = (): Transition | null => {\n const tr = transitionRef.current;\n if (!tr) return null;\n const shell = shellRefs.current.get(tr.itemId);\n const active = typeof document === \"undefined\" ? null : document.activeElement;\n refocusRef.current =\n shell && active instanceof HTMLElement && shell.contains(active)\n ? { itemId: tr.itemId, operation: tr.operation }\n : null;\n setTransition(null);\n pendingRef.current = null;\n return tr;\n };\n\n useEffect(() => {\n const target = refocusRef.current;\n if (!target || transition) return;\n refocusRef.current = null;\n const shell = shellRefs.current.get(target.itemId);\n const handle = shell?.querySelector<HTMLElement>(\n target.operation === \"resize\"\n ? \".uic-board-item__resize-handle\"\n : \".uic-board-item__drag-handle\",\n );\n if (handle && document.activeElement !== handle)\n handle.focus({ preventScroll: true });\n });\n\n const commit = () => {\n const tr = end();\n if (!tr) return;\n const { shift } = tr;\n const committable =\n shift !== null && shift.conflicts.length === 0 && shift.moves.length > 0;\n if (committable) {\n const resizeTarget = tr.operation === \"resize\" ? tr.itemId : undefined;\n const next = transformItems(itemsRef.current, shift.next, resizeTarget);\n const changed = next.find((it) => it.id === tr.itemId);\n onItemsChange(\n tr.operation === \"resize\"\n ? { items: next, resizedItem: changed }\n : { items: next, movedItem: changed },\n );\n }\n // A pointer drag released off the grid (no shift) changed nothing and is\n // discarded; a keyboard activation that stepped nowhere is a committed no-op.\n const discarded =\n shift === null ? tr.interaction === \"pointer\" : shift.conflicts.length > 0;\n announceEnd(tr.operation, !discarded);\n };\n\n const discard = () => {\n const tr = end();\n if (tr) announceEnd(tr.operation, false);\n };\n const discardRef = useRef(discard);\n discardRef.current = discard;\n\n // Escape discards a pointer drag too, where no handle holds the keyboard.\n const isPointerDrag = transition?.pointer !== undefined;\n useEffect(() => {\n if (!isPointerDrag) return;\n const onKeyDown = (event: globalThis.KeyboardEvent) => {\n if (event.key === \"Escape\") {\n event.preventDefault();\n discardRef.current();\n }\n };\n window.addEventListener(\"keydown\", onKeyDown);\n return () => window.removeEventListener(\"keydown\", onKeyDown);\n }, [isPointerDrag]);\n\n const removeItemAction = (item: BoardItem<D>) => {\n const current = interpretItems(itemsRef.current, columns);\n const rest = itemsRef.current.filter((it) => it.id !== item.id);\n onItemsChange({\n items: transformItems(rest, removeFromLayout(current, item.id)),\n removedItem: item,\n });\n setAnnouncement(\n liveAnnouncementItemRemoved?.({ item }) ?? t(\"uic.Board.itemRemoved\"),\n );\n };\n\n /** One keyboard or direction-button step of the active transition. */\n const stepBy = (tr: Transition, direction: Direction) => {\n const dx = direction === \"left\" ? -1 : direction === \"right\" ? 1 : 0;\n const dy = direction === \"up\" ? -1 : direction === \"down\" ? 1 : 0;\n const last = tr.path[tr.path.length - 1];\n if (!last) return;\n if (tr.operation === \"resize\") {\n const item = itemsRef.current.find((it) => it.id === tr.itemId);\n const placed = placementOf(tr);\n const minWidth = item ? getMinColumnSpan(item, tr.base.columns) : 1;\n const minHeight = item ? getMinRowSpan(item) : 1;\n if (placed.width + dx < minWidth || placed.height + dy < minHeight) return;\n }\n const stepped = stepTo(tr, { x: last.x + dx, y: last.y + dy });\n if (!stepped) return;\n const updated: Transition = { ...tr, ...stepped, hovered: null };\n setTransition(updated);\n announceStep(updated, placementOf(updated));\n };\n\n const onHandlePointerDown =\n (operation: BoardOperation, itemId: string) =>\n (event: PointerEvent<HTMLButtonElement>) => {\n if (event.button !== 0 || transitionRef.current?.pointer) return;\n // jsdom has no pointer capture.\n if (typeof event.currentTarget.setPointerCapture === \"function\") {\n event.currentTarget.setPointerCapture(event.pointerId);\n }\n pendingRef.current = {\n operation,\n itemId,\n pointerId: event.pointerId,\n start: { x: event.clientX, y: event.clientY },\n };\n };\n\n const beginDrag = (press: PendingPress, point: Point): Transition | null => {\n const shell = shellRefs.current.get(press.itemId);\n const gridOrigin = gridOriginOf(gridRef.current);\n const rect = shell?.getBoundingClientRect();\n const itemBox: Box = rect\n ? {\n left: rect.left - gridOrigin.x,\n top: rect.top - gridOrigin.y,\n right: rect.right - gridOrigin.x,\n bottom: rect.bottom - gridOrigin.y,\n }\n : { left: 0, top: 0, right: 0, bottom: 0 };\n // A keyboard activation on a handle gives way to a drag from it.\n if (transitionRef.current) setTransition(null);\n return start(press.operation, \"pointer\", press.itemId, {\n id: press.pointerId,\n start: press.start,\n gridOrigin,\n last: point,\n itemBox,\n dx: 0,\n dy: 0,\n });\n };\n\n /** Moves the drag to a pointer position, in viewport coordinates. */\n const applyPointer = (tr: Transition, point: Point) => {\n const drag = tr.pointer;\n if (!drag) return;\n const travel = compensateForScroll(\n point,\n drag.start,\n drag.gridOrigin,\n gridOriginOf(gridRef.current),\n );\n const { itemBox } = drag;\n const { cellWidth, cellHeight, gap } = tr.metrics;\n const span = (cells: number, cell: number) =>\n Math.max(cells * cell + (cells - 1) * gap, 0);\n const item = itemsRef.current.find((it) => it.id === tr.itemId);\n const cols = tr.base.columns;\n const rows = latticeRows(tr);\n\n let box: Box;\n let size = drag.size;\n if (tr.operation === \"resize\") {\n const minWidth = span(item ? getMinColumnSpan(item, cols) : 1, cellWidth);\n const minHeight = span(item ? getMinRowSpan(item) : 1, cellHeight);\n const maxWidth = span(cols - tr.origin.x, cellWidth);\n size = {\n width: clamp(itemBox.right - itemBox.left + travel.x, minWidth, maxWidth),\n height: Math.max(itemBox.bottom - itemBox.top + travel.y, minHeight),\n };\n box = {\n left: itemBox.left,\n top: itemBox.top,\n right: itemBox.left + size.width,\n bottom: itemBox.top + size.height,\n };\n } else {\n box = {\n left: itemBox.left + travel.x,\n top: itemBox.top + travel.y,\n right: itemBox.right + travel.x,\n bottom: itemBox.bottom + travel.y,\n };\n }\n\n const hovered = hoveredCells(box, cols, rows, tr.metrics);\n const placed = placementOf(tr);\n // A moved item must have a whole place to land on; a resized one any cell.\n const onGrid =\n hovered !== null &&\n (tr.operation === \"resize\" ||\n hovered.width * hovered.height >= placed.width * placed.height);\n let { shift, path } = tr;\n if (!onGrid) {\n shift = null;\n } else {\n const next =\n tr.operation === \"resize\"\n ? { x: hovered.x + hovered.width, y: hovered.y + hovered.height }\n : { x: hovered.x, y: hovered.y };\n const last = path[path.length - 1];\n if (!last || last.x !== next.x || last.y !== next.y || shift === null) {\n const stepped = stepTo(tr, next);\n if (stepped) ({ shift, path } = stepped);\n }\n }\n const updated: Transition = {\n ...tr,\n shift,\n path,\n hovered: onGrid ? hovered : null,\n pointer: { ...drag, last: point, dx: travel.x, dy: travel.y, size },\n };\n // A pointer step is not announced: the board under the pointer shows it.\n setTransition(updated);\n };\n const applyPointerRef = useRef(applyPointer);\n applyPointerRef.current = applyPointer;\n\n const onHandlePointerMove = (event: PointerEvent<HTMLButtonElement>) => {\n const point = { x: event.clientX, y: event.clientY };\n const press = pendingRef.current;\n if (press && press.pointerId === event.pointerId) {\n const moved =\n Math.abs(point.x - press.start.x) > CLICK_DRAG_THRESHOLD_PX ||\n Math.abs(point.y - press.start.y) > CLICK_DRAG_THRESHOLD_PX;\n if (!moved) return;\n pendingRef.current = null;\n const tr = beginDrag(press, point);\n if (tr) applyPointer(tr, point);\n return;\n }\n const tr = transitionRef.current;\n if (!tr?.pointer || tr.pointer.id !== event.pointerId) return;\n applyPointer(tr, point);\n };\n\n // While a pointer drag is on: an ancestor scrolling moves the grid under a\n // still pointer, so the last position is re-applied; and a pointer held\n // near an edge of the nearest scroll container scrolls it, frame by frame.\n useEffect(() => {\n if (!isPointerDrag) return;\n const reapply = () => {\n const tr = transitionRef.current;\n if (tr?.pointer) applyPointerRef.current(tr, tr.pointer.last);\n };\n window.addEventListener(\"scroll\", reapply, { capture: true, passive: true });\n\n const grid = gridRef.current;\n const container = grid ? findScrollParent(grid) : null;\n let frame = 0;\n const tick = () => {\n const tr = transitionRef.current;\n if (tr?.pointer && container) {\n const step = autoScrollStep(tr.pointer.last, scrollBounds(container));\n if (\n (step.x !== 0 || step.y !== 0) &&\n typeof container.scrollBy === \"function\"\n ) {\n container.scrollBy(step.x, step.y);\n reapply();\n }\n }\n frame = requestAnimationFrame(tick);\n };\n if (typeof requestAnimationFrame === \"function\")\n frame = requestAnimationFrame(tick);\n\n return () => {\n window.removeEventListener(\"scroll\", reapply, { capture: true });\n if (frame) cancelAnimationFrame(frame);\n };\n }, [isPointerDrag]);\n\n const onHandlePointerUp = (event: PointerEvent<HTMLButtonElement>) => {\n const press = pendingRef.current;\n if (press && press.pointerId === event.pointerId) {\n // A click activates the handle for keyboard and button steps, or\n // commits the activation already on it.\n pendingRef.current = null;\n const tr = transitionRef.current;\n if (tr) commit();\n if (!(tr && tr.itemId === press.itemId && tr.operation === press.operation)) {\n // Not every browser focuses a clicked button; the keys and the blur\n // that end the activation need the focus on the handle.\n event.currentTarget.focus({ preventScroll: true });\n start(press.operation, \"keyboard\", press.itemId);\n }\n return;\n }\n const tr = transitionRef.current;\n if (!tr?.pointer || tr.pointer.id !== event.pointerId) return;\n commit();\n };\n\n const onHandlePointerCancel = (event: PointerEvent<HTMLButtonElement>) => {\n if (pendingRef.current?.pointerId === event.pointerId) pendingRef.current = null;\n const tr = transitionRef.current;\n if (!tr?.pointer || tr.pointer.id !== event.pointerId) return;\n discard();\n };\n\n const onHandleKeyDown =\n (operation: BoardOperation, itemId: string) =>\n (event: KeyboardEvent<HTMLButtonElement>) => {\n const tr = transitionRef.current;\n if (tr && (tr.itemId !== itemId || tr.operation !== operation)) return;\n switch (event.key) {\n case \"ArrowUp\":\n case \"ArrowDown\":\n case \"ArrowLeft\":\n case \"ArrowRight\": {\n // Arrows step only once the handle is activated (a click, Enter or Space).\n if (tr?.interaction !== \"keyboard\") return;\n event.preventDefault();\n stepBy(tr, event.key.slice(5).toLowerCase() as Direction);\n return;\n }\n case \"Enter\":\n case \" \":\n event.preventDefault();\n if (tr) commit();\n else start(operation, \"keyboard\", itemId);\n return;\n case \"Escape\":\n if (tr) {\n event.preventDefault();\n discard();\n }\n return;\n default:\n return;\n }\n };\n\n const onHandleBlur = () => {\n const tr = transitionRef.current;\n if (tr?.interaction === \"keyboard\") commit();\n };\n\n const preview = transition ? (transition.shift?.next ?? transition.base) : null;\n const previewById = new Map(preview?.items.map((it) => [it.id, it]) ?? []);\n const activePlacement = transition ? placementOf(transition) : null;\n const hovered =\n transition?.hovered ??\n (transition?.interaction === \"keyboard\" && transition.shift\n ? activePlacement\n : null);\n const placeholders: ReactNode[] = [];\n if (transition) {\n const rows = latticeRows(transition);\n for (let row = 0; row < rows; row++) {\n for (let col = 0; col < columns; col++) {\n const hover =\n hovered !== null &&\n col >= hovered.x &&\n col < hovered.x + hovered.width &&\n row >= hovered.y &&\n row < hovered.y + hovered.height;\n placeholders.push(\n <div\n key={`placeholder-${row}-${col}`}\n className={cx(\n \"uic-board__placeholder\",\n \"uic-board__placeholder--active\",\n hover && \"uic-board__placeholder--hover\",\n )}\n style={{\n gridColumn: `${col + 1} / span 1`,\n gridRow: `${row + 1} / span 1`,\n }}\n />,\n );\n }\n }\n }\n\n const itemById = new Map(items.map((item) => [item.id, item]));\n const toPx = (cells: number, cell: number) =>\n cells * (cell + (transition?.metrics.gap ?? 0));\n\n /** The direction buttons of an activated handle. */\n const renderDirections = (operation: BoardOperation, itemId: string) => {\n const shown =\n transition !== null &&\n transition.interaction === \"keyboard\" &&\n transition.itemId === itemId &&\n transition.operation === operation;\n if (!shown) return null;\n // Real buttons, named, so a touch screen reader finds them; out of the\n // tab order, since the arrow keys on the handle do the same, and the\n // press is cancelled so the handle keeps focus.\n return DIRECTIONS.map((direction) => (\n <button\n key={direction}\n type=\"button\"\n tabIndex={-1}\n className={cx(\"uic-board__direction\", `uic-board__direction--${direction}`)}\n aria-label={t(DIRECTION_LABEL_KEYS[direction])}\n data-direction={direction}\n onPointerDown={(event) => event.preventDefault()}\n onClick={() => {\n const current = transitionRef.current;\n if (current) stepBy(current, direction);\n }}\n >\n <ArrowGlyph direction={direction} />\n </button>\n ));\n };\n\n return (\n <div\n ref={rootRef}\n className={cx(\"uic-board\", transition && \"uic-board--active\", className)}\n {...divProps}\n >\n {columns > 0 && items.length > 0 ? (\n <div\n ref={gridRef}\n className=\"uic-board__grid\"\n style={{ gridTemplateColumns: `repeat(${columns}, minmax(0, 1fr))` }}\n >\n {placeholders}\n {layout.items.map((placed) => {\n const item = itemById.get(placed.id);\n if (!item) return null;\n const isActive = transition?.itemId === placed.id;\n const pointer = isActive ? transition?.pointer : undefined;\n let column = `${placed.x + 1} / span ${placed.width}`;\n let row = `${placed.y + 1} / span ${placed.height}`;\n let transform: string | undefined;\n let liveWidth: number | undefined;\n let liveHeight: number | undefined;\n if (transition && isActive && activePlacement) {\n if (transition.operation === \"resize\") {\n if (pointer?.size) {\n liveWidth = pointer.size.width;\n liveHeight = pointer.size.height;\n } else {\n column = `${placed.x + 1} / span ${activePlacement.width}`;\n row = `${placed.y + 1} / span ${activePlacement.height}`;\n }\n } else if (pointer) {\n transform = `translate(${pointer.dx}px, ${pointer.dy}px)`;\n } else {\n const { cellWidth, cellHeight } = transition.metrics;\n transform = `translate(${toPx(activePlacement.x - placed.x, cellWidth)}px, ${toPx(activePlacement.y - placed.y, cellHeight)}px)`;\n }\n } else if (transition) {\n const next = previewById.get(placed.id);\n if (next && (next.x !== placed.x || next.y !== placed.y)) {\n const { cellWidth, cellHeight } = transition.metrics;\n transform = `translate(${toPx(next.x - placed.x, cellWidth)}px, ${toPx(next.y - placed.y, cellHeight)}px)`;\n }\n }\n const style: CSSProperties = {\n gridColumn: column,\n gridRow: row,\n transform,\n width: liveWidth,\n height: liveHeight,\n };\n const extra =\n typeof itemClassName === \"function\" ? itemClassName(item) : itemClassName;\n return (\n <div\n key={item.id}\n ref={(node) => {\n if (node) shellRefs.current.set(item.id, node);\n else shellRefs.current.delete(item.id);\n }}\n className={cx(\n \"uic-board-item\",\n variant === \"bordered\" && \"uic-board-item--bordered\",\n isActive && \"uic-board-item--active\",\n // The slide is the item's own class, so it and the\n // transform leave in one update: a transition that lived on\n // an ancestor could outlive the transform by a style pass.\n transition !== null && \"uic-board-item--sliding\",\n pointer &&\n transition?.operation === \"move\" &&\n \"uic-board-item--dragging\",\n pointer &&\n transition?.operation === \"resize\" &&\n \"uic-board-item--resizing\",\n extra,\n )}\n style={style}\n data-board-item-id={item.id}\n >\n {isMovable ? (\n <span className=\"uic-board-item__handle uic-board-item__handle--drag\">\n <IconButton\n className=\"uic-board-item__drag-handle\"\n variant=\"ghost\"\n size=\"sm\"\n label={dragHandleLabel ?? t(\"uic.Board.dragHandle\")}\n icon={dragHandleIcon ?? <GripGlyph />}\n onPointerDown={onHandlePointerDown(\"move\", item.id)}\n onPointerMove={onHandlePointerMove}\n onPointerUp={onHandlePointerUp}\n onPointerCancel={onHandlePointerCancel}\n onKeyDown={onHandleKeyDown(\"move\", item.id)}\n onBlur={onHandleBlur}\n />\n {renderDirections(\"move\", item.id)}\n </span>\n ) : null}\n <div className=\"uic-board-item__content\">\n {renderItem(item, { removeItem: () => removeItemAction(item) })}\n </div>\n {isResizable ? (\n <span className=\"uic-board-item__handle uic-board-item__handle--resize\">\n <IconButton\n className=\"uic-board-item__resize-handle\"\n variant=\"ghost\"\n size=\"sm\"\n label={resizeHandleLabel ?? t(\"uic.Board.resizeHandle\")}\n icon={resizeHandleIcon ?? <CornerGlyph />}\n onPointerDown={onHandlePointerDown(\"resize\", item.id)}\n onPointerMove={onHandlePointerMove}\n onPointerUp={onHandlePointerUp}\n onPointerCancel={onHandlePointerCancel}\n onKeyDown={onHandleKeyDown(\"resize\", item.id)}\n onBlur={onHandleBlur}\n />\n {renderDirections(\"resize\", item.id)}\n </span>\n ) : null}\n </div>\n );\n })}\n </div>\n ) : items.length === 0 ? (\n emptyContent\n ) : null}\n <VisuallyHidden as=\"div\" aria-live=\"polite\" aria-atomic=\"true\">\n {announcement}\n </VisuallyHidden>\n </div>\n );\n}\n\nBoard.displayName = \"Board\";\n"],"mappings":"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"}
@@ -0,0 +1,60 @@
1
+ import { GridLayout } from './layout';
2
+ export interface Position {
3
+ x: number;
4
+ y: number;
5
+ }
6
+ export interface Rect {
7
+ x: number;
8
+ y: number;
9
+ width: number;
10
+ height: number;
11
+ }
12
+ export type Direction = "up" | "down" | "left" | "right";
13
+ type MoveType = "MOVE" | "OVERLAP" | "FLOAT" | "RESIZE" | "REMOVE";
14
+ export interface LayoutMove extends Rect {
15
+ type: MoveType;
16
+ itemId: string;
17
+ direction: Direction;
18
+ distanceX: number;
19
+ distanceY: number;
20
+ score: number;
21
+ }
22
+ export interface LayoutShift {
23
+ current: GridLayout;
24
+ /** The layout after the moves, in reading order. */
25
+ next: GridLayout;
26
+ moves: LayoutMove[];
27
+ /** Ids of items the step could not settle; a shift with any must not commit. */
28
+ conflicts: string[];
29
+ }
30
+ export declare function intersects(a: Rect, b: Rect): boolean;
31
+ /** A move path with its loops cut out: only the last visit to a cell counts. */
32
+ export declare function normalizeMovePath(origin: Position, path: ReadonlyArray<Position>): Position[];
33
+ /** A resize path reduced to the shrink steps that matter and the final size. */
34
+ export declare function normalizeResizePath(origin: Position, path: ReadonlyArray<Position>): Position[];
35
+ /** Appends single-cell steps from the path's end to `next`. */
36
+ export declare function appendPath(path: ReadonlyArray<Position>, next: Position): Position[];
37
+ /**
38
+ * Computes layout shifts for one operation. Keep one instance for the whole
39
+ * operation: each step is resolved once and reused while the path's prefix
40
+ * stays the same.
41
+ */
42
+ export declare class LayoutEngine {
43
+ readonly layout: GridLayout;
44
+ private readonly initial;
45
+ private cachedSteps;
46
+ private cachedStates;
47
+ constructor(layout: GridLayout);
48
+ move(itemId: string, path: ReadonlyArray<Position>): LayoutShift;
49
+ resize(itemId: string, path: ReadonlyArray<Position>): LayoutShift;
50
+ remove(itemId: string): LayoutShift;
51
+ private run;
52
+ private shift;
53
+ }
54
+ /** The layout with `itemId` moved to `(x, y)` in one straight path. */
55
+ export declare function moveItem(layout: GridLayout, itemId: string, x: number, y: number): GridLayout;
56
+ /** The layout with `itemId` spanning `width` x `height`. */
57
+ export declare function resizeItem(layout: GridLayout, itemId: string, width: number, height: number): GridLayout;
58
+ /** The layout without `itemId`, the rest floated up into its place. */
59
+ export declare function removeItem(layout: GridLayout, itemId: string): GridLayout;
60
+ export {};
@@ -0,0 +1,397 @@
1
+ import { compareLayoutItems as e } from "./layout.js";
2
+ //#region src/components/Board/engine.ts
3
+ function t(e, t) {
4
+ return e.x < t.x + t.width && t.x < e.x + e.width && e.y < t.y + t.height && t.y < e.y + e.height;
5
+ }
6
+ var n = (e, t) => e === "down" && t === "up" || e === "up" && t === "down" || e === "left" && t === "right" || e === "right" && t === "left";
7
+ function r(e, t, n, r = 0) {
8
+ let i = e === "RESIZE" ? n.x - t.width : n.x - t.x, a = e === "RESIZE" ? n.y - t.height : n.y - t.y;
9
+ return {
10
+ type: e,
11
+ itemId: t.id,
12
+ x: e === "RESIZE" ? t.x : n.x,
13
+ y: e === "RESIZE" ? t.y : n.y,
14
+ width: e === "RESIZE" ? n.x : t.width,
15
+ height: e === "RESIZE" ? n.y : t.height,
16
+ direction: i > 0 ? "right" : i < 0 ? "left" : a < 0 ? "up" : "down",
17
+ distanceX: i,
18
+ distanceY: a,
19
+ score: r
20
+ };
21
+ }
22
+ var i = (e) => ({
23
+ left: e.x - e.distanceX,
24
+ right: e.x - e.distanceX + e.width - 1,
25
+ top: e.y - e.distanceY,
26
+ bottom: e.y - e.distanceY + e.height - 1
27
+ }), a = (e) => ({
28
+ left: e.x,
29
+ right: e.x + e.width - 1,
30
+ top: e.y,
31
+ bottom: e.y + e.height - 1
32
+ }), o = class e {
33
+ columns;
34
+ items;
35
+ constructor(e, t) {
36
+ this.columns = t, this.items = e.map((e) => ({ ...e }));
37
+ }
38
+ clone() {
39
+ return new e(this.items, this.columns);
40
+ }
41
+ get rows() {
42
+ return this.items.reduce((e, t) => Math.max(e, t.y + t.height), 0);
43
+ }
44
+ getItem(e) {
45
+ let t = this.items.find((t) => t.id === e);
46
+ if (!t) throw Error(`Board: no item "${e}" on the grid.`);
47
+ return t;
48
+ }
49
+ getOverlaps(e) {
50
+ return this.items.filter((n) => n.id !== e.id && t(n, e));
51
+ }
52
+ move(e, t, n) {
53
+ let r = this.getItem(e);
54
+ r.x = t, r.y = n;
55
+ }
56
+ resize(e, t, n) {
57
+ let r = this.getItem(e);
58
+ r.width = t, r.height = n;
59
+ }
60
+ remove(e) {
61
+ let t = this.items.findIndex((t) => t.id === e);
62
+ t !== -1 && this.items.splice(t, 1);
63
+ }
64
+ }, s = (e, t, n) => ({
65
+ grid: e.clone(),
66
+ moves: [...t],
67
+ moveIndex: t.length,
68
+ conflicts: n,
69
+ overlaps: /* @__PURE__ */ new Map(),
70
+ score: 0
71
+ }), c = (e) => ({
72
+ grid: e.grid.clone(),
73
+ moves: [...e.moves],
74
+ moveIndex: e.moveIndex,
75
+ conflicts: e.conflicts,
76
+ overlaps: new Map(e.overlaps),
77
+ score: e.score
78
+ }), l = (e) => e.sort((e, t) => t.y - e.y === 0 ? t.x - e.x : t.y - e.y);
79
+ function u(e, n) {
80
+ let { grid: r } = e;
81
+ switch (n.type) {
82
+ case "MOVE":
83
+ case "OVERLAP":
84
+ case "FLOAT":
85
+ r.move(n.itemId, n.x, n.y);
86
+ break;
87
+ case "RESIZE":
88
+ r.resize(n.itemId, n.width, n.height);
89
+ break;
90
+ case "REMOVE": r.remove(n.itemId);
91
+ }
92
+ if (n.type !== "REMOVE") for (let t of r.getOverlaps({
93
+ ...n,
94
+ id: n.itemId
95
+ })) e.conflicts?.items.has(t.id) || e.overlaps.set(t.id, n.itemId);
96
+ for (let [n, i] of e.overlaps) {
97
+ let a = r.items.find((e) => e.id === n), o = r.items.find((e) => e.id === i);
98
+ (!a || !o || !t(a, o)) && e.overlaps.delete(n);
99
+ }
100
+ e.moves.push(n), e.score += n.score;
101
+ }
102
+ function d(e, t, n) {
103
+ if (n.type !== "MOVE") return null;
104
+ let r = t?.direction ?? n.direction, i = e.getOverlaps({
105
+ ...n,
106
+ id: n.itemId
107
+ }).filter((e) => {
108
+ switch (r) {
109
+ case "left": return e.x < n.x;
110
+ case "right": return e.x + e.width - 1 > n.x + n.width - 1;
111
+ case "up": return e.y < n.y;
112
+ case "down": return e.y + e.height - 1 > n.y + n.height - 1;
113
+ }
114
+ });
115
+ return i.length > 0 ? {
116
+ direction: r,
117
+ items: new Set(i.map((e) => e.id))
118
+ } : null;
119
+ }
120
+ var f = [
121
+ "down",
122
+ "right",
123
+ "left",
124
+ "up"
125
+ ], p = 100, m = 5;
126
+ function h(e, t) {
127
+ for (let n = e.moves.length - 1; n >= e.moveIndex; n--) {
128
+ let r = e.moves[n];
129
+ if (r && r.itemId === t) return r;
130
+ }
131
+ return null;
132
+ }
133
+ function g(e, t, n) {
134
+ switch (n) {
135
+ case "up": return r("OVERLAP", e, {
136
+ x: e.x,
137
+ y: t.y - e.height
138
+ });
139
+ case "down": return r("OVERLAP", e, {
140
+ x: e.x,
141
+ y: t.y + t.height
142
+ });
143
+ case "left": return r("OVERLAP", e, {
144
+ x: t.x - e.width,
145
+ y: e.y
146
+ });
147
+ case "right": return r("OVERLAP", e, {
148
+ x: t.x + t.width,
149
+ y: e.y
150
+ });
151
+ }
152
+ }
153
+ function _(e, t, n) {
154
+ let { left: r, right: a, top: o, bottom: s } = i(t), c = t.distanceX <= 0 ? t.x : a + 1, l = t.distanceX < 0 ? r - 1 : a + t.distanceX, u = t.distanceY <= 0 ? t.y : s + 1, d = t.distanceY < 0 ? o - 1 : s + t.distanceY, f = new Set(e.grid.getOverlaps({
155
+ id: t.itemId,
156
+ x: c,
157
+ width: 1 + l - c,
158
+ y: u,
159
+ height: 1 + d - u
160
+ }));
161
+ return f.delete(n), f;
162
+ }
163
+ function v(e, t) {
164
+ if (t.type !== "MOVE" || !n(e.direction, t.direction)) return !1;
165
+ let r = i(e), o = a(t);
166
+ switch (t.direction) {
167
+ case "up": return r.top === o.top;
168
+ case "right": return r.right === o.right;
169
+ case "down": return r.bottom === o.bottom;
170
+ case "left": return r.left === o.left;
171
+ }
172
+ }
173
+ function y(e) {
174
+ let t = {
175
+ x: 0,
176
+ y: 0
177
+ };
178
+ for (let n = e.moveIndex; n < e.moves.length; n++) {
179
+ let r = e.moves[n];
180
+ r?.type === "OVERLAP" && (t.x += r.distanceX * r.height, t.y += r.distanceY * r.width);
181
+ }
182
+ return t;
183
+ }
184
+ function b(e) {
185
+ let t = e.moves[e.moveIndex];
186
+ if (!t) throw Error("Board: no user move to bound.");
187
+ let n = i(t), r = a(t);
188
+ return {
189
+ top: Math.min(n.top, r.top),
190
+ right: Math.max(n.right, r.right),
191
+ bottom: Math.max(n.bottom, r.bottom),
192
+ left: Math.min(n.left, r.left)
193
+ };
194
+ }
195
+ function x(e, t, r, i) {
196
+ let a = e.moves[0];
197
+ if (!a) throw Error("Board: no user move.");
198
+ let o = e.grid.getItem(a.itemId), s = e.grid.getItem(t), c = e.grid.getItem(r), l = g(s, c, i);
199
+ if (l.x < 0 || l.y < 0 || l.x + l.width > e.grid.columns) return null;
200
+ let u = h(e, s.id);
201
+ if (u && n(u.direction, i)) return null;
202
+ let d = _(e, l, c);
203
+ for (let t of d) if (t.id === o.id || e.conflicts?.items.has(t.id) || e.overlaps.has(t.id)) return null;
204
+ let f = h(e, c.id);
205
+ if (!f) throw Error("Board: an overlap's issuer has no move.");
206
+ let p = v(l, f), m = i !== f.direction, x = n(i, f.direction), S = b(e), C = y(e), w = (p ? 0 : 20) + (!p && m ? 10 : 0) + (!p && x ? 500 : 0), T = d.size * 50, E = (s.y + s.height - 1 < S.top ? 500 : 0) + (s.x + s.width - 1 < S.left ? 50 : 0) + (s.x > S.right ? 50 : 0), D = (l.distanceX * C.x < 0 ? C.x * 2 : 0) + (l.distanceY * C.y < 0 ? C.y * 2 : 0);
207
+ return {
208
+ ...l,
209
+ score: 1 + w + T + D + E
210
+ };
211
+ }
212
+ function S(e) {
213
+ let t = [];
214
+ for (let [n, r] of e.overlaps) for (let i of f) {
215
+ let a = x(e, n, r, i);
216
+ a && t.push([c(e), a]);
217
+ }
218
+ return t;
219
+ }
220
+ function C(e) {
221
+ for (; e.overlaps.size > 0;) {
222
+ let t = l([...e.overlaps.keys()].map((t) => e.grid.getItem(t)));
223
+ for (let n of t) {
224
+ let t = n.y + 1;
225
+ for (; e.grid.getOverlaps({
226
+ ...n,
227
+ y: t
228
+ }).length > 0;) t++;
229
+ u(e, r("OVERLAP", n, {
230
+ x: n.x,
231
+ y: t
232
+ }));
233
+ }
234
+ }
235
+ return e;
236
+ }
237
+ function w(e, t) {
238
+ let n = s(e.grid, e.moves, e.conflicts), i = () => {
239
+ let e = !1;
240
+ for (let i of n.grid.items) {
241
+ if (i.id === t?.itemId) continue;
242
+ let a = null;
243
+ for (let e = i.y - 1; e >= 0; e--) {
244
+ let t = r("FLOAT", i, {
245
+ x: i.x,
246
+ y: e
247
+ });
248
+ if (n.grid.getOverlaps({
249
+ ...t,
250
+ id: i.id
251
+ }).length > 0) break;
252
+ a = t;
253
+ }
254
+ a && (u(n, a), e = !0);
255
+ }
256
+ return e;
257
+ };
258
+ for (; i(););
259
+ return n;
260
+ }
261
+ function T(e, t) {
262
+ let n = d(e.grid, e.conflicts, t), r = s(e.grid, e.moves, n), i = /* @__PURE__ */ new Set(), a = ([e, t]) => `${t.itemId} ${t.x}:${t.y}:${e.score + t.score}`, o = [[r, t]], c = null, l = p;
263
+ for (; o.length > 0;) {
264
+ let e = [];
265
+ for (let t = 0; t < Math.min(m, o.length); t++) {
266
+ let n = o[t];
267
+ if (!n) break;
268
+ let [r, s] = n;
269
+ if (!(c && r.score + s.score >= c.score)) if (u(r, s), r.overlaps.size === 0) c = r;
270
+ else for (let t of S(r)) {
271
+ let n = a(t);
272
+ i.has(n) || (i.add(n), e.push(t));
273
+ }
274
+ }
275
+ if (o = e.sort((e, t) => e[0].score + e[1].score - (t[0].score + t[1].score)), --l, l <= 0) break;
276
+ }
277
+ return c ||= (r.moves.length === r.moveIndex && u(r, t), r.conflicts ? r : C(r)), c.conflicts ? c : w(c, t);
278
+ }
279
+ function E(e, t) {
280
+ let n = [], r = e.x, i = e.y;
281
+ for (let e of t) {
282
+ let t = Math.sign(e.x - r), a = Math.sign(e.y - i);
283
+ for (let o = r, s = i; o !== e.x || s !== e.y;) o === e.x ? s += a : o += t, n.push({
284
+ x: o,
285
+ y: s
286
+ });
287
+ r = e.x, i = e.y;
288
+ }
289
+ return n;
290
+ }
291
+ function D(e, t) {
292
+ let n = -1;
293
+ return t.forEach((t, r) => {
294
+ t.x === e.x && t.y === e.y && (n = r);
295
+ }), t.slice(n + 1);
296
+ }
297
+ function O(e, t) {
298
+ let n = D(e, t), r = /* @__PURE__ */ new Map();
299
+ n.forEach((e, t) => r.set(`${e.x}:${e.y}`, t));
300
+ let i = [];
301
+ for (let e = 0; e < n.length;) {
302
+ let t = n[e];
303
+ if (!t) break;
304
+ let a = r.get(`${t.x}:${t.y}`) ?? e, o = n[a];
305
+ o && i.push(o), e = a + 1;
306
+ }
307
+ return E(e, i);
308
+ }
309
+ function k(e, t) {
310
+ let n = D(e, t), r = n[n.length - 1];
311
+ if (!r) return [];
312
+ let i = [r];
313
+ for (let e = n.length - 2; e >= 0; e--) {
314
+ let t = i[i.length - 1], r = n[e];
315
+ t && r && (r.x < t.x || r.y < t.y) && i.push(r);
316
+ }
317
+ return i.reverse(), E(e, i);
318
+ }
319
+ function A(e, t) {
320
+ let n = e[e.length - 1];
321
+ return n ? [...e, ...E(n, [t])] : [t];
322
+ }
323
+ var j = class {
324
+ layout;
325
+ initial;
326
+ cachedSteps = [];
327
+ cachedStates = [];
328
+ constructor(e) {
329
+ this.layout = e, this.initial = s(new o(e.items, e.columns), [], null);
330
+ }
331
+ move(e, t) {
332
+ let n = this.initial.grid.getItem(e);
333
+ for (let e of t) if (e.x < 0 || e.y < 0 || e.x + n.width > this.initial.grid.columns) throw RangeError("Board: move outside the grid.");
334
+ let i = O({
335
+ x: n.x,
336
+ y: n.y
337
+ }, t);
338
+ return this.shift(this.run(i, (t, n) => T(t, r("MOVE", t.grid.getItem(e), n))));
339
+ }
340
+ resize(e, t) {
341
+ let n = this.initial.grid.getItem(e);
342
+ for (let e of t) {
343
+ if (e.x < 1 || e.y < 1) throw RangeError("Board: resize to nothing.");
344
+ if (e.x > this.initial.grid.columns) throw RangeError("Board: resize outside the grid.");
345
+ }
346
+ let i = k({
347
+ x: n.x + n.width,
348
+ y: n.y + n.height
349
+ }, t);
350
+ return this.shift(this.run(i, (t, n) => {
351
+ let i = t.grid.getItem(e);
352
+ return T(t, r("RESIZE", i, {
353
+ x: n.x - i.x,
354
+ y: n.y - i.y
355
+ }));
356
+ }));
357
+ }
358
+ remove(e) {
359
+ let t = this.initial.grid.getItem(e), n = r("REMOVE", t, {
360
+ x: t.x,
361
+ y: t.y
362
+ });
363
+ return this.shift(T(this.initial, n));
364
+ }
365
+ run(e, t) {
366
+ let n = 0;
367
+ for (; n < e.length && n < this.cachedSteps.length;) {
368
+ let t = this.cachedSteps[n], r = e[n];
369
+ if (!t || !r || t.x !== r.x || t.y !== r.y) break;
370
+ n++;
371
+ }
372
+ this.cachedSteps = this.cachedSteps.slice(0, n), this.cachedStates = this.cachedStates.slice(0, n);
373
+ let r = this.cachedStates[n - 1] ?? this.initial;
374
+ for (let i of e.slice(n)) r = t(r, i), this.cachedSteps.push(i), this.cachedStates.push(r);
375
+ return r;
376
+ }
377
+ shift(t) {
378
+ let n = t.grid.items.map((e) => ({ ...e })).sort(e);
379
+ return {
380
+ current: this.layout,
381
+ next: {
382
+ items: n,
383
+ columns: t.grid.columns,
384
+ rows: t.grid.rows
385
+ },
386
+ moves: t.moves,
387
+ conflicts: t.conflicts ? [...t.conflicts.items] : []
388
+ };
389
+ }
390
+ };
391
+ function M(e, t) {
392
+ return new j(e).remove(t).next;
393
+ }
394
+ //#endregion
395
+ export { j as LayoutEngine, A as appendPath, t as intersects, O as normalizeMovePath, k as normalizeResizePath, M as removeItem };
396
+
397
+ //# sourceMappingURL=engine.js.map