foldkit 0.101.0 → 0.102.1
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 +2 -1
- 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 +137 -110
- 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 +3 -1
- package/dist/runtime/runtime.d.ts.map +1 -1
- package/dist/runtime/runtime.js +123 -67
- 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/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 +6 -6
- package/dist/ui/dragAndDrop/index.d.ts.map +1 -1
- package/dist/ui/dragAndDrop/index.js +7 -7
- 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 +72 -34
- package/dist/ui/slider/index.d.ts.map +1 -1
- package/dist/ui/slider/index.js +40 -49
- 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 +18 -41
- package/dist/ui/virtualList/index.d.ts.map +1 -1
- package/dist/ui/virtualList/index.js +17 -37
- 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/dist/vdom.d.ts +3 -2
- package/dist/vdom.d.ts.map +1 -1
- package/dist/vdom.js +44 -0
- 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
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<{
|
|
@@ -181,55 +181,32 @@ export declare const subscriptions: {
|
|
|
181
181
|
readonly __subscription: never;
|
|
182
182
|
};
|
|
183
183
|
};
|
|
184
|
-
/**
|
|
184
|
+
/** Per-render view inputs passed to `view` via `h.submodel`'s `viewInputs` field.
|
|
185
185
|
*
|
|
186
|
-
* VirtualList does not
|
|
186
|
+
* VirtualList does not surface event handlers in the view. All input
|
|
187
187
|
* (scroll events and resize observations) flows through the
|
|
188
|
-
* `containerEvents` Subscription
|
|
189
|
-
*
|
|
190
|
-
*
|
|
191
|
-
export type
|
|
192
|
-
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<{
|
|
193
192
|
items: ReadonlyArray<Item>;
|
|
194
193
|
itemToKey: (item: Item, index: number) => string;
|
|
195
194
|
itemToView: (item: Item, index: number) => Html;
|
|
196
|
-
/** Optional per-item row height in pixels. When provided, the list renders
|
|
197
|
-
* with variable-height rows: each row's wrapper takes the height returned
|
|
198
|
-
* by this callback, and scroll math walks the items to compute the visible
|
|
199
|
-
* slice and spacers. When absent, all rows use `model.rowHeightPx`. Use
|
|
200
|
-
* this for tables with wrapping cells, taller detail rows, or any list
|
|
201
|
-
* where rows differ. Prefer the uniform `rowHeightPx` path when row
|
|
202
|
-
* heights are stable: it avoids the per-render walk over `items`. */
|
|
203
195
|
itemToRowHeightPx?: (item: Item, index: number) => number;
|
|
204
|
-
/** Number of rows rendered above and below the visible viewport. Higher
|
|
205
|
-
* values smooth out fast scroll at the cost of mounting more DOM. Default
|
|
206
|
-
* is 5; react-window uses 1 and react-virtualized uses 3. Pick a value
|
|
207
|
-
* that suits the row's mount cost. */
|
|
208
196
|
overscan?: number;
|
|
209
197
|
rowElement?: TagName;
|
|
210
|
-
|
|
211
|
-
|
|
198
|
+
containerClassName?: string;
|
|
199
|
+
containerAttributes?: ReadonlyArray<ChildAttribute>;
|
|
212
200
|
}>;
|
|
213
201
|
/** Renders a virtualized list. Only items inside the viewport (plus an
|
|
214
|
-
* overscan buffer) are mounted; spacer elements above and below the
|
|
215
|
-
* keep the scrollbar's apparent total height correct.
|
|
202
|
+
* overscan buffer) are mounted; spacer elements above and below the
|
|
203
|
+
* slice keep the scrollbar's apparent total height correct.
|
|
216
204
|
*
|
|
217
|
-
*
|
|
218
|
-
*
|
|
219
|
-
*
|
|
220
|
-
*
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
* vertically center content within the row.
|
|
225
|
-
*
|
|
226
|
-
* Each row carries `aria-setsize` (total item count) and `aria-posinset`
|
|
227
|
-
* (1-based logical row index) so screen readers announce the full list
|
|
228
|
-
* size and each row's position within it, rather than the much smaller
|
|
229
|
-
* count of currently mounted rows. */
|
|
230
|
-
export declare const view: <ParentMessage, Item>(config: ViewConfig<ParentMessage, Item>) => Html;
|
|
231
|
-
/** Creates a memoized virtual list view. Static config is captured in a
|
|
232
|
-
* closure; only `model` and `items` are compared per render via
|
|
233
|
-
* `createLazy`. */
|
|
234
|
-
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 {};
|
|
235
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,EACX,MAAM,EAEP,MAAM,QAAQ,CAAA;AAEf,OAAO,KAAK,OAAO,MAAM,wBAAwB,CAAA;AACjD,OAAO,EACL,KAAK,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/ui/virtualList/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
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
5
|
import * as Subscription from '../../runtime/subscription.js';
|
|
6
6
|
import { ts } from '../../schema/index.js';
|
|
@@ -332,27 +332,13 @@ export const subscriptions = Subscription.make()(entry => ({
|
|
|
332
332
|
}));
|
|
333
333
|
// VIEW
|
|
334
334
|
const DEFAULT_OVERSCAN = 5;
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
* Items must be keyed via `itemToKey` so the VDOM matches `row 150` to
|
|
340
|
-
* `row 150` after the slice shifts during scroll, rather than matching by
|
|
341
|
-
* position and producing stale DOM.
|
|
342
|
-
*
|
|
343
|
-
* Each row wrapper is rendered with `display: grid` so the consumer's
|
|
344
|
-
* `itemToView` content fills the configured `rowHeightPx` and the full row
|
|
345
|
-
* width. Use flex/grid with `align-items: center` inside `itemToView` to
|
|
346
|
-
* vertically center content within the row.
|
|
347
|
-
*
|
|
348
|
-
* Each row carries `aria-setsize` (total item count) and `aria-posinset`
|
|
349
|
-
* (1-based logical row index) so screen readers announce the full list
|
|
350
|
-
* size and each row's position within it, rather than the much smaller
|
|
351
|
-
* count of currently mounted rows. */
|
|
352
|
-
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) => {
|
|
353
339
|
const h = html();
|
|
354
|
-
const {
|
|
355
|
-
const
|
|
340
|
+
const { items, itemToKey, itemToView, itemToRowHeightPx, overscan = DEFAULT_OVERSCAN, rowElement = 'li', containerClassName, containerAttributes = [], } = viewInputs;
|
|
341
|
+
const baseContainerAttributes = [
|
|
356
342
|
h.Id(model.id),
|
|
357
343
|
h.Role('list'),
|
|
358
344
|
h.DataAttribute('virtual-list-id', model.id),
|
|
@@ -362,10 +348,15 @@ export const view = (config) => {
|
|
|
362
348
|
margin: '0',
|
|
363
349
|
padding: '0',
|
|
364
350
|
}),
|
|
365
|
-
...(
|
|
366
|
-
|
|
351
|
+
...(containerClassName !== undefined
|
|
352
|
+
? [h.Class(containerClassName)]
|
|
353
|
+
: []),
|
|
354
|
+
];
|
|
355
|
+
const allContainerAttributes = [
|
|
356
|
+
...childAttributes(baseContainerAttributes),
|
|
357
|
+
...containerAttributes,
|
|
367
358
|
];
|
|
368
|
-
const renderContainer = (children) => h.keyed('ul')(model.id,
|
|
359
|
+
const renderContainer = (children) => h.keyed('ul')(model.id, allContainerAttributes, children);
|
|
369
360
|
const maybeWindow = itemToRowHeightPx !== undefined
|
|
370
361
|
? visibleWindowVariable(model, items, itemToRowHeightPx, overscan)
|
|
371
362
|
: visibleWindow(model, items.length, overscan);
|
|
@@ -374,7 +365,7 @@ export const view = (config) => {
|
|
|
374
365
|
: model.rowHeightPx;
|
|
375
366
|
return Option.match(maybeWindow, {
|
|
376
367
|
onNone: () => renderContainer([]),
|
|
377
|
-
onSome: ({ startIndex, endIndex, topSpacerHeight, bottomSpacerHeight }) => {
|
|
368
|
+
onSome: ({ startIndex, endIndex, topSpacerHeight, bottomSpacerHeight, }) => {
|
|
378
369
|
const visibleItems = items.slice(startIndex, endIndex);
|
|
379
370
|
const topSpacer = h.keyed('li')(`${model.id}-top-spacer`, [h.Role('presentation'), h.Style({ height: `${topSpacerHeight}px` })], []);
|
|
380
371
|
const bottomSpacer = h.keyed('li')(`${model.id}-bottom-spacer`, [
|
|
@@ -397,15 +388,4 @@ export const view = (config) => {
|
|
|
397
388
|
return renderContainer([topSpacer, ...renderedRows, bottomSpacer]);
|
|
398
389
|
},
|
|
399
390
|
});
|
|
400
|
-
};
|
|
401
|
-
/** Creates a memoized virtual list view. Static config is captured in a
|
|
402
|
-
* closure; only `model` and `items` are compared per render via
|
|
403
|
-
* `createLazy`. */
|
|
404
|
-
export const lazy = (staticConfig) => {
|
|
405
|
-
const lazyView = createLazy();
|
|
406
|
-
return (model, items) => lazyView((currentModel, currentItems) => view({
|
|
407
|
-
...staticConfig,
|
|
408
|
-
model: currentModel,
|
|
409
|
-
items: currentItems,
|
|
410
|
-
}), [model, items]);
|
|
411
|
-
};
|
|
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';
|
package/dist/vdom.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { toVNode } from 'snabbdom';
|
|
1
|
+
import { type VNode, toVNode } from 'snabbdom';
|
|
2
2
|
export type { VNode } from 'snabbdom';
|
|
3
3
|
export { toVNode };
|
|
4
|
-
export declare const patch: (oldVnode:
|
|
4
|
+
export declare const patch: (oldVnode: VNode | Element | DocumentFragment, vnode: VNode) => VNode;
|
|
5
|
+
export declare const dedupeSharedVNodes: (root: VNode) => VNode;
|
|
5
6
|
//# sourceMappingURL=vdom.d.ts.map
|
package/dist/vdom.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vdom.d.ts","sourceRoot":"","sources":["../src/vdom.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"vdom.d.ts","sourceRoot":"","sources":["../src/vdom.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,KAAK,EAOV,OAAO,EACR,MAAM,UAAU,CAAA;AAIjB,YAAY,EAAE,KAAK,EAAE,MAAM,UAAU,CAAA;AACrC,OAAO,EAAE,OAAO,EAAE,CAAA;AAElB,eAAO,MAAM,KAAK,uEAOhB,CAAA;AAeF,eAAO,MAAM,kBAAkB,GAAI,MAAM,KAAK,KAAG,KA8BhD,CAAA"}
|
package/dist/vdom.js
CHANGED
|
@@ -9,3 +9,47 @@ export const patch = init([
|
|
|
9
9
|
propsModule,
|
|
10
10
|
styleModule,
|
|
11
11
|
]);
|
|
12
|
+
// NOTE: snabbdom records each element's live DOM node on `vnode.elm` by
|
|
13
|
+
// mutating the vnode object during patch. A vnode object placed in more than
|
|
14
|
+
// one tree position would share a single `.elm`, so removals and text updates
|
|
15
|
+
// land on the wrong DOM node. View code legitimately reuses vnode values, e.g.
|
|
16
|
+
// `const checkmark = h.span(...)` dropped into several slots, so before each
|
|
17
|
+
// patch we clone any vnode object reached a second time, giving every position
|
|
18
|
+
// its own object.
|
|
19
|
+
// Detection is keyed off a per-patch Set, so a vnode reused across renders (a
|
|
20
|
+
// memoized `createLazy` subtree, the identical object each render) is reached
|
|
21
|
+
// only once per patch and passes through untouched, leaving snabbdom's
|
|
22
|
+
// same-object subtree short-circuit intact. Allocation happens only along
|
|
23
|
+
// paths where a duplicate is actually found; a tree with no reuse returns
|
|
24
|
+
// unchanged.
|
|
25
|
+
export const dedupeSharedVNodes = (root) => {
|
|
26
|
+
const seen = new Set();
|
|
27
|
+
const visit = (node) => {
|
|
28
|
+
const base = seen.has(node) ? { ...node, elm: undefined } : node;
|
|
29
|
+
seen.add(base);
|
|
30
|
+
const children = base.children;
|
|
31
|
+
if (children === undefined) {
|
|
32
|
+
return base;
|
|
33
|
+
}
|
|
34
|
+
let nextChildren;
|
|
35
|
+
for (let index = 0; index < children.length; index++) {
|
|
36
|
+
const child = children[index];
|
|
37
|
+
const deduped = typeof child === 'string' ? child : visit(child);
|
|
38
|
+
if (deduped !== child) {
|
|
39
|
+
if (nextChildren === undefined) {
|
|
40
|
+
nextChildren = children.slice();
|
|
41
|
+
}
|
|
42
|
+
nextChildren[index] = deduped;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
if (nextChildren === undefined) {
|
|
46
|
+
return base;
|
|
47
|
+
}
|
|
48
|
+
if (base === node) {
|
|
49
|
+
return { ...node, children: nextChildren };
|
|
50
|
+
}
|
|
51
|
+
base.children = nextChildren;
|
|
52
|
+
return base;
|
|
53
|
+
};
|
|
54
|
+
return visit(root);
|
|
55
|
+
};
|