@ticatec/uniface-element 5.0.1 → 5.0.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.
Files changed (261) hide show
  1. package/README.md +29 -54
  2. package/README_CN.md +37 -57
  3. package/dist/base-calendar/CalendarBase.svelte +29 -6
  4. package/dist/base-calendar/CalendarBase.svelte.d.ts +4 -0
  5. package/dist/base-calendar/MonthPickupPanel.svelte +19 -6
  6. package/dist/base-calendar/MonthPickupPanel.svelte.d.ts +1 -1
  7. package/dist/base-calendar/MonthlyCalendar.svelte +18 -2
  8. package/dist/base-calendar/YearPickupPanel.svelte +24 -6
  9. package/dist/base-calendar/YearPickupPanel.svelte.d.ts +1 -1
  10. package/dist/composite/pagination_panel/PaginationPanel.svelte +2 -0
  11. package/dist/data_display/card/CommonCardActionBar.svelte +34 -14
  12. package/dist/data_display/concise_data_table/Column.d.ts +6 -0
  13. package/dist/data_display/concise_data_table/ConciseListTable.svelte +4 -3
  14. package/dist/data_display/concise_data_table/DataCell.svelte +3 -3
  15. package/dist/data_display/list_box/ListBox.svelte +90 -15
  16. package/dist/data_display/list_box/ListBox.svelte.d.ts +4 -0
  17. package/dist/data_display/tree_view/TreeNodeView.svelte +25 -4
  18. package/dist/data_table/DataTable.svelte +5 -5
  19. package/dist/data_table/DataTable.svelte.d.ts +36 -16
  20. package/dist/data_table/lib/ActionsColumn.d.ts +2 -2
  21. package/dist/data_table/lib/DataColumn.d.ts +7 -1
  22. package/dist/data_table/lib/RowAction.d.ts +5 -5
  23. package/dist/data_table/parts/FixedHeaderPanel.svelte +18 -3
  24. package/dist/data_table/parts/FixedRow.svelte +10 -1
  25. package/dist/data_table/parts/HrefCell.svelte +1 -1
  26. package/dist/data_table/parts/TableHeaderPanel.svelte +18 -2
  27. package/dist/data_table/parts/TextCell.svelte +2 -2
  28. package/dist/form/attachment_files/AttachmentEditor.svelte +9 -9
  29. package/dist/form/attachment_files/FileRender.svelte +1 -1
  30. package/dist/form/attachment_files/FileUploadPanel.svelte +5 -1
  31. package/dist/form/cascade_options_select/CascadeOptionSelect.svelte +10 -2
  32. package/dist/form/cascade_options_select/OptionsBox.svelte +48 -2
  33. package/dist/form/color_picker/ColorPickerPanel.svelte +23 -20
  34. package/dist/form/color_picker/ColorPickerPanel.svelte.d.ts +5 -18
  35. package/dist/form/common_editor/CommonEditor.svelte +36 -5
  36. package/dist/form/common_editor/CommonPicker.svelte +11 -4
  37. package/dist/form/common_editor/CommonPopupEditor.svelte +11 -2
  38. package/dist/form/common_range_editor/CommonRangeEditor.svelte +11 -2
  39. package/dist/form/date_picker/DatePicker.svelte +1 -1
  40. package/dist/form/date_picker/DateTimePicker.svelte +1 -1
  41. package/dist/form/date_picker/ScrollBar.svelte +20 -12
  42. package/dist/form/date_picker/ScrollBar.svelte.d.ts +4 -18
  43. package/dist/form/date_range/DateRangeEditor.svelte +11 -3
  44. package/dist/form/group_box/group-check-box/GroupCheckBox.svelte +6 -1
  45. package/dist/form/group_box/group-radio-box/GroupRadioBox.svelte +6 -1
  46. package/dist/form/image-files/ImageFilesField.svelte +51 -7
  47. package/dist/form/image-files/ImagePreview.svelte +8 -2
  48. package/dist/form/image-files/ImageRender.svelte +69 -11
  49. package/dist/form/input_options_select/InputOptionsSelect.svelte +10 -2
  50. package/dist/form/lookup_editor/LookupEditor.svelte +9 -2
  51. package/dist/form/number_editor/NumberEditor.svelte +2 -0
  52. package/dist/form/options_multi_select/OptionsMultiSelect.svelte +19 -3
  53. package/dist/form/options_select/OptionsSelect.svelte +15 -6
  54. package/dist/form/options_select/OptionsSelect.svelte.d.ts +39 -17
  55. package/dist/form/prompts_text_editor/PromptsTextEditor.svelte +12 -3
  56. package/dist/form/search_box/SearchBox.svelte +2 -1
  57. package/dist/form/switch/Switch.svelte +4 -4
  58. package/dist/form/text_editor/PasswordEditor.svelte +2 -1
  59. package/dist/form/text_editor/TextEditor.svelte +2 -1
  60. package/dist/form/time_editor/TimeEditor.svelte +2 -0
  61. package/dist/form/unit-number-editor/UnitNumberEditor.svelte +13 -2
  62. package/dist/form/unit-number-editor/UnitNumberEditor.svelte.d.ts +1 -0
  63. package/dist/general/button/Button.svelte +3 -0
  64. package/dist/general/button/Button.svelte.d.ts +1 -0
  65. package/dist/general/button/IconButton.svelte +3 -1
  66. package/dist/general/button/IconButton.svelte.d.ts +1 -0
  67. package/dist/general/button/TextButton.svelte +3 -0
  68. package/dist/general/button/TextButton.svelte.d.ts +1 -0
  69. package/dist/general/icon/Icon.svelte +18 -1
  70. package/dist/general/tag/Tag.svelte +9 -1
  71. package/dist/navigation/nav_menu/NavigatorMenu.svelte +2 -2
  72. package/dist/navigation/nav_menu/NavigatorMenuItem.svelte +10 -1
  73. package/dist/navigation/navigator/Navigator.svelte +17 -17
  74. package/dist/navigation/page-stack/PageStack.svelte +160 -0
  75. package/dist/navigation/page-stack/PageStack.svelte.d.ts +24 -0
  76. package/dist/navigation/page-stack/PageStackContext.d.ts +25 -0
  77. package/dist/navigation/page-stack/PageStackContext.js +12 -0
  78. package/dist/navigation/page-stack/PageStackFrame.svelte +24 -0
  79. package/dist/navigation/page-stack/PageStackFrame.svelte.d.ts +11 -0
  80. package/dist/navigation/page-stack/README.md +154 -0
  81. package/dist/navigation/page-stack/README_CN.md +154 -0
  82. package/dist/navigation/page-stack/index.d.ts +6 -0
  83. package/dist/navigation/page-stack/index.js +4 -0
  84. package/dist/navigation/pagination/Pagination.svelte +114 -14
  85. package/dist/navigation/tabs/Tabs.svelte +42 -10
  86. package/dist/navigation/tabs/Tabs.svelte.d.ts +2 -2
  87. package/dist/overlay/common/FloatingPanel.svelte +3 -11
  88. package/dist/overlay/common/FullscreenOverlay.svelte +27 -3
  89. package/dist/overlay/common/FullscreenOverlay.svelte.d.ts +6 -27
  90. package/dist/overlay/common/ModalPopover.svelte +18 -2
  91. package/dist/overlay/common/Popover.svelte +56 -57
  92. package/dist/overlay/common/Popover.svelte.d.ts +1 -5
  93. package/dist/overlay/common/escapeClose.d.ts +28 -0
  94. package/dist/overlay/common/escapeClose.js +47 -0
  95. package/dist/overlay/common/focusTrap.d.ts +8 -0
  96. package/dist/overlay/common/focusTrap.js +83 -0
  97. package/dist/overlay/common/mountSingleton.d.ts +27 -0
  98. package/dist/overlay/common/mountSingleton.js +45 -0
  99. package/dist/overlay/common/outsideClick.d.ts +28 -0
  100. package/dist/overlay/common/outsideClick.js +20 -0
  101. package/dist/overlay/common/scrollLock.d.ts +8 -0
  102. package/dist/overlay/common/scrollLock.js +49 -0
  103. package/dist/overlay/context-menu/ContextMenu.svelte.js +2 -15
  104. package/dist/overlay/context-menu/ContextMenuPanel.svelte +13 -1
  105. package/dist/overlay/dialog/Dialog.svelte +46 -29
  106. package/dist/overlay/dialog/DialogManager.svelte.js +7 -9
  107. package/dist/overlay/drawer/Drawer.svelte +30 -3
  108. package/dist/overlay/indicator/Indicator.svelte.js +2 -15
  109. package/dist/overlay/indicator/IndicatorPanel.svelte +4 -1
  110. package/dist/overlay/message-box/MessageBox.svelte.js +2 -15
  111. package/dist/overlay/message-box/MessageBoxPanel.svelte +19 -3
  112. package/dist/overlay/toast/Toast.svelte.js +2 -15
  113. package/dist/overlay/toast/ToastPanel.svelte +1 -1
  114. package/dist/overlay/tooltip/Tooltip.svelte +1 -1
  115. package/dist/ticatec-uniface-web.css +102 -7
  116. package/dist/types.d.ts +4 -3
  117. package/docs/components/README.md +133 -0
  118. package/docs/components/accordion/README.md +60 -0
  119. package/docs/components/accordion/example.svelte +7 -0
  120. package/docs/components/action-bar/README.md +114 -0
  121. package/docs/components/action-bar/example.svelte +7 -0
  122. package/docs/components/app-top-bar/README.md +60 -0
  123. package/docs/components/app-top-bar/example.svelte +9 -0
  124. package/docs/components/attachment-files/README.md +332 -0
  125. package/docs/components/attachment-files/example.svelte +16 -0
  126. package/docs/components/box/README.md +63 -0
  127. package/docs/components/box/example.svelte +10 -0
  128. package/docs/components/breadcrumbs/README.md +86 -0
  129. package/docs/components/breadcrumbs/example.svelte +11 -0
  130. package/docs/components/button/README.md +103 -0
  131. package/docs/components/button/example.svelte +10 -0
  132. package/docs/components/card/README.md +113 -0
  133. package/docs/components/card/example.svelte +10 -0
  134. package/docs/components/cascade-options-select/README.md +162 -0
  135. package/docs/components/cascade-options-select/example.svelte +18 -0
  136. package/docs/components/checkbox/README.md +103 -0
  137. package/docs/components/checkbox/example.svelte +15 -0
  138. package/docs/components/classic-layout/README.md +76 -0
  139. package/docs/components/classic-layout/example.svelte +16 -0
  140. package/docs/components/color-picker/README.md +132 -0
  141. package/docs/components/color-picker/example.svelte +16 -0
  142. package/docs/components/columns-layout/README.md +70 -0
  143. package/docs/components/columns-layout/example.svelte +12 -0
  144. package/docs/components/common-dialog/README.md +109 -0
  145. package/docs/components/common-dialog/example.svelte +12 -0
  146. package/docs/components/concise-data-table/README.md +307 -0
  147. package/docs/components/concise-data-table/example.svelte +16 -0
  148. package/docs/components/context-menu/README.md +99 -0
  149. package/docs/components/context-menu/example.svelte +10 -0
  150. package/docs/components/criteria-field/README.md +69 -0
  151. package/docs/components/criteria-field/example.svelte +9 -0
  152. package/docs/components/data-table/README.md +365 -0
  153. package/docs/components/data-table/example.svelte +23 -0
  154. package/docs/components/date-picker/README.md +136 -0
  155. package/docs/components/date-picker/example.svelte +16 -0
  156. package/docs/components/date-range/README.md +122 -0
  157. package/docs/components/date-range/example.svelte +15 -0
  158. package/docs/components/date-time-picker/README.md +142 -0
  159. package/docs/components/date-time-picker/example.svelte +16 -0
  160. package/docs/components/dialog/README.md +174 -0
  161. package/docs/components/dialog/example.svelte +13 -0
  162. package/docs/components/dialog-board/README.md +41 -0
  163. package/docs/components/dialog-board/example.svelte +5 -0
  164. package/docs/components/drawer/README.md +70 -0
  165. package/docs/components/drawer/example.svelte +12 -0
  166. package/docs/components/flex-form/README.md +55 -0
  167. package/docs/components/flex-form/example.svelte +7 -0
  168. package/docs/components/flex-row-form/README.md +56 -0
  169. package/docs/components/flex-row-form/example.svelte +7 -0
  170. package/docs/components/form-field/README.md +84 -0
  171. package/docs/components/form-field/example.svelte +10 -0
  172. package/docs/components/full-screen-overlay/README.md +66 -0
  173. package/docs/components/full-screen-overlay/example.svelte +11 -0
  174. package/docs/components/grid-form/README.md +75 -0
  175. package/docs/components/grid-form/example.svelte +9 -0
  176. package/docs/components/group-check-box/README.md +147 -0
  177. package/docs/components/group-check-box/example.svelte +21 -0
  178. package/docs/components/group-radio-box/README.md +144 -0
  179. package/docs/components/group-radio-box/example.svelte +21 -0
  180. package/docs/components/header-layout/README.md +65 -0
  181. package/docs/components/header-layout/example.svelte +12 -0
  182. package/docs/components/icon/README.md +87 -0
  183. package/docs/components/icon/example.svelte +9 -0
  184. package/docs/components/icon-button/README.md +91 -0
  185. package/docs/components/icon-button/example.svelte +10 -0
  186. package/docs/components/image-files/README.md +174 -0
  187. package/docs/components/image-files/example.svelte +19 -0
  188. package/docs/components/indicator/README.md +53 -0
  189. package/docs/components/indicator/example.svelte +14 -0
  190. package/docs/components/input-options-select/README.md +163 -0
  191. package/docs/components/input-options-select/example.svelte +16 -0
  192. package/docs/components/list-box/ListItem.svelte +14 -0
  193. package/docs/components/list-box/README.md +221 -0
  194. package/docs/components/list-box/example.svelte +61 -0
  195. package/docs/components/lookup-editor/README.md +137 -0
  196. package/docs/components/lookup-editor/example.svelte +16 -0
  197. package/docs/components/memo-editor/README.md +143 -0
  198. package/docs/components/memo-editor/example.svelte +16 -0
  199. package/docs/components/message-box/README.md +68 -0
  200. package/docs/components/message-box/example.svelte +10 -0
  201. package/docs/components/navigator/README.md +75 -0
  202. package/docs/components/navigator/example.svelte +13 -0
  203. package/docs/components/navigator-menu/README.md +113 -0
  204. package/docs/components/navigator-menu/example.svelte +10 -0
  205. package/docs/components/number-editor/README.md +144 -0
  206. package/docs/components/number-editor/example.svelte +16 -0
  207. package/docs/components/number-range/README.md +116 -0
  208. package/docs/components/number-range/example.svelte +15 -0
  209. package/docs/components/options-multi-select/README.md +161 -0
  210. package/docs/components/options-multi-select/example.svelte +20 -0
  211. package/docs/components/options-select/README.md +160 -0
  212. package/docs/components/options-select/example.svelte +21 -0
  213. package/docs/components/page/README.md +77 -0
  214. package/docs/components/page/example.svelte +10 -0
  215. package/docs/components/pagination/README.md +88 -0
  216. package/docs/components/pagination/example.svelte +10 -0
  217. package/docs/components/pagination-panel/README.md +120 -0
  218. package/docs/components/pagination-panel/example.svelte +16 -0
  219. package/docs/components/popup-hint/README.md +44 -0
  220. package/docs/components/popup-hint/example.svelte +5 -0
  221. package/docs/components/progress-bar/README.md +64 -0
  222. package/docs/components/progress-bar/example.svelte +8 -0
  223. package/docs/components/progress-step-bar/README.md +93 -0
  224. package/docs/components/progress-step-bar/example.svelte +7 -0
  225. package/docs/components/prompts-text-editor/README.md +146 -0
  226. package/docs/components/prompts-text-editor/example.svelte +17 -0
  227. package/docs/components/radio-button/README.md +121 -0
  228. package/docs/components/radio-button/example.svelte +18 -0
  229. package/docs/components/rows-layout/README.md +70 -0
  230. package/docs/components/rows-layout/example.svelte +12 -0
  231. package/docs/components/search-box/README.md +136 -0
  232. package/docs/components/search-box/example.svelte +16 -0
  233. package/docs/components/separator/README.md +44 -0
  234. package/docs/components/separator/example.svelte +7 -0
  235. package/docs/components/sidebar-layout/README.md +65 -0
  236. package/docs/components/sidebar-layout/example.svelte +12 -0
  237. package/docs/components/split/README.md +48 -0
  238. package/docs/components/split/example.svelte +8 -0
  239. package/docs/components/switch/README.md +77 -0
  240. package/docs/components/switch/example.svelte +11 -0
  241. package/docs/components/tabs/README.md +127 -0
  242. package/docs/components/tabs/example.svelte +22 -0
  243. package/docs/components/tag/README.md +63 -0
  244. package/docs/components/tag/example.svelte +8 -0
  245. package/docs/components/text-button/README.md +90 -0
  246. package/docs/components/text-button/example.svelte +9 -0
  247. package/docs/components/text-editor/README.md +147 -0
  248. package/docs/components/text-editor/example.svelte +16 -0
  249. package/docs/components/time-editor/README.md +130 -0
  250. package/docs/components/time-editor/example.svelte +16 -0
  251. package/docs/components/toast/README.md +52 -0
  252. package/docs/components/toast/example.svelte +9 -0
  253. package/docs/components/tooltip/README.md +44 -0
  254. package/docs/components/tooltip/example.svelte +5 -0
  255. package/docs/components/transfer/README.md +109 -0
  256. package/docs/components/transfer/example.svelte +13 -0
  257. package/docs/components/tree-view/README.md +163 -0
  258. package/docs/components/tree-view/example.svelte +26 -0
  259. package/docs/components/unit-number-editor/README.md +192 -0
  260. package/docs/components/unit-number-editor/example.svelte +18 -0
  261. package/package.json +15 -7
