@veluai/velu 0.2.25 → 0.2.28

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 (114) hide show
  1. package/README.md +80 -80
  2. package/dist/cli.js +44 -44
  3. package/package.json +64 -64
  4. package/runtime/velu-ui/base.css +320 -320
  5. package/runtime/velu-ui/components/Accordion.jsx +64 -64
  6. package/runtime/velu-ui/components/ApiClient.jsx +207 -207
  7. package/runtime/velu-ui/components/ApiField.jsx +87 -87
  8. package/runtime/velu-ui/components/ApiPath.jsx +63 -63
  9. package/runtime/velu-ui/components/ApiReferencePage.jsx +384 -384
  10. package/runtime/velu-ui/components/ApiSamples.jsx +36 -36
  11. package/runtime/velu-ui/components/ApiSidebar.jsx +125 -125
  12. package/runtime/velu-ui/components/AskBar.jsx +71 -71
  13. package/runtime/velu-ui/components/Callout.jsx +114 -114
  14. package/runtime/velu-ui/components/Card.jsx +131 -131
  15. package/runtime/velu-ui/components/ChangelogFilters.jsx +75 -75
  16. package/runtime/velu-ui/components/Chatbot.jsx +972 -972
  17. package/runtime/velu-ui/components/CodeBlock.jsx +375 -375
  18. package/runtime/velu-ui/components/Columns.jsx +56 -56
  19. package/runtime/velu-ui/components/ContextMenu.jsx +327 -327
  20. package/runtime/velu-ui/components/ErrorCard.jsx +138 -138
  21. package/runtime/velu-ui/components/Field.jsx +81 -81
  22. package/runtime/velu-ui/components/Image.jsx +163 -163
  23. package/runtime/velu-ui/components/Logo.jsx +31 -31
  24. package/runtime/velu-ui/components/MethodBadge.jsx +31 -31
  25. package/runtime/velu-ui/components/NavSelect.jsx +108 -108
  26. package/runtime/velu-ui/components/NotFound.jsx +63 -63
  27. package/runtime/velu-ui/components/PageFeedback.jsx +219 -219
  28. package/runtime/velu-ui/components/PageFooter.jsx +145 -145
  29. package/runtime/velu-ui/components/PageHeader.jsx +422 -422
  30. package/runtime/velu-ui/components/PageNav.jsx +77 -77
  31. package/runtime/velu-ui/components/PoweredBy.jsx +51 -51
  32. package/runtime/velu-ui/components/Prompt.jsx +115 -115
  33. package/runtime/velu-ui/components/Search.jsx +460 -460
  34. package/runtime/velu-ui/components/Sidebar.jsx +246 -246
  35. package/runtime/velu-ui/components/SocialLinks.jsx +90 -90
  36. package/runtime/velu-ui/components/Steps.jsx +65 -65
  37. package/runtime/velu-ui/components/ThemeToggle.jsx +48 -48
  38. package/runtime/velu-ui/components/Toc.jsx +537 -537
  39. package/runtime/velu-ui/components/TocBar.jsx +195 -195
  40. package/runtime/velu-ui/components/Tree.jsx +87 -87
  41. package/runtime/velu-ui/components/TryItBar.jsx +102 -102
  42. package/runtime/velu-ui/components/Update.jsx +92 -92
  43. package/runtime/velu-ui/components/accordion.css +92 -92
  44. package/runtime/velu-ui/components/api-page.css +208 -208
  45. package/runtime/velu-ui/components/api.css +635 -635
  46. package/runtime/velu-ui/components/ask-bar.css +103 -103
  47. package/runtime/velu-ui/components/card.css +105 -105
  48. package/runtime/velu-ui/components/changelog-filters.css +43 -43
  49. package/runtime/velu-ui/components/chatbot.css +687 -687
  50. package/runtime/velu-ui/components/code-block.css +263 -263
  51. package/runtime/velu-ui/components/context-menu.css +199 -199
  52. package/runtime/velu-ui/components/docs-layout.css +822 -822
  53. package/runtime/velu-ui/components/field.css +82 -82
  54. package/runtime/velu-ui/components/image.css +237 -237
  55. package/runtime/velu-ui/components/nav-select.css +157 -157
  56. package/runtime/velu-ui/components/not-found.css +94 -94
  57. package/runtime/velu-ui/components/page-feedback.css +261 -261
  58. package/runtime/velu-ui/components/page-footer.css +130 -130
  59. package/runtime/velu-ui/components/page-header.css +558 -558
  60. package/runtime/velu-ui/components/page-nav.css +50 -50
  61. package/runtime/velu-ui/components/powered-by.css +92 -92
  62. package/runtime/velu-ui/components/prompt.css +99 -99
  63. package/runtime/velu-ui/components/search.css +307 -307
  64. package/runtime/velu-ui/components/sidebar.css +205 -205
  65. package/runtime/velu-ui/components/steps.css +77 -77
  66. package/runtime/velu-ui/components/theme-toggle.css +102 -102
  67. package/runtime/velu-ui/components/toc-bar.css +234 -234
  68. package/runtime/velu-ui/components/tree.css +49 -49
  69. package/runtime/velu-ui/components/update.css +111 -111
  70. package/runtime/velu-ui/index.js +58 -58
  71. package/runtime/velu-ui/lib/api-send.js +118 -118
  72. package/runtime/velu-ui/lib/brand-icons.jsx +103 -103
  73. package/runtime/velu-ui/lib/component-schemas.js +100 -100
  74. package/runtime/velu-ui/lib/copyText.js +64 -64
  75. package/runtime/velu-ui/lib/docs-assistant.js +273 -273
  76. package/runtime/velu-ui/lib/lang-icons.jsx +147 -147
  77. package/runtime/velu-ui/lib/page-feedback.js +72 -72
  78. package/runtime/velu-ui/lib/pagefind.js +116 -116
  79. package/runtime/velu-ui/lib/prism-langs.js +957 -957
  80. package/runtime/velu-ui/lib/prism-loader.js +74 -74
  81. package/runtime/velu-ui/lib/resolveIcon.jsx +29 -29
  82. package/runtime/velu-ui/lib/scrollIntoNearestView.js +66 -66
  83. package/runtime/velu-ui/mdx-components.jsx +107 -107
  84. package/runtime/velu-ui/primitives/Cluster.jsx +49 -49
  85. package/runtime/velu-ui/primitives/Stack.jsx +63 -63
  86. package/runtime/velu-ui/primitives/Switcher.jsx +57 -57
  87. package/runtime/velu-ui/primitives/stack.css +3 -3
  88. package/runtime/velu-ui/primitives/switcher.css +25 -25
  89. package/runtime/velu-ui/styles.css +48 -48
  90. package/runtime/velu-ui/tokens.css +4 -4
  91. package/schema/velu.schema.json +419 -419
  92. package/src/lib/extract-mdx-error.js +170 -170
  93. package/src/lib/issues.js +159 -159
  94. package/src/lib/known-components.js +35 -35
  95. package/src/navigation.js +459 -459
  96. package/src/runtime/App.jsx +1754 -1754
  97. package/src/runtime/ErrorBoundary.jsx +54 -54
  98. package/src/runtime/client-entry.jsx +27 -27
  99. package/src/runtime/server-entry.jsx +24 -24
  100. package/src/template.html +48 -48
  101. package/templates/starter/ai-tools/claude-code.mdx +26 -26
  102. package/templates/starter/ai-tools/cursor.mdx +17 -17
  103. package/templates/starter/api-reference/introduction.mdx +43 -43
  104. package/templates/starter/development.mdx +19 -19
  105. package/templates/starter/essentials/code.mdx +29 -29
  106. package/templates/starter/essentials/images.mdx +29 -29
  107. package/templates/starter/essentials/markdown.mdx +25 -25
  108. package/templates/starter/essentials/navigation.mdx +39 -39
  109. package/templates/starter/essentials/settings.mdx +30 -30
  110. package/templates/starter/favicon.svg +6 -6
  111. package/templates/starter/index.mdx +31 -31
  112. package/templates/starter/openapi.json +160 -160
  113. package/templates/starter/quickstart.mdx +31 -31
  114. package/templates/starter/velu.json +40 -40
