@deepseek-ai/dsh-client-ui-primitives 0.1.6-alpha.1 → 0.1.6-alpha.2

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.
@@ -1,6 +1,6 @@
1
1
  /* Visual baseline: deepsuite `@deepseek/md` markdown.css, adapted to CSS
2
- Modules. Cite pills, header anchors, and thinking-small variants are
3
- intentionally absent (no matching DOM). Token names match that sheet. */
2
+ Modules. Cite pills and header anchors are absent (no matching DOM).
3
+ Token names match that sheet. */
4
4
 
5
5
  .markdown {
6
6
  min-width: 0;
@@ -55,7 +55,8 @@
55
55
  margin-bottom: 8px;
56
56
  }
57
57
 
58
- .markdown a {
58
+ .markdown a,
59
+ .markdown .fileLink {
59
60
  /* deepsuite markdown.css uses brand-text (blue in newDesign); this sheet
60
61
  keeps design-platform brand-text as near-black, so links use the
61
62
  dedicated link alias instead. */
@@ -80,7 +81,8 @@
80
81
  text-underline-offset: 3px;
81
82
  }
82
83
 
83
- .markdown a:focus-visible {
84
+ .markdown a:focus-visible,
85
+ .fileMention:focus-visible {
84
86
  box-shadow: 0 0 0 2px var(--dsw-alias-state-business-primary);
85
87
  }
86
88
 
@@ -314,9 +316,147 @@
314
316
  cursor: pointer;
315
317
  }
316
318
 
319
+ .fileLink {
320
+ max-width: 100%;
321
+ text-align: inherit;
322
+ }
323
+
317
324
  .fileMention:hover,
318
325
  .fileMention:focus {
319
326
  outline: none;
320
327
  text-decoration: underline dotted var(--dsw-alias-link);
321
328
  text-underline-offset: 3px;
322
329
  }
330
+
331
+ .compact {
332
+ max-width: 100%;
333
+ font-size: var(--dsh-content-font-size-secondary, 13px);
334
+ line-height: calc(20px + var(--dsh-content-font-delta-secondary, 0px));
335
+ color: var(--dsw-alias-label-tertiary);
336
+ }
337
+
338
+ .compact :is(h1, h2, h3, h4, h5, h6) {
339
+ margin: 8px 0 4px;
340
+ font: inherit;
341
+ font-weight: 600;
342
+ color: inherit;
343
+ }
344
+
345
+ .compact :is(p, ul, ol, blockquote) {
346
+ margin: 4px 0;
347
+ }
348
+
349
+ .compact li:not(:first-child) {
350
+ margin-top: 2px;
351
+ }
352
+
353
+ .compact li > p {
354
+ margin: 4px 0;
355
+ }
356
+
357
+ .compact li::marker {
358
+ line-height: inherit;
359
+ color: inherit;
360
+ }
361
+
362
+ .compact blockquote {
363
+ padding-left: 8px;
364
+ }
365
+
366
+ .compact hr {
367
+ margin: 8px 0;
368
+ }
369
+
370
+ .compact a,
371
+ .compact .fileMention {
372
+ font-weight: inherit;
373
+ color: inherit;
374
+ text-decoration: underline dotted;
375
+ }
376
+
377
+ .compact a:hover,
378
+ .compact a:focus,
379
+ .compact .fileMention:hover,
380
+ .compact .fileMention:focus {
381
+ text-decoration-color: currentColor;
382
+ }
383
+
384
+ .compact :not(pre) > code {
385
+ display: inline;
386
+ font: inherit;
387
+ font-family: var(--ds-font-family-code);
388
+ font-size: 1em !important;
389
+ border-radius: 4px;
390
+ padding: 0 3px;
391
+ box-decoration-break: clone;
392
+ }
393
+
394
+ .markdown.compact :global(.md-code-block) {
395
+ margin: 4px 0;
396
+ color: inherit;
397
+ }
398
+
399
+ .compact :global(.md-code-block) > :has(> [data-code-block-banner]) {
400
+ position: static;
401
+ z-index: auto;
402
+ }
403
+
404
+ .compact [data-code-block-banner] {
405
+ padding: 4px 8px;
406
+ font: inherit;
407
+ }
408
+
409
+ .compact [data-code-block-banner] > :first-child {
410
+ font-size: inherit;
411
+ line-height: inherit;
412
+ color: inherit;
413
+ }
414
+
415
+ .compact pre {
416
+ margin: 4px 0;
417
+ padding: 8px;
418
+ font-size: inherit;
419
+ line-height: inherit;
420
+ }
421
+
422
+ /* Shiki writes token colors inline; compact code uses the surrounding text color. */
423
+ .compact pre,
424
+ .compact pre :is(code, span) {
425
+ color: inherit !important;
426
+ }
427
+
428
+ .markdown.compact .tableScroll {
429
+ width: 100%;
430
+ max-width: 100%;
431
+ margin: 4px 0;
432
+ padding-left: 0;
433
+ }
434
+
435
+ .markdown.compact .tableScroll > table {
436
+ z-index: auto;
437
+ }
438
+
439
+ .compact :is(th, td) {
440
+ padding: 4px 8px;
441
+ font: inherit;
442
+ }
443
+
444
+ .compact th {
445
+ font-weight: 600;
446
+ }
447
+
448
+ .compact :global(.katex) {
449
+ font-size: 1em;
450
+ }
451
+
452
+ /* Keep KaTeX's inline baseline and scroll the containing block only when needed. */
453
+ .compact :is(p, h1, h2, h3, h4, h5, h6, ul, ol):has(:global(.katex)) {
454
+ overflow-x: auto;
455
+ overflow-y: hidden;
456
+ /* KaTeX descenders can paint one pixel below a fractional line-box edge. */
457
+ padding-bottom: 1px;
458
+ }
459
+
460
+ .compact :global(.katex-display) {
461
+ margin: 4px 0;
462
+ }
@@ -0,0 +1,20 @@
1
+ /** Controlled native checkbox with a caller-owned visible and accessible label. */
2
+ /**
3
+ * Render a labeled checkbox with native keyboard and form semantics.
4
+ * @param props.checked - current checked state.
5
+ * @param props.onChange - receives the requested checked state.
6
+ * @param props.label - localized visible and accessible label.
7
+ * @param props.disabled - whether the control refuses changes.
8
+ * @param props.title - optional localized hover text.
9
+ * @param props.className - extra class for the label's placement.
10
+ * @returns the label containing its checkbox.
11
+ */
12
+ export declare function Checkbox({ checked, onChange, label, disabled, title, className }: {
13
+ checked: boolean;
14
+ onChange: (next: boolean) => void;
15
+ label: string;
16
+ disabled?: boolean;
17
+ title?: string | undefined;
18
+ className?: string | undefined;
19
+ }): import("react").JSX.Element;
20
+ //# sourceMappingURL=Checkbox.d.ts.map
@@ -7,6 +7,10 @@
7
7
  * cannot compose a glyph outside a link. Design sources:
8
8
  * ic_globe_language_outline_20, ic_code_outline_20, ic_folder_outline_20,
9
9
  * ic_photo_outline_20, ic_paper_doc_outline_20, ic_paper_outline_20.
10
+ *
11
+ * A `url` glyph whose destination names a well-known site is that site's own
12
+ * mark instead of the globe (`SiteGlyph.tsx`); every mark keeps the same
13
+ * currentColor-only rule.
10
14
  */
11
15
  import type { ReactNode } from 'react';
12
16
  import type { IconProps } from './icons/props.ts';
@@ -20,6 +24,12 @@ export type LinkIconKind = 'url' | 'folder' | 'code' | 'image' | 'document' | 'o
20
24
  /** Props for {@link LinkIcon}: the category plus the shared icon sizing seat. */
21
25
  export interface LinkIconProps extends IconProps {
22
26
  kind: LinkIconKind;
27
+ /**
28
+ * Destination of a `url` link. A well-known site draws its own mark, so
29
+ * callers that know the destination should pass it; anything else keeps the
30
+ * globe. Other kinds ignore it — their destination is a path, not a site.
31
+ */
32
+ href?: string | undefined;
23
33
  }
24
34
  /**
25
35
  * Derive a file path's link-icon category from its extension. Unknown and
@@ -30,9 +40,10 @@ export interface LinkIconProps extends IconProps {
30
40
  export declare function classifyLinkPath(path: string): LinkIconKind;
31
41
  /**
32
42
  * Render the leading glyph for one clickable artifact link.
33
- * @param props - The link category, optional size (default 14px — the inline
34
- * link text size these glyphs sit beside), and optional CSS class.
43
+ * @param props - The link category, the optional destination that can select a
44
+ * site mark, optional size (default 14px — the inline link text size these
45
+ * glyphs sit beside), and optional CSS class.
35
46
  * @returns The category's SVG glyph, riding currentColor.
36
47
  */
37
- export declare function LinkIcon({ kind, size, className }: LinkIconProps): ReactNode;
48
+ export declare function LinkIcon({ kind, href, size, className }: LinkIconProps): ReactNode;
38
49
  //# sourceMappingURL=LinkIcon.d.ts.map
@@ -25,8 +25,13 @@ export interface MenuLabel {
25
25
  /** One primary-menu entry: a row, a separator, or a heading label. */
26
26
  export type MenuEntry = MenuItem | MenuSeparator | MenuLabel;
27
27
  /**
28
- * Render an anchored dropdown menu.
29
- * @param props.autoFocus - focus the first item on open and enable arrow-key navigation; Escape focuses the anchor's first button.
28
+ * Render an anchored dropdown menu. While the list is open its keys mirror the
29
+ * composer's: Tab settles the focused row — from the trigger, Tab enters the
30
+ * list instead — and Escape or Shift+Tab close it and return focus to the
31
+ * anchor's first button, and selecting a row does the same — the rows unmount
32
+ * with the list. Only a keyboard on the trigger or inside the list is
33
+ * intercepted; Tab presses elsewhere on the page stay the browser's.
34
+ * @param props.autoFocus - focus the first item on open; the arrow keys walk the list either way.
30
35
  * @param props.open - whether the list is showing (owner-controlled).
31
36
  * @param props.anchor - the trigger element (rendered in place).
32
37
  * @param props.items - selectable rows and optional separators.
@@ -19,7 +19,8 @@ type ModalProps = ModalBaseProps & ({
19
19
  /**
20
20
  * Render a centered, body-portaled modal over a blurred page mask.
21
21
  * @param props.open - whether the dialog is showing.
22
- * @param props.onClose - Escape or mask click.
22
+ * @param props.onClose - Escape or mask click; while a menu is open inside the
23
+ * dialog, Escape belongs to that menu first.
23
24
  * @param props.title - dialog heading (aria-label in every mode).
24
25
  * @param props.closeLabel - localized accessible close-button label.
25
26
  * @param props.description - optional supporting sentence under the title.
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Site marks for well-known external link hosts. {@link LinkIcon} renders one in
3
+ * the leading glyph seat, so a familiar destination leads with its own mark
4
+ * instead of the generic globe. The marks are the `simple-icons` artwork set
5
+ * (CC0-1.0), pinned by this package's dependency on it; each mark takes the
6
+ * link's `currentColor` rather than the brand fill that set records.
7
+ */
8
+ import type { ReactElement } from 'react';
9
+ /** Props for {@link siteGlyph}: the destination plus the shared icon sizing seat. */
10
+ interface SiteGlyphProps {
11
+ /** The link destination; only an absolute http(s) URL can name a host. */
12
+ href: string | undefined;
13
+ /** Square edge in px. */
14
+ size: number;
15
+ /** Extra class for layout placement. */
16
+ className?: string | undefined;
17
+ }
18
+ /**
19
+ * Render the site mark for a known external destination.
20
+ * @param props - The destination and the icon sizing seat.
21
+ * @returns The site's mark riding currentColor, or undefined for an unknown site.
22
+ */
23
+ export declare function siteGlyph({ href, size, className }: SiteGlyphProps): ReactElement | undefined;
24
+ export {};
25
+ //# sourceMappingURL=SiteGlyph.d.ts.map
@@ -9,6 +9,8 @@ export interface TerminalBlockLabels {
9
9
  signal: (signal: string) => string;
10
10
  /** Status pill text for a non-zero exit code. */
11
11
  exitCode: (exitCode: number) => string;
12
+ /** Status pill text for a command that ended without an exit code: killed by a signal the view does not know, or never started. */
13
+ noExitCode: string;
12
14
  /** Run-state text while the command is still running. */
13
15
  running: string;
14
16
  /** Run-state text for a signal or non-zero-exit settle. */
@@ -39,11 +41,14 @@ export interface TerminalBlockProps {
39
41
  home?: string | undefined;
40
42
  /** The command's output text; may contain ANSI escape sequences. */
41
43
  output?: string | undefined;
42
- /** Settled exit code; a non-zero value renders the status pill. */
43
- exitCode?: number | undefined;
44
+ /** Settled exit code; a non-zero value renders the status pill, and null (settled without one) the no-exit-code pill. */
45
+ exitCode?: number | null | undefined;
44
46
  /** Settled terminating signal name; any value renders the status pill, taking precedence over the exit code. */
45
47
  signal?: string | undefined;
46
- /** The command is still running: the block shows the prompt line alone. */
48
+ /**
49
+ * The command is still running: the block shows the prompt line, and the
50
+ * output printed so far when there is any, with no copy control until it settles.
51
+ */
47
52
  running?: boolean | undefined;
48
53
  /** Height cap in output lines before the middle collapses (default {@link DEFAULT_TERMINAL_MAX_LINES}); Infinity disables the cap. */
49
54
  maxLines?: number | undefined;
@@ -0,0 +1,9 @@
1
+ /** macOS desktop detection for hiddenInset-titlebar layout variants. */
2
+ /**
3
+ * Whether the client runs in the macOS desktop shell: the Electron preload
4
+ * marks `<html>` with `data-platform="darwin"`; plain web never sets it.
5
+ * Read at render time — the mark may arrive as late as DOMContentLoaded.
6
+ * @returns true only inside the macOS Electron shell.
7
+ */
8
+ export declare function isDarwinDesktop(): boolean;
9
+ //# sourceMappingURL=darwin-desktop.d.ts.map
@@ -161,6 +161,8 @@ export declare const IconInspectOutline12: ({ size, className }: IconProps) => i
161
161
  export declare const IconSkillOutline16: ({ size, className }: IconProps) => import("react").JSX.Element;
162
162
  /** ic_ds_question_outline_14 (figma extract): ring + question glyph. */
163
163
  export declare const IconQuestionOutline14: ({ size, className }: IconProps) => import("react").JSX.Element;
164
+ /** Info companion to the question outline: the same ring with an "i" glyph. */
165
+ export declare const IconInfoOutline14: ({ size, className }: IconProps) => import("react").JSX.Element;
164
166
  /** Alarm clock outline for active scheduled-task indicators. */
165
167
  export declare const IconAlarmClockOutline16: ({ size, className }: IconProps) => import("react").JSX.Element;
166
168
  /** ic_ds_archive_outline_20 (figma extract): lidded box + label slot. The export's
@@ -193,4 +195,6 @@ export declare const SHIELD_OUTLINE_PATH = "M8.20554 0.899994L14.7901 3.36857V7.
193
195
  export declare const SHIELD_OUTLINE_STROKE = "1.31831";
194
196
  /** Permission row glyph of the composer menu: the shield contour alone, without a mode mark. */
195
197
  export declare const IconShieldOutline16: ({ size, className }: IconProps) => import("react").JSX.Element;
198
+ /** Plugin pinwheel (design handoff for the plugin manager): four interleaved arcs on the 16 grid. */
199
+ export declare const IconPluginPinwheelOutline16: ({ size, className }: IconProps) => import("react").JSX.Element;
196
200
  //# sourceMappingURL=index.d.ts.map
@@ -11,6 +11,7 @@ export { Pill } from './Pill.tsx';
11
11
  export { Tag } from './Tag.tsx';
12
12
  export type { TagTone } from './Tag.tsx';
13
13
  export { Switch } from './Switch.tsx';
14
+ export { Checkbox } from './Checkbox.tsx';
14
15
  export { Input } from './Input.tsx';
15
16
  export { Menu } from './Menu.tsx';
16
17
  export type { MenuEntry, MenuItem, MenuSeparator, MenuLabel } from './Menu.tsx';
@@ -42,6 +43,7 @@ export { fileSizeText } from './file-size.ts';
42
43
  export { writeClipboard } from './clipboard.ts';
43
44
  export { relativeTime } from './relative-time.ts';
44
45
  export { rankByName } from './rank-by-name.ts';
46
+ export { isDarwinDesktop } from './darwin-desktop.ts';
45
47
  export type { RelativeTime, RelativeTimeUnit } from './relative-time.ts';
46
48
  export { JsonTree } from './JsonTree.tsx';
47
49
  export type { JsonTreeProps, JsonTreeLabels } from './JsonTree.tsx';
@@ -58,6 +60,8 @@ export type { WebBlockProps, WebSearchBlockProps, WebFetchBlockProps, WebSourceV
58
60
  export { CodeBlock } from './markdown/CodeBlock.tsx';
59
61
  export type { CodeBlockProps } from './markdown/CodeBlock.tsx';
60
62
  export { JsonBlock } from './markdown/JsonBlock.tsx';
63
+ export { MarkdownDelegateProvider } from './markdown/MarkdownDelegate.tsx';
64
+ export type { MarkdownDelegate, MarkdownDelegateProviderProps, MarkdownExternalLinkHandler } from './markdown/MarkdownDelegate.tsx';
61
65
  export { MarkdownText } from './markdown/MarkdownText.tsx';
62
66
  export type { MarkdownCodeLabels, MarkdownFileMentions, MarkdownLabels, MarkdownPathImages } from './markdown/MarkdownText.tsx';
63
67
  export { extractMarkdownPlainText } from './markdown/plain-text.ts';
@@ -0,0 +1,36 @@
1
+ import type { ReactNode } from 'react';
2
+ /**
3
+ * Handle one sanitized absolute HTTP(S) URL selected from Markdown.
4
+ * @param href - destination URL.
5
+ */
6
+ export type MarkdownExternalLinkHandler = (href: string) => void;
7
+ /** Navigation capabilities supplied by the nearest Markdown owner. */
8
+ export interface MarkdownDelegate {
9
+ /** Ordinary HTTP(S) activation; absent handlers retain native anchor behavior. */
10
+ readonly openExternalLink?: MarkdownExternalLinkHandler | undefined;
11
+ /**
12
+ * Open a decoded local destination from settled Markdown; absent handlers leave plain text.
13
+ * @param path - Absolute or workspace-relative file path.
14
+ * @param options - First line to reveal when the destination specifies a line or range.
15
+ */
16
+ readonly openFile?: ((path: string, options?: {
17
+ line?: number;
18
+ }) => void) | undefined;
19
+ }
20
+ /** Props for one Markdown navigation scope. */
21
+ export interface MarkdownDelegateProviderProps extends MarkdownDelegate {
22
+ readonly children: ReactNode;
23
+ }
24
+ /**
25
+ * Scope Markdown navigation without threading callbacks through renderers.
26
+ * Nested providers replace the enclosing capabilities. Handler changes reach cached links.
27
+ * @param props - Child tree and its file and HTTP(S) link handlers.
28
+ * @returns the scoped child tree.
29
+ */
30
+ export declare function MarkdownDelegateProvider({ children, openExternalLink, openFile, }: MarkdownDelegateProviderProps): ReactNode;
31
+ /**
32
+ * Read the nearest Markdown navigation capabilities.
33
+ * @returns Owner callbacks, or an empty delegate outside a provider.
34
+ */
35
+ export declare function useMarkdownDelegate(): MarkdownDelegate;
36
+ //# sourceMappingURL=MarkdownDelegate.d.ts.map
@@ -24,19 +24,26 @@ export type { MarkdownCodeLabels, MarkdownFileMentions, MarkdownLabels, Markdown
24
24
  * identity discards the streaming render cache mid-message. `fileMentions`
25
25
  * links inline-code tokens its resolver recognizes as real files, and
26
26
  * `pathImages` rewrites image destinations that are local file paths into
27
- * displayable URLs its resolver vouches for; both vocabularies are the
27
+ * displayable URLs its resolver vouches for. Those two vocabularies are the
28
28
  * single streaming gate — they apply to settled renders only, because a
29
29
  * streaming message's vocabulary is not final and frozen cached elements
30
- * must not bake in handlers that could go stale.
31
- * @returns A GFM document with TeX math rendered through KaTeX; raw HTML,
32
- * relative links, and unsafe protocols are disabled, while absolute HTTP(S)
33
- * images render directly.
30
+ * must not bake in handlers that could go stale. A surrounding
31
+ * `MarkdownDelegateProvider` can delegate ordinary HTTP(S) activation while
32
+ * modified clicks retain native behavior. `variant="compact"` uses secondary
33
+ * text sizing, uniform bold headings, and tight block spacing; the default
34
+ * `body` variant uses the full document typography.
35
+ * The provider's `openFile` enables local Markdown links in settled messages,
36
+ * including `#L24` and `#L24-L30` destinations (ranges open at their first line).
37
+ * @returns A GFM document with TeX math rendered through KaTeX; raw HTML and
38
+ * unsafe protocols are disabled. Local links without an opener remain text;
39
+ * absolute HTTP(S) images render directly.
34
40
  */
35
- export declare const MarkdownText: import("react").MemoExoticComponent<({ text, streaming, labels, fileMentions, pathImages }: {
41
+ export declare const MarkdownText: import("react").MemoExoticComponent<({ text, streaming, labels, fileMentions, pathImages, variant, }: {
36
42
  text: string;
37
43
  streaming?: boolean;
38
44
  labels: MarkdownLabels;
39
45
  fileMentions?: MarkdownFileMentions | undefined;
40
46
  pathImages?: MarkdownPathImages | undefined;
47
+ variant?: "body" | "compact";
41
48
  }) => import("react").JSX.Element>;
42
49
  //# sourceMappingURL=MarkdownText.d.ts.map
@@ -0,0 +1,13 @@
1
+ /** Local Markdown destinations accepted by the file-preview callback. */
2
+ /**
3
+ * Decode a file destination and its optional GitHub-style line fragment.
4
+ * Literal `?` and `#` in filenames must be percent-encoded.
5
+ * @param value - Parsed Markdown link destination.
6
+ * @returns A local path and optional first line, or undefined for URLs,
7
+ * fragment-only links, queries, malformed escapes, or invalid line ranges.
8
+ */
9
+ export declare function parseFileLink(value: string): {
10
+ path: string;
11
+ line?: number;
12
+ } | undefined;
13
+ //# sourceMappingURL=file-link.d.ts.map
@@ -4,8 +4,8 @@
4
4
  * cache frozen blocks as React elements; the rendered DOM is pinned
5
5
  * byte-for-byte by `tests/fixtures/markdown-dom` and must not drift.
6
6
  *
7
- * Untrusted-output policy (unchanged from the replaced pipeline): link and
8
- * image destinations pass a protocol allowlist, images additionally require
7
+ * External link and image destinations pass a protocol allowlist; settled
8
+ * local file links use an explicit owner callback. Images additionally require
9
9
  * absolute HTTP(S), raw HTML renders as literal text (no HTML enters the
10
10
  * DOM), and KaTeX runs without trusted commands. Fragment-anchor URLs fail
11
11
  * the allowlist, so footnote references and back-references render as plain
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@deepseek-ai/dsh-client-ui-primitives",
3
3
  "description": "Pure React atoms for the dsh web UI: controls, icons, markdown, and JSON inspectors (zero cordis)",
4
- "version": "0.1.6-alpha.1",
4
+ "version": "0.1.6-alpha.2",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -46,6 +46,7 @@
46
46
  "mdast-util-math": "^3.0.0",
47
47
  "micromark-extension-gfm": "^3.0.0",
48
48
  "micromark-util-sanitize-uri": "^2.0.1",
49
+ "simple-icons": "16.31.0",
49
50
  "@deepseek-ai/cordis": "^4.0.2"
50
51
  },
51
52
  "files": [