@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
@@ -0,0 +1 @@
1
+ {"version":3,"file":"axis-defaults.d.ts","sourceRoot":"","sources":["../../../src/board/layout/axis-defaults.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAEhF,MAAM,MAAM,OAAO,GAAG,SAAS,GAAG,WAAW,CAAC;AAE9C,6DAA6D;AAC7D,eAAO,MAAM,YAAY,EAAE,SAA2D,CAAC;AAEvF;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,UAAU,CAKxE;AAED,wBAAgB,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,SAAa,GAAG,MAAM,CAOpE;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,CAAC,MAAM,CAAC,GAAG,MAAM,CAK3E;AAED,2FAA2F;AAC3F,wBAAgB,aAAa,CAAC,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,OAAO,GAAG,MAAM,EAAE,CAElE;AAMD,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,OAAO,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED,wBAAgB,UAAU,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAE7D"}
@@ -0,0 +1,37 @@
1
+ /** Manual order — each item's per-board fractional index. */
2
+ export const MANUAL_ORDER = { by: 'boards.$board.order', direction: 'asc' };
3
+ /**
4
+ * Filter for a freshly added axis: `boards.$board.column: <slug>` /
5
+ * `boards.$board.row: <slug>`. Scoped per board so the same item can sit in
6
+ * different columns/rows on different boards. It starts empty and stays
7
+ * invertible, so dropping a card writes that property on the board entry.
8
+ */
9
+ export function defaultAxisFilter(dim, slug) {
10
+ return {
11
+ property: dim === 'columns' ? 'boards.$board.column' : 'boards.$board.row',
12
+ equals: slug,
13
+ };
14
+ }
15
+ export function slugify(title, fallback = 'untitled') {
16
+ const s = title
17
+ .toLowerCase()
18
+ .trim()
19
+ .replace(/[^a-z0-9]+/g, '-')
20
+ .replace(/^-|-$/g, '');
21
+ return s.length > 0 ? s : fallback;
22
+ }
23
+ export function uniqueSlug(base, taken) {
24
+ let candidate = base;
25
+ let suffix = 2;
26
+ while (taken.has(candidate))
27
+ candidate = `${base}-${suffix++}`;
28
+ return candidate;
29
+ }
30
+ /** Axis slugs the board itself declares (empty when the render uses the implicit axis). */
31
+ export function declaredSlugs(board, dim) {
32
+ return board[dim] ?? [];
33
+ }
34
+ export function axisDragId(dim, slug) {
35
+ return `axis:${dim}:${slug}`;
36
+ }
37
+ //# sourceMappingURL=axis-defaults.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"axis-defaults.js","sourceRoot":"","sources":["../../../src/board/layout/axis-defaults.ts"],"names":[],"mappings":"AAIA,6DAA6D;AAC7D,MAAM,CAAC,MAAM,YAAY,GAAc,EAAE,EAAE,EAAE,qBAAqB,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;AAEvF;;;;;GAKG;AACH,MAAM,UAAU,iBAAiB,CAAC,GAAY,EAAE,IAAY;IAC1D,OAAO;QACL,QAAQ,EAAE,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAC,mBAAmB;QAC1E,MAAM,EAAE,IAAI;KACb,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,OAAO,CAAC,KAAa,EAAE,QAAQ,GAAG,UAAU;IAC1D,MAAM,CAAC,GAAG,KAAK;SACZ,WAAW,EAAE;SACb,IAAI,EAAE;SACN,OAAO,CAAC,aAAa,EAAE,GAAG,CAAC;SAC3B,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;IACzB,OAAO,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;AACrC,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,IAAY,EAAE,KAA0B;IACjE,IAAI,SAAS,GAAG,IAAI,CAAC;IACrB,IAAI,MAAM,GAAG,CAAC,CAAC;IACf,OAAO,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC;QAAE,SAAS,GAAG,GAAG,IAAI,IAAI,MAAM,EAAE,EAAE,CAAC;IAC/D,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,2FAA2F;AAC3F,MAAM,UAAU,aAAa,CAAC,KAAY,EAAE,GAAY;IACtD,OAAO,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;AAC1B,CAAC;AAYD,MAAM,UAAU,UAAU,CAAC,GAAY,EAAE,IAAY;IACnD,OAAO,QAAQ,GAAG,IAAI,IAAI,EAAE,CAAC;AAC/B,CAAC"}
@@ -0,0 +1,21 @@
1
+ import type { FilterRule } from '@awesome-markdown/contracts';
2
+ export type CondOp = 'equals' | 'in' | 'has' | 'lacks' | 'exists' | 'missing' | 'gt' | 'gte' | 'lt' | 'lte' | 'matches';
3
+ export declare const COND_OPS: ReadonlyArray<[CondOp, string]>;
4
+ export interface CondDraft {
5
+ property: string;
6
+ op: CondOp;
7
+ value: string;
8
+ /** Original typed value, reused on save when the text is unchanged. */
9
+ original?: unknown;
10
+ }
11
+ export interface FilterDraft {
12
+ combinator: 'all' | 'any';
13
+ conds: CondDraft[];
14
+ }
15
+ /** Flat draft for the builder, or `null` when the rule nests groups / `not`. */
16
+ export declare function toDraft(rule: FilterRule | undefined): FilterDraft | null;
17
+ /** Rule for the draft; `undefined` when no complete condition remains. */
18
+ export declare function fromDraft(draft: FilterDraft): FilterRule | undefined;
19
+ /** One-line human summary, e.g. `status is todo or status is done`. */
20
+ export declare function filterSummary(rule: FilterRule | undefined, none?: string): string;
21
+ //# sourceMappingURL=filter-draft.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"filter-draft.d.ts","sourceRoot":"","sources":["../../../src/board/layout/filter-draft.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAc,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAE1E,MAAM,MAAM,MAAM,GACd,QAAQ,GACR,IAAI,GACJ,KAAK,GACL,OAAO,GACP,QAAQ,GACR,SAAS,GACT,IAAI,GACJ,KAAK,GACL,IAAI,GACJ,KAAK,GACL,SAAS,CAAC;AAEd,eAAO,MAAM,QAAQ,EAAE,aAAa,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAYpD,CAAC;AAEF,MAAM,WAAW,SAAS;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,uEAAuE;IACvE,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,WAAW;IAC1B,UAAU,EAAE,KAAK,GAAG,KAAK,CAAC;IAC1B,KAAK,EAAE,SAAS,EAAE,CAAC;CACpB;AAmCD,gFAAgF;AAChF,wBAAgB,OAAO,CAAC,IAAI,EAAE,UAAU,GAAG,SAAS,GAAG,WAAW,GAAG,IAAI,CAQxE;AAkCD,0EAA0E;AAC1E,wBAAgB,SAAS,CAAC,KAAK,EAAE,WAAW,GAAG,UAAU,GAAG,SAAS,CAKpE;AASD,uEAAuE;AACvE,wBAAgB,aAAa,CAAC,IAAI,EAAE,UAAU,GAAG,SAAS,EAAE,IAAI,SAAc,GAAG,MAAM,CAKtF"}
@@ -0,0 +1,110 @@
1
+ export const COND_OPS = [
2
+ ['equals', 'is'],
3
+ ['in', 'is one of'],
4
+ ['has', 'contains'],
5
+ ['lacks', "doesn't contain"],
6
+ ['exists', 'is set'],
7
+ ['missing', 'is not set'],
8
+ ['gt', '>'],
9
+ ['gte', '≥'],
10
+ ['lt', '<'],
11
+ ['lte', '≤'],
12
+ ['matches', 'matches regex'],
13
+ ];
14
+ const LEAF_KEYS = [
15
+ 'equals',
16
+ 'in',
17
+ 'has',
18
+ 'lacks',
19
+ 'exists',
20
+ 'gt',
21
+ 'gte',
22
+ 'lt',
23
+ 'lte',
24
+ 'matches',
25
+ ];
26
+ function leafToCond(leaf) {
27
+ const rec = leaf;
28
+ const key = LEAF_KEYS.find((k) => k in rec) ?? 'equals';
29
+ const raw = rec[key];
30
+ if (key === 'exists')
31
+ return { property: leaf.property, op: raw === false ? 'missing' : 'exists', value: '' };
32
+ if (key === 'in')
33
+ return {
34
+ property: leaf.property,
35
+ op: 'in',
36
+ value: raw.join(', '),
37
+ original: raw,
38
+ };
39
+ return { property: leaf.property, op: key, value: String(raw), original: raw };
40
+ }
41
+ function isLeaf(rule) {
42
+ return 'property' in rule;
43
+ }
44
+ /** Flat draft for the builder, or `null` when the rule nests groups / `not`. */
45
+ export function toDraft(rule) {
46
+ if (!rule)
47
+ return { combinator: 'all', conds: [] };
48
+ if (isLeaf(rule))
49
+ return { combinator: 'all', conds: [leafToCond(rule)] };
50
+ if ('all' in rule && rule.all.every(isLeaf))
51
+ return { combinator: 'all', conds: rule.all.map(leafToCond) };
52
+ if ('any' in rule && rule.any.every(isLeaf))
53
+ return { combinator: 'any', conds: rule.any.map(leafToCond) };
54
+ return null;
55
+ }
56
+ function typedValue(cond) {
57
+ if (cond.original !== undefined && String(cond.original) === cond.value)
58
+ return cond.original;
59
+ const numeric = /^-?\d+(\.\d+)?$/.test(cond.value.trim());
60
+ const comparison = cond.op === 'gt' || cond.op === 'gte' || cond.op === 'lt' || cond.op === 'lte';
61
+ return numeric && comparison ? Number(cond.value) : cond.value;
62
+ }
63
+ function condToLeaf(cond) {
64
+ const property = cond.property.trim();
65
+ switch (cond.op) {
66
+ case 'exists':
67
+ return { property, exists: true };
68
+ case 'missing':
69
+ return { property, exists: false };
70
+ case 'in':
71
+ return {
72
+ property,
73
+ in: cond.value
74
+ .split(',')
75
+ .map((v) => v.trim())
76
+ .filter(Boolean),
77
+ };
78
+ case 'equals':
79
+ return { property, equals: typedValue(cond) };
80
+ case 'matches':
81
+ return { property, matches: cond.value };
82
+ default:
83
+ return { property, [cond.op]: typedValue(cond) };
84
+ }
85
+ }
86
+ /** Rule for the draft; `undefined` when no complete condition remains. */
87
+ export function fromDraft(draft) {
88
+ const leaves = draft.conds.filter((c) => c.property.trim() !== '').map(condToLeaf);
89
+ if (leaves.length === 0)
90
+ return undefined;
91
+ if (leaves.length === 1)
92
+ return leaves[0];
93
+ return draft.combinator === 'any' ? { any: leaves } : { all: leaves };
94
+ }
95
+ function condText(c) {
96
+ const label = COND_OPS.find(([op]) => op === c.op)?.[1] ?? c.op;
97
+ return c.op === 'exists' || c.op === 'missing'
98
+ ? `${c.property} ${label}`
99
+ : `${c.property} ${label} ${c.value}`;
100
+ }
101
+ /** One-line human summary, e.g. `status is todo or status is done`. */
102
+ export function filterSummary(rule, none = 'all cards') {
103
+ const draft = toDraft(rule);
104
+ if (!draft)
105
+ return 'custom filter';
106
+ if (draft.conds.length === 0)
107
+ return none;
108
+ return draft.conds.map(condText).join(draft.combinator === 'any' ? ' or ' : ' and ');
109
+ }
110
+ //# sourceMappingURL=filter-draft.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"filter-draft.js","sourceRoot":"","sources":["../../../src/board/layout/filter-draft.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ import type { Axis, BoardRender, PatchAxisRequest, PatchBoardRequest } from '@awesome-markdown/contracts';
2
+ import type { AxisDim } from './axis-defaults.js';
3
+ export interface AxisUsage {
4
+ board: string;
5
+ dim: AxisDim;
6
+ }
7
+ export interface BoardLayout {
8
+ /** Axes in display order, with any in-flight reorder applied. */
9
+ columns: Axis[];
10
+ swimlanes: Axis[];
11
+ /** True when the board declares no axes for the dimension (implicit axis shown). */
12
+ implicit: Record<AxisDim, boolean>;
13
+ /** Each action resolves `false` after reporting a failure through `onError`. */
14
+ addAxis: (dim: AxisDim, title: string) => Promise<boolean>;
15
+ moveAxis: (dim: AxisDim, activeSlug: string, overSlug: string) => Promise<boolean>;
16
+ removeAxis: (dim: AxisDim, slug: string) => Promise<boolean>;
17
+ saveAxis: (slug: string, patch: PatchAxisRequest) => Promise<boolean>;
18
+ saveBoard: (patch: PatchBoardRequest) => Promise<boolean>;
19
+ /** Other boards that reference the axis — edits to it change them too. */
20
+ usage: (slug: string) => AxisUsage[];
21
+ }
22
+ /**
23
+ * Layout editing for a rendered board. Every action is one immediate write
24
+ * (plus a createAxis when adding), then a refetch.
25
+ */
26
+ export declare function useBoardLayout(render: BoardRender, onRefetch: () => void, onError: (msg: string) => void): BoardLayout;
27
+ //# sourceMappingURL=useBoardLayout.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useBoardLayout.d.ts","sourceRoot":"","sources":["../../../src/board/layout/useBoardLayout.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,IAAI,EAEJ,WAAW,EACX,gBAAgB,EAChB,iBAAiB,EAClB,MAAM,6BAA6B,CAAC;AAUrC,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAElD,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,OAAO,CAAC;CACd;AAED,MAAM,WAAW,WAAW;IAC1B,iEAAiE;IACjE,OAAO,EAAE,IAAI,EAAE,CAAC;IAChB,SAAS,EAAE,IAAI,EAAE,CAAC;IAClB,oFAAoF;IACpF,QAAQ,EAAE,MAAM,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IACnC,gFAAgF;IAChF,OAAO,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAC3D,QAAQ,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IACnF,UAAU,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAC7D,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,gBAAgB,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IACtE,SAAS,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAC1D,0EAA0E;IAC1E,KAAK,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,SAAS,EAAE,CAAC;CACtC;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAC5B,MAAM,EAAE,WAAW,EACnB,SAAS,EAAE,MAAM,IAAI,EACrB,OAAO,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,GAC7B,WAAW,CA+Gb"}
@@ -0,0 +1,92 @@
1
+ import { useCallback, useEffect, useMemo, useState } from 'react';
2
+ import { arrayMove } from '@dnd-kit/sortable';
3
+ import { useProvider } from '../../provider/ProviderContext.js';
4
+ import { useProviderSubscribe } from '../../state/useProviderSubscribe.js';
5
+ import { MANUAL_ORDER, declaredSlugs, defaultAxisFilter, slugify, uniqueSlug, } from './axis-defaults.js';
6
+ /**
7
+ * Layout editing for a rendered board. Every action is one immediate write
8
+ * (plus a createAxis when adding), then a refetch.
9
+ */
10
+ export function useBoardLayout(render, onRefetch, onError) {
11
+ const provider = useProvider();
12
+ const board = render.board;
13
+ const [pending, setPending] = useState({});
14
+ const [boards, setBoards] = useState([]);
15
+ const loadBoards = useCallback(() => {
16
+ provider.listBoards().then(setBoards, () => setBoards([]));
17
+ }, [provider]);
18
+ useEffect(loadBoards, [loadBoards]);
19
+ useProviderSubscribe(loadBoards);
20
+ useEffect(() => setPending({}), [render]);
21
+ const run = useCallback(async (label, action) => {
22
+ try {
23
+ await action();
24
+ return true;
25
+ }
26
+ catch (err) {
27
+ setPending({});
28
+ onError(`Failed to ${label}: ${err instanceof Error ? err.message : 'Unknown error'}`);
29
+ return false;
30
+ }
31
+ finally {
32
+ onRefetch();
33
+ }
34
+ }, [onRefetch, onError]);
35
+ const ordered = (dim) => {
36
+ const axes = render.axes[dim];
37
+ const order = pending[dim];
38
+ if (!order)
39
+ return axes;
40
+ return order
41
+ .map((slug) => axes.find((a) => a.slug === slug))
42
+ .filter((a) => a !== undefined);
43
+ };
44
+ const addAxis = useCallback((dim, title) => run('add axis', async () => {
45
+ const taken = new Set((await provider.listAxes()).map((a) => a.slug));
46
+ const slug = uniqueSlug(slugify(title, dim === 'columns' ? 'column' : 'row'), taken);
47
+ await provider.createAxis({
48
+ slug,
49
+ title,
50
+ filter: defaultAxisFilter(dim, slug),
51
+ order: MANUAL_ORDER,
52
+ });
53
+ await provider.patchBoard(board.slug, { [dim]: [...declaredSlugs(board, dim), slug] });
54
+ }), [run, provider, board]);
55
+ const moveAxis = useCallback((dim, activeSlug, overSlug) => {
56
+ const list = declaredSlugs(board, dim);
57
+ const from = list.indexOf(activeSlug);
58
+ const to = list.indexOf(overSlug);
59
+ if (from < 0 || to < 0 || from === to)
60
+ return Promise.resolve(true);
61
+ const next = arrayMove(list, from, to);
62
+ setPending((p) => ({ ...p, [dim]: next }));
63
+ return run('reorder', () => provider.patchBoard(board.slug, { [dim]: next }));
64
+ }, [run, provider, board]);
65
+ const removeAxis = useCallback((dim, slug) => run('remove axis', () => provider.patchBoard(board.slug, {
66
+ [dim]: declaredSlugs(board, dim).filter((s) => s !== slug),
67
+ })), [run, provider, board]);
68
+ const saveAxis = useCallback((slug, patch) => run('save axis', () => provider.patchAxis(slug, patch)), [run, provider]);
69
+ const saveBoard = useCallback((patch) => run('save board', () => provider.patchBoard(board.slug, patch)), [run, provider, board.slug]);
70
+ const usage = useMemo(() => {
71
+ const others = boards.filter((b) => b.slug !== board.slug);
72
+ return (slug) => others.flatMap((b) => [
73
+ ...(b.columns?.includes(slug) ? [{ board: b.slug, dim: 'columns' }] : []),
74
+ ...(b.swimlanes?.includes(slug) ? [{ board: b.slug, dim: 'swimlanes' }] : []),
75
+ ]);
76
+ }, [boards, board.slug]);
77
+ return {
78
+ columns: ordered('columns'),
79
+ swimlanes: ordered('swimlanes'),
80
+ implicit: {
81
+ columns: declaredSlugs(board, 'columns').length === 0,
82
+ swimlanes: declaredSlugs(board, 'swimlanes').length === 0,
83
+ },
84
+ addAxis,
85
+ moveAxis,
86
+ removeAxis,
87
+ saveAxis,
88
+ saveBoard,
89
+ usage,
90
+ };
91
+ }
92
+ //# sourceMappingURL=useBoardLayout.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useBoardLayout.js","sourceRoot":"","sources":["../../../src/board/layout/useBoardLayout.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAClE,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAQ9C,OAAO,EAAE,WAAW,EAAE,MAAM,mCAAmC,CAAC;AAChE,OAAO,EAAE,oBAAoB,EAAE,MAAM,qCAAqC,CAAC;AAC3E,OAAO,EACL,YAAY,EACZ,aAAa,EACb,iBAAiB,EACjB,OAAO,EACP,UAAU,GACX,MAAM,oBAAoB,CAAC;AAwB5B;;;GAGG;AACH,MAAM,UAAU,cAAc,CAC5B,MAAmB,EACnB,SAAqB,EACrB,OAA8B;IAE9B,MAAM,QAAQ,GAAG,WAAW,EAAE,CAAC;IAC/B,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC;IAC3B,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,QAAQ,CAAqC,EAAE,CAAC,CAAC;IAC/E,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,CAAU,EAAE,CAAC,CAAC;IAElD,MAAM,UAAU,GAAG,WAAW,CAAC,GAAG,EAAE;QAClC,QAAQ,CAAC,UAAU,EAAE,CAAC,IAAI,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC;IAC7D,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC;IACf,SAAS,CAAC,UAAU,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC;IACpC,oBAAoB,CAAC,UAAU,CAAC,CAAC;IACjC,SAAS,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC;IAE1C,MAAM,GAAG,GAAG,WAAW,CACrB,KAAK,EAAE,KAAa,EAAE,MAA8B,EAAoB,EAAE;QACxE,IAAI,CAAC;YACH,MAAM,MAAM,EAAE,CAAC;YACf,OAAO,IAAI,CAAC;QACd,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,UAAU,CAAC,EAAE,CAAC,CAAC;YACf,OAAO,CAAC,aAAa,KAAK,KAAK,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,EAAE,CAAC,CAAC;YACvF,OAAO,KAAK,CAAC;QACf,CAAC;gBAAS,CAAC;YACT,SAAS,EAAE,CAAC;QACd,CAAC;IACH,CAAC,EACD,CAAC,SAAS,EAAE,OAAO,CAAC,CACrB,CAAC;IAEF,MAAM,OAAO,GAAG,CAAC,GAAY,EAAU,EAAE;QACvC,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC9B,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;QAC3B,IAAI,CAAC,KAAK;YAAE,OAAO,IAAI,CAAC;QACxB,OAAO,KAAK;aACT,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;aAChD,MAAM,CAAC,CAAC,CAAC,EAAa,EAAE,CAAC,CAAC,KAAK,SAAS,CAAC,CAAC;IAC/C,CAAC,CAAC;IAEF,MAAM,OAAO,GAAG,WAAW,CACzB,CAAC,GAAY,EAAE,KAAa,EAAE,EAAE,CAC9B,GAAG,CAAC,UAAU,EAAE,KAAK,IAAI,EAAE;QACzB,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,CAAC,MAAM,QAAQ,CAAC,QAAQ,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;QACtE,MAAM,IAAI,GAAG,UAAU,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,KAAK,CAAC,CAAC;QACrF,MAAM,QAAQ,CAAC,UAAU,CAAC;YACxB,IAAI;YACJ,KAAK;YACL,MAAM,EAAE,iBAAiB,CAAC,GAAG,EAAE,IAAI,CAAC;YACpC,KAAK,EAAE,YAAY;SACpB,CAAC,CAAC;QACH,MAAM,QAAQ,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,aAAa,CAAC,KAAK,EAAE,GAAG,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC;IACzF,CAAC,CAAC,EACJ,CAAC,GAAG,EAAE,QAAQ,EAAE,KAAK,CAAC,CACvB,CAAC;IAEF,MAAM,QAAQ,GAAG,WAAW,CAC1B,CAAC,GAAY,EAAE,UAAkB,EAAE,QAAgB,EAAE,EAAE;QACrD,MAAM,IAAI,GAAG,aAAa,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;QACvC,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;QACtC,MAAM,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QAClC,IAAI,IAAI,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,IAAI,IAAI,KAAK,EAAE;YAAE,OAAO,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QACpE,MAAM,IAAI,GAAG,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC;QACvC,UAAU,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;QAC3C,OAAO,GAAG,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IAChF,CAAC,EACD,CAAC,GAAG,EAAE,QAAQ,EAAE,KAAK,CAAC,CACvB,CAAC;IAEF,MAAM,UAAU,GAAG,WAAW,CAC5B,CAAC,GAAY,EAAE,IAAY,EAAE,EAAE,CAC7B,GAAG,CAAC,aAAa,EAAE,GAAG,EAAE,CACtB,QAAQ,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,EAAE;QAC9B,CAAC,GAAG,CAAC,EAAE,aAAa,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,IAAI,CAAC;KAC3D,CAAC,CACH,EACH,CAAC,GAAG,EAAE,QAAQ,EAAE,KAAK,CAAC,CACvB,CAAC;IAEF,MAAM,QAAQ,GAAG,WAAW,CAC1B,CAAC,IAAY,EAAE,KAAuB,EAAE,EAAE,CACxC,GAAG,CAAC,WAAW,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,EACzD,CAAC,GAAG,EAAE,QAAQ,CAAC,CAChB,CAAC;IAEF,MAAM,SAAS,GAAG,WAAW,CAC3B,CAAC,KAAwB,EAAE,EAAE,CAAC,GAAG,CAAC,YAAY,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,EAC7F,CAAC,GAAG,EAAE,QAAQ,EAAE,KAAK,CAAC,IAAI,CAAC,CAC5B,CAAC;IAEF,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,EAAE;QACzB,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,KAAK,CAAC,IAAI,CAAC,CAAC;QAC3D,OAAO,CAAC,IAAY,EAAe,EAAE,CACnC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;YACpB,GAAG,CAAC,CAAC,CAAC,OAAO,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,IAAI,EAAE,GAAG,EAAE,SAAkB,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YAClF,GAAG,CAAC,CAAC,CAAC,SAAS,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,IAAI,EAAE,GAAG,EAAE,WAAoB,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;SACvF,CAAC,CAAC;IACP,CAAC,EAAE,CAAC,MAAM,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;IAEzB,OAAO;QACL,OAAO,EAAE,OAAO,CAAC,SAAS,CAAC;QAC3B,SAAS,EAAE,OAAO,CAAC,WAAW,CAAC;QAC/B,QAAQ,EAAE;YACR,OAAO,EAAE,aAAa,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC,MAAM,KAAK,CAAC;YACrD,SAAS,EAAE,aAAa,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC,MAAM,KAAK,CAAC;SAC1D;QACD,OAAO;QACP,QAAQ;QACR,UAAU;QACV,QAAQ;QACR,SAAS;QACT,KAAK;KACN,CAAC;AACJ,CAAC"}
@@ -0,0 +1,22 @@
1
+ /** One breadcrumb path segment pushed by a board-ui page. `to` is board-relative. */
2
+ export interface BreadcrumbSegment {
3
+ label: string;
4
+ to?: string;
5
+ /** When true, render `→` before this segment instead of `/` */
6
+ arrow?: boolean;
7
+ }
8
+ export interface BreadcrumbContextValue {
9
+ segments: BreadcrumbSegment[];
10
+ setSegments: (s: BreadcrumbSegment[]) => void;
11
+ }
12
+ /**
13
+ * Optional breadcrumb channel from board-ui pages to the host shell.
14
+ * Without a provider the default is a no-op, so hosts that don't render a
15
+ * breadcrumb can ignore it.
16
+ */
17
+ export declare const BreadcrumbContext: import("react").Context<BreadcrumbContextValue>;
18
+ /** Used by pages to push their breadcrumb path segments. */
19
+ export declare function useBreadcrumb(): {
20
+ setSegments: (s: BreadcrumbSegment[]) => void;
21
+ };
22
+ //# sourceMappingURL=breadcrumb.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"breadcrumb.d.ts","sourceRoot":"","sources":["../src/breadcrumb.ts"],"names":[],"mappings":"AAEA,qFAAqF;AACrF,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,+DAA+D;IAC/D,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,sBAAsB;IACrC,QAAQ,EAAE,iBAAiB,EAAE,CAAC;IAC9B,WAAW,EAAE,CAAC,CAAC,EAAE,iBAAiB,EAAE,KAAK,IAAI,CAAC;CAC/C;AAED;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,iDAG5B,CAAC;AAEH,4DAA4D;AAC5D,wBAAgB,aAAa,IAAI;IAAE,WAAW,EAAE,CAAC,CAAC,EAAE,iBAAiB,EAAE,KAAK,IAAI,CAAA;CAAE,CAEjF"}
@@ -0,0 +1,15 @@
1
+ import { createContext, useContext } from 'react';
2
+ /**
3
+ * Optional breadcrumb channel from board-ui pages to the host shell.
4
+ * Without a provider the default is a no-op, so hosts that don't render a
5
+ * breadcrumb can ignore it.
6
+ */
7
+ export const BreadcrumbContext = createContext({
8
+ segments: [],
9
+ setSegments: () => undefined,
10
+ });
11
+ /** Used by pages to push their breadcrumb path segments. */
12
+ export function useBreadcrumb() {
13
+ return useContext(BreadcrumbContext);
14
+ }
15
+ //# sourceMappingURL=breadcrumb.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"breadcrumb.js","sourceRoot":"","sources":["../src/breadcrumb.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;AAelD;;;;GAIG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,aAAa,CAAyB;IACrE,QAAQ,EAAE,EAAE;IACZ,WAAW,EAAE,GAAG,EAAE,CAAC,SAAS;CAC7B,CAAC,CAAC;AAEH,4DAA4D;AAC5D,MAAM,UAAU,aAAa;IAC3B,OAAO,UAAU,CAAC,iBAAiB,CAAC,CAAC;AACvC,CAAC"}
@@ -0,0 +1,10 @@
1
+ import React from 'react';
2
+ interface BoardAssigneeFieldProps {
3
+ boardSlug: string;
4
+ value: string;
5
+ disabled?: boolean;
6
+ onChange: (value: string) => void;
7
+ }
8
+ export declare function BoardAssigneeField({ boardSlug, value, disabled, onChange, }: BoardAssigneeFieldProps): React.ReactElement;
9
+ export {};
10
+ //# sourceMappingURL=BoardAssigneeField.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BoardAssigneeField.d.ts","sourceRoot":"","sources":["../../src/components/BoardAssigneeField.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,UAAU,uBAAuB;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACnC;AAED,wBAAgB,kBAAkB,CAAC,EACjC,SAAS,EACT,KAAK,EACL,QAAgB,EAChB,QAAQ,GACT,EAAE,uBAAuB,GAAG,KAAK,CAAC,YAAY,CAgE9C"}
@@ -0,0 +1,37 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import React from 'react';
3
+ export function BoardAssigneeField({ boardSlug, value, disabled = false, onChange, }) {
4
+ return (_jsxs("div", { style: {
5
+ display: 'flex',
6
+ flexDirection: 'column',
7
+ gap: '8px',
8
+ borderTop: '1px solid var(--border)',
9
+ paddingTop: '16px',
10
+ }, "data-testid": "item-editor-assignee-section", children: [_jsxs("div", { style: { display: 'flex', flexDirection: 'column', gap: '4px' }, children: [_jsx("label", { htmlFor: "item-editor-assignee", style: {
11
+ fontFamily: 'var(--font-mono)',
12
+ fontSize: '11px',
13
+ color: 'var(--ink-muted)',
14
+ textTransform: 'uppercase',
15
+ letterSpacing: '0.08em',
16
+ }, children: "Board assignee" }), _jsxs("span", { style: {
17
+ fontFamily: 'var(--font-mono)',
18
+ fontSize: '11px',
19
+ color: 'var(--ink-muted)',
20
+ }, children: ["Saved to boards.", boardSlug, ".assignee for this board."] })] }), _jsx("input", { id: "item-editor-assignee", type: "text", value: value, onChange: (event) => onChange(event.target.value), placeholder: "Unassigned", disabled: disabled, style: {
21
+ fontFamily: 'var(--font-sans)',
22
+ fontSize: '15px',
23
+ fontWeight: 400,
24
+ color: 'var(--ink)',
25
+ background: 'transparent',
26
+ border: '1px solid var(--border)',
27
+ borderRadius: 0,
28
+ padding: '10px 12px',
29
+ width: '100%',
30
+ outline: 'none',
31
+ }, onFocus: (event) => {
32
+ event.currentTarget.style.borderColor = 'var(--accent)';
33
+ }, onBlur: (event) => {
34
+ event.currentTarget.style.borderColor = 'var(--border)';
35
+ }, "data-testid": "item-editor-assignee" })] }));
36
+ }
37
+ //# sourceMappingURL=BoardAssigneeField.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BoardAssigneeField.js","sourceRoot":"","sources":["../../src/components/BoardAssigneeField.tsx"],"names":[],"mappings":";AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAS1B,MAAM,UAAU,kBAAkB,CAAC,EACjC,SAAS,EACT,KAAK,EACL,QAAQ,GAAG,KAAK,EAChB,QAAQ,GACgB;IACxB,OAAO,CACL,eACE,KAAK,EAAE;YACL,OAAO,EAAE,MAAM;YACf,aAAa,EAAE,QAAQ;YACvB,GAAG,EAAE,KAAK;YACV,SAAS,EAAE,yBAAyB;YACpC,UAAU,EAAE,MAAM;SACnB,iBACW,8BAA8B,aAE1C,eAAK,KAAK,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,QAAQ,EAAE,GAAG,EAAE,KAAK,EAAE,aAClE,gBACE,OAAO,EAAC,sBAAsB,EAC9B,KAAK,EAAE;4BACL,UAAU,EAAE,kBAAkB;4BAC9B,QAAQ,EAAE,MAAM;4BAChB,KAAK,EAAE,kBAAkB;4BACzB,aAAa,EAAE,WAAW;4BAC1B,aAAa,EAAE,QAAQ;yBACxB,+BAGK,EACR,gBACE,KAAK,EAAE;4BACL,UAAU,EAAE,kBAAkB;4BAC9B,QAAQ,EAAE,MAAM;4BAChB,KAAK,EAAE,kBAAkB;yBAC1B,iCAEgB,SAAS,iCACrB,IACH,EACN,gBACE,EAAE,EAAC,sBAAsB,EACzB,IAAI,EAAC,MAAM,EACX,KAAK,EAAE,KAAK,EACZ,QAAQ,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,EACjD,WAAW,EAAC,YAAY,EACxB,QAAQ,EAAE,QAAQ,EAClB,KAAK,EAAE;oBACL,UAAU,EAAE,kBAAkB;oBAC9B,QAAQ,EAAE,MAAM;oBAChB,UAAU,EAAE,GAAG;oBACf,KAAK,EAAE,YAAY;oBACnB,UAAU,EAAE,aAAa;oBACzB,MAAM,EAAE,yBAAyB;oBACjC,YAAY,EAAE,CAAC;oBACf,OAAO,EAAE,WAAW;oBACpB,KAAK,EAAE,MAAM;oBACb,OAAO,EAAE,MAAM;iBAChB,EACD,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE;oBACjB,KAAK,CAAC,aAAa,CAAC,KAAK,CAAC,WAAW,GAAG,eAAe,CAAC;gBAC1D,CAAC,EACD,MAAM,EAAE,CAAC,KAAK,EAAE,EAAE;oBAChB,KAAK,CAAC,aAAa,CAAC,KAAK,CAAC,WAAW,GAAG,eAAe,CAAC;gBAC1D,CAAC,iBACW,sBAAsB,GAClC,IACE,CACP,CAAC;AACJ,CAAC"}
@@ -0,0 +1,12 @@
1
+ import React from 'react';
2
+ /**
3
+ * Persistent banner shown when an active merge conflict exists.
4
+ *
5
+ * - Displays the number of affected paths.
6
+ * - Shows a "Resolve" button that opens the ConflictPanel.
7
+ * - Persists until the conflict is cleared via a `synced` SSE event.
8
+ *
9
+ * The banner renders nothing when there is no active conflict.
10
+ */
11
+ export declare function ConflictBanner(): React.ReactElement | null;
12
+ //# sourceMappingURL=ConflictBanner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ConflictBanner.d.ts","sourceRoot":"","sources":["../../src/components/ConflictBanner.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAgC,MAAM,OAAO,CAAC;AAKrD;;;;;;;;GAQG;AACH,wBAAgB,cAAc,IAAI,KAAK,CAAC,YAAY,GAAG,IAAI,CAsF1D"}
@@ -0,0 +1,47 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import React, { useState, useCallback } from 'react';
3
+ import { useConflict } from '../sync/conflict-store.js';
4
+ import { ConflictPanel } from './ConflictPanel.js';
5
+ /**
6
+ * Persistent banner shown when an active merge conflict exists.
7
+ *
8
+ * - Displays the number of affected paths.
9
+ * - Shows a "Resolve" button that opens the ConflictPanel.
10
+ * - Persists until the conflict is cleared via a `synced` SSE event.
11
+ *
12
+ * The banner renders nothing when there is no active conflict.
13
+ */
14
+ export function ConflictBanner() {
15
+ const { activeConflict, error, dismissError } = useConflict();
16
+ const [panelOpen, setPanelOpen] = useState(false);
17
+ if (!activeConflict && !error)
18
+ return null;
19
+ return (_jsxs(_Fragment, { children: [activeConflict && (_jsxs("div", { className: "flex items-center justify-between gap-3 px-4 py-2 flex-shrink-0", style: {
20
+ borderBottom: '1px solid var(--border)',
21
+ background: 'var(--bg)',
22
+ fontFamily: 'var(--font-mono)',
23
+ fontSize: '12px',
24
+ }, role: "alert", "aria-live": "polite", "data-testid": "conflict-banner", "data-conflict-merge-id": activeConflict.mergeId, children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("span", { style: { color: 'var(--ink-muted)' }, "aria-hidden": "true", children: "\u26A0" }), _jsxs("span", { style: { color: 'var(--ink)' }, children: ["Merge conflict:", ' ', _jsx("strong", { children: activeConflict.pendingPaths.length }), ' ', "unresolved path", activeConflict.pendingPaths.length !== 1 ? 's' : ''] })] }), _jsx("button", { type: "button", onClick: () => setPanelOpen(true), style: {
25
+ fontFamily: 'var(--font-mono)',
26
+ fontSize: '11px',
27
+ padding: '2px 8px',
28
+ border: '1px solid var(--border)',
29
+ background: 'var(--bg)',
30
+ color: 'var(--ink)',
31
+ cursor: 'pointer',
32
+ }, "data-testid": "conflict-resolve-btn", children: "Resolve" })] })), error && (_jsxs("div", { className: "flex items-center justify-between gap-3 px-4 py-2 flex-shrink-0", style: {
33
+ borderBottom: '1px solid var(--border)',
34
+ background: 'var(--bg)',
35
+ fontFamily: 'var(--font-mono)',
36
+ fontSize: '12px',
37
+ }, role: "alert", "data-testid": "conflict-error-banner", children: [_jsx("span", { style: { color: 'var(--ink)' }, children: error }), _jsx("button", { type: "button", onClick: dismissError, style: {
38
+ fontFamily: 'var(--font-mono)',
39
+ fontSize: '11px',
40
+ padding: '2px 6px',
41
+ border: '1px solid var(--border)',
42
+ background: 'var(--bg)',
43
+ color: 'var(--ink-muted)',
44
+ cursor: 'pointer',
45
+ }, "data-testid": "conflict-error-dismiss", children: "Dismiss" })] })), panelOpen && (_jsx(ConflictPanel, { onClose: () => setPanelOpen(false) }))] }));
46
+ }
47
+ //# sourceMappingURL=ConflictBanner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ConflictBanner.js","sourceRoot":"","sources":["../../src/components/ConflictBanner.tsx"],"names":[],"mappings":";AAAA,OAAO,KAAK,EAAE,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,OAAO,CAAC;AAErD,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AACxD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAEnD;;;;;;;;GAQG;AACH,MAAM,UAAU,cAAc;IAC5B,MAAM,EAAE,cAAc,EAAE,KAAK,EAAE,YAAY,EAAE,GAAG,WAAW,EAAE,CAAC;IAC9D,MAAM,CAAC,SAAS,EAAE,YAAY,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAElD,IAAI,CAAC,cAAc,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IAE3C,OAAO,CACL,8BACG,cAAc,IAAI,CACjB,eACE,SAAS,EAAC,iEAAiE,EAC3E,KAAK,EAAE;oBACL,YAAY,EAAE,yBAAyB;oBACvC,UAAU,EAAE,WAAW;oBACvB,UAAU,EAAE,kBAAkB;oBAC9B,QAAQ,EAAE,MAAM;iBACjB,EACD,IAAI,EAAC,OAAO,eACF,QAAQ,iBACN,iBAAiB,4BACL,cAAc,CAAC,OAAO,aAE9C,eAAK,SAAS,EAAC,yBAAyB,aACtC,eAAM,KAAK,EAAE,EAAE,KAAK,EAAE,kBAAkB,EAAE,iBAAc,MAAM,uBAAS,EACvE,gBAAM,KAAK,EAAE,EAAE,KAAK,EAAE,YAAY,EAAE,gCAClB,GAAG,EACnB,2BAAS,cAAc,CAAC,YAAY,CAAC,MAAM,GAAU,EAAC,GAAG,qBACzC,cAAc,CAAC,YAAY,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,IAC9D,IACH,EACN,iBACE,IAAI,EAAC,QAAQ,EACb,OAAO,EAAE,GAAG,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,EACjC,KAAK,EAAE;4BACL,UAAU,EAAE,kBAAkB;4BAC9B,QAAQ,EAAE,MAAM;4BAChB,OAAO,EAAE,SAAS;4BAClB,MAAM,EAAE,yBAAyB;4BACjC,UAAU,EAAE,WAAW;4BACvB,KAAK,EAAE,YAAY;4BACnB,MAAM,EAAE,SAAS;yBAClB,iBACW,sBAAsB,wBAG3B,IACL,CACP,EAEA,KAAK,IAAI,CACR,eACE,SAAS,EAAC,iEAAiE,EAC3E,KAAK,EAAE;oBACL,YAAY,EAAE,yBAAyB;oBACvC,UAAU,EAAE,WAAW;oBACvB,UAAU,EAAE,kBAAkB;oBAC9B,QAAQ,EAAE,MAAM;iBACjB,EACD,IAAI,EAAC,OAAO,iBACA,uBAAuB,aAEnC,eAAM,KAAK,EAAE,EAAE,KAAK,EAAE,YAAY,EAAE,YAAG,KAAK,GAAQ,EACpD,iBACE,IAAI,EAAC,QAAQ,EACb,OAAO,EAAE,YAAY,EACrB,KAAK,EAAE;4BACL,UAAU,EAAE,kBAAkB;4BAC9B,QAAQ,EAAE,MAAM;4BAChB,OAAO,EAAE,SAAS;4BAClB,MAAM,EAAE,yBAAyB;4BACjC,UAAU,EAAE,WAAW;4BACvB,KAAK,EAAE,kBAAkB;4BACzB,MAAM,EAAE,SAAS;yBAClB,iBACW,wBAAwB,wBAG7B,IACL,CACP,EAEA,SAAS,IAAI,CACZ,KAAC,aAAa,IAAC,OAAO,EAAE,GAAG,EAAE,CAAC,YAAY,CAAC,KAAK,CAAC,GAAI,CACtD,IACA,CACJ,CAAC;AACJ,CAAC"}
@@ -0,0 +1,13 @@
1
+ import React from 'react';
2
+ export interface ConflictDiffProps {
3
+ /** Repo-relative file path — used to derive the root data-testid. */
4
+ path: string;
5
+ oursLabel: string;
6
+ theirsLabel: string;
7
+ oursContent: string;
8
+ theirsContent: string;
9
+ oursTruncated: boolean;
10
+ theirsTruncated: boolean;
11
+ }
12
+ export declare function ConflictDiff({ path, oursLabel, theirsLabel, oursContent, theirsContent, oursTruncated, theirsTruncated, }: ConflictDiffProps): React.ReactElement;
13
+ //# sourceMappingURL=ConflictDiff.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ConflictDiff.d.ts","sourceRoot":"","sources":["../../src/components/ConflictDiff.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAkB,MAAM,OAAO,CAAC;AAQvC,MAAM,WAAW,iBAAiB;IAChC,qEAAqE;IACrE,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,OAAO,CAAC;IACvB,eAAe,EAAE,OAAO,CAAC;CAC1B;AAiID,wBAAgB,YAAY,CAAC,EAC3B,IAAI,EACJ,SAAS,EACT,WAAW,EACX,WAAW,EACX,aAAa,EACb,aAAa,EACb,eAAe,GAChB,EAAE,iBAAiB,GAAG,KAAK,CAAC,YAAY,CA2DxC"}
@@ -0,0 +1,97 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import React, { useMemo } from 'react';
3
+ import { diffLines } from 'diff';
4
+ // ---------------------------------------------------------------------------
5
+ // Row-building helpers
6
+ // ---------------------------------------------------------------------------
7
+ function splitLines(text) {
8
+ const lines = text.split('\n');
9
+ // drop trailing empty string caused by a terminal newline
10
+ if (lines.length > 0 && lines[lines.length - 1] === '')
11
+ lines.pop();
12
+ return lines;
13
+ }
14
+ function buildRows(oursContent, theirsContent) {
15
+ const changes = diffLines(oursContent, theirsContent);
16
+ const raw = [];
17
+ let i = 0;
18
+ while (i < changes.length) {
19
+ const chunk = changes[i];
20
+ if (!chunk.added && !chunk.removed) {
21
+ // Equal chunk — both sides advance
22
+ for (const line of splitLines(chunk.value)) {
23
+ raw.push({ oursLine: line, theirsLine: line, kind: 'equal' });
24
+ }
25
+ i++;
26
+ }
27
+ else if (chunk.removed) {
28
+ const next = changes[i + 1];
29
+ const oursLines = splitLines(chunk.value);
30
+ if (next?.added) {
31
+ // Paired remove + add: zip and pad the shorter side
32
+ const theirsLines = splitLines(next.value);
33
+ const maxLen = Math.max(oursLines.length, theirsLines.length);
34
+ for (let j = 0; j < maxLen; j++) {
35
+ const oursLine = j < oursLines.length ? (oursLines[j] ?? null) : null;
36
+ const theirsLine = j < theirsLines.length ? (theirsLines[j] ?? null) : null;
37
+ const kind = oursLine !== null && theirsLine !== null ? 'changed'
38
+ : oursLine !== null ? 'removed'
39
+ : 'added';
40
+ raw.push({ oursLine, theirsLine, kind });
41
+ }
42
+ i += 2;
43
+ }
44
+ else {
45
+ // Unpaired remove — theirs column is empty
46
+ for (const line of oursLines) {
47
+ raw.push({ oursLine: line, theirsLine: null, kind: 'removed' });
48
+ }
49
+ i++;
50
+ }
51
+ }
52
+ else {
53
+ // Unpaired add — ours column is empty
54
+ for (const line of splitLines(chunk.value)) {
55
+ raw.push({ oursLine: null, theirsLine: line, kind: 'added' });
56
+ }
57
+ i++;
58
+ }
59
+ }
60
+ // Annotate with per-side line numbers (increment only on non-null lines)
61
+ let oursNum = 0;
62
+ let theirsNum = 0;
63
+ return raw.map((r) => ({
64
+ ...r,
65
+ oursLineNum: r.oursLine !== null ? ++oursNum : null,
66
+ theirsLineNum: r.theirsLine !== null ? ++theirsNum : null,
67
+ }));
68
+ }
69
+ function DiffCell({ line, lineNum, side, kind }) {
70
+ if (line === null) {
71
+ return (_jsxs("div", { className: "flex min-w-0 bg-gray-50", "aria-hidden": "true", children: [_jsx("span", { className: "w-10 flex-shrink-0 select-none" }), _jsx("span", { className: "flex-1 px-2 whitespace-pre font-mono text-xs" })] }));
72
+ }
73
+ const isModified = kind !== 'equal';
74
+ const cellBg = isModified
75
+ ? side === 'ours' ? 'bg-red-50' : 'bg-green-50'
76
+ : 'bg-white';
77
+ const numColor = isModified
78
+ ? side === 'ours' ? 'text-red-300' : 'text-green-300'
79
+ : 'text-gray-300';
80
+ const textColor = isModified
81
+ ? side === 'ours' ? 'text-red-800' : 'text-green-800'
82
+ : 'text-gray-700';
83
+ return (_jsxs("div", { className: `flex min-w-0 ${cellBg}`, children: [_jsx("span", { className: `w-10 flex-shrink-0 text-right pr-2 select-none text-xs font-mono ${numColor}`, children: lineNum }), _jsx("span", { className: `flex-1 px-2 whitespace-pre font-mono text-xs ${textColor}`, children: line })] }));
84
+ }
85
+ // ---------------------------------------------------------------------------
86
+ // ConflictDiff
87
+ // ---------------------------------------------------------------------------
88
+ export function ConflictDiff({ path, oursLabel, theirsLabel, oursContent, theirsContent, oursTruncated, theirsTruncated, }) {
89
+ const sanitizedPath = path.replace(/\//g, '-');
90
+ const hasTruncation = oursTruncated || theirsTruncated;
91
+ const rows = useMemo(() => buildRows(oursContent, theirsContent), [oursContent, theirsContent]);
92
+ const truncationSides = oursTruncated && theirsTruncated ? 'both sides are'
93
+ : oursTruncated ? '"ours" is'
94
+ : '"theirs" is';
95
+ return (_jsxs("div", { "data-testid": `conflict-diff-${sanitizedPath}`, className: "overflow-x-auto rounded border border-gray-200", children: [hasTruncation && (_jsxs("div", { "data-testid": "conflict-diff-truncated", className: "bg-amber-50 border-b border-amber-200 text-amber-700 px-3 py-1.5 text-xs", children: ["\u26A0 ", truncationSides, " truncated at 16 KB \u2014 diff shows partial content only."] })), _jsxs("div", { className: "grid grid-cols-2 sticky top-0 bg-gray-100 border-b border-gray-200 z-10", children: [_jsx("div", { className: "px-3 py-1.5 text-xs font-semibold text-gray-600 border-r border-gray-200 truncate", children: oursLabel }), _jsx("div", { className: "px-3 py-1.5 text-xs font-semibold text-gray-600 truncate", children: theirsLabel })] }), _jsx("div", { children: rows.map((row, idx) => (_jsxs("div", { className: "grid grid-cols-2 border-b border-gray-100 last:border-b-0", children: [_jsx(DiffCell, { line: row.oursLine, lineNum: row.oursLineNum, side: "ours", kind: row.kind }), _jsx(DiffCell, { line: row.theirsLine, lineNum: row.theirsLineNum, side: "theirs", kind: row.kind })] }, idx))) })] }));
96
+ }
97
+ //# sourceMappingURL=ConflictDiff.js.map