@quillmark/svelte 0.1.1 → 0.3.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 +16 -12
- package/THEMING.md +48 -25
- package/dist/core/address.d.ts +42 -7
- package/dist/core/address.js +49 -21
- package/dist/core/bloom.d.ts +5 -5
- package/dist/core/bloom.js +8 -8
- package/dist/core/codec/anchor.d.ts +1 -1
- package/dist/core/codec/anchor.js +1 -1
- package/dist/core/codec/atoms.d.ts +10 -0
- package/dist/core/codec/atoms.js +78 -0
- package/dist/core/codec/clipboard.d.ts +59 -0
- package/dist/core/codec/clipboard.js +202 -0
- package/dist/core/codec/code.d.ts +1 -1
- package/dist/core/codec/code.js +4 -4
- package/dist/core/codec/decode.d.ts +1 -1
- package/dist/core/codec/decode.js +8 -8
- package/dist/core/codec/encode.d.ts +4 -4
- package/dist/core/codec/encode.js +14 -11
- package/dist/core/codec/field.d.ts +22 -27
- package/dist/core/codec/field.js +33 -32
- package/dist/core/codec/index.js +5 -8
- package/dist/core/codec/inputrules.js +56 -18
- package/dist/core/codec/islands.d.ts +11 -7
- package/dist/core/codec/islands.js +16 -10
- package/dist/core/codec/keymap.d.ts +5 -6
- package/dist/core/codec/keymap.js +8 -7
- package/dist/core/codec/lists.d.ts +3 -3
- package/dist/core/codec/lists.js +32 -13
- package/dist/core/codec/marks.d.ts +1 -1
- package/dist/core/codec/marks.js +1 -1
- package/dist/core/codec/positions.js +1 -1
- package/dist/core/codec/prose.css +266 -228
- package/dist/core/codec/schema.js +4 -4
- package/dist/core/codec/slash.d.ts +39 -41
- package/dist/core/codec/slash.js +0 -0
- package/dist/core/codec/table-view.d.ts +12 -16
- package/dist/core/codec/table-view.js +488 -292
- package/dist/core/codec/table.d.ts +42 -15
- package/dist/core/codec/table.js +73 -27
- package/dist/core/errors.d.ts +17 -7
- package/dist/core/index.d.ts +1 -1
- package/dist/core/index.js +6 -5
- package/dist/core/lifecycle.d.ts +21 -5
- package/dist/core/lifecycle.js +34 -8
- package/dist/core/rebind.svelte.d.ts +18 -4
- package/dist/core/rebind.svelte.js +30 -12
- package/dist/core/teardown.d.ts +1 -1
- package/dist/core/teardown.js +1 -1
- package/dist/core/theme.css +173 -58
- package/dist/preset/index.css +1 -1
- package/dist/preset/recipes.css +79 -30
- package/dist/preset/scale.css +40 -28
- package/dist/preview/Preview.svelte +22 -19
- package/dist/preview/Preview.svelte.d.ts +8 -8
- package/dist/preview/bridge.d.ts +6 -4
- package/dist/preview/bridge.js +19 -9
- package/dist/preview/controller.d.ts +13 -6
- package/dist/preview/controller.js +8 -5
- package/dist/preview/geometry.d.ts +17 -2
- package/dist/preview/geometry.js +21 -1
- package/dist/preview/index.d.ts +1 -0
- package/dist/preview/index.js +9 -2
- package/dist/preview/overlay.d.ts +2 -1
- package/dist/preview/overlay.js +26 -11
- package/dist/preview/paint.js +19 -17
- package/dist/visual/ArrayField.svelte +103 -83
- package/dist/visual/ArrayField.svelte.d.ts +5 -4
- package/dist/visual/BooleanField.svelte +8 -6
- package/dist/visual/BooleanField.svelte.d.ts +2 -2
- package/dist/visual/Card.svelte +161 -333
- package/dist/visual/Card.svelte.d.ts +5 -4
- package/dist/visual/CardControls.svelte +1 -1
- package/dist/visual/DateField.svelte +19 -19
- package/dist/visual/DateField.svelte.d.ts +3 -3
- package/dist/visual/DiagnosticList.svelte +2 -2
- package/dist/visual/EnumField.svelte +48 -28
- package/dist/visual/EnumField.svelte.d.ts +5 -4
- package/dist/visual/Field.svelte +207 -132
- package/dist/visual/Field.svelte.d.ts +11 -7
- package/dist/visual/FieldHint.svelte +79 -48
- package/dist/visual/FieldHint.svelte.d.ts +1 -1
- package/dist/visual/FieldLabel.svelte +8 -8
- package/dist/visual/FormatPopover.svelte +82 -35
- package/dist/visual/NumberField.svelte +5 -5
- package/dist/visual/NumberField.svelte.d.ts +1 -1
- package/dist/visual/ObjectField.svelte +28 -9
- package/dist/visual/ObjectField.svelte.d.ts +4 -2
- package/dist/visual/ProseArrayElement.svelte +12 -19
- package/dist/visual/ProseArrayElement.svelte.d.ts +1 -2
- package/dist/visual/ProseField.svelte +62 -85
- package/dist/visual/ProseField.svelte.d.ts +14 -17
- package/dist/visual/SlashMenu.svelte +42 -16
- package/dist/visual/TextField.svelte +5 -5
- package/dist/visual/TextField.svelte.d.ts +1 -1
- package/dist/visual/TipsCard.svelte +43 -28
- package/dist/visual/VisualEditor.svelte +18 -19
- package/dist/visual/VisualEditor.svelte.d.ts +2 -3
- package/dist/visual/VisualEditorInner.svelte +251 -184
- package/dist/visual/VisualEditorInner.svelte.d.ts +2 -3
- package/dist/visual/controls.css +85 -38
- package/dist/visual/diagnostics.d.ts +13 -21
- package/dist/visual/diagnostics.js +7 -19
- package/dist/visual/domid.js +3 -3
- package/dist/visual/ext.d.ts +1 -1
- package/dist/visual/ext.js +1 -1
- package/dist/visual/icons/nodes.d.ts +3 -0
- package/dist/visual/icons/nodes.js +2 -1
- package/dist/visual/index.d.ts +1 -0
- package/dist/visual/index.js +10 -3
- package/dist/visual/leaves.d.ts +47 -0
- package/dist/visual/leaves.js +31 -0
- package/dist/visual/links.d.ts +24 -0
- package/dist/visual/links.js +67 -0
- package/dist/visual/props.d.ts +33 -12
- package/dist/visual/signals.d.ts +6 -6
- package/dist/visual/strings.d.ts +14 -19
- package/dist/visual/strings.js +5 -7
- package/dist/visual/structure.d.ts +24 -17
- package/dist/visual/structure.js +8 -8
- package/dist/visual/synced.svelte.d.ts +1 -1
- package/dist/visual/synced.svelte.js +4 -4
- package/dist/visual/tips.d.ts +4 -2
- package/dist/visual/tips.js +7 -4
- package/package.json +2 -2
|
@@ -4,33 +4,33 @@
|
|
|
4
4
|
hidden-selection and separator-image guards. It is imported whole; the rules are
|
|
5
5
|
interdependent and which ones a given schema needs is not visible from here.
|
|
6
6
|
|
|
7
|
-
What it does
|
|
7
|
+
What it does not carry is a block reset, so without the rules below every leaf
|
|
8
8
|
inherits the UA `p { margin: 1em 0 }` (32px of margin in a box drawn to hold one
|
|
9
9
|
line), which is enough on its own to make an inline richtext field twice the height
|
|
10
10
|
of the input beside it. The reset lives here rather than per component because every
|
|
11
11
|
prose leaf in the package mounts through the codec (a field, the body, an array
|
|
12
12
|
element) and picks it up without restating it, and a leaf that carries the
|
|
13
13
|
control recipe (`visual/ProseField.svelte`) can then match `.qm-input` by
|
|
14
|
-
construction instead of by a tuned `min-height`. The source view is
|
|
14
|
+
construction instead of by a tuned `min-height`. The source view is not one of
|
|
15
15
|
them: it is a `<pre>` holding `textContent` (`source/view.ts`), outside
|
|
16
16
|
`.ProseMirror` and so outside every rule in this file.
|
|
17
17
|
|
|
18
|
-
It also carries hard-coded
|
|
18
|
+
It also carries hard-coded values that answer to no rung: a `#8cf` node-selection
|
|
19
19
|
outline, twice, and the `-32px` placing a selected list item's. Retinted and
|
|
20
20
|
re-measured here rather than in `theme.css` because a layered rule loses to that
|
|
21
21
|
unlayered stylesheet: equal specificity and a later import is what wins. */
|
|
22
22
|
.ProseMirror-selectednode {
|
|
23
|
-
outline: var(--_qm-ring
|
|
23
|
+
outline: var(--_qm-ring);
|
|
24
24
|
}
|
|
25
25
|
/* Upstream's `-32px` is measured against the UA's 40px list indent, which the list
|
|
26
26
|
rule below replaces with a rung. The offset moves with it, or a selected item's
|
|
27
27
|
outline hangs into the margin by the difference. */
|
|
28
28
|
li.ProseMirror-selectednode::after {
|
|
29
|
-
border: var(--_qm-ring
|
|
29
|
+
border: var(--_qm-ring);
|
|
30
30
|
left: calc(var(--_qm-space-4) * -1);
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
/* The
|
|
33
|
+
/* The gap cursor (`prosemirror-gapcursor`, imported beside this file): a caret
|
|
34
34
|
between two blocks, where the document holds no text position for an ordinary one.
|
|
35
35
|
It is what a press beside an island lands, so it is drawn in the surface's ink
|
|
36
36
|
rather than the upstream sheet's `black`, which is the `#8cf` defect again. */
|
|
@@ -47,14 +47,28 @@ li.ProseMirror-selectednode::after {
|
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
/* One rhythm between sibling blocks, in place of the UA's collapsed pair. Scoped by
|
|
50
|
-
|
|
51
|
-
|
|
50
|
+
parent rather than by tag, which is what keeps it true as the schema grows: the
|
|
51
|
+
containers below are every node whose content is `block+` (`schema.ts`), so
|
|
52
52
|
their children are blocks by definition, whatever kinds exist. `ul`/`ol` are
|
|
53
53
|
deliberately absent: a run of list items is tight, and the gap before a list is
|
|
54
|
-
the list's, not each item's.
|
|
54
|
+
the list's, not each item's.
|
|
55
|
+
|
|
56
|
+
An item is the exception to its own container. A list nested under an item is
|
|
57
|
+
part of the run that omission already keeps tight — `a. …` under `1. …` is the
|
|
58
|
+
next line of one list, not a new block after a paragraph — so an item's children
|
|
59
|
+
take the gap only up to the point where one of them is a list. Written as its own
|
|
60
|
+
arm rather than as a `:not()` over the shared one, because the exception is the
|
|
61
|
+
item's: a list after a paragraph inside a blockquote is an ordinary sibling pair
|
|
62
|
+
and keeps the gap.
|
|
63
|
+
|
|
64
|
+
A line box is ~22px at the paper size and the body leading, so the rung is a
|
|
65
|
+
little over half a line: enough that a break reads as a break, short of the full
|
|
66
|
+
blank line that doubles the leading and makes a short document read as a list of
|
|
67
|
+
fragments. */
|
|
55
68
|
.ProseMirror > * + *,
|
|
56
|
-
.ProseMirror :is(blockquote,
|
|
57
|
-
|
|
69
|
+
.ProseMirror :is(blockquote, [data-qm-unknown-container]) > * + *,
|
|
70
|
+
.ProseMirror li > * + :not(ul, ol) {
|
|
71
|
+
margin-top: var(--_qm-space-3);
|
|
58
72
|
}
|
|
59
73
|
|
|
60
74
|
/* A blockquote's UA indent was its only mark, and the reset above takes it. The rule
|
|
@@ -70,18 +84,18 @@ li.ProseMirror-selectednode::after {
|
|
|
70
84
|
emits, minus the four the UA already renders correctly (`strong`, `em`, `u`, `s`)
|
|
71
85
|
and the blockquote above.
|
|
72
86
|
|
|
73
|
-
Each rule answers to the
|
|
87
|
+
Each rule answers to the reference quill rather than to a browser default or to a
|
|
74
88
|
web editor's chrome, because the leaf sits beside a live preview of the same
|
|
75
89
|
content. `usaf_memo` sets `raw` in a monospace face and adds nothing; it renders a
|
|
76
|
-
heading as a bold
|
|
77
|
-
never read; it gives a link no decoration at all. So a leaf shows that a span
|
|
78
|
-
code and a line
|
|
90
|
+
heading as a bold run-in prepended to the following paragraph, with the level
|
|
91
|
+
never read; it gives a link no decoration at all. So a leaf shows that a span is
|
|
92
|
+
code and a line is a heading: never a prediction of the size paper will set it
|
|
79
93
|
at, which the package cannot know for a quill it has not seen.
|
|
80
94
|
|
|
81
|
-
Scoping is by
|
|
95
|
+
Scoping is by tag, and the schema does the rest: `h1`–`h6`, `hr` and the lists
|
|
82
96
|
cannot exist under the inline schema, so no rule for them can land on a `subject`
|
|
83
|
-
field however that field is mounted. The two
|
|
84
|
-
`link` are in both schemas, and a `plaintext` leaf strips them at
|
|
97
|
+
field however that field is mounted. The two marks are the exception: `code` and
|
|
98
|
+
`link` are in both schemas, and a `plaintext` leaf strips them at decode while
|
|
85
99
|
mounting a schema that still carries them, so a paste can put either in one. The
|
|
86
100
|
rules stand there too, and correctly: they say the leaf holds code, or a link,
|
|
87
101
|
which is exactly what it then holds.
|
|
@@ -89,28 +103,39 @@ li.ProseMirror-selectednode::after {
|
|
|
89
103
|
`visual/TipsCard.svelte` restates the two mark rules by hand, over the same
|
|
90
104
|
`toDOM` output injected outside any view. */
|
|
91
105
|
|
|
92
|
-
/* Code is a
|
|
106
|
+
/* Code is a face: no chip, no fill, no inset, no size step. The blockquote above
|
|
93
107
|
already argues the general form: a span reads as set apart without a fill or a
|
|
94
108
|
second box, on the one surface in the card with no edge of its own. A chip has
|
|
95
|
-
nowhere to come from in any case: the
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
109
|
+
nowhere to come from in any case: the body sits at `--_qm-surface` and the rungs
|
|
110
|
+
either side of it are the field well and the hover lane, so a chip at rest would
|
|
111
|
+
read as a hole in the paper or as a hovered button.
|
|
112
|
+
|
|
113
|
+
The withheld properties are declared at their zero, which is what makes the
|
|
114
|
+
paragraph above true of a mounted leaf: a chip on these tags is an ordinary page
|
|
115
|
+
rule, so left off, these are the two tags the host draws rather than the surface.
|
|
116
|
+
The other marks are ink, weight and decoration, which the leaf sets or safely
|
|
117
|
+
inherits, so the box is this mark's alone and the zeros are not a reset.
|
|
118
|
+
|
|
119
|
+
Both tags, where the face alone needs only one: a `code_block` renders `pre > code`
|
|
120
|
+
(`schema.ts`), so every character is inside a `code` element and the face reaches it
|
|
121
|
+
there — but the block's box is the `pre`, outside that element and styled by the
|
|
122
|
+
host on its own. `pre` still takes no `overflow-x`, because there is no overflow:
|
|
123
|
+
ProseMirror's own stylesheet sets `white-space: pre-wrap` there, so a long line
|
|
124
|
+
wraps. A scroller means overriding that to `pre` inside an editable `code`
|
|
125
|
+
textblock, which is an editing change, not a display rule. */
|
|
126
|
+
.ProseMirror :is(code, pre) {
|
|
106
127
|
font-family: var(--_qm-font-mono);
|
|
128
|
+
padding: 0;
|
|
129
|
+
border-radius: 0;
|
|
130
|
+
background: none;
|
|
131
|
+
font-size: inherit;
|
|
107
132
|
}
|
|
108
133
|
|
|
109
134
|
/* A link takes the surface's ink (the UA's blue is the `#8cf` defect again) and a
|
|
110
|
-
|
|
135
|
+
dotted underline. Dotted rather than solid because `underline` is a mark in the
|
|
111
136
|
same schema, and a solid rule renders an authored `<u>` and a link identically in a
|
|
112
137
|
paragraph that can hold both. An underline at all, where the tips card's link takes
|
|
113
|
-
none, because this leaf is
|
|
138
|
+
none, because this leaf is editable: the `href` is otherwise imperceptible, so
|
|
114
139
|
removing the rule loses an answer rather than ornament. No hue:
|
|
115
140
|
`--_qm-accent` already means focus, and a body of accent-coloured links collides
|
|
116
141
|
with the ring and with the correlation wash. */
|
|
@@ -128,74 +153,107 @@ li.ProseMirror-selectednode::after {
|
|
|
128
153
|
}
|
|
129
154
|
|
|
130
155
|
/* The UA's 40px list indent is the one box the reset above does not take (it is
|
|
131
|
-
padding, not margin), and it is a length nothing chose. A rung replaces it.
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
156
|
+
padding, not margin), and it is a length nothing chose. A rung replaces it.
|
|
157
|
+
Per-item spacing is untouched, which is the point of putting this on the list
|
|
158
|
+
rather than the item: the sibling-gap rule deliberately omits `ul`/`ol`, and
|
|
159
|
+
padding on the container cannot reintroduce what it withholds.
|
|
160
|
+
|
|
161
|
+
The markers are the UA's, reclaimed rather than inherited. `disc` and `decimal`
|
|
162
|
+
are right and this restates neither: a host reset (Tailwind's preflight sets
|
|
163
|
+
`list-style: none` on `ol, ul, menu`) is the common case, and against one an
|
|
164
|
+
unstated default is no default at all — bullets and numbers vanish from the leaf
|
|
165
|
+
while the preview beside it still draws them, which is an editor/paper
|
|
166
|
+
divergence on the plainest formatting there is. `revert` over a named type
|
|
167
|
+
because the UA's markers step by depth (disc, circle, square) and the schema
|
|
168
|
+
nests (`lists.ts`: Tab sinks an item); naming `disc` would flatten that ramp to
|
|
169
|
+
hold the first level. Same reclaim for `strong`/`em`/`u`/`s` above if a reset
|
|
170
|
+
that takes those ever turns up: the positive half states what it leaves to the
|
|
171
|
+
UA, and what a reset takes is what has to be asked back. */
|
|
136
172
|
.ProseMirror :is(ul, ol) {
|
|
137
173
|
padding-left: var(--_qm-space-4);
|
|
174
|
+
list-style: revert;
|
|
138
175
|
}
|
|
139
176
|
|
|
140
177
|
/* Six levels, one weight, no size step. The quill reads no level at all, so a size
|
|
141
178
|
ramp here would be the editor predicting a hierarchy the paper does not set; the
|
|
142
179
|
level stays in the model, which is where the codec round-trips it. It is also all
|
|
143
|
-
the ramp could carry: `--_qm-text-
|
|
144
|
-
|
|
145
|
-
|
|
180
|
+
the ramp could carry: this leaf renders at `--_qm-text-paper` and the next rung up
|
|
181
|
+
is `--_qm-text-title`, a chrome rung a heading inside a document has no business
|
|
182
|
+
reading. Six levels do not fit in the gap, and
|
|
146
183
|
minting five more is the drift the scale exists to prevent. */
|
|
147
184
|
.ProseMirror :is(h1, h2, h3, h4, h5, h6) {
|
|
148
185
|
font-size: inherit;
|
|
149
|
-
font-weight: var(--_qm-weight-
|
|
186
|
+
font-weight: var(--_qm-weight-strong);
|
|
150
187
|
}
|
|
151
188
|
|
|
152
189
|
/* ── The table island ────────────────────────────────────────────────────────
|
|
153
190
|
|
|
154
|
-
The one construct in this file with
|
|
191
|
+
The one construct in this file with chrome in it. The rest of the stylesheet
|
|
155
192
|
states what a block is and lets paper set its size; a table island is edited
|
|
156
|
-
through controls that do not print, so it also has a
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
data cell, hanging into a band the scroller carries as
|
|
164
|
-
the box a paragraph would, the accessibility tree is the
|
|
165
|
-
|
|
166
|
-
overlay: it is inside the cell it names.
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
193
|
+
through controls that do not print, so it also has a target floor and a reveal.
|
|
194
|
+
Those live here rather than in `visual/controls.css` for the same reason the
|
|
195
|
+
NodeView is vanilla: the island is inside the leaf, and the leaf is the codec's.
|
|
196
|
+
What it does not restate is the surface's dials: every value below is a `--_qm-*`
|
|
197
|
+
rung, so the island retints with everything else.
|
|
198
|
+
|
|
199
|
+
The band is in no track. Every control in it is absolutely positioned inside a real
|
|
200
|
+
data cell or against the grid's frame, hanging into a band the scroller carries as
|
|
201
|
+
padding. So the grid holds the box a paragraph would, the accessibility tree is the
|
|
202
|
+
data's shape, and a grip still lines up with its line by construction rather than by
|
|
203
|
+
a measured overlay: it is inside the cell it names.
|
|
204
|
+
|
|
205
|
+
Each control comes up alone. A grip or a bar is drawn while the pointer is on that
|
|
206
|
+
control, while it holds the focus, or while it is the one the gesture is about — a
|
|
207
|
+
selected line, a lifted one. The target is there the whole time either way, an
|
|
208
|
+
invisible button being hit-tested like any other, so what the reveal decides is what
|
|
209
|
+
the table looks like under a passing pointer, not what it answers to. */
|
|
210
|
+
|
|
211
|
+
/* The band, and the whole of what it costs. `padding` opens it on all four sides,
|
|
212
|
+
because each axis begins with a grip and ends with an add bar; the island's negative
|
|
213
|
+
`margin` spends the card's own inset buying the left one back, so the grid sits one
|
|
170
214
|
inset from the prose edge instead of a tap target plus one.
|
|
171
215
|
|
|
172
216
|
`margin-top: 0` overrides the sibling-gap rule rather than going negative: the band
|
|
173
|
-
|
|
174
|
-
and an `opacity: 0` control is still hit-tested, so it would take
|
|
175
|
-
presses.
|
|
176
|
-
|
|
217
|
+
absorbs the gap, at both ends. A negative margin would hang the band over the
|
|
218
|
+
neighbouring block, and an `opacity: 0` control is still hit-tested, so it would take
|
|
219
|
+
that block's presses. The `.ProseMirror` qualifier is what makes the override hold
|
|
220
|
+
wherever the island lands: two of the gap rule's arms name a container, so a bare
|
|
221
|
+
class loses to them for an island inside a list item or a quote, both of which the
|
|
222
|
+
schema admits. */
|
|
223
|
+
.ProseMirror .qm-table-island {
|
|
177
224
|
margin-top: 0;
|
|
178
225
|
margin-left: calc(var(--_qm-space-3) * -1);
|
|
179
226
|
}
|
|
227
|
+
.ProseMirror > .qm-table-island + * {
|
|
228
|
+
margin-top: 0;
|
|
229
|
+
}
|
|
180
230
|
.qm-table-scroller {
|
|
181
231
|
/* The one horizontally scrolling box in a leaf: a table is as wide as its
|
|
182
232
|
columns, and a wide one must not push the card's own layout. `overflow-y` is
|
|
183
233
|
`hidden` rather than left alone, because a non-`visible` axis computes the other
|
|
184
234
|
to `auto` and a table has nothing to scroll vertically. */
|
|
185
|
-
position: relative;
|
|
186
235
|
overflow-x: auto;
|
|
187
236
|
overflow-y: hidden;
|
|
188
|
-
padding: var(--_qm-tap-min)
|
|
237
|
+
padding: var(--_qm-tap-min);
|
|
189
238
|
width: max-content;
|
|
190
239
|
max-width: 100%;
|
|
191
240
|
}
|
|
241
|
+
/* The containing block for everything out of flow, and the reason it exists rather
|
|
242
|
+
than the scroller serving: an absolute inside a scroll container is placed against a
|
|
243
|
+
padding box the scroll then slides out from under it, so a cap pinned to the grid's
|
|
244
|
+
far end would drift into the middle of a scrolled table. The frame is the grid's own
|
|
245
|
+
box and travels with it. */
|
|
246
|
+
.qm-table-frame {
|
|
247
|
+
position: relative;
|
|
248
|
+
width: max-content;
|
|
249
|
+
}
|
|
192
250
|
.qm-table {
|
|
193
251
|
border-collapse: separate;
|
|
194
252
|
border-spacing: 0;
|
|
195
253
|
border: var(--_qm-border-width) solid var(--_qm-border);
|
|
196
254
|
border-radius: var(--_qm-radius-inner);
|
|
197
255
|
}
|
|
198
|
-
/* Two tiers of rule, because a table draws two different things. The
|
|
256
|
+
/* Two tiers of rule, because a table draws two different things. The frame and the
|
|
199
257
|
header's rule are structure and keep the full hairline; the lines between cells are
|
|
200
258
|
rhythm and drop to the faint rung, so the grid reads as one object with divisions
|
|
201
259
|
rather than as a stack of boxes. `separate` with zero spacing rather than
|
|
@@ -216,20 +274,21 @@ li.ProseMirror-selectednode::after {
|
|
|
216
274
|
.qm-table tbody tr:last-child > .qm-table-cell {
|
|
217
275
|
border-bottom: none;
|
|
218
276
|
}
|
|
219
|
-
/* The header row is the
|
|
277
|
+
/* The header row is the one weight distinction the island draws: `header` is a
|
|
220
278
|
separate field in the model rather than a flag on a row, so the surface says so.
|
|
221
|
-
It takes a tone with it, which is the same
|
|
222
|
-
|
|
279
|
+
It takes a tone with it, which is the same move a field makes: the well rung, a
|
|
280
|
+
band cut into the paper rather than a layer stacked on it, and a rung either way
|
|
281
|
+
rather than a shadow. The rest of a table's type is paper's. */
|
|
223
282
|
.qm-table-header-row .qm-table-cell {
|
|
224
|
-
font-weight: var(--_qm-weight-
|
|
225
|
-
background: var(--_qm-surface-
|
|
283
|
+
font-weight: var(--_qm-weight-strong);
|
|
284
|
+
background: var(--_qm-surface-well);
|
|
226
285
|
border-bottom: var(--_qm-border-width) solid var(--_qm-border);
|
|
227
286
|
}
|
|
228
287
|
/* A cell holds a whole nested view. Its measure floor keeps an empty table from
|
|
229
288
|
collapsing to a row of hairlines with nothing to aim at, and the caret is the
|
|
230
289
|
focus indicator here exactly as it is in the leaf: no ring.
|
|
231
290
|
|
|
232
|
-
The
|
|
291
|
+
The height floor is one line box, named as size times leading so both factors move
|
|
233
292
|
with the type ramp (`.qm-prose-block` states the same expression for three). An
|
|
234
293
|
empty row is then the height it will be once typed, so the first keystroke changes
|
|
235
294
|
no geometry. */
|
|
@@ -241,201 +300,180 @@ li.ProseMirror-selectednode::after {
|
|
|
241
300
|
outline: none;
|
|
242
301
|
}
|
|
243
302
|
/* A selected island takes the node outline every leaf block does
|
|
244
|
-
(`.ProseMirror-selectednode`, above), and that is the state
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
/*
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
303
|
+
(`.ProseMirror-selectednode`, above), and that is the state Escape leaves a cell or a
|
|
304
|
+
line for: the caret is out, the island is what is selected, and Backspace deletes it.
|
|
305
|
+
A caret inside a cell is not that state and does not paint it. */
|
|
306
|
+
|
|
307
|
+
/* The selection, washed across the cells it covers: what Backspace acts on, and the
|
|
308
|
+
only thing on the island that says what the next command is about. The accent held,
|
|
309
|
+
not the hover rung: a hover is what the pointer is passing over and a selection is
|
|
310
|
+
what the next command will act on, and two states one tone apart on the same surface
|
|
311
|
+
ladder read as the same state at a glance. Translucent, so a selected header cell
|
|
312
|
+
keeps its raised tone under the tint instead of trading it away.
|
|
313
|
+
|
|
314
|
+
One attribute for both gestures, because there is one selection: a grip draws the
|
|
315
|
+
rectangle covering its line and a sweep draws the block the pointer crossed, and the
|
|
316
|
+
wash cannot tell them apart because nothing downstream needs to. */
|
|
317
|
+
.qm-table-cell[data-selected] {
|
|
318
|
+
background: var(--_qm-accent-tint);
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
/* ── The band ────────────────────────────────────────────────────────────────
|
|
322
|
+
Two control families, one geometry: absolutely positioned out of the grid, a
|
|
323
|
+
`--_qm-tap-min` target whatever is drawn inside it, and no box of their own at rest.
|
|
324
|
+
What differs is which edge each hangs off and what it draws. The grips take the
|
|
325
|
+
leading edges, where a line begins; the add bars take the trailing ones, past where
|
|
326
|
+
the axis ends. Position is the whole of what says which is which: the grip's marks are
|
|
327
|
+
the only glyph on the island, and they say draggable rather than which control this
|
|
328
|
+
is. */
|
|
329
|
+
:is(.qm-table-grip, .qm-table-add) {
|
|
330
|
+
position: absolute;
|
|
258
331
|
display: flex;
|
|
259
332
|
align-items: center;
|
|
260
333
|
justify-content: center;
|
|
334
|
+
padding: 0;
|
|
261
335
|
border: none;
|
|
262
336
|
background: none;
|
|
337
|
+
color: var(--_qm-ink);
|
|
263
338
|
cursor: pointer;
|
|
264
339
|
}
|
|
265
|
-
:
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
/* ONE control per line, and it is a bar rather than a glyph: what a handle acts on
|
|
271
|
-
is the row or column it sits against, and position says that better than an icon
|
|
272
|
-
would.
|
|
340
|
+
/* The bar every one of them draws: a pill the length of what it acts on, a rhythm rung
|
|
341
|
+
thick where the target is the tap floor. Stated once, so a grip and an add bar cannot
|
|
342
|
+
drift into two shapes.
|
|
273
343
|
|
|
274
|
-
|
|
275
|
-
the
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
.qm-table-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
touch-action: none;
|
|
283
|
-
}
|
|
284
|
-
.qm-table-handle[data-axis='column'] {
|
|
285
|
-
inset-inline: 0;
|
|
286
|
-
bottom: 100%;
|
|
287
|
-
height: var(--_qm-tap-min);
|
|
288
|
-
}
|
|
289
|
-
.qm-table-handle[data-axis='row'] {
|
|
290
|
-
inset-block: 0;
|
|
291
|
-
right: 100%;
|
|
292
|
-
width: var(--_qm-tap-min);
|
|
293
|
-
}
|
|
294
|
-
.qm-table-handle-bar {
|
|
295
|
-
display: block;
|
|
344
|
+
One tone, not a hover ladder: the control is drawn only while it is the one the
|
|
345
|
+
pointer is on or the one a gesture is about, so a resting tone under that would be a
|
|
346
|
+
rung nothing ever reaches. The selected grip's tint below is the one exception, and it
|
|
347
|
+
says which line the next command acts on rather than where the pointer is. */
|
|
348
|
+
:is(.qm-table-grip-bar, .qm-table-add-bar) {
|
|
349
|
+
display: flex;
|
|
350
|
+
align-items: center;
|
|
351
|
+
justify-content: center;
|
|
296
352
|
border-radius: var(--_qm-radius-pill);
|
|
297
353
|
background: var(--_qm-border);
|
|
298
|
-
|
|
299
|
-
|
|
354
|
+
transition:
|
|
355
|
+
background-color var(--_qm-duration-fast) var(--_qm-ease-reverse),
|
|
356
|
+
color var(--_qm-duration-fast) var(--_qm-ease-reverse);
|
|
357
|
+
}
|
|
358
|
+
/* The glyph is square and the bar is not: the marks sit in the bar's thickness and the
|
|
359
|
+
bar's length is its line's, so the frame is sized off the one axis both share. */
|
|
360
|
+
.qm-table-grip-bar svg {
|
|
361
|
+
width: var(--_qm-space-3);
|
|
362
|
+
height: var(--_qm-space-3);
|
|
363
|
+
}
|
|
364
|
+
/* A grip runs along the line it names; an add bar runs across the axis it appends to.
|
|
365
|
+
So the two families map one `data-axis` onto opposite orientations, and orientation
|
|
366
|
+
is the one thing the rule above cannot share with them: a column's grip is as wide as
|
|
367
|
+
its column, and the bar that adds a column is as tall as the table. */
|
|
368
|
+
.qm-table-grip[data-axis='column'] .qm-table-grip-bar,
|
|
369
|
+
.qm-table-add[data-axis='row'] .qm-table-add-bar {
|
|
300
370
|
width: 100%;
|
|
301
|
-
height:
|
|
371
|
+
height: var(--_qm-space-3);
|
|
302
372
|
}
|
|
303
|
-
.qm-table-
|
|
304
|
-
|
|
373
|
+
.qm-table-grip[data-axis='row'] .qm-table-grip-bar,
|
|
374
|
+
.qm-table-add[data-axis='column'] .qm-table-add-bar {
|
|
375
|
+
width: var(--_qm-space-3);
|
|
305
376
|
height: 100%;
|
|
306
|
-
min-height: 0.75rem;
|
|
307
|
-
}
|
|
308
|
-
/* A selected handle carries the line's ink, so the bar and the wash say the same
|
|
309
|
-
thing at both ends of the gesture. */
|
|
310
|
-
.qm-table-handle[aria-pressed='true'] .qm-table-handle-bar {
|
|
311
|
-
background: var(--_qm-ink-label);
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
/* The corner is the ISLAND's handle: the grid origin, where the two bands converge,
|
|
315
|
-
and the one gesture that selects the whole table. Its mark is a square because what
|
|
316
|
-
it acts on is the rectangle and not a line of it. */
|
|
317
|
-
.qm-table-corner-handle {
|
|
318
|
-
right: 100%;
|
|
319
|
-
bottom: 100%;
|
|
320
|
-
width: var(--_qm-tap-min);
|
|
321
|
-
height: var(--_qm-tap-min);
|
|
322
|
-
}
|
|
323
|
-
.qm-table-corner-mark {
|
|
324
|
-
display: block;
|
|
325
|
-
width: 0.4375rem;
|
|
326
|
-
height: 0.4375rem;
|
|
327
|
-
border-radius: var(--_qm-radius-pill);
|
|
328
|
-
background: var(--_qm-border);
|
|
329
377
|
}
|
|
330
378
|
|
|
331
|
-
/*
|
|
332
|
-
|
|
333
|
-
|
|
379
|
+
/* One grip per line, and it is a bar rather than a glyph: what a grip acts on is the
|
|
380
|
+
row or column it sits against, and spanning that line says so better than an icon
|
|
381
|
+
could. The bar carries the grip's own marks — two rows of three, the shape a thing
|
|
382
|
+
you can pick up has everywhere else — so the control reads as draggable before it is
|
|
383
|
+
dragged.
|
|
334
384
|
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
border-radius: var(--_qm-radius-pill);
|
|
343
|
-
color: var(--_qm-accent);
|
|
385
|
+
The target is the band and the bar is drawn inside it: a grip spans its line on one
|
|
386
|
+
axis and the tap floor on the other, and the bar is drawn thinner inside that. A grip
|
|
387
|
+
sized to its own bar would be a target the thickness of the mark on it, on a control
|
|
388
|
+
the pointer has to find. */
|
|
389
|
+
.qm-table-grip {
|
|
390
|
+
/* The pointer owns this gesture, not the page's scroll: a grip drags. */
|
|
391
|
+
touch-action: none;
|
|
344
392
|
}
|
|
345
|
-
.qm-table-
|
|
393
|
+
.qm-table-grip[data-axis='column'] {
|
|
394
|
+
inset-inline: 0;
|
|
346
395
|
bottom: 100%;
|
|
347
|
-
|
|
348
|
-
}
|
|
349
|
-
/* The TRAILING seams sit flush inside their edge rather than centred on it: the last
|
|
350
|
-
boundary is the grid's own edge, and a seam centred on it would hang half outside
|
|
351
|
-
the scroller, where the padding does not reach and the clip does, making the append
|
|
352
|
-
affordance the one control that could not be pressed. */
|
|
353
|
-
.qm-table-seam[data-axis='column'][data-side='trail'] {
|
|
354
|
-
left: auto;
|
|
355
|
-
right: 0;
|
|
396
|
+
height: var(--_qm-tap-min);
|
|
356
397
|
}
|
|
357
|
-
.qm-table-
|
|
398
|
+
.qm-table-grip[data-axis='row'] {
|
|
399
|
+
inset-block: 0;
|
|
358
400
|
right: 100%;
|
|
359
|
-
|
|
401
|
+
width: var(--_qm-tap-min);
|
|
360
402
|
}
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
403
|
+
/* A selected grip takes the line's own tint and the accent for its marks, so the bar
|
|
404
|
+
and the wash say the same thing at both ends of the gesture. */
|
|
405
|
+
.qm-table-grip[aria-pressed='true'] .qm-table-grip-bar {
|
|
406
|
+
background: var(--_qm-accent-tint);
|
|
407
|
+
color: var(--_qm-accent);
|
|
364
408
|
}
|
|
365
409
|
|
|
366
|
-
/* The
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
left:
|
|
376
|
-
height: var(--_qm-tap-min);
|
|
377
|
-
background: var(--_qm-surface-raised);
|
|
378
|
-
border: var(--_qm-border-width) solid var(--_qm-border);
|
|
379
|
-
border-radius: var(--_qm-radius-pill);
|
|
380
|
-
}
|
|
381
|
-
/* The LAST column anchors right instead: a cluster is wider than a narrow column, and
|
|
382
|
-
one hung off the right edge would be the only chrome the scroller could clip. */
|
|
383
|
-
.qm-table-cell:last-child .qm-table-align {
|
|
384
|
-
left: auto;
|
|
385
|
-
right: 0;
|
|
386
|
-
}
|
|
387
|
-
.qm-table-align-item {
|
|
410
|
+
/* The add bars: one along each trailing edge, spanning it. A bar rather than a button
|
|
411
|
+
at the end of the band, because what it appends to is the axis and not a line — there
|
|
412
|
+
is no line out past the last one to sit against, and the whole edge is the easiest
|
|
413
|
+
target on the island to hit. They are the grips' mirror in every way but the edge and
|
|
414
|
+
the marks, which is what makes a bar out there read as one more of these rather than
|
|
415
|
+
as a control of its own: an empty bar past the last line is the table's own shape,
|
|
416
|
+
offered one line further on. */
|
|
417
|
+
.qm-table-add[data-axis='column'] {
|
|
418
|
+
inset-block: 0;
|
|
419
|
+
left: 100%;
|
|
388
420
|
width: var(--_qm-tap-min);
|
|
389
|
-
height: 100%;
|
|
390
|
-
padding: 0;
|
|
391
|
-
border-radius: var(--_qm-radius-pill);
|
|
392
|
-
color: var(--_qm-ink-label);
|
|
393
421
|
}
|
|
394
|
-
.qm-table-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
.qm-table-align-item[aria-pressed='true'] {
|
|
399
|
-
color: var(--_qm-accent);
|
|
422
|
+
.qm-table-add[data-axis='row'] {
|
|
423
|
+
inset-inline: 0;
|
|
424
|
+
top: 100%;
|
|
425
|
+
height: var(--_qm-tap-min);
|
|
400
426
|
}
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
.
|
|
427
|
+
/* The reveal, in two rungs, one per question (CODEC §"The table island"). The band comes
|
|
428
|
+
up muted while the pointer is anywhere on the island, answering whether there is one at
|
|
429
|
+
all; a control raises to full while the pointer is on it, while it holds the focus, or
|
|
430
|
+
while it is what a gesture is about — the selected line's grip, and the lifted one,
|
|
431
|
+
which is drawn through a drag the pointer has travelled off — answering which line.
|
|
432
|
+
|
|
433
|
+
Opacity rather than absence, so every control keeps its box and is hit-tested wherever
|
|
434
|
+
it sits. A grip's reach is the pointer's — no Tab arrives at one, the cell traversal
|
|
435
|
+
claiming the key first (`table-view.ts` §`step`) — so it is out of the tab order, and
|
|
436
|
+
the focus rung there draws the focus the view takes itself. The two bars are in it, the
|
|
437
|
+
Tab that declines off the last cell landing on them, and the same rung is what draws
|
|
438
|
+
one a keyboard has reached. */
|
|
439
|
+
:is(.qm-table-grip, .qm-table-add) {
|
|
411
440
|
opacity: 0;
|
|
412
441
|
transition: opacity var(--_qm-duration-fast) var(--_qm-ease-reverse);
|
|
413
442
|
}
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
443
|
+
/* `:where` on the island, so the first rung carries the specificity of the control alone
|
|
444
|
+
and the second one outranks it. Unwrapped, the descendant selector is the heavier of
|
|
445
|
+
the two and a hovered grip stays muted under the pointer that is on it. */
|
|
446
|
+
:where(.qm-table-island:hover) :is(.qm-table-grip, .qm-table-add) {
|
|
447
|
+
opacity: var(--_qm-opacity-muted);
|
|
417
448
|
}
|
|
418
|
-
.qm-table-
|
|
419
|
-
.qm-table-
|
|
420
|
-
.qm-table-handle[aria-pressed='true'],
|
|
421
|
-
.qm-table-seam:hover,
|
|
422
|
-
.qm-table-seam:focus-visible {
|
|
449
|
+
:is(.qm-table-grip, .qm-table-add):is(:hover, :focus-visible),
|
|
450
|
+
.qm-table-grip:is([aria-pressed='true'], .qm-table-lifted) {
|
|
423
451
|
opacity: 1;
|
|
424
452
|
}
|
|
425
453
|
|
|
426
|
-
/* The ring, on the chrome and nowhere else in this file. A prose leaf's focus
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
it. Declared here rather than reached for as
|
|
430
|
-
visual tier's stylesheet, and the island is inside
|
|
431
|
-
.
|
|
432
|
-
|
|
433
|
-
.
|
|
434
|
-
|
|
454
|
+
/* The ring, on the chrome and nowhere else in this file. A prose leaf's focus indicator
|
|
455
|
+
is its caret and a cell's is too, so the outline is dropped there; a control that comes
|
|
456
|
+
up out of nothing has the reveal, and a ring under a keyboard is what says the focus is
|
|
457
|
+
there rather than on the paper behind it. Declared here rather than reached for as
|
|
458
|
+
`.qm-focus-ring`: that recipe is the visual tier's stylesheet, and the island is inside
|
|
459
|
+
the leaf, which is the codec's.
|
|
460
|
+
|
|
461
|
+
A selected grip takes none. Focus and selection arrive together there — the grip takes
|
|
462
|
+
the focus because the selection's keys bind on it — and the tint plus the wash already
|
|
463
|
+
say where the next command lands. A ring on top is a second box around the loudest
|
|
464
|
+
thing on the island, drawn on the press that made the selection: a pointer gesture
|
|
465
|
+
answering with a keyboard's indicator. Stated as `none` rather than left unset, because
|
|
466
|
+
what fills the gap is the browser's own ring, which is the same box in a colour the
|
|
467
|
+
surface does not own. */
|
|
468
|
+
:is(.qm-table-grip, .qm-table-add):focus-visible {
|
|
469
|
+
outline: var(--_qm-ring);
|
|
435
470
|
outline-offset: var(--_qm-ring-offset);
|
|
436
471
|
}
|
|
472
|
+
.qm-table-grip[aria-pressed='true']:focus-visible {
|
|
473
|
+
outline: none;
|
|
474
|
+
}
|
|
437
475
|
|
|
438
|
-
/* A
|
|
476
|
+
/* A drag in flight. The lifted line reads as picked up by tone, never a shadow:
|
|
439
477
|
elevation is a surface rung here, which says the same thing at both poles. The drop
|
|
440
478
|
rule is the accent, the surface's one saturated ink, spent where a change is about
|
|
441
479
|
to land. */
|