@@ -60,16 +60,31 @@
60
60
  window.removeEventListener('mousemove', onMouseMove);
61
61
  window.removeEventListener('mouseup', onMouseUp);
62
62
  }
63
+
64
+ const handleHeaderKeyDown = (col: DataColumn) => (e: KeyboardEvent) => {
65
+ if (col.compareFunction != null && (e.key === 'Enter' || e.key === ' ')) {
66
+ e.preventDefault();
67
+ handleCellClick?.(col);
68
+ }
69
+ };
63
70
  </script>
64
71
 
65
72
  <div class="header-row" style="height: {headerHeight}px">
66
73
  <div style="left: {-scrollLeft}px; width: {width}px">
67
74
  {#each dataCols ?? [] as col, index (index)}
68
75
  <div class="col-{index} data-cell" class:sortable={col.compareFunction != null} class:whitespace={hasWhitespace}>
76
+ <!-- role/tabindex are only ever both set together (sortable columns);
77
+ svelte-check can't verify that pairing statically across the ternary. -->
78
+ <!-- svelte-ignore a11y_no_noninteractive_tabindex -->
69
79
  <div
70
80
  class:sortable={col.compareFunction != null}
71
81
  onclick={() => handleCellClick?.(col)}
72
- aria-hidden="true"
82
+ onkeydown={handleHeaderKeyDown(col)}
83
+ role={col.compareFunction != null ? 'button' : undefined}
84
+ tabindex={col.compareFunction != null ? 0 : undefined}
85
+ aria-sort={col.field === orderColumn?.field
86
+ ? (orderDirection === OrderDirection.Ascending ? 'ascending' : 'descending')
87
+ : undefined}
73
88
  class="vertical-center"
74
89
  >
75
90
  <span>{col.text}</span>
@@ -85,7 +100,8 @@
85
100
  <div
86
101
  class="header-cell-divider"
87
102
  class:resizer={col.resizable}
88
- aria-hidden="true"
103
+ role={col.resizable ? 'separator' : undefined}
104
+ aria-orientation={col.resizable ? 'vertical' : undefined}
89
105
  onmousedown={handleResizeMouseDown(col)}
90
106
  ></div>
91
107
  </div>
@@ -17,10 +17,10 @@
17
17
  return value ?? '';
18
18
  });
