@veluai/velu 0.2.25 → 0.2.27

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,102 +1,102 @@
1
- import React, { useState } from 'react';
2
- import resolveIcon from '../lib/resolveIcon.jsx';
3
- import Cluster from '../primitives/Cluster.jsx';
4
- import copyText from '../lib/copyText.js';
5
- import MethodBadge from './MethodBadge.jsx';
6
- import ApiPath from './ApiPath.jsx';
7
-
8
- /**
9
- * TryItBar — compact endpoint row: method badge + path + copy icon + a
10
- * method-colored "Try It" CTA. Mirrors Mintlify's docs "try-it" row.
11
- *
12
- * <TryItBar method="POST" path="/project/preview/{projectId}" />
13
- *
14
- * CTA is a dummy `<button>` (no fetch / playground wiring) — slot a
15
- * handler in via the `onTry` prop when there's a real client. Copy
16
- * writes the full "METHOD path" string to clipboard.
17
- */
18
-
19
- export default function TryItBar({
20
- method = 'GET',
21
- path = '',
22
- cta = 'Try It',
23
- onTry,
24
- loading = false,
25
- className = '',
26
- ...rest
27
- }) {
28
- const [copied, setCopied] = useState(false);
29
- const key = String(method).toLowerCase();
30
-
31
- function copy() {
32
- copyText(`${String(method).toUpperCase()} ${path}`).then(
33
- () => {
34
- setCopied(true);
35
- setTimeout(() => setCopied(false), 1400);
36
- },
37
- () => {
38
- /* silently no-op */
39
- },
40
- );
41
- }
42
-
43
- const cls = `velu-try-it velu-try-it--${key} ${className}`.trim();
44
-
45
- return (
46
- // Outer bar is a Cluster — the inner bordered row and the Try It
47
- // button are its two children, so they wrap as a unit on narrow
48
- // widths (Try It drops below the row).
49
- <Cluster
50
- space="var(--s-1)"
51
- justify="flex-end"
52
- align="center"
53
- className={cls}
54
- {...rest}
55
- >
56
- {/* Inner bordered group. The method pill + url segments live in
57
- their own Cluster that wraps internally; the copy button is a
58
- separate sibling pinned to the top-right (align-self:
59
- flex-start) so it never drops below the wrapped path. */}
60
- <div className="velu-try-it__row">
61
- <Cluster
62
- space="var(--s-1)"
63
- align="center"
64
- className="velu-try-it__endpoint"
65
- >
66
- <MethodBadge method={method} />
67
- <ApiPath method={method} path={path} />
68
- </Cluster>
69
- <button
70
- type="button"
71
- className="velu-try-it__copy"
72
- onClick={copy}
73
- aria-label={copied ? 'Copied' : 'Copy endpoint'}
74
- title={copied ? 'Copied' : 'Copy'}
75
- >
76
- {resolveIcon(copied ? 'check' : 'copy', { size: '1em' })}
77
- </button>
78
- </div>
79
- <button
80
- type="button"
81
- className="velu-try-it__cta"
82
- onClick={onTry}
83
- data-loading={loading ? 'true' : undefined}
84
- disabled={loading || undefined}
85
- aria-busy={loading || undefined}
86
- >
87
- {/* Two stacked layers swap with a vertical slide: the label slides
88
- down and out the bottom while the spinner slides in from the top.
89
- overflow:hidden on the button clips both off-screen states. */}
90
- <span className="velu-try-it__cta-label">
91
- {cta}
92
- <span className="velu-try-it__cta-icon" aria-hidden="true">
93
- {resolveIcon('chevron-right', { size: '1em' })}
94
- </span>
95
- </span>
96
- <span className="velu-try-it__cta-spinner" aria-hidden="true">
97
- {resolveIcon('loader-circle', { size: '1em' })}
98
- </span>
99
- </button>
100
- </Cluster>
101
- );
102
- }
1
+ import React, { useState } from 'react';
2
+ import resolveIcon from '../lib/resolveIcon.jsx';
3
+ import Cluster from '../primitives/Cluster.jsx';
4
+ import copyText from '../lib/copyText.js';
5
+ import MethodBadge from './MethodBadge.jsx';
6
+ import ApiPath from './ApiPath.jsx';
7
+
8
+ /**
9
+ * TryItBar — compact endpoint row: method badge + path + copy icon + a
10
+ * method-colored "Try It" CTA. Mirrors Mintlify's docs "try-it" row.
11
+ *
12
+ * <TryItBar method="POST" path="/project/preview/{projectId}" />
13
+ *
14
+ * CTA is a dummy `<button>` (no fetch / playground wiring) — slot a
15
+ * handler in via the `onTry` prop when there's a real client. Copy
16
+ * writes the full "METHOD path" string to clipboard.
17
+ */
18
+
19
+ export default function TryItBar({
20
+ method = 'GET',
21
+ path = '',
22
+ cta = 'Try It',
23
+ onTry,
24
+ loading = false,
25
+ className = '',
26
+ ...rest
27
+ }) {
28
+ const [copied, setCopied] = useState(false);
29
+ const key = String(method).toLowerCase();
30
+
31
+ function copy() {
32
+ copyText(`${String(method).toUpperCase()} ${path}`).then(
33
+ () => {
34
+ setCopied(true);
35
+ setTimeout(() => setCopied(false), 1400);
36
+ },
37
+ () => {
38
+ /* silently no-op */
39
+ },
40
+ );
41
+ }
42
+
43
+ const cls = `velu-try-it velu-try-it--${key} ${className}`.trim();
44
+
45
+ return (
46
+ // Outer bar is a Cluster — the inner bordered row and the Try It
47
+ // button are its two children, so they wrap as a unit on narrow
48
+ // widths (Try It drops below the row).
49
+ <Cluster
50
+ space="var(--s-1)"
51
+ justify="flex-end"
52
+ align="center"
53
+ className={cls}
54
+ {...rest}
55
+ >
56
+ {/* Inner bordered group. The method pill + url segments live in
57
+ their own Cluster that wraps internally; the copy button is a
58
+ separate sibling pinned to the top-right (align-self:
59
+ flex-start) so it never drops below the wrapped path. */}
60
+ <div className="velu-try-it__row">
61
+ <Cluster
62
+ space="var(--s-1)"
63
+ align="center"
64
+ className="velu-try-it__endpoint"
65
+ >
66
+ <MethodBadge method={method} />
67
+ <ApiPath method={method} path={path} />
68
+ </Cluster>
69
+ <button
70
+ type="button"
71
+ className="velu-try-it__copy"
72
+ onClick={copy}
73
+ aria-label={copied ? 'Copied' : 'Copy endpoint'}
74
+ title={copied ? 'Copied' : 'Copy'}
75
+ >
76
+ {resolveIcon(copied ? 'check' : 'copy', { size: '1em' })}
77
+ </button>
78
+ </div>
79
+ <button
80
+ type="button"
81
+ className="velu-try-it__cta"
82
+ onClick={onTry}
83
+ data-loading={loading ? 'true' : undefined}
84
+ disabled={loading || undefined}
85
+ aria-busy={loading || undefined}
86
+ >
87
+ {/* Two stacked layers swap with a vertical slide: the label slides
88
+ down and out the bottom while the spinner slides in from the top.
89
+ overflow:hidden on the button clips both off-screen states. */}
90
+ <span className="velu-try-it__cta-label">
91
+ {cta}
92
+ <span className="velu-try-it__cta-icon" aria-hidden="true">
93
+ {resolveIcon('chevron-right', { size: '1em' })}
94
+ </span>
95
+ </span>
96
+ <span className="velu-try-it__cta-spinner" aria-hidden="true">
97
+ {resolveIcon('loader-circle', { size: '1em' })}
98
+ </span>
99
+ </button>
100
+ </Cluster>
101
+ );
102
+ }
@@ -1,92 +1,92 @@
1
- import React from 'react';
2
- import resolveIcon from '../lib/resolveIcon.jsx';
3
-
4
- /**
5
- * Update — a single changelog entry.
6
- *
7
- * A changelog page is just a normal docs page that contains one or more
8
- * <Update> blocks; there is no special page type. Each entry renders as a
9
- * two-column row: a sticky left rail with the date/label pill (+ optional
10
- * description and tags) and a right column with the entry body (the MDX
11
- * children — usually `##` sub-headings and prose).
12
- *
13
- * The section gets a stable `id` derived from the label so it is linkable
14
- * and shows up in the table of contents. The id MUST match the slug the
15
- * `extract-toc` remark plugin computes for the same label (see
16
- * velu-cli/src/mdx-plugins/extract-toc.js → `slugifyUpdate`), so click→scroll
17
- * and scroll-spy line up.
18
- *
19
- * `data-update-tags` (pipe-joined) is emitted so a future tag-filter can show
20
- * / hide entries purely from the DOM.
21
- *
22
- * SSR-safe & presentational.
23
- *
24
- * @param {{ label?: string, date?: string, description?: string,
25
- * tags?: string | string[], rss?: any, children?: React.ReactNode,
26
- * className?: string }} props
27
- */
28
- export function slugifyUpdate(value) {
29
- const base = String(value || '')
30
- .toLowerCase()
31
- .replace(/[^a-z0-9]+/g, '-')
32
- .replace(/^-+|-+$/g, '');
33
- return `update-${base || 'item'}`;
34
- }
35
-
36
- function toTagList(value) {
37
- if (Array.isArray(value)) return value.map(String).filter(Boolean);
38
- if (value == null || value === false || value === '') return [];
39
- return [String(value)];
40
- }
41
-
42
- export default function Update({
43
- label,
44
- date,
45
- description,
46
- tags,
47
- rss, // accepted for authoring parity; RSS metadata is handled at build time
48
- children,
49
- className = '',
50
- ...rest
51
- }) {
52
- void rss;
53
- const updateLabel = String(label ?? date ?? 'Update');
54
- const anchorId = slugifyUpdate(updateLabel);
55
- const tagList = toTagList(tags);
56
-
57
- return (
58
- <section
59
- id={anchorId}
60
- data-update-label={updateLabel}
61
- data-update-tags={tagList.join('|')}
62
- className={`velu-update ${className}`.trim()}
63
- {...rest}
64
- >
65
- <div className="velu-update__meta">
66
- <a
67
- className="velu-update__anchor"
68
- href={`#${anchorId}`}
69
- aria-label={`Link to ${updateLabel}`}
70
- >
71
- {resolveIcon('link', { size: '1em' })}
72
- </a>
73
- <a className="velu-update__label" href={`#${anchorId}`}>
74
- {updateLabel}
75
- </a>
76
- {description ? (
77
- <div className="velu-update__description">{String(description)}</div>
78
- ) : null}
79
- {tagList.length ? (
80
- <div className="velu-update__tags">
81
- {tagList.map((tag, i) => (
82
- <span key={`${tag}-${i}`} className="velu-update__tag">
83
- {tag}
84
- </span>
85
- ))}
86
- </div>
87
- ) : null}
88
- </div>
89
- {children ? <div className="velu-update__content">{children}</div> : null}
90
- </section>
91
- );
92
- }
1
+ import React from 'react';
2
+ import resolveIcon from '../lib/resolveIcon.jsx';
3
+
4
+ /**
5
+ * Update — a single changelog entry.
6
+ *
7
+ * A changelog page is just a normal docs page that contains one or more
8
+ * <Update> blocks; there is no special page type. Each entry renders as a
9
+ * two-column row: a sticky left rail with the date/label pill (+ optional
10
+ * description and tags) and a right column with the entry body (the MDX
11
+ * children — usually `##` sub-headings and prose).
12
+ *
13
+ * The section gets a stable `id` derived from the label so it is linkable
14
+ * and shows up in the table of contents. The id MUST match the slug the
15
+ * `extract-toc` remark plugin computes for the same label (see
16
+ * velu-cli/src/mdx-plugins/extract-toc.js → `slugifyUpdate`), so click→scroll
17
+ * and scroll-spy line up.
18
+ *
19
+ * `data-update-tags` (pipe-joined) is emitted so a future tag-filter can show
20
+ * / hide entries purely from the DOM.
21
+ *
22
+ * SSR-safe & presentational.
23
+ *
24
+ * @param {{ label?: string, date?: string, description?: string,
25
+ * tags?: string | string[], rss?: any, children?: React.ReactNode,
26
+ * className?: string }} props
27
+ */
28
+ export function slugifyUpdate(value) {
29
+ const base = String(value || '')
30
+ .toLowerCase()
31
+ .replace(/[^a-z0-9]+/g, '-')
32
+ .replace(/^-+|-+$/g, '');
33
+ return `update-${base || 'item'}`;
34
+ }
35
+
36
+ function toTagList(value) {
37
+ if (Array.isArray(value)) return value.map(String).filter(Boolean);
38
+ if (value == null || value === false || value === '') return [];
39
+ return [String(value)];
40
+ }
41
+
42
+ export default function Update({
43
+ label,
44
+ date,
45
+ description,
46
+ tags,
47
+ rss, // accepted for authoring parity; RSS metadata is handled at build time
48
+ children,
49
+ className = '',
50
+ ...rest
51
+ }) {
52
+ void rss;
53
+ const updateLabel = String(label ?? date ?? 'Update');
54
+ const anchorId = slugifyUpdate(updateLabel);
55
+ const tagList = toTagList(tags);
56
+
57
+ return (
58
+ <section
59
+ id={anchorId}
60
+ data-update-label={updateLabel}
61
+ data-update-tags={tagList.join('|')}
62
+ className={`velu-update ${className}`.trim()}
63
+ {...rest}
64
+ >
65
+ <div className="velu-update__meta">
66
+ <a
67
+ className="velu-update__anchor"
68
+ href={`#${anchorId}`}
69
+ aria-label={`Link to ${updateLabel}`}
70
+ >
71
+ {resolveIcon('link', { size: '1em' })}
72
+ </a>
73
+ <a className="velu-update__label" href={`#${anchorId}`}>
74
+ {updateLabel}
75
+ </a>
76
+ {description ? (
77
+ <div className="velu-update__description">{String(description)}</div>
78
+ ) : null}
79
+ {tagList.length ? (
80
+ <div className="velu-update__tags">
81
+ {tagList.map((tag, i) => (
82
+ <span key={`${tag}-${i}`} className="velu-update__tag">
83
+ {tag}
84
+ </span>
85
+ ))}
86
+ </div>
87
+ ) : null}
88
+ </div>
89
+ {children ? <div className="velu-update__content">{children}</div> : null}
90
+ </section>
91
+ );
92
+ }
@@ -1,92 +1,92 @@
1
- /* Accordion — all values are tokens; light/dark via [data-theme].
2
- Selectors required (summary:hover, [open], chevron rotate, group
3
- dividers) so this component has CSS, like sidebar.css. Namespaced. */
4
-
5
- .velu-accordion {
6
- border: var(--border-width) solid var(--border-color);
7
- border-radius: var(--radius-sm);
8
- overflow: hidden; /* clip header tint + dividers to the rounded corners */
9
- /* `<details>` isn't in base.css's `max-width: none` override list, so
10
- it'd otherwise clamp to --measure (66ch). Opt out so the accordion
11
- fills the article column. Same fix is applied to the group below. */
12
- max-inline-size: none;
13
- inline-size: 100%;
14
- }
15
-
16
- .velu-accordion__summary {
17
- display: flex;
18
- align-items: center;
19
- gap: var(--s-2);
20
- /* matches Callout padding exactly: --s0 block, --s3 inline */
21
- padding: var(--s0) var(--s3);
22
- cursor: pointer;
23
- list-style: none; /* removes the native disclosure triangle */
24
- color: var(--text-color);
25
- font-size: var(--f-body);
26
- line-height: var(--lh-body);
27
- /* `<summary>` isn't in base.css's `max-width: none` override list,
28
- so without this it'd clamp to --measure (66ch) and the hover
29
- surface would stop short of the accordion's right edge. */
30
- max-inline-size: none;
31
- inline-size: 100%;
32
- box-sizing: border-box;
33
- }
34
- .velu-accordion__summary::-webkit-details-marker {
35
- display: none;
36
- }
37
- .velu-accordion__summary:hover {
38
- background: var(--surface-color);
39
- }
40
- .velu-accordion[open] > .velu-accordion__summary {
41
- background: var(--surface-color);
42
- }
43
-
44
- .velu-accordion__chevron {
45
- display: inline-flex;
46
- flex: none;
47
- align-items: center;
48
- justify-content: center;
49
- inline-size: var(--f-body);
50
- block-size: var(--f-body);
51
- transition: transform 0.15s ease;
52
- }
53
- .velu-accordion[open] > .velu-accordion__summary .velu-accordion__chevron {
54
- transform: rotate(90deg);
55
- }
56
-
57
- .velu-accordion__content {
58
- /* same inline padding as the header so body text aligns under it */
59
- padding: var(--s0) var(--s3);
60
- border-top: var(--border-width) solid var(--border-color); /* header / content divider */
61
- color: var(--text-color);
62
- font-size: var(--f-body);
63
- line-height: var(--lh-body);
64
- /* Same reason as `__summary` above — opt out of base.css's
65
- --measure cap so the divider line + content area span the full
66
- accordion width. */
67
- max-inline-size: none;
68
- inline-size: 100%;
69
- box-sizing: border-box;
70
- }
71
-
72
- /* Group: many items in ONE bordered box; dividers between; outer radius
73
- only (children clipped by overflow:hidden). */
74
- .velu-accordion-group {
75
- border: var(--border-width) solid var(--border-color);
76
- border-radius: var(--radius-sm);
77
- overflow: hidden;
78
- /* Group is a <div> (already covered by base.css's override), but we
79
- pin it explicitly here so a future markup swap can't regress. */
80
- max-inline-size: none;
81
- inline-size: 100%;
82
- }
83
- .velu-accordion--in-group {
84
- border: 0;
85
- border-radius: 0;
86
- overflow: visible;
87
- }
88
- .velu-accordion-group
89
- > .velu-accordion--in-group
90
- + .velu-accordion--in-group {
91
- border-top: var(--border-width) solid var(--border-color);
92
- }
1
+ /* Accordion — all values are tokens; light/dark via [data-theme].
2
+ Selectors required (summary:hover, [open], chevron rotate, group
3
+ dividers) so this component has CSS, like sidebar.css. Namespaced. */
4
+
5
+ .velu-accordion {
6
+ border: var(--border-width) solid var(--border-color);
7
+ border-radius: var(--radius-sm);
8
+ overflow: hidden; /* clip header tint + dividers to the rounded corners */
9
+ /* `<details>` isn't in base.css's `max-width: none` override list, so
10
+ it'd otherwise clamp to --measure (66ch). Opt out so the accordion
11
+ fills the article column. Same fix is applied to the group below. */
12
+ max-inline-size: none;
13
+ inline-size: 100%;
14
+ }
15
+
16
+ .velu-accordion__summary {
17
+ display: flex;
18
+ align-items: center;
19
+ gap: var(--s-2);
20
+ /* matches Callout padding exactly: --s0 block, --s3 inline */
21
+ padding: var(--s0) var(--s3);
22
+ cursor: pointer;
23
+ list-style: none; /* removes the native disclosure triangle */
24
+ color: var(--text-color);
25
+ font-size: var(--f-body);
26
+ line-height: var(--lh-body);
27
+ /* `<summary>` isn't in base.css's `max-width: none` override list,
28
+ so without this it'd clamp to --measure (66ch) and the hover
29
+ surface would stop short of the accordion's right edge. */
30
+ max-inline-size: none;
31
+ inline-size: 100%;
32
+ box-sizing: border-box;
33
+ }
34
+ .velu-accordion__summary::-webkit-details-marker {
35
+ display: none;
36
+ }
37
+ .velu-accordion__summary:hover {
38
+ background: var(--surface-color);
39
+ }
40
+ .velu-accordion[open] > .velu-accordion__summary {
41
+ background: var(--surface-color);
42
+ }
43
+
44
+ .velu-accordion__chevron {
45
+ display: inline-flex;
46
+ flex: none;
47
+ align-items: center;
48
+ justify-content: center;
49
+ inline-size: var(--f-body);
50
+ block-size: var(--f-body);
51
+ transition: transform 0.15s ease;
52
+ }
53
+ .velu-accordion[open] > .velu-accordion__summary .velu-accordion__chevron {
54
+ transform: rotate(90deg);
55
+ }
56
+
57
+ .velu-accordion__content {
58
+ /* same inline padding as the header so body text aligns under it */
59
+ padding: var(--s0) var(--s3);
60
+ border-top: var(--border-width) solid var(--border-color); /* header / content divider */
61
+ color: var(--text-color);
62
+ font-size: var(--f-body);
63
+ line-height: var(--lh-body);
64
+ /* Same reason as `__summary` above — opt out of base.css's
65
+ --measure cap so the divider line + content area span the full
66
+ accordion width. */
67
+ max-inline-size: none;
68
+ inline-size: 100%;
69
+ box-sizing: border-box;
70
+ }
71
+
72
+ /* Group: many items in ONE bordered box; dividers between; outer radius
73
+ only (children clipped by overflow:hidden). */
74
+ .velu-accordion-group {
75
+ border: var(--border-width) solid var(--border-color);
76
+ border-radius: var(--radius-sm);
77
+ overflow: hidden;
78
+ /* Group is a <div> (already covered by base.css's override), but we
79
+ pin it explicitly here so a future markup swap can't regress. */
80
+ max-inline-size: none;
81
+ inline-size: 100%;
82
+ }
83
+ .velu-accordion--in-group {
84
+ border: 0;
85
+ border-radius: 0;
86
+ overflow: visible;
87
+ }
88
+ .velu-accordion-group
89
+ > .velu-accordion--in-group
90
+ + .velu-accordion--in-group {
91
+ border-top: var(--border-width) solid var(--border-color);
92
+ }