@mieweb/ui 0.10.0-dev.6 → 0.10.0-dev.8

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 (105) hide show
  1. package/agent/mieweb-ui.instructions.md +13 -1
  2. package/dist/brands/index.cjs +13 -13
  3. package/dist/brands/index.js +1 -1
  4. package/dist/chunk-3YBS4WUQ.js +52 -0
  5. package/dist/chunk-3YBS4WUQ.js.map +1 -0
  6. package/dist/chunk-4IS3QCOQ.cjs +453 -0
  7. package/dist/chunk-4IS3QCOQ.cjs.map +1 -0
  8. package/dist/chunk-4NCDU5IG.cjs +56 -0
  9. package/dist/chunk-4NCDU5IG.cjs.map +1 -0
  10. package/dist/chunk-76TBQDED.js +166 -0
  11. package/dist/chunk-76TBQDED.js.map +1 -0
  12. package/dist/{chunk-JI244Y7C.js → chunk-7G3ZIYFY.js} +13 -3
  13. package/dist/chunk-7G3ZIYFY.js.map +1 -0
  14. package/dist/chunk-DZ5HFLRC.js +258 -0
  15. package/dist/chunk-DZ5HFLRC.js.map +1 -0
  16. package/dist/{chunk-U42F3HLE.cjs → chunk-EZSSESEU.cjs} +13 -3
  17. package/dist/chunk-EZSSESEU.cjs.map +1 -0
  18. package/dist/chunk-G4D6CLBT.js +333 -0
  19. package/dist/chunk-G4D6CLBT.js.map +1 -0
  20. package/dist/chunk-IT775BYG.js +179 -0
  21. package/dist/chunk-IT775BYG.js.map +1 -0
  22. package/dist/{chunk-ELPW32ZI.cjs → chunk-KQUI4BGS.cjs} +3 -3
  23. package/dist/{chunk-ELPW32ZI.cjs.map → chunk-KQUI4BGS.cjs.map} +1 -1
  24. package/dist/{chunk-WNM7IZJ7.js → chunk-MNILXWVY.js} +2 -2
  25. package/dist/{chunk-WNM7IZJ7.js.map → chunk-MNILXWVY.js.map} +1 -1
  26. package/dist/chunk-OCSCBB52.cjs +188 -0
  27. package/dist/chunk-OCSCBB52.cjs.map +1 -0
  28. package/dist/{chunk-2YCERQWC.js → chunk-TVTIGV7Q.js} +3 -3
  29. package/dist/{chunk-2YCERQWC.js.map → chunk-TVTIGV7Q.js.map} +1 -1
  30. package/dist/chunk-URAQIF67.cjs +356 -0
  31. package/dist/chunk-URAQIF67.cjs.map +1 -0
  32. package/dist/chunk-VINZZQBD.cjs +323 -0
  33. package/dist/chunk-VINZZQBD.cjs.map +1 -0
  34. package/dist/chunk-XDIMTPZU.cjs +202 -0
  35. package/dist/chunk-XDIMTPZU.cjs.map +1 -0
  36. package/dist/chunk-XVW5DPPP.js +429 -0
  37. package/dist/chunk-XVW5DPPP.js.map +1 -0
  38. package/dist/chunk-XZNN3S3S.cjs +281 -0
  39. package/dist/chunk-XZNN3S3S.cjs.map +1 -0
  40. package/dist/chunk-Y4QNLW7W.js +300 -0
  41. package/dist/chunk-Y4QNLW7W.js.map +1 -0
  42. package/dist/{chunk-2QKBTPUC.cjs → chunk-ZPSJ2UV6.cjs} +2 -2
  43. package/dist/{chunk-2QKBTPUC.cjs.map → chunk-ZPSJ2UV6.cjs.map} +1 -1
  44. package/dist/components/BoardView/index.cjs +24 -0
  45. package/dist/components/BoardView/index.cjs.map +1 -0
  46. package/dist/components/BoardView/index.d.cts +42 -0
  47. package/dist/components/BoardView/index.d.ts +42 -0
  48. package/dist/components/BoardView/index.js +7 -0
  49. package/dist/components/BoardView/index.js.map +1 -0
  50. package/dist/components/CalendarView/index.cjs +22 -0
  51. package/dist/components/CalendarView/index.cjs.map +1 -0
  52. package/dist/components/CalendarView/index.d.cts +40 -0
  53. package/dist/components/CalendarView/index.d.ts +40 -0
  54. package/dist/components/CalendarView/index.js +9 -0
  55. package/dist/components/CalendarView/index.js.map +1 -0
  56. package/dist/components/GanttView/index.cjs +20 -0
  57. package/dist/components/GanttView/index.cjs.map +1 -0
  58. package/dist/components/GanttView/index.d.cts +37 -0
  59. package/dist/components/GanttView/index.d.ts +37 -0
  60. package/dist/components/GanttView/index.js +7 -0
  61. package/dist/components/GanttView/index.js.map +1 -0
  62. package/dist/components/ListView/index.cjs +22 -0
  63. package/dist/components/ListView/index.cjs.map +1 -0
  64. package/dist/components/ListView/index.d.cts +37 -0
  65. package/dist/components/ListView/index.d.ts +37 -0
  66. package/dist/components/ListView/index.js +9 -0
  67. package/dist/components/ListView/index.js.map +1 -0
  68. package/dist/components/Markdown/index.cjs +15 -15
  69. package/dist/components/Markdown/index.js +3 -3
  70. package/dist/components/QuickAction/index.d.cts +1 -1
  71. package/dist/components/QuickAction/index.d.ts +1 -1
  72. package/dist/components/SuperChat/index.cjs +185 -159
  73. package/dist/components/SuperChat/index.cjs.map +1 -1
  74. package/dist/components/SuperChat/index.js +185 -159
  75. package/dist/components/SuperChat/index.js.map +1 -1
  76. package/dist/components/ViewSet/index.cjs +23 -0
  77. package/dist/components/ViewSet/index.cjs.map +1 -0
  78. package/dist/components/ViewSet/index.d.cts +89 -0
  79. package/dist/components/ViewSet/index.d.ts +89 -0
  80. package/dist/components/ViewSet/index.js +14 -0
  81. package/dist/components/ViewSet/index.js.map +1 -0
  82. package/dist/components/ViewSwitcher/index.cjs +20 -0
  83. package/dist/components/ViewSwitcher/index.cjs.map +1 -0
  84. package/dist/components/ViewSwitcher/index.d.cts +40 -0
  85. package/dist/components/ViewSwitcher/index.d.ts +40 -0
  86. package/dist/components/ViewSwitcher/index.js +7 -0
  87. package/dist/components/ViewSwitcher/index.js.map +1 -0
  88. package/dist/esheet.cjs +5 -5
  89. package/dist/esheet.js +2 -2
  90. package/dist/hooks/index.cjs +5 -5
  91. package/dist/hooks/index.js +1 -1
  92. package/dist/index.cjs +439 -372
  93. package/dist/index.cjs.map +1 -1
  94. package/dist/index.d.cts +8 -0
  95. package/dist/index.d.ts +8 -0
  96. package/dist/index.js +57 -50
  97. package/dist/index.js.map +1 -1
  98. package/dist/styles.css +1 -1
  99. package/dist/tailwind-preset.cjs +4 -4
  100. package/dist/tailwind-preset.js +1 -1
  101. package/dist/types-CbWXIKbe.d.cts +119 -0
  102. package/dist/types-CbWXIKbe.d.ts +119 -0
  103. package/package.json +1 -1
  104. package/dist/chunk-JI244Y7C.js.map +0 -1
  105. package/dist/chunk-U42F3HLE.cjs.map +0 -1
