niuma-ui 1.2.9 → 1.3.1

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 (58) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/dist/components/RsButton.css +119 -61
  3. package/dist/components/RsButton.d.ts +3 -3
  4. package/dist/components/RsButton.impl.js +4 -12
  5. package/dist/components/RsButton.js +1 -1
  6. package/dist/components/RsDialog.css +1 -0
  7. package/dist/components/RsDialog.d.ts +5 -0
  8. package/dist/components/RsDialog.impl.js +4 -0
  9. package/dist/components/RsDrawer.css +1 -0
  10. package/dist/components/RsFieldset.css +92 -0
  11. package/dist/components/RsFieldset.d.ts +61 -0
  12. package/dist/components/RsFieldset.impl.js +78 -0
  13. package/dist/components/RsFieldset.js +8 -0
  14. package/dist/components/RsFormItem.css +19 -19
  15. package/dist/components/RsFormItem.d.ts +6 -4
  16. package/dist/components/RsFormItem.impl.js +12 -2
  17. package/dist/components/RsFormItem.js +1 -1
  18. package/dist/components/RsInput.css +78 -69
  19. package/dist/components/RsInput.js +1 -1
  20. package/dist/components/RsLog.css +198 -0
  21. package/dist/components/RsLog.d.ts +126 -0
  22. package/dist/components/RsLog.impl.js +619 -0
  23. package/dist/components/RsLog.js +8 -0
  24. package/dist/components/RsTable.impl.js +2 -1
  25. package/dist/components/RsTerminal.css +59 -18
  26. package/dist/components/RsTerminal.d.ts +17 -1
  27. package/dist/components/RsTerminal.impl.js +115 -8
  28. package/dist/components/RsTerminal.js +1 -1
  29. package/dist/components/RsTextarea.css +126 -0
  30. package/dist/components/RsTextarea.d.ts +114 -0
  31. package/dist/components/RsTextarea.impl.js +385 -0
  32. package/dist/components/RsTextarea.js +8 -0
  33. package/dist/components/RsTooltip.css +4 -3
  34. package/dist/components/RsTooltip.d.ts +2 -0
  35. package/dist/components/RsTooltip.impl.js +5 -2
  36. package/dist/components/RsVirtualList.css +6 -6
  37. package/dist/components/RsVirtualList.d.ts +1 -1
  38. package/dist/components/RsVirtualList.impl.js +9 -4
  39. package/dist/components/RsVirtualList.js +1 -1
  40. package/dist/components/button-utils.d.ts +19 -10
  41. package/dist/components/button-utils.js +22 -7
  42. package/dist/components/dialog-window.d.ts +2 -0
  43. package/dist/components/dialog-window.js +2 -1
  44. package/dist/components/fieldset-utils.d.ts +29 -0
  45. package/dist/components/fieldset-utils.js +12 -0
  46. package/dist/components/log-utils.d.ts +105 -0
  47. package/dist/components/log-utils.js +354 -0
  48. package/dist/components/table/rs-table-props.d.ts +8 -0
  49. package/dist/components/table/rs-table-props.js +1 -0
  50. package/dist/components/table/rs-table.css +7 -0
  51. package/dist/components/terminal-utils.d.ts +1 -1
  52. package/dist/dev/vite-xterm-deps.d.ts +1 -0
  53. package/dist/dev/vite-xterm-deps.js +1 -0
  54. package/dist/index.d.ts +10 -2
  55. package/dist/index.js +24 -0
  56. package/dist/locale/messages.js +52 -0
  57. package/dist/styles.css +37 -0
  58. package/package.json +2 -1
