@foldkit/ui 0.112.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/LICENSE +21 -0
- package/README.md +67 -0
- package/dist/anchor.d.ts +38 -0
- package/dist/anchor.d.ts.map +1 -0
- package/dist/anchor.js +142 -0
- package/dist/animation/index.d.ts +49 -0
- package/dist/animation/index.d.ts.map +1 -0
- package/dist/animation/index.js +75 -0
- package/dist/animation/public.d.ts +3 -0
- package/dist/animation/public.d.ts.map +1 -0
- package/dist/animation/public.js +1 -0
- package/dist/animation/schema.d.ts +43 -0
- package/dist/animation/schema.d.ts.map +1 -0
- package/dist/animation/schema.js +41 -0
- package/dist/animation/update.d.ts +24 -0
- package/dist/animation/update.d.ts.map +1 -0
- package/dist/animation/update.js +67 -0
- package/dist/button/index.d.ts +17 -0
- package/dist/button/index.d.ts.map +1 -0
- package/dist/button/index.js +22 -0
- package/dist/button/public.d.ts +3 -0
- package/dist/button/public.d.ts.map +1 -0
- package/dist/button/public.js +1 -0
- package/dist/calendar/index.d.ts +462 -0
- package/dist/calendar/index.d.ts.map +1 -0
- package/dist/calendar/index.js +825 -0
- package/dist/calendar/public.d.ts +3 -0
- package/dist/calendar/public.d.ts.map +1 -0
- package/dist/calendar/public.js +1 -0
- package/dist/checkbox/index.d.ts +119 -0
- package/dist/checkbox/index.d.ts.map +1 -0
- package/dist/checkbox/index.js +111 -0
- package/dist/checkbox/public.d.ts +3 -0
- package/dist/checkbox/public.d.ts.map +1 -0
- package/dist/checkbox/public.js +1 -0
- package/dist/combobox/multi.d.ts +183 -0
- package/dist/combobox/multi.d.ts.map +1 -0
- package/dist/combobox/multi.js +81 -0
- package/dist/combobox/multiPublic.d.ts +3 -0
- package/dist/combobox/multiPublic.d.ts.map +1 -0
- package/dist/combobox/multiPublic.js +1 -0
- package/dist/combobox/public.d.ts +7 -0
- package/dist/combobox/public.d.ts.map +1 -0
- package/dist/combobox/public.js +3 -0
- package/dist/combobox/shared.d.ts +423 -0
- package/dist/combobox/shared.d.ts.map +1 -0
- package/dist/combobox/shared.js +708 -0
- package/dist/combobox/single.d.ts +198 -0
- package/dist/combobox/single.d.ts.map +1 -0
- package/dist/combobox/single.js +106 -0
- package/dist/datePicker/index.d.ts +457 -0
- package/dist/datePicker/index.d.ts.map +1 -0
- package/dist/datePicker/index.js +318 -0
- package/dist/datePicker/public.d.ts +3 -0
- package/dist/datePicker/public.d.ts.map +1 -0
- package/dist/datePicker/public.js +1 -0
- package/dist/dialog/index.d.ts +160 -0
- package/dist/dialog/index.d.ts.map +1 -0
- package/dist/dialog/index.js +211 -0
- package/dist/dialog/public.d.ts +3 -0
- package/dist/dialog/public.d.ts.map +1 -0
- package/dist/dialog/public.js +1 -0
- package/dist/disclosure/index.d.ts +110 -0
- package/dist/disclosure/index.d.ts.map +1 -0
- package/dist/disclosure/index.js +111 -0
- package/dist/disclosure/public.d.ts +3 -0
- package/dist/disclosure/public.d.ts.map +1 -0
- package/dist/disclosure/public.js +1 -0
- package/dist/dragAndDrop/index.d.ts +540 -0
- package/dist/dragAndDrop/index.d.ts.map +1 -0
- package/dist/dragAndDrop/index.js +535 -0
- package/dist/dragAndDrop/public.d.ts +3 -0
- package/dist/dragAndDrop/public.d.ts.map +1 -0
- package/dist/dragAndDrop/public.js +1 -0
- package/dist/fieldset/index.d.ts +21 -0
- package/dist/fieldset/index.d.ts.map +1 -0
- package/dist/fieldset/index.js +25 -0
- package/dist/fieldset/public.d.ts +3 -0
- package/dist/fieldset/public.d.ts.map +1 -0
- package/dist/fieldset/public.js +1 -0
- package/dist/fileDrop/index.d.ts +109 -0
- package/dist/fileDrop/index.d.ts.map +1 -0
- package/dist/fileDrop/index.js +127 -0
- package/dist/fileDrop/public.d.ts +3 -0
- package/dist/fileDrop/public.d.ts.map +1 -0
- package/dist/fileDrop/public.js +1 -0
- package/dist/group.d.ts +8 -0
- package/dist/group.d.ts.map +1 -0
- package/dist/group.js +13 -0
- package/dist/index.d.ts +25 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +24 -0
- package/dist/input/index.d.ts +26 -0
- package/dist/input/index.d.ts.map +1 -0
- package/dist/input/index.js +43 -0
- package/dist/input/public.d.ts +3 -0
- package/dist/input/public.d.ts.map +1 -0
- package/dist/input/public.js +1 -0
- package/dist/internal/optionExtensions.d.ts +6 -0
- package/dist/internal/optionExtensions.d.ts.map +1 -0
- package/dist/internal/optionExtensions.js +2 -0
- package/dist/keyboard.d.ts +6 -0
- package/dist/keyboard.d.ts.map +1 -0
- package/dist/keyboard.js +9 -0
- package/dist/listbox/multi.d.ts +189 -0
- package/dist/listbox/multi.d.ts.map +1 -0
- package/dist/listbox/multi.js +65 -0
- package/dist/listbox/multiPublic.d.ts +3 -0
- package/dist/listbox/multiPublic.d.ts.map +1 -0
- package/dist/listbox/multiPublic.js +1 -0
- package/dist/listbox/public.d.ts +7 -0
- package/dist/listbox/public.d.ts.map +1 -0
- package/dist/listbox/public.js +3 -0
- package/dist/listbox/shared.d.ts +432 -0
- package/dist/listbox/shared.d.ts.map +1 -0
- package/dist/listbox/shared.js +670 -0
- package/dist/listbox/single.d.ts +207 -0
- package/dist/listbox/single.d.ts.map +1 -0
- package/dist/listbox/single.js +73 -0
- package/dist/menu/index.d.ts +368 -0
- package/dist/menu/index.d.ts.map +1 -0
- package/dist/menu/index.js +682 -0
- package/dist/menu/public.d.ts +4 -0
- package/dist/menu/public.d.ts.map +1 -0
- package/dist/menu/public.js +1 -0
- package/dist/popover/index.d.ts +267 -0
- package/dist/popover/index.d.ts.map +1 -0
- package/dist/popover/index.js +346 -0
- package/dist/popover/public.d.ts +4 -0
- package/dist/popover/public.d.ts.map +1 -0
- package/dist/popover/public.js +1 -0
- package/dist/radioGroup/index.d.ts +169 -0
- package/dist/radioGroup/index.d.ts.map +1 -0
- package/dist/radioGroup/index.js +197 -0
- package/dist/radioGroup/public.d.ts +3 -0
- package/dist/radioGroup/public.d.ts.map +1 -0
- package/dist/radioGroup/public.js +1 -0
- package/dist/select/index.d.ts +24 -0
- package/dist/select/index.d.ts.map +1 -0
- package/dist/select/index.js +40 -0
- package/dist/select/public.d.ts +3 -0
- package/dist/select/public.d.ts.map +1 -0
- package/dist/select/public.js +1 -0
- package/dist/slider/index.d.ts +318 -0
- package/dist/slider/index.d.ts.map +1 -0
- package/dist/slider/index.js +337 -0
- package/dist/slider/public.d.ts +3 -0
- package/dist/slider/public.d.ts.map +1 -0
- package/dist/slider/public.js +1 -0
- package/dist/switch/index.d.ts +99 -0
- package/dist/switch/index.d.ts.map +1 -0
- package/dist/switch/index.js +107 -0
- package/dist/switch/public.d.ts +3 -0
- package/dist/switch/public.d.ts.map +1 -0
- package/dist/switch/public.js +1 -0
- package/dist/tabs/index.d.ts +155 -0
- package/dist/tabs/index.d.ts.map +1 -0
- package/dist/tabs/index.js +185 -0
- package/dist/tabs/public.d.ts +3 -0
- package/dist/tabs/public.d.ts.map +1 -0
- package/dist/tabs/public.js +1 -0
- package/dist/test/apps/disabledButton.d.ts +38 -0
- package/dist/test/apps/disabledButton.d.ts.map +1 -0
- package/dist/test/apps/disabledButton.js +71 -0
- package/dist/textarea/index.d.ts +26 -0
- package/dist/textarea/index.d.ts.map +1 -0
- package/dist/textarea/index.js +44 -0
- package/dist/textarea/public.d.ts +3 -0
- package/dist/textarea/public.d.ts.map +1 -0
- package/dist/textarea/public.js +1 -0
- package/dist/toast/index.d.ts +608 -0
- package/dist/toast/index.d.ts.map +1 -0
- package/dist/toast/index.js +146 -0
- package/dist/toast/public.d.ts +4 -0
- package/dist/toast/public.d.ts.map +1 -0
- package/dist/toast/public.js +1 -0
- package/dist/toast/schema.d.ts +154 -0
- package/dist/toast/schema.d.ts.map +1 -0
- package/dist/toast/schema.js +93 -0
- package/dist/toast/update.d.ts +510 -0
- package/dist/toast/update.d.ts.map +1 -0
- package/dist/toast/update.js +225 -0
- package/dist/tooltip/index.d.ts +170 -0
- package/dist/tooltip/index.d.ts.map +1 -0
- package/dist/tooltip/index.js +253 -0
- package/dist/tooltip/public.d.ts +4 -0
- package/dist/tooltip/public.d.ts.map +1 -0
- package/dist/tooltip/public.js +1 -0
- package/dist/typeahead.d.ts +4 -0
- package/dist/typeahead.d.ts.map +1 -0
- package/dist/typeahead.js +14 -0
- package/dist/virtualList/index.d.ts +203 -0
- package/dist/virtualList/index.d.ts.map +1 -0
- package/dist/virtualList/index.js +392 -0
- package/dist/virtualList/public.d.ts +3 -0
- package/dist/virtualList/public.d.ts.map +1 -0
- package/dist/virtualList/public.js +1 -0
- package/dist/vitest-setup.d.ts +2 -0
- package/dist/vitest-setup.d.ts.map +1 -0
- package/dist/vitest-setup.js +2 -0
- package/package.json +161 -0
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { init, create, Model, Message, OutMessage, Selected, SelectedItem, CompletedLockScroll, CompletedUnlockScroll, CompletedInertOthers, CompletedRestoreInert, CompletedFocusItems, CompletedFocusButton, CompletedScrollIntoView, CompletedClickItem, CompletedAnchorMenu, CompletedPortalMenuBackdrop, AnchorMenu, PortalMenuBackdrop, ClearedSearch, GotAnimationMessage, LockScroll, UnlockScroll, InertOthers, RestoreInert, FocusItems, FocusButton, ScrollIntoView, ClickItem, DelayClearSearch, DetectMovementOrAnimationEnd, } from './index.js';
|
|
2
|
+
export type { ActivationTrigger, Opened, Closed, BlurredItems, ActivatedItem, DeactivatedItem, MovedPointerOverItem, RequestedItemClick, Searched, PressedPointerOnButton, ReleasedPointerOnItems, IgnoredMouseClick, SuppressedSpaceScroll, InitConfig, ViewInputs, ItemConfig, GroupHeading, } from './index.js';
|
|
3
|
+
export type { AnchorConfig } from '../anchor.js';
|
|
4
|
+
//# sourceMappingURL=public.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"public.d.ts","sourceRoot":"","sources":["../../src/menu/public.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,IAAI,EACJ,MAAM,EACN,KAAK,EACL,OAAO,EACP,UAAU,EACV,QAAQ,EACR,YAAY,EACZ,mBAAmB,EACnB,qBAAqB,EACrB,oBAAoB,EACpB,qBAAqB,EACrB,mBAAmB,EACnB,oBAAoB,EACpB,uBAAuB,EACvB,kBAAkB,EAClB,mBAAmB,EACnB,2BAA2B,EAC3B,UAAU,EACV,kBAAkB,EAClB,aAAa,EACb,mBAAmB,EACnB,UAAU,EACV,YAAY,EACZ,WAAW,EACX,YAAY,EACZ,UAAU,EACV,WAAW,EACX,cAAc,EACd,SAAS,EACT,gBAAgB,EAChB,4BAA4B,GAC7B,MAAM,YAAY,CAAA;AAEnB,YAAY,EACV,iBAAiB,EACjB,MAAM,EACN,MAAM,EACN,YAAY,EACZ,aAAa,EACb,eAAe,EACf,oBAAoB,EACpB,kBAAkB,EAClB,QAAQ,EACR,sBAAsB,EACtB,sBAAsB,EACtB,iBAAiB,EACjB,qBAAqB,EACrB,UAAU,EACV,UAAU,EACV,UAAU,EACV,YAAY,GACb,MAAM,YAAY,CAAA;AAEnB,YAAY,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { init, create, Model, Message, OutMessage, Selected, SelectedItem, CompletedLockScroll, CompletedUnlockScroll, CompletedInertOthers, CompletedRestoreInert, CompletedFocusItems, CompletedFocusButton, CompletedScrollIntoView, CompletedClickItem, CompletedAnchorMenu, CompletedPortalMenuBackdrop, AnchorMenu, PortalMenuBackdrop, ClearedSearch, GotAnimationMessage, LockScroll, UnlockScroll, InertOthers, RestoreInert, FocusItems, FocusButton, ScrollIntoView, ClickItem, DelayClearSearch, DetectMovementOrAnimationEnd, } from './index.js';
|
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
import { Effect, Option, Schema as S } from 'effect';
|
|
2
|
+
import * as Command from 'foldkit/command';
|
|
3
|
+
import { type ChildAttribute, type Html } from 'foldkit/html';
|
|
4
|
+
import * as Mount from 'foldkit/mount';
|
|
5
|
+
import { AnchorConfig } from '../anchor.js';
|
|
6
|
+
/** Schema for the popover component's state, tracking open/closed status and animation lifecycle. */
|
|
7
|
+
export declare const Model: S.Struct<{
|
|
8
|
+
readonly id: S.String;
|
|
9
|
+
readonly isOpen: S.Boolean;
|
|
10
|
+
readonly isAnimated: S.Boolean;
|
|
11
|
+
readonly isModal: S.Boolean;
|
|
12
|
+
readonly contentFocus: S.Boolean;
|
|
13
|
+
readonly animation: S.Struct<{
|
|
14
|
+
readonly id: S.String;
|
|
15
|
+
readonly isShowing: S.Boolean;
|
|
16
|
+
readonly transitionState: S.Literals<readonly ["Idle", "EnterStart", "EnterAnimating", "LeaveStart", "LeaveAnimating"]>;
|
|
17
|
+
}>;
|
|
18
|
+
readonly maybeLastButtonPointerType: S.Option<S.String>;
|
|
19
|
+
}>;
|
|
20
|
+
export type Model = typeof Model.Type;
|
|
21
|
+
/** Sent when the popover should open via button click or keyboard activation. */
|
|
22
|
+
export declare const RequestedOpen: import("foldkit/schema").CallableTaggedStruct<"RequestedOpen", {}>;
|
|
23
|
+
/** Sent when the popover should close via Escape key or backdrop click. Returns focus to the button. */
|
|
24
|
+
export declare const RequestedClose: import("foldkit/schema").CallableTaggedStruct<"RequestedClose", {}>;
|
|
25
|
+
/** Sent when the popover panel loses focus. Does NOT return focus to the button. */
|
|
26
|
+
export declare const BlurredPanel: import("foldkit/schema").CallableTaggedStruct<"BlurredPanel", {}>;
|
|
27
|
+
/** Sent when the user presses a pointer device on the popover button. Records pointer type and toggles for mouse. */
|
|
28
|
+
export declare const PressedPointerOnButton: import("foldkit/schema").CallableTaggedStruct<"PressedPointerOnButton", {
|
|
29
|
+
pointerType: S.String;
|
|
30
|
+
button: S.Number;
|
|
31
|
+
}>;
|
|
32
|
+
/** Sent when the focus-panel command completes after opening the popover. */
|
|
33
|
+
export declare const CompletedFocusPanel: import("foldkit/schema").CallableTaggedStruct<"CompletedFocusPanel", {}>;
|
|
34
|
+
/** Sent when the focus-button command completes after closing. */
|
|
35
|
+
export declare const CompletedFocusButton: import("foldkit/schema").CallableTaggedStruct<"CompletedFocusButton", {}>;
|
|
36
|
+
/** Sent when the scroll lock command completes. */
|
|
37
|
+
export declare const CompletedLockScroll: import("foldkit/schema").CallableTaggedStruct<"CompletedLockScroll", {}>;
|
|
38
|
+
/** Sent when the scroll unlock command completes. */
|
|
39
|
+
export declare const CompletedUnlockScroll: import("foldkit/schema").CallableTaggedStruct<"CompletedUnlockScroll", {}>;
|
|
40
|
+
/** Sent when the inert-others command completes. */
|
|
41
|
+
export declare const CompletedInertOthers: import("foldkit/schema").CallableTaggedStruct<"CompletedInertOthers", {}>;
|
|
42
|
+
/** Sent when the restore-inert command completes. */
|
|
43
|
+
export declare const CompletedRestoreInert: import("foldkit/schema").CallableTaggedStruct<"CompletedRestoreInert", {}>;
|
|
44
|
+
/** Sent when a mouse click on the button is ignored because pointer-down already handled the toggle. */
|
|
45
|
+
export declare const IgnoredMouseClick: import("foldkit/schema").CallableTaggedStruct<"IgnoredMouseClick", {}>;
|
|
46
|
+
/** Sent when a Space key-up is captured to prevent page scrolling. */
|
|
47
|
+
export declare const SuppressedSpaceScroll: import("foldkit/schema").CallableTaggedStruct<"SuppressedSpaceScroll", {}>;
|
|
48
|
+
/** Sent when the popover panel mounts and Floating UI has positioned it. Update no-ops; the side effect is the act of positioning, surfaced for DevTools observability. */
|
|
49
|
+
export declare const CompletedAnchorPopover: import("foldkit/schema").CallableTaggedStruct<"CompletedAnchorPopover", {}>;
|
|
50
|
+
/** Sent when the popover backdrop mounts and is portaled to the document body. Update no-ops; surfaces the portal side effect for DevTools. */
|
|
51
|
+
export declare const CompletedPortalPopoverBackdrop: import("foldkit/schema").CallableTaggedStruct<"CompletedPortalPopoverBackdrop", {}>;
|
|
52
|
+
/** Wraps an Animation submodel message for delegation. */
|
|
53
|
+
export declare const GotAnimationMessage: import("foldkit/schema").CallableTaggedStruct<"GotAnimationMessage", {
|
|
54
|
+
message: S.Union<[import("foldkit/schema").CallableTaggedStruct<"Showed", {}>, import("foldkit/schema").CallableTaggedStruct<"Hid", {}>, import("foldkit/schema").CallableTaggedStruct<"AdvancedAnimationFrame", {}>, import("foldkit/schema").CallableTaggedStruct<"EndedAnimation", {}>]>;
|
|
55
|
+
}>;
|
|
56
|
+
/** Union of all messages the popover component can produce. */
|
|
57
|
+
export declare const Message: S.Union<[
|
|
58
|
+
typeof RequestedOpen,
|
|
59
|
+
typeof RequestedClose,
|
|
60
|
+
typeof BlurredPanel,
|
|
61
|
+
typeof PressedPointerOnButton,
|
|
62
|
+
typeof CompletedFocusPanel,
|
|
63
|
+
typeof CompletedFocusButton,
|
|
64
|
+
typeof CompletedLockScroll,
|
|
65
|
+
typeof CompletedUnlockScroll,
|
|
66
|
+
typeof CompletedInertOthers,
|
|
67
|
+
typeof CompletedRestoreInert,
|
|
68
|
+
typeof IgnoredMouseClick,
|
|
69
|
+
typeof SuppressedSpaceScroll,
|
|
70
|
+
typeof CompletedAnchorPopover,
|
|
71
|
+
typeof CompletedPortalPopoverBackdrop,
|
|
72
|
+
typeof GotAnimationMessage
|
|
73
|
+
]>;
|
|
74
|
+
export type RequestedOpen = typeof RequestedOpen.Type;
|
|
75
|
+
export type RequestedClose = typeof RequestedClose.Type;
|
|
76
|
+
export type BlurredPanel = typeof BlurredPanel.Type;
|
|
77
|
+
export type PressedPointerOnButton = typeof PressedPointerOnButton.Type;
|
|
78
|
+
export type IgnoredMouseClick = typeof IgnoredMouseClick.Type;
|
|
79
|
+
export type SuppressedSpaceScroll = typeof SuppressedSpaceScroll.Type;
|
|
80
|
+
export type Message = typeof Message.Type;
|
|
81
|
+
/** Sent to the parent after the popover transitions to its open state. Fires once `update` has processed `RequestedOpen` and `isOpen` reflects the new state. */
|
|
82
|
+
export declare const Opened: import("foldkit/schema").CallableTaggedStruct<"Opened", {}>;
|
|
83
|
+
/** Sent to the parent after the popover transitions to its closed state. */
|
|
84
|
+
export declare const Closed: import("foldkit/schema").CallableTaggedStruct<"Closed", {}>;
|
|
85
|
+
/** Union of out-messages the popover component can produce. Parents reacting to open/close transitions (e.g. to reset related state, fire analytics) read this from the third element of `update`'s return tuple. */
|
|
86
|
+
export declare const OutMessage: S.Union<readonly [import("foldkit/schema").CallableTaggedStruct<"Opened", {}>, import("foldkit/schema").CallableTaggedStruct<"Closed", {}>]>;
|
|
87
|
+
export type OutMessage = typeof OutMessage.Type;
|
|
88
|
+
export type Opened = typeof Opened.Type;
|
|
89
|
+
export type Closed = typeof Closed.Type;
|
|
90
|
+
/** Configuration for creating a popover model with `init`. `isAnimated` enables animation coordination (default `false`). `isModal` locks page scroll and inerts other elements when open (default `false`). `contentFocus` hands focus ownership to the consumer. The panel is not focusable and does not close on blur, so the consumer must focus a descendant on open and close the popover on its own blur rules (default `false`). */
|
|
91
|
+
export type InitConfig = Readonly<{
|
|
92
|
+
id: string;
|
|
93
|
+
isAnimated?: boolean;
|
|
94
|
+
isModal?: boolean;
|
|
95
|
+
contentFocus?: boolean;
|
|
96
|
+
}>;
|
|
97
|
+
/** Creates an initial popover model from a config. Defaults to closed. */
|
|
98
|
+
export declare const init: (config: InitConfig) => Model;
|
|
99
|
+
type UpdateReturn = readonly [
|
|
100
|
+
Model,
|
|
101
|
+
ReadonlyArray<Command.Command<Message>>,
|
|
102
|
+
Option.Option<OutMessage>
|
|
103
|
+
];
|
|
104
|
+
/** Prevents page scrolling while the popover is open in modal mode. */
|
|
105
|
+
export declare const LockScroll: Command.CommandDefinitionNoArgs<"LockScroll", Effect.Effect<{
|
|
106
|
+
readonly _tag: "CompletedLockScroll";
|
|
107
|
+
}, never, never>>;
|
|
108
|
+
/** Re-enables page scrolling after the popover closes. */
|
|
109
|
+
export declare const UnlockScroll: Command.CommandDefinitionNoArgs<"UnlockScroll", Effect.Effect<{
|
|
110
|
+
readonly _tag: "CompletedUnlockScroll";
|
|
111
|
+
}, never, never>>;
|
|
112
|
+
/** Marks all elements outside the popover as inert for modal behavior. */
|
|
113
|
+
export declare const InertOthers: Command.CommandDefinitionWithArgs<"InertOthers", {
|
|
114
|
+
id: S.String;
|
|
115
|
+
}, Effect.Effect<{
|
|
116
|
+
readonly _tag: "CompletedInertOthers";
|
|
117
|
+
}, never, never>>;
|
|
118
|
+
/** Removes the inert attribute from elements outside the popover. */
|
|
119
|
+
export declare const RestoreInert: Command.CommandDefinitionWithArgs<"RestoreInert", {
|
|
120
|
+
id: S.String;
|
|
121
|
+
}, Effect.Effect<{
|
|
122
|
+
readonly _tag: "CompletedRestoreInert";
|
|
123
|
+
}, never, never>>;
|
|
124
|
+
/** Moves focus to the popover panel after opening. */
|
|
125
|
+
export declare const FocusPanel: Command.CommandDefinitionWithArgs<"FocusPanel", {
|
|
126
|
+
id: S.String;
|
|
127
|
+
}, Effect.Effect<{
|
|
128
|
+
readonly _tag: "CompletedFocusPanel";
|
|
129
|
+
}, never, never>>;
|
|
130
|
+
/** Moves focus back to the popover button after closing. */
|
|
131
|
+
export declare const FocusButton: Command.CommandDefinitionWithArgs<"FocusButton", {
|
|
132
|
+
id: S.String;
|
|
133
|
+
}, Effect.Effect<{
|
|
134
|
+
readonly _tag: "CompletedFocusButton";
|
|
135
|
+
}, never, never>>;
|
|
136
|
+
/** Detects whether the popover button moved or the leave animation ended. Whichever comes first; both outcomes signal the Animation submodel that leave is complete. */
|
|
137
|
+
export declare const DetectMovementOrAnimationEnd: Command.CommandDefinitionWithArgs<"DetectMovementOrAnimationEnd", {
|
|
138
|
+
id: S.String;
|
|
139
|
+
}, Effect.Effect<{
|
|
140
|
+
readonly _tag: "GotAnimationMessage";
|
|
141
|
+
readonly message: {
|
|
142
|
+
readonly _tag: "Showed";
|
|
143
|
+
} | {
|
|
144
|
+
readonly _tag: "Hid";
|
|
145
|
+
} | {
|
|
146
|
+
readonly _tag: "AdvancedAnimationFrame";
|
|
147
|
+
} | {
|
|
148
|
+
readonly _tag: "EndedAnimation";
|
|
149
|
+
};
|
|
150
|
+
}, never, never>>;
|
|
151
|
+
/** Processes a popover message and returns the next model, commands, and optional OutMessage. */
|
|
152
|
+
export declare const update: (model: Model, message: Message) => UpdateReturn;
|
|
153
|
+
/** The anchor-positioning Mount this Popover renders on its panel. Exposed so
|
|
154
|
+
* Scene tests can call `Scene.Mount.resolve(AnchorPopover, CompletedAnchorPopover())`
|
|
155
|
+
* to acknowledge the mount produced by the rendered panel. */
|
|
156
|
+
export declare const AnchorPopover: Mount.MountDefinitionWithArgs<"AnchorPopover", {
|
|
157
|
+
buttonId: S.String;
|
|
158
|
+
anchor: S.Struct<{
|
|
159
|
+
readonly placement: S.optional<S.Literals<readonly ["top", "right", "bottom", "left", "top-start", "top-end", "right-start", "right-end", "bottom-start", "bottom-end", "left-start", "left-end"]>>;
|
|
160
|
+
readonly gap: S.optional<S.Number>;
|
|
161
|
+
readonly offset: S.optional<S.Number>;
|
|
162
|
+
readonly padding: S.optional<S.Number>;
|
|
163
|
+
readonly portal: S.optional<S.Boolean>;
|
|
164
|
+
}>;
|
|
165
|
+
focusSelector: S.optional<S.String>;
|
|
166
|
+
}, {
|
|
167
|
+
readonly _tag: "CompletedAnchorPopover";
|
|
168
|
+
}>;
|
|
169
|
+
/** The backdrop-portaling Mount this Popover renders. Exposed so Scene tests can
|
|
170
|
+
* call `Scene.Mount.resolve(PortalPopoverBackdrop, CompletedPortalPopoverBackdrop())` to
|
|
171
|
+
* acknowledge the mount produced by the rendered backdrop. */
|
|
172
|
+
export declare const PortalPopoverBackdrop: Mount.MountDefinitionNoArgs<"PortalPopoverBackdrop", {
|
|
173
|
+
readonly _tag: "CompletedPortalPopoverBackdrop";
|
|
174
|
+
}>;
|
|
175
|
+
/** Programmatically opens the popover, updating the model and returning
|
|
176
|
+
* focus and modal commands plus an `Opened` OutMessage. */
|
|
177
|
+
export declare const open: (model: Model) => UpdateReturn;
|
|
178
|
+
/** Programmatically closes the popover, updating the model and returning
|
|
179
|
+
* focus and modal commands plus a `Closed` OutMessage when it was open. */
|
|
180
|
+
export declare const close: (model: Model) => UpdateReturn;
|
|
181
|
+
/** Render-time payload published to the consumer's `toView`.
|
|
182
|
+
*
|
|
183
|
+
* - `button`: attribute bundle for the trigger button.
|
|
184
|
+
* - `panel`: attribute bundle for the floating panel. Includes the
|
|
185
|
+
* anchor Mount that positions the panel via Floating UI, ARIA
|
|
186
|
+
* linkage to the button, and panel keydown/blur handlers.
|
|
187
|
+
* - `backdrop`: attribute bundle for the modal backdrop. Includes the
|
|
188
|
+
* portal Mount that moves the backdrop to document.body. The
|
|
189
|
+
* backdrop's OnClick closes the popover.
|
|
190
|
+
* - `isVisible`: derived from `isOpen` and the Animation
|
|
191
|
+
* `transitionState`. The consumer renders the panel + backdrop only
|
|
192
|
+
* while this is true. */
|
|
193
|
+
export type RenderInfo = Readonly<{
|
|
194
|
+
button: ReadonlyArray<ChildAttribute>;
|
|
195
|
+
panel: ReadonlyArray<ChildAttribute>;
|
|
196
|
+
backdrop: ReadonlyArray<ChildAttribute>;
|
|
197
|
+
isVisible: boolean;
|
|
198
|
+
}>;
|
|
199
|
+
/** Per-render view inputs passed to `view` via `h.submodel`'s `viewInputs` field. */
|
|
200
|
+
export type ViewInputs = Readonly<{
|
|
201
|
+
anchor: AnchorConfig;
|
|
202
|
+
toView: (render: RenderInfo) => Html;
|
|
203
|
+
isDisabled?: boolean;
|
|
204
|
+
focusSelector?: string;
|
|
205
|
+
}>;
|
|
206
|
+
/** Renders a headless popover with a trigger button and a floating panel. */
|
|
207
|
+
export declare const view: import("foldkit/submodel").View<{
|
|
208
|
+
readonly id: string;
|
|
209
|
+
readonly isOpen: boolean;
|
|
210
|
+
readonly isAnimated: boolean;
|
|
211
|
+
readonly isModal: boolean;
|
|
212
|
+
readonly contentFocus: boolean;
|
|
213
|
+
readonly animation: {
|
|
214
|
+
readonly id: string;
|
|
215
|
+
readonly isShowing: boolean;
|
|
216
|
+
readonly transitionState: "Idle" | "EnterStart" | "EnterAnimating" | "LeaveStart" | "LeaveAnimating";
|
|
217
|
+
};
|
|
218
|
+
readonly maybeLastButtonPointerType: Option.Option<string>;
|
|
219
|
+
}, {
|
|
220
|
+
readonly _tag: "RequestedOpen";
|
|
221
|
+
} | {
|
|
222
|
+
readonly _tag: "RequestedClose";
|
|
223
|
+
} | {
|
|
224
|
+
readonly _tag: "BlurredPanel";
|
|
225
|
+
} | {
|
|
226
|
+
readonly _tag: "PressedPointerOnButton";
|
|
227
|
+
readonly pointerType: string;
|
|
228
|
+
readonly button: number;
|
|
229
|
+
} | {
|
|
230
|
+
readonly _tag: "CompletedFocusPanel";
|
|
231
|
+
} | {
|
|
232
|
+
readonly _tag: "CompletedFocusButton";
|
|
233
|
+
} | {
|
|
234
|
+
readonly _tag: "CompletedLockScroll";
|
|
235
|
+
} | {
|
|
236
|
+
readonly _tag: "CompletedUnlockScroll";
|
|
237
|
+
} | {
|
|
238
|
+
readonly _tag: "CompletedInertOthers";
|
|
239
|
+
} | {
|
|
240
|
+
readonly _tag: "CompletedRestoreInert";
|
|
241
|
+
} | {
|
|
242
|
+
readonly _tag: "IgnoredMouseClick";
|
|
243
|
+
} | {
|
|
244
|
+
readonly _tag: "SuppressedSpaceScroll";
|
|
245
|
+
} | {
|
|
246
|
+
readonly _tag: "CompletedAnchorPopover";
|
|
247
|
+
} | {
|
|
248
|
+
readonly _tag: "CompletedPortalPopoverBackdrop";
|
|
249
|
+
} | {
|
|
250
|
+
readonly _tag: "GotAnimationMessage";
|
|
251
|
+
readonly message: {
|
|
252
|
+
readonly _tag: "Showed";
|
|
253
|
+
} | {
|
|
254
|
+
readonly _tag: "Hid";
|
|
255
|
+
} | {
|
|
256
|
+
readonly _tag: "AdvancedAnimationFrame";
|
|
257
|
+
} | {
|
|
258
|
+
readonly _tag: "EndedAnimation";
|
|
259
|
+
};
|
|
260
|
+
}, Readonly<{
|
|
261
|
+
anchor: AnchorConfig;
|
|
262
|
+
toView: (render: RenderInfo) => Html;
|
|
263
|
+
isDisabled?: boolean;
|
|
264
|
+
focusSelector?: string;
|
|
265
|
+
}>>;
|
|
266
|
+
export {};
|
|
267
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/popover/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
import { Array, Effect, Equal, Match as M, Option, Schema as S } from 'effect';
|
|
2
|
+
import * as Command from 'foldkit/command';
|
|
3
|
+
import * as Dom from 'foldkit/dom';
|
|
4
|
+
import { childAttributes, html, } from 'foldkit/html';
|
|
5
|
+
import { m } from 'foldkit/message';
|
|
6
|
+
import * as Mount from 'foldkit/mount';
|
|
7
|
+
import { evo } from 'foldkit/struct';
|
|
8
|
+
import { defineView } from 'foldkit/submodel';
|
|
9
|
+
import { AnchorConfig, anchorSetup, portalToBody } from '../anchor.js';
|
|
10
|
+
// NOTE: Animation imports are split across schema + update to avoid a circular
|
|
11
|
+
// dependency: animation → html → runtime → devtools → popover → animation.
|
|
12
|
+
// The barrel (../animation) imports from html, which starts the cycle.
|
|
13
|
+
import { EndedAnimation as AnimationEndedAnimation, Hid as AnimationHid, Message as AnimationMessage, Model as AnimationModel, Showed as AnimationShowed, init as animationInit, } from '../animation/schema.js';
|
|
14
|
+
import { update as animationUpdate } from '../animation/update.js';
|
|
15
|
+
import * as OptionExt from '../internal/optionExtensions.js';
|
|
16
|
+
// MODEL
|
|
17
|
+
/** Schema for the popover component's state, tracking open/closed status and animation lifecycle. */
|
|
18
|
+
export const Model = S.Struct({
|
|
19
|
+
id: S.String,
|
|
20
|
+
isOpen: S.Boolean,
|
|
21
|
+
isAnimated: S.Boolean,
|
|
22
|
+
isModal: S.Boolean,
|
|
23
|
+
contentFocus: S.Boolean,
|
|
24
|
+
animation: AnimationModel,
|
|
25
|
+
maybeLastButtonPointerType: S.Option(S.String),
|
|
26
|
+
});
|
|
27
|
+
// MESSAGE
|
|
28
|
+
/** Sent when the popover should open via button click or keyboard activation. */
|
|
29
|
+
export const RequestedOpen = m('RequestedOpen');
|
|
30
|
+
/** Sent when the popover should close via Escape key or backdrop click. Returns focus to the button. */
|
|
31
|
+
export const RequestedClose = m('RequestedClose');
|
|
32
|
+
/** Sent when the popover panel loses focus. Does NOT return focus to the button. */
|
|
33
|
+
export const BlurredPanel = m('BlurredPanel');
|
|
34
|
+
/** Sent when the user presses a pointer device on the popover button. Records pointer type and toggles for mouse. */
|
|
35
|
+
export const PressedPointerOnButton = m('PressedPointerOnButton', {
|
|
36
|
+
pointerType: S.String,
|
|
37
|
+
button: S.Number,
|
|
38
|
+
});
|
|
39
|
+
/** Sent when the focus-panel command completes after opening the popover. */
|
|
40
|
+
export const CompletedFocusPanel = m('CompletedFocusPanel');
|
|
41
|
+
/** Sent when the focus-button command completes after closing. */
|
|
42
|
+
export const CompletedFocusButton = m('CompletedFocusButton');
|
|
43
|
+
/** Sent when the scroll lock command completes. */
|
|
44
|
+
export const CompletedLockScroll = m('CompletedLockScroll');
|
|
45
|
+
/** Sent when the scroll unlock command completes. */
|
|
46
|
+
export const CompletedUnlockScroll = m('CompletedUnlockScroll');
|
|
47
|
+
/** Sent when the inert-others command completes. */
|
|
48
|
+
export const CompletedInertOthers = m('CompletedInertOthers');
|
|
49
|
+
/** Sent when the restore-inert command completes. */
|
|
50
|
+
export const CompletedRestoreInert = m('CompletedRestoreInert');
|
|
51
|
+
/** Sent when a mouse click on the button is ignored because pointer-down already handled the toggle. */
|
|
52
|
+
export const IgnoredMouseClick = m('IgnoredMouseClick');
|
|
53
|
+
/** Sent when a Space key-up is captured to prevent page scrolling. */
|
|
54
|
+
export const SuppressedSpaceScroll = m('SuppressedSpaceScroll');
|
|
55
|
+
/** Sent when the popover panel mounts and Floating UI has positioned it. Update no-ops; the side effect is the act of positioning, surfaced for DevTools observability. */
|
|
56
|
+
export const CompletedAnchorPopover = m('CompletedAnchorPopover');
|
|
57
|
+
/** Sent when the popover backdrop mounts and is portaled to the document body. Update no-ops; surfaces the portal side effect for DevTools. */
|
|
58
|
+
export const CompletedPortalPopoverBackdrop = m('CompletedPortalPopoverBackdrop');
|
|
59
|
+
/** Wraps an Animation submodel message for delegation. */
|
|
60
|
+
export const GotAnimationMessage = m('GotAnimationMessage', {
|
|
61
|
+
message: AnimationMessage,
|
|
62
|
+
});
|
|
63
|
+
/** Union of all messages the popover component can produce. */
|
|
64
|
+
export const Message = S.Union([
|
|
65
|
+
RequestedOpen,
|
|
66
|
+
RequestedClose,
|
|
67
|
+
BlurredPanel,
|
|
68
|
+
PressedPointerOnButton,
|
|
69
|
+
CompletedFocusPanel,
|
|
70
|
+
CompletedFocusButton,
|
|
71
|
+
CompletedLockScroll,
|
|
72
|
+
CompletedUnlockScroll,
|
|
73
|
+
CompletedInertOthers,
|
|
74
|
+
CompletedRestoreInert,
|
|
75
|
+
IgnoredMouseClick,
|
|
76
|
+
SuppressedSpaceScroll,
|
|
77
|
+
CompletedAnchorPopover,
|
|
78
|
+
CompletedPortalPopoverBackdrop,
|
|
79
|
+
GotAnimationMessage,
|
|
80
|
+
]);
|
|
81
|
+
// OUT MESSAGE
|
|
82
|
+
/** Sent to the parent after the popover transitions to its open state. Fires once `update` has processed `RequestedOpen` and `isOpen` reflects the new state. */
|
|
83
|
+
export const Opened = m('Opened');
|
|
84
|
+
/** Sent to the parent after the popover transitions to its closed state. */
|
|
85
|
+
export const Closed = m('Closed');
|
|
86
|
+
/** Union of out-messages the popover component can produce. Parents reacting to open/close transitions (e.g. to reset related state, fire analytics) read this from the third element of `update`'s return tuple. */
|
|
87
|
+
export const OutMessage = S.Union([Opened, Closed]);
|
|
88
|
+
// INIT
|
|
89
|
+
const LEFT_MOUSE_BUTTON = 0;
|
|
90
|
+
/** Creates an initial popover model from a config. Defaults to closed. */
|
|
91
|
+
export const init = (config) => ({
|
|
92
|
+
id: config.id,
|
|
93
|
+
isOpen: false,
|
|
94
|
+
isAnimated: config.isAnimated ?? false,
|
|
95
|
+
isModal: config.isModal ?? false,
|
|
96
|
+
contentFocus: config.contentFocus ?? false,
|
|
97
|
+
animation: animationInit({ id: `${config.id}-panel` }),
|
|
98
|
+
maybeLastButtonPointerType: Option.none(),
|
|
99
|
+
});
|
|
100
|
+
// UPDATE
|
|
101
|
+
const closedModel = (model) => evo(model, {
|
|
102
|
+
isOpen: () => false,
|
|
103
|
+
maybeLastButtonPointerType: () => Option.none(),
|
|
104
|
+
});
|
|
105
|
+
const buttonSelector = (id) => `#${id}-button`;
|
|
106
|
+
const panelSelector = (id) => `#${id}-panel`;
|
|
107
|
+
const withUpdateReturn = M.withReturnType();
|
|
108
|
+
/** Prevents page scrolling while the popover is open in modal mode. */
|
|
109
|
+
export const LockScroll = Command.define('LockScroll', CompletedLockScroll)(Dom.lockScroll.pipe(Effect.as(CompletedLockScroll())));
|
|
110
|
+
/** Re-enables page scrolling after the popover closes. */
|
|
111
|
+
export const UnlockScroll = Command.define('UnlockScroll', CompletedUnlockScroll)(Dom.unlockScroll.pipe(Effect.as(CompletedUnlockScroll())));
|
|
112
|
+
/** Marks all elements outside the popover as inert for modal behavior. */
|
|
113
|
+
export const InertOthers = Command.define('InertOthers', { id: S.String }, CompletedInertOthers)(({ id }) => Dom.inertOthers(id, [buttonSelector(id), panelSelector(id)]).pipe(Effect.as(CompletedInertOthers())));
|
|
114
|
+
/** Removes the inert attribute from elements outside the popover. */
|
|
115
|
+
export const RestoreInert = Command.define('RestoreInert', { id: S.String }, CompletedRestoreInert)(({ id }) => Dom.restoreInert(id).pipe(Effect.as(CompletedRestoreInert())));
|
|
116
|
+
/** Moves focus to the popover panel after opening. */
|
|
117
|
+
export const FocusPanel = Command.define('FocusPanel', { id: S.String }, CompletedFocusPanel)(({ id }) => Dom.focus(panelSelector(id)).pipe(Effect.ignore, Effect.as(CompletedFocusPanel())));
|
|
118
|
+
/** Moves focus back to the popover button after closing. */
|
|
119
|
+
export const FocusButton = Command.define('FocusButton', { id: S.String }, CompletedFocusButton)(({ id }) => Dom.focus(buttonSelector(id)).pipe(Effect.ignore, Effect.as(CompletedFocusButton())));
|
|
120
|
+
/** Detects whether the popover button moved or the leave animation ended. Whichever comes first; both outcomes signal the Animation submodel that leave is complete. */
|
|
121
|
+
export const DetectMovementOrAnimationEnd = Command.define('DetectMovementOrAnimationEnd', { id: S.String }, GotAnimationMessage)(({ id }) => Effect.raceFirst(Dom.detectElementMovement(buttonSelector(id)).pipe(Effect.as(GotAnimationMessage({ message: AnimationEndedAnimation() }))), Dom.waitForAnimationSettled(panelSelector(id)).pipe(Effect.as(GotAnimationMessage({ message: AnimationEndedAnimation() })))));
|
|
122
|
+
const delegateToAnimation = (model, animationMessage) => {
|
|
123
|
+
const [nextAnimation, animationCommands, maybeOutMessage] = animationUpdate(model.animation, animationMessage);
|
|
124
|
+
const mappedCommands = Command.mapMessages(animationCommands, message => GotAnimationMessage({ message }));
|
|
125
|
+
const additionalCommands = Option.match(maybeOutMessage, {
|
|
126
|
+
onNone: () => [],
|
|
127
|
+
onSome: M.type().pipe(M.tagsExhaustive({
|
|
128
|
+
StartedLeaveAnimating: () => [
|
|
129
|
+
DetectMovementOrAnimationEnd({ id: model.id }),
|
|
130
|
+
],
|
|
131
|
+
TransitionedOut: () => [],
|
|
132
|
+
})),
|
|
133
|
+
});
|
|
134
|
+
return [
|
|
135
|
+
evo(model, { animation: () => nextAnimation }),
|
|
136
|
+
[...mappedCommands, ...additionalCommands],
|
|
137
|
+
Option.none(),
|
|
138
|
+
];
|
|
139
|
+
};
|
|
140
|
+
/** Processes a popover message and returns the next model, commands, and optional OutMessage. */
|
|
141
|
+
export const update = (model, message) => {
|
|
142
|
+
const maybeLockScroll = OptionExt.when(model.isModal, LockScroll());
|
|
143
|
+
const maybeUnlockScroll = OptionExt.when(model.isModal, UnlockScroll());
|
|
144
|
+
const maybeInertOthers = OptionExt.when(model.isModal, InertOthers({ id: model.id }));
|
|
145
|
+
const maybeRestoreInert = OptionExt.when(model.isModal, RestoreInert({ id: model.id }));
|
|
146
|
+
const focusButton = FocusButton({ id: model.id });
|
|
147
|
+
const openCommands = Array.getSomes([maybeLockScroll, maybeInertOthers]);
|
|
148
|
+
const closeWithFocusCommands = [
|
|
149
|
+
focusButton,
|
|
150
|
+
...Array.getSomes([maybeUnlockScroll, maybeRestoreInert]),
|
|
151
|
+
];
|
|
152
|
+
const closeWithoutFocusCommands = Array.getSomes([
|
|
153
|
+
maybeUnlockScroll,
|
|
154
|
+
maybeRestoreInert,
|
|
155
|
+
]);
|
|
156
|
+
const openPopover = (baseModel) => {
|
|
157
|
+
if (model.isAnimated) {
|
|
158
|
+
const [nextModel, animationCommands] = delegateToAnimation(baseModel, AnimationShowed());
|
|
159
|
+
return [
|
|
160
|
+
evo(nextModel, { isOpen: () => true }),
|
|
161
|
+
[...openCommands, ...animationCommands],
|
|
162
|
+
Option.some(Opened()),
|
|
163
|
+
];
|
|
164
|
+
}
|
|
165
|
+
return [
|
|
166
|
+
evo(baseModel, { isOpen: () => true }),
|
|
167
|
+
openCommands,
|
|
168
|
+
Option.some(Opened()),
|
|
169
|
+
];
|
|
170
|
+
};
|
|
171
|
+
const closePopover = (baseModel, commands) => {
|
|
172
|
+
if (!baseModel.isOpen) {
|
|
173
|
+
return [baseModel, commands, Option.none()];
|
|
174
|
+
}
|
|
175
|
+
const closed = closedModel(baseModel);
|
|
176
|
+
if (model.isAnimated) {
|
|
177
|
+
const [nextModel, animationCommands] = delegateToAnimation(closed, AnimationHid());
|
|
178
|
+
return [
|
|
179
|
+
nextModel,
|
|
180
|
+
[...commands, ...animationCommands],
|
|
181
|
+
Option.some(Closed()),
|
|
182
|
+
];
|
|
183
|
+
}
|
|
184
|
+
return [closed, commands, Option.some(Closed())];
|
|
185
|
+
};
|
|
186
|
+
return M.value(message).pipe(withUpdateReturn, M.tagsExhaustive({
|
|
187
|
+
RequestedOpen: () => openPopover(model),
|
|
188
|
+
RequestedClose: () => closePopover(model, closeWithFocusCommands),
|
|
189
|
+
BlurredPanel: () => {
|
|
190
|
+
if (Option.exists(model.maybeLastButtonPointerType, Equal.equals('mouse'))) {
|
|
191
|
+
return [model, [], Option.none()];
|
|
192
|
+
}
|
|
193
|
+
return closePopover(model, closeWithoutFocusCommands);
|
|
194
|
+
},
|
|
195
|
+
PressedPointerOnButton: ({ pointerType, button }) => {
|
|
196
|
+
const withPointerType = evo(model, {
|
|
197
|
+
maybeLastButtonPointerType: () => Option.some(pointerType),
|
|
198
|
+
});
|
|
199
|
+
if (pointerType !== 'mouse' || button !== LEFT_MOUSE_BUTTON) {
|
|
200
|
+
return [withPointerType, [], Option.none()];
|
|
201
|
+
}
|
|
202
|
+
if (model.isOpen) {
|
|
203
|
+
const [closed, commands, maybeOutMessage] = closePopover(withPointerType, closeWithFocusCommands);
|
|
204
|
+
return [
|
|
205
|
+
evo(closed, {
|
|
206
|
+
maybeLastButtonPointerType: () => Option.some(pointerType),
|
|
207
|
+
}),
|
|
208
|
+
commands,
|
|
209
|
+
maybeOutMessage,
|
|
210
|
+
];
|
|
211
|
+
}
|
|
212
|
+
return openPopover(withPointerType);
|
|
213
|
+
},
|
|
214
|
+
GotAnimationMessage: ({ message: animationMessage }) => delegateToAnimation(model, animationMessage),
|
|
215
|
+
CompletedFocusPanel: () => [model, [], Option.none()],
|
|
216
|
+
CompletedFocusButton: () => [model, [], Option.none()],
|
|
217
|
+
CompletedLockScroll: () => [model, [], Option.none()],
|
|
218
|
+
CompletedUnlockScroll: () => [model, [], Option.none()],
|
|
219
|
+
CompletedInertOthers: () => [model, [], Option.none()],
|
|
220
|
+
CompletedRestoreInert: () => [model, [], Option.none()],
|
|
221
|
+
IgnoredMouseClick: () => [
|
|
222
|
+
evo(model, { maybeLastButtonPointerType: () => Option.none() }),
|
|
223
|
+
[],
|
|
224
|
+
Option.none(),
|
|
225
|
+
],
|
|
226
|
+
SuppressedSpaceScroll: () => [model, [], Option.none()],
|
|
227
|
+
CompletedAnchorPopover: () => [model, [], Option.none()],
|
|
228
|
+
CompletedPortalPopoverBackdrop: () => [model, [], Option.none()],
|
|
229
|
+
}));
|
|
230
|
+
};
|
|
231
|
+
/** The anchor-positioning Mount this Popover renders on its panel. Exposed so
|
|
232
|
+
* Scene tests can call `Scene.Mount.resolve(AnchorPopover, CompletedAnchorPopover())`
|
|
233
|
+
* to acknowledge the mount produced by the rendered panel. */
|
|
234
|
+
export const AnchorPopover = Mount.define('AnchorPopover', {
|
|
235
|
+
buttonId: S.String,
|
|
236
|
+
anchor: AnchorConfig,
|
|
237
|
+
focusSelector: S.optional(S.String),
|
|
238
|
+
}, CompletedAnchorPopover)(({ buttonId, anchor, focusSelector }) => element => Effect.gen(function* () {
|
|
239
|
+
yield* Effect.acquireRelease(Effect.sync(() => anchorSetup({
|
|
240
|
+
buttonId,
|
|
241
|
+
anchor,
|
|
242
|
+
interceptTab: false,
|
|
243
|
+
focusAfterPosition: true,
|
|
244
|
+
...(focusSelector !== undefined && { focusSelector }),
|
|
245
|
+
})(element)), cleanup => Effect.sync(cleanup));
|
|
246
|
+
return CompletedAnchorPopover();
|
|
247
|
+
}));
|
|
248
|
+
/** The backdrop-portaling Mount this Popover renders. Exposed so Scene tests can
|
|
249
|
+
* call `Scene.Mount.resolve(PortalPopoverBackdrop, CompletedPortalPopoverBackdrop())` to
|
|
250
|
+
* acknowledge the mount produced by the rendered backdrop. */
|
|
251
|
+
export const PortalPopoverBackdrop = Mount.define('PortalPopoverBackdrop', CompletedPortalPopoverBackdrop)(element => Effect.gen(function* () {
|
|
252
|
+
yield* Effect.acquireRelease(Effect.sync(() => portalToBody(element)), cleanup => Effect.sync(cleanup));
|
|
253
|
+
return CompletedPortalPopoverBackdrop();
|
|
254
|
+
}));
|
|
255
|
+
/** Programmatically opens the popover, updating the model and returning
|
|
256
|
+
* focus and modal commands plus an `Opened` OutMessage. */
|
|
257
|
+
export const open = (model) => update(model, RequestedOpen());
|
|
258
|
+
/** Programmatically closes the popover, updating the model and returning
|
|
259
|
+
* focus and modal commands plus a `Closed` OutMessage when it was open. */
|
|
260
|
+
export const close = (model) => update(model, RequestedClose());
|
|
261
|
+
/** Renders a headless popover with a trigger button and a floating panel. */
|
|
262
|
+
export const view = defineView((model, viewInputs) => {
|
|
263
|
+
const h = html();
|
|
264
|
+
const { id, isOpen, contentFocus, animation: { transitionState }, maybeLastButtonPointerType, } = model;
|
|
265
|
+
const { anchor, toView, isDisabled, focusSelector } = viewInputs;
|
|
266
|
+
const isLeaving = transitionState === 'LeaveStart' || transitionState === 'LeaveAnimating';
|
|
267
|
+
const isVisible = isOpen || isLeaving;
|
|
268
|
+
const animationAttributes = M.value(transitionState).pipe(M.when('EnterStart', () => [
|
|
269
|
+
h.DataAttribute('closed', ''),
|
|
270
|
+
h.DataAttribute('enter', ''),
|
|
271
|
+
h.DataAttribute('transition', ''),
|
|
272
|
+
]), M.when('EnterAnimating', () => [
|
|
273
|
+
h.DataAttribute('enter', ''),
|
|
274
|
+
h.DataAttribute('transition', ''),
|
|
275
|
+
]), M.when('LeaveStart', () => [
|
|
276
|
+
h.DataAttribute('leave', ''),
|
|
277
|
+
h.DataAttribute('transition', ''),
|
|
278
|
+
]), M.when('LeaveAnimating', () => [
|
|
279
|
+
h.DataAttribute('closed', ''),
|
|
280
|
+
h.DataAttribute('leave', ''),
|
|
281
|
+
h.DataAttribute('transition', ''),
|
|
282
|
+
]), M.orElse(() => []));
|
|
283
|
+
const handleButtonKeyDown = (key) => M.value(key).pipe(M.whenOr('Enter', ' ', 'ArrowDown', () => Option.some(isOpen ? RequestedClose() : RequestedOpen())), M.when('Escape', () => OptionExt.when(isOpen, RequestedClose())), M.orElse(() => Option.none()));
|
|
284
|
+
const handleButtonPointerDown = (pointerType, button) => Option.some(PressedPointerOnButton({ pointerType, button }));
|
|
285
|
+
const handleButtonClick = () => {
|
|
286
|
+
const isMouse = Option.exists(maybeLastButtonPointerType, type => type === 'mouse');
|
|
287
|
+
if (isMouse) {
|
|
288
|
+
return IgnoredMouseClick();
|
|
289
|
+
}
|
|
290
|
+
else if (isOpen) {
|
|
291
|
+
return RequestedClose();
|
|
292
|
+
}
|
|
293
|
+
else {
|
|
294
|
+
return RequestedOpen();
|
|
295
|
+
}
|
|
296
|
+
};
|
|
297
|
+
const handleSpaceKeyUp = (key) => OptionExt.when(key === ' ', SuppressedSpaceScroll());
|
|
298
|
+
const handlePanelKeyDown = (key) => M.value(key).pipe(M.when('Escape', () => Option.some(RequestedClose())), M.orElse(() => Option.none()));
|
|
299
|
+
const buttonAttributes = [
|
|
300
|
+
h.Id(`${id}-button`),
|
|
301
|
+
h.Type('button'),
|
|
302
|
+
h.AriaExpanded(isVisible),
|
|
303
|
+
h.AriaControls(`${id}-panel`),
|
|
304
|
+
...(isDisabled
|
|
305
|
+
? [h.AriaDisabled(true), h.DataAttribute('disabled', '')]
|
|
306
|
+
: [
|
|
307
|
+
h.OnPointerDown(handleButtonPointerDown),
|
|
308
|
+
h.OnKeyDownPreventDefault(handleButtonKeyDown),
|
|
309
|
+
h.OnKeyUpPreventDefault(handleSpaceKeyUp),
|
|
310
|
+
h.OnClick(handleButtonClick()),
|
|
311
|
+
]),
|
|
312
|
+
...(isVisible
|
|
313
|
+
? [
|
|
314
|
+
h.DataAttribute('open', ''),
|
|
315
|
+
h.Style({ position: 'relative', zIndex: '1' }),
|
|
316
|
+
]
|
|
317
|
+
: []),
|
|
318
|
+
];
|
|
319
|
+
const panelAttributes = [
|
|
320
|
+
h.Id(`${id}-panel`),
|
|
321
|
+
...(contentFocus ? [] : [h.Tabindex(0)]),
|
|
322
|
+
h.Style({ position: 'absolute', margin: '0', visibility: 'hidden' }),
|
|
323
|
+
h.OnMount(AnchorPopover({
|
|
324
|
+
buttonId: `${id}-button`,
|
|
325
|
+
anchor,
|
|
326
|
+
...(focusSelector !== undefined && { focusSelector }),
|
|
327
|
+
})),
|
|
328
|
+
...animationAttributes,
|
|
329
|
+
...(isLeaving
|
|
330
|
+
? []
|
|
331
|
+
: [
|
|
332
|
+
h.OnKeyDownPreventDefault(handlePanelKeyDown),
|
|
333
|
+
...(contentFocus ? [] : [h.OnBlur(BlurredPanel())]),
|
|
334
|
+
]),
|
|
335
|
+
];
|
|
336
|
+
const backdropAttributes = [
|
|
337
|
+
h.OnMount(PortalPopoverBackdrop()),
|
|
338
|
+
...(isLeaving ? [] : [h.OnClick(RequestedClose())]),
|
|
339
|
+
];
|
|
340
|
+
return toView({
|
|
341
|
+
button: childAttributes(buttonAttributes),
|
|
342
|
+
panel: childAttributes(panelAttributes),
|
|
343
|
+
backdrop: childAttributes(backdropAttributes),
|
|
344
|
+
isVisible,
|
|
345
|
+
});
|
|
346
|
+
});
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { init, update, open, close, view, Model, Message, OutMessage, Opened, Closed, RequestedOpen, RequestedClose, CompletedFocusPanel, CompletedFocusButton, CompletedLockScroll, CompletedUnlockScroll, CompletedInertOthers, CompletedRestoreInert, CompletedAnchorPopover, CompletedPortalPopoverBackdrop, AnchorPopover, PortalPopoverBackdrop, GotAnimationMessage, LockScroll, UnlockScroll, InertOthers, RestoreInert, FocusPanel, FocusButton, DetectMovementOrAnimationEnd, } from './index.js';
|
|
2
|
+
export type { BlurredPanel, PressedPointerOnButton, IgnoredMouseClick, SuppressedSpaceScroll, InitConfig, ViewInputs, RenderInfo, } from './index.js';
|
|
3
|
+
export type { AnchorConfig } from '../anchor.js';
|
|
4
|
+
//# sourceMappingURL=public.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"public.d.ts","sourceRoot":"","sources":["../../src/popover/public.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,IAAI,EACJ,MAAM,EACN,IAAI,EACJ,KAAK,EACL,IAAI,EACJ,KAAK,EACL,OAAO,EACP,UAAU,EACV,MAAM,EACN,MAAM,EACN,aAAa,EACb,cAAc,EACd,mBAAmB,EACnB,oBAAoB,EACpB,mBAAmB,EACnB,qBAAqB,EACrB,oBAAoB,EACpB,qBAAqB,EACrB,sBAAsB,EACtB,8BAA8B,EAC9B,aAAa,EACb,qBAAqB,EACrB,mBAAmB,EACnB,UAAU,EACV,YAAY,EACZ,WAAW,EACX,YAAY,EACZ,UAAU,EACV,WAAW,EACX,4BAA4B,GAC7B,MAAM,YAAY,CAAA;AAEnB,YAAY,EACV,YAAY,EACZ,sBAAsB,EACtB,iBAAiB,EACjB,qBAAqB,EACrB,UAAU,EACV,UAAU,EACV,UAAU,GACX,MAAM,YAAY,CAAA;AAEnB,YAAY,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { init, update, open, close, view, Model, Message, OutMessage, Opened, Closed, RequestedOpen, RequestedClose, CompletedFocusPanel, CompletedFocusButton, CompletedLockScroll, CompletedUnlockScroll, CompletedInertOthers, CompletedRestoreInert, CompletedAnchorPopover, CompletedPortalPopoverBackdrop, AnchorPopover, PortalPopoverBackdrop, GotAnimationMessage, LockScroll, UnlockScroll, InertOthers, RestoreInert, FocusPanel, FocusButton, DetectMovementOrAnimationEnd, } from './index.js';
|