niuma-ui 2.1.2 → 2.1.3

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/CHANGELOG.md CHANGED
@@ -6,6 +6,12 @@
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [2.1.3] - 2026-09-22
10
+
11
+ ### 变更
12
+
13
+ - 颜色主题:`applyColorTheme` / `clearColorTheme`。主题包只覆盖 `RS_COLOR_THEME_VARS` 里的语义 `--rs-*`,并标记 `data-rs-color-theme`。明暗仍是 `data-rs-theme="light|dark"`。同一明暗下更换皮肤时,代码编辑器、Monaco、终端和代码块会重读 token。文档站「主题定制」有可切换的演示。
14
+
9
15
  ## [2.1.2] - 2026-09-22
10
16
 
11
17
  ### 修复
@@ -1,3 +1,4 @@
1
+ import { documentThemeAttributes } from "../../../theme/color-theme.js";
1
2
  //#region src/components/code-block/src/code-block-utils.ts
2
3
  var COPY_FEEDBACK_MS = 1500;
3
4
  var DOWNLOAD_REVOKE_MS = 1500;
@@ -51,7 +52,7 @@ function ensureThemeObserver() {
51
52
  });
52
53
  themeObserver.observe(document.documentElement, {
53
54
  attributes: true,
54
- attributeFilter: ["data-rs-theme"],
55
+ attributeFilter: [...documentThemeAttributes],
55
56
  subtree: true
56
57
  });
57
58
  }
@@ -1,4 +1,5 @@
1
1
  import { readResolvedTheme } from "../../../theme/apply.js";
2
+ import { documentThemeAttributes } from "../../../theme/color-theme.js";
2
3
  //#region src/components/code-editor/src/code-editor-utils.ts
3
4
  var SUPPORTED_LANGUAGES = [
4
5
  "plaintext",
@@ -81,7 +82,7 @@ function subscribeDocumentTheme(listener) {
81
82
  });
82
83
  themeObserver.observe(document.documentElement, {
83
84
  attributes: true,
84
- attributeFilter: ["data-rs-theme"]
85
+ attributeFilter: [...documentThemeAttributes]
85
86
  });
86
87
  }
87
88
  let active = true;
@@ -1,3 +1,4 @@
1
+ import { documentThemeAttributes } from "../../../theme/color-theme.js";
1
2
  import { MONACO_CLICKHOUSE_LANGUAGE, MONACO_DAMENG_LANGUAGE, MONACO_KINGBASE_LANGUAGE, MONACO_MYSQL_LANGUAGE, MONACO_ORACLE_LANGUAGE, MONACO_POSTGRESQL_LANGUAGE, MONACO_SQLITE_LSP_LANGUAGE, MONACO_SQLSERVER_LANGUAGE } from "../../../monaco/languages/types.js";
2
3
  import { MONACO_MONGODB_SHELL_LANGUAGE } from "../../../monaco/languages/mongodb-shell.js";
3
4
  import { readCodeFontFamily, readCodeFontSizePx, readCssLengthPx, readCssVar } from "../../../theme/css-token.js";
@@ -213,7 +214,7 @@ function subscribeDocumentTheme(listener) {
213
214
  });
214
215
  themeObserver.observe(document.documentElement, {
215
216
  attributes: true,
216
- attributeFilter: ["data-rs-theme"]
217
+ attributeFilter: [...documentThemeAttributes]
217
218
  });
218
219
  }
219
220
  let active = true;
@@ -1,3 +1,4 @@
1
+ import { documentThemeAttributes } from "../../../theme/color-theme.js";
1
2
  //#region src/components/terminal/src/terminal-utils.ts
2
3
  var TERMINAL_CSS_KEYS = [
3
4
  ["background", "--rs-terminal-bg"],
@@ -235,7 +236,7 @@ function ensureTerminalThemeObserver() {
235
236
  });
236
237
  sharedThemeObserver.observe(document.documentElement, {
237
238
  attributes: true,
238
- attributeFilter: ["data-rs-theme"],
239
+ attributeFilter: [...documentThemeAttributes],
239
240
  subtree: true
240
241
  });
241
242
  }
