cursedbelt 5.58.0 → 5.62.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/react/components/ColorSwatches.d.ts +33 -0
- package/dist/react/components/ColorSwatches.d.ts.map +1 -0
- package/dist/react/components/ColorSwatches.js +42 -0
- package/dist/react/components/ColorSwatches.js.map +1 -0
- package/dist/react/components/EditorPage.d.ts +1 -0
- package/dist/react/components/EditorPage.d.ts.map +1 -1
- package/dist/react/components/EditorPage.js +6 -1
- package/dist/react/components/EditorPage.js.map +1 -1
- package/dist/react/components/FormPreviewLayout.d.ts +1 -0
- package/dist/react/components/FormPreviewLayout.d.ts.map +1 -1
- package/dist/react/components/FormPreviewLayout.js +2 -1
- package/dist/react/components/FormPreviewLayout.js.map +1 -1
- package/dist/react/components/PaneSplit.d.ts +52 -0
- package/dist/react/components/PaneSplit.d.ts.map +1 -0
- package/dist/react/components/PaneSplit.js +103 -0
- package/dist/react/components/PaneSplit.js.map +1 -0
- package/dist/react/components/PointerDrag.d.ts +88 -0
- package/dist/react/components/PointerDrag.d.ts.map +1 -0
- package/dist/react/components/PointerDrag.js +156 -0
- package/dist/react/components/PointerDrag.js.map +1 -0
- package/dist/react/components/PropertyList.d.ts +17 -3
- package/dist/react/components/PropertyList.d.ts.map +1 -1
- package/dist/react/components/PropertyList.js +11 -3
- package/dist/react/components/PropertyList.js.map +1 -1
- package/dist/react/components/SwatchPicker.d.ts +37 -9
- package/dist/react/components/SwatchPicker.d.ts.map +1 -1
- package/dist/react/components/SwatchPicker.js +52 -9
- package/dist/react/components/SwatchPicker.js.map +1 -1
- package/dist/react/components/TreeView.d.ts +39 -4
- package/dist/react/components/TreeView.d.ts.map +1 -1
- package/dist/react/components/TreeView.js +54 -15
- package/dist/react/components/TreeView.js.map +1 -1
- package/dist/react/components/editorPage.css +1 -7
- package/dist/react/components/formKit.css +5 -6
- package/dist/react/components/paneSplit.css +93 -0
- package/dist/react/components/pointerDrag.css +39 -0
- package/dist/react/components/scrollRegion.css +31 -0
- package/dist/react/index.d.ts +2 -1
- package/dist/react/index.d.ts.map +1 -1
- package/dist/react/index.js +1 -0
- package/dist/react/index.js.map +1 -1
- package/dist/scripts/guardrailsEnforce.d.ts.map +1 -1
- package/dist/styles-areas/core.css +6 -6
- package/dist/styles-areas/disk-usage.css +7 -7
- package/dist/styles-areas/fields.css +24 -22
- package/dist/styles-areas/nav.css +25 -26
- package/dist/styles-areas/workbench.css +2 -2
- package/dist/styles-utilities.css +28 -0
- package/package.json +37 -4
- package/scripts/guardrails-baseline.json +2 -2
- package/scripts/guardrailsEnforce.spec.ts +31 -0
- package/scripts/guardrailsEnforce.ts +37 -2
- package/scripts/styleAreas.ts +4 -0
- package/src/componentCssReadsAreDeclared.spec.ts +62 -0
- package/src/react/components/ColorSwatches.spec.tsx +62 -0
- package/src/react/components/ColorSwatches.tsx +100 -0
- package/src/react/components/EditorPage.spec.tsx +18 -0
- package/src/react/components/EditorPage.tsx +12 -2
- package/src/react/components/FormPreviewLayout.tsx +2 -1
- package/src/react/components/PaneSplit.spec.tsx +60 -0
- package/src/react/components/PaneSplit.tsx +206 -0
- package/src/react/components/PointerDrag.spec.tsx +108 -0
- package/src/react/components/PointerDrag.tsx +261 -0
- package/src/react/components/PropertyList.spec.tsx +33 -0
- package/src/react/components/PropertyList.tsx +31 -6
- package/src/react/components/SwatchPicker.spec.tsx +92 -0
- package/src/react/components/SwatchPicker.tsx +119 -33
- package/src/react/components/TreeView.spec.tsx +157 -0
- package/src/react/components/TreeView.tsx +161 -14
- package/src/react/components/editorPage.css +1 -7
- package/src/react/components/formKit.css +5 -6
- package/src/react/components/formKit.spec.tsx +9 -0
- package/src/react/components/paneSplit.css +93 -0
- package/src/react/components/pointerDrag.css +39 -0
- package/src/react/components/scrollRegion.css +31 -0
- package/src/react/index.ts +2 -0
- package/src/styles-areas/core.css +6 -6
- package/src/styles-areas/disk-usage.css +7 -7
- package/src/styles-areas/fields.css +24 -22
- package/src/styles-areas/nav.css +25 -26
- package/src/styles-areas/workbench.css +2 -2
- package/src/styles-utilities.css +28 -0
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export interface ColorSwatchesProps {
|
|
2
|
+
/** The preset dots, in order. Any CSS colour; a 6-digit hex is what the custom well can open on. */
|
|
3
|
+
presets: readonly string[];
|
|
4
|
+
/** The current colour — one of the presets, or any other colour picked through the well. */
|
|
5
|
+
value: string | undefined;
|
|
6
|
+
onChange: (color: string) => void;
|
|
7
|
+
/** Offer a last dot for any colour (the browser's own colour well). Default `true`. */
|
|
8
|
+
custom?: boolean;
|
|
9
|
+
/** The custom dot's accessible name. Default "Any colour". */
|
|
10
|
+
customLabel?: string;
|
|
11
|
+
/** Dot diameter, as `SwatchPicker`'s: `sm` 1.5rem, `md` (default) 1.75rem, `lg` 2.25rem. */
|
|
12
|
+
size?: 'sm' | 'md' | 'lg';
|
|
13
|
+
/** Accessible name for the preset group (default "Colour"). */
|
|
14
|
+
'aria-label'?: string;
|
|
15
|
+
className?: string;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* `ColorSwatches` — an accent picker drawn as ONE row of dots: the presets, then a last dot for
|
|
19
|
+
* any colour. The preset dots are a {@link SwatchPicker} radiogroup (Radix: radio semantics,
|
|
20
|
+
* roving tabindex, arrow keys move the choice); the last dot is the browser's colour well, laid
|
|
21
|
+
* invisibly over a dot painted with the theme's categorical ramp, and becomes that colour —
|
|
22
|
+
* ringed as the current one — once a colour outside the presets is picked.
|
|
23
|
+
*
|
|
24
|
+
* desk drew this twice by hand (its component and list template pages, forge task 2829): a row
|
|
25
|
+
* of raw buttons, one of them with a raw `<input type="color">` behind an opt-out and the other
|
|
26
|
+
* with no custom colour at all. `ColorField` is a full-width hex field; this is the compact
|
|
27
|
+
* "pick an accent for this thing" control, and the next app that wants one takes it from here.
|
|
28
|
+
*
|
|
29
|
+
* Matching is case-insensitive, and what the well reports is lower-case hex, so a stored
|
|
30
|
+
* `#2563EB` still lights its preset.
|
|
31
|
+
*/
|
|
32
|
+
export declare function ColorSwatches({ presets, value, onChange, custom, customLabel, size, 'aria-label': ariaLabel, className, }: ColorSwatchesProps): import("react").JSX.Element;
|
|
33
|
+
//# sourceMappingURL=ColorSwatches.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ColorSwatches.d.ts","sourceRoot":"","sources":["../../../src/react/components/ColorSwatches.tsx"],"names":[],"mappings":"AAKA,MAAM,WAAW,kBAAkB;IACjC,oGAAoG;IACpG,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IAC3B,4FAA4F;IAC5F,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,uFAAuF;IACvF,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,8DAA8D;IAC9D,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,4FAA4F;IAC5F,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;IAC1B,+DAA+D;IAC/D,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAQD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,aAAa,CAAC,EAC5B,OAAO,EACP,KAAK,EACL,QAAQ,EACR,MAAa,EACb,WAA0B,EAC1B,IAAW,EACX,YAAY,EAAE,SAAoB,EAClC,SAAS,GACV,EAAE,kBAAkB,+BA+CpB"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect, useRef } from 'react';
|
|
3
|
+
import { cn } from '../lib/cn.js';
|
|
4
|
+
import { TAP_TARGET_SQUARE } from '../lib/tapTarget.js';
|
|
5
|
+
import { SwatchPicker } from './SwatchPicker.js';
|
|
6
|
+
const SIZE = { sm: 'size-6', md: 'size-7', lg: 'size-9' };
|
|
7
|
+
const HEX6 = /^#[0-9a-f]{6}$/i;
|
|
8
|
+
/** The any-colour dot before a custom colour is picked: the theme's categorical ramp, round the dial. */
|
|
9
|
+
const RAMP = 'conic-gradient(var(--chart-1), var(--chart-2), var(--chart-3), var(--chart-4), var(--chart-5), var(--chart-6), var(--chart-7), var(--chart-8), var(--chart-1))';
|
|
10
|
+
/**
|
|
11
|
+
* `ColorSwatches` — an accent picker drawn as ONE row of dots: the presets, then a last dot for
|
|
12
|
+
* any colour. The preset dots are a {@link SwatchPicker} radiogroup (Radix: radio semantics,
|
|
13
|
+
* roving tabindex, arrow keys move the choice); the last dot is the browser's colour well, laid
|
|
14
|
+
* invisibly over a dot painted with the theme's categorical ramp, and becomes that colour —
|
|
15
|
+
* ringed as the current one — once a colour outside the presets is picked.
|
|
16
|
+
*
|
|
17
|
+
* desk drew this twice by hand (its component and list template pages, forge task 2829): a row
|
|
18
|
+
* of raw buttons, one of them with a raw `<input type="color">` behind an opt-out and the other
|
|
19
|
+
* with no custom colour at all. `ColorField` is a full-width hex field; this is the compact
|
|
20
|
+
* "pick an accent for this thing" control, and the next app that wants one takes it from here.
|
|
21
|
+
*
|
|
22
|
+
* Matching is case-insensitive, and what the well reports is lower-case hex, so a stored
|
|
23
|
+
* `#2563EB` still lights its preset.
|
|
24
|
+
*/
|
|
25
|
+
export function ColorSwatches({ presets, value, onChange, custom = true, customLabel = 'Any colour', size = 'md', 'aria-label': ariaLabel = 'Colour', className, }) {
|
|
26
|
+
const current = value?.toLowerCase();
|
|
27
|
+
const isPreset = current !== undefined && presets.some((color) => color.toLowerCase() === current);
|
|
28
|
+
const isCustom = current !== undefined && current !== '' && !isPreset;
|
|
29
|
+
// The well opens on the current colour when it is one it can show. It is uncontrolled and kept
|
|
30
|
+
// in step here, because a controlled colour input needs a hex for "nothing chosen" and there is
|
|
31
|
+
// no honest one to write.
|
|
32
|
+
const wellHex = current !== undefined && HEX6.test(current) ? current : undefined;
|
|
33
|
+
const well = useRef(null);
|
|
34
|
+
useEffect(() => {
|
|
35
|
+
if (well.current && wellHex && well.current.value !== wellHex)
|
|
36
|
+
well.current.value = wellHex;
|
|
37
|
+
}, [wellHex]);
|
|
38
|
+
return (_jsxs("div", { "data-slot": 'color-swatches', className: cn('flex flex-wrap items-center gap-1.5', className), children: [_jsx(SwatchPicker, { "aria-label": ariaLabel, size: size, options: presets.map((color) => ({ value: color.toLowerCase(), color, label: color })), value: isPreset ? current : undefined, onChange: onChange }), custom ? (_jsx("label", { "data-slot": 'color-swatches-custom', "data-state": isCustom ? 'checked' : 'unchecked', style: { '--cb-swatch-fill': isCustom ? value : RAMP }, className: cn('relative inline-flex flex-none cursor-pointer rounded-full [background:var(--cb-swatch-fill,var(--muted))] border border-border/40 transition-transform', SIZE[size], TAP_TARGET_SQUARE, 'hover:scale-110 focus-within:ring-2 focus-within:ring-ring focus-within:ring-offset-1', 'data-[state=checked]:ring-2 data-[state=checked]:ring-foreground data-[state=checked]:ring-offset-1'), children: _jsx("input", {
|
|
39
|
+
// guardrails-ignore no-raw-inputs: task 2829 — the browser's own colour well, laid invisibly over the last dot; a hex field is ColorField's job, not a dot's
|
|
40
|
+
type: 'color', ref: well, "aria-label": customLabel, defaultValue: wellHex, onChange: (event) => onChange(event.target.value.toLowerCase()), className: 'absolute inset-0 m-0 size-full cursor-pointer appearance-none border-0 p-0 opacity-0' }) })) : null] }));
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=ColorSwatches.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ColorSwatches.js","sourceRoot":"","sources":["../../../src/react/components/ColorSwatches.tsx"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { type ReactNode } from 'react';
|
|
2
2
|
import './formKit.css';
|
|
3
3
|
import './editorPage.css';
|
|
4
|
+
import './scrollRegion.css';
|
|
4
5
|
export interface EditorPageProps {
|
|
5
6
|
/** What is being made or changed — *"New template"*, *"Edit Dynatrace"*. The page's heading. */
|
|
6
7
|
title: ReactNode;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EditorPage.d.ts","sourceRoot":"","sources":["../../../src/react/components/EditorPage.tsx"],"names":[],"mappings":"AACA,OAAO,EAIL,KAAK,SAAS,EAMf,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"EditorPage.d.ts","sourceRoot":"","sources":["../../../src/react/components/EditorPage.tsx"],"names":[],"mappings":"AACA,OAAO,EAIL,KAAK,SAAS,EAMf,MAAM,OAAO,CAAC;AAKf,OAAO,eAAe,CAAC;AACvB,OAAO,kBAAkB,CAAC;AAC1B,OAAO,oBAAoB,CAAC;AAE5B,MAAM,WAAW,eAAe;IAC9B,gGAAgG;IAChG,KAAK,EAAE,SAAS,CAAC;IACjB,+EAA+E;IAC/E,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,0FAA0F;IAC1F,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB;;;;OAIG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,wFAAwF;IACxF,OAAO,CAAC,EAAE,SAAS,CAAC;IACpB,kFAAkF;IAClF,QAAQ,EAAE,SAAS,CAAC;IACpB,wFAAwF;IACxF,OAAO,EAAE,SAAS,CAAC;IACnB,mFAAmF;IACnF,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,4FAA4F;IAC5F,YAAY,CAAC,EAAE,SAAS,CAAC;IACzB,6EAA6E;IAC7E,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,oFAAoF;IACpF,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,6EAA6E;IAC7E,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB;;;OAGG;IACH,YAAY,CAAC,EAAE,SAAS,GAAG,QAAQ,CAAC;IACpC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAgBD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,UAAU,CAAC,EACzB,KAAK,EACL,SAAkB,EAClB,MAAM,EACN,OAAO,EACP,OAAO,EACP,QAAQ,EACR,OAAO,EACP,YAAwB,EACxB,YAAY,EACZ,YAAkB,EAClB,UAAU,EACV,KAAY,EACZ,YAAwB,EACxB,SAAS,GACV,EAAE,eAAe,+BAmKjB;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,SAAS,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;;GASG;AACH,wBAAgB,SAAS,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,EAAE,cAAc,+BAEhE"}
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { ArrowLeft } from 'lucide-react';
|
|
3
3
|
import { useCallback, useEffect, useId, useRef, useState, } from 'react';
|
|
4
|
+
import { useCaretInView } from '../hooks/useCaretInView.js';
|
|
4
5
|
import { useDiscardGuard } from '../hooks/useDiscardGuard.js';
|
|
5
6
|
import { cn } from '../lib/cn.js';
|
|
6
7
|
import { UnstyledButton } from './UnstyledButton.js';
|
|
7
8
|
import './formKit.css';
|
|
8
9
|
import './editorPage.css';
|
|
10
|
+
import './scrollRegion.css';
|
|
9
11
|
/** What answers Escape itself, before the page does. */
|
|
10
12
|
const OWNS_ESCAPE = '[role="listbox"],[role="menu"],[role="combobox"][aria-expanded="true"],[aria-haspopup]:not([aria-haspopup="false"])[aria-expanded="true"]';
|
|
11
13
|
const MIN_SPLIT = 0.25;
|
|
@@ -48,6 +50,9 @@ export function EditorPage({ title, backLabel = 'Back', onBack, isDirty, actions
|
|
|
48
50
|
const titleId = useId();
|
|
49
51
|
const formId = useId();
|
|
50
52
|
const previewId = useId();
|
|
53
|
+
// `.cbfk-scroll`'s other half: ScrollArea's explicit scroll-into-view on focus, for a browser
|
|
54
|
+
// that ignores scroll-padding on its own (forge task 2827).
|
|
55
|
+
const onFocusCapture = useCaretInView();
|
|
51
56
|
const { guardedClose, discardOverlay, isConfirming, cancelDiscard } = useDiscardGuard({ onClose: onBack, isDirty });
|
|
52
57
|
const commit = useCallback((value) => {
|
|
53
58
|
const next = clampSplit(value);
|
|
@@ -115,7 +120,7 @@ export function EditorPage({ title, backLabel = 'Back', onBack, isDirty, actions
|
|
|
115
120
|
else
|
|
116
121
|
guardedClose();
|
|
117
122
|
};
|
|
118
|
-
return (_jsxs("div", { ref: rootRef, className: cn('cbfk-page', className), "data-presentation": presentation, "data-mode": mode, "data-dragging": dragging ? 'true' : undefined, role: presentation === 'overlay' ? 'dialog' : 'region', "aria-modal": presentation === 'overlay' ? true : undefined, "aria-labelledby": titleId, tabIndex: -1, onKeyDown: onKeyDown, children: [_jsxs("header", { className: 'cbfk-page-head', children: [_jsxs(UnstyledButton, { className: 'cbfk-page-back', onClick: guardedClose, "aria-label": backLabel, tooltip: backLabel, children: [_jsx(ArrowLeft, { "aria-hidden": true }), _jsx("span", { className: 'cbfk-page-crumb', children: backLabel })] }), _jsx("span", { className: 'cbfk-page-sep', "aria-hidden": true, children: "/" }), _jsx("h1", { id: titleId, className: 'cbfk-page-title', children: title }), _jsx("div", { className: 'cbfk-page-modes', role: 'tablist', "aria-label": 'Show', children: ['edit', 'preview'].map((each) => (_jsx(UnstyledButton, { role: 'tab', className: 'cbfk-page-mode', "aria-selected": mode === each, "aria-controls": each === 'edit' ? formId : previewId, onClick: () => setMode(each), children: each === 'edit' ? 'Edit' : previewLabel }, each))) }), actions ? _jsx("div", { className: 'cbfk-page-actions', children: actions }) : null] }), _jsxs("div", { ref: splitRef, className: 'cbfk-page-split', style: { '--cbfk-page-split': `${(split * 100).toFixed(2)}%` }, children: [_jsx("div", { id: formId, className: cn('cbfk-page-form', quiet && 'cbfk-quiet'), children: _jsx("div", { className: 'cbfk-page-form-inner', children: children }) }), _jsx("div", { className: 'cbfk-page-divider', role: 'separator', "aria-orientation": 'vertical', "aria-label": 'Resize the form and the preview', "aria-valuemin": MIN_SPLIT * 100, "aria-valuemax": MAX_SPLIT * 100, "aria-valuenow": Math.round(split * 100), "aria-controls": formId, tabIndex: 0, onPointerDown: onPointerDown, onPointerMove: onPointerMove, onPointerUp: onPointerUp, onPointerCancel: onPointerUp, onKeyDown: onDividerKey, onDoubleClick: () => commit(defaultSplit) }), _jsxs("section", { id: previewId, className: 'cbfk-page-preview', "aria-label": previewLabel, children: [_jsxs("div", { className: 'cbfk-page-preview-head', children: [_jsx("p", { className: 'cbfk-page-preview-label', children: previewLabel }), previewTools ? _jsx("div", { className: 'cbfk-page-preview-tools', children: previewTools }) : null] }), _jsx("div", { className: 'cbfk-page-preview-body', children: preview })] })] }), discardOverlay] }));
|
|
123
|
+
return (_jsxs("div", { ref: rootRef, className: cn('cbfk-page', className), "data-presentation": presentation, "data-mode": mode, "data-dragging": dragging ? 'true' : undefined, role: presentation === 'overlay' ? 'dialog' : 'region', "aria-modal": presentation === 'overlay' ? true : undefined, "aria-labelledby": titleId, tabIndex: -1, onKeyDown: onKeyDown, children: [_jsxs("header", { className: 'cbfk-page-head', children: [_jsxs(UnstyledButton, { className: 'cbfk-page-back', onClick: guardedClose, "aria-label": backLabel, tooltip: backLabel, children: [_jsx(ArrowLeft, { "aria-hidden": true }), _jsx("span", { className: 'cbfk-page-crumb', children: backLabel })] }), _jsx("span", { className: 'cbfk-page-sep', "aria-hidden": true, children: "/" }), _jsx("h1", { id: titleId, className: 'cbfk-page-title', children: title }), _jsx("div", { className: 'cbfk-page-modes', role: 'tablist', "aria-label": 'Show', children: ['edit', 'preview'].map((each) => (_jsx(UnstyledButton, { role: 'tab', className: 'cbfk-page-mode', "aria-selected": mode === each, "aria-controls": each === 'edit' ? formId : previewId, onClick: () => setMode(each), children: each === 'edit' ? 'Edit' : previewLabel }, each))) }), actions ? _jsx("div", { className: 'cbfk-page-actions', children: actions }) : null] }), _jsxs("div", { ref: splitRef, className: 'cbfk-page-split', style: { '--cbfk-page-split': `${(split * 100).toFixed(2)}%` }, children: [_jsx("div", { id: formId, className: cn('cbfk-page-form cbfk-scroll', quiet && 'cbfk-quiet'), onFocusCapture: onFocusCapture, children: _jsx("div", { className: 'cbfk-page-form-inner', children: children }) }), _jsx("div", { className: 'cbfk-page-divider', role: 'separator', "aria-orientation": 'vertical', "aria-label": 'Resize the form and the preview', "aria-valuemin": MIN_SPLIT * 100, "aria-valuemax": MAX_SPLIT * 100, "aria-valuenow": Math.round(split * 100), "aria-controls": formId, tabIndex: 0, onPointerDown: onPointerDown, onPointerMove: onPointerMove, onPointerUp: onPointerUp, onPointerCancel: onPointerUp, onKeyDown: onDividerKey, onDoubleClick: () => commit(defaultSplit) }), _jsxs("section", { id: previewId, className: 'cbfk-page-preview cbfk-scroll', "aria-label": previewLabel, onFocusCapture: onFocusCapture, children: [_jsxs("div", { className: 'cbfk-page-preview-head', children: [_jsx("p", { className: 'cbfk-page-preview-label', children: previewLabel }), previewTools ? _jsx("div", { className: 'cbfk-page-preview-tools', children: previewTools }) : null] }), _jsx("div", { className: 'cbfk-page-preview-body', children: preview })] })] }), discardOverlay] }));
|
|
119
124
|
}
|
|
120
125
|
/**
|
|
121
126
|
* Linear's form, for any form: inputs, textareas and selects drawn with no box until they are
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EditorPage.js","sourceRoot":"","sources":["../../../src/react/components/EditorPage.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,EAKL,WAAW,EACX,SAAS,EACT,KAAK,EACL,MAAM,EACN,QAAQ,GACT,MAAM,OAAO,CAAC;AACf,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AAClC,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,eAAe,CAAC;AACvB,OAAO,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"EditorPage.js","sourceRoot":"","sources":["../../../src/react/components/EditorPage.tsx"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FormPreviewLayout.d.ts","sourceRoot":"","sources":["../../../src/react/components/FormPreviewLayout.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,SAAS,EAAmB,MAAM,OAAO,CAAC;AAExD,OAAO,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"FormPreviewLayout.d.ts","sourceRoot":"","sources":["../../../src/react/components/FormPreviewLayout.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,SAAS,EAAmB,MAAM,OAAO,CAAC;AAExD,OAAO,eAAe,CAAC;AACvB,OAAO,oBAAoB,CAAC;AAE5B,MAAM,WAAW,sBAAsB;IACrC,mEAAmE;IACnE,QAAQ,EAAE,SAAS,CAAC;IACpB,uFAAuF;IACvF,OAAO,EAAE,SAAS,CAAC;IACnB;qDACiD;IACjD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;;OAIG;IACH,cAAc,CAAC,EAAE,SAAS,CAAC;IAC3B,8EAA8E;IAC9E,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B;;;OAGG;IACH,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,iBAAiB,CAAC,EAChC,QAAQ,EACR,OAAO,EACP,YAAwB,EACxB,cAAc,EACd,kBAA0B,EAC1B,KAAK,EACL,SAAS,GACV,EAAE,sBAAsB,+BAkCxB"}
|
|
@@ -3,6 +3,7 @@ import { ChevronDown } from 'lucide-react';
|
|
|
3
3
|
import { useId, useState } from 'react';
|
|
4
4
|
import { cn } from '../lib/cn.js';
|
|
5
5
|
import './formKit.css';
|
|
6
|
+
import './scrollRegion.css';
|
|
6
7
|
/**
|
|
7
8
|
* DESIGN.md §6's creation layout — form beside its live preview — as a layout that can go
|
|
8
9
|
* anywhere, not only inside `Modal`'s `aside`.
|
|
@@ -31,6 +32,6 @@ export function FormPreviewLayout({ children, preview, previewLabel = 'Preview',
|
|
|
31
32
|
return (_jsx("div", { className: cn('cbfk-split', className), "data-preview-open": open ? 'true' : 'false', children: _jsxs("div", { className: 'cbfk-split-grid', children: [_jsx("div", { className: 'cbfk-split-form', children: children }), _jsxs("section", { className: 'cbfk-split-preview', "aria-label": previewLabel, children: [_jsxs("button", {
|
|
32
33
|
// guardrails-ignore no-raw-action-button: the narrow preview's fold — presentational
|
|
33
34
|
// show/hide, no data-mutating intent; it must draw without Tailwind.
|
|
34
|
-
type: 'button', className: 'font-[inherit] cbfk-split-bar', "aria-expanded": open, "aria-controls": bodyId, onClick: () => setOpen(!open), children: [_jsx("span", { className: 'cbfk-split-bar-label', children: previewLabel }), _jsx("span", { className: 'cbfk-split-bar-summary', children: previewSummary }), _jsx(ChevronDown, { "aria-hidden": true })] }), _jsx("p", { className: 'cbfk-split-head', children: previewLabel }), _jsx("div", { id: bodyId, className: 'cbfk-split-body', children: preview })] }), below ? _jsx("div", { className: 'cbfk-split-below', children: below }) : null] }) }));
|
|
35
|
+
type: 'button', className: 'font-[inherit] cbfk-split-bar', "aria-expanded": open, "aria-controls": bodyId, onClick: () => setOpen(!open), children: [_jsx("span", { className: 'cbfk-split-bar-label', children: previewLabel }), _jsx("span", { className: 'cbfk-split-bar-summary', children: previewSummary }), _jsx(ChevronDown, { "aria-hidden": true })] }), _jsx("p", { className: 'cbfk-split-head', children: previewLabel }), _jsx("div", { id: bodyId, className: 'cbfk-split-body cbfk-scroll', children: preview })] }), below ? _jsx("div", { className: 'cbfk-split-below', children: below }) : null] }) }));
|
|
35
36
|
}
|
|
36
37
|
//# sourceMappingURL=FormPreviewLayout.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FormPreviewLayout.js","sourceRoot":"","sources":["../../../src/react/components/FormPreviewLayout.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,EAAkB,KAAK,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACxD,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AAClC,OAAO,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"FormPreviewLayout.js","sourceRoot":"","sources":["../../../src/react/components/FormPreviewLayout.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,EAAkB,KAAK,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACxD,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AAClC,OAAO,eAAe,CAAC;AACvB,OAAO,oBAAoB,CAAC;AA0B5B;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,UAAU,iBAAiB,CAAC,EAChC,QAAQ,EACR,OAAO,EACP,YAAY,GAAG,SAAS,EACxB,cAAc,EACd,kBAAkB,GAAG,KAAK,EAC1B,KAAK,EACL,SAAS,GACc;IACvB,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,QAAQ,CAAC,kBAAkB,CAAC,CAAC;IACrD,MAAM,MAAM,GAAG,KAAK,EAAE,CAAC;IAEvB,OAAO,CACL,cAAK,SAAS,EAAE,EAAE,CAAC,YAAY,EAAE,SAAS,CAAC,uBAAqB,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,YACrF,eAAK,SAAS,EAAC,iBAAiB,aAC9B,cAAK,SAAS,EAAC,iBAAiB,YAAE,QAAQ,GAAO,EACjD,mBAAS,SAAS,EAAC,oBAAoB,gBAAa,YAAY,aAC9D;4BACE,qFAAqF;4BACrF,qEAAqE;4BACrE,IAAI,EAAC,QAAQ,EACb,SAAS,EAAC,+BAA+B,mBAC1B,IAAI,mBACJ,MAAM,EACrB,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,aAE7B,eAAM,SAAS,EAAC,sBAAsB,YAAE,YAAY,GAAQ,EAC5D,eAAM,SAAS,EAAC,wBAAwB,YAAE,cAAc,GAAQ,EAChE,KAAC,WAAW,0BAAe,IACpB,EACT,YAAG,SAAS,EAAC,iBAAiB,YAAE,YAAY,GAAK,EACjD,cAAK,EAAE,EAAE,MAAM,EAAE,SAAS,EAAC,6BAA6B,YACrD,OAAO,GACJ,IACE,EAIT,KAAK,CAAC,CAAC,CAAC,cAAK,SAAS,EAAC,kBAAkB,YAAE,KAAK,GAAO,CAAC,CAAC,CAAC,IAAI,IAC3D,GACF,CACP,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `PaneSplit` — an editor's pane tree, drawn VS Code's way: panes that meet edge to edge, square,
|
|
3
|
+
* with one hairline between them.
|
|
4
|
+
*
|
|
5
|
+
* Graduated from desk's `WorkspaceSplit` on the owner's word: *"Panels and panes should be separated
|
|
6
|
+
* by sharp corners and thin border lines just like they are in vscode"* — and *"since these changes
|
|
7
|
+
* apply to layouts and cards they should be changed in cb and should impact desk through cb"*.
|
|
8
|
+
*
|
|
9
|
+
* The model is the app's — a tree of leaves and splits, each split carrying the fractions of its
|
|
10
|
+
* children. This component is only geometry: flex tracks, one seam between each pair of children,
|
|
11
|
+
* and the arithmetic that turns a pointer into a pair of fractions. Unlike `PanelGrid` it owns no
|
|
12
|
+
* sizes and persists nothing, which is what an app that stores its layout as a setting needs.
|
|
13
|
+
*
|
|
14
|
+
* 🔴 **The seam is keyboard-operable.** Arrow keys move it by 2%, Home/End take it to the bounds.
|
|
15
|
+
*
|
|
16
|
+
* 🔴 **The hit strip lives inside the seam's own track** — a real flex item, never a bar hung over
|
|
17
|
+
* the boundary. An invisible strip centred on the seam sits over the first pixels of the pane beside
|
|
18
|
+
* it and swallows clicks nobody aimed at it (desk's file `21`, where a 44px hit area ate a fill
|
|
19
|
+
* handle). So the track is a few pixels wide for the hand, painted the panes' own ground
|
|
20
|
+
* (`--cb-panesplit-ground`) with the hairline drawn down its middle: to the eye, two panes and one
|
|
21
|
+
* line, which is VS Code's picture; to the pointer, a target that touches no pane.
|
|
22
|
+
*
|
|
23
|
+
* Plain CSS (`paneSplit.css`), prefix `cb-panesplit`, so it draws in an app with no Tailwind pass.
|
|
24
|
+
*/
|
|
25
|
+
import type { JSX } from 'react';
|
|
26
|
+
import './paneSplit.css';
|
|
27
|
+
export type PaneSplitDirection = 'row' | 'column';
|
|
28
|
+
export type PaneSplitNode<P> = {
|
|
29
|
+
kind: 'leaf';
|
|
30
|
+
pane: P;
|
|
31
|
+
} | {
|
|
32
|
+
kind: 'split';
|
|
33
|
+
direction: PaneSplitDirection;
|
|
34
|
+
sizes: readonly number[];
|
|
35
|
+
children: readonly PaneSplitNode<P>[];
|
|
36
|
+
};
|
|
37
|
+
/** Where a node sits in the tree: the child index at each level, from the root. */
|
|
38
|
+
export type PaneSplitPath = readonly number[];
|
|
39
|
+
export interface PaneSplitProps<P> {
|
|
40
|
+
node: PaneSplitNode<P>;
|
|
41
|
+
/** A key unique across the whole tree — what keeps a pane's subtree when its siblings close. */
|
|
42
|
+
paneKey: (pane: P) => string;
|
|
43
|
+
renderPane: (pane: P) => JSX.Element;
|
|
44
|
+
/** A seam moved: the split at `path` now has these fractions. */
|
|
45
|
+
onResize: (path: PaneSplitPath, sizes: number[]) => void;
|
|
46
|
+
/** The smallest share of an axis a pane can be dragged down to. Default 0.12. */
|
|
47
|
+
minFraction?: number;
|
|
48
|
+
/** Where `node` sits — only for a tree drawn from below its root. */
|
|
49
|
+
path?: PaneSplitPath;
|
|
50
|
+
}
|
|
51
|
+
export declare function PaneSplit<P>(props: PaneSplitProps<P>): JSX.Element;
|
|
52
|
+
//# sourceMappingURL=PaneSplit.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PaneSplit.d.ts","sourceRoot":"","sources":["../../../src/react/components/PaneSplit.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,KAAK,EAAiB,GAAG,EAA0E,MAAM,OAAO,CAAC;AAExH,OAAO,iBAAiB,CAAC;AAEzB,MAAM,MAAM,kBAAkB,GAAG,KAAK,GAAG,QAAQ,CAAC;AAElD,MAAM,MAAM,aAAa,CAAC,CAAC,IACvB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,CAAC,CAAA;CAAE,GACzB;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,SAAS,EAAE,kBAAkB,CAAC;IAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IAAC,QAAQ,EAAE,SAAS,aAAa,CAAC,CAAC,CAAC,EAAE,CAAA;CAAE,CAAC;AAEtH,mFAAmF;AACnF,MAAM,MAAM,aAAa,GAAG,SAAS,MAAM,EAAE,CAAC;AAE9C,MAAM,WAAW,cAAc,CAAC,CAAC;IAC/B,IAAI,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC;IACvB,gGAAgG;IAChG,OAAO,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,MAAM,CAAC;IAC7B,UAAU,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,GAAG,CAAC,OAAO,CAAC;IACrC,iEAAiE;IACjE,QAAQ,EAAE,CAAC,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IACzD,iFAAiF;IACjF,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,qEAAqE;IACrE,IAAI,CAAC,EAAE,aAAa,CAAC;CACtB;AAaD,wBAAgB,SAAS,CAAC,CAAC,EAAE,KAAK,EAAE,cAAc,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,OAAO,CAIlE"}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useCallback, useRef } from 'react';
|
|
3
|
+
import './paneSplit.css';
|
|
4
|
+
const DEFAULT_MIN_FRACTION = 0.12;
|
|
5
|
+
/**
|
|
6
|
+
* A key for a child that follows its content rather than its position: closing a pane in the middle
|
|
7
|
+
* of a row shifts every later child's index, and `key={index}` would hand React the wrong subtree.
|
|
8
|
+
*/
|
|
9
|
+
function childKey(node, paneKey) {
|
|
10
|
+
if (node.kind === 'leaf')
|
|
11
|
+
return paneKey(node.pane);
|
|
12
|
+
return node.children.map((child) => childKey(child, paneKey)).join('|');
|
|
13
|
+
}
|
|
14
|
+
export function PaneSplit(props) {
|
|
15
|
+
const { node } = props;
|
|
16
|
+
if (node.kind === 'leaf')
|
|
17
|
+
return props.renderPane(node.pane);
|
|
18
|
+
return _jsx(SplitNode, { ...props, node: node, path: props.path ?? [] });
|
|
19
|
+
}
|
|
20
|
+
function SplitNode({ node, path, paneKey, renderPane, onResize, minFraction = DEFAULT_MIN_FRACTION, }) {
|
|
21
|
+
const frame = useRef(null);
|
|
22
|
+
const dragging = useRef(null);
|
|
23
|
+
/** Set the share of the pair either side of seam `index`; only those two panes move. */
|
|
24
|
+
const setShare = useCallback((index, share) => {
|
|
25
|
+
const pair = (node.sizes[index] ?? 0) + (node.sizes[index + 1] ?? 0);
|
|
26
|
+
if (pair <= 0)
|
|
27
|
+
return;
|
|
28
|
+
const bounded = Math.min(Math.max(share, minFraction), 1 - minFraction);
|
|
29
|
+
const sizes = [...node.sizes];
|
|
30
|
+
sizes[index] = pair * bounded;
|
|
31
|
+
sizes[index + 1] = pair * (1 - bounded);
|
|
32
|
+
onResize(path, sizes);
|
|
33
|
+
}, [node.sizes, minFraction, onResize, path]);
|
|
34
|
+
const moveSeam = (index, position) => {
|
|
35
|
+
const box = frame.current?.getBoundingClientRect();
|
|
36
|
+
if (!box)
|
|
37
|
+
return;
|
|
38
|
+
const total = node.direction === 'row' ? box.width : box.height;
|
|
39
|
+
if (total <= 0)
|
|
40
|
+
return;
|
|
41
|
+
const offset = (node.direction === 'row' ? position - box.left : position - box.top) / total;
|
|
42
|
+
const before = node.sizes.slice(0, index).reduce((sum, size) => sum + size, 0);
|
|
43
|
+
const pair = (node.sizes[index] ?? 0) + (node.sizes[index + 1] ?? 0);
|
|
44
|
+
if (pair <= 0)
|
|
45
|
+
return;
|
|
46
|
+
setShare(index, (offset - before) / pair);
|
|
47
|
+
};
|
|
48
|
+
const nudgeSeam = (index, delta) => {
|
|
49
|
+
const pair = (node.sizes[index] ?? 0) + (node.sizes[index + 1] ?? 0);
|
|
50
|
+
if (pair <= 0)
|
|
51
|
+
return;
|
|
52
|
+
setShare(index, (node.sizes[index] ?? 0) / pair + delta);
|
|
53
|
+
};
|
|
54
|
+
const onKeyDown = (event, index) => {
|
|
55
|
+
const back = node.direction === 'row' ? 'ArrowLeft' : 'ArrowUp';
|
|
56
|
+
const forward = node.direction === 'row' ? 'ArrowRight' : 'ArrowDown';
|
|
57
|
+
if (event.key === back)
|
|
58
|
+
nudgeSeam(index, -0.02);
|
|
59
|
+
else if (event.key === forward)
|
|
60
|
+
nudgeSeam(index, 0.02);
|
|
61
|
+
else if (event.key === 'Home')
|
|
62
|
+
nudgeSeam(index, -1);
|
|
63
|
+
else if (event.key === 'End')
|
|
64
|
+
nudgeSeam(index, 1);
|
|
65
|
+
else
|
|
66
|
+
return;
|
|
67
|
+
event.preventDefault();
|
|
68
|
+
};
|
|
69
|
+
const onPointerDown = (event, index) => {
|
|
70
|
+
if (event.button !== 0)
|
|
71
|
+
return;
|
|
72
|
+
dragging.current = index;
|
|
73
|
+
event.currentTarget.setPointerCapture(event.pointerId);
|
|
74
|
+
event.preventDefault();
|
|
75
|
+
};
|
|
76
|
+
const onPointerMove = (event) => {
|
|
77
|
+
if (dragging.current === null)
|
|
78
|
+
return;
|
|
79
|
+
moveSeam(dragging.current, node.direction === 'row' ? event.clientX : event.clientY);
|
|
80
|
+
};
|
|
81
|
+
const endDrag = (event) => {
|
|
82
|
+
if (dragging.current === null)
|
|
83
|
+
return;
|
|
84
|
+
dragging.current = null;
|
|
85
|
+
if (event.currentTarget.hasPointerCapture?.(event.pointerId))
|
|
86
|
+
event.currentTarget.releasePointerCapture(event.pointerId);
|
|
87
|
+
};
|
|
88
|
+
const minPercent = Math.round(minFraction * 100);
|
|
89
|
+
return (_jsx("div", { className: "cb-panesplit", "data-direction": node.direction, ref: frame, children: node.children.map((child, index) => (_jsx(ChildAndSeam, { last: index === node.children.length - 1, size: node.sizes[index] ?? 1 / node.children.length, seam: {
|
|
90
|
+
direction: node.direction,
|
|
91
|
+
percent: Math.round((node.sizes[index] ?? 0) * 100),
|
|
92
|
+
min: minPercent,
|
|
93
|
+
max: 100 - minPercent,
|
|
94
|
+
onKeyDown: (event) => onKeyDown(event, index),
|
|
95
|
+
onPointerDown: (event) => onPointerDown(event, index),
|
|
96
|
+
onPointerMove,
|
|
97
|
+
endDrag,
|
|
98
|
+
}, children: _jsx(PaneSplit, { node: child, path: [...path, index], paneKey: paneKey, renderPane: renderPane, onResize: onResize, minFraction: minFraction }) }, childKey(child, paneKey)))) }));
|
|
99
|
+
}
|
|
100
|
+
function ChildAndSeam({ last, size, seam, children }) {
|
|
101
|
+
return (_jsxs(_Fragment, { children: [_jsx("div", { className: "cb-panesplit__cell", style: { '--cb-panesplit-share': size }, children: children }), !last && (_jsx("div", { className: "cb-panesplit__seam", role: "separator", tabIndex: 0, "aria-orientation": seam.direction === 'row' ? 'vertical' : 'horizontal', "aria-label": seam.direction === 'row' ? 'Width of the pane on the left' : 'Height of the pane above', "aria-valuenow": seam.percent, "aria-valuemin": seam.min, "aria-valuemax": seam.max, onKeyDown: seam.onKeyDown, onPointerDown: seam.onPointerDown, onPointerMove: seam.onPointerMove, onPointerUp: seam.endDrag, onPointerCancel: seam.endDrag }))] }));
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=PaneSplit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PaneSplit.js","sourceRoot":"","sources":["../../../src/react/components/PaneSplit.tsx"],"names":[],"mappings":";AA0BA,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AAC5C,OAAO,iBAAiB,CAAC;AAwBzB,MAAM,oBAAoB,GAAG,IAAI,CAAC;AAElC;;;GAGG;AACH,SAAS,QAAQ,CAAI,IAAsB,EAAE,OAA4B;IACvE,IAAI,IAAI,CAAC,IAAI,KAAK,MAAM;QAAE,OAAO,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACpD,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC1E,CAAC;AAED,MAAM,UAAU,SAAS,CAAI,KAAwB;IACnD,MAAM,EAAE,IAAI,EAAE,GAAG,KAAK,CAAC;IACvB,IAAI,IAAI,CAAC,IAAI,KAAK,MAAM;QAAE,OAAO,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC7D,OAAO,KAAC,SAAS,OAAK,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,IAAI,EAAE,GAAI,CAAC;AACtE,CAAC;AAED,SAAS,SAAS,CAAI,EACpB,IAAI,EACJ,IAAI,EACJ,OAAO,EACP,UAAU,EACV,QAAQ,EACR,WAAW,GAAG,oBAAoB,GAC8D;IAChG,MAAM,KAAK,GAAG,MAAM,CAAiB,IAAI,CAAC,CAAC;IAC3C,MAAM,QAAQ,GAAG,MAAM,CAAgB,IAAI,CAAC,CAAC;IAE7C,wFAAwF;IACxF,MAAM,QAAQ,GAAG,WAAW,CAC1B,CAAC,KAAa,EAAE,KAAa,EAAE,EAAE;QAC/B,MAAM,IAAI,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;QACrE,IAAI,IAAI,IAAI,CAAC;YAAE,OAAO;QACtB,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,WAAW,CAAC,EAAE,CAAC,GAAG,WAAW,CAAC,CAAC;QACxE,MAAM,KAAK,GAAG,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC;QAC9B,KAAK,CAAC,KAAK,CAAC,GAAG,IAAI,GAAG,OAAO,CAAC;QAC9B,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC;QACxC,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IACxB,CAAC,EACD,CAAC,IAAI,CAAC,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,IAAI,CAAC,CAC1C,CAAC;IAEF,MAAM,QAAQ,GAAG,CAAC,KAAa,EAAE,QAAgB,EAAE,EAAE;QACnD,MAAM,GAAG,GAAG,KAAK,CAAC,OAAO,EAAE,qBAAqB,EAAE,CAAC;QACnD,IAAI,CAAC,GAAG;YAAE,OAAO;QACjB,MAAM,KAAK,GAAG,IAAI,CAAC,SAAS,KAAK,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC;QAChE,IAAI,KAAK,IAAI,CAAC;YAAE,OAAO;QACvB,MAAM,MAAM,GAAG,CAAC,IAAI,CAAC,SAAS,KAAK,KAAK,CAAC,CAAC,CAAC,QAAQ,GAAG,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,GAAG,GAAG,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;QAC7F,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,CAAC,GAAG,GAAG,IAAI,EAAE,CAAC,CAAC,CAAC;QAC/E,MAAM,IAAI,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;QACrE,IAAI,IAAI,IAAI,CAAC;YAAE,OAAO;QACtB,QAAQ,CAAC,KAAK,EAAE,CAAC,MAAM,GAAG,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC;IAC5C,CAAC,CAAC;IAEF,MAAM,SAAS,GAAG,CAAC,KAAa,EAAE,KAAa,EAAE,EAAE;QACjD,MAAM,IAAI,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;QACrE,IAAI,IAAI,IAAI,CAAC;YAAE,OAAO;QACtB,QAAQ,CAAC,KAAK,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,IAAI,GAAG,KAAK,CAAC,CAAC;IAC3D,CAAC,CAAC;IAEF,MAAM,SAAS,GAAG,CAAC,KAAyC,EAAE,KAAa,EAAE,EAAE;QAC7E,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,KAAK,KAAK,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,SAAS,CAAC;QAChE,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,KAAK,KAAK,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,WAAW,CAAC;QACtE,IAAI,KAAK,CAAC,GAAG,KAAK,IAAI;YAAE,SAAS,CAAC,KAAK,EAAE,CAAC,IAAI,CAAC,CAAC;aAC3C,IAAI,KAAK,CAAC,GAAG,KAAK,OAAO;YAAE,SAAS,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;aAClD,IAAI,KAAK,CAAC,GAAG,KAAK,MAAM;YAAE,SAAS,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC;aAC/C,IAAI,KAAK,CAAC,GAAG,KAAK,KAAK;YAAE,SAAS,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;;YAC7C,OAAO;QACZ,KAAK,CAAC,cAAc,EAAE,CAAC;IACzB,CAAC,CAAC;IAEF,MAAM,aAAa,GAAG,CAAC,KAAwC,EAAE,KAAa,EAAE,EAAE;QAChF,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO;QAC/B,QAAQ,CAAC,OAAO,GAAG,KAAK,CAAC;QACzB,KAAK,CAAC,aAAa,CAAC,iBAAiB,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;QACvD,KAAK,CAAC,cAAc,EAAE,CAAC;IACzB,CAAC,CAAC;IAEF,MAAM,aAAa,GAAG,CAAC,KAAwC,EAAE,EAAE;QACjE,IAAI,QAAQ,CAAC,OAAO,KAAK,IAAI;YAAE,OAAO;QACtC,QAAQ,CAAC,QAAQ,CAAC,OAAO,EAAE,IAAI,CAAC,SAAS,KAAK,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IACvF,CAAC,CAAC;IAEF,MAAM,OAAO,GAAG,CAAC,KAAwC,EAAE,EAAE;QAC3D,IAAI,QAAQ,CAAC,OAAO,KAAK,IAAI;YAAE,OAAO;QACtC,QAAQ,CAAC,OAAO,GAAG,IAAI,CAAC;QACxB,IAAI,KAAK,CAAC,aAAa,CAAC,iBAAiB,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC;YAAE,KAAK,CAAC,aAAa,CAAC,qBAAqB,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;IAC3H,CAAC,CAAC;IAEF,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW,GAAG,GAAG,CAAC,CAAC;IACjD,OAAO,CACL,cAAK,SAAS,EAAC,cAAc,oBAAiB,IAAI,CAAC,SAAS,EAAE,GAAG,EAAE,KAAK,YACrE,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC,CACnC,KAAC,YAAY,IAEX,IAAI,EAAE,KAAK,KAAK,IAAI,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,EACxC,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,EACnD,IAAI,EAAE;gBACJ,SAAS,EAAE,IAAI,CAAC,SAAS;gBACzB,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,GAAG,CAAC;gBACnD,GAAG,EAAE,UAAU;gBACf,GAAG,EAAE,GAAG,GAAG,UAAU;gBACrB,SAAS,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,SAAS,CAAC,KAAK,EAAE,KAAK,CAAC;gBAC7C,aAAa,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,aAAa,CAAC,KAAK,EAAE,KAAK,CAAC;gBACrD,aAAa;gBACb,OAAO;aACR,YAED,KAAC,SAAS,IAAC,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,GAAG,IAAI,EAAE,KAAK,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,QAAQ,EAAE,QAAQ,EAAE,WAAW,EAAE,WAAW,GAAI,IAdrI,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC,CAehB,CAChB,CAAC,GACE,CACP,CAAC;AACJ,CAAC;AAaD,SAAS,YAAY,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAA2E;IAC3H,OAAO,CACL,8BACE,cAAK,SAAS,EAAC,oBAAoB,EAAC,KAAK,EAAE,EAAE,sBAAsB,EAAE,IAAI,EAAmB,YACzF,QAAQ,GACL,EACL,CAAC,IAAI,IAAI,CAIR,cACE,SAAS,EAAC,oBAAoB,EAC9B,IAAI,EAAC,WAAW,EAChB,QAAQ,EAAE,CAAC,sBACO,IAAI,CAAC,SAAS,KAAK,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,YAAY,gBAC1D,IAAI,CAAC,SAAS,KAAK,KAAK,CAAC,CAAC,CAAC,+BAA+B,CAAC,CAAC,CAAC,0BAA0B,mBACpF,IAAI,CAAC,OAAO,mBACZ,IAAI,CAAC,GAAG,mBACR,IAAI,CAAC,GAAG,EACvB,SAAS,EAAE,IAAI,CAAC,SAAS,EACzB,aAAa,EAAE,IAAI,CAAC,aAAa,EACjC,aAAa,EAAE,IAAI,CAAC,aAAa,EACjC,WAAW,EAAE,IAAI,CAAC,OAAO,EACzB,eAAe,EAAE,IAAI,CAAC,OAAO,GAC7B,CACH,IACA,CACJ,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `usePointerDrag` + `DragGhost` — a drag you can SEE, with a mouse or a finger.
|
|
3
|
+
*
|
|
4
|
+
* The owner, of desk's tab deck: *"When I drag a tab in desk app it should animate or show the tab
|
|
5
|
+
* moving with your mouse cursor (or on iphone with the dragging gesture) like vs code does."* — and
|
|
6
|
+
* *"since these changes apply to layouts and cards they should be changed in cb"*. So the gesture
|
|
7
|
+
* and its picture live here, and an app keeps only what is its own: where a drop lands.
|
|
8
|
+
*
|
|
9
|
+
* ## The gesture
|
|
10
|
+
*
|
|
11
|
+
* Pointer events, never HTML5 drag-and-drop, for `SheetTabStrip`'s reasons: the native API's image
|
|
12
|
+
* is a translucent screenshot the page cannot style, it cannot be driven by CDP in a check, and it
|
|
13
|
+
* fires nothing at all for touch.
|
|
14
|
+
*
|
|
15
|
+
* - **Mouse and pen**: a press becomes a drag past `slop` pixels of travel, so a click is still a
|
|
16
|
+
* click and a double-click still lands. 🔴 The pointer is captured AT THE PRESS: a quick flick
|
|
17
|
+
* leaves a 30px tab inside one frame, and an element that only hears moves while the pointer is
|
|
18
|
+
* over it never sees the travel that would make it a drag (measured in desk's browser check).
|
|
19
|
+
* Capture to the pressed element itself redirects nothing a click needs — down and up both land
|
|
20
|
+
* on it.
|
|
21
|
+
* - **Touch**: a finger has to REST for `holdMs` first. Anything that moves before then is a scroll
|
|
22
|
+
* and is left to the browser — a tab strip pans sideways, and a drag that starts on any touch takes
|
|
23
|
+
* the pan away from the gesture people use most. Once the hold fires, a non-passive `touchmove`
|
|
24
|
+
* listener (registered at the press, so the browser waits for it) cancels the scroll for the rest
|
|
25
|
+
* of the gesture. 250 ms and 5 px are `pointerDnd.ts`'s long-press, so a hold means the same thing
|
|
26
|
+
* on every draggable surface of the belt.
|
|
27
|
+
* - **Escape** abandons a drag wherever focus is; nothing is committed.
|
|
28
|
+
*
|
|
29
|
+
* ## The picture
|
|
30
|
+
*
|
|
31
|
+
* `DragGhost` draws the thing being dragged under the pointer, offset by where it was grabbed, at
|
|
32
|
+
* the size it had — VS Code's lifted tab. It is `position: fixed`, so a scrolling strip or a pane's
|
|
33
|
+
* `overflow: hidden` does not clip it, and it ignores the pointer, so `document.elementFromPoint`
|
|
34
|
+
* still answers with the drop target beneath it. Plain CSS (`pointerDrag.css`), so it draws in an
|
|
35
|
+
* app with no Tailwind pass.
|
|
36
|
+
*/
|
|
37
|
+
import type { PointerEvent as ReactPointerEvent, ReactNode } from 'react';
|
|
38
|
+
import './pointerDrag.css';
|
|
39
|
+
/** Pixels a mouse or pen travels before a press is a drag. */
|
|
40
|
+
export declare const POINTER_DRAG_SLOP_PX = 5;
|
|
41
|
+
/** How long a finger rests before a touch press is a drag — `pointerDnd.ts`'s long-press. */
|
|
42
|
+
export declare const POINTER_DRAG_HOLD_MS = 250;
|
|
43
|
+
export interface DragPoint {
|
|
44
|
+
x: number;
|
|
45
|
+
y: number;
|
|
46
|
+
}
|
|
47
|
+
export interface PointerDragState<T> {
|
|
48
|
+
item: T;
|
|
49
|
+
/** Where the pointer is now, in client coordinates. */
|
|
50
|
+
at: DragPoint;
|
|
51
|
+
/** Where inside the source element it was grabbed — the ghost keeps that point under the pointer. */
|
|
52
|
+
grab: DragPoint;
|
|
53
|
+
/** The source element's size when the press began, so the ghost is the same shape. */
|
|
54
|
+
width: number;
|
|
55
|
+
height: number;
|
|
56
|
+
pointerType: string;
|
|
57
|
+
}
|
|
58
|
+
export interface UsePointerDragOptions<T> {
|
|
59
|
+
/** Every move once the press has become a drag — where a drop marker is worked out. */
|
|
60
|
+
onMove?: (state: PointerDragState<T>) => void;
|
|
61
|
+
/** Released while dragging. */
|
|
62
|
+
onDrop: (state: PointerDragState<T>) => void;
|
|
63
|
+
/** Released without ever becoming a drag. */
|
|
64
|
+
onTap?: (item: T) => void;
|
|
65
|
+
/** The drag was abandoned — Escape, or the browser took the pointer back. */
|
|
66
|
+
onCancel?: () => void;
|
|
67
|
+
slop?: number;
|
|
68
|
+
holdMs?: number;
|
|
69
|
+
disabled?: boolean;
|
|
70
|
+
}
|
|
71
|
+
export interface PointerDragBindings {
|
|
72
|
+
onPointerDown: (event: ReactPointerEvent<HTMLElement>) => void;
|
|
73
|
+
onPointerMove: (event: ReactPointerEvent<HTMLElement>) => void;
|
|
74
|
+
onPointerUp: (event: ReactPointerEvent<HTMLElement>) => void;
|
|
75
|
+
onPointerCancel: (event: ReactPointerEvent<HTMLElement>) => void;
|
|
76
|
+
}
|
|
77
|
+
export declare function usePointerDrag<T>(options: UsePointerDragOptions<T>): {
|
|
78
|
+
drag: PointerDragState<T> | null;
|
|
79
|
+
bind: (item: T) => PointerDragBindings;
|
|
80
|
+
};
|
|
81
|
+
export interface DragGhostProps {
|
|
82
|
+
drag: Pick<PointerDragState<unknown>, 'at' | 'grab' | 'width' | 'height'> | null;
|
|
83
|
+
children: ReactNode;
|
|
84
|
+
className?: string;
|
|
85
|
+
}
|
|
86
|
+
/** The dragged thing, lifted and following the pointer. Renders nothing while nothing is dragged. */
|
|
87
|
+
export declare function DragGhost({ drag, children, className }: DragGhostProps): import("react").JSX.Element | null;
|
|
88
|
+
//# sourceMappingURL=PointerDrag.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PointerDrag.d.ts","sourceRoot":"","sources":["../../../src/react/components/PointerDrag.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAEH,OAAO,KAAK,EAAiB,YAAY,IAAI,iBAAiB,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEzF,OAAO,mBAAmB,CAAC;AAE3B,8DAA8D;AAC9D,eAAO,MAAM,oBAAoB,IAAI,CAAC;AACtC,6FAA6F;AAC7F,eAAO,MAAM,oBAAoB,MAAM,CAAC;AAExC,MAAM,WAAW,SAAS;IACxB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;CACX;AAED,MAAM,WAAW,gBAAgB,CAAC,CAAC;IACjC,IAAI,EAAE,CAAC,CAAC;IACR,uDAAuD;IACvD,EAAE,EAAE,SAAS,CAAC;IACd,qGAAqG;IACrG,IAAI,EAAE,SAAS,CAAC;IAChB,sFAAsF;IACtF,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,qBAAqB,CAAC,CAAC;IACtC,uFAAuF;IACvF,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,gBAAgB,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC;IAC9C,+BAA+B;IAC/B,MAAM,EAAE,CAAC,KAAK,EAAE,gBAAgB,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC;IAC7C,6CAA6C;IAC7C,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,IAAI,CAAC;IAC1B,6EAA6E;IAC7E,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,mBAAmB;IAClC,aAAa,EAAE,CAAC,KAAK,EAAE,iBAAiB,CAAC,WAAW,CAAC,KAAK,IAAI,CAAC;IAC/D,aAAa,EAAE,CAAC,KAAK,EAAE,iBAAiB,CAAC,WAAW,CAAC,KAAK,IAAI,CAAC;IAC/D,WAAW,EAAE,CAAC,KAAK,EAAE,iBAAiB,CAAC,WAAW,CAAC,KAAK,IAAI,CAAC;IAC7D,eAAe,EAAE,CAAC,KAAK,EAAE,iBAAiB,CAAC,WAAW,CAAC,KAAK,IAAI,CAAC;CAClE;AA8BD,wBAAgB,cAAc,CAAC,CAAC,EAAE,OAAO,EAAE,qBAAqB,CAAC,CAAC,CAAC,GAAG;IACpE,IAAI,EAAE,gBAAgB,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;IACjC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,mBAAmB,CAAC;CACxC,CAoHA;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,EAAE,IAAI,GAAG,MAAM,GAAG,OAAO,GAAG,QAAQ,CAAC,GAAG,IAAI,CAAC;IACjF,QAAQ,EAAE,SAAS,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,qGAAqG;AACrG,wBAAgB,SAAS,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,EAAE,cAAc,sCAoBtE"}
|