svedit 0.7.1 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +91 -2
- package/dist/Node.svelte +4 -25
- package/dist/Node.svelte.d.ts.map +1 -1
- package/dist/NodeArrayProperty.svelte +17 -3
- package/dist/NodeArrayProperty.svelte.d.ts.map +1 -1
- package/dist/NodeGap.svelte +64 -27
- package/dist/NodeGap.svelte.d.ts +6 -6
- package/dist/NodeGap.svelte.d.ts.map +1 -1
- package/dist/NodeGapMarkers.svelte +36 -10
- package/dist/NodeGapMarkers.svelte.d.ts.map +1 -1
- package/dist/Svedit.svelte +76 -115
- package/dist/Svedit.svelte.d.ts.map +1 -1
- package/dist/node_gap_computation.svelte.js +1 -1
- package/package.json +1 -1
- package/src/lib/Node.svelte +4 -25
- package/src/lib/NodeArrayProperty.svelte +17 -3
- package/src/lib/NodeGap.svelte +64 -27
- package/src/lib/NodeGapMarkers.svelte +36 -10
- package/src/lib/Svedit.svelte +76 -115
- package/src/lib/node_gap_computation.svelte.js +1 -1
package/README.md
CHANGED
|
@@ -1056,6 +1056,82 @@ Further things to consider:
|
|
|
1056
1056
|
- Avoid CSS selectors like `:last-child` or `:first-child` on nodes (e.g., `[data-type="node"]:last-child`) because `<NodeGap>` elements are inserted in edit mode and will become the actual first or last child. This can cause unexpected layout shifts (e.g., if you have `.paragraph-node:last-child { margin-bottom: 10px }`, the margin won't apply as expected).
|
|
1057
1057
|
- Avoid adding css `margin` to nodes inside node arrays when using flex or grid layouts. Use `gap` on the container instead. This ensure `NodeGap` and `NodeGapMarkers` render consistently. If you need to add a margin, add it to child element of Node.
|
|
1058
1058
|
|
|
1059
|
+
### Node array CSS tokens
|
|
1060
|
+
|
|
1061
|
+
`<NodeArrayProperty>` renders a `[data-type="node_array"]` element. Two CSS custom properties control how gaps and carets behave inside it:
|
|
1062
|
+
|
|
1063
|
+
**`--row`** — Tell Svedit whether a node array flows horizontally (`1`) or vertically (`0`). Gaps, carets, and markers all switch orientation accordingly. Defaults to `0` on the Svedit canvas. Set it on the node array or an ancestor:
|
|
1064
|
+
|
|
1065
|
+
```css
|
|
1066
|
+
.my-horizontal-layout :global(.grid-items) {
|
|
1067
|
+
--row: 1;
|
|
1068
|
+
display: flex;
|
|
1069
|
+
flex-wrap: wrap;
|
|
1070
|
+
}
|
|
1071
|
+
```
|
|
1072
|
+
|
|
1073
|
+
**`--node-caret-boundary`** — Edge gaps (before the first node, after the last) extend outward beyond the container to enlarge their click target. If the node array has neighboring elements (e.g. a preceding node or surrounding UI), the outward extension can overlap them:
|
|
1074
|
+
|
|
1075
|
+
```
|
|
1076
|
+
Without --node-caret-boundary With --node-caret-boundary
|
|
1077
|
+
|
|
1078
|
+
: . . . . . . . . . . . . . . . :
|
|
1079
|
+
: +---------------------------+ : +-----------------------------+
|
|
1080
|
+
: | Toolbar / UI | : ← overlap | Toolbar / UI |
|
|
1081
|
+
: +---------------------------+ : +-----------------------------+
|
|
1082
|
+
: :
|
|
1083
|
+
: edge gap (unbounded) : boudary → +-----------------------------+
|
|
1084
|
+
: . . . . . . . . . . . . . . . : | : . . . . . . . . . . . . : |
|
|
1085
|
+
| : edge gap (clamped) : |
|
|
1086
|
+
+---------------------------+ | : . . . . . . . . . . . . : |
|
|
1087
|
+
| +---------------------+ | | +-----------------------+ |
|
|
1088
|
+
| | First node | | | | First node | |
|
|
1089
|
+
| +---------------------+ | | +-----------------------+ |
|
|
1090
|
+
| gap between nodes | | gap between nodes |
|
|
1091
|
+
| +---------------------+ | | +-----------------------+ |
|
|
1092
|
+
| | Last node | | | | Last node | |
|
|
1093
|
+
| +---------------------+ | | +-----------------------+ |
|
|
1094
|
+
+---------------------------+ | : . . . . . . . . . . . . : |
|
|
1095
|
+
| : edge gap (clamped) : |
|
|
1096
|
+
: . . . . . . . . . . . . . . . : | : . . . . . . . . . . . . : |
|
|
1097
|
+
: edge gap (unbounded) : boudary → +-----------------------------+
|
|
1098
|
+
: :
|
|
1099
|
+
: +---------------------------+ : +-----------------------------+
|
|
1100
|
+
: | Footer / UI | : ← overlap | Footer / UI |
|
|
1101
|
+
: +---------------------------+ : +-----------------------------+
|
|
1102
|
+
: . . . . . . . . . . . . . . . :
|
|
1103
|
+
```
|
|
1104
|
+
|
|
1105
|
+
Set `--node-caret-boundary` to the `anchor-name` of a parent element to clamp edge gaps to that element's edges:
|
|
1106
|
+
|
|
1107
|
+
```css
|
|
1108
|
+
.editor-wrapper {
|
|
1109
|
+
anchor-name: --editor-boundary;
|
|
1110
|
+
padding: 24px;
|
|
1111
|
+
}
|
|
1112
|
+
.editor-wrapper [data-type="node_array"] {
|
|
1113
|
+
--node-caret-boundary: --editor-boundary;
|
|
1114
|
+
}
|
|
1115
|
+
```
|
|
1116
|
+
|
|
1117
|
+
When set, edge gaps clamp to the boundary element's edges instead. When not set, gaps extend to the containing block edge (default).
|
|
1118
|
+
|
|
1119
|
+
Since `--node-caret-boundary` inherits to nested node arrays, you may need to unset it on inner containers that should not be clamped:
|
|
1120
|
+
|
|
1121
|
+
```css
|
|
1122
|
+
.inner-container [data-type="node_array"] {
|
|
1123
|
+
--node-caret-boundary: initial;
|
|
1124
|
+
}
|
|
1125
|
+
```
|
|
1126
|
+
|
|
1127
|
+
For per-axis control, use `--node-caret-boundary-x` (left/right) and `--node-caret-boundary-y` (top/bottom). They take precedence over `--node-caret-boundary` when set:
|
|
1128
|
+
|
|
1129
|
+
```css
|
|
1130
|
+
.editor-wrapper [data-type="node_array"] {
|
|
1131
|
+
--node-caret-boundary-x: --editor-boundary;
|
|
1132
|
+
}
|
|
1133
|
+
```
|
|
1134
|
+
|
|
1059
1135
|
## Beyond the README
|
|
1060
1136
|
|
|
1061
1137
|
The source code is compact and readable — less than 3000 LOC across a handful of files. We encourage you to explore it. The files in [`src/lib`](./src/lib) are the library code, while the files in [`src/routes`](./src/routes) are example code you can copy and adapt to your needs.
|
|
@@ -1080,9 +1156,22 @@ You can preview the production build with `npm run preview`.
|
|
|
1080
1156
|
|
|
1081
1157
|
## Contributing
|
|
1082
1158
|
|
|
1083
|
-
|
|
1159
|
+
Contributions are very welcome! Bug reports, bug fixes, and small PRs (a couple of lines of code) don't need any ceremony — just go for it. What follows applies to larger changes and new features.
|
|
1160
|
+
|
|
1161
|
+
I take long-term maintainability very seriously. Much like the SQLite project, I prioritize minimalism and code quality over features. This means I may decline pull requests — even good ones — if they don't fit my vision for Svedit at a given point in time. I'll always try to articulate my reasons, but sometimes it comes down to intuition more than logic. Please don't take it personally — it doesn't mean your idea is bad, just that I don't see it belonging in core right now.
|
|
1162
|
+
|
|
1163
|
+
### How to contribute a feature
|
|
1164
|
+
|
|
1165
|
+
1. **Start with your requirements.** Open an issue describing what you need and why. Wait for a green light that this is something that belongs in core before writing code.
|
|
1166
|
+
2. **Explore approaches.** For non-trivial features, there may be multiple ways to solve the problem. Discuss trade-offs before committing to one direction — I may ask you to explore alternatives first.
|
|
1167
|
+
3. **Prove feasibility.** Make a small PR that solves the root of the problem — no optimizations, no UX polish. This lets me evaluate the impact on the library and give you early feedback if your approach conflicts with Svedit's design decisions.
|
|
1168
|
+
4. **Plan the finish.** Once feasibility is approved, outline the remaining steps and wait for another green light. Then we iterate together until it's ready to merge.
|
|
1169
|
+
|
|
1170
|
+
**Please don't work on a feature for a long time without checking in regularly.** I have a much lower tolerance for complexity than most developers, and I need to be able to digest changes in small pieces. Going off and making a large rewrite without involving me will likely be frustrating for both of us.
|
|
1171
|
+
|
|
1172
|
+
### Sponsorship
|
|
1084
1173
|
|
|
1085
|
-
|
|
1174
|
+
Another great way to help is to donate or sponsor the project, so I can buy more dedicated development time. Email me at michael@letsken.com.
|
|
1086
1175
|
|
|
1087
1176
|
## Beta version
|
|
1088
1177
|
|
package/dist/Node.svelte
CHANGED
|
@@ -1,53 +1,32 @@
|
|
|
1
1
|
<script>
|
|
2
2
|
import { getContext } from 'svelte';
|
|
3
|
-
import DefaultNodeGap from './NodeGap.svelte';
|
|
4
3
|
|
|
5
4
|
/** @import { NodeProps } from './types.d.ts'; */
|
|
6
5
|
|
|
7
6
|
const svedit = getContext('svedit');
|
|
8
|
-
let NodeGap = $derived(svedit.session.config.system_components?.NodeGap ?? DefaultNodeGap);
|
|
9
7
|
|
|
10
8
|
/** @type {NodeProps} */
|
|
11
9
|
let { path, children, tag = 'div', class: css_class, style = '', ...rest } = $props();
|
|
12
10
|
|
|
13
11
|
let node = $derived(svedit.session.get(path));
|
|
14
12
|
|
|
15
|
-
// NodeArrayProperty sets this context — its presence means we're in a node_array.
|
|
16
|
-
// Using context avoids expensive session.inspect() and session.get() calls
|
|
17
|
-
// that would create O(N) reactive subscriptions to the parent array.
|
|
18
13
|
const node_array_meta = getContext('node_array_meta');
|
|
19
|
-
|
|
20
|
-
let
|
|
21
|
-
let
|
|
22
|
-
let is_last_node_array_child = $derived(
|
|
23
|
-
is_inside_node_array && child_index === node_array_meta.length - 1
|
|
24
|
-
);
|
|
25
|
-
|
|
26
|
-
// Drives lazy anchor positioning for node gaps. Gaps are always in the
|
|
27
|
-
// DOM (stable structure for selection), but only anchor-positioned when
|
|
28
|
-
// near the viewport to avoid O(N) layout cost.
|
|
29
|
-
let is_near_viewport = $derived(
|
|
30
|
-
svedit.is_near_viewport?.(path) ?? true
|
|
31
|
-
);
|
|
14
|
+
let child_index = $derived(node_array_meta ? parseInt(String(path.at(-1)), 10) : -1);
|
|
15
|
+
let is_first = $derived(node_array_meta && child_index === 0);
|
|
16
|
+
let is_last = $derived(node_array_meta && child_index === node_array_meta.length - 1);
|
|
32
17
|
</script>
|
|
33
18
|
|
|
34
19
|
<svelte:element
|
|
35
20
|
id={node.id}
|
|
36
21
|
this={tag}
|
|
37
|
-
class={css_class}
|
|
22
|
+
class="{css_class}{is_first ? ' first' : ''}{is_last ? ' last' : ''}"
|
|
38
23
|
data-node-id={node.id}
|
|
39
24
|
data-path={path.join('.')}
|
|
40
25
|
data-type="node"
|
|
41
26
|
style="anchor-name: --{path.join('-')};{style}"
|
|
42
27
|
{...rest}
|
|
43
28
|
>
|
|
44
|
-
{#if svedit.editable && is_first_node_array_child}
|
|
45
|
-
<NodeGap {path} type="gap-before" positioned={is_near_viewport} />
|
|
46
|
-
{/if}
|
|
47
29
|
{@render children()}
|
|
48
|
-
{#if svedit.editable && is_inside_node_array}
|
|
49
|
-
<NodeGap {path} type="gap-after" last={is_last_node_array_child} positioned={is_near_viewport} />
|
|
50
|
-
{/if}
|
|
51
30
|
</svelte:element>
|
|
52
31
|
|
|
53
32
|
<style>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Node.svelte.d.ts","sourceRoot":"","sources":["../src/lib/Node.svelte.js"],"names":[],"mappings":";;;;;
|
|
1
|
+
{"version":3,"file":"Node.svelte.d.ts","sourceRoot":"","sources":["../src/lib/Node.svelte.js"],"names":[],"mappings":";;;;;AA8BA,yFAAmD"}
|
|
@@ -20,8 +20,6 @@
|
|
|
20
20
|
.map(/** @param {string} node_id */ (node_id) => svedit.session.get(node_id))
|
|
21
21
|
);
|
|
22
22
|
|
|
23
|
-
// Expose array metadata to child Node.svelte instances via context,
|
|
24
|
-
// avoiding expensive session.inspect() / session.get() calls per node.
|
|
25
23
|
setContext('node_array_meta', {
|
|
26
24
|
get length() { return nodes.length; }
|
|
27
25
|
});
|
|
@@ -52,9 +50,17 @@
|
|
|
52
50
|
<!-- Sibling (not child) of .empty-node-array so its .svedit-selectable
|
|
53
51
|
resolves anchor positioning against the shared containing block,
|
|
54
52
|
not the placeholder which inherits .node positioning styles. -->
|
|
55
|
-
<NodeGap
|
|
53
|
+
<NodeGap array_path={path} offset={0} count={0} empty />
|
|
56
54
|
{/if}
|
|
57
55
|
{#each nodes as node, index (index)}
|
|
56
|
+
{#if svedit.editable}
|
|
57
|
+
<NodeGap
|
|
58
|
+
array_path={path}
|
|
59
|
+
offset={index}
|
|
60
|
+
count={nodes.length}
|
|
61
|
+
positioned={svedit.is_near_viewport?.([...path, index]) ?? true}
|
|
62
|
+
/>
|
|
63
|
+
{/if}
|
|
58
64
|
{@const Component = svedit.session.config.node_components[snake_to_pascal(node.type)]}
|
|
59
65
|
{#if Component}
|
|
60
66
|
<Component path={[...path, index]} />
|
|
@@ -62,6 +68,14 @@
|
|
|
62
68
|
<UnknownNode path={[...path, index]} />
|
|
63
69
|
{/if}
|
|
64
70
|
{/each}
|
|
71
|
+
{#if svedit.editable && nodes.length > 0}
|
|
72
|
+
<NodeGap
|
|
73
|
+
array_path={path}
|
|
74
|
+
offset={nodes.length}
|
|
75
|
+
count={nodes.length}
|
|
76
|
+
positioned={svedit.is_near_viewport?.([...path, nodes.length - 1]) ?? true}
|
|
77
|
+
/>
|
|
78
|
+
{/if}
|
|
65
79
|
{#if svedit.editable && NodeGapMarkers}
|
|
66
80
|
<NodeGapMarkers {path} />
|
|
67
81
|
{/if}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NodeArrayProperty.svelte.d.ts","sourceRoot":"","sources":["../src/lib/NodeArrayProperty.svelte.js"],"names":[],"mappings":";;;;;
|
|
1
|
+
{"version":3,"file":"NodeArrayProperty.svelte.d.ts","sourceRoot":"","sources":["../src/lib/NodeArrayProperty.svelte.js"],"names":[],"mappings":";;;;;AAkEA,mHAAgE"}
|
package/dist/NodeGap.svelte
CHANGED
|
@@ -2,6 +2,11 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* Invisible keyboard caret selectable and gap hit area.
|
|
4
4
|
*
|
|
5
|
+
* Rendered as a sibling of Node elements inside NodeArrayProperty,
|
|
6
|
+
* interleaved between nodes in DOM order. This ensures:
|
|
7
|
+
* - Correct DOM order for native drag-to-select across nodes
|
|
8
|
+
* - No containing-block issues from transform/filter/will-change on nodes
|
|
9
|
+
*
|
|
5
10
|
* Always present in the DOM when editable (stable structure for
|
|
6
11
|
* selection anchoring, scrollTo, etc.). Anchor positioning is
|
|
7
12
|
* activated lazily via the `positioned` prop — only gaps near the
|
|
@@ -15,29 +20,37 @@
|
|
|
15
20
|
*
|
|
16
21
|
* Row/column detection uses var(--row, 1) with the * 99999 multiplier
|
|
17
22
|
* trick — no @container style() queries, works in all browsers.
|
|
18
|
-
*
|
|
19
|
-
* Node.svelte does NOT set position: relative, so the selectable's
|
|
20
|
-
* containing block is a higher ancestor that contains all sibling
|
|
21
|
-
* nodes, making cross-sibling anchor references valid.
|
|
22
23
|
*/
|
|
23
|
-
let {
|
|
24
|
+
let { array_path, offset, count, empty = false, positioned = true } = $props();
|
|
25
|
+
|
|
26
|
+
let is_first = $derived(offset === 0);
|
|
27
|
+
let is_last = $derived(offset === count);
|
|
28
|
+
let type = $derived(is_first ? 'gap-before' : 'gap-after');
|
|
24
29
|
|
|
25
30
|
let gap_style = $derived.by(() => {
|
|
26
|
-
const
|
|
27
|
-
const
|
|
28
|
-
const
|
|
29
|
-
|
|
31
|
+
const arr = array_path.join('-');
|
|
32
|
+
const prev_idx = offset - 1;
|
|
33
|
+
const pa = is_first ? `--${arr}-0` : `--${arr}-${prev_idx}`;
|
|
34
|
+
const next = `--${arr}-${offset}`;
|
|
35
|
+
const container = `--${arr}`;
|
|
36
|
+
return `--_pa:${pa};--_next:${next};--_container:${container}`;
|
|
30
37
|
});
|
|
31
38
|
|
|
32
|
-
let anchor_name = $derived
|
|
39
|
+
let anchor_name = $derived.by(() => {
|
|
40
|
+
const arr = array_path.join('-');
|
|
41
|
+
if (is_first) return `--g-${arr}-0-gap-before`;
|
|
42
|
+
return `--g-${arr}-${offset - 1}-gap-after`;
|
|
43
|
+
});
|
|
33
44
|
</script>
|
|
34
45
|
|
|
35
46
|
<div
|
|
36
47
|
class="node-gap {type}"
|
|
37
48
|
class:empty
|
|
38
|
-
class:last
|
|
49
|
+
class:last={is_last}
|
|
39
50
|
class:positioned
|
|
40
51
|
data-type={type}
|
|
52
|
+
data-gap-array-path={array_path.join('.')}
|
|
53
|
+
data-gap-offset={offset}
|
|
41
54
|
style={gap_style}
|
|
42
55
|
>
|
|
43
56
|
<div class="svedit-selectable" style="anchor-name:{anchor_name}"><br /></div>
|
|
@@ -46,10 +59,10 @@
|
|
|
46
59
|
|
|
47
60
|
<style>
|
|
48
61
|
.node-gap {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
62
|
+
display: contents;
|
|
63
|
+
/* The native browser caret briefly appears inside .svedit-selectable for one frame
|
|
64
|
+
before the model-driven NodeCaret renders at the correct edge position.
|
|
65
|
+
Suppressing it here avoids a flash of the native caret. */
|
|
53
66
|
caret-color: transparent;
|
|
54
67
|
}
|
|
55
68
|
|
|
@@ -58,9 +71,7 @@
|
|
|
58
71
|
/* ------------------------------------------------------------------ */
|
|
59
72
|
|
|
60
73
|
.node-gap:not(.positioned) .svedit-selectable {
|
|
61
|
-
|
|
62
|
-
contain-intrinsic-size: 0 0;
|
|
63
|
-
position: static;
|
|
74
|
+
position: absolute;
|
|
64
75
|
pointer-events: none;
|
|
65
76
|
width: 0;
|
|
66
77
|
height: 0;
|
|
@@ -73,8 +84,21 @@
|
|
|
73
84
|
|
|
74
85
|
/*
|
|
75
86
|
* Anchor references resolved from CSS variable names passed via
|
|
76
|
-
* inline style (--_pa, --_next, --_container).
|
|
77
|
-
* NodeGapMarkers — keeps JS minimal and anchor() in CSS.
|
|
87
|
+
* inline style (--_pa = parent anchor, --_next, --_container).
|
|
88
|
+
* Same pattern as NodeGapMarkers — keeps JS minimal and anchor() in CSS.
|
|
89
|
+
*
|
|
90
|
+
* --_pa references the anchor-name of the node this gap belongs to,
|
|
91
|
+
* allowing us to position relative to that node's edges.
|
|
92
|
+
*
|
|
93
|
+
* Edge gaps extend outward and clamp to the containing block edge
|
|
94
|
+
* (0px floor). This can overlap neighboring elements when the node
|
|
95
|
+
* array isn't alone in its parent. anchor() only sees the border
|
|
96
|
+
* box, so it can't detect margin, gap, or parent padding around
|
|
97
|
+
* the container. --node-caret-boundary lets consumers set an
|
|
98
|
+
* explicit clamp target (a parent element's anchor-name) so edge
|
|
99
|
+
* gaps stop at that boundary instead. --node-caret-boundary-x and
|
|
100
|
+
* --node-caret-boundary-y override per-axis, falling back to
|
|
101
|
+
* --node-caret-boundary when unset.
|
|
78
102
|
*/
|
|
79
103
|
.node-gap.positioned {
|
|
80
104
|
--_s-t: anchor(var(--_pa) top);
|
|
@@ -82,6 +106,10 @@
|
|
|
82
106
|
--_s-l: anchor(var(--_pa) left);
|
|
83
107
|
--_s-r: anchor(var(--_pa) right);
|
|
84
108
|
}
|
|
109
|
+
.positioned.gap-before:not(.empty) {
|
|
110
|
+
--_b-t: anchor(var(--node-caret-boundary-y, var(--node-caret-boundary, --_no-boundary)) top, 0px);
|
|
111
|
+
--_b-l: anchor(var(--node-caret-boundary-x, var(--node-caret-boundary, --_no-boundary)) left, 0px);
|
|
112
|
+
}
|
|
85
113
|
.positioned.gap-after:not(.last) {
|
|
86
114
|
--_n-t: anchor(var(--_next) top);
|
|
87
115
|
--_n-l: anchor(var(--_next) left);
|
|
@@ -93,6 +121,10 @@
|
|
|
93
121
|
--_c-b: anchor(var(--_container) bottom);
|
|
94
122
|
--_c-l: anchor(var(--_container) left);
|
|
95
123
|
--_c-r: anchor(var(--_container) right);
|
|
124
|
+
--_b-b: anchor(var(--node-caret-boundary-y, var(--node-caret-boundary, --_no-boundary)) bottom, 0px);
|
|
125
|
+
--_b-r: anchor(var(--node-caret-boundary-x, var(--node-caret-boundary, --_no-boundary)) right, 0px);
|
|
126
|
+
--_b-bt: anchor(var(--node-caret-boundary-y, var(--node-caret-boundary, --_no-boundary)) bottom, 99999px);
|
|
127
|
+
--_b-rl: anchor(var(--node-caret-boundary-x, var(--node-caret-boundary, --_no-boundary)) right, 99999px);
|
|
96
128
|
}
|
|
97
129
|
|
|
98
130
|
.positioned .svedit-selectable {
|
|
@@ -171,28 +203,33 @@
|
|
|
171
203
|
);
|
|
172
204
|
min-height: calc(var(--_gm) * var(--_C));
|
|
173
205
|
min-width: calc(var(--_gm) * var(--_R));
|
|
206
|
+
/* min-height: max(calc(var(--_gm) * var(--_C)), calc(anchor-size(var(--_pa) height, 100%) * var(--_R)));
|
|
207
|
+
min-width: max(calc(var(--_gm) * var(--_R)), calc(anchor-size(var(--_pa) width, 100%) * var(--_C))); */
|
|
174
208
|
}
|
|
175
209
|
|
|
176
|
-
/* After last node: col extends down, row extends right
|
|
210
|
+
/* After last node: col extends down, row extends right.
|
|
211
|
+
top also clamps to boundary_bottom - eg so that min-height
|
|
212
|
+
(which wins over bottom in overconstrained abs-pos) cannot
|
|
213
|
+
push the element past the boundary. */
|
|
177
214
|
.positioned.gap-after.last .svedit-selectable {
|
|
178
215
|
top: min(
|
|
179
|
-
calc(var(--_s-b) + var(--_R) * 99999px),
|
|
216
|
+
calc(min(var(--_s-b), calc(var(--_b-bt) - var(--_eg))) + var(--_R) * 99999px),
|
|
180
217
|
calc(var(--_s-t) + var(--_C) * 99999px)
|
|
181
218
|
);
|
|
182
219
|
bottom: min(
|
|
183
|
-
calc(var(--_s-b) - var(--_eg) + var(--_R) * 99999px),
|
|
220
|
+
calc(max(var(--_b-b), var(--_s-b) - var(--_eg)) + var(--_R) * 99999px),
|
|
184
221
|
calc(var(--_s-b) + var(--_C) * 99999px)
|
|
185
222
|
);
|
|
186
223
|
left: min(
|
|
187
224
|
calc(var(--_s-l) + var(--_R) * 99999px),
|
|
188
|
-
calc(var(--_s-r) + var(--_C) * 99999px),
|
|
225
|
+
calc(min(var(--_s-r), calc(var(--_b-rl) - var(--_eg))) + var(--_C) * 99999px),
|
|
189
226
|
calc(100% - var(--_eg) + var(--_C) * 99999px)
|
|
190
227
|
);
|
|
191
228
|
right: min(
|
|
192
229
|
calc(var(--_s-r) + var(--_R) * 99999px),
|
|
193
230
|
calc(
|
|
194
231
|
max(
|
|
195
|
-
|
|
232
|
+
var(--_b-r),
|
|
196
233
|
min(
|
|
197
234
|
calc(var(--_c-r) - var(--_eg)),
|
|
198
235
|
calc(var(--_s-r) - var(--_eg))
|
|
@@ -209,7 +246,7 @@
|
|
|
209
246
|
.positioned.gap-before:not(.empty) .svedit-selectable {
|
|
210
247
|
top: min(
|
|
211
248
|
calc(
|
|
212
|
-
max(
|
|
249
|
+
max(var(--_b-t), var(--_s-t) - var(--_eg))
|
|
213
250
|
+ var(--_R) * 99999px
|
|
214
251
|
),
|
|
215
252
|
calc(var(--_s-t) + var(--_C) * 99999px)
|
|
@@ -221,7 +258,7 @@
|
|
|
221
258
|
left: min(
|
|
222
259
|
calc(var(--_s-l) + var(--_R) * 99999px),
|
|
223
260
|
calc(
|
|
224
|
-
max(
|
|
261
|
+
max(var(--_b-l), var(--_s-l) - var(--_eg))
|
|
225
262
|
+ var(--_C) * 99999px
|
|
226
263
|
)
|
|
227
264
|
);
|
package/dist/NodeGap.svelte.d.ts
CHANGED
|
@@ -4,17 +4,17 @@ type NodeGap = {
|
|
|
4
4
|
$set?(props: Partial<$$ComponentProps>): void;
|
|
5
5
|
};
|
|
6
6
|
declare const NodeGap: import("svelte").Component<{
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
array_path: any;
|
|
8
|
+
offset: any;
|
|
9
|
+
count: any;
|
|
9
10
|
empty?: boolean;
|
|
10
|
-
last?: boolean;
|
|
11
11
|
positioned?: boolean;
|
|
12
12
|
}, {}, "">;
|
|
13
13
|
type $$ComponentProps = {
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
array_path: any;
|
|
15
|
+
offset: any;
|
|
16
|
+
count: any;
|
|
16
17
|
empty?: boolean;
|
|
17
|
-
last?: boolean;
|
|
18
18
|
positioned?: boolean;
|
|
19
19
|
};
|
|
20
20
|
//# sourceMappingURL=NodeGap.svelte.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NodeGap.svelte.d.ts","sourceRoot":"","sources":["../src/lib/NodeGap.svelte.js"],"names":[],"mappings":";;;;;
|
|
1
|
+
{"version":3,"file":"NodeGap.svelte.d.ts","sourceRoot":"","sources":["../src/lib/NodeGap.svelte.js"],"names":[],"mappings":";;;;;AAyDA;gBA/BgC,GAAG;YAAU,GAAG;WAAS,GAAG;YAAU,OAAO;iBAAe,OAAO;WA+B7C;wBA/BpC;IAAE,UAAU,EAAE,GAAG,CAAC;IAAC,MAAM,EAAE,GAAG,CAAC;IAAC,KAAK,EAAE,GAAG,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAC;IAAC,UAAU,CAAC,EAAE,OAAO,CAAA;CAAE"}
|
|
@@ -66,6 +66,12 @@
|
|
|
66
66
|
* --node-caret-blink-duration
|
|
67
67
|
* --node-caret-animation
|
|
68
68
|
* --node-caret-row-inline-position
|
|
69
|
+
* --node-caret-boundary (anchor-name of a parent element; edge
|
|
70
|
+
* gaps clamp to its edges instead of 0px.
|
|
71
|
+
* Prevents overlap when the node array has
|
|
72
|
+
* neighbors. See NodeGap.svelte for details.)
|
|
73
|
+
* --node-caret-boundary-x (per-axis override; clamps left/right only)
|
|
74
|
+
* --node-caret-boundary-y (per-axis override; clamps top/bottom only)
|
|
69
75
|
*
|
|
70
76
|
* Row/column detection uses var(--row, 1) with the * 99999 multiplier
|
|
71
77
|
* trick throughout. Shorthand:
|
|
@@ -262,9 +268,11 @@
|
|
|
262
268
|
|
|
263
269
|
/* Edge first: column = above first node, row = left of first node */
|
|
264
270
|
.gap-edge.first {
|
|
271
|
+
--_b-t: anchor(var(--node-caret-boundary-y, var(--node-caret-boundary, --_no-boundary)) top, 0px);
|
|
272
|
+
--_b-l: anchor(var(--node-caret-boundary-x, var(--node-caret-boundary, --_no-boundary)) left, 0px);
|
|
265
273
|
top: min(
|
|
266
274
|
calc(anchor(var(--_a) top) + var(--_C) * 99999px),
|
|
267
|
-
calc(max(
|
|
275
|
+
calc(max(var(--_b-t), calc(anchor(var(--_a) top) - var(--_gm))) + var(--_R) * 99999px)
|
|
268
276
|
);
|
|
269
277
|
bottom: min(
|
|
270
278
|
calc(anchor(var(--_a) bottom) + var(--_C) * 99999px),
|
|
@@ -272,7 +280,7 @@
|
|
|
272
280
|
);
|
|
273
281
|
left: min(
|
|
274
282
|
calc(anchor(var(--_a) left) + var(--_R) * 99999px),
|
|
275
|
-
calc(max(
|
|
283
|
+
calc(max(var(--_b-l), calc(anchor(var(--_a) left) - var(--_gm))) + var(--_C) * 99999px)
|
|
276
284
|
);
|
|
277
285
|
right: min(
|
|
278
286
|
calc(anchor(var(--_a) right) + var(--_R) * 99999px),
|
|
@@ -280,23 +288,40 @@
|
|
|
280
288
|
);
|
|
281
289
|
}
|
|
282
290
|
|
|
283
|
-
/* Edge last: column = below last node, row = right of last node
|
|
291
|
+
/* Edge last: column = below last node, row = right of last node.
|
|
292
|
+
top/left also clamp to boundary - gm so that min-height/min-width
|
|
293
|
+
(which win over bottom/right in overconstrained abs-pos) cannot
|
|
294
|
+
push the element past the boundary. */
|
|
284
295
|
.gap-edge.last {
|
|
296
|
+
--_b-b: anchor(var(--node-caret-boundary-y, var(--node-caret-boundary, --_no-boundary)) bottom, 0px);
|
|
297
|
+
--_b-r: anchor(var(--node-caret-boundary-x, var(--node-caret-boundary, --_no-boundary)) right, 0px);
|
|
298
|
+
--_b-bt: anchor(var(--node-caret-boundary-y, var(--node-caret-boundary, --_no-boundary)) bottom, 99999px);
|
|
299
|
+
--_b-rl: anchor(var(--node-caret-boundary-x, var(--node-caret-boundary, --_no-boundary)) right, 99999px);
|
|
285
300
|
top: min(
|
|
286
301
|
calc(anchor(var(--_a) top) + var(--_C) * 99999px),
|
|
287
|
-
calc(
|
|
302
|
+
calc(
|
|
303
|
+
min(
|
|
304
|
+
anchor(var(--_a) bottom),
|
|
305
|
+
calc(var(--_b-bt) - var(--_gm))
|
|
306
|
+
) + var(--_R) * 99999px
|
|
307
|
+
)
|
|
288
308
|
);
|
|
289
309
|
bottom: min(
|
|
290
310
|
calc(anchor(var(--_a) bottom) + var(--_C) * 99999px),
|
|
291
|
-
calc(anchor(var(--_a) bottom) - var(--_gm) + var(--_R) * 99999px)
|
|
311
|
+
calc(max(var(--_b-b), calc(anchor(var(--_a) bottom) - var(--_gm))) + var(--_R) * 99999px)
|
|
292
312
|
);
|
|
293
313
|
left: min(
|
|
294
314
|
calc(anchor(var(--_a) left) + var(--_R) * 99999px),
|
|
295
|
-
calc(
|
|
315
|
+
calc(
|
|
316
|
+
min(
|
|
317
|
+
anchor(var(--_a) right),
|
|
318
|
+
calc(var(--_b-rl) - var(--_gm))
|
|
319
|
+
) + var(--_C) * 99999px
|
|
320
|
+
),
|
|
296
321
|
calc(100% - var(--_gm) + var(--_C) * 99999px)
|
|
297
322
|
);
|
|
298
323
|
right: max(
|
|
299
|
-
calc(
|
|
324
|
+
calc(var(--_b-r) + var(--_C) * -99999px),
|
|
300
325
|
calc(anchor(var(--_a) right) + var(--_R) * -99999px),
|
|
301
326
|
calc(anchor(var(--_a) right) - var(--_gm) + var(--_C) * -99999px),
|
|
302
327
|
calc(anchor(var(--_c) right) + var(--_C) * -99999px)
|
|
@@ -314,6 +339,7 @@
|
|
|
314
339
|
left: min(
|
|
315
340
|
calc(anchor(var(--_a) left) + var(--_R) * 99999px),
|
|
316
341
|
calc(anchor(var(--_a) right) + var(--_C) * 99999px),
|
|
342
|
+
calc(var(--_b-rl) - var(--_gm) + var(--_C) * 99999px),
|
|
317
343
|
calc(
|
|
318
344
|
anchor(var(--_a) right)
|
|
319
345
|
+ (max(0px, anchor(var(--_s) left) - anchor(var(--_f) right))) / 2
|
|
@@ -341,7 +367,7 @@
|
|
|
341
367
|
);
|
|
342
368
|
right: max(
|
|
343
369
|
calc(anchor(var(--_a) right) + var(--_R) * -99999px),
|
|
344
|
-
calc(
|
|
370
|
+
calc(var(--_b-r) + var(--_C) * -99999px),
|
|
345
371
|
calc(
|
|
346
372
|
anchor(var(--_a) right)
|
|
347
373
|
- (
|
|
@@ -450,7 +476,7 @@
|
|
|
450
476
|
outline: 0.1px solid green;
|
|
451
477
|
}
|
|
452
478
|
.gap-marker {
|
|
453
|
-
outline:
|
|
479
|
+
outline: 1px solid blue;
|
|
454
480
|
outline-offset: 0.5px;
|
|
455
481
|
} */
|
|
456
|
-
</style>
|
|
482
|
+
</style>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NodeGapMarkers.svelte.d.ts","sourceRoot":"","sources":["../src/lib/NodeGapMarkers.svelte.js"],"names":[],"mappings":";;;;;
|
|
1
|
+
{"version":3,"file":"NodeGapMarkers.svelte.d.ts","sourceRoot":"","sources":["../src/lib/NodeGapMarkers.svelte.js"],"names":[],"mappings":";;;;;AA0CA;UArB0B,GAAG;WAqBgC;wBArB3C;IAAE,IAAI,EAAE,GAAG,CAAA;CAAE"}
|