bo-grid 0.8.0 → 0.21.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +202 -9
- package/dist/bo-grid.FilterMenu-BHI6rILc.js +154 -0
- package/dist/bo-grid.ToolPanel-C3u-4YKc.js +34 -0
- package/dist/bo-grid.element-DPnHUXMa.js +6623 -0
- package/dist/bo-grid.element.js +4 -0
- package/dist/charts/BarChart.svelte +50 -0
- package/dist/charts/BarChart.svelte.d.ts +16 -0
- package/dist/charts/DonutChart.svelte +54 -0
- package/dist/charts/DonutChart.svelte.d.ts +18 -0
- package/dist/charts/Legend.svelte +47 -0
- package/dist/charts/Legend.svelte.d.ts +12 -0
- package/dist/charts/LineChart.svelte +59 -0
- package/dist/charts/LineChart.svelte.d.ts +14 -0
- package/dist/charts/StackedBarChart.svelte +56 -0
- package/dist/charts/StackedBarChart.svelte.d.ts +18 -0
- package/dist/charts/chart-math.d.ts +57 -0
- package/dist/charts/chart-math.js +174 -0
- package/dist/charts/index.d.ts +8 -0
- package/dist/charts/index.js +11 -0
- package/dist/charts/palette.d.ts +4 -0
- package/dist/charts/palette.js +14 -0
- package/dist/format/format.d.ts +6 -0
- package/dist/format/format.js +41 -0
- package/dist/grid/Cell.svelte +247 -8
- package/dist/grid/Cell.svelte.d.ts +6 -0
- package/dist/grid/FilterMenu.svelte +7 -0
- package/dist/grid/Grid.svelte +307 -85
- package/dist/grid/Grid.svelte.d.ts +19 -0
- package/dist/grid/GroupRow.svelte +5 -2
- package/dist/grid/Pager.svelte +4 -0
- package/dist/grid/RowMenu.svelte +65 -2
- package/dist/grid/ToolPanel.svelte +5 -0
- package/dist/grid/column.d.ts +133 -0
- package/dist/grid/column.js +133 -4
- package/dist/grid/colvirt.d.ts +15 -0
- package/dist/grid/colvirt.js +43 -0
- package/dist/grid/export.js +5 -2
- package/dist/grid/filtering.d.ts +5 -2
- package/dist/grid/filtering.js +5 -4
- package/dist/grid/grouping.d.ts +30 -0
- package/dist/grid/grouping.js +33 -0
- package/dist/grid/theme.d.ts +15 -0
- package/dist/grid/theme.js +78 -0
- package/dist/grid/tree.d.ts +19 -7
- package/dist/grid/tree.js +16 -11
- package/dist/index.d.ts +5 -4
- package/dist/index.js +2 -2
- package/package.json +12 -2
package/README.md
CHANGED
|
@@ -98,9 +98,51 @@ Only on-screen rows render DOM, so off-screen updates cost nothing until they
|
|
|
98
98
|
scroll into view. Batch bursty feeds into a `requestAnimationFrame` flush to
|
|
99
99
|
keep frames smooth.
|
|
100
100
|
|
|
101
|
+
### React, Vue, Angular & vanilla
|
|
102
|
+
|
|
103
|
+
bo-grid also ships a framework-agnostic **custom element**. Import it and drive
|
|
104
|
+
the whole API through a `config` property:
|
|
105
|
+
|
|
106
|
+
```js
|
|
107
|
+
import 'bo-grid/element'; // registers <bo-grid>, injects styles
|
|
108
|
+
|
|
109
|
+
const el = document.querySelector('bo-grid');
|
|
110
|
+
el.config = { columns, rows, theme: 'dark', height: 520 };
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
It works in React, Vue, Angular and plain HTML — see
|
|
114
|
+
**[docs/frameworks.md](./docs/frameworks.md)** for per-framework recipes. (Custom
|
|
115
|
+
`cell`/`detail` snippets are Svelte-only; use built-in types, `format`, or computed
|
|
116
|
+
`value` from other frameworks. Native Svelte users should import `Grid` directly —
|
|
117
|
+
smaller, and snippets work.)
|
|
118
|
+
|
|
101
119
|
## Column types
|
|
102
120
|
|
|
103
|
-
`text` · `price` · `percent` · `volume` · `number` · `date` · `
|
|
121
|
+
**Data:** `text` · `price` · `percent` · `volume` · `number` · `date` · `currency` ·
|
|
122
|
+
`relative` · `heatmap` · `sparkline`
|
|
123
|
+
**Rich:** `progress` · `rating` · `tags` · `badge` · `boolean` · `avatar` · `link`
|
|
124
|
+
**Escape hatch:** `custom`
|
|
125
|
+
|
|
126
|
+
Rich types render value as a widget — handy well beyond fintech (CRM, projects,
|
|
127
|
+
admin, content). All are themed from the design tokens:
|
|
128
|
+
|
|
129
|
+
```ts
|
|
130
|
+
const columns: ColumnDef[] = [
|
|
131
|
+
{ type: 'avatar', key: 'name', header: 'Member', sub: 'role' },
|
|
132
|
+
{ type: 'badge', key: 'status', header: 'Status',
|
|
133
|
+
tones: { Active: 'up', Away: 'amber', Offline: 'neutral' } },
|
|
134
|
+
{ type: 'progress', key: 'done', header: 'Progress', min: 0, max: 100 },
|
|
135
|
+
{ type: 'rating', key: 'score', header: 'Rating', max: 5 },
|
|
136
|
+
{ type: 'tags', key: 'skills', header: 'Skills' }, // value: string[]
|
|
137
|
+
{ type: 'boolean', key: 'remote', header: 'Remote', trueLabel: 'Remote', falseLabel: 'Office' },
|
|
138
|
+
{ type: 'link', key: 'email', header: 'Email', href: (r) => `mailto:${r.email}` },
|
|
139
|
+
{ type: 'relative', key: 'seen', header: 'Last seen' }, // value: epoch ms → "3h ago"
|
|
140
|
+
{ type: 'currency', key: 'rate', header: 'Rate', currency: 'USD' },
|
|
141
|
+
];
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
`link` sanitizes its href (`javascript:`/`data:` are blocked); `relative` formats
|
|
145
|
+
an epoch-ms value as relative time; `currency` localizes via `Intl.NumberFormat`.
|
|
104
146
|
|
|
105
147
|
Sizing: `width` (px) or `flex` (grow weight). See `ColumnDef` for per-type options.
|
|
106
148
|
|
|
@@ -117,6 +159,94 @@ buttons, links. The snippet receives `{ row, column, value }`:
|
|
|
117
159
|
<Grid {rows} {columns} {cell} height={640} />
|
|
118
160
|
```
|
|
119
161
|
|
|
162
|
+
## Conditional formatting
|
|
163
|
+
|
|
164
|
+
Paint analytics cues straight into numeric cells — no custom snippet needed.
|
|
165
|
+
|
|
166
|
+
**Data bars** (`dataBar`): an in-cell bar behind the value, scaled across the
|
|
167
|
+
column's range. The range auto-computes over the current view, or set `min`/`max`
|
|
168
|
+
(`min: 0` gives absolute proportional bars). When the range spans negatives, bars
|
|
169
|
+
diverge left/right around a zero baseline. `color`/`negative` override the default
|
|
170
|
+
up/down theme colours.
|
|
171
|
+
|
|
172
|
+
**Icon sets** (`icons`): an icon beside the value, chosen by the highest threshold
|
|
173
|
+
`at` that is ≤ the value. Each rule carries a semantic `tone` (`up` · `down` ·
|
|
174
|
+
`amber` · `info` · `neutral`) for its colour.
|
|
175
|
+
|
|
176
|
+
**Colour scales** (`colorScale`): tint the cell background across the value range —
|
|
177
|
+
a soft, themed heat ramp. Auto-ranges over the view (or set `min`/`max`); pass
|
|
178
|
+
`mid` for a 3-stop diverging scale; `colors` overrides the stops. Works on any
|
|
179
|
+
numeric column (the fixed `heatmap` type still exists for an absolute ramp).
|
|
180
|
+
|
|
181
|
+
```ts
|
|
182
|
+
const columns: ColumnDef[] = [
|
|
183
|
+
// Proportional bar from zero:
|
|
184
|
+
{ type: 'volume', key: 'marketValue', header: 'Mkt Value', dataBar: { min: 0 } },
|
|
185
|
+
// Diverging bar (auto-ranged) + an icon keyed by sign:
|
|
186
|
+
{ type: 'number', key: 'pnl', header: 'P&L', decimals: 0,
|
|
187
|
+
dataBar: {},
|
|
188
|
+
icons: [
|
|
189
|
+
{ at: -Infinity, icon: '▼', tone: 'down' },
|
|
190
|
+
{ at: 0, icon: '▲', tone: 'up' },
|
|
191
|
+
] },
|
|
192
|
+
// Diverging colour scale around zero (auto-ranged):
|
|
193
|
+
{ type: 'number', key: 'pnlPct', header: 'P&L %', decimals: 1, colorScale: { mid: 0 } },
|
|
194
|
+
];
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
All three compose with flashing/live cells and add nothing to the core for grids
|
|
198
|
+
that don't use them. (In-memory auto-ranging; pass explicit `min`/`max` in source
|
|
199
|
+
mode.)
|
|
200
|
+
|
|
201
|
+
## Computed columns
|
|
202
|
+
|
|
203
|
+
Derive a column's value from the whole row with `value: (row) => …` — KPIs,
|
|
204
|
+
ratios, deltas. The derived value flows through display, sort, filter, group/footer
|
|
205
|
+
aggregation, conditional formatting, export and copy, just like a real column.
|
|
206
|
+
`key` still names the column (and is the sort/filter key) but need not be a real
|
|
207
|
+
field. Computed columns aren't editable (there's no field to write back).
|
|
208
|
+
|
|
209
|
+
```ts
|
|
210
|
+
const columns: ColumnDef[] = [
|
|
211
|
+
{ type: 'number', key: 'qty', header: 'Qty' },
|
|
212
|
+
{ type: 'price', key: 'price', header: 'Price' },
|
|
213
|
+
// No `total` field on the row — derived, and still sortable/filterable/exportable:
|
|
214
|
+
{ type: 'price', key: 'total', header: 'Total', value: (row) => row.qty * row.price,
|
|
215
|
+
groupAgg: 'sum' },
|
|
216
|
+
];
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
In-memory mode (a server `source` owns its own derivations). Keep `value()` cheap
|
|
220
|
+
and pure — it's called during sort and filter.
|
|
221
|
+
|
|
222
|
+
## Charts (companion)
|
|
223
|
+
|
|
224
|
+
For dashboards, `bo-grid/charts` ships tiny, dependency-free SVG charts —
|
|
225
|
+
`LineChart`, `BarChart`, `DonutChart`, `StackedBarChart` (stacked or `grouped`
|
|
226
|
+
multi-series), and a `Legend`. They're a **separate import**, so they add nothing
|
|
227
|
+
to the grid core (~3 KB gzip on their own). Use them standalone, or inside a grid
|
|
228
|
+
cell via a `custom` column. Bar/stacked/donut elements carry an SVG `<title>`, so
|
|
229
|
+
hovering shows the value (accessible, zero-JS).
|
|
230
|
+
|
|
231
|
+
```svelte
|
|
232
|
+
<script>
|
|
233
|
+
import { LineChart, BarChart, DonutChart, StackedBarChart, Legend } from 'bo-grid/charts';
|
|
234
|
+
</script>
|
|
235
|
+
|
|
236
|
+
<LineChart data={[3, 5, 4, 8, 6, 9]} width={160} height={40} area />
|
|
237
|
+
<BarChart data={[4, 8, 6, 9, 7]} color="var(--up)" />
|
|
238
|
+
<DonutChart data={[{ value: 5, label: 'A' }, { value: 3, label: 'B' }]} />
|
|
239
|
+
|
|
240
|
+
<!-- data[series][category]; stacked by default, `grouped` for side-by-side -->
|
|
241
|
+
<StackedBarChart data={[[3, 5, 2], [4, 1, 6]]} seriesLabels={['Q1', 'Q2']} />
|
|
242
|
+
<Legend items={[{ label: 'Q1' }, { label: 'Q2' }]} />
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
Theme them with `color` / `colors` props, or by setting `--boc-color` and
|
|
246
|
+
`--boc-1`…`--boc-6` CSS vars on any ancestor. The geometry helpers (`linePoints`,
|
|
247
|
+
`barRects`, `donutArcs`, …) are exported too, for rolling your own SVG charts. See
|
|
248
|
+
the **Dashboard** example for charts inside grid cells.
|
|
249
|
+
|
|
120
250
|
## Row height
|
|
121
251
|
|
|
122
252
|
Uniform 36px by default. Pass `rowHeight` as a number for a different density, or
|
|
@@ -269,6 +399,26 @@ Group headers are the same height as data rows, so virtual scrolling stays smoot
|
|
|
269
399
|
over very large grouped sets. Subtotals recompute live as the feed ticks, and the
|
|
270
400
|
current group's header stays pinned to the top as you scroll within it.
|
|
271
401
|
|
|
402
|
+
### Server-side grouping
|
|
403
|
+
|
|
404
|
+
When the data is grouped on the server (or too large to fetch upfront), pass
|
|
405
|
+
**`lazyGroups`** (the group summaries) and **`loadGroup`** (load a group's rows on
|
|
406
|
+
expand). Headers show the server-provided count and preformatted aggregates; rows
|
|
407
|
+
load lazily with a loading row, then cache. See the **Server groups** example.
|
|
408
|
+
|
|
409
|
+
```svelte
|
|
410
|
+
<Grid
|
|
411
|
+
rows={[]}
|
|
412
|
+
{columns}
|
|
413
|
+
lazyGroups={[
|
|
414
|
+
{ key: 'North America', count: 142, agg: { amount: '$2.4M' } },
|
|
415
|
+
{ key: 'Europe', count: 98, agg: { amount: '$1.8M' } },
|
|
416
|
+
]}
|
|
417
|
+
loadGroup={(key) => fetch(`/api/orders?group=${key}`).then((r) => r.json())}
|
|
418
|
+
height={520}
|
|
419
|
+
/>
|
|
420
|
+
```
|
|
421
|
+
|
|
272
422
|
## Theming
|
|
273
423
|
|
|
274
424
|
Dark-first and self-contained — no CSS import required. Use the `theme` prop with
|
|
@@ -279,9 +429,20 @@ a built-in preset or a custom token map:
|
|
|
279
429
|
<Grid {rows} {columns} theme={{ bg: '#0b1020', up: '#22d3ee' }} height={640} />
|
|
280
430
|
```
|
|
281
431
|
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
432
|
+
Six built-in presets are exported (`GridTheme`): `darkTheme`, `lightTheme`,
|
|
433
|
+
`highContrastDark`, `highContrastLight`, `midnightTheme`, `terminalTheme` — plus a
|
|
434
|
+
`themePresets` name→preset map (and a `ThemePreset` type) for a theme picker:
|
|
435
|
+
|
|
436
|
+
```svelte
|
|
437
|
+
<script>
|
|
438
|
+
import { Grid, themePresets, type ThemePreset } from 'bo-grid';
|
|
439
|
+
let preset: ThemePreset = 'midnight';
|
|
440
|
+
</script>
|
|
441
|
+
<Grid {rows} {columns} theme={themePresets[preset]} height={640} />
|
|
442
|
+
```
|
|
443
|
+
|
|
444
|
+
Or set any `--bo-grid-*` custom property on an ancestor — the prop is just a
|
|
445
|
+
convenience over these:
|
|
285
446
|
|
|
286
447
|
```css
|
|
287
448
|
.my-app {
|
|
@@ -344,6 +505,18 @@ render as skeletons.
|
|
|
344
505
|
the same interface (handy for testing the path or client-side data). Grouping is
|
|
345
506
|
client-only, so it's not applied in source mode.
|
|
346
507
|
|
|
508
|
+
### Wide grids (column virtualization)
|
|
509
|
+
|
|
510
|
+
Rows are virtualized vertically by default. For very wide grids (100+ columns),
|
|
511
|
+
add **`virtualizeColumns`** to also virtualize horizontally — only the columns in
|
|
512
|
+
the scroll window (+ overscan) render, so a 60-column grid costs about the same as
|
|
513
|
+
a handful. It switches the grid to fixed-width horizontal scroll; **pinned columns
|
|
514
|
+
always render**. See the **Wide** example.
|
|
515
|
+
|
|
516
|
+
```svelte
|
|
517
|
+
<Grid {rows} {columns} virtualizeColumns height={520} />
|
|
518
|
+
```
|
|
519
|
+
|
|
347
520
|
## Column reorder
|
|
348
521
|
|
|
349
522
|
Pass `onRowReorder(from, to)` to enable **drag-to-reorder rows** via a handle in
|
|
@@ -418,6 +591,23 @@ In tree mode the grid renders the tree directly (filter/sort/group/paginate are
|
|
|
418
591
|
not applied to it). Nodes are keyboard-accessible: **→** expands a collapsed node,
|
|
419
592
|
**←** collapses an expanded one, and rows expose `aria-level` / `aria-expanded`.
|
|
420
593
|
|
|
594
|
+
### Lazy (server-backed) trees
|
|
595
|
+
|
|
596
|
+
For hierarchies too large to ship upfront, use **`loadChildren`** (async) instead
|
|
597
|
+
of `getChildren`. Children load on first expand — the grid shows a loading row,
|
|
598
|
+
then caches them. Pair it with **`hasChildren`** (a cheap predicate) so the chevron
|
|
599
|
+
shows without loading. See the **Lazy tree** example.
|
|
600
|
+
|
|
601
|
+
```svelte
|
|
602
|
+
<Grid
|
|
603
|
+
{rows}
|
|
604
|
+
{columns}
|
|
605
|
+
height={520}
|
|
606
|
+
hasChildren={(r) => r.kind === 'folder'}
|
|
607
|
+
loadChildren={(r) => fetch(`/api/children/${r.id}`).then((res) => res.json())}
|
|
608
|
+
/>
|
|
609
|
+
```
|
|
610
|
+
|
|
421
611
|
## Master-detail
|
|
422
612
|
|
|
423
613
|
Pass a `detail` snippet to render an expandable panel under each row — the grid
|
|
@@ -585,11 +775,14 @@ the real dimensions and positions so assistive tech isn't misled:
|
|
|
585
775
|
- `aria-activedescendant` tracks the focused cell for screen readers.
|
|
586
776
|
- Sparkline cells carry a text `aria-label`; sticky/skeleton duplicates are
|
|
587
777
|
`aria-hidden`; the aggregation bar is an `aria-live` status region.
|
|
588
|
-
- Fully keyboard-operable
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
778
|
+
- Fully keyboard-operable: one tab stop with arrow-key navigation, APG-pattern
|
|
779
|
+
menus (focus moves in, arrow-navigable, returns focus on close), a keyboard path
|
|
780
|
+
to filtering (column menu → **Filter…**), and visible `:focus-visible` rings on
|
|
781
|
+
every reachable control. Respects `prefers-reduced-motion`.
|
|
782
|
+
|
|
783
|
+
bo-grid targets **WCAG 2.1 AA**. See **[ACCESSIBILITY.md](./ACCESSIBILITY.md)** for
|
|
784
|
+
the full keyboard map, roles, measured contrast ratios, and conformance notes from
|
|
785
|
+
the audit.
|
|
593
786
|
|
|
594
787
|
## Develop
|
|
595
788
|
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import { p as ce, a as xe, v as me, w as _e, n as x, x as _, s as p, y as L, t as N, z as he, j as ke, f as C, h as w, i as u, m as ge, c as h, A as D, e as F, g as t, B as U, k as S, d as ye, l as f, C as we, o as k, D as Ae, u as Oe, q as Se, r as d, b as A } from "./bo-grid.element-DPnHUXMa.js";
|
|
2
|
+
var G = k("<option> </option>"), Ne = k('<input class="bo-fm-in svelte-f7i4av" type="number" placeholder="and" aria-label="Upper value"/>'), Ce = k('<select class="bo-fm-op svelte-f7i4av" aria-label="Operator"></select> <input class="bo-fm-in svelte-f7i4av" type="number" placeholder="value" aria-label="Value"/> <!>', 1), Ee = k('<input class="bo-fm-in svelte-f7i4av" type="date" aria-label="End date"/>'), qe = k('<select class="bo-fm-op svelte-f7i4av" aria-label="Operator"></select> <input class="bo-fm-in svelte-f7i4av" type="date" aria-label="Date"/> <!>', 1), Be = k('<label class="bo-fm-opt svelte-f7i4av"><input type="checkbox"/> <span class="svelte-f7i4av"> </span></label>'), De = k('<input class="bo-fm-in svelte-f7i4av" type="search" placeholder="search…" aria-label="Search values"/> <div class="bo-fm-setbar svelte-f7i4av"><button type="button" class="bo-fm-link svelte-f7i4av">All</button> <button type="button" class="bo-fm-link svelte-f7i4av">None</button></div> <div class="bo-fm-list svelte-f7i4av"></div>', 1), Fe = k('<select class="bo-fm-op svelte-f7i4av" aria-label="Operator"></select> <input class="bo-fm-in svelte-f7i4av" type="text" placeholder="filter…" aria-label="Value"/>', 1), ze = k('<div class="bo-filtermenu svelte-f7i4av" role="dialog" tabindex="-1"><div class="bo-fm-head svelte-f7i4av"> </div> <!> <div class="bo-fm-actions svelte-f7i4av"><button class="bo-fm-btn svelte-f7i4av" type="button">Clear</button> <button class="bo-fm-btn bo-fm-apply svelte-f7i4av" type="button">Apply</button></div></div>');
|
|
3
|
+
const Pe = {
|
|
4
|
+
hash: "svelte-f7i4av",
|
|
5
|
+
code: `.bo-filtermenu.svelte-f7i4av {position:fixed;z-index:30;display:flex;flex-direction:column;gap:6px;width:200px;padding:10px;background:var(--bo-header-bg);border:0.5px solid var(--bo-border);border-radius:8px;box-shadow:0 10px 30px rgba(0, 0, 0, 0.35);font-size:12px;color:var(--bo-text);}.bo-fm-head.svelte-f7i4av {font-weight:600;color:var(--bo-text-dim);padding-bottom:2px;}.bo-fm-op.svelte-f7i4av,
|
|
6
|
+
.bo-fm-in.svelte-f7i4av {width:100%;padding:5px 7px;font:inherit;color:var(--bo-text);background:var(--bo-bg);border:0.5px solid var(--bo-border);border-radius:5px;}.bo-fm-setbar.svelte-f7i4av {display:flex;gap:12px;}.bo-fm-link.svelte-f7i4av {padding:0;font:inherit;font-size:11px;color:var(--bo-up);background:none;border:0;cursor:pointer;}.bo-fm-link.svelte-f7i4av:hover {text-decoration:underline;}.bo-fm-list.svelte-f7i4av {display:flex;flex-direction:column;max-height:180px;overflow-y:auto;border:0.5px solid var(--bo-border);border-radius:5px;}.bo-fm-opt.svelte-f7i4av {display:flex;align-items:center;gap:7px;padding:4px 7px;cursor:pointer;white-space:nowrap;}.bo-fm-opt.svelte-f7i4av:hover {background:var(--bo-row-hover);}.bo-fm-opt.svelte-f7i4av span:where(.svelte-f7i4av) {overflow:hidden;text-overflow:ellipsis;}.bo-fm-actions.svelte-f7i4av {display:flex;justify-content:flex-end;gap:6px;margin-top:2px;}.bo-fm-btn.svelte-f7i4av {padding:5px 12px;font:inherit;font-size:11px;color:var(--bo-text-dim);background:transparent;border:0.5px solid var(--bo-border);border-radius:5px;cursor:pointer;}.bo-fm-btn.svelte-f7i4av:hover {color:var(--bo-text);}
|
|
7
|
+
/* Visible keyboard focus (WCAG 2.4.7) for the menu's custom buttons. */.bo-fm-btn.svelte-f7i4av:focus-visible,
|
|
8
|
+
.bo-fm-link.svelte-f7i4av:focus-visible {outline:2px solid var(--bo-sel-border);outline-offset:1px;border-radius:5px;}.bo-fm-apply.svelte-f7i4av {color:#0a0a0a;background:var(--bo-up);border-color:var(--bo-up);}`
|
|
9
|
+
};
|
|
10
|
+
function Ve(K, n) {
|
|
11
|
+
ce(n, !0), xe(K, Pe);
|
|
12
|
+
let Q = me(n, "values", 19, () => []);
|
|
13
|
+
const $ = [
|
|
14
|
+
{ op: "contains", label: "Contains" },
|
|
15
|
+
{ op: "notContains", label: "Not contains" },
|
|
16
|
+
{ op: "equals", label: "Equals" },
|
|
17
|
+
{ op: "starts", label: "Starts with" },
|
|
18
|
+
{ op: "ends", label: "Ends with" }
|
|
19
|
+
], ee = [
|
|
20
|
+
{ op: "eq", label: "=" },
|
|
21
|
+
{ op: "ne", label: "≠" },
|
|
22
|
+
{ op: "lt", label: "<" },
|
|
23
|
+
{ op: "le", label: "≤" },
|
|
24
|
+
{ op: "gt", label: ">" },
|
|
25
|
+
{ op: "ge", label: "≥" },
|
|
26
|
+
{ op: "between", label: "Between" }
|
|
27
|
+
], ae = [
|
|
28
|
+
{ op: "on", label: "On" },
|
|
29
|
+
{ op: "before", label: "Before" },
|
|
30
|
+
{ op: "after", label: "After" },
|
|
31
|
+
{ op: "between", label: "Between" }
|
|
32
|
+
], R = (a) => a ? Date.parse(`${a}T00:00:00Z`) : NaN, W = (a) => Number.isFinite(a) ? new Date(a).toISOString().slice(0, 10) : "", e = _e(() => n.filter);
|
|
33
|
+
let z = x(_((e == null ? void 0 : e.kind) === "text" ? e.op : "contains")), P = x(_((e == null ? void 0 : e.kind) === "text" ? e.q : "")), E = x(_((e == null ? void 0 : e.kind) === "number" ? e.op : "eq")), T = x(_((e == null ? void 0 : e.kind) === "number" && Number.isFinite(e.a) ? e.a : null)), V = x(_((e == null ? void 0 : e.kind) === "number" && e.b != null && Number.isFinite(e.b) ? e.b : null)), q = x(_((e == null ? void 0 : e.kind) === "date" ? e.op : "on")), M = x(_((e == null ? void 0 : e.kind) === "date" ? W(e.a) : "")), B = x(_((e == null ? void 0 : e.kind) === "date" && e.b != null ? W(e.b) : "")), O = x(_(new Set((e == null ? void 0 : e.kind) === "set" ? e.excluded : []))), j = x("");
|
|
34
|
+
const te = Oe(() => Q().filter((a) => a.toLowerCase().includes(t(j).trim().toLowerCase())));
|
|
35
|
+
function le(a) {
|
|
36
|
+
const s = new Set(t(O));
|
|
37
|
+
s.has(a) ? s.delete(a) : s.add(a), f(O, s, !0);
|
|
38
|
+
}
|
|
39
|
+
function oe() {
|
|
40
|
+
let a;
|
|
41
|
+
return n.kind === "number" ? a = {
|
|
42
|
+
kind: "number",
|
|
43
|
+
op: t(E),
|
|
44
|
+
a: t(T) ?? NaN,
|
|
45
|
+
b: t(V) ?? void 0
|
|
46
|
+
} : n.kind === "date" ? a = {
|
|
47
|
+
kind: "date",
|
|
48
|
+
op: t(q),
|
|
49
|
+
a: R(t(M)),
|
|
50
|
+
b: t(B) ? R(t(B)) : void 0
|
|
51
|
+
} : n.kind === "set" ? a = { kind: "set", excluded: [...t(O)] } : a = { kind: "text", op: t(z), q: t(P) }, Ae(a) ? a : null;
|
|
52
|
+
}
|
|
53
|
+
function X() {
|
|
54
|
+
n.onApply(oe());
|
|
55
|
+
}
|
|
56
|
+
function re() {
|
|
57
|
+
n.onApply(null);
|
|
58
|
+
}
|
|
59
|
+
function ie(a) {
|
|
60
|
+
a.key === "Enter" ? X() : a.key === "Escape" && n.onClose();
|
|
61
|
+
}
|
|
62
|
+
var g = ze(), I = h(g), ne = h(I, !0);
|
|
63
|
+
d(I);
|
|
64
|
+
var Z = p(I, 2);
|
|
65
|
+
{
|
|
66
|
+
var se = (a) => {
|
|
67
|
+
var s = Ce(), i = D(s);
|
|
68
|
+
F(i, 21, () => ee, (l) => l.op, (l, o) => {
|
|
69
|
+
var r = G(), y = h(r, !0);
|
|
70
|
+
d(r);
|
|
71
|
+
var c = {};
|
|
72
|
+
N(() => {
|
|
73
|
+
C(y, t(o).label), c !== (c = t(o).op) && (r.value = (r.__value = t(o).op) ?? "");
|
|
74
|
+
}), u(l, r);
|
|
75
|
+
}), d(i);
|
|
76
|
+
var v = p(i, 2);
|
|
77
|
+
A(v);
|
|
78
|
+
var b = p(v, 2);
|
|
79
|
+
{
|
|
80
|
+
var m = (l) => {
|
|
81
|
+
var o = Ne();
|
|
82
|
+
A(o), S(o, () => t(V), (r) => f(V, r)), u(l, o);
|
|
83
|
+
};
|
|
84
|
+
L(b, (l) => {
|
|
85
|
+
t(E) === "between" && l(m);
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
U(i, () => t(E), (l) => f(E, l)), S(v, () => t(T), (l) => f(T, l)), u(a, s);
|
|
89
|
+
}, ve = (a) => {
|
|
90
|
+
var s = qe(), i = D(s);
|
|
91
|
+
F(i, 21, () => ae, (l) => l.op, (l, o) => {
|
|
92
|
+
var r = G(), y = h(r, !0);
|
|
93
|
+
d(r);
|
|
94
|
+
var c = {};
|
|
95
|
+
N(() => {
|
|
96
|
+
C(y, t(o).label), c !== (c = t(o).op) && (r.value = (r.__value = t(o).op) ?? "");
|
|
97
|
+
}), u(l, r);
|
|
98
|
+
}), d(i);
|
|
99
|
+
var v = p(i, 2);
|
|
100
|
+
A(v);
|
|
101
|
+
var b = p(v, 2);
|
|
102
|
+
{
|
|
103
|
+
var m = (l) => {
|
|
104
|
+
var o = Ee();
|
|
105
|
+
A(o), S(o, () => t(B), (r) => f(B, r)), u(l, o);
|
|
106
|
+
};
|
|
107
|
+
L(b, (l) => {
|
|
108
|
+
t(q) === "between" && l(m);
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
U(i, () => t(q), (l) => f(q, l)), S(v, () => t(M), (l) => f(M, l)), u(a, s);
|
|
112
|
+
}, be = (a) => {
|
|
113
|
+
var s = De(), i = D(s);
|
|
114
|
+
A(i);
|
|
115
|
+
var v = p(i, 2), b = h(v), m = p(b, 2);
|
|
116
|
+
d(v);
|
|
117
|
+
var l = p(v, 2);
|
|
118
|
+
F(l, 20, () => t(te), (o) => o, (o, r) => {
|
|
119
|
+
var y = Be(), c = h(y);
|
|
120
|
+
A(c);
|
|
121
|
+
var Y = p(c, 2), fe = h(Y, !0);
|
|
122
|
+
d(Y), d(y), N(
|
|
123
|
+
(ue) => {
|
|
124
|
+
ye(c, ue), C(fe, r === "" ? "(blank)" : r);
|
|
125
|
+
},
|
|
126
|
+
[() => !t(O).has(r)]
|
|
127
|
+
), w("change", c, () => le(r)), u(o, y);
|
|
128
|
+
}), d(l), S(i, () => t(j), (o) => f(j, o)), w("click", b, () => f(O, /* @__PURE__ */ new Set(), !0)), w("click", m, () => f(O, new Set(Q()), !0)), u(a, s);
|
|
129
|
+
}, de = (a) => {
|
|
130
|
+
var s = Fe(), i = D(s);
|
|
131
|
+
F(i, 21, () => $, (b) => b.op, (b, m) => {
|
|
132
|
+
var l = G(), o = h(l, !0);
|
|
133
|
+
d(l);
|
|
134
|
+
var r = {};
|
|
135
|
+
N(() => {
|
|
136
|
+
C(o, t(m).label), r !== (r = t(m).op) && (l.value = (l.__value = t(m).op) ?? "");
|
|
137
|
+
}), u(b, l);
|
|
138
|
+
}), d(i);
|
|
139
|
+
var v = p(i, 2);
|
|
140
|
+
A(v), we(v), U(i, () => t(z), (b) => f(z, b)), S(v, () => t(P), (b) => f(P, b)), u(a, s);
|
|
141
|
+
};
|
|
142
|
+
L(Z, (a) => {
|
|
143
|
+
n.kind === "number" ? a(se) : n.kind === "date" ? a(ve, 1) : n.kind === "set" ? a(be, 2) : a(de, -1);
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
var H = p(Z, 2), J = h(H), pe = p(J, 2);
|
|
147
|
+
d(H), d(g), N(() => {
|
|
148
|
+
he(g, "aria-label", `Filter ${n.header ?? ""}`), ke(g, `left:${n.x ?? ""}px;top:${n.y ?? ""}px;`), C(ne, n.header);
|
|
149
|
+
}), w("pointerdown", g, (a) => a.stopPropagation()), w("keydown", g, ie), w("click", J, re), w("click", pe, X), u(K, g), ge();
|
|
150
|
+
}
|
|
151
|
+
Se(["pointerdown", "keydown", "click", "change"]);
|
|
152
|
+
export {
|
|
153
|
+
Ve as default
|
|
154
|
+
};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { p as z, a as S, c as d, s as r, r as l, b as f, e as j, t as g, g as s, d as L, f as P, h as i, i as w, j as T, k as q, l as A, m as E, n as B, u as D, o as k, q as F } from "./bo-grid.element-DPnHUXMa.js";
|
|
2
|
+
var G = k('<label class="bo-tp-opt svelte-7xdno"><input type="checkbox"/> <span class="svelte-7xdno"> </span></label>'), H = k('<div class="bo-toolpanel svelte-7xdno" role="dialog" tabindex="-1" aria-label="Columns"><div class="bo-tp-head svelte-7xdno"><span>Columns</span> <button type="button" class="bo-tp-link svelte-7xdno">Show all</button></div> <input class="bo-tp-search svelte-7xdno" type="search" placeholder="search…" aria-label="Search columns"/> <div class="bo-tp-list svelte-7xdno"></div></div>');
|
|
3
|
+
const I = {
|
|
4
|
+
hash: "svelte-7xdno",
|
|
5
|
+
code: ".bo-toolpanel.svelte-7xdno {position:fixed;z-index:30;display:flex;flex-direction:column;gap:7px;width:200px;padding:10px;background:var(--bo-header-bg);border:0.5px solid var(--bo-border);border-radius:8px;box-shadow:0 10px 30px rgba(0, 0, 0, 0.35);font-size:12px;color:var(--bo-text);}.bo-tp-head.svelte-7xdno {display:flex;align-items:baseline;justify-content:space-between;font-weight:600;color:var(--bo-text-dim);}.bo-tp-link.svelte-7xdno {padding:0;font:inherit;font-size:11px;color:var(--bo-up);background:none;border:0;cursor:pointer;}.bo-tp-link.svelte-7xdno:hover {text-decoration:underline;}.bo-tp-link.svelte-7xdno:focus-visible {outline:2px solid var(--bo-sel-border);outline-offset:1px;border-radius:4px;}.bo-tp-search.svelte-7xdno {width:100%;padding:5px 7px;font:inherit;color:var(--bo-text);background:var(--bo-bg);border:0.5px solid var(--bo-border);border-radius:5px;}.bo-tp-list.svelte-7xdno {display:flex;flex-direction:column;max-height:220px;overflow-y:auto;}.bo-tp-opt.svelte-7xdno {display:flex;align-items:center;gap:7px;padding:4px 4px;cursor:pointer;white-space:nowrap;}.bo-tp-opt.svelte-7xdno:hover {background:var(--bo-row-hover);}.bo-tp-opt.svelte-7xdno span:where(.svelte-7xdno) {overflow:hidden;text-overflow:ellipsis;}"
|
|
6
|
+
};
|
|
7
|
+
function K(c, o) {
|
|
8
|
+
z(o, !0), S(c, I);
|
|
9
|
+
let p = B("");
|
|
10
|
+
const y = D(() => o.columns.filter((e) => e.header.toLowerCase().includes(s(p).trim().toLowerCase())));
|
|
11
|
+
var t = H(), x = d(t), m = r(d(x), 2);
|
|
12
|
+
l(x);
|
|
13
|
+
var b = r(x, 2);
|
|
14
|
+
f(b);
|
|
15
|
+
var u = r(b, 2);
|
|
16
|
+
j(u, 21, () => s(y), (e) => e.key, (e, a) => {
|
|
17
|
+
var v = G(), n = d(v);
|
|
18
|
+
f(n);
|
|
19
|
+
var h = r(n, 2), _ = d(h, !0);
|
|
20
|
+
l(h), l(v), g(
|
|
21
|
+
(C) => {
|
|
22
|
+
L(n, C), P(_, s(a).header);
|
|
23
|
+
},
|
|
24
|
+
[() => !o.hidden.includes(s(a).key)]
|
|
25
|
+
), i("change", n, () => o.onToggle(s(a).key)), w(e, v);
|
|
26
|
+
}), l(u), l(t), g(() => T(t, `left:${o.x ?? ""}px;top:${o.y ?? ""}px;`)), i("pointerdown", t, (e) => e.stopPropagation()), i("keydown", t, (e) => e.key === "Escape" && o.onClose()), i("click", m, function(...e) {
|
|
27
|
+
var a;
|
|
28
|
+
(a = o.onShowAll) == null || a.apply(this, e);
|
|
29
|
+
}), q(b, () => s(p), (e) => A(p, e)), w(c, t), E();
|
|
30
|
+
}
|
|
31
|
+
F(["pointerdown", "keydown", "click", "change"]);
|
|
32
|
+
export {
|
|
33
|
+
K as default
|
|
34
|
+
};
|