@djangocfg/widget-code 0.1.18 → 0.1.21

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
@@ -13,7 +13,6 @@ pnpm add @djangocfg/widget-code @djangocfg/ui-core @djangocfg/i18n
13
13
  |---|---|---|
14
14
  | `./editor` | Monaco, single file or diff | ~550 KB, lazy |
15
15
  | `./json-editor` | an editable JSON tree | `json-edit-react` |
16
- | `./pretty-code` | a read-only listing with a panel header | Prism |
17
16
  | `./diff-viewer` | unified or split diff, virtualised | Prism + virtuoso |
18
17
  | `./diff-viewer/full` | the same, eagerly | |
19
18
  | `./markdown-message` | markdown with embedded code, diagrams and chips | |
@@ -26,10 +25,11 @@ subpaths. The root exports the role tokens and nothing else, on purpose.
26
25
 
27
26
  ## Read-only code elsewhere
28
27
 
29
- `@djangocfg/widget-media/code` renders a listing with **shiki**, and a console
30
- should pick one highlighter rather than match two themes by hand. Prefer it for
31
- a new surface; this package's Prism stack stays because `DiffViewer` and
32
- `MarkdownMessage` are built on it.
28
+ `PrettyCode` (a read-only listing with a panel header, Prism) lives in
29
+ `@djangocfg/widget-kit/pretty-code`, with `/pretty-code/lazy` for the deferred
30
+ form; `DiffViewer` and `MarkdownMessage` here use it from there, and so does the
31
+ chat's `Response`. `@djangocfg/widget-media/code` is a second, shiki listing with
32
+ no consumer in this repo.
33
33
 
34
34
  ## Verify
35
35
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@djangocfg/widget-code",
3
- "version": "0.1.18",
4
- "description": "Code surfaces: a Monaco editor, a diff viewer, a Prism listing, a JSON editor and the markdown renderer that embeds them",
3
+ "version": "0.1.21",
4
+ "description": "Code surfaces: a Monaco editor, a diff viewer, a JSON editor and the markdown renderer that embeds them",
5
5
  "keywords": [
6
6
  "code-editor",
7
7
  "monaco",
@@ -38,10 +38,6 @@
38
38
  "types": "./src/json-editor/lazy.tsx",
39
39
  "default": "./src/json-editor/lazy.tsx"
40
40
  },
41
- "./pretty-code": {
42
- "types": "./src/pretty-code/lazy.tsx",
43
- "default": "./src/pretty-code/lazy.tsx"
44
- },
45
41
  "./diff-viewer": {
46
42
  "types": "./src/diff-viewer/lazy.tsx",
47
43
  "default": "./src/diff-viewer/lazy.tsx"
@@ -74,14 +70,13 @@
74
70
  "test:watch": "vitest"
75
71
  },
76
72
  "dependencies": {
77
- "@djangocfg/widget-data": "^0.1.18",
78
- "@djangocfg/widget-diagram": "^0.1.13",
79
- "@djangocfg/widget-editor": "^0.1.71",
80
- "@djangocfg/widget-kit": "^0.1.19",
73
+ "@djangocfg/widget-data": "^0.1.30",
74
+ "@djangocfg/widget-diagram": "^0.1.25",
75
+ "@djangocfg/widget-editor": "^0.1.104",
76
+ "@djangocfg/widget-kit": "^0.1.22",
81
77
  "json-edit-react": "^2.0.5",
82
78
  "monaco-editor": "^0.57.0",
83
79
  "prism-react-renderer": "^2.4.1",
84
- "prismjs": "^1.30.0",
85
80
  "react-markdown": "10.1.0",
86
81
  "react-virtuoso": "^4.18.20",
87
82
  "rehype-external-links": "^3.0.0",
@@ -93,16 +88,16 @@
93
88
  "remark-smartypants": "^3.0.3"
94
89
  },
95
90
  "peerDependencies": {
96
- "@djangocfg/i18n": "^2.1.613",
97
- "@djangocfg/ui-core": "^2.1.613",
91
+ "@djangocfg/i18n": "^2.1.646",
92
+ "@djangocfg/ui-core": "^2.1.646",
98
93
  "lucide-react": "^1.68.0",
99
94
  "react": "^19.0.0",
100
95
  "react-dom": "^19.0.0"
101
96
  },
