@djangocfg/ui-tools 2.1.400 → 2.1.404

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 CHANGED
@@ -79,9 +79,21 @@ Subpaths come in three flavors:
79
79
  | `@djangocfg/ui-tools/map` | `LazyMapContainer`, `LazyMapView`, plus light primitives (`MapMarker`, `MapPopup`, `MapCluster`, `MapSource`, `MapLayer`, `MapControls`, `MapProvider`, types) | The heavy MapLibre GL chunk (~800 KB) only loads when `LazyMapContainer` actually mounts. Markers and popups are thin `react-map-gl` wrappers — exported synchronously. |
80
80
  | `@djangocfg/ui-tools/markdown-message` | `MarkdownMessage`, `ChatMessageRow`, `ActionRow`, `extractTextFromChildren`, types | **SSR-safe.** The component itself is `'use client'`, but rendering produces plain HTML — Next.js will pre-render it on the server when imported from a Client Component. Use this when you want the markdown renderer without dragging in the full chat. |
81
81
  | `@djangocfg/ui-tools/<tool-name>` | One tool | `mermaid`, `speech-recognition`, `json-tree`, `pretty-code`, `openapi-viewer`, `json-form`, `lottie-player`, `video-player`, `image-viewer`, `cron-scheduler`, `gallery`, `tour`, `tree`, `file-icon`, `upload` |
82
+ | `@djangocfg/ui-tools/json-form/full` | `JsonSchemaForm`, `ObjectFieldTemplate`, `evaluateDisabledWhen`, all widgets / templates / utils | Eager bundle. Use only for storybook / internal tooling that needs the template + util APIs at module scope. Production code should import `LazyJsonSchemaForm` from `/json-form` instead. |
82
83
  | `@djangocfg/ui-tools/styles` | Tailwind source CSS | |
83
84
  | `@djangocfg/ui-tools/dist.css` | Pre-compiled CSS | |
84
85
 
86
+ ### Code & data inspectors are always-dark by design
87
+
88
+ `PrettyCode` and `JsonTree` render on a fixed dark surface (`#0d1117`)
89
+ regardless of the host UI theme. Same convention as GitHub, VSCode,
90
+ ChatGPT, Chrome DevTools. Syntax highlighting / typed-value coloring
91
+ ship their own contrast model — mixing them with light UI surfaces
92
+ flattens everything into low-contrast pastels.
93
+
94
+ The chrome (border, padding, toolbars) still uses semantic UI tokens.
95
+ Only the *content surface* is fixed. See per-tool READMEs for details.
96
+
85
97
  ---
86
98
 
87
99
  ## Lazy loading
