@vectoriox/iox-ui 5.6.0 → 5.8.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/fesm2022/vectoriox-iox-ui-forms-core.mjs +6 -2
- package/fesm2022/vectoriox-iox-ui-forms-core.mjs.map +1 -1
- package/fesm2022/vectoriox-iox-ui.mjs +272 -4
- package/fesm2022/vectoriox-iox-ui.mjs.map +1 -1
- package/forms-core/index.d.ts +4 -0
- package/index.d.ts +119 -63
- package/package.json +1 -1
- package/src/forms-core/form.model.ts +4 -0
- package/src/forms-core/rule-catalog.ts +2 -2
- package/styles/iox-forms.css +40 -0
|
@@ -2871,6 +2871,10 @@ var ControlType;
|
|
|
2871
2871
|
ControlType["Textarea"] = "textarea";
|
|
2872
2872
|
ControlType["Select"] = "select";
|
|
2873
2873
|
ControlType["Checkbox"] = "checkbox";
|
|
2874
|
+
/** A checkbox in switch clothing (role="switch") — consent toggles, settings-style forms. */
|
|
2875
|
+
ControlType["Switch"] = "switch";
|
|
2876
|
+
/** A slider over a numeric range — min/max/step ride the field. */
|
|
2877
|
+
ControlType["Range"] = "range";
|
|
2874
2878
|
ControlType["Radio"] = "radio";
|
|
2875
2879
|
ControlType["Date"] = "date";
|
|
2876
2880
|
ControlType["Time"] = "time";
|
|
@@ -3425,7 +3429,7 @@ const TEXTUAL = [
|
|
|
3425
3429
|
ControlType.Password, ControlType.Textarea,
|
|
3426
3430
|
];
|
|
3427
3431
|
/** Controls with a comparable magnitude. */
|
|
3428
|
-
const NUMERIC = [ControlType.Number, ControlType.Date, ControlType.Time];
|
|
3432
|
+
const NUMERIC = [ControlType.Number, ControlType.Date, ControlType.Time, ControlType.Range];
|
|
3429
3433
|
const RULE_DESCRIPTORS = Object.freeze([
|
|
3430
3434
|
{
|
|
3431
3435
|
name: RuleName.MinLength, labelKey: 'forms.rules.minLength',
|
|
@@ -3457,7 +3461,7 @@ const RULE_DESCRIPTORS = Object.freeze([
|
|
|
3457
3461
|
// A checkbox's `required` already becomes `accepted`, so offering it again would be a
|
|
3458
3462
|
// duplicate — it is here for a checkbox the author wants ticked WITHOUT marking it required.
|
|
3459
3463
|
name: RuleName.Accepted, labelKey: 'forms.rules.accepted',
|
|
3460
|
-
param: RuleParamKind.None, controls: [ControlType.Checkbox],
|
|
3464
|
+
param: RuleParamKind.None, controls: [ControlType.Checkbox, ControlType.Switch],
|
|
3461
3465
|
},
|
|
3462
3466
|
]);
|
|
3463
3467
|
/** The rules that can be added to a field of this control type. */
|
|
@@ -3986,6 +3990,9 @@ class IoxFieldComponent {
|
|
|
3986
3990
|
this.labelHidden = false;
|
|
3987
3991
|
this.requiredMark = '*';
|
|
3988
3992
|
this.rows = 4;
|
|
3993
|
+
this.rangeMin = 0;
|
|
3994
|
+
this.rangeMax = 100;
|
|
3995
|
+
this.rangeStep = 1;
|
|
3989
3996
|
this.accept = '';
|
|
3990
3997
|
this.options = [];
|
|
3991
3998
|
this.value = '';
|
|
@@ -4071,7 +4078,7 @@ class IoxFieldComponent {
|
|
|
4071
4078
|
this.touched.emit();
|
|
4072
4079
|
}
|
|
4073
4080
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.31", ngImport: i0, type: IoxFieldComponent, deps: [{ token: FormRuntimeService, optional: true }, { token: IOX_FORM_MESSAGES }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
4074
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.31", type: IoxFieldComponent, isStandalone: false, selector: "div[iox-field]", inputs: { nodeId: "nodeId", name: "name", label: "label", control: "control", placeholder: "placeholder", help: "help", required: "required", disabled: "disabled", labelHidden: "labelHidden", requiredMark: "requiredMark", rows: "rows", accept: "accept", options: "options", value: "value", rules: "rules", forceInvalid: "forceInvalid", designErrorText: "designErrorText", showValid: "showValid" }, outputs: { valueChange: "valueChange", touched: "touched" }, host: { properties: { "class": "'iox-field iox-node-' + nodeId", "class.iox-invalid": "invalid", "class.iox-valid": "showValid", "attr.data-iox-field": "fieldName || null", "hidden": "control === 'hidden' ? true : null" } }, ngImport: i0, template: `
|
|
4081
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.31", type: IoxFieldComponent, isStandalone: false, selector: "div[iox-field]", inputs: { nodeId: "nodeId", name: "name", label: "label", control: "control", placeholder: "placeholder", help: "help", required: "required", disabled: "disabled", labelHidden: "labelHidden", requiredMark: "requiredMark", rows: "rows", rangeMin: "rangeMin", rangeMax: "rangeMax", rangeStep: "rangeStep", accept: "accept", options: "options", value: "value", rules: "rules", forceInvalid: "forceInvalid", designErrorText: "designErrorText", showValid: "showValid" }, outputs: { valueChange: "valueChange", touched: "touched" }, host: { properties: { "class": "'iox-field iox-node-' + nodeId", "class.iox-invalid": "invalid", "class.iox-valid": "showValid", "attr.data-iox-field": "fieldName || null", "hidden": "control === 'hidden' ? true : null" } }, ngImport: i0, template: `
|
|
4075
4082
|
<label class="iox-field__label"
|
|
4076
4083
|
[class.iox-field__label--hidden]="labelHidden"
|
|
4077
4084
|
[attr.for]="controlId">
|
|
@@ -4112,6 +4119,33 @@ class IoxFieldComponent {
|
|
|
4112
4119
|
}
|
|
4113
4120
|
</select>
|
|
4114
4121
|
}
|
|
4122
|
+
@case ('switch') {
|
|
4123
|
+
<input class="iox-field__control iox-field__control--switch"
|
|
4124
|
+
type="checkbox"
|
|
4125
|
+
role="switch"
|
|
4126
|
+
[id]="controlId"
|
|
4127
|
+
[name]="fieldName"
|
|
4128
|
+
[attr.aria-invalid]="invalid ? 'true' : null"
|
|
4129
|
+
[attr.aria-describedby]="describedBy"
|
|
4130
|
+
[attr.disabled]="disabled ? '' : null"
|
|
4131
|
+
[checked]="value === true"
|
|
4132
|
+
(change)="emit($any($event.target).checked)"
|
|
4133
|
+
(blur)="touch()">
|
|
4134
|
+
}
|
|
4135
|
+
@case ('range') {
|
|
4136
|
+
<input class="iox-field__control iox-field__control--range"
|
|
4137
|
+
type="range"
|
|
4138
|
+
[id]="controlId"
|
|
4139
|
+
[name]="fieldName"
|
|
4140
|
+
[attr.min]="rangeMin"
|
|
4141
|
+
[attr.max]="rangeMax"
|
|
4142
|
+
[attr.step]="rangeStep"
|
|
4143
|
+
[attr.aria-describedby]="describedBy"
|
|
4144
|
+
[attr.disabled]="disabled ? '' : null"
|
|
4145
|
+
[value]="value ?? rangeMin"
|
|
4146
|
+
(input)="emit(+$any($event.target).value)"
|
|
4147
|
+
(blur)="touch()">
|
|
4148
|
+
}
|
|
4115
4149
|
@case ('checkbox') {
|
|
4116
4150
|
<input class="iox-field__control iox-field__control--checkbox"
|
|
4117
4151
|
type="checkbox"
|
|
@@ -4209,6 +4243,33 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.31", ngImpo
|
|
|
4209
4243
|
}
|
|
4210
4244
|
</select>
|
|
4211
4245
|
}
|
|
4246
|
+
@case ('switch') {
|
|
4247
|
+
<input class="iox-field__control iox-field__control--switch"
|
|
4248
|
+
type="checkbox"
|
|
4249
|
+
role="switch"
|
|
4250
|
+
[id]="controlId"
|
|
4251
|
+
[name]="fieldName"
|
|
4252
|
+
[attr.aria-invalid]="invalid ? 'true' : null"
|
|
4253
|
+
[attr.aria-describedby]="describedBy"
|
|
4254
|
+
[attr.disabled]="disabled ? '' : null"
|
|
4255
|
+
[checked]="value === true"
|
|
4256
|
+
(change)="emit($any($event.target).checked)"
|
|
4257
|
+
(blur)="touch()">
|
|
4258
|
+
}
|
|
4259
|
+
@case ('range') {
|
|
4260
|
+
<input class="iox-field__control iox-field__control--range"
|
|
4261
|
+
type="range"
|
|
4262
|
+
[id]="controlId"
|
|
4263
|
+
[name]="fieldName"
|
|
4264
|
+
[attr.min]="rangeMin"
|
|
4265
|
+
[attr.max]="rangeMax"
|
|
4266
|
+
[attr.step]="rangeStep"
|
|
4267
|
+
[attr.aria-describedby]="describedBy"
|
|
4268
|
+
[attr.disabled]="disabled ? '' : null"
|
|
4269
|
+
[value]="value ?? rangeMin"
|
|
4270
|
+
(input)="emit(+$any($event.target).value)"
|
|
4271
|
+
(blur)="touch()">
|
|
4272
|
+
}
|
|
4212
4273
|
@case ('checkbox') {
|
|
4213
4274
|
<input class="iox-field__control iox-field__control--checkbox"
|
|
4214
4275
|
type="checkbox"
|
|
@@ -4295,6 +4356,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.31", ngImpo
|
|
|
4295
4356
|
type: Input
|
|
4296
4357
|
}], rows: [{
|
|
4297
4358
|
type: Input
|
|
4359
|
+
}], rangeMin: [{
|
|
4360
|
+
type: Input
|
|
4361
|
+
}], rangeMax: [{
|
|
4362
|
+
type: Input
|
|
4363
|
+
}], rangeStep: [{
|
|
4364
|
+
type: Input
|
|
4298
4365
|
}], accept: [{
|
|
4299
4366
|
type: Input
|
|
4300
4367
|
}], options: [{
|
|
@@ -4953,6 +5020,201 @@ function partClassName(type, partKey) {
|
|
|
4953
5020
|
return PART_CLASS_NAMES[type]?.[partKey];
|
|
4954
5021
|
}
|
|
4955
5022
|
|
|
5023
|
+
function parseHexColor(hex) {
|
|
5024
|
+
const m = /^#?([0-9a-f]{3}|[0-9a-f]{6})$/i.exec((hex ?? '').trim());
|
|
5025
|
+
if (!m)
|
|
5026
|
+
return null;
|
|
5027
|
+
let h = m[1];
|
|
5028
|
+
if (h.length === 3)
|
|
5029
|
+
h = h.split('').map(c => c + c).join('');
|
|
5030
|
+
const n = parseInt(h, 16);
|
|
5031
|
+
return { r: ((n >> 16) & 255) / 255, g: ((n >> 8) & 255) / 255, b: (n & 255) / 255 };
|
|
5032
|
+
}
|
|
5033
|
+
function toHexColor(c) {
|
|
5034
|
+
const q = (v) => Math.round(Math.min(1, Math.max(0, v)) * 255).toString(16).padStart(2, '0');
|
|
5035
|
+
return `#${q(c.r)}${q(c.g)}${q(c.b)}`;
|
|
5036
|
+
}
|
|
5037
|
+
const srgbToLinear = (v) => (v <= 0.04045 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4));
|
|
5038
|
+
const linearToSrgb = (v) => (v <= 0.0031308 ? v * 12.92 : 1.055 * Math.pow(v, 1 / 2.4) - 0.055);
|
|
5039
|
+
function rgbToOklab(c) {
|
|
5040
|
+
const r = srgbToLinear(c.r), g = srgbToLinear(c.g), b = srgbToLinear(c.b);
|
|
5041
|
+
const l = Math.cbrt(0.4122214708 * r + 0.5363325363 * g + 0.0514459929 * b);
|
|
5042
|
+
const m = Math.cbrt(0.2119034982 * r + 0.6806995451 * g + 0.1073969566 * b);
|
|
5043
|
+
const s = Math.cbrt(0.0883024619 * r + 0.2817188376 * g + 0.6299787005 * b);
|
|
5044
|
+
return {
|
|
5045
|
+
L: 0.2104542553 * l + 0.793617785 * m - 0.0040720468 * s,
|
|
5046
|
+
a: 1.9779984951 * l - 2.428592205 * m + 0.4505937099 * s,
|
|
5047
|
+
b: 0.0259040371 * l + 0.7827717662 * m - 0.808675766 * s,
|
|
5048
|
+
};
|
|
5049
|
+
}
|
|
5050
|
+
function oklabToRgb(c) {
|
|
5051
|
+
const l = Math.pow(c.L + 0.3963377774 * c.a + 0.2158037573 * c.b, 3);
|
|
5052
|
+
const m = Math.pow(c.L - 0.1055613458 * c.a - 0.0638541728 * c.b, 3);
|
|
5053
|
+
const s = Math.pow(c.L - 0.0894841775 * c.a - 1.291485548 * c.b, 3);
|
|
5054
|
+
return {
|
|
5055
|
+
r: linearToSrgb(+4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s),
|
|
5056
|
+
g: linearToSrgb(-1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s),
|
|
5057
|
+
b: linearToSrgb(-0.0041960863 * l - 0.7034186147 * m + 1.707614701 * s),
|
|
5058
|
+
};
|
|
5059
|
+
}
|
|
5060
|
+
const inGamut = (c) => [c.r, c.g, c.b].every(v => v >= -1e-6 && v <= 1 + 1e-6);
|
|
5061
|
+
/** The OKLab colour at (L, hue, chroma), chroma reduced until it fits sRGB. */
|
|
5062
|
+
function atLightness(L, hueA, hueB, chroma) {
|
|
5063
|
+
const len = Math.hypot(hueA, hueB) || 1;
|
|
5064
|
+
const ua = hueA / len, ub = hueB / len;
|
|
5065
|
+
let c = chroma;
|
|
5066
|
+
for (let i = 0; i < 24; i++) {
|
|
5067
|
+
const rgb = oklabToRgb({ L, a: ua * c, b: ub * c });
|
|
5068
|
+
if (inGamut(rgb))
|
|
5069
|
+
return rgb;
|
|
5070
|
+
c *= 0.82;
|
|
5071
|
+
}
|
|
5072
|
+
return oklabToRgb({ L, a: 0, b: 0 });
|
|
5073
|
+
}
|
|
5074
|
+
// ── WCAG 2 (the gate) ────────────────────────────────────────────────────────
|
|
5075
|
+
function relativeLuminance(c) {
|
|
5076
|
+
return 0.2126 * srgbToLinear(c.r) + 0.7152 * srgbToLinear(c.g) + 0.0722 * srgbToLinear(c.b);
|
|
5077
|
+
}
|
|
5078
|
+
/** WCAG 2 contrast ratio between two colours (order-independent), 1..21. */
|
|
5079
|
+
function wcagContrastRatio(a, b) {
|
|
5080
|
+
const ca = typeof a === 'string' ? parseHexColor(a) : a;
|
|
5081
|
+
const cb = typeof b === 'string' ? parseHexColor(b) : b;
|
|
5082
|
+
if (!ca || !cb)
|
|
5083
|
+
return 1;
|
|
5084
|
+
const la = relativeLuminance(ca), lb = relativeLuminance(cb);
|
|
5085
|
+
const [hi, lo] = la >= lb ? [la, lb] : [lb, la];
|
|
5086
|
+
return (hi + 0.05) / (lo + 0.05);
|
|
5087
|
+
}
|
|
5088
|
+
// ── APCA (the read-out — WCAG 2 stays the gate) ─────────────────────────────
|
|
5089
|
+
/**
|
|
5090
|
+
* APCA-W3 lightness contrast Lc (0.0.98G-4g constants), text-on-background and signed:
|
|
5091
|
+
* positive for dark-on-light, negative for light-on-dark; |Lc| ≈ 106–108 at the extremes.
|
|
5092
|
+
* Shown in the picker as the perceptual read-out; never used as the pass/fail gate here.
|
|
5093
|
+
*/
|
|
5094
|
+
function apcaLc(text, bg) {
|
|
5095
|
+
const toY = (c) => 0.2126729 * Math.pow(c.r, 2.4) + 0.7151522 * Math.pow(c.g, 2.4) + 0.072175 * Math.pow(c.b, 2.4);
|
|
5096
|
+
const clamp = (y) => (y < 0.022 ? y + Math.pow(0.022 - y, 1.414) : y);
|
|
5097
|
+
const ct = typeof text === 'string' ? parseHexColor(text) : text;
|
|
5098
|
+
const cb = typeof bg === 'string' ? parseHexColor(bg) : bg;
|
|
5099
|
+
if (!ct || !cb)
|
|
5100
|
+
return 0;
|
|
5101
|
+
const yTxt = clamp(toY(ct)), yBg = clamp(toY(cb));
|
|
5102
|
+
let lc;
|
|
5103
|
+
if (yBg > yTxt)
|
|
5104
|
+
lc = (Math.pow(yBg, 0.56) - Math.pow(yTxt, 0.57)) * 1.14;
|
|
5105
|
+
else
|
|
5106
|
+
lc = (Math.pow(yBg, 0.65) - Math.pow(yTxt, 0.62)) * 1.14;
|
|
5107
|
+
if (Math.abs(lc) < 0.1)
|
|
5108
|
+
return 0;
|
|
5109
|
+
return Math.round((lc > 0 ? lc - 0.027 : lc + 0.027) * 1000) / 10;
|
|
5110
|
+
}
|
|
5111
|
+
// ── The ramp ─────────────────────────────────────────────────────────────────
|
|
5112
|
+
/** Fixed, perceptually even lightness ladder for brand-50 … brand-900. */
|
|
5113
|
+
const RAMP_STEPS = [
|
|
5114
|
+
{ step: 50, L: 0.97, chromaScale: 0.22 },
|
|
5115
|
+
{ step: 100, L: 0.93, chromaScale: 0.42 },
|
|
5116
|
+
{ step: 200, L: 0.86, chromaScale: 0.66 },
|
|
5117
|
+
{ step: 300, L: 0.78, chromaScale: 0.85 },
|
|
5118
|
+
{ step: 400, L: 0.70, chromaScale: 0.96 },
|
|
5119
|
+
{ step: 500, L: 0.62, chromaScale: 1.0 },
|
|
5120
|
+
{ step: 600, L: 0.53, chromaScale: 0.96 },
|
|
5121
|
+
{ step: 700, L: 0.45, chromaScale: 0.88 },
|
|
5122
|
+
{ step: 800, L: 0.36, chromaScale: 0.76 },
|
|
5123
|
+
{ step: 900, L: 0.27, chromaScale: 0.62 },
|
|
5124
|
+
];
|
|
5125
|
+
const BLACK = { r: 0, g: 0, b: 0 };
|
|
5126
|
+
const WHITE = { r: 1, g: 1, b: 1 };
|
|
5127
|
+
/** Snap to the 8-bit hex the token will actually carry — contrast is judged on WHAT SHIPS.
|
|
5128
|
+
* (The first version searched in float space and hex rounding landed 6.9596 where 7 was owed.) */
|
|
5129
|
+
const quant = (c) => parseHexColor(toHexColor(c));
|
|
5130
|
+
/** Binary-search an OKLab lightness so `contrast(colour, against) ≥ ratio`, darkening-or-lightening. */
|
|
5131
|
+
function atContrast(against, ratio, hueA, hueB, chroma, darker) {
|
|
5132
|
+
let lo = darker ? 0 : rgbToOklab(against).L;
|
|
5133
|
+
let hi = darker ? rgbToOklab(against).L : 1;
|
|
5134
|
+
let best = quant(atLightness(darker ? 0.18 : 0.92, hueA, hueB, chroma));
|
|
5135
|
+
for (let i = 0; i < 28; i++) {
|
|
5136
|
+
const mid = (lo + hi) / 2;
|
|
5137
|
+
const candidate = quant(atLightness(mid, hueA, hueB, chroma));
|
|
5138
|
+
if (wcagContrastRatio(candidate, against) >= ratio) {
|
|
5139
|
+
best = candidate;
|
|
5140
|
+
if (darker)
|
|
5141
|
+
lo = mid;
|
|
5142
|
+
else
|
|
5143
|
+
hi = mid; // pull back toward `against`: the LOWEST passing step
|
|
5144
|
+
}
|
|
5145
|
+
else {
|
|
5146
|
+
if (darker)
|
|
5147
|
+
hi = mid;
|
|
5148
|
+
else
|
|
5149
|
+
lo = mid;
|
|
5150
|
+
}
|
|
5151
|
+
}
|
|
5152
|
+
return best;
|
|
5153
|
+
}
|
|
5154
|
+
/**
|
|
5155
|
+
* The derived brand tokens (plan §6's table, every row asserted in brand.spec.ts):
|
|
5156
|
+
* `brand-50…900` (monotonic OKLab lightness, gamut-safe) · `brandInk` (black or white, ≥4.5 on
|
|
5157
|
+
* brand-500 — brand-500's lightness is nudged when neither side clears it) · `surface`/`ink`/
|
|
5158
|
+
* `inkMuted` (seed-tinted neutrals, ≥7:1 / ≥4.5:1 on surface) · `line` (the LIGHTEST neutral that
|
|
5159
|
+
* still clears 3:1 on surface) · `accent` (pack-rotated hue, ≥4.5:1 on surface) — with dark-scheme
|
|
5160
|
+
* values for the neutral family riding `values.dark`.
|
|
5161
|
+
*
|
|
5162
|
+
* Throws on an unparseable seed: callers (the picker) validate; a silent fallback here would
|
|
5163
|
+
* launch a studio into a palette nobody chose.
|
|
5164
|
+
*/
|
|
5165
|
+
function deriveBrandTokens(seed, pack) {
|
|
5166
|
+
const seedRgb = parseHexColor(seed);
|
|
5167
|
+
if (!seedRgb)
|
|
5168
|
+
throw new TypeError(`deriveBrandTokens: not a colour: "${seed}"`);
|
|
5169
|
+
const lab = rgbToOklab(seedRgb);
|
|
5170
|
+
const chroma = Math.hypot(lab.a, lab.b);
|
|
5171
|
+
const ua = chroma > 1e-6 ? lab.a : 0.0, ub = chroma > 1e-6 ? lab.b : 1e-6; // grey seeds: keep a stable (arbitrary) hue axis
|
|
5172
|
+
const baseChroma = Math.max(chroma, 0.02); // near-grey seeds still get a usable, quiet ramp
|
|
5173
|
+
const token = (name, value, dark) => ({ name, value, ...(dark ? { values: { dark } } : {}), type: 'color', group: 'colour' });
|
|
5174
|
+
// 1 — the ramp
|
|
5175
|
+
const ramp = RAMP_STEPS.map(({ step, L, chromaScale }) => ({ step, rgb: atLightness(L, ua, ub, baseChroma * chromaScale) }));
|
|
5176
|
+
// 2 — brandInk on brand-500, nudging 500 (within its neighbours) when neither ink clears 4.5
|
|
5177
|
+
let five = ramp.find(r => r.step === 500);
|
|
5178
|
+
five.rgb = quant(five.rgb);
|
|
5179
|
+
const inkFor = (bg) => (wcagContrastRatio(WHITE, bg) >= wcagContrastRatio(BLACK, bg) ? WHITE : BLACK);
|
|
5180
|
+
for (let i = 0; i < 40 && wcagContrastRatio(inkFor(five.rgb), five.rgb) < 4.5; i++) {
|
|
5181
|
+
const L = rgbToOklab(five.rgb).L;
|
|
5182
|
+
// Mid tones can fail both inks — walk toward whichever side is already winning, but
|
|
5183
|
+
// never past the neighbouring steps: the ramp's monotonic lightness is a guarantee.
|
|
5184
|
+
const towardDark = wcagContrastRatio(WHITE, five.rgb) >= wcagContrastRatio(BLACK, five.rgb);
|
|
5185
|
+
const next = Math.min(0.695, Math.max(0.545, L + (towardDark ? -0.012 : 0.012)));
|
|
5186
|
+
if (next === L)
|
|
5187
|
+
break;
|
|
5188
|
+
five.rgb = quant(atLightness(next, ua, ub, baseChroma));
|
|
5189
|
+
}
|
|
5190
|
+
const brandInk = inkFor(five.rgb);
|
|
5191
|
+
// 3 — the neutral family, faintly tinted by the seed hue. Surfaces are quantized FIRST:
|
|
5192
|
+
// every later guarantee is measured against the hex that ships, not a float ideal.
|
|
5193
|
+
const tint = 0.006;
|
|
5194
|
+
const surface = quant(atLightness(0.985, ua, ub, tint));
|
|
5195
|
+
const surfaceDark = quant(atLightness(0.145, ua, ub, tint * 1.5));
|
|
5196
|
+
const ink = atContrast(surface, 7, ua, ub, tint * 2, true);
|
|
5197
|
+
const inkDark = atContrast(surfaceDark, 7, ua, ub, tint * 2, false);
|
|
5198
|
+
const inkMuted = atContrast(surface, 4.5, ua, ub, tint * 2, true);
|
|
5199
|
+
const inkMutedDark = atContrast(surfaceDark, 4.5, ua, ub, tint * 2, false);
|
|
5200
|
+
const line = atContrast(surface, 3, ua, ub, tint, true);
|
|
5201
|
+
const lineDark = atContrast(surfaceDark, 3, ua, ub, tint, false);
|
|
5202
|
+
// 4 — the accent: pack-defined hue rotation from the seed, readable on surface
|
|
5203
|
+
const rot = ((pack.accentHueDeg ?? 150) * Math.PI) / 180;
|
|
5204
|
+
const ra = ua * Math.cos(rot) - ub * Math.sin(rot);
|
|
5205
|
+
const rb = ua * Math.sin(rot) + ub * Math.cos(rot);
|
|
5206
|
+
const accent = atContrast(surface, 4.5, ra, rb, Math.max(baseChroma, 0.06), true);
|
|
5207
|
+
return [
|
|
5208
|
+
...ramp.map(({ step, rgb }) => token(`brand-${step}`, toHexColor(rgb))),
|
|
5209
|
+
token('brandInk', toHexColor(brandInk)),
|
|
5210
|
+
token('surface', toHexColor(surface), toHexColor(surfaceDark)),
|
|
5211
|
+
token('ink', toHexColor(ink), toHexColor(inkDark)),
|
|
5212
|
+
token('inkMuted', toHexColor(inkMuted), toHexColor(inkMutedDark)),
|
|
5213
|
+
token('line', toHexColor(line), toHexColor(lineDark)),
|
|
5214
|
+
token('accent', toHexColor(accent)),
|
|
5215
|
+
];
|
|
5216
|
+
}
|
|
5217
|
+
|
|
4956
5218
|
/**
|
|
4957
5219
|
* Design-token → CSS compilation, shared by BOTH renderers (flavors plan F0).
|
|
4958
5220
|
*
|
|
@@ -5088,6 +5350,12 @@ const SWISS_FLAVOR = {
|
|
|
5088
5350
|
ButtonBlock: { borderRadius: 'radius-control', padding: 'space-control' },
|
|
5089
5351
|
Card: { borderRadius: 'radius-surface' },
|
|
5090
5352
|
},
|
|
5353
|
+
// F2: Swiss turns the seed toward a cool counterpoint. NOTE deliberately: the brand tokens
|
|
5354
|
+
// deriveBrandTokens() emits are SEEDED per org — they do not join `defaults` here, because a
|
|
5355
|
+
// colour default repaints legacy nodes whose saved styleProps lack the key (the engine fills
|
|
5356
|
+
// missing keys from config defaults). Coloured element defaults are a Swiss v2 upgrade
|
|
5357
|
+
// decision (§10 C2), taken with the picker in front of the author — never a side effect.
|
|
5358
|
+
accentHueDeg: 150,
|
|
5091
5359
|
};
|
|
5092
5360
|
/** What both renderers use until F2 lets an org choose. */
|
|
5093
5361
|
const DEFAULT_FLAVOR = SWISS_FLAVOR;
|
|
@@ -6929,5 +7197,5 @@ function effectiveTransitionId(anim) {
|
|
|
6929
7197
|
* Generated bundle index. Do not edit.
|
|
6930
7198
|
*/
|
|
6931
7199
|
|
|
6932
|
-
export { AOSService, BREAKPOINTS, Breakpoint, BreakpointQueryKind, BuilderButtonComponent, BuilderDividerComponent, BuilderHeadingComponent, BuilderIconComponent, BuilderImageComponent, BuilderLinkComponent, BuilderSpacerComponent, ButtonBlockComponent, CONTEXT_ACTION_TYPES, CardComponent, ClientGalleryComponent, ClientListComponent, ClientListItemComponent, ClientRepeaterComponent, ClientSliderContainerComponent, ClientSliderSlideComponent, ComponentInstanceRegistryService, ContainerComponent, ContextStore, DEFAULT_FLAVOR, DEFAULT_GALLERY_SCHEDULER, DEFAULT_PAGE_TRANSITION, DEFAULT_PAGE_TRANSITION_DURATION, DEFAULT_PAGE_TRANSITION_EASING, DEFAULT_PAGE_TRANSITION_PERSPECTIVE, DEFAULT_PHOSPHOR_WEIGHT, DEFAULT_WIDTH_BY_TYPE, DeclarationContext, FormRenderState, FormRuntimeService, GALLERY_EFFECTS, GALLERY_EFFECT_DESCRIPTORS, GalleryLoop, IOX_BUILDER_EVENTS, IOX_FORM_MESSAGES, IOX_FORM_NAVIGATOR, IOX_FORM_TRANSPORT, IS_PREVIEW, IoxAnimateContainer, IoxAosDirective, IoxAosModule, IoxBuilderComponentsModule, IoxComponentRegistryService, IoxFieldComponent, IoxFormComponent, IoxFormErrorComponent, IoxFormSuccessComponent, IoxPageComponent, IoxPageModule, IoxSubmitButtonComponent, IoxUiModule, LinkedContainerComponent, PAGE_TRANSITION_CATEGORIES, PAGE_TRANSITION_PRESETS, PART_CLASS_NAMES, PIPE_DESCRIPTORS, PIPE_REGISTRY, PageScrollProvider, RESERVED_ALIAS_PREFIX, SUPPRESSED_STYLE_PROPS_BY_TYPE, SWIPER_RESPONSIVE_TRAITS, SWISS_FLAVOR, SectionComponent, TRANSITION_FEELS, TextBlockComponent, VALIDATION_STATES, VALIDATION_STATE_CLASS, VIRTUAL_TRAIT_GROUPS, VIRTUAL_TRAIT_KEYS, ViewPositionDirective, ViewPositionModule, activeActions, applyBindingPipes, applyFeel, breakpointDef, breakpointForWidth, breakpointQueryFor, buildDataSourceFilter, buildPartSelector, buildRelatedFilter, buildSwiperBreakpoints, buildTargetedStateSelector, buildTransitionTimeline, cascadeChain, clearInputOverride, clearOverride, collectContextSlotKeys, collectReferencedAliases, compileDeclarations, compilePageStyle, compileTokenCss, composeVirtualTraits, computeRelative, contextActionEffect, contextSlotKeys, countOverrides, dataSourcePlanToRequest, declaredInputNames, defaultMessageResolver, deriveSeoFromContent, describeSeoFields, effectiveTransitionId, excludeSelf, feelFor, flavorDefaultDeclarations, getByPath, getSeoValue, initialSlotValues, isActionEnabled, isContextAction, isInputOverriddenAt, isOverriddenAt, isReservedAlias, isValidSlotKey, legacyEnterToTransition, matchRouteParams, mediaQueryFor, mergeSwiperBreakpoints, nearestCommonAncestorId, nodeCssId, nodeUsesContext, normalizeCollectionResult, normalizeGalleryImage, normalizeIconClass, parentBreakpoint, parseUrlList, partClassName, planDataSource, planResponsiveRules, referencedDataSources, referencedDataSourcesDeep, renderDefaultDeclarations, resetSeoField, resolveBoundValue, resolveContextValue, resolveDerivedInto, resolveFlavorDefaults, resolveGalleryEffect, resolveGalleryUrls, resolveInputChain, resolveInputs, resolvePageTransition, resolvePath, resolveRelativeInto, resolveRepeaterItems, resolveSeo, resolveSiblings, resolveSingleItemId, resolveStateStyles, resolveStyleProps, resolveValueChain, rewriteViewportUnits, safeSetInput, setInputOverride, setOverride, setSeoAuto, setSeoBinding, setSeoOverride, setSeoValue, stateNamesIn, stripSuppressedProps, styleKeyToKebab, tokensToDarkVarMap, tokensToVarMap, validateFlavorPack, variableAliases, variableItemsFrom, withContextSlots, wrapInBreakpointQuery, wrapInMediaQuery };
|
|
7200
|
+
export { AOSService, BREAKPOINTS, Breakpoint, BreakpointQueryKind, BuilderButtonComponent, BuilderDividerComponent, BuilderHeadingComponent, BuilderIconComponent, BuilderImageComponent, BuilderLinkComponent, BuilderSpacerComponent, ButtonBlockComponent, CONTEXT_ACTION_TYPES, CardComponent, ClientGalleryComponent, ClientListComponent, ClientListItemComponent, ClientRepeaterComponent, ClientSliderContainerComponent, ClientSliderSlideComponent, ComponentInstanceRegistryService, ContainerComponent, ContextStore, DEFAULT_FLAVOR, DEFAULT_GALLERY_SCHEDULER, DEFAULT_PAGE_TRANSITION, DEFAULT_PAGE_TRANSITION_DURATION, DEFAULT_PAGE_TRANSITION_EASING, DEFAULT_PAGE_TRANSITION_PERSPECTIVE, DEFAULT_PHOSPHOR_WEIGHT, DEFAULT_WIDTH_BY_TYPE, DeclarationContext, FormRenderState, FormRuntimeService, GALLERY_EFFECTS, GALLERY_EFFECT_DESCRIPTORS, GalleryLoop, IOX_BUILDER_EVENTS, IOX_FORM_MESSAGES, IOX_FORM_NAVIGATOR, IOX_FORM_TRANSPORT, IS_PREVIEW, IoxAnimateContainer, IoxAosDirective, IoxAosModule, IoxBuilderComponentsModule, IoxComponentRegistryService, IoxFieldComponent, IoxFormComponent, IoxFormErrorComponent, IoxFormSuccessComponent, IoxPageComponent, IoxPageModule, IoxSubmitButtonComponent, IoxUiModule, LinkedContainerComponent, PAGE_TRANSITION_CATEGORIES, PAGE_TRANSITION_PRESETS, PART_CLASS_NAMES, PIPE_DESCRIPTORS, PIPE_REGISTRY, PageScrollProvider, RESERVED_ALIAS_PREFIX, SUPPRESSED_STYLE_PROPS_BY_TYPE, SWIPER_RESPONSIVE_TRAITS, SWISS_FLAVOR, SectionComponent, TRANSITION_FEELS, TextBlockComponent, VALIDATION_STATES, VALIDATION_STATE_CLASS, VIRTUAL_TRAIT_GROUPS, VIRTUAL_TRAIT_KEYS, ViewPositionDirective, ViewPositionModule, activeActions, apcaLc, applyBindingPipes, applyFeel, breakpointDef, breakpointForWidth, breakpointQueryFor, buildDataSourceFilter, buildPartSelector, buildRelatedFilter, buildSwiperBreakpoints, buildTargetedStateSelector, buildTransitionTimeline, cascadeChain, clearInputOverride, clearOverride, collectContextSlotKeys, collectReferencedAliases, compileDeclarations, compilePageStyle, compileTokenCss, composeVirtualTraits, computeRelative, contextActionEffect, contextSlotKeys, countOverrides, dataSourcePlanToRequest, declaredInputNames, defaultMessageResolver, deriveBrandTokens, deriveSeoFromContent, describeSeoFields, effectiveTransitionId, excludeSelf, feelFor, flavorDefaultDeclarations, getByPath, getSeoValue, initialSlotValues, isActionEnabled, isContextAction, isInputOverriddenAt, isOverriddenAt, isReservedAlias, isValidSlotKey, legacyEnterToTransition, matchRouteParams, mediaQueryFor, mergeSwiperBreakpoints, nearestCommonAncestorId, nodeCssId, nodeUsesContext, normalizeCollectionResult, normalizeGalleryImage, normalizeIconClass, oklabToRgb, parentBreakpoint, parseHexColor, parseUrlList, partClassName, planDataSource, planResponsiveRules, referencedDataSources, referencedDataSourcesDeep, relativeLuminance, renderDefaultDeclarations, resetSeoField, resolveBoundValue, resolveContextValue, resolveDerivedInto, resolveFlavorDefaults, resolveGalleryEffect, resolveGalleryUrls, resolveInputChain, resolveInputs, resolvePageTransition, resolvePath, resolveRelativeInto, resolveRepeaterItems, resolveSeo, resolveSiblings, resolveSingleItemId, resolveStateStyles, resolveStyleProps, resolveValueChain, rewriteViewportUnits, rgbToOklab, safeSetInput, setInputOverride, setOverride, setSeoAuto, setSeoBinding, setSeoOverride, setSeoValue, stateNamesIn, stripSuppressedProps, styleKeyToKebab, toHexColor, tokensToDarkVarMap, tokensToVarMap, validateFlavorPack, variableAliases, variableItemsFrom, wcagContrastRatio, withContextSlots, wrapInBreakpointQuery, wrapInMediaQuery };
|
|
6933
7201
|
//# sourceMappingURL=vectoriox-iox-ui.mjs.map
|