@awesome-markdown/board-ui 0.0.0-stage → 1.6.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 (184) hide show
  1. package/README.md +76 -2
  2. package/dist/board/Board.d.ts +24 -0
  3. package/dist/board/Board.d.ts.map +1 -0
  4. package/dist/board/Board.js +166 -0
  5. package/dist/board/Board.js.map +1 -0
  6. package/dist/board/Cell.d.ts +23 -0
  7. package/dist/board/Cell.d.ts.map +1 -0
  8. package/dist/board/Cell.js +145 -0
  9. package/dist/board/Cell.js.map +1 -0
  10. package/dist/board/ColumnHeader.d.ts +18 -0
  11. package/dist/board/ColumnHeader.d.ts.map +1 -0
  12. package/dist/board/ColumnHeader.js +31 -0
  13. package/dist/board/ColumnHeader.js.map +1 -0
  14. package/dist/board/HomelessItemCard.d.ts +15 -0
  15. package/dist/board/HomelessItemCard.d.ts.map +1 -0
  16. package/dist/board/HomelessItemCard.js +36 -0
  17. package/dist/board/HomelessItemCard.js.map +1 -0
  18. package/dist/board/HomelessPanel.d.ts +17 -0
  19. package/dist/board/HomelessPanel.d.ts.map +1 -0
  20. package/dist/board/HomelessPanel.js +26 -0
  21. package/dist/board/HomelessPanel.js.map +1 -0
  22. package/dist/board/ItemCard.d.ts +21 -0
  23. package/dist/board/ItemCard.d.ts.map +1 -0
  24. package/dist/board/ItemCard.js +104 -0
  25. package/dist/board/ItemCard.js.map +1 -0
  26. package/dist/board/SwimlaneRow.d.ts +23 -0
  27. package/dist/board/SwimlaneRow.d.ts.map +1 -0
  28. package/dist/board/SwimlaneRow.js +30 -0
  29. package/dist/board/SwimlaneRow.js.map +1 -0
  30. package/dist/board/dnd/boardDnd.d.ts +15 -0
  31. package/dist/board/dnd/boardDnd.d.ts.map +1 -0
  32. package/dist/board/dnd/boardDnd.js +69 -0
  33. package/dist/board/dnd/boardDnd.js.map +1 -0
  34. package/dist/board/dnd/dragTypes.d.ts +24 -0
  35. package/dist/board/dnd/dragTypes.d.ts.map +1 -0
  36. package/dist/board/dnd/dragTypes.js +22 -0
  37. package/dist/board/dnd/dragTypes.js.map +1 -0
  38. package/dist/board/dnd/mutateDragDrop.d.ts +37 -0
  39. package/dist/board/dnd/mutateDragDrop.d.ts.map +1 -0
  40. package/dist/board/dnd/mutateDragDrop.js +116 -0
  41. package/dist/board/dnd/mutateDragDrop.js.map +1 -0
  42. package/dist/board/dnd/onDragEnd.d.ts +24 -0
  43. package/dist/board/dnd/onDragEnd.d.ts.map +1 -0
  44. package/dist/board/dnd/onDragEnd.js +47 -0
  45. package/dist/board/dnd/onDragEnd.js.map +1 -0
  46. package/dist/board/layout/AxisBehavior.d.ts +35 -0
  47. package/dist/board/layout/AxisBehavior.d.ts.map +1 -0
  48. package/dist/board/layout/AxisBehavior.js +82 -0
  49. package/dist/board/layout/AxisBehavior.js.map +1 -0
  50. package/dist/board/layout/AxisDrawer.d.ts +17 -0
  51. package/dist/board/layout/AxisDrawer.d.ts.map +1 -0
  52. package/dist/board/layout/AxisDrawer.js +40 -0
  53. package/dist/board/layout/AxisDrawer.js.map +1 -0
  54. package/dist/board/layout/BoardDrawer.d.ts +11 -0
  55. package/dist/board/layout/BoardDrawer.d.ts.map +1 -0
  56. package/dist/board/layout/BoardDrawer.js +27 -0
  57. package/dist/board/layout/BoardDrawer.js.map +1 -0
  58. package/dist/board/layout/Drawer.d.ts +19 -0
  59. package/dist/board/layout/Drawer.d.ts.map +1 -0
  60. package/dist/board/layout/Drawer.js +18 -0
  61. package/dist/board/layout/Drawer.js.map +1 -0
  62. package/dist/board/layout/FilterEditor.d.ts +12 -0
  63. package/dist/board/layout/FilterEditor.d.ts.map +1 -0
  64. package/dist/board/layout/FilterEditor.js +11 -0
  65. package/dist/board/layout/FilterEditor.js.map +1 -0
  66. package/dist/board/layout/InlineControls.d.ts +22 -0
  67. package/dist/board/layout/InlineControls.d.ts.map +1 -0
  68. package/dist/board/layout/InlineControls.js +39 -0
  69. package/dist/board/layout/InlineControls.js.map +1 -0
  70. package/dist/board/layout/SortableAxis.d.ts +28 -0
  71. package/dist/board/layout/SortableAxis.d.ts.map +1 -0
  72. package/dist/board/layout/SortableAxis.js +39 -0
  73. package/dist/board/layout/SortableAxis.js.map +1 -0
  74. package/dist/board/layout/axis-defaults.d.ts +22 -0
  75. package/dist/board/layout/axis-defaults.d.ts.map +1 -0
  76. package/dist/board/layout/axis-defaults.js +37 -0
  77. package/dist/board/layout/axis-defaults.js.map +1 -0
  78. package/dist/board/layout/filter-draft.d.ts +21 -0
  79. package/dist/board/layout/filter-draft.d.ts.map +1 -0
  80. package/dist/board/layout/filter-draft.js +110 -0
  81. package/dist/board/layout/filter-draft.js.map +1 -0
  82. package/dist/board/layout/useBoardLayout.d.ts +27 -0
  83. package/dist/board/layout/useBoardLayout.d.ts.map +1 -0
  84. package/dist/board/layout/useBoardLayout.js +92 -0
  85. package/dist/board/layout/useBoardLayout.js.map +1 -0
  86. package/dist/breadcrumb.d.ts +22 -0
  87. package/dist/breadcrumb.d.ts.map +1 -0
  88. package/dist/breadcrumb.js +15 -0
  89. package/dist/breadcrumb.js.map +1 -0
  90. package/dist/components/BoardAssigneeField.d.ts +10 -0
  91. package/dist/components/BoardAssigneeField.d.ts.map +1 -0
  92. package/dist/components/BoardAssigneeField.js +37 -0
  93. package/dist/components/BoardAssigneeField.js.map +1 -0
  94. package/dist/components/ConflictBanner.d.ts +12 -0
  95. package/dist/components/ConflictBanner.d.ts.map +1 -0
  96. package/dist/components/ConflictBanner.js +47 -0
  97. package/dist/components/ConflictBanner.js.map +1 -0
  98. package/dist/components/ConflictDiff.d.ts +13 -0
  99. package/dist/components/ConflictDiff.d.ts.map +1 -0
  100. package/dist/components/ConflictDiff.js +97 -0
  101. package/dist/components/ConflictDiff.js.map +1 -0
  102. package/dist/components/ConflictPanel.d.ts +16 -0
  103. package/dist/components/ConflictPanel.d.ts.map +1 -0
  104. package/dist/components/ConflictPanel.js +53 -0
  105. package/dist/components/ConflictPanel.js.map +1 -0
  106. package/dist/components/DeleteItemConfirmDialog.d.ts +14 -0
  107. package/dist/components/DeleteItemConfirmDialog.d.ts.map +1 -0
  108. package/dist/components/DeleteItemConfirmDialog.js +46 -0
  109. package/dist/components/DeleteItemConfirmDialog.js.map +1 -0
  110. package/dist/components/ItemEditorActions.d.ts +15 -0
  111. package/dist/components/ItemEditorActions.d.ts.map +1 -0
  112. package/dist/components/ItemEditorActions.js +48 -0
  113. package/dist/components/ItemEditorActions.js.map +1 -0
  114. package/dist/index.d.ts +32 -0
  115. package/dist/index.d.ts.map +1 -0
  116. package/dist/index.js +37 -0
  117. package/dist/index.js.map +1 -0
  118. package/dist/lib/derive-summary.d.ts +9 -0
  119. package/dist/lib/derive-summary.d.ts.map +1 -0
  120. package/dist/lib/derive-summary.js +27 -0
  121. package/dist/lib/derive-summary.js.map +1 -0
  122. package/dist/lib/item-board.d.ts +5 -0
  123. package/dist/lib/item-board.d.ts.map +1 -0
  124. package/dist/lib/item-board.js +14 -0
  125. package/dist/lib/item-board.js.map +1 -0
  126. package/dist/lib/property-display.d.ts +18 -0
  127. package/dist/lib/property-display.d.ts.map +1 -0
  128. package/dist/lib/property-display.js +81 -0
  129. package/dist/lib/property-display.js.map +1 -0
  130. package/dist/pages/BoardListPage.d.ts +9 -0
  131. package/dist/pages/BoardListPage.d.ts.map +1 -0
  132. package/dist/pages/BoardListPage.js +113 -0
  133. package/dist/pages/BoardListPage.js.map +1 -0
  134. package/dist/pages/BoardPage.d.ts +7 -0
  135. package/dist/pages/BoardPage.d.ts.map +1 -0
  136. package/dist/pages/BoardPage.js +37 -0
  137. package/dist/pages/BoardPage.js.map +1 -0
  138. package/dist/pages/ItemEditorPage.d.ts +3 -0
  139. package/dist/pages/ItemEditorPage.d.ts.map +1 -0
  140. package/dist/pages/ItemEditorPage.js +255 -0
  141. package/dist/pages/ItemEditorPage.js.map +1 -0
  142. package/dist/provider/ProviderContext.d.ts +17 -0
  143. package/dist/provider/ProviderContext.d.ts.map +1 -0
  144. package/dist/provider/ProviderContext.js +21 -0
  145. package/dist/provider/ProviderContext.js.map +1 -0
  146. package/dist/router/RouterAdapter.d.ts +43 -0
  147. package/dist/router/RouterAdapter.d.ts.map +1 -0
  148. package/dist/router/RouterAdapter.js +21 -0
  149. package/dist/router/RouterAdapter.js.map +1 -0
  150. package/dist/shell/SyncStatusDot.d.ts +8 -0
  151. package/dist/shell/SyncStatusDot.d.ts.map +1 -0
  152. package/dist/shell/SyncStatusDot.js +58 -0
  153. package/dist/shell/SyncStatusDot.js.map +1 -0
  154. package/dist/shell/ThemeToggle.d.ts +8 -0
  155. package/dist/shell/ThemeToggle.d.ts.map +1 -0
  156. package/dist/shell/ThemeToggle.js +21 -0
  157. package/dist/shell/ThemeToggle.js.map +1 -0
  158. package/dist/state/theme-store.d.ts +17 -0
  159. package/dist/state/theme-store.d.ts.map +1 -0
  160. package/dist/state/theme-store.js +58 -0
  161. package/dist/state/theme-store.js.map +1 -0
  162. package/dist/state/useBoardRender.d.ts +16 -0
  163. package/dist/state/useBoardRender.d.ts.map +1 -0
  164. package/dist/state/useBoardRender.js +53 -0
  165. package/dist/state/useBoardRender.js.map +1 -0
  166. package/dist/state/useProviderSubscribe.d.ts +22 -0
  167. package/dist/state/useProviderSubscribe.d.ts.map +1 -0
  168. package/dist/state/useProviderSubscribe.js +48 -0
  169. package/dist/state/useProviderSubscribe.js.map +1 -0
  170. package/dist/sync/conflict-api.d.ts +16 -0
  171. package/dist/sync/conflict-api.d.ts.map +1 -0
  172. package/dist/sync/conflict-api.js +35 -0
  173. package/dist/sync/conflict-api.js.map +1 -0
  174. package/dist/sync/conflict-store.d.ts +44 -0
  175. package/dist/sync/conflict-store.d.ts.map +1 -0
  176. package/dist/sync/conflict-store.js +159 -0
  177. package/dist/sync/conflict-store.js.map +1 -0
  178. package/fonts/InterTight-Medium.woff2 +0 -0
  179. package/fonts/InterTight-Regular.woff2 +0 -0
  180. package/fonts/JetBrainsMono-Medium.woff2 +0 -0
  181. package/fonts/JetBrainsMono-Regular.woff2 +0 -0
  182. package/fonts/LICENSE +14 -0
  183. package/package.json +58 -3
  184. package/styles.css +232 -0
