@jsenv/navi 0.29.8 → 0.29.9
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 +468 -231
- package/dist/jsenv_navi.js.map +38 -23
- package/package.json +1 -1
package/dist/jsenv_navi.js
CHANGED
|
@@ -51959,25 +51959,30 @@ installImportMetaCssBuild(import.meta);/**
|
|
|
51959
51959
|
* A value one steps through, one press at a time: what is chosen sits between
|
|
51960
51960
|
* the way back and the way on, and the two of them are the whole control.
|
|
51961
51961
|
*
|
|
51962
|
-
*
|
|
51963
|
-
* one
|
|
51964
|
-
*
|
|
51965
|
-
*
|
|
51962
|
+
* `Spin` knows nothing about what it steps through. It is handed how to move
|
|
51963
|
+
* one step (`valueAtStep`), how to tell two values apart (`compareValues`) and
|
|
51964
|
+
* what to write for one (`renderValue`); everything else — the frame, the two
|
|
51965
|
+
* ways out, the ends one cannot go past, the value a form carries — is the
|
|
51966
|
+
* same whatever the value is. `DaySpin` and `NumberSpin` at the bottom are two
|
|
51967
|
+
* of those answers, and a caller can write a third.
|
|
51968
|
+
*
|
|
51969
|
+
* The middle is one of two things, and that is the only real fork here:
|
|
51970
|
+
*
|
|
51971
|
+
* - a value one PICKS (`DaySpin`): a headless picker holds it, pressing the
|
|
51972
|
+
* middle opens it, and the three slides of a looping container show the one
|
|
51973
|
+
* before, this one and the one after — a window over a row with no end.
|
|
51974
|
+
* - a value one TYPES (`editable`, `NumberSpin`): the middle IS the field.
|
|
51975
|
+
* Nothing travels — one cannot slide what is being typed into — and the
|
|
51976
|
+
* arrows step the value where the caret already is.
|
|
51966
51977
|
*
|
|
51967
51978
|
* A picker, so it lives here: what one presses in the middle IS a picker, and
|
|
51968
51979
|
* the stepping is a way of showing it. It is headless and behind the three
|
|
51969
51980
|
* slides — there is one value being chosen, so there is one picker for it.
|
|
51970
51981
|
*
|
|
51971
|
-
*
|
|
51972
|
-
*
|
|
51973
|
-
*
|
|
51974
|
-
*
|
|
51975
|
-
*
|
|
51976
|
-
* Two things take the keyboard and no more: the container (arrows step,
|
|
51977
|
-
* Enter/Space open the picker) and the two chevrons. What is in the middle is
|
|
51978
|
-
* not a control — a click on the container opens the picker by command — which
|
|
51979
|
-
* is what keeps the focus where the travel happens instead of moving it into a
|
|
51980
|
-
* slide that is about to leave.
|
|
51982
|
+
* Two things take the keyboard and no more: the middle (the container in the
|
|
51983
|
+
* picking case, the field in the typing one) and nothing else — the chevrons
|
|
51984
|
+
* refuse it on purpose, which is what keeps the focus where the travel happens
|
|
51985
|
+
* instead of moving it into a slide that is about to leave.
|
|
51981
51986
|
*/
|
|
51982
51987
|
const css$p = /* css */`
|
|
51983
51988
|
@layer navi {
|
|
@@ -51991,7 +51996,7 @@ const css$p = /* css */`
|
|
|
51991
51996
|
|
|
51992
51997
|
.navi_picker_spin {
|
|
51993
51998
|
/* The padding is written on what is inside the box rather than on the box
|
|
51994
|
-
— the
|
|
51999
|
+
— the value takes all four sides, the two chevrons only the vertical ones
|
|
51995
52000
|
— so the four sides are resolved once here, in the side-then-axis-then
|
|
51996
52001
|
-shorthand order a Box resolves them in. What writes them: the padding
|
|
51997
52002
|
props, through PICKER_SPIN_STYLE_CSS_VARS below. */
|
|
@@ -52025,7 +52030,7 @@ const css$p = /* css */`
|
|
|
52025
52030
|
);
|
|
52026
52031
|
/* What the loading outline is drawn around. */
|
|
52027
52032
|
position: relative;
|
|
52028
|
-
/* Written in the control font, like the picker it wraps: the
|
|
52033
|
+
/* Written in the control font, like the picker it wraps: the value and its
|
|
52029
52034
|
two chevrons are a control, not running text. */
|
|
52030
52035
|
font-size: var(--navi-control-font-size);
|
|
52031
52036
|
font-family: var(--navi-control-font-family);
|
|
@@ -52043,16 +52048,19 @@ const css$p = /* css */`
|
|
|
52043
52048
|
outline-color: var(--navi-focus-outline-color);
|
|
52044
52049
|
outline-offset: 0px;
|
|
52045
52050
|
}
|
|
52046
|
-
/* The
|
|
52047
|
-
fills it, so its own
|
|
52048
|
-
two rings that close together read as a mistake. Same offer a
|
|
52049
|
-
popover answer (data-focus-outline-delegate, see
|
|
52050
|
-
the same reply — the delegate stands down
|
|
52051
|
+
/* The middle holds the keyboard, and this box wears its ring: whatever is in
|
|
52052
|
+
there fills it, so a ring of its own would be drawn a pixel inside this
|
|
52053
|
+
border and two rings that close together read as a mistake. Same offer a
|
|
52054
|
+
dialog and a popover answer (data-focus-outline-delegate, see
|
|
52055
|
+
slide_container.jsx), and the same reply — the delegate stands down; a
|
|
52056
|
+
field says it with an outline of zero width instead (see Spin's own
|
|
52057
|
+
outlineWidth below).
|
|
52051
52058
|
Said on this box too (the first selector): nothing focuses it for real —
|
|
52052
|
-
it is the
|
|
52059
|
+
it is the middle that takes the keyboard — but it is where the ring is
|
|
52053
52060
|
drawn, so a demo can hold it there and show what it looks like. */
|
|
52054
52061
|
.navi_picker_spin[data-focus-visible],
|
|
52055
|
-
.navi_picker_spin:has([data-focus-outline-delegate][data-focus-visible])
|
|
52062
|
+
.navi_picker_spin:has([data-focus-outline-delegate][data-focus-visible]),
|
|
52063
|
+
.navi_picker_spin:has(.navi_input[data-focus-visible]) {
|
|
52056
52064
|
outline-style: solid;
|
|
52057
52065
|
}
|
|
52058
52066
|
.navi_picker_spin [data-focus-outline-delegate] {
|
|
@@ -52103,6 +52111,14 @@ const css$p = /* css */`
|
|
|
52103
52111
|
width: min(100%, var(--picker-spin-picker-width, 12ch));
|
|
52104
52112
|
translate: -50% 0;
|
|
52105
52113
|
}
|
|
52114
|
+
/* A middle one types into is the field itself: it takes the whole room
|
|
52115
|
+
between the chevrons rather than sitting in the centre of it, so the
|
|
52116
|
+
caret is where the value is and a click anywhere in the middle lands in
|
|
52117
|
+
the field. */
|
|
52118
|
+
.navi_picker_spin_middle > .navi_input {
|
|
52119
|
+
min-width: 0;
|
|
52120
|
+
flex: 1 1 auto;
|
|
52121
|
+
}
|
|
52106
52122
|
/* Where the padding lands: all four sides on the value, the two vertical
|
|
52107
52123
|
ones on the chevrons below — the same number above and below is what makes
|
|
52108
52124
|
the three one line rather than three boxes, while sideways it is the room
|
|
@@ -52128,9 +52144,9 @@ const css$p = /* css */`
|
|
|
52128
52144
|
.navi_picker_spin[data-disabled] [data-slide-container] {
|
|
52129
52145
|
cursor: default;
|
|
52130
52146
|
}
|
|
52131
|
-
/* Kept inside its own slide: the three
|
|
52132
|
-
sticking out would be written across the two beside it. A
|
|
52133
|
-
the box simply wraps — the box grows, and the words are all there; say
|
|
52147
|
+
/* Kept inside its own slide: the three values share one cell, so anything
|
|
52148
|
+
sticking out would be written across the two beside it. A value too long
|
|
52149
|
+
for the box simply wraps — the box grows, and the words are all there; say
|
|
52134
52150
|
maxLines to cut it instead, which the text itself knows how to do. */
|
|
52135
52151
|
.navi_picker_spin [data-slide] > * {
|
|
52136
52152
|
max-width: 100%;
|
|
@@ -52206,53 +52222,73 @@ const css$p = /* css */`
|
|
|
52206
52222
|
|
|
52207
52223
|
/**
|
|
52208
52224
|
* @type {import("ignore:preact").FunctionComponent<{
|
|
52209
|
-
* value?:
|
|
52210
|
-
* defaultValue?:
|
|
52211
|
-
* signal?: import("@preact/signals").Signal<
|
|
52225
|
+
* value?: any,
|
|
52226
|
+
* defaultValue?: any,
|
|
52227
|
+
* signal?: import("@preact/signals").Signal<any>,
|
|
52212
52228
|
* name?: string,
|
|
52213
|
-
* min?:
|
|
52214
|
-
* max?:
|
|
52229
|
+
* min?: any,
|
|
52230
|
+
* max?: any,
|
|
52215
52231
|
* step?: number,
|
|
52232
|
+
* type?: string,
|
|
52233
|
+
* editable?: boolean,
|
|
52234
|
+
* growsUpward?: boolean,
|
|
52235
|
+
* fallbackValue?: any,
|
|
52236
|
+
* valueAtStep: (value: any, count: number) => any,
|
|
52237
|
+
* compareValues?: (a: any, b: any) => number,
|
|
52238
|
+
* renderValue?: (value: any) => import("ignore:preact").ComponentChildren,
|
|
52239
|
+
* controlProps?: object,
|
|
52216
52240
|
* duration?: number,
|
|
52217
|
-
*
|
|
52218
|
-
* renderDay?: (day: string) => import("ignore:preact").ComponentChildren,
|
|
52241
|
+
* vertical?: boolean,
|
|
52219
52242
|
* previousLabel?: string,
|
|
52220
52243
|
* nextLabel?: string,
|
|
52221
52244
|
* [key: string]: any,
|
|
52222
52245
|
* }>}
|
|
52223
|
-
* @param {
|
|
52224
|
-
*
|
|
52225
|
-
*
|
|
52226
|
-
* @param {
|
|
52227
|
-
*
|
|
52246
|
+
* @param {any} [value] The value shown. Held from above: `uiAction` says when
|
|
52247
|
+
* it should move. Say `signal` for a two-way binding instead, or
|
|
52248
|
+
* `defaultValue` to let the spin hold the value itself.
|
|
52249
|
+
* @param {(value: any, count: number) => any} valueAtStep What is `count` steps
|
|
52250
|
+
* away from `value` — the whole of what a spin has to know about what it
|
|
52251
|
+
* steps through. Called with -1 and +1 (times `step`) for the two ways out.
|
|
52252
|
+
* @param {(a: any, b: any) => number} [compareValues] Which of two values comes
|
|
52253
|
+
* first, the way a sort comparator answers. Only `min`/`max` need it, and the
|
|
52254
|
+
* default compares them as they compare with `<` — which is what an ISO date
|
|
52255
|
+
* wants and what a number does not.
|
|
52256
|
+
* @param {any} [fallbackValue] What is shown when nobody said anything: a spin
|
|
52257
|
+
* always shows a value, so there is always one to fall back on.
|
|
52258
|
+
* @param {string} [type="text"] What kind of value it is, handed to the control
|
|
52259
|
+
* holding it — a picker's `type` ("date", "time"…) or an input's.
|
|
52260
|
+
* @param {boolean} [editable] The middle is typed into rather than pressed:
|
|
52261
|
+
* the field IS the middle, and nothing travels. Without it the value is
|
|
52262
|
+
* picked — a headless picker behind three slides that travel one step at a
|
|
52263
|
+
* press.
|
|
52264
|
+
* @param {object} [controlProps] Anything else the control in the middle takes
|
|
52265
|
+
* (`inputMode`, `maxLength`, `placeholder`…).
|
|
52266
|
+
* @param {number} [step=1] How many steps a press covers.
|
|
52228
52267
|
* @param {number} [duration=250] How long a travel takes, in milliseconds.
|
|
52229
|
-
* @param {
|
|
52230
|
-
*
|
|
52231
|
-
* that way says so.
|
|
52232
|
-
* @param {"long"|"short"|"numeric"} [format="long"] How the date is written.
|
|
52233
|
-
* Long by default, since this is a control one reads rather than a column
|
|
52234
|
-
* one scans; `short` where the room is not there.
|
|
52268
|
+
* @param {any} [min] The first value one can reach; `max` is the last. Beyond
|
|
52269
|
+
* them the travel simply does not happen and the chevron that way says so.
|
|
52235
52270
|
* @param {string} [padding] The room around the value, `paddingX`/`paddingY`
|
|
52236
52271
|
* and the four sides included. It goes on what is inside the box rather than
|
|
52237
|
-
* on the box: above and below it is taken by the
|
|
52238
|
-
* which is what makes the three the same height; sideways it is the
|
|
52239
|
-
* between the
|
|
52240
|
-
* every picker takes (`--navi-picker-padding-x-default` and its `-y`
|
|
52241
|
-
* so a theme that spaces its fields spaces this one with them.
|
|
52242
|
-
* @param {number} [maxLines] How many lines the
|
|
52243
|
-
* with an ellipsis — `maxLines={1}` keeps it on one line. Without it a
|
|
52272
|
+
* on the box: above and below it is taken by the value AND by the two
|
|
52273
|
+
* chevrons, which is what makes the three the same height; sideways it is the
|
|
52274
|
+
* room between the value and the chevron beside it. Left unsaid it is the
|
|
52275
|
+
* padding every picker takes (`--navi-picker-padding-x-default` and its `-y`
|
|
52276
|
+
* twin), so a theme that spaces its fields spaces this one with them.
|
|
52277
|
+
* @param {number} [maxLines] How many lines the value may take before it is cut
|
|
52278
|
+
* with an ellipsis — `maxLines={1}` keeps it on one line. Without it a value
|
|
52244
52279
|
* too long for the box wraps, and the box grows.
|
|
52245
52280
|
* @param {boolean} [vertical] The same control standing up: the ways out above
|
|
52246
|
-
* and below rather than left and right
|
|
52281
|
+
* and below rather than left and right.
|
|
52282
|
+
* @param {boolean} [growsUpward] Which end of a standing spin holds the value
|
|
52283
|
+
* one steps up to. Off by default — what one walks through comes from below,
|
|
52284
|
+
* the way the next line of a list does. On for a quantity: pressing ▲ has to
|
|
52285
|
+
* mean a bigger number. Nothing to say about a spin lying down, where the way
|
|
52286
|
+
* on is always to the right.
|
|
52247
52287
|
* Everything a box takes is taken here too — `width`, `borderWidth`,
|
|
52248
52288
|
* `borderRadius`, `backgroundColor`: this IS a box, and its corners are passed
|
|
52249
52289
|
* on to the chevrons sitting in them.
|
|
52250
|
-
* @param {(day: string) => import("ignore:preact").ComponentChildren} [renderDay] What
|
|
52251
|
-
* to write for a day. Defaults to the date plus what it is to today when
|
|
52252
|
-
* there is a word for it ("samedi 8 août (demain)"), since a day near now is
|
|
52253
|
-
* read as a distance from now before it is read as a date.
|
|
52254
52290
|
*/
|
|
52255
|
-
const
|
|
52291
|
+
const Spin = ({
|
|
52256
52292
|
value,
|
|
52257
52293
|
defaultValue,
|
|
52258
52294
|
uiAction,
|
|
@@ -52262,76 +52298,77 @@ const DaySpin = ({
|
|
|
52262
52298
|
max,
|
|
52263
52299
|
step = 1,
|
|
52264
52300
|
duration = 250,
|
|
52265
|
-
|
|
52266
|
-
|
|
52301
|
+
type = "text",
|
|
52302
|
+
editable,
|
|
52303
|
+
growsUpward,
|
|
52304
|
+
fallbackValue,
|
|
52305
|
+
valueAtStep,
|
|
52306
|
+
compareValues = compareValuesDefault,
|
|
52307
|
+
renderValue = renderValueDefault,
|
|
52308
|
+
controlProps,
|
|
52267
52309
|
vertical,
|
|
52268
52310
|
readOnly,
|
|
52269
52311
|
disabled,
|
|
52270
52312
|
loading,
|
|
52271
52313
|
maxLines,
|
|
52272
|
-
renderDay = renderDayDefault,
|
|
52273
52314
|
previousLabel,
|
|
52274
52315
|
nextLabel,
|
|
52275
52316
|
...rest
|
|
52276
52317
|
}) => {
|
|
52277
52318
|
import.meta.css = [css$p, "@jsenv/navi/src/control/picker/picker_spin.jsx"];
|
|
52278
52319
|
const id = useId();
|
|
52279
|
-
const containerId = `${id}
|
|
52280
|
-
const
|
|
52281
|
-
// The
|
|
52282
|
-
// `defaultValue` and `signal` are handed to it untouched (see
|
|
52283
|
-
// settles which of them wins — and what a form makes of each —
|
|
52284
|
-
// the answer back. Nothing of that story is told twice.
|
|
52285
|
-
const
|
|
52286
|
-
const
|
|
52287
|
-
|
|
52288
|
-
max,
|
|
52289
|
-
step
|
|
52290
|
-
});
|
|
52291
|
-
const day = useControlUIState(pickerRef, value ?? defaultValue ?? signalProp?.peek()) ?? dayFallback;
|
|
52320
|
+
const containerId = `${id}_values`;
|
|
52321
|
+
const controlId = `${id}_control`;
|
|
52322
|
+
// The control holds the value, and it is asked rather than shadowed:
|
|
52323
|
+
// `value`, `defaultValue` and `signal` are handed to it untouched (see
|
|
52324
|
+
// below), it settles which of them wins — and what a form makes of each —
|
|
52325
|
+
// and this reads the answer back. Nothing of that story is told twice.
|
|
52326
|
+
const controlRef = useRef();
|
|
52327
|
+
const middleRef = useRef();
|
|
52328
|
+
const valueShown = useControlUIState(controlRef, value ?? defaultValue ?? signalProp?.peek()) ?? fallbackValue;
|
|
52292
52329
|
|
|
52293
52330
|
// …and the other way round when a signal was handed over: a bound signal is
|
|
52294
|
-
// the
|
|
52295
|
-
// elsewhere on the page — and the control follows it. A
|
|
52331
|
+
// the value, wherever it is moved from — the url, a back/forward, a button
|
|
52332
|
+
// elsewhere on the page — and the control follows it. A control seeded from a
|
|
52296
52333
|
// signal only writes back into it (see resolveInputProps), which is enough
|
|
52297
|
-
// for a field one only ever types into and not for a
|
|
52298
|
-
// from outside. Undefined is not a
|
|
52299
|
-
// control goes back to what it started on.
|
|
52300
|
-
const
|
|
52301
|
-
// The
|
|
52334
|
+
// for a field one only ever types into and not for a value that is also moved
|
|
52335
|
+
// from outside. Undefined is not a value: the signal has nothing to say, so
|
|
52336
|
+
// the control goes back to what it started on.
|
|
52337
|
+
const signalValue = signalProp ? signalProp.value : undefined;
|
|
52338
|
+
// The value as of the render this effect belongs to, and not one the closure
|
|
52302
52339
|
// captured a while ago: a step writes the signal, the signal brings us back
|
|
52303
|
-
// here, and comparing against a stale
|
|
52340
|
+
// here, and comparing against a stale value would set it a second time — one
|
|
52304
52341
|
// uiAction per step becoming two.
|
|
52305
|
-
const
|
|
52306
|
-
|
|
52342
|
+
const valueRef = useRef(valueShown);
|
|
52343
|
+
valueRef.current = valueShown;
|
|
52307
52344
|
useLayoutEffect(() => {
|
|
52308
|
-
const
|
|
52309
|
-
if (!signalProp || !
|
|
52345
|
+
const controlEl = controlRef.current;
|
|
52346
|
+
if (!signalProp || !controlEl) {
|
|
52310
52347
|
return;
|
|
52311
52348
|
}
|
|
52312
|
-
if (
|
|
52313
|
-
dispatchRequestResetUIState(
|
|
52349
|
+
if (signalValue === undefined) {
|
|
52350
|
+
dispatchRequestResetUIState(controlEl);
|
|
52314
52351
|
return;
|
|
52315
52352
|
}
|
|
52316
|
-
if (
|
|
52317
|
-
dispatchRequestSetUIState(
|
|
52353
|
+
if (signalValue !== valueRef.current) {
|
|
52354
|
+
dispatchRequestSetUIState(controlEl, signalValue, {});
|
|
52318
52355
|
}
|
|
52319
|
-
}, [
|
|
52356
|
+
}, [signalValue]);
|
|
52320
52357
|
|
|
52321
|
-
// A step is a change made to the
|
|
52358
|
+
// A step is a change made to the control, not beside it: it goes in the way a
|
|
52322
52359
|
// paste or a pick from the calendar goes in, so the signal, the form and
|
|
52323
52360
|
// `uiAction` all learn about it from the same place — and the event that
|
|
52324
52361
|
// asked for it travels with it, which is how `uiAction` can tell a chevron
|
|
52325
52362
|
// from the calendar.
|
|
52326
|
-
// What asked for the
|
|
52363
|
+
// What asked for the value being set, while it is being set: the control
|
|
52327
52364
|
// announces the change as its own input event, which says nothing of what
|
|
52328
52365
|
// started it — so it is held here for the length of the dispatch and handed
|
|
52329
|
-
// to uiAction below.
|
|
52366
|
+
// to uiAction below.
|
|
52330
52367
|
const stepEventRef = useRef(null);
|
|
52331
|
-
const
|
|
52368
|
+
const setValue = (valueNext, event) => {
|
|
52332
52369
|
stepEventRef.current = event;
|
|
52333
52370
|
try {
|
|
52334
|
-
dispatchRequestSetUIState(
|
|
52371
|
+
dispatchRequestSetUIState(controlRef.current, valueNext, {
|
|
52335
52372
|
event
|
|
52336
52373
|
});
|
|
52337
52374
|
} finally {
|
|
@@ -52340,29 +52377,29 @@ const DaySpin = ({
|
|
|
52340
52377
|
};
|
|
52341
52378
|
|
|
52342
52379
|
// Passed through rather than defaulted here: a prop nobody wrote must not
|
|
52343
|
-
// reach the
|
|
52380
|
+
// reach the control at all (it reads the presence of `value`, not its
|
|
52344
52381
|
// content), so each is added only if it was given.
|
|
52345
|
-
const
|
|
52382
|
+
const valueProps = {};
|
|
52346
52383
|
if (value !== undefined) {
|
|
52347
|
-
|
|
52384
|
+
valueProps.value = value;
|
|
52348
52385
|
} else {
|
|
52349
52386
|
if (signalProp) {
|
|
52350
|
-
|
|
52387
|
+
valueProps.signal = signalProp;
|
|
52351
52388
|
}
|
|
52352
|
-
// A
|
|
52353
|
-
// what the signal starts on, or
|
|
52354
|
-
//
|
|
52355
|
-
//
|
|
52356
|
-
//
|
|
52357
|
-
//
|
|
52358
|
-
//
|
|
52359
|
-
|
|
52389
|
+
// A value is always shown, so the control always HOLDS one: what was named,
|
|
52390
|
+
// or what the signal starts on, or the fallback. Said as a default rather
|
|
52391
|
+
// than as a value, so a form reads what is shown as an answer one can send
|
|
52392
|
+
// rather than as something it already holds — and said even when a signal
|
|
52393
|
+
// is bound, because a signal with nothing in it would otherwise leave the
|
|
52394
|
+
// control empty while the spin shows a value, and a form has nothing to
|
|
52395
|
+
// send about an empty field.
|
|
52396
|
+
valueProps.defaultValue = defaultValue ?? signalProp?.options?.getDefaultValue?.(false) ?? fallbackValue;
|
|
52360
52397
|
}
|
|
52361
52398
|
|
|
52362
52399
|
// Told from above as often as said here: a form running its action puts
|
|
52363
52400
|
// every control inside it out of service (that is how the chevrons grey out
|
|
52364
|
-
// by themselves), and the
|
|
52365
|
-
// control, not a box with three moods.
|
|
52401
|
+
// by themselves), and the value they sit around must fade with them — it is
|
|
52402
|
+
// one control, not a box with three moods.
|
|
52366
52403
|
const readOnlyFromAbove = useContext(ReadOnlyContext);
|
|
52367
52404
|
const loadingFromAbove = useContext(LoadingContext$1);
|
|
52368
52405
|
const disabledFromAbove = useContext(DisabledContext);
|
|
@@ -52388,15 +52425,54 @@ const DaySpin = ({
|
|
|
52388
52425
|
}
|
|
52389
52426
|
return undefined;
|
|
52390
52427
|
};
|
|
52391
|
-
const
|
|
52392
|
-
|
|
52393
|
-
|
|
52394
|
-
|
|
52428
|
+
const valuePrevious = valueAtStep(valueShown, -step);
|
|
52429
|
+
const valueNext = valueAtStep(valueShown, step);
|
|
52430
|
+
const hasMin = min !== undefined && min !== "";
|
|
52431
|
+
const hasMax = max !== undefined && max !== "";
|
|
52432
|
+
const previousAllowed = !hasMin || compareValues(valuePrevious, min) >= 0;
|
|
52433
|
+
const nextAllowed = !hasMax || compareValues(valueNext, max) <= 0;
|
|
52434
|
+
|
|
52435
|
+
// Where the keyboard is put back after a press on a chevron: whatever holds
|
|
52436
|
+
// it in this spin, so one can keep going with the keys where one was. Found
|
|
52437
|
+
// in the middle rather than by id — a field's id lands on the box around it,
|
|
52438
|
+
// and what takes the keyboard is the input inside.
|
|
52439
|
+
const focusMiddle = () => {
|
|
52440
|
+
const target = editable ? middleRef.current?.querySelector(".navi_control_input") : document.getElementById(containerId);
|
|
52441
|
+
target?.focus({
|
|
52442
|
+
preventScroll: true
|
|
52443
|
+
});
|
|
52444
|
+
};
|
|
52445
|
+
|
|
52446
|
+
// Which end of a standing spin holds the value one steps UP to. A quantity
|
|
52447
|
+
// grows upwards — pressing ▲ on a number means a bigger number, and anything
|
|
52448
|
+
// else is read as a bug. What one walks through does the opposite: the day
|
|
52449
|
+
// after today arrives from below, the way the next line of a list does.
|
|
52450
|
+
const startIsNext = vertical && growsUpward;
|
|
52451
|
+
const valueAtStart = startIsNext ? valueNext : valuePrevious;
|
|
52452
|
+
const valueAtEnd = startIsNext ? valuePrevious : valueNext;
|
|
52453
|
+
const startAllowed = startIsNext ? nextAllowed : previousAllowed;
|
|
52454
|
+
const endAllowed = startIsNext ? previousAllowed : nextAllowed;
|
|
52455
|
+
const wayOut = atStart => {
|
|
52456
|
+
const isNext = atStart ? startIsNext : !startIsNext;
|
|
52457
|
+
return jsx(WayOut, {
|
|
52458
|
+
unavailableMessage: wayOutMessage(atStart ? startAllowed : endAllowed, isNext ? "spin.nothing_after" : "spin.nothing_before"),
|
|
52459
|
+
label: isNext ? nextLabel ?? naviI18n("spin.next") : previousLabel ?? naviI18n("spin.previous"),
|
|
52460
|
+
onPress: e => {
|
|
52461
|
+
focusMiddle();
|
|
52462
|
+
if (editable) {
|
|
52463
|
+
setValue(atStart ? valueAtStart : valueAtEnd, e);
|
|
52464
|
+
return;
|
|
52465
|
+
}
|
|
52466
|
+
// A direction on the map, not a value: the slides are laid out from
|
|
52467
|
+
// start to end (see below), so the way out at the start walks
|
|
52468
|
+
// backwards through them whichever value sits there.
|
|
52469
|
+
const command = atStart ? vertical ? "--navi-up" : "--navi-left" : vertical ? "--navi-down" : "--navi-right";
|
|
52470
|
+
triggerNaviCommand(e.currentTarget, command, e);
|
|
52471
|
+
},
|
|
52472
|
+
commandFor: editable ? undefined : containerId,
|
|
52473
|
+
children: atStart ? vertical ? jsx(ChevronUpSvg, {}) : jsx(ChevronLeftSvg, {}) : vertical ? jsx(ChevronDownSvg, {}) : jsx(ChevronRightSvg, {})
|
|
52474
|
+
});
|
|
52395
52475
|
};
|
|
52396
|
-
const dayPrevious = addDays(day, -step);
|
|
52397
|
-
const dayNext = addDays(day, step);
|
|
52398
|
-
const previousAllowed = !min || dayPrevious >= min;
|
|
52399
|
-
const nextAllowed = !max || dayNext <= max;
|
|
52400
52476
|
return jsxs(Box, {
|
|
52401
52477
|
...rest,
|
|
52402
52478
|
baseClassName: "navi_picker_spin",
|
|
@@ -52415,128 +52491,151 @@ const DaySpin = ({
|
|
|
52415
52491
|
loading: loading,
|
|
52416
52492
|
color: "var(--navi-loader-color)",
|
|
52417
52493
|
inset: -2
|
|
52418
|
-
}), jsx(
|
|
52419
|
-
command: vertical ? "--navi-up" : "--navi-left",
|
|
52420
|
-
containerId: containerId,
|
|
52421
|
-
unavailableMessage: wayOutMessage(previousAllowed, "spin.nothing_before"),
|
|
52422
|
-
label: previousLabel ?? naviI18n("spin.previous"),
|
|
52423
|
-
children: vertical ? jsx(ChevronUpSvg, {}) : jsx(ChevronLeftSvg, {})
|
|
52424
|
-
}), jsxs("div", {
|
|
52494
|
+
}), wayOut(true), jsx("div", {
|
|
52425
52495
|
className: "navi_picker_spin_middle",
|
|
52426
|
-
|
|
52427
|
-
|
|
52428
|
-
|
|
52429
|
-
type:
|
|
52430
|
-
|
|
52431
|
-
|
|
52432
|
-
|
|
52433
|
-
// holds, a `signal` it follows, a `defaultValue` it merely starts on —
|
|
52434
|
-
// including what a form makes of the difference (it HOLDS a value and
|
|
52435
|
-
// has nothing to send back, where a default is a suggestion and
|
|
52436
|
-
// confirming it is an answer). A day is always shown, so there is
|
|
52437
|
-
// always a default: today, when nobody named one.
|
|
52438
|
-
,
|
|
52439
|
-
|
|
52440
|
-
...dayProps,
|
|
52496
|
+
ref: middleRef,
|
|
52497
|
+
children: editable ? jsx(Input, {
|
|
52498
|
+
ref: controlRef,
|
|
52499
|
+
type: type,
|
|
52500
|
+
name: name,
|
|
52501
|
+
...controlProps,
|
|
52502
|
+
...valueProps,
|
|
52441
52503
|
min: min,
|
|
52442
52504
|
max: max,
|
|
52505
|
+
step: step,
|
|
52443
52506
|
readOnly: readOnly,
|
|
52444
52507
|
disabled: disabled,
|
|
52445
|
-
loading: loading
|
|
52446
|
-
|
|
52447
|
-
|
|
52448
|
-
|
|
52449
|
-
|
|
52450
|
-
id: containerId,
|
|
52451
|
-
layout: vertical ? "column" : "row"
|
|
52452
|
-
// What is left beside the two chevrons, whatever the days it holds are
|
|
52453
|
-
// long: a control that resizes as one steps through it is a control one
|
|
52454
|
-
// has to aim at twice.
|
|
52508
|
+
loading: loading
|
|
52509
|
+
// No frame of its own inside a frame, and no ring of its own
|
|
52510
|
+
// either: the spin draws both (see the CSS above), and an outline
|
|
52511
|
+
// of zero width is how a field stands down without its focus
|
|
52512
|
+
// state being touched.
|
|
52455
52513
|
,
|
|
52456
52514
|
|
|
52515
|
+
variant: "discrete",
|
|
52516
|
+
outlineWidth: "0",
|
|
52517
|
+
textAlign: "center",
|
|
52457
52518
|
expandX: true,
|
|
52458
|
-
|
|
52459
|
-
|
|
52460
|
-
|
|
52461
|
-
|
|
52462
|
-
|
|
52463
|
-
|
|
52519
|
+
uiAction: (valueNext, event) => {
|
|
52520
|
+
uiAction?.(valueNext, stepEventRef.current ?? event);
|
|
52521
|
+
}
|
|
52522
|
+
}) : jsxs(Fragment$1, {
|
|
52523
|
+
children: [jsx(Picker, {
|
|
52524
|
+
ref: controlRef,
|
|
52525
|
+
id: controlId,
|
|
52526
|
+
type: type,
|
|
52527
|
+
variant: "headless",
|
|
52528
|
+
name: name,
|
|
52529
|
+
...controlProps,
|
|
52530
|
+
...valueProps,
|
|
52531
|
+
min: min,
|
|
52532
|
+
max: max,
|
|
52533
|
+
readOnly: readOnly,
|
|
52534
|
+
disabled: disabled,
|
|
52535
|
+
loading: loading,
|
|
52536
|
+
uiAction: (valueNext, event) => {
|
|
52537
|
+
uiAction?.(valueNext, stepEventRef.current ?? event);
|
|
52538
|
+
}
|
|
52539
|
+
}), jsxs(SlideContainer, {
|
|
52540
|
+
id: containerId,
|
|
52541
|
+
layout: vertical ? "column" : "row"
|
|
52542
|
+
// What is left beside the two chevrons, whatever the values it
|
|
52543
|
+
// holds are long: a control that resizes as one steps through it
|
|
52544
|
+
// is a control one has to aim at twice.
|
|
52545
|
+
,
|
|
52464
52546
|
|
|
52465
|
-
|
|
52466
|
-
|
|
52467
|
-
|
|
52468
|
-
|
|
52469
|
-
|
|
52470
|
-
|
|
52471
|
-
|
|
52472
|
-
// one of the two is ever anything but zero. The event goes with it —
|
|
52473
|
-
// it is what says a chevron (or an arrow key) asked for this day.
|
|
52474
|
-
setDay(addDays(day, (dx || dy) * step), event);
|
|
52475
|
-
}
|
|
52476
|
-
// The whole middle opens the calendar — a command, like the chevrons
|
|
52477
|
-
// send one, and no button of its own: the day would then be one more
|
|
52478
|
-
// Tab stop, and the focus would follow it out of the box as it travels.
|
|
52479
|
-
,
|
|
52547
|
+
expandX: true,
|
|
52548
|
+
defaultCurrent: "current",
|
|
52549
|
+
duration: `${duration}ms`
|
|
52550
|
+
// The three values are a window over an endless row: the
|
|
52551
|
+
// container plays the travel and comes back to the middle, and
|
|
52552
|
+
// the value moves one step here, in onLoop, as it lands.
|
|
52553
|
+
,
|
|
52480
52554
|
|
|
52481
|
-
|
|
52482
|
-
|
|
52483
|
-
|
|
52484
|
-
|
|
52485
|
-
|
|
52486
|
-
|
|
52487
|
-
|
|
52488
|
-
|
|
52489
|
-
|
|
52555
|
+
loop: true,
|
|
52556
|
+
onLoop: ({
|
|
52557
|
+
dx,
|
|
52558
|
+
dy,
|
|
52559
|
+
event
|
|
52560
|
+
}) => {
|
|
52561
|
+
// One step, whichever axis it came from: the map is a line, so
|
|
52562
|
+
// only one of the two is ever anything but zero. Towards the
|
|
52563
|
+
// end of the line is a step forward, unless the line was laid
|
|
52564
|
+
// out the other way round (startIsNext). The event goes with
|
|
52565
|
+
// it — it is what says a chevron (or an arrow key) asked for
|
|
52566
|
+
// this value.
|
|
52567
|
+
const towardsEnd = dx || dy;
|
|
52568
|
+
setValue(valueAtStep(valueShown, (startIsNext ? -towardsEnd : towardsEnd) * step), event);
|
|
52569
|
+
}
|
|
52570
|
+
// The whole middle opens the picker — a command, like the
|
|
52571
|
+
// chevrons send one, and no button of its own: the value would
|
|
52572
|
+
// then be one more Tab stop, and the focus would follow it out of
|
|
52573
|
+
// the box as it travels.
|
|
52574
|
+
,
|
|
52490
52575
|
|
|
52491
|
-
|
|
52492
|
-
|
|
52493
|
-
|
|
52494
|
-
|
|
52495
|
-
|
|
52496
|
-
|
|
52497
|
-
|
|
52498
|
-
|
|
52499
|
-
|
|
52500
|
-
}), jsx(Slide, {
|
|
52501
|
-
area: "current",
|
|
52502
|
-
flex: true,
|
|
52503
|
-
align: "center"
|
|
52504
|
-
// The days a min/max leaves out are simply not reachable: the way out
|
|
52505
|
-
// is closed on the slide being left, so a key, a chevron and a
|
|
52506
|
-
// command are all stopped by the same thing.
|
|
52576
|
+
commandFor: controlId
|
|
52577
|
+
// Sent whatever state the control is in: the picker is the one
|
|
52578
|
+
// that knows it cannot be opened right now, and refusing there is
|
|
52579
|
+
// what says so out loud (read-only, busy). Refusing here would be
|
|
52580
|
+
// a press that does nothing and explains nothing.
|
|
52581
|
+
// preventDefault, because a <Label> around the whole control
|
|
52582
|
+
// forwards a click to what it labels — the picker — and that
|
|
52583
|
+
// would open the calendar a second time, right after this command
|
|
52584
|
+
// did.
|
|
52507
52585
|
,
|
|
52508
52586
|
|
|
52509
|
-
|
|
52510
|
-
|
|
52511
|
-
|
|
52512
|
-
|
|
52513
|
-
|
|
52514
|
-
|
|
52515
|
-
|
|
52516
|
-
|
|
52587
|
+
onClick: e => {
|
|
52588
|
+
e.preventDefault();
|
|
52589
|
+
triggerNaviCommand(e.currentTarget, "--navi-open", e);
|
|
52590
|
+
},
|
|
52591
|
+
children: [jsx(Slide, {
|
|
52592
|
+
area: "start",
|
|
52593
|
+
flex: true,
|
|
52594
|
+
align: "center",
|
|
52595
|
+
children: renderValue(valueAtStart, {
|
|
52596
|
+
maxLines
|
|
52597
|
+
})
|
|
52598
|
+
}), jsx(Slide, {
|
|
52599
|
+
area: "current",
|
|
52600
|
+
flex: true,
|
|
52601
|
+
align: "center"
|
|
52602
|
+
// The values a min/max leaves out are simply not reachable: the
|
|
52603
|
+
// way out is closed on the slide being left, so a key, a
|
|
52604
|
+
// chevron and a command are all stopped by the same thing.
|
|
52605
|
+
,
|
|
52606
|
+
|
|
52607
|
+
preventNavPrevious: !startAllowed,
|
|
52608
|
+
preventNavNext: !endAllowed,
|
|
52609
|
+
children: renderValue(valueShown, {
|
|
52610
|
+
maxLines
|
|
52611
|
+
})
|
|
52612
|
+
}), jsx(Slide, {
|
|
52613
|
+
area: "end",
|
|
52614
|
+
flex: true,
|
|
52615
|
+
align: "center",
|
|
52616
|
+
children: renderValue(valueAtEnd, {
|
|
52617
|
+
maxLines
|
|
52618
|
+
})
|
|
52619
|
+
})]
|
|
52517
52620
|
})]
|
|
52518
|
-
})
|
|
52519
|
-
}),
|
|
52520
|
-
command: vertical ? "--navi-down" : "--navi-right",
|
|
52521
|
-
containerId: containerId,
|
|
52522
|
-
unavailableMessage: wayOutMessage(nextAllowed, "spin.nothing_after"),
|
|
52523
|
-
label: nextLabel ?? naviI18n("spin.next"),
|
|
52524
|
-
children: vertical ? jsx(ChevronDownSvg, {}) : jsx(ChevronRightSvg, {})
|
|
52525
|
-
})]
|
|
52621
|
+
})
|
|
52622
|
+
}), wayOut(false)]
|
|
52526
52623
|
});
|
|
52527
52624
|
};
|
|
52528
52625
|
|
|
52529
52626
|
// A way out is a place one presses, not a control: no <button>, on purpose.
|
|
52530
52627
|
// A <button> is labelable, so a <Label> wrapping the whole spin would bind
|
|
52531
|
-
// to the first chevron instead of to the
|
|
52532
|
-
// the value — and a form would carry two more controls that answer for
|
|
52533
|
-
//
|
|
52534
|
-
//
|
|
52628
|
+
// to the first chevron instead of to the control — the thing that actually
|
|
52629
|
+
// holds the value — and a form would carry two more controls that answer for
|
|
52630
|
+
// nothing.
|
|
52631
|
+
// It is not focusable either: the keyboard walks the values on the middle (see
|
|
52632
|
+
// the container's own tabIndex, or the field's), where the arrows already mean
|
|
52633
|
+
// this.
|
|
52535
52634
|
const WayOut = ({
|
|
52536
|
-
|
|
52537
|
-
containerId,
|
|
52635
|
+
commandFor,
|
|
52538
52636
|
unavailableMessage,
|
|
52539
52637
|
label,
|
|
52638
|
+
onPress,
|
|
52540
52639
|
children
|
|
52541
52640
|
}) => jsx(Box, {
|
|
52542
52641
|
as: "span",
|
|
@@ -52560,38 +52659,32 @@ const WayOut = ({
|
|
|
52560
52659
|
// Read by triggerNaviCommand below the same way it reads a button's own.
|
|
52561
52660
|
,
|
|
52562
52661
|
|
|
52563
|
-
commandfor:
|
|
52662
|
+
commandfor: commandFor,
|
|
52564
52663
|
flex: true,
|
|
52565
52664
|
align: "center"
|
|
52566
52665
|
// A press, answered where it starts: mousedown rather than click, which is
|
|
52567
52666
|
// what makes holding one feel immediate — and the click after it is stopped
|
|
52568
52667
|
// below, so a <Label> wrapping the whole control does not forward it to the
|
|
52569
|
-
//
|
|
52668
|
+
// control and open the calendar on the way past.
|
|
52570
52669
|
,
|
|
52571
52670
|
|
|
52572
52671
|
onClick: e => {
|
|
52573
52672
|
e.preventDefault();
|
|
52574
52673
|
},
|
|
52575
52674
|
onMouseDown: e => {
|
|
52576
|
-
// No focus, no text selection: the keyboard is put on the
|
|
52675
|
+
// No focus, no text selection: the keyboard is put on the middle below.
|
|
52577
52676
|
e.preventDefault();
|
|
52578
|
-
const wayOutElement = e.currentTarget;
|
|
52579
52677
|
if (unavailableMessage) {
|
|
52580
52678
|
// Why it does nothing, said where one pressed: a control would have
|
|
52581
52679
|
// done this through its own interaction gate, and this one has none.
|
|
52582
52680
|
openCallout(unavailableMessage, {
|
|
52583
|
-
anchorElement:
|
|
52681
|
+
anchorElement: e.currentTarget,
|
|
52584
52682
|
status: "info",
|
|
52585
52683
|
openingEvent: e
|
|
52586
52684
|
});
|
|
52587
52685
|
return;
|
|
52588
52686
|
}
|
|
52589
|
-
|
|
52590
|
-
// pressing a chevron leaves one able to keep going with the keys.
|
|
52591
|
-
document.getElementById(containerId)?.focus({
|
|
52592
|
-
preventScroll: true
|
|
52593
|
-
});
|
|
52594
|
-
triggerNaviCommand(wayOutElement, command, e);
|
|
52687
|
+
onPress(e);
|
|
52595
52688
|
},
|
|
52596
52689
|
children: jsx(Icon, {
|
|
52597
52690
|
children: children
|
|
@@ -52601,8 +52694,8 @@ const PICKER_SPIN_PSEUDO_CLASSES = [":hover", ":focus-visible"];
|
|
|
52601
52694
|
|
|
52602
52695
|
// A padding written on this box would sit between its border and the chevrons,
|
|
52603
52696
|
// which are meant to reach the corners they are rounded by — so each padding
|
|
52604
|
-
// prop becomes a variable instead, and the CSS above hands it to the
|
|
52605
|
-
// the chevrons themselves. Same trick, and same var chain, as Picker's.
|
|
52697
|
+
// prop becomes a variable instead, and the CSS above hands it to the value and
|
|
52698
|
+
// to the chevrons themselves. Same trick, and same var chain, as Picker's.
|
|
52606
52699
|
const PICKER_SPIN_STYLE_CSS_VARS = {
|
|
52607
52700
|
padding: "--picker-spin-padding",
|
|
52608
52701
|
paddingX: "--picker-spin-padding-x",
|
|
@@ -52613,6 +52706,138 @@ const PICKER_SPIN_STYLE_CSS_VARS = {
|
|
|
52613
52706
|
paddingLeft: "--picker-spin-padding-left"
|
|
52614
52707
|
};
|
|
52615
52708
|
|
|
52709
|
+
// Two values compared the way `<` compares them: right for an ISO day, a time
|
|
52710
|
+
// or anything else written so that its order IS its alphabetical order. A
|
|
52711
|
+
// number is the exception, and NumberSpin below says so.
|
|
52712
|
+
const compareValuesDefault = (a, b) => {
|
|
52713
|
+
if (a < b) {
|
|
52714
|
+
return -1;
|
|
52715
|
+
}
|
|
52716
|
+
if (a > b) {
|
|
52717
|
+
return 1;
|
|
52718
|
+
}
|
|
52719
|
+
return 0;
|
|
52720
|
+
};
|
|
52721
|
+
const renderValueDefault = value => String(value ?? "");
|
|
52722
|
+
|
|
52723
|
+
/**
|
|
52724
|
+
* A whole number one steps through and types into: the field IS the middle, so
|
|
52725
|
+
* the value can be typed as readily as stepped, and the two chevrons stand
|
|
52726
|
+
* above and below it by default — sideways they would be where the caret
|
|
52727
|
+
* moves — with the bigger number up top.
|
|
52728
|
+
*
|
|
52729
|
+
* @type {import("ignore:preact").FunctionComponent<{
|
|
52730
|
+
* value?: number|string,
|
|
52731
|
+
* defaultValue?: number|string,
|
|
52732
|
+
* min?: number,
|
|
52733
|
+
* max?: number,
|
|
52734
|
+
* step?: number,
|
|
52735
|
+
* [key: string]: any,
|
|
52736
|
+
* }>}
|
|
52737
|
+
* @param {number} [min=0] The lowest number one can reach; `max` is the
|
|
52738
|
+
* highest. They also bound what typing can produce, and how wide the field
|
|
52739
|
+
* is asked to be (see `maxLength`).
|
|
52740
|
+
*/
|
|
52741
|
+
const NumberSpin = ({
|
|
52742
|
+
min = 0,
|
|
52743
|
+
max,
|
|
52744
|
+
step = 1,
|
|
52745
|
+
vertical = true,
|
|
52746
|
+
growsUpward = true,
|
|
52747
|
+
controlProps,
|
|
52748
|
+
...rest
|
|
52749
|
+
}) => jsx(Spin, {
|
|
52750
|
+
type: "navi_number",
|
|
52751
|
+
editable: true,
|
|
52752
|
+
growsUpward: growsUpward,
|
|
52753
|
+
min: min,
|
|
52754
|
+
max: max,
|
|
52755
|
+
step: step,
|
|
52756
|
+
vertical: vertical,
|
|
52757
|
+
fallbackValue: min,
|
|
52758
|
+
valueAtStep: (value, count) => numberAtStep(value, count, min),
|
|
52759
|
+
compareValues: (a, b) => Number(a) - Number(b),
|
|
52760
|
+
controlProps: {
|
|
52761
|
+
// The numeric keypad on a phone, and — through
|
|
52762
|
+
// input_resolver_mode — the "this field is full" event a group of
|
|
52763
|
+
// fields moves along on (see useInputGroup).
|
|
52764
|
+
inputMode: "numeric",
|
|
52765
|
+
maxLength: max === undefined ? undefined : String(max).length,
|
|
52766
|
+
...controlProps
|
|
52767
|
+
},
|
|
52768
|
+
...rest
|
|
52769
|
+
});
|
|
52770
|
+
|
|
52771
|
+
// One step away, bounds included: a step past `max` is a real number that
|
|
52772
|
+
// simply is not allowed, and Spin is the one that reads it as "nothing that
|
|
52773
|
+
// way" — clamping here would answer the chevron before it had a chance to say
|
|
52774
|
+
// so. A field mid-edit holding nothing (or nothing numeric) starts from `min`.
|
|
52775
|
+
const numberAtStep = (value, count, min) => {
|
|
52776
|
+
const number = Number(value);
|
|
52777
|
+
if (value === "" || value === undefined || Number.isNaN(number)) {
|
|
52778
|
+
return min;
|
|
52779
|
+
}
|
|
52780
|
+
return number + count;
|
|
52781
|
+
};
|
|
52782
|
+
|
|
52783
|
+
/**
|
|
52784
|
+
* A day one steps through: the date plus what it is to today when there is a
|
|
52785
|
+
* word for it, and a calendar behind it for the day that is far from here.
|
|
52786
|
+
*
|
|
52787
|
+
* @type {import("ignore:preact").FunctionComponent<{
|
|
52788
|
+
* value?: string,
|
|
52789
|
+
* defaultValue?: string,
|
|
52790
|
+
* signal?: import("@preact/signals").Signal<string>,
|
|
52791
|
+
* name?: string,
|
|
52792
|
+
* min?: string,
|
|
52793
|
+
* max?: string,
|
|
52794
|
+
* step?: number,
|
|
52795
|
+
* lang?: string,
|
|
52796
|
+
* renderDay?: (day: string) => import("ignore:preact").ComponentChildren,
|
|
52797
|
+
* [key: string]: any,
|
|
52798
|
+
* }>}
|
|
52799
|
+
* @param {string} [value] The day shown, as "YYYY-MM-DD".
|
|
52800
|
+
* @param {number} [step=1] How many days a press covers — 7 for a week at a
|
|
52801
|
+
* time, and the label then names the day one lands on, as it always does.
|
|
52802
|
+
* @param {string} [min] The first day one can reach, as "YYYY-MM-DD"; `max` is
|
|
52803
|
+
* the last.
|
|
52804
|
+
* @param {"long"|"short"|"numeric"} [format="long"] How the date is written.
|
|
52805
|
+
* Long by default, since this is a control one reads rather than a column
|
|
52806
|
+
* one scans; `short` where the room is not there.
|
|
52807
|
+
* @param {(day: string) => import("ignore:preact").ComponentChildren} [renderDay] What
|
|
52808
|
+
* to write for a day. Defaults to the date plus what it is to today when
|
|
52809
|
+
* there is a word for it ("samedi 8 août (demain)"), since a day near now is
|
|
52810
|
+
* read as a distance from now before it is read as a date.
|
|
52811
|
+
*/
|
|
52812
|
+
const DaySpin = ({
|
|
52813
|
+
min,
|
|
52814
|
+
max,
|
|
52815
|
+
step = 1,
|
|
52816
|
+
lang,
|
|
52817
|
+
format = "long",
|
|
52818
|
+
renderDay = renderDayDefault,
|
|
52819
|
+
...rest
|
|
52820
|
+
}) => jsx(Spin, {
|
|
52821
|
+
type: "date",
|
|
52822
|
+
min: min,
|
|
52823
|
+
max: max,
|
|
52824
|
+
step: step,
|
|
52825
|
+
fallbackValue: firstDayAllowed({
|
|
52826
|
+
min,
|
|
52827
|
+
max,
|
|
52828
|
+
step
|
|
52829
|
+
}),
|
|
52830
|
+
valueAtStep: addDays,
|
|
52831
|
+
renderValue: (day, {
|
|
52832
|
+
maxLines
|
|
52833
|
+
}) => renderDay(day, {
|
|
52834
|
+
lang,
|
|
52835
|
+
format,
|
|
52836
|
+
maxLines
|
|
52837
|
+
}),
|
|
52838
|
+
...rest
|
|
52839
|
+
});
|
|
52840
|
+
|
|
52616
52841
|
// The date, and what it is to today when that is something one has a word for:
|
|
52617
52842
|
// "samedi 8 août (demain)" says both where one is and how far that is, and only
|
|
52618
52843
|
// the second is read at a glance.
|
|
@@ -54565,6 +54790,15 @@ const css$k = /* css */`
|
|
|
54565
54790
|
--wheel-window-inset: calc((100% - var(--wheel-item-height)) / 2);
|
|
54566
54791
|
--wheel-band-inset: calc((100% - var(--wheel-emphasis-size)) / 2);
|
|
54567
54792
|
|
|
54793
|
+
/* As wide as the rows ON SCREEN, which is not the same as "as wide as
|
|
54794
|
+
the widest value": the rows are a handful of recycled slots, so a wheel
|
|
54795
|
+
whose labels are not all the same width resizes as one scrolls — "9"
|
|
54796
|
+
becoming "10" widens it mid-glide, and whatever holds it (a popup)
|
|
54797
|
+
moves under the finger. Give such a wheel a width and the question is
|
|
54798
|
+
settled once; the per-row padding stays where it is, inside it, and
|
|
54799
|
+
stays scrollable. Digits are the case where this does not arise on its
|
|
54800
|
+
own: data-wheel-type="integer" makes them tabular above, so they all
|
|
54801
|
+
advance the same — until one of them takes a digit more. */
|
|
54568
54802
|
width: fit-content;
|
|
54569
54803
|
|
|
54570
54804
|
.navi_wheel_viewport {
|
|
@@ -54649,6 +54883,9 @@ const css$k = /* css */`
|
|
|
54649
54883
|
--wheel-window-inset: calc((100% - var(--wheel-item-width)) / 2);
|
|
54650
54884
|
--wheel-band-inset: calc((100% - var(--wheel-emphasis-size)) / 2);
|
|
54651
54885
|
|
|
54886
|
+
/* The cross axis follows the rows on screen — same story as the vertical
|
|
54887
|
+
branch above, and the same answer: say a height when the rows are not
|
|
54888
|
+
all as tall as each other. */
|
|
54652
54889
|
height: fit-content;
|
|
54653
54890
|
|
|
54654
54891
|
.navi_wheel_viewport {
|
|
@@ -62425,5 +62662,5 @@ const UserSvg = () => jsx("svg", {
|
|
|
62425
62662
|
})
|
|
62426
62663
|
});
|
|
62427
62664
|
|
|
62428
|
-
export { ActionRenderer, ActiveKeyboardShortcuts, Address, Badge, BadgeCount, BadgeList, Binder, Box, Button, ButtonCopyToClipboard, Caption, CardLayout, CheckSvg, CheckboxGroup, CloseSvg, Code, Col, Colgroup, Color, ConstructionSvg, ControlGroup, DaySpin, Details, Dialog, Editable, ErrorBoundary, ErrorBoundaryContext, ExclamationSvg, EyeClosedSvg, EyeSvg, Field, FixedBar, Form, Group, Head, HeartSvg, HomeSvg, Icon, Image, Input, InputDuration, Interpolate, Label, Link, LinkAnchorSvg, LinkBlankTargetSvg, LinkCurrentSvg, List, ListItem, ListItemGroup, ListItems, Loading, LoadingDotsSvg, LoadingIndicator, LoadingIndicatorFluid, LoadingOutline, MessageBox, Meter, Nav, NaviDebug, Paragraph, Picker, Popover, Popup, Quantity, RadioGroup, Route, RowNumberCol, RowNumberTableCell, SVGMaskOverlay, SearchSvg, SelectableInput, SelectionContext, Separator, SettingsSvg, SidePanel, Slide, SlideContainer, StarSvg, SummaryMarker, Svg, Table, TableCell, Tbody, Text, TextBox, Textarea, TextareaCharCount, Thead, Time, Title, Tr, UITransition, Unit, UserSvg, ViewportLayout, Wheel, WheelGroup, WheelItem, actionRunEffect, anyMatchingRouteSignal, applySearch, arraySignalMembership, coarsePointerSignal, compareTwoJsValues, createAction, createAvailableConstraint, createRequestCanceller, createSearch, createSelectionKeyboardShortcuts, createSlot, defineNaviConfirmPopupOptions, enableDebugActions, enableDebugOnDocumentLoading, ensureDocumentStartViewTransition, filterTableSelection, formatDatetime, formatDay, formatDayRelative, formatMonth, formatNumber, formatTime, formatTimeRelative, getNowHours, getNowHoursRoundedToStep, interpolateText, isCellSelected, isColumnSelected, isRowSelected, isToday, languagesSignal, localStorageSignal, moveArrayItemByIndex, navBack, navForward, navIntegratedVia, navTo, naviI18n, openCallout, rawUrlPart, registerGlobalConstraint, reload, rerunActions, resource, route, routeAction, setBaseUrl, setPreferredLanguage, setSupportedLanguages, setupRoutes, stateSignal, stopLoad, stringifyTableSelectionValue, swapArrayItemByIndex, syncOwnedResourceToSignals, syncResourceToSignals, updateActions, useActionStatus, useArraySignalMembership, useAsyncData, useCalloutRequestClose, useCancelPrevious, useCellGridFromRows, useConstraintValidityState, useDependenciesDiff, useDisplayedLayoutEffect, useDocumentResource, useDocumentState, useDocumentUrl, useEditionController, useFocusGroup, useKeyboardShortcuts, useNavState, useOrderedColumns, usePopupMode, useRouteStatus, useRunOnMount, useSearchText, useSelectableElement, useSelectionController, useSignalSync, useSlideValue, useStateArray, useTitleLevel, useUrlSearchParam, valueInLocalStorage, windowWidthSignal };
|
|
62665
|
+
export { ActionRenderer, ActiveKeyboardShortcuts, Address, Badge, BadgeCount, BadgeList, Binder, Box, Button, ButtonCopyToClipboard, Caption, CardLayout, CheckSvg, CheckboxGroup, CloseSvg, Code, Col, Colgroup, Color, ConstructionSvg, ControlGroup, DaySpin, Details, Dialog, Editable, ErrorBoundary, ErrorBoundaryContext, ExclamationSvg, EyeClosedSvg, EyeSvg, Field, FixedBar, Form, Group, Head, HeartSvg, HomeSvg, Icon, Image, Input, InputDuration, Interpolate, Label, Link, LinkAnchorSvg, LinkBlankTargetSvg, LinkCurrentSvg, List, ListItem, ListItemGroup, ListItems, Loading, LoadingDotsSvg, LoadingIndicator, LoadingIndicatorFluid, LoadingOutline, MessageBox, Meter, Nav, NaviDebug, NumberSpin, Paragraph, Picker, Popover, Popup, Quantity, RadioGroup, Route, RowNumberCol, RowNumberTableCell, SVGMaskOverlay, SearchSvg, SelectableInput, SelectionContext, Separator, SettingsSvg, SidePanel, Slide, SlideContainer, Spin, StarSvg, SummaryMarker, Svg, Table, TableCell, Tbody, Text, TextBox, Textarea, TextareaCharCount, Thead, Time, Title, Tr, UITransition, Unit, UserSvg, ViewportLayout, Wheel, WheelGroup, WheelItem, actionRunEffect, anyMatchingRouteSignal, applySearch, arraySignalMembership, coarsePointerSignal, compareTwoJsValues, createAction, createAvailableConstraint, createRequestCanceller, createSearch, createSelectionKeyboardShortcuts, createSlot, defineNaviConfirmPopupOptions, enableDebugActions, enableDebugOnDocumentLoading, ensureDocumentStartViewTransition, filterTableSelection, formatDatetime, formatDay, formatDayRelative, formatMonth, formatNumber, formatTime, formatTimeRelative, getNowHours, getNowHoursRoundedToStep, interpolateText, isCellSelected, isColumnSelected, isRowSelected, isToday, languagesSignal, localStorageSignal, moveArrayItemByIndex, navBack, navForward, navIntegratedVia, navTo, naviI18n, openCallout, rawUrlPart, registerGlobalConstraint, reload, rerunActions, resource, route, routeAction, setBaseUrl, setPreferredLanguage, setSupportedLanguages, setupRoutes, stateSignal, stopLoad, stringifyTableSelectionValue, swapArrayItemByIndex, syncOwnedResourceToSignals, syncResourceToSignals, updateActions, useActionStatus, useArraySignalMembership, useAsyncData, useCalloutRequestClose, useCancelPrevious, useCellGridFromRows, useConstraintValidityState, useDependenciesDiff, useDisplayedLayoutEffect, useDocumentResource, useDocumentState, useDocumentUrl, useEditionController, useFocusGroup, useInputGroup, useKeyboardShortcuts, useNavState, useOrderedColumns, usePopupMode, useRouteStatus, useRunOnMount, useSearchText, useSelectableElement, useSelectionController, useSignalSync, useSlideValue, useStateArray, useTitleLevel, useUrlSearchParam, valueInLocalStorage, windowWidthSignal };
|
|
62429
62666
|
//# sourceMappingURL=jsenv_navi.js.map
|