diff options
| author | netop://ウィビ <paul@webb.page> | 2026-04-24 16:37:33 -0700 |
|---|---|---|
| committer | netop://ウィビ <paul@webb.page> | 2026-04-24 16:37:33 -0700 |
| commit | 510fd8cbe53abb39cba2c7cbaaefcf2783dc0066 (patch) | |
| tree | 8f753a33c475b285f2a297785d34cda3b0a8faed /source/library/components/Splitter.svelte | |
| parent | 261f3bdb77799009344aab4a60686b7186ebd3b0 (diff) | |
| download | graphiql-510fd8cbe53abb39cba2c7cbaaefcf2783dc0066.tar.gz graphiql-510fd8cbe53abb39cba2c7cbaaefcf2783dc0066.zip | |
Implement v0.6-1.0: shortcuts, format, export/import, splitter, timing, APQ
- v0.6: matchShortcut + format(); Cmd+Shift+Enter/W/F + Cmd+Alt+arrows
- v0.7: SessionStore.exportAll/importTabs with version-1 validator
- v0.8: Splitter component + four resize handles persisted under layout.*
- v0.10: createApqFetcher (HTTP-only) wrapping shared http-body helpers
- Drop .svelte re-exports from index.ts for multi-entry JSR/npm publishing
Diffstat (limited to 'source/library/components/Splitter.svelte')
| -rw-r--r-- | source/library/components/Splitter.svelte | 123 |
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> |