@syncedco/flow 0.1.0
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/CODE_OF_CONDUCT.md +26 -0
- package/CONTRIBUTING.md +54 -0
- package/LICENSE +21 -0
- package/README.md +334 -0
- package/SECURITY.md +30 -0
- package/SUPPORT.md +32 -0
- package/TRADEMARKS.md +14 -0
- package/base.css +100 -0
- package/bin/synced-flow.mjs +4639 -0
- package/components.css +1392 -0
- package/defaults.css +26 -0
- package/dist/config.d.ts +94 -0
- package/dist/config.js +3 -0
- package/dist/index.d.ts +45 -0
- package/dist/index.js +67 -0
- package/docs/accessibility-css.md +133 -0
- package/docs/ai-usage.md +112 -0
- package/docs/api-contract.md +81 -0
- package/docs/base-styling.md +113 -0
- package/docs/build-a-site-walkthrough.md +122 -0
- package/docs/cli-reference.md +230 -0
- package/docs/config-reference.md +81 -0
- package/docs/css-optimisation.md +117 -0
- package/docs/migration-from-tailwind.md +60 -0
- package/docs/native-components.md +156 -0
- package/docs/patterns.md +32 -0
- package/docs/presets.md +60 -0
- package/docs/quick-start.md +252 -0
- package/docs/recipes.md +285 -0
- package/docs/release-readiness.md +63 -0
- package/docs/system-primitives.md +150 -0
- package/docs/tailwind-comparison.md +66 -0
- package/docs/tokens.md +79 -0
- package/docs/website-patterns.md +114 -0
- package/docs/why-synced-flow.md +99 -0
- package/docs/wordpress.md +66 -0
- package/examples/README.md +16 -0
- package/examples/astro/package.json +19 -0
- package/examples/astro/src/pages/index.astro +85 -0
- package/examples/astro/src/styles/synced-flow.css +2 -0
- package/examples/astro/src/styles/synced-flow.generated.css +206 -0
- package/examples/astro/synced-flow.config.mjs +9 -0
- package/examples/next/app/layout.tsx +14 -0
- package/examples/next/app/page.tsx +92 -0
- package/examples/next/app/synced-flow.css +2 -0
- package/examples/next/app/synced-flow.generated.css +205 -0
- package/examples/next/package.json +19 -0
- package/examples/next/synced-flow.config.mjs +9 -0
- package/examples/plain-html/index.html +384 -0
- package/examples/plain-html/package.json +15 -0
- package/examples/plain-html/synced-flow.config.mjs +9 -0
- package/examples/plain-html/synced-flow.css +2 -0
- package/examples/plain-html/synced-flow.generated.css +205 -0
- package/examples/templates/README.md +22 -0
- package/examples/templates/blog-index.html +41 -0
- package/examples/templates/coming-soon.html +27 -0
- package/examples/templates/portfolio-scroll.html +45 -0
- package/examples/templates/saas-dashboard.html +171 -0
- package/examples/templates/saas-landing.html +104 -0
- package/examples/vite/index.html +2 -0
- package/examples/vite/package.json +20 -0
- package/examples/vite/src/main.jsx +27 -0
- package/examples/vite/src/synced-flow.css +2 -0
- package/examples/vite/src/synced-flow.generated.css +205 -0
- package/examples/vite/synced-flow.config.mjs +9 -0
- package/examples/wordpress/assets/css/synced-flow.css +641 -0
- package/examples/wordpress/functions.php +13 -0
- package/examples/wordpress/package.json +15 -0
- package/examples/wordpress/parts/footer.html +12 -0
- package/examples/wordpress/parts/header.html +10 -0
- package/examples/wordpress/patterns/contact-cta.php +28 -0
- package/examples/wordpress/patterns/feature-grid.php +38 -0
- package/examples/wordpress/patterns/landing-hero.php +45 -0
- package/examples/wordpress/synced-flow.config.mjs +11 -0
- package/examples/wordpress/templates/front-page.html +11 -0
- package/examples/wordpress/templates/index.html +27 -0
- package/examples/wordpress/theme.json +19 -0
- package/layout.css +365 -0
- package/package.json +93 -0
- package/reset.css +13 -0
- package/skills/synced-flow/SKILL.md +151 -0
- package/src/config.ts +98 -0
- package/src/index.ts +75 -0
- package/src/presets.d.mts +21 -0
- package/src/presets.mjs +171 -0
- package/src/tokens.mjs +138 -0
- package/src/utility-tokens.mjs +47 -0
- package/styles.css +2313 -0
- package/tokens.css +198 -0
- package/utilities.css +255 -0
package/defaults.css
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/* Generated by @syncedco/flow. Edit src/tokens.mjs or scripts/build-css.mjs, then run pnpm build. */
|
|
2
|
+
@layer reset, tokens, base, app, layout, components, utilities;
|
|
3
|
+
@layer app {
|
|
4
|
+
:where(a) {
|
|
5
|
+
color: inherit;
|
|
6
|
+
text-decoration: none;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
:where(ol, ul, menu) {
|
|
10
|
+
list-style: none;
|
|
11
|
+
padding-inline-start: 0;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
:where(button) {
|
|
15
|
+
background: transparent;
|
|
16
|
+
border: 0;
|
|
17
|
+
color: inherit;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
:where(fieldset) {
|
|
21
|
+
border: 0;
|
|
22
|
+
padding: 0;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
:where(legend) { padding: 0; }
|
|
26
|
+
}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
type TokenMap = Record<string, string>;
|
|
2
|
+
export type SyncedFlowTheme = {
|
|
3
|
+
/**
|
|
4
|
+
* Project font stacks. Values should be complete CSS font-family values.
|
|
5
|
+
*/
|
|
6
|
+
fonts?: Partial<Record<'sans' | 'display' | 'mono', string>>;
|
|
7
|
+
/**
|
|
8
|
+
* Semantic colour tokens. Use OKLCH where possible.
|
|
9
|
+
*/
|
|
10
|
+
colours?: TokenMap;
|
|
11
|
+
/**
|
|
12
|
+
* Semantic colour overrides for .sf-theme-dark or [data-sf-theme="dark"].
|
|
13
|
+
*/
|
|
14
|
+
darkColours?: TokenMap;
|
|
15
|
+
/**
|
|
16
|
+
* Radius scale overrides such as md, lg, xl, full.
|
|
17
|
+
*/
|
|
18
|
+
radii?: TokenMap;
|
|
19
|
+
/**
|
|
20
|
+
* Layout-level tokens.
|
|
21
|
+
*/
|
|
22
|
+
layout?: {
|
|
23
|
+
containerMax?: string;
|
|
24
|
+
gutter?: string;
|
|
25
|
+
columns?: number;
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* Component-level token overrides.
|
|
29
|
+
*/
|
|
30
|
+
components?: {
|
|
31
|
+
button?: {
|
|
32
|
+
radius?: string;
|
|
33
|
+
blockSize?: string;
|
|
34
|
+
paddingInline?: string;
|
|
35
|
+
};
|
|
36
|
+
card?: {
|
|
37
|
+
radius?: string;
|
|
38
|
+
padding?: string;
|
|
39
|
+
shadow?: string;
|
|
40
|
+
};
|
|
41
|
+
input?: {
|
|
42
|
+
radius?: string;
|
|
43
|
+
blockSize?: string;
|
|
44
|
+
};
|
|
45
|
+
};
|
|
46
|
+
};
|
|
47
|
+
export type SyncedFlowConfig = {
|
|
48
|
+
/**
|
|
49
|
+
* Directory used to resolve scan and output paths. Defaults to the current
|
|
50
|
+
* working directory.
|
|
51
|
+
*/
|
|
52
|
+
cwd?: string;
|
|
53
|
+
/**
|
|
54
|
+
* Source directories that the CLI scans for class tokens.
|
|
55
|
+
*/
|
|
56
|
+
scan?: string[];
|
|
57
|
+
/**
|
|
58
|
+
* Class tokens to always generate when they are composed dynamically.
|
|
59
|
+
*/
|
|
60
|
+
safelist?: string[];
|
|
61
|
+
/**
|
|
62
|
+
* Generated CSS output file.
|
|
63
|
+
*/
|
|
64
|
+
out?: string;
|
|
65
|
+
/**
|
|
66
|
+
* Project token overrides emitted into the generated CSS.
|
|
67
|
+
*/
|
|
68
|
+
theme?: SyncedFlowTheme;
|
|
69
|
+
/**
|
|
70
|
+
* Include reset, base, layout, and component CSS in the generated file.
|
|
71
|
+
* Most projects should import @syncedco/flow/styles.css and leave this false.
|
|
72
|
+
*/
|
|
73
|
+
includeCore?: boolean;
|
|
74
|
+
/**
|
|
75
|
+
* Include site/UI defaults when includeCore is true. For modular projects,
|
|
76
|
+
* import @syncedco/flow/defaults.css from the CSS entry instead.
|
|
77
|
+
*/
|
|
78
|
+
includeDefaults?: boolean;
|
|
79
|
+
/**
|
|
80
|
+
* Enable breakpoint-style variants such as sm:, md:, lg:, and xl:.
|
|
81
|
+
* Leave false for strict fluid projects; enable only during migrations.
|
|
82
|
+
*/
|
|
83
|
+
responsiveVariants?: boolean;
|
|
84
|
+
/**
|
|
85
|
+
* Fail the CLI when unsupported class tokens are detected.
|
|
86
|
+
*/
|
|
87
|
+
failOnUnsupported?: boolean;
|
|
88
|
+
/**
|
|
89
|
+
* Suppress non-critical CLI warnings.
|
|
90
|
+
*/
|
|
91
|
+
quiet?: boolean;
|
|
92
|
+
};
|
|
93
|
+
export declare function defineConfig(config: SyncedFlowConfig): SyncedFlowConfig;
|
|
94
|
+
export {};
|
package/dist/config.js
ADDED
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
export { defineConfig, type SyncedFlowConfig, type SyncedFlowTheme } from './config.js';
|
|
2
|
+
export { presetNames, themePresets } from '../src/presets.mjs';
|
|
3
|
+
export type ClassValue = string | number | boolean | null | undefined | ClassValue[] | Record<string, unknown>;
|
|
4
|
+
export declare function cx(...inputs: ClassValue[]): string;
|
|
5
|
+
export declare const fluidSystem: {
|
|
6
|
+
readonly layout: {
|
|
7
|
+
readonly container: "sf-container";
|
|
8
|
+
readonly section: "sf-section";
|
|
9
|
+
readonly stack: "sf-stack";
|
|
10
|
+
readonly cluster: "sf-cluster";
|
|
11
|
+
readonly repel: "sf-repel";
|
|
12
|
+
readonly grid: "sf-grid";
|
|
13
|
+
readonly autoGrid: "sf-auto-grid";
|
|
14
|
+
readonly sidebar: "sf-sidebar";
|
|
15
|
+
readonly switcher: "sf-switcher";
|
|
16
|
+
readonly frame: "sf-frame";
|
|
17
|
+
readonly cover: "sf-cover";
|
|
18
|
+
readonly flow: "sf-flow";
|
|
19
|
+
};
|
|
20
|
+
readonly components: {
|
|
21
|
+
readonly button: "sf-button";
|
|
22
|
+
readonly card: "sf-card";
|
|
23
|
+
readonly badge: "sf-badge";
|
|
24
|
+
readonly field: "sf-field";
|
|
25
|
+
readonly input: "sf-input";
|
|
26
|
+
};
|
|
27
|
+
readonly utilities: {
|
|
28
|
+
readonly visuallyHidden: "sf-visually-hidden";
|
|
29
|
+
readonly notVisuallyHidden: "sf-not-visually-hidden";
|
|
30
|
+
readonly srOnly: "sr-only";
|
|
31
|
+
readonly notSrOnly: "not-sr-only";
|
|
32
|
+
readonly skipLink: "sf-skip-link";
|
|
33
|
+
readonly focusRing: "sf-focus-ring";
|
|
34
|
+
readonly focusRingInset: "sf-focus-ring-inset";
|
|
35
|
+
readonly touchTarget: "sf-touch-target";
|
|
36
|
+
readonly listReset: "sf-list-reset";
|
|
37
|
+
readonly listDisc: "sf-list-disc";
|
|
38
|
+
readonly listDecimal: "sf-list-decimal";
|
|
39
|
+
readonly link: "sf-link";
|
|
40
|
+
readonly linkSubtle: "sf-link-subtle";
|
|
41
|
+
readonly linkPlain: "sf-link-plain";
|
|
42
|
+
readonly prose: "sf-prose";
|
|
43
|
+
};
|
|
44
|
+
};
|
|
45
|
+
export type FluidSystem = typeof fluidSystem;
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
export { defineConfig } from './config.js';
|
|
2
|
+
export { presetNames, themePresets } from '../src/presets.mjs';
|
|
3
|
+
export function cx(...inputs) {
|
|
4
|
+
const classes = [];
|
|
5
|
+
for (const input of inputs)
|
|
6
|
+
appendClassValue(classes, input);
|
|
7
|
+
return classes.join(' ');
|
|
8
|
+
}
|
|
9
|
+
function appendClassValue(classes, value) {
|
|
10
|
+
if (!value)
|
|
11
|
+
return;
|
|
12
|
+
if (typeof value === 'string' || typeof value === 'number') {
|
|
13
|
+
classes.push(String(value));
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
if (Array.isArray(value)) {
|
|
17
|
+
for (const item of value)
|
|
18
|
+
appendClassValue(classes, item);
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
if (typeof value === 'object') {
|
|
22
|
+
for (const [className, enabled] of Object.entries(value)) {
|
|
23
|
+
if (enabled)
|
|
24
|
+
classes.push(className);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
export const fluidSystem = {
|
|
29
|
+
layout: {
|
|
30
|
+
container: 'sf-container',
|
|
31
|
+
section: 'sf-section',
|
|
32
|
+
stack: 'sf-stack',
|
|
33
|
+
cluster: 'sf-cluster',
|
|
34
|
+
repel: 'sf-repel',
|
|
35
|
+
grid: 'sf-grid',
|
|
36
|
+
autoGrid: 'sf-auto-grid',
|
|
37
|
+
sidebar: 'sf-sidebar',
|
|
38
|
+
switcher: 'sf-switcher',
|
|
39
|
+
frame: 'sf-frame',
|
|
40
|
+
cover: 'sf-cover',
|
|
41
|
+
flow: 'sf-flow',
|
|
42
|
+
},
|
|
43
|
+
components: {
|
|
44
|
+
button: 'sf-button',
|
|
45
|
+
card: 'sf-card',
|
|
46
|
+
badge: 'sf-badge',
|
|
47
|
+
field: 'sf-field',
|
|
48
|
+
input: 'sf-input',
|
|
49
|
+
},
|
|
50
|
+
utilities: {
|
|
51
|
+
visuallyHidden: 'sf-visually-hidden',
|
|
52
|
+
notVisuallyHidden: 'sf-not-visually-hidden',
|
|
53
|
+
srOnly: 'sr-only',
|
|
54
|
+
notSrOnly: 'not-sr-only',
|
|
55
|
+
skipLink: 'sf-skip-link',
|
|
56
|
+
focusRing: 'sf-focus-ring',
|
|
57
|
+
focusRingInset: 'sf-focus-ring-inset',
|
|
58
|
+
touchTarget: 'sf-touch-target',
|
|
59
|
+
listReset: 'sf-list-reset',
|
|
60
|
+
listDisc: 'sf-list-disc',
|
|
61
|
+
listDecimal: 'sf-list-decimal',
|
|
62
|
+
link: 'sf-link',
|
|
63
|
+
linkSubtle: 'sf-link-subtle',
|
|
64
|
+
linkPlain: 'sf-link-plain',
|
|
65
|
+
prose: 'sf-prose',
|
|
66
|
+
},
|
|
67
|
+
};
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# Accessibility CSS
|
|
2
|
+
|
|
3
|
+
Synced Flow does not run accessibility audits. It provides CSS affordances so
|
|
4
|
+
semantic HTML and ARIA states are visible, consistent, and easy to compose.
|
|
5
|
+
|
|
6
|
+
## Principles
|
|
7
|
+
|
|
8
|
+
- Prefer native elements first: `button`, `a[href]`, `label`, `input`,
|
|
9
|
+
`select`, `textarea`, `details`, `summary`, `nav`, `main`, `section`, and
|
|
10
|
+
`footer`.
|
|
11
|
+
- Use ARIA only when native semantics do not express the state.
|
|
12
|
+
- Keep accessible names and descriptions in markup; Synced Flow styles the
|
|
13
|
+
visible states.
|
|
14
|
+
- Use project-level accessibility testing in the consuming app.
|
|
15
|
+
|
|
16
|
+
## Built-In Affordances
|
|
17
|
+
|
|
18
|
+
| Hook | Styled behavior |
|
|
19
|
+
| --- | --- |
|
|
20
|
+
| `:focus-visible` | Visible outline using `--sf-colour-ring`, with forced-colors support. |
|
|
21
|
+
| `:target` | Scroll margin for skip links and anchor navigation. |
|
|
22
|
+
| `.sf-skip-link` | Keyboard-visible skip link. |
|
|
23
|
+
| `.sf-visually-hidden`, `.sr-only` | Visually hidden text that remains available to assistive tech. |
|
|
24
|
+
| `.sf-touch-target` | Minimum interactive target sizing. |
|
|
25
|
+
| `[aria-current="page"]`, `[aria-current="true"]` | Current nav/link state. |
|
|
26
|
+
| `[aria-expanded="true"]`, `[aria-pressed="true"]`, `[aria-selected="true"]`, `[data-state="open"]` | Active disclosure/toggle/selection state for buttons and nav links. |
|
|
27
|
+
| `[aria-disabled="true"]`, `:disabled` | Disabled affordance for buttons, links, cards, and form controls. |
|
|
28
|
+
| `[aria-busy="true"]`, `[data-loading="true"]` | Busy/loading affordance for buttons and form controls. |
|
|
29
|
+
| `.sf-field[data-invalid="true"]`, `[aria-invalid="true"]` | Invalid field styling. |
|
|
30
|
+
| `.sf-required`, `.sf-label[aria-required="true"]`, `label:has(+ :required)` | Required-field marker styling. |
|
|
31
|
+
| `@media (forced-colors: active)` | High contrast mode border, focus, and button fallbacks. |
|
|
32
|
+
|
|
33
|
+
## Forms
|
|
34
|
+
|
|
35
|
+
Pair visible help and error text with `aria-describedby`. Use
|
|
36
|
+
`aria-invalid="true"` only when a field is currently invalid.
|
|
37
|
+
|
|
38
|
+
```html
|
|
39
|
+
<div class="sf-field" data-invalid="true">
|
|
40
|
+
<label class="sf-required" for="email">Email</label>
|
|
41
|
+
<input
|
|
42
|
+
class="sf-input"
|
|
43
|
+
id="email"
|
|
44
|
+
name="email"
|
|
45
|
+
type="email"
|
|
46
|
+
required
|
|
47
|
+
aria-invalid="true"
|
|
48
|
+
aria-describedby="email-help email-error"
|
|
49
|
+
/>
|
|
50
|
+
<p class="sf-help" id="email-help">Use a work email address.</p>
|
|
51
|
+
<p class="sf-error" id="email-error">Enter a valid email address.</p>
|
|
52
|
+
</div>
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Use `disabled` for native disabled controls. Use `aria-disabled="true"` only
|
|
56
|
+
when an element cannot use the native `disabled` attribute, such as an anchor
|
|
57
|
+
that is visually present but intentionally unavailable.
|
|
58
|
+
|
|
59
|
+
## Navigation And Disclosure
|
|
60
|
+
|
|
61
|
+
Use `aria-current="page"` for the current page link.
|
|
62
|
+
|
|
63
|
+
```html
|
|
64
|
+
<nav class="sf-nav" aria-label="Primary">
|
|
65
|
+
<ul class="sf-nav__list">
|
|
66
|
+
<li><a class="sf-nav__link" href="/" aria-current="page">Home</a></li>
|
|
67
|
+
<li><a class="sf-nav__link" href="/pricing">Pricing</a></li>
|
|
68
|
+
</ul>
|
|
69
|
+
</nav>
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Use native `details`/`summary` for FAQ and simple disclosure content.
|
|
73
|
+
|
|
74
|
+
```html
|
|
75
|
+
<details class="sf-faq__item">
|
|
76
|
+
<summary>Can I customize the theme?</summary>
|
|
77
|
+
<p>Yes. Override semantic tokens before adding custom CSS.</p>
|
|
78
|
+
</details>
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
For JavaScript-powered menus or toggles, use real buttons and update
|
|
82
|
+
`aria-expanded`, `aria-pressed`, or `aria-selected` as appropriate. Synced Flow
|
|
83
|
+
styles those states for `.sf-button` and `.sf-nav__link`.
|
|
84
|
+
|
|
85
|
+
For native dialog, popover, drawer, tooltip, tabs, and disclosure markup, see
|
|
86
|
+
[Native Components](native-components.md). Synced Flow styles those browser
|
|
87
|
+
primitives but does not ship JavaScript components.
|
|
88
|
+
|
|
89
|
+
## Alerts And Status
|
|
90
|
+
|
|
91
|
+
Synced Flow alert variants are visual styles. Choose the live-region behavior
|
|
92
|
+
in markup:
|
|
93
|
+
|
|
94
|
+
```html
|
|
95
|
+
<div class="sf-alert sf-alert--success" role="status">
|
|
96
|
+
<p class="sf-alert__title">Saved</p>
|
|
97
|
+
<p>Your changes were saved.</p>
|
|
98
|
+
</div>
|
|
99
|
+
|
|
100
|
+
<div class="sf-alert sf-alert--danger" role="alert">
|
|
101
|
+
<p class="sf-alert__title">Payment failed</p>
|
|
102
|
+
<p>Check the card details and try again.</p>
|
|
103
|
+
</div>
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Use `role="status"` for polite updates. Use `role="alert"` only for urgent
|
|
107
|
+
messages that need immediate announcement.
|
|
108
|
+
|
|
109
|
+
## Busy And Loading States
|
|
110
|
+
|
|
111
|
+
When an action is in progress, keep the accessible name visible and add state:
|
|
112
|
+
|
|
113
|
+
```html
|
|
114
|
+
<button class="sf-button" type="button" aria-busy="true">
|
|
115
|
+
Saving
|
|
116
|
+
</button>
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
Synced Flow styles this as a busy state, but the consuming app should still
|
|
120
|
+
manage focus, state changes, and completion messaging.
|
|
121
|
+
|
|
122
|
+
## Confidence Checklist
|
|
123
|
+
|
|
124
|
+
Use this when changing the CSS system or examples:
|
|
125
|
+
|
|
126
|
+
- Navigate the demo with keyboard only.
|
|
127
|
+
- Confirm focus is visible on links, buttons, form controls, summaries, and the
|
|
128
|
+
skip link.
|
|
129
|
+
- Confirm invalid, required, disabled, busy, current, expanded, selected, and
|
|
130
|
+
pressed states remain visible when those states are present in markup.
|
|
131
|
+
- Confirm `details`/`summary` works without JavaScript.
|
|
132
|
+
- Confirm forced-colors styles do not depend only on subtle background colour.
|
|
133
|
+
- Confirm examples use native elements before ARIA.
|
package/docs/ai-usage.md
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
# AI Agent Setup And Usage
|
|
2
|
+
|
|
3
|
+
Use this when an AI agent is building or editing a project with Synced Flow.
|
|
4
|
+
|
|
5
|
+
Synced Flow ships a skill at
|
|
6
|
+
[`skills/synced-flow/SKILL.md`](../skills/synced-flow/SKILL.md). In a
|
|
7
|
+
consumer project, make it discoverable with project-level guidance:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pnpm exec synced-flow agents install
|
|
11
|
+
pnpm exec synced-flow agents status
|
|
12
|
+
pnpm exec synced-flow skill
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Use `agents install --target all` to add project-local guidance for Cursor,
|
|
16
|
+
Codex-style agents, Claude, Copilot, Windsurf, Gemini, and Aider where those
|
|
17
|
+
tools have clear project conventions.
|
|
18
|
+
|
|
19
|
+
## First Moves
|
|
20
|
+
|
|
21
|
+
1. Install the package.
|
|
22
|
+
2. Run `synced-flow init --preset <framework> --agents`.
|
|
23
|
+
3. Ask for a short theme brief: radius, fonts, primary colour, accent colour,
|
|
24
|
+
surface style, and density.
|
|
25
|
+
4. Convert that brief into `synced-flow.config.mjs` theme tokens.
|
|
26
|
+
5. Import the generated CSS entry once.
|
|
27
|
+
6. Run `synced-flow catalog --json` before choosing recipes and classes.
|
|
28
|
+
7. Run `synced-flow pattern --list` before hand-rolling interaction markup.
|
|
29
|
+
8. Run `synced-flow lint --json` and `synced-flow doctor` before finishing.
|
|
30
|
+
|
|
31
|
+
Good theme prompt:
|
|
32
|
+
|
|
33
|
+
```text
|
|
34
|
+
Use the Synced Flow skill. Build a theme config for a modern B2B website:
|
|
35
|
+
soft but not pill-shaped radius, system sans UI, editorial display headings,
|
|
36
|
+
blue primary, green accent, light raised cards, and spacious sections.
|
|
37
|
+
Return only the Synced Flow config theme object.
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
For a file-based workflow, put the answers in `brief.md` and run:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
pnpm exec synced-flow theme init --from brief.md
|
|
44
|
+
pnpm exec synced-flow theme init --from brief.md --preset-base neutral-saas
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
If the output includes warnings, ask the user for the missing brand decisions
|
|
48
|
+
before finalising the theme.
|
|
49
|
+
|
|
50
|
+
## Styling Rules
|
|
51
|
+
|
|
52
|
+
- Prefer `sf-container`, `sf-section`, `sf-stack`, `sf-cluster`, `sf-auto-grid`,
|
|
53
|
+
`sf-split`, and `sf-sidebar` before writing custom layout CSS.
|
|
54
|
+
- Use semantic colours: `bg-background`, `text-foreground`, `bg-primary`,
|
|
55
|
+
`text-primary-foreground`, `border-border`, `bg-surface`.
|
|
56
|
+
- Use `sf-button`, `sf-card`, `sf-badge`, `sf-field`, and `sf-input` for common UI.
|
|
57
|
+
- Keep browser affordances unless the UI intentionally replaces them: body
|
|
58
|
+
links stay underlined, content lists keep markers, and focus states remain
|
|
59
|
+
visible.
|
|
60
|
+
- Use `@syncedco/flow/defaults.css` for common site/UI defaults when raw links should
|
|
61
|
+
not be underlined and menu lists should not show bullets. Add it with
|
|
62
|
+
`synced-flow add defaults` if a project was initialised without it.
|
|
63
|
+
- Use `sr-only` / `not-sr-only`, `sf-skip-link`, `sf-focus-ring`,
|
|
64
|
+
`sf-touch-target`, `sf-list-reset`, `sf-link`, and `sf-link-plain` for
|
|
65
|
+
accessibility and UI affordance work.
|
|
66
|
+
- Use theme presets or config `theme` overrides for brand choices.
|
|
67
|
+
- Put repeated brand decisions in theme tokens before adding custom CSS.
|
|
68
|
+
- Use `synced-flow suggest "<brief>"` to choose section recipes before adding
|
|
69
|
+
new one-off patterns.
|
|
70
|
+
- Use `synced-flow suggest "<brief>" --scaffold --framework <target> --dry-run`
|
|
71
|
+
when starting a page or project from a brief.
|
|
72
|
+
- Use `synced-flow pattern <id> --markup` for complete native interaction
|
|
73
|
+
patterns such as mobile drawers, scroll sections, popover drawers, and native
|
|
74
|
+
dialogs.
|
|
75
|
+
- Use `synced-flow recipe <id> --markup` to get copy-ready page sections for
|
|
76
|
+
SaaS, portfolio, agency, blog, article, about, team, contact, 404, and coming
|
|
77
|
+
soon pages.
|
|
78
|
+
- Choose `saas-landing` for public SaaS marketing pages. Choose
|
|
79
|
+
`saas-dashboard` for authenticated app UI, admin panels, portals, CRMs,
|
|
80
|
+
analytics dashboards, metrics, tables, account menus, and login state.
|
|
81
|
+
- Treat auth recipe markup as UI only; sessions, providers, permissions, and
|
|
82
|
+
sign-out logic belong to the consuming app.
|
|
83
|
+
- Keep class names complete in source files. Do not build classes from fragments.
|
|
84
|
+
- Use `safelist` only when dynamic classes are unavoidable.
|
|
85
|
+
- Do not enable `responsiveVariants` in new projects.
|
|
86
|
+
|
|
87
|
+
## Good Starter Shape
|
|
88
|
+
|
|
89
|
+
```html
|
|
90
|
+
<main class="sf-section">
|
|
91
|
+
<section class="sf-container sf-stack">
|
|
92
|
+
<p class="sf-kicker">Practical systems</p>
|
|
93
|
+
<h1 class="sf-text-display">Fluid from the first screen.</h1>
|
|
94
|
+
<p class="sf-text-lead sf-prose">Use tokens and primitives before one-off CSS.</p>
|
|
95
|
+
<div class="sf-cluster">
|
|
96
|
+
<a class="sf-button sf-button--default" href="/contact">Start discovery</a>
|
|
97
|
+
<a class="sf-button sf-button--outline" href="/docs">Read docs</a>
|
|
98
|
+
</div>
|
|
99
|
+
</section>
|
|
100
|
+
</main>
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## Finish Checklist
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
pnpm flow:build
|
|
107
|
+
pnpm flow:check
|
|
108
|
+
pnpm exec synced-flow lint --json
|
|
109
|
+
pnpm flow:doctor
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
If `doctor` warns about stale CSS, run `pnpm flow:build`.
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# CSS API Contract
|
|
2
|
+
|
|
3
|
+
Synced Flow is small enough to read, but projects still need to know which
|
|
4
|
+
parts are safe to rely on. Treat this page as the public CSS contract for the
|
|
5
|
+
0.x line.
|
|
6
|
+
|
|
7
|
+
## Stable Public Surface
|
|
8
|
+
|
|
9
|
+
These are intended for application code and examples.
|
|
10
|
+
|
|
11
|
+
| Surface | Public API |
|
|
12
|
+
| --- | --- |
|
|
13
|
+
| Imports | `@syncedco/flow/styles.css`, `tokens.css`, `reset.css`, `base.css`, `defaults.css`, `layout.css`, `components.css`, `utilities.css` |
|
|
14
|
+
| Tokens | `--sf-*` custom properties emitted by `tokens.css` |
|
|
15
|
+
| Theme config | `theme.fonts`, `theme.colours`, `theme.darkColours`, `theme.radii`, `theme.layout`, `theme.components` |
|
|
16
|
+
| Layout classes | `sf-container`, `sf-section`, `sf-stack`, `sf-flow`, `sf-cluster`, `sf-repel`, `sf-toolbar`, `sf-app-shell`, `sf-app-sidebar`, `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-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-menu`, `sf-breadcrumb`, `sf-pagination` |
|
|
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
|
+
| 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` |
|
|
21
|
+
| 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
|
+
|
|
23
|
+
## AI Agent Contract
|
|
24
|
+
|
|
25
|
+
The project-level AI setup commands are public in 0.x:
|
|
26
|
+
|
|
27
|
+
- `synced-flow agents install [--target universal|cursor|codex|claude|copilot|windsurf|gemini|aider|all] [--force] [--dry-run]`
|
|
28
|
+
- `synced-flow agents status`
|
|
29
|
+
- `synced-flow skill`
|
|
30
|
+
- `synced-flow pattern <id> [--framework html|next|react|astro] [--markup|--json]`
|
|
31
|
+
- `synced-flow pattern --list`
|
|
32
|
+
- `synced-flow suggest "<brief>" --scaffold [--framework next|vite|astro|plain] [--out dir] [--dry-run] [--force]`
|
|
33
|
+
- `synced-flow lint [--json] [--fix] [paths...]`
|
|
34
|
+
|
|
35
|
+
`catalog --json` includes `patterns[]` with copy-ready interaction metadata:
|
|
36
|
+
classes, markup, JS requirement notes, accessibility notes, and gotchas.
|
|
37
|
+
|
|
38
|
+
## Internal Or Compatibility Surface
|
|
39
|
+
|
|
40
|
+
These can change more freely.
|
|
41
|
+
|
|
42
|
+
- Generated compatibility utility selectors such as `[class~="text-primary"]`.
|
|
43
|
+
- Tailwind-migration helpers enabled by `responsiveVariants`.
|
|
44
|
+
- Implementation details inside `scripts/build-css.mjs`.
|
|
45
|
+
- Utility-compatible aliases such as `--color-*`, `--font-*`, and `--radius-*`.
|
|
46
|
+
They are useful for migration output, but `--sf-*` tokens are the preferred
|
|
47
|
+
long-term API.
|
|
48
|
+
|
|
49
|
+
## Unit Policy
|
|
50
|
+
|
|
51
|
+
Design decisions should use `rem`, fluid `clamp()` tokens, logical properties,
|
|
52
|
+
or percentages. Raw `px` is reserved for:
|
|
53
|
+
|
|
54
|
+
- `1px` borders and inset hairlines.
|
|
55
|
+
- Forced-colors/system fallback outlines.
|
|
56
|
+
- Internal generator math that is emitted as `rem` or `clamp()`.
|
|
57
|
+
|
|
58
|
+
`pnpm guardrails` enforces this policy against the shipped CSS files.
|
|
59
|
+
|
|
60
|
+
## Change Rules
|
|
61
|
+
|
|
62
|
+
- Additive tokens/classes are safe in minor releases.
|
|
63
|
+
- Renaming or removing public `--sf-*` tokens or `sf-*` classes needs a
|
|
64
|
+
migration note and should wait for a major release once the project leaves
|
|
65
|
+
`0.x`.
|
|
66
|
+
- New primitives should earn their place by replacing repeated website/app
|
|
67
|
+
CSS, not by chasing every utility class from larger frameworks.
|
|
68
|
+
- Prefer documentation recipes before adding new CSS.
|
|
69
|
+
|
|
70
|
+
## Stability Checklist
|
|
71
|
+
|
|
72
|
+
Before changing the public surface, run:
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
pnpm build
|
|
76
|
+
pnpm check
|
|
77
|
+
pnpm test
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
`pnpm check` includes generated CSS freshness, type checks, CSS size budgets,
|
|
81
|
+
dependency checks, layer-shape checks, and raw-pixel guardrails.
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# Base Styling Decisions
|
|
2
|
+
|
|
3
|
+
Synced Flow uses a conservative reset and modern base layer. The goal is to
|
|
4
|
+
make new projects consistent without hiding important browser affordances.
|
|
5
|
+
|
|
6
|
+
## What Stays Native
|
|
7
|
+
|
|
8
|
+
- Links stay visibly underlined by default.
|
|
9
|
+
- `ul` and `ol` keep their markers by default.
|
|
10
|
+
- Form controls inherit project typography but keep their native semantics.
|
|
11
|
+
- Focus styles are visible through `:focus-visible`.
|
|
12
|
+
- Headings, code, blockquotes, horizontal rules, and selection states get
|
|
13
|
+
token-based defaults without removing their native meaning.
|
|
14
|
+
|
|
15
|
+
## Optional App Defaults
|
|
16
|
+
|
|
17
|
+
Most app and marketing-site interfaces do not want raw link underlines in
|
|
18
|
+
navigation, or bullets on menu lists. Add the optional defaults layer for those
|
|
19
|
+
project-wide UI defaults:
|
|
20
|
+
|
|
21
|
+
```css
|
|
22
|
+
@import "@syncedco/flow/defaults.css";
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
You can also add it later with the CLI:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
pnpm exec synced-flow add defaults --file src/synced-flow.css
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
`defaults.css` removes raw link underlines, resets `ol`/`ul`/`menu` markers and start
|
|
32
|
+
padding, and strips basic button/fieldset chrome. Use `sf-link`, `sf-list-disc`,
|
|
33
|
+
`sf-list-decimal`, or `sf-prose` where content needs visible semantics again.
|
|
34
|
+
|
|
35
|
+
Use opt-in utilities when a component needs a different treatment:
|
|
36
|
+
|
|
37
|
+
```html
|
|
38
|
+
<nav aria-label="Primary">
|
|
39
|
+
<ul class="sf-list-reset sf-cluster">
|
|
40
|
+
<li><a class="sf-link-plain" href="/">Home</a></li>
|
|
41
|
+
<li><a class="sf-link-plain" href="/docs">Docs</a></li>
|
|
42
|
+
</ul>
|
|
43
|
+
</nav>
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Accessibility Utilities
|
|
47
|
+
|
|
48
|
+
```html
|
|
49
|
+
<a class="sf-skip-link" href="#main">Skip to main content</a>
|
|
50
|
+
<span class="sr-only">Opens in a new tab</span>
|
|
51
|
+
<button class="sf-touch-target sf-focus-ring">Save</button>
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Available helpers:
|
|
55
|
+
|
|
56
|
+
- `sr-only` / `sf-visually-hidden`
|
|
57
|
+
- `not-sr-only` / `sf-not-visually-hidden`
|
|
58
|
+
- `sf-skip-link`
|
|
59
|
+
- `sf-focus-ring`
|
|
60
|
+
- `sf-focus-ring-inset`
|
|
61
|
+
- `sf-touch-target`
|
|
62
|
+
|
|
63
|
+
## Link Utilities
|
|
64
|
+
|
|
65
|
+
- `sf-link` for primary inline links.
|
|
66
|
+
- `sf-link-subtle` for inherited-colour inline links.
|
|
67
|
+
- `sf-link-plain` for navigation, buttons, cards, and other UI where the
|
|
68
|
+
element has another clear affordance.
|
|
69
|
+
|
|
70
|
+
Body and prose links should normally stay visibly identifiable.
|
|
71
|
+
|
|
72
|
+
## Forms And UI Components
|
|
73
|
+
|
|
74
|
+
The base layer keeps native form semantics, while component classes provide
|
|
75
|
+
ready-to-use styling:
|
|
76
|
+
|
|
77
|
+
```html
|
|
78
|
+
<form class="sf-form">
|
|
79
|
+
<div class="sf-field">
|
|
80
|
+
<label for="email">Email</label>
|
|
81
|
+
<input class="sf-input" id="email" type="email" />
|
|
82
|
+
<p class="sf-help">We only use this for project updates.</p>
|
|
83
|
+
</div>
|
|
84
|
+
<button class="sf-button" type="submit">Send</button>
|
|
85
|
+
</form>
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Use `sf-input`, `sf-select`, `sf-textarea`, `sf-check`, `sf-help`, and
|
|
89
|
+
`sf-error` for common form needs. Use `sf-alert` variants for notices and
|
|
90
|
+
feedback.
|
|
91
|
+
|
|
92
|
+
Synced Flow also styles accessible states such as `[aria-invalid="true"]`,
|
|
93
|
+
`[aria-disabled="true"]`, `[aria-busy="true"]`, `[aria-current="page"]`, and
|
|
94
|
+
required-field markers. See [Accessibility CSS](accessibility-css.md) for the
|
|
95
|
+
markup contract.
|
|
96
|
+
|
|
97
|
+
## List Utilities
|
|
98
|
+
|
|
99
|
+
- `sf-list-reset` removes list markers and start padding for navigation or UI
|
|
100
|
+
lists.
|
|
101
|
+
- `sf-list-disc` restores disc markers.
|
|
102
|
+
- `sf-list-decimal` restores numbered markers.
|
|
103
|
+
|
|
104
|
+
Do not reset content lists just to remove browser defaults. Keep markers when
|
|
105
|
+
they carry meaning.
|
|
106
|
+
|
|
107
|
+
## Modern CSS Baseline
|
|
108
|
+
|
|
109
|
+
The base layer uses cascade layers, logical properties, low-specificity
|
|
110
|
+
`:where()` selectors, OKLCH-aware `color-mix()`, `:focus-visible`, and
|
|
111
|
+
`prefers-reduced-motion`. Utopia informs the fluid type, space, and grid
|
|
112
|
+
tokens; Synced Flow owns the reset, accessibility helpers, and component
|
|
113
|
+
defaults.
|