@forumone/throughline-reference-ds 0.0.2 → 0.2.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 (177) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/LICENSE +21 -0
  3. package/README.md +102 -28
  4. package/dist/components/CTASection/CTASection.contract.d.ts +3 -0
  5. package/dist/components/CTASection/CTASection.contract.d.ts.map +1 -0
  6. package/dist/components/CTASection/CTASection.contract.js +117 -0
  7. package/dist/components/CTASection/CTASection.contract.js.map +1 -0
  8. package/dist/components/CTASection/CTASection.d.ts +17 -0
  9. package/dist/components/CTASection/CTASection.d.ts.map +1 -0
  10. package/dist/components/CTASection/CTASection.js +7 -0
  11. package/dist/components/CTASection/CTASection.js.map +1 -0
  12. package/dist/components/CTASection/index.d.ts +3 -0
  13. package/dist/components/CTASection/index.d.ts.map +1 -0
  14. package/dist/components/CTASection/index.js +3 -0
  15. package/dist/components/CTASection/index.js.map +1 -0
  16. package/dist/components/Card/Card.contract.d.ts +3 -0
  17. package/dist/components/Card/Card.contract.d.ts.map +1 -0
  18. package/dist/components/Card/Card.contract.js +111 -0
  19. package/dist/components/Card/Card.contract.js.map +1 -0
  20. package/dist/components/Card/Card.d.ts +16 -0
  21. package/dist/components/Card/Card.d.ts.map +1 -0
  22. package/dist/components/Card/Card.js +11 -0
  23. package/dist/components/Card/Card.js.map +1 -0
  24. package/dist/components/Card/index.d.ts +3 -0
  25. package/dist/components/Card/index.d.ts.map +1 -0
  26. package/dist/components/Card/index.js +3 -0
  27. package/dist/components/Card/index.js.map +1 -0
  28. package/dist/components/CardGrid/CardGrid.contract.d.ts +3 -0
  29. package/dist/components/CardGrid/CardGrid.contract.d.ts.map +1 -0
  30. package/dist/components/CardGrid/CardGrid.contract.js +67 -0
  31. package/dist/components/CardGrid/CardGrid.contract.js.map +1 -0
  32. package/dist/components/CardGrid/CardGrid.d.ts +9 -0
  33. package/dist/components/CardGrid/CardGrid.d.ts.map +1 -0
  34. package/dist/components/CardGrid/CardGrid.js +7 -0
  35. package/dist/components/CardGrid/CardGrid.js.map +1 -0
  36. package/dist/components/CardGrid/index.d.ts +3 -0
  37. package/dist/components/CardGrid/index.d.ts.map +1 -0
  38. package/dist/components/CardGrid/index.js +3 -0
  39. package/dist/components/CardGrid/index.js.map +1 -0
  40. package/dist/components/Divider/Divider.contract.d.ts +3 -0
  41. package/dist/components/Divider/Divider.contract.d.ts.map +1 -0
  42. package/dist/components/Divider/Divider.contract.js +77 -0
  43. package/dist/components/Divider/Divider.contract.js.map +1 -0
  44. package/dist/components/Divider/Divider.d.ts +8 -0
  45. package/dist/components/Divider/Divider.d.ts.map +1 -0
  46. package/dist/components/Divider/Divider.js +10 -0
  47. package/dist/components/Divider/Divider.js.map +1 -0
  48. package/dist/components/Divider/index.d.ts +3 -0
  49. package/dist/components/Divider/index.d.ts.map +1 -0
  50. package/dist/components/Divider/index.js +3 -0
  51. package/dist/components/Divider/index.js.map +1 -0
  52. package/dist/components/FAQ/FAQ.contract.d.ts +3 -0
  53. package/dist/components/FAQ/FAQ.contract.d.ts.map +1 -0
  54. package/dist/components/FAQ/FAQ.contract.js +93 -0
  55. package/dist/components/FAQ/FAQ.contract.js.map +1 -0
  56. package/dist/components/FAQ/FAQ.d.ts +14 -0
  57. package/dist/components/FAQ/FAQ.d.ts.map +1 -0
  58. package/dist/components/FAQ/FAQ.js +7 -0
  59. package/dist/components/FAQ/FAQ.js.map +1 -0
  60. package/dist/components/FAQ/index.d.ts +3 -0
  61. package/dist/components/FAQ/index.d.ts.map +1 -0
  62. package/dist/components/FAQ/index.js +3 -0
  63. package/dist/components/FAQ/index.js.map +1 -0
  64. package/dist/components/Hero/Hero.contract.d.ts +3 -0
  65. package/dist/components/Hero/Hero.contract.d.ts.map +1 -0
  66. package/dist/components/Hero/Hero.contract.js +171 -0
  67. package/dist/components/Hero/Hero.contract.js.map +1 -0
  68. package/dist/components/Hero/Hero.d.ts +24 -0
  69. package/dist/components/Hero/Hero.d.ts.map +1 -0
  70. package/dist/components/Hero/Hero.js +7 -0
  71. package/dist/components/Hero/Hero.js.map +1 -0
  72. package/dist/components/Hero/index.d.ts +3 -0
  73. package/dist/components/Hero/index.d.ts.map +1 -0
  74. package/dist/components/Hero/index.js +3 -0
  75. package/dist/components/Hero/index.js.map +1 -0
  76. package/dist/components/MediaBlock/MediaBlock.contract.d.ts +3 -0
  77. package/dist/components/MediaBlock/MediaBlock.contract.d.ts.map +1 -0
  78. package/dist/components/MediaBlock/MediaBlock.contract.js +83 -0
  79. package/dist/components/MediaBlock/MediaBlock.contract.js.map +1 -0
  80. package/dist/components/MediaBlock/MediaBlock.d.ts +23 -0
  81. package/dist/components/MediaBlock/MediaBlock.d.ts.map +1 -0
  82. package/dist/components/MediaBlock/MediaBlock.js +8 -0
  83. package/dist/components/MediaBlock/MediaBlock.js.map +1 -0
  84. package/dist/components/MediaBlock/index.d.ts +3 -0
  85. package/dist/components/MediaBlock/index.d.ts.map +1 -0
  86. package/dist/components/MediaBlock/index.js +3 -0
  87. package/dist/components/MediaBlock/index.js.map +1 -0
  88. package/dist/components/Prose/Prose.contract.d.ts +3 -0
  89. package/dist/components/Prose/Prose.contract.d.ts.map +1 -0
  90. package/dist/components/Prose/Prose.contract.js +95 -0
  91. package/dist/components/Prose/Prose.contract.js.map +1 -0
  92. package/dist/components/Prose/Prose.d.ts +9 -0
  93. package/dist/components/Prose/Prose.d.ts.map +1 -0
  94. package/dist/components/Prose/Prose.js +7 -0
  95. package/dist/components/Prose/Prose.js.map +1 -0
  96. package/dist/components/Prose/index.d.ts +3 -0
  97. package/dist/components/Prose/index.d.ts.map +1 -0
  98. package/dist/components/Prose/index.js +3 -0
  99. package/dist/components/Prose/index.js.map +1 -0
  100. package/dist/components/Quote/Quote.contract.d.ts +3 -0
  101. package/dist/components/Quote/Quote.contract.d.ts.map +1 -0
  102. package/dist/components/Quote/Quote.contract.js +90 -0
  103. package/dist/components/Quote/Quote.contract.js.map +1 -0
  104. package/dist/components/Quote/Quote.d.ts +16 -0
  105. package/dist/components/Quote/Quote.d.ts.map +1 -0
  106. package/dist/components/Quote/Quote.js +7 -0
  107. package/dist/components/Quote/Quote.js.map +1 -0
  108. package/dist/components/Quote/index.d.ts +3 -0
  109. package/dist/components/Quote/index.d.ts.map +1 -0
  110. package/dist/components/Quote/index.js +3 -0
  111. package/dist/components/Quote/index.js.map +1 -0
  112. package/dist/components/SectionIntro/SectionIntro.contract.d.ts +3 -0
  113. package/dist/components/SectionIntro/SectionIntro.contract.d.ts.map +1 -0
  114. package/dist/components/SectionIntro/SectionIntro.contract.js +97 -0
  115. package/dist/components/SectionIntro/SectionIntro.contract.js.map +1 -0
  116. package/dist/components/SectionIntro/SectionIntro.d.ts +10 -0
  117. package/dist/components/SectionIntro/SectionIntro.d.ts.map +1 -0
  118. package/dist/components/SectionIntro/SectionIntro.js +7 -0
  119. package/dist/components/SectionIntro/SectionIntro.js.map +1 -0
  120. package/dist/components/SectionIntro/index.d.ts +3 -0
  121. package/dist/components/SectionIntro/index.d.ts.map +1 -0
  122. package/dist/components/SectionIntro/index.js +3 -0
  123. package/dist/components/SectionIntro/index.js.map +1 -0
  124. package/dist/components/Spacer/Spacer.contract.d.ts +3 -0
  125. package/dist/components/Spacer/Spacer.contract.d.ts.map +1 -0
  126. package/dist/components/Spacer/Spacer.contract.js +66 -0
  127. package/dist/components/Spacer/Spacer.contract.js.map +1 -0
  128. package/dist/components/Spacer/Spacer.d.ts +7 -0
  129. package/dist/components/Spacer/Spacer.d.ts.map +1 -0
  130. package/dist/components/Spacer/Spacer.js +7 -0
  131. package/dist/components/Spacer/Spacer.js.map +1 -0
  132. package/dist/components/Spacer/index.d.ts +3 -0
  133. package/dist/components/Spacer/index.d.ts.map +1 -0
  134. package/dist/components/Spacer/index.js +3 -0
  135. package/dist/components/Spacer/index.js.map +1 -0
  136. package/dist/components/Stats/Stats.contract.d.ts +3 -0
  137. package/dist/components/Stats/Stats.contract.d.ts.map +1 -0
  138. package/dist/components/Stats/Stats.contract.js +92 -0
  139. package/dist/components/Stats/Stats.contract.js.map +1 -0
  140. package/dist/components/Stats/Stats.d.ts +13 -0
  141. package/dist/components/Stats/Stats.d.ts.map +1 -0
  142. package/dist/components/Stats/Stats.js +7 -0
  143. package/dist/components/Stats/Stats.js.map +1 -0
  144. package/dist/components/Stats/index.d.ts +3 -0
  145. package/dist/components/Stats/index.d.ts.map +1 -0
  146. package/dist/components/Stats/index.js +3 -0
  147. package/dist/components/Stats/index.js.map +1 -0
  148. package/dist/index.d.ts +14 -0
  149. package/dist/index.d.ts.map +1 -0
  150. package/dist/index.js +14 -0
  151. package/dist/index.js.map +1 -0
  152. package/dist/manifest.json +2014 -0
  153. package/dist/styles/base.css +55 -0
  154. package/dist/styles/index.css +213 -0
  155. package/dist/styles/reset.css +48 -0
  156. package/dist/styles/tokens.css +105 -0
  157. package/dist/tokens/colors.d.ts +48 -0
  158. package/dist/tokens/colors.d.ts.map +1 -0
  159. package/dist/tokens/colors.js +47 -0
  160. package/dist/tokens/colors.js.map +1 -0
  161. package/dist/tokens/index.d.ts +99 -0
  162. package/dist/tokens/index.d.ts.map +1 -0
  163. package/dist/tokens/index.js +21 -0
  164. package/dist/tokens/index.js.map +1 -0
  165. package/dist/tokens/radii.d.ts +11 -0
  166. package/dist/tokens/radii.d.ts.map +1 -0
  167. package/dist/tokens/radii.js +10 -0
  168. package/dist/tokens/radii.js.map +1 -0
  169. package/dist/tokens/spacing.d.ts +26 -0
  170. package/dist/tokens/spacing.d.ts.map +1 -0
  171. package/dist/tokens/spacing.js +25 -0
  172. package/dist/tokens/spacing.js.map +1 -0
  173. package/dist/tokens/typography.d.ts +28 -0
  174. package/dist/tokens/typography.d.ts.map +1 -0
  175. package/dist/tokens/typography.js +27 -0
  176. package/dist/tokens/typography.js.map +1 -0
  177. package/package.json +88 -7
