diff --git a/.github/workflows/publish_image.yml b/.github/workflows/publish_image.yml index 40c142134ab..9865b284630 100644 --- a/.github/workflows/publish_image.yml +++ b/.github/workflows/publish_image.yml @@ -124,6 +124,12 @@ jobs: docker buildx imagetools create -t supabase/studio:latest \ supabase/studio@${{ needs.release_x86.outputs.image_digest }} \ supabase/studio@${{ needs.release_arm.outputs.image_digest }} + echo "Published Registry Images" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "| Image | Link |" >> $GITHUB_STEP_SUMMARY + echo "|-------|------|" >> $GITHUB_STEP_SUMMARY + echo "| \`supabase/studio:${{ needs.settings.outputs.image_version }}\` | [View on Docker Hub](https://hub.docker.com/r/supabase/studio/tags?name=${{ needs.settings.outputs.image_version }}) |" >> $GITHUB_STEP_SUMMARY + echo "| \`supabase/studio:latest\` | [View on Docker Hub](https://hub.docker.com/r/supabase/studio/tags?name=latest) |" >> $GITHUB_STEP_SUMMARY publish: needs: diff --git a/apps/design-system/content/docs/accessibility.mdx b/apps/design-system/content/docs/accessibility.mdx index 267d8089138..8677b350c52 100644 --- a/apps/design-system/content/docs/accessibility.mdx +++ b/apps/design-system/content/docs/accessibility.mdx @@ -21,29 +21,88 @@ About to push some code? At a minimum, check your work against this list: ## Focus management -All interactive page elements should be reachable by keyboard. They should also provide visual feedback upon selection via a `focus-visible` state. We use consistent focus styles such as `inset-focus` so users recognize this state instantly. +All interactive page elements should be reachable by keyboard. Given the below inconsistency between devices and browsers, add `tabIndex={0}` to all buttons, links, and non-text inputs, ideally at the component level. Consider tying the state of `tabIndex` to the `disabled` state of a component, if applicable. -```jsx - -

{name}

