@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.
Files changed (43) hide show
  1. package/dist/app_layout/ClassicLayout.svelte +8 -40
  2. package/dist/app_layout/ColumnsLayout.svelte +3 -3
  3. package/dist/app_layout/HeaderLayout.svelte +4 -20
  4. package/dist/app_layout/RowsLayout.svelte +3 -3
  5. package/dist/app_layout/SidebarLayout.svelte +4 -20
  6. package/dist/composite/transfer/Transfer.svelte +12 -6
  7. package/dist/data_display/accordion/Accordion.svelte +1 -4
  8. package/dist/data_display/card/CommonCardActionBar.svelte +1 -27
  9. package/dist/data_display/list_box/ListBox.svelte +6 -8
  10. package/dist/data_table/lib/clickOutSide.js +6 -5
  11. package/dist/form/attachment_files/AttachmentEditor.svelte +13 -8
  12. package/dist/form/attachment_files/FileUploadBar.svelte +5 -2
  13. package/dist/form/attachment_files/FileUploadPanel.svelte +6 -72
  14. package/dist/form/checkbox/CheckBox.svelte +2 -7
  15. package/dist/form/color_picker/ColorPicker.svelte +150 -35
  16. package/dist/form/color_picker/ColorPicker.svelte.d.ts +7 -25
  17. package/dist/form/color_picker/README.md +14 -7
  18. package/dist/form/color_picker/README_CN.md +14 -7
  19. package/dist/form/common_editor/CommonPicker.svelte +4 -7
  20. package/dist/form/image-files/ImagePreview.svelte +15 -7
  21. package/dist/form/memo_editor/MemoEditor.svelte +2 -2
  22. package/dist/form/number_editor/NumberEditor.svelte +2 -2
  23. package/dist/form/options_multi_select/OptionsMultiSelect.svelte +1 -9
  24. package/dist/form/radio_button/RadioButton.svelte +2 -8
  25. package/dist/form/text_editor/TextEditor.svelte +2 -2
  26. package/dist/general/button/Button.svelte +2 -0
  27. package/dist/general/split/Split.svelte +24 -4
  28. package/dist/navigation/nav_menu/MenuItem.d.ts +4 -2
  29. package/dist/navigation/nav_menu/NavigatorMenu.svelte +157 -34
  30. package/dist/navigation/nav_menu/NavigatorMenu.svelte.d.ts +2 -3
  31. package/dist/navigation/nav_menu/NavigatorMenuItem.svelte +15 -12
  32. package/dist/navigation/nav_menu/NavigatorMenuItem.svelte.d.ts +3 -3
  33. package/dist/navigation/progress_step_bar/ProgressStepBlock.svelte +1 -5
  34. package/dist/overlay/common/FloatingPanel.svelte +0 -6
  35. package/dist/overlay/common/Popover.svelte +8 -3
  36. package/dist/overlay/common/uniface-utils.js +0 -1
  37. package/dist/overlay/context-menu/ContextMenuPanel.svelte +14 -2
  38. package/dist/overlay/dialog/Dialog.svelte +3 -4
  39. package/dist/overlay/dialog/DialogWrapper.svelte +5 -2
  40. package/dist/ticatec-uniface-web.css +26 -6
  41. package/dist/utils/prefixFilter.d.ts +3 -3
  42. package/dist/utils/prefixFilter.js +3 -5
  43. package/package.json +1 -1
@@ -1,14 +1,14 @@
1
1
  <script lang="ts">
2
+ import {onMount} from "svelte";
2
3
  import type MenuItem from "./MenuItem";
3
- import type {OnMenuClick} from "./MenuItem";
4
- import type {IHierarchyData} from "../../lib";
4
+ import type {MenuNode, OnMenuClick} from "./MenuItem";
5
5
  import NavigatorMenuItem from "./NavigatorMenuItem.svelte";
6
6
 
7
7
  type GetText<T> = (item: T) => string;
8
8
  type Variant = 'vertical' | 'horizontal';
9
9
 
