@ai-matrx/records-ui 0.108.0 → 0.109.4

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/CHANGELOG.md CHANGED
@@ -1,5 +1,46 @@
1
1
  # Changelog — @ai-matrx/records-ui
2
2
 
3
+ ## 0.109.4
4
+ ### lane TABLE-EDITING-EDGES
5
+
6
+ - NEW RECORD ON A TABLE WITH A REQUIRED COLUMN OPENS THE FORM, never a red banner: the grid asks the store's own mirror (`predictWriteRefusals`) before writing a blank record; when it would be refused ("Brand name is required") the record form opens with the cursor on the first required column, and the required check speaks only when Create is tried. No refused write is sent, so nothing lands in the error inspector. A refusal the mirror did not foresee opens the form too. (`Grid`, `NewRecordControl` takes `ask`; `RecordForm` takes `focusFirstRequired`.)
7
+ - A typed date is read in every control that uses the one reader, including bare digits (`10142026`, `101426`) — see `@ai-matrx/records` 0.81.2; the form's date box test now holds `10142026`, `10/14/2026` and `10/14/26` to what is saved.
8
+
9
+ **Consumer action:** none.
10
+
11
+ ## 0.109.3
12
+ ### lane DESCRIBE-INSTALL: a preview never claims a save
13
+
14
+ - `FormRunner`'s preview thank-you no longer shows the form's own words ("Brand saved.") as if they were this send's result: under a preview they follow "After a real send, people read:", and the last line still says "Preview · nothing saved".
15
+
16
+ **Consumer action:** none.
17
+
18
+ ## 0.109.2
19
+ ### lane SORT-REACTS
20
+
21
+ - A grid edit that changes a sorted, filtered or grouped value moves its row: the page is read again (see `@ai-matrx/records`), and the edited row glides to its new place and is lit for a moment (`gridRowMove.ts`; the design system's `--matrx-motion-duration-slow` / `--matrx-motion-ease-panel`, none under reduced motion), its cell stays selected, and a row that landed out of view is scrolled to. A row that left the filter says so with Undo (`gridViewMove.ts`, already there — it now sees the move on a live page too). Layout check: `pnpm test:layout` case 9.
22
+
23
+ **Consumer action:** none.
24
+
25
+ ## 0.109.1
26
+
27
+ Release of 0.109.0's SSR-ROWS work (its publish gate stopped at the new test's untyped `jsdom` import; the test now types the one constructor it uses). No source change.
28
+
29
+ **Consumer action:** none.
30
+
31
+ ## 0.109.0
32
+ ### Archive record from the row menu works
33
+
34
+ - The grid's row menu "Archive record" opens its confirm once the menu has closed (`afterMenuLayerCloses`, exported from `gridControls`); opened inside the menu's select callback, the closing menu dismissed it at once (always inside a contenteditable host such as a Space), so the press did nothing. A row the page no longer holds says so. No consumer action.
35
+
36
+ ### SSR-ROWS: the table page arrives with its rows
37
+
38
+ - NEW in `@ai-matrx/records-ui/first-page`: `askTablePageSeed({ dataSource, organizationId, tableId, actor, recordId?, rows?, embedded?, pageSize? })` — a host's server asks, AS THE PERSON, the table's bundle, the grid's exact first page (`firstGridPageRequest`) and on a record page the record's bundle, and gets a `RecordsSeed`. Mount `<RecordsSeedProvider seed>` (`@ai-matrx/records/react`) above `TablePage` and the page is drawn — rows included — in the server's HTML, then hydrates with no mismatch and no page read. `embedded: true` asks the embedded table's page size (`EMBEDDED_PAGE_SIZE`, now declared here).
39
+ - `first-page` is built WITHOUT the package's "use client" banner (its own tsup entry), so a server component can call it; `presentation.ts` reads `parseTableStyle` from `@ai-matrx/design-system/data-table/table-style` (client-free) for the same reason.
40
+ - `TablePage` starts from the seed's saved views and looks (`useSeededAnswer`), so it knows its face in the first pass instead of drawing its skeleton until two effects land; `ViewBar` takes `initialViews` and skips its mount read. Without a seed both read exactly as before.
41
+
42
+ **Consumer action:** none (additive). Spaces: ask `askTablePageSeed({ …, embedded: true })` in the route and wrap the inline table in `<RecordsSeedProvider>`.
43
+
3
44
  ## 0.108.0
4
45
  ### PAGE-BUNDLE-2: the grid's first page, asked before the grid exists
5
46
 
