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,425 @@
1
+ from __future__ import annotations
2
+
3
+ import tkinter
4
+ from typing import overload, Any, Callable, Literal
5
+
6
+ from bootstack.widgets._impl.composites.tabs.tabview import TabView as _InternalTabView
7
+ from bootstack.events import TabChangeEvent, TabCloseEvent, TabRef
8
+ from bootstack.widgets._impl.primitives.flexframe import FlexFrame
9
+ from bootstack.widgets._impl.primitives.gridframe import GridFrame
10
+ from bootstack.widgets._core.base import PublicWidgetBase, adapt_handler
11
+ from bootstack.widgets._core.container import (
12
+ GRID_KEYS, grid_sticky, place_flex_child, _reject_legacy_child_kwargs,
13
+ _expand_margin,
14
+ )
15
+ from bootstack.widgets._core.context import push_container, pop_container
16
+ from bootstack.widgets._core.events import register_widget_events, resolve_event
17
+ from bootstack.events import Subscription
18
+ from bootstack._core import NavigationError
19
+ from bootstack.streams import Stream
20
+ from bootstack.widgets.types import (
21
+ Event, AccentToken, Padding, LayoutKind, AutoFlow, Orient,
22
+ )
23
+
24
+ _TABS_EVENTS: dict[str, str] = {
25
+ "change": "<<TabChanged>>",
26
+ "tab_close": "<<TabClose>>",
27
+ "tab_add": "<<TabAdd>>",
28
+ }
29
+
30
+
31
+ class TabPage:
32
+ """A handle for one tab — both a layout context and a live controller.
33
+
34
+ Returned by `Tabs.add()` and by `Tabs.item()` / `items()`. Use it as a `with`
35
+ block to place child widgets, and read `key` / read or set `label`, or call
36
+ `select()` / `hide()` / `show()` / `remove()` to drive the tab afterward.
37
+
38
+ As a context manager it accepts the same layout kwargs as the standalone
39
+ layout containers — `layout=`, `gap=`, `horizontal_items=`, `vertical_items=`,
40
+ `grow_items=`, `columns=`, `rows=`, `auto_flow=`.
41
+ """
42
+
43
+ def __init__(
44
+ self,
45
+ page_widget: tkinter.Widget,
46
+ *,
47
+ key: str,
48
+ owner: "Tabs",
49
+ layout: LayoutKind = "column",
50
+ padding: Padding | None = None,
51
+ gap: int = 0,
52
+ horizontal_items: str | None = None,
53
+ vertical_items: str | None = None,
54
+ grow_items: bool = False,
55
+ columns: int | list[int | str] | None = None,
56
+ rows: int | list[int | str] | None = None,
57
+ auto_flow: AutoFlow = "row",
58
+ ) -> None:
59
+ self._page = page_widget
60
+ self._key = key
61
+ self._owner = owner
62
+ self._layout = layout
63
+
64
+ if horizontal_items is None:
65
+ horizontal_items = (
66
+ "stretch" if layout == "grid"
67
+ else "center" if layout == "column" else "left"
68
+ )
69
+ if vertical_items is None:
70
+ vertical_items = (
71
+ "stretch" if layout == "grid"
72
+ else "center" if layout == "row" else "top"
73
+ )
74
+
75
+ if layout in ("column", "row"):
76
+ self._layout_frame = FlexFrame(
77
+ page_widget,
78
+ direction="vertical" if layout == "column" else "horizontal",
79
+ padding=padding,
80
+ gap=gap,
81
+ horizontal_items=horizontal_items,
82
+ vertical_items=vertical_items,
83
+ grow_items=grow_items,
84
+ )
85
+ elif layout == "grid":
86
+ self._layout_frame = GridFrame(
87
+ page_widget,
88
+ columns=columns,
89
+ rows=rows,
90
+ padding=padding,
91
+ gap=gap,
92
+ auto_flow=auto_flow,
93
+ )
94
+ else:
95
+ raise ValueError(
96
+ f"TabPage layout must be 'column', 'row', or 'grid', got {layout!r}"
97
+ )
98
+
99
+ self._horizontal_items = horizontal_items
100
+ self._vertical_items = vertical_items
101
+ self._layout_frame.pack(fill="both", expand=True)
102
+
103
+ def _child_master(self) -> tkinter.Widget:
104
+ return self._layout_frame
105
+
106
+ def guide_layout(self, child: PublicWidgetBase, **layout_kw: Any) -> None:
107
+ if self._layout == "grid":
108
+ _reject_legacy_child_kwargs(layout_kw, "TabPage")
109
+ _expand_margin(layout_kw)
110
+ options = {k: v for k, v in layout_kw.items() if k in GRID_KEYS}
111
+ h = layout_kw.get("horizontal") or self._horizontal_items
112
+ v = layout_kw.get("vertical") or self._vertical_items
113
+ options["sticky"] = grid_sticky(h, v)
114
+ child._internal.grid(in_=self._child_master(), **options)
115
+ return
116
+ place_flex_child(self._layout_frame, child, layout_kw, "TabPage")
117
+
118
+ # ----- Tab identity, label, and control -----
119
+
120
+ @property
121
+ def key(self) -> str:
122
+ """The tab's unique key, used with `Tabs.item()` / `select()`."""
123
+ return self._key
124
+
125
+ @property
126
+ def label(self) -> str:
127
+ """The text shown on the tab. Assigning a new value relabels the tab."""
128
+ return self._owner._internal.configure_tab(self._key, "text")
129
+
130
+ @label.setter
131
+ def label(self, value: str) -> None:
132
+ self._owner._internal.configure_tab(self._key, text=value)
133
+
134
+ def select(self) -> None:
135
+ """Select (focus) this tab."""
136
+ self._owner.select(self._key)
137
+
138
+ def hide(self) -> None:
139
+ """Hide this tab without removing it. Restore with `show()`."""
140
+ self._owner.hide_tab(self._key)
141
+
142
+ def show(self) -> None:
143
+ """Restore this tab after it was hidden."""
144
+ self._owner.show_tab(self._key)
145
+
146
+ def remove(self) -> None:
147
+ """Remove this tab and its page entirely."""
148
+ self._owner.forget_tab(self._key)
149
+
150
+ def __enter__(self) -> "TabPage":
151
+ push_container(self)
152
+ return self
153
+
154
+ def __exit__(self, exc_type, exc, tb) -> None:
155
+ pop_container(self)
156
+
157
+
158
+ class Tabs(PublicWidgetBase):
159
+ """A tabbed container. Add pages with `.add()` and place children inside them.
160
+
161
+ Usage::
162
+
163
+ tabs = bs.Tabs()
164
+ with tabs.add("home", label="Home"):
165
+ bs.Label("Welcome")
166
+ with tabs.add("settings", label="Settings"):
167
+ bs.Label("Settings here")
168
+
169
+ Args:
170
+ orient: `'horizontal'` (default, tabs above content) or `'vertical'` (tabs left).
171
+ show_divider: Show a divider line between the tab bar and the page area.
172
+ tab_width: Fixed tab width in pixels, `'stretch'` to fill available space, or
173
+ `None` (default, size to content). When tabs exceed the strip they
174
+ scroll — no scrollbar, the wheel scrolls along the strip, and a
175
+ trailing chevron lists the off-screen tabs and scrolls the chosen one
176
+ into view (both orientations). `'stretch'` tabs always fit.
177
+ allow_close: Show close buttons on tabs. `True` = always, `False` = never,
178
+ `'hover'` = on hover. Defaults to `False`.
179
+ allow_add: Show an add-tab button that fires the `tab_add` event.
180
+ max_tabs: Maximum number of tabs. When reached, the add button is
181
+ disabled (and re-enabled when a tab is removed). `None` (default)
182
+ means no limit. Pairs with `allow_add`.
183
+ accent: Accent token for the tab bar. Defaults to the theme accent.
184
+ parent: Override the context-stack parent.
185
+ **kwargs: Layout placement options applied by the parent container —
186
+ `fill`, `expand`, `anchor`, `margin`, `row`, `column`, `sticky`.
187
+ See :doc:`/tasks/layout`.
188
+ """
189
+
190
+ def __init__(
191
+ self,
192
+ *,
193
+ orient: Orient = "horizontal",
194
+ show_divider: bool | None = None,
195
+ tab_width: int | Literal["stretch"] | None = None,
196
+ allow_close: bool | Literal["hover"] = False,
197
+ allow_add: bool = False,
198
+ max_tabs: int | None = None,
199
+ accent: AccentToken | str | None = None,
200
+ parent: Any = None,
201
+ **kwargs: Any,
202
+ ) -> None:
203
+ self._parent = self._resolve_parent(parent)
204
+ layout_kw = self._split_layout_kwargs(kwargs)
205
+
206
+ tk_master = self._parent._child_master() if self._parent else None
207
+
208
+ internal_kwargs: dict[str, Any] = {
209
+ "orient": orient,
210
+ "enable_closing": allow_close,
211
+ "enable_adding": allow_add,
212
+ "max_tabs": max_tabs,
213
+ }
214
+ if show_divider is not None:
215
+ internal_kwargs["show_divider"] = show_divider
216
+ if tab_width is not None:
217
+ internal_kwargs["tab_width"] = tab_width
218
+ if accent is not None:
219
+ internal_kwargs["accent"] = accent
220
+
221
+ self._pages: dict[str, TabPage] = {}
222
+ self._internal = _InternalTabView(tk_master, **internal_kwargs)
223
+ self._attach_to_parent(layout_kw)
224
+
225
+ # ----- Event routing -----
226
+
227
+ @overload
228
+ def on(self, event: str) -> Stream: ...
229
+ @overload
230
+ def on(self, event: str, handler: Callable[[Event], Any]) -> Subscription: ...
231
+ def on(self, event: str, handler: Callable[[Event], Any] | None = None) -> Stream | Subscription:
232
+ """Bind `handler` to `event` and return a `Subscription`."""
233
+ sequence = resolve_event(self, str(event))
234
+
235
+ if handler is None:
236
+ def _source(h):
237
+ bid = self._internal.bind(sequence, adapt_handler(h), add="+")
238
+ return Subscription(self._internal, sequence, bid)
239
+ return Stream(self._internal, _source=_source)
240
+
241
+ bind_id = self._internal.bind(sequence, adapt_handler(handler), add="+")
242
+ return Subscription(self._internal, sequence, bind_id)
243
+
244
+ # ----- Tab management -----
245
+
246
+ def add(
247
+ self,
248
+ key: str,
249
+ *,
250
+ label: str = "",
251
+ icon: str | None = None,
252
+ closable: bool | Literal["hover"] | None = None,
253
+ close_command: Callable[[], Any] | None = None,
254
+ layout: LayoutKind = "column",
255
+ padding: Padding | None = None,
256
+ gap: int = 0,
257
+ horizontal_items: str | None = None,
258
+ vertical_items: str | None = None,
259
+ grow_items: bool = False,
260
+ columns: int | list[int | str] | None = None,
261
+ rows: int | list[int | str] | None = None,
262
+ auto_flow: AutoFlow = "row",
263
+ ) -> TabPage:
264
+ """Add a tab and return a handle for placing its children and controlling it.
265
+
266
+ Args:
267
+ key: Unique identifier for the tab/page.
268
+ label: Label displayed on the tab.
269
+ icon: Icon name displayed on the tab.
270
+ closable: Close-button visibility for this tab. Overrides `allow_close`.
271
+ close_command: Called when the close button is clicked.
272
+ layout: Internal layout. Defaults to `'column'`.
273
+ padding: Space inside the page frame. Defaults to `None`.
274
+ gap: Space between children in pixels. Defaults to `0`.
275
+ horizontal_items: How children sit on the horizontal axis — edge
276
+ values `'left'`/`'center'`/`'right'`/`'stretch'`, plus `'space-*'`
277
+ when horizontal is the stacking axis. Defaults to `'stretch'` in grid mode,
278
+ `'center'` in a column and `'left'` in a row.
279
+ vertical_items: How children sit on the vertical axis — edge values
280
+ `'top'`/`'center'`/`'bottom'`/`'stretch'`, plus `'space-*'` when
281
+ vertical is the stacking axis. Defaults to `'stretch'` in grid mode,
282
+ `'center'` in a row and `'top'` in a column.
283
+ grow_items: For `'column'`/`'row'`, when `True` every child grows
284
+ equally to share the main axis. Defaults to `False`.
285
+ columns: Column definitions for `'grid'` layout. An integer sets
286
+ the number of equal-weight columns; a list sets per-column
287
+ weights or sizes (e.g. `[1, 2, 'auto', '120px']`).
288
+ rows: Row definitions for `'grid'` layout, same format as `columns`.
289
+ auto_flow: Grid auto-flow direction. Defaults to `'row'`.
290
+
291
+ Returns:
292
+ `TabPage` — use as a context manager to place children, and as a
293
+ handle to `select()`/`hide()`/`show()`/`remove()` the tab.
294
+ """
295
+ add_kwargs: dict[str, Any] = {}
296
+ if icon is not None:
297
+ add_kwargs["icon"] = icon
298
+ if closable is not None:
299
+ add_kwargs["closable"] = closable
300
+ if close_command is not None:
301
+ add_kwargs["close_command"] = close_command
302
+
303
+ page_widget = self._internal.add(key, text=label, **add_kwargs)
304
+ page = TabPage(
305
+ page_widget,
306
+ key=key, owner=self,
307
+ layout=layout, padding=padding, gap=gap,
308
+ horizontal_items=horizontal_items, vertical_items=vertical_items,
309
+ grow_items=grow_items,
310
+ columns=columns, rows=rows, auto_flow=auto_flow,
311
+ )
312
+ self._pages[key] = page
313
+ return page
314
+
315
+ def select(self, key: str) -> None:
316
+ """Select the tab identified by `key`.
317
+
318
+ Raises:
319
+ NavigationError: If no tab with the given key exists.
320
+ """
321
+ self._internal.select(key)
322
+
323
+ def hide_tab(self, key: str) -> None:
324
+ """Hide a tab without removing it. Restore with `show_tab()`.
325
+
326
+ Raises:
327
+ NavigationError: If no tab with the given key exists.
328
+ """
329
+ self._internal.hide_tab(key)
330
+
331
+ def show_tab(self, key: str) -> None:
332
+ """Restore a previously hidden tab.
333
+
334
+ Raises:
335
+ NavigationError: If no tab with the given key exists.
336
+ """
337
+ self._internal.show_tab(key)
338
+
339
+ def forget_tab(self, key: str) -> None:
340
+ """Remove a tab and its page entirely.
341
+
342
+ Raises:
343
+ NavigationError: If no tab with the given key exists.
344
+ """
345
+ self._internal.forget_tab(key)
346
+ self._pages.pop(key, None)
347
+
348
+ # ----- Properties / introspection -----
349
+
350
+ @property
351
+ def current(self) -> str | None:
352
+ """Key of the currently selected tab, or `None` if no tab is selected."""
353
+ return self._internal.current
354
+
355
+ def tab_keys(self) -> tuple[str, ...]:
356
+ """All tab keys in insertion order."""
357
+ return self._internal.tab_keys()
358
+
359
+ def page_keys(self) -> tuple[str, ...]:
360
+ """All page keys in insertion order."""
361
+ return self._internal.page_keys()
362
+
363
+ def item(self, key: str) -> TabPage:
364
+ """Return the tab handle for `key`.
365
+
366
+ Args:
367
+ key: Tab key assigned in `add()`.
368
+
369
+ Returns:
370
+ The `TabPage` for that key — read/set its `label` or call
371
+ `select()`/`hide()`/`show()`/`remove()`.
372
+
373
+ Raises:
374
+ NavigationError: If no tab with the given key exists.
375
+ """
376
+ if key not in self._pages:
377
+ raise NavigationError(f"No tab with key '{key}'")
378
+ return self._pages[key]
379
+
380
+ def items(self) -> tuple[TabPage, ...]:
381
+ """Return all tab handles in insertion order."""
382
+ return tuple(self._pages[k] for k in self._internal.tab_keys())
383
+
384
+ # ----- Event shorthands -----
385
+
386
+ @overload
387
+ def on_change(self) -> Stream: ...
388
+ @overload
389
+ def on_change(self, handler: Callable[[TabChangeEvent], Any]) -> Subscription: ...
390
+ def on_change(self, handler: Callable[[TabChangeEvent], Any] | None = None) -> Stream | Subscription:
391
+ """Register a callback fired when the selected tab changes.
392
+
393
+ Returns:
394
+ `Subscription` (with handler) or `Stream` (without handler).
395
+ """
396
+ return self.on("change", handler)
397
+
398
+ @overload
399
+ def on_tab_close(self) -> Stream: ...
400
+ @overload
401
+ def on_tab_close(self, handler: Callable[[TabCloseEvent], Any]) -> Subscription: ...
402
+ def on_tab_close(self, handler: Callable[[TabCloseEvent], Any] | None = None) -> Stream | Subscription:
403
+ """Register a callback fired when a tab's close button is clicked.
404
+
405
+ Returns:
406
+ `Subscription` (with handler) or `Stream` (without handler).
407
+ """
408
+ return self.on("tab_close", handler)
409
+
410
+ @overload
411
+ def on_tab_add(self) -> Stream: ...
412
+ @overload
413
+ def on_tab_add(self, handler: Callable[[Event], Any]) -> Subscription: ...
414
+ def on_tab_add(self, handler: Callable[[Event], Any] | None = None) -> Stream | Subscription:
415
+ """Register a callback fired when the add-tab button is clicked.
416
+
417
+ Returns:
418
+ `Subscription` (with handler) or `Stream` (without handler).
419
+ """
420
+ return self.on("tab_add", handler)
421
+
422
+
423
+ register_widget_events(Tabs, _TABS_EVENTS)
424
+
425
+ __all__ = ["Tabs", "TabPage", "TabChangeEvent", "TabRef"]