Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,13 @@ in the README).
## [Unreleased]

### Added
- The renderer-neutral styling IR: `xy.styling.resolved` defines the
versioned, interned `ResolvedStyleSnapshot` (schema v1 — concrete values
only, declarations deduped, instances referencing them by index), with a
generated TypeScript mirror (`js/src/14_style_snapshot.ts`) that the test
suite pins to the Python schema. Wire shape and reserved message names:
`spec/design/wire-protocol.md` §8; nothing rides the wire yet, so
`PROTOCOL_VERSION` is unchanged.
- Every chart-, figure-, and module-level image-export API (`to_png`,
`to_svg`, `to_image`, `write_image`, `export.write_images`) accepts
`compatibility=` — facet-grid exports deliberately do not yet (their
Expand Down
105 changes: 105 additions & 0 deletions js/src/14_style_snapshot.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
// @generated by scripts/gen_style_snapshot_types.py — do not edit by hand.
//
// The TypeScript mirror of `python/xy/styling/resolved.py` (schema v1).
// Concrete values only: no var()/calc(), no relative units — the Python
// side rejects them at construction and the capture side must never
// produce them. Wire shape: spec/design/wire-protocol.md §8.

export const STYLE_SNAPSHOT_VERSION = 1 as const;

export const STYLE_SNAPSHOT_PAINT_PROPERTIES = [
"color",
"fill",
"background",
"background-image",
"opacity",
"fill-opacity",
"stroke",
"stroke-opacity",
"stroke-width",
"border-color",
"border-style",
"border-width",
"border-radius",
"box-shadow",
] as const;

export const STYLE_SNAPSHOT_TYPOGRAPHY_PROPERTIES = [
"font-family",
"font-size",
"font-style",
"font-weight",
"letter-spacing",
"line-height",
"text-align",
"xy-rotation",
] as const;

export const STYLE_SNAPSHOT_LAYOUT_PROPERTIES = [
"padding-top",
"padding-right",
"padding-bottom",
"padding-left",
"gap",
"width",
"height",
"max-width",
"max-height",
"transform",
"clip-path",
] as const;

export const STYLE_SNAPSHOT_EFFECT_PROPERTIES = [
"filter",
"mix-blend-mode",
"isolation",
"mask",
] as const;

export const STYLE_SNAPSHOT_PROPERTIES = [
...STYLE_SNAPSHOT_PAINT_PROPERTIES,
...STYLE_SNAPSHOT_TYPOGRAPHY_PROPERTIES,
...STYLE_SNAPSHOT_LAYOUT_PROPERTIES,
...STYLE_SNAPSHOT_EFFECT_PROPERTIES,
] as const;

export type StyleSnapshotProperty = (typeof STYLE_SNAPSHOT_PROPERTIES)[number];

/** One interned declaration: resolved property -> concrete value. */
export type ResolvedDeclaration = Partial<
Record<StyleSnapshotProperty, string | number>
>;

/** One styled slot occurrence; `d` indexes the snapshot's declarations.
* Instance keys are one-letter on the wire because instances are the
* part that repeats with chart density (spec §8). */
export interface StyleSnapshotInstance {
/** slot name (a `data-xy-slot` value) */
s: string;
/** declaration index into `declarations` */
d: number;
/** stable identity beyond the slot name, e.g. ["y", "major", "3"] */
q?: readonly string[];
/** resolved box in CSS px: [x, y, w, h] */
g?: readonly [number, number, number, number];
/** drawn text, when the slot has any */
c?: string;
}

export interface StyleSnapshotEnvironment {
width: number;
height: number;
dpr: number;
color_scheme: "light" | "dark";
}

export interface ResolvedStyleSnapshot {
version: 1;
style_epoch: number;
environment: StyleSnapshotEnvironment;
tokens: Record<string, string | number>;
states: readonly string[];
unrepresentable: readonly string[];
declarations: readonly ResolvedDeclaration[];
instances: readonly StyleSnapshotInstance[];
}
8 changes: 6 additions & 2 deletions python/xy/styling/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,14 @@
`preflight` applies that inventory to one concrete chart and export target:
`chart.style_compatibility_report()` routes every declared style and names
what would not survive, before any bytes exist.

`resolved` is the renderer-neutral styling IR those two converge on: the
versioned, interned `ResolvedStyleSnapshot` of concrete values that every
resolver produces and every renderer consumes.
"""

from __future__ import annotations

from . import capabilities, preflight
from . import capabilities, preflight, resolved

__all__ = ["capabilities", "preflight"]
__all__ = ["capabilities", "preflight", "resolved"]
Loading
Loading