@usefragments/ui 1.1.1 → 1.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 (141) hide show
  1. package/dist/assets/ui.css +327 -274
  2. package/dist/components/Checkbox/Checkbox.module.scss.cjs +11 -11
  3. package/dist/components/Checkbox/Checkbox.module.scss.js +11 -11
  4. package/dist/components/Chip/Chip.module.scss.cjs +15 -15
  5. package/dist/components/Chip/Chip.module.scss.js +15 -15
  6. package/dist/components/Combobox/index.cjs +106 -9
  7. package/dist/components/Combobox/index.d.ts.map +1 -1
  8. package/dist/components/Combobox/index.js +106 -9
  9. package/dist/components/DataTable/DataTable.module.scss.cjs +37 -34
  10. package/dist/components/DataTable/DataTable.module.scss.js +37 -34
  11. package/dist/components/Main/Main.module.scss.cjs +26 -0
  12. package/dist/components/Main/Main.module.scss.js +26 -0
  13. package/dist/components/Main/index.cjs +128 -0
  14. package/dist/components/Main/index.d.ts +22 -0
  15. package/dist/components/Main/index.d.ts.map +1 -0
  16. package/dist/components/Main/index.js +111 -0
  17. package/dist/components/Table/Table.module.scss.cjs +19 -19
  18. package/dist/components/Table/Table.module.scss.js +19 -19
  19. package/dist/components/TableOfContents/TableOfContents.module.scss.cjs +15 -15
  20. package/dist/components/TableOfContents/TableOfContents.module.scss.js +15 -15
  21. package/dist/components/TableOfContents/index.cjs +22 -42
  22. package/dist/components/TableOfContents/index.d.ts +3 -3
  23. package/dist/components/TableOfContents/index.d.ts.map +1 -1
  24. package/dist/components/TableOfContents/index.js +22 -42
  25. package/dist/index.cjs +87 -85
  26. package/dist/index.d.ts +1 -0
  27. package/dist/index.d.ts.map +1 -1
  28. package/dist/index.js +2 -0
  29. package/fragments.json +1 -1
  30. package/package.json +7 -2
  31. package/src/components/Checkbox/Checkbox.contract.json +5 -24
  32. package/src/components/Checkbox/Checkbox.module.scss +4 -2
  33. package/src/components/Chip/Chip.contract.json +11 -28
  34. package/src/components/Chip/Chip.module.scss +21 -45
  35. package/src/components/Combobox/Combobox.contract.json +6 -24
  36. package/src/components/Combobox/index.tsx +132 -6
  37. package/src/components/DataTable/DataTable.module.scss +31 -8
  38. package/src/components/Main/Main.contract.json +79 -0
  39. package/src/components/Main/Main.module.scss +31 -0
  40. package/src/components/Main/index.tsx +124 -0
  41. package/src/components/Table/Table.module.scss +22 -5
  42. package/src/components/TableOfContents/TableOfContents.contract.json +6 -16
  43. package/src/components/TableOfContents/TableOfContents.module.scss +10 -13
  44. package/src/components/TableOfContents/index.tsx +27 -38
  45. package/src/index.ts +3 -0
  46. package/src/tokens/_component-properties.scss +1 -0
  47. package/dist/components/Cloud/DashboardLayoutPrototypes.shared.d.ts +0 -33
  48. package/dist/components/Cloud/DashboardLayoutPrototypes.shared.d.ts.map +0 -1
  49. package/dist/components/Cloud/DashboardLayoutPrototypes.shell.d.ts +0 -11
  50. package/dist/components/Cloud/DashboardLayoutPrototypes.shell.d.ts.map +0 -1
  51. package/dist/components/Cloud/PullRequestsPrototypes.content.d.ts +0 -5
  52. package/dist/components/Cloud/PullRequestsPrototypes.content.d.ts.map +0 -1
  53. package/dist/components/Cloud/PullRequestsPrototypes.detail-panels.d.ts +0 -4
  54. package/dist/components/Cloud/PullRequestsPrototypes.detail-panels.d.ts.map +0 -1
  55. package/dist/components/Cloud/PullRequestsPrototypes.detail.d.ts +0 -3
  56. package/dist/components/Cloud/PullRequestsPrototypes.detail.d.ts.map +0 -1
  57. package/dist/components/Cloud/PullRequestsPrototypes.id-data.d.ts +0 -86
  58. package/dist/components/Cloud/PullRequestsPrototypes.id-data.d.ts.map +0 -1
  59. package/dist/components/Cloud/PullRequestsPrototypes.id-page.d.ts +0 -2
  60. package/dist/components/Cloud/PullRequestsPrototypes.id-page.d.ts.map +0 -1
  61. package/src/components/Accordion/Accordion.stories.tsx +0 -106
  62. package/src/components/Alert/Alert.stories.tsx +0 -119
  63. package/src/components/AppShell/AppShell.stories.tsx +0 -156
  64. package/src/components/Avatar/Avatar.stories.tsx +0 -74
  65. package/src/components/Badge/Badge.stories.tsx +0 -92
  66. package/src/components/BentoGrid/BentoGrid.stories.tsx +0 -98
  67. package/src/components/Box/Box.stories.tsx +0 -150
  68. package/src/components/Breadcrumbs/Breadcrumbs.stories.tsx +0 -87
  69. package/src/components/Button/Button.stories.tsx +0 -103
  70. package/src/components/ButtonGroup/ButtonGroup.stories.tsx +0 -97
  71. package/src/components/Card/Card.stories.tsx +0 -144
  72. package/src/components/Chart/Chart.stories.tsx +0 -119
  73. package/src/components/Checkbox/Checkbox.stories.tsx +0 -68
  74. package/src/components/Chip/Chip.stories.tsx +0 -70
  75. package/src/components/Cloud/CloudGovernanceShell.module.scss +0 -88
  76. package/src/components/Cloud/CloudGovernanceShell.stories.tsx +0 -446
  77. package/src/components/Cloud/ControlSizing.module.scss +0 -49
  78. package/src/components/Cloud/ControlSizing.stories.tsx +0 -238
  79. package/src/components/Cloud/DashboardLayoutPrototypes.module.scss +0 -462
  80. package/src/components/Cloud/DashboardLayoutPrototypes.shared.tsx +0 -375
  81. package/src/components/Cloud/DashboardLayoutPrototypes.shell.tsx +0 -147
  82. package/src/components/Cloud/DashboardLayoutPrototypes.stories.tsx +0 -328
  83. package/src/components/Cloud/PullRequestsPrototypes.content.tsx +0 -283
  84. package/src/components/Cloud/PullRequestsPrototypes.detail-panels.tsx +0 -381
  85. package/src/components/Cloud/PullRequestsPrototypes.detail.tsx +0 -204
  86. package/src/components/Cloud/PullRequestsPrototypes.id-data.ts +0 -395
  87. package/src/components/Cloud/PullRequestsPrototypes.id-page.tsx +0 -349
  88. package/src/components/Cloud/PullRequestsPrototypes.stories.tsx +0 -81
  89. package/src/components/CodeBlock/CodeBlock.stories.tsx +0 -147
  90. package/src/components/Collapsible/Collapsible.stories.tsx +0 -94
  91. package/src/components/ColorPicker/ColorPicker.stories.tsx +0 -74
  92. package/src/components/Combobox/Combobox.stories.tsx +0 -133
  93. package/src/components/Command/Command.stories.tsx +0 -102
  94. package/src/components/ConversationList/ConversationList.stories.tsx +0 -93
  95. package/src/components/DataTable/DataTable.stories.tsx +0 -129
  96. package/src/components/DatePicker/DatePicker.stories.tsx +0 -129
  97. package/src/components/Dialog/Dialog.stories.tsx +0 -154
  98. package/src/components/Drawer/Drawer.stories.tsx +0 -144
  99. package/src/components/Editor/Editor.stories.tsx +0 -99
  100. package/src/components/EmptyState/EmptyState.stories.tsx +0 -97
  101. package/src/components/Field/Field.stories.tsx +0 -109
  102. package/src/components/Fieldset/Fieldset.stories.tsx +0 -116
  103. package/src/components/Form/Form.stories.tsx +0 -142
  104. package/src/components/Grid/Grid.stories.tsx +0 -125
  105. package/src/components/Header/Header.stories.tsx +0 -133
  106. package/src/components/Icon/Icon.stories.tsx +0 -80
  107. package/src/components/IconButton/IconButton.stories.tsx +0 -78
  108. package/src/components/Image/Image.stories.tsx +0 -109
  109. package/src/components/Input/Input.stories.tsx +0 -104
  110. package/src/components/Link/Link.stories.tsx +0 -67
  111. package/src/components/List/List.stories.tsx +0 -95
  112. package/src/components/Listbox/Listbox.stories.tsx +0 -81
  113. package/src/components/Loading/Loading.stories.tsx +0 -69
  114. package/src/components/Markdown/Markdown.stories.tsx +0 -75
  115. package/src/components/Menu/Menu.stories.tsx +0 -113
  116. package/src/components/Message/Message.stories.tsx +0 -85
  117. package/src/components/NavigationMenu/NavigationMenu.stories.tsx +0 -161
  118. package/src/components/Pagination/Pagination.stories.tsx +0 -81
  119. package/src/components/Popover/Popover.stories.tsx +0 -152
  120. package/src/components/Progress/Progress.stories.tsx +0 -64
  121. package/src/components/Prompt/Prompt.stories.tsx +0 -93
  122. package/src/components/RadioGroup/RadioGroup.stories.tsx +0 -107
  123. package/src/components/ScrollArea/ScrollArea.stories.tsx +0 -97
  124. package/src/components/Select/Select.stories.tsx +0 -127
  125. package/src/components/Separator/Separator.stories.tsx +0 -84
  126. package/src/components/Sidebar/Sidebar.stories.tsx +0 -122
  127. package/src/components/Skeleton/Skeleton.stories.tsx +0 -80
  128. package/src/components/Slider/Slider.stories.tsx +0 -73
  129. package/src/components/Stack/Stack.stories.tsx +0 -73
  130. package/src/components/Switch/Switch.stories.tsx +0 -59
  131. package/src/components/Table/Table.stories.tsx +0 -219
  132. package/src/components/TableOfContents/TableOfContents.stories.tsx +0 -120
  133. package/src/components/Tabs/Tabs.stories.tsx +0 -136
  134. package/src/components/Text/Text.stories.tsx +0 -133
  135. package/src/components/Textarea/Textarea.stories.tsx +0 -107
  136. package/src/components/Theme/Theme.stories.tsx +0 -95
  137. package/src/components/ThinkingIndicator/ThinkingIndicator.stories.tsx +0 -85
  138. package/src/components/Toast/Toast.stories.tsx +0 -91
  139. package/src/components/ToggleGroup/ToggleGroup.stories.tsx +0 -114
  140. package/src/components/Tooltip/Tooltip.stories.tsx +0 -95
  141. package/src/components/VisuallyHidden/VisuallyHidden.stories.tsx +0 -78
