bootstack 0.1.4__tar.gz → 0.1.6__tar.gz

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 (490) hide show
  1. {bootstack-0.1.4/src/bootstack.egg-info → bootstack-0.1.6}/PKG-INFO +4 -5
  2. {bootstack-0.1.4 → bootstack-0.1.6}/README.md +3 -4
  3. {bootstack-0.1.4 → bootstack-0.1.6}/pyproject.toml +2 -2
  4. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/i18n/intl_format.py +7 -3
  5. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/validation/validation_rules.py +20 -2
  6. bootstack-0.1.6/src/bootstack/widgets/_core/kwargs.py +85 -0
  7. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_core/selection_group.py +7 -0
  8. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/_parts/numberentry_part.py +3 -2
  9. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/_parts/textentry_part.py +8 -2
  10. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/composites/dropdownbutton.py +15 -2
  11. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/composites/field.py +7 -2
  12. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/composites/form.py +71 -29
  13. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/composites/selectbox.py +89 -12
  14. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/primitives/checkbutton.py +14 -2
  15. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/boolean_controls.py +52 -25
  16. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/buttongroup.py +23 -9
  17. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/menubutton.py +4 -1
  18. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/passwordfield.py +3 -1
  19. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/pathfield.py +3 -1
  20. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/radiogroup.py +9 -2
  21. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/select.py +14 -3
  22. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/statusbar.py +5 -1
  23. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/textfield.py +3 -1
  24. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/togglegroup.py +9 -2
  25. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/toolbar.py +8 -3
  26. {bootstack-0.1.4 → bootstack-0.1.6/src/bootstack.egg-info}/PKG-INFO +4 -5
  27. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack.egg-info/SOURCES.txt +1 -0
  28. {bootstack-0.1.4 → bootstack-0.1.6}/tests/test_intl_format.py +25 -0
  29. {bootstack-0.1.4 → bootstack-0.1.6}/tests/test_validation_rules.py +61 -0
  30. {bootstack-0.1.4 → bootstack-0.1.6}/LICENSE +0 -0
  31. {bootstack-0.1.4 → bootstack-0.1.6}/MANIFEST.in +0 -0
  32. {bootstack-0.1.4 → bootstack-0.1.6}/NOTICE +0 -0
  33. {bootstack-0.1.4 → bootstack-0.1.6}/setup.cfg +0 -0
  34. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/__init__.py +0 -0
  35. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/__main__.py +0 -0
  36. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/_core/__init__.py +0 -0
  37. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/_core/capabilities/__init__.py +0 -0
  38. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/_core/capabilities/after.py +0 -0
  39. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/_core/capabilities/bind.py +0 -0
  40. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/_core/capabilities/bindtags.py +0 -0
  41. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/_core/capabilities/busy.py +0 -0
  42. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/_core/capabilities/clipboard.py +0 -0
  43. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/_core/capabilities/focus.py +0 -0
  44. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/_core/capabilities/grab.py +0 -0
  45. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/_core/capabilities/grid.py +0 -0
  46. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/_core/capabilities/localization.py +0 -0
  47. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/_core/capabilities/pack.py +0 -0
  48. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/_core/capabilities/place.py +0 -0
  49. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/_core/capabilities/selection.py +0 -0
  50. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/_core/capabilities/signals.py +0 -0
  51. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/_core/capabilities/winfo.py +0 -0
  52. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/_core/colorutils.py +0 -0
  53. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/_core/exceptions.py +0 -0
  54. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/_core/images.py +0 -0
  55. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/_core/mixins/__init__.py +0 -0
  56. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/_core/mixins/ttk_state.py +0 -0
  57. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/_core/mixins/widget.py +0 -0
  58. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/_core/paths.py +0 -0
  59. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/_core/publisher.py +0 -0
  60. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/_core/variables.py +0 -0
  61. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/_runtime/__init__.py +0 -0
  62. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/_runtime/app.py +0 -0
  63. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/_runtime/base_window.py +0 -0
  64. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/_runtime/events.py +0 -0
  65. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/_runtime/shortcuts.py +0 -0
  66. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/_runtime/tk_patch.py +0 -0
  67. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/_runtime/toplevel.py +0 -0
  68. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/_runtime/utility.py +0 -0
  69. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/_runtime/visual_focus.py +0 -0
  70. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/_runtime/window_utilities.py +0 -0
  71. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/assets/__init__.py +0 -0
  72. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/assets/bootstack.ico +0 -0
  73. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/assets/bootstack.png +0 -0
  74. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/assets/elements/__init__.py +0 -0
  75. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/assets/elements/badge-pill.png +0 -0
  76. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/assets/elements/badge-square.png +0 -0
  77. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/assets/elements/button-compact.png +0 -0
  78. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/assets/elements/button-default.png +0 -0
  79. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/assets/elements/buttongroup-after-h-compact.png +0 -0
  80. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/assets/elements/buttongroup-after-h-default.png +0 -0
  81. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/assets/elements/buttongroup-after-v-compact.png +0 -0
  82. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/assets/elements/buttongroup-after-v-default.png +0 -0
  83. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/assets/elements/buttongroup-before-h-compact.png +0 -0
  84. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/assets/elements/buttongroup-before-h-default.png +0 -0
  85. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/assets/elements/buttongroup-before-v-compact.png +0 -0
  86. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/assets/elements/buttongroup-before-v-default.png +0 -0
  87. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/assets/elements/buttongroup-center-h-compact.png +0 -0
  88. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/assets/elements/buttongroup-center-h-default.png +0 -0
  89. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/assets/elements/buttongroup-center-v-compact.png +0 -0
  90. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/assets/elements/buttongroup-center-v-default.png +0 -0
  91. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/assets/elements/card.png +0 -0
  92. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/assets/elements/checkbox-checked.png +0 -0
  93. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/assets/elements/checkbox-indeterminate.png +0 -0
  94. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/assets/elements/checkbox-unchecked.png +0 -0
  95. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/assets/elements/field.png +0 -0
  96. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/assets/elements/input-addon-compact.png +0 -0
  97. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/assets/elements/input-addon-default.png +0 -0
  98. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/assets/elements/input-compact.png +0 -0
  99. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/assets/elements/input-default.png +0 -0
  100. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/assets/elements/list-item-separated.png +0 -0
  101. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/assets/elements/list-item.png +0 -0
  102. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/assets/elements/listrow-compact.png +0 -0
  103. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/assets/elements/listrow-default.png +0 -0
  104. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/assets/elements/manifest.toml +0 -0
  105. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/assets/elements/menu-item.png +0 -0
  106. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/assets/elements/navitem-compact.png +0 -0
  107. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/assets/elements/navitem-default.png +0 -0
  108. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/assets/elements/progressbar-h-compact.png +0 -0
  109. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/assets/elements/progressbar-h-default.png +0 -0
  110. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/assets/elements/progressbar-v-compact.png +0 -0
  111. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/assets/elements/progressbar-v-default.png +0 -0
  112. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/assets/elements/radiobutton.png +0 -0
  113. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/assets/elements/scrollbar-horizontal.png +0 -0
  114. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/assets/elements/scrollbar-vertical.png +0 -0
  115. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/assets/elements/slider-handle.png +0 -0
  116. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/assets/elements/slider-track-h.png +0 -0
  117. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/assets/elements/slider-track-v.png +0 -0
  118. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/assets/elements/switch-off.png +0 -0
  119. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/assets/elements/switch-on.png +0 -0
  120. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/assets/elements/tab-h.png +0 -0
  121. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/assets/elements/tab-v.png +0 -0
  122. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/assets/icons/bootstrap.ttf +0 -0
  123. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/assets/icons/glyphmap.json +0 -0
  124. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/assets/icons/icon_metrics.json +0 -0
  125. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/assets/locales/ar/LC_MESSAGES/bootstack.mo +0 -0
  126. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/assets/locales/ar/LC_MESSAGES/bootstack.po +0 -0
  127. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/assets/locales/bg/LC_MESSAGES/bootstack.mo +0 -0
  128. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/assets/locales/bg/LC_MESSAGES/bootstack.po +0 -0
  129. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/assets/locales/cs/LC_MESSAGES/bootstack.mo +0 -0
  130. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/assets/locales/cs/LC_MESSAGES/bootstack.po +0 -0
  131. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/assets/locales/da/LC_MESSAGES/bootstack.mo +0 -0
  132. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/assets/locales/da/LC_MESSAGES/bootstack.po +0 -0
  133. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/assets/locales/de/LC_MESSAGES/bootstack.mo +0 -0
  134. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/assets/locales/de/LC_MESSAGES/bootstack.po +0 -0
  135. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/assets/locales/en/LC_MESSAGES/bootstack.mo +0 -0
  136. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/assets/locales/en/LC_MESSAGES/bootstack.po +0 -0
  137. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/assets/locales/es/LC_MESSAGES/bootstack.mo +0 -0
  138. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/assets/locales/es/LC_MESSAGES/bootstack.po +0 -0
  139. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/assets/locales/fr/LC_MESSAGES/bootstack.mo +0 -0
  140. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/assets/locales/fr/LC_MESSAGES/bootstack.po +0 -0
  141. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/assets/locales/he/LC_MESSAGES/bootstack.mo +0 -0
  142. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/assets/locales/he/LC_MESSAGES/bootstack.po +0 -0
  143. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/assets/locales/hi/LC_MESSAGES/bootstack.mo +0 -0
  144. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/assets/locales/hi/LC_MESSAGES/bootstack.po +0 -0
  145. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/assets/locales/it/LC_MESSAGES/bootstack.mo +0 -0
  146. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/assets/locales/it/LC_MESSAGES/bootstack.po +0 -0
  147. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/assets/locales/ja/LC_MESSAGES/bootstack.mo +0 -0
  148. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/assets/locales/ja/LC_MESSAGES/bootstack.po +0 -0
  149. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/assets/locales/ko/LC_MESSAGES/bootstack.mo +0 -0
  150. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/assets/locales/ko/LC_MESSAGES/bootstack.po +0 -0
  151. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/assets/locales/nb/LC_MESSAGES/bootstack.mo +0 -0
  152. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/assets/locales/nb/LC_MESSAGES/bootstack.po +0 -0
  153. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/assets/locales/nl/LC_MESSAGES/bootstack.mo +0 -0
  154. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/assets/locales/nl/LC_MESSAGES/bootstack.po +0 -0
  155. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/assets/locales/pl/LC_MESSAGES/bootstack.mo +0 -0
  156. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/assets/locales/pl/LC_MESSAGES/bootstack.po +0 -0
  157. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/assets/locales/pt/LC_MESSAGES/bootstack.mo +0 -0
  158. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/assets/locales/pt/LC_MESSAGES/bootstack.po +0 -0
  159. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/assets/locales/pt_BR/LC_MESSAGES/bootstack.mo +0 -0
  160. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/assets/locales/pt_BR/LC_MESSAGES/bootstack.po +0 -0
  161. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/assets/locales/sl/LC_MESSAGES/bootstack.mo +0 -0
  162. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/assets/locales/sl/LC_MESSAGES/bootstack.po +0 -0
  163. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/assets/locales/sv/LC_MESSAGES/bootstack.mo +0 -0
  164. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/assets/locales/sv/LC_MESSAGES/bootstack.po +0 -0
  165. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/assets/locales/tr/LC_MESSAGES/bootstack.mo +0 -0
  166. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/assets/locales/tr/LC_MESSAGES/bootstack.po +0 -0
  167. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/assets/locales/zh_CN/LC_MESSAGES/bootstack.mo +0 -0
  168. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/assets/locales/zh_CN/LC_MESSAGES/bootstack.po +0 -0
  169. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/assets/locales/zh_TW/LC_MESSAGES/bootstack.mo +0 -0
  170. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/assets/locales/zh_TW/LC_MESSAGES/bootstack.po +0 -0
  171. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/cli/__init__.py +0 -0
  172. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/cli/__main__.py +0 -0
  173. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/cli/add.py +0 -0
  174. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/cli/appicon.py +0 -0
  175. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/cli/build.py +0 -0
  176. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/cli/config.py +0 -0
  177. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/cli/demo.py +0 -0
  178. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/cli/dev.py +0 -0
  179. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/cli/doctor.py +0 -0
  180. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/cli/icons.py +0 -0
  181. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/cli/promote.py +0 -0
  182. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/cli/pyinstaller.py +0 -0
  183. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/cli/run.py +0 -0
  184. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/cli/start.py +0 -0
  185. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/cli/templates/__init__.py +0 -0
  186. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/clipboard.py +0 -0
  187. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/constants.py +0 -0
  188. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/data/README.md +0 -0
  189. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/data/__init__.py +0 -0
  190. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/data/_observable.py +0 -0
  191. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/data/base.py +0 -0
  192. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/data/file_source.py +0 -0
  193. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/data/memory_source.py +0 -0
  194. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/data/query.py +0 -0
  195. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/data/readers.py +0 -0
  196. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/data/sqlite_source.py +0 -0
  197. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/data/types.py +0 -0
  198. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/data/writers.py +0 -0
  199. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/dev/__init__.py +0 -0
  200. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/dev/_capture.py +0 -0
  201. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/dev/_env.py +0 -0
  202. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/dev/_registry.py +0 -0
  203. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/dev/_reloader.py +0 -0
  204. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/dev/_reset.py +0 -0
  205. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/dev/_watcher.py +0 -0
  206. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/dialogs/__init__.py +0 -0
  207. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/dialogs/_impl/__init__.py +0 -0
  208. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/dialogs/_impl/colorchooser.py +0 -0
  209. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/dialogs/_impl/datedialog.py +0 -0
  210. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/dialogs/_impl/dialog.py +0 -0
  211. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/dialogs/_impl/filterdialog.py +0 -0
  212. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/dialogs/_impl/fontdialog.py +0 -0
  213. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/dialogs/_impl/formdialog.py +0 -0
  214. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/dialogs/_impl/message.py +0 -0
  215. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/dialogs/_impl/query.py +0 -0
  216. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/errors.py +0 -0
  217. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/events/__init__.py +0 -0
  218. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/events/_event.py +0 -0
  219. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/events/_payloads.py +0 -0
  220. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/events/_subscription.py +0 -0
  221. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/i18n/README.md +0 -0
  222. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/i18n/__init__.py +0 -0
  223. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/i18n/catalog.py +0 -0
  224. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/i18n/msgcat.py +0 -0
  225. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/i18n/specs.py +0 -0
  226. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/images.py +0 -0
  227. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/py.typed +0 -0
  228. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/scheduling/__init__.py +0 -0
  229. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/scheduling/_schedule.py +0 -0
  230. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/shortcuts.py +0 -0
  231. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/signals/README.md +0 -0
  232. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/signals/__init__.py +0 -0
  233. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/signals/integration.py +0 -0
  234. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/signals/signal.py +0 -0
  235. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/signals/types.py +0 -0
  236. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/store.py +0 -0
  237. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/streams/__init__.py +0 -0
  238. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/streams/_stream.py +0 -0
  239. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/style/__init__.py +0 -0
  240. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/style/builders/__init__.py +0 -0
  241. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/style/builders/badge.py +0 -0
  242. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/style/builders/button.py +0 -0
  243. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/style/builders/buttongroup.py +0 -0
  244. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/style/builders/calendar.py +0 -0
  245. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/style/builders/checkbutton.py +0 -0
  246. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/style/builders/combobox.py +0 -0
  247. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/style/builders/contextmenu.py +0 -0
  248. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/style/builders/entry.py +0 -0
  249. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/style/builders/expander.py +0 -0
  250. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/style/builders/field.py +0 -0
  251. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/style/builders/frame.py +0 -0
  252. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/style/builders/label.py +0 -0
  253. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/style/builders/labelframe.py +0 -0
  254. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/style/builders/listview.py +0 -0
  255. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/style/builders/menubar.py +0 -0
  256. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/style/builders/menubutton.py +0 -0
  257. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/style/builders/panedwindow.py +0 -0
  258. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/style/builders/progressbar.py +0 -0
  259. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/style/builders/radiobutton.py +0 -0
  260. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/style/builders/scale.py +0 -0
  261. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/style/builders/scrollbar.py +0 -0
  262. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/style/builders/separator.py +0 -0
  263. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/style/builders/sidenav.py +0 -0
  264. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/style/builders/sizegrip.py +0 -0
  265. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/style/builders/spinbox.py +0 -0
  266. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/style/builders/switch.py +0 -0
  267. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/style/builders/tabitem.py +0 -0
  268. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/style/builders/togglegroup.py +0 -0
  269. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/style/builders/toolbutton.py +0 -0
  270. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/style/builders/tooltip.py +0 -0
  271. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/style/builders/treeview.py +0 -0
  272. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/style/builders/utils.py +0 -0
  273. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/style/builders_tk/__init__.py +0 -0
  274. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/style/builders_tk/defaults.py +0 -0
  275. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/style/element.py +0 -0
  276. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/style/fonts.py +0 -0
  277. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/style/style.py +0 -0
  278. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/style/style_builder_base.py +0 -0
  279. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/style/style_builder_mixed.py +0 -0
  280. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/style/style_builder_tk.py +0 -0
  281. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/style/style_builder_ttk.py +0 -0
  282. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/style/style_resolver.py +0 -0
  283. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/style/theme.py +0 -0
  284. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/style/theme_provider.py +0 -0
  285. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/style/themes/__init__.py +0 -0
  286. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/style/tk_patch.py +0 -0
  287. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/style/token_maps.py +0 -0
  288. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/style/types.py +0 -0
  289. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/style/typography.py +0 -0
  290. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/style/utility.py +0 -0
  291. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/types.py +0 -0
  292. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/validation/__init__.py +0 -0
  293. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/validation/types.py +0 -0
  294. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/validation/validation_result.py +0 -0
  295. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/__init__.py +0 -0
  296. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_core/__init__.py +0 -0
  297. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_core/app_config.py +0 -0
  298. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_core/base.py +0 -0
  299. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_core/container.py +0 -0
  300. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_core/context.py +0 -0
  301. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_core/events.py +0 -0
  302. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_core/field_mixin.py +0 -0
  303. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_core/icon_image_props.py +0 -0
  304. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_core/image_binding.py +0 -0
  305. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_core/navmodel.py +0 -0
  306. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_core/options.py +0 -0
  307. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_core/window_controls.py +0 -0
  308. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_core/window_menu.py +0 -0
  309. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/__init__.py +0 -0
  310. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/_internal/__init__.py +0 -0
  311. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/_internal/wrapper_base.py +0 -0
  312. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/_parts/__init__.py +0 -0
  313. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/_parts/spinnerentry_part.py +0 -0
  314. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/composites/__init__.py +0 -0
  315. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/composites/_dateutils.py +0 -0
  316. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/composites/_image_fit.py +0 -0
  317. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/composites/accordion.py +0 -0
  318. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/composites/avatar.py +0 -0
  319. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/composites/buttongroup.py +0 -0
  320. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/composites/calendar.py +0 -0
  321. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/composites/carousel.py +0 -0
  322. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/composites/chart.py +0 -0
  323. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/composites/compositeframe.py +0 -0
  324. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/composites/contextmenu.py +0 -0
  325. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/composites/dateentry.py +0 -0
  326. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/composites/expander.py +0 -0
  327. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/composites/gallery.py +0 -0
  328. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/composites/list/__init__.py +0 -0
  329. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/composites/list/listitem.py +0 -0
  330. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/composites/list/listview.py +0 -0
  331. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/composites/menu/__init__.py +0 -0
  332. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/composites/menu/model.py +0 -0
  333. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/composites/menu/render_native.py +0 -0
  334. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/composites/menu/render_themed.py +0 -0
  335. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/composites/meter.py +0 -0
  336. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/composites/numericentry.py +0 -0
  337. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/composites/pagestack.py +0 -0
  338. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/composites/passwordentry.py +0 -0
  339. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/composites/pathentry.py +0 -0
  340. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/composites/picture.py +0 -0
  341. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/composites/radiogroup.py +0 -0
  342. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/composites/scrolledtext.py +0 -0
  343. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/composites/scrolledtext.pyi +0 -0
  344. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/composites/scrollview.py +0 -0
  345. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/composites/shell/__init__.py +0 -0
  346. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/composites/shell/content_host.py +0 -0
  347. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/composites/shell/layout.py +0 -0
  348. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/composites/shell/nav_panel.py +0 -0
  349. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/composites/shell/providers.py +0 -0
  350. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/composites/shell/rail.py +0 -0
  351. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/composites/shell/shell.py +0 -0
  352. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/composites/shell/workspace.py +0 -0
  353. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/composites/sidenav/__init__.py +0 -0
  354. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/composites/sidenav/header.py +0 -0
  355. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/composites/sidenav/separator.py +0 -0
  356. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/composites/slider/__init__.py +0 -0
  357. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/composites/slider/_shared.py +0 -0
  358. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/composites/slider/rangeslider.py +0 -0
  359. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/composites/slider/slider.py +0 -0
  360. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/composites/spinnerentry.py +0 -0
  361. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/composites/tableview/__init__.py +0 -0
  362. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/composites/tableview/tableview.py +0 -0
  363. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/composites/tableview/types.py +0 -0
  364. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/composites/tabs/__init__.py +0 -0
  365. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/composites/tabs/tabitem.py +0 -0
  366. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/composites/tabs/tabs.py +0 -0
  367. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/composites/tabs/tabview.py +0 -0
  368. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/composites/textarea/__init__.py +0 -0
  369. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/composites/textarea/change.py +0 -0
  370. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/composites/textarea/codeeditor.py +0 -0
  371. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/composites/textarea/core.py +0 -0
  372. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/composites/textarea/decoration.py +0 -0
  373. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/composites/textarea/diff.py +0 -0
  374. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/composites/textarea/extensions/__init__.py +0 -0
  375. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/composites/textarea/extensions/bracket_matcher.py +0 -0
  376. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/composites/textarea/extensions/indent_guides.py +0 -0
  377. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/composites/textarea/extensions/line_numbers.py +0 -0
  378. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/composites/textarea/extensions/pygments_highlighter.py +0 -0
  379. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/composites/textarea/extensions/smart_indent.py +0 -0
  380. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/composites/textarea/filter.py +0 -0
  381. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/composites/textarea/search_overlay.py +0 -0
  382. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/composites/textarea/sidebar.py +0 -0
  383. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/composites/textarea/style_registry.py +0 -0
  384. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/composites/textarea/textarea.py +0 -0
  385. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/composites/textarea/undo.py +0 -0
  386. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/composites/textentry.py +0 -0
  387. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/composites/timeentry.py +0 -0
  388. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/composites/toast.py +0 -0
  389. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/composites/toast_stack.py +0 -0
  390. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/composites/togglegroup.py +0 -0
  391. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/composites/toolbar.py +0 -0
  392. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/composites/tooltip.py +0 -0
  393. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/composites/tree/__init__.py +0 -0
  394. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/composites/tree/source_binding.py +0 -0
  395. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/composites/tree/treeitem.py +0 -0
  396. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/composites/tree/treenode.py +0 -0
  397. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/composites/tree/treeview.py +0 -0
  398. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/mixins/__init__.py +0 -0
  399. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/mixins/configure_mixin.py +0 -0
  400. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/mixins/entry_mixin.py +0 -0
  401. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/mixins/font_mixin.py +0 -0
  402. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/mixins/icon_mixin.py +0 -0
  403. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/mixins/localization_mixin.py +0 -0
  404. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/mixins/signal_mixin.py +0 -0
  405. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/mixins/validation_mixin.py +0 -0
  406. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/primitives/__init__.py +0 -0
  407. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/primitives/_menubutton.py +0 -0
  408. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/primitives/badge.py +0 -0
  409. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/primitives/button.py +0 -0
  410. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/primitives/card.py +0 -0
  411. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/primitives/checktoggle.py +0 -0
  412. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/primitives/combobox.py +0 -0
  413. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/primitives/entry.py +0 -0
  414. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/primitives/flexframe.py +0 -0
  415. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/primitives/frame.py +0 -0
  416. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/primitives/gridframe.py +0 -0
  417. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/primitives/label.py +0 -0
  418. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/primitives/labelframe.py +0 -0
  419. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/primitives/optionmenu.py +0 -0
  420. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/primitives/packframe.py +0 -0
  421. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/primitives/panedwindow.py +0 -0
  422. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/primitives/progressbar.py +0 -0
  423. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/primitives/radiobutton.py +0 -0
  424. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/primitives/radiotoggle.py +0 -0
  425. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/primitives/scrollbar.py +0 -0
  426. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/primitives/separator.py +0 -0
  427. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/primitives/sizegrip.py +0 -0
  428. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/primitives/spinbox.py +0 -0
  429. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/primitives/switch.py +0 -0
  430. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/_impl/primitives/treeview.py +0 -0
  431. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/app.py +0 -0
  432. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/appshell.py +0 -0
  433. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/avatar.py +0 -0
  434. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/button.py +0 -0
  435. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/calendar.py +0 -0
  436. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/card.py +0 -0
  437. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/carousel.py +0 -0
  438. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/chart.py +0 -0
  439. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/codeeditor.py +0 -0
  440. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/contextmenu.py +0 -0
  441. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/datatable.py +0 -0
  442. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/datefield.py +0 -0
  443. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/divider.py +0 -0
  444. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/expander.py +0 -0
  445. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/form.py +0 -0
  446. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/gallery.py +0 -0
  447. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/gauge.py +0 -0
  448. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/grid.py +0 -0
  449. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/groupbox.py +0 -0
  450. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/label.py +0 -0
  451. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/listview.py +0 -0
  452. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/numberfield.py +0 -0
  453. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/pagestack.py +0 -0
  454. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/picture.py +0 -0
  455. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/progressbar.py +0 -0
  456. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/radio_variants.py +0 -0
  457. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/scrollbar.py +0 -0
  458. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/scrollview.py +0 -0
  459. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/selectbutton.py +0 -0
  460. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/sidebar_toggle.py +0 -0
  461. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/sizegrip.py +0 -0
  462. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/slider.py +0 -0
  463. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/spinbox.py +0 -0
  464. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/spinnerfield.py +0 -0
  465. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/splash.py +0 -0
  466. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/splitview.py +0 -0
  467. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/stacks.py +0 -0
  468. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/tabs.py +0 -0
  469. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/textarea.py +0 -0
  470. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/theme_toggle.py +0 -0
  471. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/timefield.py +0 -0
  472. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/toast.py +0 -0
  473. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/tooltip.py +0 -0
  474. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/tree.py +0 -0
  475. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/types.py +0 -0
  476. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack/widgets/window.py +0 -0
  477. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack.egg-info/dependency_links.txt +0 -0
  478. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack.egg-info/entry_points.txt +0 -0
  479. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack.egg-info/requires.txt +0 -0
  480. {bootstack-0.1.4 → bootstack-0.1.6}/src/bootstack.egg-info/top_level.txt +0 -0
  481. {bootstack-0.1.4 → bootstack-0.1.6}/tests/test_dialog_anchor.py +0 -0
  482. {bootstack-0.1.4 → bootstack-0.1.6}/tests/test_events_doc_coverage.py +0 -0
  483. {bootstack-0.1.4 → bootstack-0.1.6}/tests/test_hot_reload.py +0 -0
  484. {bootstack-0.1.4 → bootstack-0.1.6}/tests/test_images.py +0 -0
  485. {bootstack-0.1.4 → bootstack-0.1.6}/tests/test_images_gui.py +0 -0
  486. {bootstack-0.1.4 → bootstack-0.1.6}/tests/test_navmodel.py +0 -0
  487. {bootstack-0.1.4 → bootstack-0.1.6}/tests/test_on_color_contrast.py +0 -0
  488. {bootstack-0.1.4 → bootstack-0.1.6}/tests/test_public_surface.py +0 -0
  489. {bootstack-0.1.4 → bootstack-0.1.6}/tests/test_store.py +0 -0
  490. {bootstack-0.1.4 → bootstack-0.1.6}/tests/test_theme_from_existing.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: bootstack
