@dxos/react-ui-stack 0.8.4-main.dedc0f3 → 0.8.4-main.e8ec1fe

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.
Files changed (59) hide show
  1. package/dist/lib/browser/{chunk-3V2YUQK5.mjs → chunk-3F2KBXLP.mjs} +208 -101
  2. package/dist/lib/browser/chunk-3F2KBXLP.mjs.map +7 -0
  3. package/dist/lib/browser/index.mjs +5 -1
  4. package/dist/lib/browser/meta.json +1 -1
  5. package/dist/lib/browser/playwright/index.mjs +10 -23
  6. package/dist/lib/browser/playwright/index.mjs.map +2 -2
  7. package/dist/lib/browser/testing/index.mjs +1 -1
  8. package/dist/lib/node-esm/{chunk-HE3BRF7A.mjs → chunk-SYKFLQGK.mjs} +208 -101
  9. package/dist/lib/node-esm/chunk-SYKFLQGK.mjs.map +7 -0
  10. package/dist/lib/node-esm/index.mjs +5 -1
  11. package/dist/lib/node-esm/meta.json +1 -1
  12. package/dist/lib/node-esm/playwright/index.mjs +10 -23
  13. package/dist/lib/node-esm/playwright/index.mjs.map +2 -2
  14. package/dist/lib/node-esm/testing/index.mjs +1 -1
  15. package/dist/types/src/components/Image/Image.d.ts +5 -2
  16. package/dist/types/src/components/Image/Image.d.ts.map +1 -1
  17. package/dist/types/src/components/Image/Image.stories.d.ts +3 -1
  18. package/dist/types/src/components/Image/Image.stories.d.ts.map +1 -1
  19. package/dist/types/src/components/Stack/Stack.d.ts +6 -5
  20. package/dist/types/src/components/Stack/Stack.d.ts.map +1 -1
  21. package/dist/types/src/components/Stack/Stack.stories.d.ts +1 -2
  22. package/dist/types/src/components/Stack/Stack.stories.d.ts.map +1 -1
  23. package/dist/types/src/components/StackItem/StackItem.d.ts +4 -3
  24. package/dist/types/src/components/StackItem/StackItem.d.ts.map +1 -1
  25. package/dist/types/src/components/StackItem/StackItem.stories.d.ts +0 -1
  26. package/dist/types/src/components/StackItem/StackItem.stories.d.ts.map +1 -1
  27. package/dist/types/src/components/StackItem/StackItemContent.d.ts +20 -10
  28. package/dist/types/src/components/StackItem/StackItemContent.d.ts.map +1 -1
  29. package/dist/types/src/components/StackItem/StackItemHeading.d.ts.map +1 -1
  30. package/dist/types/src/exemplars/Card/Card.d.ts +21 -10
  31. package/dist/types/src/exemplars/Card/Card.d.ts.map +1 -1
  32. package/dist/types/src/exemplars/Card/Card.stories.d.ts +0 -23
  33. package/dist/types/src/exemplars/Card/Card.stories.d.ts.map +1 -1
  34. package/dist/types/src/exemplars/Card/fragments.d.ts +1 -1
  35. package/dist/types/src/exemplars/Card/fragments.d.ts.map +1 -1
  36. package/dist/types/src/exemplars/CardStack/CardStack.d.ts +3 -1
  37. package/dist/types/src/exemplars/CardStack/CardStack.d.ts.map +1 -1
  38. package/dist/types/src/exemplars/CardStack/CardStack.stories.d.ts +3 -1
  39. package/dist/types/src/exemplars/CardStack/CardStack.stories.d.ts.map +1 -1
  40. package/dist/types/src/hooks/useStackDropForElements.d.ts +2 -2
  41. package/dist/types/src/hooks/useStackDropForElements.d.ts.map +1 -1
  42. package/dist/types/tsconfig.tsbuildinfo +1 -1
  43. package/package.json +27 -27
  44. package/src/components/Image/Image.stories.tsx +34 -8
  45. package/src/components/Image/Image.tsx +158 -73
  46. package/src/components/Stack/Stack.stories.tsx +2 -4
  47. package/src/components/Stack/Stack.tsx +93 -38
  48. package/src/components/StackItem/StackItem.stories.tsx +3 -5
  49. package/src/components/StackItem/StackItem.tsx +11 -4
  50. package/src/components/StackItem/StackItemContent.tsx +19 -8
  51. package/src/components/StackItem/StackItemHeading.tsx +1 -5
  52. package/src/exemplars/Card/Card.stories.tsx +1 -25
  53. package/src/exemplars/Card/Card.tsx +39 -15
  54. package/src/exemplars/Card/fragments.ts +1 -1
  55. package/src/exemplars/CardStack/CardStack.stories.tsx +5 -4
  56. package/src/exemplars/CardStack/CardStack.tsx +11 -8
  57. package/src/hooks/useStackDropForElements.ts +42 -35
  58. package/dist/lib/browser/chunk-3V2YUQK5.mjs.map +0 -7
  59. package/dist/lib/node-esm/chunk-HE3BRF7A.mjs.map +0 -7
@@ -1,66 +1,48 @@
1
1
  // src/components/Image/Image.tsx
2
2
  import { useSignals as _useSignals } from "@preact-signals/safe-react/tracking";
