foldkit-primitives 0.1.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.
Files changed (41) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +454 -0
  3. package/dist/device/index.d.mts +312 -0
  4. package/dist/device/index.d.mts.map +1 -0
  5. package/dist/device/index.mjs +490 -0
  6. package/dist/device/index.mjs.map +1 -0
  7. package/dist/dom/index.d.mts +73 -0
  8. package/dist/dom/index.d.mts.map +1 -0
  9. package/dist/dom/index.mjs +218 -0
  10. package/dist/dom/index.mjs.map +1 -0
  11. package/dist/events/index.d.mts +154 -0
  12. package/dist/events/index.d.mts.map +1 -0
  13. package/dist/events/index.mjs +287 -0
  14. package/dist/events/index.mjs.map +1 -0
  15. package/dist/index.d.mts +10 -0
  16. package/dist/index.mjs +10 -0
  17. package/dist/media/index.d.mts +79 -0
  18. package/dist/media/index.d.mts.map +1 -0
  19. package/dist/media/index.mjs +127 -0
  20. package/dist/media/index.mjs.map +1 -0
  21. package/dist/motion/index.d.mts +112 -0
  22. package/dist/motion/index.d.mts.map +1 -0
  23. package/dist/motion/index.mjs +208 -0
  24. package/dist/motion/index.mjs.map +1 -0
  25. package/dist/net/index.d.mts +199 -0
  26. package/dist/net/index.d.mts.map +1 -0
  27. package/dist/net/index.mjs +329 -0
  28. package/dist/net/index.mjs.map +1 -0
  29. package/dist/observers/index.d.mts +59 -0
  30. package/dist/observers/index.d.mts.map +1 -0
  31. package/dist/observers/index.mjs +156 -0
  32. package/dist/observers/index.mjs.map +1 -0
  33. package/dist/state/index.d.mts +342 -0
  34. package/dist/state/index.d.mts.map +1 -0
  35. package/dist/state/index.mjs +504 -0
  36. package/dist/state/index.mjs.map +1 -0
  37. package/dist/time/index.d.mts +129 -0
  38. package/dist/time/index.d.mts.map +1 -0
  39. package/dist/time/index.mjs +213 -0
  40. package/dist/time/index.mjs.map +1 -0
  41. package/package.json +96 -0