@@ -146,6 +158,8 @@ function Chat() {
146
158
 
147
159
  **What's wired by default:** desktop side-mode toggle (auto-hides on narrow screens), persisted dock prefs, two-step Escape, click-to-focus composer, mobile fullscreen with `dvh` heights, push-preview bubble for inbound messages while closed, **ChatGPT-style autoscroll** (sticky-to-bottom within 120 px, every user-send re-anchors the viewport), **bundled chat notification sounds** (sent/received/start/error/mention/notification, ~136KB inlined as `data:`-URLs inside the lazy chat chunk — zero host setup). Native hosts (cmdop_go / Tauri) pass `audio={{ silenced: true, onSoundEvent }}` to keep web silent while routing triggers to the backend.
148
160
 
161
+ Need a fully custom input row (e.g. mention autocomplete via `MarkdownEditor`)? Pass `renderComposer={({ composer }) => <YourComposer composer={composer} />}` to `<ChatRoot>` — it replaces the default `<Composer>` while keeping autoscroll, JumpToLatest, and history behaviour. Story: `UI Tools / Chat / Mentions / Machine Mentions`.
162
+
149
163
  Drop `<VoiceComposerSlot />` from `@djangocfg/ui-tools/speech-recognition` into `composerToolbarEnd` 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.
150
164
 
151
165
  Full docs: [`Chat/README.md`](src/tools/Chat/README.md). Stories: `Tools/Chat/{Basic,Bubbles,ToolCalls,Personas,Launcher,Header,Audio & Actions,Voice composer}`.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@djangocfg/ui-tools",
3
- "version": "2.1.400",
3
+ "version": "2.1.404",
4
4
  "description": "Heavy React tools with lazy loading - for Electron, Vite, CRA, Next.js apps",
5
5
  "keywords": [
6
6
  "ui-tools",
@@ -96,6 +96,11 @@
96
96
  "import": "./src/tools/JsonForm/lazy.tsx",
97
97
  "require": "./src/tools/JsonForm/lazy.tsx"
98
98
  },
99
+ "./json-form/full": {
100
+ "types": "./src/tools/JsonForm/index.ts",
101
+ "import": "./src/tools/JsonForm/index.ts",
102
+ "require": "./src/tools/JsonForm/index.ts"
103
+ },
99
104
  "./json-tree": {
100
105
  "types": "./src/tools/JsonTree/lazy.tsx",
101
106
  "import": "./src/tools/JsonTree/lazy.tsx",
@@ -154,8 +159,8 @@
154
159
  "test:watch": "vitest"
155
160
  },
156
161
  "peerDependencies": {
157
- "@djangocfg/i18n": "^2.1.400",
158
- "@djangocfg/ui-core": "^2.1.400",
162
+ "@djangocfg/i18n": "^2.1.404",
163
+ "@djangocfg/ui-core": "^2.1.404",
159
164
  "consola": "^3.4.2",
160
165
  "lodash-es": "^4.18.1",
161
166
  "lucide-react": "^0.545.0",
@@ -209,9 +214,9 @@
209
214
  "material-file-icons": "^2.4.0"
210
215
  },
211
216
  "devDependencies": {
212
- "@djangocfg/i18n": "^2.1.400",
213
- "@djangocfg/typescript-config": "^2.1.400",
214
- "@djangocfg/ui-core": "^2.1.400",
217
+ "@djangocfg/i18n": "^2.1.404",
218
+ "@djangocfg/typescript-config": "^2.1.404",
219
+ "@djangocfg/ui-core": "^2.1.404",
215
220
  "@types/lodash-es": "^4.17.12",
216
221
  "@types/mapbox__mapbox-gl-draw": "^1.4.8",
217
222
  "@types/node": "^24.7.2",
@@ -17,7 +17,7 @@ import {
17
17
  import { JsonFormContext, JsonSchemaFormProps } from './types';
18
18
  import { normalizeFormData, validateSchema } from './utils';
19
19
  import {
20
- CheckboxWidget, ColorWidget, NumberWidget, SelectWidget, SliderWidget, SwitchWidget, TextWidget
20
+ CheckboxWidget, ColorWidget, NumberWidget, SelectWidget, SliderWidget, SwitchWidget, TextareaWidget, TextWidget
21
21
  } from './widgets';
22
22
 
23
23
  /**
@@ -104,6 +104,7 @@ export function JsonSchemaForm<T = any>(props: JsonSchemaFormProps<T>) {
104
104
  const widgets: RegistryWidgetsType = useMemo(() => ({
105
105
  // Standard widget names (PascalCase) - used by RJSF internally
106
106
  TextWidget,
107
+ TextareaWidget,
107
108
  NumberWidget,
108
109
  CheckboxWidget,
109
110
  SelectWidget,
@@ -112,6 +113,7 @@ export function JsonSchemaForm<T = any>(props: JsonSchemaFormProps<T>) {
112
113
  SliderWidget,
113
114
  // Lowercase aliases - for uiSchema 'ui:widget' references
114
115
  text: TextWidget,
116
+ textarea: TextareaWidget,
115
117
  number: NumberWidget,
116
118
  checkbox: CheckboxWidget,
117
119
  select: SelectWidget,
@@ -3,10 +3,20 @@
3
3
  Schema-driven forms on top of [react-jsonschema-form](https://github.com/rjsf-team/react-jsonschema-form) (RJSF) with `@djangocfg/ui` widgets, AJV8 validation, and a few custom extensions for compact playground-style UIs.
4
4
 
5
5
  ```tsx
6
- import { JsonSchemaForm } from '@djangocfg/ui-tools/json-form';
7
- // or, for code-splitting:
6
+ // Lazy entry what production code should import. Ships only the
7
+ // component reference + a Suspense fallback; the ~300KB RJSF bundle
8
+ // loads on first mount.
8
9
  import { LazyJsonSchemaForm } from '@djangocfg/ui-tools/json-form';
9
10
 
11
+ // Full entry — eager bundle. Use only for storybook / internal
12
+ // tooling that needs templates, widgets, or `evaluateDisabledWhen`
13
+ // at module scope. Pulls RJSF synchronously, no code-splitting.
14
+ import {
15
+ JsonSchemaForm,
16
+ ObjectFieldTemplate,
17
+ evaluateDisabledWhen,
18
+ } from '@djangocfg/ui-tools/json-form/full';
19
+
10
20
  const schema = {
11
21
  type: 'object',
12
22
  properties: {
@@ -0,0 +1,25 @@
1
+ "use client"
2
+
3
+ import React from 'react';
4
+
5
+ import type { WidgetProps } from '@rjsf/utils';
6
+
7
+ import { TextWidget } from './TextWidget';
8
+
9
+ /**
10
+ * Multiline text widget for JSON Schema Form. Thin wrapper around
11
+ * `TextWidget` that pins `options.widget = 'textarea'` so the
12
+ * underlying renderer reaches the `<textarea>` branch.
13
+ *
14
+ * Registered under the `textarea` ui:widget alias — schemas can opt
15
+ * into multiline editing without setting `ui:options.widget`:
16
+ *
17
+ * uiSchema = { description: { 'ui:widget': 'textarea' } }
18
+ *
19
+ * Honors all the same `ui:options` as `TextWidget` — most usefully
20
+ * `rows` (default `3`).
21
+ */
22
+ export function TextareaWidget(props: WidgetProps) {
23
+ const options = { ...(props.options ?? {}), widget: 'textarea' };
24
+ return <TextWidget {...props} options={options} />;
25
+ }
@@ -6,6 +6,7 @@
6
6
  */
7
7
 
8
8
  export { TextWidget } from './TextWidget';
9
+ export { TextareaWidget } from './TextareaWidget';
9
10
  export { NumberWidget } from './NumberWidget';
10
11
  export { CheckboxWidget } from './CheckboxWidget';
11
12
  export { SelectWidget } from './SelectWidget';
@@ -2,6 +2,18 @@
2
2
 
3
3
  Interactive JSON tree viewer with expand/collapse, copy, and download.
4
4
 
5
+ ## Why dark by default
6
+
7
+ JsonTree renders on a fixed dark surface (`#0d1117`) regardless of
8
+ the host UI theme — same convention as Chrome DevTools, Insomnia,
9
+ Bruno, Postman. JSON inspectors carry their own data-typed palette
10
+ (blue keys, green strings, orange numbers, red null) tuned for dark
11
+ backgrounds; mixing it with light UI tokens flattens values into
12
+ unreadable pastels.
13
+
14
+ The palette is intentionally **not** a semantic token. See PrettyCode
15
+ README for the same rationale.
16
+
5
17
  ## Structure
6
18
 
7
19
  ```
@@ -0,0 +1,81 @@
1
+ # PrettyCode
2
+
3
+ Syntax-highlighted code block. Prism-powered, dark-by-default surface.
4
+
5
+ ## Why dark by default
6
+
7
+ PrettyCode renders on a fixed dark surface (`#0d1117` + `vsDark` palette)
8
+ regardless of the host theme — the same convention as GitHub, VSCode,
9
+ ChatGPT, Slack. Syntax highlighting ships its own contrast model
10
+ (keyword / string / number / comment) that flattens to low-contrast
11
+ pastels when forced onto a light UI surface.
12
+
13
+ The surface is intentionally **not** a semantic token. Semantic tokens
14
+ (`--primary`, `--accent`, `--card`) describe UI affordances; code
15
+ display is data, not UI.
16
+
17
+ ## Structure
18
+
19
+ ```
20
+ PrettyCode/
21
+ ├── PrettyCode.client.tsx # Main component (Highlight + dark surface)
22
+ ├── registerPrismLanguages.ts # Lazy-load extra grammars (bash, ruby, java, php)
23
+ ├── index.tsx # Public re-export
24
+ └── lazy.tsx # Lazy-loaded export
25
+ ```
26
+
27
+ ## Usage
28
+
29
+ ```tsx
30
+ import { PrettyCode } from '@djangocfg/ui-tools/code';
31
+
32
+ <PrettyCode data={sourceCode} language="typescript" />
33
+
34
+ // Inline snippet (used in markdown rendering)
35
+ <PrettyCode data={`const x = 1`} language="ts" inline />
36
+
37
+ // Capped at 50 visible lines, scrolls if longer
38
+ <PrettyCode data={longBlob} language="json" maxLines={50} />
39
+
40
+ // Chrome-less variant — embed inside another scroll container
41
+ <PrettyCode data={src} language="bash" variant="plain" />
42
+ ```
43
+
44
+ ## Props
45
+
46
+ | Prop | Type | Default | Description |
47
+ |------|------|---------|-------------|
48
+ | `data` | `string \| object` | — | Code string. Objects are `JSON.stringify`d. |
49
+ | `language` | `Language` | — | Prism language id. Unknown → plain text. |
50
+ | `mode` | `'dark' \| 'light'` | `'dark'` | Palette override. Default is always dark (see "Why dark"). |
51
+ | `inline` | `boolean` | `false` | Render as inline `<code>` (no card / toolbar). |
52
+ | `variant` | `'card' \| 'plain'` | `'card'` | `plain` strips border, background, and toolbar. |
53
+ | `isCompact` | `boolean` | `false` | 12px font instead of 14px. |
54
+ | `maxLines` | `number` | `undefined` | When set, block scrolls past this many lines. |
55
+ | `customBg` | `string` | — | Tailwind class to override the dark surface. |
56
+ | `scrollIsolation` | `boolean` | `true` | Block scroll capture until clicked (long snippets). |
57
+ | `className` | `string` | — | Extra classes on the wrapper. |
58
+
59
+ ## When to override `mode`
60
+
61
+ Almost never. The dark default is correct for ~all cases. Pass
62
+ `mode="light"` only for deliberate light-on-light renders (e.g. PDF
63
+ export targeting a printed page). The surface falls back to
64
+ `bg-card` semantic token in that mode.
65
+
66
+ ## Supported languages
67
+
68
+ Out of the box: `javascript`, `typescript`, `python`, `json`, `css`,
69
+ `markup` (html/xml), `sql`, `yaml`, `markdown`, `go`.
70
+
71
+ Lazy-loaded on first use: `bash`/`shell`, `ruby`, `java`, `php`.
72
+ Lazy load is tracked through `useEnsurePrismLanguages()` — the
73
+ component re-renders once the grammar resolves.
74
+
75
+ Unknown languages fall back to plain text (no highlighting, no error).
76
+
77
+ ## Storybook
78
+
79
+ `UI Tools / Code / PrettyCode` — `Playground`, `TypeScript`, `Json`,
80
+ `Python`, `Bash`, `Sql`, `Yaml`, `LongFileWithScroll`, `Inline`,
81
+ `Compact`, `LightMode`, `PlainVariant`.