@dxos/react-ui-mosaic 0.8.4-main.21d9917 → 0.8.4-main.3eb6e50203

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 (132) hide show
  1. package/dist/lib/browser/{chunk-FS5LRPMY.mjs → chunk-Y6GU2CCU.mjs} +700 -769
  2. package/dist/lib/browser/chunk-Y6GU2CCU.mjs.map +7 -0
  3. package/dist/lib/browser/index.mjs +420 -46
  4. package/dist/lib/browser/index.mjs.map +4 -4
  5. package/dist/lib/browser/meta.json +1 -1
  6. package/dist/lib/browser/testing/index.mjs +27 -274
  7. package/dist/lib/browser/testing/index.mjs.map +4 -4
  8. package/dist/lib/node-esm/{chunk-E5JUEEB7.mjs → chunk-KTLFCRVA.mjs} +700 -769
  9. package/dist/lib/node-esm/chunk-KTLFCRVA.mjs.map +7 -0
  10. package/dist/lib/node-esm/index.mjs +420 -46
  11. package/dist/lib/node-esm/index.mjs.map +4 -4
  12. package/dist/lib/node-esm/meta.json +1 -1
  13. package/dist/lib/node-esm/testing/index.mjs +27 -274
  14. package/dist/lib/node-esm/testing/index.mjs.map +4 -4
  15. package/dist/types/src/components/Board/Board.d.ts +70 -0
  16. package/dist/types/src/components/Board/Board.d.ts.map +1 -0
  17. package/dist/types/src/components/{Mosaic/Mosaic.stories.d.ts → Board/Board.stories.d.ts} +12 -2
  18. package/dist/types/src/components/Board/Board.stories.d.ts.map +1 -0
  19. package/dist/types/src/components/Board/Column.d.ts +31 -0
  20. package/dist/types/src/components/Board/Column.d.ts.map +1 -0
  21. package/dist/types/src/components/Board/Item.d.ts +9 -0
  22. package/dist/types/src/components/Board/Item.d.ts.map +1 -0
  23. package/dist/types/src/components/Board/index.d.ts +2 -0
  24. package/dist/types/src/components/Board/index.d.ts.map +1 -0
  25. package/dist/types/src/components/Card/Card.d.ts +7 -4
  26. package/dist/types/src/components/Card/Card.d.ts.map +1 -1
  27. package/dist/types/src/components/Focus/Focus.d.ts +5 -4
  28. package/dist/types/src/components/Focus/Focus.d.ts.map +1 -1
  29. package/dist/types/src/components/Focus/styles.d.ts.map +1 -1
  30. package/dist/types/src/components/Mosaic/Mosaic.d.ts +10 -21
  31. package/dist/types/src/components/Mosaic/Mosaic.d.ts.map +1 -1
  32. package/dist/types/src/components/Mosaic/styles.d.ts.map +1 -1
  33. package/dist/types/src/components/Mosaic/types.d.ts +0 -2
  34. package/dist/types/src/components/Mosaic/types.d.ts.map +1 -1
  35. package/dist/types/src/components/Stack/Stack.d.ts +7 -9
  36. package/dist/types/src/components/Stack/Stack.d.ts.map +1 -1
  37. package/dist/types/src/components/Stack/Stack.stories.d.ts.map +1 -1
  38. package/dist/types/src/{testing/Virtualizer.stories.d.ts → components/Stack/virtualizer.stories.d.ts} +2 -2
  39. package/dist/types/src/components/Stack/virtualizer.stories.d.ts.map +1 -0
  40. package/dist/types/src/components/index.d.ts +1 -1
  41. package/dist/types/src/components/index.d.ts.map +1 -1
  42. package/dist/types/src/hooks/index.d.ts +1 -0
  43. package/dist/types/src/hooks/index.d.ts.map +1 -1
  44. package/dist/types/src/hooks/useContainerDebug.d.ts +9 -0
  45. package/dist/types/src/hooks/useContainerDebug.d.ts.map +1 -0
  46. package/dist/types/src/hooks/useEventHandlerAdapter.d.ts +1 -1
  47. package/dist/types/src/hooks/useEventHandlerAdapter.d.ts.map +1 -1
  48. package/dist/types/src/hooks/useVisibleItems.d.ts.map +1 -1
  49. package/dist/types/src/index.d.ts +1 -0
  50. package/dist/types/src/index.d.ts.map +1 -1
  51. package/dist/types/src/playwright/board-manager.d.ts +45 -0
  52. package/dist/types/src/playwright/board-manager.d.ts.map +1 -0
  53. package/dist/types/src/playwright/playwright.config.d.ts +3 -0
  54. package/dist/types/src/playwright/playwright.config.d.ts.map +1 -0
  55. package/dist/types/src/playwright/smoke.spec.d.ts +2 -0
  56. package/dist/types/src/playwright/smoke.spec.d.ts.map +1 -0
  57. package/dist/types/src/testing/CardContainer.d.ts +1 -1
  58. package/dist/types/src/testing/CardContainer.d.ts.map +1 -1
  59. package/dist/types/src/testing/index.d.ts +1 -1
  60. package/dist/types/src/testing/index.d.ts.map +1 -1
  61. package/dist/types/src/testing/{Board.d.ts → types.d.ts} +2 -15
  62. package/dist/types/src/testing/types.d.ts.map +1 -0
  63. package/dist/types/src/translations.d.ts +4 -1
  64. package/dist/types/src/translations.d.ts.map +1 -1
  65. package/dist/types/tsconfig.tsbuildinfo +1 -1
  66. package/package.json +27 -26
  67. package/src/components/Board/Board.stories.tsx +204 -0
  68. package/src/components/Board/Board.tsx +171 -0
  69. package/src/components/Board/Column.tsx +261 -0
  70. package/src/components/Board/Item.tsx +84 -0
  71. package/src/components/{Layout → Board}/index.ts +1 -1
  72. package/src/components/Card/Card.stories.tsx +1 -1
  73. package/src/components/Card/Card.tsx +25 -2
  74. package/src/components/Card/styles.ts +1 -1
  75. package/src/components/Focus/Focus.tsx +9 -9
  76. package/src/components/Focus/styles.ts +3 -6
  77. package/src/components/Image/Image.stories.tsx +1 -1
  78. package/src/components/Mosaic/Mosaic.tsx +179 -205
  79. package/src/components/Mosaic/styles.ts +14 -11
  80. package/src/components/Mosaic/types.ts +0 -4
  81. package/src/components/Stack/Stack.stories.tsx +30 -25
  82. package/src/components/Stack/Stack.tsx +43 -34
  83. package/src/{testing/Virtualizer.stories.tsx → components/Stack/virtualizer.stories.tsx} +49 -39
  84. package/src/components/index.ts +1 -1
  85. package/src/hooks/index.ts +1 -0
  86. package/src/hooks/useContainerDebug.tsx +48 -0
  87. package/src/hooks/useEventHandlerAdapter.ts +15 -6
  88. package/src/hooks/useVisibleItems.ts +3 -0
  89. package/src/index.ts +1 -0
  90. package/src/playwright/board-manager.ts +144 -0
  91. package/src/playwright/playwright.config.ts +16 -0
  92. package/src/playwright/smoke.spec.ts +138 -0
  93. package/src/testing/CardContainer.tsx +12 -7
  94. package/src/testing/index.ts +1 -1
  95. package/src/testing/types.ts +38 -0
  96. package/src/translations.ts +4 -1
  97. package/dist/lib/browser/chunk-FS5LRPMY.mjs.map +0 -7
  98. package/dist/lib/browser/index.css +0 -13
  99. package/dist/lib/browser/index.css.map +0 -7
  100. package/dist/lib/browser/testing/index.css +0 -13
  101. package/dist/lib/browser/testing/index.css.map +0 -7
  102. package/dist/lib/node-esm/chunk-E5JUEEB7.mjs.map +0 -7
  103. package/dist/lib/node-esm/index.css +0 -13
  104. package/dist/lib/node-esm/index.css.map +0 -7
  105. package/dist/lib/node-esm/testing/index.css +0 -13
  106. package/dist/lib/node-esm/testing/index.css.map +0 -7
  107. package/dist/types/src/components/Layout/Layout.d.ts +0 -33
  108. package/dist/types/src/components/Layout/Layout.d.ts.map +0 -1
  109. package/dist/types/src/components/Layout/Layout.stories.d.ts +0 -10
  110. package/dist/types/src/components/Layout/Layout.stories.d.ts.map +0 -1
  111. package/dist/types/src/components/Layout/index.d.ts +0 -2
  112. package/dist/types/src/components/Layout/index.d.ts.map +0 -1
  113. package/dist/types/src/components/Mosaic/Mosaic.stories.d.ts.map +0 -1
  114. package/dist/types/src/components/Scrollable/Scrollable.d.ts +0 -17
  115. package/dist/types/src/components/Scrollable/Scrollable.d.ts.map +0 -1
  116. package/dist/types/src/components/Scrollable/Scrollable.stories.d.ts +0 -8
  117. package/dist/types/src/components/Scrollable/Scrollable.stories.d.ts.map +0 -1
  118. package/dist/types/src/components/Scrollable/index.d.ts +0 -2
  119. package/dist/types/src/components/Scrollable/index.d.ts.map +0 -1
  120. package/dist/types/src/testing/Board.d.ts.map +0 -1
  121. package/dist/types/src/testing/Slot.stories.d.ts +0 -14
  122. package/dist/types/src/testing/Slot.stories.d.ts.map +0 -1
  123. package/dist/types/src/testing/Virtualizer.stories.d.ts.map +0 -1
  124. package/src/components/Layout/Layout.stories.tsx +0 -59
  125. package/src/components/Layout/Layout.tsx +0 -108
  126. package/src/components/Mosaic/Mosaic.stories.tsx +0 -113
  127. package/src/components/Scrollable/Scrollable.stories.tsx +0 -33
  128. package/src/components/Scrollable/Scrollable.tsx +0 -99
  129. package/src/components/Scrollable/index.ts +0 -5
  130. package/src/components/Scrollable/scrollable.css +0 -20
  131. package/src/testing/Board.tsx +0 -262
  132. package/src/testing/Slot.stories.tsx +0 -101
