diff --git a/examples/BasicExample.tsx b/examples/BasicExample.tsx index f7e00399..408637fa 100644 --- a/examples/BasicExample.tsx +++ b/examples/BasicExample.tsx @@ -1,4 +1,4 @@ -import React, { useState, useEffect } from 'react'; +import React, { useState } from 'react'; import { SplitPane, Pane } from '../src'; export function BasicExample() { @@ -6,36 +6,19 @@ export function BasicExample() { 'horizontal' ); - // Default to vertical on mobile for better usability - useEffect(() => { - const isMobile = window.innerWidth <= 768; - if (isMobile) { - setDirection('vertical'); - } - }, []); - return (
-
+

Basic Split Pane

A simple two-pane layout.{' '} @@ -43,47 +26,21 @@ export function BasicExample() {

- -
-

Sidebar

-

Min size: 80px. Drag the divider to resize.

-
-
src
-
- index.ts -
-
- App.tsx -
-
components
-
styles
-
+ +
+

Left Pane

+

minSize: 100px

-
-

Main Content

-

Use arrow keys when focused for keyboard control.

-
+
+

Right Pane

+

Drag the divider to resize.

+
- {`import { SplitPane, Pane } from 'react-split-pane'; - - - - Sidebar - - - Main Content - + {` + Left + Right `}
diff --git a/examples/ControlledExample.tsx b/examples/ControlledExample.tsx index 460192aa..4963c9cf 100644 --- a/examples/ControlledExample.tsx +++ b/examples/ControlledExample.tsx @@ -1,98 +1,44 @@ -import React, { useState, useEffect } from 'react'; +import React, { useState } from 'react'; import { SplitPane, Pane } from '../src'; -const STORAGE_KEY = 'split-pane-sizes'; - export function ControlledExample() { - const [sizes, setSizes] = useState(() => { - const saved = localStorage.getItem(STORAGE_KEY); - return saved ? JSON.parse(saved) : [300, 500]; - }); - - useEffect(() => { - localStorage.setItem(STORAGE_KEY, JSON.stringify(sizes)); - }, [sizes]); - - const handleResize = (newSizes: number[]) => { - setSizes(newSizes); - }; - - const handleReset = () => { - setSizes([300, 500]); - }; + const [sizes, setSizes] = useState([200, 400]); return (
-
-

Controlled + Persistent

+
+

Controlled

- Sizes are controlled via state and persisted to localStorage. Refresh - to see persistence. -

- - -
-

Panel A

-

This pane's size is controlled.

-
- Width: {Math.round(sizes[0])}px -
-
+ + +
+

Panel A

+

{Math.round(sizes[0])}px

+
+
+ +
+

Panel B

+

{Math.round(sizes[1])}px

+
- {`const [sizes, setSizes] = useState([300, 500]); + {`const [sizes, setSizes] = useState([200, 400]); - - Panel A - - - Panel B - + A + B `}
- -
-

Panel B

-

Sizes are saved to localStorage on every change.

-
- Width: {Math.round(sizes[1])}px -
-
-

- localStorage -

- - {STORAGE_KEY}: {JSON.stringify(sizes.map(Math.round))} - -
-
-
diff --git a/examples/NestedExample.tsx b/examples/NestedExample.tsx index 4eab6cf5..7d84e9cb 100644 --- a/examples/NestedExample.tsx +++ b/examples/NestedExample.tsx @@ -1,88 +1,30 @@ -import React, { useState, useEffect } from 'react'; +import React from 'react'; import { SplitPane, Pane } from '../src'; export function NestedExample() { - const [isMobile, setIsMobile] = useState(false); - - useEffect(() => { - setIsMobile(window.innerWidth <= 768); - }, []); - return (
-
+

Nested Split Panes

-

Create complex layouts by nesting split panes. IDE-style layout.

+

Create complex layouts by nesting split panes.

- - -
-

Explorer

-
-
react-split-pane
-
- src -
-
- index.ts -
-
- SplitPane.tsx -
-
- Pane.tsx -
-
+ + +
+

Sidebar

- + - -
-

Editor

-
- - {`export function SplitPane(props) { - const { - direction = 'horizontal', - children, - } = props; - - return ( -
- {renderChildren()} -
- ); -}`} -
-
+ +
+

Main

- -
-

Terminal

-
-
$ npm test
-
- ✓ 14 tests passed -
-
- All tests passed -
-
+ +
+

Panel

diff --git a/examples/PercentageExample.tsx b/examples/PercentageExample.tsx new file mode 100644 index 00000000..f05c0b6d --- /dev/null +++ b/examples/PercentageExample.tsx @@ -0,0 +1,41 @@ +import React from 'react'; +import { SplitPane, Pane } from '../src'; + +export function PercentageExample() { + return ( +
+
+

Percentage Sizes

+

Use percentage values for responsive layouts.

+
+
+ + +
+

25%

+
+
+ +
+

50%

+
+ + {` + A + B + C +`} + +
+
+
+ +
+

25%

+
+
+
+
+
+ ); +} diff --git a/examples/SnapPointsExample.tsx b/examples/SnapPointsExample.tsx index 9a089dec..705ff74e 100644 --- a/examples/SnapPointsExample.tsx +++ b/examples/SnapPointsExample.tsx @@ -3,28 +3,13 @@ import { SplitPane, Pane } from '../src'; export function SnapPointsExample() { const [currentSize, setCurrentSize] = useState(null); - const snapPoints = [150, 300, 450]; + const snapPoints = [150, 300, 450, 600, 800]; return (
-
+

Snap Points

-

- Panes snap to predefined positions when dragging. Snap points:{' '} - {snapPoints.map((p, i) => ( - - {p}px{i < snapPoints.length - 1 ? ', ' : ''} - - ))} -

- {currentSize !== null && ( -

- Current size: {Math.round(currentSize)}px - {snapPoints.includes(Math.round(currentSize)) && ( - Snapped! - )} -

- )} +

Panes snap to predefined positions: {snapPoints.join(', ')}px

setCurrentSize(sizes[0] ?? null)} > -
-

Sidebar

-

Drag the divider and feel it snap to:

+
+

Left Pane

+ {currentSize !== null && ( +

{Math.round(currentSize)}px

+ )}
    {snapPoints.map((point) => (
  • ))}
-

- Tip: When within 20px of a snap point, the pane will snap to - that position. -

-
-

Main Content

-

- Snap points are useful for creating consistent layouts where - panes should align to specific widths. -

-
+
+

Right Pane

+
- {`import { SplitPane, Pane } from 'react-split-pane'; - -function App() { - return ( - - - Sidebar - - - Main Content - - - ); -}`} + {` + ... +`}
diff --git a/examples/StyledExample.tsx b/examples/StyledExample.tsx index 8dcb8714..8a4d29f0 100644 --- a/examples/StyledExample.tsx +++ b/examples/StyledExample.tsx @@ -3,30 +3,14 @@ import { SplitPane, Pane } from '../src'; import type { DividerProps } from '../src/types'; function CustomDivider(props: DividerProps) { - const { - direction, - isDragging, - disabled, - onMouseDown, - onTouchStart, - onTouchEnd, - onKeyDown, - } = props; + const { direction, isDragging, disabled, onMouseDown, onTouchStart, onTouchEnd, onKeyDown } = props; return (
-
-

Custom Styling

-

- Use custom divider components and CSS for unique looks. This example - uses a gradient divider. -

+
+
+

Custom Divider

+

Use a custom divider component for different styles.

-
-

Panel 1

-

- Custom gradient background -

+
+

Panel 1

-
-

Panel 2

-

- The divider is a custom component -

-
- +
+

Panel 2

+
+ {` ... - ... `}
-
-

Panel 3

-

- Three panes supported -

+
+

Panel 3

diff --git a/examples/TouchExample.tsx b/examples/TouchExample.tsx deleted file mode 100644 index 976c7cf6..00000000 --- a/examples/TouchExample.tsx +++ /dev/null @@ -1,99 +0,0 @@ -import React, { useState, useEffect } from 'react'; -import { SplitPane, Pane } from '../src'; - -export function TouchExample() { - const [resizeSource, setResizeSource] = useState(null); - const [sizes, setSizes] = useState([]); - const [direction, setDirection] = useState<'horizontal' | 'vertical'>( - 'horizontal' - ); - - // Use vertical layout on mobile for better touch experience - useEffect(() => { - const isMobile = window.innerWidth <= 768; - if (isMobile) { - setDirection('vertical'); - } - }, []); - - return ( -
-
-

Touch Support

-

Full touch support for mobile. Drag the divider with your finger!

- {resizeSource && ( -

- Via:{' '} - {resizeSource} - {sizes.length > 0 && ( - | {sizes.map((s) => Math.round(s)).join('/')}px - )} -

- )} -
-
- setResizeSource(event.source)} - onResize={(newSizes) => setSizes(newSizes)} - > - -
-

Touch Here

-
-
- - 👆 - -
-

Drag the divider with your finger

-
    -
  • Works on iOS Safari
  • -
  • Works on Chrome Android
  • -
  • Works on tablets
  • -
-
-
-
- -
-

Resize Methods

-
-
- 🖱️ - Mouse - Click and drag -
-
- 👆 - Touch - Tap and drag -
-
- ⌨️ - Keyboard - Arrow keys when focused -
-
-
- - {`// Touch events handled automatically - { - // e.source: 'mouse' | 'touch' | 'keyboard' - }} - onResize={(sizes) => { - console.log('Sizes:', sizes); - }} -> - ... -`} - -
-
-
-
-
-
- ); -} diff --git a/examples/main.tsx b/examples/main.tsx index ec74eb02..ed4a4d04 100644 --- a/examples/main.tsx +++ b/examples/main.tsx @@ -5,10 +5,10 @@ import { NestedExample } from './NestedExample'; import { ControlledExample } from './ControlledExample'; import { StyledExample } from './StyledExample'; import { SnapPointsExample } from './SnapPointsExample'; -import { TouchExample } from './TouchExample'; +import { PercentageExample } from './PercentageExample'; import './styles.css'; -type Example = 'basic' | 'nested' | 'controlled' | 'styled' | 'snap' | 'touch'; +type Example = 'basic' | 'nested' | 'controlled' | 'styled' | 'snap' | 'percent'; const examples: { id: Example; label: string; shortLabel: string }[] = [ { id: 'basic', label: 'Basic', shortLabel: 'Basic' }, @@ -16,11 +16,11 @@ const examples: { id: Example; label: string; shortLabel: string }[] = [ { id: 'controlled', label: 'Controlled', shortLabel: 'Ctrl' }, { id: 'styled', label: 'Styled', shortLabel: 'Style' }, { id: 'snap', label: 'Snap Points', shortLabel: 'Snap' }, - { id: 'touch', label: 'Touch', shortLabel: 'Touch' }, + { id: 'percent', label: 'Percentage', shortLabel: '%' }, ]; function App() { - const [example, setExample] = useState('touch'); + const [example, setExample] = useState('basic'); return (
@@ -32,7 +32,6 @@ function App() { key={id} className={example === id ? 'active' : ''} onClick={() => setExample(id)} - aria-label={label} > {label} {shortLabel} @@ -47,7 +46,7 @@ function App() { {example === 'controlled' && } {example === 'styled' && } {example === 'snap' && } - {example === 'touch' && } + {example === 'percent' && }
); diff --git a/examples/styles.css b/examples/styles.css index b78ee8fd..a5bcce54 100644 --- a/examples/styles.css +++ b/examples/styles.css @@ -2,37 +2,25 @@ box-sizing: border-box; margin: 0; padding: 0; - -webkit-tap-highlight-color: transparent; } html, body, #root { height: 100%; - /* Prevent pull-to-refresh on mobile */ - overscroll-behavior: none; } body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; - background: #1a1a2e; - color: #eee; - /* Prevent text selection during drag on mobile */ - -webkit-user-select: none; - user-select: none; - /* Safe area support for iPhone notch */ - padding-top: env(safe-area-inset-top); - padding-bottom: env(safe-area-inset-bottom); - padding-left: env(safe-area-inset-left); - padding-right: env(safe-area-inset-right); + background: #fff; + color: #333; } .app { display: flex; flex-direction: column; height: 100%; - overflow: hidden; } .nav { @@ -40,55 +28,42 @@ body { align-items: center; justify-content: space-between; padding: 1rem 2rem; - background: #16213e; - border-bottom: 1px solid #0f3460; - flex-shrink: 0; + background: #fff; + border-bottom: 1px solid #ddd; } .nav h1 { font-size: 1.25rem; font-weight: 600; - color: #e94560; } .nav-buttons { display: flex; gap: 0.5rem; - flex-wrap: wrap; } .nav-buttons button { padding: 0.5rem 1rem; - border: 1px solid #0f3460; + border: 1px solid #ddd; border-radius: 4px; - background: transparent; - color: #eee; + background: #fff; cursor: pointer; - transition: all 0.2s; - /* Minimum touch target size (44px recommended by Apple) */ - min-height: 44px; - min-width: 44px; } .nav-buttons button:hover { - background: #0f3460; + background: #f5f5f5; } .nav-buttons button.active { - background: #e94560; - border-color: #e94560; + background: #333; + border-color: #333; + color: #fff; } -/* Label visibility for responsive buttons */ .nav-buttons .label-short { display: none; } -.nav-buttons .label-full { - display: inline; -} - -/* Mobile navigation */ @media (max-width: 768px) { .nav { flex-direction: column; @@ -96,26 +71,16 @@ body { padding: 0.75rem 1rem; } - .nav h1 { - font-size: 1.1rem; - } - .nav-buttons { - width: 100%; + flex-wrap: wrap; justify-content: center; - gap: 0.375rem; } .nav-buttons button { - padding: 0.5rem 0.75rem; - font-size: 0.8rem; - flex: 1; - min-width: unset; + padding: 0.4rem 0.75rem; + font-size: 0.875rem; } -} -/* iPhone SE and small phones */ -@media (max-width: 480px) { .nav-buttons .label-short { display: inline; } @@ -125,190 +90,77 @@ body { } } -@media (max-width: 375px) { - .nav-buttons { - display: grid; - grid-template-columns: repeat(3, 1fr); - gap: 0.25rem; - } - - .nav-buttons button { - padding: 0.5rem 0.25rem; - font-size: 0.7rem; - } -} - .main { flex: 1; overflow: hidden; } -/* Pane content styles */ -.pane-content { - height: 100%; - padding: 1rem; - display: flex; - flex-direction: column; - overflow: auto; - -webkit-overflow-scrolling: touch; -} - -.pane-content h2 { - font-size: 1rem; - margin-bottom: 0.5rem; - color: #e94560; -} - -.pane-content p { - font-size: 0.875rem; - color: #aaa; - line-height: 1.5; -} - -.pane-content.sidebar { - background: #16213e; -} - -.pane-content.editor { - background: #1a1a2e; -} - -.pane-content.preview { - background: #0f3460; -} - -.pane-content.console { - background: #111; - font-family: monospace; +/* Split pane divider - 1px line with expanded hit area */ +.split-pane-divider { + background: #ddd; + position: relative; } -/* Mobile pane content adjustments */ -@media (max-width: 768px) { - .pane-content { - padding: 0.75rem; - } - - .pane-content h2 { - font-size: 0.9rem; - } - - .pane-content p { - font-size: 0.8rem; - } +.split-pane-divider::before { + content: ''; + position: absolute; + background: transparent; } -/* Split pane divider styles - expanded hover area pattern */ -.split-pane-divider { - background: #0f3460; - z-index: 1; - box-sizing: border-box; - background-clip: padding-box; - transition: all 0.2s ease; +.split-pane-divider:hover::before, +.split-pane-divider.dragging::before { + background: rgba(0, 0, 0, 0.08); } .split-pane-divider:focus { - outline: 2px solid #e94560; - outline-offset: -2px; + outline: 2px solid #0066cc; + outline-offset: -1px; } .split-pane-divider.horizontal { - width: 11px !important; - margin-left: -5px !important; - margin-right: -5px !important; - border-left: 5px solid rgba(0, 0, 0, 0); - border-right: 5px solid rgba(0, 0, 0, 0); + width: 1px; cursor: col-resize; } -.split-pane-divider.horizontal:hover { - border-left: 5px solid rgba(233, 69, 96, 0.5); - border-right: 5px solid rgba(233, 69, 96, 0.5); +.split-pane-divider.horizontal::before { + top: 0; + bottom: 0; + left: -4px; + right: -4px; } .split-pane-divider.vertical { - height: 11px !important; - margin-top: -5px !important; - margin-bottom: -5px !important; - border-top: 5px solid rgba(0, 0, 0, 0); - border-bottom: 5px solid rgba(0, 0, 0, 0); + height: 1px; cursor: row-resize; } -.split-pane-divider.vertical:hover { - border-top: 5px solid rgba(233, 69, 96, 0.5); - border-bottom: 5px solid rgba(233, 69, 96, 0.5); -} - -/* Mobile/touch-friendly divider sizes */ -@media (max-width: 768px) { - .split-pane-divider.horizontal { - width: 20px !important; - margin-left: -10px !important; - margin-right: -10px !important; - border-left: 10px solid rgba(0, 0, 0, 0); - border-right: 10px solid rgba(0, 0, 0, 0); - } - - .split-pane-divider.vertical { - height: 20px !important; - margin-top: -10px !important; - margin-bottom: -10px !important; - border-top: 10px solid rgba(0, 0, 0, 0); - border-bottom: 10px solid rgba(0, 0, 0, 0); - } -} - -/* Touch device detection - even larger targets */ -@media (hover: none) and (pointer: coarse) { - .split-pane-divider.horizontal { - width: 24px !important; - margin-left: -12px !important; - margin-right: -12px !important; - border-left: 12px solid rgba(0, 0, 0, 0); - border-right: 12px solid rgba(0, 0, 0, 0); - } - - .split-pane-divider.horizontal:active { - border-left: 12px solid rgba(233, 69, 96, 0.7); - border-right: 12px solid rgba(233, 69, 96, 0.7); - } - - .split-pane-divider.vertical { - height: 24px !important; - margin-top: -12px !important; - margin-bottom: -12px !important; - border-top: 12px solid rgba(0, 0, 0, 0); - border-bottom: 12px solid rgba(0, 0, 0, 0); - } - - .split-pane-divider.vertical:active { - border-top: 12px solid rgba(233, 69, 96, 0.7); - border-bottom: 12px solid rgba(233, 69, 96, 0.7); - } +.split-pane-divider.vertical::before { + left: 0; + right: 0; + top: -4px; + bottom: -4px; } -/* Example specific styles */ +/* Example layout */ .example-container { height: 100%; display: flex; flex-direction: column; } -.example-info { +.example-header { padding: 1rem; - background: #16213e; - border-bottom: 1px solid #0f3460; - flex-shrink: 0; + border-bottom: 1px solid #ddd; } -.example-info h2 { +.example-header h2 { font-size: 1rem; margin-bottom: 0.25rem; } -.example-info p { - font-size: 0.8rem; - color: #888; +.example-header p { + font-size: 0.875rem; + color: #666; } .example-content { @@ -316,313 +168,148 @@ body { min-height: 0; } -/* Mobile example info */ -@media (max-width: 768px) { - .example-info { - padding: 0.75rem; - } - - .example-info h2 { - font-size: 0.9rem; - } - - .example-info p { - font-size: 0.75rem; - } -} - -/* Controlled example */ -.size-display { - font-family: monospace; - font-size: 0.75rem; - color: #e94560; - margin-top: 0.5rem; -} - -/* Styled example - custom divider */ -.custom-divider { - background: linear-gradient(to bottom, #e94560, #0f3460); - display: flex; - align-items: center; - justify-content: center; -} - -.custom-divider.horizontal { - width: 8px !important; - margin-left: -4px !important; - margin-right: -4px !important; -} - -.custom-divider.vertical { - height: 8px !important; - margin-top: -4px !important; - margin-bottom: -4px !important; -} - -.custom-divider::after { - content: '···'; - color: white; - font-size: 10px; - writing-mode: vertical-rl; -} - -.custom-divider.vertical::after { - writing-mode: horizontal-tb; -} - -/* File tree styles */ -.file-tree { - font-size: 0.8rem; - margin-top: 1rem; -} - -.file-tree-item { - padding: 0.25rem 0; - cursor: pointer; +/* Pane content */ +.pane { + height: 100%; + padding: 1rem; display: flex; - align-items: center; - gap: 0.5rem; + flex-direction: column; } -.file-tree-item:hover { - color: #e94560; +.pane h3 { + font-size: 0.875rem; + margin-bottom: 0.5rem; + color: #333; } -.file-tree-item.folder::before { - content: '📁'; +.pane p { + font-size: 0.875rem; + color: #666; } -.file-tree-item.file::before { - content: '📄'; +.pane.gray { + background: #f5f5f5; } /* Code block */ -.code-block { - background: #0a0a0a; +.code { + background: #f5f5f5; border-radius: 4px; padding: 1rem; font-family: monospace; font-size: 0.8rem; overflow: auto; - flex: 1; margin-top: 0.5rem; - -webkit-overflow-scrolling: touch; } -.code-block code { - color: #8be9fd; +.code code { white-space: pre; display: block; } -/* Mobile file tree and code blocks */ -@media (max-width: 768px) { - .file-tree { - font-size: 0.75rem; - } - - .file-tree-item { - padding: 0.375rem 0; - } - - .code-block { - padding: 0.75rem; - font-size: 0.65rem; - } -} - -/* Very small screens - hide code blocks or make them scrollable */ -@media (max-width: 375px) { - .code-block { - font-size: 0.6rem; - padding: 0.5rem; - } - - .code-block code { - font-size: inherit; - } -} - -/* Snap points example */ -.snap-indicator { - display: inline-block; - background: #0f3460; - padding: 0.125rem 0.5rem; - border-radius: 4px; - font-family: monospace; - font-size: 0.75rem; - margin-right: 0.25rem; +/* Styled example */ +.styled-pane { + color: #fff; } -.snap-list { - list-style: none; - margin-top: 1rem; +.styled-pane h3 { + color: #fff; } -.snap-list li { - padding: 0.5rem; - font-family: monospace; - border-left: 3px solid #0f3460; - margin-bottom: 0.25rem; - transition: all 0.2s; +.styled-pane.purple { + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); } -.snap-list li.active { - border-color: #e94560; - background: rgba(233, 69, 96, 0.1); - color: #e94560; +.styled-pane.pink { + background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%); } -.snapped-badge { - display: inline-block; - background: #e94560; - color: white; - padding: 0.125rem 0.5rem; - border-radius: 4px; - font-size: 0.75rem; - margin-left: 0.5rem; +.styled-pane.blue { + background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%); } -.tip { - margin-top: 1rem; - padding: 0.5rem; - background: rgba(139, 233, 253, 0.1); - border-radius: 4px; - font-size: 0.75rem; - color: #8be9fd; +.code.dark { + background: rgba(0, 0, 0, 0.2); } -/* Touch example */ -.touch-example .split-pane-divider { - background: #e94560; +.code.dark code { + color: #fff; } -.touch-pane { +/* Custom divider - gradient with grip dots */ +.custom-divider { + background: linear-gradient(to bottom, #e94560, #0f3460); display: flex; - flex-direction: column; align-items: center; justify-content: center; - text-align: center; -} - -.touch-instructions { - margin-top: 1rem; -} - -.touch-icon { - font-size: 3rem; - margin-bottom: 1rem; + cursor: col-resize; + transition: opacity 0.15s; } -.touch-instructions ul { - list-style: none; - margin-top: 1rem; +.custom-divider:hover, +.custom-divider.dragging { + opacity: 0.8; } -.touch-instructions li { - padding: 0.25rem 0; - color: #8be9fd; +.custom-divider.horizontal { + width: 8px; } -.resize-methods { - display: flex; - flex-direction: column; - gap: 0.5rem; - margin: 1rem 0; - text-align: left; - width: 100%; +.custom-divider.vertical { + height: 8px; + cursor: row-resize; } -.method { - display: flex; - align-items: center; - gap: 1rem; - padding: 0.5rem; - background: #0f3460; - border-radius: 4px; +.custom-divider::after { + content: '···'; + color: rgba(255, 255, 255, 0.8); + font-size: 10px; + letter-spacing: 1px; + writing-mode: vertical-rl; } -.method-icon { - font-size: 1.5rem; +.custom-divider.vertical::after { + writing-mode: horizontal-tb; } -.method-name { - font-weight: bold; - color: #e94560; - min-width: 80px; +/* Snap points */ +.snap-list { + list-style: none; + margin-top: 0.5rem; } -.method-desc { - color: #aaa; +.snap-list li { + padding: 0.25rem 0.5rem; + font-family: monospace; font-size: 0.8rem; + border-left: 2px solid #ddd; + margin-bottom: 0.25rem; } -.source-mouse { - color: #8be9fd; -} - -.source-touch { - color: #50fa7b; +.snap-list li.active { + border-color: #0066cc; + background: #f0f7ff; } -.source-keyboard { - color: #ffb86c; +/* Size display */ +.size-display { + font-family: monospace; + font-size: 0.8rem; + color: #666; + margin-top: 0.5rem; } -/* Mobile touch example */ -@media (max-width: 768px) { - .touch-icon { - font-size: 2rem; - margin-bottom: 0.5rem; - } - - .touch-instructions { - margin-top: 0.5rem; - } - - .touch-instructions li { - font-size: 0.8rem; - } - - .method { - gap: 0.5rem; - padding: 0.375rem; - } - - .method-icon { - font-size: 1.25rem; - } - - .method-name { - font-size: 0.8rem; - min-width: 60px; - } - - .method-desc { - font-size: 0.7rem; - } - - .resize-methods { - margin: 0.5rem 0; - } +/* Button */ +.btn { + padding: 0.25rem 0.5rem; + background: #333; + border: none; + border-radius: 4px; + color: #fff; + cursor: pointer; + font-size: 0.8rem; } -/* iPhone SE and very small screens */ -@media (max-width: 375px) { - .touch-pane h2 { - font-size: 0.85rem; - } - - .touch-icon { - font-size: 1.5rem; - } - - .method { - flex-wrap: wrap; - } - - .method-desc { - width: 100%; - margin-top: 0.25rem; - } +.btn:hover { + background: #555; } diff --git a/src/components/Divider.tsx b/src/components/Divider.tsx index 56e576ec..dee87b03 100644 --- a/src/components/Divider.tsx +++ b/src/components/Divider.tsx @@ -62,16 +62,12 @@ export function Divider(props: DividerProps) { touchAction: 'none', ...(direction === 'horizontal' ? { - width: '11px', + width: '1px', cursor: disabled ? 'default' : 'col-resize', - marginLeft: '-5px', - marginRight: '-5px', } : { - height: '11px', + height: '1px', cursor: disabled ? 'default' : 'row-resize', - marginTop: '-5px', - marginBottom: '-5px', }), ...(isDragging && { cursor: direction === 'horizontal' ? 'col-resize' : 'row-resize', @@ -83,7 +79,12 @@ export function Divider(props: DividerProps) { ...style, }; - const combinedClassName = [DEFAULT_CLASSNAME, direction, className] + const combinedClassName = [ + DEFAULT_CLASSNAME, + direction, + isDragging && 'dragging', + className, + ] .filter(Boolean) .join(' ');