@texturehq/edges 1.24.1 → 1.25.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/styles.css CHANGED
@@ -1487,6 +1487,9 @@
1487
1487
  .top-20 {
1488
1488
  top: var(--spacing-20);
1489
1489
  }
1490
+ .top-\[-2px\] {
1491
+ top: -2px;
1492
+ }
1490
1493
  .top-\[2rem\] {
1491
1494
  top: 2rem;
1492
1495
  }
@@ -1979,6 +1982,9 @@
1979
1982
  .max-h-\[300px\] {
1980
1983
  max-height: 300px;
1981
1984
  }
1985
+ .max-h-\[500px\] {
1986
+ max-height: 500px;
1987
+ }
1982
1988
  .min-h-0 {
1983
1989
  min-height: var(--spacing-0);
1984
1990
  }
@@ -2175,6 +2181,9 @@
2175
2181
  .max-w-7xl {
2176
2182
  max-width: var(--container-7xl);
2177
2183
  }
2184
+ .max-w-\[90vw\] {
2185
+ max-width: 90vw;
2186
+ }
2178
2187
  .max-w-\[150px\] {
2179
2188
  max-width: 150px;
2180
2189
  }
@@ -2350,8 +2359,8 @@
2350
2359
  --tw-translate-y: calc(calc(1/2 * 100%) * -1);
2351
2360
  translate: var(--tw-translate-x) var(--tw-translate-y);
2352
2361
  }
2353
- .-translate-y-\[calc\(50\%\+1px\)\] {
2354
- --tw-translate-y: calc(calc(50% + 1px) * -1);
2362
+ .translate-y-\[0\.5px\] {
2363
+ --tw-translate-y: 0.5px;
2355
2364
  translate: var(--tw-translate-x) var(--tw-translate-y);
2356
2365
  }
2357
2366
  .rotate-0 {
@@ -3690,9 +3699,6 @@
3690
3699
  .p-\[1rem\] {
3691
3700
  padding: 1rem;
3692
3701
  }
3693
- .\!px-1 {
3694
- padding-inline: var(--spacing-1) !important;
3695
- }
3696
3702
  .\!px-2 {
3697
3703
  padding-inline: var(--spacing-2) !important;
3698
3704
  }
@@ -3825,9 +3831,6 @@
3825
3831
  .pt-8 {
3826
3832
  padding-top: var(--spacing-8);
3827
3833
  }
3828
- .pt-\[60px\] {
3829
- padding-top: 60px;
3830
- }
3831
3834
  .pr-0 {
3832
3835
  padding-right: var(--spacing-0);
3833
3836
  }
@@ -3939,6 +3942,10 @@
3939
3942
  .font-mono {
3940
3943
  font-family: var(--font-mono);
3941
3944
  }
3945
+ .\!text-base {
3946
+ font-size: var(--text-base) !important;
3947
+ line-height: var(--tw-leading, var(--text-base--line-height)) !important;
3948
+ }
3942
3949
  .text-2xl {
3943
3950
  font-size: var(--text-2xl);
3944
3951
  line-height: var(--tw-leading, var(--text-2xl--line-height));
@@ -4790,6 +4797,11 @@
4790
4797
  }
4791
4798
  }
4792
4799
  }
4800
+ .group-focus-visible\:opacity-100 {
4801
+ &:is(:where(.group):focus-visible *) {
4802
+ opacity: 100%;
4803
+ }
4804
+ }
4793
4805
  .group-disabled\:text-gray-200 {
4794
4806
  &:is(:where(.group):disabled *) {
4795
4807
  color: var(--color-gray-200);
@@ -4800,6 +4812,11 @@
4800
4812
  color: var(--color-text-disabled);
4801
4813
  }
4802
4814
  }