@@ -1,424 +1,37 @@
1
- // src/components/Card/styles.ts
2
- var styles = {
3
- root: "group/card relative min-bs-[--rail-item] overflow-hidden is-full card-min-width __card-max-width",
4
- border: "bg-cardSurface border border-separator dark:border-subduedSeparator rounded-sm dx-focus-ring-group-y-indicator",
5
- /**
6
- * Row grid.
7
- * NOTE: Rows should provide their own line padding (since they may need to encapsulate buttons, etc.)
8
- */
9
- grid_3: "grid grid-cols-[var(--rail-item)_minmax(0,1fr)_var(--rail-item)] gap-x-1",
10
- grid_2: "grid grid-cols-[var(--rail-item)_minmax(0,1fr)] gap-x-1",
11
- // TODO(burdon): Address density.
12
- grid_3_coarse: "grid grid-cols-[var(--l0-avatar-size)_minmax(0,1fr)_var(--rail-item)] gap-x-1",
13
- poster: "max-bs-[200px]"
14
- };
15
-
16
- // src/components/Image/Image.tsx
17
- import React, { useCallback, useRef, useState } from "react";
18
- import { mx } from "@dxos/ui-theme";
19
- var cache = /* @__PURE__ */ new Map();
20
- var Image = ({ classNames, src, alt = "", crossOrigin = "anonymous", sampleSize = 64, contrast = 0.9 }) => {
21
- const [crossOriginState, setCrossOriginState] = useState(crossOrigin);
22
- const [dominantColor, setDominantColor] = useState(void 0);
23
- const [imageLoaded, setImageLoaded] = useState(false);
24
- const canvasRef = useRef(null);
25
- const handleImageError = () => {
26
- setCrossOriginState(void 0);
27
- };
28
- const handleImageLoad = useCallback(({ target }) => {
29
- const rgb = cache.get(src);
30
- if (rgb) {
31
- setDominantColor(rgb);
32
- setImageLoaded(true);
33
- return;
34
- }
35
- const img = target;
36
- if (!canvasRef.current) {
37
- return;
1
+ // src/hooks/useVisibleItems.ts
2
+ import { useMemo } from "react";
3
+ var useVisibleItems = ({ id, items, dragging, getId }) => {
4
+ const visibleItems = useMemo(() => {
5
+ if (!items || !dragging || id !== dragging.containerId) {
6
+ return items ?? [];
38
7
  }
39
- try {
40
- const color = extractDominantColor(canvasRef.current, img, {
41
- sampleSize,
42
- contrast
43
- });
44
- if (color) {
45
- const rgb2 = `rgb(${color[0]}, ${color[1]}, ${color[2]})`;
46
- cache.set(src, rgb2);
47
- setDominantColor(rgb2);
48
- }
49
- } catch {
50
- setCrossOriginState(void 0);
8
+ const idx = items.findIndex((item) => getId(item) === dragging.id);
9
+ if (idx === -1) {
10
+ return items;
51
11
  }
52
- setImageLoaded(true);
12
+ const visibleItems2 = items.slice();
13
+ visibleItems2.splice(idx, 1);
14
+ return visibleItems2;
53
15
  }, [
54
- sampleSize,
55
- contrast,
56
- src
16
+ id,
17
+ items,
18
+ dragging,
19
+ getId
57
20
  ]);
58
- return /* @__PURE__ */ React.createElement("div", {
59
- className: mx(`relative flex is-full justify-center overflow-hidden transition-all duration-700`, classNames),
60
- style: {
61
- backgroundColor: dominantColor
62
- }
63
- }, /* @__PURE__ */ React.createElement("canvas", {
64
- ref: canvasRef,
65
- style: {
66
- display: "none"
67
- },
68
- "aria-hidden": "true"
69
- }), /* @__PURE__ */ React.createElement("div", {
70
- className: "absolute inset-0 pointer-events-none",
71
- style: {
72
- background: dominantColor ? `radial-gradient(circle at center, transparent 30%, ${dominantColor} 100%)` : void 0,
73
- transition: "opacity 0.7s ease-in-out",
74
- opacity: 0.5
75
- }
76
- }), /* @__PURE__ */ React.createElement("img", {
77
- src,
78
- alt,
79
- crossOrigin: crossOriginState,
80
- onError: handleImageError,
81
- onLoad: handleImageLoad,
82
- className: mx("z-10 object-contain transition-opacity duration-500", classNames),
83
- style: {
84
- opacity: imageLoaded ? 1 : 0
85
- }
86
- }));
87
- };
88
- var extractDominantColor = (canvas, img, { sampleSize = 64, contrast = 0.95 }) => {
89
- const ctx = canvas.getContext("2d");
90
- if (!ctx) {
91
- return null;
92
- }
93
- canvas.width = sampleSize;
94
- canvas.height = sampleSize;
95
- ctx.drawImage(img, 0, 0, sampleSize, sampleSize);
96
- const imageData = ctx.getImageData(0, 0, sampleSize, sampleSize);
97
- const pixels = imageData.data;
98
- if (isTransparent(pixels, sampleSize)) {
99
- return null;
100
- }
101
- let r = 0;
102
- let g = 0;
103
- let b = 0;
104
- let totalWeight = 0;
105
- const cornerSize = Math.floor(sampleSize * 0.125);
106
- for (let y = 0; y < sampleSize; y++) {
107
- for (let x = 0; x < sampleSize; x++) {
108
- const isInTopLeft = x < cornerSize && y < cornerSize;
109
- const isInTopRight = x >= sampleSize - cornerSize && y < cornerSize;
110
- const isInBottomLeft = x < cornerSize && y >= sampleSize - cornerSize;
111
- const isInBottomRight = x >= sampleSize - cornerSize && y >= sampleSize - cornerSize;
112
- if (!isInTopLeft && !isInTopRight && !isInBottomLeft && !isInBottomRight) {
113
- continue;
114
- }
115
- const i = (y * sampleSize + x) * 4;
116
- const red = pixels[i];
117
- const green = pixels[i + 1];
118
- const blue = pixels[i + 2];
119
- const alpha = pixels[i + 3];
120
- if (alpha === 0) continue;
121
- const max = Math.max(red, green, blue);
122
- const min = Math.min(red, green, blue);
123
- const saturation = max === 0 ? 0 : (max - min) / max;
124
- const weight = 1 + saturation * 2;
125
- r += red * weight;
126
- g += green * weight;
127
- b += blue * weight;
128
- totalWeight += weight;
129
- }
130
- }
131
- if (totalWeight > 0) {
132
- r = Math.round(Math.round(r / totalWeight) * contrast);
133
- g = Math.round(Math.round(g / totalWeight) * contrast);
134
- b = Math.round(Math.round(b / totalWeight) * contrast);
135
- return [
136
- r,
137
- g,
138
- b
139
- ];
140
- }
141
- return null;
142
- };
143
- var isTransparent = (pixels, sampleSize, threshold = 0.5) => {
144
- let edgeTransparentPixels = 0;
145
- const edgePixels = sampleSize * 4 - 4;
146
- for (let x = 0; x < sampleSize; x++) {
147
- const topIndex = x * 4;
148
- if (pixels[topIndex + 3] === 0) edgeTransparentPixels++;
149
- const bottomIndex = ((sampleSize - 1) * sampleSize + x) * 4;
150
- if (pixels[bottomIndex + 3] === 0) edgeTransparentPixels++;
151
- }
152
- for (let y = 1; y < sampleSize - 1; y++) {
153
- const leftIndex = y * sampleSize * 4;
154
- if (pixels[leftIndex + 3] === 0) edgeTransparentPixels++;
155
- const rightIndex = (y * sampleSize + sampleSize - 1) * 4;
156
- if (pixels[rightIndex + 3] === 0) edgeTransparentPixels++;
157
- }
158
- return edgeTransparentPixels / edgePixels > threshold;
159
- };
160
-
161
- // src/components/Card/Card.tsx
162
- import { Slot } from "@radix-ui/react-slot";
163
- import React2, { createContext, forwardRef, useContext } from "react";
164
- import { Button, DropdownMenu, Icon, Toolbar, useTranslation } from "@dxos/react-ui";
165
- import { mx as mx2 } from "@dxos/ui-theme";
166
-
167
- // src/translations.ts
168
- var translationKey = "@dxos/react-ui-mosaic";
169
- var translations = [
170
- {
171
- "en-US": {
172
- [translationKey]: {}
173
- }
174
- }
175
- ];
176
-
177
- // src/components/Card/Card.tsx
178
- var CardContext = /* @__PURE__ */ createContext({});
179
- var CardRoot = /* @__PURE__ */ forwardRef(({ children, classNames, className, id, asChild, role = "group", border = true, fullWidth, ...props }, forwardedRef) => {
180
- const Root2 = asChild ? Slot : "div";
181
- return /* @__PURE__ */ React2.createElement(Root2, {
182
- ...id && {
183
- "data-object-id": id
184
- },
185
- ...props,
186
- role,
187
- className: mx2(styles.root, border && styles.border, fullWidth && "!max-is-none", className, classNames),
188
- ref: forwardedRef
189
- }, children);
190
- });
191
- var CardToolbar = /* @__PURE__ */ forwardRef(({ children, classNames, density = "fine", ...props }, forwardedRef) => {
192
- return /* @__PURE__ */ React2.createElement(Toolbar.Root, {
193
- ...props,
194
- classNames: [
195
- "density-fine bg-transparent",
196
- density === "fine" ? styles.grid_3 : styles.grid_3_coarse,
197
- classNames
198
- ],
199
- ref: forwardedRef
200
- }, children);
201
- });
202
- var CardToolbarIconButton = Toolbar.IconButton;
203
- var CardToolbarSeparator = Toolbar.Separator;
204
- var CardDragHandle = /* @__PURE__ */ forwardRef((_, forwardedRef) => {
205
- const { t } = useTranslation(translationKey);
206
- return /* @__PURE__ */ React2.createElement(Toolbar.IconButton, {
207
- "data-testid": "card-drag-handle",
208
- noTooltip: true,
209
- iconOnly: true,
210
- icon: "ph--dots-six-vertical--regular",
211
- variant: "ghost",
212
- label: t("drag handle label"),
213
- classNames: "cursor-pointer",
214
- size: 5,
215
- disabled: !forwardedRef,
216
- ref: forwardedRef
217
- });
218
- });
219
- var CardClose = /* @__PURE__ */ forwardRef(({ onClick }, forwardedRef) => {
220
- const { t } = useTranslation(translationKey);
221
- return /* @__PURE__ */ React2.createElement(Toolbar.IconButton, {
222
- iconOnly: true,
223
- icon: "ph--x--regular",
224
- variant: "ghost",
225
- label: t("card close label"),
226
- classNames: "cursor-pointer",
227
- size: 5,
228
- onClick,
229
- ref: forwardedRef
230
- });
231
- });
232
- var CardMenu = ({ context, items }) => {
233
- const { t } = useTranslation(translationKey);
234
- const { menuItems } = useContext(CardContext) ?? {};
235
- const combinedItems = [
236
- ...items ?? [],
237
- ...menuItems ?? []
238
- ];
239
- return /* @__PURE__ */ React2.createElement(DropdownMenu.Root, null, /* @__PURE__ */ React2.createElement(DropdownMenu.Trigger, {
240
- disabled: !combinedItems.length,
241
- asChild: true
242
- }, /* @__PURE__ */ React2.createElement(Card.ToolbarIconButton, {
243
- iconOnly: true,
244
- variant: "ghost",
245
- icon: "ph--dots-three-vertical--regular",
246
- label: t("action menu label")
247
- })), (combinedItems?.length ?? 0) > 0 && /* @__PURE__ */ React2.createElement(DropdownMenu.Portal, null, /* @__PURE__ */ React2.createElement(DropdownMenu.Content, null, /* @__PURE__ */ React2.createElement(DropdownMenu.Viewport, null, combinedItems?.map(({ label, onClick: onSelect }, i) => /* @__PURE__ */ React2.createElement(DropdownMenu.Item, {
248
- key: i,
249
- onSelect: () => onSelect(context)
250
- }, label))), /* @__PURE__ */ React2.createElement(DropdownMenu.Arrow, null))));
251
- };
252
- var CardTitle = /* @__PURE__ */ forwardRef(({ children, classNames, className, asChild, role = "heading", ...props }, forwardedRef) => {
253
- const Root2 = asChild ? Slot : "div";
254
- return /* @__PURE__ */ React2.createElement(Root2, {
255
- ...props,
256
- role,
257
- className: mx2("grow truncate", classNames, className),
258
- ref: forwardedRef
259
- }, children);
260
- });
261
- var CardContent = /* @__PURE__ */ forwardRef(({ children, ...props }, forwardedRef) => {
262
- return /* @__PURE__ */ React2.createElement("div", {
263
- role: "none",
264
- className: "contents [&>:last-child]:pbe-1",
265
- ...props,
266
- ref: forwardedRef
267
- }, children);
268
- });
269
- var CardRow = /* @__PURE__ */ forwardRef(({ children, classNames, className, role = "none", icon, ...props }, forwardedRef) => {
270
- return /* @__PURE__ */ React2.createElement("div", {
271
- ...props,
272
- role,
273
- className: mx2(styles.grid_2, "pli-1", classNames, className),
274
- ref: forwardedRef
275
- }, icon && /* @__PURE__ */ React2.createElement(CardIcon, {
276
- classNames: "text-subdued",
277
- icon
278
- }) || /* @__PURE__ */ React2.createElement("div", null), children);
279
- });
280
- var CardHeading = /* @__PURE__ */ forwardRef(({ children, classNames, className, asChild, role = "heading", variant = "default", ...props }, forwardedRef) => {
281
- const Root2 = asChild ? Slot : "div";
282
- const variantClassNames = {
283
- default: "plb-1",
284
- subtitle: "plb-2 text-xs text-description font-medium uppercase"
285
- };
286
- return /* @__PURE__ */ React2.createElement(Root2, {
287
- ...props,
288
- role,
289
- className: mx2(variantClassNames[variant], classNames, className),
290
- ref: forwardedRef
291
- }, children);
292
- });
293
- var CardText = /* @__PURE__ */ forwardRef(({ children, classNames, className, asChild, role = "none", truncate, variant = "default", ...props }, forwardedRef) => {
294
- const Root2 = asChild ? Slot : "div";
295
- const variantClassNames = {
296
- default: {
297
- root: "plb-1"
298
- },
299
- description: {
300
- root: "plb-1.5",
301
- span: "text-sm text-description line-clamp-3"
302
- }
303
- };
304
- return /* @__PURE__ */ React2.createElement(Root2, {
305
- ...props,
306
- role,
307
- className: mx2("flex overflow-hidden", variantClassNames[variant].root, classNames, className),
308
- ref: forwardedRef
309
- }, /* @__PURE__ */ React2.createElement("span", {
310
- className: mx2(variantClassNames[variant].span, truncate && "truncate")
311
- }, children));
312
- });
313
- var CardPoster = (props) => {
314
- const aspect = props.aspect === "auto" ? "aspect-auto" : "aspect-video";
315
- if (props.image) {
316
- return /* @__PURE__ */ React2.createElement("div", {
317
- role: "none",
318
- className: "mbe-1"
319
- }, /* @__PURE__ */ React2.createElement(Image, {
320
- classNames: [
321
- styles.poster,
322
- aspect,
323
- props.classNames
324
- ],
325
- src: props.image,
326
- alt: props.alt
327
- }));
328
- }
329
- if (props.icon) {
330
- return /* @__PURE__ */ React2.createElement("div", {
331
- role: "image",
332
- className: mx2("grid place-items-center bg-inputSurface text-subdued", styles.poster, aspect, props.classNames),
333
- "aria-label": props.alt
334
- }, /* @__PURE__ */ React2.createElement(Icon, {
335
- icon: props.icon,
336
- size: 10
337
- }));
338
- }
339
- };
340
- var CardAction = ({ icon, actionIcon = "ph--arrow-right--regular", label, onClick }) => {
341
- return /* @__PURE__ */ React2.createElement("div", {
342
- role: "none",
343
- className: "is-full pli-1"
344
- }, /* @__PURE__ */ React2.createElement(Button, {
345
- variant: "ghost",
346
- classNames: mx2(styles.grid_3, "!p-0 is-full text-start overflow-hidden"),
347
- onClick
348
- }, icon ? /* @__PURE__ */ React2.createElement(CardIcon, {
349
- classNames: "text-subdued",
350
- icon
351
- }) : /* @__PURE__ */ React2.createElement("div", null), /* @__PURE__ */ React2.createElement("span", {
352
- className: mx2("min-is-0 flex-1 truncate", !actionIcon && "col-span-2")
353
- }, label), actionIcon && /* @__PURE__ */ React2.createElement(CardIcon, {
354
- icon: actionIcon
355
- })));
356
- };
357
- var CardLink = ({ label, href }) => {
358
- return /* @__PURE__ */ React2.createElement("div", {
359
- role: "none",
360
- className: "is-full pli-1"
361
- }, /* @__PURE__ */ React2.createElement("a", {
362
- className: mx2(styles.grid_3, "group !p-0 dx-button dx-focus-ring !min-bs-1"),
363
- "data-variant": "ghost",
364
- href,
365
- target: "_blank",
366
- rel: "noreferrer"
367
- }, /* @__PURE__ */ React2.createElement(CardIcon, {
368
- classNames: "text-subdued",
369
- icon: "ph--link--regular"
370
- }), /* @__PURE__ */ React2.createElement("span", {
371
- className: mx2("min-is-0 flex-1 truncate")
372
- }, label), /* @__PURE__ */ React2.createElement(CardIcon, {
373
- classNames: "invisible group-hover:visible",
374
- icon: "ph--arrow-square-out--regular"
375
- })));
376
- };
377
- var CardIcon = ({ toolbar, ...props }) => {
378
- return /* @__PURE__ */ React2.createElement("div", {
379
- role: "none",
380
- className: "grid bs-[var(--rail-item)] is-[var(--rail-item)] place-items-center"
381
- }, /* @__PURE__ */ React2.createElement(Icon, {
382
- ...props,
383
- size: toolbar ? 5 : 4
384
- }));
385
- };
386
- var Card = {
387
- Context: CardContext,
388
- Root: CardRoot,
389
- // Toolbar
390
- Toolbar: CardToolbar,
391
- ToolbarIconButton: CardToolbarIconButton,
392
- ToolbarSeparator: CardToolbarSeparator,
393
- DragHandle: CardDragHandle,
394
- Title: CardTitle,
395
- Close: CardClose,
396
- Menu: CardMenu,
397
- Icon: CardIcon,
398
- // Content
399
- Content: CardContent,
400
- Row: CardRow,
401
- Heading: CardHeading,
402
- Text: CardText,
403
- Poster: CardPoster,
404
- Action: CardAction,
405
- Link: CardLink
21
+ return visibleItems;
406
22
  };
407
23
 
408
24
  // src/components/Focus/styles.ts
409
- var styles2 = {
25
+ var styles = {
410
26
  container: {
411
- // TODO(burdon): Handle selection (aria-current?)
412
- // TODO(burdon): Use ring instead of border?
413
27
  root: [
414
- "outline-none border border-separator rounded-sm",
28
+ // TODO(burdon): Option for border/rounded; ring/outline vs border?
29
+ "outline-none border border-separator md:rounded-sm",
415
30
  // Focus (e.g., via tabster).
416
- // TODO(burdon): Why is ! required?
417
31
  "focus:!border-accentSurface",
418
32
  // Active (e.g., drop target).
419
33
  "data-[focus-state=active]:border-neutralFocusIndicator",
420
34
  // Error
421
- // TODO(burdon): Error token.
422
35
  "data-[focus-state=error]:border-rose-500"
423
36
  ]
424
37
  }
@@ -428,32 +41,32 @@ var styles2 = {
428
41
  import { useArrowNavigationGroup, useFocusableGroup, useMergedTabsterAttributes_unstable } from "@fluentui/react-tabster";
429
42
  import { useComposedRefs } from "@radix-ui/react-compose-refs";
430
43
  import { Primitive } from "@radix-ui/react-primitive";
431
- import { Slot as Slot2 } from "@radix-ui/react-slot";
432
- import React3, { createContext as createContext2, forwardRef as forwardRef2, useContext as useContext2, useRef as useRef2, useState as useState2 } from "react";
433
- import { mx as mx3 } from "@dxos/ui-theme";
44
+ import { Slot } from "@radix-ui/react-slot";
45
+ import React, { createContext, forwardRef, useContext, useRef, useState } from "react";
46
+ import { mx } from "@dxos/ui-theme";
434
47
  var FOCUS_STATE_ATTR = "focus-state";
435
- var FocusContext = /* @__PURE__ */ createContext2({});
436
- var useFocus = () => useContext2(FocusContext);
437
- var Group = /* @__PURE__ */ forwardRef2(({ classNames, className, children, asChild, axis = "vertical", ...props }, forwardedRef) => {
438
- const rootRef = useRef2(null);
48
+ var FocusContext = /* @__PURE__ */ createContext({});
49
+ var useFocus = () => useContext(FocusContext);
50
+ var Group = /* @__PURE__ */ forwardRef(({ classNames, className, children, asChild, orientation = "vertical", ...props }, forwardedRef) => {
51
+ const rootRef = useRef(null);
439
52
  const composedRef = useComposedRefs(rootRef, forwardedRef);
440
- const Root2 = asChild ? Slot2 : Primitive.div;
53
+ const Root2 = asChild ? Slot : Primitive.div;
441
54
  const focusableGroupAttrs = useFocusableGroup({
442
55
  tabBehavior: "limited-trap-focus"
443
56
  });
444
57
  const arrowNavigationAttrs = useArrowNavigationGroup({
445
- axis,
58
+ axis: orientation,
446
59
  memorizeCurrent: true
447
60
  });
448
61
  const tabsterAttrs = useMergedTabsterAttributes_unstable(focusableGroupAttrs, arrowNavigationAttrs);
449
- const [state, setState] = useState2();
450
- return /* @__PURE__ */ React3.createElement(FocusContext.Provider, {
62
+ const [state, setState] = useState();
63
+ return /* @__PURE__ */ React.createElement(FocusContext.Provider, {
451
64
  value: {
452
65
  setFocus: setState
453
66
  }
454
- }, /* @__PURE__ */ React3.createElement(Root2, {
67
+ }, /* @__PURE__ */ React.createElement(Root2, {
455
68
  tabIndex: 0,
456
- className: mx3(styles2.container.root, className, classNames),
69
+ className: mx(styles.container.root, className, classNames),
457
70
  ...tabsterAttrs,
458
71
  ...state && {
459
72
  [`data-${FOCUS_STATE_ATTR}`]: state
@@ -467,26 +80,29 @@ var Focus = {
467
80
  };
468
81
 
469
82
  // src/components/Mosaic/styles.ts
470
- var styles3 = {
83
+ var styles2 = {
471
84
  placeholder: {
472
85
  root: [
473
86
  "group opacity-0",
474
- 'group-data-[mosaic-debug="true"]:bg-orange-500',
475
87
  'group-data-[mosaic-debug="true"]:opacity-100',
88
+ 'group-data-[mosaic-debug="true"]:bg-orange-500',
476
89
  "data-[mosaic-placeholder-state=active]:opacity-100",
477
- "data-[mosaic-placeholder-axis=vertical]:plb-1",
478
- "data-[mosaic-placeholder-axis=vertical]:data-[mosaic-placeholder-state=active]:plb-2.5",
479
- "data-[mosaic-placeholder-axis=horizontal]:pli-1",
480
- "data-[mosaic-placeholder-axis=horizontal]:data-[mosaic-placeholder-state=active]:pli-2.5"
90
+ "data-[mosaic-placeholder-orientation=vertical]:snap-start",
91
+ "data-[mosaic-placeholder-orientation=vertical]:plb-1",
92
+ "data-[mosaic-placeholder-orientation=vertical]:data-[mosaic-placeholder-state=active]:plb-2.5",
93
+ "data-[mosaic-placeholder-orientation=horizontal]:pli-1",
94
+ "data-[mosaic-placeholder-orientation=horizontal]:data-[mosaic-placeholder-state=active]:pli-2.5"
481
95
  ],
482
- // TODO(burdon): Don't animate open if placeholder is the source.
483
96
  content: [
484
97
  "transition-all duration-0",
485
- "group-data-[mosaic-placeholder-state=active]:duration-200",
486
- "group-data-[mosaic-placeholder-axis=vertical]:bs-0",
487
- "group-data-[mosaic-placeholder-axis=horizontal]:is-0",
488
- "group-data-[mosaic-placeholder-axis=vertical]:group-data-[mosaic-placeholder-state=active]:bs-[var(--mosaic-placeholder-height)]",
489
- "group-data-[mosaic-placeholder-axis=horizontal]:group-data-[mosaic-placeholder-state=active]:is-[var(--mosaic-placeholder-width)]"
98
+ // TODO(burdon): Don't animate open if placeholder is the source.
99
+ // TODO(burdon): Flickers when start to drag since source is removed and then the placeholder shows up.
100
+ // - Use absolute positioning?
101
+ // 'group-data-[mosaic-placeholder-state=active]:duration-200',
102
+ "group-data-[mosaic-placeholder-orientation=vertical]:bs-0",
103
+ "group-data-[mosaic-placeholder-orientation=vertical]:group-data-[mosaic-placeholder-state=active]:bs-[var(--mosaic-placeholder-height)]",
104
+ "group-data-[mosaic-placeholder-orientation=horizontal]:is-0",
105
+ "group-data-[mosaic-placeholder-orientation=horizontal]:group-data-[mosaic-placeholder-state=active]:is-[var(--mosaic-placeholder-width)]"
490
106
  ]
491
107
  }
492
108
  };
@@ -619,32 +235,9 @@ var dropField = StateField.define({
619
235
 
620
236
  // src/components/Stack/Stack.tsx
621
237
  import { useVirtualizer } from "@tanstack/react-virtual";
622
- import React6, { Fragment, forwardRef as forwardRef5 } from "react";
238
+ import React5, { Fragment, forwardRef as forwardRef4 } from "react";
623
239
  import { invariant } from "@dxos/invariant";
624
- import { mx as mx6 } from "@dxos/ui-theme";
625
-
626
- // src/hooks/useVisibleItems.ts
627
- import { useMemo } from "react";
628
- var useVisibleItems = ({ id, items, dragging, getId }) => {
629
- const visibleItems = useMemo(() => {
630
- if (!items || !dragging || id !== dragging.containerId) {
631
- return items ?? [];
632
- }
633
- const idx = items.findIndex((item) => getId(item) === dragging.id);
634
- if (idx === -1) {
635
- return items;
636
- }
637
- const visibleItems2 = items.slice();
638
- visibleItems2.splice(idx, 1);
639
- return visibleItems2;
640
- }, [
641
- id,
642
- items,
643
- dragging,
644
- getId
645
- ]);
646
- return visibleItems;
647
- };
240
+ import { mx as mx5 } from "@dxos/ui-theme";
648
241
 
649
242
  // src/components/Mosaic/Mosaic.tsx
650
243
  import { combine } from "@atlaskit/pragmatic-drag-and-drop/combine";
@@ -655,100 +248,29 @@ import { autoScrollForElements } from "@atlaskit/pragmatic-drag-and-drop-auto-sc
655
248
  import { attachClosestEdge, extractClosestEdge } from "@atlaskit/pragmatic-drag-and-drop-hitbox/closest-edge";
656
249
  import { DropIndicator as NativeDropIndicator } from "@atlaskit/pragmatic-drag-and-drop-react-drop-indicator/box";
657
250
  import { composeRefs, useComposedRefs as useComposedRefs2 } from "@radix-ui/react-compose-refs";
658
- import { createContext as createContext3 } from "@radix-ui/react-context";
251
+ import { createContext as createContext2 } from "@radix-ui/react-context";
659
252
  import { Primitive as Primitive2 } from "@radix-ui/react-primitive";
660
- import { Slot as Slot3 } from "@radix-ui/react-slot";
253
+ import { Slot as Slot2 } from "@radix-ui/react-slot";
661
254
  import { bind } from "bind-event-listener";
662
- import React5, { forwardRef as forwardRef4, useCallback as useCallback2, useEffect as useEffect2, useLayoutEffect, useMemo as useMemo3, useRef as useRef4, useState as useState3 } from "react";
255
+ import React2, { forwardRef as forwardRef2, useCallback, useEffect, useLayoutEffect, useMemo as useMemo2, useRef as useRef2, useState as useState2 } from "react";
663
256
  import { createPortal } from "react-dom";
664
257
  import { log } from "@dxos/log";
665
- import { Json } from "@dxos/react-ui-syntax-highlighter";
666
- import { mx as mx5 } from "@dxos/ui-theme";
258
+ import { mx as mx2 } from "@dxos/ui-theme";
667
259
  import { isTruthy } from "@dxos/util";
668
-
669
- // src/components/Scrollable/Scrollable.tsx
670
- import { OverlayScrollbarsComponent } from "overlayscrollbars-react";
671
- import React4, { forwardRef as forwardRef3, useEffect, useMemo as useMemo2, useRef as useRef3 } from "react";
672
- import { mx as mx4 } from "@dxos/ui-theme";
673
- import "overlayscrollbars/styles/overlayscrollbars.css";
674
- var defaultOptions = {
675
- scrollbars: {
676
- autoHide: "leave",
677
- autoHideDelay: 1e3,
678
- autoHideSuspend: true
679
- }
680
- };
681
- var Scrollable = /* @__PURE__ */ forwardRef3(({ classNames, axis = "vertical", padding, options: optionsProp = defaultOptions, onScroll, viewportRef, ...props }, forwardedRef) => {
682
- const osRef = useRef3(null);
683
- const options = useMemo2(() => {
684
- const options2 = {
685
- ...optionsProp
686
- };
687
- if (axis) {
688
- options2.overflow = {
689
- x: axis === "horizontal" ? "scroll" : "hidden",
690
- y: axis === "vertical" ? "scroll" : "hidden"
691
- };
692
- }
693
- return options2;
694
- }, [
695
- axis,
696
- optionsProp
697
- ]);
698
- useEffect(() => {
699
- const hostElement = osRef.current?.getElement();
700
- if (forwardedRef) {
701
- if (typeof forwardedRef === "function") {
702
- forwardedRef(hostElement ?? null);
703
- } else {
704
- forwardedRef.current = hostElement ?? null;
705
- }
706
- }
707
- });
708
- useEffect(() => {
709
- const instance = osRef.current?.osInstance();
710
- if (viewportRef) {
711
- viewportRef.current = instance?.elements().viewport ?? null;
712
- }
713
- }, [
714
- osRef,
715
- viewportRef
716
- ]);
717
- const events = useMemo2(() => {
718
- if (!onScroll) {
719
- return null;
720
- }
721
- return {
722
- scroll: (_, event) => {
723
- onScroll(event);
724
- }
725
- };
726
- }, [
727
- onScroll
728
- ]);
729
- return /* @__PURE__ */ React4.createElement(OverlayScrollbarsComponent, {
730
- ...props,
731
- className: mx4(padding && axis === "vertical" ? "pli-3" : "pbe-3", classNames),
732
- options,
733
- events,
734
- ref: osRef
735
- });
736
- });
737
-
738
- // src/components/Mosaic/Mosaic.tsx
739
260
  var __dxlog_file = "/__w/dxos/dxos/packages/ui/react-ui-mosaic/src/components/Mosaic/Mosaic.tsx";
740
261
  var getSourceData = (source) => {
741
262
  return source.data.type === "tile" ? source.data : null;
742
263
  };
743
- var [RootContextProvider, useRootContext] = createContext3("MosaicRoot");
264
+ var [RootContextProvider, useRootContext] = createContext2("MosaicRoot");
265
+ var ROOT_NAME = "Mosaic.Root";
744
266
  var ROOT_DEBUG_ATTR = "mosaic-debug";
745
- var Root = /* @__PURE__ */ forwardRef4(({ classNames, children, asChild, debug }, forwardedRef) => {
746
- const rootRef = useRef4(null);
267
+ var Root = /* @__PURE__ */ forwardRef2(({ classNames, children, asChild, debug }, forwardedRef) => {
268
+ const rootRef = useRef2(null);
747
269
  const composedRef = useComposedRefs2(rootRef, forwardedRef);
748
- const Root2 = asChild ? Slot3 : Primitive2.div;
749
- const [handlers, setHandlers] = useState3({});
750
- const [dragging, setDragging] = useState3();
751
- const getSourceHandler = useCallback2((source) => {
270
+ const Root2 = asChild ? Slot2 : Primitive2.div;
271
+ const [handlers, setHandlers] = useState2({});
272
+ const [dragging, setDragging] = useState2();
273
+ const getSourceHandler = useCallback((source) => {
752
274
  const data = source.data;
753
275
  return {
754
276
  data,
@@ -757,7 +279,7 @@ var Root = /* @__PURE__ */ forwardRef4(({ classNames, children, asChild, debug }
757
279
  }, [
758
280
  handlers
759
281
  ]);
760
- const getTargetHandler = useCallback2((location) => {
282
+ const getTargetHandler = useCallback((location) => {
761
283
  for (const target of location.current.dropTargets) {
762
284
  const data = target.data;
763
285
  let containerId;
@@ -782,7 +304,7 @@ var Root = /* @__PURE__ */ forwardRef4(({ classNames, children, asChild, debug }
782
304
  }, [
783
305
  handlers
784
306
  ]);
785
- useEffect2(() => {
307
+ useEffect(() => {
786
308
  const handleChange = ({ source, location }) => {
787
309
  const { data: sourceData } = getSourceHandler(source);
788
310
  const { data: targetData, handler } = getTargetHandler(location);
@@ -802,7 +324,19 @@ var Root = /* @__PURE__ */ forwardRef4(({ classNames, children, asChild, debug }
802
324
  };
803
325
  });
804
326
  };
805
- return monitorForElements({
327
+ const handleCancel = () => {
328
+ setDragging((dragging2) => {
329
+ requestAnimationFrame(() => {
330
+ dragging2?.target?.handler?.onCancel?.();
331
+ dragging2?.source?.container?.dispatchEvent(new CustomEvent("dnd:cancel", {
332
+ bubbles: true
333
+ }));
334
+ });
335
+ return void 0;
336
+ });
337
+ };
338
+ let noTargetTimeout;
339
+ return combine(monitorForElements({
806
340
  /**
807
341
  * Dragging started within any container.
808
342
  */
@@ -812,7 +346,7 @@ var Root = /* @__PURE__ */ forwardRef4(({ classNames, children, asChild, debug }
812
346
  location: location.current.dropTargets.map((target) => target.data)
813
347
  }, {
814
348
  F: __dxlog_file,
815
- L: 203,
349
+ L: 219,
816
350
  S: void 0,
817
351
  C: (f, a) => f(...a)
818
352
  });
@@ -825,19 +359,24 @@ var Root = /* @__PURE__ */ forwardRef4(({ classNames, children, asChild, debug }
825
359
  * Dragging entered a new container.
826
360
  */
827
361
  onDropTargetChange: ({ source, location }) => {
362
+ clearTimeout(noTargetTimeout);
828
363
  log("Root.onDropTargetChange", {
829
364
  source: source.data,
830
365
  location: location.current.dropTargets.map((target) => target.data)
831
366
  }, {
832
367
  F: __dxlog_file,
833
- L: 215,
368
+ L: 232,
834
369
  S: void 0,
835
370
  C: (f, a) => f(...a)
836
371
  });
837
- handleChange({
838
- source,
839
- location
840
- });
372
+ if (location.current.dropTargets.length === 0) {
373
+ noTargetTimeout = setTimeout(() => setDragging(void 0), 1e3);
374
+ } else {
375
+ handleChange({
376
+ source,
377
+ location
378
+ });
379
+ }
841
380
  },
842
381
  /**
843
382
  * Dragging within any container.
@@ -860,12 +399,12 @@ var Root = /* @__PURE__ */ forwardRef4(({ classNames, children, asChild, debug }
860
399
  * Dragging ended.
861
400
  */
862
401
  onDrop: ({ source, location }) => {
863
- log("Root.onDrop", {
402
+ log.info("Root.onDrop", {
864
403
  source: source.data,
865
404
  location: location.current.dropTargets.map((target) => target.data)
866
405
  }, {
867
406
  F: __dxlog_file,
868
- L: 239,
407
+ L: 261,
869
408
  S: void 0,
870
409
  C: (f, a) => f(...a)
871
410
  });
@@ -876,14 +415,21 @@ var Root = /* @__PURE__ */ forwardRef4(({ classNames, children, asChild, debug }
876
415
  handlers: Object.keys(handlers)
877
416
  }, {
878
417
  F: __dxlog_file,
879
- L: 247,
418
+ L: 269,
880
419
  S: void 0,
881
420
  C: (f, a) => f(...a)
882
421
  });
883
422
  return;
884
423
  }
885
424
  try {
886
- if (location.current.dropTargets.length > 0) {
425
+ if (location.current.dropTargets.length === 0) {
426
+ log.info("cancelled", void 0, {
427
+ F: __dxlog_file,
428
+ L: 284,
429
+ S: void 0,
430
+ C: (f, a) => f(...a)
431
+ });
432
+ } else {
887
433
  const { data: targetData, handler: targetHandler } = getTargetHandler(location);
888
434
  if (!targetHandler) {
889
435
  log.warn("invalid target", {
@@ -892,7 +438,7 @@ var Root = /* @__PURE__ */ forwardRef4(({ classNames, children, asChild, debug }
892
438
  handlers: Object.keys(handlers)
893
439
  }, {
894
440
  F: __dxlog_file,
895
- L: 260,
441
+ L: 289,
896
442
  S: void 0,
897
443
  C: (f, a) => f(...a)
898
444
  });
@@ -909,7 +455,7 @@ var Root = /* @__PURE__ */ forwardRef4(({ classNames, children, asChild, debug }
909
455
  source: sourceData
910
456
  }, {
911
457
  F: __dxlog_file,
912
- L: 276,
458
+ L: 305,
913
459
  S: void 0,
914
460
  C: (f, a) => f(...a)
915
461
  });
@@ -919,7 +465,6 @@ var Root = /* @__PURE__ */ forwardRef4(({ classNames, children, asChild, debug }
919
465
  source: sourceData
920
466
  }, async (object) => {
921
467
  targetHandler.onDrop?.({
922
- // TODO(burdon): Change source!!!
923
468
  source: {
924
469
  ...sourceData,
925
470
  data: object
@@ -931,24 +476,16 @@ var Root = /* @__PURE__ */ forwardRef4(({ classNames, children, asChild, debug }
931
476
  }
932
477
  }
933
478
  } finally {
934
- setDragging((dragging2) => {
935
- requestAnimationFrame(() => {
936
- dragging2?.target?.handler?.onCancel?.();
937
- dragging2?.source?.container?.dispatchEvent(new CustomEvent("dnd:cancel", {
938
- bubbles: true
939
- }));
940
- });
941
- return void 0;
942
- });
479
+ handleCancel();
943
480
  }
944
481
  }
945
- });
482
+ }));
946
483
  }, [
947
484
  handlers,
948
485
  getSourceHandler,
949
486
  getTargetHandler
950
487
  ]);
951
- return /* @__PURE__ */ React5.createElement(RootContextProvider, {
488
+ return /* @__PURE__ */ React2.createElement(RootContextProvider, {
952
489
  containers: handlers,
953
490
  addContainer: (container) => setHandlers((containers) => ({
954
491
  ...containers,
@@ -961,34 +498,36 @@ var Root = /* @__PURE__ */ forwardRef4(({ classNames, children, asChild, debug }
961
498
  };
962
499
  }),
963
500
  dragging
964
- }, /* @__PURE__ */ React5.createElement(Root2, {
965
- className: mx5("group overflow-hidden", classNames),
501
+ }, /* @__PURE__ */ React2.createElement(Root2, {
502
+ className: mx2("group", classNames),
966
503
  [`data-${ROOT_DEBUG_ATTR}`]: debug,
967
504
  ref: composedRef
968
505
  }, children));
969
506
  });
970
- var [ContainerContextProvider, useContainerContext] = createContext3("MosaicContainer");
507
+ Root.displayName = ROOT_NAME;
508
+ var CONTAINER_NAME = "Mosaic.Container";
509
+ var [ContainerContextProvider, useContainerContext] = createContext2("MosaicContainer");
971
510
  var CONTAINER_STATE_ATTR = "mosaic-container-state";
972
511
  var CONTAINER_PLACEHOLDER_WIDTH = "--mosaic-placeholder-width";
973
512
  var CONTAINER_PLACEHOLDER_HEIGHT = "--mosaic-placeholder-height";
974
513
  var counter = 0;
975
- var Container = /* @__PURE__ */ forwardRef4(({ className, classNames, children, eventHandler: eventHandlerProp, axis = "vertical", asChild, autoScroll: autoscrollElement, withFocus, debug, ...props }, forwardedRef) => {
976
- const rootRef = useRef4(null);
514
+ var Container = /* @__PURE__ */ forwardRef2(({ className, classNames, children, eventHandler: eventHandlerProp, orientation = "vertical", asChild, autoScroll: autoscrollElement, withFocus, debug, ...props }, forwardedRef) => {
515
+ const rootRef = useRef2(null);
977
516
  const composedRef = useComposedRefs2(rootRef, forwardedRef);
978
- const Root2 = asChild ? Slot3 : Primitive2.div;
979
- const eventHandler = useMemo3(() => eventHandlerProp ?? {
517
+ const Root2 = asChild ? Slot2 : Primitive2.div;
518
+ const eventHandler = useMemo2(() => eventHandlerProp ?? {
980
519
  id: `mosaic-container-${counter++}`
981
520
  }, [
982
521
  eventHandlerProp
983
522
  ]);
984
- const { dragging } = useRootContext(Container.displayName);
985
- const [state, setState] = useState3({
523
+ const { dragging } = useRootContext(CONTAINER_NAME);
524
+ const [state, setState] = useState2({
986
525
  type: "idle"
987
526
  });
988
- const [activeLocation, setActiveLocation] = useState3();
989
- const [scrolling, setScrolling] = useState3(false);
527
+ const [activeLocation, setActiveLocation] = useState2();
528
+ const [scrolling, setScrolling] = useState2(false);
990
529
  const { setFocus } = useFocus();
991
- useEffect2(() => {
530
+ useEffect(() => {
992
531
  if (withFocus) {
993
532
  setFocus?.(state.type === "active" ? "active" : void 0);
994
533
  }
@@ -998,19 +537,19 @@ var Container = /* @__PURE__ */ forwardRef4(({ className, classNames, children,
998
537
  state
999
538
  ]);
1000
539
  const { addContainer, removeContainer } = useRootContext(eventHandler.id);
1001
- useEffect2(() => {
540
+ useEffect(() => {
1002
541
  addContainer(eventHandler);
1003
542
  return () => removeContainer(eventHandler.id);
1004
543
  }, [
1005
544
  eventHandler
1006
545
  ]);
1007
- const data = useMemo3(() => ({
546
+ const data = useMemo2(() => ({
1008
547
  type: "container",
1009
548
  id: eventHandler.id
1010
549
  }), [
1011
550
  eventHandler.id
1012
551
  ]);
1013
- useEffect2(() => {
552
+ useEffect(() => {
1014
553
  if (!rootRef.current) {
1015
554
  return;
1016
555
  }
@@ -1023,23 +562,17 @@ var Container = /* @__PURE__ */ forwardRef4(({ className, classNames, children,
1023
562
  }, 500);
1024
563
  };
1025
564
  return combine(...[
1026
- autoscrollElement && [
1027
- autoScrollForElements({
1028
- element: autoscrollElement,
1029
- canScroll: ({ element: _ }) => {
1030
- return true;
1031
- },
1032
- getAllowedAxis: () => axis,
1033
- getConfiguration: () => ({
1034
- maxScrollSpeed: "fast"
1035
- })
1036
- }),
1037
- bind(autoscrollElement, {
1038
- type: "scroll",
1039
- listener: handleScroll
1040
- }),
1041
- () => setScrolling(false)
1042
- ],
565
+ /**
566
+ * Custom event for dragging cancellation.
567
+ */
568
+ bind(rootRef.current, {
569
+ type: "dnd:cancel",
570
+ listener: () => {
571
+ setState({
572
+ type: "idle"
573
+ });
574
+ }
575
+ }),
1043
576
  // Target.
1044
577
  dropTargetForElements({
1045
578
  element: rootRef.current,
@@ -1100,17 +633,26 @@ var Container = /* @__PURE__ */ forwardRef4(({ className, classNames, children,
1100
633
  });
1101
634
  }
1102
635
  }),
1103
- /**
1104
- * Custom event for dragging cancellation.
1105
- */
1106
- bind(rootRef.current, {
1107
- type: "dnd:cancel",
1108
- listener: () => {
1109
- setState({
1110
- type: "idle"
1111
- });
1112
- }
1113
- })
636
+ // Autoscroll.
637
+ // NOTE: When used with Scrollable we get a spurious warning (in dev mode).
638
+ // "Auto scrolling has been attached to an element that appears not to be scrollable."
639
+ autoscrollElement && [
640
+ autoScrollForElements({
641
+ element: autoscrollElement,
642
+ // canScroll: ({ element: _ }) => {
643
+ // return true;
644
+ // },
645
+ getAllowedAxis: () => orientation,
646
+ getConfiguration: () => ({
647
+ maxScrollSpeed: "fast"
648
+ })
649
+ }),
650
+ bind(autoscrollElement, {
651
+ type: "scroll",
652
+ listener: handleScroll
653
+ }),
654
+ () => setScrolling(false)
655
+ ]
1114
656
  ].filter(isTruthy).flatMap((x) => x));
1115
657
  }, [
1116
658
  rootRef,
@@ -1118,17 +660,17 @@ var Container = /* @__PURE__ */ forwardRef4(({ className, classNames, children,
1118
660
  data,
1119
661
  autoscrollElement
1120
662
  ]);
1121
- return /* @__PURE__ */ React5.createElement(ContainerContextProvider, {
663
+ return /* @__PURE__ */ React2.createElement(ContainerContextProvider, {
1122
664
  id: eventHandler.id,
1123
665
  eventHandler,
1124
- axis,
666
+ orientation,
1125
667
  state,
1126
668
  dragging: state.type === "active" ? dragging : void 0,
1127
669
  scrolling,
1128
670
  activeLocation,
1129
671
  setActiveLocation
1130
- }, /* @__PURE__ */ React5.createElement(Root2, {
1131
- className: mx5("bs-full", className, classNames),
672
+ }, /* @__PURE__ */ React2.createElement(Root2, {
673
+ className: mx2("bs-full", className, classNames),
1132
674
  style: {
1133
675
  [CONTAINER_PLACEHOLDER_WIDTH]: state.type === "active" && state.bounds ? `${state.bounds.width}px` : "0px",
1134
676
  [CONTAINER_PLACEHOLDER_HEIGHT]: state.type === "active" && state.bounds ? `${state.bounds.height}px` : "0px"
@@ -1138,56 +680,19 @@ var Container = /* @__PURE__ */ forwardRef4(({ className, classNames, children,
1138
680
  ref: composedRef
1139
681
  }, children), debug?.());
1140
682
  });
1141
- Container.displayName = "MosaicContainer";
1142
- var useContainerDebug = (debug) => {
1143
- const debugRef = useRef4(null);
1144
- return useMemo3(() => {
1145
- if (!debug) {
1146
- return [
1147
- () => null,
1148
- void 0
1149
- ];
1150
- }
1151
- return [
1152
- ({ classNames }) => /* @__PURE__ */ React5.createElement("div", {
1153
- role: "none",
1154
- className: mx5("overflow-hidden", classNames),
1155
- ref: debugRef
1156
- }),
1157
- () => debugRef.current && /* @__PURE__ */ createPortal(/* @__PURE__ */ React5.createElement(ContainerInfo, null), debugRef.current)
1158
- ];
1159
- }, [
1160
- debug,
1161
- debugRef
1162
- ]);
1163
- };
1164
- var ContainerInfo = /* @__PURE__ */ forwardRef4(({ classNames }, forwardedRef) => {
1165
- const { id, state, activeLocation, scrolling } = useContainerContext(ContainerInfo.displayName);
1166
- const counter2 = useRef4(0);
1167
- return /* @__PURE__ */ React5.createElement(Json, {
1168
- data: {
1169
- id,
1170
- activeLocation,
1171
- scrolling,
1172
- state,
1173
- count: counter2.current++
1174
- },
1175
- classNames: mx5("text-xs", classNames),
1176
- ref: forwardedRef
1177
- });
1178
- });
1179
- ContainerInfo.displayName = "ContainerInfo";
1180
- var [TileContextProvider, useTileContext] = createContext3("MosaicTile");
683
+ Container.displayName = CONTAINER_NAME;
684
+ var TILE_NAME = "Mosaic.Tile";
685
+ var [TileContextProvider, useTileContext] = createContext2("MosaicTile");
1181
686
  var TILE_STATE_ATTR = "mosaic-tile-state";
1182
- var Tile = /* @__PURE__ */ forwardRef4(({ className, classNames, children, asChild, dragHandle, allowedEdges: allowedEdgesProp, location, id, data: dataProp, debug: _ }, forwardedRef) => {
1183
- const rootRef = useRef4(null);
687
+ var Tile = /* @__PURE__ */ forwardRef2(({ className, classNames, children, asChild, dragHandle, allowedEdges: allowedEdgesProp, location, id, data: dataProp, debug: _ }, forwardedRef) => {
688
+ const rootRef = useRef2(null);
1184
689
  const composedRef = composeRefs(rootRef, forwardedRef);
1185
- const Root2 = asChild ? Slot3 : Primitive2.div;
1186
- const { id: containerId, eventHandler, axis, scrolling, setActiveLocation } = useContainerContext(Tile.displayName);
1187
- const [state, setState] = useState3({
690
+ const Root2 = asChild ? Slot2 : Primitive2.div;
691
+ const { id: containerId, eventHandler, orientation, scrolling, setActiveLocation } = useContainerContext(TILE_NAME);
692
+ const [state, setState] = useState2({
1188
693
  type: "idle"
1189
694
  });
1190
- const allowedEdges = useMemo3(() => allowedEdgesProp || (axis === "vertical" ? [
695
+ const allowedEdges = useMemo2(() => allowedEdgesProp || (orientation === "vertical" ? [
1191
696
  "top",
1192
697
  "bottom"
1193
698
  ] : [
@@ -1195,9 +700,9 @@ var Tile = /* @__PURE__ */ forwardRef4(({ className, classNames, children, asChi
1195
700
  "right"
1196
701
  ]), [
1197
702
  allowedEdgesProp,
1198
- axis
703
+ orientation
1199
704
  ]);
1200
- const data = useMemo3(() => ({
705
+ const data = useMemo2(() => ({
1201
706
  type: "tile",
1202
707
  id,
1203
708
  containerId,
@@ -1311,152 +816,577 @@ var Tile = /* @__PURE__ */ forwardRef4(({ className, classNames, children, asChi
1311
816
  allowedEdges,
1312
817
  setActiveLocation
1313
818
  ]);
1314
- return /* @__PURE__ */ React5.createElement(TileContextProvider, {
819
+ return /* @__PURE__ */ React2.createElement(TileContextProvider, {
1315
820
  state
1316
- }, /* @__PURE__ */ React5.createElement(Root2, {
821
+ }, /* @__PURE__ */ React2.createElement(Root2, {
1317
822
  [`data-${TILE_STATE_ATTR}`]: state.type,
1318
823
  role: "listitem",
1319
- className: mx5("relative", className, classNames),
824
+ className: mx2("relative", className, classNames),
1320
825
  ref: composedRef
1321
- }, children), state.type === "preview" && /* @__PURE__ */ createPortal(/* @__PURE__ */ React5.createElement(Root2, {
826
+ }, children), state.type === "preview" && /* @__PURE__ */ createPortal(/* @__PURE__ */ React2.createElement(Root2, {
1322
827
  // NOTE: Use to control appearance while dragging.
1323
828
  [`data-${TILE_STATE_ATTR}`]: state.type,
1324
829
  // TODO(burdon): Configure drop animation.
1325
- className: mx5("relative", className, classNames),
830
+ className: mx2("relative", className, classNames),
1326
831
  style: {
1327
832
  width: `${state.rect.width}px`,
1328
833
  height: `${state.rect.height}px`
1329
834
  }
1330
835
  }, children), state.container));
1331
836
  });
1332
- Tile.displayName = "MosaicTile";
1333
- var PLACEHOLDER_AXIS_ATTR = "mosaic-placeholder-axis";
1334
- var PLACEHOLDER_STATE_ATTR = "mosaic-placeholder-state";
1335
- var Placeholder = ({ classNames, children, asChild, axis = "vertical", location }) => {
1336
- const rootRef = useRef4(null);
1337
- const Root2 = asChild ? Slot3 : Primitive2.div;
1338
- const { id: containerId, eventHandler, scrolling, activeLocation, setActiveLocation } = useContainerContext(Placeholder.displayName);
1339
- const data = useMemo3(() => ({
1340
- type: "placeholder",
1341
- containerId,
1342
- location
1343
- }), [
1344
- containerId,
1345
- location
1346
- ]);
1347
- useLayoutEffect(() => {
1348
- const root = rootRef.current;
1349
- if (!root || scrolling) {
1350
- return;
837
+ Tile.displayName = TILE_NAME;
838
+ var PLACEHOLDER_NAME = "Mosaic.Placeholder";
839
+ var PLACEHOLDER_ORIENTATION_ATTR = "mosaic-placeholder-orientation";
840
+ var PLACEHOLDER_STATE_ATTR = "mosaic-placeholder-state";
841
+ var Placeholder = ({ classNames, children, asChild, orientation = "vertical", location }) => {
842
+ const rootRef = useRef2(null);
843
+ const Root2 = asChild ? Slot2 : Primitive2.div;
844
+ const { id: containerId, eventHandler, scrolling, activeLocation, setActiveLocation } = useContainerContext(PLACEHOLDER_NAME);
845
+ const data = useMemo2(() => ({
846
+ type: "placeholder",
847
+ containerId,
848
+ location
849
+ }), [
850
+ containerId,
851
+ location
852
+ ]);
853
+ useLayoutEffect(() => {
854
+ const root = rootRef.current;
855
+ if (!root || scrolling) {
856
+ return;
857
+ }
858
+ return dropTargetForElements({
859
+ element: root,
860
+ getData: () => data,
861
+ canDrop: ({ source }) => {
862
+ const data2 = getSourceData(source);
863
+ return data2 && eventHandler.canDrop?.({
864
+ source: data2
865
+ }) || false;
866
+ },
867
+ onDragEnter: () => {
868
+ setActiveLocation(data.location);
869
+ },
870
+ onDragLeave: () => {
871
+ setActiveLocation(void 0);
872
+ },
873
+ onDrop: () => {
874
+ setActiveLocation(void 0);
875
+ }
876
+ });
877
+ }, [
878
+ rootRef,
879
+ data,
880
+ scrolling,
881
+ setActiveLocation
882
+ ]);
883
+ return /* @__PURE__ */ React2.createElement(Root2, {
884
+ [`data-${PLACEHOLDER_ORIENTATION_ATTR}`]: orientation,
885
+ [`data-${PLACEHOLDER_STATE_ATTR}`]: data.location === activeLocation ? "active" : "idle",
886
+ role: "none",
887
+ className: mx2("relative", classNames),
888
+ ref: rootRef
889
+ }, children);
890
+ };
891
+ Placeholder.displayName = PLACEHOLDER_NAME;
892
+ var DROP_INDICATOR_NAME = "Mosaic.DropIndicator";
893
+ var DropIndicator = (props) => {
894
+ const { state } = useTileContext(DROP_INDICATOR_NAME);
895
+ return state.type === "target" && state.closestEdge ? /* @__PURE__ */ React2.createElement(NativeDropIndicator, {
896
+ ...props,
897
+ edge: state.closestEdge
898
+ }) : null;
899
+ };
900
+ DropIndicator.displayName = DROP_INDICATOR_NAME;
901
+ var Mosaic = {
902
+ Root,
903
+ Container,
904
+ Tile,
905
+ Placeholder,
906
+ DropIndicator,
907
+ Stack,
908
+ VirtualStack
909
+ };
910
+
911
+ // src/translations.ts
912
+ var translationKey = "@dxos/react-ui-mosaic";
913
+ var translations = [
914
+ {
915
+ "en-US": {
916
+ [translationKey]: {
917
+ "add item label": "Add item",
918
+ "delete menu label": "Delete"
919
+ }
920
+ }
921
+ }
922
+ ];
923
+
924
+ // src/components/Card/styles.ts
925
+ var styles3 = {
926
+ root: "group/card relative min-bs-[--rail-item] is-full card-min-width overflow-hidden",
927
+ border: "bg-cardSurface border border-separator dark:border-subduedSeparator rounded-sm dx-focus-ring-group-y-indicator",
928
+ /**
929
+ * Row grid.
930
+ * NOTE: Rows should provide their own line padding (since they may need to encapsulate buttons, etc.)
931
+ */
932
+ grid_3: "grid grid-cols-[var(--rail-item)_minmax(0,1fr)_var(--rail-item)] gap-x-1",
933
+ grid_2: "grid grid-cols-[var(--rail-item)_minmax(0,1fr)] gap-x-1",
934
+ // TODO(burdon): Address density.
935
+ grid_3_coarse: "grid grid-cols-[var(--l0-avatar-size)_minmax(0,1fr)_var(--rail-item)] gap-x-1",
936
+ poster: "max-bs-[200px]"
937
+ };
938
+
939
+ // src/components/Card/Card.tsx
940
+ import { Slot as Slot3 } from "@radix-ui/react-slot";
941
+ import React4, { createContext as createContext3, forwardRef as forwardRef3, useContext as useContext2 } from "react";
942
+ import { Button, DropdownMenu, Icon, Toolbar, useTranslation } from "@dxos/react-ui";
943
+ import { mx as mx4 } from "@dxos/ui-theme";
944
+
945
+ // src/components/Image/Image.tsx
946
+ import React3, { useCallback as useCallback2, useRef as useRef3, useState as useState3 } from "react";
947
+ import { mx as mx3 } from "@dxos/ui-theme";
948
+ var cache = /* @__PURE__ */ new Map();
949
+ var Image = ({ classNames, src, alt = "", crossOrigin = "anonymous", sampleSize = 64, contrast = 0.9 }) => {
950
+ const [crossOriginState, setCrossOriginState] = useState3(crossOrigin);
951
+ const [dominantColor, setDominantColor] = useState3(void 0);
952
+ const [imageLoaded, setImageLoaded] = useState3(false);
953
+ const canvasRef = useRef3(null);
954
+ const handleImageError = () => {
955
+ setCrossOriginState(void 0);
956
+ };
957
+ const handleImageLoad = useCallback2(({ target }) => {
958
+ const rgb = cache.get(src);
959
+ if (rgb) {
960
+ setDominantColor(rgb);
961
+ setImageLoaded(true);
962
+ return;
963
+ }
964
+ const img = target;
965
+ if (!canvasRef.current) {
966
+ return;
967
+ }
968
+ try {
969
+ const color = extractDominantColor(canvasRef.current, img, {
970
+ sampleSize,
971
+ contrast
972
+ });
973
+ if (color) {
974
+ const rgb2 = `rgb(${color[0]}, ${color[1]}, ${color[2]})`;
975
+ cache.set(src, rgb2);
976
+ setDominantColor(rgb2);
977
+ }
978
+ } catch {
979
+ setCrossOriginState(void 0);
980
+ }
981
+ setImageLoaded(true);
982
+ }, [
983
+ sampleSize,
984
+ contrast,
985
+ src
986
+ ]);
987
+ return /* @__PURE__ */ React3.createElement("div", {
988
+ className: mx3(`relative flex is-full justify-center overflow-hidden transition-all duration-700`, classNames),
989
+ style: {
990
+ backgroundColor: dominantColor
991
+ }
992
+ }, /* @__PURE__ */ React3.createElement("canvas", {
993
+ ref: canvasRef,
994
+ style: {
995
+ display: "none"
996
+ },
997
+ "aria-hidden": "true"
998
+ }), /* @__PURE__ */ React3.createElement("div", {
999
+ className: "absolute inset-0 pointer-events-none",
1000
+ style: {
1001
+ background: dominantColor ? `radial-gradient(circle at center, transparent 30%, ${dominantColor} 100%)` : void 0,
1002
+ transition: "opacity 0.7s ease-in-out",
1003
+ opacity: 0.5
1004
+ }
1005
+ }), /* @__PURE__ */ React3.createElement("img", {
1006
+ src,
1007
+ alt,
1008
+ crossOrigin: crossOriginState,
1009
+ onError: handleImageError,
1010
+ onLoad: handleImageLoad,
1011
+ className: mx3("z-10 object-contain transition-opacity duration-500", classNames),
1012
+ style: {
1013
+ opacity: imageLoaded ? 1 : 0
1014
+ }
1015
+ }));
1016
+ };
1017
+ var extractDominantColor = (canvas, img, { sampleSize = 64, contrast = 0.95 }) => {
1018
+ const ctx = canvas.getContext("2d");
1019
+ if (!ctx) {
1020
+ return null;
1021
+ }
1022
+ canvas.width = sampleSize;
1023
+ canvas.height = sampleSize;
1024
+ ctx.drawImage(img, 0, 0, sampleSize, sampleSize);
1025
+ const imageData = ctx.getImageData(0, 0, sampleSize, sampleSize);
1026
+ const pixels = imageData.data;
1027
+ if (isTransparent(pixels, sampleSize)) {
1028
+ return null;
1029
+ }
1030
+ let r = 0;
1031
+ let g = 0;
1032
+ let b = 0;
1033
+ let totalWeight = 0;
1034
+ const cornerSize = Math.floor(sampleSize * 0.125);
1035
+ for (let y = 0; y < sampleSize; y++) {
1036
+ for (let x = 0; x < sampleSize; x++) {
1037
+ const isInTopLeft = x < cornerSize && y < cornerSize;
1038
+ const isInTopRight = x >= sampleSize - cornerSize && y < cornerSize;
1039
+ const isInBottomLeft = x < cornerSize && y >= sampleSize - cornerSize;
1040
+ const isInBottomRight = x >= sampleSize - cornerSize && y >= sampleSize - cornerSize;
1041
+ if (!isInTopLeft && !isInTopRight && !isInBottomLeft && !isInBottomRight) {
1042
+ continue;
1043
+ }
1044
+ const i = (y * sampleSize + x) * 4;
1045
+ const red = pixels[i];
1046
+ const green = pixels[i + 1];
1047
+ const blue = pixels[i + 2];
1048
+ const alpha = pixels[i + 3];
1049
+ if (alpha === 0) continue;
1050
+ const max = Math.max(red, green, blue);
1051
+ const min = Math.min(red, green, blue);
1052
+ const saturation = max === 0 ? 0 : (max - min) / max;
1053
+ const weight = 1 + saturation * 2;
1054
+ r += red * weight;
1055
+ g += green * weight;
1056
+ b += blue * weight;
1057
+ totalWeight += weight;
1058
+ }
1059
+ }
1060
+ if (totalWeight > 0) {
1061
+ r = Math.round(Math.round(r / totalWeight) * contrast);
1062
+ g = Math.round(Math.round(g / totalWeight) * contrast);
1063
+ b = Math.round(Math.round(b / totalWeight) * contrast);
1064
+ return [
1065
+ r,
1066
+ g,
1067
+ b
1068
+ ];
1069
+ }
1070
+ return null;
1071
+ };
1072
+ var isTransparent = (pixels, sampleSize, threshold = 0.5) => {
1073
+ let edgeTransparentPixels = 0;
1074
+ const edgePixels = sampleSize * 4 - 4;
1075
+ for (let x = 0; x < sampleSize; x++) {
1076
+ const topIndex = x * 4;
1077
+ if (pixels[topIndex + 3] === 0) edgeTransparentPixels++;
1078
+ const bottomIndex = ((sampleSize - 1) * sampleSize + x) * 4;
1079
+ if (pixels[bottomIndex + 3] === 0) edgeTransparentPixels++;
1080
+ }
1081
+ for (let y = 1; y < sampleSize - 1; y++) {
1082
+ const leftIndex = y * sampleSize * 4;
1083
+ if (pixels[leftIndex + 3] === 0) edgeTransparentPixels++;
1084
+ const rightIndex = (y * sampleSize + sampleSize - 1) * 4;
1085
+ if (pixels[rightIndex + 3] === 0) edgeTransparentPixels++;
1086
+ }
1087
+ return edgeTransparentPixels / edgePixels > threshold;
1088
+ };
1089
+
1090
+ // src/components/Card/Card.tsx
1091
+ var CardContext = /* @__PURE__ */ createContext3({});
1092
+ var CardRoot = /* @__PURE__ */ forwardRef3(({ children, classNames, className, id, asChild, role = "group", border = true, fullWidth, ...props }, forwardedRef) => {
1093
+ const Root2 = asChild ? Slot3 : "div";
1094
+ return /* @__PURE__ */ React4.createElement(Root2, {
1095
+ ...id && {
1096
+ "data-object-id": id
1097
+ },
1098
+ ...props,
1099
+ role,
1100
+ className: mx4(styles3.root, border && styles3.border, fullWidth && "!max-is-none", className, classNames),
1101
+ ref: forwardedRef
1102
+ }, children);
1103
+ });
1104
+ var CardToolbar = /* @__PURE__ */ forwardRef3(({ children, classNames, density = "fine", ...props }, forwardedRef) => {
1105
+ return /* @__PURE__ */ React4.createElement(Toolbar.Root, {
1106
+ ...props,
1107
+ classNames: [
1108
+ "density-fine bg-transparent",
1109
+ density === "fine" ? styles3.grid_3 : styles3.grid_3_coarse,
1110
+ classNames
1111
+ ],
1112
+ ref: forwardedRef
1113
+ }, children);
1114
+ });
1115
+ var CardToolbarIconButton = Toolbar.IconButton;
1116
+ var CardToolbarSeparator = Toolbar.Separator;
1117
+ var CardDragHandle = /* @__PURE__ */ forwardRef3((_, forwardedRef) => {
1118
+ const { t } = useTranslation(translationKey);
1119
+ return /* @__PURE__ */ React4.createElement(Toolbar.IconButton, {
1120
+ "data-testid": "card-drag-handle",
1121
+ noTooltip: true,
1122
+ iconOnly: true,
1123
+ icon: "ph--dots-six-vertical--regular",
1124
+ variant: "ghost",
1125
+ label: t("drag handle label"),
1126
+ classNames: "cursor-pointer",
1127
+ size: 5,
1128
+ disabled: !forwardedRef,
1129
+ ref: forwardedRef
1130
+ });
1131
+ });
1132
+ var CardClose = /* @__PURE__ */ forwardRef3(({ onClick }, forwardedRef) => {
1133
+ const { t } = useTranslation(translationKey);
1134
+ return /* @__PURE__ */ React4.createElement(Toolbar.IconButton, {
1135
+ iconOnly: true,
1136
+ icon: "ph--x--regular",
1137
+ variant: "ghost",
1138
+ label: t("card close label"),
1139
+ classNames: "cursor-pointer",
1140
+ size: 5,
1141
+ onClick,
1142
+ ref: forwardedRef
1143
+ });
1144
+ });
1145
+ var CardMenu = ({ context, items }) => {
1146
+ const { t } = useTranslation(translationKey);
1147
+ const { menuItems } = useContext2(CardContext) ?? {};
1148
+ const combinedItems = [
1149
+ ...items ?? [],
1150
+ ...menuItems ?? []
1151
+ ];
1152
+ return /* @__PURE__ */ React4.createElement(DropdownMenu.Root, null, /* @__PURE__ */ React4.createElement(DropdownMenu.Trigger, {
1153
+ disabled: !combinedItems.length,
1154
+ asChild: true
1155
+ }, /* @__PURE__ */ React4.createElement(Card.ToolbarIconButton, {
1156
+ iconOnly: true,
1157
+ variant: "ghost",
1158
+ icon: "ph--dots-three-vertical--regular",
1159
+ label: t("action menu label")
1160
+ })), (combinedItems?.length ?? 0) > 0 && /* @__PURE__ */ React4.createElement(DropdownMenu.Portal, null, /* @__PURE__ */ React4.createElement(DropdownMenu.Content, null, /* @__PURE__ */ React4.createElement(DropdownMenu.Viewport, null, combinedItems?.map(({ label, onClick: onSelect }, i) => /* @__PURE__ */ React4.createElement(DropdownMenu.Item, {
1161
+ key: i,
1162
+ onSelect: () => onSelect(context)
1163
+ }, label))), /* @__PURE__ */ React4.createElement(DropdownMenu.Arrow, null))));
1164
+ };
1165
+ var CardTitle = /* @__PURE__ */ forwardRef3(({ children, classNames, className, asChild, role = "heading", ...props }, forwardedRef) => {
1166
+ const Root2 = asChild ? Slot3 : "div";
1167
+ return /* @__PURE__ */ React4.createElement(Root2, {
1168
+ ...props,
1169
+ role,
1170
+ className: mx4("grow truncate", classNames, className),
1171
+ ref: forwardedRef
1172
+ }, children);
1173
+ });
1174
+ var CardContent = /* @__PURE__ */ forwardRef3(({ children, ...props }, forwardedRef) => {
1175
+ return /* @__PURE__ */ React4.createElement("div", {
1176
+ role: "none",
1177
+ className: "contents [&>:last-child]:pbe-1",
1178
+ ...props,
1179
+ ref: forwardedRef
1180
+ }, children);
1181
+ });
1182
+ var CardRow = /* @__PURE__ */ forwardRef3(({ children, classNames, className, role = "none", icon, ...props }, forwardedRef) => {
1183
+ return /* @__PURE__ */ React4.createElement("div", {
1184
+ ...props,
1185
+ role,
1186
+ className: mx4(styles3.grid_2, "pli-1", classNames, className),
1187
+ ref: forwardedRef
1188
+ }, icon && /* @__PURE__ */ React4.createElement(CardIcon, {
1189
+ classNames: "text-subdued",
1190
+ icon
1191
+ }) || /* @__PURE__ */ React4.createElement("div", null), children);
1192
+ });
1193
+ var CardHeading = /* @__PURE__ */ forwardRef3(({ children, classNames, className, asChild, role = "heading", variant = "default", ...props }, forwardedRef) => {
1194
+ const Root2 = asChild ? Slot3 : "div";
1195
+ const variantClassNames = {
1196
+ default: "plb-1",
1197
+ subtitle: "plb-2 text-xs text-description font-medium uppercase"
1198
+ };
1199
+ return /* @__PURE__ */ React4.createElement(Root2, {
1200
+ ...props,
1201
+ role,
1202
+ className: mx4(variantClassNames[variant], classNames, className),
1203
+ ref: forwardedRef
1204
+ }, children);
1205
+ });
1206
+ var CardText = /* @__PURE__ */ forwardRef3(({ children, classNames, className, asChild, role = "none", truncate, variant = "default", ...props }, forwardedRef) => {
1207
+ const Root2 = asChild ? Slot3 : "div";
1208
+ const variantClassNames = {
1209
+ default: {
1210
+ root: "plb-1"
1211
+ },
1212
+ description: {
1213
+ root: "plb-1.5",
1214
+ span: "text-sm text-description line-clamp-3"
1351
1215
  }
1352
- return dropTargetForElements({
1353
- element: root,
1354
- getData: () => data,
1355
- canDrop: ({ source }) => {
1356
- const data2 = getSourceData(source);
1357
- return data2 && eventHandler.canDrop?.({
1358
- source: data2
1359
- }) || false;
1360
- },
1361
- onDragEnter: () => {
1362
- setActiveLocation(data.location);
1363
- },
1364
- onDragLeave: () => {
1365
- setActiveLocation(void 0);
1366
- },
1367
- onDrop: () => {
1368
- setActiveLocation(void 0);
1369
- }
1370
- });
1371
- }, [
1372
- rootRef,
1373
- data,
1374
- scrolling,
1375
- setActiveLocation
1376
- ]);
1377
- return /* @__PURE__ */ React5.createElement(Root2, {
1378
- [`data-${PLACEHOLDER_AXIS_ATTR}`]: axis,
1379
- [`data-${PLACEHOLDER_STATE_ATTR}`]: data.location === activeLocation ? "active" : "idle",
1216
+ };
1217
+ return /* @__PURE__ */ React4.createElement(Root2, {
1218
+ ...props,
1219
+ role,
1220
+ className: mx4("flex overflow-hidden", variantClassNames[variant].root, classNames, className),
1221
+ ref: forwardedRef
1222
+ }, /* @__PURE__ */ React4.createElement("span", {
1223
+ className: mx4(variantClassNames[variant].span, truncate && "truncate")
1224
+ }, children));
1225
+ });
1226
+ var CardPoster = (props) => {
1227
+ const aspect = props.aspect === "auto" ? "aspect-auto" : "aspect-video";
1228
+ if (props.image) {
1229
+ return /* @__PURE__ */ React4.createElement("div", {
1230
+ role: "none",
1231
+ className: "mbe-1"
1232
+ }, /* @__PURE__ */ React4.createElement(Image, {
1233
+ classNames: [
1234
+ styles3.poster,
1235
+ aspect,
1236
+ props.classNames
1237
+ ],
1238
+ src: props.image,
1239
+ alt: props.alt
1240
+ }));
1241
+ }
1242
+ if (props.icon) {
1243
+ return /* @__PURE__ */ React4.createElement("div", {
1244
+ role: "image",
1245
+ className: mx4("grid place-items-center bg-inputSurface text-subdued", styles3.poster, aspect, props.classNames),
1246
+ "aria-label": props.alt
1247
+ }, /* @__PURE__ */ React4.createElement(Icon, {
1248
+ icon: props.icon,
1249
+ size: 10
1250
+ }));
1251
+ }
1252
+ };
1253
+ var CardAction = ({ icon, actionIcon = "ph--arrow-right--regular", label, onClick }) => {
1254
+ return /* @__PURE__ */ React4.createElement("div", {
1380
1255
  role: "none",
1381
- className: mx5("relative", classNames),
1382
- ref: rootRef
1256
+ className: "is-full pli-1"
1257
+ }, /* @__PURE__ */ React4.createElement(Button, {
1258
+ variant: "ghost",
1259
+ classNames: mx4(styles3.grid_3, "!p-0 is-full text-start overflow-hidden"),
1260
+ onClick
1261
+ }, icon ? /* @__PURE__ */ React4.createElement(CardIcon, {
1262
+ classNames: "text-subdued",
1263
+ icon
1264
+ }) : /* @__PURE__ */ React4.createElement("div", null), /* @__PURE__ */ React4.createElement("span", {
1265
+ className: mx4("min-is-0 flex-1 truncate", !actionIcon && "col-span-2")
1266
+ }, label), actionIcon && /* @__PURE__ */ React4.createElement(CardIcon, {
1267
+ icon: actionIcon
1268
+ })));
1269
+ };
1270
+ var CardLink = ({ label, href }) => {
1271
+ return /* @__PURE__ */ React4.createElement("div", {
1272
+ role: "none",
1273
+ className: "is-full pli-1"
1274
+ }, /* @__PURE__ */ React4.createElement("a", {
1275
+ className: mx4(styles3.grid_3, "group !p-0 dx-button dx-focus-ring !min-bs-1"),
1276
+ "data-variant": "ghost",
1277
+ href,
1278
+ target: "_blank",
1279
+ rel: "noreferrer"
1280
+ }, /* @__PURE__ */ React4.createElement(CardIcon, {
1281
+ classNames: "text-subdued",
1282
+ icon: "ph--link--regular"
1283
+ }), /* @__PURE__ */ React4.createElement("span", {
1284
+ className: mx4("min-is-0 flex-1 truncate")
1285
+ }, label), /* @__PURE__ */ React4.createElement(CardIcon, {
1286
+ classNames: "invisible group-hover:visible",
1287
+ icon: "ph--arrow-square-out--regular"
1288
+ })));
1289
+ };
1290
+ var CardIconBlock = ({ classNames, children, role = "none", ...props }) => {
1291
+ return /* @__PURE__ */ React4.createElement("div", {
1292
+ ...props,
1293
+ role,
1294
+ className: mx4("grid bs-[var(--rail-item)] is-[var(--rail-item)] place-items-center", classNames)
1383
1295
  }, children);
1384
1296
  };
1385
- Placeholder.displayName = "MosaicPlaceholder";
1386
- var DropIndicator = (props) => {
1387
- const { state } = useTileContext(DropIndicator.displayName);
1388
- return state.type === "target" && state.closestEdge ? /* @__PURE__ */ React5.createElement(NativeDropIndicator, {
1297
+ var CardIcon = ({ toolbar, ...props }) => {
1298
+ return /* @__PURE__ */ React4.createElement(CardIconBlock, null, /* @__PURE__ */ React4.createElement(Icon, {
1389
1299
  ...props,
1390
- edge: state.closestEdge
1391
- }) : null;
1300
+ size: toolbar ? 5 : 4
1301
+ }));
1392
1302
  };
1393
- DropIndicator.displayName = "MosaicDropIndicator";
1394
- var Mosaic = {
1395
- Root,
1396
- Container,
1397
- ContainerInfo,
1398
- Tile,
1399
- Placeholder,
1400
- DropIndicator,
1401
- // TODO(burdon): Move out of Mosaic namespace?
1402
- Viewport: Scrollable,
1403
- Stack,
1404
- VirtualStack
1303
+ var Card = {
1304
+ Context: CardContext,
1305
+ Root: CardRoot,
1306
+ // Toolbar
1307
+ Toolbar: CardToolbar,
1308
+ ToolbarIconButton: CardToolbarIconButton,
1309
+ ToolbarSeparator: CardToolbarSeparator,
1310
+ DragHandle: CardDragHandle,
1311
+ Title: CardTitle,
1312
+ Close: CardClose,
1313
+ Menu: CardMenu,
1314
+ Icon: CardIcon,
1315
+ IconBlock: CardIconBlock,
1316
+ // Content
1317
+ Content: CardContent,
1318
+ Row: CardRow,
1319
+ Heading: CardHeading,
1320
+ Text: CardText,
1321
+ Poster: CardPoster,
1322
+ Action: CardAction,
1323
+ Link: CardLink
1405
1324
  };
1406
1325
 
1407
1326
  // src/components/Stack/Stack.tsx
1408
1327
  var __dxlog_file2 = "/__w/dxos/dxos/packages/ui/react-ui-mosaic/src/components/Stack/Stack.tsx";
1409
- var StackInner = /* @__PURE__ */ forwardRef5(({ className, classNames, role = "list", axis = "vertical", draggable: draggable2 = true, items, getId, Tile: Tile2, debug, ...props }, forwardedRef) => {
1328
+ var STACK_NAME = "Stack";
1329
+ var StackInner = /* @__PURE__ */ forwardRef4(({ className, classNames, role = "list", orientation: orientationProp = "vertical", draggable: draggable2 = true, items, getId, Tile: Tile2, debug, ...props }, forwardedRef) => {
1410
1330
  invariant(Tile2, void 0, {
1411
1331
  F: __dxlog_file2,
1412
- L: 44,
1332
+ L: 50,
1413
1333
  S: void 0,
1414
1334
  A: [
1415
1335
  "Tile",
1416
1336
  ""
1417
1337
  ]
1418
1338
  });
1419
- const { id, dragging } = useContainerContext(StackInner.displayName);
1339
+ const { id, orientation = orientationProp, dragging } = useContainerContext(STACK_NAME);
1420
1340
  const visibleItems = useVisibleItems({
1421
1341
  id,
1422
1342
  items,
1423
1343
  dragging: dragging?.source.data,
1424
1344
  getId
1425
1345
  });
1426
- return /* @__PURE__ */ React6.createElement("div", {
1346
+ invariant(orientation === "vertical" || orientation === "horizontal", `Invalid orientation: ${orientation}`, {
1347
+ F: __dxlog_file2,
1348
+ L: 53,
1349
+ S: void 0,
1350
+ A: [
1351
+ "orientation === 'vertical' || orientation === 'horizontal'",
1352
+ "`Invalid orientation: ${orientation}`"
1353
+ ]
1354
+ });
1355
+ return /* @__PURE__ */ React5.createElement("div", {
1427
1356
  ...props,
1428
1357
  role,
1429
- className: mx6("flex", axis === "horizontal" && "bs-full [&>*]:shrink-0", axis === "vertical" && "flex-col", classNames, className),
1358
+ className: mx5("flex", orientation === "horizontal" && "bs-full [&>*]:shrink-0", orientation === "vertical" && "flex-col", classNames, className),
1430
1359
  ref: forwardedRef
1431
- }, /* @__PURE__ */ React6.createElement(Placeholder2, {
1432
- axis,
1360
+ }, /* @__PURE__ */ React5.createElement(Placeholder2, {
1361
+ orientation,
1433
1362
  location: 0.5
1434
- }), visibleItems?.map((item, index) => /* @__PURE__ */ React6.createElement(Fragment, {
1363
+ }), visibleItems?.map((item, index) => /* @__PURE__ */ React5.createElement(Fragment, {
1435
1364
  key: getId(item)
1436
- }, /* @__PURE__ */ React6.createElement(Tile2, {
1365
+ }, /* @__PURE__ */ React5.createElement(Tile2, {
1437
1366
  id: getId(item),
1438
1367
  data: item,
1439
1368
  location: index + 1,
1440
1369
  draggable: draggable2,
1441
1370
  debug
1442
- }), /* @__PURE__ */ React6.createElement(Placeholder2, {
1443
- axis,
1371
+ }), /* @__PURE__ */ React5.createElement(Placeholder2, {
1372
+ orientation,
1444
1373
  location: index + 1.5
1445
1374
  }))));
1446
1375
  });
1447
- StackInner.displayName = "Stack";
1376
+ StackInner.displayName = STACK_NAME;
1448
1377
  var Stack = StackInner;
1449
- var VirtualStackInner = /* @__PURE__ */ forwardRef5(({ className, classNames, role = "list", axis = "vertical", items, getId, Tile: Tile2, estimateSize, getScrollElement, overscan = 8, onChange, debug, ...props }, forwardedRef) => {
1378
+ var VIRTUAL_STACK_NAME = "VirtualStackInner";
1379
+ var VirtualStackInner = /* @__PURE__ */ forwardRef4(({ className, classNames, role = "list", orientation = "vertical", items, getId, Tile: Tile2, estimateSize, getScrollElement, overscan = 8, onChange, debug, ...props }, forwardedRef) => {
1450
1380
  invariant(Tile2, void 0, {
1451
1381
  F: __dxlog_file2,
1452
- L: 106,
1382
+ L: 115,
1453
1383
  S: void 0,
1454
1384
  A: [
1455
1385
  "Tile",
1456
1386
  ""
1457
1387
  ]
1458
1388
  });
1459
- const { id, dragging } = useContainerContext(VirtualStackInner.displayName);
1389
+ const { id, dragging } = useContainerContext(VIRTUAL_STACK_NAME);
1460
1390
  const visibleItems = useVisibleItems({
1461
1391
  id,
1462
1392
  items,
@@ -1471,13 +1401,13 @@ var VirtualStackInner = /* @__PURE__ */ forwardRef5(({ className, classNames, ro
1471
1401
  onChange
1472
1402
  });
1473
1403
  const virtualItems = virtualizer.getVirtualItems();
1474
- return /* @__PURE__ */ React6.createElement("div", {
1404
+ return /* @__PURE__ */ React5.createElement("div", {
1475
1405
  ...props,
1476
1406
  role,
1477
- className: mx6("flex", axis === "horizontal" && "bs-full [&>*]:shrink-0", axis === "vertical" && "flex-col", classNames, className),
1407
+ className: mx5("flex", orientation === "horizontal" && "bs-full [&>*]:shrink-0", orientation === "vertical" && "flex-col", classNames, className),
1478
1408
  style: {
1479
1409
  position: "relative",
1480
- ...axis === "vertical" ? {
1410
+ ...orientation === "vertical" ? {
1481
1411
  width: "100%",
1482
1412
  height: virtualizer.getTotalSize()
1483
1413
  } : {
@@ -1488,14 +1418,14 @@ var VirtualStackInner = /* @__PURE__ */ forwardRef5(({ className, classNames, ro
1488
1418
  ref: forwardedRef
1489
1419
  }, virtualItems.map((virtualItem) => {
1490
1420
  const data = visibleItems[Math.floor(virtualItem.index / 2)];
1491
- return /* @__PURE__ */ React6.createElement("div", {
1421
+ return /* @__PURE__ */ React5.createElement("div", {
1492
1422
  key: virtualItem.key,
1493
1423
  "data-index": virtualItem.index,
1494
1424
  style: {
1495
1425
  position: "absolute",
1496
1426
  top: 0,
1497
1427
  left: 0,
1498
- ...axis === "vertical" ? {
1428
+ ...orientation === "vertical" ? {
1499
1429
  width: "100%",
1500
1430
  transform: `translateY(${virtualItem.start}px)`
1501
1431
  } : {
@@ -1504,10 +1434,10 @@ var VirtualStackInner = /* @__PURE__ */ forwardRef5(({ className, classNames, ro
1504
1434
  }
1505
1435
  },
1506
1436
  ref: virtualizer.measureElement
1507
- }, virtualItem.index % 2 === 0 ? /* @__PURE__ */ React6.createElement(Placeholder2, {
1508
- axis,
1437
+ }, virtualItem.index % 2 === 0 ? /* @__PURE__ */ React5.createElement(Placeholder2, {
1438
+ orientation,
1509
1439
  location: Math.floor(virtualItem.index / 2) + 0.5
1510
- }) : /* @__PURE__ */ React6.createElement(Tile2, {
1440
+ }) : /* @__PURE__ */ React5.createElement(Tile2, {
1511
1441
  id: getId(data),
1512
1442
  data,
1513
1443
  location: Math.floor(virtualItem.index / 2) + 1,
@@ -1515,33 +1445,34 @@ var VirtualStackInner = /* @__PURE__ */ forwardRef5(({ className, classNames, ro
1515
1445
  }));
1516
1446
  }));
1517
1447
  });
1518
- VirtualStackInner.displayName = "VirtualStackInner";
1448
+ VirtualStackInner.displayName = VIRTUAL_STACK_NAME;
1519
1449
  var VirtualStack = VirtualStackInner;
1520
1450
  var Placeholder2 = (props) => {
1521
- return /* @__PURE__ */ React6.createElement(Mosaic.Placeholder, {
1451
+ return /* @__PURE__ */ React5.createElement(Mosaic.Placeholder, {
1522
1452
  ...props,
1523
- classNames: styles3.placeholder.root
1524
- }, /* @__PURE__ */ React6.createElement("div", {
1525
- className: mx6("flex bs-full bg-baseSurface border border-dashed border-separator rounded-sm", styles3.placeholder.content)
1453
+ classNames: styles2.placeholder.root
1454
+ }, /* @__PURE__ */ React5.createElement("div", {
1455
+ className: mx5("flex bs-full bg-baseSurface border border-dashed border-separator rounded-sm", styles2.placeholder.content)
1526
1456
  }));
1527
1457
  };
1528
1458
  Placeholder2.displayName = "Placeholder";
1529
1459
 
1530
1460
  export {
1461
+ useVisibleItems,
1531
1462
  styles,
1532
- Image,
1533
- Card,
1534
- styles2,
1535
1463
  useFocus,
1536
1464
  Focus,
1537
- styles3,
1465
+ styles2,
1538
1466
  dropHandler,
1539
1467
  Stack,
1540
1468
  VirtualStack,
1541
1469
  useRootContext,
1542
1470
  useContainerContext,
1543
- useContainerDebug,
1544
1471
  useTileContext,
1545
- Mosaic
1472
+ Mosaic,
1473
+ translationKey,
1474
+ styles3,
1475
+ Image,
1476
+ Card
1546
1477
  };
1547
- //# sourceMappingURL=chunk-FS5LRPMY.mjs.map
1478
+ //# sourceMappingURL=chunk-Y6GU2CCU.mjs.map