@djangocfg/ui-tools 2.1.419 → 2.1.420
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 +51 -224
- package/package.json +6 -6
- package/src/tools/data/DataGrid/README.md +48 -0
- package/src/tools/data/DataTable/README.md +42 -0
- package/src/tools/dev/Mermaid/README.md +46 -0
- package/src/tools/input/CronScheduler/README.md +61 -0
- package/src/tools/visual/charts/Gauge/README.md +45 -0
package/README.md
CHANGED
|
@@ -6,264 +6,91 @@
|
|
|
6
6
|
|
|
7
7
|
# @djangocfg/ui-tools
|
|
8
8
|
|
|
9
|
-
Heavy React
|
|
9
|
+
Heavy, lazy-loaded React components for admin, devtools, and dashboards. Pairs with [`@djangocfg/ui-core`](../ui-core) (primitives + theme tokens).
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
Every tool is `React.lazy` by default — import what you use, pay only its bundle cost.
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
pnpm add @djangocfg/ui-tools
|
|
15
|
-
```
|
|
16
|
-
|
|
17
|
-
---
|
|
18
|
-
|
|
19
|
-
## What's inside
|
|
20
|
-
|
|
21
|
-
Sixteen tools, each one lazy-loaded so it doesn't ship until used. Bundle size is the gzipped tool by itself; deps (mapbox, monaco, etc.) load on first render.
|
|
22
|
-
|
|
23
|
-
| Tool | Bundle | Docs |
|
|
24
|
-
|------|--------|------|
|
|
25
|
-
| `Map` | ~800KB | MapLibre maps, markers, clusters, layers. [README](src/tools/Map/README.md) |
|
|
26
|
-
| `Mermaid` | ~800KB | Diagrams + declarative builders |
|
|
27
|
-
| `CodeEditor` | ~550KB | Monaco editor + diff view |
|
|
28
|
-
| `PrettyCode` | ~500KB | Syntax-highlighted read-only code |
|
|
29
|
-
| `OpenapiViewer` | ~400KB | OpenAPI schema viewer + playground |
|
|
30
|
-
| `JsonForm` | ~300KB | JSON-Schema-driven form generator |
|
|
31
|
-
| `MarkdownEditor` | ~200KB | Tiptap WYSIWYG with `@`-mentions |
|
|
32
|
-
| `LottiePlayer` | ~200KB | Lottie animation player |
|
|
33
|
-
| `Chat` | ~150KB | Streaming chat (SSE + tool calls + attachments). [README](src/tools/Chat/README.md) |
|
|
34
|
-
| `SpeechRecognition` | ~40KB | Mic capture + STT with pluggable engines (Web Speech / HTTP / WS). [README](src/tools/SpeechRecognition/README.md) |
|
|
35
|
-
| `VideoPlayer` | ~12KB core | media-chrome player — YouTube / Vimeo / HLS / MP4 in one composable shell. [README](src/tools/VideoPlayer/README.md) |
|
|
36
|
-
| `MarkdownMessage` | ~120KB | Read-only chat-tuned markdown. **SSR-safe** — use as a Client Component, the result is server-rendered. [README](src/components/markdown/MarkdownMessage/README.md) |
|
|
37
|
-
| `JsonTree` | ~100KB | JSON visualization (full/compact/inline modes) |
|
|
38
|
-
| `AudioPlayer` | ~80KB | WebView-safe waveform player |
|
|
39
|
-
| `Gallery` | ~50KB | Image/video gallery + lightbox |
|
|
40
|
-
| `ImageViewer` | ~50KB | Zoom/pan/rotate viewer |
|
|
41
|
-
| `CronScheduler` | ~15KB | Cron expression builder |
|
|
42
|
-
| `Masonry` | ~8KB | Virtualised window-scroll masonry grid with column balancing. [README](src/tools/data/Masonry/README.md) |
|
|
43
|
-
|
|
44
|
-
Plus utility primitives: `Tree`, `Tour` (with spotlight overlay), `FileIcon`, `UploadDropzone`.
|
|
13
|
+
## Install
|
|
45
14
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
## Imports
|
|
49
|
-
|
|
50
|
-
**There is no root barrel** — `import … from '@djangocfg/ui-tools'` is intentionally **not** supported. Always import from a tool subpath.
|
|
51
|
-
|
|
52
|
-
Why: a root barrel plus per-tool subpaths would inevitably ship the same modules twice (the bundled `dist/` copy via the root, plus the raw `src/` copy via the subpath). Different physical modules mean different `React.createContext()` instances — `ChatProvider`, `MapProvider`, `TreeProvider` all silently break across the boundary.
|
|
53
|
-
|
|
54
|
-
The TypeScript / bundler error you'll see is `Cannot find module '@djangocfg/ui-tools'`. That's intentional; fix it by picking a subpath:
|
|
55
|
-
|
|
56
|
-
```tsx
|
|
57
|
-
import { LazyJsonTree } from '@djangocfg/ui-tools/json-tree';
|
|
58
|
-
import { Gallery } from '@djangocfg/ui-tools/gallery';
|
|
59
|
-
import { LazyMapContainer, MapMarker } from '@djangocfg/ui-tools/map';
|
|
60
|
-
import { MarkdownMessage } from '@djangocfg/ui-tools/markdown-message';
|
|
61
|
-
import { LazyEditor, useMonaco } from '@djangocfg/ui-tools/code-editor';
|
|
62
|
-
import { LazyChat, createPydanticAIChatTransport } from '@djangocfg/ui-tools/chat';
|
|
63
|
-
import { LazyMarkdownEditor, mentionPresets } from '@djangocfg/ui-tools/markdown-editor';
|
|
64
|
-
import { LazyPlayer, PlayerProvider } from '@djangocfg/ui-tools/audio-player';
|
|
65
|
-
// …same pattern for every tool
|
|
15
|
+
```bash
|
|
16
|
+
pnpm add @djangocfg/ui-tools @djangocfg/ui-core
|
|
66
17
|
```
|
|
67
18
|
|
|
68
|
-
|
|
19
|
+
Wrap your app in `<UiProviders>` from `@djangocfg/ui-core` once at the root (gives Tooltip/Dialog/Toast context to every tool).
|
|
69
20
|
|
|
70
|
-
|
|
71
|
-
- **Lazy primitives co-exist with light primitives.** `./map` exports `LazyMapContainer` (heavy MapLibre GL) plus `MapMarker` / `MapPopup` etc. — the markers are thin `react-map-gl` wrappers that don't import the heavy lib at module scope.
|
|
72
|
-
- **Synchronous, SSR-safe.** `./markdown-message` is intentionally not lazy — the component is `'use client'` but produces plain HTML, so Next renders it on the server.
|
|
21
|
+
## Catalogue
|
|
73
22
|
|
|
74
|
-
|
|
|
75
|
-
|
|
76
|
-
|
|
|
77
|
-
|
|
|
78
|
-
|
|
|
79
|
-
|
|
|
80
|
-
|
|
|
81
|
-
|
|
|
82
|
-
|
|
|
83
|
-
|
|
|
84
|
-
|
|
|
85
|
-
|
|
|
86
|
-
|
|
|
23
|
+
| Group | Tools |
|
|
24
|
+
|---|---|
|
|
25
|
+
| `chat/` | ChatLauncher, MessageList, Composer, SuggestedPrompts |
|
|
26
|
+
| `data/` | DataGrid · DataTable · JsonTree · Kanban · Listbox · Masonry · Timeline · Tree |
|
|
27
|
+
| `dev/code/` | PrettyCode · DiffViewer · MarkdownMessage |
|
|
28
|
+
| `dev/api/` | OpenapiViewer · ApiRefTable · RequestViewer |
|
|
29
|
+
| `dev/ops/` | LogViewer · EnvTable |
|
|
30
|
+
| `dev/` (top) | Mermaid · Map |
|
|
31
|
+
| `forms/` | CodeEditor (Monaco) · JsonEditor · JsonForm · MarkdownEditor · NotionEditor · FileUpload · Uploader |
|
|
32
|
+
| `input/` | Combobox · CronScheduler (+ CronPreview) · Scroller · Sortable · SpeechRecognition |
|
|
33
|
+
| `media/` | AudioPlayer · VideoPlayer · ImageViewer · LottiePlayer · Gallery |
|
|
34
|
+
| `overlay/` | ResponsiveDialog · ScrollSpy · SelectionToolbar · Tour |
|
|
35
|
+
| `visual/charts/` | Gauge · ActivityGraph · CommitGraph · Sparkline |
|
|
36
|
+
| `visual/indicators/` | StatusIndicator · Fps · Rating |
|
|
37
|
+
| `visual/design/` | ColorPicker · ColorPalette · FileIcon |
|
|
38
|
+
| `visual/` (top) | Marquee · QRCode |
|
|
87
39
|
|
|
88
|
-
|
|
40
|
+
Sub-grouping is internal — public imports stay flat.
|
|
89
41
|
|
|
90
|
-
|
|
91
|
-
regardless of the host UI theme. Same convention as GitHub, VSCode,
|
|
92
|
-
ChatGPT, Chrome DevTools. Syntax highlighting / typed-value coloring
|
|
93
|
-
ship their own contrast model — mixing them with light UI surfaces
|
|
94
|
-
flattens everything into low-contrast pastels.
|
|
95
|
-
|
|
96
|
-
The chrome (border, padding, toolbars) still uses semantic UI tokens.
|
|
97
|
-
Only the *content surface* is fixed. See per-tool READMEs for details.
|
|
98
|
-
|
|
99
|
-
---
|
|
100
|
-
|
|
101
|
-
## Lazy loading
|
|
102
|
-
|
|
103
|
-
Every heavy tool ships in two flavors:
|
|
104
|
-
|
|
105
|
-
- `Lazy*` — wrapped in `React.lazy` + `Suspense` + skeleton. Use by default.
|
|
106
|
-
- bare tool (`Mermaid`, `JsonTree`, …) — for explicit loading control.
|
|
42
|
+
## Usage
|
|
107
43
|
|
|
108
44
|
```tsx
|
|
109
|
-
import {
|
|
45
|
+
import { JsonTree, LogViewer, DiffViewer, CronScheduler } from '@djangocfg/ui-tools';
|
|
110
46
|
|
|
111
|
-
<
|
|
112
|
-
<
|
|
47
|
+
<JsonTree data={response} compactHeader />
|
|
48
|
+
<LogViewer entries={logs} />
|
|
49
|
+
<DiffViewer oldCode={a} newCode={b} language="ts" view="split" />
|
|
50
|
+
<CronScheduler value={cron} onChange={setCron} />
|
|
113
51
|
```
|
|
114
52
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
---
|
|
118
|
-
|
|
119
|
-
## Chat — quick start
|
|
120
|
-
|
|
121
|
-
The most-used tool. Headless reducer + composable UI: streaming SSE transport, pydantic-AI mapper, decomposed parts (`MessageBubble`, `Composer`, `MessageList`, `ToolCalls`, …), role-aware styling. Floating launcher with FAB, popover/side dock, proactive greeting, live-push notifications, audio mute toggle, reset-with-confirm, Linear-style hotkeys.
|
|
53
|
+
Subpath imports avoid loading siblings:
|
|
122
54
|
|
|
123
55
|
```tsx
|
|
124
|
-
import {
|
|
125
|
-
|
|
126
|
-
ChatRoot,
|
|
127
|
-
createPydanticAIChatTransport,
|
|
128
|
-
} from '@djangocfg/ui-tools/chat';
|
|
129
|
-
|
|
130
|
-
const transport = createPydanticAIChatTransport({
|
|
131
|
-
buildStreamUrl: (sid, msg) => `${API}/chat/sessions/${sid}/stream?message=${encodeURIComponent(msg)}`,
|
|
132
|
-
streamMethod: 'GET',
|
|
133
|
-
buildHeaders: async () => ({ Authorization: `Bearer ${getToken()}` }),
|
|
134
|
-
});
|
|
135
|
-
|
|
136
|
-
function Chat() {
|
|
137
|
-
// ChatLauncher mounts <ChatProvider> internally — pass transport / audio /
|
|
138
|
-
// config here, then render <ChatRoot /> as a child without props.
|
|
139
|
-
return (
|
|
140
|
-
<ChatLauncher
|
|
141
|
-
transport={transport}
|
|
142
|
-
audio={{}} // ChatAudioConfig (sounds map). `{}` uses bundled defaults.
|
|
143
|
-
hotkey={{ key: '/', meta: true }}
|
|
144
|
-
fab={{ variant: 'animated' }} // size='responsive' default — phone/tablet/desktop
|
|
145
|
-
dock={{ title: 'Assistant', height: 600 }}
|
|
146
|
-
greeting="Hi 👋 Need help?"
|
|
147
|
-
headerSlots={{ // declarative header buttons, rendered inside the provider
|
|
148
|
-
languagePicker: true,
|
|
149
|
-
modeToggle: { persistAs: 'my.chat.dock' },
|
|
150
|
-
reset: {
|
|
151
|
-
onReset: async () => { await api.clearChat(); return true; },
|
|
152
|
-
},
|
|
153
|
-
}}
|
|
154
|
-
>
|
|
155
|
-
<ChatRoot />
|
|
156
|
-
</ChatLauncher>
|
|
157
|
-
);
|
|
158
|
-
}
|
|
56
|
+
import { JsonTree } from '@djangocfg/ui-tools/json-tree';
|
|
57
|
+
import { LogViewer } from '@djangocfg/ui-tools/log-viewer';
|
|
159
58
|
```
|
|
160
59
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
Need a fully custom input row (e.g. mention autocomplete via `MarkdownEditor`)? Pass `composer={{ render: ({ composer }) => <YourComposer composer={composer} /> }}` to `<ChatRoot>` — it replaces the default `<Composer>` while keeping autoscroll, JumpToLatest, and history behaviour. Story: `UI Tools / Chat / Composer / Mentions`.
|
|
164
|
-
|
|
165
|
-
Drop `<VoiceComposerSlot />` from `@djangocfg/ui-tools/speech-recognition` into the composer's `slots.blockStart` (`composer={{ slots: { blockStart: <VoiceComposerSlot /> } }}`) for live mic-to-text — **zero props**, reads / writes the composer through `ComposerHandle` registered in chat context. Set `headerSlots={{ languagePicker: true }}` on `<ChatLauncher>` for a flag-button language picker (66 BCP-47 tags). Both auto-hide on Firefox / in-app browsers / missing `getUserMedia`. See [`SpeechRecognition`](#speech-recognition--quick-start) below.
|
|
60
|
+
## Theming
|
|
166
61
|
|
|
167
|
-
|
|
62
|
+
All tools render through `@djangocfg/ui-core` semantic tokens (`bg-card`, `text-foreground`, `border-border`, status surfaces) — they adapt automatically to light/dark and to the theme presets in ui-core.
|
|
168
63
|
|
|
169
|
-
|
|
64
|
+
Two intentional exceptions, both opt-in via prop:
|
|
170
65
|
|
|
171
|
-
|
|
66
|
+
- **`PrettyCode`** — fixed dark surface regardless of UI theme. Code blocks ship their own contrast model (GitHub/VSCode/ChatGPT convention); mixing with light UI produces low-contrast pastel renders. Override via `mode="light"`.
|
|
67
|
+
- **`DiffViewer`** — adaptive; uses `themes.github` on light, `themes.vsDark` on dark via `useResolvedTheme()`.
|
|
172
68
|
|
|
173
|
-
|
|
69
|
+
Canvas/SVG components (charts, viz) sample theme colors via `useThemeColor`/`alpha` from `@djangocfg/ui-core/styles/palette` — never `color-mix`/`oklch` strings (Canvas2D rejects them).
|
|
174
70
|
|
|
175
|
-
##
|
|
176
|
-
|
|
177
|
-
Decomposed STT (Speech-to-Text) tool. Headless hook + composable UI + lazy bundle, same shape as `Chat` and `AudioPlayer`. Default backend is the browser Web Speech API (zero deps, zero network); custom engines plug in via a small interface — Deepgram, AssemblyAI, OpenAI Whisper REST, your own gateway, all without vendor SDKs on the critical path.
|
|
178
|
-
|
|
179
|
-
```tsx
|
|
180
|
-
import {
|
|
181
|
-
DictationButton,
|
|
182
|
-
TranscriptView,
|
|
183
|
-
useSpeechRecognition,
|
|
184
|
-
} from '@djangocfg/ui-tools/speech-recognition';
|
|
185
|
-
|
|
186
|
-
function Dictate() {
|
|
187
|
-
const rec = useSpeechRecognition(); // Web Speech engine, browser language
|
|
188
|
-
return (
|
|
189
|
-
<>
|
|
190
|
-
<DictationButton status={rec.status} onClick={() => rec.toggle()} />
|
|
191
|
-
<TranscriptView transcript={rec.transcript} />
|
|
192
|
-
</>
|
|
193
|
-
);
|
|
194
|
-
}
|
|
195
|
-
```
|
|
196
|
-
|
|
197
|
-
For the chat composer:
|
|
198
|
-
|
|
199
|
-
```tsx
|
|
200
|
-
import { VoiceComposerSlot } from '@djangocfg/ui-tools/speech-recognition';
|
|
201
|
-
|
|
202
|
-
<ChatRoot
|
|
203
|
-
transport={transport}
|
|
204
|
-
composer={{ slots: { blockStart: <VoiceComposerSlot /> } }}
|
|
205
|
-
/>
|
|
206
|
-
|
|
207
|
-
// Plus a flag-button language picker in the dock header:
|
|
208
|
-
<ChatLauncher headerSlots={{ languagePicker: true }} ... >
|
|
209
|
-
```
|
|
210
|
-
|
|
211
|
-
**What's wired by default:** auto-hide on Firefox / in-app WebViews / missing `getUserMedia` (via `useVoiceSupport`); live interim+final stream into the composer via `ComposerHandle` (works transparently for the built-in textarea Composer and a TipTap MarkdownEditor); typed prefix anchored; focus + cursor-to-end on start and every partial; 90-second countdown + 2.5-second silence auto-stop; Esc cancels (without closing the chat) / Enter finishes (without submitting); persisted prefs (`djangocfg-stt:prefs`); `<SpeechRecognitionProvider>` for sharing engine state across the tree. Language picker shows 66 BCP-47 tags sourced from the Chrome Web Speech demo with country flags. Custom engines through `createHttpEngine` (REST/Whisper), `createWebSocketEngine` (Deepgram-style streaming), or `createExternalEngine` (Wails / Tauri / native sidecar — `onStart` / `onStop` / `subscribe` and you're done).
|
|
212
|
-
|
|
213
|
-
Full docs: [`SpeechRecognition/README.md`](src/tools/SpeechRecognition/README.md). Stories: `UI Tools/Speech/{Dictation, ComposerSlot, PushToTalk, MicMeter, Engines, Languages, Errors}` + `UI Tools/Chat/Composer/Speech & Attachments` and `UI Tools/Chat/Launcher/Playground` (flag-button picker in the dock header). Unit-tested with vitest (`pnpm test`, 21 cases).
|
|
214
|
-
|
|
215
|
-
---
|
|
216
|
-
|
|
217
|
-
## Markdown
|
|
218
|
-
|
|
219
|
-
Read-only `<MarkdownMessage>` powers every chat bubble. Stays useful standalone for docs, AI replies, system messages.
|
|
220
|
-
|
|
221
|
-
```tsx
|
|
222
|
-
import { MarkdownMessage } from '@djangocfg/ui-tools/markdown-message';
|
|
223
|
-
|
|
224
|
-
<MarkdownMessage content="# Hello\n\nGFM + emoji 😄 + code:\n\n```ts\nconst x = 1;\n```" />
|
|
225
|
-
```
|
|
226
|
-
|
|
227
|
-
GFM, soft line breaks, smart typography, emoji shortcodes, sanitized HTML, mermaid blocks, syntax-highlighted code, declarative `linkRules` for custom URL schemes (e.g. `cmdop://`, `vehicle://`). Details: [`MarkdownMessage/README.md`](src/tools/MarkdownMessage/README.md).
|
|
228
|
-
|
|
229
|
-
---
|
|
230
|
-
|
|
231
|
-
## Map
|
|
232
|
-
|
|
233
|
-
MapLibre GL maps with markers, clusters, layers, drawing, geocoding. Subpath: `@djangocfg/ui-tools/map`. Details: [`Map/README.md`](src/tools/Map/README.md).
|
|
234
|
-
|
|
235
|
-
```tsx
|
|
236
|
-
import { MapContainer, MapMarker } from '@djangocfg/ui-tools/map';
|
|
71
|
+
## Lazy loading
|
|
237
72
|
|
|
238
|
-
|
|
239
|
-
<MapMarker position={[37.6, 55.7]} />
|
|
240
|
-
</MapContainer>
|
|
241
|
-
```
|
|
73
|
+
Every tool's default export is `React.lazy`-wrapped; initial bundle stays small. Heaviest:
|
|
242
74
|
|
|
243
|
-
|
|
75
|
+
Mermaid ~800KB · Monaco CodeEditor ~550KB · PrettyCode (shiki) ~500KB · OpenapiViewer ~400KB · JsonForm ~300KB · AudioPlayer (WaveSurfer) ~200KB · LottiePlayer ~200KB · NotionEditor (TipTap) ~200KB · VideoPlayer (media-chrome) ~150KB · JsonTree ~100KB · ImageViewer ~50KB · CronScheduler ~15KB.
|
|
244
76
|
|
|
245
|
-
|
|
77
|
+
Works in Next.js, Vite, Wails, CRA — no framework lock-in.
|
|
246
78
|
|
|
247
|
-
##
|
|
79
|
+
## Build discipline
|
|
248
80
|
|
|
249
|
-
|
|
81
|
+
After any `src/` change, **run `pnpm build`** before considering the change done — consumers pick up `dist/` via `pnpm sync:cfg`; a stale `dist/` ships old code silently. See [`CLAUDE.md`](./CLAUDE.md) for details.
|
|
250
82
|
|
|
251
83
|
```bash
|
|
252
|
-
pnpm
|
|
84
|
+
pnpm build # rebuild dist/ (tsup)
|
|
85
|
+
pnpm check # tsc --noEmit
|
|
253
86
|
```
|
|
254
87
|
|
|
255
|
-
Open browser to the URL printed in the console. Categories: `Tools/<ToolName>` plus per-feature subsections for Chat and Map.
|
|
256
|
-
|
|
257
|
-
---
|
|
258
|
-
|
|
259
88
|
## Requirements
|
|
260
89
|
|
|
261
|
-
- React 18
|
|
262
|
-
-
|
|
263
|
-
-
|
|
264
|
-
|
|
265
|
-
---
|
|
90
|
+
- React 18 or 19
|
|
91
|
+
- `@djangocfg/ui-core` (peer)
|
|
92
|
+
- Tailwind CSS v4 (host imports `@djangocfg/ui-core/styles`)
|
|
266
93
|
|
|
267
94
|
## License
|
|
268
95
|
|
|
269
|
-
MIT —
|
|
96
|
+
MIT — © djangocfg.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@djangocfg/ui-tools",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.420",
|
|
4
4
|
"description": "Heavy React tools with lazy loading - for Electron, Vite, CRA, Next.js apps",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ui-tools",
|
|
@@ -329,8 +329,8 @@
|
|
|
329
329
|
"test:watch": "vitest"
|
|
330
330
|
},
|
|
331
331
|
"peerDependencies": {
|
|
332
|
-
"@djangocfg/i18n": "^2.1.
|
|
333
|
-
"@djangocfg/ui-core": "^2.1.
|
|
332
|
+
"@djangocfg/i18n": "^2.1.420",
|
|
333
|
+
"@djangocfg/ui-core": "^2.1.420",
|
|
334
334
|
"consola": "^3.4.2",
|
|
335
335
|
"lodash-es": "^4.18.1",
|
|
336
336
|
"lucide-react": "^0.545.0",
|
|
@@ -405,9 +405,9 @@
|
|
|
405
405
|
"@maplibre/maplibre-gl-geocoder": "^1.7.0"
|
|
406
406
|
},
|
|
407
407
|
"devDependencies": {
|
|
408
|
-
"@djangocfg/i18n": "^2.1.
|
|
409
|
-
"@djangocfg/typescript-config": "^2.1.
|
|
410
|
-
"@djangocfg/ui-core": "^2.1.
|
|
408
|
+
"@djangocfg/i18n": "^2.1.420",
|
|
409
|
+
"@djangocfg/typescript-config": "^2.1.420",
|
|
410
|
+
"@djangocfg/ui-core": "^2.1.420",
|
|
411
411
|
"@types/lodash-es": "^4.17.12",
|
|
412
412
|
"@types/mapbox__mapbox-gl-draw": "^1.4.8",
|
|
413
413
|
"@types/node": "^25.2.3",
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# DataGrid
|
|
2
|
+
|
|
3
|
+
Headless data grid with built-in sort / filter / pagination / selection and column resizing. Composable: `<DataGrid>` is the all-in-one entry point, while `DataGridProvider` + `DataGridHeader` / `DataGridRow` / `DataGridCell` / `DataGridPagination` let you swap individual parts. Pure React, no `@tanstack/react-table` dependency.
|
|
4
|
+
|
|
5
|
+
```tsx
|
|
6
|
+
import { DataGrid } from '@djangocfg/ui-tools/data-grid';
|
|
7
|
+
|
|
8
|
+
<DataGrid
|
|
9
|
+
data={users}
|
|
10
|
+
columns={[
|
|
11
|
+
{ key: 'name', header: 'Name', sortable: true, filterable: true },
|
|
12
|
+
{ key: 'email', header: 'Email', sortable: true },
|
|
13
|
+
{ key: 'role', header: 'Role', align: 'right' },
|
|
14
|
+
]}
|
|
15
|
+
getRowId={(u) => u.id}
|
|
16
|
+
selectionMode="multiple"
|
|
17
|
+
onSelectionChange={setSelected}
|
|
18
|
+
/>
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Props
|
|
22
|
+
|
|
23
|
+
| Prop | Type | Default | Description |
|
|
24
|
+
|---|---|---|---|
|
|
25
|
+
| `data` | `T[]` | — | Row data. |
|
|
26
|
+
| `columns` | `DataGridColumn<T>[]` | — | Column defs (`key`, `header`, `cell?`, `sortable?`, `filterable?`, `width?`, `align?`, `filterFn?`). |
|
|
27
|
+
| `getRowId` | `(row: T) => string \| number` | — | Stable row id. |
|
|
28
|
+
| `selectionMode` | `'none' \| 'single' \| 'multiple'` | `'none'` | Selection behaviour. |
|
|
29
|
+
| `initialSelectedIds` / `onSelectionChange` | `RowId[]` / `(ids) => void` | — | Uncontrolled selection. |
|
|
30
|
+
| `sort` / `onSortChange` / `initialSort` | `DataGridSortState` | — | Controlled or uncontrolled sort. |
|
|
31
|
+
| `filters` / `onFilterChange` / `initialFilters` | `DataGridFilterState` | — | Per-column text filters. |
|
|
32
|
+
| `pagination` / `onPaginationChange` / `initialPagination` | `DataGridPaginationState` | — | Controlled or uncontrolled pagination. |
|
|
33
|
+
| `pageSizeOptions` | `number[]` | `[10, 25, 50, 100]` | Page-size choices. |
|
|
34
|
+
| `resizable` | `boolean` | `false` | Enable column resizing. |
|
|
35
|
+
| `stickyHeader` | `boolean` | `true` | Sticky header row. |
|
|
36
|
+
| `loading` | `boolean` | `false` | Loading state. |
|
|
37
|
+
| `emptyMessage` | `ReactNode` | — | Rendered when `data` is empty. |
|
|
38
|
+
| `getRowClassName` | `(row, i) => string` | — | Per-row class hook. |
|
|
39
|
+
| `onRowClick` / `onRowDoubleClick` | `(row) => void` | — | Row event handlers. |
|
|
40
|
+
|
|
41
|
+
## Notes
|
|
42
|
+
|
|
43
|
+
- No virtualization — for >10k rows pair with pagination or use a virtualized list above the grid.
|
|
44
|
+
- All state slots support both controlled (`sort` + `onSortChange`) and uncontrolled (`initialSort`) usage.
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
Adapted from jalcoui (MIT).
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# DataTable
|
|
2
|
+
|
|
3
|
+
Lighter sibling of `DataGrid`. Same sort / filter / pagination / selection model, but no column resizing, no sticky header, no `width`/`minWidth`/`maxWidth` per column — use when you want a plain semantic `<table>` for read-heavy lists. For resizable / sticky-header grids reach for `DataGrid` instead.
|
|
4
|
+
|
|
5
|
+
```tsx
|
|
6
|
+
import { DataTable } from '@djangocfg/ui-tools/data-table';
|
|
7
|
+
|
|
8
|
+
<DataTable
|
|
9
|
+
data={invoices}
|
|
10
|
+
columns={[
|
|
11
|
+
{ key: 'number', header: '#', sortable: true },
|
|
12
|
+
{ key: 'client', header: 'Client', filterable: true },
|
|
13
|
+
{ key: 'total', header: 'Total', align: 'right' },
|
|
14
|
+
]}
|
|
15
|
+
getRowId={(inv) => inv.id}
|
|
16
|
+
onRowClick={openInvoice}
|
|
17
|
+
/>
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Props
|
|
21
|
+
|
|
22
|
+
| Prop | Type | Default | Description |
|
|
23
|
+
|---|---|---|---|
|
|
24
|
+
| `data` | `T[]` | — | Row data. |
|
|
25
|
+
| `columns` | `DataTableColumn<T>[]` | — | Column defs (`key`, `header`, `cell?`, `sortable?`, `filterable?`, `align?`, `filterFn?`). |
|
|
26
|
+
| `getRowId` | `(row: T) => string \| number` | — | Stable row id. |
|
|
27
|
+
| `selectionMode` | `'none' \| 'single' \| 'multiple'` | `'none'` | Selection behaviour. |
|
|
28
|
+
| `initialSelectedIds` / `onSelectionChange` | `RowId[]` / `(ids) => void` | — | Uncontrolled selection. |
|
|
29
|
+
| `sort` / `onSortChange` / `initialSort` | `DataTableSortState` | — | Controlled or uncontrolled sort. |
|
|
30
|
+
| `filters` / `onFilterChange` / `initialFilters` | `DataTableFilterState` | — | Per-column text filters. |
|
|
31
|
+
| `pagination` / `onPaginationChange` / `initialPagination` | `DataTablePaginationState` | — | Controlled or uncontrolled pagination. |
|
|
32
|
+
| `pageSizeOptions` | `number[]` | `[10, 25, 50, 100]` | Page-size choices. |
|
|
33
|
+
| `loading` | `boolean` | `false` | Loading state. |
|
|
34
|
+
| `emptyMessage` | `ReactNode` | — | Rendered when `data` is empty. |
|
|
35
|
+
| `getRowClassName` | `(row, i) => string` | — | Per-row class hook. |
|
|
36
|
+
| `onRowClick` / `onRowDoubleClick` | `(row) => void` | — | Row event handlers. |
|
|
37
|
+
|
|
38
|
+
Composable parts (`DataTableProvider`, `DataTableHeader`, `DataTableRow`, `DataTablePagination`) are exported for custom compositions.
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
Adapted from jalcoui (MIT).
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# Mermaid
|
|
2
|
+
|
|
3
|
+
Mermaid diagram renderer with a typed declarative builder layer on top of the raw `chart` string. Supports the diagram types covered by the builders (`FlowDiagram`, `SequenceDiagram`, `JourneyDiagram`) plus anything else Mermaid parses (gantt, class, state, ER, pie, …) via the `chart` prop. Click-to-fullscreen via the floating toolbar.
|
|
4
|
+
|
|
5
|
+
```tsx
|
|
6
|
+
import Mermaid from '@djangocfg/ui-tools/mermaid';
|
|
7
|
+
|
|
8
|
+
<Mermaid chart={`
|
|
9
|
+
flowchart LR
|
|
10
|
+
A[Client] --> B[API] --> C[(DB)]
|
|
11
|
+
`} />
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Builder API:
|
|
15
|
+
|
|
16
|
+
```tsx
|
|
17
|
+
import Mermaid, { FlowDiagram } from '@djangocfg/ui-tools/mermaid';
|
|
18
|
+
|
|
19
|
+
const chart = new FlowDiagram({ direction: 'LR' })
|
|
20
|
+
.node('a', 'Client')
|
|
21
|
+
.node('b', 'API')
|
|
22
|
+
.edge('a', 'b')
|
|
23
|
+
.build();
|
|
24
|
+
|
|
25
|
+
<Mermaid chart={chart} />
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Props
|
|
29
|
+
|
|
30
|
+
| Prop | Type | Default | Description |
|
|
31
|
+
|---|---|---|---|
|
|
32
|
+
| `chart` | `string` | — | Mermaid source. |
|
|
33
|
+
| `isCompact` | `boolean` | `false` | Tighter padding for embedded contexts. |
|
|
34
|
+
| `fullscreen` | `boolean` | `true` | Click-to-fullscreen via the floating toolbar. |
|
|
35
|
+
| `scrollIsolation` | `boolean` | `false` | Lock page wheel while hovering. Off by default — Mermaid SVGs don't scroll, the overlay just steals wheel events. |
|
|
36
|
+
| `debounceMs` | `number` | `300` | Re-render debounce after `chart` changes. Lower for static diagrams, higher while streaming. |
|
|
37
|
+
| `className` | `string` | — | — |
|
|
38
|
+
|
|
39
|
+
## Notes
|
|
40
|
+
|
|
41
|
+
- **~800KB bundle** — entry point is already `lazy()`-wrapped with a `Suspense` spinner, so the cost is only paid when a diagram is actually mounted.
|
|
42
|
+
- Theming pulls from `useThemePalette` / `useStylePresets` / `useBoxColors` (exported alongside the builders) — Mermaid colors follow the active app theme; do not hard-code hex.
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
Adapted from jalcoui (MIT).
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# CronScheduler
|
|
2
|
+
|
|
3
|
+
Cron expression builder + read-only preview. Standard Unix 5-field format (`minute hour day-of-month month day-of-week`). Two surfaces:
|
|
4
|
+
|
|
5
|
+
- `<CronScheduler>` — interactive builder (daily / weekly / monthly / custom), popover or `inline`.
|
|
6
|
+
- `<CronPreview>` — standalone read-only summary with human description and next run times.
|
|
7
|
+
|
|
8
|
+
```tsx
|
|
9
|
+
import { CronScheduler, CronPreview } from '@djangocfg/ui-tools/cron-scheduler';
|
|
10
|
+
|
|
11
|
+
// Edit
|
|
12
|
+
<CronScheduler value={cron} onChange={setCron} showCronExpression />
|
|
13
|
+
|
|
14
|
+
// Display
|
|
15
|
+
<CronPreview value="0 9 * * 1-5" nextRuns={5} />
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## `<CronScheduler>` props
|
|
19
|
+
|
|
20
|
+
| Prop | Type | Default | Description |
|
|
21
|
+
|---|---|---|---|
|
|
22
|
+
| `value` | `string` | — | Current cron expression. |
|
|
23
|
+
| `onChange` | `(cron: string) => void` | — | Fires on every valid state change. |
|
|
24
|
+
| `defaultType` | `'daily' \| 'weekly' \| 'monthly' \| 'custom'` | `'daily'` | Initial mode. |
|
|
25
|
+
| `showCronExpression` | `boolean` | `false` | Render the raw expression under the trigger. |
|
|
26
|
+
| `allowCopy` | `boolean` | `false` | Copy-to-clipboard button. |
|
|
27
|
+
| `timeFormat` | `'12h' \| '24h'` | `'24h'` | Time picker format. |
|
|
28
|
+
| `inline` | `boolean` | `false` | Expand the editor in place instead of a popover. |
|
|
29
|
+
| `size` | `'default' \| 'sm'` | `'default'` | Compact fields (`sm`) for narrow side panels / modals. |
|
|
30
|
+
| `placeholder` | `string` | — | Trigger label when no schedule is set (popover mode). |
|
|
31
|
+
| `disabled` | `boolean` | `false` | Disable all interactions. |
|
|
32
|
+
|
|
33
|
+
## `<CronPreview>` props
|
|
34
|
+
|
|
35
|
+
| Prop | Type | Default | Description |
|
|
36
|
+
|---|---|---|---|
|
|
37
|
+
| `value` | `string` | — | Cron expression to preview. Invalid values render a destructive-toned error card. |
|
|
38
|
+
| `title` | `string` | — | Optional heading above the summary. |
|
|
39
|
+
| `nextRuns` | `number` | `5` | Upcoming runs to list. `0` hides the list. |
|
|
40
|
+
| `showExpression` | `boolean` | `true` | Show the raw cron string alongside the summary. |
|
|
41
|
+
| `referenceDate` | `Date` | `new Date()` | Anchor for `getNextRuns`. |
|
|
42
|
+
|
|
43
|
+
## Utilities
|
|
44
|
+
|
|
45
|
+
Exported alongside the components for custom UIs:
|
|
46
|
+
|
|
47
|
+
- `buildCron(state)` / `parseCron(expr)` — state ↔ expression
|
|
48
|
+
- `isValidCron(expr)` — boolean validator
|
|
49
|
+
- `humanizeCron(expr)` — human-readable summary string
|
|
50
|
+
- `getNextRuns(expr, n, from?)` / `formatNextRun(date)` — upcoming run times
|
|
51
|
+
|
|
52
|
+
Advanced compositions can use `CronSchedulerProvider` + the slice hooks (`useCronType`, `useCronTime`, `useCronWeekDays`, `useCronMonthDays`, `useCronCustom`, `useCronPreview`, `useCronSize`) and field components (`ScheduleTypeSelector`, `TimeSelector`, `DayChips`, `MonthDayGrid`, `CustomInput`, `SchedulePreview`).
|
|
53
|
+
|
|
54
|
+
## Notes
|
|
55
|
+
|
|
56
|
+
- Builder is lazy-loaded (~15KB). `CronPreview` is not lazy — it ships with the entry module.
|
|
57
|
+
- `SchedulePreview` (inside the editor) and `CronPreview` (standalone) are distinct: the former reads from `CronSchedulerProvider`, the latter takes a value prop and stands alone.
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
Adapted from jalcoui (MIT).
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# Gauge
|
|
2
|
+
|
|
3
|
+
Accessible SVG meter (`role="meter"`) with composable parts: `Gauge` (root + context), `GaugeIndicator` (svg), `GaugeTrack`, `GaugeRange`, `GaugeValueText`, `GaugeLabel`. `GaugeCombined` is the all-in-one shorthand. Track / range colors come from Tailwind semantic tokens (`text-muted-foreground/20`, `text-primary`) — no Canvas, no `useThemePalette` hooks needed.
|
|
4
|
+
|
|
5
|
+
```tsx
|
|
6
|
+
import {
|
|
7
|
+
Gauge,
|
|
8
|
+
GaugeIndicator,
|
|
9
|
+
GaugeTrack,
|
|
10
|
+
GaugeRange,
|
|
11
|
+
GaugeValueText,
|
|
12
|
+
} from '@djangocfg/ui-tools/gauge';
|
|
13
|
+
|
|
14
|
+
<Gauge value={72} size={140} thickness={10} startAngle={-120} endAngle={120}>
|
|
15
|
+
<GaugeIndicator>
|
|
16
|
+
<GaugeTrack />
|
|
17
|
+
<GaugeRange />
|
|
18
|
+
</GaugeIndicator>
|
|
19
|
+
<GaugeValueText />
|
|
20
|
+
</Gauge>
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## `<Gauge>` props
|
|
24
|
+
|
|
25
|
+
| Prop | Type | Default | Description |
|
|
26
|
+
|---|---|---|---|
|
|
27
|
+
| `value` | `number \| null` | `null` | Current value. `null` / `undefined` → indeterminate state. Out-of-range values are clamped. |
|
|
28
|
+
| `min` | `number` | `0` | Lower bound. |
|
|
29
|
+
| `max` | `number` | `100` | Upper bound. Must be `> min`; otherwise auto-bumped. |
|
|
30
|
+
| `size` | `number` | `120` | Outer size in px. |
|
|
31
|
+
| `thickness` | `number` | `8` | Arc stroke width. Must be `< size`. |
|
|
32
|
+
| `startAngle` | `number` | `0` | Arc start in degrees (12 o'clock = 0). |
|
|
33
|
+
| `endAngle` | `number` | `360` | Arc end in degrees. `|end - start| >= 360` renders a full ring. |
|
|
34
|
+
| `getValueText` | `(value, min, max) => string` | percentage `0–100` | Override the text rendered inside `GaugeValueText` and announced via `aria-valuetext`. |
|
|
35
|
+
| `asChild` | `boolean` | `false` | Render-as via Radix `Slot`. |
|
|
36
|
+
|
|
37
|
+
## Notes
|
|
38
|
+
|
|
39
|
+
- All sub-parts (`GaugeIndicator`, `GaugeTrack`, `GaugeRange`, `GaugeValueText`, `GaugeLabel`) **must** be rendered under a `<Gauge>` — they throw without the context.
|
|
40
|
+
- Override colors by passing `className` to `GaugeTrack` / `GaugeRange` (they use `currentColor`, so any `text-*` token works).
|
|
41
|
+
- State is exposed via `data-state="indeterminate" | "loading" | "complete"` on every part for custom styling.
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
Adapted from jalcoui (MIT).
|