@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.
Files changed (90) hide show
  1. package/CODE_OF_CONDUCT.md +26 -0
  2. package/CONTRIBUTING.md +54 -0
  3. package/LICENSE +21 -0
  4. package/README.md +334 -0
  5. package/SECURITY.md +30 -0
  6. package/SUPPORT.md +32 -0
  7. package/TRADEMARKS.md +14 -0
  8. package/base.css +100 -0
  9. package/bin/synced-flow.mjs +4639 -0
  10. package/components.css +1392 -0
  11. package/defaults.css +26 -0
  12. package/dist/config.d.ts +94 -0
  13. package/dist/config.js +3 -0
  14. package/dist/index.d.ts +45 -0
  15. package/dist/index.js +67 -0
  16. package/docs/accessibility-css.md +133 -0
  17. package/docs/ai-usage.md +112 -0
  18. package/docs/api-contract.md +81 -0
  19. package/docs/base-styling.md +113 -0
  20. package/docs/build-a-site-walkthrough.md +122 -0
  21. package/docs/cli-reference.md +230 -0
  22. package/docs/config-reference.md +81 -0
  23. package/docs/css-optimisation.md +117 -0
  24. package/docs/migration-from-tailwind.md +60 -0
  25. package/docs/native-components.md +156 -0
  26. package/docs/patterns.md +32 -0
  27. package/docs/presets.md +60 -0
  28. package/docs/quick-start.md +252 -0
  29. package/docs/recipes.md +285 -0
  30. package/docs/release-readiness.md +63 -0
  31. package/docs/system-primitives.md +150 -0
  32. package/docs/tailwind-comparison.md +66 -0
  33. package/docs/tokens.md +79 -0
  34. package/docs/website-patterns.md +114 -0
  35. package/docs/why-synced-flow.md +99 -0
  36. package/docs/wordpress.md +66 -0
  37. package/examples/README.md +16 -0
  38. package/examples/astro/package.json +19 -0
  39. package/examples/astro/src/pages/index.astro +85 -0
  40. package/examples/astro/src/styles/synced-flow.css +2 -0
  41. package/examples/astro/src/styles/synced-flow.generated.css +206 -0
  42. package/examples/astro/synced-flow.config.mjs +9 -0
  43. package/examples/next/app/layout.tsx +14 -0
  44. package/examples/next/app/page.tsx +92 -0
  45. package/examples/next/app/synced-flow.css +2 -0
  46. package/examples/next/app/synced-flow.generated.css +205 -0
  47. package/examples/next/package.json +19 -0
  48. package/examples/next/synced-flow.config.mjs +9 -0
  49. package/examples/plain-html/index.html +384 -0
  50. package/examples/plain-html/package.json +15 -0
  51. package/examples/plain-html/synced-flow.config.mjs +9 -0
  52. package/examples/plain-html/synced-flow.css +2 -0
  53. package/examples/plain-html/synced-flow.generated.css +205 -0
  54. package/examples/templates/README.md +22 -0
  55. package/examples/templates/blog-index.html +41 -0
  56. package/examples/templates/coming-soon.html +27 -0
  57. package/examples/templates/portfolio-scroll.html +45 -0
  58. package/examples/templates/saas-dashboard.html +171 -0
  59. package/examples/templates/saas-landing.html +104 -0
  60. package/examples/vite/index.html +2 -0
  61. package/examples/vite/package.json +20 -0
  62. package/examples/vite/src/main.jsx +27 -0
  63. package/examples/vite/src/synced-flow.css +2 -0
  64. package/examples/vite/src/synced-flow.generated.css +205 -0
  65. package/examples/vite/synced-flow.config.mjs +9 -0
  66. package/examples/wordpress/assets/css/synced-flow.css +641 -0
  67. package/examples/wordpress/functions.php +13 -0
  68. package/examples/wordpress/package.json +15 -0
  69. package/examples/wordpress/parts/footer.html +12 -0
  70. package/examples/wordpress/parts/header.html +10 -0
  71. package/examples/wordpress/patterns/contact-cta.php +28 -0
  72. package/examples/wordpress/patterns/feature-grid.php +38 -0
  73. package/examples/wordpress/patterns/landing-hero.php +45 -0
  74. package/examples/wordpress/synced-flow.config.mjs +11 -0
  75. package/examples/wordpress/templates/front-page.html +11 -0
  76. package/examples/wordpress/templates/index.html +27 -0
  77. package/examples/wordpress/theme.json +19 -0
  78. package/layout.css +365 -0
  79. package/package.json +93 -0
  80. package/reset.css +13 -0
  81. package/skills/synced-flow/SKILL.md +151 -0
  82. package/src/config.ts +98 -0
  83. package/src/index.ts +75 -0
  84. package/src/presets.d.mts +21 -0
  85. package/src/presets.mjs +171 -0
  86. package/src/tokens.mjs +138 -0
  87. package/src/utility-tokens.mjs +47 -0
  88. package/styles.css +2313 -0
  89. package/tokens.css +198 -0
  90. package/utilities.css +255 -0
