foldkit 0.100.1 → 0.102.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/README.md +3 -2
- package/dist/canvas/view.d.ts +1 -1
- package/dist/canvas/view.d.ts.map +1 -1
- package/dist/canvas/view.js +5 -5
- package/dist/command/index.d.ts +71 -0
- package/dist/command/index.d.ts.map +1 -1
- package/dist/command/index.js +34 -1
- package/dist/command/public.d.ts +1 -1
- package/dist/command/public.d.ts.map +1 -1
- package/dist/command/public.js +1 -1
- package/dist/devTools/overlay.d.ts.map +1 -1
- package/dist/devTools/overlay.js +156 -149
- package/dist/dom/dom.d.ts +8 -11
- package/dist/dom/dom.d.ts.map +1 -1
- package/dist/dom/dom.js +8 -11
- package/dist/dom/elementMovement.d.ts +1 -3
- package/dist/dom/elementMovement.d.ts.map +1 -1
- package/dist/dom/elementMovement.js +1 -3
- package/dist/dom/inert.d.ts +2 -4
- package/dist/dom/inert.d.ts.map +1 -1
- package/dist/dom/inert.js +2 -4
- package/dist/dom/scrollLock.d.ts +2 -2
- package/dist/dom/scrollLock.js +2 -2
- package/dist/dom/waitForAnimation.d.ts +1 -1
- package/dist/dom/waitForAnimation.js +1 -1
- package/dist/html/boundary.d.ts +98 -0
- package/dist/html/boundary.d.ts.map +1 -0
- package/dist/html/boundary.js +176 -0
- package/dist/html/childAttribute.d.ts +44 -0
- package/dist/html/childAttribute.d.ts.map +1 -0
- package/dist/html/childAttribute.js +34 -0
- package/dist/html/index.d.ts +70 -23
- package/dist/html/index.d.ts.map +1 -1
- package/dist/html/index.js +639 -575
- package/dist/html/lazy.d.ts +12 -7
- package/dist/html/lazy.d.ts.map +1 -1
- package/dist/html/lazy.js +30 -11
- package/dist/html/public.d.ts +2 -2
- package/dist/html/public.d.ts.map +1 -1
- package/dist/html/public.js +1 -1
- package/dist/html/runtimeSingleton.d.ts +72 -0
- package/dist/html/runtimeSingleton.d.ts.map +1 -0
- package/dist/html/runtimeSingleton.js +112 -0
- package/dist/html/submodel.d.ts +98 -0
- package/dist/html/submodel.d.ts.map +1 -0
- package/dist/html/submodel.js +190 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/render/render.d.ts +1 -1
- package/dist/render/render.js +1 -1
- package/dist/runtime/messagePriority.d.ts +5 -1
- package/dist/runtime/messagePriority.d.ts.map +1 -1
- package/dist/runtime/messagePriority.js +25 -4
- package/dist/runtime/runtime.d.ts +11 -11
- package/dist/runtime/runtime.d.ts.map +1 -1
- package/dist/runtime/runtime.js +118 -63
- package/dist/runtime/subscription.d.ts +139 -19
- package/dist/runtime/subscription.d.ts.map +1 -1
- package/dist/runtime/subscription.js +90 -9
- package/dist/submodel/public.d.ts +4 -0
- package/dist/submodel/public.d.ts.map +1 -0
- package/dist/submodel/public.js +1 -0
- package/dist/submodel/submodel.d.ts +32 -0
- package/dist/submodel/submodel.d.ts.map +1 -0
- package/dist/submodel/submodel.js +1 -0
- package/dist/subscription/animationFrame.d.ts +23 -26
- package/dist/subscription/animationFrame.d.ts.map +1 -1
- package/dist/subscription/animationFrame.js +17 -18
- package/dist/subscription/public.d.ts +2 -2
- package/dist/subscription/public.d.ts.map +1 -1
- package/dist/subscription/public.js +1 -1
- package/dist/test/apps/disabledButton.d.ts +4 -5
- package/dist/test/apps/disabledButton.d.ts.map +1 -1
- package/dist/test/apps/disabledButton.js +16 -16
- package/dist/test/scene.d.ts +8 -8
- package/dist/test/scene.d.ts.map +1 -1
- package/dist/test/scene.js +25 -13
- package/dist/test/story.d.ts +15 -8
- package/dist/test/story.d.ts.map +1 -1
- package/dist/test/story.js +21 -9
- package/dist/ui/animation/index.d.ts +30 -14
- package/dist/ui/animation/index.d.ts.map +1 -1
- package/dist/ui/animation/index.js +9 -19
- package/dist/ui/animation/public.d.ts +2 -2
- package/dist/ui/animation/public.d.ts.map +1 -1
- package/dist/ui/animation/public.js +1 -1
- package/dist/ui/calendar/index.d.ts +199 -84
- package/dist/ui/calendar/index.d.ts.map +1 -1
- package/dist/ui/calendar/index.js +129 -140
- package/dist/ui/calendar/public.d.ts +2 -2
- package/dist/ui/calendar/public.d.ts.map +1 -1
- package/dist/ui/calendar/public.js +1 -1
- package/dist/ui/checkbox/index.d.ts +93 -21
- package/dist/ui/checkbox/index.d.ts.map +1 -1
- package/dist/ui/checkbox/index.js +62 -33
- package/dist/ui/checkbox/public.d.ts +2 -2
- package/dist/ui/checkbox/public.d.ts.map +1 -1
- package/dist/ui/checkbox/public.js +1 -1
- package/dist/ui/combobox/multi.d.ts +35 -91
- package/dist/ui/combobox/multi.d.ts.map +1 -1
- package/dist/ui/combobox/multi.js +34 -17
- package/dist/ui/combobox/multiPublic.d.ts +2 -2
- package/dist/ui/combobox/multiPublic.d.ts.map +1 -1
- package/dist/ui/combobox/multiPublic.js +1 -1
- package/dist/ui/combobox/public.d.ts +3 -3
- package/dist/ui/combobox/public.d.ts.map +1 -1
- package/dist/ui/combobox/public.js +2 -2
- package/dist/ui/combobox/shared.d.ts +56 -31
- package/dist/ui/combobox/shared.d.ts.map +1 -1
- package/dist/ui/combobox/shared.js +333 -322
- package/dist/ui/combobox/single.d.ts +46 -93
- package/dist/ui/combobox/single.d.ts.map +1 -1
- package/dist/ui/combobox/single.js +44 -17
- package/dist/ui/datePicker/index.d.ts +256 -48
- package/dist/ui/datePicker/index.d.ts.map +1 -1
- package/dist/ui/datePicker/index.js +149 -104
- package/dist/ui/datePicker/public.d.ts +2 -2
- package/dist/ui/datePicker/public.d.ts.map +1 -1
- package/dist/ui/datePicker/public.js +1 -1
- package/dist/ui/dialog/index.d.ts +95 -39
- package/dist/ui/dialog/index.d.ts.map +1 -1
- package/dist/ui/dialog/index.js +71 -62
- package/dist/ui/dialog/public.d.ts +2 -2
- package/dist/ui/dialog/public.d.ts.map +1 -1
- package/dist/ui/dialog/public.js +1 -1
- package/dist/ui/disclosure/index.d.ts +71 -31
- package/dist/ui/disclosure/index.d.ts.map +1 -1
- package/dist/ui/disclosure/index.js +57 -62
- package/dist/ui/disclosure/public.d.ts +2 -2
- package/dist/ui/disclosure/public.d.ts.map +1 -1
- package/dist/ui/disclosure/public.js +1 -1
- package/dist/ui/dragAndDrop/index.d.ts +385 -103
- package/dist/ui/dragAndDrop/index.d.ts.map +1 -1
- package/dist/ui/dragAndDrop/index.js +26 -31
- package/dist/ui/dragAndDrop/public.d.ts +1 -1
- package/dist/ui/dragAndDrop/public.d.ts.map +1 -1
- package/dist/ui/dragAndDrop/public.js +1 -1
- package/dist/ui/fileDrop/index.d.ts +42 -46
- package/dist/ui/fileDrop/index.d.ts.map +1 -1
- package/dist/ui/fileDrop/index.js +30 -46
- package/dist/ui/fileDrop/public.d.ts +2 -2
- package/dist/ui/fileDrop/public.d.ts.map +1 -1
- package/dist/ui/fileDrop/public.js +1 -1
- package/dist/ui/listbox/multi.d.ts +39 -84
- package/dist/ui/listbox/multi.d.ts.map +1 -1
- package/dist/ui/listbox/multi.js +38 -20
- package/dist/ui/listbox/multiPublic.d.ts +2 -2
- package/dist/ui/listbox/multiPublic.d.ts.map +1 -1
- package/dist/ui/listbox/multiPublic.js +1 -1
- package/dist/ui/listbox/public.d.ts +3 -3
- package/dist/ui/listbox/public.d.ts.map +1 -1
- package/dist/ui/listbox/public.js +2 -2
- package/dist/ui/listbox/shared.d.ts +71 -30
- package/dist/ui/listbox/shared.d.ts.map +1 -1
- package/dist/ui/listbox/shared.js +319 -296
- package/dist/ui/listbox/single.d.ts +57 -85
- package/dist/ui/listbox/single.d.ts.map +1 -1
- package/dist/ui/listbox/single.js +48 -24
- package/dist/ui/menu/index.d.ts +80 -36
- package/dist/ui/menu/index.d.ts.map +1 -1
- package/dist/ui/menu/index.js +117 -86
- package/dist/ui/menu/public.d.ts +2 -2
- package/dist/ui/menu/public.d.ts.map +1 -1
- package/dist/ui/menu/public.js +1 -1
- package/dist/ui/popover/index.d.ts +117 -44
- package/dist/ui/popover/index.d.ts.map +1 -1
- package/dist/ui/popover/index.js +88 -101
- package/dist/ui/popover/public.d.ts +2 -2
- package/dist/ui/popover/public.d.ts.map +1 -1
- package/dist/ui/popover/public.js +1 -1
- package/dist/ui/radioGroup/index.d.ts +122 -45
- package/dist/ui/radioGroup/index.d.ts.map +1 -1
- package/dist/ui/radioGroup/index.js +111 -72
- package/dist/ui/radioGroup/public.d.ts +2 -2
- package/dist/ui/radioGroup/public.d.ts.map +1 -1
- package/dist/ui/radioGroup/public.js +1 -1
- package/dist/ui/slider/index.d.ts +247 -103
- package/dist/ui/slider/index.d.ts.map +1 -1
- package/dist/ui/slider/index.js +52 -68
- package/dist/ui/slider/public.d.ts +2 -2
- package/dist/ui/slider/public.d.ts.map +1 -1
- package/dist/ui/slider/public.js +1 -1
- package/dist/ui/switch/index.d.ts +74 -21
- package/dist/ui/switch/index.d.ts.map +1 -1
- package/dist/ui/switch/index.js +62 -33
- package/dist/ui/switch/public.d.ts +2 -2
- package/dist/ui/switch/public.d.ts.map +1 -1
- package/dist/ui/switch/public.js +1 -1
- package/dist/ui/tabs/index.d.ts +107 -45
- package/dist/ui/tabs/index.d.ts.map +1 -1
- package/dist/ui/tabs/index.js +99 -81
- package/dist/ui/tabs/public.d.ts +2 -2
- package/dist/ui/tabs/public.d.ts.map +1 -1
- package/dist/ui/tabs/public.js +1 -1
- package/dist/ui/toast/index.d.ts +93 -109
- package/dist/ui/toast/index.d.ts.map +1 -1
- package/dist/ui/toast/index.js +16 -29
- package/dist/ui/toast/schema.d.ts +15 -4
- package/dist/ui/toast/schema.d.ts.map +1 -1
- package/dist/ui/toast/schema.js +11 -4
- package/dist/ui/toast/update.d.ts +36 -18
- package/dist/ui/toast/update.d.ts.map +1 -1
- package/dist/ui/toast/update.js +33 -14
- package/dist/ui/tooltip/index.d.ts +94 -42
- package/dist/ui/tooltip/index.d.ts.map +1 -1
- package/dist/ui/tooltip/index.js +64 -73
- package/dist/ui/tooltip/public.d.ts +2 -2
- package/dist/ui/tooltip/public.d.ts.map +1 -1
- package/dist/ui/tooltip/public.js +1 -1
- package/dist/ui/virtualList/index.d.ts +63 -80
- package/dist/ui/virtualList/index.d.ts.map +1 -1
- package/dist/ui/virtualList/index.js +22 -49
- package/dist/ui/virtualList/public.d.ts +2 -2
- package/dist/ui/virtualList/public.d.ts.map +1 -1
- package/dist/ui/virtualList/public.js +1 -1
- package/package.json +1 -1
package/dist/ui/tooltip/index.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import { Duration, Effect, Equal, Match as M, Number, Option, Schema as S, } from 'effect';
|
|
1
|
+
import { Duration, Effect, Equal, Function, Match as M, Number, Option, Schema as S, } from 'effect';
|
|
2
2
|
import * as Command from '../../command/index.js';
|
|
3
3
|
import { OptionExt } from '../../effectExtensions/index.js';
|
|
4
|
-
import {
|
|
4
|
+
import { childAttributes, defineView, html, } from '../../html/index.js';
|
|
5
5
|
import { m } from '../../message/index.js';
|
|
6
6
|
import * as Mount from '../../mount/index.js';
|
|
7
7
|
import { evo } from '../../struct/index.js';
|
|
8
8
|
import { AnchorConfig, anchorSetup } from '../anchor.js';
|
|
9
9
|
// MODEL
|
|
10
|
-
/** Schema for the tooltip component's state. `isOpen` is visibility; `isHovered` tracks pointer on trigger; `isFocused` tracks tooltip-affirming focus on the trigger (focus arriving without a preceding mouse press
|
|
10
|
+
/** Schema for the tooltip component's state. `isOpen` is visibility; `isHovered` tracks pointer on trigger; `isFocused` tracks tooltip-affirming focus on the trigger (focus arriving without a preceding mouse press, like keyboard, touch, or pen; mouse-click-induced focus is excluded since it doesn't affirm the user wants the tooltip visible); `isDismissed` suppresses re-opening after the user dismissed the tooltip (via Escape or left-click) until they disengage (leave or blur). `showDelay` is the hover-to-show duration. `maybeLastPointerType` records the most recent pointer type that pressed the trigger, so a mouse-click-induced focus can be distinguished from other focus. */
|
|
11
11
|
export const Model = S.Struct({
|
|
12
12
|
id: S.String,
|
|
13
13
|
isOpen: S.Boolean,
|
|
@@ -19,30 +19,26 @@ export const Model = S.Struct({
|
|
|
19
19
|
maybeLastPointerType: S.Option(S.String),
|
|
20
20
|
});
|
|
21
21
|
// MESSAGE
|
|
22
|
-
/** Sent when the pointer enters the tooltip trigger.
|
|
22
|
+
/** Sent when the pointer enters the tooltip trigger. */
|
|
23
23
|
export const EnteredTrigger = m('EnteredTrigger');
|
|
24
|
-
/** Sent when the pointer leaves the tooltip trigger.
|
|
24
|
+
/** Sent when the pointer leaves the tooltip trigger. */
|
|
25
25
|
export const LeftTrigger = m('LeftTrigger');
|
|
26
|
-
/** Sent when focus enters the trigger.
|
|
26
|
+
/** Sent when focus enters the trigger. */
|
|
27
27
|
export const FocusedTrigger = m('FocusedTrigger');
|
|
28
|
-
/** Sent when focus leaves the trigger.
|
|
28
|
+
/** Sent when focus leaves the trigger. */
|
|
29
29
|
export const BlurredTrigger = m('BlurredTrigger');
|
|
30
|
-
/** Sent when Escape is pressed while the tooltip is visible.
|
|
30
|
+
/** Sent when Escape is pressed while the tooltip is visible. */
|
|
31
31
|
export const PressedEscape = m('PressedEscape');
|
|
32
|
-
/** Sent when a pointer presses the trigger.
|
|
32
|
+
/** Sent when a pointer presses the trigger. */
|
|
33
33
|
export const PressedPointerOnTrigger = m('PressedPointerOnTrigger', {
|
|
34
34
|
pointerType: S.String,
|
|
35
35
|
button: S.Number,
|
|
36
36
|
});
|
|
37
|
-
/** Sent when the show-delay timer fires.
|
|
37
|
+
/** Sent when the show-delay timer fires. */
|
|
38
38
|
export const ElapsedShowDelay = m('ElapsedShowDelay', {
|
|
39
39
|
version: S.Number,
|
|
40
40
|
});
|
|
41
|
-
/**
|
|
42
|
-
export const ChangedShowDelay = m('ChangedShowDelay', {
|
|
43
|
-
showDelay: S.DurationFromMillis,
|
|
44
|
-
});
|
|
45
|
-
/** Sent when the tooltip panel mounts and Floating UI has positioned it. Update no-ops; the side effect is the act of positioning, surfaced for DevTools observability. */
|
|
41
|
+
/** Sent when the tooltip panel mounts and Floating UI has positioned it. */
|
|
46
42
|
export const CompletedAnchorTooltip = m('CompletedAnchorTooltip');
|
|
47
43
|
/** Union of all messages the tooltip component can produce. */
|
|
48
44
|
export const Message = S.Union([
|
|
@@ -53,9 +49,17 @@ export const Message = S.Union([
|
|
|
53
49
|
PressedEscape,
|
|
54
50
|
PressedPointerOnTrigger,
|
|
55
51
|
ElapsedShowDelay,
|
|
56
|
-
ChangedShowDelay,
|
|
57
52
|
CompletedAnchorTooltip,
|
|
58
53
|
]);
|
|
54
|
+
// OUT MESSAGE
|
|
55
|
+
/** Emitted once the tooltip transitions to visible (`isOpen` becomes true).
|
|
56
|
+
* Consumers typically use this for analytics, instrumentation, or to
|
|
57
|
+
* coordinate with other transient UI. */
|
|
58
|
+
export const Shown = m('Shown');
|
|
59
|
+
/** Emitted once the tooltip transitions to hidden (`isOpen` becomes false). */
|
|
60
|
+
export const Hidden = m('Hidden');
|
|
61
|
+
/** Union of out-messages the tooltip component can produce. */
|
|
62
|
+
export const OutMessage = S.Union([Shown, Hidden]);
|
|
59
63
|
// INIT
|
|
60
64
|
const DEFAULT_SHOW_DELAY = Duration.millis(500);
|
|
61
65
|
const LEFT_MOUSE_BUTTON = 0;
|
|
@@ -73,11 +77,9 @@ export const init = (config) => ({
|
|
|
73
77
|
maybeLastPointerType: Option.none(),
|
|
74
78
|
});
|
|
75
79
|
const withUpdateReturn = M.withReturnType();
|
|
76
|
-
/** Waits for the tooltip's show delay before emitting `ElapsedShowDelay`.
|
|
80
|
+
/** Waits for the tooltip's show delay before emitting `ElapsedShowDelay`. */
|
|
77
81
|
export const ShowAfterDelay = Command.define('ShowAfterDelay', { delay: S.DurationFromMillis, version: S.Number }, ElapsedShowDelay)(({ delay, version }) => Effect.sleep(delay).pipe(Effect.as(ElapsedShowDelay({ version }))));
|
|
78
|
-
/** The anchor-positioning Mount this Tooltip renders on its panel.
|
|
79
|
-
* Scene tests can call `Scene.Mount.resolve(AnchorTooltip, CompletedAnchorTooltip())`
|
|
80
|
-
* to acknowledge the mount produced by the rendered panel. */
|
|
82
|
+
/** The anchor-positioning Mount this Tooltip renders on its panel. */
|
|
81
83
|
export const AnchorTooltip = Mount.define('AnchorTooltip', { buttonId: S.String, anchor: AnchorConfig }, CompletedAnchorTooltip)(({ buttonId, anchor }) => element => Effect.gen(function* () {
|
|
82
84
|
yield* Effect.acquireRelease(Effect.sync(() => anchorSetup({
|
|
83
85
|
buttonId,
|
|
@@ -86,8 +88,7 @@ export const AnchorTooltip = Mount.define('AnchorTooltip', { buttonId: S.String,
|
|
|
86
88
|
})(element)), cleanup => Effect.sync(cleanup));
|
|
87
89
|
return CompletedAnchorTooltip();
|
|
88
90
|
}));
|
|
89
|
-
|
|
90
|
-
export const update = (model, message) => M.value(message).pipe(withUpdateReturn, M.tagsExhaustive({
|
|
91
|
+
const computeUpdate = (model, message) => M.value(message).pipe(withUpdateReturn, M.tagsExhaustive({
|
|
91
92
|
EnteredTrigger: () => {
|
|
92
93
|
if (model.isOpen || model.isDismissed) {
|
|
93
94
|
return [evo(model, { isHovered: () => true }), []];
|
|
@@ -186,21 +187,36 @@ export const update = (model, message) => M.value(message).pipe(withUpdateReturn
|
|
|
186
187
|
}
|
|
187
188
|
return [evo(model, { isOpen: () => true }), []];
|
|
188
189
|
},
|
|
189
|
-
ChangedShowDelay: ({ showDelay }) => [
|
|
190
|
-
evo(model, { showDelay: () => showDelay }),
|
|
191
|
-
[],
|
|
192
|
-
],
|
|
193
190
|
CompletedAnchorTooltip: () => [model, []],
|
|
194
191
|
}));
|
|
195
|
-
/**
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
192
|
+
/** Processes a tooltip message and returns the next model, commands, and
|
|
193
|
+
* an optional OutMessage. `Shown`/`Hidden` fire only on `isOpen`
|
|
194
|
+
* transitions, so consumers don't get spurious events for messages that
|
|
195
|
+
* only update hover/focus/delay state without changing visibility. */
|
|
196
|
+
export const update = (model, message) => {
|
|
197
|
+
const [nextModel, commands] = computeUpdate(model, message);
|
|
198
|
+
const maybeOutMessage = !model.isOpen && nextModel.isOpen
|
|
199
|
+
? Option.some(Shown())
|
|
200
|
+
: model.isOpen && !nextModel.isOpen
|
|
201
|
+
? Option.some(Hidden())
|
|
202
|
+
: Option.none();
|
|
203
|
+
return [nextModel, commands, maybeOutMessage];
|
|
204
|
+
};
|
|
205
|
+
/** Reflects an externally-sourced hover show-delay onto the model without
|
|
206
|
+
* emitting an OutMessage. Use to mirror an external config value (a user
|
|
207
|
+
* preference, a restored setting) onto the tooltip. */
|
|
208
|
+
export const reflectShowDelay = Function.dual(2, (model, showDelay) => evo(model, { showDelay: () => Duration.fromInputUnsafe(showDelay) }));
|
|
209
|
+
/** Renders a headless tooltip with an anchored non-interactive panel.
|
|
210
|
+
* Shows on hover (after delay) or focus (from keyboard, touch, or pen;
|
|
211
|
+
* mouse-click focus is excluded); hides on leave, blur, Escape, or
|
|
212
|
+
* left-click of the trigger. */
|
|
213
|
+
export const view = defineView((model, viewInputs) => {
|
|
199
214
|
const h = html();
|
|
200
|
-
const {
|
|
201
|
-
const
|
|
202
|
-
const
|
|
203
|
-
const
|
|
215
|
+
const { id, isOpen } = model;
|
|
216
|
+
const { anchor, toView, isDisabled } = viewInputs;
|
|
217
|
+
const handleTriggerKeyDown = (key) => M.value(key).pipe(M.when('Escape', () => OptionExt.when(isOpen, PressedEscape())), M.orElse(() => Option.none()));
|
|
218
|
+
const handleTriggerPointerDown = (pointerType, button) => Option.some(PressedPointerOnTrigger({ pointerType, button }));
|
|
219
|
+
const triggerAttributes = [
|
|
204
220
|
h.Id(`${id}-trigger`),
|
|
205
221
|
h.Type('button'),
|
|
206
222
|
h.AriaDescribedBy(`${id}-panel`),
|
|
@@ -208,54 +224,29 @@ export const view = (config) => {
|
|
|
208
224
|
...(isDisabled
|
|
209
225
|
? [h.AriaDisabled(true), h.DataAttribute('disabled', '')]
|
|
210
226
|
: [
|
|
211
|
-
h.OnMouseEnter(
|
|
212
|
-
h.OnMouseLeave(
|
|
213
|
-
h.OnFocus(
|
|
214
|
-
h.OnBlur(
|
|
227
|
+
h.OnMouseEnter(EnteredTrigger()),
|
|
228
|
+
h.OnMouseLeave(LeftTrigger()),
|
|
229
|
+
h.OnFocus(FocusedTrigger()),
|
|
230
|
+
h.OnBlur(BlurredTrigger()),
|
|
215
231
|
h.OnKeyDownPreventDefault(handleTriggerKeyDown),
|
|
216
232
|
h.OnPointerDown(handleTriggerPointerDown),
|
|
217
233
|
]),
|
|
218
|
-
...(triggerClassName ? [h.Class(triggerClassName)] : []),
|
|
219
|
-
...triggerAttributes,
|
|
220
234
|
];
|
|
221
|
-
const
|
|
222
|
-
|
|
235
|
+
const panelAttributes = [
|
|
236
|
+
h.Id(`${id}-panel`),
|
|
237
|
+
h.Role('tooltip'),
|
|
223
238
|
h.Style({
|
|
224
239
|
position: 'absolute',
|
|
225
240
|
margin: '0',
|
|
226
241
|
visibility: 'hidden',
|
|
227
242
|
pointerEvents: 'none',
|
|
228
243
|
}),
|
|
229
|
-
h.OnMount(
|
|
230
|
-
];
|
|
231
|
-
const resolvedPanelAttributes = [
|
|
232
|
-
h.Id(`${id}-panel`),
|
|
233
|
-
h.Role('tooltip'),
|
|
234
|
-
...anchorAttributes,
|
|
244
|
+
h.OnMount(AnchorTooltip({ buttonId: `${id}-trigger`, anchor })),
|
|
235
245
|
...(isOpen ? [h.DataAttribute('open', '')] : []),
|
|
236
|
-
...(panelClassName ? [h.Class(panelClassName)] : []),
|
|
237
|
-
...panelAttributes,
|
|
238
|
-
];
|
|
239
|
-
const wrapperAttributes = [
|
|
240
|
-
...(className ? [h.Class(className)] : []),
|
|
241
|
-
...attributes,
|
|
242
246
|
];
|
|
243
|
-
return
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
: []),
|
|
250
|
-
]);
|
|
251
|
-
};
|
|
252
|
-
/** Creates a memoized tooltip view. Static config is captured in a closure;
|
|
253
|
-
* only `model` and `toParentMessage` are compared per render via `createLazy`. */
|
|
254
|
-
export const lazy = (staticConfig) => {
|
|
255
|
-
const lazyView = createLazy();
|
|
256
|
-
return (model, toParentMessage) => lazyView((currentModel, currentToParentMessage) => view({
|
|
257
|
-
...staticConfig,
|
|
258
|
-
model: currentModel,
|
|
259
|
-
toParentMessage: currentToParentMessage,
|
|
260
|
-
}), [model, toParentMessage]);
|
|
261
|
-
};
|
|
247
|
+
return toView({
|
|
248
|
+
trigger: childAttributes(triggerAttributes),
|
|
249
|
+
panel: childAttributes(panelAttributes),
|
|
250
|
+
isVisible: isOpen,
|
|
251
|
+
});
|
|
252
|
+
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { init, update, view,
|
|
2
|
-
export type { InitConfig,
|
|
1
|
+
export { init, update, view, reflectShowDelay, Model, Message, OutMessage, Shown, Hidden, EnteredTrigger, LeftTrigger, FocusedTrigger, BlurredTrigger, PressedEscape, PressedPointerOnTrigger, ElapsedShowDelay, ShowAfterDelay, CompletedAnchorTooltip, AnchorTooltip, } from './index.js';
|
|
2
|
+
export type { InitConfig, ViewInputs, RenderInfo } from './index.js';
|
|
3
3
|
export type { AnchorConfig } from '../anchor.js';
|
|
4
4
|
//# sourceMappingURL=public.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"public.d.ts","sourceRoot":"","sources":["../../../src/ui/tooltip/public.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,IAAI,EACJ,MAAM,EACN,IAAI,EACJ,
|
|
1
|
+
{"version":3,"file":"public.d.ts","sourceRoot":"","sources":["../../../src/ui/tooltip/public.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,IAAI,EACJ,MAAM,EACN,IAAI,EACJ,gBAAgB,EAChB,KAAK,EACL,OAAO,EACP,UAAU,EACV,KAAK,EACL,MAAM,EACN,cAAc,EACd,WAAW,EACX,cAAc,EACd,cAAc,EACd,aAAa,EACb,uBAAuB,EACvB,gBAAgB,EAChB,cAAc,EACd,sBAAsB,EACtB,aAAa,GACd,MAAM,YAAY,CAAA;AAEnB,YAAY,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAEpE,YAAY,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export { init, update, view,
|
|
1
|
+
export { init, update, view, reflectShowDelay, Model, Message, OutMessage, Shown, Hidden, EnteredTrigger, LeftTrigger, FocusedTrigger, BlurredTrigger, PressedEscape, PressedPointerOnTrigger, ElapsedShowDelay, ShowAfterDelay, CompletedAnchorTooltip, AnchorTooltip, } from './index.js';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { Effect, Option, Schema as S } from 'effect';
|
|
1
|
+
import { Effect, Option, Schema as S, Stream } from 'effect';
|
|
2
2
|
import * as Command from '../../command/index.js';
|
|
3
|
-
import { type
|
|
3
|
+
import { type ChildAttribute, type Html, type SubmodelView, type TagName } from '../../html/index.js';
|
|
4
4
|
/** Schema for the virtual list's state. Tracks scroll position, container
|
|
5
5
|
* measurement, and any in-flight programmatic scroll. */
|
|
6
6
|
export declare const Model: S.Struct<{
|
|
@@ -123,13 +123,6 @@ export declare const visibleWindow: (model: Model, itemCount: number, overscan:
|
|
|
123
123
|
*
|
|
124
124
|
* Returns `Option.none()` when the container has not yet been measured. */
|
|
125
125
|
export declare const visibleWindowVariable: <Item>(model: Model, items: ReadonlyArray<Item>, itemToRowHeightPx: (item: Item, index: number) => number, overscan: number) => Option.Option<VisibleWindow>;
|
|
126
|
-
/** Schema describing the subscription dependencies for container scroll and
|
|
127
|
-
* resize tracking. */
|
|
128
|
-
export declare const SubscriptionDependencies: S.Struct<{
|
|
129
|
-
readonly containerEvents: S.Struct<{
|
|
130
|
-
readonly id: S.String;
|
|
131
|
-
}>;
|
|
132
|
-
}>;
|
|
133
126
|
/** Subscriptions that track the container's scroll position and size.
|
|
134
127
|
*
|
|
135
128
|
* - **scroll**: listens for `scroll` events on the container element and
|
|
@@ -143,87 +136,77 @@ export declare const SubscriptionDependencies: S.Struct<{
|
|
|
143
136
|
* makes the subscription robust across SPA route changes: navigating to a
|
|
144
137
|
* page that mounts the list, away, and back all reattach correctly without
|
|
145
138
|
* the consumer having to teach the framework about navigation. */
|
|
146
|
-
export declare const subscriptions:
|
|
147
|
-
readonly
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
readonly
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
139
|
+
export declare const subscriptions: {
|
|
140
|
+
readonly containerEvents: {
|
|
141
|
+
readonly dependenciesSchema: S.Schema<{
|
|
142
|
+
readonly id: string;
|
|
143
|
+
}> & {
|
|
144
|
+
readonly fields: S.Struct.Fields;
|
|
145
|
+
};
|
|
146
|
+
readonly modelToDependencies: (model: {
|
|
147
|
+
readonly id: string;
|
|
148
|
+
readonly rowHeightPx: number;
|
|
149
|
+
readonly scrollTop: number;
|
|
150
|
+
readonly measurement: {
|
|
151
|
+
readonly _tag: "Unmeasured";
|
|
152
|
+
} | {
|
|
153
|
+
readonly _tag: "Measured";
|
|
154
|
+
readonly containerHeight: number;
|
|
155
|
+
};
|
|
156
|
+
readonly pendingScroll: {
|
|
157
|
+
readonly _tag: "Idle";
|
|
158
|
+
} | {
|
|
159
|
+
readonly _tag: "ScrollingToIndex";
|
|
160
|
+
readonly index: number;
|
|
161
|
+
readonly version: number;
|
|
162
|
+
};
|
|
163
|
+
readonly pendingScrollVersion: number;
|
|
164
|
+
}) => {
|
|
165
|
+
readonly id: string;
|
|
166
|
+
};
|
|
167
|
+
readonly keepAliveEquivalence?: never;
|
|
168
|
+
readonly dependenciesToStream: (dependencies: {
|
|
169
|
+
readonly id: string;
|
|
170
|
+
}) => Stream.Stream<{
|
|
171
|
+
readonly _tag: "ScrolledContainer";
|
|
172
|
+
readonly scrollTop: number;
|
|
173
|
+
} | {
|
|
174
|
+
readonly _tag: "MeasuredContainer";
|
|
175
|
+
readonly containerHeight: number;
|
|
176
|
+
} | {
|
|
177
|
+
readonly _tag: "CompletedApplyScroll";
|
|
178
|
+
readonly version: number;
|
|
179
|
+
}, never, never>;
|
|
180
|
+
} & {
|
|
181
|
+
readonly __subscription: never;
|
|
162
182
|
};
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
readonly _tag: "ScrolledContainer";
|
|
166
|
-
readonly scrollTop: number;
|
|
167
|
-
} | {
|
|
168
|
-
readonly _tag: "MeasuredContainer";
|
|
169
|
-
readonly containerHeight: number;
|
|
170
|
-
} | {
|
|
171
|
-
readonly _tag: "CompletedApplyScroll";
|
|
172
|
-
readonly version: number;
|
|
173
|
-
}, S.Struct<{
|
|
174
|
-
readonly containerEvents: S.Struct<{
|
|
175
|
-
readonly id: S.String;
|
|
176
|
-
}>;
|
|
177
|
-
}>, never>;
|
|
178
|
-
/** Configuration for rendering a virtual list with `view`.
|
|
183
|
+
};
|
|
184
|
+
/** Per-render view inputs passed to `view` via `h.submodel`'s `viewInputs` field.
|
|
179
185
|
*
|
|
180
|
-
* VirtualList does not
|
|
186
|
+
* VirtualList does not surface event handlers in the view. All input
|
|
181
187
|
* (scroll events and resize observations) flows through the
|
|
182
|
-
* `containerEvents` Subscription
|
|
183
|
-
*
|
|
184
|
-
*
|
|
185
|
-
export type
|
|
186
|
-
model: Model;
|
|
188
|
+
* `containerEvents` Subscription. The consumer wraps that
|
|
189
|
+
* Subscription's stream into their parent Message in their own
|
|
190
|
+
* `subscriptions` definition. */
|
|
191
|
+
export type ViewInputs<Item> = Readonly<{
|
|
187
192
|
items: ReadonlyArray<Item>;
|
|
188
193
|
itemToKey: (item: Item, index: number) => string;
|
|
189
194
|
itemToView: (item: Item, index: number) => Html;
|
|
190
|
-
/** Optional per-item row height in pixels. When provided, the list renders
|
|
191
|
-
* with variable-height rows: each row's wrapper takes the height returned
|
|
192
|
-
* by this callback, and scroll math walks the items to compute the visible
|
|
193
|
-
* slice and spacers. When absent, all rows use `model.rowHeightPx`. Use
|
|
194
|
-
* this for tables with wrapping cells, taller detail rows, or any list
|
|
195
|
-
* where rows differ. Prefer the uniform `rowHeightPx` path when row
|
|
196
|
-
* heights are stable: it avoids the per-render walk over `items`. */
|
|
197
195
|
itemToRowHeightPx?: (item: Item, index: number) => number;
|
|
198
|
-
/** Number of rows rendered above and below the visible viewport. Higher
|
|
199
|
-
* values smooth out fast scroll at the cost of mounting more DOM. Default
|
|
200
|
-
* is 5; react-window uses 1 and react-virtualized uses 3. Pick a value
|
|
201
|
-
* that suits the row's mount cost. */
|
|
202
196
|
overscan?: number;
|
|
203
197
|
rowElement?: TagName;
|
|
204
|
-
|
|
205
|
-
|
|
198
|
+
containerClassName?: string;
|
|
199
|
+
containerAttributes?: ReadonlyArray<ChildAttribute>;
|
|
206
200
|
}>;
|
|
207
201
|
/** Renders a virtualized list. Only items inside the viewport (plus an
|
|
208
|
-
* overscan buffer) are mounted; spacer elements above and below the
|
|
209
|
-
* keep the scrollbar's apparent total height correct.
|
|
210
|
-
*
|
|
211
|
-
* Items must be keyed via `itemToKey` so the VDOM matches `row 150` to
|
|
212
|
-
* `row 150` after the slice shifts during scroll, rather than matching by
|
|
213
|
-
* position and producing stale DOM.
|
|
214
|
-
*
|
|
215
|
-
* Each row wrapper is rendered with `display: grid` so the consumer's
|
|
216
|
-
* `itemToView` content fills the configured `rowHeightPx` and the full row
|
|
217
|
-
* width. Use flex/grid with `align-items: center` inside `itemToView` to
|
|
218
|
-
* vertically center content within the row.
|
|
202
|
+
* overscan buffer) are mounted; spacer elements above and below the
|
|
203
|
+
* slice keep the scrollbar's apparent total height correct.
|
|
219
204
|
*
|
|
220
|
-
*
|
|
221
|
-
*
|
|
222
|
-
*
|
|
223
|
-
*
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
* `createLazy`. */
|
|
228
|
-
export declare const lazy: <ParentMessage, Item>(staticConfig: Omit<ViewConfig<ParentMessage, Item>, "model" | "items">) => ((model: Model, items: ReadonlyArray<Item>) => Html);
|
|
205
|
+
* Generic over `Item`: call as `Ui.VirtualList.view<MyItem>()` at the
|
|
206
|
+
* embed site to get a `SubmodelView` typed for your item type. The
|
|
207
|
+
* underlying view implementation is shared; the call only narrows the
|
|
208
|
+
* type. */
|
|
209
|
+
type ViewForItem<Item> = SubmodelView<Model, Message, ViewInputs<Item>>;
|
|
210
|
+
export declare const view: <Item>() => ViewForItem<Item>;
|
|
211
|
+
export {};
|
|
229
212
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/ui/virtualList/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,MAAM,EAGN,MAAM,EAEN,MAAM,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/ui/virtualList/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { Array, Effect, Match as M, Number, Option, Queue, Schema as S, Stream, pipe, } from 'effect';
|
|
2
2
|
import * as Command from '../../command/index.js';
|
|
3
|
-
import {
|
|
3
|
+
import { childAttributes, defineView, html, } from '../../html/index.js';
|
|
4
4
|
import { m } from '../../message/index.js';
|
|
5
|
-
import
|
|
5
|
+
import * as Subscription from '../../runtime/subscription.js';
|
|
6
6
|
import { ts } from '../../schema/index.js';
|
|
7
7
|
import { evo } from '../../struct/index.js';
|
|
8
8
|
// MODEL
|
|
@@ -235,13 +235,6 @@ export const visibleWindowVariable = (model, items, itemToRowHeightPx, overscan)
|
|
|
235
235
|
}));
|
|
236
236
|
// SUBSCRIPTION
|
|
237
237
|
const containerElement = (id) => Option.fromNullishOr(document.getElementById(id));
|
|
238
|
-
/** Schema describing the subscription dependencies for container scroll and
|
|
239
|
-
* resize tracking. */
|
|
240
|
-
export const SubscriptionDependencies = S.Struct({
|
|
241
|
-
containerEvents: S.Struct({
|
|
242
|
-
id: S.String,
|
|
243
|
-
}),
|
|
244
|
-
});
|
|
245
238
|
/** Subscriptions that track the container's scroll position and size.
|
|
246
239
|
*
|
|
247
240
|
* - **scroll**: listens for `scroll` events on the container element and
|
|
@@ -255,8 +248,8 @@ export const SubscriptionDependencies = S.Struct({
|
|
|
255
248
|
* makes the subscription robust across SPA route changes: navigating to a
|
|
256
249
|
* page that mounts the list, away, and back all reattach correctly without
|
|
257
250
|
* the consumer having to teach the framework about navigation. */
|
|
258
|
-
export const subscriptions =
|
|
259
|
-
containerEvents: {
|
|
251
|
+
export const subscriptions = Subscription.make()(entry => ({
|
|
252
|
+
containerEvents: entry({ id: S.String }, {
|
|
260
253
|
modelToDependencies: model => ({ id: model.id }),
|
|
261
254
|
dependenciesToStream: ({ id }) => Stream.callback(queue => Effect.acquireRelease(Effect.sync(() => {
|
|
262
255
|
const state = {
|
|
@@ -335,31 +328,17 @@ export const subscriptions = makeSubscriptions(SubscriptionDependencies)({
|
|
|
335
328
|
}
|
|
336
329
|
detach();
|
|
337
330
|
})).pipe(Effect.flatMap(() => Effect.never))),
|
|
338
|
-
},
|
|
339
|
-
});
|
|
331
|
+
}),
|
|
332
|
+
}));
|
|
340
333
|
// VIEW
|
|
341
334
|
const DEFAULT_OVERSCAN = 5;
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
* Items must be keyed via `itemToKey` so the VDOM matches `row 150` to
|
|
347
|
-
* `row 150` after the slice shifts during scroll, rather than matching by
|
|
348
|
-
* position and producing stale DOM.
|
|
349
|
-
*
|
|
350
|
-
* Each row wrapper is rendered with `display: grid` so the consumer's
|
|
351
|
-
* `itemToView` content fills the configured `rowHeightPx` and the full row
|
|
352
|
-
* width. Use flex/grid with `align-items: center` inside `itemToView` to
|
|
353
|
-
* vertically center content within the row.
|
|
354
|
-
*
|
|
355
|
-
* Each row carries `aria-setsize` (total item count) and `aria-posinset`
|
|
356
|
-
* (1-based logical row index) so screen readers announce the full list
|
|
357
|
-
* size and each row's position within it, rather than the much smaller
|
|
358
|
-
* count of currently mounted rows. */
|
|
359
|
-
export const view = (config) => {
|
|
335
|
+
export const view = () =>
|
|
336
|
+
/* eslint-disable-next-line @typescript-eslint/consistent-type-assertions */
|
|
337
|
+
viewImpl;
|
|
338
|
+
const viewImpl = defineView((model, viewInputs) => {
|
|
360
339
|
const h = html();
|
|
361
|
-
const {
|
|
362
|
-
const
|
|
340
|
+
const { items, itemToKey, itemToView, itemToRowHeightPx, overscan = DEFAULT_OVERSCAN, rowElement = 'li', containerClassName, containerAttributes = [], } = viewInputs;
|
|
341
|
+
const baseContainerAttributes = [
|
|
363
342
|
h.Id(model.id),
|
|
364
343
|
h.Role('list'),
|
|
365
344
|
h.DataAttribute('virtual-list-id', model.id),
|
|
@@ -369,10 +348,15 @@ export const view = (config) => {
|
|
|
369
348
|
margin: '0',
|
|
370
349
|
padding: '0',
|
|
371
350
|
}),
|
|
372
|
-
...(
|
|
373
|
-
|
|
351
|
+
...(containerClassName !== undefined
|
|
352
|
+
? [h.Class(containerClassName)]
|
|
353
|
+
: []),
|
|
354
|
+
];
|
|
355
|
+
const allContainerAttributes = [
|
|
356
|
+
...childAttributes(baseContainerAttributes),
|
|
357
|
+
...containerAttributes,
|
|
374
358
|
];
|
|
375
|
-
const renderContainer = (children) => h.keyed('ul')(model.id,
|
|
359
|
+
const renderContainer = (children) => h.keyed('ul')(model.id, allContainerAttributes, children);
|
|
376
360
|
const maybeWindow = itemToRowHeightPx !== undefined
|
|
377
361
|
? visibleWindowVariable(model, items, itemToRowHeightPx, overscan)
|
|
378
362
|
: visibleWindow(model, items.length, overscan);
|
|
@@ -381,7 +365,7 @@ export const view = (config) => {
|
|
|
381
365
|
: model.rowHeightPx;
|
|
382
366
|
return Option.match(maybeWindow, {
|
|
383
367
|
onNone: () => renderContainer([]),
|
|
384
|
-
onSome: ({ startIndex, endIndex, topSpacerHeight, bottomSpacerHeight }) => {
|
|
368
|
+
onSome: ({ startIndex, endIndex, topSpacerHeight, bottomSpacerHeight, }) => {
|
|
385
369
|
const visibleItems = items.slice(startIndex, endIndex);
|
|
386
370
|
const topSpacer = h.keyed('li')(`${model.id}-top-spacer`, [h.Role('presentation'), h.Style({ height: `${topSpacerHeight}px` })], []);
|
|
387
371
|
const bottomSpacer = h.keyed('li')(`${model.id}-bottom-spacer`, [
|
|
@@ -404,15 +388,4 @@ export const view = (config) => {
|
|
|
404
388
|
return renderContainer([topSpacer, ...renderedRows, bottomSpacer]);
|
|
405
389
|
},
|
|
406
390
|
});
|
|
407
|
-
};
|
|
408
|
-
/** Creates a memoized virtual list view. Static config is captured in a
|
|
409
|
-
* closure; only `model` and `items` are compared per render via
|
|
410
|
-
* `createLazy`. */
|
|
411
|
-
export const lazy = (staticConfig) => {
|
|
412
|
-
const lazyView = createLazy();
|
|
413
|
-
return (model, items) => lazyView((currentModel, currentItems) => view({
|
|
414
|
-
...staticConfig,
|
|
415
|
-
model: currentModel,
|
|
416
|
-
items: currentItems,
|
|
417
|
-
}), [model, items]);
|
|
418
|
-
};
|
|
391
|
+
});
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { init, update, scrollToIndex, scrollToIndexVariable, view,
|
|
2
|
-
export type { InitConfig,
|
|
1
|
+
export { init, update, scrollToIndex, scrollToIndexVariable, view, subscriptions, visibleWindow, visibleWindowVariable, Model, Message, ScrolledContainer, MeasuredContainer, CompletedApplyScroll, } from './index.js';
|
|
2
|
+
export type { InitConfig, ViewInputs, VisibleWindow } from './index.js';
|
|
3
3
|
//# sourceMappingURL=public.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"public.d.ts","sourceRoot":"","sources":["../../../src/ui/virtualList/public.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,IAAI,EACJ,MAAM,EACN,aAAa,EACb,qBAAqB,EACrB,IAAI,EACJ,
|
|
1
|
+
{"version":3,"file":"public.d.ts","sourceRoot":"","sources":["../../../src/ui/virtualList/public.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,IAAI,EACJ,MAAM,EACN,aAAa,EACb,qBAAqB,EACrB,IAAI,EACJ,aAAa,EACb,aAAa,EACb,qBAAqB,EACrB,KAAK,EACL,OAAO,EACP,iBAAiB,EACjB,iBAAiB,EACjB,oBAAoB,GACrB,MAAM,YAAY,CAAA;AAEnB,YAAY,EAAE,UAAU,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export { init, update, scrollToIndex, scrollToIndexVariable, view,
|
|
1
|
+
export { init, update, scrollToIndex, scrollToIndexVariable, view, subscriptions, visibleWindow, visibleWindowVariable, Model, Message, ScrolledContainer, MeasuredContainer, CompletedApplyScroll, } from './index.js';
|