Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 32 additions & 19 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,12 @@ Rules that come up often:
`export default` metadata). No TS `enum` (use disjoint string unions); prop names never repeat
the component name (`type`, not `buttonType`) and avoid direction/color-coupled names
(`leftIcon` breaks under RTL).
- **Lists, menus, tabs, segmented controls, and grids** extend the collection system
(`useListModel`, `useGridModel`, `useOverflowListModel`, and item hooks from
`@workday/canvas-kit-react/collection`). Do not hand-roll selection, roving tabindex, or list
keyboard handling. See
[Collection.mdx](modules/react/collection/stories/mdx/Collection.mdx) and
[`/sana-canvas-kit-contribute-component`](skills/sana-canvas-kit-contribute-component/SKILL.md).

Full reference: [CREATING_COMPOUND_COMPONENTS.mdx](modules/docs/mdx/CREATING_COMPOUND_COMPONENTS.mdx),
[API_PATTERN_GUIDELINES.mdx](modules/docs/mdx/API_PATTERN_GUIDELINES.mdx).
Expand Down Expand Up @@ -190,16 +196,17 @@ When implementing or changing a component:
Check whether Tab/Shift+Tab is sufficient or whether the APG pattern calls for additional keys
(arrow keys for a listbox/menu/tablist, Escape to dismiss, Enter/Space to activate). Don't ship
mouse-only interaction.
- **Focus management** — visible focus indicators are required by default. Only suppress the
focus ring for mouse/touch/pointer input specifically, using the existing `data-whatinput`
pattern, never by removing `outline` unconditionally:
- **Focus management** — visible focus indicators are required by default. Use **`:focus-visible`**
so browser heuristics show the ring for keyboard (and other non-pointer) focus, and pair it with
a `&.focus` class twin for Chromatic/`StaticStates`. Never remove `outline` on `:focus` without a
`:focus-visible` replacement. Do not use `data-whatinput` or `InputProvider` (removed in v14).
See [`/sana-canvas-kit-accessibility`](skills/sana-canvas-kit-accessibility/SKILL.md) and the
`MenuItem` pattern:

```tsx
[`[data-whatinput='mouse'] &:focus,
[data-whatinput='touch'] &:focus,
[data-whatinput='pointer'] &:focus`]: {
outline: 'none',
border: 'none',
'&:is(.focus, :focus-visible)': {
outline: `2px solid ${system.legacy.color.brand.border.primary}`,
outlineOffset: '-2px',
},
```
- **Popups, portals, and live regions** have their own established patterns — check
Expand All @@ -222,7 +229,9 @@ and the rest of [modules/docs/mdx/accessibility](modules/docs/mdx/accessibility)
See [STYLE.md](./STYLE.md) for the full reference. The headline rules:

- **Use `createStyles` / `createStencil` from `@workday/canvas-kit-styling`.** Define them at
module scope, never inside a render function.
module scope, never inside a render function. `createStencil` already injects
`box-sizing: border-box` — do not repeat `boxSizing: 'border-box'` in a stencil's `base`.
`createStyles` does **not** get that automatically.
- **Don't use `Box`, `Flex`, `Grid`, `Stack`, `HStack`, or `VStack` in new code**, and don't use
style props (`padding="s"`, `depth={1}`, `backgroundColor="frenchVanilla100"`, etc.) or
Emotion's `styled()`. `Stack`/`HStack`/`VStack` were removed in v9; style props and `styled()`
Expand Down Expand Up @@ -347,21 +356,24 @@ testing complete.
- Call out the areas you want reviewer focus on ("Where Should the Reviewer Start?", "Areas for
Feedback?" in the template) instead of leaving them blank.

## Agent skills (consumer apps)
## Agent skills

This file is the **maintainer** guide for working on Canvas Kit itself. The [`skills/`](./skills/)
directory is a separate, **consumer-facing** skill pack for apps that *use* `@workday/canvas-kit-react`
— tokens, styling, accessibility, component selection, migration, and similar tasks in downstream
codebases.
This file is the **maintainer** guide for working on Canvas Kit itself. Most skills under
[`skills/`](./skills/) are **consumer-facing** (apps that *use* `@workday/canvas-kit-react` —
tokens, styling, accessibility, component selection, migration). For adding a component **to this
repo**, use
[`/sana-canvas-kit-contribute-component`](skills/sana-canvas-kit-contribute-component/SKILL.md)
(maintainer-only). It builds on the consumer factory/styling/a11y skills plus
[STYLE.md](./STYLE.md) (`system.legacy.*`, Chromatic class twins, publishing).

**Do not confuse the two.** Consumer skills teach `system.*` tokens and avoiding deprecated exports
in app code. Maintainer work in `modules/**/lib/**` follows [STYLE.md](./STYLE.md) (`system.legacy.*`,
Chromatic class twins, publishing). A maintainer-focused skill pack may come later; it does not
exist yet.
in app code. Maintainer work in `modules/**/lib/**` follows [STYLE.md](./STYLE.md) and the
contribute skill.

| Resource | Audience | Use when |
| -------- | -------- | -------- |
| [`skills/README.md`](./skills/README.md) | Consumers + maintainers editing skills | Skill index, dependencies, scope |
| [`sana-canvas-kit-contribute-component`](skills/sana-canvas-kit-contribute-component/SKILL.md) | Maintainers | New component in `modules/react` (or preview/labs) from issue + Figma |
| [Storybook → Agent Skills](modules/docs/mdx/agent-skills/Overview.mdx) | Humans browsing docs | Overview with links to each `SKILL.md` on GitHub |
| [Storybook → AI For LLMs → MCP Docs](modules/mcp/stories/mdx/MCPDocs.mdx) | Consumers using MCP | Runtime upgrade guides, tokens, accessibility, component examples |

Expand Down Expand Up @@ -391,8 +403,9 @@ Storybook stays in sync. Do not duplicate the full skill catalog here — link o
- Import the package barrel or anything under `/lib/`.
- Commit Cursor or Claude plan files, debug sessions, or other local AI session artifacts
(`.cursor/`, `.claude/`, etc.).
- Add ARIA attributes speculatively, or suppress focus outlines unconditionally instead of
scoping to `[data-whatinput='mouse'|'touch'|'pointer']`.
- Add ARIA attributes speculatively, or suppress focus outlines with `data-whatinput` /
unconditional `outline: none` on `:focus` — use `:focus-visible` (plus `&.focus` for static
states) instead.
- Modify `tsconfig*.json`, build config, or CI workflows without explaining why first.
- Add DOM snapshot tests.
- Ship a breaking change without an upgrade-guide entry.
24 changes: 10 additions & 14 deletions modules/docs/mdx/API_PATTERN_GUIDELINES.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ Some of the below rules are inspired by painpoints we've encountered in this pro
- [Patterns](#patterns)
- [Event Handlers](#event-handlers-1)
- [Grow Interface](#grow-interface)
- [Input Provider](#input-provider)
- [Focus indicators](#focus-indicators)
- [Prop Spread Behavior](#prop-spread-behavior)
- [Controlled Components](#controlled-components)
- [Accessibility](#accessibility)
Expand Down Expand Up @@ -139,22 +139,18 @@ If objects are desired, the keys follow these rules:
- Then use the `grow` boolean prop in your styles to achieve the desired effect (e.g.
`width: grow ? '100%' : undefined`)

#### Input Provider
#### Focus indicators

- All Canvas Kit components should support an `InputProvider` component to provide the cleanest
experience for mouse users. Read the docs
[here](https://github.com/Workday/canvas-kit/tree/master/modules/core/react#input-provider).
- Do not use `InputProvider` within your components. It is meant to be used only once in your
application. It does not require wrapping any children
- Make sure you provide fully accessible styling by default, and only override for mouse usage.
-
- Visible focus indicators are required by default. Use **`:focus-visible`** so browser heuristics
show the ring for keyboard (and other non-pointer) focus. Pair it with a `&.focus` class twin for
Chromatic / `StaticStates` visual testing.
- Do **not** use `data-whatinput` or `InputProvider` — those were removed in v14. Never remove
`outline` on `:focus` without a `:focus-visible` replacement.

```tsx
[`[data-whatinput='mouse'] &:focus,
[data-whatinput='touch'] &:focus,
[data-whatinput='pointer'] &:focus`]: {
outline: 'none',
border: 'none',
'&:is(.focus, :focus-visible)': {
outline: `2px solid ${system.legacy.color.brand.border.primary}`,
outlineOffset: '-2px',
},
```

Expand Down
9 changes: 5 additions & 4 deletions skills/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ design system correctly. Written against the **current generation**: Canvas Kit
`@workday/canvas-tokens-web` **4.4** (Sana Canvas theme). `/sana-canvas-kit-version` detects when an
install is older and hands off to the upgrade path instead of applying current-gen tables as truth.

This is **not** the maintainer skill set for working on the `canvas-kit` repo's own source
(`system.legacy.*` in `modules/**/lib/**`, `cornerShapeStencil`, Chromatic class twins, publishing
concerns — see [STYLE.md](../STYLE.md) / [AGENTS.md](../AGENTS.md)). A maintainer-focused skill
pack is a possible future addition; don't assume it exists yet.
Most skills below are consumer-facing. For contributing a component **into the canvas-kit repo**
itself (`modules/**/lib/**`, `system.legacy.*`, Chromatic class twins, publishing), use
[`sana-canvas-kit-contribute-component`](sana-canvas-kit-contribute-component/SKILL.md) plus
[STYLE.md](../STYLE.md) / [AGENTS.md](../AGENTS.md).

## Skills

Expand All @@ -28,6 +28,7 @@ pack is a possible future addition; don't assume it exists yet.
| [`sana-canvas-kit-migration`](sana-canvas-kit-migration/SKILL.md) | Running `@workday/canvas-kit-codemod` across majors; upgrade-guide checklist | version |
| [`sana-canvas-kit-builder`](sana-canvas-kit-builder/SKILL.md) | Building custom components with `createComponent`/`createContainer`/`createModelHook`/etc. | styling, tokens, a11y, design-principles |
| [`sana-canvas-kit-review`](sana-canvas-kit-review/SKILL.md) | Report-only grep/checklist review of a diff/branch for design-system compliance | version, all of the above |
| [`sana-canvas-kit-contribute-component`](sana-canvas-kit-contribute-component/SKILL.md) | **Maintainer-only:** add a component to this repo from a GitHub issue + Figma (collection models, Sana stencils, stories, tests, PR) | builder, styling, tokens, a11y |

## How they fit together

Expand Down
19 changes: 18 additions & 1 deletion skills/sana-canvas-kit-builder/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,21 @@ export const useDisclosureModel = createModelHook({
});
```

## Lists and grids — use the collection system

If the custom component is a **list, grid, or set of items** with selection, roving focus, or
arrow-key navigation, extend `@workday/canvas-kit-react/collection` instead of hand-rolling
selection/`useState` for the item set:

- Models: `useListModel`, `useGridModel`, `useOverflowListModel`
- Item hooks: `useListItemRegister`, `useListItemSelect`, `useListItemRovingFocus` (compose via
`composeHooks`; register last unless overriding a prop register sets)
- Selection managers: `singleSelectionManager`, `multiSelectionManager`

Keep a plain `createModelHook` (like the disclosure example above) for non-collection state
(visibility, ids, form flags). For contributing a collection-based component into the canvas-kit
repo, see `/sana-canvas-kit-contribute-component`.

## Accessibility

Wire a11y in `createElemPropsHook` (e.g. `aria-expanded`, `aria-controls`, `id` from
Expand All @@ -210,7 +225,7 @@ Wire a11y in `createElemPropsHook` (e.g. `aria-expanded`, `aria-controls`, `id`

```text
- [ ] Pick factory (createComponent vs createContainer + model)
- [ ] Define model with createModelHook if behavior is shared
- [ ] List/grid/selection/roving focus? → extend collection models; else createModelHook
- [ ] Extract elemProps into createElemPropsHook (module scope)
- [ ] Style with createStyles/createStencil + cs (/sana-canvas-kit-styling)
- [ ] Use system tokens (/sana-canvas-kit-tokens)
Expand All @@ -236,6 +251,7 @@ This is encouraged when the app knows its context (translations, test ids, analy
## Anti-patterns

- ❌ `createModelHook` for a static styled div
- ❌ Hand-rolled selection / roving tabindex for a list or grid — use collection
- ❌ `createElemPropsHook` inside render
- ❌ Manual `React.Context` when `createContainer`/`createSubcomponent` handle it
- ❌ `forwardRef` + Context by hand — use the factories
Expand All @@ -250,6 +266,7 @@ This is encouraged when the app knows its context (translations, test ids, analy
```
No shared state, just markup/styles? → createComponent
Root provides state to children? → createContainer + createModelHook
List/grid with selection or roving focus?→ extend useListModel / collection item hooks
Child reads model from context? → createSubcomponent
Reusable ARIA/event props for an element?→ createElemPropsHook
Combining multiple elemProps hooks? → composeHooks (module scope)
Expand Down
Loading
Loading