@morlay/dsh-client-ui-primitives 0.0.7 → 0.0.9

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.
Files changed (83) hide show
  1. package/README.md +32 -9
  2. package/dist/client-DYp99CgT.mjs +3730 -0
  3. package/dist/client-uyVkC7mu.cjs +17197 -0
  4. package/dist/client.cjs +54 -0
  5. package/dist/client.d.cts +4 -0
  6. package/dist/client.d.mts +3 -11680
  7. package/dist/client.mjs +3 -4575
  8. package/dist/index-AMHtcyMt.d.mts +647 -0
  9. package/dist/index.cjs +54 -0
  10. package/dist/index.d.mts +4 -5
  11. package/dist/index.mjs +4 -5
  12. package/dist/reference-hchCWm3z.cjs +482 -0
  13. package/dist/reference.cjs +4 -0
  14. package/dist/reference.d.mts +3 -0
  15. package/dist/reference.mjs +1 -0
  16. package/package.json +31 -35
  17. package/src/client/controls/Bubble.module.css +17 -0
  18. package/src/client/controls/Bubble.tsx +17 -0
  19. package/src/client/controls/Button.module.css +10 -0
  20. package/src/client/controls/Button.tsx +29 -0
  21. package/src/client/controls/DisclosureRow.module.css +22 -0
  22. package/src/client/controls/DisclosureRow.tsx +20 -0
  23. package/src/client/controls/IconButton.module.css +50 -0
  24. package/src/client/controls/IconButton.tsx +47 -0
  25. package/src/client/controls/ModelRouteList.module.css +100 -0
  26. package/src/client/controls/ModelRouteList.tsx +118 -0
  27. package/src/client/controls/MultilineField.module.css +26 -0
  28. package/src/client/controls/MultilineField.tsx +19 -0
  29. package/src/client/controls/SearchSelect.module.css +34 -0
  30. package/src/client/controls/SearchSelect.tsx +138 -0
  31. package/src/client/controls/SeatButton.module.css +53 -0
  32. package/src/client/controls/SeatButton.tsx +39 -0
  33. package/src/client/controls/Spinner.module.css +18 -0
  34. package/src/client/controls/Spinner.tsx +14 -0
  35. package/src/client/controls/TagInput.module.css +105 -0
  36. package/src/client/controls/TagInput.tsx +152 -0
  37. package/src/client/controls/TimeLabel.module.css +16 -0
  38. package/src/client/controls/TimeLabel.tsx +15 -0
  39. package/src/client/controls/VisuallyHidden.module.css +9 -0
  40. package/src/client/controls/VisuallyHidden.tsx +16 -0
  41. package/src/client/controls/classes.ts +5 -0
  42. package/src/client/controls/index.ts +24 -0
  43. package/src/client/controls/tags.ts +24 -0
  44. package/src/client/index.ts +16 -2
  45. package/src/client/layout/Row.tsx +89 -0
  46. package/src/client/layout/Stack.tsx +82 -0
  47. package/src/client/layout/Text.tsx +61 -0
  48. package/src/client/layout/index.ts +16 -0
  49. package/src/client/layout/layout.module.css +217 -0
  50. package/src/client/layout/scales.ts +91 -0
  51. package/src/client/schema-form/Editor.tsx +65 -65
  52. package/src/client/schema-form/SchemaForm.tsx +9 -4
  53. package/src/client/schema-form/controller.ts +5 -2
  54. package/src/client/schema-form/geometry.ts +3 -0
  55. package/src/client/schema-form/index.ts +5 -0
  56. package/src/client/schema-form/schema-form.module.css +335 -0
  57. package/src/client/schema-form/testing/fake-scope.ts +0 -1
  58. package/src/client/schema-form/value.tsx +15 -9
  59. package/src/client/settings-form/SettingsFieldRow.module.css +93 -0
  60. package/src/client/settings-form/SettingsFieldRow.tsx +105 -0
  61. package/src/client/settings-form/index.ts +5 -18
  62. package/src/css-modules.d.ts +6 -0
  63. package/src/index.ts +6 -2
  64. package/src/reference-markdown.tsx +2 -6
  65. package/dist/rolldown-runtime-EAsCxrDo.mjs +0 -14
  66. package/locale/en.json +0 -6
  67. package/locale/zh.json +0 -6
  68. package/src/client/schema-form/styles.ts +0 -321
  69. package/src/client/settings-form/SettingsForm.styles.ts +0 -58
  70. package/src/client/settings-form/SettingsForm.tsx +0 -68
  71. package/src/client/settings-form/fields.styles.ts +0 -158
  72. package/src/client/settings-form/fields.tsx +0 -184
  73. package/src/client/settings-form/form-model.ts +0 -339
  74. package/src/client/styling/css.ts +0 -27
  75. package/src/client/styling/focus.ts +0 -9
  76. package/src/client/styling/index.ts +0 -6
  77. package/src/client/styling/styled.tsx +0 -54
  78. package/src/client/styling/styling.ts +0 -142
  79. package/src/client/styling/token.ts +0 -275
  80. package/src/client/styling/toolkit.ts +0 -37
  81. package/src/client/theme.generated.ts +0 -846
  82. package/src/client/theme.ts +0 -5
  83. /package/src/{client/markdown-text.ts → markdown-text.ts} +0 -0
