@deepseek-ai/dsh-client-ui-primitives 0.1.2-alpha.5 → 0.1.3-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.
@@ -57,9 +57,10 @@
57
57
 
58
58
  .markdown a {
59
59
  /* deepsuite markdown.css uses brand-text (blue in newDesign); this sheet
60
- keeps design-platform brand-text as near-black, so links use the blue
61
- business-primary alias instead. */
62
- color: var(--dsw-alias-state-business-primary);
60
+ keeps design-platform brand-text as near-black, so links use the
61
+ dedicated link alias instead. */
62
+ color: var(--dsw-alias-link);
63
+ font-weight: 500;
63
64
  transition: box-shadow var(--ds-transition-duration) var(--ds-ease-in-out);
64
65
  position: relative;
65
66
  text-decoration: none;
@@ -75,13 +76,27 @@
75
76
  .markdown a:hover,
76
77
  .markdown a:focus {
77
78
  outline: none;
78
- text-decoration: underline var(--dsw-alias-state-business-primary);
79
+ text-decoration: underline dotted var(--dsw-alias-link);
80
+ text-underline-offset: 3px;
79
81
  }
80
82
 
81
83
  .markdown a:focus-visible {
82
84
  box-shadow: 0 0 0 2px var(--dsw-alias-state-business-primary);
83
85
  }
84
86
 
87
+ /* Leading link-category glyph inside anchors, file mentions, and
88
+ URL-promoted inline code: outline glyphs ride the link's currentColor.
89
+ 1.1em keeps the glyph proportional to the surrounding text's size (it
90
+ shrinks with the code chip's 0.875em); the small negative offset seats
91
+ its optical center on the cap height. */
92
+ .linkIcon {
93
+ flex: none;
94
+ width: 1.1em;
95
+ height: 1.1em;
96
+ vertical-align: -0.25em;
97
+ margin-right: 5px;
98
+ }
99
+
85
100
  .markdown :where(ul, ol) {
86
101
  margin: 16px 0;
87
102
  padding-left: 18px;
@@ -151,6 +166,7 @@
151
166
  font-family: var(--ds-font-family-code);
152
167
  font-size: 0.875em !important;
153
168
  background-color: var(--dsw-alias-markdown-inline-code);
169
+ border: 0.5px solid var(--dsw-alias-border-l1);
154
170
  border-radius: 6px;
155
171
  padding: 0 5px;
156
172
  }
@@ -282,8 +298,8 @@
282
298
  }
283
299
 
284
300
  /* Inline file mention: the same link language this sheet gives anchors (and
285
- thereby URL-promoted inline code) — link-blue at rest, underline only on
286
- hover/focus. An underline at rest reads badly inside the code chip, where
301
+ thereby URL-promoted inline code) — link-blue at rest, dotted underline only
302
+ on hover/focus. An underline at rest reads badly inside the code chip, where
287
303
  it collides with monospace descenders and the pill background. */
288
304
  .fileMention {
289
305
  margin: 0;
@@ -291,7 +307,8 @@
291
307
  border: none;
292
308
  background: none;
293
309
  font: inherit;
294
- color: var(--dsw-alias-state-business-primary);
310
+ font-weight: 500;
311
+ color: var(--dsw-alias-link);
295
312
  text-decoration: none;
296
313
  cursor: pointer;
297
314
  }
@@ -299,6 +316,6 @@
299
316
  .fileMention:hover,