@@ -1,44 +1,22 @@
1
- "use client";
2
- "use strict";
3
- var __defProp = Object.defineProperty;
4
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
- var __getOwnPropNames = Object.getOwnPropertyNames;
6
- var __hasOwnProp = Object.prototype.hasOwnProperty;
7
- var __export = (target, all) => {
8
- for (var name in all)
9
- __defProp(target, name, { get: all[name], enumerable: true });
10
- };
11
- var __copyProps = (to, from, except, desc) => {
12
- if (from && typeof from === "object" || typeof from === "function") {
13
- for (let key of __getOwnPropNames(from))
14
- if (!__hasOwnProp.call(to, key) && key !== except)
15
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
- }
17
- return to;
18
- };
19
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
1
+ 'use strict';
20
2
 
21
- // src/firstPage.ts
22
- var firstPage_exports = {};
23
- __export(firstPage_exports, {
24
- TABLE_PAGE_SIZE: () => TABLE_PAGE_SIZE,
25
- firstGridPageArgs: () => firstGridPageArgs,
26
- firstGridPageRequest: () => firstGridPageRequest
27
- });
28
- module.exports = __toCommonJS(firstPage_exports);
3
+ var core = require('@ai-matrx/records/core');
4
+ var records = require('@ai-matrx/records');
5
+ require('@ai-matrx/kit/text-case');
6
+ require('@ai-matrx/design-system/data-table');
7
+ var tableStyle = require('@ai-matrx/design-system/data-table/table-style');
8
+ require('@ai-matrx/design-system/field-formats');
29
9
 
30
- // src/parity.ts
31
- var import_records = require("@ai-matrx/records");
32
- var import_text_case = require("@ai-matrx/kit/text-case");
33
- var kernelId = (name) => import_records.KERNEL_TABLES.find((t) => t.name === name)?.id ?? "";
10
+ // src/firstPage.ts
11
+ var kernelId = (name) => records.KERNEL_TABLES.find((t) => t.name === name)?.id ?? "";
34
12
  var KERNEL_FILE_TABLE = kernelId("File");
35
13
  var KERNEL_PERSON_TABLE = kernelId("Person");
