@typed/ui 0.2.0 → 0.3.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 (39) hide show
  1. package/dist/cjs/Anchor.js +39 -48
  2. package/dist/cjs/Anchor.js.map +1 -1
  3. package/dist/cjs/Link.js +27 -17
  4. package/dist/cjs/Link.js.map +1 -1
  5. package/dist/cjs/internal/addEventListener.js +1 -1
  6. package/dist/cjs/internal/addEventListener.js.map +1 -1
  7. package/dist/cjs/useClickAway.js +6 -6
  8. package/dist/cjs/useClickAway.js.map +1 -1
  9. package/dist/cjs/usePagination.js +13 -14
  10. package/dist/cjs/usePagination.js.map +1 -1
  11. package/dist/dts/Anchor.d.ts +8 -7
  12. package/dist/dts/Anchor.d.ts.map +1 -1
  13. package/dist/dts/Link.d.ts +2 -2
  14. package/dist/dts/Link.d.ts.map +1 -1
  15. package/dist/dts/internal/addEventListener.d.ts +2 -1
  16. package/dist/dts/internal/addEventListener.d.ts.map +1 -1
  17. package/dist/dts/internal/dom-properties.d.ts +36 -36
  18. package/dist/dts/internal/dom-properties.d.ts.map +1 -1
  19. package/dist/dts/useClickAway.d.ts +2 -3
  20. package/dist/dts/useClickAway.d.ts.map +1 -1
  21. package/dist/dts/usePagination.d.ts +9 -9
  22. package/dist/dts/usePagination.d.ts.map +1 -1
  23. package/dist/esm/Anchor.js +21 -45
  24. package/dist/esm/Anchor.js.map +1 -1
  25. package/dist/esm/Link.js +12 -11
  26. package/dist/esm/Link.js.map +1 -1
  27. package/dist/esm/internal/addEventListener.js +1 -1
  28. package/dist/esm/internal/addEventListener.js.map +1 -1
  29. package/dist/esm/useClickAway.js +4 -4
  30. package/dist/esm/useClickAway.js.map +1 -1
  31. package/dist/esm/usePagination.js +10 -11
  32. package/dist/esm/usePagination.js.map +1 -1
  33. package/package.json +12 -12
  34. package/src/Anchor.ts +46 -54
  35. package/src/Link.ts +27 -18
  36. package/src/internal/addEventListener.ts +11 -8
  37. package/src/internal/dom-properties.ts +36 -36
  38. package/src/useClickAway.ts +22 -20
  39. package/src/usePagination.ts +39 -36
package/src/Anchor.ts CHANGED
@@ -9,11 +9,11 @@ import type { DefaultEventMap, ElementSource } from "@typed/template/ElementSour
9
9
  import * as EventHandler from "@typed/template/EventHandler"
10
10
  import type { Placeholder } from "@typed/template/Placeholder"
11
11
  import type { Renderable } from "@typed/template/Renderable"
12
- import type { TemplateFx } from "@typed/template/RenderTemplate"
13
- import { html } from "@typed/template/RenderTemplate"
12
+ import type { RenderEvent } from "@typed/template/RenderEvent"
13
+ import { html, type RenderTemplate } from "@typed/template/RenderTemplate"
14
14
  import type { Rendered } from "@typed/wire"
15
15
  import type { ReadonlyRecord, Scope } from "effect"
16
- import { Effect } from "effect"
16
+ import * as Effect from "effect/Effect"
17
17
  import { uncapitalize } from "effect/String"
18
18
  import type { HTMLAnchorElementProperties } from "./internal/dom-properties.js"
19
19
 
@@ -22,14 +22,14 @@ import type { HTMLAnchorElementProperties } from "./internal/dom-properties.js"
22
22
  */
23
23
  export type AnchorProps =
24
24
  & {
25
- readonly [K in keyof HTMLAnchorElementProperties]:
25
+ readonly [K in keyof HTMLAnchorElementProperties]?:
26
26
  | HTMLAnchorElementProperties[K]
27
27
  | Placeholder.Any<HTMLAnchorElementProperties[K]>
28
- | Directive.Directive<any, any>
28
+ | undefined
29
29
  }
