-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy patheditor.html
More file actions
145 lines (137 loc) · 6.9 KB
/
Copy patheditor.html
File metadata and controls
145 lines (137 loc) · 6.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover" />
<meta name="theme-color" content="#ffffff" />
<title>FUTO Notes Editor</title>
<!-- Legacy Android System WebView runtime shim (github#8). The editor bundle
targets ES2020 (syntax floor: Chromium 80), but Svelte 5's client runtime
calls String.prototype.replaceAll (Chromium 85), so without this the whole
app throws on Chromium 80-84 and the editor never mounts. A classic (non-
module) script runs before the deferred module bundle. Engines below the
ES2020 syntax floor are caught natively (see Android EditorWebView). -->
<script>
if (!String.prototype.replaceAll) {
String.prototype.replaceAll = function (search, replacement) {
if (Object.prototype.toString.call(search) === '[object RegExp]') {
if (!search.global) {
throw new TypeError('replaceAll must be called with a global RegExp');
}
return String.prototype.replace.call(this, search, replacement);
}
var escaped = String(search).replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
return String.prototype.replace.call(this, new RegExp(escaped, 'g'), replacement);
};
}
</script>
<style>
/* ------------------------------------------------------------------ *
* Embedded editor layout for the native-iOS WKWebView host.
*
* Goals (all observed on a real iPhone):
* 1. Comfortable horizontal margins (+ safe-area insets for notch /
* landscape).
* 2. SCROLLING that actually works. We use CodeMirror 6's NATIVE
* fixed-height mode: give .cm-editor a definite (viewport) height and
* let its .cm-scroller scroll internally. (The earlier "let the page
* scroll" approach with height:auto + overflow:visible did NOT scroll
* — CM is built to scroll inside .cm-scroller when the editor has a
* fixed height.)
* 3. An empty note must still be tappable: the contenteditable
* (.cm-content) fills the scroller so a tap anywhere focuses the
* editor (popping the keyboard).
*
* NOTE ON SPECIFICITY: MarkdownEditor.svelte installs an inline
* EditorView.theme with `&{height:auto}` and `.cm-content{padding:0}`.
* That CSS is unlayered and injected by CodeMirror. The rules below are
* also unlayered (plain <style>); we use !important to beat CM's theme.
* ------------------------------------------------------------------ */
:root {
--futo-edit-pad-x: 18px;
/* Trailing space so the last lines can scroll clear of the keyboard. */
--futo-edit-pad-bottom: max(40vh, 280px);
}
html, body {
height: 100%;
margin: 0;
padding: 0;
overflow: hidden; /* the page never scrolls; .cm-scroller does */
overscroll-behavior: none;
/* Both native hosts render this page in a TRANSPARENT web view
* (iOS: isOpaque=false + .clear, Android: setBackgroundColor(TRANSPARENT))
* and paint the app background behind it (iOS Theme.background, Android
* Compose surface). app.css's @layer base would otherwise paint the web
* palette's --color-bg over it — dark #0A0A0A vs the hosts' dark
* surfaces — so the editor pane visibly mismatches the surrounding
* native UI in dark mode. Unlayered, so it beats the layered rule. */
background: transparent;
}
/* Legacy-WebView text-color fallback (github#8). Non-updated Android 8-10
* system WebViews predate @layer (Chromium 99) and drop EVERY rule inside
* Tailwind's layers — including the @theme light tokens and the
* body/.cm-editor color rules — leaving UA-black text over the hosts'
* surface (invisible in dark mode). The [data-theme='dark'] variable
* overrides in theme.css stay unlayered, so var() still resolves there;
* the literal fallback covers light mode, where the @layer'd token is
* lost. Inherited from html, so it never outranks the layered rules that
* modern engines apply on body/.cm-editor. The hex must equal theme.css's
* light --color-text (locked by the legacy-WebView tests in
* tests/editor-embed-bridge.spec.ts). */
html {
color: var(--color-text, #0f0f0f);
}
#editor {
position: absolute;
inset: 0; /* fill the web view: a DEFINITE height */
}
/* MarkdownEditor.svelte mounts a single wrapper <div> inside #editor;
* carry #editor's definite height down through it so .cm-editor can
* resolve a percentage height. */
#editor > :first-child {
height: 100% !important;
}
/* Fixed height enables CM's internal scroller. We anchor to a definite
* height CHAIN (#editor is absolute inset:0) rather than viewport units:
* Android System WebView resolves 100dvh/100vh to 0 here (while
* innerHeight/clientHeight are correct), collapsing the editor to 0px and
* painting blank. 100% off the definite chain works on both WKWebView and
* Android WebView. */
.cm-editor {
height: 100% !important;
}
/* CM's own scroller is the scroll container (vertical), with momentum.
* overscroll-behavior:contain keeps the native rubber-band BOUNCE at the
* top/bottom (iOS users expect it; its absence reads as "stuck") while still
* preventing scroll from chaining out to the host web view. (We previously
* used `none` to suppress bounce for a scroll-jump guard that wrote scrollTop
* mid-scroll; that guard is gone — the height map is warmed up front instead,
* see $lib/heightMapWarm.ts — so bounce is back.) */
.cm-scroller {
overflow-y: auto !important;
-webkit-overflow-scrolling: touch !important;
overscroll-behavior: contain !important;
}
/* The contenteditable surface:
* - horizontal gutters (+ safe-area) so text isn't flush to the edge,
* - min-height fills the scroller so an EMPTY note is fully tappable,
* - bottom padding lifts the last lines above the keyboard. */
.cm-content {
padding-left: calc(var(--futo-edit-pad-x) + env(safe-area-inset-left)) !important;
padding-right: calc(var(--futo-edit-pad-x) + env(safe-area-inset-right)) !important;
padding-top: 14px !important;
padding-bottom: var(--futo-edit-pad-bottom) !important;
box-sizing: border-box !important;
/* Fill the scroller so an EMPTY note is fully tappable. The definite
* height chain above (#editor → wrapper → .cm-editor → .cm-scroller)
* gives the scroller a resolvable height, so 100% no longer collapses —
* and unlike 100dvh it isn't zeroed by Android WebView. */
min-height: 100% !important;
}
</style>
</head>
<body>
<div id="editor"></div>
<script type="module" src="/src/editor-embed/main.ts"></script>
</body>
</html>