3
- Version: 0.1.4
3
+ Version: 0.1.6
4
4
  Summary: Build desktop GUI apps in pure Python and ship them as a standalone executable — built on Tk, no Tkinter boilerplate.
5
5
  Author-email: Israel Dryer <israel.dryer@gmail.com>
6
6
  License-Expression: MIT
@@ -66,10 +66,9 @@ Dynamic: license-file
66
66
 
67
67
  ### Desktop apps in pure Python — Tk underneath, none of the boilerplate.
68
68
 
69
- bootstack is built on Tk, so the install is light, there's no Qt license, and
70
- your app ships as a small standalone executable. But you'll never write a
71
- `StringVar` or call `.pack()` — the API is its own. 60+ widgets, reactive state,
72
- and a CLI that scaffolds and packages the whole thing.
69
+ bootstack is built on Tk, so the install is light and your app ships as a small standalone executable. But you'll never
70
+ write a `StringVar` or call `.pack()` the API is its own. 60+ widgets, reactive state, and a CLI that scaffolds and
71
+ packages the whole thing.
73
72
 
74
73
  <p align="center">
75
74
  <picture>
@@ -13,10 +13,9 @@
13
13
 
14
14
  ### Desktop apps in pure Python — Tk underneath, none of the boilerplate.
15
15
 