- -
+Chromium-based browsers and Firefox handle this automatically via the Tab key. Safari, by default, requires the Option key to also be held down. Enabling _Keyboard navigation_ on macOS Settings [removes this requirement](https://mayank.co/blog/safari-focus/#keyboard-navigation) but makes links non-tabbable as a result. + +Interactive page elements should also provide visual feedback upon selection via a `focus-visible` state. We use consistent focus styles such as `inset-focus` so users recognize this state instantly. + +[Button](../components/button) has all of the above built-in. Bespoke interactive elements however, such as the below clickable [TableRow](../components/table), require these props to be added manually: + +```tsx showLineNumbers {3, 5-11} + handleBucketNavigation(name, event)} + onKeyDown={(event) => { + if (event.key === 'Enter' || event.key === ' ') { + event.preventDefault() + handleBucketNavigation(name, event) + } + }} + tabIndex={0} +> + +

{name}

+
+
``` Consider also affordances like `ctrl` and `meta` key support for opening in a new tab. Anything that you can do with a mouse input should be replicable by keyboard. -## Screen reader support +### Radio groups -Textual elements are supported out-of-the-box by screen readers. Imagery of course should be described by `alt` tags. +Single-select option groups such as `` should behave as a single control. Only the first item of radio groups should become focused with the Tab key. The next Tab should move focus from the group to the next focusable control. -Less obvious however are scaffolding elements that only makes sense visually, when paired with other content. For example: a table column for actions may not have a visual _Actions_ label because its purpose is obvious to a sighted person. For everyone else’s sake, this column should be titled with `sr-only` text: +Individual options inside of a group can be reached by arrow keys (↑ ↓ ← →). Space is the canonical key to activate radio options, with Enter being a secondary affordance. -```jsx +### Jumping ahead + +Some keyboard-navigable content may be contain hundreds or thousands of items. Help users jump to specific content with the following mitigation strategies: + +- Search and filtering +- Pagination or virtualization +- “Jump to” shortcuts to skip ahead + +## Screen readers + +Textual elements are supported out-of-the-box by screen readers. + +### Imagery + +Images should have their contents described with an `alt` attribute. Write an objective description of the content rather than its context. For example: + +```tsx showLineNumbers {2} +// Correct: painting a picture with words +A tricolor beagle galloping through a grassy field, ears in the air + +// Incorrect: Unhelpful context +Our logo +``` + +Icons and other visual elements that aren’t strictly images should use the `aria-label` attribute. For example: + +```tsx showLineNumbers {2} + + + +``` + +Visual elements that are _purely_ visual aids may be removed from the accessibility tree via the `aria-hidden` attribute. For example: + +```tsx showLineNumbers {2} + + + +``` + +Never use `aria-hidden={true}` on focusable elements, since these are critical pieces of functionality. + +### Scaffolding + +Some scaffolding elements only make sense visually, in the context of surrounding visual content. For example: a table column for actions may not have a visual _Actions_ label because its purpose is obvious (by nearby contents) to a sighted person. For everyone else’s sake, this column should be titled with `sr-only` text: + +```tsx showLineNumbers {2} Actions diff --git a/apps/design-system/content/docs/components/button.mdx b/apps/design-system/content/docs/components/button.mdx index 53c183989c5..2fe36168c07 100644 --- a/apps/design-system/content/docs/components/button.mdx +++ b/apps/design-system/content/docs/components/button.mdx @@ -122,3 +122,13 @@ Displaying only an Icon in a button. Supports slot behavior with `asChild` prop. + +## Accessibility + +[Keyboard focus](../accessibility#focus-management) is automatically handled: + +- Enabled buttons default to `tabIndex={0}` (keyboard accessible) +- Disabled buttons default to `tabIndex={-1}` (removed from tab order) +- You can still override with an explicit `tabIndex` prop when needed + +You therefore don't need to manually set `tabIndex`, as Button handles it automatically based on its `disabled` state. diff --git a/apps/design-system/content/docs/icons.mdx b/apps/design-system/content/docs/icons.mdx index 5e020a680d4..7dc1dbf5a67 100644 --- a/apps/design-system/content/docs/icons.mdx +++ b/apps/design-system/content/docs/icons.mdx @@ -49,7 +49,7 @@ function app() { ### Adding new custom icons -To add a new custom icon to the Supabase icon library: +Follow these steps to add a new custom icon to the Supabase icon library. 1. **Create SVG file**: Add your SVG file to `packages/icons/src/raw-icons/` with a kebab-case name (e.g., `my-new-icon.svg`). Make sure it has follows these exact requirements: @@ -60,16 +60,18 @@ To add a new custom icon to the Supabase icon library: - Any unnecessary elements like ``, ``, and `` wrappers have been removed - SVG structure is as simple as possible with just `` elements -Just leave attributes like `stroke-width` as they are. The conversion to camel-case (for React compatibility) is handled by the below build process. +Leave attributes like `stroke-width` as they are. The conversion to camel-case for React compatibility (e.g. `strokeWidth`) is handled by the below build process. 2. **Build the component**: Run `npm run build:icons` from inside the `packages/icons` directory 3. **Use the icon**: Import and use like any other icon: - ```jsx - import { MyNewIcon } from 'icons' - ; - ``` +```tsx +import { MyNewIcon } from 'icons' +; +``` + +The icon name is automatically made available in camel-case, determined by the kebab-case input SVG. For example, `my-new-icon.svg` will become available as `MyNewIcon`. ### SVG design guidelines diff --git a/apps/design-system/registry/default/example/empty-state-initial-state-presentational.tsx b/apps/design-system/registry/default/example/empty-state-initial-state-presentational.tsx index 81ace8d4713..4200a1e3b4f 100644 --- a/apps/design-system/registry/default/example/empty-state-initial-state-presentational.tsx +++ b/apps/design-system/registry/default/example/empty-state-initial-state-presentational.tsx @@ -1,4 +1,4 @@ -import { BucketAdd } from 'icons' +import { BucketPlus } from 'icons' import { Plus } from 'lucide-react' import { Button } from 'ui' @@ -6,7 +6,7 @@ export default function EmptyStateInitialStatePresentational() { return (