colibri-ui 0.8.95 → 0.8.97
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/ColorPicker/ColorPicker.d.ts +3 -0
- package/ColorPicker/ColorPicker.js +116 -0
- package/ColorPicker/ColorPicker.module.css +22 -0
- package/ColorPicker/assets/none.png +0 -0
- package/ColorPicker/components/ColorPreview/ColorPreview.module.css +23 -0
- package/ColorPicker/components/ColorPreview/index.d.ts +10 -0
- package/ColorPicker/components/ColorPreview/index.js +29 -0
- package/ColorPicker/components/CustomColorModal/CustomColorModal.module.css +18 -0
- package/ColorPicker/components/CustomColorModal/index.d.ts +15 -0
- package/ColorPicker/components/CustomColorModal/index.js +107 -0
- package/ColorPicker/components/HueSlider/HueSlider.module.css +31 -0
- package/ColorPicker/components/HueSlider/index.d.ts +10 -0
- package/ColorPicker/components/HueSlider/index.js +73 -0
- package/ColorPicker/components/Palette/Palette.module.css +12 -0
- package/ColorPicker/components/Palette/index.d.ts +19 -0
- package/ColorPicker/components/Palette/index.js +99 -0
- package/ColorPicker/components/SaturationPanel/SaturationPanel.module.css +26 -0
- package/ColorPicker/components/SaturationPanel/index.d.ts +13 -0
- package/ColorPicker/components/SaturationPanel/index.js +86 -0
- package/ColorPicker/components/Swatch/Swatch.module.css +36 -0
- package/ColorPicker/components/Swatch/index.d.ts +14 -0
- package/ColorPicker/components/Swatch/index.js +47 -0
- package/ColorPicker/hooks/useEyeDropper.d.ts +8 -0
- package/ColorPicker/hooks/useEyeDropper.js +38 -0
- package/ColorPicker/hooks/useHexDraft.d.ts +19 -0
- package/ColorPicker/hooks/useHexDraft.js +49 -0
- package/ColorPicker/hooks/usePointerDrag.d.ts +20 -0
- package/ColorPicker/hooks/usePointerDrag.js +55 -0
- package/ColorPicker/index.d.ts +3 -0
- package/ColorPicker/index.js +9 -0
- package/ColorPicker/index.props.d.ts +43 -0
- package/ColorPicker/package.json +9 -0
- package/ColorPicker/presets.d.ts +3 -0
- package/ColorPicker/presets.js +92 -0
- package/ColorPicker/utils/color.d.ts +25 -0
- package/ColorPicker/utils/color.js +162 -0
- package/Icons/Pipette.d.ts +3 -0
- package/Icons/Pipette.js +35 -0
- package/Icons/index.d.ts +1 -0
- package/Icons/index.js +2 -0
- package/Modal/Modal.module.css +10 -0
- package/Modal/index.js +4 -2
- package/Modal/index.props.d.ts +6 -0
- package/esm/ColorPicker/ColorPicker.d.ts +3 -0
- package/esm/ColorPicker/ColorPicker.js +108 -0
- package/esm/ColorPicker/ColorPicker.module.css +22 -0
- package/esm/ColorPicker/assets/none.png +0 -0
- package/esm/ColorPicker/components/ColorPreview/ColorPreview.module.css +23 -0
- package/esm/ColorPicker/components/ColorPreview/index.d.ts +10 -0
- package/esm/ColorPicker/components/ColorPreview/index.js +21 -0
- package/esm/ColorPicker/components/CustomColorModal/CustomColorModal.module.css +18 -0
- package/esm/ColorPicker/components/CustomColorModal/index.d.ts +15 -0
- package/esm/ColorPicker/components/CustomColorModal/index.js +100 -0
- package/esm/ColorPicker/components/HueSlider/HueSlider.module.css +31 -0
- package/esm/ColorPicker/components/HueSlider/index.d.ts +10 -0
- package/esm/ColorPicker/components/HueSlider/index.js +66 -0
- package/esm/ColorPicker/components/Palette/Palette.module.css +12 -0
- package/esm/ColorPicker/components/Palette/index.d.ts +19 -0
- package/esm/ColorPicker/components/Palette/index.js +92 -0
- package/esm/ColorPicker/components/SaturationPanel/SaturationPanel.module.css +26 -0
- package/esm/ColorPicker/components/SaturationPanel/index.d.ts +13 -0
- package/esm/ColorPicker/components/SaturationPanel/index.js +79 -0
- package/esm/ColorPicker/components/Swatch/Swatch.module.css +36 -0
- package/esm/ColorPicker/components/Swatch/index.d.ts +14 -0
- package/esm/ColorPicker/components/Swatch/index.js +38 -0
- package/esm/ColorPicker/hooks/useEyeDropper.d.ts +8 -0
- package/esm/ColorPicker/hooks/useEyeDropper.js +36 -0
- package/esm/ColorPicker/hooks/useHexDraft.d.ts +19 -0
- package/esm/ColorPicker/hooks/useHexDraft.js +47 -0
- package/esm/ColorPicker/hooks/usePointerDrag.d.ts +20 -0
- package/esm/ColorPicker/hooks/usePointerDrag.js +53 -0
- package/esm/ColorPicker/index.d.ts +3 -0
- package/esm/ColorPicker/index.js +2 -0
- package/esm/ColorPicker/index.props.d.ts +43 -0
- package/esm/ColorPicker/presets.d.ts +3 -0
- package/esm/ColorPicker/presets.js +89 -0
- package/esm/ColorPicker/utils/color.d.ts +25 -0
- package/esm/ColorPicker/utils/color.js +152 -0
- package/esm/Icons/Pipette.d.ts +3 -0
- package/esm/Icons/Pipette.js +29 -0
- package/esm/Icons/index.d.ts +1 -0
- package/esm/Icons/index.js +1 -0
- package/esm/Modal/Modal.module.css +10 -0
- package/esm/Modal/index.js +4 -2
- package/esm/Modal/index.props.d.ts +6 -0
- package/esm/index.d.ts +2 -0
- package/esm/index.js +3 -0
- package/index.d.ts +2 -0
- package/index.js +7 -0
- package/package.json +1 -1
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var React = require('react');
|
|
4
|
+
var usePointerDrag = require('../../hooks/usePointerDrag.js');
|
|
5
|
+
var color = require('../../utils/color.js');
|
|
6
|
+
var styles = require('./SaturationPanel.module.css');
|
|
7
|
+
|
|
8
|
+
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
9
|
+
|
|
10
|
+
var React__default = /*#__PURE__*/_interopDefault(React);
|
|
11
|
+
var styles__default = /*#__PURE__*/_interopDefault(styles);
|
|
12
|
+
|
|
13
|
+
const STEP = 1;
|
|
14
|
+
const BIG_STEP = 10;
|
|
15
|
+
/**
|
|
16
|
+
* Saturation (horizontal) and brightness (vertical) area. Arrow keys change
|
|
17
|
+
* by 1, with Shift by 10.
|
|
18
|
+
*/
|
|
19
|
+
const SaturationPanel = ({
|
|
20
|
+
value,
|
|
21
|
+
onChange,
|
|
22
|
+
"aria-label": ariaLabel
|
|
23
|
+
}) => {
|
|
24
|
+
const {
|
|
25
|
+
h,
|
|
26
|
+
s,
|
|
27
|
+
v
|
|
28
|
+
} = value;
|
|
29
|
+
const {
|
|
30
|
+
ref,
|
|
31
|
+
handlers
|
|
32
|
+
} = usePointerDrag.usePointerDrag(({
|
|
33
|
+
x,
|
|
34
|
+
y
|
|
35
|
+
}) => onChange({
|
|
36
|
+
h,
|
|
37
|
+
s: x * 100,
|
|
38
|
+
v: (1 - y) * 100
|
|
39
|
+
}));
|
|
40
|
+
const handleKeyDown = event => {
|
|
41
|
+
const step = event.shiftKey ? BIG_STEP : STEP;
|
|
42
|
+
const deltas = {
|
|
43
|
+
ArrowLeft: [-step, 0],
|
|
44
|
+
ArrowRight: [step, 0],
|
|
45
|
+
ArrowUp: [0, step],
|
|
46
|
+
ArrowDown: [0, -step]
|
|
47
|
+
};
|
|
48
|
+
const delta = deltas[event.key];
|
|
49
|
+
if (!delta) return;
|
|
50
|
+
event.preventDefault();
|
|
51
|
+
onChange({
|
|
52
|
+
h,
|
|
53
|
+
s: color.clamp(s + delta[0], 0, 100),
|
|
54
|
+
v: color.clamp(v + delta[1], 0, 100)
|
|
55
|
+
});
|
|
56
|
+
};
|
|
57
|
+
return /*#__PURE__*/React__default.default.createElement("div", Object.assign({
|
|
58
|
+
ref: ref
|
|
59
|
+
}, handlers, {
|
|
60
|
+
role: "slider",
|
|
61
|
+
tabIndex: 0,
|
|
62
|
+
"aria-label": ariaLabel,
|
|
63
|
+
"aria-valuemin": 0,
|
|
64
|
+
"aria-valuemax": 100,
|
|
65
|
+
"aria-valuenow": Math.round(s),
|
|
66
|
+
"aria-valuetext": `${Math.round(s)}%, ${Math.round(v)}%`,
|
|
67
|
+
onKeyDown: handleKeyDown,
|
|
68
|
+
className: styles__default.default.root,
|
|
69
|
+
style: {
|
|
70
|
+
backgroundColor: color.hsv2css({
|
|
71
|
+
h,
|
|
72
|
+
s: 100,
|
|
73
|
+
v: 100
|
|
74
|
+
})
|
|
75
|
+
}
|
|
76
|
+
}), /*#__PURE__*/React__default.default.createElement("div", {
|
|
77
|
+
className: styles__default.default.thumb,
|
|
78
|
+
style: {
|
|
79
|
+
left: `${s}%`,
|
|
80
|
+
top: `${100 - v}%`,
|
|
81
|
+
backgroundColor: color.hsv2css(value)
|
|
82
|
+
}
|
|
83
|
+
}));
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
exports.SaturationPanel = SaturationPanel;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
.root {
|
|
2
|
+
align-items: center;
|
|
3
|
+
border-radius: var(--radius-full);
|
|
4
|
+
cursor: pointer;
|
|
5
|
+
display: inline-flex;
|
|
6
|
+
flex-shrink: 0;
|
|
7
|
+
height: var(--space-6);
|
|
8
|
+
justify-content: center;
|
|
9
|
+
padding: 0;
|
|
10
|
+
transition: transform 0.1s ease;
|
|
11
|
+
width: var(--space-6);
|
|
12
|
+
}
|
|
13
|
+
.root:hover {
|
|
14
|
+
transform: scale(1.1);
|
|
15
|
+
}
|
|
16
|
+
.root:focus-visible {
|
|
17
|
+
outline: var(--focus-ring-width) solid var(--color-focus-ring);
|
|
18
|
+
outline-offset: var(--focus-ring-width);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.check_light {
|
|
22
|
+
color: var(--color-neutral-0);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.check_dark {
|
|
26
|
+
color: var(--color-neutral-950);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.outlined {
|
|
30
|
+
box-shadow: inset 0 0 0 var(--border-width-hairline) var(--color-border-default);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.check {
|
|
34
|
+
height: var(--space-4);
|
|
35
|
+
width: var(--space-4);
|
|
36
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import type { ButtonHTMLAttributes } from "react";
|
|
3
|
+
interface SwatchProps extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, "color" | "type"> {
|
|
4
|
+
/** `#rrggbb` */
|
|
5
|
+
color: string;
|
|
6
|
+
label: string;
|
|
7
|
+
selected: boolean;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Color circle button. The check mark adapts to the color, light colors get
|
|
11
|
+
* an outline.
|
|
12
|
+
*/
|
|
13
|
+
export declare const Swatch: ({ color, label, selected, className, ...props }: SwatchProps) => React.JSX.Element;
|
|
14
|
+
export {};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var tslib = require('tslib');
|
|
4
|
+
var React = require('react');
|
|
5
|
+
var clsx = require('clsx');
|
|
6
|
+
require('../../../Icons/index.js');
|
|
7
|
+
var color = require('../../utils/color.js');
|
|
8
|
+
var styles = require('./Swatch.module.css');
|
|
9
|
+
var Check = require('../../../Icons/Check.js');
|
|
10
|
+
|
|
11
|
+
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
12
|
+
|
|
13
|
+
var React__default = /*#__PURE__*/_interopDefault(React);
|
|
14
|
+
var clsx__default = /*#__PURE__*/_interopDefault(clsx);
|
|
15
|
+
var styles__default = /*#__PURE__*/_interopDefault(styles);
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Color circle button. The check mark adapts to the color, light colors get
|
|
19
|
+
* an outline.
|
|
20
|
+
*/
|
|
21
|
+
const Swatch = _a => {
|
|
22
|
+
var {
|
|
23
|
+
color: color$1,
|
|
24
|
+
label,
|
|
25
|
+
selected,
|
|
26
|
+
className
|
|
27
|
+
} = _a,
|
|
28
|
+
props = tslib.__rest(_a, ["color", "label", "selected", "className"]);
|
|
29
|
+
return /*#__PURE__*/React__default.default.createElement("button", Object.assign({}, props, {
|
|
30
|
+
type: "button",
|
|
31
|
+
role: "menuitemradio",
|
|
32
|
+
"aria-checked": selected,
|
|
33
|
+
"aria-label": label,
|
|
34
|
+
title: label,
|
|
35
|
+
className: clsx__default.default(styles__default.default.root, color.prefersLightText(color$1) ? styles__default.default.check_light : styles__default.default.check_dark, {
|
|
36
|
+
[styles__default.default.outlined]: color.isLightColor(color$1)
|
|
37
|
+
}, className),
|
|
38
|
+
style: {
|
|
39
|
+
backgroundColor: color$1
|
|
40
|
+
}
|
|
41
|
+
}), selected && /*#__PURE__*/React__default.default.createElement(Check.Check, {
|
|
42
|
+
className: styles__default.default.check,
|
|
43
|
+
"aria-hidden": "true"
|
|
44
|
+
}));
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
exports.Swatch = Swatch;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var React = require('react');
|
|
4
|
+
var color = require('../utils/color.js');
|
|
5
|
+
|
|
6
|
+
const subscribe = () => () => {};
|
|
7
|
+
const getSnapshot = () => "EyeDropper" in window;
|
|
8
|
+
// No API on the server, so hydration does not mismatch.
|
|
9
|
+
const getServerSnapshot = () => false;
|
|
10
|
+
/**
|
|
11
|
+
* Native browser eye dropper (EyeDropper API). Chromium only: in Safari and
|
|
12
|
+
* Firefox `isSupported` is `false`.
|
|
13
|
+
*/
|
|
14
|
+
const useEyeDropper = () => {
|
|
15
|
+
const isSupported = React.useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
|
|
16
|
+
/** `#rrggbb`, or `null` when the user cancels with Escape. */
|
|
17
|
+
const pick = React.useCallback(async () => {
|
|
18
|
+
const {
|
|
19
|
+
EyeDropper
|
|
20
|
+
} = window;
|
|
21
|
+
if (!EyeDropper) return null;
|
|
22
|
+
try {
|
|
23
|
+
// eslint-disable-next-line compat/compat -- guarded by the feature check above
|
|
24
|
+
const {
|
|
25
|
+
sRGBHex
|
|
26
|
+
} = await new EyeDropper().open();
|
|
27
|
+
return color.toHex(sRGBHex);
|
|
28
|
+
} catch (_a) {
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
}, []);
|
|
32
|
+
return {
|
|
33
|
+
isSupported,
|
|
34
|
+
pick
|
|
35
|
+
};
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
exports.useEyeDropper = useEyeDropper;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { ChangeEvent, KeyboardEvent } from "react";
|
|
2
|
+
/**
|
|
3
|
+
* HEX field logic for `Input`:
|
|
4
|
+
* - while focused, the field keeps a draft, so it can be cleared and retyped;
|
|
5
|
+
* - a full `#rrggbb` applies while typing;
|
|
6
|
+
* - a short `#abc` applies on blur or Enter (focus stays), so typing
|
|
7
|
+
* `#abcdef` does not flash `#aabbcc`;
|
|
8
|
+
* - invalid input reverts to the current value on blur.
|
|
9
|
+
*/
|
|
10
|
+
export declare const useHexDraft: (value: string, onChange: (hex: string) => void) => {
|
|
11
|
+
invalid: boolean;
|
|
12
|
+
inputProps: {
|
|
13
|
+
value: string;
|
|
14
|
+
onFocus: () => void;
|
|
15
|
+
onChange: (event: ChangeEvent<HTMLInputElement>) => void;
|
|
16
|
+
onBlur: () => void;
|
|
17
|
+
onKeyDown: (event: KeyboardEvent<HTMLInputElement>) => void;
|
|
18
|
+
};
|
|
19
|
+
};
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var React = require('react');
|
|
4
|
+
var color = require('../utils/color.js');
|
|
5
|
+
|
|
6
|
+
const FULL_HEX_RE = /^#?[0-9a-f]{6}$/i;
|
|
7
|
+
/**
|
|
8
|
+
* HEX field logic for `Input`:
|
|
9
|
+
* - while focused, the field keeps a draft, so it can be cleared and retyped;
|
|
10
|
+
* - a full `#rrggbb` applies while typing;
|
|
11
|
+
* - a short `#abc` applies on blur or Enter (focus stays), so typing
|
|
12
|
+
* `#abcdef` does not flash `#aabbcc`;
|
|
13
|
+
* - invalid input reverts to the current value on blur.
|
|
14
|
+
*/
|
|
15
|
+
const useHexDraft = (value, onChange) => {
|
|
16
|
+
// null: not editing, show `value`.
|
|
17
|
+
const [draft, setDraft] = React.useState(null);
|
|
18
|
+
const commit = text => {
|
|
19
|
+
const hex = color.normalizeHex(text);
|
|
20
|
+
if (hex && hex !== value) onChange(hex);
|
|
21
|
+
};
|
|
22
|
+
return {
|
|
23
|
+
invalid: draft !== null && color.normalizeHex(draft) === null,
|
|
24
|
+
inputProps: {
|
|
25
|
+
value: draft !== null && draft !== void 0 ? draft : value,
|
|
26
|
+
onFocus: () => setDraft(value),
|
|
27
|
+
onChange: event => {
|
|
28
|
+
const text = event.target.value;
|
|
29
|
+
setDraft(text);
|
|
30
|
+
if (FULL_HEX_RE.test(text.trim())) commit(text);
|
|
31
|
+
},
|
|
32
|
+
onBlur: () => {
|
|
33
|
+
if (draft !== null) commit(draft);
|
|
34
|
+
setDraft(null);
|
|
35
|
+
},
|
|
36
|
+
// Applies a short HEX and keeps focus in the field.
|
|
37
|
+
onKeyDown: event => {
|
|
38
|
+
if (event.key !== "Enter" || draft === null) return;
|
|
39
|
+
const hex = color.normalizeHex(draft);
|
|
40
|
+
if (hex) {
|
|
41
|
+
commit(draft);
|
|
42
|
+
setDraft(hex);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
exports.useHexDraft = useHexDraft;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { PointerEvent as ReactPointerEvent } from "react";
|
|
2
|
+
/** Pointer position inside the element, 0–1 on each axis. */
|
|
3
|
+
export interface DragPosition {
|
|
4
|
+
x: number;
|
|
5
|
+
y: number;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Dragging inside an element with Pointer Events (mouse, touch, pen).
|
|
9
|
+
* Pointer capture keeps tracking outside the element without document
|
|
10
|
+
* listeners. The element needs `touch-action: none`.
|
|
11
|
+
*/
|
|
12
|
+
export declare const usePointerDrag: <T extends HTMLElement>(onMove: (position: DragPosition) => void) => {
|
|
13
|
+
ref: import("react").RefObject<T | null>;
|
|
14
|
+
handlers: {
|
|
15
|
+
onPointerDown: (event: ReactPointerEvent<T>) => void;
|
|
16
|
+
onPointerMove: (event: ReactPointerEvent<T>) => void;
|
|
17
|
+
onPointerUp: (event: ReactPointerEvent<T>) => void;
|
|
18
|
+
onPointerCancel: (event: ReactPointerEvent<T>) => void;
|
|
19
|
+
};
|
|
20
|
+
};
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var React = require('react');
|
|
4
|
+
var color = require('../utils/color.js');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Dragging inside an element with Pointer Events (mouse, touch, pen).
|
|
8
|
+
* Pointer capture keeps tracking outside the element without document
|
|
9
|
+
* listeners. The element needs `touch-action: none`.
|
|
10
|
+
*/
|
|
11
|
+
const usePointerDrag = onMove => {
|
|
12
|
+
const ref = React.useRef(null);
|
|
13
|
+
const onMoveRef = React.useRef(onMove);
|
|
14
|
+
React.useEffect(() => {
|
|
15
|
+
onMoveRef.current = onMove;
|
|
16
|
+
});
|
|
17
|
+
const move = React.useCallback(event => {
|
|
18
|
+
const element = ref.current;
|
|
19
|
+
if (!element) return;
|
|
20
|
+
const rect = element.getBoundingClientRect();
|
|
21
|
+
onMoveRef.current({
|
|
22
|
+
x: color.clamp((event.clientX - rect.left) / rect.width),
|
|
23
|
+
y: color.clamp((event.clientY - rect.top) / rect.height)
|
|
24
|
+
});
|
|
25
|
+
}, []);
|
|
26
|
+
const onPointerDown = React.useCallback(event => {
|
|
27
|
+
if (event.button !== 0 || !ref.current) return;
|
|
28
|
+
// preventDefault stops text selection but also focus, so focus manually.
|
|
29
|
+
event.preventDefault();
|
|
30
|
+
ref.current.setPointerCapture(event.pointerId);
|
|
31
|
+
ref.current.focus();
|
|
32
|
+
move(event);
|
|
33
|
+
}, [move]);
|
|
34
|
+
const onPointerMove = React.useCallback(event => {
|
|
35
|
+
var _a;
|
|
36
|
+
if ((_a = ref.current) === null || _a === void 0 ? void 0 : _a.hasPointerCapture(event.pointerId)) move(event);
|
|
37
|
+
}, [move]);
|
|
38
|
+
const onPointerUp = React.useCallback(event => {
|
|
39
|
+
var _a;
|
|
40
|
+
if ((_a = ref.current) === null || _a === void 0 ? void 0 : _a.hasPointerCapture(event.pointerId)) {
|
|
41
|
+
ref.current.releasePointerCapture(event.pointerId);
|
|
42
|
+
}
|
|
43
|
+
}, []);
|
|
44
|
+
return {
|
|
45
|
+
ref,
|
|
46
|
+
handlers: {
|
|
47
|
+
onPointerDown,
|
|
48
|
+
onPointerMove,
|
|
49
|
+
onPointerUp,
|
|
50
|
+
onPointerCancel: onPointerUp
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
exports.usePointerDrag = usePointerDrag;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { ReactElement } from "react";
|
|
2
|
+
import type { Placement } from "@floating-ui/react";
|
|
3
|
+
export interface ColorPickerPreset {
|
|
4
|
+
/** HEX color, for example `#d81b60`. */
|
|
5
|
+
value: string;
|
|
6
|
+
/** Accessible name and tooltip of the swatch. */
|
|
7
|
+
label: string;
|
|
8
|
+
}
|
|
9
|
+
export interface ColorPickerLabels {
|
|
10
|
+
/** Accessible name of the default trigger. */
|
|
11
|
+
trigger: string;
|
|
12
|
+
/** Accessible name of the preset grid. */
|
|
13
|
+
palette: string;
|
|
14
|
+
/** "+" button that opens the custom color dialog. */
|
|
15
|
+
addCustom: string;
|
|
16
|
+
customTitle: string;
|
|
17
|
+
customDescription: string;
|
|
18
|
+
/** Sample text in the preview circle. */
|
|
19
|
+
preview: string;
|
|
20
|
+
hex: string;
|
|
21
|
+
eyeDropper: string;
|
|
22
|
+
saturation: string;
|
|
23
|
+
hue: string;
|
|
24
|
+
cancel: string;
|
|
25
|
+
save: string;
|
|
26
|
+
}
|
|
27
|
+
export interface ColorPickerProps {
|
|
28
|
+
/** Current color in HEX. A color missing from `presets` is shown as an extra swatch. */
|
|
29
|
+
value?: string;
|
|
30
|
+
/** Called with the chosen color as lowercase `#rrggbb`. */
|
|
31
|
+
onChange: (color: string) => void;
|
|
32
|
+
/** Preset colors. Defaults to `COLOR_PICKER_PRESETS`. */
|
|
33
|
+
presets?: ColorPickerPreset[];
|
|
34
|
+
/** Number of grid columns. */
|
|
35
|
+
columns?: number;
|
|
36
|
+
disabled?: boolean;
|
|
37
|
+
placement?: Placement;
|
|
38
|
+
zIndex?: number;
|
|
39
|
+
/** Texts and accessible names. Missing keys use English defaults. */
|
|
40
|
+
labels?: Partial<ColorPickerLabels>;
|
|
41
|
+
/** Custom trigger element. Defaults to a round button with the current color. */
|
|
42
|
+
children?: ReactElement;
|
|
43
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const COLOR_PICKER_PRESETS = [{
|
|
4
|
+
value: "#ad1457",
|
|
5
|
+
label: "Radicchio"
|
|
6
|
+
}, {
|
|
7
|
+
value: "#f4511e",
|
|
8
|
+
label: "Tangerine"
|
|
9
|
+
}, {
|
|
10
|
+
value: "#e4c441",
|
|
11
|
+
label: "Citron"
|
|
12
|
+
}, {
|
|
13
|
+
value: "#0b8043",
|
|
14
|
+
label: "Basil"
|
|
15
|
+
}, {
|
|
16
|
+
value: "#3f51b5",
|
|
17
|
+
label: "Blueberry"
|
|
18
|
+
}, {
|
|
19
|
+
value: "#8e24aa",
|
|
20
|
+
label: "Grape"
|
|
21
|
+
}, {
|
|
22
|
+
value: "#d81b60",
|
|
23
|
+
label: "Cherry blossom"
|
|
24
|
+
}, {
|
|
25
|
+
value: "#ef6c00",
|
|
26
|
+
label: "Pumpkin"
|
|
27
|
+
}, {
|
|
28
|
+
value: "#c0ca33",
|
|
29
|
+
label: "Avocado"
|
|
30
|
+
}, {
|
|
31
|
+
value: "#009688",
|
|
32
|
+
label: "Eucalyptus"
|
|
33
|
+
}, {
|
|
34
|
+
value: "#7986cb",
|
|
35
|
+
label: "Lavender"
|
|
36
|
+
}, {
|
|
37
|
+
value: "#795548",
|
|
38
|
+
label: "Cocoa"
|
|
39
|
+
}, {
|
|
40
|
+
value: "#d50000",
|
|
41
|
+
label: "Tomato"
|
|
42
|
+
}, {
|
|
43
|
+
value: "#f09300",
|
|
44
|
+
label: "Mango"
|
|
45
|
+
}, {
|
|
46
|
+
value: "#7cb342",
|
|
47
|
+
label: "Pistachio"
|
|
48
|
+
}, {
|
|
49
|
+
value: "#039be5",
|
|
50
|
+
label: "Peacock"
|
|
51
|
+
}, {
|
|
52
|
+
value: "#b39ddb",
|
|
53
|
+
label: "Wisteria"
|
|
54
|
+
}, {
|
|
55
|
+
value: "#616161",
|
|
56
|
+
label: "Graphite"
|
|
57
|
+
}, {
|
|
58
|
+
value: "#e67c73",
|
|
59
|
+
label: "Flamingo"
|
|
60
|
+
}, {
|
|
61
|
+
value: "#f6bf26",
|
|
62
|
+
label: "Banana"
|
|
63
|
+
}, {
|
|
64
|
+
value: "#33b679",
|
|
65
|
+
label: "Sage"
|
|
66
|
+
}, {
|
|
67
|
+
value: "#4285f4",
|
|
68
|
+
label: "Cobalt"
|
|
69
|
+
}, {
|
|
70
|
+
value: "#9e69af",
|
|
71
|
+
label: "Amethyst"
|
|
72
|
+
}, {
|
|
73
|
+
value: "#a79b8e",
|
|
74
|
+
label: "Birch"
|
|
75
|
+
}];
|
|
76
|
+
const DEFAULT_LABELS = {
|
|
77
|
+
trigger: "Choose color",
|
|
78
|
+
palette: "Colors",
|
|
79
|
+
addCustom: "Add custom color",
|
|
80
|
+
customTitle: "Choose custom color",
|
|
81
|
+
customDescription: "Choose a background color. The text color will be adjusted automatically.",
|
|
82
|
+
preview: "A",
|
|
83
|
+
hex: "Hex",
|
|
84
|
+
eyeDropper: "Pick a color from the screen",
|
|
85
|
+
saturation: "Saturation and brightness",
|
|
86
|
+
hue: "Hue",
|
|
87
|
+
cancel: "Cancel",
|
|
88
|
+
save: "Save"
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
exports.COLOR_PICKER_PRESETS = COLOR_PICKER_PRESETS;
|
|
92
|
+
exports.DEFAULT_LABELS = DEFAULT_LABELS;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/** h: 0–360, s: 0–100, v: 0–100 */
|
|
2
|
+
export interface HSV {
|
|
3
|
+
h: number;
|
|
4
|
+
s: number;
|
|
5
|
+
v: number;
|
|
6
|
+
}
|
|
7
|
+
export declare const clamp: (value: number, min?: number, max?: number) => number;
|
|
8
|
+
/** HSV → `hsl(...)` for inline styles. */
|
|
9
|
+
export declare const hsv2css: ({ h, s, v }: HSV) => string;
|
|
10
|
+
/** `#ABC`, `abc`, `#aabbcc` → `#aabbcc`. Invalid input → `null`. */
|
|
11
|
+
export declare const normalizeHex: (input: string) => string | null;
|
|
12
|
+
export declare const hsv2hex: (hsv: HSV) => string;
|
|
13
|
+
export declare const hex2hsv: (hex: string) => HSV | null;
|
|
14
|
+
/** HEX or `rgb()`/`rgba()` → `#rrggbb`. Invalid input → `null`. */
|
|
15
|
+
export declare const toHex: (input: string) => string | null;
|
|
16
|
+
/**
|
|
17
|
+
* HEX → HSV that keeps hue and saturation from `prev` where the color has
|
|
18
|
+
* none: grey has no hue, black has neither. Without this, typing `#000000`
|
|
19
|
+
* would jump the hue slider to 0 (red).
|
|
20
|
+
*/
|
|
21
|
+
export declare const toHsvPreservingHue: (hex: string, prev: HSV) => HSV | null;
|
|
22
|
+
/** Whether light text reads better than dark text on `background` (HEX). */
|
|
23
|
+
export declare const prefersLightText: (background: string) => boolean;
|
|
24
|
+
/** A light color that merges with a light surface and needs an outline. */
|
|
25
|
+
export declare const isLightColor: (hex: string, threshold?: number) => boolean;
|