@syncedco/flow 0.2.0 → 0.3.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/bin/synced-flow.mjs +362 -3
- package/components.css +173 -1
- package/docs/api-contract.md +3 -3
- package/docs/patterns.md +7 -0
- package/docs/system-primitives.md +7 -5
- package/docs/tokens.md +5 -1
- package/layout.css +89 -0
- package/package.json +1 -1
- package/skills/synced-flow/SKILL.md +23 -6
- package/src/tokens.mjs +10 -0
- package/styles.css +282 -1
- package/tokens.css +19 -0
- package/utilities.css +1 -0
package/components.css
CHANGED
|
@@ -885,6 +885,76 @@
|
|
|
885
885
|
--sf-data-table-padding-inline: var(--sf-space-xs);
|
|
886
886
|
}
|
|
887
887
|
|
|
888
|
+
.sf-data-table :where(th button, .sf-table-sort) {
|
|
889
|
+
align-items: center;
|
|
890
|
+
color: inherit;
|
|
891
|
+
display: inline-flex;
|
|
892
|
+
font: inherit;
|
|
893
|
+
font-weight: inherit;
|
|
894
|
+
gap: var(--sf-space-3xs);
|
|
895
|
+
padding: 0;
|
|
896
|
+
}
|
|
897
|
+
|
|
898
|
+
.sf-data-table :where(th button, .sf-table-sort)[aria-sort]::after {
|
|
899
|
+
color: var(--sf-colour-subtle);
|
|
900
|
+
content: "\2195";
|
|
901
|
+
font-size: var(--sf-step--2);
|
|
902
|
+
}
|
|
903
|
+
|
|
904
|
+
.sf-data-table :where(th button, .sf-table-sort)[aria-sort="ascending"]::after { content: "\2191"; }
|
|
905
|
+
.sf-data-table :where(th button, .sf-table-sort)[aria-sort="descending"]::after { content: "\2193"; }
|
|
906
|
+
|
|
907
|
+
.sf-data-table tr[data-clickable="true"] {
|
|
908
|
+
cursor: pointer;
|
|
909
|
+
}
|
|
910
|
+
|
|
911
|
+
.sf-data-table tr[data-clickable="true"]:focus-within {
|
|
912
|
+
outline: 0.125rem solid var(--sf-colour-ring);
|
|
913
|
+
outline-offset: -0.125rem;
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
@container (max-width: 38rem) {
|
|
917
|
+
.sf-table-wrap[data-view="cards"] {
|
|
918
|
+
border: 0;
|
|
919
|
+
overflow: visible;
|
|
920
|
+
}
|
|
921
|
+
|
|
922
|
+
.sf-table-wrap[data-view="cards"] .sf-data-table,
|
|
923
|
+
.sf-table-wrap[data-view="cards"] .sf-data-table :where(thead, tbody, tr, th, td) {
|
|
924
|
+
display: block;
|
|
925
|
+
min-inline-size: 0;
|
|
926
|
+
}
|
|
927
|
+
|
|
928
|
+
.sf-table-wrap[data-view="cards"] .sf-data-table thead {
|
|
929
|
+
display: none;
|
|
930
|
+
}
|
|
931
|
+
|
|
932
|
+
.sf-table-wrap[data-view="cards"] .sf-data-table tr {
|
|
933
|
+
background: var(--sf-colour-surface);
|
|
934
|
+
border: 1px solid var(--sf-colour-border);
|
|
935
|
+
border-radius: var(--sf-radius-panel);
|
|
936
|
+
margin-block-end: var(--sf-space-xs);
|
|
937
|
+
padding: var(--sf-space-xs);
|
|
938
|
+
}
|
|
939
|
+
|
|
940
|
+
.sf-table-wrap[data-view="cards"] .sf-data-table td {
|
|
941
|
+
align-items: center;
|
|
942
|
+
border: 0;
|
|
943
|
+
display: flex;
|
|
944
|
+
gap: var(--sf-space-s);
|
|
945
|
+
justify-content: space-between;
|
|
946
|
+
padding-block: var(--sf-space-2xs);
|
|
947
|
+
padding-inline: 0;
|
|
948
|
+
}
|
|
949
|
+
|
|
950
|
+
.sf-table-wrap[data-view="cards"] .sf-data-table td::before {
|
|
951
|
+
color: var(--sf-colour-muted);
|
|
952
|
+
content: attr(data-label);
|
|
953
|
+
font-size: var(--sf-step--1);
|
|
954
|
+
font-weight: 800;
|
|
955
|
+
}
|
|
956
|
+
}
|
|
957
|
+
|
|
888
958
|
.sf-status {
|
|
889
959
|
align-items: center;
|
|
890
960
|
background: var(--sf-status-bg, var(--sf-colour-surface-alt));
|
|
@@ -900,6 +970,12 @@
|
|
|
900
970
|
padding-inline: .7em;
|
|
901
971
|
}
|
|
902
972
|
|
|
973
|
+
.sf-status[data-size="sm"] {
|
|
974
|
+
font-size: var(--sf-step--2);
|
|
975
|
+
min-block-size: 1.35rem;
|
|
976
|
+
padding-inline: .55em;
|
|
977
|
+
}
|
|
978
|
+
|
|
903
979
|
.sf-status::before {
|
|
904
980
|
background: currentColor;
|
|
905
981
|
block-size: .42em;
|
|
@@ -1055,6 +1131,13 @@
|
|
|
1055
1131
|
gap: var(--sf-form-gap, var(--sf-space-s-m));
|
|
1056
1132
|
}
|
|
1057
1133
|
|
|
1134
|
+
.sf-form[data-density="compact"],
|
|
1135
|
+
.sf-field[data-density="compact"] {
|
|
1136
|
+
--sf-form-gap: var(--sf-space-xs);
|
|
1137
|
+
--sf-input-block-size: 2.25rem;
|
|
1138
|
+
--sf-input-padding-inline: var(--sf-space-xs);
|
|
1139
|
+
}
|
|
1140
|
+
|
|
1058
1141
|
.sf-fieldset {
|
|
1059
1142
|
border: 1px solid var(--sf-colour-border);
|
|
1060
1143
|
border-radius: var(--sf-radius-panel);
|
|
@@ -1120,6 +1203,45 @@
|
|
|
1120
1203
|
transition: background-color var(--sf-duration-fast) var(--sf-ease-standard), border-color var(--sf-duration-fast) var(--sf-ease-standard), box-shadow var(--sf-duration-fast) var(--sf-ease-standard);
|
|
1121
1204
|
}
|
|
1122
1205
|
|
|
1206
|
+
.sf-search {
|
|
1207
|
+
position: relative;
|
|
1208
|
+
}
|
|
1209
|
+
|
|
1210
|
+
.sf-search::before {
|
|
1211
|
+
block-size: .75em;
|
|
1212
|
+
border: 0.125em solid currentColor;
|
|
1213
|
+
border-radius: var(--sf-radius-full);
|
|
1214
|
+
color: var(--sf-colour-subtle);
|
|
1215
|
+
content: "";
|
|
1216
|
+
inline-size: .75em;
|
|
1217
|
+
inset-block-start: 50%;
|
|
1218
|
+
inset-inline-start: var(--sf-space-xs);
|
|
1219
|
+
line-height: 1;
|
|
1220
|
+
position: absolute;
|
|
1221
|
+
transform: translateY(-58%);
|
|
1222
|
+
}
|
|
1223
|
+
|
|
1224
|
+
.sf-search::after {
|
|
1225
|
+
background: var(--sf-colour-subtle);
|
|
1226
|
+
block-size: .125em;
|
|
1227
|
+
content: "";
|
|
1228
|
+
inline-size: .45em;
|
|
1229
|
+
inset-block-start: 50%;
|
|
1230
|
+
inset-inline-start: calc(var(--sf-space-xs) + .58em);
|
|
1231
|
+
position: absolute;
|
|
1232
|
+
transform: translateY(120%) rotate(45deg);
|
|
1233
|
+
transform-origin: inline-start center;
|
|
1234
|
+
}
|
|
1235
|
+
|
|
1236
|
+
.sf-search > .sf-input {
|
|
1237
|
+
padding-inline-start: var(--sf-space-l);
|
|
1238
|
+
}
|
|
1239
|
+
|
|
1240
|
+
.sf-help[data-density="compact"],
|
|
1241
|
+
.sf-error[data-density="compact"] {
|
|
1242
|
+
font-size: var(--sf-step--2);
|
|
1243
|
+
}
|
|
1244
|
+
|
|
1123
1245
|
.sf-textarea {
|
|
1124
1246
|
min-block-size: var(--sf-textarea-block-size, 8rem);
|
|
1125
1247
|
padding-block: var(--sf-space-xs);
|
|
@@ -1240,7 +1362,7 @@
|
|
|
1240
1362
|
.sf-dialog::backdrop,
|
|
1241
1363
|
.sf-popover::backdrop,
|
|
1242
1364
|
.sf-drawer::backdrop {
|
|
1243
|
-
background:
|
|
1365
|
+
background: var(--sf-colour-backdrop);
|
|
1244
1366
|
}
|
|
1245
1367
|
|
|
1246
1368
|
.sf-dialog__header,
|
|
@@ -1266,6 +1388,11 @@
|
|
|
1266
1388
|
justify-content: flex-end;
|
|
1267
1389
|
}
|
|
1268
1390
|
|
|
1391
|
+
.sf-dialog[data-layout="form"] .sf-dialog__body {
|
|
1392
|
+
display: grid;
|
|
1393
|
+
gap: var(--sf-space-s);
|
|
1394
|
+
}
|
|
1395
|
+
|
|
1269
1396
|
.sf-popover,
|
|
1270
1397
|
.sf-menu-popover,
|
|
1271
1398
|
.sf-tooltip,
|
|
@@ -1319,6 +1446,16 @@
|
|
|
1319
1446
|
background: var(--sf-colour-surface-alt);
|
|
1320
1447
|
}
|
|
1321
1448
|
|
|
1449
|
+
.sf-menu :where(a, button)[data-variant="danger"],
|
|
1450
|
+
.sf-menu-popover :where(a, button)[data-variant="danger"] {
|
|
1451
|
+
color: var(--sf-colour-danger);
|
|
1452
|
+
}
|
|
1453
|
+
|
|
1454
|
+
.sf-menu :where(a, button)[data-variant="danger"]:hover,
|
|
1455
|
+
.sf-menu-popover :where(a, button)[data-variant="danger"]:hover {
|
|
1456
|
+
background: var(--sf-colour-danger-soft);
|
|
1457
|
+
}
|
|
1458
|
+
|
|
1322
1459
|
.sf-tooltip {
|
|
1323
1460
|
border-radius: var(--sf-radius-md);
|
|
1324
1461
|
box-shadow: var(--sf-shadow-md);
|
|
@@ -1345,6 +1482,16 @@
|
|
|
1345
1482
|
top: var(--sf-space-s);
|
|
1346
1483
|
}
|
|
1347
1484
|
|
|
1485
|
+
.sf-toast-stack {
|
|
1486
|
+
display: grid;
|
|
1487
|
+
gap: var(--sf-space-xs);
|
|
1488
|
+
inline-size: min(100% - (var(--sf-gutter) * 2), var(--sf-toast-width, 24rem));
|
|
1489
|
+
inset-block-start: var(--sf-space-s);
|
|
1490
|
+
inset-inline-end: var(--sf-space-s);
|
|
1491
|
+
position: fixed;
|
|
1492
|
+
z-index: 50;
|
|
1493
|
+
}
|
|
1494
|
+
|
|
1348
1495
|
.sf-banner {
|
|
1349
1496
|
block-size: auto;
|
|
1350
1497
|
border-radius: var(--sf-radius-lg);
|
|
@@ -1458,14 +1605,21 @@
|
|
|
1458
1605
|
|
|
1459
1606
|
.sf-tab {
|
|
1460
1607
|
border-block-end: 0.125rem solid transparent;
|
|
1608
|
+
border-radius: var(--sf-radius-full);
|
|
1461
1609
|
color: var(--sf-colour-muted);
|
|
1462
1610
|
display: inline-flex;
|
|
1611
|
+
gap: var(--sf-space-2xs);
|
|
1463
1612
|
font-weight: 800;
|
|
1464
1613
|
padding-block: var(--sf-space-xs);
|
|
1465
1614
|
padding-inline: var(--sf-space-s);
|
|
1466
1615
|
text-decoration: none;
|
|
1467
1616
|
}
|
|
1468
1617
|
|
|
1618
|
+
.sf-tab[data-variant="pill"] {
|
|
1619
|
+
border: 1px solid transparent;
|
|
1620
|
+
padding-block: var(--sf-space-2xs);
|
|
1621
|
+
}
|
|
1622
|
+
|
|
1469
1623
|
.sf-tab:hover,
|
|
1470
1624
|
.sf-tab[aria-selected="true"],
|
|
1471
1625
|
.sf-tab[data-state="active"] {
|
|
@@ -1473,6 +1627,24 @@
|
|
|
1473
1627
|
color: var(--sf-colour-foreground);
|
|
1474
1628
|
}
|
|
1475
1629
|
|
|
1630
|
+
.sf-tab[data-variant="pill"]:hover,
|
|
1631
|
+
.sf-tab[data-variant="pill"][aria-selected="true"],
|
|
1632
|
+
.sf-tab[data-variant="pill"][data-state="active"] {
|
|
1633
|
+
background: var(--sf-colour-primary-soft);
|
|
1634
|
+
border-color: var(--sf-colour-primary-soft-border);
|
|
1635
|
+
color: var(--sf-colour-primary);
|
|
1636
|
+
}
|
|
1637
|
+
|
|
1638
|
+
.sf-tab__count {
|
|
1639
|
+
background: var(--sf-colour-surface-alt);
|
|
1640
|
+
border: 1px solid var(--sf-colour-border);
|
|
1641
|
+
border-radius: var(--sf-radius-full);
|
|
1642
|
+
color: var(--sf-colour-muted);
|
|
1643
|
+
font-size: var(--sf-step--2);
|
|
1644
|
+
line-height: 1;
|
|
1645
|
+
padding: .25em .55em;
|
|
1646
|
+
}
|
|
1647
|
+
|
|
1476
1648
|
.sf-tab-panel {
|
|
1477
1649
|
background: var(--sf-colour-surface);
|
|
1478
1650
|
border: 1px solid var(--sf-colour-border);
|
package/docs/api-contract.md
CHANGED
|
@@ -13,9 +13,9 @@ These are intended for application code and examples.
|
|
|
13
13
|
| Imports | `@syncedco/flow/styles.css`, `tokens.css`, `reset.css`, `base.css`, `defaults.css`, `layout.css`, `components.css`, `utilities.css` |
|
|
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
|
-
| 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-progress`, `sf-skeleton`, `sf-filter-bar`, `sf-data-table`, `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-menu`, `sf-breadcrumb`, `sf-pagination` |
|
|
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` |
|
|
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
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
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` |
|
package/docs/patterns.md
CHANGED
|
@@ -18,6 +18,13 @@ pnpm exec synced-flow pattern scroll-viewport-sections --json
|
|
|
18
18
|
| `scroll-viewport-with-spy` | Scroll snap panels with optional IntersectionObserver active-state notes. |
|
|
19
19
|
| `native-dialog-react` | Native `<dialog>` markup plus React/Next fallback shape. |
|
|
20
20
|
| `popover-drawer-layout` | Popover-backed drawer or filter panel with `sf-drawer--stack`. |
|
|
21
|
+
| `app-shell-layout` | Fixed header, sidebar, collapsed state, and mobile drawer app shell. |
|
|
22
|
+
| `row-action-menu` | Native popover row actions with destructive menu item styling. |
|
|
23
|
+
| `tabs-with-counts` | Pill tabs with compact count chips. |
|
|
24
|
+
| `data-table-actions` | Sortable header controls, clickable rows, and responsive card fallback. |
|
|
25
|
+
| `search-field` | Labelled native search input with icon shell and compact density. |
|
|
26
|
+
| `modal-form` | Native dialog layout for form body and footer actions. |
|
|
27
|
+
| `toast-stack` | Fixed app notification stack layout. |
|
|
21
28
|
| `filter-toolbar` | Search, filters, and actions above app lists and tables. |
|
|
22
29
|
| `date-filter-form` | Native date/time inputs inside filter forms. |
|
|
23
30
|
| `active-filter-tags` | Visible selected filter tags with remove and clear actions. |
|
|
@@ -14,6 +14,8 @@ Use the `--sf-*` variables as the stable CSS foundation.
|
|
|
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. |
|
|
17
|
+
| App colour | `--sf-colour-surface-hover`, `--sf-colour-surface-raised-2`, `--sf-colour-border-subtle`, `--sf-colour-backdrop` | App surfaces, hover states, subtle dividers, and overlays. |
|
|
18
|
+
| Categorical colour | `--sf-colour-categorical-1` ... `--sf-colour-categorical-6` | Charts, stages, labels, and recurring data accents. |
|
|
17
19
|
| State | `--sf-colour-success`, `--sf-colour-warning`, `--sf-colour-danger`, `--sf-colour-info` | Feedback and notices. |
|
|
18
20
|
| Motion | `--sf-duration-fast`, `--sf-duration-normal`, `--sf-ease-standard` | Consistent transitions. |
|
|
19
21
|
| Component | `--sf-button-*`, `--sf-card-*`, `--sf-input-*`, `--sf-alert-*` | Reusable component defaults. |
|
|
@@ -36,7 +38,7 @@ These classes are the first choice for page structure.
|
|
|
36
38
|
| `sf-cluster` | Wrapping inline groups such as actions or tags. |
|
|
37
39
|
| `sf-repel` | Space-between layout that wraps safely. |
|
|
38
40
|
| `sf-toolbar` | Dense app/page toolbar that wraps actions safely. |
|
|
39
|
-
| `sf-app-shell`, `sf-app-sidebar`, `sf-app-sidebar__brand`, `sf-app-main` | Product app shell with
|
|
41
|
+
| `sf-app-shell`, `sf-app-header`, `sf-app-sidebar`, `sf-app-sidebar__brand`, `sf-app-backdrop`, `sf-app-main` | Product app shell with optional fixed header, collapsed sidebar, mobile drawer, and main workspace. |
|
|
40
42
|
| `sf-split` | Responsive two-column layout. |
|
|
41
43
|
| `sf-split--reverse` | Reverses split layout visual order. |
|
|
42
44
|
| `sf-auto-grid`, `sf-panel-grid`, `sf-metric-grid`, `sf-pipeline` | Responsive card, metric, and operational grids. |
|
|
@@ -62,16 +64,16 @@ These cover the common UI elements needed for a simple site.
|
|
|
62
64
|
| `sf-nav`, `sf-nav__list`, `sf-nav__link` | Navigation basics. |
|
|
63
65
|
| `sf-nav--mobile`, `sf-menu`, `sf-breadcrumb`, `sf-pagination` | Mobile, menu, breadcrumb, and paginated navigation. |
|
|
64
66
|
| `sf-dialog`, `sf-dialog__header`, `sf-dialog__body`, `sf-dialog__footer` | Native `<dialog>` styling. |
|
|
65
|
-
| `sf-popover`, `sf-tooltip`, `sf-tooltip-trigger`, `sf-menu-popover`, `sf-toast`, `sf-banner`, `sf-drawer` | Popover-backed native overlays. |
|
|
67
|
+
| `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. |
|
|
66
68
|
| `sf-disclosure`, `sf-accordion` | Native `details`/`summary` disclosure patterns. |
|
|
67
|
-
| `sf-tabs`, `sf-tab-list`, `sf-tab`, `sf-tab-panel` | HTML/CSS-first tab styling. |
|
|
69
|
+
| `sf-tabs`, `sf-tab-list`, `sf-tab`, `sf-tab__count`, `sf-tab-panel` | HTML/CSS-first tab styling, including counted pill tabs. |
|
|
68
70
|
| `sf-form`, `sf-fieldset`, `sf-field`, `sf-label`, `sf-help`, `sf-error` | Form structure and messaging. |
|
|
69
|
-
| `sf-input`, `sf-select`, `sf-textarea`, `sf-check` | Form controls. |
|
|
71
|
+
| `sf-input`, `sf-select`, `sf-textarea`, `sf-search`, `sf-check` | Form controls, including search input shell. |
|
|
70
72
|
| `sf-alert`, `sf-alert--info`, `sf-alert--success`, `sf-alert--warning`, `sf-alert--danger`, `sf-alert__title` | Notices and feedback. |
|
|
71
73
|
| `sf-section-header`, `sf-kicker`, `sf-badge`, `sf-avatar` | Common marketing/content and account patterns. |
|
|
72
74
|
| `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. |
|
|
73
75
|
| `sf-progress`, `sf-skeleton` | Native progress bars and CSS-only loading placeholders for async app states. |
|
|
74
|
-
| `sf-filter-bar`, `sf-data-table`, `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. |
|
|
76
|
+
| `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. |
|
|
75
77
|
|
|
76
78
|
## Utility Classes
|
|
77
79
|
|
package/docs/tokens.md
CHANGED
|
@@ -75,6 +75,7 @@ The generated core includes enough semantic variables for common website UI:
|
|
|
75
75
|
|
|
76
76
|
- surfaces: `--sf-colour-background`, `--sf-colour-surface`,
|
|
77
77
|
`--sf-colour-surface-alt`, `--sf-colour-surface-raised`,
|
|
78
|
+
`--sf-colour-surface-raised-2`, `--sf-colour-surface-hover`,
|
|
78
79
|
`--sf-colour-surface-inset`
|
|
79
80
|
- text and links: `--sf-colour-foreground`, `--sf-colour-muted`,
|
|
80
81
|
`--sf-colour-subtle`, `--sf-colour-link`, `--sf-colour-link-hover`
|
|
@@ -82,8 +83,11 @@ The generated core includes enough semantic variables for common website UI:
|
|
|
82
83
|
`--sf-colour-primary-foreground`, `--sf-colour-primary-soft`
|
|
83
84
|
- state feedback: `--sf-colour-success`, `--sf-colour-warning`,
|
|
84
85
|
`--sf-colour-danger`, `--sf-colour-info`, plus matching soft variants
|
|
85
|
-
- structure: `--sf-colour-border`, `--sf-colour-border
|
|
86
|
+
- structure: `--sf-colour-border-subtle`, `--sf-colour-border`,
|
|
87
|
+
`--sf-colour-border-strong`, `--sf-colour-backdrop`,
|
|
86
88
|
`--sf-radius-control`, `--sf-radius-panel`, `--sf-shadow-*`
|
|
89
|
+
- data accents: `--sf-colour-categorical-1` through
|
|
90
|
+
`--sf-colour-categorical-6`
|
|
87
91
|
|
|
88
92
|
For class-level usage, see [System primitives](system-primitives.md).
|
|
89
93
|
|
package/layout.css
CHANGED
|
@@ -95,11 +95,47 @@
|
|
|
95
95
|
}
|
|
96
96
|
|
|
97
97
|
.sf-app-shell {
|
|
98
|
+
--sf-app-header-height: 4rem;
|
|
99
|
+
--sf-app-sidebar-collapsed-width: 4.75rem;
|
|
98
100
|
background: var(--sf-colour-background);
|
|
99
101
|
color: var(--sf-colour-foreground);
|
|
100
102
|
display: grid;
|
|
101
103
|
grid-template-columns: minmax(14rem, var(--sf-app-sidebar-width, 16rem)) minmax(0, 1fr);
|
|
102
104
|
min-block-size: 100dvh;
|
|
105
|
+
position: relative;
|
|
106
|
+
transition: grid-template-columns var(--sf-duration-normal) var(--sf-ease-standard);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
.sf-app-header {
|
|
110
|
+
align-items: center;
|
|
111
|
+
background: var(--sf-colour-surface);
|
|
112
|
+
border-block-end: 1px solid var(--sf-colour-border);
|
|
113
|
+
display: flex;
|
|
114
|
+
gap: var(--sf-space-s);
|
|
115
|
+
grid-column: 1 / -1;
|
|
116
|
+
justify-content: space-between;
|
|
117
|
+
min-block-size: var(--sf-app-header-height);
|
|
118
|
+
padding-inline: var(--sf-space-s-m);
|
|
119
|
+
z-index: 20;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
.sf-app-shell[data-layout~="fixed-header"] {
|
|
123
|
+
grid-template-rows: var(--sf-app-header-height) minmax(0, 1fr);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
.sf-app-shell[data-layout~="fixed-header"] .sf-app-header {
|
|
127
|
+
inset-block-start: 0;
|
|
128
|
+
position: sticky;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
.sf-app-shell[data-layout~="fixed-header"] .sf-app-sidebar {
|
|
132
|
+
inset-block-start: var(--sf-app-header-height);
|
|
133
|
+
max-block-size: calc(100dvh - var(--sf-app-header-height));
|
|
134
|
+
min-block-size: calc(100dvh - var(--sf-app-header-height));
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
.sf-app-shell[data-collapsed="true"] {
|
|
138
|
+
grid-template-columns: var(--sf-app-sidebar-collapsed-width) minmax(0, 1fr);
|
|
103
139
|
}
|
|
104
140
|
|
|
105
141
|
.sf-app-sidebar {
|
|
@@ -115,6 +151,7 @@
|
|
|
115
151
|
padding: var(--sf-space-s);
|
|
116
152
|
position: sticky;
|
|
117
153
|
inset-block-start: 0;
|
|
154
|
+
transition: transform var(--sf-duration-normal) var(--sf-ease-standard), inline-size var(--sf-duration-normal) var(--sf-ease-standard);
|
|
118
155
|
}
|
|
119
156
|
|
|
120
157
|
.sf-app-sidebar__brand {
|
|
@@ -134,6 +171,58 @@
|
|
|
134
171
|
padding: var(--sf-app-main-padding, var(--sf-space-m-l));
|
|
135
172
|
}
|
|
136
173
|
|
|
174
|
+
.sf-app-shell[data-collapsed="true"] .sf-app-sidebar {
|
|
175
|
+
overflow-x: hidden;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
.sf-app-shell[data-collapsed="true"] .sf-app-sidebar__brand,
|
|
179
|
+
.sf-app-shell[data-collapsed="true"] .sf-app-sidebar .sf-nav__link {
|
|
180
|
+
justify-content: center;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
.sf-app-shell[data-collapsed="true"] [data-hide-collapsed="true"] {
|
|
184
|
+
display: none;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
.sf-app-backdrop {
|
|
188
|
+
display: none;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
@media (max-width: 48rem) {
|
|
192
|
+
.sf-app-shell[data-mobile="drawer"] {
|
|
193
|
+
display: block;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
.sf-app-shell[data-mobile="drawer"] .sf-app-header {
|
|
197
|
+
position: sticky;
|
|
198
|
+
inset-block-start: 0;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
.sf-app-shell[data-mobile="drawer"] .sf-app-sidebar {
|
|
202
|
+
box-shadow: var(--sf-shadow-xl);
|
|
203
|
+
inline-size: min(18rem, calc(100vw - var(--sf-space-l)));
|
|
204
|
+
inset-block: 0;
|
|
205
|
+
inset-inline-start: 0;
|
|
206
|
+
max-block-size: none;
|
|
207
|
+
min-block-size: 100dvh;
|
|
208
|
+
position: fixed;
|
|
209
|
+
transform: translateX(-100%);
|
|
210
|
+
z-index: 30;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
.sf-app-shell[data-mobile="drawer"][data-sidebar-open="true"] .sf-app-sidebar {
|
|
214
|
+
transform: translateX(0);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
.sf-app-shell[data-mobile="drawer"][data-sidebar-open="true"] .sf-app-backdrop {
|
|
218
|
+
background: var(--sf-colour-backdrop);
|
|
219
|
+
display: block;
|
|
220
|
+
inset: 0;
|
|
221
|
+
position: fixed;
|
|
222
|
+
z-index: 25;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
137
226
|
.sf-grid {
|
|
138
227
|
display: grid;
|
|
139
228
|
gap: var(--sf-grid-gap, var(--sf-gutter));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
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.
|
|
3
|
+
description: Use Synced Flow to set up and build modern fluid CSS systems with the CLI, tokens, presets, app UI primitives, WordPress support, and source-scanned utility CSS.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Synced Flow
|
|
@@ -87,12 +87,25 @@ intact. Leave out `utilities.css` unless static helpers such as `sf-text-*`,
|
|
|
87
87
|
|
|
88
88
|
- Prefer primitives first: `sf-container`, `sf-section`, `sf-stack`,
|
|
89
89
|
`sf-cluster`, `sf-repel`, `sf-auto-grid`, `sf-split`, `sf-sidebar`,
|
|
90
|
-
`sf-
|
|
90
|
+
`sf-app-shell`, `sf-app-header`, `sf-app-sidebar`, `sf-app-main`,
|
|
91
|
+
`sf-app-backdrop`, `sf-frame`, and `sf-flow`.
|
|
91
92
|
- Prefer component primitives for common UI: `sf-button`, `sf-card`,
|
|
92
|
-
`sf-badge`, `sf-field`,
|
|
93
|
-
-
|
|
94
|
-
|
|
95
|
-
|
|
93
|
+
`sf-badge`, `sf-status`, `sf-field`, `sf-input`, `sf-search`,
|
|
94
|
+
`sf-data-table`, `sf-table-sort`, `sf-tab__count`, and `sf-toast-stack`.
|
|
95
|
+
- Use `saas-landing` for public SaaS marketing pages. Use `saas-dashboard` when
|
|
96
|
+
a full authenticated starter is useful, but prefer neutral app patterns for
|
|
97
|
+
reusable UI in admin panels, portals, CRMs, analytics dashboards, internal
|
|
98
|
+
tools, account areas, and product workspaces.
|
|
99
|
+
- Use app patterns before writing project CSS:
|
|
100
|
+
`app-shell-layout`, `row-action-menu`, `tabs-with-counts`,
|
|
101
|
+
`data-table-actions`, `search-field`, `modal-form`, and `toast-stack`.
|
|
102
|
+
- Use app shell states instead of bespoke layout CSS: `data-layout="fixed-header"`
|
|
103
|
+
for fixed app headers, `data-collapsed="true"` for collapsed sidebars, and
|
|
104
|
+
`data-mobile="drawer"` with `data-sidebar-open="true"` for mobile drawer
|
|
105
|
+
navigation.
|
|
106
|
+
- Keep product-specific structures out of Synced Flow. Kanban boards, invoices,
|
|
107
|
+
proposal builders, scheduling workflows, and complex editable grids should stay
|
|
108
|
+
in the consuming app unless they become broadly reusable primitives.
|
|
96
109
|
- Do not implement authentication logic in Synced Flow markup. Wire sessions,
|
|
97
110
|
providers, permissions, and sign-out actions in the consuming app.
|
|
98
111
|
- Prefer native component patterns for common interaction: `sf-dialog`,
|
|
@@ -112,6 +125,10 @@ intact. Leave out `utilities.css` unless static helpers such as `sf-text-*`,
|
|
|
112
125
|
accessibility and explicit UI styling.
|
|
113
126
|
- Put brand choices in `theme` config or theme presets rather than scattered
|
|
114
127
|
one-off CSS.
|
|
128
|
+
- Use semantic app tokens before local overrides: `surfaceRaised2`,
|
|
129
|
+
`surfaceHover`, `borderSubtle`, `backdrop`, and `categorical1` through
|
|
130
|
+
`categorical6`. Devs may still supply valid CSS colour formats such as hex,
|
|
131
|
+
RGB, HSL, or OKLCH in their own theme config.
|
|
115
132
|
- Use modern CSS techniques already in the system: cascade layers, custom
|
|
116
133
|
properties, logical properties, `clamp()`, OKLCH colour, container-aware
|
|
117
134
|
layout, and `prefers-reduced-motion`.
|
package/src/tokens.mjs
CHANGED
|
@@ -75,9 +75,13 @@ export const semanticTokens = {
|
|
|
75
75
|
surface: 'var(--sf-colour-neutral-0)',
|
|
76
76
|
surfaceAlt: 'var(--sf-colour-neutral-100)',
|
|
77
77
|
surfaceRaised: 'var(--sf-colour-neutral-0)',
|
|
78
|
+
surfaceRaised2: 'var(--sf-colour-neutral-50)',
|
|
79
|
+
surfaceHover: 'var(--sf-colour-neutral-100)',
|
|
78
80
|
surfaceInset: 'var(--sf-colour-neutral-100)',
|
|
81
|
+
borderSubtle: 'oklch(18% 0.026 250 / 0.08)',
|
|
79
82
|
border: 'oklch(18% 0.026 250 / 0.12)',
|
|
80
83
|
borderStrong: 'oklch(18% 0.026 250 / 0.22)',
|
|
84
|
+
backdrop: 'oklch(0% 0 0 / 0.48)',
|
|
81
85
|
primary: 'var(--sf-colour-orange-600)',
|
|
82
86
|
primaryHover: 'var(--sf-colour-orange-700)',
|
|
83
87
|
primaryForeground: 'var(--sf-colour-neutral-0)',
|
|
@@ -99,6 +103,12 @@ export const semanticTokens = {
|
|
|
99
103
|
info: 'var(--sf-colour-cyan-600)',
|
|
100
104
|
infoForeground: 'var(--sf-colour-neutral-0)',
|
|
101
105
|
infoSoft: 'oklch(70% 0.12 205 / 0.14)',
|
|
106
|
+
categorical1: 'var(--sf-colour-cyan-600)',
|
|
107
|
+
categorical2: 'var(--sf-colour-green-600)',
|
|
108
|
+
categorical3: 'var(--sf-colour-amber-500)',
|
|
109
|
+
categorical4: 'var(--sf-colour-orange-600)',
|
|
110
|
+
categorical5: 'var(--sf-colour-red-600)',
|
|
111
|
+
categorical6: 'oklch(58% 0.15 292)',
|
|
102
112
|
ring: 'var(--sf-colour-orange-600)',
|
|
103
113
|
},
|
|
104
114
|
}
|