@@ -3,7 +3,10 @@
3
3
 
4
4
  .wrapper {
5
5
  --fui-data-table-bg: var(--fui-table-bg, var(--fui-bg-elevated, #{$fui-bg-elevated}));
6
- --fui-data-table-header-bg: var(--fui-table-header-bg, color-mix(in srgb, var(--fui-text-primary, #{$fui-text-primary}) 5%, transparent));
6
+ --fui-data-table-header-bg: var(
7
+ --fui-table-header-bg,
8
+ color-mix(in srgb, var(--fui-text-primary, #{$fui-text-primary}) 5%, transparent)
9
+ );
7
10
 
8
11
  overflow-x: auto;
9
12
  -webkit-overflow-scrolling: touch;
@@ -69,7 +72,10 @@
69
72
  user-select: none;
70
73
  // Opaque so the sticky header doesn't let rows bleed through on scroll,
71
74
  // while inheriting the table surface instead of forcing the page background.
72
- background: var(--fui-data-table-header-bg);
75
+ background: var(
76
+ --fui-data-table-header-bg,
77
+ var(--fui-data-table-bg, var(--fui-bg-primary, #{$fui-bg-primary}))
78
+ );
73
79
 
74
80
  &:first-child {
75
81
  border-top-left-radius: var(--fui-radius-md, $fui-radius-md);
@@ -142,6 +148,10 @@
142
148
 
143
149
  // Body
144
150
  .tbody {
151
+ .td {
152
+ padding-top: var(--fui-space-2, $fui-space-2);
153
+ padding-bottom: var(--fui-space-2, $fui-space-2);
154
+ }
145
155
  }
146
156
 
147
157
  .row {
@@ -174,11 +184,18 @@
174
184
  }
175
185
 
176
186
  .selected {
177
- background-color: var(--fui-table-row-selected-bg, color-mix(in srgb, var(--fui-text-primary, #{$fui-text-primary}) 8%, transparent));
178
- box-shadow: inset 1px 0 0 var(--fui-table-row-selected-border, var(--fui-border-strong, #{$fui-border-strong}));
187
+ background-color: var(
188
+ --fui-table-row-selected-bg,
189
+ color-mix(in srgb, var(--fui-text-primary, #{$fui-text-primary}) 8%, transparent)
190
+ );
191
+ box-shadow: inset 1px 0 0
192
+ var(--fui-table-row-selected-border, var(--fui-border-strong, #{$fui-border-strong}));
179
193
 
180
194
  &:hover {
181
- background-color: var(--fui-table-row-selected-bg, color-mix(in srgb, var(--fui-text-primary, #{$fui-text-primary}) 10%, transparent));
195
+ background-color: var(
196
+ --fui-table-row-selected-bg,
197
+ color-mix(in srgb, var(--fui-text-primary, #{$fui-text-primary}) 10%, transparent)
198
+ );
182
199
  }
183
200
  }
184
201
 
@@ -204,10 +221,16 @@
204
221
  }
205
222
 
206
223
  .selected {
207
- background-color: var(--fui-table-row-selected-bg, color-mix(in srgb, var(--fui-text-primary, #{$fui-text-primary}) 8%, transparent));
224
+ background-color: var(
225
+ --fui-table-row-selected-bg,
226
+ color-mix(in srgb, var(--fui-text-primary, #{$fui-text-primary}) 8%, transparent)
227
+ );
208
228
 
209
229
  &:hover {
210
- background-color: var(--fui-table-row-selected-bg, color-mix(in srgb, var(--fui-text-primary, #{$fui-text-primary}) 10%, transparent));
230
+ background-color: var(
231
+ --fui-table-row-selected-bg,
232
+ color-mix(in srgb, var(--fui-text-primary, #{$fui-text-primary}) 10%, transparent)
233
+ );
211
234
  }
212
235
  }
213
236
  }
@@ -216,7 +239,7 @@
216
239
  .bordered {
217
240
  border: 1px solid var(--fui-table-border, var(--fui-border, #{$fui-border}));
218
241
  border-radius: var(--fui-radius-md, $fui-radius-md);
219
- background: var(--fui-data-table-bg);
242
+ background: var(--fui-data-table-bg, var(--fui-bg-primary, #{$fui-bg-primary}));
220
243
  overflow: hidden;
221
244
  }
222
245
 
@@ -0,0 +1,79 @@
1
+ {
2
+ "$schema": "https://usefragments.com/schemas/contract.v1.json",
3
+ "name": "Main",
4
+ "description": "Canonical page composition owning gutter, measure, and vertical rhythm.",
5
+ "category": "layout",
6
+ "tags": ["main", "page", "layout", "compound"],
7
+ "status": "stable",
8
+ "sourcePath": "src/components/Main/index.tsx",
9
+ "exportName": "Main",
10
+ "propsSummary": [
11
+ "children: node (required)",
12
+ "measure: full|narrow (default: full)",
13
+ "as: semantic element (default: main)"
14
+ ],
15
+ "props": {
16
+ "children": {
17
+ "type": "node",
18
+ "description": "Page regions composed from Main.Header, Main.Description, Main.Content, and Main.Footer",
19
+ "required": true
20
+ },
21
+ "measure": {
22
+ "type": "enum",
23
+ "description": "Maximum width applied to the page composition",
24
+ "default": "full",
25
+ "required": false,
26
+ "values": ["full", "narrow"]
27
+ },
28
+ "as": {
29
+ "type": "enum",
30
+ "description": "Semantic HTML element rendered by the root",
31
+ "default": "main",
32
+ "required": false,
33
+ "values": [
34
+ "div",
35
+ "section",
36
+ "nav",
37
+ "article",
38
+ "aside",
39
+ "header",
40
+ "footer",
41
+ "main",
42
+ "ul",
43
+ "ol"
44
+ ]
45
+ }
46
+ },
47
+ "usage": {
48
+ "when": ["Composing a page header, description, content, and footer"],
49
+ "whenNot": ["Application shell navigation (use AppShell)"],
50
+ "guidelines": [
51
+ "Use one Main gutter owner per page",
52
+ "Compose page regions with Main.Header, Main.Description, Main.Content, and Main.Footer"
53
+ ],
54
+ "accessibility": [
55
+ "Use the default main element unless an existing shell already owns the main landmark"
56
+ ]
57
+ },
58
+ "examples": [
59
+ {
60
+ "name": "Full Measure",
61
+ "description": "Page composition that uses the full available canvas",
62
+ "code": "<Main measure=\"full\">\n <Main.Header>Page statement</Main.Header>\n <Main.Description>Supporting page context.</Main.Description>\n <Main.Content>Page content</Main.Content>\n <Main.Footer>Page actions</Main.Footer>\n</Main>"
63
+ },
64
+ {
65
+ "name": "Narrow Measure",
66
+ "description": "Readable page composition constrained to the canonical 800px measure",
67
+ "code": "<Main measure=\"narrow\">\n <Main.Header>Settings</Main.Header>\n <Main.Description>Manage the workspace contract.</Main.Description>\n <Main.Content>Settings content</Main.Content>\n <Main.Footer>Save changes</Main.Footer>\n</Main>"
68
+ }
69
+ ],
70
+ "ai": {
71
+ "compositionPattern": "compound",
72
+ "subComponents": ["Header", "Description", "Content", "Footer"]
73
+ },
74
+ "provenance": {
75
+ "source": "manual",
76
+ "verified": true,
77
+ "frameworkSupport": "native"
78
+ }
79
+ }
@@ -0,0 +1,31 @@
1
+ @use "../../tokens/variables" as *;
2
+
3
+ $fui-main-measure-narrow: 57.143rem !default;
4
+
5
+ .root {
6
+ box-sizing: border-box;
7
+ width: 100%;
8
+ min-width: 0;
9
+ min-height: 100%;
10
+ margin-inline: auto;
11
+ padding: var(--fui-space-3, $fui-space-3);
12
+ }
13
+
14
+ .full {
15
+ max-width: none;
16
+ }
17
+
18
+ .narrow {
19
+ max-width: $fui-main-measure-narrow;
20
+ }
21
+
22
+ .header,
23
+ .description,
24
+ .content,
25
+ .footer {
26
+ min-width: 0;
27
+ }
28
+
29
+ .description {
30
+ max-width: 68ch;
31
+ }
@@ -0,0 +1,124 @@
1
+ import * as React from "react";
2
+ import { Stack, type StackProps } from "../Stack";
3
+ import styles from "./Main.module.scss";
4
+
5
+ export type MainMeasure = "full" | "narrow";
6
+
7
+ export interface MainProps extends Omit<StackProps, "as" | "children" | "direction" | "gap"> {
8
+ as?: StackProps["as"];
9
+ children: React.ReactNode;
10
+ /** Maximum readable width for the page content. */
11
+ measure?: MainMeasure;
12
+ }
13
+
14
+ export type MainRegionProps = StackProps;
15
+
16
+ function joinClasses(...classes: Array<string | false | undefined>) {
17
+ return classes.filter(Boolean).join(" ");
18
+ }
19
+
20
+ const MainRoot = React.forwardRef<HTMLElement, MainProps>(function MainRoot(
21
+ { as = "main", children, className, measure = "full", ...htmlProps },
22
+ ref
23
+ ) {
24
+ return (
25
+ <Stack
26
+ {...htmlProps}
27
+ ref={ref}
28
+ as={as}
29
+ direction="column"
30
+ gap="lg"
31
+ className={joinClasses(
32
+ styles.root,
33
+ measure === "narrow" ? styles.narrow : styles.full,
34
+ className
35
+ )}
36
+ data-main-measure={measure}
37
+ >
38
+ {children}
39
+ </Stack>
40
+ );
41
+ });
42
+
43
+ function MainHeader({
44
+ as = "header",
45
+ direction = "column",
46
+ gap = "sm",
47
+ className,
48
+ ...props
49
+ }: MainRegionProps) {
50
+ return (
51
+ <Stack
52
+ {...props}
53
+ as={as}
54
+ direction={direction}
55
+ gap={gap}
56
+ className={joinClasses(styles.header, className)}
57
+ />
58
+ );
59
+ }
60
+
61
+ function MainDescription({
62
+ as = "div",
63
+ direction = "column",
64
+ gap = "xs",
65
+ className,
66
+ ...props
67
+ }: MainRegionProps) {
68
+ return (
69
+ <Stack
70
+ {...props}
71
+ as={as}
72
+ direction={direction}
73
+ gap={gap}
74
+ className={joinClasses(styles.description, className)}
75
+ />
76
+ );
77
+ }
78
+
79
+ function MainContent({
80
+ as = "div",
81
+ direction = "column",
82
+ gap = "lg",
83
+ className,
84
+ ...props
85
+ }: MainRegionProps) {
86
+ return (
87
+ <Stack
88
+ {...props}
89
+ as={as}
90
+ direction={direction}
91
+ gap={gap}
92
+ className={joinClasses(styles.content, className)}
93
+ />
94
+ );
95
+ }
96
+
97
+ function MainFooter({
98
+ as = "footer",
99
+ direction = "row",
100
+ gap = "sm",
101
+ justify = "end",
102
+ wrap = true,
103
+ className,
104
+ ...props
105
+ }: MainRegionProps) {
106
+ return (
107
+ <Stack
108
+ {...props}
109
+ as={as}
110
+ direction={direction}
111
+ gap={gap}
112
+ justify={justify}
113
+ wrap={wrap}
114
+ className={joinClasses(styles.footer, className)}
115
+ />
116
+ );
117
+ }
118
+
119
+ export const Main = Object.assign(MainRoot, {
120
+ Header: MainHeader,
121
+ Description: MainDescription,
122
+ Content: MainContent,
123
+ Footer: MainFooter,
124
+ });
@@ -108,14 +108,24 @@
108
108
 
109
109
  // Body
110
110
  .tbody {
111
+ .td {
112
+ padding-top: var(--fui-space-2, $fui-space-2);
113
+ padding-bottom: var(--fui-space-2, $fui-space-2);
114
+ }
111
115
  }
112
116
 
113
117
  .row {
114
- --fui-table-row-base-bg: var(--fui-table-bg, var(--fui-main-bg, var(--fui-bg-primary, #{$fui-bg-primary})));
118
+ --fui-table-row-base-bg: var(
119
+ --fui-table-bg,
120
+ var(--fui-main-bg, var(--fui-bg-primary, #{$fui-bg-primary}))
121
+ );
115
122
  --fui-table-row-bg: var(--fui-table-row-base-bg);
116
123
 
117
124
  border-bottom: 1px solid var(--fui-table-border, var(--fui-border, #{$fui-border}));
118
- background-color: var(--fui-table-row-bg);
125
+ background-color: var(
126
+ --fui-table-row-bg,
127
+ var(--fui-table-row-base-bg, var(--fui-bg-primary, #{$fui-bg-primary}))
128
+ );
119
129
  transition: background-color var(--fui-transition-fast, $fui-transition-fast);
120
130
 
121
131
  &:last-child {
@@ -128,11 +138,18 @@
128
138
  }
129
139
 
130
140
  .selected {
131
- --fui-table-row-bg: var(--fui-table-row-selected-bg, color-mix(in srgb, var(--fui-text-primary, #{$fui-text-primary}) 8%, transparent));
132
- box-shadow: inset 1px 0 0 var(--fui-table-row-selected-border, var(--fui-border-strong, #{$fui-border-strong}));
141
+ --fui-table-row-bg: var(
142
+ --fui-table-row-selected-bg,
143
+ color-mix(in srgb, var(--fui-text-primary, #{$fui-text-primary}) 8%, transparent)
144
+ );
145
+ box-shadow: inset 1px 0 0
146
+ var(--fui-table-row-selected-border, var(--fui-border-strong, #{$fui-border-strong}));
133
147
 
134
148
  &:hover {
135
- --fui-table-row-bg: var(--fui-table-row-selected-bg, color-mix(in srgb, var(--fui-text-primary, #{$fui-text-primary}) 10%, transparent));
149
+ --fui-table-row-bg: var(
150
+ --fui-table-row-selected-bg,
151
+ color-mix(in srgb, var(--fui-text-primary, #{$fui-text-primary}) 10%, transparent)
152
+ );
136
153
  }
137
154
  }
138
155
 
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://usefragments.com/schemas/contract.v1.json",
3
3
  "name": "TableOfContents",
4
- "description": "Sticky sidebar navigation for long-form content or filterable lists. Renders heading links with a continuous hierarchy rail that branches in for nested groups and back out for parent items, with active-segment highlighting.",
4
+ "description": "Sticky sidebar navigation for long-form content or filterable lists. Renders a quiet, flush index with nested indentation and an ink-weight active state.",
5
5
  "category": "navigation",
6
6
  "tags": [
7
7
  "toc",
@@ -84,7 +84,7 @@
84
84
  },
85
85
  {
86
86
  "name": "Nested Groups",
87
- "description": "Filterable list grouped by category the hierarchy rail branches in for children and back out for the next parent item",
87
+ "description": "Filterable list grouped by category with clear nested indentation",
88
88
  "code": "<TableOfContents title=\"Components\">\n <TableOfContents.Item id=\"all\" active>All</TableOfContents.Item>\n <TableOfContents.Group label=\"Primitives\" trailing={<span>3</span>}>\n <TableOfContents.Item id=\"button\">Button</TableOfContents.Item>\n <TableOfContents.Item id=\"card\">Card</TableOfContents.Item>\n <TableOfContents.Item id=\"input\">Input</TableOfContents.Item>\n </TableOfContents.Group>\n <TableOfContents.Group label=\"Custom\" defaultOpen={false}>\n <TableOfContents.Item id=\"features\">Features</TableOfContents.Item>\n <TableOfContents.Item id=\"plans\">Plans</TableOfContents.Item>\n </TableOfContents.Group>\n</TableOfContents>"
89
89
  },
90
90
  {
@@ -126,7 +126,7 @@
126
126
  "hideTitle: boolean - hide the title",
127
127
  "label: string - aria-label for nav landmark",
128
128
  "TableOfContents.Item id: string - heading ID to link to",
129
- "TableOfContents.Item active: boolean - highlight as current (also paints the rail segment in accent)",
129
+ "TableOfContents.Item active: boolean - highlight the current item with ink and weight",
130
130
  "TableOfContents.Item indent: boolean - legacy depth=1 indent for flat lists; prefer Group for new code",
131
131
  "TableOfContents.Item leading/trailing: node - optional adornments before/after the label",
132
132
  "TableOfContents.Group label: node - header text for the group",
@@ -135,22 +135,12 @@
135
135
  "TableOfContents.Group trailing/leading: node - optional adornments on the group header row",
136
136
  "Forwards standard nav/anchor DOM props; TableOfContents.Item onClick can prevent default smooth scroll"
137
137
  ],
138
- "a11yRules": [
139
- "A11Y_NAV_LANDMARK",
140
- "A11Y_ARIA_CURRENT",
141
- "A11Y_ARIA_EXPANDED"
142
- ]
138
+ "a11yRules": ["A11Y_NAV_LANDMARK", "A11Y_ARIA_CURRENT", "A11Y_ARIA_EXPANDED"]
143
139
  },
144
140
  "ai": {
145
141
  "compositionPattern": "compound",
146
- "subComponents": [
147
- "Item",
148
- "Group"
149
- ],
150
- "requiredChildren": [
151
- "Item",
152
- "Group"
153
- ],
142
+ "subComponents": ["Item", "Group"],
143
+ "requiredChildren": ["Item", "Group"],
154
144
  "commonPatterns": [
155
145
  "<TableOfContents>{headings.map(h => <TableOfContents.Item key={h.id} id={h.id} active={activeId === h.id} indent={h.level === 3}>{h.text}</TableOfContents.Item>)}</TableOfContents>",
156
146
  "<TableOfContents>{groups.map(g => <TableOfContents.Group key={g.label} label={g.label} trailing={g.count}>{g.items.map(i => <TableOfContents.Item key={i.id} id={i.id} active={activeId === i.id}>{i.label}</TableOfContents.Item>)}</TableOfContents.Group>)}</TableOfContents>"
@@ -2,21 +2,17 @@
2
2
  @use "../../tokens/mixins" as *;
3
3
 
4
4
  // ============================================
5
- // Single-rail "snake" geometry
5
+ // Dormant single-rail geometry
6
6
  // ============================================
7
7
  //
8
- // All <li>s are siblings in one flat <ul>. Each carries data-depth, which
9
- // sets the X of its per-row rail (drawn as `::before`). At depth-0 depth-1
10
- // transitions an opening elbow is drawn via `::after` on the depth-1 item;
11
- // at depth-1 → depth-0 transitions a closing elbow is drawn via `::after`
12
- // on the depth-0 item. Active items paint their rail in accent; the curves
13
- // into and out of an active depth-1 also flip to accent so the section
14
- // reads as one continuous coloured snake.
8
+ // The public default is the quiet, flush index disabled below. These values
9
+ // retain the existing optional rail geometry without making its inset part of
10
+ // the default list contract.
15
11
 
16
12
  $rail-x-0: 7px;
17
13
  $rail-indent: 14px;
18
14
  $rail-x-1: 21px; // = $rail-x-0 + $rail-indent
19
- $rail-pad: 18px; // <ul> padding-left
15
+ $rail-pad: 18px; // optional rail inset; never default <ul> padding
20
16
  $rail-curve: 14px;
21
17
  $rail-thickness: 1px;
22
18
  $rail-active-thickness: 1px;
@@ -44,11 +40,13 @@ $rail-from-item-1: $rail-x-1 - $rail-pad; // 3px
44
40
  padding: 0 var(--fui-space-2, $fui-space-2);
45
41
  }
46
42
 
43
+ // Plain index (the design-system default, see below) draws no rail, so the
44
+ // list is flush — its links/group headers share the same inline inset as
45
+ // .title. A future rail variant must reinstate its own $rail-pad inset.
47
46
  .list {
48
47
  list-style: none;
49
48
  margin: 0;
50
49
  padding: 0;
51
- padding-left: $rail-pad;
52
50
  position: relative;
53
51
  display: flex;
54
52
  flex-direction: column;
@@ -210,9 +208,8 @@ $rail-from-item-1: $rail-x-1 - $rail-pad; // 3px
210
208
  }
211
209
  }
212
210
 
213
- // Depth-1 link sits to the right of the rail (which lives at x=3px from li edge).
214
- // Margin pushes the link's hover/active background past the rail so it doesn't
215
- // paint over the line. Reduced padding-left keeps the text in the same x-position.
211
+ // Depth-1 links carry the hierarchy indent while the top-level index remains
212
+ // flush with the title and group headers.
216
213
  [data-depth="1"] .link {
217
214
  margin-left: var(--fui-space-2, $fui-space-2);
218
215
  padding-left: $rail-indent;
@@ -1,8 +1,8 @@
1
- 'use client';
1
+ "use client";
2
2
 
3
- import * as React from 'react';
4
- import styles from './TableOfContents.module.scss';
5
- import { Text } from '../Text';
3
+ import * as React from "react";
4
+ import styles from "./TableOfContents.module.scss";
5
+ import { Text } from "../Text";
6
6
 
7
7
  // ============================================
8
8
  // Types
@@ -18,7 +18,10 @@ export interface TableOfContentsProps extends React.HTMLAttributes<HTMLElement>
18
18
  hideTitle?: boolean;
19
19
  }
20
20
 
21
- export interface TableOfContentsItemProps extends Omit<React.AnchorHTMLAttributes<HTMLAnchorElement>, 'children'> {
21
+ export interface TableOfContentsItemProps extends Omit<
22
+ React.AnchorHTMLAttributes<HTMLAnchorElement>,
23
+ "children"
24
+ > {
22
25
  children: React.ReactNode;
23
26
  /** The heading ID to link to */
24
27
  id: string;
@@ -89,14 +92,14 @@ function ChevronIcon() {
89
92
 
90
93
  function TableOfContentsRoot({
91
94
  children,
92
- label = 'Table of contents',
93
- title = 'On This Page',
95
+ label = "Table of contents",
96
+ title = "On This Page",
94
97
  hideTitle = false,
95
98
  className,
96
- 'aria-label': ariaLabel,
99
+ "aria-label": ariaLabel,
97
100
  ...htmlProps
98
101
  }: TableOfContentsProps) {
99
- const classes = [styles.root, className].filter(Boolean).join(' ');
102
+ const classes = [styles.root, className].filter(Boolean).join(" ");
100
103
 
101
104
  return (
102
105
  <nav {...htmlProps} aria-label={ariaLabel ?? label} className={classes}>
@@ -127,11 +130,7 @@ function TableOfContentsItem({
127
130
  const { depth } = React.useContext(TocContext);
128
131
  const effectiveDepth = depth > 0 ? depth : indent ? 1 : 0;
129
132
 
130
- const linkClasses = [
131
- styles.link,
132
- active && styles.active,
133
- className,
134
- ].filter(Boolean).join(' ');
133
+ const linkClasses = [styles.link, active && styles.active, className].filter(Boolean).join(" ");
135
134
 
136
135
  const handleClick = (e: React.MouseEvent<HTMLAnchorElement>) => {
137
136
  onClick?.(e);
@@ -140,23 +139,19 @@ function TableOfContentsItem({
140
139
  e.preventDefault();
141
140
  const el = document.getElementById(id);
142
141
  if (el) {
143
- el.scrollIntoView({ behavior: 'smooth' });
144
- window.history.replaceState(null, '', `#${id}`);
142
+ el.scrollIntoView({ behavior: "smooth" });
143
+ window.history.replaceState(null, "", `#${id}`);
145
144
  }
146
145
  };
147
146
 
148
147
  return (
149
- <li
150
- className={styles.item}
151
- data-depth={effectiveDepth}
152
- data-active={active || undefined}
153
- >
148
+ <li className={styles.item} data-depth={effectiveDepth} data-active={active || undefined}>
154
149
  <a
155
150
  {...htmlProps}
156
151
  href={`#${id}`}
157
152
  className={linkClasses}
158
153
  onClick={handleClick}
159
- aria-current={active ? 'location' : undefined}
154
+ aria-current={active ? "location" : undefined}
160
155
  >
161
156
  {leading != null && <span className={styles.leading}>{leading}</span>}
162
157
  <span className={styles.linkLabel}>{children}</span>
@@ -169,7 +164,7 @@ function TableOfContentsItem({
169
164
  function useControlledOpen(
170
165
  controlled: boolean | undefined,
171
166
  defaultValue: boolean,
172
- onChange: ((open: boolean) => void) | undefined,
167
+ onChange: ((open: boolean) => void) | undefined
173
168
  ): [boolean, (next: boolean) => void] {
174
169
  const [internal, setInternal] = React.useState(defaultValue);
175
170
  const isControlled = controlled !== undefined;
@@ -179,14 +174,14 @@ function useControlledOpen(
179
174
  if (!isControlled) setInternal(next);
180
175
  onChange?.(next);
181
176
  },
182
- [isControlled, onChange],
177
+ [isControlled, onChange]
183
178
  );
184
179
  return [value, setValue];
185
180
  }
186
181
 
187
- // Group renders a Fragment: its header <li> and its children become direct
188
- // siblings in the parent <ul>, which lets CSS adjacency selectors detect
189
- // depth transitions and draw the opening/closing elbows.
182
+ // Group renders a Fragment so its header <li> and children remain direct
183
+ // siblings in the parent <ul>. This preserves list semantics and depth-based
184
+ // indentation without adding a nested list inset.
190
185
  function TableOfContentsGroup({
191
186
  children,
192
187
  label,
@@ -209,7 +204,9 @@ function TableOfContentsGroup({
209
204
  styles.groupHeader,
210
205
  isToggleable && styles.groupHeaderInteractive,
211
206
  active && styles.groupHeaderActive,
212
- ].filter(Boolean).join(' ');
207
+ ]
208
+ .filter(Boolean)
209
+ .join(" ");
213
210
 
214
211
  const headerContent = (
215
212
  <>
@@ -226,11 +223,7 @@ function TableOfContentsGroup({
226
223
 
227
224
  return (
228
225
  <>
229
- <li
230
- className={styles.groupHeaderRow}
231
- data-depth={depth}
232
- data-active={active || undefined}
233
- >
226
+ <li className={styles.groupHeaderRow} data-depth={depth} data-active={active || undefined}>
234
227
  {isToggleable ? (
235
228
  <button
236
229
  type="button"
@@ -244,11 +237,7 @@ function TableOfContentsGroup({
244
237
  <div className={headerClasses}>{headerContent}</div>
245
238
  )}
246
239
  </li>
247
- {isOpen && (
248
- <TocContext.Provider value={{ depth: depth + 1 }}>
249
- {children}
250
- </TocContext.Provider>
251
- )}
240
+ {isOpen && <TocContext.Provider value={{ depth: depth + 1 }}>{children}</TocContext.Provider>}
252
241
  </>
253
242
  );
254
243
  }
package/src/index.ts CHANGED
@@ -389,6 +389,9 @@ export {
389
389
  type ResponsiveGap,
390
390
  } from "./components/Stack";
391
391
 
392
+ // Main
393
+ export { Main, type MainProps, type MainRegionProps, type MainMeasure } from "./components/Main";
394
+
392
395
  // Text
393
396
  export { Text, type TextProps } from "./components/Text";
394
397
 
@@ -5,6 +5,7 @@
5
5
  // doing so would override each component's fallback/inheritance behavior.
6
6
  // Governance reads this file as the explicit vocabulary for dynamic values.
7
7
  @mixin fui-component-property-contract {
8
+ --fui-checkbox-radius: 0.25rem;
8
9
  --fui-grid-min-child-width: 16rem;
9
10
  --fui-line-clamp: 2;
10
11
  --fui-navmenu-viewport-height: 0px;
@@ -1,33 +0,0 @@
1
- import { type ProgressProps } from "../Progress";
2
- export { PrototypeShell } from "./DashboardLayoutPrototypes.shell";
3
- export type StateVariant = "success" | "warning" | "error" | "info";
4
- export type AreaRow = {
5
- area: string;
6
- owner: string;
7
- coverage: number;
8
- drift: number;
9
- criticality: string;
10
- state: "Healthy" | "Watching" | "Blocked" | "Review";
11
- variant: StateVariant;
12
- };
13
- export declare const areas: AreaRow[];
14
- export declare function MetricPanel({ label, value, progress, variant, }: {
15
- label: string;
16
- value: string;
17
- progress: number;
18
- variant?: ProgressProps["variant"];
19
- }): import("react/jsx-runtime").JSX.Element;
20
- export declare function CoverageHero({ className }?: {
21
- className?: string;
22
- }): import("react/jsx-runtime").JSX.Element;
23
- export declare function AreasTable({ title }: {
24
- title?: string;
25
- }): import("react/jsx-runtime").JSX.Element;
26
- export declare function ActionPanel({ className }?: {
27
- className?: string;
28
- }): import("react/jsx-runtime").JSX.Element;
29
- export declare function ActivityPanel(): import("react/jsx-runtime").JSX.Element;
30
- export declare function ActivityTable(): import("react/jsx-runtime").JSX.Element;
31
- export declare function StatePanel(): import("react/jsx-runtime").JSX.Element;
32
- export declare function FindingsToolbar(): import("react/jsx-runtime").JSX.Element;
33
- //# sourceMappingURL=DashboardLayoutPrototypes.shared.d.ts.map