diff --git a/demo/index.css b/demo/index.css index 46b84b7..15b42cf 100644 --- a/demo/index.css +++ b/demo/index.css @@ -1,46 +1,579 @@ -[draggable] { - user-select: none; +* { + margin: 0; + padding: 0; + box-sizing: border-box; + font-family: Poppins, sans-serif; + font-weight: 400; +} + +html, +body { + position: relative; + width: 100%; + height: 100dvh; + overflow: hidden; +} + +h1, +h2, +h3 { + letter-spacing: -0.025em; + margin-bottom: 1.25em; + + a { + color: black; + text-decoration: none; + } +} + +h1 { + font-size: 24px; + font-weight: 500; + text-decoration: underline; + text-underline-offset: 0.25em; +} + +h2 { + font-size: 20px; + font-weight: 500; + text-decoration: underline; + text-underline-offset: 0.25em; +} + +h3 { + font-size: 18px; + scroll-margin-top: 3.75em; +} + +p { + font-size: 16px; + color: rgb(51, 65, 85); + margin-bottom: 1.25em; +} + +ul { + margin-left: 1.25em; + display: flex; + flex-direction: column; + gap: 0.625em; +} + +span.snippet { + background-color: rgb(233, 233, 233); + padding: 0.25em; + border-radius: 6px; + font-size: 14px; +} + +pre.shiki { + padding: 1.25em 0; + overflow: auto; + border-radius: 12px; + + code { + * { + font-family: "Cascadia Code", monospace; + } + + span.line { + padding: 0.125em 1.25em; + } + } +} + +.code-container { + position: relative; + width: 100%; + max-width: 100%; + margin-bottom: 1.25em; +} + +#container { + position: relative; + width: 100%; + height: 100%; + display: flex; + flex-direction: column; + justify-content: flex-start; + align-items: center; + overflow-y: auto; + scroll-behavior: smooth; +} + +div#content { + position: relative; + width: 100%; + flex-grow: 1; + display: flex; + justify-content: center; + align-items: flex-start; + gap: 10em; + padding: 0 1.25em; +} + +main { + position: relative; + width: 100%; + display: flex; + flex-direction: column; + justify-content: flex-start; + align-items: flex-start; + gap: 2.5em; + max-width: 45em; +} + +section { + position: relative; + width: 100%; + display: flex; + flex-direction: column; + justify-content: flex-start; + scroll-margin-top: 3.75em; +} + +section:first-child { + padding-top: 0; +} + +#navbar { + position: sticky; + top: 0; + left: 0; + width: 100%; + min-height: 3.75em; + padding: 0 1.25em; + display: flex; + justify-content: space-between; + align-items: center; + background-color: rgba(255, 255, 255, 0.4); + z-index: 10; + backdrop-filter: blur(5px); + + a { + display: flex; + justify-content: center; + align-items: center; + color: black; + } + + #menu-button { + border: none; + background-color: transparent; + cursor: pointer; + display: flex; + justify-content: center; + align-items: center; + } +} + +span.copyright { + align-self: center; + font-size: 14px; +} + +footer { + padding: 1.25em 0; +} + +#navigation-menu { + #background-overlay { + position: fixed; + display: none; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-color: rgba(0, 0, 0, 0.2); + opacity: 0; + transition: opacity 0.25s ease-in-out 0.25s; + z-index: -1; + } + + &.open #background-overlay { + display: block; + opacity: 1; + z-index: 20; + } + + #menu { + position: fixed; + top: 0; + right: -100%; + height: 100%; + display: flex; + flex-direction: column; + justify-content: space-between; + align-items: flex-start; + padding: 1.25em; + background-color: white; + transition: right 0.25s ease-in-out; + box-shadow: 0 0 2px 4px rgba(0, 0, 0, 0.1); + z-index: 30; + + #menu-links { + position: relative; + width: 100%; + display: flex; + flex-direction: column; + justify-content: flex-start; + align-items: flex-start; + gap: 2.5em; + + header { + position: relative; + width: 100%; + display: flex; + justify-content: space-between; + align-items: center; + + #close-button { + border: none; + background-color: transparent; + cursor: pointer; + } + } + + menu { + position: relative; + width: 100%; + display: flex; + flex-direction: column; + justify-content: flex-start; + align-items: flex-start; + gap: 0.625em; + + a { + color: black; + text-decoration: none; + } + + .menu-indented { + display: flex; + flex-direction: column; + gap: 0.625em; + padding-left: 2.5em; + } + } + } + } + + &.open #menu { + right: 0; + } +} + +#intro { + position: relative; + width: 100%; + display: flex; + flex-direction: column; + justify-content: flex-start; + align-items: flex-start; + gap: 1.25em; +} + +.note { + background-color: rgb(254, 252, 232); + padding: 1.25em; + border-radius: 12px; + margin-bottom: 1.25em; + + header { + display: flex; + gap: 1.25em; + align-items: center; + margin-bottom: 1.25em; + } + + p:last-child { + margin-bottom: 0; + } +} + +#overriding-default-behaviour { + div { + position: relative; + width: 100%; + overflow-x: auto; + + table { + border-collapse: collapse; + border-spacing: 0; + + th, + td { + padding: 1.25em 0; + text-align: start; + } + + th { + color: grey; + font-weight: 500; + } + + tr { + border-bottom: 1px solid lightgrey; + } + + tbody tr:last-child { + border-bottom: none; + } + + .attribute { + width: 38%; + } + + .description { + position: relative; + display: flex; + flex-direction: column; + justify-content: flex-start; + align-items: flex-start; + gap: 0.5em; + font-size: 14px; + + span { + position: relative; + width: 100%; + } + + .default-value { + color: grey; + } + } + + th.description { + font-size: 16px; + } + + .type { + width: 22%; + } + } + } +} + +[draggable] { + user-select: none; } .dragging { - opacity: 0.5; + opacity: 0.5; } #columns { - display: flex; - gap: 1rem; + display: grid; + grid-template-columns: repeat(2, auto); + gap: 1rem; + margin-bottom: 1.25em; - .column { - display: inline-block; - height: 150px; - width: 150px; - background: lightgrey; - opacity: 1; + .column { + display: inline-block; + height: 150px; + width: 150px; + background: lightgrey; + opacity: 1; - header { - color: #fff; - padding: 5px; - background: #222; - pointer-events: none; + header { + color: #fff; + padding: 5px; + background: #222; + pointer-events: none; + } + + &.over { + border: 2px dashed #000; + opacity: 0.5; + box-sizing: border-box; + } + + & > input, + & > textarea, + & > select { + display: block; + width: 85%; + margin: 5%; + max-height: calc(1.25em * 4); + } + + & > img { + height: 50%; + } + } +} + +#tasks { + margin-left: 0; + margin-bottom: 1.25em; + + .task { + position: relative; + display: flex; + gap: 1.25em; + + button { + outline: none; + border: none; + background-color: transparent; + } + + &.drag-over { + opacity: 0.5; + } + } +} + +#kanban-list { + margin-bottom: 1.25em; + + p { + margin-bottom: 0; + } +} + +#kanban-board { + position: relative; + width: 100%; + display: flex; + flex-direction: column; + justify-content: flex-start; + align-items: flex-start; + gap: 1.25em; + + .block { + position: relative; + width: 100%; + display: flex; + flex-direction: column; + justify-content: flex-start; + align-items: flex-start; + gap: 1.25em; + + &.drag-over ul { + border: 2px dashed rgb(0, 0, 0, 0.5); + } + + ul { + position: relative; + width: 100%; + display: flex; + justify-content: flex-start; + align-items: flex-start; + gap: 1.25em; + padding: 1.25em; + border-radius: 12px; + margin-left: 0; + list-style: none; + + li { + padding: 0.625em; + border-radius: 6px; + + &.drag-over { + opacity: 0.5; + } + } + } + + &#backlog ul { + background-color: rgb(240, 128, 128, 0.3); + + li { + background-color: rgb(240, 128, 128, 0.5); + } + } + + &#in-progress ul { + background-color: rgb(173, 216, 230, 0.3); + + li { + background-color: rgb(173, 216, 230, 0.5); + } + } + + &#done ul { + background-color: rgb(144, 238, 144, 0.3); + + li { + background-color: rgb(144, 238, 144, 0.5); + } + } + } +} + +#desktop-nav { + position: sticky; + display: none; + gap: 2.5em; + flex-direction: column; + top: 5em; + text-wrap: nowrap; + + menu { + display: flex; + flex-direction: column; + gap: 0.5em; + + span { + font-weight: 500; + margin-bottom: 1.25em; + } + + a { + color: black; + text-decoration: none; + } + + .menu-indented { + display: flex; + flex-direction: column; + gap: 0.5em; + padding-left: 2.5em; + } + } + + a#github-link { + display: flex; + align-items: center; + gap: 1.25em; + color: black; + text-decoration: none; + + span { + font-weight: 500; + } + } +} + +@media (min-width: 768px) { + #columns { + grid-template-columns: repeat(4, minmax(0, 1fr)); + } + + footer { + margin-top: 2.5em; + + span.copyright { + font-size: 16px; + } + } +} + +@media (min-width: 1200px) { + #navbar, + #navigation-menu { + display: none; } - &.over { - border: 2px dashed #000; - opacity: 0.5; - box-sizing: border-box; + #desktop-nav { + display: flex; } - & > input, - & > textarea, - & > select { - display: block; - width: 85%; - margin: 5%; - max-height: calc(1.25em * 4); + h1 { + margin-top: 3em; } - & > img { - height: 50%; + h3 { + scroll-margin-top: 1.25em; } - } } diff --git a/demo/index.html b/demo/index.html index 44f2666..ad6214e 100644 --- a/demo/index.html +++ b/demo/index.html @@ -1,81 +1,758 @@  - - - - - DragDropTouch - - - - - - -
-

Drag and Drop Touch

-

- This is a demo page that loads the drag-drop-touch.esm.js file for - shimming drag-and-drop functions for touch events. -

-

- Its project page is over on - https://github.com/drag-drop-touch-js/dragdroptouch. -

-
- -
-
-
-

A box dragging example

-

- Drag some boxes around with the mouse, then open your Developer - Tools, turn on mobile emulation, and try to do the same with touch - input enabled. Things should still work. -

-
- -
-
-
Input
- - -
- -
-
TextArea
- -
- -
-
Select
- - -
- -
-
Image
- grapefruit -
+ + + + + + + DragDropTouch + + + + + + + + + +
+ + +
+ +
+
+

Drag and Drop Touch

+

+ A polyfill that enables HTML5 drag drop support on mobile (touch) + devices. +

+

+ See the Github page + here. +

+
+
+

+ Why +

+

+ The HTML5 specification includes support for drag and drop operations. +

+

+ Unfortunately, this specification is based on mouse events, rather than + pointer events, and so most mobile browsers do not implement it. +

+

+ As such, applications that rely on HTML5 drag and drop have reduced + functionality when running on mobile devices. +

+

+ The DragDropTouch class is a polyfill that translates touch events into + standard HTML5 drag drop events. +

+

+ If you add the polyfill to your pages, drag and drop operations should + work on mobile devices just like they do on the desktop. +

+
+
+

Installation

+
+

+ Download the polyfill +

+

+ Add the drag-drop-touch.esm.js or + drag-drop-touch.esm.min.js polyfill + script to your page to enable drag and drop on devices with touch + input: +

+
+
+
+ + + + + ?autoload query argument +
+

+ This loads the polyfill and immediately enables it so that you + do not need to write any code yourself. +

+

+ If omitted, the library will instead set up a + window.DragDropTouch object with a + single function, + DragDropTouch.enable(dragRoot, dropRoot, options). All three arguments are optional. +

+

+ If left off, + DragDropTouch.enable() simply + polyfills the entire page. +

+

+ If you only want the polyfill to apply to specific elements + though, you can call the enable function once for each set of + elements that need polyfilling. +

+
+
+
+ + + + + type="module" attribute +
+

+ The type="module" attribute is + required. If left off, you'll probably get a browser error + similar to: +

+
+
+
+
+

Via a CDN url

+

+ If you can't or don't want to download the file, you can use the + following to include the polyfill. +

+
+
+
+

Via ESM

+

+ As an ES module, you can also use this polyfill as an import in + other scripts: +

+
+
+
+
+

Polyfill behaviour

+

+ The DragDropTouch class attaches listeners + to the document's touch events: +

+
    +
  • +

    + On touchstart, it checks whether + the target element has the + draggable attribute or is contained + in an element that does. If that is the case, it saves a + reference to the "drag source" element and prevents the default + handling of the event. +

    +
  • +
  • +

    + On touchmove, it checks whether the + touch has moved a certain threshold distance from the origin. If + that is the case, it raises the + dragstart event and continues + monitoring moves to fire + dragenter and + dragleave. +

    +
  • +
  • +

    + On touchend, it raises the + dragend and + drop events. +

    +
  • +
+

+ To avoid interfering with the automatic browser translation of some + touch events into mouse events, the polyfill performs a few additional + tasks: +

+
    +
  • +

    + Raise the mousemove, + mousedown, + mouseup, and + click events when the user touches + a draggable element but doesn't start dragging +

    +
  • +
  • +

    + Raise the dblclick event when + there's a new touchstart right + after a click +

    +
  • +
  • +

    + Raise the contextmenu event when + the touch lasts a while but the user doesn't start dragging the + element. +

    +
  • +
+
+
+

+ Overriding the default behaviour +

+

+ The following options can be passed into the enabling function to change + how the polyfill works: +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
AttributeTypeDescription
+ allowDragScroll + boolean + + Determines whether to allow scrolling when a drag + reaches the edges of the screen. + +
+ Default: true +
+ contextMenuDelayMS + number + + The number of milliseconds before the polyfill + triggers a context menu event on long press. + +
+ Default: 900 +
+ dragImageOpacity + + number (0 to 1) + + + Determines how transparent the drag placeholder + attached to the cursor should be. + +
+ Default: 0.5 +
+ dragScrollPercentage + number + + The size of the "hot region" at the edge of the + screen where scrolling is allowed during drag. + +
+ Default: 10 +
+ dragScrollSpeed + number + + The number of pixels to scroll when a drag event + occurs within the scrolling region. + +
+ Default: 10 +
+ dragThresholdPixels + number + + The number of pixels a touchmove needs to travel + before switching to drag mode. + +
+ Default: 5 +
+ isPressHoldMode + boolean + + Determines whether a long press is required to + initiate drag events. + +
+ Default: false +
+ forceListen + boolean + + Determines whether the polyfill should be enabled + irrespective of device touch capability. + +
+ Default: true +
+ pressHoldDelayMS + number + + The number of milliseconds before the polyfill + considers an active press as a "long press". + +
+ Default: 400 +
+ pressHoldMargin + number + + The number of pixels a touch event can drift during + a long press start. + +
+ Default: 25 +
+ pressHoldThresholdPixels + number + + The drift in pixels that determines whether a long + press initiates or starts a touch-drag. + +
+ Default: 0 +
+
+
+
+

Examples

+

+ Try some of the examples below, then 1) open your Developer Tools, turn + on mobile emulation to enable touch input or 2) use your phone, and try + to do the same. Things should still work. +