300
317
  .fileMention:focus {
301
318
  outline: none;
302
- text-decoration: underline var(--dsw-alias-state-business-primary);
319
+ text-decoration: underline dotted var(--dsw-alias-link);
303
320
  text-underline-offset: 3px;
304
321
  }
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Render the DeepSeek Web document glyph used by generic-file cards.
3
+ * @param props - optional CSS class for sizing and placement.
4
+ * @returns a decorative document SVG with an instance-safe gradient id.
5
+ */
6
+ export declare function DocumentFileIcon({ className }: {
7
+ readonly className?: string | undefined;
8
+ }): import("react").JSX.Element;
9
+ //# sourceMappingURL=DocumentFileIcon.d.ts.map
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Leading category glyph for clickable artifact links (anchors, file
3
+ * mentions, produced-file chips). One component keyed by link category;
4
+ * every glyph renders fill="currentColor" and so rides the link's own
5
+ * color. Glyphs stay private to this module: the public surface is the
6
+ * category vocabulary, not the individual glyph components, so consumers
7
+ * cannot compose a glyph outside a link. Design sources:
8
+ * ic_globe_language_outline_20, ic_code_outline_20, ic_folder_outline_20,
9
+ * ic_photo_outline_20, ic_paper_doc_outline_20, ic_paper_outline_20.
10
+ */
11
+ import type { ReactNode } from 'react';
12
+ import type { IconProps } from './icons/props.ts';
13
+ /**
14
+ * Link categories with distinct leading glyphs. `url` and `folder` are
15
+ * destination categories the consumer states directly; the rest are file
16
+ * categories `classifyLinkPath` derives from a path. Code, web, and data
17
+ * files share the `code` glyph by design.
18
+ */
19
+ export type LinkIconKind = 'url' | 'folder' | 'code' | 'image' | 'document' | 'other';
20
+ /** Props for {@link LinkIcon}: the category plus the shared icon sizing seat. */
21
+ export interface LinkIconProps extends IconProps {
22
+ kind: LinkIconKind;
23
+ }
24
+ /**
25
+ * Derive a file path's link-icon category from its extension. Unknown and
26
+ * missing extensions fall to `other` (the plain-paper glyph).
27
+ * @param path - File path as the producing tool spelled it (either separator).
28
+ * @returns The file's glyph category; never `url` or `folder`.
29
+ */
30
+ export declare function classifyLinkPath(path: string): LinkIconKind;
31
+ /**
32
+ * 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.
35
+ * @returns The category's SVG glyph, riding currentColor.
36
+ */
37
+ export declare function LinkIcon({ kind, size, className }: LinkIconProps): ReactNode;
38
+ //# sourceMappingURL=LinkIcon.d.ts.map
@@ -53,9 +53,13 @@ export type MenuEntry = MenuItem | MenuSeparator | MenuLabel;
53
53
  * scroll/resize; return null to skip placement for that frame.
54
54
  * @param props.footer - rows pinned below the scrolling items area, separated
55
55
  * by a hairline; they stay visible while the items above scroll.
56
+ * @param props.selection - how a selected row is marked: a trailing check
57
+ * (`'check'`, default — figma .Menu_cell) or the hover fill held on the row
58
+ * with no check (`'fill'`, for icon-labelled rows where a trailing glyph
59
+ * crowds the cell).
56
60
  * @returns anchor wrapper with the conditional list.
57
61
  */