package/dist/index.d.ts CHANGED
@@ -27,7 +27,7 @@ export { RsDivider } from './components/divider';
27
27
  export type { RsDividerOrientation } from './components/divider';
28
28
  export { RsDescriptions } from './components/descriptions';
29
29
  export { RsDescriptionsItem } from './components/descriptions';
30
- export type { RsDescriptionsItem as RsDescriptionsItemData, RsDescriptionsLabelAlign, RsDescriptionsLabelPlacement, RsDescriptionsSize, } from './components/descriptions';
30
+ export type { RsDescriptionsItemData, RsDescriptionsLabelAlign, RsDescriptionsLabelPlacement, RsDescriptionsSize, } from './components/descriptions';
31
31
  export { RsLoadingBar } from './components/loading-bar';
32
32
  export type { RsLoadingBarAttach, RsLoadingBarExpose, RsLoadingBarInstance, RsLoadingBarPosition, RsLoadingBarTone, } from './components/loading-bar';
33
33
  export { useRsLoadingBar } from './composables/useRsLoadingBar';
@@ -240,6 +240,7 @@ export { rsCommonIconNames, rsBrandIconNames, rsBrandIconAccentVar, LUCIDE_ATTRI
240
240
  export { registerRsIcon } from './icons/host';
241
241
  export type { RsBrandIconName } from './icons/registry';
242
242
  export type { RsThemeMode, RsResolvedTheme, RsThemeTokens, RsComponentSize, RsRadius, RsFontSize, RsFontWeight, } from './theme/types';
243
+ export type { RsColorTheme, RsColorThemeToken } from './theme/color-theme';
243
244
  export { RS_COMPONENT_SIZES, RS_COMPONENT_SIZE_ICON_PX, RS_RADII, RS_RADIUS_CSS, RS_FONT_SIZES, RS_FONT_SIZE_CSS, RS_FONT_WEIGHTS, RS_FONT_WEIGHT_CSS, } from './theme/types';
244
245
  export type { RsBuiltinLocale, RsDirMode, RsLocale, RsLocaleMessages, RsTextDirection, } from './locale/types';
245
246
  export { defaultLocale, fallbackLocale } from './locale/types';
@@ -250,4 +251,5 @@ export { useResolvedRsComponentSize, resolveRsComponentSize } from './components
250
251
  export { useResolvedRsRadius, rsRadiusCss } from './components/_shared';
251
252
  export { themePresets } from './theme/presets';
252
253
  export { applyTheme, prefersColorSchemeDark, readResolvedTheme, resolveThemeMode, subscribePreferredColorScheme, } from './theme/apply';
254
+ export { RS_COLOR_THEME_VARS, applyColorTheme, clearColorTheme, colorThemeAttribute, isSafeColorThemeId, isSafeColorThemeValue, } from './theme/color-theme';
253
255
  export { parseCssLengthToPx, readCodeFontFamily, readCodeFontSizePx, readCssLengthPx, readCssVar, readRootFontSizePx, readTerminalFontFamily, readTerminalFontSizePx, readTerminalFontWeight, readTerminalFontWeightBold, } from './theme/css-token';
package/dist/index.js CHANGED
@@ -11,6 +11,7 @@ export { MONACO_MYSQL_LANGUAGE } from './monaco/languages/types.js'
11
11
  export { MONACO_PGSQL_LANGUAGE } from './monaco/languages/types.js'
12
12
  export { MONACO_POSTGRESQL_LANGUAGE } from './monaco/languages/types.js'
13
13
  export { MONACO_SQLITE_LANGUAGE } from './monaco/languages/types.js'
14
+ export { RS_COLOR_THEME_VARS } from './theme/color-theme.js'
14
15
  export { RS_COMPONENT_SIZES } from './theme/types.js'
15
16
  export { RS_COMPONENT_SIZE_ICON_PX } from './theme/types.js'
16
17
  export { RS_DATETIME_FORMAT } from './utils/rs-dayjs.js'
@@ -130,6 +131,7 @@ export { TIME_HOUR12_OPTIONS } from './components/time-picker/src/time-picker-ut
130
131
  export { TIME_HOUR_OPTIONS } from './components/time-picker/src/time-picker-utils.js'
131
132
  export { TIME_SECOND_OPTIONS } from './components/time-picker/src/time-picker-utils.js'
132
133
  export { aggregateColumnSummary } from './components/table/src/utils/table-summary-utils.js'
134
+ export { applyColorTheme } from './theme/color-theme.js'
133
135
  export { applyLocale } from './locale/apply.js'
134
136
  export { applyMonacoDebugDecorations } from './monaco/debug-decorations2.js'
135
137
  export { applySplitResize } from './components/split-pane/src/split-pane-utils.js'
@@ -155,6 +157,7 @@ export { clampLogCount } from './components/log/src/log-utils.js'
155
157
  export { clampNumber } from './components/input-number/src/input-number-utils.js'
156
158
  export { clampPage } from './components/pagination/src/pagination-utils.js'
157
159
  export { clampRsDrawerSize } from './components/drawer/src/drawer-utils.js'
160
+ export { clearColorTheme } from './theme/color-theme.js'
158
161
  export { cloneFormFieldValue } from './components/form/src/form-utils.js'
159
162
  export { codeEditorLanguageLabel } from './components/code-editor/src/code-editor-utils.js'
160
163
  export { collapseSplitPane } from './components/split-pane/src/split-pane-utils.js'
@@ -164,6 +167,7 @@ export { collectHalfCheckedKeys } from './components/tree/src/tree-utils.js'
164
167
  export { collectTableTreeDescendantKeys } from './components/table/src/utils/table-utils.js'
165
168
  export { collectTableTreeExpandableKeys } from './components/table/src/utils/table-utils.js'
166
169
  export { collectTableTreeHalfCheckedKeys } from './components/table/src/utils/table-utils.js'
170
+ export { colorThemeAttribute } from './theme/color-theme.js'
167
171
  export { compareTableValues } from './components/table/src/utils/table-utils.js'
168
172
  export { concatNamePath } from './components/form/src/form-path.js'
169
173
  export { containsEscapeSequence } from './components/terminal/src/terminal-utils.js'
@@ -270,6 +274,8 @@ export { isRsLocaleRegistered } from './locale/registry.js'
270
274
  export { isRsLogLevel } from './components/log/src/log-utils.js'
271
275
  export { isRsSplitPaneAutoSize } from './components/split-pane/src/split-pane-utils.js'
272
276
  export { isRsTableApi } from './components/table/src/rs-table-api.js'
277
+ export { isSafeColorThemeId } from './theme/color-theme.js'
278
+ export { isSafeColorThemeValue } from './theme/color-theme.js'
273
279
  export { isSafeHref } from './components/markdown/src/markdown-utils.js'
274
280
  export { isSafeImageSrc } from './components/markdown/src/markdown-utils.js'
275
281
  export { isSelectLabeledValue } from './components/select/src/select-utils.js'
@@ -0,0 +1,64 @@
1
+ import { type RsResolvedTheme } from './types';
2
+ /**
3
+ * 颜色主题身份。只标记当前皮肤,组件样式不要用它做选择器。
4
+ * 明暗仍只写 `data-rs-theme="light|dark"`。
5
+ */
6
+ export declare const colorThemeAttribute = "data-rs-color-theme";
7
+ /** 文档级编辑器要同时观察明暗和颜色主题,否则同为暗色时换皮肤不会重读 token。 */
8
+ export declare const documentThemeAttributes: readonly ["data-rs-theme", "data-rs-color-theme"];
9
+ /**
10
+ * 主题包可以覆盖的语义令牌。表格、树、按钮等已用 var() 指向这些名字。
11
+ * 键是主题文件里的字段,值是要写到元素上的 CSS 变量。
12
+ */
13
+ export declare const RS_COLOR_THEME_VARS: {
14
+ readonly primary: "--rs-primary";
15
+ readonly primaryHover: "--rs-primary-hover";
16
+ readonly primaryForeground: "--rs-primary-foreground";
17
+ readonly primaryContainer: "--rs-primary-container";
18
+ readonly onPrimaryContainer: "--rs-on-primary-container";
19
+ readonly bg: "--rs-bg";
20
+ readonly surface: "--rs-surface";
21
+ readonly surfaceElevated: "--rs-surface-elevated";
22
+ readonly surfaceHover: "--rs-surface-hover";
23
+ readonly itemHover: "--rs-item-hover";
24
+ readonly inputBg: "--rs-input-bg";
25
+ readonly inputBorder: "--rs-input-border";
26
+ readonly inputBorderHover: "--rs-input-border-hover";
27
+ readonly border: "--rs-border";
28
+ readonly borderSubtle: "--rs-border-subtle";
29
+ readonly text: "--rs-text-primary";
30
+ readonly muted: "--rs-text-secondary";
31
+ readonly placeholder: "--rs-text-tertiary";
32
+ readonly textDisabled: "--rs-text-disabled";
33
+ readonly textInverse: "--rs-text-inverse";
34
+ readonly danger: "--rs-danger";
35
+ readonly dangerContainer: "--rs-danger-container";
36
+ readonly onDangerContainer: "--rs-on-danger-container";
37
+ readonly success: "--rs-success";
38
+ readonly successContainer: "--rs-success-container";
39
+ readonly onSuccessContainer: "--rs-on-success-container";
40
+ readonly warning: "--rs-warning";
41
+ readonly warningContainer: "--rs-warning-container";
42
+ readonly onWarningContainer: "--rs-on-warning-container";
43
+ readonly info: "--rs-info";
44
+ readonly infoContainer: "--rs-info-container";
45
+ readonly onInfoContainer: "--rs-on-info-container";
46
+ };
47
+ export type RsColorThemeToken = keyof typeof RS_COLOR_THEME_VARS;
48
+ /** 一份可安装的颜色主题。`id` 不翻译;`label` 用英文,宿主自己做语言包。 */
49
+ export interface RsColorTheme {
50
+ id: string;
51
+ label: string;
52
+ uiTheme: RsResolvedTheme;
53
+ colors: Partial<Record<RsColorThemeToken, string>>;
54
+ }
55
+ /** 拒绝能逃出自定义属性、注入样式或外链的值。允许 hex、函数色和 var()。 */
56
+ export declare function isSafeColorThemeValue(value: string): boolean;
57
+ export declare function isSafeColorThemeId(id: string): boolean;
58
+ /**
59
+ * 把主题包写到元素的内联 `--rs-*` 上,盖过 styles.css 与 brand.css。
60
+ * 未列出的字段保持样式表原值。非法 id 或没有目标元素时不改 DOM。
61
+ */
62
+ export declare function applyColorTheme(theme: RsColorTheme, el?: HTMLElement | null): boolean;
63
+ /** 去掉该元素上由颜色主题写上的变量,回到样式表。 */
64
+ export declare function clearColorTheme(el?: HTMLElement | null): void;
@@ -0,0 +1,100 @@
1
+ import { themeAttribute } from "./types.js";
2
+ //#region src/theme/color-theme.ts
3
+ /**
4
+ * 颜色主题身份。只标记当前皮肤,组件样式不要用它做选择器。
5
+ * 明暗仍只写 `data-rs-theme="light|dark"`。
6
+ */
7
+ var colorThemeAttribute = "data-rs-color-theme";
8
+ /** 文档级编辑器要同时观察明暗和颜色主题,否则同为暗色时换皮肤不会重读 token。 */
9
+ var documentThemeAttributes = [themeAttribute, colorThemeAttribute];
10
+ /**
11
+ * 主题包可以覆盖的语义令牌。表格、树、按钮等已用 var() 指向这些名字。
12
+ * 键是主题文件里的字段,值是要写到元素上的 CSS 变量。
13
+ */
14
+ var RS_COLOR_THEME_VARS = {
15
+ primary: "--rs-primary",
16
+ primaryHover: "--rs-primary-hover",
17
+ primaryForeground: "--rs-primary-foreground",
18
+ primaryContainer: "--rs-primary-container",
19
+ onPrimaryContainer: "--rs-on-primary-container",
20
+ bg: "--rs-bg",
21
+ surface: "--rs-surface",
22
+ surfaceElevated: "--rs-surface-elevated",
23
+ surfaceHover: "--rs-surface-hover",
24
+ itemHover: "--rs-item-hover",
25
+ inputBg: "--rs-input-bg",
26
+ inputBorder: "--rs-input-border",
27
+ inputBorderHover: "--rs-input-border-hover",
28
+ border: "--rs-border",
29
+ borderSubtle: "--rs-border-subtle",
30
+ text: "--rs-text-primary",
31
+ muted: "--rs-text-secondary",
32
+ placeholder: "--rs-text-tertiary",
33
+ textDisabled: "--rs-text-disabled",
34
+ textInverse: "--rs-text-inverse",
35
+ danger: "--rs-danger",
36
+ dangerContainer: "--rs-danger-container",
37
+ onDangerContainer: "--rs-on-danger-container",
38
+ success: "--rs-success",
39
+ successContainer: "--rs-success-container",
40
+ onSuccessContainer: "--rs-on-success-container",
41
+ warning: "--rs-warning",
42
+ warningContainer: "--rs-warning-container",
43
+ onWarningContainer: "--rs-on-warning-container",
44
+ info: "--rs-info",
45
+ infoContainer: "--rs-info-container",
46
+ onInfoContainer: "--rs-on-info-container"
47
+ };
48
+ var THEME_ID = /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/;
49
+ var appliedVars = /* @__PURE__ */ new WeakMap();
50
+ function themeTarget(el) {
51
+ if (el) return el;
52
+ if (typeof document === "undefined") return null;
53
+ return document.documentElement;
54
+ }
55
+ /** 拒绝能逃出自定义属性、注入样式或外链的值。允许 hex、函数色和 var()。 */
56
+ function isSafeColorThemeValue(value) {
57
+ const raw = value.trim();
58
+ if (!raw || raw.length > 240) return false;
59
+ if (/[;{}<>]|url\s*\(|expression\s*\(|@import|\/\*|\*\//i.test(raw)) return false;
60
+ return true;
61
+ }
62
+ function isSafeColorThemeId(id) {
63
+ return THEME_ID.test(id);
64
+ }
65
+ /**
66
+ * 把主题包写到元素的内联 `--rs-*` 上,盖过 styles.css 与 brand.css。
67
+ * 未列出的字段保持样式表原值。非法 id 或没有目标元素时不改 DOM。
68
+ */
69
+ function applyColorTheme(theme, el) {
70
+ const target = themeTarget(el);
71
+ if (!target || !isSafeColorThemeId(theme.id)) return false;
72
+ const previous = appliedVars.get(target) ?? /* @__PURE__ */ new Set();
73
+ const next = /* @__PURE__ */ new Set();
74
+ for (const key of Object.keys(RS_COLOR_THEME_VARS)) {
75
+ const value = theme.colors[key];
76
+ if (value == null) continue;
77
+ const raw = String(value).trim();
78
+ if (!isSafeColorThemeValue(raw)) continue;
79
+ const prop = RS_COLOR_THEME_VARS[key];
80
+ target.style.setProperty(prop, raw);
81
+ next.add(prop);
82
+ }
83
+ for (const prop of previous) if (!next.has(prop)) target.style.removeProperty(prop);
84
+ appliedVars.set(target, next);
85
+ target.setAttribute(colorThemeAttribute, theme.id);
86
+ return true;
87
+ }
88
+ /** 去掉该元素上由颜色主题写上的变量,回到样式表。 */
89
+ function clearColorTheme(el) {
90
+ const target = themeTarget(el);
91
+ if (!target) return;
92
+ const previous = appliedVars.get(target);
93
+ if (previous) {
94
+ for (const prop of previous) target.style.removeProperty(prop);
95
+ appliedVars.delete(target);
96
+ }
97
+ target.removeAttribute(colorThemeAttribute);
98
+ }
99
+ //#endregion
100
+ export { RS_COLOR_THEME_VARS, applyColorTheme, clearColorTheme, colorThemeAttribute, documentThemeAttributes, isSafeColorThemeId, isSafeColorThemeValue };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "niuma-ui",
3
- "version": "2.1.2",
3
+ "version": "2.1.3",
4
4
  "license": "Apache-2.0",
5
5
  "type": "module",
6
6
  "description": "Vue 3 workbench design system — Rs* components, --rs-* tokens, optional Monaco / CodeMirror / xterm",