@cratis/scene.primereact 4.6.0 → 4.8.0

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 (388) hide show
  1. package/.storybook/preview.tsx +8 -1
  2. package/EnumerationResolution.ts +7 -0
  3. package/README.md +22 -12
  4. package/data/DataGallery.stories.tsx +6 -0
  5. package/data/DataScrollerRow.tsx +35 -0
  6. package/data/PrimeDataScroller.tsx +84 -0
  7. package/data/PrimeTreeTable.tsx +145 -0
  8. package/data/TreeTableCheckState.ts +9 -0
  9. package/data/TreeTableRow.ts +22 -0
  10. package/data/TreeTableRowView.tsx +86 -0
  11. package/data/TreeTableSelectionMode.ts +10 -0
  12. package/data/checkboxSelection.ts +92 -0
  13. package/data/index.ts +4 -0
  14. package/data/isSerializedLegacyElement.ts +30 -0
  15. package/data/readableValue.ts +32 -0
  16. package/data/selectionKeysOf.ts +40 -0
  17. package/data/treeTableRows.ts +32 -0
  18. package/data/useIncrementalLoad.ts +36 -0
  19. package/data/useLoadOnReach.ts +31 -0
  20. package/data/useTreeGridNavigation.ts +81 -0
  21. package/dist/cjs/data/DataScrollerRow.js +50 -0
  22. package/dist/cjs/data/DataScrollerRow.js.map +1 -0
  23. package/dist/cjs/data/PrimeDataScroller.js +120 -0
  24. package/dist/cjs/data/PrimeDataScroller.js.map +1 -0
  25. package/dist/cjs/data/PrimeTreeTable.js +217 -0
  26. package/dist/cjs/data/PrimeTreeTable.js.map +1 -0
  27. package/dist/cjs/data/TreeTableCheckState.js +13 -0
  28. package/dist/cjs/data/TreeTableCheckState.js.map +1 -0
  29. package/dist/cjs/data/TreeTableRowView.js +76 -0
  30. package/dist/cjs/data/TreeTableRowView.js.map +1 -0
  31. package/dist/cjs/data/TreeTableSelectionMode.js +14 -0
  32. package/dist/cjs/data/TreeTableSelectionMode.js.map +1 -0
  33. package/dist/cjs/data/checkboxSelection.js +88 -0
  34. package/dist/cjs/data/checkboxSelection.js.map +1 -0
  35. package/dist/cjs/data/isSerializedLegacyElement.js +30 -0
  36. package/dist/cjs/data/isSerializedLegacyElement.js.map +1 -0
  37. package/dist/cjs/data/readableValue.js +31 -0
  38. package/dist/cjs/data/readableValue.js.map +1 -0
  39. package/dist/cjs/data/selectionKeysOf.js +40 -0
  40. package/dist/cjs/data/selectionKeysOf.js.map +1 -0
  41. package/dist/cjs/data/treeTableRows.js +42 -0
  42. package/dist/cjs/data/treeTableRows.js.map +1 -0
  43. package/dist/cjs/data/useIncrementalLoad.js +46 -0
  44. package/dist/cjs/data/useIncrementalLoad.js.map +1 -0
  45. package/dist/cjs/data/useLoadOnReach.js +42 -0
  46. package/dist/cjs/data/useLoadOnReach.js.map +1 -0
  47. package/dist/cjs/data/useTreeGridNavigation.js +75 -0
  48. package/dist/cjs/data/useTreeGridNavigation.js.map +1 -0
  49. package/dist/cjs/editor/PrimeEditor.js +96 -0
  50. package/dist/cjs/editor/PrimeEditor.js.map +1 -0
  51. package/dist/cjs/editor/QuillLoaderContext.js +10 -0
  52. package/dist/cjs/editor/QuillLoaderContext.js.map +1 -0
  53. package/dist/cjs/editor/QuillLoaderProvider.js +21 -0
  54. package/dist/cjs/editor/QuillLoaderProvider.js.map +1 -0
  55. package/dist/cjs/editor/applyHtml.js +25 -0
  56. package/dist/cjs/editor/applyHtml.js.map +1 -0
  57. package/dist/cjs/editor/characterCount.js +10 -0
  58. package/dist/cjs/editor/characterCount.js.map +1 -0
  59. package/dist/cjs/editor/htmlToPlainText.js +101 -0
  60. package/dist/cjs/editor/htmlToPlainText.js.map +1 -0
  61. package/dist/cjs/editor/renderSafeNodes.js +35 -0
  62. package/dist/cjs/editor/renderSafeNodes.js.map +1 -0
  63. package/dist/cjs/editor/safeUrls.js +44 -0
  64. package/dist/cjs/editor/safeUrls.js.map +1 -0
  65. package/dist/cjs/editor/sanitizeHtml.js +140 -0
  66. package/dist/cjs/editor/sanitizeHtml.js.map +1 -0
  67. package/dist/cjs/editor/serializeSafeNodes.js +33 -0
  68. package/dist/cjs/editor/serializeSafeNodes.js.map +1 -0
  69. package/dist/cjs/editor/toolbarLayout.js +35 -0
  70. package/dist/cjs/editor/toolbarLayout.js.map +1 -0
  71. package/dist/cjs/editor/useQuillEditor.js +137 -0
  72. package/dist/cjs/editor/useQuillEditor.js.map +1 -0
  73. package/dist/cjs/file/FileUploadContext.js +13 -0
  74. package/dist/cjs/file/FileUploadContext.js.map +1 -0
  75. package/dist/cjs/file/FileUploadHandlerProvider.js +25 -0
  76. package/dist/cjs/file/FileUploadHandlerProvider.js.map +1 -0
  77. package/dist/cjs/file/FileUploadMode.js +13 -0
  78. package/dist/cjs/file/FileUploadMode.js.map +1 -0
  79. package/dist/cjs/file/PrimeFileUpload.js +161 -0
  80. package/dist/cjs/file/PrimeFileUpload.js.map +1 -0
  81. package/dist/cjs/file/postFiles.js +31 -0
  82. package/dist/cjs/file/postFiles.js.map +1 -0
  83. package/dist/cjs/file/resolveUploadTarget.js +68 -0
  84. package/dist/cjs/file/resolveUploadTarget.js.map +1 -0
  85. package/dist/cjs/file/useUploadSession.js +62 -0
  86. package/dist/cjs/file/useUploadSession.js.map +1 -0
  87. package/dist/cjs/index.js +32 -0
  88. package/dist/cjs/index.js.map +1 -1
  89. package/dist/cjs/legacyEnumerationChoices.js +39 -0
  90. package/dist/cjs/legacyEnumerationChoices.js.map +1 -0
  91. package/dist/cjs/loadQuill/index.js +22 -0
  92. package/dist/cjs/loadQuill/index.js.map +1 -0
  93. package/dist/cjs/primeReactComponents.js +10 -0
  94. package/dist/cjs/primeReactComponents.js.map +1 -1
  95. package/dist/cjs/primeReactDescriptors.js +243 -0
  96. package/dist/cjs/primeReactDescriptors.js.map +1 -1
  97. package/dist/cjs/primeReactPackage.js +4 -0
  98. package/dist/cjs/primeReactPackage.js.map +1 -1
  99. package/dist/cjs/resolveEnumeration.js +55 -0
  100. package/dist/cjs/resolveEnumeration.js.map +1 -0
  101. package/dist/cjs/treeNodes.js +42 -7
  102. package/dist/cjs/treeNodes.js.map +1 -1
  103. package/dist/cjs/useResettingState.js +47 -0
  104. package/dist/cjs/useResettingState.js.map +1 -0
  105. package/dist/esm/EnumerationResolution.d.ts +9 -0
  106. package/dist/esm/EnumerationResolution.d.ts.map +1 -0
  107. package/dist/esm/EnumerationResolution.js +2 -0
  108. package/dist/esm/EnumerationResolution.js.map +1 -0
  109. package/dist/esm/data/DataGallery.stories.d.ts.map +1 -1
  110. package/dist/esm/data/DataGallery.stories.js +6 -0
  111. package/dist/esm/data/DataGallery.stories.js.map +1 -1
  112. package/dist/esm/data/DataScrollerRow.d.ts +4 -0
  113. package/dist/esm/data/DataScrollerRow.d.ts.map +1 -0
  114. package/dist/esm/data/DataScrollerRow.js +48 -0
  115. package/dist/esm/data/DataScrollerRow.js.map +1 -0
  116. package/dist/esm/data/PrimeDataScroller.d.ts +3 -0
  117. package/dist/esm/data/PrimeDataScroller.d.ts.map +1 -0
  118. package/dist/esm/data/PrimeDataScroller.js +118 -0
  119. package/dist/esm/data/PrimeDataScroller.js.map +1 -0
  120. package/dist/esm/data/PrimeTreeTable.d.ts +3 -0
  121. package/dist/esm/data/PrimeTreeTable.d.ts.map +1 -0
  122. package/dist/esm/data/PrimeTreeTable.js +215 -0
  123. package/dist/esm/data/PrimeTreeTable.js.map +1 -0
  124. package/dist/esm/data/TreeTableCheckState.d.ts +6 -0
  125. package/dist/esm/data/TreeTableCheckState.d.ts.map +1 -0
  126. package/dist/esm/data/TreeTableCheckState.js +11 -0
  127. package/dist/esm/data/TreeTableCheckState.js.map +1 -0
  128. package/dist/esm/data/TreeTableRow.d.ts +10 -0
  129. package/dist/esm/data/TreeTableRow.d.ts.map +1 -0
  130. package/dist/esm/data/TreeTableRow.js +2 -0
  131. package/dist/esm/data/TreeTableRow.js.map +1 -0
  132. package/dist/esm/data/TreeTableRowView.d.ts +21 -0
  133. package/dist/esm/data/TreeTableRowView.d.ts.map +1 -0
  134. package/dist/esm/data/TreeTableRowView.js +74 -0
  135. package/dist/esm/data/TreeTableRowView.js.map +1 -0
  136. package/dist/esm/data/TreeTableSelectionMode.d.ts +7 -0
  137. package/dist/esm/data/TreeTableSelectionMode.d.ts.map +1 -0
  138. package/dist/esm/data/TreeTableSelectionMode.js +12 -0
  139. package/dist/esm/data/TreeTableSelectionMode.js.map +1 -0
  140. package/dist/esm/data/checkboxSelection.d.ts +9 -0
  141. package/dist/esm/data/checkboxSelection.d.ts.map +1 -0
  142. package/dist/esm/data/checkboxSelection.js +85 -0
  143. package/dist/esm/data/checkboxSelection.js.map +1 -0
  144. package/dist/esm/data/index.d.ts +4 -0
  145. package/dist/esm/data/index.d.ts.map +1 -1
  146. package/dist/esm/data/index.js +4 -0
  147. package/dist/esm/data/index.js.map +1 -1
  148. package/dist/esm/data/isSerializedLegacyElement.d.ts +3 -0
  149. package/dist/esm/data/isSerializedLegacyElement.d.ts.map +1 -0
  150. package/dist/esm/data/isSerializedLegacyElement.js +27 -0
  151. package/dist/esm/data/isSerializedLegacyElement.js.map +1 -0
  152. package/dist/esm/data/readableValue.d.ts +2 -0
  153. package/dist/esm/data/readableValue.d.ts.map +1 -0
  154. package/dist/esm/data/readableValue.js +29 -0
  155. package/dist/esm/data/readableValue.js.map +1 -0
  156. package/dist/esm/data/selectionKeysOf.d.ts +2 -0
  157. package/dist/esm/data/selectionKeysOf.d.ts.map +1 -0
  158. package/dist/esm/data/selectionKeysOf.js +38 -0
  159. package/dist/esm/data/selectionKeysOf.js.map +1 -0
  160. package/dist/esm/data/treeTableRows.d.ts +6 -0
  161. package/dist/esm/data/treeTableRows.d.ts.map +1 -0
  162. package/dist/esm/data/treeTableRows.js +38 -0
  163. package/dist/esm/data/treeTableRows.js.map +1 -0
  164. package/dist/esm/data/useIncrementalLoad.d.ts +6 -0
  165. package/dist/esm/data/useIncrementalLoad.d.ts.map +1 -0
  166. package/dist/esm/data/useIncrementalLoad.js +44 -0
  167. package/dist/esm/data/useIncrementalLoad.js.map +1 -0
  168. package/dist/esm/data/useLoadOnReach.d.ts +3 -0
  169. package/dist/esm/data/useLoadOnReach.d.ts.map +1 -0
  170. package/dist/esm/data/useLoadOnReach.js +40 -0
  171. package/dist/esm/data/useLoadOnReach.js.map +1 -0
  172. package/dist/esm/data/useTreeGridNavigation.d.ts +17 -0
  173. package/dist/esm/data/useTreeGridNavigation.d.ts.map +1 -0
  174. package/dist/esm/data/useTreeGridNavigation.js +73 -0
  175. package/dist/esm/data/useTreeGridNavigation.js.map +1 -0
  176. package/dist/esm/editor/PrimeEditor.d.ts +3 -0
  177. package/dist/esm/editor/PrimeEditor.d.ts.map +1 -0
  178. package/dist/esm/editor/PrimeEditor.js +94 -0
  179. package/dist/esm/editor/PrimeEditor.js.map +1 -0
  180. package/dist/esm/editor/QuillConstructor.d.ts +4 -0
  181. package/dist/esm/editor/QuillConstructor.d.ts.map +1 -0
  182. package/dist/esm/editor/QuillConstructor.js +2 -0
  183. package/dist/esm/editor/QuillConstructor.js.map +1 -0
  184. package/dist/esm/editor/QuillEditorOptions.d.ts +13 -0
  185. package/dist/esm/editor/QuillEditorOptions.d.ts.map +1 -0
  186. package/dist/esm/editor/QuillEditorOptions.js +2 -0
  187. package/dist/esm/editor/QuillEditorOptions.js.map +1 -0
  188. package/dist/esm/editor/QuillEditorState.d.ts +6 -0
  189. package/dist/esm/editor/QuillEditorState.d.ts.map +1 -0
  190. package/dist/esm/editor/QuillEditorState.js +2 -0
  191. package/dist/esm/editor/QuillEditorState.js.map +1 -0
  192. package/dist/esm/editor/QuillInstance.d.ts +16 -0
  193. package/dist/esm/editor/QuillInstance.d.ts.map +1 -0
  194. package/dist/esm/editor/QuillInstance.js +2 -0
  195. package/dist/esm/editor/QuillInstance.js.map +1 -0
  196. package/dist/esm/editor/QuillLoader.d.ts +5 -0
  197. package/dist/esm/editor/QuillLoader.d.ts.map +1 -0
  198. package/dist/esm/editor/QuillLoader.js +2 -0
  199. package/dist/esm/editor/QuillLoader.js.map +1 -0
  200. package/dist/esm/editor/QuillLoaderContext.d.ts +3 -0
  201. package/dist/esm/editor/QuillLoaderContext.d.ts.map +1 -0
  202. package/dist/esm/editor/QuillLoaderContext.js +8 -0
  203. package/dist/esm/editor/QuillLoaderContext.js.map +1 -0
  204. package/dist/esm/editor/QuillLoaderProvider.d.ts +8 -0
  205. package/dist/esm/editor/QuillLoaderProvider.d.ts.map +1 -0
  206. package/dist/esm/editor/QuillLoaderProvider.js +19 -0
  207. package/dist/esm/editor/QuillLoaderProvider.js.map +1 -0
  208. package/dist/esm/editor/QuillOptions.d.ts +9 -0
  209. package/dist/esm/editor/QuillOptions.d.ts.map +1 -0
  210. package/dist/esm/editor/QuillOptions.js +2 -0
  211. package/dist/esm/editor/QuillOptions.js.map +1 -0
  212. package/dist/esm/editor/SafeElement.d.ts +7 -0
  213. package/dist/esm/editor/SafeElement.d.ts.map +1 -0
  214. package/dist/esm/editor/SafeElement.js +2 -0
  215. package/dist/esm/editor/SafeElement.js.map +1 -0
  216. package/dist/esm/editor/SafeNode.d.ts +3 -0
  217. package/dist/esm/editor/SafeNode.d.ts.map +1 -0
  218. package/dist/esm/editor/SafeNode.js +2 -0
  219. package/dist/esm/editor/SafeNode.js.map +1 -0
  220. package/dist/esm/editor/applyHtml.d.ts +3 -0
  221. package/dist/esm/editor/applyHtml.d.ts.map +1 -0
  222. package/dist/esm/editor/applyHtml.js +23 -0
  223. package/dist/esm/editor/applyHtml.js.map +1 -0
  224. package/dist/esm/editor/characterCount.d.ts +3 -0
  225. package/dist/esm/editor/characterCount.d.ts.map +1 -0
  226. package/dist/esm/editor/characterCount.js +8 -0
  227. package/dist/esm/editor/characterCount.js.map +1 -0
  228. package/dist/esm/editor/htmlToPlainText.d.ts +2 -0
  229. package/dist/esm/editor/htmlToPlainText.d.ts.map +1 -0
  230. package/dist/esm/editor/htmlToPlainText.js +99 -0
  231. package/dist/esm/editor/htmlToPlainText.js.map +1 -0
  232. package/dist/esm/editor/index.d.ts +14 -0
  233. package/dist/esm/editor/index.d.ts.map +1 -0
  234. package/dist/esm/editor/index.js +14 -0
  235. package/dist/esm/editor/index.js.map +1 -0
  236. package/dist/esm/editor/renderSafeNodes.d.ts +4 -0
  237. package/dist/esm/editor/renderSafeNodes.d.ts.map +1 -0
  238. package/dist/esm/editor/renderSafeNodes.js +33 -0
  239. package/dist/esm/editor/renderSafeNodes.js.map +1 -0
  240. package/dist/esm/editor/safeUrls.d.ts +3 -0
  241. package/dist/esm/editor/safeUrls.d.ts.map +1 -0
  242. package/dist/esm/editor/safeUrls.js +41 -0
  243. package/dist/esm/editor/safeUrls.js.map +1 -0
  244. package/dist/esm/editor/sanitizeHtml.d.ts +3 -0
  245. package/dist/esm/editor/sanitizeHtml.d.ts.map +1 -0
  246. package/dist/esm/editor/sanitizeHtml.js +138 -0
  247. package/dist/esm/editor/sanitizeHtml.js.map +1 -0
  248. package/dist/esm/editor/serializeSafeNodes.d.ts +3 -0
  249. package/dist/esm/editor/serializeSafeNodes.d.ts.map +1 -0
  250. package/dist/esm/editor/serializeSafeNodes.js +31 -0
  251. package/dist/esm/editor/serializeSafeNodes.js.map +1 -0
  252. package/dist/esm/editor/toolbarLayout.d.ts +2 -0
  253. package/dist/esm/editor/toolbarLayout.d.ts.map +1 -0
  254. package/dist/esm/editor/toolbarLayout.js +33 -0
  255. package/dist/esm/editor/toolbarLayout.js.map +1 -0
  256. package/dist/esm/editor/useQuillEditor.d.ts +4 -0
  257. package/dist/esm/editor/useQuillEditor.d.ts.map +1 -0
  258. package/dist/esm/editor/useQuillEditor.js +135 -0
  259. package/dist/esm/editor/useQuillEditor.js.map +1 -0
  260. package/dist/esm/file/FileGallery.stories.d.ts +19 -0
  261. package/dist/esm/file/FileGallery.stories.d.ts.map +1 -0
  262. package/dist/esm/file/FileGallery.stories.js +23 -0
  263. package/dist/esm/file/FileGallery.stories.js.map +1 -0
  264. package/dist/esm/file/FileUploadContext.d.ts +7 -0
  265. package/dist/esm/file/FileUploadContext.d.ts.map +1 -0
  266. package/dist/esm/file/FileUploadContext.js +11 -0
  267. package/dist/esm/file/FileUploadContext.js.map +1 -0
  268. package/dist/esm/file/FileUploadHandler.d.ts +4 -0
  269. package/dist/esm/file/FileUploadHandler.d.ts.map +1 -0
  270. package/dist/esm/file/FileUploadHandler.js +2 -0
  271. package/dist/esm/file/FileUploadHandler.js.map +1 -0
  272. package/dist/esm/file/FileUploadHandlerProvider.d.ts +9 -0
  273. package/dist/esm/file/FileUploadHandlerProvider.d.ts.map +1 -0
  274. package/dist/esm/file/FileUploadHandlerProvider.js +23 -0
  275. package/dist/esm/file/FileUploadHandlerProvider.js.map +1 -0
  276. package/dist/esm/file/FileUploadMode.d.ts +6 -0
  277. package/dist/esm/file/FileUploadMode.d.ts.map +1 -0
  278. package/dist/esm/file/FileUploadMode.js +11 -0
  279. package/dist/esm/file/FileUploadMode.js.map +1 -0
  280. package/dist/esm/file/PrimeFileUpload.d.ts +3 -0
  281. package/dist/esm/file/PrimeFileUpload.d.ts.map +1 -0
  282. package/dist/esm/file/PrimeFileUpload.js +159 -0
  283. package/dist/esm/file/PrimeFileUpload.js.map +1 -0
  284. package/dist/esm/file/UploadStatus.d.ts +5 -0
  285. package/dist/esm/file/UploadStatus.d.ts.map +1 -0
  286. package/dist/esm/file/UploadStatus.js +2 -0
  287. package/dist/esm/file/UploadStatus.js.map +1 -0
  288. package/dist/esm/file/UploadTarget.d.ts +8 -0
  289. package/dist/esm/file/UploadTarget.d.ts.map +1 -0
  290. package/dist/esm/file/UploadTarget.js +2 -0
  291. package/dist/esm/file/UploadTarget.js.map +1 -0
  292. package/dist/esm/file/index.d.ts +7 -0
  293. package/dist/esm/file/index.d.ts.map +1 -0
  294. package/dist/esm/file/index.js +7 -0
  295. package/dist/esm/file/index.js.map +1 -0
  296. package/dist/esm/file/postFiles.d.ts +2 -0
  297. package/dist/esm/file/postFiles.d.ts.map +1 -0
  298. package/dist/esm/file/postFiles.js +29 -0
  299. package/dist/esm/file/postFiles.js.map +1 -0
  300. package/dist/esm/file/resolveUploadTarget.d.ts +3 -0
  301. package/dist/esm/file/resolveUploadTarget.d.ts.map +1 -0
  302. package/dist/esm/file/resolveUploadTarget.js +66 -0
  303. package/dist/esm/file/resolveUploadTarget.js.map +1 -0
  304. package/dist/esm/file/useUploadSession.d.ts +10 -0
  305. package/dist/esm/file/useUploadSession.d.ts.map +1 -0
  306. package/dist/esm/file/useUploadSession.js +60 -0
  307. package/dist/esm/file/useUploadSession.js.map +1 -0
  308. package/dist/esm/form/FormGallery.stories.d.ts.map +1 -1
  309. package/dist/esm/form/FormGallery.stories.js +1 -0
  310. package/dist/esm/form/FormGallery.stories.js.map +1 -1
  311. package/dist/esm/index.d.ts +2 -0
  312. package/dist/esm/index.d.ts.map +1 -1
  313. package/dist/esm/index.js +16 -1
  314. package/dist/esm/index.js.map +1 -1
  315. package/dist/esm/legacyEnumerationChoices.d.ts +3 -0
  316. package/dist/esm/legacyEnumerationChoices.d.ts.map +1 -0
  317. package/dist/esm/legacyEnumerationChoices.js +37 -0
  318. package/dist/esm/legacyEnumerationChoices.js.map +1 -0
  319. package/dist/esm/loadQuill/index.d.ts +3 -0
  320. package/dist/esm/loadQuill/index.d.ts.map +1 -0
  321. package/dist/esm/loadQuill/index.js +20 -0
  322. package/dist/esm/loadQuill/index.js.map +1 -0
  323. package/dist/esm/primeReactComponents.d.ts.map +1 -1
  324. package/dist/esm/primeReactComponents.js +10 -0
  325. package/dist/esm/primeReactComponents.js.map +1 -1
  326. package/dist/esm/primeReactDescriptors.d.ts.map +1 -1
  327. package/dist/esm/primeReactDescriptors.js +243 -0
  328. package/dist/esm/primeReactDescriptors.js.map +1 -1
  329. package/dist/esm/primeReactPackage.js +4 -0
  330. package/dist/esm/primeReactPackage.js.map +1 -1
  331. package/dist/esm/resolveEnumeration.d.ts +3 -0
  332. package/dist/esm/resolveEnumeration.d.ts.map +1 -0
  333. package/dist/esm/resolveEnumeration.js +53 -0
  334. package/dist/esm/resolveEnumeration.js.map +1 -0
  335. package/dist/esm/treeNodes.d.ts +2 -1
  336. package/dist/esm/treeNodes.d.ts.map +1 -1
  337. package/dist/esm/treeNodes.js +42 -8
  338. package/dist/esm/treeNodes.js.map +1 -1
  339. package/dist/esm/tsconfig.tsbuildinfo +1 -1
  340. package/dist/esm/useResettingState.d.ts +3 -0
  341. package/dist/esm/useResettingState.d.ts.map +1 -0
  342. package/dist/esm/useResettingState.js +45 -0
  343. package/dist/esm/useResettingState.js.map +1 -0
  344. package/editor/PrimeEditor.tsx +83 -0
  345. package/editor/QuillConstructor.ts +8 -0
  346. package/editor/QuillEditorOptions.ts +29 -0
  347. package/editor/QuillEditorState.ts +14 -0
  348. package/editor/QuillInstance.ts +27 -0
  349. package/editor/QuillLoader.ts +13 -0
  350. package/editor/QuillLoaderContext.ts +8 -0
  351. package/editor/QuillLoaderProvider.tsx +24 -0
  352. package/editor/QuillOptions.ts +10 -0
  353. package/editor/SafeElement.ts +15 -0
  354. package/editor/SafeNode.ts +7 -0
  355. package/editor/applyHtml.ts +21 -0
  356. package/editor/characterCount.ts +9 -0
  357. package/editor/htmlToPlainText.ts +74 -0
  358. package/editor/index.ts +16 -0
  359. package/editor/renderSafeNodes.tsx +26 -0
  360. package/editor/safeUrls.ts +43 -0
  361. package/editor/sanitizeHtml.ts +94 -0
  362. package/editor/serializeSafeNodes.ts +26 -0
  363. package/editor/toolbarLayout.ts +10 -0
  364. package/editor/useQuillEditor.ts +114 -0
  365. package/file/FileGallery.stories.tsx +32 -0
  366. package/file/FileUploadContext.ts +17 -0
  367. package/file/FileUploadHandler.ts +15 -0
  368. package/file/FileUploadHandlerProvider.tsx +33 -0
  369. package/file/FileUploadMode.ts +9 -0
  370. package/file/PrimeFileUpload.tsx +129 -0
  371. package/file/UploadStatus.ts +9 -0
  372. package/file/UploadTarget.ts +12 -0
  373. package/file/index.ts +9 -0
  374. package/file/postFiles.ts +23 -0
  375. package/file/resolveUploadTarget.ts +61 -0
  376. package/file/useUploadSession.ts +67 -0
  377. package/form/FormGallery.stories.tsx +1 -0
  378. package/index.ts +2 -0
  379. package/legacyEnumerationChoices.ts +35 -0
  380. package/loadQuill/index.ts +21 -0
  381. package/package.json +17 -7
  382. package/primeReactComponents.ts +8 -0
  383. package/primeReactDescriptors.ts +63 -0
  384. package/primeReactPackage.ts +2 -2
  385. package/primeReactTheme.css +69 -0
  386. package/resolveEnumeration.ts +50 -0
  387. package/treeNodes.ts +44 -6
  388. package/useResettingState.ts +34 -0
