@veluai/velu 0.2.35 → 0.2.36
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/README.md +39 -0
- package/dist/cli.js +57 -49
- package/package.json +1 -1
- package/runtime/velu-ui/components/Accordion.jsx +3 -3
- package/runtime/velu-ui/components/ApiClient.jsx +4 -2
- package/runtime/velu-ui/components/ApiReferencePage.jsx +12 -12
- package/runtime/velu-ui/components/ApiSamples.jsx +2 -2
- package/runtime/velu-ui/components/AskBar.jsx +3 -2
- package/runtime/velu-ui/components/Callout.jsx +11 -26
- package/runtime/velu-ui/components/Card.jsx +9 -8
- package/runtime/velu-ui/components/ChangelogFilters.jsx +2 -1
- package/runtime/velu-ui/components/Chatbot.jsx +11 -5
- package/runtime/velu-ui/components/CodeBlock.jsx +7 -6
- package/runtime/velu-ui/components/Columns.jsx +1 -0
- package/runtime/velu-ui/components/ContextMenu.jsx +3 -2
- package/runtime/velu-ui/components/Field.jsx +2 -2
- package/runtime/velu-ui/components/Icon.jsx +1 -0
- package/runtime/velu-ui/components/Image.jsx +2 -2
- package/runtime/velu-ui/components/MethodBadge.jsx +2 -2
- package/runtime/velu-ui/components/NavSelect.jsx +22 -4
- package/runtime/velu-ui/components/NotFound.jsx +7 -7
- package/runtime/velu-ui/components/PageFeedback.jsx +13 -3
- package/runtime/velu-ui/components/PageHeader.jsx +24 -9
- package/runtime/velu-ui/components/PageNav.jsx +2 -1
- package/runtime/velu-ui/components/Prompt.jsx +2 -2
- package/runtime/velu-ui/components/Search.jsx +1 -0
- package/runtime/velu-ui/components/Sidebar.jsx +18 -6
- package/runtime/velu-ui/components/Steps.jsx +4 -4
- package/runtime/velu-ui/components/ThemeToggle.jsx +1 -0
- package/runtime/velu-ui/components/Toc.jsx +6 -4
- package/runtime/velu-ui/components/Tree.jsx +6 -5
- package/runtime/velu-ui/components/TryItBar.jsx +1 -0
- package/runtime/velu-ui/components/Update.jsx +2 -2
- package/runtime/velu-ui/components/callout.css +28 -0
- package/runtime/velu-ui/components/docs-layout.css +5 -0
- package/runtime/velu-ui/components/sidebar.css +5 -5
- package/runtime/velu-ui/element-selectors.css +66 -0
- package/runtime/velu-ui/primitives/Cluster.jsx +12 -0
- package/runtime/velu-ui/primitives/Stack.jsx +12 -0
- package/runtime/velu-ui/primitives/Switcher.jsx +11 -1
- package/runtime/velu-ui/styles.css +51 -35
- package/src/runtime/App.jsx +43 -11
- package/src/runtime/client-entry.jsx +23 -0
- package/src/runtime/dev-warnings.js +16 -0
- package/src/runtime/server-entry.jsx +1 -0
|
@@ -110,10 +110,11 @@ export default function ApiClient({
|
|
|
110
110
|
align="flex-start"
|
|
111
111
|
className="velu-api-client__head"
|
|
112
112
|
>
|
|
113
|
-
<
|
|
113
|
+
<option-dropdown class="velu-api-client__op" ref={opRef}>
|
|
114
114
|
{canSwitch ? (
|
|
115
115
|
<button
|
|
116
116
|
type="button"
|
|
117
|
+
id="endpoints-menu-trigger"
|
|
117
118
|
className="velu-api-client__op-btn"
|
|
118
119
|
onClick={() => setMenuOpen((v) => !v)}
|
|
119
120
|
aria-haspopup="listbox"
|
|
@@ -166,7 +167,7 @@ export default function ApiClient({
|
|
|
166
167
|
))}
|
|
167
168
|
</ul>
|
|
168
169
|
)}
|
|
169
|
-
</
|
|
170
|
+
</option-dropdown>
|
|
170
171
|
<TryItBar
|
|
171
172
|
method={method}
|
|
172
173
|
path={path}
|
|
@@ -183,6 +184,7 @@ export default function ApiClient({
|
|
|
183
184
|
visible without scrolling past the inputs; the form and code samples
|
|
184
185
|
follow. See api.css. */}
|
|
185
186
|
<div
|
|
187
|
+
id="api-playground-input"
|
|
186
188
|
className="velu-api-client__body"
|
|
187
189
|
data-has-response={response != null ? 'true' : undefined}
|
|
188
190
|
>
|
|
@@ -80,14 +80,14 @@ export default function ApiReferencePage({ operation, samples = [], apiOperation
|
|
|
80
80
|
|
|
81
81
|
{/* Authorizations */}
|
|
82
82
|
{operation.auth?.length > 0 && (
|
|
83
|
-
<section
|
|
84
|
-
<h2>Authorizations</h2>
|
|
83
|
+
<api-section class="velu-api-page__section">
|
|
84
|
+
<h2 data-component="api-section-heading">Authorizations</h2>
|
|
85
85
|
{operation.auth.map((a, i) => (
|
|
86
86
|
<Field key={i} name={a.name} pre={a.prefix} type={a.type} required={a.required} post={a.in}>
|
|
87
87
|
{a.description}
|
|
88
88
|
</Field>
|
|
89
89
|
))}
|
|
90
|
-
</section>
|
|
90
|
+
</api-section>
|
|
91
91
|
)}
|
|
92
92
|
|
|
93
93
|
{/* Parameters, by location */}
|
|
@@ -95,37 +95,37 @@ export default function ApiReferencePage({ operation, samples = [], apiOperation
|
|
|
95
95
|
const rows = operation.parameters?.[loc] || [];
|
|
96
96
|
if (!rows.length) return null;
|
|
97
97
|
return (
|
|
98
|
-
<section key={loc}
|
|
99
|
-
<h2>{LOCATION_LABEL[loc]}</h2>
|
|
98
|
+
<api-section key={loc} class="velu-api-page__section">
|
|
99
|
+
<h2 data-component="api-section-heading">{LOCATION_LABEL[loc]}</h2>
|
|
100
100
|
{rows.map((p, i) => (
|
|
101
101
|
<Field key={i} name={p.name} type={p.type} required={p.required}>
|
|
102
102
|
{p.description}
|
|
103
103
|
{p.enum && <EnumHint values={p.enum} />}
|
|
104
104
|
</Field>
|
|
105
105
|
))}
|
|
106
|
-
</section>
|
|
106
|
+
</api-section>
|
|
107
107
|
);
|
|
108
108
|
})}
|
|
109
109
|
|
|
110
110
|
{/* Request body */}
|
|
111
111
|
{operation.body?.fields?.length > 0 && (
|
|
112
|
-
<section
|
|
113
|
-
<h2>Body</h2>
|
|
112
|
+
<api-section class="velu-api-page__section">
|
|
113
|
+
<h2 data-component="api-section-heading">Body</h2>
|
|
114
114
|
{operation.body.fields.map((f, i) => (
|
|
115
115
|
<Field key={i} name={f.name} type={f.type} required={f.required}>
|
|
116
116
|
{f.description}
|
|
117
117
|
{f.enum && <EnumHint values={f.enum} />}
|
|
118
118
|
</Field>
|
|
119
119
|
))}
|
|
120
|
-
</section>
|
|
120
|
+
</api-section>
|
|
121
121
|
)}
|
|
122
122
|
|
|
123
123
|
{/* Responses */}
|
|
124
124
|
{operation.responses?.length > 0 && (
|
|
125
|
-
<section
|
|
126
|
-
<h2>Response</h2>
|
|
125
|
+
<api-section class="velu-api-page__section">
|
|
126
|
+
<h2 data-component="api-section-heading">Response</h2>
|
|
127
127
|
<ResponseSections responses={operation.responses} />
|
|
128
|
-
</section>
|
|
128
|
+
</api-section>
|
|
129
129
|
)}
|
|
130
130
|
|
|
131
131
|
{/* Try-It playground — rendered as an overlay above the page, with a
|
|
@@ -14,7 +14,7 @@ export default function ApiSamples({ samples = [], responses = [] }) {
|
|
|
14
14
|
return (
|
|
15
15
|
<div className="velu-api-samples">
|
|
16
16
|
{samples.length > 0 && (
|
|
17
|
-
<CodeGroup className="velu-api-samples__req">
|
|
17
|
+
<CodeGroup id="request-example" className="velu-api-samples__req">
|
|
18
18
|
{samples.map((s) => (
|
|
19
19
|
<CodeBlock key={s.key} title={s.label} language={s.language}>
|
|
20
20
|
{s.code}
|
|
@@ -23,7 +23,7 @@ export default function ApiSamples({ samples = [], responses = [] }) {
|
|
|
23
23
|
</CodeGroup>
|
|
24
24
|
)}
|
|
25
25
|
{withExample.length > 0 && (
|
|
26
|
-
<CodeGroup className="velu-api-samples__res">
|
|
26
|
+
<CodeGroup id="response-example" className="velu-api-samples__res">
|
|
27
27
|
{withExample.map((r) => (
|
|
28
28
|
<CodeBlock key={r.status} title={r.status} language="json">
|
|
29
29
|
{JSON.stringify(r.example, null, 2)}
|
|
@@ -48,7 +48,7 @@ export default function AskBar({
|
|
|
48
48
|
const isEmpty = value.trim().length === 0;
|
|
49
49
|
|
|
50
50
|
return (
|
|
51
|
-
<
|
|
51
|
+
<chat-assistant-floating-input class={`velu-ask-bar ${className}`.trim()} {...rest}>
|
|
52
52
|
<textarea
|
|
53
53
|
className="velu-ask-bar__input"
|
|
54
54
|
placeholder={placeholder}
|
|
@@ -59,6 +59,7 @@ export default function AskBar({
|
|
|
59
59
|
/>
|
|
60
60
|
<button
|
|
61
61
|
type="button"
|
|
62
|
+
data-component="chat-assistant-send-button"
|
|
62
63
|
className="velu-ask-bar__send"
|
|
63
64
|
onClick={submit}
|
|
64
65
|
disabled={isEmpty}
|
|
@@ -66,6 +67,6 @@ export default function AskBar({
|
|
|
66
67
|
>
|
|
67
68
|
{resolveIcon('arrow-up', { size: '1em' })}
|
|
68
69
|
</button>
|
|
69
|
-
</
|
|
70
|
+
</chat-assistant-floating-input>
|
|
70
71
|
);
|
|
71
72
|
}
|
|
@@ -73,42 +73,27 @@ export default function Callout({
|
|
|
73
73
|
// (.lucide rule in base.css), not set per-icon.
|
|
74
74
|
const iconNode = resolveIcon(icon ?? v.icon, { size: '1em' });
|
|
75
75
|
|
|
76
|
+
// Static styles live in callout.css so a project's custom CSS can override
|
|
77
|
+
// them with a plain `callout { ... }` element selector (inline styles would
|
|
78
|
+
// beat any stylesheet). Only the per-instance colours are inline, as custom
|
|
79
|
+
// properties the stylesheet reads.
|
|
76
80
|
return (
|
|
77
|
-
<
|
|
78
|
-
className={className}
|
|
81
|
+
<callout
|
|
82
|
+
className={`velu-callout ${className}`.trim()}
|
|
83
|
+
data-type={type}
|
|
79
84
|
style={{
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
background: bgColor,
|
|
83
|
-
border: `var(--border-width) solid ${strokeColor}`,
|
|
84
|
-
borderRadius: 'var(--radius-sm)',
|
|
85
|
-
color: 'var(--text-color)',
|
|
86
|
-
fontSize: 'var(--f-body)',
|
|
87
|
-
lineHeight: 'var(--lh-body)',
|
|
85
|
+
'--velu-callout-bg': bgColor,
|
|
86
|
+
'--velu-callout-stroke': strokeColor,
|
|
88
87
|
...style,
|
|
89
88
|
}}
|
|
90
89
|
{...rest}
|
|
91
90
|
>
|
|
92
91
|
{iconNode && (
|
|
93
|
-
<span
|
|
94
|
-
aria-hidden="true"
|
|
95
|
-
style={{
|
|
96
|
-
float: 'left',
|
|
97
|
-
display: 'inline-flex',
|
|
98
|
-
alignItems: 'center',
|
|
99
|
-
// one line-box tall (body font-size × body line-height token) so
|
|
100
|
-
// the icon is centered on the FIRST line; text wraps beside it
|
|
101
|
-
// then flows back under it (no hanging indent).
|
|
102
|
-
blockSize: 'calc(var(--f-body) * var(--lh-body))',
|
|
103
|
-
marginInlineEnd: 'var(--s-1)',
|
|
104
|
-
color: strokeColor,
|
|
105
|
-
fontSize: 'var(--f-body)',
|
|
106
|
-
}}
|
|
107
|
-
>
|
|
92
|
+
<span className="velu-callout__icon" aria-hidden="true">
|
|
108
93
|
{iconNode}
|
|
109
94
|
</span>
|
|
110
95
|
)}
|
|
111
96
|
{children}
|
|
112
|
-
</
|
|
97
|
+
</callout>
|
|
113
98
|
);
|
|
114
99
|
}
|
|
@@ -49,13 +49,13 @@ export function Card({
|
|
|
49
49
|
.join(' ');
|
|
50
50
|
|
|
51
51
|
const iconEl = icon ? (
|
|
52
|
-
<span className="velu-card__icon" aria-hidden="true">
|
|
52
|
+
<span className="velu-card__icon" data-component-part="card-icon" aria-hidden="true">
|
|
53
53
|
{resolveIcon(icon, { size: '1em' })}
|
|
54
54
|
</span>
|
|
55
55
|
) : null;
|
|
56
56
|
|
|
57
57
|
const ctaEl = cta ? (
|
|
58
|
-
<a className="velu-card__cta" href={cta.href}>
|
|
58
|
+
<a className="velu-card__cta" data-component-part="card-cta" href={cta.href}>
|
|
59
59
|
{cta.label}
|
|
60
60
|
<span className="velu-card__cta-icon" aria-hidden="true">
|
|
61
61
|
{resolveIcon('chevron-right', { size: '1em' })}
|
|
@@ -64,21 +64,21 @@ export function Card({
|
|
|
64
64
|
) : null;
|
|
65
65
|
|
|
66
66
|
const titleEl = title ? (
|
|
67
|
-
<div className="velu-card__title">{title}</div>
|
|
67
|
+
<div className="velu-card__title" data-component-part="card-title">{title}</div>
|
|
68
68
|
) : null;
|
|
69
69
|
const textEl = children ? (
|
|
70
|
-
<div className="velu-card__text">{children}</div>
|
|
70
|
+
<div className="velu-card__text" data-component-part="card-content">{children}</div>
|
|
71
71
|
) : null;
|
|
72
72
|
|
|
73
73
|
return (
|
|
74
|
-
<
|
|
74
|
+
<card className={cls} {...rest}>
|
|
75
75
|
{img && (
|
|
76
|
-
<div className="velu-card__media">
|
|
76
|
+
<div className="velu-card__media" data-component-part="card-image">
|
|
77
77
|
<img src={img} alt={imgAlt} loading="lazy" />
|
|
78
78
|
</div>
|
|
79
79
|
)}
|
|
80
80
|
|
|
81
|
-
<div className="velu-card__body">
|
|
81
|
+
<div className="velu-card__body" data-component-part="card-content-container">
|
|
82
82
|
{horizontal ? (
|
|
83
83
|
<>
|
|
84
84
|
{iconEl}
|
|
@@ -97,7 +97,7 @@ export function Card({
|
|
|
97
97
|
</>
|
|
98
98
|
)}
|
|
99
99
|
</div>
|
|
100
|
-
</
|
|
100
|
+
</card>
|
|
101
101
|
);
|
|
102
102
|
}
|
|
103
103
|
|
|
@@ -117,6 +117,7 @@ export function CardGroup({
|
|
|
117
117
|
}) {
|
|
118
118
|
return (
|
|
119
119
|
<Switcher
|
|
120
|
+
as="card-group"
|
|
120
121
|
className={`velu-card-group ${className}`.trim()}
|
|
121
122
|
space={space}
|
|
122
123
|
min={min}
|
|
@@ -45,9 +45,10 @@ export default function ChangelogFilters({ tags = [] }) {
|
|
|
45
45
|
};
|
|
46
46
|
|
|
47
47
|
return (
|
|
48
|
-
<div className="velu-changelog-filters">
|
|
48
|
+
<div id="changelog-filters" className="velu-changelog-filters">
|
|
49
49
|
<div className="velu-changelog-filters__heading">Filters</div>
|
|
50
50
|
<div
|
|
51
|
+
id="changelog-filters-content"
|
|
51
52
|
className="velu-changelog-filters__list"
|
|
52
53
|
role="group"
|
|
53
54
|
aria-label="Filter updates by tag"
|
|
@@ -339,6 +339,7 @@ function renderStream(tokens, sources, onNavigate) {
|
|
|
339
339
|
function ChatHeader({ onClose, onNew, onHistory, historyOpen }) {
|
|
340
340
|
return (
|
|
341
341
|
<Cluster
|
|
342
|
+
as="chat-assistant-sheet-header"
|
|
342
343
|
space="var(--s-2)"
|
|
343
344
|
justify="space-between"
|
|
344
345
|
align="center"
|
|
@@ -461,7 +462,7 @@ function Welcome({ onPick, suggestions }) {
|
|
|
461
462
|
>
|
|
462
463
|
<Cluster space="var(--s-2)" align="center">
|
|
463
464
|
{resolveIcon(s.icon, { size: '1em' })}
|
|
464
|
-
<
|
|
465
|
+
<starter-question-text>{s.label}</starter-question-text>
|
|
465
466
|
</Cluster>
|
|
466
467
|
{resolveIcon('arrow-right', { size: '1em' })}
|
|
467
468
|
</button>
|
|
@@ -616,6 +617,8 @@ function Composer({ value, onChange, onSubmit, disabled }) {
|
|
|
616
617
|
<div className="velu-chatbot__input-wrap">
|
|
617
618
|
<textarea
|
|
618
619
|
ref={taRef}
|
|
620
|
+
id="chat-assistant-textarea"
|
|
621
|
+
data-component="chat-assistant-input"
|
|
619
622
|
className="velu-chatbot__input"
|
|
620
623
|
placeholder="Ask anything about the docs…"
|
|
621
624
|
rows={1}
|
|
@@ -625,6 +628,7 @@ function Composer({ value, onChange, onSubmit, disabled }) {
|
|
|
625
628
|
/>
|
|
626
629
|
<button
|
|
627
630
|
type="button"
|
|
631
|
+
data-component="chat-assistant-send-button"
|
|
628
632
|
className={`velu-chatbot__send${active ? ' is-active' : ''}`}
|
|
629
633
|
onClick={onSubmit}
|
|
630
634
|
disabled={!active}
|
|
@@ -633,9 +637,9 @@ function Composer({ value, onChange, onSubmit, disabled }) {
|
|
|
633
637
|
{resolveIcon('arrow-up', { size: '1em' })}
|
|
634
638
|
</button>
|
|
635
639
|
</div>
|
|
636
|
-
<
|
|
640
|
+
<chat-assistant-disclaimer-text class="velu-chatbot__foot">
|
|
637
641
|
<kbd>Enter</kbd> to send · <kbd>⇧ Enter</kbd> for newline
|
|
638
|
-
</
|
|
642
|
+
</chat-assistant-disclaimer-text>
|
|
639
643
|
</div>
|
|
640
644
|
);
|
|
641
645
|
}
|
|
@@ -910,6 +914,8 @@ export default function Chatbot({
|
|
|
910
914
|
|
|
911
915
|
return (
|
|
912
916
|
<aside
|
|
917
|
+
id="chat-assistant-sheet"
|
|
918
|
+
data-component="chat-assistant-sheet"
|
|
913
919
|
className={cls}
|
|
914
920
|
aria-hidden={!open}
|
|
915
921
|
aria-label="Ask AI"
|
|
@@ -944,7 +950,7 @@ export default function Chatbot({
|
|
|
944
950
|
/>
|
|
945
951
|
)}
|
|
946
952
|
|
|
947
|
-
<
|
|
953
|
+
<chat-assistant-sheet-content class="velu-chatbot__body" ref={bodyRef}>
|
|
948
954
|
{messages.length === 0 ? (
|
|
949
955
|
<Welcome onPick={(t) => send(t)} suggestions={suggestions} />
|
|
950
956
|
) : (
|
|
@@ -968,7 +974,7 @@ export default function Chatbot({
|
|
|
968
974
|
)}
|
|
969
975
|
</Stack>
|
|
970
976
|
)}
|
|
971
|
-
</
|
|
977
|
+
</chat-assistant-sheet-content>
|
|
972
978
|
|
|
973
979
|
<Composer
|
|
974
980
|
value={input}
|
|
@@ -90,9 +90,9 @@ function TabLabel({ icon, label }) {
|
|
|
90
90
|
return (
|
|
91
91
|
<>
|
|
92
92
|
{icon != null && (
|
|
93
|
-
<
|
|
93
|
+
<code-block-icon class="velu-code-block__tab-icon" aria-hidden="true">
|
|
94
94
|
{typeof icon === 'string' ? resolveIcon(icon, { size: '1em' }) : icon}
|
|
95
|
-
</
|
|
95
|
+
</code-block-icon>
|
|
96
96
|
)}
|
|
97
97
|
<span className="velu-code-block__tab-label">{label}</span>
|
|
98
98
|
</>
|
|
@@ -143,6 +143,7 @@ function CopyButton({ code }) {
|
|
|
143
143
|
type="button"
|
|
144
144
|
onClick={copy}
|
|
145
145
|
className="velu-code-block__copy"
|
|
146
|
+
data-component="code-block-copy-button"
|
|
146
147
|
aria-label={copied ? 'Copied' : 'Copy code'}
|
|
147
148
|
title={copied ? 'Copied' : 'Copy'}
|
|
148
149
|
>
|
|
@@ -242,7 +243,7 @@ export function CodeBlock({
|
|
|
242
243
|
const label = filename || title;
|
|
243
244
|
const tabIcon = pickIcon({ icon, withIcon, language });
|
|
244
245
|
return (
|
|
245
|
-
<
|
|
246
|
+
<code-block class={cls} {...rest}>
|
|
246
247
|
{label && (
|
|
247
248
|
<div className="velu-code-block__header">
|
|
248
249
|
<Tab active icon={tabIcon} label={label} />
|
|
@@ -254,7 +255,7 @@ export function CodeBlock({
|
|
|
254
255
|
lineNumbers={lineNumbers}
|
|
255
256
|
highlight={highlight}
|
|
256
257
|
/>
|
|
257
|
-
</
|
|
258
|
+
</code-block>
|
|
258
259
|
);
|
|
259
260
|
}
|
|
260
261
|
CodeBlock.displayName = 'CodeBlock';
|
|
@@ -340,7 +341,7 @@ export function CodeGroup({
|
|
|
340
341
|
}
|
|
341
342
|
|
|
342
343
|
return (
|
|
343
|
-
<
|
|
344
|
+
<code-group class={cls} {...rest}>
|
|
344
345
|
<div className="velu-code-block__header">
|
|
345
346
|
{canLeft && (
|
|
346
347
|
<button
|
|
@@ -391,7 +392,7 @@ export function CodeGroup({
|
|
|
391
392
|
lineNumbers={lineNumbers}
|
|
392
393
|
highlight={highlight}
|
|
393
394
|
/>
|
|
394
|
-
</
|
|
395
|
+
</code-group>
|
|
395
396
|
);
|
|
396
397
|
}
|
|
397
398
|
|
|
@@ -256,11 +256,11 @@ export default function ContextMenu({
|
|
|
256
256
|
className="velu-context-bar"
|
|
257
257
|
data-pagefind-ignore=""
|
|
258
258
|
>
|
|
259
|
-
{eyebrow ? <
|
|
259
|
+
{eyebrow ? <eyebrow className="velu-context-bar__eyebrow">{eyebrow}</eyebrow> : <span />}
|
|
260
260
|
|
|
261
261
|
<div className="velu-context-bar__actions">
|
|
262
262
|
{items.length > 0 && (
|
|
263
|
-
<div ref={rootRef} className="velu-context-menu" data-open={open ? 'true' : 'false'}>
|
|
263
|
+
<div ref={rootRef} id="page-context-menu" className="velu-context-menu" data-open={open ? 'true' : 'false'}>
|
|
264
264
|
<div className="velu-context-menu__split">
|
|
265
265
|
<button
|
|
266
266
|
type="button"
|
|
@@ -275,6 +275,7 @@ export default function ContextMenu({
|
|
|
275
275
|
</button>
|
|
276
276
|
<button
|
|
277
277
|
type="button"
|
|
278
|
+
id="page-context-menu-button"
|
|
278
279
|
className="velu-context-menu__toggle"
|
|
279
280
|
aria-haspopup="menu"
|
|
280
281
|
aria-expanded={open}
|
|
@@ -46,7 +46,7 @@ export default function Field({
|
|
|
46
46
|
}) {
|
|
47
47
|
const hasDefault = defaultValue !== undefined && defaultValue !== null;
|
|
48
48
|
return (
|
|
49
|
-
<
|
|
49
|
+
<field className={`velu-field ${className}`.trim()} {...rest}>
|
|
50
50
|
{/* Cluster handles the wrap-friendly inline row layout — chips +
|
|
51
51
|
name + type + required + default + post — with a 16px gap and
|
|
52
52
|
baseline alignment so the bold name doesn't shift vertically
|
|
@@ -76,6 +76,6 @@ export default function Field({
|
|
|
76
76
|
{children != null && children !== false && (
|
|
77
77
|
<div className="velu-field__body">{children}</div>
|
|
78
78
|
)}
|
|
79
|
-
</
|
|
79
|
+
</field>
|
|
80
80
|
);
|
|
81
81
|
}
|
|
@@ -149,14 +149,14 @@ export default function Image({
|
|
|
149
149
|
|
|
150
150
|
if (caption) {
|
|
151
151
|
return (
|
|
152
|
-
<figure className={cls} {...rest}>
|
|
152
|
+
<figure className={cls} data-component={chrome === 'frame' ? 'frame' : undefined} {...rest}>
|
|
153
153
|
{body}
|
|
154
154
|
<figcaption className="velu-image__caption">{caption}</figcaption>
|
|
155
155
|
</figure>
|
|
156
156
|
);
|
|
157
157
|
}
|
|
158
158
|
return (
|
|
159
|
-
<div className={cls} {...rest}>
|
|
159
|
+
<div className={cls} data-component={chrome === 'frame' ? 'frame' : undefined} {...rest}>
|
|
160
160
|
{body}
|
|
161
161
|
</div>
|
|
162
162
|
);
|
|
@@ -24,8 +24,8 @@ export default function MethodBadge({
|
|
|
24
24
|
const safe = METHODS.includes(key) ? key : 'get';
|
|
25
25
|
const cls = `velu-method-badge velu-method-badge--${safe} ${className}`.trim();
|
|
26
26
|
return (
|
|
27
|
-
<
|
|
27
|
+
<method-pill class={cls} {...rest}>
|
|
28
28
|
{String(method).toUpperCase()}
|
|
29
|
-
</
|
|
29
|
+
</method-pill>
|
|
30
30
|
);
|
|
31
31
|
}
|
|
@@ -30,9 +30,16 @@ export default function NavSelect({
|
|
|
30
30
|
bare = false,
|
|
31
31
|
linkComponent = 'a',
|
|
32
32
|
className = '',
|
|
33
|
+
// Mintlify-compatible hooks: id prefix for the trigger/menu
|
|
34
|
+
// (e.g. 'localization-select' → #localization-select-trigger /
|
|
35
|
+
// #localization-select-content / #localization-select-item) and the
|
|
36
|
+
// data-component family ('nav-dropdown' → nav-dropdown-trigger, …).
|
|
37
|
+
idPrefix,
|
|
38
|
+
component = 'nav-dropdown',
|
|
33
39
|
...rest
|
|
34
40
|
}) {
|
|
35
41
|
const Link = linkComponent;
|
|
42
|
+
const hookId = (suffix) => (idPrefix ? `${idPrefix}-${suffix}` : undefined);
|
|
36
43
|
const [open, setOpen] = React.useState(false);
|
|
37
44
|
const rootRef = React.useRef(null);
|
|
38
45
|
|
|
@@ -61,6 +68,8 @@ export default function NavSelect({
|
|
|
61
68
|
>
|
|
62
69
|
<button
|
|
63
70
|
type="button"
|
|
71
|
+
id={hookId('trigger')}
|
|
72
|
+
data-component={`${component}-trigger`}
|
|
64
73
|
className="velu-nav-select__btn"
|
|
65
74
|
aria-haspopup="menu"
|
|
66
75
|
aria-expanded={open}
|
|
@@ -82,23 +91,32 @@ export default function NavSelect({
|
|
|
82
91
|
focusable="false"
|
|
83
92
|
/>
|
|
84
93
|
</button>
|
|
85
|
-
<ul
|
|
94
|
+
<ul
|
|
95
|
+
id={hookId('content')}
|
|
96
|
+
data-component={`${component}-content`}
|
|
97
|
+
className="velu-nav-select__menu"
|
|
98
|
+
role="menu"
|
|
99
|
+
aria-hidden={!open}
|
|
100
|
+
>
|
|
86
101
|
{options.map((o, i) => (
|
|
87
102
|
<li key={o.href ?? i} role="none">
|
|
88
103
|
<Link
|
|
89
104
|
role="menuitem"
|
|
105
|
+
id={i === 0 ? hookId('item') : undefined}
|
|
106
|
+
data-component={`${component}-item`}
|
|
107
|
+
data-active={o.active ? 'true' : undefined}
|
|
90
108
|
className={`velu-nav-select__item${o.active ? ' velu-nav-select__item--active' : ''}`}
|
|
91
109
|
href={o.href}
|
|
92
110
|
tabIndex={open ? 0 : -1}
|
|
93
111
|
onClick={() => setOpen(false)}
|
|
94
112
|
>
|
|
95
113
|
{o.icon && (
|
|
96
|
-
<
|
|
114
|
+
<nav-dropdown-item-icon class="velu-nav-select__item-icon" aria-hidden="true">
|
|
97
115
|
{resolveIcon(o.icon, { size: '1em' })}
|
|
98
|
-
</
|
|
116
|
+
</nav-dropdown-item-icon>
|
|
99
117
|
)}
|
|
100
118
|
{o.code && <span className="velu-nav-select__code">{o.code}</span>}
|
|
101
|
-
<
|
|
119
|
+
<nav-dropdown-item-title>{o.label}</nav-dropdown-item-title>
|
|
102
120
|
</Link>
|
|
103
121
|
</li>
|
|
104
122
|
))}
|
|
@@ -27,15 +27,15 @@ export default function NotFound({
|
|
|
27
27
|
}) {
|
|
28
28
|
const Link = linkComponent;
|
|
29
29
|
return (
|
|
30
|
-
<
|
|
30
|
+
<not-found-container class="velu-404">
|
|
31
31
|
<p className="velu-404__eyebrow">{eyebrow}</p>
|
|
32
|
-
<
|
|
32
|
+
<not-found-status-code class="velu-404__num" aria-hidden="true">
|
|
33
33
|
404
|
|
34
|
-
</
|
|
35
|
-
<h1 className="velu-404__title">{title}</h1>
|
|
36
|
-
<p className="velu-404__body">{body}</p>
|
|
34
|
+
</not-found-status-code>
|
|
35
|
+
<h1 className="velu-404__title" data-component="not-found-title">{title}</h1>
|
|
36
|
+
<p className="velu-404__body" data-component="not-found-description">{body}</p>
|
|
37
37
|
<div className="velu-404__actions">
|
|
38
|
-
<Link className="velu-404__btn velu-404__btn--primary" href={homeHref}>
|
|
38
|
+
<Link className="velu-404__btn velu-404__btn--primary" data-component="not-found-recommended-page-link" href={homeHref}>
|
|
39
39
|
<span className="velu-404__btn-ic" aria-hidden="true">
|
|
40
40
|
{resolveIcon('house', { size: '1em' })}
|
|
41
41
|
</span>
|
|
@@ -58,6 +58,6 @@ export default function NotFound({
|
|
|
58
58
|
</button>
|
|
59
59
|
)}
|
|
60
60
|
</div>
|
|
61
|
-
</
|
|
61
|
+
</not-found-container>
|
|
62
62
|
);
|
|
63
63
|
}
|
|
@@ -110,16 +110,19 @@ export default function PageFeedback({
|
|
|
110
110
|
|
|
111
111
|
return (
|
|
112
112
|
<Stack
|
|
113
|
+
as="contextual-feedback-container"
|
|
113
114
|
space="var(--s0)"
|
|
114
115
|
className={`velu-feedback ${className}`.trim()}
|
|
115
116
|
{...rest}
|
|
116
117
|
>
|
|
117
|
-
<Cluster space="var(--s0)" align="center" className="velu-feedback__bar">
|
|
118
|
+
<Cluster as="feedback-toolbar" space="var(--s0)" align="center" className="velu-feedback__bar">
|
|
118
119
|
<span className="velu-feedback__question">{question}</span>
|
|
119
120
|
|
|
120
121
|
<Cluster space="var(--s-2)" align="center">
|
|
121
122
|
<button
|
|
122
123
|
type="button"
|
|
124
|
+
id="feedback-thumbs-up"
|
|
125
|
+
data-component="contextual-feedback-button"
|
|
123
126
|
className={`velu-feedback__btn${
|
|
124
127
|
vote === 'yes' ? ' velu-feedback__btn--chosen' : ''
|
|
125
128
|
}`}
|
|
@@ -132,6 +135,8 @@ export default function PageFeedback({
|
|
|
132
135
|
</button>
|
|
133
136
|
<button
|
|
134
137
|
type="button"
|
|
138
|
+
id="feedback-thumbs-down"
|
|
139
|
+
data-component="contextual-feedback-button"
|
|
135
140
|
className={`velu-feedback__btn${
|
|
136
141
|
vote === 'no' ? ' velu-feedback__btn--chosen' : ''
|
|
137
142
|
}`}
|
|
@@ -151,8 +156,8 @@ export default function PageFeedback({
|
|
|
151
156
|
</Cluster>
|
|
152
157
|
|
|
153
158
|
{showForm && (
|
|
154
|
-
<Stack space="var(--s1)" className="velu-feedback__form">
|
|
155
|
-
<h3 className="velu-feedback__form-title">
|
|
159
|
+
<Stack as="contextual-feedback-form" id="feedback-form" space="var(--s1)" className="velu-feedback__form">
|
|
160
|
+
<h3 className="velu-feedback__form-title" data-component="contextual-feedback-form-title">
|
|
156
161
|
How can we improve our product?
|
|
157
162
|
</h3>
|
|
158
163
|
|
|
@@ -176,6 +181,8 @@ export default function PageFeedback({
|
|
|
176
181
|
</Stack>
|
|
177
182
|
|
|
178
183
|
<textarea
|
|
184
|
+
id="feedback-form-input"
|
|
185
|
+
data-component="contextual-feedback-input"
|
|
179
186
|
className="velu-feedback__detail"
|
|
180
187
|
placeholder="(optional) Could you share more about your experience?"
|
|
181
188
|
value={detail}
|
|
@@ -186,6 +193,7 @@ export default function PageFeedback({
|
|
|
186
193
|
<Cluster space="var(--s-1)">
|
|
187
194
|
<button
|
|
188
195
|
type="button"
|
|
196
|
+
id="feedback-form-cancel"
|
|
189
197
|
className="velu-feedback__action velu-feedback__action--cancel"
|
|
190
198
|
onClick={cancel}
|
|
191
199
|
>
|
|
@@ -193,6 +201,8 @@ export default function PageFeedback({
|
|
|
193
201
|
</button>
|
|
194
202
|
<button
|
|
195
203
|
type="button"
|
|
204
|
+
id="feedback-form-submit"
|
|
205
|
+
data-component="contextual-feedback-form-submit-button"
|
|
196
206
|
className="velu-feedback__action velu-feedback__action--submit"
|
|
197
207
|
onClick={submit}
|
|
198
208
|
>
|