@variance-authority/presentation 0.1.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 +32 -0
- package/LICENSE +21 -0
- package/README.md +319 -0
- package/dist/alignment.d.ts +9 -0
- package/dist/alignment.js +100 -0
- package/dist/alignment.js.map +1 -0
- package/dist/analyze.d.ts +20 -0
- package/dist/analyze.js +132 -0
- package/dist/analyze.js.map +1 -0
- package/dist/browser-agent-entry.d.ts +2 -0
- package/dist/browser-agent-entry.js +8 -0
- package/dist/browser-agent-entry.js.map +1 -0
- package/dist/browser-agent.bundle.js +3587 -0
- package/dist/browser-agent.d.ts +37 -0
- package/dist/browser-agent.js +130 -0
- package/dist/browser-agent.js.map +1 -0
- package/dist/bundle.d.ts +3 -0
- package/dist/bundle.js +20 -0
- package/dist/bundle.js.map +1 -0
- package/dist/compare.d.ts +4 -0
- package/dist/compare.js +49 -0
- package/dist/compare.js.map +1 -0
- package/dist/findings.d.ts +5 -0
- package/dist/findings.js +285 -0
- package/dist/findings.js.map +1 -0
- package/dist/focus.d.ts +17 -0
- package/dist/focus.js +84 -0
- package/dist/focus.js.map +1 -0
- package/dist/graph.d.ts +11 -0
- package/dist/graph.js +145 -0
- package/dist/graph.js.map +1 -0
- package/dist/hierarchy.d.ts +4 -0
- package/dist/hierarchy.js +171 -0
- package/dist/hierarchy.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/dist/math.d.ts +24 -0
- package/dist/math.js +124 -0
- package/dist/math.js.map +1 -0
- package/dist/measure.d.ts +15 -0
- package/dist/measure.js +216 -0
- package/dist/measure.js.map +1 -0
- package/dist/model.d.ts +346 -0
- package/dist/model.js +2 -0
- package/dist/model.js.map +1 -0
- package/dist/paint.d.ts +12 -0
- package/dist/paint.js +192 -0
- package/dist/paint.js.map +1 -0
- package/dist/patterns.d.ts +10 -0
- package/dist/patterns.js +148 -0
- package/dist/patterns.js.map +1 -0
- package/dist/playwright.d.ts +27 -0
- package/dist/playwright.js +108 -0
- package/dist/playwright.js.map +1 -0
- package/dist/report.d.ts +17 -0
- package/dist/report.js +126 -0
- package/dist/report.js.map +1 -0
- package/dist/spacing.d.ts +4 -0
- package/dist/spacing.js +112 -0
- package/dist/spacing.js.map +1 -0
- package/dist/telemetry.d.ts +4 -0
- package/dist/telemetry.js +73 -0
- package/dist/telemetry.js.map +1 -0
- package/mark.svg +30 -0
- package/package.json +62 -0
- package/skills/variance-presentation/SKILL.md +463 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spacing.js","sourceRoot":"","sources":["../src/spacing.ts"],"names":[],"mappings":"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","sourcesContent":["import { median, round } from './math.js';\nimport type {\n PaintInstruction,\n PresentationReport,\n PresentationSpacingAxis,\n PresentationSpacingReading,\n} from './model.js';\n\n/** Measure spacing across consecutive immediate children of one box or composition. */\nexport function inspectPresentationSpacing(\n report: PresentationReport,\n ownerId: string,\n members: readonly string[],\n axis: PresentationSpacingAxis,\n): PresentationSpacingReading {\n const byId = new Map(report.graph.nodes.map((node) => [node.id, node]));\n const owner = byId.get(ownerId);\n if (owner === undefined) throw new Error(`presentation owner ${ownerId} is not in report ${report.digest}`);\n const uniqueMembers = [...new Set(members)];\n if (uniqueMembers.length < 2) throw new Error('presentation spacing needs at least two distinct members');\n const selected = uniqueMembers.map((id) => {\n const node = byId.get(id);\n if (node === undefined) throw new Error(`presentation spacing member ${id} is not in report ${report.digest}`);\n if (node.parent !== ownerId) {\n throw new Error(`presentation spacing member ${id} is not an immediate child of owner ${ownerId}`);\n }\n return node;\n });\n const positions = uniqueMembers.map((id) => owner.children.indexOf(id));\n const ordered = positions.every((position, index) => index === 0 || position === positions[index - 1]! + 1);\n if (!ordered) throw new Error('presentation spacing members must be consecutive in owner child order');\n\n const separations = selected.slice(0, -1).map((from, index) => {\n const to = selected[index + 1]!;\n const relation = report.graph.relations.find((candidate) =>\n candidate.kind === 'separates' && candidate.from === from.id && candidate.to === to.id);\n if (relation === undefined) throw new Error(`presentation spacing has no separation ${from.id} → ${to.id}`);\n const orderedOverlap = relation.axis === 'overlap' && (\n axis === 'vertical'\n ? to.rect.y >= from.rect.y\n : to.rect.x >= from.rect.x\n );\n if (relation.axis !== axis && !orderedOverlap) {\n throw new Error(`presentation spacing separation ${from.id} → ${to.id} is ${relation.axis}, not ${axis}`);\n }\n if (relation.distancePx === undefined || relation.boundaryStrength === undefined) {\n throw new Error(`presentation spacing separation ${from.id} → ${to.id} is incomplete`);\n }\n return {\n from,\n to,\n distancePx: relation.distancePx,\n boundaryStrength: relation.boundaryStrength,\n ...(relation.spacingCluster === undefined ? {} : { spacingCluster: relation.spacingCluster }),\n };\n });\n const distances = separations.map((separation) => separation.distancePx);\n const boundaries = separations.map((separation) => separation.boundaryStrength);\n return {\n formatVersion: 1,\n report: report.digest,\n owner,\n axis,\n members: selected,\n separations,\n distance: pixelRange(distances),\n boundary: scalarRange(boundaries),\n paint: separations.map((separation) => paint(ownerId, axis, separation)),\n };\n}\n\nfunction pixelRange(values: readonly number[]): {\n readonly minPx: number;\n readonly medianPx: number;\n readonly maxPx: number;\n} {\n return {\n minPx: round(Math.min(...values), 2),\n medianPx: round(median(values)!, 2),\n maxPx: round(Math.max(...values), 2),\n };\n}\n\nfunction scalarRange(values: readonly number[]): {\n readonly min: number;\n readonly median: number;\n readonly max: number;\n} {\n return {\n min: round(Math.min(...values)),\n median: round(median(values)!),\n max: round(Math.max(...values)),\n };\n}\n\nfunction paint(\n owner: string,\n axis: PresentationSpacingAxis,\n separation: PresentationSpacingReading['separations'][number],\n): PaintInstruction {\n const label = `${separation.distancePx}px · boundary ${separation.boundaryStrength}`;\n const id = `spacing:${separation.from.id}:${separation.to.id}`;\n if (axis === 'vertical') {\n const coordinate = round((separation.from.rect.y + separation.from.rect.height + separation.to.rect.y) / 2, 2);\n return {\n id,\n owner,\n nodes: [separation.from.id, separation.to.id],\n layer: 'spacing',\n shape: 'line',\n color: '#ffca55',\n label,\n line: {\n x1: Math.min(separation.from.rect.x, separation.to.rect.x),\n y1: coordinate,\n x2: Math.max(\n separation.from.rect.x + separation.from.rect.width,\n separation.to.rect.x + separation.to.rect.width,\n ),\n y2: coordinate,\n },\n };\n }\n const coordinate = round((separation.from.rect.x + separation.from.rect.width + separation.to.rect.x) / 2, 2);\n return {\n id,\n owner,\n nodes: [separation.from.id, separation.to.id],\n layer: 'spacing',\n shape: 'line',\n color: '#ffca55',\n label,\n line: {\n x1: coordinate,\n y1: Math.min(separation.from.rect.y, separation.to.rect.y),\n x2: coordinate,\n y2: Math.max(\n separation.from.rect.y + separation.from.rect.height,\n separation.to.rect.y + separation.to.rect.height,\n ),\n },\n };\n}\n"]}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { RawCapture } from '@variance-authority/core';
|
|
2
|
+
import type { PresentationNode, PresentationTelemetry, RepeatedPattern } from './model.js';
|
|
3
|
+
export declare function telemetryOf(capture: RawCapture, nodes: readonly PresentationNode[], patterns: readonly RepeatedPattern[] | undefined): PresentationTelemetry;
|
|
4
|
+
//# sourceMappingURL=telemetry.d.ts.map
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { round, unionArea } from './math.js';
|
|
2
|
+
export function telemetryOf(capture, nodes, patterns) {
|
|
3
|
+
const census = censusOf([capture.root, ...(capture.portals ?? [])]);
|
|
4
|
+
const root = nodes.find((node) => node.id === 'r0:0');
|
|
5
|
+
const repeatedObjects = patterns?.reduce((total, pattern) => total + pattern.instances.length, 0) ?? 0;
|
|
6
|
+
const content = {
|
|
7
|
+
elements: census.elements,
|
|
8
|
+
characters: census.characters,
|
|
9
|
+
estimatedLines: estimateLines(nodes),
|
|
10
|
+
controls: census.controls,
|
|
11
|
+
repeatedObjects,
|
|
12
|
+
};
|
|
13
|
+
if (root === undefined)
|
|
14
|
+
return { content };
|
|
15
|
+
const viewport = capture.environment.viewport;
|
|
16
|
+
const viewportHeights = root.rect.height / Math.max(1, viewport.height);
|
|
17
|
+
const leafRects = nodes
|
|
18
|
+
.filter((node) => node.children.length === 0)
|
|
19
|
+
.map((node) => node.rect);
|
|
20
|
+
const regionArea = Math.max(1, root.rect.width * root.rect.height);
|
|
21
|
+
const occupied = unionArea(leafRects);
|
|
22
|
+
return {
|
|
23
|
+
content,
|
|
24
|
+
dimensions: {
|
|
25
|
+
regionWidthPx: root.rect.width,
|
|
26
|
+
regionHeightPx: root.rect.height,
|
|
27
|
+
viewportWidthPx: viewport.width,
|
|
28
|
+
viewportHeightPx: viewport.height,
|
|
29
|
+
viewportHeights: round(viewportHeights, 2),
|
|
30
|
+
},
|
|
31
|
+
utilization: {
|
|
32
|
+
horizontal: round(root.rect.width / Math.max(1, viewport.width)),
|
|
33
|
+
occupiedArea: round(occupied / regionArea),
|
|
34
|
+
},
|
|
35
|
+
density: {
|
|
36
|
+
charactersPer1000Px2: round((census.characters / regionArea) * 1000),
|
|
37
|
+
linesPerViewport: round(content.estimatedLines / Math.max(1, viewportHeights)),
|
|
38
|
+
controlsPerViewport: round(census.controls / Math.max(1, viewportHeights)),
|
|
39
|
+
repeatedObjectsPerViewport: round(repeatedObjects / Math.max(1, viewportHeights)),
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
function censusOf(roots) {
|
|
44
|
+
let elements = 0;
|
|
45
|
+
let characters = 0;
|
|
46
|
+
let controls = 0;
|
|
47
|
+
const controlRoles = new Set(['button', 'checkbox', 'combobox', 'link', 'menuitem', 'radio', 'slider', 'spinbutton', 'switch', 'tab', 'textbox']);
|
|
48
|
+
for (const root of roots)
|
|
49
|
+
walk(root);
|
|
50
|
+
return { elements, characters, controls };
|
|
51
|
+
function walk(node) {
|
|
52
|
+
if (node.tag === '#text')
|
|
53
|
+
characters += node.text?.replace(/\s+/g, ' ').trim().length ?? 0;
|
|
54
|
+
else {
|
|
55
|
+
elements += 1;
|
|
56
|
+
if (node.aria?.role !== null && node.aria?.role !== undefined && controlRoles.has(node.aria.role))
|
|
57
|
+
controls += 1;
|
|
58
|
+
}
|
|
59
|
+
for (const child of node.children)
|
|
60
|
+
walk(child);
|
|
61
|
+
for (const child of node.shadowChildren ?? [])
|
|
62
|
+
walk(child);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
function estimateLines(nodes) {
|
|
66
|
+
return nodes
|
|
67
|
+
.filter((node) => node.children.length === 0 && (node.text !== undefined || node.name !== undefined))
|
|
68
|
+
.reduce((total, node) => {
|
|
69
|
+
const lineHeight = node.typography.lineHeightPx ?? node.typography.sizePx ?? node.rect.height;
|
|
70
|
+
return total + Math.max(1, Math.round(node.rect.height / Math.max(1, lineHeight)));
|
|
71
|
+
}, 0);
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=telemetry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"telemetry.js","sourceRoot":"","sources":["../src/telemetry.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAE7C,MAAM,UAAU,WAAW,CACzB,OAAmB,EACnB,KAAkC,EAClC,QAAgD;IAEhD,MAAM,MAAM,GAAG,QAAQ,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,OAAO,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IACpE,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,KAAK,MAAM,CAAC,CAAC;IACtD,MAAM,eAAe,GAAG,QAAQ,EAAE,MAAM,CAAC,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE,CAAC,KAAK,GAAG,OAAO,CAAC,SAAS,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;IACvG,MAAM,OAAO,GAAG;QACd,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,UAAU,EAAE,MAAM,CAAC,UAAU;QAC7B,cAAc,EAAE,aAAa,CAAC,KAAK,CAAC;QACpC,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,eAAe;KAChB,CAAC;IACF,IAAI,IAAI,KAAK,SAAS;QAAE,OAAO,EAAE,OAAO,EAAE,CAAC;IAE3C,MAAM,QAAQ,GAAG,OAAO,CAAC,WAAW,CAAC,QAAQ,CAAC;IAC9C,MAAM,eAAe,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IACxE,MAAM,SAAS,GAAG,KAAK;SACpB,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC,CAAC;SAC5C,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC5B,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACnE,MAAM,QAAQ,GAAG,SAAS,CAAC,SAAS,CAAC,CAAC;IACtC,OAAO;QACL,OAAO;QACP,UAAU,EAAE;YACV,aAAa,EAAE,IAAI,CAAC,IAAI,CAAC,KAAK;YAC9B,cAAc,EAAE,IAAI,CAAC,IAAI,CAAC,MAAM;YAChC,eAAe,EAAE,QAAQ,CAAC,KAAK;YAC/B,gBAAgB,EAAE,QAAQ,CAAC,MAAM;YACjC,eAAe,EAAE,KAAK,CAAC,eAAe,EAAE,CAAC,CAAC;SAC3C;QACD,WAAW,EAAE;YACX,UAAU,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAC;YAChE,YAAY,EAAE,KAAK,CAAC,QAAQ,GAAG,UAAU,CAAC;SAC3C;QACD,OAAO,EAAE;YACP,oBAAoB,EAAE,KAAK,CAAC,CAAC,MAAM,CAAC,UAAU,GAAG,UAAU,CAAC,GAAG,IAAI,CAAC;YACpE,gBAAgB,EAAE,KAAK,CAAC,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,eAAe,CAAC,CAAC;YAC9E,mBAAmB,EAAE,KAAK,CAAC,MAAM,CAAC,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,eAAe,CAAC,CAAC;YAC1E,0BAA0B,EAAE,KAAK,CAAC,eAAe,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,eAAe,CAAC,CAAC;SAClF;KACF,CAAC;AACJ,CAAC;AAED,SAAS,QAAQ,CAAC,KAAyB;IAKzC,IAAI,QAAQ,GAAG,CAAC,CAAC;IACjB,IAAI,UAAU,GAAG,CAAC,CAAC;IACnB,IAAI,QAAQ,GAAG,CAAC,CAAC;IACjB,MAAM,YAAY,GAAG,IAAI,GAAG,CAAC,CAAC,QAAQ,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,QAAQ,EAAE,KAAK,EAAE,SAAS,CAAC,CAAC,CAAC;IAClJ,KAAK,MAAM,IAAI,IAAI,KAAK;QAAE,IAAI,CAAC,IAAI,CAAC,CAAC;IACrC,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,QAAQ,EAAE,CAAC;IAE1C,SAAS,IAAI,CAAC,IAAa;QACzB,IAAI,IAAI,CAAC,GAAG,KAAK,OAAO;YAAE,UAAU,IAAI,IAAI,CAAC,IAAI,EAAE,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,MAAM,IAAI,CAAC,CAAC;aACtF,CAAC;YACJ,QAAQ,IAAI,CAAC,CAAC;YACd,IAAI,IAAI,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,IAAI,IAAI,CAAC,IAAI,EAAE,IAAI,KAAK,SAAS,IAAI,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;gBAAE,QAAQ,IAAI,CAAC,CAAC;QACnH,CAAC;QACD,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,QAAQ;YAAE,IAAI,CAAC,KAAK,CAAC,CAAC;QAC/C,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,cAAc,IAAI,EAAE;YAAE,IAAI,CAAC,KAAK,CAAC,CAAC;IAC7D,CAAC;AACH,CAAC;AAED,SAAS,aAAa,CAAC,KAAkC;IACvD,OAAO,KAAK;SACT,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,KAAK,SAAS,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC;SACpG,MAAM,CAAC,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE;QACtB,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC,YAAY,IAAI,IAAI,CAAC,UAAU,CAAC,MAAM,IAAI,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC;QAC9F,OAAO,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC;IACrF,CAAC,EAAE,CAAC,CAAC,CAAC;AACV,CAAC","sourcesContent":["import type { RawCapture, RawNode } from '@variance-authority/core';\nimport type { PresentationNode, PresentationTelemetry, RepeatedPattern } from './model.js';\nimport { round, unionArea } from './math.js';\n\nexport function telemetryOf(\n capture: RawCapture,\n nodes: readonly PresentationNode[],\n patterns: readonly RepeatedPattern[] | undefined,\n): PresentationTelemetry {\n const census = censusOf([capture.root, ...(capture.portals ?? [])]);\n const root = nodes.find((node) => node.id === 'r0:0');\n const repeatedObjects = patterns?.reduce((total, pattern) => total + pattern.instances.length, 0) ?? 0;\n const content = {\n elements: census.elements,\n characters: census.characters,\n estimatedLines: estimateLines(nodes),\n controls: census.controls,\n repeatedObjects,\n };\n if (root === undefined) return { content };\n\n const viewport = capture.environment.viewport;\n const viewportHeights = root.rect.height / Math.max(1, viewport.height);\n const leafRects = nodes\n .filter((node) => node.children.length === 0)\n .map((node) => node.rect);\n const regionArea = Math.max(1, root.rect.width * root.rect.height);\n const occupied = unionArea(leafRects);\n return {\n content,\n dimensions: {\n regionWidthPx: root.rect.width,\n regionHeightPx: root.rect.height,\n viewportWidthPx: viewport.width,\n viewportHeightPx: viewport.height,\n viewportHeights: round(viewportHeights, 2),\n },\n utilization: {\n horizontal: round(root.rect.width / Math.max(1, viewport.width)),\n occupiedArea: round(occupied / regionArea),\n },\n density: {\n charactersPer1000Px2: round((census.characters / regionArea) * 1000),\n linesPerViewport: round(content.estimatedLines / Math.max(1, viewportHeights)),\n controlsPerViewport: round(census.controls / Math.max(1, viewportHeights)),\n repeatedObjectsPerViewport: round(repeatedObjects / Math.max(1, viewportHeights)),\n },\n };\n}\n\nfunction censusOf(roots: readonly RawNode[]): {\n readonly elements: number;\n readonly characters: number;\n readonly controls: number;\n} {\n let elements = 0;\n let characters = 0;\n let controls = 0;\n const controlRoles = new Set(['button', 'checkbox', 'combobox', 'link', 'menuitem', 'radio', 'slider', 'spinbutton', 'switch', 'tab', 'textbox']);\n for (const root of roots) walk(root);\n return { elements, characters, controls };\n\n function walk(node: RawNode): void {\n if (node.tag === '#text') characters += node.text?.replace(/\\s+/g, ' ').trim().length ?? 0;\n else {\n elements += 1;\n if (node.aria?.role !== null && node.aria?.role !== undefined && controlRoles.has(node.aria.role)) controls += 1;\n }\n for (const child of node.children) walk(child);\n for (const child of node.shadowChildren ?? []) walk(child);\n }\n}\n\nfunction estimateLines(nodes: readonly PresentationNode[]): number {\n return nodes\n .filter((node) => node.children.length === 0 && (node.text !== undefined || node.name !== undefined))\n .reduce((total, node) => {\n const lineHeight = node.typography.lineHeightPx ?? node.typography.sizePx ?? node.rect.height;\n return total + Math.max(1, Math.round(node.rect.height / Math.max(1, lineHeight)));\n }, 0);\n}\n"]}
|
package/mark.svg
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 320" role="img" aria-labelledby="title desc">
|
|
2
|
+
<title id="title">Variance Authority mark</title>
|
|
3
|
+
<desc id="desc">Folded ribbon VA mark in charcoal and orange.</desc>
|
|
4
|
+
|
|
5
|
+
<defs>
|
|
6
|
+
<style>
|
|
7
|
+
.ribbon-dark {
|
|
8
|
+
fill: #24282A;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
@media (prefers-color-scheme: dark) {
|
|
12
|
+
.ribbon-dark {
|
|
13
|
+
fill: #F3F4F6;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
</style>
|
|
17
|
+
</defs>
|
|
18
|
+
|
|
19
|
+
<!-- Left descending ribbon -->
|
|
20
|
+
<path class="ribbon-dark" d="M64 54H159L256 266H160Z"/>
|
|
21
|
+
|
|
22
|
+
<!-- Right descending ribbon -->
|
|
23
|
+
<path class="ribbon-dark" d="M331 28H419L494 266H397Z"/>
|
|
24
|
+
|
|
25
|
+
<!-- Chosen / variant ribbon -->
|
|
26
|
+
<path d="M256 266L202 152L283 28H376L301 165Z" fill="#FF4A19"/>
|
|
27
|
+
|
|
28
|
+
<!-- Fold shadow -->
|
|
29
|
+
<path d="M202 152L256 266L301 165L264 103Z" fill="#D83A13" opacity="0.72"/>
|
|
30
|
+
</svg>
|
package/package.json
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@variance-authority/presentation",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Sense spacing, alignment, prominence and repetition inside one live interface, as evidence an agent can read.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"variance-authority",
|
|
7
|
+
"layout",
|
|
8
|
+
"spacing",
|
|
9
|
+
"alignment",
|
|
10
|
+
"accessibility",
|
|
11
|
+
"agent",
|
|
12
|
+
"ui-analysis"
|
|
13
|
+
],
|
|
14
|
+
"license": "MIT",
|
|
15
|
+
"author": "Machine Garden",
|
|
16
|
+
"homepage": "https://variance-authority.dev#packages",
|
|
17
|
+
"repository": {
|
|
18
|
+
"type": "git",
|
|
19
|
+
"url": "git+https://github.com/Variance-Authority/variance-authority.git",
|
|
20
|
+
"directory": "packages/presentation"
|
|
21
|
+
},
|
|
22
|
+
"bugs": "https://github.com/Variance-Authority/variance-authority/issues",
|
|
23
|
+
"engines": {
|
|
24
|
+
"node": ">=22"
|
|
25
|
+
},
|
|
26
|
+
"type": "module",
|
|
27
|
+
"exports": {
|
|
28
|
+
".": {
|
|
29
|
+
"types": "./dist/index.d.ts",
|
|
30
|
+
"default": "./dist/index.js"
|
|
31
|
+
},
|
|
32
|
+
"./playwright": {
|
|
33
|
+
"types": "./dist/playwright.d.ts",
|
|
34
|
+
"default": "./dist/playwright.js"
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
"main": "./dist/index.js",
|
|
38
|
+
"types": "./dist/index.d.ts",
|
|
39
|
+
"files": [
|
|
40
|
+
"dist",
|
|
41
|
+
"!dist/**/*.d.ts.map",
|
|
42
|
+
"skills",
|
|
43
|
+
"mark.svg"
|
|
44
|
+
],
|
|
45
|
+
"scripts": {
|
|
46
|
+
"build": "tsc --build"
|
|
47
|
+
},
|
|
48
|
+
"dependencies": {
|
|
49
|
+
"@variance-authority/core": "^0.1.0",
|
|
50
|
+
"@variance-authority/dom": "^0.1.0",
|
|
51
|
+
"@variance-authority/react": "^0.1.0",
|
|
52
|
+
"@variance-authority/report": "^0.1.0"
|
|
53
|
+
},
|
|
54
|
+
"peerDependencies": {
|
|
55
|
+
"@playwright/test": ">=1.49 <2"
|
|
56
|
+
},
|
|
57
|
+
"peerDependenciesMeta": {
|
|
58
|
+
"@playwright/test": {
|
|
59
|
+
"optional": true
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|