@@ -3,6 +3,8 @@
3
3
 
4
4
  import type { Decorator, Preview } from '@storybook/react';
5
5
  import { PrimeReactProvider } from '@primereact/core';
6
+ import { QuillLoaderProvider } from '../editor';
7
+ import { loadQuill } from '../loadQuill';
6
8
  import { primeReactTheme, usePrimeReactTheme } from '../theme';
7
9
  import '../primeReactTheme.css';
8
10
  import './preview.css';
@@ -12,6 +14,9 @@ import './preview.css';
12
14
  // resolve to. Only the icon font is still a stylesheet.
13
15
  import 'primeicons/primeicons.css';
14
16
 
17
+ // A host that wants editable rich text installs Quill and its stylesheet, and provides the loader.
18
+ import 'quill/dist/quill.snow.css';
19
+
15
20
  /**
16
21
  * Puts every story inside a `PrimeReactProvider` carrying a real Scene theme.
17
22
  *
@@ -29,7 +34,9 @@ const withTheme: Decorator = (Story) => {
29
34
 
30
35
  return (
31
36
  <PrimeReactProvider value={configuration}>
32
- <Story />
37
+ <QuillLoaderProvider loader={loadQuill}>
38
+ <Story />
39
+ </QuillLoaderProvider>
33
40
  </PrimeReactProvider>
34
41
  );
35
42
  };
@@ -0,0 +1,7 @@
1
+ // Copyright (c) Cratis. All rights reserved.
2
+ // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3
+
4
+ /** The outcome of resolving an authored enumeration value: the member, or the reason none could be chosen. */
5
+ export type EnumerationResolution<TMember extends string> =
6
+ | { isValid: true; value: TMember }
7
+ | { isValid: false; value: unknown; message: string };
package/README.md CHANGED
@@ -109,16 +109,9 @@ twenty-fifth theme cannot be added without it. The full attribution table is in
109
109
  components - through the semantic token layer `SceneThemeProvider` applies to the whole subtree, though
