@quillmark/svelte 0.5.1 → 0.7.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/README.md +6 -0
- package/THEMING.md +13 -17
- package/dist/core/address.d.ts +17 -3
- package/dist/core/address.js +20 -3
- package/dist/core/codec/blocks.d.ts +37 -0
- package/dist/core/codec/blocks.js +163 -0
- package/dist/core/codec/field.js +5 -6
- package/dist/core/codec/index.d.ts +1 -1
- package/dist/core/codec/index.js +3 -2
- package/dist/core/codec/inputrules.js +24 -144
- package/dist/core/codec/prose.css +14 -25
- package/dist/core/codec/schema.d.ts +8 -0
- package/dist/core/codec/schema.js +33 -1
- package/dist/core/codec/slash.d.ts +18 -16
- package/dist/core/codec/slash.js +0 -0
- package/dist/core/codec/table-view.d.ts +4 -0
- package/dist/core/codec/table-view.js +137 -158
- package/dist/core/codec/table.d.ts +0 -10
- package/dist/core/codec/table.js +0 -15
- package/dist/core/theme.css +357 -346
- package/dist/preset/recipes.css +25 -21
- package/dist/preview/Preview.svelte +4 -2
- package/dist/preview/bridge.d.ts +23 -0
- package/dist/preview/bridge.js +92 -35
- package/dist/preview/controller.d.ts +6 -5
- package/dist/preview/controller.js +13 -7
- package/dist/preview/geometry.d.ts +10 -9
- package/dist/preview/geometry.js +11 -13
- package/dist/preview/index.js +3 -2
- package/dist/preview/paint.js +9 -1
- package/dist/visual/ArrayField.svelte +246 -63
- package/dist/visual/ArrayField.svelte.d.ts +5 -1
- package/dist/visual/Card.svelte +84 -50
- package/dist/visual/EnumField.svelte +37 -3
- package/dist/visual/Field.svelte +28 -4
- package/dist/visual/FieldLabel.svelte +2 -2
- package/dist/visual/FormatPopover.svelte +13 -1
- package/dist/visual/ObjectField.svelte +128 -35
- package/dist/visual/ObjectField.svelte.d.ts +11 -4
- package/dist/visual/ProseArrayElement.svelte +22 -2
- package/dist/visual/ProseArrayElement.svelte.d.ts +1 -0
- package/dist/visual/SlashMenu.svelte +7 -0
- package/dist/visual/TipsCard.svelte +33 -13
- package/dist/visual/VariantField.svelte +95 -0
- package/dist/visual/VariantField.svelte.d.ts +21 -0
- package/dist/visual/VisualEditorInner.svelte +44 -21
- package/dist/visual/controls.css +282 -283
- package/dist/visual/diagnostics.d.ts +13 -11
- package/dist/visual/diagnostics.js +11 -9
- package/dist/visual/domid.d.ts +13 -0
- package/dist/visual/domid.js +16 -0
- package/dist/visual/hold.d.ts +17 -0
- package/dist/visual/hold.js +39 -0
- package/dist/visual/index.js +1 -1
- package/dist/visual/leaves.d.ts +9 -7
- package/dist/visual/links.d.ts +5 -2
- package/dist/visual/links.js +9 -3
- package/dist/visual/motion.d.ts +9 -0
- package/dist/visual/motion.js +10 -2
- package/dist/visual/strings.d.ts +15 -0
- package/dist/visual/strings.js +3 -0
- package/dist/visual/structure.d.ts +32 -6
- package/dist/visual/structure.js +49 -3
- package/package.json +2 -2
- package/dist/core/codec/clipboard.d.ts +0 -59
- package/dist/core/codec/clipboard.js +0 -202
package/dist/core/theme.css
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
every element marked `data-qm-root`. The package imports it itself, so there is
|
|
9
9
|
no `import './theme.css'` for a consumer to forget. A stylesheet rather than an
|
|
10
10
|
inline `style` attribute is what buys the three things an attribute cannot
|
|
11
|
-
carry: a
|
|
11
|
+
carry: a selector consumer CSS outranks without `!important`, real properties
|
|
12
12
|
on the root rule (`font-family`) that every root then inherits, and a free
|
|
13
13
|
`style` attribute for the consumer.
|
|
14
14
|
|
|
@@ -16,8 +16,8 @@
|
|
|
16
16
|
the package claims `sideEffects: true`. Pruned, every rung below is undefined,
|
|
17
17
|
every `var()` reading one is invalid at computed-value time, and the declaration
|
|
18
18
|
holding it drops: a control with no border, no background and no padding, under
|
|
19
|
-
chrome that still reads as intact. `check:bundle`
|
|
20
|
-
the
|
|
19
|
+
chrome that still reads as intact. `check:bundle` reads the built bytes for it;
|
|
20
|
+
the claim in the manifest is review's.
|
|
21
21
|
|
|
22
22
|
Every value stays a `var()` reference, so the dials resolve against the cascade
|
|
23
23
|
at each root: a consumer's `[data-theme="dark"]` ancestor rule flows in
|
|
@@ -26,10 +26,12 @@
|
|
|
26
26
|
declared on the root, so they are reachable only by a rule targeting it:
|
|
27
27
|
THEMING.md §"What is deliberately not public" states the terms.
|
|
28
28
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
29
|
+
Rank: no cascade layer, and every selector here and in the shared recipes is
|
|
30
|
+
`:where()`-wrapped, so each computes at specificity zero. Any rule of a consumer's
|
|
31
|
+
outranks them at any specificity, and no layer of a consumer's outranks them at all —
|
|
32
|
+
unlayered beats layered whatever order the sheets arrive in, which is what makes the
|
|
33
|
+
rank independent of the bundler (THEMING §"Your CSS beats ours"). `check:style` holds
|
|
34
|
+
both halves over the sheets it names.
|
|
33
35
|
|
|
34
36
|
`@property` registers the three entry rungs, the ones reading a dial, and
|
|
35
37
|
nothing below them. An `initial-value` must be computationally independent,
|
|
@@ -64,366 +66,375 @@
|
|
|
64
66
|
initial-value: 14px;
|
|
65
67
|
}
|
|
66
68
|
|
|
67
|
-
|
|
69
|
+
:where([data-qm-root]) {
|
|
70
|
+
/* ── Poles ───────────────────────────────────────────────────────────────
|
|
71
|
+
Each dial's default, stated once. Every rung below reads a pole, never a
|
|
72
|
+
dial, so both schemes cost two declarations rather than fifteen; and the
|
|
73
|
+
dial sits in front of the default, so a consumer's ancestor value wins in
|
|
74
|
+
either scheme, which it would not if a scheme rule set `--qm-bg` instead.
|
|
68
75
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
either scheme, which it would not if a scheme rule set `--qm-bg` instead.
|
|
76
|
-
|
|
77
|
-
`light-dark()` keys the default off the `color-scheme` this root inherits,
|
|
78
|
-
which is the host's: an app that declares `dark` gets a dark surface
|
|
79
|
-
whatever the OS says, and one that declares nothing gets light, matching
|
|
80
|
-
its own unstyled text. So the package owns no mode logic at all: light or
|
|
81
|
-
dark is the mounting site's, like every other value here (THEMING.md
|
|
82
|
-
§"The surface follows your colour scheme").
|
|
76
|
+
`light-dark()` keys the default off the `color-scheme` this root inherits,
|
|
77
|
+
which is the host's: an app that declares `dark` gets a dark surface
|
|
78
|
+
whatever the OS says, and one that declares nothing gets light, matching
|
|
79
|
+
its own unstyled text. So the package owns no mode logic at all: light or
|
|
80
|
+
dark is the mounting site's, like every other value here (THEMING.md
|
|
81
|
+
§"The surface follows your colour scheme").
|
|
83
82
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
83
|
+
`--qm-bg` is the card, not the column behind it: the plane content is
|
|
84
|
+
written on, which is also the preview's paper. Everything else is a step
|
|
85
|
+
off it, and the column is a step down. */
|
|
86
|
+
--_qm-bg: var(--qm-bg, light-dark(#fff, #272729));
|
|
87
|
+
--_qm-fg: var(--qm-fg, light-dark(#1c1c1c, #d7dadc));
|
|
88
|
+
/* Neutral: the surface spends no hue on a state it can draw in grey. The pair
|
|
89
|
+
clears WCAG 2.4.11's 3:1 against the card at both poles, at 4.8:1 and 5.8:1. */
|
|
90
|
+
--_qm-accent: var(--qm-accent, light-dark(#71717a, #a1a1aa));
|
|
91
|
+
/* The one hue the surface spends, and it spends it on a state. Each pole is
|
|
92
|
+
its own figure rather than one ink shown twice: a hue calibrated against
|
|
93
|
+
white reads as a stain on a dark card. Both clear WCAG 1.4.3's 4.5:1 against
|
|
94
|
+
the card, which is the bar the label rung asks for and the one the glyphs
|
|
95
|
+
drawn in this hue clear on the way past 1.4.11's 3:1. Dark enough at its own
|
|
96
|
+
pole to carry a label at 4.5:1, so a filled chip needs no third figure. The
|
|
97
|
+
figures are the host scale's (`preset/scale.css`), so a page's status line
|
|
98
|
+
and a card's diagnostic carry one colour meaning error. */
|
|
99
|
+
--_qm-danger: var(--qm-danger, light-dark(#9e1518, #f9786c));
|
|
100
|
+
--_qm-font: var(--qm-font, ui-sans-serif, system-ui, sans-serif);
|
|
101
|
+
--_qm-font-mono: var(--qm-font-mono, ui-monospace, monospace);
|
|
103
102
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
103
|
+
/* ── Colour ──────────────────────────────────────────────────────────────
|
|
104
|
+
Ink steps fg → bg, the border and hover rungs step bg → fg, all mixed in
|
|
105
|
+
oklab; sRGB muddies the mid-tones and the label/meta/border rungs are
|
|
106
|
+
exactly mid-tone. So inverting the poles inverts that half of the scale.
|
|
107
|
+
The percentages are calibrated to the light-mode literals they stand in
|
|
108
|
+
for (17% ≈ #d4d4d4, 35% ≈ #555).
|
|
110
109
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
110
|
+
Planes are the half that does not read the ink pole, because what makes a
|
|
111
|
+
card read as a card is that it is the brighter plane, in both schemes
|
|
112
|
+
alike (ARCHITECTURE §Styling). A plane stepped toward the ink is right in
|
|
113
|
+
dark and inverted in light, where it darkens the card below the page it
|
|
114
|
+
floats on. So `sunken` and `well` step toward shadow and `raised` toward
|
|
115
|
+
light, and the base plane — a card, the preview's paper — is the pole
|
|
116
|
+
itself.
|
|
118
117
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
118
|
+
Two planes sink. `sunken` is the ground — the column behind the cards, the
|
|
119
|
+
desk behind the sheets — and lifting the plane above it takes very little
|
|
120
|
+
at the light pole. `well` is the hole cut into a card: a field, a table's
|
|
121
|
+
header band, the one native select, none of which draw an edge, so the
|
|
122
|
+
step is the whole of what says a value is typed there. The order at the
|
|
123
|
+
light pole is card, ground, well; at the dark pole the two sink to within
|
|
124
|
+
a channel of each other, which is where a card with little light left to
|
|
125
|
+
give up leaves them.
|
|
127
126
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
127
|
+
How far each sinks is a function of the card's own L, not of the scheme the
|
|
128
|
+
host declared: a dark surface has to spend more of what little it has
|
|
129
|
+
before the card above it reads as lifted, so the two calibrated distances
|
|
130
|
+
— 0.0214 off white, 0.0553 off the dark default — interpolate linearly
|
|
131
|
+
between. A card pinned at neither pole takes a proportionate step whatever
|
|
132
|
+
`color-scheme` says, which is the half of the derivation that reads a
|
|
133
|
+
colour rather than a declaration.
|
|
135
134
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
135
|
+
Both sink by subtraction where every other rung mixes: a mix toward black
|
|
136
|
+
is a ratio, so it scales what it takes and pulls the result toward
|
|
137
|
+
neutral, and a ground is a fixed distance. `a b` pass through, so the
|
|
138
|
+
plane keeps the pole's hue and a turned `--qm-bg` tints it. The defaults
|
|
139
|
+
land within a channel of `#f7f8f9` and `#1a1a1b`. Below L ≈ 0.065 the
|
|
140
|
+
ground clamps to black, which is where a near-black card leaves no room
|
|
141
|
+
for a ground of its own. */
|
|
142
|
+
--_qm-surface: var(--_qm-bg);
|
|
143
|
+
--_qm-surface-sunken: oklab(from var(--_qm-bg) calc(l - (0.0214 + 0.0467 * (1 - l))) a b);
|
|
144
|
+
--_qm-surface-well: oklab(from var(--_qm-bg) calc(l - (0.04 + 0.0202 * (1 - l))) a b);
|
|
145
|
+
/* `raised` is the same ramp spelled as a mix, its step 0.08 × (1 − l): the light
|
|
146
|
+
arm is zero, a white card having nowhere further to go, so a floating surface
|
|
147
|
+
separates on its hairline and `--_qm-lift` there and the step joins them in
|
|
148
|
+
dark. */
|
|
149
|
+
--_qm-surface-raised: color-mix(in oklab, var(--_qm-bg), #fff 8%);
|
|
150
|
+
--_qm-surface-hover: color-mix(in oklab, var(--_qm-bg), var(--_qm-fg) 8%);
|
|
151
|
+
/* The one rung whose arms are not a single ratio: a stroke is read against what it
|
|
152
|
+
separates, and the mix that reads as a hairline on the dark default draws the
|
|
153
|
+
light card in a line heavier than the type it frames. The light arm is
|
|
154
|
+
calibrated rather than derived, which makes this the one rung under the poles
|
|
155
|
+
that reads the declared scheme rather than only the colours it resolves to. */
|
|
156
|
+
--_qm-border: light-dark(
|
|
157
|
+
color-mix(in oklab, var(--_qm-bg), var(--_qm-fg) 6%),
|
|
158
|
+
color-mix(in oklab, var(--_qm-bg), var(--_qm-fg) 17%)
|
|
159
|
+
);
|
|
160
|
+
/* A rule that separates without structuring: the lines between a table's cells,
|
|
161
|
+
where the frame around them is the structure. Half the border, and read off
|
|
162
|
+
it rather than restated as a percentage of its own, so the two hold their
|
|
163
|
+
relationship at any mix: a stroke against the surface behind it, not a fill
|
|
164
|
+
stacked on one. */
|
|
165
|
+
--_qm-border-faint: color-mix(in oklab, var(--_qm-bg), var(--_qm-border) 50%);
|
|
166
|
+
/* Two rungs, and there is no third: a step below `label` lands under 3:1 on the
|
|
167
|
+
well a field draws it against, and what would take it — a placeholder, an
|
|
168
|
+
unset value, the resolved `default:` — is content a reader has to read
|
|
169
|
+
(WCAG 1.4.3), not decoration. So tone carries hierarchy alone, and a leaf
|
|
170
|
+
saying shown-never-written says it against the `ink` a written value takes,
|
|
171
|
+
in italic where it has no written neighbour to be read against. */
|
|
172
|
+
--_qm-ink: var(--_qm-fg);
|
|
173
|
+
--_qm-ink-label: color-mix(in oklab, var(--_qm-fg), var(--_qm-bg) 35%);
|
|
174
|
+
/* The arrival wash (`core/bloom.ts`). Its alpha is a peak, not a tint: the
|
|
175
|
+
wash animates from and back to zero, never held, so it reads over the leaf it
|
|
176
|
+
lands on while the leaf rests clean. */
|
|
177
|
+
--_qm-accent-wash: color-mix(in oklab, var(--_qm-accent) 18%, transparent);
|
|
178
|
+
/* The accent held: what a selected line of a table is tinted with, and what its
|
|
179
|
+
grip is filled with, so the two ends of one gesture are one colour. A second
|
|
180
|
+
name rather than the wash reused, because the two answer different questions
|
|
181
|
+
and the numbers follow: a peak passes over paper and can be strong, where a
|
|
182
|
+
tint is held under body text and cannot. Translucent, so it
|
|
183
|
+
stacks over whichever surface rung the cell already draws instead of replacing
|
|
184
|
+
it. */
|
|
185
|
+
--_qm-accent-tint: color-mix(in oklab, var(--_qm-accent) 12%, transparent);
|
|
186
|
+
/* The danger hue held: what a destructive control fills with where the family's
|
|
187
|
+
neutral hover rung would read as one more button. Mixed at the accent tint's
|
|
188
|
+
strength, so a held tint is a held tint whichever hue it carries. */
|
|
189
|
+
--_qm-danger-tint: color-mix(in oklab, var(--_qm-danger) 12%, transparent);
|
|
190
|
+
/* The label ink held: what a trigger fills with whose own ink never steps, so
|
|
191
|
+
the fill arriving under it is that tone at a strength a surface reads
|
|
192
|
+
through. */
|
|
193
|
+
--_qm-add-fill: color-mix(in oklab, var(--_qm-ink-label) 15%, transparent);
|
|
187
194
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
195
|
+
/* The tips card'S hue: the surface's one exit from the greyscale that is not
|
|
196
|
+
a status, and what the amber and the typewriter face say together is
|
|
197
|
+
draft (VISUAL_EDITOR §"Card operations"). A literal rather than a dial
|
|
198
|
+
because there is nothing left to turn: the rungs under it mix over
|
|
199
|
+
the surface and the ink a consumer already tuned, so the card follows a
|
|
200
|
+
brand untold. The mixes are faint on purpose: a warmth, not a badge.
|
|
194
201
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
202
|
+
The one group mixed in sRGB. oklab holds perceived lightness across a mix and
|
|
203
|
+
spends chroma to do it, which is right where both endpoints are grey and wrong
|
|
204
|
+
for a hue: at either pole it lands the ink a channel short of warm. */
|
|
205
|
+
--_qm-tips: #e88c0a;
|
|
206
|
+
--_qm-tips-surface: color-mix(in srgb, var(--_qm-surface), var(--_qm-tips) 3%);
|
|
207
|
+
--_qm-tips-ink: color-mix(in srgb, var(--_qm-ink), var(--_qm-tips) 24%);
|
|
208
|
+
/* The ink and the amber stepped up, and the pair is spent on the two runs that
|
|
209
|
+
are not the sentence: a token in a tip, and the foot's control under the
|
|
210
|
+
pointer. One rung each rather than one per run, a chip and a hover four
|
|
211
|
+
percent apart being a number with no second decision under it. */
|
|
212
|
+
--_qm-tips-ink-warm: color-mix(in srgb, var(--_qm-ink), var(--_qm-tips) 45%);
|
|
213
|
+
--_qm-tips-fill: color-mix(in srgb, var(--_qm-tips) 12%, transparent);
|
|
214
|
+
/* The typewriter, the half of the slip the amber cannot carry: a modern mono
|
|
215
|
+
reads as code where a Courier reads as typed. Its own rung rather than
|
|
216
|
+
`--_qm-font-mono`, the chrome's readout face, which a consumer turns for
|
|
217
|
+
tabular figures and not to dress this card. Courier Prime leads and is nobody's
|
|
218
|
+
system font, so a host that loads it lands on it and every other host falls to
|
|
219
|
+
the Courier the platform already carries; the package fetches nothing, a preset
|
|
220
|
+
costing a network request being one a consumer cannot decline. */
|
|
221
|
+
--_qm-tips-font: 'Courier Prime', 'Courier New', Courier, ui-monospace, monospace;
|
|
215
222
|
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
--_qm-opacity-muted: 0.5;
|
|
223
|
+
/* ── Ratios and effects ──────────────────────────────────────────────────
|
|
224
|
+
No palette fixes these, so they are their own rungs. */
|
|
225
|
+
--_qm-blur: 8px;
|
|
226
|
+
/* The popover's translucency: the raised surface mixed toward transparent, so
|
|
227
|
+
the page reads faintly through the pill. */
|
|
228
|
+
--_qm-surface-popover: color-mix(in oklab, var(--_qm-surface-raised) 82%, transparent);
|
|
229
|
+
/* What a surface with no plane under it lifts on. A tone rung cannot carry that at
|
|
230
|
+
both poles: `raised` is a no-op against a white card (§Colour), so in light the
|
|
231
|
+
hairline is otherwise the whole separation over the body prose these float on.
|
|
232
|
+
Offset-free is the whole of it: an offset states where the light is and no pole
|
|
233
|
+
carries that, where a halo states occlusion. Toward black at both poles for the
|
|
234
|
+
same reason — a crevice is darker than what surrounds it in a dark room too — so
|
|
235
|
+
the cue means one thing whichever way the scale runs. Spent only on what portals,
|
|
236
|
+
and the one shadow any surface casts, which is review's to hold. */
|
|
237
|
+
--_qm-lift: 0 0 12px color-mix(in oklab, #000 16%, transparent);
|
|
238
|
+
/* The recede ladder: a hover-revealed or disabled affordance at rest, and a
|
|
239
|
+
muted one. Opacity recedes toward whatever is behind, so these invert
|
|
240
|
+
correctly given the element's own colour is a rung. */
|
|
241
|
+
--_qm-opacity-idle: 0.35;
|
|
242
|
+
--_qm-opacity-muted: 0.5;
|
|
237
243
|
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
244
|
+
/* ── Focus ───────────────────────────────────────────────────────────────
|
|
245
|
+
These fix the ring's value, so no control mints it. Which properties draw a
|
|
246
|
+
ring, and on what state, is the other half: a rule, `.qm-focus-ring` in
|
|
247
|
+
`visual/controls.css`, since a rung each control reassembles is a scale
|
|
248
|
+
only up to the point where it is assembled. One width: focus is the only
|
|
249
|
+
state that draws a ring anywhere, so there is no held-back tier under it.
|
|
250
|
+
Sub-pixel, because at two it reads as a second border on a card whose every
|
|
251
|
+
other edge is a hairline. */
|
|
252
|
+
--_qm-ring-width: 1.5px;
|
|
253
|
+
/* Every ring the surface draws, focus and selection alike, which is why the name
|
|
254
|
+
carries neither. Assembled here because the parts spelled out at a use site pass
|
|
255
|
+
every axis — each reads a rung — while drawing a ring nothing else agrees with. */
|
|
256
|
+
--_qm-ring: var(--_qm-ring-width) solid var(--_qm-accent);
|
|
257
|
+
--_qm-ring-offset: 1px;
|
|
258
|
+
/* What a clip box carries past its content for a focused control inside it to
|
|
259
|
+
keep the whole mark. */
|
|
260
|
+
--_qm-ring-reach: calc(var(--_qm-ring-width) + var(--_qm-ring-offset));
|
|
255
261
|
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
262
|
+
/* ── Motion ──────────────────────────────────────────────────────────────
|
|
263
|
+
Two rungs, by what the trip disturbs: `fast` stays inside the element's own
|
|
264
|
+
box, `slow` moves the layout around it. */
|
|
265
|
+
--_qm-duration-fast: 120ms;
|
|
266
|
+
--_qm-duration-slow: 200ms;
|
|
267
|
+
/* The bloom's whole rise-hold-decay, and deliberately not a third rung. A
|
|
268
|
+
custom property rather than a constant in `core/bloom.ts` because that module
|
|
269
|
+
animates over WAAPI and reads it from here. */
|
|
270
|
+
--_qm-bloom-dwell: 1100ms;
|
|
265
271
|
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
272
|
+
/* One curve, symmetric because an interruption turns these trips around: a hover
|
|
273
|
+
leaves before it arrives, a card collapses mid-expand. Every trip at `fast` or
|
|
274
|
+
`slow` takes it; a one-way shape is legible only over a longer one. */
|
|
275
|
+
--_qm-ease-reverse: cubic-bezier(0.4, 0, 0.6, 1);
|
|
276
|
+
/* A trip rather than a rung, duration and curve composed the way `--_qm-ring`
|
|
277
|
+
composes its three: neither half is reachable alone. Weighted to its end, so an
|
|
278
|
+
arrival settles into its rest instead of stopping at it, and long enough that a
|
|
279
|
+
control resting at nothing reads as arriving rather than as switching. */
|
|
280
|
+
--_qm-reveal: 500ms cubic-bezier(0.4, 0, 0.2, 1);
|
|
275
281
|
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
282
|
+
/* ── Geometry ──────────────────────────────────────────────────────────*/
|
|
283
|
+
/* One stroke width for every edge the chrome draws: a card's, a control's,
|
|
284
|
+
and the verticals nested inside it alike. A threshold rather than a
|
|
285
|
+
rhythm choice, like the tap floor: a hairline is a hairline at any
|
|
286
|
+
`--qm-space`, so it does not derive from a dial. It exists as a rung because
|
|
287
|
+
the nesting ladder's whole claim is that a card's edge, a section's vertical
|
|
288
|
+
and a subform's are one stroke at three depths, and `check:style`'s
|
|
289
|
+
border-width axis can only hold that against a token. */
|
|
290
|
+
--_qm-border-width: 1px;
|
|
291
|
+
--_qm-radius: var(--qm-radius, 8px);
|
|
292
|
+
/* The interior corner, and half is the relationship rather than the number: a
|
|
293
|
+
corner inside a corner reads as nested only while it is visibly tighter, and
|
|
294
|
+
halving holds that at every setting of the dial, zero included. */
|
|
295
|
+
--_qm-radius-inner: calc(var(--_qm-radius) / 2);
|
|
296
|
+
/* A fully-rounded end cap: a shape tier, not a step on the radius ramp, so
|
|
297
|
+
it does not derive from the dial: a pill stays a pill at any radius. */
|
|
298
|
+
--_qm-radius-pill: 999px;
|
|
299
|
+
--_qm-space: var(--qm-space, 0.25rem);
|
|
300
|
+
--_qm-space-half: calc(var(--_qm-space) / 2);
|
|
301
|
+
--_qm-space-2: calc(var(--_qm-space) * 2);
|
|
302
|
+
--_qm-space-3: calc(var(--_qm-space) * 3);
|
|
303
|
+
--_qm-space-4: calc(var(--_qm-space) * 4);
|
|
304
|
+
--_qm-space-5: calc(var(--_qm-space) * 5);
|
|
305
|
+
/* A rung because the two axes are two decisions and the ladder alone cannot hold
|
|
306
|
+
them together: `check:style`'s rhythm axis sees each box read a rung, never that
|
|
307
|
+
they read the same one, which is the drift `visual/controls.css` already names
|
|
308
|
+
for the type half. Asymmetric because the vertical is what leading leaves once
|
|
309
|
+
it has taken the line box, and the horizontal is how far in the text starts,
|
|
310
|
+
which nothing else fixes. */
|
|
311
|
+
--_qm-inset-control: var(--_qm-space) var(--_qm-space-3);
|
|
312
|
+
/* The nesting step: the distance from one structural stroke to the next, and what
|
|
313
|
+
makes the depths read as a ladder rather than as indents that happen to look
|
|
314
|
+
alike. A rung because the boxes holding that distance are in two components and
|
|
315
|
+
`check:style`'s rhythm axis sees each of them read a rung, never that they read
|
|
316
|
+
the same one — the case `--_qm-inset-control` above is cut for. */
|
|
317
|
+
--_qm-nest: var(--_qm-space-3);
|
|
318
|
+
/* The scroll tail: dead space under the last card, so it can be read at the
|
|
319
|
+
middle of a pane rather than at its bottom edge. A fraction of the viewport
|
|
320
|
+
rather than a step on the ramp, because what it answers is how far the eye
|
|
321
|
+
sits from the bottom of the screen, which no spacing dial knows. Spent by
|
|
322
|
+
the editor alone (`.qm-pane`): a stack of cards is what has a last one to
|
|
323
|
+
reach, where a page and a text mirror end where the document ends. */
|
|
324
|
+
--_qm-tail: 40vh;
|
|
325
|
+
/* WCAG 2.5.8's 24x24 pointer-target floor. A rung rather than a sixth step on
|
|
326
|
+
the space scale: it is a threshold the spec fixes, not a rhythm choice, so
|
|
327
|
+
it does not move when `--qm-space` does. Both button families read it, so the
|
|
328
|
+
floor is one number instead of one expression per control. */
|
|
329
|
+
--_qm-tap-min: 24px;
|
|
330
|
+
/* The reorder/delete glyph. A rung because the card header's
|
|
331
|
+
right hang is half the difference between this and the tap floor: the glyph
|
|
332
|
+
centres in a target sized by the floor, so what stands between it and the
|
|
333
|
+
card's gutter is an arithmetic of the two, and a literal on either side is a
|
|
334
|
+
balance that silently breaks when the glyph moves. Sized in CSS rather than
|
|
335
|
+
through the icon's `size`, so the hang and the glyph read one number. Scoped to
|
|
336
|
+
the control pair: the hint and the format marks take their own sizes, and a
|
|
337
|
+
rung claiming to be every glyph would be false at three of them. */
|
|
338
|
+
--_qm-glyph-control: 14px;
|
|
327
339
|
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
340
|
+
/* ── Type ────────────────────────────────────────────────────────────────
|
|
341
|
+
`--qm-font-size` anchors the chrome rung; 1.125 is the ratio between adjacent
|
|
342
|
+
rungs: a step up (title) and one down (label). The ratio and the
|
|
343
|
+
weight are fixed conventions, not dials: no consumer tunes a typographic
|
|
344
|
+
ratio, and a dial nobody turns is a name every reader still holds. Three chrome
|
|
345
|
+
rungs: a second step below `label` lands near 11px, under a size anything here
|
|
346
|
+
wants to be read at, and the supporting text that would take it is what `label`
|
|
347
|
+
already is. */
|
|
348
|
+
--_qm-text-body: var(--qm-font-size, 0.875rem);
|
|
349
|
+
--_qm-text-title: calc(var(--_qm-text-body) * 1.125);
|
|
350
|
+
--_qm-text-label: calc(var(--_qm-text-body) / 1.125);
|
|
351
|
+
/* Paper: the document body answers to the preview's paper where every other
|
|
352
|
+
surface here answers to the control beside it, so a rung shared with the chrome
|
|
353
|
+
makes a consumer asking for larger prose take larger inputs with it. 16/15 where
|
|
354
|
+
the ramp steps at 9/8: small enough to read as a change of register rather than
|
|
355
|
+
a rung of hierarchy, and clear of the title rung, which one 9/8 step lands on
|
|
356
|
+
exactly. */
|
|
357
|
+
--_qm-text-paper: calc(var(--_qm-text-body) * 16 / 15);
|
|
358
|
+
/* Two weights over the regular, and only one of them is chrome. `mid` names
|
|
359
|
+
everything the surface names — a card title, a section header, a field
|
|
360
|
+
label, a nested property — so a stack of them reads as one register and
|
|
361
|
+
hierarchy stays the size ramp's, which is the axis that can carry it.
|
|
362
|
+
500 rather than 600 because the family dial resolves to the platform UI
|
|
363
|
+
face, whose 600 is heavier at the same number than the webfont a surface
|
|
364
|
+
is usually drawn against: at the label rung it goes smudgy, and one
|
|
365
|
+
number across three sizes does not read as one weight.
|
|
354
366
|
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
367
|
+
`strong` is not a rung of that ramp. It is the mark a run wears where
|
|
368
|
+
weight is the only signal it has: a heading inside a prose leaf, drawn at
|
|
369
|
+
no size step of its own because the quill sets the paper's; a table
|
|
370
|
+
island's header row; the stored value in an enum listbox. Reaching for it
|
|
371
|
+
where a size or a tone could speak is the drift the split exists to
|
|
372
|
+
stop. */
|
|
373
|
+
--_qm-weight-strong: 600;
|
|
374
|
+
--_qm-weight-mid: 500;
|
|
375
|
+
/* Leading: the ramp's third axis, and it does not track the sizes one for one:
|
|
376
|
+
two rungs, because a wrapped label and a wrapped paragraph want different
|
|
377
|
+
rhythms and nothing wants four. `body` is reading rhythm (both prose leaves,
|
|
378
|
+
every control beside them, the tips card's guidance); `tight` is a line that is
|
|
379
|
+
a label rather than a passage. Unitless, so a rung inherits multiplicatively
|
|
380
|
+
and holds against whichever size rung the surface reads: a `rem` leading
|
|
381
|
+
would freeze at one size and disagree with the rest of the ramp. It is the
|
|
382
|
+
axis paper and chrome share: both read `body`, and the size rung is what
|
|
383
|
+
separates them. `line-height: 1` is outside the axis: it collapses the
|
|
384
|
+
line box onto its content, a glyph or a button's one-line label. */
|
|
385
|
+
--_qm-leading-body: 1.5;
|
|
386
|
+
--_qm-leading-tight: 1.3;
|
|
375
387
|
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
388
|
+
/* ── The baseline every root inherits ────────────────────────────────────
|
|
389
|
+
Real properties, not only custom ones: the thing an inline attribute
|
|
390
|
+
could carry but never did, which is why `--qm-font` reached one root of
|
|
391
|
+
five. `color-scheme` is deliberately absent: it inherits, so the host's
|
|
392
|
+
reaches this root untouched and native chrome (scrollbars, the date
|
|
393
|
+
picker, the caret) lands on the same pole the poles above resolve to.
|
|
394
|
+
Declaring it here would break that lockstep in the one direction that
|
|
395
|
+
matters: a host that declares `dark` would get light native chrome under
|
|
396
|
+
a dark surface. A consumer that pins a palette against its own scheme
|
|
397
|
+
declares `color-scheme` with it, on the root (THEMING.md).
|
|
386
398
|
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
399
|
+
Face, ink and leading are the three axes a root carries this way. Leading
|
|
400
|
+
belongs with the other two because a unitless ratio inherits
|
|
401
|
+
multiplicatively: it holds against whatever size rung each surface reads, so
|
|
402
|
+
it imposes less than the ink beside it, and the reason `font-size` stays off
|
|
403
|
+
does not transfer: a ratio has no size to sweep a consumer's content with.
|
|
404
|
+
What it buys is that `normal` (the UA figure near 1.14, varying by font) is
|
|
405
|
+
unreachable under a marker, so a type-bearing surface lands on the ramp
|
|
406
|
+
whether or not it remembers to say so, and a per-surface
|
|
407
|
+
`--_qm-leading-tight` reads as the deliberate override it is.
|
|
396
408
|
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
409
|
+
Deliberately not `font-size`, and the reason is about the root rule rather
|
|
410
|
+
than about size: a root-level body size sweeps every descendant a consumer
|
|
411
|
+
may have put inside the marker, which is a reach the derivation does not
|
|
412
|
+
have. The rung is not withheld from the surfaces: every control and every
|
|
413
|
+
prose leaf reads `--_qm-text-body` in its own recipe, which is
|
|
414
|
+
what closes the ramp and makes `--qm-font-size` move an input. What would
|
|
415
|
+
break a mounted leaf is a size that changes under it; a rung is fixed at
|
|
416
|
+
mount unless the consumer turns the dial, and a consumer turning a dial is
|
|
417
|
+
entitled to the reflow. So: the root imposes no size, each surface reads the
|
|
418
|
+
rung it wants. */
|
|
419
|
+
font-family: var(--_qm-font);
|
|
420
|
+
color: var(--_qm-ink);
|
|
421
|
+
line-height: var(--_qm-leading-body);
|
|
422
|
+
}
|
|
411
423
|
|
|
412
|
-
|
|
413
|
-
|
|
424
|
+
/* Reduced motion collapses the scale, never a list of selectors.
|
|
425
|
+
Two values here are not the rung they look like:
|
|
414
426
|
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
427
|
+
`1ms` rather than `none`, because a collapsed transition still fires: a surface
|
|
428
|
+
waiting on `transitionend` keeps its event, where `transition: none` would strand
|
|
429
|
+
it. The beat is under perception either way.
|
|
418
430
|
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
}
|
|
431
|
+
`200ms` rather than `1ms` for the dwell, because the bloom's reduced form is a
|
|
432
|
+
hold and a cut (`core/bloom.ts` swaps the ramps out), and a hold is a duration:
|
|
433
|
+
collapsing it deletes the gesture instead of shortening it. */
|
|
434
|
+
@media (prefers-reduced-motion: reduce) {
|
|
435
|
+
:where([data-qm-root]) {
|
|
436
|
+
--_qm-duration-fast: 1ms;
|
|
437
|
+
--_qm-duration-slow: 1ms;
|
|
438
|
+
--_qm-bloom-dwell: 200ms;
|
|
428
439
|
}
|
|
429
440
|
}
|