3
- import React, { useRef, useState } from "react";
3
+ import React, { useCallback, useRef, useState } from "react";
4
4
  import { mx } from "@dxos/react-ui-theme";
5
- var Image = ({ classNames, src, alt = "", crossOrigin = "anonymous", sampleSize = 64, contrast = 0.95 }) => {
5
+ var cache = /* @__PURE__ */ new Map();
6
+ var Image = ({ classNames, src, alt = "", crossOrigin = "anonymous", sampleSize = 64, contrast = 0.9 }) => {
6
7
  var _effect = _useSignals();
7
8
  try {
8
9
  const [crossOriginState, setCrossOriginState] = useState(crossOrigin);
9
10
  const [dominantColor, setDominantColor] = useState(void 0);
10
11
  const [imageLoaded, setImageLoaded] = useState(false);
11
12
  const canvasRef = useRef(null);
12
- const extractDominantColor = (img) => {
13
- const canvas = canvasRef.current;
14
- const ctx = canvas?.getContext("2d");
15
- if (!canvas || !ctx) {
13
+ const handleImageError = () => {
14
+ setCrossOriginState(void 0);
15
+ };
16
+ const handleImageLoad = useCallback(({ target }) => {
17
+ const rgb = cache.get(src);
18
+ if (rgb) {
19
+ setDominantColor(rgb);
20
+ setImageLoaded(true);
21
+ return;
22
+ }
23
+ const img = target;
24
+ if (!canvasRef.current) {
16
25
  return;
17
26
  }
18
- canvas.width = sampleSize;
19
- canvas.height = sampleSize;
20
- ctx.drawImage(img, 0, 0, sampleSize, sampleSize);
21
27
  try {
22
- const imageData = ctx.getImageData(0, 0, sampleSize, sampleSize);
23
- const pixels = imageData.data;
24
- let r = 0;
25
- let g = 0;
26
- let b = 0;
27
- let totalWeight = 0;
28
- for (let i = 0; i < pixels.length; i += 4) {
29
- const red = pixels[i];
30
- const green = pixels[i + 1];
31
- const blue = pixels[i + 2];
32
- const alpha = pixels[i + 3];
33
- if (alpha === 0) continue;
34
- const max = Math.max(red, green, blue);
35
- const min = Math.min(red, green, blue);
36
- const saturation = max === 0 ? 0 : (max - min) / max;
37
- const weight = 1 + saturation * 2;
38
- r += red * weight;
39
- g += green * weight;
40
- b += blue * weight;
41
- totalWeight += weight;
42
- }
43
- if (totalWeight > 0) {
44
- r = Math.round(r / totalWeight);
45
- g = Math.round(g / totalWeight);
46
- b = Math.round(b / totalWeight);
47
- r = Math.round(r * contrast);
48
- g = Math.round(g * contrast);
49
- b = Math.round(b * contrast);
50
- setDominantColor(`rgb(${r}, ${g}, ${b})`);
28
+ const color = extractDominantColor(canvasRef.current, img, {
29
+ sampleSize,
30
+ contrast
31
+ });
32
+ if (color) {
33
+ const rgb2 = `rgb(${color[0]}, ${color[1]}, ${color[2]})`;
34
+ cache.set(src, rgb2);
35
+ setDominantColor(rgb2);
51
36
  }
52
37
  } catch {
53
38
  setCrossOriginState(void 0);
54
39
  }
55
- };
56
- const handleImageError = () => {
57
- setCrossOriginState(void 0);
58
- };
59
- const handleImageLoad = (ev) => {
60
- const img = ev.target;
61
- extractDominantColor(img);
62
40
  setImageLoaded(true);
63
- };
41
+ }, [
42
+ sampleSize,
43
+ contrast,
44
+ src
45
+ ]);
64
46
  return /* @__PURE__ */ React.createElement("div", {
65
47
  className: mx(`relative flex is-full justify-center overflow-hidden transition-all duration-700`, classNames),
66
48
  style: {
@@ -94,6 +76,78 @@ var Image = ({ classNames, src, alt = "", crossOrigin = "anonymous", sampleSize
94
76
  _effect.f();
95
77
  }
96
78
  };
79
+ var extractDominantColor = (canvas, img, { sampleSize = 64, contrast = 0.95 }) => {
80
+ const ctx = canvas.getContext("2d");
81
+ if (!ctx) {
82
+ return null;
83
+ }
84
+ canvas.width = sampleSize;
85
+ canvas.height = sampleSize;
86
+ ctx.drawImage(img, 0, 0, sampleSize, sampleSize);
87
+ const imageData = ctx.getImageData(0, 0, sampleSize, sampleSize);
88
+ const pixels = imageData.data;
89
+ if (isTransparent(pixels, sampleSize)) {
90
+ return null;
91
+ }
92
+ let r = 0;
93
+ let g = 0;
94
+ let b = 0;
95
+ let totalWeight = 0;
96
+ const cornerSize = Math.floor(sampleSize * 0.125);
97
+ for (let y = 0; y < sampleSize; y++) {
98
+ for (let x = 0; x < sampleSize; x++) {
99
+ const isInTopLeft = x < cornerSize && y < cornerSize;
100
+ const isInTopRight = x >= sampleSize - cornerSize && y < cornerSize;
101
+ const isInBottomLeft = x < cornerSize && y >= sampleSize - cornerSize;
102
+ const isInBottomRight = x >= sampleSize - cornerSize && y >= sampleSize - cornerSize;
103
+ if (!isInTopLeft && !isInTopRight && !isInBottomLeft && !isInBottomRight) {
104
+ continue;
105
+ }
106
+ const i = (y * sampleSize + x) * 4;
107
+ const red = pixels[i];
108
+ const green = pixels[i + 1];
109
+ const blue = pixels[i + 2];
110
+ const alpha = pixels[i + 3];
111
+ if (alpha === 0) continue;
112
+ const max = Math.max(red, green, blue);
113
+ const min = Math.min(red, green, blue);
114
+ const saturation = max === 0 ? 0 : (max - min) / max;
115
+ const weight = 1 + saturation * 2;
116
+ r += red * weight;
117
+ g += green * weight;
118
+ b += blue * weight;
119
+ totalWeight += weight;
120
+ }
121
+ }
122
+ if (totalWeight > 0) {
123
+ r = Math.round(Math.round(r / totalWeight) * contrast);
124
+ g = Math.round(Math.round(g / totalWeight) * contrast);
125
+ b = Math.round(Math.round(b / totalWeight) * contrast);
126
+ return [
127
+ r,
128
+ g,
129
+ b
130
+ ];
131
+ }
132
+ return null;
133
+ };
134
+ var isTransparent = (pixels, sampleSize, threshold = 0.5) => {
135
+ let edgeTransparentPixels = 0;
136
+ const edgePixels = sampleSize * 4 - 4;
137
+ for (let x = 0; x < sampleSize; x++) {
138
+ const topIndex = x * 4;
139
+ if (pixels[topIndex + 3] === 0) edgeTransparentPixels++;
140
+ const bottomIndex = ((sampleSize - 1) * sampleSize + x) * 4;
141
+ if (pixels[bottomIndex + 3] === 0) edgeTransparentPixels++;
142
+ }
143
+ for (let y = 1; y < sampleSize - 1; y++) {
144
+ const leftIndex = y * sampleSize * 4;
145
+ if (pixels[leftIndex + 3] === 0) edgeTransparentPixels++;
146
+ const rightIndex = (y * sampleSize + sampleSize - 1) * 4;
147
+ if (pixels[rightIndex + 3] === 0) edgeTransparentPixels++;
148
+ }
149
+ return edgeTransparentPixels / edgePixels > threshold;
150
+ };
97
151
 
98
152
  // src/components/StackContext.tsx
99
153
  import { createContext, useContext } from "react";
@@ -121,7 +175,7 @@ var useStackItem = () => useContext(StackItemContext);
121
175
  // src/components/Stack/Stack.tsx
122
176
  import { useSignals as _useSignals2 } from "@preact-signals/safe-react/tracking";
123
177
  import { composeRefs } from "@radix-ui/react-compose-refs";
124
- import React2, { Children, forwardRef, useCallback, useEffect, useMemo, useState as useState3 } from "react";
178
+ import React2, { Children, forwardRef, useCallback as useCallback2, useEffect, useMemo, useState as useState3 } from "react";
125
179
  import { ListItem, useId } from "@dxos/react-ui";
126
180
  import { mx as mx2 } from "@dxos/react-ui-theme";
127
181
 
@@ -131,14 +185,16 @@ import { dropTargetForElements } from "@atlaskit/pragmatic-drag-and-drop/element
131
185
  import { autoScrollForElements } from "@atlaskit/pragmatic-drag-and-drop-auto-scroll/element";
132
186
  import { attachClosestEdge, extractClosestEdge } from "@atlaskit/pragmatic-drag-and-drop-hitbox/closest-edge";
133
187
  import { useLayoutEffect, useState as useState2 } from "react";
134
- var useStackDropForElements = ({ id, element, scrollElement = element, selfDroppable, orientation, onRearrange }) => {
188
+ var noop = () => {
189
+ };
190
+ var useStackDropForElements = ({ id, element, scrollElement = element, orientation, selfDroppable, onRearrange }) => {
135
191
  const [dropping, setDropping] = useState2(false);
136
192
  useLayoutEffect(() => {
137
- if (!element || !selfDroppable) {
193
+ if (!element) {
138
194
  return;
139
195
  }
140
196
  const acceptSourceType = orientation === "horizontal" ? "column" : "card";
141
- return combine(dropTargetForElements({
197
+ return combine(selfDroppable ? dropTargetForElements({
142
198
  element,
143
199
  getData: ({ input, element: element2 }) => {
144
200
  return attachClosestEdge({
@@ -171,10 +227,10 @@ var useStackDropForElements = ({ id, element, scrollElement = element, selfDropp
171
227
  onRearrange(source.data, self.data, extractClosestEdge(self.data));
172
228
  }
173
229
  }
174
- }), autoScrollForElements({
230
+ }) : noop, scrollElement ? autoScrollForElements({
175
231
  element: scrollElement,
176
232
  getAllowedAxis: () => orientation
177
- }));
233
+ }) : noop);
178
234
  }, [
179
235
  element,
180
236
  scrollElement,
@@ -204,11 +260,12 @@ var scrollIntoViewAndFocus = (el, orientation) => {
204
260
  });
205
261
  return el.focus();
206
262
  };
207
- var Stack = /* @__PURE__ */ forwardRef(({ children, classNames, style, orientation = "vertical", rail = true, size = "intrinsic", onRearrange, itemsCount = Children.count(children), getDropElement, separatorOnScroll, ...props }, forwardedRef) => {
263
+ var Stack = /* @__PURE__ */ forwardRef(({ children, classNames, style, orientation = "vertical", rail = true, size = "intrinsic", onRearrange, itemsCount = Children.count(children), getDropElement, separatorOnScroll, circularFocus, ...props }, forwardedRef) => {
208
264
  var _effect = _useSignals2();
209
265
  try {
210
266
  const stackId = useId("stack", props.id);
211
267
  const [stackElement, stackRef] = useState3(null);
268
+ const [lastFocusedItem, setLastFocusedItem] = useState3();
212
269
  const composedItemRef = composeRefs(stackRef, forwardedRef);
213
270
  const styles = {
214
271
  [orientation === "horizontal" ? "gridTemplateColumns" : "gridTemplateRows"]: size === "split" ? `repeat(${itemsCount}, 1fr)` : `repeat(${itemsCount}, min-content) [tabster-dummies] 0`,
@@ -223,7 +280,7 @@ var Stack = /* @__PURE__ */ forwardRef(({ children, classNames, style, orientati
223
280
  orientation,
224
281
  onRearrange
225
282
  });
226
- const handleScroll = useCallback(() => {
283
+ const handleScroll = useCallback2(() => {
227
284
  if (stackElement && Number.isFinite(separatorOnScroll)) {
228
285
  const scrollPosition = orientation === "horizontal" ? stackElement.scrollLeft : stackElement.scrollTop;
229
286
  const scrollSize = orientation === "horizontal" ? stackElement.scrollWidth : stackElement.scrollHeight;
@@ -239,7 +296,20 @@ var Stack = /* @__PURE__ */ forwardRef(({ children, classNames, style, orientati
239
296
  separatorOnScroll,
240
297
  orientation
241
298
  ]);
242
- const handleKeyDown = useCallback((event) => {
299
+ const handleBlur = useCallback2((event) => {
300
+ if (event.target) {
301
+ const target = event.target;
302
+ const closestStackItem = target.closest(`[data-dx-item-id]`);
303
+ if (closestStackItem?.closest(`[data-dx-stack="${stackId}"]`)) {
304
+ setLastFocusedItem(closestStackItem?.getAttribute("data-dx-item-id") ?? void 0);
305
+ }
306
+ }
307
+ props.onBlur?.(event);
308
+ }, [
309
+ stackId,
310
+ props.onBlur
311
+ ]);
312
+ const handleKeyDown = useCallback2((event) => {
243
313
  const target = event.target;
244
314
  if (event.key.startsWith("Arrow") && !target.closest(`input, textarea, [role="textbox"], [data-tabster*="mover"], [data-arrow-keys="all"], [data-arrow-keys~="${event.key.toLowerCase().slice(5)}"]`)) {
245
315
  const closestOwnedItem = target.closest(`[data-dx-stack-item="${stackId}"]`);
@@ -252,7 +322,16 @@ var Stack = /* @__PURE__ */ forwardRef(({ children, classNames, style, orientati
252
322
  const parallelDelta = (closestStackOrientation === "vertical" ? event.key === "ArrowUp" : event.key === "ArrowLeft") ? -1 : (closestStackOrientation === "vertical" ? event.key === "ArrowDown" : event.key === "ArrowRight") ? 1 : 0;
253
323
  const perpendicularDelta = (closestStackOrientation === "vertical" ? event.key === "ArrowLeft" : event.key === "ArrowUp") ? -1 : (closestStackOrientation === "vertical" ? event.key === "ArrowRight" : event.key === "ArrowDown") ? 1 : 0;
254
324
  if (parallelDelta !== 0) {
255
- const adjacentItem = closestStackItems[(closestStackItems.indexOf(closestOwnedItem) + parallelDelta + closestStackItems.length) % closestStackItems.length];
325
+ const currentIndex = closestStackItems.indexOf(closestOwnedItem);
326
+ const nextIndex = currentIndex + parallelDelta;
327
+ let adjacentItem;
328
+ if (circularFocus) {
329
+ adjacentItem = closestStackItems[(nextIndex + closestStackItems.length) % closestStackItems.length];
330
+ } else {
331
+ if (nextIndex >= 0 && nextIndex < closestStackItems.length) {
332
+ adjacentItem = closestStackItems[nextIndex];
333
+ }
334
+ }
256
335
  if (adjacentItem) {
257
336
  event.preventDefault();
258
337
  scrollIntoViewAndFocus(adjacentItem, closestStackOrientation);
@@ -261,24 +340,38 @@ var Stack = /* @__PURE__ */ forwardRef(({ children, classNames, style, orientati
261
340
  if (perpendicularDelta !== 0) {
262
341
  if (ancestorStack && ancestorOrientation !== closestStackOrientation) {
263
342
  const siblingStacks = Array.from(ancestorStack.querySelectorAll(`[data-dx-stack-item="${ancestorStack.getAttribute("data-dx-stack")}"] [data-dx-stack]`));
264
- const adjacentStack = siblingStacks[(siblingStacks.indexOf(closestStack) + perpendicularDelta + siblingStacks.length) % siblingStacks.length];
343
+ const currentStackIndex = siblingStacks.indexOf(closestStack);
344
+ const nextStackIndex = currentStackIndex + perpendicularDelta;
345
+ let adjacentStack;
346
+ if (ancestorStack.getAttribute("data-dx-stack-circular-focus") === "true") {
347
+ adjacentStack = siblingStacks[(nextStackIndex + siblingStacks.length) % siblingStacks.length];
348
+ } else {
349
+ if (nextStackIndex >= 0 && nextStackIndex < siblingStacks.length) {
350
+ adjacentStack = siblingStacks[nextStackIndex];
351
+ }
352
+ }
265
353
  const adjacentStackSelfItem = adjacentStack?.closest(`[data-dx-stack-item=${ancestorStack.getAttribute("data-dx-stack")}]`);
266
354
  const adjacentStackItems = adjacentStack ? Array.from(adjacentStack.querySelectorAll(`[data-dx-stack-item="${adjacentStack.getAttribute("data-dx-stack")}"]`)) : [];
267
- if (adjacentStackItems.length > 0) {
268
- const ownedItemRect = closestOwnedItem.getBoundingClientRect();
269
- const targetPosition = closestStackOrientation === "vertical" ? ownedItemRect.top : ownedItemRect.left;
355
+ if (adjacentStack && adjacentStackItems.length > 0) {
270
356
  let closestItem = adjacentStackItems[0];
271
- let closestDistance = Infinity;
272
- for (const item of adjacentStackItems) {
273
- const itemRect = item.getBoundingClientRect();
274
- const itemPosition = closestStackOrientation === "vertical" ? itemRect.top : itemRect.left;
275
- const distance = Math.abs(itemPosition - targetPosition);
276
- if (distance < closestDistance) {
277
- closestDistance = distance;
278
- closestItem = item;
279
- }
280
- if (closestDistance <= PERPENDICULAR_FOCUS_THRESHHOLD) {
281
- break;
357
+ const lastFocusedItem2 = adjacentStack.querySelector(`[data-dx-item-id="${adjacentStack.getAttribute("data-dx-last-focused-item") ?? "never"}"]`);
358
+ if (lastFocusedItem2) {
359
+ closestItem = lastFocusedItem2;
360
+ } else {
361
+ const ownedItemRect = closestOwnedItem.getBoundingClientRect();
362
+ const targetPosition = closestStackOrientation === "vertical" ? ownedItemRect.top : ownedItemRect.left;
363
+ let closestDistance = Infinity;
364
+ for (const item of adjacentStackItems) {
365
+ const itemRect = item.getBoundingClientRect();
366
+ const itemPosition = closestStackOrientation === "vertical" ? itemRect.top : itemRect.left;
367
+ const distance = Math.abs(itemPosition - targetPosition);
368
+ if (distance < closestDistance) {
369
+ closestDistance = distance;
370
+ closestItem = item;
371
+ }
372
+ if (closestDistance <= PERPENDICULAR_FOCUS_THRESHHOLD) {
373
+ break;
374
+ }
282
375
  }
283
376
  }
284
377
  event.preventDefault();
@@ -304,7 +397,8 @@ var Stack = /* @__PURE__ */ forwardRef(({ children, classNames, style, orientati
304
397
  props.onKeyDown?.(event);
305
398
  }, [
306
399
  props.onKeyDown,
307
- stackId
400
+ stackId,
401
+ circularFocus
308
402
  ]);
309
403
  const gridClasses = useMemo(() => {
310
404
  if (!rail) {
@@ -350,7 +444,10 @@ var Stack = /* @__PURE__ */ forwardRef(({ children, classNames, style, orientati
350
444
  ...props,
351
445
  className: mx2("grid relative [--stack-gap:var(--dx-trimXs)]", gridClasses, size === "contain" && (orientation === "horizontal" ? "overflow-x-auto overscroll-x-contain min-bs-0 max-bs-full bs-full" : "overflow-y-auto min-is-0 max-is-full is-full"), classNames),
352
446
  onKeyDown: handleKeyDown,
447
+ onBlur: handleBlur,
353
448
  "data-dx-stack": stackId,
449
+ "data-dx-stack-circular-focus": circularFocus,
450
+ "data-dx-last-focused-item": lastFocusedItem,
354
451
  "data-rail": rail,
355
452
  "aria-orientation": orientation,
356
453
  style: styles,
@@ -395,9 +492,9 @@ import { draggable, dropTargetForElements as dropTargetForElements2 } from "@atl
395
492
  import { preserveOffsetOnSource } from "@atlaskit/pragmatic-drag-and-drop/element/preserve-offset-on-source";
396
493
  import { setCustomNativeDragPreview } from "@atlaskit/pragmatic-drag-and-drop/element/set-custom-native-drag-preview";
397
494
  import { attachClosestEdge as attachClosestEdge2, extractClosestEdge as extractClosestEdge2 } from "@atlaskit/pragmatic-drag-and-drop-hitbox/closest-edge";
398
- import { useFocusableGroup as useFocusableGroup2 } from "@fluentui/react-tabster";
495
+ import { useFocusableGroup } from "@fluentui/react-tabster";
399
496
  import { composeRefs as composeRefs2 } from "@radix-ui/react-compose-refs";
400
- import React9, { forwardRef as forwardRef5, useCallback as useCallback2, useLayoutEffect as useLayoutEffect2, useMemo as useMemo3, useState as useState5 } from "react";
497
+ import React9, { forwardRef as forwardRef5, useCallback as useCallback3, useLayoutEffect as useLayoutEffect2, useMemo as useMemo3, useState as useState5 } from "react";
401
498
  import { createPortal } from "react-dom";
402
499
  import { ListItem as ListItem2 } from "@dxos/react-ui";
403
500
  import { resizeAttributes, sizeStyle } from "@dxos/react-ui-dnd";
@@ -407,7 +504,7 @@ import { mx as mx6 } from "@dxos/react-ui-theme";
407
504
  import { useSignals as _useSignals3 } from "@preact-signals/safe-react/tracking";
408
505
  import React3, { forwardRef as forwardRef2, useMemo as useMemo2 } from "react";
409
506
  import { mx as mx3 } from "@dxos/react-ui-theme";
410
- var StackItemContent = /* @__PURE__ */ forwardRef2(({ children, toolbar, statusbar, layoutManaged, classNames, size = "intrinsic", ...props }, forwardedRef) => {
507
+ var StackItemContent = /* @__PURE__ */ forwardRef2(({ children, toolbar, statusbar, layoutManaged, classNames, size = "intrinsic", scrollable, ...props }, forwardedRef) => {
411
508
  var _effect = _useSignals3();
412
509
  try {
413
510
  const { size: stackItemSize } = useStack();
@@ -430,7 +527,7 @@ var StackItemContent = /* @__PURE__ */ forwardRef2(({ children, toolbar, statusb
430
527
  return /* @__PURE__ */ React3.createElement("div", {
431
528
  role: "none",
432
529
  ...props,
433
- className: mx3("group grid grid-cols-[100%] density-coarse", stackItemSize === "contain" && "min-bs-0 overflow-hidden", size === "video" ? "aspect-video" : size === "square" && "aspect-square", toolbar && "[&>.dx-toolbar]:relative [&>.dx-toolbar]:border-be [&>.dx-toolbar]:border-subduedSeparator", role === "section" && toolbar && "[&_.dx-toolbar]:sticky [&_.dx-toolbar]:z-[1] [&_.dx-toolbar]:block-start-0 [&_.dx-toolbar]:-mbe-px [&_.dx-toolbar]:min-is-0", classNames),
530
+ className: mx3("group grid grid-cols-[100%] density-coarse", size === "video" ? "aspect-video" : size === "square" && "aspect-square", stackItemSize === "contain" && "min-bs-0 overflow-hidden", scrollable ? "min-bs-0 overflow-y-auto scrollbar-thin contain-layout" : "overflow-hidden", role === "section" && toolbar && "[&_.dx-toolbar]:sticky [&_.dx-toolbar]:z-[1] [&_.dx-toolbar]:block-start-0 [&_.dx-toolbar]:-mbe-px [&_.dx-toolbar]:min-is-0", toolbar && "[&>.dx-toolbar]:relative [&>.dx-toolbar]:border-be [&>.dx-toolbar]:border-subduedSeparator", classNames),
434
531
  style,
435
532
  "data-popover-collision-boundary": true,
436
533
  ref: forwardedRef
@@ -460,7 +557,6 @@ var StackItemDragHandle = ({ asChild, children }) => {
460
557
 
461
558
  // src/components/StackItem/StackItemHeading.tsx
462
559
  import { useSignals as _useSignals5 } from "@preact-signals/safe-react/tracking";
463
- import { useFocusableGroup } from "@fluentui/react-tabster";
464
560
  import { Slot as Slot2 } from "@radix-ui/react-slot";
465
561
  import React5, { forwardRef as forwardRef3 } from "react";
466
562
  import { useAttention } from "@dxos/react-ui-attention";
@@ -469,16 +565,11 @@ var StackItemHeading = ({ children, classNames, asChild, separateOnScroll, ...pr
469
565
  var _effect = _useSignals5();
470
566
  try {
471
567
  const { orientation } = useStack();
472
- const focusableGroupAttrs = useFocusableGroup({
473
- tabBehavior: "limited"
474
- });
475
568
  const Root = asChild ? Slot2 : "div";
476
569
  return /* @__PURE__ */ React5.createElement(Root, {
477
570
  role: "heading",
478
571
  ...props,
479
- tabIndex: 0,
480
- ...focusableGroupAttrs,
481
- className: mx4("flex items-center dx-focus-ring-inset-over-all relative !border-is-0 bg-headerSurface", separateOnScroll ? 'border-transparent [[data-scroll-separator="true"]_&]:border-subduedSeparator' : "border-subduedSeparator", orientation === "horizontal" ? "bs-[--rail-size]" : "is-[--rail-size] flex-col", orientation === "horizontal" ? "border-be" : "border-ie", classNames)
572
+ className: mx4("flex items-center !border-is-0 bg-headerSurface", separateOnScroll ? 'border-transparent [[data-scroll-separator="true"]_&]:border-subduedSeparator' : "border-subduedSeparator", orientation === "horizontal" ? "bs-[--rail-size]" : "is-[--rail-size] flex-col", orientation === "horizontal" ? "border-be" : "border-ie", classNames)
482
573
  }, children);
483
574
  } finally {
484
575
  _effect.f();
@@ -679,7 +770,7 @@ var StackItemRoot = /* @__PURE__ */ forwardRef5(({ item, children, classNames, s
679
770
  const [size = orientation === "horizontal" ? DEFAULT_HORIZONTAL_SIZE : DEFAULT_VERTICAL_SIZE, setInternalSize] = useState5(propsSize);
680
771
  const Root = role ?? "div";
681
772
  const composedItemRef = composeRefs2(itemRef, forwardedRef);
682
- const setSize = useCallback2((nextSize, commit) => {
773
+ const setSize = useCallback3((nextSize, commit) => {
683
774
  setInternalSize(nextSize);
684
775
  if (commit) {
685
776
  onSizeChange?.(nextSize);
@@ -788,7 +879,7 @@ var StackItemRoot = /* @__PURE__ */ forwardRef5(({ item, children, classNames, s
788
879
  selfDragHandleElement,
789
880
  itemElement
790
881
  ]);
791
- const focusableGroupAttrs = useFocusableGroup2({
882
+ const focusableGroupAttrs = useFocusableGroup({
792
883
  tabBehavior: "limited"
793
884
  });
794
885
  const shouldShowDropIndicator = () => {
@@ -829,8 +920,9 @@ var StackItemRoot = /* @__PURE__ */ forwardRef5(({ item, children, classNames, s
829
920
  ...props,
830
921
  tabIndex: 0,
831
922
  ...focusableGroupAttrs,
832
- className: mx6("group/stack-item grid relative", focusIndicatorVariant === "over-all" ? "dx-focus-ring-inset-over-all" : orientation === "horizontal" ? "dx-focus-ring-group-x" : "dx-focus-ring-group-y", orientation === "horizontal" ? "grid-rows-subgrid" : "grid-cols-subgrid", rail && (orientation === "horizontal" ? "row-span-2" : "col-span-2"), role === "section" && orientation !== "horizontal" && "border-be border-subduedSeparator", classNames),
923
+ className: mx6("group/stack-item grid relative", focusIndicatorVariant === "over-all" ? "dx-focus-ring-inset-over-all" : focusIndicatorVariant === "over-all-always" ? "dx-focus-ring-inset-over-all-always" : orientation === "horizontal" ? focusIndicatorVariant === "group-always" ? "dx-focus-ring-group-x-always" : "dx-focus-ring-group-x" : focusIndicatorVariant === "group-always" ? "dx-focus-ring-group-y-always" : "dx-focus-ring-group-y", orientation === "horizontal" ? "grid-rows-subgrid" : "grid-cols-subgrid", rail && (orientation === "horizontal" ? "row-span-2" : "col-span-2"), role === "section" && orientation !== "horizontal" && "border-be border-subduedSeparator", classNames),
833
924
  "data-dx-stack-item": stackId,
925
+ "data-dx-item-id": item.id,
834
926
  ...resizeAttributes,
835
927
  style: {
836
928
  ...stackSize !== "split" && sizeStyle(size, orientation),
@@ -880,7 +972,7 @@ var cardDialogPaddedOverflow = `${cardDialogOverflow} plb-cardSpacingBlock`;
880
972
  var cardDialogSearchListRoot = "pli-cardSpacingInline pbs-cardSpacingBlock [&>input]:mbe-0 min-bs-0 flex-1 flex flex-col";
881
973
  var cardText = cardSpacing;
882
974
  var cardHeading = "text-lg font-medium line-clamp-2 grow";
883
- var cardChrome = "pli-[--dx-cardSpacingChrome] mlb-[--dx-cardSpacingChrome] [&_.dx-button]:text-start [&_.dx-button]:is-full";
975
+ var cardChrome = "pli-[--dx-cardSpacingChrome] mlb-[--dx-cardSpacingChrome] [&_.dx-button]:text-start [&_.dx-button]:is-full [&_.dx-button]:pis-[calc(var(--dx-cardSpacingInline)-var(--dx-cardSpacingChrome))]";
884
976
 
885
977
  // src/exemplars/Card/Card.tsx
886
978
  import { useSignals as _useSignals10 } from "@preact-signals/safe-react/tracking";
@@ -888,8 +980,10 @@ import { Primitive } from "@radix-ui/react-primitive";
888
980
  import { Slot as Slot3 } from "@radix-ui/react-slot";
889
981
  import React10, { forwardRef as forwardRef6 } from "react";
890
982
  import { Icon as Icon2, IconButton, Toolbar, useTranslation as useTranslation2 } from "@dxos/react-ui";
891
- import { hoverableControls, mx as mx7 } from "@dxos/react-ui-theme";
892
- var CardStaticRoot = /* @__PURE__ */ forwardRef6(({ children, classNames, asChild, role = "group", ...props }, forwardedRef) => {
983
+ import { cardMinInlineSize, hoverableControls, mx as mx7 } from "@dxos/react-ui-theme";
984
+ var cardDefaultInlineSize = cardMinInlineSize;
985
+ var cardStackDefaultInlineSizeRem = cardDefaultInlineSize + 2.125;
986
+ var CardStaticRoot = /* @__PURE__ */ forwardRef6(({ children, classNames, id, asChild, role = "group", ...props }, forwardedRef) => {
893
987
  var _effect = _useSignals10();
894
988
  try {
895
989
  const Root = asChild ? Slot3 : "div";
@@ -903,6 +997,9 @@ var CardStaticRoot = /* @__PURE__ */ forwardRef6(({ children, classNames, asChil
903
997
  role
904
998
  };
905
999
  return /* @__PURE__ */ React10.createElement(Root, {
1000
+ ...id && {
1001
+ "data-object-id": id
1002
+ },
906
1003
  ...props,
907
1004
  ...rootProps,
908
1005
  ref: forwardedRef
@@ -911,7 +1008,7 @@ var CardStaticRoot = /* @__PURE__ */ forwardRef6(({ children, classNames, asChil
911
1008
  _effect.f();
912
1009
  }
913
1010
  });
914
- var CardSurfaceRoot = ({ role = "never", children, classNames }) => {
1011
+ var CardSurfaceRoot = ({ id, role = "never", children, classNames }) => {
915
1012
  var _effect = _useSignals10();
916
1013
  try {
917
1014
  if ([
@@ -920,6 +1017,9 @@ var CardSurfaceRoot = ({ role = "never", children, classNames }) => {
920
1017
  "card--extrinsic"
921
1018
  ].includes(role)) {
922
1019
  return /* @__PURE__ */ React10.createElement("div", {
1020
+ ...id && {
1021
+ "data-object-id": id
1022
+ },
923
1023
  className: mx7(role === "card--popover" ? "popover-card-width" : [
924
1024
  "card--intrinsic",
925
1025
  "card--extrinsic"
@@ -927,6 +1027,7 @@ var CardSurfaceRoot = ({ role = "never", children, classNames }) => {
927
1027
  }, children);
928
1028
  } else {
929
1029
  return /* @__PURE__ */ React10.createElement(CardStaticRoot, {
1030
+ id,
930
1031
  classNames: [
931
1032
  role === "card--transclusion" && "mlb-1",
932
1033
  role === "card--transclusion" && hoverableControls,
@@ -1004,8 +1105,9 @@ var CardPoster = (props) => {
1004
1105
  if (props.image) {
1005
1106
  return /* @__PURE__ */ React10.createElement(Image, {
1006
1107
  classNames: [
1007
- `dx-card__poster is-full __bs-auto`,
1008
- aspect
1108
+ `dx-card__poster is-full`,
1109
+ aspect,
1110
+ props.classNames
1009
1111
  ],
1010
1112
  src: props.image,
1011
1113
  alt: props.alt
@@ -1014,7 +1116,7 @@ var CardPoster = (props) => {
1014
1116
  if (props.icon) {
1015
1117
  return /* @__PURE__ */ React10.createElement("div", {
1016
1118
  role: "image",
1017
- className: mx7(`dx-card__poster grid place-items-center bg-inputSurface text-subdued`, aspect),
1119
+ className: mx7(`dx-card__poster grid place-items-center bg-inputSurface text-subdued`, aspect, props.classNames),
1018
1120
  "aria-label": props.alt
1019
1121
  }, /* @__PURE__ */ React10.createElement(Icon2, {
1020
1122
  icon: props.icon,
@@ -1190,21 +1292,24 @@ var CardStackFooter = /* @__PURE__ */ forwardRef7(({ children, classNames, asChi
1190
1292
  _effect.f();
1191
1293
  }
1192
1294
  });
1193
- var cardStackContent = [
1194
- "shrink min-bs-0 bg-baseSurface border border-separator rounded-md grid dx-focus-ring-group-x-indicator kanban-drop",
1195
- railGridHorizontalContainFitContent
1196
- ];
1197
- var CardStackContent = /* @__PURE__ */ forwardRef7(({ children, classNames, asChild, role = "none", ...props }, forwardedRef) => {
1295
+ var cardStackContent = "shrink min-bs-0 bg-baseSurface border border-separator rounded-md grid dx-focus-ring-group-x-indicator kanban-drop";
1296
+ var CardStackContent = /* @__PURE__ */ forwardRef7(({ children, classNames, asChild, role = "none", footer = true, ...props }, forwardedRef) => {
1198
1297
  var _effect = _useSignals12();
1199
1298
  try {
1200
1299
  const Root = asChild ? Slot4 : "div";
1300
+ const baseClassNames = footer ? [
1301
+ cardStackContent,
1302
+ railGridHorizontalContainFitContent
1303
+ ] : [
1304
+ cardStackContent
1305
+ ];
1201
1306
  const rootProps = asChild ? {
1202
1307
  classNames: [
1203
- ...cardStackContent,
1308
+ ...baseClassNames,
1204
1309
  classNames
1205
1310
  ]
1206
1311
  } : {
1207
- className: mx9(...cardStackContent, classNames),
1312
+ className: mx9(...baseClassNames, classNames),
1208
1313
  role
1209
1314
  };
1210
1315
  return /* @__PURE__ */ React12.createElement(Root, {
@@ -1362,6 +1467,8 @@ export {
1362
1467
  cardText,
1363
1468
  cardHeading,
1364
1469
  cardChrome,
1470
+ cardDefaultInlineSize,
1471
+ cardStackDefaultInlineSizeRem,
1365
1472
  Card,
1366
1473
  CardDragPreview2 as CardDragPreview,
1367
1474
  cardStackHeading,
@@ -1372,4 +1479,4 @@ export {
1372
1479
  CardStack,
1373
1480
  CardStackDragPreview
1374
1481
  };
1375
- //# sourceMappingURL=chunk-3V2YUQK5.mjs.map
1482
+ //# sourceMappingURL=chunk-3F2KBXLP.mjs.map