@@ -1,103 +1,103 @@
1
- import React from 'react';
2
-
3
- /**
4
- * Brand glyphs for the contextual menu's "Open in <tool>" / "Connect to <IDE>"
5
- * actions. Sourced from svgl.app and inlined (the project inlines icons as JSX,
6
- * like lucide — no SVG loader). Each takes a `size` prop, mirroring lucide's
7
- * icon API so they're drop-in in the menu.
8
- *
9
- * ALL marks use `currentColor` so the icon column reads as one uniform set:
10
- * muted/grey at rest, accent on hover (matching the lucide icons beside them).
11
- * The brand glyphs keep their distinctive shapes; only the fill follows the
12
- * menu's text/hover color across light + dark.
13
- */
14
-
15
- export function MarkdownIcon({ size = '1em', ...rest }) {
16
- return (
17
- <svg width={size} height={size} viewBox="0 0 208 128" fill="none" aria-hidden="true" {...rest}>
18
- <path
19
- fill="none"
20
- stroke="currentColor"
21
- strokeWidth="10"
22
- d="M15 5h178a10 10 0 0 1 10 10v98a10 10 0 0 1-10 10H15a10 10 0 0 1-10-10V15A10 10 0 0 1 15 5z"
23
- />
24
- <path
25
- fill="currentColor"
26
- d="M30 98V30h20l20 25 20-25h20v68H90V59L70 84 50 59v39H30zm125 0-30-33h20V30h20v35h20l-30 33z"
27
- />
28
- </svg>
29
- );
30
- }
31
-
32
- export function OpenAIIcon({ size = '1em', ...rest }) {
33
- return (
34
- <svg width={size} height={size} viewBox="0 0 256 260" fill="currentColor" aria-hidden="true" {...rest}>
35
- <path d="M239.184 106.203a64.716 64.716 0 0 0-5.576-53.103C219.452 28.459 191 15.784 163.213 21.74A65.586 65.586 0 0 0 52.096 45.22a64.716 64.716 0 0 0-43.23 31.36c-14.31 24.602-11.061 55.634 8.033 76.74a64.665 64.665 0 0 0 5.525 53.102c14.174 24.65 42.644 37.324 70.446 31.36a64.72 64.72 0 0 0 48.754 21.744c28.481.025 53.714-18.361 62.414-45.481a64.767 64.767 0 0 0 43.229-31.36c14.137-24.558 10.875-55.423-8.083-76.483Zm-97.56 136.338a48.397 48.397 0 0 1-31.105-11.255l1.535-.87 51.67-29.825a8.595 8.595 0 0 0 4.247-7.367v-72.85l21.845 12.636c.218.111.37.32.409.563v60.367c-.056 26.818-21.783 48.545-48.601 48.601Zm-104.466-44.61a48.345 48.345 0 0 1-5.781-32.589l1.534.921 51.722 29.826a8.339 8.339 0 0 0 8.441 0l63.181-36.425v25.221a.87.87 0 0 1-.358.665l-52.335 30.184c-23.257 13.398-52.97 5.431-66.404-17.803ZM23.549 85.38a48.499 48.499 0 0 1 25.58-21.333v61.39a8.288 8.288 0 0 0 4.195 7.316l62.874 36.272-21.845 12.636a.819.819 0 0 1-.767 0L41.353 151.53c-23.211-13.454-31.171-43.144-17.804-66.405v.256Zm179.466 41.695-63.08-36.63L161.73 77.86a.819.819 0 0 1 .768 0l52.233 30.184a48.6 48.6 0 0 1-7.316 87.635v-61.391a8.544 8.544 0 0 0-4.4-7.213Zm21.742-32.69-1.535-.922-51.619-30.081a8.39 8.39 0 0 0-8.492 0L99.98 99.808V74.587a.716.716 0 0 1 .307-.665l52.233-30.133a48.652 48.652 0 0 1 72.236 50.391v.205ZM88.061 139.097l-21.845-12.585a.87.87 0 0 1-.41-.614V65.685a48.652 48.652 0 0 1 79.757-37.346l-1.535.87-51.67 29.825a8.595 8.595 0 0 0-4.246 7.367l-.051 72.697Zm11.868-25.58 28.138-16.217 28.188 16.218v32.434l-28.086 16.218-28.188-16.218-.052-32.434Z" />
36
- </svg>
37
- );
38
- }
39
-
40
- export function ClaudeIcon({ size = '1em', ...rest }) {
41
- return (
42
- <svg width={size} height={size} viewBox="0 0 256 257" aria-hidden="true" {...rest}>
43
- <path fill="currentColor" d="m50.228 170.321 50.357-28.257.843-2.463-.843-1.361h-2.462l-8.426-.518-28.775-.778-24.952-1.037-24.175-1.296-6.092-1.297L0 125.796l.583-3.759 5.12-3.434 7.324.648 16.202 1.101 24.304 1.685 17.629 1.037 26.118 2.722h4.148l.583-1.685-1.426-1.037-1.101-1.037-25.147-17.045-27.22-18.017-14.258-10.37-7.713-5.25-3.888-4.925-1.685-10.758 7-7.713 9.397.649 2.398.648 9.527 7.323 20.35 15.75L94.817 91.9l3.889 3.24 1.555-1.102.195-.777-1.75-2.917-14.453-26.118-15.425-26.572-6.87-11.018-1.814-6.61c-.648-2.723-1.102-4.991-1.102-7.778l7.972-10.823L71.42 0 82.05 1.426l4.472 3.888 6.61 15.101 10.694 23.786 16.591 32.34 4.861 9.592 2.592 8.879.973 2.722h1.685v-1.556l1.36-18.211 2.528-22.36 2.463-28.776.843-8.1 4.018-9.722 7.971-5.25 6.222 2.981 5.12 7.324-.713 4.73-3.046 19.768-5.962 30.98-3.889 20.739h2.268l2.593-2.593 10.499-13.934 17.628-22.036 7.778-8.749 9.073-9.657 5.833-4.601h11.018l8.1 12.055-3.628 12.443-11.342 14.388-9.398 12.184-13.48 18.147-8.426 14.518.778 1.166 2.01-.194 30.46-6.481 16.462-2.982 19.637-3.37 8.88 4.148.971 4.213-3.5 8.62-20.998 5.184-24.628 4.926-36.682 8.685-.454.324.519.648 16.526 1.555 7.065.389h17.304l32.21 2.398 8.426 5.574 5.055 6.805-.843 5.184-12.962 6.611-17.498-4.148-40.83-9.721-14-3.5h-1.944v1.167l11.666 11.406 21.387 19.314 26.767 24.887 1.36 6.157-3.434 4.86-3.63-.518-23.526-17.693-9.073-7.972-20.545-17.304h-1.36v1.814l4.73 6.935 25.017 37.59 1.296 11.536-1.814 3.76-6.481 2.268-7.13-1.297-14.647-20.544-15.1-23.138-12.185-20.739-1.49.843-7.194 77.448-3.37 3.953-7.778 2.981-6.48-4.925-3.436-7.972 3.435-15.749 4.148-20.544 3.37-16.333 3.046-20.285 1.815-6.74-.13-.454-1.49.194-15.295 20.999-23.267 31.433-18.406 19.702-4.407 1.75-7.648-3.954.713-7.064 4.277-6.286 25.47-32.405 15.36-20.092 9.917-11.6-.065-1.686h-.583L44.07 198.125l-12.055 1.555-5.185-4.86.648-7.972 2.463-2.593 20.35-13.999-.064.065Z" />
44
- </svg>
45
- );
46
- }
47
-
48
- export function PerplexityIcon({ size = '1em', ...rest }) {
49
- return (
50
- <svg width={size} height={size} viewBox="0 0 48 48" fill="none" aria-hidden="true" {...rest}>
51
- <g stroke="currentColor" strokeLinecap="round" strokeLinejoin="round">
52
- <path d="M24 4.5v39M13.73 16.573v-9.99L24 16.573m0 14.5L13.73 41.417V27.01L24 16.573m0 0l10.27-9.99v9.99" />
53
- <path d="M13.73 31.396H9.44V16.573h29.12v14.823h-4.29" />
54
- <path d="M24 16.573L34.27 27.01v14.407L24 31.073" />
55
- </g>
56
- </svg>
57
- );
58
- }
59
-
60
- export function CursorIcon({ size = '1em', ...rest }) {
61
- return (
62
- <svg width={size} height={size} viewBox="0 0 466.73 532.09" fill="currentColor" aria-hidden="true" {...rest}>
63
- <path d="M457.43,125.94L244.42,2.96c-6.84-3.95-15.28-3.95-22.12,0L9.3,125.94c-5.75,3.32-9.3,9.46-9.3,16.11v247.99c0,6.65,3.55,12.79,9.3,16.11l213.01,122.98c6.84,3.95,15.28,3.95,22.12,0l213.01-122.98c5.75-3.32,9.3-9.46,9.3-16.11v-247.99c0-6.65-3.55-12.79-9.3-16.11h-.01ZM444.05,151.99l-205.63,356.16c-1.39,2.4-5.06,1.42-5.06-1.36v-233.21c0-4.66-2.49-8.97-6.53-11.31L24.87,145.67c-2.4-1.39-1.42-5.06,1.36-5.06h411.26c5.84,0,9.49,6.33,6.57,11.39h-.01Z" />
64
- </svg>
65
- );
66
- }
67
-
68
- export function VscodeIcon({ size = '1em', ...rest }) {
69
- return (
70
- <svg width={size} height={size} viewBox="0 0 100 100" fill="none" aria-hidden="true" {...rest}>
71
- <mask
72
- id="velu-vsc-mask"
73
- width="100"
74
- height="100"
75
- x="0"
76
- y="0"
77
- maskUnits="userSpaceOnUse"
78
- style={{ maskType: 'alpha' }}
79
- >
80
- <path
81
- fill="#fff"
82
- fillRule="evenodd"
83
- clipRule="evenodd"
84
- d="M70.912 99.317a6.223 6.223 0 0 0 4.96-.19l20.589-9.907A6.25 6.25 0 0 0 100 83.587V16.413a6.25 6.25 0 0 0-3.54-5.632L75.874.874a6.226 6.226 0 0 0-7.104 1.21L29.355 38.04 12.187 25.01a4.162 4.162 0 0 0-5.318.236l-5.506 5.009a4.168 4.168 0 0 0-.004 6.162L16.247 50 1.36 63.583a4.168 4.168 0 0 0 .004 6.162l5.506 5.01a4.162 4.162 0 0 0 5.318.236l17.168-13.032L68.77 97.917a6.217 6.217 0 0 0 2.143 1.4ZM75.015 27.3 45.11 50l29.906 22.701V27.3Z"
85
- />
86
- </mask>
87
- <g mask="url(#velu-vsc-mask)">
88
- <path
89
- fill="currentColor"
90
- d="M96.461 10.796 75.857.876a6.23 6.23 0 0 0-7.107 1.207l-67.451 61.5a4.167 4.167 0 0 0 .004 6.162l5.51 5.009a4.167 4.167 0 0 0 5.32.236l81.228-61.62c2.725-2.067 6.639-.124 6.639 3.297v-.24a6.25 6.25 0 0 0-3.539-5.63Z"
91
- />
92
- <path
93
- fill="currentColor"
94
- d="m96.461 89.204-20.604 9.92a6.229 6.229 0 0 1-7.107-1.207l-67.451-61.5a4.167 4.167 0 0 1 .004-6.162l5.51-5.009a4.167 4.167 0 0 1 5.32-.236l81.228 61.62c2.725 2.067 6.639.124 6.639-3.297v.24a6.25 6.25 0 0 1-3.539 5.63Z"
95
- />
96
- <path
97
- fill="currentColor"
98
- d="M75.858 99.126a6.232 6.232 0 0 1-7.108-1.21c2.306 2.307 6.25.674 6.25-2.588V4.672c0-3.262-3.944-4.895-6.25-2.589a6.232 6.232 0 0 1 7.108-1.21l20.6 9.908A6.25 6.25 0 0 1 100 16.413v67.174a6.25 6.25 0 0 1-3.541 5.633l-20.601 9.906Z"
99
- />
100
- </g>
101
- </svg>
102
- );
103
- }
1
+ import React from 'react';
2
+
3
+ /**
4
+ * Brand glyphs for the contextual menu's "Open in <tool>" / "Connect to <IDE>"
5
+ * actions. Sourced from svgl.app and inlined (the project inlines icons as JSX,
6
+ * like lucide — no SVG loader). Each takes a `size` prop, mirroring lucide's
7
+ * icon API so they're drop-in in the menu.
8
+ *
9
+ * ALL marks use `currentColor` so the icon column reads as one uniform set:
10
+ * muted/grey at rest, accent on hover (matching the lucide icons beside them).
11
+ * The brand glyphs keep their distinctive shapes; only the fill follows the
12
+ * menu's text/hover color across light + dark.
13
+ */
14
+
15
+ export function MarkdownIcon({ size = '1em', ...rest }) {
16
+ return (
17
+ <svg width={size} height={size} viewBox="0 0 208 128" fill="none" aria-hidden="true" {...rest}>
18
+ <path
19
+ fill="none"
20
+ stroke="currentColor"
21
+ strokeWidth="10"
22
+ d="M15 5h178a10 10 0 0 1 10 10v98a10 10 0 0 1-10 10H15a10 10 0 0 1-10-10V15A10 10 0 0 1 15 5z"
23
+ />
24
+ <path
25
+ fill="currentColor"
26
+ d="M30 98V30h20l20 25 20-25h20v68H90V59L70 84 50 59v39H30zm125 0-30-33h20V30h20v35h20l-30 33z"
27
+ />
28
+ </svg>
29
+ );
30
+ }
31
+
32
+ export function OpenAIIcon({ size = '1em', ...rest }) {
33
+ return (
34
+ <svg width={size} height={size} viewBox="0 0 256 260" fill="currentColor" aria-hidden="true" {...rest}>
35
+ <path d="M239.184 106.203a64.716 64.716 0 0 0-5.576-53.103C219.452 28.459 191 15.784 163.213 21.74A65.586 65.586 0 0 0 52.096 45.22a64.716 64.716 0 0 0-43.23 31.36c-14.31 24.602-11.061 55.634 8.033 76.74a64.665 64.665 0 0 0 5.525 53.102c14.174 24.65 42.644 37.324 70.446 31.36a64.72 64.72 0 0 0 48.754 21.744c28.481.025 53.714-18.361 62.414-45.481a64.767 64.767 0 0 0 43.229-31.36c14.137-24.558 10.875-55.423-8.083-76.483Zm-97.56 136.338a48.397 48.397 0 0 1-31.105-11.255l1.535-.87 51.67-29.825a8.595 8.595 0 0 0 4.247-7.367v-72.85l21.845 12.636c.218.111.37.32.409.563v60.367c-.056 26.818-21.783 48.545-48.601 48.601Zm-104.466-44.61a48.345 48.345 0 0 1-5.781-32.589l1.534.921 51.722 29.826a8.339 8.339 0 0 0 8.441 0l63.181-36.425v25.221a.87.87 0 0 1-.358.665l-52.335 30.184c-23.257 13.398-52.97 5.431-66.404-17.803ZM23.549 85.38a48.499 48.499 0 0 1 25.58-21.333v61.39a8.288 8.288 0 0 0 4.195 7.316l62.874 36.272-21.845 12.636a.819.819 0 0 1-.767 0L41.353 151.53c-23.211-13.454-31.171-43.144-17.804-66.405v.256Zm179.466 41.695-63.08-36.63L161.73 77.86a.819.819 0 0 1 .768 0l52.233 30.184a48.6 48.6 0 0 1-7.316 87.635v-61.391a8.544 8.544 0 0 0-4.4-7.213Zm21.742-32.69-1.535-.922-51.619-30.081a8.39 8.39 0 0 0-8.492 0L99.98 99.808V74.587a.716.716 0 0 1 .307-.665l52.233-30.133a48.652 48.652 0 0 1 72.236 50.391v.205ZM88.061 139.097l-21.845-12.585a.87.87 0 0 1-.41-.614V65.685a48.652 48.652 0 0 1 79.757-37.346l-1.535.87-51.67 29.825a8.595 8.595 0 0 0-4.246 7.367l-.051 72.697Zm11.868-25.58 28.138-16.217 28.188 16.218v32.434l-28.086 16.218-28.188-16.218-.052-32.434Z" />
36
+ </svg>
37
+ );
38
+ }
39
+
40
+ export function ClaudeIcon({ size = '1em', ...rest }) {
41
+ return (
42
+ <svg width={size} height={size} viewBox="0 0 256 257" aria-hidden="true" {...rest}>
43
+ <path fill="currentColor" d="m50.228 170.321 50.357-28.257.843-2.463-.843-1.361h-2.462l-8.426-.518-28.775-.778-24.952-1.037-24.175-1.296-6.092-1.297L0 125.796l.583-3.759 5.12-3.434 7.324.648 16.202 1.101 24.304 1.685 17.629 1.037 26.118 2.722h4.148l.583-1.685-1.426-1.037-1.101-1.037-25.147-17.045-27.22-18.017-14.258-10.37-7.713-5.25-3.888-4.925-1.685-10.758 7-7.713 9.397.649 2.398.648 9.527 7.323 20.35 15.75L94.817 91.9l3.889 3.24 1.555-1.102.195-.777-1.75-2.917-14.453-26.118-15.425-26.572-6.87-11.018-1.814-6.61c-.648-2.723-1.102-4.991-1.102-7.778l7.972-10.823L71.42 0 82.05 1.426l4.472 3.888 6.61 15.101 10.694 23.786 16.591 32.34 4.861 9.592 2.592 8.879.973 2.722h1.685v-1.556l1.36-18.211 2.528-22.36 2.463-28.776.843-8.1 4.018-9.722 7.971-5.25 6.222 2.981 5.12 7.324-.713 4.73-3.046 19.768-5.962 30.98-3.889 20.739h2.268l2.593-2.593 10.499-13.934 17.628-22.036 7.778-8.749 9.073-9.657 5.833-4.601h11.018l8.1 12.055-3.628 12.443-11.342 14.388-9.398 12.184-13.48 18.147-8.426 14.518.778 1.166 2.01-.194 30.46-6.481 16.462-2.982 19.637-3.37 8.88 4.148.971 4.213-3.5 8.62-20.998 5.184-24.628 4.926-36.682 8.685-.454.324.519.648 16.526 1.555 7.065.389h17.304l32.21 2.398 8.426 5.574 5.055 6.805-.843 5.184-12.962 6.611-17.498-4.148-40.83-9.721-14-3.5h-1.944v1.167l11.666 11.406 21.387 19.314 26.767 24.887 1.36 6.157-3.434 4.86-3.63-.518-23.526-17.693-9.073-7.972-20.545-17.304h-1.36v1.814l4.73 6.935 25.017 37.59 1.296 11.536-1.814 3.76-6.481 2.268-7.13-1.297-14.647-20.544-15.1-23.138-12.185-20.739-1.49.843-7.194 77.448-3.37 3.953-7.778 2.981-6.48-4.925-3.436-7.972 3.435-15.749 4.148-20.544 3.37-16.333 3.046-20.285 1.815-6.74-.13-.454-1.49.194-15.295 20.999-23.267 31.433-18.406 19.702-4.407 1.75-7.648-3.954.713-7.064 4.277-6.286 25.47-32.405 15.36-20.092 9.917-11.6-.065-1.686h-.583L44.07 198.125l-12.055 1.555-5.185-4.86.648-7.972 2.463-2.593 20.35-13.999-.064.065Z" />
44
+ </svg>
45
+ );
46
+ }
47
+
48
+ export function PerplexityIcon({ size = '1em', ...rest }) {
49
+ return (
50
+ <svg width={size} height={size} viewBox="0 0 48 48" fill="none" aria-hidden="true" {...rest}>
51
+ <g stroke="currentColor" strokeLinecap="round" strokeLinejoin="round">
52
+ <path d="M24 4.5v39M13.73 16.573v-9.99L24 16.573m0 14.5L13.73 41.417V27.01L24 16.573m0 0l10.27-9.99v9.99" />
53
+ <path d="M13.73 31.396H9.44V16.573h29.12v14.823h-4.29" />
54
+ <path d="M24 16.573L34.27 27.01v14.407L24 31.073" />
55
+ </g>
56
+ </svg>
57
+ );
58
+ }
59
+
60
+ export function CursorIcon({ size = '1em', ...rest }) {
61
+ return (
62
+ <svg width={size} height={size} viewBox="0 0 466.73 532.09" fill="currentColor" aria-hidden="true" {...rest}>
63
+ <path d="M457.43,125.94L244.42,2.96c-6.84-3.95-15.28-3.95-22.12,0L9.3,125.94c-5.75,3.32-9.3,9.46-9.3,16.11v247.99c0,6.65,3.55,12.79,9.3,16.11l213.01,122.98c6.84,3.95,15.28,3.95,22.12,0l213.01-122.98c5.75-3.32,9.3-9.46,9.3-16.11v-247.99c0-6.65-3.55-12.79-9.3-16.11h-.01ZM444.05,151.99l-205.63,356.16c-1.39,2.4-5.06,1.42-5.06-1.36v-233.21c0-4.66-2.49-8.97-6.53-11.31L24.87,145.67c-2.4-1.39-1.42-5.06,1.36-5.06h411.26c5.84,0,9.49,6.33,6.57,11.39h-.01Z" />
64
+ </svg>
65
+ );
66
+ }
67
+
68
+ export function VscodeIcon({ size = '1em', ...rest }) {
69
+ return (
70
+ <svg width={size} height={size} viewBox="0 0 100 100" fill="none" aria-hidden="true" {...rest}>
71
+ <mask
72
+ id="velu-vsc-mask"
73
+ width="100"
74
+ height="100"
75
+ x="0"
76
+ y="0"
77
+ maskUnits="userSpaceOnUse"
78
+ style={{ maskType: 'alpha' }}
79
+ >
80
+ <path
81
+ fill="#fff"
82
+ fillRule="evenodd"
83
+ clipRule="evenodd"
84
+ d="M70.912 99.317a6.223 6.223 0 0 0 4.96-.19l20.589-9.907A6.25 6.25 0 0 0 100 83.587V16.413a6.25 6.25 0 0 0-3.54-5.632L75.874.874a6.226 6.226 0 0 0-7.104 1.21L29.355 38.04 12.187 25.01a4.162 4.162 0 0 0-5.318.236l-5.506 5.009a4.168 4.168 0 0 0-.004 6.162L16.247 50 1.36 63.583a4.168 4.168 0 0 0 .004 6.162l5.506 5.01a4.162 4.162 0 0 0 5.318.236l17.168-13.032L68.77 97.917a6.217 6.217 0 0 0 2.143 1.4ZM75.015 27.3 45.11 50l29.906 22.701V27.3Z"
85
+ />
86
+ </mask>
87
+ <g mask="url(#velu-vsc-mask)">
88
+ <path
89
+ fill="currentColor"
90
+ d="M96.461 10.796 75.857.876a6.23 6.23 0 0 0-7.107 1.207l-67.451 61.5a4.167 4.167 0 0 0 .004 6.162l5.51 5.009a4.167 4.167 0 0 0 5.32.236l81.228-61.62c2.725-2.067 6.639-.124 6.639 3.297v-.24a6.25 6.25 0 0 0-3.539-5.63Z"
91
+ />
92
+ <path
93
+ fill="currentColor"
94
+ d="m96.461 89.204-20.604 9.92a6.229 6.229 0 0 1-7.107-1.207l-67.451-61.5a4.167 4.167 0 0 1 .004-6.162l5.51-5.009a4.167 4.167 0 0 1 5.32-.236l81.228 61.62c2.725 2.067 6.639.124 6.639-3.297v.24a6.25 6.25 0 0 1-3.539 5.63Z"
95
+ />
96
+ <path
97
+ fill="currentColor"
98
+ d="M75.858 99.126a6.232 6.232 0 0 1-7.108-1.21c2.306 2.307 6.25.674 6.25-2.588V4.672c0-3.262-3.944-4.895-6.25-2.589a6.232 6.232 0 0 1 7.108-1.21l20.6 9.908A6.25 6.25 0 0 1 100 16.413v67.174a6.25 6.25 0 0 1-3.541 5.633l-20.601 9.906Z"
99
+ />
100
+ </g>
101
+ </svg>
102
+ );
103
+ }
@@ -1,100 +1,100 @@
1
- // Per-component option schemas — the props whose wrong value would otherwise
2
- // render incorrectly *silently*. Deliberately small and high-signal; extend a
3
- // component's entry here when it gains a new constrained option.
4
- //
5
- // Pure data + a pure validator (no React, no other imports) so BOTH sides can
6
- // use it: the live MDX registry (velu-ui/mdx-components.jsx) validates at
7
- // render time, and `velu validate` (velu-cli) imports this same module to
8
- // statically check literal attributes — one source of truth, no drift.
9
-
10
- // Canonical accepted values (must match the components):
11
- // Callout — VARIANTS keys; the component is CASE-SENSITIVE (VARIANTS[type]).
12
- // MethodBadge — METHODS; the component lower-cases the input first.
13
- export const CALLOUT_TYPES = ['note', 'warning', 'info', 'tip', 'check', 'danger', 'callout'];
14
- export const METHOD_NAMES = ['get', 'post', 'put', 'patch', 'delete'];
15
-
16
- // schema: { enums: { prop: { values, caseSensitive } }, required: [prop, …] }
17
- const SCHEMAS = {
18
- Callout: { enums: { type: { values: CALLOUT_TYPES, caseSensitive: true } } },
19
- MethodBadge: { enums: { method: { values: METHOD_NAMES, caseSensitive: false } } },
20
- ApiPath: { enums: { method: { values: METHOD_NAMES, caseSensitive: false } } },
21
- Image: { required: ['src'] },
22
- };
23
-
24
- // Smallest edit distance match within a set (for "did you mean"). Tiny inputs.
25
- function closest(value, values) {
26
- const v = String(value).toLowerCase();
27
- let best = null;
28
- let bestD = Infinity;
29
- for (const cand of values) {
30
- const a = v;
31
- const b = cand.toLowerCase();
32
- // inline Levenshtein
33
- const m = a.length;
34
- const n = b.length;
35
- const d = Array.from({ length: n + 1 }, (_, i) => i);
36
- for (let i = 1; i <= m; i++) {
37
- let prev = d[0];
38
- d[0] = i;
39
- for (let j = 1; j <= n; j++) {
40
- const tmp = d[j];
41
- d[j] = Math.min(d[j] + 1, d[j - 1] + 1, prev + (a[i - 1] === b[j - 1] ? 0 : 1));
42
- prev = tmp;
43
- }
44
- }
45
- if (d[n] < bestD) {
46
- bestD = d[n];
47
- best = cand;
48
- }
49
- }
50
- return bestD <= 3 ? best : null;
51
- }
52
-
53
- /**
54
- * Validate a component's props against its schema.
55
- * @param {string} name component tag name
56
- * @param {object} props props passed to it
57
- * @param {{ checkRequired?: boolean }} [opts] static callers pass
58
- * checkRequired:false because a prop supplied via a {expression}
59
- * isn't a literal they can see, so "missing required" would be a
60
- * false positive.
61
- * @returns an issue-shaped object (category 'invalid-props') or null if valid.
62
- * { category, title, detail, hint, suggestion }
63
- */
64
- export function validateProps(name, props = {}, opts = {}) {
65
- const { checkRequired = true } = opts;
66
- const schema = SCHEMAS[name];
67
- if (!schema) return null;
68
-
69
- for (const req of checkRequired ? schema.required || [] : []) {
70
- const v = props[req];
71
- if (v == null || v === '') {
72
- return {
73
- category: 'invalid-props',
74
- title: `<${name}> is missing the required "${req}" prop`,
75
- hint: `Add ${req}="…" to the component.`,
76
- };
77
- }
78
- }
79
-
80
- for (const [prop, rule] of Object.entries(schema.enums || {})) {
81
- if (!(prop in props) || props[prop] == null) continue;
82
- const raw = props[prop];
83
- const ok = rule.caseSensitive
84
- ? rule.values.includes(raw)
85
- : rule.values.map((s) => s.toLowerCase()).includes(String(raw).toLowerCase());
86
- if (!ok) {
87
- const guess = closest(raw, rule.values);
88
- return {
89
- category: 'invalid-props',
90
- title: `Invalid "${prop}" on <${name}>: "${raw}"`,
91
- detail: `Expected one of: ${rule.values.join(', ')}.`,
92
- hint: guess ? `Did you mean "${guess}"?` : '',
93
- };
94
- }
95
- }
96
-
97
- return null;
98
- }
99
-
100
- export default validateProps;
1
+ // Per-component option schemas — the props whose wrong value would otherwise
2
+ // render incorrectly *silently*. Deliberately small and high-signal; extend a
3
+ // component's entry here when it gains a new constrained option.
4
+ //
5
+ // Pure data + a pure validator (no React, no other imports) so BOTH sides can
6
+ // use it: the live MDX registry (velu-ui/mdx-components.jsx) validates at
7
+ // render time, and `velu validate` (velu-cli) imports this same module to
8
+ // statically check literal attributes — one source of truth, no drift.
9
+
10
+ // Canonical accepted values (must match the components):
11
+ // Callout — VARIANTS keys; the component is CASE-SENSITIVE (VARIANTS[type]).
12
+ // MethodBadge — METHODS; the component lower-cases the input first.
13
+ export const CALLOUT_TYPES = ['note', 'warning', 'info', 'tip', 'check', 'danger', 'callout'];
14
+ export const METHOD_NAMES = ['get', 'post', 'put', 'patch', 'delete'];
15
+
16
+ // schema: { enums: { prop: { values, caseSensitive } }, required: [prop, …] }
17
+ const SCHEMAS = {
18
+ Callout: { enums: { type: { values: CALLOUT_TYPES, caseSensitive: true } } },
19
+ MethodBadge: { enums: { method: { values: METHOD_NAMES, caseSensitive: false } } },
20
+ ApiPath: { enums: { method: { values: METHOD_NAMES, caseSensitive: false } } },
21
+ Image: { required: ['src'] },
22
+ };
23
+
24
+ // Smallest edit distance match within a set (for "did you mean"). Tiny inputs.
25
+ function closest(value, values) {
26
+ const v = String(value).toLowerCase();
27
+ let best = null;
28
+ let bestD = Infinity;
29
+ for (const cand of values) {
30
+ const a = v;
31
+ const b = cand.toLowerCase();
32
+ // inline Levenshtein
33
+ const m = a.length;
34
+ const n = b.length;
35
+ const d = Array.from({ length: n + 1 }, (_, i) => i);
36
+ for (let i = 1; i <= m; i++) {
37
+ let prev = d[0];
38
+ d[0] = i;
39
+ for (let j = 1; j <= n; j++) {
40
+ const tmp = d[j];
41
+ d[j] = Math.min(d[j] + 1, d[j - 1] + 1, prev + (a[i - 1] === b[j - 1] ? 0 : 1));
42
+ prev = tmp;
43
+ }
44
+ }
45
+ if (d[n] < bestD) {
46
+ bestD = d[n];
47
+ best = cand;
48
+ }
49
+ }
50
+ return bestD <= 3 ? best : null;
51
+ }
52
+
53
+ /**
54
+ * Validate a component's props against its schema.
55
+ * @param {string} name component tag name
56
+ * @param {object} props props passed to it
57
+ * @param {{ checkRequired?: boolean }} [opts] static callers pass
58
+ * checkRequired:false because a prop supplied via a {expression}
59
+ * isn't a literal they can see, so "missing required" would be a
60
+ * false positive.
61
+ * @returns an issue-shaped object (category 'invalid-props') or null if valid.
62
+ * { category, title, detail, hint, suggestion }
63
+ */
64
+ export function validateProps(name, props = {}, opts = {}) {
65
+ const { checkRequired = true } = opts;
66
+ const schema = SCHEMAS[name];
67
+ if (!schema) return null;
68
+
69
+ for (const req of checkRequired ? schema.required || [] : []) {
70
+ const v = props[req];
71
+ if (v == null || v === '') {
72
+ return {
73
+ category: 'invalid-props',
74
+ title: `<${name}> is missing the required "${req}" prop`,
75
+ hint: `Add ${req}="…" to the component.`,
76
+ };
77
+ }
78
+ }
79
+
80
+ for (const [prop, rule] of Object.entries(schema.enums || {})) {
81
+ if (!(prop in props) || props[prop] == null) continue;
82
+ const raw = props[prop];
83
+ const ok = rule.caseSensitive
84
+ ? rule.values.includes(raw)
85
+ : rule.values.map((s) => s.toLowerCase()).includes(String(raw).toLowerCase());
86
+ if (!ok) {
87
+ const guess = closest(raw, rule.values);
88
+ return {
89
+ category: 'invalid-props',
90
+ title: `Invalid "${prop}" on <${name}>: "${raw}"`,
91
+ detail: `Expected one of: ${rule.values.join(', ')}.`,
92
+ hint: guess ? `Did you mean "${guess}"?` : '',
93
+ };
94
+ }
95
+ }
96
+
97
+ return null;
98
+ }
99
+
100
+ export default validateProps;
@@ -1,64 +1,64 @@
1
- /**
2
- * copyText — copy a string to the clipboard, working in BOTH secure and
3
- * insecure contexts.
4
- *
5
- * `navigator.clipboard` only exists in a secure context (HTTPS or
6
- * localhost). On a plain-HTTP origin — e.g. previewing the dev server
7
- * over the LAN at http://<ip>:8358 on a phone — it's `undefined`, so a
8
- * `if (!navigator.clipboard) return` guard makes copy buttons silently
9
- * no-op. This util falls back to the legacy `execCommand('copy')` via a
10
- * hidden textarea so copy still works on those origins.
11
- *
12
- * Must be called from a user gesture (click) — both paths require it.
13
- * Returns a Promise: resolves on success, rejects on failure.
14
- */
15
- export default function copyText(text) {
16
- const str = String(text ?? '');
17
-
18
- // Preferred path — async Clipboard API (secure contexts only).
19
- if (
20
- typeof navigator !== 'undefined' &&
21
- navigator.clipboard &&
22
- typeof window !== 'undefined' &&
23
- window.isSecureContext
24
- ) {
25
- return navigator.clipboard.writeText(str);
26
- }
27
-
28
- // Fallback — hidden <textarea> + execCommand, for insecure origins.
29
- return new Promise((resolve, reject) => {
30
- if (typeof document === 'undefined') {
31
- reject(new Error('copyText: no document'));
32
- return;
33
- }
34
- const ta = document.createElement('textarea');
35
- ta.value = str;
36
- ta.setAttribute('readonly', '');
37
- // Keep it out of view and inert, but still selectable.
38
- ta.style.position = 'fixed';
39
- ta.style.top = '0';
40
- ta.style.left = '0';
41
- ta.style.inlineSize = '1px';
42
- ta.style.blockSize = '1px';
43
- ta.style.padding = '0';
44
- ta.style.border = 'none';
45
- ta.style.opacity = '0';
46
- document.body.appendChild(ta);
47
- ta.focus();
48
- ta.select();
49
- try {
50
- ta.setSelectionRange(0, str.length);
51
- } catch {
52
- /* some browsers reject setSelectionRange on a readonly field */
53
- }
54
- let ok = false;
55
- try {
56
- ok = document.execCommand('copy');
57
- } catch {
58
- ok = false;
59
- }
60
- document.body.removeChild(ta);
61
- if (ok) resolve();
62
- else reject(new Error('copyText: execCommand copy failed'));
63
- });
64
- }
1
+ /**
2
+ * copyText — copy a string to the clipboard, working in BOTH secure and
3
+ * insecure contexts.
4
+ *
5
+ * `navigator.clipboard` only exists in a secure context (HTTPS or
6
+ * localhost). On a plain-HTTP origin — e.g. previewing the dev server
7
+ * over the LAN at http://<ip>:8358 on a phone — it's `undefined`, so a
8
+ * `if (!navigator.clipboard) return` guard makes copy buttons silently
9
+ * no-op. This util falls back to the legacy `execCommand('copy')` via a
10
+ * hidden textarea so copy still works on those origins.
11
+ *
12
+ * Must be called from a user gesture (click) — both paths require it.
13
+ * Returns a Promise: resolves on success, rejects on failure.
14
+ */
15
+ export default function copyText(text) {
16
+ const str = String(text ?? '');
17
+
18
+ // Preferred path — async Clipboard API (secure contexts only).
19
+ if (
20
+ typeof navigator !== 'undefined' &&
21
+ navigator.clipboard &&
22
+ typeof window !== 'undefined' &&
23
+ window.isSecureContext
24
+ ) {
25
+ return navigator.clipboard.writeText(str);
26
+ }
27
+
28
+ // Fallback — hidden <textarea> + execCommand, for insecure origins.
29
+ return new Promise((resolve, reject) => {
30
+ if (typeof document === 'undefined') {
31
+ reject(new Error('copyText: no document'));
32
+ return;
33
+ }
34
+ const ta = document.createElement('textarea');
35
+ ta.value = str;
36
+ ta.setAttribute('readonly', '');
37
+ // Keep it out of view and inert, but still selectable.
38
+ ta.style.position = 'fixed';
39
+ ta.style.top = '0';
40
+ ta.style.left = '0';
41
+ ta.style.inlineSize = '1px';
42
+ ta.style.blockSize = '1px';
43
+ ta.style.padding = '0';
44
+ ta.style.border = 'none';
45
+ ta.style.opacity = '0';
46
+ document.body.appendChild(ta);
47
+ ta.focus();
48
+ ta.select();
49
+ try {
50
+ ta.setSelectionRange(0, str.length);
51
+ } catch {
52
+ /* some browsers reject setSelectionRange on a readonly field */
53
+ }
54
+ let ok = false;
55
+ try {
56
+ ok = document.execCommand('copy');
57
+ } catch {
58
+ ok = false;
59
+ }
60
+ document.body.removeChild(ta);
61
+ if (ok) resolve();
62
+ else reject(new Error('copyText: execCommand copy failed'));
63
+ });
64
+ }