@ticatec/uniface-element 5.0.0 → 5.0.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.
- package/dist/app_layout/ClassicLayout.svelte +8 -40
- package/dist/app_layout/ColumnsLayout.svelte +3 -3
- package/dist/app_layout/HeaderLayout.svelte +4 -20
- package/dist/app_layout/RowsLayout.svelte +3 -3
- package/dist/app_layout/SidebarLayout.svelte +4 -20
- package/dist/composite/transfer/Transfer.svelte +12 -6
- package/dist/data_display/accordion/Accordion.svelte +1 -4
- package/dist/data_display/card/CommonCardActionBar.svelte +1 -27
- package/dist/data_display/list_box/ListBox.svelte +6 -8
- package/dist/data_table/lib/clickOutSide.js +6 -5
- package/dist/form/attachment_files/AttachmentEditor.svelte +13 -8
- package/dist/form/attachment_files/FileUploadBar.svelte +5 -2
- package/dist/form/attachment_files/FileUploadPanel.svelte +6 -72
- package/dist/form/checkbox/CheckBox.svelte +2 -7
- package/dist/form/color_picker/ColorPicker.svelte +150 -35
- package/dist/form/color_picker/ColorPicker.svelte.d.ts +7 -25
- package/dist/form/color_picker/README.md +14 -7
- package/dist/form/color_picker/README_CN.md +14 -7
- package/dist/form/common_editor/CommonPicker.svelte +4 -7
- package/dist/form/image-files/ImagePreview.svelte +15 -7
- package/dist/form/memo_editor/MemoEditor.svelte +2 -2
- package/dist/form/number_editor/NumberEditor.svelte +2 -2
- package/dist/form/options_multi_select/OptionsMultiSelect.svelte +1 -9
- package/dist/form/radio_button/RadioButton.svelte +2 -8
- package/dist/form/text_editor/TextEditor.svelte +2 -2
- package/dist/general/button/Button.svelte +2 -0
- package/dist/general/split/Split.svelte +24 -4
- package/dist/navigation/nav_menu/MenuItem.d.ts +4 -2
- package/dist/navigation/nav_menu/NavigatorMenu.svelte +157 -34
- package/dist/navigation/nav_menu/NavigatorMenu.svelte.d.ts +2 -3
- package/dist/navigation/nav_menu/NavigatorMenuItem.svelte +15 -12
- package/dist/navigation/nav_menu/NavigatorMenuItem.svelte.d.ts +3 -3
- package/dist/navigation/progress_step_bar/ProgressStepBlock.svelte +1 -5
- package/dist/overlay/common/FloatingPanel.svelte +0 -6
- package/dist/overlay/common/Popover.svelte +8 -3
- package/dist/overlay/common/uniface-utils.js +0 -1
- package/dist/overlay/context-menu/ContextMenuPanel.svelte +14 -2
- package/dist/overlay/dialog/Dialog.svelte +3 -4
- package/dist/overlay/dialog/DialogWrapper.svelte +5 -2
- package/dist/ticatec-uniface-web.css +26 -6
- package/dist/utils/prefixFilter.d.ts +3 -3
- package/dist/utils/prefixFilter.js +3 -5
- package/package.json +1 -1
|
@@ -1,58 +1,173 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
import type {OnChangeHandler} from "../../types";
|
|
5
3
|
import CommonPicker from "../common_editor/CommonPicker.svelte";
|
|
4
|
+
import type CommonFieldProps from "../common_editor/CommonFieldProps";
|
|
6
5
|
|
|
7
|
-
|
|
6
|
+
interface Props extends CommonFieldProps {
|
|
7
|
+
value?: string;
|
|
8
|
+
}
|
|
8
9
|
|
|
9
|
-
//
|
|
10
|
-
//
|
|
10
|
+
// The manually-typed value must resolve to exactly #RRGGBB. An 8-digit #RRGGBBAA
|
|
11
|
+
// form was supported briefly, but <input type="color"> has no concept of alpha —
|
|
12
|
+
// the swatch always showed just the RGB portion and nothing in the UI ever
|
|
13
|
+
// rendered the transparency, so the last 2 digits had no visible effect. Dropped
|
|
14
|
+
// rather than half-implemented; revisit with a real alpha-aware swatch (checkered
|
|
15
|
+
// background + rgba preview) if this is needed later.
|
|
16
|
+
const HEX_PATTERN = /^#[0-9a-fA-F]{6}$/;
|
|
17
|
+
const DEFAULT_SWATCH = '#000000';
|
|
18
|
+
|
|
19
|
+
// CommonPicker always renders its own internal <input> in the non-readonly branch,
|
|
20
|
+
// even when a `children` snippet is also supplied — it doesn't apply the same
|
|
21
|
+
// "children replaces the default input" rule that its readonly branch does. Every
|
|
22
|
+
// other consumer works around this by never passing `children` in the first place
|
|
23
|
+
// (DatePicker, OptionsSelect...) except OptionsMultiSelect, which needs custom
|
|
24
|
+
// content (its tag list) the same way ColorPicker needs its swatch+hex layout —
|
|
25
|
+
// it hides CommonPicker's own input via `input$style` (shrink to 1x1, transparent,
|
|
26
|
+
// click-through) so only the custom children are visible. Same fix here: without
|
|
27
|
+
// this, edit mode showed CommonPicker's own empty input fighting for space with our
|
|
28
|
+
// swatch, while readonly mode (which only renders `children`) looked correct.
|
|
29
|
+
const HIDDEN_INTERNAL_INPUT_STYLE = 'position: absolute; left: 0; top: 0; width: 1px; height: 1px; opacity: 0; pointer-events: none';
|
|
30
|
+
|
|
31
|
+
let {
|
|
32
|
+
variant,
|
|
33
|
+
theme,
|
|
34
|
+
disabled = false,
|
|
35
|
+
readonly = false,
|
|
36
|
+
compact = false,
|
|
37
|
+
value = $bindable<string | undefined>("#000000"),
|
|
38
|
+
style,
|
|
39
|
+
placeholder,
|
|
40
|
+
error,
|
|
41
|
+
tooltip,
|
|
42
|
+
onchange,
|
|
43
|
+
onfocus,
|
|
44
|
+
onblur
|
|
45
|
+
}: Props = $props();
|
|
46
|
+
|
|
47
|
+
let editor: HTMLInputElement | undefined = $state();
|
|
48
|
+
let textInput: HTMLInputElement | undefined = $state();
|
|
49
|
+
|
|
50
|
+
// Editing buffer for the manual hex field, kept separate from `value` so the user
|
|
51
|
+
// can type through transient/incomplete states (e.g. "#3b8") without every
|
|
52
|
+
// keystroke being validated against the full #RRGGBB format — validation only
|
|
53
|
+
// happens on commit (blur / Enter).
|
|
54
|
+
let textValue = $state(value ?? '');
|
|
55
|
+
|
|
56
|
+
$effect(() => {
|
|
57
|
+
textValue = value ?? '';
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
let swatchValue = $derived(value && HEX_PATTERN.test(value) ? value : DEFAULT_SWATCH);
|
|
61
|
+
|
|
62
|
+
export const focus = () => {
|
|
63
|
+
editor?.focus();
|
|
64
|
+
}
|
|
11
65
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
export let value: any = "#ff3e00";
|
|
17
|
-
export let style: string = '';
|
|
18
|
-
export let onChange: OnChangeHandler<any> = null as unknown as OnChangeHandler<any>;
|
|
66
|
+
const clean = () => {
|
|
67
|
+
value = undefined;
|
|
68
|
+
onchange?.(undefined);
|
|
69
|
+
}
|
|
19
70
|
|
|
71
|
+
const handleActionIconClick = () => {
|
|
72
|
+
if (!readonly && !disabled) {
|
|
73
|
+
editor?.click();
|
|
74
|
+
}
|
|
75
|
+
}
|
|
20
76
|
|
|
21
|
-
|
|
77
|
+
const handleSwatchChange = (event: Event) => {
|
|
78
|
+
const newValue = (event.target as HTMLInputElement).value;
|
|
79
|
+
value = newValue;
|
|
80
|
+
onchange?.(newValue);
|
|
81
|
+
}
|
|
22
82
|
|
|
23
|
-
|
|
24
|
-
|
|
83
|
+
// The native color picker dialog opens on `click`, and preventing the default
|
|
84
|
+
// action here blocks it — this is the only reliable way to make the swatch
|
|
85
|
+
// non-interactive for `readonly`, since <input type="color"> ignores the
|
|
86
|
+
// `readonly` attribute entirely. Using the native `disabled` attribute instead
|
|
87
|
+
// would work too, but it also greys the swatch out, which conflates readonly
|
|
88
|
+
// with disabled (see the component README: readonly stays fully visible,
|
|
89
|
+
// disabled is dimmed).
|
|
90
|
+
const handleColorInputClick = (event: MouseEvent) => {
|
|
91
|
+
if (readonly) {
|
|
92
|
+
event.preventDefault();
|
|
93
|
+
}
|
|
25
94
|
}
|
|
26
95
|
|
|
27
|
-
|
|
96
|
+
const handleColorInputKeydown = (event: KeyboardEvent) => {
|
|
97
|
+
if (readonly && (event.key === 'Enter' || event.key === ' ')) {
|
|
98
|
+
event.preventDefault();
|
|
99
|
+
}
|
|
100
|
+
}
|
|
28
101
|
|
|
29
|
-
const
|
|
30
|
-
|
|
102
|
+
const commitTextValue = () => {
|
|
103
|
+
let candidate = textValue.trim();
|
|
104
|
+
if (candidate && !candidate.startsWith('#')) {
|
|
105
|
+
candidate = `#${candidate}`;
|
|
106
|
+
}
|
|
107
|
+
if (HEX_PATTERN.test(candidate)) {
|
|
108
|
+
textValue = candidate;
|
|
109
|
+
if (candidate !== value) {
|
|
110
|
+
value = candidate;
|
|
111
|
+
onchange?.(candidate);
|
|
112
|
+
}
|
|
113
|
+
} else {
|
|
114
|
+
// Doesn't resolve to a valid #RRGGBB value on commit — revert to the last
|
|
115
|
+
// known-good value rather than accepting a malformed color.
|
|
116
|
+
textValue = value ?? '';
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Only '#' and hex digits are allowed while typing; the exact length requirement
|
|
121
|
+
// is enforced separately on commit (see commitTextValue), since rejecting
|
|
122
|
+
// incomplete input on every keystroke would make it impossible to type a value
|
|
123
|
+
// character by character.
|
|
124
|
+
const handleTextKeydown = (event: KeyboardEvent) => {
|
|
125
|
+
const allowKeys = ['Backspace', 'Delete', 'Tab', 'ArrowLeft', 'ArrowRight', 'Home', 'End'];
|
|
126
|
+
if (allowKeys.includes(event.key) || event.metaKey || event.ctrlKey) return;
|
|
127
|
+
if (event.key === 'Enter') {
|
|
128
|
+
event.preventDefault();
|
|
129
|
+
textInput?.blur();
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
if (event.key === 'Escape') {
|
|
133
|
+
textValue = value ?? '';
|
|
134
|
+
textInput?.blur();
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
if (!/^[0-9a-fA-F#]$/.test(event.key)) {
|
|
138
|
+
event.preventDefault();
|
|
139
|
+
}
|
|
31
140
|
}
|
|
32
141
|
|
|
33
|
-
const
|
|
34
|
-
|
|
142
|
+
const handleTextPaste = (event: ClipboardEvent) => {
|
|
143
|
+
const pasted = event.clipboardData?.getData('text') ?? '';
|
|
144
|
+
if (/[^0-9a-fA-F#]/.test(pasted)) {
|
|
145
|
+
event.preventDefault();
|
|
146
|
+
}
|
|
35
147
|
}
|
|
36
148
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
149
|
+
// Defense in depth against anything that bypasses handleTextKeydown (IME, mobile
|
|
150
|
+
// virtual keyboards, drag-and-drop text) — strip disallowed characters and cap at
|
|
151
|
+
// one leading '#' plus 6 hex digits.
|
|
152
|
+
const handleTextInput = () => {
|
|
153
|
+
const hasHash = textValue.startsWith('#');
|
|
154
|
+
const hexOnly = textValue.replace(/#/g, '').replace(/[^0-9a-fA-F]/g, '').slice(0, 6);
|
|
155
|
+
const sanitized = (hasHash ? '#' : '') + hexOnly;
|
|
156
|
+
if (sanitized !== textValue) {
|
|
157
|
+
textValue = sanitized;
|
|
158
|
+
}
|
|
45
159
|
}
|
|
46
160
|
|
|
47
161
|
</script>
|
|
48
162
|
|
|
49
|
-
<CommonPicker {variant} {style} {compact} className="multiple" iconName="icon_google_color_lens"
|
|
50
|
-
autoFit clear={clean} textValue={value} {readonly} {disabled} iconClickHandler={handleActionIconClick}
|
|
51
|
-
|
|
163
|
+
<CommonPicker {variant} {style} {theme} {error} {tooltip} {compact} {placeholder} className="multiple" iconName="icon_google_color_lens"
|
|
164
|
+
autoFit clear={clean} textValue={value} {readonly} {disabled} {onfocus} {onblur} iconClickHandler={handleActionIconClick}
|
|
165
|
+
input$style={HIDDEN_INTERNAL_INPUT_STYLE}>
|
|
52
166
|
<div style="width: 100%; display: flex; overflow: hidden; flex-direction: row; align-items: center; height: 100%; gap: 8px">
|
|
53
|
-
<input bind:this={editor} style="flex: 0 0 auto; width: 40%; height: 80%; border-radius: 8px;" type="color"
|
|
54
|
-
|
|
167
|
+
<input bind:this={editor} style="flex: 0 0 auto; width: 40%; height: 80%; border-radius: 8px;" type="color" value={swatchValue} {disabled}
|
|
168
|
+
tabindex={readonly ? -1 : 0} onclick={handleColorInputClick} onkeydown={handleColorInputKeydown} onchange={handleSwatchChange}/>
|
|
169
|
+
<input bind:this={textInput} style="flex: 0 0 auto; width: 50%; text-align: center" class="text-editor" bind:value={textValue}
|
|
170
|
+
readonly={readonly} {disabled} {placeholder} maxlength="7" spellcheck="false" autocomplete="off"
|
|
171
|
+
onblur={commitTextValue} onkeydown={handleTextKeydown} onpaste={handleTextPaste} oninput={handleTextInput}/>
|
|
55
172
|
</div>
|
|
56
|
-
|
|
57
|
-
|
|
58
173
|
</CommonPicker>
|
|
@@ -1,27 +1,9 @@
|
|
|
1
|
-
import type
|
|
2
|
-
interface
|
|
3
|
-
|
|
4
|
-
$$bindings?: Bindings;
|
|
5
|
-
} & Exports;
|
|
6
|
-
(internal: unknown, props: Props & {
|
|
7
|
-
$$events?: Events;
|
|
8
|
-
$$slots?: Slots;
|
|
9
|
-
}): Exports & {
|
|
10
|
-
$set?: any;
|
|
11
|
-
$on?: any;
|
|
12
|
-
};
|
|
13
|
-
z_$$bindings?: Bindings;
|
|
1
|
+
import type CommonFieldProps from "../common_editor/CommonFieldProps";
|
|
2
|
+
interface Props extends CommonFieldProps {
|
|
3
|
+
value?: string;
|
|
14
4
|
}
|
|
15
|
-
declare const ColorPicker:
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
compact?: boolean;
|
|
20
|
-
value?: any;
|
|
21
|
-
style?: string;
|
|
22
|
-
onChange?: OnChangeHandler<any>;
|
|
23
|
-
}, {
|
|
24
|
-
[evt: string]: CustomEvent<any>;
|
|
25
|
-
}, {}, {}, string>;
|
|
26
|
-
type ColorPicker = InstanceType<typeof ColorPicker>;
|
|
5
|
+
declare const ColorPicker: import("svelte").Component<Props, {
|
|
6
|
+
focus: () => void;
|
|
7
|
+
}, "value">;
|
|
8
|
+
type ColorPicker = ReturnType<typeof ColorPicker>;
|
|
27
9
|
export default ColorPicker;
|
|
@@ -40,7 +40,7 @@ import ColorPicker from "@ticatec/uniface-element/ColorPicker";
|
|
|
40
40
|
|
|
41
41
|
| Prop | Type | Default | Description |
|
|
42
42
|
|------|------|---------|-------------|
|
|
43
|
-
| `value` | `string` (bindable) | `"#000000"` | The selected color in hex format (e.g., `#3b82f6`). `bind:value={...}` for two-way binding. |
|
|
43
|
+
| `value` | `string` (bindable) | `"#000000"` | The selected color in `#RRGGBB` hex format (e.g., `#3b82f6`). `bind:value={...}` for two-way binding. |
|
|
44
44
|
| `variant` | `'' \| 'plain' \| 'outlined' \| 'filled'` | `''` | Visual style variant. |
|
|
45
45
|
| `compact` | `boolean` | `false` | Dense layout for table cells and inline forms. |
|
|
46
46
|
| `disabled` | `boolean` | `false` | Fully disabled — the color picker is non-interactive. |
|
|
@@ -263,18 +263,25 @@ import ColorPicker from "@ticatec/uniface-element/ColorPicker";
|
|
|
263
263
|
|
|
264
264
|
## Behavior Notes
|
|
265
265
|
|
|
266
|
-
### Native color input
|
|
266
|
+
### Native color input + editable hex field
|
|
267
267
|
|
|
268
|
-
The component
|
|
268
|
+
The component shows two parts side by side: a native `<input type="color">` swatch (opens the browser's built-in color picker) and a text field showing the hex value. The text field is directly editable — typing a value and committing it (blur or Enter) updates `value` the same as picking a color from the swatch.
|
|
269
269
|
|
|
270
|
-
|
|
270
|
+
There's no alpha/transparency support — `<input type="color">` has no concept of it, so `value` is always a plain 6-digit `#rrggbb`.
|
|
271
271
|
|
|
272
|
-
|
|
272
|
+
### Hex format and validation
|
|
273
|
+
|
|
274
|
+
`value` must be exactly `#RRGGBB` (6 hex digits after `#`, case-insensitive). When typing in the text field:
|
|
275
|
+
|
|
276
|
+
- Only `#` and hex digits (`0-9a-fA-F`) can be typed, capped at 6 digits — anything else is blocked or truncated as you type.
|
|
277
|
+
- The value is validated on commit (blur or Enter), not on every keystroke, so you can type through incomplete intermediate states.
|
|
278
|
+
- A missing leading `#` is added automatically on commit (e.g. typing `ff0000` commits as `#ff0000`).
|
|
279
|
+
- If the committed text isn't a valid `#RRGGBB` string, the field reverts to the last valid value — `onchange` is not called.
|
|
273
280
|
|
|
274
281
|
### Disabled and readonly states
|
|
275
282
|
|
|
276
|
-
- **Disabled**: The color picker is non-interactive. The visual swatch is dimmed.
|
|
277
|
-
- **Readonly**: The color picker is non-interactive but the
|
|
283
|
+
- **Disabled**: The color picker is non-interactive. The visual swatch is dimmed, and the hex field is disabled.
|
|
284
|
+
- **Readonly**: The color picker is non-interactive but fully visible — the swatch blocks clicks (it can't open the native picker) and the hex field becomes a non-editable (but not dimmed) readonly text field.
|
|
278
285
|
|
|
279
286
|
## Accessibility
|
|
280
287
|
|
|
@@ -40,7 +40,7 @@ import ColorPicker from "@ticatec/uniface-element/ColorPicker";
|
|
|
40
40
|
|
|
41
41
|
| 属性 | 类型 | 默认值 | 说明 |
|
|
42
42
|
|------|------|--------|------|
|
|
43
|
-
| `value` | `string`(可绑定) | `"#000000"` |
|
|
43
|
+
| `value` | `string`(可绑定) | `"#000000"` | `#RRGGBB` 格式的颜色(例如 `#3b82f6`)。`bind:value={...}` 用于双向绑定。 |
|
|
44
44
|
| `variant` | `'' \| 'plain' \| 'outlined' \| 'filled'` | `''` | 视觉风格变体。 |
|
|
45
45
|
| `compact` | `boolean` | `false` | 紧凑布局,适用于表格单元格和行内表单。 |
|
|
46
46
|
| `disabled` | `boolean` | `false` | 完全禁用 —— 颜色选择器不可交互。 |
|
|
@@ -263,18 +263,25 @@ import ColorPicker from "@ticatec/uniface-element/ColorPicker";
|
|
|
263
263
|
|
|
264
264
|
## 行为说明
|
|
265
265
|
|
|
266
|
-
### 原生颜色输入
|
|
266
|
+
### 原生颜色输入 + 可编辑的 hex 文本框
|
|
267
267
|
|
|
268
|
-
|
|
268
|
+
组件并排展示两部分:原生 `<input type="color">` 色板(点击打开浏览器内置的颜色选择器)和展示 hex 值的文本框。文本框可以直接编辑——输入一个值并提交(失焦或回车)后,`value` 会像通过色板选色一样更新。
|
|
269
269
|
|
|
270
|
-
|
|
270
|
+
不支持透明通道——`<input type="color">` 本身没有这个概念,因此 `value` 始终是纯 6 位 `#rrggbb`。
|
|
271
271
|
|
|
272
|
-
|
|
272
|
+
### Hex 格式与校验
|
|
273
|
+
|
|
274
|
+
`value` 必须是合法的 `#RRGGBB`(`#` 后跟 6 位十六进制数字,大小写不敏感)。在文本框中输入时:
|
|
275
|
+
|
|
276
|
+
- 只能输入 `#` 和十六进制字符(`0-9a-fA-F`),最多 6 位——其他字符在输入时会被拦截或截断。
|
|
277
|
+
- 校验只在提交时(失焦或回车)进行,不是每次按键都校验,因此可以正常输入中间的不完整状态。
|
|
278
|
+
- 提交时如果缺少开头的 `#` 会自动补上(例如输入 `ff0000` 会被提交为 `#ff0000`)。
|
|
279
|
+
- 如果提交的文本不是合法的 `#RRGGBB`,文本框会回退到上一个合法值——不会触发 `onchange`。
|
|
273
280
|
|
|
274
281
|
### 禁用和只读状态
|
|
275
282
|
|
|
276
|
-
-
|
|
277
|
-
-
|
|
283
|
+
- **禁用**:颜色选择器不可交互。视觉色板变暗,hex 文本框也被禁用。
|
|
284
|
+
- **只读**:颜色选择器不可交互,但完全可见——色板会拦截点击(无法打开原生选择器),hex 文本框变为不可编辑(但不变暗)的只读文本框。
|
|
278
285
|
|
|
279
286
|
## 无障碍
|
|
280
287
|
|
|
@@ -70,7 +70,7 @@
|
|
|
70
70
|
let editorElement: HTMLElement | undefined = $state();
|
|
71
71
|
let editor: HTMLDivElement | undefined = $state();
|
|
72
72
|
let hasFocus = $state(false);
|
|
73
|
-
let canClean = $
|
|
73
|
+
let canClean = $derived(!mandatory && value != null);
|
|
74
74
|
|
|
75
75
|
|
|
76
76
|
const handleFocus = (event: FocusEvent) => {
|
|
@@ -111,7 +111,6 @@
|
|
|
111
111
|
}
|
|
112
112
|
|
|
113
113
|
$effect(() => {
|
|
114
|
-
canClean = !mandatory && value != null;
|
|
115
114
|
if (!isOpen && hasFocus) {
|
|
116
115
|
setTimeout(() => {
|
|
117
116
|
if (document.activeElement !== editor) {
|
|
@@ -148,12 +147,12 @@
|
|
|
148
147
|
<input style={input$style} tabindex="-1" readonly {disabled} value={textValue}/>
|
|
149
148
|
{/if}
|
|
150
149
|
{:else}
|
|
151
|
-
<div style="flex: 1 1 auto; position: relative; overflow: hidden; height: 100%"
|
|
150
|
+
<div style="flex: 1 1 auto; position: relative; overflow: hidden; height: 100%">
|
|
152
151
|
{#if input$readonly}
|
|
153
|
-
<input bind:this={editor} style={input$style} value={textValue} readonly {placeholder} onkeydown={handleKeyDown}
|
|
152
|
+
<input bind:this={editor} style={input$style} value={textValue} readonly {placeholder} onclick={openPopup} onkeydown={handleKeyDown}
|
|
154
153
|
tabindex="0"/>
|
|
155
154
|
{:else}
|
|
156
|
-
<input bind:this={editor} style={input$style} value={textValue} {oninput} {oncompositionstart} {oncompositionend}
|
|
155
|
+
<input bind:this={editor} style={input$style} value={textValue} {oninput} {oncompositionstart} {oncompositionend} onclick={openPopup}
|
|
157
156
|
{placeholder} tabindex="0" onkeydown={handleKeyDown}/>
|
|
158
157
|
{/if}
|
|
159
158
|
{#if children}
|
|
@@ -181,5 +180,3 @@
|
|
|
181
180
|
{/if}
|
|
182
181
|
</Popover>
|
|
183
182
|
{/if}
|
|
184
|
-
|
|
185
|
-
|
|
@@ -65,12 +65,13 @@
|
|
|
65
65
|
<div style="width: 100%; height: 100%; overflow: auto">
|
|
66
66
|
<div class="image-container"
|
|
67
67
|
style="width: {containerWidth}px; height: {containerHeight}px; {imgStyle}">
|
|
68
|
-
<
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
68
|
+
<button type="button" class="image-content" aria-label="Preview image" onclick={(e: Event) => e.stopPropagation()}>
|
|
69
|
+
<img src={src}
|
|
70
|
+
alt="Preview"
|
|
71
|
+
onload={handleImageLoad}
|
|
72
|
+
style="width: {imgPanelWidth}px; height: {imgPanelHeight}px;"
|
|
73
|
+
/>
|
|
74
|
+
</button>
|
|
74
75
|
</div>
|
|
75
76
|
</div>
|
|
76
77
|
<div class="toolbar" onclick={(e: Event) => e.stopPropagation()} aria-hidden="true">
|
|
@@ -120,10 +121,17 @@
|
|
|
120
121
|
img {
|
|
121
122
|
transition: transform 0.3s ease;
|
|
122
123
|
}
|
|
124
|
+
|
|
125
|
+
.image-content {
|
|
126
|
+
display: inline-flex;
|
|
127
|
+
padding: 0;
|
|
128
|
+
border: 0;
|
|
129
|
+
background: transparent;
|
|
130
|
+
}
|
|
123
131
|
}
|
|
124
132
|
|
|
125
133
|
&:hover .toolbar {
|
|
126
134
|
display: flex;
|
|
127
135
|
}
|
|
128
136
|
}
|
|
129
|
-
</style>
|
|
137
|
+
</style>
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
...restProps
|
|
46
46
|
}: Props = $props();
|
|
47
47
|
|
|
48
|
-
let numberInput
|
|
48
|
+
let numberInput = $state<NumberInput>();
|
|
49
49
|
|
|
50
50
|
export function focus() {
|
|
51
51
|
numberInput?.focus();
|
|
@@ -94,4 +94,4 @@
|
|
|
94
94
|
{...input$}
|
|
95
95
|
/>
|
|
96
96
|
{/if}
|
|
97
|
-
</CommonEditor>
|
|
97
|
+
</CommonEditor>
|
|
@@ -214,16 +214,8 @@
|
|
|
214
214
|
outline: none;
|
|
215
215
|
}
|
|
216
216
|
|
|
217
|
-
.options-editor.disabled {
|
|
218
|
-
filter: grayscale(1);
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
.options-editor.disabled * {
|
|
222
|
-
cursor: not-allowed;
|
|
223
|
-
}
|
|
224
|
-
|
|
225
217
|
.options-editor .placeholder {
|
|
226
218
|
color: var(--uniface-editor-color-placeholder);
|
|
227
219
|
}
|
|
228
220
|
|
|
229
|
-
</style>
|
|
221
|
+
</style>
|
|
@@ -72,13 +72,6 @@
|
|
|
72
72
|
text-overflow: ellipsis;
|
|
73
73
|
color: var(--uniface-checkbox-text-color);
|
|
74
74
|
}
|
|
75
|
-
.uniface-radio-button label {
|
|
76
|
-
display: inline-block;
|
|
77
|
-
width: 100%;
|
|
78
|
-
text-overflow: ellipsis;
|
|
79
|
-
overflow: hidden;
|
|
80
|
-
cursor: pointer;
|
|
81
|
-
}
|
|
82
75
|
.uniface-radio-button > span {
|
|
83
76
|
line-height: var(--uniface-checkbox-size);
|
|
84
77
|
padding-left: var(--uniface-checkbox-label-padding-left);
|
|
@@ -107,6 +100,7 @@
|
|
|
107
100
|
--disabled-inner: var(--uniface-checkbox-checkmark-color-disabled);
|
|
108
101
|
-webkit-appearance: none;
|
|
109
102
|
-moz-appearance: none;
|
|
103
|
+
appearance: none;
|
|
110
104
|
height: var(--uniface-checkbox-size);
|
|
111
105
|
width: var(--uniface-checkbox-size);
|
|
112
106
|
outline: none;
|
|
@@ -180,4 +174,4 @@
|
|
|
180
174
|
.uniface-radio-button *::before,
|
|
181
175
|
.uniface-radio-button *::after {
|
|
182
176
|
box-sizing: inherit;
|
|
183
|
-
}</style>
|
|
177
|
+
}</style>
|
|
@@ -69,7 +69,7 @@
|
|
|
69
69
|
}
|
|
70
70
|
|
|
71
71
|
let input$ = $derived(prefixFilter(restProps, 'input$', excludeAttrs));
|
|
72
|
-
let eventHandlers = filterProps(restProps, keyboardAttrs);
|
|
72
|
+
let eventHandlers = $derived(filterProps(restProps, keyboardAttrs));
|
|
73
73
|
|
|
74
74
|
const clear = () => {
|
|
75
75
|
value = undefined;
|
|
@@ -83,4 +83,4 @@
|
|
|
83
83
|
{error}>
|
|
84
84
|
<input bind:this={editor} {...input$} {placeholder} {...eventHandlers}
|
|
85
85
|
oninput={handleInput} onchange={handleChange} bind:value/>
|
|
86
|
-
</CommonEditor>
|
|
86
|
+
</CommonEditor>
|
|
@@ -44,6 +44,8 @@
|
|
|
44
44
|
|
|
45
45
|
</script>
|
|
46
46
|
|
|
47
|
+
<!-- autofocus is an explicit opt-in component API; consumers decide when initial focus is appropriate. -->
|
|
48
|
+
<!-- svelte-ignore a11y_autofocus -->
|
|
47
49
|
<button
|
|
48
50
|
{style}
|
|
49
51
|
class="uniface-button common-button {variant} {size} {type} {theme}"
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import {
|
|
2
|
+
import {onDestroy} from 'svelte';
|
|
3
3
|
|
|
4
4
|
interface Props {
|
|
5
5
|
direction?: "horizontal" | "vertical";
|
|
@@ -76,6 +76,22 @@
|
|
|
76
76
|
}
|
|
77
77
|
};
|
|
78
78
|
|
|
79
|
+
const resizeWithKeyboard = (event: KeyboardEvent) => {
|
|
80
|
+
if (fixed || !bindingPanel) return;
|
|
81
|
+
const decreaseKey = direction === 'horizontal' ? 'ArrowUp' : 'ArrowLeft';
|
|
82
|
+
const increaseKey = direction === 'horizontal' ? 'ArrowDown' : 'ArrowRight';
|
|
83
|
+
if (event.key !== decreaseKey && event.key !== increaseKey) return;
|
|
84
|
+
|
|
85
|
+
event.preventDefault();
|
|
86
|
+
const directionFactor = event.key === increaseKey ? 1 : -1;
|
|
87
|
+
const delta = directionFactor * (reverse ? -10 : 10);
|
|
88
|
+
const currentSize = direction === 'horizontal' ? bindingPanel.clientHeight : bindingPanel.clientWidth;
|
|
89
|
+
const newSize = Math.max(5, currentSize + delta);
|
|
90
|
+
if (direction === 'horizontal') bindingPanel.style.height = `${newSize}px`;
|
|
91
|
+
else bindingPanel.style.width = `${newSize}px`;
|
|
92
|
+
onResizeEnd?.(newSize);
|
|
93
|
+
};
|
|
94
|
+
|
|
79
95
|
// 组件销毁时清理
|
|
80
96
|
onDestroy(() => {
|
|
81
97
|
if (isDragging) {
|
|
@@ -85,6 +101,9 @@
|
|
|
85
101
|
|
|
86
102
|
</script>
|
|
87
103
|
|
|
104
|
+
<!-- The separator is intentionally focusable because its arrow-key handler resizes the bound panel. -->
|
|
105
|
+
<!-- svelte-ignore a11y_no_noninteractive_tabindex -->
|
|
106
|
+
<!-- svelte-ignore a11y_no_noninteractive_element_interactions -->
|
|
88
107
|
<div
|
|
89
108
|
class="uniface-divider {direction}"
|
|
90
109
|
class:fixed
|
|
@@ -92,9 +111,10 @@
|
|
|
92
111
|
role="separator"
|
|
93
112
|
aria-orientation={direction}
|
|
94
113
|
aria-label="Resize handle"
|
|
95
|
-
tabindex=
|
|
114
|
+
tabindex={fixed ? -1 : 0}
|
|
96
115
|
onmousedown={startDrag}
|
|
97
|
-
|
|
116
|
+
onkeydown={resizeWithKeyboard}
|
|
117
|
+
></div>
|
|
98
118
|
|
|
99
119
|
<style>
|
|
100
120
|
.uniface-divider {
|
|
@@ -127,4 +147,4 @@
|
|
|
127
147
|
.uniface-divider:active {
|
|
128
148
|
transition: none;
|
|
129
149
|
}
|
|
130
|
-
</style>
|
|
150
|
+
</style>
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import type { IHierarchyData } from "../../lib";
|
|
2
1
|
export default interface MenuItem {
|
|
3
2
|
[key: string]: any;
|
|
4
3
|
}
|
|
5
|
-
export interface MenuNode
|
|
4
|
+
export interface MenuNode {
|
|
5
|
+
item: MenuItem;
|
|
6
|
+
children?: MenuNode[];
|
|
7
|
+
expand?: boolean;
|
|
6
8
|
}
|
|
7
9
|
export type OnMenuClick = (item: MenuItem) => void;
|