manywidgets 0.1.0__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 (182) hide show
  1. manywidgets-0.1.0/.gitignore +34 -0
  2. manywidgets-0.1.0/LICENSE +21 -0
  3. manywidgets-0.1.0/PKG-INFO +168 -0
  4. manywidgets-0.1.0/README.md +137 -0
  5. manywidgets-0.1.0/package-lock.json +2749 -0
  6. manywidgets-0.1.0/package.json +30 -0
  7. manywidgets-0.1.0/packages/core/src/index.ts +392 -0
  8. manywidgets-0.1.0/packages/core/tests/core.test.ts +194 -0
  9. manywidgets-0.1.0/pyproject.toml +130 -0
  10. manywidgets-0.1.0/scripts/browser_check.py +293 -0
  11. manywidgets-0.1.0/scripts/build.mjs +74 -0
  12. manywidgets-0.1.0/scripts/build_skill_reference.py +151 -0
  13. manywidgets-0.1.0/scripts/build_widget_docs.py +137 -0
  14. manywidgets-0.1.0/src/manywidgets/__init__.py +49 -0
  15. manywidgets-0.1.0/src/manywidgets/__main__.py +107 -0
  16. manywidgets-0.1.0/src/manywidgets/_base.py +73 -0
  17. manywidgets-0.1.0/src/manywidgets/_version.py +1 -0
  18. manywidgets-0.1.0/src/manywidgets/binder/__init__.py +3 -0
  19. manywidgets-0.1.0/src/manywidgets/binder/dist/widget.js +171 -0
  20. manywidgets-0.1.0/src/manywidgets/binder/doc.md +38 -0
  21. manywidgets-0.1.0/src/manywidgets/binder/src/index.ts +81 -0
  22. manywidgets-0.1.0/src/manywidgets/binder/tests/binder.test.ts +64 -0
  23. manywidgets-0.1.0/src/manywidgets/binder/tests/test_binder.py +33 -0
  24. manywidgets-0.1.0/src/manywidgets/binder/widget.py +81 -0
  25. manywidgets-0.1.0/src/manywidgets/button/__init__.py +3 -0
  26. manywidgets-0.1.0/src/manywidgets/button/dist/widget.js +31 -0
  27. manywidgets-0.1.0/src/manywidgets/button/doc.md +46 -0
  28. manywidgets-0.1.0/src/manywidgets/button/src/index.ts +27 -0
  29. manywidgets-0.1.0/src/manywidgets/button/style.css +22 -0
  30. manywidgets-0.1.0/src/manywidgets/button/tests/button.test.ts +31 -0
  31. manywidgets-0.1.0/src/manywidgets/button/tests/test_button.py +40 -0
  32. manywidgets-0.1.0/src/manywidgets/button/widget.py +46 -0
  33. manywidgets-0.1.0/src/manywidgets/chart/__init__.py +3 -0
  34. manywidgets-0.1.0/src/manywidgets/chart/dist/widget.js +14663 -0
  35. manywidgets-0.1.0/src/manywidgets/chart/doc.md +50 -0
  36. manywidgets-0.1.0/src/manywidgets/chart/src/index.ts +201 -0
  37. manywidgets-0.1.0/src/manywidgets/chart/style.css +10 -0
  38. manywidgets-0.1.0/src/manywidgets/chart/tests/chart.test.ts +80 -0
  39. manywidgets-0.1.0/src/manywidgets/chart/tests/test_chart.py +59 -0
  40. manywidgets-0.1.0/src/manywidgets/chart/widget.py +126 -0
  41. manywidgets-0.1.0/src/manywidgets/column/__init__.py +3 -0
  42. manywidgets-0.1.0/src/manywidgets/column/dist/widget.js +72 -0
  43. manywidgets-0.1.0/src/manywidgets/column/doc.md +31 -0
  44. manywidgets-0.1.0/src/manywidgets/column/src/index.ts +50 -0
  45. manywidgets-0.1.0/src/manywidgets/column/style.css +7 -0
  46. manywidgets-0.1.0/src/manywidgets/column/tests/column.test.ts +27 -0
  47. manywidgets-0.1.0/src/manywidgets/column/tests/test_column.py +25 -0
  48. manywidgets-0.1.0/src/manywidgets/column/widget.py +35 -0
  49. manywidgets-0.1.0/src/manywidgets/dropdown/__init__.py +3 -0
  50. manywidgets-0.1.0/src/manywidgets/dropdown/dist/widget.js +60 -0
  51. manywidgets-0.1.0/src/manywidgets/dropdown/doc.md +36 -0
  52. manywidgets-0.1.0/src/manywidgets/dropdown/src/index.ts +72 -0
  53. manywidgets-0.1.0/src/manywidgets/dropdown/style.css +28 -0
  54. manywidgets-0.1.0/src/manywidgets/dropdown/tests/dropdown.test.ts +40 -0
  55. manywidgets-0.1.0/src/manywidgets/dropdown/tests/test_dropdown.py +28 -0
  56. manywidgets-0.1.0/src/manywidgets/dropdown/widget.py +41 -0
  57. manywidgets-0.1.0/src/manywidgets/grid/__init__.py +3 -0
  58. manywidgets-0.1.0/src/manywidgets/grid/dist/widget.js +72 -0
  59. manywidgets-0.1.0/src/manywidgets/grid/doc.md +35 -0
  60. manywidgets-0.1.0/src/manywidgets/grid/src/index.ts +50 -0
  61. manywidgets-0.1.0/src/manywidgets/grid/style.css +7 -0
  62. manywidgets-0.1.0/src/manywidgets/grid/tests/grid.test.ts +34 -0
  63. manywidgets-0.1.0/src/manywidgets/grid/tests/test_grid.py +30 -0
  64. manywidgets-0.1.0/src/manywidgets/grid/widget.py +33 -0
  65. manywidgets-0.1.0/src/manywidgets/legend/__init__.py +3 -0
  66. manywidgets-0.1.0/src/manywidgets/legend/dist/widget.js +55 -0
  67. manywidgets-0.1.0/src/manywidgets/legend/doc.md +32 -0
  68. manywidgets-0.1.0/src/manywidgets/legend/src/index.ts +62 -0
  69. manywidgets-0.1.0/src/manywidgets/legend/style.css +46 -0
  70. manywidgets-0.1.0/src/manywidgets/legend/tests/legend.test.ts +40 -0
  71. manywidgets-0.1.0/src/manywidgets/legend/tests/test_legend.py +26 -0
  72. manywidgets-0.1.0/src/manywidgets/legend/widget.py +42 -0
  73. manywidgets-0.1.0/src/manywidgets/lonboard/__init__.py +24 -0
  74. manywidgets-0.1.0/src/manywidgets/lonboard/conftest.py +20 -0
  75. manywidgets-0.1.0/src/manywidgets/lonboard/filter_binder/__init__.py +3 -0
  76. manywidgets-0.1.0/src/manywidgets/lonboard/filter_binder/dist/widget.js +177 -0
  77. manywidgets-0.1.0/src/manywidgets/lonboard/filter_binder/doc.md +52 -0
  78. manywidgets-0.1.0/src/manywidgets/lonboard/filter_binder/src/index.ts +77 -0
  79. manywidgets-0.1.0/src/manywidgets/lonboard/filter_binder/tests/filter_binder.test.ts +72 -0
  80. manywidgets-0.1.0/src/manywidgets/lonboard/filter_binder/tests/test_filter_binder.py +58 -0
  81. manywidgets-0.1.0/src/manywidgets/lonboard/filter_binder/widget.py +72 -0
  82. manywidgets-0.1.0/src/manywidgets/lonboard/layer_filter/__init__.py +3 -0
  83. manywidgets-0.1.0/src/manywidgets/lonboard/layer_filter/dist/widget.js +190 -0
  84. manywidgets-0.1.0/src/manywidgets/lonboard/layer_filter/doc.md +41 -0
  85. manywidgets-0.1.0/src/manywidgets/lonboard/layer_filter/src/index.ts +94 -0
  86. manywidgets-0.1.0/src/manywidgets/lonboard/layer_filter/style.css +37 -0
  87. manywidgets-0.1.0/src/manywidgets/lonboard/layer_filter/tests/layer_filter.test.ts +46 -0
  88. manywidgets-0.1.0/src/manywidgets/lonboard/layer_filter/tests/test_layer_filter.py +30 -0
  89. manywidgets-0.1.0/src/manywidgets/lonboard/layer_filter/widget.py +43 -0
  90. manywidgets-0.1.0/src/manywidgets/lonboard/layer_toggle/__init__.py +3 -0
  91. manywidgets-0.1.0/src/manywidgets/lonboard/layer_toggle/dist/widget.js +177 -0
  92. manywidgets-0.1.0/src/manywidgets/lonboard/layer_toggle/doc.md +36 -0
  93. manywidgets-0.1.0/src/manywidgets/lonboard/layer_toggle/src/index.ts +78 -0
  94. manywidgets-0.1.0/src/manywidgets/lonboard/layer_toggle/style.css +54 -0
  95. manywidgets-0.1.0/src/manywidgets/lonboard/layer_toggle/tests/layer_toggle.test.ts +33 -0
  96. manywidgets-0.1.0/src/manywidgets/lonboard/layer_toggle/tests/test_layer_toggle.py +23 -0
  97. manywidgets-0.1.0/src/manywidgets/lonboard/layer_toggle/widget.py +31 -0
  98. manywidgets-0.1.0/src/manywidgets/lonboard/map_compare/__init__.py +3 -0
  99. manywidgets-0.1.0/src/manywidgets/lonboard/map_compare/dist/widget.js +317 -0
  100. manywidgets-0.1.0/src/manywidgets/lonboard/map_compare/doc.md +65 -0
  101. manywidgets-0.1.0/src/manywidgets/lonboard/map_compare/src/index.ts +243 -0
  102. manywidgets-0.1.0/src/manywidgets/lonboard/map_compare/style.css +99 -0
  103. manywidgets-0.1.0/src/manywidgets/lonboard/map_compare/tests/map_compare.test.ts +161 -0
  104. manywidgets-0.1.0/src/manywidgets/lonboard/map_compare/tests/test_map_compare.py +90 -0
  105. manywidgets-0.1.0/src/manywidgets/lonboard/map_compare/widget.py +111 -0
  106. manywidgets-0.1.0/src/manywidgets/lonboard/map_flyer/__init__.py +3 -0
  107. manywidgets-0.1.0/src/manywidgets/lonboard/map_flyer/dist/widget.js +177 -0
  108. manywidgets-0.1.0/src/manywidgets/lonboard/map_flyer/doc.md +43 -0
  109. manywidgets-0.1.0/src/manywidgets/lonboard/map_flyer/src/index.ts +78 -0
  110. manywidgets-0.1.0/src/manywidgets/lonboard/map_flyer/style.css +41 -0
  111. manywidgets-0.1.0/src/manywidgets/lonboard/map_flyer/tests/map_flyer.test.ts +69 -0
  112. manywidgets-0.1.0/src/manywidgets/lonboard/map_flyer/tests/test_map_flyer.py +25 -0
  113. manywidgets-0.1.0/src/manywidgets/lonboard/map_flyer/widget.py +47 -0
  114. manywidgets-0.1.0/src/manywidgets/number_display/__init__.py +3 -0
  115. manywidgets-0.1.0/src/manywidgets/number_display/dist/widget.js +80 -0
  116. manywidgets-0.1.0/src/manywidgets/number_display/doc.md +28 -0
  117. manywidgets-0.1.0/src/manywidgets/number_display/src/index.ts +100 -0
  118. manywidgets-0.1.0/src/manywidgets/number_display/style.css +23 -0
  119. manywidgets-0.1.0/src/manywidgets/number_display/tests/number_display.test.ts +52 -0
  120. manywidgets-0.1.0/src/manywidgets/number_display/tests/test_number_display.py +17 -0
  121. manywidgets-0.1.0/src/manywidgets/number_display/widget.py +31 -0
  122. manywidgets-0.1.0/src/manywidgets/number_input/__init__.py +3 -0
  123. manywidgets-0.1.0/src/manywidgets/number_input/dist/widget.js +58 -0
  124. manywidgets-0.1.0/src/manywidgets/number_input/doc.md +34 -0
  125. manywidgets-0.1.0/src/manywidgets/number_input/src/index.ts +55 -0
  126. manywidgets-0.1.0/src/manywidgets/number_input/style.css +28 -0
  127. manywidgets-0.1.0/src/manywidgets/number_input/tests/number_input.test.ts +39 -0
  128. manywidgets-0.1.0/src/manywidgets/number_input/tests/test_number_input.py +18 -0
  129. manywidgets-0.1.0/src/manywidgets/number_input/widget.py +24 -0
  130. manywidgets-0.1.0/src/manywidgets/range_slider/__init__.py +3 -0
  131. manywidgets-0.1.0/src/manywidgets/range_slider/dist/widget.js +84 -0
  132. manywidgets-0.1.0/src/manywidgets/range_slider/doc.md +36 -0
  133. manywidgets-0.1.0/src/manywidgets/range_slider/src/index.ts +89 -0
  134. manywidgets-0.1.0/src/manywidgets/range_slider/style.css +40 -0
  135. manywidgets-0.1.0/src/manywidgets/range_slider/tests/range_slider.test.ts +46 -0
  136. manywidgets-0.1.0/src/manywidgets/range_slider/tests/test_range_slider.py +17 -0
  137. manywidgets-0.1.0/src/manywidgets/range_slider/widget.py +26 -0
  138. manywidgets-0.1.0/src/manywidgets/row/__init__.py +3 -0
  139. manywidgets-0.1.0/src/manywidgets/row/dist/widget.js +73 -0
  140. manywidgets-0.1.0/src/manywidgets/row/doc.md +32 -0
  141. manywidgets-0.1.0/src/manywidgets/row/src/index.ts +51 -0
  142. manywidgets-0.1.0/src/manywidgets/row/style.css +7 -0
  143. manywidgets-0.1.0/src/manywidgets/row/tests/row.test.ts +42 -0
  144. manywidgets-0.1.0/src/manywidgets/row/tests/test_row.py +31 -0
  145. manywidgets-0.1.0/src/manywidgets/row/widget.py +38 -0
  146. manywidgets-0.1.0/src/manywidgets/skill/SKILL.md +71 -0
  147. manywidgets-0.1.0/src/manywidgets/skill/references/authoring.md +113 -0
  148. manywidgets-0.1.0/src/manywidgets/skill/references/usage.md +143 -0
  149. manywidgets-0.1.0/src/manywidgets/skill/references/widgets-api.md +358 -0
  150. manywidgets-0.1.0/src/manywidgets/slider/__init__.py +3 -0
  151. manywidgets-0.1.0/src/manywidgets/slider/dist/widget.js +61 -0
  152. manywidgets-0.1.0/src/manywidgets/slider/doc.md +34 -0
  153. manywidgets-0.1.0/src/manywidgets/slider/src/index.ts +66 -0
  154. manywidgets-0.1.0/src/manywidgets/slider/style.css +35 -0
  155. manywidgets-0.1.0/src/manywidgets/slider/tests/slider.test.ts +56 -0
  156. manywidgets-0.1.0/src/manywidgets/slider/tests/test_slider.py +17 -0
  157. manywidgets-0.1.0/src/manywidgets/slider/widget.py +25 -0
  158. manywidgets-0.1.0/src/manywidgets/stat/__init__.py +3 -0
  159. manywidgets-0.1.0/src/manywidgets/stat/dist/widget.js +51 -0
  160. manywidgets-0.1.0/src/manywidgets/stat/doc.md +28 -0
  161. manywidgets-0.1.0/src/manywidgets/stat/src/index.ts +57 -0
  162. manywidgets-0.1.0/src/manywidgets/stat/style.css +55 -0
  163. manywidgets-0.1.0/src/manywidgets/stat/tests/stat.test.ts +36 -0
  164. manywidgets-0.1.0/src/manywidgets/stat/tests/test_stat.py +17 -0
  165. manywidgets-0.1.0/src/manywidgets/stat/widget.py +26 -0
  166. manywidgets-0.1.0/src/manywidgets/text/__init__.py +3 -0
  167. manywidgets-0.1.0/src/manywidgets/text/dist/widget.js +2104 -0
  168. manywidgets-0.1.0/src/manywidgets/text/doc.md +31 -0
  169. manywidgets-0.1.0/src/manywidgets/text/src/index.ts +31 -0
  170. manywidgets-0.1.0/src/manywidgets/text/style.css +23 -0
  171. manywidgets-0.1.0/src/manywidgets/text/tests/test_text.py +17 -0
  172. manywidgets-0.1.0/src/manywidgets/text/tests/text.test.ts +31 -0
  173. manywidgets-0.1.0/src/manywidgets/text/widget.py +22 -0
  174. manywidgets-0.1.0/src/manywidgets/toggle/__init__.py +3 -0
  175. manywidgets-0.1.0/src/manywidgets/toggle/dist/widget.js +40 -0
  176. manywidgets-0.1.0/src/manywidgets/toggle/doc.md +34 -0
  177. manywidgets-0.1.0/src/manywidgets/toggle/src/index.ts +43 -0
  178. manywidgets-0.1.0/src/manywidgets/toggle/style.css +54 -0
  179. manywidgets-0.1.0/src/manywidgets/toggle/tests/test_toggle.py +17 -0
  180. manywidgets-0.1.0/src/manywidgets/toggle/tests/toggle.test.ts +34 -0
  181. manywidgets-0.1.0/src/manywidgets/toggle/widget.py +17 -0
  182. manywidgets-0.1.0/tsconfig.base.json +22 -0
