@syncedco/flow 0.3.1 → 0.4.1

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/dist/index.js CHANGED
@@ -42,10 +42,79 @@ export const fluidSystem = {
42
42
  },
43
43
  components: {
44
44
  button: 'sf-button',
45
+ buttonGroup: 'sf-button-group',
46
+ icon: 'sf-icon',
47
+ iconButton: 'sf-icon-button',
45
48
  card: 'sf-card',
49
+ surface: 'sf-surface',
50
+ hero: 'sf-hero',
51
+ logoCloud: 'sf-logo-cloud',
52
+ feature: 'sf-feature',
53
+ stats: 'sf-stats',
54
+ testimonial: 'sf-testimonial',
55
+ pricingGrid: 'sf-pricing-grid',
56
+ faq: 'sf-faq',
57
+ callToAction: 'sf-cta',
58
+ footer: 'sf-footer',
46
59
  badge: 'sf-badge',
60
+ avatar: 'sf-avatar',
61
+ alert: 'sf-alert',
62
+ status: 'sf-status',
63
+ sectionHeader: 'sf-section-header',
64
+ kicker: 'sf-kicker',
65
+ nav: 'sf-nav',
66
+ form: 'sf-form',
67
+ fieldset: 'sf-fieldset',
47
68
  field: 'sf-field',
69
+ label: 'sf-label',
70
+ help: 'sf-help',
71
+ error: 'sf-error',
48
72
  input: 'sf-input',
73
+ inputGroup: 'sf-input-group',
74
+ select: 'sf-select',
75
+ textarea: 'sf-textarea',
76
+ check: 'sf-check',
77
+ switch: 'sf-switch',
78
+ fileInput: 'sf-file-input',
79
+ range: 'sf-range',
80
+ segmentedControl: 'sf-segmented-control',
81
+ spinner: 'sf-spinner',
82
+ search: 'sf-search',
83
+ combobox: 'sf-combobox',
84
+ filterBar: 'sf-filter-bar',
85
+ bulkActions: 'sf-bulk-actions',
86
+ dataTable: 'sf-data-table',
87
+ tableSort: 'sf-table-sort',
88
+ dataList: 'sf-data-list',
89
+ emptyState: 'sf-empty-state',
90
+ settingsSection: 'sf-settings-section',
91
+ detailPanel: 'sf-detail-panel',
92
+ dialog: 'sf-dialog',
93
+ popover: 'sf-popover',
94
+ drawer: 'sf-drawer',
95
+ tooltip: 'sf-tooltip',
96
+ toast: 'sf-toast',
97
+ toastStack: 'sf-toast-stack',
98
+ banner: 'sf-banner',
99
+ disclosure: 'sf-disclosure',
100
+ accordion: 'sf-accordion',
101
+ tabs: 'sf-tabs',
102
+ tab: 'sf-tab',
103
+ menu: 'sf-menu',
104
+ breadcrumb: 'sf-breadcrumb',
105
+ pagination: 'sf-pagination',
106
+ stepper: 'sf-stepper',
107
+ wizardActions: 'sf-wizard-actions',
108
+ progress: 'sf-progress',
109
+ skeleton: 'sf-skeleton',
110
+ chart: 'sf-chart',
111
+ meter: 'sf-meter',
112
+ codeWindow: 'sf-code-window',
113
+ codeLines: 'sf-code-lines',
114
+ tokenStrip: 'sf-token-strip',
115
+ marquee: 'sf-marquee',
116
+ commandList: 'sf-command-list',
117
+ platformCard: 'sf-platform-card',
49
118
  },
