@hraness/design-kit 0.33.0 → 0.35.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 (44) hide show
  1. package/README.md +19 -3
  2. package/dist/{chunk-mr1vdcjq.js → chunk-8xfssb9c.js} +6 -3
  3. package/dist/{chunk-95mpmzc9.js → chunk-c9mhn3yb.js} +1130 -442
  4. package/dist/{chunk-h4k7yv6x.js → chunk-fjf81bww.js} +28 -2
  5. package/dist/chunk-gmea6p0d.js +13 -0
  6. package/dist/index.js +5 -1
  7. package/dist/mockups/client.js +50 -15
  8. package/dist/portfolio.js +586 -85
  9. package/dist/react/index.js +141 -13
  10. package/dist/react/platform-install.js +3 -2
  11. package/dist/react/server.js +17 -3
  12. package/dist/stylex-manifest.json +1 -1
  13. package/dist/stylex.css +350 -36
  14. package/package.json +14 -3
  15. package/portfolio-inventory.json +1 -1
  16. package/src/diagrams.ts +11 -0
  17. package/src/index.ts +2 -0
  18. package/src/marketing-comparison.css +162 -0
  19. package/src/marketing-diagram.css +24 -0
  20. package/src/mockups/client.tsx +25 -17
  21. package/src/mockups.css +19 -0
  22. package/src/plain-publication.css +9 -6
  23. package/src/portfolio.generated.json +578 -86
  24. package/src/portfolio.generated.ts +578 -86
  25. package/src/portfolio.ts +73 -0
  26. package/src/product-marketing-foundation.css +29 -0
  27. package/src/product-marketing.css +136 -39
  28. package/src/react/article.tsx +2 -2
  29. package/src/react/design-gallery.tsx +37 -8
  30. package/src/react/index.ts +3 -0
  31. package/src/react/marketing-account.stylex.ts +74 -0
  32. package/src/react/marketing-account.tsx +69 -0
  33. package/src/react/marketing-comparison.stylex.ts +24 -0
  34. package/src/react/marketing-comparison.tsx +73 -0
  35. package/src/react/marketing-diagram.stylex.ts +8 -0
  36. package/src/react/marketing-diagram.tsx +33 -0
  37. package/src/react/platform-install.stylex.ts +2 -1
  38. package/src/react/platform-install.tsx +2 -1
  39. package/src/react/product-marketing.stylex.ts +144 -111
  40. package/src/react/product-marketing.tsx +83 -45
  41. package/src/react/server.ts +3 -0
  42. package/src/styles.css +2 -0
  43. package/src/typography.css +32 -0
  44. /package/dist/{chunk-4d79eskk.js → chunk-c80g58j1.js} +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hraness/design-kit",
3
- "version": "0.33.0",
3
+ "version": "0.35.0",
4
4
  "description": "React components and CSS for Hraness apps and product sites: application shells, marketing sections, charts, themes, effects, and syntax highlighting. Built on @hraness/ui.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -126,7 +126,9 @@
126
126
  "./testing": {
127
127
  "types": "./src/testing.ts",
128
128
  "import": "./dist/testing.js"
129
- }
129
+ },
130
+ "./marketing-comparison.css": "./src/marketing-comparison.css",
131
+ "./marketing-diagram.css": "./src/marketing-diagram.css"
130
132
  },
131
133
  "main": "./dist/index.js",
132
134
  "types": "./src/index.ts",
@@ -209,6 +211,8 @@
209
211
  "src/react/production-data-preview-notice.stylex.ts",
210
212
  "src/react/product-marketing.stylex.ts",
211
213
  "src/react/product-marketing.tsx",
214
+ "src/react/marketing-account.tsx",
215
+ "src/react/marketing-account.stylex.ts",
212
216
  "src/react/route-state.stylex.ts",
213
217
  "src/react/route-state.tsx",
214
218
  "src/react/server.ts",
@@ -296,7 +300,14 @@
296
300
  "src/agent-setup.ts",
297
301
  "src/react/agent-setup-prompt.tsx",
298
302
  "src/react/agent-setup-prompt.stylex.ts",
