@rocicorp/zero 0.26.0-canary.0 → 0.26.0-canary.3
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 +1 -1
- package/out/replicache/src/persist/collect-idb-databases.d.ts +4 -4
- package/out/replicache/src/persist/collect-idb-databases.d.ts.map +1 -1
- package/out/replicache/src/persist/collect-idb-databases.js +22 -19
- package/out/replicache/src/persist/collect-idb-databases.js.map +1 -1
- package/out/replicache/src/persist/refresh.d.ts.map +1 -1
- package/out/replicache/src/persist/refresh.js +0 -8
- package/out/replicache/src/persist/refresh.js.map +1 -1
- package/out/replicache/src/process-scheduler.d.ts +23 -0
- package/out/replicache/src/process-scheduler.d.ts.map +1 -1
- package/out/replicache/src/process-scheduler.js +50 -1
- package/out/replicache/src/process-scheduler.js.map +1 -1
- package/out/replicache/src/replicache-impl.d.ts +8 -0
- package/out/replicache/src/replicache-impl.d.ts.map +1 -1
- package/out/replicache/src/replicache-impl.js +11 -2
- package/out/replicache/src/replicache-impl.js.map +1 -1
- package/out/shared/src/custom-key-map.d.ts +4 -4
- package/out/shared/src/custom-key-map.d.ts.map +1 -1
- package/out/shared/src/custom-key-map.js.map +1 -1
- package/out/shared/src/falsy.d.ts +3 -0
- package/out/shared/src/falsy.d.ts.map +1 -0
- package/out/shared/src/iterables.d.ts +6 -8
- package/out/shared/src/iterables.d.ts.map +1 -1
- package/out/shared/src/iterables.js +13 -7
- package/out/shared/src/iterables.js.map +1 -1
- package/out/shared/src/options.d.ts +1 -0
- package/out/shared/src/options.d.ts.map +1 -1
- package/out/shared/src/options.js +5 -1
- package/out/shared/src/options.js.map +1 -1
- package/out/zero/package.json.js +1 -1
- package/out/zero/src/adapters/drizzle.js +1 -2
- package/out/zero/src/adapters/prisma.d.ts +2 -0
- package/out/zero/src/adapters/prisma.d.ts.map +1 -0
- package/out/zero/src/adapters/prisma.js +6 -0
- package/out/zero/src/adapters/prisma.js.map +1 -0
- package/out/zero/src/pg.js +4 -7
- package/out/zero/src/react.js +3 -1
- package/out/zero/src/react.js.map +1 -1
- package/out/zero/src/server.js +5 -8
- package/out/zero/src/zero-cache-dev.js +7 -3
- package/out/zero/src/zero-cache-dev.js.map +1 -1
- package/out/zero-cache/src/auth/load-permissions.d.ts +3 -2
- package/out/zero-cache/src/auth/load-permissions.d.ts.map +1 -1
- package/out/zero-cache/src/auth/load-permissions.js +14 -8
- package/out/zero-cache/src/auth/load-permissions.js.map +1 -1
- package/out/zero-cache/src/auth/write-authorizer.d.ts +6 -0
- package/out/zero-cache/src/auth/write-authorizer.d.ts.map +1 -1
- package/out/zero-cache/src/auth/write-authorizer.js +16 -3
- package/out/zero-cache/src/auth/write-authorizer.js.map +1 -1
- package/out/zero-cache/src/config/zero-config.d.ts +54 -9
- package/out/zero-cache/src/config/zero-config.d.ts.map +1 -1
- package/out/zero-cache/src/config/zero-config.js +80 -20
- package/out/zero-cache/src/config/zero-config.js.map +1 -1
- package/out/zero-cache/src/custom/fetch.d.ts +3 -0
- package/out/zero-cache/src/custom/fetch.d.ts.map +1 -1
- package/out/zero-cache/src/custom/fetch.js +26 -0
- package/out/zero-cache/src/custom/fetch.js.map +1 -1
- package/out/zero-cache/src/db/lite-tables.js +1 -1
- package/out/zero-cache/src/db/lite-tables.js.map +1 -1
- package/out/zero-cache/src/db/migration-lite.d.ts.map +1 -1
- package/out/zero-cache/src/db/migration-lite.js +9 -3
- package/out/zero-cache/src/db/migration-lite.js.map +1 -1
- package/out/zero-cache/src/db/migration.d.ts.map +1 -1
- package/out/zero-cache/src/db/migration.js +9 -3
- package/out/zero-cache/src/db/migration.js.map +1 -1
- package/out/zero-cache/src/db/specs.d.ts +4 -3
- package/out/zero-cache/src/db/specs.d.ts.map +1 -1
- package/out/zero-cache/src/db/specs.js +4 -1
- package/out/zero-cache/src/db/specs.js.map +1 -1
- package/out/zero-cache/src/db/transaction-pool.d.ts.map +1 -1
- package/out/zero-cache/src/db/transaction-pool.js +9 -3
- package/out/zero-cache/src/db/transaction-pool.js.map +1 -1
- package/out/zero-cache/src/observability/events.d.ts.map +1 -1
- package/out/zero-cache/src/observability/events.js +15 -5
- package/out/zero-cache/src/observability/events.js.map +1 -1
- package/out/zero-cache/src/server/change-streamer.d.ts.map +1 -1
- package/out/zero-cache/src/server/change-streamer.js +10 -2
- package/out/zero-cache/src/server/change-streamer.js.map +1 -1
- package/out/zero-cache/src/server/inspector-delegate.d.ts +1 -1
- package/out/zero-cache/src/server/inspector-delegate.d.ts.map +1 -1
- package/out/zero-cache/src/server/inspector-delegate.js +11 -30
- package/out/zero-cache/src/server/inspector-delegate.js.map +1 -1
- package/out/zero-cache/src/server/main.js +1 -1
- package/out/zero-cache/src/server/main.js.map +1 -1
- package/out/zero-cache/src/server/priority-op.d.ts +8 -0
- package/out/zero-cache/src/server/priority-op.d.ts.map +1 -0
- package/out/zero-cache/src/server/priority-op.js +29 -0
- package/out/zero-cache/src/server/priority-op.js.map +1 -0
- package/out/zero-cache/src/server/syncer.d.ts.map +1 -1
- package/out/zero-cache/src/server/syncer.js +10 -10
- package/out/zero-cache/src/server/syncer.js.map +1 -1
- package/out/zero-cache/src/services/analyze.js +1 -1
- package/out/zero-cache/src/services/analyze.js.map +1 -1
- package/out/zero-cache/src/services/change-source/custom/change-source.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/custom/change-source.js +4 -7
- package/out/zero-cache/src/services/change-source/custom/change-source.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/change-source.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/change-source.js +68 -13
- package/out/zero-cache/src/services/change-source/pg/change-source.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/initial-sync.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/initial-sync.js +7 -2
- package/out/zero-cache/src/services/change-source/pg/initial-sync.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/logical-replication/stream.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/logical-replication/stream.js +7 -4
- package/out/zero-cache/src/services/change-source/pg/logical-replication/stream.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/ddl.d.ts +125 -180
- package/out/zero-cache/src/services/change-source/pg/schema/ddl.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/ddl.js +1 -10
- package/out/zero-cache/src/services/change-source/pg/schema/ddl.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/init.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/init.js +26 -12
- package/out/zero-cache/src/services/change-source/pg/schema/init.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/published.d.ts +36 -90
- package/out/zero-cache/src/services/change-source/pg/schema/published.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/published.js +51 -14
- package/out/zero-cache/src/services/change-source/pg/schema/published.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/shard.d.ts +31 -36
- package/out/zero-cache/src/services/change-source/pg/schema/shard.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/shard.js +25 -17
- package/out/zero-cache/src/services/change-source/pg/schema/shard.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/validation.d.ts +2 -2
- package/out/zero-cache/src/services/change-source/pg/schema/validation.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/validation.js +2 -4
- package/out/zero-cache/src/services/change-source/pg/schema/validation.js.map +1 -1
- package/out/zero-cache/src/services/change-source/protocol/current/data.d.ts +158 -53
- package/out/zero-cache/src/services/change-source/protocol/current/data.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/protocol/current/data.js +55 -10
- package/out/zero-cache/src/services/change-source/protocol/current/data.js.map +1 -1
- package/out/zero-cache/src/services/change-source/protocol/current/downstream.d.ts +210 -72
- package/out/zero-cache/src/services/change-source/protocol/current/downstream.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/protocol/current.js +4 -2
- package/out/zero-cache/src/services/change-source/replica-schema.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/replica-schema.js +20 -4
- package/out/zero-cache/src/services/change-source/replica-schema.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/change-streamer-service.d.ts +1 -1
- package/out/zero-cache/src/services/change-streamer/change-streamer-service.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-streamer/change-streamer-service.js +6 -4
- package/out/zero-cache/src/services/change-streamer/change-streamer-service.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/change-streamer.d.ts +71 -25
- package/out/zero-cache/src/services/change-streamer/change-streamer.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-streamer/change-streamer.js +1 -1
- package/out/zero-cache/src/services/change-streamer/change-streamer.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/schema/tables.d.ts +1 -0
- package/out/zero-cache/src/services/change-streamer/schema/tables.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-streamer/schema/tables.js +6 -5
- package/out/zero-cache/src/services/change-streamer/schema/tables.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/storer.d.ts +1 -1
- package/out/zero-cache/src/services/change-streamer/storer.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-streamer/storer.js +17 -6
- package/out/zero-cache/src/services/change-streamer/storer.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/subscriber.d.ts +2 -0
- package/out/zero-cache/src/services/change-streamer/subscriber.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-streamer/subscriber.js +14 -1
- package/out/zero-cache/src/services/change-streamer/subscriber.js.map +1 -1
- package/out/zero-cache/src/services/heapz.d.ts.map +1 -1
- package/out/zero-cache/src/services/heapz.js +1 -0
- package/out/zero-cache/src/services/heapz.js.map +1 -1
- package/out/zero-cache/src/services/life-cycle.d.ts +1 -1
- package/out/zero-cache/src/services/life-cycle.d.ts.map +1 -1
- package/out/zero-cache/src/services/life-cycle.js.map +1 -1
- package/out/zero-cache/src/services/litestream/commands.d.ts.map +1 -1
- package/out/zero-cache/src/services/litestream/commands.js +3 -1
- package/out/zero-cache/src/services/litestream/commands.js.map +1 -1
- package/out/zero-cache/src/services/litestream/config.yml +1 -0
- package/out/zero-cache/src/services/mutagen/error.d.ts.map +1 -1
- package/out/zero-cache/src/services/mutagen/error.js +4 -1
- package/out/zero-cache/src/services/mutagen/error.js.map +1 -1
- package/out/zero-cache/src/services/mutagen/mutagen.d.ts +4 -4
- package/out/zero-cache/src/services/mutagen/mutagen.d.ts.map +1 -1
- package/out/zero-cache/src/services/mutagen/mutagen.js +10 -24
- package/out/zero-cache/src/services/mutagen/mutagen.js.map +1 -1
- package/out/zero-cache/src/services/mutagen/pusher.d.ts +8 -6
- package/out/zero-cache/src/services/mutagen/pusher.d.ts.map +1 -1
- package/out/zero-cache/src/services/mutagen/pusher.js +130 -19
- package/out/zero-cache/src/services/mutagen/pusher.js.map +1 -1
- package/out/zero-cache/src/services/replicator/change-processor.d.ts.map +1 -1
- package/out/zero-cache/src/services/replicator/change-processor.js +24 -31
- package/out/zero-cache/src/services/replicator/change-processor.js.map +1 -1
- package/out/zero-cache/src/services/replicator/schema/change-log.d.ts +4 -4
- package/out/zero-cache/src/services/replicator/schema/change-log.d.ts.map +1 -1
- package/out/zero-cache/src/services/replicator/schema/change-log.js +38 -36
- package/out/zero-cache/src/services/replicator/schema/change-log.js.map +1 -1
- package/out/zero-cache/src/services/{change-source → replicator/schema}/column-metadata.d.ts +3 -3
- package/out/zero-cache/src/services/replicator/schema/column-metadata.d.ts.map +1 -0
- package/out/zero-cache/src/services/{change-source → replicator/schema}/column-metadata.js +3 -3
- package/out/zero-cache/src/services/replicator/schema/column-metadata.js.map +1 -0
- package/out/zero-cache/src/services/replicator/schema/replication-state.d.ts.map +1 -1
- package/out/zero-cache/src/services/replicator/schema/replication-state.js +3 -1
- package/out/zero-cache/src/services/replicator/schema/replication-state.js.map +1 -1
- package/out/zero-cache/src/services/run-ast.js +1 -1
- package/out/zero-cache/src/services/run-ast.js.map +1 -1
- package/out/zero-cache/src/services/statz.d.ts.map +1 -1
- package/out/zero-cache/src/services/statz.js +1 -0
- package/out/zero-cache/src/services/statz.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/client-handler.d.ts +5 -6
- package/out/zero-cache/src/services/view-syncer/client-handler.d.ts.map +1 -1
- package/out/zero-cache/src/services/view-syncer/client-handler.js +5 -23
- package/out/zero-cache/src/services/view-syncer/client-handler.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/cvr-store.d.ts +1 -1
- package/out/zero-cache/src/services/view-syncer/cvr-store.d.ts.map +1 -1
- package/out/zero-cache/src/services/view-syncer/cvr-store.js +65 -44
- package/out/zero-cache/src/services/view-syncer/cvr-store.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/cvr.d.ts +0 -1
- package/out/zero-cache/src/services/view-syncer/cvr.d.ts.map +1 -1
- package/out/zero-cache/src/services/view-syncer/cvr.js +23 -6
- package/out/zero-cache/src/services/view-syncer/cvr.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/pipeline-driver.d.ts +14 -22
- package/out/zero-cache/src/services/view-syncer/pipeline-driver.d.ts.map +1 -1
- package/out/zero-cache/src/services/view-syncer/pipeline-driver.js +46 -67
- package/out/zero-cache/src/services/view-syncer/pipeline-driver.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/row-record-cache.d.ts +1 -1
- package/out/zero-cache/src/services/view-syncer/row-record-cache.d.ts.map +1 -1
- package/out/zero-cache/src/services/view-syncer/row-record-cache.js +22 -11
- package/out/zero-cache/src/services/view-syncer/row-record-cache.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/snapshotter.d.ts +0 -2
- package/out/zero-cache/src/services/view-syncer/snapshotter.d.ts.map +1 -1
- package/out/zero-cache/src/services/view-syncer/snapshotter.js +3 -11
- package/out/zero-cache/src/services/view-syncer/snapshotter.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/view-syncer.d.ts +6 -4
- package/out/zero-cache/src/services/view-syncer/view-syncer.d.ts.map +1 -1
- package/out/zero-cache/src/services/view-syncer/view-syncer.js +216 -243
- package/out/zero-cache/src/services/view-syncer/view-syncer.js.map +1 -1
- package/out/zero-cache/src/types/lexi-version.d.ts.map +1 -1
- package/out/zero-cache/src/types/lexi-version.js +4 -1
- package/out/zero-cache/src/types/lexi-version.js.map +1 -1
- package/out/zero-cache/src/types/lite.d.ts.map +1 -1
- package/out/zero-cache/src/types/lite.js +8 -2
- package/out/zero-cache/src/types/lite.js.map +1 -1
- package/out/zero-cache/src/types/shards.js +1 -1
- package/out/zero-cache/src/types/shards.js.map +1 -1
- package/out/zero-cache/src/types/sql.d.ts +5 -0
- package/out/zero-cache/src/types/sql.d.ts.map +1 -1
- package/out/zero-cache/src/types/sql.js +5 -1
- package/out/zero-cache/src/types/sql.js.map +1 -1
- package/out/zero-cache/src/types/subscription.js +1 -1
- package/out/zero-cache/src/types/subscription.js.map +1 -1
- package/out/zero-cache/src/workers/connect-params.d.ts +1 -1
- package/out/zero-cache/src/workers/connect-params.d.ts.map +1 -1
- package/out/zero-cache/src/workers/connect-params.js +2 -3
- package/out/zero-cache/src/workers/connect-params.js.map +1 -1
- package/out/zero-cache/src/workers/replicator.d.ts.map +1 -1
- package/out/zero-cache/src/workers/replicator.js +2 -5
- package/out/zero-cache/src/workers/replicator.js.map +1 -1
- package/out/zero-cache/src/workers/syncer-ws-message-handler.d.ts.map +1 -1
- package/out/zero-cache/src/workers/syncer-ws-message-handler.js +15 -10
- package/out/zero-cache/src/workers/syncer-ws-message-handler.js.map +1 -1
- package/out/zero-cache/src/workers/syncer.d.ts.map +1 -1
- package/out/zero-cache/src/workers/syncer.js +17 -10
- package/out/zero-cache/src/workers/syncer.js.map +1 -1
- package/out/zero-client/src/client/connection-manager.d.ts +8 -0
- package/out/zero-client/src/client/connection-manager.d.ts.map +1 -1
- package/out/zero-client/src/client/connection-manager.js +33 -0
- package/out/zero-client/src/client/connection-manager.js.map +1 -1
- package/out/zero-client/src/client/connection.d.ts.map +1 -1
- package/out/zero-client/src/client/connection.js +6 -3
- package/out/zero-client/src/client/connection.js.map +1 -1
- package/out/zero-client/src/client/context.js +1 -0
- package/out/zero-client/src/client/context.js.map +1 -1
- package/out/zero-client/src/client/error.js +1 -1
- package/out/zero-client/src/client/error.js.map +1 -1
- package/out/zero-client/src/client/mutator-proxy.d.ts.map +1 -1
- package/out/zero-client/src/client/mutator-proxy.js +15 -1
- package/out/zero-client/src/client/mutator-proxy.js.map +1 -1
- package/out/zero-client/src/client/options.d.ts +11 -1
- package/out/zero-client/src/client/options.d.ts.map +1 -1
- package/out/zero-client/src/client/options.js.map +1 -1
- package/out/zero-client/src/client/query-manager.d.ts +4 -0
- package/out/zero-client/src/client/query-manager.d.ts.map +1 -1
- package/out/zero-client/src/client/query-manager.js +7 -0
- package/out/zero-client/src/client/query-manager.js.map +1 -1
- package/out/zero-client/src/client/version.js +1 -1
- package/out/zero-client/src/client/zero.d.ts +5 -5
- package/out/zero-client/src/client/zero.d.ts.map +1 -1
- package/out/zero-client/src/client/zero.js +53 -8
- package/out/zero-client/src/client/zero.js.map +1 -1
- package/out/zero-client/src/mod.d.ts +1 -0
- package/out/zero-client/src/mod.d.ts.map +1 -1
- package/out/zero-protocol/src/connect.d.ts +4 -0
- package/out/zero-protocol/src/connect.d.ts.map +1 -1
- package/out/zero-protocol/src/connect.js +3 -1
- package/out/zero-protocol/src/connect.js.map +1 -1
- package/out/zero-protocol/src/protocol-version.d.ts +1 -1
- package/out/zero-protocol/src/protocol-version.d.ts.map +1 -1
- package/out/zero-protocol/src/protocol-version.js +1 -1
- package/out/zero-protocol/src/protocol-version.js.map +1 -1
- package/out/zero-protocol/src/push.d.ts +16 -0
- package/out/zero-protocol/src/push.d.ts.map +1 -1
- package/out/zero-protocol/src/push.js +25 -1
- package/out/zero-protocol/src/push.js.map +1 -1
- package/out/zero-protocol/src/up.d.ts +2 -0
- package/out/zero-protocol/src/up.d.ts.map +1 -1
- package/out/zero-react/src/mod.d.ts +3 -1
- package/out/zero-react/src/mod.d.ts.map +1 -1
- package/out/zero-react/src/paging-reducer.d.ts +61 -0
- package/out/zero-react/src/paging-reducer.d.ts.map +1 -0
- package/out/zero-react/src/paging-reducer.js +77 -0
- package/out/zero-react/src/paging-reducer.js.map +1 -0
- package/out/zero-react/src/use-query.d.ts +11 -1
- package/out/zero-react/src/use-query.d.ts.map +1 -1
- package/out/zero-react/src/use-query.js +13 -11
- package/out/zero-react/src/use-query.js.map +1 -1
- package/out/zero-react/src/use-rows.d.ts +39 -0
- package/out/zero-react/src/use-rows.d.ts.map +1 -0
- package/out/zero-react/src/use-rows.js +130 -0
- package/out/zero-react/src/use-rows.js.map +1 -0
- package/out/zero-react/src/use-zero-virtualizer.d.ts +122 -0
- package/out/zero-react/src/use-zero-virtualizer.d.ts.map +1 -0
- package/out/zero-react/src/use-zero-virtualizer.js +342 -0
- package/out/zero-react/src/use-zero-virtualizer.js.map +1 -0
- package/out/zero-react/src/zero-provider.js +1 -1
- package/out/zero-react/src/zero-provider.js.map +1 -1
- package/out/zero-server/src/adapters/drizzle.d.ts +18 -18
- package/out/zero-server/src/adapters/drizzle.d.ts.map +1 -1
- package/out/zero-server/src/adapters/drizzle.js +8 -22
- package/out/zero-server/src/adapters/drizzle.js.map +1 -1
- package/out/zero-server/src/adapters/pg.d.ts +19 -13
- package/out/zero-server/src/adapters/pg.d.ts.map +1 -1
- package/out/zero-server/src/adapters/pg.js.map +1 -1
- package/out/zero-server/src/adapters/postgresjs.d.ts +19 -13
- package/out/zero-server/src/adapters/postgresjs.d.ts.map +1 -1
- package/out/zero-server/src/adapters/postgresjs.js.map +1 -1
- package/out/zero-server/src/adapters/prisma.d.ts +66 -0
- package/out/zero-server/src/adapters/prisma.d.ts.map +1 -0
- package/out/zero-server/src/adapters/prisma.js +63 -0
- package/out/zero-server/src/adapters/prisma.js.map +1 -0
- package/out/zero-server/src/custom.js +1 -15
- package/out/zero-server/src/custom.js.map +1 -1
- package/out/zero-server/src/mod.d.ts +9 -8
- package/out/zero-server/src/mod.d.ts.map +1 -1
- package/out/zero-server/src/process-mutations.d.ts +2 -1
- package/out/zero-server/src/process-mutations.d.ts.map +1 -1
- package/out/zero-server/src/process-mutations.js +39 -4
- package/out/zero-server/src/process-mutations.js.map +1 -1
- package/out/zero-server/src/push-processor.js +1 -1
- package/out/zero-server/src/push-processor.js.map +1 -1
- package/out/zero-server/src/schema.d.ts.map +1 -1
- package/out/zero-server/src/schema.js +4 -1
- package/out/zero-server/src/schema.js.map +1 -1
- package/out/zero-server/src/zql-database.d.ts.map +1 -1
- package/out/zero-server/src/zql-database.js +18 -0
- package/out/zero-server/src/zql-database.js.map +1 -1
- package/out/zero-solid/src/mod.d.ts +1 -1
- package/out/zero-solid/src/mod.d.ts.map +1 -1
- package/out/zero-solid/src/solid-view.js +1 -0
- package/out/zero-solid/src/solid-view.js.map +1 -1
- package/out/zero-solid/src/use-query.d.ts +10 -1
- package/out/zero-solid/src/use-query.d.ts.map +1 -1
- package/out/zero-solid/src/use-query.js +22 -5
- package/out/zero-solid/src/use-query.js.map +1 -1
- package/out/zero-solid/src/use-zero.js +1 -1
- package/out/zero-solid/src/use-zero.js.map +1 -1
- package/out/zql/src/ivm/constraint.d.ts.map +1 -1
- package/out/zql/src/ivm/constraint.js +4 -1
- package/out/zql/src/ivm/constraint.js.map +1 -1
- package/out/zql/src/ivm/exists.d.ts.map +1 -1
- package/out/zql/src/ivm/exists.js +4 -1
- package/out/zql/src/ivm/exists.js.map +1 -1
- package/out/zql/src/ivm/join-utils.d.ts.map +1 -1
- package/out/zql/src/ivm/join-utils.js +8 -2
- package/out/zql/src/ivm/join-utils.js.map +1 -1
- package/out/zql/src/ivm/memory-source.d.ts.map +1 -1
- package/out/zql/src/ivm/memory-source.js +12 -3
- package/out/zql/src/ivm/memory-source.js.map +1 -1
- package/out/zql/src/ivm/push-accumulated.d.ts.map +1 -1
- package/out/zql/src/ivm/push-accumulated.js +25 -2
- package/out/zql/src/ivm/push-accumulated.js.map +1 -1
- package/out/zql/src/ivm/stream.d.ts.map +1 -1
- package/out/zql/src/ivm/stream.js +1 -1
- package/out/zql/src/ivm/stream.js.map +1 -1
- package/out/zql/src/ivm/take.d.ts.map +1 -1
- package/out/zql/src/ivm/take.js +24 -6
- package/out/zql/src/ivm/take.js.map +1 -1
- package/out/zql/src/ivm/union-fan-in.d.ts.map +1 -1
- package/out/zql/src/ivm/union-fan-in.js +12 -3
- package/out/zql/src/ivm/union-fan-in.js.map +1 -1
- package/out/zql/src/mutate/mutator.js +4 -4
- package/out/zql/src/mutate/mutator.js.map +1 -1
- package/out/zql/src/query/create-builder.js +3 -5
- package/out/zql/src/query/create-builder.js.map +1 -1
- package/out/zql/src/query/query-registry.js +4 -4
- package/out/zql/src/query/query-registry.js.map +1 -1
- package/out/zqlite/src/table-source.d.ts.map +1 -1
- package/out/zqlite/src/table-source.js +1 -2
- package/out/zqlite/src/table-source.js.map +1 -1
- package/package.json +8 -4
- package/out/zero-cache/src/services/change-source/column-metadata.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-source/column-metadata.js.map +0 -1
- package/out/zero-cache/src/types/schema-versions.d.ts +0 -12
- package/out/zero-cache/src/types/schema-versions.d.ts.map +0 -1
- package/out/zero-cache/src/types/schema-versions.js +0 -28
- package/out/zero-cache/src/types/schema-versions.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-query.js","sources":["../../../../zero-react/src/use-query.tsx"],"sourcesContent":["import {resolver} from '@rocicorp/resolver';\nimport React, {useSyncExternalStore} from 'react';\nimport {\n type Immutable,\n addContextToQuery,\n asQueryInternals,\n deepClone,\n DEFAULT_TTL_MS,\n} from './bindings.ts';\nimport {useZero} from './zero-provider.tsx';\nimport type {\n AnyMutatorRegistry,\n CustomMutatorDefs,\n DefaultContext,\n DefaultSchema,\n ErroredQuery,\n HumanReadable,\n PullRow,\n Query,\n QueryErrorDetails,\n QueryOrQueryRequest,\n QueryResultDetails,\n ReadonlyJSONValue,\n ResultType,\n Schema,\n TTL,\n TypedView,\n Zero,\n} from './zero.ts';\n\nexport type QueryResult<TReturn> = readonly [\n HumanReadable<TReturn>,\n QueryResultDetails & {},\n];\n\nexport type UseQueryOptions = {\n enabled?: boolean | undefined;\n /**\n * Time to live (TTL) in seconds. Controls how long query results are cached\n * after the query is removed. During this time, Zero continues to sync the query.\n * Default is 'never'.\n */\n ttl?: TTL | undefined;\n};\n\nexport type UseSuspenseQueryOptions = UseQueryOptions & {\n /**\n * Whether to suspend until:\n * - 'partial': the query has partial results (partial array or defined\n * value for singular results) which may be of result type 'unknown',\n * or the query result type is 'complete' (in which case results may be\n * empty). This is useful for suspending until there are partial\n * optimistic local results, or the query has completed loading from the\n * server.\n * - 'complete': the query result type is 'complete'.\n *\n * Default is 'partial'.\n */\n suspendUntil?: 'complete' | 'partial';\n};\n\nconst reactUse = (React as {use?: (p: Promise<unknown>) => void}).use;\nconst suspend: (p: Promise<unknown>) => void = reactUse\n ? reactUse\n : p => {\n throw p;\n };\n\nexport function useQuery<\n TTable extends keyof TSchema['tables'] & string,\n TInput extends ReadonlyJSONValue | undefined,\n TOutput extends ReadonlyJSONValue | undefined,\n TSchema extends Schema = DefaultSchema,\n TReturn = PullRow<TTable, TSchema>,\n TContext = DefaultContext,\n>(\n query: QueryOrQueryRequest<\n TTable,\n TInput,\n TOutput,\n TSchema,\n TReturn,\n TContext\n >,\n options?: UseQueryOptions | boolean,\n): QueryResult<TReturn> {\n let enabled = true;\n let ttl: TTL = DEFAULT_TTL_MS;\n if (typeof options === 'boolean') {\n enabled = options;\n } else if (options) {\n ({enabled = true, ttl = DEFAULT_TTL_MS} = options);\n }\n\n const zero = useZero<TSchema, undefined, TContext>();\n const q = addContextToQuery(query, zero.context);\n const view = viewStore.getView(zero, q, enabled, ttl);\n // https://react.dev/reference/react/useSyncExternalStore\n return useSyncExternalStore(\n view.subscribeReactInternals,\n view.getSnapshot,\n view.getSnapshot,\n );\n}\n\nexport function useSuspenseQuery<\n TTable extends keyof TSchema['tables'] & string,\n TInput extends ReadonlyJSONValue | undefined,\n TOutput extends ReadonlyJSONValue | undefined,\n TSchema extends Schema = DefaultSchema,\n TReturn = PullRow<TTable, TSchema>,\n TContext = DefaultContext,\n>(\n query: QueryOrQueryRequest<\n TTable,\n TInput,\n TOutput,\n TSchema,\n TReturn,\n TContext\n >,\n options?: UseSuspenseQueryOptions | boolean,\n): QueryResult<TReturn> {\n let enabled = true;\n let ttl: TTL = DEFAULT_TTL_MS;\n let suspendUntil: 'complete' | 'partial' = 'partial';\n if (typeof options === 'boolean') {\n enabled = options;\n } else if (options) {\n ({\n enabled = true,\n ttl = DEFAULT_TTL_MS,\n suspendUntil = 'complete',\n } = options);\n }\n\n const zero = useZero<TSchema, undefined, TContext>();\n const q = addContextToQuery(query, zero.context);\n\n const view = viewStore.getView(zero, q, enabled, ttl);\n // https://react.dev/reference/react/useSyncExternalStore\n const snapshot = useSyncExternalStore(\n view.subscribeReactInternals,\n view.getSnapshot,\n view.getSnapshot,\n );\n\n if (enabled) {\n if (suspendUntil === 'complete' && !view.complete) {\n suspend(view.waitForComplete());\n }\n\n if (suspendUntil === 'partial' && !view.nonEmpty) {\n suspend(view.waitForNonEmpty());\n }\n }\n\n return snapshot;\n}\n\nconst emptyArray: unknown[] = [];\nconst disabledSubscriber = () => () => {};\n\nconst resultTypeUnknown = {type: 'unknown'} as const;\nconst resultTypeComplete = {type: 'complete'} as const;\nconst resultTypeError = {type: 'error'} as const;\n\nconst emptySnapshotSingularUnknown = [undefined, resultTypeUnknown] as const;\nconst emptySnapshotSingularComplete = [undefined, resultTypeComplete] as const;\nconst emptySnapshotSingularErrorUnknown = [undefined, resultTypeError] as const;\nconst emptySnapshotPluralUnknown = [emptyArray, resultTypeUnknown] as const;\nconst emptySnapshotPluralComplete = [emptyArray, resultTypeComplete] as const;\nconst emptySnapshotErrorUnknown = [emptyArray, resultTypeError] as const;\n\nfunction getDefaultSnapshot<TReturn>(singular: boolean): QueryResult<TReturn> {\n return (\n singular ? emptySnapshotSingularUnknown : emptySnapshotPluralUnknown\n ) as QueryResult<TReturn>;\n}\n\n/**\n * Returns a new snapshot or one of the empty predefined ones. Returning the\n * predefined ones is important to prevent unnecessary re-renders in React.\n */\nfunction getSnapshot<TReturn>(\n singular: boolean,\n data: HumanReadable<TReturn>,\n resultType: ResultType,\n retryFn: () => void,\n error?: ErroredQuery,\n): QueryResult<TReturn> {\n if (singular && data === undefined) {\n switch (resultType) {\n case 'error':\n if (error) {\n return [\n undefined,\n makeError(retryFn, error),\n ] as unknown as QueryResult<TReturn>;\n }\n return emptySnapshotSingularErrorUnknown as unknown as QueryResult<TReturn>;\n case 'complete':\n return emptySnapshotSingularComplete as unknown as QueryResult<TReturn>;\n case 'unknown':\n return emptySnapshotSingularUnknown as unknown as QueryResult<TReturn>;\n }\n }\n\n if (!singular && (data as unknown[]).length === 0) {\n switch (resultType) {\n case 'error':\n if (error) {\n return [\n emptyArray,\n makeError(retryFn, error),\n ] as unknown as QueryResult<TReturn>;\n }\n return emptySnapshotErrorUnknown as unknown as QueryResult<TReturn>;\n case 'complete':\n return emptySnapshotPluralComplete as unknown as QueryResult<TReturn>;\n case 'unknown':\n return emptySnapshotPluralUnknown as unknown as QueryResult<TReturn>;\n }\n }\n\n switch (resultType) {\n case 'error':\n if (error) {\n return [data, makeError(retryFn, error)];\n }\n return [\n data,\n makeError(retryFn, {\n error: 'app',\n id: 'unknown',\n name: 'unknown',\n message: 'An unknown error occurred',\n }),\n ];\n case 'complete':\n return [data, resultTypeComplete];\n case 'unknown':\n return [data, resultTypeUnknown];\n }\n}\n\nfunction makeError(retry: () => void, error: ErroredQuery): QueryErrorDetails {\n const message = error.message ?? 'An unknown error occurred';\n return {\n type: 'error',\n retry,\n refetch: retry,\n error: {\n type: error.error,\n message,\n ...(error.details ? {details: error.details} : {}),\n },\n };\n}\n\ndeclare const TESTING: boolean;\n\n// oxlint-disable-next-line @typescript-eslint/no-explicit-any\ntype AnyViewWrapper = ViewWrapper<any, any, any, any, any>;\n\nconst allViews = new WeakMap<ViewStore, Map<string, AnyViewWrapper>>();\n\nexport function getAllViewsSizeForTesting(store: ViewStore): number {\n if (TESTING) {\n return allViews.get(store)?.size ?? 0;\n }\n return 0;\n}\n\n/**\n * A global store of all active views.\n *\n * React subscribes and unsubscribes to these views\n * via `useSyncExternalStore`.\n *\n * Managing views through `useEffect` or `useLayoutEffect` causes\n * inconsistencies because effects run after render.\n *\n * For example, if useQuery used use*Effect in the component below:\n * ```ts\n * function Foo({issueID}) {\n * const issue = useQuery(z.query.issue.where('id', issueID).one());\n * if (issue?.id !== undefined && issue.id !== issueID) {\n * console.log('MISMATCH!', issue.id, issueID);\n * }\n * }\n * ```\n *\n * `MISMATCH` will be printed whenever the `issueID` prop changes.\n *\n * This is because the component will render once with\n * the old state returned from `useQuery`. Then the effect inside\n * `useQuery` will run. The component will render again with the new\n * state. This inconsistent transition can cause unexpected results.\n *\n * Emulating `useEffect` via `useState` and `if` causes resource leaks.\n * That is:\n *\n * ```ts\n * function useQuery(q) {\n * const [oldHash, setOldHash] = useState();\n * if (hash(q) !== oldHash) {\n * // make new view\n * }\n *\n * useEffect(() => {\n * return () => view.destroy();\n * }, []);\n * }\n * ```\n *\n * I'm not sure why but in strict mode the cleanup function\n * fails to be called for the first instance of the view and only\n * cleans up later instances.\n *\n * Swapping `useState` to `useRef` has similar problems.\n */\nexport class ViewStore {\n #views = new Map<string, AnyViewWrapper>();\n\n constructor() {\n if (TESTING) {\n allViews.set(this, this.#views);\n }\n }\n\n getView<\n TTable extends keyof TSchema['tables'] & string,\n TSchema extends Schema,\n TReturn,\n MD extends CustomMutatorDefs | undefined,\n TContext,\n >(\n zero: Zero<TSchema, MD, TContext>,\n q: Query<TTable, TSchema, TReturn>,\n enabled: boolean,\n ttl: TTL,\n ): {\n getSnapshot: () => QueryResult<TReturn>;\n subscribeReactInternals: (internals: () => void) => () => void;\n updateTTL: (ttl: TTL) => void;\n waitForComplete: () => Promise<void>;\n waitForNonEmpty: () => Promise<void>;\n complete: boolean;\n nonEmpty: boolean;\n } {\n const qi = asQueryInternals(q);\n\n if (!enabled) {\n return {\n getSnapshot: () => getDefaultSnapshot(qi.format.singular),\n subscribeReactInternals: disabledSubscriber,\n updateTTL: () => {},\n waitForComplete: () => Promise.resolve(),\n waitForNonEmpty: () => Promise.resolve(),\n complete: false,\n nonEmpty: false,\n };\n }\n\n const hash = qi.hash() + zero.clientID;\n let existing = this.#views.get(hash);\n if (!existing) {\n existing = new ViewWrapper(q, zero, ttl, view => {\n const currentView = this.#views.get(hash);\n if (currentView && currentView !== view) {\n // we replaced the view with a new one already.\n return;\n }\n this.#views.delete(hash);\n });\n this.#views.set(hash, existing);\n } else {\n existing.updateTTL(ttl);\n }\n return existing as ViewWrapper<TTable, TSchema, TReturn, MD, TContext>;\n }\n}\n\nconst viewStore = new ViewStore();\n\n/**\n * This wraps and ref counts a view.\n *\n * The only signal we have from React as to whether or not it is\n * done with a view is when it calls `unsubscribe`.\n *\n * In non-strict-mode we can clean up the view as soon\n * as the listener count goes to 0.\n *\n * In strict-mode, the listener count will go to 0 then a\n * new listener for the same view is immediately added back.\n *\n * This is why the `onMaterialized` and `onDematerialized` callbacks exist --\n * they allow a view which React is still referencing to be added\n * back into the store when React re-subscribes to it.\n *\n * This wrapper also exists to deal with the various\n * `useSyncExternalStore` caveats that cause excessive\n * re-renders and materializations.\n *\n * See: https://react.dev/reference/react/useSyncExternalStore#caveats\n * Especially:\n * 1. The store snapshot returned by getSnapshot must be immutable. If the underlying store has mutable data, return a new immutable snapshot if the data has changed. Otherwise, return a cached last snapshot.\n * 2. If a different subscribe function is passed during a re-render, React will re-subscribe to the store using the newly passed subscribe function. You can prevent this by declaring subscribe outside the component.\n */\nclass ViewWrapper<\n TTable extends keyof TSchema['tables'] & string,\n TSchema extends Schema,\n TReturn,\n MD extends AnyMutatorRegistry | CustomMutatorDefs | undefined,\n TContext,\n> {\n #view: TypedView<HumanReadable<TReturn>> | undefined;\n readonly #onDematerialized;\n readonly #query: Query<TTable, TSchema, TReturn>;\n #snapshot: QueryResult<TReturn>;\n readonly #reactInternals: Set<() => void> = new Set();\n #ttl: TTL;\n #complete = false;\n #completeResolver = resolver<void>();\n #nonEmpty = false;\n #nonEmptyResolver = resolver<void>();\n readonly #zero: Pick<Zero<TSchema, undefined, TContext>, 'materialize'>;\n readonly #singular: boolean;\n\n constructor(\n query: Query<TTable, TSchema, TReturn>,\n zero: Pick<Zero<TSchema, undefined, TContext>, 'materialize'>,\n ttl: TTL,\n onDematerialized: (\n view: ViewWrapper<TTable, TSchema, TReturn, MD, TContext>,\n ) => void,\n ) {\n this.#query = query;\n this.#zero = zero;\n this.#ttl = ttl;\n this.#onDematerialized = onDematerialized;\n const {singular} = asQueryInternals(query).format;\n this.#singular = singular;\n this.#snapshot = getDefaultSnapshot(singular);\n this.#materializeIfNeeded();\n }\n\n #onData = (\n snap: Immutable<HumanReadable<TReturn>>,\n resultType: ResultType,\n error?: ErroredQuery,\n ) => {\n const data =\n snap === undefined\n ? snap\n : (deepClone(snap as ReadonlyJSONValue) as HumanReadable<TReturn>);\n this.#snapshot = getSnapshot(\n this.#singular,\n data,\n resultType,\n this.#retry,\n error,\n );\n if (resultType === 'complete' || resultType === 'error') {\n this.#complete = true;\n this.#completeResolver.resolve();\n this.#nonEmpty = true;\n this.#nonEmptyResolver.resolve();\n }\n\n if (\n this.#singular\n ? this.#snapshot[0] !== undefined\n : (this.#snapshot[0] as unknown[]).length !== 0\n ) {\n this.#nonEmpty = true;\n this.#nonEmptyResolver.resolve();\n }\n\n for (const internals of this.#reactInternals) {\n internals();\n }\n };\n\n /**\n * Called by the user to force a retry of the query\n * in the case the query errored.\n */\n #retry = () => {\n this.#view?.destroy();\n this.#view = undefined;\n this.#materializeIfNeeded();\n };\n\n #materializeIfNeeded = () => {\n if (this.#view) {\n return;\n }\n this.#view = this.#zero.materialize(this.#query, {\n ttl: this.#ttl,\n });\n this.#view.addListener(this.#onData);\n };\n\n getSnapshot = () => this.#snapshot;\n\n subscribeReactInternals = (internals: () => void): (() => void) => {\n this.#reactInternals.add(internals);\n this.#materializeIfNeeded();\n return () => {\n this.#reactInternals.delete(internals);\n\n // only schedule a cleanup task if we have no listeners left\n if (this.#reactInternals.size === 0) {\n setTimeout(() => {\n // We already destroyed the view\n if (this.#view === undefined) {\n return;\n }\n\n // Someone re-registered a listener on this view before the timeout elapsed.\n // This happens often in strict-mode which forces a component\n // to mount, unmount, remount.\n if (this.#reactInternals.size > 0) {\n return;\n }\n\n this.#view.destroy();\n this.#view = undefined;\n this.#complete = false;\n this.#completeResolver = resolver();\n this.#nonEmpty = false;\n this.#nonEmptyResolver = resolver();\n this.#onDematerialized(this);\n }, 10);\n }\n };\n };\n\n updateTTL(ttl: TTL): void {\n this.#ttl = ttl;\n this.#view?.updateTTL(ttl);\n }\n\n get complete() {\n return this.#complete;\n }\n\n waitForComplete(): Promise<void> {\n return this.#completeResolver.promise;\n }\n\n get nonEmpty() {\n return this.#nonEmpty;\n }\n\n waitForNonEmpty(): Promise<void> {\n return this.#nonEmptyResolver.promise;\n }\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"use-query.js","sources":["../../../../zero-react/src/use-query.tsx"],"sourcesContent":["import {resolver} from '@rocicorp/resolver';\nimport React, {useSyncExternalStore} from 'react';\nimport {\n type Immutable,\n addContextToQuery,\n asQueryInternals,\n deepClone,\n DEFAULT_TTL_MS,\n} from './bindings.ts';\nimport {useZero} from './zero-provider.tsx';\nimport type {\n AnyMutatorRegistry,\n CustomMutatorDefs,\n DefaultContext,\n DefaultSchema,\n ErroredQuery,\n Falsy,\n HumanReadable,\n PullRow,\n Query,\n QueryErrorDetails,\n QueryOrQueryRequest,\n QueryResultDetails,\n ReadonlyJSONValue,\n ResultType,\n Schema,\n TTL,\n TypedView,\n Zero,\n} from './zero.ts';\n\nexport type QueryResult<TReturn> = readonly [\n HumanReadable<TReturn>,\n QueryResultDetails & {},\n];\n\n/**\n * Result type for \"maybe queries\" - queries that may be falsy.\n * The data value can be undefined when the query is falsy/disabled.\n */\nexport type MaybeQueryResult<TReturn> = readonly [\n HumanReadable<TReturn> | undefined,\n QueryResultDetails & {},\n];\n\nexport type UseQueryOptions = {\n enabled?: boolean | undefined;\n /**\n * Time to live (TTL) in seconds. Controls how long query results are cached\n * after the query is removed. During this time, Zero continues to sync the query.\n * Default is 'never'.\n */\n ttl?: TTL | undefined;\n};\n\nexport type UseSuspenseQueryOptions = UseQueryOptions & {\n /**\n * Whether to suspend until:\n * - 'partial': the query has partial results (partial array or defined\n * value for singular results) which may be of result type 'unknown',\n * or the query result type is 'complete' (in which case results may be\n * empty). This is useful for suspending until there are partial\n * optimistic local results, or the query has completed loading from the\n * server.\n * - 'complete': the query result type is 'complete'.\n *\n * Default is 'partial'.\n */\n suspendUntil?: 'complete' | 'partial';\n};\n\nconst reactUse = (React as {use?: (p: Promise<unknown>) => void}).use;\nconst suspend: (p: Promise<unknown>) => void = reactUse\n ? reactUse\n : p => {\n throw p;\n };\n\n// Overload 1: Query\nexport function useQuery<\n TTable extends keyof TSchema['tables'] & string,\n TInput extends ReadonlyJSONValue | undefined,\n TOutput extends ReadonlyJSONValue | undefined,\n TSchema extends Schema = DefaultSchema,\n TReturn = PullRow<TTable, TSchema>,\n TContext = DefaultContext,\n>(\n query: QueryOrQueryRequest<\n TTable,\n TInput,\n TOutput,\n TSchema,\n TReturn,\n TContext\n >,\n options?: UseQueryOptions | boolean,\n): QueryResult<TReturn>;\n\n// Overload 2: Maybe query\nexport function useQuery<\n TTable extends keyof TSchema['tables'] & string,\n TInput extends ReadonlyJSONValue | undefined,\n TOutput extends ReadonlyJSONValue | undefined,\n TSchema extends Schema = DefaultSchema,\n TReturn = PullRow<TTable, TSchema>,\n TContext = DefaultContext,\n>(\n query:\n | QueryOrQueryRequest<TTable, TInput, TOutput, TSchema, TReturn, TContext>\n | Falsy,\n options?: UseQueryOptions | boolean,\n): MaybeQueryResult<TReturn>;\n\n// Implementation\nexport function useQuery<\n TTable extends keyof TSchema['tables'] & string,\n TInput extends ReadonlyJSONValue | undefined,\n TOutput extends ReadonlyJSONValue | undefined,\n TSchema extends Schema = DefaultSchema,\n TReturn = PullRow<TTable, TSchema>,\n TContext = DefaultContext,\n>(\n query:\n | QueryOrQueryRequest<TTable, TInput, TOutput, TSchema, TReturn, TContext>\n | Falsy,\n options?: UseQueryOptions | boolean,\n): QueryResult<TReturn> | MaybeQueryResult<TReturn> {\n let enabled = true;\n let ttl: TTL = DEFAULT_TTL_MS;\n if (typeof options === 'boolean') {\n enabled = options;\n } else if (options) {\n ({enabled = true, ttl = DEFAULT_TTL_MS} = options);\n }\n\n const zero = useZero<TSchema, undefined, TContext>();\n\n // When query is falsy, use disabled subscriber/snapshot to maintain hook order\n const q = query ? addContextToQuery(query, zero.context) : undefined;\n const view = q ? viewStore.getView(zero, q, enabled, ttl) : undefined;\n\n // https://react.dev/reference/react/useSyncExternalStore\n // Always call useSyncExternalStore to maintain consistent hook order\n return useSyncExternalStore(\n view?.subscribeReactInternals ?? disabledSubscriber,\n view?.getSnapshot ??\n (getDisabledSnapshot as () => MaybeQueryResult<TReturn>),\n view?.getSnapshot ??\n (getDisabledSnapshot as () => MaybeQueryResult<TReturn>),\n );\n}\n\n// Overload 1: Query\nexport function useSuspenseQuery<\n TTable extends keyof TSchema['tables'] & string,\n TInput extends ReadonlyJSONValue | undefined,\n TOutput extends ReadonlyJSONValue | undefined,\n TSchema extends Schema = DefaultSchema,\n TReturn = PullRow<TTable, TSchema>,\n TContext = DefaultContext,\n>(\n query: QueryOrQueryRequest<\n TTable,\n TInput,\n TOutput,\n TSchema,\n TReturn,\n TContext\n >,\n options?: UseSuspenseQueryOptions | boolean,\n): QueryResult<TReturn>;\n\n// Overload 2: Maybe query\nexport function useSuspenseQuery<\n TTable extends keyof TSchema['tables'] & string,\n TInput extends ReadonlyJSONValue | undefined,\n TOutput extends ReadonlyJSONValue | undefined,\n TSchema extends Schema = DefaultSchema,\n TReturn = PullRow<TTable, TSchema>,\n TContext = DefaultContext,\n>(\n query:\n | QueryOrQueryRequest<TTable, TInput, TOutput, TSchema, TReturn, TContext>\n | Falsy,\n options?: UseSuspenseQueryOptions | boolean,\n): MaybeQueryResult<TReturn>;\n\n// Implementation\nexport function useSuspenseQuery<\n TTable extends keyof TSchema['tables'] & string,\n TInput extends ReadonlyJSONValue | undefined,\n TOutput extends ReadonlyJSONValue | undefined,\n TSchema extends Schema = DefaultSchema,\n TReturn = PullRow<TTable, TSchema>,\n TContext = DefaultContext,\n>(\n query:\n | QueryOrQueryRequest<TTable, TInput, TOutput, TSchema, TReturn, TContext>\n | Falsy,\n options?: UseSuspenseQueryOptions | boolean,\n): QueryResult<TReturn> | MaybeQueryResult<TReturn> {\n let enabled = true;\n let ttl: TTL = DEFAULT_TTL_MS;\n let suspendUntil: 'complete' | 'partial' = 'partial';\n if (typeof options === 'boolean') {\n enabled = options;\n } else if (options) {\n ({\n enabled = true,\n ttl = DEFAULT_TTL_MS,\n suspendUntil = 'complete',\n } = options);\n }\n\n const zero = useZero<TSchema, undefined, TContext>();\n\n // When query is falsy, use disabled subscriber/snapshot to maintain hook order\n const q = query ? addContextToQuery(query, zero.context) : undefined;\n const view = q ? viewStore.getView(zero, q, enabled, ttl) : undefined;\n\n // https://react.dev/reference/react/useSyncExternalStore\n // Always call useSyncExternalStore to maintain consistent hook order\n const snapshot = useSyncExternalStore(\n view?.subscribeReactInternals ?? disabledSubscriber,\n view?.getSnapshot ??\n (getDisabledSnapshot as () => MaybeQueryResult<TReturn>),\n view?.getSnapshot ??\n (getDisabledSnapshot as () => MaybeQueryResult<TReturn>),\n );\n\n if (view && enabled) {\n if (suspendUntil === 'complete' && !view.complete) {\n suspend(view.waitForComplete());\n }\n\n if (suspendUntil === 'partial' && !view.nonEmpty) {\n suspend(view.waitForNonEmpty());\n }\n }\n\n return snapshot;\n}\n\nconst emptyArray: unknown[] = [];\nconst disabledSubscriber = () => () => {};\n\nconst resultTypeUnknown = {type: 'unknown'} as const;\nconst resultTypeComplete = {type: 'complete'} as const;\nconst resultTypeError = {type: 'error'} as const;\n\nconst disabledQuerySnapshot = [undefined, resultTypeUnknown] as const;\nconst getDisabledSnapshot = () => disabledQuerySnapshot;\n\nconst emptySnapshotSingularUnknown = [undefined, resultTypeUnknown] as const;\nconst emptySnapshotSingularComplete = [undefined, resultTypeComplete] as const;\nconst emptySnapshotSingularErrorUnknown = [undefined, resultTypeError] as const;\nconst emptySnapshotPluralUnknown = [emptyArray, resultTypeUnknown] as const;\nconst emptySnapshotPluralComplete = [emptyArray, resultTypeComplete] as const;\nconst emptySnapshotErrorUnknown = [emptyArray, resultTypeError] as const;\n\nfunction getDefaultSnapshot<TReturn>(singular: boolean): QueryResult<TReturn> {\n return (\n singular ? emptySnapshotSingularUnknown : emptySnapshotPluralUnknown\n ) as QueryResult<TReturn>;\n}\n\n/**\n * Returns a new snapshot or one of the empty predefined ones. Returning the\n * predefined ones is important to prevent unnecessary re-renders in React.\n */\nfunction getSnapshot<TReturn>(\n singular: boolean,\n data: HumanReadable<TReturn>,\n resultType: ResultType,\n retryFn: () => void,\n error?: ErroredQuery,\n): QueryResult<TReturn> {\n if (singular && data === undefined) {\n switch (resultType) {\n case 'error':\n if (error) {\n return [\n undefined,\n makeError(retryFn, error),\n ] as unknown as QueryResult<TReturn>;\n }\n return emptySnapshotSingularErrorUnknown as unknown as QueryResult<TReturn>;\n case 'complete':\n return emptySnapshotSingularComplete as unknown as QueryResult<TReturn>;\n case 'unknown':\n return emptySnapshotSingularUnknown as unknown as QueryResult<TReturn>;\n }\n }\n\n if (!singular && (data as unknown[]).length === 0) {\n switch (resultType) {\n case 'error':\n if (error) {\n return [\n emptyArray,\n makeError(retryFn, error),\n ] as unknown as QueryResult<TReturn>;\n }\n return emptySnapshotErrorUnknown as unknown as QueryResult<TReturn>;\n case 'complete':\n return emptySnapshotPluralComplete as unknown as QueryResult<TReturn>;\n case 'unknown':\n return emptySnapshotPluralUnknown as unknown as QueryResult<TReturn>;\n }\n }\n\n switch (resultType) {\n case 'error':\n if (error) {\n return [data, makeError(retryFn, error)];\n }\n return [\n data,\n makeError(retryFn, {\n error: 'app',\n id: 'unknown',\n name: 'unknown',\n message: 'An unknown error occurred',\n }),\n ];\n case 'complete':\n return [data, resultTypeComplete];\n case 'unknown':\n return [data, resultTypeUnknown];\n }\n}\n\nfunction makeError(retry: () => void, error: ErroredQuery): QueryErrorDetails {\n const message = error.message ?? 'An unknown error occurred';\n return {\n type: 'error',\n retry,\n refetch: retry,\n error: {\n type: error.error,\n message,\n ...(error.details ? {details: error.details} : {}),\n },\n };\n}\n\ndeclare const TESTING: boolean;\n\n// oxlint-disable-next-line @typescript-eslint/no-explicit-any\ntype AnyViewWrapper = ViewWrapper<any, any, any, any, any>;\n\nconst allViews = new WeakMap<ViewStore, Map<string, AnyViewWrapper>>();\n\nexport function getAllViewsSizeForTesting(store: ViewStore): number {\n if (TESTING) {\n return allViews.get(store)?.size ?? 0;\n }\n return 0;\n}\n\n/**\n * A global store of all active views.\n *\n * React subscribes and unsubscribes to these views\n * via `useSyncExternalStore`.\n *\n * Managing views through `useEffect` or `useLayoutEffect` causes\n * inconsistencies because effects run after render.\n *\n * For example, if useQuery used use*Effect in the component below:\n * ```ts\n * function Foo({issueID}) {\n * const issue = useQuery(z.query.issue.where('id', issueID).one());\n * if (issue?.id !== undefined && issue.id !== issueID) {\n * console.log('MISMATCH!', issue.id, issueID);\n * }\n * }\n * ```\n *\n * `MISMATCH` will be printed whenever the `issueID` prop changes.\n *\n * This is because the component will render once with\n * the old state returned from `useQuery`. Then the effect inside\n * `useQuery` will run. The component will render again with the new\n * state. This inconsistent transition can cause unexpected results.\n *\n * Emulating `useEffect` via `useState` and `if` causes resource leaks.\n * That is:\n *\n * ```ts\n * function useQuery(q) {\n * const [oldHash, setOldHash] = useState();\n * if (hash(q) !== oldHash) {\n * // make new view\n * }\n *\n * useEffect(() => {\n * return () => view.destroy();\n * }, []);\n * }\n * ```\n *\n * I'm not sure why but in strict mode the cleanup function\n * fails to be called for the first instance of the view and only\n * cleans up later instances.\n *\n * Swapping `useState` to `useRef` has similar problems.\n */\nexport class ViewStore {\n #views = new Map<string, AnyViewWrapper>();\n\n constructor() {\n if (TESTING) {\n allViews.set(this, this.#views);\n }\n }\n\n getView<\n TTable extends keyof TSchema['tables'] & string,\n TSchema extends Schema,\n TReturn,\n MD extends CustomMutatorDefs | undefined,\n TContext,\n >(\n zero: Zero<TSchema, MD, TContext>,\n q: Query<TTable, TSchema, TReturn>,\n enabled: boolean,\n ttl: TTL,\n ): {\n getSnapshot: () => QueryResult<TReturn>;\n subscribeReactInternals: (internals: () => void) => () => void;\n updateTTL: (ttl: TTL) => void;\n waitForComplete: () => Promise<void>;\n waitForNonEmpty: () => Promise<void>;\n complete: boolean;\n nonEmpty: boolean;\n } {\n const qi = asQueryInternals(q);\n\n if (!enabled) {\n return {\n getSnapshot: () => getDefaultSnapshot(qi.format.singular),\n subscribeReactInternals: disabledSubscriber,\n updateTTL: () => {},\n waitForComplete: () => Promise.resolve(),\n waitForNonEmpty: () => Promise.resolve(),\n complete: false,\n nonEmpty: false,\n };\n }\n\n const hash = qi.hash() + zero.clientID;\n let existing = this.#views.get(hash);\n if (!existing) {\n existing = new ViewWrapper(q, zero, ttl, view => {\n const currentView = this.#views.get(hash);\n if (currentView && currentView !== view) {\n // we replaced the view with a new one already.\n return;\n }\n this.#views.delete(hash);\n });\n this.#views.set(hash, existing);\n } else {\n existing.updateTTL(ttl);\n }\n return existing as ViewWrapper<TTable, TSchema, TReturn, MD, TContext>;\n }\n}\n\nconst viewStore = new ViewStore();\n\n/**\n * This wraps and ref counts a view.\n *\n * The only signal we have from React as to whether or not it is\n * done with a view is when it calls `unsubscribe`.\n *\n * In non-strict-mode we can clean up the view as soon\n * as the listener count goes to 0.\n *\n * In strict-mode, the listener count will go to 0 then a\n * new listener for the same view is immediately added back.\n *\n * This is why the `onMaterialized` and `onDematerialized` callbacks exist --\n * they allow a view which React is still referencing to be added\n * back into the store when React re-subscribes to it.\n *\n * This wrapper also exists to deal with the various\n * `useSyncExternalStore` caveats that cause excessive\n * re-renders and materializations.\n *\n * See: https://react.dev/reference/react/useSyncExternalStore#caveats\n * Especially:\n * 1. The store snapshot returned by getSnapshot must be immutable. If the underlying store has mutable data, return a new immutable snapshot if the data has changed. Otherwise, return a cached last snapshot.\n * 2. If a different subscribe function is passed during a re-render, React will re-subscribe to the store using the newly passed subscribe function. You can prevent this by declaring subscribe outside the component.\n */\nclass ViewWrapper<\n TTable extends keyof TSchema['tables'] & string,\n TSchema extends Schema,\n TReturn,\n MD extends AnyMutatorRegistry | CustomMutatorDefs | undefined,\n TContext,\n> {\n #view: TypedView<HumanReadable<TReturn>> | undefined;\n readonly #onDematerialized;\n readonly #query: Query<TTable, TSchema, TReturn>;\n #snapshot: QueryResult<TReturn>;\n readonly #reactInternals: Set<() => void> = new Set();\n #ttl: TTL;\n #complete = false;\n #completeResolver = resolver<void>();\n #nonEmpty = false;\n #nonEmptyResolver = resolver<void>();\n readonly #zero: Pick<Zero<TSchema, undefined, TContext>, 'materialize'>;\n readonly #singular: boolean;\n\n constructor(\n query: Query<TTable, TSchema, TReturn>,\n zero: Pick<Zero<TSchema, undefined, TContext>, 'materialize'>,\n ttl: TTL,\n onDematerialized: (\n view: ViewWrapper<TTable, TSchema, TReturn, MD, TContext>,\n ) => void,\n ) {\n this.#query = query;\n this.#zero = zero;\n this.#ttl = ttl;\n this.#onDematerialized = onDematerialized;\n const {singular} = asQueryInternals(query).format;\n this.#singular = singular;\n this.#snapshot = getDefaultSnapshot(singular);\n this.#materializeIfNeeded();\n }\n\n #onData = (\n snap: Immutable<HumanReadable<TReturn>>,\n resultType: ResultType,\n error?: ErroredQuery,\n ) => {\n const data =\n snap === undefined\n ? snap\n : (deepClone(snap as ReadonlyJSONValue) as HumanReadable<TReturn>);\n this.#snapshot = getSnapshot(\n this.#singular,\n data,\n resultType,\n this.#retry,\n error,\n );\n if (resultType === 'complete' || resultType === 'error') {\n this.#complete = true;\n this.#completeResolver.resolve();\n this.#nonEmpty = true;\n this.#nonEmptyResolver.resolve();\n }\n\n if (\n this.#singular\n ? this.#snapshot[0] !== undefined\n : (this.#snapshot[0] as unknown[]).length !== 0\n ) {\n this.#nonEmpty = true;\n this.#nonEmptyResolver.resolve();\n }\n\n for (const internals of this.#reactInternals) {\n internals();\n }\n };\n\n /**\n * Called by the user to force a retry of the query\n * in the case the query errored.\n */\n #retry = () => {\n this.#view?.destroy();\n this.#view = undefined;\n this.#materializeIfNeeded();\n };\n\n #materializeIfNeeded = () => {\n if (this.#view) {\n return;\n }\n this.#view = this.#zero.materialize(this.#query, {\n ttl: this.#ttl,\n });\n this.#view.addListener(this.#onData);\n };\n\n getSnapshot = () => this.#snapshot;\n\n subscribeReactInternals = (internals: () => void): (() => void) => {\n this.#reactInternals.add(internals);\n this.#materializeIfNeeded();\n return () => {\n this.#reactInternals.delete(internals);\n\n // only schedule a cleanup task if we have no listeners left\n if (this.#reactInternals.size === 0) {\n setTimeout(() => {\n // We already destroyed the view\n if (this.#view === undefined) {\n return;\n }\n\n // Someone re-registered a listener on this view before the timeout elapsed.\n // This happens often in strict-mode which forces a component\n // to mount, unmount, remount.\n if (this.#reactInternals.size > 0) {\n return;\n }\n\n this.#view.destroy();\n this.#view = undefined;\n this.#complete = false;\n this.#completeResolver = resolver();\n this.#nonEmpty = false;\n this.#nonEmptyResolver = resolver();\n this.#onDematerialized(this);\n }, 10);\n }\n };\n };\n\n updateTTL(ttl: TTL): void {\n this.#ttl = ttl;\n this.#view?.updateTTL(ttl);\n }\n\n get complete() {\n return this.#complete;\n }\n\n waitForComplete(): Promise<void> {\n return this.#completeResolver.promise;\n }\n\n get nonEmpty() {\n return this.#nonEmpty;\n }\n\n waitForNonEmpty(): Promise<void> {\n return this.#nonEmptyResolver.promise;\n }\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { DefaultContext, DefaultSchema } from '../../zero-types/src/default-types.ts';
|
|
2
|
+
import type { QueryOrQueryRequest } from '../../zql/src/query/query-registry.ts';
|
|
3
|
+
import { type UseQueryOptions } from './use-query.tsx';
|
|
4
|
+
export type Anchor<TStartRow> = Readonly<{
|
|
5
|
+
index: number;
|
|
6
|
+
kind: 'forward';
|
|
7
|
+
startRow?: TStartRow | undefined;
|
|
8
|
+
}> | Readonly<{
|
|
9
|
+
index: number;
|
|
10
|
+
kind: 'backward';
|
|
11
|
+
startRow: TStartRow;
|
|
12
|
+
}> | Readonly<{
|
|
13
|
+
index: number;
|
|
14
|
+
kind: 'permalink';
|
|
15
|
+
id: string;
|
|
16
|
+
}>;
|
|
17
|
+
export type GetPageQuery<TRow, TStartRow> = (limit: number, start: TStartRow | null, dir: 'forward' | 'backward') => GetQueryReturnType<TRow>;
|
|
18
|
+
export type GetSingleQuery<TRow> = (id: string) => GetQueryReturnType<TRow | undefined>;
|
|
19
|
+
export type GetQueryReturnType<TReturn> = QueryOrQueryRequest<keyof DefaultSchema['tables'] & string, any, // input
|
|
20
|
+
any, // output
|
|
21
|
+
DefaultSchema, TReturn, DefaultContext>;
|
|
22
|
+
export declare function useRows<TRow, TStartRow>({ pageSize, anchor, options, getPageQuery, getSingleQuery, toStartRow, }: {
|
|
23
|
+
pageSize: number;
|
|
24
|
+
anchor: Anchor<TStartRow>;
|
|
25
|
+
options?: UseQueryOptions | undefined;
|
|
26
|
+
getPageQuery: GetPageQuery<TRow, TStartRow>;
|
|
27
|
+
getSingleQuery: GetSingleQuery<TRow>;
|
|
28
|
+
toStartRow: (row: TRow) => TStartRow;
|
|
29
|
+
}): {
|
|
30
|
+
rowAt: (index: number) => TRow | undefined;
|
|
31
|
+
rowsLength: number;
|
|
32
|
+
complete: boolean;
|
|
33
|
+
rowsEmpty: boolean;
|
|
34
|
+
atStart: boolean;
|
|
35
|
+
atEnd: boolean;
|
|
36
|
+
firstRowIndex: number;
|
|
37
|
+
permalinkNotFound: boolean;
|
|
38
|
+
};
|
|
39
|
+
//# sourceMappingURL=use-rows.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-rows.d.ts","sourceRoot":"","sources":["../../../../zero-react/src/use-rows.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,cAAc,EACd,aAAa,EACd,MAAM,uCAAuC,CAAC;AAC/C,OAAO,KAAK,EAAC,mBAAmB,EAAC,MAAM,uCAAuC,CAAC;AAC/E,OAAO,EAAW,KAAK,eAAe,EAAC,MAAM,iBAAiB,CAAC;AAE/D,MAAM,MAAM,MAAM,CAAC,SAAS,IACxB,QAAQ,CAAC;IACP,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,SAAS,CAAC;IAChB,QAAQ,CAAC,EAAE,SAAS,GAAG,SAAS,CAAC;CAClC,CAAC,GACF,QAAQ,CAAC;IACP,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,UAAU,CAAC;IACjB,QAAQ,EAAE,SAAS,CAAC;CACrB,CAAC,GACF,QAAQ,CAAC;IACP,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,WAAW,CAAC;IAClB,EAAE,EAAE,MAAM,CAAC;CACZ,CAAC,CAAC;AAEP,MAAM,MAAM,YAAY,CAAC,IAAI,EAAE,SAAS,IAAI,CAC1C,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,SAAS,GAAG,IAAI,EACvB,GAAG,EAAE,SAAS,GAAG,UAAU,KACxB,kBAAkB,CAAC,IAAI,CAAC,CAAC;AAE9B,MAAM,MAAM,cAAc,CAAC,IAAI,IAAI,CACjC,EAAE,EAAE,MAAM,KACP,kBAAkB,CAAC,IAAI,GAAG,SAAS,CAAC,CAAC;AAE1C,MAAM,MAAM,kBAAkB,CAAC,OAAO,IAAI,mBAAmB,CAC3D,MAAM,aAAa,CAAC,QAAQ,CAAC,GAAG,MAAM,EAEtC,GAAG,EAAE,QAAQ;AAEb,GAAG,EAAE,SAAS;AACd,aAAa,EACb,OAAO,EACP,cAAc,CACf,CAAC;AAEF,wBAAgB,OAAO,CAAC,IAAI,EAAE,SAAS,EAAE,EACvC,QAAQ,EACR,MAAM,EACN,OAAO,EACP,YAAY,EACZ,cAAc,EACd,UAAU,GACX,EAAE;IACD,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC,SAAS,CAAC,CAAC;IAC1B,OAAO,CAAC,EAAE,eAAe,GAAG,SAAS,CAAC;IAEtC,YAAY,EAAE,YAAY,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;IAC5C,cAAc,EAAE,cAAc,CAAC,IAAI,CAAC,CAAC;IACrC,UAAU,EAAE,CAAC,GAAG,EAAE,IAAI,KAAK,SAAS,CAAC;CACtC,GAAG;IACF,KAAK,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,GAAG,SAAS,CAAC;IAC3C,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,OAAO,CAAC;IAClB,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,OAAO,CAAC;IACf,aAAa,EAAE,MAAM,CAAC;IACtB,iBAAiB,EAAE,OAAO,CAAC;CAC5B,CAoJA"}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { assert } from "../../shared/src/asserts.js";
|
|
2
|
+
import { useQuery } from "./use-query.js";
|
|
3
|
+
function useRows({
|
|
4
|
+
pageSize,
|
|
5
|
+
anchor,
|
|
6
|
+
options,
|
|
7
|
+
getPageQuery,
|
|
8
|
+
getSingleQuery,
|
|
9
|
+
toStartRow
|
|
10
|
+
}) {
|
|
11
|
+
const { kind, index: anchorIndex } = anchor;
|
|
12
|
+
let permalinkNotFound = false;
|
|
13
|
+
if (kind === "permalink") {
|
|
14
|
+
const { id } = anchor;
|
|
15
|
+
assert(id);
|
|
16
|
+
assert(pageSize % 2 === 0);
|
|
17
|
+
const halfPageSize = pageSize / 2;
|
|
18
|
+
const qItem = getSingleQuery(id);
|
|
19
|
+
const [row, resultRow] = useQuery(qItem, options);
|
|
20
|
+
const completeRow = resultRow.type === "complete";
|
|
21
|
+
const typedRow = row;
|
|
22
|
+
if (completeRow && typedRow === void 0) {
|
|
23
|
+
void useQuery(null, options);
|
|
24
|
+
void useQuery(null, options);
|
|
25
|
+
return {
|
|
26
|
+
rowAt: () => void 0,
|
|
27
|
+
rowsLength: 0,
|
|
28
|
+
complete: true,
|
|
29
|
+
rowsEmpty: true,
|
|
30
|
+
atStart: true,
|
|
31
|
+
atEnd: true,
|
|
32
|
+
firstRowIndex: anchorIndex,
|
|
33
|
+
permalinkNotFound: true
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
const start2 = typedRow && toStartRow(typedRow);
|
|
37
|
+
const qBefore = start2 && getPageQuery(halfPageSize + 1, start2, "backward");
|
|
38
|
+
const qAfter = start2 && getPageQuery(halfPageSize, start2, "forward");
|
|
39
|
+
const [rowsBefore, resultBefore] = useQuery(qBefore, options);
|
|
40
|
+
const [rowsAfter, resultAfter] = useQuery(qAfter, options);
|
|
41
|
+
const completeBefore = resultBefore.type === "complete";
|
|
42
|
+
const completeAfter = resultAfter.type === "complete";
|
|
43
|
+
const typedRowsBefore = rowsBefore;
|
|
44
|
+
const typedRowsAfter = rowsAfter;
|
|
45
|
+
const rowsBeforeLength = typedRowsBefore?.length ?? 0;
|
|
46
|
+
const rowsAfterLength = typedRowsAfter?.length ?? 0;
|
|
47
|
+
const rowsBeforeSize = Math.min(rowsBeforeLength, halfPageSize);
|
|
48
|
+
const rowsAfterSize = Math.min(rowsAfterLength, halfPageSize - 1);
|
|
49
|
+
const firstRowIndex = anchorIndex - rowsBeforeSize;
|
|
50
|
+
return {
|
|
51
|
+
rowAt: (index) => {
|
|
52
|
+
if (index === anchorIndex) {
|
|
53
|
+
return typedRow;
|
|
54
|
+
}
|
|
55
|
+
if (index > anchorIndex) {
|
|
56
|
+
if (typedRowsAfter === void 0) {
|
|
57
|
+
return void 0;
|
|
58
|
+
}
|
|
59
|
+
const i2 = index - anchorIndex - 1;
|
|
60
|
+
if (i2 >= rowsAfterSize) {
|
|
61
|
+
return void 0;
|
|
62
|
+
}
|
|
63
|
+
return typedRowsAfter[i2];
|
|
64
|
+
}
|
|
65
|
+
assert(index < anchorIndex);
|
|
66
|
+
if (typedRowsBefore === void 0) {
|
|
67
|
+
return void 0;
|
|
68
|
+
}
|
|
69
|
+
const i = anchorIndex - index - 1;
|
|
70
|
+
if (i >= rowsBeforeSize) {
|
|
71
|
+
return void 0;
|
|
72
|
+
}
|
|
73
|
+
return typedRowsBefore[i];
|
|
74
|
+
},
|
|
75
|
+
rowsLength: rowsBeforeSize + rowsAfterSize + (typedRow ? 1 : 0),
|
|
76
|
+
complete: completeRow && (typedRow === void 0 || completeBefore && completeAfter),
|
|
77
|
+
rowsEmpty: typedRow === void 0 || rowsBeforeSize === 0 && rowsAfterSize === 0,
|
|
78
|
+
atStart: completeBefore && rowsBeforeLength <= halfPageSize,
|
|
79
|
+
atEnd: completeAfter && rowsAfterLength <= halfPageSize - 1,
|
|
80
|
+
firstRowIndex,
|
|
81
|
+
permalinkNotFound
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
const { startRow: start = null } = anchor;
|
|
85
|
+
const q = getPageQuery(pageSize + 1, start, kind);
|
|
86
|
+
const [rows, result] = useQuery(q, options);
|
|
87
|
+
void useQuery(null, options);
|
|
88
|
+
void useQuery(null, options);
|
|
89
|
+
const typedRows = rows;
|
|
90
|
+
const complete = result.type === "complete";
|
|
91
|
+
const hasMoreRows = typedRows.length > pageSize;
|
|
92
|
+
const rowsLength = hasMoreRows ? pageSize : typedRows.length;
|
|
93
|
+
const rowsEmpty = typedRows.length === 0;
|
|
94
|
+
if (kind === "forward") {
|
|
95
|
+
return {
|
|
96
|
+
rowAt: (index) => index - anchorIndex < rowsLength ? typedRows[index - anchorIndex] : void 0,
|
|
97
|
+
rowsLength,
|
|
98
|
+
complete,
|
|
99
|
+
rowsEmpty,
|
|
100
|
+
atStart: start === null || anchorIndex === 0,
|
|
101
|
+
atEnd: complete && !hasMoreRows,
|
|
102
|
+
firstRowIndex: anchorIndex,
|
|
103
|
+
permalinkNotFound
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
assert(start !== null);
|
|
107
|
+
return {
|
|
108
|
+
rowAt: (index) => {
|
|
109
|
+
if (index >= anchorIndex) {
|
|
110
|
+
return void 0;
|
|
111
|
+
}
|
|
112
|
+
const i = anchorIndex - index - 1;
|
|
113
|
+
if (i < 0 || i >= rowsLength) {
|
|
114
|
+
return void 0;
|
|
115
|
+
}
|
|
116
|
+
return typedRows[i];
|
|
117
|
+
},
|
|
118
|
+
rowsLength,
|
|
119
|
+
complete,
|
|
120
|
+
rowsEmpty,
|
|
121
|
+
atStart: complete && !hasMoreRows,
|
|
122
|
+
atEnd: false,
|
|
123
|
+
firstRowIndex: anchorIndex - rowsLength,
|
|
124
|
+
permalinkNotFound
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
export {
|
|
128
|
+
useRows
|
|
129
|
+
};
|
|
130
|
+
//# sourceMappingURL=use-rows.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-rows.js","sources":["../../../../zero-react/src/use-rows.ts"],"sourcesContent":["import {assert} from 'shared/src/asserts.ts';\nimport type {\n DefaultContext,\n DefaultSchema,\n} from '../../zero-types/src/default-types.ts';\nimport type {QueryOrQueryRequest} from '../../zql/src/query/query-registry.ts';\nimport {useQuery, type UseQueryOptions} from './use-query.tsx';\n\nexport type Anchor<TStartRow> =\n | Readonly<{\n index: number;\n kind: 'forward';\n startRow?: TStartRow | undefined;\n }>\n | Readonly<{\n index: number;\n kind: 'backward';\n startRow: TStartRow;\n }>\n | Readonly<{\n index: number;\n kind: 'permalink';\n id: string;\n }>;\n\nexport type GetPageQuery<TRow, TStartRow> = (\n limit: number,\n start: TStartRow | null,\n dir: 'forward' | 'backward',\n) => GetQueryReturnType<TRow>;\n\nexport type GetSingleQuery<TRow> = (\n id: string,\n) => GetQueryReturnType<TRow | undefined>;\n\nexport type GetQueryReturnType<TReturn> = QueryOrQueryRequest<\n keyof DefaultSchema['tables'] & string,\n // oxlint-disable-next-line no-explicit-any\n any, // input\n // oxlint-disable-next-line no-explicit-any\n any, // output\n DefaultSchema,\n TReturn,\n DefaultContext\n>;\n\nexport function useRows<TRow, TStartRow>({\n pageSize,\n anchor,\n options,\n getPageQuery,\n getSingleQuery,\n toStartRow,\n}: {\n pageSize: number;\n anchor: Anchor<TStartRow>;\n options?: UseQueryOptions | undefined;\n\n getPageQuery: GetPageQuery<TRow, TStartRow>;\n getSingleQuery: GetSingleQuery<TRow>;\n toStartRow: (row: TRow) => TStartRow;\n}): {\n rowAt: (index: number) => TRow | undefined;\n rowsLength: number;\n complete: boolean;\n rowsEmpty: boolean;\n atStart: boolean;\n atEnd: boolean;\n firstRowIndex: number;\n permalinkNotFound: boolean;\n} {\n const {kind, index: anchorIndex} = anchor;\n let permalinkNotFound = false;\n\n if (kind === 'permalink') {\n const {id} = anchor;\n assert(id);\n assert(pageSize % 2 === 0);\n\n const halfPageSize = pageSize / 2;\n\n const qItem = getSingleQuery(id);\n\n const [row, resultRow] = useQuery(qItem, options);\n const completeRow = resultRow.type === 'complete';\n\n const typedRow = row as TRow | undefined;\n\n // Early return if permalink not found to skip unnecessary queries\n if (completeRow && typedRow === undefined) {\n // Call dummy useQuery to maintain hooks call order\n void useQuery(null, options);\n void useQuery(null, options);\n\n return {\n rowAt: () => undefined,\n rowsLength: 0,\n complete: true,\n rowsEmpty: true,\n atStart: true,\n atEnd: true,\n firstRowIndex: anchorIndex,\n permalinkNotFound: true,\n };\n }\n\n const start = typedRow && toStartRow(typedRow);\n\n const qBefore = start && getPageQuery(halfPageSize + 1, start, 'backward');\n const qAfter = start && getPageQuery(halfPageSize, start, 'forward');\n\n const [rowsBefore, resultBefore] = useQuery(qBefore, options);\n const [rowsAfter, resultAfter] = useQuery(qAfter, options);\n const completeBefore = resultBefore.type === 'complete';\n const completeAfter = resultAfter.type === 'complete';\n\n const typedRowsBefore = rowsBefore as unknown as TRow[] | undefined;\n const typedRowsAfter = rowsAfter as unknown as TRow[] | undefined;\n const rowsBeforeLength = typedRowsBefore?.length ?? 0;\n const rowsAfterLength = typedRowsAfter?.length ?? 0;\n const rowsBeforeSize = Math.min(rowsBeforeLength, halfPageSize);\n const rowsAfterSize = Math.min(rowsAfterLength, halfPageSize - 1);\n\n const firstRowIndex = anchorIndex - rowsBeforeSize;\n\n return {\n rowAt: (index: number) => {\n if (index === anchorIndex) {\n return typedRow;\n }\n if (index > anchorIndex) {\n if (typedRowsAfter === undefined) {\n return undefined;\n }\n const i = index - anchorIndex - 1;\n if (i >= rowsAfterSize) {\n return undefined;\n }\n return typedRowsAfter[i];\n }\n assert(index < anchorIndex);\n if (typedRowsBefore === undefined) {\n return undefined;\n }\n const i = anchorIndex - index - 1;\n if (i >= rowsBeforeSize) {\n return undefined;\n }\n return typedRowsBefore[i];\n },\n rowsLength: rowsBeforeSize + rowsAfterSize + (typedRow ? 1 : 0),\n complete:\n completeRow &&\n (typedRow === undefined || (completeBefore && completeAfter)),\n rowsEmpty:\n typedRow === undefined || (rowsBeforeSize === 0 && rowsAfterSize === 0),\n atStart: completeBefore && rowsBeforeLength <= halfPageSize,\n atEnd: completeAfter && rowsAfterLength <= halfPageSize - 1,\n firstRowIndex: firstRowIndex,\n permalinkNotFound,\n };\n }\n\n kind satisfies 'forward' | 'backward';\n\n const {startRow: start = null} = anchor;\n\n const q = getPageQuery(pageSize + 1, start, kind);\n\n const [rows, result] = useQuery(q, options);\n // not used but needed to follow rules of hooks\n void useQuery(null, options);\n void useQuery(null, options);\n\n const typedRows = rows as unknown as TRow[];\n const complete = result.type === 'complete';\n const hasMoreRows = typedRows.length > pageSize;\n const rowsLength = hasMoreRows ? pageSize : typedRows.length;\n const rowsEmpty = typedRows.length === 0;\n\n if (kind === 'forward') {\n return {\n rowAt: (index: number) =>\n index - anchorIndex < rowsLength\n ? typedRows[index - anchorIndex]\n : undefined,\n rowsLength: rowsLength,\n complete,\n rowsEmpty: rowsEmpty,\n atStart: start === null || anchorIndex === 0,\n atEnd: complete && !hasMoreRows,\n firstRowIndex: anchorIndex,\n permalinkNotFound,\n };\n }\n\n kind satisfies 'backward';\n assert(start !== null);\n\n return {\n rowAt: (index: number) => {\n if (index >= anchorIndex) {\n return undefined;\n }\n const i = anchorIndex - index - 1;\n if (i < 0 || i >= rowsLength) {\n return undefined;\n }\n return typedRows[i];\n },\n rowsLength: rowsLength,\n complete,\n rowsEmpty: rowsEmpty,\n atStart: complete && !hasMoreRows,\n atEnd: false,\n firstRowIndex: anchorIndex - rowsLength,\n permalinkNotFound,\n };\n}\n"],"names":["start","i"],"mappings":";;AA8CO,SAAS,QAAyB;AAAA,EACvC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAiBE;AACA,QAAM,EAAC,MAAM,OAAO,YAAA,IAAe;AACnC,MAAI,oBAAoB;AAExB,MAAI,SAAS,aAAa;AACxB,UAAM,EAAC,OAAM;AACb,WAAO,EAAE;AACT,WAAO,WAAW,MAAM,CAAC;AAEzB,UAAM,eAAe,WAAW;AAEhC,UAAM,QAAQ,eAAe,EAAE;AAE/B,UAAM,CAAC,KAAK,SAAS,IAAI,SAAS,OAAO,OAAO;AAChD,UAAM,cAAc,UAAU,SAAS;AAEvC,UAAM,WAAW;AAGjB,QAAI,eAAe,aAAa,QAAW;AAEzC,WAAK,SAAS,MAAM,OAAO;AAC3B,WAAK,SAAS,MAAM,OAAO;AAE3B,aAAO;AAAA,QACL,OAAO,MAAM;AAAA,QACb,YAAY;AAAA,QACZ,UAAU;AAAA,QACV,WAAW;AAAA,QACX,SAAS;AAAA,QACT,OAAO;AAAA,QACP,eAAe;AAAA,QACf,mBAAmB;AAAA,MAAA;AAAA,IAEvB;AAEA,UAAMA,SAAQ,YAAY,WAAW,QAAQ;AAE7C,UAAM,UAAUA,UAAS,aAAa,eAAe,GAAGA,QAAO,UAAU;AACzE,UAAM,SAASA,UAAS,aAAa,cAAcA,QAAO,SAAS;AAEnE,UAAM,CAAC,YAAY,YAAY,IAAI,SAAS,SAAS,OAAO;AAC5D,UAAM,CAAC,WAAW,WAAW,IAAI,SAAS,QAAQ,OAAO;AACzD,UAAM,iBAAiB,aAAa,SAAS;AAC7C,UAAM,gBAAgB,YAAY,SAAS;AAE3C,UAAM,kBAAkB;AACxB,UAAM,iBAAiB;AACvB,UAAM,mBAAmB,iBAAiB,UAAU;AACpD,UAAM,kBAAkB,gBAAgB,UAAU;AAClD,UAAM,iBAAiB,KAAK,IAAI,kBAAkB,YAAY;AAC9D,UAAM,gBAAgB,KAAK,IAAI,iBAAiB,eAAe,CAAC;AAEhE,UAAM,gBAAgB,cAAc;AAEpC,WAAO;AAAA,MACL,OAAO,CAAC,UAAkB;AACxB,YAAI,UAAU,aAAa;AACzB,iBAAO;AAAA,QACT;AACA,YAAI,QAAQ,aAAa;AACvB,cAAI,mBAAmB,QAAW;AAChC,mBAAO;AAAA,UACT;AACA,gBAAMC,KAAI,QAAQ,cAAc;AAChC,cAAIA,MAAK,eAAe;AACtB,mBAAO;AAAA,UACT;AACA,iBAAO,eAAeA,EAAC;AAAA,QACzB;AACA,eAAO,QAAQ,WAAW;AAC1B,YAAI,oBAAoB,QAAW;AACjC,iBAAO;AAAA,QACT;AACA,cAAM,IAAI,cAAc,QAAQ;AAChC,YAAI,KAAK,gBAAgB;AACvB,iBAAO;AAAA,QACT;AACA,eAAO,gBAAgB,CAAC;AAAA,MAC1B;AAAA,MACA,YAAY,iBAAiB,iBAAiB,WAAW,IAAI;AAAA,MAC7D,UACE,gBACC,aAAa,UAAc,kBAAkB;AAAA,MAChD,WACE,aAAa,UAAc,mBAAmB,KAAK,kBAAkB;AAAA,MACvE,SAAS,kBAAkB,oBAAoB;AAAA,MAC/C,OAAO,iBAAiB,mBAAmB,eAAe;AAAA,MAC1D;AAAA,MACA;AAAA,IAAA;AAAA,EAEJ;AAIA,QAAM,EAAC,UAAU,QAAQ,KAAA,IAAQ;AAEjC,QAAM,IAAI,aAAa,WAAW,GAAG,OAAO,IAAI;AAEhD,QAAM,CAAC,MAAM,MAAM,IAAI,SAAS,GAAG,OAAO;AAE1C,OAAK,SAAS,MAAM,OAAO;AAC3B,OAAK,SAAS,MAAM,OAAO;AAE3B,QAAM,YAAY;AAClB,QAAM,WAAW,OAAO,SAAS;AACjC,QAAM,cAAc,UAAU,SAAS;AACvC,QAAM,aAAa,cAAc,WAAW,UAAU;AACtD,QAAM,YAAY,UAAU,WAAW;AAEvC,MAAI,SAAS,WAAW;AACtB,WAAO;AAAA,MACL,OAAO,CAAC,UACN,QAAQ,cAAc,aAClB,UAAU,QAAQ,WAAW,IAC7B;AAAA,MACN;AAAA,MACA;AAAA,MACA;AAAA,MACA,SAAS,UAAU,QAAQ,gBAAgB;AAAA,MAC3C,OAAO,YAAY,CAAC;AAAA,MACpB,eAAe;AAAA,MACf;AAAA,IAAA;AAAA,EAEJ;AAGA,SAAO,UAAU,IAAI;AAErB,SAAO;AAAA,IACL,OAAO,CAAC,UAAkB;AACxB,UAAI,SAAS,aAAa;AACxB,eAAO;AAAA,MACT;AACA,YAAM,IAAI,cAAc,QAAQ;AAChC,UAAI,IAAI,KAAK,KAAK,YAAY;AAC5B,eAAO;AAAA,MACT;AACA,aAAO,UAAU,CAAC;AAAA,IACpB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,SAAS,YAAY,CAAC;AAAA,IACtB,OAAO;AAAA,IACP,eAAe,cAAc;AAAA,IAC7B;AAAA,EAAA;AAEJ;"}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { useVirtualizer, type Virtualizer } from '@tanstack/react-virtual';
|
|
2
|
+
import { type Key } from 'react';
|
|
3
|
+
import type { UseQueryOptions } from './use-query.tsx';
|
|
4
|
+
import { type Anchor, type GetPageQuery, type GetSingleQuery } from './use-rows.ts';
|
|
5
|
+
/**
|
|
6
|
+
* State object that captures the virtualizer's scroll position and pagination state.
|
|
7
|
+
* Used for persisting and restoring the virtualizer state across navigation or page reloads.
|
|
8
|
+
*
|
|
9
|
+
* @typeParam TStartRow - The type of the start row data used for pagination anchoring
|
|
10
|
+
*/
|
|
11
|
+
export type PermalinkHistoryState<TStartRow> = Readonly<{
|
|
12
|
+
/** The anchor point for pagination (includes position, direction, and start row data) */
|
|
13
|
+
anchor: Anchor<TStartRow>;
|
|
14
|
+
/** The scroll position in pixels from the top of the scrollable container */
|
|
15
|
+
scrollTop: number;
|
|
16
|
+
/** The estimated total number of rows in the list */
|
|
17
|
+
estimatedTotal: number;
|
|
18
|
+
/** Whether the virtualizer has reached the start of the list */
|
|
19
|
+
hasReachedStart: boolean;
|
|
20
|
+
/** Whether the virtualizer has reached the end of the list */
|
|
21
|
+
hasReachedEnd: boolean;
|
|
22
|
+
}>;
|
|
23
|
+
type TanstackUseVirtualizerOptions<TScrollElement extends Element, TItemElement extends Element> = Parameters<typeof useVirtualizer<TScrollElement, TItemElement>>[0];
|
|
24
|
+
/**
|
|
25
|
+
* Options for configuring the Zero virtualizer.
|
|
26
|
+
* Extends Tanstack Virtual's options with Zero-specific pagination and state management.
|
|
27
|
+
*
|
|
28
|
+
* @typeParam TScrollElement - The type of the scrollable container element
|
|
29
|
+
* @typeParam TItemElement - The type of the individual item elements
|
|
30
|
+
* @typeParam TListContextParams - The type of parameters that define the list's query context
|
|
31
|
+
* @typeParam TRow - The type of row data returned from queries
|
|
32
|
+
* @typeParam TStartRow - The type of data needed to anchor pagination (typically a subset of TRow)
|
|
33
|
+
*/
|
|
34
|
+
export type UseZeroVirtualizerOptions<TScrollElement extends Element, TItemElement extends Element, TListContextParams, TRow, TStartRow> = Omit<TanstackUseVirtualizerOptions<TScrollElement, TItemElement>, 'count' | 'initialOffset' | 'horizontal'> & {
|
|
35
|
+
/** Parameters that define the list's query context (filters, sort order, etc.) */
|
|
36
|
+
listContextParams: TListContextParams;
|
|
37
|
+
/** Optional ID to highlight/scroll to a specific row (permalink functionality) */
|
|
38
|
+
permalinkID?: string | null | undefined;
|
|
39
|
+
/** Function that returns a query for fetching a page of rows */
|
|
40
|
+
getPageQuery: GetPageQuery<TRow, TStartRow>;
|
|
41
|
+
/** Function that returns a query for fetching a single row by ID */
|
|
42
|
+
getSingleQuery: GetSingleQuery<TRow>;
|
|
43
|
+
/** Optional query options */
|
|
44
|
+
options?: UseQueryOptions | undefined;
|
|
45
|
+
/** Function to extract the start row data from a full row (for pagination anchoring) */
|
|
46
|
+
toStartRow: (row: TRow) => TStartRow;
|
|
47
|
+
/**
|
|
48
|
+
* Function to extract a unique key from a row, used for stable item identification.
|
|
49
|
+
* If provided, this will override {@linkcode TanstackUseVirtualizerOptions.getItemKey}
|
|
50
|
+
*/
|
|
51
|
+
getRowKey?: ((row: TRow) => Key) | undefined;
|
|
52
|
+
/**
|
|
53
|
+
* Optional current permalink state for restoring virtualizer position.
|
|
54
|
+
* If provided along with `onPermalinkStateChange`, enables state persistence.
|
|
55
|
+
* If not provided, virtualizer operates in uncontrolled mode.
|
|
56
|
+
*/
|
|
57
|
+
permalinkState?: PermalinkHistoryState<TStartRow> | null | undefined;
|
|
58
|
+
/**
|
|
59
|
+
* Optional callback invoked when the virtualizer state changes.
|
|
60
|
+
* Use this to persist state (e.g., to browser history, local storage, etc.).
|
|
61
|
+
* Called with the new state approximately 100ms after scroll/pagination changes.
|
|
62
|
+
*/
|
|
63
|
+
onPermalinkStateChange?: (state: PermalinkHistoryState<TStartRow>) => void;
|
|
64
|
+
};
|
|
65
|
+
/**
|
|
66
|
+
* Result object returned by the useZeroVirtualizer hook.
|
|
67
|
+
*
|
|
68
|
+
* @typeParam TScrollElement - The type of the scrollable container element
|
|
69
|
+
* @typeParam TItemElement - The type of the individual item elements
|
|
70
|
+
* @typeParam TRow - The type of row data returned from queries
|
|
71
|
+
*/
|
|
72
|
+
export type ZeroVirtualizerResult<TScrollElement extends Element, TItemElement extends Element, TRow> = {
|
|
73
|
+
/** The Tanstack Virtual virtualizer instance for rendering virtual items */
|
|
74
|
+
virtualizer: Virtualizer<TScrollElement, TItemElement>;
|
|
75
|
+
/** Function to get the row data at a specific index, or undefined if not loaded */
|
|
76
|
+
rowAt: (index: number) => TRow | undefined;
|
|
77
|
+
/** Whether all initially requested data has finished loading */
|
|
78
|
+
complete: boolean;
|
|
79
|
+
/** Whether the list is empty (no rows exist matching the query) */
|
|
80
|
+
rowsEmpty: boolean;
|
|
81
|
+
/** Whether the specified permalinkID was not found in the query results */
|
|
82
|
+
permalinkNotFound: boolean;
|
|
83
|
+
/** Estimated total number of rows (may be inexact until both ends are reached) */
|
|
84
|
+
estimatedTotal: number;
|
|
85
|
+
/** Exact total number of rows, or undefined if not yet known (requires reaching both ends) */
|
|
86
|
+
total: number | undefined;
|
|
87
|
+
};
|
|
88
|
+
/**
|
|
89
|
+
* Hook that creates a virtualized list with bidirectional pagination and state persistence.
|
|
90
|
+
*
|
|
91
|
+
* This hook combines Tanstack Virtual's efficient virtualization with Zero's reactive queries
|
|
92
|
+
* to create infinitely scrolling lists that load data on demand. It supports:
|
|
93
|
+
* - Bidirectional scrolling (load more items at top or bottom)
|
|
94
|
+
* - Permalink functionality (jump to and highlight specific items)
|
|
95
|
+
* - State persistence (restore scroll position across navigation)
|
|
96
|
+
* - Dynamic page sizing based on viewport
|
|
97
|
+
*
|
|
98
|
+
* @typeParam TScrollElement - The type of the scrollable container element
|
|
99
|
+
* @typeParam TItemElement - The type of the individual item elements
|
|
100
|
+
* @typeParam TListContextParams - The type of parameters that define the list's query context
|
|
101
|
+
* @typeParam TRow - The type of row data returned from queries
|
|
102
|
+
* @typeParam TStartRow - The type of data needed to anchor pagination
|
|
103
|
+
*
|
|
104
|
+
* @param options - Configuration options including query functions, sizing, and state management
|
|
105
|
+
* @returns An object containing the virtualizer instance, row accessor, and state flags
|
|
106
|
+
*
|
|
107
|
+
* @example
|
|
108
|
+
* ```tsx
|
|
109
|
+
* const {virtualizer, rowAt, complete} = useZeroVirtualizer({
|
|
110
|
+
* estimateSize: () => 50,
|
|
111
|
+
* getScrollElement: () => scrollRef.current,
|
|
112
|
+
* listContextParams: {projectId: 'abc'},
|
|
113
|
+
* getPageQuery: (limit, start, dir) => z.query.issues.where(...).limit(limit),
|
|
114
|
+
* getSingleQuery: (id) => z.query.issues.where('id', id),
|
|
115
|
+
* toStartRow: (row) => ({id: row.id, created: row.created}),
|
|
116
|
+
* });
|
|
117
|
+
* ```
|
|
118
|
+
*/
|
|
119
|
+
export declare function useZeroVirtualizer<TScrollElement extends Element, TItemElement extends Element, TListContextParams, TRow, TStartRow>({ estimateSize, overscan, // Virtualizer defaults to 1.
|
|
120
|
+
getScrollElement, getItemKey, listContextParams, permalinkID, getPageQuery, getSingleQuery, options, toStartRow, getRowKey, permalinkState, onPermalinkStateChange, ...restVirtualizerOptions }: UseZeroVirtualizerOptions<TScrollElement, TItemElement, TListContextParams, TRow, TStartRow>): ZeroVirtualizerResult<TScrollElement, TItemElement, TRow>;
|
|
121
|
+
export {};
|
|
122
|
+
//# sourceMappingURL=use-zero-virtualizer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-zero-virtualizer.d.ts","sourceRoot":"","sources":["../../../../zero-react/src/use-zero-virtualizer.ts"],"names":[],"mappings":"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"}
|