@ai-matrx/records-ui 0.102.21 → 0.103.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,14 @@
1
1
  # Changelog — @ai-matrx/records-ui
2
2
 
3
+ ## 0.103.0
4
+
5
+ - **Notion's calculation row on the embedded grid** (Spaces N6): every column's footer cell says "Calculate" on hover and offers Notion's list in Notion's words — Count all · Count unique values · Count empty · Count not empty · Percent empty · Percent not empty · Sum · Average · Median · Min · Max · Range — narrowed to what the column can mean and to the store's `custom.agg_operations`. The pick is reported through `onPresentationChange` as `summaries` (unchanged door). The band stays plain until one is picked.
6
+ - The summary bar knows the store's three newer measures `percent_empty`, `percent_filled` (shown as a percent) and `range` (a date column's range in days).
7
+ - `searchBox={false}` on `Grid` / `ViewSwitcher` / `TablePage` (and the built-in source's embedded views): the embedded grid draws no magnifier, for a host that draws its own and hands the term through `searchOverride` (Spaces N-19).
8
+ - Both embedded magnifiers are `TapTargetSearchGroup surface="solid"` — no more `[tap-target] glass on a solid surface` on a page. Needs design-system 0.72.1.
9
+
10
+ **Consumer action:** none required. A host drawing its own search field may pass `searchBox={false}`.
11
+
3
12
  ## 0.102.21
4
13
 
5
14
  Automatic changed-only republish (docs/metadata drift since the last tag — see
package/dist/index.cjs CHANGED
@@ -10520,8 +10520,29 @@ var MEASURE_LABEL = {
10520
10520
  median: "Median",
10521
10521
  filled: "Filled",
10522
10522
  empty: "Empty",
10523
- unique: "Unique"
10523
+ unique: "Unique",
10524
+ percent_empty: "Percent empty",
10525
+ percent_filled: "Percent filled",
10526
+ range: "Range"
10524
10527
  };
10528
+ var NOTION_CALCULATIONS = [
10529
+ { op: "count", menu: "Count all", footer: "Count" },
10530
+ { op: "unique", menu: "Count unique values", footer: "Unique" },
10531
+ { op: "empty", menu: "Count empty", footer: "Empty" },
10532
+ { op: "filled", menu: "Count not empty", footer: "Not empty" },
10533
+ { op: "percent_empty", menu: "Percent empty", footer: "Empty" },
10534
+ { op: "percent_filled", menu: "Percent not empty", footer: "Not empty" },
10535
+ { op: "sum", menu: "Sum", footer: "Sum" },
10536
+ { op: "avg", menu: "Average", footer: "Average" },
10537
+ { op: "median", menu: "Median", footer: "Median" },
10538
+ { op: "min", menu: "Min", footer: "Min" },
10539
+ { op: "max", menu: "Max", footer: "Max" },
10540
+ { op: "range", menu: "Range", footer: "Range" }
10541
+ ];
10542
+ function calculationsFor(field2, storeOps) {
10543
+ const offered = new Set(measuresFor(field2, storeOps, true));
10544
+ return NOTION_CALCULATIONS.filter((c) => offered.has(c.op));
10545
+ }
10525
10546
  var NUMERIC_ONLY = /* @__PURE__ */ new Set(["sum", "avg", "median"]);
10526
10547
  var ARITHMETIC2 = /* @__PURE__ */ new Set([
10527
10548
  "add",
@@ -10539,7 +10560,7 @@ var ARITHMETIC2 = /* @__PURE__ */ new Set([
10539
10560
  "ceiling",
10540
10561
  "floor"
10541
10562
  ]);
10542
- var ORDERED = /* @__PURE__ */ new Set(["min", "max"]);
10563
+ var ORDERED = /* @__PURE__ */ new Set(["min", "max", "range"]);
10543
10564
  function isNumericField(field2) {
10544
10565
  const kind = editorKindFor(field2);
10545
10566
  if (kind === "number" || kind === "currency" || kind === "percent" || kind === "rollup") return true;
@@ -13769,14 +13790,17 @@ function SummaryCell({
13769
13790
  value,
13770
13791
  rowCount,
13771
13792
  summaries,
13772
- onChoose
13793
+ onChoose,
13794
+ calculate = false
13773
13795
  }) {
13774
13796
  const offered = (0, import_react73.useMemo)(
13775
- () => summaries.operations ? measuresFor(field2, summaries.operations, firstColumn) : null,
13776
- [summaries.operations, field2, firstColumn]
13797
+ () => summaries.operations ? calculate ? calculationsFor(field2, summaries.operations).map((c) => c.op) : measuresFor(field2, summaries.operations, firstColumn) : null,
13798
+ [summaries.operations, field2, firstColumn, calculate]
13777
13799
  );
13778
- const label = chosen ? MEASURE_LABEL[chosen] ?? chosen : null;
13779
- const shown4 = chosen === void 0 ? null : summaries.loading && value === void 0 ? "\u2026" : value === null || value === void 0 ? "\u2014" : chosen === "count" || chosen === "filled" || chosen === "empty" || chosen === "unique" ? String(value) : null;
13800
+ const words2 = (op2, where) => calculate ? NOTION_CALCULATIONS.find((c) => c.op === op2)?.[where] ?? MEASURE_LABEL[op2] ?? op2 : MEASURE_LABEL[op2] ?? op2;
13801
+ const label = chosen ? words2(chosen, "footer") : null;
13802
+ const isDate4 = editorKindFor(field2) === "datetime";
13803
+ const shown4 = chosen === void 0 ? null : summaries.loading && value === void 0 ? "\u2026" : value === null || value === void 0 ? "\u2014" : chosen === "count" || chosen === "filled" || chosen === "empty" || chosen === "unique" ? String(value) : chosen === "percent_empty" || chosen === "percent_filled" ? `${Number(value.toFixed(2))}%` : chosen === "range" && isDate4 ? `${Math.round(value)} day${Math.round(value) === 1 ? "" : "s"}` : null;
13780
13804
  return /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)(import_design_system42.DropdownMenu, { onOpenChange: (open) => open ? summaries.askOperations() : void 0, children: [
13781
13805
  /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_design_system42.DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
13782
13806
  import_design_system42.Button,
@@ -13798,7 +13822,7 @@ function SummaryCell({
13798
13822
  // AGG-WITHHELD: the store withheld this column from her — say so, never a bare dash.
13799
13823
  /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("span", { className: "font-medium", children: /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(WithheldValue, { field: field2, notice: summaries.withheld[field2.key] }) })
13800
13824
  ) : shown4 !== null ? /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("span", { className: "font-medium tabular-nums", children: shown4 }) : /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("span", { className: "font-medium tabular-nums", children: /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(RecordValue, { field: field2, value, format: formatForField(field2) }) })
13801
- ] }) : "Summarize"
13825
+ ] }) : calculate ? "Calculate" : "Summarize"
13802
13826
  }
13803
13827
  ) }),
