selecto icon indicating copy to clipboard operation
selecto copied to clipboard

Not working with CSS modules

Open oliveryasuna opened this issue 7 months ago • 1 comments

Environments

  • Framework name: React
  • Framework version: 18.2.0
  • Component name: Selecto
  • Component version: 1.26.1

Description

I cannot seem to get Selecto working when class names are populated from a CSS module using Vite. Maybe I am missing something obvious? Thanks!

Also, I am still learning how to use your libraries. They are great! If you have a moment, could you please answer these questions?

  1. I noticed that the selected border and circle do not move with the target when the canvas scrolls. Any idea why?
  2. How can I disable the border and/or circle on selected targets?
  3. If I have content above or left of the viewer, I noticed that the blue drag selection is offset. How can I fix this? I fixed it with rootContainer={viewerRef.current?.getElement() || document.body}, but this feels messy.
  4. Is it possible to implement a coordinate system in Infinite Viewer?
import classes from './Canvas.module.scss';

const Canvas = ((): React.ReactNode => {
  const moveableRef: React.RefObject<Moveable> = useRef<Moveable>(null);
  const selectoRef: React.RefObject<Selecto> = useRef<Selecto>(null);
  const viewerRef: React.RefObject<InfiniteViewer> = useRef<InfiniteViewer>(null);

  const [targets, setTargets] = useState<(HTMLElement | SVGElement)[]>([]);

  useEffect((): void => {
    viewerRef.current!.scrollCenter();
  }, []);

  return (
      <div className={classes['Canvas']}>
        <Moveable
            ref={moveableRef}
            target={targets}
            draggable
            onClickGroup={(event: OnClickGroup): void => {
              selectoRef.current!.clickTarget(event.inputEvent, event.inputTarget);
            }}
            onRender={(event: OnRender): void => {
              event.target.style.cssText += event.cssText;
            }}
            onRenderGroup={(event: OnRenderGroup): void => {
              for(const subEvent of event.events) {
                subEvent.target.style.cssText += subEvent.cssText;
              }
            }}/>
        <Selecto
            ref={selectoRef}
            dragContainer={classes['Canvas__viewer']}
            selectableTargets={[`.${classes['viewport']} > .${classes['target']}`]}
            hitRate={0}
            selectByClick
            selectFromInside={false}
            toggleContinueSelect="shift"
            ratio={0}
            keyContainer={window}
            scrollOptions={{
              container: ((): HTMLElement => viewerRef.current!.getElement()),
              getScrollPosition: ((): [number, number] => [viewerRef.current!.getScrollLeft(), viewerRef.current!.getScrollTop()]),
              throttleTime: 30,
              threshold: 0
            }}
            onSelect={(event: OnSelect): void => {
              console.log(event);

              for(const added of event.added) {
                added.classList.add('selected');
              }
              for(const removed of event.removed) {
                removed.classList.remove('selected');
              }
            }}
            onScroll={(event: OnScroll): void => {
              viewerRef.current!.scrollBy((event.direction[0]! * 10), (event.direction[1]! * 10));
            }}
            onDragStart={(event: OnDragStart): void => {
              const target: any = event.inputEvent.target;

              if(moveableRef.current!.isMoveableElement(target) || targets.some((existingTarget: (HTMLElement | SVGElement)): boolean =>
                  ((existingTarget === target) || (existingTarget.contains(target))))) {
                event.stop();
              }
            }}
            onSelectEnd={(event: OnSelectEnd): void => {
              if(event.isDragStartEnd) {
                event.inputEvent.preventDefault();

                moveableRef.current!.waitToChangeTarget()
                    .then((): void => {
                      moveableRef.current!.dragStart(event.inputEvent);
                    });
              }

              setTargets(event.selected);
            }}/>
        <InfiniteViewer
            ref={viewerRef}
            className={classes['Canvas__viewer']!}
            displayHorizontalScroll
            displayVerticalScroll
            onScroll={(): void => {
              selectoRef.current!.checkScroll();
            }}>
          <div className={classes['viewport']}>
            <div className={classes['target']}>Target</div>
          </div>
        </InfiniteViewer>
      </div>
  );
});
.Canvas {
  position: relative;

  width: 100%;
  height: 100%;

  transform-style: preserve-3d;

  > .Canvas__viewer {
    position: relative;

    width: 100%;
    height: 100%;

    .viewport {
      > .target {
        width: 100px;
        height: 100px;

        box-sizing: border-box;

        line-height: 100px;

        text-align: center;

        background-color: #ee8;

        &.selected {
          background-color: #4af;
        }
      }
    }
  }
}

oliveryasuna avatar Nov 21 '23 17:11 oliveryasuna

Hi, it is common to put a moveable in the viewport.

The reason it doesn't follow the scroll is because the moveable is not within the scroll area. The following structure is recommended.

https://daybrush.com/moveable/storybook/?path=/story/combination-with-other-components--components-infinite-viewer

  • <Canvas>
  • => <Selector />
  • => <InfiniteViewer>
  • ==> <div class="viewport">
  • ===> <Moveable />

if you hide target rect line (blue line) or origin dot (red circle)

hideDefaultLines={true}
origin={false}

rootContainer is the correct way to use it in general.

rootContainer={() => viewerRef.current?.getElement() || document.body}

daybrush avatar Nov 30 '23 11:11 daybrush