Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement new drag-and-drop engine #598

Merged
merged 133 commits into from
Jan 2, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
133 commits
Select commit Hold shift + click to select a range
a9b5e42
feat: introduce new drag-and-drop engine
chrisvxd Nov 2, 2024
83b00c4
docs: update demo to use new dnd engine
chrisvxd Nov 2, 2024
6f849a2
fix: render DropZones the same in Puck and Render
chrisvxd Aug 15, 2024
8e2052f
fix: don't trigger move action if source / destination the same
chrisvxd Nov 1, 2024
1c520a9
refactor: don't consider dragged item as pointer candidate
chrisvxd Nov 15, 2024
abd0331
refactor: default pointer candidate to default zone
chrisvxd Nov 15, 2024
b4d04f7
refactor: debounce pointer area changes
chrisvxd Nov 15, 2024
da7fc6e
refactor: use closest corners when no collision found
chrisvxd Nov 15, 2024
7208b31
refactor: use x-axis for grids and flex rows
chrisvxd Nov 16, 2024
e2dcf82
feat: add DropZone collisionAxis API for forcing collision direction
chrisvxd Nov 16, 2024
f13d5d3
refactor: force fallback collision with intersected area first
chrisvxd Nov 18, 2024
7ef9ad1
refactor: use full intersection instead of center-in-intersection for…
chrisvxd Nov 18, 2024
ea66897
refactor: tidy up NestedDroppablePlugin
chrisvxd Nov 18, 2024
cd01875
refactor: set deepest candidates on drag start
chrisvxd Nov 18, 2024
feb766d
refactor: change default collision axis for CSS grid to dynamic
chrisvxd Nov 18, 2024
28ea37d
feat: reduce DropZone to height of items unless empty
chrisvxd Nov 20, 2024
72f7923
feat: control empty DropZone height with minEmptyHeight prop
chrisvxd Nov 20, 2024
dea772a
fix: set root DropZone to 100% height
chrisvxd Nov 20, 2024
15f3950
fix: trigger iframe resize when closing devtools
chrisvxd Nov 20, 2024
9feb380
docs: make demo Header sticky
chrisvxd Nov 20, 2024
55d327f
refactor: use correct DropZone for nested render DropZones
chrisvxd Nov 20, 2024
4d9ce65
refactor: add missing dragRef to Preview component
chrisvxd Nov 20, 2024
8c5d030
refactor: enable autoscroller and other dnd-kit plugins
chrisvxd Nov 20, 2024
e72ad11
fix: stop actions from overflowing outside left of frame
chrisvxd Nov 20, 2024
06d105f
refactor: support disabled permission with new dnd engine
chrisvxd Nov 20, 2024
0dbe338
fix: always respect history hotkeys inside iframes
chrisvxd Nov 21, 2024
bb2a306
refactor: prevent ghosting when dragging quickly between zones
chrisvxd Nov 21, 2024
94105b0
refactor: reduce area change debounce to make more responsive
chrisvxd Nov 21, 2024
bbafd65
refactor: prevent overlay flicker on drop
chrisvxd Nov 21, 2024
8414992
refactor: add types for dnd data
chrisvxd Nov 21, 2024
f38c1cf
refactor: tidy up imports and removed unused CSS
chrisvxd Nov 21, 2024
e06a0b2
docs: tweak demo to use Grid instead of Flex
chrisvxd Nov 21, 2024
726c84e
docs: document new drag-and-drop functionality
chrisvxd Nov 21, 2024
e0de893
refactor: ensure new drag-and-drop engine runs on server
chrisvxd Nov 21, 2024
9443e34
docs: document DropZone className and style props
chrisvxd Nov 21, 2024
fe95743
docs: document minEmptyHeight API
chrisvxd Nov 21, 2024
2708d57
feat: support inline Drawers, deprecating unnecessary props
chrisvxd Nov 21, 2024
447a20b
docs: add missing isDragDisabled API docs
chrisvxd Nov 21, 2024
89f8401
refactor: support drag cancelling
chrisvxd Nov 21, 2024
9056652
docs: swap direction and justify content on Flex component
chrisvxd Nov 21, 2024
f25aaac
docs: document collisionAxis API
chrisvxd Nov 21, 2024
cacee1a
refactor: provide displayName for preview component
chrisvxd Nov 21, 2024
0756e00
refactor: use correct import for @dnd-kit/state
chrisvxd Nov 21, 2024
a49e0bd
build: use latest dndkit beta
chrisvxd Nov 21, 2024
a78ccc8
build: upgrade to nightly dndkit
chrisvxd Nov 22, 2024
b4038b6
refactor: only debounce area changes, not zone changes
chrisvxd Nov 22, 2024
76b1c54
refactor: infer collision axis for inline display modes
chrisvxd Nov 22, 2024
76abae6
docs: improve multi-column layout docs
chrisvxd Nov 22, 2024
2ef58fc
refactor: wrap dnd-kit hooks in server-safe wrappers
chrisvxd Nov 22, 2024
1f8d69b
build: remove cost dist before running dev server
chrisvxd Nov 22, 2024
a7365b8
docs: add missing link to Multi Column Layouts docs
chrisvxd Nov 22, 2024
48a740e
refactor: improve performance of overlay position sync
chrisvxd Nov 22, 2024
9739306
refactor: ensure selected outline is shown over hover outline
chrisvxd Nov 22, 2024
26a35ea
refactor: always set outline-offset when dragging
chrisvxd Nov 22, 2024
4996f3e
refactor: remove unnecessary Safari fallback mode
chrisvxd Nov 22, 2024
8bd214f
refactor: don't show hover overlay during item drop
chrisvxd Nov 22, 2024
979c8e2
build: exclude dndkit from bundle
chrisvxd Nov 23, 2024
78832b4
refactor: defer loading of DragDropContext until mounted
chrisvxd Nov 23, 2024
6cad938
refactor: don't recreate manager on each render
chrisvxd Dec 2, 2024
f876e28
refactor: don't rerender DragDropContext on pointer move
chrisvxd Dec 2, 2024
0416e8f
refactor: show overlay consistently on hover
chrisvxd Dec 4, 2024
35abf73
refactor: partially fix strict mode support for new dnd engine
chrisvxd Dec 4, 2024
a769e32
refactor: tidy up cancelled drags properly
chrisvxd Dec 4, 2024
2ab1da7
refactor: ensure overlay renders correctly outside of iframes
chrisvxd Dec 4, 2024
adfeda7
refactor: fix remaining flickering of overlay before sync finished
chrisvxd Dec 4, 2024
540db9b
chore: add debug mode to DraggableComponent
chrisvxd Dec 4, 2024
071f051
feat: deselect item on viewport change
chrisvxd Dec 4, 2024
e7898ac
refactor: update to latest dndkit nightly to fix strict mode
chrisvxd Dec 5, 2024
b4f936e
fix: remove unnecessary transpile from next recipe
chrisvxd Dec 5, 2024
22d5c92
refactor: defer iframe event bubbling until after load
chrisvxd Dec 5, 2024
377088d
refactor: never collide with Drawer droppable
chrisvxd Dec 6, 2024
43dd6f9
refactor: reduce area change deboucne to 100ms
chrisvxd Dec 6, 2024
26846fb
refactor: add missing grab pointer to Drawer.Item
chrisvxd Dec 6, 2024
dc977d1
refactor: prevent pointer events within draggable components
chrisvxd Dec 6, 2024
7b04502
refactor: fix touch dragging
chrisvxd Dec 7, 2024
7e43724
refactor: don't show overlay during drag on touch devices
chrisvxd Dec 7, 2024
cff4736
refactor: recalculate auto drag axis on viewport change
chrisvxd Dec 7, 2024
be04a20
fix: factor in border when setting viewport size
chrisvxd Dec 8, 2024
60b9601
chore: remove old comment
chrisvxd Dec 8, 2024
f912547
refactor: clear deepest droppable ref on drag end for touch
chrisvxd Dec 8, 2024
28513b2
refactor: extend delay after drop to prevent ghosting
chrisvxd Dec 8, 2024
61ccd7a
refactor: make overlay syncing more deterministic
chrisvxd Dec 8, 2024
c964019
refactor: don't show ActionBar on hover, matching main behaviour
chrisvxd Dec 9, 2024
7e151f7
refactor: cancel drop if user drops before preview is set
chrisvxd Dec 9, 2024
33cbbdc
refactor: prevent render ghosting when dragging between areas
chrisvxd Dec 9, 2024
ee855ae
refactor: fulfill insertion rather than cancel on fast drag
chrisvxd Dec 9, 2024
84491a9
refactor: select new item after duplicate
chrisvxd Dec 9, 2024
2bfd333
fix: select new item when dispatching duplicate action
chrisvxd Dec 9, 2024
3b544ed
refactor: don't scroll to top when drag starts
chrisvxd Dec 9, 2024
4ff2b2b
refactor: prevent actions from leaking outside either side of viewport
chrisvxd Dec 9, 2024
0607637
refactor: prevent action bar from flashing
chrisvxd Dec 9, 2024
03bcbad
refactor: ensure frame can exceed 100vh
chrisvxd Dec 12, 2024
2d3a8c9
refactor: use custom PointerSensor to address orphaned event issues
chrisvxd Dec 12, 2024
7a1344c
refactor: refactor DragDropContext preview code to prevent race condi…
chrisvxd Dec 12, 2024
83bed85
docs: adjust DropZone disallows in demo
chrisvxd Dec 12, 2024
e02e641
refactor: don't set deepest zone if parent zone not droppable
chrisvxd Dec 12, 2024
cc085f6
refactor: fix overlay position in custom interfaces
chrisvxd Dec 12, 2024
fbf3bc5
refactor: rework overlay positioning to account for docs
chrisvxd Dec 13, 2024
455ca8a
refactor: resize overlay if ref changes size
chrisvxd Dec 13, 2024
e62a8d0
build: don't bundle any dnd-kit libs
chrisvxd Dec 13, 2024
12a9fdc
refactor: always set the correct area for the zone
chrisvxd Dec 13, 2024
8d6d5a1
refactor: rewrite area debounce behaviour
chrisvxd Dec 13, 2024
dbdea44
refactor: ensure DropZone debug mode is visible
chrisvxd Dec 13, 2024
266b54b
refactor: use better names for debouncing refs
chrisvxd Dec 14, 2024
92c3c76
fix: prevent propagation of custom ActionBar actions by default
chrisvxd Dec 14, 2024
c92b4cb
feat: add ActionBar.Label component for adding labels to action bars
chrisvxd Dec 14, 2024
80ccb06
feat: add action to select parent component to ActionBar
chrisvxd Dec 14, 2024
5d9a07f
refactor: move drag styles into separate file, but retain injection h…
chrisvxd Dec 14, 2024
c65d0e1
refactor: reinstate disableAutoScroll behaviour
chrisvxd Dec 16, 2024
4b5b8a5
refactor: fix action bar flicker regression
chrisvxd Dec 16, 2024
c973744
refactor: set initialValue for ref following React 19 upgrade
chrisvxd Dec 27, 2024
934af1f
fix: prevent user pollution of ActionBar styles
chrisvxd Dec 27, 2024
0bbdc46
refactor: check if dnd item exists before accessing data
chrisvxd Dec 27, 2024
794f7f7
refactor: flush containsActiveZone when child zones removed
chrisvxd Dec 27, 2024
40fb832
refactor: delay selection until box has rendered
chrisvxd Dec 27, 2024
e4911b8
fix: improve heading-analyzer reliability
chrisvxd Dec 27, 2024
5cb8215
test: add e2e testing tools, and smoke test script
chrisvxd Dec 30, 2024
84a57fc
refactor: don't reset actions bounds offset after correction
chrisvxd Dec 30, 2024
cb0a65b
test: add multi-test support to smoke testing framework
chrisvxd Dec 30, 2024
47d507a
refactor: rework NestedPointerSensor to avoid recalculating all shapes
chrisvxd Dec 31, 2024
83fc54a
refactor: tidy up DropZone code
chrisvxd Dec 31, 2024
fb0f456
refactor: don't reference PointerEvent on server
chrisvxd Jan 1, 2025
b3bc3ed
refactor: memoize DropZone context for minor perf boost
chrisvxd Jan 1, 2025
4cd396f
refactor: don't resize DropZone on initial render
chrisvxd Jan 1, 2025
b169025
refactor: account for iframe offset in NestedDroppablePlugin since re…
chrisvxd Jan 1, 2025
af49603
refactor: retain previous DropZone height during drag
chrisvxd Jan 2, 2025
9788d0f
refactor: don't reset deepest on drag start
chrisvxd Jan 2, 2025
ba1b677
test: add more smoke test cases
chrisvxd Jan 2, 2025
e6226d4
refactor: retain original drawer item during drag
chrisvxd Jan 2, 2025
01bf755
refactor: handle overlapping drawer since Nested plugin refactor
chrisvxd Jan 2, 2025
c6fbd4a
refactor: rewrite ArrayField to use dnd-kit
chrisvxd Jan 2, 2025
34600af
feat: forward the ref to the DropZone component
chrisvxd Jan 2, 2025
5b485b7
refactor: add missing displayNames to DropZone
chrisvxd Jan 2, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions apps/demo/app/[...puckPath]/client.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ export function Client({ path, isEdit }: { path: string; isEdit: boolean }) {

if (!isClient) return null;

const params = new URL(window.location.href).searchParams;

if (isEdit) {
return (
<div>
Expand All @@ -32,6 +34,9 @@ export function Client({ path, isEdit }: { path: string; isEdit: boolean }) {
}}
plugins={[headingAnalyzer]}
headerPath={path}
iframe={{
enabled: params.get("disableIframe") === "true" ? false : true,
}}
overrides={{
headerActions: ({ children }) => (
<>
Expand Down
33 changes: 16 additions & 17 deletions apps/demo/app/custom-ui/[...puckPath]/client.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -281,13 +281,15 @@ const CustomDrawer = () => {
const { getPermissions } = usePuck();

return (
<Drawer direction="horizontal">
<Drawer>
<div
style={{
display: "flex",
display: "grid",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe consider adding
grid-auto-flow: column;

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What would the intention of adding that be?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was just thinking if the grid layout was column and they start adding colums this setting would be advantageous, and vice-versa if they wanted rows

gridTemplateColumns: "repeat(auto-fill, minmax(256px, 1fr))",
pointerEvents: "all",
padding: "16px",
background: "var(--puck-color-grey-12)",
gap: 8,
}}
>
{Object.keys(config.components).map((componentKey, componentIndex) => {
Expand All @@ -299,19 +301,8 @@ const CustomDrawer = () => {
<Drawer.Item
key={componentKey}
name={componentKey}
index={componentIndex}
isDragDisabled={!canInsert}
>
{({ children }) => (
<div
style={{
marginRight: 8,
}}
>
{children}
</div>
)}
</Drawer.Item>
/>
);
})}
</div>
Expand Down Expand Up @@ -377,7 +368,7 @@ export function Client({ path, isEdit }: { path: string; isEdit: boolean }) {
outline: ({ children }) => (
<div style={{ padding: 16 }}>{children}</div>
),
actionBar: ({ children, label }) => {
actionBar: ({ children, label, parentAction }) => {
const { getPermissions, selectedItem, refreshPermissions } =
// Disable rules of hooks since this is a render function
// eslint-disable-next-line react-hooks/rules-of-hooks
Expand All @@ -397,15 +388,23 @@ export function Client({ path, isEdit }: { path: string; isEdit: boolean }) {

if (!selectedItem)
return (
<ActionBar label={label}>
<ActionBar>
<ActionBar.Group>
{parentAction}
{label && <ActionBar.Label label={label} />}
</ActionBar.Group>
<ActionBar.Group>{children}</ActionBar.Group>
</ActionBar>
);

const isLocked = !!lockedComponents[selectedItem.props.id];

return (
<ActionBar label={label}>
<ActionBar>
<ActionBar.Group>
{parentAction}
{label && <ActionBar.Label label={label} />}
</ActionBar.Group>
<ActionBar.Group>
{children}
{globalPermissions.lockable && (
Expand Down
6 changes: 3 additions & 3 deletions apps/demo/config/blocks/Blank/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ import { ComponentConfig } from "@/core";
import styles from "./styles.module.css";
import { getClassNameFactory } from "@/core/lib";

const getClassName = getClassNameFactory("Hero", styles);
const getClassName = getClassNameFactory("Blank", styles);

export type HeroProps = {};
export type BlankProps = {};

export const Hero: ComponentConfig<HeroProps> = {
export const Blank: ComponentConfig<BlankProps> = {
fields: {},
defaultProps: {},
render: () => {
Expand Down
2 changes: 1 addition & 1 deletion apps/demo/config/blocks/Blank/styles.module.css
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
.Hero {
.Blank {
background: hotpink;
padding: 16px;
}
43 changes: 43 additions & 0 deletions apps/demo/config/blocks/Button/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import React from "react";
import { ComponentConfig } from "@/core/types";
import { Button as _Button } from "@/core/components/Button";

export type ButtonProps = {
label: string;
href: string;
variant: "primary" | "secondary";
};

export const Button: ComponentConfig<ButtonProps> = {
label: "Button",
fields: {
label: { type: "text" },
href: { type: "text" },
variant: {
type: "radio",
options: [
{ label: "primary", value: "primary" },
{ label: "secondary", value: "secondary" },
],
},
},
defaultProps: {
label: "Button",
href: "#",
variant: "primary",
},
render: ({ href, variant, label, puck }) => {
return (
<div>
<_Button
href={puck.isEditing ? "#" : href}
variant={variant}
size="large"
tabIndex={puck.isEditing ? -1 : undefined}
>
{label}
</_Button>
</div>
);
},
};
69 changes: 0 additions & 69 deletions apps/demo/config/blocks/ButtonGroup/index.tsx

This file was deleted.

9 changes: 0 additions & 9 deletions apps/demo/config/blocks/ButtonGroup/styles.module.css

This file was deleted.

18 changes: 12 additions & 6 deletions apps/demo/config/blocks/Card/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import styles from "./styles.module.css";
import { getClassNameFactory } from "@/core/lib";
import dynamic from "next/dynamic";
import dynamicIconImports from "lucide-react/dynamicIconImports";
import { withLayout, WithLayout } from "../../components/Layout";

const getClassName = getClassNameFactory("Card", styles);

Expand All @@ -24,14 +25,14 @@ const iconOptions = Object.keys(dynamicIconImports).map((iconName) => ({
value: iconName,
}));

export type CardProps = {
export type CardProps = WithLayout<{
title: string;
description: string;
icon?: string;
mode: "flat" | "card";
};
}>;

export const Card: ComponentConfig<CardProps> = {
const CardInner: ComponentConfig<CardProps> = {
fields: {
title: { type: "text" },
description: { type: "textarea" },
Expand All @@ -56,10 +57,15 @@ export const Card: ComponentConfig<CardProps> = {
render: ({ title, icon, description, mode }) => {
return (
<div className={getClassName({ [mode]: mode })}>
<div className={getClassName("icon")}>{icon && icons[icon]}</div>
<div className={getClassName("title")}>{title}</div>
<div className={getClassName("description")}>{description}</div>
<div className={getClassName("inner")}>
<div className={getClassName("icon")}>{icon && icons[icon]}</div>

<div className={getClassName("title")}>{title}</div>
<div className={getClassName("description")}>{description}</div>
</div>
</div>
);
},
};

export const Card = withLayout(CardInner);
24 changes: 12 additions & 12 deletions apps/demo/config/blocks/Card/styles.module.css
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
.Card {
display: flex;
flex-direction: column;
align-items: center;
margin-left: auto;
margin-right: auto;
gap: 16px;
width: 100%;
height: 100%;
}

.Card--card {
background: white;
box-shadow: rgba(140, 152, 164, 0.25) 0px 3px 6px 0px;
border-radius: 8px;
flex: 1;
max-width: 100%;
margin-left: unset;
margin-right: unset;
padding: 24px;
}

.Card-inner {
align-items: center;
display: flex;
gap: 16px;
flex-direction: column;
}

.Card--card .Card-inner {
align-items: flex-start;
width: auto;
padding: 24px;
}

.Card-icon {
Expand Down
Loading
Loading