@texturehq/edges 1.24.2 → 1.25.1

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
@@ -1982,6 +1982,9 @@
1982
1982
  .max-h-\[300px\] {
1983
1983
  max-height: 300px;
1984
1984
  }
1985
+ .max-h-\[500px\] {
1986
+ max-height: 500px;
1987
+ }
1985
1988
  .min-h-0 {
1986
1989
  min-height: var(--spacing-0);
1987
1990
  }
@@ -2178,6 +2181,9 @@
2178
2181
  .max-w-7xl {
2179
2182
  max-width: var(--container-7xl);
2180
2183
  }
2184
+ .max-w-\[90vw\] {
2185
+ max-width: 90vw;
2186
+ }
2181
2187
  .max-w-\[150px\] {
2182
2188
  max-width: 150px;
2183
2189
  }
@@ -3693,9 +3699,6 @@
3693
3699
  .p-\[1rem\] {
3694
3700
  padding: 1rem;
3695
3701
  }
3696
- .\!px-1 {
3697
- padding-inline: var(--spacing-1) !important;
3698
- }
3699
3702
  .\!px-2 {
3700
3703
  padding-inline: var(--spacing-2) !important;
3701
3704
  }
@@ -3828,9 +3831,6 @@
3828
3831
  .pt-8 {
3829
3832
  padding-top: var(--spacing-8);
3830
3833
  }
3831
- .pt-\[60px\] {
3832
- padding-top: 60px;
3833
- }
3834
3834
  .pr-0 {
3835
3835
  padding-right: var(--spacing-0);
3836
3836
  }
@@ -3942,6 +3942,10 @@
3942
3942
  .font-mono {
3943
3943
  font-family: var(--font-mono);
3944
3944
  }
3945
+ .\!text-base {
3946
+ font-size: var(--text-base) !important;
3947
+ line-height: var(--tw-leading, var(--text-base--line-height)) !important;
3948
+ }
3945
3949
  .text-2xl {
3946
3950
  font-size: var(--text-2xl);
3947
3951
  line-height: var(--tw-leading, var(--text-2xl--line-height));
@@ -4793,6 +4797,11 @@
4793
4797
  }
4794
4798
  }
4795
4799
  }
4800
+ .group-focus-visible\:opacity-100 {
4801
+ &:is(:where(.group):focus-visible *) {
4802
+ opacity: 100%;
4803
+ }
4804
+ }
4796
4805
  .group-disabled\:text-gray-200 {
4797
4806
  &:is(:where(.group):disabled *) {
4798
4807
  color: var(--color-gray-200);
@@ -4803,6 +4812,11 @@
4803
4812
  color: var(--color-text-disabled);
4804
4813
  }
4805
4814
  }
4815
+ .group-data-\[focused\]\:opacity-100 {
4816
+ &:is(:where(.group)[data-focused] *) {
4817
+ opacity: 100%;
4818
+ }
4819
+ }
4806
4820
  .peer-checked\/category\:block {
4807
4821
  &:is(:where(.peer\/category):checked ~ *) {
4808
4822
  display: block;
@@ -5136,6 +5150,13 @@
5136
5150
  }
5137
5151
  }
5138
5152
  }
5153
+ .hover\:bg-background-surface {
5154
+ &:hover {
5155
+ @media (hover: hover) {
5156
+ background-color: var(--color-background-surface);
5157
+ }
5158
+ }
5159
+ }
5139
5160
  .hover\:bg-black\/10 {
5140
5161
  &:hover {
5141
5162
  @media (hover: hover) {
@@ -5259,13 +5280,6 @@
5259
5280
  }
5260
5281
  }
5261
5282
  }
