@jsenv/navi 0.29.52 → 0.29.53
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/dist/jsenv_navi.js +375 -140
- package/dist/jsenv_navi.js.map +36 -22
- package/dist/jsenv_navi_side_effects.js +131 -12
- package/dist/jsenv_navi_side_effects.js.map +4 -2
- package/docs/AI_INSTRUCTIONS.md +38 -0
- package/docs/MOBILE_LAYOUT_PITFALLS.md +2 -2
- package/docs/actions.md +3 -1
- package/docs/create_and_edit.md +3 -1
- package/docs/css_architecture.md +10 -8
- package/docs/error_handling.md +174 -0
- package/docs/navigation.md +27 -6
- package/docs/safe_area.md +161 -0
- package/docs/scroll.md +10 -5
- package/package.json +1 -1
|
@@ -194,6 +194,120 @@ const smallTouchScreenSignal = computed(() => {
|
|
|
194
194
|
return false;
|
|
195
195
|
});
|
|
196
196
|
|
|
197
|
+
/**
|
|
198
|
+
* The part of the window an app actually has, in two levels.
|
|
199
|
+
*
|
|
200
|
+
* Two, and not one, for a reason worth stating up front: a fixed bar is one of
|
|
201
|
+
* the things that reduce the free region, so it cannot ALSO be placed against
|
|
202
|
+
* that region — it would push itself off the edge it is pinned to. What is
|
|
203
|
+
* anchored and what is anchored-inside are two different rectangles.
|
|
204
|
+
*
|
|
205
|
+
* 1. `--navi-app-inset-{top,right,bottom,left}` — from the window's edges to
|
|
206
|
+
* the app's own rectangle. Whatever is pinned to an edge (a fixed bar, a
|
|
207
|
+
* side panel, a popup aimed at a corner) is pinned to THAT, so an app
|
|
208
|
+
* pretending to be a 600px handheld inside a 1500px window stays one
|
|
209
|
+
* rectangle instead of a column with its furniture spread across the glass.
|
|
210
|
+
*
|
|
211
|
+
* 2. `--navi-safe-area-inset-{top,right,bottom,left}` — from the window's edges
|
|
212
|
+
* to the band left free INSIDE that rectangle. Whatever flows, scrolls, or
|
|
213
|
+
* gets painted keeps to it.
|
|
214
|
+
*
|
|
215
|
+
* Level 2 is a sum, and the contract for taking part in it is only "publish
|
|
216
|
+
* what you take on one edge": the device's own notch (`env(safe-area-inset-*)`,
|
|
217
|
+
* which is the browser's version of this very idea), the fixed bars
|
|
218
|
+
* (fixed_bar_space.js), and anything an app adds. That is the point of naming
|
|
219
|
+
* it at all — a component that must stay clear of what covers the screen reads
|
|
220
|
+
* ONE set of numbers, and never has to learn what is covering it.
|
|
221
|
+
*
|
|
222
|
+
* `max()` between the notch and the bars rather than a sum: a bar pinned to an
|
|
223
|
+
* edge already reaches under the notch and counts it in its own size (see
|
|
224
|
+
* fixed_bar.jsx), so adding both would reserve it twice.
|
|
225
|
+
*
|
|
226
|
+
* Sizes only, not placement, for the time being — see "Current limitations" in
|
|
227
|
+
* docs/css_architecture.md.
|
|
228
|
+
*/
|
|
229
|
+
|
|
230
|
+
const SAFE_AREA_CSS = /* css */ `
|
|
231
|
+
@layer navi {
|
|
232
|
+
:root {
|
|
233
|
+
/* The room each kind of furniture takes, declared here at zero and
|
|
234
|
+
written by whoever takes it. A slot rather than a value: the sum below
|
|
235
|
+
has to be readable whether or not the app ever mounts a fixed bar. */
|
|
236
|
+
--navi-fixed-bar-space-top: 0px;
|
|
237
|
+
--navi-fixed-bar-space-right: 0px;
|
|
238
|
+
--navi-fixed-bar-space-bottom: 0px;
|
|
239
|
+
--navi-fixed-bar-space-left: 0px;
|
|
240
|
+
|
|
241
|
+
/* Level 1. Centered bands, so that declaring one ceiling
|
|
242
|
+
(--navi-app-max-width) is all an app has to do to be a narrow screen in
|
|
243
|
+
a wide window; an app that wants them uneven writes these directly. */
|
|
244
|
+
--navi-app-inset-top: max(
|
|
245
|
+
0px,
|
|
246
|
+
(var(--navi-vvh) - var(--navi-app-max-height, var(--navi-vvh))) / 2
|
|
247
|
+
);
|
|
248
|
+
--navi-app-inset-bottom: var(--navi-app-inset-top);
|
|
249
|
+
--navi-app-inset-left: max(
|
|
250
|
+
0px,
|
|
251
|
+
(var(--navi-vvw) - var(--navi-app-max-width, var(--navi-vvw))) / 2
|
|
252
|
+
);
|
|
253
|
+
--navi-app-inset-right: var(--navi-app-inset-left);
|
|
254
|
+
|
|
255
|
+
/* Level 2. */
|
|
256
|
+
--navi-safe-area-inset-top: calc(
|
|
257
|
+
var(--navi-app-inset-top) +
|
|
258
|
+
max(env(safe-area-inset-top), var(--navi-fixed-bar-space-top))
|
|
259
|
+
);
|
|
260
|
+
--navi-safe-area-inset-right: calc(
|
|
261
|
+
var(--navi-app-inset-right) +
|
|
262
|
+
max(env(safe-area-inset-right), var(--navi-fixed-bar-space-right))
|
|
263
|
+
);
|
|
264
|
+
--navi-safe-area-inset-bottom: calc(
|
|
265
|
+
var(--navi-app-inset-bottom) +
|
|
266
|
+
max(env(safe-area-inset-bottom), var(--navi-fixed-bar-space-bottom))
|
|
267
|
+
);
|
|
268
|
+
--navi-safe-area-inset-left: calc(
|
|
269
|
+
var(--navi-app-inset-left) +
|
|
270
|
+
max(env(safe-area-inset-left), var(--navi-fixed-bar-space-left))
|
|
271
|
+
);
|
|
272
|
+
|
|
273
|
+
/* The document is the scrollport in the common case, and something the
|
|
274
|
+
browser scrolls to — an anchor, a focused field, a restored position —
|
|
275
|
+
landing under a bar is never what anyone wants. */
|
|
276
|
+
scroll-padding-top: var(--navi-safe-area-inset-top);
|
|
277
|
+
scroll-padding-right: var(--navi-safe-area-inset-right);
|
|
278
|
+
scroll-padding-bottom: var(--navi-safe-area-inset-bottom);
|
|
279
|
+
scroll-padding-left: var(--navi-safe-area-inset-left);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/* Put this on whatever scrolls under the furniture.
|
|
283
|
+
|
|
284
|
+
There are TWO rooms to give back, and forgetting the second one is the
|
|
285
|
+
classic bug:
|
|
286
|
+
|
|
287
|
+
- padding, so the end of the content can be scrolled out from under it.
|
|
288
|
+
Without it the last screenful stays covered, unreachable.
|
|
289
|
+
- scroll-padding, so anything the browser scrolls TO lands in front of it
|
|
290
|
+
rather than under. The padding above does not help here: it moves the
|
|
291
|
+
content, not the place the browser scrolls the target to.
|
|
292
|
+
|
|
293
|
+
Marked by the app rather than picked by navi: which element scrolls is
|
|
294
|
+
the app's business, and an app with more than one would have to fight a
|
|
295
|
+
component that chose for it. An app is free to read the variables itself
|
|
296
|
+
instead. */
|
|
297
|
+
[data-navi-safe-area] {
|
|
298
|
+
padding-top: var(--navi-safe-area-inset-top);
|
|
299
|
+
padding-right: var(--navi-safe-area-inset-right);
|
|
300
|
+
padding-bottom: var(--navi-safe-area-inset-bottom);
|
|
301
|
+
padding-left: var(--navi-safe-area-inset-left);
|
|
302
|
+
|
|
303
|
+
scroll-padding-top: var(--navi-safe-area-inset-top);
|
|
304
|
+
scroll-padding-right: var(--navi-safe-area-inset-right);
|
|
305
|
+
scroll-padding-bottom: var(--navi-safe-area-inset-bottom);
|
|
306
|
+
scroll-padding-left: var(--navi-safe-area-inset-left);
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
`;
|
|
310
|
+
|
|
197
311
|
installImportMetaCssBuild(import.meta);/**
|
|
198
312
|
* Regroup CSS vars that makes sense to share across all navi components.
|
|
199
313
|
*/
|
|
@@ -214,8 +328,9 @@ const css = /* css */`
|
|
|
214
328
|
|
|
215
329
|
/* What navi treats as "the screen" when it sizes something that escapes
|
|
216
330
|
normal flow (a dialog in the top layer, a popover, anything built on
|
|
217
|
-
them)
|
|
218
|
-
|
|
331
|
+
them): the app's own rectangle, which is the visual viewport minus the
|
|
332
|
+
bands an app asks for. An app that never spans the whole window says so
|
|
333
|
+
ONCE, without ever naming a component:
|
|
219
334
|
|
|
220
335
|
:root {
|
|
221
336
|
--navi-app-max-width: 600px;
|
|
@@ -235,17 +350,19 @@ const css = /* css */`
|
|
|
235
350
|
from it as before. A single popup that genuinely needs more can still
|
|
236
351
|
raise its own maxWidth/maxHeight prop.
|
|
237
352
|
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
docs/css_architecture.md. */
|
|
242
|
-
--navi-app-width:
|
|
243
|
-
var(--navi-vvw)
|
|
244
|
-
|
|
353
|
+
Read from the insets rather than as a min() of its own so that the
|
|
354
|
+
width and the placement come from ONE description of where the app is
|
|
355
|
+
(see layout/safe_area.js). Placement does not follow yet everywhere —
|
|
356
|
+
see "Current limitations" in docs/css_architecture.md. */
|
|
357
|
+
--navi-app-width: calc(
|
|
358
|
+
var(--navi-vvw) - var(--navi-app-inset-left) - var(
|
|
359
|
+
--navi-app-inset-right
|
|
360
|
+
)
|
|
245
361
|
);
|
|
246
|
-
--navi-app-height:
|
|
247
|
-
var(--navi-vvh)
|
|
248
|
-
|
|
362
|
+
--navi-app-height: calc(
|
|
363
|
+
var(--navi-vvh) - var(--navi-app-inset-top) - var(
|
|
364
|
+
--navi-app-inset-bottom
|
|
365
|
+
)
|
|
249
366
|
);
|
|
250
367
|
|
|
251
368
|
--navi-focus-outline-width: 2px;
|
|
@@ -385,6 +502,8 @@ const css = /* css */`
|
|
|
385
502
|
}
|
|
386
503
|
}
|
|
387
504
|
|
|
505
|
+
${SAFE_AREA_CSS}
|
|
506
|
+
|
|
388
507
|
/* Hidden appearance */
|
|
389
508
|
input[navi-visually-hidden],
|
|
390
509
|
button[navi-visually-hidden],
|