@transtyle/exporter-primeng 0.1.0-alpha.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/package.json +43 -0
- package/src/archetypes.js +162 -0
- package/src/descriptors.js +468 -0
- package/src/index.js +447 -0
- package/src/ramp.js +55 -0
- package/src/severity-grid.js +87 -0
- package/src/surface-coverage.js +164 -0
- package/surface-inventory.json +21474 -0
package/package.json
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@transtyle/exporter-primeng",
|
|
3
|
+
"version": "0.1.0-alpha.0",
|
|
4
|
+
"description": "Transtyle exporter for PrimeNG design-token presets (definePreset over Aura). Not yet registered in the CLI — see docs/plan/component-tier.md C6.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./src/index.js",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": "./src/index.js"
|
|
9
|
+
},
|
|
10
|
+
"dependencies": {
|
|
11
|
+
"@transtyle/ir": "0.1.0-alpha.0"
|
|
12
|
+
},
|
|
13
|
+
"transtyle": {
|
|
14
|
+
"kind": "exporter",
|
|
15
|
+
"name": "primeng",
|
|
16
|
+
"irSpec": "v0-draft",
|
|
17
|
+
"pluginApi": "0",
|
|
18
|
+
"targets": {
|
|
19
|
+
"primeng": [
|
|
20
|
+
"*"
|
|
21
|
+
]
|
|
22
|
+
},
|
|
23
|
+
"modes": [
|
|
24
|
+
"color-scheme"
|
|
25
|
+
],
|
|
26
|
+
"capabilities": [
|
|
27
|
+
"build"
|
|
28
|
+
]
|
|
29
|
+
},
|
|
30
|
+
"files": [
|
|
31
|
+
"src",
|
|
32
|
+
"surface-inventory.json"
|
|
33
|
+
],
|
|
34
|
+
"publishConfig": { "access": "public" },
|
|
35
|
+
"repository": {
|
|
36
|
+
"type": "git",
|
|
37
|
+
"url": "git+https://github.com/transtyle/transtyle.git",
|
|
38
|
+
"directory": "packages/exporter-primeng"
|
|
39
|
+
},
|
|
40
|
+
"homepage": "https://github.com/transtyle/transtyle#readme",
|
|
41
|
+
"bugs": "https://github.com/transtyle/transtyle/issues",
|
|
42
|
+
"license": "MIT"
|
|
43
|
+
}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Exporter-private archetype helpers (docs/proposals/0002-component-theming-primeng.md
|
|
3
|
+
* §2.3, §2.8, §4; docs/plan/component-tier.md C5). Per C1's cross-ecosystem
|
|
4
|
+
* study (docs/findings/component-tier-study.md), `field`/`list`/`navigation`/
|
|
5
|
+
* `overlay` are PrimeNG-specific groupings, not convergent vocabulary — they
|
|
6
|
+
* live here, permanently, reading straight from existing catalog cells.
|
|
7
|
+
* Nothing here is a catalog addition; every value below is `get(map, ...)`
|
|
8
|
+
* against a slot that already exists in `semantic.*`.
|
|
9
|
+
*
|
|
10
|
+
* Each helper returns `{ structural, colorScheme }` — verified against real
|
|
11
|
+
* PrimeNG source (`aura/base/index.ts`, fetched 2026-07-21), which itself
|
|
12
|
+
* splits every one of these groups the same way: a mode-invariant object
|
|
13
|
+
* (padding/gap/radius/focusRing-shape) at the top level, and a SEPARATE
|
|
14
|
+
* `colorScheme.{light,dark}.<group>` object for anything color-ish. This
|
|
15
|
+
* isn't a stylistic choice on our end — PrimeNG's own DesignTokens TypeScript
|
|
16
|
+
* types reject color fields on the top-level object and reject dimensional
|
|
17
|
+
* fields on the colorScheme-scoped one, so index.js calls each helper once
|
|
18
|
+
* per mode and assembles both halves into the shape PrimeNG's types require.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
const get = (map, path) => map.get(`semantic.${path}`)?.value;
|
|
22
|
+
/** Component-tier read (AL2) — the promoted shared interactive-control slots. */
|
|
23
|
+
const comp = (map, path) => map.get(`component.${path}`)?.value;
|
|
24
|
+
|
|
25
|
+
export function field(map) {
|
|
26
|
+
return {
|
|
27
|
+
structural: {
|
|
28
|
+
// AL2: the shared control geometry is catalog vocabulary now, so an
|
|
29
|
+
// authored `component.control.*` reaches PrimeNG's formField (and, via
|
|
30
|
+
// buildButton, its Button) exactly as it reaches Bootstrap's
|
|
31
|
+
// $input-btn-*. Unauthored, these resolve to the same space.4/space.2/
|
|
32
|
+
// radius.control this helper read directly before.
|
|
33
|
+
paddingX: comp(map, 'control.padding-x'),
|
|
34
|
+
paddingY: comp(map, 'control.padding-y'),
|
|
35
|
+
borderRadius: comp(map, 'control.radius'),
|
|
36
|
+
transitionDuration: get(map, 'duration.fast'),
|
|
37
|
+
sm: { paddingX: get(map, 'space.3'), paddingY: get(map, 'space.1') },
|
|
38
|
+
lg: { paddingX: get(map, 'space.5'), paddingY: get(map, 'space.3') },
|
|
39
|
+
},
|
|
40
|
+
colorScheme: {
|
|
41
|
+
background: get(map, 'color.elevation.0.surface'),
|
|
42
|
+
disabledBackground: get(map, 'color.neutral.tint'),
|
|
43
|
+
filledBackground: get(map, 'color.elevation.1.surface'),
|
|
44
|
+
borderColor: get(map, 'color.neutral.outline'),
|
|
45
|
+
hoverBorderColor: get(map, 'color.neutral.outline-hover'),
|
|
46
|
+
focusBorderColor: get(map, 'color.primary.solid'),
|
|
47
|
+
invalidBorderColor: get(map, 'color.danger.solid'),
|
|
48
|
+
color: get(map, 'color.text.base'),
|
|
49
|
+
disabledColor: get(map, 'color.text.disabled'),
|
|
50
|
+
placeholderColor: get(map, 'color.text.muted'),
|
|
51
|
+
shadow: 'none', // no direct grid cell for a form-field elevation shadow; PrimeNG's own Aura default is flat too
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export function list(map) {
|
|
57
|
+
return {
|
|
58
|
+
structural: {
|
|
59
|
+
padding: get(map, 'space.1'),
|
|
60
|
+
gap: get(map, 'space.0'),
|
|
61
|
+
header: { padding: get(map, 'space.2') },
|
|
62
|
+
option: { padding: get(map, 'space.2'), borderRadius: get(map, 'radius.control') },
|
|
63
|
+
optionGroup: {
|
|
64
|
+
padding: get(map, 'space.2'),
|
|
65
|
+
fontWeight: String(get(map, 'type.weight.semibold')),
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
colorScheme: {
|
|
69
|
+
option: {
|
|
70
|
+
focusBackground: get(map, 'color.primary.tint'),
|
|
71
|
+
selectedBackground: get(map, 'color.primary.tint-active'),
|
|
72
|
+
selectedFocusBackground: get(map, 'color.primary.tint-active'),
|
|
73
|
+
color: get(map, 'color.text.base'),
|
|
74
|
+
focusColor: get(map, 'color.text.base'),
|
|
75
|
+
selectedColor: get(map, 'color.primary.on-tint'),
|
|
76
|
+
selectedFocusColor: get(map, 'color.primary.on-tint'),
|
|
77
|
+
},
|
|
78
|
+
optionGroup: { background: 'transparent', color: get(map, 'color.text.muted') },
|
|
79
|
+
},
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export function navigation(map) {
|
|
84
|
+
return {
|
|
85
|
+
structural: {
|
|
86
|
+
list: { padding: get(map, 'space.1'), gap: get(map, 'space.0') },
|
|
87
|
+
item: {
|
|
88
|
+
padding: get(map, 'space.2'),
|
|
89
|
+
borderRadius: get(map, 'radius.control'),
|
|
90
|
+
gap: get(map, 'space.2'),
|
|
91
|
+
},
|
|
92
|
+
submenuLabel: {
|
|
93
|
+
padding: get(map, 'space.2'),
|
|
94
|
+
fontWeight: String(get(map, 'type.weight.semibold')),
|
|
95
|
+
},
|
|
96
|
+
},
|
|
97
|
+
colorScheme: {
|
|
98
|
+
item: {
|
|
99
|
+
focusBackground: get(map, 'color.primary.tint'),
|
|
100
|
+
activeBackground: get(map, 'color.primary.tint-active'),
|
|
101
|
+
color: get(map, 'color.text.base'),
|
|
102
|
+
focusColor: get(map, 'color.text.base'),
|
|
103
|
+
activeColor: get(map, 'color.text.base'),
|
|
104
|
+
icon: { color: get(map, 'color.text.muted'), focusColor: get(map, 'color.text.base') },
|
|
105
|
+
},
|
|
106
|
+
submenuLabel: { background: 'transparent', color: get(map, 'color.text.muted') },
|
|
107
|
+
},
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/** kind: 'popover' | 'modal' | 'navigation' | 'select' — each picks an elevation level. */
|
|
112
|
+
const OVERLAY_LEVEL = { select: 2, popover: 2, modal: 3, navigation: 2 };
|
|
113
|
+
|
|
114
|
+
export function overlay(map, kind, ctx) {
|
|
115
|
+
const n = OVERLAY_LEVEL[kind] ?? 2;
|
|
116
|
+
const shadow = map.get(`semantic.color.elevation.${n}.shadow`)?.value;
|
|
117
|
+
const shadowStr = shadow
|
|
118
|
+
? `${shadow.offsetX} ${shadow.offsetY} ${shadow.blur} ${shadow.spread} ${ctx.formatColor(shadow.color)}`
|
|
119
|
+
: undefined;
|
|
120
|
+
return {
|
|
121
|
+
// borderRadius/shadow are mode-invariant at this position in PrimeNG's own
|
|
122
|
+
// type (verified: aura/base's top-level `overlay.*` carries no background/color at
|
|
123
|
+
// all) — `shadow` is computed from whichever map is passed; callers pass the light
|
|
124
|
+
// map once for this half, matching PrimeNG's own single (non-mode-varying) shadow.
|
|
125
|
+
// `padding` is NOT part of this object — verified it belongs on each component's
|
|
126
|
+
// own `content.padding` (Popover/Dialog), not on the shared semantic.overlay.* shape.
|
|
127
|
+
structural: {
|
|
128
|
+
...(kind !== 'navigation' && {
|
|
129
|
+
borderRadius: get(map, kind === 'modal' ? 'radius.container' : 'radius.field'),
|
|
130
|
+
}),
|
|
131
|
+
shadow: shadowStr,
|
|
132
|
+
},
|
|
133
|
+
padding:
|
|
134
|
+
kind === 'navigation' || kind === 'select'
|
|
135
|
+
? undefined
|
|
136
|
+
: get(map, kind === 'modal' ? 'space.6' : 'space.3'),
|
|
137
|
+
// navigation has no colorScheme-scoped entry in real PrimeNG (Menu's root reads
|
|
138
|
+
// `content.*` for its own background/color instead) — callers skip this for 'navigation'.
|
|
139
|
+
colorScheme:
|
|
140
|
+
kind === 'navigation'
|
|
141
|
+
? undefined
|
|
142
|
+
: {
|
|
143
|
+
background: get(map, `color.elevation.${n}.surface`),
|
|
144
|
+
borderColor: get(map, 'color.neutral.outline'),
|
|
145
|
+
color: get(map, 'color.text.base'),
|
|
146
|
+
},
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/** Card/Panel-style containers (§4: "content needs no helper" — inline, kept as one function for call-site symmetry). */
|
|
151
|
+
export function content(map) {
|
|
152
|
+
return {
|
|
153
|
+
structural: { borderRadius: get(map, 'radius.field') },
|
|
154
|
+
colorScheme: {
|
|
155
|
+
background: get(map, 'color.elevation.1.surface'),
|
|
156
|
+
hoverBackground: get(map, 'color.elevation.1.surface'),
|
|
157
|
+
borderColor: get(map, 'color.neutral.outline'),
|
|
158
|
+
color: get(map, 'color.text.base'),
|
|
159
|
+
hoverColor: get(map, 'color.text.base'),
|
|
160
|
+
},
|
|
161
|
+
};
|
|
162
|
+
}
|
|
@@ -0,0 +1,468 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-component builders (docs/plan/component-tier.md C4). Each reads either
|
|
3
|
+
* `mapSeverityGrid` (severity-colored components) or a plain semantic alias
|
|
4
|
+
* (primary-anchored components) or an archetype helper (field/list/navigation/
|
|
5
|
+
* overlay consumers) — zero per-component mapping *logic*, only which cells
|
|
6
|
+
* a component's real shape (verified against source, fetched 2026-07-21) asks
|
|
7
|
+
* for. See docs/worklog/2026-07-21-component-tier-c3-c5.md for what was
|
|
8
|
+
* verified and what this deliberately does not cover yet.
|
|
9
|
+
*
|
|
10
|
+
* Every builder takes `(light, dark, ctx)` — two per-mode token maps — and
|
|
11
|
+
* returns `{ tokens, coverage }` with `tokens.colorScheme = { light, dark }`
|
|
12
|
+
* wherever the real PrimeNG type requires that split (verified: it's not
|
|
13
|
+
* optional — PrimeNG's own DesignTokens types reject an unwrapped colorScheme
|
|
14
|
+
* object, confirmed by compiling the emitted preset against them directly).
|
|
15
|
+
*
|
|
16
|
+
* A real, corrective finding from verifying source rather than assuming
|
|
17
|
+
* proposal 0002's ~25-35 estimate (§5.2): most components proposal 0002
|
|
18
|
+
* expected to be severity-colored are NOT. Only Button, Tag, Badge, Message,
|
|
19
|
+
* and InlineMessage actually carry the `variant x severity x part` (or flat
|
|
20
|
+
* `severity x part`) shape. Checkbox, RadioButton, ToggleSwitch, SelectButton,
|
|
21
|
+
* ToggleButton, and SplitButton are `field`-shaped (single primary + neutral
|
|
22
|
+
* surfaces, no severity axis). ProgressBar, Slider, Knob, and Rating are
|
|
23
|
+
* primary-anchored only — and, verified against source, carry NO colorScheme
|
|
24
|
+
* block at all; their real Aura default literally writes token-reference
|
|
25
|
+
* strings like `'{primary.color}'`/`'{text.muted.color}'` rather than
|
|
26
|
+
* resolving a color, and PrimeNG's own alias engine resolves those per the
|
|
27
|
+
* active mode — so this file reuses that exact convention for them (a
|
|
28
|
+
* resolved literal would be mode-wrong: there's no per-mode slot to put it
|
|
29
|
+
* in). Chip has no brand color at all (plain neutral surface, not covered
|
|
30
|
+
* in this pass).
|
|
31
|
+
*/
|
|
32
|
+
|
|
33
|
+
import { mapSeverityGrid } from './severity-grid.js';
|
|
34
|
+
import { field, list, navigation, overlay, content } from './archetypes.js';
|
|
35
|
+
|
|
36
|
+
const get = (map, path) => map.get(`semantic.${path}`)?.value;
|
|
37
|
+
|
|
38
|
+
// ---------- severity-colored components (the generic mapper, called once per mode) ----------
|
|
39
|
+
|
|
40
|
+
function buildButtonColorScheme(map) {
|
|
41
|
+
const g = mapSeverityGrid(map, {
|
|
42
|
+
variants: [
|
|
43
|
+
{
|
|
44
|
+
name: 'root',
|
|
45
|
+
parts: {
|
|
46
|
+
background: 'solid',
|
|
47
|
+
hoverBackground: 'solid-hover',
|
|
48
|
+
activeBackground: 'solid-active',
|
|
49
|
+
borderColor: 'solid',
|
|
50
|
+
hoverBorderColor: 'solid-hover',
|
|
51
|
+
activeBorderColor: 'solid-active',
|
|
52
|
+
color: 'on-solid',
|
|
53
|
+
hoverColor: 'on-solid',
|
|
54
|
+
activeColor: 'on-solid',
|
|
55
|
+
focusRingColor: 'solid',
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
name: 'outlined',
|
|
60
|
+
parts: {
|
|
61
|
+
hoverBackground: 'tint',
|
|
62
|
+
activeBackground: 'tint-active',
|
|
63
|
+
borderColor: 'outline',
|
|
64
|
+
color: 'text',
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
name: 'text',
|
|
69
|
+
parts: { hoverBackground: 'tint', activeBackground: 'tint-active', color: 'text' },
|
|
70
|
+
},
|
|
71
|
+
],
|
|
72
|
+
});
|
|
73
|
+
const scheme = { root: {}, outlined: {}, text: {} };
|
|
74
|
+
for (const severity of [
|
|
75
|
+
'primary',
|
|
76
|
+
'secondary',
|
|
77
|
+
'success',
|
|
78
|
+
'info',
|
|
79
|
+
'warn',
|
|
80
|
+
'danger',
|
|
81
|
+
'contrast',
|
|
82
|
+
]) {
|
|
83
|
+
scheme.root[severity] = {
|
|
84
|
+
background: g.get('root', severity, 'background'),
|
|
85
|
+
hoverBackground: g.get('root', severity, 'hoverBackground'),
|
|
86
|
+
activeBackground: g.get('root', severity, 'activeBackground'),
|
|
87
|
+
borderColor: g.get('root', severity, 'borderColor'),
|
|
88
|
+
hoverBorderColor: g.get('root', severity, 'hoverBorderColor'),
|
|
89
|
+
activeBorderColor: g.get('root', severity, 'activeBorderColor'),
|
|
90
|
+
color: g.get('root', severity, 'color'),
|
|
91
|
+
hoverColor: g.get('root', severity, 'hoverColor'),
|
|
92
|
+
activeColor: g.get('root', severity, 'activeColor'),
|
|
93
|
+
focusRing: { color: g.get('root', severity, 'focusRingColor'), shadow: 'none' },
|
|
94
|
+
};
|
|
95
|
+
scheme.outlined[severity] = {
|
|
96
|
+
hoverBackground: g.get('outlined', severity, 'hoverBackground'),
|
|
97
|
+
activeBackground: g.get('outlined', severity, 'activeBackground'),
|
|
98
|
+
borderColor: g.get('outlined', severity, 'borderColor'),
|
|
99
|
+
color: g.get('outlined', severity, 'color'),
|
|
100
|
+
};
|
|
101
|
+
scheme.text[severity] = {
|
|
102
|
+
hoverBackground: g.get('text', severity, 'hoverBackground'),
|
|
103
|
+
activeBackground: g.get('text', severity, 'activeBackground'),
|
|
104
|
+
color: g.get('text', severity, 'color'),
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
return {
|
|
108
|
+
scheme,
|
|
109
|
+
coverage: g.coverage.map((c) => ({ ...c, variable: `button.colorScheme.${c.variable}` })),
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export function buildButton(light, dark, ctx) {
|
|
114
|
+
const l = buildButtonColorScheme(light);
|
|
115
|
+
const d = buildButtonColorScheme(dark);
|
|
116
|
+
const f = field(light).structural;
|
|
117
|
+
// AL2 parity fix: Button reads the BUTTON layer (which defaults from
|
|
118
|
+
// control), not the shared field object directly. Before this, an authored
|
|
119
|
+
// `component.button.radius` moved Bootstrap but not PrimeNG — the two
|
|
120
|
+
// targets disagreed about what authoring a button token meant.
|
|
121
|
+
const btn = (t) => light.get(`component.button.${t}`)?.value;
|
|
122
|
+
return {
|
|
123
|
+
tokens: {
|
|
124
|
+
root: {
|
|
125
|
+
borderRadius: btn('radius'),
|
|
126
|
+
paddingX: btn('padding-x'),
|
|
127
|
+
paddingY: btn('padding-y'),
|
|
128
|
+
gap: get(light, 'space.2'),
|
|
129
|
+
transitionDuration: f.transitionDuration,
|
|
130
|
+
},
|
|
131
|
+
colorScheme: { light: l.scheme, dark: d.scheme },
|
|
132
|
+
...(ctx.roleArchetypeExtend ? { extend: ctx.roleArchetypeExtend } : {}),
|
|
133
|
+
},
|
|
134
|
+
coverage: l.coverage,
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function buildFlatSeverity(map, { variants, severities, path }) {
|
|
139
|
+
const g = mapSeverityGrid(map, { variants, severities });
|
|
140
|
+
const scheme = {};
|
|
141
|
+
for (const severity of severities) {
|
|
142
|
+
scheme[severity] = {};
|
|
143
|
+
for (const field of Object.keys(variants[0].parts))
|
|
144
|
+
scheme[severity][field] = g.get(variants[0].name, severity, field);
|
|
145
|
+
}
|
|
146
|
+
return {
|
|
147
|
+
scheme,
|
|
148
|
+
coverage: g.coverage.map((c) => ({ ...c, variable: `${path}.colorScheme.${c.variable}` })),
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
export function buildTag(light, dark) {
|
|
153
|
+
const opts = {
|
|
154
|
+
variants: [{ name: 'root', parts: { background: 'tint', color: 'text' } }],
|
|
155
|
+
severities: ['primary', 'secondary', 'success', 'info', 'warn', 'danger', 'contrast'],
|
|
156
|
+
path: 'tag',
|
|
157
|
+
};
|
|
158
|
+
const l = buildFlatSeverity(light, opts);
|
|
159
|
+
const d = buildFlatSeverity(dark, opts);
|
|
160
|
+
return { tokens: { colorScheme: { light: l.scheme, dark: d.scheme } }, coverage: l.coverage };
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
export function buildBadge(light, dark) {
|
|
164
|
+
const opts = {
|
|
165
|
+
variants: [{ name: 'root', parts: { background: 'solid', color: 'on-solid' } }],
|
|
166
|
+
severities: ['primary', 'secondary', 'success', 'info', 'warn', 'danger', 'contrast'],
|
|
167
|
+
path: 'badge',
|
|
168
|
+
};
|
|
169
|
+
const l = buildFlatSeverity(light, opts);
|
|
170
|
+
const d = buildFlatSeverity(dark, opts);
|
|
171
|
+
return { tokens: { colorScheme: { light: l.scheme, dark: d.scheme } }, coverage: l.coverage };
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/** Message nests severity-major (colorScheme.<mode>.<severity>.{filled fields, outlined:{}, simple:{}}) — the opposite variant/severity order from Button. Verified against source, not assumed. No `primary` severity (info/success/warn/danger/secondary/contrast only) — a real PrimeNG inconsistency with Button/Tag/Badge, not ours. */
|
|
175
|
+
function buildMessageColorScheme(map) {
|
|
176
|
+
const g = mapSeverityGrid(map, {
|
|
177
|
+
severities: ['info', 'success', 'warn', 'danger', 'secondary', 'contrast'],
|
|
178
|
+
variants: [
|
|
179
|
+
{ name: 'filled', parts: { background: 'tint', borderColor: 'outline', color: 'text' } },
|
|
180
|
+
{ name: 'outlined', parts: { color: 'text', borderColor: 'text' } },
|
|
181
|
+
{ name: 'simple', parts: { color: 'text' } },
|
|
182
|
+
],
|
|
183
|
+
});
|
|
184
|
+
const scheme = {};
|
|
185
|
+
for (const severity of ['info', 'success', 'warn', 'danger', 'secondary', 'contrast']) {
|
|
186
|
+
const key = severity === 'danger' ? 'error' : severity; // real PrimeNG naming inconsistency (verified against source), not ours
|
|
187
|
+
scheme[key] = {
|
|
188
|
+
background: g.get('filled', severity, 'background'),
|
|
189
|
+
borderColor: g.get('filled', severity, 'borderColor'),
|
|
190
|
+
color: g.get('filled', severity, 'color'),
|
|
191
|
+
outlined: {
|
|
192
|
+
color: g.get('outlined', severity, 'color'),
|
|
193
|
+
borderColor: g.get('outlined', severity, 'borderColor'),
|
|
194
|
+
},
|
|
195
|
+
simple: { color: g.get('simple', severity, 'color') },
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
return {
|
|
199
|
+
scheme,
|
|
200
|
+
coverage: g.coverage.map((c) => ({ ...c, variable: `message.colorScheme.${c.variable}` })),
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
export function buildMessage(light, dark) {
|
|
205
|
+
const l = buildMessageColorScheme(light);
|
|
206
|
+
const d = buildMessageColorScheme(dark);
|
|
207
|
+
return { tokens: { colorScheme: { light: l.scheme, dark: d.scheme } }, coverage: l.coverage };
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/** Flat like Tag/Badge but uses `danger`-as-`error` naming (real PrimeNG inconsistency) plus a `shadow` field, approximated from the role's solid color at fixed low alpha (PrimeNG's own convention: `color-mix(..., transparent 96%)`). */
|
|
211
|
+
function buildInlineMessageColorScheme(map, ctx) {
|
|
212
|
+
const g = mapSeverityGrid(map, {
|
|
213
|
+
severities: ['info', 'success', 'warn', 'danger', 'secondary', 'contrast'],
|
|
214
|
+
variants: [
|
|
215
|
+
{ name: 'root', parts: { background: 'tint', borderColor: 'outline', color: 'text' } },
|
|
216
|
+
],
|
|
217
|
+
});
|
|
218
|
+
const scheme = {};
|
|
219
|
+
const coverage = [...g.coverage];
|
|
220
|
+
const roleFor = {
|
|
221
|
+
info: 'info',
|
|
222
|
+
success: 'success',
|
|
223
|
+
warn: 'warning',
|
|
224
|
+
danger: 'danger',
|
|
225
|
+
secondary: 'secondary',
|
|
226
|
+
};
|
|
227
|
+
for (const severity of ['info', 'success', 'warn', 'danger', 'secondary', 'contrast']) {
|
|
228
|
+
const solid =
|
|
229
|
+
severity === 'contrast'
|
|
230
|
+
? map.get('semantic.color.neutral.text-strong')?.value
|
|
231
|
+
: map.get(`semantic.color.${roleFor[severity]}.solid`)?.value;
|
|
232
|
+
const key = severity === 'danger' ? 'error' : severity;
|
|
233
|
+
scheme[key] = {
|
|
234
|
+
background: g.get('root', severity, 'background'),
|
|
235
|
+
borderColor: g.get('root', severity, 'borderColor'),
|
|
236
|
+
color: g.get('root', severity, 'color'),
|
|
237
|
+
shadow: solid ? `0px 4px 8px 0px ${ctx.formatColor({ ...solid, alpha: 0.04 })}` : undefined,
|
|
238
|
+
};
|
|
239
|
+
if (solid)
|
|
240
|
+
coverage.push({
|
|
241
|
+
variable: `inlinemessage.colorScheme.${severity}.shadow`,
|
|
242
|
+
slot: '—',
|
|
243
|
+
class: 'approximated',
|
|
244
|
+
note: "fixed low-alpha tint of the role solid color, matching PrimeNG's own color-mix(..., transparent 96%) convention — not a colorimetric shadow derivation",
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
return {
|
|
248
|
+
scheme,
|
|
249
|
+
coverage: coverage.map((c) =>
|
|
250
|
+
c.variable?.startsWith('inlinemessage')
|
|
251
|
+
? c
|
|
252
|
+
: { ...c, variable: `inlinemessage.colorScheme.${c.variable}` },
|
|
253
|
+
),
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
export function buildInlineMessage(light, dark, ctx) {
|
|
258
|
+
const l = buildInlineMessageColorScheme(light, ctx);
|
|
259
|
+
const d = buildInlineMessageColorScheme(dark, ctx);
|
|
260
|
+
return { tokens: { colorScheme: { light: l.scheme, dark: d.scheme } }, coverage: l.coverage };
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// ---------- primary-anchored components: verified to have NO colorScheme block in real
|
|
264
|
+
// PrimeNG at all — their own Aura default writes a bare token-reference string, which
|
|
265
|
+
// PrimeNG's own alias engine resolves per the active mode. We reuse those exact strings
|
|
266
|
+
// rather than resolving a literal (a literal would be mode-wrong: there is no per-mode
|
|
267
|
+
// slot to put a second value in). Not mode-dependent, so a single build suffices. ----------
|
|
268
|
+
|
|
269
|
+
export function buildProgressBar() {
|
|
270
|
+
return {
|
|
271
|
+
tokens: {
|
|
272
|
+
value: { background: '{primary.color}' },
|
|
273
|
+
label: { color: '{primary.contrastColor}' },
|
|
274
|
+
},
|
|
275
|
+
coverage: [
|
|
276
|
+
{
|
|
277
|
+
variable: 'progressbar.value.background',
|
|
278
|
+
slot: 'PrimeNG preset {primary.color} (runtime alias, not an IR path)',
|
|
279
|
+
class: 'native',
|
|
280
|
+
},
|
|
281
|
+
],
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
export function buildRating() {
|
|
286
|
+
return {
|
|
287
|
+
tokens: {
|
|
288
|
+
icon: {
|
|
289
|
+
color: '{text.mutedColor}',
|
|
290
|
+
hoverColor: '{primary.color}',
|
|
291
|
+
activeColor: '{primary.color}',
|
|
292
|
+
},
|
|
293
|
+
},
|
|
294
|
+
coverage: [
|
|
295
|
+
{
|
|
296
|
+
variable: 'rating.icon.hoverColor',
|
|
297
|
+
slot: 'PrimeNG preset {primary.color} (runtime alias, not an IR path)',
|
|
298
|
+
class: 'native',
|
|
299
|
+
},
|
|
300
|
+
],
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
// ---------- archetype-consumer components (§4/§5, C5) ----------
|
|
305
|
+
|
|
306
|
+
export function buildListbox(light, dark) {
|
|
307
|
+
const fl = field(light),
|
|
308
|
+
fd = field(dark);
|
|
309
|
+
const ll = list(light),
|
|
310
|
+
ld = list(dark);
|
|
311
|
+
return {
|
|
312
|
+
tokens: {
|
|
313
|
+
root: {
|
|
314
|
+
borderRadius: fl.structural.borderRadius,
|
|
315
|
+
transitionDuration: fl.structural.transitionDuration,
|
|
316
|
+
},
|
|
317
|
+
colorScheme: {
|
|
318
|
+
light: {
|
|
319
|
+
root: {
|
|
320
|
+
background: fl.colorScheme.background,
|
|
321
|
+
disabledBackground: fl.colorScheme.disabledBackground,
|
|
322
|
+
borderColor: fl.colorScheme.borderColor,
|
|
323
|
+
invalidBorderColor: fl.colorScheme.invalidBorderColor,
|
|
324
|
+
color: fl.colorScheme.color,
|
|
325
|
+
disabledColor: fl.colorScheme.disabledColor,
|
|
326
|
+
},
|
|
327
|
+
option: ll.colorScheme.option,
|
|
328
|
+
},
|
|
329
|
+
dark: {
|
|
330
|
+
root: {
|
|
331
|
+
background: fd.colorScheme.background,
|
|
332
|
+
disabledBackground: fd.colorScheme.disabledBackground,
|
|
333
|
+
borderColor: fd.colorScheme.borderColor,
|
|
334
|
+
invalidBorderColor: fd.colorScheme.invalidBorderColor,
|
|
335
|
+
color: fd.colorScheme.color,
|
|
336
|
+
disabledColor: fd.colorScheme.disabledColor,
|
|
337
|
+
},
|
|
338
|
+
option: ld.colorScheme.option,
|
|
339
|
+
},
|
|
340
|
+
},
|
|
341
|
+
list: {
|
|
342
|
+
padding: ll.structural.padding,
|
|
343
|
+
gap: ll.structural.gap,
|
|
344
|
+
header: ll.structural.header,
|
|
345
|
+
},
|
|
346
|
+
option: ll.structural.option,
|
|
347
|
+
optionGroup: ll.structural.optionGroup,
|
|
348
|
+
},
|
|
349
|
+
coverage: [
|
|
350
|
+
{ variable: 'listbox.root.*', slot: 'exporter-private: field()', class: 'derived' },
|
|
351
|
+
{ variable: 'listbox.option.*', slot: 'exporter-private: list()', class: 'derived' },
|
|
352
|
+
],
|
|
353
|
+
};
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
export function buildMenu(light, dark, ctx) {
|
|
357
|
+
const nl = navigation(light),
|
|
358
|
+
nd = navigation(dark);
|
|
359
|
+
const cl = content(light),
|
|
360
|
+
cd = content(dark);
|
|
361
|
+
const shadow = light.get('semantic.color.elevation.2.shadow')?.value;
|
|
362
|
+
return {
|
|
363
|
+
tokens: {
|
|
364
|
+
root: {
|
|
365
|
+
borderRadius: cl.structural.borderRadius,
|
|
366
|
+
shadow: shadow
|
|
367
|
+
? `${shadow.offsetX} ${shadow.offsetY} ${shadow.blur} ${shadow.spread} ${ctx.formatColor(shadow.color)}`
|
|
368
|
+
: undefined,
|
|
369
|
+
},
|
|
370
|
+
colorScheme: {
|
|
371
|
+
// Menu's own component-level `item` type is narrower than the shared
|
|
372
|
+
// semantic.navigation.item group (verified against source: no active*
|
|
373
|
+
// fields at the component level — only focus, since Menu has no active state).
|
|
374
|
+
light: {
|
|
375
|
+
root: {
|
|
376
|
+
background: cl.colorScheme.background,
|
|
377
|
+
borderColor: cl.colorScheme.borderColor,
|
|
378
|
+
color: cl.colorScheme.color,
|
|
379
|
+
},
|
|
380
|
+
item: {
|
|
381
|
+
focusBackground: nl.colorScheme.item.focusBackground,
|
|
382
|
+
color: nl.colorScheme.item.color,
|
|
383
|
+
focusColor: nl.colorScheme.item.focusColor,
|
|
384
|
+
icon: nl.colorScheme.item.icon,
|
|
385
|
+
},
|
|
386
|
+
submenuLabel: nl.colorScheme.submenuLabel,
|
|
387
|
+
},
|
|
388
|
+
dark: {
|
|
389
|
+
root: {
|
|
390
|
+
background: cd.colorScheme.background,
|
|
391
|
+
borderColor: cd.colorScheme.borderColor,
|
|
392
|
+
color: cd.colorScheme.color,
|
|
393
|
+
},
|
|
394
|
+
item: {
|
|
395
|
+
focusBackground: nd.colorScheme.item.focusBackground,
|
|
396
|
+
color: nd.colorScheme.item.color,
|
|
397
|
+
focusColor: nd.colorScheme.item.focusColor,
|
|
398
|
+
icon: nd.colorScheme.item.icon,
|
|
399
|
+
},
|
|
400
|
+
submenuLabel: nd.colorScheme.submenuLabel,
|
|
401
|
+
},
|
|
402
|
+
},
|
|
403
|
+
list: nl.structural.list,
|
|
404
|
+
item: nl.structural.item,
|
|
405
|
+
submenuLabel: nl.structural.submenuLabel,
|
|
406
|
+
},
|
|
407
|
+
coverage: [
|
|
408
|
+
{ variable: 'menu.item.*', slot: 'exporter-private: navigation()', class: 'derived' },
|
|
409
|
+
],
|
|
410
|
+
};
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
export function buildPopover(light, dark, ctx) {
|
|
414
|
+
const ol = overlay(light, 'popover', ctx),
|
|
415
|
+
od = overlay(dark, 'popover', ctx);
|
|
416
|
+
return {
|
|
417
|
+
tokens: {
|
|
418
|
+
root: { ...ol.structural },
|
|
419
|
+
colorScheme: { light: { root: ol.colorScheme }, dark: { root: od.colorScheme } },
|
|
420
|
+
content: { padding: ol.padding },
|
|
421
|
+
},
|
|
422
|
+
coverage: [
|
|
423
|
+
{ variable: 'popover.root.*', slot: 'exporter-private: overlay(popover)', class: 'derived' },
|
|
424
|
+
],
|
|
425
|
+
};
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
export function buildDialog(light, dark, ctx) {
|
|
429
|
+
const ol = overlay(light, 'modal', ctx),
|
|
430
|
+
od = overlay(dark, 'modal', ctx);
|
|
431
|
+
return {
|
|
432
|
+
tokens: {
|
|
433
|
+
root: { ...ol.structural },
|
|
434
|
+
colorScheme: { light: { root: ol.colorScheme }, dark: { root: od.colorScheme } },
|
|
435
|
+
header: { padding: ol.padding },
|
|
436
|
+
content: { padding: ol.padding },
|
|
437
|
+
footer: { padding: ol.padding },
|
|
438
|
+
},
|
|
439
|
+
coverage: [
|
|
440
|
+
{ variable: 'dialog.root.*', slot: 'exporter-private: overlay(modal)', class: 'derived' },
|
|
441
|
+
],
|
|
442
|
+
};
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
/**
|
|
446
|
+
* Structural residue (§5.2 / C5): components with no severity-colored surface
|
|
447
|
+
* and not yet given a real builder above. Honest `unsupported` coverage,
|
|
448
|
+
* matching every other exporter's convention — not silently dropped.
|
|
449
|
+
*/
|
|
450
|
+
export const STRUCTURAL_RESIDUE = [
|
|
451
|
+
'datatable',
|
|
452
|
+
'galleria',
|
|
453
|
+
'tree',
|
|
454
|
+
'treetable',
|
|
455
|
+
'splitter',
|
|
456
|
+
'timeline',
|
|
457
|
+
'organizationchart',
|
|
458
|
+
'carousel',
|
|
459
|
+
'dataview',
|
|
460
|
+
'orderlist',
|
|
461
|
+
'picklist',
|
|
462
|
+
'paginator',
|
|
463
|
+
'stepper',
|
|
464
|
+
'steps',
|
|
465
|
+
'tabs',
|
|
466
|
+
'tabview',
|
|
467
|
+
'accordion',
|
|
468
|
+
];
|