@nteract/sift 0.0.1 → 0.5.5-nightly.38500811922
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 +100 -7
- package/docs/embedding-guide.md +185 -0
- package/lib/LICENSE +28 -0
- package/lib/THIRD_PARTY_NOTICES.md +3079 -0
- package/lib/handoff.css +37 -0
- package/lib/handoff.js +26 -0
- package/lib/index.js +3455 -0
- package/lib/style.css +2 -0
- package/lib/types/packages/sift/src/auto-width.d.ts +13 -0
- package/lib/types/packages/sift/src/column-menu.d.ts +8 -0
- package/lib/types/packages/sift/src/components/column-context-menu.d.ts +32 -0
- package/lib/types/packages/sift/src/components/image-viewer.d.ts +16 -0
- package/lib/types/packages/sift/src/events.d.ts +1 -0
- package/lib/types/packages/sift/src/file-data.d.ts +36 -0
- package/lib/types/packages/sift/src/filter-schema.d.ts +100 -0
- package/lib/types/packages/sift/src/handoff.d.ts +11 -0
- package/lib/types/packages/sift/src/index.d.ts +28 -0
- package/lib/types/packages/sift/src/parquet-features.d.ts +15 -0
- package/lib/types/packages/sift/src/predicate.d.ts +199 -0
- package/lib/types/packages/sift/src/react.d.ts +97 -0
- package/lib/types/packages/sift/src/sparkline.d.ts +25 -0
- package/lib/types/packages/sift/src/table-response.d.ts +5 -0
- package/lib/types/packages/sift/src/table.d.ts +175 -0
- package/lib/types/packages/sift/src/wasm-summaries.d.ts +3 -0
- package/lib/types/packages/sift/src/wasm-table-data.d.ts +19 -0
- package/lib/types/src/components/ui/button.d.ts +11 -0
- package/lib/types/src/components/ui/popover.d.ts +7 -0
- package/lib/types/src/lib/utils.d.ts +2 -0
- package/lib/wasm/sift_wasm.d.ts +382 -0
- package/lib/wasm/sift_wasm.js +1398 -0
- package/lib/wasm/sift_wasm_bg.wasm +0 -0
- package/package.json +73 -5
package/README.md
CHANGED
|
@@ -1,13 +1,106 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Sift
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
publish through npm trusted publishing. It contains no code.
|
|
3
|
+
Crossfilter data explorer. [Pretext](https://github.com/chenglou/pretext) × [Arrow](https://arrow.apache.org/).
|
|
5
4
|
|
|
6
|
-
|
|
5
|
+

|
|
6
|
+
|
|
7
|
+
Published as [`@nteract/sift`](https://www.npmjs.com/package/@nteract/sift). Try it at [rgbkrk.github.io/sift](https://rgbkrk.github.io/sift/).
|
|
8
|
+
|
|
9
|
+
## Features
|
|
10
|
+
|
|
11
|
+
- **Local CSV/TSV, Parquet, and Arrow IPC streams** — bounded file adapters, no notebook or server needed
|
|
12
|
+
- **Stream hosted Arrow IPC or load Parquet URLs** — WASM-native
|
|
13
|
+
- **Crossfilter** — brush histograms to filter, all other summaries update instantly
|
|
14
|
+
- **Column profiling** — null%, distinct count shown inline in headers
|
|
15
|
+
- **Smart summaries** — histograms, category bars, boolean ratios, binary value bars, searchable popovers. Adapts visualization to column type × cardinality.
|
|
16
|
+
- **Column type casting** — right-click to treat text as numbers, dates, booleans — with full undo
|
|
17
|
+
- **Smart column detection** — pandas index columns, HuggingFace ClassLabel features
|
|
18
|
+
- **Virtual scroll** — 100k+ rows at 120fps. Pretext layout at 0.0002ms/cell.
|
|
19
|
+
- **Odometer status bar** — rolling digit animation for row count, visible range, FPS
|
|
20
|
+
- **Multi-instance** — embed multiple tables on one page (notebook demo included)
|
|
21
|
+
- **RxJS streaming** — cancellable dataset loading via `switchMap`
|
|
22
|
+
- **Mobile** — tap any row for a detail sheet with all column values
|
|
23
|
+
- **Dark mode**, keyboard nav, pinned columns, ARIA grid
|
|
24
|
+
- **8 HuggingFace datasets** built into the demo
|
|
25
|
+
|
|
26
|
+
## Quick start
|
|
27
|
+
|
|
28
|
+
From the nteract repository root:
|
|
29
|
+
|
|
30
|
+
```sh
|
|
31
|
+
pnpm install --frozen-lockfile
|
|
32
|
+
cargo xtask wasm sift --skip-renderer-plugins
|
|
33
|
+
pnpm --dir packages/sift dev
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Use as a library
|
|
37
|
+
|
|
38
|
+
The package ships JavaScript, compiled CSS, TypeScript declarations, and WASM,
|
|
39
|
+
with notices for the Rust crates compiled into the WASM in
|
|
40
|
+
`lib/THIRD_PARTY_NOTICES.md`. React and React DOM are peer dependencies; no
|
|
41
|
+
notebook, kernel, or daemon is needed. Tested with React 19. Types resolve
|
|
42
|
+
under TypeScript's `bundler` module resolution (Vite, webpack, esbuild).
|
|
43
|
+
|
|
44
|
+
```tsx
|
|
45
|
+
import { loadTableFile, SiftTable } from '@nteract/sift'
|
|
46
|
+
import '@nteract/sift/style.css'
|
|
47
|
+
|
|
48
|
+
const load = useCallback(() => loadTableFile(bytes), [bytes]) // Parquet or Arrow IPC
|
|
49
|
+
<SiftTable source={{ kind: 'loader', load }} style={{ height: 600 }} />
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Files load whole or fail; defaults are 16 MiB, 100,000 rows, and 256 columns.
|
|
53
|
+
CSV and TSV go through [`@nteract/sift-csv`](../sift-csv), a separate WASM
|
|
54
|
+
module that returns Arrow IPC bytes for `loadTableFile`, so apps that only open
|
|
55
|
+
Parquet or Arrow do not carry the CSV parser.
|
|
56
|
+
|
|
57
|
+
See the [embedding guide](docs/embedding-guide.md) for WASM asset setup, memory
|
|
58
|
+
limits, lifecycle, styling, and host viewer/editor integration.
|
|
59
|
+
|
|
60
|
+
## Engine API
|
|
61
|
+
|
|
62
|
+
```ts
|
|
63
|
+
engine.setSort('age', 'desc')
|
|
64
|
+
engine.setFilter(colIndex, { kind: 'range', min: 18, max: 65 })
|
|
65
|
+
engine.clearAllFilters()
|
|
66
|
+
|
|
67
|
+
// Inspect the current sort, filters, and counts.
|
|
68
|
+
const state = engine.getState()
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
See [`docs/embedding-guide.md`](docs/embedding-guide.md) for the full API.
|
|
72
|
+
|
|
73
|
+
## WASM compute (`sift-wasm`)
|
|
74
|
+
|
|
75
|
+
Rust crate wrapping arrow-rs. Parquet decoding, sort, histograms, value counts, string search, column casting — all in one WASM binary. Data lives in WASM memory; JS holds handles.
|
|
7
76
|
|
|
8
77
|
```sh
|
|
9
|
-
|
|
78
|
+
cargo xtask wasm sift --skip-renderer-plugins
|
|
10
79
|
```
|
|
11
80
|
|
|
12
|
-
|
|
13
|
-
|
|
81
|
+
## Stack
|
|
82
|
+
|
|
83
|
+
| Layer | What |
|
|
84
|
+
|-------|------|
|
|
85
|
+
| Layout | [@chenglou/pretext](https://github.com/chenglou/pretext) — DOM-free text measurement |
|
|
86
|
+
| Data | [Apache Arrow](https://arrow.apache.org/) — columnar, streamed via RecordBatchReader |
|
|
87
|
+
| Compute | [sift-wasm](../../crates/sift-wasm/) — arrow-rs WASM kernels |
|
|
88
|
+
| Reactivity | [RxJS](https://rxjs.dev/) — streaming pipeline |
|
|
89
|
+
| Charts | SVG histograms + HTML bars |
|
|
90
|
+
|
|
91
|
+
## Development
|
|
92
|
+
|
|
93
|
+
Run from the repository root after the setup above:
|
|
94
|
+
|
|
95
|
+
```sh
|
|
96
|
+
pnpm --dir packages/sift test # Vitest unit tests
|
|
97
|
+
pnpm --dir packages/sift test:e2e # Playwright E2E
|
|
98
|
+
pnpm --dir packages/sift build # production build (demo)
|
|
99
|
+
pnpm --dir packages/sift build:lib # lib/ (JS, CSS, types, WASM)
|
|
100
|
+
pnpm --dir packages/sift test:package # packed consumer outside the workspace
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## Demo pages
|
|
104
|
+
|
|
105
|
+
- `/` — main demo with dataset picker
|
|
106
|
+
- `/notebook.html` — multi-table notebook simulation
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
# Embedding Sift
|
|
2
|
+
|
|
3
|
+
`@nteract/sift` is a browser table viewer with compiled JavaScript, CSS, TypeScript
|
|
4
|
+
interfaces, and a matching WebAssembly decoder. It does not require a notebook,
|
|
5
|
+
kernel, daemon, Tauri, Electron, or an nteract runtime connection. React and React
|
|
6
|
+
DOM are required even for the imperative API because column controls use React.
|
|
7
|
+
|
|
8
|
+
## Install and assets
|
|
9
|
+
|
|
10
|
+
```sh
|
|
11
|
+
npm install @nteract/sift react react-dom
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
```tsx
|
|
15
|
+
import { SiftTable, setWasmUrl } from '@nteract/sift'
|
|
16
|
+
import '@nteract/sift/style.css'
|
|
17
|
+
// Vite example: emit the packaged binary through the host's asset pipeline.
|
|
18
|
+
import wasmUrl from '@nteract/sift/sift.wasm?url'
|
|
19
|
+
|
|
20
|
+
setWasmUrl(wasmUrl) // Configure once, before the first binary table loads.
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Other bundlers can copy `@nteract/sift/sift.wasm` into their local assets and pass
|
|
24
|
+
its served URL to `setWasmUrl`. Without an override, the shipped wasm-bindgen glue
|
|
25
|
+
resolves `sift_wasm_bg.wasm` relative to itself; preserve that layout when serving
|
|
26
|
+
unbundled modules. Serve the binary with `application/wasm`. Keep the JavaScript
|
|
27
|
+
and WASM from the same package version. No CDN or data upload is required.
|
|
28
|
+
|
|
29
|
+
The host owns file access and its existing sandbox/CSP policy. In an Electron
|
|
30
|
+
app, read selected files through the approved main/preload bridge and pass text
|
|
31
|
+
or bytes to the renderer; Sift does not need Node integration or filesystem
|
|
32
|
+
access. The package's URL API explicitly fetches URLs supplied by the host.
|
|
33
|
+
|
|
34
|
+
## Local CSV and TSV
|
|
35
|
+
|
|
36
|
+
CSV parsing is a separate package, `@nteract/sift-csv`, so apps that only open
|
|
37
|
+
Parquet or Arrow do not carry it. It converts text or bytes to an Arrow IPC
|
|
38
|
+
stream that `loadTableFile` accepts:
|
|
39
|
+
|
|
40
|
+
```tsx
|
|
41
|
+
import { csvToArrowIpc } from '@nteract/sift-csv'
|
|
42
|
+
import { loadTableFile, SiftTable } from '@nteract/sift'
|
|
43
|
+
|
|
44
|
+
const load = useCallback(async () => {
|
|
45
|
+
const ipc = await csvToArrowIpc(text, { delimiter: '\t' })
|
|
46
|
+
return loadTableFile(ipc, { format: 'arrow-ipc' })
|
|
47
|
+
}, [text])
|
|
48
|
+
|
|
49
|
+
<SiftTable source={{ kind: 'loader', load }} style={{ height: 600 }} />
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Type inference reads the whole file. Booleans, Int64, Float64 (including
|
|
53
|
+
exponents), ISO dates, and ISO timestamps are detected; a column with mixed
|
|
54
|
+
shapes stays text. Empty fields are null in every type. Malformed quoting and
|
|
55
|
+
ragged rows reject with the reason; nothing is truncated or sampled. The host
|
|
56
|
+
owns text decoding and delimiter choice; there is no guessing. Defaults are
|
|
57
|
+
16 MiB of input, 100,000 rows, and 256 columns, each an option. See the
|
|
58
|
+
package README for the WASM asset setup.
|
|
59
|
+
|
|
60
|
+
## Local Parquet and Arrow
|
|
61
|
+
|
|
62
|
+
```ts
|
|
63
|
+
import { loadTableFile, createTable } from '@nteract/sift'
|
|
64
|
+
|
|
65
|
+
const data = await loadTableFile(bytes) // Uint8Array; detects Parquet magic.
|
|
66
|
+
const engine = createTable(container, data)
|
|
67
|
+
// When the document closes or changes:
|
|
68
|
+
engine.destroy() // Also disposes the data's WASM store.
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
For React, use a memoized loader returning fresh data for every invocation.
|
|
72
|
+
This also supports React StrictMode's setup/cleanup replay:
|
|
73
|
+
|
|
74
|
+
```tsx
|
|
75
|
+
import { useCallback } from 'react'
|
|
76
|
+
import { loadTableFile, SiftTable } from '@nteract/sift'
|
|
77
|
+
|
|
78
|
+
function ParquetView({ bytes }: { bytes: Uint8Array }) {
|
|
79
|
+
const load = useCallback(() => loadTableFile(bytes), [bytes])
|
|
80
|
+
return <SiftTable source={{ kind: 'loader', load }} style={{ height: 600 }} />
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Keep the bytes snapshot stable until the file changes. Do not capture and return
|
|
85
|
+
one previously loaded disposable table from the callback.
|
|
86
|
+
|
|
87
|
+
`loadTableFile` supports Parquet and uncompressed Arrow IPC streams. The optional
|
|
88
|
+
`format` is `'parquet'` or `'arrow-ipc'`. CSV and TSV go through `@nteract/sift-csv`. Arrow file
|
|
89
|
+
containers and compressed IPC streams are not supported by this path.
|
|
90
|
+
|
|
91
|
+
Binary input defaults to 16 MiB, 100,000 rows, 256 columns, and 128 MiB of
|
|
92
|
+
retained Arrow memory (`maxBytes`, `maxRows`, `maxColumns`, `maxDecodedBytes`).
|
|
93
|
+
Rows and columns are checked from file metadata before decoding. Retained memory
|
|
94
|
+
is checked after each decoded batch, and the decoder can allocate one batch past
|
|
95
|
+
the limit before that check runs. These limits are meant for files you chose to
|
|
96
|
+
open, not a sandbox for hostile input: a crafted Parquet file can make one batch
|
|
97
|
+
large. If you load untrusted files, do it in a Worker you can terminate.
|
|
98
|
+
|
|
99
|
+
This API loads a complete file. Virtual scrolling bounds rendered DOM, not the
|
|
100
|
+
dataset: sorting, filtering, and summaries cover every accepted row. There is no
|
|
101
|
+
paging or sampled preview.
|
|
102
|
+
|
|
103
|
+
Lists, structs, and maps display as text. Known image structures have dedicated
|
|
104
|
+
rendering.
|
|
105
|
+
|
|
106
|
+
## Lifecycle and host controls
|
|
107
|
+
|
|
108
|
+
A `TableData` instance returned by `loadTableFile` owns one WASM store. The React
|
|
109
|
+
loader source creates a fresh store for each setup and discards stale completions;
|
|
110
|
+
the mounted engine disposes the store on teardown. Avoid passing preloaded binary
|
|
111
|
+
data directly to the React `data` prop, because effect replay would reuse a freed
|
|
112
|
+
store. For the imperative API, pass each result to one `createTable` instance. If
|
|
113
|
+
an imperative load is stale or never mounted, call `data.dispose?.()`, using an
|
|
114
|
+
activation token to recognize results completed after switching or closing files.
|
|
115
|
+
Reopen/reload creates fresh data. Do not share disposable data between tables.
|
|
116
|
+
|
|
117
|
+
Sift is a read-only exploration surface. Sorting, filtering, and type casts do
|
|
118
|
+
not rewrite the file. Keep editor text and dirty state in the host; a viewer/editor
|
|
119
|
+
toggle should derive its preview from the current text buffer and preserve edits
|
|
120
|
+
on parse errors or mode changes. Save, Save As/export, reveal-in-folder, file
|
|
121
|
+
watching, dirty-file conflict handling, and loading/error messages remain host
|
|
122
|
+
responsibilities. Parquet can use a view-only mode.
|
|
123
|
+
|
|
124
|
+
For already hosted data, `<SiftTable url="/data.arrow" />` and
|
|
125
|
+
`<SiftTable url="/data.parquet" />` remain available. The URL/manifest paths have
|
|
126
|
+
different loading behavior and do not inherit `loadTableFile` admission limits.
|
|
127
|
+
A sampled Arrow manifest must include its `summary.sampled` and included/total
|
|
128
|
+
row metadata; its sorting, filtering, and summaries cover only the supplied rows.
|
|
129
|
+
|
|
130
|
+
## Interaction and appearance
|
|
131
|
+
|
|
132
|
+
```ts
|
|
133
|
+
engine.setSort('age', 'desc')
|
|
134
|
+
engine.setFilter(0, { kind: 'range', min: 18, max: 65 })
|
|
135
|
+
engine.clearAllFilters()
|
|
136
|
+
const state = engine.getState()
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
The container needs a defined height. The table supplies keyboard navigation and
|
|
140
|
+
ARIA grid semantics.
|
|
141
|
+
|
|
142
|
+
## Styling
|
|
143
|
+
|
|
144
|
+
`style.css` is compiled and self-contained. It writes nothing to `:root`,
|
|
145
|
+
`html`, or `body` and ships no document-wide CSS reset, so it can load into a host document
|
|
146
|
+
next to the host's own stylesheet. Every rule is keyed on `.sift-root`, which
|
|
147
|
+
Sift puts on the table container and on each element it appends to `<body>`
|
|
148
|
+
(popovers, the column menu, the row detail sheet, the image viewer).
|
|
149
|
+
|
|
150
|
+
Dark mode follows the host: put `.dark` or `data-theme="dark"` on `<html>` or
|
|
151
|
+
`<body>`, so body-mounted overlays receive the same theme.
|
|
152
|
+
|
|
153
|
+
Sift reads eight colors, a font, and a radius. Set them on `<html>` or `<body>`. A table-local wrapper does not theme overlays
|
|
154
|
+
that are portaled to `<body>`:
|
|
155
|
+
|
|
156
|
+
```css
|
|
157
|
+
:root {
|
|
158
|
+
--sift-color-bg: #fff; /* table background */
|
|
159
|
+
--sift-color-panel: #fff; /* header, popovers, menus, sheets */
|
|
160
|
+
--sift-color-ink: #111; /* text */
|
|
161
|
+
--sift-color-muted: #666; /* secondary text, null markers */
|
|
162
|
+
--sift-color-rule: #e5e5e5; /* borders and grid lines */
|
|
163
|
+
--sift-color-accent: #2563eb; /* histogram bars, selection, focus ring */
|
|
164
|
+
--sift-color-true: #22c55e; /* boolean true */
|
|
165
|
+
--sift-color-false: #ef4444; /* boolean false */
|
|
166
|
+
--sift-font-family: Inter, system-ui, sans-serif;
|
|
167
|
+
--sift-radius-base: 0.5rem;
|
|
168
|
+
}
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
Every other color (row stripes, scrollbars, badges, skeletons) is derived from
|
|
172
|
+
these with `color-mix()`, so they follow light and dark automatically.
|
|
173
|
+
|
|
174
|
+
The neutrals fall back to the shadcn token names when the host defines them:
|
|
175
|
+
`--background`, `--card`, `--foreground`, `--muted-foreground`, `--border`, and
|
|
176
|
+
`--radius`. A shadcn app gets Sift in its own palette without setting anything.
|
|
177
|
+
Accent and boolean colors keep Sift's defaults unless set, since a shadcn
|
|
178
|
+
`--primary` is a button color and often near-black.
|
|
179
|
+
|
|
180
|
+
## Notices
|
|
181
|
+
|
|
182
|
+
`lib/THIRD_PARTY_NOTICES.md` lists the Rust crates compiled into the WASM with
|
|
183
|
+
their license texts and NOTICE files. Ship it with any app that redistributes
|
|
184
|
+
Sift. Building and verifying the package from source is covered in the
|
|
185
|
+
package's `AGENTS.md`.
|
package/lib/LICENSE
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
BSD 3-Clause License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024, runtimed
|
|
4
|
+
|
|
5
|
+
Redistribution and use in source and binary forms, with or without
|
|
6
|
+
modification, are permitted provided that the following conditions are met:
|
|
7
|
+
|
|
8
|
+
1. Redistributions of source code must retain the above copyright notice, this
|
|
9
|
+
list of conditions and the following disclaimer.
|
|
10
|
+
|
|
11
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
12
|
+
this list of conditions and the following disclaimer in the documentation
|
|
13
|
+
and/or other materials provided with the distribution.
|
|
14
|
+
|
|
15
|
+
3. Neither the name of the copyright holder nor the names of its
|
|
16
|
+
contributors may be used to endorse or promote products derived from
|
|
17
|
+
this software without specific prior written permission.
|
|
18
|
+
|
|
19
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
20
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
21
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
22
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
23
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
24
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
25
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
26
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
27
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
28
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|