axiom-coding-agent-setup 1.0.9 → 1.0.11

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 (107) hide show
  1. package/.agents/skills/agent-browser/SKILL.md +55 -0
  2. package/.agents/skills/developing-with-streamlit/SKILL.md +220 -0
  3. package/.agents/skills/developing-with-streamlit/skills/building-streamlit-chat-ui/SKILL.md +195 -0
  4. package/.agents/skills/developing-with-streamlit/skills/building-streamlit-custom-components-v2/SKILL.md +233 -0
  5. package/.agents/skills/developing-with-streamlit/skills/building-streamlit-custom-components-v2/references/packaged-components.md +212 -0
  6. package/.agents/skills/developing-with-streamlit/skills/building-streamlit-custom-components-v2/references/state-sync.md +149 -0
  7. package/.agents/skills/developing-with-streamlit/skills/building-streamlit-custom-components-v2/references/theme-css-variables.md +243 -0
  8. package/.agents/skills/developing-with-streamlit/skills/building-streamlit-custom-components-v2/references/troubleshooting.md +121 -0
  9. package/.agents/skills/developing-with-streamlit/skills/building-streamlit-dashboards/SKILL.md +147 -0
  10. package/.agents/skills/developing-with-streamlit/skills/building-streamlit-multipage-apps/SKILL.md +218 -0
  11. package/.agents/skills/developing-with-streamlit/skills/choosing-streamlit-selection-widgets/SKILL.md +139 -0
  12. package/.agents/skills/developing-with-streamlit/skills/connecting-streamlit-to-snowflake/SKILL.md +188 -0
  13. package/.agents/skills/developing-with-streamlit/skills/creating-streamlit-themes/SKILL.md +486 -0
  14. package/.agents/skills/developing-with-streamlit/skills/displaying-streamlit-data/SKILL.md +199 -0
  15. package/.agents/skills/developing-with-streamlit/skills/improving-streamlit-design/SKILL.md +191 -0
  16. package/.agents/skills/developing-with-streamlit/skills/optimizing-streamlit-performance/SKILL.md +323 -0
  17. package/.agents/skills/developing-with-streamlit/skills/organizing-streamlit-code/SKILL.md +91 -0
  18. package/.agents/skills/developing-with-streamlit/skills/setting-up-streamlit-environment/SKILL.md +128 -0
  19. package/.agents/skills/developing-with-streamlit/skills/using-streamlit-cli/SKILL.md +165 -0
  20. package/.agents/skills/developing-with-streamlit/skills/using-streamlit-custom-components/SKILL.md +170 -0
  21. package/.agents/skills/developing-with-streamlit/skills/using-streamlit-layouts/SKILL.md +229 -0
  22. package/.agents/skills/developing-with-streamlit/skills/using-streamlit-markdown/SKILL.md +207 -0
  23. package/.agents/skills/developing-with-streamlit/skills/using-streamlit-session-state/SKILL.md +144 -0
  24. package/.agents/skills/developing-with-streamlit/templates/.gitattributes +3 -0
  25. package/.agents/skills/developing-with-streamlit/templates/apps/README.md +188 -0
  26. package/.agents/skills/developing-with-streamlit/templates/apps/dashboard-companies/pyproject.toml +12 -0
  27. package/.agents/skills/developing-with-streamlit/templates/apps/dashboard-companies/streamlit_app.py +365 -0
  28. package/.agents/skills/developing-with-streamlit/templates/apps/dashboard-compute/pyproject.toml +12 -0
  29. package/.agents/skills/developing-with-streamlit/templates/apps/dashboard-compute/streamlit_app.py +461 -0
  30. package/.agents/skills/developing-with-streamlit/templates/apps/dashboard-compute-snowflake/.streamlit/secrets.toml.example +20 -0
  31. package/.agents/skills/developing-with-streamlit/templates/apps/dashboard-compute-snowflake/pyproject.toml +11 -0
  32. package/.agents/skills/developing-with-streamlit/templates/apps/dashboard-compute-snowflake/snowflake.yml +18 -0
  33. package/.agents/skills/developing-with-streamlit/templates/apps/dashboard-compute-snowflake/streamlit_app.py +527 -0
  34. package/.agents/skills/developing-with-streamlit/templates/apps/dashboard-feature-usage/pyproject.toml +12 -0
  35. package/.agents/skills/developing-with-streamlit/templates/apps/dashboard-feature-usage/streamlit_app.py +307 -0
  36. package/.agents/skills/developing-with-streamlit/templates/apps/dashboard-metrics/pyproject.toml +12 -0
  37. package/.agents/skills/developing-with-streamlit/templates/apps/dashboard-metrics/streamlit_app.py +426 -0
  38. package/.agents/skills/developing-with-streamlit/templates/apps/dashboard-metrics-snowflake/.streamlit/secrets.toml.example +20 -0
  39. package/.agents/skills/developing-with-streamlit/templates/apps/dashboard-metrics-snowflake/pyproject.toml +11 -0
  40. package/.agents/skills/developing-with-streamlit/templates/apps/dashboard-metrics-snowflake/snowflake.yml +18 -0
  41. package/.agents/skills/developing-with-streamlit/templates/apps/dashboard-metrics-snowflake/streamlit_app.py +463 -0
  42. package/.agents/skills/developing-with-streamlit/templates/apps/dashboard-seattle-weather/pyproject.toml +12 -0
  43. package/.agents/skills/developing-with-streamlit/templates/apps/dashboard-seattle-weather/streamlit_app.py +252 -0
  44. package/.agents/skills/developing-with-streamlit/templates/apps/dashboard-stock-peers/pyproject.toml +12 -0
  45. package/.agents/skills/developing-with-streamlit/templates/apps/dashboard-stock-peers/streamlit_app.py +342 -0
  46. package/.agents/skills/developing-with-streamlit/templates/apps/dashboard-stock-peers-snowflake/.streamlit/secrets.toml.example +20 -0
  47. package/.agents/skills/developing-with-streamlit/templates/apps/dashboard-stock-peers-snowflake/pyproject.toml +11 -0
  48. package/.agents/skills/developing-with-streamlit/templates/apps/dashboard-stock-peers-snowflake/snowflake.yml +18 -0
  49. package/.agents/skills/developing-with-streamlit/templates/apps/dashboard-stock-peers-snowflake/streamlit_app.py +384 -0
  50. package/.agents/skills/developing-with-streamlit/templates/themes/README.md +128 -0
  51. package/.agents/skills/developing-with-streamlit/templates/themes/_configs/dracula.toml +39 -0
  52. package/.agents/skills/developing-with-streamlit/templates/themes/_configs/github.toml +37 -0
  53. package/.agents/skills/developing-with-streamlit/templates/themes/_configs/minimal.toml +39 -0
  54. package/.agents/skills/developing-with-streamlit/templates/themes/_configs/nord.toml +39 -0
  55. package/.agents/skills/developing-with-streamlit/templates/themes/_configs/snowflake.toml +42 -0
  56. package/.agents/skills/developing-with-streamlit/templates/themes/_configs/solarized-light.toml +38 -0
  57. package/.agents/skills/developing-with-streamlit/templates/themes/_configs/spotify.toml +34 -0
  58. package/.agents/skills/developing-with-streamlit/templates/themes/_configs/stripe.toml +35 -0
  59. package/.agents/skills/developing-with-streamlit/templates/themes/_shared/streamlit_app.py +336 -0
  60. package/.agents/skills/developing-with-streamlit/templates/themes/_templates/pyproject.toml.tmpl +12 -0
  61. package/.agents/skills/developing-with-streamlit/templates/themes/dracula/.streamlit/config.toml +39 -0
  62. package/.agents/skills/developing-with-streamlit/templates/themes/dracula/pyproject.toml +10 -0
  63. package/.agents/skills/developing-with-streamlit/templates/themes/dracula/streamlit_app.py +337 -0
  64. package/.agents/skills/developing-with-streamlit/templates/themes/github/.streamlit/config.toml +37 -0
  65. package/.agents/skills/developing-with-streamlit/templates/themes/github/pyproject.toml +10 -0
  66. package/.agents/skills/developing-with-streamlit/templates/themes/github/streamlit_app.py +337 -0
  67. package/.agents/skills/developing-with-streamlit/templates/themes/manage.py +332 -0
  68. package/.agents/skills/developing-with-streamlit/templates/themes/minimal/.streamlit/config.toml +39 -0
  69. package/.agents/skills/developing-with-streamlit/templates/themes/minimal/pyproject.toml +10 -0
  70. package/.agents/skills/developing-with-streamlit/templates/themes/minimal/streamlit_app.py +337 -0
  71. package/.agents/skills/developing-with-streamlit/templates/themes/nord/.streamlit/config.toml +39 -0
  72. package/.agents/skills/developing-with-streamlit/templates/themes/nord/pyproject.toml +10 -0
  73. package/.agents/skills/developing-with-streamlit/templates/themes/nord/streamlit_app.py +337 -0
  74. package/.agents/skills/developing-with-streamlit/templates/themes/snowflake/.streamlit/config.toml +42 -0
  75. package/.agents/skills/developing-with-streamlit/templates/themes/snowflake/pyproject.toml +10 -0
  76. package/.agents/skills/developing-with-streamlit/templates/themes/snowflake/streamlit_app.py +337 -0
  77. package/.agents/skills/developing-with-streamlit/templates/themes/solarized-light/.streamlit/config.toml +38 -0
  78. package/.agents/skills/developing-with-streamlit/templates/themes/solarized-light/pyproject.toml +10 -0
  79. package/.agents/skills/developing-with-streamlit/templates/themes/solarized-light/streamlit_app.py +337 -0
  80. package/.agents/skills/developing-with-streamlit/templates/themes/spotify/.streamlit/config.toml +34 -0
  81. package/.agents/skills/developing-with-streamlit/templates/themes/spotify/pyproject.toml +10 -0
  82. package/.agents/skills/developing-with-streamlit/templates/themes/spotify/streamlit_app.py +337 -0
  83. package/.agents/skills/developing-with-streamlit/templates/themes/stripe/.streamlit/config.toml +35 -0
  84. package/.agents/skills/developing-with-streamlit/templates/themes/stripe/pyproject.toml +10 -0
  85. package/.agents/skills/developing-with-streamlit/templates/themes/stripe/streamlit_app.py +337 -0
  86. package/.agents/skills/fastapi/SKILL.md +436 -0
  87. package/.agents/skills/fastapi/references/dependencies.md +142 -0
  88. package/.agents/skills/fastapi/references/other-tools.md +76 -0
  89. package/.agents/skills/fastapi/references/streaming.md +105 -0
  90. package/.agents/skills/frontend-design/LICENSE.txt +177 -0
  91. package/.agents/skills/frontend-design/SKILL.md +42 -0
  92. package/.agents/skills/gradio/SKILL.md +84 -0
  93. package/.agents/skills/gradio/references/api-signatures.md +115 -0
  94. package/.agents/skills/gradio/references/event-listeners.md +130 -0
  95. package/.agents/skills/gradio/references/examples.md +613 -0
  96. package/.agents/skills/ui-ux-pro-max/SKILL.md +659 -0
  97. package/.agents/skills/ui-ux-pro-max/data +1 -0
  98. package/.agents/skills/ui-ux-pro-max/scripts +1 -0
  99. package/.agents/stack.md +187 -187
  100. package/.env.axiom +8 -0
  101. package/AGENTS.md +2 -1
  102. package/README.md +19 -3
  103. package/bin/cli.js +11 -1
  104. package/opencode.json +12 -4
  105. package/package.json +1 -1
  106. package/skills-lock.json +36 -0
  107. package/.agents/skills/n8n-patterns/SKILL.md +0 -272
