Updated Sealious-Playground to use the external version of sortable
Summary: Ref T2984 Test Plan: Remove the node_modules directory, run npm i and check http://localhost:8080/demos/sortable/ for testing Reviewers: #testers, kuba-orlik Reviewed By: #testers, kuba-orlik Subscribers: jenkins-user Maniphest Tasks: T2984 Differential Revision: https://hub.sealcode.org/D1623
This commit is contained in:
parent
727e65707d
commit
c261aacef3
20
package-lock.json
generated
20
package-lock.json
generated
@ -19,6 +19,7 @@
|
|||||||
"@sealcode/jdd-editor": "^0.2.1",
|
"@sealcode/jdd-editor": "^0.2.1",
|
||||||
"@sealcode/sealgen": "^0.18.10",
|
"@sealcode/sealgen": "^0.18.10",
|
||||||
"@sealcode/simplemde": "^1.12.1",
|
"@sealcode/simplemde": "^1.12.1",
|
||||||
|
"@sealcode/sortable": "^0.0.1",
|
||||||
"@sealcode/ts-predicates": "^0.6.2",
|
"@sealcode/ts-predicates": "^0.6.2",
|
||||||
"@types/kill-port": "^2.0.0",
|
"@types/kill-port": "^2.0.0",
|
||||||
"@types/leaflet": "^1.9.8",
|
"@types/leaflet": "^1.9.8",
|
||||||
@ -1530,6 +1531,16 @@
|
|||||||
"turndown-plugin-gfm": "^1.0.2"
|
"turndown-plugin-gfm": "^1.0.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@sealcode/sortable": {
|
||||||
|
"version": "0.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@sealcode/sortable/-/sortable-0.0.1.tgz",
|
||||||
|
"integrity": "sha512-I9dFsXcweQ91ly4if/7EoTga76TKQEbpA4UEvDTnRPNRhTt1jn657mA2yA7G/3lSWBvY5NixDgkdp0vIXzZ+DQ==",
|
||||||
|
"hasInstallScript": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@hotwired/stimulus": "^3.2.2",
|
||||||
|
"tempstream": "^0.4.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@sealcode/ts-predicates": {
|
"node_modules/@sealcode/ts-predicates": {
|
||||||
"version": "0.6.2",
|
"version": "0.6.2",
|
||||||
"resolved": "https://registry.npmjs.org/@sealcode/ts-predicates/-/ts-predicates-0.6.2.tgz",
|
"resolved": "https://registry.npmjs.org/@sealcode/ts-predicates/-/ts-predicates-0.6.2.tgz",
|
||||||
@ -16072,6 +16083,15 @@
|
|||||||
"turndown-plugin-gfm": "^1.0.2"
|
"turndown-plugin-gfm": "^1.0.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@sealcode/sortable": {
|
||||||
|
"version": "0.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@sealcode/sortable/-/sortable-0.0.1.tgz",
|
||||||
|
"integrity": "sha512-I9dFsXcweQ91ly4if/7EoTga76TKQEbpA4UEvDTnRPNRhTt1jn657mA2yA7G/3lSWBvY5NixDgkdp0vIXzZ+DQ==",
|
||||||
|
"requires": {
|
||||||
|
"@hotwired/stimulus": "^3.2.2",
|
||||||
|
"tempstream": "^0.4.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"@sealcode/ts-predicates": {
|
"@sealcode/ts-predicates": {
|
||||||
"version": "0.6.2",
|
"version": "0.6.2",
|
||||||
"resolved": "https://registry.npmjs.org/@sealcode/ts-predicates/-/ts-predicates-0.6.2.tgz",
|
"resolved": "https://registry.npmjs.org/@sealcode/ts-predicates/-/ts-predicates-0.6.2.tgz",
|
||||||
|
@ -40,10 +40,12 @@
|
|||||||
},
|
},
|
||||||
"sealgen": {
|
"sealgen": {
|
||||||
"styleDirs": [
|
"styleDirs": [
|
||||||
"node_modules/@sealcode/jdd-editor/assets"
|
"node_modules/@sealcode/jdd-editor/assets",
|
||||||
|
"node_modules/@sealcode/sortable/src/stimulus-styles"
|
||||||
],
|
],
|
||||||
"controllerDirs": [
|
"controllerDirs": [
|
||||||
"node_modules/@sealcode/jdd-editor/src/controllers"
|
"node_modules/@sealcode/jdd-editor/src/controllers",
|
||||||
|
"node_modules/@sealcode/sortable/src/controllers"
|
||||||
],
|
],
|
||||||
"copyToPublic": [
|
"copyToPublic": [
|
||||||
{
|
{
|
||||||
@ -85,6 +87,7 @@
|
|||||||
"@sealcode/jdd-editor": "^0.2.1",
|
"@sealcode/jdd-editor": "^0.2.1",
|
||||||
"@sealcode/sealgen": "^0.18.10",
|
"@sealcode/sealgen": "^0.18.10",
|
||||||
"@sealcode/simplemde": "^1.12.1",
|
"@sealcode/simplemde": "^1.12.1",
|
||||||
|
"@sealcode/sortable": "^0.0.1",
|
||||||
"@sealcode/ts-predicates": "^0.6.2",
|
"@sealcode/ts-predicates": "^0.6.2",
|
||||||
"@types/kill-port": "^2.0.0",
|
"@types/kill-port": "^2.0.0",
|
||||||
"@types/leaflet": "^1.9.8",
|
"@types/leaflet": "^1.9.8",
|
||||||
|
@ -1,80 +0,0 @@
|
|||||||
@keyframes sortable-enter {
|
|
||||||
from {
|
|
||||||
transform: scale(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
to {
|
|
||||||
transform: scale(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.sortable-wrapper {
|
|
||||||
.edge-detector {
|
|
||||||
height: 30px;
|
|
||||||
position: fixed;
|
|
||||||
left: 0;
|
|
||||||
width: 100%;
|
|
||||||
display: none;
|
|
||||||
z-index: 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:has(.is-dragged) {
|
|
||||||
.edge-detector {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.sortable {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: 1fr;
|
|
||||||
--element-height: 50px;
|
|
||||||
--gap: 8px;
|
|
||||||
|
|
||||||
.sortable__element {
|
|
||||||
height: var(--element-height);
|
|
||||||
grid-column: 1/2;
|
|
||||||
grid-row: calc((var(--index) + 1) * 3 + 1) / calc((var(--index) + 1) * 3 + 3);
|
|
||||||
|
|
||||||
background-color: white;
|
|
||||||
box-sizing: border-box;
|
|
||||||
min-width: 400px;
|
|
||||||
font-size: 20px;
|
|
||||||
border: 1px solid black;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
cursor: move;
|
|
||||||
user-select: none;
|
|
||||||
|
|
||||||
animation: sortable-enter 100ms;
|
|
||||||
|
|
||||||
&.is-dragged {
|
|
||||||
opacity: 20%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.sortable__spacer {
|
|
||||||
grid-column: 1/2;
|
|
||||||
grid-row: calc((var(--index) + 1) * 3 + 3) / calc((var(--index) + 1) * 3 + 4);
|
|
||||||
transition: all 200ms;
|
|
||||||
height: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sortable__hole {
|
|
||||||
grid-column: 1/2;
|
|
||||||
z-index: 1;
|
|
||||||
pointer-events: none;
|
|
||||||
grid-row: calc((var(--index) + 1) * 3 + 2) / calc((var(--index) + 1) * 3 + 5);
|
|
||||||
|
|
||||||
&.ready-to-drop + .sortable__spacer {
|
|
||||||
height: var(--element-height) !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&:has(.is-dragged) {
|
|
||||||
.sortable__hole {
|
|
||||||
pointer-events: all;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,139 +0,0 @@
|
|||||||
/* eslint-disable @typescript-eslint/no-for-in-array */
|
|
||||||
/* eslint-disable @typescript-eslint/consistent-type-assertions */
|
|
||||||
import { Controller } from "stimulus";
|
|
||||||
|
|
||||||
async function sleep(time: number) {
|
|
||||||
return new Promise((resolve) => {
|
|
||||||
setTimeout(resolve, time);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export default class Sortable extends Controller {
|
|
||||||
dragged_element: HTMLDivElement | null = null;
|
|
||||||
|
|
||||||
clearDoubleHoles() {
|
|
||||||
this.element
|
|
||||||
.querySelectorAll(".ready-to-drop")
|
|
||||||
.forEach((e: HTMLDivElement) => e.classList.remove("ready-to-drop"));
|
|
||||||
}
|
|
||||||
|
|
||||||
getNthElement(n: number): HTMLDivElement | null {
|
|
||||||
return this.element.querySelector(`.sortable__element:nth-child(${n})`);
|
|
||||||
}
|
|
||||||
|
|
||||||
setIndex(node: HTMLDivElement, index: number) {
|
|
||||||
node.setAttribute("data-index", String(index));
|
|
||||||
node.style.setProperty("--index", String(index));
|
|
||||||
}
|
|
||||||
|
|
||||||
setupHoleListeners(hole: HTMLDivElement) {
|
|
||||||
hole.addEventListener("dragenter", (event) => {
|
|
||||||
event.dataTransfer.dropEffect = "move";
|
|
||||||
if (!this.dragged_element) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
(event.target as HTMLDivElement).classList.add("ready-to-drop");
|
|
||||||
event.preventDefault();
|
|
||||||
});
|
|
||||||
|
|
||||||
hole.addEventListener("dragover", (event) => {
|
|
||||||
event.dataTransfer.dropEffect = "move";
|
|
||||||
if (!this.dragged_element) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
event.preventDefault();
|
|
||||||
});
|
|
||||||
|
|
||||||
hole.addEventListener("dragleave", (event) => {
|
|
||||||
(event.target as HTMLDivElement).classList.remove("ready-to-drop");
|
|
||||||
event.preventDefault();
|
|
||||||
});
|
|
||||||
|
|
||||||
hole.addEventListener("drop", (event) => {
|
|
||||||
const target = event.target as HTMLDivElement;
|
|
||||||
target.classList.remove("ready-to-drop");
|
|
||||||
const index_of_dropped_element = parseInt(
|
|
||||||
this.dragged_element.getAttribute("data-index")
|
|
||||||
);
|
|
||||||
const index_of_drop_target = parseInt(target.getAttribute("data-index"));
|
|
||||||
|
|
||||||
const nodes_of_dropped_element_index = this.element.querySelectorAll(
|
|
||||||
`[data-index="${index_of_dropped_element}"]`
|
|
||||||
);
|
|
||||||
const nodes_of_target_index = this.element.querySelectorAll(
|
|
||||||
`[data-index="${index_of_drop_target}"]`
|
|
||||||
);
|
|
||||||
|
|
||||||
let last_node_of_target_index =
|
|
||||||
nodes_of_target_index[nodes_of_target_index.length - 1];
|
|
||||||
|
|
||||||
for (const node of Array.from(nodes_of_dropped_element_index)) {
|
|
||||||
last_node_of_target_index.after(node);
|
|
||||||
this.setIndex(node as HTMLDivElement, index_of_drop_target);
|
|
||||||
last_node_of_target_index = node;
|
|
||||||
}
|
|
||||||
const next_to_correct = nodes_of_dropped_element_index[0].previousSibling;
|
|
||||||
const children = Array.from(next_to_correct.parentNode.childNodes);
|
|
||||||
const children_to_correct = children.slice(2);
|
|
||||||
for (const dom_index in children_to_correct) {
|
|
||||||
const index = Math.max(Math.floor(parseInt(dom_index) / 3), 0);
|
|
||||||
this.setIndex(children_to_correct[dom_index] as HTMLDivElement, index);
|
|
||||||
}
|
|
||||||
|
|
||||||
event.preventDefault();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
connect() {
|
|
||||||
this.element.querySelectorAll(".sortable__element").forEach((element) => {
|
|
||||||
element.addEventListener("dragstart", (e: DragEvent) => {
|
|
||||||
e.dataTransfer.effectAllowed = "move";
|
|
||||||
const target = e.target as HTMLDivElement;
|
|
||||||
this.dragged_element = target;
|
|
||||||
setTimeout(() => {
|
|
||||||
// https://stackoverflow.com/a/20733870/1467284
|
|
||||||
target.classList.add("is-dragged");
|
|
||||||
}, 0);
|
|
||||||
});
|
|
||||||
|
|
||||||
element.addEventListener("dragend", (e: DragEvent) => {
|
|
||||||
const target = e.target as HTMLDivElement;
|
|
||||||
this.dragged_element = null;
|
|
||||||
target.classList.remove("is-dragged");
|
|
||||||
});
|
|
||||||
});
|
|
||||||
this.element
|
|
||||||
.querySelectorAll(".edge-detector")
|
|
||||||
.forEach((detector: HTMLDivElement) => {
|
|
||||||
let is_hovered = false;
|
|
||||||
detector.addEventListener("dragenter", (e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
const target = e.target as HTMLDivElement;
|
|
||||||
const step = parseInt(target.getAttribute("data-step"));
|
|
||||||
is_hovered = true;
|
|
||||||
void (async () => {
|
|
||||||
while (is_hovered && this.dragged_element) {
|
|
||||||
window.scrollTo(window.scrollX, window.scrollY + step);
|
|
||||||
// eslint-disable-next-line no-await-in-loop
|
|
||||||
await sleep(16);
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
});
|
|
||||||
|
|
||||||
detector.addEventListener("dragover ", (e) => {
|
|
||||||
// necessary for drag events;
|
|
||||||
e.preventDefault();
|
|
||||||
});
|
|
||||||
|
|
||||||
detector.addEventListener("dragleave", (e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
is_hovered = false;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
this.element
|
|
||||||
.querySelectorAll(".sortable__hole")
|
|
||||||
.forEach((dropElement: HTMLDivElement) =>
|
|
||||||
this.setupHoleListeners(dropElement)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,42 +0,0 @@
|
|||||||
import { TempstreamJSX } from "tempstream";
|
|
||||||
|
|
||||||
export function sortable({ items }: { items: JSX.Element[] }) {
|
|
||||||
return (
|
|
||||||
<div class="sortable-wrapper">
|
|
||||||
<div
|
|
||||||
data-controller="sortable"
|
|
||||||
class="sortable"
|
|
||||||
style={`grid-template-rows: repeat(${
|
|
||||||
items.length * 2
|
|
||||||
}, minmax(8px, min-content))`}
|
|
||||||
>
|
|
||||||
<div class="edge-detector" style="top: 0" data-step="-10"></div>
|
|
||||||
<div class="edge-detector" style="bottom: 0" data-step="10"></div>
|
|
||||||
<div class="sortable__hole" data-index="-1" style="--index: -1"></div>
|
|
||||||
<div class="sortable__spacer" data-index="-1" style="--index: -1"></div>
|
|
||||||
{items.map((item, index) => (
|
|
||||||
<>
|
|
||||||
<div
|
|
||||||
class="sortable__element"
|
|
||||||
draggable="true"
|
|
||||||
style={`--index: ${index}`}
|
|
||||||
data-index={index.toString()}
|
|
||||||
>
|
|
||||||
{item}
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
class="sortable__hole"
|
|
||||||
style={`--index: ${index}`}
|
|
||||||
data-index={index.toString()}
|
|
||||||
></div>
|
|
||||||
<div
|
|
||||||
class="sortable__spacer"
|
|
||||||
style={`--index: ${index}`}
|
|
||||||
data-index={index.toString()}
|
|
||||||
></div>
|
|
||||||
</>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
@ -2,7 +2,7 @@ import type { Context } from "koa";
|
|||||||
import { TempstreamJSX } from "tempstream";
|
import { TempstreamJSX } from "tempstream";
|
||||||
import { Page } from "@sealcode/sealgen";
|
import { Page } from "@sealcode/sealgen";
|
||||||
import html from "../../html.js";
|
import html from "../../html.js";
|
||||||
import { sortable } from "../common/sortable/sortable.js";
|
import { sortable } from "@sealcode/sortable";
|
||||||
|
|
||||||
export const actionName = "SortableDemo";
|
export const actionName = "SortableDemo";
|
||||||
|
|
||||||
|
@ -16,9 +16,6 @@ application.register("map-with-pins", MapWithPins);
|
|||||||
import { default as HorizontalScroller } from "./../back/routes/common/horizontal-scroller/horizontal-scroller.stimulus.js";
|
import { default as HorizontalScroller } from "./../back/routes/common/horizontal-scroller/horizontal-scroller.stimulus.js";
|
||||||
application.register("horizontal-scroller", HorizontalScroller);
|
application.register("horizontal-scroller", HorizontalScroller);
|
||||||
|
|
||||||
import { default as Sortable } from "./../back/routes/common/sortable/sortable.stimulus.js";
|
|
||||||
application.register("sortable", Sortable);
|
|
||||||
|
|
||||||
import { default as AutogrowTextarea } from "./../../node_modules/@sealcode/jdd-editor/src/controllers/autogrow-textarea.stimulus.js";
|
import { default as AutogrowTextarea } from "./../../node_modules/@sealcode/jdd-editor/src/controllers/autogrow-textarea.stimulus.js";
|
||||||
application.register("autogrow-textarea", AutogrowTextarea);
|
application.register("autogrow-textarea", AutogrowTextarea);
|
||||||
|
|
||||||
@ -52,4 +49,7 @@ application.register("submit-on-input", SubmitOnInput);
|
|||||||
import { default as Toast } from "./../../node_modules/@sealcode/jdd-editor/src/controllers/toast.stimulus.js";
|
import { default as Toast } from "./../../node_modules/@sealcode/jdd-editor/src/controllers/toast.stimulus.js";
|
||||||
application.register("toast", Toast);
|
application.register("toast", Toast);
|
||||||
|
|
||||||
|
import { default as Sortable } from "./../../node_modules/@sealcode/sortable/src/controllers/sortable.stimulus.js";
|
||||||
|
application.register("sortable", Sortable);
|
||||||
|
|
||||||
export { Turbo };
|
export { Turbo };
|
||||||
|
Loading…
x
Reference in New Issue
Block a user