@dxos/react-ui-mosaic 0.3.9-main.57b66d1 → 0.3.9-main.58adff6

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.
@@ -5,12 +5,6 @@ import { useContext } from "react";
5
5
  import React, { createContext, useEffect } from "react";
6
6
  var DEFAULT_TRANSITION = 200;
7
7
  var DEFAULT_TYPE = "unknown";
8
- var MosaicOperations = [
9
- "transfer",
10
- "copy",
11
- "rearrange",
12
- "reject"
13
- ];
14
8
  var MosaicContainerContext = /* @__PURE__ */ createContext({
15
9
  id: "never",
16
10
  type: DEFAULT_TYPE
@@ -91,10 +85,6 @@ var Path = {
91
85
  onPath: (path, id) => Path.parts(path).includes(id)
92
86
  };
93
87
 
94
- // packages/ui/react-ui-mosaic/src/mosaic/util/props.ts
95
- var isTileProps = (props) => typeof props.path === "string" && typeof props.item === "object" && props.item ? "id" in props.item && typeof props.item.id === "string" : false;
96
- var isTileComponentProps = (props) => isTileProps(props) && typeof props.operation === "string" && MosaicOperations.includes(props.operation);
97
-
98
88
  // packages/ui/react-ui-mosaic/src/mosaic/util/styles.ts
99
89
  import { CSS } from "@dnd-kit/utilities";
100
90
  var getTransformCSS = (transform) => transform ? CSS.Transform.toString(Object.assign(transform, {
@@ -380,19 +370,19 @@ var MosaicDragOverlay = ({ delay = 200, debug = false, ...overlayProps }) => {
380
370
  useEffect3(() => {
381
371
  if (activeItem) {
382
372
  let container2;
383
- let OverlayComponent2;
373
+ let OverlayComponent3;
384
374
  if (overItem?.path) {
385
375
  container2 = containers[Path.first(overItem.path)];
386
- OverlayComponent2 = container2?.Component;
376
+ OverlayComponent3 = container2?.Component;
387
377
  }
388
- if (!OverlayComponent2) {
378
+ if (!OverlayComponent3) {
389
379
  container2 = containers[Path.first(activeItem.path)];
390
- OverlayComponent2 = container2?.Component ?? DefaultComponent;
380
+ OverlayComponent3 = container2?.Component ?? DefaultComponent;
391
381
  }
392
382
  clearTimeout(timer.current);
393
383
  timer.current = setTimeout(() => setState({
394
384
  container: container2,
395
- OverlayComponent: OverlayComponent2
385
+ OverlayComponent: OverlayComponent3
396
386
  }), timer.current ? delay : 0);
397
387
  } else {
398
388
  setState({});
@@ -402,7 +392,7 @@ var MosaicDragOverlay = ({ delay = 200, debug = false, ...overlayProps }) => {
402
392
  overItem
403
393
  ]);
404
394
  const container = state.container ?? (activeItem && containers[Path.first(activeItem.path)]);
405
- const OverlayComponent = state.OverlayComponent ?? container?.Component;
395
+ const OverlayComponent2 = state.OverlayComponent ?? container?.Component;
406
396
  const FallbackComponent = (activeItem && containers[Path.first(activeItem.path)])?.Component ?? DefaultComponent;
407
397
  return (
408
398
  // TODO(burdon): Set custom animations (e.g., in/out/around).
@@ -412,7 +402,7 @@ var MosaicDragOverlay = ({ delay = 200, debug = false, ...overlayProps }) => {
412
402
  style: {
413
403
  ...container?.getOverlayStyle?.()
414
404
  }
415
- }, activeItem?.path && container && OverlayComponent && /* @__PURE__ */ React5.createElement(OverlayErrorBoundary, {
405
+ }, activeItem?.path && container && OverlayComponent2 && /* @__PURE__ */ React5.createElement(OverlayErrorBoundary, {
416
406
  fallback: /* @__PURE__ */ React5.createElement(FallbackComponent, {
417
407
  ...container.getOverlayProps?.(),
418
408
  item: activeItem.item,
@@ -420,11 +410,10 @@ var MosaicDragOverlay = ({ delay = 200, debug = false, ...overlayProps }) => {
420
410
  operation,
421
411
  active: "overlay"
422
412
  })
423
- }, /* @__PURE__ */ React5.createElement(OverlayComponent, {
413
+ }, /* @__PURE__ */ React5.createElement(OverlayComponent2, {
424
414
  ...container.getOverlayProps?.(),
425
415
  item: activeItem.item,
426
416
  path: activeItem.path,
427
- type: activeItem.type,
428
417
  operation,
429
418
  active: "overlay"
430
419
  }), debug && /* @__PURE__ */ React5.createElement("div", {
@@ -624,12 +613,441 @@ var Mosaic = {
624
613
  // TODO(burdon): Don't export; move to util.
625
614
  Debug
626
615
  };
616
+
617
+ // packages/ui/react-ui-mosaic/src/views/Grid/layout.ts
618
+ var createMatrix = (size, value) => {
619
+ const matrix = [];
620
+ for (let x = 0; x < size.x; x++) {
621
+ matrix.push(Array.from({
622
+ length: size.y
623
+ }, (_, y) => value({
624
+ x,
625
+ y
626
+ })));
627
+ }
628
+ return matrix;
629
+ };
630
+ var getDimension = ({ width, height }, spacing = 0) => ({
631
+ width: width - spacing * 2,
632
+ height: height - spacing * 2
633
+ });
634
+ var getBounds = ({ x, y }, { width, height }, spacing = 0) => ({
635
+ left: x * width + spacing * 2,
636
+ top: y * height + spacing * 2,
637
+ width: width - spacing * 2,
638
+ height: height - spacing * 2
639
+ });
640
+ var getPanelBounds = ({ x, y }, { width, height }, spacing = 0) => ({
641
+ width: x * width + spacing * 2,
642
+ height: y * height + spacing * 2
643
+ });
644
+ var calculateCellWidth = (defaultWidth, screenWidth, options = {
645
+ min: 260,
646
+ max: 400
647
+ }) => {
648
+ return screenWidth > options.min && screenWidth < options.max ? screenWidth : defaultWidth;
649
+ };
650
+
651
+ // packages/ui/react-ui-mosaic/src/views/Grid/Grid.tsx
652
+ import { useDroppable as useDroppable2 } from "@dnd-kit/core";
653
+ import { PlusCircle } from "@phosphor-icons/react";
654
+ import defaultsDeep from "lodash.defaultsdeep";
655
+ import React8, { useState as useState4, useMemo, useEffect as useEffect4 } from "react";
656
+ import { useResizeDetector } from "react-resize-detector";
657
+ import { Button, useMediaQuery } from "@dxos/react-ui";
658
+ import { getSize, mx as mx2 } from "@dxos/react-ui-theme";
659
+ var defaultGridOptions = {
660
+ size: {
661
+ x: 8,
662
+ y: 8
663
+ },
664
+ cellBounds: {
665
+ width: 272,
666
+ height: 272
667
+ },
668
+ spacing: 6
669
+ };
670
+ var Grid = ({ id, items = [], layout = {}, options: opts, margin, square = true, debug, selected: controlledSelected, Component: Component2 = Mosaic.DefaultComponent, className, onDrop, onOver, onSelect, onCreate, onAction }) => {
671
+ const { ref: containerRef, width, height } = useResizeDetector({
672
+ refreshRate: 200
673
+ });
674
+ const options = defaultsDeep({}, opts, defaultGridOptions);
675
+ const { matrix, bounds, cellBounds } = useMemo(() => {
676
+ const cellWidth = calculateCellWidth(options.cellBounds.width, width ?? 0);
677
+ const cellBounds2 = {
678
+ width: cellWidth,
679
+ height: square ? cellWidth : options.cellBounds.height
680
+ };
681
+ return {
682
+ matrix: createMatrix(options.size, ({ x, y }) => ({
683
+ x,
684
+ y
685
+ })),
686
+ bounds: getPanelBounds(options.size, cellBounds2, options.spacing),
687
+ cellBounds: cellBounds2
688
+ };
689
+ }, [
690
+ options,
691
+ width
692
+ ]);
693
+ const [isNotMobile] = useMediaQuery("md");
694
+ const marginSize = margin && !isNotMobile ? Math.max(cellBounds.width, cellBounds.height) : 0;
695
+ const [selected, setSelected] = useState4(controlledSelected);
696
+ useEffect4(() => {
697
+ setSelected(controlledSelected);
698
+ if (controlledSelected) {
699
+ scrollToCenter(controlledSelected);
700
+ }
701
+ }, [
702
+ controlledSelected
703
+ ]);
704
+ const scrollToCenter = (id2) => {
705
+ const item = items.find((item2) => item2.id === id2);
706
+ if (item && width && height) {
707
+ const pos = getBounds(layout[item.id], cellBounds);
708
+ const top = pos.top + marginSize - (height - cellBounds.height) / 2;
709
+ const left = pos.left + marginSize - (width - cellBounds.width) / 2;
710
+ containerRef.current.scrollTo({
711
+ top,
712
+ left,
713
+ behavior: "smooth"
714
+ });
715
+ }
716
+ };
717
+ const handleSelect = (id2) => {
718
+ setSelected(id2);
719
+ scrollToCenter(id2);
720
+ onSelect?.(id2);
721
+ };
722
+ useEffect4(() => {
723
+ if (selected) {
724
+ scrollToCenter(selected);
725
+ }
726
+ }, [
727
+ selected,
728
+ width,
729
+ height
730
+ ]);
731
+ return /* @__PURE__ */ React8.createElement(Mosaic.Container, {
732
+ id,
733
+ Component: Component2,
734
+ getOverlayProps: () => ({
735
+ grow: true
736
+ }),
737
+ getOverlayStyle: () => ({
738
+ display: "flex",
739
+ ...getDimension(cellBounds, options.spacing)
740
+ }),
741
+ onDrop,
742
+ onOver
743
+ }, /* @__PURE__ */ React8.createElement("div", {
744
+ className: mx2("flex grow overflow-auto", className)
745
+ }, /* @__PURE__ */ React8.createElement("div", {
746
+ ref: containerRef,
747
+ className: mx2("grow overflow-auto snap-x md:snap-none snap-mandatory")
748
+ }, /* @__PURE__ */ React8.createElement("div", {
749
+ className: "group block relative",
750
+ style: {
751
+ ...bounds,
752
+ margin: marginSize
753
+ }
754
+ }, matrix && /* @__PURE__ */ React8.createElement("div", {
755
+ style: {
756
+ padding: options.spacing
757
+ }
758
+ }, /* @__PURE__ */ React8.createElement("div", {
759
+ className: "relative"
760
+ }, matrix.map((row) => row.map(({ x, y }) => /* @__PURE__ */ React8.createElement(GridCell, {
761
+ key: `${x}-${y}`,
762
+ path: id,
763
+ position: {
764
+ x,
765
+ y
766
+ },
767
+ bounds: getBounds({
768
+ x,
769
+ y
770
+ }, cellBounds),
771
+ padding: options.spacing,
772
+ onCreate
773
+ }))))), /* @__PURE__ */ React8.createElement("div", null, items.map((item) => {
774
+ const position = layout[item.id] ?? {
775
+ x: 0,
776
+ y: 0
777
+ };
778
+ return /* @__PURE__ */ React8.createElement(Mosaic.DraggableTile, {
779
+ key: item.id,
780
+ item,
781
+ path: id,
782
+ position,
783
+ Component: Component2,
784
+ draggableStyle: {
785
+ position: "absolute",
786
+ ...getBounds(position, cellBounds, options.spacing)
787
+ },
788
+ onSelect: () => handleSelect(item.id),
789
+ onAction
790
+ });
791
+ }))), debug && /* @__PURE__ */ React8.createElement(Mosaic.Debug, {
792
+ data: {
793
+ items: items?.length
794
+ },
795
+ position: "bottom-right"
796
+ }))));
797
+ };
798
+ var GridCell = ({ path, position, bounds, padding, onCreate }) => {
799
+ const { overItem } = useMosaic();
800
+ const isOverContainer = path === overItem?.path;
801
+ const { setNodeRef, isOver } = useDroppable2({
802
+ id: Path.create(path, "cell", `${position.x}-${position.y}`),
803
+ data: {
804
+ path,
805
+ position
806
+ }
807
+ });
808
+ return /* @__PURE__ */ React8.createElement("div", {
809
+ ref: setNodeRef,
810
+ style: {
811
+ ...bounds,
812
+ padding
813
+ },
814
+ className: "absolute flex justify-center items-center grow select-none cursor-pointer"
815
+ }, /* @__PURE__ */ React8.createElement("div", {
816
+ className: mx2("group/cell flex group-hover:flex w-full h-full items-center justify-center", "box-border border-dashed border-4 border-neutral-75 dark:border-neutral-850 rounded-lg", "transition ease-in-out duration-300", isOver && "flex bg-neutral-75 dark:bg-neutral-850 border-neutral-200 dark:border-neutral-800")
817
+ }, /* @__PURE__ */ React8.createElement("div", {
818
+ className: mx2("opacity-10 transition ease-in-out duration-300 group-hover/cell:opacity-100", isOverContainer && "hidden")
819
+ }, onCreate && // TODO(burdon): Style button.
820
+ /* @__PURE__ */ React8.createElement(Button, {
821
+ variant: "ghost",
822
+ onClick: () => onCreate(position)
823
+ }, /* @__PURE__ */ React8.createElement(PlusCircle, {
824
+ className: getSize(8)
825
+ })))));
826
+ };
827
+
828
+ // packages/ui/react-ui-mosaic/src/views/Kanban/Kanban.tsx
829
+ import React9, { forwardRef as forwardRef2, useMemo as useMemo2 } from "react";
830
+ import { Card as Card2 } from "@dxos/react-ui";
831
+ import { groupSurface, mx as mx3 } from "@dxos/react-ui-theme";
832
+ var Kanban = ({ id, columns, Component: TileComponent = Mosaic.DefaultComponent, debug, onDrop }) => {
833
+ const Component2 = useMemo2(() => OverlayComponent(id, TileComponent), [
834
+ id,
835
+ TileComponent
836
+ ]);
837
+ return /* @__PURE__ */ React9.createElement(Mosaic.Container, {
838
+ id,
839
+ debug,
840
+ Component: Component2,
841
+ // Restrict columns to x-axis.
842
+ modifier: ({ path, item }, { transform }) => path === Path.create(id, item.id) ? {
843
+ ...transform,
844
+ y: 0
845
+ } : transform,
846
+ // Restrict to objects from other columns.
847
+ // TODO(burdon): Consider objects from other containers.
848
+ // TODO(wittjosiah): Allow override.
849
+ onOver: ({ active, over }) => Path.length(active.path) >= Path.length(over.path) ? "transfer" : "reject",
850
+ onDrop
851
+ }, /* @__PURE__ */ React9.createElement("div", {
852
+ className: "grow flex overflow-y-hidden overflow-x-auto"
853
+ }, /* @__PURE__ */ React9.createElement("div", {
854
+ className: "flex"
855
+ }, /* @__PURE__ */ React9.createElement(Mosaic.SortableContext, {
856
+ items: columns,
857
+ direction: "horizontal"
858
+ }, columns.map((column, index) => /* @__PURE__ */ React9.createElement(Mosaic.SortableTile, {
859
+ key: column.id,
860
+ item: column,
861
+ path: id,
862
+ position: index,
863
+ Component: Component2,
864
+ debug
865
+ }))))));
866
+ };
867
+ var OverlayComponent = (id, Component2) => /* @__PURE__ */ forwardRef2((props, ref) => {
868
+ const isColumn = Path.hasRoot(props.path, id) && Path.length(props.path) === 2;
869
+ if (isColumn && props.active === "overlay") {
870
+ return (
871
+ // Needs to not override the main kanban path.
872
+ /* @__PURE__ */ React9.createElement(Mosaic.Container, {
873
+ id: `${id}-active`,
874
+ Component: Component2
875
+ }, /* @__PURE__ */ React9.createElement(KanbanColumnComponent, {
876
+ ...props,
877
+ ref
878
+ }))
879
+ );
880
+ }
881
+ return isColumn ? /* @__PURE__ */ React9.createElement(KanbanColumnComponent, {
882
+ ...props,
883
+ ref
884
+ }) : /* @__PURE__ */ React9.createElement(Component2, {
885
+ ...props,
886
+ ref
887
+ });
888
+ });
889
+ var KanbanColumnComponent = /* @__PURE__ */ forwardRef2(({ path, item, active, draggableStyle, draggableProps, debug }, forwardRef1) => {
890
+ const { id, title, items } = item;
891
+ const { Component: Component2 } = useContainer();
892
+ const itemsWithPreview = useItemsWithPreview({
893
+ path,
894
+ items
895
+ });
896
+ return /* @__PURE__ */ React9.createElement("div", {
897
+ role: "none",
898
+ className: "grow flex flex-col",
899
+ ref: forwardRef1
900
+ }, /* @__PURE__ */ React9.createElement("div", {
901
+ className: mx3(groupSurface, "grow flex flex-col w-[300px] snap-center overflow-hidden m-1", active === "rearrange" && "opacity-0"),
902
+ style: draggableStyle
903
+ }, /* @__PURE__ */ React9.createElement(Card2.Root, {
904
+ classNames: "shrink-0 bg-cyan-200"
905
+ }, /* @__PURE__ */ React9.createElement(Card2.Header, null, /* @__PURE__ */ React9.createElement(Card2.DragHandle, draggableProps), /* @__PURE__ */ React9.createElement(Card2.Title, {
906
+ title
907
+ }), /* @__PURE__ */ React9.createElement(Card2.Menu, null))), /* @__PURE__ */ React9.createElement("div", {
908
+ className: mx3("flex flex-col grow overflow-y-scroll")
909
+ }, /* @__PURE__ */ React9.createElement("div", {
910
+ className: "flex flex-col my-1"
911
+ }, /* @__PURE__ */ React9.createElement(Mosaic.SortableContext, {
912
+ id: path,
913
+ items: itemsWithPreview,
914
+ direction: "vertical"
915
+ }, itemsWithPreview.map((item2, index) => /* @__PURE__ */ React9.createElement(Mosaic.SortableTile, {
916
+ key: item2.id,
917
+ item: item2,
918
+ path,
919
+ position: index,
920
+ Component: Component2,
921
+ className: "m-1"
922
+ }))))), debug && /* @__PURE__ */ React9.createElement(Mosaic.Debug, {
923
+ data: {
924
+ path,
925
+ id,
926
+ items: itemsWithPreview.length
927
+ }
928
+ })));
929
+ });
930
+
931
+ // packages/ui/react-ui-mosaic/src/views/Stack/Stack.tsx
932
+ import React10 from "react";
933
+ import { mx as mx4 } from "@dxos/react-ui-theme";
934
+ var Stack = ({ id, Component: Component2 = Mosaic.DefaultComponent, onOver, onDrop, items = [], direction = "vertical", debug }) => {
935
+ const itemsWithPreview = useItemsWithPreview({
936
+ path: id,
937
+ items
938
+ });
939
+ return /* @__PURE__ */ React10.createElement("div", {
940
+ className: mx4("flex overflow-hidden", direction === "vertical" && "w-[300px]")
941
+ }, /* @__PURE__ */ React10.createElement("div", {
942
+ className: mx4("flex flex-col w-full my-1", direction === "vertical" ? "overflow-y-auto" : "overflow-x-auto")
943
+ }, /* @__PURE__ */ React10.createElement(Mosaic.Container, {
944
+ id,
945
+ Component: Component2,
946
+ onOver,
947
+ onDrop
948
+ }, /* @__PURE__ */ React10.createElement(Mosaic.SortableContext, {
949
+ items: itemsWithPreview,
950
+ direction
951
+ }, itemsWithPreview.map((item, index) => /* @__PURE__ */ React10.createElement(Mosaic.SortableTile, {
952
+ key: item.id,
953
+ item,
954
+ path: id,
955
+ position: index,
956
+ className: "m-1"
957
+ })))), debug && /* @__PURE__ */ React10.createElement("div", {
958
+ className: "grow"
959
+ }, /* @__PURE__ */ React10.createElement(Mosaic.Debug, {
960
+ data: {
961
+ id,
962
+ items: itemsWithPreview.length
963
+ }
964
+ }))));
965
+ };
966
+
967
+ // packages/ui/react-ui-mosaic/src/views/Tree/Tree.tsx
968
+ import React11, { forwardRef as forwardRef3 } from "react";
969
+ import { Card as Card3, Tree as TreeComponent, TreeItem as TreeItemComponent } from "@dxos/react-ui";
970
+ import { dropRing, mx as mx5 } from "@dxos/react-ui-theme";
971
+ var Tree = ({ id, Component: Component2 = TreeItem, onOver, onDrop, items = [], debug }) => {
972
+ return /* @__PURE__ */ React11.createElement(Mosaic.Container, {
973
+ id,
974
+ debug,
975
+ Component: Component2,
976
+ onOver,
977
+ onDrop
978
+ }, /* @__PURE__ */ React11.createElement(TreeRoot, {
979
+ items
980
+ }));
981
+ };
982
+ var TreeRoot = ({ items }) => {
983
+ const { id, Component: Component2 } = useContainer();
984
+ const itemsWithOrigin = useItemsWithOrigin(id, items);
985
+ return /* @__PURE__ */ React11.createElement(TreeComponent.Root, {
986
+ classNames: "flex flex-col"
987
+ }, /* @__PURE__ */ React11.createElement(Mosaic.SortableContext, {
988
+ id,
989
+ items: itemsWithOrigin,
990
+ direction: "vertical"
991
+ }, itemsWithOrigin.map((item, index) => /* @__PURE__ */ React11.createElement(TreeItemComponent.Root, {
992
+ key: item.id,
993
+ collapsible: true,
994
+ defaultOpen: true
995
+ }, /* @__PURE__ */ React11.createElement(Mosaic.SortableTile, {
996
+ item,
997
+ path: id,
998
+ position: index,
999
+ Component: Component2
1000
+ })))));
1001
+ };
1002
+ var TreeItem = /* @__PURE__ */ forwardRef3(({ path, draggableStyle, draggableProps, item, operation, active, isOver, isDragging, className }, forwardedRef) => {
1003
+ return /* @__PURE__ */ React11.createElement("div", {
1004
+ ref: forwardedRef,
1005
+ style: draggableStyle,
1006
+ className: mx5("flex flex-col rounded", className, (active === "rearrange" || active === "origin") && "opacity-0", active === "destination" && "opacity-20", isOver && dropRing)
1007
+ }, /* @__PURE__ */ React11.createElement(Card3.Header, null, /* @__PURE__ */ React11.createElement(Card3.DragHandle, draggableProps), /* @__PURE__ */ React11.createElement(Card3.Title, {
1008
+ title: item.label ?? path,
1009
+ classNames: "truncate"
1010
+ })), !active && item.children && /* @__PURE__ */ React11.createElement(TreeBranch, {
1011
+ path,
1012
+ items: item.children
1013
+ }));
1014
+ });
1015
+ var TreeBranch = ({ path, items }) => {
1016
+ const { operation, overItem } = useMosaic();
1017
+ const { Component: Component2 } = useContainer();
1018
+ const itemsWithOrigin = useItemsWithOrigin(path, items);
1019
+ return /* @__PURE__ */ React11.createElement(TreeItemComponent.Body, {
1020
+ className: "pis-4"
1021
+ }, /* @__PURE__ */ React11.createElement(Mosaic.SortableContext, {
1022
+ id: path,
1023
+ items: itemsWithOrigin,
1024
+ direction: "vertical"
1025
+ }, itemsWithOrigin.map((child, index) => /* @__PURE__ */ React11.createElement(TreeComponent.Branch, {
1026
+ key: child.id
1027
+ }, /* @__PURE__ */ React11.createElement(TreeItemComponent.Root, {
1028
+ collapsible: true,
1029
+ defaultOpen: true
1030
+ }, /* @__PURE__ */ React11.createElement(Mosaic.SortableTile, {
1031
+ item: child,
1032
+ path,
1033
+ position: index,
1034
+ Component: Component2,
1035
+ isOver: overItem?.path === Path.create(path, child.id) && (operation === "transfer" || operation === "copy")
1036
+ }))))));
1037
+ };
627
1038
  export {
1039
+ Grid,
1040
+ Kanban,
628
1041
  Mosaic,
629
1042
  Path,
1043
+ Stack,
1044
+ Tree,
1045
+ calculateCellWidth,
1046
+ createMatrix,
1047
+ getBounds,
1048
+ getDimension,
1049
+ getPanelBounds,
630
1050
  getTransformCSS,
631
- isTileComponentProps,
632
- isTileProps,
633
1051
  swapItems,
634
1052
  useContainer,
635
1053
  useItemsWithOrigin,