@@ -168,7 +168,19 @@ Tailwind: on Tailwind 4, add an `@source` for `@mieweb/ui` so library classes ar
168
168
 
169
169
  If JSDoc, the console, or the docs mark something deprecated (`AGGrid` today), do not use it in new code and do not suppress the warning. Use the documented replacement.
170
170
 
171
- ## Rule 14: When existing components do not meet the need
171
+ ## Rule 14: A component that renders a collection takes it through props
172
+
173
+ Anything that displays a list, board, calendar, timeline or inbox of records the caller owns is a **headless module**. It receives `items` / `loading` / `error` as props, hands changes back through `on*` callbacks typed `void | Promise<void>`, and navigates through `onOpen(id)` / `getHref(id)`.
174
+
175
+ Never fetch, subscribe, read a store, or import a router or app framework inside such a component — `meteor/*`, `next/*`, `react-router*`, `@tanstack/react-query` and `@fortawesome/*` are blocked by ESLint. Make it generic over the item type with accessor props (`getId`, `getStatus`, `getStart`, …), put domain rendering in `render*` slots, return a token _name_ for colour (never a class string), and make every user-facing string overridable through `labels`.
176
+
177
+ Declare it with `parameters.catalog.collection: true`; `pnpm catalog:check` then requires an **Empty**, **Loading** and **Error** story. Full contract:
178
+ [component-policy → Tier 2.5](https://github.com/mieweb/ui/blob/main/lessons/component-policy.md#tier-25-headless-modules).
179
+
180
+ Wiring one to an app's data layer — accessors, awaited mutations, `onOpen` plus `getHref`, where filter state lives:
181
+ [wiring-headless-modules.md](https://github.com/mieweb/ui/blob/main/lessons/wiring-headless-modules.md).
182
+
183
+ ## Rule 15: When existing components do not meet the need
172
184
 
173
185
  Before creating or materially extending a reusable component, read the
174
186
  [upstream contribution guide](https://github.com/mieweb/ui/blob/main/CONTRIBUTING.md)
@@ -6,10 +6,10 @@ var chunkNM7O7RY5_cjs = require('../chunk-NM7O7RY5.cjs');
6
6
  var chunkLCQGAOAZ_cjs = require('../chunk-LCQGAOAZ.cjs');
7
7
  var chunkZ5J4NTPL_cjs = require('../chunk-Z5J4NTPL.cjs');
8
8
  var chunkU7VQUOLS_cjs = require('../chunk-U7VQUOLS.cjs');
9
- var chunkNGQRS7AW_cjs = require('../chunk-NGQRS7AW.cjs');
10
9
  var chunkWNJRS7Y7_cjs = require('../chunk-WNJRS7Y7.cjs');
11
10
  var chunkUCGUA3QV_cjs = require('../chunk-UCGUA3QV.cjs');
12
11
  var chunkRR2MJBGV_cjs = require('../chunk-RR2MJBGV.cjs');
12
+ var chunkNGQRS7AW_cjs = require('../chunk-NGQRS7AW.cjs');
13
13
  require('../chunk-EUAMEVVI.cjs');
14
14
 
15
15
 
@@ -38,18 +38,6 @@ Object.defineProperty(exports, "webchartBrand", {
38
38
  enumerable: true,
39
39
  get: function () { return chunkU7VQUOLS_cjs.webchartBrand; }
40
40
  });
41
- Object.defineProperty(exports, "createBrandPreset", {
42
- enumerable: true,
43
- get: function () { return chunkNGQRS7AW_cjs.createBrandPreset; }
44
- });
45
- Object.defineProperty(exports, "generateBrandCSS", {
46
- enumerable: true,
47
- get: function () { return chunkNGQRS7AW_cjs.generateBrandCSS; }
48
- });
49
- Object.defineProperty(exports, "generateTailwindTheme", {
50
- enumerable: true,
51
- get: function () { return chunkNGQRS7AW_cjs.generateTailwindTheme; }
52
- });
53
41
  Object.defineProperty(exports, "bluehiveBrand", {
54
42
  enumerable: true,
55
43
  get: function () { return chunkWNJRS7Y7_cjs.bluehiveBrand; }
@@ -62,5 +50,17 @@ Object.defineProperty(exports, "ozwellBrand", {
62
50
  enumerable: true,
63
51
  get: function () { return chunkRR2MJBGV_cjs.ozwellBrand; }
64
52
  });
53
+ Object.defineProperty(exports, "createBrandPreset", {
54
+ enumerable: true,
55
+ get: function () { return chunkNGQRS7AW_cjs.createBrandPreset; }
56
+ });
57
+ Object.defineProperty(exports, "generateBrandCSS", {
58
+ enumerable: true,
59
+ get: function () { return chunkNGQRS7AW_cjs.generateBrandCSS; }
60
+ });
61
+ Object.defineProperty(exports, "generateTailwindTheme", {
62
+ enumerable: true,
63
+ get: function () { return chunkNGQRS7AW_cjs.generateTailwindTheme; }
64
+ });
65
65
  //# sourceMappingURL=index.cjs.map
66
66
  //# sourceMappingURL=index.cjs.map
@@ -4,10 +4,10 @@ export { enterpriseHealthBrand } from '../chunk-Q77TE5DZ.js';
4
4
  export { miewebBrand } from '../chunk-NERS5ZT6.js';
5
5
  export { wagglelineBrand } from '../chunk-2NTYAALC.js';
6
6
  export { webchartBrand } from '../chunk-CW66SO5O.js';
7
- export { createBrandPreset, generateBrandCSS, generateTailwindTheme } from '../chunk-5GOWFNQ6.js';
8
7
  export { bluehiveBrand } from '../chunk-3T7QGLNB.js';
9
8
  export { ccmeBrand } from '../chunk-SCQRJPSV.js';
10
9
  export { ozwellBrand } from '../chunk-5YUBQIC7.js';
10
+ export { createBrandPreset, generateBrandCSS, generateTailwindTheme } from '../chunk-5GOWFNQ6.js';
11
11
  import '../chunk-PX6F3LHL.js';
12
12
  //# sourceMappingURL=index.js.map
13
13
  //# sourceMappingURL=index.js.map
@@ -0,0 +1,52 @@
1
+ import { DateTime } from 'luxon';
2
+
3
+ // src/views/types.ts
4
+ var defaultViewLabels = {
5
+ viewSwitcher: "View",
6
+ loading: "Loading",
7
+ empty: "Nothing to show",
8
+ error: "Could not load this view",
9
+ retry: "Try again",
10
+ ungrouped: "Ungrouped"
11
+ };
12
+ function toDateTime(value, zone) {
13
+ if (value == null) return null;
14
+ const dt = value instanceof Date ? DateTime.fromJSDate(value, { zone }) : DateTime.fromISO(value, { zone });
15
+ return dt.isValid ? dt : null;
16
+ }
17
+ var accentClasses = {
18
+ primary: {
19
+ tint: "bg-primary-500/10",
20
+ border: "border-primary-500/40",
21
+ marker: "bg-primary-500"
22
+ },
23
+ success: {
24
+ tint: "bg-success/10",
25
+ border: "border-success/40",
26
+ marker: "bg-success"
27
+ },
28
+ warning: {
29
+ tint: "bg-warning/10",
30
+ border: "border-warning/40",
31
+ marker: "bg-warning"
32
+ },
33
+ destructive: {
34
+ tint: "bg-destructive/10",
35
+ border: "border-destructive/40",
36
+ marker: "bg-destructive"
37
+ },
38
+ info: {
39
+ tint: "bg-info/10",
40
+ border: "border-info/40",
41
+ marker: "bg-info"
42
+ },
43
+ neutral: {
44
+ tint: "bg-muted",
45
+ border: "border-border",
46
+ marker: "bg-muted-foreground"
47
+ }
48
+ };
49
+
50
+ export { accentClasses, defaultViewLabels, toDateTime };
51
+ //# sourceMappingURL=chunk-3YBS4WUQ.js.map
52
+ //# sourceMappingURL=chunk-3YBS4WUQ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/views/types.ts"],"names":[],"mappings":";;;AAmFO,IAAM,iBAAA,GAAgC;AAAA,EAC3C,YAAA,EAAc,MAAA;AAAA,EACd,OAAA,EAAS,SAAA;AAAA,EACT,KAAA,EAAO,iBAAA;AAAA,EACP,KAAA,EAAO,0BAAA;AAAA,EACP,KAAA,EAAO,WAAA;AAAA,EACP,SAAA,EAAW;AACb;AAoCO,SAAS,UAAA,CACd,OACA,IAAA,EACiB;AACjB,EAAA,IAAI,KAAA,IAAS,MAAM,OAAO,IAAA;AAC1B,EAAA,MAAM,EAAA,GACJ,KAAA,YAAiB,IAAA,GACb,QAAA,CAAS,WAAW,KAAA,EAAO,EAAE,IAAA,EAAM,IACnC,QAAA,CAAS,OAAA,CAAQ,KAAA,EAAO,EAAE,MAAM,CAAA;AACtC,EAAA,OAAO,EAAA,CAAG,UAAU,EAAA,GAAK,IAAA;AAC3B;AAWO,IAAM,aAAA,GAGT;AAAA,EACF,OAAA,EAAS;AAAA,IACP,IAAA,EAAM,mBAAA;AAAA,IACN,MAAA,EAAQ,uBAAA;AAAA,IACR,MAAA,EAAQ;AAAA,GACV;AAAA,EACA,OAAA,EAAS;AAAA,IACP,IAAA,EAAM,eAAA;AAAA,IACN,MAAA,EAAQ,mBAAA;AAAA,IACR,MAAA,EAAQ;AAAA,GACV;AAAA,EACA,OAAA,EAAS;AAAA,IACP,IAAA,EAAM,eAAA;AAAA,IACN,MAAA,EAAQ,mBAAA;AAAA,IACR,MAAA,EAAQ;AAAA,GACV;AAAA,EACA,WAAA,EAAa;AAAA,IACX,IAAA,EAAM,mBAAA;AAAA,IACN,MAAA,EAAQ,uBAAA;AAAA,IACR,MAAA,EAAQ;AAAA,GACV;AAAA,EACA,IAAA,EAAM;AAAA,IACJ,IAAA,EAAM,YAAA;AAAA,IACN,MAAA,EAAQ,gBAAA;AAAA,IACR,MAAA,EAAQ;AAAA,GACV;AAAA,EACA,OAAA,EAAS;AAAA,IACP,IAAA,EAAM,UAAA;AAAA,IACN,MAAA,EAAQ,eAAA;AAAA,IACR,MAAA,EAAQ;AAAA;AAEZ","file":"chunk-3YBS4WUQ.js","sourcesContent":["/**\n * The contract every component in the `Modules/Views` family reads through.\n *\n * A page describes its collection once — which field is the id, the title, the\n * status, the start date — and every view understands it. That is the whole\n * reason the family exists: without it each view needs its own adapter and you\n * end up re-implementing the same board per entity.\n *\n * Views are headless. Nothing here fetches, subscribes, or navigates.\n * See CONTRIBUTING → \"Modules: headless data components\".\n */\nimport type * as React from 'react';\nimport { DateTime } from 'luxon';\n\n/**\n * Which layout is on screen. `overview` and `table` are rendered by the host\n * through `ViewSet` slots rather than by a component in this family — a tabular\n * collection is `DataVisNitroGrid`, and an overview is domain content.\n */\nexport type ViewId =\n | 'overview'\n | 'list'\n | 'board'\n | 'calendar'\n | 'gantt'\n | 'roadmap'\n | 'table';\n\n/**\n * A semantic colour name, resolved to `--mieweb-*` tokens by each view.\n *\n * Accessors return one of these rather than a class string so a caller cannot\n * hardcode a palette that breaks under another brand or in dark mode.\n */\nexport type Accent =\n | 'primary'\n | 'success'\n | 'warning'\n | 'destructive'\n | 'info'\n | 'neutral';\n\n/** A named stage: a board column, and the segments of a stage bar. */\nexport interface Stage {\n id: string;\n label: string;\n accent?: Accent;\n}\n\n/**\n * How a view reads one item. Only `getId` and `getTitle` are always required;\n * each view documents which of the rest it needs (a board needs `getStatus`, a\n * Gantt needs `getStart`) and renders an explanatory empty state without them.\n */\nexport interface ViewAccessors<T> {\n getId: (item: T) => string;\n getTitle: (item: T) => string;\n /** Secondary line under the title. */\n getSubtitle?: (item: T) => string | undefined;\n /** Board column and list group; matched against `Stage['id']`. */\n getStatus?: (item: T) => string;\n /** Gantt bar start, calendar placement. */\n getStart?: (item: T) => Date | string | null | undefined;\n /** Gantt bar end, calendar span. Falls back to the start when absent. */\n getEnd?: (item: T) => Date | string | null | undefined;\n /** Swimlane in a roadmap, row group in a Gantt. */\n getGroup?: (item: T) => string | undefined;\n getAccent?: (item: T) => Accent;\n}\n\n/** Strings a view renders. Every one is overridable; the defaults are English. */\nexport interface ViewLabels {\n /** Accessible name of the view switcher group. */\n viewSwitcher: string;\n loading: string;\n empty: string;\n error: string;\n /** Action on the error state. */\n retry: string;\n /** Heading for the group a record with no status or group falls into. */\n ungrouped: string;\n}\n\nexport const defaultViewLabels: ViewLabels = {\n viewSwitcher: 'View',\n loading: 'Loading',\n empty: 'Nothing to show',\n error: 'Could not load this view',\n retry: 'Try again',\n ungrouped: 'Ungrouped',\n};\n\n/**\n * Props every view accepts. Views are controlled: selection, the active view and\n * filter state live in the page, and every change is handed back.\n */\nexport interface ViewBaseProps<T> {\n items: T[];\n accessors: ViewAccessors<T>;\n loading?: boolean;\n error?: Error | null;\n selectedId?: string | null;\n /** Called when the user activates an item. */\n onOpen?: (id: string, item: T) => void;\n /** Return a URL to render each item as a real anchor — middle-clickable and crawlable. */\n getHref?: (id: string, item: T) => string;\n /** Render one item. Receives the active view so one function can serve several. */\n renderItem?: (item: T, context: { view: ViewId }) => React.ReactNode;\n /** Replaces the built-in empty state. */\n emptyState?: React.ReactNode;\n labels?: Partial<ViewLabels>;\n /** Pins \"today\" so stories, tests and visual snapshots stay deterministic. */\n now?: Date;\n className?: string;\n}\n\n/**\n * Reads an accessor's date in the view's zone.\n *\n * `DateTime.fromISO` is what makes this correct for both shapes an accessor may\n * return. A date-only string is a wall date — `2026-03-10` means that calendar\n * day where the collection lives, not UTC midnight, which is the 9th in the\n * Americas — while a full timestamp is an instant and gets converted. Going via\n * `new Date()` would collapse the first case into the second and shift the item\n * onto the previous day in every zone behind UTC.\n */\nexport function toDateTime(\n value: Date | string | null | undefined,\n zone: string\n): DateTime | null {\n if (value == null) return null;\n const dt =\n value instanceof Date\n ? DateTime.fromJSDate(value, { zone })\n : DateTime.fromISO(value, { zone });\n return dt.isValid ? dt : null;\n}\n\n/**\n * Tailwind classes per accent, so every view tints the same way.\n *\n * There is deliberately no text colour here. `--mieweb-success` and friends are\n * fill tokens: as ink on a surface — even their own 10% wash — they fail WCAG AA\n * contrast, which axe catches as a serious violation. So an accent is carried by\n * a wash, a border and a solid marker, and label text always uses a foreground\n * token. That also means colour is never the only signal.\n */\nexport const accentClasses: Record<\n Accent,\n { tint: string; border: string; marker: string }\n> = {\n primary: {\n tint: 'bg-primary-500/10',\n border: 'border-primary-500/40',\n marker: 'bg-primary-500',\n },\n success: {\n tint: 'bg-success/10',\n border: 'border-success/40',\n marker: 'bg-success',\n },\n warning: {\n tint: 'bg-warning/10',\n border: 'border-warning/40',\n marker: 'bg-warning',\n },\n destructive: {\n tint: 'bg-destructive/10',\n border: 'border-destructive/40',\n marker: 'bg-destructive',\n },\n info: {\n tint: 'bg-info/10',\n border: 'border-info/40',\n marker: 'bg-info',\n },\n neutral: {\n tint: 'bg-muted',\n border: 'border-border',\n marker: 'bg-muted-foreground',\n },\n};\n"]}
@@ -0,0 +1,453 @@
1
+ 'use strict';
2
+
3
+ var chunk4NCDU5IG_cjs = require('./chunk-4NCDU5IG.cjs');
4
+ var chunkXXVUHLQN_cjs = require('./chunk-XXVUHLQN.cjs');
5
+ var chunkS5RVSXDV_cjs = require('./chunk-S5RVSXDV.cjs');
6
+ var React = require('react');
7
+ var core = require('@dnd-kit/core');
8
+ var classVarianceAuthority = require('class-variance-authority');
9
+ var jsxRuntime = require('react/jsx-runtime');
10
+
11
+ function _interopNamespace(e) {
12
+ if (e && e.__esModule) return e;
13
+ var n = Object.create(null);
14
+ if (e) {
15
+ Object.keys(e).forEach(function (k) {
16
+ if (k !== 'default') {
17
+ var d = Object.getOwnPropertyDescriptor(e, k);
18
+ Object.defineProperty(n, k, d.get ? d : {
19
+ enumerable: true,
20
+ get: function () { return e[k]; }
21
+ });
22
+ }
23
+ });
24
+ }
25
+ n.default = e;
26
+ return Object.freeze(n);
27
+ }
28
+
29
+ var React__namespace = /*#__PURE__*/_interopNamespace(React);
30
+
31
+ var defaultBoardLabels = {
32
+ ...chunk4NCDU5IG_cjs.defaultViewLabels,
33
+ empty: "Nothing in this stage",
34
+ board: "Board",
35
+ moved: "{item} moved to {stage}",
36
+ moveFailed: "Could not move {item}",
37
+ moveHint: "Press Control with the arrow keys to move between stages"
38
+ };
39
+ var cardVariants = classVarianceAuthority.cva(
40
+ [
41
+ "w-full rounded-md border border-border bg-card p-2 text-start",
42
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
43
+ ],
44
+ {
45
+ variants: {
46
+ density: {
47
+ comfortable: "p-3",
48
+ compact: "p-2"
49
+ },
50
+ interactive: { true: "hover:border-primary-500/40", false: "" },
51
+ selected: { true: "ring-2 ring-primary-500/50", false: "" },
52
+ pending: { true: "opacity-60", false: "" }
53
+ },
54
+ defaultVariants: {
55
+ density: "comfortable",
56
+ interactive: false,
57
+ selected: false,
58
+ pending: false
59
+ }
60
+ }
61
+ );
62
+ var fill = (template, values) => template.replace(/\{(\w+)\}/g, (_, key) => values[key] ?? "");
63
+ function BoardCard({
64
+ id,
65
+ title,
66
+ subtitle,
67
+ accent,
68
+ selected,
69
+ pending,
70
+ draggable,
71
+ hint,
72
+ href,
73
+ className,
74
+ children,
75
+ onOpen,
76
+ onKeyDown
77
+ }) {
78
+ const { attributes, listeners, setNodeRef, isDragging } = core.useDraggable({
79
+ id,
80
+ disabled: !draggable
81
+ });
82
+ const body = children ?? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex items-start gap-2", children: [
83
+ accent && /* @__PURE__ */ jsxRuntime.jsx(
84
+ "span",
85
+ {
86
+ "aria-hidden": true,
87
+ className: chunkS5RVSXDV_cjs.cn(
88
+ "mt-1.5 size-2 shrink-0 rounded-full",
89
+ chunk4NCDU5IG_cjs.accentClasses[accent].marker
90
+ )
91
+ }
92
+ ),
93
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "min-w-0 flex-1", children: [
94
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-foreground block text-sm font-medium", children: title }),
95
+ subtitle && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground block truncate text-xs", children: subtitle })
96
+ ] })
97
+ ] });
98
+ const onCardKeyDown = (event) => {
99
+ if (onOpen && !href && (event.key === "Enter" || event.key === " ")) {
100
+ if (!event.ctrlKey && !event.metaKey) {
101
+ event.preventDefault();
102
+ onOpen();
103
+ return;
104
+ }
105
+ }
106
+ onKeyDown?.(event);
107
+ };
108
+ const shared = {
109
+ ref: setNodeRef,
110
+ // Only the pointer listeners are shared. dnd-kit's `attributes` carry
111
+ // `role="button"` and a `tabIndex`, which on an `<a href>` would override
112
+ // the native link role — the card would announce as a button, and the
113
+ // middle-click / "copy link" affordance this branch exists to preserve
114
+ // would no longer be what assistive tech describes. The non-link card takes
115
+ // them below, where button semantics are the correct answer.
116
+ ...draggable ? listeners : {},
117
+ "aria-current": selected ? "true" : void 0,
118
+ "aria-describedby": hint,
119
+ "aria-busy": pending || void 0,
120
+ "data-slot": "board-view-card",
121
+ className: chunkS5RVSXDV_cjs.cn(className, isDragging && "opacity-40")
122
+ };
123
+ return /* @__PURE__ */ jsxRuntime.jsx("li", { children: href ? (
124
+ // An anchor, like every other view: the card stays middle-clickable and
125
+ // "copy link" works. dnd-kit's listeners still own the drag.
126
+ /* @__PURE__ */ jsxRuntime.jsx(
127
+ "a",
128
+ {
129
+ ...shared,
130
+ href,
131
+ onKeyDown: onCardKeyDown,
132
+ onClick: (event) => {
133
+ if (!onOpen || event.defaultPrevented || event.metaKey || event.ctrlKey || event.shiftKey || event.button !== 0)
134
+ return;
135
+ event.preventDefault();
136
+ onOpen();
137
+ },
138
+ children: body
139
+ }
140
+ )
141
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
142
+ "div",
143
+ {
144
+ ...shared,
145
+ ...draggable ? attributes : {},
146
+ role: onOpen ? "button" : void 0,
147
+ tabIndex: draggable || onOpen ? 0 : void 0,
148
+ onKeyDown: onCardKeyDown,
149
+ onClick: onOpen,
150
+ children: body
151
+ }
152
+ ) });
153
+ }
154
+ function BoardColumn({
155
+ stage,
156
+ headerId,
157
+ count,
158
+ headingLevel: Heading,
159
+ droppable,
160
+ classNames,
161
+ children
162
+ }) {
163
+ const { setNodeRef, isOver } = core.useDroppable({
164
+ id: stage.id,
165
+ disabled: !droppable
166
+ });
167
+ const accent = stage.accent ?? "neutral";
168
+ return /* @__PURE__ */ jsxRuntime.jsxs(
169
+ "section",
170
+ {
171
+ ref: setNodeRef,
172
+ "data-slot": "board-view-column",
173
+ "data-over": isOver || void 0,
174
+ className: chunkS5RVSXDV_cjs.cn(
175
+ "bg-muted/40 flex min-w-0 flex-col rounded-lg border",
176
+ isOver ? chunk4NCDU5IG_cjs.accentClasses[accent].border : "border-border",
177
+ "sm:w-72 sm:shrink-0",
178
+ classNames?.column
179
+ ),
180
+ children: [
181
+ /* @__PURE__ */ jsxRuntime.jsx(Heading, { children: /* @__PURE__ */ jsxRuntime.jsxs(
182
+ "span",
183
+ {
184
+ id: headerId,
185
+ "data-slot": "board-view-column-header",
186
+ className: chunkS5RVSXDV_cjs.cn(
187
+ "border-border text-muted-foreground flex items-center gap-2 border-b px-3 py-2 text-xs font-semibold tracking-wide uppercase",
188
+ classNames?.columnHeader
189
+ ),
190
+ children: [
191
+ /* @__PURE__ */ jsxRuntime.jsx(
192
+ "span",
193
+ {
194
+ "aria-hidden": true,
195
+ className: chunkS5RVSXDV_cjs.cn(
196
+ "size-2 shrink-0 rounded-full",
197
+ chunk4NCDU5IG_cjs.accentClasses[accent].marker
198
+ )
199
+ }
200
+ ),
201
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: stage.label }),
202
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ms-auto font-normal tabular-nums", children: count })
203
+ ]
204
+ }
205
+ ) }),
206
+ children
207
+ ]
208
+ }
209
+ );
210
+ }
211
+ function BoardView({
212
+ items,
213
+ accessors,
214
+ stages,
215
+ loading = false,
216
+ error = null,
217
+ selectedId = null,
218
+ onOpen,
219
+ getHref,
220
+ onMove,
221
+ renderItem,
222
+ emptyState,
223
+ labels,
224
+ density,
225
+ className,
226
+ classNames,
227
+ headingLevel = "h3"
228
+ }) {
229
+ const text = { ...defaultBoardLabels, ...labels };
230
+ const hintId = React__namespace.useId();
231
+ const baseId = React__namespace.useId();
232
+ const [announcement, setAnnouncement] = React__namespace.useState("");
233
+ const [draggingId, setDraggingId] = React__namespace.useState(null);
234
+ const [pending, setPending] = React__namespace.useState(
235
+ () => /* @__PURE__ */ new Map()
236
+ );
237
+ const byId = React__namespace.useMemo(() => {
238
+ const map = /* @__PURE__ */ new Map();
239
+ for (const item of items) map.set(accessors.getId(item), item);
240
+ return map;
241
+ }, [items, accessors]);
242
+ const stageOf = React__namespace.useCallback(
243
+ (item) => pending.get(accessors.getId(item)) ?? accessors.getStatus?.(item),
244
+ [pending, accessors]
245
+ );
246
+ const columns = React__namespace.useMemo(() => {
247
+ const buckets = new Map(stages.map((s) => [s.id, []]));
248
+ const extra = /* @__PURE__ */ new Map();
249
+ for (const item of items) {
250
+ const key = stageOf(item) ?? "";
251
+ const bucket = buckets.get(key);
252
+ if (bucket) bucket.push(item);
253
+ else {
254
+ const spill = extra.get(key);
255
+ if (spill) spill.push(item);
256
+ else extra.set(key, [item]);
257
+ }
258
+ }
259
+ return [
260
+ ...stages.map((stage) => ({
261
+ stage,
262
+ declared: true,
263
+ items: buckets.get(stage.id) ?? []
264
+ })),
265
+ // Never silently drop a record whose status matches no stage. These are
266
+ // shown so the record stays visible, but they are not drop targets: their
267
+ // ids were never declared, and `onMove` promises a named stage.
268
+ ...[...extra].map(([key, bucket]) => ({
269
+ stage: { id: key, label: key || text.ungrouped },
270
+ declared: false,
271
+ items: bucket
272
+ }))
273
+ ];
274
+ }, [items, stages, stageOf, text.ungrouped]);
275
+ const commit = React__namespace.useCallback(
276
+ async (id, toStage) => {
277
+ const item = byId.get(id);
278
+ if (!item || !onMove) return;
279
+ if (pending.has(id)) return;
280
+ const stage = stages.find((s) => s.id === toStage);
281
+ if (!stage) return;
282
+ const from = accessors.getStatus?.(item);
283
+ if (from === toStage) return;
284
+ const title = accessors.getTitle(item);
285
+ setPending((prev) => new Map(prev).set(id, toStage));
286
+ setAnnouncement(
287
+ fill(text.moved, { item: title, stage: stage.label ?? toStage })
288
+ );
289
+ try {
290
+ await onMove(id, toStage, item);
291
+ } catch {
292
+ setAnnouncement(fill(text.moveFailed, { item: title }));
293
+ } finally {
294
+ setPending((prev) => {
295
+ const next = new Map(prev);
296
+ next.delete(id);
297
+ return next;
298
+ });
299
+ }
300
+ },
301
+ [byId, onMove, pending, accessors, stages, text.moved, text.moveFailed]
302
+ );
303
+ const sensors = core.useSensors(
304
+ core.useSensor(core.PointerSensor, { activationConstraint: { distance: 5 } })
305
+ );
306
+ const onDragStart = (event) => setDraggingId(String(event.active.id));
307
+ const onDragEnd = (event) => {
308
+ setDraggingId(null);
309
+ if (event.over) void commit(String(event.active.id), String(event.over.id));
310
+ };
311
+ const onCardKeyDown = (event, id, columnIndex) => {
312
+ if (!onMove || !(event.ctrlKey || event.metaKey)) return;
313
+ const rtl = getComputedStyle(event.currentTarget).direction === "rtl";
314
+ let delta = 0;
315
+ if (event.key === "ArrowRight") delta = rtl ? -1 : 1;
316
+ else if (event.key === "ArrowLeft") delta = rtl ? 1 : -1;
317
+ else return;
318
+ let target;
319
+ for (let i = columnIndex + delta; i >= 0 && i < columns.length; i += delta) {
320
+ if (columns[i].declared) {
321
+ target = columns[i];
322
+ break;
323
+ }
324
+ }
325
+ if (!target) return;
326
+ event.preventDefault();
327
+ void commit(id, target.stage.id);
328
+ };
329
+ const state = (content) => /* @__PURE__ */ jsxRuntime.jsx(
330
+ "div",
331
+ {
332
+ "data-slot": "board-view-state",
333
+ className: chunkS5RVSXDV_cjs.cn(
334
+ "border-border bg-card text-muted-foreground flex flex-col items-center justify-center gap-2 rounded-lg border px-4 py-10 text-center text-sm",
335
+ classNames?.state
336
+ ),
337
+ children: content
338
+ }
339
+ );
340
+ if (error) {
341
+ return state(
342
+ /* @__PURE__ */ jsxRuntime.jsx("p", { role: "alert", className: "text-destructive", children: text.error })
343
+ );
344
+ }
345
+ if (loading) {
346
+ return state(
347
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex items-center gap-2", children: [
348
+ /* @__PURE__ */ jsxRuntime.jsx(chunkXXVUHLQN_cjs.Spinner, { size: "sm", label: text.loading }),
349
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, children: text.loading })
350
+ ] })
351
+ );
352
+ }
353
+ if (items.length === 0 && emptyState) return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: emptyState });
354
+ const draggingItem = draggingId ? byId.get(draggingId) : void 0;
355
+ return /* @__PURE__ */ jsxRuntime.jsxs(
356
+ core.DndContext,
357
+ {
358
+ sensors,
359
+ collisionDetection: core.pointerWithin,
360
+ onDragStart,
361
+ onDragEnd,
362
+ onDragCancel: () => setDraggingId(null),
363
+ children: [
364
+ /* @__PURE__ */ jsxRuntime.jsx(
365
+ "div",
366
+ {
367
+ "data-slot": "board-view",
368
+ tabIndex: 0,
369
+ role: "group",
370
+ "aria-label": text.board,
371
+ className: chunkS5RVSXDV_cjs.cn(
372
+ // Columns on one scrolling row once there is room; stacked below it,
373
+ // because five 288px columns on a phone is a horizontal maze.
374
+ "flex flex-col gap-3 sm:flex-row sm:overflow-x-auto sm:pb-2",
375
+ className
376
+ ),
377
+ children: columns.map((column, columnIndex) => /* @__PURE__ */ jsxRuntime.jsx(
378
+ BoardColumn,
379
+ {
380
+ stage: column.stage,
381
+ droppable: column.declared && Boolean(onMove),
382
+ headerId: `${baseId}-col-${columnIndex}`,
383
+ count: column.items.length,
384
+ headingLevel,
385
+ classNames,
386
+ children: /* @__PURE__ */ jsxRuntime.jsxs(
387
+ "ul",
388
+ {
389
+ "aria-labelledby": `${baseId}-col-${columnIndex}`,
390
+ className: "flex flex-1 flex-col gap-2 p-2",
391
+ children: [
392
+ column.items.map((item) => {
393
+ const id = accessors.getId(item);
394
+ return /* @__PURE__ */ jsxRuntime.jsx(
395
+ BoardCard,
396
+ {
397
+ id,
398
+ title: accessors.getTitle(item),
399
+ subtitle: accessors.getSubtitle?.(item),
400
+ accent: accessors.getAccent?.(item),
401
+ selected: id === selectedId,
402
+ pending: pending.has(id),
403
+ draggable: Boolean(onMove),
404
+ hint: onMove ? hintId : void 0,
405
+ href: getHref?.(id, item),
406
+ className: chunkS5RVSXDV_cjs.cn(
407
+ cardVariants({
408
+ density,
409
+ interactive: Boolean(onOpen),
410
+ selected: id === selectedId,
411
+ pending: pending.has(id)
412
+ }),
413
+ classNames?.card,
414
+ id === selectedId && classNames?.selectedCard
415
+ ),
416
+ onOpen: onOpen ? () => onOpen(id, item) : void 0,
417
+ onKeyDown: (event) => onCardKeyDown(event, id, columnIndex),
418
+ children: renderItem?.(item, { view: "board" })
419
+ },
420
+ id
421
+ );
422
+ }),
423
+ column.items.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("li", { className: "text-muted-foreground px-1 py-2 text-xs", children: text.empty })
424
+ ]
425
+ }
426
+ )
427
+ },
428
+ column.stage.id
429
+ ))
430
+ }
431
+ ),
432
+ onMove && /* @__PURE__ */ jsxRuntime.jsx("span", { id: hintId, className: "sr-only", children: text.moveHint }),
433
+ /* @__PURE__ */ jsxRuntime.jsx(
434
+ "span",
435
+ {
436
+ "data-slot": "board-view-announcer",
437
+ role: "status",
438
+ "aria-live": "polite",
439
+ className: "sr-only",
440
+ children: announcement
441
+ }
442
+ ),
443
+ /* @__PURE__ */ jsxRuntime.jsx(core.DragOverlay, { children: draggingItem && /* @__PURE__ */ jsxRuntime.jsx("div", { className: chunkS5RVSXDV_cjs.cn(cardVariants({ density }), "shadow-lg"), children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-foreground block text-sm font-medium", children: accessors.getTitle(draggingItem) }) }) })
444
+ ]
445
+ }
446
+ );
447
+ }
448
+
449
+ exports.BoardView = BoardView;
450
+ exports.cardVariants = cardVariants;
451
+ exports.defaultBoardLabels = defaultBoardLabels;
452
+ //# sourceMappingURL=chunk-4IS3QCOQ.cjs.map
453
+ //# sourceMappingURL=chunk-4IS3QCOQ.cjs.map