16
- bootstack is built on Tk, so the install is light, there's no Qt license, and
17
- your app ships as a small standalone executable. But you'll never write a
18
- `StringVar` or call `.pack()` — the API is its own. 60+ widgets, reactive state,
19
- and a CLI that scaffolds and packages the whole thing.
16
+ bootstack is built on Tk, so the install is light and your app ships as a small standalone executable. But you'll never
17
+ write a `StringVar` or call `.pack()` the API is its own. 60+ widgets, reactive state, and a CLI that scaffolds and
18
+ packages the whole thing.
20
19
 
21
20
  <p align="center">
22
21
  <picture>
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "bootstack"
7
- version = "0.1.4"
7
+ version = "0.1.6"
8
8
  description = "Build desktop GUI apps in pure Python and ship them as a standalone executable — built on Tk, no Tkinter boilerplate."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.12"
@@ -114,7 +114,7 @@ where = ["src"]
114
114
  ]
115
115
 
116
116
  [tool.bumpversion]
117
- current_version = "0.1.4"
117
+ current_version = "0.1.6"
118
118
  parse = "(?P<major>\\d+)\\.(?P<minor>\\d+)\\.(?P<patch>\\d+)((?P<pre>a|b|rc)(?P<pre_n>\\d+))?"
119
119
  serialize = [
120
120
  "{major}.{minor}.{patch}{pre}{pre_n}",
@@ -12,6 +12,7 @@ import locale
12
12
  import re
13
13
  import warnings
14
14
  from dataclasses import dataclass
15
+ from decimal import Decimal
15
16
  from datetime import date, datetime, time
16
17
  from typing import Any, Literal, Mapping, Optional, TypedDict, Union, cast
17
18
 
@@ -148,7 +149,10 @@ SUFFIXES_EN = (
148
149
  Suffix(1_000, "K"),
149
150
  )
150
151
  _SUFFIX_TO_FACTOR = {"K": 1_000, "M": 1_000_000, "B": 1_000_000_000, "T": 1_000_000_000_000}
151
- _NUMBERISH = (int, float)
152
+ # Values formatted as numbers. `Decimal` is passed to Babel as-is rather than
153
+ # coerced: Babel formats it natively, and going through `float` would round
154
+ # away the precision a caller chose `Decimal` to keep.
155
+ _NUMBERISH = (int, float, Decimal)
152
156
 
153
157
 
154
158
  def _locale_to_languages(loc: str) -> list[str]:
@@ -208,7 +212,7 @@ class IntlFormatter:
208
212
  if value is None:
209
213
  return ""
210
214
  if isinstance(value, _NUMBERISH):
211
- return self._format_number(float(value), spec)
215
+ return self._format_number(value if isinstance(value, Decimal) else float(value), spec)
212
216
  if isinstance(value, datetime):
213
217
  return self._format_datetime(value, spec)
214
218
  if isinstance(value, date):
@@ -238,7 +242,7 @@ class IntlFormatter:
238
242
  return self._parse_temporal(s, spec)
239
243
 
240
244
  # ---------- Numbers ----------
241
- def _format_number(self, x: float, spec: LooseSpec) -> str:
245
+ def _format_number(self, x: float | Decimal, spec: LooseSpec) -> str:
242
246
  opt = self._normalize_number_spec(spec)
243
247
 
244
248
  if opt["type"] == "custom":
@@ -33,6 +33,16 @@ def rule_applies_to_kind(rule_type: str, kind: str) -> bool:
33
33
  return True
34
34
 
35
35
 
36
+ def _is_empty(value: object) -> bool:
37
+ """Whether a field holds nothing, for rules that only shape a value.
38
+
39
+ Matches the emptiness test `range` uses: `None` or the empty string. A
40
+ whitespace-only entry is real input — `stringLength` should still measure
41
+ it — so only `required` treats blank text as absent.
42
+ """
43
+ return value is None or value == ""
44
+
45
+
36
46
  def _as_text(value: object) -> str:
37
47
  """Coerce a value to text for the string rules.
38
48
 
@@ -104,7 +114,15 @@ class ValidationRule:
104
114
  # Everything else is valid (non-empty string, number, date, etc.)
105
115
  return ValidationResult(True, "")
106
116
 
107
- elif self.type == "email":
117
+ # A rule other than `required` describes what a value must look like,
118
+ # not that one must be present. An untouched optional field has nothing
119
+ # to check, so it passes — otherwise leaving it blank would block a
120
+ # submit with no way forward. Use `required` for presence, the same
121
+ # contract `range` states below.
122
+ if self.type in TEXT_RULES and _is_empty(value):
123
+ return ValidationResult(True, "")
124
+
125
+ if self.type == "email":
108
126
  if not re.match(r"[^@]+@[^@]+\.[^@]+", _as_text(value)):
109
127
  return ValidationResult(False, msg)
110
128
  elif self.type == "stringLength":
@@ -119,7 +137,7 @@ class ValidationRule:
119
137
  elif self.type == "range":
120
138
  # Bounds on an ordered value (number/date/time). An empty field is
121
139
  # not out of range — use 'required' for presence.
122
- if value is None or value == "":
140
+ if _is_empty(value):
123
141
  return ValidationResult(True)
124
142
  lo = self.params.get("min")
125
143
  hi = self.params.get("max")
@@ -0,0 +1,85 @@
1
+ """Merging a caller's options dict over framework-built keyword arguments.
2
+
3
+ Several widgets accept a bag of options aimed at a widget they build for you —
4
+ `Form`'s `editor_options`, `MenuButton`'s `menu_options`, the keyword
5
+ passthrough on `ButtonGroup.add` / `RadioGroup.add` / `Toolbar.add_widget`.
6
+ Those bags name the built widget's own public keyword arguments, so a caller
7
+ may name a parameter the framework also fills.
8
+
9
+ Splatting both into one call raises `TypeError: got multiple values for
10
+ keyword argument`, which names an internal class the caller never wrote.
11
+ `merge_kwargs` gives that meeting point one rule instead:
12
+
13
+ - The caller's options WIN over the framework's defaults. Naming a parameter
14
+ the framework also fills is how you override it.
15
+ - A short list of keys is structural — the widget cannot do its job if they
16
+ are replaced (it would be parented elsewhere, or lose the command that emits
17
+ its events). Supplying one raises `BootstackError` naming the API you called
18
+ and what to use instead.
19
+ """
20
+ from __future__ import annotations
21
+
22
+ from typing import Any, Mapping
23
+
24
+ from bootstack.errors import BootstackError
25
+
26
+
27
+ def reject_reserved(
28
+ user: Mapping[str, Any] | None,
29
+ reserved: Mapping[str, str] | None,
30
+ context: str,
31
+ ) -> None:
32
+ """Raise if the caller set a key the framework owns.
33
+
34
+ Args:
35
+ user: The caller's options. `None` is treated as empty.
36
+ reserved: Structural keys the caller may not set, mapped to the
37
+ guidance shown when they try.
38
+ context: The API the caller invoked, e.g. `'ButtonGroup.add()'`.
39
+
40
+ Raises:
41
+ BootstackError: If `user` contains a key listed in `reserved`.
42
+ """
43
+ if not user or not reserved:
44
+ return
45
+ for key in user:
46
+ if key in reserved:
47
+ raise BootstackError(f"{context} does not accept {key}= — {reserved[key]}")
48
+
49
+
50
+ def merge_kwargs(
51
+ defaults: Mapping[str, Any],
52
+ user: Mapping[str, Any] | None,
53
+ *,
54
+ reserved: Mapping[str, str] | None = None,
55
+ context: str = "this call",
56
+ ) -> dict[str, Any]:
57
+ """Merge a caller's options over framework-built keyword arguments.
58
+
59
+ Args:
60
+ defaults: Keyword arguments the framework derived for the call. Any
61
+ key also present in `user` is overridden.
62
+ reserved: Structural keys the caller may not set, mapped to the
63
+ guidance shown when they try.
64
+ context: The API the caller invoked, used in the error message.
65
+ user: The caller's options. `None` is treated as empty.
66
+
67
+ Returns:
68
+ The merged keyword arguments.
69
+
70
+ Raises:
71
+ BootstackError: If `user` contains a key listed in `reserved`.
72
+ """
73
+ merged = dict(defaults)
74
+ if not user:
75
+ return merged
76
+ reject_reserved(user, reserved, context)
77
+ merged.update(user)
78
+ return merged
79
+
80
+
81
+ # Structural keys a bar's widget-options passthrough may not set — a toolbar or
82
+ # status bar places every widget it builds.
83
+ RESERVED_BAR_KWARGS = {
84
+ 'parent': 'the bar places the widgets it builds.',
85
+ }
@@ -4,6 +4,13 @@ from typing import Any
4
4
 
5
5
  from bootstack.widgets._core.options import OptionRecord, record_to_dict, option_localize
6
6
 
7
+ # Structural keys a per-option kwargs passthrough may not set — the group owns
8
+ # each option's identity and tracks its own selection.
9
+ RESERVED_OPTION_KWARGS = {
10
+ 'text': 'set the caption with the label argument.',
11
+ 'variable': 'the group tracks its own selection.',
12
+ }
13
+
7
14
 
8
15
  class SelectionGroupMixin:
9
16
  """Shared item-management surface for the option-group widgets.
@@ -272,9 +272,10 @@ class NumberEntryPart(TextEntryPart):
272
272
  A plain numeric field parses to a string when no display format is set,
273
273
  so coerce it the same way the public value does — validation rules and a
274
274
  `custom` func receive a real `int`/`float` (or `None` for empty/invalid
275
- input), never the display string.
275
+ input), never the display string. A visible placeholder is not input,
276
+ so it reads as empty here — same rule as the text field this overrides.
276
277
  """
277
- text = self.get()
278
+ text = '' if self._showing_placeholder else self.get()
278
279
  try:
279
280
  raw = self._parse_or_none(text)
280
281
  except Exception:
@@ -288,11 +288,17 @@ class TextEntryPart(ValidationMixin, Entry):
288
288
  last-committed value. This keeps a manual `validate()`, the automatic
289
289
  blur/key validation, and a form-level validate in agreement on the same
290
290
  live, typed input.
291
+
292
+ A visible placeholder is not input. It is inserted into the entry to
293
+ render it, so reading the raw text would hand the placeholder string to
294
+ the rules and `required` would pass on an untouched field — the field
295
+ reads as empty here, exactly as it does through `value`.
291
296
  """
