@svgrid/enterprise 3.1.23 → 3.1.25

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.
@@ -64741,7 +64741,7 @@ function g1(e) {
64741
64741
  }
64742
64742
  //#endregion
64743
64743
  //#region src/version.ts
64744
- var _1 = "3.1.23", v1 = "3.0.22", y1 = (e, t) => e.some((e) => e.config.kind === t), b1 = (e) => `activeTab_${e.replace(/[^a-zA-Z0-9_$]/g, "_")}`, x1 = (e, t) => `${e}-${t}`, S1 = (e) => `accOpen_${e.replace(/[^a-zA-Z0-9_$]/g, "_")}`, C1 = (e, t) => `${e}-s${t}`, w1 = (e) => `md_${e.replace(/[^a-zA-Z0-9]/g, "_")}_rows`;
64744
+ var _1 = "3.1.25", v1 = "3.0.22", y1 = (e, t) => e.some((e) => e.config.kind === t), b1 = (e) => `activeTab_${e.replace(/[^a-zA-Z0-9_$]/g, "_")}`, x1 = (e, t) => `${e}-${t}`, S1 = (e) => `accOpen_${e.replace(/[^a-zA-Z0-9_$]/g, "_")}`, C1 = (e, t) => `${e}-s${t}`, w1 = (e) => `md_${e.replace(/[^a-zA-Z0-9]/g, "_")}_rows`;
64745
64745
  function T1(e) {
64746
64746
  switch (e.type) {
64747
64747
  case "number": {
@@ -76261,7 +76261,7 @@ ${k}
76261
76261
  .st-home a { color: var(--sg-accent, #6366f1); font-weight: 600; }
76262
76262
  @keyframes st-home-spin { to { transform: rotate(360deg); } }
76263
76263
  </style>
76264
- `}}function M1(e){for(let t of e)MG(t);let t=new Map(e.map(e=>[e.name,e])),n=e.map(e=>{let n=c1(e,t);return{schema:l1(e,n),infos:n}});return{entries:n,seed:u1(n)}}function wre(e,t={}){let{entries:n,seed:r}=M1(e),{file:i,needs:a}=O1(n,r,t.sources,t.supabaseConn,t.serverMemory),o=[_re(n),i];(a.supabase||t.supabaseAuth)&&!a.supabaseUrl&&(t.supabaseConn?.url||t.supabaseConn?.key)&&(a.supabaseUrl=t.supabaseConn.url,a.supabaseKey=t.supabaseConn.key),(a.supabase||t.supabaseAuth)&&o.push(k1(a));for(let e of a.sqlRoutes)o.push(y1(e.schema,e.table,e.dialect,{access:t.accessEnabled,audit:t.auditEnabled,screenIds:t.screensByEntity?.get(e.schema.name)??[],triggers:t.triggers?.[e.schema.name],dbSchema:e.dbSchema,tenantField:t.tenantField&&t.tenantScoped?.(e.schema.name)!==!1?t.tenantField:void 0}));if(a.memoryRoutes.length){o.push(x1(a.memoryRoutes));for(let e of a.memoryRoutes)o.push(b1(e.schema,{access:t.accessEnabled,audit:t.auditEnabled,screenIds:t.screensByEntity?.get(e.schema.name)??[],triggers:t.triggers?.[e.schema.name],tenantField:t.tenantField&&t.tenantScoped?.(e.schema.name)!==!1?t.tenantField:void 0}))}return{files:o,prepared:n.map(e=>e.schema)}}var N1=`3.1.23`,P1=`3.0.22`,F1=(e,t)=>e.some(e=>e.config.kind===t),I1=e=>`activeTab_${e.replace(/[^a-zA-Z0-9_$]/g,`_`)}`,L1=(e,t)=>`${e}-${t}`,R1=e=>`accOpen_${e.replace(/[^a-zA-Z0-9_$]/g,`_`)}`,z1=(e,t)=>`${e}-s${t}`,B1=e=>`md_${e.replace(/[^a-zA-Z0-9]/g,`_`)}_rows`;function V1(e){switch(e.type){case`number`:{let t=e.decimals;return t==null?`{ type: 'number' }`:`{ type: 'number', options: { minimumFractionDigits: ${t}, maximumFractionDigits: ${t} } }`}case`currency`:return`{ type: 'currency', currency: ${$1(e.currency||`USD`)} }`;case`percent`:{let t=[`type: 'percent'`];return e.valueIsPercentPoints&&t.push(`valueIsPercentPoints: true`),e.decimals!=null&&t.push(`options: { minimumFractionDigits: ${e.decimals}, maximumFractionDigits: ${e.decimals} }`),`{ ${t.join(`, `)} }`}case`date`:case`datetime`:return e.pattern?`{ type: '${e.type}', pattern: ${$1(e.pattern)} }`:`{ type: '${e.type}' }`}}function H1(e,t,n,r){if(t.config.kind!==`grid`)return`schemaToColumns(${e})`;let i=t.config,a=t.id.replace(/-/g,`_`),o=i.columns.filter(e=>e.show),s=new Set(o.map(e=>e.field)),c=new Set,l=o.map(e=>{let t=r?.get(e.field);return{c:e,col:t&&!s.has(t)?t:e.field}}).filter(e=>!c.has(e.col)&&!!c.add(e.col)),u=i.editing===`inline`?``:`, editable: false`;if(l.length===0)return u?`schemaToColumns(${e}).map((c) => ({ ...c${u} }))`:`schemaToColumns(${e})`;let d=l.map(e=>`'${e.col}'`),f=l.map(({c:e,col:t})=>{let r=[];return e.header&&r.push(`header: ${JSON.stringify(e.header)}`),e.width!=null&&r.push(`width: ${e.width}`),e.align&&r.push(`align: '${e.align}'`),e.aggregate&&r.push(`aggregate: '${e.aggregate}'`),i.treeData&&e.field===i.treeData.labelField&&n?r.push(`cell: (ctx: CellContext<${n}>) => renderSnippet(treeCell_${a}, { value: ctx.getValue(), row: ctx.row.original })`):e.cellType&&n?r.push(`cell: (ctx: CellContext<${n}>) => renderSnippet(${d0(a,e.field)}, { value: ctx.getValue() })`):e.format&&r.push(`format: ${V1(e.format)}`),r.length?`'${t}': { ${r.join(`, `)} }`:null}).filter(e=>!!e),p=f.length?` const ov: Record<string, Partial<(typeof all)[number]>> = { ${f.join(`, `)} };`:``,m=f.length?`, ...(ov[String(c.field)] ?? {})`:``,h=`[${d.join(`, `)}].map((f) => all.find((c) => c.field === f)).filter((c): c is (typeof all)[number] => !!c)`;return`(() => { const all = schemaToColumns(${e});${p} return ${u||m?`${h}.map((c) => ({ ...c${u}${m} }))`:h} })()`}function U1(e,t){let n=[`grid-column: span ${uZ(e)}`,`min-width: 0`];t&&n.push(t);let r=fZ(e.style);return r&&n.push(r),`style="${n.join(`; `)}"`}var Tre=e=>e&&e.replace(/[^#a-zA-Z0-9(),.%\s_-]/g,``).slice(0,40)||`var(--sg-accent)`;function W1(e,t){let n=[t,lZ(e)].filter(Boolean).join(` `);return n?` class="${n}"`:``}function G1(e){let t=cZ(e.className);return t?` ${t}`:``}function Ere(e){let t=n$(e);if(t===`grid`){let t=BZ(e),n=t.maxWidth?` max-width: ${t.maxWidth}px; margin-inline: auto;`:``;return` .st-screen { grid-template-columns: repeat(12, 1fr); gap: ${t.rowGap}px ${t.colGap}px; align-items: ${t.align};${n} }\n @media (max-width: ${t.mobileBreakpoint}px) { .st-screen { grid-template-columns: 1fr; gap: 12px; } }\n`}if(t===`stack`){let t=VZ(e),n=t.maxWidth?` max-width: ${t.maxWidth}px;${t.align===`center`?` margin-inline: auto;`:``}`:``,r=t.minHeight?`\n .st-stack > * { min-height: ${t.minHeight}px; }`:``,i=t.dividers?`\n .st-stack > * + * { border-top: 1px solid var(--sg-border, #e2e8f0); padding-top: ${t.gap}px; }`:``;return` .st-stack { gap: ${t.gap}px;${n} }${r}${i}\n`}if(t===`canvas`){let t=WZ(e),n=t.showGrid?`\n .st-canvas { background-image: linear-gradient(var(--sg-border, #e6e8ec) 1px, transparent 1px), linear-gradient(90deg, var(--sg-border, #e6e8ec) 1px, transparent 1px); background-size: calc((100% - ${t.cols-1} * ${t.gap}px) / ${t.cols} + ${t.gap}px) calc(${t.rowHeight}px + ${t.gap}px); }`:``;return` .st-canvas { grid-template-columns: repeat(${t.cols}, 1fr); grid-auto-rows: ${t.rowHeight}px; gap: ${t.gap}px; }${n}\n`}return``}function K1(e,t,n,r,i,a={hasRecord:!1}){let o=(e,t)=>a.i18n?`{$t('block.${t}', ${JSON.stringify(e)})}`:e,s=a.pane?`style="height: 100%; min-width: 0; min-height: 0; display: flex; flex-direction: column;"`:U1(r),c=W1(r),l=r.config,u=a.handleNames?.get(r.id),d=u?`${u}.rows`:`allRows`;switch(l.kind){case`grid`:{let t=r.id.replace(/-/g,`_`),o=`columns_${t}`,u=`No ${(e.label??e.name).toLowerCase()} yet.`,d=Dre(l,t);if(l.scheduler){let t=s1(a.rawEntity??e,i);return` <div ${s}${c}>
76264
+ `}}function M1(e){for(let t of e)MG(t);let t=new Map(e.map(e=>[e.name,e])),n=e.map(e=>{let n=c1(e,t);return{schema:l1(e,n),infos:n}});return{entries:n,seed:u1(n)}}function wre(e,t={}){let{entries:n,seed:r}=M1(e),{file:i,needs:a}=O1(n,r,t.sources,t.supabaseConn,t.serverMemory),o=[_re(n),i];(a.supabase||t.supabaseAuth)&&!a.supabaseUrl&&(t.supabaseConn?.url||t.supabaseConn?.key)&&(a.supabaseUrl=t.supabaseConn.url,a.supabaseKey=t.supabaseConn.key),(a.supabase||t.supabaseAuth)&&o.push(k1(a));for(let e of a.sqlRoutes)o.push(y1(e.schema,e.table,e.dialect,{access:t.accessEnabled,audit:t.auditEnabled,screenIds:t.screensByEntity?.get(e.schema.name)??[],triggers:t.triggers?.[e.schema.name],dbSchema:e.dbSchema,tenantField:t.tenantField&&t.tenantScoped?.(e.schema.name)!==!1?t.tenantField:void 0}));if(a.memoryRoutes.length){o.push(x1(a.memoryRoutes));for(let e of a.memoryRoutes)o.push(b1(e.schema,{access:t.accessEnabled,audit:t.auditEnabled,screenIds:t.screensByEntity?.get(e.schema.name)??[],triggers:t.triggers?.[e.schema.name],tenantField:t.tenantField&&t.tenantScoped?.(e.schema.name)!==!1?t.tenantField:void 0}))}return{files:o,prepared:n.map(e=>e.schema)}}var N1=`3.1.25`,P1=`3.0.22`,F1=(e,t)=>e.some(e=>e.config.kind===t),I1=e=>`activeTab_${e.replace(/[^a-zA-Z0-9_$]/g,`_`)}`,L1=(e,t)=>`${e}-${t}`,R1=e=>`accOpen_${e.replace(/[^a-zA-Z0-9_$]/g,`_`)}`,z1=(e,t)=>`${e}-s${t}`,B1=e=>`md_${e.replace(/[^a-zA-Z0-9]/g,`_`)}_rows`;function V1(e){switch(e.type){case`number`:{let t=e.decimals;return t==null?`{ type: 'number' }`:`{ type: 'number', options: { minimumFractionDigits: ${t}, maximumFractionDigits: ${t} } }`}case`currency`:return`{ type: 'currency', currency: ${$1(e.currency||`USD`)} }`;case`percent`:{let t=[`type: 'percent'`];return e.valueIsPercentPoints&&t.push(`valueIsPercentPoints: true`),e.decimals!=null&&t.push(`options: { minimumFractionDigits: ${e.decimals}, maximumFractionDigits: ${e.decimals} }`),`{ ${t.join(`, `)} }`}case`date`:case`datetime`:return e.pattern?`{ type: '${e.type}', pattern: ${$1(e.pattern)} }`:`{ type: '${e.type}' }`}}function H1(e,t,n,r){if(t.config.kind!==`grid`)return`schemaToColumns(${e})`;let i=t.config,a=t.id.replace(/-/g,`_`),o=i.columns.filter(e=>e.show),s=new Set(o.map(e=>e.field)),c=new Set,l=o.map(e=>{let t=r?.get(e.field);return{c:e,col:t&&!s.has(t)?t:e.field}}).filter(e=>!c.has(e.col)&&!!c.add(e.col)),u=i.editing===`inline`?``:`, editable: false`;if(l.length===0)return u?`schemaToColumns(${e}).map((c) => ({ ...c${u} }))`:`schemaToColumns(${e})`;let d=l.map(e=>`'${e.col}'`),f=l.map(({c:e,col:t})=>{let r=[];return e.header&&r.push(`header: ${JSON.stringify(e.header)}`),e.width!=null&&r.push(`width: ${e.width}`),e.align&&r.push(`align: '${e.align}'`),e.aggregate&&r.push(`aggregate: '${e.aggregate}'`),i.treeData&&e.field===i.treeData.labelField&&n?r.push(`cell: (ctx: CellContext<${n}>) => renderSnippet(treeCell_${a}, { value: ctx.getValue(), row: ctx.row.original })`):e.cellType&&n?r.push(`cell: (ctx: CellContext<${n}>) => renderSnippet(${d0(a,e.field)}, { value: ctx.getValue() })`):e.format&&r.push(`format: ${V1(e.format)}`),r.length?`'${t}': { ${r.join(`, `)} }`:null}).filter(e=>!!e),p=f.length?` const ov: Record<string, Partial<(typeof all)[number]>> = { ${f.join(`, `)} };`:``,m=f.length?`, ...(ov[String(c.field)] ?? {})`:``,h=`[${d.join(`, `)}].map((f) => all.find((c) => c.field === f)).filter((c): c is (typeof all)[number] => !!c)`;return`(() => { const all = schemaToColumns(${e});${p} return ${u||m?`${h}.map((c) => ({ ...c${u}${m} }))`:h} })()`}function U1(e,t){let n=[`grid-column: span ${uZ(e)}`,`min-width: 0`];t&&n.push(t);let r=fZ(e.style);return r&&n.push(r),`style="${n.join(`; `)}"`}var Tre=e=>e&&e.replace(/[^#a-zA-Z0-9(),.%\s_-]/g,``).slice(0,40)||`var(--sg-accent)`;function W1(e,t){let n=[t,lZ(e)].filter(Boolean).join(` `);return n?` class="${n}"`:``}function G1(e){let t=cZ(e.className);return t?` ${t}`:``}function Ere(e){let t=n$(e);if(t===`grid`){let t=BZ(e),n=t.maxWidth?` max-width: ${t.maxWidth}px; margin-inline: auto;`:``;return` .st-screen { grid-template-columns: repeat(12, 1fr); gap: ${t.rowGap}px ${t.colGap}px; align-items: ${t.align};${n} }\n @media (max-width: ${t.mobileBreakpoint}px) { .st-screen { grid-template-columns: 1fr; gap: 12px; } }\n`}if(t===`stack`){let t=VZ(e),n=t.maxWidth?` max-width: ${t.maxWidth}px;${t.align===`center`?` margin-inline: auto;`:``}`:``,r=t.minHeight?`\n .st-stack > * { min-height: ${t.minHeight}px; }`:``,i=t.dividers?`\n .st-stack > * + * { border-top: 1px solid var(--sg-border, #e2e8f0); padding-top: ${t.gap}px; }`:``;return` .st-stack { gap: ${t.gap}px;${n} }${r}${i}\n`}if(t===`canvas`){let t=WZ(e),n=t.showGrid?`\n .st-canvas { background-image: linear-gradient(var(--sg-border, #e6e8ec) 1px, transparent 1px), linear-gradient(90deg, var(--sg-border, #e6e8ec) 1px, transparent 1px); background-size: calc((100% - ${t.cols-1} * ${t.gap}px) / ${t.cols} + ${t.gap}px) calc(${t.rowHeight}px + ${t.gap}px); }`:``;return` .st-canvas { grid-template-columns: repeat(${t.cols}, 1fr); grid-auto-rows: ${t.rowHeight}px; gap: ${t.gap}px; }${n}\n`}return``}function K1(e,t,n,r,i,a={hasRecord:!1}){let o=(e,t)=>a.i18n?`{$t('block.${t}', ${JSON.stringify(e)})}`:e,s=a.pane?`style="height: 100%; min-width: 0; min-height: 0; display: flex; flex-direction: column;"`:U1(r),c=W1(r),l=r.config,u=a.handleNames?.get(r.id),d=u?`${u}.rows`:`allRows`;switch(l.kind){case`grid`:{let t=r.id.replace(/-/g,`_`),o=`columns_${t}`,u=`No ${(e.label??e.name).toLowerCase()} yet.`,d=Dre(l,t);if(l.scheduler){let t=s1(a.rawEntity??e,i);return` <div ${s}${c}>
76265
76265
  ${d.decls} <SvGrid
76266
76266
  data={allRows}
76267
76267
  columns={${o}}
@@ -4,7 +4,7 @@
4
4
  <meta charset="UTF-8" />
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
6
  <title>SvGrid Studio - Designer</title>
7
- <script type="module" crossorigin src="./assets/index-CIxqRzKJ.js"></script>
7
+ <script type="module" crossorigin src="./assets/index-UhFdGGXv.js"></script>
8
8
  <link rel="modulepreload" crossorigin href="./assets/rolldown-runtime-Dd_uD5pT.js">
9
9
  <link rel="modulepreload" crossorigin href="./assets/disclose-version-CIm4S9xS.js">
10
10
  <link rel="modulepreload" crossorigin href="./assets/cell-formatting-JoxA0t65.js">
package/dist/export.d.ts CHANGED
@@ -304,6 +304,13 @@ export declare function buildLinkResolver<TData extends RowData>(cols: ReadonlyA
304
304
  * the numeric / currency columns. Values use the same formatting as the grid.
305
305
  */
306
306
  export declare function buildGroupedPdfBody<TData extends RowData>(cols: ReadonlyArray<ExportColumn<TData>>, rows: ReadonlyArray<TData>, groupBy: ReadonlyArray<string>): PdfBodyRow[];
307
+ /**
308
+ * Export a grid's rows to a file: xlsx, xls, pdf, csv, tsv, html, json, xml
309
+ * or md, picked by `opts.format`. It reads the columns and rows through the
310
+ * grid api, so sorting, filtering and grouping carry over, and downloads the
311
+ * file unless `opts.download` is false. Resolves with the file (`ExportResult`)
312
+ * on the paths that build it in memory, undefined on the others.
313
+ */
307
314
  export declare function exportGrid<TFeatures extends TableFeatures, TData extends RowData>(api: SvGridApi<TFeatures, TData>, opts: ExportOptions<TData>): Promise<ExportResult | undefined>;
308
315
  /** Native formats that can be placed on the clipboard. */
309
316
  export type ClipboardFormat = 'csv' | 'tsv' | 'html' | 'json' | 'xml' | 'md';
package/dist/export.js CHANGED
@@ -833,6 +833,13 @@ async function exportXlsxNative(api, opts) {
833
833
  opts.onProgress?.({ phase: 'write', ratio: 1, total: src.length });
834
834
  return deliver(blob, ensureExt(filename, 'xlsx'), 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', src.length, opts.download);
835
835
  }
836
+ /**
837
+ * Export a grid's rows to a file: xlsx, xls, pdf, csv, tsv, html, json, xml
838
+ * or md, picked by `opts.format`. It reads the columns and rows through the
839
+ * grid api, so sorting, filtering and grouping carry over, and downloads the
840
+ * file unless `opts.download` is false. Resolves with the file (`ExportResult`)
841
+ * on the paths that build it in memory, undefined on the others.
842
+ */
836
843
  export async function exportGrid(api, opts) {
837
844
  assertEnterpriseLicensed('Export');
838
845
  // Native text formats have their own dependency-free, streaming path.
@@ -16506,7 +16506,7 @@ function hasFieldConditions(schema) {
16506
16506
  *
16507
16507
  * `version.test.ts` asserts this matches `package.json`, so the two cannot drift.
16508
16508
  */
16509
- var SVGRID_VERSION = "3.1.23";
16509
+ var SVGRID_VERSION = "3.1.25";
16510
16510
  /**
16511
16511
  * The version of `@svgrid/grid`, which releases on its own line: enterprise is
16512
16512
  * on 3.1.x while the grid is on 3.0.x.
@@ -12,6 +12,10 @@ import { type AIClassifyOptions, type AIClassifyResult, type AISmartFillOptions,
12
12
  import type { ReviewGridApi } from './model.svelte.js';
13
13
  import type { ProposalInput, ProposalSource } from './types.js';
14
14
  type RowIdApi = Pick<ReviewGridApi, 'getOption'>;
15
+ /**
16
+ * A change set built from another tool's output, ready for `review.add`, with
17
+ * a count of the predictions that could not become proposals.
18
+ */
15
19
  export type AdapterResult = {
16
20
  source: ProposalSource;
17
21
  title: string;
@@ -21,11 +25,19 @@ export type AdapterResult = {
21
25
  };
22
26
  /** Blank cells of `field`: what `aiSmartFill` targets when given no indices. */
23
27
  export declare const blankTargets: (snapshot: ReadonlyArray<unknown>, field: string) => number[];
28
+ /**
29
+ * Proposals from an `aiSmartFill` result, its row indices resolved to row ids
30
+ * through the snapshot the call ran on.
31
+ */
24
32
  export declare function fromSmartFill<TData>(result: AISmartFillResult, snapshot: ReadonlyArray<TData>, opts: {
25
33
  api: RowIdApi;
26
34
  targets?: ReadonlyArray<number>;
27
35
  source?: ProposalSource;
28
36
  }): AdapterResult;
37
+ /**
38
+ * Proposals from an `aiClassify` result, its row indices resolved to row ids
39
+ * through the snapshot the call ran on.
40
+ */
29
41
  export declare function fromClassify<TData>(result: AIClassifyResult, snapshot: ReadonlyArray<TData>, opts: {
30
42
  api: RowIdApi;
31
43
  targets?: ReadonlyArray<number>;
@@ -39,12 +39,20 @@ function fromPredictions(predictions, field, snapshot, targets, api, reason) {
39
39
  }
40
40
  /** Blank cells of `field`: what `aiSmartFill` targets when given no indices. */
41
41
  export const blankTargets = (snapshot, field) => snapshot.flatMap((row, i) => (isBlank(row[field]) ? [i] : []));
42
+ /**
43
+ * Proposals from an `aiSmartFill` result, its row indices resolved to row ids
44
+ * through the snapshot the call ran on.
45
+ */
42
46
  export function fromSmartFill(result, snapshot, opts) {
43
47
  const targets = opts.targets ?? blankTargets(snapshot, result.field);
44
48
  const { proposals, dropped } = fromPredictions(result.predictions, result.field, snapshot, targets, opts.api, result.rationale || undefined);
45
49
  const source = opts.source ?? { kind: 'ai', id: `smart-fill:${result.field}`, label: 'Smart fill' };
46
50
  return { source, title: `Smart fill: ${result.field}`, proposals, dropped };
47
51
  }
52
+ /**
53
+ * Proposals from an `aiClassify` result, its row indices resolved to row ids
54
+ * through the snapshot the call ran on.
55
+ */
48
56
  export function fromClassify(result, snapshot, opts) {
49
57
  const targets = opts.targets ?? snapshot.map((_, i) => i);
50
58
  const { proposals, dropped } = fromPredictions(result.predictions, result.outputField, snapshot, targets, opts.api, `classified from ${result.inputField}`);
@@ -1,5 +1,9 @@
1
1
  import type { ReviewGridApi } from './model.svelte.js';
2
2
  import type { Proposal, ProposalGroup, ProposalInput, ProposalSource } from './types.js';
3
+ /**
4
+ * One agent tool in the shape tool-use loops take: a name, a description, a
5
+ * JSON Schema for its input, and `execute`.
6
+ */
3
7
  export type GridTool = {
4
8
  name: string;
5
9
  description: string;
@@ -21,6 +25,10 @@ type ToolReview = {
21
25
  proposals(): Proposal[];
22
26
  };
23
27
  type ToolApi = Pick<ReviewGridApi, 'getData' | 'getColumns' | 'getOption'>;
28
+ /**
29
+ * Options for `createGridTools`: the review edits are proposed into, the grid
30
+ * api, and the fields the agent may edit.
31
+ */
24
32
  export type GridToolsOptions = {
25
33
  review: ToolReview;
26
34
  /** The grid api, or a getter for it. */
@@ -36,6 +44,11 @@ export type GridToolsOptions = {
36
44
  /** Most edits one grid_propose_edits call may carry. Default 500. */
37
45
  maxEdits?: number;
38
46
  };
47
+ /**
48
+ * The tools an agent edits a grid through: `grid_describe`, `grid_query_rows`,
49
+ * `grid_propose_edits` and `grid_review_status`. None of them writes the data:
50
+ * edits arrive in the review as proposals for a person to accept.
51
+ */
39
52
  export declare function createGridTools(opts: GridToolsOptions): GridTool[];
40
53
  /**
41
54
  * Register tools with the browser's WebMCP API, so an agent driving the page
@@ -43,6 +43,11 @@ function wrongType(type, current, value) {
43
43
  return 'expects a date (YYYY-MM-DD)';
44
44
  return null;
45
45
  }
46
+ /**
47
+ * The tools an agent edits a grid through: `grid_describe`, `grid_query_rows`,
48
+ * `grid_propose_edits` and `grid_review_status`. None of them writes the data:
49
+ * edits arrive in the review as proposals for a person to accept.
50
+ */
46
51
  export function createGridTools(opts) {
47
52
  const prefix = opts.prefix ?? 'grid_';
48
53
  const source = opts.source ?? { kind: 'agent', id: 'agent', label: 'Agent' };
@@ -1,5 +1,10 @@
1
1
  import { type ReviewMessages } from './messages.js';
2
2
  import type { Proposal, ProposalGroup } from './types.js';
3
+ /**
4
+ * How `clusterProposals` labels and splits groups: field labels, the size a
5
+ * scale group needs, the confidence below which a proposal counts as unsure,
6
+ * and the wording.
7
+ */
3
8
  export type ClusterOptions = {
4
9
  /** Wording of the group labels (the `label*`, `case*`, `punct*` keys); English by default. */
5
10
  messages?: Partial<ReviewMessages>;
@@ -10,12 +15,21 @@ export type ClusterOptions = {
10
15
  /** Below this, a judgment group sorts with the risky ones. Default 0.6. */
11
16
  lowConfidence?: number;
12
17
  };
18
+ /**
19
+ * Group proposals by the change they make (trim, case, reformat, scale, one
20
+ * mapping, fill empty, one target, no pattern), the groups that need a person
21
+ * first. What the panel lists.
22
+ */
13
23
  export declare function clusterProposals(proposals: ReadonlyArray<Proposal>, opts?: ClusterOptions): ProposalGroup[];
14
- /** A key that tells values apart by type as well as content. */
24
+ /**
25
+ * A key that tells values apart by type as well as content.
26
+ * @internal
27
+ */
15
28
  export declare function keyOf(v: unknown): string;
16
29
  /**
17
30
  * Spaces a reader cannot see, drawn as `·`: leading and trailing ones and runs
18
31
  * of two or more. A trim proposal otherwise reads "Acme -> Acme".
32
+ * @internal
19
33
  */
20
34
  export declare function visibleSpaces(s: string): string;
21
35
  /**
@@ -28,6 +28,11 @@ import { isBlank } from './equal.js';
28
28
  import { fill, reviewMessages } from './messages.js';
29
29
  const RULE_KINDS = new Set(['whitespace', 'case', 'format', 'scale']);
30
30
  const SEP = '\u0001';
31
+ /**
32
+ * Group proposals by the change they make (trim, case, reformat, scale, one
33
+ * mapping, fill empty, one target, no pattern), the groups that need a person
34
+ * first. What the panel lists.
35
+ */
31
36
  export function clusterProposals(proposals, opts = {}) {
32
37
  const fieldLabel = opts.fieldLabel ?? ((f) => f);
33
38
  const msg = reviewMessages(opts.messages);
@@ -241,7 +246,10 @@ function valid(y, mo, d) {
241
246
  }
242
247
  const ymd = (y, m, d) => `${y}-${String(m).padStart(2, '0')}-${String(d).padStart(2, '0')}`;
243
248
  // ---- grouping helpers -----------------------------------------------------
244
- /** A key that tells values apart by type as well as content. */
249
+ /**
250
+ * A key that tells values apart by type as well as content.
251
+ * @internal
252
+ */
245
253
  export function keyOf(v) {
246
254
  if (v instanceof Date)
247
255
  return 'd:' + v.getTime();
@@ -307,6 +315,7 @@ function rankOf(g, low) {
307
315
  /**
308
316
  * Spaces a reader cannot see, drawn as `·`: leading and trailing ones and runs
309
317
  * of two or more. A trim proposal otherwise reads "Acme -> Acme".
318
+ * @internal
310
319
  */
311
320
  export function visibleSpaces(s) {
312
321
  return s.replace(/^\s+|\s+$/g, (m) => '·'.repeat(m.length)).replace(/ {2,}/g, (m) => '·'.repeat(m.length));
@@ -5,5 +5,10 @@
5
5
  * the same rule Base sync uses (`fields/base-sync.ts`), so a cell cleared to
6
6
  * '' does not make a proposal made against `null` look stale.
7
7
  */
8
+ /** Whether a cell value is blank: null, undefined or the empty string. */
8
9
  export declare const isBlank: (v: unknown) => boolean;
10
+ /**
11
+ * Whether two cell values are the same for a review: `Object.is`, Dates by
12
+ * time, arrays and plain objects by structure, and any two blanks.
13
+ */
9
14
  export declare function sameValue(a: unknown, b: unknown): boolean;
@@ -5,7 +5,12 @@
5
5
  * the same rule Base sync uses (`fields/base-sync.ts`), so a cell cleared to
6
6
  * '' does not make a proposal made against `null` look stale.
7
7
  */
8
+ /** Whether a cell value is blank: null, undefined or the empty string. */
8
9
  export const isBlank = (v) => v == null || v === '';
10
+ /**
11
+ * Whether two cell values are the same for a review: `Object.is`, Dates by
12
+ * time, arrays and plain objects by structure, and any two blanks.
13
+ */
9
14
  export function sameValue(a, b) {
10
15
  if (Object.is(a, b))
11
16
  return true;
@@ -12,7 +12,10 @@ import type { Proposal } from './types.js';
12
12
  * selection and focus.
13
13
  */
14
14
  export declare const PENDING_BG = "var(--sg-review-pending-bg, color-mix(in srgb, var(--sg-warning, #d97706) 13%, transparent))";
15
- /** The row "Show in grid" lands on, for a moment: a stronger wash of the same amber. */
15
+ /**
16
+ * The row "Show in grid" lands on, for a moment: a stronger wash of the same amber.
17
+ * @internal
18
+ */
16
19
  export declare const FLASH_BG = "var(--sg-review-flash-bg, color-mix(in srgb, var(--sg-warning, #d97706) 32%, transparent))";
17
20
  /** Drawn before the value, so a pending cell is never marked by colour alone. */
18
21
  export declare const PENDING_ICON = "\u2022";
@@ -21,7 +24,15 @@ export declare const PENDING_ICON = "\u2022";
21
24
  * a "!" before the value, so the grid shows where the panel's conflicts are.
22
25
  */
23
26
  export declare const CONFLICT_BG = "var(--sg-review-conflict-bg, color-mix(in srgb, var(--sg-danger, #dc2626) 12%, transparent))";
27
+ /**
28
+ * Drawn before the value of a cell two sources disagree on.
29
+ */
24
30
  export declare const CONFLICT_ICON = "!";
31
+ /**
32
+ * `conditionalFormats` rules that tint the cells of the given proposals, one
33
+ * rule per field, scoped to that field's columns. `review.formats` is built
34
+ * from it.
35
+ */
25
36
  export declare function pendingFormats<TData>(pending: ReadonlyArray<Proposal>, rowId: (row: TData, index: number) => string, columns: ReadonlyArray<{
26
37
  id: string;
27
38
  field?: string;
@@ -4,7 +4,10 @@
4
4
  * selection and focus.
5
5
  */
6
6
  export const PENDING_BG = 'var(--sg-review-pending-bg, color-mix(in srgb, var(--sg-warning, #d97706) 13%, transparent))';
7
- /** The row "Show in grid" lands on, for a moment: a stronger wash of the same amber. */
7
+ /**
8
+ * The row "Show in grid" lands on, for a moment: a stronger wash of the same amber.
9
+ * @internal
10
+ */
8
11
  export const FLASH_BG = 'var(--sg-review-flash-bg, color-mix(in srgb, var(--sg-warning, #d97706) 32%, transparent))';
9
12
  /** Drawn before the value, so a pending cell is never marked by colour alone. */
10
13
  export const PENDING_ICON = '•';
@@ -13,7 +16,15 @@ export const PENDING_ICON = '•';
13
16
  * a "!" before the value, so the grid shows where the panel's conflicts are.
14
17
  */
15
18
  export const CONFLICT_BG = 'var(--sg-review-conflict-bg, color-mix(in srgb, var(--sg-danger, #dc2626) 12%, transparent))';
19
+ /**
20
+ * Drawn before the value of a cell two sources disagree on.
21
+ */
16
22
  export const CONFLICT_ICON = '!';
23
+ /**
24
+ * `conditionalFormats` rules that tint the cells of the given proposals, one
25
+ * rule per field, scoped to that field's columns. `review.formats` is built
26
+ * from it.
27
+ */
17
28
  export function pendingFormats(pending, rowId, columns, look = { background: PENDING_BG, icon: PENDING_ICON }) {
18
29
  const rowsByField = new Map();
19
30
  for (const p of pending) {
@@ -12,6 +12,7 @@ export declare function canGhost(raw: any, sample?: unknown, columns?: ReadonlyA
12
12
  /**
13
13
  * Wrap the `cell` of every ghostable column whose field has a pending
14
14
  * proposal. Returns the same array when nothing needs wrapping.
15
+ * @internal
15
16
  */
16
17
  export declare function wrapColumns<C extends ReadonlyArray<any>>(cols: C, fields: ReadonlySet<string>, review: Ghostable, sample?: (field: string) => unknown): C;
17
18
  export {};
@@ -46,6 +46,7 @@ export function canGhost(raw, sample, columns = []) {
46
46
  /**
47
47
  * Wrap the `cell` of every ghostable column whose field has a pending
48
48
  * proposal. Returns the same array when nothing needs wrapping.
49
+ * @internal
49
50
  */
50
51
  export function wrapColumns(cols, fields, review, sample = () => undefined) {
51
52
  if (!fields.size)
@@ -106,8 +106,17 @@ export declare const REVIEW_MESSAGES: {
106
106
  labelConstant: string;
107
107
  labelUnpatterned: string;
108
108
  };
109
+ /**
110
+ * Every string the review shows, with the keys of `REVIEW_MESSAGES`.
111
+ */
109
112
  export type ReviewMessages = typeof REVIEW_MESSAGES;
110
- /** English, with `overrides` laid over it (blank values ignored). */
113
+ /**
114
+ * English, with `overrides` laid over it (blank values ignored).
115
+ * @internal
116
+ */
111
117
  export declare function reviewMessages(...overrides: Array<Partial<ReviewMessages> | null | undefined>): ReviewMessages;
112
- /** A template with its `{name}` placeholders filled. */
118
+ /**
119
+ * A template with its `{name}` placeholders filled.
120
+ * @internal
121
+ */
113
122
  export declare function fill(template: string, vars: Record<string, string | number>): string;
@@ -115,7 +115,10 @@ export const REVIEW_MESSAGES = {
115
115
  labelConstant: 'Set {field} to {value}',
116
116
  labelUnpatterned: '{field}: no shared pattern',
117
117
  };
118
- /** English, with `overrides` laid over it (blank values ignored). */
118
+ /**
119
+ * English, with `overrides` laid over it (blank values ignored).
120
+ * @internal
121
+ */
119
122
  export function reviewMessages(...overrides) {
120
123
  const out = { ...REVIEW_MESSAGES };
121
124
  for (const o of overrides) {
@@ -129,7 +132,10 @@ export function reviewMessages(...overrides) {
129
132
  }
130
133
  return out;
131
134
  }
132
- /** A template with its `{name}` placeholders filled. */
135
+ /**
136
+ * A template with its `{name}` placeholders filled.
137
+ * @internal
138
+ */
133
139
  export function fill(template, vars) {
134
140
  return template.replace(/\{(\w+)\}/g, (whole, key) => (key in vars ? String(vars[key]) : whole));
135
141
  }
@@ -29,6 +29,11 @@ import { type ReviewMessages } from './messages.js';
29
29
  import type { ChangeSet, Proposal, ProposalGroup, ProposalInput, ProposalSource } from './types.js';
30
30
  /** The part of the grid api a review uses. Any `SvGridApi` satisfies it. */
31
31
  export type ReviewGridApi = Pick<SvGridApi<any, any>, 'getData' | 'getOption' | 'getActiveCell' | 'getRowId' | 'getColumns' | 'getCommandContext' | 'stopEditing' | 'scrollToRow' | 'getDisplayedRows' | 'getAdvancedFilter' | 'setAdvancedFilter' | 'getRowPosition' | 'getPageInfo' | 'setPage' | 'getState'>;
32
+ /**
33
+ * Options for `createReview`: the grid it reviews, how accepted values are
34
+ * written (`setRows`, or `server` with `onCommit`), and what to call as
35
+ * decisions are made.
36
+ */
32
37
  export type ReviewOptions<TData> = {
33
38
  /** The grid api, or a getter for it (it is bound after mount). */
34
39
  api: ReviewGridApi | (() => ReviewGridApi | undefined | null);
@@ -74,6 +79,10 @@ export type ReviewOptions<TData> = {
74
79
  */
75
80
  rowLabel?: (row: TData) => string | null | undefined;
76
81
  };
82
+ /**
83
+ * One decision, its undo or its redo, as `onDecision` receives it, with copies
84
+ * of the proposals it moved. Write these to an audit log.
85
+ */
77
86
  export type ReviewDecision = {
78
87
  action: 'accept' | 'reject' | 'undo' | 'redo';
79
88
  /** For undo / redo: which decision was undone or redone. */
@@ -82,6 +91,11 @@ export type ReviewDecision = {
82
91
  by?: string;
83
92
  at: number;
84
93
  };
94
+ /**
95
+ * What an accept or a reject did, by proposal id: accepted, rejected, stale
96
+ * (the cell changed before the write), committed and then found stale, or
97
+ * skipped; and what `onCommit` threw, if it did.
98
+ */
85
99
  export type ReviewOutcome = {
86
100
  accepted: string[];
87
101
  rejected: string[];
@@ -98,165 +112,108 @@ export type ReviewOutcome = {
98
112
  /** What `onCommit` threw; nothing was written and the proposals stay pending. */
99
113
  error?: unknown;
100
114
  };
115
+ /**
116
+ * A change set for `review.add`: where it came from, an optional title and
117
+ * id, and its proposals.
118
+ */
101
119
  export type AddInput = {
102
120
  source: ProposalSource;
103
121
  title?: string;
104
122
  id?: string;
105
123
  proposals: ReadonlyArray<ProposalInput>;
106
124
  };
125
+ /**
126
+ * A review's change sets as `review.toJSON()` writes them and `review.load` /
127
+ * `review.merge` read them, to route a review to an approver.
128
+ */
107
129
  export type ReviewJSON = {
108
130
  v: 1;
109
131
  sets: ChangeSet[];
110
132
  };
111
- export type Review<TData = unknown> = ReturnType<typeof createReview<TData>>;
112
- export declare function createReview<TData = unknown>(opts: ReviewOptions<TData>): {
133
+ /**
134
+ * What `createReview` returns: the proposals, their groups, the decisions,
135
+ * and what the grid takes (`columns`, `formats`). Every read is reactive.
136
+ */
137
+ export interface Review<TData = unknown> {
138
+ /** Bumped on every change, for code that caches what it reads. */
113
139
  readonly version: number;
114
140
  /** The wording in effect: English with `messages` laid over it. */
115
- messages: {
116
- title: string;
117
- decided: string;
118
- pendingInGroups: string;
119
- pendingInOneGroup: string;
120
- nothingPending: string;
121
- inConflict: string;
122
- acceptAll: string;
123
- rejectAll: string;
124
- acceptRuleGroups: string;
125
- resolveFirst: string;
126
- onlyRowsWithChanges: string;
127
- confirmAcceptGroup: string;
128
- confirmRejectGroup: string;
129
- confirmAcceptAll: string;
130
- confirmRejectAll: string;
131
- confirmAcceptRules: string;
132
- confirmYes: string;
133
- cancel: string;
134
- conflictsTitle: string;
135
- conflictCell: string;
136
- keep: string;
137
- badgeRule: string;
138
- hintRule: string;
139
- hintMapping: string;
140
- hintFill: string;
141
- hintConstant: string;
142
- hintEach: string;
143
- oneChange: string;
144
- changes: string;
145
- sure: string;
146
- sureRange: string;
147
- accept: string;
148
- reject: string;
149
- acceptGroupLabel: string;
150
- rejectGroupLabel: string;
151
- from: string;
152
- otherValues: string;
153
- sampleOf: string;
154
- everyChange: string;
155
- firstN: string;
156
- showRow: string;
157
- rowId: string;
158
- acceptOne: string;
159
- rejectOne: string;
160
- showAll: string;
161
- keysHint: string;
162
- showInGrid: string;
163
- nextInGrid: string;
164
- hiddenRows: string;
165
- allReviewed: string;
166
- reviewedSummary: string;
167
- reviewedStale: string;
168
- noProposals: string;
169
- noProposalsHint: string;
170
- notWritten: string;
171
- rowField: string;
172
- decidedLabel: string;
173
- noteCellChanged: string;
174
- noteRowGone: string;
175
- noteRowEditing: string;
176
- noteGridNotReady: string;
177
- noteSavedStale: string;
178
- noteConflict: string;
179
- undoHint: string;
180
- announceAccepted: string;
181
- announceRejected: string;
182
- announceStale: string;
183
- announceSkipped: string;
184
- announceCommittedStale: string;
185
- announceNotSaved: string;
186
- announceNothing: string;
187
- undoFailed: string;
188
- redoFailed: string;
189
- cardProposed: string;
190
- proposes: string;
191
- nowValue: string;
192
- empty: string;
193
- labelWhitespace: string;
194
- labelCase: string;
195
- caseUpper: string;
196
- caseLower: string;
197
- caseTitle: string;
198
- caseMixed: string;
199
- labelToNumber: string;
200
- labelDates: string;
201
- datesAsDates: string;
202
- labelShape: string;
203
- labelPunct: string;
204
- punctRemove: string;
205
- punctAdd: string;
206
- punctSpaces: string;
207
- labelDivide: string;
208
- labelMultiply: string;
209
- labelMapping: string;
210
- mappingValues: string;
211
- labelFill: string;
212
- labelFillVarious: string;
213
- labelConstant: string;
214
- labelUnpatterned: string;
215
- };
141
+ readonly messages: ReviewMessages;
216
142
  /** The last undo or redo whose save failed, or null. */
217
143
  readonly lastError: {
218
144
  error: unknown;
219
- during: "undo" | "redo";
145
+ during: 'undo' | 'redo';
220
146
  at: number;
221
147
  } | null;
222
- add: (input: AddInput) => ChangeSet;
223
- get: (id: string) => Proposal | undefined;
224
- proposals: () => Proposal[];
225
- /** What names the proposal's row (`rowLabel`), or null. */
226
- rowLabel: (p: Proposal) => string | null;
148
+ /** Add a change set; a cell that already has a live proposal from another source becomes a conflict. */
149
+ add(input: AddInput): ChangeSet;
150
+ /** One proposal by id. */
151
+ get(id: string): Proposal | undefined;
152
+ /** Every proposal of the session, whatever its status. */
153
+ proposals(): Proposal[];
154
+ /** What names a proposal's row (`rowLabel`), or null. */
155
+ rowLabel(p: Proposal): string | null;
227
156
  /** A field's column header, as the group labels show it. */
228
- fieldLabel: (field: string) => string;
229
- pending: () => Proposal[];
230
- conflicts: () => Proposal[];
231
- groups: () => ProposalGroup[];
232
- pendingFor: (rowId: string, field: string) => Proposal | undefined;
233
- accept: (ids: ReadonlyArray<string>) => Promise<ReviewOutcome>;
234
- reject: (ids: ReadonlyArray<string>) => ReviewOutcome;
235
- acceptGroup: (key: string, shownIds: ReadonlyArray<string>) => Promise<ReviewOutcome>;
236
- rejectGroup: (key: string, shownIds: ReadonlyArray<string>) => ReviewOutcome;
237
- resolveConflict: (keepId: string) => void;
157
+ fieldLabel(field: string): string;
158
+ /** The proposals waiting for a decision. */
159
+ pending(): Proposal[];
160
+ /** The proposals two sources disagree on, to settle with `resolveConflict`. */
161
+ conflicts(): Proposal[];
162
+ /** The pending proposals grouped by the change they make, the groups that need a person first. */
163
+ groups(): ProposalGroup[];
164
+ /** The pending proposal for one cell, if there is one. */
165
+ pendingFor(rowId: string, field: string): Proposal | undefined;
166
+ /** Write these proposals: checks each cell still holds `before`, before and after `onCommit`. One undo step. */
167
+ accept(ids: ReadonlyArray<string>): Promise<ReviewOutcome>;
168
+ /** Decide against these proposals; nothing is written. One undo step. */
169
+ reject(ids: ReadonlyArray<string>): ReviewOutcome;
170
+ /** Accept a group, limited to the ids the person was shown, so a proposal added since is not decided unseen. */
171
+ acceptGroup(key: string, shownIds: ReadonlyArray<string>): Promise<ReviewOutcome>;
172
+ /** Reject a group, limited to the ids the person was shown. */
173
+ rejectGroup(key: string, shownIds: ReadonlyArray<string>): ReviewOutcome;
174
+ /** Keep one of a cell's conflicting proposals (it becomes pending) and reject the rest, as one undo step. */
175
+ resolveConflict(keepId: string): void;
176
+ /** `conditionalFormats` for the grid: pending cells tinted, conflicting cells marked, the row "Show in grid" lands on lit. */
238
177
  readonly formats: ConditionalFormat<any>[];
239
- columns: <C extends ReadonlyArray<any>>(cols: C) => C;
240
- reveal: (ids: ReadonlyArray<string>, fromId?: string) => {
178
+ /** The grid's columns with the proposed value drawn in each pending cell. */
179
+ columns<C extends ReadonlyArray<any>>(cols: C): C;
180
+ /** Show the next proposal of `ids` after `fromId` in the grid, on whatever page it is. */
181
+ reveal(ids: ReadonlyArray<string>, fromId?: string): {
241
182
  id: string | null;
242
183
  hidden: number;
243
184
  };
244
- showPendingOnly: (on: boolean) => void;
245
- /** On while our condition is in the grid's advanced filter (the grid's own Clear takes it out too). */
185
+ /** Show only rows with a pending or conflicting proposal, on top of the user's own filters. */
186
+ showPendingOnly(on: boolean): void;
187
+ /** Whether `showPendingOnly` is on (the grid's own Clear turns it off too). */
246
188
  readonly pendingOnly: boolean;
247
- toJSON: (opts?: {
189
+ /** Every set with its proposals and their status, as plain JSON; `setIds` exports only some. */
190
+ toJSON(opts?: {
248
191
  setIds?: ReadonlyArray<string>;
249
- }) => ReviewJSON;
250
- load: (json: ReviewJSON) => {
192
+ }): ReviewJSON;
193
+ /** Replace everything with an export; returns how many malformed proposals were dropped. */
194
+ load(json: ReviewJSON): {
251
195
  dropped: number;
252
196
  };
253
- merge: (json: ReviewJSON) => {
197
+ /** Add the sets of an export, keeping what is here; returns how many were dropped. */
198
+ merge(json: ReviewJSON): {
254
199
  dropped: number;
255
200
  };
256
- log: () => Proposal[];
257
- revertSet: (setId: string) => ChangeSet | null;
258
- sets: () => Array<Omit<ChangeSet, "proposals"> & {
201
+ /** Every decided proposal (accepted, rejected or stale), oldest decision first. */
202
+ log(): Proposal[];
203
+ /** Propose undoing what a set wrote, as a new set to review; null when nothing of it was accepted. */
204
+ revertSet(setId: string): ChangeSet | null;
205
+ /** The sets in this review, newest last, without their proposals. */
206
+ sets(): Array<Omit<ChangeSet, 'proposals'> & {
259
207
  count: number;
260
208
  }>;
261
- clear: () => void;
262
- };
209
+ /** Forget every proposal and set. */
210
+ clear(): void;
211
+ }
212
+ /**
213
+ * Hold writes nobody typed (an agent's edits, an import, an AI helper's
214
+ * output) as proposals, grouped by the change they make, and write them only
215
+ * when a person accepts them. Give the grid `review.columns(columns)` and
216
+ * `review.formats`, and render `<SvReviewPanel {review} />` beside it. Each
217
+ * decision is one Ctrl+Z in the grid.
218
+ */
219
+ export declare function createReview<TData = unknown>(opts: ReviewOptions<TData>): Review<TData>;
@@ -56,6 +56,13 @@ let uid = 0;
56
56
  const nextId = (prefix) => `${prefix}${Date.now().toString(36)}-${(uid++).toString(36)}`;
57
57
  const SEP = '\u0000';
58
58
  const cellKey = (rowId, field) => rowId + SEP + field;
59
+ /**
60
+ * Hold writes nobody typed (an agent's edits, an import, an AI helper's
61
+ * output) as proposals, grouped by the change they make, and write them only
62
+ * when a person accepts them. Give the grid `review.columns(columns)` and
63
+ * `review.formats`, and render `<SvReviewPanel {review} />` beside it. Each
64
+ * decision is one Ctrl+Z in the grid.
65
+ */
59
66
  export function createReview(opts) {
60
67
  if (!opts.setRows && !opts.server)
61
68
  throw new Error('[svgrid review] pass setRows (client data) or server (server row model)');
@@ -10,7 +10,16 @@ export type ProposalSource = {
10
10
  id: string;
11
11
  label: string;
12
12
  };
13
+ /**
14
+ * Where a proposal stands: waiting, accepted, rejected, stale (its cell
15
+ * changed first), or in conflict with another source's proposal for the same
16
+ * cell.
17
+ */
13
18
  export type ProposalStatus = 'pending' | 'accepted' | 'rejected' | 'stale' | 'conflict';
19
+ /**
20
+ * One proposed change to one cell, with where it came from and where it
21
+ * stands.
22
+ */
14
23
  export type Proposal = {
15
24
  id: string;
16
25
  /** Only `update` in this release; inserts and deletes come later. */
@@ -53,6 +62,10 @@ export type ChangeSet = {
53
62
  * has to look.
54
63
  */
55
64
  export type GroupKind = 'whitespace' | 'case' | 'format' | 'scale' | 'same-mapping' | 'fill-empty' | 'constant-target' | 'unpatterned';
65
+ /**
66
+ * Proposals that make the same change, as the panel lists them: a label, a
67
+ * kind, whether a rule proves every member, and a sample to check.
68
+ */
56
69
  export type ProposalGroup = {
57
70
  /** Stable while the group's members do not change: source, field, kind and param. */
58
71
  key: string;
package/dist/version.d.ts CHANGED
@@ -10,7 +10,7 @@
10
10
  *
11
11
  * `version.test.ts` asserts this matches `package.json`, so the two cannot drift.
12
12
  */
13
- export declare const SVGRID_VERSION = "3.1.23";
13
+ export declare const SVGRID_VERSION = "3.1.25";
14
14
  /**
15
15
  * The version of `@svgrid/grid`, which releases on its own line: enterprise is
16
16
  * on 3.1.x while the grid is on 3.0.x.
package/dist/version.js CHANGED
@@ -10,7 +10,7 @@
10
10
  *
11
11
  * `version.test.ts` asserts this matches `package.json`, so the two cannot drift.
12
12
  */
13
- export const SVGRID_VERSION = '3.1.23';
13
+ export const SVGRID_VERSION = '3.1.25';
14
14
  /**
15
15
  * The version of `@svgrid/grid`, which releases on its own line: enterprise is
16
16
  * on 3.1.x while the grid is on 3.0.x.
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "type": "commercial",
5
5
  "url": "https://svgrid.com/pricing"
6
6
  },
7
- "version": "3.1.23",
7
+ "version": "3.1.25",
8
8
  "description": "Enterprise feature pack for SvGrid: the server-side row model (lazy grouping, tree, pivot, transactions, selection across unloaded rows), Excel (xlsx) and PDF export, Excel/CSV/JSON import, pivot tables with a drag-and-drop designer, paginated print, Kanban board and scheduler renderers, no-code alerts and batch editing. CSV, TSV and JSON export are already free in @svgrid/grid. Requires a paid license key.",
9
9
  "license": "SEE LICENSE IN LICENSE",
10
10
  "author": "jQWidgets <sales@jqwidgets.com>",