@cwellt_software/cwellt-reactjs-lib 1.4.15 → 1.5.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 (281) hide show
  1. package/dist/content/fonts/roboto-mono/LICENSE +93 -0
  2. package/dist/content/fonts/roboto-mono/RobotoMono.css +43 -0
  3. package/dist/content/fonts/roboto-mono/files/roboto-mono-latin-ext-wght-italic.woff2 +0 -0
  4. package/dist/content/fonts/roboto-mono/files/roboto-mono-latin-ext-wght-normal.woff2 +0 -0
  5. package/dist/content/fonts/roboto-mono/files/roboto-mono-latin-wght-italic.woff2 +0 -0
  6. package/dist/content/fonts/roboto-mono/files/roboto-mono-latin-wght-normal.woff2 +0 -0
  7. package/dist/content/icons/new-cw-icons/NewCwIcons.json +1 -1
  8. package/dist/content/icons/new-cw-icons/css/new-cw-icons.css +260 -824
  9. package/dist/content/icons/new-cw-icons/fonts/NewCwIcons.woff +0 -0
  10. package/dist/deprecated/components/MultiSelect_deprecated_.d.ts +24 -0
  11. package/dist/deprecated/components/MultiSelect_deprecated_.d.ts.map +1 -0
  12. package/dist/deprecated/components/dropdown/CwDropdownContainer.d.ts +17 -0
  13. package/dist/deprecated/components/dropdown/CwDropdownContainer.d.ts.map +1 -0
  14. package/dist/deprecated/components/multiselect/CwHeadFilter.d.ts +17 -0
  15. package/dist/deprecated/components/multiselect/CwHeadFilter.d.ts.map +1 -0
  16. package/dist/deprecated/components/multiselect/CwMultiselect.d.ts +13 -0
  17. package/dist/deprecated/components/multiselect/CwMultiselect.d.ts.map +1 -0
  18. package/dist/deprecated/components/multiselect/CwOptionList.d.ts +14 -0
  19. package/dist/deprecated/components/multiselect/CwOptionList.d.ts.map +1 -0
  20. package/dist/deprecated/components/tag/CwTag.d.ts +15 -0
  21. package/dist/deprecated/components/tag/CwTag.d.ts.map +1 -0
  22. package/dist/index.cjs.js +514 -213
  23. package/dist/index.css +2 -2
  24. package/dist/index.d.ts +226 -51
  25. package/dist/index.es.js +508 -212
  26. package/dist/playground/main.d.ts +4 -0
  27. package/dist/playground/main.d.ts.map +1 -0
  28. package/dist/src/components/control/action/button/CwPopoverButton.d.ts +33 -0
  29. package/dist/src/components/control/action/button/CwPopoverButton.d.ts.map +1 -0
  30. package/dist/src/components/control/action/contextual-menu/CwContextualMenu.d.ts +29 -0
  31. package/dist/src/components/control/action/contextual-menu/CwContextualMenu.d.ts.map +1 -0
  32. package/dist/src/components/control/action/search/CwAsyncSearch.d.ts +102 -0
  33. package/dist/src/components/control/action/search/CwAsyncSearch.d.ts.map +1 -0
  34. package/dist/src/components/control/action/search/CwSearch.d.ts +2 -0
  35. package/dist/src/components/control/action/search/CwSearch.d.ts.map +1 -1
  36. package/dist/src/components/control/action/search/searchKeyboardNavigation.d.ts +35 -0
  37. package/dist/src/components/control/action/search/searchKeyboardNavigation.d.ts.map +1 -0
  38. package/dist/src/components/control/action/tooltip-dialog/CwTooltipDialog.d.ts +19 -0
  39. package/dist/src/components/control/action/tooltip-dialog/CwTooltipDialog.d.ts.map +1 -0
  40. package/dist/src/components/control/choice/deprecated/CwDropdown.d.ts +19 -0
  41. package/dist/src/components/control/choice/deprecated/CwDropdown.d.ts.map +1 -0
  42. package/dist/src/components/control/choice/deprecated/CwDropdownNavigation.d.ts +21 -0
  43. package/dist/src/components/control/choice/deprecated/CwDropdownNavigation.d.ts.map +1 -0
  44. package/dist/src/components/control/choice/deprecated/MultiSelect_deprecated_.d.ts +24 -0
  45. package/dist/src/components/control/choice/deprecated/MultiSelect_deprecated_.d.ts.map +1 -0
  46. package/dist/src/components/control/choice/dropdown/CwDropdown.d.ts +19 -0
  47. package/dist/src/components/control/choice/dropdown/CwDropdown.d.ts.map +1 -0
  48. package/dist/src/components/control/choice/dropdown/CwDropdownContainer.d.ts +17 -0
  49. package/dist/src/components/control/choice/dropdown/CwDropdownContainer.d.ts.map +1 -0
  50. package/dist/src/components/control/choice/dropdown/CwDropdownNavigation.d.ts +21 -0
  51. package/dist/src/components/control/choice/dropdown/CwDropdownNavigation.d.ts.map +1 -0
  52. package/dist/src/components/control/choice/multiselect/CwHeadFilter.d.ts +17 -0
  53. package/dist/src/components/control/choice/multiselect/CwHeadFilter.d.ts.map +1 -0
  54. package/dist/src/components/control/choice/multiselect/CwMultiselect.d.ts +13 -0
  55. package/dist/src/components/control/choice/multiselect/CwMultiselect.d.ts.map +1 -0
  56. package/dist/src/components/control/choice/multiselect/CwOptionList.d.ts +14 -0
  57. package/dist/src/components/control/choice/multiselect/CwOptionList.d.ts.map +1 -0
  58. package/dist/src/components/control/choice/nav-menu/CwNavMenu.d.ts +78 -0
  59. package/dist/src/components/control/choice/nav-menu/CwNavMenu.d.ts.map +1 -0
  60. package/dist/src/components/control/choice/nav-menu/filterNavItems.d.ts +9 -0
  61. package/dist/src/components/control/choice/nav-menu/filterNavItems.d.ts.map +1 -0
  62. package/dist/src/components/control/choice/nav-menu/sortNavItems.d.ts +9 -0
  63. package/dist/src/components/control/choice/nav-menu/sortNavItems.d.ts.map +1 -0
  64. package/dist/src/components/control/input/file/CwFileUploadMultiple.d.ts +12 -0
  65. package/dist/src/components/control/input/file/CwFileUploadMultiple.d.ts.map +1 -1
  66. package/dist/src/components/control/input/image/CwInputImage.d.ts +17 -2
  67. package/dist/src/components/control/input/image/CwInputImage.d.ts.map +1 -1
  68. package/dist/src/components/control/input/new-dates/CwDateTimePicker2.d.ts +47 -0
  69. package/dist/src/components/control/input/new-dates/CwDateTimePicker2.d.ts.map +1 -0
  70. package/dist/src/components/custom/scheduler-temporal/CwSchedulerComp2.d.ts +24 -0
  71. package/dist/src/components/custom/scheduler-temporal/CwSchedulerComp2.d.ts.map +1 -0
  72. package/dist/src/components/custom/scheduler-temporal/CwSuperSchedulerComp.d.ts +86 -0
  73. package/dist/src/components/custom/scheduler-temporal/CwSuperSchedulerComp.d.ts.map +1 -0
  74. package/dist/src/components/custom/scheduler-temporal/components/EventRender.d.ts +10 -0
  75. package/dist/src/components/custom/scheduler-temporal/components/EventRender.d.ts.map +1 -0
  76. package/dist/src/components/custom/scheduler-temporal/components/ResourceListRender.d.ts +20 -0
  77. package/dist/src/components/custom/scheduler-temporal/components/ResourceListRender.d.ts.map +1 -0
  78. package/dist/src/components/custom/scheduler-temporal/components/ResourceRender.d.ts +14 -0
  79. package/dist/src/components/custom/scheduler-temporal/components/ResourceRender.d.ts.map +1 -0
  80. package/dist/src/components/custom/scheduler-temporal/components/day_headers/DayHeader.d.ts +11 -0
  81. package/dist/src/components/custom/scheduler-temporal/components/day_headers/DayHeader.d.ts.map +1 -0
  82. package/dist/src/components/custom/scheduler-temporal/components/day_headers/MonthHeader.d.ts +11 -0
  83. package/dist/src/components/custom/scheduler-temporal/components/day_headers/MonthHeader.d.ts.map +1 -0
  84. package/dist/src/components/custom/scheduler-temporal/components/day_headers/MyDaysHeader.d.ts +13 -0
  85. package/dist/src/components/custom/scheduler-temporal/components/day_headers/MyDaysHeader.d.ts.map +1 -0
  86. package/dist/src/components/custom/scheduler-temporal/components/day_headers/WeekHeader.d.ts +11 -0
  87. package/dist/src/components/custom/scheduler-temporal/components/day_headers/WeekHeader.d.ts.map +1 -0
  88. package/dist/src/components/custom/scheduler-temporal/components/resources_title_list/ResourcesTitleList.d.ts +14 -0
  89. package/dist/src/components/custom/scheduler-temporal/components/resources_title_list/ResourcesTitleList.d.ts.map +1 -0
  90. package/dist/src/components/custom/scheduler-temporal/components/scheduler_content_area/SchedulerContentArea.d.ts +23 -0
  91. package/dist/src/components/custom/scheduler-temporal/components/scheduler_content_area/SchedulerContentArea.d.ts.map +1 -0
  92. package/dist/src/components/custom/scheduler-temporal/components/scheduler_header/SchedulerHeader.d.ts +8 -0
  93. package/dist/src/components/custom/scheduler-temporal/components/scheduler_header/SchedulerHeader.d.ts.map +1 -0
  94. package/dist/src/components/custom/scheduler-temporal/components/scheduler_timeline/SchedulerTimeLine.d.ts +12 -0
  95. package/dist/src/components/custom/scheduler-temporal/components/scheduler_timeline/SchedulerTimeLine.d.ts.map +1 -0
  96. package/dist/src/components/custom/scheduler-temporal/components/time_headers/TimeHeader.d.ts +12 -0
  97. package/dist/src/components/custom/scheduler-temporal/components/time_headers/TimeHeader.d.ts.map +1 -0
  98. package/dist/src/components/custom/scheduler-temporal/components/time_headers/TimeHeaderRow.d.ts +10 -0
  99. package/dist/src/components/custom/scheduler-temporal/components/time_headers/TimeHeaderRow.d.ts.map +1 -0
  100. package/dist/src/components/custom/scheduler-temporal/components/time_line/TimeLine.d.ts +12 -0
  101. package/dist/src/components/custom/scheduler-temporal/components/time_line/TimeLine.d.ts.map +1 -0
  102. package/dist/src/components/custom/scheduler-temporal/logic/dates/addMinutesToDateFromPx.d.ts +2 -0
  103. package/dist/src/components/custom/scheduler-temporal/logic/dates/addMinutesToDateFromPx.d.ts.map +1 -0
  104. package/dist/src/components/custom/scheduler-temporal/logic/dates/daysBetweenTwoDates.d.ts +2 -0
  105. package/dist/src/components/custom/scheduler-temporal/logic/dates/daysBetweenTwoDates.d.ts.map +1 -0
  106. package/dist/src/components/custom/scheduler-temporal/logic/dates/daysBetweenTwoDatesWithoutCeil.d.ts +2 -0
  107. package/dist/src/components/custom/scheduler-temporal/logic/dates/daysBetweenTwoDatesWithoutCeil.d.ts.map +1 -0
  108. package/dist/src/components/custom/scheduler-temporal/logic/dates/getFormatedTimeForHeader.d.ts +7 -0
  109. package/dist/src/components/custom/scheduler-temporal/logic/dates/getFormatedTimeForHeader.d.ts.map +1 -0
  110. package/dist/src/components/custom/scheduler-temporal/logic/dates/getMonthHeaderData.d.ts +10 -0
  111. package/dist/src/components/custom/scheduler-temporal/logic/dates/getMonthHeaderData.d.ts.map +1 -0
  112. package/dist/src/components/custom/scheduler-temporal/logic/dates/getUtcToday.d.ts +2 -0
  113. package/dist/src/components/custom/scheduler-temporal/logic/dates/getUtcToday.d.ts.map +1 -0
  114. package/dist/src/components/custom/scheduler-temporal/logic/dates/getWeekHeaderDataFromWeekRange.d.ts +7 -0
  115. package/dist/src/components/custom/scheduler-temporal/logic/dates/getWeekHeaderDataFromWeekRange.d.ts.map +1 -0
  116. package/dist/src/components/custom/scheduler-temporal/logic/dates/listOfDatesToWeeks.d.ts +8 -0
  117. package/dist/src/components/custom/scheduler-temporal/logic/dates/listOfDatesToWeeks.d.ts.map +1 -0
  118. package/dist/src/components/custom/scheduler-temporal/logic/divisions/calculateDivisionType.d.ts +2 -0
  119. package/dist/src/components/custom/scheduler-temporal/logic/divisions/calculateDivisionType.d.ts.map +1 -0
  120. package/dist/src/components/custom/scheduler-temporal/logic/divisions/calculateDivisions.d.ts +2 -0
  121. package/dist/src/components/custom/scheduler-temporal/logic/divisions/calculateDivisions.d.ts.map +1 -0
  122. package/dist/src/components/custom/scheduler-temporal/logic/filtering/filterAndProcessResources.d.ts +4 -0
  123. package/dist/src/components/custom/scheduler-temporal/logic/filtering/filterAndProcessResources.d.ts.map +1 -0
  124. package/dist/src/components/custom/scheduler-temporal/logic/filtering/filterEvents.d.ts +3 -0
  125. package/dist/src/components/custom/scheduler-temporal/logic/filtering/filterEvents.d.ts.map +1 -0
  126. package/dist/src/components/custom/scheduler-temporal/logic/filtering/filterResources.d.ts +3 -0
  127. package/dist/src/components/custom/scheduler-temporal/logic/filtering/filterResources.d.ts.map +1 -0
  128. package/dist/src/components/custom/scheduler-temporal/logic/filtering/hasSameProperties.d.ts +3 -0
  129. package/dist/src/components/custom/scheduler-temporal/logic/filtering/hasSameProperties.d.ts.map +1 -0
  130. package/dist/src/components/custom/scheduler-temporal/logic/onDrop/OnDrop.d.ts +13 -0
  131. package/dist/src/components/custom/scheduler-temporal/logic/onDrop/OnDrop.d.ts.map +1 -0
  132. package/dist/src/components/custom/scheduler-temporal/logic/pixels/getHeightLineScheduler.d.ts +2 -0
  133. package/dist/src/components/custom/scheduler-temporal/logic/pixels/getHeightLineScheduler.d.ts.map +1 -0
  134. package/dist/src/components/custom/scheduler-temporal/logic/pixels/getPixelsForEvent.d.ts +7 -0
  135. package/dist/src/components/custom/scheduler-temporal/logic/pixels/getPixelsForEvent.d.ts.map +1 -0
  136. package/dist/src/components/custom/scheduler-temporal/logic/pixels/heightScheduler.d.ts +3 -0
  137. package/dist/src/components/custom/scheduler-temporal/logic/pixels/heightScheduler.d.ts.map +1 -0
  138. package/dist/src/components/custom/scheduler-temporal/logic/pixels/heightSchedulerPinned.d.ts +2 -0
  139. package/dist/src/components/custom/scheduler-temporal/logic/pixels/heightSchedulerPinned.d.ts.map +1 -0
  140. package/dist/src/components/custom/scheduler-temporal/logic/state_handle/doubleClickOnResource.d.ts +4 -0
  141. package/dist/src/components/custom/scheduler-temporal/logic/state_handle/doubleClickOnResource.d.ts.map +1 -0
  142. package/dist/src/components/custom/scheduler-temporal/logic/state_handle/handlePropChanges.d.ts +6 -0
  143. package/dist/src/components/custom/scheduler-temporal/logic/state_handle/handlePropChanges.d.ts.map +1 -0
  144. package/dist/src/components/custom/scheduler-temporal/logic/state_handle/handleResourceChange.d.ts +5 -0
  145. package/dist/src/components/custom/scheduler-temporal/logic/state_handle/handleResourceChange.d.ts.map +1 -0
  146. package/dist/src/components/custom/scheduler-temporal/logic/state_handle/onDragOver.d.ts +2 -0
  147. package/dist/src/components/custom/scheduler-temporal/logic/state_handle/onDragOver.d.ts.map +1 -0
  148. package/dist/src/components/custom/scheduler-temporal/logic/state_handle/onDropEventToResource.d.ts +5 -0
  149. package/dist/src/components/custom/scheduler-temporal/logic/state_handle/onDropEventToResource.d.ts.map +1 -0
  150. package/dist/src/components/custom/scheduler-temporal/logic/state_handle/onResizeEvent.d.ts +4 -0
  151. package/dist/src/components/custom/scheduler-temporal/logic/state_handle/onResizeEvent.d.ts.map +1 -0
  152. package/dist/src/components/custom/scheduler-temporal/logic/strings/compareStrings.d.ts +2 -0
  153. package/dist/src/components/custom/scheduler-temporal/logic/strings/compareStrings.d.ts.map +1 -0
  154. package/dist/src/components/custom/scheduler-temporal/logic/strings/getGUID.d.ts +2 -0
  155. package/dist/src/components/custom/scheduler-temporal/logic/strings/getGUID.d.ts.map +1 -0
  156. package/dist/src/components/custom/scheduler-temporal/logic/ui/checkIfSlotAvailable.d.ts +3 -0
  157. package/dist/src/components/custom/scheduler-temporal/logic/ui/checkIfSlotAvailable.d.ts.map +1 -0
  158. package/dist/src/components/custom/scheduler-temporal/logic/ui/getEventsOfResource.d.ts +6 -0
  159. package/dist/src/components/custom/scheduler-temporal/logic/ui/getEventsOfResource.d.ts.map +1 -0
  160. package/dist/src/components/custom/scheduler-temporal/logic/ui/getHasPropsChanged.d.ts +4 -0
  161. package/dist/src/components/custom/scheduler-temporal/logic/ui/getHasPropsChanged.d.ts.map +1 -0
  162. package/dist/src/components/custom/scheduler-temporal/logic/ui/getTimeHeaders.d.ts +2 -0
  163. package/dist/src/components/custom/scheduler-temporal/logic/ui/getTimeHeaders.d.ts.map +1 -0
  164. package/dist/src/components/custom/scheduler-temporal/logic/ui/isAllowedToMove.d.ts +3 -0
  165. package/dist/src/components/custom/scheduler-temporal/logic/ui/isAllowedToMove.d.ts.map +1 -0
  166. package/dist/src/components/custom/scheduler-temporal/logic/ui/shouldTriggerScroll.d.ts +4 -0
  167. package/dist/src/components/custom/scheduler-temporal/logic/ui/shouldTriggerScroll.d.ts.map +1 -0
  168. package/dist/src/components/custom/scheduler-temporal/logic/ui/updateResourceVisibility.d.ts +3 -0
  169. package/dist/src/components/custom/scheduler-temporal/logic/ui/updateResourceVisibility.d.ts.map +1 -0
  170. package/dist/src/components/custom/scheduler-temporal/state/CblDragAndDrop.d.ts +11 -0
  171. package/dist/src/components/custom/scheduler-temporal/state/CblDragAndDrop.d.ts.map +1 -0
  172. package/dist/src/components/custom/scheduler-temporal/state/CwSchedulerProps.d.ts +43 -0
  173. package/dist/src/components/custom/scheduler-temporal/state/CwSchedulerProps.d.ts.map +1 -0
  174. package/dist/src/components/custom/scheduler-temporal/state/Resource.d.ts +14 -0
  175. package/dist/src/components/custom/scheduler-temporal/state/Resource.d.ts.map +1 -0
  176. package/dist/src/components/custom/scheduler-temporal/state/State.d.ts +25 -0
  177. package/dist/src/components/custom/scheduler-temporal/state/State.d.ts.map +1 -0
  178. package/dist/src/components/custom/scheduler-temporal/state/cblEvent.d.ts +18 -0
  179. package/dist/src/components/custom/scheduler-temporal/state/cblEvent.d.ts.map +1 -0
  180. package/dist/src/components/custom/scheduler-temporal/state/cblEventCompProps.d.ts +7 -0
  181. package/dist/src/components/custom/scheduler-temporal/state/cblEventCompProps.d.ts.map +1 -0
  182. package/dist/src/components/custom/scheduler-temporal/state/resourceCompProps2.d.ts +6 -0
  183. package/dist/src/components/custom/scheduler-temporal/state/resourceCompProps2.d.ts.map +1 -0
  184. package/dist/src/components/display/data/table/CwTable.d.ts +4 -1
  185. package/dist/src/components/display/data/table/CwTable.d.ts.map +1 -1
  186. package/dist/src/components/display/data/table-serverside/CwTableServerSide.d.ts +4 -1
  187. package/dist/src/components/display/data/table-serverside/CwTableServerSide.d.ts.map +1 -1
  188. package/dist/src/components/display/data/table_sortable/CwSortableTable.d.ts +4 -2
  189. package/dist/src/components/display/data/table_sortable/CwSortableTable.d.ts.map +1 -1
  190. package/dist/src/components/display/graphics/icon/CwIcon.d.ts +1 -1
  191. package/dist/src/components/display/graphics/icon/CwIcon.d.ts.map +1 -1
  192. package/dist/src/components/display/graphics/loading/CwLoading.d.ts +3 -14
  193. package/dist/src/components/display/graphics/loading/CwLoading.d.ts.map +1 -1
  194. package/dist/src/components/display/graphics/loading/loadingConfig.d.ts +16 -0
  195. package/dist/src/components/display/graphics/loading/loadingConfig.d.ts.map +1 -0
  196. package/dist/src/components/display/graphics/progress/CwProgress.d.ts +36 -0
  197. package/dist/src/components/display/graphics/progress/CwProgress.d.ts.map +1 -0
  198. package/dist/src/components/display/graphics/skeleton/CwSkeleton.d.ts +31 -0
  199. package/dist/src/components/display/graphics/skeleton/CwSkeleton.d.ts.map +1 -0
  200. package/dist/src/components/display/graphics/skeleton/CwSkeletonCard.d.ts +21 -0
  201. package/dist/src/components/display/graphics/skeleton/CwSkeletonCard.d.ts.map +1 -0
  202. package/dist/src/components/display/graphics/skeleton/normalizeSkeletonCount.d.ts +8 -0
  203. package/dist/src/components/display/graphics/skeleton/normalizeSkeletonCount.d.ts.map +1 -0
  204. package/dist/src/components/display/graphics/skeleton/skeletonCellWidth.d.ts +8 -0
  205. package/dist/src/components/display/graphics/skeleton/skeletonCellWidth.d.ts.map +1 -0
  206. package/dist/src/components/display/text/tag/CwTag.d.ts +15 -0
  207. package/dist/src/components/display/text/tag/CwTag.d.ts.map +1 -0
  208. package/dist/src/components/display/text/tooltip/CwTooltip.d.ts +11 -0
  209. package/dist/src/components/display/text/tooltip/CwTooltip.d.ts.map +1 -0
  210. package/dist/src/components/layout/card/CwCard.d.ts +3 -1
  211. package/dist/src/components/layout/card/CwCard.d.ts.map +1 -1
  212. package/dist/src/components/layout/card/CwCardList.d.ts +4 -2
  213. package/dist/src/components/layout/card/CwCardList.d.ts.map +1 -1
  214. package/dist/src/components/layout/list/key-value/CwKeyValueList.d.ts +4 -0
  215. package/dist/src/components/layout/list/key-value/CwKeyValueList.d.ts.map +1 -1
  216. package/dist/src/components/layout/master-detail/CwMasterDetail.d.ts +4 -0
  217. package/dist/src/components/layout/master-detail/CwMasterDetail.d.ts.map +1 -1
  218. package/dist/src/components/layout/modal/legacy/cw_modal_confirm.d.ts +16 -0
  219. package/dist/src/components/layout/modal/legacy/cw_modal_confirm.d.ts.map +1 -0
  220. package/dist/src/components/layout/modal/legacy/cw_modal_iframe.d.ts +21 -0
  221. package/dist/src/components/layout/modal/legacy/cw_modal_iframe.d.ts.map +1 -0
  222. package/dist/src/components/layout/tabs/CwTabs.d.ts +7 -0
  223. package/dist/src/components/layout/tabs/CwTabs.d.ts.map +1 -1
  224. package/dist/src/index.d.ts +6 -2
  225. package/dist/src/index.d.ts.map +1 -1
  226. package/dist/src/playground/PlaygroundApp.d.ts.map +1 -1
  227. package/dist/src/playground/pages/CwFileUploadMultiplePage.d.ts +3 -0
  228. package/dist/src/playground/pages/CwFileUploadMultiplePage.d.ts.map +1 -0
  229. package/dist/src/playground/pages/CwInputImagePage.d.ts.map +1 -1
  230. package/dist/src/playground/pages/CwNavMenuPage.d.ts +3 -0
  231. package/dist/src/playground/pages/CwNavMenuPage.d.ts.map +1 -0
  232. package/dist/src/playground/pages/IconLibraryPage.d.ts +3 -0
  233. package/dist/src/playground/pages/IconLibraryPage.d.ts.map +1 -0
  234. package/dist/src/playground/pages/LoadingPage.d.ts +3 -0
  235. package/dist/src/playground/pages/LoadingPage.d.ts.map +1 -0
  236. package/dist/src/playground/pages/ProgressPage.d.ts +3 -0
  237. package/dist/src/playground/pages/ProgressPage.d.ts.map +1 -0
  238. package/dist/src/playground/pages/SelectorsPage.d.ts.map +1 -1
  239. package/dist/src/playground/pages/SkeletonPage.d.ts +3 -0
  240. package/dist/src/playground/pages/SkeletonPage.d.ts.map +1 -0
  241. package/dist/test/components/control/action/search/searchKeyboardNavigation.test.d.ts +2 -0
  242. package/dist/test/components/control/action/search/searchKeyboardNavigation.test.d.ts.map +1 -0
  243. package/dist/test/components/control/choice/nav-menu/CwNavMenu.test.d.ts +2 -0
  244. package/dist/test/components/control/choice/nav-menu/CwNavMenu.test.d.ts.map +1 -0
  245. package/dist/test/components/control/choice/nav-menu/filterNavItems.test.d.ts +2 -0
  246. package/dist/test/components/control/choice/nav-menu/filterNavItems.test.d.ts.map +1 -0
  247. package/dist/test/components/control/choice/nav-menu/sortNavItems.test.d.ts +2 -0
  248. package/dist/test/components/control/choice/nav-menu/sortNavItems.test.d.ts.map +1 -0
  249. package/dist/test/components/control/input/file/fileMatchesAccept.test.d.ts +2 -0
  250. package/dist/test/components/control/input/file/fileMatchesAccept.test.d.ts.map +1 -0
  251. package/dist/test/components/control/input/image/readImageFileAsDataUrl.test.d.ts +2 -0
  252. package/dist/test/components/control/input/image/readImageFileAsDataUrl.test.d.ts.map +1 -0
  253. package/dist/test/components/display/data/table/CwTable.test.d.ts +2 -0
  254. package/dist/test/components/display/data/table/CwTable.test.d.ts.map +1 -0
  255. package/dist/test/components/display/data/table-serverside/CwTableServerSide.test.d.ts +2 -0
  256. package/dist/test/components/display/data/table-serverside/CwTableServerSide.test.d.ts.map +1 -0
  257. package/dist/test/components/display/data/table_sortable/CwSortableTable.test.d.ts +2 -0
  258. package/dist/test/components/display/data/table_sortable/CwSortableTable.test.d.ts.map +1 -0
  259. package/dist/test/components/display/graphics/loading/CwLoading.test.d.ts +2 -0
  260. package/dist/test/components/display/graphics/loading/CwLoading.test.d.ts.map +1 -0
  261. package/dist/test/components/display/graphics/progress/CwProgress.test.d.ts +2 -0
  262. package/dist/test/components/display/graphics/progress/CwProgress.test.d.ts.map +1 -0
  263. package/dist/test/components/display/graphics/skeleton/CwSkeleton.test.d.ts +2 -0
  264. package/dist/test/components/display/graphics/skeleton/CwSkeleton.test.d.ts.map +1 -0
  265. package/dist/test/components/display/graphics/skeleton/CwSkeletonCard.test.d.ts +2 -0
  266. package/dist/test/components/display/graphics/skeleton/CwSkeletonCard.test.d.ts.map +1 -0
  267. package/dist/test/components/display/graphics/skeleton/normalizeSkeletonCount.test.d.ts +2 -0
  268. package/dist/test/components/display/graphics/skeleton/normalizeSkeletonCount.test.d.ts.map +1 -0
  269. package/dist/test/components/display/graphics/skeleton/skeletonCellWidth.test.d.ts +2 -0
  270. package/dist/test/components/display/graphics/skeleton/skeletonCellWidth.test.d.ts.map +1 -0
  271. package/dist/test/components/layout/card/CwCard.test.d.ts +2 -0
  272. package/dist/test/components/layout/card/CwCard.test.d.ts.map +1 -0
  273. package/dist/test/components/layout/card/CwCardList.test.d.ts +2 -0
  274. package/dist/test/components/layout/card/CwCardList.test.d.ts.map +1 -0
  275. package/dist/test/components/layout/list/key-value/CwKeyValueList.test.d.ts +2 -0
  276. package/dist/test/components/layout/list/key-value/CwKeyValueList.test.d.ts.map +1 -0
  277. package/dist/test/components/layout/master-detail/CwMasterDetail.test.d.ts +2 -0
  278. package/dist/test/components/layout/master-detail/CwMasterDetail.test.d.ts.map +1 -0
  279. package/dist/test/jest.setup.d.ts +2 -0
  280. package/dist/test/jest.setup.d.ts.map +1 -0
  281. package/package.json +1 -2
