@stackcraftmx/calcita 0.32.2 → 0.47.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 (336) hide show
  1. package/README.md +263 -2
  2. package/cli/packageVersions.js +12 -3
  3. package/cli/projectFiles.js +5 -2
  4. package/cli/templates/module/__Name__Page.test.jsx.tpl +24 -0
  5. package/cli/templates/project/README.md.tpl +14 -1
  6. package/cli/templates/project/src/app/appRouter.jsx.tpl +5 -2
  7. package/cli/templates/project/src/core/accountConnector.js.tpl +4 -2
  8. package/cli/templates/project/src/modules/auth/SignInPage.test.jsx.tpl +20 -0
  9. package/cli/templates/project/src/modules/home/HomePage.test.jsx.tpl +16 -0
  10. package/cli/templates/project/src/testing/browserGaps.js.tpl +70 -0
  11. package/cli/templates/project/src/testing/openScreen.jsx.tpl +58 -0
  12. package/cli/templates/project/src/testing/setup.js.tpl +25 -0
  13. package/cli/templates/project/vite.config.js.tpl +12 -0
  14. package/dist/DataTable/GoToPage.js +69 -13
  15. package/dist/DataTable/GoToPage.js.map +1 -1
  16. package/dist/DataTable/ServerTable.js +2 -0
  17. package/dist/DataTable/ServerTable.js.map +1 -1
  18. package/dist/DataTable/ServerTableFilterDrawer.js +52 -0
  19. package/dist/DataTable/ServerTableFilterDrawer.js.map +1 -0
  20. package/dist/DataTable/filterContext.js.map +1 -1
  21. package/dist/DataTable/goToPageOptions.js +17 -0
  22. package/dist/DataTable/goToPageOptions.js.map +1 -0
  23. package/dist/date-pickers.js +28 -2
  24. package/dist/date-pickers.js.map +1 -1
  25. package/dist/datePickers/DateInput.js +15 -34
  26. package/dist/datePickers/DateInput.js.map +1 -1
  27. package/dist/datePickers/DateTimeInput.js +75 -0
  28. package/dist/datePickers/DateTimeInput.js.map +1 -0
  29. package/dist/datePickers/FormDateTimeField.js +12 -0
  30. package/dist/datePickers/FormDateTimeField.js.map +1 -0
  31. package/dist/datePickers/FormMonthField.js +12 -0
  32. package/dist/datePickers/FormMonthField.js.map +1 -0
  33. package/dist/datePickers/FormTimeField.js +12 -0
  34. package/dist/datePickers/FormTimeField.js.map +1 -0
  35. package/dist/datePickers/MonthInput.js +58 -0
  36. package/dist/datePickers/MonthInput.js.map +1 -0
  37. package/dist/datePickers/PickerFrame.js +27 -0
  38. package/dist/datePickers/PickerFrame.js.map +1 -0
  39. package/dist/datePickers/TimeInput.js +55 -0
  40. package/dist/datePickers/TimeInput.js.map +1 -0
  41. package/dist/datePickers/dateTimeRules.js +24 -0
  42. package/dist/datePickers/dateTimeRules.js.map +1 -0
  43. package/dist/datePickers/pickerValues.js +106 -0
  44. package/dist/datePickers/pickerValues.js.map +1 -0
  45. package/dist/datePickers/useCurrentMinute.js +28 -0
  46. package/dist/datePickers/useCurrentMinute.js.map +1 -0
  47. package/dist/datePickers/usePickerField.js +22 -0
  48. package/dist/datePickers/usePickerField.js.map +1 -0
  49. package/dist/dictionaries/dictionaries.js +3 -1
  50. package/dist/dictionaries/dictionaries.js.map +1 -1
  51. package/dist/forms/FormAttachmentsField.js +12 -0
  52. package/dist/forms/FormAttachmentsField.js.map +1 -0
  53. package/dist/forms/FormCheckboxGroupField.js +12 -0
  54. package/dist/forms/FormCheckboxGroupField.js.map +1 -0
  55. package/dist/forms/FormFileField.js +12 -0
  56. package/dist/forms/FormFileField.js.map +1 -0
  57. package/dist/forms/FormFileUploadField.js +12 -0
  58. package/dist/forms/FormFileUploadField.js.map +1 -0
  59. package/dist/forms/FormImageField.js +12 -0
  60. package/dist/forms/FormImageField.js.map +1 -0
  61. package/dist/forms/FormMaskedField.js +12 -0
  62. package/dist/forms/FormMaskedField.js.map +1 -0
  63. package/dist/forms/FormRepeatingFields.js +54 -0
  64. package/dist/forms/FormRepeatingFields.js.map +1 -0
  65. package/dist/forms/FormTransferListField.js +12 -0
  66. package/dist/forms/FormTransferListField.js.map +1 -0
  67. package/dist/forms/applyServerProblem.js +10 -3
  68. package/dist/forms/applyServerProblem.js.map +1 -1
  69. package/dist/forms/listRules.js +111 -0
  70. package/dist/forms/listRules.js.map +1 -0
  71. package/dist/forms/serverProblemFields.js +17 -0
  72. package/dist/forms/serverProblemFields.js.map +1 -1
  73. package/dist/forms.js +51 -29
  74. package/dist/forms.js.map +1 -1
  75. package/dist/hookForm/FormAttachmentsField.js +12 -0
  76. package/dist/hookForm/FormAttachmentsField.js.map +1 -0
  77. package/dist/hookForm/FormCheckboxGroupField.js +12 -0
  78. package/dist/hookForm/FormCheckboxGroupField.js.map +1 -0
  79. package/dist/hookForm/FormFileField.js +12 -0
  80. package/dist/hookForm/FormFileField.js.map +1 -0
  81. package/dist/hookForm/FormFileUploadField.js +12 -0
  82. package/dist/hookForm/FormFileUploadField.js.map +1 -0
  83. package/dist/hookForm/FormImageField.js +12 -0
  84. package/dist/hookForm/FormImageField.js.map +1 -0
  85. package/dist/hookForm/FormMaskedField.js +12 -0
  86. package/dist/hookForm/FormMaskedField.js.map +1 -0
  87. package/dist/hookForm/FormRepeatingFields.js +44 -0
  88. package/dist/hookForm/FormRepeatingFields.js.map +1 -0
  89. package/dist/hookForm/FormTransferListField.js +12 -0
  90. package/dist/hookForm/FormTransferListField.js.map +1 -0
  91. package/dist/hookForm/applyServerProblem.js +8 -3
  92. package/dist/hookForm/applyServerProblem.js.map +1 -1
  93. package/dist/index.js +188 -100
  94. package/dist/index.js.map +1 -1
  95. package/dist/inputs/CatalogInput.js +74 -7
  96. package/dist/inputs/CatalogInput.js.map +1 -1
  97. package/dist/inputs/CheckboxGroupInput.js +100 -0
  98. package/dist/inputs/CheckboxGroupInput.js.map +1 -0
  99. package/dist/inputs/MaskedInput.js +86 -0
  100. package/dist/inputs/MaskedInput.js.map +1 -0
  101. package/dist/inputs/NumberInput.js +12 -1
  102. package/dist/inputs/NumberInput.js.map +1 -1
  103. package/dist/inputs/RepeatingFields.js +177 -0
  104. package/dist/inputs/RepeatingFields.js.map +1 -0
  105. package/dist/inputs/SelectInput.js +43 -5
  106. package/dist/inputs/SelectInput.js.map +1 -1
  107. package/dist/inputs/TransferListInput.js +215 -0
  108. package/dist/inputs/TransferListInput.js.map +1 -0
  109. package/dist/inputs/inputMasks.js +84 -0
  110. package/dist/inputs/inputMasks.js.map +1 -0
  111. package/dist/inputs/selectAllState.js +20 -0
  112. package/dist/inputs/selectAllState.js.map +1 -0
  113. package/dist/inputs/useRowKeys.js +26 -0
  114. package/dist/inputs/useRowKeys.js.map +1 -0
  115. package/dist/legal/CookieNotice.js +79 -0
  116. package/dist/legal/CookieNotice.js.map +1 -0
  117. package/dist/legal/TermsAcceptanceDialog.js +129 -0
  118. package/dist/legal/TermsAcceptanceDialog.js.map +1 -0
  119. package/dist/legal/consentStorage.js +18 -0
  120. package/dist/legal/consentStorage.js.map +1 -0
  121. package/dist/legal/useCookieConsent.js +17 -0
  122. package/dist/legal/useCookieConsent.js.map +1 -0
  123. package/dist/locales/en.js +233 -1
  124. package/dist/locales/en.js.map +1 -1
  125. package/dist/locales/es.js +233 -1
  126. package/dist/locales/es.js.map +1 -1
  127. package/dist/mexico/CfdiSummary.js +81 -0
  128. package/dist/mexico/CfdiSummary.js.map +1 -0
  129. package/dist/mexico/EfirmaFields.js +167 -0
  130. package/dist/mexico/EfirmaFields.js.map +1 -0
  131. package/dist/mexico/certificateReader.js +79 -0
  132. package/dist/mexico/certificateReader.js.map +1 -0
  133. package/dist/mexico/cfdiReader.js +81 -0
  134. package/dist/mexico/cfdiReader.js.map +1 -0
  135. package/dist/mexico/derReader.js +81 -0
  136. package/dist/mexico/derReader.js.map +1 -0
  137. package/dist/mexico/efirmaKey.js +51 -0
  138. package/dist/mexico/efirmaKey.js.map +1 -0
  139. package/dist/mexico/mexicoIdentifiers.js +86 -0
  140. package/dist/mexico/mexicoIdentifiers.js.map +1 -0
  141. package/dist/mexico/mexicoRules.js +16 -0
  142. package/dist/mexico/mexicoRules.js.map +1 -0
  143. package/dist/mexico.js +32 -0
  144. package/dist/mexico.js.map +1 -0
  145. package/dist/react-hook-form.js +40 -17
  146. package/dist/react-hook-form.js.map +1 -1
  147. package/dist/rich-text.js +19 -0
  148. package/dist/rich-text.js.map +1 -0
  149. package/dist/richText/FormRichTextField.js +12 -0
  150. package/dist/richText/FormRichTextField.js.map +1 -0
  151. package/dist/richText/RichTextEditor.js +108 -0
  152. package/dist/richText/RichTextEditor.js.map +1 -0
  153. package/dist/richText/RichTextLinkPopover.js +57 -0
  154. package/dist/richText/RichTextLinkPopover.js.map +1 -0
  155. package/dist/richText/RichTextToolbar.js +189 -0
  156. package/dist/richText/RichTextToolbar.js.map +1 -0
  157. package/dist/richText/RichTextView.js +26 -0
  158. package/dist/richText/RichTextView.js.map +1 -0
  159. package/dist/richText/richTextContentSx.js +42 -0
  160. package/dist/richText/richTextContentSx.js.map +1 -0
  161. package/dist/richText/richTextExtensions.js +44 -0
  162. package/dist/richText/richTextExtensions.js.map +1 -0
  163. package/dist/richText/richTextRules.js +46 -0
  164. package/dist/richText/richTextRules.js.map +1 -0
  165. package/dist/table.js +2 -0
  166. package/dist/table.js.map +1 -1
  167. package/dist/theme/components/glassComponents.js +27 -0
  168. package/dist/theme/components/glassComponents.js.map +1 -1
  169. package/dist/theme/components/minimalComponents.js +12 -0
  170. package/dist/theme/components/minimalComponents.js.map +1 -1
  171. package/dist/types/DataTable/ServerTableFilterDrawer.d.ts +21 -0
  172. package/dist/types/DataTable/filterContext.d.ts +2 -1
  173. package/dist/types/DataTable/goToPageOptions.d.ts +15 -0
  174. package/dist/types/DataTable/index.d.ts +1 -0
  175. package/dist/types/date-pickers.d.ts +10 -1
  176. package/dist/types/datePickers/DateInput.d.ts +6 -4
  177. package/dist/types/datePickers/DateTimeInput.d.ts +50 -0
  178. package/dist/types/datePickers/FormDateTimeField.d.ts +7 -0
  179. package/dist/types/datePickers/FormMonthField.d.ts +7 -0
  180. package/dist/types/datePickers/FormTimeField.d.ts +7 -0
  181. package/dist/types/datePickers/MonthInput.d.ts +39 -0
  182. package/dist/types/datePickers/PickerFrame.d.ts +22 -0
  183. package/dist/types/datePickers/TimeInput.d.ts +38 -0
  184. package/dist/types/datePickers/dateTimeRules.d.ts +31 -0
  185. package/dist/types/datePickers/pickerValues.d.ts +114 -0
  186. package/dist/types/datePickers/useCurrentMinute.d.ts +5 -0
  187. package/dist/types/datePickers/usePickerField.d.ts +24 -0
  188. package/dist/types/dictionaries/dictionaries.d.ts +6 -3
  189. package/dist/types/forms/FormAttachmentsField.d.ts +7 -0
  190. package/dist/types/forms/FormCheckboxGroupField.d.ts +7 -0
  191. package/dist/types/forms/FormFileField.d.ts +7 -0
  192. package/dist/types/forms/FormFileUploadField.d.ts +7 -0
  193. package/dist/types/forms/FormImageField.d.ts +7 -0
  194. package/dist/types/forms/FormMaskedField.d.ts +7 -0
  195. package/dist/types/forms/FormRepeatingFields.d.ts +25 -0
  196. package/dist/types/forms/FormTransferListField.d.ts +7 -0
  197. package/dist/types/forms/index.d.ts +10 -1
  198. package/dist/types/forms/listRules.d.ts +48 -0
  199. package/dist/types/forms/serverProblemFields.d.ts +13 -0
  200. package/dist/types/forms.d.ts +1 -1
  201. package/dist/types/hookForm/FormAttachmentsField.d.ts +8 -0
  202. package/dist/types/hookForm/FormCheckboxGroupField.d.ts +8 -0
  203. package/dist/types/hookForm/FormFileField.d.ts +8 -0
  204. package/dist/types/hookForm/FormFileUploadField.d.ts +8 -0
  205. package/dist/types/hookForm/FormImageField.d.ts +8 -0
  206. package/dist/types/hookForm/FormMaskedField.d.ts +9 -0
  207. package/dist/types/hookForm/FormRepeatingFields.d.ts +27 -0
  208. package/dist/types/hookForm/FormTransferListField.d.ts +8 -0
  209. package/dist/types/index.d.ts +25 -3
  210. package/dist/types/inputs/CatalogInput.d.ts +7 -1
  211. package/dist/types/inputs/CheckboxGroupInput.d.ts +39 -0
  212. package/dist/types/inputs/MaskedInput.d.ts +35 -0
  213. package/dist/types/inputs/RepeatingFields.d.ts +52 -0
  214. package/dist/types/inputs/SelectInput.d.ts +6 -1
  215. package/dist/types/inputs/TransferListInput.d.ts +43 -0
  216. package/dist/types/inputs/inputMasks.d.ts +52 -0
  217. package/dist/types/inputs/selectAllState.d.ts +11 -0
  218. package/dist/types/inputs/useRowKeys.d.ts +11 -0
  219. package/dist/types/legal/CookieNotice.d.ts +30 -0
  220. package/dist/types/legal/TermsAcceptanceDialog.d.ts +32 -0
  221. package/dist/types/legal/consentStorage.d.ts +16 -0
  222. package/dist/types/legal/useCookieConsent.d.ts +13 -0
  223. package/dist/types/locales/en.d.ts +232 -0
  224. package/dist/types/locales/es.d.ts +232 -0
  225. package/dist/types/mexico/CfdiSummary.d.ts +17 -0
  226. package/dist/types/mexico/EfirmaFields.d.ts +38 -0
  227. package/dist/types/mexico/certificateReader.d.ts +37 -0
  228. package/dist/types/mexico/cfdiReader.d.ts +95 -0
  229. package/dist/types/mexico/derReader.d.ts +54 -0
  230. package/dist/types/mexico/efirmaKey.d.ts +26 -0
  231. package/dist/types/mexico/mexicoIdentifiers.d.ts +61 -0
  232. package/dist/types/mexico/mexicoRules.d.ts +29 -0
  233. package/dist/types/mexico.d.ts +11 -0
  234. package/dist/types/react-hook-form.d.ts +10 -1
  235. package/dist/types/rich-text.d.ts +5 -0
  236. package/dist/types/richText/FormRichTextField.d.ts +7 -0
  237. package/dist/types/richText/RichTextEditor.d.ts +42 -0
  238. package/dist/types/richText/RichTextLinkPopover.d.ts +17 -0
  239. package/dist/types/richText/RichTextToolbar.d.ts +15 -0
  240. package/dist/types/richText/RichTextView.d.ts +13 -0
  241. package/dist/types/richText/richTextContentSx.d.ts +7 -0
  242. package/dist/types/richText/richTextExtensions.d.ts +15 -0
  243. package/dist/types/richText/richTextRules.d.ts +41 -0
  244. package/dist/types/table.d.ts +1 -1
  245. package/dist/types/ui/actions/ActionsMenu.d.ts +18 -3
  246. package/dist/types/ui/actions/CopyButton.d.ts +7 -4
  247. package/dist/types/ui/actions/tableRowText.d.ts +6 -0
  248. package/dist/types/ui/cards/RecordCard.d.ts +65 -0
  249. package/dist/types/ui/cards/RecordCardSkeleton.d.ts +17 -0
  250. package/dist/types/ui/countdown/Countdown.d.ts +31 -0
  251. package/dist/types/ui/countdown/countdownParts.d.ts +39 -0
  252. package/dist/types/ui/countdown/useCountdown.d.ts +14 -0
  253. package/dist/types/ui/documents/PdfViewerDialog.d.ts +21 -0
  254. package/dist/types/ui/filters/FilterDrawer.d.ts +34 -0
  255. package/dist/types/ui/filters/filterDrawerFields.d.ts +139 -0
  256. package/dist/types/ui/help/HelpButton.d.ts +15 -0
  257. package/dist/types/ui/help/HelpCarouselDialog.d.ts +35 -0
  258. package/dist/types/ui/help/useHelpCarousel.d.ts +21 -0
  259. package/dist/types/ui/index.d.ts +10 -0
  260. package/dist/types/ui/labels/IconBadge.d.ts +34 -0
  261. package/dist/types/ui/navigation/RouteTabs.d.ts +44 -0
  262. package/dist/types/ui/navigation/routeTabMatching.d.ts +27 -0
  263. package/dist/types/upload/AttachmentsInput.d.ts +62 -0
  264. package/dist/types/upload/FileChip.d.ts +18 -0
  265. package/dist/types/upload/FileDropzone.d.ts +3 -0
  266. package/dist/types/upload/FileInput.d.ts +48 -0
  267. package/dist/types/upload/FileUploadInput.d.ts +80 -0
  268. package/dist/types/upload/ImageInput.d.ts +53 -0
  269. package/dist/types/upload/TemplateDownloadButton.d.ts +39 -0
  270. package/dist/types/upload/fileAppearance.d.ts +8 -0
  271. package/dist/types/upload/fileRules.d.ts +38 -0
  272. package/dist/types/upload/transferProgress.d.ts +18 -0
  273. package/dist/types/upload/uploadMachine.d.ts +6 -2
  274. package/dist/types/upload/uploadWithProgress.d.ts +6 -2
  275. package/dist/types/upload/useFilePicker.d.ts +39 -0
  276. package/dist/ui/actions/ActionsMenu.js +98 -15
  277. package/dist/ui/actions/ActionsMenu.js.map +1 -1
  278. package/dist/ui/actions/CopyButton.js +31 -11
  279. package/dist/ui/actions/CopyButton.js.map +1 -1
  280. package/dist/ui/actions/tableRowText.js +7 -0
  281. package/dist/ui/actions/tableRowText.js.map +1 -0
  282. package/dist/ui/cards/RecordCard.js +145 -0
  283. package/dist/ui/cards/RecordCard.js.map +1 -0
  284. package/dist/ui/cards/RecordCardSkeleton.js +33 -0
  285. package/dist/ui/cards/RecordCardSkeleton.js.map +1 -0
  286. package/dist/ui/countdown/Countdown.js +38 -0
  287. package/dist/ui/countdown/Countdown.js.map +1 -0
  288. package/dist/ui/countdown/countdownParts.js +34 -0
  289. package/dist/ui/countdown/countdownParts.js.map +1 -0
  290. package/dist/ui/countdown/useCountdown.js +35 -0
  291. package/dist/ui/countdown/useCountdown.js.map +1 -0
  292. package/dist/ui/documents/PdfViewerDialog.js +81 -0
  293. package/dist/ui/documents/PdfViewerDialog.js.map +1 -0
  294. package/dist/ui/filters/FilterDrawer.js +211 -0
  295. package/dist/ui/filters/FilterDrawer.js.map +1 -0
  296. package/dist/ui/filters/filterDrawerFields.js +119 -0
  297. package/dist/ui/filters/filterDrawerFields.js.map +1 -0
  298. package/dist/ui/help/HelpButton.js +17 -0
  299. package/dist/ui/help/HelpButton.js.map +1 -0
  300. package/dist/ui/help/HelpCarouselDialog.js +154 -0
  301. package/dist/ui/help/HelpCarouselDialog.js.map +1 -0
  302. package/dist/ui/help/useHelpCarousel.js +25 -0
  303. package/dist/ui/help/useHelpCarousel.js.map +1 -0
  304. package/dist/ui/labels/IconBadge.js +82 -0
  305. package/dist/ui/labels/IconBadge.js.map +1 -0
  306. package/dist/ui/navigation/RouteTabs.js +75 -0
  307. package/dist/ui/navigation/RouteTabs.js.map +1 -0
  308. package/dist/ui/navigation/routeTabMatching.js +23 -0
  309. package/dist/ui/navigation/routeTabMatching.js.map +1 -0
  310. package/dist/upload/AttachmentsInput.js +127 -0
  311. package/dist/upload/AttachmentsInput.js.map +1 -0
  312. package/dist/upload/FileChip.js +27 -0
  313. package/dist/upload/FileChip.js.map +1 -0
  314. package/dist/upload/FileDropzone.js +19 -84
  315. package/dist/upload/FileDropzone.js.map +1 -1
  316. package/dist/upload/FileInput.js +112 -0
  317. package/dist/upload/FileInput.js.map +1 -0
  318. package/dist/upload/FileUploadInput.js +285 -0
  319. package/dist/upload/FileUploadInput.js.map +1 -0
  320. package/dist/upload/ImageInput.js +125 -0
  321. package/dist/upload/ImageInput.js.map +1 -0
  322. package/dist/upload/TemplateDownloadButton.js +67 -0
  323. package/dist/upload/TemplateDownloadButton.js.map +1 -0
  324. package/dist/upload/fileAppearance.js +21 -0
  325. package/dist/upload/fileAppearance.js.map +1 -0
  326. package/dist/upload/fileRules.js +27 -1
  327. package/dist/upload/fileRules.js.map +1 -1
  328. package/dist/upload/transferProgress.js +23 -0
  329. package/dist/upload/transferProgress.js.map +1 -0
  330. package/dist/upload/uploadMachine.js +8 -8
  331. package/dist/upload/uploadMachine.js.map +1 -1
  332. package/dist/upload/uploadWithProgress.js +1 -1
  333. package/dist/upload/uploadWithProgress.js.map +1 -1
  334. package/dist/upload/useFilePicker.js +101 -0
  335. package/dist/upload/useFilePicker.js.map +1 -0
  336. package/package.json +44 -1