10
10
  interface Props {
11
- menuItems: Array<IHierarchyData<MenuItem>>;
11
+ menuItems: Array<MenuNode>;
12
12
  style?: string;
13
13
  textField: string | GetText<MenuItem>;
14
14
  onItemClick: OnMenuClick;
@@ -27,15 +27,46 @@
27
27
 
28
28
  // 横向模式:当前展开的 root 索引(同时只开一个 dropdown)
29
29
  let openRootIdx = $state<number | null>(null);
30
+ let scrollViewport = $state<HTMLDivElement>();
31
+ let scrollTrack = $state<HTMLDivElement>();
32
+ let horizontalMenu = $state<HTMLElement>();
33
+ let hasOverflow = $state(false);
34
+ let canScrollLeft = $state(false);
35
+ let canScrollRight = $state(false);
36
+ let dropdownLeft = $state(0);
30
37
 
31
- const rootText = (root: IHierarchyData<MenuItem>): string => {
38
+ const rootText = (root: MenuNode): string => {
32
39
  return typeof textField === 'string'
33
- ? root.data?.[textField] ?? ''
34
- : textField(root.data);
40
+ ? root.item?.[textField] ?? ''
41
+ : textField(root.item);
42
+ };
43
+
44
+ const updateDropdownPosition = () => {
45
+ if (openRootIdx === null || !horizontalMenu || !scrollTrack) return;
46
+ const item = scrollTrack.children[openRootIdx] as HTMLElement | undefined;
47
+ if (!item) return;
48
+ dropdownLeft = item.getBoundingClientRect().left - horizontalMenu.getBoundingClientRect().left;
49
+ };
50
+
51
+ const updateScrollState = () => {
52
+ if (!scrollViewport) return;
53
+ const maxScrollLeft = scrollViewport.scrollWidth - scrollViewport.clientWidth;
54
+ hasOverflow = maxScrollLeft > 1;
55
+ canScrollLeft = scrollViewport.scrollLeft > 1;
56
+ canScrollRight = scrollViewport.scrollLeft < maxScrollLeft - 1;
57
+ updateDropdownPosition();
35
58
  };
36
59
 
37
60
  const handleRootClick = (idx: number) => {
38
61
  openRootIdx = openRootIdx === idx ? null : idx;
62
+ requestAnimationFrame(updateDropdownPosition);
63
+ };
64
+
65
+ const scrollMenu = (direction: -1 | 1) => {
66
+ scrollViewport?.scrollBy({
67
+ left: direction * Math.max(scrollViewport.clientWidth * 0.7, 160),
68
+ behavior: 'smooth'
69
+ });
39
70
  };
40
71
 
41
72
  // 横向模式下点叶子:触发 onItemClick + 关闭 dropdown
@@ -59,6 +90,15 @@
59
90
  }
60
91
  };
61
92
  };
93
+
94
+ onMount(() => {
95
+ if (!scrollViewport || !scrollTrack) return;
96
+ const resizeObserver = new ResizeObserver(updateScrollState);
97
+ resizeObserver.observe(scrollViewport);
98
+ resizeObserver.observe(scrollTrack);
99
+ updateScrollState();
100
+ return () => resizeObserver.disconnect();
101
+ });
62
102
  </script>
63
103
 