@@ -0,0 +1,385 @@
1
+ import { useRsI18n } from "../composables/useRsI18n.js";
2
+ import RsIcon_default from "./RsIcon.js";
3
+ import { buildLocalInputRules, runFormFieldRules } from "./form-rules.js";
4
+ import { isRsFormItemBoundControl, useRsFormContext, useRsFormField, useRsFormItemContext } from "./form-utils.js";
5
+ import { useResolvedRsComponentSize } from "./resolve-size.js";
6
+ import { rsRadiusCss, useResolvedRsRadius } from "./resolve-radius.js";
7
+ import { computed, createCommentVNode, createElementBlock, createElementVNode, createTextVNode, createVNode, defineComponent, mergeModels, mergeProps, nextTick, normalizeClass, normalizeStyle, onMounted, openBlock, ref, renderSlot, toDisplayString, unref, useAttrs, useId, useModel, watch, withModifiers } from "vue";
8
+ //#region src/components/RsTextarea.vue?vue&type=script&setup=true&lang.ts
9
+ var _hoisted_1 = {
10
+ key: 0,
11
+ class: "rs-field__label"
12
+ };
13
+ var _hoisted_2 = ["for"];
14
+ var _hoisted_3 = {
15
+ key: 0,
16
+ class: "rs-field__required",
17
+ "aria-hidden": "true"
18
+ };
19
+ var _hoisted_4 = { class: "rs-textarea" };
20
+ var _hoisted_5 = [
21
+ "id",
22
+ "value",
23
+ "rows",
24
+ "placeholder",
25
+ "disabled",
26
+ "readonly",
27
+ "minlength",
28
+ "maxlength",
29
+ "aria-invalid",
30
+ "aria-describedby"
31
+ ];
32
+ var _hoisted_6 = ["aria-label"];
33
+ var _hoisted_7 = ["id"];
34
+ var _hoisted_8 = {
35
+ key: 1,
36
+ class: "rs-field__hint"
37
+ };
38
+ var RsTextarea_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineComponent({
39
+ inheritAttrs: false,
40
+ __name: "RsTextarea",
41
+ props: /*@__PURE__*/ mergeModels({
42
+ id: {},
43
+ placeholder: {},
44
+ disabled: {
45
+ type: Boolean,
46
+ default: false
47
+ },
48
+ readonly: {
49
+ type: Boolean,
50
+ default: false
51
+ },
52
+ invalid: {
53
+ type: Boolean,
54
+ default: false
55
+ },
56
+ errorMessage: {},
57
+ size: {},
58
+ radius: {},
59
+ rows: { default: 3 },
60
+ resize: { default: "vertical" },
61
+ autosize: {
62
+ type: [Boolean, Object],
63
+ default: false
64
+ },
65
+ rule: {},
66
+ validator: {},
67
+ required: {
68
+ type: Boolean,
69
+ default: false
70
+ },
71
+ validateTrigger: { default: "blur" },
72
+ name: {},
73
+ minlength: {},
74
+ maxlength: {},
75
+ showCount: {
76
+ type: Boolean,
77
+ default: false
78
+ },
79
+ clearable: {
80
+ type: Boolean,
81
+ default: false
82
+ },
83
+ showValidateMessage: {
84
+ type: Boolean,
85
+ default: true
86
+ },
87
+ label: {},
88
+ hint: {},
89
+ labelPosition: {}
90
+ }, {
91
+ "modelValue": { default: "" },
92
+ "modelModifiers": {}
93
+ }),
94
+ emits: /*@__PURE__*/ mergeModels([
95
+ "validate",
96
+ "blur",
97
+ "focus",
98
+ "pressEnter",
99
+ "clear"
100
+ ], ["update:modelValue"]),
101
+ setup(__props, { expose: __expose, emit: __emit }) {
102
+ const { t } = useRsI18n();
103
+ const model = useModel(__props, "modelValue", {
104
+ get(value) {
105
+ return value == null ? "" : String(value);
106
+ },
107
+ set(value) {
108
+ return value == null ? "" : String(value);
109
+ }
110
+ });
111
+ const props = __props;
112
+ const emit = __emit;
113
+ const attrs = useAttrs();
114
+ const formContext = useRsFormContext();
115
+ const formItem = useRsFormItemContext();
116
+ const boundToItem = computed(() => isRsFormItemBoundControl(formItem, {
117
+ id: props.id,
118
+ name: props.name
119
+ }));
120
+ const fieldId = useId();
121
+ const textareaRef = ref(null);
122
+ const touched = ref(false);
123
+ const autoInvalid = ref(false);
124
+ const autoMessage = ref("");
125
+ const composing = ref(false);
126
+ const resolvedId = computed(() => props.id ?? fieldId);
127
+ const resolvedLabelPosition = computed(() => props.labelPosition ?? formContext?.labelPosition.value ?? "top");
128
+ const resolvedLabelAlign = computed(() => formContext?.labelAlign.value ?? "start");
129
+ const errorId = computed(() => `${resolvedId.value}-error`);
130
+ const displayMessage = computed(() => {
131
+ if (boundToItem.value) return "";
132
+ if (props.errorMessage) return props.errorMessage;
133
+ if (props.showValidateMessage && autoInvalid.value) return autoMessage.value;
134
+ return "";
135
+ });
136
+ const isInvalid = computed(() => {
137
+ if (boundToItem.value) return Boolean(formItem?.invalid.value || props.invalid);
138
+ return props.invalid || autoInvalid.value;
139
+ });
140
+ const describedBy = computed(() => {
141
+ if (boundToItem.value) return formItem?.describedBy.value;
142
+ return displayMessage.value ? errorId.value : void 0;
143
+ });
144
+ const resolvedDisabled = computed(() => props.disabled || formContext?.disabled.value || false);
145
+ const resolvedSize = useResolvedRsComponentSize(() => props.size);
146
+ const resolvedRadius = useResolvedRsRadius(() => props.radius, "sm");
147
+ const radiusStyle = computed(() => ({ "--rs-input-radius": rsRadiusCss(resolvedRadius.value) }));
148
+ const fieldStyle = computed(() => {
149
+ if (resolvedLabelPosition.value !== "left") return void 0;
150
+ const labelWidth = formContext?.labelWidth.value;
151
+ if (!labelWidth) return void 0;
152
+ return { "--rs-field-label-width": labelWidth };
153
+ });
154
+ const autosizeEnabled = computed(() => Boolean(props.autosize));
155
+ const autosizeSpec = computed(() => typeof props.autosize === "object" && props.autosize ? props.autosize : {});
156
+ const displayRows = computed(() => autosizeSpec.value.minRows ?? props.rows);
157
+ const resolvedResize = computed(() => autosizeEnabled.value ? "none" : props.resize);
158
+ const countText = computed(() => {
159
+ const n = model.value.length;
160
+ return props.maxlength != null ? `${n} / ${props.maxlength}` : String(n);
161
+ });
162
+ const countLimitReached = computed(() => props.maxlength != null && model.value.length >= props.maxlength);
163
+ const showClearButton = computed(() => props.clearable && !resolvedDisabled.value && !props.readonly && model.value.length > 0);
164
+ function parseLineHeight(el) {
165
+ const style = getComputedStyle(el);
166
+ const lh = Number.parseFloat(style.lineHeight);
167
+ if (Number.isFinite(lh) && lh > 0) return lh;
168
+ return (Number.parseFloat(style.fontSize) || 14) * 1.5;
169
+ }
170
+ function autosizePadding(el) {
171
+ const style = getComputedStyle(el);
172
+ const pad = Number.parseFloat(style.paddingTop) + Number.parseFloat(style.paddingBottom);
173
+ if (style.boxSizing !== "border-box") return 0;
174
+ const border = Number.parseFloat(style.borderTopWidth) + Number.parseFloat(style.borderBottomWidth);
175
+ return (Number.isFinite(pad) ? pad : 0) + (Number.isFinite(border) ? border : 0);
176
+ }
177
+ function adjustHeight() {
178
+ const el = textareaRef.value;
179
+ if (!el) return;
180
+ if (!autosizeEnabled.value) {
181
+ el.style.height = "";
182
+ el.style.overflowY = "";
183
+ return;
184
+ }
185
+ el.style.height = "auto";
186
+ el.style.overflowY = "hidden";
187
+ const lineHeight = parseLineHeight(el);
188
+ const extra = autosizePadding(el);
189
+ const minRows = autosizeSpec.value.minRows ?? props.rows;
190
+ const maxRows = autosizeSpec.value.maxRows;
191
+ const min = lineHeight * minRows + extra;
192
+ const max = maxRows != null ? lineHeight * maxRows + extra : void 0;
193
+ let height = el.scrollHeight;
194
+ if (height < min) height = min;
195
+ if (max != null && height > max) {
196
+ height = max;
197
+ el.style.overflowY = "auto";
198
+ }
199
+ el.style.height = `${height}px`;
200
+ }
201
+ function scheduleAdjustHeight() {
202
+ nextTick(adjustHeight);
203
+ }
204
+ async function runValidate(trigger = "submit") {
205
+ const formRules = formContext?.getFieldRules(props.name) ?? [];
206
+ const localRules = buildLocalInputRules({
207
+ required: props.required,
208
+ rule: props.rule,
209
+ validator: props.validator
210
+ });
211
+ const rules = [...formRules, ...localRules];
212
+ if (!rules.length) {
213
+ autoInvalid.value = false;
214
+ autoMessage.value = "";
215
+ emit("validate", { valid: true });
216
+ return true;
217
+ }
218
+ const result = await runFormFieldRules(model.value, rules, {
219
+ trigger,
220
+ t
221
+ });
222
+ autoInvalid.value = !result.valid;
223
+ autoMessage.value = result.message ?? "";
224
+ emit("validate", result);
225
+ return result.valid;
226
+ }
227
+ function setError(message) {
228
+ autoInvalid.value = true;
229
+ autoMessage.value = message;
230
+ }
231
+ function setValue(value) {
232
+ model.value = String(value ?? "");
233
+ scheduleAdjustHeight();
234
+ }
235
+ function clearValidation() {
236
+ touched.value = false;
237
+ autoInvalid.value = false;
238
+ autoMessage.value = "";
239
+ }
240
+ function focus() {
241
+ textareaRef.value?.focus();
242
+ }
243
+ function blur() {
244
+ textareaRef.value?.blur();
245
+ }
246
+ function onNativeInput(event) {
247
+ const el = event.target;
248
+ model.value = el?.value ?? "";
249
+ scheduleAdjustHeight();
250
+ if (composing.value) return;
251
+ if (touched.value && (props.validateTrigger === "input" || props.validateTrigger === "both")) runValidate("change");
252
+ }
253
+ function onCompositionStart() {
254
+ composing.value = true;
255
+ }
256
+ function onCompositionEnd(event) {
257
+ composing.value = false;
258
+ onNativeInput(event);
259
+ }
260
+ function onBlur(event) {
261
+ touched.value = true;
262
+ if (props.validateTrigger === "blur" || props.validateTrigger === "both") runValidate("blur");
263
+ emit("blur", event);
264
+ }
265
+ function onKeydown(event) {
266
+ if (event.key !== "Enter" || composing.value) return;
267
+ emit("pressEnter", event);
268
+ }
269
+ function onClear() {
270
+ if (resolvedDisabled.value || props.readonly) return;
271
+ model.value = "";
272
+ emit("clear");
273
+ nextTick(() => {
274
+ textareaRef.value?.focus();
275
+ adjustHeight();
276
+ if (props.validateTrigger === "input" || props.validateTrigger === "both") runValidate("change");
277
+ });
278
+ }
279
+ watch([
280
+ model,
281
+ () => props.autosize,
282
+ () => props.rows,
283
+ () => props.size,
284
+ () => props.showCount
285
+ ], scheduleAdjustHeight);
286
+ onMounted(adjustHeight);
287
+ useRsFormField(() => ({
288
+ get name() {
289
+ return props.name;
290
+ },
291
+ getValue: () => model.value,
292
+ setValue,
293
+ validate: async (trigger) => {
294
+ return {
295
+ valid: await runValidate(trigger ?? "submit"),
296
+ message: autoMessage.value || void 0,
297
+ name: props.name
298
+ };
299
+ },
300
+ clearValidation,
301
+ setError
302
+ }));
303
+ __expose({
304
+ validate: runValidate,
305
+ clearValidation,
306
+ setValue,
307
+ setError,
308
+ focus,
309
+ blur
310
+ });
311
+ return (_ctx, _cache) => {
312
+ return openBlock(), createElementBlock("div", {
313
+ class: normalizeClass(["rs-field", [
314
+ `rs-field--label-${resolvedLabelPosition.value}`,
315
+ resolvedLabelPosition.value === "left" && resolvedLabelAlign.value === "end" ? "rs-field--label-align-end" : void 0,
316
+ `rs-input-field--${unref(resolvedSize)}`
317
+ ]]),
318
+ style: normalizeStyle([fieldStyle.value, radiusStyle.value])
319
+ }, [__props.label ? (openBlock(), createElementBlock("span", _hoisted_1, [createElementVNode("label", { for: resolvedId.value }, toDisplayString(__props.label), 9, _hoisted_2), __props.required ? (openBlock(), createElementBlock("span", _hoisted_3, "*")) : createCommentVNode("", true)])) : createCommentVNode("", true), createElementVNode("div", _hoisted_4, [
320
+ createElementVNode("div", { class: normalizeClass(["rs-textarea__shell", {
321
+ "is-invalid": isInvalid.value,
322
+ "is-disabled": resolvedDisabled.value,
323
+ "is-readonly": __props.readonly,
324
+ "is-autosize": autosizeEnabled.value,
325
+ "has-count": __props.showCount,
326
+ "has-clear": showClearButton.value
327
+ }]) }, [
328
+ createElementVNode("textarea", mergeProps({
329
+ ref_key: "textareaRef",
330
+ ref: textareaRef
331
+ }, unref(attrs), {
332
+ id: resolvedId.value,
333
+ value: model.value,
334
+ class: "rs-textarea__control",
335
+ rows: displayRows.value,
336
+ style: { resize: resolvedResize.value },
337
+ placeholder: __props.placeholder,
338
+ disabled: resolvedDisabled.value,
339
+ readonly: __props.readonly,
340
+ minlength: __props.minlength,
341
+ maxlength: __props.maxlength,
342
+ "aria-invalid": isInvalid.value || void 0,
343
+ "aria-describedby": describedBy.value,
344
+ onInput: onNativeInput,
345
+ onCompositionstart: onCompositionStart,
346
+ onCompositionend: onCompositionEnd,
347
+ onKeydown,
348
+ onBlur,
349
+ onFocus: _cache[0] || (_cache[0] = ($event) => emit("focus", $event))
350
+ }), null, 16, _hoisted_5),
351
+ showClearButton.value ? (openBlock(), createElementBlock("button", {
352
+ key: 0,
353
+ type: "button",
354
+ class: "rs-textarea__clear",
355
+ tabindex: "-1",
356
+ "aria-label": unref(t)("input.clear"),
357
+ onPointerdown: _cache[1] || (_cache[1] = withModifiers(() => {}, ["prevent"])),
358
+ onClick: onClear
359
+ }, [createVNode(RsIcon_default, {
360
+ name: "x",
361
+ size: 14
362
+ })], 40, _hoisted_6)) : createCommentVNode("", true),
363
+ __props.showCount ? (openBlock(), createElementBlock("span", {
364
+ key: 1,
365
+ class: normalizeClass(["rs-textarea__count", { "is-limit": countLimitReached.value }]),
366
+ "aria-hidden": "true"
367
+ }, [renderSlot(_ctx.$slots, "count", {
368
+ value: model.value,
369
+ count: model.value.length,
370
+ maxlength: __props.maxlength
371
+ }, () => [createTextVNode(toDisplayString(countText.value), 1)], true)], 2)) : createCommentVNode("", true)
372
+ ], 2),
373
+ displayMessage.value ? (openBlock(), createElementBlock("p", {
374
+ key: 0,
375
+ id: errorId.value,
376
+ class: "rs-field__error",
377
+ role: "alert"
378
+ }, [renderSlot(_ctx.$slots, "error", { message: displayMessage.value }, () => [createTextVNode(toDisplayString(displayMessage.value), 1)], true)], 8, _hoisted_7)) : createCommentVNode("", true),
379
+ __props.hint ? (openBlock(), createElementBlock("span", _hoisted_8, toDisplayString(__props.hint), 1)) : createCommentVNode("", true)
380
+ ])], 6);
381
+ };
382
+ }
383
+ });
384
+ //#endregion
385
+ export { RsTextarea_vue_vue_type_script_setup_true_lang_default as default };
@@ -0,0 +1,8 @@
1
+ import './RsTextarea.css'
2
+ import _plugin_vue_export_helper_default from "../_virtual/_plugin-vue_export-helper.js";
3
+ import RsTextarea_vue_vue_type_script_setup_true_lang_default from "./RsTextarea.impl.js";
4
+
5
+ //#region src/components/RsTextarea.vue
6
+ var RsTextarea_default = /*#__PURE__*/ _plugin_vue_export_helper_default(RsTextarea_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-f75ef1a0"]]);
7
+ //#endregion
8
+ export { RsTextarea_default as default };
@@ -1,15 +1,16 @@
1
1
 
2
2
  .rs-tooltip__with-icon {
3
3
  display: inline-flex;
4
+ flex-wrap: nowrap;
4
5
  align-items: center;
5
6
  gap: 0.25rem;
7
+ width: max-content;
6
8
  max-width: 100%;
7
- vertical-align: baseline;
9
+ vertical-align: middle;
8
10
  }
9
11
  .rs-tooltip__label {
10
- display: inline-flex;
12
+ display: inline;
11
13
  min-width: 0;
12
- max-width: 100%;
13
14
  }
14
15
  .rs-tooltip__icon-trigger {
15
16
  display: inline-flex;
@@ -18,6 +18,8 @@ type __VLS_Props = {
18
18
  icon?: boolean;
19
19
  /** 后缀图标名,默认 info(问号/说明圆标;对齐表单帮助惯用) */
20
20
  iconName?: string;
21
+ /** 帮助图标的无障碍名称;缺省用 content,再回退 locale `tooltip.help` */
22
+ ariaLabel?: string;
21
23
  };
22
24
  declare var __VLS_8: {}, __VLS_27: {}, __VLS_41: {};
23
25
  type __VLS_Slots = {} & {
@@ -1,3 +1,4 @@
1
+ import { useRsI18n } from "../composables/useRsI18n.js";
1
2
  import RsIcon_default from "./RsIcon.js";
2
3
  import { TooltipContent, TooltipPortal, TooltipRoot, TooltipTrigger } from "./reka.js";
3
4
  import { computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createTextVNode, createVNode, defineComponent, normalizeClass, openBlock, renderSlot, toDisplayString, unref, useSlots, withCtx } from "vue";
@@ -34,13 +35,15 @@ var RsTooltip_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ define
34
35
  type: Boolean,
35
36
  default: false
36
37
  },
37
- iconName: { default: "info" }
38
+ iconName: { default: "info" },
39
+ ariaLabel: {}
38
40
  },
39
41
  setup(__props) {
40
42
  const props = __props;
41
43
  const slots = useSlots();
44
+ const { t } = useRsI18n();
42
45
  const hasLabelSlot = computed(() => Boolean(slots.default));
43
- const iconAriaLabel = computed(() => props.content?.trim() || "Help");
46
+ const iconAriaLabel = computed(() => props.ariaLabel?.trim() || props.content?.trim() || t("tooltip.help", "Help"));
44
47
  return (_ctx, _cache) => {
45
48
  return openBlock(), createBlock(unref(TooltipRoot), {
46
49
  disabled: __props.disabled,
@@ -1,29 +1,29 @@
1
1
 
2
- .rs-virtual-list[data-v-c2c4b7ba] {
2
+ .rs-virtual-list[data-v-808bf3fd] {
3
3
  overflow: auto;
4
4
  border: 1px solid var(--rs-border-subtle);
5
5
  border-radius: var(--rs-virtual-list-radius, var(--rs-radius-sm));
6
6
  }
7
- .rs-virtual-list--fill[data-v-c2c4b7ba] {
7
+ .rs-virtual-list--fill[data-v-808bf3fd] {
8
8
  flex: 1;
9
9
  align-self: stretch;
10
10
  width: 100%;
11
11
  min-height: 0;
12
12
  height: 0;
13
13
  }
14
- .rs-virtual-list__spacer[data-v-c2c4b7ba] {
14
+ .rs-virtual-list__spacer[data-v-808bf3fd] {
15
15
  position: relative;
16
16
  }
17
- .rs-virtual-list__items[data-v-c2c4b7ba] {
17
+ .rs-virtual-list__items[data-v-808bf3fd] {
18
18
  position: absolute;
19
19
  left: 0;
20
20
  right: 0;
21
21
  top: 0;
22
22
  }
23
- .rs-virtual-list__item[data-v-c2c4b7ba] {
23
+ .rs-virtual-list__item[data-v-808bf3fd] {
24
24
  box-sizing: border-box;
25
25
  }
26
- .rs-virtual-list__item--active[data-v-c2c4b7ba] {
26
+ .rs-virtual-list__item--active[data-v-808bf3fd] {
27
27
  background: color-mix(in srgb, var(--rs-primary) 14%, var(--rs-surface));
28
28
  box-shadow: inset 2px 0 0 var(--rs-primary);
29
29
  }
@@ -15,7 +15,7 @@ declare const __VLS_export: <T>(__VLS_props: NonNullable<Awaited<typeof __VLS_se
15
15
  __VLS_PROPS_FALLBACK: infer P;
16
16
  } ? P : {});
17
17
  expose: (exposed: import("vue").ShallowUnwrapRef<{
18
- scrollToIndex: (index: number) => void;
18
+ scrollToIndex: (index: number, align?: "nearest" | "center" | "start" | "end") => void;
19
19
  }>) => void;
20
20
  attrs: any;
21
21
  slots: {
@@ -89,17 +89,22 @@ var RsVirtualList_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ de
89
89
  })));
90
90
  const totalHeight = computed(() => props.items.length * fixedItemSize.value);
91
91
  const offsetY = computed(() => startIndex.value * fixedItemSize.value);
92
- function scrollToIndex(index) {
92
+ function scrollToIndex(index, align = "center") {
93
93
  const el = rootRef.value;
94
94
  if (!el || index < 0 || index >= props.items.length) return;
95
95
  const itemTop = index * fixedItemSize.value;
96
96
  const itemBottom = itemTop + fixedItemSize.value;
97
97
  const viewTop = el.scrollTop;
98
98
  const viewBottom = viewTop + el.clientHeight;
99
- if (itemTop >= viewTop && itemBottom <= viewBottom) return;
99
+ if (align === "nearest" && itemTop >= viewTop && itemBottom <= viewBottom) return;
100
100
  const maxScroll = Math.max(0, totalHeight.value - el.clientHeight);
101
- const centered = itemTop - (el.clientHeight - fixedItemSize.value) / 2;
102
- el.scrollTop = Math.min(maxScroll, Math.max(0, centered));
101
+ let next = itemTop - (el.clientHeight - fixedItemSize.value) / 2;
102
+ if (align === "start") next = itemTop;
103
+ if (align === "end") next = itemBottom - el.clientHeight;
104
+ if (align === "nearest") if (itemTop < viewTop) next = itemTop;
105
+ else if (itemBottom > viewBottom) next = itemBottom - el.clientHeight;
106
+ else return;
107
+ el.scrollTop = Math.min(maxScroll, Math.max(0, next));
103
108
  scrollTop.value = el.scrollTop;
104
109
  }
105
110
  watch(() => [props.activeIndex, props.items.length], async ([index, length]) => {
@@ -3,6 +3,6 @@ import _plugin_vue_export_helper_default from "../_virtual/_plugin-vue_export-he
3
3
  import RsVirtualList_vue_vue_type_script_setup_true_lang_default from "./RsVirtualList.impl.js";
4
4
 
5
5
  //#region src/components/RsVirtualList.vue
6
- var RsVirtualList_default = /*#__PURE__*/ _plugin_vue_export_helper_default(RsVirtualList_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-c2c4b7ba"]]);
6
+ var RsVirtualList_default = /*#__PURE__*/ _plugin_vue_export_helper_default(RsVirtualList_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-808bf3fd"]]);
7
7
  //#endregion
8
8
  export { RsVirtualList_default as default };
@@ -1,17 +1,26 @@
1
1
  /**
2
- * RsButton 外观变体
3
- * - primary / default / ghost / danger:常规控件按钮
4
- * - link:行内链接态(可带下划线)
5
- * - text:工具栏/表格操作等 quaternary 文字按钮(无底无边,靠 tone 着色)
2
+ * RsButton 外观变体(形态,与 tone 正交)
3
+ * - primary:实心
4
+ * - default / secondary:轮廓 + 浅底(secondary 等价 default)
5
+ * - ghost:透明底 + 描边
6
+ * - text:无底无边
7
+ * - link:行内链接
8
+ * - danger:兼容别名,等价 primary + tone="danger" 的历史实心底(保留独立样式)
6
9
  */
7
10
  export type RsButtonVariant = 'primary' | 'default' | 'secondary' | 'ghost' | 'danger' | 'link' | 'text';
8
11
  /**
9
- * RsButton 语义色调
10
- * 主要用于 text / ghost / link:只改文字与图标色,不改变填充形态。
11
- * 对 primary / default / danger 等填充变体将被忽略。
12
+ * RsButton 语义色(色相,与 variant 正交)
13
+ * 对齐 Ant Design color / Element Plus type / Naive UI type:
14
+ * `variant="default" tone="warning"` → 描边 + 浅底 + 警告色。
12
15
  */
13
16
  export type RsButtonTone = 'neutral' | 'primary' | 'danger' | 'success' | 'warning' | 'info';
14
- /** 填充类变体:已自带语义色,不再叠加 tone */
17
+ /** 规范化变体:未传为 primary;secondary 视为 default。 */
18
+ export declare function resolveRsButtonVariant(variant?: RsButtonVariant): Exclude<RsButtonVariant, 'secondary'>;
19
+ /**
20
+ * 解析语义色。未传 tone 时:primary/link 用 primary,danger 变体用 danger,其余 neutral。
21
+ */
22
+ export declare function resolveRsButtonTone(variant?: RsButtonVariant, tone?: RsButtonTone): RsButtonTone;
23
+ /** 实心/轮廓填充类变体(相对 text / ghost / link)。 */
15
24
  export declare function isRsButtonFilledVariant(variant: RsButtonVariant): boolean;
16
- /** text / ghost / link 可叠加 tone */
17
- export declare function supportsRsButtonTone(variant: RsButtonVariant): boolean;
25
+ /** 所有变体都可叠加 tone(形态 × 色相)。 */
26
+ export declare function supportsRsButtonTone(_variant?: RsButtonVariant): boolean;
@@ -1,13 +1,28 @@
1
1
  //#region src/components/button-utils.ts
2
- /** 填充类变体:已自带语义色,不再叠加 tone */
2
+ /** 规范化变体:未传为 primary;secondary 视为 default。 */
3
+ function resolveRsButtonVariant(variant) {
4
+ if (variant === "secondary") return "default";
5
+ if (!variant) return "primary";
6
+ return variant;
7
+ }
8
+ /**
9
+ * 解析语义色。未传 tone 时:primary/link 用 primary,danger 变体用 danger,其余 neutral。
10
+ */
11
+ function resolveRsButtonTone(variant, tone) {
12
+ if (tone) return tone;
13
+ const resolved = resolveRsButtonVariant(variant);
14
+ if (resolved === "danger") return "danger";
15
+ if (resolved === "primary" || resolved === "link") return "primary";
16
+ return "neutral";
17
+ }
18
+ /** 实心/轮廓填充类变体(相对 text / ghost / link)。 */
3
19
  function isRsButtonFilledVariant(variant) {
4
- const resolved = variant === "secondary" ? "default" : variant;
20
+ const resolved = resolveRsButtonVariant(variant);
5
21
  return resolved === "primary" || resolved === "default" || resolved === "danger";
6
22
  }
7
- /** text / ghost / link 可叠加 tone */
8
- function supportsRsButtonTone(variant) {
9
- const resolved = variant === "secondary" ? "default" : variant;
10
- return resolved === "text" || resolved === "ghost" || resolved === "link";
23
+ /** 所有变体都可叠加 tone(形态 × 色相)。 */
24
+ function supportsRsButtonTone(_variant) {
25
+ return true;
11
26
  }
12
27
  //#endregion
13
- export { isRsButtonFilledVariant, supportsRsButtonTone };
28
+ export { isRsButtonFilledVariant, resolveRsButtonTone, resolveRsButtonVariant, supportsRsButtonTone };
@@ -14,6 +14,8 @@ export declare function useRsDialogWindow(options: {
14
14
  widthPreset: Ref<RsDialogWidthPreset>;
15
15
  /** 自定义初始宽度(px);有值时优先于预设/比例 */
16
16
  initialWidth?: Ref<number | undefined>;
17
+ /** 自定义初始高度(px);有值时优先于默认 75% 视口高 */
18
+ initialHeight?: Ref<number | undefined>;
17
19
  draggable: Ref<boolean>;
18
20
  resizable: Ref<boolean>;
19
21
  compact?: Ref<boolean>;
@@ -62,9 +62,10 @@ function useRsDialogWindow(options) {
62
62
  function defaultWindowSize() {
63
63
  const { width: maxW, height: maxH } = dialogViewportSize();
64
64
  const customW = options.initialWidth?.value;
65
+ const customH = options.initialHeight?.value;
65
66
  return {
66
67
  width: customW != null && Number.isFinite(customW) && customW > 0 ? Math.min(maxW, Math.max(minWidth, Math.round(customW))) : Math.min(maxW, Math.max(minWidth, Math.round(maxW * defaultWidthRatio))),
67
- height: Math.min(maxH, Math.max(minHeight, Math.round(maxH * defaultHeightRatio)))
68
+ height: customH != null && Number.isFinite(customH) && customH > 0 ? Math.min(maxH, Math.max(minHeight, Math.round(customH))) : Math.min(maxH, Math.max(minHeight, Math.round(maxH * defaultHeightRatio)))
68
69
  };
69
70
  }
70
71
  function refreshCachedInsets() {
@@ -0,0 +1,29 @@
1
+ import type { RsFontSize, RsFontWeight } from '../theme/types';
2
+ /**
3
+ * 表单分组密度。只影响内边距与组内间距,不改变控件高度。
4
+ */
5
+ export type RsFieldsetSize = 'sm' | 'md';
6
+ /**
7
+ * 边框线型。对齐 CSS `border-style`(solid / dashed / dotted)。
8
+ */
9
+ export type RsFieldsetBorderStyle = 'solid' | 'dashed' | 'dotted';
10
+ /**
11
+ * 边框浓度。
12
+ * - default:主题分隔线
13
+ * - subtle:弱分隔
14
+ * - faded:虚化(降低不透明度)
15
+ */
16
+ export type RsFieldsetBorderTone = 'default' | 'subtle' | 'faded';
17
+ /**
18
+ * 标题对比(清晰度)。
19
+ * - strong:最高对比
20
+ * - default:正文色
21
+ * - muted:次要说明色
22
+ */
23
+ export type RsFieldsetTitleTone = 'strong' | 'default' | 'muted';
24
+ /** 分组标题字号,只开放 caption / 次要 / 正文三档。 */
25
+ export type RsFieldsetTitleSize = Extract<RsFontSize, 'xs' | 'sm' | 'base'>;
26
+ /** 解析标题字号 token。 */
27
+ export declare function resolveFieldsetTitleSize(size: RsFieldsetTitleSize): string;
28
+ /** 解析标题字重 token。 */
29
+ export declare function resolveFieldsetTitleWeight(weight: RsFontWeight): string;
@@ -0,0 +1,12 @@
1
+ import { RS_FONT_SIZE_CSS, RS_FONT_WEIGHT_CSS } from "../theme/types.js";
2
+ //#region src/components/fieldset-utils.ts
3
+ /** 解析标题字号 token。 */
4
+ function resolveFieldsetTitleSize(size) {
5
+ return RS_FONT_SIZE_CSS[size];
6
+ }
7
+ /** 解析标题字重 token。 */
8
+ function resolveFieldsetTitleWeight(weight) {
9
+ return RS_FONT_WEIGHT_CSS[weight];
10
+ }
11
+ //#endregion
12
+ export { resolveFieldsetTitleSize, resolveFieldsetTitleWeight };