5262
- .hover\:bg-transparent {
5263
- &:hover {
5264
- @media (hover: hover) {
5265
- background-color: transparent;
5266
- }
5267
- }
5268
- }
5269
5283
  .hover\:bg-white\/10 {
5270
5284
  &:hover {
5271
5285
  @media (hover: hover) {
@@ -5484,6 +5498,11 @@
5484
5498
  outline-style: none;
5485
5499
  }
5486
5500
  }
5501
+ .focus-visible\:bg-brand-light {
5502
+ &:focus-visible {
5503
+ background-color: var(--color-brand-light);
5504
+ }
5505
+ }
5487
5506
  .focus-visible\:ring-0 {
5488
5507
  &:focus-visible {
5489
5508
  --tw-ring-shadow: var(--tw-ring-inset,) 0 0 0 calc(0px + var(--tw-ring-offset-width)) var(--tw-ring-color, currentcolor);
@@ -5942,11 +5961,21 @@
5942
5961
  padding-bottom: var(--spacing-0);
5943
5962
  }
5944
5963
  }
5964
+ .md\:absolute {
5965
+ @media (width >= 48rem) {
5966
+ position: absolute;
5967
+ }
5968
+ }
5945
5969
  .md\:relative {
5946
5970
  @media (width >= 48rem) {
5947
5971
  position: relative;
5948
5972
  }
5949
5973
  }
5974
+ .md\:left-1\/2 {
5975
+ @media (width >= 48rem) {
5976
+ left: calc(1/2 * 100%);
5977
+ }
5978
+ }
5950
5979
  .md\:order-1 {
5951
5980
  @media (width >= 48rem) {
5952
5981
  order: 1;
@@ -6072,6 +6101,11 @@
6072
6101
  display: none;
6073
6102
  }
6074
6103
  }
6104
+ .md\:inline {
6105
+ @media (width >= 48rem) {
6106
+ display: inline;
6107
+ }
6108
+ }
6075
6109
  .md\:h-10 {
6076
6110
  @media (width >= 48rem) {
6077
6111
  height: var(--spacing-10);
@@ -6117,6 +6151,11 @@
6117
6151
  width: auto;
6118
6152
  }
6119
6153
  }
6154
+ .md\:max-w-4xl {
6155
+ @media (width >= 48rem) {
6156
+ max-width: var(--container-4xl);
6157
+ }
6158
+ }
6120
6159
  .md\:max-w-none {
6121
6160
  @media (width >= 48rem) {
6122
6161
  max-width: none;
@@ -6142,6 +6181,12 @@
6142
6181
  flex-shrink: 0;
6143
6182
  }
6144
6183
  }
6184
+ .md\:-translate-x-1\/2 {
6185
+ @media (width >= 48rem) {
6186
+ --tw-translate-x: calc(calc(1/2 * 100%) * -1);
6187
+ translate: var(--tw-translate-x) var(--tw-translate-y);
6188
+ }
6189
+ }
6145
6190
  .md\:translate-x-0 {
6146
6191
  @media (width >= 48rem) {
6147
6192
  --tw-translate-x: var(--spacing-0);
@@ -6247,6 +6292,11 @@
6247
6292
  }
6248
6293
  }
6249
6294
  }
6295
+ .md\:px-4 {
6296
+ @media (width >= 48rem) {
6297
+ padding-inline: var(--spacing-4);
6298
+ }
6299
+ }
6250
6300
  .md\:px-6 {
6251
6301
  @media (width >= 48rem) {
6252
6302
  padding-inline: var(--spacing-6);
@@ -6267,6 +6317,28 @@
6267
6317
  padding-bottom: var(--spacing-28);
6268
6318
  }
6269
6319
  }
6320
+ .md\:text-sm {
6321
+ @media (width >= 48rem) {
6322
+ font-size: var(--text-sm);
6323
+ line-height: var(--tw-leading, var(--text-sm--line-height));
6324
+ }
6325
+ }
6326
+ .md\:text-xs {
6327
+ @media (width >= 48rem) {
6328
+ font-size: var(--text-xs);
6329
+ line-height: var(--tw-leading, var(--text-xs--line-height));
6330
+ }
6331
+ }
6332
+ .md\:\!text-\[length\:var\(--control-text-md\)\] {
6333
+ @media (width >= 48rem) {
6334
+ font-size: var(--control-text-md) !important;
6335
+ }
6336
+ }
6337
+ .md\:\!text-\[length\:var\(--control-text-sm\)\] {
6338
+ @media (width >= 48rem) {
6339
+ font-size: var(--control-text-sm) !important;
6340
+ }
6341
+ }
6270
6342
  .lg\:sticky {
6271
6343
  @media (width >= 64rem) {
6272
6344
  position: sticky;
@@ -1,6 +1,5 @@
1
1
  {
2
- "version": "1.24.2",
3
- "generatedAt": "2025-12-01T02:27:01.139Z",
2
+ "version": "1.25.1",
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.2",
3
+ "version": "1.25.1",
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
+ ```