package/dist/index.cjs.js CHANGED
@@ -181,12 +181,7 @@ function getContrastColor(color) {
181
181
  return `hsl(${hsl.h}, ${contrastS}%, ${targetL}%)`;
182
182
  }
183
183
 
184
- const SVG_ICONS = {
185
- 'sortable-asc': (jsxRuntime.jsxs("svg", { width: "16", height: "16", viewBox: "0 0 128 128", fill: "currentColor", children: [jsxRuntime.jsx("path", { d: "M93.1675 73.1739C94.5691 74.5758 94.7323 76.7924 93.5515 78.3846L93.1675 78.8326L63.6741 108.326L34.1755 78.8326C32.6908 77.3518 32.6014 74.9761 33.9708 73.3881C35.3401 71.8001 37.7033 71.5391 39.3861 72.7899L39.8341 73.1739L63.6741 97.0137L87.5088 73.1739C88.9104 71.7726 91.1274 71.6092 92.7194 72.7899L93.1674 73.1739H93.1675Z", opacity: "0.3" }), jsxRuntime.jsx("path", { d: "M34.1714 55.1518C32.7697 53.7499 32.6066 51.5333 33.7874 49.9411L34.1714 49.4931L63.6647 20L93.1634 49.4931C94.6481 50.9739 94.7375 53.3496 93.3681 54.9376C91.9987 56.5256 89.6356 56.7866 87.9527 55.5358L87.5047 55.1517L63.6647 31.312L39.8301 55.1518C38.4285 56.5531 36.2115 56.7165 34.6195 55.5358L34.1715 55.1518L34.1714 55.1518Z", opacity: "1" })] })),
186
- 'sortable-desc': (jsxRuntime.jsxs("svg", { width: "16", height: "16", viewBox: "0 0 128 128", fill: "currentColor", children: [jsxRuntime.jsx("path", { d: "M93.1675 73.1739C94.5691 74.5758 94.7323 76.7924 93.5515 78.3846L93.1675 78.8326L63.6741 108.326L34.1755 78.8326C32.6908 77.3518 32.6014 74.9761 33.9708 73.3881C35.3401 71.8001 37.7033 71.5391 39.3861 72.7899L39.8341 73.1739L63.6741 97.0137L87.5088 73.1739C88.9104 71.7726 91.1274 71.6092 92.7194 72.7899L93.1674 73.1739H93.1675Z", opacity: "1" }), jsxRuntime.jsx("path", { d: "M34.1714 55.1518C32.7697 53.7499 32.6066 51.5333 33.7874 49.9411L34.1714 49.4931L63.6647 20L93.1634 49.4931C94.6481 50.9739 94.7375 53.3496 93.3681 54.9376C91.9987 56.5256 89.6356 56.7866 87.9527 55.5358L87.5047 55.1517L63.6647 31.312L39.8301 55.1518C38.4285 56.5531 36.2115 56.7165 34.6195 55.5358L34.1715 55.1518L34.1714 55.1518Z", opacity: "0.3" })] })),
187
- };
188
-
189
- var styles$u = {"cw-tooltip-content":"cw-tooltip-module__cw-tooltip-content__RZczd","cw-tooltip":"cw-tooltip-module__cw-tooltip__1KYig"};
184
+ var styles$x = {"cw-tooltip-content":"cw-tooltip-module__cw-tooltip-content__RZczd","cw-tooltip":"cw-tooltip-module__cw-tooltip__1KYig"};
190
185
 
191
186
  // Constants
192
187
  const margin$1 = 16;
@@ -476,7 +471,7 @@ const CwTooltipManager = () => {
476
471
  if (!state.isVisible || !state.content) {
477
472
  return null;
478
473
  }
479
- return reactDom.createPortal(jsxRuntime.jsx("div", { ref: tooltipRef, className: styles$u["cw-tooltip-content"], "data-position": actualPosition, "data-visible": state.isVisible, "data-inline": state.displayInline, style: {
474
+ return reactDom.createPortal(jsxRuntime.jsx("div", { ref: tooltipRef, className: styles$x["cw-tooltip-content"], "data-position": actualPosition, "data-visible": state.isVisible, "data-inline": state.displayInline, style: {
480
475
  top: `${tooltipPosition.top}px`,
481
476
  left: `${tooltipPosition.left}px`,
482
477
  opacity: (isPositioned && !isMeasuring) ? 1 : 0,
@@ -557,16 +552,22 @@ const CwTooltipNew = ({ children, content = null, position = "right", dissapears
557
552
  React.useEffect(() => {
558
553
  ensureTooltipManager();
559
554
  }, []);
560
- return (jsxRuntime.jsx("div", { ref: containerRef, onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, style: overlayStyle, "data-inline": displayInline, className: styles$u["cw-tooltip"], children: children }));
555
+ return (jsxRuntime.jsx("div", { ref: containerRef, onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, style: overlayStyle, "data-inline": displayInline, className: styles$x["cw-tooltip"], children: children }));
556
+ };
557
+
558
+ const SVG_ICONS = {
559
+ 'sortable-asc': (jsxRuntime.jsxs("svg", { width: "16", height: "16", viewBox: "0 0 128 128", fill: "currentColor", children: [jsxRuntime.jsx("path", { d: "M93.1675 73.1739C94.5691 74.5758 94.7323 76.7924 93.5515 78.3846L93.1675 78.8326L63.6741 108.326L34.1755 78.8326C32.6908 77.3518 32.6014 74.9761 33.9708 73.3881C35.3401 71.8001 37.7033 71.5391 39.3861 72.7899L39.8341 73.1739L63.6741 97.0137L87.5088 73.1739C88.9104 71.7726 91.1274 71.6092 92.7194 72.7899L93.1674 73.1739H93.1675Z", opacity: "0.3" }), jsxRuntime.jsx("path", { d: "M34.1714 55.1518C32.7697 53.7499 32.6066 51.5333 33.7874 49.9411L34.1714 49.4931L63.6647 20L93.1634 49.4931C94.6481 50.9739 94.7375 53.3496 93.3681 54.9376C91.9987 56.5256 89.6356 56.7866 87.9527 55.5358L87.5047 55.1517L63.6647 31.312L39.8301 55.1518C38.4285 56.5531 36.2115 56.7165 34.6195 55.5358L34.1715 55.1518L34.1714 55.1518Z", opacity: "1" })] })),
560
+ 'sortable-desc': (jsxRuntime.jsxs("svg", { width: "16", height: "16", viewBox: "0 0 128 128", fill: "currentColor", children: [jsxRuntime.jsx("path", { d: "M93.1675 73.1739C94.5691 74.5758 94.7323 76.7924 93.5515 78.3846L93.1675 78.8326L63.6741 108.326L34.1755 78.8326C32.6908 77.3518 32.6014 74.9761 33.9708 73.3881C35.3401 71.8001 37.7033 71.5391 39.3861 72.7899L39.8341 73.1739L63.6741 97.0137L87.5088 73.1739C88.9104 71.7726 91.1274 71.6092 92.7194 72.7899L93.1674 73.1739H93.1675Z", opacity: "1" }), jsxRuntime.jsx("path", { d: "M34.1714 55.1518C32.7697 53.7499 32.6066 51.5333 33.7874 49.9411L34.1714 49.4931L63.6647 20L93.1634 49.4931C94.6481 50.9739 94.7375 53.3496 93.3681 54.9376C91.9987 56.5256 89.6356 56.7866 87.9527 55.5358L87.5047 55.1517L63.6647 31.312L39.8301 55.1518C38.4285 56.5531 36.2115 56.7165 34.6195 55.5358L34.1715 55.1518L34.1714 55.1518Z", opacity: "0.3" })] })),
561
561
  };
562
562
 
563
563
  function CwIcon(props) {
564
- const { iconId, color, size, title, tooltipPosition = 'bottom', ...iconProps } = props;
564
+ const { iconId, color, size, className, title, tooltipPosition = 'bottom', ...iconProps } = props;
565
565
  const getClassName = (baseClass) => {
566
566
  return [
567
567
  baseClass,
568
568
  color && `cw-color-${color}`,
569
- size && `cw-font-size-${size}`
569
+ size && `cw-font-size-${size}`,
570
+ className
570
571
  ].filter(Boolean).join(' ');
571
572
  };
572
573
  let iconElement;
@@ -978,49 +979,128 @@ function CwImageZoom(image) {
978
979
  } }), jsxRuntime.jsx("div", { style: { color: "#fff", fontSize: "1rem", textAlign: "center" }, children: selectedImage.filename && jsxRuntime.jsx("div", { children: selectedImage.filename }) })] }))] }));
979
980
  }
980
981
 
982
+ let defaults = {};
983
+ /**
984
+ * Register global CwLoading defaults. Call once at app init, before the first render.
985
+ * Merges into any previously configured defaults.
986
+ */
987
+ function configureCwLoading(next) {
988
+ defaults = { ...defaults, ...next };
989
+ }
990
+ /** Read the currently configured CwLoading defaults. */
991
+ function getCwLoadingDefaults() {
992
+ return defaults;
993
+ }
994
+
981
995
  /**
982
- * CwLoading
996
+ * CwLoading — a spinner with optional text that dims the wrapped content while loading.
983
997
  *
984
- * A versatile loading component that shows a spinner with optional text
985
- * and disables the wrapped content while in loading state.
998
+ * Icon resolves as `iconName` prop → `getCwLoadingDefaults().icon` → none (neutral ring).
986
999
  *
987
1000
  * @example
988
- * // Basic usage
989
1001
  * <CwLoading isLoading={isSubmitting}>
990
1002
  * <form>...</form>
991
1003
  * </CwLoading>
992
- *
993
- * // With custom text and size
994
- * <CwLoading
995
- * isLoading={isLoading}
996
- * text="Please wait..."
997
- * size="large"
998
- * >
999
- * <UserProfile />
1000
- * </CwLoading>
1001
1004
  */
