@ai-matrx/design-system 0.35.0 → 0.36.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,37 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.36.0 — 2026-09-23
4
+
5
+ **A press inside a popover a grid cell opened is no longer a press on the cell.** (lane
6
+ FIX-15.)
7
+
8
+ React synthetic events propagate through the REACT tree, not the DOM tree. A Radix Popover
9
+ portals its content to `document.body`, but that content is still a React child of the
10
+ table cell that rendered it — so every mousedown, keystroke and clipboard event inside the
11
+ popover was delivered to `useSpreadsheetGrid`'s own handlers as if the person had pressed
12
+ the cell.
13
+
14
+ On production (build `93970125f9`, 2026-09-22) that made the relation picker unusable: one
15
+ real mouse click in its own `Search` box ran `cellProps.onMouseDown`, whose
16
+ `preventDefault()` stopped the input taking focus and whose `focus()` moved focus to the
17
+ spreadsheet scroll container; Radix saw focus leave its layer and dismissed the picker. The
18
+ box could not be typed into at all, so 0.35.0's un-clipped Create offer behind it was
19
+ unreachable by any person.
20
+
21
+ * `useSpreadsheetGrid` now ignores any mouse, key or clipboard event whose real DOM target
22
+ is not inside the element the handler is bound to (`camePastAPortal`) — the test is DOM
23
+ containment, not a list of known overlays, so it covers a relation picker, a person
24
+ picker, a select, a date picker and a menu alike, today and tomorrow.
25
+ * No consumer action. A table with no `spreadsheet` prop is untouched.
26
+
27
+ Proof: `MatrxDataTable.sheet.test.tsx` clause 15 mounts a cell whose content is a real
28
+ `createPortal` into `document.body` and fails on the pre-fix bytes (focus moved to the
29
+ scroller) — RED then GREEN. Headless, against the live store on the records-ui grid harness
30
+ at 1600×1000 and 375 wide: a real click leaves focus in the box, three typed characters
31
+ keep the picker open and land in it, and the Create offer is hit-testable
32
+ (`matrx-frontend/scripts/campaign-tests/fix15_the_pickers_search_box_survives_typing.mjs`;
33
+ 12 clauses fail on the pre-fix bytes).
34
+
3
35
  ## 0.35.0 — 2026-09-22
4
36
 
5
37
  **A popover may now be sized by its CONTENT, because a fixed width cannot be right for a
@@ -8439,6 +8439,19 @@ function targetsAnEditor(target) {
8439
8439
  if (!element) return false;
8440
8440
  return element.closest("input, textarea, select, [contenteditable='true']") !== null;
8441
8441
  }
8442
+ function camePastAPortal(target, host) {
8443
+ if (typeof Element === "undefined") return false;
8444
+ const element = target instanceof Element ? target : null;
8445
+ const owner = host instanceof Element ? host : null;
8446
+ if (!element || !owner) return false;
8447
+ return !owner.contains(element);
8448
+ }
8449
+ function camePastAPortalIntoTheContainer(target) {
8450
+ if (typeof Element === "undefined") return false;
8451
+ const element = target instanceof Element ? target : null;
8452
+ if (!element) return false;
8453
+ return element.closest('[data-matrx-table-spreadsheet="true"]') === null;
8454
+ }
8442
8455
  function useSpreadsheetGrid(options) {
8443
8456
  const [range, setRange] = (0, import_react15.useState)(null);
8444
8457
  const [fillTarget, setFillTarget] = (0, import_react15.useState)(null);
@@ -8610,6 +8623,7 @@ function useSpreadsheetGrid(options) {
8610
8623
  const current = optionsRef.current;
8611
8624
  if (!current) return;
8612
8625
  if (targetsAnEditor(event.target)) return;
8626
+ if (camePastAPortalIntoTheContainer(event.target)) return;
8613
8627
  const accel = event.metaKey || event.ctrlKey;
8614
8628
  if (accel && (event.key === "z" || event.key === "Z")) {
8615
8629
  event.preventDefault();
@@ -8696,6 +8710,7 @@ function useSpreadsheetGrid(options) {
8696
8710
  const onCopy = (0, import_react15.useCallback)(
8697
8711
  (event) => {
8698
8712
  if (!optionsRef.current || !range || targetsAnEditor(event.target)) return;
8713
+ if (camePastAPortalIntoTheContainer(event.target)) return;
8699
8714
  const text = selectionAsTsv();
8700
8715
  if (!text) return;
8701
8716
  event.preventDefault();
@@ -8706,6 +8721,7 @@ function useSpreadsheetGrid(options) {
8706
8721
  const onCut = (0, import_react15.useCallback)(
8707
8722
  (event) => {
8708
8723
  if (!optionsRef.current || !range || targetsAnEditor(event.target)) return;
8724
+ if (camePastAPortalIntoTheContainer(event.target)) return;
8709
8725
  const text = selectionAsTsv();
8710
8726
  if (!text) return;
8711
8727
  event.preventDefault();
@@ -8718,6 +8734,7 @@ function useSpreadsheetGrid(options) {
8718
8734
  (event) => {
8719
8735
  const current = optionsRef.current;
8720
8736
  if (!current || current.paste === false || !range || targetsAnEditor(event.target)) return;
8737
+ if (camePastAPortalIntoTheContainer(event.target)) return;
8721
8738
  const text = event.clipboardData?.getData("text/plain") ?? "";
8722
8739
  if (!text) return;
8723
8740
  event.preventDefault();
@@ -8801,6 +8818,7 @@ function useSpreadsheetGrid(options) {
8801
8818
  ...inFillPreview ? { "data-matrx-cell-fill-preview": "true" } : {},
8802
8819
  onMouseDown: (event) => {
8803
8820
  if (event.button !== 0) return;
8821
+ if (camePastAPortal(event.target ?? null, event.currentTarget)) return;
8804
8822
  event.preventDefault();
8805
8823
  const origin = event.currentTarget;
8806
8824
  if (typeof HTMLElement !== "undefined" && origin instanceof HTMLElement) {