30
30
  & {
31
- readonly ref?: (ref: ElementSource<HTMLAnchorElement>) => Effect.Effect<any, any, any>
32
- readonly data?: Placeholder.Any<ReadonlyRecord.ReadonlyRecord<any>>
31
+ readonly ref?: ((ref: ElementSource<HTMLAnchorElement>) => Effect.Effect<any, any, any>) | undefined
32
+ readonly data?: Placeholder.Any<ReadonlyRecord.ReadonlyRecord<any>> | undefined
33
33
  }
34
34
  & EventHandlerProps<HTMLAnchorElement>
35
35
 
@@ -58,60 +58,52 @@ export function Anchor<
58
58
  >(
59
59
  props: Props,
60
60
  ...children: Children
61
- ): TemplateFx<
62
- Placeholder.Context<Props[keyof Props] | ReturnOf<Props["ref"]> | Children[number]>,
61
+ ): Fx.Fx<
62
+ RenderTemplate | Scope.Scope | Placeholder.Context<Props[keyof Props] | ReturnOf<Props["ref"]> | Children[number]>,
63
63
  Placeholder.Error<Props[keyof Props] | ReturnOf<Props["ref"]> | Children[number]>,
64
- HTMLAnchorElement
64
+ RenderEvent
65
65
  > {
66
- const ref = Directive.ref(({ value: ref }) =>
66
+ const {
67
+ data,
68
+ hash,
69
+ host,
70
+ hostname,
71
+ href,
72
+ hreflang,
73
+ pathname,
74
+ port,
75
+ protocol,
76
+ ref,
77
+ scrollLeft,
78
+ scrollTop,
79
+ search,
80
+ ...rest
81
+ } = props
82
+
83
+ const refDirective = Directive.ref(({ value }) =>
67
84
  Effect.gen(function*(_) {
68
- yield* _(addEventListeners(props, ref))
85
+ yield* _(addEventListeners(props, value))
69
86
 
70
- if (props.ref) {
71
- yield* _(props.ref(ref as any))
87
+ if (ref) {
88
+ yield* _(ref(value as any))
72
89
  }
73
90
  })
74
91
  )
75
92
  return html`<a
76
- ref="${ref}"
77
- .data="${props.data}"
78
- ?hidden="${props.hidden}"
79
- ?hidefocus="${props.hideFocus}"
80
- ?spellcheck="${props.spellcheck}"
81
- .scrollLeft="${props.scrollLeft}"
82
- .scrollTop="${props.scrollTop}"
83
- accesskey="${props.accessKey}"
84
- charset="${props.charset}"
85
- class="${props.className}"
86
- contenteditable="${props.contentEditable}"
87
- coords="${props.coords}"
88
- dir="${props.dir}"
89
- download="${props.download}"
90
- draggable="${props.draggable}"
91
- .hash="${props.hash}"
92
- .host="${props.host}"
93
- .hostname="${props.hostname}"
94
- .href="${props.href}"
95
- hreflang="${props.hreflang}"
96
- id="${props.id}"
97
- id="${props.id}"
98
- lang="${props.lang}"
99
- Methods="${props.Methods}"
100
- name="${props.name}"
101
- .pathname="${props.pathname}"
102
- .port="${props.port}"
103
- .protocol="${props.protocol}"
104
- rel="${props.rel}"
105
- rev="${props.rev}"
106
- .search="${props.search}"
107
- shape="${props.shape}"
108
- slot="${props.slot}"
109
- tabindex="${props.tabIndex}"
110
- target="${props.target}"
111
- text="${props.text}"
112
- title="${props.title}"
113
- type="${props.type}"
114
- urn="${props.urn}"
93
+ ref="${refDirective}"
94
+ .props="${rest}"
95
+ .data="${data}"
96
+ .scrollLeft="${scrollLeft}"
97
+ .scrollTop="${scrollTop}"
98
+ .hash="${hash}"
99
+ .host="${host}"
100
+ .hostname="${hostname}"
101
+ .href="${href}"
102
+ .hreflang="${hreflang}"
103
+ .pathname="${pathname}"
104
+ .port="${port}"
105
+ .protocol="${protocol}"
106
+ .search="${search}"
115
107
  >${children}</a>` as any
116
108
  }
117
109
 
@@ -123,7 +115,7 @@ export function addEventListeners<Props extends EventHandlerProps<any>, T extend
123
115
  ref: ElementSource<T>
124
116
  ): Effect.Effect<Scope.Scope | GetEventHandlersContext<Props>, never, void> {
125
117
  return Fx.forkScoped(
126
- Fx.merge(
118
+ Fx.mergeAll(
127
119
  getEventHandlers(props).map(([type, handler]: any) => addEventListener(ref, type, handler))
128
120
  )
129
121
  ) as any
package/src/Link.ts CHANGED
@@ -12,7 +12,8 @@ import { Placeholder } from "@typed/template/Placeholder"
12
12
  import type { Renderable } from "@typed/template/Renderable"
13
13
  import type { RenderEvent } from "@typed/template/RenderEvent"
14
14
  import type { RenderTemplate } from "@typed/template/RenderTemplate"
15
- import { Effect, type Scope } from "effect"
15
+ import * as Effect from "effect/Effect"
16
+ import type * as Scope from "effect/Scope"
16
17
  import { Anchor, type AnchorProps, getEventHandler } from "./Anchor.js"
17
18
 
18
19
  /**
@@ -30,36 +31,36 @@ export type LinkProps = Omit<AnchorProps, keyof URL> & {
30
31
  * @since 1.0.0
31
32
  */
32
33
  export function Link<Props extends LinkProps, Children extends ReadonlyArray<Renderable<any, any>> = readonly []>(
33
- props: Props,
34
+ { onClick, ref, relative, replace, state, to, ...props }: Props,
34
35
  ...children: Children
35
36
  ): Fx.Fx<
36
37
  | Navigation.Navigation
37
38
  | CurrentRoute
38
39
  | RenderTemplate
39
40
  | Scope.Scope
40
- | Location
41
- | Placeholder.Context<Props[keyof Props] | Children[number]>,
42
- Placeholder.Error<Props[keyof Props] | Children[number]>,
41
+ | Placeholder.Context<Props[keyof Props] | Children[number]>
42
+ | Fx.Context<Props[keyof Props] | Children[number]>,
43
+ Placeholder.Error<Props[keyof Props] | Children[number]> | Fx.Error<Props[keyof Props] | Children[number]>,
43
44
  RenderEvent
44
45
  > {
45
46
  return Fx.gen(function*(_) {
46
- const onClickHandler = getEventHandler(props.onClick)
47
- const to = yield* _(
48
- Placeholder.asRef<Placeholder.Context<Props["to"]>, Placeholder.Error<Props["to"]>, string>(props.to)
47
+ const onClickHandler = getEventHandler(onClick)
48
+ const toRef = yield* _(
49
+ Placeholder.asRef<Placeholder.Context<Props["to"]>, Placeholder.Error<Props["to"]>, string>(to)
49
50
  )
50
- const relative = yield* _(
51
+ const relativeRef = yield* _(
51
52
  Placeholder.asRef<Placeholder.Context<Props["relative"]>, Placeholder.Error<Props["relative"]>, boolean>(
52
- props.relative ?? true
53
+ relative ?? true
53
54
  )
54
55
  )
55
- const replace = yield* _(
56
+ const replaceRef = yield* _(
56
57
  Placeholder.asRef<Placeholder.Context<Props["replace"]>, Placeholder.Error<Props["replace"]>, boolean>(
57
- props.replace ?? false
58
+ replace ?? false
58
59
  )
59
60
  )
60
- const state = yield* _(
61
+ const stateRef = yield* _(
61
62
  Placeholder.asRef<Placeholder.Context<Props["state"]>, Placeholder.Error<Props["state"]>, unknown>(
62
- props.state as Placeholder.Any<unknown>
63
+ state as Placeholder.Any<unknown>
63
64
  )
64
65
  )
65
66
  const reloadDocument = yield* _(
@@ -72,10 +73,13 @@ export function Link<Props extends LinkProps, Children extends ReadonlyArray<Ren
72
73
  )
73
74
  )
74
75
 
75
- const href = RefSubject.tuple(relative, to).mapEffect(([rel, to]) => rel ? makeHref(to) : Effect.succeed(to))
76
+ const href = RefSubject.mapEffect(
77
+ RefSubject.tuple([relativeRef, toRef]),
78
+ ([rel, to]) => rel ? makeHref(to) : Effect.succeed(to)
79
+ )
76
80
 
77
81
  const navigate = Effect.gen(function*(_) {
78
- const current = yield* _(Effect.all({ replace, state, reloadDocument }))
82
+ const current = yield* _(Effect.all({ replace: replaceRef, state: stateRef, reloadDocument }))
79
83
  const url = yield* _(href)
80
84
 
81
85
  yield* _(Navigation.navigate(url, {
@@ -88,7 +92,7 @@ export function Link<Props extends LinkProps, Children extends ReadonlyArray<Ren
88
92
  }
89
93
  })
90
94
 
91
- const onClick = EventHandler.preventDefault(
95
+ const onClickEventHandler = EventHandler.preventDefault(
92
96
  (ev: EventWithCurrentTarget<HTMLAnchorElement, MouseEvent>) =>
93
97
  Effect.gen(function*(_) {
94
98
  if (onClickHandler) {
@@ -99,6 +103,11 @@ export function Link<Props extends LinkProps, Children extends ReadonlyArray<Ren
99
103
  onClickHandler?.options
100
104
  )
101
105
 
102
- return Anchor({ ...props, href, state, onClick }, ...children)
106
+ const allProps = { ...props, ref, href, state: stateRef, onClick: onClickEventHandler }
107
+
108
+ return Anchor(
109
+ allProps as any as AnchorProps,
110
+ ...children
111
+ )
103
112
  })
104
113
  }
@@ -1,19 +1,22 @@
1
1
  import type { EventWithCurrentTarget } from "@typed/dom/EventTarget"
2
2
  import * as Fx from "@typed/fx/Fx"
3
3
  import type { DefaultEventMap } from "@typed/template/ElementSource"
4
+ import type { Scope } from "effect"
4
5
  import * as Effect from "effect/Effect"
5
6
 
6
7
  export function addEventListeners<T extends EventTarget, Events extends ReadonlyArray<keyof DefaultEventMap<T>>>(
7
8
  target: T,
8
9
  ...events: Events
9
10
  ) {
10
- return Fx.fromEmitter<never, never, EventWithCurrentTarget<T, DefaultEventMap<T>[Events[number]]>>((emitter) => {
11
- events.forEach((event) => target.addEventListener(event as string, emitter.succeed as any))
11
+ return Fx.withEmitter<never, EventWithCurrentTarget<T, DefaultEventMap<T>[Events[number]]>, Scope.Scope>(
12
+ (emitter) => {
13
+ events.forEach((event) => target.addEventListener(event as string, emitter.succeed as any))
12
14
 
13
- return Effect.addFinalizer(() =>
14
- Effect.sync(() => {
15
- events.forEach((event) => target.addEventListener(event as string, emitter.succeed as any))
16
- })
17
- )
18
- })
15
+ return Effect.addFinalizer(() =>
16
+ Effect.sync(() => {
17
+ events.forEach((event) => target.addEventListener(event as string, emitter.succeed as any))
18
+ })
19
+ )
20
+ }
21
+ )
19
22
  }
@@ -1,50 +1,50 @@
1
1
  export type ElementProperties = {
2
- className?: string
3
- id?: string
4
- scrollLeft?: number
5
- scrollTop?: number
6
- slot?: string
2
+ className?: string | undefined
3
+ id?: string | undefined
4
+ scrollLeft?: number | undefined
5
+ scrollTop?: number | undefined
6
+ slot?: string | undefined
7
7
  }
8
8
 
9
9
  export type HTMLElementProperties =
10
10
  & ElementProperties
11
11
  & {
12
- accessKey?: string
13
- contentEditable?: string
14
- dir?: string
15
- draggable?: boolean
16
- hidden?: boolean
17
- hideFocus?: boolean
18
- lang?: string
19
- spellcheck?: boolean
20
- tabIndex?: boolean
21
- title?: string
12
+ accessKey?: string | undefined
13
+ contentEditable?: string | undefined
14
+ dir?: string | undefined
15
+ draggable?: boolean | undefined
16
+ hidden?: boolean | undefined
17
+ hideFocus?: boolean | undefined
18
+ lang?: string | undefined
19
+ spellcheck?: boolean | undefined
20
+ tabIndex?: boolean | undefined
21
+ title?: string | undefined
22
22
  }
23
23
 
24
24
  export type HTMLAnchorElementProperties =
25
25
  & HTMLElementProperties
26
26
  & {
27
- Methods?: string
28
- charset?: string
29
- coords?: string
30
- download?: string
31
- hash?: string
32
- host?: string
33
- hostname?: string
34
- href?: string
35
- hreflang?: string
36
- name?: string
37
- pathname?: string
38
- port?: string
39
- protocol?: string
40
- rel?: string
41
- rev?: string
42
- search?: string
43
- shape?: string
44
- target?: string
45
- text?: string
46
- type?: string
47
- urn?: string
27
+ Methods?: string | undefined
28
+ charset?: string | undefined
29
+ coords?: string | undefined
30
+ download?: string | undefined
31
+ hash?: string | undefined
32
+ host?: string | undefined
33
+ hostname?: string | undefined
34
+ href?: string | undefined
35
+ hreflang?: string | undefined
36
+ name?: string | undefined
37
+ pathname?: string | undefined
38
+ port?: string | undefined
39
+ protocol?: string | undefined
40
+ rel?: string | undefined
41
+ rev?: string | undefined
42
+ search?: string | undefined
43
+ shape?: string | undefined
44
+ target?: string | undefined
45
+ text?: string | undefined
46
+ type?: string | undefined
47
+ urn?: string | undefined
48
48
  }
49
49
 
50
50
  export type HTMLAppletElementProperties =
@@ -8,8 +8,8 @@ import * as Fx from "@typed/fx/Fx"
8
8
  import type * as ElementRef from "@typed/template/ElementRef"
9
9
  import { getElements } from "@typed/template/ElementSource"
10
10
  import type { Rendered } from "@typed/wire"
11
- import type { Fiber, Scope } from "effect"
12
- import { Effect, Option } from "effect"
11
+ import type { Effect, Fiber, Scope } from "effect"
12
+ import * as Option from "effect/Option"
13
13
  import { addEventListeners } from "./internal/addEventListener"
14
14
 
15
15
  /**
@@ -28,11 +28,11 @@ export function useClickAway<Refs extends ReadonlyArray<ElementRef.ElementRef<an
28
28
  export function onClickAway<Refs extends ReadonlyArray<ElementRef.ElementRef<any>>, R2, E2, B>(
29
29
  refs: Refs,
30
30
  f: (event: EventWithCurrentTarget<Document, MouseEvent | TouchEvent>) => Effect.Effect<R2, E2, B>
31
- ): Fx.Fx<Document | R2, E2, B> {
31
+ ): Fx.Fx<Document | R2 | Scope.Scope, E2, B> {
32
32
  return Fx.fromFxEffect(Document.with((document) => {
33
33
  const events = addEventListeners(document, "click", "touchend", "contextmenu")
34
34
  const elements = Fx.map(
35
- Fx.combine(refs as ReadonlyArray<Fx.Fx<never, never, Rendered>>),
35
+ Fx.tuple(refs as ReadonlyArray<Fx.Fx<Scope.Scope, never, Rendered>>),
36
36
  (els) => els.flatMap(getElements)
37
37
  )
38
38
 
@@ -43,20 +43,22 @@ export function onClickAway<Refs extends ReadonlyArray<ElementRef.ElementRef<any
43
43
  }))
44
44
  }
45
45
 
46
- const containsRefs = (event: EventWithCurrentTarget<Document, MouseEvent | TouchEvent>, refs: ReadonlyArray<Element>) =>
47
- Effect.sync(() => {
48
- const target = event.target
46
+ const containsRefs = (
47
+ event: EventWithCurrentTarget<Document, MouseEvent | TouchEvent>,
48
+ refs: ReadonlyArray<Element>
49
+ ): Option.Option<EventWithCurrentTarget<Document, MouseEvent | TouchEvent>> => {
50
+ const target = event.target
49
51
 
50
- if (
51
- target === null ||
52
- refs.some(
53
- (c) =>
54
- c === target ||
55
- c.contains(target as Element)
56
- )
57
- ) {
58
- return Option.none()
59
- } else {
60
- return Option.some(event)
61
- }
62
- })
52
+ if (
53
+ target === null ||
54
+ refs.some(
55
+ (c) =>
56
+ c === target ||
57
+ c.contains(target as Element)
58
+ )
59
+ ) {
60
+ return Option.none()
61
+ } else {
62
+ return Option.some(event)
63
+ }
64
+ }
@@ -2,10 +2,9 @@
2
2
  * @since 1.0.0
3
3
  */
4
4
 
5
- import * as Computed from "@typed/fx/Computed"
6
5
  import * as RefSubject from "@typed/fx/RefSubject"
7
6
  import type { Scope } from "effect"
8
- import { Effect } from "effect"
7
+ import * as Effect from "effect/Effect"
9
8
 
10
9
  /**
11
10
  * @since 1.0.0
@@ -19,12 +18,12 @@ export type PaginationOptions = {
19
18
  * @since 1.0.0
20
19
  */
21
20
  export interface Pagination<E, A> {
22
- readonly page: Computed.Computed<never, never, number>
23
- readonly pageSize: Computed.Computed<never, never, number>
24
- readonly canGoBack: Computed.Computed<never, never, boolean>
25
- readonly canGoForward: Computed.Computed<never, E, boolean>
26
- readonly paginated: Computed.Computed<never, E, ReadonlyArray<A>>
27
- readonly viewing: Computed.Computed<never, E, Viewing>
21
+ readonly page: RefSubject.Computed<never, never, number>
22
+ readonly pageSize: RefSubject.Computed<never, never, number>
23
+ readonly canGoBack: RefSubject.Computed<never, never, boolean>
24
+ readonly canGoForward: RefSubject.Computed<never, E, boolean>
25
+ readonly paginated: RefSubject.Computed<never, E, ReadonlyArray<A>>
26
+ readonly viewing: RefSubject.Computed<never, E, Viewing>
28
27
 
29
28
  readonly goBack: Effect.Effect<never, never, number>
30
29
  readonly goForward: Effect.Effect<never, E, number>
@@ -45,19 +44,20 @@ export interface Viewing {
45
44
  * @since 1.0.0
46
45
  */
47
46
  export function usePagination<R, E, A>(
48
- items: Computed.Computed<R, E, ReadonlyArray<A>>,
47
+ items: RefSubject.Computed<R, E, ReadonlyArray<A>>,
49
48
  options: PaginationOptions = {}
50
49
  ): Effect.Effect<R | Scope.Scope, never, Pagination<E, A>> {
51
50
  return Effect.gen(function*(_) {
52
51
  const ctx = yield* _(Effect.context<R>())
53
52
  const page: RefSubject.RefSubject<never, never, number> = yield* _(RefSubject.of(options.initialPage ?? 0))
54
53
  const pageSize: RefSubject.RefSubject<never, never, number> = yield* _(RefSubject.of(options.initialPageSize ?? 10))
55
- const canGoBack: Computed.Computed<never, never, boolean> = page.map((x) => x > 0)
56
- const combined: Computed.Computed<never, E, readonly [number, number, ReadonlyArray<A>]> = Computed.provide(
57
- Computed.combine([page, pageSize, items] as const),
54
+ const canGoBack: RefSubject.Computed<never, never, boolean> = RefSubject.map(page, (x) => x > 0)
55
+ const combined: RefSubject.Computed<never, E, readonly [number, number, ReadonlyArray<A>]> = RefSubject.provide(
56
+ RefSubject.tuple([page, pageSize, items] as const),
58
57
  ctx
59
58
  )
60
- const canGoForward: Computed.Computed<never, E, boolean> = combined.map(
59
+ const canGoForward: RefSubject.Computed<never, E, boolean> = RefSubject.map(
60
+ combined,
61
61
  ([page, pageSize, results]) => page < Math.ceil(results.length / pageSize - 1)
62
62
  )
63
63
 
@@ -70,39 +70,42 @@ export function usePagination<R, E, A>(
70
70
  }),
71
71
  ctx
72
72
  )
73
- const goBack: Effect.Effect<never, never, number> = page.update((x) => Math.max(x - 1, 0))
74
- const goForward: Effect.Effect<never, E, number> = page.updateEffect((currentPage) =>
75
- Effect.gen(function*($) {
76
- const totalPages = yield* $(getTotalPages)
77
- const nextPage = Math.min(currentPage + 1, totalPages)
73
+ const goBack: Effect.Effect<never, never, number> = RefSubject.update(page, (x) => Math.max(x - 1, 0))
74
+ const goForward: Effect.Effect<never, E, number> = RefSubject.updateEffect(
75
+ page,
76
+ (currentPage) =>
77
+ Effect.gen(function*($) {
78
+ const totalPages = yield* $(getTotalPages)
79
+ const nextPage = Math.min(currentPage + 1, totalPages)
78
80
 
79
- return nextPage
80
- })
81
+ return nextPage
82
+ })
81
83
  )
82
- const goToStart: Effect.Effect<never, never, number> = page.set(0)
83
- const goToEnd: Effect.Effect<never, E, number> = page.updateEffect(() => getTotalPages)
84
-
85
- const paginated: Computed.Computed<never, E, ReadonlyArray<A>> = combined.map(([page, pageSize, results]) => {
86
- const start = page * pageSize
87
- const end = start + pageSize
88
-
89
- return results.slice(start, end)
90
- })
84
+ const goToStart: Effect.Effect<never, never, number> = RefSubject.set(page, 0)
85
+ const goToEnd: Effect.Effect<never, E, number> = RefSubject.updateEffect(page, () => getTotalPages)
91
86
 
92
- const viewing: Computed.Computed<never, E, Viewing> = combined.map(
87
+ const paginated: RefSubject.Computed<never, E, ReadonlyArray<A>> = RefSubject.map(
88
+ combined,
93
89
  ([page, pageSize, results]) => {
94
90
  const start = page * pageSize
95
91
  const end = start + pageSize
96
- const total = results.length
97
92
 
98
- return {
99
- from: start + 1,
100
- to: Math.min(end, total),
101
- total
102
- }
93
+ return results.slice(start, end)
103
94
  }
104
95
  )
105
96
 
97
+ const viewing: RefSubject.Computed<never, E, Viewing> = RefSubject.map(combined, ([page, pageSize, results]) => {
98
+ const start = page * pageSize
99
+ const end = start + pageSize
100
+ const total = results.length
101
+
102
+ return {
103
+ from: start + 1,
104
+ to: Math.min(end, total),
105
+ total
106
+ }
107
+ })
108
+
106
109
  return {
107
110
  page,
108
111
  pageSize,