@@ -0,0 +1,83 @@
1
+ export const contract = {
2
+ name: 'MediaBlock',
3
+ category: 'media',
4
+ description: 'A full-width image or video block with optional caption and configurable aspect ratio.',
5
+ intent: 'Insert a single piece of featured media inside a content flow. Use for editorial imagery that deserves its own moment — a photograph illustrating a story, a portrait accompanying a quote, or a video introducing a program. Not a gallery; for multiple items compose a custom layout.',
6
+ composition: {
7
+ placement: ['section'],
8
+ maxPerPage: null,
9
+ requiredSiblings: [],
10
+ forbiddenAdjacent: [],
11
+ },
12
+ content: {
13
+ fields: [
14
+ {
15
+ name: 'media',
16
+ type: 'group',
17
+ required: true,
18
+ of: [
19
+ { name: 'type', type: 'select', required: true },
20
+ { name: 'url', type: 'link', required: true },
21
+ { name: 'alt', type: 'text', required: false, maxLength: 200 },
22
+ { name: 'poster', type: 'image', required: false },
23
+ { name: 'ariaLabel', type: 'text', required: false, maxLength: 120 },
24
+ ],
25
+ },
26
+ {
27
+ name: 'caption',
28
+ type: 'text',
29
+ required: false,
30
+ maxLength: 200,
31
+ constraints: 'One sentence that adds context the image alone cannot carry',
32
+ },
33
+ ],
34
+ variants: [
35
+ { name: '16:9', description: 'Cinematic widescreen', whenToUse: 'Most photographs and video' },
36
+ { name: '4:3', description: 'Classic television ratio', whenToUse: 'Vintage or squared compositions' },
37
+ { name: 'square', description: '1:1', whenToUse: 'Portraits or product shots' },
38
+ { name: 'auto', description: 'Media\'s native ratio', whenToUse: 'Diagrams, infographics, or tall images' },
39
+ ],
40
+ },
41
+ tokens: {
42
+ consumes: [
43
+ 'color.bg.tertiary',
44
+ 'color.text.secondary',
45
+ 'spacing.container',
46
+ 'spacing.3',
47
+ 'font.size.sm',
48
+ 'radius.lg',
49
+ ],
50
+ },
51
+ accessibility: {
52
+ keyboardSupport: ['Video: native play/pause/seek controls'],
53
+ screenReaderBehavior: 'Images announce their alt text. Videos announce their aria-label (or fall back to native labeling). Captions are associated with the figure semantically via <figcaption>.',
54
+ contentWarnings: [
55
+ 'Always author alt text for images that carry information; use empty alt ("") for purely decorative media',
56
+ 'Videos with spoken content must ship captions',
57
+ ],
58
+ },
59
+ examples: [
60
+ { label: 'Image with caption', intent: 'Editorial photograph', storyId: 'media-block--image' },
61
+ { label: 'Square crop', intent: 'Portrait or product shot', storyId: 'media-block--square' },
62
+ { label: 'Video', intent: 'Introductory video with poster', storyId: 'media-block--video' },
63
+ ],
64
+ antiExamples: [
65
+ {
66
+ label: 'Stacking three MediaBlocks for a gallery',
67
+ why: 'MediaBlock is a spotlight element; stacking them creates awkward repetition without true gallery ergonomics',
68
+ useInstead: 'Build a dedicated gallery component in your client DS',
69
+ },
70
+ {
71
+ label: 'Decorative image with invented alt text',
72
+ why: 'Screen readers read the alt text; inventing "people smiling" for decorative media wastes listener attention',
73
+ useInstead: 'Use alt="" for purely decorative media',
74
+ },
75
+ ],
76
+ behavior: {
77
+ fetchesData: false,
78
+ hasClientState: false,
79
+ animates: false,
80
+ requiresAnalytics: false,
81
+ },
82
+ };
83
+ //# sourceMappingURL=MediaBlock.contract.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MediaBlock.contract.js","sourceRoot":"","sources":["../../../src/components/MediaBlock/MediaBlock.contract.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,QAAQ,GAAsB;IACzC,IAAI,EAAE,YAAY;IAClB,QAAQ,EAAE,OAAO;IACjB,WAAW,EACT,wFAAwF;IAC1F,MAAM,EACJ,0RAA0R;IAE5R,WAAW,EAAE;QACX,SAAS,EAAE,CAAC,SAAS,CAAC;QACtB,UAAU,EAAE,IAAI;QAChB,gBAAgB,EAAE,EAAE;QACpB,iBAAiB,EAAE,EAAE;KACtB;IAED,OAAO,EAAE;QACP,MAAM,EAAE;YACN;gBACE,IAAI,EAAE,OAAO;gBACb,IAAI,EAAE,OAAO;gBACb,QAAQ,EAAE,IAAI;gBACd,EAAE,EAAE;oBACF,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE;oBAChD,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE;oBAC7C,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE;oBAC9D,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE;oBAClD,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE;iBACrE;aACF;YACD;gBACE,IAAI,EAAE,SAAS;gBACf,IAAI,EAAE,MAAM;gBACZ,QAAQ,EAAE,KAAK;gBACf,SAAS,EAAE,GAAG;gBACd,WAAW,EAAE,6DAA6D;aAC3E;SACF;QACD,QAAQ,EAAE;YACR,EAAE,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,sBAAsB,EAAE,SAAS,EAAE,4BAA4B,EAAE;YAC9F,EAAE,IAAI,EAAE,KAAK,EAAE,WAAW,EAAE,0BAA0B,EAAE,SAAS,EAAE,iCAAiC,EAAE;YACtG,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,KAAK,EAAE,SAAS,EAAE,4BAA4B,EAAE;YAC/E,EAAE,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,uBAAuB,EAAE,SAAS,EAAE,wCAAwC,EAAE;SAC5G;KACF;IAED,MAAM,EAAE;QACN,QAAQ,EAAE;YACR,mBAAmB;YACnB,sBAAsB;YACtB,mBAAmB;YACnB,WAAW;YACX,cAAc;YACd,WAAW;SACZ;KACF;IAED,aAAa,EAAE;QACb,eAAe,EAAE,CAAC,wCAAwC,CAAC;QAC3D,oBAAoB,EAClB,4KAA4K;QAC9K,eAAe,EAAE;YACf,0GAA0G;YAC1G,+CAA+C;SAChD;KACF;IAED,QAAQ,EAAE;QACR,EAAE,KAAK,EAAE,oBAAoB,EAAE,MAAM,EAAE,sBAAsB,EAAE,OAAO,EAAE,oBAAoB,EAAE;QAC9F,EAAE,KAAK,EAAE,aAAa,EAAE,MAAM,EAAE,0BAA0B,EAAE,OAAO,EAAE,qBAAqB,EAAE;QAC5F,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,gCAAgC,EAAE,OAAO,EAAE,oBAAoB,EAAE;KAC5F;IAED,YAAY,EAAE;QACZ;YACE,KAAK,EAAE,0CAA0C;YACjD,GAAG,EAAE,6GAA6G;YAClH,UAAU,EAAE,uDAAuD;SACpE;QACD;YACE,KAAK,EAAE,yCAAyC;YAChD,GAAG,EAAE,6GAA6G;YAClH,UAAU,EAAE,wCAAwC;SACrD;KACF;IAED,QAAQ,EAAE;QACR,WAAW,EAAE,KAAK;QAClB,cAAc,EAAE,KAAK;QACrB,QAAQ,EAAE,KAAK;QACf,iBAAiB,EAAE,KAAK;KACzB;CACF,CAAA"}
@@ -0,0 +1,23 @@
1
+ export type MediaBlockAspect = '16:9' | '4:3' | 'square' | 'auto';
2
+ type ImageMedia = {
3
+ type: 'image';
4
+ url: string;
5
+ alt: string;
6
+ };
7
+ type VideoMedia = {
8
+ type: 'video';
9
+ url: string;
10
+ poster?: string;
11
+ /** Accessible label used when the video lacks audio/captions narrative context. */
12
+ ariaLabel?: string;
13
+ };
14
+ export type MediaBlockMedia = ImageMedia | VideoMedia;
15
+ export interface MediaBlockProps {
16
+ media: MediaBlockMedia;
17
+ caption?: string;
18
+ aspect?: MediaBlockAspect;
19
+ className?: string;
20
+ }
21
+ export declare function MediaBlock({ media, caption, aspect, className, }: MediaBlockProps): import("react/jsx-runtime").JSX.Element;
22
+ export {};
23
+ //# sourceMappingURL=MediaBlock.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MediaBlock.d.ts","sourceRoot":"","sources":["../../../src/components/MediaBlock/MediaBlock.tsx"],"names":[],"mappings":"AAGA,MAAM,MAAM,gBAAgB,GAAG,MAAM,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAA;AAEjE,KAAK,UAAU,GAAG;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAAA;AAC7D,KAAK,UAAU,GAAG;IAChB,IAAI,EAAE,OAAO,CAAA;IACb,GAAG,EAAE,MAAM,CAAA;IACX,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,mFAAmF;IACnF,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,CAAA;AAED,MAAM,MAAM,eAAe,GAAG,UAAU,GAAG,UAAU,CAAA;AAErD,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,eAAe,CAAA;IACtB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,MAAM,CAAC,EAAE,gBAAgB,CAAA;IACzB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED,wBAAgB,UAAU,CAAC,EACzB,KAAK,EACL,OAAO,EACP,MAAe,EACf,SAAS,GACV,EAAE,eAAe,2CAoBjB"}
@@ -0,0 +1,8 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { clsx } from 'clsx';
3
+ import styles from './MediaBlock.module.css';
4
+ export function MediaBlock({ media, caption, aspect = '16:9', className, }) {
5
+ const aspectKey = aspect === '16:9' ? 'aspect16x9' : aspect === '4:3' ? 'aspect4x3' : `aspect-${aspect}`;
6
+ return (_jsxs("figure", { className: clsx(styles.figure, className), children: [_jsx("div", { className: clsx(styles.frame, styles[aspectKey]), children: media.type === 'image' ? (_jsx("img", { src: media.url, alt: media.alt, className: styles.media })) : (_jsx("video", { src: media.url, poster: media.poster, controls: true, "aria-label": media.ariaLabel, className: styles.media })) }), caption ? _jsx("figcaption", { className: styles.caption, children: caption }) : null] }));
7
+ }
8
+ //# sourceMappingURL=MediaBlock.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MediaBlock.js","sourceRoot":"","sources":["../../../src/components/MediaBlock/MediaBlock.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAC3B,OAAO,MAAM,MAAM,yBAAyB,CAAA;AAsB5C,MAAM,UAAU,UAAU,CAAC,EACzB,KAAK,EACL,OAAO,EACP,MAAM,GAAG,MAAM,EACf,SAAS,GACO;IAChB,MAAM,SAAS,GAAG,MAAM,KAAK,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,MAAM,KAAK,KAAK,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,UAAU,MAAM,EAAE,CAAA;IACxG,OAAO,CACL,kBAAQ,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,aAC/C,cAAK,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,SAAS,CAAC,CAAC,YAClD,KAAK,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,CACxB,cAAK,GAAG,EAAE,KAAK,CAAC,GAAG,EAAE,GAAG,EAAE,KAAK,CAAC,GAAG,EAAE,SAAS,EAAE,MAAM,CAAC,KAAK,GAAI,CACjE,CAAC,CAAC,CAAC,CACF,gBACE,GAAG,EAAE,KAAK,CAAC,GAAG,EACd,MAAM,EAAE,KAAK,CAAC,MAAM,EACpB,QAAQ,sBACI,KAAK,CAAC,SAAS,EAC3B,SAAS,EAAE,MAAM,CAAC,KAAK,GACvB,CACH,GACG,EACL,OAAO,CAAC,CAAC,CAAC,qBAAY,SAAS,EAAE,MAAM,CAAC,OAAO,YAAG,OAAO,GAAc,CAAC,CAAC,CAAC,IAAI,IACxE,CACV,CAAA;AACH,CAAC"}
@@ -0,0 +1,3 @@
1
+ export { MediaBlock, type MediaBlockAspect, type MediaBlockMedia, type MediaBlockProps, } from './MediaBlock.js';
2
+ export { contract as mediaBlockContract } from './MediaBlock.contract.js';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/MediaBlock/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,EACV,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACpB,KAAK,eAAe,GACrB,MAAM,iBAAiB,CAAA;AACxB,OAAO,EAAE,QAAQ,IAAI,kBAAkB,EAAE,MAAM,0BAA0B,CAAA"}
@@ -0,0 +1,3 @@
1
+ export { MediaBlock, } from './MediaBlock.js';
2
+ export { contract as mediaBlockContract } from './MediaBlock.contract.js';
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/components/MediaBlock/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,GAIX,MAAM,iBAAiB,CAAA;AACxB,OAAO,EAAE,QAAQ,IAAI,kBAAkB,EAAE,MAAM,0BAA0B,CAAA"}
@@ -0,0 +1,3 @@
1
+ import type { ComponentContract } from '@forumone/throughline-design-contract';
2
+ export declare const contract: ComponentContract;
3
+ //# sourceMappingURL=Prose.contract.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Prose.contract.d.ts","sourceRoot":"","sources":["../../../src/components/Prose/Prose.contract.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,uCAAuC,CAAA;AAE9E,eAAO,MAAM,QAAQ,EAAE,iBAwGtB,CAAA"}
@@ -0,0 +1,95 @@
1
+ export const contract = {
2
+ name: 'Prose',
3
+ category: 'section',
4
+ description: 'A typographic container for long-form content — articles, policies, documentation, any flowing prose with headings and lists.',
5
+ intent: 'Wrap free-flowing editorial content with sensible typography defaults (heading hierarchy, paragraph rhythm, list styling, blockquote treatment). Use any time you have a block of content authored as rich text and you want it to read well without styling each element individually.',
6
+ composition: {
7
+ placement: ['section'],
8
+ maxPerPage: null,
9
+ requiredSiblings: [],
10
+ forbiddenAdjacent: [],
11
+ },
12
+ content: {
13
+ fields: [
14
+ {
15
+ name: 'children',
16
+ type: 'richtext',
17
+ required: true,
18
+ constraints: 'Rich text content authored in the CMS; can include h2-h4, paragraphs, lists, blockquotes, links',
19
+ },
20
+ ],
21
+ variants: [
22
+ {
23
+ name: 'default',
24
+ description: 'Standard reading rhythm',
25
+ whenToUse: 'Most articles and editorial content',
26
+ },
27
+ {
28
+ name: 'compact',
29
+ description: 'Tighter spacing and line height',
30
+ whenToUse: 'Denser reference content, product docs, or reading-room pages',
31
+ },
32
+ {
33
+ name: 'spacious',
34
+ description: 'Looser spacing and line height',
35
+ whenToUse: 'Long-form essays where the reader benefits from breathing room',
36
+ },
37
+ ],
38
+ },
39
+ tokens: {
40
+ consumes: [
41
+ 'color.text.primary',
42
+ 'color.text.secondary',
43
+ 'color.border.strong',
44
+ 'color.brand.primary',
45
+ 'spacing.container',
46
+ 'spacing.10',
47
+ 'spacing.8',
48
+ 'spacing.6',
49
+ 'spacing.5',
50
+ 'spacing.4',
51
+ 'spacing.2',
52
+ 'font.size.3xl',
53
+ 'font.size.2xl',
54
+ 'font.size.xl',
55
+ 'font.size.lg',
56
+ 'font.weight.semibold',
57
+ 'line.height.snug',
58
+ 'line.height.normal',
59
+ 'line.height.relaxed',
60
+ 'line.height.loose',
61
+ ],
62
+ },
63
+ accessibility: {
64
+ keyboardSupport: [],
65
+ screenReaderBehavior: 'Children render as their native semantic HTML (h2, h3, p, ul, ol, blockquote, a). Prose adds no ARIA beyond what the authored content provides.',
66
+ contentWarnings: [
67
+ 'Author h2 and below inside Prose; never h1 (the page already has one)',
68
+ 'Use real list markup, not paragraphs with bullets',
69
+ ],
70
+ },
71
+ examples: [
72
+ { label: 'Default', intent: 'Standard article body', storyId: 'prose--default' },
73
+ { label: 'Compact', intent: 'Reference or documentation page', storyId: 'prose--compact' },
74
+ { label: 'Spacious', intent: 'Long-form essay or manifesto', storyId: 'prose--spacious' },
75
+ ],
76
+ antiExamples: [
77
+ {
78
+ label: 'Nesting Prose inside Prose',
79
+ why: 'Creates duplicate typography scales and unpredictable spacing',
80
+ useInstead: 'Use a single Prose at the outermost level',
81
+ },
82
+ {
83
+ label: 'Putting interactive components inside Prose',
84
+ why: 'Prose is for flowing editorial content; components like Stats or CardGrid have their own layout',
85
+ useInstead: 'Close the Prose, render the component, open another Prose for continuing text',
86
+ },
87
+ ],
88
+ behavior: {
89
+ fetchesData: false,
90
+ hasClientState: false,
91
+ animates: false,
92
+ requiresAnalytics: false,
93
+ },
94
+ };
95
+ //# sourceMappingURL=Prose.contract.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Prose.contract.js","sourceRoot":"","sources":["../../../src/components/Prose/Prose.contract.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,QAAQ,GAAsB;IACzC,IAAI,EAAE,OAAO;IACb,QAAQ,EAAE,SAAS;IACnB,WAAW,EACT,+HAA+H;IACjI,MAAM,EACJ,yRAAyR;IAE3R,WAAW,EAAE;QACX,SAAS,EAAE,CAAC,SAAS,CAAC;QACtB,UAAU,EAAE,IAAI;QAChB,gBAAgB,EAAE,EAAE;QACpB,iBAAiB,EAAE,EAAE;KACtB;IAED,OAAO,EAAE;QACP,MAAM,EAAE;YACN;gBACE,IAAI,EAAE,UAAU;gBAChB,IAAI,EAAE,UAAU;gBAChB,QAAQ,EAAE,IAAI;gBACd,WAAW,EACT,iGAAiG;aACpG;SACF;QACD,QAAQ,EAAE;YACR;gBACE,IAAI,EAAE,SAAS;gBACf,WAAW,EAAE,yBAAyB;gBACtC,SAAS,EAAE,qCAAqC;aACjD;YACD;gBACE,IAAI,EAAE,SAAS;gBACf,WAAW,EAAE,iCAAiC;gBAC9C,SAAS,EAAE,+DAA+D;aAC3E;YACD;gBACE,IAAI,EAAE,UAAU;gBAChB,WAAW,EAAE,gCAAgC;gBAC7C,SAAS,EAAE,gEAAgE;aAC5E;SACF;KACF;IAED,MAAM,EAAE;QACN,QAAQ,EAAE;YACR,oBAAoB;YACpB,sBAAsB;YACtB,qBAAqB;YACrB,qBAAqB;YACrB,mBAAmB;YACnB,YAAY;YACZ,WAAW;YACX,WAAW;YACX,WAAW;YACX,WAAW;YACX,WAAW;YACX,eAAe;YACf,eAAe;YACf,cAAc;YACd,cAAc;YACd,sBAAsB;YACtB,kBAAkB;YAClB,oBAAoB;YACpB,qBAAqB;YACrB,mBAAmB;SACpB;KACF;IAED,aAAa,EAAE;QACb,eAAe,EAAE,EAAE;QACnB,oBAAoB,EAClB,iJAAiJ;QACnJ,eAAe,EAAE;YACf,uEAAuE;YACvE,mDAAmD;SACpD;KACF;IAED,QAAQ,EAAE;QACR,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,uBAAuB,EAAE,OAAO,EAAE,gBAAgB,EAAE;QAChF,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,iCAAiC,EAAE,OAAO,EAAE,gBAAgB,EAAE;QAC1F,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,8BAA8B,EAAE,OAAO,EAAE,iBAAiB,EAAE;KAC1F;IAED,YAAY,EAAE;QACZ;YACE,KAAK,EAAE,4BAA4B;YACnC,GAAG,EAAE,+DAA+D;YACpE,UAAU,EAAE,2CAA2C;SACxD;QACD;YACE,KAAK,EAAE,6CAA6C;YACpD,GAAG,EAAE,iGAAiG;YACtG,UAAU,EAAE,+EAA+E;SAC5F;KACF;IAED,QAAQ,EAAE;QACR,WAAW,EAAE,KAAK;QAClB,cAAc,EAAE,KAAK;QACrB,QAAQ,EAAE,KAAK;QACf,iBAAiB,EAAE,KAAK;KACzB;CACF,CAAA"}
@@ -0,0 +1,9 @@
1
+ import type { ReactNode } from 'react';
2
+ export type ProseSize = 'default' | 'compact' | 'spacious';
3
+ export interface ProseProps {
4
+ children: ReactNode;
5
+ size?: ProseSize;
6
+ className?: string;
7
+ }
8
+ export declare function Prose({ children, size, className }: ProseProps): import("react/jsx-runtime").JSX.Element;
9
+ //# sourceMappingURL=Prose.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Prose.d.ts","sourceRoot":"","sources":["../../../src/components/Prose/Prose.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAGtC,MAAM,MAAM,SAAS,GAAG,SAAS,GAAG,SAAS,GAAG,UAAU,CAAA;AAE1D,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,SAAS,CAAA;IACnB,IAAI,CAAC,EAAE,SAAS,CAAA;IAChB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED,wBAAgB,KAAK,CAAC,EAAE,QAAQ,EAAE,IAAgB,EAAE,SAAS,EAAE,EAAE,UAAU,2CAE1E"}
@@ -0,0 +1,7 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { clsx } from 'clsx';
3
+ import styles from './Prose.module.css';
4
+ export function Prose({ children, size = 'default', className }) {
5
+ return _jsx("div", { className: clsx(styles.prose, styles[size], className), children: children });
6
+ }
7
+ //# sourceMappingURL=Prose.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Prose.js","sourceRoot":"","sources":["../../../src/components/Prose/Prose.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAE3B,OAAO,MAAM,MAAM,oBAAoB,CAAA;AAUvC,MAAM,UAAU,KAAK,CAAC,EAAE,QAAQ,EAAE,IAAI,GAAG,SAAS,EAAE,SAAS,EAAc;IACzE,OAAO,cAAK,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,IAAI,CAAC,EAAE,SAAS,CAAC,YAAG,QAAQ,GAAO,CAAA;AACtF,CAAC"}
@@ -0,0 +1,3 @@
1
+ export { Prose, type ProseProps, type ProseSize } from './Prose.js';
2
+ export { contract as proseContract } from './Prose.contract.js';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/Prose/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,KAAK,UAAU,EAAE,KAAK,SAAS,EAAE,MAAM,YAAY,CAAA;AACnE,OAAO,EAAE,QAAQ,IAAI,aAAa,EAAE,MAAM,qBAAqB,CAAA"}
@@ -0,0 +1,3 @@
1
+ export { Prose } from './Prose.js';
2
+ export { contract as proseContract } from './Prose.contract.js';
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/components/Prose/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAmC,MAAM,YAAY,CAAA;AACnE,OAAO,EAAE,QAAQ,IAAI,aAAa,EAAE,MAAM,qBAAqB,CAAA"}
@@ -0,0 +1,3 @@
1
+ import type { ComponentContract } from '@forumone/throughline-design-contract';
2
+ export declare const contract: ComponentContract;
3
+ //# sourceMappingURL=Quote.contract.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Quote.contract.d.ts","sourceRoot":"","sources":["../../../src/components/Quote/Quote.contract.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,uCAAuC,CAAA;AAE9E,eAAO,MAAM,QAAQ,EAAE,iBAkGtB,CAAA"}
@@ -0,0 +1,90 @@
1
+ export const contract = {
2
+ name: 'Quote',
3
+ category: 'media',
4
+ description: 'A pullquote or testimonial rendered as a <figure> with a <blockquote> and optional figcaption attribution.',
5
+ intent: 'Surface a single human-scale quotation — a testimonial, a pullquote, a foundational claim. Use sparingly; quotes lose weight when stacked. The attribution is optional because some quotes stand on their own without a named author.',
6
+ composition: {
7
+ placement: ['section'],
8
+ maxPerPage: null,
9
+ requiredSiblings: [],
10
+ forbiddenAdjacent: ['Quote'],
11
+ },
12
+ content: {
13
+ fields: [
14
+ {
15
+ name: 'quote',
16
+ type: 'text',
17
+ required: true,
18
+ maxLength: 400,
19
+ constraints: 'One or two sentences; longer belongs in Prose',
20
+ },
21
+ {
22
+ name: 'attribution',
23
+ type: 'group',
24
+ required: false,
25
+ of: [
26
+ { name: 'name', type: 'text', required: true, maxLength: 80 },
27
+ { name: 'role', type: 'text', required: false, maxLength: 100 },
28
+ { name: 'avatar', type: 'image', required: false },
29
+ ],
30
+ },
31
+ ],
32
+ variants: [
33
+ { name: 'default', description: 'Standard size', whenToUse: 'Most testimonials and pullquotes' },
34
+ { name: 'large', description: 'Oversized display treatment', whenToUse: 'Editorial openers or mission-page quotes that carry real weight' },
35
+ ],
36
+ },
37
+ tokens: {
38
+ consumes: [
39
+ 'color.text.primary',
40
+ 'color.text.secondary',
41
+ 'spacing.10',
42
+ 'spacing.6',
43
+ 'spacing.3',
44
+ 'spacing.container',
45
+ 'font.size.4xl',
46
+ 'font.size.2xl',
47
+ 'font.size.sm',
48
+ 'font.weight.semibold',
49
+ 'line.height.tight',
50
+ 'line.height.snug',
51
+ 'radius.full',
52
+ ],
53
+ configurable: [
54
+ { prop: 'size', tokenGroup: 'layout', allowedValues: ['default', 'large'] },
55
+ ],
56
+ },
57
+ accessibility: {
58
+ keyboardSupport: [],
59
+ screenReaderBehavior: 'Rendered as <figure> containing a <blockquote>; attribution is read as the figcaption. Decorative quotation marks are generated via CSS and are not in the accessible name.',
60
+ contentWarnings: [
61
+ 'Do not quote someone without permission',
62
+ 'Use their actual words; a paraphrase inside quotation marks misrepresents them',
63
+ ],
64
+ },
65
+ examples: [
66
+ { label: 'Default', intent: 'Testimonial with role', storyId: 'quote--default' },
67
+ { label: 'With avatar', intent: 'Testimonial with portrait', storyId: 'quote--with-avatar' },
68
+ { label: 'Large', intent: 'Editorial mission statement', storyId: 'quote--large' },
69
+ { label: 'Without attribution', intent: 'Aphoristic pullquote', storyId: 'quote--without-attribution' },
70
+ ],
71
+ antiExamples: [
72
+ {
73
+ label: 'Four quotes in a row',
74
+ why: 'Quote is meant to punctuate content, not fill a page',
75
+ useInstead: 'Pick the strongest quote; move the rest into Prose or a CardGrid of Cards',
76
+ },
77
+ {
78
+ label: 'Using Quote for product blurbs',
79
+ why: 'Quote implies a real human author; marketing copy without a source undermines trust',
80
+ useInstead: 'CTASection or Prose',
81
+ },
82
+ ],
83
+ behavior: {
84
+ fetchesData: false,
85
+ hasClientState: false,
86
+ animates: false,
87
+ requiresAnalytics: false,
88
+ },
89
+ };
90
+ //# sourceMappingURL=Quote.contract.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Quote.contract.js","sourceRoot":"","sources":["../../../src/components/Quote/Quote.contract.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,QAAQ,GAAsB;IACzC,IAAI,EAAE,OAAO;IACb,QAAQ,EAAE,OAAO;IACjB,WAAW,EACT,4GAA4G;IAC9G,MAAM,EACJ,uOAAuO;IAEzO,WAAW,EAAE;QACX,SAAS,EAAE,CAAC,SAAS,CAAC;QACtB,UAAU,EAAE,IAAI;QAChB,gBAAgB,EAAE,EAAE;QACpB,iBAAiB,EAAE,CAAC,OAAO,CAAC;KAC7B;IAED,OAAO,EAAE;QACP,MAAM,EAAE;YACN;gBACE,IAAI,EAAE,OAAO;gBACb,IAAI,EAAE,MAAM;gBACZ,QAAQ,EAAE,IAAI;gBACd,SAAS,EAAE,GAAG;gBACd,WAAW,EAAE,+CAA+C;aAC7D;YACD;gBACE,IAAI,EAAE,aAAa;gBACnB,IAAI,EAAE,OAAO;gBACb,QAAQ,EAAE,KAAK;gBACf,EAAE,EAAE;oBACF,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,EAAE;oBAC7D,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE;oBAC/D,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE;iBACnD;aACF;SACF;QACD,QAAQ,EAAE;YACR,EAAE,IAAI,EAAE,SAAS,EAAE,WAAW,EAAE,eAAe,EAAE,SAAS,EAAE,kCAAkC,EAAE;YAChG,EAAE,IAAI,EAAE,OAAO,EAAE,WAAW,EAAE,6BAA6B,EAAE,SAAS,EAAE,iEAAiE,EAAE;SAC5I;KACF;IAED,MAAM,EAAE;QACN,QAAQ,EAAE;YACR,oBAAoB;YACpB,sBAAsB;YACtB,YAAY;YACZ,WAAW;YACX,WAAW;YACX,mBAAmB;YACnB,eAAe;YACf,eAAe;YACf,cAAc;YACd,sBAAsB;YACtB,mBAAmB;YACnB,kBAAkB;YAClB,aAAa;SACd;QACD,YAAY,EAAE;YACZ,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,aAAa,EAAE,CAAC,SAAS,EAAE,OAAO,CAAC,EAAE;SAC5E;KACF;IAED,aAAa,EAAE;QACb,eAAe,EAAE,EAAE;QACnB,oBAAoB,EAClB,6KAA6K;QAC/K,eAAe,EAAE;YACf,yCAAyC;YACzC,gFAAgF;SACjF;KACF;IAED,QAAQ,EAAE;QACR,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,uBAAuB,EAAE,OAAO,EAAE,gBAAgB,EAAE;QAChF,EAAE,KAAK,EAAE,aAAa,EAAE,MAAM,EAAE,2BAA2B,EAAE,OAAO,EAAE,oBAAoB,EAAE;QAC5F,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,6BAA6B,EAAE,OAAO,EAAE,cAAc,EAAE;QAClF,EAAE,KAAK,EAAE,qBAAqB,EAAE,MAAM,EAAE,sBAAsB,EAAE,OAAO,EAAE,4BAA4B,EAAE;KACxG;IAED,YAAY,EAAE;QACZ;YACE,KAAK,EAAE,sBAAsB;YAC7B,GAAG,EAAE,sDAAsD;YAC3D,UAAU,EAAE,2EAA2E;SACxF;QACD;YACE,KAAK,EAAE,gCAAgC;YACvC,GAAG,EAAE,qFAAqF;YAC1F,UAAU,EAAE,qBAAqB;SAClC;KACF;IAED,QAAQ,EAAE;QACR,WAAW,EAAE,KAAK;QAClB,cAAc,EAAE,KAAK;QACrB,QAAQ,EAAE,KAAK;QACf,iBAAiB,EAAE,KAAK;KACzB;CACF,CAAA"}
@@ -0,0 +1,16 @@
1
+ export type QuoteSize = 'default' | 'large';
2
+ export interface QuoteProps {
3
+ quote: string;
4
+ attribution?: {
5
+ name: string;
6
+ role?: string;
7
+ avatar?: {
8
+ url: string;
9
+ alt: string;
10
+ };
11
+ };
12
+ size?: QuoteSize;
13
+ className?: string;
14
+ }
15
+ export declare function Quote({ quote, attribution, size, className }: QuoteProps): import("react/jsx-runtime").JSX.Element;
16
+ //# sourceMappingURL=Quote.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Quote.d.ts","sourceRoot":"","sources":["../../../src/components/Quote/Quote.tsx"],"names":[],"mappings":"AAGA,MAAM,MAAM,SAAS,GAAG,SAAS,GAAG,OAAO,CAAA;AAE3C,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAA;IACb,WAAW,CAAC,EAAE;QACZ,IAAI,EAAE,MAAM,CAAA;QACZ,IAAI,CAAC,EAAE,MAAM,CAAA;QACb,MAAM,CAAC,EAAE;YAAE,GAAG,EAAE,MAAM,CAAC;YAAC,GAAG,EAAE,MAAM,CAAA;SAAE,CAAA;KACtC,CAAA;IACD,IAAI,CAAC,EAAE,SAAS,CAAA;IAChB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED,wBAAgB,KAAK,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,IAAgB,EAAE,SAAS,EAAE,EAAE,UAAU,2CAuBpF"}
@@ -0,0 +1,7 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { clsx } from 'clsx';
3
+ import styles from './Quote.module.css';
4
+ export function Quote({ quote, attribution, size = 'default', className }) {
5
+ return (_jsxs("figure", { className: clsx(styles.figure, styles[size], className), children: [_jsx("blockquote", { className: styles.quote, children: _jsx("p", { children: quote }) }), attribution ? (_jsxs("figcaption", { className: styles.attribution, children: [attribution.avatar ? (_jsx("img", { src: attribution.avatar.url, alt: attribution.avatar.alt, className: styles.avatar })) : null, _jsx("span", { className: styles.name, children: attribution.name }), attribution.role ? (_jsx("span", { className: styles.role, children: attribution.role })) : null] })) : null] }));
6
+ }
7
+ //# sourceMappingURL=Quote.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Quote.js","sourceRoot":"","sources":["../../../src/components/Quote/Quote.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAC3B,OAAO,MAAM,MAAM,oBAAoB,CAAA;AAevC,MAAM,UAAU,KAAK,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,IAAI,GAAG,SAAS,EAAE,SAAS,EAAc;IACnF,OAAO,CACL,kBAAQ,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,EAAE,SAAS,CAAC,aAC7D,qBAAY,SAAS,EAAE,MAAM,CAAC,KAAK,YACjC,sBAAI,KAAK,GAAK,GACH,EACZ,WAAW,CAAC,CAAC,CAAC,CACb,sBAAY,SAAS,EAAE,MAAM,CAAC,WAAW,aACtC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,CACpB,cACE,GAAG,EAAE,WAAW,CAAC,MAAM,CAAC,GAAG,EAC3B,GAAG,EAAE,WAAW,CAAC,MAAM,CAAC,GAAG,EAC3B,SAAS,EAAE,MAAM,CAAC,MAAM,GACxB,CACH,CAAC,CAAC,CAAC,IAAI,EACR,eAAM,SAAS,EAAE,MAAM,CAAC,IAAI,YAAG,WAAW,CAAC,IAAI,GAAQ,EACtD,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,CAClB,eAAM,SAAS,EAAE,MAAM,CAAC,IAAI,YAAG,WAAW,CAAC,IAAI,GAAQ,CACxD,CAAC,CAAC,CAAC,IAAI,IACG,CACd,CAAC,CAAC,CAAC,IAAI,IACD,CACV,CAAA;AACH,CAAC"}
@@ -0,0 +1,3 @@
1
+ export { Quote, type QuoteProps, type QuoteSize } from './Quote.js';
2
+ export { contract as quoteContract } from './Quote.contract.js';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/Quote/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,KAAK,UAAU,EAAE,KAAK,SAAS,EAAE,MAAM,YAAY,CAAA;AACnE,OAAO,EAAE,QAAQ,IAAI,aAAa,EAAE,MAAM,qBAAqB,CAAA"}
@@ -0,0 +1,3 @@
1
+ export { Quote } from './Quote.js';
2
+ export { contract as quoteContract } from './Quote.contract.js';
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/components/Quote/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAmC,MAAM,YAAY,CAAA;AACnE,OAAO,EAAE,QAAQ,IAAI,aAAa,EAAE,MAAM,qBAAqB,CAAA"}
@@ -0,0 +1,3 @@
1
+ import type { ComponentContract } from '@forumone/throughline-design-contract';
2
+ export declare const contract: ComponentContract;
3
+ //# sourceMappingURL=SectionIntro.contract.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SectionIntro.contract.d.ts","sourceRoot":"","sources":["../../../src/components/SectionIntro/SectionIntro.contract.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,uCAAuC,CAAA;AAE9E,eAAO,MAAM,QAAQ,EAAE,iBAyGtB,CAAA"}
@@ -0,0 +1,97 @@
1
+ export const contract = {
2
+ name: 'SectionIntro',
3
+ category: 'section',
4
+ description: 'A section opener that establishes what the next block of content is about without competing with the page hero.',
5
+ intent: 'Introduce a new section inside a page. Use when you need an h2-level heading with optional eyebrow and supporting body copy, such as "Our approach", "Recent work", or "What we believe". Pairs with any content block below it.',
6
+ composition: {
7
+ placement: ['section'],
8
+ maxPerPage: null,
9
+ requiredSiblings: [],
10
+ forbiddenAdjacent: ['SectionIntro'],
11
+ },
12
+ content: {
13
+ fields: [
14
+ {
15
+ name: 'eyebrow',
16
+ type: 'text',
17
+ required: false,
18
+ maxLength: 40,
19
+ constraints: 'Short kicker label above the headline',
20
+ },
21
+ {
22
+ name: 'headline',
23
+ type: 'text',
24
+ required: true,
25
+ maxLength: 100,
26
+ constraints: 'Sentence case; scannable; reads like a chapter title',
27
+ },
28
+ {
29
+ name: 'body',
30
+ type: 'text',
31
+ required: false,
32
+ maxLength: 240,
33
+ constraints: 'One or two sentences that set up the section',
34
+ },
35
+ ],
36
+ variants: [
37
+ {
38
+ name: 'start',
39
+ description: 'Left-aligned',
40
+ whenToUse: 'Default — pairs with left-aligned content blocks below',
41
+ },
42
+ {
43
+ name: 'center',
44
+ description: 'Center-aligned',
45
+ whenToUse: 'Landing pages and marketing sections where the intro anchors a centered layout',
46
+ },
47
+ ],
48
+ },
49
+ tokens: {
50
+ consumes: [
51
+ 'color.text.primary',
52
+ 'color.text.secondary',
53
+ 'spacing.container',
54
+ 'spacing.3',
55
+ 'spacing.2',
56
+ 'font.size.3xl',
57
+ 'font.size.lg',
58
+ 'font.size.sm',
59
+ 'font.weight.semibold',
60
+ 'line.height.snug',
61
+ 'line.height.relaxed',
62
+ 'letter.spacing.wide',
63
+ ],
64
+ },
65
+ accessibility: {
66
+ role: 'region',
67
+ keyboardSupport: [],
68
+ screenReaderBehavior: 'The headline is announced as an h2 element. The eyebrow is supplementary text read before the headline. No interactive controls.',
69
+ contentWarnings: [
70
+ 'Do not use SectionIntro before Hero on the same page — the page must start with a single h1',
71
+ ],
72
+ },
73
+ examples: [
74
+ { label: 'Default', intent: 'Introduce a section inside a content page', storyId: 'section-intro--default' },
75
+ { label: 'Centered', intent: 'Anchor a centered marketing section', storyId: 'section-intro--centered' },
76
+ { label: 'Headline only', intent: 'Minimal section divider with just a heading', storyId: 'section-intro--headline-only' },
77
+ ],
78
+ antiExamples: [
79
+ {
80
+ label: 'Using SectionIntro as the page opener',
81
+ why: 'SectionIntro renders h2; a page should begin with an h1 for accessibility and SEO',
82
+ useInstead: 'Hero',
83
+ },
84
+ {
85
+ label: 'Stacking two SectionIntros with no content between them',
86
+ why: 'Creates a visual and semantic duplicate that signals nothing new',
87
+ useInstead: 'Merge into a single SectionIntro with a longer body',
88
+ },
89
+ ],
90
+ behavior: {
91
+ fetchesData: false,
92
+ hasClientState: false,
93
+ animates: false,
94
+ requiresAnalytics: false,
95
+ },
96
+ };
97
+ //# sourceMappingURL=SectionIntro.contract.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SectionIntro.contract.js","sourceRoot":"","sources":["../../../src/components/SectionIntro/SectionIntro.contract.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,QAAQ,GAAsB;IACzC,IAAI,EAAE,cAAc;IACpB,QAAQ,EAAE,SAAS;IACnB,WAAW,EACT,iHAAiH;IACnH,MAAM,EACJ,kOAAkO;IAEpO,WAAW,EAAE;QACX,SAAS,EAAE,CAAC,SAAS,CAAC;QACtB,UAAU,EAAE,IAAI;QAChB,gBAAgB,EAAE,EAAE;QACpB,iBAAiB,EAAE,CAAC,cAAc,CAAC;KACpC;IAED,OAAO,EAAE;QACP,MAAM,EAAE;YACN;gBACE,IAAI,EAAE,SAAS;gBACf,IAAI,EAAE,MAAM;gBACZ,QAAQ,EAAE,KAAK;gBACf,SAAS,EAAE,EAAE;gBACb,WAAW,EAAE,uCAAuC;aACrD;YACD;gBACE,IAAI,EAAE,UAAU;gBAChB,IAAI,EAAE,MAAM;gBACZ,QAAQ,EAAE,IAAI;gBACd,SAAS,EAAE,GAAG;gBACd,WAAW,EAAE,sDAAsD;aACpE;YACD;gBACE,IAAI,EAAE,MAAM;gBACZ,IAAI,EAAE,MAAM;gBACZ,QAAQ,EAAE,KAAK;gBACf,SAAS,EAAE,GAAG;gBACd,WAAW,EAAE,8CAA8C;aAC5D;SACF;QACD,QAAQ,EAAE;YACR;gBACE,IAAI,EAAE,OAAO;gBACb,WAAW,EAAE,cAAc;gBAC3B,SAAS,EAAE,wDAAwD;aACpE;YACD;gBACE,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,gBAAgB;gBAC7B,SAAS,EAAE,gFAAgF;aAC5F;SACF;KACF;IAED,MAAM,EAAE;QACN,QAAQ,EAAE;YACR,oBAAoB;YACpB,sBAAsB;YACtB,mBAAmB;YACnB,WAAW;YACX,WAAW;YACX,eAAe;YACf,cAAc;YACd,cAAc;YACd,sBAAsB;YACtB,kBAAkB;YAClB,qBAAqB;YACrB,qBAAqB;SACtB;KACF;IAED,aAAa,EAAE;QACb,IAAI,EAAE,QAAQ;QACd,eAAe,EAAE,EAAE;QACnB,oBAAoB,EAClB,kIAAkI;QACpI,eAAe,EAAE;YACf,6FAA6F;SAC9F;KACF;IAED,QAAQ,EAAE;QACR,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,2CAA2C,EAAE,OAAO,EAAE,wBAAwB,EAAE;QAC5G,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,qCAAqC,EAAE,OAAO,EAAE,yBAAyB,EAAE;QACxG,EAAE,KAAK,EAAE,eAAe,EAAE,MAAM,EAAE,6CAA6C,EAAE,OAAO,EAAE,8BAA8B,EAAE;KAC3H;IAED,YAAY,EAAE;QACZ;YACE,KAAK,EAAE,uCAAuC;YAC9C,GAAG,EAAE,mFAAmF;YACxF,UAAU,EAAE,MAAM;SACnB;QACD;YACE,KAAK,EAAE,yDAAyD;YAChE,GAAG,EAAE,kEAAkE;YACvE,UAAU,EAAE,qDAAqD;SAClE;KACF;IAED,QAAQ,EAAE;QACR,WAAW,EAAE,KAAK;QAClB,cAAc,EAAE,KAAK;QACrB,QAAQ,EAAE,KAAK;QACf,iBAAiB,EAAE,KAAK;KACzB;CACF,CAAA"}
@@ -0,0 +1,10 @@
1
+ export type SectionIntroAlignment = 'start' | 'center';
2
+ export interface SectionIntroProps {
3
+ eyebrow?: string;
4
+ headline: string;
5
+ body?: string;
6
+ alignment?: SectionIntroAlignment;
7
+ className?: string;
8
+ }
9
+ export declare function SectionIntro({ eyebrow, headline, body, alignment, className, }: SectionIntroProps): import("react/jsx-runtime").JSX.Element;
10
+ //# sourceMappingURL=SectionIntro.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SectionIntro.d.ts","sourceRoot":"","sources":["../../../src/components/SectionIntro/SectionIntro.tsx"],"names":[],"mappings":"AAGA,MAAM,MAAM,qBAAqB,GAAG,OAAO,GAAG,QAAQ,CAAA;AAEtD,MAAM,WAAW,iBAAiB;IAChC,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,MAAM,CAAA;IAChB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,SAAS,CAAC,EAAE,qBAAqB,CAAA;IACjC,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED,wBAAgB,YAAY,CAAC,EAC3B,OAAO,EACP,QAAQ,EACR,IAAI,EACJ,SAAmB,EACnB,SAAS,GACV,EAAE,iBAAiB,2CAQnB"}
@@ -0,0 +1,7 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { clsx } from 'clsx';
3
+ import styles from './SectionIntro.module.css';
4
+ export function SectionIntro({ eyebrow, headline, body, alignment = 'start', className, }) {
5
+ return (_jsxs("header", { className: clsx(styles.intro, styles[alignment], className), children: [eyebrow ? _jsx("p", { className: styles.eyebrow, children: eyebrow }) : null, _jsx("h2", { className: styles.headline, children: headline }), body ? _jsx("p", { className: styles.body, children: body }) : null] }));
6
+ }
7
+ //# sourceMappingURL=SectionIntro.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SectionIntro.js","sourceRoot":"","sources":["../../../src/components/SectionIntro/SectionIntro.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAC3B,OAAO,MAAM,MAAM,2BAA2B,CAAA;AAY9C,MAAM,UAAU,YAAY,CAAC,EAC3B,OAAO,EACP,QAAQ,EACR,IAAI,EACJ,SAAS,GAAG,OAAO,EACnB,SAAS,GACS;IAClB,OAAO,CACL,kBAAQ,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,SAAS,CAAC,EAAE,SAAS,CAAC,aAChE,OAAO,CAAC,CAAC,CAAC,YAAG,SAAS,EAAE,MAAM,CAAC,OAAO,YAAG,OAAO,GAAK,CAAC,CAAC,CAAC,IAAI,EAC7D,aAAI,SAAS,EAAE,MAAM,CAAC,QAAQ,YAAG,QAAQ,GAAM,EAC9C,IAAI,CAAC,CAAC,CAAC,YAAG,SAAS,EAAE,MAAM,CAAC,IAAI,YAAG,IAAI,GAAK,CAAC,CAAC,CAAC,IAAI,IAC7C,CACV,CAAA;AACH,CAAC"}
@@ -0,0 +1,3 @@
1
+ export { SectionIntro, type SectionIntroProps, type SectionIntroAlignment } from './SectionIntro.js';
2
+ export { contract as sectionIntroContract } from './SectionIntro.contract.js';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/SectionIntro/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,KAAK,iBAAiB,EAAE,KAAK,qBAAqB,EAAE,MAAM,mBAAmB,CAAA;AACpG,OAAO,EAAE,QAAQ,IAAI,oBAAoB,EAAE,MAAM,4BAA4B,CAAA"}
@@ -0,0 +1,3 @@
1
+ export { SectionIntro } from './SectionIntro.js';
2
+ export { contract as sectionIntroContract } from './SectionIntro.contract.js';
3
+ //# sourceMappingURL=index.js.map