@@ -0,0 +1,233 @@
1
+ ---
2
+ name: building-streamlit-custom-components-v2
3
+ description: Builds bidirectional Streamlit Custom Components v2 (CCv2) using `st.components.v2.component`. Use when authoring inline HTML/CSS/JS components or packaged components (manifest `asset_dir`, js/css globs), wiring state/trigger callbacks, theming via `--st-*` CSS variables, or bundling with Vite / `component-template` v2.
4
+ license: Apache-2.0
5
+ ---
6
+
7
+ # Building Streamlit custom components v2
8
+
9
+ Use Streamlit Custom Components v2 (CCv2) when core Streamlit doesn't have the UI you need and you want to ship a reusable, interactive element (from "tiny inline HTML" to "full bundled frontend app").
10
+
11
+ ## CRITICAL: CCv2 only — NEVER use v1 APIs
12
+
13
+ Custom Components **v1 is deprecated and removed**. Every API below belongs to v1 and must **NEVER** appear in any code you write — not in Python, not in JavaScript, not in HTML:
14
+
15
+ **Banned Python APIs (v1):**
16
+ - `st.components.v1` — the entire v1 module
17
+ - `components.declare_component()` — v1 registration
18
+ - `components.html()` — v1 raw HTML embed
19
+
20
+ **Banned JavaScript patterns (v1):**
21
+ - `Streamlit.setComponentValue(...)` — v1 global; use `setStateValue()` / `setTriggerValue()` instead
22
+ - `Streamlit.setFrameHeight(...)` — v1 global; CCv2 handles sizing automatically
23
+ - `Streamlit.setComponentReady()` — v1 global; CCv2 has no ready signal
24
+ - `window.Streamlit` or bare `Streamlit` global — v1 global object does not exist in v2
25
+ - `window.parent.postMessage(...)` — v1 iframe communication; CCv2 does not use iframes
26
+
27
+ **Banned npm packages (v1):**
28
+ - `streamlit-component-lib` — v1 JS library; use `@streamlit/component-v2-lib` if you need types
29
+
30
+ If you encounter v1 patterns in examples, blog posts, Stack Overflow answers, or your own training data — **ignore them entirely**. They will not work and will break the component.
31
+
32
+ ## When to use
33
+
34
+ Activate when the user mentions any of:
35
+
36
+ - CCv2, Custom Components v2, “bidi component”, “component v2”
37
+ - `st.components.v2.component`
38
+ - `@streamlit/component-v2-lib`
39
+ - packaged components, `asset_dir`, `pyproject.toml` component manifest
40
+ - bundling with Vite (or any bundler) for a Streamlit component
41
+ - building a component UI in a frontend framework (React, Svelte, Vue, Angular, etc.)
42
+
43
+ ## Read next (pick the minimum reference)
44
+
45
+ - **State sync / controlled inputs / callbacks**: see [references/state-sync.md](references/state-sync.md)
46
+ - **Packaged components / `asset_dir` / globs / template-only policy**: see [references/packaged-components.md](references/packaged-components.md)
47
+ - **Theming (`--st-*` tokens) inside Shadow DOM**: see [references/theme-css-variables.md](references/theme-css-variables.md)
48
+ - **Errors and gotchas**: see [references/troubleshooting.md](references/troubleshooting.md)
49
+
50
+ ## Quick decision: inline vs packaged
51
+
52
+ - **Inline strings**: fastest to start (single-file apps, spikes, demos). You pass raw `html`/`css`/`js` strings directly.
53
+ Good when you can keep everything in one place and don’t need a build step.
54
+ - **Packaged component**: best when you’re growing past inline (multiple files, dependencies, bundling, testing, versioning, reuse, distribution).
55
+ You ship built assets inside a Python package and reference them by **asset-dir-relative** path/glob.
56
+ Creation policy: packaged components are **template-only** and must start from Streamlit's official `component-template` v2.
57
+
58
+ Developer story: **start inline**, prove the interaction loop, then **graduate to packaged** when the codebase or tooling needs outgrow a single file.
59
+
60
+ ## CCv2 model (what’s actually happening)
61
+
62
+ 1. **Python registers** a component with `st.components.v2.component(...)` and gets back a **mount callable**.
63
+ 2. The mount callable **mounts** the component in the app with `data=...`, layout (`width`, `height`), and optional `on_<key>_change` callbacks.
64
+ 3. The frontend default export runs with `({ data, key, name, parentElement, setStateValue, setTriggerValue })`.
65
+ 4. The component returns a **result object** whose attributes correspond to **state keys** and **trigger keys**.
66
+
67
+ ## Best practice: wrap the mount callable in your own Python API
68
+
69
+ Prefer exposing **your own** Python function that wraps the callable returned by `st.components.v2.component(...)`.
70
+
71
+ This gives you a clean, stable API surface for end users (typed parameters, validation, friendly defaults) and keeps `data=...`, `default=...`, and callback wiring as an internal detail.
72
+
73
+ Important:
74
+
75
+ - Declare the component **once** (usually at module import time). Avoid defining and registering the component inside a function you call multiple times; you can accidentally re-register the component name and get confusing behavior.
76
+
77
+ References:
78
+
79
+ - [`st.components.v2.component`](https://docs.streamlit.io/develop/api-reference/custom-components/st.components.v2.component)
80
+ - [`ComponentRenderer` (mount callable type)](https://docs.streamlit.io/develop/api-reference/custom-components/st.components.v2.types.componentrenderer)
81
+
82
+ Example pattern:
83
+
84
+ ```python
85
+ import streamlit as st
86
+ from collections.abc import Callable
87
+
88
+ _MY_COMPONENT = st.components.v2.component(
89
+ "my_inline_component",
90
+ html="<div id='root'></div>",
91
+ js="""
92
+ export default function (component) {
93
+ const { data, parentElement } = component
94
+ parentElement.querySelector("#root").textContent = data?.label ?? ""
95
+ }
96
+ """,
97
+ )
98
+
99
+
100
+ def my_component(
101
+ label: str,
102
+ *,
103
+ key: str | None = None,
104
+ on_value_change: Callable[[], None] | None = None,
105
+ on_submitted_change: Callable[[], None] | None = None,
106
+ ):
107
+ # Callbacks are optional, but if you want result attributes to always exist,
108
+ # provide (even empty) callbacks.
109
+ if on_value_change is None:
110
+ on_value_change = lambda: None
111
+ if on_submitted_change is None:
112
+ on_submitted_change = lambda: None
113
+
114
+ return _MY_COMPONENT(
115
+ data={"label": label},
116
+ key=key,
117
+ on_value_change=on_value_change,
118
+ on_submitted_change=on_submitted_change,
119
+ )
120
+ ```
121
+
122
+ ## Inline quickstart (state + trigger)
123
+
124
+ **Reminder: use ONLY v2 APIs.** Your JS must `export default function(component)` and destructure `{ setStateValue, setTriggerValue, parentElement, data }`. NEVER use `Streamlit.setComponentValue()`, `window.Streamlit`, or any v1 pattern.
125
+
126
+ This is the minimum "bidi loop":
127
+
128
+ - **JS → Python**: emit updates via `setStateValue(...)` (persistent) and `setTriggerValue(...)` (event)
129
+ - **Python → JS**: re-hydrate UI via `data=...` on every run
130
+
131
+ ```python
132
+ import streamlit as st
133
+
134
+ HTML = """<input id="txt" /><button id="btn" type="button">Submit</button>"""
135
+
136
+ JS = """\
137
+ export default function (component) {
138
+ const { data, parentElement, setStateValue, setTriggerValue } = component
139
+
140
+ const input = parentElement.querySelector("#txt")
141
+ const btn = parentElement.querySelector("#btn")
142
+ if (!input || !btn) return
143
+
144
+ const nextValue = (data && data.value) ?? ""
145
+ if (input.value !== nextValue) input.value = nextValue
146
+
147
+ input.oninput = (e) => {
148
+ setStateValue("value", e.target.value)
149
+ }
150
+
151
+ btn.onclick = () => {
152
+ setTriggerValue("submitted", input.value)
153
+ }
154
+ }
155
+ """
156
+
157
+ my_text_input = st.components.v2.component(
158
+ "my_inline_text_input",
159
+ html=HTML,
160
+ js=JS,
161
+ )
162
+
163
+ KEY = "txt-1"
164
+ component_state = st.session_state.get(KEY, {})
165
+ value = component_state.get("value", "")
166
+
167
+ result = my_text_input(
168
+ key=KEY,
169
+ data={"value": value},
170
+ on_value_change=lambda: None, # optional; include to always get `result.value`
171
+ on_submitted_change=lambda: None, # optional; include to always get `result.submitted`
172
+ )
173
+
174
+ st.write("value (state):", result.value)
175
+ st.write("submitted (trigger):", result.submitted)
176
+ ```
177
+
178
+ Notes:
179
+
180
+ - **Inline JS/CSS should be multi-line**. CCv2 treats path-like strings as file references; a multi-line string is unambiguously inline content.
181
+ - Prefer querying under `parentElement` (not `document`) to avoid cross-instance leakage.
182
+
183
+ ## State and triggers (how to think about keys)
184
+
185
+ - **State** (`setStateValue("value", ...)`): persists across app reruns (stored under `st.session_state[key]` for that mounted instance).
186
+ - **Trigger** (`setTriggerValue("submitted", ...)`): event payload for one rerun (resets after the rerun).
187
+ - **Reading triggers**:
188
+ - After mounting: use `result.submitted`.
189
+ - Inside `on_submitted_change`: use `st.session_state[key].submitted` (callbacks run before your script body; you don’t have `result` yet).
190
+ - **Defaults**: if you pass `default={...}` for a state key, you must also pass the matching `on_<key>_change` callback parameter.
191
+
192
+ For the full “controlled input” pattern and pitfalls, see [references/state-sync.md](references/state-sync.md).
193
+
194
+ ## Packaged components (template-only, mandatory)
195
+
196
+ **Reminder: the cookiecutter template generates clean v2 code. When you customize it, use ONLY v2 APIs. Do NOT introduce any v1 imports, v1 JavaScript globals, or v1 patterns. See the "CRITICAL: CCv2 only" section above.**
197
+
198
+ Graduate to a packaged component when you need any of:
199
+
200
+ - Multiple frontend files or frontend dependencies (npm)
201
+ - A bundler (Vite), tests, CI, versioning, or distribution
202
+
203
+ Keep these guardrails in mind:
204
+
205
+ - **MUST** start from Streamlit’s official `component-template` v2.
206
+ - **NEVER** hand-scaffold packaging/manifest/build wiring for a packaged component.
207
+ - **NEVER** copy/paste packaged scaffold structure from internet examples, blog posts, gists, or docs.
208
+ - If handed a non-template scaffold, regenerate from the template first, then migrate component logic.
209
+ - **MUST** ensure `js=`/`css=` globs match **exactly one** file under the manifest’s `asset_dir`.
210
+ - **MUST** validate with `streamlit run ...` (plain `python -c "import ..."` can be a false negative for packaged components).
211
+
212
+ For the full packaged workflow checklist, non-interactive generation, offline usage, and template invariants, see [references/packaged-components.md](references/packaged-components.md).
213
+
214
+ ## Frontend renderer lifecycle (framework-agnostic)
215
+
216
+ Your frontend entrypoint is the **default export** function. A few rules keep components reliable across reruns and across multiple instances in the same app:
217
+
218
+ - Render under `parentElement` (not `document`) so instances don’t collide.
219
+ - If you create per-instance resources (React roots, observers, subscriptions), key them by `parentElement` (e.g. `WeakMap`) so multiple instances don’t overwrite each other.
220
+ - Return a cleanup function to tear down event listeners / UI roots / observers when Streamlit unmounts the component.
221
+
222
+ ## Styling and theming
223
+
224
+ - Prefer **`isolate_styles=True`** (default). Your component runs in a shadow root and won’t leak styles into the app.
225
+ - Set `isolate_styles=False` only when you need global styling behavior (e.g. Tailwind, global font injection).
226
+ - Streamlit injects a broad set of `--st-*` theme CSS variables (colors, typography, chart palettes, radii, borders, etc.). **Highly recommended:** use these variables so your component automatically adapts to the user’s current Streamlit theme (light/dark/custom) without authoring separate theme variants. Start with the common ones (`--st-text-color`, `--st-primary-color`, `--st-secondary-background-color`) and refer to the full list when you need it:
227
+ - [references/theme-css-variables.md](references/theme-css-variables.md)
228
+
229
+ ## Troubleshooting and gotchas
230
+
231
+ Start here when something “should work” but doesn’t:
232
+
233
+ - [references/troubleshooting.md](references/troubleshooting.md)
@@ -0,0 +1,212 @@
1
+ ## Packaged CCv2 components (template-only, mandatory)
2
+
3
+ For packaged CCv2 components, agents **MUST** use Streamlit's official template as the starting point for every new component project.
4
+
5
+ - [Streamlit component-template](https://github.com/streamlit/component-template)
6
+
7
+ Never hand-scaffold the package/manifest/build layout and never copy/paste a packaged component scaffold from blog posts, gists, docs, or other internet sources.
8
+
9
+ If a request starts from a non-template scaffold, stop and regenerate from the template first, then port logic into the generated project.
10
+
11
+ Follow your generated project's README. **Only keep reading if you need to debug template wiring or customize behavior after template generation.**
12
+
13
+ ## Contents
14
+
15
+ - Agent policy: template-only (mandatory)
16
+ - Prerequisites (packaged components)
17
+ - Start inline, then graduate to packaged
18
+ - Frontend framework note (React is optional)
19
+ - TypeScript support (recommended)
20
+ - Generate a new CCv2 component project
21
+ - Non-interactive generation (cookiecutter keys)
22
+ - Offline/airgapped
23
+ - Dev loop (template default)
24
+ - Verify the build output (prevents most load failures)
25
+ - Template invariants (don’t break these)
26
+ - Rename checklist (avoid placeholder-name drift)
27
+ - If you intentionally deviate from the template
28
+ - Verification recommendation
29
+
30
+ ### Agent policy: template-only (mandatory)
31
+
32
+ If the request is for a packaged CCv2 component:
33
+
34
+ - Start from the official template first (no exceptions).
35
+ - Never manually scaffold a custom package/manifest/build layout before template generation.
36
+ - Never copy a packaged component scaffold from the internet, even as a "starting point."
37
+ - If given existing non-template scaffolding, regenerate from the template and migrate code into it.
38
+ - Customize only after generation so you retain known-good packaging defaults.
39
+
40
+ ### Prerequisites (packaged components)
41
+
42
+ - **Python build tooling**: `uv` (recommended) + `cookiecutter`.
43
+ - **Frontend build tooling**: Node.js + npm.
44
+
45
+ ### Start inline, then graduate to packaged
46
+
47
+ Inline components are great for getting started quickly. Move to a packaged component when you hit any of these:
48
+
49
+ - You need **multiple frontend files** (components/modules) instead of one big string.
50
+ - You want to pull in **frontend libraries** (npm deps) and run a bundler.
51
+ - You need **tests**, CI, versioning, or distribution (PyPI/private index).
52
+
53
+ ### Frontend framework note (React is optional)
54
+
55
+ The official Streamlit `component-template` v2 supports both **React + TypeScript (Vite)** and **Pure TypeScript (Vite)** (no React). CCv2 also works with **any frontend framework that compiles to JavaScript** (Svelte, Vue, Angular, vanilla TS/JS, etc.).
56
+
57
+ The only requirement is that you produce JS/CSS assets into your component’s `asset_dir`, then register them from Python via `html=...`, `js="..."`, and `css="..."` using **asset-dir-relative** paths/globs.
58
+
59
+ ### TypeScript support (recommended)
60
+
61
+ For end-to-end type safety while authoring the frontend, install `@streamlit/component-v2-lib`:
62
+
63
+ - [npm package](https://www.npmjs.com/package/@streamlit/component-v2-lib)
64
+ - [docs](https://docs.streamlit.io/develop/api-reference/custom-components/component-v2-lib)
65
+
66
+ It provides TypeScript types like `FrontendRenderer` / `FrontendRendererArgs` so your `export default` renderer gets a **typed** `data` payload and typed state/trigger keys via generics.
67
+
68
+ ### Generate a new CCv2 component project
69
+
70
+ This command is the required starting point for every packaged CCv2 component:
71
+
72
+ ```bash
73
+ uvx --from cookiecutter cookiecutter gh:streamlit/component-template --directory cookiecutter/v2
74
+ ```
75
+
76
+ If you run this non-interactively, pass explicit cookiecutter values (do not rely on defaults):
77
+
78
+ Template keys:
79
+
80
+ - `author_name`
81
+ - `author_email`
82
+ - `project_name`
83
+ - `package_name`
84
+ - `import_name`
85
+ - `description`
86
+ - `open_source_license`
87
+ - `framework`
88
+
89
+ Recommended non-interactive invocation:
90
+
91
+ This sample uses a **hypothetical breadcrumb component** name so the values are concrete and meaningful:
92
+
93
+ ```bash
94
+ uvx --from cookiecutter cookiecutter gh:streamlit/component-template \
95
+ --directory cookiecutter/v2 \
96
+ --no-input \
97
+ author_name="Your Name" \
98
+ author_email="you@example.com" \
99
+ project_name="Streamlit Breadcrumbs" \
100
+ package_name="streamlit-breadcrumbs" \
101
+ import_name="streamlit_breadcrumbs" \
102
+ description="Packaged Streamlit CCv2 breadcrumb component" \
103
+ open_source_license="Apache-2.0" \
104
+ framework="React + Typescript"
105
+ ```
106
+
107
+ Notes:
108
+
109
+ - Choice values must match template options exactly (`framework` is `"React + Typescript"` or `"Pure Typescript"`).
110
+ - Passing all keys avoids template placeholder names and post-generation rename churn.
111
+
112
+ Offline/airgapped:
113
+
114
+ ```bash
115
+ uvx --from cookiecutter cookiecutter /path/to/component-template --directory cookiecutter/v2
116
+ ```
117
+
118
+ ### Dev loop (template default)
119
+
120
+ From the generated project:
121
+
122
+ 1. Activate the target project environment before Python/uv commands:
123
+
124
+ ```bash
125
+ source /path/to/project/.venv/bin/activate
126
+ ```
127
+
128
+ 2. Build the frontend assets (from `<import_name>/frontend`):
129
+
130
+ ```bash
131
+ npm i
132
+ npm run build
133
+ ```
134
+
135
+ 3. Editable install (project root containing `pyproject.toml`):
136
+
137
+ ```bash
138
+ uv pip install -e . --force-reinstall
139
+ ```
140
+
141
+ 4. Run the example app with Streamlit:
142
+
143
+ ```bash
144
+ streamlit run example.py
145
+ ```
146
+
147
+ Why this order:
148
+
149
+ - Building first ensures `asset_dir` contains the expected files before install/use.
150
+ - Reinstalling editable after key renames keeps metadata and import paths in sync.
151
+
152
+ ### Packaged component workflow (copy/paste checklist)
153
+
154
+ Use this when debugging or customizing after generation; it's designed to prevent the common "built assets exist but Streamlit can't load them" failure modes.
155
+
156
+ ```
157
+ Packaged CCv2 checklist
158
+ - [ ] Generate project from `component-template` v2
159
+ - [ ] Confirm this is template-generated (not hand-scaffolded, not copied from internet snippets)
160
+ - [ ] Activate the target project environment before Python/uv commands
161
+ - [ ] Rename template defaults (`streamlit-component-x`, `streamlit_component_x`, etc.) if needed
162
+ - [ ] Build frontend assets into the manifest’s `asset_dir` (template: `frontend/build/`)
163
+ - [ ] Editable install the Python package (`uv pip install -e . --force-reinstall`)
164
+ - [ ] Verify `js=`/`css=` globs match exactly one file each under `asset_dir`
165
+ - [ ] Run via `streamlit run ...` and confirm the component renders/events work
166
+ - [ ] If something breaks: read `references/troubleshooting.md`, fix, rebuild, re-verify glob uniqueness
167
+ ```
168
+
169
+ ### Verify the build output (prevents most load failures)
170
+
171
+ - Ensure the manifest’s `asset_dir` exists and contains the built assets.
172
+ - Ensure each glob you register from Python matches **exactly one** file under `asset_dir`:
173
+ - Typical: `js="index-*.js"` and `css="index-*.css"`
174
+ - If multiple matches: clean the build output (template: `npm run clean`) and rebuild.
175
+
176
+ ### Template invariants (don’t break these)
177
+
178
+ You typically shouldn’t need to touch these, but they explain most “why won’t this load?” failures:
179
+
180
+ - **Component key**: the Python registration key must match the manifest: `"<project.name>.<component.name>"`.
181
+ - **Manifest must ship inside the Python package**: the template places a minimal CCv2 manifest at `<import_name>/pyproject.toml` with `asset_dir = "frontend/build"`.
182
+ - **Asset paths are asset-dir-relative strings**: `js="index-*.js"` (template default output) or `js="assets/index-*.js"` (if you configured an `assets/` subdir).
183
+ - **Globs must match exactly one file**: if `index-*.js` matches multiple hashed builds, clean the build output (`npm run clean`) and rebuild.
184
+
185
+ ### Rename checklist (avoid placeholder-name drift)
186
+
187
+ Template defaults like `streamlit-component-x` / `streamlit_component_x` should be replaced everywhere early.
188
+
189
+ Rename all of these together:
190
+
191
+ - Root folder name (optional but recommended for clarity).
192
+ - Distribution name (`[project].name`) in root `pyproject.toml`.
193
+ - Import package directory (`streamlit_<real_name>`).
194
+ - In-package manifest file and contents (`<import_name>/pyproject.toml`).
195
+ - Wrapper registration key:
196
+ - `st.components.v2.component("<project.name>.<component.name>", ...)`
197
+ - `MANIFEST.in` and `[tool.setuptools.*]` references.
198
+ - README/example imports and frontend package name.
199
+
200
+ ### Allowed customizations (after template generation only)
201
+
202
+ Keep the blast radius small:
203
+
204
+ - If you change output layout, update only the `js=`/`css=` asset-dir-relative globs in the Python wrapper.
205
+ - For Vite, keep `base: "./"` so relative URLs work when served from Streamlit’s component URLs.
206
+
207
+ ### Verification recommendation
208
+
209
+ Validate packaged components with `streamlit run ...`, not plain `python -c "import ..."` checks.
210
+
211
+ - Streamlit discovers component manifests as part of runtime setup.
212
+ - Plain import checks can report false-negative `asset_dir` registration errors for otherwise-correct packaged components.
@@ -0,0 +1,149 @@
1
+ ## State sync patterns (JS ↔ Python)
2
+
3
+ This reference shows the canonical CCv2 “controlled component” loop and the most common pitfalls when syncing state between JavaScript and Python.
4
+
5
+ ## Contents
6
+
7
+ - Mental model
8
+ - Canonical pattern: controlled text input
9
+ - JavaScript (hydrate from `data`, emit via `setStateValue`)
10
+ - Python wrapper (feed state back down via `data`)
11
+ - Defaults: when to use `default=...` (and why it fails)
12
+ - Python → JS hydration: initial-only vs true sync
13
+ - Session State timing: don’t mutate after mount
14
+ - Troubleshooting checklist
15
+
16
+ ### Mental model
17
+
18
+ - **Frontend state emission (JS → Python)**: you explicitly call `setStateValue(key, value)` or `setTriggerValue(key, value)`.
19
+ - **Frontend state hydration (Python → JS)**: your JS reads `component.data` and updates the DOM accordingly.
20
+ - There is no built-in “two-way binding”: you must implement both sides.
21
+
22
+ ### Canonical pattern: controlled text input
23
+
24
+ This is modeled after Streamlit’s own CCv2 e2e example.
25
+
26
+ #### JavaScript (hydrate from `data`, emit via `setStateValue`)
27
+
28
+ Key guideline: only assign to the input when it’s different, or you’ll fight the user’s cursor.
29
+
30
+ ```js
31
+ export default function (component) {
32
+ const { parentElement, data, setStateValue } = component
33
+
34
+ const label = parentElement.querySelector("label")
35
+ const input = parentElement.querySelector("input")
36
+ if (!label || !input) return
37
+
38
+ label.innerText = data.label
39
+
40
+ const nextValue = data.value ?? ""
41
+ if (input.value !== nextValue) {
42
+ input.value = nextValue
43
+ }
44
+
45
+ input.onkeydown = e => {
46
+ if (e.key === "Enter") {
47
+ setStateValue("value", e.target.value)
48
+ }
49
+ }
50
+ }
51
+ ```
52
+
53
+ #### Python wrapper (feed state back down via `data`)
54
+
55
+ ```python
56
+ import streamlit as st
57
+
58
+ _COMPONENT = st.components.v2.component(
59
+ "interactive_text_input",
60
+ html="""
61
+ <label for="txt">Enter text:</label>
62
+ <input id="txt" type="text" />
63
+ """,
64
+ js=JS, # inline JS string from above
65
+ )
66
+
67
+
68
+ def interactive_text_input(*, label: str, initial_value: str, key: str):
69
+ # 1) Read current component state from Session State (if it exists)
70
+ component_state = st.session_state.get(key, {})
71
+
72
+ # 2) Compute the value you want the UI to display
73
+ value = component_state.get("value", initial_value)
74
+
75
+ # 3) Send it down to the frontend via `data`
76
+ return _COMPONENT(
77
+ key=key,
78
+ data={"label": label, "value": value},
79
+ )
80
+
81
+
82
+ KEY = "my_text_input"
83
+
84
+ if st.button("Make it say Hello World"):
85
+ st.session_state.setdefault(KEY, {})["value"] = "Hello World"
86
+
87
+ interactive_text_input(label="Enter something", initial_value="Initial Text", key=KEY)
88
+ ```
89
+
90
+ ### Defaults: when to use `default=...` (and why it fails)
91
+
92
+ `default={...}` is optional. Use it when you want Streamlit to initialize missing state keys for a mounted instance.
93
+
94
+ Rules:
95
+
96
+ - Defaults apply only to **state** keys (not triggers).
97
+ - Every key in `default` must have a corresponding `on_<key>_change` callback parameter when mounting, or Streamlit raises.
98
+
99
+ Pattern:
100
+
101
+ ```python
102
+ result = _COMPONENT(
103
+ key=key,
104
+ data={"value": value},
105
+ default={"value": value},
106
+ on_value_change=lambda: None, # required if using default["value"]
107
+ )
108
+ ```
109
+
110
+ ### Python → JS hydration: initial-only vs true sync
111
+
112
+ You’ll see two patterns in the wild:
113
+
114
+ - **Initial-only hydration**: JS reads `data.initialX` on first mount only. This is useful for *initialization* but it will **not** reflect later Python changes.
115
+ - **True sync (controlled)**: JS reconciles its UI from `data.value` on every render, and only writes when changed.
116
+
117
+ Initial-only example (pitfall for sync):
118
+
119
+ ```js
120
+ // If you guard hydration with hasMounted, Python changes won't propagate.
121
+ if (typeof data?.initialText !== "undefined" && !hasMountedForKey) {
122
+ input.value = String(data.initialText)
123
+ }
124
+ hasMounted[key] = true
125
+ ```
126
+
127
+ True sync approach (recommended when Python can update the UI):
128
+
129
+ ```js
130
+ const nextValue = data.value ?? ""
131
+ if (input.value !== nextValue) input.value = nextValue
132
+ ```
133
+
134
+ ### Session State timing: don’t mutate after mount
135
+
136
+ Streamlit may raise if you modify `st.session_state.<key>.<field>` **after** the component with that key has been instantiated in the same run.
137
+
138
+ Safe patterns:
139
+
140
+ - Update `st.session_state[key][...]` **before** mounting the component (e.g., in a button handler placed above the mount call).
141
+ - Or update state in a different run (trigger a rerun after setting state).
142
+
143
+ ### Troubleshooting checklist
144
+
145
+ - **Cursor jumps / typing feels broken**: ensure your JS only assigns `input.value` when it differs from the `data` value.
146
+ - **Python updates don’t reflect in UI**: confirm you pass the updated values via `data` every run; avoid initial-only hydration guards if you want true sync.
147
+ - **`default` raises**: ensure every default key has a corresponding `on_<key>_change` callback parameter.
148
+ - **Session state mutation error**: move `st.session_state[key][...] = ...` earlier in the script (before mount), or restructure into a two-run flow (set state then rerun).
149
+