@data-profile/fingerprint 0.0.0-stage → 0.2.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/CHANGELOG.md +19 -0
- package/LICENSE +21 -0
- package/README.md +345 -2
- package/dist/chunk-eygy4k4w.js +669 -0
- package/dist/chunk-eygy4k4w.js.map +18 -0
- package/dist/index.d.ts +350 -0
- package/dist/index.js +25 -0
- package/dist/index.js.map +9 -0
- package/dist/react/index.d.ts +300 -0
- package/dist/react/index.js +632 -0
- package/dist/react/index.js.map +13 -0
- package/dist/styles.css +117 -0
- package/package.json +72 -4
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@data-profile/fingerprint/react`: the canvas, legends, list and view switch, the
|
|
3
|
+
* `useFingerprint` hook that wires them together, and the built-in renderers.
|
|
4
|
+
*
|
|
5
|
+
* @packageDocumentation
|
|
6
|
+
* @module react
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type { FingerprintAnnotation } from '@data-profile/fingerprint';
|
|
10
|
+
import { FingerprintDataError } from '@data-profile/fingerprint';
|
|
11
|
+
import type { FingerprintDimension } from '@data-profile/fingerprint';
|
|
12
|
+
import type { FingerprintEncoding } from '@data-profile/fingerprint';
|
|
13
|
+
import type { FingerprintForm } from '@data-profile/fingerprint';
|
|
14
|
+
import type { FingerprintItem } from '@data-profile/fingerprint';
|
|
15
|
+
import type { FingerprintLayout } from '@data-profile/fingerprint';
|
|
16
|
+
import type { FingerprintLegendGroup } from '@data-profile/fingerprint';
|
|
17
|
+
import type { FingerprintNode } from '@data-profile/fingerprint';
|
|
18
|
+
import { JSX } from 'react';
|
|
19
|
+
import { markOpacity } from '@data-profile/fingerprint';
|
|
20
|
+
import type { ReactNode } from 'react';
|
|
21
|
+
import type { RidgeStyle } from '@data-profile/fingerprint';
|
|
22
|
+
|
|
23
|
+
/** Every mark a dot, shape ignored. Only for when shape must carry nothing. */
|
|
24
|
+
export declare const dotsRenderer: FingerprintRenderer;
|
|
25
|
+
|
|
26
|
+
/** Where callouts go. */
|
|
27
|
+
export declare interface FingerprintCallouts {
|
|
28
|
+
/** `auto` (the default) puts them beside the print when there is room and numbered below it when not. */
|
|
29
|
+
placement?: "auto" | "beside" | "below";
|
|
30
|
+
/** Below this container width, `auto` puts callouts below. Defaults to 640 px. */
|
|
31
|
+
breakpoint?: number;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* The fingerprint itself: ridges, one mark per laid-out node drawn by `renderer`, and optional
|
|
36
|
+
* callouts. Marks move to their new places when the layout's view changes (instantly under reduced
|
|
37
|
+
* motion), and marks outside a selection dim. Both are CSS: a selection re-renders no marks. The SVG is one image to assistive technology, named and described by `title` and
|
|
38
|
+
* `description`; choosing a category is done from the legend or list, which are keyboard
|
|
39
|
+
* reachable, and also by pointer on a mark.
|
|
40
|
+
*/
|
|
41
|
+
export declare function FingerprintCanvas({ layout, title, description, renderer, ridges, selected, onSelect, annotations, callouts, unit, motion, className, }: FingerprintCanvasProps): JSX.Element;
|
|
42
|
+
|
|
43
|
+
/** Props for `FingerprintCanvas`, ready to spread; add a `title`. */
|
|
44
|
+
export declare interface FingerprintCanvasBinding {
|
|
45
|
+
/** The current view's layout. */
|
|
46
|
+
layout: FingerprintLayout;
|
|
47
|
+
/** `describeLayout`'s summary of it, or the data error's message. */
|
|
48
|
+
description: string;
|
|
49
|
+
/** The current selection. */
|
|
50
|
+
selected: FingerprintSelection | null;
|
|
51
|
+
/** Updates the selection. */
|
|
52
|
+
onSelect: (selection: FingerprintSelection | null) => void;
|
|
53
|
+
/** What one item is. */
|
|
54
|
+
unit: string;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** Props of `FingerprintCanvas`. `useFingerprint`'s `canvasProps` supplies most of them. */
|
|
58
|
+
export declare interface FingerprintCanvasProps {
|
|
59
|
+
/** What to draw: from `useFingerprint` (`canvasProps`) or `layoutFingerprint`. */
|
|
60
|
+
layout: FingerprintLayout;
|
|
61
|
+
/** The drawing's accessible name. */
|
|
62
|
+
title: string;
|
|
63
|
+
/** What it shows, in words (`describeLayout` writes one). */
|
|
64
|
+
description: string;
|
|
65
|
+
/** Draws each mark. Defaults to `shapesRenderer`. */
|
|
66
|
+
renderer?: FingerprintRenderer;
|
|
67
|
+
/** How the ridges behind the marks are drawn. Defaults to `{ show: "auto" }`. */
|
|
68
|
+
ridges?: RidgeStyle;
|
|
69
|
+
/** Marks in this category of this dimension are highlighted, the rest dimmed. */
|
|
70
|
+
selected?: FingerprintSelection | null;
|
|
71
|
+
/**
|
|
72
|
+
* Called when a mark is clicked, with its category in the arranging dimension, or null when that
|
|
73
|
+
* is already the selection.
|
|
74
|
+
*/
|
|
75
|
+
onSelect?: (selection: FingerprintSelection | null) => void;
|
|
76
|
+
/** Notes pinned to the print, each with a leader to a mark of the categories it names. */
|
|
77
|
+
annotations?: readonly FingerprintAnnotation[];
|
|
78
|
+
/** Where the annotations go. See `FingerprintCallouts`. */
|
|
79
|
+
callouts?: FingerprintCallouts;
|
|
80
|
+
/** Names what one item is, for the selection announcement. Defaults to "items". */
|
|
81
|
+
unit?: string;
|
|
82
|
+
/** How marks move when the view changes. See `FingerprintMotion`. */
|
|
83
|
+
motion?: FingerprintMotion;
|
|
84
|
+
/** Extra class on the canvas's wrapper. */
|
|
85
|
+
className?: string;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/** Props for `FingerprintLegend` or `FingerprintList`, for one legend group, ready to spread. */
|
|
89
|
+
export declare interface FingerprintGroupBinding {
|
|
90
|
+
/** The legend group. */
|
|
91
|
+
group: FingerprintLegendGroup;
|
|
92
|
+
/** The current selection. */
|
|
93
|
+
selected: FingerprintSelection | null;
|
|
94
|
+
/** Updates the selection. */
|
|
95
|
+
onSelect: (selection: FingerprintSelection | null) => void;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* One dimension's categories, each drawn as a mark of it would be in the properties this dimension
|
|
100
|
+
* drives (a colour swatch for colour, a neutral shape for shape, a fading tone for lightness), and
|
|
101
|
+
* each a toggle that selects it in the canvas. Render one per `layout.legends` group: the legends
|
|
102
|
+
* are how a keyboard reaches a category, and what names it.
|
|
103
|
+
*/
|
|
104
|
+
export declare function FingerprintLegend({ group, renderer, selected, onSelect, heading, counts, hideEmpty, className, }: FingerprintLegendProps): JSX.Element;
|
|
105
|
+
|
|
106
|
+
/** Props of `FingerprintLegend`. `useFingerprint`'s `legendProps(group)` supplies most of them. */
|
|
107
|
+
export declare interface FingerprintLegendProps {
|
|
108
|
+
/** One dimension's legend, from `layout.legends`. */
|
|
109
|
+
group: FingerprintLegendGroup;
|
|
110
|
+
/** The current selection, from `useFingerprint`. */
|
|
111
|
+
selected?: FingerprintSelection | null;
|
|
112
|
+
/** Called with a category of this group, or null to clear; makes each entry a toggle. */
|
|
113
|
+
onSelect?: (selection: FingerprintSelection | null) => void;
|
|
114
|
+
/** Extra class on the outer element. */
|
|
115
|
+
className?: string;
|
|
116
|
+
/** Draws each entry's swatch; use the canvas's renderer so they match. Defaults to `shapesRenderer`. */
|
|
117
|
+
renderer?: FingerprintRenderer;
|
|
118
|
+
/** Show the dimension's label above its entries. Defaults to true. */
|
|
119
|
+
heading?: boolean;
|
|
120
|
+
/** Show each category's count. Defaults to true. */
|
|
121
|
+
counts?: boolean;
|
|
122
|
+
/** Leave out categories with no items. Defaults to false. */
|
|
123
|
+
hideEmpty?: boolean;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* One dimension as a table: every category with its exact count and share. Render one per
|
|
128
|
+
* `layout.legends` group: together they are the accessible equivalent of the drawing, and the place
|
|
129
|
+
* a callout's claim can be checked.
|
|
130
|
+
*/
|
|
131
|
+
export declare function FingerprintList({ group, unit, linkLabel, selected, onSelect, className, }: FingerprintListProps): JSX.Element;
|
|
132
|
+
|
|
133
|
+
/** Props of `FingerprintList`. `useFingerprint`'s `listProps(group)` supplies most of them. */
|
|
134
|
+
export declare interface FingerprintListProps {
|
|
135
|
+
/** One dimension's legend, from `layout.legends`. */
|
|
136
|
+
group: FingerprintLegendGroup;
|
|
137
|
+
/** The current selection, from `useFingerprint`. */
|
|
138
|
+
selected?: FingerprintSelection | null;
|
|
139
|
+
/** Called with a category of this group, or null to clear; makes each entry a toggle. */
|
|
140
|
+
onSelect?: (selection: FingerprintSelection | null) => void;
|
|
141
|
+
/** Extra class on the outer element. */
|
|
142
|
+
className?: string;
|
|
143
|
+
/** What one item is, e.g. "sets". Defaults to "items". */
|
|
144
|
+
unit?: string;
|
|
145
|
+
/** Text for each category's link, when it has an `href`. Defaults to "Explore". */
|
|
146
|
+
linkLabel?: string;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/** What a renderer's `mark` receives. */
|
|
150
|
+
export declare interface FingerprintMarkProps {
|
|
151
|
+
/** Carries the resolved `color`, `shape` (null when unknown) and `lightness` (null when full strength). */
|
|
152
|
+
node: FingerprintNode;
|
|
153
|
+
/** Prefix for any ids the renderer's `defs` declared, unique to this drawing. */
|
|
154
|
+
idPrefix: string;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* How marks move when the view changes. SVG animates only so many marks smoothly, so above each
|
|
159
|
+
* limit the change is instant instead of stuttering. Under `prefers-reduced-motion` nothing moves.
|
|
160
|
+
*/
|
|
161
|
+
export declare interface FingerprintMotion {
|
|
162
|
+
/**
|
|
163
|
+
* Marks glide to their new places while there are at most this many. Defaults to 800: about what
|
|
164
|
+
* SVG animates smoothly enough (43-50 fps in Chrome); 1,500 gliding marks fell to 16-27 fps. It
|
|
165
|
+
* sits above the default mark cap of 600 because a layout can exceed its cap slightly.
|
|
166
|
+
*/
|
|
167
|
+
glide?: number;
|
|
168
|
+
/**
|
|
169
|
+
* Colours, fills and lightness fade while there are at most this many marks. Defaults to 400:
|
|
170
|
+
* fades on top of a glide cost a third of the frame rate at 600 marks, and nothing at 400.
|
|
171
|
+
*/
|
|
172
|
+
fade?: number;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Draws marks. `mark` draws one mark centred on the origin, `node.size` across, with the ridge
|
|
177
|
+
* running along the x axis: the canvas positions and rotates it, so a renderer never changes
|
|
178
|
+
* layout, counts or selection. It should honour `node.color`, `node.shape` and `node.lightness`
|
|
179
|
+
* (see `markOpacity`), since those carry data. `defs` runs once per drawing. Marks are memoised and
|
|
180
|
+
* selection is drawn by the canvas (dimming the rest), so `mark` must depend on its props alone.
|
|
181
|
+
* The canvas transitions the fill, fill-opacity and stroke of each mark's top-level elements.
|
|
182
|
+
*/
|
|
183
|
+
export declare interface FingerprintRenderer {
|
|
184
|
+
/** A name for debugging and for telling renderers apart. */
|
|
185
|
+
name: string;
|
|
186
|
+
/** Shared SVG definitions (gradients, patterns, symbols), rendered once per drawing. */
|
|
187
|
+
defs?: (props: {
|
|
188
|
+
idPrefix: string;
|
|
189
|
+
legends: readonly FingerprintLegendGroup[];
|
|
190
|
+
}) => ReactNode;
|
|
191
|
+
/** Draws one mark. */
|
|
192
|
+
mark: (props: FingerprintMarkProps) => ReactNode;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/** A category of one dimension: what a legend entry or a mark selects. */
|
|
196
|
+
export declare interface FingerprintSelection {
|
|
197
|
+
/** The dimension the category belongs to. */
|
|
198
|
+
dimensionId: string;
|
|
199
|
+
/** The category's id, or `UNKNOWN_CATEGORY_ID`. */
|
|
200
|
+
categoryId: string;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/** What `useFingerprint` returns. */
|
|
204
|
+
export declare interface FingerprintState {
|
|
205
|
+
/** The current view's layout; empty while `error` is set. */
|
|
206
|
+
layout: FingerprintLayout;
|
|
207
|
+
/** A plain-language summary of the layout, for the canvas's description. */
|
|
208
|
+
description: string;
|
|
209
|
+
/** Invalid data (duplicate ids, lightness on an unordered dimension, …), or null. */
|
|
210
|
+
error: FingerprintDataError | null;
|
|
211
|
+
/** The views, as given or one per dimension. */
|
|
212
|
+
views: readonly FingerprintView[];
|
|
213
|
+
/** The active view. */
|
|
214
|
+
view: FingerprintView | undefined;
|
|
215
|
+
/** The active view's id. */
|
|
216
|
+
viewId: string;
|
|
217
|
+
/** Switches view and clears the selection. */
|
|
218
|
+
setViewId: (viewId: string) => void;
|
|
219
|
+
/** The selected category of a dimension, or null. */
|
|
220
|
+
selected: FingerprintSelection | null;
|
|
221
|
+
/** Selects a category of a dimension, or clears with null. */
|
|
222
|
+
setSelected: (selection: FingerprintSelection | null) => void;
|
|
223
|
+
/** Spread onto `FingerprintCanvas`, with a `title`. */
|
|
224
|
+
canvasProps: FingerprintCanvasBinding;
|
|
225
|
+
/** Spread onto a `FingerprintLegend` for one group. */
|
|
226
|
+
legendProps: (group: FingerprintLegendGroup) => FingerprintGroupBinding;
|
|
227
|
+
/** Spread onto a `FingerprintList` for one group, with `unit` included. */
|
|
228
|
+
listProps: (group: FingerprintLegendGroup) => FingerprintGroupBinding & {
|
|
229
|
+
unit: string;
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/** A named way of looking at the items: which dimension drives which visual property. */
|
|
234
|
+
export declare interface FingerprintView {
|
|
235
|
+
/** Unique among the views. */
|
|
236
|
+
id: string;
|
|
237
|
+
/** The switch's button text. */
|
|
238
|
+
label: string;
|
|
239
|
+
/** Which dimension drives what in this view. */
|
|
240
|
+
encoding: FingerprintEncoding;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/** One pressed button per view. */
|
|
244
|
+
export declare function FingerprintViewSwitch({ views, value, onChange, label, className, }: FingerprintViewSwitchProps): JSX.Element;
|
|
245
|
+
|
|
246
|
+
/** Props of `FingerprintViewSwitch`. */
|
|
247
|
+
export declare interface FingerprintViewSwitchProps {
|
|
248
|
+
/** The views, in button order. */
|
|
249
|
+
views: readonly FingerprintView[];
|
|
250
|
+
/** The active view's id. */
|
|
251
|
+
value: string;
|
|
252
|
+
/** Called with a view's id when its button is pressed. */
|
|
253
|
+
onChange: (viewId: string) => void;
|
|
254
|
+
/** The group's accessible name. Defaults to "View". */
|
|
255
|
+
label?: string;
|
|
256
|
+
/** Extra class on the group. */
|
|
257
|
+
className?: string;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
export { markOpacity }
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* The default: five shapes (circle, rounded square, triangle, diamond, hexagon) by `node.shape`, a
|
|
264
|
+
* ring in the mark's colour when its shape category is unknown, and lightness as opacity.
|
|
265
|
+
*/
|
|
266
|
+
export declare const shapesRenderer: FingerprintRenderer;
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* The state a fingerprint needs: the active view, the selected category, the layout for both, and
|
|
270
|
+
* prop bundles that wire them to the components. The form is derived from all the items and
|
|
271
|
+
* dimensions, never the active view, so the ridges hold still and only the marks move when the
|
|
272
|
+
* view changes. Changing view clears the selection. Invalid data comes back as `error` with an
|
|
273
|
+
* empty layout, rather than throwing out of render.
|
|
274
|
+
*/
|
|
275
|
+
export declare function useFingerprint({ items, dimensions, views: given, initialViewId, form, seed, maxMarks, unit, }: UseFingerprintOptions): FingerprintState;
|
|
276
|
+
|
|
277
|
+
/** What `useFingerprint` takes. */
|
|
278
|
+
export declare interface UseFingerprintOptions {
|
|
279
|
+
/** One per mark (below the cap), unique ids. Treated as immutable: pass a new array to change it. */
|
|
280
|
+
items: readonly FingerprintItem[];
|
|
281
|
+
/** Every dimension the items carry values for. */
|
|
282
|
+
dimensions: readonly FingerprintDimension[];
|
|
283
|
+
/**
|
|
284
|
+
* The ways of looking, in switcher order. Defaults to one view per dimension, each driving
|
|
285
|
+
* colour, shape and arrangement from that dimension alone.
|
|
286
|
+
*/
|
|
287
|
+
views?: readonly FingerprintView[];
|
|
288
|
+
/** The view shown first. Defaults to the first. */
|
|
289
|
+
initialViewId?: string;
|
|
290
|
+
/** Overrides fields of the form `formFromItems` derives from the data. */
|
|
291
|
+
form?: Partial<FingerprintForm>;
|
|
292
|
+
/** Seeds the form's free fields. Same seed, same picture. Defaults to "fingerprint". */
|
|
293
|
+
seed?: string;
|
|
294
|
+
/** Above this many items, marks stand for several. Defaults to 600. */
|
|
295
|
+
maxMarks?: number;
|
|
296
|
+
/** What one item is, for the description and announcements. Defaults to "items". */
|
|
297
|
+
unit?: string;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
export { }
|