13804
13828
  /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)(import_design_system42.DropdownMenuContent, { align: "start", children: [
@@ -13809,13 +13833,13 @@ function SummaryCell({
13809
13833
  "data-records-summary-choice": op2,
13810
13834
  onSelect: () => onChoose(op2),
13811
13835
  className: (0, import_design_system42.cn)(op2 === chosen && "font-medium"),
13812
- children: MEASURE_LABEL[op2] ?? op2
13836
+ children: words2(op2, "menu")
13813
13837
  },
13814
13838
  op2
13815
13839
  )),
13816
13840
  chosen ? /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)(import_jsx_runtime48.Fragment, { children: [
13817
13841
  /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_design_system42.DropdownMenuSeparator, {}),
13818
- /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_design_system42.DropdownMenuItem, { onSelect: () => onChoose(null), children: "No summary" })
13842
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_design_system42.DropdownMenuItem, { onSelect: () => onChoose(null), children: calculate ? "None" : "No summary" })
13819
13843
  ] }) : null
13820
13844
  ] })
13821
13845
  ] });
@@ -21789,7 +21813,8 @@ function GridBody({
21789
21813
  newRowLabel,
21790
21814
  sortOverride,
21791
21815
  searchOverride,
21792
- onSearchChange
21816
+ onSearchChange,
21817
+ searchBox = true
21793
21818
  }) {
21794
21819
  const toolbarSlot = useTableToolbarSlot();
21795
21820
  const tableCard = (0, import_data_table11.useMatrxTableCard)();
@@ -22784,6 +22809,7 @@ function GridBody({
22784
22809
  value: summaries.values[columnId2],
22785
22810
  rowCount: summaries.rowCount,
22786
22811
  summaries,
22812
+ calculate: embedded,
22787
22813
  onChoose: (op2) => footerNow.current.choose(columnId2, op2)
22788
22814
  }
22789
22815
  );
@@ -23048,7 +23074,8 @@ function GridBody({
23048
23074
  [storePaged, query, queryTotal, classicInCard, records.data?.total]
23049
23075
  );
23050
23076
  const showAddLine = mayAddRow && rows.length > 0;
23051
- const showSummaryLine = rows.length > 0 && (embedded ? Object.keys(chosenSummaries).length > 0 : !merged || Object.keys(chosenSummaries).length > 0);
23077
+ const showSummaryLine = rows.length > 0 && (embedded || !merged || Object.keys(chosenSummaries).length > 0);
23078
+ const calculationChosen = Object.keys(chosenSummaries).length > 0;
23052
23079
  const footerFace = JSON.stringify([
23053
23080
  showAddLine ? added.busy : null,
23054
23081
  showSummaryLine ? [chosenSummaries, summaries.values, summaries.rowCount, summaries.loading] : null
@@ -23151,10 +23178,11 @@ function GridBody({
23151
23178
  search: !embedded,
23152
23179
  // EMBEDDED: Notion's magnifier — the design system's own search group, a button that
23153
23180
  // opens into a field. It is the same `query.search` the store's read asks.
23154
- ...embedded ? {
23181
+ ...embedded && searchBox ? {
23155
23182
  customSearch: /* @__PURE__ */ (0, import_jsx_runtime70.jsx)(
23156
23183
  import_design_system60.TapTargetSearchGroup,
23157
23184
  {
23185
+ surface: "solid",
23158
23186
  placeholder: "Search",
23159
23187
  value: searchOverride ?? query.search,
23160
23188
  onValueChange: (term) => {
@@ -23366,7 +23394,8 @@ function GridBody({
23366
23394
  noun,
23367
23395
  embedded,
23368
23396
  searchOverride,
23369
- onSearchChange
23397
+ onSearchChange,
23398
+ searchBox
23370
23399
  ]
23371
23400
  );
23372
23401
  const labelOfField = (0, import_react113.useCallback)(
@@ -23588,7 +23617,7 @@ function GridBody({
23588
23617
  !look.wrap && "[&_tbody_td]:max-w-[28rem] [&_tbody_td]:overflow-hidden [&_tbody_td]:text-ellipsis [&_tbody_td]:whitespace-nowrap! [&_tbody_td_*]:whitespace-nowrap!",
23589
23618
  look.fit === "scroll" && "sm:[&>table]:w-max! sm:[&>table]:max-w-none! sm:[&>table]:min-w-full!",
23590
23619
  embedded && EMBEDDED_TABLE_CLASS,
23591
- embedded && !showSummaryLine && EMBEDDED_PLAIN_FOOTER_CLASS
23620
+ embedded && !calculationChosen && EMBEDDED_PLAIN_FOOTER_CLASS
23592
23621
  ),
23593
23622
  footerRows,
23594
23623
  ...embedded ? { copy: false } : copyConfig ? { copy: copyConfig } : {},
@@ -32943,6 +32972,7 @@ function ViewSwitcher({
32943
32972
  sortOverride,
32944
32973
  searchOverride,
32945
32974
  onSearchChange,
32975
+ searchBox,
32946
32976
  newRowLabel,
32947
32977
  className
32948
32978
  }) {
@@ -33010,6 +33040,7 @@ function ViewSwitcher({
33010
33040
  ...sortOverride !== void 0 ? { sortOverride } : {},
33011
33041
  ...searchOverride !== void 0 ? { searchOverride } : {},
33012
33042
  ...onSearchChange ? { onSearchChange } : {},
33043
+ ...searchBox === false ? { searchBox } : {},
33013
33044
  ...newRowLabel ? { newRowLabel } : {},
33014
33045
  ...filter ? { filter } : {},
33015
33046
  ...onClearFilter ? { onClearFilter } : {},
@@ -47661,6 +47692,7 @@ function TablePage({
47661
47692
  newRowLabel,
47662
47693
  searchOverride,
47663
47694
  onSearchChange,
47695
+ searchBox,
47664
47696
  pageSize: pageSizeAsked,
47665
47697
  seedViews,
47666
47698
  onLeave,
@@ -48550,6 +48582,7 @@ function TablePage({
48550
48582
  ...newRowLabel ? { newRowLabel } : {},
48551
48583
  ...searchOverride !== void 0 ? { searchOverride } : {},
48552
48584
  ...onSearchChange ? { onSearchChange } : {},
48585
+ ...searchBox === false ? { searchBox } : {},
48553
48586
  footer,
48554
48587
  openExport: () => setRail("export"),
48555
48588
  view: {
@@ -48856,6 +48889,7 @@ function EntityTablePageBody({
48856
48889
  presentation = "page",
48857
48890
  searchOverride,
48858
48891
  onSearchChange,
48892
+ searchBox = true,
48859
48893
  pageSize = presentation === "embedded" ? EMBEDDED_PAGE_SIZE : 100,
48860
48894
  layout: opened = "grid",
48861
48895
  onLayoutChange,
@@ -48943,9 +48977,10 @@ function EntityTablePageBody({
48943
48977
  ] }) : null,
48944
48978
  addRefused ? /* @__PURE__ */ (0, import_jsx_runtime156.jsx)(import_design_system142.ErrorBox, { className: "rounded border border-destructive/40 px-1.5 py-1 text-xs text-destructive", message: addRefused, operation: "Add a row", origin: "records-ui/entityViews" }) : null,
48945
48979
  entity.error ? /* @__PURE__ */ (0, import_jsx_runtime156.jsx)("p", { className: "px-1 py-3 text-xs text-muted-foreground", children: `This table could not be read: ${entity.error}` }) : layout === "board" && boardable ? /* @__PURE__ */ (0, import_jsx_runtime156.jsx)(EntityBoard, { entity, groupBy, onOpenRecord }) : /* @__PURE__ */ (0, import_jsx_runtime156.jsxs)(import_jsx_runtime156.Fragment, { children: [
48946
- presentation === "embedded" ? /* @__PURE__ */ (0, import_jsx_runtime156.jsx)("div", { className: "flex min-w-0 items-center justify-end", "data-records-entity-search": "", children: /* @__PURE__ */ (0, import_jsx_runtime156.jsx)(import_design_system141.TooltipProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime156.jsx)(
48980
+ presentation === "embedded" && searchBox ? /* @__PURE__ */ (0, import_jsx_runtime156.jsx)("div", { className: "flex min-w-0 items-center justify-end", "data-records-entity-search": "", children: /* @__PURE__ */ (0, import_jsx_runtime156.jsx)(import_design_system141.TooltipProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime156.jsx)(
48947
48981
  import_design_system141.TapTargetSearchGroup,
48948
48982
  {
48983
+ surface: "solid",
48949
48984
  placeholder: "Search",
48950
48985
  value: term,
48951
48986
  onValueChange: (next) => {
@@ -48982,6 +49017,7 @@ function TablePage2(props) {
48982
49017
  ...rest.pageSize ? { pageSize: rest.pageSize } : {},
48983
49018
  ...rest.searchOverride !== void 0 ? { searchOverride: rest.searchOverride } : {},
48984
49019
  ...rest.onSearchChange ? { onSearchChange: rest.onSearchChange } : {},
49020
+ ...rest.searchBox === false ? { searchBox: false } : {},
48985
49021
  ...layout ? { layout } : {},
48986
49022
  ...onLayoutChange ? { onLayoutChange } : {},
48987
49023
  ...groupBy ? { groupBy } : {},