297
+ text = "" if self._showing_placeholder else self.get()
292
298
  try:
293
- return self._parse_or_none(self.get())
299
+ return self._parse_or_none(text)
294
300
  except Exception:
295
- return self.get()
301
+ return text
296
302
 
297
303
  def text(self, value=None):
298
304
  """Get or set the raw display text without committing.
@@ -7,8 +7,18 @@ from typing_extensions import Unpack
7
7
  from bootstack.widgets._impl.composites.contextmenu import ContextMenu, ContextMenuItem, ContextMenuItemResult
8
8
  from bootstack.widgets._impl.primitives._menubutton import MenuButton
9
9
  from bootstack.widgets._impl.mixins import configure_delegate
10
+ from bootstack.widgets._core.kwargs import merge_kwargs
10
11
  from bootstack.widgets.types import Master, StyledKwargs, CompoundMode, WidgetState, WidgetDensity
11
12
 
13
+ # Structural keys a menu_options bag may not set — the button owns the menu's
14
+ # contents and the callback that emits its selection events.
15
+ _RESERVED_MENU_OPTIONS = {
16
+ 'items': 'pass the menu items to the button itself.',
17
+ 'command': "use the button's on_select event.",
18
+ 'trigger': 'the button opens its own menu when clicked.',
19
+ 'target': 'the menu belongs to the button that opens it.',
20
+ }
21
+
12
22
  if TYPE_CHECKING:
13
23
  from bootstack.signals import Signal
14
24
 
@@ -122,10 +132,13 @@ class DropdownButton(MenuButton):
122
132
  "offset": (offset_x, 0),
123
133
  "density": density,
124
134
  }
125
- options.update(self._popdown_options)
126
135
  # DropdownButton manages its own activation (left-click, Return/
127
136
  # KP_Enter via show_menu), so opt out of ContextMenu's auto-trigger.
128
- cm = ContextMenu(self, target=self, items=self._items, trigger=None, command=self._command, **options)
137
+ options["trigger"] = None
138
+ options = merge_kwargs(options, self._popdown_options,
139
+ reserved=_RESERVED_MENU_OPTIONS,
140
+ context='MenuButton menu_options')
141
+ cm = ContextMenu(self, target=self, items=self._items, command=self._command, **options)
129
142
  return cm
130
143
 
131
144
  @property
@@ -273,8 +273,13 @@ class Field(EntryMixin, Frame):
273
273
  self._entry.value(value)
274
274
 
275
275
  def get(self) -> str:
276
- """Return the raw text from the underlying entry widget."""
277
- return self._entry.get()
276
+ """Return the display text from the underlying entry widget.
277
+
278
+ Reads the entry's own text rather than its raw contents, so a field
279
+ showing only its placeholder reports an empty string — `text` and
280
+ `value` are a pair and must agree on whether the field is empty.
281
+ """
282
+ return self._entry.text()
278
283
 
279
284
  @property
280
285
  def entry_widget(self) -> EntryWidget:
@@ -15,8 +15,15 @@ from bootstack.widgets._impl.primitives.label import Label
15
15
  from bootstack.widgets._impl.primitives.labelframe import LabelFrame
16
16
  from bootstack.widgets._impl.mixins import configure_delegate
17
17
  from bootstack.widgets._impl.composites.tabs.tabview import TabView
18
+ from bootstack.widgets._core.kwargs import merge_kwargs
18
19
  from bootstack.widgets.types import EditorType, Master
19
20
 
21
+ # Structural keys an editor_options bag may not set — the form's field
22
+ # container owns where the editor is placed.
23
+ _RESERVED_EDITOR_OPTIONS = {
24
+ 'parent': 'the form places each editor in its own field container',
25
+ }
26
+
20
27
  if TYPE_CHECKING:
21
28
  from bootstack.dialogs._impl.dialog import DialogButton
22
29
  ButtonInput = str | Mapping[str, Any] | DialogButton
@@ -603,10 +610,10 @@ class Form(Frame):
603
610
  auto_col = 0
604
611
  auto_row += 1
605
612
 
606
- # Editors that accept validation kwargs (required, etc.). Boolean and slider
607
- # editors validate nothing, so `required` and friends are dropped for them.
608
- _VALIDATING_EDITORS = frozenset(
609
- {'textfield', 'numberfield', 'passwordfield', 'datefield', 'textarea', 'select', 'spinnerfield'})
613
+ # Editors that render something other than a validating field, so `required`
614
+ # and friends are dropped for them. Anything NOT named here — including a
615
+ # misspelled editor name — falls back to a text field, which does validate.
616
+ _NON_VALIDATING_EDITORS = frozenset({'checkbox', 'switch', 'slider'})
610
617
 
611
618
  def _build_field(self, parent: Frame, item: FieldItem):
612
619
  if not item.visible:
@@ -614,7 +621,11 @@ class Form(Frame):
614
621
 
615
622
  editor = item.editor or self._default_editor_for_dtype(item.dtype, self._data.get(item.key))
616
623
  options = dict(item.editor_options or {})
617
- if item.required and editor in self._VALIDATING_EDITORS:
624
+ # Gate on what does NOT validate, not on what does: an unrecognized
625
+ # editor name falls back to a text field, so testing membership of the
626
+ # validating set silently dropped `required` on a typo and let the form
627
+ # submit empty.
628
+ if item.required and editor not in self._NON_VALIDATING_EDITORS:
618
629
  options["required"] = True
619
630
  initial_value = self._data.get(item.key)
620
631
  label_text = item.label if item.label is not None else item.key.replace("_", " ").title()
@@ -680,45 +691,76 @@ class Form(Frame):
680
691
  for internal_only in ("show_message", "validator"):
681
692
  opts.pop(internal_only, None)
682
693
 
694
+ # `value` in editor_options seeds the editor when the form data carries
695
+ # nothing for the key; the data wins when it does. Every editor below
696
+ # passes `value=` positionally-by-keyword, so leaving it in `opts` would
697
+ # raise "got multiple values for keyword argument 'value'".
698
+ seed_value = opts.pop('value', None)
699
+ if initial is None:
700
+ initial = seed_value
701
+
702
+ def build(cls, *args, **defaults):
703
+ """Construct `cls`, letting `editor_options` override the defaults."""
704
+ merged = merge_kwargs(defaults, opts, reserved=_RESERVED_EDITOR_OPTIONS,
705
+ context='Form editor_options')
706
+ merged['parent'] = container
707
+ return cls(*args, **merged)
708
+
709
+ def choice_list():
710
+ """Pop the documented `items`/`values` aliases for the option list."""
711
+ choices = opts.pop('items', None)
712
+ if choices is None:
713
+ choices = opts.pop('values', None)
714
+ return choices
715
+
716
+ # Test against None, not truthiness: a falsy-but-real datum (0, False)
717
+ # is a value, not an absent one, and blanking it here would write the
718
+ # blank straight back into the form data. Pass the datum through as it
719
+ # came, too — `data` is the caller's record, and stringifying it here
720
+ # would flip a Decimal or a date to `str` in `form.data` before the
721
+ # user has edited anything.
722
+ text_value = initial if initial is not None else ""
723
+
683
724
  if editor == 'textfield':
684
- return TextField(value=initial or "", label=label_text, parent=container, **opts)
725
+ return build(TextField, value=text_value, label=label_text)
685
726
  if editor == 'numberfield':
686
- numeric_value = initial if initial is not None else 0
687
- return NumberField(value=numeric_value, label=label_text, parent=container, **opts)
727
+ return build(NumberField, value=initial if initial is not None else 0,
728
+ label=label_text)
688
729
  if editor == 'passwordfield':
689
- return PasswordField(value=initial or "", label=label_text, parent=container, **opts)
730
+ return build(PasswordField, value=text_value, label=label_text)
690
731
  if editor == 'datefield':
691
- return DateField(value=initial, label=label_text, parent=container, **opts)
732
+ return build(DateField, value=initial, label=label_text)
692
733
  if editor == 'textarea':
693
- text = str(initial) if initial is not None else ""
694
- return TextArea(value=text, label=label_text, parent=container, **opts)
734
+ return build(TextArea, value=text_value, label=label_text)
695
735
  if editor == 'select':
696
- choices = opts.pop('items', opts.pop('values', None)) or []
697
- choices = [str(i) for i in choices]
698
- return Select(options=choices, value=initial if initial is not None else "",
699
- label=label_text, parent=container, **opts)
736
+ choices = [str(i) for i in (choice_list() or [])]
737
+ return build(Select, options=choices, label=label_text,
738
+ value=initial if initial is not None else "")
700
739
  if editor == 'spinnerfield':
701
- choices = opts.pop('items', opts.pop('values', None))
740
+ choices = choice_list()
702
741
  if choices is not None:
703
742
  opts['options'] = [str(i) for i in choices]
704
- return SpinnerField(value=initial if initial is not None else "",
705
- label=label_text, parent=container, **opts)
706
- if editor == 'checkbox':
707
- text = opts.pop('text', None) or label_text
708
- return Checkbox(text, value=bool(initial) if initial is not None else False,
709
- parent=container, **opts)
710
- if editor == 'switch':
711
- text = opts.pop('text', None) or label_text
712
- return Switch(text, value=bool(initial) if initial is not None else False,
713
- parent=container, **opts)
743
+ return build(SpinnerField, value=initial if initial is not None else "",
744
+ label=label_text)
745
+ if editor in ('checkbox', 'switch'):
746
+ # The boolean controls call their caption `label`, so pass it by
747
+ # keyword passing it positionally would collide with a `label`
748
+ # option instead of letting it override, and `text` is the alias a
749
+ # caller reaches for first.
750
+ caption = opts.pop('text', None) or label_text
751
+ # `None` stays `None` so a tristate checkbox starts indeterminate;
752
+ # the widget maps `None` to unchecked when tristate is off.
753
+ cls = Checkbox if editor == 'checkbox' else Switch
754
+ return build(cls, label=caption,
755
+ value=bool(initial) if initial is not None else None)
714
756
  if editor == 'slider':
715
757
  # Slider has no label parameter, so render a stacked caption above it
716
758
  # (the field wrappers render their own label internally).
717
759
  if label_text:
718
760
  Label(container, text=label_text).pack(anchor='w', pady=(0, 2))
719
- return Slider(value=initial if initial is not None else 0, parent=container, **opts)
761
+ return build(Slider, value=initial if initial is not None else 0)
720
762
  # Fallback: treat any unknown editor as a text field.
721
- return TextField(value=initial or "", label=label_text, parent=container, **opts)
763
+ return build(TextField, value=text_value, label=label_text)
722
764
 
723
765
  def _build_buttons(self, parent: Frame, buttons: Sequence[ButtonInput]) -> None:
724
766
  parsed = self._normalize_buttons(buttons)