bootstack 0.1.0__py3-none-any.whl

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 (471) hide show
  1. bootstack/__init__.py +157 -0
  2. bootstack/__main__.py +5 -0
  3. bootstack/_core/__init__.py +21 -0
  4. bootstack/_core/capabilities/__init__.py +45 -0
  5. bootstack/_core/capabilities/after.py +103 -0
  6. bootstack/_core/capabilities/bind.py +192 -0
  7. bootstack/_core/capabilities/bindtags.py +112 -0
  8. bootstack/_core/capabilities/busy.py +72 -0
  9. bootstack/_core/capabilities/clipboard.py +89 -0
  10. bootstack/_core/capabilities/focus.py +118 -0
  11. bootstack/_core/capabilities/grab.py +65 -0
  12. bootstack/_core/capabilities/grid.py +211 -0
  13. bootstack/_core/capabilities/localization.py +231 -0
  14. bootstack/_core/capabilities/pack.py +140 -0
  15. bootstack/_core/capabilities/place.py +113 -0
  16. bootstack/_core/capabilities/selection.py +136 -0
  17. bootstack/_core/capabilities/signals.py +244 -0
  18. bootstack/_core/capabilities/winfo.py +315 -0
  19. bootstack/_core/colorutils.py +234 -0
  20. bootstack/_core/exceptions.py +25 -0
  21. bootstack/_core/images.py +463 -0
  22. bootstack/_core/mixins/__init__.py +1 -0
  23. bootstack/_core/mixins/ttk_state.py +35 -0
  24. bootstack/_core/mixins/widget.py +132 -0
  25. bootstack/_core/paths.py +49 -0
  26. bootstack/_core/publisher.py +149 -0
  27. bootstack/_core/variables.py +62 -0
  28. bootstack/_runtime/__init__.py +3 -0
  29. bootstack/_runtime/app.py +930 -0
  30. bootstack/_runtime/base_window.py +945 -0
  31. bootstack/_runtime/events.py +399 -0
  32. bootstack/_runtime/shortcuts.py +496 -0
  33. bootstack/_runtime/tk_patch.py +43 -0
  34. bootstack/_runtime/toplevel.py +276 -0
  35. bootstack/_runtime/utility.py +457 -0
  36. bootstack/_runtime/visual_focus.py +240 -0
  37. bootstack/_runtime/window_utilities.py +1123 -0
  38. bootstack/assets/__init__.py +21 -0
  39. bootstack/assets/bootstack.ico +0 -0
  40. bootstack/assets/bootstack.png +0 -0
  41. bootstack/assets/elements/__init__.py +0 -0
  42. bootstack/assets/elements/badge-pill.png +0 -0
  43. bootstack/assets/elements/badge-square.png +0 -0
  44. bootstack/assets/elements/button-compact.png +0 -0
  45. bootstack/assets/elements/button-default.png +0 -0
  46. bootstack/assets/elements/buttongroup-after-h-compact.png +0 -0
  47. bootstack/assets/elements/buttongroup-after-h-default.png +0 -0
  48. bootstack/assets/elements/buttongroup-after-v-compact.png +0 -0
  49. bootstack/assets/elements/buttongroup-after-v-default.png +0 -0
  50. bootstack/assets/elements/buttongroup-before-h-compact.png +0 -0
  51. bootstack/assets/elements/buttongroup-before-h-default.png +0 -0
  52. bootstack/assets/elements/buttongroup-before-v-compact.png +0 -0
  53. bootstack/assets/elements/buttongroup-before-v-default.png +0 -0
  54. bootstack/assets/elements/buttongroup-center-h-compact.png +0 -0
  55. bootstack/assets/elements/buttongroup-center-h-default.png +0 -0
  56. bootstack/assets/elements/buttongroup-center-v-compact.png +0 -0
  57. bootstack/assets/elements/buttongroup-center-v-default.png +0 -0
  58. bootstack/assets/elements/card.png +0 -0
  59. bootstack/assets/elements/checkbox-checked.png +0 -0
  60. bootstack/assets/elements/checkbox-indeterminate.png +0 -0
  61. bootstack/assets/elements/checkbox-unchecked.png +0 -0
  62. bootstack/assets/elements/field.png +0 -0
  63. bootstack/assets/elements/input-addon-compact.png +0 -0
  64. bootstack/assets/elements/input-addon-default.png +0 -0
  65. bootstack/assets/elements/input-compact.png +0 -0
  66. bootstack/assets/elements/input-default.png +0 -0
  67. bootstack/assets/elements/list-item-separated.png +0 -0
  68. bootstack/assets/elements/list-item.png +0 -0
  69. bootstack/assets/elements/listrow-compact.png +0 -0
  70. bootstack/assets/elements/listrow-default.png +0 -0
  71. bootstack/assets/elements/manifest.toml +361 -0
  72. bootstack/assets/elements/menu-item.png +0 -0
  73. bootstack/assets/elements/navitem-compact.png +0 -0
  74. bootstack/assets/elements/navitem-default.png +0 -0
  75. bootstack/assets/elements/progressbar-h-compact.png +0 -0
  76. bootstack/assets/elements/progressbar-h-default.png +0 -0
  77. bootstack/assets/elements/progressbar-v-compact.png +0 -0
  78. bootstack/assets/elements/progressbar-v-default.png +0 -0
  79. bootstack/assets/elements/radiobutton.png +0 -0
  80. bootstack/assets/elements/scrollbar-horizontal.png +0 -0
  81. bootstack/assets/elements/scrollbar-vertical.png +0 -0
  82. bootstack/assets/elements/slider-handle.png +0 -0
  83. bootstack/assets/elements/slider-track-h.png +0 -0
  84. bootstack/assets/elements/slider-track-v.png +0 -0
  85. bootstack/assets/elements/switch-off.png +0 -0
  86. bootstack/assets/elements/switch-on.png +0 -0
  87. bootstack/assets/elements/tab-h.png +0 -0
  88. bootstack/assets/elements/tab-v.png +0 -0
  89. bootstack/assets/icons/bootstrap.ttf +0 -0
  90. bootstack/assets/icons/glyphmap.json +2080 -0
  91. bootstack/assets/icons/icon_metrics.json +12470 -0
  92. bootstack/assets/locales/ar/LC_MESSAGES/bootstack.mo +0 -0
  93. bootstack/assets/locales/ar/LC_MESSAGES/bootstack.po +856 -0
  94. bootstack/assets/locales/bg/LC_MESSAGES/bootstack.mo +0 -0
  95. bootstack/assets/locales/bg/LC_MESSAGES/bootstack.po +878 -0
  96. bootstack/assets/locales/cs/LC_MESSAGES/bootstack.mo +0 -0
  97. bootstack/assets/locales/cs/LC_MESSAGES/bootstack.po +856 -0
  98. bootstack/assets/locales/da/LC_MESSAGES/bootstack.mo +0 -0
  99. bootstack/assets/locales/da/LC_MESSAGES/bootstack.po +856 -0
  100. bootstack/assets/locales/de/LC_MESSAGES/bootstack.mo +0 -0
  101. bootstack/assets/locales/de/LC_MESSAGES/bootstack.po +856 -0
  102. bootstack/assets/locales/en/LC_MESSAGES/bootstack.mo +0 -0
  103. bootstack/assets/locales/en/LC_MESSAGES/bootstack.po +878 -0
  104. bootstack/assets/locales/es/LC_MESSAGES/bootstack.mo +0 -0
  105. bootstack/assets/locales/es/LC_MESSAGES/bootstack.po +856 -0
  106. bootstack/assets/locales/fr/LC_MESSAGES/bootstack.mo +0 -0
  107. bootstack/assets/locales/fr/LC_MESSAGES/bootstack.po +856 -0
  108. bootstack/assets/locales/he/LC_MESSAGES/bootstack.mo +0 -0
  109. bootstack/assets/locales/he/LC_MESSAGES/bootstack.po +854 -0
  110. bootstack/assets/locales/hi/LC_MESSAGES/bootstack.mo +0 -0
  111. bootstack/assets/locales/hi/LC_MESSAGES/bootstack.po +845 -0
  112. bootstack/assets/locales/it/LC_MESSAGES/bootstack.mo +0 -0
  113. bootstack/assets/locales/it/LC_MESSAGES/bootstack.po +844 -0
  114. bootstack/assets/locales/ja/LC_MESSAGES/bootstack.mo +0 -0
  115. bootstack/assets/locales/ja/LC_MESSAGES/bootstack.po +917 -0
  116. bootstack/assets/locales/ko/LC_MESSAGES/bootstack.mo +0 -0
  117. bootstack/assets/locales/ko/LC_MESSAGES/bootstack.po +845 -0
  118. bootstack/assets/locales/nb/LC_MESSAGES/bootstack.mo +0 -0
  119. bootstack/assets/locales/nb/LC_MESSAGES/bootstack.po +844 -0
  120. bootstack/assets/locales/nl/LC_MESSAGES/bootstack.mo +0 -0
  121. bootstack/assets/locales/nl/LC_MESSAGES/bootstack.po +844 -0
  122. bootstack/assets/locales/pl/LC_MESSAGES/bootstack.mo +0 -0
  123. bootstack/assets/locales/pl/LC_MESSAGES/bootstack.po +845 -0
  124. bootstack/assets/locales/pt/LC_MESSAGES/bootstack.mo +0 -0
  125. bootstack/assets/locales/pt/LC_MESSAGES/bootstack.po +845 -0
  126. bootstack/assets/locales/pt_BR/LC_MESSAGES/bootstack.mo +0 -0
  127. bootstack/assets/locales/pt_BR/LC_MESSAGES/bootstack.po +845 -0
  128. bootstack/assets/locales/sl/LC_MESSAGES/bootstack.mo +0 -0
  129. bootstack/assets/locales/sl/LC_MESSAGES/bootstack.po +845 -0
  130. bootstack/assets/locales/sv/LC_MESSAGES/bootstack.mo +0 -0
  131. bootstack/assets/locales/sv/LC_MESSAGES/bootstack.po +845 -0
  132. bootstack/assets/locales/tr/LC_MESSAGES/bootstack.mo +0 -0
  133. bootstack/assets/locales/tr/LC_MESSAGES/bootstack.po +845 -0
  134. bootstack/assets/locales/zh_CN/LC_MESSAGES/bootstack.mo +0 -0
  135. bootstack/assets/locales/zh_CN/LC_MESSAGES/bootstack.po +845 -0
  136. bootstack/assets/locales/zh_TW/LC_MESSAGES/bootstack.mo +0 -0
  137. bootstack/assets/locales/zh_TW/LC_MESSAGES/bootstack.po +845 -0
  138. bootstack/cli/__init__.py +133 -0
  139. bootstack/cli/__main__.py +6 -0
  140. bootstack/cli/add.py +395 -0
  141. bootstack/cli/appicon.py +285 -0
  142. bootstack/cli/build.py +115 -0
  143. bootstack/cli/config.py +313 -0
  144. bootstack/cli/demo.py +564 -0
  145. bootstack/cli/dev.py +153 -0
  146. bootstack/cli/doctor.py +195 -0
  147. bootstack/cli/icons.py +98 -0
  148. bootstack/cli/promote.py +120 -0
  149. bootstack/cli/pyinstaller.py +268 -0
  150. bootstack/cli/run.py +95 -0
  151. bootstack/cli/start.py +117 -0
  152. bootstack/cli/templates/__init__.py +931 -0
  153. bootstack/clipboard.py +48 -0
  154. bootstack/constants.py +318 -0
  155. bootstack/data/README.md +615 -0
  156. bootstack/data/__init__.py +78 -0
  157. bootstack/data/_observable.py +276 -0
  158. bootstack/data/base.py +780 -0
  159. bootstack/data/file_source.py +367 -0
  160. bootstack/data/memory_source.py +450 -0
  161. bootstack/data/query.py +367 -0
  162. bootstack/data/readers.py +289 -0
  163. bootstack/data/sqlite_source.py +869 -0
  164. bootstack/data/types.py +354 -0
  165. bootstack/data/writers.py +232 -0
  166. bootstack/dev/__init__.py +36 -0
  167. bootstack/dev/_capture.py +141 -0
  168. bootstack/dev/_env.py +43 -0
  169. bootstack/dev/_registry.py +140 -0
  170. bootstack/dev/_reloader.py +351 -0
  171. bootstack/dev/_reset.py +50 -0
  172. bootstack/dev/_watcher.py +91 -0
  173. bootstack/dialogs/__init__.py +948 -0
  174. bootstack/dialogs/_impl/__init__.py +47 -0
  175. bootstack/dialogs/_impl/colorchooser.py +588 -0
  176. bootstack/dialogs/_impl/datedialog.py +450 -0
  177. bootstack/dialogs/_impl/dialog.py +594 -0
  178. bootstack/dialogs/_impl/filterdialog.py +358 -0
  179. bootstack/dialogs/_impl/fontdialog.py +364 -0
  180. bootstack/dialogs/_impl/formdialog.py +564 -0
  181. bootstack/dialogs/_impl/message.py +486 -0
  182. bootstack/dialogs/_impl/query.py +570 -0
  183. bootstack/errors.py +67 -0
  184. bootstack/events/__init__.py +111 -0
  185. bootstack/events/_event.py +135 -0
  186. bootstack/events/_payloads.py +539 -0
  187. bootstack/events/_subscription.py +38 -0
  188. bootstack/i18n/README.md +77 -0
  189. bootstack/i18n/__init__.py +23 -0
  190. bootstack/i18n/catalog.py +121 -0
  191. bootstack/i18n/intl_format.py +584 -0
  192. bootstack/i18n/msgcat.py +425 -0
  193. bootstack/i18n/specs.py +156 -0
  194. bootstack/images.py +563 -0
  195. bootstack/py.typed +1 -0
  196. bootstack/scheduling/__init__.py +11 -0
  197. bootstack/scheduling/_schedule.py +218 -0
  198. bootstack/shortcuts.py +21 -0
  199. bootstack/signals/README.md +98 -0
  200. bootstack/signals/__init__.py +10 -0
  201. bootstack/signals/integration.py +100 -0
  202. bootstack/signals/signal.py +353 -0
  203. bootstack/signals/types.py +6 -0
  204. bootstack/store.py +286 -0
  205. bootstack/streams/__init__.py +12 -0
  206. bootstack/streams/_stream.py +321 -0
  207. bootstack/style/__init__.py +38 -0
  208. bootstack/style/builders/__init__.py +51 -0
  209. bootstack/style/builders/badge.py +46 -0
  210. bootstack/style/builders/button.py +339 -0
  211. bootstack/style/builders/buttongroup.py +311 -0
  212. bootstack/style/builders/calendar.py +271 -0
  213. bootstack/style/builders/checkbutton.py +110 -0
  214. bootstack/style/builders/combobox.py +113 -0
  215. bootstack/style/builders/contextmenu.py +268 -0
  216. bootstack/style/builders/entry.py +82 -0
  217. bootstack/style/builders/expander.py +148 -0
  218. bootstack/style/builders/field.py +335 -0
  219. bootstack/style/builders/frame.py +50 -0
  220. bootstack/style/builders/label.py +28 -0
  221. bootstack/style/builders/labelframe.py +34 -0
  222. bootstack/style/builders/listview.py +369 -0
  223. bootstack/style/builders/menubar.py +91 -0
  224. bootstack/style/builders/menubutton.py +359 -0
  225. bootstack/style/builders/panedwindow.py +25 -0
  226. bootstack/style/builders/progressbar.py +67 -0
  227. bootstack/style/builders/radiobutton.py +99 -0
  228. bootstack/style/builders/scale.py +64 -0
  229. bootstack/style/builders/scrollbar.py +225 -0
  230. bootstack/style/builders/separator.py +49 -0
  231. bootstack/style/builders/sidenav.py +643 -0
  232. bootstack/style/builders/sizegrip.py +15 -0
  233. bootstack/style/builders/spinbox.py +119 -0
  234. bootstack/style/builders/switch.py +70 -0
  235. bootstack/style/builders/tabitem.py +204 -0
  236. bootstack/style/builders/togglegroup.py +294 -0
  237. bootstack/style/builders/toolbutton.py +275 -0
  238. bootstack/style/builders/tooltip.py +26 -0
  239. bootstack/style/builders/treeview.py +193 -0
  240. bootstack/style/builders/utils.py +455 -0
  241. bootstack/style/builders_tk/__init__.py +16 -0
  242. bootstack/style/builders_tk/defaults.py +229 -0
  243. bootstack/style/element.py +173 -0
  244. bootstack/style/fonts.py +123 -0
  245. bootstack/style/style.py +609 -0
  246. bootstack/style/style_builder_base.py +716 -0
  247. bootstack/style/style_builder_mixed.py +93 -0
  248. bootstack/style/style_builder_tk.py +109 -0
  249. bootstack/style/style_builder_ttk.py +353 -0
  250. bootstack/style/style_resolver.py +447 -0
  251. bootstack/style/theme.py +245 -0
  252. bootstack/style/theme_provider.py +471 -0
  253. bootstack/style/themes/__init__.py +128 -0
  254. bootstack/style/tk_patch.py +5 -0
  255. bootstack/style/token_maps.py +41 -0
  256. bootstack/style/types.py +32 -0
  257. bootstack/style/typography.py +523 -0
  258. bootstack/style/utility.py +746 -0
  259. bootstack/types.py +39 -0
  260. bootstack/validation/__init__.py +6 -0
  261. bootstack/validation/types.py +15 -0
  262. bootstack/validation/validation_result.py +17 -0
  263. bootstack/validation/validation_rules.py +205 -0
  264. bootstack/widgets/__init__.py +74 -0
  265. bootstack/widgets/_core/__init__.py +31 -0
  266. bootstack/widgets/_core/app_config.py +266 -0
  267. bootstack/widgets/_core/base.py +461 -0
  268. bootstack/widgets/_core/container.py +334 -0
  269. bootstack/widgets/_core/context.py +35 -0
  270. bootstack/widgets/_core/events.py +130 -0
  271. bootstack/widgets/_core/field_mixin.py +353 -0
  272. bootstack/widgets/_core/icon_image_props.py +72 -0
  273. bootstack/widgets/_core/image_binding.py +93 -0
  274. bootstack/widgets/_core/navmodel.py +345 -0
  275. bootstack/widgets/_core/options.py +210 -0
  276. bootstack/widgets/_core/selection_group.py +130 -0
  277. bootstack/widgets/_core/window_controls.py +96 -0
  278. bootstack/widgets/_core/window_menu.py +246 -0
  279. bootstack/widgets/_impl/__init__.py +1 -0
  280. bootstack/widgets/_impl/_internal/__init__.py +0 -0
  281. bootstack/widgets/_impl/_internal/wrapper_base.py +307 -0
  282. bootstack/widgets/_impl/_parts/__init__.py +11 -0
  283. bootstack/widgets/_impl/_parts/numberentry_part.py +385 -0
  284. bootstack/widgets/_impl/_parts/spinnerentry_part.py +434 -0
  285. bootstack/widgets/_impl/_parts/textentry_part.py +406 -0
  286. bootstack/widgets/_impl/composites/__init__.py +33 -0
  287. bootstack/widgets/_impl/composites/_dateutils.py +33 -0
  288. bootstack/widgets/_impl/composites/_image_fit.py +105 -0
  289. bootstack/widgets/_impl/composites/accordion.py +381 -0
  290. bootstack/widgets/_impl/composites/avatar.py +191 -0
  291. bootstack/widgets/_impl/composites/buttongroup.py +371 -0
  292. bootstack/widgets/_impl/composites/calendar.py +972 -0
  293. bootstack/widgets/_impl/composites/carousel.py +567 -0
  294. bootstack/widgets/_impl/composites/chart.py +882 -0
  295. bootstack/widgets/_impl/composites/compositeframe.py +298 -0
  296. bootstack/widgets/_impl/composites/contextmenu.py +1951 -0
  297. bootstack/widgets/_impl/composites/dateentry.py +404 -0
  298. bootstack/widgets/_impl/composites/dropdownbutton.py +325 -0
  299. bootstack/widgets/_impl/composites/expander.py +515 -0
  300. bootstack/widgets/_impl/composites/field.py +670 -0
  301. bootstack/widgets/_impl/composites/form.py +1066 -0
  302. bootstack/widgets/_impl/composites/gallery.py +551 -0
  303. bootstack/widgets/_impl/composites/list/__init__.py +15 -0
  304. bootstack/widgets/_impl/composites/list/listitem.py +802 -0
  305. bootstack/widgets/_impl/composites/list/listview.py +1433 -0
  306. bootstack/widgets/_impl/composites/menu/__init__.py +18 -0
  307. bootstack/widgets/_impl/composites/menu/model.py +358 -0
  308. bootstack/widgets/_impl/composites/menu/render_native.py +134 -0
  309. bootstack/widgets/_impl/composites/menu/render_themed.py +134 -0
  310. bootstack/widgets/_impl/composites/meter.py +860 -0
  311. bootstack/widgets/_impl/composites/numericentry.py +201 -0
  312. bootstack/widgets/_impl/composites/pagestack.py +395 -0
  313. bootstack/widgets/_impl/composites/passwordentry.py +142 -0
  314. bootstack/widgets/_impl/composites/pathentry.py +168 -0
  315. bootstack/widgets/_impl/composites/picture.py +289 -0
  316. bootstack/widgets/_impl/composites/radiogroup.py +511 -0
  317. bootstack/widgets/_impl/composites/scrolledtext.py +375 -0
  318. bootstack/widgets/_impl/composites/scrolledtext.pyi +186 -0
  319. bootstack/widgets/_impl/composites/scrollview.py +764 -0
  320. bootstack/widgets/_impl/composites/selectbox.py +1026 -0
  321. bootstack/widgets/_impl/composites/shell/__init__.py +40 -0
  322. bootstack/widgets/_impl/composites/shell/content_host.py +52 -0
  323. bootstack/widgets/_impl/composites/shell/layout.py +335 -0
  324. bootstack/widgets/_impl/composites/shell/nav_panel.py +345 -0
  325. bootstack/widgets/_impl/composites/shell/providers.py +558 -0
  326. bootstack/widgets/_impl/composites/shell/rail.py +117 -0
  327. bootstack/widgets/_impl/composites/shell/shell.py +581 -0
  328. bootstack/widgets/_impl/composites/shell/workspace.py +273 -0
  329. bootstack/widgets/_impl/composites/sidenav/__init__.py +16 -0
  330. bootstack/widgets/_impl/composites/sidenav/header.py +81 -0
  331. bootstack/widgets/_impl/composites/sidenav/separator.py +44 -0
  332. bootstack/widgets/_impl/composites/slider/__init__.py +7 -0
  333. bootstack/widgets/_impl/composites/slider/_shared.py +195 -0
  334. bootstack/widgets/_impl/composites/slider/rangeslider.py +982 -0
  335. bootstack/widgets/_impl/composites/slider/slider.py +851 -0
  336. bootstack/widgets/_impl/composites/spinnerentry.py +185 -0
  337. bootstack/widgets/_impl/composites/tableview/__init__.py +5 -0
  338. bootstack/widgets/_impl/composites/tableview/tableview.py +3388 -0
  339. bootstack/widgets/_impl/composites/tableview/types.py +169 -0
  340. bootstack/widgets/_impl/composites/tabs/__init__.py +23 -0
  341. bootstack/widgets/_impl/composites/tabs/tabitem.py +389 -0
  342. bootstack/widgets/_impl/composites/tabs/tabs.py +974 -0
  343. bootstack/widgets/_impl/composites/tabs/tabview.py +650 -0
  344. bootstack/widgets/_impl/composites/textarea/__init__.py +26 -0
  345. bootstack/widgets/_impl/composites/textarea/change.py +46 -0
  346. bootstack/widgets/_impl/composites/textarea/codeeditor.py +526 -0
  347. bootstack/widgets/_impl/composites/textarea/core.py +495 -0
  348. bootstack/widgets/_impl/composites/textarea/decoration.py +42 -0
  349. bootstack/widgets/_impl/composites/textarea/diff.py +127 -0
  350. bootstack/widgets/_impl/composites/textarea/extensions/__init__.py +1 -0
  351. bootstack/widgets/_impl/composites/textarea/extensions/bracket_matcher.py +138 -0
  352. bootstack/widgets/_impl/composites/textarea/extensions/indent_guides.py +158 -0
  353. bootstack/widgets/_impl/composites/textarea/extensions/line_numbers.py +138 -0
  354. bootstack/widgets/_impl/composites/textarea/extensions/pygments_highlighter.py +312 -0
  355. bootstack/widgets/_impl/composites/textarea/extensions/smart_indent.py +177 -0
  356. bootstack/widgets/_impl/composites/textarea/filter.py +171 -0
  357. bootstack/widgets/_impl/composites/textarea/search_overlay.py +459 -0
  358. bootstack/widgets/_impl/composites/textarea/sidebar.py +88 -0
  359. bootstack/widgets/_impl/composites/textarea/style_registry.py +178 -0
  360. bootstack/widgets/_impl/composites/textarea/textarea.py +606 -0
  361. bootstack/widgets/_impl/composites/textarea/undo.py +217 -0
  362. bootstack/widgets/_impl/composites/textentry.py +57 -0
  363. bootstack/widgets/_impl/composites/timeentry.py +176 -0
  364. bootstack/widgets/_impl/composites/toast.py +390 -0
  365. bootstack/widgets/_impl/composites/toast_stack.py +156 -0
  366. bootstack/widgets/_impl/composites/togglegroup.py +418 -0
  367. bootstack/widgets/_impl/composites/toolbar.py +608 -0
  368. bootstack/widgets/_impl/composites/tooltip.py +491 -0
  369. bootstack/widgets/_impl/composites/tree/__init__.py +7 -0
  370. bootstack/widgets/_impl/composites/tree/source_binding.py +136 -0
  371. bootstack/widgets/_impl/composites/tree/treeitem.py +393 -0
  372. bootstack/widgets/_impl/composites/tree/treenode.py +174 -0
  373. bootstack/widgets/_impl/composites/tree/treeview.py +841 -0
  374. bootstack/widgets/_impl/mixins/__init__.py +24 -0
  375. bootstack/widgets/_impl/mixins/configure_mixin.py +216 -0
  376. bootstack/widgets/_impl/mixins/entry_mixin.py +134 -0
  377. bootstack/widgets/_impl/mixins/font_mixin.py +368 -0
  378. bootstack/widgets/_impl/mixins/icon_mixin.py +61 -0
  379. bootstack/widgets/_impl/mixins/localization_mixin.py +253 -0
  380. bootstack/widgets/_impl/mixins/signal_mixin.py +268 -0
  381. bootstack/widgets/_impl/mixins/validation_mixin.py +226 -0
  382. bootstack/widgets/_impl/primitives/__init__.py +49 -0
  383. bootstack/widgets/_impl/primitives/_menubutton.py +107 -0
  384. bootstack/widgets/_impl/primitives/badge.py +45 -0
  385. bootstack/widgets/_impl/primitives/button.py +76 -0
  386. bootstack/widgets/_impl/primitives/card.py +45 -0
  387. bootstack/widgets/_impl/primitives/checkbutton.py +124 -0
  388. bootstack/widgets/_impl/primitives/checktoggle.py +62 -0
  389. bootstack/widgets/_impl/primitives/combobox.py +156 -0
  390. bootstack/widgets/_impl/primitives/entry.py +87 -0
  391. bootstack/widgets/_impl/primitives/flexframe.py +448 -0
  392. bootstack/widgets/_impl/primitives/frame.py +185 -0
  393. bootstack/widgets/_impl/primitives/gridframe.py +546 -0
  394. bootstack/widgets/_impl/primitives/label.py +84 -0
  395. bootstack/widgets/_impl/primitives/labelframe.py +54 -0
  396. bootstack/widgets/_impl/primitives/optionmenu.py +387 -0
  397. bootstack/widgets/_impl/primitives/packframe.py +227 -0
  398. bootstack/widgets/_impl/primitives/panedwindow.py +45 -0
  399. bootstack/widgets/_impl/primitives/progressbar.py +83 -0
  400. bootstack/widgets/_impl/primitives/radiobutton.py +115 -0
  401. bootstack/widgets/_impl/primitives/radiotoggle.py +54 -0
  402. bootstack/widgets/_impl/primitives/scrollbar.py +42 -0
  403. bootstack/widgets/_impl/primitives/separator.py +43 -0
  404. bootstack/widgets/_impl/primitives/sizegrip.py +33 -0
  405. bootstack/widgets/_impl/primitives/spinbox.py +95 -0
  406. bootstack/widgets/_impl/primitives/switch.py +44 -0
  407. bootstack/widgets/_impl/primitives/treeview.py +69 -0
  408. bootstack/widgets/app.py +371 -0
  409. bootstack/widgets/appshell.py +1179 -0
  410. bootstack/widgets/avatar.py +140 -0
  411. bootstack/widgets/boolean_controls.py +455 -0
  412. bootstack/widgets/button.py +224 -0
  413. bootstack/widgets/buttongroup.py +239 -0
  414. bootstack/widgets/calendar.py +195 -0
  415. bootstack/widgets/card.py +159 -0
  416. bootstack/widgets/carousel.py +241 -0
  417. bootstack/widgets/chart.py +302 -0
  418. bootstack/widgets/codeeditor.py +675 -0
  419. bootstack/widgets/contextmenu.py +371 -0
  420. bootstack/widgets/datatable.py +688 -0
  421. bootstack/widgets/datefield.py +395 -0
  422. bootstack/widgets/divider.py +60 -0
  423. bootstack/widgets/expander.py +579 -0
  424. bootstack/widgets/form.py +200 -0
  425. bootstack/widgets/gallery.py +250 -0
  426. bootstack/widgets/gauge.py +168 -0
  427. bootstack/widgets/grid.py +121 -0
  428. bootstack/widgets/groupbox.py +162 -0
  429. bootstack/widgets/label.py +229 -0
  430. bootstack/widgets/listview.py +354 -0
  431. bootstack/widgets/menubutton.py +419 -0
  432. bootstack/widgets/numberfield.py +431 -0
  433. bootstack/widgets/pagestack.py +345 -0
  434. bootstack/widgets/passwordfield.py +383 -0
  435. bootstack/widgets/pathfield.py +454 -0
  436. bootstack/widgets/picture.py +251 -0
  437. bootstack/widgets/progressbar.py +106 -0
  438. bootstack/widgets/radio_variants.py +271 -0
  439. bootstack/widgets/radiogroup.py +228 -0
  440. bootstack/widgets/scrollbar.py +64 -0
  441. bootstack/widgets/scrollview.py +186 -0
  442. bootstack/widgets/select.py +302 -0
  443. bootstack/widgets/selectbutton.py +182 -0
  444. bootstack/widgets/sidebar_toggle.py +130 -0
  445. bootstack/widgets/sizegrip.py +42 -0
  446. bootstack/widgets/slider.py +408 -0
  447. bootstack/widgets/spinbox.py +147 -0
  448. bootstack/widgets/spinnerfield.py +413 -0
  449. bootstack/widgets/splash.py +367 -0
  450. bootstack/widgets/splitview.py +482 -0
  451. bootstack/widgets/stacks.py +249 -0
  452. bootstack/widgets/statusbar.py +189 -0
  453. bootstack/widgets/tabs.py +425 -0
  454. bootstack/widgets/textarea.py +459 -0
  455. bootstack/widgets/textfield.py +410 -0
  456. bootstack/widgets/theme_toggle.py +92 -0
  457. bootstack/widgets/timefield.py +340 -0
  458. bootstack/widgets/toast.py +314 -0
  459. bootstack/widgets/togglegroup.py +231 -0
  460. bootstack/widgets/toolbar.py +347 -0
  461. bootstack/widgets/tooltip.py +94 -0
  462. bootstack/widgets/tree.py +648 -0
  463. bootstack/widgets/types.py +305 -0
  464. bootstack/widgets/window.py +307 -0
  465. bootstack-0.1.0.dist-info/METADATA +301 -0
  466. bootstack-0.1.0.dist-info/RECORD +471 -0
  467. bootstack-0.1.0.dist-info/WHEEL +5 -0
  468. bootstack-0.1.0.dist-info/entry_points.txt +2 -0
  469. bootstack-0.1.0.dist-info/licenses/LICENSE +21 -0
  470. bootstack-0.1.0.dist-info/licenses/NOTICE +10 -0
  471. bootstack-0.1.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,459 @@