36
- var PARITY_MADE_OF = Object.fromEntries(
37
- import_records.PARITY_FIELD_TYPES.map((p) => [p.parity_type, p.made_of])
14
+ Object.fromEntries(
15
+ records.PARITY_FIELD_TYPES.map((p) => [p.parity_type, p.made_of])
38
16
  );
39
17
  var KERNEL = { file: KERNEL_FILE_TABLE, person: KERNEL_PERSON_TABLE };
40
18
  function editorKindFor(field) {
41
- return (0, import_records.fieldKindFor)(field, KERNEL);
19
+ return records.fieldKindFor(field, KERNEL);
42
20
  }
43
21
 
44
22
  // src/gridLook.ts
@@ -68,10 +46,6 @@ function defaultSortOf(table, fields) {
68
46
  const field = fields.find((f) => f.key === name) ?? fields.find((f) => f.id === name);
69
47
  return field ? { id: field.key, direction } : null;
70
48
  }
71
-
72
- // src/gridPage.ts
73
- var import_records2 = require("@ai-matrx/records");
74
- var import_data_table = require("@ai-matrx/design-system/data-table");
75
49
  function holdsNumbers(field) {
76
50
  const kind = String(editorKindFor(field));
77
51
  if (kind === "number" || kind === "currency" || kind === "percent") return true;
@@ -89,11 +63,6 @@ function pageSortFor(fields, sort) {
89
63
  if (!field) return [];
90
64
  return [{ field: field.key, direction: sort.direction === "desc" ? "desc" : "asc", as: sortAsFor(field) }];
91
65
  }
92
-
93
- // src/presentation.ts
94
- var import_data_table2 = require("@ai-matrx/design-system/data-table");
95
- var import_field_formats = require("@ai-matrx/design-system/field-formats");
96
- var import_records3 = require("@ai-matrx/records");
97
66
  var MIN_ROW_HEIGHT = 24;
98
67
  var MAX_ROW_HEIGHT = 96;
99
68
  var AGGREGATE_KINDS = [
@@ -131,8 +100,8 @@ function parseGridPresentation(raw) {
131
100
  }
132
101
  if (!isRecord(value)) return {};
133
102
  const out = {};
134
- const style = (0, import_data_table2.parseTableStyle)(value["style"]);
135
- if (!(0, import_data_table2.tableStyleIsEmpty)(style)) out.style = style;
103
+ const style = tableStyle.parseTableStyle(value["style"]);
104
+ if (!tableStyle.tableStyleIsEmpty(style)) out.style = style;
136
105
  if (isRecord(value["formats"])) {
137
106
  const formats = {};
138
107
  for (const [key, cfg] of Object.entries(value["formats"])) {
@@ -261,53 +230,7 @@ function parseGrouping(raw) {
261
230
  }
262
231
  return out;
263
232
  }
264
-
265
- // src/viewKeys.ts
266
- var STORE_KEEPS_TIMELINE = true;
267
- var ALL = ["grid", "kanban", "calendar", "gallery", ...STORE_KEEPS_TIMELINE ? ["timeline"] : [], "list"];
268
- var HIDES = ["grid", "gallery", "kanban", "calendar", ...STORE_KEEPS_TIMELINE ? ["timeline"] : [], "list"];
269
- var GRIDS = ["grid"];
270
- var VIEW_KEYS = [
271
- { path: "layout", shape: "kind", layouts: ALL, writer: "caller" },
272
- { path: "filters", shape: "filter", layouts: ALL, writer: "caller" },
273
- { path: "where", shape: "rule", layouts: ALL, writer: "caller" },
274
- { path: "group_field", shape: "field", layouts: ["kanban", ...STORE_KEEPS_TIMELINE ? ["timeline"] : []], writer: "caller" },
275
- { path: "swimlane_field", shape: "field:lane", layouts: ["kanban"], writer: "caller" },
276
- { path: "collapsed_columns", shape: "values", layouts: ["kanban"], writer: "caller" },
277
- { path: "measure", shape: "field:number", layouts: ["kanban"], writer: "caller" },
278
- { path: "date_field", shape: "field:date", layouts: ["calendar"], writer: "caller" },
279
- ...STORE_KEEPS_TIMELINE ? [
280
- { path: "start_field", shape: "field:date", layouts: ["timeline"], writer: "caller" },
281
- { path: "end_field", shape: "field:date", layouts: ["calendar", "timeline"], writer: "caller" }
282
- ] : [],
283
- { path: "image_field", shape: "field", layouts: ["gallery"], writer: "caller" },
284
- { path: "sorts", shape: "sorts", layouts: ALL, writer: "caller" },
285
- { path: "rule_id", shape: "uuid", layouts: ALL, writer: "caller" },
286
- { path: "is_default", shape: "boolean", layouts: ALL, writer: "caller" },
287
- { path: "presentation", shape: "presentation", layouts: ALL, writer: "caller" },
288
- { path: "presentation.style", shape: "style", layouts: ALL, writer: "caller" },
289
- { path: "presentation.formats", shape: "object", layouts: GRIDS, writer: "caller" },
290
- { path: "presentation.frozen", shape: "fields", layouts: GRIDS, writer: "caller" },
291
- { path: "presentation.grouping", shape: "grouping", layouts: ["grid", "gallery", "list"], writer: "caller" },
292
- { path: "presentation.widths", shape: "widths", layouts: GRIDS, writer: "caller" },
293
- { path: "presentation.rowHeight", shape: "row_height", layouts: GRIDS, writer: "caller" },
294
- { path: "presentation.hiddenFields", shape: "fields", layouts: HIDES, writer: "caller" },
295
- { path: "presentation.cardHidden", shape: "fields", layouts: ["kanban", "calendar", ...STORE_KEEPS_TIMELINE ? ["timeline"] : [], "list", "gallery"], writer: "caller" },
296
- { path: "presentation.columnOrder", shape: "fields", layouts: GRIDS, writer: "caller" },
297
- { path: "presentation.gallerySize", shape: "gallery_size", layouts: ["gallery"], writer: "caller" },
298
- { path: "presentation.wrap", shape: "boolean", layouts: GRIDS, writer: "caller" },
299
- { path: "presentation.wrapColumns", shape: "fields", layouts: GRIDS, writer: "caller" },
300
- { path: "presentation.fit", shape: "fit", layouts: GRIDS, writer: "caller" },
301
- { path: "presentation.freezeFirst", shape: "boolean", layouts: GRIDS, writer: "caller" },
302
- { path: "presentation.footer", shape: "footer", layouts: GRIDS, writer: "caller" },
303
- { path: "presentation.summaries", shape: "summaries", layouts: GRIDS, writer: "caller" },
304
- { path: "grid", shape: "grid", layouts: GRIDS, writer: "caller" },
305
- { path: "hidden_fields", shape: "input", layouts: HIDES, writer: "input" },
306
- { path: "table_id", shape: "server", layouts: ALL, writer: "server" },
307
- { path: "order", shape: "server", layouts: GRIDS, writer: "server" },
308
- { path: "moved_from", shape: "server", layouts: ALL, writer: "server" }
309
- ];
310
- var STORE_KEPT_LAYOUTS = ["grid", "kanban", "calendar", "gallery", ...STORE_KEEPS_TIMELINE ? ["timeline"] : [], "list"];
233
+ var STORE_KEPT_LAYOUTS = ["grid", "kanban", "calendar", "gallery", ...["timeline"] , "list"];
311
234
  var KINDS = STORE_KEPT_LAYOUTS;
312
235
  function viewSettings(definition, rowFilters) {
313
236
  const data = definition ?? {};
@@ -360,14 +283,6 @@ function parseSorts(raw) {
360
283
 
361
284
  // src/views.ts
362
285
  var VIEW_LAYOUTS = ["grid", "kanban", "calendar", "gallery", "timeline", "list"];
363
- var LAYOUT_LABEL = {
364
- grid: "Grid",
365
- kanban: "Kanban",
366
- calendar: "Calendar",
367
- gallery: "Gallery",
368
- timeline: "Timeline",
369
- list: "List"
370
- };
371
286
  function viewOrderOf(definition) {
372
287
  const raw = definition?.["order"];
373
288
  return raw === "manual" ? "manual" : raw === "sorted" ? "sorted" : null;
@@ -375,12 +290,6 @@ function viewOrderOf(definition) {
375
290
  function defaultViewOf(views) {
376
291
  return views.find((v) => v.isDefault);
377
292
  }
378
- var PAGE_VIEWS = [...VIEW_LAYOUTS, "dashboards", "archived"];
379
- var PAGE_VIEW_LABEL = {
380
- ...LAYOUT_LABEL,
381
- dashboards: "Dashboards",
382
- archived: "Archived"
383
- };
384
293
  function viewFromRow(row) {
385
294
  const data = row.definition ?? {};
386
295
  const k = viewSettings(data, row.filters && Object.keys(row.filters).length > 0 ? row.filters : null);
@@ -450,6 +359,7 @@ async function readLooks(client, tableId) {
450
359
 
451
360
  // src/firstPage.ts
452
361
  var TABLE_PAGE_SIZE = 100;
362
+ var EMBEDDED_PAGE_SIZE = 50;
453
363
  function firstGridPageArgs(input) {
454
364
  const { shown, fields } = input;
455
365
  if (!shown) return null;
@@ -484,4 +394,42 @@ async function firstGridPageRequest(client, tableId, options = {}) {
484
394
  const shown = view ? applyLook(view, looks.data[view.id]) : null;
485
395
  return firstGridPageArgs({ tableId, table: table.data, fields: fields.data, shown, ...options.pageSize ? { pageSize: options.pageSize } : {} });
486
396
  }
397
+ async function askTablePageSeed(input) {
398
+ const recording = core.recordingDataSource(core.asRecordsDataSource(input.dataSource));
399
+ const client = core.createRecordsClient({
400
+ dataSource: recording.source,
401
+ organizationId: input.organizationId,
402
+ actor: input.actor,
403
+ onError: () => {
404
+ }
405
+ });
406
+ const record = input.recordId ? Promise.resolve(
407
+ recording.source.rpc("record_page_bundle", { p_organization_id: input.organizationId, p_record_id: input.recordId }, { schema: "custom" })
408
+ ).catch(() => null) : null;
409
+ try {
410
+ const pageSize = input.pageSize ?? (input.embedded ? EMBEDDED_PAGE_SIZE : TABLE_PAGE_SIZE);
411
+ const args = await firstGridPageRequest(client, input.tableId, { pageSize });
412
+ if (args && input.rows !== false) {
413
+ await client.listPage({
414
+ table_id: args.p_table_id,
415
+ filter: args.p_filter,
416
+ search: args.p_search,
417
+ sort: args.p_sort,
418
+ view_id: args.p_view_id,
419
+ limit: args.p_limit,
420
+ offset: args.p_offset
421
+ });
422
+ }
423
+ } catch {
424
+ }
425
+ if (record) await record;
426
+ return recording.seed();
427
+ }
428
+
429
+ exports.EMBEDDED_PAGE_SIZE = EMBEDDED_PAGE_SIZE;
430
+ exports.TABLE_PAGE_SIZE = TABLE_PAGE_SIZE;
431
+ exports.askTablePageSeed = askTablePageSeed;
432
+ exports.firstGridPageArgs = firstGridPageArgs;
433
+ exports.firstGridPageRequest = firstGridPageRequest;
434
+ //# sourceMappingURL=first-page.cjs.map
487
435
  //# sourceMappingURL=first-page.cjs.map