@@ -0,0 +1,82 @@
1
+ // `Stack`:纵向列 + 间距档。设置面上绝大多数区块都是它(页根、分组、字段列),
2
+ // 间距只从档位里选,页面不写数值。
3
+
4
+ import { forwardRef, type ElementType, type HTMLAttributes, type ReactNode } from "react";
5
+ import { classes } from "../controls/classes.ts";
6
+ import css from "./layout.module.css";
7
+ import {
8
+ alignClass,
9
+ gapClass,
10
+ padClass,
11
+ type LayoutAlign,
12
+ type LayoutGap,
13
+ type LayoutPad,
14
+ } from "./scales.ts";
15
+
16
+ export interface StackProps extends HTMLAttributes<HTMLDivElement> {
17
+ // 渲染成哪个元素(区块用 `section`、列表用 `ul`、行内用 `span`)。
18
+ as?: ElementType;
19
+ // 子项之间的纵向间距。
20
+ gap?: LayoutGap;
21
+ // 交叉轴对齐;缺省 `stretch`(子项撑满整列)。
22
+ align?: LayoutAlign;
23
+ // 内距档;缺省不留内距。
24
+ pad?: LayoutPad;
25
+ // 撑开:吃掉剩下的宽度并允许收缩。
26
+ grow?: boolean;
27
+ // 卡片底座(边框 + 圆角 + 底色)。
28
+ boxed?: boolean;
29
+ // 不被压缩(页头、动作排这类固定项)。
30
+ fixed?: boolean;
31
+ // 窄列宽度(对话消息那一列)。
32
+ narrow?: boolean;
33
+ // 占满:页面根(宽高撑满、自己不滚)。
34
+ fill?: boolean;
35
+ // 滚动区:吃掉剩下的高度,内容长了它自己滚。
36
+ scroll?: boolean;
37
+ // 列表(配 `as="ul"`):去掉列表标记与内距。
38
+ plain?: boolean;
39
+ }
40
+
41
+ export const Stack = forwardRef<HTMLElement, StackProps>(function Stack(
42
+ {
43
+ as: Element = "div",
44
+ gap,
45
+ align,
46
+ pad,
47
+ grow = false,
48
+ boxed = false,
49
+ fixed = false,
50
+ narrow = false,
51
+ fill = false,
52
+ scroll = false,
53
+ plain = false,
54
+ className,
55
+ children,
56
+ ...rest
57
+ },
58
+ ref,
59
+ ): ReactNode {
60
+ return (
61
+ <Element
62
+ ref={ref}
63
+ className={classes(
64
+ css.stack,
65
+ gapClass(css, gap),
66
+ alignClass(css, align),
67
+ padClass(css, pad),
68
+ grow ? css.grow : undefined,
69
+ boxed ? css.boxed : undefined,
70
+ fixed ? css.fixed : undefined,
71
+ narrow ? css.narrow : undefined,
72
+ fill ? css.fill : undefined,
73
+ scroll ? css.scroll : undefined,
74
+ plain ? css.plain : undefined,
75
+ className,
76
+ )}
77
+ {...rest}
78
+ >
79
+ {children}
80
+ </Element>
81
+ );
82
+ });
@@ -0,0 +1,61 @@
1
+ // `Text`:文本档位(字号 / 颜色 / 字重 / 等宽 / 截断)。设置面上的标题、说明、摘要、诊断行都从这里选档,
2
+ // 页面不写字号与颜色。
3
+
4
+ import type { ElementType, HTMLAttributes, ReactNode } from "react";
5
+ import { classes } from "../controls/classes.ts";
6
+ import css from "./layout.module.css";
7
+ import {
8
+ sizeClass,
9
+ toneClass,
10
+ weightClass,
11
+ type TextSize,
12
+ type TextTone,
13
+ type TextWeight,
14
+ } from "./scales.ts";
15
+
16
+ export interface TextProps extends Omit<HTMLAttributes<HTMLElement>, "children" | "color"> {
17
+ // 渲染成哪个元素(标题用 `h4`、说明用 `p`、行内摘要用 `span`)。
18
+ as?: ElementType;
19
+ // 字号档;缺省继承。
20
+ size?: TextSize;
21
+ // 颜色档;缺省继承。
22
+ tone?: TextTone;
23
+ // 字重档(区块标题那一档)。
24
+ weight?: TextWeight;
25
+ // 等宽(诊断行、配置值那类文本)。
26
+ mono?: boolean;
27
+ // 一行放不下就省略号截断。
28
+ truncate?: boolean;
29
+ // 数字等宽(计数、分页这类会跳动的数值)。
30
+ tabular?: boolean;
31
+ children?: ReactNode;
32
+ }
33
+
34
+ export function Text({
35
+ as: Element = "span",
36
+ size,
37
+ tone,
38
+ weight,
39
+ mono = false,
40
+ truncate = false,
41
+ tabular = false,
42
+ className,
43
+ children,
44
+ }: TextProps): ReactNode {
45
+ return (
46
+ <Element
47
+ className={classes(
48
+ css.text,
49
+ sizeClass(css, size),
50
+ toneClass(css, tone),
51
+ weightClass(css, weight),
52
+ mono ? css.mono : undefined,
53
+ truncate ? css.truncate : undefined,
54
+ tabular ? css.tabular : undefined,
55
+ className,
56
+ )}
57
+ >
58
+ {children}
59
+ </Element>
60
+ );
61
+ }
@@ -0,0 +1,16 @@
1
+ // 布局原语:业务页面只摆结构与选档,不写样式。
2
+ //
3
+ // 通用原语(`Stack` / `Row` / `Text` / `Panel`)覆盖设置面的绝大多数排法;成型的那几件(字段行
4
+ // `SettingsFieldRow`、标签输入 `TagInput` 等)住在 `../controls` 与 `../settings-form`。
5
+
6
+ export { Row, type RowProps } from "./Row.tsx";
7
+ export { Stack, type StackProps } from "./Stack.tsx";
8
+ export { Text, type TextProps } from "./Text.tsx";
9
+ export type {
10
+ LayoutAlign,
11
+ LayoutGap,
12
+ LayoutJustify,
13
+ LayoutPad,
14
+ TextSize,
15
+ TextTone,
16
+ } from "./scales.ts";
@@ -0,0 +1,217 @@
1
+ /* 布局原语共用的档位表:几何只有一套(间距 / 内距 / 文本档位),四个原语都从这份里取类名。
2
+ 数值照官方设置面的尺度:2/4/6/8/12/14/16 的间距档、11/12/13/16 的字号档。 */
3
+
4
+ /* 纵向列与横向行的底座。 */
5
+ .stack {
6
+ display: flex;
7
+ flex-direction: column;
8
+ min-width: 0;
9
+ }
10
+
11
+ .row {
12
+ display: flex;
13
+ flex-direction: row;
14
+ align-items: center;
15
+ min-width: 0;
16
+ }
17
+
18
+ /* 间距档。 */
19
+ .gap0 {
20
+ gap: 0;
21
+ }
22
+ .gap2 {
23
+ gap: 2px;
24
+ }
25
+ .gap4 {
26
+ gap: 4px;
27
+ }
28
+ .gap6 {
29
+ gap: 6px;
30
+ }
31
+ .gap8 {
32
+ gap: 8px;
33
+ }
34
+ .gap10 {
35
+ gap: 10px;
36
+ }
37
+ .gap12 {
38
+ gap: 12px;
39
+ }
40
+ .gap14 {
41
+ gap: 14px;
42
+ }
43
+ .gap16 {
44
+ gap: 16px;
45
+ }
46
+
47
+ /* 交叉轴对齐:不写就是 `stretch`(列里子项撑满,行里子项等高)。 */
48
+ .alignStart {
49
+ align-items: flex-start;
50
+ }
51
+ .alignCenter {
52
+ align-items: center;
53
+ }
54
+ .alignEnd {
55
+ align-items: flex-end;
56
+ }
57
+
58
+ /* 主轴分布:`between` 是「左列文本 + 右侧控件」那一行,`end` 是分页那种贴右。 */
59
+ .justifyBetween {
60
+ justify-content: space-between;
61
+ }
62
+ .justifyEnd {
63
+ justify-content: flex-end;
64
+ }
65
+ .justifyCenter {
66
+ justify-content: center;
67
+ }
68
+
69
+ /* 一行放不下就换行(标签与按钮排)。 */
70
+ .wrap {
71
+ flex-wrap: wrap;
72
+ }
73
+
74
+ /* 撑开:吃掉剩下的宽度并允许收缩(长文本因此不会把整行撑出去)。 */
75
+ .grow {
76
+ flex: 1 1 auto;
77
+ min-width: 0;
78
+ }
79
+
80
+ /* 贴右:把这一项推到行尾。 */
81
+ .push {
82
+ margin-left: auto;
83
+ }
84
+
85
+ /* 占满:整块页面的根(宽高都撑满,自己不滚——滚动交给里面的 `scroll` 那一层)。 */
86
+ .fill {
87
+ box-sizing: border-box;
88
+ width: 100%;
89
+ height: 100%;
90
+ overflow: hidden;
91
+ }
92
+
93
+ /* 滚动区:吃掉剩下的高度,内容长了它自己滚。 */
94
+ .scroll {
95
+ flex: 1 1 auto;
96
+ min-height: 0;
97
+ overflow-y: auto;
98
+ }
99
+
100
+ /* 列表(`as="ul"` 时):去掉列表标记与内距。 */
101
+ .plain {
102
+ margin: 0;
103
+ padding: 0;
104
+ list-style: none;
105
+ }
106
+
107
+ /* 内距档:`card` 是模式卡片那档,`body` 是卡片内容那档,`page` / `row` / `blocking` 见注释。
108
+ 上下必须对称——不对称的内距会让里面的行看着不在卡片中线(旧实现里的 4/8 与 8/4 就是这么偏的)。 */
109
+ .padNone {
110
+ padding: 0;
111
+ }
112
+ .padCard {
113
+ padding: 8px 12px;
114
+ }
115
+ .padBody {
116
+ padding: 8px 0;
117
+ }
118
+ /* 页面根那一档。 */
119
+ .padPage {
120
+ padding: 24px 28px;
121
+ }
122
+ /* 列表里的一行卡片。 */
123
+ .padRow {
124
+ padding: 10px 12px;
125
+ }
126
+ /* 居中的提示块(加载中 / 阻塞提示)。 */
127
+ .padBlocking {
128
+ padding: 32px 40px;
129
+ }
130
+
131
+ /* 文本档:字号 / 行高 / 颜色 / 字重 / 等宽 / 截断 / 等宽数字。 */
132
+ .text {
133
+ margin: 0;
134
+ }
135
+ .sizeXs {
136
+ font-size: 11px;
137
+ line-height: 1.5;
138
+ }
139
+ .sizeSm {
140
+ font-size: 12px;
141
+ line-height: 18px;
142
+ }
143
+ .sizeMd {
144
+ font-size: 13px;
145
+ line-height: 20px;
146
+ }
147
+ .sizeBase {
148
+ font-size: 14px;
149
+ line-height: 24px;
150
+ }
151
+ .sizeLg {
152
+ font-size: 16px;
153
+ line-height: 24px;
154
+ }
155
+ .tonePrimary {
156
+ color: var(--dsw-alias-label-primary);
157
+ }
158
+ .toneSecondary {
159
+ color: var(--dsw-alias-label-secondary);
160
+ }
161
+ .toneTertiary {
162
+ color: var(--dsw-alias-label-tertiary);
163
+ }
164
+ /* 失败提示那一档:官方主题里有就用它,没有就退回主文本色。 */
165
+ .toneDanger {
166
+ color: var(--dsw-alias-label-error, var(--dsw-alias-label-primary));
167
+ }
168
+ .weightMedium {
169
+ font-weight: 500;
170
+ }
171
+ .strong {
172
+ font-weight: 600;
173
+ }
174
+ .mono {
175
+ font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
176
+ word-break: break-all;
177
+ }
178
+ .truncate {
179
+ overflow: hidden;
180
+ text-overflow: ellipsis;
181
+ white-space: nowrap;
182
+ }
183
+ .tabular {
184
+ font-variant-numeric: tabular-nums;
185
+ }
186
+
187
+ /* 卡片底座:边框 + 圆角 + 底色(列表里的一行、用量块)。内距由 `pad` 档给。 */
188
+ .boxed {
189
+ border: 1px solid var(--dsw-alias-border-l1);
190
+ border-radius: 10px;
191
+ background: var(--dsw-alias-bg-base);
192
+ }
193
+
194
+ /* 不被压缩:页头、动作排这类固定项(内容变长时它们不该被压成 min-content)。 */
195
+ .fixed {
196
+ flex: none;
197
+ }
198
+
199
+ /* 两轴不同间距的一排(统计项:列间距 20,换行后的行间距 6)。 */
200
+ .gapWide {
201
+ column-gap: 20px;
202
+ row-gap: 6px;
203
+ }
204
+
205
+ /* 窄列:对话消息那一列。上游以宽度轴的比例表达 Figma 那个 525px 上限(525/748 ≈ 0.702),
206
+ 748px 的兜底覆盖"挂在会话列之外"的挂载(此时轴变量不在)。 */
207
+ .narrow {
208
+ min-width: 0;
209
+ max-width: min(calc(var(--dsh-chat-content-width, 748px) * 0.702), 82%);
210
+ }
211
+
212
+ /* 搜索框那一档宽度(列表与设置面的搜索行)。 */
213
+ .wSearch {
214
+ width: 360px;
215
+ max-width: 100%;
216
+ flex: none;
217
+ }
@@ -0,0 +1,91 @@
1
+ // 布局原语的档位:几何只有这一套,四个原语与消费方都从这里取,页面不写数值。
2
+
3
+ // 间距档(px):2/4/6/8 是行内与字段内的尺度,12/14/16 是区块之间的尺度。
4
+ export type LayoutGap = 0 | 2 | 4 | 6 | 8 | 10 | 12 | 14 | 16 | "wide";
5
+
6
+ // 交叉轴对齐:`stretch`(缺省)让列里子项撑满、行里子项等高。
7
+ export type LayoutAlign = "stretch" | "start" | "center" | "end";
8
+
9
+ // 主轴分布:`between` 用于"左列文本 + 右侧控件"那一行,`end` 用于贴右(分页)。
10
+ export type LayoutJustify = "start" | "center" | "between" | "end";
11
+
12
+ // 内距档:`card` = 模式卡片那档,`body` = 卡片内容那档,`page` / `row` / `blocking` 见样式表。
13
+ export type LayoutPad = "none" | "card" | "body" | "page" | "row" | "blocking";
14
+
15
+ // 文本字号档:11 / 12 / 13 / 16px。
16
+ export type TextSize = "xs" | "sm" | "md" | "base" | "lg";
17
+
18
+ // 文本颜色档。
19
+ export type TextTone = "primary" | "secondary" | "tertiary" | "danger";
20
+
21
+ // 文本字重档。
22
+ export type TextWeight = "medium" | "strong";
23
+
24
+ // 档位 → 类名。CSS Modules 的映射查表可能给 undefined(exactOptionalPropertyTypes),交给 `classes` 过滤。
25
+ export function gapClass(
26
+ css: Readonly<Record<string, string | undefined>>,
27
+ gap?: LayoutGap,
28
+ ): string | undefined {
29
+ if (gap === undefined) return undefined;
30
+ // `wide` 是两轴不同间距的那一档(见样式表的 `.gapWide`)。
31
+ return gap === "wide" ? css.gapWide : css[`gap${gap}`];
32
+ }
33
+
34
+ export function alignClass(
35
+ css: Readonly<Record<string, string | undefined>>,
36
+ align?: LayoutAlign,
37
+ ): string | undefined {
38
+ if (align === undefined || align === "stretch") return undefined;
39
+ if (align === "start") return css.alignStart;
40
+ return align === "center" ? css.alignCenter : css.alignEnd;
41
+ }
42
+
43
+ export function justifyClass(
44
+ css: Readonly<Record<string, string | undefined>>,
45
+ justify?: LayoutJustify,
46
+ ): string | undefined {
47
+ if (justify === undefined) return undefined;
48
+ if (justify === "between") return css.justifyBetween;
49
+ if (justify === "end") return css.justifyEnd;
50
+ return justify === "center" ? css.justifyCenter : undefined;
51
+ }
52
+
53
+ export function padClass(
54
+ css: Readonly<Record<string, string | undefined>>,
55
+ pad?: LayoutPad,
56
+ ): string | undefined {
57
+ if (pad === undefined || pad === "none") return undefined;
58
+ if (pad === "card") return css.padCard;
59
+ if (pad === "body") return css.padBody;
60
+ if (pad === "page") return css.padPage;
61
+ return pad === "row" ? css.padRow : css.padBlocking;
62
+ }
63
+
64
+ export function sizeClass(
65
+ css: Readonly<Record<string, string | undefined>>,
66
+ size?: TextSize,
67
+ ): string | undefined {
68
+ if (size === undefined) return undefined;
69
+ if (size === "xs") return css.sizeXs;
70
+ if (size === "sm") return css.sizeSm;
71
+ if (size === "md") return css.sizeMd;
72
+ return size === "base" ? css.sizeBase : css.sizeLg;
73
+ }
74
+
75
+ export function toneClass(
76
+ css: Readonly<Record<string, string | undefined>>,
77
+ tone?: TextTone,
78
+ ): string | undefined {
79
+ if (tone === undefined) return undefined;
80
+ if (tone === "primary") return css.tonePrimary;
81
+ if (tone === "secondary") return css.toneSecondary;
82
+ return tone === "tertiary" ? css.toneTertiary : css.toneDanger;
83
+ }
84
+
85
+ export function weightClass(
86
+ css: Readonly<Record<string, string | undefined>>,
87
+ weight?: TextWeight,
88
+ ): string | undefined {
89
+ if (weight === undefined) return undefined;
90
+ return weight === "medium" ? css.weightMedium : css.strong;
91
+ }