@svadmin/surface 0.13.6 → 0.14.0
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 +1 -2
- package/STYLING.md +4 -5
- package/compatibility.json +1 -1
- package/dist/builtin-definitions.js +4 -4
- package/dist/builtin-schemas.d.ts +0 -3
- package/dist/builtin-schemas.js +0 -2
- package/dist/business-definitions.d.ts +0 -2
- package/dist/business-definitions.js +1 -2
- package/dist/components/ActivityFeedWidget.svelte +3 -4
- package/dist/components/MetricWidget.svelte +3 -3
- package/dist/components/ResourceDetailWidget.svelte +4 -6
- package/dist/components/ResourceFormBody.svelte +1 -1
- package/dist/components/ResourceTableWidget.svelte +3 -3
- package/dist/components/SurfaceEditPreview.svelte +2 -3
- package/dist/components/SurfaceEditPreview.svelte.d.ts +0 -1
- package/dist/components/SurfaceRenderer.svelte +2 -2
- package/dist/components/SvarGridWidget.svelte +1 -1
- package/dist/design-contract.d.ts +1 -1
- package/dist/recipes.d.ts +3 -6
- package/dist/recipes.js +9 -10
- package/dist/styles/editor.css +2 -6
- package/dist/styles/editor.d.ts +1 -2
- package/dist/styles/editor.js +1 -2
- package/dist/styles.css +9 -19
- package/dist/svar-schema.d.ts +0 -1
- package/dist/svar-schema.js +0 -1
- package/dist/workflows/catalog.d.ts +0 -2
- package/dist/workflows/catalog.js +0 -2
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -136,14 +136,13 @@ The Svelte `SurfaceEditPreview` component accepts a controlled revision and untr
|
|
|
136
136
|
{catalog}
|
|
137
137
|
{dataProvider}
|
|
138
138
|
scopeKey={trustedSessionRevision}
|
|
139
|
-
density="comfortable"
|
|
140
139
|
onApply={applyApprovedRevision}
|
|
141
140
|
/>
|
|
142
141
|
```
|
|
143
142
|
|
|
144
143
|
It leaves the current surface intact during streaming, offers a separate preview/back action, and revalidates at the explicit apply click. It calls `onApply(candidate)` only for a valid proposal. The host performs any persistence with server authorization and atomic revision compare-and-swap, then updates `revision` and clears `proposal`. Missing handlers, invalid proposals and pending callbacks disable application. A rejected callback reports an error without changing the controlled revision. Changing scope does not authorize an old proposal: the host must discard old proposals as described above.
|
|
145
144
|
|
|
146
|
-
Preview controls use local finite class helpers and maintained static CSS. `@svadmin/surface/editor.css` remains available for explicit CSS collection.
|
|
145
|
+
Preview controls use local finite class helpers and maintained static CSS. `@svadmin/surface/editor.css` remains available for explicit CSS collection. Button variants and complete-color semantic CSS variable overrides are preserved. Widgets use local semantic recipes to retain compatibility with older UI peers; no UI-generated helpers are copied during build. The separate `@svadmin/surface/styles.css` entry remains available and rendering components also import it automatically; see `STYLING.md`.
|
|
147
146
|
|
|
148
147
|
## Built-in catalog
|
|
149
148
|
|
package/STYLING.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Surface semantic styles
|
|
2
2
|
|
|
3
|
-
默认 `svadmin/v1` 的校验规则和未指定变体时的组件样式保持兼容。新语义变体必须显式选择 `styledSurfaceCatalog`,不能只把 tone
|
|
3
|
+
默认 `svadmin/v1` 的校验规则和未指定变体时的组件样式保持兼容。新语义变体必须显式选择 `styledSurfaceCatalog`,不能只把 tone 添加到旧版 spec。
|
|
4
4
|
|
|
5
5
|
```ts
|
|
6
6
|
import '@svadmin/ui/app.css';
|
|
@@ -8,7 +8,7 @@ import '@svadmin/surface/styles.css';
|
|
|
8
8
|
import { styledSurfaceCatalog, STYLED_SURFACE_CATALOG_VERSION } from '@svadmin/surface/svelte';
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
-
将 spec.catalogVersion 设置为 STYLED_SURFACE_CATALOG_VERSION,并把同一 styledSurfaceCatalog 传给提示生成器、校验器和 SurfaceRenderer 的 catalog 属性。这样三个环节使用同一组件契约。`metric` 支持 tone(neutral/success/warning/danger/info
|
|
11
|
+
将 spec.catalogVersion 设置为 STYLED_SURFACE_CATALOG_VERSION,并把同一 styledSurfaceCatalog 传给提示生成器、校验器和 SurfaceRenderer 的 catalog 属性。这样三个环节使用同一组件契约。`metric` 支持 tone(neutral/success/warning/danger/info);`resource-table` 不需要额外外观变体。
|
|
12
12
|
|
|
13
13
|
```json
|
|
14
14
|
{
|
|
@@ -16,8 +16,7 @@ import { styledSurfaceCatalog, STYLED_SURFACE_CATALOG_VERSION } from '@svadmin/s
|
|
|
16
16
|
"props": {
|
|
17
17
|
"label": "待处理订单",
|
|
18
18
|
"format": "number",
|
|
19
|
-
"tone": "warning"
|
|
20
|
-
"density": "compact"
|
|
19
|
+
"tone": "warning"
|
|
21
20
|
}
|
|
22
21
|
}
|
|
23
22
|
```
|
|
@@ -26,7 +25,7 @@ import { styledSurfaceCatalog, STYLED_SURFACE_CATALOG_VERSION } from '@svadmin/s
|
|
|
26
25
|
|
|
27
26
|
Surface 使用本地有限 recipe helper 和静态 styles.css;design-contract 统一从 @svadmin/ui/design-contract 导入,要求 UI >=0.73.0 <0.74.0。不复制 UI 生成物,也不依赖样式编译器。渲染组件自动导入语义样式;原有 styles.css 子路径仍可显式导入。UI 基础样式仍由宿主通过 @svadmin/ui/app.css 加载。构建仅执行 svelte-package;styles:check 检查全部有限变体及静态 CSS 边界。
|
|
28
27
|
|
|
29
|
-
editor.css 与本地 styles/editor.ts 一起维护,保留
|
|
28
|
+
editor.css 与本地 styles/editor.ts 一起维护,保留 button variant、禁用/焦点状态和语义变量覆盖;editor.css 子路径不变。宿主升级时应同时升级 UI 与 Surface,并重新执行消费侧构建。
|
|
30
29
|
|
|
31
30
|
AI 只能选择公开枚举,不能指定 class/style、任意颜色、recipe 定义或可执行代码。字段权限、只读查询、版本匹配和宿主确认要求不因样式变体而改变。
|
|
32
31
|
|
package/compatibility.json
CHANGED
|
@@ -28,13 +28,13 @@ export const styledSurfaceDefinitions = {
|
|
|
28
28
|
widgets: defaultSurfaceDefinitions.widgets.map((widget) => {
|
|
29
29
|
if (widget.type === 'metric')
|
|
30
30
|
return { ...widget, propsSchema: styledMetricPropsSchema,
|
|
31
|
-
description: 'Numeric KPI; tone
|
|
32
|
-
examples: [{ label: 'Pending orders', format: 'number', tone: 'warning'
|
|
31
|
+
description: 'Numeric KPI; tone selects prebuilt semantic styles, never CSS.',
|
|
32
|
+
examples: [{ label: 'Pending orders', format: 'number', tone: 'warning' }] };
|
|
33
33
|
if (widget.type === 'resource-table')
|
|
34
34
|
return { ...widget, propsSchema: styledResourceTablePropsSchema,
|
|
35
35
|
getReferencedFields: (props) => Value.Decode(styledResourceTablePropsSchema, props).columns.map((column) => column.field),
|
|
36
|
-
description: 'Read-only table;
|
|
37
|
-
examples: [{ title: 'Inventory', columns: [{ field: 'name', label: 'Name' }]
|
|
36
|
+
description: 'Read-only table; prebuilt semantic variants only, never raw CSS.',
|
|
37
|
+
examples: [{ title: 'Inventory', columns: [{ field: 'name', label: 'Name' }] }] };
|
|
38
38
|
return widget;
|
|
39
39
|
}),
|
|
40
40
|
};
|
|
@@ -38,21 +38,18 @@ export type BarChartProps = Static<typeof barChartPropsSchema>;
|
|
|
38
38
|
export type LineChartProps = Static<typeof lineChartPropsSchema>;
|
|
39
39
|
export declare const styledMetricPropsSchema: Type.TUnion<[Type.TObject<{
|
|
40
40
|
tone: Type.TOptional<Type.TUnion<Type.TLiteral<"info" | "warning" | "success" | "neutral" | "danger">[]>>;
|
|
41
|
-
density: Type.TOptional<Type.TUnion<Type.TLiteral<"compact" | "comfortable">[]>>;
|
|
42
41
|
label: Type.TString;
|
|
43
42
|
format: Type.TLiteral<"currency">;
|
|
44
43
|
currency: Type.TString;
|
|
45
44
|
description: Type.TOptional<Type.TString>;
|
|
46
45
|
}>, Type.TObject<{
|
|
47
46
|
tone: Type.TOptional<Type.TUnion<Type.TLiteral<"info" | "warning" | "success" | "neutral" | "danger">[]>>;
|
|
48
|
-
density: Type.TOptional<Type.TUnion<Type.TLiteral<"compact" | "comfortable">[]>>;
|
|
49
47
|
label: Type.TString;
|
|
50
48
|
format: Type.TUnion<[Type.TLiteral<"number">, Type.TLiteral<"percent">]>;
|
|
51
49
|
currency: Type.TOptional<Type.TNever>;
|
|
52
50
|
description: Type.TOptional<Type.TString>;
|
|
53
51
|
}>]>;
|
|
54
52
|
export declare const styledResourceTablePropsSchema: Type.TObject<{
|
|
55
|
-
density: Type.TOptional<Type.TUnion<Type.TLiteral<"compact" | "comfortable">[]>>;
|
|
56
53
|
title: Type.TString;
|
|
57
54
|
emptyLabel: Type.TOptional<Type.TString>;
|
|
58
55
|
columns: Type.TArray<Type.TObject<{
|
package/dist/builtin-schemas.js
CHANGED
|
@@ -47,7 +47,6 @@ export const lineChartPropsSchema = Type.Object({
|
|
|
47
47
|
}, { additionalProperties: false });
|
|
48
48
|
const styledMetricProperties = {
|
|
49
49
|
tone: Type.Optional(Type.Union(surfaceDesignContract.metric.tone.map((value) => Type.Literal(value)))),
|
|
50
|
-
density: Type.Optional(Type.Union(surfaceDesignContract.metric.density.map((value) => Type.Literal(value)))),
|
|
51
50
|
};
|
|
52
51
|
export const styledMetricPropsSchema = Type.Union([
|
|
53
52
|
Type.Object({ ...currencyMetric.properties, ...styledMetricProperties }, { additionalProperties: false }),
|
|
@@ -55,5 +54,4 @@ export const styledMetricPropsSchema = Type.Union([
|
|
|
55
54
|
]);
|
|
56
55
|
export const styledResourceTablePropsSchema = Type.Object({
|
|
57
56
|
...resourceTablePropsSchema.properties,
|
|
58
|
-
density: Type.Optional(Type.Union(surfaceDesignContract.table.density.map((value) => Type.Literal(value)))),
|
|
59
57
|
}, { additionalProperties: false });
|
|
@@ -8,7 +8,6 @@ export declare const resourceDetailPropsSchema: Type.TObject<{
|
|
|
8
8
|
}>>;
|
|
9
9
|
title: Type.TString;
|
|
10
10
|
tone: Type.TOptional<Type.TUnion<Type.TLiteral<"info" | "warning" | "success" | "neutral" | "danger">[]>>;
|
|
11
|
-
density: Type.TOptional<Type.TUnion<Type.TLiteral<"compact" | "comfortable">[]>>;
|
|
12
11
|
}>;
|
|
13
12
|
export declare const activityFeedPropsSchema: Type.TObject<{
|
|
14
13
|
idField: Type.TString;
|
|
@@ -20,7 +19,6 @@ export declare const activityFeedPropsSchema: Type.TObject<{
|
|
|
20
19
|
statusField: Type.TOptional<Type.TString>;
|
|
21
20
|
title: Type.TString;
|
|
22
21
|
tone: Type.TOptional<Type.TUnion<Type.TLiteral<"info" | "warning" | "success" | "neutral" | "danger">[]>>;
|
|
23
|
-
density: Type.TOptional<Type.TUnion<Type.TLiteral<"compact" | "comfortable">[]>>;
|
|
24
22
|
}>;
|
|
25
23
|
export type ResourceDetailProps = Static<typeof resourceDetailPropsSchema>;
|
|
26
24
|
export type ActivityFeedProps = Static<typeof activityFeedPropsSchema>;
|
|
@@ -6,7 +6,6 @@ const field = Type.String({ minLength: 1, maxLength: 64, pattern: '^[A-Za-z][A-Z
|
|
|
6
6
|
const presentation = {
|
|
7
7
|
title: Type.String({ minLength: 1, maxLength: 80 }),
|
|
8
8
|
tone: Type.Optional(Type.Union(surfaceDesignContract.metric.tone.map((value) => Type.Literal(value)))),
|
|
9
|
-
density: Type.Optional(Type.Union(surfaceDesignContract.metric.density.map((value) => Type.Literal(value)))),
|
|
10
9
|
};
|
|
11
10
|
export const resourceDetailPropsSchema = Type.Object({
|
|
12
11
|
...presentation,
|
|
@@ -25,7 +24,7 @@ const definitions = [
|
|
|
25
24
|
{
|
|
26
25
|
type: 'resource-detail', dataKind: 'record', propsSchema: resourceDetailPropsSchema,
|
|
27
26
|
description: 'Read-only detail of one authorized record. Bind a permitted resource-one source with pointer "". Select up to sixteen distinct readable fields; never provide record values in props.',
|
|
28
|
-
examples: [{ title: 'Contact details', fields: [{ field: 'name', label: 'Name' }]
|
|
27
|
+
examples: [{ title: 'Contact details', fields: [{ field: 'name', label: 'Name' }] }],
|
|
29
28
|
getReferencedFields: (props) => {
|
|
30
29
|
const fields = Value.Decode(resourceDetailPropsSchema, props).fields.map((item) => item.field);
|
|
31
30
|
if (new Set(fields).size !== fields.length)
|
|
@@ -10,15 +10,14 @@
|
|
|
10
10
|
let { props, data, locale = 'en-US', messages }: SurfaceWidgetRendererProps = $props();
|
|
11
11
|
const baseProps = $derived(Object.fromEntries(Object.entries(props).filter(([key]) => key !== 'appearance')));
|
|
12
12
|
const p = $derived(Value.Decode(activityFeedPropsSchema, baseProps));
|
|
13
|
-
const appearance = $derived(typeof props['appearance'] === 'object' && props['appearance'] !== null ? props['appearance'] as { tone?: typeof p.tone
|
|
13
|
+
const appearance = $derived(typeof props['appearance'] === 'object' && props['appearance'] !== null ? props['appearance'] as { tone?: typeof p.tone } : undefined);
|
|
14
14
|
const tone = $derived(appearance?.tone ?? p.tone ?? 'neutral');
|
|
15
|
-
const
|
|
16
|
-
const classes = $derived(surfaceMetric({ tone, density }));
|
|
15
|
+
const classes = $derived(surfaceMetric({ tone }));
|
|
17
16
|
const text = $derived(resolveSurfaceMessages(locale, messages));
|
|
18
17
|
const activities = $derived(data.status === 'ready' ? asSurfaceActivities(data.value, p, text.activityUnknownActor) : null);
|
|
19
18
|
</script>
|
|
20
19
|
|
|
21
|
-
<section class={classes.root + ' ' + classes.card} aria-label={p.title} data-surface-business="activity-feed"
|
|
20
|
+
<section class={classes.root + ' ' + classes.card} aria-label={p.title} data-surface-business="activity-feed">
|
|
22
21
|
{#if data.status === 'loading'}
|
|
23
22
|
<p role="status">{text.activityLoading}</p>
|
|
24
23
|
{:else if data.status === 'empty'}
|
|
@@ -11,8 +11,8 @@
|
|
|
11
11
|
const activeMessages = $derived(resolveSurfaceMessages(locale, messages));
|
|
12
12
|
|
|
13
13
|
const metricProps = $derived(Value.Decode(metricPropsSchema, props));
|
|
14
|
-
const metricClasses = $derived(metricProps.tone !== undefined
|
|
15
|
-
? surfaceMetric({ tone: metricProps.tone
|
|
14
|
+
const metricClasses = $derived(metricProps.tone !== undefined
|
|
15
|
+
? surfaceMetric({ tone: metricProps.tone }) : undefined);
|
|
16
16
|
const formattedValue = $derived.by(() => {
|
|
17
17
|
if (data.status !== 'ready') return '—';
|
|
18
18
|
const value = data.value;
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
});
|
|
31
31
|
</script>
|
|
32
32
|
|
|
33
|
-
<article class={metricClasses?.root} data-surface-tone={metricProps.tone}
|
|
33
|
+
<article class={metricClasses?.root} data-surface-tone={metricProps.tone} aria-labelledby="{widgetId}-label" aria-busy={data.status === 'loading'}>
|
|
34
34
|
<span id="{widgetId}-label" class="visually-hidden">{metricProps.label}</span>
|
|
35
35
|
{#if data.status === 'loading'}
|
|
36
36
|
<StatsCard class={metricClasses?.card ?? ''} label={metricProps.label} value="" loading />
|
|
@@ -14,16 +14,15 @@
|
|
|
14
14
|
let { props, data, locale = 'en-US', messages }: SurfaceWidgetRendererProps = $props();
|
|
15
15
|
const baseProps = $derived(Object.fromEntries(Object.entries(props).filter(([key]) => key !== 'appearance')));
|
|
16
16
|
const p = $derived(Value.Decode(resourceDetailPropsSchema, baseProps));
|
|
17
|
-
const appearance = $derived(typeof props['appearance'] === 'object' && props['appearance'] !== null ? props['appearance'] as { tone?: typeof p.tone
|
|
17
|
+
const appearance = $derived(typeof props['appearance'] === 'object' && props['appearance'] !== null ? props['appearance'] as { tone?: typeof p.tone } : undefined);
|
|
18
18
|
const tone = $derived(appearance?.tone ?? p.tone ?? 'neutral');
|
|
19
|
-
const
|
|
20
|
-
const classes = $derived(surfaceMetric({ tone, density }));
|
|
19
|
+
const classes = $derived(surfaceMetric({ tone }));
|
|
21
20
|
const text = $derived(resolveSurfaceMessages(locale, messages));
|
|
22
21
|
const record = $derived(data.status === 'ready' && data.value !== null && typeof data.value === 'object' && !Array.isArray(data.value)
|
|
23
22
|
? data.value as JsonObject : null);
|
|
24
23
|
</script>
|
|
25
24
|
|
|
26
|
-
<Card class={classes.root + ' ' + classes.card} data-surface-business="resource-detail"
|
|
25
|
+
<Card class={classes.root + ' ' + classes.card} data-surface-business="resource-detail">
|
|
27
26
|
<CardHeader><CardTitle>{p.title}</CardTitle></CardHeader>
|
|
28
27
|
<CardContent>
|
|
29
28
|
{#if data.status === 'loading'}
|
|
@@ -33,7 +32,7 @@
|
|
|
33
32
|
{:else if data.status === 'error'}
|
|
34
33
|
<p role="alert">{text.detailUnavailable}</p>
|
|
35
34
|
{:else if record}
|
|
36
|
-
<dl aria-label={p.title}
|
|
35
|
+
<dl aria-label={p.title}>
|
|
37
36
|
{#each p.fields as item, index (`${index}:${item.field}`)}
|
|
38
37
|
<div>
|
|
39
38
|
<dt>{item.label}</dt>
|
|
@@ -52,5 +51,4 @@
|
|
|
52
51
|
dl > div { min-width: 0; }
|
|
53
52
|
dt { color: var(--muted-foreground); font-size: .8125rem; }
|
|
54
53
|
dd { margin: .25rem 0 0; color: var(--foreground); overflow-wrap: anywhere; font-variant-numeric: tabular-nums; }
|
|
55
|
-
dl[data-density='compact'] { gap: .5rem; }
|
|
56
54
|
</style>
|
|
@@ -57,7 +57,7 @@
|
|
|
57
57
|
}
|
|
58
58
|
</script>
|
|
59
59
|
|
|
60
|
-
<section class="svadmin-surface-editor {editorClasses.
|
|
60
|
+
<section class="svadmin-surface-editor {editorClasses.default}" aria-labelledby="{instanceId}-form-title" aria-busy={formState.busy}>
|
|
61
61
|
<h3 id="{instanceId}-form-title">{title}</h3>
|
|
62
62
|
{#if !scope.enabled}<p role="status">{labels.disabled}</p>{/if}
|
|
63
63
|
{#if errors.length}
|
|
@@ -21,11 +21,11 @@
|
|
|
21
21
|
const activeMessages = $derived(resolveSurfaceMessages(locale, messages));
|
|
22
22
|
|
|
23
23
|
const tableProps = $derived(Value.Decode(resourceTablePropsSchema, props));
|
|
24
|
-
const tableClasses = $derived(
|
|
24
|
+
const tableClasses = $derived(surfaceTable());
|
|
25
25
|
const records = $derived(data.status === 'ready' ? asRecordArray(data.value) : null);
|
|
26
26
|
</script>
|
|
27
27
|
|
|
28
|
-
<Card class={tableClasses?.root}
|
|
28
|
+
<Card class={tableClasses?.root}>
|
|
29
29
|
<CardHeader class={tableClasses?.header}>
|
|
30
30
|
<CardTitle>{tableProps.title}</CardTitle>
|
|
31
31
|
</CardHeader>
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
<p class={"table-state " + (tableClasses?.state ?? "")} role="alert">{data.error.message}</p>
|
|
39
39
|
{:else if data.status === 'ready' && records?.ok}
|
|
40
40
|
<div class="surface-table">
|
|
41
|
-
<Table
|
|
41
|
+
<Table aria-label={tableProps.title}>
|
|
42
42
|
<TableHeader>
|
|
43
43
|
<TableRow>
|
|
44
44
|
{#each tableProps.columns as column (column.field)}
|
|
@@ -18,14 +18,13 @@
|
|
|
18
18
|
readonly dataProvider?: SurfaceDataProvider;
|
|
19
19
|
readonly scopeKey?: string;
|
|
20
20
|
readonly locale?: string;
|
|
21
|
-
readonly density?: 'compact' | 'comfortable';
|
|
22
21
|
/** 用户确认后返回候选快照。宿主负责持久化 CAS 与服务端授权。 */
|
|
23
22
|
readonly onApply?: (candidate: SurfaceRevision) => void | Promise<void>;
|
|
24
23
|
}
|
|
25
24
|
|
|
26
25
|
let {
|
|
27
26
|
revision, proposal, streaming = false, policy, catalog = defaultSurfaceCatalog,
|
|
28
|
-
dataProvider, scopeKey = '', locale,
|
|
27
|
+
dataProvider, scopeKey = '', locale, onApply,
|
|
29
28
|
}: SurfaceEditPreviewProps = $props();
|
|
30
29
|
const i18n = useTranslation();
|
|
31
30
|
const activeLocale = $derived(locale ?? i18n.locale);
|
|
@@ -72,7 +71,7 @@
|
|
|
72
71
|
}
|
|
73
72
|
</script>
|
|
74
73
|
|
|
75
|
-
<section class="svadmin-surface-editor {editorClasses
|
|
74
|
+
<section class="svadmin-surface-editor {editorClasses.default}" aria-label={labels.title}>
|
|
76
75
|
<div data-part="toolbar">
|
|
77
76
|
<div>
|
|
78
77
|
<h3 data-part="title">{labels.title}</h3>
|
|
@@ -11,7 +11,6 @@ export interface SurfaceEditPreviewProps {
|
|
|
11
11
|
readonly dataProvider?: SurfaceDataProvider;
|
|
12
12
|
readonly scopeKey?: string;
|
|
13
13
|
readonly locale?: string;
|
|
14
|
-
readonly density?: 'compact' | 'comfortable';
|
|
15
14
|
/** 用户确认后返回候选快照。宿主负责持久化 CAS 与服务端授权。 */
|
|
16
15
|
readonly onApply?: (candidate: SurfaceRevision) => void | Promise<void>;
|
|
17
16
|
}
|
|
@@ -21,9 +21,9 @@
|
|
|
21
21
|
import { withoutSurfaceAppearance } from '../workflows/catalog.js';
|
|
22
22
|
|
|
23
23
|
function appearanceClasses(props: JsonObject): string {
|
|
24
|
-
const appearance = props['appearance'] as { tone?: 'neutral' | 'success' | 'warning' | 'danger' | 'info'
|
|
24
|
+
const appearance = props['appearance'] as { tone?: 'neutral' | 'success' | 'warning' | 'danger' | 'info' } | undefined;
|
|
25
25
|
if (!appearance) return '';
|
|
26
|
-
const classes = surfaceMetric(appearance);
|
|
26
|
+
const classes = surfaceMetric({ tone: appearance.tone });
|
|
27
27
|
return `surface-appearance ${classes.root} ${classes.card}`;
|
|
28
28
|
}
|
|
29
29
|
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
<p role="alert">{labels.tableInvalidData}</p>
|
|
32
32
|
{:else}
|
|
33
33
|
<SvarDataGrid {Grid} {Theme} {columns} items={records?.ok ? records.value : []}
|
|
34
|
-
primaryKey={config.rowKey ?? 'id'} height={config.height ?? 360}
|
|
34
|
+
primaryKey={config.rowKey ?? 'id'} height={config.height ?? 360}
|
|
35
35
|
freezeLeft={config.freezeLeft ?? 0} freezeRight={config.freezeRight ?? 0}
|
|
36
36
|
loading={data.status === 'loading'} label={config.title} {locale}
|
|
37
37
|
scopeKey={`${host?.scopeKey ?? 0}:${widgetId}:${'sourceId' in data ? data.sourceId : ''}`}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export { surfaceDesignContract } from '@svadmin/ui/design-contract';
|
|
2
|
-
export type { SurfaceTone
|
|
2
|
+
export type { SurfaceTone } from '@svadmin/ui/design-contract';
|
package/dist/recipes.d.ts
CHANGED
|
@@ -1,16 +1,13 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
export declare function surfaceMetric({ tone,
|
|
1
|
+
import type { SurfaceTone } from './design-contract.js';
|
|
2
|
+
export declare function surfaceMetric({ tone, }?: {
|
|
3
3
|
tone?: SurfaceTone | undefined;
|
|
4
|
-
density?: SurfaceDensity | undefined;
|
|
5
4
|
}): {
|
|
6
5
|
root: string;
|
|
7
6
|
card: string;
|
|
8
7
|
description: string;
|
|
9
8
|
state: string;
|
|
10
9
|
};
|
|
11
|
-
export declare function surfaceTable(
|
|
12
|
-
density?: SurfaceDensity | undefined;
|
|
13
|
-
}): {
|
|
10
|
+
export declare function surfaceTable(): {
|
|
14
11
|
root: string;
|
|
15
12
|
header: string;
|
|
16
13
|
content: string;
|
package/dist/recipes.js
CHANGED
|
@@ -1,20 +1,19 @@
|
|
|
1
1
|
// 有限语义变体与静态 CSS 配套;不接受模型提供的 class/style。
|
|
2
|
-
export function surfaceMetric({ tone = 'neutral',
|
|
2
|
+
export function surfaceMetric({ tone = 'neutral', } = {}) {
|
|
3
3
|
return {
|
|
4
4
|
root: 'svadmin-surface-metric__root',
|
|
5
|
-
card: `svadmin-surface-metric__card svadmin-surface-tone--${tone}
|
|
5
|
+
card: `svadmin-surface-metric__card svadmin-surface-tone--${tone}`,
|
|
6
6
|
description: 'svadmin-surface-metric__description',
|
|
7
|
-
state: `svadmin-surface-metric__state svadmin-surface-tone--${tone}
|
|
7
|
+
state: `svadmin-surface-metric__state svadmin-surface-tone--${tone}`,
|
|
8
8
|
};
|
|
9
9
|
}
|
|
10
|
-
export function surfaceTable(
|
|
11
|
-
const variant = `svadmin-surface-density--${density}`;
|
|
10
|
+
export function surfaceTable() {
|
|
12
11
|
return {
|
|
13
12
|
root: 'svadmin-surface-table__root',
|
|
14
|
-
header:
|
|
15
|
-
content:
|
|
16
|
-
head:
|
|
17
|
-
cell:
|
|
18
|
-
state:
|
|
13
|
+
header: 'svadmin-surface-table__header',
|
|
14
|
+
content: 'svadmin-surface-table__content',
|
|
15
|
+
head: 'svadmin-surface-table__head',
|
|
16
|
+
cell: 'svadmin-surface-table__cell',
|
|
17
|
+
state: 'svadmin-surface-table__state',
|
|
19
18
|
};
|
|
20
19
|
}
|
package/dist/styles/editor.css
CHANGED
|
@@ -103,13 +103,9 @@
|
|
|
103
103
|
}
|
|
104
104
|
}
|
|
105
105
|
|
|
106
|
-
.svsurface-surface-editor
|
|
106
|
+
.svsurface-surface-editor {
|
|
107
107
|
padding: var(--svsurface-spacing-lg);
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
.svsurface-surface-editor--density_compact {
|
|
111
|
-
padding: var(--svsurface-spacing-md);
|
|
112
|
-
}
|
|
108
|
+
}
|
|
113
109
|
|
|
114
110
|
.svsurface-surface-editor-button--variant_secondary {
|
|
115
111
|
background-color: var(--svsurface-colors-background);
|
package/dist/styles/editor.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
export declare const editorClasses: {
|
|
2
|
-
readonly
|
|
3
|
-
readonly comfortable: "svsurface-surface-editor svsurface-surface-editor--density_comfortable";
|
|
2
|
+
readonly default: "svsurface-surface-editor";
|
|
4
3
|
};
|
|
5
4
|
export declare const editorButtonClasses: {
|
|
6
5
|
readonly secondary: "svsurface-surface-editor-button svsurface-surface-editor-button--variant_secondary";
|
package/dist/styles/editor.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
// 本地有限变体,与 editor.css 一起维护。
|
|
2
2
|
export const editorClasses = {
|
|
3
|
-
"
|
|
4
|
-
"comfortable": "svsurface-surface-editor svsurface-surface-editor--density_comfortable"
|
|
3
|
+
"default": "svsurface-surface-editor"
|
|
5
4
|
};
|
|
6
5
|
export const editorButtonClasses = {
|
|
7
6
|
"secondary": "svsurface-surface-editor-button svsurface-surface-editor-button--variant_secondary",
|
package/dist/styles.css
CHANGED
|
@@ -1,20 +1,7 @@
|
|
|
1
1
|
/* 独立的有限语义样式;保持旧 UI peer 和无宿主编译器的消费方式。 */
|
|
2
2
|
.svadmin-surface-metric__root,
|
|
3
|
-
.svadmin-surface-table__root {
|
|
4
|
-
|
|
5
|
-
.svadmin-surface-tone--success { --svadmin-surface-accent: var(--success); }
|
|
6
|
-
.svadmin-surface-tone--warning { --svadmin-surface-accent: var(--warning); }
|
|
7
|
-
.svadmin-surface-tone--danger { --svadmin-surface-accent: var(--destructive); }
|
|
8
|
-
.svadmin-surface-tone--info { --svadmin-surface-accent: var(--info); }
|
|
9
|
-
.svadmin-surface-density--compact {
|
|
10
|
-
--svadmin-surface-padding: 0.75rem;
|
|
11
|
-
--svadmin-surface-cell-padding: 0.25rem;
|
|
12
|
-
--svadmin-surface-cell-font: 0.75rem;
|
|
13
|
-
--svadmin-metric-state-padding: 0.75rem;
|
|
14
|
-
--svadmin-metric-state-height: 4.5rem;
|
|
15
|
-
--svadmin-table-state-height: 6rem;
|
|
16
|
-
}
|
|
17
|
-
.svadmin-surface-density--comfortable {
|
|
3
|
+
.svadmin-surface-table__root {
|
|
4
|
+
min-width: 0;
|
|
18
5
|
--svadmin-surface-padding: 1.25rem;
|
|
19
6
|
--svadmin-surface-cell-padding: 0.5rem;
|
|
20
7
|
--svadmin-surface-cell-font: 0.875rem;
|
|
@@ -22,6 +9,11 @@
|
|
|
22
9
|
--svadmin-metric-state-height: 6rem;
|
|
23
10
|
--svadmin-table-state-height: 8rem;
|
|
24
11
|
}
|
|
12
|
+
.svadmin-surface-tone--neutral { --svadmin-surface-accent: var(--border); }
|
|
13
|
+
.svadmin-surface-tone--success { --svadmin-surface-accent: var(--success); }
|
|
14
|
+
.svadmin-surface-tone--warning { --svadmin-surface-accent: var(--warning); }
|
|
15
|
+
.svadmin-surface-tone--danger { --svadmin-surface-accent: var(--destructive); }
|
|
16
|
+
.svadmin-surface-tone--info { --svadmin-surface-accent: var(--info); }
|
|
25
17
|
.svadmin-surface-metric__card.svadmin-surface-metric__card {
|
|
26
18
|
border-inline-start: 3px solid var(--svadmin-surface-accent);
|
|
27
19
|
padding: var(--svadmin-surface-padding);
|
|
@@ -32,10 +24,8 @@
|
|
|
32
24
|
--svadmin-metric-state-border-width: 3px;
|
|
33
25
|
--svadmin-metric-state-accent: var(--svadmin-surface-accent);
|
|
34
26
|
}
|
|
35
|
-
.svadmin-surface-table__header
|
|
36
|
-
.svadmin-surface-table__content
|
|
37
|
-
.svadmin-surface-table__header.svadmin-surface-density--comfortable,
|
|
38
|
-
.svadmin-surface-table__content.svadmin-surface-density--comfortable { padding-inline: 1rem; }
|
|
27
|
+
.svadmin-surface-table__header,
|
|
28
|
+
.svadmin-surface-table__content { padding-inline: 1rem; }
|
|
39
29
|
.svadmin-surface-table__head[data-slot="table-head"],
|
|
40
30
|
.svadmin-surface-table__cell[data-slot="table-cell"] {
|
|
41
31
|
padding-block: var(--svadmin-surface-cell-padding);
|
package/dist/svar-schema.d.ts
CHANGED
|
@@ -5,7 +5,6 @@ export declare const svarGridPropsSchema: Type.TObject<{
|
|
|
5
5
|
title: Type.TString;
|
|
6
6
|
rowKey: Type.TOptional<Type.TString>;
|
|
7
7
|
height: Type.TOptional<Type.TInteger>;
|
|
8
|
-
density: Type.TOptional<Type.TUnion<[Type.TLiteral<"compact">, Type.TLiteral<"comfortable">]>>;
|
|
9
8
|
freezeLeft: Type.TOptional<Type.TInteger>;
|
|
10
9
|
freezeRight: Type.TOptional<Type.TInteger>;
|
|
11
10
|
emptyLabel: Type.TOptional<Type.TString>;
|
package/dist/svar-schema.js
CHANGED
|
@@ -6,7 +6,6 @@ export const svarGridPropsSchema = Type.Object({
|
|
|
6
6
|
title: Type.String({ minLength: 1, maxLength: 80 }),
|
|
7
7
|
rowKey: Type.Optional(field),
|
|
8
8
|
height: Type.Optional(Type.Integer({ minimum: 160, maximum: 1200 })),
|
|
9
|
-
density: Type.Optional(Type.Union([Type.Literal('compact'), Type.Literal('comfortable')])),
|
|
10
9
|
freezeLeft: Type.Optional(Type.Integer({ minimum: 0, maximum: 8 })),
|
|
11
10
|
freezeRight: Type.Optional(Type.Integer({ minimum: 0, maximum: 8 })),
|
|
12
11
|
emptyLabel: Type.Optional(Type.String({ minLength: 1, maxLength: 80 })),
|
|
@@ -3,12 +3,10 @@ import type { SurfaceCatalog, SurfaceWidgetDefinition, JsonObject } from '../typ
|
|
|
3
3
|
import type { SurfaceActionDescriptor } from './types.js';
|
|
4
4
|
export declare const surfaceAppearanceSchema: Type.TObject<{
|
|
5
5
|
tone: Type.TOptional<Type.TUnion<Type.TLiteral<"info" | "warning" | "success" | "neutral" | "danger">[]>>;
|
|
6
|
-
density: Type.TOptional<Type.TUnion<Type.TLiteral<"compact" | "comfortable">[]>>;
|
|
7
6
|
}>;
|
|
8
7
|
export declare function withoutSurfaceAppearance(props: JsonObject): JsonObject;
|
|
9
8
|
/** Adds frame-level semantic appearance to every registered widget without
|
|
10
9
|
* leaking presentation props into its existing component implementation.
|
|
11
|
-
* Internal table cell density remains the table's own semantic prop.
|
|
12
10
|
*/
|
|
13
11
|
export declare function withSurfaceAppearance<T extends SurfaceWidgetDefinition>(catalog: {
|
|
14
12
|
version: string;
|
|
@@ -3,7 +3,6 @@ import { surfaceDesignContract } from '../design-contract.js';
|
|
|
3
3
|
import { validateSurfaceActionDescriptor } from './action-contracts.js';
|
|
4
4
|
export const surfaceAppearanceSchema = Type.Object({
|
|
5
5
|
tone: Type.Optional(Type.Union(surfaceDesignContract.metric.tone.map((tone) => Type.Literal(tone)))),
|
|
6
|
-
density: Type.Optional(Type.Union(surfaceDesignContract.metric.density.map((density) => Type.Literal(density)))),
|
|
7
6
|
}, { additionalProperties: false });
|
|
8
7
|
export function withoutSurfaceAppearance(props) {
|
|
9
8
|
return Object.fromEntries(Object.entries(props).filter(([key]) => key !== 'appearance'));
|
|
@@ -19,7 +18,6 @@ function withAppearance(input) {
|
|
|
19
18
|
}
|
|
20
19
|
/** Adds frame-level semantic appearance to every registered widget without
|
|
21
20
|
* leaking presentation props into its existing component implementation.
|
|
22
|
-
* Internal table cell density remains the table's own semantic prop.
|
|
23
21
|
*/
|
|
24
22
|
export function withSurfaceAppearance(catalog) {
|
|
25
23
|
return { version: `${catalog.version}+appearance/v1`, widgets: catalog.widgets.map((widget) => ({
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@svadmin/surface",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.14.0",
|
|
4
4
|
"description": "Validated declarative surfaces for svadmin dashboards",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": [
|
|
@@ -74,8 +74,8 @@
|
|
|
74
74
|
}
|
|
75
75
|
},
|
|
76
76
|
"peerDependencies": {
|
|
77
|
-
"@svadmin/core": ">=0.53.0 <0.
|
|
78
|
-
"@svadmin/ui": ">=0.73.0 <0.
|
|
77
|
+
"@svadmin/core": ">=0.53.0 <0.63.0",
|
|
78
|
+
"@svadmin/ui": ">=0.73.0 <0.87.0",
|
|
79
79
|
"svelte": "^5.56.10"
|
|
80
80
|
},
|
|
81
81
|
"dependencies": {
|