50
119
  utilities: {
51
120
  visuallyHidden: 'sf-visually-hidden',
@@ -27,6 +27,8 @@ semantic HTML and ARIA states are visible, consistent, and easy to compose.
27
27
  | `[aria-disabled="true"]`, `:disabled` | Disabled affordance for buttons, links, cards, and form controls. |
28
28
  | `[aria-busy="true"]`, `[data-loading="true"]` | Busy/loading affordance for buttons and form controls. |
29
29
  | `.sf-field[data-invalid="true"]`, `[aria-invalid="true"]` | Invalid field styling. |
30
+ | `.sf-switch input:checked`, `.sf-segmented-control input:checked` | Native checkbox/radio state shown without replacing the input semantics. |
31
+ | `.sf-spinner` | Presentational loading indicator with a reduced-motion fallback; text status remains required. |
30
32
  | `.sf-required`, `.sf-label[aria-required="true"]`, `label:has(+ :required)` | Required-field marker styling. |
31
33
  | `@media (forced-colors: active)` | High contrast mode border, focus, and button fallbacks. |
32
34
 
@@ -111,13 +113,22 @@ messages that need immediate announcement.
111
113
  When an action is in progress, keep the accessible name visible and add state:
112
114
 
113
115
  ```html
114
- <button class="sf-button" type="button" aria-busy="true">
115
- Saving
116
+ <button class="sf-button" type="button" aria-busy="true" aria-disabled="true">
117
+ <span class="sf-spinner" aria-hidden="true"></span>
118
+ <span>Saving…</span>
116
119
  </button>
120
+ <p class="sr-only" role="status" aria-live="polite">Saving changes</p>
117
121
  ```
118
122
 
119
123
  Synced Flow styles this as a busy state, but the consuming app should still
120
- manage focus, state changes, and completion messaging.
124
+ manage focus, state changes, and completion messaging. `aria-disabled` keeps
125
+ focus stable but does not block activation, so the app must guard its handler.
126
+ Native `disabled` is also valid when removing the action from focus order is
127
+ preferable.
128
+
129
+ For a searchable select, the `sf-combobox` classes only style the shell. The
130
+ app must implement the full combobox keyboard and ARIA contract. A static
131
+ `role="combobox"` without synchronized state is not production-ready.
121
132
 
122
133
  ## Confidence Checklist
123
134
 
package/docs/ai-usage.md CHANGED
@@ -53,7 +53,9 @@ before finalising the theme.
53
53
  `sf-split`, and `sf-sidebar` before writing custom layout CSS.
54
54
  - Use semantic colours: `bg-background`, `text-foreground`, `bg-primary`,
55
55
  `text-primary-foreground`, `border-border`, `bg-surface`.
56
- - Use `sf-button`, `sf-card`, `sf-badge`, `sf-field`, and `sf-input` for common UI.
56
+ - Use `sf-button`, `sf-card`, `sf-badge`, `sf-field`, `sf-input`, `sf-switch`,
57
+ `sf-input-group`, `sf-file-input`, `sf-range`, and `sf-segmented-control` for
58
+ common UI.
57
59
  - Keep browser affordances unless the UI intentionally replaces them: body
58
60
  links stay underlined, content lists keep markers, and focus states remain
59
61
  visible.
@@ -78,6 +80,9 @@ before finalising the theme.
78
80
  - Choose `saas-landing` for public SaaS marketing pages. Choose
79
81
  `saas-dashboard` for authenticated app UI, admin panels, portals, CRMs,
80
82
  analytics dashboards, metrics, tables, account menus, and login state.
83
+ - Choose `app-settings-workflow` for richer forms. Use the
84
+ `searchable-select`, `bulk-actions-toolbar`, `complete-pagination`, and
85
+ `multi-step-form` patterns for app-owned interactive behavior.
81
86
  - Treat auth recipe markup as UI only; sessions, providers, permissions, and
82
87
  sign-out logic belong to the consuming app.
83
88
  - Keep class names complete in source files. Do not build classes from fragments.
@@ -110,3 +115,19 @@ pnpm flow:doctor
110
115
  ```
111
116
 
112
117
  If `doctor` warns about stale CSS, run `pnpm flow:build`.
118
+
119
+ ## Machine-Readable Integration
120
+
121
+ Synced Flow does not ship an MCP server. AI and external tool integrations
122
+ should use the local CLI as the canonical discovery surface:
123
+
124
+ ```bash
125
+ pnpm exec synced-flow tokens --json
126
+ pnpm exec synced-flow catalog --json
127
+ pnpm exec synced-flow suggest "searchable select settings" --json
128
+ pnpm exec synced-flow pattern searchable-select --json
129
+ pnpm exec synced-flow recipe app-settings-workflow --json
130
+ ```
131
+
132
+ This keeps component names, app-owned behavior notes, accessibility guidance,
133
+ and copy-ready markup in one versioned contract.
@@ -14,10 +14,12 @@ These are intended for application code and examples.
14
14
  | Tokens | Unlayered `--sf-*` custom properties emitted by `tokens.css` |
15
15
  | Theme config | `theme.fonts`, `theme.colours`, `theme.darkColours`, `theme.radii`, `theme.layout`, `theme.components` |
16
16
  | Layout classes | `sf-container`, `sf-section`, `sf-stack`, `sf-flow`, `sf-cluster`, `sf-repel`, `sf-toolbar`, `sf-app-shell`, `sf-app-header`, `sf-app-sidebar`, `sf-app-backdrop`, `sf-app-main`, `sf-auto-grid`, `sf-switcher`, `sf-sidebar`, `sf-split`, `sf-frame`, `sf-cover`, `sf-metric-grid`, `sf-pipeline` |
17
- | Components | `sf-button`, `sf-icon`, `sf-icon-button`, `sf-avatar`, `sf-chart`, `sf-meter`, `sf-progress`, `sf-skeleton`, `sf-filter-bar`, `sf-search`, `sf-data-table`, `sf-table-sort`, `sf-status`, `sf-data-list`, `sf-empty-state`, `sf-settings-section`, `sf-detail-panel`, `sf-card`, `sf-surface`, `sf-hero`, `sf-nav`, `sf-form`, `sf-field`, `sf-input`, `sf-select`, `sf-textarea`, `sf-check`, `sf-alert`, `sf-badge`, `sf-section-header`, `sf-kicker` |
18
- | Native components | `sf-dialog`, `sf-popover`, `sf-tooltip`, `sf-drawer`, `sf-drawer--stack`, `sf-disclosure`, `sf-accordion`, `sf-tabs`, `sf-tab__count`, `sf-menu`, `sf-breadcrumb`, `sf-pagination`, `sf-toast-stack` |
17
+ | Components | `sf-button`, `sf-spinner`, `sf-icon`, `sf-icon-button`, `sf-avatar`, `sf-chart`, `sf-meter`, `sf-progress`, `sf-skeleton`, `sf-filter-bar`, `sf-search`, `sf-input-group`, `sf-file-input`, `sf-range`, `sf-switch`, `sf-segmented-control`, `sf-combobox`, `sf-bulk-actions`, `sf-stepper`, `sf-wizard-actions`, `sf-data-table`, `sf-table-sort`, `sf-status`, `sf-data-list`, `sf-empty-state`, `sf-settings-section`, `sf-detail-panel`, `sf-card`, `sf-surface`, `sf-hero`, `sf-nav`, `sf-form`, `sf-field`, `sf-input`, `sf-select`, `sf-textarea`, `sf-check`, `sf-alert`, `sf-badge`, `sf-section-header`, `sf-kicker` |
18
+ | Native components | `sf-dialog`, `sf-popover`, `sf-tooltip`, `sf-drawer`, `sf-drawer--stack`, `sf-disclosure`, `sf-accordion`, `sf-tabs`, `sf-tab__count`, `sf-menu`, `sf-breadcrumb`, `sf-pagination`, `sf-pagination__*`, `sf-toast-stack` |
19
19
  | Website patterns | `sf-logo-cloud`, `sf-feature`, `sf-stats`, `sf-testimonial`, `sf-pricing-grid`, `sf-price-card`, `sf-faq`, `sf-cta`, `sf-footer` |
20
+ | Technical presentation | `sf-code-window`, `sf-code-lines`, `sf-code-block`, `sf-code-token--*`, `sf-token-strip`, `sf-marquee`, `sf-command-list`, `sf-platform-card` |
20
21
  | Utilities | `sf-prose`, `sf-link`, `sf-link-subtle`, `sf-link-plain`, `sf-list-*`, `sf-push-*`, `sf-focus-ring`, `sf-touch-target`, `sf-skip-link`, `sr-only`, `not-sr-only` |
22
+ | TypeScript runtime | `cx()` and the typed `fluidSystem.layout`, `fluidSystem.components`, and `fluidSystem.utilities` class shortcuts exported from `@syncedco/flow` |
21
23
  | CLI | `synced-flow init`, `agents install`, `agents status`, `skill`, `add defaults`, `build`, `watch`, `lint`, `doctor`, `tokens`, `catalog`, `suggest`, `pattern`, `recipe`, `theme init`, `theme validate` |
22
24
 
23
25
  ## AI Agent Contract
@@ -35,6 +37,12 @@ The project-level AI setup commands are public in 0.x:
35
37
  `catalog --json` includes `patterns[]` with copy-ready interaction metadata:
36
38
  classes, markup, JS requirement notes, accessibility notes, and gotchas.
37
39
 
40
+ The package does not own an MCP server. Its supported machine-readable
41
+ integration is the local CLI: `tokens --json`, `catalog --json`, `suggest
42
+ --json`, and `pattern`/`recipe` JSON or markup output. External MCP tools may
43
+ invoke those commands, but they should treat the CLI output as the package
44
+ contract rather than maintaining a separate component inventory.
45
+
38
46
  ## Internal Or Compatibility Surface
39
47
 
40
48
  These can change more freely.
@@ -68,13 +68,14 @@ than implying runtime AI integration.
68
68
 
69
69
  ## App-tier coverage gaps (from real CRM adoption)
70
70
 
71
- Shipped and adopted: app-shell, data-table, empty-state, filter-bar, status
72
- chips, tabs, toast skin, form field shells. Still missing for production app
73
- work (CRM kept custom or deferred): combobox/searchable select, pagination
74
- depth (page size, jump-to-page), modal-with-form as a primitive (not just a
75
- pattern), bulk-actions toolbar, multi-step/wizard, skeleton loading compounds,
76
- sticky-header + horizontal-scroll tables. Kanban/timesheet/invoice-doc are
77
- deliberately consumer-specific and out of scope.
71
+ Shipped and adopted at audit time: app-shell, data-table, empty-state,
72
+ filter-bar, status chips, tabs, toast skin, and form field shells. The later
73
+ component-completeness batch adds the missing searchable-select presentation
74
+ shell, page-size/jump pagination, bulk-actions toolbar, multi-step/wizard
75
+ structure, switch, grouped/file/range inputs, segmented choice, and compact
76
+ loading button. JavaScript state and keyboard behavior remain app-owned where
77
+ the browser has no complete native primitive. Kanban/timesheet/invoice-doc
78
+ remain deliberately consumer-specific and out of scope.
78
79
 
79
80
  ## Strengths (keep doing)
80
81
 
@@ -97,13 +98,13 @@ deliberately consumer-specific and out of scope.
97
98
  **0.4.0 — structural gaps:**
98
99
  6. Continue dark-mode validation with a real consumer using Flow's built-in
99
100
  theme selectors.
100
- 7. Begin app-tier depth: combobox, pagination, modal-with-form, bulk-actions —
101
- prioritised by what the CRM had to keep custom.
101
+ 7. Add app-tier depth: combobox presentation, pagination, modal-with-form,
102
+ bulk-actions, and wizard structure. ✅ Implemented after the audit.
102
103
 
103
104
  **Docs / positioning / CI (cheap, high-trust):**
104
- 8. CI: smoke-build the examples; add a test asserting the CLI catalog matches
105
- the shipped CSS (in sync today only by hand); consider a CSS parse/lint and
106
- a small visual-regression pass.
105
+ 8. CI: the component-completeness batch adds a regression assertion that every
106
+ catalogued component selector ships in `styles.css`. Example smoke builds,
107
+ CSS parsing, and broader visual regression remain useful future additions.
107
108
 
108
109
  ## Meta-observation
109
110
 
@@ -111,3 +111,8 @@ The base layer uses cascade layers, logical properties, low-specificity
111
111
  `prefers-reduced-motion`. Utopia informs the fluid type, space, and grid
112
112
  tokens; Synced Flow owns the reset, accessibility helpers, and component
113
113
  defaults.
114
+
115
+ The root element is kept at `font-size: 100%` rather than a fixed pixel value so
116
+ browser and user font-size settings remain respected. Body copy starts from the
117
+ fluid text token with `body { font-size: var(--sf-text-base); }`, where
118
+ `--sf-text-base` maps to the existing body type scale.
@@ -189,9 +189,11 @@ pnpm exec synced-flow pattern mobile-nav-drawer --framework next --markup
189
189
  pnpm exec synced-flow pattern scroll-viewport-sections --json
190
190
  ```
191
191
 
192
- Current interaction patterns include `mobile-nav-drawer`,
193
- `scroll-viewport-sections`, `scroll-viewport-with-spy`,
194
- `native-dialog-react`, and `popover-drawer-layout`. Pattern JSON includes
192
+ Current interaction patterns include native navigation and overlays, app shell
193
+ and data patterns, plus `switch-control`, `input-group`,
194
+ `native-file-and-range`, `segmented-control`, `loading-button`,
195
+ `searchable-select`, `bulk-actions-toolbar`, `complete-pagination`, and
196
+ `multi-step-form`. Pattern JSON includes
195
197
  classes, framework markup, JS requirement notes, accessibility notes, and
196
198
  implementation gotchas.
197
199
 
@@ -210,9 +212,10 @@ pnpm exec synced-flow recipe coming-soon --json
210
212
 
211
213
  Current recipes include SaaS landing, scroll portfolio, agency homepage, blog
212
214
  index, article page, about timeline, team grid, contact page, 404, coming soon,
213
- and SaaS dashboard. Use `saas-landing` for public product marketing and
214
- `saas-dashboard` for authenticated app UI with account state, metrics, tables,
215
- and workspace navigation. Recipes are composed from public `sf-*` classes and
215
+ SaaS dashboard, and application settings workflow. Use `saas-landing` for
216
+ public product marketing, `saas-dashboard` for authenticated app UI, and
217
+ `app-settings-workflow` for the richer form-control surface. Recipes are
218
+ composed from public `sf-*` classes and
216
219
  are intended as copy-paste starting points rather than new utility APIs.
217
220
 
218
221
  Use `--framework html`, `--framework next`, `--framework react`, or
@@ -52,8 +52,8 @@ theme: {
52
52
  colours: {
53
53
  background: 'oklch(98.6% 0.006 80)',
54
54
  foreground: 'oklch(18% 0.026 250)',
55
- primary: 'oklch(68% 0.18 44)',
56
- primaryHover: 'oklch(60% 0.18 44)',
55
+ primary: 'oklch(50% 0.16 40)',
56
+ primaryHover: 'oklch(44% 0.14 40)',
57
57
  primaryForeground: 'oklch(100% 0 0)',
58
58
  border: 'oklch(18% 0.026 250 / 0.12)',
59
59
  },
@@ -1,6 +1,6 @@
1
1
  # CSS Optimisation Notes
2
2
 
3
- Current measurements from `pnpm build` on 2026-05-24.
3
+ Current measurements from `pnpm build` on 2026-09-09.
4
4
 
5
5
  ## Developer Notes
6
6
 
@@ -33,14 +33,14 @@ Sizes are raw bytes and gzip bytes from `gzip -c`.
33
33
 
34
34
  | File | Raw | Gzip | Use |
35
35
  | --- | ---: | ---: | --- |
36
- | `tokens.css` | 9,505 B | 2,232 B | Design tokens only. |
37
- | `reset.css` | 713 B | 430 B | Reset layer only. |
38
- | `base.css` | 3,455 B | 1,152 B | Base element styles. |
39
- | `defaults.css` | 505 B | 296 B | Optional site/UI defaults for raw links, lists, and controls. |
40
- | `layout.css` | 7,510 B | 1,866 B | Layout primitives such as container, stack, grid, app shell, sidebar, scroll snap, sticky, media object, and split. |
41
- | `components.css` | 31,195 B | 5,001 B | Component primitives such as button, icon, avatar, chart, card, surface, nav, form, alert, native overlays, disclosure, tabs, website patterns, accessibility states, and input. |
42
- | `utilities.css` | 7,498 B | 1,886 B | Static type, prose, content, positioning, motion, accessibility, link, list, colour, border, and shadow helpers. |
43
- | `styles.css` | 59,051 B | 10,457 B | Full core stylesheet with tokens, reset, base, layout, components, and utilities. |
36
+ | `tokens.css` | 11,953 B | 2,563 B | Design tokens only. |
37
+ | `reset.css` | 731 B | 435 B | Reset layer only. |
38
+ | `base.css` | 3,477 B | 1,163 B | Base element styles. |
39
+ | `defaults.css` | 506 B | 302 B | Optional site/UI defaults for raw links, lists, and controls. |
40
+ | `layout.css` | 12,195 B | 2,820 B | Layout primitives such as container, stack, grid, app shell, sidebar, scroll snap, sticky, media object, and split. |
41
+ | `components.css` | 62,874 B | 9,319 B | Component primitives including complete forms, app data controls, native overlays, website patterns, loading states, and technical presentation. |
42
+ | `utilities.css` | 7,550 B | 1,902 B | Static type, prose, content, positioning, motion, accessibility, link, list, colour, border, and shadow helpers. |
43
+ | `styles.css` | 97,950 B | 15,776 B | Full core stylesheet with tokens, reset, base, layout, components, and utilities. |
44
44
 
45
45
  Example generated project CSS with tokens plus one scanned `text-primary`
46
46
  utility measured 7,031 B raw and 1,943 B gzip.
@@ -91,7 +91,7 @@ Safe claims:
91
91
 
92
92
  - Modern CSS-first: Synced Flow uses cascade layers, custom properties,
93
93
  `clamp()`, logical properties, OKLCH colour, and container-aware primitives.
94
- - Compact by default: the full core stylesheet is currently about 10.5 KB gzip.
94
+ - Compact by default: the full core stylesheet is currently about 15.8 KB gzip.
95
95
  - Flexible loading: developers can import only the CSS layers their project
96
96
  uses.
97
97
  - Source-scanned utilities: project utility CSS is generated from actual class
@@ -25,6 +25,127 @@ Synced Flow sets `color-scheme` for native controls, forms, dialogs, and
25
25
  popover-backed UI. Projects can toggle the attribute however they like; the
26
26
  package does not ship a JavaScript theme switcher.
27
27
 
28
+ ## Switches And Segmented Choices
29
+
30
+ Use `sf-switch` only for a strict binary setting. The native checkbox owns the
31
+ checked, keyboard, disabled, and form states. Keep the visible label unchanged
32
+ when the value changes, and do not use `indeterminate` or `aria-checked="mixed"`
33
+ for this pattern.
34
+
35
+ ```html
36
+ <label class="sf-switch">
37
+ <input type="checkbox" role="switch" name="notifications" checked>
38
+ <span class="sf-switch__control" aria-hidden="true"></span>
39
+ <span class="sf-switch__label">Email notifications</span>
40
+ </label>
41
+ ```
42
+
43
+ Checkboxes do not have a native read-only state. Use `disabled` when a setting
44
+ is unavailable. If a product needs a focusable but non-editable explanation,
45
+ the app must implement and test that behavior rather than adding `readonly` to
46
+ the checkbox.
47
+
48
+ State mapping is deliberately small: omit `checked` for off, add `checked` for
49
+ on, rely on native `:focus-visible` for keyboard focus, and add `disabled` to
50
+ the input when unavailable. The visible label must stay the same in every
51
+ state.
52
+
53
+ Use the radio-backed segmented control for one choice from a small set. It is a
54
+ form control, not a tab list and not a group of independent switches.
55
+
56
+ ```html
57
+ <fieldset class="sf-fieldset">
58
+ <legend>Billing cycle</legend>
59
+ <div class="sf-segmented-control">
60
+ <label class="sf-segmented-control__option">
61
+ <input type="radio" name="cycle" value="monthly" checked>
62
+ <span class="sf-segmented-control__label">Monthly</span>
63
+ </label>
64
+ <label class="sf-segmented-control__option">
65
+ <input type="radio" name="cycle" value="annual">
66
+ <span class="sf-segmented-control__label">Annual</span>
67
+ </label>
68
+ </div>
69
+ </fieldset>
70
+ ```
71
+
72
+ Both controls include light/dark token behavior, visible keyboard focus,
73
+ disabled styling, forced-colors fallbacks, and reduced-motion handling.
74
+
75
+ ## Input Groups, File Inputs, And Range Inputs
76
+
77
+ `sf-input-group` composes one flexible input with leading/trailing content or
78
+ an inline action. Prefixes that repeat visible label context should be hidden
79
+ from assistive technology. Use `sf-search` for a normal search field.
80
+
81
+ ```html
82
+ <label class="sf-field">
83
+ <span class="sf-label">Monthly budget</span>
84
+ <span class="sf-input-group">
85
+ <span class="sf-input-group__leading" aria-hidden="true">£</span>
86
+ <input class="sf-input" name="budget" inputmode="decimal">
87
+ <span class="sf-input-group__trailing" aria-hidden="true">GBP</span>
88
+ </span>
89
+ </label>
90
+ ```
91
+
92
+ Use `sf-file-input` and `sf-range` on their native input types. File previews,
93
+ upload limits, live range output, and persistence belong to the app.
94
+
95
+ ```html
96
+ <label class="sf-field">
97
+ <span class="sf-label">Supporting document</span>
98
+ <input class="sf-file-input" type="file" accept=".pdf,.doc,.docx">
99
+ <span class="sf-help">PDF or Word, up to 10 MB.</span>
100
+ </label>
101
+
102
+ <label class="sf-field">
103
+ <span class="sf-label">Team size: <output for="team-size">12</output></span>
104
+ <input class="sf-range" id="team-size" type="range" min="1" max="50" value="12">
105
+ </label>
106
+ ```
107
+
108
+ ## Loading Buttons
109
+
110
+ `sf-spinner` is a presentational indicator. A pending action must also expose a
111
+ text status and use app state to prevent duplicate submission.
112
+
113
+ ```html
114
+ <button class="sf-button" type="submit" aria-busy="true" aria-disabled="true">
115
+ <span class="sf-spinner" aria-hidden="true"></span>
116
+ <span>Saving…</span>
117
+ </button>
118
+ <p class="sr-only" role="status" aria-live="polite">Saving changes</p>
119
+ ```
120
+
121
+ The spinner stops rotating under reduced motion while remaining visible.
122
+ `aria-disabled` keeps an in-flight button in the focus order, but the app must
123
+ prevent click and submit activation while it is set. Use native `disabled`
124
+ instead when removing the action from the focus order is the better tradeoff.
125
+
126
+ ## App-Owned Interactive Shells
127
+
128
+ Synced Flow includes presentation classes for searchable selects, selection
129
+ toolbars, complete pagination, and multi-step forms. The copy-ready contracts
130
+ live in the CLI:
131
+
132
+ ```bash
133
+ pnpm exec synced-flow pattern searchable-select --markup
134
+ pnpm exec synced-flow pattern bulk-actions-toolbar --markup
135
+ pnpm exec synced-flow pattern complete-pagination --markup
136
+ pnpm exec synced-flow pattern multi-step-form --markup
137
+ ```
138
+
139
+ The combobox shell does not implement filtering or keyboard behavior. The app
140
+ must synchronize `aria-expanded`, `aria-controls`, `aria-activedescendant`, and
141
+ `aria-selected`, and test the complete interaction with keyboard and assistive
142
+ technology. Bulk selection, client-side pagination state, step validation,
143
+ focus movement, persistence, and history are also app-owned.
144
+
145
+ For a completed wizard step, include hidden text such as
146
+ `<span class="sr-only">Completed: </span>` before the visible label. The tick
147
+ or marker may remain `aria-hidden`; completion must still be available as text.
148
+
28
149
  ## Dialog
29
150
 
30
151
  Use `<dialog>` for modal UI. Style the dialog with `sf-dialog` and structure it
package/docs/patterns.md CHANGED
@@ -31,6 +31,15 @@ pnpm exec synced-flow pattern scroll-viewport-sections --json
31
31
  | `data-table` | Native responsive table markup with status pills. |
32
32
  | `empty-state` | No-results and first-run states with clear next actions. |
33
33
  | `settings-section` | Settings/detail sections for account, team, billing, and security screens. |
34
+ | `switch-control` | Native checkbox-backed binary setting switch. |
35
+ | `input-group` | Prefix, suffix, unit, or inline-action input composition. |
36
+ | `native-file-and-range` | Styled native file and bounded range inputs. |
37
+ | `segmented-control` | Native radio-backed mutually exclusive choice. |
38
+ | `loading-button` | Busy action with spinner and text/live-region guidance. |
39
+ | `searchable-select` | Presentation shell and complete app-owned combobox contract. |
40
+ | `bulk-actions-toolbar` | Selection count and list/table actions. |
41
+ | `complete-pagination` | Result context, page links, page size, and direct page entry. |
42
+ | `multi-step-form` | Step progress and form navigation structure with textual current and completed states. |
34
43
 
35
44
  Pattern JSON includes:
36
45
 
@@ -43,3 +52,12 @@ Pattern JSON includes:
43
52
  Use patterns before hand-rolling interaction markup. Use recipes for full-page
44
53
  composition and patterns for the tricky native interaction details inside those
45
54
  pages.
55
+
56
+ Patterns with `requiresJs: true` are presentation and markup contracts. Synced
57
+ Flow deliberately does not pretend that CSS supplies combobox keyboard
58
+ behavior, async state, row selection, or wizard validation. The consuming app
59
+ owns those behaviors and their browser/assistive-technology tests.
60
+
61
+ Wizard completion cannot rely on the tick marker alone. Keep that decorative
62
+ marker hidden from assistive technology and prefix completed labels with
63
+ screen-reader text such as `Completed:`.
@@ -50,10 +50,11 @@ theme: {
50
50
  display: 'Fraunces, Georgia, serif',
51
51
  },
52
52
  colours: {
53
- primary: 'oklch(68% 0.18 44)',
53
+ primary: 'oklch(50% 0.16 40)',
54
+ primaryHover: 'oklch(44% 0.14 40)',
54
55
  primaryForeground: 'oklch(100% 0 0)',
55
56
  accent: 'oklch(70% 0.12 205)',
56
- ring: 'oklch(68% 0.18 44)',
57
+ ring: 'oklch(50% 0.16 40)',
57
58
  },
58
59
  components: {
59
60
  button: { radius: '0.5rem' },
@@ -153,7 +154,8 @@ export default defineConfig({
153
154
  display: 'Fraunces, Georgia, serif',
154
155
  },
155
156
  colours: {
156
- primary: 'oklch(68% 0.18 44)',
157
+ primary: 'oklch(50% 0.16 40)',
158
+ primaryHover: 'oklch(44% 0.14 40)',
157
159
  secondary: 'oklch(62% 0.12 205)',
158
160
  tertiary: 'oklch(64% 0.14 185)',
159
161
  primaryForeground: 'oklch(100% 0 0)',
@@ -174,7 +176,7 @@ Use the CSS entry file for one-off local overrides.
174
176
 
175
177
  :root {
176
178
  --sf-font-sans: Inter, ui-sans-serif, system-ui, sans-serif;
177
- --sf-colour-primary: oklch(68% 0.18 44);
179
+ --sf-colour-primary: oklch(50% 0.16 40);
178
180
  }
179
181
  ```
180
182
 
package/docs/recipes.md CHANGED
@@ -21,6 +21,7 @@ Available recipe ids:
21
21
 
22
22
  - `saas-landing`
23
23
  - `saas-dashboard`
24
+ - `app-settings-workflow`
24
25
  - `portfolio-scroll`
25
26
  - `agency-home`
26
27
  - `blog-index`
@@ -31,6 +32,17 @@ Available recipe ids:
31
32
  - `not-found`
32
33
  - `coming-soon`
33
34
 
35
+ `app-settings-workflow` composes the switch, grouped input, file and range
36
+ inputs, segmented choice, combobox presentation shell, stepper, wizard actions,
37
+ and loading-button structure. Generate the complete copy-ready markup with:
38
+
39
+ ```bash
40
+ pnpm exec synced-flow recipe app-settings-workflow --markup
41
+ ```
42
+
43
+ The consuming app still owns async state, upload handling, live range output,
44
+ combobox keyboard behavior, step validation, persistence, and focus movement.
45
+
34
46
  ## Marketing Homepage
35
47
 
36
48
  ```html
@@ -34,10 +34,19 @@ keep the CSS affordances in place.
34
34
  the system provides matching primitives.
35
35
  - Native disabled, required, invalid, `details[open]`, and `:target` states are
36
36
  styled.
37
+ - Checkbox-backed switches remain strictly binary and radio-backed segmented
38
+ controls preserve native keyboard behavior.
39
+ - Loading indicators have a text status; reduced motion leaves a visible
40
+ non-rotating indicator.
41
+ - App-owned combobox, bulk-selection, pagination, and wizard examples clearly
42
+ name the JavaScript and focus behavior the consumer must implement.
37
43
  - Forced-colors fallbacks keep borders and focus outlines visible.
38
44
  - `prefers-reduced-motion` is respected by the base styles.
39
45
  - Examples use semantic landmarks, real buttons, real links, labels, help text,
40
46
  and native disclosure controls.
47
+ - Every catalogue pattern and recipe has valid IDs and ID references and passes
48
+ automated WCAG A/AA checks in light and dark themes.
49
+ - Native component behaviour passes in Chromium, Firefox, and WebKit.
41
50
 
42
51
  ## Documentation Checks
43
52
 
@@ -51,23 +60,39 @@ keep the CSS affordances in place.
51
60
  ## Commands
52
61
 
53
62
  ```bash
54
- pnpm build
63
+ pnpm install --ignore-scripts
64
+ pnpm build:types
65
+ pnpm check:generated
55
66
  pnpm check
56
67
  pnpm test
68
+ pnpm test:browser:all
69
+ npm pack --dry-run
57
70
  node bin/synced-flow.mjs tokens --json
58
71
  node bin/synced-flow.mjs catalog --json
72
+ node bin/synced-flow.mjs pattern switch-control --markup
73
+ node bin/synced-flow.mjs pattern searchable-select --json
74
+ node bin/synced-flow.mjs recipe app-settings-workflow --markup
59
75
  node bin/synced-flow.mjs doctor --cwd examples/plain-html
60
76
  ```
61
77
 
62
- If a browser-visible example changes, inspect it at mobile and desktop widths
63
- before calling the release ready.
78
+ Run freshness checks before `pnpm build`, `pnpm install` without
79
+ `--ignore-scripts`, or another lifecycle command can regenerate tracked CSS.
80
+ The freshness gate covers the eight package layer/bundle files plus plain HTML,
81
+ Vite, Next, Astro, and WordPress generated outputs. The unit suite semantically
82
+ compiles all 35 patterns and 12 recipes for React and Next (94 generated TSX
83
+ files), and exercises the generated React scroll-spy lifecycle. Browser tests
84
+ use shipped CSS and generated markup to cover native keyboard/form behaviour,
85
+ focus, reduced motion, forced colours, dialogs, responsive overflow, IDs, and
86
+ light/dark Axe checks.
64
87
 
65
88
  ## npm Trusted Publishing
66
89
 
67
- Publishing is handled by `.github/workflows/npm-publish.yml` when a `v*` tag is
68
- pushed. The workflow checks that the tag matches `package.json`, installs with
69
- pnpm, runs tests, verifies package contents, and publishes with npm trusted
70
- publishing.
90
+ Pull requests and `main` use `.github/workflows/ci.yml` to run the freshness,
91
+ static, unit, package dry-run, and Chromium gates. Publishing is handled by
92
+ `.github/workflows/npm-publish.yml` when a `v*` tag is pushed. Its release gate
93
+ checks that the tag matches `package.json` and runs the same checks with
94
+ Chromium, Firefox, and WebKit. The publish job can start only after that gate
95
+ passes and is the only job granted npm trusted-publishing identity permission.
71
96
 
72
97
  Configure npm package trusted publishing for `@syncedco/flow` with:
73
98
 
@@ -10,7 +10,7 @@ Use the `--sf-*` variables as the stable CSS foundation.
10
10
  | Layer | Examples | Use for |
11
11
  | --- | --- | --- |
12
12
  | Font | `--sf-font-sans`, `--sf-font-display`, `--sf-font-mono` | Site typography families. |
13
- | Type | `--sf-type-body`, `--sf-type-lead`, `--sf-type-h1`, `--sf-type-display` | Fluid text sizes. |
13
+ | Type | `--sf-text-base`, `--sf-type-body`, `--sf-type-lead`, `--sf-type-h1`, `--sf-type-display` | Fluid text sizes. |
14
14
  | Space | `--sf-space-s`, `--sf-space-m-l`, `--sf-space-xl-2xl` | Fluid padding, margin, and gaps. |
15
15
  | Radius | `--sf-radius-control`, `--sf-radius-panel`, `--sf-radius-full` | Controls, panels, pills. |
16
16
  | Colour | `--sf-colour-background`, `--sf-colour-surface`, `--sf-colour-primary` | Semantic UI colour roles. |
@@ -63,18 +63,25 @@ These cover the common UI elements needed for a simple site.
63
63
  | `sf-surface`, `sf-surface--alt`, `sf-surface--raised` | Generic reusable panels. |
64
64
  | `sf-logo-cloud`, `sf-feature`, `sf-stats`, `sf-testimonial`, `sf-pricing-grid`, `sf-faq`, `sf-cta`, `sf-footer` | Common website patterns. |
65
65
  | `sf-nav`, `sf-nav__list`, `sf-nav__link` | Navigation basics. |
66
- | `sf-nav--mobile`, `sf-menu`, `sf-breadcrumb`, `sf-pagination` | Mobile, menu, breadcrumb, and paginated navigation. |
66
+ | `sf-nav--mobile`, `sf-menu`, `sf-breadcrumb`, `sf-pagination`, `sf-pagination__summary`, `sf-pagination__controls`, `sf-pagination__pages`, `sf-pagination__jump` | Mobile, menu, breadcrumb, and complete paginated navigation. |
67
67
  | `sf-dialog`, `sf-dialog__header`, `sf-dialog__body`, `sf-dialog__footer` | Native `<dialog>` styling. |
68
68
  | `sf-popover`, `sf-tooltip`, `sf-tooltip-trigger`, `sf-menu-popover`, `sf-toast`, `sf-toast-stack`, `sf-banner`, `sf-drawer` | Popover-backed native overlays and app feedback stacks. |
69
69
  | `sf-disclosure`, `sf-accordion` | Native `details`/`summary` disclosure patterns. |
70
70
  | `sf-tabs`, `sf-tab-list`, `sf-tab`, `sf-tab__count`, `sf-tab-panel` | HTML/CSS-first tab styling, including counted pill tabs. |
71
71
  | `sf-form`, `sf-fieldset`, `sf-field`, `sf-label`, `sf-help`, `sf-error` | Form structure and messaging. |
72
- | `sf-input`, `sf-select`, `sf-textarea`, `sf-search`, `sf-check` | Form controls, including search input shell. |
72
+ | `sf-input`, `sf-select`, `sf-textarea`, `sf-search`, `sf-input-group`, `sf-file-input`, `sf-range`, `sf-check` | Native form controls, search, grouped prefixes/suffixes/actions, file selection, and range input. |
73
+ | `sf-switch`, `sf-switch__control`, `sf-switch__label` | Native checkbox-backed binary setting switch. |
74
+ | `sf-segmented-control`, `sf-segmented-control__option`, `sf-segmented-control__label` | Native radio-backed single-choice control. |
75
+ | `sf-spinner` | Compact loading indicator for buttons and small async surfaces. |
73
76
  | `sf-alert`, `sf-alert--info`, `sf-alert--success`, `sf-alert--warning`, `sf-alert--danger`, `sf-alert__title` | Notices and feedback. |
74
77
  | `sf-section-header`, `sf-kicker`, `sf-badge`, `sf-avatar` | Common marketing/content and account patterns. |
75
78
  | `sf-chart`, `sf-chart__plot`, `sf-chart__svg`, `sf-chart__legend`, `sf-meter-list`, `sf-meter` | Lightweight chart shells for app-owned SVG charts and native meter bars. |
76
79
  | `sf-progress`, `sf-skeleton` | Native progress bars and CSS-only loading placeholders for async app states. |
77
80
  | `sf-filter-bar`, `sf-data-table`, `sf-table-sort`, `sf-status`, `sf-data-list`, `sf-empty-state`, `sf-settings-section`, `sf-detail-panel` | Lean application primitives for filters, operational data, status, empty states, and settings/detail screens. |
81
+ | `sf-combobox`, `sf-combobox__listbox`, `sf-combobox__option`, `sf-combobox__empty` | Presentation shell for an app-owned accessible searchable select. |
82
+ | `sf-bulk-actions`, `sf-bulk-actions__count`, `sf-bulk-actions__controls` | Selection count and actions above a list or table. |
83
+ | `sf-stepper`, `sf-stepper__step`, `sf-stepper__marker`, `sf-stepper__label`, `sf-wizard-actions` | Multi-step progress and form navigation structure. |
84
+ | `sf-code-window`, `sf-code-lines`, `sf-code-block`, `sf-token-strip`, `sf-marquee`, `sf-command-list`, `sf-platform-card` | Public technical/product presentation primitives used by the catalogue and examples. |
78
85
 
79
86
  ## Utility Classes
80
87