@@ -0,0 +1,189 @@
1
+ "use client";
2
+ import { jsxs, Fragment, jsx } from "react/jsx-runtime";
3
+ import { useState, useRef } from "react";
4
+ import { useEditorState } from "@tiptap/react";
5
+ import Divider from "@mui/material/Divider";
6
+ import IconButton from "@mui/material/IconButton";
7
+ import MenuItem from "@mui/material/MenuItem";
8
+ import Select from "@mui/material/Select";
9
+ import Tooltip from "@mui/material/Tooltip";
10
+ import CodeIcon from "@mui/icons-material/Code";
11
+ import FormatAlignCenterIcon from "@mui/icons-material/FormatAlignCenter";
12
+ import FormatAlignLeftIcon from "@mui/icons-material/FormatAlignLeft";
13
+ import FormatAlignRightIcon from "@mui/icons-material/FormatAlignRight";
14
+ import FormatBoldIcon from "@mui/icons-material/FormatBold";
15
+ import FormatClearIcon from "@mui/icons-material/FormatClear";
16
+ import FormatItalicIcon from "@mui/icons-material/FormatItalic";
17
+ import FormatListBulletedIcon from "@mui/icons-material/FormatListBulleted";
18
+ import FormatListNumberedIcon from "@mui/icons-material/FormatListNumbered";
19
+ import FormatQuoteIcon from "@mui/icons-material/FormatQuote";
20
+ import FormatStrikethroughIcon from "@mui/icons-material/FormatStrikethrough";
21
+ import FormatUnderlinedIcon from "@mui/icons-material/FormatUnderlined";
22
+ import InsertLinkIcon from "@mui/icons-material/InsertLink";
23
+ import RedoIcon from "@mui/icons-material/Redo";
24
+ import UndoIcon from "@mui/icons-material/Undo";
25
+ import { RICH_TEXT_HEADING_LEVELS } from "./richTextExtensions.js";
26
+ import RichTextLinkPopover from "./RichTextLinkPopover.js";
27
+ import { RICH_TEXT_FEATURE } from "./richTextRules.js";
28
+ const PARAGRAPH_STYLE = "paragraph";
29
+ const headingStyleOf = (level) => `heading${level}`;
30
+ const TEXT_ALIGNMENTS = Object.freeze([
31
+ { value: "left", Icon: FormatAlignLeftIcon },
32
+ { value: "center", Icon: FormatAlignCenterIcon },
33
+ { value: "right", Icon: FormatAlignRightIcon }
34
+ ]);
35
+ const MARK_BUTTONS = Object.freeze([
36
+ { feature: RICH_TEXT_FEATURE.bold, mark: "bold", Icon: FormatBoldIcon, toggle: (chain) => chain.toggleBold() },
37
+ { feature: RICH_TEXT_FEATURE.italic, mark: "italic", Icon: FormatItalicIcon, toggle: (chain) => chain.toggleItalic() },
38
+ { feature: RICH_TEXT_FEATURE.underline, mark: "underline", Icon: FormatUnderlinedIcon, toggle: (chain) => chain.toggleUnderline() },
39
+ { feature: RICH_TEXT_FEATURE.strike, mark: "strike", Icon: FormatStrikethroughIcon, toggle: (chain) => chain.toggleStrike() }
40
+ ]);
41
+ const BLOCK_BUTTONS = Object.freeze([
42
+ { feature: RICH_TEXT_FEATURE.bulletList, node: "bulletList", Icon: FormatListBulletedIcon, toggle: (chain) => chain.toggleBulletList() },
43
+ { feature: RICH_TEXT_FEATURE.orderedList, node: "orderedList", Icon: FormatListNumberedIcon, toggle: (chain) => chain.toggleOrderedList() },
44
+ { feature: RICH_TEXT_FEATURE.blockquote, node: "blockquote", Icon: FormatQuoteIcon, toggle: (chain) => chain.toggleBlockquote() },
45
+ { feature: RICH_TEXT_FEATURE.codeBlock, node: "codeBlock", Icon: CodeIcon, toggle: (chain) => chain.toggleCodeBlock() }
46
+ ]);
47
+ function ToolbarButton({ label, isActive, disabled, onClick, children }) {
48
+ return /* @__PURE__ */ jsx(Tooltip, { title: label, children: /* @__PURE__ */ jsx("span", { children: /* @__PURE__ */ jsx(
49
+ IconButton,
50
+ {
51
+ size: "small",
52
+ "aria-label": label,
53
+ "aria-pressed": isActive ?? void 0,
54
+ disabled,
55
+ color: isActive ? "primary" : "default",
56
+ onMouseDown: (event) => event.preventDefault(),
57
+ onClick,
58
+ sx: isActive ? { bgcolor: "action.selected" } : void 0,
59
+ children
60
+ }
61
+ ) }) });
62
+ }
63
+ function RichTextToolbar({ editor, features, disabled, t, actions }) {
64
+ const [linkAnchor, setLinkAnchor] = useState(null);
65
+ const linkButtonRef = useRef(null);
66
+ const has = (feature) => features.includes(feature);
67
+ const state = useEditorState({
68
+ editor,
69
+ selector: ({ editor: current }) => {
70
+ if (!current) {
71
+ return null;
72
+ }
73
+ const headingLevel = RICH_TEXT_HEADING_LEVELS.find((level) => current.isActive("heading", { level }));
74
+ return {
75
+ marks: Object.fromEntries(MARK_BUTTONS.filter(({ feature }) => has(feature)).map(({ mark }) => [mark, current.isActive(mark)])),
76
+ blocks: Object.fromEntries(BLOCK_BUTTONS.filter(({ feature }) => has(feature)).map(({ node }) => [node, current.isActive(node)])),
77
+ textStyle: headingLevel ? headingStyleOf(headingLevel) : PARAGRAPH_STYLE,
78
+ alignment: TEXT_ALIGNMENTS.find(({ value }) => current.isActive({ textAlign: value }))?.value ?? TEXT_ALIGNMENTS[0].value,
79
+ isLink: has(RICH_TEXT_FEATURE.link) && current.isActive("link"),
80
+ linkHref: has(RICH_TEXT_FEATURE.link) ? current.getAttributes("link").href ?? "" : "",
81
+ canUndo: has(RICH_TEXT_FEATURE.history) && current.can().undo(),
82
+ canRedo: has(RICH_TEXT_FEATURE.history) && current.can().redo()
83
+ };
84
+ }
85
+ });
86
+ if (!editor || !state) {
87
+ return null;
88
+ }
89
+ const chain = () => editor.chain().focus();
90
+ const isDisabled = disabled || !editor.isEditable;
91
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
92
+ has(RICH_TEXT_FEATURE.textStyle) && /* @__PURE__ */ jsxs(
93
+ Select,
94
+ {
95
+ size: "small",
96
+ variant: "standard",
97
+ disableUnderline: true,
98
+ value: state.textStyle,
99
+ disabled: isDisabled,
100
+ inputProps: { "aria-label": t("toolbar.textStyle") },
101
+ sx: { minWidth: 110, mx: 0.5, fontSize: 14 },
102
+ onChange: (event) => {
103
+ const style = event.target.value;
104
+ const level = RICH_TEXT_HEADING_LEVELS.find((candidate) => headingStyleOf(candidate) === style);
105
+ (level ? chain().setHeading({ level }) : chain().setParagraph()).run();
106
+ },
107
+ children: [
108
+ /* @__PURE__ */ jsx(MenuItem, { value: PARAGRAPH_STYLE, children: t("toolbar.paragraph") }),
109
+ RICH_TEXT_HEADING_LEVELS.map((level) => /* @__PURE__ */ jsx(MenuItem, { value: headingStyleOf(level), children: t(`toolbar.${headingStyleOf(level)}`) }, level))
110
+ ]
111
+ }
112
+ ),
113
+ MARK_BUTTONS.filter(({ feature }) => has(feature)).map(({ feature, mark, Icon, toggle }) => /* @__PURE__ */ jsx(
114
+ ToolbarButton,
115
+ {
116
+ label: t(`toolbar.${feature}`),
117
+ isActive: state.marks[mark],
118
+ disabled: isDisabled,
119
+ onClick: () => toggle(chain()).run(),
120
+ children: /* @__PURE__ */ jsx(Icon, { fontSize: "small" })
121
+ },
122
+ feature
123
+ )),
124
+ /* @__PURE__ */ jsx(Divider, { orientation: "vertical", flexItem: true, sx: { mx: 0.5 } }),
125
+ BLOCK_BUTTONS.filter(({ feature }) => has(feature)).map(({ feature, node, Icon, toggle }) => /* @__PURE__ */ jsx(
126
+ ToolbarButton,
127
+ {
128
+ label: t(`toolbar.${feature}`),
129
+ isActive: state.blocks[node],
130
+ disabled: isDisabled,
131
+ onClick: () => toggle(chain()).run(),
132
+ children: /* @__PURE__ */ jsx(Icon, { fontSize: "small" })
133
+ },
134
+ feature
135
+ )),
136
+ has(RICH_TEXT_FEATURE.link) && /* @__PURE__ */ jsx("span", { ref: linkButtonRef, children: /* @__PURE__ */ jsx(
137
+ ToolbarButton,
138
+ {
139
+ label: t("toolbar.link"),
140
+ isActive: state.isLink,
141
+ disabled: isDisabled,
142
+ onClick: () => setLinkAnchor(linkButtonRef.current),
143
+ children: /* @__PURE__ */ jsx(InsertLinkIcon, { fontSize: "small" })
144
+ }
145
+ ) }),
146
+ has(RICH_TEXT_FEATURE.align) && /* @__PURE__ */ jsxs(Fragment, { children: [
147
+ /* @__PURE__ */ jsx(Divider, { orientation: "vertical", flexItem: true, sx: { mx: 0.5 } }),
148
+ TEXT_ALIGNMENTS.map(({ value, Icon }) => /* @__PURE__ */ jsx(
149
+ ToolbarButton,
150
+ {
151
+ label: t(`toolbar.align.${value}`),
152
+ isActive: state.alignment === value,
153
+ disabled: isDisabled,
154
+ onClick: () => chain().setTextAlign(value).run(),
155
+ children: /* @__PURE__ */ jsx(Icon, { fontSize: "small" })
156
+ },
157
+ value
158
+ ))
159
+ ] }),
160
+ has(RICH_TEXT_FEATURE.clear) && /* @__PURE__ */ jsx(ToolbarButton, { label: t("toolbar.clear"), disabled: isDisabled, onClick: () => chain().unsetAllMarks().clearNodes().run(), children: /* @__PURE__ */ jsx(FormatClearIcon, { fontSize: "small" }) }),
161
+ has(RICH_TEXT_FEATURE.history) && /* @__PURE__ */ jsxs(Fragment, { children: [
162
+ /* @__PURE__ */ jsx(Divider, { orientation: "vertical", flexItem: true, sx: { mx: 0.5 } }),
163
+ /* @__PURE__ */ jsx(ToolbarButton, { label: t("toolbar.undo"), disabled: isDisabled || !state.canUndo, onClick: () => chain().undo().run(), children: /* @__PURE__ */ jsx(UndoIcon, { fontSize: "small" }) }),
164
+ /* @__PURE__ */ jsx(ToolbarButton, { label: t("toolbar.redo"), disabled: isDisabled || !state.canRedo, onClick: () => chain().redo().run(), children: /* @__PURE__ */ jsx(RedoIcon, { fontSize: "small" }) })
165
+ ] }),
166
+ actions,
167
+ linkAnchor && /* @__PURE__ */ jsx(
168
+ RichTextLinkPopover,
169
+ {
170
+ anchorElement: linkAnchor,
171
+ initialUrl: state.linkHref,
172
+ t,
173
+ onClose: () => setLinkAnchor(null),
174
+ onSave: (url) => {
175
+ chain().extendMarkRange("link").setLink({ href: url }).run();
176
+ setLinkAnchor(null);
177
+ },
178
+ onRemove: () => {
179
+ chain().extendMarkRange("link").unsetLink().run();
180
+ setLinkAnchor(null);
181
+ }
182
+ }
183
+ )
184
+ ] });
185
+ }
186
+ export {
187
+ RichTextToolbar as default
188
+ };
189
+ //# sourceMappingURL=RichTextToolbar.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RichTextToolbar.js","sources":["../../src/richText/RichTextToolbar.jsx"],"sourcesContent":["// La barra del editor de texto: estilo (texto, título, subtítulo), negrita, cursiva, subrayado y tachado, listas, cita,\n// código, liga, alineación, quitar el formato y deshacer o rehacer. Solo trae los botones que se piden (features) y cada uno\n// dice si está puesto (aria-pressed) y su nombre al pasar el cursor.\n//\n// OJO: los botones no se llevan el foco al picarlos (onMouseDown sin acción): si se lo llevaran, el texto elegido se\n// perdería antes de darle formato.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {useRef, useState} from 'react';\nimport {useEditorState} from '@tiptap/react';\nimport Divider from '@mui/material/Divider';\nimport IconButton from '@mui/material/IconButton';\nimport MenuItem from '@mui/material/MenuItem';\nimport Select from '@mui/material/Select';\nimport Tooltip from '@mui/material/Tooltip';\nimport CodeIcon from '@mui/icons-material/Code';\nimport FormatAlignCenterIcon from '@mui/icons-material/FormatAlignCenter';\nimport FormatAlignLeftIcon from '@mui/icons-material/FormatAlignLeft';\nimport FormatAlignRightIcon from '@mui/icons-material/FormatAlignRight';\nimport FormatBoldIcon from '@mui/icons-material/FormatBold';\nimport FormatClearIcon from '@mui/icons-material/FormatClear';\nimport FormatItalicIcon from '@mui/icons-material/FormatItalic';\nimport FormatListBulletedIcon from '@mui/icons-material/FormatListBulleted';\nimport FormatListNumberedIcon from '@mui/icons-material/FormatListNumbered';\nimport FormatQuoteIcon from '@mui/icons-material/FormatQuote';\nimport FormatStrikethroughIcon from '@mui/icons-material/FormatStrikethrough';\nimport FormatUnderlinedIcon from '@mui/icons-material/FormatUnderlined';\nimport InsertLinkIcon from '@mui/icons-material/InsertLink';\nimport RedoIcon from '@mui/icons-material/Redo';\nimport UndoIcon from '@mui/icons-material/Undo';\n\nimport {RICH_TEXT_HEADING_LEVELS} from '@/richText/richTextExtensions.js';\nimport RichTextLinkPopover from '@/richText/RichTextLinkPopover.jsx';\nimport {RICH_TEXT_FEATURE} from '@/richText/richTextRules.js';\n\n// el estilo del renglón: texto normal o uno de los títulos\nconst PARAGRAPH_STYLE = 'paragraph';\nconst headingStyleOf = (level) => `heading${level}`;\nconst TEXT_ALIGNMENTS = Object.freeze([\n {value: 'left', Icon: FormatAlignLeftIcon},\n {value: 'center', Icon: FormatAlignCenterIcon},\n {value: 'right', Icon: FormatAlignRightIcon},\n]);\n// las marcas que se ponen y se quitan con un botón\nconst MARK_BUTTONS = Object.freeze([\n {feature: RICH_TEXT_FEATURE.bold, mark: 'bold', Icon: FormatBoldIcon, toggle: (chain) => chain.toggleBold()},\n {feature: RICH_TEXT_FEATURE.italic, mark: 'italic', Icon: FormatItalicIcon, toggle: (chain) => chain.toggleItalic()},\n {feature: RICH_TEXT_FEATURE.underline, mark: 'underline', Icon: FormatUnderlinedIcon, toggle: (chain) => chain.toggleUnderline()},\n {feature: RICH_TEXT_FEATURE.strike, mark: 'strike', Icon: FormatStrikethroughIcon, toggle: (chain) => chain.toggleStrike()},\n]);\n// los bloques que se ponen y se quitan con un botón\nconst BLOCK_BUTTONS = Object.freeze([\n {feature: RICH_TEXT_FEATURE.bulletList, node: 'bulletList', Icon: FormatListBulletedIcon, toggle: (chain) => chain.toggleBulletList()},\n {feature: RICH_TEXT_FEATURE.orderedList, node: 'orderedList', Icon: FormatListNumberedIcon, toggle: (chain) => chain.toggleOrderedList()},\n {feature: RICH_TEXT_FEATURE.blockquote, node: 'blockquote', Icon: FormatQuoteIcon, toggle: (chain) => chain.toggleBlockquote()},\n {feature: RICH_TEXT_FEATURE.codeBlock, node: 'codeBlock', Icon: CodeIcon, toggle: (chain) => chain.toggleCodeBlock()},\n]);\n\n/**\n * Un botón de la barra: no se lleva el foco, dice si está puesto y su nombre.\n *\n * @param {{label: string, isActive?: boolean, disabled?: boolean, onClick: (event: object) => void, children: import('react').ReactNode}} props\n */\nfunction ToolbarButton({label, isActive, disabled, onClick, children}) {\n return (\n <Tooltip title={label}>\n <span>\n <IconButton size=\"small\" aria-label={label} aria-pressed={isActive ?? undefined} disabled={disabled} color={isActive ? 'primary' : 'default'}\n onMouseDown={(event) => event.preventDefault()} onClick={onClick}\n sx={isActive ? {bgcolor: 'action.selected'} : undefined}>\n {children}\n </IconButton>\n </span>\n </Tooltip>\n );\n}\n\n/**\n * @param {object} props\n * @param {import('@tiptap/react').Editor|null} props.editor\n * @param {string[]} props.features\n * @param {boolean} props.disabled\n * @param {(key: string, values?: object) => string} props.t el traductor del editor (namespace richText)\n * @param {import('react').ReactNode} [props.actions] botones del proyecto al final de la barra\n */\nexport default function RichTextToolbar({editor, features, disabled, t, actions}) {\n const [linkAnchor, setLinkAnchor] = useState(null);\n const linkButtonRef = useRef(null);\n const has = (feature) => features.includes(feature);\n // lo que está puesto donde está el cursor: la barra se pinta otra vez solo cuando eso cambia\n const state = useEditorState({\n editor,\n selector: ({editor: current}) => {\n if (!current) {\n return null;\n }\n const headingLevel = RICH_TEXT_HEADING_LEVELS.find((level) => current.isActive('heading', {level}));\n return {\n marks: Object.fromEntries(MARK_BUTTONS.filter(({feature}) => has(feature)).map(({mark}) => [mark, current.isActive(mark)])),\n blocks: Object.fromEntries(BLOCK_BUTTONS.filter(({feature}) => has(feature)).map(({node}) => [node, current.isActive(node)])),\n textStyle: headingLevel ? headingStyleOf(headingLevel) : PARAGRAPH_STYLE,\n alignment: TEXT_ALIGNMENTS.find(({value}) => current.isActive({textAlign: value}))?.value ?? TEXT_ALIGNMENTS[0].value,\n isLink: has(RICH_TEXT_FEATURE.link) && current.isActive('link'),\n linkHref: has(RICH_TEXT_FEATURE.link) ? current.getAttributes('link').href ?? '' : '',\n canUndo: has(RICH_TEXT_FEATURE.history) && current.can().undo(),\n canRedo: has(RICH_TEXT_FEATURE.history) && current.can().redo(),\n };\n },\n });\n\n if (!editor || !state) {\n return null;\n }\n const chain = () => editor.chain().focus();\n const isDisabled = disabled || !editor.isEditable;\n\n return (\n <>\n {has(RICH_TEXT_FEATURE.textStyle) && (\n <Select size=\"small\" variant=\"standard\" disableUnderline value={state.textStyle} disabled={isDisabled}\n inputProps={{'aria-label': t('toolbar.textStyle')}} sx={{minWidth: 110, mx: 0.5, fontSize: 14}}\n onChange={(event) => {\n const style = event.target.value;\n const level = RICH_TEXT_HEADING_LEVELS.find((candidate) => headingStyleOf(candidate) === style);\n (level ? chain().setHeading({level}) : chain().setParagraph()).run();\n }}>\n <MenuItem value={PARAGRAPH_STYLE}>{t('toolbar.paragraph')}</MenuItem>\n {RICH_TEXT_HEADING_LEVELS.map((level) => (\n <MenuItem key={level} value={headingStyleOf(level)}>{t(`toolbar.${headingStyleOf(level)}`)}</MenuItem>\n ))}\n </Select>\n )}\n {MARK_BUTTONS.filter(({feature}) => has(feature)).map(({feature, mark, Icon, toggle}) => (\n <ToolbarButton key={feature} label={t(`toolbar.${feature}`)} isActive={state.marks[mark]} disabled={isDisabled}\n onClick={() => toggle(chain()).run()}>\n <Icon fontSize=\"small\" />\n </ToolbarButton>\n ))}\n <Divider orientation=\"vertical\" flexItem sx={{mx: 0.5}} />\n {BLOCK_BUTTONS.filter(({feature}) => has(feature)).map(({feature, node, Icon, toggle}) => (\n <ToolbarButton key={feature} label={t(`toolbar.${feature}`)} isActive={state.blocks[node]} disabled={isDisabled}\n onClick={() => toggle(chain()).run()}>\n <Icon fontSize=\"small\" />\n </ToolbarButton>\n ))}\n {has(RICH_TEXT_FEATURE.link) && (\n <span ref={linkButtonRef}>\n <ToolbarButton label={t('toolbar.link')} isActive={state.isLink} disabled={isDisabled}\n onClick={() => setLinkAnchor(linkButtonRef.current)}>\n <InsertLinkIcon fontSize=\"small\" />\n </ToolbarButton>\n </span>\n )}\n {has(RICH_TEXT_FEATURE.align) && (\n <>\n <Divider orientation=\"vertical\" flexItem sx={{mx: 0.5}} />\n {TEXT_ALIGNMENTS.map(({value, Icon}) => (\n <ToolbarButton key={value} label={t(`toolbar.align.${value}`)} isActive={state.alignment === value} disabled={isDisabled}\n onClick={() => chain().setTextAlign(value).run()}>\n <Icon fontSize=\"small\" />\n </ToolbarButton>\n ))}\n </>\n )}\n {has(RICH_TEXT_FEATURE.clear) && (\n <ToolbarButton label={t('toolbar.clear')} disabled={isDisabled} onClick={() => chain().unsetAllMarks().clearNodes().run()}>\n <FormatClearIcon fontSize=\"small\" />\n </ToolbarButton>\n )}\n {has(RICH_TEXT_FEATURE.history) && (\n <>\n <Divider orientation=\"vertical\" flexItem sx={{mx: 0.5}} />\n <ToolbarButton label={t('toolbar.undo')} disabled={isDisabled || !state.canUndo} onClick={() => chain().undo().run()}>\n <UndoIcon fontSize=\"small\" />\n </ToolbarButton>\n <ToolbarButton label={t('toolbar.redo')} disabled={isDisabled || !state.canRedo} onClick={() => chain().redo().run()}>\n <RedoIcon fontSize=\"small\" />\n </ToolbarButton>\n </>\n )}\n {actions}\n {linkAnchor && (\n <RichTextLinkPopover anchorElement={linkAnchor} initialUrl={state.linkHref} t={t}\n onClose={() => setLinkAnchor(null)}\n onSave={(url) => {\n chain().extendMarkRange('link').setLink({href: url}).run();\n setLinkAnchor(null);\n }}\n onRemove={() => {\n chain().extendMarkRange('link').unsetLink().run();\n setLinkAnchor(null);\n }} />\n )}\n </>\n );\n}\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ "use client";
2
+ import { jsx } from "react/jsx-runtime";
3
+ import { useEditor, EditorContent } from "@tiptap/react";
4
+ import Box from "@mui/material/Box";
5
+ import { richTextContentSxOf } from "./richTextContentSx.js";
6
+ import { richTextExtensionsOf } from "./richTextExtensions.js";
7
+ import { DEFAULT_RICH_TEXT_FEATURES } from "./richTextRules.js";
8
+ import { piecePart, usePieceProps } from "../theme/themePieces.js";
9
+ import { warnUnknownProps } from "../toolkit/unknownProps.js";
10
+ const THEME_NAME = "CalcitaRichTextView";
11
+ const ViewRoot = piecePart(THEME_NAME, "Root", Box);
12
+ function RichTextView(props) {
13
+ const { value, features = DEFAULT_RICH_TEXT_FEATURES, extensions, sx, ...unknownProps } = usePieceProps(props, THEME_NAME);
14
+ warnUnknownProps(THEME_NAME, unknownProps);
15
+ const editor = useEditor({
16
+ extensions: richTextExtensionsOf({ features, extensions }),
17
+ content: value ?? "",
18
+ editable: false,
19
+ immediatelyRender: false
20
+ }, [value, features.join(",")]);
21
+ return /* @__PURE__ */ jsx(ViewRoot, { ownSx: richTextContentSxOf, sx, children: /* @__PURE__ */ jsx(EditorContent, { editor }) });
22
+ }
23
+ export {
24
+ RichTextView as default
25
+ };
26
+ //# sourceMappingURL=RichTextView.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RichTextView.js","sources":["../../src/richText/RichTextView.jsx"],"sourcesContent":["// Enseña el texto con formato que guardó RichTextEditor, sin poder editarlo. Pasa por el mismo esquema del editor: solo entra\n// lo que el editor entiende (párrafos, títulos, listas, ligas seguras…) y lo demás se queda afuera. Un <script>, un\n// onclick o una liga javascript: pegados en el HTML no llegan a la página (XSS), sin otra librería para limpiarlo.\n//\n// Se cambia desde el tema del proyecto, como las piezas de MUI: components.CalcitaRichTextView con defaultProps y\n// styleOverrides de su parte root.\n//\n// Genérico del paquete: function (regla de la casa).\nimport {EditorContent, useEditor} from '@tiptap/react';\nimport Box from '@mui/material/Box';\n\nimport {richTextContentSxOf} from '@/richText/richTextContentSx.js';\nimport {richTextExtensionsOf} from '@/richText/richTextExtensions.js';\nimport {DEFAULT_RICH_TEXT_FEATURES} from '@/richText/richTextRules.js';\nimport {piecePart, usePieceProps} from '@/theme/themePieces.js';\nimport {warnUnknownProps} from '@/toolkit/unknownProps.js';\n\n// el nombre de la pieza en el tema y su parte (theme.components.CalcitaRichTextView)\nconst THEME_NAME = 'CalcitaRichTextView';\nconst ViewRoot = piecePart(THEME_NAME, 'Root', Box);\n\n/**\n * @param {object} props\n * @param {string|null|undefined} props.value el HTML guardado\n * @param {string[]} [props.features] lo que se deja pasar (por omisión, lo de un editor completo)\n * @param {Array<object>} [props.extensions] las extensiones de Tiptap del proyecto (las mismas que tiene su editor)\n * @param {object} [props.sx]\n */\nexport default function RichTextView(props) {\n const {value, features = DEFAULT_RICH_TEXT_FEATURES, extensions, sx, ...unknownProps} = usePieceProps(props, THEME_NAME);\n warnUnknownProps(THEME_NAME, unknownProps);\n const editor = useEditor({\n extensions: richTextExtensionsOf({features, extensions}),\n content: value ?? '',\n editable: false,\n immediatelyRender: false,\n }, [value, features.join(',')]);\n\n return (\n <ViewRoot ownSx={richTextContentSxOf} sx={sx}>\n <EditorContent editor={editor} />\n </ViewRoot>\n );\n}\n"],"names":[],"mappings":";;;;;;;;;AAkBA,MAAM,aAAa;AACnB,MAAM,WAAW,UAAU,YAAY,QAAQ,GAAG;AASlD,SAAwB,aAAa,OAAO;AACxC,QAAM,EAAC,OAAO,WAAW,4BAA4B,YAAY,IAAI,GAAG,aAAA,IAAgB,cAAc,OAAO,UAAU;AACvH,mBAAiB,YAAY,YAAY;AACzC,QAAM,SAAS,UAAU;AAAA,IACrB,YAAY,qBAAqB,EAAC,UAAU,YAAW;AAAA,IACvD,SAAS,SAAS;AAAA,IAClB,UAAU;AAAA,IACV,mBAAmB;AAAA,EAAA,GACpB,CAAC,OAAO,SAAS,KAAK,GAAG,CAAC,CAAC;AAE9B,SACI,oBAAC,YAAS,OAAO,qBAAqB,IAClC,UAAA,oBAAC,eAAA,EAAc,QAAgB,EAAA,CACnC;AAER;"}
@@ -0,0 +1,42 @@
1
+ function richTextContentSxOf(theme) {
2
+ const palette = (theme.vars ?? theme).palette;
3
+ return {
4
+ "& .tiptap": {
5
+ outline: "none",
6
+ ...theme.typography.body1,
7
+ "& > :first-of-type": { mt: 0 },
8
+ "& > :last-child": { mb: 0 },
9
+ "& p": { my: 1 },
10
+ "& h2": { ...theme.typography.h6, mt: 2, mb: 1 },
11
+ "& h3": { ...theme.typography.subtitle1, fontWeight: 600, mt: 1.5, mb: 0.5 },
12
+ "& ul, & ol": { pl: 3, my: 1 },
13
+ "& li > p": { my: 0.25 },
14
+ "& blockquote": { borderLeft: 3, borderColor: "divider", pl: 2, ml: 0, my: 1.5, color: "text.secondary" },
15
+ "& pre": {
16
+ bgcolor: "action.hover",
17
+ borderRadius: 1,
18
+ px: 2,
19
+ py: 1.5,
20
+ my: 1.5,
21
+ overflowX: "auto",
22
+ fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace",
23
+ fontSize: "0.875em"
24
+ },
25
+ "& code": { fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace", fontSize: "0.9em", bgcolor: "action.hover", borderRadius: 0.5, px: 0.5 },
26
+ "& pre code": { bgcolor: "transparent", p: 0 },
27
+ "& a": { color: palette.primary.main, textDecorationThickness: 1 },
28
+ // el texto de ejemplo con el editor vacío (Placeholder de Tiptap)
29
+ "& p.is-editor-empty:first-of-type::before": {
30
+ content: "attr(data-placeholder)",
31
+ color: "text.disabled",
32
+ float: "left",
33
+ height: 0,
34
+ pointerEvents: "none"
35
+ }
36
+ }
37
+ };
38
+ }
39
+ export {
40
+ richTextContentSxOf
41
+ };
42
+ //# sourceMappingURL=richTextContentSx.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"richTextContentSx.js","sources":["../../src/richText/richTextContentSx.js"],"sourcesContent":["// Cómo se ve el texto con formato, dentro del editor y en la vista de solo lectura: párrafos, títulos, listas, cita, código y\n// ligas con los colores y la tipografía del tema. Uno solo para los dos: lo que se escribe se ve igual a como se guarda.\n//\n// Genérico del paquete: function (regla de la casa).\n\n/**\n * El sx del contenido (.tiptap es la caja que edita Tiptap; en la vista es la misma, sin editar).\n *\n * @param {object} theme\n * @returns {object}\n */\nexport function richTextContentSxOf(theme) {\n const palette = (theme.vars ?? theme).palette;\n return {\n '& .tiptap': {\n outline: 'none',\n ...theme.typography.body1,\n '& > :first-of-type': {mt: 0},\n '& > :last-child': {mb: 0},\n '& p': {my: 1},\n '& h2': {...theme.typography.h6, mt: 2, mb: 1},\n '& h3': {...theme.typography.subtitle1, fontWeight: 600, mt: 1.5, mb: 0.5},\n '& ul, & ol': {pl: 3, my: 1},\n '& li > p': {my: 0.25},\n '& blockquote': {borderLeft: 3, borderColor: 'divider', pl: 2, ml: 0, my: 1.5, color: 'text.secondary'},\n '& pre': {\n bgcolor: 'action.hover', borderRadius: 1, px: 2, py: 1.5, my: 1.5, overflowX: 'auto',\n fontFamily: 'ui-monospace, SFMono-Regular, Menlo, monospace', fontSize: '0.875em',\n },\n '& code': {fontFamily: 'ui-monospace, SFMono-Regular, Menlo, monospace', fontSize: '0.9em', bgcolor: 'action.hover', borderRadius: 0.5, px: 0.5},\n '& pre code': {bgcolor: 'transparent', p: 0},\n '& a': {color: palette.primary.main, textDecorationThickness: 1},\n // el texto de ejemplo con el editor vacío (Placeholder de Tiptap)\n '& p.is-editor-empty:first-of-type::before': {\n content: 'attr(data-placeholder)', color: 'text.disabled', float: 'left', height: 0, pointerEvents: 'none',\n },\n },\n };\n}\n"],"names":[],"mappings":"AAWO,SAAS,oBAAoB,OAAO;AACvC,QAAM,WAAW,MAAM,QAAQ,OAAO;AACtC,SAAO;AAAA,IACH,aAAa;AAAA,MACT,SAAS;AAAA,MACT,GAAG,MAAM,WAAW;AAAA,MACpB,sBAAsB,EAAC,IAAI,EAAC;AAAA,MAC5B,mBAAmB,EAAC,IAAI,EAAC;AAAA,MACzB,OAAO,EAAC,IAAI,EAAC;AAAA,MACb,QAAQ,EAAC,GAAG,MAAM,WAAW,IAAI,IAAI,GAAG,IAAI,EAAC;AAAA,MAC7C,QAAQ,EAAC,GAAG,MAAM,WAAW,WAAW,YAAY,KAAK,IAAI,KAAK,IAAI,IAAG;AAAA,MACzE,cAAc,EAAC,IAAI,GAAG,IAAI,EAAC;AAAA,MAC3B,YAAY,EAAC,IAAI,KAAI;AAAA,MACrB,gBAAgB,EAAC,YAAY,GAAG,aAAa,WAAW,IAAI,GAAG,IAAI,GAAG,IAAI,KAAK,OAAO,iBAAgB;AAAA,MACtG,SAAS;AAAA,QACL,SAAS;AAAA,QAAgB,cAAc;AAAA,QAAG,IAAI;AAAA,QAAG,IAAI;AAAA,QAAK,IAAI;AAAA,QAAK,WAAW;AAAA,QAC9E,YAAY;AAAA,QAAkD,UAAU;AAAA,MACxF;AAAA,MACY,UAAU,EAAC,YAAY,kDAAkD,UAAU,SAAS,SAAS,gBAAgB,cAAc,KAAK,IAAI,IAAG;AAAA,MAC/I,cAAc,EAAC,SAAS,eAAe,GAAG,EAAC;AAAA,MAC3C,OAAO,EAAC,OAAO,QAAQ,QAAQ,MAAM,yBAAyB,EAAC;AAAA;AAAA,MAE/D,6CAA6C;AAAA,QACzC,SAAS;AAAA,QAA0B,OAAO;AAAA,QAAiB,OAAO;AAAA,QAAQ,QAAQ;AAAA,QAAG,eAAe;AAAA,MACpH;AAAA,IACA;AAAA,EACA;AACA;"}
@@ -0,0 +1,44 @@
1
+ import TextAlign from "@tiptap/extension-text-align";
2
+ import { Placeholder, CharacterCount } from "@tiptap/extensions";
3
+ import StarterKit from "@tiptap/starter-kit";
4
+ import { RICH_TEXT_FEATURE, isSafeLinkUrl } from "./richTextRules.js";
5
+ const RICH_TEXT_HEADING_LEVELS = Object.freeze([2, 3]);
6
+ const ALIGNABLE_NODES = Object.freeze(["heading", "paragraph"]);
7
+ function richTextExtensionsOf({ features, placeholder, maxLength, extensions = [] }) {
8
+ const has = (feature) => features.includes(feature);
9
+ const onlyIf = (feature, options = {}) => has(feature) ? options : false;
10
+ return [
11
+ StarterKit.configure({
12
+ heading: onlyIf(RICH_TEXT_FEATURE.textStyle, { levels: [...RICH_TEXT_HEADING_LEVELS] }),
13
+ bold: onlyIf(RICH_TEXT_FEATURE.bold),
14
+ italic: onlyIf(RICH_TEXT_FEATURE.italic),
15
+ underline: onlyIf(RICH_TEXT_FEATURE.underline),
16
+ strike: onlyIf(RICH_TEXT_FEATURE.strike),
17
+ bulletList: onlyIf(RICH_TEXT_FEATURE.bulletList),
18
+ orderedList: onlyIf(RICH_TEXT_FEATURE.orderedList),
19
+ // sin listas tampoco hay renglones de lista
20
+ listItem: has(RICH_TEXT_FEATURE.bulletList) || has(RICH_TEXT_FEATURE.orderedList) ? {} : false,
21
+ blockquote: onlyIf(RICH_TEXT_FEATURE.blockquote),
22
+ codeBlock: onlyIf(RICH_TEXT_FEATURE.codeBlock),
23
+ // el código dentro de un renglón lo pide solo el bloque de código
24
+ code: onlyIf(RICH_TEXT_FEATURE.codeBlock),
25
+ undoRedo: onlyIf(RICH_TEXT_FEATURE.history),
26
+ link: onlyIf(RICH_TEXT_FEATURE.link, {
27
+ openOnClick: false,
28
+ autolink: true,
29
+ defaultProtocol: "https",
30
+ isAllowedUri: (url) => isSafeLinkUrl(url),
31
+ HTMLAttributes: { rel: "noopener noreferrer nofollow", target: "_blank" }
32
+ })
33
+ }),
34
+ ...has(RICH_TEXT_FEATURE.align) ? [TextAlign.configure({ types: [...ALIGNABLE_NODES] })] : [],
35
+ ...placeholder ? [Placeholder.configure({ placeholder })] : [],
36
+ CharacterCount.configure({ limit: maxLength ?? null }),
37
+ ...extensions
38
+ ];
39
+ }
40
+ export {
41
+ RICH_TEXT_HEADING_LEVELS,
42
+ richTextExtensionsOf
43
+ };
44
+ //# sourceMappingURL=richTextExtensions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"richTextExtensions.js","sources":["../../src/richText/richTextExtensions.js"],"sourcesContent":["// Las extensiones de Tiptap del editor de la casa, armadas según los botones que se piden (features). Lo que no se pide se\n// quita también del documento: si la barra no trae código, un bloque de código pegado llega como texto normal.\n//\n// Las ligas solo con protocolos seguros (richTextRules.js) y con rel=\"noopener noreferrer nofollow\": la página que se abre no\n// puede tocar la de la app ni sumar puntos de búsqueda.\n//\n// Genérico del paquete: function (regla de la casa).\nimport TextAlign from '@tiptap/extension-text-align';\nimport {CharacterCount, Placeholder} from '@tiptap/extensions';\nimport StarterKit from '@tiptap/starter-kit';\n\nimport {RICH_TEXT_FEATURE, isSafeLinkUrl} from '@/richText/richTextRules.js';\n\n// los títulos que ofrece la barra: el de la página ya es h1, el texto va de h2 para abajo\nexport const RICH_TEXT_HEADING_LEVELS = Object.freeze([2, 3]);\nconst ALIGNABLE_NODES = Object.freeze(['heading', 'paragraph']);\n\n/**\n * @param {object} options\n * @param {string[]} options.features los botones de la barra (RICH_TEXT_FEATURE)\n * @param {string} [options.placeholder] ya traducido: lo que se ve con el editor vacío\n * @param {number} [options.maxLength] el tope de caracteres; sin él, sin tope\n * @param {Array<object>} [options.extensions] extensiones de Tiptap del proyecto, al final\n * @returns {Array<object>}\n */\nexport function richTextExtensionsOf({features, placeholder, maxLength, extensions = []}) {\n const has = (feature) => features.includes(feature);\n const onlyIf = (feature, options = {}) => (has(feature) ? options : false);\n\n return [\n StarterKit.configure({\n heading: onlyIf(RICH_TEXT_FEATURE.textStyle, {levels: [...RICH_TEXT_HEADING_LEVELS]}),\n bold: onlyIf(RICH_TEXT_FEATURE.bold),\n italic: onlyIf(RICH_TEXT_FEATURE.italic),\n underline: onlyIf(RICH_TEXT_FEATURE.underline),\n strike: onlyIf(RICH_TEXT_FEATURE.strike),\n bulletList: onlyIf(RICH_TEXT_FEATURE.bulletList),\n orderedList: onlyIf(RICH_TEXT_FEATURE.orderedList),\n // sin listas tampoco hay renglones de lista\n listItem: has(RICH_TEXT_FEATURE.bulletList) || has(RICH_TEXT_FEATURE.orderedList) ? {} : false,\n blockquote: onlyIf(RICH_TEXT_FEATURE.blockquote),\n codeBlock: onlyIf(RICH_TEXT_FEATURE.codeBlock),\n // el código dentro de un renglón lo pide solo el bloque de código\n code: onlyIf(RICH_TEXT_FEATURE.codeBlock),\n undoRedo: onlyIf(RICH_TEXT_FEATURE.history),\n link: onlyIf(RICH_TEXT_FEATURE.link, {\n openOnClick: false,\n autolink: true,\n defaultProtocol: 'https',\n isAllowedUri: (url) => isSafeLinkUrl(url),\n HTMLAttributes: {rel: 'noopener noreferrer nofollow', target: '_blank'},\n }),\n }),\n ...(has(RICH_TEXT_FEATURE.align) ? [TextAlign.configure({types: [...ALIGNABLE_NODES]})] : []),\n ...(placeholder ? [Placeholder.configure({placeholder})] : []),\n CharacterCount.configure({limit: maxLength ?? null}),\n ...extensions,\n ];\n}\n"],"names":[],"mappings":";;;;AAcY,MAAC,2BAA2B,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC;AAC5D,MAAM,kBAAkB,OAAO,OAAO,CAAC,WAAW,WAAW,CAAC;AAUvD,SAAS,qBAAqB,EAAC,UAAU,aAAa,WAAW,aAAa,CAAA,EAAE,GAAG;AACtF,QAAM,MAAM,CAAC,YAAY,SAAS,SAAS,OAAO;AAClD,QAAM,SAAS,CAAC,SAAS,UAAU,CAAA,MAAQ,IAAI,OAAO,IAAI,UAAU;AAEpE,SAAO;AAAA,IACH,WAAW,UAAU;AAAA,MACjB,SAAS,OAAO,kBAAkB,WAAW,EAAC,QAAQ,CAAC,GAAG,wBAAwB,EAAC,CAAC;AAAA,MACpF,MAAM,OAAO,kBAAkB,IAAI;AAAA,MACnC,QAAQ,OAAO,kBAAkB,MAAM;AAAA,MACvC,WAAW,OAAO,kBAAkB,SAAS;AAAA,MAC7C,QAAQ,OAAO,kBAAkB,MAAM;AAAA,MACvC,YAAY,OAAO,kBAAkB,UAAU;AAAA,MAC/C,aAAa,OAAO,kBAAkB,WAAW;AAAA;AAAA,MAEjD,UAAU,IAAI,kBAAkB,UAAU,KAAK,IAAI,kBAAkB,WAAW,IAAI,CAAA,IAAK;AAAA,MACzF,YAAY,OAAO,kBAAkB,UAAU;AAAA,MAC/C,WAAW,OAAO,kBAAkB,SAAS;AAAA;AAAA,MAE7C,MAAM,OAAO,kBAAkB,SAAS;AAAA,MACxC,UAAU,OAAO,kBAAkB,OAAO;AAAA,MAC1C,MAAM,OAAO,kBAAkB,MAAM;AAAA,QACjC,aAAa;AAAA,QACb,UAAU;AAAA,QACV,iBAAiB;AAAA,QACjB,cAAc,CAAC,QAAQ,cAAc,GAAG;AAAA,QACxC,gBAAgB,EAAC,KAAK,gCAAgC,QAAQ,SAAQ;AAAA,MACtF,CAAa;AAAA,IACb,CAAS;AAAA,IACD,GAAI,IAAI,kBAAkB,KAAK,IAAI,CAAC,UAAU,UAAU,EAAC,OAAO,CAAC,GAAG,eAAe,EAAC,CAAC,CAAC,IAAI,CAAA;AAAA,IAC1F,GAAI,cAAc,CAAC,YAAY,UAAU,EAAC,YAAW,CAAC,CAAC,IAAI;IAC3D,eAAe,UAAU,EAAC,OAAO,aAAa,KAAI,CAAC;AAAA,IACnD,GAAG;AAAA,EACX;AACA;"}
@@ -0,0 +1,46 @@
1
+ const RICH_TEXT_FEATURE = Object.freeze({
2
+ textStyle: "textStyle",
3
+ bold: "bold",
4
+ italic: "italic",
5
+ underline: "underline",
6
+ strike: "strike",
7
+ bulletList: "bulletList",
8
+ orderedList: "orderedList",
9
+ blockquote: "blockquote",
10
+ codeBlock: "codeBlock",
11
+ link: "link",
12
+ align: "align",
13
+ clear: "clear",
14
+ history: "history"
15
+ });
16
+ const DEFAULT_RICH_TEXT_FEATURES = Object.freeze(Object.values(RICH_TEXT_FEATURE));
17
+ const SAFE_LINK_PROTOCOLS = Object.freeze(["https", "http", "mailto", "tel"]);
18
+ const PROTOCOL_PATTERN = /^([a-z][a-z\d+.-]*):/i;
19
+ const BARE_DOMAIN_PATTERN = /^[\w-]+(\.[\w-]+)+(\/\S*)?$/;
20
+ const EMPTY_DOCUMENT_PATTERN = /^\s*(<p>\s*<\/p>\s*)*$/;
21
+ function linkUrlOf(typedUrl) {
22
+ const url = (typedUrl ?? "").trim();
23
+ if (!url) {
24
+ return null;
25
+ }
26
+ const protocol = PROTOCOL_PATTERN.exec(url)?.[1]?.toLowerCase();
27
+ if (protocol) {
28
+ return SAFE_LINK_PROTOCOLS.includes(protocol) ? url : null;
29
+ }
30
+ return BARE_DOMAIN_PATTERN.test(url) ? `https://${url}` : null;
31
+ }
32
+ function isSafeLinkUrl(url) {
33
+ return linkUrlOf(url) !== null;
34
+ }
35
+ function normalizedHtmlOf(html) {
36
+ return !html || EMPTY_DOCUMENT_PATTERN.test(html) ? "" : html;
37
+ }
38
+ export {
39
+ DEFAULT_RICH_TEXT_FEATURES,
40
+ RICH_TEXT_FEATURE,
41
+ SAFE_LINK_PROTOCOLS,
42
+ isSafeLinkUrl,
43
+ linkUrlOf,
44
+ normalizedHtmlOf
45
+ };
46
+ //# sourceMappingURL=richTextRules.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"richTextRules.js","sources":["../../src/richText/richTextRules.js"],"sourcesContent":["// Lo que el editor de texto decide sin pantalla: qué botones trae (RICH_TEXT_FEATURE), qué dirección de liga se acepta y\n// cómo queda el texto vacío.\n//\n// Ligas: solo https, http, mailto y tel. Una dirección sin protocolo («calcita.mx») se completa con https://. Lo demás\n// (javascript:, data:, file:) se rechaza: una liga así ejecuta código al picarla (XSS).\n//\n// Vacío: el editor deja «<p></p>» cuando se borra todo; al formulario llega '' para que required() funcione.\n//\n// Puro (sin React): se prueba con node (richTextRules.test.js).\n//\n// Genérico del paquete: function (regla de la casa).\n\n/** Los botones que puede traer la barra del editor. */\nexport const RICH_TEXT_FEATURE = Object.freeze({\n textStyle: 'textStyle',\n bold: 'bold',\n italic: 'italic',\n underline: 'underline',\n strike: 'strike',\n bulletList: 'bulletList',\n orderedList: 'orderedList',\n blockquote: 'blockquote',\n codeBlock: 'codeBlock',\n link: 'link',\n align: 'align',\n clear: 'clear',\n history: 'history',\n});\n\n/** Los de siempre: todos. Un editor más sencillo pasa su lista (features={[RICH_TEXT_FEATURE.bold, …]}). */\nexport const DEFAULT_RICH_TEXT_FEATURES = Object.freeze(Object.values(RICH_TEXT_FEATURE));\n\n/** Los protocolos que puede llevar una liga. */\nexport const SAFE_LINK_PROTOCOLS = Object.freeze(['https', 'http', 'mailto', 'tel']);\n\nconst PROTOCOL_PATTERN = /^([a-z][a-z\\d+.-]*):/i;\n// «calcita.mx», «www.ejemplo.com/ruta»: un dominio sin protocolo\nconst BARE_DOMAIN_PATTERN = /^[\\w-]+(\\.[\\w-]+)+(\\/\\S*)?$/;\nconst EMPTY_DOCUMENT_PATTERN = /^\\s*(<p>\\s*<\\/p>\\s*)*$/;\n\n/**\n * La dirección de una liga lista para guardarse, o null si no se acepta.\n *\n * @param {string|null|undefined} typedUrl lo que escribió la persona\n * @returns {string|null}\n */\nexport function linkUrlOf(typedUrl) {\n const url = (typedUrl ?? '').trim();\n if (!url) {\n return null;\n }\n const protocol = PROTOCOL_PATTERN.exec(url)?.[1]?.toLowerCase();\n if (protocol) {\n return SAFE_LINK_PROTOCOLS.includes(protocol) ? url : null;\n }\n return BARE_DOMAIN_PATTERN.test(url) ? `https://${url}` : null;\n}\n\n/**\n * ¿Se acepta esta dirección como liga? (lo que pide la extensión de ligas del editor)\n *\n * @param {string} url\n * @returns {boolean}\n */\nexport function isSafeLinkUrl(url) {\n return linkUrlOf(url) !== null;\n}\n\n/**\n * El HTML del editor como se guarda: '' si no hay nada escrito.\n *\n * @param {string|null|undefined} html\n * @returns {string}\n */\nexport function normalizedHtmlOf(html) {\n return !html || EMPTY_DOCUMENT_PATTERN.test(html) ? '' : html;\n}\n"],"names":[],"mappings":"AAaY,MAAC,oBAAoB,OAAO,OAAO;AAAA,EAC3C,WAAW;AAAA,EACX,MAAM;AAAA,EACN,QAAQ;AAAA,EACR,WAAW;AAAA,EACX,QAAQ;AAAA,EACR,YAAY;AAAA,EACZ,aAAa;AAAA,EACb,YAAY;AAAA,EACZ,WAAW;AAAA,EACX,MAAM;AAAA,EACN,OAAO;AAAA,EACP,OAAO;AAAA,EACP,SAAS;AACb,CAAC;AAGW,MAAC,6BAA6B,OAAO,OAAO,OAAO,OAAO,iBAAiB,CAAC;AAG5E,MAAC,sBAAsB,OAAO,OAAO,CAAC,SAAS,QAAQ,UAAU,KAAK,CAAC;AAEnF,MAAM,mBAAmB;AAEzB,MAAM,sBAAsB;AAC5B,MAAM,yBAAyB;AAQxB,SAAS,UAAU,UAAU;AAChC,QAAM,OAAO,YAAY,IAAI,KAAI;AACjC,MAAI,CAAC,KAAK;AACN,WAAO;AAAA,EACX;AACA,QAAM,WAAW,iBAAiB,KAAK,GAAG,IAAI,CAAC,GAAG,YAAW;AAC7D,MAAI,UAAU;AACV,WAAO,oBAAoB,SAAS,QAAQ,IAAI,MAAM;AAAA,EAC1D;AACA,SAAO,oBAAoB,KAAK,GAAG,IAAI,WAAW,GAAG,KAAK;AAC9D;AAQO,SAAS,cAAc,KAAK;AAC/B,SAAO,UAAU,GAAG,MAAM;AAC9B;AAQO,SAAS,iBAAiB,MAAM;AACnC,SAAO,CAAC,QAAQ,uBAAuB,KAAK,IAAI,IAAI,KAAK;AAC7D;"}
package/dist/table.js CHANGED
@@ -4,6 +4,7 @@ import { default as default4 } from "./DataTable/EmptyState.js";
4
4
  import { default as default5 } from "./DataTable/FilterChips.js";
5
5
  import { default as default6 } from "./DataTable/GoToPage.js";
6
6
  import { default as default7 } from "./DataTable/ServerTable.js";
7
+ import { default as default8 } from "./DataTable/ServerTableFilterDrawer.js";
7
8
  import { buildChipConfig } from "./DataTable/buildChipConfig.js";
8
9
  import { detailColumn, facetColumn, textColumn } from "./DataTable/columns.js";
9
10
  import { TableFilterContext, useTableFilter } from "./DataTable/filterContext.js";
@@ -21,6 +22,7 @@ export {
21
22
  default6 as GoToPage,
22
23
  SELECTION_PHONE_LAYOUT,
23
24
  default7 as ServerTable,
25
+ default8 as ServerTableFilterDrawer,
24
26
  TableFilterContext,
25
27
  buildChipConfig,
26
28
  buildTableActors,
package/dist/table.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"table.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"table.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;"}
@@ -106,6 +106,20 @@ function whiteLabelOf(theme, colorName) {
106
106
  };
107
107
  return lightDarkStylesOf(theme, schemeStylesOf("light"), schemeStylesOf("dark"));
108
108
  }
109
+ function clockItemStylesOf(theme) {
110
+ const palette = paletteOf(theme);
111
+ const selected = {
112
+ backgroundColor: `color-mix(in srgb, ${palette.primary.main} 22%, transparent)`,
113
+ ...accentTextStylesOf(theme),
114
+ fontWeight: 600
115
+ };
116
+ return {
117
+ justifyContent: "center",
118
+ marginInline: MENU_ROW_INSET_PIXELS,
119
+ "&.Mui-selected, &.Mui-selected:hover, &.Mui-selected:focus-visible": selected,
120
+ "&.Mui-selected::after": { content: "none" }
121
+ };
122
+ }
109
123
  function monogramOf(theme) {
110
124
  return lightDarkStylesOf(theme, { color: WHITE_LABEL, backgroundColor: MONOGRAM_GRAY.light }, { color: WHITE_LABEL, backgroundColor: MONOGRAM_GRAY.dark });
111
125
  }
@@ -704,6 +718,19 @@ function glassComponents({ surfaces = false } = {}) {
704
718
  }
705
719
  }
706
720
  },
721
+ // las columnas de horas y minutos de MUI X: sus renglones son MenuItem, así que heredaban la palomita del menú (tapaba
722
+ // el número y lo corría) y además MUI X les pone el color lleno con la letra de contraste (negra sobre el naranja en
723
+ // oscuro). Aquí el elegido va como el día elegido del calendario: círculo tenue de su color y número legible, centrado
724
+ MuiMultiSectionDigitalClockSection: {
725
+ styleOverrides: {
726
+ item: ({ theme }) => clockItemStylesOf(theme)
727
+ }
728
+ },
729
+ MuiDigitalClock: {
730
+ styleOverrides: {
731
+ item: ({ theme }) => clockItemStylesOf(theme)
732
+ }
733
+ },
707
734
  // las pestañas: la misma tira, y la marca de abajo se vuelve la gota detrás de la pestaña elegida (se desliza sola)
708
735
  MuiTabs: {
709
736
  styleOverrides: {