@dillingerstaffing/strand-ui 0.10.0 → 0.12.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/HTML_REFERENCE.md CHANGED
@@ -407,7 +407,7 @@ All container components (Grid, Stack, Card, Container) enforce boundary integri
407
407
  </div>
408
408
  ```
409
409
 
410
- **Sizes:** `--sm` (text-xl, 25px) | default (text-3xl, 39px) | `--lg` (text-4xl, 49px). Label stays xs across all sizes.
410
+ **Sizes:** `--sm` (text-xl, 25px) | default (text-3xl, 39px) | `--lg` (text-4xl, 49px) | `--xl` (fluid 72-112px, primary instrument readout). Label stays xs across all sizes.
411
411
 
412
412
  > **The DataReadout pattern** is uniquely Strand: monospace overline + large light-weight value + tabular numerals. See [DESIGN_LANGUAGE.md 11.2: Data Display (L918-L955)](./DESIGN_LANGUAGE.md#L918).
413
413
 
@@ -900,15 +900,19 @@ Named CSS classes for common compositions. Each implements one or more productio
900
900
  Production: `section-boundary`.
901
901
 
902
902
  ```html
903
- <div class="strand-card strand-card--elevated strand-card--pad-md">
904
- <div class="strand-card-section">
905
- <span class="strand-overline">Section Label</span>
906
- </div>
907
- <!-- section content -->
903
+ <!-- Single label -->
904
+ <div class="strand-card-section">
905
+ <span class="strand-overline">Section Label</span>
906
+ </div>
907
+
908
+ <!-- Distributed header (label + secondary) -->
909
+ <div class="strand-card-section">
910
+ <span class="strand-overline">7-Day Forecast</span>
911
+ <span class="strand-overline" style="color: var(--strand-gray-400)">Ethiopian Yirgacheffe</span>
908
912
  </div>