+

+ Dragging some boxes +

+

Just drag the boxes around.

+
+
+
Input
+ + +
+
+
TextArea
+ +
+
+
Select
+ + +
+
+
Image
+ grapefruit +
+
+

Sorting tasks

+

Drag the tasks into the order you want them to be sorted.

+
    +
  • + + Clean the dishes +
  • +
  • + + Walk the dog +
  • +
  • + + Wash the car +
  • +
  • + + Feed the cat +
  • +
+

+ Kanban board +

+

Drag and drop tasks into a Kanban board:

+
    +
  • +

    You can switch tasks by dropping one on top of another.

    +
  • +
  • +

    You can reorder tasks by dragging them up or down.

    +
  • +
  • +

    You can move them to another column by dragging them into it.

    +
  • +
+
+
+

Backlog

+
    +
  • + Implement user authentication flow +
  • +
  • + Write unit tests for API +
  • +
+
+
+

In progress

+
    +
  • + Add error handling for login +
  • +
+
+
+

Done

+
    +
  • + Set up the database +
  • +
  • + Create API endpoints for users +
  • +
+
+
+
+
+
+
-
-
- + diff --git a/demo/index.js b/demo/index.js index c6d121b..86ac1bd 100644 --- a/demo/index.js +++ b/demo/index.js @@ -1,77 +1,306 @@ -let draggable = null; +import { codeToHtml } from "https://esm.sh/shiki@1.0.0"; + +/** + * Swap two DOM nodes. + * @param {HTMLElement} a The first node. + * @param {HTMLElement} b The second node. + * @see https://stackoverflow.com/questions/9732624/how-to-swap-dom-child-nodes-in-javascript + */ +function swapDom(a, b) { + if (!a || !b) return; + + const aParent = a.parentNode; + const bParent = b.parentNode; + const aHolder = document.createElement(`div`); + const bHolder = document.createElement(`div`); + + aParent.replaceChild(aHolder, a); + bParent.replaceChild(bHolder, b); + aParent.replaceChild(b, aHolder); + bParent.replaceChild(a, bHolder); +} + +let draggableColumn = null; const cols = document.querySelectorAll(`#columns .column`); cols.forEach((col) => { - col.addEventListener(`dragstart`, handleDragStart); - col.addEventListener(`dragenter`, handleDragEnter); - col.addEventListener(`dragover`, handleDragOver); - col.addEventListener(`dragleave`, handleDragLeave); - col.addEventListener(`drop`, handleDrop); - col.addEventListener(`dragend`, handleDragEnd); + col.addEventListener(`dragstart`, handleDragStart); + col.addEventListener(`dragenter`, handleDragEnter); + col.addEventListener(`dragover`, handleDragOver); + col.addEventListener(`dragleave`, handleDragLeave); + col.addEventListener(`drop`, handleDrop); + col.addEventListener(`dragend`, handleDragEnd); }); function handleDragStart({ target, dataTransfer }) { - if (target.className.includes(`column`)) { - draggable = target; - draggable.classList.add(`dragging`); - - dataTransfer.effectAllowed = `move`; - dataTransfer.setData(`text`, draggable.innerHTML); - - // customize drag image for one of the panels - const haveDragFn = dataTransfer.setDragImage instanceof Function; - if (haveDragFn && target.textContent.includes(`X`)) { - let img = new Image(); - img.src = `dragimage.jpg`; - dataTransfer.setDragImage(img, img.width / 2, img.height / 2); + if (target.className.includes(`column`)) { + draggableColumn = target; + draggableColumn.classList.add(`dragging`); + + dataTransfer.effectAllowed = `move`; + dataTransfer.setData(`text`, draggableColumn.innerHTML); + + // customize drag image for one of the panels + const haveDragFn = dataTransfer.setDragImage instanceof Function; + if (haveDragFn && target.textContent.includes(`X`)) { + let img = new Image(); + img.src = `dragimage.jpg`; + dataTransfer.setDragImage(img, img.width / 2, img.height / 2); + } } - } } function handleDragOver(evt) { - if (draggable) { - evt.preventDefault(); - evt.dataTransfer.dropEffect = `move`; - } + if (draggableColumn) { + evt.preventDefault(); + evt.dataTransfer.dropEffect = `move`; + } } function handleDragEnter({ target }) { - if (draggable) { - target.classList.add(`over`); - } + if (draggableColumn) { + target.classList.add(`over`); + } } function handleDragLeave({ target }) { - if (draggable) { - target.classList.remove(`over`); - } + if (draggableColumn) { + target.classList.remove(`over`); + } } function handleDragEnd() { - draggable = null; - cols.forEach((col) => col.classList.remove(`over`)); + draggableColumn = null; + cols.forEach((col) => col.classList.remove(`over`)); } function handleDrop(evt) { - if (draggable === null) return; + if (draggableColumn === null) return; - evt.stopPropagation(); - evt.stopImmediatePropagation(); - evt.preventDefault(); + evt.stopPropagation(); + evt.stopImmediatePropagation(); + evt.preventDefault(); - if (draggable !== this) { - swapDom(draggable, this); - } + if (draggableColumn !== this) { + swapDom(draggableColumn, this); + } } -// https://stackoverflow.com/questions/9732624/how-to-swap-dom-child-nodes-in-javascript -function swapDom(a, b) { - let aParent = a.parentNode; - let bParent = b.parentNode; - let aHolder = document.createElement(`div`); - let bHolder = document.createElement(`div`); - aParent.replaceChild(aHolder, a); - bParent.replaceChild(bHolder, b); - aParent.replaceChild(b, aHolder); - bParent.replaceChild(a, bHolder); +function enableDragForTasks() { + /** @type {HTMLElement | null} */ + let currentlyDraggedTask = null; + + const tasks = document.querySelectorAll(`#tasks .task`); + for (let i = 0; i < tasks.length; i++) { + const task = tasks.item(i); + task.addEventListener("dragenter", () => { + if (currentlyDraggedTask === task) return; + + task.classList.add("drag-over"); + }); + task.addEventListener("drop", (event) => { + event.preventDefault(); + event.stopPropagation(); + event.stopImmediatePropagation(); + + task.classList.remove("drag-over"); + + if (currentlyDraggedTask !== task) { + swapDom(currentlyDraggedTask, task); + } + }); + task.addEventListener("dragleave", () => { + task.classList.remove("drag-over"); + }); + task.addEventListener("dragover", (event) => event.preventDefault()); + task.addEventListener("dragstart", () => { + currentlyDraggedTask = task; + }); + task.addEventListener("dragend", () => { + currentlyDraggedTask = null; + }); + } } + +enableDragForTasks(); + +function enableDragForKanbanBoard() { + let currentlyDraggedTask = null; + + const blocks = document.querySelectorAll(`#kanban-board .block`); + for (let i = 0; i < blocks.length; i++) { + const block = blocks[i]; + const tasks = block.querySelectorAll(".task"); + + for (let j = 0; j < tasks.length; j++) { + const task = tasks[j]; + + task.addEventListener("dragstart", () => { + currentlyDraggedTask = task; + }); + + task.addEventListener("dragend", () => { + currentlyDraggedTask = null; + }); + + task.addEventListener("dragover", (event) => { + event.preventDefault(); + task.classList.add("drag-over"); + }); + + task.addEventListener("dragleave", () => { + task.classList.remove("drag-over"); + }); + + task.addEventListener("drop", (event) => { + event.preventDefault(); + event.stopPropagation(); + + task.classList.remove("drag-over"); + blocks.forEach((block) => block.classList.remove("drag-over")); + + if (currentlyDraggedTask && currentlyDraggedTask !== task) { + swapDom(currentlyDraggedTask, task); + } + }); + } + + block.addEventListener("dragover", (event) => { + event.preventDefault(); + block.classList.add("drag-over"); + }); + + block.addEventListener("dragleave", () => { + block.classList.remove("drag-over"); + }); + + block.addEventListener("drop", (event) => { + event.preventDefault(); + event.stopPropagation(); + + block.classList.remove("drag-over"); + + if (currentlyDraggedTask) { + const ul = block.querySelector("ul"); + const tasks = block.querySelectorAll(".task"); + + // Get mouse position + const mouseY = event.clientY; + + // Loop through tasks and find the correct position + let inserted = false; + for (let i = 0; i < tasks.length; i++) { + const task = tasks[i]; + + // Get the task's bounding rectangle + const taskRect = task.getBoundingClientRect(); + + // Calculate the midpoint of the task + const taskMidY = taskRect.top + taskRect.height / 2; + + // If mouse is above the midpoint, insert before + if (mouseY < taskMidY) { + ul.insertBefore(currentlyDraggedTask, task); + inserted = true; + break; + } + } + + // If not inserted above any task, append at the end + if (!inserted) { + ul.appendChild(currentlyDraggedTask); + } + } + }); + } +} + +enableDragForKanbanBoard(); + +/** Change the current year in the copyright. */ +const currentYear = new Date().getFullYear(); +const copyrights = document.querySelectorAll(`.current-year`); +for (let i = 0; i < copyrights.length; i++) { + copyrights.item(i).innerHTML = currentYear; +} + +/** Handle opening and closing the menu on mobile. */ +const navigationContainer = document.querySelector(`#navigation-menu`); +const menuButton = document.querySelector(`#menu-button`); +const backgroundOverlay = document.querySelector(`#background-overlay`); +const closeButton = document.querySelector(`#close-button`); + +menuButton.addEventListener("click", () => { + navigationContainer.classList.toggle("open"); +}); + +backgroundOverlay.addEventListener("click", () => { + navigationContainer.classList.remove("open"); +}); + +closeButton.addEventListener("click", () => { + navigationContainer.classList.remove("open"); +}); + +/** Close the menu when a link is clicked. */ +const menuLinks = navigationContainer.getElementsByTagName("a"); +for (let i = 0; i < menuLinks.length; i++) { + menuLinks.item(i).addEventListener("click", () => { + navigationContainer.classList.remove("open"); + }); +} + +/** Highlight the code with Shiki. */ +const downloadPolyfillCode = document.querySelector(`#download-polyfill-code`); +downloadPolyfillCode.innerHTML = await codeToHtml( + ``, + { + lang: "javascript", + theme: "catppuccin-latte", + } +); + +const importMetaErrorCode = document.querySelector(`#import-meta-error-code`); +importMetaErrorCode.innerHTML = await codeToHtml( + `Uncaught SyntaxError: import.meta may only appear in a module`, + { + lang: "html", + theme: "catppuccin-latte", + } +); + +const cdnURLCode = document.querySelector(`#cdn-url-code`); +cdnURLCode.innerHTML = await codeToHtml( + ``, + { + lang: "javascript", + theme: "catppuccin-latte", + } +); + +const esmCode = document.querySelector(`#esm-code`); +esmCode.innerHTML = await codeToHtml( + `import { enableDragDropTouch } from "./drag-drop-touch.esm.min.js"; + +// Set up the default full page polyfill: +enableDragDropTouch(); + +// Or, explicitly polyfill only certain elements +enableDragDropTouch(dragRootElement, dropRootElement); + +// Or even explicitly polyfill only certain elements with non-default behaviour +const options = { + // ... +}; +enableDragDropTouch(dragRootElement, dropRootElement, options);`, + { + lang: "javascript", + theme: "catppuccin-latte", + } +);