@@ -0,0 +1,342 @@
1
+ import { Schema } from "effect";
2
+ import * as Mount from "foldkit/mount";
3
+ import { Bundle } from "foldkit-bundle";
4
+ //#region src/state/history.d.ts
5
+ export declare const HistoryModel: <Value>(value: Schema.Codec<Value, unknown>) => Schema.Struct<{
6
+ readonly past: Schema.$Array<Schema.Codec<Value, unknown, never, never>>;
7
+ readonly present: Schema.Codec<Value, unknown, never, never>;
8
+ readonly future: Schema.$Array<Schema.Codec<Value, unknown, never, never>>;
9
+ }>;
10
+ export type HistoryModel<Value> = {
11
+ readonly past: ReadonlyArray<Value>;
12
+ readonly present: Value;
13
+ readonly future: ReadonlyArray<Value>;
14
+ };
15
+ export declare const history: <const Name extends string, Value>(config: {
16
+ readonly name: Name;
17
+ readonly value: Schema.Codec<Value, unknown>;
18
+ readonly capacity?: number | undefined;
19
+ }) => Bundle.Bundle<Name, {
20
+ readonly initial: Value;
21
+ }, {
22
+ readonly past: readonly Value[];
23
+ readonly present: Value;
24
+ readonly future: readonly Value[];
25
+ }, {
26
+ readonly _tag: "Push";
27
+ readonly value: Value;
28
+ } | {
29
+ readonly _tag: "Undo";
30
+ } | {
31
+ readonly _tag: "Redo";
32
+ } | {
33
+ readonly _tag: "Clear";
34
+ }, never, never, never, void, {}, {}> & {
35
+ Message: import("foldkit/message").MessageUnion<{
36
+ readonly Push: {
37
+ readonly value: Schema.Codec<Value, unknown, never, never>;
38
+ };
39
+ readonly Undo: {};
40
+ readonly Redo: {};
41
+ readonly Clear: {};
42
+ }>;
43
+ };
44
+ /** Whether Undo would move: the past is non-empty. */
45
+ export declare const canUndo: <Value>(model: HistoryModel<Value>) => boolean;
46
+ /** Whether Redo would move: the future is non-empty. */
47
+ export declare const canRedo: <Value>(model: HistoryModel<Value>) => boolean;
48
+ //#endregion
49
+ //#region src/state/locale.d.ts
50
+ export declare const LocaleModel: Schema.Struct<{
51
+ readonly locale: Schema.String;
52
+ }>;
53
+ export type LocaleModel = typeof LocaleModel.Type;
54
+ export declare const LocaleMessage: import("foldkit/message").MessageUnion<{
55
+ readonly SetLocale: {
56
+ readonly locale: Schema.String;
57
+ };
58
+ }>;
59
+ export type LocaleMessage = typeof LocaleMessage.Type;
60
+ export declare const Locale: Bundle.Bundle<"Locale", {
61
+ readonly default: string;
62
+ }, {
63
+ locale: string;
64
+ }, {
65
+ readonly _tag: "SetLocale";
66
+ readonly locale: string;
67
+ }, never, never, never, void, {}, {}>;
68
+ //#endregion
69
+ //#region src/state/pagination.d.ts
70
+ export declare const PaginationModel: Schema.Struct<{
71
+ readonly page: Schema.Number;
72
+ readonly perPage: Schema.Number;
73
+ readonly total: Schema.NullOr<Schema.Number>;
74
+ }>;
75
+ export type PaginationModel = typeof PaginationModel.Type;
76
+ export declare const PaginationMessage: import("foldkit/message").MessageUnion<{
77
+ readonly GoToPage: {
78
+ readonly page: Schema.Number;
79
+ };
80
+ readonly NextPage: {};
81
+ readonly PrevPage: {};
82
+ readonly SetPerPage: {
83
+ readonly perPage: Schema.Number;
84
+ };
85
+ readonly SetTotal: {
86
+ readonly total: Schema.NullOr<Schema.Number>;
87
+ };
88
+ }>;
89
+ export type PaginationMessage = typeof PaginationMessage.Type;
90
+ /** The number of pages, or null while the total is unknown. */
91
+ export declare const pageCount: (model: PaginationModel) => number | null;
92
+ /** The offset of the first item on the page, for a slice or a query. */
93
+ export declare const offset: (model: PaginationModel) => number;
94
+ export declare const Pagination: Bundle.Bundle<"Pagination", {
95
+ readonly perPage: number;
96
+ readonly total?: number | null | undefined;
97
+ }, {
98
+ total: number | null;
99
+ page: number;
100
+ perPage: number;
101
+ }, {
102
+ readonly _tag: "GoToPage";
103
+ readonly page: number;
104
+ } | {
105
+ readonly _tag: "NextPage";
106
+ } | {
107
+ readonly _tag: "PrevPage";
108
+ } | {
109
+ readonly _tag: "SetPerPage";
110
+ readonly perPage: number;
111
+ } | {
112
+ readonly _tag: "SetTotal";
113
+ readonly total: number | null;
114
+ }, never, never, never, void, {}, {}>;
115
+ //#endregion
116
+ //#region src/state/range.d.ts
117
+ /**
118
+ * A numeric range as an array: `range(1, 4)` is `[1, 2, 3]`, inclusive of
119
+ * the start and exclusive of the end, like `Array.from` length math. The
120
+ * pagination companion: `range(1, (pageCount(model) ?? 0) + 1)` is the page
121
+ * list. A zero or non-finite step would loop forever, so it throws, naming
122
+ * the caller — like History's capacity check.
123
+ */
124
+ export declare const range: (start: number, end: number, step?: number) => ReadonlyArray<number>;
125
+ //#endregion
126
+ //#region src/state/selection.d.ts
127
+ export declare const SelectionSetModel: Schema.Struct<{
128
+ readonly selected: Schema.$Array<Schema.String>;
129
+ }>;
130
+ export type SelectionSetModel = typeof SelectionSetModel.Type;
131
+ export declare const SelectionSetMessage: import("foldkit/message").MessageUnion<{
132
+ readonly Select: {
133
+ readonly id: Schema.String;
134
+ };
135
+ readonly Deselect: {
136
+ readonly id: Schema.String;
137
+ };
138
+ readonly Toggle: {
139
+ readonly id: Schema.String;
140
+ };
141
+ readonly ReplaceAll: {
142
+ readonly ids: Schema.$Array<Schema.String>;
143
+ };
144
+ readonly Clear: {};
145
+ }>;
146
+ export type SelectionSetMessage = typeof SelectionSetMessage.Type;
147
+ /** Whether the id is currently selected. */
148
+ export declare const isSelected: (model: SelectionSetModel, id: string) => boolean;
149
+ export declare const SelectionSet: Bundle.Bundle<"SelectionSet", void, {
150
+ readonly selected: readonly string[];
151
+ }, {
152
+ readonly _tag: "Clear";
153
+ } | {
154
+ readonly _tag: "Select";
155
+ readonly id: string;
156
+ } | {
157
+ readonly _tag: "Deselect";
158
+ readonly id: string;
159
+ } | {
160
+ readonly _tag: "Toggle";
161
+ readonly id: string;
162
+ } | {
163
+ readonly _tag: "ReplaceAll";
164
+ readonly ids: readonly string[];
165
+ }, never, never, never, void, {}, {}>;
166
+ //#endregion
167
+ //#region src/state/virtual.d.ts
168
+ export interface VirtualWindow {
169
+ /** First visible row index, inclusive. */
170
+ readonly start: number;
171
+ /** End row index, exclusive. */
172
+ readonly end: number;
173
+ }
174
+ /** Layout constants: per-row estimate, inter-row gap, and end padding. */
175
+ export interface VirtualLayout {
176
+ readonly estimatedHeight: number;
177
+ readonly gap: number;
178
+ readonly paddingStart: number;
179
+ readonly paddingEnd: number;
180
+ }
181
+ /** Total scrollable height: padding, measured rows, estimates, and gaps. */
182
+ export declare const totalHeight: (keys: ReadonlyArray<string>, heights: Readonly<Record<string, number>>, layout: VirtualLayout) => number;
183
+ /** Pixel offset of a row's top edge: padding plus the prefix before it. */
184
+ export declare const offsetFor: (index: number, keys: ReadonlyArray<string>, heights: Readonly<Record<string, number>>, layout: VirtualLayout) => number;
185
+ /**
186
+ * Which rows to render for a scroll position: the rows intersecting
187
+ * `[scrollTop, scrollTop + viewportHeight)`, widened by `overscan` on both
188
+ * sides and clamped to `[0, count]`. Gaps and padding are dead space — no
189
+ * row — so boxes are tested, not cumulative coverage. An overscan of zero
190
+ * renders exactly the visible rows.
191
+ */
192
+ export declare const visibleRange: (keys: ReadonlyArray<string>, heights: Readonly<Record<string, number>>, layout: VirtualLayout, scrollTop: number, viewportHeight: number, overscan: number) => VirtualWindow;
193
+ export declare const VirtualModel: Schema.Struct<{
194
+ readonly scrollTop: Schema.Number;
195
+ readonly heights: Schema.$Record<Schema.String, Schema.Number>;
196
+ readonly scrolling: Schema.Boolean;
197
+ readonly generation: Schema.Number;
198
+ readonly estimatedHeight: Schema.Number;
199
+ readonly overscan: Schema.Number;
200
+ readonly gap: Schema.Number;
201
+ readonly paddingStart: Schema.Number;
202
+ readonly paddingEnd: Schema.Number;
203
+ }>;
204
+ export type VirtualModel = typeof VirtualModel.Type;
205
+ export declare const VirtualMessage: import("foldkit/message").MessageUnion<{
206
+ readonly Scrolled: {
207
+ readonly top: Schema.Number;
208
+ };
209
+ readonly Measured: {
210
+ readonly key: Schema.String;
211
+ readonly height: Schema.Number;
212
+ };
213
+ /** Drops heights for keys no longer listed: the bundle never sees the key
214
+ order, so the application tells it what left. */
215
+ readonly Prune: {
216
+ readonly keys: Schema.$Array<Schema.String>;
217
+ };
218
+ /** Fires when scrolling has been silent for `settleMs`: only the latest
219
+ generation counts, so a fling's intermediate timers emit nothing. */
220
+ readonly Settled: {
221
+ readonly generation: Schema.Number;
222
+ };
223
+ }>;
224
+ export type VirtualMessage = typeof VirtualMessage.Type;
225
+ /**
226
+ * The rows to render plus the spacer height, from the Model, the key order,
227
+ * and the viewport height. Layout and overscan come from the Model, so the
228
+ * call cannot disagree with the placement. Keys stay the application's:
229
+ * render each row keyed, and per-row placements keep identity.
230
+ */
231
+ export declare const windowFor: (model: VirtualModel, keys: ReadonlyArray<string>, viewportHeight: number) => VirtualWindow & {
232
+ readonly totalHeight: number;
233
+ };
234
+ /**
235
+ * Whether the viewport rests at (or past) the end, within `threshold`
236
+ * pixels: the infinite-scroll check. An empty list counts as ended — there
237
+ * is nothing to scroll, so more should load. Thresholds below zero clamp
238
+ * to zero.
239
+ */
240
+ export declare const isAtEnd: (model: VirtualModel, keys: ReadonlyArray<string>, viewportHeight: number, threshold?: number) => boolean;
241
+ export declare const Virtual: Bundle.Bundle<"Virtual", {
242
+ readonly estimatedHeight: number;
243
+ readonly overscan: number;
244
+ readonly gap: number;
245
+ readonly paddingStart: number;
246
+ readonly paddingEnd: number;
247
+ readonly settleMs?: number | undefined;
248
+ readonly initialScrollTop?: number | undefined;
249
+ readonly initialHeights?: Readonly<Record<string, number>> | undefined;
250
+ }, {
251
+ readonly scrollTop: number;
252
+ readonly heights: {
253
+ readonly [x: string]: number;
254
+ };
255
+ readonly scrolling: boolean;
256
+ readonly generation: number;
257
+ readonly estimatedHeight: number;
258
+ readonly overscan: number;
259
+ readonly gap: number;
260
+ readonly paddingStart: number;
261
+ readonly paddingEnd: number;
262
+ }, {
263
+ readonly _tag: "Measured";
264
+ readonly key: string;
265
+ readonly height: number;
266
+ } | {
267
+ readonly _tag: "Settled";
268
+ readonly generation: number;
269
+ } | {
270
+ readonly _tag: "Scrolled";
271
+ readonly top: number;
272
+ } | {
273
+ readonly _tag: "Prune";
274
+ readonly keys: readonly string[];
275
+ }, never, never, never, void, {}, {}>;
276
+ export declare const ViewportScrolled: Schema.TaggedStruct<"ViewportScrolled", {
277
+ readonly top: Schema.Number;
278
+ }>;
279
+ export type ViewportScrolled = typeof ViewportScrolled.Type;
280
+ /**
281
+ * The scroll container's position, reported on its own scrolls starting
282
+ * with the current one. Attach to the scrolling element — viewport scrolls
283
+ * arrive through the window-level scroll entry instead.
284
+ */
285
+ export declare const Viewport: Mount.MountDefinitionNoArgs<"Viewport", {
286
+ readonly _tag: "ViewportScrolled";
287
+ readonly top: number;
288
+ }>;
289
+ export declare const RowMeasured: Schema.TaggedStruct<"RowMeasured", {
290
+ readonly key: Schema.String;
291
+ readonly height: Schema.Number;
292
+ }>;
293
+ export type RowMeasured = typeof RowMeasured.Type;
294
+ /**
295
+ * One row's height, reported on every resize starting with the current
296
+ * one. The key is the application's row identity, echoed back so the
297
+ * parent files the height without tracking which Mount sent what.
298
+ */
299
+ export declare const MeasureRow: Mount.MountDefinitionWithArgs<"MeasureRow", {
300
+ key: Schema.String;
301
+ }, {
302
+ readonly _tag: "RowMeasured";
303
+ readonly key: string;
304
+ readonly height: number;
305
+ }>;
306
+ /**
307
+ * Which section header sticks for a window: the last section starting at
308
+ * or before the first rendered row, or null above the first section. Order
309
+ * independent — the scan takes the maximum, so unsorted input still
310
+ * answers. CSS `position: sticky` does the sticking; this answers *what*
311
+ * sticks, for styling and callbacks.
312
+ */
313
+ export declare const stickyHeader: (sections: ReadonlyArray<{
314
+ readonly key: string;
315
+ readonly index: number;
316
+ }>, startIndex: number) => string | null;
317
+ export interface MasonryPlacement {
318
+ readonly key: string;
319
+ readonly column: number;
320
+ readonly x: number;
321
+ readonly y: number;
322
+ readonly width: number;
323
+ readonly height: number;
324
+ }
325
+ /**
326
+ * Masonry layout as a pure function: fixed column count and width, each
327
+ * item packed into the currently shortest column. Unmeasured items use the
328
+ * estimate; poisoned heights fall back the same way. This is layout only,
329
+ * not windowing — every placed item renders, so it fits hundreds of images,
330
+ * not hundred-thousands. Needing a windowed grid is a different algorithm.
331
+ */
332
+ export declare const masonry: (keys: ReadonlyArray<string>, heights: Readonly<Record<string, number>>, options: {
333
+ readonly columns: number;
334
+ readonly columnWidth: number;
335
+ readonly gap: number;
336
+ readonly estimatedHeight: number;
337
+ }) => {
338
+ readonly placements: ReadonlyArray<MasonryPlacement>;
339
+ readonly totalHeight: number;
340
+ };
341
+ //#endregion
342
+ //# sourceMappingURL=index.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../../src/state/history.ts","../../src/state/locale.ts","../../src/state/pagination.ts","../../src/state/range.ts","../../src/state/selection.ts","../../src/state/virtual.ts"],"mappings":";;;;qBASa,eAAgB,OAAK,OAAS,OAAO,MAAM,oBAAe,OAAA;;;;;YAM3D,aAAa;WACd,MAAM,cAAc;WACpB,SAAS;WACT,QAAQ,cAAc;;qBAGpB,gBAAiB,qBAAqB,OAAK;WAC7C,MAAM;WACN,OAAO,OAAO,MAAM;WACpB;MACV,OAAA,OAAA;;;;;;;;;;;;;;;;;;;;;;;;;;qBA+DY,UAAW,OAAK,OAAS,aAAa;;qBAGtC,UAAW,OAAK,OAAS,aAAa;;;qBCjFtC,aAAW,OAAA;;;YACZ,qBAAqB,YAAY;qBAEhC,yCAAa;;qBAAb,OAAA;;;YACD,uBAAuB,cAAc;qBAEpC,QAAM,OAAA;;;;;;;;;;qBCPN,iBAAe,OAAA;;;;;YAKhB,yBAAyB,gBAAgB;qBAExC,6CAAiB;;;;;;;;;;;;;YAOlB,2BAA2B,kBAAkB;;qBAU5C,YAAS,OAAW;;qBAIpB,SAAM,OAAW;qBAEjB,YAAU,OAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBChCV,QAAK,eAAiB,aAAa,kBAAa;;;qBCEhD,mBAAiB,OAAA;;;YAClB,2BAA2B,kBAAkB;qBAE5C,+CAAmB;;;;;;;;;;;;;;;YAOpB,6BAA6B,oBAAoB;;qBAMhD,aAAU,OAAW,mBAAiB;qBAGtC,cAAY,OAAA;;;;;;;;;;;;;;;;;;;iBCRR;;WAEN;;WAEA;;;iBAIM;WACN;WACA;WACA;WACA;;;qBAkBE,cAAW,MAChB,uBAAqB,SAClB,SAAS,yBAAuB,QACjC;;qBAWG,YAAS,eACP,MACP,uBAAqB,SAClB,SAAS,yBAAuB,QACjC;;;;;;;;qBAiBG,eAAY,MACjB,uBAAqB,SAClB,SAAS,yBAAuB,QACjC,eAAa,mBACJ,wBACK,qBAErB;qBA4BU,cAAY,OAAA;;;;;;;;;;;YAWb,sBAAsB,aAAa;qBAElC,0CAAc;;;;;;;;;;;;;;;;;;;YAUf,wBAAwB,eAAe;;;;;;;qBAetC,YAAS,OACb,cAAY,MACb,uBAAqB,2BAE1B;WAA2B;;;;;;;;qBAmBjB,UAAO,OACX,cAAY,MACb,uBAAqB,wBACL;qBAaX,SAAO,OAAA;WAKU;WACP;WACL;WACS;WACF;WACD;WACQ;WACF,iBAAA,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;qBAmG1B,kBAAgB,OAAA;;;YACjB,0BAA0B,iBAAiB;;;;;;qBAO1C,UAAQ,MAAA;;;;qBAeR,aAAW,OAAA;;;;YAIZ,qBAAqB,YAAY;;;;;;qBAShC,YAAU,MAAA;;;;;;;;;;;;;;qBAgCV,eAAY,UACb;WAAyB;WAAsB;IAAgB;iBAc1D;WACN;WACA;WACA;WACA;WACA;WACA;;;;;;;;;qBAUE,UAAO,MACZ,uBAAqB,SAClB,SAAS,yBAAuB;WAE9B;WACA;WACA;WACA;;WAEC,YAAY,cAAc;WAA4B"}