@oxide/design-system 6.6.1 → 6.7.0-canary.e63e89e
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
CHANGED
|
@@ -20,10 +20,19 @@ Releases are managed via GitHub Actions workflows triggered from the Actions tab
|
|
|
20
20
|
tag. Install it with `npm install @oxide/design-system@canary` to test changes before
|
|
21
21
|
merging.
|
|
22
22
|
|
|
23
|
-
##
|
|
23
|
+
## Figma Plugins
|
|
24
|
+
|
|
25
|
+
Figma plugins live in `plugins/`. Each is a standalone npm project with its own
|
|
26
|
+
`package.json` and `node_modules` — `cd plugins/<name> && npm install && npm run build`
|
|
27
|
+
(or use the `dual-grid:*` / `token-sync:*` scripts at the root). Load a built plugin in
|
|
28
|
+
Figma via **Plugins → Development → Import plugin from manifest…**.
|
|
24
29
|
|
|
25
|
-
|
|
26
|
-
|
|
30
|
+
- `plugins/token-sync` — reads the CSS files in `styles/` and compares them against
|
|
31
|
+
Figma variables; changes can be applied from the plugin UI.
|
|
32
|
+
- `plugins/dual-grid` — generates a synchronised column + cell grid, ASCII grid, and
|
|
33
|
+
type specimens on a frame.
|
|
34
|
+
|
|
35
|
+
## Syncing with Figma
|
|
27
36
|
|
|
28
37
|
To regenerate colour palettes, run `npm run color-gen:apply`. This updates the `--color-*`
|
|
29
38
|
variables in `styles/main.css` and writes the accent override files.
|
|
@@ -72,7 +81,7 @@ This is type-checked, and will throw an error if the corresponding icon doesn't
|
|
|
72
81
|
|
|
73
82
|
## Usage
|
|
74
83
|
|
|
75
|
-
This package provides
|
|
84
|
+
This package provides three main entry points:
|
|
76
85
|
|
|
77
86
|
### UI Components (`@oxide/design-system/ui`)
|
|
78
87
|
|
|
@@ -117,3 +126,43 @@ content: [
|
|
|
117
126
|
'node_modules/@oxide/design-system/components/**/*.{ts,tsx,jsx,js}',
|
|
118
127
|
],
|
|
119
128
|
```
|
|
129
|
+
|
|
130
|
+
### Grid math (`@oxide/design-system/grid`)
|
|
131
|
+
|
|
132
|
+
The maths behind the dual-grid Figma plugin: computes an ASCII cell grid aligned with a
|
|
133
|
+
column grid, where margin, column and gutter widths are all whole multiples of the cell
|
|
134
|
+
size. Pure TypeScript with no dependencies. See `plugins/dual-grid/README.md` for the
|
|
135
|
+
derivation.
|
|
136
|
+
|
|
137
|
+
`computeGrid` takes the layout column count, the frame size, and either pixel targets
|
|
138
|
+
(`mode: 'auto'` — a solver finds the closest whole-cell fit) or explicit cell counts
|
|
139
|
+
(`mode: 'manual'`):
|
|
140
|
+
|
|
141
|
+
```ts
|
|
142
|
+
import { computeGrid, gridLineSegments } from '@oxide/design-system/grid'
|
|
143
|
+
|
|
144
|
+
const grid = computeGrid({
|
|
145
|
+
mode: 'auto', // or 'manual' with marginCells / gutterCells
|
|
146
|
+
columns: 12, // layout columns
|
|
147
|
+
width: 1920, // frame size, px
|
|
148
|
+
height: 1080,
|
|
149
|
+
targetMarginPx: 50, // the solver aims at these…
|
|
150
|
+
targetGutterPx: 20,
|
|
151
|
+
targetCellColumns: 89, // …and at this ASCII column count
|
|
152
|
+
// optional: cellAspect, snapRows, pixelSnap, snapTolerancePx, aspectTolerancePct
|
|
153
|
+
})
|
|
154
|
+
|
|
155
|
+
grid.N // ASCII grid columns
|
|
156
|
+
grid.rows // ASCII grid rows
|
|
157
|
+
grid.u // cell width, px
|
|
158
|
+
grid.cellH // cell height, px
|
|
159
|
+
grid.solvedM // margin in cells
|
|
160
|
+
grid.solvedG // gutter in cells
|
|
161
|
+
grid.margin // margin in px (effectiveMargin includes the pixel-snap remainder)
|
|
162
|
+
grid.gutterWidth // gutter in px
|
|
163
|
+
grid.columnWidth // column width in px
|
|
164
|
+
|
|
165
|
+
// The cell grid as drawable [x1, y1, x2, y2] line segments, with lines near
|
|
166
|
+
// the frame edge culled.
|
|
167
|
+
const segments = gridLineSegments(grid, 1920, 1080, { edgeCull: true })
|
|
168
|
+
```
|
package/dist/asciidoc.css
CHANGED
|
@@ -419,7 +419,6 @@
|
|
|
419
419
|
border: 1px solid var(--stroke-secondary);
|
|
420
420
|
border-radius: var(--radius-md);
|
|
421
421
|
padding: 1rem 1.25rem;
|
|
422
|
-
position: relative;
|
|
423
422
|
|
|
424
423
|
@media (min-width: 800px) {
|
|
425
424
|
padding: 1.5rem 1.75rem;
|
|
@@ -440,9 +439,19 @@
|
|
|
440
439
|
content: attr(data-lang);
|
|
441
440
|
position: absolute;
|
|
442
441
|
top: 0.5rem;
|
|
443
|
-
right: 0.
|
|
442
|
+
right: 0.75rem;
|
|
444
443
|
display: block;
|
|
445
444
|
color: var(--content-secondary);
|
|
445
|
+
z-index: 1;
|
|
446
|
+
padding: 0 0.25rem;
|
|
447
|
+
background-color: var(--surface-default);
|
|
448
|
+
border-radius: var(--radius-sm);
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
/* Optional role that caps the height for extra long snippets */
|
|
452
|
+
&.scrollable pre {
|
|
453
|
+
max-height: 32rem;
|
|
454
|
+
overflow: auto;
|
|
446
455
|
}
|
|
447
456
|
}
|
|
448
457
|
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
type GridSpec = {
|
|
2
|
+
columns: number;
|
|
3
|
+
width: number;
|
|
4
|
+
height: number;
|
|
5
|
+
targetCellColumns?: number;
|
|
6
|
+
cellAspect?: number;
|
|
7
|
+
snapRows?: boolean;
|
|
8
|
+
pixelSnap?: boolean;
|
|
9
|
+
snapTolerancePx?: number;
|
|
10
|
+
aspectTolerancePct?: number;
|
|
11
|
+
} & ({
|
|
12
|
+
mode: 'manual';
|
|
13
|
+
marginCells: number;
|
|
14
|
+
gutterCells: number;
|
|
15
|
+
} | {
|
|
16
|
+
mode: 'auto';
|
|
17
|
+
targetMarginPx: number;
|
|
18
|
+
targetGutterPx: number;
|
|
19
|
+
});
|
|
20
|
+
interface GridResult {
|
|
21
|
+
N: number;
|
|
22
|
+
u: number;
|
|
23
|
+
solvedM: number;
|
|
24
|
+
solvedK: number;
|
|
25
|
+
solvedG: number;
|
|
26
|
+
solved: boolean;
|
|
27
|
+
offsetX: number;
|
|
28
|
+
cellsPerGutter: number;
|
|
29
|
+
columnWidth: number;
|
|
30
|
+
columnCells: number;
|
|
31
|
+
gutterWidth: number;
|
|
32
|
+
margin: number;
|
|
33
|
+
effectiveMargin: number;
|
|
34
|
+
contentWidth: number;
|
|
35
|
+
rows: number;
|
|
36
|
+
cellH: number;
|
|
37
|
+
rowOffset: number;
|
|
38
|
+
hRemainder: number;
|
|
39
|
+
vRemainder: number;
|
|
40
|
+
actualAspect: number;
|
|
41
|
+
deltaPct: number;
|
|
42
|
+
warn: boolean;
|
|
43
|
+
cellLadder: number[];
|
|
44
|
+
cellColumnsTaken: number;
|
|
45
|
+
}
|
|
46
|
+
interface Solution {
|
|
47
|
+
m: number;
|
|
48
|
+
k: number;
|
|
49
|
+
g: number;
|
|
50
|
+
marginPx: number;
|
|
51
|
+
gutterPx: number;
|
|
52
|
+
u: number;
|
|
53
|
+
N: number;
|
|
54
|
+
err: number;
|
|
55
|
+
}
|
|
56
|
+
interface CellOption {
|
|
57
|
+
u: number;
|
|
58
|
+
k: number;
|
|
59
|
+
N: number;
|
|
60
|
+
bleed: number;
|
|
61
|
+
}
|
|
62
|
+
interface GridExtent {
|
|
63
|
+
startX: number;
|
|
64
|
+
startY: number;
|
|
65
|
+
cols: number;
|
|
66
|
+
rows: number;
|
|
67
|
+
width: number;
|
|
68
|
+
height: number;
|
|
69
|
+
}
|
|
70
|
+
type Segment = [number, number, number, number];
|
|
71
|
+
declare const DEFAULT_TARGET_CELL_COLUMNS = 89;
|
|
72
|
+
declare const DEFAULT_CELL_ASPECT = 2;
|
|
73
|
+
declare const DEFAULT_SNAP_TOLERANCE_PX = 0.5;
|
|
74
|
+
declare const DEFAULT_ASPECT_TOL_PCT = 5;
|
|
75
|
+
declare const DEFAULT_EDGE_CULL_PCT = 20;
|
|
76
|
+
declare const SOLVE_MAX_GUTTER = 8;
|
|
77
|
+
declare const SOLVE_MAX_MARGIN = 24;
|
|
78
|
+
declare const SOLVE_MAX_COLUMN = 48;
|
|
79
|
+
declare const GUTTER_WEIGHT = 8;
|
|
80
|
+
declare const COLUMNS_WEIGHT = 16;
|
|
81
|
+
declare const LADDER_MIN_CELL = 2;
|
|
82
|
+
declare const EDGE_CULL_EPSILON = 0.01;
|
|
83
|
+
declare function snapUnit(value: number, pixelSnap: boolean, tolPx: number): number;
|
|
84
|
+
declare function betterFit(a: Solution, b: Solution): boolean;
|
|
85
|
+
declare function solveMultiples(W: number, c: number, targetMargin: number, targetGutter: number, targetN: number, pixelSnap: boolean, snapTolPx: number): Solution;
|
|
86
|
+
declare function round2(n: number): number;
|
|
87
|
+
declare function cellLadder(W: number, c: number, m: number, g: number, pixelSnap: boolean, snapTolPx: number): CellOption[];
|
|
88
|
+
declare function pickCellOption(ladder: CellOption[], targetN: number): CellOption | null;
|
|
89
|
+
declare function computeGrid(spec: GridSpec): GridResult;
|
|
90
|
+
declare function gridExtent(g: GridResult): GridExtent;
|
|
91
|
+
declare function gridLineSegments(g: GridResult, width: number, height: number, opts?: {
|
|
92
|
+
density?: number;
|
|
93
|
+
edgeCull?: boolean;
|
|
94
|
+
edgeCullPct?: number;
|
|
95
|
+
}): Segment[];
|
|
96
|
+
declare function parseAspect(ratio: string): number;
|
|
97
|
+
|
|
98
|
+
export { COLUMNS_WEIGHT, type CellOption, DEFAULT_ASPECT_TOL_PCT, DEFAULT_CELL_ASPECT, DEFAULT_EDGE_CULL_PCT, DEFAULT_SNAP_TOLERANCE_PX, DEFAULT_TARGET_CELL_COLUMNS, EDGE_CULL_EPSILON, GUTTER_WEIGHT, type GridExtent, type GridResult, type GridSpec, LADDER_MIN_CELL, SOLVE_MAX_COLUMN, SOLVE_MAX_GUTTER, SOLVE_MAX_MARGIN, type Segment, type Solution, betterFit, cellLadder, computeGrid, gridExtent, gridLineSegments, parseAspect, pickCellOption, round2, snapUnit, solveMultiples };
|
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
// components/src/grid/index.ts
|
|
2
|
+
var DEFAULT_TARGET_CELL_COLUMNS = 89;
|
|
3
|
+
var DEFAULT_CELL_ASPECT = 2;
|
|
4
|
+
var DEFAULT_SNAP_TOLERANCE_PX = 0.5;
|
|
5
|
+
var DEFAULT_ASPECT_TOL_PCT = 5;
|
|
6
|
+
var DEFAULT_EDGE_CULL_PCT = 20;
|
|
7
|
+
var SOLVE_MAX_GUTTER = 8;
|
|
8
|
+
var SOLVE_MAX_MARGIN = 24;
|
|
9
|
+
var SOLVE_MAX_COLUMN = 48;
|
|
10
|
+
var GUTTER_WEIGHT = 8;
|
|
11
|
+
var COLUMNS_WEIGHT = 16;
|
|
12
|
+
var LADDER_MIN_CELL = 2;
|
|
13
|
+
var EDGE_CULL_EPSILON = 0.01;
|
|
14
|
+
function snapUnit(value, pixelSnap, tolPx) {
|
|
15
|
+
if (!pixelSnap) return value;
|
|
16
|
+
const snapped = Math.max(1, Math.round(value));
|
|
17
|
+
return Math.abs(value - snapped) <= tolPx + 1e-9 ? snapped : value;
|
|
18
|
+
}
|
|
19
|
+
function betterFit(a, b) {
|
|
20
|
+
if (a.err < b.err - 1e-6) return true;
|
|
21
|
+
if (a.err > b.err + 1e-6) return false;
|
|
22
|
+
return a.N < b.N;
|
|
23
|
+
}
|
|
24
|
+
function solveMultiples(W, c, targetMargin, targetGutter, targetN, pixelSnap, snapTolPx) {
|
|
25
|
+
const relErr = (got, want) => Math.abs(got - want) / Math.max(1, want);
|
|
26
|
+
let best = null;
|
|
27
|
+
for (let g = 1; g <= SOLVE_MAX_GUTTER; g++) {
|
|
28
|
+
for (let m = 0; m <= SOLVE_MAX_MARGIN; m++) {
|
|
29
|
+
for (let k = 1; k <= SOLVE_MAX_COLUMN; k++) {
|
|
30
|
+
const N = 2 * m + c * k + (c - 1) * g;
|
|
31
|
+
const u = snapUnit(W / N, pixelSnap, snapTolPx);
|
|
32
|
+
const gutterPx = g * u;
|
|
33
|
+
const marginPx = m * u + (W - N * u) / 2;
|
|
34
|
+
const err = GUTTER_WEIGHT * relErr(gutterPx, targetGutter) + COLUMNS_WEIGHT * relErr(N, targetN) + relErr(marginPx, targetMargin);
|
|
35
|
+
const candidate = { m, k, g, marginPx, gutterPx, u, N, err };
|
|
36
|
+
if (!best || betterFit(candidate, best)) best = candidate;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return best || {
|
|
41
|
+
m: 3,
|
|
42
|
+
k: 6,
|
|
43
|
+
g: 1,
|
|
44
|
+
marginPx: 0,
|
|
45
|
+
gutterPx: 0,
|
|
46
|
+
u: 0,
|
|
47
|
+
N: 0,
|
|
48
|
+
err: Infinity
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
function round2(n) {
|
|
52
|
+
return Math.round(n * 100) / 100;
|
|
53
|
+
}
|
|
54
|
+
function cellLadder(W, c, m, g, pixelSnap, snapTolPx) {
|
|
55
|
+
const byCell = /* @__PURE__ */ new Map();
|
|
56
|
+
for (let k = 1; k <= SOLVE_MAX_COLUMN; k++) {
|
|
57
|
+
const N = 2 * m + c * k + (c - 1) * g;
|
|
58
|
+
const u = snapUnit(W / N, pixelSnap, snapTolPx);
|
|
59
|
+
if (u < LADDER_MIN_CELL) continue;
|
|
60
|
+
const bleed = Math.abs(W - N * u);
|
|
61
|
+
const key = round2(u);
|
|
62
|
+
const prev = byCell.get(key);
|
|
63
|
+
if (!prev || bleed < prev.bleed) byCell.set(key, { u, k, N, bleed });
|
|
64
|
+
}
|
|
65
|
+
const out = [];
|
|
66
|
+
byCell.forEach((v) => out.push(v));
|
|
67
|
+
return out.sort((a, b) => a.u - b.u);
|
|
68
|
+
}
|
|
69
|
+
function pickCellOption(ladder, targetN) {
|
|
70
|
+
let best = null;
|
|
71
|
+
let bestErr = Infinity;
|
|
72
|
+
for (const opt of ladder) {
|
|
73
|
+
const err = Math.abs(opt.N - targetN);
|
|
74
|
+
if (err < bestErr - 1e-9 || best && err < bestErr + 1e-9 && opt.N < best.N) {
|
|
75
|
+
bestErr = err;
|
|
76
|
+
best = opt;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return best;
|
|
80
|
+
}
|
|
81
|
+
function computeGrid(spec) {
|
|
82
|
+
const W = spec.width;
|
|
83
|
+
const H = spec.height;
|
|
84
|
+
const c = Math.max(1, Math.round(spec.columns));
|
|
85
|
+
const a = spec.cellAspect !== void 0 ? spec.cellAspect : DEFAULT_CELL_ASPECT;
|
|
86
|
+
const snapRows = spec.snapRows !== void 0 ? spec.snapRows : true;
|
|
87
|
+
const pixelSnap = spec.pixelSnap === true;
|
|
88
|
+
const snapTol = spec.snapTolerancePx !== void 0 ? spec.snapTolerancePx : DEFAULT_SNAP_TOLERANCE_PX;
|
|
89
|
+
const aspectTolPct = spec.aspectTolerancePct !== void 0 ? spec.aspectTolerancePct : DEFAULT_ASPECT_TOL_PCT;
|
|
90
|
+
const targetN = Math.max(
|
|
91
|
+
1,
|
|
92
|
+
Math.round(
|
|
93
|
+
spec.targetCellColumns !== void 0 ? spec.targetCellColumns : DEFAULT_TARGET_CELL_COLUMNS
|
|
94
|
+
)
|
|
95
|
+
);
|
|
96
|
+
let solved = null;
|
|
97
|
+
let gm;
|
|
98
|
+
let m;
|
|
99
|
+
if (spec.mode === "auto") {
|
|
100
|
+
solved = solveMultiples(
|
|
101
|
+
W,
|
|
102
|
+
c,
|
|
103
|
+
Math.max(0, spec.targetMarginPx),
|
|
104
|
+
Math.max(1, spec.targetGutterPx),
|
|
105
|
+
targetN,
|
|
106
|
+
pixelSnap,
|
|
107
|
+
snapTol
|
|
108
|
+
);
|
|
109
|
+
gm = solved.g;
|
|
110
|
+
m = solved.m;
|
|
111
|
+
} else {
|
|
112
|
+
gm = Math.max(1, Math.round(spec.gutterCells));
|
|
113
|
+
m = Math.max(0, Math.round(spec.marginCells));
|
|
114
|
+
}
|
|
115
|
+
const ladder = solved ? [] : cellLadder(W, c, m, gm, pixelSnap, snapTol);
|
|
116
|
+
const chosen = solved ? null : pickCellOption(ladder, targetN);
|
|
117
|
+
const k = solved ? solved.k : chosen ? chosen.k : 1;
|
|
118
|
+
const N = 2 * m + c * k + (c - 1) * gm;
|
|
119
|
+
const uExact = W / N;
|
|
120
|
+
const u = snapUnit(uExact, pixelSnap, snapTol);
|
|
121
|
+
const columnWidth = k * u;
|
|
122
|
+
const gutterWidth = gm * u;
|
|
123
|
+
const margin = m * u;
|
|
124
|
+
const columnCells = k;
|
|
125
|
+
const contentWidth = c * columnWidth + (c - 1) * gutterWidth;
|
|
126
|
+
const hRemainder = W - N * u;
|
|
127
|
+
const effectiveMargin = margin + hRemainder / 2;
|
|
128
|
+
const offsetX = 0;
|
|
129
|
+
let rows;
|
|
130
|
+
let cellH;
|
|
131
|
+
if (snapRows) {
|
|
132
|
+
rows = Math.max(1, Math.round(H / (a * uExact)));
|
|
133
|
+
const band = pixelSnap ? Math.min(50, aspectTolPct) / 100 : 0;
|
|
134
|
+
if (band > 0) {
|
|
135
|
+
const lo = Math.max(1, Math.ceil(H / (a * u * (1 + band))));
|
|
136
|
+
const hi = Math.max(lo, Math.floor(H / (a * u * (1 - band))));
|
|
137
|
+
let bestR = 0;
|
|
138
|
+
let bestErr = Infinity;
|
|
139
|
+
for (let r = lo; r <= hi; r++) {
|
|
140
|
+
const snapped = Math.max(1, Math.round(H / r));
|
|
141
|
+
if (Math.abs(H / r - snapped) > snapTol + 1e-9) continue;
|
|
142
|
+
const err = Math.abs(snapped / u / a - 1);
|
|
143
|
+
if (err > band + 1e-9) continue;
|
|
144
|
+
if (err < bestErr - 1e-12 || err < bestErr + 1e-12 && Math.abs(r - rows) < Math.abs(bestR - rows)) {
|
|
145
|
+
bestErr = err;
|
|
146
|
+
bestR = r;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
if (bestR) rows = bestR;
|
|
150
|
+
}
|
|
151
|
+
cellH = snapUnit(H / rows, pixelSnap, snapTol);
|
|
152
|
+
} else {
|
|
153
|
+
cellH = snapUnit(a * u, pixelSnap, snapTol);
|
|
154
|
+
rows = Math.max(1, Math.ceil(H / cellH - 1e-9));
|
|
155
|
+
}
|
|
156
|
+
const vRemainder = H - rows * cellH;
|
|
157
|
+
const rowOffset = vRemainder / 2;
|
|
158
|
+
const actualAspect = cellH / u;
|
|
159
|
+
const deltaPct = (actualAspect / a - 1) * 100;
|
|
160
|
+
return {
|
|
161
|
+
N,
|
|
162
|
+
u,
|
|
163
|
+
solvedM: m,
|
|
164
|
+
solvedK: k,
|
|
165
|
+
solvedG: gm,
|
|
166
|
+
solved: !!solved,
|
|
167
|
+
offsetX,
|
|
168
|
+
cellsPerGutter: gm,
|
|
169
|
+
columnWidth,
|
|
170
|
+
columnCells,
|
|
171
|
+
gutterWidth,
|
|
172
|
+
margin,
|
|
173
|
+
effectiveMargin,
|
|
174
|
+
contentWidth,
|
|
175
|
+
rows,
|
|
176
|
+
cellH,
|
|
177
|
+
rowOffset,
|
|
178
|
+
hRemainder,
|
|
179
|
+
vRemainder,
|
|
180
|
+
actualAspect,
|
|
181
|
+
deltaPct,
|
|
182
|
+
warn: Math.abs(deltaPct) > 1,
|
|
183
|
+
// Ascending in N, which is *descending* in cell size — the ladder is built
|
|
184
|
+
// u-ascending, so this reverses it.
|
|
185
|
+
cellLadder: ladder.map((o) => o.N).sort((x, y) => x - y),
|
|
186
|
+
// The count actually taken: the nearest ladder rung in manual mode, the
|
|
187
|
+
// solver's N in auto.
|
|
188
|
+
cellColumnsTaken: solved ? N : chosen ? chosen.N : targetN
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
function gridExtent(g) {
|
|
192
|
+
const extraCols = g.hRemainder > 0 ? Math.ceil(g.hRemainder / 2 / g.u) : 0;
|
|
193
|
+
const extraRows = g.vRemainder > 0 ? Math.ceil(g.vRemainder / 2 / g.cellH) : 0;
|
|
194
|
+
const startX = g.hRemainder / 2 - extraCols * g.u;
|
|
195
|
+
const startY = g.vRemainder / 2 - extraRows * g.cellH;
|
|
196
|
+
const cols = g.N + 2 * extraCols;
|
|
197
|
+
const rows = g.rows + 2 * extraRows;
|
|
198
|
+
return {
|
|
199
|
+
startX,
|
|
200
|
+
startY,
|
|
201
|
+
cols,
|
|
202
|
+
rows,
|
|
203
|
+
width: cols * g.u,
|
|
204
|
+
height: rows * g.cellH
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
function gridLineSegments(g, width, height, opts) {
|
|
208
|
+
const o = opts || {};
|
|
209
|
+
const d = o.density !== void 0 ? o.density : 1;
|
|
210
|
+
const cullOn = o.edgeCull !== void 0 ? o.edgeCull : true;
|
|
211
|
+
const cullPct = o.edgeCullPct !== void 0 ? o.edgeCullPct : DEFAULT_EDGE_CULL_PCT;
|
|
212
|
+
const cull = Math.min(50, cullPct) / 100;
|
|
213
|
+
const ext = gridExtent(g);
|
|
214
|
+
const right = ext.startX + ext.width;
|
|
215
|
+
const bottom = ext.startY + ext.height;
|
|
216
|
+
const stepX = g.u / d;
|
|
217
|
+
const stepY = g.cellH / d;
|
|
218
|
+
const tolX = stepX * cull;
|
|
219
|
+
const tolY = stepY * cull;
|
|
220
|
+
const lastCol = Math.floor(ext.cols * d + 1e-9);
|
|
221
|
+
const lastRow = Math.floor(ext.rows * d + 1e-9);
|
|
222
|
+
const segments = [];
|
|
223
|
+
for (let i = 0; i <= lastCol; i++) {
|
|
224
|
+
const x = ext.startX + i * stepX;
|
|
225
|
+
if (x < EDGE_CULL_EPSILON || x > width - EDGE_CULL_EPSILON) continue;
|
|
226
|
+
if (cullOn && (x < tolX || width - x < tolX)) continue;
|
|
227
|
+
segments.push([x, ext.startY, x, bottom]);
|
|
228
|
+
}
|
|
229
|
+
for (let j = 0; j <= lastRow; j++) {
|
|
230
|
+
const y = ext.startY + j * stepY;
|
|
231
|
+
if (y < EDGE_CULL_EPSILON || y > height - EDGE_CULL_EPSILON) continue;
|
|
232
|
+
if (cullOn && (y < tolY || height - y < tolY)) continue;
|
|
233
|
+
segments.push([ext.startX, y, right, y]);
|
|
234
|
+
}
|
|
235
|
+
return segments;
|
|
236
|
+
}
|
|
237
|
+
function parseAspect(ratio) {
|
|
238
|
+
const parts = ratio.split(":");
|
|
239
|
+
const w = Number(parts[0]);
|
|
240
|
+
const h = Number(parts[1]);
|
|
241
|
+
return w > 0 && h > 0 ? w / h : 16 / 9;
|
|
242
|
+
}
|
|
243
|
+
export {
|
|
244
|
+
COLUMNS_WEIGHT,
|
|
245
|
+
DEFAULT_ASPECT_TOL_PCT,
|
|
246
|
+
DEFAULT_CELL_ASPECT,
|
|
247
|
+
DEFAULT_EDGE_CULL_PCT,
|
|
248
|
+
DEFAULT_SNAP_TOLERANCE_PX,
|
|
249
|
+
DEFAULT_TARGET_CELL_COLUMNS,
|
|
250
|
+
EDGE_CULL_EPSILON,
|
|
251
|
+
GUTTER_WEIGHT,
|
|
252
|
+
LADDER_MIN_CELL,
|
|
253
|
+
SOLVE_MAX_COLUMN,
|
|
254
|
+
SOLVE_MAX_GUTTER,
|
|
255
|
+
SOLVE_MAX_MARGIN,
|
|
256
|
+
betterFit,
|
|
257
|
+
cellLadder,
|
|
258
|
+
computeGrid,
|
|
259
|
+
gridExtent,
|
|
260
|
+
gridLineSegments,
|
|
261
|
+
parseAspect,
|
|
262
|
+
pickCellOption,
|
|
263
|
+
round2,
|
|
264
|
+
snapUnit,
|
|
265
|
+
solveMultiples
|
|
266
|
+
};
|
|
267
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../components/src/grid/index.ts"],"sourcesContent":["/*\n * This Source Code Form is subject to the terms of the Mozilla Public\n * License, v. 2.0. If a copy of the MPL was not distributed with this\n * file, you can obtain one at https://mozilla.org/MPL/2.0/.\n *\n * Copyright Oxide Computer Company\n */\n\n// Dual-grid math: overlays an aligned column grid and ASCII cell grid on a\n// frame. Margin, column and gutter widths are whole multiples of the cell\n// width `u`, so every edge lands on a cell line:\n//\n// N = 2m + c·k + (c−1)·g (cells across the frame)\n// u = W / N (cell size = base unit)\n// margin = m·u column = k·u gutter = g·u\n//\n// See plugins/dual-grid/README.md for the derivation, solver weight\n// comparisons and measured error tables.\n//\n// This module is consumed both as `@oxide/design-system/grid` and bundled\n// directly into the dual-grid Figma plugin. Keep it dependency-free, with no\n// Figma types and no syntax newer than ES2018 (the plugin engine's ceiling).\n\nexport type GridSpec = {\n columns: number // c — layout column count\n width: number // frame width, px\n height: number // frame height, px\n // Rough target for the number of ASCII cell columns N. Only certain counts\n // are reachable (N steps by c with m and g fixed), so the nearest is taken.\n targetCellColumns?: number\n cellAspect?: number // a — cell height as a multiple of cell width\n // Snap the row count so rows fill the height exactly; off, the cell aspect\n // is kept exact and the last row runs off the bottom edge instead.\n snapRows?: boolean\n // Round the cell size to whole pixels when within snapTolerancePx. The\n // leftover (W − N·u) is split between the margins. Off, the cell divides\n // the frame exactly and there is no bleed.\n pixelSnap?: boolean\n // Maximum rounding distance per cell in pixels. Total horizontal bleed is\n // bounded by N times this tolerance. 0 disables snapping; 0.5 always snaps.\n snapTolerancePx?: number\n // With snapRows and pixelSnap on, allow this percentage of aspect deviation\n // to find an integer row height. 0 keeps the original row count.\n aspectTolerancePct?: number\n} & (\n | {\n // Margin and gutter are given directly as cell counts; column width is\n // derived from targetCellColumns via the ladder.\n mode: 'manual'\n marginCells: number // m — margin width in cells\n gutterCells: number // g — cells per gutter\n }\n | {\n // The solver finds the whole-cell multiples (m, k, g) whose margin,\n // gutter and column count come closest to the pixel targets.\n mode: 'auto'\n targetMarginPx: number\n targetGutterPx: number\n }\n)\n\nexport interface GridResult {\n N: number // whole cells that fit across the frame\n u: number // cell size = base unit\n solvedM: number // multiples actually used (from the spec or the solver)\n solvedK: number\n solvedG: number\n solved: boolean // whether the solver chose them\n offsetX: number // phase of the cell grid, so x = margin lands on a boundary\n cellsPerGutter: number\n columnWidth: number\n columnCells: number // columnWidth in whole cells (= k)\n gutterWidth: number\n margin: number\n effectiveMargin: number\n contentWidth: number\n rows: number\n cellH: number\n rowOffset: number\n hRemainder: number // leftover width from snapping u, split between the margins\n vRemainder: number // leftover height — split top/bottom (snapRows) or a partial row at the bottom\n actualAspect: number\n deltaPct: number\n warn: boolean\n cellLadder: number[] // reachable cell-column counts, ascending (manual only)\n cellColumnsTaken: number // the rung actually taken (manual), or N (auto)\n}\n\nexport interface Solution {\n m: number\n k: number\n g: number\n marginPx: number\n gutterPx: number\n u: number\n N: number\n err: number\n}\n\nexport interface CellOption {\n u: number // exact cell size\n k: number // cells per column that produces it\n N: number\n bleed: number // px left over after rounding u — padding that lands in the margins\n}\n\n// The full-bleed extent of the cell grid: the N × rows grid plus enough whole\n// cells on every side to cover the snap's remainder margins, so the grid\n// fills the frame edge to edge. Whole units keep everything aligned; the\n// overhang is clipped by the frame.\nexport interface GridExtent {\n startX: number\n startY: number\n cols: number\n rows: number\n width: number\n height: number\n}\n\nexport type Segment = [number, number, number, number] // x1, y1, x2, y2\n\n// 89 = 2(3) + 12(6) + 11(1), i.e. k=6 — an exact rung for the default margin,\n// gutter and column count at 1920 wide, giving a 21.57px cell, 25 rows and a\n// 129px column.\nexport const DEFAULT_TARGET_CELL_COLUMNS = 89\nexport const DEFAULT_CELL_ASPECT = 2\n// Half a pixel accepts any rounding distance. Lower tolerances preserve more\n// fractional sizes and limit bleed; 0.1 caps it at N/10 pixels.\nexport const DEFAULT_SNAP_TOLERANCE_PX = 0.5\n// Allow 5% aspect deviation when searching for an integer row height.\n// For example, 24 rows of 45px fill a 1080px frame exactly.\nexport const DEFAULT_ASPECT_TOL_PCT = 5\n// 20% of a step: wide enough to catch the few-px inset the pixel snap leaves\n// (3px on a 22px cell is 13.6%), narrow enough that a real interior line — a\n// full step from the edge — can never be caught.\nexport const DEFAULT_EDGE_CULL_PCT = 20\n\n// Search all ~10k combinations on each edit to find the best match within these bounds.\nexport const SOLVE_MAX_GUTTER = 8\nexport const SOLVE_MAX_MARGIN = 24\nexport const SOLVE_MAX_COLUMN = 48\n// Prioritise column count to preserve cell density. Gutter width is g*W/N with\n// integer g, so the two targets may conflict. Report gutter mismatches rather\n// than substantially changing N. Margin has weight 1 and is quantised in\n// cell-width increments.\nexport const GUTTER_WEIGHT = 8\nexport const COLUMNS_WEIGHT = 16\n\n// Cell sizes below this are not a usable design grid, and enumerating them only\n// crowds the options.\nexport const LADDER_MIN_CELL = 2\n\n// Lines on or beyond the frame boundary (to within this epsilon) are always\n// culled as doubled frame edges, whatever the edge-cull options say.\nexport const EDGE_CULL_EPSILON = 0.01\n\n// Round to whole pixels only within tolerance. computeGrid, the solver and the\n// ladder must all use this function so previews and generated grids agree.\nexport function snapUnit(value: number, pixelSnap: boolean, tolPx: number): number {\n if (!pixelSnap) return value\n const snapped = Math.max(1, Math.round(value))\n // The epsilon keeps an exactly-on-tolerance value (and a tolerance of 0.5,\n // where |value − round(value)| can equal 0.5 up to float error) snapping.\n return Math.abs(value - snapped) <= tolPx + 1e-9 ? snapped : value\n}\n\n// Treat errors within 1e-6 as ties and prefer the coarser grid.\nexport function betterFit(a: Solution, b: Solution): boolean {\n if (a.err < b.err - 1e-6) return true\n if (a.err > b.err + 1e-6) return false\n return a.N < b.N\n}\n\n// Finds the whole-cell multiples (m, k, g) whose margin, gutter and column count\n// come closest to the three requested values.\n//\n// Whole-cell multiples preserve alignment. Inputs are weighted targets, not\n// hard constraints, so a grid is returned even when no exact match exists.\nexport function solveMultiples(\n W: number,\n c: number,\n targetMargin: number,\n targetGutter: number,\n targetN: number,\n pixelSnap: boolean,\n snapTolPx: number,\n): Solution {\n const relErr = (got: number, want: number) => Math.abs(got - want) / Math.max(1, want)\n\n let best: Solution | null = null\n\n for (let g = 1; g <= SOLVE_MAX_GUTTER; g++) {\n for (let m = 0; m <= SOLVE_MAX_MARGIN; m++) {\n for (let k = 1; k <= SOLVE_MAX_COLUMN; k++) {\n const N = 2 * m + c * k + (c - 1) * g\n // Must snap exactly as computeGrid will, or the solved fit drifts once\n // the pixel snap rounds the cell size.\n const u = snapUnit(W / N, pixelSnap, snapTolPx)\n\n // Include half the rounding remainder in the margin to account for centring.\n const gutterPx = g * u\n const marginPx = m * u + (W - N * u) / 2\n\n const err =\n GUTTER_WEIGHT * relErr(gutterPx, targetGutter) +\n COLUMNS_WEIGHT * relErr(N, targetN) +\n relErr(marginPx, targetMargin)\n const candidate: Solution = { m, k, g, marginPx, gutterPx, u, N, err }\n\n // Prefer the closest fit, then the coarsest grid on a tie.\n if (!best || betterFit(candidate, best)) best = candidate\n }\n }\n }\n\n return (\n best || {\n m: 3,\n k: 6,\n g: 1,\n marginPx: 0,\n gutterPx: 0,\n u: 0,\n N: 0,\n err: Infinity,\n }\n )\n}\n\n// Two decimals is the resolution at which ladder rungs are considered distinct\n// (it is also the resolution the plugin panel displays).\nexport function round2(n: number): number {\n return Math.round(n * 100) / 100\n}\n\n// The manual-mode cell ladder. With c, m and g fixed, k is the only free\n// variable in N = 2m + ck + (c−1)g. Possible counts step by c, giving a\n// discrete set of cell sizes u = W/N. Aspect deviation is reported, not used\n// to reject sizes.\nexport function cellLadder(\n W: number,\n c: number,\n m: number,\n g: number,\n pixelSnap: boolean,\n snapTolPx: number,\n): CellOption[] {\n const byCell = new Map<number, CellOption>()\n for (let k = 1; k <= SOLVE_MAX_COLUMN; k++) {\n const N = 2 * m + c * k + (c - 1) * g\n const u = snapUnit(W / N, pixelSnap, snapTolPx)\n if (u < LADDER_MIN_CELL) continue\n\n const bleed = Math.abs(W - N * u)\n // Rounding u to whole pixels collapses several adjacent k onto the same cell\n // size; keep whichever leaves the least bleed, since that is the one that\n // fills the frame most cleanly.\n const key = round2(u)\n const prev = byCell.get(key)\n if (!prev || bleed < prev.bleed) byCell.set(key, { u, k, N, bleed })\n }\n const out: CellOption[] = []\n byCell.forEach((v) => out.push(v))\n return out.sort((a, b) => a.u - b.u)\n}\n\n// Nearest available column count. Ties prefer fewer columns, matching the solver.\nexport function pickCellOption(ladder: CellOption[], targetN: number): CellOption | null {\n let best: CellOption | null = null\n let bestErr = Infinity\n for (const opt of ladder) {\n const err = Math.abs(opt.N - targetN)\n if (err < bestErr - 1e-9 || (best && err < bestErr + 1e-9 && opt.N < best.N)) {\n bestErr = err\n best = opt\n }\n }\n return best\n}\n\n// The mathematical core. Dimensions are measured in cells; cell size is\n// derived from the frame width. All pixel sizes are reported back in the\n// result.\nexport function computeGrid(spec: GridSpec): GridResult {\n const W = spec.width\n const H = spec.height\n const c = Math.max(1, Math.round(spec.columns))\n const a = spec.cellAspect !== undefined ? spec.cellAspect : DEFAULT_CELL_ASPECT\n const snapRows = spec.snapRows !== undefined ? spec.snapRows : true\n const pixelSnap = spec.pixelSnap === true\n const snapTol =\n spec.snapTolerancePx !== undefined ? spec.snapTolerancePx : DEFAULT_SNAP_TOLERANCE_PX\n // The aspect band as a share, capped at 50%. 0 disables the row-count search.\n const aspectTolPct =\n spec.aspectTolerancePct !== undefined ? spec.aspectTolerancePct : DEFAULT_ASPECT_TOL_PCT\n const targetN = Math.max(\n 1,\n Math.round(\n spec.targetCellColumns !== undefined\n ? spec.targetCellColumns\n : DEFAULT_TARGET_CELL_COLUMNS,\n ),\n )\n\n // In auto mode the multiples come from the solver rather than the spec.\n // Manual: the gutter sets the scale, the margin is measured against it, and the\n // column width is derived. Rounding keeps every part a whole number of cells,\n // which is what holds the two grids in phase.\n let solved: Solution | null = null\n let gm: number\n let m: number\n if (spec.mode === 'auto') {\n solved = solveMultiples(\n W,\n c,\n Math.max(0, spec.targetMarginPx),\n Math.max(1, spec.targetGutterPx),\n targetN,\n pixelSnap,\n snapTol,\n )\n gm = solved.g\n m = solved.m\n } else {\n gm = Math.max(1, Math.round(spec.gutterCells))\n m = Math.max(0, Math.round(spec.marginCells))\n }\n // Manual: the column count is picked straight off the ladder. The ladder depends\n // on c, m, g, the pixel snap and its tolerance, so it is rebuilt whenever any of\n // those move and the request is re-snapped by *count* — 197 cells stays ≈197\n // across a margin change rather than sliding to whatever sits at the same\n // ladder index.\n const ladder = solved ? [] : cellLadder(W, c, m, gm, pixelSnap, snapTol)\n const chosen = solved ? null : pickCellOption(ladder, targetN)\n const k = solved ? solved.k : chosen ? chosen.k : 1\n\n const N = 2 * m + c * k + (c - 1) * gm\n const uExact = W / N\n const u = snapUnit(uExact, pixelSnap, snapTol)\n\n const columnWidth = k * u\n const gutterWidth = gm * u\n const margin = m * u\n const columnCells = k\n const contentWidth = c * columnWidth + (c - 1) * gutterWidth\n\n // Rounding u leaves a remainder; split evenly it shifts both grids by the same\n // amount, so they stay in phase.\n const hRemainder = W - N * u\n const effectiveMargin = margin + hRemainder / 2\n const offsetX = 0 // centring handles the phase; no offset needed\n\n let rows: number\n let cellH: number\n if (snapRows) {\n // Counted off the exact cell, not the snapped one, so snapping u to a whole\n // pixel cannot flip the row count the fractional grid chose (at the borderline\n // it otherwise does: u 22.07 → 24 rows, u 22 → 25).\n rows = Math.max(1, Math.round(H / (a * uExact)))\n // Search row counts within the aspect tolerance for a height that snaps.\n // Prefer the closest aspect ratio; a divisor of H gives an exact vertical fit.\n const band = pixelSnap ? Math.min(50, aspectTolPct) / 100 : 0\n if (band > 0) {\n const lo = Math.max(1, Math.ceil(H / (a * u * (1 + band))))\n const hi = Math.max(lo, Math.floor(H / (a * u * (1 - band))))\n let bestR = 0\n let bestErr = Infinity\n for (let r = lo; r <= hi; r++) {\n const snapped = Math.max(1, Math.round(H / r))\n if (Math.abs(H / r - snapped) > snapTol + 1e-9) continue\n const err = Math.abs(snapped / u / a - 1)\n if (err > band + 1e-9) continue\n // Closest to the aspect ask wins; ties go to the natural row count.\n if (\n err < bestErr - 1e-12 ||\n (err < bestErr + 1e-12 && Math.abs(r - rows) < Math.abs(bestR - rows))\n ) {\n bestErr = err\n bestR = r\n }\n }\n if (bestR) rows = bestR\n }\n // H/rows divides H exactly; the whole-pixel snap trades that for a small\n // remainder, split top and bottom like the horizontal one.\n cellH = snapUnit(H / rows, pixelSnap, snapTol)\n } else {\n // Keep the aspect exact and let the last row run off the bottom edge rather\n // than stopping the grid short — the overhang is clipped by the frame, the\n // same way the side edges already bleed. Snapping is the opposite trade:\n // exact fit, approximate aspect.\n cellH = snapUnit(a * u, pixelSnap, snapTol)\n rows = Math.max(1, Math.ceil(H / cellH - 1e-9))\n }\n const vRemainder = H - rows * cellH\n // Same trick vertically: centre the leftover so the rows stay in phase.\n const rowOffset = vRemainder / 2\n\n const actualAspect = cellH / u\n const deltaPct = (actualAspect / a - 1) * 100\n\n return {\n N,\n u,\n solvedM: m,\n solvedK: k,\n solvedG: gm,\n solved: !!solved,\n offsetX,\n cellsPerGutter: gm,\n columnWidth,\n columnCells,\n gutterWidth,\n margin,\n effectiveMargin,\n contentWidth,\n rows,\n cellH,\n rowOffset,\n hRemainder,\n vRemainder,\n actualAspect,\n deltaPct,\n warn: Math.abs(deltaPct) > 1,\n // Ascending in N, which is *descending* in cell size — the ladder is built\n // u-ascending, so this reverses it.\n cellLadder: ladder.map((o) => o.N).sort((x, y) => x - y),\n // The count actually taken: the nearest ladder rung in manual mode, the\n // solver's N in auto.\n cellColumnsTaken: solved ? N : chosen ? chosen.N : targetN,\n }\n}\n\n// Extends the grid by whole cells past its own bounds so the rounding remainder\n// at the frame edges is covered too; the frame clips the overhang.\nexport function gridExtent(g: GridResult): GridExtent {\n const extraCols = g.hRemainder > 0 ? Math.ceil(g.hRemainder / 2 / g.u) : 0\n const extraRows = g.vRemainder > 0 ? Math.ceil(g.vRemainder / 2 / g.cellH) : 0\n const startX = g.hRemainder / 2 - extraCols * g.u\n const startY = g.vRemainder / 2 - extraRows * g.cellH\n const cols = g.N + 2 * extraCols\n const rows = g.rows + 2 * extraRows\n return {\n startX,\n startY,\n cols,\n rows,\n width: cols * g.u,\n height: rows * g.cellH,\n }\n}\n\n// The cell grid as drawable line segments over the full-bleed extent. Density\n// subdivides (2, 3) or coarsens (0.5, 0.25) the cell. Lines on or beyond the\n// frame boundary are always omitted; edge cull additionally removes interior\n// lines within edgeCullPct of a step from the boundary, to avoid darkening the\n// frame edge. The percentage is capped at half a step so it can never reach\n// two adjacent lines.\nexport function gridLineSegments(\n g: GridResult,\n width: number,\n height: number,\n opts?: { density?: number; edgeCull?: boolean; edgeCullPct?: number },\n): Segment[] {\n const o = opts || {}\n const d = o.density !== undefined ? o.density : 1\n const cullOn = o.edgeCull !== undefined ? o.edgeCull : true\n const cullPct = o.edgeCullPct !== undefined ? o.edgeCullPct : DEFAULT_EDGE_CULL_PCT\n const cull = Math.min(50, cullPct) / 100\n\n const ext = gridExtent(g)\n const right = ext.startX + ext.width\n const bottom = ext.startY + ext.height\n\n const stepX = g.u / d\n const stepY = g.cellH / d\n\n const tolX = stepX * cull\n const tolY = stepY * cull\n\n // Coarse densities can leave a fractional line count; the loop floor just\n // stops at the last coarse line inside the extent.\n const lastCol = Math.floor(ext.cols * d + 1e-9)\n const lastRow = Math.floor(ext.rows * d + 1e-9)\n\n const segments: Segment[] = []\n for (let i = 0; i <= lastCol; i++) {\n const x = ext.startX + i * stepX\n if (x < EDGE_CULL_EPSILON || x > width - EDGE_CULL_EPSILON) continue\n if (cullOn && (x < tolX || width - x < tolX)) continue\n segments.push([x, ext.startY, x, bottom])\n }\n for (let j = 0; j <= lastRow; j++) {\n const y = ext.startY + j * stepY\n if (y < EDGE_CULL_EPSILON || y > height - EDGE_CULL_EPSILON) continue\n if (cullOn && (y < tolY || height - y < tolY)) continue\n segments.push([ext.startX, y, right, y])\n }\n return segments\n}\n\nexport function parseAspect(ratio: string): number {\n const parts = ratio.split(':')\n const w = Number(parts[0])\n const h = Number(parts[1])\n return w > 0 && h > 0 ? w / h : 16 / 9\n}\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oxide/design-system",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.7.0-canary.e63e89e",
|
|
4
4
|
"description": "Home of reusable design assets and token for oxide internal sites",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
"./styles/*": "./styles/*",
|
|
9
9
|
"./components/*.css": "./dist/*.css",
|
|
10
10
|
"./asciidoc": "./dist/components/src/asciidoc/index.js",
|
|
11
|
+
"./grid": "./dist/components/src/grid/index.js",
|
|
11
12
|
"./syntax": "./dist/components/src/syntax/index.js",
|
|
12
13
|
"./ui": "./dist/components/src/ui/index.js",
|
|
13
14
|
"./icons": "./dist/icons/index.js",
|
|
@@ -25,6 +26,10 @@
|
|
|
25
26
|
"color-gen:dev": "vite --config color-gen/vite.config.ts color-gen",
|
|
26
27
|
"color-gen:apply": "tsx color-gen/apply-colors.ts",
|
|
27
28
|
"preview:dev": "vite --config preview/vite.config.ts",
|
|
29
|
+
"dual-grid:build": "npm --prefix plugins/dual-grid run build",
|
|
30
|
+
"dual-grid:test": "npm --prefix plugins/dual-grid run test",
|
|
31
|
+
"token-sync:dev": "npm --prefix plugins/token-sync run dev",
|
|
32
|
+
"token-sync:build": "npm --prefix plugins/token-sync run build",
|
|
28
33
|
"design-md": "node scripts/design-md.mjs",
|
|
29
34
|
"design-md:check": "node scripts/design-md.mjs --check"
|
|
30
35
|
},
|