@cosmicdrift/kumiko-renderer 0.378.0 → 0.380.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 (79) hide show
  1. package/dist/app/action-form-shim.js +1 -2
  2. package/dist/app/action-form-support.js +16 -4
  3. package/dist/app/kumiko-screen.js +49 -38
  4. package/dist/app/list-empty-content.d.ts +1 -0
  5. package/dist/app/list-empty-content.js +5 -0
  6. package/dist/app/row-actions.d.ts +7 -1
  7. package/dist/app/row-actions.js +6 -1
  8. package/dist/app/secret-mint-body.js +3 -2
  9. package/dist/components/embedded-list-field.js +16 -7
  10. package/dist/components/file-list-field.js +4 -0
  11. package/dist/components/grid-cell-for-field.d.ts +4 -1
  12. package/dist/components/grid-cell-for-field.js +6 -2
  13. package/dist/components/list-empty-state.d.ts +4 -1
  14. package/dist/components/list-empty-state.js +4 -1
  15. package/dist/components/reference-create-dialog.js +1 -1
  16. package/dist/components/related-list-section.js +4 -1
  17. package/dist/components/render-edit-logic.d.ts +1 -1
  18. package/dist/components/render-edit-logic.js +8 -2
  19. package/dist/components/render-edit-types.d.ts +3 -0
  20. package/dist/components/render-edit.js +25 -6
  21. package/dist/components/render-field.d.ts +3 -1
  22. package/dist/components/render-field.js +19 -7
  23. package/dist/components/render-list.d.ts +3 -1
  24. package/dist/components/render-list.js +29 -8
  25. package/dist/components/write-form-section.js +4 -1
  26. package/dist/field-issue-text.d.ts +4 -0
  27. package/dist/field-issue-text.js +14 -0
  28. package/dist/headless/dispatcher/index.d.ts +1 -0
  29. package/dist/headless/dispatcher/index.js +1 -0
  30. package/dist/headless/dispatcher/request-id.d.ts +1 -0
  31. package/dist/headless/dispatcher/request-id.js +15 -0
  32. package/dist/headless/form/form-controller.js +16 -1
  33. package/dist/headless/form/zod-bridge.js +7 -0
  34. package/dist/headless/index.d.ts +2 -1
  35. package/dist/headless/index.js +2 -1
  36. package/dist/headless/plural-key.d.ts +1 -0
  37. package/dist/headless/plural-key.js +5 -0
  38. package/dist/headless/view-model/edit.d.ts +4 -0
  39. package/dist/headless/view-model/edit.js +10 -5
  40. package/dist/headless/view-model/types.d.ts +10 -2
  41. package/dist/hooks/live-refetch-scheduler.d.ts +6 -0
  42. package/dist/hooks/live-refetch-scheduler.js +45 -0
  43. package/dist/hooks/use-query.js +8 -4
  44. package/dist/hooks/use-reference-lookup.d.ts +1 -0
  45. package/dist/hooks/use-reference-lookup.js +6 -3
  46. package/dist/i18n-defaults.js +22 -3
  47. package/dist/index.d.ts +3 -1
  48. package/dist/index.js +3 -1
  49. package/dist/leave-guard-dialog.d.ts +2 -0
  50. package/dist/leave-guard-dialog.js +28 -0
  51. package/dist/leave-guard.d.ts +15 -0
  52. package/dist/leave-guard.js +39 -0
  53. package/dist/live/dispatcher-live.js +1 -16
  54. package/dist/primitives.d.ts +29 -0
  55. package/dist/sse/live-events.d.ts +3 -0
  56. package/dist/sse/live-events.js +3 -0
  57. package/dist/web/app/create-app.js +2 -2
  58. package/dist/web/app/dashboard-body.js +13 -1
  59. package/dist/web/app/nav.js +51 -9
  60. package/dist/web/layout/nav-tree.js +13 -3
  61. package/dist/web/layout/shell-header.js +3 -3
  62. package/dist/web/lib/file-upload-form-data.d.ts +2 -0
  63. package/dist/web/lib/file-upload-form-data.js +2 -0
  64. package/dist/web/lib/upload-error-key.d.ts +7 -0
  65. package/dist/web/lib/upload-error-key.js +23 -0
  66. package/dist/web/lib/upload-file-ref.d.ts +1 -1
  67. package/dist/web/primitives/embedded-list-input.js +5 -4
  68. package/dist/web/primitives/file-upload.d.ts +2 -1
  69. package/dist/web/primitives/file-upload.js +11 -7
  70. package/dist/web/primitives/files-dropzone.d.ts +16 -0
  71. package/dist/web/primitives/files-dropzone.js +52 -0
  72. package/dist/web/primitives/index.js +62 -29
  73. package/dist/web/primitives/segmented-select.js +8 -2
  74. package/dist/web/sse/live-events.d.ts +13 -0
  75. package/dist/web/sse/live-events.js +88 -23
  76. package/dist/web/widgets/upload-zone.d.ts +11 -2
  77. package/dist/web/widgets/upload-zone.js +30 -7
  78. package/package.json +5 -5
  79. package/src/changes.json +104 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cosmicdrift/kumiko-renderer",