1
+ from __future__ import annotations
2
+
3
+ import tkinter
4
+ from typing import overload, Any, Callable, Literal, TYPE_CHECKING
5
+
6
+ from bootstack.widgets._impl.composites.textarea.textarea import TextArea as _InternalTextArea
7
+ from bootstack.widgets._core.base import PublicWidgetBase, adapt_handler
8
+ from bootstack.widgets._core.events import register_widget_events, resolve_event
9
+ from bootstack.events import ChangeEvent, InputEvent, Subscription, TextModifiedEvent, ValidationEvent
10
+ from bootstack.streams import Stream
11
+ from bootstack.validation import RuleType
12
+ from bootstack.widgets.types import AccentToken, Event
13
+
14
+ if TYPE_CHECKING:
15
+ from bootstack.signals import Signal
16
+
17
+ # Events that fire on the inner tk.Text widget, not the outer frame.
18
+ _INNER_TEXT_SEQUENCES = frozenset({
19
+ "<FocusIn>",
20
+ "<FocusOut>",
21
+ "<<TextModified>>",
22
+ "<<TextUndo>>",
23
+ "<<TextRedo>>",
24
+ })
25
+
26
+ _TEXTAREA_EVENTS: dict[str, str] = {
27
+ "input": "<<Input>>",
28
+ "change": "<<Changed>>",
29
+ "valid": "<<Valid>>",
30
+ "invalid": "<<Invalid>>",
31
+ "validate": "<<Validate>>",
32
+ "focus": "<FocusIn>",
33
+ "blur": "<FocusOut>",
34
+ "modified": "<<TextModified>>",
35
+ "undo": "<<TextUndo>>",
36
+ "redo": "<<TextRedo>>",
37
+ }
38
+
39
+
40
+ class TextArea(PublicWidgetBase):
41
+ """A multi-line text input with optional label, placeholder, and scrollbars.
42
+
43
+ Args:
44
+ value: Initial text content.
45
+ textsignal: Reactive `Signal[str]` linked to the text content.
46
+ label: Label displayed above the field.
47
+ message: Hint text displayed below the field.
48
+ required: If True, field cannot be left empty.
49
+ placeholder: Placeholder text shown when the field is empty.
50
+ max_length: Maximum number of characters allowed.
51
+ read_only: If True, text is visible but not editable.
52
+ wrap: If True (default), long lines wrap at the widget boundary.
53
+ height: Visible row count. Default `4`.
54
+ width: Width in character units. Omit to let the widget fill its
55
+ container via layout.
56
+ scrollbars: Scrollbar visibility. Default `'auto'`. Horizontal
57
+ scrolling requires `wrap=False`.
58
+ font: Semantic font token. Default `'body'`. See
59
+ :doc:`/reference/typography`.
60
+ accent: Accent token applied to the focus border. Default `'primary'`.
61
+ show_border: If True (default), wraps the text area in a themed
62
+ border with a focus ring.
63
+ parent: Override the context-stack parent.
64
+ **kwargs: Layout placement options applied by the parent container —
65
+ `fill`, `expand`, `anchor`, `margin`, `row`, `column`, `sticky`.
66
+ See :doc:`/tasks/layout`.
67
+ """
68
+
69
+ def __init__(
70
+ self,
71
+ value: str = "",
72
+ *,
73
+ textsignal: "Signal[str] | None" = None,
74
+ label: str | None = None,
75
+ message: str | None = None,
76
+ required: bool = False,
77
+ placeholder: str | None = None,
78
+ max_length: int | None = None,
79
+ read_only: bool = False,
80
+ wrap: bool = True,
81
+ height: int = 4,
82
+ width: int | None = None,
83
+ scrollbars: Literal["auto", "vertical", "both", "none"] = "auto",
84
+ font: str = "body",
85
+ accent: AccentToken | str = "primary",
86
+ show_border: bool = True,
87
+ parent: Any = None,
88
+ **kwargs: Any,
89
+ ) -> None:
90
+ self._parent = self._resolve_parent(parent)
91
+ layout_kw = self._split_layout_kwargs(kwargs)
92
+
93
+ tk_master = self._parent._child_master() if self._parent else None
94
+
95
+ internal_kwargs: dict[str, Any] = {
96
+ "value": value,
97
+ "read_only": read_only,
98
+ "wrap": wrap,
99
+ "height": height,
100
+ "scrollbars": scrollbars,
101
+ **({"width": width} if width is not None else {}),
102
+ "show_border": show_border,
103
+ "font": font,
104
+ "accent": accent,
105
+ }
106
+ if textsignal is not None:
107
+ internal_kwargs["textsignal"] = textsignal
108
+ if label is not None:
109
+ internal_kwargs["label"] = label
110
+ if message is not None:
111
+ internal_kwargs["message"] = message
112
+ if required:
113
+ internal_kwargs["required"] = True
114
+ if placeholder is not None:
115
+ internal_kwargs["placeholder"] = placeholder
116
+ if max_length is not None:
117
+ internal_kwargs["max_length"] = max_length
118
+
119
+ self._internal = _InternalTextArea(tk_master, **internal_kwargs)
120
+ self._attach_to_parent(layout_kw)
121
+
122
+ # ----- Event routing -----
123
+
124
+ def _text_widget(self) -> tkinter.Misc:
125
+ return self._internal._core.text
126
+
127
+ @overload
128
+ def on(self, event: str) -> Stream: ...
129
+ @overload
130
+ def on(self, event: str, handler: Callable[[Event], Any]) -> Subscription: ...
131
+ def on(self, event: str, handler: Callable[[Event], Any] | None = None) -> Stream | Subscription:
132
+ """Register a callback for an event by name.
133
+
134
+ A generic, string-keyed escape hatch — prefer the typed `on_*`
135
+ shorthands (e.g. `on_change`), which carry the precise payload type.
136
+ Called with no handler, returns a composable `Stream`; with a handler,
137
+ binds it and returns a `Subscription`.
138
+
139
+ Args:
140
+ event: Event name (for example `'change'` or `'focus'`).
141
+ handler: Called with the event payload. Omit to get a composable
142
+ :class:`~bootstack.streams.Stream` instead.
143
+
144
+ Returns:
145
+ A cancellable :class:`~bootstack.events.Subscription` when a handler
146
+ is given, otherwise a :class:`~bootstack.streams.Stream`.
147
+ """
148
+ sequence = resolve_event(self, str(event))
149
+ target = self._text_widget() if sequence in _INNER_TEXT_SEQUENCES else self._internal
150
+ if handler is None:
151
+ def _source(h):
152
+ t = self._text_widget() if sequence in _INNER_TEXT_SEQUENCES else self._internal
153
+ bid = t.bind(sequence, adapt_handler(h), add="+")
154
+ return Subscription(t, sequence, bid)
155
+ return Stream(self._internal, _source=_source)
156
+ bid = target.bind(sequence, adapt_handler(handler), add="+")
157
+ return Subscription(target, sequence, bid)
158
+
159
+ # ----- Properties -----
160
+
161
+ @property
162
+ def value(self) -> str:
163
+ """The current text content."""
164
+ return self._internal.value
165
+
166
+ @value.setter
167
+ def value(self, v: str) -> None:
168
+ self._internal.value = v
169
+
170
+ @property
171
+ def text(self) -> str:
172
+ """The current display text. Same as `value` for a text area (no
173
+ formatting layer). Read-only — assign to `value` to change it."""
174
+ return self._internal.value
175
+
176
+ @property
177
+ def signal(self) -> "Signal[str] | None":
178
+ """The reactive `Signal` bound to this field, or `None`."""
179
+ return getattr(self._internal, "signal", None)
180
+
181
+ @property
182
+ def valid(self) -> "Signal[bool]":
183
+ """Reactive `Signal[bool]` — `True` when all validation rules pass.
184
+
185
+ Starts `True`. Updates after every validation run (blur or manual
186
+ `validate()` call). Subscribe a named handler to react immediately when
187
+ validity changes (a `lambda` cannot assign, so define a function):
188
+ `def on_valid(ok): btn.disabled = not ok` then
189
+ `area.valid.subscribe(on_valid)`.
190
+ """
191
+ return self._internal._valid_signal
192
+
193
+ @property
194
+ def error(self) -> "Signal[str]":
195
+ """Reactive `Signal[str]` — current validation error message.
196
+
197
+ Empty string when the field is valid. Updates in lockstep with `valid`.
198
+ """
199
+ return self._internal._error_signal
200
+
201
+ @property
202
+ def read_only(self) -> bool:
203
+ """Whether the text area is visible but not editable."""
204
+ return self._internal._core.read_only
205
+
206
+ @read_only.setter
207
+ def read_only(self, v: bool) -> None:
208
+ # Delegate to the core property so its `_read_only` flag stays in sync —
209
+ # the value/insert setters rely on it to apply programmatic writes.
210
+ self._internal._core.read_only = v
211
+
212
+ @property
213
+ def is_dirty(self) -> bool:
214
+ """True if the content has changed since the last `mark_saved()` call."""
215
+ return self._internal.is_dirty
216
+
217
+ # ----- Methods -----
218
+
219
+ def focus(self) -> None:
220
+ """Give keyboard focus to the text area."""
221
+ self._text_widget().focus_set()
222
+
223
+ def clear(self) -> None:
224
+ """Clear all text content."""
225
+ self._internal.value = ""
226
+
227
+ def validate(self) -> bool:
228
+ """Run validation rules against the current value.
229
+
230
+ Returns:
231
+ `True` if all rules pass, `False` otherwise.
232
+ """
233
+ return self._internal.validate()
234
+
235
+ def add_validation_rule(self, rule_type: RuleType, **kwargs: Any) -> None:
236
+ """Attach a validation rule to this field.
237
+
238
+ Args:
239
+ rule_type: The kind of validation rule to apply.
240
+ **kwargs: Rule options such as `message=`, `min=`, `max=`,
241
+ `trigger=`.
242
+ """
243
+ self._internal.add_validation_rule(rule_type, **kwargs)
244
+
245
+ def insert(self, text: str) -> None:
246
+ """Insert `text` at the cursor.
247
+
248
+ Read-only blocks *user* edits, not programmatic ones: this applies
249
+ even when `read_only=True`, leaving the area read-only afterward.
250
+
251
+ Args:
252
+ text: Text to insert at the current cursor position.
253
+ """
254
+ self._internal._core.insert("insert", text)
255
+
256
+ def append(self, text: str) -> None:
257
+ """Append `text` to the end of the content.
258
+
259
+ Applies even when `read_only=True`, leaving the area read-only
260
+ afterward.
261
+
262
+ Args:
263
+ text: Text to add at the end of the content.
264
+ """
265
+ self._internal._core.insert("end-1c", text)
266
+
267
+ def select_all(self) -> None:
268
+ """Select all text content."""
269
+ tw = self._internal._core.text
270
+ tw.focus_set()
271
+ tw.tag_add("sel", "1.0", "end-1c")
272
+ tw.mark_set("insert", "end-1c")
273
+
274
+ def mark_saved(self) -> None:
275
+ """Reset the dirty flag — call after saving content."""
276
+ self._internal.mark_saved()
277
+
278
+ def undo(self) -> None:
279
+ """Undo the last edit."""
280
+ self._internal.undo()
281
+
282
+ def redo(self) -> None:
283
+ """Redo the last undone edit."""
284
+ self._internal.redo()
285
+
286
+ # ----- Event shorthands -----
287
+
288
+ @overload
289
+ def on_input(self) -> Stream: ...
290
+ @overload
291
+ def on_input(self, handler: Callable[[InputEvent], Any]) -> Subscription: ...
292
+ def on_input(self, handler: Callable[[InputEvent], Any] | None = None) -> Stream | Subscription:
293
+ """Register a callback fired on every edit.
294
+
295
+ Args:
296
+ handler: Called with an :class:`~bootstack.events.InputEvent`. Omit to
297
+ get a composable :class:`~bootstack.streams.Stream` instead.
298
+
299
+ Returns:
300
+ A cancellable :class:`~bootstack.events.Subscription` when a
301
+ handler is given, otherwise a :class:`~bootstack.streams.Stream`.
302
+ """
303
+ return self.on("input", handler)
304
+
305
+ @overload
306
+ def on_change(self) -> Stream: ...
307
+ @overload
308
+ def on_change(self, handler: Callable[[ChangeEvent], Any]) -> Subscription: ...
309
+ def on_change(self, handler: Callable[[ChangeEvent], Any] | None = None) -> Stream | Subscription:
310
+ """Register a callback fired when the value is committed (on blur).
311
+
312
+ Args:
313
+ handler: Called with a :class:`~bootstack.events.ChangeEvent`. Omit to
314
+ get a composable :class:`~bootstack.streams.Stream` instead.
315
+
316
+ Returns:
317
+ A cancellable :class:`~bootstack.events.Subscription` when a
318
+ handler is given, otherwise a :class:`~bootstack.streams.Stream`.
319
+ """
320
+ return self.on("change", handler)
321
+
322
+ @overload
323
+ def on_focus(self) -> Stream: ...
324
+ @overload
325
+ def on_focus(self, handler: Callable[[Event], Any]) -> Subscription: ...
326
+ def on_focus(self, handler: Callable[[Event], Any] | None = None) -> Stream | Subscription:
327
+ """Register a callback fired when the text area gains focus.
328
+
329
+ Args:
330
+ handler: Called with an :class:`~bootstack.events.Event`. Omit to
331
+ get a composable :class:`~bootstack.streams.Stream` instead.
332
+
333
+ Returns:
334
+ A cancellable :class:`~bootstack.events.Subscription` when a
335
+ handler is given, otherwise a :class:`~bootstack.streams.Stream`.
336
+ """
337
+ return self.on("focus", handler)
338
+
339
+ @overload
340
+ def on_blur(self) -> Stream: ...
341
+ @overload
342
+ def on_blur(self, handler: Callable[[Event], Any]) -> Subscription: ...
343
+ def on_blur(self, handler: Callable[[Event], Any] | None = None) -> Stream | Subscription:
344
+ """Register a callback fired when the text area loses focus.
345
+
346
+ Args:
347
+ handler: Called with an :class:`~bootstack.events.Event`. Omit to
348
+ get a composable :class:`~bootstack.streams.Stream` instead.
349
+
350
+ Returns:
351
+ A cancellable :class:`~bootstack.events.Subscription` when a
352
+ handler is given, otherwise a :class:`~bootstack.streams.Stream`.
353
+ """
354
+ return self.on("blur", handler)
355
+
356
+ @overload
357
+ def on_valid(self) -> Stream: ...
358
+ @overload
359
+ def on_valid(self, handler: Callable[[ValidationEvent], Any]) -> Subscription: ...
360
+ def on_valid(self, handler: Callable[[ValidationEvent], Any] | None = None) -> Stream | Subscription:
361
+ """Register a callback fired when validation passes.
362
+
363
+ Args:
364
+ handler: Called with a :class:`~bootstack.events.ValidationEvent`. Omit to
365
+ get a composable :class:`~bootstack.streams.Stream` instead.
366
+
367
+ Returns:
368
+ A cancellable :class:`~bootstack.events.Subscription` when a
369
+ handler is given, otherwise a :class:`~bootstack.streams.Stream`.
370
+ """
371
+ return self.on("valid", handler)
372
+
373
+ @overload
374
+ def on_invalid(self) -> Stream: ...
375
+ @overload
376
+ def on_invalid(self, handler: Callable[[ValidationEvent], Any]) -> Subscription: ...
377
+ def on_invalid(self, handler: Callable[[ValidationEvent], Any] | None = None) -> Stream | Subscription:
378
+ """Register a callback fired when validation fails.
379
+
380
+ Args:
381
+ handler: Called with a :class:`~bootstack.events.ValidationEvent`. Omit to
382
+ get a composable :class:`~bootstack.streams.Stream` instead.
383
+
384
+ Returns:
385
+ A cancellable :class:`~bootstack.events.Subscription` when a
386
+ handler is given, otherwise a :class:`~bootstack.streams.Stream`.
387
+ """
388
+ return self.on("invalid", handler)
389
+
390
+ @overload
391
+ def on_validate(self) -> Stream: ...
392
+ @overload
393
+ def on_validate(self, handler: Callable[[ValidationEvent], Any]) -> Subscription: ...
394
+ def on_validate(self, handler: Callable[[ValidationEvent], Any] | None = None) -> Stream | Subscription:
395
+ """Register a callback fired after any validation run.
396
+
397
+ Args:
398
+ handler: Called with a :class:`~bootstack.events.ValidationEvent`. Omit to
399
+ get a composable :class:`~bootstack.streams.Stream` instead.
400
+
401
+ Returns:
402
+ A cancellable :class:`~bootstack.events.Subscription` when a
403
+ handler is given, otherwise a :class:`~bootstack.streams.Stream`.
404
+ """
405
+ return self.on("validate", handler)
406
+
407
+ @overload
408
+ def on_modified(self) -> Stream: ...
409
+ @overload
410
+ def on_modified(self, handler: Callable[[TextModifiedEvent], Any]) -> Subscription: ...
411
+ def on_modified(self, handler: Callable[[TextModifiedEvent], Any] | None = None) -> Stream | Subscription:
412
+ """Register a callback fired when the dirty state changes.
413
+
414
+ Args:
415
+ handler: Called with a :class:`~bootstack.events.TextModifiedEvent`. Omit to
416
+ get a composable :class:`~bootstack.streams.Stream` instead.
417
+
418
+ Returns:
419
+ A cancellable :class:`~bootstack.events.Subscription` when a
420
+ handler is given, otherwise a :class:`~bootstack.streams.Stream`.
421
+ """
422
+ return self.on("modified", handler)
423
+
424
+ @overload
425
+ def on_undo(self) -> Stream: ...
426
+ @overload
427
+ def on_undo(self, handler: Callable[[InputEvent], Any]) -> Subscription: ...
428
+ def on_undo(self, handler: Callable[[InputEvent], Any] | None = None) -> Stream | Subscription:
429
+ """Register a callback fired after an undo operation.
430
+
431
+ Args:
432
+ handler: Called with an :class:`~bootstack.events.InputEvent`. Omit to
433
+ get a composable :class:`~bootstack.streams.Stream` instead.
434
+
435
+ Returns:
436
+ A cancellable :class:`~bootstack.events.Subscription` when a
437
+ handler is given, otherwise a :class:`~bootstack.streams.Stream`.
438
+ """
439
+ return self.on("undo", handler)
440
+
441
+ @overload
442
+ def on_redo(self) -> Stream: ...
443
+ @overload
444
+ def on_redo(self, handler: Callable[[InputEvent], Any]) -> Subscription: ...
445
+ def on_redo(self, handler: Callable[[InputEvent], Any] | None = None) -> Stream | Subscription:
446
+ """Register a callback fired after a redo operation.
447
+
448
+ Args:
449
+ handler: Called with an :class:`~bootstack.events.InputEvent`. Omit to
450
+ get a composable :class:`~bootstack.streams.Stream` instead.
451
+
452
+ Returns:
453
+ A cancellable :class:`~bootstack.events.Subscription` when a
454
+ handler is given, otherwise a :class:`~bootstack.streams.Stream`.
455
+ """
456
+ return self.on("redo", handler)
457
+
458
+
459
+ register_widget_events(TextArea, _TEXTAREA_EVENTS)