@dxos/react-ui-mosaic 0.3.3-main.3ce60d4 → 0.3.3-main.44bdbf7

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