@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
@@ -4,6 +4,7 @@
4
4
 
5
5
  interface Props {
6
6
  type?: ButtonType;
7
+ htmlType?: 'button' | 'submit' | 'reset';
7
8
  label?: string;
8
9
  variant?: 'plain' | 'round' | '';
9
10
  disabled?: boolean;
@@ -20,6 +21,7 @@
20
21
 
21
22
  let {
22
23
  type = 'default',
24
+ htmlType = 'button',
23
25
  label = '',
24
26
  variant = '',
25
27
  disabled = false,
@@ -47,6 +49,7 @@
47
49
  <!-- autofocus is an explicit opt-in component API; consumers decide when initial focus is appropriate. -->
48
50
  <!-- svelte-ignore a11y_autofocus -->
49
51
  <button
52
+ type={htmlType}
50
53
  {style}
51
54
  class="uniface-button common-button {variant} {size} {type} {theme}"
52
55
  class:disabled={disabled}
@@ -2,6 +2,7 @@ import type { Snippet } from 'svelte';
2
2
  import type { ButtonType } from '../../types';
3
3
  interface Props {
4
4
  type?: ButtonType;
5
+ htmlType?: 'button' | 'submit' | 'reset';
5
6
  label?: string;
6
7
  variant?: 'plain' | 'round' | '';
7
8
  disabled?: boolean;
@@ -6,6 +6,7 @@
6
6
 
7
7
  interface Props {
8
8
  type?: ButtonType;
9
+ htmlType?: 'button' | 'submit' | 'reset';
9
10
  disabled?: boolean;
10
11
  size?: ButtonSize;
11
12
  style?: string;
@@ -18,6 +19,7 @@
18
19
 
19
20
  let {
20
21
  type = 'default',
22
+ htmlType = 'button',
21
23
  disabled = false,
22
24
  size = 'medium',
23
25
  style,
@@ -40,7 +42,7 @@
40
42
 
41
43
  </script>
42
44
 
43
- <button class="uniface-button icon-button {size} {type} {theme}" {style} class:disabled {disabled}
45
+ <button type={htmlType} class="uniface-button icon-button {size} {type} {theme}" {style} class:disabled {disabled}
44
46
  tabindex={disabled ? -1 : 0} data-tip={disabled ? null : tooltip} onclick={handleClick}>
45
47
  {#if children}
46
48
  {@render children()}
@@ -3,6 +3,7 @@ type ButtonType = 'default' | 'primary' | 'secondary' | 'third' | 'forth';
3
3
  type ButtonSize = 'big' | 'medium' | 'small';
4
4
  interface Props {
5
5
  type?: ButtonType;
6
+ htmlType?: 'button' | 'submit' | 'reset';
6
7
  disabled?: boolean;
7
8
  size?: ButtonSize;
8
9
  style?: string;
@@ -9,6 +9,7 @@
9
9
  size?: ButtonSize;
10
10
  label?: string;
11
11
  type?: ButtonType;
12
+ htmlType?: 'button' | 'submit' | 'reset';
12
13
  onclick?: (event: MouseEvent) => void;
13
14
  style?: string;
14
15
  theme?: string;
@@ -21,6 +22,7 @@
21
22
  size = 'medium',
22
23
  label = '',
23
24
  type = 'default',
25
+ htmlType = 'button',
24
26
  onclick = undefined,
25
27
  style = '',
26
28
  theme,
@@ -45,6 +47,7 @@
45
47
  </script>
46
48
 
47
49
  <button
50
+ type={htmlType}
48
51
  class="uniface-button text-button {size} {type} {theme}"
49
52
  {style}
50
53
  class:disabled
@@ -6,6 +6,7 @@ interface Props {
6
6
  size?: ButtonSize;
7
7
  label?: string;
8
8
  type?: ButtonType;
9
+ htmlType?: 'button' | 'submit' | 'reset';
9
10
  onclick?: (event: MouseEvent) => void;
10
11
  style?: string;
11
12
  theme?: string;
@@ -32,17 +32,34 @@
32
32
  respClick = true;
33
33
  }
34
34
  }
35
+
36
+ const isInteractive = $derived(onclick != null);
37
+
38
+ function handleKeyDown(e: KeyboardEvent) {
39
+ if (isInteractive && !disabled && (e.key === 'Enter' || e.key === ' ')) {
40
+ e.preventDefault();
41
+ handleClickEvent(e as unknown as MouseEvent);
42
+ }
43
+ }
35
44
  </script>
36
45
 
46
+ <!-- role/tabindex are only ever both set together when onclick is provided
47
+ (isInteractive); svelte-check can't verify that pairing statically. -->
48
+ <!-- svelte-ignore a11y_no_noninteractive_tabindex -->
37
49
  <div
38
50
  class="uniface-icon {theme} {className}"
39
51
  class:clickable={onclick!=null && !disabled}
40
52
  class:disabled={disabled}
41
53
  onmousedown={(event: MouseEvent) => {event.preventDefault();}}
42
54
  {style}
43
- aria-hidden="true"
55
+ role={isInteractive ? 'button' : undefined}
56
+ tabindex={isInteractive && !disabled ? 0 : undefined}
57
+ aria-disabled={isInteractive ? disabled : undefined}
58
+ aria-hidden={isInteractive ? undefined : true}
59
+ aria-label={isInteractive ? (tooltip || undefined) : undefined}
44
60
  data-tip={disabled ? null : tooltip || null}
45
61
  onclick={handleClickEvent}
62
+ onkeydown={handleKeyDown}
46
63
  >
47
64
  <i class={name}></i>
48
65
  </div>
@@ -34,13 +34,21 @@
34
34
  event.stopPropagation();
35
35
  }
36
36
 
37
+ const handleTagKeyDown = (event: KeyboardEvent) => {
38
+ if (event.key === 'Enter' || event.key === ' ') {
39
+ event.preventDefault();
40
+ ondelete?.(data?.id);
41
+ }
42
+ }
43
+
37
44
  </script>
38
45
 
39
46
  <div class="uniface-tag" {style} data-theme="{theme}">
40
47
  <div class="{size} {variant} {colorClass}" class:removable={removable}>
41
48
  <span>{text}</span>
42
49
  {#if removable}
43
- <i class="icon_google_clear uniface-remove-icon" aria-hidden="true" onclick={handleTagClick}></i>
50
+ <i class="icon_google_clear uniface-remove-icon" role="button" tabindex="0" aria-label="Remove {text}"
51
+ onclick={handleTagClick} onkeydown={handleTagKeyDown}></i>
44
52
  {/if}
45
53
  </div>
46
54
  </div>
@@ -114,7 +114,7 @@
114
114
  {:else}
115
115
  <nav bind:this={horizontalMenu} class="uniface-navigator-menu horizontal" {style} data-theme={theme || undefined}>
116
116
  {#if hasOverflow}
117
- <button class="scroll-button previous" aria-label="向左滚动菜单" disabled={!canScrollLeft} onclick={() => scrollMenu(-1)}>
117
+ <button type="button" class="scroll-button previous" aria-label="向左滚动菜单" disabled={!canScrollLeft} onclick={() => scrollMenu(-1)}>
118
118
  <i aria-hidden="true"></i>
119
119
  </button>
120
120
  {/if}
@@ -139,7 +139,7 @@
139
139
  </div>
140
140
  </div>
141
141
  {#if hasOverflow}
142
- <button class="scroll-button next" aria-label="向右滚动菜单" disabled={!canScrollRight} onclick={() => scrollMenu(1)}>
142
+ <button type="button" class="scroll-button next" aria-label="向右滚动菜单" disabled={!canScrollRight} onclick={() => scrollMenu(1)}>
143
143
  <i aria-hidden="true"></i>
144
144
  </button>
145
145
  {/if}
@@ -60,12 +60,21 @@
60
60
  }
61
61
  }
62
62
  }
63
+
64
+ function handleMenuItemKeyDown(e: KeyboardEvent) {
65
+ if (e.key === 'Enter' || e.key === ' ') {
66
+ e.preventDefault();
67
+ handleMenuItemClick();
68
+ }
69
+ }
63
70
  </script>
64
71
 
65
72
  <li bind:this={liEl} class:expandable class:fold={!expand} class:cascade class:fly-left={flyLeft}>
66
73
  <span
67
74
  onclick={handleMenuItemClick}
68
- aria-hidden="true"
75
+ onkeydown={handleMenuItemKeyDown}
76
+ role="button" tabindex="0"
77
+ aria-expanded={expandable ? expand : undefined}
69
78
  >
70
79
  <span class="label">{menuText}</span>
71
80
  {#if expandable}
@@ -26,16 +26,23 @@
26
26
  activeItem = item;
27
27
  itemClickHandler?.(item);
28
28
  };
29
+
30
+ const handleKeyDown = (item: any) => (e: KeyboardEvent) => {
31
+ if (e.key === 'Enter' || e.key === ' ') {
32
+ e.preventDefault();
33
+ handleClick(item);
34
+ }
35
+ };
29
36
  </script>
30
37
 
31
38
  <div class="uniface-navigator-panel" {style}>
32
- <div class="navigator-content">
39
+ <div class="navigator-content" role="list">
33
40
  {#each items as item}
34
41
  <div class="uniface-navigator-item {retrieveStatus?.(item) ?? NavItemStatus.Completed}"
35
42
  class:active={activeItem === item}
36
43
  class:highlight={highlights.indexOf(item) > -1}
37
- aria-hidden="true"
38
- onclick={() => handleClick(item)}>
44
+ role="button" tabindex="0" aria-current={activeItem === item ? 'step' : undefined}
45
+ onclick={() => handleClick(item)} onkeydown={handleKeyDown(item)}>
39
46
  <span>{item.text}</span>
40
47
  </div>
41
48
  {/each}
@@ -44,15 +51,7 @@
44
51
 
45
52
  <style>
46
53
  .uniface-navigator-panel {
47
- --uniface-navigator-background-color: var(--uniface-application-bg);
48
- --uniface-navigator-vertical-padding: 16px;
49
- --uniface-navigator-completed-text-color: #374151;
50
- --uniface-navigator-not-start-text-color: #6B7280;
51
- --uniface-navigator-warning-dot-color: #C62828;
52
- --uniface-navigator-hover-text-color: #298DFF;
53
- --uniface-navigator-active-text-color: #0061FF;
54
54
  --uniface-navigator-active-text-weight: 600;
55
- --uniface-navigator-highlight-text-color: #0061FF;
56
55
 
57
56
  position: relative;
58
57
  width: 100%;
@@ -76,7 +75,7 @@
76
75
  font-size: 12px;
77
76
  padding: 4px 8px 4px 24px;
78
77
  position: relative;
79
- background: linear-gradient(to right, transparent 12px, lightgray 12px, lightgray 13px, transparent 13px);
78
+ background: linear-gradient(to right, transparent 12px, var(--uniface-navigator-connector-color) 12px, var(--uniface-navigator-connector-color) 13px, transparent 13px);
80
79
  }
81
80
 
82
81
  .uniface-navigator-item:first-child {
@@ -134,14 +133,15 @@
134
133
  .uniface-navigator-item.active::before {
135
134
  content: "";
136
135
  position: absolute;
137
- left: 5px;
136
+ left: 8px;
138
137
  top: 50%;
139
138
  transform: translateY(-50%);
140
- width: 15px;
141
- height: 15px;
142
- border: 4px solid var(--uniface-navigator-active-text-color);
139
+ box-sizing: border-box;
140
+ width: 10px;
141
+ height: 10px;
142
+ border: 3px solid var(--uniface-navigator-active-text-color);
143
143
  border-radius: 50%;
144
- background-color: white;
144
+ background-color: var(--uniface-navigator-background-color, white);
145
145
  }
146
146
 
147
147
  .uniface-navigator-item.active:hover {
@@ -0,0 +1,160 @@
1
+ <script lang="ts">
2
+ import {untrack} from 'svelte';
3
+ import type {Snippet} from 'svelte';
4
+ import type {TransitionConfig} from 'svelte/transition';
5
+ import {fly} from 'svelte/transition';
6
+ import {cubicOut} from 'svelte/easing';
7
+ import PageStackFrame from './PageStackFrame.svelte';
8
+ import {providePageStackContext} from './PageStackContext';
9
+
10
+ interface StackEntry {
11
+ id: string;
12
+ component: any;
13
+ props: Record<string, any>;
14
+ resolve: (value: any) => void;
15
+ }
16
+
17
+ type TransitionFn = (node: Element, params?: any) => TransitionConfig;
18
+
19
+ interface Props {
20
+ style?: string;
21
+ /** 每一帧 push/pop 的滑入滑出时长(ms)。仅在没有传 transitionParams 时生效;设为 0 关闭动画。 */
22
+ transitionDuration?: number;
23
+ /**
24
+ * 换成任意 svelte/transition 函数(fly/fade/scale/slide...)或自定义的过渡函数。
25
+ * 默认是从右侧滑入的 fly,效果同 transitionParams 未设置时的 {x:'100%', duration:transitionDuration, easing:cubicOut}。
26
+ */
27
+ transition?: TransitionFn;
28
+ /** 传给 transition 函数的参数;一旦提供,会完全替代基于 transitionDuration 生成的默认参数。 */
29
+ transitionParams?: Record<string, any>;
30
+ /** 根页面(初始内容,depth = 0) */
31
+ children?: Snippet;
32
+ }
33
+
34
+ let {
35
+ style = '',
36
+ transitionDuration = 260,
37
+ transition = fly,
38
+ transitionParams,
39
+ children
40
+ }: Props = $props();
41
+
42
+ let resolvedTransitionParams = $derived(
43
+ transitionParams ?? {x: '100%', duration: transitionDuration, easing: cubicOut}
44
+ );
45
+
46
+ let stack = $state<StackEntry[]>([]);
47
+
48
+ const generateId = (): string => `page_${Date.now()}_${Math.random().toString(36).slice(2, 9)}`;
49
+
50
+ function closeEntry(id: string, result?: any): void {
51
+ // untrack: push()/close()/reset() are meant to be callable from anywhere,
52
+ // including from inside a caller's own $effect (e.g. a page that
53
+ // auto-navigates further based on its props). Reading `stack` (to find/
54
+ // filter it) *and* writing it back in the same synchronous call would
55
+ // otherwise get attributed to whatever effect happens to be running at
56
+ // call time, and the write would then re-trigger that same effect —
57
+ // Svelte reports this as "effect reads and writes the same state" /
58
+ // effect_update_depth_exceeded. untrack() keeps this internal
59
+ // read+write from being picked up as a dependency of an unrelated,
60
+ // currently-running effect; existing subscribers of `stack` (the
61
+ // {#each} below) are unaffected — untrack only suppresses *new*
62
+ // spurious subscriptions created during this call.
63
+ let entry: StackEntry | undefined;
64
+ untrack(() => {
65
+ entry = stack.find(e => e.id === id);
66
+ if (!entry) return;
67
+ // 先移除再 resolve:resolve 可能同步触发调用方的后续逻辑(比如再次 push),
68
+ // 那时候这一帧必须已经不在栈里了。
69
+ stack = stack.filter(e => e.id !== id);
70
+ });
71
+ entry?.resolve(result);
72
+ }
73
+
74
+ /**
75
+ * push 一个组件进栈,覆盖显示在当前内容之上。返回的 Promise 在该页面调用
76
+ * getPageStack().close(result) 时以 result resolve;也可以用 PageStack 实例的
77
+ * pop(result) 从外部(比如 bottombar 的返回按钮)关闭当前栈顶。
78
+ */
79
+ export function push<R = any>(component: any, props: Record<string, any> = {}): Promise<R> {
80
+ return new Promise<R>(resolve => {
81
+ const id = generateId();
82
+ // see closeEntry() above for why this is wrapped in untrack()
83
+ untrack(() => {
84
+ stack = [...stack, {id, component, props, resolve: resolve as (v: any) => void}];
85
+ });
86
+ });
87
+ }
88
+
89
+ /** 关闭当前栈顶的一帧。栈为空时是 no-op。 */
90
+ export function pop(result?: any): void {
91
+ const top = stack[stack.length - 1];
92
+ if (top) closeEntry(top.id, result);
93
+ }
94
+
95
+ /** 清空整个栈,直接回到根页面。不逐帧过渡,适合"注销/切换上下文"这类场景。 */
96
+ export function reset(): void {
97
+ // see closeEntry() above for why this is wrapped in untrack()
98
+ let entries: StackEntry[] = [];
99
+ untrack(() => {
100
+ entries = stack;
101
+ stack = [];
102
+ });
103
+ entries.forEach(entry => entry.resolve(undefined));
104
+ }
105
+
106
+ // 根页面(children)本身也活在这个 context 里,depth = 0,close() 是 no-op——
107
+ // 根页面不是被 push 进来的,没有"关闭返回上一层"的语义,但它应该能拿到 push()
108
+ // 来发起第一层导航,不需要额外用 bind:this 去引用 PageStack 实例。
109
+ providePageStackContext({
110
+ close: () => {
111
+ if (typeof console !== 'undefined') {
112
+ console.warn('[PageStack] root page has no close() semantics — it was not pushed onto the stack');
113
+ }
114
+ },
115
+ push,
116
+ depth: 0
117
+ });
118
+ </script>
119
+
120
+ <div class="uniface-page-stack" {style}>
121
+ <div class="page-stack-root" inert={stack.length > 0}>
122
+ {@render children?.()}
123
+ </div>
124
+ {#each stack as entry, i (entry.id)}
125
+ <div class="page-stack-frame" style="z-index: {i + 1}" inert={i < stack.length - 1}
126
+ transition:transition={resolvedTransitionParams}>
127
+ <PageStackFrame
128
+ id={entry.id}
129
+ component={entry.component}
130
+ props={entry.props}
131
+ depth={i + 1}
132
+ close={(result) => closeEntry(entry.id, result)}
133
+ {push}
134
+ />
135
+ </div>
136
+ {/each}
137
+ </div>
138
+
139
+ <style>
140
+ .uniface-page-stack {
141
+ width: 100%;
142
+ height: 100%;
143
+ position: relative;
144
+ overflow: hidden;
145
+ box-sizing: border-box;
146
+ }
147
+
148
+ .page-stack-root {
149
+ width: 100%;
150
+ height: 100%;
151
+ position: relative;
152
+ }
153
+
154
+ .page-stack-frame {
155
+ position: absolute;
156
+ inset: 0;
157
+ overflow: auto;
158
+ background-color: var(--uniface-page-stack-color-surface, var(--uniface-color-surface));
159
+ }
160
+ </style>
@@ -0,0 +1,24 @@
1
+ import type { Snippet } from 'svelte';
2
+ import type { TransitionConfig } from 'svelte/transition';
3
+ type TransitionFn = (node: Element, params?: any) => TransitionConfig;
4
+ interface Props {
5
+ style?: string;
6
+ /** 每一帧 push/pop 的滑入滑出时长(ms)。仅在没有传 transitionParams 时生效;设为 0 关闭动画。 */
7
+ transitionDuration?: number;
8
+ /**
9
+ * 换成任意 svelte/transition 函数(fly/fade/scale/slide...)或自定义的过渡函数。
10
+ * 默认是从右侧滑入的 fly,效果同 transitionParams 未设置时的 {x:'100%', duration:transitionDuration, easing:cubicOut}。
11
+ */
12
+ transition?: TransitionFn;
13
+ /** 传给 transition 函数的参数;一旦提供,会完全替代基于 transitionDuration 生成的默认参数。 */
14
+ transitionParams?: Record<string, any>;
15
+ /** 根页面(初始内容,depth = 0) */
16
+ children?: Snippet;
17
+ }
18
+ declare const PageStack: import("svelte").Component<Props, {
19
+ push: <R = any>(component: any, props?: Record<string, any>) => Promise<R>;
20
+ pop: (result?: any) => void;
21
+ reset: () => void;
22
+ }, "">;
23
+ type PageStack = ReturnType<typeof PageStack>;
24
+ export default PageStack;
@@ -0,0 +1,25 @@
1
+ /**
2
+ * 每一层被 push 进 PageStack 的页面组件,都可以通过 getPageStack() 拿到这个 API。
3
+ * 根页面(PageStack 的 children)同样能拿到(depth = 0),但它的 close() 是 no-op——
4
+ * 根页面不是被 push 进来的,没有"关闭并返回上一层"这个语义。
5
+ */
6
+ export interface PageStackApi<T = any> {
7
+ /**
8
+ * 关闭当前页面。对应这一页 push() 时返回的 Promise 会以 result resolve。
9
+ * 根页面调用无效果(会在开发模式下打一条 warning)。
10
+ */
11
+ close: (result?: T) => void;
12
+ /**
13
+ * 在当前页面之上继续 push 一个新页面,和 PageStack 实例上的 push() 是同一个函数——
14
+ * 多级 drill-down 时不需要一路把最外层的 PageStack 引用传下去。
15
+ */
16
+ push: <R = any>(component: any, props?: Record<string, any>) => Promise<R>;
17
+ /** 当前页面在栈中的深度,根页面为 0,第一层 push 进来的页面为 1,以此类推。 */
18
+ depth: number;
19
+ }
20
+ export declare function providePageStackContext(api: PageStackApi): void;
21
+ /**
22
+ * 在被 PageStack push 进来的页面组件(或它的任意后代)里调用,拿到 {close, push, depth}。
23
+ * 在 PageStack 之外调用返回 undefined。
24
+ */
25
+ export declare function getPageStack<T = any>(): PageStackApi<T> | undefined;
@@ -0,0 +1,12 @@
1
+ import { getContext, setContext, hasContext } from 'svelte';
2
+ const CONTEXT_KEY = 'uniface-page-stack';
3
+ export function providePageStackContext(api) {
4
+ setContext(CONTEXT_KEY, api);
5
+ }
6
+ /**
7
+ * 在被 PageStack push 进来的页面组件(或它的任意后代)里调用,拿到 {close, push, depth}。
8
+ * 在 PageStack 之外调用返回 undefined。
9
+ */
10
+ export function getPageStack() {
11
+ return hasContext(CONTEXT_KEY) ? getContext(CONTEXT_KEY) : undefined;
12
+ }
@@ -0,0 +1,24 @@
1
+ <script lang="ts">
2
+ import {providePageStackContext} from './PageStackContext';
3
+
4
+ interface Props {
5
+ id: string;
6
+ component: any;
7
+ props: Record<string, any>;
8
+ depth: number;
9
+ close: (result?: any) => void;
10
+ push: <R = any>(component: any, props?: Record<string, any>) => Promise<R>;
11
+ }
12
+
13
+ let {id, component: Comp, props, depth, close, push}: Props = $props();
14
+
15
+ // Context identity is fixed for the lifetime of this frame — mirrors
16
+ // DialogWrapper's getInitialDialogId pattern (overlay/dialog/DialogWrapper.svelte):
17
+ // later prop changes (e.g. depth staying the same but close/push identity
18
+ // churning on parent re-render) must not replace what this frame's
19
+ // descendants already captured via getPageStack().
20
+ const getInitialContext = () => ({close, push, depth});
21
+ providePageStackContext(getInitialContext());
22
+ </script>
23
+
24
+ <Comp {...props}/>
@@ -0,0 +1,11 @@
1
+ interface Props {
2
+ id: string;
3
+ component: any;
4
+ props: Record<string, any>;
5
+ depth: number;
6
+ close: (result?: any) => void;
7
+ push: <R = any>(component: any, props?: Record<string, any>) => Promise<R>;
8
+ }
9
+ declare const PageStackFrame: import("svelte").Component<Props, {}, "">;
10
+ type PageStackFrame = ReturnType<typeof PageStackFrame>;
11
+ export default PageStackFrame;