4815
+ .group-data-\[focused\]\:opacity-100 {
4816
+ &:is(:where(.group)[data-focused] *) {
4817
+ opacity: 100%;
4818
+ }
4819
+ }
4803
4820
  .peer-checked\/category\:block {
4804
4821
  &:is(:where(.peer\/category):checked ~ *) {
4805
4822
  display: block;
@@ -4935,6 +4952,12 @@
4935
4952
  background-color: var(--color-border-muted);
4936
4953
  }
4937
4954
  }
4955
+ .after\:bg-transparent {
4956
+ &::after {
4957
+ content: var(--tw-content);
4958
+ background-color: transparent;
4959
+ }
4960
+ }
4938
4961
  .after\:content-\[\'\'\] {
4939
4962
  &::after {
4940
4963
  --tw-content: '';
@@ -5127,6 +5150,13 @@
5127
5150
  }
5128
5151
  }
5129
5152
  }
5153
+ .hover\:bg-background-surface {
5154
+ &:hover {
5155
+ @media (hover: hover) {
5156
+ background-color: var(--color-background-surface);
5157
+ }
5158
+ }
5159
+ }
5130
5160
  .hover\:bg-black\/10 {
5131
5161
  &:hover {
5132
5162
  @media (hover: hover) {
@@ -5250,13 +5280,6 @@
5250
5280
  }
5251
5281
  }
5252
5282
  }
5253
- .hover\:bg-transparent {
5254
- &:hover {
5255
- @media (hover: hover) {
5256
- background-color: transparent;
5257
- }
5258
- }
5259
- }
5260
5283
  .hover\:bg-white\/10 {
5261
5284
  &:hover {
5262
5285
  @media (hover: hover) {
@@ -5475,6 +5498,11 @@
5475
5498
  outline-style: none;
5476
5499
  }
5477
5500
  }
5501
+ .focus-visible\:bg-brand-light {
5502
+ &:focus-visible {
5503
+ background-color: var(--color-brand-light);
5504
+ }
5505
+ }
5478
5506
  .focus-visible\:ring-0 {
5479
5507
  &:focus-visible {
5480
5508
  --tw-ring-shadow: var(--tw-ring-inset,) 0 0 0 calc(0px + var(--tw-ring-offset-width)) var(--tw-ring-color, currentcolor);
@@ -5933,11 +5961,21 @@
5933
5961
  padding-bottom: var(--spacing-0);
5934
5962
  }
5935
5963
  }
5964
+ .md\:absolute {
5965
+ @media (width >= 48rem) {
5966
+ position: absolute;
5967
+ }
5968
+ }
5936
5969
  .md\:relative {
5937
5970
  @media (width >= 48rem) {
5938
5971
  position: relative;
5939
5972
  }
5940
5973
  }
5974
+ .md\:left-1\/2 {
5975
+ @media (width >= 48rem) {
5976
+ left: calc(1/2 * 100%);
5977
+ }
5978
+ }
5941
5979
  .md\:order-1 {
5942
5980
  @media (width >= 48rem) {
5943
5981
  order: 1;
@@ -6108,6 +6146,11 @@
6108
6146
  width: auto;
6109
6147
  }
6110
6148
  }
6149
+ .md\:max-w-4xl {
6150
+ @media (width >= 48rem) {
6151
+ max-width: var(--container-4xl);
6152
+ }
6153
+ }
6111
6154
  .md\:max-w-none {
6112
6155
  @media (width >= 48rem) {
6113
6156
  max-width: none;
@@ -6133,6 +6176,12 @@
6133
6176
  flex-shrink: 0;
6134
6177
  }
6135
6178
  }
6179
+ .md\:-translate-x-1\/2 {
6180
+ @media (width >= 48rem) {
6181
+ --tw-translate-x: calc(calc(1/2 * 100%) * -1);
6182
+ translate: var(--tw-translate-x) var(--tw-translate-y);
6183
+ }
6184
+ }
6136
6185
  .md\:translate-x-0 {
6137
6186
  @media (width >= 48rem) {
6138
6187
  --tw-translate-x: var(--spacing-0);
@@ -6238,6 +6287,11 @@
6238
6287
  }
6239
6288
  }
6240
6289
  }