19
19
 
20
- let escapeHTML = $derived(column.escapeHTML == true);
20
+ let renderAsHtml = $derived((column.renderHTML ?? column.escapeHTML) == true);
21
21
  </script>
22
22
 
23
- {#if escapeHTML == true}
23
+ {#if renderAsHtml == true}
24
24
  {@html text}
25
25
  {:else}
26
26
  <span>{text}</span>
@@ -122,12 +122,12 @@
122
122
  {#each files as file (file)}
123
123
  <FileRender {file} {readonly} onRemove={removeFile}/>
124
124
  {/each}
125
+ {#if canUpload}
126
+ <button type="button" class="editor-action-icon" aria-label="Upload file" onclick={triggerUpload}>
127
+ <i class="icon_google_file_upload" aria-hidden="true"></i>
128
+ </button>
129
+ {/if}
125
130
  </div>
126
- {#if canUpload}
127
- <button type="button" class="editor-action-icon" aria-label="Upload file" onclick={triggerUpload}>
128
- <i class="icon_google_file_upload" aria-hidden="true"></i>
129
- </button>
130
- {/if}
131
131
  </div>
132
132
  </FormEditor>
133
133
 
@@ -146,25 +146,25 @@
146
146
  <style>
147
147
  .uniface-attachment-editor {
148
148
  display: flex;
149
- flex-direction: row;
150
- align-items: center;
151
149
  width: 100%;
152
150
  outline: none;
153
151
  }
154
152
 
155
153
  .files-field {
156
- flex: 1 1 auto;
157
154
  display: flex;
158
155
  flex-direction: column;
159
156
  gap: 4px;
157
+ width: 100%;
160
158
  min-width: 0;
159
+ height: 96px;
160
+ overflow-y: auto;
161
+ box-sizing: border-box;
161
162
  }
162
163
 
163
164
  .editor-action-icon {
164
165
  flex: 0 0 auto;
165
166
  cursor: pointer;
166
167
  padding: 4px;
167
- margin-right: 8px;
168
168
  border-radius: 4px;
169
169
  display: flex;
170
170
  align-items: center;
@@ -44,7 +44,7 @@
44
44
  {/if}
45
45
  </div>
46
46
  {#if !readonly}
47
- <button class="remove-btn" onclick={removeFile} aria-label="remove file">
47
+ <button type="button" class="remove-btn" onclick={removeFile} aria-label="remove file">
48
48
  <i class="icon_google_delete" aria-hidden="true"></i>
49
49
  </button>
50
50
  {/if}
@@ -117,8 +117,12 @@
117
117
  });
118
118
  </script>
119
119
  <ModalPopover {canClose} {theme} bind:visible>
120
+ <!-- onclick only stops propagation to the modal's outside-click handler; the
121
+ real controls (Button, file input) inside carry their own semantics. -->
122
+ <!-- svelte-ignore a11y_click_events_have_key_events -->
123
+ <!-- svelte-ignore a11y_no_noninteractive_element_interactions -->
120
124
  <div class="uniface-file-upload-panel" class:highlight={dragActive} ondragover={handleDragOver} ondragleave={handleDragLeave}
121
- ondrop={handleDrop} onclick={handleMouseClick} aria-hidden="true">
125
+ ondrop={handleDrop} onclick={handleMouseClick} role="group" aria-label={btnPickup}>
122
126
  <div class="file-upload-contents">
123
127
  <div style="position: absolute; top: 0; width: 0; overflow: hidden">
124
128
  <input bind:this={fileInput} type="file" {accept} multiple={maxFiles > 1} onchange={handleFilePickup}/>
@@ -65,7 +65,14 @@
65
65
  }, 50);
66
66
  };
67
67
 
68
- const mh = $derived(` width: 400px; height: ${menu$height}px`);
68
+ // Previously a flat "width: 400px" regardless of how many cascade levels
69
+ // (columns) were actually open — with box$style unset (columns had no
70
+ // default width of their own before this fix) or with 3+ levels open,
71
+ // that either squeezed columns illegibly narrow or clipped/scrolled
72
+ // content that didn't need to. Let the popover grow to fit however many
73
+ // columns are currently shown, capped so a very deep hierarchy still
74
+ // scrolls instead of overflowing the viewport.
75
+ const mh = $derived(`width: max-content; max-width: min(90vw, 700px); height: ${menu$height}px`);
69
76
  const textValue = $derived(
70
77
  selectedItems.length > 0
71
78
  ? selectedItems[selectedItems.length - 1][textField]
@@ -129,7 +136,8 @@
129
136
  bind:isOpen
130
137
  {theme} {value} {mandatory}
131
138
  clear={cleanData}
132
- {onfocus} {onblur}>
139
+ {onfocus} {onblur}
140
+ autoFit={false}>
133
141
  {#snippet popupLayer()}
134
142
  <div class="cascade-options-popover" style={mh}>
135
143
  <div style="height: 100%; position: relative">
@@ -23,13 +23,59 @@
23
23
  selectedItem = item;
24
24
  onSelect(item);
25
25
  }
26
+
27
+ const handleItemKeyDown = (item: any) => (e: KeyboardEvent) => {
28
+ if (e.key === 'Enter' || e.key === ' ') {
29
+ e.preventDefault();
30
+ handleItemClick(item)(e as unknown as MouseEvent);
31
+ }
32
+ }
26
33
  </script>
27
34
 
28
- <div class="cascade-column" style={box$style}>
35
+ <div class="cascade-column" style={box$style} role="listbox">
29
36
  {#each options as op (op[keyField])}
30
37
  <div class="option-item" class:selected={op[keyField] === (selectedItem ?? {})[keyField]}
31
- aria-hidden="true" onclick={handleItemClick(op)}>
38
+ role="option" tabindex="0" aria-selected={op[keyField] === (selectedItem ?? {})[keyField]}
39
+ onclick={handleItemClick(op)} onkeydown={handleItemKeyDown(op)}>
32
40
  <span>{op[textField]}</span>
33
41
  </div>
34
42
  {/each}
35
43
  </div>
44
+
45
+ <style>
46
+ /* Base sizing so a column looks correct even when the consumer doesn't
47
+ pass box$style — previously there was no default at all, so columns
48
+ had no width/overflow handling and collapsed unpredictably inside the
49
+ popover's flex row. box$style (inline style, applied after these
50
+ rules) can still override any of this per column. */
51
+ .cascade-column {
52
+ flex: 0 0 auto;
53
+ width: 140px;
54
+ height: 100%;
55
+ box-sizing: border-box;
56
+ overflow-y: auto;
57
+ overflow-x: hidden;
58
+ border-right: 1px solid var(--uniface-color-border-secondary);
59
+ }
60
+
61
+ .cascade-column:last-child {
62
+ border-right: none;
63
+ }
64
+
65
+ .option-item {
66
+ padding: 6px 12px;
67
+ cursor: pointer;
68
+ overflow: hidden;
69
+ text-overflow: ellipsis;
70
+ white-space: nowrap;
71
+ }
72
+
73
+ .option-item:hover {
74
+ background-color: var(--uniface-popover-item-color-surface-hover);
75
+ }
76
+
77
+ .option-item.selected {
78
+ background-color: var(--uniface-popover-item-color-surface-active);
79
+ color: var(--uniface-popover-item-color-active);
80
+ }
81
+ </style>
@@ -3,14 +3,25 @@
3
3
 
4
4
  import i18nRes from "../../i18nRes";
5
5
 
6
- export let initialColor = "#ffffff";
7
- export let showHex = true;
8
- export let showRgb = false;
9
- export let swatches: Array<any> = [];
6
+ interface Props {
7
+ initialColor?: string;
8
+ showHex?: boolean;
9
+ showRgb?: boolean;
10
+ swatches?: Array<any>;
11
+ onchange?: (color: string) => void;
12
+ }
13
+
14
+ let {initialColor = "#ffffff", showHex = true, showRgb = false, swatches = [], onchange}: Props = $props();
10
15
 
11
- let selectedColor = initialColor;
12
- let rgbValues = hexToRgb(initialColor);
16
+ // Neutral initial value + effect-driven sync (rather than $state(initialColor))
17
+ // avoids implying initialColor is captured only once; the effect keeps
18
+ // selectedColor in sync whenever the prop changes later.
19
+ let selectedColor = $state('#ffffff');
20
+ let rgbValues = $derived(hexToRgb(selectedColor));
13
21
 
22
+ $effect(() => {
23
+ selectedColor = initialColor;
24
+ });
14
25
 
15
26
  // Convert hex to RGB
16
27
  function hexToRgb(hex: string) {
@@ -22,24 +33,15 @@
22
33
  } : { r: 0, g: 0, b: 0 };
23
34
  }
24
35
 
25
- // Emit change event when color changes
36
+ // selectedColor is already updated by bind:value before this fires
26
37
  function handleColorChange(event: Event) {
27
- selectedColor = "0x000000"; //event.target?.value;
28
- rgbValues = hexToRgb(selectedColor);
29
- // dispatch('change', {
30
- // hex: selectedColor,
31
- // rgb: rgbValues
32
- // });
38
+ onchange?.(selectedColor);
33
39
  }
34
40
 
35
41
  // Select a swatch
36
42
  function selectSwatch(color: any) {
37
43
  selectedColor = color;
38
- rgbValues = hexToRgb(selectedColor);
39
- // dispatch('change', {
40
- // hex: selectedColor,
41
- // rgb: rgbValues
42
- // });
44
+ onchange?.(selectedColor);
43
45
  }
44
46
  </script>
45
47
 
@@ -53,7 +55,7 @@
53
55
  id="color-input"
54
56
  type="color"
55
57
  bind:value={selectedColor}
56
- on:change={handleColorChange}
58
+ onchange={handleColorChange}
57
59
  />
58
60
  <div
59
61
  class="color-preview"
@@ -77,9 +79,10 @@
77
79
  <div class="swatches">
78
80
  {#each swatches as swatch}
79
81
  <button
82
+ type="button"
80
83
  class="swatch"
81
84
  style="background-color: {swatch};"
82
- on:click={() => selectSwatch(swatch)}
85
+ onclick={() => selectSwatch(swatch)}
83
86
  aria-label={`Select color ${swatch}`}
84
87
  class:selected={selectedColor === swatch}
85
88
  ></button>
@@ -1,23 +1,10 @@
1
- interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
2
- new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
3
- $$bindings?: Bindings;
4
- } & Exports;
5
- (internal: unknown, props: Props & {
6
- $$events?: Events;
7
- $$slots?: Slots;
8
- }): Exports & {
9
- $set?: any;
10
- $on?: any;
11
- };
12
- z_$$bindings?: Bindings;
13
- }
14
- declare const ColorPickerPanel: $$__sveltets_2_IsomorphicComponent<{
1
+ interface Props {
15
2
  initialColor?: string;
16
3
  showHex?: boolean;
17
4
  showRgb?: boolean;
18
5
  swatches?: Array<any>;
19
- }, {
20
- [evt: string]: CustomEvent<any>;
21
- }, {}, {}, string>;
22
- type ColorPickerPanel = InstanceType<typeof ColorPickerPanel>;
6
+ onchange?: (color: string) => void;
7
+ }
8
+ declare const ColorPickerPanel: import("svelte").Component<Props, {}, "">;
9
+ type ColorPickerPanel = ReturnType<typeof ColorPickerPanel>;
23
10
  export default ColorPickerPanel;
@@ -50,11 +50,35 @@
50
50
  if (disabled) return;
51
51
  focus();
52
52
  }
53
+
54
+ // Only intercept mousedowns that land on the wrapper's own decorative chrome
55
+ // (padding, prefix/suffix, icons) — preventing their default avoids a
56
+ // blur-then-refocus flicker when clicking near the control. A mousedown that
57
+ // originates on the actual form control (input/textarea, including the one
58
+ // rendered by NumberInput.svelte) must NOT be intercepted: preventDefault()
59
+ // there cancels the browser's native text-selection-start behavior for that
60
+ // same event, even though this listener runs on an ancestor during bubbling —
61
+ // that's what made it impossible to drag-select or double-click-select text
62
+ // inside every CommonEditor-based input (SearchBox, TextEditor, PasswordEditor,
63
+ // NumberEditor, TimeEditor, and anything built on CommonPopupEditor).
64
+ const handleContainerMouseDown = (e: MouseEvent) => {
65
+ const tag = (e.target as HTMLElement).tagName;
66
+ if (tag !== 'INPUT' && tag !== 'TEXTAREA') {
67
+ e.preventDefault();
68
+ }
69
+ };
53
70
  </script>
54
71
 
55
72
  <FormEditor {theme} {tooltip} {error} {style} {readonly} {disabled} {compact} {variant}>
56
- <div class="uniface-common-editor" role="textbox" bind:this={container} aria-hidden="true" tabindex="-1" {style}
57
- onmousedown={(e: MouseEvent)=>{e.preventDefault()}} onclick={handleContainerClick}>
73
+ <!-- Decorative flex wrapper only: the real interactive control is the
74
+ <input>/children snippet rendered inside, which carries its own
75
+ semantics — this div must not steal or hide them via role/aria-hidden.
76
+ onclick here only forwards focus to that inner control, it's not an
77
+ independent action, so no interactive role/keyboard handler applies. -->
78
+ <!-- svelte-ignore a11y_click_events_have_key_events -->
79
+ <!-- svelte-ignore a11y_no_static_element_interactions -->
80
+ <div class="uniface-common-editor" bind:this={container} {style}
81
+ onmousedown={handleContainerMouseDown} onclick={handleContainerClick}>
58
82
  {#if leadingIcon}
59
83
  <div class="editor-embed-icon" style="flex: 0 0 auto;">
60
84
  {@render leadingIcon()}
@@ -69,9 +93,16 @@
69
93
  {:else}
70
94
  <div class={input$class} style="position: relative; flex: 1 1 auto">
71
95
  {@render children()}
72
- {#if textValue && canClean}
73
- <div class="clean-icon">
74
- <i class="icon_google_clear" aria-hidden="true" onmousedown={(e: MouseEvent)=>{e.preventDefault()}} onclick={clear}></i>
96
+ {#if canClean}
97
+ <!-- Reserved unconditionally (not gated on textValue) so
98
+ .uniface-common-editor:has(.clean-icon)'s input
99
+ padding-right in uniface-form-editor.scss stays
100
+ constant — otherwise the editor visibly grows/shifts
101
+ the moment text is first entered. -->
102
+ <div class="clean-icon" class:has-value={textValue}>
103
+ <i class="icon_google_clear" role="button" tabindex={textValue ? 0 : -1} aria-label="Clear"
104
+ onmousedown={(e: MouseEvent)=>{e.preventDefault()}} onclick={textValue ? clear : undefined}
105
+ onkeydown={(e: KeyboardEvent) => { if (textValue && (e.key === 'Enter' || e.key === ' ')) { e.preventDefault(); clear?.(); } }}></i>
75
106
  </div>
76
107
  {/if}
77
108
  </div>
@@ -70,7 +70,6 @@
70
70
  let editorElement: HTMLElement | undefined = $state();
71
71
  let editor: HTMLDivElement | undefined = $state();
72
72
  let hasFocus = $state(false);
73
- let canClean = $derived(!mandatory && value != null);
74
73
 
75
74
 
76
75
  const handleFocus = (event: FocusEvent) => {
@@ -158,9 +157,17 @@
158
157
  {#if children}
159
158
  {@render children()}
160
159
  {/if}
161
- {#if textValue && canClean}
162
- <div class="clean-icon">
163
- <i class="icon_google_clear" role="none" onclick={doClean}></i>
160
+ {#if !mandatory}
161
+ <!-- Space is reserved (and input padding-right adjusted via
162
+ .uniface-common-picker:has(.clean-icon) in
163
+ uniface-form-editor.scss) whenever clearing is allowed
164
+ at all, not only once a value is picked — otherwise the
165
+ whole picker visibly grows/shifts by that padding the
166
+ moment a value is first selected. Visibility of the
167
+ glyph itself still depends on there being something to
168
+ clear. -->
169
+ <div class="clean-icon" class:has-value={textValue}>
170
+ <i class="icon_google_clear" role="none" onclick={textValue ? doClean : undefined}></i>
164
171
  </div>
165
172
  {/if}
166
173
  </div>
@@ -18,6 +18,7 @@
18
18
 
19
19
  let {
20
20
  variant,
21
+ theme,
21
22
  compact = false,
22
23
  disabled = false,
23
24
  readonly = false,
@@ -57,11 +58,18 @@
57
58
  showPopup = false;
58
59
  }
59
60
 
61
+ const handleTriggerKeyDown = (e: KeyboardEvent) => {
62
+ if (e.key === 'Enter' || e.key === ' ') {
63
+ e.preventDefault();
64
+ openPopup();
65
+ }
66
+ };
60
67
  </script>
61
68
 
62
69
  <CommonEditor
63
70
  bind:this={editorRef}
64
71
  {variant}
72
+ {theme}
65
73
  {compact}
66
74
  {style}
67
75
  {tooltip}
@@ -76,12 +84,13 @@
76
84
 
77
85
  {#snippet trailingIcon()}
78
86
  {#if !disabled && !readonly}
79
- <i class="icon_google_arrow_drop_down" aria-hidden="true" onclick={openPopup}></i>
87
+ <i class="icon_google_arrow_drop_down" role="button" tabindex="0" aria-label="Open" aria-expanded={showPopup}
88
+ onclick={openPopup} onkeydown={handleTriggerKeyDown}></i>
80
89
  {/if}
81
90
  {/snippet}
82
91
 
83
92
  {#if showPopup && getTargetElement()}
84
- <Popover target={getTargetElement()} {autoFit} align="right" onclose={closePopup}>
93
+ <Popover target={getTargetElement()} {autoFit} {theme} align="right" onclose={closePopup}>
85
94
  {#if popupLayer}
86
95
  {@render popupLayer()}
87
96
  {/if}
@@ -40,6 +40,13 @@
40
40
  toChild,
41
41
  actionIcon
42
42
  }: Props = $props();
43
+
44
+ const handleCleanKeyDown = (handler: () => void) => (e: KeyboardEvent) => {
45
+ if (e.key === 'Enter' || e.key === ' ') {
46
+ e.preventDefault();
47
+ handler();
48
+ }
49
+ };
43
50
  </script>
44
51
 
45
52
  <FormEditor {variant} {compact} {disabled} {readonly} {error} {tooltip} {theme} {style} {className}>
@@ -48,14 +55,16 @@
48
55
  <div class="range-cell">
49
56
  {@render fromChild()}
50
57
  <div class="clean-icon" class:visible={showFromClean}>
51
- <i class="icon_google_clear" aria-hidden="true" onclick={cleanFrom}></i>
58
+ <i class="icon_google_clear" role="button" tabindex={showFromClean ? 0 : -1} aria-label="Clear"
59
+ onclick={cleanFrom} onkeydown={handleCleanKeyDown(cleanFrom)}></i>
52
60
  </div>
53
61
  </div>
54
62
  <div class="divider"></div>
55
63
  <div class="range-cell">
56
64
  {@render toChild()}
57
65
  <div class="clean-icon" class:visible={showToClean}>
58
- <i class="icon_google_clear" aria-hidden="true" onclick={cleanTo}></i>
66
+ <i class="icon_google_clear" role="button" tabindex={showToClean ? 0 : -1} aria-label="Clear"
67
+ onclick={cleanTo} onkeydown={handleCleanKeyDown(cleanTo)}></i>
59
68
  </div>
60
69
  </div>
61
70
  </div>
@@ -59,7 +59,7 @@
59
59
  bind:isOpen autoFit={false} {textValue} {readonly} {disabled}>
60
60
  {#snippet popupLayer()}
61
61
  <div class="date-popover">
62
- <Calendar value={value} {min} {max} onselect={handleCalendarSelect}/>
62
+ <Calendar value={value} {min} {max} onchange={handleCalendarSelect}/>
63
63
  </div>
64
64
  {/snippet}
65
65
  </CommonPicker>
@@ -123,7 +123,7 @@
123
123
  <Calendar
124
124
  style="border-right: 1px solid var(--uniface-inside-border-color, #f0f0f0)"
125
125
  value={currentValue}
126
- onselect={handleCalendarSelect}
126
+ onchange={handleCalendarSelect}
127
127
  {min} {max}/>
128
128
  <TimePanel style="width: 120px" value={currentValue} {precision} onchange={handleTimeChange}/>
129
129
  </div>
@@ -2,12 +2,16 @@
2
2
 
3
3
  import type {OnChangeHandler} from "../../types";
4
4
 
5
- export let value: number;
6
- export let mode: 24 | 60 = 60;
7
- export let enable: boolean = true;
8
- export let onchange: OnChangeHandler<number> = null as unknown as OnChangeHandler<number>;
5
+ interface Props {
6
+ value: number;
7
+ mode?: 24 | 60;
8
+ enable?: boolean;
9
+ onchange?: OnChangeHandler<number>;
10
+ }
11
+
12
+ let {value = $bindable(), mode = 60, enable = true, onchange}: Props = $props();
9
13
 
10
- let list: Array<any> = [];
14
+ let list: Array<any> = $state([]);
11
15
 
12
16
  const decValue = () => {
13
17
  if (enable) {
@@ -75,25 +79,29 @@
75
79
 
76
80
  let timer: any;
77
81
 
78
- $:resetList();
82
+ $effect(() => {
83
+ void value;
84
+ void mode;
85
+ resetList();
86
+ });
79
87
 
80
88
  </script>
81
- <div class="scroll-bar" on:wheel={handleMouseWheel}>
89
+ <div class="scroll-bar" onwheel={handleMouseWheel}>
82
90
  <div class="action-bar">
83
91
  <div class="arrow-up" class:disabled={!enable}>
84
- <i class="icon_google_keyboard_arrow_up" on:click={decValue} on:keydown={handleKeyDown(decValue)} on:dragstart={(e)=>{e.preventDefault()}}
85
- on:mousedown={handleMouseDown(-1)} on:mouseup={handleMouseUp} on:mouseleave={handleMouseUp}
92
+ <i class="icon_google_keyboard_arrow_up" onclick={decValue} onkeydown={handleKeyDown(decValue)} ondragstart={(e)=>{e.preventDefault()}}
93
+ onmousedown={handleMouseDown(-1)} onmouseup={handleMouseUp} onmouseleave={handleMouseUp}
86
94
  role="button" tabindex="0" aria-label="Decrease value"></i>
87
95
  </div>
88
96
  </div>
89
97
  {#each list as v}
90
- <div style={!enable && v!= value ? "visibility: hidden; " : ""} class="digital-block" on:click={()=>{handleDigitalClick(v)}} on:keydown={handleKeyDown(() => handleDigitalClick(v))} class:inactive={v!=value}
98
+ <div style={!enable && v!= value ? "visibility: hidden; " : ""} class="digital-block" onclick={()=>{handleDigitalClick(v)}} onkeydown={handleKeyDown(() => handleDigitalClick(v))} class:inactive={v!=value}
91
99
  role="button" tabindex="0" aria-label="Select {v}"><span>{v}</span></div>
92
100
  {/each}
93
101
  <div class="action-bar">
94
102
  <div class="arrow-down" class:disabled={!enable}>
95
- <i class="icon_google_keyboard_arrow_down" on:click={incValue} on:keydown={handleKeyDown(incValue)} on:dragstart={(e)=>{e.preventDefault()}}
96
- on:mousedown={handleMouseDown(1)} on:mouseup={handleMouseUp} on:mouseleave={handleMouseUp}
103
+ <i class="icon_google_keyboard_arrow_down" onclick={incValue} onkeydown={handleKeyDown(incValue)} ondragstart={(e)=>{e.preventDefault()}}
104
+ onmousedown={handleMouseDown(1)} onmouseup={handleMouseUp} onmouseleave={handleMouseUp}
97
105
  role="button" tabindex="0" aria-label="Increase value"></i>
98
106
  </div>
99
107
  </div>
@@ -1,24 +1,10 @@
1
1
  import type { OnChangeHandler } from "../../types";
2
- interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
3
- new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
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;
14
- }
15
- declare const ScrollBar: $$__sveltets_2_IsomorphicComponent<{
2
+ interface Props {
16
3
  value: number;
17
4
  mode?: 24 | 60;
18
5
  enable?: boolean;
19
6
  onchange?: OnChangeHandler<number>;
20
- }, {
21
- [evt: string]: CustomEvent<any>;
22
- }, {}, {}, string>;
23
- type ScrollBar = InstanceType<typeof ScrollBar>;
7
+ }
8
+ declare const ScrollBar: import("svelte").Component<Props, {}, "value">;
9
+ type ScrollBar = ReturnType<typeof ScrollBar>;
24
10
  export default ScrollBar;
@@ -80,6 +80,13 @@
80
80
  toValue = normalizeValue(value.toDate(), false);
81
81
  isOpen = false;
82
82
  };
83
+
84
+ const handleIconKeyDown = (e: KeyboardEvent) => {
85
+ if (e.key === 'Enter' || e.key === ' ') {
86
+ e.preventDefault();
87
+ showPopover();
88
+ }
89
+ };
83
90
  </script>
84
91
 
85
92
  <div bind:this={rootElement}>
@@ -91,7 +98,8 @@
91
98
  <input style="width: 100%; text-align: center" readonly onclick={showPopover} value={textTo}/>
92
99
  {/snippet}
93
100
  {#snippet actionIcon()}
94
- <i class="icon_google_event_note action-icon" aria-hidden="true" onclick={showPopover}></i>
101
+ <i class="icon_google_event_note action-icon" role="button" tabindex="0" aria-label="Open date range picker"
102
+ onclick={showPopover} onkeydown={handleIconKeyDown}></i>
95
103
  {/snippet}
96
104
  </CommonRangeEditor>
97
105
 
@@ -101,12 +109,12 @@
101
109
  <Calendar
102
110
  style="border-right: 1px solid #f0f0f0"
103
111
  value={fromValue}
104
- onselect={handleFormCalendarSelect}
112
+ onchange={handleFormCalendarSelect}
105
113
  {min}
106
114
  max={maxFrom}/>
107
115
  <Calendar
108
116
  value={toValue}
109
- onselect={handleToCalendarSelect}
117
+ onchange={handleToCalendarSelect}
110
118
  min={minTo}
111
119
  {max}/>
112
120
  </div>