@xsolla/xui-gradient-picker 0.204.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/README.md +280 -0
- package/native/index.d.mts +243 -0
- package/native/index.d.ts +243 -0
- package/native/index.js +1063 -0
- package/native/index.js.map +1 -0
- package/native/index.mjs +1033 -0
- package/native/index.mjs.map +1 -0
- package/package.json +62 -0
- package/web/index.d.mts +243 -0
- package/web/index.d.ts +243 -0
- package/web/index.js +1096 -0
- package/web/index.js.map +1 -0
- package/web/index.mjs +1049 -0
- package/web/index.mjs.map +1 -0
package/README.md
ADDED
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
# Gradient Picker
|
|
2
|
+
|
|
3
|
+
A cross-platform React gradient picker: a live preview track with draggable colour stops, per-stop colour and opacity editing via ColorPicker, and CSS-compatible gradient output.
|
|
4
|
+
|
|
5
|
+
<!-- BEGIN:xui-mcp-instructions:gradient-picker -->
|
|
6
|
+
|
|
7
|
+
A compound component for defining a CSS-style colour gradient. Combines a visual gradient preview track with draggable stop markers and integrates with ColorPicker to edit the colour and opacity of each stop individually. Supports three gradient types and up to five colour stops.
|
|
8
|
+
|
|
9
|
+
### When to use
|
|
10
|
+
|
|
11
|
+
- When a user needs to define a multi-colour gradient — background fills, banner overlays, avatar tints, UI theme customisation
|
|
12
|
+
- In design tool contexts, theme editors, or advanced colour configuration panels where fine-grained gradient control is required
|
|
13
|
+
- When the product supports gradient fills as a first-class input (e.g. a game customisation screen, a chart background picker)
|
|
14
|
+
|
|
15
|
+
### When not to use
|
|
16
|
+
|
|
17
|
+
- When a solid colour is sufficient — use ColorPicker instead
|
|
18
|
+
- When only a simple two-colour linear gradient with fixed endpoints is needed and the user doesn't need to adjust stops — consider a simpler two-swatch input
|
|
19
|
+
- In contexts where gradient complexity would overwhelm the user — hide behind an "Advanced" toggle
|
|
20
|
+
|
|
21
|
+
### Content guidelines
|
|
22
|
+
|
|
23
|
+
- Gradient type labels — use the standard CSS-adjacent names: "Linear", "Radial", "Angular" (or "Conic" if the product uses that term). Do not use internal technical names.
|
|
24
|
+
- Stop position display — when a stop is active, show its position as a percentage (e.g. 0%, 50%, 100%) in a read-only or editable label near the marker or in the ColorPicker header. This helps users set precise positions numerically.
|
|
25
|
+
- Minimum stops warning — if the user tries to remove the last stop, show a tooltip or brief inline message: "A gradient requires at least one stop" rather than silently blocking the action.
|
|
26
|
+
|
|
27
|
+
### Behaviour guidelines
|
|
28
|
+
|
|
29
|
+
- Adding stops — clicking on an empty area of the stop track adds a new stop at that position, interpolating its initial colour from the gradient at that point. The new stop immediately becomes Active. Adding is only permitted up to the product-defined maximum (5 in Figma).
|
|
30
|
+
- Removing stops — a stop can be removed by dragging it off the track (up or down beyond a threshold) or via a delete action (e.g. pressing Delete / Backspace when the stop is active). A minimum of 1 stop must always remain; do not allow removing the last stop.
|
|
31
|
+
- Dragging stops — a stop is dragged horizontally along the track. Position is expressed as a percentage (0%–100%). Stops cannot be dragged past each other — they swap order when they cross. Provide a smooth position update with no snap unless the product explicitly requires snapping to percentage increments.
|
|
32
|
+
- Active stop ColorPicker — the ColorPicker panel opens below the component when a stop is activated. If the panel would push the component out of the viewport, position it above the track instead. Closing the ColorPicker (clicking outside, pressing Escape) deactivates the stop.
|
|
33
|
+
- Gradient type change — switching Gradient type via the Select applies immediately to the preview without resetting stop positions or colours.
|
|
34
|
+
- Angle / centre point — for Linear, the gradient angle should be adjustable (e.g. via a degree input or a rotation handle on the preview). For Radial, the centre point should be configurable. For Angular, the rotation angle and start point should be configurable. These controls are not shown in the Figma component directly but are part of the full implementation.
|
|
35
|
+
- Real-time preview — every interaction (dragging a stop, changing a colour, switching gradient type, adjusting angle) must update the gradient preview in real time without requiring a confirm action.
|
|
36
|
+
- Output format — the component outputs a CSS-compatible gradient string that can be applied directly as a background or background-image value. Provide a copy action to let the user copy the gradient string.
|
|
37
|
+
|
|
38
|
+
### Accessibility
|
|
39
|
+
|
|
40
|
+
- The stop track must be operable by keyboard. When a stop has focus, ← / → arrows move it by 1% increments; Shift+← / Shift+→ move it by 10% increments.
|
|
41
|
+
- Each .GradientStop must have role=*"slider"* with aria-label identifying the stop (e.g. aria-label=*"Stop 1 position"*) and aria-valuenow / aria-valuemin=*"0"* / aria-valuemax=*"100"*.
|
|
42
|
+
- The gradient type selector must have aria-label=*"Gradient type"*.
|
|
43
|
+
- When a stop is activated and the ColorPicker opens, focus must move into the ColorPicker. When the ColorPicker closes, focus must return to the stop marker.
|
|
44
|
+
- The gradient preview is decorative — it must have aria-hidden=*"true"* and not receive focus.
|
|
45
|
+
- Adding a stop via keyboard: provide a button (e.g. *"+ Add stop"*) as a keyboard-accessible alternative to clicking on the track.
|
|
46
|
+
- Removing a stop via keyboard: when a stop is active, Delete / Backspace removes it and focus moves to the adjacent stop or the track.
|
|
47
|
+
- Do not rely on the visual gradient colour alone to communicate stop positions — always show numeric position values for screen reader users and users who cannot perceive colour differences in the gradient.
|
|
48
|
+
|
|
49
|
+
### Gradient types
|
|
50
|
+
|
|
51
|
+
The angle can only be controlled for linear gradients and angular gradients.
|
|
52
|
+
|
|
53
|
+
### Stop hover
|
|
54
|
+
|
|
55
|
+
While dragging a gradient stop, the row of the corresponding stop transitions into the active state.
|
|
56
|
+
|
|
57
|
+
<!-- END:xui-mcp-instructions:gradient-picker -->
|
|
58
|
+
|
|
59
|
+
## Installation
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
npm install @xsolla/xui-gradient-picker
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Demo
|
|
66
|
+
|
|
67
|
+
### Basic Gradient Picker
|
|
68
|
+
|
|
69
|
+
```tsx
|
|
70
|
+
import * as React from "react";
|
|
71
|
+
import { GradientPicker } from "@xsolla/xui-gradient-picker";
|
|
72
|
+
|
|
73
|
+
export default function BasicGradientPicker() {
|
|
74
|
+
return <GradientPicker onChange={({ css }) => console.log(css)} />;
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Controlled Gradient Picker
|
|
79
|
+
|
|
80
|
+
```tsx
|
|
81
|
+
import * as React from "react";
|
|
82
|
+
import {
|
|
83
|
+
GradientPicker,
|
|
84
|
+
DEFAULT_GRADIENT,
|
|
85
|
+
toCssGradient,
|
|
86
|
+
type GradientValue,
|
|
87
|
+
} from "@xsolla/xui-gradient-picker";
|
|
88
|
+
|
|
89
|
+
export default function ControlledGradientPicker() {
|
|
90
|
+
const [gradient, setGradient] = React.useState<GradientValue>(
|
|
91
|
+
DEFAULT_GRADIENT
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
return (
|
|
95
|
+
<>
|
|
96
|
+
<GradientPicker
|
|
97
|
+
value={gradient}
|
|
98
|
+
onChange={({ value }) => setGradient(value)}
|
|
99
|
+
/>
|
|
100
|
+
<div style={{ backgroundImage: toCssGradient(gradient) }} />
|
|
101
|
+
</>
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### Radial Gradient
|
|
107
|
+
|
|
108
|
+
```tsx
|
|
109
|
+
import * as React from "react";
|
|
110
|
+
import { GradientPicker } from "@xsolla/xui-gradient-picker";
|
|
111
|
+
|
|
112
|
+
export default function RadialGradient() {
|
|
113
|
+
return (
|
|
114
|
+
<GradientPicker
|
|
115
|
+
defaultValue={{
|
|
116
|
+
type: "radial",
|
|
117
|
+
angle: 0,
|
|
118
|
+
stops: [
|
|
119
|
+
{ id: "stop-1", color: "#D9D9D9", position: 0, opacity: 100 },
|
|
120
|
+
{ id: "stop-2", color: "#22A8C3", position: 100, opacity: 100 },
|
|
121
|
+
],
|
|
122
|
+
}}
|
|
123
|
+
/>
|
|
124
|
+
);
|
|
125
|
+
}
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
Radial gradients have no rotation, so the angle field is hidden for them.
|
|
129
|
+
|
|
130
|
+
### Angular ("Conic") Gradient
|
|
131
|
+
|
|
132
|
+
```tsx
|
|
133
|
+
import * as React from "react";
|
|
134
|
+
import { GradientPicker } from "@xsolla/xui-gradient-picker";
|
|
135
|
+
|
|
136
|
+
export default function AngularGradient() {
|
|
137
|
+
return (
|
|
138
|
+
<GradientPicker
|
|
139
|
+
typeLabels={{ angular: "Conic gradient" }}
|
|
140
|
+
onChange={({ css }) => console.log(css)}
|
|
141
|
+
/>
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
## Anatomy
|
|
147
|
+
|
|
148
|
+
```jsx
|
|
149
|
+
import { GradientPicker } from "@xsolla/xui-gradient-picker";
|
|
150
|
+
|
|
151
|
+
<GradientPicker
|
|
152
|
+
value={gradient} // Controlled gradient value
|
|
153
|
+
defaultValue={initial} // Initial value for uncontrolled usage
|
|
154
|
+
onChange={handleChange} // ({ value, css }) => void
|
|
155
|
+
gradientTypes={["linear", "radial", "angular"]} // Types offered in the selector
|
|
156
|
+
typeLabels={{ angular: "Conic gradient" }} // Option label overrides
|
|
157
|
+
minStops={1} // Floor for removal
|
|
158
|
+
maxStops={5} // Ceiling for adding
|
|
159
|
+
disabled={false} // Disable every control
|
|
160
|
+
stopsLabel="Stops" // Heading above the stop list
|
|
161
|
+
/>;
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
## API Reference
|
|
165
|
+
|
|
166
|
+
### GradientPicker
|
|
167
|
+
|
|
168
|
+
**GradientPickerProps:**
|
|
169
|
+
|
|
170
|
+
| Prop | Type | Default | Description |
|
|
171
|
+
| :------------- | :---------------------------------------------- | :----------------------------------- | :------------------------------------------------------------------------------------------------------------ |
|
|
172
|
+
| `testID` | `string` | — | Test ID for testing frameworks. On web this renders as `data-testid`; on React Native it renders as `testID`. |
|
|
173
|
+
| value | `GradientValue` | — | Controlled gradient value. Pair with `onChange`. |
|
|
174
|
+
| defaultValue | `GradientValue` | `DEFAULT_GRADIENT` | Initial gradient value for uncontrolled usage. |
|
|
175
|
+
| onChange | `(event: GradientPickerChangeEvent) => void` | — | Fired on every interaction. Receives the new value and its CSS string. |
|
|
176
|
+
| gradientTypes | `GradientType[]` | `["linear", "radial", "angular"]` | Gradient types offered in the selector, in display order. |
|
|
177
|
+
| typeLabels | `Partial<Record<GradientType, string>>` | — | Overrides for the gradient-type option labels. |
|
|
178
|
+
| minStops | `number` | `1` | Smallest number of stops the user may reduce the gradient to. |
|
|
179
|
+
| maxStops | `number` | `5` | Largest number of stops the user may add. |
|
|
180
|
+
| disabled | `boolean` | `false` | Disables every control and blocks track interaction. |
|
|
181
|
+
| typeAriaLabel | `string` | `"Gradient type"` | Accessible name for the gradient-type selector. |
|
|
182
|
+
| angleAriaLabel | `string` | `"Gradient angle"` | Accessible name for the angle field. |
|
|
183
|
+
| stopsLabel | `string` | `"Stops"` | Heading rendered above the stop list. |
|
|
184
|
+
|
|
185
|
+
### Types
|
|
186
|
+
|
|
187
|
+
```typescript
|
|
188
|
+
type GradientType = "linear" | "radial" | "angular";
|
|
189
|
+
|
|
190
|
+
interface GradientStop {
|
|
191
|
+
id: string; // Stable identity, survives reordering
|
|
192
|
+
color: string; // "#RRGGBB"
|
|
193
|
+
position: number; // 0–100 (percent)
|
|
194
|
+
opacity: number; // 0–100 (percent)
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
interface GradientValue {
|
|
198
|
+
type: GradientType;
|
|
199
|
+
angle: number; // Degrees; ignored for "radial"
|
|
200
|
+
stops: GradientStop[];
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
interface GradientPickerChangeEvent {
|
|
204
|
+
value: GradientValue;
|
|
205
|
+
css: string; // e.g. "linear-gradient(0deg, #D9D9D9 0%, #22A8C3 100%)"
|
|
206
|
+
}
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
### Exported helpers
|
|
210
|
+
|
|
211
|
+
Every gradient operation is a pure function, so a consuming surface can render
|
|
212
|
+
or transform a gradient without mounting the component.
|
|
213
|
+
|
|
214
|
+
| Helper | Signature | Description |
|
|
215
|
+
| :------------------------------------ | :--------------------------------------------------------------- | :-------------------------------------------------------------------------------- |
|
|
216
|
+
| `toCssGradient(value)` | `(value: GradientValue) => string` | Serialises to `linear-gradient()` / `radial-gradient()` / `conic-gradient()`. |
|
|
217
|
+
| `toPreviewCssGradient(value)` | `(value: GradientValue) => string` | Left-to-right ramp used by the preview track, regardless of gradient type. |
|
|
218
|
+
| `interpolateColorAt(stops, position)` | `(stops: GradientStop[], position: number) => { color, opacity }` | Samples the gradient — the colour a stop added at `position` inherits. |
|
|
219
|
+
| `addStopAt(stops, position, max)` | `(…) => GradientStop[]` | Adds an interpolated stop; returns the input array unchanged at `max`. |
|
|
220
|
+
| `removeStop(stops, id, min)` | `(…) => GradientStop[]` | Removes by id; returns the input array unchanged at `min`. |
|
|
221
|
+
| `updateStop(stops, id, patch)` | `(…) => GradientStop[]` | Applies a clamped, normalised patch to one stop. |
|
|
222
|
+
| `sortStops(stops)` | `(stops: GradientStop[]) => GradientStop[]` | Position order, stable on ties, non-mutating. |
|
|
223
|
+
| `supportsAngle(type)` | `(type: GradientType) => boolean` | `false` for `radial` — the angle field is hidden for it. |
|
|
224
|
+
| `DEFAULT_GRADIENT` | `GradientValue` | The two-stop `#D9D9D9 → #22A8C3` linear ramp from the Figma component. |
|
|
225
|
+
|
|
226
|
+
## CSS output
|
|
227
|
+
|
|
228
|
+
| Type | Output |
|
|
229
|
+
| :-------- | :-------------------------------------------------------------- |
|
|
230
|
+
| `linear` | `linear-gradient(<angle>deg, <stops>)` |
|
|
231
|
+
| `radial` | `radial-gradient(circle, <stops>)` |
|
|
232
|
+
| `angular` | `conic-gradient(from <angle>deg, <stops>)` |
|
|
233
|
+
|
|
234
|
+
A fully opaque stop serialises to its hex value; a partially transparent stop
|
|
235
|
+
serialises to `rgba()`. A gradient with a single stop is emitted twice (`0%` and
|
|
236
|
+
`100%`) because CSS gradients require at least two colour stops.
|
|
237
|
+
|
|
238
|
+
## Keyboard navigation
|
|
239
|
+
|
|
240
|
+
| Key | Action |
|
|
241
|
+
| :------------------------ | :------------------------------------------------ |
|
|
242
|
+
| Tab / Shift+Tab | Move focus between markers, fields and buttons |
|
|
243
|
+
| ← / → (marker focused) | Move the stop by 1% |
|
|
244
|
+
| Shift+← / Shift+→ | Move the stop by 10% |
|
|
245
|
+
| Home / End | Jump the stop to 0% / 100% |
|
|
246
|
+
| Enter / Space | Activate the stop and open its ColorPicker |
|
|
247
|
+
| Delete / Backspace | Remove the stop (blocked at `minStops`) |
|
|
248
|
+
| Escape | Close the ColorPicker; focus returns to the marker |
|
|
249
|
+
|
|
250
|
+
## Theme
|
|
251
|
+
|
|
252
|
+
- The panel background comes from the `layer/float` colour token (`theme.colors.layer.float`) so it reads as a floating surface in both light and dark mode, matching ColorPicker.
|
|
253
|
+
- Corner radius comes from `theme.shape.contextMenu.lg.borderRadius`.
|
|
254
|
+
- Stop markers use `theme.colors.background.primary` for their ring so the stop colour stays legible against any track fill.
|
|
255
|
+
|
|
256
|
+
## Accessibility
|
|
257
|
+
|
|
258
|
+
- Each stop marker is a `role="slider"` with `aria-label="Stop N position"`, `aria-valuenow`, `aria-valuemin="0"`, `aria-valuemax="100"` and `aria-valuetext="N%"`.
|
|
259
|
+
- The preview track is `aria-hidden="true"` and is not focusable — position is always available numerically from the per-stop position field and the marker's `aria-valuetext`.
|
|
260
|
+
- The **+** button is the keyboard-accessible alternative to clicking the track; it drops the new stop in the widest gap.
|
|
261
|
+
- Closing the ColorPicker (Escape) returns focus to the marker that opened it.
|
|
262
|
+
- The angle field and every per-stop field carry an explicit `aria-label`.
|
|
263
|
+
|
|
264
|
+
## Known gaps
|
|
265
|
+
|
|
266
|
+
These are deliberate v1 boundaries, tracked as follow-ups:
|
|
267
|
+
|
|
268
|
+
- **Type selector naming** — `SelectProps` has no `aria-label`, so the accessible
|
|
269
|
+
name for the gradient-type selector is carried by a wrapping
|
|
270
|
+
`role="group"` element. Once Select accepts `aria-label`, move it onto the
|
|
271
|
+
combobox itself.
|
|
272
|
+
- **ColorPicker placement** — the active-stop ColorPicker renders inline below
|
|
273
|
+
the stop list. The spec's "flip above the track when the panel would leave the
|
|
274
|
+
viewport" behaviour needs a floating-popover layer.
|
|
275
|
+
- **Pointer drag is web-only** — keyboard operation works everywhere; marker
|
|
276
|
+
dragging uses web mouse events. React Native `PanResponder` parity is a
|
|
277
|
+
follow-up, matching the approach `Slider` takes.
|
|
278
|
+
- **Radial centre point / angular start point** are not exposed. They are not in
|
|
279
|
+
the Figma component; the behaviour spec lists them as part of a fuller
|
|
280
|
+
implementation.
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { ThemeOverrideProps } from '@xsolla/xui-core';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Supported gradient geometries.
|
|
6
|
+
*
|
|
7
|
+
* `angular` maps to the CSS `conic-gradient()` function. Some products call
|
|
8
|
+
* this "Conic" — use `typeLabels` to relabel it without changing the value.
|
|
9
|
+
*/
|
|
10
|
+
type GradientType = "linear" | "radial" | "angular";
|
|
11
|
+
/**
|
|
12
|
+
* A single colour stop on the gradient track.
|
|
13
|
+
*/
|
|
14
|
+
interface GradientStop {
|
|
15
|
+
/**
|
|
16
|
+
* Stable identity for the stop. Used as the React key and as the handle for
|
|
17
|
+
* update / remove operations, so it must survive reordering.
|
|
18
|
+
*/
|
|
19
|
+
id: string;
|
|
20
|
+
/**
|
|
21
|
+
* Stop colour as a `#RRGGBB` hex string. Opacity is tracked separately in
|
|
22
|
+
* `opacity` so the hex field stays human-editable.
|
|
23
|
+
*/
|
|
24
|
+
color: string;
|
|
25
|
+
/**
|
|
26
|
+
* Position along the track, `0`–`100` (percent).
|
|
27
|
+
*/
|
|
28
|
+
position: number;
|
|
29
|
+
/**
|
|
30
|
+
* Stop opacity, `0`–`100` (percent).
|
|
31
|
+
*/
|
|
32
|
+
opacity: number;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* The full gradient definition rendered by the picker.
|
|
36
|
+
*/
|
|
37
|
+
interface GradientValue {
|
|
38
|
+
/**
|
|
39
|
+
* Gradient geometry.
|
|
40
|
+
*/
|
|
41
|
+
type: GradientType;
|
|
42
|
+
/**
|
|
43
|
+
* Rotation in degrees. Only meaningful for `linear` and `angular` — a radial
|
|
44
|
+
* gradient has no angle, so the angle field is hidden for it.
|
|
45
|
+
*/
|
|
46
|
+
angle: number;
|
|
47
|
+
/**
|
|
48
|
+
* Colour stops. Order is not significant: the component sorts by `position`
|
|
49
|
+
* when serialising, so stops may swap as the user drags them past each other.
|
|
50
|
+
*/
|
|
51
|
+
stops: GradientStop[];
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Payload emitted on every gradient change.
|
|
55
|
+
*/
|
|
56
|
+
interface GradientPickerChangeEvent {
|
|
57
|
+
/**
|
|
58
|
+
* The new gradient definition.
|
|
59
|
+
*/
|
|
60
|
+
value: GradientValue;
|
|
61
|
+
/**
|
|
62
|
+
* The same gradient serialised as a CSS-compatible string, ready to drop into
|
|
63
|
+
* a `background` / `background-image` declaration.
|
|
64
|
+
*/
|
|
65
|
+
css: string;
|
|
66
|
+
}
|
|
67
|
+
interface GradientPickerProps extends ThemeOverrideProps {
|
|
68
|
+
/**
|
|
69
|
+
* Controlled gradient value. Pair with `onChange`.
|
|
70
|
+
*/
|
|
71
|
+
value?: GradientValue;
|
|
72
|
+
/**
|
|
73
|
+
* Initial gradient value for uncontrolled usage.
|
|
74
|
+
*/
|
|
75
|
+
defaultValue?: GradientValue;
|
|
76
|
+
/**
|
|
77
|
+
* Called on every interaction — stop drag, colour edit, opacity edit,
|
|
78
|
+
* gradient-type switch, angle change, add / remove stop.
|
|
79
|
+
*/
|
|
80
|
+
onChange?: (event: GradientPickerChangeEvent) => void;
|
|
81
|
+
/**
|
|
82
|
+
* Gradient types offered in the type selector, in display order.
|
|
83
|
+
* @default ["linear", "radial", "angular"]
|
|
84
|
+
*/
|
|
85
|
+
gradientTypes?: GradientType[];
|
|
86
|
+
/**
|
|
87
|
+
* Overrides for the gradient-type option labels — e.g. `{ angular: "Conic gradient" }`
|
|
88
|
+
* when the product uses the CSS term.
|
|
89
|
+
*/
|
|
90
|
+
typeLabels?: Partial<Record<GradientType, string>>;
|
|
91
|
+
/**
|
|
92
|
+
* Smallest number of stops the user may reduce the gradient to. The remove
|
|
93
|
+
* control is disabled once this floor is reached.
|
|
94
|
+
* @default 1
|
|
95
|
+
*/
|
|
96
|
+
minStops?: number;
|
|
97
|
+
/**
|
|
98
|
+
* Largest number of stops the user may add. The add control is disabled once
|
|
99
|
+
* this ceiling is reached.
|
|
100
|
+
* @default 5
|
|
101
|
+
*/
|
|
102
|
+
maxStops?: number;
|
|
103
|
+
/**
|
|
104
|
+
* Disables every control and blocks track interaction.
|
|
105
|
+
*/
|
|
106
|
+
disabled?: boolean;
|
|
107
|
+
/**
|
|
108
|
+
* Accessible label for the gradient-type selector.
|
|
109
|
+
* @default "Gradient type"
|
|
110
|
+
*/
|
|
111
|
+
typeAriaLabel?: string;
|
|
112
|
+
/**
|
|
113
|
+
* Accessible label for the angle field.
|
|
114
|
+
* @default "Gradient angle"
|
|
115
|
+
*/
|
|
116
|
+
angleAriaLabel?: string;
|
|
117
|
+
/**
|
|
118
|
+
* Heading rendered above the stop list.
|
|
119
|
+
* @default "Stops"
|
|
120
|
+
*/
|
|
121
|
+
stopsLabel?: string;
|
|
122
|
+
testID?: string;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* A compound control for defining a CSS gradient.
|
|
127
|
+
*
|
|
128
|
+
* Combines a live preview track carrying draggable stop markers with a per-stop
|
|
129
|
+
* row editor (position, colour, opacity) and an integrated `ColorPicker` for
|
|
130
|
+
* the active stop. Supports linear, radial and angular (CSS `conic`) gradients
|
|
131
|
+
* and 1–5 colour stops.
|
|
132
|
+
*
|
|
133
|
+
* Every interaction updates the preview immediately — there is no confirm step —
|
|
134
|
+
* and the gradient is emitted both as structured data and as a ready-to-apply
|
|
135
|
+
* CSS string.
|
|
136
|
+
*
|
|
137
|
+
* @example
|
|
138
|
+
* ```tsx
|
|
139
|
+
* const [gradient, setGradient] = useState<GradientValue>();
|
|
140
|
+
*
|
|
141
|
+
* <GradientPicker
|
|
142
|
+
* value={gradient}
|
|
143
|
+
* onChange={({ value, css }) => {
|
|
144
|
+
* setGradient(value);
|
|
145
|
+
* setBackground(css); // e.g. "linear-gradient(0deg, #D9D9D9 0%, #22A8C3 100%)"
|
|
146
|
+
* }}
|
|
147
|
+
* />
|
|
148
|
+
* ```
|
|
149
|
+
*/
|
|
150
|
+
declare const GradientPicker: React.FC<GradientPickerProps>;
|
|
151
|
+
|
|
152
|
+
interface GradientStopMarkerProps extends ThemeOverrideProps {
|
|
153
|
+
/**
|
|
154
|
+
* The stop this marker represents.
|
|
155
|
+
*/
|
|
156
|
+
stop: GradientStop;
|
|
157
|
+
/**
|
|
158
|
+
* 1-based index used to build the accessible name (`"Stop 2 position"`).
|
|
159
|
+
*/
|
|
160
|
+
index: number;
|
|
161
|
+
/**
|
|
162
|
+
* Whether this stop is the one currently being edited in the ColorPicker.
|
|
163
|
+
*/
|
|
164
|
+
active?: boolean;
|
|
165
|
+
/**
|
|
166
|
+
* Whether the whole picker is disabled.
|
|
167
|
+
*/
|
|
168
|
+
disabled?: boolean;
|
|
169
|
+
/**
|
|
170
|
+
* Pointer-down on the marker — the parent owns the drag because it owns the
|
|
171
|
+
* track geometry.
|
|
172
|
+
*/
|
|
173
|
+
onDragStart?: (event: React.MouseEvent) => void;
|
|
174
|
+
/**
|
|
175
|
+
* Keyboard interaction on the marker. Handled by the parent so that arrow
|
|
176
|
+
* keys, Home/End, Enter/Space and Delete/Backspace share one implementation.
|
|
177
|
+
*/
|
|
178
|
+
onKeyDown?: (event: React.KeyboardEvent) => void;
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* A single draggable handle on the gradient preview track.
|
|
182
|
+
*
|
|
183
|
+
* Exposed as `role="slider"` over the `0`–`100` position range so the stop can
|
|
184
|
+
* be moved with the keyboard alone, and so its numeric position is announced —
|
|
185
|
+
* the visual gradient must never be the only carrier of that information.
|
|
186
|
+
*/
|
|
187
|
+
declare const GradientStopMarker: React.FC<GradientStopMarkerProps>;
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Returns the stops ordered by position without mutating the input array.
|
|
191
|
+
* Ties keep their original relative order, so two stops parked on the same
|
|
192
|
+
* percent do not flicker while one of them is being dragged.
|
|
193
|
+
*/
|
|
194
|
+
declare const sortStops: (stops: GradientStop[]) => GradientStop[];
|
|
195
|
+
/**
|
|
196
|
+
* Serialises the gradient to a CSS-compatible string usable as a `background`
|
|
197
|
+
* or `background-image` value.
|
|
198
|
+
*/
|
|
199
|
+
declare const toCssGradient: (value: GradientValue) => string;
|
|
200
|
+
/**
|
|
201
|
+
* The gradient rendered inside the horizontal preview track. The track always
|
|
202
|
+
* reads left-to-right regardless of gradient type, so the user can see stop
|
|
203
|
+
* ordering while dragging — the type-specific rendering is what `toCssGradient`
|
|
204
|
+
* produces for the consuming surface.
|
|
205
|
+
*/
|
|
206
|
+
declare const toPreviewCssGradient: (value: GradientValue) => string;
|
|
207
|
+
/**
|
|
208
|
+
* Whether the given gradient type exposes an angle control. Radial gradients
|
|
209
|
+
* have no rotation, so the angle field is hidden for them.
|
|
210
|
+
*/
|
|
211
|
+
declare const supportsAngle: (value: GradientValue["type"]) => boolean;
|
|
212
|
+
/**
|
|
213
|
+
* Samples the gradient at `position` (`0`–`100`) and returns the interpolated
|
|
214
|
+
* colour + opacity. Used to give a newly added stop the colour the gradient
|
|
215
|
+
* already had at that point, so adding a stop never visibly changes the ramp.
|
|
216
|
+
*/
|
|
217
|
+
declare const interpolateColorAt: (stops: GradientStop[], position: number) => {
|
|
218
|
+
color: string;
|
|
219
|
+
opacity: number;
|
|
220
|
+
};
|
|
221
|
+
/**
|
|
222
|
+
* Adds a stop at `position`, taking its colour from the gradient at that point.
|
|
223
|
+
* Returns the original array untouched when `maxStops` is already reached, so
|
|
224
|
+
* callers can compare by reference to detect a no-op.
|
|
225
|
+
*/
|
|
226
|
+
declare const addStopAt: (stops: GradientStop[], position: number, maxStops: number) => GradientStop[];
|
|
227
|
+
/**
|
|
228
|
+
* Removes a stop by id. Returns the original array when the removal would drop
|
|
229
|
+
* below `minStops`, or when the id is unknown.
|
|
230
|
+
*/
|
|
231
|
+
declare const removeStop: (stops: GradientStop[], id: string, minStops: number) => GradientStop[];
|
|
232
|
+
/**
|
|
233
|
+
* Applies a partial update to a single stop, clamping position and opacity and
|
|
234
|
+
* normalising the hex colour.
|
|
235
|
+
*/
|
|
236
|
+
declare const updateStop: (stops: GradientStop[], id: string, patch: Partial<Omit<GradientStop, "id">>) => GradientStop[];
|
|
237
|
+
/**
|
|
238
|
+
* The default gradient — the two-stop `#D9D9D9 → #22A8C3` linear ramp from the
|
|
239
|
+
* Figma component.
|
|
240
|
+
*/
|
|
241
|
+
declare const DEFAULT_GRADIENT: GradientValue;
|
|
242
|
+
|
|
243
|
+
export { DEFAULT_GRADIENT, GradientPicker, type GradientPickerChangeEvent, type GradientPickerProps, type GradientStop, GradientStopMarker, type GradientStopMarkerProps, type GradientType, type GradientValue, addStopAt, interpolateColorAt, removeStop, sortStops, supportsAngle, toCssGradient, toPreviewCssGradient, updateStop };
|