@quillmark/svelte 0.27.0 → 0.28.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/NOTICE +4 -4
- package/README.md +26 -8
- package/THEMING.md +10 -8
- package/dist/core/address.d.ts +35 -64
- package/dist/core/address.js +35 -55
- package/dist/core/bloom.d.ts +4 -10
- package/dist/core/bloom.js +14 -27
- package/dist/core/codec/blocks.d.ts +41 -43
- package/dist/core/codec/blocks.js +97 -130
- package/dist/core/codec/code.d.ts +7 -10
- package/dist/core/codec/code.js +37 -46
- package/dist/core/codec/decode.d.ts +19 -23
- package/dist/core/codec/decode.js +76 -111
- package/dist/core/codec/encode.d.ts +11 -15
- package/dist/core/codec/encode.js +60 -67
- package/dist/core/codec/field.d.ts +62 -95
- package/dist/core/codec/field.js +107 -179
- package/dist/core/codec/islands.d.ts +33 -41
- package/dist/core/codec/islands.js +76 -86
- package/dist/core/codec/lists.d.ts +17 -26
- package/dist/core/codec/lists.js +117 -157
- package/dist/core/codec/marks.d.ts +4 -3
- package/dist/core/codec/marks.js +8 -3
- package/dist/core/codec/prose.css +84 -46
- package/dist/core/codec/schema.d.ts +18 -23
- package/dist/core/codec/schema.js +84 -76
- package/dist/core/codec/slash.d.ts +42 -48
- package/dist/core/codec/slash.js +0 -0
- package/dist/core/codec/table-copy.d.ts +4 -3
- package/dist/core/codec/table-copy.js +25 -7
- package/dist/core/codec/table-view.d.ts +12 -12
- package/dist/core/codec/table-view.js +460 -383
- package/dist/core/codec/table.d.ts +94 -61
- package/dist/core/codec/table.js +331 -83
- package/dist/core/codec/tasks.d.ts +6 -0
- package/dist/core/codec/tasks.js +30 -3
- package/dist/core/errors.d.ts +15 -30
- package/dist/core/errors.js +2 -6
- package/dist/core/index.js +7 -12
- package/dist/core/lifecycle.d.ts +7 -16
- package/dist/core/lifecycle.js +10 -21
- package/dist/core/rebind.svelte.d.ts +10 -20
- package/dist/core/rebind.svelte.js +15 -27
- package/dist/core/rungs.d.ts +14 -11
- package/dist/core/rungs.js +17 -19
- package/dist/core/teardown.d.ts +4 -6
- package/dist/core/teardown.js +7 -10
- package/dist/core/theme.css +74 -54
- package/dist/index.js +3 -8
- package/dist/preset/app.css +3 -1
- package/dist/preset/index.css +6 -8
- package/dist/preset/recipes.css +12 -15
- package/dist/preset/scale.css +18 -17
- package/dist/preset/shell.css +10 -0
- package/dist/preview/bridge.d.ts +18 -22
- package/dist/preview/bridge.js +29 -58
- package/dist/preview/controller.d.ts +21 -29
- package/dist/preview/controller.js +14 -39
- package/dist/preview/geometry.d.ts +13 -34
- package/dist/preview/geometry.js +13 -34
- package/dist/preview/index.js +4 -16
- package/dist/preview/paint.d.ts +3 -3
- package/dist/preview/paint.js +28 -68
- package/dist/preview/strings.d.ts +1 -1
- package/dist/preview/strings.js +2 -14
- package/dist/preview/zoom.d.ts +18 -23
- package/dist/preview/zoom.js +28 -27
- package/dist/visual/ArrayField.svelte +77 -16
- package/dist/visual/BooleanField.svelte +27 -14
- package/dist/visual/Card.svelte +61 -48
- package/dist/visual/CardControls.svelte +5 -11
- package/dist/visual/DateField.svelte +20 -4
- package/dist/visual/EnumField.svelte +3 -0
- package/dist/visual/FieldHint.svelte +2 -1
- package/dist/visual/FormatPopover.svelte +82 -15
- package/dist/visual/FormatPopover.svelte.d.ts +4 -0
- package/dist/visual/MatrixAdd.svelte +30 -12
- package/dist/visual/MatrixField.svelte +24 -16
- package/dist/visual/NumberField.svelte +7 -0
- package/dist/visual/ObjectField.svelte +4 -4
- package/dist/visual/ProseField.svelte +0 -5
- package/dist/visual/TipsCard.svelte +11 -10
- package/dist/visual/VariantField.svelte +3 -1
- package/dist/visual/VisualEditorInner.svelte +19 -3
- package/dist/visual/controls.css +7 -2
- package/dist/visual/fonts.d.ts +18 -0
- package/dist/visual/fonts.js +59 -0
- package/dist/visual/icons/nodes.d.ts +0 -5
- package/dist/visual/icons/nodes.js +0 -4
- package/dist/visual/props.d.ts +14 -1
- package/dist/visual/strings.d.ts +7 -0
- package/dist/visual/strings.js +5 -2
- package/dist/visual/structure.d.ts +43 -87
- package/dist/visual/structure.js +42 -83
- package/package.json +2 -2
package/dist/preview/zoom.d.ts
CHANGED
|
@@ -1,45 +1,40 @@
|
|
|
1
1
|
import type { PageSize } from '@quillmark/wasm';
|
|
2
|
-
/** CSS px per PDF pt at 100%: 96 CSS px to the inch over 72 pt
|
|
3
|
-
* size. */
|
|
2
|
+
/** CSS px per PDF pt at 100%: 96 CSS px to the inch over 72 pt. */
|
|
4
3
|
export declare const ACTUAL: number;
|
|
5
4
|
/** The furthest a gesture zooms in. */
|
|
6
5
|
export declare const MAX_ZOOM = 2;
|
|
7
|
-
/** What `Mod +` and `Mod −` step through
|
|
8
|
-
* keys land on, so a step lands somewhere a reader has been before. */
|
|
6
|
+
/** What `Mod +` and `Mod −` step through. */
|
|
9
7
|
export declare const STEPS: readonly [0.67, 0.75, 0.9, 1, 1.1, 1.25, 1.5, 1.75, 2];
|
|
10
8
|
/** The pane's content box, in CSS px. */
|
|
11
9
|
export interface Pane {
|
|
12
10
|
width: number;
|
|
13
11
|
height: number;
|
|
14
12
|
}
|
|
15
|
-
/** The default: the widest page fits the pane's width, capped at {@link FIT_CAP}.
|
|
16
|
-
* portrait-only document lands at the pane's width, as a narrow pane always drew it. */
|
|
13
|
+
/** The default: the widest page fits the pane's width, capped at {@link FIT_CAP}. */
|
|
17
14
|
export declare function fitZoom(pages: readonly PageSize[], pane: Pane): number;
|
|
18
|
-
/**
|
|
19
|
-
*
|
|
20
|
-
*
|
|
15
|
+
/**
|
|
16
|
+
* The furthest a gesture zooms out: every page fits the pane whole with {@link FLOOR_FILL} filled
|
|
17
|
+
* on its limiting axis, and never past the default.
|
|
18
|
+
*/
|
|
21
19
|
export declare function floorZoom(pages: readonly PageSize[], pane: Pane): number;
|
|
22
20
|
export declare function clampZoom(zoom: number, floor: number): number;
|
|
23
|
-
/**
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
|
|
21
|
+
/**
|
|
22
|
+
* The next level in `dir` from `zoom`, skipping levels under `floor`; past the last, the floor.
|
|
23
|
+
* Half a percent of slack, so a zoom shown as a level is at it.
|
|
24
|
+
*/
|
|
27
25
|
export declare function stepZoom(zoom: number, dir: 1 | -1, floor: number, fit: number): number;
|
|
28
26
|
/**
|
|
29
|
-
* A continuous gesture's run: the zoom its events
|
|
30
|
-
*
|
|
31
|
-
* log of the ratio). The run moves `shown` by each event's ratio rather than snapping
|
|
32
|
-
* `raw`, so a trackpad's small deltas carry it out of a hold as smoothly as they carried
|
|
33
|
-
* it in.
|
|
27
|
+
* A continuous gesture's run: the zoom its events asked for (`raw`), what it shows, and while it
|
|
28
|
+
* shows a hold, how far past it the events have carried (`slack`, a log of the ratio).
|
|
34
29
|
*/
|
|
35
30
|
export interface Glide {
|
|
36
31
|
raw: number;
|
|
37
32
|
shown: number;
|
|
38
33
|
slack: number;
|
|
39
34
|
}
|
|
40
|
-
/**
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
|
|
35
|
+
/**
|
|
36
|
+
* One event of a continuous gesture, carrying the run to `raw`. It stops at the first of `fit` or
|
|
37
|
+
* 100% it crosses, and leaves a hold once carried {@link DETENT} past. 100% gives way to a `fit`
|
|
38
|
+
* within the detent of it.
|
|
39
|
+
*/
|
|
45
40
|
export declare function glide(run: Glide, raw: number, floor: number, fit: number): Glide;
|
package/dist/preview/zoom.js
CHANGED
|
@@ -1,30 +1,31 @@
|
|
|
1
|
-
/** CSS px per PDF pt at 100%: 96 CSS px to the inch over 72 pt
|
|
2
|
-
* size. */
|
|
1
|
+
/** CSS px per PDF pt at 100%: 96 CSS px to the inch over 72 pt. */
|
|
3
2
|
export const ACTUAL = 96 / 72;
|
|
4
|
-
/** The default never draws a page larger than this
|
|
5
|
-
* size print would recognise rather than one stretched to the pane. */
|
|
3
|
+
/** The default never draws a page larger than this. */
|
|
6
4
|
const FIT_CAP = 1.25;
|
|
7
5
|
/** The furthest a gesture zooms in. */
|
|
8
6
|
export const MAX_ZOOM = 2;
|
|
9
|
-
/**
|
|
10
|
-
*
|
|
7
|
+
/**
|
|
8
|
+
* How much of the pane the page still fills, on its limiting axis, at the furthest a gesture zooms
|
|
9
|
+
* out.
|
|
10
|
+
*/
|
|
11
11
|
const FLOOR_FILL = 0.9;
|
|
12
|
-
/** What `Mod +` and `Mod −` step through
|
|
13
|
-
* keys land on, so a step lands somewhere a reader has been before. */
|
|
12
|
+
/** What `Mod +` and `Mod −` step through. */
|
|
14
13
|
export const STEPS = [0.67, 0.75, 0.9, 1, 1.1, 1.25, 1.5, 1.75, 2];
|
|
15
|
-
/**
|
|
16
|
-
*
|
|
14
|
+
/**
|
|
15
|
+
* How far, as a log of the zoom's ratio to a hold, a continuous gesture carries past it before it
|
|
16
|
+
* leaves it.
|
|
17
|
+
*/
|
|
17
18
|
const DETENT = 0.04;
|
|
18
19
|
const near = (zoom, hold) => Math.abs(Math.log(zoom / hold)) <= DETENT;
|
|
19
|
-
/** The default: the widest page fits the pane's width, capped at {@link FIT_CAP}.
|
|
20
|
-
* portrait-only document lands at the pane's width, as a narrow pane always drew it. */
|
|
20
|
+
/** The default: the widest page fits the pane's width, capped at {@link FIT_CAP}. */
|
|
21
21
|
export function fitZoom(pages, pane) {
|
|
22
22
|
const widest = Math.max(...pages.map((p) => p.widthPt));
|
|
23
23
|
return Math.min(pane.width / (widest * ACTUAL), FIT_CAP);
|
|
24
24
|
}
|
|
25
|
-
/**
|
|
26
|
-
*
|
|
27
|
-
*
|
|
25
|
+
/**
|
|
26
|
+
* The furthest a gesture zooms out: every page fits the pane whole with {@link FLOOR_FILL} filled
|
|
27
|
+
* on its limiting axis, and never past the default.
|
|
28
|
+
*/
|
|
28
29
|
export function floorZoom(pages, pane) {
|
|
29
30
|
const whole = Math.min(...pages.map((p) => Math.min(pane.width / p.widthPt, pane.height / p.heightPt)));
|
|
30
31
|
return Math.min((FLOOR_FILL * whole) / ACTUAL, fitZoom(pages, pane));
|
|
@@ -32,16 +33,16 @@ export function floorZoom(pages, pane) {
|
|
|
32
33
|
export function clampZoom(zoom, floor) {
|
|
33
34
|
return Math.min(MAX_ZOOM, Math.max(floor, zoom));
|
|
34
35
|
}
|
|
35
|
-
/**
|
|
36
|
-
*
|
|
37
|
-
|
|
36
|
+
/**
|
|
37
|
+
* The levels a step lands on: `STEPS` with `fit` replacing any level within {@link DETENT} of it.
|
|
38
|
+
*/
|
|
38
39
|
function stops(fit) {
|
|
39
40
|
return [...STEPS.filter((s) => !near(s, fit)), fit].sort((a, b) => a - b);
|
|
40
41
|
}
|
|
41
|
-
/**
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
|
|
42
|
+
/**
|
|
43
|
+
* The next level in `dir` from `zoom`, skipping levels under `floor`; past the last, the floor.
|
|
44
|
+
* Half a percent of slack, so a zoom shown as a level is at it.
|
|
45
|
+
*/
|
|
45
46
|
export function stepZoom(zoom, dir, floor, fit) {
|
|
46
47
|
const levels = stops(fit);
|
|
47
48
|
const next = dir > 0
|
|
@@ -49,11 +50,11 @@ export function stepZoom(zoom, dir, floor, fit) {
|
|
|
49
50
|
: levels.reverse().find((s) => s < zoom - 0.005 && s >= floor);
|
|
50
51
|
return clampZoom(next ?? (dir > 0 ? MAX_ZOOM : floor), floor);
|
|
51
52
|
}
|
|
52
|
-
/**
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
|
|
53
|
+
/**
|
|
54
|
+
* One event of a continuous gesture, carrying the run to `raw`. It stops at the first of `fit` or
|
|
55
|
+
* 100% it crosses, and leaves a hold once carried {@link DETENT} past. 100% gives way to a `fit`
|
|
56
|
+
* within the detent of it.
|
|
57
|
+
*/
|
|
57
58
|
export function glide(run, raw, floor, fit) {
|
|
58
59
|
const holds = near(fit, 1) ? [fit] : [fit, 1];
|
|
59
60
|
const step = Math.log(raw / run.raw);
|
|
@@ -652,6 +652,27 @@
|
|
|
652
652
|
if (!drag?.engaged || drag.drop !== k || drag.drop === drag.k) return undefined;
|
|
653
653
|
return drag.drop > drag.k ? 'after' : 'before';
|
|
654
654
|
}
|
|
655
|
+
|
|
656
|
+
/** Whether cells stand past the table scroller's end edge, under the pinned remove,
|
|
657
|
+
* which is what the fade before the remove draws on. */
|
|
658
|
+
let tableOverflow = $state(false);
|
|
659
|
+
/** The head row spans every track, so its box is the content width a new row or a
|
|
660
|
+
* longer cell changes. */
|
|
661
|
+
function trackOverflow(el: HTMLElement): () => void {
|
|
662
|
+
const measure = () => {
|
|
663
|
+
tableOverflow = el.scrollWidth - el.clientWidth - Math.abs(el.scrollLeft) > 1;
|
|
664
|
+
};
|
|
665
|
+
measure();
|
|
666
|
+
el.addEventListener('scroll', measure, { passive: true });
|
|
667
|
+
const observer =
|
|
668
|
+
typeof ResizeObserver === 'undefined' ? undefined : new ResizeObserver(measure);
|
|
669
|
+
observer?.observe(el);
|
|
670
|
+
if (el.firstElementChild) observer?.observe(el.firstElementChild);
|
|
671
|
+
return () => {
|
|
672
|
+
el.removeEventListener('scroll', measure);
|
|
673
|
+
observer?.disconnect();
|
|
674
|
+
};
|
|
675
|
+
}
|
|
655
676
|
</script>
|
|
656
677
|
|
|
657
678
|
<div
|
|
@@ -691,7 +712,12 @@
|
|
|
691
712
|
data-default={defaulted ? '' : undefined}
|
|
692
713
|
bind:this={rowsEl}
|
|
693
714
|
>
|
|
694
|
-
<div
|
|
715
|
+
<div
|
|
716
|
+
class="qm-array-table-scroller"
|
|
717
|
+
data-overflow={tableOverflow ? '' : undefined}
|
|
718
|
+
style:--table-cols={columns.length}
|
|
719
|
+
{@attach trackOverflow}
|
|
720
|
+
>
|
|
695
721
|
<!-- The header names the columns, so a cell carries no label of its own: its
|
|
696
722
|
accessible name is the row's and the column's composed (`ObjectField`). The
|
|
697
723
|
guidance affordance rides the header, being the column's rather than any
|
|
@@ -1072,27 +1098,21 @@
|
|
|
1072
1098
|
The distance inside an open row is the list's own, and the row then takes a rung of
|
|
1073
1099
|
air from the rows either side of it, so what it unfolded is nearer the summary it
|
|
1074
1100
|
hangs off than the sibling below. The wider distance on the inside is the inversion:
|
|
1075
|
-
a subform reading as the next row's preamble. A variant
|
|
1076
|
-
|
|
1077
|
-
|
|
1101
|
+
a subform reading as the next row's preamble. A variant takes the same distance and
|
|
1102
|
+
needs no such guard, a field carrying one control and no siblings for its cells to
|
|
1103
|
+
drift toward. */
|
|
1078
1104
|
.qm-element {
|
|
1079
1105
|
row-gap: var(--_qm-space);
|
|
1080
1106
|
}
|
|
1081
1107
|
.qm-element.open {
|
|
1082
1108
|
margin-block: var(--_qm-space);
|
|
1083
1109
|
}
|
|
1084
|
-
/*
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
stands outboard of the chevron that opened it. A variant's cells and a matrix's
|
|
1091
|
-
columns keep the flush edge: those sit beside the discriminant and the tick they are
|
|
1092
|
-
stored with, not under them. */
|
|
1093
|
-
.qm-element > :global(.qm-object) {
|
|
1094
|
-
margin-inline-start: var(--_qm-nest);
|
|
1095
|
-
}
|
|
1110
|
+
/* No inline distance: the subform's vertical hangs at the row's edge, under the
|
|
1111
|
+
summary that unfolded it, as a variant's cells hang at the discriminant's and a
|
|
1112
|
+
matrix's columns at the tick's. Every vertical hangs at the edge of the control it
|
|
1113
|
+
unfolds from, so a step in is one nesting distance wherever it is read, the
|
|
1114
|
+
`--_qm-nest` the subform keeps from its own stroke (ARCHITECTURE §"A plane is a
|
|
1115
|
+
tone"); a second rung here read as a deeper level than the object the row holds. */
|
|
1096
1116
|
/* The slabs measure the head, not the row: an open element is the head plus
|
|
1097
1117
|
everything it unfolded, and the controls belong to the line they sit on rather than
|
|
1098
1118
|
to all of that. Positioned, so `.qm-row-actions` anchors here. */
|
|
@@ -1123,6 +1143,7 @@
|
|
|
1123
1143
|
.qm-element-summary :global(.qm-el-chevron) {
|
|
1124
1144
|
flex-shrink: 0;
|
|
1125
1145
|
display: block;
|
|
1146
|
+
stroke-width: var(--_qm-glyph-stroke);
|
|
1126
1147
|
color: var(--_qm-ink-label);
|
|
1127
1148
|
transform: rotate(0deg);
|
|
1128
1149
|
transform-origin: center;
|
|
@@ -1130,6 +1151,9 @@
|
|
|
1130
1151
|
transform var(--_qm-duration-slow) var(--_qm-ease-reverse),
|
|
1131
1152
|
color var(--_qm-duration-fast) var(--_qm-ease-reverse);
|
|
1132
1153
|
}
|
|
1154
|
+
.qm-element-summary :global(.qm-el-chevron > *) {
|
|
1155
|
+
vector-effect: non-scaling-stroke;
|
|
1156
|
+
}
|
|
1133
1157
|
.qm-element-summary:hover :global(.qm-el-chevron),
|
|
1134
1158
|
.qm-element.open > .qm-element-head :global(.qm-el-chevron) {
|
|
1135
1159
|
color: var(--_qm-ink);
|
|
@@ -1251,6 +1275,28 @@
|
|
|
1251
1275
|
background: var(--_qm-surface);
|
|
1252
1276
|
box-shadow: 0 0 0 var(--_qm-ring-reach) var(--_qm-surface);
|
|
1253
1277
|
}
|
|
1278
|
+
/* While cells stand past the end edge, the slab fades them in over a step before it
|
|
1279
|
+
rather than cutting them at its edge: the column the cut hides is still there. */
|
|
1280
|
+
.qm-array-table-row > .qm-remove::before,
|
|
1281
|
+
.qm-array-table-head-end::before {
|
|
1282
|
+
content: '';
|
|
1283
|
+
position: absolute;
|
|
1284
|
+
inset-block: calc(-1 * var(--_qm-ring-reach));
|
|
1285
|
+
inset-inline-end: calc(100% + var(--_qm-ring-reach));
|
|
1286
|
+
width: var(--_qm-space-3);
|
|
1287
|
+
background: linear-gradient(to right, transparent, var(--_qm-surface));
|
|
1288
|
+
pointer-events: none;
|
|
1289
|
+
opacity: 0;
|
|
1290
|
+
transition: opacity var(--_qm-duration-fast) var(--_qm-ease-reverse);
|
|
1291
|
+
}
|
|
1292
|
+
.qm-array-table-row > .qm-remove:dir(rtl)::before,
|
|
1293
|
+
.qm-array-table-head-end:dir(rtl)::before {
|
|
1294
|
+
background: linear-gradient(to left, transparent, var(--_qm-surface));
|
|
1295
|
+
}
|
|
1296
|
+
.qm-array-table-scroller[data-overflow] > .qm-array-table-row > .qm-remove::before,
|
|
1297
|
+
.qm-array-table-scroller[data-overflow] .qm-array-table-head-end::before {
|
|
1298
|
+
opacity: 1;
|
|
1299
|
+
}
|
|
1254
1300
|
/* The glyph stands on the row's first line with the cells, however far the slab
|
|
1255
1301
|
stretches under it. */
|
|
1256
1302
|
.qm-array-table-row > .qm-remove {
|
|
@@ -1261,6 +1307,17 @@
|
|
|
1261
1307
|
border-radius: var(--_qm-radius-inner);
|
|
1262
1308
|
color: var(--_qm-ink-label);
|
|
1263
1309
|
}
|
|
1310
|
+
/* The pad past the slab, flat: the plane's spread above rounds with the slab's
|
|
1311
|
+
corners, and a cell scrolled under them shows through at the clip. */
|
|
1312
|
+
.qm-array-table-row > .qm-remove::after,
|
|
1313
|
+
.qm-array-table-head-end::after {
|
|
1314
|
+
content: '';
|
|
1315
|
+
position: absolute;
|
|
1316
|
+
inset-block: calc(-1 * var(--_qm-ring-reach));
|
|
1317
|
+
inset-inline-start: 100%;
|
|
1318
|
+
width: var(--_qm-ring-reach);
|
|
1319
|
+
background: var(--_qm-surface);
|
|
1320
|
+
}
|
|
1264
1321
|
/* The label line's own type: size, weight and leading are `.qm-field-label`'s, so
|
|
1265
1322
|
the two read as one register. Inner radius: the chip family is the card's, and this
|
|
1266
1323
|
box is a line of type. The chip's tap floor is given back (`.qm-tap-floor`),
|
|
@@ -1273,6 +1330,10 @@
|
|
|
1273
1330
|
line-height: var(--_qm-leading-tight);
|
|
1274
1331
|
border-radius: var(--_qm-radius-inner);
|
|
1275
1332
|
opacity: var(--_qm-opacity-idle);
|
|
1333
|
+
transition:
|
|
1334
|
+
opacity var(--_qm-duration-fast) var(--_qm-ease-reverse),
|
|
1335
|
+
background-color var(--_qm-duration-fast) var(--_qm-ease-reverse),
|
|
1336
|
+
color var(--_qm-duration-fast) var(--_qm-ease-reverse);
|
|
1276
1337
|
}
|
|
1277
1338
|
.qm-add-el:hover:not(:disabled),
|
|
1278
1339
|
.qm-add-el:focus-visible {
|
|
@@ -78,8 +78,13 @@
|
|
|
78
78
|
|
|
79
79
|
<style>
|
|
80
80
|
/* The switch stands on the first line of the boxes beside it: a row of controls tops
|
|
81
|
-
out together, and a mark carries no line of its own to sit on.
|
|
81
|
+
out together, and a mark carries no line of its own to sit on.
|
|
82
|
+
|
|
83
|
+
One length, the thumb's, and the track is two of them around the inset: the travel
|
|
84
|
+
is a thumb's width at every setting of `--qm-space`, where a track sized apart from
|
|
85
|
+
its inset ran the checked thumb into the end cap as the inset grew. */
|
|
82
86
|
.qm-toggle-wrap {
|
|
87
|
+
--thumb: 0.75rem;
|
|
83
88
|
display: flex;
|
|
84
89
|
align-items: center;
|
|
85
90
|
min-height: var(--_qm-box-line);
|
|
@@ -94,15 +99,17 @@
|
|
|
94
99
|
.qm-toggle-wrap :global(.qm-toggle) {
|
|
95
100
|
display: inline-flex;
|
|
96
101
|
align-items: center;
|
|
97
|
-
width:
|
|
98
|
-
height:
|
|
102
|
+
width: calc(2 * var(--thumb) + 2 * var(--_qm-space-half));
|
|
103
|
+
height: calc(var(--thumb) + 2 * var(--_qm-space-half));
|
|
99
104
|
padding: var(--_qm-space-half);
|
|
100
105
|
border: none;
|
|
101
106
|
border-radius: var(--_qm-radius-pill);
|
|
102
107
|
/* The track is a fill and nothing else: an edge around it would be a second
|
|
103
108
|
statement of a shape the tone already draws, and the checked state swaps that
|
|
104
|
-
one fill for the accent (ARCHITECTURE §Styling).
|
|
105
|
-
|
|
109
|
+
one fill for the accent (ARCHITECTURE §Styling). The fill is the band, a
|
|
110
|
+
resting tone: on the hover rung an off switch read as a button under the
|
|
111
|
+
pointer. */
|
|
112
|
+
background: var(--_qm-surface-band);
|
|
106
113
|
cursor: pointer;
|
|
107
114
|
transition: background var(--_qm-duration-fast) var(--_qm-ease-reverse);
|
|
108
115
|
}
|
|
@@ -113,21 +120,27 @@
|
|
|
113
120
|
background: var(--_qm-accent-default);
|
|
114
121
|
}
|
|
115
122
|
/* The focus ring rides `.qm-focus-ring` on the switch (controls.css). */
|
|
116
|
-
/* The thumb reads on tone alone
|
|
117
|
-
|
|
118
|
-
|
|
123
|
+
/* The thumb reads on tone alone, and its tone is what says where it stands: the
|
|
124
|
+
label rung over the track's band unchecked, and the base surface over
|
|
125
|
+
`--_qm-accent` checked. The card's own tone over the band is a step of about
|
|
126
|
+
1.3:1 in light and 1.5:1 in dark, a state indicator under WCAG 1.4.11's 3:1; the
|
|
127
|
+
label rung clears it at both, at 4.6:1 and 3.3:1. No edge of its own: a hairline
|
|
128
|
+
around a 12px pill is a second box inside the track's. */
|
|
119
129
|
.qm-toggle-wrap :global(.qm-toggle-thumb) {
|
|
120
|
-
width:
|
|
121
|
-
height:
|
|
130
|
+
width: var(--thumb);
|
|
131
|
+
height: var(--thumb);
|
|
122
132
|
border-radius: var(--_qm-radius-pill);
|
|
123
|
-
background: var(--_qm-
|
|
124
|
-
transition:
|
|
133
|
+
background: var(--_qm-ink-label);
|
|
134
|
+
transition:
|
|
135
|
+
translate var(--_qm-duration-fast) var(--_qm-ease-reverse),
|
|
136
|
+
background var(--_qm-duration-fast) var(--_qm-ease-reverse);
|
|
125
137
|
}
|
|
126
138
|
.qm-toggle-wrap :global(.qm-toggle-thumb[data-state='checked']) {
|
|
127
|
-
translate:
|
|
139
|
+
translate: var(--thumb);
|
|
140
|
+
background: var(--_qm-surface);
|
|
128
141
|
}
|
|
129
142
|
/* Unset, the thumb stands at neither end: halfway along its travel. */
|
|
130
143
|
.qm-toggle-wrap[data-unset] :global(.qm-toggle-thumb) {
|
|
131
|
-
translate:
|
|
144
|
+
translate: calc(var(--thumb) / 2);
|
|
132
145
|
}
|
|
133
146
|
</style>
|
package/dist/visual/Card.svelte
CHANGED
|
@@ -122,7 +122,8 @@
|
|
|
122
122
|
}
|
|
123
123
|
|
|
124
124
|
/** Not `--_qm-glyph-control`: that rung centres a glyph in a tap target, where this
|
|
125
|
-
* one stands in a run of text at the body rung and is sized to sit level with it.
|
|
125
|
+
* one stands in a run of text at the body rung and is sized to sit level with it. It
|
|
126
|
+
* strokes at the control glyph's weight (`--_qm-glyph-stroke`). */
|
|
126
127
|
const CHEVRON = 16;
|
|
127
128
|
|
|
128
129
|
const ungrouped = $derived(card.sections.filter((s) => s.group == null));
|
|
@@ -428,15 +429,18 @@
|
|
|
428
429
|
{/snippet}
|
|
429
430
|
|
|
430
431
|
<style>
|
|
431
|
-
/* An island: the card is the base plane
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
half stands a step tighter
|
|
436
|
-
|
|
437
|
-
further for it.
|
|
432
|
+
/* An island: the card is the base plane and the column behind it the sunken one, and
|
|
433
|
+
the step between the two tones is the whole of its edge (ARCHITECTURE §"A plane is a
|
|
434
|
+
tone"). The block half is the same rung as the gap: the payload stands that far off
|
|
435
|
+
the card's edge and off the body below it. The header insets itself to the
|
|
436
|
+
section-heading column (`.qm-card-header`). The inline half stands a step tighter
|
|
437
|
+
than the nesting rung the verticals inside keep: this edge closes the block rather
|
|
438
|
+
than nesting one, and the rules it holds run that much further for it.
|
|
439
|
+
|
|
440
|
+
Inside that inset is the card's one text column (`--_qm-column`): the title, a
|
|
441
|
+
top-level field, the body's lines, the recovery note and the delete glyph's far edge
|
|
442
|
+
all stand on it, so the card reads as one measure at both ends. */
|
|
438
443
|
.qm-card {
|
|
439
|
-
border: var(--_qm-border-width) solid var(--_qm-border);
|
|
440
444
|
border-radius: var(--_qm-radius);
|
|
441
445
|
padding: var(--_qm-space-3) var(--_qm-space-2);
|
|
442
446
|
background: var(--_qm-surface);
|
|
@@ -463,10 +467,9 @@
|
|
|
463
467
|
align-items: center;
|
|
464
468
|
justify-content: space-between;
|
|
465
469
|
gap: var(--_qm-space-2);
|
|
466
|
-
/*
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
padding-inline: calc(var(--_qm-space) + var(--_qm-vertical-width));
|
|
470
|
+
/* On the column, inline only. The block pull is half the card's block inset,
|
|
471
|
+
so the header sits that far off the card's edge and the rule. */
|
|
472
|
+
padding-inline: var(--_qm-column);
|
|
470
473
|
margin-block: calc(-1 * var(--_qm-space-3) / 2);
|
|
471
474
|
}
|
|
472
475
|
.qm-card-header-right {
|
|
@@ -500,9 +503,9 @@
|
|
|
500
503
|
overlaid input tracks its content width. Both carry the same nothing for a box model
|
|
501
504
|
and inherit the same type tokens, which is what makes the two measure alike.
|
|
502
505
|
|
|
503
|
-
The type is the group header's
|
|
504
|
-
|
|
505
|
-
|
|
506
|
+
The type is the group header's: a card title and a section header both name a block
|
|
507
|
+
of fields, so they read as one register and what ranks them is position rather than
|
|
508
|
+
a size step. */
|
|
506
509
|
.qm-card-title-sizer {
|
|
507
510
|
display: inline-grid;
|
|
508
511
|
align-items: center;
|
|
@@ -521,9 +524,9 @@
|
|
|
521
524
|
min-width: 2ch;
|
|
522
525
|
}
|
|
523
526
|
/* The title draws no box in any state: a card title is already the one line that
|
|
524
|
-
reads as the card's name, and the region's `cursor: text`
|
|
525
|
-
|
|
526
|
-
|
|
527
|
+
reads as the card's name, and the region's `cursor: text` answers the pointer. A
|
|
528
|
+
typed title is a value, at the ink, and the automatic one a placeholder, at label
|
|
529
|
+
ink, as in every field. */
|
|
527
530
|
.qm-card-title {
|
|
528
531
|
grid-area: 1 / 1;
|
|
529
532
|
width: 100%;
|
|
@@ -531,18 +534,12 @@
|
|
|
531
534
|
font: inherit;
|
|
532
535
|
/* `font: inherit` does not carry colour: a form control defaults to the UA's own
|
|
533
536
|
text colour rather than the header's ink without this line. */
|
|
534
|
-
color: var(--_qm-ink
|
|
537
|
+
color: var(--_qm-ink);
|
|
535
538
|
border: none;
|
|
536
539
|
padding: 0;
|
|
537
540
|
background: transparent;
|
|
538
|
-
transition: color var(--_qm-duration-fast) var(--_qm-ease-reverse);
|
|
539
541
|
}
|
|
540
|
-
.
|
|
541
|
-
.qm-card-title:focus {
|
|
542
|
-
color: var(--_qm-ink);
|
|
543
|
-
}
|
|
544
|
-
/* The automatic title, at the label ink every placeholder takes rather than the UA's
|
|
545
|
-
grey, and steady under focus, where a typed title steps to the ink. */
|
|
542
|
+
/* The label ink every placeholder takes rather than the UA's grey. */
|
|
546
543
|
.qm-card-title::placeholder {
|
|
547
544
|
color: var(--_qm-ink-label);
|
|
548
545
|
opacity: 1;
|
|
@@ -591,11 +588,10 @@
|
|
|
591
588
|
vertical those two edges hold.
|
|
592
589
|
|
|
593
590
|
No stroke: a vertical would mark a section a reader has no name for. The start
|
|
594
|
-
inset is the
|
|
595
|
-
off it — so a top-level field and a section heading share a column. */
|
|
591
|
+
inset is the column, so a top-level field and a section heading share it. */
|
|
596
592
|
.qm-section {
|
|
597
593
|
padding-block: var(--_qm-space);
|
|
598
|
-
padding-inline-start:
|
|
594
|
+
padding-inline-start: var(--_qm-column);
|
|
599
595
|
}
|
|
600
596
|
/* Where it faces a rule, the rung a heading already stands off one. The fields
|
|
601
597
|
sit on the heading column, not the card's edge. */
|
|
@@ -622,8 +618,8 @@
|
|
|
622
618
|
}
|
|
623
619
|
/* The nesting vertical, one `--_qm-nest` in from the card's edge with the panel's
|
|
624
620
|
fields the same rung off it (ARCHITECTURE §"A plane is a tone"). `--_qm-border` and
|
|
625
|
-
not `--_qm-accent`:
|
|
626
|
-
|
|
621
|
+
not `--_qm-accent`: the verticals and the rules beside them are one stroke at every
|
|
622
|
+
depth, and a tone that changed as it went in would read as unrelated lines rather
|
|
627
623
|
than one figure. A named section is what earns it, which is why the ungrouped block
|
|
628
624
|
above draws none.
|
|
629
625
|
|
|
@@ -684,17 +680,10 @@
|
|
|
684
680
|
the accordion stops looking like structure. Size, weight and leading sit after
|
|
685
681
|
`font`, a shorthand that carries `line-height`. */
|
|
686
682
|
.qm-group-header {
|
|
687
|
-
/* Positioned, and paint is not what it buys: a group's box grows by
|
|
688
|
-
`--stroke-reach` at both ends and hands the growth back as margin, so
|
|
689
|
-
consecutive boxes overlap in a band at every seam, and a closed group's header
|
|
690
|
-
ends inside the next group's box. In flow, the later sibling takes the presses
|
|
691
|
-
that land in the band and the bottom of the header is a dead strip; positioned,
|
|
692
|
-
the control holds its own box, and the band paints the same either way. */
|
|
693
|
-
position: relative;
|
|
694
683
|
display: flex;
|
|
695
684
|
align-items: center;
|
|
696
685
|
gap: var(--_qm-space);
|
|
697
|
-
width:
|
|
686
|
+
min-width: 0;
|
|
698
687
|
border: none;
|
|
699
688
|
background: transparent;
|
|
700
689
|
padding: var(--_qm-space) 0 var(--_qm-space) var(--_qm-space);
|
|
@@ -709,17 +698,26 @@
|
|
|
709
698
|
}
|
|
710
699
|
/* The header row: the press target, and beside it the guidance marker a headed
|
|
711
700
|
section carries (`FieldHint`), which is its own control and so not inside the
|
|
712
|
-
button.
|
|
713
|
-
|
|
701
|
+
button. The button sizes to its text so the marker follows the name, and its
|
|
702
|
+
`::after` spans the row so the whole row still presses it; the marker, positioned
|
|
703
|
+
by its tap floor and later in the row, stands over that plane.
|
|
704
|
+
|
|
705
|
+
Positioned, and paint is not what it buys: a group's box grows by `--stroke-reach`
|
|
706
|
+
at both ends and hands the growth back as margin, so consecutive boxes overlap in a
|
|
707
|
+
band at every seam, and a closed group's header ends inside the next group's box.
|
|
708
|
+
In flow, the later sibling takes the presses that land in the band and the bottom
|
|
709
|
+
of the header is a dead strip; positioned, the row holds its own box, and the band
|
|
710
|
+
paints the same either way. */
|
|
714
711
|
.qm-group-head {
|
|
715
712
|
position: relative;
|
|
716
713
|
display: flex;
|
|
717
714
|
align-items: center;
|
|
718
715
|
gap: var(--_qm-space);
|
|
719
716
|
}
|
|
720
|
-
.qm-group-
|
|
721
|
-
|
|
722
|
-
|
|
717
|
+
.qm-group-header::after {
|
|
718
|
+
content: '';
|
|
719
|
+
position: absolute;
|
|
720
|
+
inset: 0;
|
|
723
721
|
}
|
|
724
722
|
/* The parked description: `FieldLabel`'s recipe, for the one description a
|
|
725
723
|
header rather than a label parks. */
|
|
@@ -734,10 +732,14 @@
|
|
|
734
732
|
.qm-group-header :global(.qm-group-chevron) {
|
|
735
733
|
flex-shrink: 0;
|
|
736
734
|
display: block;
|
|
735
|
+
stroke-width: var(--_qm-glyph-stroke);
|
|
737
736
|
transform: rotate(0deg);
|
|
738
737
|
transform-origin: center;
|
|
739
738
|
transition: transform var(--_qm-duration-slow) var(--_qm-ease-reverse);
|
|
740
739
|
}
|
|
740
|
+
.qm-group-header :global(.qm-group-chevron > *) {
|
|
741
|
+
vector-effect: non-scaling-stroke;
|
|
742
|
+
}
|
|
741
743
|
/* Open shares hover's ink step: a big borderless target draws no box, so the ink is
|
|
742
744
|
the only cue an open section keeps once the pointer leaves it. The chevron's
|
|
743
745
|
rotation is the other cue, and stays open-only below. */
|
|
@@ -792,9 +794,17 @@
|
|
|
792
794
|
flex-direction: column;
|
|
793
795
|
gap: var(--_qm-space);
|
|
794
796
|
}
|
|
795
|
-
/*
|
|
797
|
+
/* Paper's margin is the column. On the editable, so a press in the strip lands a
|
|
798
|
+
caret; carried by the leaf's inset it would be dead width. The diagnostics under the
|
|
799
|
+
body start where its lines do, as a field's start under its well. */
|
|
800
|
+
.qm-body-leaf :global(.ProseMirror),
|
|
801
|
+
.qm-body-leaf > :global(.qm-diag-list) {
|
|
802
|
+
padding-inline: var(--_qm-column);
|
|
803
|
+
}
|
|
804
|
+
/* The one card that draws an edge, and the edge is the state: a dashed stroke is the
|
|
805
|
+
placeholder idiom, which a card the schema cannot project is. */
|
|
796
806
|
.qm-card.qm-unschemable {
|
|
797
|
-
border
|
|
807
|
+
border: var(--_qm-border-width) dashed var(--_qm-border);
|
|
798
808
|
}
|
|
799
809
|
/* One typographic role with the editable title above. */
|
|
800
810
|
.qm-card-title-static {
|
|
@@ -807,6 +817,7 @@
|
|
|
807
817
|
display: flex;
|
|
808
818
|
flex-direction: column;
|
|
809
819
|
gap: var(--_qm-space-2);
|
|
820
|
+
padding-inline: var(--_qm-column);
|
|
810
821
|
}
|
|
811
822
|
.qm-recovery-note {
|
|
812
823
|
margin: 0;
|
|
@@ -820,9 +831,11 @@
|
|
|
820
831
|
font-size: var(--_qm-text-label);
|
|
821
832
|
color: var(--_qm-ink-label);
|
|
822
833
|
}
|
|
823
|
-
/* The one native control the surface draws, on the box's own recipe (controls.css).
|
|
834
|
+
/* The one native control the surface draws, on the box's own recipe (controls.css).
|
|
835
|
+
`font` carries no colour, so the value's ink is restated over the UA's. */
|
|
824
836
|
.qm-recovery-retype select {
|
|
825
837
|
font: inherit;
|
|
838
|
+
color: var(--_qm-ink);
|
|
826
839
|
border: none;
|
|
827
840
|
border-radius: var(--_qm-radius-inner);
|
|
828
841
|
background: var(--_qm-surface-well);
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Right-aligned in the header: a move-up/move-down chevron pair (each disabled at its
|
|
4
4
|
edge), then delete, the row revealed while the pointer or the caret is in the card.
|
|
5
5
|
Reorder is buttons, not drag (V1). All three are chips (controls.css): fill arrives
|
|
6
|
-
on hover, and delete
|
|
6
|
+
on hover, and delete rests at the label ink beside them. The card scopes
|
|
7
7
|
that reveal, so its condition lives in the parent's CSS; the row keeps the narrower
|
|
8
8
|
guarantee here, that a focused control is a visible one.
|
|
9
9
|
-->
|
|
@@ -80,18 +80,12 @@
|
|
|
80
80
|
height: var(--_qm-tap-min);
|
|
81
81
|
padding: 0;
|
|
82
82
|
}
|
|
83
|
-
/*
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
.qm-card-delete {
|
|
87
|
-
color: color-mix(
|
|
88
|
-
in oklab,
|
|
89
|
-
var(--_qm-danger) calc(100% * var(--_qm-opacity-idle)),
|
|
90
|
-
var(--_qm-surface)
|
|
91
|
-
);
|
|
92
|
-
}
|
|
83
|
+
/* The delete rests at the chip's label ink, as an array row's and a matrix member's
|
|
84
|
+
remove do, and under the pointer or the focus takes their danger tint and ink in
|
|
85
|
+
place of the chip's hover fill. */
|
|
93
86
|
.qm-card-delete:hover,
|
|
94
87
|
.qm-card-delete:focus-visible {
|
|
88
|
+
background: var(--_qm-danger-tint);
|
|
95
89
|
color: var(--_qm-danger);
|
|
96
90
|
}
|
|
97
91
|
</style>
|