dsh-fonttune 0.2.7 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.en.md +22 -0
- package/CHANGELOG.md +22 -0
- package/README.en.md +11 -8
- package/README.md +11 -8
- package/lib/client.js +911 -132
- package/lib/index.js +6 -6
- package/lib/shared.cjs +551 -70
- package/package.json +1 -1
package/lib/shared.cjs
CHANGED
|
@@ -134,11 +134,105 @@ var UI_FOLLOWS_FIELD = "uiFollowsDialog";
|
|
|
134
134
|
var SIZE_MIN = -3;
|
|
135
135
|
var SIZE_MAX = 6;
|
|
136
136
|
|
|
137
|
-
/** Allowed
|
|
137
|
+
/** Allowed CODE weight range (an absolute value), and "do not touch". */
|
|
138
138
|
var WEIGHT_MIN = 300;
|
|
139
139
|
var WEIGHT_MAX = 600;
|
|
140
140
|
var WEIGHT_UNSET = 0;
|
|
141
141
|
|
|
142
|
+
/**
|
|
143
|
+
* Allowed range of the two RELATIVE weight axes, in steps of 100-weight.
|
|
144
|
+
*
|
|
145
|
+
* The conversation and interface weight axes are offsets on each element's own
|
|
146
|
+
* weight, not replacements: a flat `font-weight` over the markdown subtree
|
|
147
|
+
* erased the heading hierarchy (measured on 0.1.7-rc.2, where every markdown
|
|
148
|
+
* weight lives inside its `font` shorthand — `._markdown_ h2{font:var(--dsw-font-markdown-h2)}`
|
|
149
|
+
* with `700` in it — and a long-handed `font-weight` with `!important` beat the
|
|
150
|
+
* shorthand). The delta window is the old absolute window shifted by −400, so
|
|
151
|
+
* `300…600` maps onto `−100…+200` one-to-one and `400` (normal) becomes 0, which
|
|
152
|
+
* is the value meaning "do not touch".
|
|
153
|
+
*/
|
|
154
|
+
var WEIGHT_DELTA_MIN = -100;
|
|
155
|
+
var WEIGHT_DELTA_MAX = 200;
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* The widest range a font-derived slider may use, either way.
|
|
159
|
+
*
|
|
160
|
+
* The nominal window above is what the axes can always express; a family with
|
|
161
|
+
* faces outside it (a black 900 cut, a hairline 100) earns a wider slider — see
|
|
162
|
+
* `weightProfileFrom` — and these are the hard bounds that keeps that in check.
|
|
163
|
+
*/
|
|
164
|
+
var WEIGHT_DELTA_FLOOR = -300;
|
|
165
|
+
var WEIGHT_DELTA_CEIL = 600;
|
|
166
|
+
|
|
167
|
+
/** The weight DSH gives an element that declares none of its own. */
|
|
168
|
+
var WEIGHT_BASE = 400;
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* The weight range CSS accepts at all.
|
|
172
|
+
*
|
|
173
|
+
* Named because it is easy to confuse with `WEIGHT_MIN…WEIGHT_MAX`, which is the
|
|
174
|
+
* window an ABSOLUTE weight from a pre-relative document occupies (300…600) and
|
|
175
|
+
* has nothing to do with what a font can render.
|
|
176
|
+
*/
|
|
177
|
+
var WEIGHT_CSS_MIN = 100;
|
|
178
|
+
var WEIGHT_CSS_MAX = 900;
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* The weight ladder of the conversation: each group carries the weight DSH's
|
|
182
|
+
* own stylesheet gives those elements, so an offset lands ON TOP of it.
|
|
183
|
+
*
|
|
184
|
+
* The bases are the measured ones (`--dsw-font-markdown-h*-font-weight` 700 /
|
|
185
|
+
* 600, `-base-strong-font-weight` 600, `-table-head-font-weight` 500, everything
|
|
186
|
+
* else 400).
|
|
187
|
+
*/
|
|
188
|
+
var DIALOG_WEIGHT_GROUPS = [
|
|
189
|
+
{ base: 700, elements: "h1,h2,h3" },
|
|
190
|
+
{ base: 600, elements: "h4,h5,h6" },
|
|
191
|
+
{ base: 600, elements: "strong,b" },
|
|
192
|
+
{ base: 500, elements: "th" },
|
|
193
|
+
{
|
|
194
|
+
base: 400,
|
|
195
|
+
elements: "p,li,td,dt,dd,blockquote,summary,em,i,a,label,small,div,span",
|
|
196
|
+
},
|
|
197
|
+
];
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* The heaviest base in the conversation ladder — the layer with the least room.
|
|
201
|
+
*
|
|
202
|
+
* Derived from the ladder so the two cannot drift apart.
|
|
203
|
+
*/
|
|
204
|
+
var WEIGHT_LADDER_TOP = DIALOG_WEIGHT_GROUPS.reduce(function (top, group) {
|
|
205
|
+
return group.base > top ? group.base : top;
|
|
206
|
+
}, WEIGHT_BASE);
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* How far above its base an offset may reach at all.
|
|
210
|
+
*
|
|
211
|
+
* Every axis applies the offset to each element's OWN weight, and the heaviest
|
|
212
|
+
* layer of the ladder sits at `WEIGHT_LADDER_TOP`; past `WEIGHT_CSS_MAX` minus
|
|
213
|
+
* that, the heaviest layer cannot move any further, so a longer range would only
|
|
214
|
+
* add positions that change nothing for the boldest text on screen.
|
|
215
|
+
*
|
|
216
|
+
* Staying inside it has a second, load-bearing effect: offsets then never land in
|
|
217
|
+
* `WEIGHT_MIN…WEIGHT_MAX`, the range an ABSOLUTE weight from a pre-relative
|
|
218
|
+
* document occupies (see `clampWeightDelta`). The two meanings cannot be confused,
|
|
219
|
+
* so a stored offset is never rescaled into a different one.
|
|
220
|
+
*/
|
|
221
|
+
var WEIGHT_DELTA_UP_LIMIT = WEIGHT_CSS_MAX - WEIGHT_LADDER_TOP;
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* The heaviest layer a notch still has to move: bold text.
|
|
225
|
+
*
|
|
226
|
+
* The heading layer above it is deliberately left out of that requirement. A heavy
|
|
227
|
+
* family spaces its top faces far apart (a 700 cut next to a 900), so headings
|
|
228
|
+
* reach their heaviest rendering part-way up the range and would otherwise hold the
|
|
229
|
+
* whole control down to one wide step. Every notch must move the text you read and
|
|
230
|
+
* the text you emphasise; a heading that is already at its boldest face stays there.
|
|
231
|
+
*/
|
|
232
|
+
var WEIGHT_LADDER_STRONG = DIALOG_WEIGHT_GROUPS.reduce(function (strong, group) {
|
|
233
|
+
return group.base < WEIGHT_LADDER_TOP && group.base > strong ? group.base : strong;
|
|
234
|
+
}, WEIGHT_BASE);
|
|
235
|
+
|
|
142
236
|
/** Allowed line-height ratio range, in percent (100 = untouched). */
|
|
143
237
|
var LINE_HEIGHT_MIN = 100;
|
|
144
238
|
var LINE_HEIGHT_MAX = 160;
|
|
@@ -354,7 +448,7 @@ function normalizeField(field, value) {
|
|
|
354
448
|
case WEIGHT_FIELD:
|
|
355
449
|
case WEIGHT_DIALOG_FIELD:
|
|
356
450
|
case CODE_WEIGHT_FIELD:
|
|
357
|
-
return
|
|
451
|
+
return clampWeightDelta(value);
|
|
358
452
|
case LINE_HEIGHT_FIELD:
|
|
359
453
|
case LINE_HEIGHT_DIALOG_FIELD:
|
|
360
454
|
return clampRatio(value);
|
|
@@ -426,6 +520,33 @@ function clampWeight(value) {
|
|
|
426
520
|
return Math.min(WEIGHT_MAX, Math.max(WEIGHT_MIN, weight));
|
|
427
521
|
}
|
|
428
522
|
|
|
523
|
+
/**
|
|
524
|
+
* Clamp one RELATIVE weight to its allowed range, migrating an absolute value.
|
|
525
|
+
*
|
|
526
|
+
* A document written before the axes became relative stores an absolute weight
|
|
527
|
+
* (`300…600`, `400` = normal). That window sits entirely outside the delta
|
|
528
|
+
* window, so the conversion is unambiguous and idempotent: a value inside
|
|
529
|
+
* `300…600` is old and becomes its distance from normal (`400 → 0`, `560 → +160`,
|
|
530
|
+
* `300 → −100`), while a value already inside `−100…200` is a delta and is left
|
|
531
|
+
* alone. The user's saved setup therefore keeps meaning "as bold as before"
|
|
532
|
+
* instead of jumping to the top of the new scale.
|
|
533
|
+
*
|
|
534
|
+
* @param {unknown} value - candidate offset, or a pre-0.2.8 absolute weight.
|
|
535
|
+
* @returns {number} the offset the stylesheet may use.
|
|
536
|
+
*/
|
|
537
|
+
function clampWeightDelta(value) {
|
|
538
|
+
var delta = Number(value);
|
|
539
|
+
if (!isFinite(delta)) return WEIGHT_UNSET;
|
|
540
|
+
delta = Math.round(delta);
|
|
541
|
+
if (delta >= WEIGHT_MIN && delta <= WEIGHT_MAX) delta -= WEIGHT_BASE;
|
|
542
|
+
// The slider's own range comes from the font (see `weightProfileFrom`) and can
|
|
543
|
+
// reach further than the nominal one, so the hard bounds are the widest range
|
|
544
|
+
// any font-derived slider may use.
|
|
545
|
+
if (delta > WEIGHT_DELTA_CEIL) return WEIGHT_DELTA_CEIL;
|
|
546
|
+
if (delta < WEIGHT_DELTA_FLOOR) return WEIGHT_DELTA_FLOOR;
|
|
547
|
+
return delta;
|
|
548
|
+
}
|
|
549
|
+
|
|
429
550
|
/**
|
|
430
551
|
* Clamp one line-height ratio to the allowed percent range.
|
|
431
552
|
* @param {unknown} value - candidate ratio in percent.
|
|
@@ -943,6 +1064,28 @@ var DELTA_PATTERN = /^--dsh-content-font-delta(?:-secondary)?$/;
|
|
|
943
1064
|
/** The whole official content-size chain (size / line height / delta). */
|
|
944
1065
|
var CONTENT_PATTERN = /^--dsh-content-font-(?:size|line-height|delta)(?:-secondary)?$/;
|
|
945
1066
|
|
|
1067
|
+
/**
|
|
1068
|
+
* The one property the conversation size offset is added to: the official
|
|
1069
|
+
* "对话字号" source, which the app writes INLINE on `body`.
|
|
1070
|
+
*
|
|
1071
|
+
* Every other markdown size is derived from it (through
|
|
1072
|
+
* `--dsh-content-font-delta` and the markdown shorthands), and custom properties
|
|
1073
|
+
* resolve where they are DECLARED — so the offset has to land here, once, or a
|
|
1074
|
+
* deeper override would leave the derived tokens at their body-computed values.
|
|
1075
|
+
*/
|
|
1076
|
+
var CONTENT_SIZE_SOURCE = "--dsh-content-font-size";
|
|
1077
|
+
|
|
1078
|
+
/**
|
|
1079
|
+
* Whether one declared value is a plain literal this plugin may wrap in
|
|
1080
|
+
* `calc(… + Npx)`. A `var()` reference is NOT: it is either derived from a
|
|
1081
|
+
* property this plugin already shifted, or it belongs to another axis.
|
|
1082
|
+
* @param {unknown} value - a declared custom-property value.
|
|
1083
|
+
* @returns {boolean}
|
|
1084
|
+
*/
|
|
1085
|
+
function isLiteralTokenValue(value) {
|
|
1086
|
+
return typeof value === "string" && value !== "" && value.indexOf("var(") === -1;
|
|
1087
|
+
}
|
|
1088
|
+
|
|
946
1089
|
/**
|
|
947
1090
|
* The PART-token suffixes DSH appends for single-axis consumers.
|
|
948
1091
|
*/
|
|
@@ -1021,6 +1164,30 @@ function isMarkdownToken(name) {
|
|
|
1021
1164
|
return typeof name === "string" && name.indexOf("--dsw-font-markdown-") === 0 && !isCodeToken(name);
|
|
1022
1165
|
}
|
|
1023
1166
|
|
|
1167
|
+
/**
|
|
1168
|
+
* The one markdown family whose sizes are LITERALS instead of following the
|
|
1169
|
+
* official content-size chain: the `small` series (`12px/20px`, measured on
|
|
1170
|
+
* 0.1.7-rc.2).
|
|
1171
|
+
*
|
|
1172
|
+
* Every other markdown size derives from `--dsh-content-font-size` through
|
|
1173
|
+
* `--dsh-content-font-delta`, so shifting them as well applies the offset a
|
|
1174
|
+
* second time. The value cannot tell the families apart: the page also carries
|
|
1175
|
+
* `--dsw-font-markdown-h1` with its var() already substituted
|
|
1176
|
+
* (`700 calc(21px + -2px)/…`), which reads exactly like a literal and made
|
|
1177
|
+
* H1/H2 shrink while H3 stayed right (the asymmetric report that started this).
|
|
1178
|
+
* The NAME is the only reliable discriminator, so this is a whitelist.
|
|
1179
|
+
*/
|
|
1180
|
+
var MARKDOWN_LITERAL_PREFIX = "--dsw-font-markdown-small";
|
|
1181
|
+
|
|
1182
|
+
/**
|
|
1183
|
+
* Whether a token belongs to the literal (non-derived) markdown family.
|
|
1184
|
+
* @param {string} name - custom property name including the leading dashes.
|
|
1185
|
+
* @returns {boolean}
|
|
1186
|
+
*/
|
|
1187
|
+
function isMarkdownLiteralToken(name) {
|
|
1188
|
+
return typeof name === "string" && name.indexOf(MARKDOWN_LITERAL_PREFIX) === 0;
|
|
1189
|
+
}
|
|
1190
|
+
|
|
1024
1191
|
/**
|
|
1025
1192
|
* Whether one NAME looks like a `font` shorthand token (a bare
|
|
1026
1193
|
* `--dsw-font-…` name that is not a PART token or a family variable).
|
|
@@ -1258,8 +1425,7 @@ function codeSurfaceList() {
|
|
|
1258
1425
|
* not free: an ancestor-walking selector costs about 0.03 s per 50-step drag on
|
|
1259
1426
|
* 0.1.5-rc.3 (measured: stripping the ` *` forms from these two rules took the
|
|
1260
1427
|
* drag from 0.89 s to 0.52 s of style recalculation). The weight family keeps
|
|
1261
|
-
* the code subtree right through `--dfp-
|
|
1262
|
-
* `weightRule`.
|
|
1428
|
+
* the code subtree right through `--dfp-wdelta` instead — see `weightRule`.
|
|
1263
1429
|
*
|
|
1264
1430
|
* @param {{code?: string[], terminal?: string[]}|null} [hints] - unused; kept so
|
|
1265
1431
|
* the browser half can keep passing one harvest object to `buildFontCss`.
|
|
@@ -1351,16 +1517,19 @@ var WEIGHT_MARKDOWN_GUARD =
|
|
|
1351
1517
|
"))";
|
|
1352
1518
|
|
|
1353
1519
|
/**
|
|
1354
|
-
* The elements that carry a weight of their own in
|
|
1520
|
+
* The elements that carry a weight of their own in the INTERFACE (the chrome).
|
|
1355
1521
|
*
|
|
1356
1522
|
* The weight is the one property that cannot ride inheritance alone: an element
|
|
1357
1523
|
* whose own rule declares a weight ignores the value it would inherit, whatever
|
|
1358
|
-
* that value's importance. Measured on 0.1.5-rc.3, the
|
|
1359
|
-
*
|
|
1360
|
-
*
|
|
1361
|
-
*
|
|
1362
|
-
*
|
|
1363
|
-
*
|
|
1524
|
+
* that value's importance. Measured on 0.1.5-rc.3, the chrome's pinned elements
|
|
1525
|
+
* are `button` / `span` / `div`; the rest of the list is the inline markup that
|
|
1526
|
+
* could plausibly join them. This replaces the old `body,body *` reach, which
|
|
1527
|
+
* matched 1892 elements on every recalculation — the whole point of the table is
|
|
1528
|
+
* that it matches a fraction of that while still covering every pinned element.
|
|
1529
|
+
*
|
|
1530
|
+
* The CONVERSATION is not covered here: it has its own ladder with per-element
|
|
1531
|
+
* bases (`DIALOG_WEIGHT_GROUPS`), because one flat weight cannot preserve a
|
|
1532
|
+
* heading hierarchy.
|
|
1364
1533
|
*/
|
|
1365
1534
|
var WEIGHT_ELEMENT_TABLE = [
|
|
1366
1535
|
"button",
|
|
@@ -1512,6 +1681,196 @@ function resolveAxes(config) {
|
|
|
1512
1681
|
* the stylesheet builder
|
|
1513
1682
|
* ------------------------------------------------------------------ */
|
|
1514
1683
|
|
|
1684
|
+
/**
|
|
1685
|
+
* The steps a weight slider may use, finest first.
|
|
1686
|
+
*
|
|
1687
|
+
* A family ships a fixed set of faces and the browser rounds any requested
|
|
1688
|
+
* weight to the nearest one, so a slider that runs in single units spends long
|
|
1689
|
+
* stretches on one face. The control is therefore built from what the family can
|
|
1690
|
+
* actually render: its range runs from the lightest face it has to the heaviest,
|
|
1691
|
+
* and its notch is the family's own granularity.
|
|
1692
|
+
*/
|
|
1693
|
+
var WEIGHT_STEP_CANDIDATES = [1, 5, 10, 25, 50, 100, 200, 300];
|
|
1694
|
+
|
|
1695
|
+
/** The weight grid the profile is measured on. */
|
|
1696
|
+
var WEIGHT_PROBE_LOW = 100;
|
|
1697
|
+
var WEIGHT_PROBE_HIGH = 900;
|
|
1698
|
+
var WEIGHT_PROBE_STEP = 10;
|
|
1699
|
+
|
|
1700
|
+
/** Round down/up to a multiple of `step`. */
|
|
1701
|
+
function floorTo(value, step) {
|
|
1702
|
+
return Math.floor(value / step) * step;
|
|
1703
|
+
}
|
|
1704
|
+
function ceilTo(value, step) {
|
|
1705
|
+
return Math.ceil(value / step) * step;
|
|
1706
|
+
}
|
|
1707
|
+
|
|
1708
|
+
/**
|
|
1709
|
+
* Does every position of `[min..max]` in `step` increments render differently?
|
|
1710
|
+
*
|
|
1711
|
+
* Checked at every base the offset is added to: a step that is fine for body text
|
|
1712
|
+
* can be a no-op one layer up, where the faces are further apart.
|
|
1713
|
+
* @param {(weight: number) => string|number} sample - probe.
|
|
1714
|
+
* @param {number[]} bases - the weights the offsets are added to.
|
|
1715
|
+
* @param {number} min - first offset.
|
|
1716
|
+
* @param {number} max - last offset.
|
|
1717
|
+
* @param {number} step - offset increment.
|
|
1718
|
+
* @returns {boolean} true when no two neighbours render the same at any base.
|
|
1719
|
+
*/
|
|
1720
|
+
function everyPositionDiffers(sample, bases, min, max, step) {
|
|
1721
|
+
for (var index = 0; index < bases.length; index += 1) {
|
|
1722
|
+
var base = bases[index];
|
|
1723
|
+
var previous = null;
|
|
1724
|
+
for (var position = min; position <= max; position += step) {
|
|
1725
|
+
var signature = sample(base + position);
|
|
1726
|
+
if (previous !== null && signature === previous) return false;
|
|
1727
|
+
previous = signature;
|
|
1728
|
+
}
|
|
1729
|
+
}
|
|
1730
|
+
return true;
|
|
1731
|
+
}
|
|
1732
|
+
|
|
1733
|
+
/**
|
|
1734
|
+
* The slider a family deserves: how far it can go, and by how much.
|
|
1735
|
+
*
|
|
1736
|
+
* A font with six faces can be made lighter or heavier only as far as those faces
|
|
1737
|
+
* reach, and only in steps between them; a family with a continuous axis gets a
|
|
1738
|
+
* fine step and a wide range. Measured on a weight grid:
|
|
1739
|
+
* - the downward reach is the highest weight that still renders as light as the
|
|
1740
|
+
* family can (asking for less cannot change anything);
|
|
1741
|
+
* - the upward reach is the LOWEST weight at or above the layer a notch has to
|
|
1742
|
+
* move that already renders as heavy as the family can, so the range ends where
|
|
1743
|
+
* bold text stops changing instead of running past it (see `WEIGHT_DELTA_UP_LIMIT`
|
|
1744
|
+
* for why that ceiling is also the widest one allowed);
|
|
1745
|
+
* - the step is the finest candidate whose positions all differ at every base a
|
|
1746
|
+
* notch has to move, so no notch is a no-op for body text or bold text. A family whose faces are unevenly spaced
|
|
1747
|
+
* (a 700 next to a 900) may end up with one repeated position whichever uniform
|
|
1748
|
+
* step is used — the coarsest candidate is then the honest answer, never a crash.
|
|
1749
|
+
* @param {(weight: number) => string|number} sample - renders a probe at one
|
|
1750
|
+
* weight and returns a signature; equal signatures mean identical rendering.
|
|
1751
|
+
* @param {{candidates?: number[], floor?: number, ceil?: number, top?: number}}
|
|
1752
|
+
* [options] overrides for the candidates, the widest allowed range and the
|
|
1753
|
+
* heaviest base the offset is added to (the ladder's, or the axis's own).
|
|
1754
|
+
* @returns {{min: number, max: number, step: number}} the slider's shape; the
|
|
1755
|
+
* range always contains 0, which is the "leave DSH alone" position.
|
|
1756
|
+
*/
|
|
1757
|
+
function weightProfileFrom(sample, options) {
|
|
1758
|
+
var settings = options || {};
|
|
1759
|
+
var candidates =
|
|
1760
|
+
Array.isArray(settings.candidates) && settings.candidates.length > 0
|
|
1761
|
+
? settings.candidates
|
|
1762
|
+
: WEIGHT_STEP_CANDIDATES;
|
|
1763
|
+
var floor = typeof settings.floor === "number" ? settings.floor : WEIGHT_DELTA_FLOOR;
|
|
1764
|
+
var ceil = typeof settings.ceil === "number" ? settings.ceil : WEIGHT_DELTA_CEIL;
|
|
1765
|
+
var top = typeof settings.top === "number" ? settings.top : WEIGHT_LADDER_STRONG;
|
|
1766
|
+
var topSignature = sample(WEIGHT_PROBE_HIGH);
|
|
1767
|
+
var bottomSignature = sample(WEIGHT_PROBE_LOW);
|
|
1768
|
+
var heaviest = WEIGHT_PROBE_HIGH;
|
|
1769
|
+
for (var weight = WEIGHT_PROBE_LOW; weight <= WEIGHT_PROBE_HIGH; weight += WEIGHT_PROBE_STEP) {
|
|
1770
|
+
if (sample(weight) === topSignature) {
|
|
1771
|
+
heaviest = weight;
|
|
1772
|
+
break;
|
|
1773
|
+
}
|
|
1774
|
+
}
|
|
1775
|
+
var lightest = WEIGHT_PROBE_LOW;
|
|
1776
|
+
for (var back = WEIGHT_PROBE_HIGH; back >= WEIGHT_PROBE_LOW; back -= WEIGHT_PROBE_STEP) {
|
|
1777
|
+
if (sample(back) === bottomSignature) {
|
|
1778
|
+
lightest = back;
|
|
1779
|
+
break;
|
|
1780
|
+
}
|
|
1781
|
+
}
|
|
1782
|
+
// How far the offset can go before NO layer that must move can move any more:
|
|
1783
|
+
// the widest horizon among those bases, since a layer that could still change
|
|
1784
|
+
// must not be cut off by one that already sits at its heaviest face.
|
|
1785
|
+
var headroom = Math.max(0, heaviest - WEIGHT_BASE);
|
|
1786
|
+
if (top !== WEIGHT_BASE) {
|
|
1787
|
+
for (var up = top; up <= WEIGHT_PROBE_HIGH; up += WEIGHT_PROBE_STEP) {
|
|
1788
|
+
if (sample(up) === topSignature) {
|
|
1789
|
+
headroom = Math.max(headroom, up - top);
|
|
1790
|
+
break;
|
|
1791
|
+
}
|
|
1792
|
+
}
|
|
1793
|
+
}
|
|
1794
|
+
var reachUp = Math.min(ceil, WEIGHT_DELTA_UP_LIMIT, headroom);
|
|
1795
|
+
var reachDown = Math.max(floor, Math.min(0, lightest - WEIGHT_BASE));
|
|
1796
|
+
var bases = top === WEIGHT_BASE ? [WEIGHT_BASE] : [WEIGHT_BASE, top];
|
|
1797
|
+
for (var index = 0; index < candidates.length; index += 1) {
|
|
1798
|
+
var step = candidates[index];
|
|
1799
|
+
if (!(step > 0)) continue;
|
|
1800
|
+
var min = floorTo(reachDown, step);
|
|
1801
|
+
// Rounding up to the step must not push the range past the limit: the widest
|
|
1802
|
+
// offset has to stay out of the absolute-weight window.
|
|
1803
|
+
var max = Math.min(ceilTo(reachUp, step), WEIGHT_DELTA_UP_LIMIT);
|
|
1804
|
+
// A step wider than the range would leave only one reachable position.
|
|
1805
|
+
if (max > min && step > max - min) continue;
|
|
1806
|
+
if (everyPositionDiffers(sample, bases, min, max, step)) {
|
|
1807
|
+
return { min: min, max: max, step: step };
|
|
1808
|
+
}
|
|
1809
|
+
}
|
|
1810
|
+
var coarsest = candidates[candidates.length - 1];
|
|
1811
|
+
var min = floorTo(reachDown, coarsest);
|
|
1812
|
+
var max = Math.min(ceilTo(reachUp, coarsest), WEIGHT_DELTA_UP_LIMIT);
|
|
1813
|
+
// Nothing kept every position alive: the coarsest step that still fits is the
|
|
1814
|
+
// honest answer, never a step the control cannot reach.
|
|
1815
|
+
var span = max - min;
|
|
1816
|
+
return { min: min, max: max, step: span > 0 ? Math.min(coarsest, span) : 1 };
|
|
1817
|
+
}
|
|
1818
|
+
|
|
1819
|
+
/**
|
|
1820
|
+
* Turn a measured profile into the slider the card shows.
|
|
1821
|
+
*
|
|
1822
|
+
* The document keeps storing a weight offset (so nothing written before has to be
|
|
1823
|
+
* migrated), but the CONTROL counts the family's own steps: a six-face family
|
|
1824
|
+
* offers "-2 … +4" instead of "-200 … +400", which is what a reader can actually
|
|
1825
|
+
* see. `unit` is how many weight units one step is worth.
|
|
1826
|
+
* @param {{min: number, max: number, step: number}} profile - measured shape.
|
|
1827
|
+
* @param {number} value - the stored offset, in weight units.
|
|
1828
|
+
* @returns {{min: number, max: number, unit: number, value: number}} the slider
|
|
1829
|
+
* in step counts; a stored value outside the measured range widens it, so it is
|
|
1830
|
+
* never unreachable.
|
|
1831
|
+
*/
|
|
1832
|
+
function weightStepRange(profile, value) {
|
|
1833
|
+
var unit = profile && profile.step > 0 ? profile.step : 1;
|
|
1834
|
+
var count = Math.round(Number(value) / unit);
|
|
1835
|
+
if (!isFinite(count)) count = 0;
|
|
1836
|
+
var min = Math.floor(profile.min / unit);
|
|
1837
|
+
var max = Math.ceil(profile.max / unit);
|
|
1838
|
+
if (count < min) min = count;
|
|
1839
|
+
if (count > max) max = count;
|
|
1840
|
+
return { min: min, max: max, unit: unit, value: count };
|
|
1841
|
+
}
|
|
1842
|
+
|
|
1843
|
+
/**
|
|
1844
|
+
* What a slider's local (unconfirmed) value should do when a value arrives from
|
|
1845
|
+
* the settings document.
|
|
1846
|
+
*
|
|
1847
|
+
* A slider keeps the value the user released until the document echoes it back;
|
|
1848
|
+
* dropping it immediately would show the old number for a frame (the "bounce
|
|
1849
|
+
* back, then settle" flicker). Two cases must NOT drop it:
|
|
1850
|
+
* - a confirmation for the PREVIOUS commit arriving after the user already
|
|
1851
|
+
* started a new drag — the document write is debounced and can land seconds
|
|
1852
|
+
* later (measured on 0.1.7-rc.2: 0.7–5 s), and clearing there snapped the
|
|
1853
|
+
* thumb back to the old value mid-drag;
|
|
1854
|
+
* - any unrelated outside value (another page, a reset) arriving mid-drag.
|
|
1855
|
+
*
|
|
1856
|
+
* @param {{pending: number|null, awaiting: number|null, confirmed: number}} state
|
|
1857
|
+
* the local value, the value a commit is waiting for (null when idle), and the
|
|
1858
|
+
* value the document currently reports.
|
|
1859
|
+
* @returns {{pending: number|null, awaiting: number|null}} the state to keep.
|
|
1860
|
+
*/
|
|
1861
|
+
function reconcileSliderValue(state) {
|
|
1862
|
+
var pending = state.pending;
|
|
1863
|
+
var awaiting = state.awaiting;
|
|
1864
|
+
var confirmed = state.confirmed;
|
|
1865
|
+
if (awaiting !== null && confirmed === awaiting) {
|
|
1866
|
+
awaiting = null;
|
|
1867
|
+
if (pending === confirmed) pending = null;
|
|
1868
|
+
return { pending: pending, awaiting: awaiting };
|
|
1869
|
+
}
|
|
1870
|
+
if (awaiting === null && pending !== null && pending === confirmed) pending = null;
|
|
1871
|
+
return { pending: pending, awaiting: awaiting };
|
|
1872
|
+
}
|
|
1873
|
+
|
|
1515
1874
|
/**
|
|
1516
1875
|
* Whether a normalized configuration asks for any change at all.
|
|
1517
1876
|
* @param {unknown} config - candidate configuration.
|
|
@@ -1537,9 +1896,9 @@ function isDormant(config) {
|
|
|
1537
1896
|
sanitize(axis[MONO_FIELD]) === "" &&
|
|
1538
1897
|
clampOffset(axis[SIZE_DIALOG_FIELD]) === 0 &&
|
|
1539
1898
|
clampOffset(axis[CODE_SIZE_FIELD]) === 0 &&
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1899
|
+
clampWeightDelta(axis[WEIGHT_FIELD]) === WEIGHT_UNSET &&
|
|
1900
|
+
clampWeightDelta(axis[WEIGHT_DIALOG_FIELD]) === WEIGHT_UNSET &&
|
|
1901
|
+
clampWeightDelta(axis[CODE_WEIGHT_FIELD]) === WEIGHT_UNSET &&
|
|
1543
1902
|
clampRatio(axis[LINE_HEIGHT_DIALOG_FIELD]) === LINE_HEIGHT_MIN &&
|
|
1544
1903
|
clampLineOffset(axis[CODE_LINE_HEIGHT_FIELD]) === 0 &&
|
|
1545
1904
|
clampLigatures(axis[LIGATURES_FIELD]) === LIGATURES_DEFAULT &&
|
|
@@ -1572,8 +1931,9 @@ function buildAxisCss(axis, baseTokens, isDark, hints) {
|
|
|
1572
1931
|
var dialog = formatStack(parseStack(axis[STACK_DIALOG_FIELD]));
|
|
1573
1932
|
// Normalised once: an expanded axis always carries a number, but a caller
|
|
1574
1933
|
// handing in a raw object may leave the field out, and "absent" has to mean
|
|
1575
|
-
// "unset" rather than "write the string undefined".
|
|
1576
|
-
|
|
1934
|
+
// "unset" rather than "write the string undefined". The conversation's value
|
|
1935
|
+
// is an OFFSET (see `clampWeightDelta`), not a weight.
|
|
1936
|
+
var dialogDelta = typeof axis[WEIGHT_DIALOG_FIELD] === "number" ? axis[WEIGHT_DIALOG_FIELD] : WEIGHT_UNSET;
|
|
1577
1937
|
var codeSurfaces = codeSelector(hints);
|
|
1578
1938
|
var dialogSurfaces = dialogSelector(hints);
|
|
1579
1939
|
var declarations = [];
|
|
@@ -1610,24 +1970,86 @@ function buildAxisCss(axis, baseTokens, isDark, hints) {
|
|
|
1610
1970
|
* plus an element table for the tags DSH pins a weight on of their own (see
|
|
1611
1971
|
* `WEIGHT_ELEMENT_TABLE`).
|
|
1612
1972
|
*
|
|
1613
|
-
* The
|
|
1973
|
+
* The offset rides a custom property (`--dfp-wdelta`, declared on
|
|
1614
1974
|
* `:root,body` by the caller) rather than a literal. That is what keeps the
|
|
1615
1975
|
* code subtree right without a descendant selector: a highlight `<span>`
|
|
1616
1976
|
* inside a `<pre>` IS matched by this rule's table, but it resolves the
|
|
1617
|
-
* variable its code ancestor set (see the code weight
|
|
1618
|
-
* code
|
|
1977
|
+
* variable its code ancestor set (see the code weight rules), so it takes the
|
|
1978
|
+
* code offset instead of the interface one. Naming `pre *` and friends here
|
|
1619
1979
|
* or in the code rules instead cost 0.03 s per selector per drag.
|
|
1620
1980
|
*
|
|
1621
|
-
* The markdown guard only rides along when the conversation has NO
|
|
1622
|
-
* its own — with one set, the class-scoped
|
|
1623
|
-
* inside markdown anyway.
|
|
1981
|
+
* The markdown guard only rides along when the conversation has NO offset of
|
|
1982
|
+
* its own — with one set, the class-scoped conversation ladder out-ranks this
|
|
1983
|
+
* rule inside markdown anyway.
|
|
1624
1984
|
*/
|
|
1625
1985
|
function weightRule(declarations) {
|
|
1626
1986
|
var base = isDark ? DARK_ATTR : "body";
|
|
1627
1987
|
var selector = base + "," + base + " :where(" + WEIGHT_ELEMENT_TABLE + ")";
|
|
1628
|
-
if (
|
|
1988
|
+
if (dialogDelta === WEIGHT_UNSET) selector += WEIGHT_MARKDOWN_GUARD;
|
|
1629
1989
|
return selector + "{" + declarations + "}";
|
|
1630
1990
|
}
|
|
1991
|
+
/**
|
|
1992
|
+
* The weight one element group resolves to: its own base plus the offset that
|
|
1993
|
+
* is in force where the element sits, clamped to the legal CSS range so an
|
|
1994
|
+
* extreme offset cannot leave it (a weight below 100 is invalid, above 900 is
|
|
1995
|
+
* ignored by the font).
|
|
1996
|
+
* @param {number} base - the weight DSH gives this group.
|
|
1997
|
+
* @returns {string} the `font-weight` value.
|
|
1998
|
+
*/
|
|
1999
|
+
function ladderWeight(base) {
|
|
2000
|
+
return (
|
|
2001
|
+
"clamp(" + WEIGHT_CSS_MIN + ",calc(" + base + " + var(--dfp-wdelta,0))," + WEIGHT_CSS_MAX + ")"
|
|
2002
|
+
);
|
|
2003
|
+
}
|
|
2004
|
+
/**
|
|
2005
|
+
* The scope the conversation WEIGHT rules hang on: the cheap markdown wrapper
|
|
2006
|
+
* (the harvested hint when the page has one, the substring form otherwise).
|
|
2007
|
+
*
|
|
2008
|
+
* Not the family rule's `dialogSurfaces` list: that one has to reach every
|
|
2009
|
+
* descendant because it overrides an inherited family, while the ladder names
|
|
2010
|
+
* its own elements — and reusing that list would multiply its ancestor-walking
|
|
2011
|
+
* `… *` selectors by five groups, which is exactly the cost the element table
|
|
2012
|
+
* was introduced to remove. Code surfaces need no exclusion here either: the
|
|
2013
|
+
* code rules pin `--dfp-wdelta` on themselves, so an element inside one adds
|
|
2014
|
+
* the offset in force THERE (the code's), which is the value it should get.
|
|
2015
|
+
* @returns {string} one selector.
|
|
2016
|
+
*/
|
|
2017
|
+
function weightScopeSelector() {
|
|
2018
|
+
return hints !== null && typeof hints === "object" && typeof hints.markdown === "string"
|
|
2019
|
+
? hints.markdown
|
|
2020
|
+
: '[class*="_markdown_" i]';
|
|
2021
|
+
}
|
|
2022
|
+
/**
|
|
2023
|
+
* A rule for the conversation scope itself, so text sitting directly in the
|
|
2024
|
+
* container moves with the axis (and so `--dfp-wdelta` is pinned for the
|
|
2025
|
+
* ladder below before any child resolves it).
|
|
2026
|
+
* @param {string} declarations - the declarations to write.
|
|
2027
|
+
* @returns {string} the rule.
|
|
2028
|
+
*/
|
|
2029
|
+
function weightScopeRule(declarations) {
|
|
2030
|
+
var scope = weightScopeSelector();
|
|
2031
|
+
return (isDark ? DARK_ATTR + " " : "") + scope + "{" + declarations + "}";
|
|
2032
|
+
}
|
|
2033
|
+
/**
|
|
2034
|
+
* The conversation ladder: one rule per group in `DIALOG_WEIGHT_GROUPS`, each
|
|
2035
|
+
* scoped under the conversation.
|
|
2036
|
+
* @param {string} surfaceList - a comma-separated selector list.
|
|
2037
|
+
* @returns {string[]} one rule per group.
|
|
2038
|
+
*/
|
|
2039
|
+
function weightLadderRules(surfaceList) {
|
|
2040
|
+
var rules = [];
|
|
2041
|
+
var surfaces = splitSelectorList(surfaceList);
|
|
2042
|
+
for (var groupIndex = 0; groupIndex < DIALOG_WEIGHT_GROUPS.length; groupIndex += 1) {
|
|
2043
|
+
var group = DIALOG_WEIGHT_GROUPS[groupIndex];
|
|
2044
|
+
var scoped = [];
|
|
2045
|
+
for (var surfaceIndex = 0; surfaceIndex < surfaces.length; surfaceIndex += 1) {
|
|
2046
|
+
var one = surfaces[surfaceIndex] + " :is(" + group.elements + ")";
|
|
2047
|
+
scoped.push(isDark ? DARK_ATTR + " " + one : one);
|
|
2048
|
+
}
|
|
2049
|
+
rules.push(scoped.join(",") + "{font-weight:" + ladderWeight(group.base) + " !important}");
|
|
2050
|
+
}
|
|
2051
|
+
return rules;
|
|
2052
|
+
}
|
|
1631
2053
|
/**
|
|
1632
2054
|
* Re-assert the code family inside the dialog: scoped under the markdown
|
|
1633
2055
|
* container, after the dialog rule and above it in specificity, so a
|
|
@@ -1685,39 +2107,35 @@ function buildAxisCss(axis, baseTokens, isDark, hints) {
|
|
|
1685
2107
|
// page-wide `font-family` on body plus the theme variable) and the weight
|
|
1686
2108
|
// (below).
|
|
1687
2109
|
|
|
1688
|
-
// ---- interface weight ----
|
|
2110
|
+
// ---- interface weight (a relative offset) ----
|
|
1689
2111
|
// A `body{font-weight}` rule only reaches the elements that INHERIT their
|
|
1690
2112
|
// weight; the chrome's `button` / `span` / `div` class rules pin their own
|
|
1691
2113
|
// (measured on 0.1.5-rc.3), which is why the second reach exists. The
|
|
1692
2114
|
// conversation is held apart by `weightRule`'s guard (or by the class-scoped
|
|
1693
|
-
//
|
|
1694
|
-
|
|
2115
|
+
// conversation ladder when the conversation has an offset of its own).
|
|
2116
|
+
//
|
|
2117
|
+
// The value is an OFFSET on the element's own weight, never a replacement, so
|
|
2118
|
+
// raising the interface weight cannot flatten anything that shipped heavier
|
|
2119
|
+
// than the base. The offset rides `--dfp-wdelta` so the code rules can pin it
|
|
2120
|
+
// back to zero (or to the code offset) on their surfaces without any
|
|
2121
|
+
// descendant selector.
|
|
2122
|
+
var interfaceDelta = typeof axis[WEIGHT_FIELD] === "number" ? axis[WEIGHT_FIELD] : WEIGHT_UNSET;
|
|
1695
2123
|
var codeWeight = typeof axis[CODE_WEIGHT_FIELD] === "number" ? axis[CODE_WEIGHT_FIELD] : WEIGHT_UNSET;
|
|
1696
|
-
if (
|
|
1697
|
-
// The variable the weight rule resolves; the code rules below override it
|
|
1698
|
-
// on their surfaces so everything inside them inherits the code weight.
|
|
2124
|
+
if (interfaceDelta !== WEIGHT_UNSET) {
|
|
1699
2125
|
declarations.push(
|
|
1700
|
-
(isDark ? DARK_ATTR : ":root,body") +
|
|
1701
|
-
"{--dfp-interface-weight:" +
|
|
1702
|
-
interfaceWeight +
|
|
1703
|
-
"}"
|
|
1704
|
-
);
|
|
1705
|
-
declarations.push(
|
|
1706
|
-
weightRule(
|
|
1707
|
-
"font-weight:var(--dfp-interface-weight," + interfaceWeight + ") !important"
|
|
1708
|
-
)
|
|
2126
|
+
(isDark ? DARK_ATTR : ":root,body") + "{--dfp-wdelta:" + interfaceDelta + "}"
|
|
1709
2127
|
);
|
|
2128
|
+
declarations.push(weightRule("font-weight:" + ladderWeight(WEIGHT_BASE) + " !important"));
|
|
1710
2129
|
if (codeWeight === WEIGHT_UNSET) {
|
|
1711
2130
|
// The code rules come after this one and win on their own (class hooks by
|
|
1712
2131
|
// specificity, element selectors by order), so code surfaces — which
|
|
1713
2132
|
// inherit nothing but start from the body weight — are reset here.
|
|
1714
2133
|
// `normal` is what DSH computes for them (the code `font` shorthands
|
|
1715
2134
|
// carry no weight), so an unset code weight keeps code exactly as DSH
|
|
1716
|
-
// shipped it. The
|
|
1717
|
-
// surface (which the interface table matches) lands on `normal`
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
);
|
|
2135
|
+
// shipped it. The offset is pinned to zero alongside so an element INSIDE
|
|
2136
|
+
// a code surface (which the interface table matches) lands on `normal`
|
|
2137
|
+
// too.
|
|
2138
|
+
declarations.push(codeRule("font-weight:normal !important;--dfp-wdelta:0"));
|
|
1721
2139
|
}
|
|
1722
2140
|
}
|
|
1723
2141
|
|
|
@@ -1730,17 +2148,55 @@ function buildAxisCss(axis, baseTokens, isDark, hints) {
|
|
|
1730
2148
|
}
|
|
1731
2149
|
}
|
|
1732
2150
|
|
|
1733
|
-
// ---- dialog weight (
|
|
1734
|
-
|
|
1735
|
-
|
|
2151
|
+
// ---- dialog weight (a relative offset, applied element by element) ----
|
|
2152
|
+
// The conversation cannot take one flat weight: DSH gives h1..h3 700,
|
|
2153
|
+
// h4..h6/strong 600, th 500 and the rest 400, all inside `font` shorthands, so
|
|
2154
|
+
// a single `font-weight: <value> !important` on the markdown scope replaced
|
|
2155
|
+
// every one of them with that value — setting the axis at all flattened the
|
|
2156
|
+
// headings (measured on 0.1.7-rc.2: `##` came out at the body weight). The
|
|
2157
|
+
// ladder below re-states each group's own base PLUS the offset, so the
|
|
2158
|
+
// hierarchy survives any offset, in both directions, and `d = 0` injects
|
|
2159
|
+
// nothing at all.
|
|
2160
|
+
if (dialogDelta === WEIGHT_UNSET && interfaceDelta !== WEIGHT_UNSET) {
|
|
2161
|
+
// The conversation has NO offset of its own — which is exactly why it has to
|
|
2162
|
+
// say so. The interface axis declares `--dfp-wdelta` on `:root,body`, so an
|
|
2163
|
+
// unset conversation INHERITED it: with the interface at +80 the card showed 0
|
|
2164
|
+
// for the conversation while the page rendered +80, and the first notch above
|
|
2165
|
+
// it only added 20 units — a step nobody can see (measured on 0.1.7-rc.2:
|
|
2166
|
+
// `delta` read 80 at the "0" position and 100 at "+1"). Pinning zero keeps
|
|
2167
|
+
// "0 = leave DSH alone" true no matter what the other axes are set to.
|
|
2168
|
+
declarations.push(weightScopeRule("--dfp-wdelta:0"));
|
|
2169
|
+
}
|
|
2170
|
+
if (dialogDelta !== WEIGHT_UNSET) {
|
|
2171
|
+
// Every ladder rule reads `--dfp-wdelta`, so the conversation pins it to its
|
|
2172
|
+
// own offset: the interface's value must not leak in, and an element inside
|
|
2173
|
+
// a code surface inside the conversation still resolves the code offset that
|
|
2174
|
+
// the code rules pin on their own surfaces. The scope itself takes the base
|
|
2175
|
+
// group's weight, so text sitting directly in the container moves with the
|
|
2176
|
+
// axis exactly as it did when the axis was absolute.
|
|
2177
|
+
declarations.push(
|
|
2178
|
+
weightScopeRule(
|
|
2179
|
+
"--dfp-wdelta:" + dialogDelta + ";font-weight:" + ladderWeight(WEIGHT_BASE) + " !important"
|
|
2180
|
+
)
|
|
2181
|
+
);
|
|
2182
|
+
var dialogLadder = weightLadderRules(weightScopeSelector());
|
|
2183
|
+
for (var ladderIndex = 0; ladderIndex < dialogLadder.length; ladderIndex += 1) {
|
|
2184
|
+
declarations.push(dialogLadder[ladderIndex]);
|
|
2185
|
+
}
|
|
1736
2186
|
// The card's conversation preview simulates this surface, so it takes the
|
|
1737
|
-
// same
|
|
2187
|
+
// same ladder (and is excluded from the interface rule above).
|
|
1738
2188
|
declarations.push(
|
|
1739
2189
|
(isDark ? DARK_ATTR + " " : "") +
|
|
1740
|
-
".dfp-previewDialog{
|
|
1741
|
-
|
|
2190
|
+
".dfp-previewDialog{--dfp-wdelta:" +
|
|
2191
|
+
dialogDelta +
|
|
2192
|
+
";font-weight:" +
|
|
2193
|
+
ladderWeight(WEIGHT_BASE) +
|
|
1742
2194
|
" !important}"
|
|
1743
2195
|
);
|
|
2196
|
+
var previewLadder = weightLadderRules(".dfp-previewDialog");
|
|
2197
|
+
for (var previewIndex = 0; previewIndex < previewLadder.length; previewIndex += 1) {
|
|
2198
|
+
declarations.push(previewLadder[previewIndex]);
|
|
2199
|
+
}
|
|
1744
2200
|
}
|
|
1745
2201
|
|
|
1746
2202
|
// ---- dialog size offset (additive, on the official content-size source) ----
|
|
@@ -1757,32 +2213,33 @@ function buildAxisCss(axis, baseTokens, isDark, hints) {
|
|
|
1757
2213
|
var dialogOffsetValue = axis[SIZE_DIALOG_FIELD];
|
|
1758
2214
|
if (dialogOffsetValue !== 0) {
|
|
1759
2215
|
var contentSources = tokenNames(baseTokens).filter(function (name) {
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
//
|
|
1763
|
-
//
|
|
1764
|
-
return
|
|
1765
|
-
|
|
1766
|
-
base !== "" &&
|
|
1767
|
-
base.indexOf("var(") === -1 &&
|
|
1768
|
-
base.indexOf("calc(") === -1
|
|
1769
|
-
);
|
|
2216
|
+
// The source property, by NAME: `--dsh-content-font-size`. The derived
|
|
2217
|
+
// members of the chain (`-delta`, `-size-secondary`, the markdown
|
|
2218
|
+
// shorthands) all read it, so shifting them as well would count the offset
|
|
2219
|
+
// twice.
|
|
2220
|
+
if (name !== CONTENT_SIZE_SOURCE) return false;
|
|
2221
|
+
return isLiteralTokenValue(baseTokens[name]);
|
|
1770
2222
|
});
|
|
1771
2223
|
var contentShift = shiftTokens(contentSources, baseTokens, dialogOffsetValue);
|
|
1772
2224
|
if (contentShift.length > 0) declarations.push(rootRule(contentShift.join(";")));
|
|
1773
|
-
// The `small` series is the only markdown family with literal sizes: it
|
|
1774
|
-
//
|
|
2225
|
+
// The `small` series is the only markdown family with literal sizes: it does
|
|
2226
|
+
// not derive from the chain, so its parts and shorthands shift here — and
|
|
2227
|
+
// ONLY it, by name. A value test cannot stand in for the name: the page also
|
|
2228
|
+
// carries `--dsw-font-markdown-h1` with its var() already substituted, which
|
|
2229
|
+
// looks like a literal and used to take the offset a second time (H1/H2
|
|
2230
|
+
// shrank, H3 did not).
|
|
1775
2231
|
var literals = markdownTokenNames(baseTokens).filter(function (name) {
|
|
1776
|
-
|
|
1777
|
-
|
|
2232
|
+
return (
|
|
2233
|
+
isMarkdownLiteralToken(name) &&
|
|
2234
|
+
name.indexOf("-font-size") >= 0 &&
|
|
2235
|
+
isLiteralTokenValue(baseTokens[name])
|
|
2236
|
+
);
|
|
1778
2237
|
});
|
|
1779
2238
|
var literalShift = shiftTokens(literals, baseTokens, dialogOffsetValue);
|
|
1780
2239
|
if (literalShift.length > 0) declarations.push(rootRule(literalShift.join(";")));
|
|
1781
|
-
// The shorthands whose size is a literal (the small series) must ride the
|
|
1782
|
-
// shift too; the delta-derived shorthands flow through the chain above.
|
|
1783
2240
|
var sizeShifted = [];
|
|
1784
2241
|
var markdownEntries = shorthandTokens(baseTokens).filter(function (entry) {
|
|
1785
|
-
return
|
|
2242
|
+
return isMarkdownLiteralToken(entry.name) && isLiteralTokenValue(entry.parts.size);
|
|
1786
2243
|
});
|
|
1787
2244
|
for (var mIndex = 0; mIndex < markdownEntries.length; mIndex += 1) {
|
|
1788
2245
|
var mEntry = markdownEntries[mIndex];
|
|
@@ -1837,12 +2294,16 @@ function buildAxisCss(axis, baseTokens, isDark, hints) {
|
|
|
1837
2294
|
if (codeScaled.length > 0) declarations.push(rootRule(codeScaled.join(";")));
|
|
1838
2295
|
}
|
|
1839
2296
|
if (codeWeight !== WEIGHT_UNSET) {
|
|
1840
|
-
// The
|
|
1841
|
-
//
|
|
1842
|
-
// instead of
|
|
2297
|
+
// The code axis is a relative offset too (all three weight axes share one
|
|
2298
|
+
// scale, so the card shows one kind of control). Pinning the offset here
|
|
2299
|
+
// instead of writing a flat `font-weight` keeps whatever weight a code
|
|
2300
|
+
// surface ships with AND is what makes the elements INSIDE a code surface —
|
|
2301
|
+
// which the interface table and the conversation ladder both match — resolve
|
|
2302
|
+
// the code offset rather than the surrounding one, without any `… *`
|
|
2303
|
+
// selector. `WEIGHT_BASE` is what DSH's code `font` shorthands carry.
|
|
1843
2304
|
declarations.push(
|
|
1844
2305
|
codeRule(
|
|
1845
|
-
"font-weight:" +
|
|
2306
|
+
"font-weight:" + ladderWeight(WEIGHT_BASE) + " !important;--dfp-wdelta:" + codeWeight
|
|
1846
2307
|
)
|
|
1847
2308
|
);
|
|
1848
2309
|
}
|
|
@@ -2397,7 +2858,27 @@ var shared = {
|
|
|
2397
2858
|
isFontToken: isFontToken,
|
|
2398
2859
|
isCodeToken: isCodeToken,
|
|
2399
2860
|
isMarkdownToken: isMarkdownToken,
|
|
2861
|
+
isMarkdownLiteralToken: isMarkdownLiteralToken,
|
|
2862
|
+
MARKDOWN_LITERAL_PREFIX: MARKDOWN_LITERAL_PREFIX,
|
|
2863
|
+
CONTENT_SIZE_SOURCE: CONTENT_SIZE_SOURCE,
|
|
2864
|
+
isLiteralTokenValue: isLiteralTokenValue,
|
|
2865
|
+
clampWeightDelta: clampWeightDelta,
|
|
2866
|
+
WEIGHT_DELTA_MIN: WEIGHT_DELTA_MIN,
|
|
2867
|
+
WEIGHT_DELTA_MAX: WEIGHT_DELTA_MAX,
|
|
2868
|
+
WEIGHT_BASE: WEIGHT_BASE,
|
|
2869
|
+
DIALOG_WEIGHT_GROUPS: DIALOG_WEIGHT_GROUPS,
|
|
2400
2870
|
isDeltaToken: isDeltaToken,
|
|
2871
|
+
reconcileSliderValue: reconcileSliderValue,
|
|
2872
|
+
WEIGHT_STEP_CANDIDATES: WEIGHT_STEP_CANDIDATES,
|
|
2873
|
+
WEIGHT_DELTA_FLOOR: WEIGHT_DELTA_FLOOR,
|
|
2874
|
+
WEIGHT_DELTA_CEIL: WEIGHT_DELTA_CEIL,
|
|
2875
|
+
WEIGHT_LADDER_TOP: WEIGHT_LADDER_TOP,
|
|
2876
|
+
WEIGHT_LADDER_STRONG: WEIGHT_LADDER_STRONG,
|
|
2877
|
+
WEIGHT_DELTA_UP_LIMIT: WEIGHT_DELTA_UP_LIMIT,
|
|
2878
|
+
WEIGHT_CSS_MIN: WEIGHT_CSS_MIN,
|
|
2879
|
+
WEIGHT_CSS_MAX: WEIGHT_CSS_MAX,
|
|
2880
|
+
weightProfileFrom: weightProfileFrom,
|
|
2881
|
+
weightStepRange: weightStepRange,
|
|
2401
2882
|
isShorthandName: isShorthandName,
|
|
2402
2883
|
isScaledToken: isScaledToken,
|
|
2403
2884
|
tokenNames: tokenNames,
|