110
110
  not through the `--p-*` properties, which only PrimeReact's own components read.
111
111
 
112
- ## Not covered
112
+ ## Optional peers
113
113
 
114
- | Component | Why |
115
- | --- | --- |
116
- | `editor` | `Editor` wraps Quill and needs `quill` installed. Same reasoning — a rich-text editor is a product decision, not a mapping. |
117
-
118
- The editor is a deliberate omission, not an oversight. A profile needing it should activate a package
119
- that owns its dependency.
120
-
121
- ## Chart.js peer dependency
114
+ ### Chart.js peer dependency
122
115
 
123
116
  PrimeReact 11 removed its former Chart.js wrapper, so the Scene `chart` adapter mounts a Chart.js canvas
124
117
  itself. `chart.js@^4.5.1` is an optional peer dependency of `@cratis/scene.primereact`, optional only in that
@@ -134,6 +127,23 @@ the type, data or options change in content, not when a document edit hands it e
134
127
  rewriting the stored element. Any other type is reported instead of drawn as a bar chart. A chart without data
135
128
  points shows its `emptyLabel`.
136
129
 
130
+ ### Quill peer dependency
131
+
132
+ `quill` is not imported by the package root, so a host that renders no rich text needs neither `quill` nor its
133
+ stylesheet to build. A host that wants editable rich text installs `quill@^2.0.3` and opts in explicitly:
134
+
135
+ ```tsx
136
+ import 'quill/dist/quill.snow.css';
137
+ import { QuillLoaderProvider } from '@cratis/scene.primereact';
138
+ import { loadQuill } from '@cratis/scene.primereact/quill';
139
+
140
+ <QuillLoaderProvider loader={loadQuill}>{screen}</QuillLoaderProvider>
141
+ ```
142
+
143
+ `@cratis/scene.primereact/quill` (sources in `loadQuill/`) is the only module that names `quill`. Without a
144
+ loader the editor shows its content read-only and says so. Authored HTML always passes an allowlist first; see
145
+ the [component reference](../../../Documentation/primereact-package/component-reference.md#rich-text-and-quill).
146
+
137
147
  ## Browser specifications
138
148
 
139
149
  Most specifications run under jsdom with `yarn test`. Painted pixels, keyboard behavior and computed theme
@@ -162,9 +172,9 @@ The short version for a contributor:
162
172
  compiles cleanly and silently swaps an overlay for a static shell.
163
173
  - **v11 ships zero CSS.** There is no `primereact/resources` directory. A look comes from a preset handed
164
174
  to `PrimeReactProvider`; `usePrimeReactTheme` returns that configuration for a Scene theme.
165
- - **14 abstract names are now backed by Cratis-owned components** built here because v11 removed theirs,
166
- 2 are expressed over `@primereact/headless` hooks, and 4 were dropped from the manifest
167
- (`cascadeSelect`, `inputMask`, `treeTable`, `virtualScroller`).
175
+ - **16 abstract names are now backed by Cratis-owned components** built here because v11 removed theirs,
176
+ 2 are expressed over `@primereact/headless` hooks, and 3 were dropped from the manifest
177
+ (`cascadeSelect`, `inputMask`, `virtualScroller`).
168
178
  - **`MenuItem` and `TreeNode` are Scene's types now** - `primereact/menuitem` and `primereact/treenode`
169
179
  were removed. Import them from this package, never from `primereact/*`.
170
180
 
@@ -37,7 +37,13 @@ export const Gallery: Story = {
37
37
  ),
38
38
  sceneComponent('dataTable', 'dataTable', { rows: [{ id: 1, title: 'Inferred columns' }] }),
39
39
  sceneComponent('dataView', 'dataView', { rows: [{ title: 'Kickoff', description: 'Agree the scope' }] }),
40
+ sceneComponent('dataScroller', 'dataScroller', { items: ['First', 'Second', 'Third'], rows: 2, inline: true, scrollHeight: 96 }),
40
41
  sceneComponent('tree', 'tree', { nodes: [{ label: 'Documents', children: ['Work', 'Home'] }] }),
42
+ sceneComponent('treeTable', 'treeTable', {
43
+ columns: [{ field: 'name', header: 'Name' }, { field: 'type', header: 'Type' }],
44
+ items: [{ label: 'Documents', data: { name: 'Documents', type: 'Folder' }, children: [{ label: 'Plan', data: { name: 'Plan', type: 'File' } }] }],
45
+ selectionMode: 'checkbox', paginator: true, rows: 1,
46
+ }),
41
47
  sceneComponent('timeline', 'timeline', {
42
48
  events: [{ title: 'Ordered', description: 'Order placed', date: '09:00' }, { title: 'Shipped', description: 'Left the depot', date: '14:20' }],
43
49
  }),
@@ -0,0 +1,35 @@
1
+ // Copyright (c) Cratis. All rights reserved.
2
+ // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3
+
4
+ import { readableValue } from './readableValue';
5
+
6
+ /** The fields that, when present as text, name a record. */
7
+ const titleFields = ['label', 'title', 'name', 'text', 'header'];
8
+
9
+ /**
10
+ * One authored data row, shown readably.
11
+ *
12
+ * A scalar is its text. A record is titled by its first text field among `label`, `title`, `name`, `text` and
13
+ * `header`, and every other field follows as a name and a readable value. No row is ever dumped as JSON.
14
+ */
15
+ export function DataScrollerRow({ value }: { value: unknown }) {
16
+ if (typeof value !== 'object' || value === null || Array.isArray(value)) return <>{readableValue(value)}</>;
17
+
18
+ const record = value as Record<string, unknown>;
19
+ const titleField = titleFields.find(field => typeof record[field] === 'string' && record[field] !== '');
20
+ const details = Object.entries(record)
21
+ .filter(([name]) => name !== titleField)
22
+ .map(([name, entry]) => [name, readableValue(entry)] as const)
23
+ .filter(([, text]) => text !== '');
24
+
25
+ return (
26
+ <>
27
+ {titleField !== undefined && <strong>{record[titleField] as string}</strong>}
28
+ {details.length > 0 && (
29
+ <dl>
30
+ {details.map(([name, text]) => <div key={name}><dt>{name}</dt><dd>{text}</dd></div>)}
31
+ </dl>
32
+ )}
33
+ </>
34
+ );
35
+ }
@@ -0,0 +1,84 @@
1
+ // Copyright (c) Cratis. All rights reserved.
2
+ // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3
+
4
+ import { ReactNode, useEffect, useMemo, useRef } from 'react';
5
+ import { RegisteredComponentProps } from '@cratis/scene.react';
6
+ import { arrayProperty, booleanProperty, numberProperty, stringProperty } from '../properties';
7
+ import { useStructuralValue } from '../useStructuralValue';
8
+ import { DataScrollerRow } from './DataScrollerRow';
9
+ import { isSerializedLegacyElement, legacyElementMessage } from './isSerializedLegacyElement';
10
+ import { useIncrementalLoad } from './useIncrementalLoad';
11
+ import { useLoadOnReach } from './useLoadOnReach';
12
+
13
+ /** How tall an inline scroller is when no `scrollHeight` was authored: without a height it would never overflow. */
14
+ const defaultScrollHeight = 320;
15
+
16
+ /**
17
+ * The `PrimeReact:dataScroller` component, a list that loads a chunk at a time as its end is reached.
18
+ *
19
+ * The entries are read as data: strings, numbers and records (see {@link DataScrollerRow}) from `items`, then
20
+ * any child elements authored in the `items` (or `content`) slot, which render as themselves. Serialized
21
+ * legacy UI elements in `items` are refused with a visible message, not shown as JSON.
22
+ *
23
+ * - `inline: true` scrolls inside the control, `scrollHeight` pixels tall (320 when omitted). `inline: false`
24
+ * loads as the page scrolls the end of the list into view.
25
+ * - The "Load more" button remains for keyboard and assistive technology; focus moves to the first entry it
26
+ * loads, and the number shown is announced.
27
+ * - A disabled element loads nothing on scroll and its button is disabled.
28
+ * - The loaded count restarts when `rows` or the content of `items` changes.
29
+ */
30
+ export function PrimeDataScroller({ element, slots, interactions }: RegisteredComponentProps) {
31
+ const authored = useStructuralValue(arrayProperty(element, 'items'));
32
+ const data = useMemo(() => authored.filter(entry => !isSerializedLegacyElement(entry) && entry !== null && entry !== undefined), [authored]);
33
+ const refusal = legacyElementMessage(authored, 'items', "Author them as child elements in the 'items' slot, or as data.");
34
+ const slotted = slots.items ?? slots.content ?? [];
35
+ const rows = useMemo<ReactNode[]>(() => [...data.map((value, index) => <DataScrollerRow key={index} value={value} />), ...slotted], [data, slotted]);
36
+ const chunk = Math.max(Math.floor(numberProperty(element, 'rows', 10)), 1);
37
+ const inline = booleanProperty(element, 'inline', false);
38
+ const scrollHeight = numberProperty(element, 'scrollHeight', defaultScrollHeight);
39
+ const enabled = element.isEnabled;
40
+ const { loaded, loadMore } = useIncrementalLoad(rows.length, chunk, data);
41
+ const canLoad = loaded < rows.length;
42
+ const scroller = useRef<HTMLDivElement>(null);
43
+ const sentinel = useRef<HTMLDivElement>(null);
44
+ const entries = useRef<(HTMLLIElement | null)[]>([]);
45
+ const focusIndex = useRef<number | undefined>(undefined);
46
+
47
+ useLoadOnReach(sentinel, inline ? scroller : null, enabled && canLoad, loaded, loadMore);
48
+
49
+ useEffect(() => {
50
+ if (focusIndex.current === undefined) return;
51
+ entries.current[focusIndex.current]?.focus();
52
+ focusIndex.current = undefined;
53
+ }, [loaded]);
54
+
55
+ const loadByButton = () => {
56
+ focusIndex.current = loaded;
57
+ loadMore();
58
+ };
59
+
60
+ return (
61
+ <div
62
+ data-scene-id={element.id}
63
+ data-scene-component='dataScroller'
64
+ aria-disabled={!enabled}
65
+ onClick={interactions?.onClick}
66
+ onDoubleClick={interactions?.onDoubleClick}>
67
+ <div
68
+ ref={scroller}
69
+ role='region'
70
+ tabIndex={inline ? 0 : undefined}
71
+ aria-label={stringProperty(element, 'ariaLabel', 'Scrollable data')}
72
+ style={inline ? { maxHeight: `${scrollHeight}px`, overflowY: 'auto' } : undefined}>
73
+ <ol>
74
+ {rows.slice(0, loaded).map((row, index) => <li key={index} tabIndex={-1} ref={node => { entries.current[index] = node; }}>{row}</li>)}
75
+ </ol>
76
+ {canLoad && <div ref={sentinel} aria-hidden='true' />}
77
+ </div>
78
+ {rows.length === 0 && <p role='status'>{stringProperty(element, 'emptyLabel', 'No items to show')}</p>}
79
+ {refusal !== undefined && <p role='alert' data-scene-state='legacy-elements'>{refusal}</p>}
80
+ {canLoad && <button type='button' disabled={!enabled} onClick={loadByButton}>Load more</button>}
81
+ {rows.length > 0 && <output aria-live='polite'>{`Showing ${loaded} of ${rows.length} items`}</output>}
82
+ </div>
83
+ );
84
+ }
@@ -0,0 +1,145 @@
1
+ // Copyright (c) Cratis. All rights reserved.
2
+ // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3
+
4
+ import { useEffect, useMemo, useState } from 'react';
5
+ import { RegisteredComponentProps } from '@cratis/scene.react';
6
+ import { arrayProperty, booleanProperty, numberProperty, stringProperty } from '../properties';
7
+ import { resolveEnumeration } from '../resolveEnumeration';
8
+ import { countUnreadableEntries, toTreeNodes } from '../treeNodes';
9
+ import { useResettingState } from '../useResettingState';
10
+ import { useStructuralValue } from '../useStructuralValue';
11
+ import { ColumnDefinition } from './ColumnDefinition';
12
+ import { TreeTableRow } from './TreeTableRow';
13
+ import { TreeTableRowView } from './TreeTableRowView';
14
+ import { TreeTableSelectionMode } from './TreeTableSelectionMode';
15
+ import { columnDefinitions } from './columnDefinitions';
16
+ import { SettledSelection, settleSelection, toggleCheckbox } from './checkboxSelection';
17
+ import { isSerializedLegacyElement, legacyElementMessage } from './isSerializedLegacyElement';
18
+ import { selectionKeysOf } from './selectionKeysOf';
19
+ import { expandedKeysOf, visibleRows } from './treeTableRows';
20
+ import { useTreeGridNavigation } from './useTreeGridNavigation';
21
+
22
+ const labelColumn: ColumnDefinition[] = [{ field: 'label', header: 'Label', sortable: false }];
23
+
24
+ /**
25
+ * The `PrimeReact:treeTable` component, an ARIA tree grid over the canonical Scene node and column properties.
26
+ *
27
+ * `items` is an array of nodes - strings, numbers, or records with `key`, `label`, `data`, `children`,
28
+ * `expanded` and `selectable` - and the columns come from nested `column` elements, a `columns` property or the
29
+ * fields of the first row's `data`, in that order (see `columnDefinitions`). Serialized legacy UI elements in
30
+ * `items` or `columns` are refused with a visible message; see the package documentation for how they map to
31
+ * canonical slots.
32
+ *
33
+ * - Selection follows the authored `selection` (keys, numbers, `{ key }` objects or PrimeReact's key map) and
34
+ * starts over when it changes; expansion starts from the authored `expanded` flags the same way. An unrelated
35
+ * property edit leaves what the user did alone.
36
+ * - In checkbox mode a parent checks and unchecks its subtree and shows a partial state when only some of it is
37
+ * checked.
38
+ * - The rows form a `treegrid` with a roving tab index and the usual arrow-key navigation.
39
+ * - Object cell values are shown readably, never as `[object Object]`.
40
+ */
41
+ export function PrimeTreeTable({ element, interactions }: RegisteredComponentProps) {
42
+ const authoredItems = useStructuralValue(arrayProperty(element, 'items'));
43
+ const items = useMemo(() => authoredItems.filter(entry => !isSerializedLegacyElement(entry)), [authoredItems]);
44
+ const nodes = useMemo(() => toTreeNodes(items), [items]);
45
+ const modeResolution = resolveEnumeration('selectionMode', element.properties.selectionMode, TreeTableSelectionMode, TreeTableSelectionMode.None);
46
+ const mode = modeResolution.isValid ? modeResolution.value : TreeTableSelectionMode.None;
47
+ const enabled = element.isEnabled;
48
+ const pageSize = Math.max(Math.floor(numberProperty(element, 'rows', 10)), 1);
49
+ const paginator = booleanProperty(element, 'paginator', false);
50
+ const [expanded, setExpanded] = useResettingState(expandedKeysOf(nodes), () => new Set(expandedKeysOf(nodes)));
51
+ const [requested, setRequested] = useResettingState(element.properties.selection, () => selectionKeysOf(element.properties.selection));
52
+ const [page, setPage] = useState(0);
53
+ const pageCount = Math.max(Math.ceil(nodes.length / pageSize), 1);
54
+ const currentPage = Math.min(page, pageCount - 1);
55
+ const rows = useMemo(() => visibleRows(paginator ? nodes.slice(currentPage * pageSize, (currentPage + 1) * pageSize) : nodes, expanded), [nodes, paginator, currentPage, pageSize, expanded]);
56
+ const settled = useMemo<SettledSelection>(
57
+ () => mode === TreeTableSelectionMode.Checkbox ? settleSelection(nodes, requested) : { checked: requested, states: new Map() },
58
+ [mode, nodes, requested]
59
+ );
60
+ const columns = useMemo(() => {
61
+ const first = rows.find(row => typeof row.node.data === 'object' && row.node.data !== null && !Array.isArray(row.node.data))?.node.data as Record<string, unknown> | undefined;
62
+ const defined = columnDefinitions(element, first === undefined ? [] : [first]);
63
+ return defined.length > 0 ? defined : labelColumn;
64
+ }, [element, rows]);
65
+
66
+ useEffect(() => setPage(current => Math.min(current, pageCount - 1)), [pageCount]);
67
+
68
+ const toggle = (key: string) => {
69
+ if (enabled) setExpanded(current => {
70
+ const next = new Set(current);
71
+ if (next.has(key)) next.delete(key); else next.add(key);
72
+ return next;
73
+ });
74
+ };
75
+
76
+ const select = (row: TreeTableRow) => {
77
+ if (mode === TreeTableSelectionMode.None || !enabled || row.node.selectable === false) return;
78
+ if (mode === TreeTableSelectionMode.Checkbox) {
79
+ setRequested(toggleCheckbox(nodes, settled, row.node));
80
+ } else if (mode === TreeTableSelectionMode.Single) {
81
+ setRequested(new Set([row.key]));
82
+ } else {
83
+ const next = new Set(settled.checked);
84
+ if (next.has(row.key)) next.delete(row.key); else next.add(row.key);
85
+ setRequested(next);
86
+ }
87
+
88
+ interactions?.onSelect?.();
89
+ interactions?.onChange?.();
90
+ };
91
+
92
+ const navigation = useTreeGridNavigation({ rows, expanded, enabled, toggle, select });
93
+ const changePage = (target: number) => { if (enabled && target >= 0 && target < pageCount) setPage(target); };
94
+ const refusals = [
95
+ modeResolution.isValid ? undefined : modeResolution.message,
96
+ legacyElementMessage(authoredItems, 'items', 'Provide items as node data: strings, numbers, or records with key, label, data and children.'),
97
+ legacyElementMessage(arrayProperty(element, 'columns'), 'columns', "Author them as child elements in the 'columns' slot, or as column definitions."),
98
+ ].filter((message): message is string => message !== undefined);
99
+ const skipped = countUnreadableEntries(items);
100
+
101
+ return (
102
+ <div data-scene-id={element.id} data-scene-component='treeTable' aria-disabled={!enabled} onClick={interactions?.onClick} onDoubleClick={interactions?.onDoubleClick}>
103
+ <table
104
+ role='treegrid'
105
+ aria-label={stringProperty(element, 'ariaLabel', 'Hierarchical data')}
106
+ aria-multiselectable={mode === TreeTableSelectionMode.Multiple || mode === TreeTableSelectionMode.Checkbox ? true : undefined}>
107
+ <thead>
108
+ <tr role='row'>{columns.map((column, index) => <th key={index} role='columnheader'>{column.header}</th>)}</tr>
109
+ </thead>
110
+ <tbody>
111
+ {rows.map(row => (
112
+ <TreeTableRowView
113
+ key={row.key}
114
+ row={row}
115
+ columns={columns}
116
+ mode={mode}
117
+ enabled={enabled}
118
+ expanded={expanded.has(row.key)}
119
+ selected={settled.checked.has(row.key)}
120
+ checkState={settled.states.get(row.key)}
121
+ tabStop={navigation.tabStopKey === row.key}
122
+ register={navigation.register}
123
+ onActivate={() => navigation.activate(row.key)}
124
+ onToggle={() => toggle(row.key)}
125
+ onSelect={() => select(row)}
126
+ onKeyDown={event => navigation.onKeyDown(row, event)}
127
+ />
128
+ ))}
129
+ {rows.length === 0 && (
130
+ <tr role='row'><td role='gridcell' colSpan={columns.length}>{stringProperty(element, 'emptyLabel', 'No records found')}</td></tr>
131
+ )}
132
+ </tbody>
133
+ </table>
134
+ {paginator && (
135
+ <nav aria-label='Tree table pages'>
136
+ <button type='button' aria-disabled={!enabled || currentPage === 0} onClick={() => changePage(currentPage - 1)}>Previous</button>
137
+ <span>{currentPage + 1} / {pageCount}</span>
138
+ <button type='button' aria-disabled={!enabled || currentPage + 1 >= pageCount} onClick={() => changePage(currentPage + 1)}>Next</button>
139
+ </nav>
140
+ )}
141
+ {refusals.map(message => <p key={message} role='alert' data-scene-state='refused'>{message}</p>)}
142
+ {skipped > 0 && <p role='status'>{`${skipped} entr${skipped === 1 ? 'y' : 'ies'} of items could not be read as a node and ${skipped === 1 ? 'was' : 'were'} skipped.`}</p>}
143
+ </div>
144
+ );
145
+ }
@@ -0,0 +1,9 @@
1
+ // Copyright (c) Cratis. All rights reserved.
2
+ // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3
+
4
+ /** How much of a tree table row's subtree is checked, in checkbox selection mode. */
5
+ export enum TreeTableCheckState {
6
+ Unchecked = 'unchecked',
7
+ Partial = 'partial',
8
+ Checked = 'checked',
9
+ }
@@ -0,0 +1,22 @@
1
+ // Copyright (c) Cratis. All rights reserved.
2
+ // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3
+
4
+ import { TreeNode } from '../TreeNode';
5
+
6
+ /** One visible row of a tree table, with where it sits in the tree. */
7
+ export interface TreeTableRow {
8
+ node: TreeNode;
9
+ key: string;
10
+
11
+ /** Zero for a root row. */
12
+ depth: number;
13
+
14
+ /** The key of the parent row, `undefined` for a root row. */
15
+ parentKey: string | undefined;
16
+
17
+ /** The 1-based position among the siblings, for `aria-posinset`. */
18
+ position: number;
19
+
20
+ /** The number of siblings, for `aria-setsize`. */
21
+ siblings: number;
22
+ }
@@ -0,0 +1,86 @@
1
+ // Copyright (c) Cratis. All rights reserved.
2
+ // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3
+
4
+ import { ColumnDefinition } from './ColumnDefinition';
5
+ import { TreeTableCheckState } from './TreeTableCheckState';
6
+ import { TreeTableRow } from './TreeTableRow';
7
+ import { TreeTableSelectionMode } from './TreeTableSelectionMode';
8
+ import { nodeLabel } from './treeTableRows';
9
+ import { readableValue } from './readableValue';
10
+
11
+ export interface TreeTableRowViewProps {
12
+ row: TreeTableRow;
13
+ columns: ColumnDefinition[];
14
+ mode: TreeTableSelectionMode;
15
+ enabled: boolean;
16
+ expanded: boolean;
17
+ selected: boolean;
18
+ checkState: TreeTableCheckState | undefined;
19
+ tabStop: boolean;
20
+ register(key: string, element: HTMLElement | null): void;
21
+ onActivate(): void;
22
+ onToggle(): void;
23
+ onSelect(): void;
24
+ onKeyDown(event: React.KeyboardEvent<HTMLElement>): void;
25
+ }
26
+
27
+ /** One `row` of the tree grid: its cells, its expand button and, in checkbox mode, its tri-state checkbox. */
28
+ export function TreeTableRowView({ row, columns, mode, enabled, expanded, selected, checkState, tabStop, register, onActivate, onToggle, onSelect, onKeyDown }: TreeTableRowViewProps) {
29
+ const { node } = row;
30
+ const label = nodeLabel(node);
31
+ const hasChildren = (node.children?.length ?? 0) > 0;
32
+ const selectionOffered = mode !== TreeTableSelectionMode.None;
33
+ const rowSelectable = selectionOffered && node.selectable !== false;
34
+
35
+ return (
36
+ <tr
37
+ ref={element => register(row.key, element)}
38
+ role='row'
39
+ tabIndex={tabStop ? 0 : -1}
40
+ aria-level={row.depth + 1}
41
+ aria-posinset={row.position}
42
+ aria-setsize={row.siblings}
43
+ aria-expanded={hasChildren ? expanded : undefined}
44
+ aria-selected={selectionOffered ? selected : undefined}
45
+ className={node.className}
46
+ onFocus={onActivate}
47
+ onKeyDown={onKeyDown}
48
+ onClick={event => {
49
+ onActivate();
50
+ if (mode === TreeTableSelectionMode.Single || mode === TreeTableSelectionMode.Multiple) {
51
+ if (!(event.target as HTMLElement).closest('button, input')) onSelect();
52
+ }
53
+ }}>
54
+ {columns.map((column, index) => (
55
+ <td key={index} role='gridcell' style={index === 0 ? { paddingInlineStart: `${row.depth * 1.25}rem` } : undefined}>
56
+ {index === 0 && hasChildren && (
57
+ <button type='button' tabIndex={-1} disabled={!enabled} aria-expanded={expanded} aria-label={`${expanded ? 'Collapse' : 'Expand'} ${label}`} onClick={onToggle}>
58
+ {expanded ? 'Collapse' : 'Expand'}
59
+ </button>
60
+ )}
61
+ {index === 0 && mode === TreeTableSelectionMode.Checkbox && checkState !== undefined && (
62
+ <input
63
+ type='checkbox'
64
+ tabIndex={-1}
65
+ ref={input => { if (input !== null) input.indeterminate = checkState === TreeTableCheckState.Partial; }}
66
+ checked={checkState === TreeTableCheckState.Checked}
67
+ disabled={!enabled || !rowSelectable}
68
+ aria-label={`Select ${label}`}
69
+ aria-checked={checkState === TreeTableCheckState.Partial ? 'mixed' : checkState === TreeTableCheckState.Checked}
70
+ onChange={onSelect}
71
+ />
72
+ )}
73
+ {cellText(row, column.field, index === 0)}
74
+ </td>
75
+ ))}
76
+ </tr>
77
+ );
78
+ }
79
+
80
+ function cellText(row: TreeTableRow, field: string, firstColumn: boolean): string {
81
+ const { data } = row.node;
82
+ const record = typeof data === 'object' && data !== null && !Array.isArray(data) ? data as Record<string, unknown> : undefined;
83
+ if (record !== undefined && record[field] !== undefined) return readableValue(record[field]);
84
+ if (!firstColumn) return '';
85
+ return row.node.label ?? (record === undefined ? readableValue(data) : '');
86
+ }
@@ -0,0 +1,10 @@
1
+ // Copyright (c) Cratis. All rights reserved.
2
+ // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3
+
4
+ /** The canonical selection behavior for a hierarchical table. */
5
+ export enum TreeTableSelectionMode {
6
+ None = 'none',
7
+ Single = 'single',
8
+ Multiple = 'multiple',
9
+ Checkbox = 'checkbox',
10
+ }
@@ -0,0 +1,92 @@
1
+ // Copyright (c) Cratis. All rights reserved.
2
+ // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3
+
4
+ import { TreeNode } from '../TreeNode';
5
+ import { TreeTableCheckState } from './TreeTableCheckState';
6
+
7
+ /** The outcome of settling a checkbox selection: the keys that are checked, and how each row reads. */
8
+ export interface SettledSelection {
9
+ checked: Set<string>;
10
+ states: Map<string, TreeTableCheckState>;
11
+ }
12
+
13
+ const selectable = (node: TreeNode) => node.selectable !== false;
14
+
15
+ /**
16
+ * Settles a checkbox selection against the tree, the way a checkbox tree reads:
17
+ * - a checked parent has all of its selectable descendants checked;
18
+ * - a parent is checked when all of its selectable children are, partially checked when some are, and
19
+ * unchecked otherwise;
20
+ * - a node that is not selectable, and has nothing selectable below it, takes no part.
21
+ *
22
+ * Applying this to what the user toggled, or to an authored selection, is what keeps both consistent.
23
+ *
24
+ * @param nodes The root nodes.
25
+ * @param requested The keys asked for.
26
+ */
27
+ export function settleSelection(nodes: TreeNode[], requested: ReadonlySet<string>): SettledSelection {
28
+ const cascaded = new Set<string>();
29
+ const cascade = (node: TreeNode, inherited: boolean) => {
30
+ const on = inherited || requested.has(node.key ?? '');
31
+ if (on) cascaded.add(node.key ?? '');
32
+ node.children?.forEach(child => cascade(child, on));
33
+ };
34
+ nodes.forEach(node => cascade(node, false));
35
+
36
+ const checked = new Set<string>();
37
+ const states = new Map<string, TreeTableCheckState>();
38
+ const settle = (node: TreeNode): TreeTableCheckState | undefined => {
39
+ const key = node.key ?? '';
40
+ const childStates = (node.children ?? []).map(settle).filter((state): state is TreeTableCheckState => state !== undefined);
41
+ let state: TreeTableCheckState | undefined;
42
+ if (childStates.length === 0) {
43
+ state = selectable(node) ? (cascaded.has(key) ? TreeTableCheckState.Checked : TreeTableCheckState.Unchecked) : undefined;
44
+ } else if (childStates.every(child => child === TreeTableCheckState.Checked)) {
45
+ state = TreeTableCheckState.Checked;
46
+ } else {
47
+ state = childStates.some(child => child !== TreeTableCheckState.Unchecked) ? TreeTableCheckState.Partial : TreeTableCheckState.Unchecked;
48
+ }
49
+
50
+ if (state !== undefined) states.set(key, state);
51
+ if (state === TreeTableCheckState.Checked) checked.add(key);
52
+ return state;
53
+ };
54
+ nodes.forEach(settle);
55
+
56
+ return { checked, states };
57
+ }
58
+
59
+ /**
60
+ * Toggles one row's checkbox: a checked row unchecks its whole subtree, any other row checks it.
61
+ *
62
+ * @param nodes The root nodes.
63
+ * @param settled The current settled selection.
64
+ * @param node The row's node.
65
+ * @returns The keys to settle again.
66
+ */
67
+ export function toggleCheckbox(nodes: TreeNode[], settled: SettledSelection, node: TreeNode): Set<string> {
68
+ const subtree: string[] = [];
69
+ const collect = (current: TreeNode) => {
70
+ subtree.push(current.key ?? '');
71
+ current.children?.forEach(collect);
72
+ };
73
+ collect(node);
74
+
75
+ const next = new Set(settled.checked);
76
+ const checking = settled.states.get(node.key ?? '') !== TreeTableCheckState.Checked;
77
+ subtree.forEach(key => { if (checking) next.add(key); else next.delete(key); });
78
+
79
+ // A checked ancestor would check the unchecked subtree again, so unchecking also unchecks the ancestors.
80
+ if (!checking) (ancestorKeys(nodes, node.key ?? '') ?? []).forEach(key => next.delete(key));
81
+ return settleSelection(nodes, next).checked;
82
+ }
83
+
84
+ function ancestorKeys(nodes: TreeNode[], key: string, path: string[] = []): string[] | undefined {
85
+ for (const node of nodes) {
86
+ if (node.key === key) return path;
87
+ const found = ancestorKeys(node.children ?? [], key, [...path, node.key ?? '']);
88
+ if (found !== undefined) return found;
89
+ }
90
+
91
+ return undefined;
92
+ }
package/data/index.ts CHANGED
@@ -13,3 +13,7 @@ export * from './PrimePaginator';
13
13
  export * from './PrimeOrderList';
14
14
  export * from './PrimePickList';
15
15
  export * from './PrimeOrganizationChart';
16
+ export * from './PrimeDataScroller';
17
+ export * from './PrimeTreeTable';
18
+ export * from './TreeTableSelectionMode';
19
+ export * from './readableValue';
@@ -0,0 +1,30 @@
1
+ // Copyright (c) Cratis. All rights reserved.
2
+ // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3
+
4
+ /**
5
+ * Whether an entry is a serialized legacy UI element - an object that names its type in `_derivedTypeId`.
6
+ *
7
+ * The original `ItemsControl.Items` and `TreeTable.Columns` held UI elements, not data. Scene does not
8
+ * read those shapes and has no runtime adapter for them: the controls recognize them only to refuse them
9
+ * visibly, instead of listing the element's fields as if they were rows. Converting them is the migration
10
+ * tool's job, which maps each element to a canonical slot (see the package documentation).
11
+ *
12
+ * @param entry An entry of `items` or `columns`.
13
+ */
14
+ export function isSerializedLegacyElement(entry: unknown): boolean {
15
+ return typeof entry === 'object' && entry !== null && !Array.isArray(entry) && typeof (entry as { _derivedTypeId?: unknown })._derivedTypeId === 'string';
16
+ }
17
+
18
+ /**
19
+ * The message for entries that were refused, or `undefined` when there were none.
20
+ *
21
+ * @param entries The authored entries.
22
+ * @param property The property they came from.
23
+ * @param guidance What the author should do instead, finishing the sentence "Author them ..." or similar.
24
+ */
25
+ export function legacyElementMessage(entries: unknown[], property: string, guidance: string): string | undefined {
26
+ const refused = entries.filter(isSerializedLegacyElement).length;
27
+ return refused === 0
28
+ ? undefined
29
+ : `${refused} entr${refused === 1 ? 'y' : 'ies'} of ${property} ${refused === 1 ? 'is a' : 'are'} serialized legacy UI element${refused === 1 ? '' : 's'}, which this control does not read. ${guidance}`;
30
+ }