1002
- function CwLoading({ isLoading = false, text = '', size = 'regular', iconPosition = 'outside', iconName = 'cwi-plane-solid', animation = 'spin', children }) {
1003
- const iconClasses = `cwi-icons ${iconName || ''}`;
1004
- return (jsxRuntime.jsxs("div", { "aria-busy": isLoading, className: isLoading ? 'cw-loading-container' : '', "data-children": !!children, children: [isLoading && (jsxRuntime.jsxs("div", { className: "cw-loading-content", "data-size": size, "data-animation": animation, children: [jsxRuntime.jsx("div", { className: "cw-loading", "data-icon-position": iconPosition, children: jsxRuntime.jsx("span", { className: iconClasses }) }), text && (jsxRuntime.jsx("p", { children: text }))] })), jsxRuntime.jsx("div", { className: isLoading ? 'cw-loading-disabled-content' : '', children: children })] }));
1005
+ function CwLoading({ isLoading = false, text = '', size = 'regular', iconPosition = 'outside', iconName, animation = 'spin', children }) {
1006
+ let overlay = null;
1007
+ if (isLoading) {
1008
+ const resolvedIcon = iconName ?? getCwLoadingDefaults().icon;
1009
+ overlay = (jsxRuntime.jsxs("div", { className: "cw-loading-content", "data-size": size, "data-animation": animation, role: "status", "aria-label": text || 'Loading', children: [jsxRuntime.jsx("div", { className: "cw-loading", "data-icon-position": iconPosition, "data-has-icon": !!resolvedIcon, children: resolvedIcon && jsxRuntime.jsx("span", { className: `cwi-icons ${resolvedIcon}` }) }), text && (jsxRuntime.jsx("p", { children: text }))] }));
1010
+ }
1011
+ return (jsxRuntime.jsxs("div", { "aria-busy": isLoading, className: "cw-loading-container", "data-children": !!children, children: [overlay, jsxRuntime.jsx("div", { className: "cw-loading-disabled-content", children: children })] }));
1005
1012
  }
1006
1013
 
1014
+ var styles$w = {"skeleton":"cw-skeleton-module__skeleton__Jvx2x","group":"cw-skeleton-module__group__Cm8AU"};
1015
+
1016
+ /*
1017
+ * Internal helper for skeleton allocations (CwSkeleton, tables, cards).
1018
+ * Not exported from the library barrel - not a public API.
1019
+ */
1020
+ /** Upper bound so a pathological count cannot allocate an unbounded number of nodes. */
1021
+ const MAX_SKELETON_COUNT = 100;
1007
1022
  /**
1008
- * @deprecated since may 2025. Use <CwLoading size="small"> instead.
1023
+ * Normalizes a skeleton count to a finite, floored, non-negative integer capped at
1024
+ * MAX_SKELETON_COUNT. Falls back to `fallback` for undefined, NaN, non-finite or
1025
+ * non-positive input, so valid inputs keep the public default behaviour and only
1026
+ * pathological ones are bounded.
1027
+ */
1028
+ function normalizeSkeletonCount(value, fallback) {
1029
+ if (value === undefined || !Number.isFinite(value) || value < 1) {
1030
+ return fallback;
1031
+ }
1032
+ return Math.min(Math.floor(value), MAX_SKELETON_COUNT);
1033
+ }
1034
+
1035
+ /**
1036
+ * CwSkeleton - a shimmering placeholder that reserves the shape of content while it loads.
1009
1037
  *
1010
- * This component will be removed in a future release.
1038
+ * Renders inline <span> elements so it can sit inside text-level contexts. Sizing flows
1039
+ * through component-scoped custom properties; only the props the caller provides are set
1040
+ * inline, so the CSS defaults per variant (and the 60% last-line rule) stay in charge.
1011
1041
  *
1012
1042
  * @example
1013
- * // Instead of:
1014
- * <CwLoadingSmall />
1015
- *
1016
- * // Use:
1017
- * <CwLoading size="small" />
1043
+ * <CwSkeleton count={3} />
1044
+ * <CwSkeleton variant="circle" />
1045
+ * <CwSkeleton variant="rect" height="10rem" />
1018
1046
  */
1019
- function CwLoadingSmall(CwelltLoadingAppointements) {
1020
- return (jsxRuntime.jsx("div", { children: CwelltLoadingAppointements.isLoading === true ? (jsxRuntime.jsx("div", { className: "cw-loading-container", children: jsxRuntime.jsx("div", { className: "cw-loading" }) })) : (jsxRuntime.jsx("div", {})) }));
1047
+ function CwSkeleton({ variant = 'text', width, height, count = 1, radius, gap }) {
1048
+ // Only forward the custom properties the caller actually set; CSS declares the defaults.
1049
+ const style = {
1050
+ ...(width !== undefined && { '--skeleton-width': width }),
1051
+ ...(height !== undefined && { '--skeleton-height': height }),
1052
+ ...(radius !== undefined && { '--skeleton-radius': radius })
1053
+ };
1054
+ // The un-hashed cw-skeleton / cw-skeleton-group classes carry no styles in the
1055
+ // library - they are stable public hooks for exceptional external overrides.
1056
+ const skeletonClassName = ['cw-skeleton', styles$w.skeleton].filter(Boolean).join(' ');
1057
+ const groupClassName = ['cw-skeleton-group', styles$w.group].filter(Boolean).join(' ');
1058
+ const lineCount = normalizeSkeletonCount(count, 1);
1059
+ if (lineCount <= 1) {
1060
+ return (jsxRuntime.jsx("span", { className: skeletonClassName, "data-variant": variant, "aria-hidden": "true", style: style }));
1061
+ }
1062
+ const skeletonElements = Array.from({ length: lineCount }, (_, index) => (jsxRuntime.jsx("span", { className: skeletonClassName, "data-variant": variant, style: style }, index)));
1063
+ const groupStyle = {
1064
+ ...(gap !== undefined && { '--skeleton-gap': gap })
1065
+ };
1066
+ return (jsxRuntime.jsx("span", { className: groupClassName, "aria-hidden": "true", style: groupStyle, children: skeletonElements }));
1021
1067
  }
1022
1068
 
1023
- var styles$t = {"cw-generic-tooltip-content":"cw-generic-tooltip-module__cw-generic-tooltip-content__la-Si","cw-generic-tooltip":"cw-generic-tooltip-module__cw-generic-tooltip__Ij76M"};
1069
+ var styles$v = {"progress":"cw-progress-module__progress__d-g2-","value":"cw-progress-module__value__Q-DrH","header":"cw-progress-module__header__mv5ct","label":"cw-progress-module__label__jwOWp","track":"cw-progress-module__track__572-3","fill":"cw-progress-module__fill__fX1UA"};
1070
+
1071
+ /**
1072
+ * CwProgress - a determinate or indeterminate progress bar.
1073
+ *
1074
+ * Use it for measurable operations (imports, uploads, batch jobs). For short
1075
+ * unmeasurable waits use CwLoading; for initial layout loads use CwSkeleton.
1076
+ *
1077
+ * @example
1078
+ * <CwProgress value={62} label="Import" color="success" />
1079
+ * <CwProgress indeterminate label="Uploading" />
1080
+ */
1081
+ function CwProgress({ value, indeterminate = false, label, rightLabel, size = 'regular', layout = 'row', color = 'primary', monoValue = false, prominent = false }) {
1082
+ const labelId = React.useId();
1083
+ // Determinate: a missing or non-finite value is treated as 0 (never NaN), then
1084
+ // clamped to [0,100] for aria-valuenow and the fill width. Indeterminate has no value.
1085
+ const clamped = indeterminate
1086
+ ? undefined
1087
+ : Math.min(Math.max(Number.isFinite(value) ? value : 0, 0), 100);
1088
+ const percent = clamped !== undefined ? Math.round(clamped) : undefined;
1089
+ const showValue = rightLabel !== undefined || (!indeterminate && percent !== undefined);
1090
+ const valueText = rightLabel ?? (percent !== undefined ? `${percent}%` : '');
1091
+ // The un-hashed cw-progress class carries no styles in the library - a stable
1092
+ // public hook for exceptional external overrides only.
1093
+ const rootClassName = ['cw-progress', styles$v.progress].filter(Boolean).join(' ');
1094
+ const labelSpan = label ? jsxRuntime.jsx("span", { className: styles$v.label, id: labelId, children: label }) : null;
1095
+ const valueLabel = showValue ? (jsxRuntime.jsx("span", { className: styles$v.value, "data-mono": monoValue || undefined, children: valueText })) : null;
1096
+ return (jsxRuntime.jsxs("div", { className: rootClassName, "data-layout": layout, "data-size": size, "data-color": color, "data-prominent": prominent || undefined, "data-indeterminate": indeterminate || undefined, children: [layout === 'column' && (labelSpan || valueLabel) && (jsxRuntime.jsxs("header", { className: styles$v.header, children: [labelSpan, valueLabel] })), layout === 'row' && labelSpan, jsxRuntime.jsx("div", { className: styles$v.track, role: "progressbar", ...(label && { 'aria-labelledby': labelId }), ...(!indeterminate && percent !== undefined && {
1097
+ 'aria-valuenow': percent,
1098
+ 'aria-valuemin': 0,
1099
+ 'aria-valuemax': 100
1100
+ }), children: jsxRuntime.jsx("div", { className: styles$v.fill, style: !indeterminate && clamped !== undefined ? { width: `${clamped}%` } : undefined }) }), layout === 'row' && valueLabel] }));
1101
+ }
1102
+
1103
+ var styles$u = {"cw-generic-tooltip-content":"cw-generic-tooltip-module__cw-generic-tooltip-content__la-Si","cw-generic-tooltip":"cw-generic-tooltip-module__cw-generic-tooltip__Ij76M"};
1024
1104
 
1025
1105
  // Constants moved outside to prevent recreation
1026
1106
  const margin = 16;
@@ -1143,12 +1223,12 @@ const CwGenericTooltip = ({ children, content = null, position = defaultPosition
1143
1223
  const { setTooltipTimeout, clearTooltipTimeout } = useTooltipDelay(() => {
1144
1224
  setIsVisible(true);
1145
1225
  }, showDelay);
1146
- const { position: tooltipPosition, actualPosition } = useTooltipPosition(isVisible, containerRef, position, styles$t["cw-generic-tooltip-content"]);
1226
+ const { position: tooltipPosition, actualPosition } = useTooltipPosition(isVisible, containerRef, position, styles$u["cw-generic-tooltip-content"]);
1147
1227
  // Memoize tooltip content creation
1148
1228
  const tooltipContent = React.useMemo(() => {
1149
1229
  if (hide || !isVisible || !content)
1150
1230
  return null;
1151
- return reactDom.createPortal(jsxRuntime.jsx("div", { className: styles$t["cw-generic-tooltip-content"], "data-position": actualPosition, "data-visible": isVisible, "data-inline": displayInline, style: {
1231
+ return reactDom.createPortal(jsxRuntime.jsx("div", { className: styles$u["cw-generic-tooltip-content"], "data-position": actualPosition, "data-visible": isVisible, "data-inline": displayInline, style: {
1152
1232
  position: 'fixed',
1153
1233
  top: `${tooltipPosition.top}px`,
1154
1234
  left: `${tooltipPosition.left}px`,
@@ -1163,7 +1243,7 @@ const CwGenericTooltip = ({ children, content = null, position = defaultPosition
1163
1243
  clearTooltipTimeout();
1164
1244
  setIsVisible(false);
1165
1245
  }, [clearTooltipTimeout]);
1166
- return (jsxRuntime.jsxs("div", { ref: containerRef, className: styles$t["cw-generic-tooltip"], onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, style: overlayStyle, "data-inline": displayInline, children: [tooltipContent, children] }));
1246
+ return (jsxRuntime.jsxs("div", { ref: containerRef, className: styles$u["cw-generic-tooltip"], onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, style: overlayStyle, "data-inline": displayInline, children: [tooltipContent, children] }));
1167
1247
  };
1168
1248
 
1169
1249
  const CwButton = React.forwardRef(function CwButton({ text, variant = 'solid', color = 'primary', size = 'medium', iconPosition = 'left', pressed, className = '', icon = "", title, tooltipPosition = "bottom", children, ...buttonProps }, ref) {
@@ -1225,7 +1305,7 @@ function CwModal(custModalProps) {
1225
1305
  return (jsxRuntime.jsx("div", { children: custModalProps.modalState && (jsxRuntime.jsxs("div", { className: custModalProps.classNameModalOverlay + " cwelltModalOverlay", children: [jsxRuntime.jsx("div", { className: "cwelltModalOverlayBg", onClick: custModalProps.onCloseModal }), jsxRuntime.jsx(Draggable, { disabled: isModalDisabled, axis: "both", nodeRef: draggableRef, children: jsxRuntime.jsxs("div", { className: custModalProps.classNameModal + " cwelltContainerModal", ref: draggableRef, style: widthModalDef !== "40em" ? modalStyle.widthCustomStyle : modalStyle.widthDefStyle, children: [jsxRuntime.jsxs("div", { className: "cwelltModalHeader", onMouseOver: cwelltOnMouseOverModal, onMouseOut: cwelltOnMouseOutModal, children: [jsxRuntime.jsx("div", { className: "cwelltModalTitle", children: custModalProps.titleModal }), jsxRuntime.jsx("button", { className: "cwelltBtnCloseModal", onClick: custModalProps.onCloseModal, children: jsxRuntime.jsx("span", { className: "cwelltCloseIcon" }) })] }), jsxRuntime.jsx("div", { className: "cwelltModalBody", children: jsxRuntime.jsx("div", { className: "cwelltContainerModalBody", style: { position: "relative" }, children: custModalProps.children }) }), isHide === false ? (jsxRuntime.jsx("footer", { className: "legacy-modal-footer", onMouseOver: cwelltOnMouseOverModal, onMouseOut: cwelltOnMouseOutModal, children: jsxRuntime.jsx(CwButton, { variant: "icon", icon: "save", title: "Save", onClick: custModalProps.onSaveModal, form: custModalProps.formSaveModal, hidden: custModalProps.HideBtnModal, type: custModalProps.HtmlSubmitModal }) })) : (jsxRuntime.jsx("div", { style: { display: "none" } }))] }) })] })) }));
1226
1306
  }
1227
1307
 
1228
- var styles$s = {"overlayPositioned":"CwConfirmationPopup-module__overlayPositioned__11qYB","popup":"CwConfirmationPopup-module__popup__ahPjM","message":"CwConfirmationPopup-module__message__MnNL4","buttons":"CwConfirmationPopup-module__buttons__fGYYE","button":"CwConfirmationPopup-module__button__ugYQE","confirmButton":"CwConfirmationPopup-module__confirmButton__rTP4S","cancelButton":"CwConfirmationPopup-module__cancelButton__Ry694"};
1308
+ var styles$t = {"overlayPositioned":"CwConfirmationPopup-module__overlayPositioned__11qYB","popup":"CwConfirmationPopup-module__popup__ahPjM","message":"CwConfirmationPopup-module__message__MnNL4","buttons":"CwConfirmationPopup-module__buttons__fGYYE","button":"CwConfirmationPopup-module__button__ugYQE","confirmButton":"CwConfirmationPopup-module__confirmButton__rTP4S","cancelButton":"CwConfirmationPopup-module__cancelButton__Ry694"};
1229
1309
 
1230
1310
  function CwConfirmationPopup(props) {
1231
1311
  const { isOpen, onConfirm, onCancel, message = "Are you sure you want to proceed?", confirmText = "Confirm", cancelText = "Cancel", placement = 'bottom', children } = props;
@@ -1289,15 +1369,15 @@ function CwConfirmationPopup(props) {
1289
1369
  onCancel();
1290
1370
  }
1291
1371
  };
1292
- return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [renderChildren(), isOpen && (jsxRuntime.jsx("div", { className: styles$s.overlayPositioned, onClick: handleOverlayClick, children: jsxRuntime.jsxs("div", { ref: popupRef, className: styles$s.popup, style: {
1372
+ return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [renderChildren(), isOpen && (jsxRuntime.jsx("div", { className: styles$t.overlayPositioned, onClick: handleOverlayClick, children: jsxRuntime.jsxs("div", { ref: popupRef, className: styles$t.popup, style: {
1293
1373
  position: 'absolute',
1294
1374
  top: `${position.top}px`,
1295
1375
  left: `${position.left}px`,
1296
1376
  transform: 'none'
1297
- }, children: [jsxRuntime.jsx("p", { className: styles$s.message, children: message }), jsxRuntime.jsxs("div", { className: styles$s.buttons, children: [jsxRuntime.jsx("button", { className: `${styles$s.button} ${styles$s.confirmButton}`, onClick: onConfirm, children: confirmText }), jsxRuntime.jsx("button", { className: `${styles$s.button} ${styles$s.cancelButton}`, onClick: onCancel, children: cancelText })] })] }) }))] }));
1377
+ }, children: [jsxRuntime.jsx("p", { className: styles$t.message, children: message }), jsxRuntime.jsxs("div", { className: styles$t.buttons, children: [jsxRuntime.jsx("button", { className: `${styles$t.button} ${styles$t.confirmButton}`, onClick: onConfirm, children: confirmText }), jsxRuntime.jsx("button", { className: `${styles$t.button} ${styles$t.cancelButton}`, onClick: onCancel, children: cancelText })] })] }) }))] }));
1298
1378
  }
1299
1379
 
1300
- var styles$r = {"cw-dialog-main":"cw-dialog-module__cw-dialog-main__cHxHt","cw-dialog-button-close":"cw-dialog-module__cw-dialog-button-close__9GRd8"};
1380
+ var styles$s = {"cw-dialog-main":"cw-dialog-module__cw-dialog-main__cHxHt","cw-dialog-button-close":"cw-dialog-module__cw-dialog-button-close__9GRd8"};
1301
1381
 
1302
1382
  // Helper function to parse size values
1303
1383
  const parseSize = (size) => {
@@ -1570,7 +1650,7 @@ const CwDialog = props => {
1570
1650
  }
1571
1651
  }
1572
1652
  }, [open]);
1573
- const header = React.useMemo(() => (jsxRuntime.jsxs("header", { onMouseDown: handleMouseDown, children: [jsxRuntime.jsx("span", { children: headline }), customHeader || (jsxRuntime.jsx("button", { className: styles$r["cw-dialog-button-close"], onClick: onClose }))] })), [handleMouseDown, headline, customHeader, onClose]);
1653
+ const header = React.useMemo(() => (jsxRuntime.jsxs("header", { onMouseDown: handleMouseDown, children: [jsxRuntime.jsx("span", { children: headline }), customHeader || (jsxRuntime.jsx("button", { className: styles$s["cw-dialog-button-close"], onClick: onClose }))] })), [handleMouseDown, headline, customHeader, onClose]);
1574
1654
  const content = React.useMemo(() => (jsxRuntime.jsx("section", { children: children })), [children]);
1575
1655
  const footer = React.useMemo(() => (jsxRuntime.jsx("footer", { children: customFooter || (jsxRuntime.jsx(CwButton, { variant: "icon", icon: "save", title: "Save", onClick: onSave, tooltipPosition: "top", disabled: disableSave, "data-testid": "cw-dialog-save" })) })), [customFooter, onSave, disableSave]);
1576
1656
  const resizeHandles = React.useMemo(() => size.autoHeight
@@ -1597,7 +1677,7 @@ const CwDialog = props => {
1597
1677
  : `${convertFromPx(size.height, size.heightUnit)}${size.heightUnit}`;
1598
1678
  return { displayWidth, displayHeight };
1599
1679
  }, [size.width, size.height, size.widthUnit, size.heightUnit, size.autoHeight]);
1600
- const dialogContent = (jsxRuntime.jsx("div", { "data-has-scrim": hasScrim, className: styles$r["cw-dialog-main"], onMouseDown: handleScrimMouseDown, onMouseUp: handleScrimMouseUpOrLeave, onMouseLeave: handleScrimMouseUpOrLeave, "data-pressing": isPressingScrim, children: jsxRuntime.jsxs("dialog", { ...domProps, ref: dialogRef, style: {
1680
+ const dialogContent = (jsxRuntime.jsx("div", { "data-has-scrim": hasScrim, className: styles$s["cw-dialog-main"], onMouseDown: handleScrimMouseDown, onMouseUp: handleScrimMouseUpOrLeave, onMouseLeave: handleScrimMouseUpOrLeave, "data-pressing": isPressingScrim, children: jsxRuntime.jsxs("dialog", { ...domProps, ref: dialogRef, style: {
1601
1681
  left: `${position.x}px`,
1602
1682
  top: `${position.y}px`,
1603
1683
  width: displayDimensions.displayWidth,
@@ -1758,7 +1838,7 @@ function CwAlign(props) {
1758
1838
  }, children: props.children }));
1759
1839
  }
1760
1840
 
1761
- var styles$q = {"card":"cw-card-module__card__HJUT0","clickable":"cw-card-module__clickable__Y-V3X","disabled":"cw-card-module__disabled__0wHh1","loading":"cw-card-module__loading__-fzlx","content":"cw-card-module__content__ma9qy","headerContent":"cw-card-module__headerContent__x4Jfl","footerTags":"cw-card-module__footerTags__80sSW","loadingOverlay":"cw-card-module__loadingOverlay__8-zVV"};
1841
+ var styles$r = {"card":"cw-card-module__card__HJUT0","clickable":"cw-card-module__clickable__Y-V3X","disabled":"cw-card-module__disabled__0wHh1","content":"cw-card-module__content__ma9qy","headerContent":"cw-card-module__headerContent__x4Jfl","footerTags":"cw-card-module__footerTags__80sSW"};
1762
1842
 
1763
1843
  /**
1764
1844
  * CwCard - A simple card component for displaying content in a contained format
@@ -1778,17 +1858,16 @@ var styles$q = {"card":"cw-card-module__card__HJUT0","clickable":"cw-card-module
1778
1858
  * <p>This is the main content of the card.</p>
1779
1859
  * </CwCard>
1780
1860
  **/
1781
- const CwCard = ({ id, title, subtitle, alignment = 'center', children, footer, onEdit, onDelete, extraActions, className = '', clickable = false, onClick, isLoading = false, disabled = false, style, chips = [], variant = "border", direction = "column", layout, }) => {
1861
+ const CwCard = ({ id, title, subtitle, alignment = 'center', children, footer, onEdit, onDelete, extraActions, className = '', clickable = false, onClick, isLoading = false, skeletonLines = 3, disabled = false, style, chips = [], variant = "border", direction = "column", layout, }) => {
1782
1862
  const resolvedDirection = layout?.direction ?? direction;
1783
1863
  const resolvedAlign = layout?.align ?? (alignment === 'left' ? 'start' : 'center');
1784
1864
  // Construct class names using CSS modules
1785
1865
  const cardClassNames = [
1786
1866
  'cw-card',
1787
- styles$q.card,
1867
+ styles$r.card,
1788
1868
  className,
1789
- clickable ? styles$q.clickable : '',
1790
- disabled ? styles$q.disabled : '',
1791
- isLoading ? styles$q.loading : '',
1869
+ clickable ? styles$r.clickable : '',
1870
+ disabled ? styles$r.disabled : '',
1792
1871
  ].filter(Boolean).join(' ');
1793
1872
  // Handle click event when card is clickable
1794
1873
  const handleClick = () => {
@@ -1804,16 +1883,17 @@ const CwCard = ({ id, title, subtitle, alignment = 'center', children, footer, o
1804
1883
  const hasChips = chips.length > 0;
1805
1884
  // Determine if footer should be rendered
1806
1885
  const hasFooter = hasChips || footer || (hasActions && resolvedDirection === "row");
1807
- // Actions component to reuse
1808
- const ActionsComponent = hasActions && !disabled ? (jsxRuntime.jsxs("div", { className: styles$q.actions, children: [extraActions ?? null, onEdit && jsxRuntime.jsx(CwButton, { variant: "icon", icon: "edit", onClick: onEdit }), onDelete && jsxRuntime.jsx(CwButton, { variant: "icon", icon: "delete", color: "danger", onClick: onDelete })] })) : null;
1809
- return (jsxRuntime.jsxs("div", { ...(id && { id }), className: cardClassNames, ...(style && { style }), ...(clickable && {
1886
+ // Actions component to reuse. While loading, each provided action renders a circular
1887
+ // ghost sized to the CwButton icon footprint (2rem) - no interactive buttons.
1888
+ const ActionsComponent = hasActions && !disabled ? (jsxRuntime.jsx("div", { className: styles$r.actions, children: isLoading ? (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [extraActions && jsxRuntime.jsx(CwSkeleton, { variant: "circle", height: "2rem" }), onEdit && jsxRuntime.jsx(CwSkeleton, { variant: "circle", height: "2rem" }), onDelete && jsxRuntime.jsx(CwSkeleton, { variant: "circle", height: "2rem" })] })) : (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [extraActions ?? null, onEdit && jsxRuntime.jsx(CwButton, { variant: "icon", icon: "edit", onClick: onEdit }), onDelete && jsxRuntime.jsx(CwButton, { variant: "icon", icon: "delete", color: "danger", onClick: onDelete })] })) })) : null;
1889
+ return (jsxRuntime.jsxs("div", { ...(id && { id }), className: cardClassNames, ...(style && { style }), ...(clickable && !isLoading && {
1810
1890
  role: 'button',
1811
1891
  tabIndex: 0,
1812
1892
  onClick: handleClick,
1813
- }), "data-variant": variant, "data-direction": resolvedDirection, children: [hasHeader && (jsxRuntime.jsxs("header", { children: [(title || subtitle) && (jsxRuntime.jsxs("div", { className: styles$q.headerContent, "data-align": resolvedAlign, children: [title && jsxRuntime.jsx("h5", { children: title }), subtitle && jsxRuntime.jsx("strong", { children: subtitle })] })), resolvedDirection === "column" && ActionsComponent] })), jsxRuntime.jsx("div", { className: styles$q.content, children: children }), hasFooter && (jsxRuntime.jsxs("footer", { children: [hasChips && (jsxRuntime.jsx("div", { className: styles$q.footerTags, children: chips.map((chip, index) => (jsxRuntime.jsx(CwChip, { label: chip.label, colorScheme: chip.colorScheme, className: styles$q.chip, ...(chip.customColor && { customColor: chip.customColor }), ...(chip.variant && { variant: chip.variant }), ...(chip.icon && { icon: chip.icon }) }, index))) })), footer && (jsxRuntime.jsx("div", { className: styles$q.footerContent, children: footer }))] })), resolvedDirection === "row" && ActionsComponent, isLoading && (jsxRuntime.jsx("div", { className: styles$q.loadingOverlay, children: jsxRuntime.jsx(CwLoading, { isLoading: isLoading, size: "small" }) }))] }));
1893
+ }), "data-variant": variant, "data-direction": resolvedDirection, "aria-busy": isLoading || undefined, children: [isLoading ? (jsxRuntime.jsxs("header", { children: [jsxRuntime.jsx("div", { className: styles$r.headerContent, "data-align": resolvedAlign, children: jsxRuntime.jsx(CwSkeleton, { width: "8rem", height: "1.5em" }) }), resolvedDirection === "column" && ActionsComponent] })) : (hasHeader && (jsxRuntime.jsxs("header", { children: [(title || subtitle) && (jsxRuntime.jsxs("div", { className: styles$r.headerContent, "data-align": resolvedAlign, children: [title && jsxRuntime.jsx("h5", { children: title }), subtitle && jsxRuntime.jsx("strong", { children: subtitle })] })), resolvedDirection === "column" && ActionsComponent] }))), jsxRuntime.jsx("div", { className: styles$r.content, children: isLoading ? jsxRuntime.jsx(CwSkeleton, { count: normalizeSkeletonCount(skeletonLines, 3) }) : children }), hasFooter && (isLoading ? (jsxRuntime.jsx("footer", { children: jsxRuntime.jsx("div", { className: styles$r.footerTags, children: jsxRuntime.jsx(CwSkeleton, { variant: "rect", width: "4rem", height: "1.5em", radius: "1rem" }) }) })) : (jsxRuntime.jsxs("footer", { children: [hasChips && (jsxRuntime.jsx("div", { className: styles$r.footerTags, children: chips.map((chip, index) => (jsxRuntime.jsx(CwChip, { label: chip.label, colorScheme: chip.colorScheme, className: styles$r.chip, ...(chip.customColor && { customColor: chip.customColor }), ...(chip.variant && { variant: chip.variant }), ...(chip.icon && { icon: chip.icon }) }, index))) })), footer && (jsxRuntime.jsx("div", { className: styles$r.footerContent, children: footer }))] }))), resolvedDirection === "row" && ActionsComponent] }));
1814
1894
  };
1815
1895
 
1816
- var styles$p = {"cardContainer":"cw-card-list-module__cardContainer__l3YEh","pagination":"cw-card-list-module__pagination__5Ay78","pageInfo":"cw-card-list-module__pageInfo__uiMel","loading":"cw-card-list-module__loading__cYpND","emptyState":"cw-card-list-module__emptyState__RlqiS"};
1896
+ var styles$q = {"cardContainer":"cw-card-list-module__cardContainer__l3YEh","pagination":"cw-card-list-module__pagination__5Ay78","pageInfo":"cw-card-list-module__pageInfo__uiMel","emptyState":"cw-card-list-module__emptyState__RlqiS"};
1817
1897
 
1818
1898
  /**
1819
1899
  * Option to display in the CwSelect
@@ -1871,7 +1951,7 @@ function CwSelect(props) {
1871
1951
  : selectProps.onChange, children: [placeholder && jsxRuntime.jsx(CwOption, { value: "", children: placeholder }), children] }), buttonProps && jsxRuntime.jsx(CwButton, { ...buttonProps })] })] }), feedbackMessages.map((feedbackItem, index) => (jsxRuntime.jsx("p", { className: "cw-input-info", "data-color": feedbackItem.type, children: feedbackItem.message }, index)))] }));
1872
1952
  }
1873
1953
 
1874
- function CwCardList({ items, renderCard, pageSize = 10, layout = 'grid', defaultCardWidth = 320, cardGap = 16, isLoading = false, emptyState, sortOptions = [], defaultSortKey, keyExtractor, ...htmlProps }) {
1954
+ function CwCardList({ items, renderCard, pageSize = 10, layout = 'grid', defaultCardWidth = 320, cardGap = 16, isLoading = false, skeletonCards = 6, emptyState, sortOptions = [], defaultSortKey, keyExtractor, ...htmlProps }) {
1875
1955
  const [currentPage, setCurrentPage] = React.useState(1);
1876
1956
  const [sortKey, setSortKey] = React.useState(defaultSortKey || sortOptions[0]?.key || '');
1877
1957
  const [sortDirection, setSortDirection] = React.useState('asc');
@@ -1908,10 +1988,10 @@ function CwCardList({ items, renderCard, pageSize = 10, layout = 'grid', default
1908
1988
  icon: sortDirection === 'asc' ? 'arrow-up' : 'arrow-down',
1909
1989
  onClick: () => setSortDirection(prev => prev === 'asc' ? 'desc' : 'asc'),
1910
1990
  title: `Sort ${sortDirection === 'asc' ? 'descending' : 'ascending'}`,
1911
- }, value: sortKey, onChange: (e) => handleSortChange(e.target.value), children: sortOptions.map(option => (jsxRuntime.jsx(CwOption, { value: option.key, children: option.label }, option.key))) }) })), isLoading ? (jsxRuntime.jsx("div", { className: styles$p.loading, children: jsxRuntime.jsx(CwLoading, { isLoading: isLoading }) })) : sortedItems.length === 0 ? (jsxRuntime.jsx("div", { className: styles$p.emptyState, children: emptyState || jsxRuntime.jsx("p", { children: "No items to display" }) })) : (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("div", { className: `${styles$p.cardContainer}`, "data-layout": layout, style: gridStyle, children: visibleItems.map((item, index) => (jsxRuntime.jsx(React.Fragment, { children: renderCard(item, index) }, keyExtractor ? keyExtractor(item, index) : index))) }), totalPages > 1 && (jsxRuntime.jsxs("div", { className: styles$p.pagination, children: [jsxRuntime.jsx(CwButton, { variant: "icon", icon: "chevron-left", disabled: currentPage === 1, onClick: () => setCurrentPage(p => Math.max(1, p - 1)) }), jsxRuntime.jsxs("span", { className: styles$p.pageInfo, children: [currentPage, " / ", totalPages] }), jsxRuntime.jsx(CwButton, { variant: "icon", icon: "chevron-right", disabled: currentPage === totalPages, onClick: () => setCurrentPage(p => Math.min(totalPages, p + 1)) })] }))] }))] }));
1991
+ }, value: sortKey, onChange: (e) => handleSortChange(e.target.value), children: sortOptions.map(option => (jsxRuntime.jsx(CwOption, { value: option.key, children: option.label }, option.key))) }) })), isLoading ? (jsxRuntime.jsx("div", { className: `${styles$q.cardContainer}`, "data-layout": layout, style: gridStyle, "aria-busy": true, children: Array.from({ length: normalizeSkeletonCount(skeletonCards, 6) }, (_, index) => (jsxRuntime.jsx(CwCard, { isLoading: true, children: null }, `skeleton_${index}`))) })) : sortedItems.length === 0 ? (jsxRuntime.jsx("div", { className: styles$q.emptyState, children: emptyState || jsxRuntime.jsx("p", { children: "No items to display" }) })) : (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("div", { className: `${styles$q.cardContainer}`, "data-layout": layout, style: gridStyle, children: visibleItems.map((item, index) => (jsxRuntime.jsx(React.Fragment, { children: renderCard(item, index) }, keyExtractor ? keyExtractor(item, index) : index))) }), totalPages > 1 && (jsxRuntime.jsxs("div", { className: styles$q.pagination, children: [jsxRuntime.jsx(CwButton, { variant: "icon", icon: "chevron-left", disabled: currentPage === 1, onClick: () => setCurrentPage(p => Math.max(1, p - 1)) }), jsxRuntime.jsxs("span", { className: styles$q.pageInfo, children: [currentPage, " / ", totalPages] }), jsxRuntime.jsx(CwButton, { variant: "icon", icon: "chevron-right", disabled: currentPage === totalPages, onClick: () => setCurrentPage(p => Math.min(totalPages, p + 1)) })] }))] }))] }));
1912
1992
  }
1913
1993
 
1914
- var styles$o = {"cw-accordion":"cw-accordion-module__cw-accordion__ErvlW","cw-accordion-body":"cw-accordion-module__cw-accordion-body__xlI8b"};
1994
+ var styles$p = {"cw-accordion":"cw-accordion-module__cw-accordion__ErvlW","cw-accordion-body":"cw-accordion-module__cw-accordion-body__xlI8b"};
1915
1995
 
1916
1996
  /**
1917
1997
  *
@@ -1928,7 +2008,22 @@ function CwAccordionContainer(CwelltAccordionContainerProps) {
1928
2008
  setVisible_accordionBody(!isVisible_accordionBody);
1929
2009
  };
1930
2010
  // #endregion
1931
- return (jsxRuntime.jsxs("div", { className: styles$o["cw-accordion"], style: CwelltAccordionContainerProps.style, "data-open": isVisible_accordionBody, children: [jsxRuntime.jsxs("header", { onClick: () => showAccordionBody(), children: [jsxRuntime.jsx("div", { children: CwelltAccordionContainerProps.desc_text }), jsxRuntime.jsx("button", { className: "cw-button-icon" })] }), jsxRuntime.jsx("div", { className: styles$o["cw-accordion-body"], children: CwelltAccordionContainerProps.children })] }));
2011
+ return (jsxRuntime.jsxs("div", { className: styles$p["cw-accordion"], style: CwelltAccordionContainerProps.style, "data-open": isVisible_accordionBody, children: [jsxRuntime.jsxs("header", { onClick: () => showAccordionBody(), children: [jsxRuntime.jsx("div", { children: CwelltAccordionContainerProps.desc_text }), jsxRuntime.jsx("button", { className: "cw-button-icon" })] }), jsxRuntime.jsx("div", { className: styles$p["cw-accordion-body"], children: CwelltAccordionContainerProps.children })] }));
2012
+ }
2013
+
2014
+ /*
2015
+ * Internal helper for table loading ghosts (CwTable, CwSortableTable).
2016
+ * Not exported from the library barrel - not a public API.
2017
+ */
2018
+ const SKELETON_CELL_WIDTHS = ['85%', '60%', '95%', '70%', '80%', '65%'];
2019
+ /**
2020
+ * Deterministic width for a table ghost cell so skeleton rows look like real,
2021
+ * unevenly sized content. Derived purely from indices - stable across re-renders
2022
+ * (no reshuffling) - and offset by the column count so the pattern does not
2023
+ * repeat identically per row or per column.
2024
+ */
2025
+ function getSkeletonCellWidth(rowIndex, columnIndex, columnCount) {
2026
+ return SKELETON_CELL_WIDTHS[(rowIndex * columnCount + columnIndex) % SKELETON_CELL_WIDTHS.length];
1932
2027
  }
1933
2028
 
1934
2029
  /**
@@ -2000,7 +2095,7 @@ function CwAccordionContainer(CwelltAccordionContainerProps) {
2000
2095
  *
2001
2096
  * @returns React component
2002
2097
  */
2003
- function CwTable({ columns, data, pagination = false, pageSizeOptions = [5, 10, 20, 50], expandedRowRender, onExpand, className, classNameRow, style, classNameContainer, id, testId, textNoData = "No data available at the moment", rowKey = "key", loading = false, scrollHeight, stickyHeader = false, pageLabel = "page", rowSelection }) {
2098
+ function CwTable({ columns, data, pagination = false, pageSizeOptions = [5, 10, 20, 50], expandedRowRender, onExpand, className, classNameRow, style, classNameContainer, id, testId, textNoData = "No data available at the moment", rowKey = "key", loading = false, skeletonRows = 5, scrollHeight, stickyHeader = false, pageLabel = "page", rowSelection }) {
2004
2099
  const [currentPage, setCurrentPage] = React.useState(1);
2005
2100
  const [expandedRowKey, setExpandedRowKey] = React.useState(null);
2006
2101
  const [sortConfig, setSortConfig] = React.useState({
@@ -2138,7 +2233,9 @@ function CwTable({ columns, data, pagination = false, pageSizeOptions = [5, 10,
2138
2233
  };
2139
2234
  const renderTableBody = () => {
2140
2235
  if (loading) {
2141
- return (jsxRuntime.jsx("tr", { children: jsxRuntime.jsx("td", { colSpan: getColSpan(), children: jsxRuntime.jsx("div", { children: "Loading data..." }) }) }));
2236
+ // Ghost rows: rendered outside the data/selection/expand code paths, so they
2237
+ // cannot trigger row click, selection or expansion.
2238
+ return Array.from({ length: normalizeSkeletonCount(skeletonRows, 5) }, (_, rowIndex) => (jsxRuntime.jsxs("tr", { children: [expandedRowRender && jsxRuntime.jsx("td", { className: "cw-table-col-action" }), columns.map((col, columnIndex) => (jsxRuntime.jsx("td", { className: col.className ?? "", children: jsxRuntime.jsx(CwSkeleton, { variant: "text", width: getSkeletonCellWidth(rowIndex, columnIndex, columns.length) }) }, col.key)))] }, `skeleton_${rowIndex}`)));
2142
2239
  }
2143
2240
  if (!paginatedData || paginatedData.length === 0) {
2144
2241
  return (jsxRuntime.jsx("tr", { children: jsxRuntime.jsx("td", { colSpan: getColSpan(), className: "cw-table-cell-empty", style: { textAlign: "center" }, children: textNoData }) }));
@@ -2160,7 +2257,7 @@ function CwTable({ columns, data, pagination = false, pageSizeOptions = [5, 10,
2160
2257
  : "cwi-chevron-right"}` }) })), columns.map(col => (jsxRuntime.jsx("td", { className: col.className ?? "", children: col.render ? col.render(item) : col.dataIndex ? String(item[col.dataIndex] ?? "") : "" }, `${itemKey}_${col.key}`)))] }), expandedRowRender && expandedRowKey === itemKey && (jsxRuntime.jsx("tr", { className: "cw-table-row-expanded", children: jsxRuntime.jsx("td", { colSpan: getColSpan(), children: expandedRowRender(item) }) }))] }, String(itemKey)));
2161
2258
  });
2162
2259
  };
2163
- return (jsxRuntime.jsxs("div", { id: id, "data-testid": testId, className: `cw-table-container${stickyHeader || scrollHeight ? " cw-table-scroll" : ""} ${classNameContainer ?? ""}`, style: { ...(scrollHeight ? { "--table-height": typeof scrollHeight === "number" ? `${scrollHeight}px` : scrollHeight } : {}), ...style }, children: [jsxRuntime.jsxs("table", { className: `cw-table ${className ?? ""}`, style: { width: "100%" }, children: [jsxRuntime.jsx("thead", { children: jsxRuntime.jsxs("tr", { children: [expandedRowRender && jsxRuntime.jsx("th", {}), columns.map(col => (jsxRuntime.jsxs("th", { onClick: () => col.sortable && col.dataIndex && handleSort(col.dataIndex), className: `${col.className ?? ""} ${sortConfig.key === col.dataIndex
2260
+ return (jsxRuntime.jsxs("div", { id: id, "data-testid": testId, className: `cw-table-container${stickyHeader || scrollHeight ? " cw-table-scroll" : ""} ${classNameContainer ?? ""}`, style: { ...(scrollHeight ? { "--table-height": typeof scrollHeight === "number" ? `${scrollHeight}px` : scrollHeight } : {}), ...style }, "aria-busy": loading || undefined, children: [jsxRuntime.jsxs("table", { className: `cw-table ${className ?? ""}`, style: { width: "100%" }, children: [jsxRuntime.jsx("thead", { children: jsxRuntime.jsxs("tr", { children: [expandedRowRender && jsxRuntime.jsx("th", {}), columns.map(col => (jsxRuntime.jsxs("th", { onClick: () => col.sortable && col.dataIndex && handleSort(col.dataIndex), className: `${col.className ?? ""} ${sortConfig.key === col.dataIndex
2164
2261
  ? sortConfig.direction
2165
2262
  : ""}`.trim(), style: {
2166
2263
  cursor: col.sortable ? "pointer" : "default",
@@ -2186,7 +2283,7 @@ function CwTable({ columns, data, pagination = false, pageSizeOptions = [5, 10,
2186
2283
  }, min: 1, max: totalPages }), jsxRuntime.jsx("span", { children: "/" }), jsxRuntime.jsx("span", { children: totalPages }), jsxRuntime.jsx(CwButton, { onClick: () => handlePageChange(currentPage + 1), disabled: currentPage === totalPages || totalPages <= 1, variant: "icon", icon: "chevron-right" }), jsxRuntime.jsx(CwButton, { onClick: () => handlePageChange(totalPages), disabled: currentPage === totalPages || totalPages <= 1, variant: "icon", icon: "chevron-right-double" })] })] }))] }));
2187
2284
  }
2188
2285
 
2189
- var styles$n = {"dropIndicator":"cw-sortable-table-module__dropIndicator__ov-Jz","dragging":"cw-sortable-table-module__dragging__MrLrz","skeletonRow":"cw-sortable-table-module__skeletonRow__vyD0M","skeleton":"cw-sortable-table-module__skeleton__QGXAD","saveBar":"cw-sortable-table-module__saveBar__3OdoZ cw-flex-row cw-align-center-center cw-gap-small"};
2286
+ var styles$o = {"dropIndicator":"cw-sortable-table-module__dropIndicator__ov-Jz","dragging":"cw-sortable-table-module__dragging__MrLrz","saveBar":"cw-sortable-table-module__saveBar__3OdoZ cw-flex-row cw-align-center-center cw-gap-small"};
2190
2287
 
2191
2288
  /**
2192
2289
  * Hook that provides state management for CwSortableTable.
@@ -2249,9 +2346,14 @@ function useSortableTable(initialItems) {
2249
2346
  }
2250
2347
 
2251
2348
  // ─── Drop indicator row ───────────────────────────────────────────────────────
2252
- const DropIndicatorRow = ({ colSpan }) => (jsxRuntime.jsx("tr", { className: styles$n.dropIndicator, "aria-hidden": true, children: jsxRuntime.jsx("td", { colSpan: colSpan, children: jsxRuntime.jsx("div", {}) }) }));
2349
+ const DropIndicatorRow = ({ colSpan }) => (jsxRuntime.jsx("tr", { className: styles$o.dropIndicator, "aria-hidden": true, children: jsxRuntime.jsx("td", { colSpan: colSpan, children: jsxRuntime.jsx("div", {}) }) }));
2253
2350
  // ─── Loading skeleton ─────────────────────────────────────────────────────────
2254
- const LoadingRows = ({ colSpan }) => (jsxRuntime.jsx(jsxRuntime.Fragment, { children: Array.from({ length: 4 }).map((_, i) => (jsxRuntime.jsx("tr", { className: styles$n.skeletonRow, children: jsxRuntime.jsx("td", { colSpan: colSpan, children: jsxRuntime.jsx("div", { className: styles$n.skeleton }) }) }, i))) }));
2351
+ // Plain td cells (no local class): the ghost cells get the same global cw-table
2352
+ // padding as real body cells, so row heights match the loaded rows exactly.
2353
+ // One cell per real column, so column classNames/widths apply to the ghost too.
2354
+ function LoadingRows({ columns, showHandle, skeletonRows }) {
2355
+ return (jsxRuntime.jsx(jsxRuntime.Fragment, { children: Array.from({ length: skeletonRows }).map((_, rowIndex) => (jsxRuntime.jsxs("tr", { children: [showHandle && jsxRuntime.jsx("td", { className: "cw-table-col-action" }), columns.map((col, columnIndex) => (jsxRuntime.jsx("td", { className: col.className ?? "", style: col.width ? { width: col.width } : undefined, children: jsxRuntime.jsx(CwSkeleton, { variant: "text", width: getSkeletonCellWidth(rowIndex, columnIndex, columns.length) }) }, col.key)))] }, rowIndex))) }));
2356
+ }
2255
2357
  // ─── Component ────────────────────────────────────────────────────────────────
2256
2358
  /**
2257
2359
  * CwSortableTable
@@ -2268,7 +2370,7 @@ const LoadingRows = ({ colSpan }) => (jsxRuntime.jsx(jsxRuntime.Fragment, { chil
2268
2370
  * - Reorder is calculated in onDragEnd using lastValidDropIndex
2269
2371
  * - draggedItem is tracked in state, not via dataTransfer
2270
2372
  */
2271
- function CwSortableTable({ columns, data, rowKey = "key", onReorder, loading = false, textNoData = "No data available", className, tableClassName, maxHeight, showHandle = true, style, saveLabel = "Save order", discardLabel = "Discard", }) {
2373
+ function CwSortableTable({ columns, data, rowKey = "key", onReorder, loading = false, skeletonRows = 5, textNoData = "No data available", className, tableClassName, maxHeight, showHandle = true, style, saveLabel = "Save order", discardLabel = "Discard", }) {
2272
2374
  const { items, hasChanges, handleReorder, handleSave, handleDiscard, } = useSortableTable(data);
2273
2375
  // Drag state lives in the component, same as CwSortableList
2274
2376
  const [draggedItem, setDraggedItem] = React.useState(null);
@@ -2287,11 +2389,15 @@ function CwSortableTable({ columns, data, rowKey = "key", onReorder, loading = f
2287
2389
  setLastValidDropIndex(null);
2288
2390
  };
2289
2391
  const handleDragStart = (e, item) => {
2392
+ if (loading)
2393
+ return;
2290
2394
  setDraggedItem(item);
2291
2395
  setLastValidDropIndex(null);
2292
2396
  e.dataTransfer.effectAllowed = "move";
2293
2397
  };
2294
2398
  const handleDragOver = (e, index) => {
2399
+ if (loading)
2400
+ return;
2295
2401
  e.preventDefault();
2296
2402
  if (!draggedItem)
2297
2403
  return;
@@ -2304,6 +2410,11 @@ function CwSortableTable({ columns, data, rowKey = "key", onReorder, loading = f
2304
2410
  }
2305
2411
  };
2306
2412
  const handleDragEnd = () => {
2413
+ // Never persist a reorder computed against stale/ghost data while loading.
2414
+ if (loading) {
2415
+ cleanupDragState();
2416
+ return;
2417
+ }
2307
2418
  if (draggedItem && lastValidDropIndex !== null) {
2308
2419
  const dragIndex = items.findIndex(item => item[rowKey] === draggedItem[rowKey]);
2309
2420
  if (dragIndex !== lastValidDropIndex && dragIndex !== lastValidDropIndex - 1) {
@@ -2330,7 +2441,7 @@ function CwSortableTable({ columns, data, rowKey = "key", onReorder, loading = f
2330
2441
  };
2331
2442
  const renderBody = () => {
2332
2443
  if (loading) {
2333
- return jsxRuntime.jsx(LoadingRows, { colSpan: totalCols });
2444
+ return jsxRuntime.jsx(LoadingRows, { columns: columns, showHandle: showHandle, skeletonRows: normalizeSkeletonCount(skeletonRows, 5) });
2334
2445
  }
2335
2446
  if (!items || items.length === 0) {
2336
2447
  return (jsxRuntime.jsx("tr", { children: jsxRuntime.jsx("td", { colSpan: totalCols, className: "cw-table-cell-empty", style: { textAlign: "center" }, children: textNoData }) }));
@@ -2338,11 +2449,11 @@ function CwSortableTable({ columns, data, rowKey = "key", onReorder, loading = f
2338
2449
  return items.map((item, index) => {
2339
2450
  const key = item[rowKey];
2340
2451
  const isDragging = draggedItem?.[rowKey] === key;
2341
- return (jsxRuntime.jsxs(React.Fragment, { children: [dropIndicatorIndex === index && (jsxRuntime.jsx(DropIndicatorRow, { colSpan: totalCols })), jsxRuntime.jsxs("tr", { draggable: true, onDragStart: (e) => handleDragStart(e, item), onDragOver: (e) => handleDragOver(e, index), onDragEnd: handleDragEnd, className: isDragging ? styles$n.dragging : "", children: [showHandle && (jsxRuntime.jsx("td", { className: "cw-table-col-action", children: jsxRuntime.jsx(CwIcon, { iconId: "grip-dots", color: "neutral", style: { opacity: 0.75 } }) })), columns.map(col => (jsxRuntime.jsx("td", { className: col.className ?? "", style: col.width ? { width: col.width } : undefined, children: renderCell(item, col) }, `${String(key)}_${col.key}`)))] }), index === items.length - 1 && dropIndicatorIndex === items.length && (jsxRuntime.jsx(DropIndicatorRow, { colSpan: totalCols }))] }, String(key)));
2452
+ return (jsxRuntime.jsxs(React.Fragment, { children: [dropIndicatorIndex === index && (jsxRuntime.jsx(DropIndicatorRow, { colSpan: totalCols })), jsxRuntime.jsxs("tr", { draggable: true, onDragStart: (e) => handleDragStart(e, item), onDragOver: (e) => handleDragOver(e, index), onDragEnd: handleDragEnd, className: isDragging ? styles$o.dragging : "", children: [showHandle && (jsxRuntime.jsx("td", { className: "cw-table-col-action", children: jsxRuntime.jsx(CwIcon, { iconId: "grip-dots", color: "neutral", style: { opacity: 0.75 } }) })), columns.map(col => (jsxRuntime.jsx("td", { className: col.className ?? "", style: col.width ? { width: col.width } : undefined, children: renderCell(item, col) }, `${String(key)}_${col.key}`)))] }), index === items.length - 1 && dropIndicatorIndex === items.length && (jsxRuntime.jsx(DropIndicatorRow, { colSpan: totalCols }))] }, String(key)));
2342
2453
  });
2343
2454
  };
2344
2455
  // ── Render ──────────────────────────────────────────────────────────────
2345
- return (jsxRuntime.jsxs("div", { className: `cw-table-container ${className ?? ""}`, style: containerStyle, children: [jsxRuntime.jsxs("table", { className: `cw-table cw-sortable-table ${tableClassName ?? ""}`, style: { width: "100%" }, children: [jsxRuntime.jsx("thead", { children: jsxRuntime.jsxs("tr", { children: [showHandle && jsxRuntime.jsx("th", { className: "cw-table-col-action" }), columns.map(col => (jsxRuntime.jsx("th", { className: col.className ?? "", style: col.width ? { width: col.width, minWidth: 50 } : undefined, children: col.title }, col.key)))] }) }), jsxRuntime.jsx("tbody", { children: renderBody() })] }), hasChanges && (jsxRuntime.jsxs("footer", { className: styles$n.saveBar, children: [jsxRuntime.jsx(CwButton, { variant: "outline", color: "neutral", icon: "undo", text: discardLabel, onClick: handleDiscard }), jsxRuntime.jsx(CwButton, { variant: "solid", color: "primary", icon: "save", text: saveLabel, onClick: () => handleSave(onReorder) })] }))] }));
2456
+ return (jsxRuntime.jsxs("div", { className: `cw-table-container ${className ?? ""}`, style: containerStyle, "aria-busy": loading || undefined, children: [jsxRuntime.jsxs("table", { className: `cw-table cw-sortable-table ${tableClassName ?? ""}`, style: { width: "100%" }, children: [jsxRuntime.jsx("thead", { children: jsxRuntime.jsxs("tr", { children: [showHandle && jsxRuntime.jsx("th", { className: "cw-table-col-action" }), columns.map(col => (jsxRuntime.jsx("th", { className: col.className ?? "", style: col.width ? { width: col.width, minWidth: 50 } : undefined, children: col.title }, col.key)))] }) }), jsxRuntime.jsx("tbody", { children: renderBody() })] }), !loading && hasChanges && (jsxRuntime.jsxs("footer", { className: styles$o.saveBar, children: [jsxRuntime.jsx(CwButton, { variant: "outline", color: "neutral", icon: "undo", text: discardLabel, onClick: handleDiscard }), jsxRuntime.jsx(CwButton, { variant: "solid", color: "primary", icon: "save", text: saveLabel, onClick: () => handleSave(onReorder) })] }))] }));
2346
2457
  }
2347
2458
 
2348
2459
  /**
@@ -2398,7 +2509,7 @@ function CwSortableTable({ columns, data, rowKey = "key", onReorder, loading = f
2398
2509
  *
2399
2510
  * @returns React component
2400
2511
  */
2401
- function CwTableServerSide({ columns, data, totalItems, pagination = false, pageSizeOptions = [5, 10, 20, 50], pageLabel = "page", expandedRowRender, onExpand, className, classNameRow, style, classNameContainer, id, testId, textNoData = "No data available at the moment", rowKey = "key", loading = false, scrollHeight, stickyHeader = false, rowSelection, onChange, serverState, }) {
2512
+ function CwTableServerSide({ columns, data, totalItems, pagination = false, pageSizeOptions = [5, 10, 20, 50], pageLabel = "page", expandedRowRender, onExpand, className, classNameRow, style, classNameContainer, id, testId, textNoData = "No data available at the moment", rowKey = "key", loading = false, skeletonRows = 5, scrollHeight, stickyHeader = false, rowSelection, onChange, serverState, }) {
2402
2513
  const [internalState, setInternalState] = React.useState({
2403
2514
  page: 1,
2404
2515
  pageSize: pageSizeOptions[0],
@@ -2499,7 +2610,9 @@ function CwTableServerSide({ columns, data, totalItems, pagination = false, page
2499
2610
  };
2500
2611
  const renderTableBody = () => {
2501
2612
  if (loading) {
2502
- return (jsxRuntime.jsx("tr", { children: jsxRuntime.jsx("td", { colSpan: getColSpan(), children: jsxRuntime.jsx("div", { children: "Loading data..." }) }) }));
2613
+ // Ghost rows: rendered outside the data/selection/expand code paths, so they
2614
+ // cannot trigger row click, selection or expansion.
2615
+ return Array.from({ length: normalizeSkeletonCount(skeletonRows, 5) }, (_, rowIndex) => (jsxRuntime.jsxs("tr", { children: [expandedRowRender && jsxRuntime.jsx("td", { className: "cw-table-col-action" }), columns.map((col, columnIndex) => (jsxRuntime.jsx("td", { className: col.className ?? "", children: jsxRuntime.jsx(CwSkeleton, { variant: "text", width: getSkeletonCellWidth(rowIndex, columnIndex, columns.length) }) }, col.key)))] }, `skeleton_${rowIndex}`)));
2503
2616
  }
2504
2617
  if (!data || data.length === 0) {
2505
2618
  return (jsxRuntime.jsx("tr", { children: jsxRuntime.jsx("td", { colSpan: getColSpan(), className: "cw-table-cell-empty", style: { textAlign: "center" }, children: textNoData }) }));
@@ -2517,7 +2630,7 @@ function CwTableServerSide({ columns, data, totalItems, pagination = false, page
2517
2630
  }, children: [expandedRowRender && (jsxRuntime.jsx("td", { className: "cw-table-col-action cw-table-col-expand", children: jsxRuntime.jsx("button", { onClick: () => handleRowExpand(item), className: `cw-button-icon ${expandedRowKey === itemKey ? "cwi-chevron-down" : "cwi-chevron-right"}` }) })), columns.map((col) => (jsxRuntime.jsx("td", { className: col.className ?? "", children: col.render ? col.render(item) : col.dataIndex ? String(item[col.dataIndex] ?? "") : "" }, `${itemKey}_${col.key}`)))] }), expandedRowRender && expandedRowKey === itemKey && (jsxRuntime.jsx("tr", { className: "cw-table-row-expanded", children: jsxRuntime.jsx("td", { colSpan: getColSpan(), children: expandedRowRender(item) }) }))] }, String(itemKey)));
2518
2631
  });
2519
2632
  };
2520
- return (jsxRuntime.jsxs("div", { id: id, "data-testid": testId, className: `cw-table-container${stickyHeader || scrollHeight ? " cw-table-scroll" : ""} ${classNameContainer ?? ""}`, style: { ...(scrollHeight ? { "--table-height": typeof scrollHeight === "number" ? `${scrollHeight}px` : scrollHeight } : {}), ...style }, children: [jsxRuntime.jsxs("table", { className: `cw-table ${className ?? ""}`, style: { width: "100%" }, children: [jsxRuntime.jsx("thead", { children: jsxRuntime.jsxs("tr", { children: [expandedRowRender && jsxRuntime.jsx("th", {}), columns.map((col) => (jsxRuntime.jsxs("th", { onClick: () => col.sortable && col.dataIndex && handleSort(col.dataIndex), className: `${col.className ?? ""} ${state.sortKey === col.dataIndex ? state.sortDirection : ""}`.trim(), style: {
2633
+ return (jsxRuntime.jsxs("div", { id: id, "data-testid": testId, className: `cw-table-container${stickyHeader || scrollHeight ? " cw-table-scroll" : ""} ${classNameContainer ?? ""}`, style: { ...(scrollHeight ? { "--table-height": typeof scrollHeight === "number" ? `${scrollHeight}px` : scrollHeight } : {}), ...style }, "aria-busy": loading || undefined, children: [jsxRuntime.jsxs("table", { className: `cw-table ${className ?? ""}`, style: { width: "100%" }, children: [jsxRuntime.jsx("thead", { children: jsxRuntime.jsxs("tr", { children: [expandedRowRender && jsxRuntime.jsx("th", {}), columns.map((col) => (jsxRuntime.jsxs("th", { onClick: () => col.sortable && col.dataIndex && handleSort(col.dataIndex), className: `${col.className ?? ""} ${state.sortKey === col.dataIndex ? state.sortDirection : ""}`.trim(), style: {
2521
2634
  cursor: col.sortable ? "pointer" : "default",
2522
2635
  userSelect: "none",
2523
2636
  width: columnWidths[col.key] ?? col.width,
@@ -2541,7 +2654,7 @@ function CwTableServerSide({ columns, data, totalItems, pagination = false, page
2541
2654
  }, min: 1, max: totalPages }), jsxRuntime.jsx("span", { children: "/" }), jsxRuntime.jsx("span", { children: totalPages }), jsxRuntime.jsx(CwButton, { onClick: () => handlePageChange(state.page + 1), disabled: state.page === totalPages || totalPages <= 1, variant: "icon", icon: "chevron-right" }), jsxRuntime.jsx(CwButton, { onClick: () => handlePageChange(totalPages), disabled: state.page === totalPages || totalPages <= 1, variant: "icon", icon: "chevron-right-double" })] })] }))] }));
2542
2655
  }
2543
2656
 
2544
- var styles$m = {"cw-tabs":"cw-tabs-module__cw-tabs__1pmji","badge":"cw-tabs-module__badge__AmVxW","cw-tabs-content":"cw-tabs-module__cw-tabs-content__HTp8d"};
2657
+ var styles$n = {"cw-tabs":"cw-tabs-module__cw-tabs__1pmji","badge":"cw-tabs-module__badge__AmVxW","cw-tabs-content":"cw-tabs-module__cw-tabs-content__HTp8d"};
2545
2658
 
2546
2659
  const TabIcon = ({ icon }) => {
2547
2660
  if (!icon)
@@ -2591,7 +2704,7 @@ function CwTabs(CwTabsProps) {
2591
2704
  const tabsListStyle = position === 'left' && CwTabsProps.tabsListWidth
2592
2705
  ? { minWidth: CwTabsProps.tabsListWidth }
2593
2706
  : undefined;
2594
- return (jsxRuntime.jsxs("div", { id: CwTabsProps.id, "data-testid": CwTabsProps.testId, className: styles$m['cw-tabs'] + (CwTabsProps.className ? ` ${CwTabsProps.className}` : "") + "", style: CwTabsProps.style, "data-tabs-position": position, children: [jsxRuntime.jsx("ul", { style: tabsListStyle, children: CwTabsProps.tabs.map(tab => (jsxRuntime.jsxs("li", { className: `${tab.key === activeTab ? "cw-tab-active" : ""}`, onClick: () => handleTabClick(tab), "data-active": tab.key === activeTab, "data-tab-key": tab.key, children: [jsxRuntime.jsx(TabIcon, { icon: tab.icon }), tab.title, (tab.badge !== undefined || tab.badgeColor) && (jsxRuntime.jsx("span", { className: styles$m['badge'], style: tab.badgeColor ? { backgroundColor: tab.badgeColor, color: getContrastColor(tab.badgeColor) } : undefined, children: tab.badge }))] }, tab.key))) }), jsxRuntime.jsx("div", { className: styles$m['cw-tabs-content'], "data-active-tab-key": activeTab ?? undefined, children: activeTab !== null && CwTabsProps.tabs.find(tab => tab.key === activeTab)?.content })] }));
2707
+ return (jsxRuntime.jsxs("div", { id: CwTabsProps.id, "data-testid": CwTabsProps.testId, className: styles$n['cw-tabs'] + (CwTabsProps.className ? ` ${CwTabsProps.className}` : "") + "", style: CwTabsProps.style, "data-tabs-position": position, children: [jsxRuntime.jsx("ul", { style: tabsListStyle, children: CwTabsProps.tabs.map(tab => (jsxRuntime.jsxs("li", { className: `${tab.key === activeTab ? "cw-tab-active" : ""}`, onClick: () => handleTabClick(tab), "data-active": tab.key === activeTab, "data-tab-key": tab.key, children: [jsxRuntime.jsx(TabIcon, { icon: tab.icon }), tab.title, (tab.badge !== undefined || tab.badgeColor) && (jsxRuntime.jsx("span", { className: styles$n['badge'], style: tab.badgeColor ? { backgroundColor: tab.badgeColor, color: getContrastColor(tab.badgeColor) } : undefined, children: tab.badge }))] }, tab.key))) }), jsxRuntime.jsx("div", { className: styles$n['cw-tabs-content'], "data-active-tab-key": activeTab ?? undefined, style: CwTabsProps.contentHeight ? { '--tabs-height': CwTabsProps.contentHeight } : undefined, children: activeTab !== null && CwTabsProps.tabs.find(tab => tab.key === activeTab)?.content })] }));
2595
2708
  }
2596
2709
 
2597
2710
  /**
@@ -2618,9 +2731,17 @@ const CwExpandable = ({ briefing, onToggle, onOpen, onClose, children, ...detail
2618
2731
  return (jsxRuntime.jsxs("details", { ref: myRef, ...detailsProps, className: "cw-expandable", children: [jsxRuntime.jsx("summary", { children: briefing }), children && jsxRuntime.jsx("section", { children: children })] }));
2619
2732
  };
2620
2733
 
2621
- var styles$l = {"cw-master-detail":"cw-master-detail-module__cw-master-detail__O8-FA","resizer":"cw-master-detail-module__resizer__hvGhL","detail":"cw-master-detail-module__detail__BG4Dm","detail-empty":"cw-master-detail-module__detail-empty__KFScK"};
2734
+ var styles$m = {"cw-master-detail":"cw-master-detail-module__cw-master-detail__O8-FA","resizer":"cw-master-detail-module__resizer__hvGhL","detail":"cw-master-detail-module__detail__BG4Dm","skeletonRow":"cw-master-detail-module__skeletonRow__6BUgt","detailSkeleton":"cw-master-detail-module__detailSkeleton__GcDS4","detail-empty":"cw-master-detail-module__detail-empty__KFScK"};
2622
2735
 
2623
- const CwMasterDetail = ({ id, className, style, items, selectedKey, onSelect, detailContent, emptyDetail, searchPlaceholder = 'Search...', onSearch, masterHeader, masterFooter, masterWidth: initialWidth = 320, minMasterWidth = 240, maxMasterWidth = 500, resizable = true, showSearch = true, }) => {
2736
+ /*
2737
+ * Fixed rem widths for the ghosts: the master rows and detail panel size their
2738
+ * content freely, so a percentage-width skeleton would resolve to 100% of ~0 and
2739
+ * collapse to nothing. Fixed widths render regardless of layout. Cycled so rows do
2740
+ * not all look identical.
2741
+ */
2742
+ const MASTER_TITLE_WIDTHS = ['9rem', '11rem', '8rem', '10rem'];
2743
+ const MASTER_SUBTITLE_WIDTH = '5rem';
2744
+ const CwMasterDetail = ({ id, className, style, items, selectedKey, onSelect, detailContent, emptyDetail, searchPlaceholder = 'Search...', onSearch, masterHeader, masterFooter, masterWidth: initialWidth = 320, minMasterWidth = 240, maxMasterWidth = 500, resizable = true, showSearch = true, loading = false, skeletonRows = 5, }) => {
2624
2745
  const [masterWidth, setMasterWidth] = React.useState(initialWidth);
2625
2746
  const [isResizing, setIsResizing] = React.useState(false);
2626
2747
  const containerRef = React.useRef(null);
@@ -2654,12 +2775,22 @@ const CwMasterDetail = ({ id, className, style, items, selectedKey, onSelect, de
2654
2775
  document.body.style.userSelect = '';
2655
2776
  };
2656
2777
  }, [isResizing, minMasterWidth, maxMasterWidth]);
2657
- const rootClassName = [styles$l['cw-master-detail'], className].filter(Boolean).join(' ');
2658
- return (jsxRuntime.jsxs("div", { id: id, ref: containerRef, className: rootClassName, style: style, children: [jsxRuntime.jsxs("aside", { style: { width: masterWidth, minWidth: masterWidth }, children: [showSearch && (jsxRuntime.jsx("search", { children: jsxRuntime.jsx("input", { type: "text", placeholder: searchPlaceholder, onChange: (e) => onSearch?.(e.target.value) }) })), masterHeader && (jsxRuntime.jsx("header", { children: masterHeader })), jsxRuntime.jsx("ul", { children: items.map((item) => (jsxRuntime.jsx("li", { "data-master-key": item.key, "data-selected": item.key === selectedKey, "data-disabled": item.disabled, onClick: () => onSelect?.(item.key), children: item.content }, item.key))) }), masterFooter && (jsxRuntime.jsx("footer", { children: masterFooter }))] }), resizable && (jsxRuntime.jsx("div", { className: styles$l.resizer, "data-resizing": isResizing, onMouseDown: handleMouseDown })), jsxRuntime.jsx("section", { className: styles$l.detail, children: selectedKey && detailContent
2778
+ const rootClassName = [styles$m['cw-master-detail'], className].filter(Boolean).join(' ');
2779
+ return (jsxRuntime.jsxs("div", { id: id, ref: containerRef, className: rootClassName, style: style, "aria-busy": loading || undefined, children: [jsxRuntime.jsxs("aside", { style: { width: masterWidth, minWidth: masterWidth }, children: [showSearch && (jsxRuntime.jsx("search", { children: jsxRuntime.jsx("input", { type: "text", placeholder: searchPlaceholder, onChange: (e) => onSearch?.(e.target.value) }) })), masterHeader && (jsxRuntime.jsx("header", { children: masterHeader })), jsxRuntime.jsx("ul", { children: loading
2780
+ ? Array.from({ length: skeletonRows }, (_unused, rowIndex) => (jsxRuntime.jsxs("li", { "aria-hidden": "true", children: [jsxRuntime.jsx(CwSkeleton, { variant: "circle", height: "2rem" }), jsxRuntime.jsxs("div", { className: styles$m.skeletonRow, children: [jsxRuntime.jsx(CwSkeleton, { variant: "text", width: MASTER_TITLE_WIDTHS[rowIndex % MASTER_TITLE_WIDTHS.length] }), jsxRuntime.jsx(CwSkeleton, { variant: "text", width: MASTER_SUBTITLE_WIDTH })] })] }, `skeleton_${rowIndex}`)))
2781
+ : items.map((item) => (jsxRuntime.jsx("li", { "data-master-key": item.key, "data-selected": item.key === selectedKey, "data-disabled": item.disabled, onClick: () => onSelect?.(item.key), children: item.content }, item.key))) }), masterFooter && (jsxRuntime.jsx("footer", { children: masterFooter }))] }), resizable && (jsxRuntime.jsx("div", { className: styles$m.resizer, "data-resizing": isResizing, onMouseDown: handleMouseDown })), jsxRuntime.jsx("section", { className: styles$m.detail, children: loading ? (jsxRuntime.jsxs("div", { className: styles$m.detailSkeleton, "aria-hidden": "true", children: [jsxRuntime.jsx(CwSkeleton, { variant: "text", width: "14rem", height: "1.5em" }), jsxRuntime.jsx(CwSkeleton, { variant: "text", width: "22rem" }), jsxRuntime.jsx(CwSkeleton, { variant: "text", width: "18rem" }), jsxRuntime.jsx(CwSkeleton, { variant: "text", width: "20rem" })] })) : selectedKey && detailContent
2659
2782
  ? detailContent
2660
- : (jsxRuntime.jsx("div", { className: styles$l['detail-empty'], children: emptyDetail ?? 'Select an item to view details' })) })] }));
2783
+ : (jsxRuntime.jsx("div", { className: styles$m['detail-empty'], children: emptyDetail ?? 'Select an item to view details' })) })] }));
2661
2784
  };
2662
2785
 
2786
+ /*
2787
+ * Fixed rem widths (not percentages): dt and dd size to their content in the list
2788
+ * item, so a percentage-width skeleton would resolve to 100% of ~0 and collapse to
2789
+ * nothing. Fixed widths are visible in both row (dt beside dd) and column (dt above
2790
+ * dd) item layouts. Cycled by row so keys and values do not all look identical.
2791
+ */
2792
+ const SKELETON_KEY_WIDTHS = ["5rem", "6.5rem", "4.5rem", "6rem"];
2793
+ const SKELETON_VALUE_WIDTHS = ["8rem", "6rem", "9rem", "7rem"];
2663
2794
  /**
2664
2795
  * A component for displaying key-value pairs in a definition list format
2665
2796
  * Used for read-only display of structured data
@@ -2673,16 +2804,23 @@ const CwMasterDetail = ({ id, className, style, items, selectedKey, onSelect, de
2673
2804
  * emptyValue="N/A"
2674
2805
  * />
2675
2806
  */
2676
- const CwKeyValueList = ({ items, className = "", emptyValue = "-", direction = "row", groupLayout, itemLayout, ...htmlProps }) => {
2807
+ const CwKeyValueList = ({ items, className = "", emptyValue = "-", direction = "row", loading = false, skeletonRows = 4, groupLayout, itemLayout, ...htmlProps }) => {
2677
2808
  const itemDirection = itemLayout?.direction ?? direction;
2678
- return (jsxRuntime.jsx("dl", { className: `cw-keyvalue-list ${className}`, "data-direction": groupLayout?.direction, "data-align": groupLayout?.align, "data-justify": groupLayout?.justify, "data-gap": groupLayout?.gap, ...htmlProps, children: items.map(item => (jsxRuntime.jsxs("div", { className: `cw-keyvalue-list-item cw-flex-${itemDirection}`, "data-align": itemLayout?.align, "data-justify": itemLayout?.justify, "data-gap": itemLayout?.gap, children: [jsxRuntime.jsx("dt", { children: item.label }), jsxRuntime.jsx("dd", { children: item.value !== undefined && item.value !== null && item.value !== ""
2809
+ const renderItems = () => {
2810
+ if (loading) {
2811
+ // The whole list comes from one data load, so both key and value ghost.
2812
+ return Array.from({ length: skeletonRows }, (_unused, rowIndex) => (jsxRuntime.jsxs("div", { className: `cw-keyvalue-list-item cw-flex-${itemDirection}`, "data-align": itemLayout?.align, "data-justify": itemLayout?.justify, "data-gap": itemLayout?.gap, "aria-hidden": "true", children: [jsxRuntime.jsx("dt", { children: jsxRuntime.jsx(CwSkeleton, { variant: "text", width: SKELETON_KEY_WIDTHS[rowIndex % SKELETON_KEY_WIDTHS.length] }) }), jsxRuntime.jsx("dd", { children: jsxRuntime.jsx(CwSkeleton, { variant: "text", width: SKELETON_VALUE_WIDTHS[rowIndex % SKELETON_VALUE_WIDTHS.length] }) })] }, `skeleton_${rowIndex}`)));
2813
+ }
2814
+ return items.map(item => (jsxRuntime.jsxs("div", { className: `cw-keyvalue-list-item cw-flex-${itemDirection}`, "data-align": itemLayout?.align, "data-justify": itemLayout?.justify, "data-gap": itemLayout?.gap, children: [jsxRuntime.jsx("dt", { children: item.label }), jsxRuntime.jsx("dd", { children: item.value !== undefined && item.value !== null && item.value !== ""
2679
2815
  ? (React.isValidElement(item.value)
2680
2816
  ? item.value
2681
2817
  : `${item.value}${item.suffix ? ` ${item.suffix}` : ''}`)
2682
- : emptyValue })] }, item.key))) }));
2818
+ : emptyValue })] }, item.key)));
2819
+ };
2820
+ return (jsxRuntime.jsx("dl", { className: `cw-keyvalue-list ${className}`, "data-direction": groupLayout?.direction, "data-align": groupLayout?.align, "data-justify": groupLayout?.justify, "data-gap": groupLayout?.gap, "aria-busy": loading || undefined, ...htmlProps, children: renderItems() }));
2683
2821
  };
2684
2822
 
2685
- var styles$k = {"sortableList":"cw-sortable-list-module__sortableList__PyLO-","sortableItem":"cw-sortable-list-module__sortableItem__FAnn2","readOnly":"cw-sortable-list-module__readOnly__r7GcH","dragging":"cw-sortable-list-module__dragging__MD715","moved":"cw-sortable-list-module__moved__sE6-N","expandedContent":"cw-sortable-list-module__expandedContent__Kocna","sortableHandle":"cw-sortable-list-module__sortableHandle__HvYBK","sortableContent":"cw-sortable-list-module__sortableContent__C6JhR","sortableTitle":"cw-sortable-list-module__sortableTitle__EgWXr","sortableExtraContent":"cw-sortable-list-module__sortableExtraContent__s4LSv","sortableActions":"cw-sortable-list-module__sortableActions__gwQOU","dropIndicator":"cw-sortable-list-module__dropIndicator__MNSF-","emptyMessage":"cw-sortable-list-module__emptyMessage__gMpaL"};
2823
+ var styles$l = {"sortableList":"cw-sortable-list-module__sortableList__PyLO-","sortableItem":"cw-sortable-list-module__sortableItem__FAnn2","readOnly":"cw-sortable-list-module__readOnly__r7GcH","dragging":"cw-sortable-list-module__dragging__MD715","moved":"cw-sortable-list-module__moved__sE6-N","expandedContent":"cw-sortable-list-module__expandedContent__Kocna","sortableHandle":"cw-sortable-list-module__sortableHandle__HvYBK","sortableContent":"cw-sortable-list-module__sortableContent__C6JhR","sortableTitle":"cw-sortable-list-module__sortableTitle__EgWXr","sortableExtraContent":"cw-sortable-list-module__sortableExtraContent__s4LSv","sortableActions":"cw-sortable-list-module__sortableActions__gwQOU","dropIndicator":"cw-sortable-list-module__dropIndicator__MNSF-","emptyMessage":"cw-sortable-list-module__emptyMessage__gMpaL"};
2686
2824
 
2687
2825
  function CwSortableList({ items, onReorder, renderItem, className = '', movedItems = new Set(), emptyMessage = "No elements to show", readOnly = false, maxHeight = "300px", }) {
2688
2826
  const [draggedItem, setDraggedItem] = React.useState(null);
@@ -2745,15 +2883,15 @@ function CwSortableList({ items, onReorder, renderItem, className = '', movedIte
2745
2883
  }
2746
2884
  };
2747
2885
  if (items.length === 0) {
2748
- return (jsxRuntime.jsx("div", { className: `${styles$k.sortableList} ${styles$k.emptyState} ${className}`, children: jsxRuntime.jsx("div", { className: styles$k.emptyMessage, children: emptyMessage }) }));
2886
+ return (jsxRuntime.jsx("div", { className: `${styles$l.sortableList} ${styles$l.emptyState} ${className}`, children: jsxRuntime.jsx("div", { className: styles$l.emptyMessage, children: emptyMessage }) }));
2749
2887
  }
2750
- return (jsxRuntime.jsx("div", { className: `${styles$k.sortableList} ${className}`, style: { maxHeight }, children: items.map((item, index) => {
2888
+ return (jsxRuntime.jsx("div", { className: `${styles$l.sortableList} ${className}`, style: { maxHeight }, children: items.map((item, index) => {
2751
2889
  const { title, extraContent, actions, showHandle = true, expandedContent } = renderItem(item);
2752
2890
  const isDragging = draggedItem?.id === item.id;
2753
2891
  const isMoved = movedItems.has(item.id);
2754
2892
  const canExpand = Boolean(expandedContent);
2755
2893
  const isExpanded = expandedItems.has(item.id);
2756
- return (jsxRuntime.jsxs(React.Fragment, { children: [dropIndicatorIndex === index && jsxRuntime.jsx("div", { className: styles$k.dropIndicator }), jsxRuntime.jsxs("div", { className: `${styles$k.sortableItem} ${isDragging ? styles$k.dragging : ''} ${isMoved ? styles$k.moved : ''} ${readOnly ? styles$k.readOnly : ''}`, draggable: !readOnly, onDragStart: (e) => handleDragStart(e, item), onDragOver: (e) => handleDragOver(e, index), onDragEnd: handleDragEnd, children: [jsxRuntime.jsxs("header", { children: [canExpand ? (jsxRuntime.jsx(CwButton, { variant: "icon", onClick: () => toggleExpanded(item.id), type: "button", title: isExpanded ? "Collapse" : "Expand", icon: isExpanded ? "chevron-up" : "chevron-down" })) : showHandle ? (jsxRuntime.jsx("div", { className: styles$k.sortableHandle, children: jsxRuntime.jsx(CwIcon, { iconId: "grip-dots" }) })) : null, jsxRuntime.jsxs("div", { className: styles$k.sortableContent, children: [jsxRuntime.jsx("div", { className: styles$k.sortableTitle, children: title }), extraContent && jsxRuntime.jsx("div", { className: styles$k.sortableExtraContent, children: extraContent })] }), jsxRuntime.jsx("div", { className: styles$k.sortableActions, children: actions })] }), isExpanded && expandedContent && (jsxRuntime.jsx("div", { className: styles$k.expandedContent, children: expandedContent }))] }), !readOnly && dropIndicatorIndex === items.length && index === items.length - 1 && (jsxRuntime.jsx("div", { className: styles$k.dropIndicator }))] }, item.id));
2894
+ return (jsxRuntime.jsxs(React.Fragment, { children: [dropIndicatorIndex === index && jsxRuntime.jsx("div", { className: styles$l.dropIndicator }), jsxRuntime.jsxs("div", { className: `${styles$l.sortableItem} ${isDragging ? styles$l.dragging : ''} ${isMoved ? styles$l.moved : ''} ${readOnly ? styles$l.readOnly : ''}`, draggable: !readOnly, onDragStart: (e) => handleDragStart(e, item), onDragOver: (e) => handleDragOver(e, index), onDragEnd: handleDragEnd, children: [jsxRuntime.jsxs("header", { children: [canExpand ? (jsxRuntime.jsx(CwButton, { variant: "icon", onClick: () => toggleExpanded(item.id), type: "button", title: isExpanded ? "Collapse" : "Expand", icon: isExpanded ? "chevron-up" : "chevron-down" })) : showHandle ? (jsxRuntime.jsx("div", { className: styles$l.sortableHandle, children: jsxRuntime.jsx(CwIcon, { iconId: "grip-dots" }) })) : null, jsxRuntime.jsxs("div", { className: styles$l.sortableContent, children: [jsxRuntime.jsx("div", { className: styles$l.sortableTitle, children: title }), extraContent && jsxRuntime.jsx("div", { className: styles$l.sortableExtraContent, children: extraContent })] }), jsxRuntime.jsx("div", { className: styles$l.sortableActions, children: actions })] }), isExpanded && expandedContent && (jsxRuntime.jsx("div", { className: styles$l.expandedContent, children: expandedContent }))] }), !readOnly && dropIndicatorIndex === items.length && index === items.length - 1 && (jsxRuntime.jsx("div", { className: styles$l.dropIndicator }))] }, item.id));
2757
2895
  }) }));
2758
2896
  }
2759
2897
 
@@ -2879,60 +3017,9 @@ const CwTableGrouped = props => {
2879
3017
  group.rows.map((child, j) => (jsxRuntime.jsx("tr", { "data-row": true, "data-row-last-of-group": j == group.rows.length - 1, children: child.cells.map((cell, k) => (jsxRuntime.jsx("td", { children: cell.content }, k))) }, j)))] }, i))) }), jsxRuntime.jsx("tfoot", {})] }) }));
2880
3018
  };
2881
3019
 
2882
- function CwFileUpload(fileUploadProps) {
2883
- const [previewURL, setPreviewURL] = React.useState("");
2884
- const [error, setError] = React.useState(null);
2885
- const [_selectedFileName, setSelectedFileName] = React.useState("");
2886
- const [_currentHexContent, setCurrentHexContent] = React.useState("");
2887
- React.useEffect(() => {
2888
- // If there is hexadecimal preview content, set the Preview URL
2889
- if (fileUploadProps.file?.Bindata) {
2890
- setPreviewURL(`data:image/png;base64,${fileUploadProps.file.Bindata}`);
2891
- }
2892
- }, [fileUploadProps.file?.Bindata]);
2893
- const handleFileChange = (event) => {
2894
- const file = event.target.files?.[0];
2895
- setSelectedFileName(file?.name ?? "");
2896
- if (file) {
2897
- const allowedExts = fileUploadProps.accept.split(',').map(ext => ext.trim().replace('.', '').toLowerCase());
2898
- const fileExt = file.name.split('.').pop()?.toLowerCase() ?? "";
2899
- if (!allowedExts.includes(fileExt)) {
2900
- setError(`Invalid file type. Only ${fileUploadProps.acceptString} files are allowed.`);
2901
- setPreviewURL("");
2902
- return;
2903
- }
2904
- setError(null);
2905
- const reader = new FileReader();
2906
- reader.onloadend = () => {
2907
- if (typeof reader.result === "string") {
2908
- const hexContent = arrayBufferToHex(reader.result);
2909
- setCurrentHexContent(hexContent);
2910
- setPreviewURL(reader.result);
2911
- setCurrentHexContent(arrayBufferToHex(reader.result));
2912
- // Call function to store hexadecimal content
2913
- fileUploadProps.onSaveHexContent(arrayBufferToHex(reader.result));
2914
- }
2915
- };
2916
- reader.readAsDataURL(file);
2917
- }
2918
- };
2919
- // Function to convert the image buffer into hexadecimal content
2920
- const arrayBufferToHex = (dataUrl) => {
2921
- // Decodes the base64 of the URL data
2922
- const base64 = dataUrl.split(",")[1];
2923
- const binary = atob(base64);
2924
- let hex = "";
2925
- for (let i = 0; i < binary.length; i++) {
2926
- hex += binary.charCodeAt(i).toString(16).padStart(2, "0");
2927
- }
2928
- return hex;
2929
- };
2930
- return (jsxRuntime.jsxs("div", { children: [jsxRuntime.jsxs("div", { className: "row", children: [jsxRuntime.jsx("input", { className: "cw-button", type: "file", accept: fileUploadProps.accept, readOnly: true, placeholder: "No file selected...", onChange: handleFileChange }), previewURL && (jsxRuntime.jsx("div", { className: "row", children: jsxRuntime.jsx("img", { src: previewURL, alt: "Preview", style: { maxWidth: "200px", maxHeight: "200px" } }) }))] }), error && jsxRuntime.jsx("div", { className: "row error", children: error }), jsxRuntime.jsx("div", { className: "row", children: jsxRuntime.jsxs("label", { children: ["Please note: File/image has to be in ", fileUploadProps.acceptString, " format", fileUploadProps.sizeString && `, ${fileUploadProps.sizeString}`] }) })] }));
2931
- }
2932
-
2933
- var styles$j = {"fileUploadContainer":"cw-file-upload-multiple-module__fileUploadContainer__liEc1","hiddenInput":"cw-file-upload-multiple-module__hiddenInput__TZBBI","uploadArea":"cw-file-upload-multiple-module__uploadArea__DdOhs","uploadAreaDisabled":"cw-file-upload-multiple-module__uploadAreaDisabled__VWeFX","uploadTitle":"cw-file-upload-multiple-module__uploadTitle__gjRk8","uploadSubtitle":"cw-file-upload-multiple-module__uploadSubtitle__Z0S5t","filesContainer":"cw-file-upload-multiple-module__filesContainer__g44PY","fileItem":"cw-file-upload-multiple-module__fileItem__w27Dg","fileIcon":"cw-file-upload-multiple-module__fileIcon__iJJUX","fileExtension":"cw-file-upload-multiple-module__fileExtension__vOuHv","fileInfo":"cw-file-upload-multiple-module__fileInfo__R5ZTv","fileName":"cw-file-upload-multiple-module__fileName__DjepK","fileSize":"cw-file-upload-multiple-module__fileSize__b8GSm","smallButton":"cw-file-upload-multiple-module__smallButton__siUAh"};
3020
+ var styles$k = {"fileUploadContainer":"cw-file-upload-multiple-module__fileUploadContainer__liEc1","hiddenInput":"cw-file-upload-multiple-module__hiddenInput__TZBBI","uploadArea":"cw-file-upload-multiple-module__uploadArea__DdOhs","uploadAreaDisabled":"cw-file-upload-multiple-module__uploadAreaDisabled__VWeFX","uploadTitle":"cw-file-upload-multiple-module__uploadTitle__gjRk8","uploadSubtitle":"cw-file-upload-multiple-module__uploadSubtitle__Z0S5t","filesContainer":"cw-file-upload-multiple-module__filesContainer__g44PY","fileItem":"cw-file-upload-multiple-module__fileItem__w27Dg","fileIcon":"cw-file-upload-multiple-module__fileIcon__iJJUX","fileExtension":"cw-file-upload-multiple-module__fileExtension__vOuHv","fileInfo":"cw-file-upload-multiple-module__fileInfo__R5ZTv","fileName":"cw-file-upload-multiple-module__fileName__DjepK","fileSize":"cw-file-upload-multiple-module__fileSize__b8GSm","smallButton":"cw-file-upload-multiple-module__smallButton__siUAh"};
2934
3021
 
2935
- const DEFAULT_LABELS = {
3022
+ const DEFAULT_LABELS$1 = {
2936
3023
  uploadDisabled: 'Upload disabled',
2937
3024
  clickToUpload: 'Click to upload or drag and drop',
2938
3025
  acceptedFiles: (accept) => `Accepted files: ${accept}`,
@@ -2940,6 +3027,7 @@ const DEFAULT_LABELS = {
2940
3027
  allTypesAccepted: 'All file types accepted',
2941
3028
  changeFile: 'Change File',
2942
3029
  clearAll: 'Clear all',
3030
+ upload: 'Upload',
2943
3031
  addMoreFiles: 'Add More Files',
2944
3032
  filesSelected: (count) => `${count} file${count !== 1 ? 's' : ''} selected`,
2945
3033
  fileTooLarge: (name, maxSize) => `File "${name}" is too large. Maximum size allowed is ${maxSize}MB.`,
@@ -2947,11 +3035,38 @@ const DEFAULT_LABELS = {
2947
3035
  invalidMimeType: (name, types) => `File "${name}" has an invalid MIME type. Allowed types: ${types}`,
2948
3036
  alreadySelected: (name) => `File "${name}" is already selected.`,
2949
3037
  };
3038
+ /**
3039
+ * Checks a file against an `accept` string (comma-separated tokens). A token can be a dotted
3040
+ * extension (".pdf"), an exact MIME type ("application/pdf"), a wildcard MIME ("image" + slash + "star"),
3041
+ * or a bare "star" / "star-slash-star" for anything. Returns true if the file matches ANY token
3042
+ * (or if `accept` is empty).
3043
+ */
3044
+ function fileMatchesAccept(fileName, fileType, accept) {
3045
+ const tokens = accept.split(',').map(token => token.trim().toLowerCase()).filter(Boolean);
3046
+ if (tokens.length === 0) {
3047
+ return true;
3048
+ }
3049
+ const fileExtension = '.' + (fileName.split('.').pop()?.toLowerCase() ?? '');
3050
+ const mimeType = fileType.toLowerCase();
3051
+ return tokens.some(token => {
3052
+ if (token === '*' || token === '*/*') {
3053
+ return true;
3054
+ }
3055
+ if (token.startsWith('.')) {
3056
+ return token === fileExtension;
3057
+ }
3058
+ if (token.endsWith('/*')) {
3059
+ const prefix = token.slice(0, token.indexOf('/') + 1);
3060
+ return mimeType.startsWith(prefix);
3061
+ }
3062
+ return token === mimeType;
3063
+ });
3064
+ }
2950
3065
  function CwFileUploadMultiple(fileUploadProps) {
2951
3066
  const fileInputRef = React.useRef(null);
2952
3067
  const [selectedFiles, setSelectedFiles] = React.useState([]);
2953
3068
  const [existingFile, setExistingFile] = React.useState(fileUploadProps.initialFileName);
2954
- const labels = { ...DEFAULT_LABELS, ...fileUploadProps.labels };
3069
+ const labels = { ...DEFAULT_LABELS$1, ...fileUploadProps.labels };
2955
3070
  React.useEffect(() => {
2956
3071
  setExistingFile(fileUploadProps.initialFileName);
2957
3072
  }, [fileUploadProps.initialFileName]);
@@ -2969,17 +3084,9 @@ function CwFileUploadMultiple(fileUploadProps) {
2969
3084
  };
2970
3085
  }
2971
3086
  }
2972
- // Validate file type by extension (based in accept)
3087
+ // Validate file type against accept (dotted extensions, exact MIME, wildcard MIME, or *)
2973
3088
  if (fileUploadProps.accept) {
2974
- const acceptedExtensions = fileUploadProps.accept.split(',').map(ext => ext.trim().toLowerCase());
2975
- const fileExtension = '.' + file.name.split('.').pop()?.toLowerCase();
2976
- const isExtensionValid = acceptedExtensions.some(ext => {
2977
- if (ext.startsWith('.')) {
2978
- return ext === fileExtension;
2979
- }
2980
- return false;
2981
- });
2982
- if (!isExtensionValid) {
3089
+ if (!fileMatchesAccept(file.name, file.type, fileUploadProps.accept)) {
2983
3090
  return {
2984
3091
  isValid: false,
2985
3092
  error: labels.invalidFormat(file.name, fileUploadProps.accept)
@@ -3004,7 +3111,7 @@ function CwFileUploadMultiple(fileUploadProps) {
3004
3111
  const errors = [];
3005
3112
  for (const file of fileArray) {
3006
3113
  // Check if the file already exists (by name and size)
3007
- const isDuplicate = existingFiles.some(existingFile => existingFile.name === file.name && existingFile.size === file.size);
3114
+ const isDuplicate = validFiles.some(existingFile => existingFile.name === file.name && existingFile.size === file.size);
3008
3115
  if (isDuplicate) {
3009
3116
  errors.push(labels.alreadySelected(file.name));
3010
3117
  continue;
@@ -3022,8 +3129,7 @@ function CwFileUploadMultiple(fileUploadProps) {
3022
3129
  fileUploadProps.onError(errors.join('\n'));
3023
3130
  }
3024
3131
  else {
3025
- console.error(errors.join('\n'));
3026
- alert(errors.join('\n')); // Fallback if there is no onError
3132
+ CwDisplayMessage(errors.join('\n'), exports.CwMessageType.ERROR);
3027
3133
  }
3028
3134
  }
3029
3135
  // If not multiple, only take the first valid file (replace)
@@ -3097,12 +3203,20 @@ function CwFileUploadMultiple(fileUploadProps) {
3097
3203
  }
3098
3204
  }
3099
3205
  };
3100
- return (jsxRuntime.jsxs("div", { className: `${styles$j.fileUploadContainer} ${fileUploadProps.className}`, children: [jsxRuntime.jsx("input", { ref: fileInputRef, type: "file", name: fileUploadProps.name, accept: fileUploadProps.accept, multiple: fileUploadProps.multiple, onChange: handleFileSelectInternal, disabled: fileUploadProps.disabled, "aria-label": "files", className: styles$j.hiddenInput }), selectedFiles.length === 0 && !existingFile ? (jsxRuntime.jsxs("div", { className: `${styles$j.uploadArea} ${fileUploadProps.disabled ? styles$j.uploadAreaDisabled : ''}`, onDragOver: handleDragOver, onDrop: handleDrop, onClick: !fileUploadProps.disabled ? handleButtonClick : undefined, children: [jsxRuntime.jsx(CwIcon, { iconId: "upload" }), jsxRuntime.jsx("p", { className: `${styles$j.uploadTitle}`, children: fileUploadProps.disabled ? labels.uploadDisabled : labels.clickToUpload }), jsxRuntime.jsxs("p", { className: `${styles$j.uploadSubtitle}`, children: [fileUploadProps.accept ? labels.acceptedFiles(fileUploadProps.accept) : labels.allTypesAccepted, !fileUploadProps.multiple && ` ${labels.singleFileOnly}`] })] })) : selectedFiles.length === 0 && existingFile ? (jsxRuntime.jsxs("div", { className: styles$j.filesContainer, children: [jsxRuntime.jsxs("div", { className: styles$j.fileItem, children: [jsxRuntime.jsxs("div", { className: styles$j.fileIcon, children: [jsxRuntime.jsx(CwIcon, { iconId: "page" }), jsxRuntime.jsx("span", { className: styles$j.fileExtension, children: getFileExtension(existingFile) })] }), jsxRuntime.jsx("div", { className: styles$j.fileInfo, children: jsxRuntime.jsx("p", { className: styles$j.fileName, children: existingFile }) }), jsxRuntime.jsx(CwButton, { variant: "icon", icon: "close", color: "neutral", onClick: () => {
3206
+ return (jsxRuntime.jsxs("div", { className: `${styles$k.fileUploadContainer} ${fileUploadProps.className}`, children: [jsxRuntime.jsx("input", { ref: fileInputRef, type: "file", name: fileUploadProps.name, accept: fileUploadProps.accept, multiple: fileUploadProps.multiple, onChange: handleFileSelectInternal, disabled: fileUploadProps.disabled, "aria-label": "files", className: styles$k.hiddenInput }), selectedFiles.length === 0 && !existingFile ? (jsxRuntime.jsxs("div", { className: `${styles$k.uploadArea} ${fileUploadProps.disabled ? styles$k.uploadAreaDisabled : ''}`, onDragOver: handleDragOver, onDrop: handleDrop, onClick: !fileUploadProps.disabled ? handleButtonClick : undefined, children: [jsxRuntime.jsx(CwIcon, { iconId: "upload" }), jsxRuntime.jsx("p", { className: `${styles$k.uploadTitle}`, children: fileUploadProps.disabled ? labels.uploadDisabled : labels.clickToUpload }), jsxRuntime.jsxs("p", { className: `${styles$k.uploadSubtitle}`, children: [fileUploadProps.accept ? labels.acceptedFiles(fileUploadProps.accept) : labels.allTypesAccepted, !fileUploadProps.multiple && ` ${labels.singleFileOnly}`] })] })) : selectedFiles.length === 0 && existingFile ? (jsxRuntime.jsxs("div", { className: styles$k.filesContainer, children: [jsxRuntime.jsxs("div", { className: styles$k.fileItem, children: [jsxRuntime.jsxs("div", { className: styles$k.fileIcon, children: [jsxRuntime.jsx(CwIcon, { iconId: "page" }), jsxRuntime.jsx("span", { className: styles$k.fileExtension, children: getFileExtension(existingFile) })] }), jsxRuntime.jsx("div", { className: styles$k.fileInfo, children: jsxRuntime.jsx("p", { className: styles$k.fileName, children: existingFile }) }), jsxRuntime.jsx(CwButton, { variant: "icon", icon: "close", color: "neutral", onClick: () => {
3101
3207
  setExistingFile(undefined);
3102
3208
  if (fileUploadProps.onSelect) {
3103
3209
  fileUploadProps.onSelect(null);
3104
3210
  }
3105
- }, disabled: fileUploadProps.disabled, className: styles$j.smallButton })] }), jsxRuntime.jsx(CwButton, { text: labels.changeFile, icon: "refresh", onClick: handleButtonClick, disabled: fileUploadProps.disabled })] })) : (jsxRuntime.jsxs("div", { className: styles$j.filesContainer, children: [jsxRuntime.jsxs("div", { className: "cw-flex-row cw-align-between-center", children: [jsxRuntime.jsx("small", { className: styles$j.filesCount, children: labels.filesSelected(selectedFiles.length) }), !fileUploadProps.hideClearAll && (jsxRuntime.jsx(CwButton, { onClick: removeAllFiles, disabled: fileUploadProps.disabled, color: "danger", variant: "outline", icon: "delete", text: labels.clearAll }))] }), selectedFiles.map((file, index) => (jsxRuntime.jsxs("div", { className: styles$j.fileItem, children: [jsxRuntime.jsxs("div", { className: styles$j.fileIcon, children: [jsxRuntime.jsx(CwIcon, { iconId: "page" }), jsxRuntime.jsx("span", { className: styles$j.fileExtension, children: getFileExtension(file.name) })] }), jsxRuntime.jsxs("div", { className: styles$j.fileInfo, children: [jsxRuntime.jsx("p", { className: styles$j.fileName, children: file.name }), jsxRuntime.jsxs("p", { className: styles$j.fileSize, children: [(file.size / 1024).toFixed(1), " KB"] })] }), jsxRuntime.jsx(CwButton, { variant: "icon", icon: "close", color: "neutral", onClick: () => removeFile(index), className: styles$j.smallButton })] }, index))), fileUploadProps.multiple && (jsxRuntime.jsx(CwButton, { text: labels.addMoreFiles, icon: "plus", variant: "outline", onClick: handleButtonClick, disabled: fileUploadProps.disabled })), !fileUploadProps.multiple && (jsxRuntime.jsx(CwButton, { text: labels.changeFile, icon: "refresh", onClick: handleButtonClick, disabled: fileUploadProps.disabled }))] }))] }));
3211
+ }, disabled: fileUploadProps.disabled, className: styles$k.smallButton })] }), jsxRuntime.jsx(CwButton, { text: labels.changeFile, icon: "refresh", onClick: handleButtonClick, disabled: fileUploadProps.disabled })] })) : (jsxRuntime.jsxs("div", { className: styles$k.filesContainer, children: [jsxRuntime.jsxs("header", { className: "cw-flex-row cw-align-between-center cw-flex-wrap", children: [jsxRuntime.jsx("small", { className: styles$k.filesCount, children: fileUploadProps.statusText ?? labels.filesSelected(selectedFiles.length) }), jsxRuntime.jsxs("div", { className: "cw-flex-row", children: [fileUploadProps.onConfirm && selectedFiles.length > 0 && (jsxRuntime.jsx(CwButton, { onClick: () => {
3212
+ let files = fileInputRef.current?.files ?? null;
3213
+ if (!files) {
3214
+ const dataTransfer = new DataTransfer();
3215
+ selectedFiles.forEach(file => dataTransfer.items.add(file));
3216
+ files = dataTransfer.files;
3217
+ }
3218
+ fileUploadProps.onConfirm?.(files);
3219
+ }, disabled: fileUploadProps.disabled || fileUploadProps.confirmDisabled, icon: "upload", text: fileUploadProps.confirmLabel ?? labels.upload })), !fileUploadProps.hideClearAll && (jsxRuntime.jsx(CwButton, { onClick: removeAllFiles, disabled: fileUploadProps.disabled, color: "danger", variant: "outline", icon: "delete", text: labels.clearAll }))] })] }), selectedFiles.map((file, index) => (jsxRuntime.jsxs("div", { className: styles$k.fileItem, children: [jsxRuntime.jsxs("div", { className: styles$k.fileIcon, children: [jsxRuntime.jsx(CwIcon, { iconId: "page" }), jsxRuntime.jsx("span", { className: styles$k.fileExtension, children: getFileExtension(file.name) })] }), jsxRuntime.jsxs("div", { className: styles$k.fileInfo, children: [jsxRuntime.jsx("p", { className: styles$k.fileName, children: file.name }), jsxRuntime.jsxs("p", { className: styles$k.fileSize, children: [(file.size / 1024).toFixed(1), " KB"] })] }), jsxRuntime.jsx(CwButton, { variant: "icon", icon: "close", color: "neutral", onClick: () => removeFile(index), className: styles$k.smallButton })] }, `${file.name}-${file.size}`))), fileUploadProps.multiple && (jsxRuntime.jsx(CwButton, { text: labels.addMoreFiles, icon: "plus", variant: "outline", onClick: handleButtonClick, disabled: fileUploadProps.disabled })), !fileUploadProps.multiple && (jsxRuntime.jsx(CwButton, { text: labels.changeFile, icon: "refresh", onClick: handleButtonClick, disabled: fileUploadProps.disabled }))] }))] }));
3106
3220
  }
3107
3221
 
3108
3222
  function CwInput(CwInputProps) {
@@ -3143,7 +3257,7 @@ function CwDigit(props) {
3143
3257
  return (jsxRuntime.jsx("div", { className: "cw-input-text", children: jsxRuntime.jsxs(CwAlign, { ...alignProps, itemProp: inputProps.required === true ? "required" : "", children: [labelProps && (jsxRuntime.jsxs(CwLabel, { ...labelProps, children: [iconProps && jsxRuntime.jsx(CwIcon, { ...iconProps }), labelProps.text] })), jsxRuntime.jsx("input", { type: "number", ...inputProps }), buttonProps && jsxRuntime.jsx(CwButton, { ...buttonProps })] }) }));
3144
3258
  }
3145
3259
 
3146
- var styles$i = {"colorPreview":"cw-color-picker-module__colorPreview__ylJcD","hueBar":"cw-color-picker-module__hueBar__bFhyC","hueBarSlider":"cw-color-picker-module__hueBarSlider__D53IV","colorPickerInteractiveArea":"cw-color-picker-module__colorPickerInteractiveArea__KZFR1","colorArea":"cw-color-picker-module__colorArea__xgpSE","colorAreaOverlay":"cw-color-picker-module__colorAreaOverlay__pmgOc","hueBackground":"cw-color-picker-module__hueBackground__Mks78","whiteGradient":"cw-color-picker-module__whiteGradient__Bt-fU","blackGradient":"cw-color-picker-module__blackGradient__VnEKJ","colorAreaCursor":"cw-color-picker-module__colorAreaCursor__lotg3"};
3260
+ var styles$j = {"colorPreview":"cw-color-picker-module__colorPreview__ylJcD","hueBar":"cw-color-picker-module__hueBar__bFhyC","hueBarSlider":"cw-color-picker-module__hueBarSlider__D53IV","colorPickerInteractiveArea":"cw-color-picker-module__colorPickerInteractiveArea__KZFR1","colorArea":"cw-color-picker-module__colorArea__xgpSE","colorAreaOverlay":"cw-color-picker-module__colorAreaOverlay__pmgOc","hueBackground":"cw-color-picker-module__hueBackground__Mks78","whiteGradient":"cw-color-picker-module__whiteGradient__Bt-fU","blackGradient":"cw-color-picker-module__blackGradient__VnEKJ","colorAreaCursor":"cw-color-picker-module__colorAreaCursor__lotg3"};
3147
3261
 
3148
3262
  const CwColorPicker = ({ initialColor, onChange, previewText = "Color preview" }) => {
3149
3263
  const [rgb, setRgb] = React.useState({ r: 255, g: 255, b: 255 });
@@ -3346,13 +3460,13 @@ const CwColorPicker = ({ initialColor, onChange, previewText = "Color preview" }
3346
3460
  // Calculate background color for the main area based on current hue
3347
3461
  const hueColor = hsvToRgb(hsv.h, 100, 100);
3348
3462
  const hueHex = rgbToHex(hueColor.r, hueColor.g, hueColor.b);
3349
- return (jsxRuntime.jsxs("div", { className: "cw-flex-column cw-gap-small", children: [jsxRuntime.jsxs("div", { className: "cw-flex-row cw-align-between-center cw-gap-small", children: [jsxRuntime.jsx("div", { className: styles$i.colorPreview, style: { backgroundColor: hexColor, color: getContrastColor(hexColor) }, children: previewText }), jsxRuntime.jsx("button", { type: "button", className: "cw-button", onClick: toggleInputMode, style: { minWidth: "3ch" }, children: inputMode === 'hex' ? 'RGB' : 'HEX' })] }), jsxRuntime.jsx("div", { className: "color-inputs-row", children: inputMode === 'hex' ? (jsxRuntime.jsx("input", { type: "text", value: hexColor, onChange: handleHexChange })) : (jsxRuntime.jsxs("div", { className: "cw-grid-base-3 cw-gap-small", children: [jsxRuntime.jsxs("div", { children: [jsxRuntime.jsx("label", { children: "R:" }), jsxRuntime.jsx("input", { type: "number", name: "r", min: "0", max: "255", value: rgb.r, onChange: handleRgbChange })] }), jsxRuntime.jsxs("div", { children: [jsxRuntime.jsx("label", { children: "G:" }), jsxRuntime.jsx("input", { type: "number", name: "g", min: "0", max: "255", value: rgb.g, onChange: handleRgbChange })] }), jsxRuntime.jsxs("div", { children: [jsxRuntime.jsx("label", { children: "B:" }), jsxRuntime.jsx("input", { type: "number", name: "b", min: "0", max: "255", value: rgb.b, onChange: handleRgbChange })] })] })) }), jsxRuntime.jsxs("div", { className: styles$i.colorPickerInteractiveArea, children: [jsxRuntime.jsx("div", { className: styles$i.hueBar, ref: hueBarRef, onClick: handleHueBarClick, children: jsxRuntime.jsx("div", { className: styles$i.hueBarSlider, style: { top: `${(360 - hsv.h) / 360 * 100}%` } }) }), jsxRuntime.jsxs("div", { className: styles$i.colorArea, ref: colorAreaRef, onClick: handleColorAreaClick, children: [jsxRuntime.jsxs("div", { className: styles$i.colorAreaOverlay, children: [jsxRuntime.jsx("div", { className: styles$i.hueBackground, style: { backgroundColor: hueHex } }), jsxRuntime.jsx("div", { className: styles$i.whiteGradient }), jsxRuntime.jsx("div", { className: styles$i.blackGradient })] }), jsxRuntime.jsx("div", { className: styles$i.colorAreaCursor, style: {
3463
+ return (jsxRuntime.jsxs("div", { className: "cw-flex-column cw-gap-small", children: [jsxRuntime.jsxs("div", { className: "cw-flex-row cw-align-between-center cw-gap-small", children: [jsxRuntime.jsx("div", { className: styles$j.colorPreview, style: { backgroundColor: hexColor, color: getContrastColor(hexColor) }, children: previewText }), jsxRuntime.jsx("button", { type: "button", className: "cw-button", onClick: toggleInputMode, style: { minWidth: "3ch" }, children: inputMode === 'hex' ? 'RGB' : 'HEX' })] }), jsxRuntime.jsx("div", { className: "color-inputs-row", children: inputMode === 'hex' ? (jsxRuntime.jsx("input", { type: "text", value: hexColor, onChange: handleHexChange })) : (jsxRuntime.jsxs("div", { className: "cw-grid-base-3 cw-gap-small", children: [jsxRuntime.jsxs("div", { children: [jsxRuntime.jsx("label", { children: "R:" }), jsxRuntime.jsx("input", { type: "number", name: "r", min: "0", max: "255", value: rgb.r, onChange: handleRgbChange })] }), jsxRuntime.jsxs("div", { children: [jsxRuntime.jsx("label", { children: "G:" }), jsxRuntime.jsx("input", { type: "number", name: "g", min: "0", max: "255", value: rgb.g, onChange: handleRgbChange })] }), jsxRuntime.jsxs("div", { children: [jsxRuntime.jsx("label", { children: "B:" }), jsxRuntime.jsx("input", { type: "number", name: "b", min: "0", max: "255", value: rgb.b, onChange: handleRgbChange })] })] })) }), jsxRuntime.jsxs("div", { className: styles$j.colorPickerInteractiveArea, children: [jsxRuntime.jsx("div", { className: styles$j.hueBar, ref: hueBarRef, onClick: handleHueBarClick, children: jsxRuntime.jsx("div", { className: styles$j.hueBarSlider, style: { top: `${(360 - hsv.h) / 360 * 100}%` } }) }), jsxRuntime.jsxs("div", { className: styles$j.colorArea, ref: colorAreaRef, onClick: handleColorAreaClick, children: [jsxRuntime.jsxs("div", { className: styles$j.colorAreaOverlay, children: [jsxRuntime.jsx("div", { className: styles$j.hueBackground, style: { backgroundColor: hueHex } }), jsxRuntime.jsx("div", { className: styles$j.whiteGradient }), jsxRuntime.jsx("div", { className: styles$j.blackGradient })] }), jsxRuntime.jsx("div", { className: styles$j.colorAreaCursor, style: {
3350
3464
  left: `${hsv.s}%`,
3351
3465
  top: `${100 - hsv.v}%`
3352
3466
  } })] })] })] }));
3353
3467
  };
3354
3468
 
3355
- var styles$h = {"container":"cw-input-color-module__container__x7gpk","selectColor":"cw-input-color-module__selectColor__DTo3V","disabled":"cw-input-color-module__disabled__O1fK5","readOnly":"cw-input-color-module__readOnly__HL-Bz","colorDropdown":"cw-input-color-module__colorDropdown__pX2bc"};
3469
+ var styles$i = {"container":"cw-input-color-module__container__x7gpk","selectColor":"cw-input-color-module__selectColor__DTo3V","disabled":"cw-input-color-module__disabled__O1fK5","readOnly":"cw-input-color-module__readOnly__HL-Bz","colorDropdown":"cw-input-color-module__colorDropdown__pX2bc"};
3356
3470
 
3357
3471
  const CwInputColor = ({ value, onChange, previewText = "Color preview", disabled = false, readOnly = false, width = '4rem', height = '2rem', labelProps, layoutProps, }) => {
3358
3472
  const [isOpen, setIsOpen] = React.useState(false);
@@ -3485,11 +3599,11 @@ const CwInputColor = ({ value, onChange, previewText = "Color preview", disabled
3485
3599
  break;
3486
3600
  }
3487
3601
  };
3488
- return (jsxRuntime.jsxs("div", { className: `cw-input-color ${styles$h.container}`, "data-direction": layoutProps?.direction ?? "row", "data-align": layoutProps?.align, children: [labelProps && (jsxRuntime.jsx(CwLabel, { ...labelProps })), jsxRuntime.jsx("div", { ref: containerRef, onClick: handleToggle, className: `${styles$h.selectColor} ${disabled ? styles$h.disabled : ''} ${readOnly ? styles$h.readOnly : ''}`, style: {
3602
+ return (jsxRuntime.jsxs("div", { className: `cw-input-color ${styles$i.container}`, "data-direction": layoutProps?.direction ?? "row", "data-align": layoutProps?.align, children: [labelProps && (jsxRuntime.jsx(CwLabel, { ...labelProps })), jsxRuntime.jsx("div", { ref: containerRef, onClick: handleToggle, className: `${styles$i.selectColor} ${disabled ? styles$i.disabled : ''} ${readOnly ? styles$i.readOnly : ''}`, style: {
3489
3603
  width,
3490
3604
  height,
3491
3605
  backgroundColor: value,
3492
- }, "aria-label": "Open color picker", "aria-expanded": isOpen, "aria-haspopup": "dialog", "aria-readonly": readOnly, role: "button", tabIndex: disabled ? -1 : 0, onKeyDown: handleKeyDown }), isOpen && reactDom.createPortal(jsxRuntime.jsx("div", { ref: dropdownRef, className: styles$h.colorDropdown, style: dropdownStyle, role: "dialog", "aria-modal": "true", "aria-label": "Color picker", children: jsxRuntime.jsx(CwColorPicker, { initialColor: value, onChange: handleColorChange, previewText: previewText }) }), document.body)] }));
3606
+ }, "aria-label": "Open color picker", "aria-expanded": isOpen, "aria-haspopup": "dialog", "aria-readonly": readOnly, role: "button", tabIndex: disabled ? -1 : 0, onKeyDown: handleKeyDown }), isOpen && reactDom.createPortal(jsxRuntime.jsx("div", { ref: dropdownRef, className: styles$i.colorDropdown, style: dropdownStyle, role: "dialog", "aria-modal": "true", "aria-label": "Color picker", children: jsxRuntime.jsx(CwColorPicker, { initialColor: value, onChange: handleColorChange, previewText: previewText }) }), document.body)] }));
3493
3607
  };
3494
3608
 
3495
3609
  /**
@@ -3739,31 +3853,63 @@ function CwInputDateText(props) {
3739
3853
  return (jsxRuntime.jsx("div", { className: "cw-input-date-text", children: jsxRuntime.jsxs(CwAlign, { ...alignProps, itemProp: required ? "required" : "", children: [labelProps && (jsxRuntime.jsxs(CwLabel, { ...labelProps, children: [iconProps && jsxRuntime.jsx(CwIcon, { ...iconProps }), labelProps.text] })), jsxRuntime.jsxs("div", { children: [jsxRuntime.jsx("input", { type: "text", disabled: disabled, maxLength: 10, onChange: onChangeInputText, pattern: "^$ --|[.0-9\\/\\-]{10}", placeholder: format.toLowerCase(), readOnly: readOnly, ref: textInputRef, required: required, size: width, tabIndex: tabIndex, value: displayedDate }), jsxRuntime.jsxs("span", { children: [jsxRuntime.jsx(CwIcon, { iconId: "calendar" }), jsxRuntime.jsx("input", { type: "date", disabled: disabled, onChange: onChangeInputDate, readOnly: readOnly, ref: dateInputRef, tabIndex: -1, value: date, ...inputProps })] })] }), buttonProps && jsxRuntime.jsx(CwButton, { ...buttonProps })] }) }));
3740
3854
  }
3741
3855
 
3742
- var styles$g = {"dropZone":"cw-input-image-module__dropZone__ygrGu"};
3856
+ var styles$h = {"hiddenInput":"cw-input-image-module__hiddenInput__pS7hb","dropZone":"cw-input-image-module__dropZone__ygrGu","title":"cw-input-image-module__title__Rji5M","subtitle":"cw-input-image-module__subtitle__djYYu","container":"cw-input-image-module__container__qh7Tm"};
3743
3857
 
3858
+ const DEFAULT_LABELS = {
3859
+ dropImageHere: "Drop image here",
3860
+ paste: "Paste",
3861
+ browse: "Browse",
3862
+ acceptedFormats: (formats) => `(${formats})`,
3863
+ clipboardError: "Failed to read from clipboard. Ensure the app has permission to access the clipboard.",
3864
+ invalidType: (formats) => `Unsupported file type. Allowed: ${formats}`,
3865
+ readError: "Could not read the image file.",
3866
+ };
3867
+ /** Reads a file/blob into a base64 data URL (persistable, no blob URL to revoke). */
3868
+ function readImageFileAsDataUrl(file) {
3869
+ return new Promise((resolve, reject) => {
3870
+ const reader = new FileReader();
3871
+ reader.onload = () => resolve(reader.result);
3872
+ reader.onerror = () => reject(reader.error ?? new Error("Failed to read file"));
3873
+ reader.readAsDataURL(file);
3874
+ });
3875
+ }
3744
3876
  function CwInputImage(props) {
3745
3877
  const [_uploadedImage, setUploadedImage] = React.useState(null);
3746
3878
  const inputRef = React.useRef(null);
3747
- const { allowedImageFormats, onChange, ...inputProps } = props;
3879
+ const { allowedImageFormats, onChange, onError, labels: labelsProp, size, ...inputProps } = props;
3748
3880
  const allowedFormats = allowedImageFormats || ["image/jpeg", "image/png", "image/gif"];
3881
+ const labels = { ...DEFAULT_LABELS, ...labelsProp };
3749
3882
  const isValidFileType = (type) => allowedFormats.includes(type);
3750
- const handleFile = (file) => {
3751
- if (file && isValidFileType(file.type)) {
3752
- const imgURL = URL.createObjectURL(file);
3753
- setUploadedImage(imgURL);
3754
- if (onChange)
3755
- onChange(imgURL);
3883
+ const reportError = (message) => {
3884
+ if (onError)
3885
+ onError(message);
3886
+ else
3887
+ CwDisplayMessage(message, exports.CwMessageType.ERROR);
3888
+ };
3889
+ const handleFile = async (file) => {
3890
+ if (!file) {
3891
+ onChange?.(null);
3892
+ return;
3756
3893
  }
3757
- else {
3758
- // Optionally handle unsupported file types
3759
- if (onChange)
3760
- onChange(null);
3894
+ if (!isValidFileType(file.type)) {
3895
+ reportError(labels.invalidType(allowedFormats.join(", ").replace(/image\//g, "")));
3896
+ onChange?.(null);
3897
+ return;
3898
+ }
3899
+ try {
3900
+ const dataUrl = await readImageFileAsDataUrl(file);
3901
+ setUploadedImage(dataUrl);
3902
+ onChange?.(dataUrl, file);
3903
+ }
3904
+ catch {
3905
+ reportError(labels.readError);
3906
+ onChange?.(null);
3761
3907
  }
3762
3908
  };
3763
3909
  const handleDrop = (e) => {
3764
3910
  e.preventDefault();
3765
3911
  const file = e.dataTransfer.files[0];
3766
- handleFile(file);
3912
+ void handleFile(file ?? null);
3767
3913
  };
3768
3914
  const onPasteButtonClick = async () => {
3769
3915
  try {
@@ -3773,21 +3919,20 @@ function CwInputImage(props) {
3773
3919
  for (const type of clipboardItem.types) {
3774
3920
  if (type.startsWith("image/")) {
3775
3921
  const blob = await clipboardItem.getType(type);
3776
- handleFile(blob);
3922
+ await handleFile(blob);
3777
3923
  }
3778
3924
  }
3779
3925
  }
3780
3926
  }
3781
- catch (err) {
3782
- console.error("Failed to read clipboard:", err);
3783
- alert("Failed to read from clipboard. Ensure the app has permission to access clipboard.");
3927
+ catch {
3928
+ reportError(labels.clipboardError);
3784
3929
  }
3785
3930
  };
3786
3931
  const handleFileChange = (e) => {
3787
- const file = e.target.files?.[0];
3788
- handleFile(file ?? null);
3932
+ const file = e.currentTarget.files?.[0];
3933
+ void handleFile(file ?? null);
3789
3934
  };
3790
- return (jsxRuntime.jsxs("div", { className: "cw-input-image", children: [jsxRuntime.jsxs("div", { onDragOver: (e) => e.preventDefault(), onDrop: handleDrop, className: styles$g.dropZone, children: [jsxRuntime.jsx("p", { children: "Drop image here" }), jsxRuntime.jsxs("small", { children: ["(", allowedFormats.join(", ").replace(/image\//g, ""), ")"] })] }), jsxRuntime.jsxs("div", { className: "cw-flex-row cw-align-center-center cw-gap-small", children: [jsxRuntime.jsx(CwButton, { onClick: onPasteButtonClick, icon: "paste", text: "Paste" }), jsxRuntime.jsx(CwButton, { onClick: () => inputRef.current?.click(), icon: "folder-open", text: "Browse" })] }), jsxRuntime.jsx("input", { ref: inputRef, type: "file", accept: allowedFormats.join(","), onChange: handleFileChange, style: { display: "none" }, ...inputProps })] }));
3935
+ return (jsxRuntime.jsxs("div", { className: `cw-input-image ${styles$h.container}`, "data-size": size, children: [jsxRuntime.jsxs("div", { onDragOver: (e) => e.preventDefault(), onDrop: handleDrop, className: styles$h.dropZone, children: [jsxRuntime.jsx(CwIcon, { iconId: "upload" }), jsxRuntime.jsxs("div", { className: "cw-flex-column cw-gap-tiny", children: [jsxRuntime.jsx("p", { className: styles$h.title, children: labels.dropImageHere }), jsxRuntime.jsx("p", { className: styles$h.subtitle, children: labels.acceptedFormats(allowedFormats.join(", ").replace(/image\//g, "")) })] })] }), jsxRuntime.jsxs("div", { className: "cw-flex-row cw-align-center-center cw-gap-small", children: [jsxRuntime.jsx(CwButton, { onClick: onPasteButtonClick, icon: "paste", text: labels.paste, size: size }), jsxRuntime.jsx(CwButton, { onClick: () => inputRef.current?.click(), icon: "folder-open", text: labels.browse, size: size })] }), jsxRuntime.jsx("input", { ref: inputRef, type: "file", accept: allowedFormats.join(","), onChange: handleFileChange, className: styles$h.hiddenInput, ...inputProps })] }));
3791
3936
  }
3792
3937
 
3793
3938
  /**
@@ -3919,7 +4064,7 @@ const CwImageArea = React.forwardRef((props, ref) => {
3919
4064
  });
3920
4065
  CwImageArea.displayName = "CwImageArea";
3921
4066
 
3922
- var styles$f = {"cw-weekday-selector":"cw-weekday-selector-module__cw-weekday-selector__Iz4GZ"};
4067
+ var styles$g = {"cw-weekday-selector":"cw-weekday-selector-module__cw-weekday-selector__Iz4GZ"};
3923
4068
 
3924
4069
  /**
3925
4070
  * This class represents a week where days can be selected or unselected
@@ -4059,16 +4204,16 @@ const CwWeekdaySelector = ({ value = "", onChange, disabled = false }) => {
4059
4204
  setSelectedDays(newWeekdays);
4060
4205
  onChange?.(newWeekdays.toString());
4061
4206
  };
4062
- return (jsxRuntime.jsx("div", { className: styles$f["cw-weekday-selector"], children: Weekdays.getFullWeek().map(day => (jsxRuntime.jsx("input", { type: "checkbox", "data-day": day, checked: selectedDays.toArray().includes(day), onChange: (e) => handleChange(day, e.target.checked), disabled: disabled }, day))) }));
4207
+ return (jsxRuntime.jsx("div", { className: styles$g["cw-weekday-selector"], children: Weekdays.getFullWeek().map(day => (jsxRuntime.jsx("input", { type: "checkbox", "data-day": day, checked: selectedDays.toArray().includes(day), onChange: (e) => handleChange(day, e.target.checked), disabled: disabled }, day))) }));
4063
4208
  };
4064
4209
 
4065
- var styles$e = {"check-container":"cw-check-module__check-container__4nscZ","group":"cw-check-module__group__6JCQo","options":"cw-check-module__options__-g9LF"};
4210
+ var styles$f = {"check-container":"cw-check-module__check-container__4nscZ","group":"cw-check-module__group__6JCQo","options":"cw-check-module__options__-g9LF"};
4066
4211
 
4067
4212
  function CwCheck(props) {
4068
4213
  const { labelProps, labelText, direction, alignment, className, ...inputProps } = props;
4069
4214
  const resolvedDirection = direction ?? alignment ?? "row";
4070
4215
  const displayText = labelProps?.text ?? labelText;
4071
- return (jsxRuntime.jsx("div", { className: `cw-check ${styles$e["check-container"]}${className ? ` ${className}` : ''}`, children: jsxRuntime.jsxs("label", { "data-direction": resolvedDirection, children: [jsxRuntime.jsx("input", { type: "checkbox", ...inputProps }), displayText && (jsxRuntime.jsx("span", { className: "cw-icon-text", children: displayText }))] }) }));
4216
+ return (jsxRuntime.jsx("div", { className: `cw-check ${styles$f["check-container"]}${className ? ` ${className}` : ''}`, children: jsxRuntime.jsxs("label", { "data-direction": resolvedDirection, children: [jsxRuntime.jsx("input", { type: "checkbox", ...inputProps }), displayText && (jsxRuntime.jsx("span", { className: "cw-icon-text", children: displayText }))] }) }));
4072
4217
  }
4073
4218
 
4074
4219
  function CwCheckbox(CwCheckboxProps) {
@@ -4119,14 +4264,14 @@ function CwCheckboxGroup({ options, value = [], onChange, labelProps, groupLayou
4119
4264
  ?? (optionsAlignment === "column" ? "row" : "column");
4120
4265
  // Each checkbox's box-to-text layout is the opposite of the options flow, mirroring CwRadioGroup.
4121
4266
  const checkDirection = itemDirection === "row" ? "column" : "row";
4122
- return (jsxRuntime.jsxs("div", { className: `cw-checkbox-group ${styles$e.group}${className ? ` ${className}` : ""}`, "data-testid": dataTestId, "data-direction": labelProps ? groupDirection : "column", "data-align": groupLayout?.align, "data-gap": groupLayout?.gap, children: [labelProps && (jsxRuntime.jsx(CwLabel, { ...labelProps, children: labelProps.text })), jsxRuntime.jsx("div", { className: styles$e.options, role: "group", "aria-label": labelProps?.text, "aria-required": required || undefined, "data-direction": itemDirection, "data-gap": itemLayout?.gap, children: options.map((option) => (jsxRuntime.jsx(CwCheck, { labelProps: { text: option.label }, checked: value.includes(option.value), disabled: disabled || option.disabled, direction: checkDirection, onChange: (e) => handleChange(option.value, e.currentTarget.checked) }, option.value))) }), feedbackMessages.map((feedbackItem, index) => (jsxRuntime.jsx("p", { className: "cw-input-info", "data-color": feedbackItem.type, children: feedbackItem.message }, index)))] }));
4267
+ return (jsxRuntime.jsxs("div", { className: `cw-checkbox-group ${styles$f.group}${className ? ` ${className}` : ""}`, "data-testid": dataTestId, "data-direction": labelProps ? groupDirection : "column", "data-align": groupLayout?.align, "data-gap": groupLayout?.gap, children: [labelProps && (jsxRuntime.jsx(CwLabel, { ...labelProps, children: labelProps.text })), jsxRuntime.jsx("div", { className: styles$f.options, role: "group", "aria-label": labelProps?.text, "aria-required": required || undefined, "data-direction": itemDirection, "data-gap": itemLayout?.gap, children: options.map((option) => (jsxRuntime.jsx(CwCheck, { labelProps: { text: option.label }, checked: value.includes(option.value), disabled: disabled || option.disabled, direction: checkDirection, onChange: (e) => handleChange(option.value, e.currentTarget.checked) }, option.value))) }), feedbackMessages.map((feedbackItem, index) => (jsxRuntime.jsx("p", { className: "cw-input-info", "data-color": feedbackItem.type, children: feedbackItem.message }, index)))] }));
4123
4268
  }
4124
4269
 
4125
- var styles$d = {"radio":"cw-radio-module__radio__5sh7a","group":"cw-radio-module__group__br-HM","options":"cw-radio-module__options__LSw7M"};
4270
+ var styles$e = {"radio":"cw-radio-module__radio__5sh7a","group":"cw-radio-module__group__br-HM","options":"cw-radio-module__options__LSw7M"};
4126
4271
 
4127
4272
  /** Single native radio input. Building block for CwRadioGroup. */
4128
4273
  function CwRadio({ label, direction = "row", className, ...inputProps }) {
4129
- return (jsxRuntime.jsxs("label", { className: `cw-radio ${styles$d.radio}${className ? ` ${className}` : ""}`, "data-direction": direction, children: [jsxRuntime.jsx("input", { type: "radio", ...inputProps }), label && jsxRuntime.jsx("span", { children: label })] }));
4274
+ return (jsxRuntime.jsxs("label", { className: `cw-radio ${styles$e.radio}${className ? ` ${className}` : ""}`, "data-direction": direction, children: [jsxRuntime.jsx("input", { type: "radio", ...inputProps }), label && jsxRuntime.jsx("span", { children: label })] }));
4130
4275
  }
4131
4276
 
4132
4277
  /**
@@ -4150,7 +4295,7 @@ function CwRadioGroup({ options, value, onChange, labelProps, groupLayout, itemL
4150
4295
  // (itemLayout column) reads best with the circle beside the text; a side-by-side row reads
4151
4296
  // best with the circle above the text.
4152
4297
  const radioDirection = itemLayout?.direction === "row" ? "column" : "row";
4153
- return (jsxRuntime.jsxs("div", { className: `cw-radio-group ${styles$d.group}${className ? ` ${className}` : ""}`, "data-testid": dataTestId, "data-direction": labelProps ? (groupLayout?.direction ?? "column") : "column", "data-align": groupLayout?.align, "data-gap": groupLayout?.gap, children: [labelProps && (jsxRuntime.jsx(CwLabel, { ...labelProps, children: labelProps.text })), jsxRuntime.jsx("div", { className: styles$d.options, role: "radiogroup", "aria-labelledby": ariaLabelledby, "aria-label": ariaLabelledby ? undefined : (ariaLabel ?? labelProps?.text), "aria-required": required || undefined, "data-direction": itemLayout?.direction ?? "column", "data-gap": itemLayout?.gap, children: options.map((option) => (jsxRuntime.jsx(CwRadio, { name: groupName, label: option.label, direction: radioDirection, checked: value === option.value, required: required, disabled: disabled || option.disabled, onChange: () => onChange(option.value) }, option.value))) }), feedbackMessages.map((feedbackItem, index) => (jsxRuntime.jsx("p", { className: "cw-input-info", "data-color": feedbackItem.type, children: feedbackItem.message }, index)))] }));
4298
+ return (jsxRuntime.jsxs("div", { className: `cw-radio-group ${styles$e.group}${className ? ` ${className}` : ""}`, "data-testid": dataTestId, "data-direction": labelProps ? (groupLayout?.direction ?? "column") : "column", "data-align": groupLayout?.align, "data-gap": groupLayout?.gap, children: [labelProps && (jsxRuntime.jsx(CwLabel, { ...labelProps, children: labelProps.text })), jsxRuntime.jsx("div", { className: styles$e.options, role: "radiogroup", "aria-labelledby": ariaLabelledby, "aria-label": ariaLabelledby ? undefined : (ariaLabel ?? labelProps?.text), "aria-required": required || undefined, "data-direction": itemLayout?.direction ?? "column", "data-gap": itemLayout?.gap, children: options.map((option) => (jsxRuntime.jsx(CwRadio, { name: groupName, label: option.label, direction: radioDirection, checked: value === option.value, required: required, disabled: disabled || option.disabled, onChange: () => onChange(option.value) }, option.value))) }), feedbackMessages.map((feedbackItem, index) => (jsxRuntime.jsx("p", { className: "cw-input-info", "data-color": feedbackItem.type, children: feedbackItem.message }, index)))] }));
4154
4299
  }
4155
4300
 
4156
4301
  function CwToggle(props) {
@@ -4416,7 +4561,7 @@ function CwDropdownFilter(props) {
4416
4561
  return (jsxRuntime.jsxs("div", { id: props.IdContent, className: containerClassName, children: [props.children, isVisible && (jsxRuntime.jsx("nav", { className: "cw-dropdown-menu", style: inlineStyles, onMouseLeave: props.onMouseLeave, id: props.idDropDownFilter, role: "menu", children: jsxRuntime.jsx("ul", { role: "none", children: props.DataSourceDropDownItem?.map((item) => (jsxRuntime.jsx("li", { id: item.IdDropDown_filter, role: "menuitem", children: item.dropDownFilter_desc }, item.IdDropDown_filter))) }) }))] }));
4417
4562
  }
4418
4563
 
4419
- var styles$c = {"container":"cw-popover-button-module__container__YSWQU","panel":"cw-popover-button-module__panel__C-BTn"};
4564
+ var styles$d = {"container":"cw-popover-button-module__container__YSWQU","panel":"cw-popover-button-module__panel__C-BTn"};
4420
4565
 
4421
4566
  /**
4422
4567
  * Button that toggles a floating panel with arbitrary children.
@@ -4495,7 +4640,7 @@ function CwPopoverButton({ children, panelWidth = "auto", placement = "bottom-st
4495
4640
  }
4496
4641
  panel.showPopover();
4497
4642
  }, [placement]);
4498
- return (jsxRuntime.jsxs("div", { ref: containerRef, className: styles$c.container, children: [jsxRuntime.jsx(CwButton, { ...buttonProps, onClick: handleClick }), jsxRuntime.jsx("div", { ref: panelCallbackRef, className: `${styles$c.panel}${panelClassName ? ` ${panelClassName}` : ""}`, style: { width: panelWidth }, children: children })] }));
4643
+ return (jsxRuntime.jsxs("div", { ref: containerRef, className: styles$d.container, children: [jsxRuntime.jsx(CwButton, { ...buttonProps, onClick: handleClick }), jsxRuntime.jsx("div", { ref: panelCallbackRef, className: `${styles$d.panel}${panelClassName ? ` ${panelClassName}` : ""}`, style: { width: panelWidth }, children: children })] }));
4499
4644
  }
4500
4645
 
4501
4646
  function itemsToMultiFilterTags(items, nameKey, valueKey, category, primaryColor, onPrimaryColor) {
@@ -4513,13 +4658,13 @@ function itemsToMultiFilterTags(items, nameKey, valueKey, category, primaryColor
4513
4658
  return result;
4514
4659
  }
4515
4660
 
4516
- var styles$b = {"cw-multifilter-tag":"cw-multi-filter-tag-module__cw-multifilter-tag__Epda-"};
4661
+ var styles$c = {"cw-multifilter-tag":"cw-multi-filter-tag-module__cw-multifilter-tag__Epda-"};
4517
4662
 
4518
4663
  const CwMultiFilterTag = props => {
4519
4664
  const { ID, Name, Value, Category, Removable, PrimaryColor, Selectable, Selected } = props;
4520
4665
  const backgroundColor = `rgb(${PrimaryColor.r},${PrimaryColor.g},${PrimaryColor.b})`;
4521
4666
  const isOutlineMode = Selected && !Removable;
4522
- return (jsxRuntime.jsx("li", { className: styles$b["cw-multifilter-tag"], id: ID, "data-value": Value, "data-category": Category, "data-selected": !!Selected, title: props.tooltip ?? Name, onClick: () => {
4667
+ return (jsxRuntime.jsx("li", { className: styles$c["cw-multifilter-tag"], id: ID, "data-value": Value, "data-category": Category, "data-selected": !!Selected, title: props.tooltip ?? Name, onClick: () => {
4523
4668
  if (Selectable)
4524
4669
  props.OnSelect?.(props);
4525
4670
  }, children: jsxRuntime.jsx(CwChip, { label: Name, colorScheme: "custom", customColor: backgroundColor, variant: isOutlineMode ? "outline" : "soft", closable: Removable, onClose: () => props.OnRemove?.(props),
@@ -4529,7 +4674,7 @@ const CwMultiFilterTag = props => {
4529
4674
  } : undefined }) }));
4530
4675
  };
4531
4676
 
4532
- var styles$a = {"cw-multi-filter-catalog-container":"cw-multi-filter-module__cw-multi-filter-catalog-container__S3nsq","cw-multi-filter":"cw-multi-filter-module__cw-multi-filter__zipBK","category-selected":"cw-multi-filter-module__category-selected__eYbes","cw-multi-filter-search":"cw-multi-filter-module__cw-multi-filter-search__eyHr0 cw-choice-input-box-module__inputBox__gHY9d"};
4677
+ var styles$b = {"cw-multi-filter-catalog-container":"cw-multi-filter-module__cw-multi-filter-catalog-container__S3nsq","cw-multi-filter":"cw-multi-filter-module__cw-multi-filter__zipBK","category-selected":"cw-multi-filter-module__category-selected__eYbes","cw-multi-filter-search":"cw-multi-filter-module__cw-multi-filter-search__eyHr0 cw-choice-input-box-module__inputBox__gHY9d"};
4533
4678
 
4534
4679
  /**
4535
4680
  * A multiple filter selector, a MULTI-SELECT even. Allows users to select and filter items based on tags.
@@ -4756,9 +4901,9 @@ const CwMultiFilter = ({ allTags, id, onChangeSelectedTags, selectedTags, placeh
4756
4901
  inputRef.current?.focus();
4757
4902
  }
4758
4903
  };
4759
- return (jsxRuntime.jsxs("form", { ref: componentRef, id: id, className: `${styles$a["cw-multi-filter"]}${className ? ` ${className}` : ""}`, style: style, onSubmit: (e) => {
4904
+ return (jsxRuntime.jsxs("form", { ref: componentRef, id: id, className: `${styles$b["cw-multi-filter"]}${className ? ` ${className}` : ""}`, style: style, onSubmit: (e) => {
4760
4905
  e.preventDefault();
4761
- }, children: [jsxRuntime.jsxs("div", { onClick: handleDivClick, ref: wrapperRef, className: styles$a["cw-multi-filter-search"], style: isPanelOpen ? { outline: "1px solid var(--cw-color-outline-variant)" } : {}, children: [jsxRuntime.jsxs("ul", { id: id + "_selected_filters", children: [Array.from(selectedTags).map(tag => (React.createElement(CwMultiFilterTag, { ...tag, key: tag.ID, Selectable: false, Removable: true, OnRemove: () => removeTag(tag.ID) }))), jsxRuntime.jsx("input", { type: "text", id: id + "_input", ref: inputRef, value: inputTextValue, spellCheck: false, onFocus: () => setIsPanelOpen(true), onChange: e => handleInputText(e.currentTarget.value), autoComplete: "off", placeholder: selectedTags.size === 0 ? placeholder : "", onKeyDown: e => {
4906
+ }, children: [jsxRuntime.jsxs("div", { onClick: handleDivClick, ref: wrapperRef, className: styles$b["cw-multi-filter-search"], style: isPanelOpen ? { outline: "1px solid var(--cw-color-outline-variant)" } : {}, children: [jsxRuntime.jsxs("ul", { id: id + "_selected_filters", children: [Array.from(selectedTags).map(tag => (React.createElement(CwMultiFilterTag, { ...tag, key: tag.ID, Selectable: false, Removable: true, OnRemove: () => removeTag(tag.ID) }))), jsxRuntime.jsx("input", { type: "text", id: id + "_input", ref: inputRef, value: inputTextValue, spellCheck: false, onFocus: () => setIsPanelOpen(true), onChange: e => handleInputText(e.currentTarget.value), autoComplete: "off", placeholder: selectedTags.size === 0 ? placeholder : "", onKeyDown: e => {
4762
4907
  switch (e.key) {
4763
4908
  case "Enter":
4764
4909
  case "Tab": {
@@ -4785,7 +4930,7 @@ const CwMultiFilter = ({ allTags, id, onChangeSelectedTags, selectedTags, placeh
4785
4930
  break;
4786
4931
  }
4787
4932
  }
4788
- } })] }), selectedTags.size > 0 && (jsxRuntime.jsx(CwButton, { type: "button", variant: "icon", color: "neutral", icon: "close", onMouseDown: e => e.preventDefault(), onClick: (e) => { e.stopPropagation(); onChangeSelectedTags(new Set()); setIsPanelOpen(false); }, tabIndex: -1, "aria-label": "Clear all" }))] }), renderPanel(jsxRuntime.jsxs("section", { ref: panelRef, className: styles$a["cw-multi-filter-catalog-container"], style: panelStyle, children: [jsxRuntime.jsxs("nav", { children: [jsxRuntime.jsx("button", { className: selectedCategory === "All" ? styles$a["category-selected"] : undefined, onClick: () => handleClickCategory("All"), children: allCategoriesLabel }), Array.from(categoriesMappedToTags().keys()).map(category => (jsxRuntime.jsx("button", { className: selectedCategory === category ? styles$a["category-selected"] : undefined, style: {
4933
+ } })] }), selectedTags.size > 0 && (jsxRuntime.jsx(CwButton, { type: "button", variant: "icon", color: "neutral", icon: "close", onMouseDown: e => e.preventDefault(), onClick: (e) => { e.stopPropagation(); onChangeSelectedTags(new Set()); setIsPanelOpen(false); }, tabIndex: -1, "aria-label": "Clear all" }))] }), renderPanel(jsxRuntime.jsxs("section", { ref: panelRef, className: styles$b["cw-multi-filter-catalog-container"], style: panelStyle, children: [jsxRuntime.jsxs("nav", { children: [jsxRuntime.jsx("button", { className: selectedCategory === "All" ? styles$b["category-selected"] : undefined, onClick: () => handleClickCategory("All"), children: allCategoriesLabel }), Array.from(categoriesMappedToTags().keys()).map(category => (jsxRuntime.jsx("button", { className: selectedCategory === category ? styles$b["category-selected"] : undefined, style: {
4789
4934
  backgroundColor: getColor(category).primary,
4790
4935
  color: getColor(category).onPrimary,
4791
4936
  }, onClick: () => handleClickCategory(category), children: category }, category)))] }), jsxRuntime.jsx("ul", { children: displayTags
@@ -4811,7 +4956,7 @@ const CwMultiFilter = ({ allTags, id, onChangeSelectedTags, selectedTags, placeh
4811
4956
  } }, props.ID))) })] }))] }));
4812
4957
  };
4813
4958
 
4814
- var styles$9 = {"container":"cw-tag-selector-module__container__-do8i","inputBox":"cw-tag-selector-module__inputBox__3NGz9 cw-choice-input-box-module__inputBox__gHY9d","disabled":"cw-tag-selector-module__disabled__vbud9 cw-choice-input-box-module__disabled__TFAnC","dropdown":"cw-tag-selector-module__dropdown__X6Dob cw-choice-dropdown-module__dropdown__P0b4j","option":"cw-tag-selector-module__option__2UQ7g cw-choice-dropdown-module__option__uR-ro","optionFocused":"cw-tag-selector-module__optionFocused__8-lv8 cw-choice-dropdown-module__optionFocused__BYMxj","optionDot":"cw-tag-selector-module__optionDot__CdFlG cw-choice-dropdown-module__colorCircle__x7mI9","selectAll":"cw-tag-selector-module__selectAll__HyvMA"};
4959
+ var styles$a = {"container":"cw-tag-selector-module__container__-do8i","inputBox":"cw-tag-selector-module__inputBox__3NGz9 cw-choice-input-box-module__inputBox__gHY9d","disabled":"cw-tag-selector-module__disabled__vbud9 cw-choice-input-box-module__disabled__TFAnC","dropdown":"cw-tag-selector-module__dropdown__X6Dob cw-choice-dropdown-module__dropdown__P0b4j","option":"cw-tag-selector-module__option__2UQ7g cw-choice-dropdown-module__option__uR-ro","optionFocused":"cw-tag-selector-module__optionFocused__8-lv8 cw-choice-dropdown-module__optionFocused__BYMxj","optionDot":"cw-tag-selector-module__optionDot__CdFlG cw-choice-dropdown-module__colorCircle__x7mI9","selectAll":"cw-tag-selector-module__selectAll__HyvMA"};
4815
4960
 
4816
4961
  /**
4817
4962
  * Multi-select input with chip tags and searchable dropdown.
@@ -4946,11 +5091,11 @@ function CwTagSelector({ id, options, value, onChange, labelProps, iconProps, al
4946
5091
  // Keeping containerRef for any other potential use
4947
5092
  const direction = alignProps?.flexDirection ?? "row";
4948
5093
  const feedbackMessages = feedback ? (Array.isArray(feedback) ? feedback : [feedback]) : [];
4949
- return (jsxRuntime.jsxs("div", { ref: containerRef, className: `${styles$9.container}${className ? ` ${className}` : ""}`, style: style, id: id, "data-direction": direction, children: [jsxRuntime.jsxs(CwAlign, { ...alignProps, children: [labelProps && (jsxRuntime.jsxs(CwLabel, { ...labelProps, children: [iconProps && jsxRuntime.jsx(CwIcon, { ...iconProps }), labelProps.text] })), jsxRuntime.jsxs("div", { className: `${styles$9.inputBox}${disabled ? ` ${styles$9.disabled}` : ""}`, ref: inputBoxRef, onClick: () => { if (!disabled)
4950
- inputRef.current?.focus(); }, children: [selectedOptions.map(opt => (jsxRuntime.jsx(CwChip, { label: opt.label, colorScheme: opt.color ? "custom" : "info", customColor: opt.color, closable: !disabled, onClose: () => handleRemove(opt.value) }, opt.value))), jsxRuntime.jsx("input", { ref: inputRef, type: "text", value: search, onChange: handleInputChange, onFocus: handleInputFocus, onKeyDown: handleKeyDown, placeholder: selectedOptions.length === 0 ? placeholder : "", disabled: disabled, autoComplete: "off" }), value.length > 0 && !disabled && (jsxRuntime.jsx(CwButton, { type: "button", variant: "icon", color: "neutral", icon: "close", onMouseDown: (e) => e.preventDefault(), onClick: (e) => { e.stopPropagation(); onChange([]); setSearch(""); setOpen(false); }, tabIndex: -1, "aria-label": "Clear all" }))] })] }), feedbackMessages.map((fb, i) => (jsxRuntime.jsx("p", { className: "cw-input-info", "data-color": fb.type, children: fb.message }, i))), renderPanel((showSelectAll || filtered.length > 0) ? (jsxRuntime.jsxs("div", { ref: panelRef, className: styles$9.dropdown, style: panelStyle, children: [showSelectAll && !search && (jsxRuntime.jsxs("div", { className: styles$9.selectAll, onMouseDown: (e) => e.preventDefault(), onClick: handleToggleAll, children: [jsxRuntime.jsx("input", { type: "checkbox", checked: allSelected, readOnly: true, tabIndex: -1 }), allSelected ? "Deselect all" : "Select all"] })), jsxRuntime.jsx("ul", { ref: listRef, children: filtered.map((opt, idx) => (jsxRuntime.jsxs("li", { className: `${styles$9.option}${idx === focusedIndex ? ` ${styles$9.optionFocused}` : ""}`, onMouseDown: (e) => e.preventDefault(), onClick: () => handleSelect(opt.value), onMouseEnter: () => setFocusedIndex(idx), title: opt.tooltip, children: [opt.color && jsxRuntime.jsx("span", { className: styles$9.optionDot, style: { backgroundColor: opt.color } }), opt.label] }, opt.value))) })] })) : null)] }));
5094
+ return (jsxRuntime.jsxs("div", { ref: containerRef, className: `${styles$a.container}${className ? ` ${className}` : ""}`, style: style, id: id, "data-direction": direction, children: [jsxRuntime.jsxs(CwAlign, { ...alignProps, children: [labelProps && (jsxRuntime.jsxs(CwLabel, { ...labelProps, children: [iconProps && jsxRuntime.jsx(CwIcon, { ...iconProps }), labelProps.text] })), jsxRuntime.jsxs("div", { className: `${styles$a.inputBox}${disabled ? ` ${styles$a.disabled}` : ""}`, ref: inputBoxRef, onClick: () => { if (!disabled)
5095
+ inputRef.current?.focus(); }, children: [selectedOptions.map(opt => (jsxRuntime.jsx(CwChip, { label: opt.label, colorScheme: opt.color ? "custom" : "info", customColor: opt.color, closable: !disabled, onClose: () => handleRemove(opt.value) }, opt.value))), jsxRuntime.jsx("input", { ref: inputRef, type: "text", value: search, onChange: handleInputChange, onFocus: handleInputFocus, onKeyDown: handleKeyDown, placeholder: selectedOptions.length === 0 ? placeholder : "", disabled: disabled, autoComplete: "off" }), value.length > 0 && !disabled && (jsxRuntime.jsx(CwButton, { type: "button", variant: "icon", color: "neutral", icon: "close", onMouseDown: (e) => e.preventDefault(), onClick: (e) => { e.stopPropagation(); onChange([]); setSearch(""); setOpen(false); }, tabIndex: -1, "aria-label": "Clear all" }))] })] }), feedbackMessages.map((fb, i) => (jsxRuntime.jsx("p", { className: "cw-input-info", "data-color": fb.type, children: fb.message }, i))), renderPanel((showSelectAll || filtered.length > 0) ? (jsxRuntime.jsxs("div", { ref: panelRef, className: styles$a.dropdown, style: panelStyle, children: [showSelectAll && !search && (jsxRuntime.jsxs("div", { className: styles$a.selectAll, onMouseDown: (e) => e.preventDefault(), onClick: handleToggleAll, children: [jsxRuntime.jsx("input", { type: "checkbox", checked: allSelected, readOnly: true, tabIndex: -1 }), allSelected ? "Deselect all" : "Select all"] })), jsxRuntime.jsx("ul", { ref: listRef, children: filtered.map((opt, idx) => (jsxRuntime.jsxs("li", { className: `${styles$a.option}${idx === focusedIndex ? ` ${styles$a.optionFocused}` : ""}`, onMouseDown: (e) => e.preventDefault(), onClick: () => handleSelect(opt.value), onMouseEnter: () => setFocusedIndex(idx), title: opt.tooltip, children: [opt.color && jsxRuntime.jsx("span", { className: styles$a.optionDot, style: { backgroundColor: opt.color } }), opt.label] }, opt.value))) })] })) : null)] }));
4951
5096
  }
4952
5097
 
4953
- var styles$8 = {"tree-container":"cw-tree-view-module__tree-container__NN-HJ","tree-wrapper":"cw-tree-view-module__tree-wrapper__keBZI","tree-item":"cw-tree-view-module__tree-item__prE9N","tree-node":"cw-tree-view-module__tree-node__wfro9","selected":"cw-tree-view-module__selected__XJQ0w","non-selectable":"cw-tree-view-module__non-selectable__YuPSx","tree-children":"cw-tree-view-module__tree-children__ji8CZ","empty-state":"cw-tree-view-module__empty-state__yvRjo","tree-label":"cw-tree-view-module__tree-label__ss3Nf","tree-spacer":"cw-tree-view-module__tree-spacer__E9Ud2"};
5098
+ var styles$9 = {"tree-container":"cw-tree-view-module__tree-container__NN-HJ","tree-wrapper":"cw-tree-view-module__tree-wrapper__keBZI","tree-item":"cw-tree-view-module__tree-item__prE9N","tree-node":"cw-tree-view-module__tree-node__wfro9","selected":"cw-tree-view-module__selected__XJQ0w","non-selectable":"cw-tree-view-module__non-selectable__YuPSx","tree-children":"cw-tree-view-module__tree-children__ji8CZ","empty-state":"cw-tree-view-module__empty-state__yvRjo","tree-label":"cw-tree-view-module__tree-label__ss3Nf","tree-spacer":"cw-tree-view-module__tree-spacer__E9Ud2"};
4954
5099
 
4955
5100
  function CwTreeView({ data, onSelect, allowParentSelection = false, selectedId: initialSelectedId = null }) {
4956
5101
  const [expanded, setExpanded] = React.useState(new Set());
@@ -5017,10 +5162,10 @@ function CwTreeView({ data, onSelect, allowParentSelection = false, selectedId:
5017
5162
  const isLeaf = !hasChildren;
5018
5163
  const isSelected = selectedId?.toString().toLowerCase() === node.id.toString().toLowerCase();
5019
5164
  const selectable = allowParentSelection || isLeaf;
5020
- return (jsxRuntime.jsxs("div", { className: styles$8["tree-item"], children: [jsxRuntime.jsxs("div", { className: [
5021
- styles$8["tree-node"],
5022
- isSelected && styles$8["selected"],
5023
- !selectable && styles$8["non-selectable"]
5165
+ return (jsxRuntime.jsxs("div", { className: styles$9["tree-item"], children: [jsxRuntime.jsxs("div", { className: [
5166
+ styles$9["tree-node"],
5167
+ isSelected && styles$9["selected"],
5168
+ !selectable && styles$9["non-selectable"]
5024
5169
  ].filter(Boolean).join(' '), style: { paddingLeft: `${depth * 24 + 8}px` }, onClick: () => {
5025
5170
  if (selectable) {
5026
5171
  setSelectedId(node.id);
@@ -5029,7 +5174,7 @@ function CwTreeView({ data, onSelect, allowParentSelection = false, selectedId:
5029
5174
  else {
5030
5175
  toggleExpand(node.id);
5031
5176
  }
5032
- }, children: [hasChildren && (jsxRuntime.jsx(CwIcon, { size: "large", iconId: isExpanded ? "chevron-down" : "chevron-right" })), jsxRuntime.jsx("div", { className: `${styles$8["tree-label"]} ${!hasChildren ? styles$8["tree-spacer"] : ''}`, children: node.label })] }), hasChildren && isExpanded && (jsxRuntime.jsx("div", { className: styles$8["tree-children"], children: node.children.map((child) => renderNode(child, depth + 1)) }))] }, node.id));
5177
+ }, children: [hasChildren && (jsxRuntime.jsx(CwIcon, { size: "large", iconId: isExpanded ? "chevron-down" : "chevron-right" })), jsxRuntime.jsx("div", { className: `${styles$9["tree-label"]} ${!hasChildren ? styles$9["tree-spacer"] : ''}`, children: node.label })] }), hasChildren && isExpanded && (jsxRuntime.jsx("div", { className: styles$9["tree-children"], children: node.children.map((child) => renderNode(child, depth + 1)) }))] }, node.id));
5033
5178
  };
5034
5179
  // Function to search for nodes that match the search term
5035
5180
  const searchInTree = (nodes, searchTerm) => {
@@ -5053,7 +5198,129 @@ function CwTreeView({ data, onSelect, allowParentSelection = false, selectedId:
5053
5198
  return results;
5054
5199
  };
5055
5200
  const filteredData = searchInTree(data, search);
5056
- return (jsxRuntime.jsxs("div", { className: `cw-tree-view ${styles$8["tree-container"]}`, children: [jsxRuntime.jsxs("header", { children: [jsxRuntime.jsx("input", { type: "text", placeholder: "Search in tree...", value: search, onChange: (e) => setSearch(e.target.value) }), search && (jsxRuntime.jsx(CwButton, { onClick: () => setSearch(""), type: "button", icon: "close", variant: "icon", color: "neutral" }))] }), jsxRuntime.jsx("div", { className: styles$8["tree-wrapper"], children: filteredData.length > 0 ? (filteredData.map((node) => renderNode(node))) : (jsxRuntime.jsxs("div", { className: styles$8["empty-state"], children: [jsxRuntime.jsx(CwIcon, { iconId: "comment" }), search ? "No results found" : "There are no items"] })) })] }));
5201
+ return (jsxRuntime.jsxs("div", { className: `cw-tree-view ${styles$9["tree-container"]}`, children: [jsxRuntime.jsxs("header", { children: [jsxRuntime.jsx("input", { type: "text", placeholder: "Search in tree...", value: search, onChange: (e) => setSearch(e.target.value) }), search && (jsxRuntime.jsx(CwButton, { onClick: () => setSearch(""), type: "button", icon: "close", variant: "icon", color: "neutral" }))] }), jsxRuntime.jsx("div", { className: styles$9["tree-wrapper"], children: filteredData.length > 0 ? (filteredData.map((node) => renderNode(node))) : (jsxRuntime.jsxs("div", { className: styles$9["empty-state"], children: [jsxRuntime.jsx(CwIcon, { iconId: "comment" }), search ? "No results found" : "There are no items"] })) })] }));
5202
+ }
5203
+
5204
+ const EXACT_PHRASE = /"([^"]+)"/g;
5205
+ /**
5206
+ * Quoted phrases are matched against the label only; loose words against label + description + href.
5207
+ * Parsed once instead of per node.
5208
+ */
5209
+ function parseSearch(search) {
5210
+ const phrases = Array.from(search.matchAll(EXACT_PHRASE), match => match[1].toLowerCase());
5211
+ const words = search
5212
+ .replace(EXACT_PHRASE, "")
5213
+ .trim()
5214
+ .toLowerCase()
5215
+ .split(/\s+/)
5216
+ .filter(Boolean);
5217
+ return { phrases, words };
5218
+ }
5219
+ /**
5220
+ * Filters a nav tree by a search string, keeping a group whose descendants match.
5221
+ *
5222
+ * Supports `"quoted phrases"` (must appear in the label) alongside loose words (any field) — this is
5223
+ * behaviour users are told about, so don't simplify it.
5224
+ */
5225
+ function filterNavItems(items, search) {
5226
+ if (!search?.trim())
5227
+ return items;
5228
+ const { phrases, words } = parseSearch(search);
5229
+ if (phrases.length === 0 && words.length === 0)
5230
+ return items;
5231
+ const keep = (item, parentMatchedPhrases) => {
5232
+ const label = item.label.toLowerCase();
5233
+ const haystack = [item.label, item.description, item.href].filter(Boolean).join(" ").toLowerCase();
5234
+ const matchesPhrases = phrases.every(phrase => label.includes(phrase));
5235
+ const matchesWords = words.every(word => haystack.includes(word));
5236
+ const selfMatches = (phrases.length === 0 || matchesPhrases || parentMatchedPhrases) && matchesWords;
5237
+ if (!item.children?.length)
5238
+ return selfMatches ? item : null;
5239
+ let children = item.children
5240
+ .map(child => keep(child, matchesPhrases || parentMatchedPhrases))
5241
+ .filter((child) => child !== null);
5242
+ // A phrase-only search narrows the survivors further: each must carry the phrase itself.
5243
+ if (phrases.length > 0 && words.length === 0 && matchesPhrases) {
5244
+ children = children.filter(child => phrases.every(phrase => child.label.toLowerCase().includes(phrase)));
5245
+ }
5246
+ if (children.length > 0)
5247
+ return { ...item, children };
5248
+ // The group matched but nothing under it did. Returning `children: []` would make it a leaf —
5249
+ // and a leaf with no href — so keep the subtree instead of emptying it.
5250
+ return selfMatches ? item : null;
5251
+ };
5252
+ return items
5253
+ .map(item => keep(item, false))
5254
+ .filter((item) => item !== null);
5255
+ }
5256
+
5257
+ /**
5258
+ * Sorts the top level alphabetically, leaving every nested list in the order the consumer gave.
5259
+ *
5260
+ * Deliberately level 1 only: this exists because a long list of modules is hard to scan, while the
5261
+ * pages inside a module are ordered on purpose. Returns the input untouched when not sorting.
5262
+ */
5263
+ function sortNavItems(items, alphabetically) {
5264
+ if (!alphabetically)
5265
+ return items;
5266
+ return [...items].sort((first, second) => first.label.localeCompare(second.label));
5267
+ }
5268
+
5269
+ var styles$8 = {"menu":"cw-nav-menu-module__menu__LmeQg","expandIndicator":"cw-nav-menu-module__expandIndicator__TBSdQ","favorites":"cw-nav-menu-module__favorites__Esaqd","favoritesContent":"cw-nav-menu-module__favoritesContent__l5DGG","favoriteStar":"cw-nav-menu-module__favoriteStar__J-jzg","emptyMessage":"cw-nav-menu-module__emptyMessage__-CQNd","skeleton":"cw-nav-menu-module__skeleton__INQqF"};
5270
+
5271
+ const SKELETON_ROW_COUNT = 5;
5272
+ const defaultRenderLink = (item, children) => (jsxRuntime.jsx("a", { href: item.href, children: children }));
5273
+ /** Sizes only its own icons — content injected via `renderLink` is styled by the consumer. */
5274
+ function CwNavMenu({ items, loading = false, isActive, renderLink = defaultRenderLink, showExpandIndicator = false, search, emptyMessage, sortAlphabetically = false, favoritesSlot, favoritesLabel = "Favorites", favoritesProps, isFavorite, beforeTreeSlot, className, ...navProps }) {
5275
+ const visibleItems = sortNavItems(filterNavItems(items, search), sortAlphabetically);
5276
+ const showEmptyMessage = !loading && Boolean(emptyMessage) && Boolean(search?.trim()) && visibleItems.length === 0;
5277
+ const hasActiveDescendant = (node) => node.children?.some(child => isActive?.(child) || hasActiveDescendant(child)) ?? false;
5278
+ const renderItem = (item, level) => {
5279
+ const children = item.children;
5280
+ if (children && children.length > 0) {
5281
+ return (jsxRuntime.jsx("li", { children: jsxRuntime.jsxs("details", { "data-level": level, open: hasActiveDescendant(item) || undefined, children: [jsxRuntime.jsxs("summary", { children: [item.icon && jsxRuntime.jsx(CwIcon, { iconId: item.icon, size: level >= 2 ? "small" : "medium" }), item.label, (showExpandIndicator || level >= 2) && (jsxRuntime.jsx(CwIcon, { iconId: "chevron-down", size: "small", className: styles$8.expandIndicator }))] }), jsxRuntime.jsx("ul", { children: children.map(child => renderItem(child, level + 1)) })] }) }, item.id));
5282
+ }
5283
+ return (jsxRuntime.jsx("li", { "data-active": isActive?.(item) ? "true" : undefined, children: renderLink(item, jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [item.icon && jsxRuntime.jsx(CwIcon, { iconId: item.icon, size: "medium" }), item.label, isFavorite?.(item) && jsxRuntime.jsx(CwIcon, { iconId: "star", size: "small", className: styles$8.favoriteStar })] })) }, item.id));
5284
+ };
5285
+ return (jsxRuntime.jsxs("nav", { ...navProps, className: [styles$8.menu, className].filter(Boolean).join(" "), "aria-busy": loading || undefined, children: [favoritesSlot && (jsxRuntime.jsxs("details", { open: true, ...favoritesProps, className: [styles$8.favorites, favoritesProps?.className].filter(Boolean).join(" "), children: [jsxRuntime.jsxs("summary", { children: [jsxRuntime.jsx(CwIcon, { iconId: "star", size: "medium" }), favoritesLabel] }), jsxRuntime.jsx("div", { className: styles$8.favoritesContent, children: favoritesSlot })] })), beforeTreeSlot, jsxRuntime.jsx("ul", { children: loading
5286
+ ? Array.from({ length: SKELETON_ROW_COUNT }, (_unused, index) => (jsxRuntime.jsx("li", { className: styles$8.skeleton, children: jsxRuntime.jsx(CwSkeleton, { height: "var(--cw-size-small)", radius: "var(--cw-border-radius-small)" }) }, index)))
5287
+ : visibleItems.map(item => renderItem(item, 1)) }), showEmptyMessage && jsxRuntime.jsx("p", { className: styles$8.emptyMessage, children: emptyMessage })] }));
5288
+ }
5289
+
5290
+ /**
5291
+ * Pure keyboard-navigation resolver shared by the `CwSearchInput` combobox.
5292
+ * Kept side-effect-free so the arrow/home/end/enter/escape behaviour can be unit
5293
+ * tested without a DOM (the library's vitest runs with `environment: "node"`).
5294
+ */
5295
+ /**
5296
+ * Resolves a key press against the current highlight into a {@link SearchKeyAction}.
5297
+ * Arrow navigation wraps around; `Enter` selects only when a valid row is highlighted.
5298
+ *
5299
+ * @param key `KeyboardEvent.key` value.
5300
+ * @param currentIndex Currently highlighted option index (`-1` = none).
5301
+ * @param optionsLength Number of options currently in the dropdown.
5302
+ */
5303
+ function resolveSearchKeyAction(key, currentIndex, optionsLength) {
5304
+ if (optionsLength <= 0)
5305
+ return { type: "none" };
5306
+ switch (key) {
5307
+ case "ArrowDown":
5308
+ return { type: "move", index: currentIndex < optionsLength - 1 ? currentIndex + 1 : 0 };
5309
+ case "ArrowUp":
5310
+ return { type: "move", index: currentIndex > 0 ? currentIndex - 1 : optionsLength - 1 };
5311
+ case "Home":
5312
+ return { type: "move", index: 0 };
5313
+ case "End":
5314
+ return { type: "move", index: optionsLength - 1 };
5315
+ case "Enter":
5316
+ return currentIndex >= 0 && currentIndex < optionsLength
5317
+ ? { type: "select", index: currentIndex }
5318
+ : { type: "none" };
5319
+ case "Escape":
5320
+ return { type: "close" };
5321
+ default:
5322
+ return { type: "none" };
5323
+ }
5057
5324
  }
5058
5325
 
5059
5326
  /**
@@ -5074,14 +5341,19 @@ function CwSearchInput(optionsProps) {
5074
5341
  const [_selectedOption, setSelectedOption] = React.useState(null);
5075
5342
  const [showDropdown, setShowDropdown] = React.useState(false);
5076
5343
  const [isLoading, setIsLoading] = React.useState(false);
5344
+ const [highlightedIndex, setHighlightedIndex] = React.useState(-1);
5077
5345
  const wrapperRef = React.useRef(null);
5346
+ const inputRef = React.useRef(null);
5347
+ // Stable ids wiring the combobox input to its listbox popup for assistive tech.
5348
+ const listboxId = React.useId();
5349
+ const optionId = (index) => `${listboxId}-opt-${index}`;
5078
5350
  const { panelRef, panelStyle, renderPanel } = useDropdownPortal({
5079
5351
  anchorRef: wrapperRef,
5080
5352
  isOpen: showDropdown && filteredOptions.length > 0,
5081
- onClose: () => setShowDropdown(false),
5353
+ onClose: () => { setShowDropdown(false); setHighlightedIndex(-1); },
5082
5354
  });
5083
5355
  // Extract props
5084
- const { labelProps, iconProps, alignProps, selectList, handleChange, placeholder = "Search…", disabled, renderOption, style, id, className, defaultValue, ...otherProps } = optionsProps;
5356
+ const { labelProps, iconProps, alignProps, selectList, handleChange, placeholder = "Search…", disabled, renderOption, style, id, className, defaultValue, autoFocus, ...otherProps } = optionsProps;
5085
5357
  // Get direction for data attribute
5086
5358
  const direction = alignProps?.flexDirection || "row";
5087
5359
  // Make default value selection when loading the component
@@ -5100,9 +5372,10 @@ function CwSearchInput(optionsProps) {
5100
5372
  }
5101
5373
  }, [defaultValue, selectList]);
5102
5374
  const handleInputChange = (event) => {
5103
- const text = event.target.value;
5375
+ const text = event.currentTarget.value;
5104
5376
  setSearchText(text);
5105
5377
  setShowDropdown(true);
5378
+ setHighlightedIndex(-1);
5106
5379
  if (text === "") {
5107
5380
  setFilteredOptions(selectList);
5108
5381
  setSelectedOption(null);
@@ -5125,10 +5398,30 @@ function CwSearchInput(optionsProps) {
5125
5398
  };
5126
5399
  const handleInputFocus = () => {
5127
5400
  setShowDropdown(true);
5401
+ setHighlightedIndex(-1);
5128
5402
  if (searchText === "") {
5129
5403
  setFilteredOptions(selectList);
5130
5404
  }
5131
5405
  };
5406
+ const handleKeyDown = (event) => {
5407
+ if (!(showDropdown && filteredOptions.length > 0))
5408
+ return;
5409
+ const action = resolveSearchKeyAction(event.key, highlightedIndex, filteredOptions.length);
5410
+ switch (action.type) {
5411
+ case "move":
5412
+ event.preventDefault();
5413
+ setHighlightedIndex(action.index);
5414
+ break;
5415
+ case "select":
5416
+ event.preventDefault();
5417
+ handleOptionSelect(filteredOptions[action.index]);
5418
+ break;
5419
+ case "close":
5420
+ setShowDropdown(false);
5421
+ setHighlightedIndex(-1);
5422
+ break;
5423
+ }
5424
+ };
5132
5425
  const handleInputBlur = () => {
5133
5426
  // Dropdown is closed by useDropdownPortal's outside-click handler.
5134
5427
  // Blur alone must not close it — clicking an option would lose focus before the click fires.
@@ -5140,16 +5433,19 @@ function CwSearchInput(optionsProps) {
5140
5433
  handleChange(option.id);
5141
5434
  }
5142
5435
  setFilteredOptions([]);
5436
+ setHighlightedIndex(-1);
5143
5437
  };
5144
5438
  const handleClearClick = () => {
5145
5439
  setSearchText("");
5146
5440
  setFilteredOptions([]);
5147
5441
  setSelectedOption(null);
5442
+ setHighlightedIndex(-1);
5148
5443
  if (handleChange) {
5149
5444
  handleChange("");
5150
5445
  }
5446
+ inputRef.current?.focus();
5151
5447
  };
5152
- return (jsxRuntime.jsxs("div", { className: `cw-search-input ${className || ""}`, style: style, id: id, ...otherProps, "data-direction": direction, children: [jsxRuntime.jsxs(CwAlign, { ...alignProps, children: [labelProps && (jsxRuntime.jsx(CwLabel, { ...labelProps, children: labelProps.text })), jsxRuntime.jsxs("div", { className: "cw-search-input-wrapper", ref: wrapperRef, children: [jsxRuntime.jsx("input", { type: "text", value: searchText, onChange: handleInputChange, onFocus: handleInputFocus, onBlur: handleInputBlur, placeholder: placeholder, className: "cw-input-search", disabled: disabled }), isLoading && (jsxRuntime.jsx("div", { className: "cw-search-input-loading", children: jsxRuntime.jsx(CwIcon, { iconId: "spinner" }) })), jsxRuntime.jsx("div", { className: "cw-search-input-icons", children: searchText && !disabled && !isLoading ? (jsxRuntime.jsx(CwButton, { type: "button", onClick: handleClearClick, "aria-label": "Clear search", variant: "icon", icon: "close", color: "neutral" })) : (iconProps ? jsxRuntime.jsx(CwIcon, { ...iconProps }) : jsxRuntime.jsx(CwIcon, { iconId: "search" })) })] })] }), renderPanel(jsxRuntime.jsx("div", { ref: panelRef, className: dropdownStyles.dropdown, style: panelStyle, children: jsxRuntime.jsx("ul", { children: filteredOptions.map((option) => (jsxRuntime.jsx("li", { className: dropdownStyles.option, onClick: () => handleOptionSelect(option), onMouseDown: (e) => e.preventDefault(), children: renderOption ? renderOption(option) : option.description }, option.id))) }) }))] }));
5448
+ return (jsxRuntime.jsxs("div", { className: `cw-search-input ${className || ""}`, style: style, ...otherProps, "data-direction": direction, children: [jsxRuntime.jsxs(CwAlign, { ...alignProps, children: [labelProps && (jsxRuntime.jsx(CwLabel, { ...labelProps, children: labelProps.text })), jsxRuntime.jsxs("div", { className: "cw-search-input-wrapper", ref: wrapperRef, children: [jsxRuntime.jsx("input", { ref: inputRef, id: id, type: "text", value: searchText, onChange: handleInputChange, onKeyDown: handleKeyDown, onFocus: handleInputFocus, onBlur: handleInputBlur, placeholder: placeholder, className: "cw-input-search", disabled: disabled, autoFocus: autoFocus, autoComplete: "off", role: "combobox", "aria-haspopup": "listbox", "aria-expanded": showDropdown && filteredOptions.length > 0, "aria-controls": listboxId, "aria-activedescendant": highlightedIndex >= 0 ? optionId(highlightedIndex) : undefined }), isLoading && (jsxRuntime.jsx("div", { className: "cw-search-input-loading", children: jsxRuntime.jsx(CwIcon, { iconId: "spinner" }) })), jsxRuntime.jsx("div", { className: "cw-search-input-icons", children: searchText && !disabled && !isLoading ? (jsxRuntime.jsx(CwButton, { type: "button", onClick: handleClearClick, "aria-label": "Clear search", variant: "icon", icon: "close", color: "neutral" })) : (iconProps ? jsxRuntime.jsx(CwIcon, { ...iconProps }) : jsxRuntime.jsx(CwIcon, { iconId: "search" })) })] })] }), renderPanel(jsxRuntime.jsx("div", { ref: panelRef, id: listboxId, className: dropdownStyles.dropdown, style: panelStyle, role: "listbox", children: jsxRuntime.jsx("ul", { children: filteredOptions.map((option, index) => (jsxRuntime.jsx("li", { id: optionId(index), className: `${dropdownStyles.option}${index === highlightedIndex ? ` ${dropdownStyles.optionFocused}` : ""}`, onClick: () => handleOptionSelect(option), onMouseDown: (e) => e.preventDefault(), onMouseEnter: () => setHighlightedIndex(index), role: "option", "aria-selected": index === highlightedIndex, children: renderOption ? renderOption(option) : option.description }, option.id))) }) }))] }));
5153
5449
  }
5154
5450
 
5155
5451
  /**
@@ -11346,7 +11642,6 @@ exports.CwDisplayMessage = CwDisplayMessage;
11346
11642
  exports.CwDropdown = CwDropdown;
11347
11643
  exports.CwDropdownFilter = CwDropdownFilter;
11348
11644
  exports.CwExpandable = CwExpandable;
11349
- exports.CwFileUpload = CwFileUpload;
11350
11645
  exports.CwFileUploadMultiple = CwFileUploadMultiple;
11351
11646
  exports.CwFindAirport = CwFindAirport;
11352
11647
  exports.CwFindCrewmember = CwFindCrewmember;
@@ -11368,7 +11663,6 @@ exports.CwInputText = CwInputText;
11368
11663
  exports.CwKeyValueList = CwKeyValueList;
11369
11664
  exports.CwLabel = CwLabel;
11370
11665
  exports.CwLoading = CwLoading;
11371
- exports.CwLoadingSmall = CwLoadingSmall;
11372
11666
  exports.CwMasterDetail = CwMasterDetail;
11373
11667
  exports.CwMessage = CwMessage;
11374
11668
  exports.CwMessageManager = CwMessageManager;
@@ -11377,9 +11671,11 @@ exports.CwModalHover = CwModalHover;
11377
11671
  exports.CwModalReportFunctional = CwModalReportFunctional;
11378
11672
  exports.CwMultiFilter = CwMultiFilter;
11379
11673
  exports.CwMultiFilterTag = CwMultiFilterTag;
11674
+ exports.CwNavMenu = CwNavMenu;
11380
11675
  exports.CwNote = CwNote;
11381
11676
  exports.CwOption = CwOption;
11382
11677
  exports.CwPopoverButton = CwPopoverButton;
11678
+ exports.CwProgress = CwProgress;
11383
11679
  exports.CwRadioGroup = CwRadioGroup;
11384
11680
  exports.CwReportModal = CwReportModal;
11385
11681
  exports.CwScheduler = CwScheduler;
@@ -11388,6 +11684,7 @@ exports.CwSearchInput = CwSearchInput;
11388
11684
  exports.CwSelect = CwSelect;
11389
11685
  exports.CwSelectList = CwSelectList;
11390
11686
  exports.CwSelectListItems = CwSelectListItems;
11687
+ exports.CwSkeleton = CwSkeleton;
11391
11688
  exports.CwSortableList = CwSortableList;
11392
11689
  exports.CwSortableTable = CwSortableTable;
11393
11690
  exports.CwSuperScheduler = CwSuperScheduler;
@@ -11436,12 +11733,16 @@ exports.TooltipConstraintContext = TooltipConstraintContext;
11436
11733
  exports.UiEvent = UiEvent;
11437
11734
  exports.Weekdays = Weekdays;
11438
11735
  exports.cblEvent = cblEvent;
11736
+ exports.configureCwLoading = configureCwLoading;
11439
11737
  exports.eventIsVisible = eventIsVisible;
11738
+ exports.filterNavItems = filterNavItems;
11440
11739
  exports.filterVisibleEvents = filterVisibleEvents;
11740
+ exports.getCwLoadingDefaults = getCwLoadingDefaults;
11441
11741
  exports.getDefaultDivisions = getDefaultDivisions;
11442
11742
  exports.getEventSizes = getEventSizes;
11443
11743
  exports.getPresetsByKeysTemporal = getPresetsByKeysTemporal;
11444
11744
  exports.itemsToMultiFilterTags = itemsToMultiFilterTags;
11745
+ exports.sortNavItems = sortNavItems;
11445
11746
  exports.useCwMessage = useCwMessage;
11446
11747
  exports.useSortableList = useSortableList;
11447
11748
  exports.useSortableTable = useSortableTable;