@reventlessdev/reventless-ui-slots 3.0.0-alpha.2 → 3.0.0-alpha.3

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.
package/README.md CHANGED
@@ -145,6 +145,11 @@ the question.
145
145
  | `tracker.summary` | row | the line beside one row's name; its summary fields |
146
146
  | `detail.media` | row | the media column of a `detailLayout: "media"` page; the record's picture |
147
147
  | `detail.aside` | row | above the field set on a `detailLayout: "media"` page; nothing by default |
148
+ | `list.selection` | view | the bar over a list whose rows the caller can pick out: what is picked, a way to empty it, and the one command that takes the lot |
149
+
150
+ `list.selection` is the one id that is not `<mode>.<region>`: it belongs to the
151
+ list itself rather than to a mode, which is what lets a picking made in the table
152
+ survive a switch to cards.
148
153
 
149
154
  An id nothing offers is reported to the console at boot — a renderer nothing will
150
155
  ever call is a mistake the running app would otherwise never mention.
@@ -156,7 +161,7 @@ ever call is a mistake the running app would otherwise never mention.
156
161
  { row, label?, image?, open?, actions? }
157
162
 
158
163
  // view slot
159
- { rows, total?, selection?, run? }
164
+ { rows, total?, selection?, picked?, run? }
160
165
  ```
161
166
 
162
167
  `row` is the read model's own JSON. `image` is already resolved for this
@@ -164,10 +169,12 @@ deployment's asset origins. `actions` are already resolved against the
164
169
  deployment's declarations, the caller's permissions and the row's lifecycle
165
170
  state. `open` drills into the row.
166
171
 
167
- `selection` and `run` are declared and filled by nothing yet — cross-row
168
- selection is its own piece of work. They are in the contract from the start
169
- because discovering that a region needs a second arity after publishing would be
170
- a breaking change.
172
+ `selection` is the picked row **ids**; `picked` is the rows behind them, each as
173
+ the same row-slot payload above. Both, and not just the ids, because a list's
174
+ window is replaced page by page: a row picked on page 1 is gone from `rows` by
175
+ the time the caller is on page 3, and a bar whose job is to name what is in it
176
+ cannot look one up. `run` takes the command's name and opens its form with the
177
+ picked ids already in place.
171
178
 
172
179
  ## What a slot may not do
173
180
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reventlessdev/reventless-ui-slots",
3
- "version": "3.0.0-alpha.2",
3
+ "version": "3.0.0-alpha.3",
4
4
  "description": "Types and one runtime helper for writing custom renderers into the regions of Reventless AutoUI's standard view modes.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -54,5 +54,5 @@
54
54
  "react-dom": "^18.3.1",
55
55
  "rescript": "^12.3.0"
56
56
  },
57
- "gitHead": "6d74b362ba047678919b27c22f84e698dea48741"
57
+ "gitHead": "d2a7156f66c7f5f42837c6d5c13faf6d33a6df7e"
58
58
  }
@@ -20,6 +20,7 @@ type viewPayload = {
20
20
  rows: array<JSON.t>,
21
21
  total?: int,
22
22
  selection?: array<string>,
23
+ picked?: array<rowPayload>,
23
24
  run?: string => unit,
24
25
  }
25
26
 
@@ -144,6 +145,19 @@ module Format = {
144
145
  let at = Date.fromString(iso)
145
146
  Float.isNaN(Date.getTime(at)) ? "" : Date.toLocaleDateString(at)
146
147
  }
148
+
149
+ let pad = (n: int): string => n < 10 ? "0" ++ Int.toString(n) : Int.toString(n)
150
+
151
+ let isoDay = (iso: string): string => {
152
+ let at = Date.fromString(iso)
153
+ Float.isNaN(Date.getTime(at))
154
+ ? ""
155
+ : Int.toString(Date.getFullYear(at)) ++
156
+ "-" ++
157
+ pad(Date.getMonth(at) + 1) ++
158
+ "-" ++
159
+ pad(Date.getDate(at))
160
+ }
147
161
  }
148
162
 
149
163
  let titleOf = (payload: rowPayload): string =>
@@ -208,5 +222,6 @@ module RowSlot = {
208
222
  module ViewSlot = {
209
223
  let cardsEmpty = "cards.empty"
210
224
  let galleryEmpty = "gallery.empty"
211
- let all = [cardsEmpty, galleryEmpty]
225
+ let listSelection = "list.selection"
226
+ let all = [cardsEmpty, galleryEmpty, listSelection]
212
227
  }
@@ -121,10 +121,22 @@ function day(iso) {
121
121
  }
122
122
  }
123
123
 
124
- let Format = {
125
- money: money$1,
126
- day: day
127
- };
124
+ function pad(n) {
125
+ if (n < 10) {
126
+ return "0" + n.toString();
127
+ } else {
128
+ return n.toString();
129
+ }
130
+ }
131
+
132
+ function isoDay(iso) {
133
+ let at = new Date(iso);
134
+ if (Number.isNaN(at.getTime())) {
135
+ return "";
136
+ } else {
137
+ return at.getFullYear().toString() + "-" + pad(at.getMonth() + 1 | 0) + "-" + pad(at.getDate());
138
+ }
139
+ }
128
140
 
129
141
  function titleOf(payload) {
130
142
  let label = payload.label;
@@ -189,17 +201,27 @@ let cardsEmpty = "cards.empty";
189
201
 
190
202
  let galleryEmpty = "gallery.empty";
191
203
 
204
+ let listSelection = "list.selection";
205
+
192
206
  let all$1 = [
193
207
  cardsEmpty,
194
- galleryEmpty
208
+ galleryEmpty,
209
+ listSelection
195
210
  ];
196
211
 
197
212
  let ViewSlot = {
198
213
  cardsEmpty: cardsEmpty,
199
214
  galleryEmpty: galleryEmpty,
215
+ listSelection: listSelection,
200
216
  all: all$1
201
217
  };
202
218
 
219
+ let Format = {
220
+ money: money$1,
221
+ day: day,
222
+ isoDay: isoDay
223
+ };
224
+
203
225
  export {
204
226
  h,
205
227
  RowSlot,
@@ -42,17 +42,21 @@ type rowPayload = {
42
42
  actions?: array<action>,
43
43
  }
44
44
 
45
- /** What a per-view region is handed. `selection` and `run` are declared and
46
- filled by nothing yet — cross-row selection is its own piece of work. They
47
- are in the contract from the start because discovering that a region needs a
48
- second arity after publishing would be a breaking change. */
45
+ /** What a per-view region is handed. */
49
46
  type viewPayload = {
50
47
  /** The rows the mode is currently drawing — its page window, not the table. */
51
48
  rows: array<JSON.t>,
52
49
  /** How many rows that window holds. */
53
50
  total?: int,
54
- /** Row ids the caller has picked out, where the mode offers picking. */
51
+ /** Row ids the caller has picked out, where the view offers picking. */
55
52
  selection?: array<string>,
53
+ /** The rows behind `selection`, as they were when picked.
54
+
55
+ A list's window is replaced page by page, so a row picked on page 1 is
56
+ gone from `rows` by the time the caller is on page 3 — and a bar whose job
57
+ is to name what is in it cannot look one up. So the rows travel, each as
58
+ the same `rowPayload` a per-row region is handed. */
59
+ picked?: array<rowPayload>,
56
60
  /** Start the region's one command, by name. */
57
61
  run?: string => unit,
58
62
  }
@@ -187,8 +191,21 @@ module Format: {
187
191
  most currencies and quietly wrong for JPY and TND. */
188
192
  let money: ((float, string)) => string
189
193
 
190
- /** An ISO instant as a short local date. `""` when it does not parse. */
194
+ /** An ISO instant as a short date **in the viewer's own locale**.
195
+
196
+ Which format that is comes from the runtime, not from you or from the
197
+ deployment: the same order reads `9/4/2026` to one customer and `04/09/2026`
198
+ to another, and a screenshot never matches CI. That is right for a surface
199
+ whose readers are the public, and wrong wherever a date has to be
200
+ unambiguous or stable — take `isoDay` there. */
191
201
  let day: string => string
202
+
203
+ /** An ISO instant as `YYYY-MM-DD`, the same everywhere.
204
+
205
+ Built from the **local** calendar parts rather than by slicing the string,
206
+ which would silently publish the UTC date and land a day out either side of
207
+ midnight for most of the world. */
208
+ let isoDay: string => string
192
209
  }
193
210
 
194
211
  /** What the mode would have titled this row, else the row's own `name`.
@@ -216,5 +233,13 @@ module ViewSlot: {
216
233
  let cardsEmpty: string
217
234
  /** The tile grid when the view has no rows. */
218
235
  let galleryEmpty: string
236
+ /** The bar over a list whose rows the caller can pick out: what is picked, a
237
+ way to empty it, and the one command that takes the lot.
238
+
239
+ Offered by the list producer rather than by a view mode — the first id
240
+ that is not `<mode>.<region>`. The list renders the mode inside its own
241
+ chrome and the bar is that chrome, so a picking made in the table survives
242
+ a switch to cards and the bar has to outlive both. */
243
+ let listSelection: string
219
244
  let all: array<string>
220
245
  }
package/src/index.d.ts CHANGED
@@ -48,19 +48,21 @@ export interface RowPayload<Row = Record<string, unknown>> {
48
48
  actions?: SlotAction[]
49
49
  }
50
50
 
51
- /** What a per-view region is handed.
52
- *
53
- * `selection` and `run` are declared and filled by nothing yet: cross-row
54
- * selection is its own piece of work. They are here from the start because
55
- * discovering that a region needs a second arity after the contract is
56
- * published would be a breaking change. */
51
+ /** What a per-view region is handed. */
57
52
  export interface ViewPayload<Row = Record<string, unknown>> {
58
53
  /** The rows the mode is currently drawing — its page window, not the table. */
59
54
  rows: Row[]
60
55
  /** How many rows that window holds. */
61
56
  total?: number
62
- /** Row ids the caller has picked out, where the mode offers picking. */
57
+ /** Row ids the caller has picked out, where the view offers picking. */
63
58
  selection?: string[]
59
+ /** The rows behind `selection`, as they were when picked.
60
+ *
61
+ * A list's window is replaced page by page, so a row picked on page 1 is gone
62
+ * from `rows` by the time the caller is on page 3 — and a bar whose job is to
63
+ * name what is in it cannot look one up. So the rows travel, each as the same
64
+ * `RowPayload` a per-row region is handed. */
65
+ picked?: RowPayload<Row>[]
64
66
  /** Start the region's one command, by name. */
65
67
  run?: (command: string) => void
66
68
  }
@@ -126,8 +128,14 @@ export type RowSlotId =
126
128
  * | --- | --- |
127
129
  * | `cards.empty` | the card grid when the view has no rows |
128
130
  * | `gallery.empty` | the tile grid when the view has no rows |
131
+ * | `list.selection` | the bar over a list whose rows the caller can pick out |
132
+ *
133
+ * `list.selection` is the one id that is not `<mode>.<region>`: it belongs to
134
+ * the list producer, not to a mode. The list renders the mode inside its own
135
+ * chrome and the bar is that chrome, so a picking made in the table survives a
136
+ * switch to cards and the bar has to outlive both.
129
137
  */
130
- export type ViewSlotId = 'cards.empty' | 'gallery.empty'
138
+ export type ViewSlotId = 'cards.empty' | 'gallery.empty' | 'list.selection'
131
139
 
132
140
  /**
133
141
  * Identity helper: type-checks a `register` function without changing it.