rj-grid 0.2.7 → 0.2.8
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_EN.md +328 -0
- package/dist/rj-grid.js +65 -11
- package/dist/types/src/RjGrid.vue.d.ts +7 -0
- package/dist/types/src/theme.d.ts +6 -2
- package/package.json +16 -17
package/README_EN.md
ADDED
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="docs/images/01-overview.png" alt="rj-grid full feature overview" width="100%" />
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
<h1 align="center">rj-grid</h1>
|
|
6
|
+
|
|
7
|
+
<p align="center">
|
|
8
|
+
<b>An enterprise-grade Vue 3 data grid with zero third-party dependencies — every AG Grid feature, MIT licensed, ~110 KB gzip.</b><br/>
|
|
9
|
+
Virtual scrolling · pinned columns · grouping & pivoting · tree · undoable editing · formula engine · SSRM server-side row model · theming & i18n · print/CSV/Excel/PDF · offline natural-language query (NLQ)
|
|
10
|
+
</p>
|
|
11
|
+
|
|
12
|
+
<p align="center">
|
|
13
|
+
<a href="https://www.npmjs.com/package/rj-grid"><img src="https://img.shields.io/npm/v/rj-grid.svg?logo=npm&color=cb3837" alt="npm version"/></a>
|
|
14
|
+
<a href="https://github.com/rjding/rjGrid"><img src="https://img.shields.io/github/stars/rjding/rjGrid?logo=github&color=181717" alt="GitHub stars"/></a>
|
|
15
|
+
<a href="https://gitee.com/rjding/rj-grid"><img src="https://img.shields.io/badge/Gitee-rj--grid-orange?logo=gitee&logoColor=white" alt="Gitee mirror"/></a>
|
|
16
|
+
<a href="https://github.com/rjding/rjGrid/blob/master/LICENSE"><img src="https://img.shields.io/badge/license-MIT-green.svg" alt="License MIT"/></a>
|
|
17
|
+
<a href="https://gitee.com/rjding/rj-grid"><img src="https://img.shields.io/badge/third--party%20deps-0-blue.svg" alt="Zero dependencies"/></a>
|
|
18
|
+
<img src="https://img.shields.io/badge/gzip-~110KB-lightgrey.svg" alt="Bundle size"/>
|
|
19
|
+
<a href="https://vuejs.org/"><img src="https://img.shields.io/badge/vue-3.x-brightgreen.svg?logo=vuedotjs" alt="Vue 3"/></a>
|
|
20
|
+
<img src="https://img.shields.io/badge/tests-407%20passed-yellowgreen.svg" alt="Tests"/>
|
|
21
|
+
<img src="https://img.shields.io/badge/types-TypeScript-blue.svg?logo=typescript" alt="TypeScript"/>
|
|
22
|
+
</p>
|
|
23
|
+
|
|
24
|
+
<p align="center">
|
|
25
|
+
<a href="#-quick-start">Quick Start</a> ·
|
|
26
|
+
<a href="#-feature-showcase">Showcase</a> ·
|
|
27
|
+
<a href="#-vs-ag-grid">vs AG Grid</a> ·
|
|
28
|
+
<a href="docs/RjGrid_Manual_EN.md">Full Manual</a> ·
|
|
29
|
+
<a href="https://github.com/rjding/rjGrid">GitHub</a> ·
|
|
30
|
+
<a href="https://gitee.com/rjding/rj-grid">Gitee</a> ·
|
|
31
|
+
<a href="README.md">中文</a>
|
|
32
|
+
</p>
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## 💡 Why rj-grid
|
|
37
|
+
|
|
38
|
+
Picture this: a single `<rj-grid>` tag that replaces those tables in your project that freeze past a few tens of thousands of rows, and that force you to swap libraries the moment you need grouping — all **without pulling in any third-party dependency** and without paying a license fee to a commercial grid vendor.
|
|
39
|
+
|
|
40
|
+
- **Truly zero-dependency**: the only runtime requirement is `vue`; even the optional charting is lazily `import('echarts')`. Nothing is bundled, nothing pollutes your lockfile.
|
|
41
|
+
- **Absurdly small**: ~110 KB gzip, yet it packs the combined feature set of several other libraries.
|
|
42
|
+
- **Silky at 100k rows**: two-way row/column virtual scrolling; 100,000 rows × 12 columns open instantly in practice (generation takes only ~12 ms).
|
|
43
|
+
- **AG Grid-parity features**: tree / grouping / pivoting / SSRM / formulas / theming / i18n / export / NLQ — all included.
|
|
44
|
+
- **Native TypeScript**: full type inference and `.d.ts`; editor autocompletion throughout — not a rough "make it work first" job.
|
|
45
|
+
- **Free for commercial use**: MIT license, safe for individuals and companies alike.
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## ✨ Feature overview
|
|
50
|
+
|
|
51
|
+
| Category | What you get |
|
|
52
|
+
|---|---|
|
|
53
|
+
| Rendering | Row/column virtual scrolling (smooth at 100k rows), pinned columns, multi-level headers, three density levels, pinned rows, full-width rows; **single-click a cell to select its row** (`selectOnCellClick`, no checkbox needed) |
|
|
54
|
+
| Data | Four modes: client-side / pagination / infinite scroll / **SSRM server-side row model** (block cache on demand) |
|
|
55
|
+
| Grouping | Tree of arbitrary depth, drag-to-group, multi-level grouping + group footers, column pivoting (with a high-cardinality guardrail) |
|
|
56
|
+
| Editing | 8 editor types, validation, undo/redo, batched transaction back-fill, built-in add/edit row dialog |
|
|
57
|
+
| Formulas | Zero-dependency Excel-style formulas: `=B2*C2`, `SUM/COUNTIF/SUMIF`, range references, circular-reference detection |
|
|
58
|
+
| Filtering | Header funnel / floating filter row / quick search / advanced filter (cross-column AND/OR expression tree) — four layers stackable |
|
|
59
|
+
| Appearance | Theme engine (4 presets × light/dark × accent color × custom CSS variables), i18n (zh/en + text override), icon replacement |
|
|
60
|
+
| Output | Print / CSV / Excel / PDF, with three scopes: selected rows / current view / backend export; the four buttons can each be shown/hidden (`showPrint`/`showCsv`/`showPdf`/`showExcel`) |
|
|
61
|
+
| AI | Purely offline deterministic **NLQ**, bilingual and following i18n: Chinese like `数量大于50 按单价降序`, English like `qty > 50 sort by price desc`, with the readback matching the language |
|
|
62
|
+
| State | `stateKey` auto-persistence + programmatic `getState/setState`; your view survives a refresh |
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## 🚀 Quick Start
|
|
67
|
+
|
|
68
|
+
> Three steps, two minutes, running.
|
|
69
|
+
|
|
70
|
+
**① Install**
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
npm install rj-grid
|
|
74
|
+
# or pnpm add rj-grid / yarn add rj-grid
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
**② Import the component and styles**
|
|
78
|
+
|
|
79
|
+
```ts
|
|
80
|
+
// main.ts —— importing the stylesheet once globally is enough
|
|
81
|
+
import 'rj-grid/style.css'
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
**③ Use it directly**
|
|
85
|
+
|
|
86
|
+
```vue
|
|
87
|
+
<template>
|
|
88
|
+
<rj-grid :columns="cols" :rows="rows" row-key="id" :height="480" show-toolbar />
|
|
89
|
+
</template>
|
|
90
|
+
|
|
91
|
+
<script setup lang="ts">
|
|
92
|
+
import { RjGrid } from 'rj-grid' // ⚠️ must be a VALUE import, not `type` only
|
|
93
|
+
import type { RjColumn, RjRowData } from 'rj-grid'
|
|
94
|
+
|
|
95
|
+
const cols: RjColumn[] = [
|
|
96
|
+
{ field: 'name', title: 'Name', width: 160, filter: 'text' },
|
|
97
|
+
{ field: 'qty', title: 'Qty', type: 'num', aggFunc: 'sum' },
|
|
98
|
+
{ field: 'price', title: 'Price', type: 'money', aggFunc: 'avg' }
|
|
99
|
+
]
|
|
100
|
+
const rows: RjRowData[] = [
|
|
101
|
+
{ id: 1, name: 'Bearing', qty: 100, price: 12.5 },
|
|
102
|
+
{ id: 2, name: 'Motor', qty: 30, price: 480 }
|
|
103
|
+
]
|
|
104
|
+
</script>
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Turn on `show-toolbar` and you instantly get pinned columns, grouping, filtering, export and column visibility — without writing another line of code. Want more? Just add a prop — full parameters for every feature are in the [📖 Manual](docs/RjGrid_Manual_EN.md).
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
## 🎬 Feature showcase
|
|
112
|
+
|
|
113
|
+
Real product screenshots/GIFs, all captured from the `playground` demo page:
|
|
114
|
+
|
|
115
|
+
<table>
|
|
116
|
+
<tr>
|
|
117
|
+
<td width="50%">
|
|
118
|
+
<b>🎨 Theme engine · 4 presets × light/dark × multi-language</b><br/>
|
|
119
|
+
<img src="docs/images/theme-cycle.gif" alt="Theme switching animation" width="100%"/>
|
|
120
|
+
</td>
|
|
121
|
+
<td width="50%">
|
|
122
|
+
<b>🤖 Offline natural-language query (NLQ)</b><br/>
|
|
123
|
+
Type a sentence; it applies filter + sort + grouping automatically.<br/>
|
|
124
|
+
<img src="docs/images/nlq-query.gif" alt="NLQ query animation" width="100%"/>
|
|
125
|
+
</td>
|
|
126
|
+
</tr>
|
|
127
|
+
<tr>
|
|
128
|
+
<td>
|
|
129
|
+
<b>🌲 Tree hierarchy · expand / collapse in one click</b><br/>
|
|
130
|
+
<img src="docs/images/tree-expand.gif" alt="Tree expand/collapse animation" width="100%"/>
|
|
131
|
+
</td>
|
|
132
|
+
<td>
|
|
133
|
+
<b>🔍 Quick filter · instant cross-column match highlighting</b><br/>
|
|
134
|
+
<img src="docs/images/quick-filter.gif" alt="Quick filter animation" width="100%"/>
|
|
135
|
+
</td>
|
|
136
|
+
</tr>
|
|
137
|
+
<tr>
|
|
138
|
+
<td>
|
|
139
|
+
<b>🧮 Formula engine · Excel-style, zero dependency</b><br/>
|
|
140
|
+
<img src="docs/images/15-formula.png" alt="Formula column" width="100%"/>
|
|
141
|
+
</td>
|
|
142
|
+
<td>
|
|
143
|
+
<b>📦 Built-in row edit / add dialog · form generated from column defs</b><br/>
|
|
144
|
+
<img src="docs/images/08-row-form.png" alt="Row dialog" width="100%"/>
|
|
145
|
+
</td>
|
|
146
|
+
</tr>
|
|
147
|
+
<tr>
|
|
148
|
+
<td>
|
|
149
|
+
<b>📊 Group aggregation + footers</b><br/>
|
|
150
|
+
<img src="docs/images/12-group.png" alt="Group aggregation" width="100%"/>
|
|
151
|
+
</td>
|
|
152
|
+
<td>
|
|
153
|
+
<b>⚡ 100k-row virtual scrolling · generation takes only ~12 ms</b><br/>
|
|
154
|
+
<img src="docs/images/10-perf-100k.png" alt="Big-data performance" width="100%"/>
|
|
155
|
+
</td>
|
|
156
|
+
</tr>
|
|
157
|
+
<tr>
|
|
158
|
+
<td>
|
|
159
|
+
<b>↕️ Row drag · drag the handle to reorder rows</b><br/>
|
|
160
|
+
<img src="docs/images/row-drag.gif" alt="Row drag animation" width="100%"/>
|
|
161
|
+
</td>
|
|
162
|
+
<td>
|
|
163
|
+
<b>⇄ Column drag · drag in the column menu's "Columns" tab to reorder (order changes live)</b><br/>
|
|
164
|
+
<img src="docs/images/col-drag.gif" alt="Column drag animation" width="100%"/>
|
|
165
|
+
</td>
|
|
166
|
+
</tr>
|
|
167
|
+
<tr>
|
|
168
|
+
<td colspan="2">
|
|
169
|
+
<b>➕ Dynamic query fields · get a configurable query bar with a single `queryable` prop</b><br/>
|
|
170
|
+
<img src="docs/images/query-field.gif" alt="Dynamic query field animation" width="100%"/>
|
|
171
|
+
</td>
|
|
172
|
+
</tr>
|
|
173
|
+
<tr>
|
|
174
|
+
<td width="50%">
|
|
175
|
+
<b>🔎 Server-side query + pagination · condition bar and pager on one row</b><br/>
|
|
176
|
+
<img src="docs/images/13-server-pagination.png" alt="Server-side query pagination" width="100%"/>
|
|
177
|
+
</td>
|
|
178
|
+
<td width="50%">
|
|
179
|
+
<b>☰ Three density levels · fit more on screen or go roomy and readable, switch freely</b><br/>
|
|
180
|
+
<img src="docs/images/21-density.png" alt="Display density switching" width="100%"/>
|
|
181
|
+
</td>
|
|
182
|
+
</tr>
|
|
183
|
+
<tr>
|
|
184
|
+
<td width="50%">
|
|
185
|
+
<b>💾 Save view · snapshot the current query/column layout/sorting in one click</b><br/>
|
|
186
|
+
<img src="docs/images/save-view.gif" alt="Save view animation" width="100%"/>
|
|
187
|
+
</td>
|
|
188
|
+
<td width="50%">
|
|
189
|
+
<b>▦ Tool panel · manage column visibility / grouping / pivoting by drag</b><br/>
|
|
190
|
+
<img src="docs/images/panel.gif" alt="Tool panel animation" width="100%"/>
|
|
191
|
+
</td>
|
|
192
|
+
</tr>
|
|
193
|
+
<tr>
|
|
194
|
+
<td colspan="2">
|
|
195
|
+
<b>🖨 Print / export · front-end (selected rows / current view) + backend export, three scopes</b><br/>
|
|
196
|
+
<img src="docs/images/print-export.gif" alt="Print/export scope animation" width="100%"/>
|
|
197
|
+
</td>
|
|
198
|
+
</tr>
|
|
199
|
+
</table>
|
|
200
|
+
|
|
201
|
+
---
|
|
202
|
+
|
|
203
|
+
## 🔍 vs AG Grid
|
|
204
|
+
|
|
205
|
+
| Aspect | rj-grid | AG Grid |
|
|
206
|
+
|---|---|---|
|
|
207
|
+
| License / cost | ✅ MIT, completely free | ⚠️ enterprise features need a commercial license |
|
|
208
|
+
| Third-party runtime deps | ✅ `vue` only | ⚠️ ships its own framework and module system |
|
|
209
|
+
| gzip size | ✅ ~110 KB | considerably larger |
|
|
210
|
+
| Native Vue 3 | ✅ value-import and use, not a wrapper | provides a Vue wrapper layer |
|
|
211
|
+
| Offline natural-language query | ✅ built-in deterministic NLQ | ❌ none |
|
|
212
|
+
| Virtual scroll / grouping / pivot / SSRM / formulas / theming / export | ✅ all built in | ✅ some behind the paid tier |
|
|
213
|
+
|
|
214
|
+
> rj-grid is not positioned as an "AG Grid clone" — it's a **free, lightweight, batteries-included**, high-quality option for Vue projects.
|
|
215
|
+
|
|
216
|
+
---
|
|
217
|
+
|
|
218
|
+
## 🧩 Data modes (pick as needed)
|
|
219
|
+
|
|
220
|
+
```vue
|
|
221
|
+
<!-- Client-side: load everything into rows; sorting/filtering/grouping all run in the browser, virtual scrolling handles 100k rows -->
|
|
222
|
+
<rj-grid :columns="cols" :rows="rows" row-key="id" />
|
|
223
|
+
|
|
224
|
+
<!-- Pagination: backend-paged, loadData automatically carries sorting/filters/page number; pager position is set by pager-position -->
|
|
225
|
+
<rj-grid :columns="cols" data-mode="pagination" :load-data="loadData" :page-size="20" />
|
|
226
|
+
|
|
227
|
+
<!-- Infinite scroll: fetch the next block when scrolling to the bottom, no page numbers -->
|
|
228
|
+
<rj-grid :columns="cols" data-mode="infinite" :load-data="loadData" />
|
|
229
|
+
|
|
230
|
+
<!-- SSRM server-side row model: grouping / big-data block cache, load blocks on demand -->
|
|
231
|
+
<rj-grid :columns="cols" data-mode="serverSide" :load-data="loadData" server-side-grouping />
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
```ts
|
|
235
|
+
import type { RjLoadServerParams } from 'rj-grid'
|
|
236
|
+
// params automatically include start/end/page/pageSize/sort/filters/quickFilterText/rowGroup… — pass them straight to the backend
|
|
237
|
+
async function loadData(p: RjLoadServerParams) {
|
|
238
|
+
const res = await api.queryPage(p)
|
|
239
|
+
return { rows: res.list, total: res.total, success: true }
|
|
240
|
+
}
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
Full configuration and callback signatures for each mode are in [Manual §6 Data modes](docs/RjGrid_Manual_EN.md).
|
|
244
|
+
|
|
245
|
+
---
|
|
246
|
+
|
|
247
|
+
## 🛠 Compatibility & tech stack
|
|
248
|
+
|
|
249
|
+
- **Framework**: Vue `^3.4.0` (the only required peer dependency)
|
|
250
|
+
- **Optional**: `echarts >= 5.0.0` (used only by the "integrated chart" dialog; degrades gracefully when not installed, without crashing the page)
|
|
251
|
+
- **Language**: fully typed TypeScript, `.d.ts` shipped with the package
|
|
252
|
+
- **Styles**: a single `rj-grid/style.css`; theming via CSS variables, overridable as needed
|
|
253
|
+
- **Build**: Vite library mode, single ESM file, `sideEffects` limited to CSS, tree-shaking friendly
|
|
254
|
+
|
|
255
|
+
---
|
|
256
|
+
|
|
257
|
+
## 🖥 Run the demo page locally
|
|
258
|
+
|
|
259
|
+
The demo page (`playground/`) starts its own server and doesn't depend on a host project; the 8 tabs are your feature map:
|
|
260
|
+
|
|
261
|
+
```bash
|
|
262
|
+
git clone https://github.com/rjding/rjGrid.git # in mainland China you can use the mirror: git clone https://gitee.com/rjding/rj-grid.git
|
|
263
|
+
cd rjGrid
|
|
264
|
+
pnpm install
|
|
265
|
+
pnpm dev # defaults to http://localhost:5173
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
> ① Full features ② Big-data performance ③ Tree/grouping/pivot ④ Server-side modes ⑤ SSRM block cache ⑥ Formula engine ⑦ Theming & i18n ⑧ AI natural-language query
|
|
269
|
+
|
|
270
|
+
---
|
|
271
|
+
|
|
272
|
+
<details>
|
|
273
|
+
<summary><b>📚 Maintainer info (repo layout / dev commands / release discipline)</b></summary>
|
|
274
|
+
|
|
275
|
+
### Repository structure
|
|
276
|
+
|
|
277
|
+
| Path | Purpose |
|
|
278
|
+
|---|---|
|
|
279
|
+
| `index.ts` | Package entry (value-exports `RjGrid` + the NLQ / query-condition kernel + all public types) |
|
|
280
|
+
| `src/` | Component and engine source (`src/types.ts` is the type authority) |
|
|
281
|
+
| `__tests__/` | 407 unit-test cases, entry `__tests__/run.ts` |
|
|
282
|
+
| `build/rjDistCheck.mjs` | Five dist health-check guards (run automatically at the end of a build) |
|
|
283
|
+
| `vite.lib.config.ts` | Library build: single ESM file + single `style.css`, external `vue`/`echarts`, no sourcemap |
|
|
284
|
+
| `playground/` | 8-tab demo page |
|
|
285
|
+
| `docs/RjGrid_Manual_EN.md` | Full manual (features, API, pitfalls and boundaries) |
|
|
286
|
+
| `dist/` | Release artifacts, committed alongside the library |
|
|
287
|
+
|
|
288
|
+
### Development commands
|
|
289
|
+
|
|
290
|
+
```bash
|
|
291
|
+
pnpm test # unit tests, 407 passed
|
|
292
|
+
pnpm ts # vue-tsc --noEmit
|
|
293
|
+
pnpm lint # eslint + stylelint
|
|
294
|
+
pnpm build # vite lib → vue-tsc d.ts → five dist health-check guards
|
|
295
|
+
pnpm size # bundle size report
|
|
296
|
+
pnpm dev # playground demo page
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
### Releasing a new version
|
|
300
|
+
|
|
301
|
+
Edit the source → `npm version patch|minor|major` (auto bump + commit + tag) → `git push --follow-tags` → `npm publish` (`prepublishOnly` automatically runs `pnpm build && pnpm test`, so a stale dist can never be published).
|
|
302
|
+
|
|
303
|
+
### Host-integration notes
|
|
304
|
+
|
|
305
|
+
- When installed from npm the directory name is standardized (`node_modules/rj-grid`), so styles can be imported directly with `import 'rj-grid/style.css'`.
|
|
306
|
+
- On the component side you must **value-import** `import { RjGrid } from 'rj-grid'`; a type-only import throws `Failed to resolve component: rj-grid` at runtime.
|
|
307
|
+
- When installing via a git URL, pnpm places the dependency in a directory whose name contains `#<commit>`; vite resource URLs with a bare `#` are treated as a fragment and dropped → 404 under dev, so use a CSS `@import` shim in that case (see Manual §15.4).
|
|
308
|
+
- Committing `dist` only exists to support the git-URL install path; `sourcemap: false` is source protection, not an option, and the five dist guards keep it in check at the same time.
|
|
309
|
+
|
|
310
|
+
</details>
|
|
311
|
+
|
|
312
|
+
---
|
|
313
|
+
|
|
314
|
+
## 🤝 Contributing
|
|
315
|
+
|
|
316
|
+
Issues and PRs are welcome: report bugs, request features, improve docs. Please include relevant unit tests with your change and keep `pnpm test && pnpm ts && pnpm lint && pnpm build` all green.
|
|
317
|
+
|
|
318
|
+
## 📄 License
|
|
319
|
+
|
|
320
|
+
[MIT](LICENSE) — free for individuals and companies to use, modify and redistribute.
|
|
321
|
+
|
|
322
|
+
## ☕ Support the author
|
|
323
|
+
|
|
324
|
+
If rj-grid has helped you, consider dropping a ⭐ Star, or buying the author a coffee:
|
|
325
|
+
|
|
326
|
+
<p align="center">
|
|
327
|
+
<img src="docs/88888.png" alt="A little support, a lot of love" width="240"/>
|
|
328
|
+
</p>
|
package/dist/rj-grid.js
CHANGED
|
@@ -4019,11 +4019,13 @@ function buildThemeVars(params = {}) {
|
|
|
4019
4019
|
}
|
|
4020
4020
|
return vars;
|
|
4021
4021
|
}
|
|
4022
|
-
function resolveMode(mode, prefersDark) {
|
|
4022
|
+
function resolveMode(mode, prefersDark, hostDark = null) {
|
|
4023
4023
|
if (mode === "dark")
|
|
4024
4024
|
return "dark";
|
|
4025
4025
|
if (mode === "light")
|
|
4026
4026
|
return "light";
|
|
4027
|
+
if (hostDark !== null)
|
|
4028
|
+
return hostDark ? "dark" : "light";
|
|
4027
4029
|
return prefersDark ? "dark" : "light";
|
|
4028
4030
|
}
|
|
4029
4031
|
const zhCN = {
|
|
@@ -10146,6 +10148,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
10146
10148
|
height: { default: "100%" },
|
|
10147
10149
|
loading: { type: Boolean },
|
|
10148
10150
|
theme: {},
|
|
10151
|
+
detectHostTheme: { type: Boolean, default: true },
|
|
10149
10152
|
density: { default: "medium" },
|
|
10150
10153
|
lang: {},
|
|
10151
10154
|
localeText: {},
|
|
@@ -10320,6 +10323,32 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
10320
10323
|
prefersDark.value = mq.matches;
|
|
10321
10324
|
(_a = mq.addEventListener) == null ? void 0 : _a.call(mq, "change", (e) => prefersDark.value = e.matches);
|
|
10322
10325
|
}
|
|
10326
|
+
const hostDark = ref(null);
|
|
10327
|
+
function readHostClass() {
|
|
10328
|
+
if (typeof document === "undefined")
|
|
10329
|
+
return;
|
|
10330
|
+
const cl = document.documentElement.classList;
|
|
10331
|
+
if (cl.contains("dark"))
|
|
10332
|
+
hostDark.value = true;
|
|
10333
|
+
else if (cl.contains("light"))
|
|
10334
|
+
hostDark.value = false;
|
|
10335
|
+
else
|
|
10336
|
+
hostDark.value = null;
|
|
10337
|
+
}
|
|
10338
|
+
if (props.detectHostTheme)
|
|
10339
|
+
readHostClass();
|
|
10340
|
+
let hostThemeMo = null;
|
|
10341
|
+
onMounted(() => {
|
|
10342
|
+
if (!props.detectHostTheme || typeof MutationObserver === "undefined")
|
|
10343
|
+
return;
|
|
10344
|
+
readHostClass();
|
|
10345
|
+
hostThemeMo = new MutationObserver(readHostClass);
|
|
10346
|
+
hostThemeMo.observe(document.documentElement, { attributes: true, attributeFilter: ["class"] });
|
|
10347
|
+
});
|
|
10348
|
+
onBeforeUnmount(() => {
|
|
10349
|
+
hostThemeMo == null ? void 0 : hostThemeMo.disconnect();
|
|
10350
|
+
hostThemeMo = null;
|
|
10351
|
+
});
|
|
10323
10352
|
function themeFromProp(t2) {
|
|
10324
10353
|
if (!t2)
|
|
10325
10354
|
return {};
|
|
@@ -10334,7 +10363,11 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
10334
10363
|
{ deep: true }
|
|
10335
10364
|
);
|
|
10336
10365
|
const themeMode = computed(
|
|
10337
|
-
() => resolveMode(
|
|
10366
|
+
() => resolveMode(
|
|
10367
|
+
themeState.value.mode,
|
|
10368
|
+
prefersDark.value,
|
|
10369
|
+
props.detectHostTheme ? hostDark.value : null
|
|
10370
|
+
)
|
|
10338
10371
|
);
|
|
10339
10372
|
const themeVars = computed(() => buildThemeVars({ ...themeState.value, mode: themeMode.value }));
|
|
10340
10373
|
const dark = computed(() => themeMode.value === "dark");
|
|
@@ -11970,21 +12003,42 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
11970
12003
|
return {};
|
|
11971
12004
|
return { left: r.left + "px", top: r.top + "px", width: r.width + "px", height: r.height + "px" };
|
|
11972
12005
|
}
|
|
12006
|
+
function rightFit() {
|
|
12007
|
+
return layout.value.totalWidth <= viewportW.value;
|
|
12008
|
+
}
|
|
11973
12009
|
function headerClipStyle(side) {
|
|
11974
|
-
|
|
12010
|
+
if (side === "left")
|
|
12011
|
+
return { left: "0px", width: layout.value.leftWidth + "px" };
|
|
12012
|
+
return rightFit() ? {
|
|
12013
|
+
left: layout.value.totalWidth - layout.value.rightWidth + "px",
|
|
12014
|
+
right: "auto",
|
|
12015
|
+
width: layout.value.rightWidth + "px"
|
|
12016
|
+
} : { right: "0px", width: layout.value.rightWidth + "px" };
|
|
11975
12017
|
}
|
|
11976
12018
|
function fixedLayerStyle(side) {
|
|
11977
12019
|
const clip = { height: viewportH.value + "px", overflow: "hidden" };
|
|
11978
|
-
|
|
11979
|
-
|
|
11980
|
-
|
|
11981
|
-
|
|
11982
|
-
|
|
11983
|
-
|
|
11984
|
-
|
|
12020
|
+
if (side === "left") {
|
|
12021
|
+
return {
|
|
12022
|
+
position: "absolute",
|
|
12023
|
+
left: "0px",
|
|
12024
|
+
top: "0px",
|
|
12025
|
+
width: layout.value.leftWidth + "px",
|
|
12026
|
+
...clip
|
|
12027
|
+
};
|
|
12028
|
+
}
|
|
12029
|
+
if (rightFit()) {
|
|
12030
|
+
return {
|
|
12031
|
+
position: "absolute",
|
|
12032
|
+
left: layout.value.totalWidth - layout.value.rightWidth + "px",
|
|
12033
|
+
right: "auto",
|
|
12034
|
+
top: "0px",
|
|
12035
|
+
width: layout.value.rightWidth + "px",
|
|
12036
|
+
...clip
|
|
12037
|
+
};
|
|
12038
|
+
}
|
|
12039
|
+
return {
|
|
11985
12040
|
position: "absolute",
|
|
11986
12041
|
right: "0px",
|
|
11987
|
-
// 基类 .rj-fixed-layer 带 left:0,绝对定位下 left 会压过 right → 必须显式 auto,否则右冻结层贴到左边缘
|
|
11988
12042
|
left: "auto",
|
|
11989
12043
|
top: "0px",
|
|
11990
12044
|
width: layout.value.rightWidth + "px",
|
|
@@ -24,6 +24,8 @@ declare const _default: __VLS_WithTemplateSlots<import("vue").DefineComponent<im
|
|
|
24
24
|
height?: string | number | undefined;
|
|
25
25
|
loading?: boolean | undefined;
|
|
26
26
|
theme?: RjThemeParams | "light" | "dark" | undefined;
|
|
27
|
+
/** 未显式指定主题时,是否自动跟随宿主 <html> 的 dark/light class(element-plus/vben/tailwind 约定);默认 true */
|
|
28
|
+
detectHostTheme?: boolean | undefined;
|
|
27
29
|
density?: "small" | "medium" | "large" | undefined;
|
|
28
30
|
/** 语言:'zh' | 'en' | 区域标识(内部归一),默认中文 */
|
|
29
31
|
lang?: string | undefined;
|
|
@@ -151,6 +153,7 @@ declare const _default: __VLS_WithTemplateSlots<import("vue").DefineComponent<im
|
|
|
151
153
|
}>, {
|
|
152
154
|
rows: () => never[];
|
|
153
155
|
height: string;
|
|
156
|
+
detectHostTheme: boolean;
|
|
154
157
|
density: string;
|
|
155
158
|
showToolbar: boolean;
|
|
156
159
|
quickFilterEnabled: boolean;
|
|
@@ -250,6 +253,8 @@ declare const _default: __VLS_WithTemplateSlots<import("vue").DefineComponent<im
|
|
|
250
253
|
height?: string | number | undefined;
|
|
251
254
|
loading?: boolean | undefined;
|
|
252
255
|
theme?: RjThemeParams | "light" | "dark" | undefined;
|
|
256
|
+
/** 未显式指定主题时,是否自动跟随宿主 <html> 的 dark/light class(element-plus/vben/tailwind 约定);默认 true */
|
|
257
|
+
detectHostTheme?: boolean | undefined;
|
|
253
258
|
density?: "small" | "medium" | "large" | undefined;
|
|
254
259
|
/** 语言:'zh' | 'en' | 区域标识(内部归一),默认中文 */
|
|
255
260
|
lang?: string | undefined;
|
|
@@ -377,6 +382,7 @@ declare const _default: __VLS_WithTemplateSlots<import("vue").DefineComponent<im
|
|
|
377
382
|
}>, {
|
|
378
383
|
rows: () => never[];
|
|
379
384
|
height: string;
|
|
385
|
+
detectHostTheme: boolean;
|
|
380
386
|
density: string;
|
|
381
387
|
showToolbar: boolean;
|
|
382
388
|
quickFilterEnabled: boolean;
|
|
@@ -477,6 +483,7 @@ declare const _default: __VLS_WithTemplateSlots<import("vue").DefineComponent<im
|
|
|
477
483
|
rows: RjRowData[];
|
|
478
484
|
pageSize: number;
|
|
479
485
|
queryFields: RjQueryFieldDef[];
|
|
486
|
+
detectHostTheme: boolean;
|
|
480
487
|
showToolbar: boolean;
|
|
481
488
|
quickFilterEnabled: boolean;
|
|
482
489
|
floatingFilters: boolean;
|
|
@@ -29,5 +29,9 @@ export interface RjThemeParams {
|
|
|
29
29
|
* 纯函数:无 DOM / 无时间戳 / 无随机,确定性可单测/快照。
|
|
30
30
|
*/
|
|
31
31
|
export declare function buildThemeVars(params?: RjThemeParams): Record<string, string>;
|
|
32
|
-
/**
|
|
33
|
-
|
|
32
|
+
/**
|
|
33
|
+
* 解析 auto → light/dark(组件侧调用)。
|
|
34
|
+
* 三级优先级:显式 mode(dark/light)> 宿主 <html>.dark/.light class(hostDark,null 表示宿主未表态)> OS prefers-color-scheme。
|
|
35
|
+
* hostDark 作为可选第三参并默认 null,保持既有两参调用与测试不受影响。
|
|
36
|
+
*/
|
|
37
|
+
export declare function resolveMode(mode: RjThemeParams['mode'], prefersDark: boolean, hostDark?: boolean | null): 'light' | 'dark';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rj-grid",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.8",
|
|
4
4
|
"description": "零第三方依赖的自研 Vue3 虚拟表格:虚拟滚动 / 冻结列 / 行拖拽 / 分组透视 / 公式 / SSRM / 主题 i18n / 自然语言查询",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -45,21 +45,6 @@
|
|
|
45
45
|
"optional": true
|
|
46
46
|
}
|
|
47
47
|
},
|
|
48
|
-
"scripts": {
|
|
49
|
-
"start": "vite --config vite.playground.config.ts",
|
|
50
|
-
"dev": "vite --config vite.playground.config.ts",
|
|
51
|
-
"build:play": "vite build --config vite.playground.config.ts",
|
|
52
|
-
"preview:play": "vite preview --config vite.playground.config.ts",
|
|
53
|
-
"build": "node ./node_modules/vite/bin/vite.js build --config vite.lib.config.ts && node --max_old_space_size=8192 ./node_modules/vue-tsc/bin/vue-tsc.js -p tsconfig.types.json && node build/rjDistCheck.mjs",
|
|
54
|
-
"check:dist": "node build/rjDistCheck.mjs",
|
|
55
|
-
"test": "esbuild __tests__/run.ts --bundle --platform=node --format=cjs --external:vue --outfile=node_modules/.cache/rjtest.cjs --log-level=error && node node_modules/.cache/rjtest.cjs",
|
|
56
|
-
"lint": "eslint --fix --ext .ts,.vue index.ts src __tests__ playground && stylelint \"src/styles/*.scss\"",
|
|
57
|
-
"ts": "node --max_old_space_size=8192 ./node_modules/vue-tsc/bin/vue-tsc.js --noEmit -p tsconfig.json",
|
|
58
|
-
"size": "node ./node_modules/vite/bin/vite.js build --config vite.size.config.ts && node build/rjSizeReport.mjs",
|
|
59
|
-
"publish:github": "node scripts/publish-github.mjs",
|
|
60
|
-
"publish:github:push": "node scripts/publish-github.mjs --push",
|
|
61
|
-
"prepublishOnly": "pnpm build && pnpm test"
|
|
62
|
-
},
|
|
63
48
|
"keywords": [
|
|
64
49
|
"vue3",
|
|
65
50
|
"virtual-table",
|
|
@@ -89,5 +74,19 @@
|
|
|
89
74
|
"vue": "3.5.12",
|
|
90
75
|
"vue-eslint-parser": "^9.3.2",
|
|
91
76
|
"vue-tsc": "^1.8.27"
|
|
77
|
+
},
|
|
78
|
+
"scripts": {
|
|
79
|
+
"start": "vite --config vite.playground.config.ts",
|
|
80
|
+
"dev": "vite --config vite.playground.config.ts",
|
|
81
|
+
"build:play": "vite build --config vite.playground.config.ts",
|
|
82
|
+
"preview:play": "vite preview --config vite.playground.config.ts",
|
|
83
|
+
"build": "node ./node_modules/vite/bin/vite.js build --config vite.lib.config.ts && node --max_old_space_size=8192 ./node_modules/vue-tsc/bin/vue-tsc.js -p tsconfig.types.json && node build/rjDistCheck.mjs",
|
|
84
|
+
"check:dist": "node build/rjDistCheck.mjs",
|
|
85
|
+
"test": "esbuild __tests__/run.ts --bundle --platform=node --format=cjs --external:vue --outfile=node_modules/.cache/rjtest.cjs --log-level=error && node node_modules/.cache/rjtest.cjs",
|
|
86
|
+
"lint": "eslint --fix --ext .ts,.vue index.ts src __tests__ playground && stylelint \"src/styles/*.scss\"",
|
|
87
|
+
"ts": "node --max_old_space_size=8192 ./node_modules/vue-tsc/bin/vue-tsc.js --noEmit -p tsconfig.json",
|
|
88
|
+
"size": "node ./node_modules/vite/bin/vite.js build --config vite.size.config.ts && node build/rjSizeReport.mjs",
|
|
89
|
+
"publish:github": "node scripts/publish-github.mjs",
|
|
90
|
+
"publish:github:push": "node scripts/publish-github.mjs --push"
|
|
92
91
|
}
|
|
93
|
-
}
|
|
92
|
+
}
|