solid-dnd icon indicating copy to clipboard operation
solid-dnd copied to clipboard

TSX types missing

Open delaneyj opened this issue 3 years ago • 8 comments

Ran into problems and looked at #60 but this example fails to run with typescript strict mode.

image

With unhealthy amount of any I can compile

import {
  closestCenter,
  createSortable,
  DragDropProvider,
  DragDropSensors,
  DragOverlay,
  SortableProvider,
  useDragDropContext,
} from '@thisbeyond/solid-dnd'
import { Component, createSignal, For } from 'solid-js'

const Sortable: Component<{ item: any }> = (props) => {
  const sortable = createSortable(props.item)
  const ctx = useDragDropContext()
  return (
    <div
      use:sortable
      class="sortable"
      classList={{
        'opacity-25': sortable.isActiveDraggable,
        'transition-transform': !!ctx?.[0].active.draggable,
      }}
    >
      {props.item}
    </div>
  )
}

export const SortableVerticalListExample = () => {
  const [items, setItems] = createSignal([1, 2, 3])
  const [activeItem, setActiveItem] = createSignal(null)
  const ids = () => items()

  const onDragStart = (obj: any) => setActiveItem(obj.draggable.id)

  const onDragEnd = (obj: any) => {
    if (obj.draggable && obj.droppable) {
      const currentItems = ids()
      const fromIndex = currentItems.indexOf(obj.draggable.id)
      const toIndex = currentItems.indexOf(obj.droppable.id)
      if (fromIndex !== toIndex) {
        const updatedItems = currentItems.slice()
        updatedItems.splice(toIndex, 0, ...updatedItems.splice(fromIndex, 1))
        setItems(updatedItems)
      }
    }
  }

  return (
    <DragDropProvider
      onDragStart={onDragStart}
      onDragEnd={onDragEnd}
      collisionDetector={closestCenter}
    >
      <DragDropSensors />
      <div class="column self-stretch">
        <SortableProvider ids={ids()}>
          <For each={items()}>{(item) => <Sortable item={item} />}</For>
        </SortableProvider>
      </div>
      <DragOverlay>
        <div class="sortable">{activeItem()}</div>
      </DragOverlay>
    </DragDropProvider>
  )
}

However at runtime I'm getting useDragDropContext is not a function or its return value is not iterable error and not sure what to do. I know the lib is written in TS show I'd think the .tsx would be straight forward. Could someone ELI5 what I'm missing?

delaneyj avatar Nov 21 '22 04:11 delaneyj

checkout #63

mohamed-adly avatar Nov 22 '22 05:11 mohamed-adly

I filed the parallel issue https://github.com/thisbeyond/solid-dnd-site/issues/4 in the repository that holds the under-typed examples. It's not necessarily straightforward to fix this just because the library is in TS: giving users the types they expect is a whole extra development task compared to writing a library that's internally type-safe.

jyasskin avatar Nov 26 '22 04:11 jyasskin

Running into the same issue here, but I also get a bunch of warning about the "use:" attributes

Type '{ children: string; "use:draggable": true; }' is not assignable to type 'HTMLAttributes<HTMLDivElement>'.
  Property 'use:draggable' does not exist on type 'HTMLAttributes<HTMLDivElement>'. Did you mean 'draggable'?ts(2322)

MikaelPorttila avatar Jan 06 '23 13:01 MikaelPorttila

I am also unable to use it with TS, any possible fixes?

image

ShivamJoker avatar May 05 '23 16:05 ShivamJoker

@martinpengellyphillips any way to get around with this?

ShivamJoker avatar May 05 '23 16:05 ShivamJoker

Have you looked at #60 yet?

I'm general, you should be able to use the exported types from solid-dnd to get what you need (as well as the types from solidjs for things like components).

Where specifically are the types not working for you (the screenshot you share is completely untyped)?

martinpengellyphillips avatar May 08 '23 06:05 martinpengellyphillips

If you don't want to declare directives for draggable, droppable and sortable functions, you can pass them directly into the ref attribute, since directives are just a convenient way to obtain a reference to underlying node:

<div ref={draggable}></div>

Of course, if you need the reference in another place too, the syntax becomes less plausible:

let ref

<div ref={(element) => {
  ref = element;
  draggable(element);
}}></div>

But this should still work. Perhaps it is worth to add the definitions of those directives to the package itself, because it is a common feature that potentially is and will be used in most projects with DnD?

Kapelianovych avatar Aug 22 '23 21:08 Kapelianovych

Here's how I fixed errors in strict mode: Specifically, the useDragDropContext is not a function or its return value is not iterable error was addressed by implementing const state = context && context[0];

import {
  closestCenter,
  createSortable,
  DragDropProvider,
  DragDropSensors,
  DragEventHandler,
  DragOverlay,
  Id,
  SortableProvider,
  useDragDropContext,
} from "@thisbeyond/solid-dnd";
import { createSignal, For } from "solid-js";

const Sortable = (props: { item: Id }) => {
  const sortable = createSortable(props.item);
  const context = useDragDropContext();
  const state = context && context[0];  // <-- this

  return (
    <div
      ref={sortable}
      class="sortable"
      classList={{
        "opacity-25": sortable.isActiveDraggable,
        "transition-transform": !!state?.active.draggable,
      }}
    >
      {props.item}
    </div>
  );
};

export const SortableVerticalListExample = () => {
  const [items, setItems] = createSignal<Id[]>([1, 2, 3]);
  const [activeItem, setActiveItem] = createSignal<Id | null>(null);
  const ids = () => items();

  const onDragStart: DragEventHandler = ({ draggable }) =>
    setActiveItem(draggable.id);

  const onDragEnd: DragEventHandler = ({ draggable, droppable }) => {
    if (draggable && droppable) {
      const currentItems = ids();
      const fromIndex = currentItems.indexOf(draggable.id);
      const toIndex = currentItems.indexOf(droppable.id);
      if (fromIndex !== toIndex) {
        const updatedItems = currentItems.slice();
        updatedItems.splice(toIndex, 0, ...updatedItems.splice(fromIndex, 1));
        setItems(updatedItems);
      }
    }
  };

  return (
    <DragDropProvider
      onDragStart={onDragStart}
      onDragEnd={onDragEnd}
      collisionDetector={closestCenter}
    >
      <DragDropSensors />
      <div class="column self-stretch">
        <SortableProvider ids={ids()}>
          <For each={items()}>{(item) => <Sortable item={item} />}</For>
        </SortableProvider>
      </div>
      <DragOverlay>
        <div class="sortable">{activeItem()}</div>
      </DragOverlay>
    </DragDropProvider>
  );
};

ikemo3 avatar Feb 11 '24 12:02 ikemo3