@@ -0,0 +1,151 @@
1
+ ---
2
+ name: synced-flow
3
+ description: Use Synced Flow to set up and build modern fluid CSS systems with the CLI, tokens, presets, WordPress support, and source-scanned utility CSS.
4
+ ---
5
+
6
+ # Synced Flow
7
+
8
+ Use this skill when a project uses, evaluates, installs, migrates to, or
9
+ generates UI with Synced Flow.
10
+
11
+ Synced Flow is an independent modern fluid CSS system. It is not a Tailwind
12
+ copy, compatibility layer, or one-for-one replacement. Tailwind references
13
+ should only support migration from existing projects.
14
+
15
+ ## First Moves
16
+
17
+ 1. Check whether `@syncedco/flow` is installed.
18
+ 2. Check for `synced-flow.config.mjs`.
19
+ 3. Run or recommend `synced-flow agents status` to see whether project-level
20
+ guidance is installed.
21
+ 4. Run or recommend `synced-flow catalog --json` before choosing recipes and
22
+ class names.
23
+ 5. Use `synced-flow pattern --list` and `synced-flow pattern <id> --markup`
24
+ before hand-rolling native interaction markup.
25
+ 6. Use `synced-flow suggest "<brief>"` or
26
+ `synced-flow suggest "<brief>" --scaffold --dry-run` for section, page, or
27
+ starter composition.
28
+ 7. Use `synced-flow recipe <id> --markup` when a project needs copy-ready page
29
+ structure.
30
+ 8. Use `synced-flow lint --json` and `synced-flow doctor` to verify setup.
31
+ 9. Keep `responsiveVariants` off for new projects.
32
+
33
+ ## Setup
34
+
35
+ Use the closest preset:
36
+
37
+ ```bash
38
+ pnpm exec synced-flow init --preset next --agents
39
+ pnpm exec synced-flow init --preset vite
40
+ pnpm exec synced-flow init --preset astro
41
+ pnpm exec synced-flow init --preset wordpress
42
+ pnpm exec synced-flow init --preset plain
43
+ ```
44
+
45
+ For an existing project, install project-local AI guidance:
46
+
47
+ ```bash
48
+ pnpm exec synced-flow agents install
49
+ pnpm exec synced-flow agents install --target all
50
+ pnpm exec synced-flow agents status
51
+ pnpm exec synced-flow skill
52
+ ```
53
+
54
+ Use `--preset wordpress` for WordPress themes and plugins. It scans PHP and
55
+ template files, enables `includeCore`, and writes an enqueue-ready CSS file at
56
+ `assets/css/synced-flow.css`.
57
+
58
+ ## CSS Imports
59
+
60
+ For simple bundled apps:
61
+
62
+ ```css
63
+ @import "@syncedco/flow/styles.css";
64
+ @import "@syncedco/flow/defaults.css";
65
+ @import "./synced-flow.generated.css";
66
+ ```
67
+
68
+ For smaller core loading, import only the layers needed:
69
+
70
+ ```css
71
+ @import "@syncedco/flow/tokens.css";
72
+ @import "@syncedco/flow/reset.css";
73
+ @import "@syncedco/flow/base.css";
74
+ @import "@syncedco/flow/defaults.css";
75
+ @import "@syncedco/flow/layout.css";
76
+ @import "@syncedco/flow/components.css";
77
+ @import "./synced-flow.generated.css";
78
+ ```
79
+
80
+ Leave out `components.css` if the project only uses tokens and layout
81
+ primitives. Leave out `defaults.css` when content-style browser defaults should stay
82
+ intact. Leave out `utilities.css` unless static helpers such as `sf-text-*`,
83
+ `sf-prose`, `sr-only`, `not-sr-only`, `sf-skip-link`, `sf-focus-ring`,
84
+ `sf-touch-target`, `sf-list-reset`, `sf-link`, or `sf-full-bleed` are used.
85
+
86
+ ## Styling Rules
87
+
88
+ - Prefer primitives first: `sf-container`, `sf-section`, `sf-stack`,
89
+ `sf-cluster`, `sf-repel`, `sf-auto-grid`, `sf-split`, `sf-sidebar`,
90
+ `sf-frame`, and `sf-flow`.
91
+ - Prefer component primitives for common UI: `sf-button`, `sf-card`,
92
+ `sf-badge`, `sf-field`, and `sf-input`.
93
+ - Use `saas-landing` for public SaaS marketing pages. Use `saas-dashboard` for
94
+ authenticated app UI, admin panels, portals, CRMs, analytics dashboards,
95
+ metrics, tables, account menus, and login state.
96
+ - Do not implement authentication logic in Synced Flow markup. Wire sessions,
97
+ providers, permissions, and sign-out actions in the consuming app.
98
+ - Prefer native component patterns for common interaction: `sf-dialog`,
99
+ `sf-popover`, `sf-drawer`, `sf-drawer--stack`, `sf-disclosure`,
100
+ `sf-accordion`, `sf-tabs`, `sf-tooltip`, `sf-toast`, and `sf-banner`.
101
+ - Use `synced-flow pattern mobile-nav-drawer --markup` for complete mobile nav
102
+ drawers instead of composing only `sf-nav--mobile`.
103
+ - Use semantic utility classes such as `bg-background`, `text-foreground`,
104
+ `bg-primary`, `text-primary-foreground`, `border-border`, and `bg-surface`.
105
+ - Keep browser affordances by default: body links stay underlined, content
106
+ lists keep markers, focus styles stay visible, and reduced-motion preferences
107
+ are respected.
108
+ - Include `@syncedco/flow/defaults.css`, or run `synced-flow add defaults`, when a
109
+ site or app should remove raw link underlines and list markers globally.
110
+ - Use `sr-only` / `not-sr-only`, `sf-skip-link`, `sf-focus-ring`,
111
+ `sf-touch-target`, `sf-list-reset`, `sf-link`, and `sf-link-plain` for
112
+ accessibility and explicit UI styling.
113
+ - Put brand choices in `theme` config or theme presets rather than scattered
114
+ one-off CSS.
115
+ - Use modern CSS techniques already in the system: cascade layers, custom
116
+ properties, logical properties, `clamp()`, OKLCH colour, container-aware
117
+ layout, and `prefers-reduced-motion`.
118
+ - Keep class names complete in source files. Do not compose class names from
119
+ fragments.
120
+ - Use `safelist` only when dynamic classes are unavoidable.
121
+
122
+ ## Migration Guidance
123
+
124
+ When migrating from Tailwind, frame the work as migration guidance only.
125
+
126
+ - Do not describe Synced Flow as a Tailwind clone or full replacement.
127
+ - Use `responsiveVariants: true` only while migrating existing breakpoint
128
+ classes such as `sm:` or `lg:`.
129
+ - Replace breakpoint-heavy layout with fluid primitives over time.
130
+ - Move repeated visual decisions into tokens and theme config.
131
+
132
+ ## Finish Checklist
133
+
134
+ Run:
135
+
136
+ ```bash
137
+ pnpm flow:build
138
+ pnpm flow:check
139
+ pnpm exec synced-flow lint --json
140
+ pnpm flow:doctor
141
+ ```
142
+
143
+ For package or repo changes, also run:
144
+
145
+ ```bash
146
+ pnpm check
147
+ pnpm test
148
+ pnpm pack --dry-run
149
+ ```
150
+
151
+ If `doctor` warns about stale CSS, run `pnpm flow:build`.
package/src/config.ts ADDED
@@ -0,0 +1,98 @@
1
+ type TokenMap = Record<string, string>
2
+
3
+ export type SyncedFlowTheme = {
4
+ /**
5
+ * Project font stacks. Values should be complete CSS font-family values.
6
+ */
7
+ fonts?: Partial<Record<'sans' | 'display' | 'mono', string>>
8
+ /**
9
+ * Semantic colour tokens. Use OKLCH where possible.
10
+ */
11
+ colours?: TokenMap
12
+ /**
13
+ * Semantic colour overrides for .sf-theme-dark or [data-sf-theme="dark"].
14
+ */
15
+ darkColours?: TokenMap
16
+ /**
17
+ * Radius scale overrides such as md, lg, xl, full.
18
+ */
19
+ radii?: TokenMap
20
+ /**
21
+ * Layout-level tokens.
22
+ */
23
+ layout?: {
24
+ containerMax?: string
25
+ gutter?: string
26
+ columns?: number
27
+ }
28
+ /**
29
+ * Component-level token overrides.
30
+ */
31
+ components?: {
32
+ button?: {
33
+ radius?: string
34
+ blockSize?: string
35
+ paddingInline?: string
36
+ }
37
+ card?: {
38
+ radius?: string
39
+ padding?: string
40
+ shadow?: string
41
+ }
42
+ input?: {
43
+ radius?: string
44
+ blockSize?: string
45
+ }
46
+ }
47
+ }
48
+
49
+ export type SyncedFlowConfig = {
50
+ /**
51
+ * Directory used to resolve scan and output paths. Defaults to the current
52
+ * working directory.
53
+ */
54
+ cwd?: string
55
+ /**
56
+ * Source directories that the CLI scans for class tokens.
57
+ */
58
+ scan?: string[]
59
+ /**
60
+ * Class tokens to always generate when they are composed dynamically.
61
+ */
62
+ safelist?: string[]
63
+ /**
64
+ * Generated CSS output file.
65
+ */
66
+ out?: string
67
+ /**
68
+ * Project token overrides emitted into the generated CSS.
69
+ */
70
+ theme?: SyncedFlowTheme
71
+ /**
72
+ * Include reset, base, layout, and component CSS in the generated file.
73
+ * Most projects should import @syncedco/flow/styles.css and leave this false.
74
+ */
75
+ includeCore?: boolean
76
+ /**
77
+ * Include site/UI defaults when includeCore is true. For modular projects,
78
+ * import @syncedco/flow/defaults.css from the CSS entry instead.
79
+ */
80
+ includeDefaults?: boolean
81
+ /**
82
+ * Enable breakpoint-style variants such as sm:, md:, lg:, and xl:.
83
+ * Leave false for strict fluid projects; enable only during migrations.
84
+ */
85
+ responsiveVariants?: boolean
86
+ /**
87
+ * Fail the CLI when unsupported class tokens are detected.
88
+ */
89
+ failOnUnsupported?: boolean
90
+ /**
91
+ * Suppress non-critical CLI warnings.
92
+ */
93
+ quiet?: boolean
94
+ }
95
+
96
+ export function defineConfig(config: SyncedFlowConfig): SyncedFlowConfig {
97
+ return config
98
+ }
package/src/index.ts ADDED
@@ -0,0 +1,75 @@
1
+ export { defineConfig, type SyncedFlowConfig, type SyncedFlowTheme } from './config.js'
2
+ export { presetNames, themePresets } from '../src/presets.mjs'
3
+
4
+ export type ClassValue = string | number | boolean | null | undefined | ClassValue[] | Record<string, unknown>
5
+
6
+ export function cx(...inputs: ClassValue[]) {
7
+ const classes: string[] = []
8
+
9
+ for (const input of inputs) appendClassValue(classes, input)
10
+
11
+ return classes.join(' ')
12
+ }
13
+
14
+ function appendClassValue(classes: string[], value: ClassValue): void {
15
+ if (!value) return
16
+
17
+ if (typeof value === 'string' || typeof value === 'number') {
18
+ classes.push(String(value))
19
+ return
20
+ }
21
+
22
+ if (Array.isArray(value)) {
23
+ for (const item of value) appendClassValue(classes, item)
24
+ return
25
+ }
26
+
27
+ if (typeof value === 'object') {
28
+ for (const [className, enabled] of Object.entries(value)) {
29
+ if (enabled) classes.push(className)
30
+ }
31
+ }
32
+ }
33
+
34
+ export const fluidSystem = {
35
+ layout: {
36
+ container: 'sf-container',
37
+ section: 'sf-section',
38
+ stack: 'sf-stack',
39
+ cluster: 'sf-cluster',
40
+ repel: 'sf-repel',
41
+ grid: 'sf-grid',
42
+ autoGrid: 'sf-auto-grid',
43
+ sidebar: 'sf-sidebar',
44
+ switcher: 'sf-switcher',
45
+ frame: 'sf-frame',
46
+ cover: 'sf-cover',
47
+ flow: 'sf-flow',
48
+ },
49
+ components: {
50
+ button: 'sf-button',
51
+ card: 'sf-card',
52
+ badge: 'sf-badge',
53
+ field: 'sf-field',
54
+ input: 'sf-input',
55
+ },
56
+ utilities: {
57
+ visuallyHidden: 'sf-visually-hidden',
58
+ notVisuallyHidden: 'sf-not-visually-hidden',
59
+ srOnly: 'sr-only',
60
+ notSrOnly: 'not-sr-only',
61
+ skipLink: 'sf-skip-link',
62
+ focusRing: 'sf-focus-ring',
63
+ focusRingInset: 'sf-focus-ring-inset',
64
+ touchTarget: 'sf-touch-target',
65
+ listReset: 'sf-list-reset',
66
+ listDisc: 'sf-list-disc',
67
+ listDecimal: 'sf-list-decimal',
68
+ link: 'sf-link',
69
+ linkSubtle: 'sf-link-subtle',
70
+ linkPlain: 'sf-link-plain',
71
+ prose: 'sf-prose',
72
+ },
73
+ } as const
74
+
75
+ export type FluidSystem = typeof fluidSystem
@@ -0,0 +1,21 @@
1
+ export type SyncedFlowThemePreset = {
2
+ fonts?: Record<string, string>
3
+ colours?: Record<string, string>
4
+ darkColours?: Record<string, string>
5
+ radii?: Record<string, string>
6
+ layout?: {
7
+ containerMax?: string
8
+ gutter?: string
9
+ columns?: number
10
+ }
11
+ components?: Record<string, Record<string, string>>
12
+ }
13
+
14
+ export declare const themePresets: {
15
+ synced: SyncedFlowThemePreset
16
+ neutralSaas: SyncedFlowThemePreset
17
+ editorial: SyncedFlowThemePreset
18
+ darkApp: SyncedFlowThemePreset
19
+ }
20
+
21
+ export declare const presetNames: string[]
@@ -0,0 +1,171 @@
1
+ export const themePresets = {
2
+ synced: {
3
+ fonts: {
4
+ sans: 'Inter, ui-sans-serif, system-ui, sans-serif',
5
+ display: 'Fraunces, Georgia, serif',
6
+ },
7
+ colours: {
8
+ background: 'oklch(98.6% 0.006 80)',
9
+ foreground: 'oklch(18% 0.026 250)',
10
+ muted: 'oklch(45% 0.018 236)',
11
+ surface: 'oklch(100% 0 0)',
12
+ surfaceAlt: 'oklch(96.4% 0.011 80)',
13
+ border: 'oklch(18% 0.026 250 / 0.12)',
14
+ primary: 'oklch(68% 0.18 44)',
15
+ primaryHover: 'oklch(60% 0.17 42)',
16
+ primaryForeground: 'oklch(100% 0 0)',
17
+ accent: 'oklch(70% 0.12 205)',
18
+ link: 'oklch(58% 0.17 42)',
19
+ linkHover: 'oklch(68% 0.18 44)',
20
+ ring: 'oklch(68% 0.18 44)',
21
+ },
22
+ components: {
23
+ button: {
24
+ radius: '0.5rem',
25
+ blockSize: '2.75rem',
26
+ paddingInline: 'var(--sf-space-s)',
27
+ },
28
+ card: {
29
+ radius: '0.75rem',
30
+ padding: 'var(--sf-space-m-l)',
31
+ },
32
+ input: {
33
+ radius: '0.5rem',
34
+ blockSize: '2.75rem',
35
+ },
36
+ },
37
+ },
38
+ neutralSaas: {
39
+ fonts: {
40
+ sans: 'Inter, ui-sans-serif, system-ui, sans-serif',
41
+ display: 'Inter, ui-sans-serif, system-ui, sans-serif',
42
+ },
43
+ colours: {
44
+ background: 'oklch(98.5% 0.002 247)',
45
+ foreground: 'oklch(20.8% 0.042 265)',
46
+ muted: 'oklch(44.6% 0.043 257)',
47
+ surface: 'oklch(100% 0 0)',
48
+ surfaceAlt: 'oklch(96.8% 0.007 247)',
49
+ border: 'oklch(20.8% 0.042 265 / 0.12)',
50
+ primary: 'oklch(52% 0.14 250)',
51
+ primaryHover: 'oklch(44% 0.13 250)',
52
+ primaryForeground: 'oklch(100% 0 0)',
53
+ accent: 'oklch(70% 0.12 205)',
54
+ link: 'oklch(45% 0.13 250)',
55
+ linkHover: 'oklch(52% 0.14 250)',
56
+ ring: 'oklch(52% 0.14 250)',
57
+ },
58
+ layout: {
59
+ containerMax: '76rem',
60
+ gutter: 'var(--sf-space-s-l)',
61
+ },
62
+ components: {
63
+ button: {
64
+ radius: '0.5rem',
65
+ blockSize: '2.625rem',
66
+ },
67
+ card: {
68
+ radius: '0.625rem',
69
+ },
70
+ input: {
71
+ radius: '0.5rem',
72
+ blockSize: '2.625rem',
73
+ },
74
+ },
75
+ },
76
+ editorial: {
77
+ fonts: {
78
+ sans: 'Inter, ui-sans-serif, system-ui, sans-serif',
79
+ display: 'Fraunces, Georgia, serif',
80
+ },
81
+ colours: {
82
+ background: 'oklch(97% 0.018 78)',
83
+ foreground: 'oklch(18% 0.022 55)',
84
+ muted: 'oklch(43% 0.02 65)',
85
+ surface: 'oklch(100% 0 0)',
86
+ surfaceAlt: 'oklch(94% 0.02 80)',
87
+ border: 'oklch(18% 0.022 55 / 0.14)',
88
+ primary: 'oklch(58% 0.17 42)',
89
+ primaryHover: 'oklch(50% 0.16 40)',
90
+ primaryForeground: 'oklch(100% 0 0)',
91
+ accent: 'oklch(62% 0.13 150)',
92
+ link: 'oklch(50% 0.16 40)',
93
+ linkHover: 'oklch(58% 0.17 42)',
94
+ ring: 'oklch(58% 0.17 42)',
95
+ },
96
+ layout: {
97
+ containerMax: '72rem',
98
+ gutter: 'var(--sf-space-m-l)',
99
+ },
100
+ components: {
101
+ button: {
102
+ radius: '999rem',
103
+ blockSize: '2.75rem',
104
+ },
105
+ card: {
106
+ radius: '0.5rem',
107
+ padding: 'var(--sf-space-l)',
108
+ },
109
+ input: {
110
+ radius: '0.375rem',
111
+ },
112
+ },
113
+ },
114
+ darkApp: {
115
+ fonts: {
116
+ sans: 'Inter, ui-sans-serif, system-ui, sans-serif',
117
+ display: 'Inter, ui-sans-serif, system-ui, sans-serif',
118
+ },
119
+ colours: {
120
+ background: 'oklch(13.5% 0.03 252)',
121
+ foreground: 'oklch(96% 0.008 86)',
122
+ muted: 'oklch(78% 0.012 86)',
123
+ surface: 'oklch(18% 0.026 250)',
124
+ surfaceAlt: 'oklch(22% 0.024 248)',
125
+ border: 'oklch(100% 0 0 / 0.14)',
126
+ primary: 'oklch(70% 0.12 205)',
127
+ primaryHover: 'oklch(76% 0.12 205)',
128
+ primaryForeground: 'oklch(13.5% 0.03 252)',
129
+ accent: 'oklch(68% 0.18 44)',
130
+ link: 'oklch(76% 0.12 205)',
131
+ linkHover: 'oklch(82% 0.1 205)',
132
+ ring: 'oklch(70% 0.12 205)',
133
+ },
134
+ darkColours: {
135
+ background: 'oklch(13.5% 0.03 252)',
136
+ foreground: 'oklch(96% 0.008 86)',
137
+ muted: 'oklch(78% 0.012 86)',
138
+ subtle: 'oklch(68% 0.012 86)',
139
+ surface: 'oklch(18% 0.026 250)',
140
+ surfaceAlt: 'oklch(22% 0.024 248)',
141
+ surfaceRaised: 'oklch(21% 0.028 250)',
142
+ surfaceInset: 'oklch(15% 0.03 252)',
143
+ border: 'oklch(100% 0 0 / 0.14)',
144
+ borderStrong: 'oklch(100% 0 0 / 0.24)',
145
+ primarySoft: 'oklch(70% 0.12 205 / 0.16)',
146
+ primarySoftBorder: 'oklch(70% 0.12 205 / 0.32)',
147
+ link: 'oklch(76% 0.12 205)',
148
+ linkHover: 'oklch(82% 0.1 205)',
149
+ ring: 'oklch(70% 0.12 205)',
150
+ },
151
+ layout: {
152
+ containerMax: '80rem',
153
+ gutter: 'var(--sf-space-s-l)',
154
+ },
155
+ components: {
156
+ button: {
157
+ radius: '0.5rem',
158
+ blockSize: '2.625rem',
159
+ },
160
+ card: {
161
+ radius: '0.75rem',
162
+ },
163
+ input: {
164
+ radius: '0.5rem',
165
+ blockSize: '2.625rem',
166
+ },
167
+ },
168
+ },
169
+ }
170
+
171
+ export const presetNames = Object.keys(themePresets)
package/src/tokens.mjs ADDED
@@ -0,0 +1,138 @@
1
+ export const fluidConfig = {
2
+ minViewport: 360,
3
+ maxViewport: 1536,
4
+ minRoot: 16,
5
+ maxRoot: 18,
6
+ minTypeScale: 1.2,
7
+ maxTypeScale: 1.25,
8
+ typeMinStep: -2,
9
+ typeMaxStep: 8,
10
+ gridColumns: 12,
11
+ gridMaxWidthRem: 90,
12
+ }
13
+
14
+ export const primitiveTokens = {
15
+ fonts: {
16
+ sans: 'Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif',
17
+ display: 'Fraunces, Georgia, "Times New Roman", serif',
18
+ mono: '"SFMono-Regular", Consolas, "Liberation Mono", Menlo, monospace',
19
+ },
20
+ colours: {
21
+ neutral0: 'oklch(100% 0 0)',
22
+ neutral50: 'oklch(98.6% 0.006 80)',
23
+ neutral100: 'oklch(96.4% 0.011 80)',
24
+ neutral200: 'oklch(90.8% 0.014 78)',
25
+ neutral300: 'oklch(82% 0.018 76)',
26
+ neutral400: 'oklch(68% 0.018 246)',
27
+ neutral500: 'oklch(53% 0.018 244)',
28
+ neutral600: 'oklch(43% 0.02 244)',
29
+ neutral700: 'oklch(34% 0.02 244)',
30
+ neutral800: 'oklch(27% 0.022 246)',
31
+ neutral850: 'oklch(22% 0.024 248)',
32
+ neutral900: 'oklch(18% 0.026 250)',
33
+ neutral950: 'oklch(13.5% 0.03 252)',
34
+ amber500: 'oklch(78% 0.15 82)',
35
+ amber700: 'oklch(54% 0.13 74)',
36
+ orange500: 'oklch(74% 0.17 48)',
37
+ orange600: 'oklch(68% 0.18 44)',
38
+ orange700: 'oklch(58% 0.17 42)',
39
+ green500: 'oklch(62% 0.13 150)',
40
+ green600: 'oklch(54% 0.13 150)',
41
+ green700: 'oklch(44% 0.12 150)',
42
+ cyan500: 'oklch(70% 0.12 205)',
43
+ cyan600: 'oklch(58% 0.12 210)',
44
+ blue600: 'oklch(52% 0.14 250)',
45
+ red600: 'oklch(56% 0.2 28)',
46
+ red700: 'oklch(47% 0.19 28)',
47
+ },
48
+ radii: {
49
+ none: '0',
50
+ xs: '0.25rem',
51
+ sm: '0.375rem',
52
+ md: '0.5rem',
53
+ lg: '0.75rem',
54
+ xl: '1rem',
55
+ '2xl': '1.25rem',
56
+ '3xl': '1.5rem',
57
+ full: '999rem',
58
+ },
59
+ shadows: {
60
+ sm: '0 0.125rem 0.375rem oklch(0% 0 0 / 0.08)',
61
+ md: '0 0.75rem 1.75rem oklch(0% 0 0 / 0.12)',
62
+ lg: '0 1.25rem 3rem oklch(0% 0 0 / 0.16)',
63
+ xl: '0 1.75rem 4rem oklch(0% 0 0 / 0.18)',
64
+ inset: 'inset 0 0 0 1px var(--sf-colour-border)',
65
+ glow: '0 0 2rem oklch(68% 0.18 44 / 0.24)',
66
+ },
67
+ }
68
+
69
+ export const semanticTokens = {
70
+ colours: {
71
+ background: 'var(--sf-colour-neutral-50)',
72
+ foreground: 'var(--sf-colour-neutral-900)',
73
+ muted: 'var(--sf-colour-neutral-700)',
74
+ subtle: 'var(--sf-colour-neutral-500)',
75
+ surface: 'var(--sf-colour-neutral-0)',
76
+ surfaceAlt: 'var(--sf-colour-neutral-100)',
77
+ surfaceRaised: 'var(--sf-colour-neutral-0)',
78
+ surfaceInset: 'var(--sf-colour-neutral-100)',
79
+ border: 'oklch(18% 0.026 250 / 0.12)',
80
+ borderStrong: 'oklch(18% 0.026 250 / 0.22)',
81
+ primary: 'var(--sf-colour-orange-600)',
82
+ primaryHover: 'var(--sf-colour-orange-700)',
83
+ primaryForeground: 'var(--sf-colour-neutral-0)',
84
+ primarySoft: 'oklch(68% 0.18 44 / 0.12)',
85
+ primarySoftBorder: 'oklch(68% 0.18 44 / 0.28)',
86
+ link: 'var(--sf-colour-orange-700)',
87
+ linkHover: 'var(--sf-colour-orange-600)',
88
+ accent: 'var(--sf-colour-cyan-500)',
89
+ accentForeground: 'var(--sf-colour-neutral-950)',
90
+ success: 'var(--sf-colour-green-500)',
91
+ successForeground: 'var(--sf-colour-neutral-0)',
92
+ successSoft: 'oklch(62% 0.13 150 / 0.12)',
93
+ warning: 'var(--sf-colour-amber-500)',
94
+ warningForeground: 'var(--sf-colour-neutral-950)',
95
+ warningSoft: 'oklch(78% 0.15 82 / 0.16)',
96
+ danger: 'var(--sf-colour-red-600)',
97
+ dangerForeground: 'var(--sf-colour-neutral-0)',
98
+ dangerSoft: 'oklch(56% 0.2 28 / 0.12)',
99
+ info: 'var(--sf-colour-cyan-600)',
100
+ infoForeground: 'var(--sf-colour-neutral-0)',
101
+ infoSoft: 'oklch(70% 0.12 205 / 0.14)',
102
+ ring: 'var(--sf-colour-orange-600)',
103
+ },
104
+ }
105
+
106
+ export const componentTokens = {
107
+ button: {
108
+ radius: 'var(--sf-radius-md)',
109
+ blockSize: '2.75rem',
110
+ paddingInline: 'var(--sf-space-s)',
111
+ },
112
+ card: {
113
+ radius: 'var(--sf-radius-lg)',
114
+ padding: 'var(--sf-space-m-l)',
115
+ },
116
+ input: {
117
+ radius: 'var(--sf-radius-md)',
118
+ blockSize: '2.75rem',
119
+ paddingInline: 'var(--sf-space-s)',
120
+ border: 'var(--sf-colour-border)',
121
+ background: 'var(--sf-colour-surface)',
122
+ },
123
+ alert: {
124
+ radius: 'var(--sf-radius-lg)',
125
+ padding: 'var(--sf-space-s-m)',
126
+ },
127
+ nav: {
128
+ gap: 'var(--sf-space-xs-s)',
129
+ linkRadius: 'var(--sf-radius-sm)',
130
+ },
131
+ }
132
+
133
+ export const tokens = {
134
+ fluidConfig,
135
+ primitiveTokens,
136
+ semanticTokens,
137
+ componentTokens,
138
+ }
@@ -0,0 +1,47 @@
1
+ export const fluidConfig = {
2
+ minViewport: 360,
3
+ maxViewport: 1536,
4
+ minRoot: 16,
5
+ maxRoot: 18,
6
+ minTypeScale: 1.2,
7
+ maxTypeScale: 1.25,
8
+ typeMinStep: -2,
9
+ typeMaxStep: 8,
10
+ gridColumns: 12,
11
+ gridMaxWidthRem: 90,
12
+ radii: {
13
+ none: '0',
14
+ xs: '0.25rem',
15
+ sm: '0.375rem',
16
+ md: '0.5rem',
17
+ lg: '0.75rem',
18
+ xl: '1rem',
19
+ '2xl': '1.25rem',
20
+ '3xl': '1.5rem',
21
+ full: '999rem',
22
+ },
23
+ colours: {
24
+ ink950: 'oklch(14% 0.025 248)',
25
+ ink900: 'oklch(18% 0.024 246)',
26
+ ink800: 'oklch(24% 0.022 244)',
27
+ ink700: 'oklch(34% 0.02 240)',
28
+ ink600: 'oklch(45% 0.018 236)',
29
+ ink500: 'oklch(56% 0.015 232)',
30
+ paper: 'oklch(98.6% 0.014 78)',
31
+ paperAlt: 'oklch(96.6% 0.018 82)',
32
+ surface: 'oklch(99% 0.004 90)',
33
+ surfaceAlt: 'oklch(96% 0.015 80)',
34
+ orange700: 'oklch(58% 0.17 44)',
35
+ orange600: 'oklch(69% 0.18 44)',
36
+ orange500: 'oklch(74% 0.17 48)',
37
+ orangeSoft: 'oklch(69% 0.18 44 / 0.1)',
38
+ green700: 'oklch(45% 0.12 148)',
39
+ green600: 'oklch(55% 0.12 148)',
40
+ green100: 'oklch(90% 0.06 148)',
41
+ blue600: 'oklch(50% 0.13 236)',
42
+ purple600: 'oklch(55% 0.2 280)',
43
+ red600: 'oklch(55% 0.2 28)',
44
+ white: 'oklch(100% 0 0)',
45
+ black: 'oklch(0% 0 0)',
46
+ },
47
+ }