@@ -0,0 +1,34 @@
1
+ # Node
2
+ /node_modules/
3
+ package-lock.json.bak
4
+
5
+ # Built JS bundles (regenerated by `npm run build`; shipped in the wheel via hatch).
6
+ # ** so nested widgets (e.g. lonboard/<name>/dist/) are ignored too.
7
+ src/manywidgets/**/dist/
8
+
9
+ # Python
10
+ __pycache__/
11
+ *.py[cod]
12
+ *.egg-info/
13
+ /build/
14
+ /dist/
15
+ .venv/
16
+ venv/
17
+ .pytest_cache/
18
+
19
+ # MyST / docs build output
20
+ docs/_build/
21
+ docs/plugin.mjs
22
+ # Sidecar widget assets emitted next to notebooks by the static-export plugin
23
+ **/_widget_assets/
24
+ .ipynb_checkpoints/
25
+ # Per-widget doc notebooks are generated from src/manywidgets/<name>/doc.md
26
+ # (scripts/build_widget_docs.py) — build artifacts, not source.
27
+ docs/widgets/*.ipynb
28
+
29
+ # Agent tooling: the skill ships in the package (src/manywidgets/skill/) and is
30
+ # installed locally with `manywidgets install-skill` — don't commit the copy.
31
+ .claude/
32
+
33
+ # OS
34
+ .DS_Store
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Development Seed
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,168 @@
1
+ Metadata-Version: 2.4
2
+ Name: manywidgets
3
+ Version: 0.1.0
4
+ Summary: A composable set of anywidget-based widgets for data analysis and geospatial work in notebooks — works well with lonboard, and renders statically (no kernel) via the myst-anywidget-static-export plugin.
5
+ Project-URL: Homepage, https://github.com/developmentseed/manywidgets
6
+ Project-URL: Repository, https://github.com/developmentseed/manywidgets
7
+ Project-URL: Issues, https://github.com/developmentseed/manywidgets/issues
8
+ Author-email: Development Seed <sanjay@developmentseed.org>
9
+ License-Expression: MIT
10
+ License-File: LICENSE
11
+ Keywords: anywidget,geospatial,jupyter,lonboard,mystmd,widgets
12
+ Classifier: Framework :: Jupyter
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Topic :: Scientific/Engineering :: Visualization
16
+ Requires-Python: >=3.9
17
+ Requires-Dist: anywidget>=0.9
18
+ Requires-Dist: ipywidgets>=8
19
+ Requires-Dist: traitlets>=5
20
+ Provides-Extra: dev
21
+ Requires-Dist: ipykernel; extra == 'dev'
22
+ Requires-Dist: nbconvert; extra == 'dev'
23
+ Requires-Dist: nbformat; extra == 'dev'
24
+ Requires-Dist: numpy; extra == 'dev'
25
+ Requires-Dist: pytest>=8; extra == 'dev'
26
+ Provides-Extra: lonboard
27
+ Requires-Dist: lonboard>=0.10; extra == 'lonboard'
28
+ Provides-Extra: numpy
29
+ Requires-Dist: numpy; extra == 'numpy'
30
+ Description-Content-Type: text/markdown
31
+
32
+ # manywidgets
33
+
34
+ A composable set of [anywidget](https://anywidget.dev)-based widgets for data
35
+ analysis and geospatial work in notebooks. They're self-contained, link and
36
+ compose, work well with [lonboard](https://developmentseed.org/lonboard/), and
37
+ render statically (no kernel) via the
38
+ [`myst-anywidget-static-export`](https://github.com/developmentseed/myst-anywidget-static-export)
39
+ MyST plugin.
40
+
41
+ > **Status:** early but feature-complete for v1 — `Chart`, input controls (`Slider`,
42
+ > `RangeSlider`, `Dropdown`, `Toggle`, `Button`, `NumberInput`), value displays
43
+ > (`Stat`, `NumberDisplay`, `Text`), layout containers (`Row`, `Column`, `Grid`),
44
+ > the `Binder` linking primitive, and optional lonboard interop (`LayerToggle`,
45
+ > `FilterBinder`, `LayerFilter`).
46
+
47
+ ## Install
48
+
49
+ ```bash
50
+ pip install manywidgets
51
+ # optional lonboard interop widgets:
52
+ pip install "manywidgets[lonboard]"
53
+ ```
54
+
55
+ ## Quick start
56
+
57
+ ```python
58
+ from manywidgets import Chart, Slider, Binder
59
+ import numpy as np
60
+
61
+ chart = Chart(title="Demo", x_label="x", y_label="y", height=320)
62
+ chart.add_series(x=np.linspace(0, 10, 100), y=np.sin(np.linspace(0, 10, 100)), name="sin")
63
+ chart
64
+ ```
65
+
66
+ ## Widgets
67
+
68
+ ```python
69
+ from manywidgets import (
70
+ Chart, # Chart.js charts
71
+ Slider, RangeSlider, Dropdown, Toggle, Button, NumberInput, # input controls
72
+ Stat, NumberDisplay, Text, Legend, # value displays
73
+ Row, Column, Grid, # layout (arrange + keep children linked)
74
+ Binder, # linking with transforms / nested paths
75
+ )
76
+
77
+ # Optional lonboard interop (pip install "manywidgets[lonboard]")
78
+ from manywidgets.lonboard import LayerToggle, FilterBinder, LayerFilter
79
+ ```
80
+
81
+ ## Linking widgets
82
+
83
+ Two complementary tools — see [`docs/guides/linking.md`](docs/guides/linking.md):
84
+
85
+ ```python
86
+ from ipywidgets import jsdlink
87
+
88
+ # 1. jslink / jsdlink — the canonical, kernel-free pass-through link.
89
+ slider = Slider(label="Amplitude", min=0, max=5, value=1)
90
+ jsdlink((slider, "value"), (chart, "title")) # browser-side, works live + static
91
+
92
+ # 2. Binder — for transforms / nested paths jslink can't express.
93
+ Binder(source=slider, source_field="value",
94
+ target=chart, target_field="height",
95
+ multiplier=100, offset=200)
96
+ ```
97
+
98
+ ## Agent skill
99
+
100
+ manywidgets ships an [agent skill](src/manywidgets/skill/SKILL.md) so coding
101
+ agents can help you build widgets and dashboards. Install it into a location your
102
+ agent discovers:
103
+
104
+ ```bash
105
+ manywidgets install-skill # ./.claude/skills/manywidgets/ (this project)
106
+ manywidgets install-skill --user # ~/.claude/skills/manywidgets/ (all projects)
107
+ manywidgets install-skill --path DIR # anywhere else (other agents)
108
+ ```
109
+
110
+ The skill (an entrypoint plus `references/` on widget API, usage, and authoring)
111
+ travels inside the wheel, so it always matches the installed version. The
112
+ per-widget API reference is generated from widget traits — never hand-edited.
113
+
114
+ ## How it works / design
115
+
116
+ Every widget extends a thin `BaseWidget` (auto-assigns a stable `widget_id`) and
117
+ follows the TypeScript "golden example" structure: `src/index.ts` bundled by
118
+ esbuild into `dist/widget.js`, styling via the `_css` trait. Cross-widget
119
+ resolution and the static-export safety rules live once in a shared
120
+ `@manywidgets/core` TypeScript module that esbuild inlines into each widget.
121
+
122
+ This package has **no code dependency** on the static-export plugin — it just
123
+ follows the rules the plugin needs (wrap `save_changes`, never inject `<link>`
124
+ into the mount element, vanilla DOM, buffer-free core widgets, link via
125
+ `jslink`/`Binder`). The docs site references the plugin by release URL only.
126
+
127
+ ## Development
128
+
129
+ ```bash
130
+ npm install
131
+ npm run build # esbuild every widget src/index.ts -> dist/widget.js
132
+ npm run typecheck # tsc --noEmit
133
+ npm test # vitest (JS unit tests)
134
+ pip install -e ".[dev]"
135
+ pytest
136
+ ```
137
+
138
+ ### Docs
139
+
140
+ Each widget owns its docs in `src/manywidgets/<name>/doc.md` (prose + a
141
+ `{code-cell}` example + an `{api-table}` placeholder). `npm run docs:gen` builds
142
+ `docs/widgets/<name>.ipynb` from those — auto-generating the API table from trait
143
+ introspection — so the per-widget pages are **generated build artifacts**
144
+ (gitignored), not hand-maintained. The agent skill's API reference is generated
145
+ the same way (`npm run skill:gen` → `src/manywidgets/skill/references/widgets-api.md`,
146
+ which **is** committed and CI-checked for drift) — regenerate it after changing
147
+ any widget's traits. Build and view:
148
+
149
+ ```bash
150
+ # lonboard + geopandas + pyarrow are only needed for the lonboard interop example
151
+ pip install -e ".[numpy,lonboard]" ipykernel nbconvert nbformat geopandas pyarrow
152
+ python -m ipykernel install --user --name manywidgets-venv
153
+ npm run docs:gen # generate docs/widgets/*.ipynb from each widget's doc.md
154
+ jupyter nbconvert --to notebook --execute --inplace docs/examples/*.ipynb docs/widgets/*.ipynb
155
+ cd docs && npx myst build --html && cd ..
156
+ npm run serve # serve over HTTP at http://localhost:8000 (NOT file://)
157
+ ```
158
+
159
+ > Serve the built site over HTTP — opening the HTML via `file://` breaks asset and
160
+ > widget loading (absolute paths + dynamic `import()`).
161
+
162
+ Releases are cut by publishing a GitHub Release (CI builds the wheel — with JS
163
+ compiled by the build hook — and publishes to PyPI). The JS bundles are
164
+ gitignored and rebuilt by the build; they ship inside the wheel.
165
+
166
+ ## License
167
+
168
+ MIT — see [LICENSE](LICENSE).
@@ -0,0 +1,137 @@
1
+ # manywidgets
2
+
3
+ A composable set of [anywidget](https://anywidget.dev)-based widgets for data
4
+ analysis and geospatial work in notebooks. They're self-contained, link and
5
+ compose, work well with [lonboard](https://developmentseed.org/lonboard/), and
6
+ render statically (no kernel) via the
7
+ [`myst-anywidget-static-export`](https://github.com/developmentseed/myst-anywidget-static-export)
8
+ MyST plugin.
9
+
10
+ > **Status:** early but feature-complete for v1 — `Chart`, input controls (`Slider`,
11
+ > `RangeSlider`, `Dropdown`, `Toggle`, `Button`, `NumberInput`), value displays
12
+ > (`Stat`, `NumberDisplay`, `Text`), layout containers (`Row`, `Column`, `Grid`),
13
+ > the `Binder` linking primitive, and optional lonboard interop (`LayerToggle`,
14
+ > `FilterBinder`, `LayerFilter`).
15
+
16
+ ## Install
17
+
18
+ ```bash
19
+ pip install manywidgets
20
+ # optional lonboard interop widgets:
21
+ pip install "manywidgets[lonboard]"
22
+ ```
23
+
24
+ ## Quick start
25
+
26
+ ```python
27
+ from manywidgets import Chart, Slider, Binder
28
+ import numpy as np
29
+
30
+ chart = Chart(title="Demo", x_label="x", y_label="y", height=320)
31
+ chart.add_series(x=np.linspace(0, 10, 100), y=np.sin(np.linspace(0, 10, 100)), name="sin")
32
+ chart
33
+ ```
34
+
35
+ ## Widgets
36
+
37
+ ```python
38
+ from manywidgets import (
39
+ Chart, # Chart.js charts
40
+ Slider, RangeSlider, Dropdown, Toggle, Button, NumberInput, # input controls
41
+ Stat, NumberDisplay, Text, Legend, # value displays
42
+ Row, Column, Grid, # layout (arrange + keep children linked)
43
+ Binder, # linking with transforms / nested paths
44
+ )
45
+
46
+ # Optional lonboard interop (pip install "manywidgets[lonboard]")
47
+ from manywidgets.lonboard import LayerToggle, FilterBinder, LayerFilter
48
+ ```
49
+
50
+ ## Linking widgets
51
+
52
+ Two complementary tools — see [`docs/guides/linking.md`](docs/guides/linking.md):
53
+
54
+ ```python
55
+ from ipywidgets import jsdlink
56
+
57
+ # 1. jslink / jsdlink — the canonical, kernel-free pass-through link.
58
+ slider = Slider(label="Amplitude", min=0, max=5, value=1)
59
+ jsdlink((slider, "value"), (chart, "title")) # browser-side, works live + static
60
+
61
+ # 2. Binder — for transforms / nested paths jslink can't express.
62
+ Binder(source=slider, source_field="value",
63
+ target=chart, target_field="height",
64
+ multiplier=100, offset=200)
65
+ ```
66
+
67
+ ## Agent skill
68
+
69
+ manywidgets ships an [agent skill](src/manywidgets/skill/SKILL.md) so coding
70
+ agents can help you build widgets and dashboards. Install it into a location your
71
+ agent discovers:
72
+
73
+ ```bash
74
+ manywidgets install-skill # ./.claude/skills/manywidgets/ (this project)
75
+ manywidgets install-skill --user # ~/.claude/skills/manywidgets/ (all projects)
76
+ manywidgets install-skill --path DIR # anywhere else (other agents)
77
+ ```
78
+
79
+ The skill (an entrypoint plus `references/` on widget API, usage, and authoring)
80
+ travels inside the wheel, so it always matches the installed version. The
81
+ per-widget API reference is generated from widget traits — never hand-edited.
82
+
83
+ ## How it works / design
84
+
85
+ Every widget extends a thin `BaseWidget` (auto-assigns a stable `widget_id`) and
86
+ follows the TypeScript "golden example" structure: `src/index.ts` bundled by
87
+ esbuild into `dist/widget.js`, styling via the `_css` trait. Cross-widget
88
+ resolution and the static-export safety rules live once in a shared
89
+ `@manywidgets/core` TypeScript module that esbuild inlines into each widget.
90
+
91
+ This package has **no code dependency** on the static-export plugin — it just
92
+ follows the rules the plugin needs (wrap `save_changes`, never inject `<link>`
93
+ into the mount element, vanilla DOM, buffer-free core widgets, link via
94
+ `jslink`/`Binder`). The docs site references the plugin by release URL only.
95
+
96
+ ## Development
97
+
98
+ ```bash
99
+ npm install
100
+ npm run build # esbuild every widget src/index.ts -> dist/widget.js
101
+ npm run typecheck # tsc --noEmit
102
+ npm test # vitest (JS unit tests)
103
+ pip install -e ".[dev]"
104
+ pytest
105
+ ```
106
+
107
+ ### Docs
108
+
109
+ Each widget owns its docs in `src/manywidgets/<name>/doc.md` (prose + a
110
+ `{code-cell}` example + an `{api-table}` placeholder). `npm run docs:gen` builds
111
+ `docs/widgets/<name>.ipynb` from those — auto-generating the API table from trait
112
+ introspection — so the per-widget pages are **generated build artifacts**
113
+ (gitignored), not hand-maintained. The agent skill's API reference is generated
114
+ the same way (`npm run skill:gen` → `src/manywidgets/skill/references/widgets-api.md`,
115
+ which **is** committed and CI-checked for drift) — regenerate it after changing
116
+ any widget's traits. Build and view:
117
+
118
+ ```bash
119
+ # lonboard + geopandas + pyarrow are only needed for the lonboard interop example
120
+ pip install -e ".[numpy,lonboard]" ipykernel nbconvert nbformat geopandas pyarrow
121
+ python -m ipykernel install --user --name manywidgets-venv
122
+ npm run docs:gen # generate docs/widgets/*.ipynb from each widget's doc.md
123
+ jupyter nbconvert --to notebook --execute --inplace docs/examples/*.ipynb docs/widgets/*.ipynb
124
+ cd docs && npx myst build --html && cd ..
125
+ npm run serve # serve over HTTP at http://localhost:8000 (NOT file://)
126
+ ```
127
+
128
+ > Serve the built site over HTTP — opening the HTML via `file://` breaks asset and
129
+ > widget loading (absolute paths + dynamic `import()`).
130
+
131
+ Releases are cut by publishing a GitHub Release (CI builds the wheel — with JS
132
+ compiled by the build hook — and publishes to PyPI). The JS bundles are
133
+ gitignored and rebuilt by the build; they ship inside the wheel.
134
+
135
+ ## License
136
+
137
+ MIT — see [LICENSE](LICENSE).