@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,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../temp/src/react/FingerprintCanvas.tsx", "../temp/src/react/renderers.tsx", "../temp/src/react/FingerprintControls.tsx", "../temp/src/react/useFingerprint.ts"],
|
|
4
|
+
"sourcesContent": [
|
|
5
|
+
"import {\n memo,\n useCallback,\n useEffect,\n useId,\n useMemo,\n useRef,\n useState,\n type CSSProperties,\n} from \"react\";\nimport { CALLOUT_GUTTER, CALLOUT_HEIGHT, placeCallouts } from \"../callouts\";\nimport { ridgeOpacity } from \"../opacity\";\nimport type {\n FingerprintAnnotation,\n FingerprintLayout,\n FingerprintNode,\n RidgeStyle,\n} from \"../types\";\nimport { shapesRenderer, type FingerprintRenderer } from \"./renderers\";\n\n/** A category of one dimension: what a legend entry or a mark selects. */\nexport interface FingerprintSelection {\n /** The dimension the category belongs to. */\n dimensionId: string;\n /** The category's id, or `UNKNOWN_CATEGORY_ID`. */\n categoryId: string;\n}\n\n/** Props of `FingerprintCanvas`. `useFingerprint`'s `canvasProps` supplies most of them. */\nexport interface FingerprintCanvasProps {\n /** What to draw: from `useFingerprint` (`canvasProps`) or `layoutFingerprint`. */\n layout: FingerprintLayout;\n /** The drawing's accessible name. */\n title: string;\n /** What it shows, in words (`describeLayout` writes one). */\n description: string;\n /** Draws each mark. Defaults to `shapesRenderer`. */\n renderer?: FingerprintRenderer;\n /** How the ridges behind the marks are drawn. Defaults to `{ show: \"auto\" }`. */\n ridges?: RidgeStyle;\n /** Marks in this category of this dimension are highlighted, the rest dimmed. */\n selected?: FingerprintSelection | null;\n /**\n * Called when a mark is clicked, with its category in the arranging dimension, or null when that\n * is already the selection.\n */\n onSelect?: (selection: FingerprintSelection | null) => void;\n /** Notes pinned to the print, each with a leader to a mark of the categories it names. */\n annotations?: readonly FingerprintAnnotation[];\n /** Where the annotations go. See `FingerprintCallouts`. */\n callouts?: FingerprintCallouts;\n /** Names what one item is, for the selection announcement. Defaults to \"items\". */\n unit?: string;\n /** How marks move when the view changes. See `FingerprintMotion`. */\n motion?: FingerprintMotion;\n /** Extra class on the canvas's wrapper. */\n className?: string;\n}\n\n/** Where callouts go. */\nexport interface FingerprintCallouts {\n /** `auto` (the default) puts them beside the print when there is room and numbered below it when not. */\n placement?: \"auto\" | \"beside\" | \"below\";\n /** Below this container width, `auto` puts callouts below. Defaults to 640 px. */\n breakpoint?: number;\n}\n\n/**\n * How marks move when the view changes. SVG animates only so many marks smoothly, so above each\n * limit the change is instant instead of stuttering. Under `prefers-reduced-motion` nothing moves.\n */\nexport interface FingerprintMotion {\n /**\n * Marks glide to their new places while there are at most this many. Defaults to 800: about what\n * SVG animates smoothly enough (43-50 fps in Chrome); 1,500 gliding marks fell to 16-27 fps. It\n * sits above the default mark cap of 600 because a layout can exceed its cap slightly.\n */\n glide?: number;\n /**\n * Colours, fills and lightness fade while there are at most this many marks. Defaults to 400:\n * fades on top of a glide cost a third of the frame rate at 600 marks, and nothing at 400.\n */\n fade?: number;\n}\n\n/** Ridge directions are equivalent half a turn apart; keeping them in one half stops marks spinning between lenses. */\nconst halfTurn = (degrees: number) => ((((degrees + 90) % 180) + 180) % 180) - 90;\n\n/** A CSS attribute-selector string literal for any category id. */\nconst cssString = (value: string) => `\"${value.replace(/[\"\\\\]/g, \"\\\\$&\").replace(/\\n/g, \"\\\\a \")}\"`;\n\n/**\n * Which element draws each mark, and in what DOM order. A mark takes the key of a previous mark\n * that held one of its items, so a view change moves elements rather than replacing them:\n * single-item marks follow their item, and grouped marks (whose ids change with every view) glide\n * from where their items were. Marks with no counterpart get a fresh key and appear.\n *\n * Carried elements also keep their previous DOM order, with new ones after them. Marks never\n * overlap, so order does not show, but React moving hundreds of SVG elements to match a new order\n * cost a 300 ms stall with 1,500 marks. Recomputed only when the layout changes; the state is\n * committed after render, so a discarded render cannot disturb it.\n */\nfunction useCarriedMarks(layout: FingerprintLayout): { key: string; node: FingerprintNode }[] {\n const committed = useRef({ keyOf: new Map<string, string>(), order: [] as string[] });\n const pending = useRef(committed.current);\n const marks = useMemo(() => {\n const previous = committed.current;\n const keyOf = new Map<string, string>();\n const nodeOf = new Map<string, FingerprintNode>();\n layout.nodes.forEach((node, i) => {\n let key: string | undefined;\n for (const id of node.itemIds) {\n const candidate = previous.keyOf.get(id);\n if (candidate !== undefined && !nodeOf.has(candidate)) {\n key = candidate;\n break;\n }\n }\n if (key === undefined) key = nodeOf.has(node.id) ? `${node.id}~${i}` : node.id;\n nodeOf.set(key, node);\n for (const id of node.itemIds) keyOf.set(id, key);\n });\n const kept = previous.order.filter((key) => nodeOf.has(key));\n const keptSet = new Set(kept);\n const order = [...kept, ...[...nodeOf.keys()].filter((key) => !keptSet.has(key))];\n pending.current = { keyOf, order };\n return order.map((key) => ({ key, node: nodeOf.get(key)! }));\n }, [layout]);\n useEffect(() => {\n committed.current = pending.current;\n }, [marks]);\n return marks;\n}\n\n/** The opacity of marks outside the selection. */\nconst DIMMED = 0.22;\n\n/**\n * One mark. Memoised: it re-renders only when its node changes (a new view or new data), never for\n * a selection, a callout or a resize. Selection is drawn by the canvas's style rule, matching the\n * `data-d{n}` attributes each mark carries for every encoded dimension.\n */\nconst Mark = memo(function Mark({\n node,\n dimensions,\n arrange,\n renderer,\n idPrefix,\n onChoose,\n}: {\n node: FingerprintNode;\n dimensions: readonly string[];\n arrange: string;\n renderer: FingerprintRenderer;\n idPrefix: string;\n onChoose?: (categoryId: string) => void;\n}) {\n const attributes: Record<string, string> = {};\n dimensions.forEach((id, k) => (attributes[`data-d${k}`] = node.categories[id] ?? \"\"));\n return (\n <g\n className=\"fp-mark\"\n data-category={node.categories[arrange]}\n {...attributes}\n onClick={onChoose ? () => onChoose(node.categories[arrange]!) : undefined}\n style={{\n transform: `translate(${node.x}px, ${node.y}px) rotate(${halfTurn(node.rotation)}deg)`,\n }}\n >\n {renderer.mark({ node, idPrefix })}\n </g>\n );\n});\n\nfunction useWidth() {\n const ref = useRef<HTMLDivElement>(null);\n const [width, setWidth] = useState<number | null>(null);\n useEffect(() => {\n const element = ref.current;\n if (!element || typeof ResizeObserver !== \"function\") return;\n const observer = new ResizeObserver(([entry]) => setWidth(entry?.contentRect.width ?? null));\n observer.observe(element);\n return () => observer.disconnect();\n }, []);\n return [ref, width] as const;\n}\n\nconst visuallyHidden: CSSProperties = {\n position: \"absolute\",\n width: 1,\n height: 1,\n overflow: \"hidden\",\n clip: \"rect(0 0 0 0)\",\n whiteSpace: \"nowrap\",\n};\n\n/**\n * The fingerprint itself: ridges, one mark per laid-out node drawn by `renderer`, and optional\n * callouts. Marks move to their new places when the layout's view changes (instantly under reduced\n * 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\n * `description`; choosing a category is done from the legend or list, which are keyboard\n * reachable, and also by pointer on a mark.\n */\nexport function FingerprintCanvas({\n layout,\n title,\n description,\n renderer = shapesRenderer,\n ridges,\n selected = null,\n onSelect,\n annotations = [],\n callouts,\n unit = \"items\",\n motion,\n className,\n}: FingerprintCanvasProps) {\n const uid = useId().replace(/[^\\w-]/g, \"\");\n const [ref, width] = useWidth();\n const placed = useMemo(() => placeCallouts(layout, annotations), [layout, annotations]);\n const mode =\n placed.length === 0\n ? \"none\"\n : (callouts?.placement ?? \"auto\") === \"auto\"\n ? width !== null && width < (callouts?.breakpoint ?? 640)\n ? \"below\"\n : \"beside\"\n : callouts!.placement!;\n const gutter = mode === \"beside\" ? CALLOUT_GUTTER : 0;\n const opacity = ridgeOpacity(layout.itemCount, ridges);\n const selectedEntry = selected\n ? layout.legends\n .find((group) => group.dimensionId === selected.dimensionId)\n ?.entries.find((entry) => entry.id === selected.categoryId)\n : undefined;\n // One stable click handler for every mark, reading the latest props, so a new selection does not\n // hand 1,500 memoised marks a new function and re-render them all.\n const latest = useRef({ selected, onSelect, dimensionId: layout.encoding.arrange });\n latest.current = { selected, onSelect, dimensionId: layout.encoding.arrange };\n const choose = useCallback((categoryId: string) => {\n const { selected: current, onSelect: select, dimensionId } = latest.current;\n select?.(\n current?.dimensionId === dimensionId && current.categoryId === categoryId\n ? null\n : { dimensionId, categoryId },\n );\n }, []);\n const dimensions = useMemo(() => layout.legends.map((g) => g.dimensionId), [layout.legends]);\n const marks = useCarriedMarks(layout);\n // Motion, cursor and selection as one rule set: a selection rewrites this text, not every mark.\n const scope = `.fp-${uid} .fp-mark`;\n const selectedIndex = selected ? dimensions.indexOf(selected.dimensionId) : -1;\n const glides = layout.nodes.length <= (motion?.glide ?? 800);\n const fades = layout.nodes.length <= (motion?.fade ?? 400);\n const css = [\n `${scope}{transition:${glides ? \"transform 700ms cubic-bezier(.2,.7,.2,1),\" : \"\"}opacity 250ms ease${onSelect ? \";cursor:pointer\" : \"\"}}`,\n fades ? `${scope}>*{transition:fill 600ms ease,fill-opacity 600ms ease,stroke 600ms ease}` : \"\",\n `@media (prefers-reduced-motion:reduce){${scope},${scope}>*{transition:none}}`,\n selected && selectedIndex >= 0\n ? `${scope}:not([data-d${selectedIndex}=${cssString(selected.categoryId)}]){opacity:${DIMMED}}`\n : \"\",\n ].join(\"\\n\");\n const ridgeLines = useMemo(\n () =>\n opacity > 0 ? (\n <g\n className=\"fp-ridges\"\n fill=\"none\"\n stroke={ridges?.color ?? \"currentColor\"}\n strokeOpacity={opacity}\n strokeWidth={layout.ridgeSpacing * (ridges?.width ?? 0.12)}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n {layout.ridges.map((ridge, i) => (\n <polyline\n key={i}\n points={ridge.map(([x, y]) => `${x.toFixed(1)},${y.toFixed(1)}`).join(\" \")}\n />\n ))}\n </g>\n ) : null,\n [opacity, ridges?.color, ridges?.width, layout.ridgeSpacing, layout.ridges],\n );\n\n return (\n <div\n ref={ref}\n className={[\"fp-canvas\", `fp-${uid}`, className].filter(Boolean).join(\" \")}\n style={{ position: \"relative\" }}\n data-selection={selected ? `${selected.dimensionId}:${selected.categoryId}` : undefined}\n >\n <style>{css}</style>\n <svg\n viewBox={`${-gutter} 0 ${layout.width + gutter * 2} ${layout.height}`}\n role=\"img\"\n aria-labelledby={`${uid}-title ${uid}-desc`}\n style={{ display: \"block\", width: \"100%\", height: \"auto\", overflow: \"visible\" }}\n >\n <title id={`${uid}-title`}>{title}</title>\n <desc id={`${uid}-desc`}>{description}</desc>\n {renderer.defs && <defs>{renderer.defs({ idPrefix: uid, legends: layout.legends })}</defs>}\n {ridgeLines}\n <g className=\"fp-marks\">\n {marks.map(({ key, node }) => (\n <Mark\n key={key}\n node={node}\n dimensions={dimensions}\n arrange={layout.encoding.arrange}\n renderer={renderer}\n idPrefix={uid}\n onChoose={onSelect ? choose : undefined}\n />\n ))}\n </g>\n {mode === \"beside\" &&\n placed.map((callout) => {\n const left = callout.side === \"left\";\n const edge = left ? -12 : layout.width + 12;\n return (\n <g key={callout.annotation.id} className=\"fp-callout\" data-side={callout.side}>\n <polyline\n className=\"fp-callout__leader\"\n points={`${edge},${callout.labelY + 14} ${left ? edge + 10 : edge - 10},${callout.labelY + 14} ${callout.anchor.x},${callout.anchor.y}`}\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={1.2}\n />\n <circle cx={callout.anchor.x} cy={callout.anchor.y} r={3.5} fill=\"currentColor\" />\n <foreignObject\n x={left ? -gutter : layout.width + 16}\n y={callout.labelY}\n width={gutter - 16}\n height={CALLOUT_HEIGHT}\n >\n <div\n className=\"fp-callout__label\"\n style={{ textAlign: left ? \"right\" : \"left\", fontSize: 13, lineHeight: 1.35 }}\n >\n <strong style={{ display: \"block\", fontSize: 15 }}>\n {callout.annotation.title}\n </strong>\n {callout.annotation.body && <span>{callout.annotation.body}</span>}\n </div>\n </foreignObject>\n </g>\n );\n })}\n {mode === \"below\" &&\n placed.map((callout) => (\n <g key={callout.annotation.id} className=\"fp-callout-marker\" aria-hidden=\"true\">\n <circle cx={callout.anchor.x} cy={callout.anchor.y} r={11} fill=\"currentColor\" />\n <text\n x={callout.anchor.x}\n y={callout.anchor.y}\n dy=\"0.35em\"\n textAnchor=\"middle\"\n fontSize={13}\n fontWeight={700}\n style={{ fill: \"var(--fp-callout-ink, Canvas)\" }}\n >\n {callout.number}\n </text>\n </g>\n ))}\n </svg>\n {mode === \"below\" && (\n <ol className=\"fp-callouts\">\n {placed.map((callout) => (\n <li key={callout.annotation.id} value={callout.number}>\n <strong>{callout.annotation.title}</strong>\n {callout.annotation.body && <> {callout.annotation.body}</>}\n </li>\n ))}\n </ol>\n )}\n {/* The callouts drawn beside the print are inside the image; their words are repeated here\n so a screen reader gets them too. */}\n {mode === \"beside\" && (\n <ul style={visuallyHidden}>\n {placed.map((callout) => (\n <li key={callout.annotation.id}>\n {callout.annotation.title}. {callout.annotation.body}\n </li>\n ))}\n </ul>\n )}\n <p role=\"status\" aria-live=\"polite\" style={visuallyHidden}>\n {selectedEntry\n ? `${selectedEntry.label}: ${selectedEntry.count.toLocaleString(\"en-GB\")} ${unit}.`\n : \"\"}\n </p>\n </div>\n );\n}\n",
|
|
6
|
+
"import type { ReactNode } from \"react\";\nimport { markOpacity } from \"../opacity\";\nimport type { FingerprintLegendGroup, FingerprintNode } from \"../types\";\n\nexport { markOpacity };\n\n/** What a renderer's `mark` receives. */\nexport interface FingerprintMarkProps {\n /** Carries the resolved `color`, `shape` (null when unknown) and `lightness` (null when full strength). */\n node: FingerprintNode;\n /** Prefix for any ids the renderer's `defs` declared, unique to this drawing. */\n idPrefix: string;\n}\n\n/**\n * Draws marks. `mark` draws one mark centred on the origin, `node.size` across, with the ridge\n * running along the x axis: the canvas positions and rotates it, so a renderer never changes\n * layout, counts or selection. It should honour `node.color`, `node.shape` and `node.lightness`\n * (see `markOpacity`), since those carry data. `defs` runs once per drawing. Marks are memoised and\n * selection is drawn by the canvas (dimming the rest), so `mark` must depend on its props alone.\n * The canvas transitions the fill, fill-opacity and stroke of each mark's top-level elements.\n */\nexport interface FingerprintRenderer {\n /** A name for debugging and for telling renderers apart. */\n name: string;\n /** Shared SVG definitions (gradients, patterns, symbols), rendered once per drawing. */\n defs?: (props: { idPrefix: string; legends: readonly FingerprintLegendGroup[] }) => ReactNode;\n /** Draws one mark. */\n mark: (props: FingerprintMarkProps) => ReactNode;\n}\n\n/**\n * The default: five shapes (circle, rounded square, triangle, diamond, hexagon) by `node.shape`, a\n * ring in the mark's colour when its shape category is unknown, and lightness as opacity.\n */\nexport const shapesRenderer: FingerprintRenderer = {\n name: \"shapes\",\n mark: ({ node }) => {\n const r = node.size / 2;\n const paint = {\n fill: node.color,\n fillOpacity: markOpacity(node),\n };\n if (node.shape === null)\n return (\n <circle\n r={r * 0.8}\n fill=\"none\"\n stroke={node.color}\n strokeOpacity={markOpacity(node)}\n strokeWidth={r * 0.35}\n />\n );\n switch (node.shape % 5) {\n case 1:\n return (\n <rect\n x={-r * 0.85}\n y={-r * 0.85}\n width={r * 1.7}\n height={r * 1.7}\n rx={r * 0.25}\n {...paint}\n />\n );\n case 2:\n return (\n <polygon points={`0,${-r} ${r * 0.95},${r * 0.75} ${-r * 0.95},${r * 0.75}`} {...paint} />\n );\n case 3:\n return <polygon points={`0,${-r} ${r},0 0,${r} ${-r},0`} {...paint} />;\n case 4:\n return (\n <polygon\n points={Array.from({ length: 6 }, (_, i) => {\n const a = (Math.PI / 3) * i;\n return `${(r * Math.cos(a)).toFixed(2)},${(r * Math.sin(a)).toFixed(2)}`;\n }).join(\" \")}\n {...paint}\n />\n );\n default:\n return <circle r={r} {...paint} />;\n }\n },\n};\n\n/** Every mark a dot, shape ignored. Only for when shape must carry nothing. */\nexport const dotsRenderer: FingerprintRenderer = {\n name: \"dots\",\n mark: ({ node }) =>\n node.shape === null ? (\n <circle\n r={node.size * 0.4}\n fill=\"none\"\n stroke={node.color}\n strokeOpacity={markOpacity(node)}\n strokeWidth={node.size * 0.18}\n />\n ) : (\n <circle r={node.size / 2} fill={node.color} fillOpacity={markOpacity(node)} />\n ),\n};\n",
|
|
7
|
+
"import { useId } from \"react\";\nimport type { FingerprintEncoding, FingerprintLegendGroup } from \"../types\";\nimport type { FingerprintSelection } from \"./FingerprintCanvas\";\nimport { shapesRenderer, type FingerprintRenderer } from \"./renderers\";\n\nconst join = (...names: (string | undefined | false)[]) => names.filter(Boolean).join(\" \");\n\n/** A named way of looking at the items: which dimension drives which visual property. */\nexport interface FingerprintView {\n /** Unique among the views. */\n id: string;\n /** The switch's button text. */\n label: string;\n /** Which dimension drives what in this view. */\n encoding: FingerprintEncoding;\n}\n\n/** Props of `FingerprintViewSwitch`. */\nexport interface FingerprintViewSwitchProps {\n /** The views, in button order. */\n views: readonly FingerprintView[];\n /** The active view's id. */\n value: string;\n /** Called with a view's id when its button is pressed. */\n onChange: (viewId: string) => void;\n /** The group's accessible name. Defaults to \"View\". */\n label?: string;\n /** Extra class on the group. */\n className?: string;\n}\n\n/** One pressed button per view. */\nexport function FingerprintViewSwitch({\n views,\n value,\n onChange,\n label = \"View\",\n className,\n}: FingerprintViewSwitchProps) {\n return (\n <div role=\"group\" aria-label={label} className={join(\"fp-views\", className)}>\n {views.map((view) => (\n <button\n key={view.id}\n type=\"button\"\n className=\"fp-views__view\"\n aria-pressed={view.id === value}\n onClick={() => onChange(view.id)}\n >\n {view.label}\n </button>\n ))}\n </div>\n );\n}\n\nconst isSelected = (\n selected: FingerprintSelection | null,\n group: FingerprintLegendGroup,\n id: string,\n) => selected?.dimensionId === group.dimensionId && selected.categoryId === id;\n\n/** Props of `FingerprintLegend`. `useFingerprint`'s `legendProps(group)` supplies most of them. */\nexport interface FingerprintLegendProps {\n /** One dimension's legend, from `layout.legends`. */\n group: FingerprintLegendGroup;\n /** The current selection, from `useFingerprint`. */\n selected?: FingerprintSelection | null;\n /** Called with a category of this group, or null to clear; makes each entry a toggle. */\n onSelect?: (selection: FingerprintSelection | null) => void;\n /** Extra class on the outer element. */\n className?: string;\n\n /** Draws each entry's swatch; use the canvas's renderer so they match. Defaults to `shapesRenderer`. */\n renderer?: FingerprintRenderer;\n /** Show the dimension's label above its entries. Defaults to true. */\n heading?: boolean;\n /** Show each category's count. Defaults to true. */\n counts?: boolean;\n /** Leave out categories with no items. Defaults to false. */\n hideEmpty?: boolean;\n}\n\n/**\n * One dimension's categories, each drawn as a mark of it would be in the properties this dimension\n * drives (a colour swatch for colour, a neutral shape for shape, a fading tone for lightness), and\n * each a toggle that selects it in the canvas. Render one per `layout.legends` group: the legends\n * are how a keyboard reaches a category, and what names it.\n */\nexport function FingerprintLegend({\n group,\n renderer = shapesRenderer,\n selected = null,\n onSelect,\n heading = true,\n counts = true,\n hideEmpty = false,\n className,\n}: FingerprintLegendProps) {\n const uid = useId().replace(/[^\\w-]/g, \"\");\n const headingId = `${uid}-heading`;\n return (\n <div className={join(\"fp-legend\", className)} data-channels={group.channels.join(\" \")}>\n {heading && (\n <p id={headingId} className=\"fp-legend__heading\">\n {group.label}\n </p>\n )}\n <ul\n aria-labelledby={heading ? headingId : undefined}\n aria-label={heading ? undefined : group.label}\n style={{ listStyle: \"none\", padding: 0, margin: 0 }}\n >\n {group.entries\n .filter((entry) => !hideEmpty || entry.count > 0)\n .map((entry, index) => {\n const prefix = `${uid}-${index}`;\n const swatch = (\n <svg\n viewBox=\"-7 -7 14 14\"\n width=\"1em\"\n height=\"1em\"\n aria-hidden=\"true\"\n className=\"fp-legend__swatch\"\n >\n {renderer.defs && (\n <defs>{renderer.defs({ idPrefix: prefix, legends: [group] })}</defs>\n )}\n {renderer.mark({\n node: {\n id: entry.id,\n itemIds: [],\n categories: { [group.dimensionId]: entry.id },\n x: 0,\n y: 0,\n rotation: 0,\n size: 12,\n weight: 1,\n color: entry.color,\n shape: entry.shape,\n lightness: entry.lightness,\n },\n idPrefix: prefix,\n })}\n </svg>\n );\n const text = (\n <>\n {swatch}\n <span className=\"fp-legend__label\">{entry.label}</span>\n {counts && (\n <span className=\"fp-legend__count\">{entry.count.toLocaleString(\"en-GB\")}</span>\n )}\n </>\n );\n return (\n <li key={entry.id} className=\"fp-legend__entry\">\n {onSelect ? (\n <button\n type=\"button\"\n className=\"fp-legend__toggle\"\n aria-pressed={isSelected(selected, group, entry.id)}\n onClick={() =>\n onSelect(\n isSelected(selected, group, entry.id)\n ? null\n : { dimensionId: group.dimensionId, categoryId: entry.id },\n )\n }\n >\n {text}\n </button>\n ) : (\n text\n )}\n </li>\n );\n })}\n </ul>\n </div>\n );\n}\n\n/** Props of `FingerprintList`. `useFingerprint`'s `listProps(group)` supplies most of them. */\nexport interface FingerprintListProps {\n /** One dimension's legend, from `layout.legends`. */\n group: FingerprintLegendGroup;\n /** The current selection, from `useFingerprint`. */\n selected?: FingerprintSelection | null;\n /** Called with a category of this group, or null to clear; makes each entry a toggle. */\n onSelect?: (selection: FingerprintSelection | null) => void;\n /** Extra class on the outer element. */\n className?: string;\n\n /** What one item is, e.g. \"sets\". Defaults to \"items\". */\n unit?: string;\n /** Text for each category's link, when it has an `href`. Defaults to \"Explore\". */\n linkLabel?: string;\n}\n\n/**\n * One dimension as a table: every category with its exact count and share. Render one per\n * `layout.legends` group: together they are the accessible equivalent of the drawing, and the place\n * a callout's claim can be checked.\n */\nexport function FingerprintList({\n group,\n unit = \"items\",\n linkLabel = \"Explore\",\n selected = null,\n onSelect,\n className,\n}: FingerprintListProps) {\n // Every group counts every item once, so its entries sum to the whole collection.\n const total = group.entries.reduce((sum, entry) => sum + entry.count, 0);\n const share = (count: number) => (total ? `${Math.round((count / total) * 100)}%` : \"–\");\n const links = group.entries.some((entry) => entry.href);\n return (\n <table className={join(\"fp-list\", className)}>\n <caption>\n {group.label}: {total.toLocaleString(\"en-GB\")} {unit}\n </caption>\n <thead>\n <tr>\n <th scope=\"col\">{group.label}</th>\n <th scope=\"col\">{unit[0]!.toUpperCase() + unit.slice(1)}</th>\n <th scope=\"col\">Share</th>\n {links && (\n <th scope=\"col\">\n <span className=\"fp-list__hidden\">Link</span>\n </th>\n )}\n </tr>\n </thead>\n <tbody>\n {group.entries.map((entry) => (\n <tr key={entry.id} data-selected={isSelected(selected, group, entry.id) || undefined}>\n <th scope=\"row\">\n {onSelect ? (\n <button\n type=\"button\"\n className=\"fp-list__toggle\"\n aria-pressed={isSelected(selected, group, entry.id)}\n onClick={() =>\n onSelect(\n isSelected(selected, group, entry.id)\n ? null\n : { dimensionId: group.dimensionId, categoryId: entry.id },\n )\n }\n >\n {entry.label}\n </button>\n ) : (\n entry.label\n )}\n </th>\n <td>{entry.count.toLocaleString(\"en-GB\")}</td>\n <td>{share(entry.count)}</td>\n {links && (\n <td>\n {entry.href && (\n <a href={entry.href}>\n {linkLabel}\n <span className=\"fp-list__hidden\"> {entry.label}</span>\n </a>\n )}\n </td>\n )}\n </tr>\n ))}\n </tbody>\n </table>\n );\n}\n",
|
|
8
|
+
"import { useCallback, useMemo, useState } from \"react\";\nimport { describeLayout } from \"../describe\";\nimport { formFromItems } from \"../form\";\nimport { emptyLayout, FingerprintDataError, layoutFingerprint } from \"../layout\";\nimport type {\n FingerprintDimension,\n FingerprintForm,\n FingerprintItem,\n FingerprintLayout,\n FingerprintLegendGroup,\n} from \"../types\";\nimport type { FingerprintSelection } from \"./FingerprintCanvas\";\nimport type { FingerprintView } from \"./FingerprintControls\";\n\n/** What `useFingerprint` takes. */\nexport interface UseFingerprintOptions {\n /** One per mark (below the cap), unique ids. Treated as immutable: pass a new array to change it. */\n items: readonly FingerprintItem[];\n /** Every dimension the items carry values for. */\n dimensions: readonly FingerprintDimension[];\n /**\n * The ways of looking, in switcher order. Defaults to one view per dimension, each driving\n * colour, shape and arrangement from that dimension alone.\n */\n views?: readonly FingerprintView[];\n /** The view shown first. Defaults to the first. */\n initialViewId?: string;\n /** Overrides fields of the form `formFromItems` derives from the data. */\n form?: Partial<FingerprintForm>;\n /** Seeds the form's free fields. Same seed, same picture. Defaults to \"fingerprint\". */\n seed?: string;\n /** Above this many items, marks stand for several. Defaults to 600. */\n maxMarks?: number;\n /** What one item is, for the description and announcements. Defaults to \"items\". */\n unit?: string;\n}\n\n/** Props for `FingerprintCanvas`, ready to spread; add a `title`. */\nexport interface FingerprintCanvasBinding {\n /** The current view's layout. */\n layout: FingerprintLayout;\n /** `describeLayout`'s summary of it, or the data error's message. */\n description: string;\n /** The current selection. */\n selected: FingerprintSelection | null;\n /** Updates the selection. */\n onSelect: (selection: FingerprintSelection | null) => void;\n /** What one item is. */\n unit: string;\n}\n\n/** Props for `FingerprintLegend` or `FingerprintList`, for one legend group, ready to spread. */\nexport interface FingerprintGroupBinding {\n /** The legend group. */\n group: FingerprintLegendGroup;\n /** The current selection. */\n selected: FingerprintSelection | null;\n /** Updates the selection. */\n onSelect: (selection: FingerprintSelection | null) => void;\n}\n\n/** What `useFingerprint` returns. */\nexport interface FingerprintState {\n /** The current view's layout; empty while `error` is set. */\n layout: FingerprintLayout;\n /** A plain-language summary of the layout, for the canvas's description. */\n description: string;\n /** Invalid data (duplicate ids, lightness on an unordered dimension, …), or null. */\n error: FingerprintDataError | null;\n /** The views, as given or one per dimension. */\n views: readonly FingerprintView[];\n /** The active view. */\n view: FingerprintView | undefined;\n /** The active view's id. */\n viewId: string;\n /** Switches view and clears the selection. */\n setViewId: (viewId: string) => void;\n /** The selected category of a dimension, or null. */\n selected: FingerprintSelection | null;\n /** Selects a category of a dimension, or clears with null. */\n setSelected: (selection: FingerprintSelection | null) => void;\n /** Spread onto `FingerprintCanvas`, with a `title`. */\n canvasProps: FingerprintCanvasBinding;\n /** Spread onto a `FingerprintLegend` for one group. */\n legendProps: (group: FingerprintLegendGroup) => FingerprintGroupBinding;\n /** Spread onto a `FingerprintList` for one group, with `unit` included. */\n listProps: (group: FingerprintLegendGroup) => FingerprintGroupBinding & { unit: string };\n}\n\n/**\n * The state a fingerprint needs: the active view, the selected category, the layout for both, and\n * prop bundles that wire them to the components. The form is derived from all the items and\n * dimensions, never the active view, so the ridges hold still and only the marks move when the\n * view changes. Changing view clears the selection. Invalid data comes back as `error` with an\n * empty layout, rather than throwing out of render.\n */\nexport function useFingerprint({\n items,\n dimensions,\n views: given,\n initialViewId,\n form,\n seed = \"fingerprint\",\n maxMarks,\n unit = \"items\",\n}: UseFingerprintOptions): FingerprintState {\n const views = useMemo<readonly FingerprintView[]>(\n () =>\n given ?? dimensions.map((d) => ({ id: d.id, label: d.label, encoding: { arrange: d.id } })),\n [given, dimensions],\n );\n const [viewId, setView] = useState(initialViewId ?? views[0]?.id ?? \"\");\n const [selected, setSelected] = useState<FingerprintSelection | null>(null);\n const view = views.find((v) => v.id === viewId) ?? views[0];\n const resolvedForm = useMemo(\n () => ({ ...formFromItems(items, dimensions, seed), ...form }),\n [items, dimensions, seed, form],\n );\n const { layout, error } = useMemo(() => {\n try {\n const layout = layoutFingerprint({\n items,\n dimensions,\n encoding: view?.encoding,\n seed,\n form: resolvedForm,\n maxMarks,\n });\n return { layout, error: null };\n } catch (caught) {\n if (caught instanceof FingerprintDataError) return { layout: emptyLayout(), error: caught };\n throw caught;\n }\n }, [items, dimensions, view, seed, resolvedForm, maxMarks]);\n const description = useMemo(\n () => (error ? error.message : describeLayout(layout, unit)),\n [layout, error, unit],\n );\n const setViewId = useCallback((id: string) => {\n setView(id);\n setSelected(null);\n }, []);\n const canvasProps = useMemo(\n () => ({ layout, description, selected, onSelect: setSelected, unit }),\n [layout, description, selected, unit],\n );\n const legendProps = useCallback(\n (group: FingerprintLegendGroup) => ({ group, selected, onSelect: setSelected }),\n [selected],\n );\n const listProps = useCallback(\n (group: FingerprintLegendGroup) => ({ group, selected, onSelect: setSelected, unit }),\n [selected, unit],\n );\n return {\n layout,\n description,\n error,\n views,\n view,\n viewId: view?.id ?? \"\",\n setViewId,\n selected,\n setSelected,\n canvasProps,\n legendProps,\n listProps,\n };\n}\n"
|
|
9
|
+
],
|
|
10
|
+
"mappings": "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",
|
|
11
|
+
"debugId": "F7CD85AE8DCB22DE64756E2164756E21",
|
|
12
|
+
"names": []
|
|
13
|
+
}
|
package/dist/styles.css
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* @data-profile/fingerprint — optional styles for the legend, list, view switch and
|
|
3
|
+
* callouts. Import once: `import "@data-profile/fingerprint/styles.css"`. Neutral by
|
|
4
|
+
* default; theme it through the custom properties below, on any ancestor.
|
|
5
|
+
*
|
|
6
|
+
* --fp-accent pressed buttons, focus rings, selected rows (default: #4f46e5)
|
|
7
|
+
* --fp-accent-text text on the accent (default: #ffffff)
|
|
8
|
+
* --fp-muted counts, headings, captions (default: color-mix of currentColor)
|
|
9
|
+
* --fp-border button and table rules (default: color-mix of currentColor)
|
|
10
|
+
* --fp-radius button corners (default: 8px)
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
.fp-views {
|
|
14
|
+
display: flex;
|
|
15
|
+
flex-wrap: wrap;
|
|
16
|
+
gap: 0.375rem;
|
|
17
|
+
}
|
|
18
|
+
.fp-views__view {
|
|
19
|
+
font: inherit;
|
|
20
|
+
color: inherit;
|
|
21
|
+
background: transparent;
|
|
22
|
+
border: 1px solid var(--fp-border, color-mix(in srgb, currentColor 22%, transparent));
|
|
23
|
+
border-radius: var(--fp-radius, 8px);
|
|
24
|
+
padding: 0.4rem 0.9rem;
|
|
25
|
+
cursor: pointer;
|
|
26
|
+
}
|
|
27
|
+
.fp-views__view[aria-pressed="true"] {
|
|
28
|
+
background: var(--fp-accent, #4f46e5);
|
|
29
|
+
color: var(--fp-accent-text, #ffffff);
|
|
30
|
+
border-color: transparent;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.fp-legend__heading {
|
|
34
|
+
margin: 0 0 0.35rem;
|
|
35
|
+
font-size: 0.72rem;
|
|
36
|
+
letter-spacing: 0.12em;
|
|
37
|
+
text-transform: uppercase;
|
|
38
|
+
color: var(--fp-muted, color-mix(in srgb, currentColor 65%, transparent));
|
|
39
|
+
}
|
|
40
|
+
.fp-legend ul {
|
|
41
|
+
display: grid;
|
|
42
|
+
gap: 2px;
|
|
43
|
+
}
|
|
44
|
+
.fp-legend__entry {
|
|
45
|
+
display: flex;
|
|
46
|
+
align-items: center;
|
|
47
|
+
gap: 0.5rem;
|
|
48
|
+
}
|
|
49
|
+
.fp-legend__toggle {
|
|
50
|
+
all: unset;
|
|
51
|
+
box-sizing: border-box;
|
|
52
|
+
display: flex;
|
|
53
|
+
align-items: center;
|
|
54
|
+
gap: 0.5rem;
|
|
55
|
+
width: 100%;
|
|
56
|
+
padding: 0.2rem 0.4rem;
|
|
57
|
+
border-radius: calc(var(--fp-radius, 8px) * 0.75);
|
|
58
|
+
cursor: pointer;
|
|
59
|
+
}
|
|
60
|
+
.fp-legend__toggle[aria-pressed="true"] {
|
|
61
|
+
background: color-mix(in srgb, var(--fp-accent, #4f46e5) 16%, transparent);
|
|
62
|
+
}
|
|
63
|
+
.fp-legend__swatch {
|
|
64
|
+
flex: none;
|
|
65
|
+
font-size: 1.15rem;
|
|
66
|
+
}
|
|
67
|
+
.fp-legend__count {
|
|
68
|
+
margin-left: auto;
|
|
69
|
+
color: var(--fp-muted, color-mix(in srgb, currentColor 65%, transparent));
|
|
70
|
+
font-variant-numeric: tabular-nums;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.fp-views__view:focus-visible,
|
|
74
|
+
.fp-legend__toggle:focus-visible,
|
|
75
|
+
.fp-list__toggle:focus-visible {
|
|
76
|
+
outline: 2px solid var(--fp-accent, #4f46e5);
|
|
77
|
+
outline-offset: 2px;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
.fp-list {
|
|
81
|
+
width: 100%;
|
|
82
|
+
border-collapse: collapse;
|
|
83
|
+
font-variant-numeric: tabular-nums;
|
|
84
|
+
}
|
|
85
|
+
.fp-list caption {
|
|
86
|
+
text-align: left;
|
|
87
|
+
font-weight: 600;
|
|
88
|
+
padding-bottom: 0.4rem;
|
|
89
|
+
}
|
|
90
|
+
.fp-list th,
|
|
91
|
+
.fp-list td {
|
|
92
|
+
text-align: left;
|
|
93
|
+
padding: 0.4rem 0.5rem;
|
|
94
|
+
border-bottom: 1px solid var(--fp-border, color-mix(in srgb, currentColor 22%, transparent));
|
|
95
|
+
}
|
|
96
|
+
.fp-list__toggle {
|
|
97
|
+
all: unset;
|
|
98
|
+
cursor: pointer;
|
|
99
|
+
}
|
|
100
|
+
.fp-list__toggle[aria-pressed="true"] {
|
|
101
|
+
font-weight: 700;
|
|
102
|
+
}
|
|
103
|
+
.fp-list__hidden {
|
|
104
|
+
position: absolute;
|
|
105
|
+
width: 1px;
|
|
106
|
+
height: 1px;
|
|
107
|
+
overflow: hidden;
|
|
108
|
+
clip: rect(0 0 0 0);
|
|
109
|
+
white-space: nowrap;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
.fp-callouts {
|
|
113
|
+
margin: 0.75rem 0 0;
|
|
114
|
+
padding-left: 1.25rem;
|
|
115
|
+
display: grid;
|
|
116
|
+
gap: 0.4rem;
|
|
117
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,74 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@data-profile/fingerprint",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "Draw any collection as a deterministic fingerprint: one mark per item along real-looking ridges, grouped and coloured by your own categories, with pluggable renderers.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "Will Thirkettle",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/SirKettle/data-profile.git",
|
|
11
|
+
"directory": "packages/fingerprint"
|
|
12
|
+
},
|
|
13
|
+
"homepage": "https://sirkettle.github.io/data-profile/",
|
|
14
|
+
"bugs": {
|
|
15
|
+
"url": "https://github.com/SirKettle/data-profile/issues"
|
|
16
|
+
},
|
|
17
|
+
"keywords": [
|
|
18
|
+
"react",
|
|
19
|
+
"svg",
|
|
20
|
+
"fingerprint",
|
|
21
|
+
"collection",
|
|
22
|
+
"visualisation",
|
|
23
|
+
"data-visualization",
|
|
24
|
+
"categorical",
|
|
25
|
+
"deterministic",
|
|
26
|
+
"accessible"
|
|
27
|
+
],
|
|
28
|
+
"sideEffects": [
|
|
29
|
+
"*.css"
|
|
30
|
+
],
|
|
31
|
+
"exports": {
|
|
32
|
+
".": {
|
|
33
|
+
"types": "./dist/index.d.ts",
|
|
34
|
+
"import": "./dist/index.js"
|
|
35
|
+
},
|
|
36
|
+
"./react": {
|
|
37
|
+
"types": "./dist/react/index.d.ts",
|
|
38
|
+
"import": "./dist/react/index.js"
|
|
39
|
+
},
|
|
40
|
+
"./styles.css": "./dist/styles.css",
|
|
41
|
+
"./package.json": "./package.json"
|
|
42
|
+
},
|
|
43
|
+
"files": [
|
|
44
|
+
"dist",
|
|
45
|
+
"README.md",
|
|
46
|
+
"LICENSE",
|
|
47
|
+
"CHANGELOG.md"
|
|
48
|
+
],
|
|
49
|
+
"engines": {
|
|
50
|
+
"node": ">=20"
|
|
51
|
+
},
|
|
52
|
+
"scripts": {
|
|
53
|
+
"build": "bun run scripts/build.ts",
|
|
54
|
+
"test": "bun test",
|
|
55
|
+
"typecheck": "tsc --noEmit && tsc --noEmit -p tsconfig.examples.json",
|
|
56
|
+
"api:report": "bun run scripts/build.ts --api-report",
|
|
57
|
+
"lint:package": "publint && attw --pack . --profile esm-only --exclude-entrypoints ./styles.css",
|
|
58
|
+
"check:consumer": "bun run scripts/check-consumer.ts"
|
|
59
|
+
},
|
|
60
|
+
"peerDependencies": {
|
|
61
|
+
"react": "^18.0.0 || ^19.0.0"
|
|
62
|
+
},
|
|
63
|
+
"devDependencies": {
|
|
64
|
+
"@arethetypeswrong/cli": "^0.18.5",
|
|
65
|
+
"@happy-dom/global-registrator": "^20.11.2",
|
|
66
|
+
"@microsoft/api-extractor": "^7.59.4",
|
|
67
|
+
"@testing-library/react": "^16.3.2",
|
|
68
|
+
"@types/react": "^19.0.0",
|
|
69
|
+
"@types/react-dom": "^19.0.0",
|
|
70
|
+
"publint": "^0.3.25",
|
|
71
|
+
"react": "^19.0.0",
|
|
72
|
+
"react-dom": "^19.0.0"
|
|
73
|
+
}
|
|
74
|
+
}
|