panelui-native 0.99.0 → 0.101.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 +2 -0
- package/lib/module/components/animated-badge/index.js +24 -2
- package/lib/module/components/animated-badge/index.js.map +1 -1
- package/lib/module/components/bump-chart/index.js +1236 -0
- package/lib/module/components/bump-chart/index.js.map +1 -0
- package/lib/module/components/compare/index.js +576 -0
- package/lib/module/components/compare/index.js.map +1 -0
- package/lib/module/components/mirror-area-chart/index.js +1113 -0
- package/lib/module/components/mirror-area-chart/index.js.map +1 -0
- package/lib/module/components/sankey-chart/index.js +933 -0
- package/lib/module/components/sankey-chart/index.js.map +1 -0
- package/lib/module/components/sankey-chart/sankey-layout.js +530 -0
- package/lib/module/components/sankey-chart/sankey-layout.js.map +1 -0
- package/lib/module/icons/index.js +15 -3
- package/lib/module/icons/index.js.map +1 -1
- package/lib/module/index.js +4 -0
- package/lib/module/index.js.map +1 -1
- package/lib/module/utils/chart.js +101 -0
- package/lib/module/utils/chart.js.map +1 -1
- package/lib/typescript/src/components/animated-badge/index.d.ts +5 -0
- package/lib/typescript/src/components/animated-badge/index.d.ts.map +1 -1
- package/lib/typescript/src/components/bump-chart/index.d.ts +267 -0
- package/lib/typescript/src/components/bump-chart/index.d.ts.map +1 -0
- package/lib/typescript/src/components/compare/index.d.ts +183 -0
- package/lib/typescript/src/components/compare/index.d.ts.map +1 -0
- package/lib/typescript/src/components/mirror-area-chart/index.d.ts +263 -0
- package/lib/typescript/src/components/mirror-area-chart/index.d.ts.map +1 -0
- package/lib/typescript/src/components/sankey-chart/index.d.ts +307 -0
- package/lib/typescript/src/components/sankey-chart/index.d.ts.map +1 -0
- package/lib/typescript/src/components/sankey-chart/sankey-layout.d.ts +107 -0
- package/lib/typescript/src/components/sankey-chart/sankey-layout.d.ts.map +1 -0
- package/lib/typescript/src/icons/index.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +4 -0
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/utils/chart.d.ts +40 -0
- package/lib/typescript/src/utils/chart.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/components/animated-badge/index.tsx +35 -2
- package/src/components/bump-chart/index.tsx +1455 -0
- package/src/components/compare/index.tsx +650 -0
- package/src/components/mirror-area-chart/index.tsx +1333 -0
- package/src/components/sankey-chart/index.tsx +1165 -0
- package/src/components/sankey-chart/sankey-layout.ts +645 -0
- package/src/icons/index.tsx +20 -6
- package/src/index.ts +62 -0
- package/src/utils/chart.ts +116 -0
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BumpChart — how a set of things ranked against each other over time.
|
|
3
|
+
*
|
|
4
|
+
* ```tsx
|
|
5
|
+
* <BumpChart data={standings} xDataKey="week" defaultHighlight="harbour">
|
|
6
|
+
* <BumpChart.Grid />
|
|
7
|
+
* <BumpChart.Line dataKey="harbour" label="Harbour" />
|
|
8
|
+
* <BumpChart.Line dataKey="northside" label="Northside" />
|
|
9
|
+
* <BumpChart.YAxis />
|
|
10
|
+
* <BumpChart.XAxis />
|
|
11
|
+
* <BumpChart.Labels />
|
|
12
|
+
* <BumpChart.Tooltip />
|
|
13
|
+
* </BumpChart>
|
|
14
|
+
* ```
|
|
15
|
+
*
|
|
16
|
+
* ## Positions, not values
|
|
17
|
+
*
|
|
18
|
+
* The y-axis is the rank, so the rows are evenly spaced whatever the gap
|
|
19
|
+
* between the underlying scores. That is the point of the chart: who passed
|
|
20
|
+
* whom, and when. A line chart of the same scores answers how far apart they
|
|
21
|
+
* were, and loses the order wherever two lines run close together.
|
|
22
|
+
*
|
|
23
|
+
* Pass the ranks directly, or pass the scores with `values="score"` and each
|
|
24
|
+
* column is ranked for you, highest first. `bumpRanks` is exported so a header
|
|
25
|
+
* or a table beside the chart can read the same order the chart drew.
|
|
26
|
+
*
|
|
27
|
+
* ## One line at a time
|
|
28
|
+
*
|
|
29
|
+
* Past three or four series, every line in its own colour is a tangle. The
|
|
30
|
+
* chart reads best with one line picked out: `highlight` draws that one in its
|
|
31
|
+
* colour and on top, and the rest in a muted grey. Tapping a name in
|
|
32
|
+
* `BumpChart.Labels` picks that line, and tapping it again clears it.
|
|
33
|
+
*/
|
|
34
|
+
import { type ReactNode } from 'react';
|
|
35
|
+
import { type ViewProps } from 'react-native';
|
|
36
|
+
import { type ChartAccessibilityProps } from '../../primitives/chart-accessibility.js';
|
|
37
|
+
import { type SeriesColorIndex } from '../../utils/chart.js';
|
|
38
|
+
type Layer = 'svg' | 'series' | 'overlay' | 'header';
|
|
39
|
+
export type BumpChartStatus = 'loading' | 'ready';
|
|
40
|
+
export type BumpChartDatum = Record<string, string | number | null | undefined>;
|
|
41
|
+
/** Ranks per series key, one entry per row. `null` where a series has none. */
|
|
42
|
+
export type BumpRanks = Record<string, (number | null)[]>;
|
|
43
|
+
/**
|
|
44
|
+
* Each series' rank in every row.
|
|
45
|
+
*
|
|
46
|
+
* With `values: 'rank'` the rows already hold ranks and they are only
|
|
47
|
+
* validated. With `values: 'score'` each row is ranked highest first; a tie
|
|
48
|
+
* keeps the order the keys are passed in, so two equal scores never draw on
|
|
49
|
+
* top of each other.
|
|
50
|
+
*/
|
|
51
|
+
export declare function bumpRanks(data: BumpChartDatum[], keys: string[], options?: {
|
|
52
|
+
values?: 'rank' | 'score';
|
|
53
|
+
}): BumpRanks;
|
|
54
|
+
/** The row under the scrub, and which line is picked out. */
|
|
55
|
+
export declare function useBumpChart(): {
|
|
56
|
+
activeIndex: number;
|
|
57
|
+
activePoint: BumpChartDatum | null;
|
|
58
|
+
xDataKey: string;
|
|
59
|
+
ranks: BumpRanks;
|
|
60
|
+
highlight: string | null;
|
|
61
|
+
setHighlight: (key: string | null) => void;
|
|
62
|
+
};
|
|
63
|
+
export interface BumpChartProps extends ViewProps, ChartAccessibilityProps<BumpChartDatum> {
|
|
64
|
+
className?: string;
|
|
65
|
+
/** The rows. Each one is a column: a week, a round, a release. */
|
|
66
|
+
data: BumpChartDatum[];
|
|
67
|
+
/** Key holding the column's label. */
|
|
68
|
+
xDataKey?: string;
|
|
69
|
+
/**
|
|
70
|
+
* What the series columns hold. `rank` (the default) takes them as places,
|
|
71
|
+
* `1` at the top. `score` ranks every row for you, highest first.
|
|
72
|
+
*/
|
|
73
|
+
values?: 'rank' | 'score';
|
|
74
|
+
/**
|
|
75
|
+
* The series drawn in its colour and on top, with the rest muted. `null`
|
|
76
|
+
* picks none, and every line keeps its own colour. Controlled — pair it with
|
|
77
|
+
* `onHighlightChange`.
|
|
78
|
+
*/
|
|
79
|
+
highlight?: string | null;
|
|
80
|
+
/** The series picked out on first render, when `highlight` is not passed. */
|
|
81
|
+
defaultHighlight?: string | null;
|
|
82
|
+
/** Called when a name in `BumpChart.Labels` is tapped. */
|
|
83
|
+
onHighlightChange?: (key: string | null) => void;
|
|
84
|
+
/**
|
|
85
|
+
* `loading` hides the lines and shows `BumpChart.Skeleton` if there is one.
|
|
86
|
+
* The lines are revealed when it turns `ready`.
|
|
87
|
+
*/
|
|
88
|
+
status?: BumpChartStatus;
|
|
89
|
+
/** Width ÷ height. */
|
|
90
|
+
aspectRatio?: number;
|
|
91
|
+
/** Milliseconds for the reveal on mount. */
|
|
92
|
+
animationDuration?: number;
|
|
93
|
+
/** Milliseconds for the lines to move to new places when the data changes. */
|
|
94
|
+
morphDuration?: number;
|
|
95
|
+
/**
|
|
96
|
+
* The column under the scrub as it moves, and `-1`/`null` when it lifts.
|
|
97
|
+
* Fires when the index changes, not per frame.
|
|
98
|
+
*/
|
|
99
|
+
onActiveIndexChange?: (index: number, datum: BumpChartDatum | null) => void;
|
|
100
|
+
/** Drop the axis padding, for a chart with no axes. */
|
|
101
|
+
compact?: boolean;
|
|
102
|
+
children?: ReactNode;
|
|
103
|
+
}
|
|
104
|
+
/** Imperative handle: re-run the reveal on demand, for a "replay" control. */
|
|
105
|
+
export interface BumpChartHandle {
|
|
106
|
+
replay: () => void;
|
|
107
|
+
}
|
|
108
|
+
export interface BumpChartGridProps {
|
|
109
|
+
/** A guide down every column. */
|
|
110
|
+
vertical?: boolean;
|
|
111
|
+
/** A guide across every rank. */
|
|
112
|
+
horizontal?: boolean;
|
|
113
|
+
color?: string;
|
|
114
|
+
dashArray?: string;
|
|
115
|
+
opacity?: number;
|
|
116
|
+
}
|
|
117
|
+
/** Guides down each column, so a dot can be read against the label below it. */
|
|
118
|
+
declare function BumpChartGrid({ vertical, horizontal, color, dashArray, opacity, }: BumpChartGridProps): import("react").JSX.Element;
|
|
119
|
+
declare namespace BumpChartGrid {
|
|
120
|
+
var displayName: string;
|
|
121
|
+
var layer: Layer;
|
|
122
|
+
}
|
|
123
|
+
export interface BumpChartLineProps {
|
|
124
|
+
/** Column in the data holding this series' rank, or its score with `values="score"`. */
|
|
125
|
+
dataKey: string;
|
|
126
|
+
/** The name shown by `Labels`, the tooltip and the legend. Defaults to `dataKey`. */
|
|
127
|
+
label?: string;
|
|
128
|
+
/** Explicit colour. Defaults to the `--color-chart-*` token for `colorIndex`. */
|
|
129
|
+
color?: string;
|
|
130
|
+
/** Which of the five chart tokens to take. */
|
|
131
|
+
colorIndex?: SeriesColorIndex;
|
|
132
|
+
/** Thickness of the line. The picked-out line is drawn one point thicker. */
|
|
133
|
+
strokeWidth?: number;
|
|
134
|
+
/** Draw a dot at every column. */
|
|
135
|
+
showDots?: boolean;
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* One series. It draws nothing itself: the lines are drawn together, so the
|
|
139
|
+
* one picked out can be drawn last and sit on top of every crossing.
|
|
140
|
+
*/
|
|
141
|
+
declare function BumpChartLine({ dataKey, label, color, colorIndex, strokeWidth, showDots, }: BumpChartLineProps): null;
|
|
142
|
+
declare namespace BumpChartLine {
|
|
143
|
+
var displayName: string;
|
|
144
|
+
var layer: Layer;
|
|
145
|
+
var line: true;
|
|
146
|
+
}
|
|
147
|
+
export interface BumpChartSkeletonProps {
|
|
148
|
+
/** Milliseconds for one pass of the sweep. */
|
|
149
|
+
duration?: number;
|
|
150
|
+
color?: string;
|
|
151
|
+
/** How many rank rows to stand in for. */
|
|
152
|
+
rows?: number;
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* The loading state: a thin bar on every rank row with a highlight travelling
|
|
156
|
+
* across them. Flat, so it says where the lines will be and nothing about
|
|
157
|
+
* where they go.
|
|
158
|
+
*/
|
|
159
|
+
declare function BumpChartSkeleton({ duration, color, rows: rowsProp }: BumpChartSkeletonProps): import("react").JSX.Element | null;
|
|
160
|
+
declare namespace BumpChartSkeleton {
|
|
161
|
+
var displayName: string;
|
|
162
|
+
var layer: Layer;
|
|
163
|
+
}
|
|
164
|
+
export interface BumpChartXAxisProps {
|
|
165
|
+
/** How many columns to label, spread across the run. */
|
|
166
|
+
ticks?: number;
|
|
167
|
+
format?: (datum: BumpChartDatum, index: number) => string;
|
|
168
|
+
className?: string;
|
|
169
|
+
}
|
|
170
|
+
/** The column labels. Real text, so they follow the theme's font and text scaling. */
|
|
171
|
+
declare function BumpChartXAxis({ ticks, format, className }: BumpChartXAxisProps): import("react").JSX.Element;
|
|
172
|
+
declare namespace BumpChartXAxis {
|
|
173
|
+
var displayName: string;
|
|
174
|
+
var layer: Layer;
|
|
175
|
+
}
|
|
176
|
+
export interface BumpChartYAxisProps {
|
|
177
|
+
/** Format a rank. Defaults to `#1`, `#2`… */
|
|
178
|
+
format?: (rank: number) => string;
|
|
179
|
+
className?: string;
|
|
180
|
+
}
|
|
181
|
+
/** The ranks down the side, one on every row. */
|
|
182
|
+
declare function BumpChartYAxis({ format, className }: BumpChartYAxisProps): import("react").JSX.Element;
|
|
183
|
+
declare namespace BumpChartYAxis {
|
|
184
|
+
var displayName: string;
|
|
185
|
+
var layer: Layer;
|
|
186
|
+
var axis: "y";
|
|
187
|
+
}
|
|
188
|
+
export interface BumpChartLabelsProps {
|
|
189
|
+
/** Room kept to the right of the plot for the names. Longer names are cut short. */
|
|
190
|
+
width?: number;
|
|
191
|
+
/** Let a tap on a name pick that line out, and a second tap clear it. */
|
|
192
|
+
pressable?: boolean;
|
|
193
|
+
className?: string;
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Each series' name beside its last point, so the lines can be told apart
|
|
197
|
+
* without a legend to look across to. The names move with their lines when
|
|
198
|
+
* the data changes.
|
|
199
|
+
*/
|
|
200
|
+
declare function BumpChartLabels({ pressable, className }: BumpChartLabelsProps): import("react").JSX.Element | null;
|
|
201
|
+
declare namespace BumpChartLabels {
|
|
202
|
+
var displayName: string;
|
|
203
|
+
var layer: Layer;
|
|
204
|
+
var labels: true;
|
|
205
|
+
}
|
|
206
|
+
export interface BumpChartTooltipProps {
|
|
207
|
+
color?: string;
|
|
208
|
+
/** Format a rank in the readout. Defaults to `#1`, `#2`… */
|
|
209
|
+
formatRank?: (rank: number) => string;
|
|
210
|
+
/** Format the readout's heading from the row. Defaults to the value at xDataKey. */
|
|
211
|
+
formatX?: (datum: BumpChartDatum) => string;
|
|
212
|
+
className?: string;
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* A scrub across the columns, and a readout listing every series in the order
|
|
216
|
+
* it stood at the column under the finger.
|
|
217
|
+
*/
|
|
218
|
+
declare function BumpChartTooltip({ color, formatRank, formatX, className }: BumpChartTooltipProps): import("react").JSX.Element | null;
|
|
219
|
+
declare namespace BumpChartTooltip {
|
|
220
|
+
var displayName: string;
|
|
221
|
+
var layer: Layer;
|
|
222
|
+
}
|
|
223
|
+
export interface BumpChartLegendProps extends ViewProps {
|
|
224
|
+
className?: string;
|
|
225
|
+
}
|
|
226
|
+
/** A swatch and a name per series, in declaration order. */
|
|
227
|
+
declare function BumpChartLegend({ className, ...props }: BumpChartLegendProps): import("react").JSX.Element | null;
|
|
228
|
+
declare namespace BumpChartLegend {
|
|
229
|
+
var displayName: string;
|
|
230
|
+
var layer: Layer;
|
|
231
|
+
}
|
|
232
|
+
export interface BumpChartHeaderProps extends ViewProps {
|
|
233
|
+
className?: string;
|
|
234
|
+
/** Small line above the value — what the chart is of. */
|
|
235
|
+
title?: string;
|
|
236
|
+
/** The readout. The largest thing on the card, and the first thing read. */
|
|
237
|
+
value?: string;
|
|
238
|
+
/** One muted line under the value — a period, a comparison, a total. */
|
|
239
|
+
caption?: string;
|
|
240
|
+
/** Draw a swatch and a name per series along the trailing edge. */
|
|
241
|
+
legend?: boolean;
|
|
242
|
+
/** Trailing slot — a control, a badge, a range picker. Wins over `legend`. */
|
|
243
|
+
children?: ReactNode;
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* The strip above the plot: what the chart is of and what it currently reads.
|
|
247
|
+
* The value is not derived here — pass the formatted string, from
|
|
248
|
+
* `onActiveIndexChange` or `onHighlightChange` if it follows the chart.
|
|
249
|
+
*/
|
|
250
|
+
declare function BumpChartHeader({ className, title, value, caption, legend, children, ...props }: BumpChartHeaderProps): import("react").JSX.Element;
|
|
251
|
+
declare namespace BumpChartHeader {
|
|
252
|
+
var displayName: string;
|
|
253
|
+
var layer: Layer;
|
|
254
|
+
}
|
|
255
|
+
export declare const BumpChart: import("react").ForwardRefExoticComponent<BumpChartProps & import("react").RefAttributes<BumpChartHandle>> & {
|
|
256
|
+
Header: typeof BumpChartHeader;
|
|
257
|
+
Grid: typeof BumpChartGrid;
|
|
258
|
+
Line: typeof BumpChartLine;
|
|
259
|
+
Skeleton: typeof BumpChartSkeleton;
|
|
260
|
+
XAxis: typeof BumpChartXAxis;
|
|
261
|
+
YAxis: typeof BumpChartYAxis;
|
|
262
|
+
Labels: typeof BumpChartLabels;
|
|
263
|
+
Tooltip: typeof BumpChartTooltip;
|
|
264
|
+
Legend: typeof BumpChartLegend;
|
|
265
|
+
};
|
|
266
|
+
export {};
|
|
267
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/components/bump-chart/index.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compare — two versions of one picture, with a seam the reader drags across
|
|
3
|
+
* it.
|
|
4
|
+
*
|
|
5
|
+
* ```tsx
|
|
6
|
+
* <Compare height={260}>
|
|
7
|
+
* <Compare.After>
|
|
8
|
+
* <Image source={retouched} style={{ width: '100%', height: '100%' }} />
|
|
9
|
+
* </Compare.After>
|
|
10
|
+
* <Compare.Before>
|
|
11
|
+
* <Image source={original} style={{ width: '100%', height: '100%' }} />
|
|
12
|
+
* </Compare.Before>
|
|
13
|
+
* <Compare.Handle />
|
|
14
|
+
* </Compare>
|
|
15
|
+
* ```
|
|
16
|
+
*
|
|
17
|
+
* ## What it is for
|
|
18
|
+
*
|
|
19
|
+
* Showing that two images differ, when they differ in a way a pair of
|
|
20
|
+
* thumbnails side by side will not carry. Retouching, a filter, a render at two
|
|
21
|
+
* quality settings, a map at two dates: the change is spread across the frame
|
|
22
|
+
* rather than gathered in one place, and the eye cannot hold one image well
|
|
23
|
+
* enough to spot it in the other.
|
|
24
|
+
*
|
|
25
|
+
* The seam works because both versions are in the same place on the screen at
|
|
26
|
+
* the same scale. Every pixel the reader is comparing is a pixel that was just
|
|
27
|
+
* under the one beside it, so the difference arrives as movement rather than as
|
|
28
|
+
* something to be remembered.
|
|
29
|
+
*
|
|
30
|
+
* ## It clips, it does not resize
|
|
31
|
+
*
|
|
32
|
+
* The revealed side is a window onto a full-size copy of its content, not a
|
|
33
|
+
* copy of the content squeezed into the window. That distinction is the whole
|
|
34
|
+
* implementation: a view whose width is animated will lay its children out
|
|
35
|
+
* again at every new width, so an image inside one is an image being squashed
|
|
36
|
+
* and stretched as the seam moves, and the two halves stop lining up — which
|
|
37
|
+
* is the one thing this component exists to guarantee.
|
|
38
|
+
*
|
|
39
|
+
* It follows that the content has to be told how big to be, and the only thing
|
|
40
|
+
* that knows is the container once it has been measured. So nothing is drawn
|
|
41
|
+
* until the first layout pass has run, and `Compare.Before` sizes its child to
|
|
42
|
+
* the measured box rather than to itself.
|
|
43
|
+
*
|
|
44
|
+
* ## It needs a height
|
|
45
|
+
*
|
|
46
|
+
* Everything inside is positioned absolutely, so the box has no height of its
|
|
47
|
+
* own to take from its content. `height` is what gives it one. An image told to
|
|
48
|
+
* fill the box will fill whatever height is set here, and cropping is
|
|
49
|
+
* `resizeMode` on the image rather than anything this component does.
|
|
50
|
+
*
|
|
51
|
+
* ## Dragging, and the two ways round it
|
|
52
|
+
*
|
|
53
|
+
* The whole frame is the drag target, not just the knob — a knob is a small
|
|
54
|
+
* thing to hit on a phone and the reader's finger is already over the picture.
|
|
55
|
+
* The gesture only claims horizontal movement, so a Compare inside a scrolling
|
|
56
|
+
* page still scrolls.
|
|
57
|
+
*
|
|
58
|
+
* A drag is not available to everyone, so the seam is also `adjustable`: a
|
|
59
|
+
* screen reader moves it a `step` at a time without one, and `value` drives it
|
|
60
|
+
* from anywhere else — a button that snaps to the ends, an animation, a slider
|
|
61
|
+
* somewhere else on the screen.
|
|
62
|
+
*/
|
|
63
|
+
import { type ReactNode } from 'react';
|
|
64
|
+
import { type ViewProps } from 'react-native';
|
|
65
|
+
export type CompareOrientation = 'horizontal' | 'vertical';
|
|
66
|
+
export interface CompareProps extends Omit<ViewProps, 'children'> {
|
|
67
|
+
className?: string;
|
|
68
|
+
/**
|
|
69
|
+
* How tall the frame is, in points.
|
|
70
|
+
*
|
|
71
|
+
* Required in practice rather than in the types: both sides are positioned
|
|
72
|
+
* absolutely, so there is no content left to give the box a height of its own.
|
|
73
|
+
*/
|
|
74
|
+
height?: number;
|
|
75
|
+
/** Where the seam sits, `0` to `1`. Leave unset to let the frame track it. */
|
|
76
|
+
value?: number;
|
|
77
|
+
/** Where it starts when the frame is tracking it itself. */
|
|
78
|
+
defaultValue?: number;
|
|
79
|
+
/** Fires while the seam moves, with its new position. */
|
|
80
|
+
onValueChange?: (value: number) => void;
|
|
81
|
+
/** Fires once, when the finger is lifted. The one to persist. */
|
|
82
|
+
onValueCommit?: (value: number) => void;
|
|
83
|
+
/** Which way the seam runs. */
|
|
84
|
+
orientation?: CompareOrientation;
|
|
85
|
+
/** Freezes the seam where it is and takes it out of the accessibility tree. */
|
|
86
|
+
disabled?: boolean;
|
|
87
|
+
/** How far one screen-reader increment moves the seam, `0` to `1`. */
|
|
88
|
+
step?: number;
|
|
89
|
+
/** A tick when the seam reaches either end. */
|
|
90
|
+
haptics?: boolean;
|
|
91
|
+
children?: ReactNode;
|
|
92
|
+
}
|
|
93
|
+
declare function CompareRoot({ className, height, value, defaultValue, onValueChange, onValueCommit, orientation, disabled, step, haptics, children, ...props }: CompareProps): import("react").JSX.Element;
|
|
94
|
+
declare namespace CompareRoot {
|
|
95
|
+
var displayName: string;
|
|
96
|
+
}
|
|
97
|
+
export interface CompareAfterProps extends ViewProps {
|
|
98
|
+
className?: string;
|
|
99
|
+
children?: ReactNode;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* The side the seam uncovers as it travels: the whole frame, underneath.
|
|
103
|
+
*
|
|
104
|
+
* It is drawn at full size and never clipped, so it is the one that decides
|
|
105
|
+
* what the frame looks like at either end of the travel.
|
|
106
|
+
*/
|
|
107
|
+
declare function CompareAfter({ className, children, ...props }: CompareAfterProps): import("react").JSX.Element;
|
|
108
|
+
declare namespace CompareAfter {
|
|
109
|
+
var displayName: string;
|
|
110
|
+
var layer: "base";
|
|
111
|
+
}
|
|
112
|
+
export interface CompareBeforeProps extends ViewProps {
|
|
113
|
+
className?: string;
|
|
114
|
+
children?: ReactNode;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* The side on the near edge of the seam: a window onto the content, sized to
|
|
118
|
+
* the frame.
|
|
119
|
+
*
|
|
120
|
+
* The child is given the frame's measured size in points rather than a
|
|
121
|
+
* percentage. A percentage would be a percentage *of the window*, which shrinks
|
|
122
|
+
* as the seam closes — so the image would slide and scale under the seam
|
|
123
|
+
* instead of standing still behind it, and the two halves would no longer be
|
|
124
|
+
* the same picture in the same place.
|
|
125
|
+
*/
|
|
126
|
+
declare function CompareBefore({ className, children, ...props }: CompareBeforeProps): import("react").JSX.Element;
|
|
127
|
+
declare namespace CompareBefore {
|
|
128
|
+
var displayName: string;
|
|
129
|
+
var layer: "clip";
|
|
130
|
+
}
|
|
131
|
+
export interface CompareHandleProps extends ViewProps {
|
|
132
|
+
className?: string;
|
|
133
|
+
/** Hide the two grip bars inside the knob. */
|
|
134
|
+
withGrip?: boolean;
|
|
135
|
+
/** Spoken name. */
|
|
136
|
+
accessibilityLabel?: string;
|
|
137
|
+
/** Replaces the knob. The line behind it is kept. */
|
|
138
|
+
children?: ReactNode;
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* The seam: a line across the frame with a knob on it.
|
|
142
|
+
*
|
|
143
|
+
* The knob is a marker rather than the target — the drag is on the whole frame,
|
|
144
|
+
* and a 36-point circle is not something to ask a thumb to find. What it is
|
|
145
|
+
* for is saying where the seam is and that it is the thing that moves, which a
|
|
146
|
+
* bare line does not.
|
|
147
|
+
*
|
|
148
|
+
* It carries the accessibility wiring for the same reason a splitter's handle
|
|
149
|
+
* does: it is the one part of this that is a control, so it is the part that is
|
|
150
|
+
* `adjustable` and takes the increment and decrement a screen reader sends
|
|
151
|
+
* instead of a drag.
|
|
152
|
+
*/
|
|
153
|
+
declare function CompareHandle({ className, withGrip, accessibilityLabel, children, style, ...props }: CompareHandleProps): import("react").JSX.Element;
|
|
154
|
+
declare namespace CompareHandle {
|
|
155
|
+
var displayName: string;
|
|
156
|
+
var layer: "over";
|
|
157
|
+
}
|
|
158
|
+
export interface CompareLabelProps extends ViewProps {
|
|
159
|
+
className?: string;
|
|
160
|
+
/** Which side of the frame it sits on. */
|
|
161
|
+
side?: 'start' | 'end';
|
|
162
|
+
children?: ReactNode;
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* A caption pinned to one corner, for saying which side is which.
|
|
166
|
+
*
|
|
167
|
+
* Worth adding wherever the two versions are not obviously an original and an
|
|
168
|
+
* edit — two dates, two settings, two models. Where they are, it is one more
|
|
169
|
+
* thing over the picture and the picture is the point.
|
|
170
|
+
*/
|
|
171
|
+
declare function CompareLabel({ className, side, children, ...props }: CompareLabelProps): import("react").JSX.Element;
|
|
172
|
+
declare namespace CompareLabel {
|
|
173
|
+
var displayName: string;
|
|
174
|
+
var layer: "over";
|
|
175
|
+
}
|
|
176
|
+
export declare const Compare: typeof CompareRoot & {
|
|
177
|
+
Before: typeof CompareBefore;
|
|
178
|
+
After: typeof CompareAfter;
|
|
179
|
+
Handle: typeof CompareHandle;
|
|
180
|
+
Label: typeof CompareLabel;
|
|
181
|
+
};
|
|
182
|
+
export {};
|
|
183
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/components/compare/index.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6DG;AACH,OAAO,EASL,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AACf,OAAO,EAIL,KAAK,SAAS,EACf,MAAM,cAAc,CAAC;AAkCtB,MAAM,MAAM,kBAAkB,GAAG,YAAY,GAAG,UAAU,CAAC;AA4D3D,MAAM,WAAW,YAAa,SAAQ,IAAI,CAAC,SAAS,EAAE,UAAU,CAAC;IAC/D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;;OAKG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,8EAA8E;IAC9E,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,4DAA4D;IAC5D,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,yDAAyD;IACzD,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,iEAAiE;IACjE,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,+BAA+B;IAC/B,WAAW,CAAC,EAAE,kBAAkB,CAAC;IACjC,+EAA+E;IAC/E,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,sEAAsE;IACtE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,+CAA+C;IAC/C,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAED,iBAAS,WAAW,CAAC,EACnB,SAAS,EACT,MAAuB,EACvB,KAAK,EACL,YAA4B,EAC5B,aAAa,EACb,aAAa,EACb,WAA0B,EAC1B,QAAgB,EAChB,IAAmB,EACnB,OAAc,EACd,QAAQ,EACR,GAAG,KAAK,EACT,EAAE,YAAY,+BAiMd;kBA9MQ,WAAW;;;AAoNpB,MAAM,WAAW,iBAAkB,SAAQ,SAAS;IAClD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAED;;;;;GAKG;AACH,iBAAS,YAAY,CAAC,EAAE,SAAS,EAAE,QAAQ,EAAE,GAAG,KAAK,EAAE,EAAE,iBAAiB,+BAazE;kBAbQ,YAAY;;;;AAiBrB,MAAM,WAAW,kBAAmB,SAAQ,SAAS;IACnD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAED;;;;;;;;;GASG;AACH,iBAAS,aAAa,CAAC,EAAE,SAAS,EAAE,QAAQ,EAAE,GAAG,KAAK,EAAE,EAAE,kBAAkB,+BAgC3E;kBAhCQ,aAAa;;;;AAoCtB,MAAM,WAAW,kBAAmB,SAAQ,SAAS;IACnD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,8CAA8C;IAC9C,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,mBAAmB;IACnB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,qDAAqD;IACrD,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAED;;;;;;;;;;;;GAYG;AACH,iBAAS,aAAa,CAAC,EACrB,SAAS,EACT,QAAe,EACf,kBAA8B,EAC9B,QAAQ,EACR,KAAK,EACL,GAAG,KAAK,EACT,EAAE,kBAAkB,+BAqEpB;kBA5EQ,aAAa;;;;AAgFtB,MAAM,WAAW,iBAAkB,SAAQ,SAAS;IAClD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,0CAA0C;IAC1C,IAAI,CAAC,EAAE,OAAO,GAAG,KAAK,CAAC;IACvB,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAED;;;;;;GAMG;AACH,iBAAS,YAAY,CAAC,EAAE,SAAS,EAAE,IAAc,EAAE,QAAQ,EAAE,GAAG,KAAK,EAAE,EAAE,iBAAiB,+BA8BzF;kBA9BQ,YAAY;;;;AAoCrB,eAAO,MAAM,OAAO;;;;;CAKlB,CAAC"}
|