3
- "version": "0.378.0",
3
+ "version": "0.380.0",
4
4
  "description": "React renderer for Kumiko screens. The root export holds the platform-agnostic logic (primitives contract, hooks, KumikoScreen, navigation and SSE abstractions); ./headless the DOM-free UI logic, ./live the HTTP dispatcher, ./web the browser bindings (HTML primitives, history navigation, EventSource live events, createKumikoApp).",
5
5
  "license": "BUSL-1.1",
6
6
  "author": "Marc Frost <marc@cosmicdriftgamestudio.com>",
@@ -48,8 +48,8 @@
48
48
  }
49
49
  },
50
50
  "dependencies": {
51
- "@cosmicdrift/kumiko-framework": "0.378.0",
52
- "@cosmicdrift/kumiko-types": "0.378.0",
51
+ "@cosmicdrift/kumiko-framework": "0.380.0",
52
+ "@cosmicdrift/kumiko-types": "0.380.0",
53
53
  "@radix-ui/react-dialog": "^1.1.15",
54
54
  "@radix-ui/react-dropdown-menu": "^2.1.16",
55
55
  "@radix-ui/react-label": "^2.1.8",
@@ -92,8 +92,8 @@
92
92
  }
93
93
  },
94
94
  "devDependencies": {
95
- "@cosmicdrift/kumiko-locale-de": "0.378.0",
96
- "@cosmicdrift/kumiko-testing": "0.378.0",
95
+ "@cosmicdrift/kumiko-locale-de": "0.380.0",
96
+ "@cosmicdrift/kumiko-testing": "0.380.0",
97
97
  "@tailwindcss/cli": "^4.3.0",
98
98
  "@testing-library/react": "^16.3.2",
99
99
  "@testing-library/user-event": "^14.6.1",
package/src/changes.json CHANGED
@@ -1,4 +1,108 @@
1
1
  [
2
+ {
3
+ "version": "0.379.0",
4
+ "type": "fix",
5
+ "title": "actionForm success box shows the message and every fact on its own line",
6
+ "detail": "The success message and the successFacts of an actionForm no longer run together (\"Fertig.Gebucht: 20Übersprungen: 0\"). The message is its own line, a fact with one value is one \"Label: value\" line, a fact with several lines (for example file names) is a label line followed by one line per value instead of a comma chain. New test ids action-form-success-text and action-form-success-fact-<n>-line-<i>.",
7
+ "migration": "None. Tests that read the textContent of a multi-line fact now see the label and the lines without the former \", \" separators."
8
+ },
9
+ {
10
+ "version": "0.379.0",
11
+ "type": "improvement",
12
+ "title": "Empty list with an active default filter offers \"Show all\"",
13
+ "detail": "A list that is empty only because its defaultFilters are on says so and offers a Show all button instead of the \"create the first one\" text. The hard-coded Loading… banners use the kumiko.widget.loading key, so they follow the locale."
14
+ },
15
+ {
16
+ "version": "0.379.0",
17
+ "type": "fix",
18
+ "title": "Count messages use singular and plural forms",
19
+ "detail": "Nine count messages (template usage, mail preview entries, layout origin and footer, tag delete confirmation, embedded-list paste warnings) now come as .one and .other keys in en, de, es, fr and it, so \"1 template\" no longer reads \"1 templates\". Apps that override these keys must rename them to .one and .other."
20
+ },
21
+ {
22
+ "version": "0.379.0",
23
+ "type": "fix",
24
+ "title": "Shell header: the parent crumb no longer slides under a long title",
25
+ "detail": "The page title truncates on its own; the parent crumb stays whole and is left out when the space beside the header actions gets narrower than 20rem (a container query on the header's left side instead of the sm viewport breakpoint). The h1 carries the full title as tooltip."
26
+ },
27
+ {
28
+ "version": "0.379.0",
29
+ "type": "fix",
30
+ "title": "A rejected empty embedded list shows its error at the list, once, without a banner-only failure",
31
+ "detail": "The empty state of an embedded list now shows list-level issues (min items, required), and the surrounding field no longer prints them a second time. An issue on a derived head total that is not laid out (an empty list leaves it without a value) no longer adds the generic form banner while another issue is shown; it still shows the banner when it is the only issue. A list below its minItems now reads \"At least 1 row required.\" / \"At least N rows required.\" (errors.validation.list_min_rows.one and .other) instead of the generic too-small text. Only embedded lists get the row wording (their schema reports a custom issue with params.i18nKey and minimum, which both zod bridges now forward); other arrays such as a required multiSelect keep errors.validation.too_small.",
32
+ "migration": "None."
33
+ },
34
+ {
35
+ "version": "0.379.0",
36
+ "type": "fix",
37
+ "title": "An embedded list does not repeat its section title as a visible label",
38
+ "detail": "When the label of an embedded-list field equals the title of the section it sits in (for example \"Positionen\" under \"Positionen\"), entityEdit and actionForm screens now keep the label for screen readers only instead of printing it twice. Applies by default, no setting.",
39
+ "migration": "None."
40
+ },
41
+ {
42
+ "version": "0.379.0",
43
+ "type": "improvement",
44
+ "title": "Embedded-list footer totals can sum several columns under their own label",
45
+ "detail": "EmbeddedFieldDef.totals entries are now a column name (as before) or { label, from } with an i18n label and the sub-fields to add up, for example Net { from: [\"amount\"] }, VAT { from: [\"vatAmount\"] } and Gross { from: [\"amount\", \"vatAmount\"] }. Display only, the server derivation is unchanged. The boot validator rejects an empty from and any from entry that is not a number, money or decimal sub-field. Money sums use the same format as string totals. The ui-walkthrough receive-invoice screen and the embedded recipe now lay out only the Positionen list with a footer of Net, VAT and Gross; the derived head totals are still computed on the server but not laid out, and the list requires at least one line (minItems 1).",
46
+ "migration": "Optional. Replace a totals string list with labelled entries where the footer should show Net, VAT and Gross (solon invoice screens)."
47
+ },
48
+ {
49
+ "version": "0.379.0",
50
+ "type": "fix",
51
+ "title": "projectionDetail shows the record again after a record action",
52
+ "detail": "After a writeHandler action on a projectionDetail (header or section action) the screen refetched the record but the shown fields kept their old values until a reload. The actions now reload through the same path as the reload button, which re-applies the refetched record to a form without user input.",
53
+ "migration": "None."
54
+ },
55
+ {
56
+ "version": "0.379.0",
57
+ "type": "improvement",
58
+ "title": "Live updates reconnect, resync and coalesce refetches",
59
+ "detail": "The web EventSource reconnects with exponential backoff and jitter after a refused handshake unless the session ended, rewires every subscribed entity on the new connection and sends each listener a LIVE_RESYNC_EVENT_TYPE event after a reconnect, because frames during the gap are lost. useQuery and the nav tree refetch in the background and collapse a burst of live events into one trailing run (LIVE_REFETCH_COALESCE_MS); an event during a running fetch queues exactly one follow-up. A failed refetch keeps the last data on screen and shows QueryErrorBanner with a retry button above it."
60
+ },
61
+ {
62
+ "version": "0.379.0",
63
+ "type": "breaking",
64
+ "title": "Forms ask before unsaved input is discarded",
65
+ "detail": "A dirty entity form or writeForm section now asks with the discard dialog before an in-app navigation, a projectionDetail tab switch, browser back or forward, and the browser asks on tab close or reload (beforeunload). A successful save clears the form before its follow-up navigation, and wizards with layout.draft keep their draft instead of asking. requestLeave, hasUnsavedInput and useUnsavedInputSource are exported for custom screens.",
66
+ "migration": "End-to-end tests that fill a form and then navigate away without saving now meet the dialog (testId leave-guard-dialog); confirm it or save first. page.goto from a dirty form triggers the browser's beforeunload prompt."
67
+ },
68
+ {
69
+ "version": "0.379.0",
70
+ "type": "breaking",
71
+ "title": "Form writes carry a requestId and reuse it only for a safe retry",
72
+ "detail": "The form controller passes { requestId } as third argument to dispatcher.write. After a transport failure without a server answer, a submit with the same values reuses the requestId, so the server idempotency guard does not run the write twice; any server answer or changed values get a new one. generateRequestId moved to the headless dispatcher module.",
73
+ "migration": "Tests that assert a mocked dispatcher.write with toHaveBeenCalledWith(type, payload) must accept the third argument, e.g. toHaveBeenCalledWith(type, payload, expect.objectContaining({ requestId: expect.any(String) })). Custom Dispatcher implementations should forward options.requestId."
74
+ },
75
+ {
76
+ "version": "0.379.0",
77
+ "type": "improvement",
78
+ "title": "Failed submits focus the first invalid field, clearer format errors",
79
+ "detail": "After a failed submit the web form focuses and scrolls to the first field with aria-invalid (FormProps.focusFirstErrorKey; native forms ignore it). Format errors for email, url, date, datetime and uuid name the expected format with an example, the error line no longer shifts the labels of neighbouring fields, and SegmentedControl options with up to four entries get equal widths."
80
+ },
81
+ {
82
+ "version": "0.379.0",
83
+ "type": "fix",
84
+ "title": "Toolbar navigate actions are hidden when the user may not open the target screen",
85
+ "detail": "A toolbarAction of kind navigate on entityList, projectionList and relatedList now follows the access rule of its target screen, the same check metric jumps use. Before, the button showed for every role and led to an access-denied page.",
86
+ "migration": "None. Gate the target screen with its own access rule; the toolbar button follows it."
87
+ },
88
+ {
89
+ "version": "0.379.0",
90
+ "type": "improvement",
91
+ "title": "actionForm loads a singleton row without a record id",
92
+ "detail": "load.singleton: true on an actionForm sends the load query without idParam and prefills the form from the tenant's single row, like projectionDetail. A route id is never forwarded. The boot validator rejects singleton together with idParam."
93
+ },
94
+ {
95
+ "version": "0.379.0",
96
+ "type": "improvement",
97
+ "title": "Dashboard text block link shown only to given roles",
98
+ "detail": "A text block of kind link ({ text, screen, roles? }) renders a link to a screen and is hidden unless the user holds one of the roles. This only gates the display; the target screen still checks access on the server. The boot validator rejects an unknown target screen and an empty roles list."
99
+ },
100
+ {
101
+ "version": "0.379.0",
102
+ "type": "fix",
103
+ "title": "DataTable no longer hides its last column under the sticky actions column",
104
+ "detail": "Header and text cells wrap instead of staying on one line (badges, dates and row actions keep their own nowrap), and a row-action group wraps when the column is narrow. A table whose cells could not shrink scrolled sideways without a visible scrollbar and its last column slid under the sticky actions column. Long values now wrap (up to max-w-xs per column) instead of being cut with an ellipsis."
105
+ },
2
106
  {
3
107
  "version": "0.378.0",
4
108
  "type": "fix",