299
- "AGENT_SETUP.md"
303
+ "AGENT_SETUP.md",
304
+ "src/react/marketing-comparison.tsx",
305
+ "src/react/marketing-comparison.stylex.ts",
306
+ "src/marketing-comparison.css",
307
+ "src/diagrams.ts",
308
+ "src/react/marketing-diagram.tsx",
309
+ "src/react/marketing-diagram.stylex.ts",
310
+ "src/marketing-diagram.css"
300
311
  ],
301
312
  "scripts": {
302
313
  "build": "bun run ./scripts/build.ts",
@@ -6,7 +6,7 @@
6
6
  "name": "@hraness/design-kit",
7
7
  "path": ".",
8
8
  "visibility": "public",
9
- "version": "0.33.0"
9
+ "version": "0.35.0"
10
10
  }
11
11
  ],
12
12
  "contract": "hraness.portfolio-inventory/v1",
@@ -0,0 +1,11 @@
1
+ /** Shared source-space measurements for diagrams; generators retain layout ownership. */
2
+ export const diagramMetrics = Object.freeze({
3
+ labelSize: 20,
4
+ detailSize: 16,
5
+ strokeWidth: 1.5,
6
+ arrowheadSize: 6,
7
+ nodePadding: 24,
8
+ nodeGap: 48,
9
+ minimumCanvasWidth: 640,
10
+ fontFamily: '"Nebula Sans", ui-sans-serif, system-ui, sans-serif',
11
+ });
package/src/index.ts CHANGED
@@ -274,3 +274,5 @@ export type ThemeColors = {
274
274
  export function themeFor(mode: ColorMode): ThemeColors {
275
275
  return colors[mode];
276
276
  }
277
+
278
+ export * from "./diagrams.js";
@@ -0,0 +1,162 @@
1
+ /* Raw HTML counterpart to the shared MarketingComparison composition. */
2
+ @layer components.hraness-design-kit.legacy {
3
+ .hraness-marketing-comparison {
4
+ margin: 0;
5
+ min-inline-size: 0;
6
+ color: var(--hraness-marketing-ink, var(--foreground));
7
+ font-family: var(--font-text);
8
+ }
9
+
10
+ .hraness-marketing-comparison__scroll {
11
+ overflow-x: auto;
12
+ max-inline-size: 100%;
13
+ }
14
+
15
+ .hraness-marketing-comparison__scroll:focus-visible {
16
+ outline: 2px solid var(--primary);
17
+ outline-offset: 3px;
18
+ }
19
+
20
+ .hraness-marketing-comparison__table {
21
+ inline-size: 100%;
22
+ border-collapse: collapse;
23
+ text-align: start;
24
+ font-size: 0.9375rem;
25
+ line-height: 1.4;
26
+ }
27
+
28
+ .hraness-marketing-comparison__caption {
29
+ padding-block-end: 1.25rem;
30
+ text-align: start;
31
+ font-size: 1.125rem;
32
+ font-weight: 550;
33
+ color: var(--foreground);
34
+ }
35
+
36
+ .hraness-marketing-comparison__corner {
37
+ min-inline-size: 9rem;
38
+ border-block-end: 1px solid var(--line);
39
+ }
40
+
41
+ .hraness-marketing-comparison__option {
42
+ padding: 1rem;
43
+ min-inline-size: 8.5rem;
44
+ border-block-end: 1px solid var(--line);
45
+ vertical-align: bottom;
46
+ font-weight: 600;
47
+ }
48
+
49
+ .hraness-marketing-comparison__option-label {
50
+ display: flex;
51
+ align-items: center;
52
+ gap: 0.6rem;
53
+ }
54
+
55
+ .hraness-marketing-comparison__mark {
56
+ object-fit: contain;
57
+ flex-shrink: 0;
58
+ inline-size: 1.5rem;
59
+ block-size: 1.5rem;
60
+ }
61
+
62
+ .hraness-marketing-comparison__row-label {
63
+ padding: 1rem 1rem 1rem 0;
64
+ min-inline-size: 9rem;
65
+ max-inline-size: 15rem;
66
+ border-block-end: 1px solid var(--line);
67
+ vertical-align: top;
68
+ font-weight: 500;
69
+ }
70
+
71
+ .hraness-marketing-comparison__cell {
72
+ padding: 1rem;
73
+ border-block-end: 1px solid var(--line);
74
+ vertical-align: top;
75
+ }
76
+
77
+ .hraness-marketing-comparison [data-highlight] {
78
+ background-color: color-mix(in srgb, var(--primary) 5%, transparent);
79
+ color: var(--foreground);
80
+ }
81
+
82
+ @media (forced-colors: active) {
83
+ .hraness-marketing-comparison [data-highlight] {
84
+ background-color: Canvas;
85
+ }
86
+ }
87
+
88
+ .hraness-marketing-comparison__value {
89
+ display: grid;
90
+ gap: 0.25rem;
91
+ }
92
+
93
+ .hraness-marketing-comparison__label {
94
+ display: flex;
95
+ align-items: flex-start;
96
+ gap: 0.45rem;
97
+ }
98
+
99
+ .hraness-marketing-comparison__glyph {
100
+ flex-shrink: 0;
101
+ margin-block-start: 0.1rem;
102
+ inline-size: 1.125rem;
103
+ block-size: 1.125rem;
104
+ }
105
+
106
+ .hraness-marketing-comparison [data-comparison-status="yes"] .hraness-marketing-comparison__glyph {
107
+ color: var(--hraness-studio-emerald);
108
+ }
109
+
110
+ @media (forced-colors: active) {
111
+ .hraness-marketing-comparison [data-comparison-status="yes"] .hraness-marketing-comparison__glyph {
112
+ color: CanvasText;
113
+ }
114
+ }
115
+
116
+ .hraness-marketing-comparison [data-comparison-status="no"] .hraness-marketing-comparison__glyph {
117
+ color: var(--muted);
118
+ }
119
+
120
+ @media (forced-colors: active) {
121
+ .hraness-marketing-comparison [data-comparison-status="no"] .hraness-marketing-comparison__glyph {
122
+ color: CanvasText;
123
+ }
124
+ }
125
+
126
+ .hraness-marketing-comparison [data-comparison-status="partial"] .hraness-marketing-comparison__glyph,
127
+ .hraness-marketing-comparison [data-comparison-status="depends"] .hraness-marketing-comparison__glyph,
128
+ .hraness-marketing-comparison [data-comparison-status="optional"] .hraness-marketing-comparison__glyph {
129
+ color: var(--hraness-studio-amber);
130
+ }
131
+
132
+ @media (forced-colors: active) {
133
+ .hraness-marketing-comparison [data-comparison-status="partial"] .hraness-marketing-comparison__glyph,
134
+ .hraness-marketing-comparison [data-comparison-status="depends"] .hraness-marketing-comparison__glyph,
135
+ .hraness-marketing-comparison [data-comparison-status="optional"] .hraness-marketing-comparison__glyph {
136
+ color: CanvasText;
137
+ }
138
+ }
139
+
140
+ .hraness-marketing-comparison__text {
141
+ font-variant-numeric: tabular-nums;
142
+ }
143
+
144
+ .hraness-marketing-comparison__detail {
145
+ display: block;
146
+ color: var(--muted);
147
+ font-size: 0.8125rem;
148
+ font-weight: 400;
149
+ line-height: 1.45;
150
+ margin-block-start: 0.2rem;
151
+ max-inline-size: 26ch;
152
+ }
153
+
154
+ .hraness-marketing-comparison__note {
155
+ color: var(--muted);
156
+ font-size: 0.875rem;
157
+ line-height: 1.5;
158
+ margin-block-start: 1rem;
159
+ max-inline-size: 76ch;
160
+ }
161
+
162
+ }
@@ -0,0 +1,24 @@
1
+ /* SVG source conventions shared by React and generated diagram consumers. */
2
+ @layer components.hraness-design-kit.legacy {
3
+ .hraness-diagram {
4
+ --diagram-accent: var(--primary);
5
+ margin: 0;
6
+ min-inline-size: 0;
7
+ color: var(--foreground);
8
+ font-family: var(--font-text);
9
+ }
10
+ .hraness-diagram__scroll { max-inline-size: 100%; overflow-x: auto; }
11
+ .hraness-diagram__scroll:focus-visible { outline: 2px solid var(--primary); outline-offset: 3px; }
12
+ .hraness-diagram__canvas { display: block; inline-size: 100%; min-inline-size: 40rem; block-size: auto; color: var(--diagram-accent); font-family: var(--font-text); font-size: 20px; }
13
+ .hraness-diagram__label { fill: var(--foreground); font-family: var(--font-text); font-size: 20px; font-weight: 500; }
14
+ .hraness-diagram__detail { fill: var(--muted); font-family: var(--font-text); font-size: 16px; font-weight: 400; }
15
+ .hraness-diagram__node { fill: var(--background); stroke: var(--line); stroke-width: 1; }
16
+ .hraness-diagram__connector,
17
+ .hraness-diagram__icon { color: var(--diagram-accent); fill: none; stroke: currentColor; stroke-width: 1.5; stroke-linecap: round; stroke-linejoin: round; }
18
+ .hraness-diagram figcaption { margin-block-start: 1rem; max-inline-size: 76ch; color: var(--muted); font-size: 0.875rem; line-height: 1.5; }
19
+ @media (forced-colors: active) {
20
+ .hraness-diagram { --diagram-accent: CanvasText; }
21
+ .hraness-diagram__label, .hraness-diagram__detail { fill: CanvasText; }
22
+ .hraness-diagram__node { fill: Canvas; stroke: CanvasText; }
23
+ }
24
+ }
@@ -315,14 +315,15 @@ export function ModeShowcase<S extends string, M extends string, O extends strin
315
315
  export type ThroughStep = Readonly<{
316
316
  id: string;
317
317
  label: string;
318
- /** One sentence under the stage that says what this step shows. */
318
+ /** Optional accessible context; the visual keeps its own explanation. */
319
319
  hint?: string;
320
320
  render: (state: Readonly<{ animated: boolean; theme: MockupTheme | undefined }>) => ReactNode;
321
321
  }>;
322
322
 
323
323
  /**
324
- * Walks a flow one step at a time: numbered step tabs, Back and Next buttons,
325
- * and a live hint. The keyboard model matches `ModeShowcase`.
324
+ * Folder tabs and chevron controls walk a flow. All render functions stay mounted
325
+ * to reserve the tallest panel; inactive panels are inert and visually hidden.
326
+ * The keyboard model matches `ModeShowcase`.
326
327
  */
327
328
  export function StepThrough({
328
329
  caption,
@@ -369,7 +370,7 @@ export function StepThrough({
369
370
  <div aria-label={label} className="hkm-tabs hkm-step-tabs" role="tablist">
370
371
  {steps.map((entry, position) => (
371
372
  <button
372
- aria-controls={`${id}-panel`}
373
+ aria-controls={`${id}-panel-${entry.id}`}
373
374
  aria-selected={position === current}
374
375
  className="hkm-tab"
375
376
  data-hkm-done={position < current ? "" : undefined}
@@ -391,24 +392,31 @@ export function StepThrough({
391
392
  ))}
392
393
  </div>
393
394
  </div>
394
- <div
395
- aria-labelledby={`${id}-tab-${step.id}`}
396
- className="hkm-showcase-stage"
397
- data-hkm-animated={animated ? "" : undefined}
398
- id={`${id}-panel`}
399
- role="tabpanel"
400
- >
401
- <FitToWidth minWidth={minWidth}>{step.render({ animated, theme })}</FitToWidth>
395
+ <div className="hkm-showcase-stage hkm-step-stage">
396
+ {steps.map((entry, position) => (
397
+ <div
398
+ aria-hidden={position !== current}
399
+ aria-labelledby={`${id}-tab-${entry.id}`}
400
+ className="hkm-step-panel"
401
+ data-hkm-animated={position === current && animated ? "" : undefined}
402
+ id={`${id}-panel-${entry.id}`}
403
+ inert={position !== current}
404
+ key={entry.id}
405
+ role="tabpanel"
406
+ >
407
+ <FitToWidth minWidth={minWidth}>{entry.render({ animated: position === current && animated, theme })}</FitToWidth>
408
+ </div>
409
+ ))}
402
410
  </div>
403
411
  <div className="hkm-step-nav">
404
- <button className="hkm-step-button" disabled={current === 0} onClick={() => go(current - 1)} type="button">
405
- Back
412
+ <button aria-label="Back" className="hkm-step-button" disabled={current === 0} onClick={() => go(current - 1)} type="button">
413
+ <svg aria-hidden="true" focusable="false" height="28" viewBox="0 0 24 24" width="28"><path d="m14.5 5-7 7 7 7" fill="none" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" strokeWidth="1.75" /></svg>
406
414
  </button>
407
- <span aria-live="polite" className="hkm-showcase-status">
415
+ <span aria-live="polite" className="hkm-showcase-status hkm-step-announcement">
408
416
  Step {current + 1} of {steps.length}{step.hint === undefined ? "" : `. ${step.hint}`}
409
417
  </span>
410
- <button className="hkm-step-button" data-hkm-primary="" disabled={current === steps.length - 1} onClick={() => go(current + 1)} type="button">
411
- Next
418
+ <button aria-label="Next" className="hkm-step-button" data-hkm-primary="" disabled={current === steps.length - 1} onClick={() => go(current + 1)} type="button">
419
+ <svg aria-hidden="true" focusable="false" height="28" viewBox="0 0 24 24" width="28"><path d="m9.5 5 7 7-7 7" fill="none" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" strokeWidth="1.75" /></svg>
412
420
  </button>
413
421
  </div>
414
422
  {captionText === undefined ? null : (
package/src/mockups.css CHANGED
@@ -2503,6 +2503,25 @@
2503
2503
  }
2504
2504
  }
2505
2505
 
2506
+ /* Folder tabs share an edge with the stable-height walkthrough stage. */
2507
+ .hkm-showcase.hkm-steps { gap: 0; }
2508
+ .hkm-showcase.hkm-steps .hkm-showcase-controls { padding: 0; border: 0; border-radius: 0; background: transparent; }
2509
+ .hkm-showcase.hkm-steps .hkm-step-tabs { gap: 6px; margin: 0; padding: 0; border: 0; position: relative; z-index: 1; }
2510
+ .hkm-showcase.hkm-steps .hkm-tab { min-block-size: 48px; padding: 12px 18px; border: 1px solid var(--hkm-sc-line); border-block-end: 0; border-radius: 12px 12px 0 0; background: var(--hkm-sc-field); color: var(--hkm-sc-muted); }
2511
+ .hkm-showcase.hkm-steps .hkm-tab[aria-selected="true"] { background: var(--hkm-sc-bg); color: var(--hkm-sc-fg); }
2512
+ .hkm-showcase.hkm-steps .hkm-tab:hover { color: var(--hkm-sc-fg); }
2513
+ .hkm-showcase.hkm-steps .hkm-step-stage { display: grid; border: 1px solid var(--hkm-sc-line); border-radius: 0 12px 12px 12px; background: var(--hkm-sc-bg); margin-block-start: -1px; overflow: clip; }
2514
+ .hkm-step-panel { grid-area: 1 / 1; min-inline-size: 0; align-self: start; }
2515
+ .hkm-step-panel[aria-hidden="true"] { visibility: hidden; pointer-events: none; }
2516
+ .hkm-showcase.hkm-steps .hkm-step-panel .hkm-root { border-start-start-radius: 0; border-start-end-radius: 0; box-shadow: none; }
2517
+ .hkm-showcase.hkm-steps .hkm-step-nav { justify-content: space-between; padding-block-start: 18px; gap: 16px; }
2518
+ .hkm-showcase.hkm-steps .hkm-step-button { display: inline-grid; place-items: center; min-inline-size: 52px; min-block-size: 52px; padding: 10px; border: 0; border-radius: 12px; background: transparent; color: var(--hkm-sc-fg); }
2519
+ .hkm-showcase.hkm-steps .hkm-step-button[data-hkm-primary] { background: var(--hkm-sc-fg); color: var(--hkm-sc-bg); }
2520
+ .hkm-showcase.hkm-steps .hkm-step-button:disabled { color: var(--hkm-sc-muted); background: transparent; }
2521
+ .hkm-showcase.hkm-steps .hkm-step-button[data-hkm-primary]:disabled { background: var(--hkm-sc-field); }
2522
+ .hkm-showcase.hkm-steps .hkm-step-announcement { position: absolute; inline-size: 1px; block-size: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
2523
+ .hkm-showcase.hkm-steps .hkm-showcase-caption { margin-block-start: 1rem; }
2524
+
2506
2525
  /* ---------------------------------------------------------------- */
2507
2526
  /* Motion */
2508
2527
  /* ---------------------------------------------------------------- */
@@ -37,7 +37,8 @@
37
37
  .plain-site.plain-publication
38
38
  a:not(.hraness-design-skip-link):is(:hover, :focus-visible)
39
39
  ) {
40
- text-decoration: underline;
40
+ text-decoration-line: underline;
41
+ text-decoration-style: dotted;
41
42
  }
42
43
 
43
44
  :where(.plain-site.plain-publication a:not(.hraness-design-skip-link):focus-visible) {
@@ -697,7 +698,8 @@
697
698
 
698
699
  .plain-site.plain-publication.plain-publication--embedded .plain-publication__byline a {
699
700
  color: inherit;
700
- text-decoration: underline;
701
+ text-decoration-line: underline;
702
+ text-decoration-style: dotted;
701
703
  text-decoration-color: color-mix(in srgb, currentColor 40%, transparent);
702
704
  text-decoration-thickness: 1px;
703
705
  }
@@ -716,7 +718,8 @@
716
718
  }
717
719
 
718
720
  .plain-site.plain-publication.plain-publication--embedded .plain-publication__article-body a {
719
- text-decoration: underline;
721
+ text-decoration-line: underline;
722
+ text-decoration-style: dotted;
720
723
  text-decoration-color: color-mix(in srgb, currentColor 45%, transparent);
721
724
  text-decoration-thickness: 1px;
722
725
  text-underline-offset: 0.18em;
@@ -777,7 +780,7 @@
777
780
  line-height: 1.5;
778
781
  }
779
782
 
780
- .plain-site.plain-publication.plain-publication--embedded .plain-publication__article-body table:not(.plain-publication__table) {
783
+ .plain-site.plain-publication.plain-publication--embedded .plain-publication__article-body table:not(.plain-publication__table, .hraness-marketing-comparison__table) {
781
784
  inline-size: 100%;
782
785
  margin: 1.5rem 0;
783
786
  border-collapse: collapse;
@@ -786,7 +789,7 @@
786
789
  line-height: 1.5;
787
790
  }
788
791
 
789
- .plain-site.plain-publication.plain-publication--embedded .plain-publication__article-body table:not(.plain-publication__table) :is(th, td) {
792
+ .plain-site.plain-publication.plain-publication--embedded .plain-publication__article-body table:not(.plain-publication__table, .hraness-marketing-comparison__table) :is(th, td) {
790
793
  padding: 0.55rem 0.65rem 0.55rem 0;
791
794
  border-top: 1px solid var(--plain-line);
792
795
  overflow-wrap: break-word;
@@ -794,7 +797,7 @@
794
797
  vertical-align: top;
795
798
  }
796
799
 
797
- .plain-site.plain-publication.plain-publication--embedded .plain-publication__article-body table:not(.plain-publication__table) thead th {
800
+ .plain-site.plain-publication.plain-publication--embedded .plain-publication__article-body table:not(.plain-publication__table, .hraness-marketing-comparison__table) thead th {
798
801
  border-top: 0;
799
802
  color: var(--plain-muted);
800
803
  font-weight: 700;