Skip to content

Commit e0d53b1

Browse files
committed
feat: Added an example using @shopify/draggable, weird layout shifts.
1 parent 47fed78 commit e0d53b1

File tree

3 files changed

+70
-66
lines changed

3 files changed

+70
-66
lines changed

bun.lockb

14 Bytes
Binary file not shown.

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,13 @@
3232
"vite": "^6.0.5"
3333
},
3434
"dependencies": {
35+
"@shopify/draggable": "^1.1.3",
3536
"@solid-primitives/input-mask": "^0.2.2",
3637
"dayjs": "^1.11.13",
3738
"hono": "^4.6.14",
3839
"intl-number-input": "^1.4.1",
3940
"nanoid": "^5.0.9",
4041
"solid-js": "^1.9.3",
41-
"sortablejs": "^1.15.6",
4242
"tippy.js": "^6.3.7",
4343
"vike": "0.4.210",
4444
"vike-metadata-solid": "^1.0.4",

src/components/finance-calculator.tsx

+69-65
Original file line numberDiff line numberDiff line change
@@ -164,25 +164,15 @@ export function FinanceCalculator() {
164164
// Sortable
165165
// ===========================================================================
166166
const { parentRef: sortableParentRef } = useSortable({
167-
onEnd: (newIndex, oldIndex) => {
168-
if (newIndex === oldIndex) return;
169-
console.log("onEnd", newIndex, oldIndex);
170-
171-
// Workaround for some bug: https://github.com/solidjs/solid/issues/1898
172-
const lastElementWasMoved =
173-
oldIndex === savedSummaries.length - 1 || newIndex == savedSummaries.length - 1;
174-
if (lastElementWasMoved) {
175-
const copy = unwrap(savedSummaries);
176-
arrayMoveMutable(copy, oldIndex, newIndex);
177-
setSavedSummaries(reconcile(copy));
178-
return;
179-
}
167+
onEnd: ({ fromIndex, toIndex }) => {
168+
if (toIndex === fromIndex) return;
169+
170+
console.log("on End", fromIndex, toIndex);
180171

181-
setSavedSummaries((_savedSummaries) => {
182-
const copy = structuredClone(_savedSummaries);
183-
const sorted = arrayMoveImmutable(copy, oldIndex, newIndex);
184-
return sorted;
185-
});
172+
const copy = unwrap(savedSummaries);
173+
const sorted = arrayMoveImmutable(copy, fromIndex, toIndex);
174+
175+
setSavedSummaries(reconcile(sorted));
186176
},
187177
});
188178

@@ -285,45 +275,47 @@ export function FinanceCalculator() {
285275
<div class="mt-4 flex flex-col gap-y-2" ref={sortableParentRef}>
286276
<For each={savedSummaries}>
287277
{(summary) => (
288-
<div
289-
class={`sortable-item flex cursor-pointer justify-between gap-x-1 rounded-md border p-2 ${summary.id === formData.id ? "border-blue-500 bg-blue-100" : "border-gray-200 bg-white"}`}
290-
onClick={(_) => {
291-
_.stopPropagation();
292-
handleViewClick(summary.id);
293-
}}
294-
>
295-
<div>
296-
<div class="mb-2">{summary.quickNote}</div>
297-
<div class="flex flex-wrap items-center gap-x-3 text-xs">
298-
<IconWithTooltip icon={<IconPaperMoney class="h-4 w-4" />} tooltip="Total Cost">
299-
{formatCurrency(summary.totalCost)}
300-
</IconWithTooltip>
301-
<IconWithTooltip
302-
icon={<IconCalendar class="h-4 w-4" />}
303-
tooltip="Monthly Payment"
304-
>
305-
{formatCurrency(summary.monthlyPayment)} for {summary.loanTermMonths} mos
306-
</IconWithTooltip>
307-
308-
<IconWithTooltip
309-
class="text-red-700"
310-
icon={<IconPaperMoneyRemove class="h-4 w-4" />}
311-
tooltip="Total Interest (Money you'll pay more because of financing)"
312-
>
313-
{formatCurrency(summary.totalInterest)}
314-
</IconWithTooltip>
315-
</div>
316-
<div class="mt-1 text-xs text-gray-400">
317-
{formatDateWithTime(summary.createdAt)}
278+
<div class="sortable-item">
279+
<div
280+
class={`flex cursor-pointer justify-between gap-x-1 rounded-md border p-2 ${summary.id === formData.id ? "border-blue-500 bg-blue-100" : "border-gray-200 bg-white"}`}
281+
onClick={(_) => {
282+
_.stopPropagation();
283+
handleViewClick(summary.id);
284+
}}
285+
>
286+
<div>
287+
<div class="mb-2">{summary.quickNote}</div>
288+
<div class="flex flex-wrap items-center gap-x-3 text-xs">
289+
<IconWithTooltip icon={<IconPaperMoney class="h-4 w-4" />} tooltip="Total Cost">
290+
{formatCurrency(summary.totalCost)}
291+
</IconWithTooltip>
292+
<IconWithTooltip
293+
icon={<IconCalendar class="h-4 w-4" />}
294+
tooltip="Monthly Payment"
295+
>
296+
{formatCurrency(summary.monthlyPayment)} for {summary.loanTermMonths} mos
297+
</IconWithTooltip>
298+
299+
<IconWithTooltip
300+
class="text-red-700"
301+
icon={<IconPaperMoneyRemove class="h-4 w-4" />}
302+
tooltip="Total Interest (Money you'll pay more because of financing)"
303+
>
304+
{formatCurrency(summary.totalInterest)}
305+
</IconWithTooltip>
306+
</div>
307+
<div class="mt-1 text-xs text-gray-400">
308+
{formatDateWithTime(summary.createdAt)}
309+
</div>
318310
</div>
319-
</div>
320311

321-
<button
322-
class="place-self-start text-red-500 transition active:scale-95"
323-
onClick={(_) => handleDelete(summary.id)}
324-
>
325-
<IconClose class="h-4 w-4" />
326-
</button>
312+
<button
313+
class="place-self-start text-red-500 transition active:scale-95"
314+
onClick={(_) => handleDelete(summary.id)}
315+
>
316+
<IconClose class="h-4 w-4" />
317+
</button>
318+
</div>
327319
</div>
328320
)}
329321
</For>
@@ -354,22 +346,34 @@ function IconWithTooltip(
354346
);
355347
}
356348

357-
import { arrayMoveImmutable, arrayMoveMutable } from "@/utils/array-move";
358-
import Sortable from "sortablejs";
349+
import { arrayMoveImmutable } from "@/utils/array-move";
359350

360-
function useSortable(params: { onEnd: (newIndex: number, oldIndex: number) => void }) {
351+
function useSortable(params: { onEnd: (data: { fromIndex: number; toIndex: number }) => void }) {
361352
const [_parentRef, setParentRef] = createSignal<HTMLDivElement>();
362353
onMount(async () => {
354+
const { Sortable } = await import("@shopify/draggable");
355+
363356
if (_parentRef() === undefined) return;
364357

365-
const sortable = Sortable.create(_parentRef()!, {
366-
animation: 200,
367-
onEnd: (e) => {
368-
if (e.newIndex !== undefined && e.oldIndex !== undefined) {
369-
params?.onEnd(e.newIndex, e.oldIndex);
370-
}
371-
},
358+
const sortable = new Sortable(_parentRef()!, {
359+
draggable: ".sortable-item",
360+
distance: 50,
361+
});
362+
363+
sortable.on("sortable:stop", (data) => {
364+
if (data.canceled() === false) {
365+
console.log("sorting", "woohoo");
366+
params?.onEnd({ fromIndex: data.oldIndex, toIndex: data.newIndex });
367+
}
372368
});
369+
// const sortable = Sortable.create(_parentRef()!, {
370+
// animation: 200,
371+
// onEnd: (e) => {
372+
// if (e.newIndex !== undefined && e.oldIndex !== undefined) {
373+
// params?.onEnd(e.newIndex, e.oldIndex);
374+
// }
375+
// },
376+
// });
373377
});
374378

375379
return { parentRef: setParentRef };

0 commit comments

Comments
 (0)