softr-vibe-coding 1.10.0 → 1.10.2

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.
package/CHANGELOG.md CHANGED
@@ -4,6 +4,12 @@ All notable changes to this skill are documented here. Versions follow [Semantic
4
4
 
5
5
  Entries from 1.3.1 onward are generated automatically from git commit subjects between version bumps (see `.github/workflows/publish.yml`). Entries before 1.3.1 were backfilled by hand from the existing commit history.
6
6
 
7
+ ## [1.10.2] - 2026-06-12
8
+ - Document the autoNumber-formula blank-read gotcha — a formula that references an Airtable autoNumber field frequently reads back empty through Softr's data layer even though Airtable shows the value and a data re-sync doesn't fix it (sibling formulas without an autoNumber dependency read fine). Add to datasources/airtable.md Gotchas + the Formula row of the field table, with the JS rebuild-from-autoNumber fix and the plain-text-stamped-by-automation alternative; bump to 1.10.2
9
+
10
+ ## [1.10.1] - 2026-06-12
11
+ - Document useFieldOptions companion-useRecords requirement — the hook only populates once an active useRecords in the same block has loaded the table schema; without it options settles to [] with isLoading false (bites write-only/helper blocks hardest). Add the required companion query to the example, correct the return shape to { options, isLoading } with options { id, label, color }, note the cross-table helper-block pattern, and add a prefer-live-fall-back-to-hardcoded recommendation; bump to 1.10.1
12
+
7
13
  ## [1.10.0] - 2026-06-04
8
14
  - Bundle get-airtable-base CLI script for full base metadata export; document in SKILL.md, airtable.md, fields.md
9
15
 
@@ -128,7 +128,7 @@ This script reads only **metadata**, never records. To inspect record contents i
128
128
  | Phone | Yes | |
129
129
  | Linked Record | Read/Write | Returns as `{ label, id }` objects |
130
130
  | Rollup | Read-only | |
131
- | Formula | Read-only | |
131
+ | Formula | Read-only | Reads fine for most formulas — BUT a formula that references an **autoNumber** field often comes back blank through Softr's data layer. See Gotchas → "Formulas depending on autoNumber". |
132
132
  | Lookup | Read-only | |
133
133
  | Computed | Read-only | |
134
134
  | Created Time | Read-only | |
@@ -151,6 +151,21 @@ Mitigation: Use PAT authentication. Cache data where possible. Avoid unnecessary
151
151
  - **Linked records are objects** with `{ label, id }` structure, not plain text.
152
152
  - **View connections** apply Airtable-side filters and sorts before data reaches Softr. This is useful for pre-filtering but means the Softr block only sees the view's subset.
153
153
  - **Column names are case-sensitive.** `"First name"` and `"First Name"` are different.
154
+ - **Formulas that depend on an `autoNumber` field can read back blank** (verified 2026-06-12). Softr serves most formulas fine — a `CONCATENATE` of text fields reads correctly — but a formula like `"WIG-" & RIGHT("0000" & {Autonumber}, 4)` frequently comes through as `""`, even though Airtable shows the value and a data re-sync doesn't fix it. The autoNumber dependency is the differentiator: a sibling formula on the same record (no autoNumber) reads fine.
155
+ - **Symptom:** one computed field is empty in `record.fields` while the rest populate; re-syncing the Softr data source doesn't help.
156
+ - **Fix:** don't read the formula — read the raw `autoNumber` field and rebuild the value in JS:
157
+ ```jsx
158
+ // q.select({ tag: "Wig Tag ID", auto: "Autonumber", ... })
159
+ function buildTag(f) {
160
+ var raw = getFieldValue(f.tag);
161
+ if (raw) return raw; // formula populated — use it
162
+ var n = f.auto;
163
+ if (n != null && typeof n === "object") n = (n.value != null) ? n.value : "";
164
+ var s = (n == null) ? "" : String(n).trim();
165
+ return s ? "WIG-" + ("0000" + s).slice(-4) : ""; // mirror the Airtable formula in JS
166
+ }
167
+ ```
168
+ - **Alternative (most robust):** add a plain single-line-text field and stamp the value into it with an Airtable automation on record create. Softr reads plain text 100% reliably, with no formula/autoNumber dependency.
154
169
 
155
170
  ## Best For
156
171
  - Teams already managing data in Airtable
@@ -108,23 +108,43 @@ var options = (result.data && result.data.pages) ? result.data.pages.flatMap(fun
108
108
  Returns the current option list for any `singleSelect` / `multipleSelects` field — without hardcoding option IDs in your block. Useful when the schema's option list changes (renames, additions, reorders) and you don't want to redeploy the block every time.
109
109
 
110
110
  ```jsx
111
- import { useFieldOptions, q } from "@/lib/datasource";
111
+ import { useFieldOptions, useRecords, q } from "@/lib/datasource";
112
+
113
+ var specSelect = q.select({ status: "Status" });
114
+
115
+ // REQUIRED: a companion records query in the SAME block loads the table schema that
116
+ // useFieldOptions reads from. Without it, useFieldOptions settles to `{ options: [] }`
117
+ // (isLoading false, length 0) even though the field has choices. count: 1 is enough.
118
+ useRecords({ select: specSelect, count: 1 });
112
119
 
113
120
  var statusOptions = useFieldOptions({
114
- select: q.select({ status: "Status" }),
121
+ select: specSelect,
115
122
  field: "status", // the ALIAS from q.select(), NOT the raw field ID
116
123
  });
117
124
 
118
- // statusOptions.options[{ id: "sel...", label: "Active" }, { id: "sel...", label: "Inactive" }]
119
- // Each item has `id` (the option's UUID, used in mutate payloads) and `label` (display string).
125
+ // statusOptions → { options: [...], isLoading: bool }
126
+ // statusOptions.options [{ id: "sel...", label: "Active", color: "greenLight1" }, ...]
127
+ // id — the option's UUID, used in mutate payloads
128
+ // label — display string
129
+ // color — Airtable swatch color name (optional; handy for tinting chips)
120
130
  ```
121
131
 
132
+ **⚠️ Gotcha — requires a companion `useRecords` (verified 2026-06-12).** `useFieldOptions`
133
+ only populates once an active `useRecords` in the same block has loaded that table's schema.
134
+ This bites hardest in **write-only / invisible helper blocks** (the natural home for an
135
+ option-publishing helper) because they otherwise never query records — so `options` stays
136
+ `[]` forever with `isLoading: false`, which looks like "the field has no choices." The fix is
137
+ a throwaway `useRecords({ select, count: 1 })` alongside the `useFieldOptions` call(s); the
138
+ same `select` object can be shared by both. Reuse one `select` for many fields and call
139
+ `useFieldOptions` once per field (alias). Symptom to recognise: hook returns
140
+ `{ options: [], isLoading: false }` while the block is correctly bound to the data source.
141
+
122
142
  **When to use this vs. hardcoding:**
123
143
 
124
- - **Use `useFieldOptions`** when option IDs / labels could change post-deploy — selects with rapidly-evolving lists, user-editable choices, or any case where re-pasting blocks for an option rename is annoying.
125
- - **Hardcode** when the option set is stable and frequently referenced (e.g. a status enum that drives a state machine), so the IDs live in source and rename-safety is enforced by greppable constants.
144
+ - **Use `useFieldOptions`** when option IDs / labels could change post-deploy — selects with rapidly-evolving lists, user-editable choices, or any case where re-pasting blocks for an option rename is annoying. Cross-table case: to render a select field from table B inside a block bound to table A (e.g. an intake form bound to Jobs that needs the Wigs `Color` options), put the `useRecords` + `useFieldOptions` in a hidden helper block bound to table B and publish the options to a `window` global (see [helper-blocks.md](../references/helper-blocks.md)).
145
+ - **Hardcode** when the option set is stable and frequently referenced (e.g. a status enum that drives a state machine), so the IDs live in source and rename-safety is enforced by greppable constants. A robust middle ground: prefer the live options, fall back to a hardcoded list per field so the UI still renders if the helper hasn't published yet.
126
146
 
127
- `useFieldOptions` is the read-side equivalent of using `useLinkedRecords` for foreign records — it abstracts away the field's option store. Items are shaped `{ id, label }` (note: `label`, not `title` like `useLinkedRecords`).
147
+ `useFieldOptions` is the read-side equivalent of using `useLinkedRecords` for foreign records — it abstracts away the field's option store. Items are shaped `{ id, label, color }` (note: `label`, not `title` like `useLinkedRecords`).
128
148
 
129
149
  ## Filtering
130
150
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "softr-vibe-coding",
3
- "version": "1.10.0",
3
+ "version": "1.10.2",
4
4
  "description": "Claude Code skill for generating production-ready Softr Vibe Coding blocks (JSX). Installs into ~/.claude/skills/ and auto-updates on each Claude Code session.",
5
5
  "bin": {
6
6
  "softr-vibe-coding": "./bin/cli.js"