package/README.md CHANGED
@@ -1,3 +1,77 @@
1
- # Temporary Holding Version
1
+ # @awesome-markdown/board-ui
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ The awesome-markdown board surface — board list, kanban board with filter-derived
4
+ drag-and-drop, homeless panel, inline layout editing, item editor and sync-engine
5
+ conflict resolution — as a router-agnostic React 19 library.
6
+
7
+ `apps/kanban-ui` is a thin shell around this package; other hosts (for example a
8
+ multi-tenant cloud app) mount the same pages under their own router and provider.
9
+
10
+ ## Install
11
+
12
+ ```bash
13
+ pnpm add @awesome-markdown/board-ui react react-dom
14
+ ```
15
+
16
+ ## Usage
17
+
18
+ ```tsx
19
+ import '@awesome-markdown/board-ui/styles.css';
20
+ import {
21
+ BoardListPage,
22
+ BoardPage,
23
+ ItemEditorPage,
24
+ ProviderContextProvider,
25
+ RouterAdapterProvider,
26
+ type RouterAdapter,
27
+ } from '@awesome-markdown/board-ui';
28
+
29
+ const adapter: RouterAdapter = {
30
+ Link: ({ to, ...props }) => <MyLink to={`/w/acme${to}`} {...props} />,
31
+ navigate: (to) => router.navigate(`/w/acme${to}`),
32
+ useParams: () => useMyRouterParams(),
33
+ useSearchParams: () => new URLSearchParams(useMyRouterLocation().search),
34
+ };
35
+
36
+ <RouterAdapterProvider adapter={adapter}>
37
+ <ProviderContextProvider provider={persistenceProvider}>
38
+ {/* route `/` → <BoardListPage/>, `/boards/:slug` → <BoardPage/>, `/items/:slug` → <ItemEditorPage/> */}
39
+ </ProviderContextProvider>
40
+ </RouterAdapterProvider>;
41
+ ```
42
+
43
+ ### RouterAdapter
44
+
45
+ board-ui never imports a router. All paths it emits are **board-relative**
46
+ (`/`, `/boards/:slug`, `/items/:slug?board=:boardSlug`); the adapter maps them onto
47
+ the host URL space.
48
+
49
+ | Member | Purpose |
50
+ |---|---|
51
+ | `Link` | Component rendering an in-app link (`to`, `children`, `className`, `style`, `data-testid`, …) |
52
+ | `navigate(to)` | Imperative navigation to a board-relative path |
53
+ | `useParams()` | Hook returning route params; pages read `slug` |
54
+ | `useSearchParams()` | Hook returning the current query string; the item editor reads `board` |
55
+
56
+ `apps/kanban-ui/src/router/react-router-adapter.tsx` is the reference
57
+ implementation for `react-router-dom`.
58
+
59
+ ### Optional contexts
60
+
61
+ - `BreadcrumbContext` — pages push `BreadcrumbSegment[]` via `useBreadcrumb()`; provide it
62
+ if your shell renders a breadcrumb. The default is a no-op.
63
+ - `ConflictProvider syncEngineUrl="…"` + `<ConflictBanner/>` — only for hosts backed by
64
+ the git sync-engine.
65
+
66
+ ### Shell widgets
67
+
68
+ `SyncStatusDot` (HTTP provider connection state), `ThemeToggle` / `useTheme`
69
+ (light/dark via `data-theme` on `<html>`).
70
+
71
+ ## Styles
72
+
73
+ `@awesome-markdown/board-ui/styles.css` contains the design tokens (`--bg`, `--ink`,
74
+ `--ink-muted`, `--border`, `--accent`, `--font-mono`, `--font-sans`; light and
75
+ `[data-theme="dark"]`), the self-hosted JetBrains Mono / Inter Tight fonts (resolved
76
+ relative to the CSS file, so any bundler that handles CSS `url()` picks them up), the
77
+ small utility-class set the components use, and the board-editing classes.
@@ -0,0 +1,24 @@
1
+ import React from 'react';
2
+ import type { BoardRender, Homeless } from '@awesome-markdown/contracts';
3
+ interface BoardProps {
4
+ render: BoardRender;
5
+ homeless: Homeless | null;
6
+ onRefetch: () => void;
7
+ }
8
+ /**
9
+ * Main board component: renders the column×swimlane grid and wires up DnD.
10
+ *
11
+ * Manages optimistic cell state — on drag-drop, applies the move immediately
12
+ * then reverts on PATCH failure with a user-visible error toast.
13
+ *
14
+ * Drop semantics:
15
+ * - Invertibility check + mutation derivation via @awesome-markdown/filter-engine
16
+ * - Read-only cells reject drops before any network call
17
+ * - One drop → exactly one PATCH /items/:slug
18
+ *
19
+ * Layout editing: "+" adds a column/swimlane, headers drag to reorder, the
20
+ * pencil opens the axis (or board) settings drawer.
21
+ */
22
+ export declare function Board({ render, homeless, onRefetch }: BoardProps): React.ReactElement;
23
+ export {};
24
+ //# sourceMappingURL=Board.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Board.d.ts","sourceRoot":"","sources":["../../src/board/Board.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAgC,MAAM,OAAO,CAAC;AAgBrD,OAAO,KAAK,EAAE,WAAW,EAAoB,QAAQ,EAAE,MAAM,6BAA6B,CAAC;AAe3F,UAAU,UAAU;IAClB,MAAM,EAAE,WAAW,CAAC;IACpB,QAAQ,EAAE,QAAQ,GAAG,IAAI,CAAC;IAC1B,SAAS,EAAE,MAAM,IAAI,CAAC;CACvB;AAID;;;;;;;;;;;;;GAaG;AACH,wBAAgB,KAAK,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,EAAE,UAAU,GAAG,KAAK,CAAC,YAAY,CA0UrF"}
@@ -0,0 +1,166 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import React, { useCallback, useState } from 'react';
3
+ import { DndContext, DragOverlay, PointerSensor, KeyboardSensor, useSensor, useSensors, } from '@dnd-kit/core';
4
+ import { SortableContext, horizontalListSortingStrategy, sortableKeyboardCoordinates, verticalListSortingStrategy, } from '@dnd-kit/sortable';
5
+ import { ColumnHeader } from './ColumnHeader.js';
6
+ import { SwimlaneRow } from './SwimlaneRow.js';
7
+ import { HomelessPanel } from './HomelessPanel.js';
8
+ import { onDragEnd } from './dnd/onDragEnd.js';
9
+ import { computeDropMutations, applyOptimisticMove } from './dnd/mutateDragDrop.js';
10
+ import { layoutAwareCollision, planHomelessDrop } from './dnd/boardDnd.js';
11
+ import { useProvider } from '../provider/ProviderContext.js';
12
+ import { useBoardLayout } from './layout/useBoardLayout.js';
13
+ import { axisDragId } from './layout/axis-defaults.js';
14
+ import { AddAxisButton, PencilIcon } from './layout/InlineControls.js';
15
+ import { AxisDrawer } from './layout/AxisDrawer.js';
16
+ import { BoardDrawer } from './layout/BoardDrawer.js';
17
+ /**
18
+ * Main board component: renders the column×swimlane grid and wires up DnD.
19
+ *
20
+ * Manages optimistic cell state — on drag-drop, applies the move immediately
21
+ * then reverts on PATCH failure with a user-visible error toast.
22
+ *
23
+ * Drop semantics:
24
+ * - Invertibility check + mutation derivation via @awesome-markdown/filter-engine
25
+ * - Read-only cells reject drops before any network call
26
+ * - One drop → exactly one PATCH /items/:slug
27
+ *
28
+ * Layout editing: "+" adds a column/swimlane, headers drag to reorder, the
29
+ * pencil opens the axis (or board) settings drawer.
30
+ */
31
+ export function Board({ render, homeless, onRefetch }) {
32
+ const provider = useProvider();
33
+ const [activeItemSlug, setActiveItemSlug] = useState(null);
34
+ const [optimisticCells, setOptimisticCells] = useState(null);
35
+ const [error, setError] = useState(null);
36
+ const [editing, setEditing] = useState(null);
37
+ const layout = useBoardLayout(render, onRefetch, setError);
38
+ const closeDrawer = useCallback(() => setEditing(null), []);
39
+ const cells = optimisticCells ?? render.cells;
40
+ const sensors = useSensors(useSensor(PointerSensor, { activationConstraint: { distance: 4 } }), useSensor(KeyboardSensor, { coordinateGetter: sortableKeyboardCoordinates }));
41
+ const handleDragStart = useCallback((event) => {
42
+ setActiveItemSlug(String(event.active.id));
43
+ }, []);
44
+ const handleDragCancel = useCallback(() => {
45
+ setActiveItemSlug(null);
46
+ }, []);
47
+ const handleDragEnd = useCallback((event) => {
48
+ setActiveItemSlug(null);
49
+ // --- Axis header reorder branch ---
50
+ const activeData = event.active.data.current;
51
+ if (activeData?.type === 'axis') {
52
+ const { dim, slug } = activeData;
53
+ const over = event.over?.data.current;
54
+ if (over?.type === 'axis' && over.dim === dim)
55
+ void layout.moveAxis(dim, slug, over.slug);
56
+ return;
57
+ }
58
+ // --- Homeless item drop branch ---
59
+ if (activeData?.type === 'homeless-item') {
60
+ if (!homeless)
61
+ return;
62
+ const plan = planHomelessDrop(event, cells, render, homeless);
63
+ if (!plan)
64
+ return;
65
+ setOptimisticCells(plan.newCells);
66
+ void (async () => {
67
+ try {
68
+ await provider.patchItem(plan.itemSlug, { mutations: plan.mutations });
69
+ setOptimisticCells(null);
70
+ }
71
+ catch (err) {
72
+ setOptimisticCells(null);
73
+ setError(`Failed to move item: ${err instanceof Error ? err.message : 'Unknown error'}`);
74
+ }
75
+ })();
76
+ return;
77
+ }
78
+ // --- Regular cell-to-cell drop branch ---
79
+ const action = onDragEnd(event, cells);
80
+ if (action.type === 'noop')
81
+ return;
82
+ const { itemSlug, srcColumnSlug, srcSwimlaneSlug, dstColumnSlug, dstSwimlaneSlug, insertBeforeSlug, } = action;
83
+ const srcCell = cells.find((c) => c.columnSlug === srcColumnSlug && c.swimlaneSlug === srcSwimlaneSlug);
84
+ const dstCell = cells.find((c) => c.columnSlug === dstColumnSlug && c.swimlaneSlug === dstSwimlaneSlug);
85
+ if (!srcCell || !dstCell)
86
+ return;
87
+ // Reject read-only destination before any UI change
88
+ if (dstCell.readOnly)
89
+ return;
90
+ const colAxis = render.axes.columns.find((a) => a.slug === dstColumnSlug);
91
+ const slAxis = render.axes.swimlanes.find((a) => a.slug === dstSwimlaneSlug);
92
+ if (!colAxis || !slAxis)
93
+ return;
94
+ const dropResult = computeDropMutations({
95
+ itemSlug,
96
+ srcCell,
97
+ dstCell,
98
+ colAxis,
99
+ slAxis,
100
+ board: render.board,
101
+ insertBeforeSlug,
102
+ });
103
+ if (!dropResult)
104
+ return; // readonly guard
105
+ // Optimistic update — apply before the network call
106
+ const movingItem = srcCell.items.find((i) => i.slug === itemSlug);
107
+ if (!movingItem)
108
+ return;
109
+ const newCells = applyOptimisticMove(cells, movingItem, srcColumnSlug, srcSwimlaneSlug, dstColumnSlug, dstSwimlaneSlug, insertBeforeSlug);
110
+ setOptimisticCells(newCells);
111
+ void (async () => {
112
+ try {
113
+ await provider.patchItem(itemSlug, { mutations: dropResult.mutations });
114
+ // Clear optimistic state; SSE will deliver the definitive render
115
+ setOptimisticCells(null);
116
+ }
117
+ catch (err) {
118
+ setOptimisticCells(null);
119
+ setError(`Failed to move item: ${err instanceof Error ? err.message : 'Unknown error'}`);
120
+ }
121
+ })();
122
+ }, [cells, render, provider, homeless, layout]);
123
+ const activeItem = activeItemSlug !== null
124
+ ? (cells.flatMap((c) => c.items).find((i) => i.slug === activeItemSlug) ??
125
+ homeless?.items.find((i) => i.slug === activeItemSlug) ??
126
+ null)
127
+ : null;
128
+ const visibleHomelessItems = homeless
129
+ ? homeless.items.filter((i) => !optimisticCells ||
130
+ !optimisticCells.some((c) => c.items.some((it) => it.slug === i.slug)))
131
+ : [];
132
+ const isEditing = (dim, slug) => editing?.kind === 'axis' && editing.dim === dim && editing.slug === slug;
133
+ const toggleAxis = (dim, slug) => setEditing(isEditing(dim, slug) ? null : { kind: 'axis', dim, slug });
134
+ const editingAxis = editing?.kind === 'axis' ? layout[editing.dim].find((a) => a.slug === editing.slug) : undefined;
135
+ return (_jsxs("div", { className: "flex flex-col h-full", "data-testid": "board", "data-board-slug": render.board.slug, children: [_jsxs("div", { className: "px-4 py-3", style: { borderBottom: '1px solid var(--border)', background: 'var(--bg)' }, children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("h1", { style: { fontFamily: 'var(--font-mono)', fontSize: '1.125rem', fontWeight: 500, color: 'var(--ink)', margin: 0 }, "data-testid": "board-title", children: render.board.title }), _jsx("button", { type: "button", className: "icon-btn", "aria-pressed": editing?.kind === 'board', "aria-label": "Board settings", title: "Board settings", "data-testid": "edit-board", onClick: () => setEditing(editing?.kind === 'board' ? null : { kind: 'board' }), children: _jsx(PencilIcon, {}) })] }), render.board.description !== undefined && (_jsx("p", { style: { fontSize: '0.875rem', color: 'var(--ink-muted)', marginTop: '2px' }, children: render.board.description }))] }), error !== null && (_jsxs("div", { className: "flex items-center justify-between px-4 py-2 flex-shrink-0", style: {
136
+ borderBottom: '1px solid var(--border)',
137
+ fontFamily: 'var(--font-mono)',
138
+ fontSize: '12px',
139
+ color: 'var(--ink)',
140
+ background: 'var(--bg)',
141
+ }, "data-testid": "board-error-toast", role: "alert", children: [_jsx("span", { children: error }), _jsx("button", { type: "button", onClick: () => setError(null), style: {
142
+ marginLeft: '1rem',
143
+ color: 'var(--ink-muted)',
144
+ background: 'none',
145
+ border: 'none',
146
+ cursor: 'pointer',
147
+ fontFamily: 'var(--font-mono)',
148
+ fontSize: '12px',
149
+ }, "aria-label": "Dismiss error", children: "\u2715" })] })), _jsxs(DndContext, { sensors: sensors, collisionDetection: layoutAwareCollision, onDragStart: handleDragStart, onDragEnd: handleDragEnd, onDragCancel: handleDragCancel, children: [_jsxs("div", { className: "flex-1 overflow-auto", children: [_jsxs("div", { className: "flex sticky top-0 z-10", style: { background: 'var(--bg)', borderBottom: '1px solid var(--border)' }, children: [_jsx("div", { className: "w-28 flex-shrink-0" }), _jsx(SortableContext, { items: layout.columns.map((c) => axisDragId('columns', c.slug)), strategy: horizontalListSortingStrategy, children: layout.columns.map((col) => {
150
+ const count = cells
151
+ .filter((c) => c.columnSlug === col.slug)
152
+ .reduce((sum, c) => sum + c.items.length, 0);
153
+ return (_jsx(ColumnHeader, { column: col, itemCount: count, editable: !layout.implicit.columns, selected: isEditing('columns', col.slug), onEdit: () => toggleAxis('columns', col.slug), onRename: (title) => void layout.saveAxis(col.slug, { title }) }, col.slug));
154
+ }) }), _jsx(AddAxisButton, { label: "column", style: { width: '36px', minWidth: '36px', margin: '4px 8px', alignSelf: 'stretch' }, onAdd: (title) => void layout.addAxis('columns', title) })] }), _jsxs("div", { className: "flex flex-col", "data-testid": "swimlane-rows", children: [_jsx(SortableContext, { items: layout.swimlanes.map((s) => axisDragId('swimlanes', s.slug)), strategy: verticalListSortingStrategy, children: layout.swimlanes.map((sl) => (_jsx(SwimlaneRow, { swimlane: sl, columns: layout.columns, cells: cells, board: render.board, editable: !layout.implicit.swimlanes, selected: isEditing('swimlanes', sl.slug), onEdit: () => toggleAxis('swimlanes', sl.slug), onRename: (title) => void layout.saveAxis(sl.slug, { title }), onError: setError, onCreated: onRefetch }, sl.slug))) }), _jsx(AddAxisButton, { label: "swimlane", style: { width: '112px', height: '32px', margin: '8px 0' }, onAdd: (title) => void layout.addAxis('swimlanes', title) })] })] }), homeless !== null && visibleHomelessItems.length > 0 && (_jsx(HomelessPanel, { homeless: homeless, items: visibleHomelessItems })), _jsx(DragOverlay, { children: activeItem !== null && (_jsx("div", { style: {
155
+ background: 'var(--bg)',
156
+ border: '1px solid var(--border)',
157
+ padding: '10px 12px',
158
+ fontSize: '14px',
159
+ fontWeight: 500,
160
+ color: 'var(--ink)',
161
+ fontFamily: 'var(--font-sans)',
162
+ opacity: 0.9,
163
+ boxShadow: 'none',
164
+ }, children: activeItem.title })) })] }), editing?.kind === 'axis' && editingAxis && (_jsx(AxisDrawer, { axis: editingAxis, dim: editing.dim, boardSlug: render.board.slug, usage: layout.usage(editing.slug), onSave: (patch) => layout.saveAxis(editing.slug, patch), onRemove: () => layout.removeAxis(editing.dim, editing.slug), onClose: closeDrawer }, `${editing.dim}:${editing.slug}`)), editing?.kind === 'board' && (_jsx(BoardDrawer, { board: render.board, onSave: layout.saveBoard, onClose: closeDrawer }))] }));
165
+ }
166
+ //# sourceMappingURL=Board.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Board.js","sourceRoot":"","sources":["../../src/board/Board.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ import React from 'react';
2
+ import type { Cell as CellData, Axis, Board } from '@awesome-markdown/contracts';
3
+ interface CellProps {
4
+ cell: CellData;
5
+ columnAxis: Axis;
6
+ swimlaneAxis: Axis;
7
+ board: Board;
8
+ onError: (msg: string) => void;
9
+ /** Called after a successful item creation so the board can refetch. */
10
+ onCreated: () => void;
11
+ }
12
+ /**
13
+ * A droppable column×swimlane cell containing sortable ItemCards.
14
+ *
15
+ * Read-only cells (cell.readOnly) suppress the drag-over highlight,
16
+ * show a tooltip explaining why, and hide the "+ Add" affordance.
17
+ *
18
+ * "+ Add" derives mutations from the cell's combined filter via
19
+ * filter-engine and sends POST /items (createItem).
20
+ */
21
+ export declare function Cell({ cell, columnAxis, swimlaneAxis, board, onError, onCreated, }: CellProps): React.ReactElement;
22
+ export {};
23
+ //# sourceMappingURL=Cell.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Cell.d.ts","sourceRoot":"","sources":["../../src/board/Cell.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA2B,MAAM,OAAO,CAAC;AAGhD,OAAO,KAAK,EAAE,IAAI,IAAI,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,6BAA6B,CAAC;AAOjF,UAAU,SAAS;IACjB,IAAI,EAAE,QAAQ,CAAC;IACf,UAAU,EAAE,IAAI,CAAC;IACjB,YAAY,EAAE,IAAI,CAAC;IACnB,KAAK,EAAE,KAAK,CAAC;IACb,OAAO,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/B,wEAAwE;IACxE,SAAS,EAAE,MAAM,IAAI,CAAC;CACvB;AAYD;;;;;;;;GAQG;AACH,wBAAgB,IAAI,CAAC,EACnB,IAAI,EACJ,UAAU,EACV,YAAY,EACZ,KAAK,EACL,OAAO,EACP,SAAS,GACV,EAAE,SAAS,GAAG,KAAK,CAAC,YAAY,CA0MhC"}
@@ -0,0 +1,145 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import React, { useState, useRef } from 'react';
3
+ import { useDroppable } from '@dnd-kit/core';
4
+ import { SortableContext, verticalListSortingStrategy } from '@dnd-kit/sortable';
5
+ import { deriveMutations, analyzeInvertibility } from '@awesome-markdown/filter-engine';
6
+ import { ItemCard } from './ItemCard.js';
7
+ import { encodeCellId } from './dnd/dragTypes.js';
8
+ import { buildCellFilter } from './dnd/mutateDragDrop.js';
9
+ import { useProvider } from '../provider/ProviderContext.js';
10
+ /** Slugify a title string to a valid slug. */
11
+ function slugify(title) {
12
+ const s = title
13
+ .toLowerCase()
14
+ .trim()
15
+ .replace(/[^a-z0-9]+/g, '-')
16
+ .replace(/^-|-$/g, '');
17
+ return s.length > 0 ? s : 'item';
18
+ }
19
+ /**
20
+ * A droppable column×swimlane cell containing sortable ItemCards.
21
+ *
22
+ * Read-only cells (cell.readOnly) suppress the drag-over highlight,
23
+ * show a tooltip explaining why, and hide the "+ Add" affordance.
24
+ *
25
+ * "+ Add" derives mutations from the cell's combined filter via
26
+ * filter-engine and sends POST /items (createItem).
27
+ */
28
+ export function Cell({ cell, columnAxis, swimlaneAxis, board, onError, onCreated, }) {
29
+ const provider = useProvider();
30
+ const [creating, setCreating] = useState(false);
31
+ const [newTitle, setNewTitle] = useState('');
32
+ const [saving, setSaving] = useState(false);
33
+ const inputRef = useRef(null);
34
+ const cellId = encodeCellId(columnAxis.slug, swimlaneAxis.slug);
35
+ const { setNodeRef, isOver } = useDroppable({
36
+ id: cellId,
37
+ disabled: cell.readOnly,
38
+ });
39
+ const itemIds = cell.items.map((i) => i.slug);
40
+ // Compute read-only tooltip from invertibility reasons
41
+ const readOnlyTooltip = React.useMemo(() => {
42
+ if (!cell.readOnly)
43
+ return '';
44
+ const filter = buildCellFilter(board, columnAxis, swimlaneAxis);
45
+ const override = columnAxis.writeOnDrop ?? swimlaneAxis.writeOnDrop;
46
+ if (override !== undefined && !Array.isArray(override)) {
47
+ return 'This cell is marked read-only.';
48
+ }
49
+ const { reasons } = analyzeInvertibility(filter);
50
+ return reasons.length > 0 ? reasons.join('; ') : 'This cell is read-only.';
51
+ }, [cell.readOnly, board, columnAxis, swimlaneAxis]);
52
+ const handleAddClick = () => {
53
+ setCreating(true);
54
+ setNewTitle('');
55
+ setTimeout(() => inputRef.current?.focus(), 0);
56
+ };
57
+ const handleCreate = async () => {
58
+ const title = newTitle.trim();
59
+ if (!title) {
60
+ setCreating(false);
61
+ return;
62
+ }
63
+ const filter = buildCellFilter(board, columnAxis, swimlaneAxis);
64
+ const writeOnDrop = columnAxis.writeOnDrop ?? swimlaneAxis.writeOnDrop;
65
+ const result = deriveMutations(filter, { board: board.slug }, writeOnDrop);
66
+ if (!Array.isArray(result)) {
67
+ onError('Cannot create item: cell is read-only.');
68
+ setCreating(false);
69
+ return;
70
+ }
71
+ setSaving(true);
72
+ try {
73
+ await provider.createItem({ slug: slugify(title), title, mutations: result });
74
+ setCreating(false);
75
+ setNewTitle('');
76
+ onCreated();
77
+ }
78
+ catch (err) {
79
+ onError(`Failed to create item: ${err instanceof Error ? err.message : 'Unknown error'}`);
80
+ }
81
+ finally {
82
+ setSaving(false);
83
+ }
84
+ };
85
+ const handleKeyDown = (e) => {
86
+ if (e.key === 'Enter') {
87
+ void handleCreate();
88
+ }
89
+ else if (e.key === 'Escape') {
90
+ setCreating(false);
91
+ setNewTitle('');
92
+ }
93
+ };
94
+ const dropHighlight = isOver && !cell.readOnly;
95
+ return (_jsxs("div", { ref: setNodeRef, className: "min-w-[240px] w-[240px] flex-shrink-0 min-h-[120px] p-2 flex flex-col gap-1", style: {
96
+ border: dropHighlight
97
+ ? '1.5px solid var(--accent)'
98
+ : cell.readOnly
99
+ ? '1px dashed var(--ink-muted)'
100
+ : '1px solid var(--border)',
101
+ background: 'transparent',
102
+ cursor: cell.readOnly ? 'not-allowed' : 'default',
103
+ borderRadius: 0,
104
+ }, "data-testid": `cell-${columnAxis.slug}-${swimlaneAxis.slug}`, "data-column-slug": columnAxis.slug, "data-swimlane-slug": swimlaneAxis.slug, "data-readonly": cell.readOnly ? 'true' : undefined, title: cell.readOnly ? readOnlyTooltip : undefined, children: [_jsx(SortableContext, { items: itemIds, strategy: verticalListSortingStrategy, children: cell.items.map((item) => (_jsx(ItemCard, { item: item, columnSlug: columnAxis.slug, swimlaneSlug: swimlaneAxis.slug, boardSlug: board.slug, board: board }, item.slug))) }), !cell.readOnly && (_jsxs(_Fragment, { children: [!creating && (_jsx("button", { type: "button", onClick: handleAddClick, style: {
105
+ marginTop: '4px',
106
+ fontFamily: 'var(--font-mono)',
107
+ fontSize: '11px',
108
+ color: 'var(--ink-muted)',
109
+ background: 'none',
110
+ border: 'none',
111
+ padding: '4px 8px',
112
+ cursor: 'pointer',
113
+ textAlign: 'left',
114
+ }, "data-testid": `add-item-${columnAxis.slug}-${swimlaneAxis.slug}`, children: "+ add item" })), creating && (_jsxs("div", { className: "mt-1 flex flex-col gap-1", children: [_jsx("input", { ref: inputRef, type: "text", value: newTitle, onChange: (e) => setNewTitle(e.target.value), onKeyDown: handleKeyDown, placeholder: "Item title\u2026", disabled: saving, style: {
115
+ fontFamily: 'var(--font-sans)',
116
+ fontSize: '12px',
117
+ border: '1px solid var(--border)',
118
+ borderRadius: 0,
119
+ padding: '4px 8px',
120
+ width: '100%',
121
+ background: 'var(--bg)',
122
+ color: 'var(--ink)',
123
+ outline: 'none',
124
+ }, onFocus: (e) => { e.currentTarget.style.boxShadow = '0 0 0 2px var(--accent)'; }, onBlur: (e) => { e.currentTarget.style.boxShadow = 'none'; }, "data-testid": `new-item-input-${columnAxis.slug}-${swimlaneAxis.slug}` }), _jsxs("div", { className: "flex gap-1", children: [_jsx("button", { type: "button", onClick: () => void handleCreate(), disabled: saving || !newTitle.trim(), style: {
125
+ fontFamily: 'var(--font-mono)',
126
+ fontSize: '11px',
127
+ background: 'var(--accent)',
128
+ color: 'var(--on-accent)',
129
+ border: 'none',
130
+ borderRadius: 0,
131
+ padding: '2px 8px',
132
+ cursor: saving || !newTitle.trim() ? 'not-allowed' : 'pointer',
133
+ opacity: saving || !newTitle.trim() ? 0.5 : 1,
134
+ }, "data-testid": `confirm-add-${columnAxis.slug}-${swimlaneAxis.slug}`, children: saving ? '…' : 'add' }), _jsx("button", { type: "button", onClick: () => { setCreating(false); setNewTitle(''); }, disabled: saving, style: {
135
+ fontFamily: 'var(--font-mono)',
136
+ fontSize: '11px',
137
+ color: 'var(--ink-muted)',
138
+ background: 'none',
139
+ border: 'none',
140
+ borderRadius: 0,
141
+ padding: '2px 8px',
142
+ cursor: saving ? 'not-allowed' : 'pointer',
143
+ }, "data-testid": `cancel-add-${columnAxis.slug}-${swimlaneAxis.slug}`, children: "cancel" })] })] }))] }))] }));
144
+ }
145
+ //# sourceMappingURL=Cell.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Cell.js","sourceRoot":"","sources":["../../src/board/Cell.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ import React from 'react';
2
+ import type { Axis } from '@awesome-markdown/contracts';
3
+ interface ColumnHeaderProps {
4
+ column: Axis;
5
+ itemCount: number;
6
+ editable: boolean;
7
+ selected: boolean;
8
+ onEdit: () => void;
9
+ onRename: (title: string) => void;
10
+ }
11
+ /**
12
+ * Renders the header cell for a single column axis.
13
+ * Format: "TODO · 3" — uppercase mono, hairline rule below. Editable columns
14
+ * are drag handles (reorder), rename on double-click and open settings via the pencil.
15
+ */
16
+ export declare function ColumnHeader({ column, itemCount, editable, selected, onEdit, onRename, }: ColumnHeaderProps): React.ReactElement;
17
+ export {};
18
+ //# sourceMappingURL=ColumnHeader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ColumnHeader.d.ts","sourceRoot":"","sources":["../../src/board/ColumnHeader.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,6BAA6B,CAAC;AAIxD,UAAU,iBAAiB;IACzB,MAAM,EAAE,IAAI,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,OAAO,CAAC;IAClB,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACnC;AAQD;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,EAC3B,MAAM,EACN,SAAS,EACT,QAAQ,EACR,QAAQ,EACR,MAAM,EACN,QAAQ,GACT,EAAE,iBAAiB,GAAG,KAAK,CAAC,YAAY,CA2CxC"}
@@ -0,0 +1,31 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import React from 'react';
3
+ import { SortableAxis } from './layout/SortableAxis.js';
4
+ import { filterSummary } from './layout/filter-draft.js';
5
+ function orderLabel(column) {
6
+ if (!column.order)
7
+ return 'recently updated';
8
+ if (column.order.by === 'boards.$board.order')
9
+ return 'manual';
10
+ return `by ${column.order.by} ${column.order.direction === 'desc' ? '↓' : '↑'}`;
11
+ }
12
+ /**
13
+ * Renders the header cell for a single column axis.
14
+ * Format: "TODO · 3" — uppercase mono, hairline rule below. Editable columns
15
+ * are drag handles (reorder), rename on double-click and open settings via the pencil.
16
+ */
17
+ export function ColumnHeader({ column, itemCount, editable, selected, onEdit, onRename, }) {
18
+ return (_jsx(SortableAxis, { dim: "columns", axis: column, editable: editable, selected: selected, label: `${column.title} · ${itemCount}`, subtitle: editable ? `${filterSummary(column.filter)} · ${orderLabel(column)}` : undefined, onEdit: onEdit, onRename: onRename, children: ({ setNodeRef, style, handleProps, handleClassName, title }) => (_jsx("div", { ref: setNodeRef, ...handleProps, className: `min-w-[240px] w-[240px] flex-shrink-0 px-3 py-2 ${handleClassName}`, style: {
19
+ ...style,
20
+ borderBottom: selected ? '3px solid var(--accent)' : '1px solid var(--border)',
21
+ background: 'var(--bg)',
22
+ }, "data-testid": `column-header-${column.slug}`, "data-column-slug": column.slug, "data-synthetic": column.synthetic ? 'true' : undefined, children: _jsx("span", { className: "block", style: {
23
+ fontFamily: 'var(--font-mono)',
24
+ fontSize: '11px',
25
+ fontWeight: 500,
26
+ textTransform: 'uppercase',
27
+ letterSpacing: '0.08em',
28
+ color: 'var(--ink-muted)',
29
+ }, children: title }) })) }));
30
+ }
31
+ //# sourceMappingURL=ColumnHeader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ColumnHeader.js","sourceRoot":"","sources":["../../src/board/ColumnHeader.tsx"],"names":[],"mappings":";AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AACxD,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAWzD,SAAS,UAAU,CAAC,MAAY;IAC9B,IAAI,CAAC,MAAM,CAAC,KAAK;QAAE,OAAO,kBAAkB,CAAC;IAC7C,IAAI,MAAM,CAAC,KAAK,CAAC,EAAE,KAAK,qBAAqB;QAAE,OAAO,QAAQ,CAAC;IAC/D,OAAO,MAAM,MAAM,CAAC,KAAK,CAAC,EAAE,IAAI,MAAM,CAAC,KAAK,CAAC,SAAS,KAAK,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC;AAClF,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,YAAY,CAAC,EAC3B,MAAM,EACN,SAAS,EACT,QAAQ,EACR,QAAQ,EACR,MAAM,EACN,QAAQ,GACU;IAClB,OAAO,CACL,KAAC,YAAY,IACX,GAAG,EAAC,SAAS,EACb,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,QAAQ,EAClB,QAAQ,EAAE,QAAQ,EAClB,KAAK,EAAE,GAAG,MAAM,CAAC,KAAK,MAAM,SAAS,EAAE,EACvC,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC,GAAG,aAAa,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,EAC1F,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,QAAQ,YAEjB,CAAC,EAAE,UAAU,EAAE,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAC/D,cACE,GAAG,EAAE,UAAU,KACX,WAAW,EACf,SAAS,EAAE,mDAAmD,eAAe,EAAE,EAC/E,KAAK,EAAE;gBACL,GAAG,KAAK;gBACR,YAAY,EAAE,QAAQ,CAAC,CAAC,CAAC,yBAAyB,CAAC,CAAC,CAAC,yBAAyB;gBAC9E,UAAU,EAAE,WAAW;aACxB,iBACY,iBAAiB,MAAM,CAAC,IAAI,EAAE,sBACzB,MAAM,CAAC,IAAI,oBACb,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,YAErD,eACE,SAAS,EAAC,OAAO,EACjB,KAAK,EAAE;oBACL,UAAU,EAAE,kBAAkB;oBAC9B,QAAQ,EAAE,MAAM;oBAChB,UAAU,EAAE,GAAG;oBACf,aAAa,EAAE,WAAW;oBAC1B,aAAa,EAAE,QAAQ;oBACvB,KAAK,EAAE,kBAAkB;iBAC1B,YAEA,KAAK,GACD,GACH,CACP,GACY,CAChB,CAAC;AACJ,CAAC"}
@@ -0,0 +1,15 @@
1
+ import React from 'react';
2
+ import type { Item } from '@awesome-markdown/contracts';
3
+ interface HomelessItemCardProps {
4
+ item: Item;
5
+ }
6
+ /**
7
+ * A draggable card for homeless items. Uses `useDraggable` (not `useSortable`)
8
+ * because the homeless panel is a drag source only — no in-panel reordering.
9
+ *
10
+ * Carries `HomelessItemDragData` so Board.handleDragEnd can distinguish it
11
+ * from a regular cell-to-cell item drag.
12
+ */
13
+ export declare function HomelessItemCard({ item }: HomelessItemCardProps): React.ReactElement;
14
+ export {};
15
+ //# sourceMappingURL=HomelessItemCard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"HomelessItemCard.d.ts","sourceRoot":"","sources":["../../src/board/HomelessItemCard.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAG1B,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,6BAA6B,CAAC;AAGxD,UAAU,qBAAqB;IAC7B,IAAI,EAAE,IAAI,CAAC;CACZ;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,EAAE,IAAI,EAAE,EAAE,qBAAqB,GAAG,KAAK,CAAC,YAAY,CAqCpF"}
@@ -0,0 +1,36 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import React from 'react';
3
+ import { useDraggable } from '@dnd-kit/core';
4
+ import { CSS } from '@dnd-kit/utilities';
5
+ /**
6
+ * A draggable card for homeless items. Uses `useDraggable` (not `useSortable`)
7
+ * because the homeless panel is a drag source only — no in-panel reordering.
8
+ *
9
+ * Carries `HomelessItemDragData` so Board.handleDragEnd can distinguish it
10
+ * from a regular cell-to-cell item drag.
11
+ */
12
+ export function HomelessItemCard({ item }) {
13
+ const dragData = {
14
+ type: 'homeless-item',
15
+ itemSlug: item.slug,
16
+ };
17
+ const { attributes, listeners, setNodeRef, transform, isDragging } = useDraggable({
18
+ id: item.slug,
19
+ data: dragData,
20
+ });
21
+ const style = {
22
+ transform: CSS.Translate.toString(transform),
23
+ fontFamily: 'var(--font-sans)',
24
+ fontSize: '13px',
25
+ color: 'var(--ink)',
26
+ border: '1px solid var(--border)',
27
+ padding: '2px 10px',
28
+ background: 'var(--bg)',
29
+ cursor: isDragging ? 'grabbing' : 'grab',
30
+ opacity: isDragging ? 0.4 : 1,
31
+ userSelect: 'none',
32
+ touchAction: 'none',
33
+ };
34
+ return (_jsx("li", { ref: setNodeRef, style: style, "data-testid": `homeless-item-${item.slug}`, "data-item-slug": item.slug, ...attributes, ...listeners, children: item.title }));
35
+ }
36
+ //# sourceMappingURL=HomelessItemCard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"HomelessItemCard.js","sourceRoot":"","sources":["../../src/board/HomelessItemCard.tsx"],"names":[],"mappings":";AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,EAAE,GAAG,EAAE,MAAM,oBAAoB,CAAC;AAQzC;;;;;;GAMG;AACH,MAAM,UAAU,gBAAgB,CAAC,EAAE,IAAI,EAAyB;IAC9D,MAAM,QAAQ,GAAyB;QACrC,IAAI,EAAE,eAAe;QACrB,QAAQ,EAAE,IAAI,CAAC,IAAI;KACpB,CAAC;IAEF,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,EAAE,GAAG,YAAY,CAAC;QAChF,EAAE,EAAE,IAAI,CAAC,IAAI;QACb,IAAI,EAAE,QAAQ;KACf,CAAC,CAAC;IAEH,MAAM,KAAK,GAAwB;QACjC,SAAS,EAAE,GAAG,CAAC,SAAS,CAAC,QAAQ,CAAC,SAAS,CAAC;QAC5C,UAAU,EAAE,kBAAkB;QAC9B,QAAQ,EAAE,MAAM;QAChB,KAAK,EAAE,YAAY;QACnB,MAAM,EAAE,yBAAyB;QACjC,OAAO,EAAE,UAAU;QACnB,UAAU,EAAE,WAAW;QACvB,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,MAAM;QACxC,OAAO,EAAE,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QAC7B,UAAU,EAAE,MAAM;QAClB,WAAW,EAAE,MAAM;KACpB,CAAC;IAEF,OAAO,CACL,aACE,GAAG,EAAE,UAAU,EACf,KAAK,EAAE,KAAK,iBACC,iBAAiB,IAAI,CAAC,IAAI,EAAE,oBACzB,IAAI,CAAC,IAAI,KACrB,UAAU,KACV,SAAS,YAEZ,IAAI,CAAC,KAAK,GACR,CACN,CAAC;AACJ,CAAC"}
@@ -0,0 +1,17 @@
1
+ import React from 'react';
2
+ import type { Homeless, Item } from '@awesome-markdown/contracts';
3
+ interface HomelessPanelProps {
4
+ homeless: Homeless;
5
+ /**
6
+ * When provided, overrides `homeless.items` for rendering (e.g. to hide
7
+ * items that have been optimistically moved into a cell).
8
+ */
9
+ items?: Item[];
10
+ }
11
+ /**
12
+ * Collapsible panel listing items that belong to this board but no longer
13
+ * match any column filter. Populated from GET /boards/:slug/homeless.
14
+ */
15
+ export declare function HomelessPanel({ homeless, items: itemsProp }: HomelessPanelProps): React.ReactElement;
16
+ export {};
17
+ //# sourceMappingURL=HomelessPanel.d.ts.map