64
104
  {#if variant === 'vertical'}
@@ -72,36 +112,50 @@
72
112
  {/if}
73
113
  </div>
74
114
  {:else}
75
- <nav class="uniface-navigator-menu horizontal" {style} data-theme={theme || undefined}>
76
- {#each menuItems as root, idx (idx)}
77
- <div
78
- class="root-item"
79
- class:open={openRootIdx === idx}
80
- class:leaf={root.children.length === 0}
81
- onclick={(e) => { e.stopPropagation(); handleRootClick(idx); }}
82
- onkeydown={(e) => { if (e.key === 'Enter' || e.key === ' ') handleRootClick(idx); }}
83
- role="button"
84
- tabindex="0"
85
- >
86
- <span class="label">{rootText(root)}</span>
87
- {#if root.children.length > 0}
88
- <i class="caret" aria-hidden="true"></i>
89
- {/if}
90
- {#if openRootIdx === idx && root.children.length > 0}
115
+ <nav bind:this={horizontalMenu} class="uniface-navigator-menu horizontal" {style} data-theme={theme || undefined}>
116
+ {#if hasOverflow}
117
+ <button class="scroll-button previous" aria-label="向左滚动菜单" disabled={!canScrollLeft} onclick={() => scrollMenu(-1)}>
118
+ <i aria-hidden="true"></i>
119
+ </button>
120
+ {/if}
121
+ <div bind:this={scrollViewport} class="scroll-viewport" onscroll={updateScrollState}>
122
+ <div bind:this={scrollTrack} class="scroll-track">
123
+ {#each menuItems as root, idx (idx)}
91
124
  <div
92
- class="dropdown-panel"
93
- use:outerClick={() => { openRootIdx = null; }}
94
- onclick={(e) => e.stopPropagation()}
125
+ class="root-item"
126
+ class:open={openRootIdx === idx}
127
+ class:leaf={!root.children?.length}
128
+ onclick={(e) => { e.stopPropagation(); handleRootClick(idx); }}
129
+ onkeydown={(e) => { if (e.key === 'Enter' || e.key === ' ') handleRootClick(idx); }}
130
+ role="button"
131
+ tabindex="0"
95
132
  >
96
- <ul class="dropdown">
97
- {#each root.children as child}
98
- <NavigatorMenuItem menu={child} onMenuItemClick={handleLeafClickInDropdown} {textField} cascade={true}/>
99
- {/each}
100
- </ul>
133
+ <span class="label">{rootText(root)}</span>
134
+ {#if root.children?.length}
135
+ <i class="caret" aria-hidden="true"></i>
136
+ {/if}
101
137
  </div>
102
- {/if}
138
+ {/each}
103
139
  </div>
104
- {/each}
140
+ </div>
141
+ {#if hasOverflow}
142
+ <button class="scroll-button next" aria-label="向右滚动菜单" disabled={!canScrollRight} onclick={() => scrollMenu(1)}>
143
+ <i aria-hidden="true"></i>
144
+ </button>
145
+ {/if}
146
+ {#if openRootIdx !== null && menuItems[openRootIdx]?.children?.length}
147
+ <div
148
+ class="dropdown-panel"
149
+ style:left="{dropdownLeft}px"
150
+ use:outerClick={() => { openRootIdx = null; }}
151
+ >
152
+ <ul class="dropdown">
153
+ {#each menuItems[openRootIdx].children ?? [] as child}
154
+ <NavigatorMenuItem menu={child} onMenuItemClick={handleLeafClickInDropdown} {textField} cascade={true}/>
155
+ {/each}
156
+ </ul>
157
+ </div>
158
+ {/if}
105
159
  </nav>
106
160
  {/if}
107
161
 
@@ -143,6 +197,76 @@
143
197
  height: 48px;
144
198
  }
145
199
 
200
+ .scroll-viewport {
201
+ flex: 1 1 auto;
202
+ min-width: 0;
203
+ height: 100%;
204
+ overflow-x: auto;
205
+ overflow-y: hidden;
206
+ scrollbar-width: none;
207
+ scroll-behavior: smooth;
208
+ }
209
+
210
+ .scroll-viewport::-webkit-scrollbar {
211
+ display: none;
212
+ }
213
+
214
+ .scroll-track {
215
+ display: flex;
216
+ align-items: center;
217
+ width: max-content;
218
+ min-width: 100%;
219
+ height: 100%;
220
+ }
221
+
222
+ .scroll-button {
223
+ flex: 0 0 32px;
224
+ width: 32px;
225
+ height: 100%;
226
+ padding: 0;
227
+ border: 0;
228
+ background: var(--uniface-nav-menu-bg);
229
+ color: inherit;
230
+ cursor: pointer;
231
+ opacity: 0;
232
+ visibility: hidden;
233
+ pointer-events: none;
234
+ transition: opacity 0.15s ease, visibility 0.15s ease;
235
+ }
236
+
237
+ .uniface-navigator-menu.horizontal:hover .scroll-button,
238
+ .uniface-navigator-menu.horizontal:focus-within .scroll-button {
239
+ opacity: 1;
240
+ visibility: visible;
241
+ pointer-events: auto;
242
+ }
243
+
244
+ .scroll-button:hover:not(:disabled) {
245
+ background-color: var(--uniface-nav-menu-hover-bg);
246
+ color: var(--uniface-nav-menu-hover-color);
247
+ }
248
+
249
+ .scroll-button:disabled {
250
+ cursor: default;
251
+ opacity: 0.35;
252
+ }
253
+
254
+ .scroll-button i {
255
+ display: inline-block;
256
+ width: 8px;
257
+ height: 8px;
258
+ border-top: 2px solid currentColor;
259
+ border-left: 2px solid currentColor;
260
+ }
261
+
262
+ .scroll-button.previous i {
263
+ transform: rotate(-45deg);
264
+ }
265
+
266
+ .scroll-button.next i {
267
+ transform: rotate(135deg);
268
+ }
269
+
146
270
  .uniface-navigator-menu.horizontal .root-item {
147
271
  position: relative;
148
272
  padding: 0 16px;
@@ -176,7 +300,6 @@
176
300
  .dropdown-panel {
177
301
  position: absolute;
178
302
  top: 100%;
179
- left: 0;
180
303
  z-index: 1000;
181
304
  }
182
305
 
@@ -190,4 +313,4 @@
190
313
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
191
314
  min-width: 180px;
192
315
  }
193
- </style>
316
+ </style>
@@ -1,10 +1,9 @@
1
1
  import type MenuItem from "./MenuItem";
2
- import type { OnMenuClick } from "./MenuItem";
3
- import type { IHierarchyData } from "../../lib";
2
+ import type { MenuNode, OnMenuClick } from "./MenuItem";
4
3
  type GetText<T> = (item: T) => string;
5
4
  type Variant = 'vertical' | 'horizontal';
6
5
  interface Props {
7
- menuItems: Array<IHierarchyData<MenuItem>>;
6
+ menuItems: Array<MenuNode>;
8
7
  style?: string;
9
8
  textField: string | GetText<MenuItem>;
10
9
  onItemClick: OnMenuClick;
@@ -1,13 +1,13 @@
1
1
  <script lang="ts">
2
2
  import {slide, fly} from "svelte/transition";
3
3
  import type MenuItem from "./MenuItem";
4
- import type {OnMenuClick} from "./MenuItem";
5
- import type {IHierarchyData} from "../../lib";
4
+ import type {MenuNode, OnMenuClick} from "./MenuItem";
5
+ import NavigatorMenuItem from "./NavigatorMenuItem.svelte";
6
6
 
7
7
  type GetText<T> = (item: T) => string;
8
8
 
9
9
  interface Props {
10
- menu: IHierarchyData<MenuItem>;
10
+ menu: MenuNode;
11
11
  textField: string | GetText<MenuItem>;
12
12
  onMenuItemClick: OnMenuClick;
13
13
  defaultExpand?: boolean;
@@ -26,14 +26,17 @@
26
26
  cascade = false
27
27
  }: Props = $props();
28
28
 
29
- let expand = $state(defaultExpand);
29
+ // defaultExpand seeds local interaction state once; subsequent prop changes must
30
+ // not overwrite a choice the user has already made.
31
+ const getInitialExpanded = () => defaultExpand;
32
+ let expand = $state(getInitialExpanded());
30
33
  let respond = $state(true);
31
34
  let liEl: HTMLElement;
32
35
  /** true = 子菜单飞到左边(右边空间不够时) */
33
36
  let flyLeft = $state(false);
34
37
 
35
- let expandable = $derived(menu.children.length > 0);
36
- let menuText = $derived(typeof textField == 'string' ? menu.data?.[textField] ?? 'Unknown item' : textField(menu.data));
38
+ let expandable = $derived(!!menu.children?.length);
39
+ let menuText = $derived(typeof textField == 'string' ? menu.item?.[textField] ?? 'Unknown item' : textField(menu.item));
37
40
 
38
41
  // 级联模式下,展开前先测一下右边够不够放子菜单
39
42
  const measureFlyout = () => {
@@ -53,7 +56,7 @@
53
56
  }
54
57
  expand = !expand;
55
58
  } else {
56
- onMenuItemClick?.(menu.data);
59
+ onMenuItemClick?.(menu.item);
57
60
  }
58
61
  }
59
62
  }
@@ -74,14 +77,14 @@
74
77
  {#if expandable && expand}
75
78
  {#if cascade}
76
79
  <ul class="flyout" transition:fly={{duration: 200, x: flyLeft ? -20 : 20}}>
77
- {#each menu.children as el}
78
- <svelte:self menu={el} {onMenuItemClick} {textField} {cascade}/>
80
+ {#each menu.children ?? [] as el}
81
+ <NavigatorMenuItem menu={el} {onMenuItemClick} {textField} {cascade}/>
79
82
  {/each}
80
83
  </ul>
81
84
  {:else}
82
85
  <ul class="inline" transition:slide={{duration: 200}}>
83
- {#each menu.children as el}
84
- <svelte:self menu={el} {onMenuItemClick} {textField} {cascade}/>
86
+ {#each menu.children ?? [] as el}
87
+ <NavigatorMenuItem menu={el} {onMenuItemClick} {textField} {cascade}/>
85
88
  {/each}
86
89
  </ul>
87
90
  {/if}
@@ -168,4 +171,4 @@
168
171
  left: auto;
169
172
  right: 100%;
170
173
  }
171
- </style>
174
+ </style>
@@ -1,9 +1,9 @@
1
1
  import type MenuItem from "./MenuItem";
2
- import type { OnMenuClick } from "./MenuItem";
3
- import type { IHierarchyData } from "../../lib";
2
+ import type { MenuNode, OnMenuClick } from "./MenuItem";
3
+ import NavigatorMenuItem from "./NavigatorMenuItem.svelte";
4
4
  type GetText<T> = (item: T) => string;
5
5
  interface Props {
6
- menu: IHierarchyData<MenuItem>;
6
+ menu: MenuNode;
7
7
  textField: string | GetText<MenuItem>;
8
8
  onMenuItemClick: OnMenuClick;
9
9
  defaultExpand?: boolean;
@@ -157,10 +157,6 @@
157
157
  color: var(--uniface-progress-step-completed-color, #374151);
158
158
  }
159
159
 
160
- .progress-step-block:last-child {
161
- /* Keep the line for the last step */
162
- }
163
-
164
160
  /* Vertical styles */
165
161
  .progress-step-block.vertical {
166
162
  margin-left: 0;
@@ -198,4 +194,4 @@
198
194
  .progress-step-block.vertical:last-child .step-indicator > div {
199
195
  background: transparent;
200
196
  }
201
- </style>
197
+ </style>
@@ -75,9 +75,3 @@
75
75
  >
76
76
  {@render children?.()}
77
77
  </div>
78
-
79
- <style>
80
- .floating-panel {
81
- /* 视觉样式由调用方在 children 上控制。这里只负责定位 + 挂载到 body。 */
82
- }
83
- </style>
@@ -110,8 +110,13 @@
110
110
  }, 50);
111
111
  }, 50); // 延迟显示 portal
112
112
  window.addEventListener("resize", updatePosition);
113
- document.addEventListener("scroll", updatePosition, {passive: false});
114
- const interval = setInterval(checkPosition, 10); // 100ms 检测一次
113
+ // capture:true — scroll events don't bubble, so a listener on the bubble phase
114
+ // only ever sees window/document-level scroll. Capturing catches scroll on any
115
+ // nested scrollable ancestor (a table body, a dialog's scroll area, etc.) too,
116
+ // which is what keeps the popover pinned to its anchor while that container
117
+ // scrolls. Matches the pattern in FloatingPanel.svelte.
118
+ window.addEventListener("scroll", updatePosition, true);
119
+ const interval = setInterval(checkPosition, 10); // 每 10ms 检测一次
115
120
  const resizeObserver = new ResizeObserver(entries => {
116
121
  for (let entry of entries) {
117
122
  updatePosition();
@@ -120,7 +125,7 @@
120
125
  resizeObserver.observe(contentPanel);
121
126
  return () => {
122
127
  window.removeEventListener("resize", updatePosition);
123
- document.removeEventListener("scroll", updatePosition);
128
+ window.removeEventListener("scroll", updatePosition, true);
124
129
  resizeObserver.disconnect();
125
130
  clearInterval(interval);
126
131
  };
@@ -1,6 +1,5 @@
1
1
  export function clickOutside(node) {
2
2
  const handleClick = (event) => {
3
- // @ts-ignore 因为 event.target 是 EventTarget,不能直接传给 contains
4
3
  if (node && !node.contains(event.target) && !event.defaultPrevented) {
5
4
  node.dispatchEvent(new CustomEvent('outerClick', {
6
5
  bubbles: true, // 通常自定义事件要冒泡,方便捕获
@@ -78,6 +78,16 @@
78
78
  break;
79
79
  }
80
80
  }
81
+
82
+ function activateItem(event: MouseEvent | KeyboardEvent, index: number) {
83
+ if (event instanceof KeyboardEvent && event.key !== 'Enter' && event.key !== ' ') return;
84
+ event.preventDefault();
85
+ event.stopPropagation();
86
+ const item = contextMenuSvelte.items[index];
87
+ if (item.disabled) return;
88
+ item.action?.();
89
+ contextMenuSvelte.hide();
90
+ }
81
91
  </script>
82
92
 
83
93
  {#if contextMenuSvelte.visible}
@@ -103,8 +113,10 @@
103
113
  class:focused={focusedIndex === index}
104
114
  style={item.style || ''}
105
115
  role="menuitem"
116
+ tabindex="-1"
106
117
  aria-disabled={item.disabled}
107
- onclick={() => { if(!item.disabled && item.action) { item.action(); contextMenuSvelte.hide(); } }}
118
+ onclick={(event) => activateItem(event, index)}
119
+ onkeydown={(event) => activateItem(event, index)}
108
120
  onmouseenter={() => { if(!item.disabled) focusedIndex = index; }}
109
121
  >
110
122
  {#if item.icon}
@@ -184,4 +196,4 @@
184
196
  height: 1px;
185
197
  background-color: var(--uniface-contextmenu-color-separator);
186
198
  margin: var(--uniface-contextmenu-separator-margin) 0;
187
- }</style>
199
+ }</style>
@@ -128,11 +128,10 @@
128
128
  );
129
129
  </script>
130
130
 
131
- <svelte:window onkeydown={handleWindowKeyDown}/>
131
+ <svelte:window onkeydown={handleWindowKeyDown} onmousemove={handleMouseMove} onmouseup={handleMouseUp}/>
132
132
 
133
133
  <div class="uniface-dialog" data-dialog-id={dialogId}
134
- style="{startMove ? 'cursor: move' : ''}"
135
- onmousemove={handleMouseMove} onmouseleave={handleMouseUp}>
134
+ style="{startMove ? 'cursor: move' : ''}">
136
135
  <div class="uniface-dialog-box"
137
136
  style="{dialog$style}; top: {top}px; left: {left}px; width: {width}; height: {height};">
138
137
  <div class="title-bar" onmousedown={handleMouseDown} onmouseup={handleMouseUp} aria-hidden="true">
@@ -230,4 +229,4 @@
230
229
  align-items: center;
231
230
  justify-content: flex-end;
232
231
  border-top: 1px solid var(--uniface-dialog-divider-color, #F0F0F0);
233
- }</style>
232
+ }</style>
@@ -3,7 +3,10 @@
3
3
 
4
4
  let {id, component: Comp, params}: {id: string, component: any, params: Record<string, any>} = $props();
5
5
 
6
- setContext('dialogId', id);
6
+ // Context identity is fixed for the lifetime of this wrapper; later prop changes
7
+ // must not replace the dialog registration used by its descendants.
8
+ const getInitialDialogId = () => id;
9
+ setContext('dialogId', getInitialDialogId());
7
10
  </script>
8
11
 
9
- <Comp {...params}/>
12
+ <Comp {...params}/>
@@ -412,6 +412,11 @@
412
412
  --uniface-progress-step-completed-color: #374151;
413
413
  --uniface-progress-step-completed-icon-bg: #0061FF1A;
414
414
  --uniface-progress-step-completed-icon-color: #0061FF;
415
+ /* TreeView Tokens */
416
+ --uniface-treeview-chevron-color: #6b7280;
417
+ --uniface-treeview-chevron-hover-color: #111827;
418
+ --uniface-treeview-item-bg: #EEF4FF;
419
+ --uniface-treeview-item-selected-color: #0061FF;
415
420
  --uniface-listbox-separator-color: #F0F0F0;
416
421
  --uniface-list-box-hover-surface: #FFFFE1;
417
422
  --uniface-list-box-selected-surface: #b1c8f6;
@@ -521,6 +526,11 @@
521
526
  --uniface-calendar-color-selected-surface: #2563eb;
522
527
  --uniface-calendar-color-selected: #ffffff;
523
528
  --uniface-calendar-color-day-surface-hover: rgba(255, 255, 255, 0.08);
529
+ /* TreeView Tokens */
530
+ --uniface-treeview-chevron-color: #9ca3af;
531
+ --uniface-treeview-chevron-hover-color: #e5e7eb;
532
+ --uniface-treeview-item-bg: rgba(255, 255, 255, 0.08);
533
+ --uniface-treeview-item-selected-color: #60a5fa;
524
534
  /* Menu Separator */
525
535
  --uniface-menu-separator-color: rgba(255, 255, 255, 0.08);
526
536
  /* Drawer Tokens */
@@ -991,11 +1001,6 @@
991
1001
  background-color: var(--uniface-editor-color-filled-surface);
992
1002
  transition: background-color 0.2s ease, border-color 0.2s ease;
993
1003
  }
994
- .uniface-form-editor.plain {
995
- background-color: transparent;
996
- border-bottom-color: transparent;
997
- border-radius: 0;
998
- }
999
1004
  .uniface-form-editor {
1000
1005
  /* 1.2 状态感知拦截 (States) */
1001
1006
  }
@@ -1005,6 +1010,14 @@
1005
1010
  .uniface-form-editor:focus-within {
1006
1011
  border-color: var(--uniface-editor-color-active-border);
1007
1012
  }
1013
+ .uniface-form-editor.plain {
1014
+ background-color: transparent;
1015
+ border-bottom-color: transparent;
1016
+ border-radius: 0;
1017
+ }
1018
+ .uniface-form-editor.plain.focus-within {
1019
+ border-color: transparent;
1020
+ }
1008
1021
  .uniface-form-editor.disabled {
1009
1022
  color: var(--uniface-editor-color-disabled);
1010
1023
  cursor: not-allowed;
@@ -1201,7 +1214,14 @@
1201
1214
  }
1202
1215
 
1203
1216
  .uniface-popover-wrapper {
1204
- position: absolute;
1217
+ /* Popover.svelte computes position.top/left from target.getBoundingClientRect(),
1218
+ which is viewport-relative. `position: absolute` places this element relative to
1219
+ the document instead, so it drifted away from its anchor by the page's (or any
1220
+ ancestor's) scroll offset. `fixed` keeps the same coordinate frame as the values
1221
+ driving top/left, and combined with the scroll listener in Popover.svelte the
1222
+ overlay stays pinned to its anchor while scrolling. See also ContextMenuPanel.svelte
1223
+ and FloatingPanel.svelte, which use the same fixed + viewport-relative-coords pattern. */
1224
+ position: fixed;
1205
1225
  display: block;
1206
1226
  z-index: 100;
1207
1227
  opacity: 1;
@@ -1,5 +1,5 @@
1
- declare const prefixFilter: (attrs: any, prefix: string, excludes?: Array<string>) => any;
2
- declare const eventFilter: (attrs: any) => any;
3
- declare const filterProps: (attrs: any, keys: Array<any>) => any;
1
+ declare const prefixFilter: (attrs: Record<string, unknown>, prefix: string, excludes?: Array<string>) => Record<string, unknown>;
2
+ declare const eventFilter: (attrs: Record<string, unknown>) => Record<string, unknown>;
3
+ declare const filterProps: (attrs: Record<string, unknown>, keys: Array<string>) => Record<string, unknown>;
4
4
  export default prefixFilter;
5
5
  export { eventFilter, filterProps };
@@ -1,12 +1,11 @@
1
1
  import { keyboardAttrs } from "../form/common_editor/EditorEvents";
2
2
  const prefixFilter = (attrs, prefix, excludes = []) => {
3
- let obj = {};
3
+ const obj = {};
4
4
  let len = prefix.length;
5
5
  for (let attr in attrs) {
6
6
  if (attr.startsWith(prefix) && attr.length > len) {
7
7
  let newAttr = attr.substring(len);
8
8
  if (excludes.indexOf(newAttr) < 0) {
9
- // @ts-ignore
10
9
  obj[newAttr] = attrs[attr];
11
10
  }
12
11
  }
@@ -14,17 +13,16 @@ const prefixFilter = (attrs, prefix, excludes = []) => {
14
13
  return obj;
15
14
  };
16
15
  const eventFilter = (attrs) => {
17
- let obj = {};
16
+ const obj = {};
18
17
  for (let attr in attrs) {
19
18
  if (attr.startsWith('on') && attr.length > 2) {
20
- // @ts-ignore
21
19
  obj[attr] = attrs[attr];
22
20
  }
23
21
  }
24
22
  return obj;
25
23
  };
26
24
  const filterProps = (attrs, keys) => {
27
- let obj = {};
25
+ const obj = {};
28
26
  for (let attr in attrs) {
29
27
  if (keys.indexOf(attr) > -1) {
30
28
  obj[attr] = attrs[attr];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ticatec/uniface-element",
3
- "version": "5.0.0",
3
+ "version": "5.0.1",
4
4
  "description": "A comprehensive UI component library for Svelte applications with rich form controls, data tables, layouts and interactive elements",
5
5
  "keywords": [
6
6
  "svelte",