102
97
  "devDependencies": {
103
- "@djangocfg/i18n": "^2.1.613",
104
- "@djangocfg/typescript-config": "^2.1.613",
105
- "@djangocfg/ui-core": "^2.1.613",
98
+ "@djangocfg/i18n": "^2.1.646",
99
+ "@djangocfg/typescript-config": "^2.1.646",
100
+ "@djangocfg/ui-core": "^2.1.646",
106
101
  "@storybook/react-vite": "^10.6.5",
107
102
  "@types/node": "^25.9.5",
108
103
  "@types/react": "19.3.0",
@@ -1,54 +1,18 @@
1
1
  // Adapted from jalcoui (MIT) — github.com/jal-co/ui
2
2
  //
3
- // Shared tokenizer for DiffViewer. Reuses the same `prism-react-renderer`
4
- // bundle that `PrettyCode` ships — no second highlighter is loaded. We
5
- // also re-import `PrettyCode`'s grammar-registration hook so `bash`,
6
- // `ruby`, `java`, `php` work in diffs without duplicating the dynamic
7
- // imports.
3
+ // The language answer for DiffViewer. The tokenizer and the grammar loader are
4
+ // the kit's `PrettyCode` ones, so a diff and a code block agree on which
5
+ // languages exist and what a fence name means — no second table here.
8
6
 
9
7
  import { useMemo } from 'react';
10
8
  import type { Language } from 'prism-react-renderer';
11
- import { useEnsurePrismLanguages } from '../../pretty-code/registerPrismLanguages';
9
+ import { normalizePrismLanguage, useEnsurePrismLanguages } from '@djangocfg/widget-kit/pretty-code';
12
10
 
13
11
  /**
14
- * Normalize a free-form language string into a Prism language key. Falls
15
- * back to `text` when the key isn't one Prism knows about.
16
- */
17
- export function normalizeLanguage(language: string | undefined): Language {
18
- if (!language) return 'text' as Language;
19
- const lang = language.toLowerCase();
20
- switch (lang) {
21
- case 'js':
22
- return 'javascript' as Language;
23
- case 'ts':
24
- return 'typescript' as Language;
25
- case 'py':
26
- return 'python' as Language;
27
- case 'rb':
28
- return 'ruby' as Language;
29
- case 'sh':
30
- case 'shell':
31
- return 'bash' as Language;
32
- case 'html':
33
- case 'xml':
34
- return 'markup' as Language;
35
- case 'md':
36
- return 'markdown' as Language;
37
- case 'yml':
38
- return 'yaml' as Language;
39
- case 'golang':
40
- return 'go' as Language;
41
- default:
42
- return lang as Language;
43
- }
44
- }
45
-
46
- /**
47
- * Subscribe to PrettyCode's extra-grammar loader and return the resolved
48
- * Prism language key. The component re-renders once `bash`/`ruby`/… are
49
- * registered so the first paint isn't stuck on plain text.
12
+ * The resolved Prism language key. The component re-renders once
13
+ * `bash`/`ruby`/… are registered so the first paint isn't stuck on plain text.
50
14
  */
51
15
  export function useDiffLanguage(language: string | undefined): Language {
52
16
  useEnsurePrismLanguages();
53
- return useMemo(() => normalizeLanguage(language), [language]);
17
+ return useMemo(() => normalizePrismLanguage(language), [language]);
54
18
  }
@@ -9,7 +9,6 @@ export {
9
9
  lineNumberWidth as diffLineNumberWidth,
10
10
  } from './utils/computeDiff';
11
11
  export { useDiff } from './hooks/useDiff';
12
- export { normalizeLanguage as normalizeDiffLanguage } from './hooks/useHighlighter';
13
12
 
14
13
  export type {
15
14
  DiffLayout,
package/src/index.ts CHANGED
@@ -1,10 +1,10 @@
1
1
  /**
2
- * Code surfaces: an editor, a diff, a highlighted listing, a JSON editor and
2
+ * Code surfaces: an editor, a diff, a JSON editor and
3
3
  * the markdown renderer that embeds them.
4
4
  *
5
5
  * No root barrel worth importing — Monaco alone is ~550 KB and `json-edit-react`
6
6
  * and Prism sit behind their own subpaths. Import the one you want:
7
- * `@djangocfg/widget-code/editor`, `/pretty-code`, `/diff-viewer`,
7
+ * `@djangocfg/widget-code/editor`, `/diff-viewer`,
8
8
  * `/json-editor`, `/markdown-message`.
9
9
  */
10
10
  export { ANCHOR, TOGGLE } from './role-tokens';
@@ -1,6 +1,6 @@
1
1
  import React, { memo } from 'react';
2
2
  import { CopyButton } from '@djangocfg/ui-core/components';
3
- import PrettyCode from '../pretty-code';
3
+ import { LazyPrettyCode as PrettyCode } from '@djangocfg/widget-kit/pretty-code/lazy';
4
4
 
5
5
  interface CodeBlockProps {
6
6
  code: string;
@@ -15,8 +15,8 @@ interface CodeBlockProps {
15
15
  }
16
16
 
17
17
  /**
18
- * Markdown code block. Renders <PrettyCode> directly — its own
19
- * FloatingToolbar already carries the language tag and Copy action.
18
+ * Markdown code block. Renders the kit's <PrettyCode> directly — its header
19
+ * already carries the language tag and the Copy action.
20
20
  *
21
21
  * Earlier versions stacked an extra <CopyButton> here too, which
22
22
  * surfaced as two copy buttons on every code fence. The fallback
@@ -58,13 +58,6 @@ function CodeBlockRaw({ code, language, codeTheme = 'auto' }: CodeBlockProps) {
58
58
  // dark page hid it). The inline var()-based surface needs no content
59
59
  // scan, so it renders correctly in every consumer and both themes.
60
60
  isCompact
61
- // Disable click-to-scroll-isolation in chat markdown: code
62
- // fences here are part of an assistant reply, not a docs
63
- // viewer. Forcing the user to click into a small block to
64
- // scroll past it interrupts the reading flow. The standalone
65
- // PrettyCode use cases (docs, diff viewers, long code panes)
66
- // keep the default `true`.
67
- scrollIsolation={false}
68
61
  />
69
62
  </div>
70
63
  );
@@ -1,121 +0,0 @@
1
- 'use client';
2
-
3
- /**
4
- * CodePanelHeader — a slim, persistent header bar for the code panel
5
- * (PrettyCode), GitHub / ChatGPT style: the detected language on the left,
6
- * a copy button on the right. In flow (not an absolute hover overlay), so
7
- * the copy button never floats over the code.
8
- *
9
- * Code panels are usually DARK (like the map basemap is always light), so
10
- * the header defaults to FIXED on-dark colors — theme tokens
11
- * (`text-foreground`, `border-border`) would render dark-on-dark / an
12
- * over-bright divider on the dark panel. Pass `dark={false}` for a
13
- * light-surfaced panel, which switches to muted semantic tokens.
14
- */
15
-
16
- import { useCallback, useState, type ReactNode } from 'react';
17
-
18
- import { cn } from '@djangocfg/ui-core/lib';
19
- import { Check, Copy, Maximize2 } from 'lucide-react';
20
-
21
- export interface CodePanelHeaderProps {
22
- /** Display label on the left (e.g. "typescript", "json", "bash"). */
23
- language?: ReactNode;
24
- /** Text copied when the copy button is pressed. Omit to hide copy. */
25
- copyValue?: string;
26
- /** a11y label for the copy button. */
27
- copyLabel?: string;
28
- /** When set, an expand (⤢) button is shown that calls this — used to open
29
- * the panel full-screen when it's height-capped. */
30
- onExpand?: () => void;
31
- /** a11y / tooltip label for the expand button. */
32
- expandLabel?: string;
33
- /** Extra trailing actions, rendered left of the copy button. */
34
- actions?: ReactNode;
35
- /** Dark panel (default). `false` → light-surface muted tokens. */
36
- dark?: boolean;
37
- className?: string;
38
- }
39
-
40
- export function CodePanelHeader({
41
- language,
42
- copyValue,
43
- copyLabel = 'Copy',
44
- onExpand,
45
- expandLabel = 'Expand',
46
- actions,
47
- dark = true,
48
- className,
49
- }: CodePanelHeaderProps) {
50
- const [copied, setCopied] = useState(false);
51
-
52
- const onCopy = useCallback(() => {
53
- if (copyValue == null) return;
54
- void navigator.clipboard?.writeText(copyValue).then(() => {
55
- setCopied(true);
56
- setTimeout(() => setCopied(false), 1400);
57
- });
58
- }, [copyValue]);
59
-
60
- // Fixed on-dark vs semantic light. The hairline is faint so it never
61
- // reads as a heavy rule across the panel.
62
- const dividerCls = dark ? 'border-white/[0.06]' : 'border-border/60';
63
- const labelCls = dark ? 'text-white/40' : 'text-muted-foreground';
64
- const btnCls = dark
65
- ? 'text-white/45 hover:bg-white/10 hover:text-white/80 focus-visible:ring-white/40'
66
- : 'text-muted-foreground hover:bg-foreground/10 hover:text-foreground focus-visible:ring-ring';
67
-
68
- return (
69
- <div
70
- className={cn(
71
- 'flex items-center justify-between gap-2 border-b px-3 py-1',
72
- dividerCls,
73
- className,
74
- )}
75
- >
76
- <span
77
- className={cn(
78
- 'min-w-0 truncate font-mono text-[11px] lowercase tracking-wide',
79
- labelCls,
80
- )}
81
- >
82
- {language}
83
- </span>
84
-
85
- <div className="flex shrink-0 items-center gap-0.5">
86
- {actions}
87
- {onExpand ? (
88
- <button
89
- type="button"
90
- onClick={onExpand}
91
- aria-label={expandLabel}
92
- title={expandLabel}
93
- className={cn(
94
- 'inline-flex size-5 items-center justify-center rounded-md transition-colors focus-visible:outline-none focus-visible:ring-1',
95
- btnCls,
96
- )}
97
- >
98
- <Maximize2 className="size-3" aria-hidden />
99
- </button>
100
- ) : null}
101
- {copyValue != null ? (
102
- <button
103
- type="button"
104
- onClick={onCopy}
105
- aria-label={copyLabel}
106
- className={cn(
107
- 'inline-flex size-5 items-center justify-center rounded-md transition-colors focus-visible:outline-none focus-visible:ring-1',
108
- btnCls,
109
- )}
110
- >
111
- {copied ? (
112
- <Check className="size-3" aria-hidden />
113
- ) : (
114
- <Copy className="size-3" aria-hidden />
115
- )}
116
- </button>
117
- ) : null}
118
- </div>
119
- </div>
120
- );
121
- }
@@ -1 +0,0 @@
1
- export { CodePanelHeader, type CodePanelHeaderProps } from './CodePanelHeader';