aboutsummaryrefslogtreecommitdiff
path: root/source/library/components/Splitter.svelte
diff options
context:
space:
mode:
Diffstat (limited to 'source/library/components/Splitter.svelte')
-rw-r--r--source/library/components/Splitter.svelte123
1 files changed, 123 insertions, 0 deletions
diff --git a/source/library/components/Splitter.svelte b/source/library/components/Splitter.svelte
new file mode 100644
index 0000000..f4138f2
--- /dev/null
+++ b/source/library/components/Splitter.svelte
@@ -0,0 +1,123 @@
+<script lang="ts">
+ type Props = {
+ onDrag: (dx: number, dy: number) => void;
+ onDragEnd?: () => void;
+ onDragStart?: () => void;
+ onKeyAdjust?: (delta: number) => void;
+ orientation: "horizontal" | "vertical";
+ };
+
+ let { onDrag, onDragEnd, onDragStart, onKeyAdjust, orientation }: Props = $props();
+
+ let dragging = $state(false);
+ let startX = $state(0);
+ let startY = $state(0);
+
+ function onPointerDown(event: PointerEvent) {
+ event.preventDefault();
+ dragging = true;
+ startX = event.clientX;
+ startY = event.clientY;
+ event.currentTarget instanceof Element &&
+ event.currentTarget.setPointerCapture(event.pointerId);
+ onDragStart?.();
+ }
+
+ function onPointerMove(event: PointerEvent) {
+ if (!dragging)
+ return;
+
+ onDrag(event.clientX - startX, event.clientY - startY);
+ }
+
+ function onPointerUp(event: PointerEvent) {
+ if (!dragging)
+ return;
+
+ dragging = false;
+ event.currentTarget instanceof Element &&
+ event.currentTarget.releasePointerCapture(event.pointerId);
+ onDragEnd?.();
+ }
+
+ function onKeydown(event: KeyboardEvent) {
+ if (!onKeyAdjust)
+ return;
+
+ if (orientation === "horizontal") {
+ if (event.key === "ArrowLeft") {
+ event.preventDefault();
+ onKeyAdjust(-16);
+ } else if (event.key === "ArrowRight") {
+ event.preventDefault();
+ onKeyAdjust(16);
+ }
+ } else {
+ if (event.key === "ArrowUp") {
+ event.preventDefault();
+ onKeyAdjust(-16);
+ } else if (event.key === "ArrowDown") {
+ event.preventDefault();
+ onKeyAdjust(16);
+ }
+ }
+ }
+</script>
+
+<style lang="scss">
+ .splitter {
+ align-items: center;
+ background: transparent;
+ display: flex;
+ justify-content: center;
+ position: relative;
+ touch-action: none;
+ user-select: none;
+
+ &:hover::after,
+ &.dragging::after {
+ background: var(--graphiql-accent, #0e639c);
+ }
+
+ &::after {
+ background: var(--graphiql-border, #333);
+ content: "";
+ position: absolute;
+ transition: background 120ms ease;
+ }
+
+ &.horizontal {
+ cursor: col-resize;
+ height: 100%;
+ width: 6px;
+
+ &::after {
+ height: 100%;
+ width: 1px;
+ }
+ }
+
+ &.vertical {
+ cursor: row-resize;
+ height: 6px;
+ width: 100%;
+
+ &::after {
+ height: 1px;
+ width: 100%;
+ }
+ }
+ }
+</style>
+
+<div
+ aria-orientation={orientation}
+ class="splitter {orientation}"
+ class:dragging
+ onkeydown={onKeydown}
+ onpointerdown={onPointerDown}
+ onpointermove={onPointerMove}
+ onpointerup={onPointerUp}
+ role="separator"
+ tabindex="0"
+></div>