58
- export declare function Menu({ open, anchor, items, selectedId, selectedIds, onSelect, onClose, align, side, portal, closeOnPointerLeave, dense, compact, getAnchorRect, footer, className }: {
62
+ export declare function Menu({ open, anchor, items, selectedId, selectedIds, onSelect, onClose, align, side, portal, closeOnPointerLeave, dense, compact, selection, getAnchorRect, footer, className }: {
59
63
  open: boolean;
60
64
  anchor: ReactNode;
61
65
  items: readonly MenuEntry[];
@@ -70,6 +74,7 @@ export declare function Menu({ open, anchor, items, selectedId, selectedIds, onS
70
74
  closeOnPointerLeave?: boolean;
71
75
  dense?: boolean;
72
76
  compact?: boolean;
77
+ selection?: 'check' | 'fill';
73
78
  getAnchorRect?: () => DOMRect | null;
74
79
  className?: string;
75
80
  }): import("react").JSX.Element;
@@ -1,8 +1,11 @@
1
- /** Four-color state semantic (green done / amber user-attention / blue running ring / red error). */
2
- export type StateDotState = 'done' | 'warning' | 'ongoing' | 'error';
1
+ /**
2
+ * State semantic: green done / amber user-attention / blue running ring /
3
+ * red error / grey idle for a tracked subject with nothing in progress.
4
+ */
5
+ export type StateDotState = 'done' | 'warning' | 'ongoing' | 'error' | 'idle';
3
6
  /**
4
7
  * Render a state dot.
5
- * @param props.state - which of the four states to show.
8
+ * @param props.state - which of `done`, `warning`, `ongoing`, `error`, or `idle` to show.
6
9
  * @param props.size - outer diameter in px (default 10, the figma size).
7
10
  * @param props.className - extra class for layout placement.
8
11
  * @returns the dot element (aria-hidden; pair with text for accessibility).
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Render a toggle switch.
3
+ * @param props.checked - the current state; the control is fully controlled.
4
+ * @param props.onChange - called with the state the click asks for.
5
+ * @param props.label - localized accessible name, owned by the render site.
6
+ * @param props.disabled - whether the control refuses input; owners also set it
7
+ * while a write is in flight, not only when a deployment locks the toggle.
8
+ * @param props.title - localized hover text, typically why the toggle is locked.
9
+ * @param props.className - extra class for layout placement.
10
+ * @returns the switch element.
11
+ */
12
+ export declare function Switch({ 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=Switch.d.ts.map
@@ -0,0 +1,32 @@
1
+ import type { ReactNode } from 'react';
2
+ /** Palette selector; each tone names one shipped appearance. */
3
+ export type TagTone =
4
+ /** Hairline outline on tertiary text: the read-only default. */
5
+ 'outline'
6
+ /** Inverted fill: one tag per group that names the current selection. */
7
+ | 'solid'
8
+ /** Platform-gray fill: a neutral fact with no status meaning. */
9
+ | 'neutral'
10
+ /** Text only, no fill: a fact stated more quietly than `neutral`. */
11
+ | 'quiet'
12
+ /** Tinted green: a healthy or enabled state. */
13
+ | 'success'
14
+ /** Tinted blue: informational classification, not health. */
15
+ | 'info'
16
+ /** Tinted amber: attention needed, not yet a failure. */
17
+ | 'warning'
18
+ /** Tinted red: a failure. */
19
+ | 'danger';
20
+ /**
21
+ * Render a read-only tag.
22
+ * @param props.tone - which palette to use (default `outline`).
23
+ * @param props.className - extra class for layout placement.
24
+ * @param props.children - the localized label, owned by the render site.
25
+ * @returns the tag element.
26
+ */
27
+ export declare function Tag({ tone, className, children }: {
28
+ tone?: TagTone;
29
+ className?: string | undefined;
30
+ children?: ReactNode;
31
+ }): import("react").JSX.Element;
32
+ //# sourceMappingURL=Tag.d.ts.map
@@ -0,0 +1,8 @@
1
+ /** Compact human-readable byte counts shared by attachment presenters. @module @deepseek-ai/dsh-client-ui-primitives/file-size */
2
+ /**
3
+ * Byte count as compact user-facing size text (`312B`, `4.2KB`, `1.5MB`, `2.4GB`).
4
+ * @param bytes - exact byte count.
5
+ * @returns whole-unit text with one decimal below ten of the chosen unit.
6
+ */
7
+ export declare function fileSizeText(bytes: number): string;
8
+ //# sourceMappingURL=file-size.d.ts.map
@@ -8,6 +8,9 @@ export type { DisclosureRowProps } from './DisclosureRow.tsx';
8
8
  export { Button } from './Button.tsx';
9
9
  export type { ButtonVariant } from './Button.tsx';
10
10
  export { Pill } from './Pill.tsx';
11
+ export { Tag } from './Tag.tsx';
12
+ export type { TagTone } from './Tag.tsx';
13
+ export { Switch } from './Switch.tsx';
11
14
  export { Input } from './Input.tsx';
12
15
  export { Menu } from './Menu.tsx';
13
16
  export type { MenuEntry, MenuItem, MenuSeparator, MenuLabel } from './Menu.tsx';
@@ -27,12 +30,17 @@ export { BrandWordmark } from './BrandWordmark.tsx';
27
30
  export type { BrandWordmarkProps } from './BrandWordmark.tsx';
28
31
  export { ReferenceIcon } from './ReferenceIcon.tsx';
29
32
  export type { ReferenceIconKind, ReferenceIconProps } from './ReferenceIcon.tsx';
33
+ export { LinkIcon, classifyLinkPath } from './LinkIcon.tsx';
34
+ export type { LinkIconKind, LinkIconProps } from './LinkIcon.tsx';
30
35
  export { projectUserText } from './user-text.tsx';
31
36
  export { Tooltip } from './Tooltip.tsx';
32
37
  export type { TooltipSide } from './Tooltip.tsx';
33
38
  export { Toast } from './Toast.tsx';
39
+ export { fileSizeText } from './file-size.ts';
40
+ export { DocumentFileIcon } from './DocumentFileIcon.tsx';
34
41
  export { writeClipboard } from './clipboard.ts';
35
42
  export { relativeTime } from './relative-time.ts';
43
+ export { rankByName } from './rank-by-name.ts';
36
44
  export type { RelativeTime, RelativeTimeUnit } from './relative-time.ts';
37
45
  export { JsonTree } from './JsonTree.tsx';
38
46
  export type { JsonTreeProps, JsonTreeLabels } from './JsonTree.tsx';
@@ -51,7 +59,6 @@ export type { CodeBlockProps } from './markdown/CodeBlock.tsx';
51
59
  export { JsonBlock } from './markdown/JsonBlock.tsx';
52
60
  export { MarkdownText } from './markdown/MarkdownText.tsx';
53
61
  export type { MarkdownCodeLabels, MarkdownFileMentions, MarkdownLabels } from './markdown/MarkdownText.tsx';
54
- export { MessageText } from './markdown/MessageText.tsx';
55
62
  export { extractMarkdownPlainText } from './markdown/plain-text.ts';
56
63
  export type { MarkdownPlainTextMode, MarkdownPlainTextOptions } from './markdown/plain-text.ts';
57
64
  export * from './icons/index.tsx';
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Shared ranking for `/` menu candidates: the query must be a
3
+ * case-insensitive ordered subsequence of the candidate name. Prefix hits
4
+ * rank first, then the strongest alignment score, then the source order of
5
+ * the input. Decision record:
6
+ * .agents/notes/archived/feature/2026-08-04-web-slash-command-fuzzy-discovery.md
7
+ */
8
+ /**
9
+ * Rank named items by a menu query.
10
+ * @param items - candidates in source order (a host catalog, then client contributions).
11
+ * @param rawQuery - the text typed after the trigger, matched case-insensitively.
12
+ * @returns the matching items: prefix hits first, then by alignment score,
13
+ * then in source order. The input list itself for an empty query.
14
+ */
15
+ export declare function rankByName<T extends {
16
+ readonly name: string;
17
+ }>(items: readonly T[], rawQuery: string): readonly T[];
18
+ //# sourceMappingURL=rank-by-name.d.ts.map
@@ -2,18 +2,28 @@
2
2
  * Display projection of reference forms in sent user text (bubble and queue
3
3
  * rows). The logged model text remains the single truth; this is presentation
4
4
  * only, and every part renders inline so a single-line message never breaks
5
- * across lines. Three decoration sources, by precedence: the wire session form
5
+ * across lines. Four decoration sources, by precedence: the wire session form
6
6
  * `@[label](dsh-session:...)` folds to its label; exact session labels
7
- * supplied by an adjacent recall decorate their bare `@label` mention; and
8
- * plain `/name` / `@name` word-boundary tokens decorate by shape alone (sent
9
- * tokens were validated at compose time).
7
+ * supplied by an adjacent recall decorate their bare `@label` mention; plain
8
+ * `@name` word-boundary tokens decorate by shape alone; and a plain `/name`
9
+ * token decorates only when the caller names it — a skill the host actually
10
+ * loaded for that message (ui-chat reads the step's `skill-invocation`
11
+ * injections) or the command a command-input bubble echoes — so `/123` or a
12
+ * stray `/word` stays plain text. A `/name` token is whitespace-bounded like
13
+ * the host skill gesture (`dsh-tool-skill`): it ends at whitespace or the
14
+ * text end, so slash paths (`/nfs-hg/xxx`, `/plan.md`) and punctuation-glued
15
+ * tokens (`/plan。`) stay plain even for a loaded name.
10
16
  */
11
17
  import type { ReactNode } from 'react';
12
18
  /**
13
19
  * Split one sent text into inline plain runs and reference chips.
14
20
  * @param text - the logged model text of the message or queue row.
15
21
  * @param sessionLabels - exact session mention labels associated by an adjacent recall.
22
+ * @param slashNames - names a `/name` token may decorate as: the skills the
23
+ * host loaded for this message, or the command a command bubble echoes
24
+ * (unsent queue rows pass none).
25
+ * @param slashKind - the chip kind those tokens render as.
16
26
  * @returns inline nodes covering the whole text.
17
27
  */
18
- export declare function projectUserText(text: string, sessionLabels: readonly string[]): ReactNode;
28
+ export declare function projectUserText(text: string, sessionLabels: readonly string[], slashNames?: readonly string[], slashKind?: 'skill' | 'command'): ReactNode;
19
29
  //# sourceMappingURL=user-text.d.ts.map
@@ -20,6 +20,14 @@
20
20
  white-space: nowrap;
21
21
  }
22
22
 
23
+ /* Skill and command tokens read as code: the theme's code family at the
24
+ consumer's own size and line height, so the chip sits on the bubble line
25
+ like the plain runs around it. `@` chips keep the body face — a file or
26
+ session name is a label, not code. */
27
+ .slashChip {
28
+ font-family: var(--dsw-font-markdown-code-font-family);
29
+ }
30
+
23
31
  /* Inline reference glyphs (always ReferenceIcon svgs) ride the consumer's own
24
32
  font: 1em keeps the glyph at the text's size in the bubble (14px + user
25
33
  setting), the queue preview's fixed 13px line, and any future consumer — a
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.2-alpha.5",
4
+ "version": "0.1.3-alpha.2",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -1,9 +0,0 @@
1
- .text {
2
- white-space: pre-wrap;
3
- word-break: break-word;
4
- /* Font metrics inherit from the consumer's container (bubble 16/24,
5
- assistant flow 16/28) — a generic text primitive must not pin its own
6
- size, or every consumer's line grid breaks (44px bubble spec regression). */
7
- font-size: inherit;
8
- line-height: inherit;
9
- }
@@ -1,4 +0,0 @@
1
- export declare function MessageText({ text }: {
2
- text: string;
3
- }): import("react").JSX.Element;
4
- //# sourceMappingURL=MessageText.d.ts.map