909
913
  ```
910
914
 
911
- Multiple sections stack. Last section omits trailing border via `:last-child`.
915
+ Children distribute on the inline axis (space-between). Single child sits at the start. Multiple sections stack; last omits trailing border via `:last-child`.
912
916
 
913
917
  ### Key-Value Row
914
918
 
@@ -5,8 +5,8 @@ export interface DataReadoutProps extends Omit<JSX.HTMLAttributes<HTMLDivElement
5
5
  label: string;
6
6
  /** The large displayed value */
7
7
  value: string | number;
8
- /** Size variant: sm (compact), md (default), lg (hero) */
9
- size?: "sm" | "md" | "lg";
8
+ /** Size variant: sm (compact), md (default), lg (hero), xl (primary instrument) */
9
+ size?: "sm" | "md" | "lg" | "xl";
10
10
  }
11
11
  export declare const DataReadout: import("preact").FunctionalComponent<import("preact/compat").PropsWithoutRef<DataReadoutProps> & {
12
12
  ref?: import("preact").Ref<HTMLDivElement> | undefined;
@@ -1 +1 @@
1
- {"version":3,"file":"DataReadout.d.ts","sourceRoot":"","sources":["../../../src/components/DataReadout/DataReadout.tsx"],"names":[],"mappings":"AAAA,sDAAsD;AAEtD,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,QAAQ,CAAC;AAGlC,MAAM,WAAW,gBACf,SAAQ,IAAI,CAAC,GAAG,CAAC,cAAc,CAAC,cAAc,CAAC,EAAE,OAAO,CAAC;IACzD,0BAA0B;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,gCAAgC;IAChC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC;IACvB,0DAA0D;IAC1D,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;CAC3B;AAED,eAAO,MAAM,WAAW;;EAiBvB,CAAC"}
1
+ {"version":3,"file":"DataReadout.d.ts","sourceRoot":"","sources":["../../../src/components/DataReadout/DataReadout.tsx"],"names":[],"mappings":"AAAA,sDAAsD;AAEtD,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,QAAQ,CAAC;AAGlC,MAAM,WAAW,gBACf,SAAQ,IAAI,CAAC,GAAG,CAAC,cAAc,CAAC,cAAc,CAAC,EAAE,OAAO,CAAC;IACzD,0BAA0B;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,gCAAgC;IAChC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC;IACvB,mFAAmF;IACnF,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;CAClC;AAED,eAAO,MAAM,WAAW;;EAiBvB,CAAC"}
@@ -763,6 +763,10 @@
763
763
  font-size: var(--strand-text-4xl);
764
764
  }
765
765
 
766
+ .strand-data-readout--xl .strand-data-readout__value {
767
+ font-size: clamp(4.5rem, 10vw, 7rem);
768
+ }
769
+
766
770
 
767
771
  /* Dialog */
768
772
  /*! Strand UI | MIT License | dillingerstaffing.com */
@@ -1136,6 +1140,32 @@
1136
1140
  outline-offset: 2px;
1137
1141
  }
1138
1142
 
1143
+ /* ── CTA link variant ── */
1144
+ .strand-link--cta {
1145
+ display: inline-flex;
1146
+ align-items: center;
1147
+ min-height: var(--strand-touch-target);
1148
+ padding-block: var(--strand-space-2);
1149
+ font-size: var(--strand-text-sm);
1150
+ }
1151
+
1152
+ .strand-link--cta:hover {
1153
+ color: var(--strand-blue-vivid);
1154
+ }
1155
+
1156
+ /* ── Monospace link variant (footer, overline-style) ── */
1157
+ .strand-link--mono {
1158
+ font-family: var(--strand-font-mono);
1159
+ font-size: var(--strand-text-xs);
1160
+ letter-spacing: var(--strand-tracking-wider);
1161
+ color: var(--strand-gray-400);
1162
+ background-image: none;
1163
+ }
1164
+
1165
+ .strand-link--mono:hover {
1166
+ color: var(--strand-blue-primary);
1167
+ }
1168
+
1139
1169
  /* ── Reduced motion ── */
1140
1170
  @media (prefers-reduced-motion: reduce) {
1141
1171
  .strand-link {
@@ -1547,11 +1577,35 @@
1547
1577
  .strand-reveal-group > .strand-reveal:nth-child(5) { transition-delay: calc(var(--strand-stagger-delay) * 4); }
1548
1578
  .strand-reveal-group > .strand-reveal:nth-child(6) { transition-delay: var(--strand-duration-slow); }
1549
1579
 
1580
+ /* ── CSS-only scroll-driven animation (no JS required) ── */
1581
+ @supports (animation-timeline: view()) {
1582
+ .strand-reveal {
1583
+ opacity: 0;
1584
+ transform: translateY(24px);
1585
+ transition: none;
1586
+ animation: strand-reveal-up linear both;
1587
+ animation-timeline: view();
1588
+ animation-range: entry 0% entry 100%;
1589
+ }
1590
+
1591
+ .strand-reveal-group > .strand-reveal {
1592
+ animation: strand-reveal-up linear both;
1593
+ animation-timeline: view();
1594
+ animation-range: entry 0% entry 100%;
1595
+ }
1596
+
1597
+ @keyframes strand-reveal-up {
1598
+ from { opacity: 0; transform: translateY(24px); }
1599
+ to { opacity: 1; transform: translateY(0); }
1600
+ }
1601
+ }
1602
+
1550
1603
  @media (prefers-reduced-motion: reduce) {
1551
1604
  .strand-reveal {
1552
1605
  opacity: 1;
1553
1606
  transform: none;
1554
1607
  transition: none;
1608
+ animation: none;
1555
1609
  }
1556
1610
  }
1557
1611
 
@@ -1586,6 +1640,11 @@
1586
1640
  background-color: var(--strand-surface-recessed);
1587
1641
  }
1588
1642
 
1643
+ /* ── Border variant ── */
1644
+ .strand-section--border-top {
1645
+ border-top: 1px solid var(--strand-gray-200);
1646
+ }
1647
+
1589
1648
 
1590
1649
  /* Select */
1591
1650
  /*! Strand UI | MIT License | dillingerstaffing.com */
@@ -2687,6 +2746,9 @@
2687
2746
  Derivation: section-boundary production (DL 11.10).
2688
2747
  OVERLINE + border-bottom + margin-bottom + padding-bottom */
2689
2748
  .strand-card-section {
2749
+ display: flex;
2750
+ justify-content: space-between;
2751
+ align-items: center;
2690
2752
  margin-bottom: var(--strand-space-3);
2691
2753
  padding-bottom: var(--strand-space-2);
2692
2754
  border-bottom: 1px solid var(--strand-gray-200);
@@ -2822,4 +2884,44 @@
2822
2884
  color: var(--strand-gray-400);
2823
2885
  }
2824
2886
 
2887
+ /* ══════════════════════════════════════════════════
2888
+ UTILITIES
2889
+ ══════════════════════════════════════════════════ */
2890
+
2891
+ /* ── Screen reader only ── */
2892
+ .strand-sr-only {
2893
+ position: absolute;
2894
+ width: 1px;
2895
+ height: 1px;
2896
+ padding: 0;
2897
+ margin: -1px;
2898
+ overflow: hidden;
2899
+ clip: rect(0, 0, 0, 0);
2900
+ white-space: nowrap;
2901
+ border: 0;
2902
+ }
2903
+
2904
+ /* ── Section header ──
2905
+ Derivation: section-boundary production (DL 11.10).
2906
+ Centered heading group with bottom margin. */
2907
+ .strand-section-header {
2908
+ margin-bottom: clamp(2rem, 4vw, 4rem);
2909
+ }
2910
+
2911
+ /* ── Step indicator ──
2912
+ Numbered position indicator for sequential steps. */
2913
+ .strand-step-indicator {
2914
+ display: inline-flex;
2915
+ align-items: center;
2916
+ justify-content: center;
2917
+ width: var(--strand-space-8);
2918
+ height: var(--strand-space-8);
2919
+ border-radius: var(--strand-radius-full);
2920
+ background: var(--strand-blue-glow);
2921
+ color: var(--strand-blue-primary);
2922
+ font-family: var(--strand-font-mono);
2923
+ font-size: var(--strand-text-sm);
2924
+ font-weight: var(--strand-weight-semibold);
2925
+ }
2926
+
2825
2927
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dillingerstaffing/strand-ui",
3
- "version": "0.10.0",
3
+ "version": "0.12.0",
4
4
  "description": "Strand UI - Preact/React component library built on the Strand Design Language",
5
5
  "author": "Dillinger Staffing <engineering@dillingerstaffing.com> (https://dillingerstaffing.com)",
6
6
  "license": "MIT",
@@ -60,7 +60,7 @@
60
60
  }
61
61
  },
62
62
  "dependencies": {
63
- "@dillingerstaffing/strand": "^0.10.0"
63
+ "@dillingerstaffing/strand": "^0.12.0"
64
64
  },
65
65
  "devDependencies": {
66
66
  "@testing-library/preact": "^3.2.0",
@@ -37,3 +37,7 @@
37
37
  .strand-data-readout--lg .strand-data-readout__value {
38
38
  font-size: var(--strand-text-4xl);
39
39
  }
40
+
41
+ .strand-data-readout--xl .strand-data-readout__value {
42
+ font-size: clamp(4.5rem, 10vw, 7rem);
43
+ }
@@ -111,6 +111,14 @@ describe("DataReadout", () => {
111
111
  expect(readout?.className).toContain("strand-data-readout--lg");
112
112
  });
113
113
 
114
+ it("applies xl size modifier class", () => {
115
+ const { container } = render(
116
+ <DataReadout label="Remaining" value="284g" size="xl" />,
117
+ );
118
+ const readout = container.querySelector(".strand-data-readout");
119
+ expect(readout?.className).toContain("strand-data-readout--xl");
120
+ });
121
+
114
122
  it("does not apply size modifier for md (default)", () => {
115
123
  const { container } = render(
116
124
  <DataReadout label="Metric" value="100" size="md" />,
@@ -9,8 +9,8 @@ export interface DataReadoutProps
9
9
  label: string;
10
10
  /** The large displayed value */
11
11
  value: string | number;
12
- /** Size variant: sm (compact), md (default), lg (hero) */
13
- size?: "sm" | "md" | "lg";
12
+ /** Size variant: sm (compact), md (default), lg (hero), xl (primary instrument) */
13
+ size?: "sm" | "md" | "lg" | "xl";
14
14
  }
15
15
 
16
16
  export const DataReadout = forwardRef<HTMLDivElement, DataReadoutProps>(
@@ -22,6 +22,32 @@
22
22
  outline-offset: 2px;
23
23
  }
24
24
 
25
+ /* ── CTA link variant ── */
26
+ .strand-link--cta {
27
+ display: inline-flex;
28
+ align-items: center;
29
+ min-height: var(--strand-touch-target);
30
+ padding-block: var(--strand-space-2);
31
+ font-size: var(--strand-text-sm);
32
+ }
33
+
34
+ .strand-link--cta:hover {
35
+ color: var(--strand-blue-vivid);
36
+ }
37
+
38
+ /* ── Monospace link variant (footer, overline-style) ── */
39
+ .strand-link--mono {
40
+ font-family: var(--strand-font-mono);
41
+ font-size: var(--strand-text-xs);
42
+ letter-spacing: var(--strand-tracking-wider);
43
+ color: var(--strand-gray-400);
44
+ background-image: none;
45
+ }
46
+
47
+ .strand-link--mono:hover {
48
+ color: var(--strand-blue-primary);
49
+ }
50
+
25
51
  /* ── Reduced motion ── */
26
52
  @media (prefers-reduced-motion: reduce) {
27
53
  .strand-link {
@@ -20,10 +20,34 @@
20
20
  .strand-reveal-group > .strand-reveal:nth-child(5) { transition-delay: calc(var(--strand-stagger-delay) * 4); }
21
21
  .strand-reveal-group > .strand-reveal:nth-child(6) { transition-delay: var(--strand-duration-slow); }
22
22
 
23
+ /* ── CSS-only scroll-driven animation (no JS required) ── */
24
+ @supports (animation-timeline: view()) {
25
+ .strand-reveal {
26
+ opacity: 0;
27
+ transform: translateY(24px);
28
+ transition: none;
29
+ animation: strand-reveal-up linear both;
30
+ animation-timeline: view();
31
+ animation-range: entry 0% entry 100%;
32
+ }
33
+
34
+ .strand-reveal-group > .strand-reveal {
35
+ animation: strand-reveal-up linear both;
36
+ animation-timeline: view();
37
+ animation-range: entry 0% entry 100%;
38
+ }
39
+
40
+ @keyframes strand-reveal-up {
41
+ from { opacity: 0; transform: translateY(24px); }
42
+ to { opacity: 1; transform: translateY(0); }
43
+ }
44
+ }
45
+
23
46
  @media (prefers-reduced-motion: reduce) {
24
47
  .strand-reveal {
25
48
  opacity: 1;
26
49
  transform: none;
27
50
  transition: none;
51
+ animation: none;
28
52
  }
29
53
  }
@@ -26,3 +26,8 @@
26
26
  .strand-section--bg-recessed {
27
27
  background-color: var(--strand-surface-recessed);
28
28
  }
29
+
30
+ /* ── Border variant ── */
31
+ .strand-section--border-top {
32
+ border-top: 1px solid var(--strand-gray-200);
33
+ }
package/src/static.css CHANGED
@@ -118,6 +118,9 @@
118
118
  Derivation: section-boundary production (DL 11.10).
119
119
  OVERLINE + border-bottom + margin-bottom + padding-bottom */
120
120
  .strand-card-section {
121
+ display: flex;
122
+ justify-content: space-between;
123
+ align-items: center;
121
124
  margin-bottom: var(--strand-space-3);
122
125
  padding-bottom: var(--strand-space-2);
123
126
  border-bottom: 1px solid var(--strand-gray-200);
@@ -252,3 +255,43 @@
252
255
  text-transform: uppercase;
253
256
  color: var(--strand-gray-400);
254
257
  }
258
+
259
+ /* ══════════════════════════════════════════════════
260
+ UTILITIES
261
+ ══════════════════════════════════════════════════ */
262
+
263
+ /* ── Screen reader only ── */
264
+ .strand-sr-only {
265
+ position: absolute;
266
+ width: 1px;
267
+ height: 1px;
268
+ padding: 0;
269
+ margin: -1px;
270
+ overflow: hidden;
271
+ clip: rect(0, 0, 0, 0);
272
+ white-space: nowrap;
273
+ border: 0;
274
+ }
275
+
276
+ /* ── Section header ──
277
+ Derivation: section-boundary production (DL 11.10).
278
+ Centered heading group with bottom margin. */
279
+ .strand-section-header {
280
+ margin-bottom: clamp(2rem, 4vw, 4rem);
281
+ }
282
+
283
+ /* ── Step indicator ──
284
+ Numbered position indicator for sequential steps. */
285
+ .strand-step-indicator {
286
+ display: inline-flex;
287
+ align-items: center;
288
+ justify-content: center;
289
+ width: var(--strand-space-8);
290
+ height: var(--strand-space-8);
291
+ border-radius: var(--strand-radius-full);
292
+ background: var(--strand-blue-glow);
293
+ color: var(--strand-blue-primary);
294
+ font-family: var(--strand-font-mono);
295
+ font-size: var(--strand-text-sm);
296
+ font-weight: var(--strand-weight-semibold);
297
+ }