From 9c17042c2ee67cb2f3b456c76180f5f076a06736 Mon Sep 17 00:00:00 2001 From: Waleed Latif Date: Mon, 9 Nov 2026 18:01:15 -0800 Subject: [PATCH 1/2] fix(docs): polish code rendering and keyboard navigation --- apps/docs/components/docs/mdx.tsx | 2 +- apps/docs/components/ui/code-block.tsx | 2 +- apps/docs/components/ui/scroll-region.tsx | 15 +- apps/docs/components/ui/tabs.tsx | 2 + apps/docs/content/docs/files/editor.mdx | 35 ++--- apps/docs/lib/shiki-theme.ts | 1 + apps/docs/openapi-v2-workflows.json | 132 +++++++++++++++++- .../contracts/v2/openapi/workspace-sync.ts | 64 ++++++++- 8 files changed, 212 insertions(+), 41 deletions(-) diff --git a/apps/docs/components/docs/mdx.tsx b/apps/docs/components/docs/mdx.tsx index ede1fe46fbf..d4c58298ff2 100644 --- a/apps/docs/components/docs/mdx.tsx +++ b/apps/docs/components/docs/mdx.tsx @@ -79,7 +79,7 @@ export function getMDXComponents(overrides: MDXComponents = {}): MDXComponents { diff --git a/apps/docs/components/ui/code-block.tsx b/apps/docs/components/ui/code-block.tsx index eebd7306e3e..805ac01d6de 100644 --- a/apps/docs/components/ui/code-block.tsx +++ b/apps/docs/components/ui/code-block.tsx @@ -24,7 +24,7 @@ export function CodeContent({ children, label = 'Code sample' }: CodeContentProp return ( {children} diff --git a/apps/docs/components/ui/scroll-region.tsx b/apps/docs/components/ui/scroll-region.tsx index ec10d70c3f6..32ea9e4d44a 100644 --- a/apps/docs/components/ui/scroll-region.tsx +++ b/apps/docs/components/ui/scroll-region.tsx @@ -8,24 +8,31 @@ interface ScrollRegionProps extends HTMLAttributes { label: string } -/** Keyboard scrolling is reachable only when this region has horizontal overflow. */ -export function ScrollRegion({ label, className, children, ...props }: ScrollRegionProps) { +/** Keeps scrolling keyboard-accessible before hydration, then skips regions without overflow. */ +export function ScrollRegion({ + label, + className, + children, + tabIndex = 0, + ...props +}: ScrollRegionProps) { const region = useRef(null) useEffect(() => { const element = region.current if (!element) return function updateFocusability() { - if (element) element.tabIndex = element.scrollWidth > element.clientWidth + 1 ? 0 : -1 + if (element) element.tabIndex = element.scrollWidth > element.clientWidth + 1 ? tabIndex : -1 } const observer = new ResizeObserver(updateFocusability) observer.observe(element) if (element.firstElementChild) observer.observe(element.firstElementChild) return () => observer.disconnect() - }, []) + }, [tabIndex]) return (
+ ## Formatting text Select text to open the formatting toolbar for bold, italic, strikethrough, inline code, and links. You can also type Markdown, such as `**bold**` and `*italic*`. A link's hover card lets you open, copy, edit, or remove it. -Selected text in the Markdown editor with the text style, bold, italic, link, and more formatting controls - | Action | Shortcut or Markdown | | --- | --- | | Bold | **Cmd/Ctrl + B** | @@ -39,28 +38,10 @@ Type `/` at the start of a block or after whitespace to open the insertion menu. Insert a table from the slash menu. Select a cell to open the table toolbar, then add or remove rows and columns, or delete the table. The header row stays in place; you can edit its text. Column resizing and merged cells are not supported. -A Markdown owner table with controls for adding a row, managing columns, and deleting the table - ## Code blocks Fenced code blocks have syntax highlighting, a language picker, line wrapping, and a copy button. Hover over the block or focus a control to reveal its toolbar. -A highlighted JSON code block with language, line wrap, and copy controls - Choose `mermaid` to render a diagram. Select **Show source** when you need to edit its definition. ## Images diff --git a/apps/docs/lib/shiki-theme.ts b/apps/docs/lib/shiki-theme.ts index c35aafd46e9..a7cd7004a61 100644 --- a/apps/docs/lib/shiki-theme.ts +++ b/apps/docs/lib/shiki-theme.ts @@ -195,4 +195,5 @@ const simShikiDark = buildTheme('sim-dark', 'dark', DARK) export const simShikiOptions = { themes: { light: simShikiLight, dark: simShikiDark }, defaultColor: false, + tabindex: false, } as const diff --git a/apps/docs/openapi-v2-workflows.json b/apps/docs/openapi-v2-workflows.json index b9192e47728..f36b9bc5f69 100644 --- a/apps/docs/openapi-v2-workflows.json +++ b/apps/docs/openapi-v2-workflows.json @@ -5275,6 +5275,20 @@ "application/json": { "schema": { "$ref": "#/components/schemas/PreviewWorkspaceForkResponse" + }, + "examples": { + "example1": { + "summary": "Response example 1", + "value": { + "data": { + "previewFingerprint": "c7d158e8cbc5137a2d0a4fc37ddaeb51a3b9757485679a6ad82a7de3fdac4e3a", + "sourceWorkspaceId": "9f4c2a10-3b7e-4d58-8f6a-2c1d0e5b7a94", + "workflows": [], + "selectedResourceCount": 0, + "draftOnly": true + } + } + } } } } @@ -5466,6 +5480,25 @@ "application/json": { "schema": { "$ref": "#/components/schemas/PreviewWorkspacePushResponse" + }, + "examples": { + "example1": { + "summary": "Response example 1", + "value": { + "data": { + "previewFingerprint": "c7d158e8cbc5137a2d0a4fc37ddaeb51a3b9757485679a6ad82a7de3fdac4e3a", + "sourceWorkspaceId": "e4f8d2b6-9a1c-4e3d-8b7f-5c0a2d9e6f13", + "targetWorkspaceId": "9f4c2a10-3b7e-4d58-8f6a-2c1d0e5b7a94", + "ready": true, + "workflows": [], + "unresolvedBindings": [], + "configuration": [], + "excludedTargets": [], + "triggerSlots": [], + "triggerUrlChanges": [] + } + } + } } } } @@ -5658,6 +5691,25 @@ "application/json": { "schema": { "$ref": "#/components/schemas/PreviewWorkspacePullResponse" + }, + "examples": { + "example1": { + "summary": "Response example 1", + "value": { + "data": { + "previewFingerprint": "c7d158e8cbc5137a2d0a4fc37ddaeb51a3b9757485679a6ad82a7de3fdac4e3a", + "sourceWorkspaceId": "9f4c2a10-3b7e-4d58-8f6a-2c1d0e5b7a94", + "targetWorkspaceId": "e4f8d2b6-9a1c-4e3d-8b7f-5c0a2d9e6f13", + "ready": true, + "workflows": [], + "unresolvedBindings": [], + "configuration": [], + "excludedTargets": [], + "triggerSlots": [], + "triggerUrlChanges": [] + } + } + } } } } @@ -6716,6 +6768,22 @@ "application/json": { "schema": { "$ref": "#/components/schemas/PreviewWorkflowImportResponse" + }, + "examples": { + "example1": { + "summary": "Response example 1", + "value": { + "data": { + "previewFingerprint": "c7d158e8cbc5137a2d0a4fc37ddaeb51a3b9757485679a6ad82a7de3fdac4e3a", + "ready": true, + "bindings": [], + "unresolvedBindings": [], + "configuration": [], + "unresolvedConfiguration": [], + "discovery": [] + } + } + } } } } @@ -15566,7 +15634,18 @@ "required": ["data"], "additionalProperties": false, "title": "Preview workspace fork response", - "description": "Deployed source workflows, selected-copy count, and a preview fingerprint." + "description": "Deployed source workflows, selected-copy count, and a preview fingerprint.", + "examples": [ + { + "data": { + "previewFingerprint": "c7d158e8cbc5137a2d0a4fc37ddaeb51a3b9757485679a6ad82a7de3fdac4e3a", + "sourceWorkspaceId": "9f4c2a10-3b7e-4d58-8f6a-2c1d0e5b7a94", + "workflows": [], + "selectedResourceCount": 0, + "draftOnly": true + } + } + ] }, "PreviewWorkspaceForkBody": { "type": "object", @@ -16446,7 +16525,23 @@ "required": ["data"], "additionalProperties": false, "title": "Preview workspace push response", - "description": "Current-to-other workflow actions, required choices, and preview fingerprint." + "description": "Current-to-other workflow actions, required choices, and preview fingerprint.", + "examples": [ + { + "data": { + "previewFingerprint": "c7d158e8cbc5137a2d0a4fc37ddaeb51a3b9757485679a6ad82a7de3fdac4e3a", + "sourceWorkspaceId": "e4f8d2b6-9a1c-4e3d-8b7f-5c0a2d9e6f13", + "targetWorkspaceId": "9f4c2a10-3b7e-4d58-8f6a-2c1d0e5b7a94", + "ready": true, + "workflows": [], + "unresolvedBindings": [], + "configuration": [], + "excludedTargets": [], + "triggerSlots": [], + "triggerUrlChanges": [] + } + } + ] }, "PreviewWorkspacePushBody": { "type": "object", @@ -16972,7 +17067,23 @@ "required": ["data"], "additionalProperties": false, "title": "Preview workspace pull response", - "description": "Other-to-current workflow actions, required choices, and preview fingerprint." + "description": "Other-to-current workflow actions, required choices, and preview fingerprint.", + "examples": [ + { + "data": { + "previewFingerprint": "c7d158e8cbc5137a2d0a4fc37ddaeb51a3b9757485679a6ad82a7de3fdac4e3a", + "sourceWorkspaceId": "9f4c2a10-3b7e-4d58-8f6a-2c1d0e5b7a94", + "targetWorkspaceId": "e4f8d2b6-9a1c-4e3d-8b7f-5c0a2d9e6f13", + "ready": true, + "workflows": [], + "unresolvedBindings": [], + "configuration": [], + "excludedTargets": [], + "triggerSlots": [], + "triggerUrlChanges": [] + } + } + ] }, "PreviewWorkspacePullBody": { "type": "object", @@ -18487,7 +18598,20 @@ "required": ["data"], "additionalProperties": false, "title": "Preview workflow import response", - "description": "Import readiness, unresolved bindings, and destination discovery instructions." + "description": "Import readiness, unresolved bindings, and destination discovery instructions.", + "examples": [ + { + "data": { + "previewFingerprint": "c7d158e8cbc5137a2d0a4fc37ddaeb51a3b9757485679a6ad82a7de3fdac4e3a", + "ready": true, + "bindings": [], + "unresolvedBindings": [], + "configuration": [], + "unresolvedConfiguration": [], + "discovery": [] + } + } + ] }, "ImportWorkflowRequest": { "type": "object", diff --git a/apps/sim/lib/api/contracts/v2/openapi/workspace-sync.ts b/apps/sim/lib/api/contracts/v2/openapi/workspace-sync.ts index 8e622737eba..c939a6f0eed 100644 --- a/apps/sim/lib/api/contracts/v2/openapi/workspace-sync.ts +++ b/apps/sim/lib/api/contracts/v2/openapi/workspace-sync.ts @@ -75,7 +75,18 @@ export const workspaceSyncOpenApiRoutes = [ v2PreviewWorkspaceForkContract.response.schema, 'PreviewWorkspaceForkResponse', 'Preview workspace fork response', - 'Deployed source workflows, selected-copy count, and a preview fingerprint.' + 'Deployed source workflows, selected-copy count, and a preview fingerprint.', + [ + { + data: { + previewFingerprint: PREVIEW_FINGERPRINT_EXAMPLE, + sourceWorkspaceId: '9f4c2a10-3b7e-4d58-8f6a-2c1d0e5b7a94', + workflows: [], + selectedResourceCount: 0, + draftOnly: true, + }, + }, + ] ), } ), @@ -175,7 +186,23 @@ export const workspaceSyncOpenApiRoutes = [ v2PreviewWorkspacePushContract.response.schema, 'PreviewWorkspacePushResponse', 'Preview workspace push response', - 'Current-to-other workflow actions, required choices, and preview fingerprint.' + 'Current-to-other workflow actions, required choices, and preview fingerprint.', + [ + { + data: { + previewFingerprint: PREVIEW_FINGERPRINT_EXAMPLE, + sourceWorkspaceId: 'e4f8d2b6-9a1c-4e3d-8b7f-5c0a2d9e6f13', + targetWorkspaceId: '9f4c2a10-3b7e-4d58-8f6a-2c1d0e5b7a94', + ready: true, + workflows: [], + unresolvedBindings: [], + configuration: [], + excludedTargets: [], + triggerSlots: [], + triggerUrlChanges: [], + }, + }, + ] ), } ), @@ -276,7 +303,23 @@ export const workspaceSyncOpenApiRoutes = [ v2PreviewWorkspacePullContract.response.schema, 'PreviewWorkspacePullResponse', 'Preview workspace pull response', - 'Other-to-current workflow actions, required choices, and preview fingerprint.' + 'Other-to-current workflow actions, required choices, and preview fingerprint.', + [ + { + data: { + previewFingerprint: PREVIEW_FINGERPRINT_EXAMPLE, + sourceWorkspaceId: '9f4c2a10-3b7e-4d58-8f6a-2c1d0e5b7a94', + targetWorkspaceId: 'e4f8d2b6-9a1c-4e3d-8b7f-5c0a2d9e6f13', + ready: true, + workflows: [], + unresolvedBindings: [], + configuration: [], + excludedTargets: [], + triggerSlots: [], + triggerUrlChanges: [], + }, + }, + ] ), } ), @@ -683,7 +726,20 @@ export const workspaceSyncOpenApiRoutes = [ v2PreviewWorkflowImportContract.response.schema, 'PreviewWorkflowImportResponse', 'Preview workflow import response', - 'Import readiness, unresolved bindings, and destination discovery instructions.' + 'Import readiness, unresolved bindings, and destination discovery instructions.', + [ + { + data: { + previewFingerprint: PREVIEW_FINGERPRINT_EXAMPLE, + ready: true, + bindings: [], + unresolvedBindings: [], + configuration: [], + unresolvedConfiguration: [], + discovery: [], + }, + }, + ] ), } ), From 5dff20a2c6fcdf623567989365319a52a83d1626 Mon Sep 17 00:00:00 2001 From: Waleed Latif Date: Mon, 9 Nov 2026 21:09:05 -0800 Subject: [PATCH 2/2] fix(docs): give API samples one keyboard entry --- apps/docs/components/docs/sample-panels.tsx | 5 ++- apps/docs/components/ui/code-block.tsx | 4 ++- apps/docs/components/ui/scroll-region.tsx | 9 ++--- .../scripts/fixtures/content-baseline.json | 35 +++---------------- 4 files changed, 16 insertions(+), 37 deletions(-) diff --git a/apps/docs/components/docs/sample-panels.tsx b/apps/docs/components/docs/sample-panels.tsx index 9176973148a..62b6892a593 100644 --- a/apps/docs/components/docs/sample-panels.tsx +++ b/apps/docs/components/docs/sample-panels.tsx @@ -86,10 +86,13 @@ export function SamplePanels({ value={item.value} label={item.label} id={item.id ?? `${selectorId}-${item.value}`} + tabIndex={-1} {...(presentation === 'select' ? { role: 'region', 'aria-labelledby': selectorId } : {})} className='[&>div]:pt-0' > - {item.panel} + + {item.panel} + ))} diff --git a/apps/docs/components/ui/code-block.tsx b/apps/docs/components/ui/code-block.tsx index 805ac01d6de..d01b974e1a2 100644 --- a/apps/docs/components/ui/code-block.tsx +++ b/apps/docs/components/ui/code-block.tsx @@ -18,12 +18,14 @@ interface CodeBlockProps extends HTMLAttributes { interface CodeContentProps { children: ReactNode label?: string + tabIndex?: number } -export function CodeContent({ children, label = 'Code sample' }: CodeContentProps) { +export function CodeContent({ children, label = 'Code sample', tabIndex }: CodeContentProps) { return ( {children} diff --git a/apps/docs/components/ui/scroll-region.tsx b/apps/docs/components/ui/scroll-region.tsx index 32ea9e4d44a..d6e2fccdbb1 100644 --- a/apps/docs/components/ui/scroll-region.tsx +++ b/apps/docs/components/ui/scroll-region.tsx @@ -8,12 +8,12 @@ interface ScrollRegionProps extends HTMLAttributes { label: string } -/** Keeps scrolling keyboard-accessible before hydration, then skips regions without overflow. */ +/** Keeps scrolling keyboard-accessible before hydration, then skips nonoverflowing regions unless opted in. */ export function ScrollRegion({ label, className, children, - tabIndex = 0, + tabIndex, ...props }: ScrollRegionProps) { const region = useRef(null) @@ -21,7 +21,8 @@ export function ScrollRegion({ const element = region.current if (!element) return function updateFocusability() { - if (element) element.tabIndex = element.scrollWidth > element.clientWidth + 1 ? tabIndex : -1 + if (element) + element.tabIndex = tabIndex ?? (element.scrollWidth > element.clientWidth + 1 ? 0 : -1) } const observer = new ResizeObserver(updateFocusability) observer.observe(element) @@ -32,7 +33,7 @@ export function ScrollRegion({