6290
+ .md\:px-4 {
6291
+ @media (width >= 48rem) {
6292
+ padding-inline: var(--spacing-4);
6293
+ }
6294
+ }
6241
6295
  .md\:px-6 {
6242
6296
  @media (width >= 48rem) {
6243
6297
  padding-inline: var(--spacing-6);
@@ -6258,6 +6312,28 @@
6258
6312
  padding-bottom: var(--spacing-28);
6259
6313
  }
6260
6314
  }
6315
+ .md\:text-sm {
6316
+ @media (width >= 48rem) {
6317
+ font-size: var(--text-sm);
6318
+ line-height: var(--tw-leading, var(--text-sm--line-height));
6319
+ }
6320
+ }
6321
+ .md\:text-xs {
6322
+ @media (width >= 48rem) {
6323
+ font-size: var(--text-xs);
6324
+ line-height: var(--tw-leading, var(--text-xs--line-height));
6325
+ }
6326
+ }
6327
+ .md\:\!text-\[length\:var\(--control-text-md\)\] {
6328
+ @media (width >= 48rem) {
6329
+ font-size: var(--control-text-md) !important;
6330
+ }
6331
+ }
6332
+ .md\:\!text-\[length\:var\(--control-text-sm\)\] {
6333
+ @media (width >= 48rem) {
6334
+ font-size: var(--control-text-sm) !important;
6335
+ }
6336
+ }
6261
6337
  .lg\:sticky {
6262
6338
  @media (width >= 64rem) {
6263
6339
  position: sticky;
@@ -1,6 +1,5 @@
1
1
  {
2
- "version": "1.24.1",
3
- "generatedAt": "2025-11-30T15:12:49.135Z",
2
+ "version": "1.25.0",
4
3
  "categories": {
5
4
  "hooks": {
6
5
  "description": "React hooks for common functionality like breakpoints, debouncing, local storage, and media queries",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@texturehq/edges",
3
- "version": "1.24.1",
3
+ "version": "1.25.0",
4
4
  "author": "Nicholas Brown <nick@texturehq.com>",
5
5
  "description": "A shared component library for Texture",
6
6
  "type": "module",
@@ -65,7 +65,7 @@
65
65
  "test:watch": "vitest",
66
66
  "test:coverage": "vitest run --coverage",
67
67
  "test:ui": "vitest --ui",
68
- "storybook": "VITE_MAPBOX_ACCESS_TOKEN=pk.eyJ1IjoidmljdG9yLXRleHR1cmUiLCJhIjoiY2x1cXM5dnVqMDFvYTJrcWszbnZmdGo4cCJ9.uEu0gqmITLtBMKEVW0aFtA storybook dev -p 6010 --no-open",
68
+ "storybook": "VITE_MAPBOX_ACCESS_TOKEN=pk.eyJ1IjoidmljdG9yLXRleHR1cmUiLCJhIjoiY2x1cXM5dnVqMDFvYTJrcWszbnZmdGo4cCJ9.uEu0gqmITLtBMKEVW0aFtA storybook dev -p ${STORYBOOK_PORT:-6010} --no-open",
69
69
  "build-storybook": "storybook build",
70
70
  "postinstall": "node scripts/setup-cursor-rules.js || echo \"! setup-cursor-rules: non-fatal error\""
71
71
  },
@@ -37,6 +37,12 @@ function ensureDir(dir) {
37
37
  if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
38
38
  }
39
39
 
40
+ function escapeMarkdownTableCell(text) {
41
+ // Only escape backslashes since the text will be wrapped in backticks (inline code).
42
+ // Pipes and backticks don't need escaping inside inline code spans.
43
+ return text.replace(/\\/g, "\\\\");
44
+ }
45
+
40
46
  function writeFile(filePath, content) {
41
47
  ensureDir(path.dirname(filePath));
42
48
  fs.writeFileSync(filePath, content, "utf8");
@@ -242,6 +248,8 @@ function generateComponentsManifest() {
242
248
 
243
249
  // Extract props
244
250
  const props = extractProps(content, name);
251
+ // Sort props alphabetically for deterministic output
252
+ props.sort((a, b) => a.name.localeCompare(b.name));
245
253
 
246
254
  // Extract Storybook metadata
247
255
  const storyFile = findStorybookFile(relPath);
@@ -285,7 +293,8 @@ function generateComponentsManifest() {
285
293
 
286
294
  const manifest = {
287
295
  version: PACKAGE_VERSION,
288
- generatedAt: new Date().toISOString(),
296
+ // generatedAt removed to prevent unnecessary git churn
297
+ // Use version field to track which package version generated this
289
298
  components: components,
290
299
  categories: categories,
291
300
  };
@@ -405,7 +414,8 @@ function generateUtilitiesManifest() {
405
414
 
406
415
  const manifest = {
407
416
  version: PACKAGE_VERSION,
408
- generatedAt: new Date().toISOString(),
417
+ // generatedAt removed to prevent unnecessary git churn
418
+ // Use version field to track which package version generated this
409
419
  categories: {},
410
420
  };
411
421
 
@@ -588,7 +598,8 @@ This document provides a complete reference of all ${components.length} componen
588
598
  content += `| Prop | Type |\n`;
589
599
  content += `|------|------|\n`;
590
600
  for (const prop of component.props) {
591
- content += `| \`${prop.name}\` | \`${prop.type}\` |\n`;
601
+ const safeType = escapeMarkdownTableCell(prop.type);
602
+ content += `| \`${prop.name}\` | \`${safeType}\` |\n`;
592
603
  }
593
604
  content += `\n`;
594
605
  }
@@ -823,7 +834,8 @@ function generateEdgesReadme(componentsManifest, utilitiesManifest) {
823
834
  const componentCount = componentsManifest.components.length;
824
835
  const categoryCount = Object.keys(componentsManifest.categories).length;
825
836
  const hookCount = utilitiesManifest.categories.hooks?.utilities.length || 0;
826
- const generatedAt = componentsManifest.generatedAt || new Date().toISOString();
837
+ // Use version instead of timestamp to avoid git churn
838
+ const version = componentsManifest.version || PACKAGE_VERSION;
827
839
 
828
840
  let utilityCount = 0;
829
841
  for (const cat in utilitiesManifest.categories) {
@@ -916,8 +928,7 @@ When building UI in \`apps/dashboard\`, reference:
916
928
 
917
929
  ---
918
930
 
919
- **Package Version:** ${componentsManifest.version}
920
- **Generated:** ${generatedAt}
931
+ **Package Version:** ${version}
921
932
  `;
922
933
 
923
934
  writeFile(path.join(DOCS_AI_EDGES, "README.md"), content);
@@ -42,6 +42,10 @@ const setupCursorRules = () => {
42
42
  path.dirname(new URL(import.meta.url).pathname),
43
43
  "../templates/claude-rules"
44
44
  );
45
+ const codexTemplatesDir = path.join(
46
+ path.dirname(new URL(import.meta.url).pathname),
47
+ "../templates/codex-rules"
48
+ );
45
49
  const cursorDir = path.join(cwd, ".cursor");
46
50
  const rulesDir = path.join(cursorDir, "rules");
47
51
 
@@ -80,31 +84,8 @@ const setupCursorRules = () => {
80
84
  .readdirSync(claudeTemplatesDir)
81
85
  .filter((file) => file.endsWith(".md"));
82
86
 
83
- if (claudeTemplateFiles.length > 0) {
84
- let claudeCopiedCount = 0;
85
-
86
- // Create .claude directory for namespaced files
87
- const claudeDir = path.join(cwd, ".claude");
88
- fs.mkdirSync(claudeDir, { recursive: true });
89
-
90
- claudeTemplateFiles.forEach((file) => {
91
- const templatePath = path.join(claudeTemplatesDir, file);
92
- // Namespace the file as edges-specific
93
- const namespacedFileName = "edges.md";
94
- const targetPath = path.join(claudeDir, namespacedFileName);
95
-
96
- // Always copy to ensure latest version
97
- fs.copyFileSync(templatePath, targetPath);
98
- claudeCopiedCount++;
99
- console.log(`✅ Updated .claude/${namespacedFileName} for Claude`);
100
- });
101
-
102
- if (claudeCopiedCount > 0) {
103
- console.log(
104
- `🤖 Added ${claudeCopiedCount} namespaced Claude rule(s) for @texturehq/edges design system`
105
- );
106
- }
107
- }
87
+ // Claude template processing is done later with component injection (lines 221-236)
88
+ // so we don't need to copy templates here
108
89
  }
109
90
 
110
91
  // Also render edges-components.mdc from manifest when present
@@ -112,9 +93,17 @@ const setupCursorRules = () => {
112
93
  path.join(cwd, "node_modules/@texturehq/edges/dist/components.manifest.json"),
113
94
  ].find((p) => fs.existsSync(p));
114
95
 
96
+ // Track what we generated for summary
97
+ let cursorComponentCount = 0;
98
+ let claudeComponentCount = 0;
99
+ let codexComponentCount = 0;
100
+ let packageVersion = "unknown";
101
+
115
102
  if (manifestPath) {
116
103
  try {
117
104
  const manifest = JSON.parse(fs.readFileSync(manifestPath, "utf8"));
105
+ packageVersion = manifest.version || "unknown";
106
+ // Don't set counts yet - only set them when files are actually written
118
107
 
119
108
  // Generate Cursor components list
120
109
  const cursorLines = [
@@ -150,7 +139,9 @@ const setupCursorRules = () => {
150
139
 
151
140
  if (c.props && c.props.length) {
152
141
  cursorLines.push("**Props:**");
153
- c.props.forEach((prop) => {
142
+ // Sort props alphabetically for deterministic output
143
+ const sortedProps = [...c.props].sort((a, b) => a.name.localeCompare(b.name));
144
+ sortedProps.forEach((prop) => {
154
145
  cursorLines.push(`- \`${prop.name}: ${prop.type}\``);
155
146
  });
156
147
  cursorLines.push("");
@@ -161,8 +152,9 @@ const setupCursorRules = () => {
161
152
  const cursorOutPath = path.join(rulesDir, "edges-components.mdc");
162
153
 
163
154
  fs.writeFileSync(cursorOutPath, cursorLines.join("\n"), "utf8");
155
+ cursorComponentCount = manifest.components?.length || 0;
164
156
  console.log(
165
- `✅ Wrote .cursor/rules/edges-components.mdc from manifest (${manifest.components?.length || 0} components)`
157
+ `✅ Wrote .cursor/rules/edges-components.mdc from manifest (${cursorComponentCount} components)`
166
158
  );
167
159
 
168
160
  // Generate Claude components list
@@ -192,7 +184,9 @@ const setupCursorRules = () => {
192
184
 
193
185
  if (c.props && c.props.length) {
194
186
  claudeLines.push("**Props:**");
195
- c.props.forEach((prop) => {
187
+ // Sort props alphabetically for deterministic output
188
+ const sortedProps = [...c.props].sort((a, b) => a.name.localeCompare(b.name));
189
+ sortedProps.forEach((prop) => {
196
190
  claudeLines.push(`- \`${prop.name}: ${prop.type}\``);
197
191
  });
198
192
  claudeLines.push("");
@@ -212,18 +206,72 @@ const setupCursorRules = () => {
212
206
 
213
207
  const claudeOutPath = path.join(claudeDir, "edges.md");
214
208
  fs.writeFileSync(claudeOutPath, claudeContent, "utf8");
209
+ claudeComponentCount = manifest.components?.length || 0;
210
+ console.log(
211
+ `✅ Wrote .claude/edges.md with components list (${claudeComponentCount} components)`
212
+ );
213
+ }
214
+
215
+ // Generate Codex docs using template
216
+ const codexTemplatePath = path.join(codexTemplatesDir, "codex.md");
217
+ if (fs.existsSync(codexTemplatePath)) {
218
+ const codexDir = path.join(cwd, ".codex");
219
+ fs.mkdirSync(codexDir, { recursive: true });
220
+
221
+ let codexContent = fs.readFileSync(codexTemplatePath, "utf8");
222
+ codexContent = codexContent.split("{{COMPONENTS_LIST}}").join(claudeLines.join("\n"));
223
+
224
+ const codexOutPath = path.join(codexDir, "edges.md");
225
+ fs.writeFileSync(codexOutPath, codexContent, "utf8");
226
+ codexComponentCount = manifest.components?.length || 0;
215
227
  console.log(
216
- `✅ Wrote .claude/edges.md with components list (${manifest.components?.length || 0} components)`
228
+ `✅ Wrote .codex/edges.md with components list (${codexComponentCount} components)`
217
229
  );
218
230
  }
219
231
  } catch (err) {
220
232
  console.log("⚠️ Failed to read components.manifest.json:", err.message);
233
+ console.log(" This might mean:");
234
+ console.log(" 1. @texturehq/edges is not installed");
235
+ console.log(" 2. Package is installed but not built");
236
+ console.log(" 3. Try: cd packages/edges && yarn build");
221
237
  }
222
238
  }
239
+
240
+ // Return summary for outer handler
241
+ return {
242
+ cursorCount: cursorComponentCount,
243
+ claudeCount: claudeComponentCount,
244
+ codexCount: codexComponentCount,
245
+ version: packageVersion
246
+ };
223
247
  };
224
248
 
225
249
  try {
226
- setupCursorRules();
250
+ const result = setupCursorRules();
251
+
252
+ // Print summary if we generated context
253
+ if (result && (result.cursorCount > 0 || result.claudeCount > 0 || result.codexCount > 0)) {
254
+ console.log("\n" + "=".repeat(60));
255
+ console.log("🤖 Agent Context Generated Successfully");
256
+ console.log("=".repeat(60));
257
+
258
+ if (result.cursorCount > 0) {
259
+ console.log(` ✅ Cursor: ${result.cursorCount} components (v${result.version})`);
260
+ }
261
+ if (result.claudeCount > 0) {
262
+ console.log(` ✅ Claude: ${result.claudeCount} components (v${result.version})`);
263
+ }
264
+ if (result.codexCount > 0) {
265
+ console.log(` ✅ Codex: ${result.codexCount} components (v${result.version})`);
266
+ }
267
+
268
+ console.log(` 📦 Source: @texturehq/edges v${result.version}`);
269
+ console.log("\n💡 Tip: Reload your AI agent to use the latest context");
270
+ console.log(" Cursor: Cmd+Shift+P → 'Developer: Reload Window'");
271
+ console.log(" Claude: Restart Claude Desktop / Reload project");
272
+ console.log("=".repeat(60) + "\n");
273
+ }
227
274
  } catch (err) {
228
- console.warn("setup-cursor-rules error:", err);
275
+ console.warn("⚠️ setup-cursor-rules error:", err);
276
+ console.warn(" Agent context may not be available");
229
277
  }
@@ -0,0 +1,85 @@
1
+ # @texturehq/edges Design System
2
+
3
+ This project uses the @texturehq/edges design system with Tailwind 4. The theme CSS file contains all design system variables that automatically become available as Tailwind classes.
4
+
5
+ ## Setup
6
+
7
+ The theme is imported via CSS:
8
+ ```css
9
+ @import "@texturehq/edges/theme.css";
10
+ ```
11
+
12
+ ## How It Works
13
+
14
+ - CSS variables in the theme file automatically become Tailwind classes
15
+ - `--color-brand-primary` becomes available as `bg-brand-primary`, `text-brand-primary`, `border-brand-primary`, etc.
16
+ - `--spacing-md` becomes available as `p-md`, `m-md`, `gap-md`, etc.
17
+ - `--text-lg` becomes available as `text-lg`
18
+ - `--radius-lg` becomes available as `rounded-lg`
19
+
20
+ ## Usage Guidelines
21
+
22
+ - **Use semantic classes over arbitrary values**
23
+ - Prefer: `bg-brand-primary`, `text-text-body`, `p-md`, `rounded-lg`
24
+ - Avoid: `bg-[#444ae1]`, `text-[#333333]`, `p-[1rem]`, `rounded-[0.5rem]`
25
+
26
+ ## Naming Conventions
27
+
28
+ - Brand colors: `brand-primary`, `brand-light`, `brand-dark`
29
+ - Text colors: `text-body`, `text-heading`, `text-muted`, `text-caption`
30
+ - Background colors: `background-body`, `background-surface`, `background-muted`
31
+ - Border colors: `border-default`, `border-focus`, `border-muted`
32
+ - Action colors: `action-primary`, `action-secondary`, `action-destructive`
33
+ - Feedback colors: `feedback-success`, `feedback-error`, `feedback-warning`, `feedback-info`
34
+ - Spacing: `xs`, `sm`, `md`, `lg`, `xl`, `2xl`, `3xl`, `4xl`
35
+ - Typography: `xs`, `sm`, `base`, `lg`, `xl`, `2xl`, `3xl`, `4xl`
36
+ - Border radius: `xs`, `sm`, `md`, `lg`, `xl`, `2xl`, `3xl`, `4xl`
37
+
38
+ ## Examples
39
+
40
+ ```html
41
+ <!-- ✅ Good - Uses semantic classes -->
42
+ <div class="bg-brand-primary text-text-on-primary p-md rounded-lg shadow-md">
43
+ <h2 class="text-text-heading text-lg font-medium">Title</h2>
44
+ <p class="text-text-body text-base">Content</p>
45
+ </div>
46
+
47
+ <!-- ❌ Avoid - Uses arbitrary values -->
48
+ <div class="bg-[#444ae1] text-[#ffffff] p-[1rem] rounded-[0.5rem]">
49
+ <h2 class="text-[#111827] text-[1.125rem] font-[500]">Title</h2>
50
+ <p class="text-[#333333] text-[1rem]">Content</p>
51
+ </div>
52
+ ```
53
+
54
+ ## Dark Mode
55
+
56
+ All colors automatically adapt to dark mode when `.theme-dark` class is present.
57
+
58
+ ## Available Variables
59
+
60
+ All CSS variables from the theme file are automatically available. The theme includes:
61
+ - Complete color system (brand, text, background, border, action, feedback, device states, data visualization)
62
+ - Spacing scale
63
+ - Typography scale
64
+ - Border radius scale
65
+ - Shadow system
66
+ - Animation definitions
67
+ - Form control specifications
68
+
69
+ ## Available Components
70
+
71
+ The following components are available from @texturehq/edges:
72
+
73
+ {{COMPONENTS_LIST}}
74
+
75
+ ## Import Examples
76
+
77
+ ```typescript
78
+ // Import from package root
79
+ import { Button, TextField, Card } from "@texturehq/edges";
80
+
81
+ // Import individual components for tree-shaking
82
+ import { Button } from "@texturehq/edges/components/Button";
83
+ import { TextField } from "@texturehq/edges/components/TextField";
84
+ import { Card } from "@texturehq/edges/components/Card";
85
+ ```