@jsenv/navi 0.29.89 → 0.29.90
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 +78 -5
- package/dist/jsenv_navi.js.map +7 -7
- package/docs/AI_INSTRUCTIONS.md +15 -0
- package/docs/control_object.md +13 -1
- package/package.json +1 -1
package/dist/jsenv_navi.js
CHANGED
|
@@ -24747,9 +24747,6 @@ const useUIGroupStateController = (
|
|
|
24747
24747
|
if (!shouldPropagateStateToChild(childUIStateController)) {
|
|
24748
24748
|
return;
|
|
24749
24749
|
}
|
|
24750
|
-
if (childUIStateController.hasStateProp) {
|
|
24751
|
-
return;
|
|
24752
|
-
}
|
|
24753
24750
|
const childNewState = resolvedDistributeChildUIState(
|
|
24754
24751
|
groupUIState,
|
|
24755
24752
|
childUIStateController,
|
|
@@ -24757,6 +24754,22 @@ const useUIGroupStateController = (
|
|
|
24757
24754
|
if (childNewState === CANNOT_DERIVE) {
|
|
24758
24755
|
return;
|
|
24759
24756
|
}
|
|
24757
|
+
if (
|
|
24758
|
+
childUIStateController.hasStateProp &&
|
|
24759
|
+
!childUIStateController.props.signal
|
|
24760
|
+
) {
|
|
24761
|
+
// A child bound to a signal is placed like any other: bound is not
|
|
24762
|
+
// frozen, and the placement writes the signal, so both ends keep
|
|
24763
|
+
// saying the same thing. Only a child controlled by a `value` /
|
|
24764
|
+
// `checked` prop cannot be moved — its owner decides. Worth saying
|
|
24765
|
+
// out loud only when the two disagree: a child already showing what
|
|
24766
|
+
// the group would put there has lost nothing, and both being fed
|
|
24767
|
+
// from the same value is a legitimate way to write a group.
|
|
24768
|
+
if (
|
|
24769
|
+
!compareTwoJsValues(childNewState, childUIStateController.uiState)
|
|
24770
|
+
) ;
|
|
24771
|
+
return;
|
|
24772
|
+
}
|
|
24760
24773
|
childUIStateController.setUIState(childNewState, e);
|
|
24761
24774
|
},
|
|
24762
24775
|
setUIState: (newUIState, e) => {
|
|
@@ -25447,6 +25460,11 @@ const PROPAGATE_DOWN_EVENT_SET = new Set([
|
|
|
25447
25460
|
"propagate_down_set_ui_state",
|
|
25448
25461
|
"propagate_down_reset_ui_state",
|
|
25449
25462
|
"propagate_down_clear_ui_state",
|
|
25463
|
+
// The FIRST value handed down is one too: a control placed as it registers
|
|
25464
|
+
// (a group filling a child that just arrived, a picker filling its popup)
|
|
25465
|
+
// holds it from that moment, and a signal that kept saying nothing would have
|
|
25466
|
+
// the app and the screen disagree from the very first paint.
|
|
25467
|
+
"initial_state_push",
|
|
25450
25468
|
]);
|
|
25451
25469
|
const isPropagateDownEvent = (e) => {
|
|
25452
25470
|
return PROPAGATE_DOWN_EVENT_SET.has(e.type);
|
|
@@ -28092,6 +28110,7 @@ const createOpenController = (
|
|
|
28092
28110
|
// Last: the close effects above are what starts the exit transition the
|
|
28093
28111
|
// content must outlive (see popup_content_mount.js).
|
|
28094
28112
|
controller.unmountContent?.();
|
|
28113
|
+
controller.onOpenedChange?.(false);
|
|
28095
28114
|
};
|
|
28096
28115
|
const controller = {
|
|
28097
28116
|
opened: false,
|
|
@@ -28110,6 +28129,11 @@ const createOpenController = (
|
|
|
28110
28129
|
// The counterpart, set only when the popup was told to throw its content
|
|
28111
28130
|
// away on close (`unmountWhenClosed`). Called from performClose above.
|
|
28112
28131
|
unmountContent: null,
|
|
28132
|
+
// Told whenever `opened` actually changes, whatever asked for it — an
|
|
28133
|
+
// interaction, a command, a prop. What lets a `signal` prop reflect the
|
|
28134
|
+
// popup's real state (see useOpenPropsEffectOnOpenController), called once
|
|
28135
|
+
// the open/close has fully happened rather than mid-sequence.
|
|
28136
|
+
onOpenedChange: null,
|
|
28113
28137
|
open: (e, detail) => {
|
|
28114
28138
|
if (controller.opened || !controller.openEffect) {
|
|
28115
28139
|
return;
|
|
@@ -28212,6 +28236,7 @@ const createOpenController = (
|
|
|
28212
28236
|
openEffectReturnValue?.(closeEvent);
|
|
28213
28237
|
};
|
|
28214
28238
|
closeHandlers = openHandler(requestOpenEvent) || null;
|
|
28239
|
+
controller.onOpenedChange?.(true);
|
|
28215
28240
|
},
|
|
28216
28241
|
requestClose: (
|
|
28217
28242
|
e = new CustomEvent("programmatic", { detail: {} }),
|
|
@@ -28340,10 +28365,23 @@ const scheduleMountOpen = (run) => {
|
|
|
28340
28365
|
* `requestOpen`/`requestClose` wrappers).
|
|
28341
28366
|
*
|
|
28342
28367
|
* @param {{ open: (e: Event, detail?: object) => void, requestClose: (e: Event, detail?: object) => void, opened: boolean }} openController
|
|
28343
|
-
* @param {{ open?: boolean|"interaction", defaultOpen?: boolean|"interaction" }} props
|
|
28368
|
+
* @param {{ open?: boolean|"interaction", defaultOpen?: boolean|"interaction", signal?: import("@preact/signals").Signal<boolean> }} props
|
|
28344
28369
|
*/
|
|
28345
28370
|
const useOpenPropsEffectOnOpenController = (openController, props) => {
|
|
28346
|
-
const {
|
|
28371
|
+
const { signal, defaultOpen } = props;
|
|
28372
|
+
// What the caller holds, however they hold it: an `open` they re-render
|
|
28373
|
+
// themselves, or a `signal` this hook also writes (see onOpenedChange below).
|
|
28374
|
+
// Reading .value during render is what subscribes the popup to it.
|
|
28375
|
+
const open = signal ? signal.value : props.open;
|
|
28376
|
+
// Assigned on every render, like openEffect, so it always closes over the
|
|
28377
|
+
// latest prop: a popup that opens or closes on its own (Escape, backdrop, a
|
|
28378
|
+
// --navi-close command) writes what happened into the signal, so whoever
|
|
28379
|
+
// holds it always reads where the popup is.
|
|
28380
|
+
openController.onOpenedChange = signal
|
|
28381
|
+
? (opened) => {
|
|
28382
|
+
signal.value = opened;
|
|
28383
|
+
}
|
|
28384
|
+
: null;
|
|
28347
28385
|
// Tracks whether the effect below has ever run before — only the very
|
|
28348
28386
|
// first run gets the "mount already open" treatment (`open` truthy from
|
|
28349
28387
|
// the start, or the uncontrolled, mount-only `defaultOpen`); every
|
|
@@ -28396,6 +28434,12 @@ const useOpenPropsEffectOnOpenController = (openController, props) => {
|
|
|
28396
28434
|
{ isCancel: true },
|
|
28397
28435
|
);
|
|
28398
28436
|
}
|
|
28437
|
+
if (signal) {
|
|
28438
|
+
// The request can be refused (a busy form denying the close): the popup
|
|
28439
|
+
// then stays where it was, and the signal is told so — otherwise it
|
|
28440
|
+
// would keep saying "closed" about a popup still open.
|
|
28441
|
+
signal.value = openController.opened;
|
|
28442
|
+
}
|
|
28399
28443
|
}, [open]);
|
|
28400
28444
|
};
|
|
28401
28445
|
|
|
@@ -29820,6 +29864,14 @@ const css$X = /* css */`
|
|
|
29820
29864
|
* the focus only leaves it for something that asked by name (`autoFocus` on
|
|
29821
29865
|
* that element, which outranks whatever the dialog says).
|
|
29822
29866
|
* @param {boolean} [props.open] - Controlled open state.
|
|
29867
|
+
* @param {import("@preact/signals").Signal<boolean>} [props.signal] - The open
|
|
29868
|
+
* state said the way every navi control says it: the dialog opens and closes
|
|
29869
|
+
* to match the signal, and writes into it whenever it opens or closes on its
|
|
29870
|
+
* own (Escape, backdrop, a --navi-close command) — one binding to both drive
|
|
29871
|
+
* the dialog and know where it is, and the state stays where the app put it.
|
|
29872
|
+
* Excludes `open`; `onOpen`/`onClose` still fire. A signal holding `true` at
|
|
29873
|
+
* mount behaves like `defaultOpen`: the dialog was already open, no entrance
|
|
29874
|
+
* plays.
|
|
29823
29875
|
* @param {boolean|"interaction"} [props.defaultOpen] - Uncontrolled, mount-only
|
|
29824
29876
|
* initial open state. `true` plays no entrance animation: the dialog was
|
|
29825
29877
|
* already open when the page appeared, and nothing was ever shown as "closed"
|
|
@@ -29902,6 +29954,7 @@ const UncontrolledDialog = props => {
|
|
|
29902
29954
|
return jsx(ControlledDialog, {
|
|
29903
29955
|
...props,
|
|
29904
29956
|
open: undefined,
|
|
29957
|
+
signal: undefined,
|
|
29905
29958
|
defaultOpen: undefined,
|
|
29906
29959
|
onClose: undefined,
|
|
29907
29960
|
openController: openController,
|
|
@@ -31259,6 +31312,14 @@ const css$W = /* css */`
|
|
|
31259
31312
|
* the focus only leaves it for something that asked by name (`autoFocus` on
|
|
31260
31313
|
* that element, which outranks whatever the popover says).
|
|
31261
31314
|
* @param {boolean} [props.open] - Controlled open state.
|
|
31315
|
+
* @param {import("@preact/signals").Signal<boolean>} [props.signal] - The open
|
|
31316
|
+
* state said the way every navi control says it: the popover opens and closes
|
|
31317
|
+
* to match the signal, and writes into it whenever it opens or closes on its
|
|
31318
|
+
* own (Escape, light dismiss, a --navi-close command) — one binding to both
|
|
31319
|
+
* drive the popover and know where it is, and the state stays where the app
|
|
31320
|
+
* put it. Excludes `open`; `onOpen`/`onClose` still fire. A signal holding
|
|
31321
|
+
* `true` at mount behaves like `defaultOpen`: the popover was already open,
|
|
31322
|
+
* no entrance plays.
|
|
31262
31323
|
* @param {boolean|"interaction"} [props.defaultOpen] - Uncontrolled, mount-only
|
|
31263
31324
|
* initial open state. `true` plays no entrance animation: the popover was
|
|
31264
31325
|
* already open when the page appeared, and nothing was ever shown as "closed"
|
|
@@ -31339,6 +31400,7 @@ const UncontrolledPopover = props => {
|
|
|
31339
31400
|
return jsx(ControlledPopover, {
|
|
31340
31401
|
...props,
|
|
31341
31402
|
open: undefined,
|
|
31403
|
+
signal: undefined,
|
|
31342
31404
|
defaultOpen: undefined,
|
|
31343
31405
|
onClose: undefined,
|
|
31344
31406
|
openController: openController,
|
|
@@ -54163,6 +54225,9 @@ const css$A = /* css */`
|
|
|
54163
54225
|
* to `--dialog-maxmax-height` (`data-expand-y`).
|
|
54164
54226
|
* @param {boolean} [props.scrollCapture] - Forwarded as-is.
|
|
54165
54227
|
* @param {boolean} [props.open] - Forwarded as-is (controlled).
|
|
54228
|
+
* @param {import("@preact/signals").Signal<boolean>} [props.signal] -
|
|
54229
|
+
* Forwarded as-is: one binding to both drive the popup's open state and
|
|
54230
|
+
* know where it is (see `Dialog`/`Popover`'s own `signal`).
|
|
54166
54231
|
* @param {boolean} [props.defaultOpen] - Forwarded as-is (uncontrolled,
|
|
54167
54232
|
* mount-only).
|
|
54168
54233
|
* @param {(event: Event) => void} [props.onClose] - Forwarded as-is.
|
|
@@ -74247,6 +74312,12 @@ const css = /* css */`
|
|
|
74247
74312
|
* @param {object} props
|
|
74248
74313
|
* @param {boolean} [props.open] - Controlled open state, forwarded as-is to
|
|
74249
74314
|
* `Popup`'s own `open`.
|
|
74315
|
+
* @param {import("@preact/signals").Signal<boolean>} [props.signal] - The open
|
|
74316
|
+
* state said the way every navi control says it: the panel opens and closes
|
|
74317
|
+
* to match the signal, and writes into it whenever it opens or closes on its
|
|
74318
|
+
* own (Escape, swipe, a --navi-close command) — one binding to both drive
|
|
74319
|
+
* the panel and know where it is. Forwarded as-is to `Popup`; excludes
|
|
74320
|
+
* `open` (see `Dialog`/`Popover`'s own `signal`).
|
|
74250
74321
|
* @param {boolean} [props.defaultOpen] - Uncontrolled, mount-only initial
|
|
74251
74322
|
* open state, forwarded as-is to `Popup`. Neither this nor `open` is
|
|
74252
74323
|
* required at all for a purely command-driven panel (an `id` plus a
|
|
@@ -74313,6 +74384,7 @@ const css = /* css */`
|
|
|
74313
74384
|
*/
|
|
74314
74385
|
const SidePanel = ({
|
|
74315
74386
|
open,
|
|
74387
|
+
signal,
|
|
74316
74388
|
defaultOpen,
|
|
74317
74389
|
onClose,
|
|
74318
74390
|
children,
|
|
@@ -74334,6 +74406,7 @@ const SidePanel = ({
|
|
|
74334
74406
|
return jsx(Popup, {
|
|
74335
74407
|
mode: mode,
|
|
74336
74408
|
open: open,
|
|
74409
|
+
signal: signal,
|
|
74337
74410
|
defaultOpen: defaultOpen,
|
|
74338
74411
|
onClose: onClose,
|
|
74339
74412
|
layer: layer,
|