diff --git a/.circleci/config.yml b/.circleci/config.yml index 3f290164467..b7665dbc8f5 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -757,7 +757,9 @@ jobs: name: deploy command: | if [ $AZURE_STORAGE_SAS_TOKEN ]; then - azcopy copy "/tmp/dist/*" "https://reactspectrum.blob.core.windows.net/reactspectrum${AZURE_STORAGE_SAS_TOKEN}" --recursive + azcopy copy "/tmp/dist/*" "https://reactspectrum.blob.core.windows.net/reactspectrum${AZURE_STORAGE_SAS_TOKEN}" --recursive --exclude-pattern "*.md;*.txt" + azcopy copy "/tmp/dist/*" "https://reactspectrum.blob.core.windows.net/reactspectrum${AZURE_STORAGE_SAS_TOKEN}" --recursive --include-pattern "*.md" --content-type "text/markdown; charset=utf-8" + azcopy copy "/tmp/dist/*" "https://reactspectrum.blob.core.windows.net/reactspectrum${AZURE_STORAGE_SAS_TOKEN}" --recursive --include-pattern "*.txt" --content-type "text/plain; charset=utf-8" fi # Separate deploy workflow for the test docs built w/ verdaccio packages so it doesn't hold up the other deploy workflows @@ -778,7 +780,9 @@ jobs: command: | if [ $AZURE_STORAGE_SAS_TOKEN ]; then for dir in /tmp/verdaccio_dist/*/verdaccio; do - azcopy copy "$dir/*" "https://reactspectrum.blob.core.windows.net/reactspectrum/$CIRCLE_SHA1/verdaccio${AZURE_STORAGE_SAS_TOKEN}" --recursive + azcopy copy "$dir/*" "https://reactspectrum.blob.core.windows.net/reactspectrum/$CIRCLE_SHA1/verdaccio${AZURE_STORAGE_SAS_TOKEN}" --recursive --exclude-pattern "*.md;*.txt" + azcopy copy "$dir/*" "https://reactspectrum.blob.core.windows.net/reactspectrum/$CIRCLE_SHA1/verdaccio${AZURE_STORAGE_SAS_TOKEN}" --recursive --include-pattern "*.md" --content-type "text/markdown; charset=utf-8" + azcopy copy "$dir/*" "https://reactspectrum.blob.core.windows.net/reactspectrum/$CIRCLE_SHA1/verdaccio${AZURE_STORAGE_SAS_TOKEN}" --recursive --include-pattern "*.txt" --content-type "text/plain; charset=utf-8" done fi @@ -796,7 +800,10 @@ jobs: mv ./azcopy_linux_amd64_*/azcopy /usr/local/bin/ - run: name: deploy - command: azcopy copy "/tmp/dist/production/docs/*" "https://reactspectrum.blob.core.windows.net/\$web${AZURE_STORAGE_SAS_TOKEN}" --recursive + command: | + azcopy copy "/tmp/dist/production/docs/*" "https://reactspectrum.blob.core.windows.net/\$web${AZURE_STORAGE_SAS_TOKEN}" --recursive --exclude-pattern "*.md;*.txt" + azcopy copy "/tmp/dist/production/docs/*" "https://reactspectrum.blob.core.windows.net/\$web${AZURE_STORAGE_SAS_TOKEN}" --recursive --include-pattern "*.md" --content-type "text/markdown; charset=utf-8" + azcopy copy "/tmp/dist/production/docs/*" "https://reactspectrum.blob.core.windows.net/\$web${AZURE_STORAGE_SAS_TOKEN}" --recursive --include-pattern "*.txt" --content-type "text/plain; charset=utf-8" comment: executor: rsp diff --git a/Makefile b/Makefile index 684fd286e04..ff400933c7a 100644 --- a/Makefile +++ b/Makefile @@ -143,7 +143,8 @@ s2-api-diff: node scripts/api-diff.js --skip-same --skip-style-props s2-docs: - node scripts/extractStarter.mjs + yarn workspace @react-spectrum/s2-docs generate:md + yarn workspace @react-spectrum/s2-docs generate:og REGISTRY_URL=https://reactspectrum.blob.core.windows.net/reactspectrum/$$(git rev-parse HEAD)/s2-docs/registry node scripts/buildRegistry.mjs REGISTRY_URL=https://reactspectrum.blob.core.windows.net/reactspectrum/$$(git rev-parse HEAD)/s2-docs/registry yarn build:s2-docs --public-url /reactspectrum/$$(git rev-parse HEAD)/s2-docs/ mkdir -p dist/$$(git rev-parse HEAD) diff --git a/package.json b/package.json index b64ca456c7f..a8e14a59c93 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,9 @@ "build:docs": "DOCS_ENV=staging parcel build 'packages/@react-{spectrum,aria,stately}/*/docs/*.mdx' 'packages/react-aria-components/docs/**/*.mdx' 'packages/@internationalized/*/docs/*.mdx' 'packages/dev/docs/pages/**/*.mdx'", "start:s2-docs": "yarn workspace @react-spectrum/s2-docs start", "build:s2-docs": "yarn workspace @react-spectrum/s2-docs build", + "build:mcp": "yarn workspace @react-spectrum/mcp build", + "start:mcp": "yarn workspace @react-spectrum/s2-docs generate:md && yarn workspace @react-spectrum/mcp build && node packages/dev/mcp/dist/index.js", + "test:mcp": "yarn build:s2-docs && yarn build:mcp && node packages/dev/mcp/scripts/smoke-list-pages.mjs", "test": "cross-env STRICT_MODE=1 VIRT_ON=1 yarn jest", "test:lint": "node packages/**/*.test-lint.js", "test-loose": "cross-env VIRT_ON=1 yarn jest", @@ -64,7 +67,8 @@ "packages/react-aria", "packages/react-aria-components", "packages/tailwindcss-react-aria-components", - "packages/*/*" + "packages/*/*", + "packages/dev/mcp" ], "devDependencies": { "@actions/core": "^1.1.0", @@ -245,7 +249,8 @@ "micromark-extension-mdxjs": "patch:micromark-extension-mdxjs@npm%3A1.0.0#~/.yarn/patches/micromark-extension-mdxjs-npm-1.0.0-d2b6b69e4a.patch", "remark-mdx": "patch:remark-mdx@npm%3A2.0.0-rc.2#~/.yarn/patches/remark-mdx-npm-2.0.0-rc.2-7a71234e1f.patch", "remark-parse": "patch:remark-parse@npm%3A10.0.1#~/.yarn/patches/remark-parse-npm-10.0.1-e654d7df78.patch", - "lightningcss": "1.30.1" + "lightningcss": "1.30.1", + "react-server-dom-parcel": "canary" }, "@parcel/transformer-css": { "cssModules": { @@ -280,7 +285,8 @@ { "name": "s2-styles", "assets": [ - "packages/@react-spectrum/s2/**" + "packages/@react-spectrum/s2/**", + "packages/dev/s2-docs/src/**" ], "types": [ "css" diff --git a/packages/@react-aria/autocomplete/docs/anatomy.svg b/packages/@react-aria/autocomplete/docs/anatomy.svg index d8fa5048604..d15379993fa 100644 --- a/packages/@react-aria/autocomplete/docs/anatomy.svg +++ b/packages/@react-aria/autocomplete/docs/anatomy.svg @@ -1,4 +1,4 @@ - + @@ -13,13 +13,13 @@ - Label + Label - Op - Label + Op + Label @@ -37,19 +37,19 @@ - Option 1 + Option 1 - Option 3 + Option 3 - Option 3 + Option 3 - Label + Label - Op + Op @@ -68,7 +68,7 @@ - Input + Input @@ -76,7 +76,7 @@ - ClearButton + ClearButton @@ -84,7 +84,7 @@ - SearchIcon + SearchIcon @@ -92,7 +92,7 @@ - List box + List box diff --git a/packages/@react-aria/breadcrumbs/docs/anatomy.svg b/packages/@react-aria/breadcrumbs/docs/anatomy.svg index e04ad26f612..7328d50763f 100644 --- a/packages/@react-aria/breadcrumbs/docs/anatomy.svg +++ b/packages/@react-aria/breadcrumbs/docs/anatomy.svg @@ -10,11 +10,11 @@ - + Trend - + Sub Item - + January 2019 Assets @@ -28,13 +28,13 @@ - + Breadcrumb item - + Separator - + Current page - + Navigation diff --git a/packages/@react-aria/button/docs/ToggleButtonGroupAnatomy.svg b/packages/@react-aria/button/docs/ToggleButtonGroupAnatomy.svg index abbd4f7d238..eb2232884e7 100644 --- a/packages/@react-aria/button/docs/ToggleButtonGroupAnatomy.svg +++ b/packages/@react-aria/button/docs/ToggleButtonGroupAnatomy.svg @@ -7,7 +7,7 @@ - List + List @@ -16,16 +16,16 @@ - Grid + Grid - Group + Group - Toggle button + Toggle button diff --git a/packages/@react-aria/calendar/docs/calendar-anatomy.svg b/packages/@react-aria/calendar/docs/calendar-anatomy.svg index d42e13a7d97..6ea80f8b254 100644 --- a/packages/@react-aria/calendar/docs/calendar-anatomy.svg +++ b/packages/@react-aria/calendar/docs/calendar-anatomy.svg @@ -1,56 +1,56 @@ - September 2021 - S - M - T - W - T - F - 5 - 7 - 8 - 9 - 10 - 13 - 14 - 15 - 16 - 19 - 20 - 21 - 22 - 23 - 24 - 1 - 2 - 3 + September 2021 + S + M + T + W + T + F + 5 + 7 + 8 + 9 + 10 + 13 + 14 + 15 + 16 + 19 + 20 + 21 + 22 + 23 + 24 + 1 + 2 + 3 - 26 - 27 - 29 - 30 - 6 - 28 + 26 + 27 + 29 + 30 + 6 + 28 - S - 11 - 18 - 25 - 4 + S + 11 + 18 + 25 + 4 - Cell - Grid - Next button + Cell + Grid + Next button - 12 - 17 + 12 + 17 - 6 + 6 - Previous button + Previous button diff --git a/packages/@react-aria/calendar/docs/rangecalendar-anatomy.svg b/packages/@react-aria/calendar/docs/rangecalendar-anatomy.svg index 250f42c2fd1..682d4e6f342 100644 --- a/packages/@react-aria/calendar/docs/rangecalendar-anatomy.svg +++ b/packages/@react-aria/calendar/docs/rangecalendar-anatomy.svg @@ -5,58 +5,58 @@ - September 2021 - S - M - T - W - T - F - 5 - 7 - 8 - 9 - 10 - 13 - 14 - 15 - 16 - 19 - 20 - 21 - 22 - 23 - 24 - 1 - 2 - 3 + September 2021 + S + M + T + W + T + F + 5 + 7 + 8 + 9 + 10 + 13 + 14 + 15 + 16 + 19 + 20 + 21 + 22 + 23 + 24 + 1 + 2 + 3 - 26 - 27 - 29 - 30 - 6 - 28 + 26 + 27 + 29 + 30 + 6 + 28 - S - 11 - 18 - 25 - 4 + S + 11 + 18 + 25 + 4 - 12 + 12 - 17 + 17 - 6 - Cell - Grid - Next button + 6 + Cell + Grid + Next button - Previous button + Previous button diff --git a/packages/@react-aria/checkbox/docs/checkbox-anatomy.svg b/packages/@react-aria/checkbox/docs/checkbox-anatomy.svg index fd7cf711319..4ff0d6873e0 100644 --- a/packages/@react-aria/checkbox/docs/checkbox-anatomy.svg +++ b/packages/@react-aria/checkbox/docs/checkbox-anatomy.svg @@ -3,7 +3,7 @@ Shows a checkbox component with labels pointing to its parts, including the input, and label elements. - + Subscribe @@ -11,13 +11,13 @@ - + Label - + Input diff --git a/packages/@react-aria/checkbox/docs/checkboxgroup-anatomy.svg b/packages/@react-aria/checkbox/docs/checkboxgroup-anatomy.svg index e80a210d682..3d32fe2e2b0 100644 --- a/packages/@react-aria/checkbox/docs/checkboxgroup-anatomy.svg +++ b/packages/@react-aria/checkbox/docs/checkboxgroup-anatomy.svg @@ -1,56 +1,59 @@ - + Checkbox group anatomy diagram Shows a checkbox group component with labels pointing to its parts, including the checkbox group label, and group element containing three checkboxes with input and label elements. - - - - - - Shopping - - - - - - - - Music - - - - - Travel - - - - + + + + + + + Shopping + + + + + + + Music + + + + + Travel + + + + + + + + Interests + - - + + Input - - Interests - - - + + + Checkbox group label - + Group - - + + - - + + - - + + Checkbox label diff --git a/packages/@react-aria/color/docs/ColorAreaAnatomy.svg b/packages/@react-aria/color/docs/ColorAreaAnatomy.svg index b9a3989add4..cb0df17bb16 100644 --- a/packages/@react-aria/color/docs/ColorAreaAnatomy.svg +++ b/packages/@react-aria/color/docs/ColorAreaAnatomy.svg @@ -1,9 +1,9 @@ - + Color area anatomy diagram Shows a color area component with labels pointing to its parts, including the area, and thumb elements. - - + + - + Area @@ -22,7 +22,7 @@ - + Thumb diff --git a/packages/@react-aria/color/docs/ColorFieldAnatomy.svg b/packages/@react-aria/color/docs/ColorFieldAnatomy.svg index a3bcd647278..62c58247b82 100644 --- a/packages/@react-aria/color/docs/ColorFieldAnatomy.svg +++ b/packages/@react-aria/color/docs/ColorFieldAnatomy.svg @@ -7,21 +7,21 @@ - + #ABCDEF - + Background color - + Input - + Label diff --git a/packages/@react-aria/color/docs/ColorSliderAnatomy.svg b/packages/@react-aria/color/docs/ColorSliderAnatomy.svg index a6f5551e709..1fd5e28e6e1 100644 --- a/packages/@react-aria/color/docs/ColorSliderAnatomy.svg +++ b/packages/@react-aria/color/docs/ColorSliderAnatomy.svg @@ -10,33 +10,33 @@ - + Thumb - + Track - + Output - + Label - + Label - + Hue - + 230° diff --git a/packages/@react-aria/color/docs/ColorWheelAnatomy.svg b/packages/@react-aria/color/docs/ColorWheelAnatomy.svg index a8f2bac31ec..b9d4f772427 100644 --- a/packages/@react-aria/color/docs/ColorWheelAnatomy.svg +++ b/packages/@react-aria/color/docs/ColorWheelAnatomy.svg @@ -1,23 +1,23 @@ - + Color wheel anatomy diagram Shows a color wheel component with labels pointing to its parts, including the track, and thumb elements. - - + + - + - + Track - + Thumb diff --git a/packages/@react-aria/color/src/useColorWheel.ts b/packages/@react-aria/color/src/useColorWheel.ts index 55373448c9b..bcfa244cda8 100644 --- a/packages/@react-aria/color/src/useColorWheel.ts +++ b/packages/@react-aria/color/src/useColorWheel.ts @@ -308,8 +308,8 @@ export function useColorWheel(props: AriaColorWheelOptions, state: ColorWheelSta ...thumbInteractions, style: { position: 'absolute', - left: outerRadius + x, - top: outerRadius + y, + left: (outerRadius + x).toFixed(3) + 'px', + top: (outerRadius + y).toFixed(3) + 'px', transform: 'translate(-50%, -50%)', touchAction: 'none', ...forcedColorAdjustNoneStyle diff --git a/packages/@react-aria/combobox/docs/anatomy.svg b/packages/@react-aria/combobox/docs/anatomy.svg index 794bf6dc5d5..14239ca90b0 100644 --- a/packages/@react-aria/combobox/docs/anatomy.svg +++ b/packages/@react-aria/combobox/docs/anatomy.svg @@ -20,7 +20,7 @@ - + Label @@ -35,16 +35,16 @@ - + Label - + Input - + Button - + Label @@ -52,19 +52,19 @@ - + Option one - + Option two - + Option three @@ -73,7 +73,7 @@ - + Op @@ -87,14 +87,14 @@ - + List box - + Op diff --git a/packages/@react-aria/datepicker/docs/datefield-anatomy.svg b/packages/@react-aria/datepicker/docs/datefield-anatomy.svg index 7766abee9bb..cdb17c29f43 100644 --- a/packages/@react-aria/datepicker/docs/datefield-anatomy.svg +++ b/packages/@react-aria/datepicker/docs/datefield-anatomy.svg @@ -8,24 +8,24 @@ - Event date + Event date - 8 / 15 / 2022 - Segment + 8 / 15 / 2022 + Segment - Field + Field - Label + Label diff --git a/packages/@react-aria/datepicker/docs/datepicker-anatomy.svg b/packages/@react-aria/datepicker/docs/datepicker-anatomy.svg index 999e6ca6717..c2aa884b884 100644 --- a/packages/@react-aria/datepicker/docs/datepicker-anatomy.svg +++ b/packages/@react-aria/datepicker/docs/datepicker-anatomy.svg @@ -15,12 +15,12 @@ - Event date + Event date - 9 / 17 / 2021 + 9 / 17 / 2021 - Group + Group @@ -28,7 +28,7 @@ - Label + Label @@ -98,11 +98,11 @@ - Button + Button - Field + Field @@ -120,54 +120,54 @@ - September 2021 - S - M - T - W - T - F - 5 - 7 - 8 - 9 - 10 - 13 - 14 - 15 - 16 - 19 - 20 - 21 - 22 - 23 - 24 - 1 - 2 - 3 + September 2021 + S + M + T + W + T + F + 5 + 7 + 8 + 9 + 10 + 13 + 14 + 15 + 16 + 19 + 20 + 21 + 22 + 23 + 24 + 1 + 2 + 3 - 26 - 27 - 29 - 30 - 6 - 28 - S - 11 - 18 - 25 - 4 + 26 + 27 + 29 + 30 + 6 + 28 + S + 11 + 18 + 25 + 4 - 12 + 12 - 17 + 17 - Calendar + Calendar - Dialog + Dialog diff --git a/packages/@react-aria/datepicker/docs/daterangepicker-anatomy.svg b/packages/@react-aria/datepicker/docs/daterangepicker-anatomy.svg index fc0fc0bba8f..f03ddde5199 100644 --- a/packages/@react-aria/datepicker/docs/daterangepicker-anatomy.svg +++ b/packages/@react-aria/datepicker/docs/daterangepicker-anatomy.svg @@ -26,59 +26,59 @@ - September 2021 - S - M - T - W - T - F - 5 - 7 - 8 - 9 - 10 - 13 - 14 - 15 - 16 - 19 - 20 - 21 - 22 - 23 - 24 - 1 - 2 - 3 + September 2021 + S + M + T + W + T + F + 5 + 7 + 8 + 9 + 10 + 13 + 14 + 15 + 16 + 19 + 20 + 21 + 22 + 23 + 24 + 1 + 2 + 3 - 26 - 27 - 29 - 30 - 6 - 28 + 26 + 27 + 29 + 30 + 6 + 28 - S - 11 - 18 - 25 - 4 + S + 11 + 18 + 25 + 4 - 12 + 12 - 17 + 17 - 6 + 6 - Event date + Event date - Group + Group @@ -86,7 +86,7 @@ - Label + Label @@ -159,36 +159,36 @@ - Button + Button - Start field + Start field - End field + End field - Calendar + Calendar - Dialog + Dialog - 9 / 17 / 2021 + 9 / 17 / 2021 - 9 / 6 / 2021 – + 9 / 6 / 2021 – diff --git a/packages/@react-aria/datepicker/docs/timefield-anatomy.svg b/packages/@react-aria/datepicker/docs/timefield-anatomy.svg index 30981b79255..35461d623bd 100644 --- a/packages/@react-aria/datepicker/docs/timefield-anatomy.svg +++ b/packages/@react-aria/datepicker/docs/timefield-anatomy.svg @@ -8,24 +8,24 @@ - Appointment time + Appointment time - 12 : 45 PM - Segment + 12 : 45 PM + Segment - Field + Field - Label + Label diff --git a/packages/@react-aria/dialog/docs/anatomy.svg b/packages/@react-aria/dialog/docs/anatomy.svg index 846f58038eb..4f2bf8c5f5f 100644 --- a/packages/@react-aria/dialog/docs/anatomy.svg +++ b/packages/@react-aria/dialog/docs/anatomy.svg @@ -8,30 +8,30 @@ - + Cancel - + Enable - + Enable smart filters? - + Smart filters are nondestructive and will preserve your original images. - + Title - + Dialog diff --git a/packages/@react-aria/disclosure/docs/anatomy.svg b/packages/@react-aria/disclosure/docs/anatomy.svg index 0a0f10c9950..64a51e24d63 100644 --- a/packages/@react-aria/disclosure/docs/anatomy.svg +++ b/packages/@react-aria/disclosure/docs/anatomy.svg @@ -1,7 +1,7 @@ - Landscape + Landscape @@ -11,9 +11,9 @@ - Button - Landscape content - Panel + Button + Landscape content + Panel diff --git a/packages/@react-aria/dnd/docs/Anatomy.svg b/packages/@react-aria/dnd/docs/Anatomy.svg index 14f485d133f..88efdaf3e9a 100644 --- a/packages/@react-aria/dnd/docs/Anatomy.svg +++ b/packages/@react-aria/dnd/docs/Anatomy.svg @@ -11,7 +11,7 @@ - + Pictures @@ -20,7 +20,7 @@ - + Music @@ -29,7 +29,7 @@ - + Documents @@ -38,7 +38,7 @@ - + Videos @@ -50,7 +50,7 @@ - + Applications @@ -59,7 +59,7 @@ - + Folder @@ -68,7 +68,7 @@ - + Downloads @@ -80,7 +80,7 @@ - + Shared @@ -110,7 +110,7 @@ - + Music @@ -120,7 +120,7 @@ - + 2 @@ -134,7 +134,7 @@ - + Drag preview @@ -143,7 +143,7 @@ - + Drag source @@ -152,7 +152,7 @@ - + Drop target diff --git a/packages/@react-aria/dnd/docs/BetweenDropPosition.svg b/packages/@react-aria/dnd/docs/BetweenDropPosition.svg index d83142ad4a9..e35eababb2e 100644 --- a/packages/@react-aria/dnd/docs/BetweenDropPosition.svg +++ b/packages/@react-aria/dnd/docs/BetweenDropPosition.svg @@ -12,7 +12,7 @@ - Dragged Folder + Dragged Folder @@ -20,7 +20,7 @@ - Pictures + Pictures @@ -28,7 +28,7 @@ - Documents + Documents @@ -36,7 +36,7 @@ - Downloads + Downloads @@ -63,7 +63,7 @@ - Dragged Folder + Dragged Folder diff --git a/packages/@react-aria/dnd/docs/DragAffordance.svg b/packages/@react-aria/dnd/docs/DragAffordance.svg index f1242c03ecd..b11d9d6dda4 100644 --- a/packages/@react-aria/dnd/docs/DragAffordance.svg +++ b/packages/@react-aria/dnd/docs/DragAffordance.svg @@ -13,7 +13,7 @@ - Panda + Panda @@ -25,7 +25,7 @@ - Kangaroo + Kangaroo @@ -36,7 +36,7 @@ - Dog + Dog @@ -45,7 +45,7 @@ - Cat + Cat diff --git a/packages/@react-aria/dnd/docs/DragPreview.svg b/packages/@react-aria/dnd/docs/DragPreview.svg index bdbbb375e86..6c7f4bca7c7 100644 --- a/packages/@react-aria/dnd/docs/DragPreview.svg +++ b/packages/@react-aria/dnd/docs/DragPreview.svg @@ -27,7 +27,7 @@ - Documents + Documents @@ -36,7 +36,7 @@ - 5 + 5 diff --git a/packages/@react-aria/dnd/docs/DropOperation.svg b/packages/@react-aria/dnd/docs/DropOperation.svg index 96b9f1a3374..36598479066 100644 --- a/packages/@react-aria/dnd/docs/DropOperation.svg +++ b/packages/@react-aria/dnd/docs/DropOperation.svg @@ -16,7 +16,7 @@ - Dragged Folder + Dragged Folder @@ -24,7 +24,7 @@ - Folder + Folder @@ -32,7 +32,7 @@ - Folder + Folder @@ -43,7 +43,7 @@ - Destination + Destination @@ -61,7 +61,7 @@ - Dragged Folder + Dragged Folder diff --git a/packages/@react-aria/dnd/docs/OnDropPosition.svg b/packages/@react-aria/dnd/docs/OnDropPosition.svg index 8bccf89a7a4..87cf48d60db 100644 --- a/packages/@react-aria/dnd/docs/OnDropPosition.svg +++ b/packages/@react-aria/dnd/docs/OnDropPosition.svg @@ -13,7 +13,7 @@ - Applications + Applications @@ -21,7 +21,7 @@ - Pictures + Pictures @@ -29,7 +29,7 @@ - Downloads + Downloads @@ -40,7 +40,7 @@ - Documents + Documents @@ -58,7 +58,7 @@ - Dragged Folder + Dragged Folder diff --git a/packages/@react-aria/dnd/docs/RootDropPosition.svg b/packages/@react-aria/dnd/docs/RootDropPosition.svg index d57529ba31a..bff32255ce0 100644 --- a/packages/@react-aria/dnd/docs/RootDropPosition.svg +++ b/packages/@react-aria/dnd/docs/RootDropPosition.svg @@ -16,7 +16,7 @@ - Documents + Documents @@ -27,7 +27,7 @@ - Applications + Applications @@ -35,7 +35,7 @@ - Pictures + Pictures @@ -43,7 +43,7 @@ - Downloads + Downloads @@ -59,7 +59,7 @@ - Dragged Folder + Dragged Folder diff --git a/packages/@react-aria/gridlist/docs/anatomy.svg b/packages/@react-aria/gridlist/docs/anatomy.svg index cd889dc2816..4dc667b119a 100644 --- a/packages/@react-aria/gridlist/docs/anatomy.svg +++ b/packages/@react-aria/gridlist/docs/anatomy.svg @@ -1,4 +1,4 @@ - + List anatomy diagram Shows a list and list item component with labels pointing to its parts. @@ -9,7 +9,7 @@ - List container + List container @@ -28,10 +28,10 @@ - List item - List item - List item - List item + List item + List item + List item + List item @@ -84,14 +84,14 @@ - List item row + List item row - List item grid cell + List item grid cell @@ -99,7 +99,7 @@ Selectioncheckbox(optional) +(optional)" transform="translate(175 14)" fill="var(--anatomy-gray-700)" font-size="12" font-family="var(--anatomy-font)" font-style="italic">Selectioncheckbox(optional) diff --git a/packages/@react-aria/listbox/docs/anatomy.svg b/packages/@react-aria/listbox/docs/anatomy.svg index a751dc17255..08ff01ea76e 100644 --- a/packages/@react-aria/listbox/docs/anatomy.svg +++ b/packages/@react-aria/listbox/docs/anatomy.svg @@ -6,18 +6,18 @@ - + Label - + Option 1 - + Option 2 - + Option @@ -26,41 +26,41 @@ - + Label - + Option label - + Description - + Description - + Option 3 - + Description - + Option description - + Listbox - + SECTION TITLE - + Section heading @@ -70,7 +70,7 @@ - + Group diff --git a/packages/@react-aria/menu/docs/menu-trigger-anatomy.svg b/packages/@react-aria/menu/docs/menu-trigger-anatomy.svg index dec818bb685..5f729711d94 100644 --- a/packages/@react-aria/menu/docs/menu-trigger-anatomy.svg +++ b/packages/@react-aria/menu/docs/menu-trigger-anatomy.svg @@ -10,49 +10,49 @@ - + Option 1 - + Option 2 - + Menu item - + Menu item keyboard shortcut - + Menu item label - + Description - + Description - + Option 3 - + Description - + Menu item description - + Menu - + SECTION TITLE - + Section heading @@ -62,13 +62,13 @@ - + Group - K + K - + Menu item description @@ -93,12 +93,12 @@ - + More Actions - + Menu Trigger diff --git a/packages/@react-aria/meter/docs/anatomy.svg b/packages/@react-aria/meter/docs/anatomy.svg index 6e0f0067581..db5c690604e 100644 --- a/packages/@react-aria/meter/docs/anatomy.svg +++ b/packages/@react-aria/meter/docs/anatomy.svg @@ -8,21 +8,21 @@ - + Value - + Label - + Tasks completed - + 4 of 5 @@ -33,13 +33,13 @@ - + Track - + Fill diff --git a/packages/@react-aria/numberfield/docs/anatomy.svg b/packages/@react-aria/numberfield/docs/anatomy.svg index d1f42fb276e..374bb1337d7 100644 --- a/packages/@react-aria/numberfield/docs/anatomy.svg +++ b/packages/@react-aria/numberfield/docs/anatomy.svg @@ -6,20 +6,20 @@ - + 1280 - + Label - + Input - + Label @@ -35,19 +35,19 @@ - + Increment button - + Decrement button - + Group diff --git a/packages/@react-aria/overlays/docs/modal-anatomy.svg b/packages/@react-aria/overlays/docs/modal-anatomy.svg index e31bf26ceb0..131f263fe5c 100644 --- a/packages/@react-aria/overlays/docs/modal-anatomy.svg +++ b/packages/@react-aria/overlays/docs/modal-anatomy.svg @@ -15,12 +15,12 @@ - Underlay + Underlay - Modal + Modal diff --git a/packages/@react-aria/overlays/docs/popover-anatomy.svg b/packages/@react-aria/overlays/docs/popover-anatomy.svg index dcd4d3849d4..0ba7d703670 100644 --- a/packages/@react-aria/overlays/docs/popover-anatomy.svg +++ b/packages/@react-aria/overlays/docs/popover-anatomy.svg @@ -17,12 +17,12 @@ - Arrow (optional) + Arrow (optional) - Popover + Popover diff --git a/packages/@react-aria/progress/docs/anatomy.svg b/packages/@react-aria/progress/docs/anatomy.svg index 32e91085c2e..c1bc0126f64 100644 --- a/packages/@react-aria/progress/docs/anatomy.svg +++ b/packages/@react-aria/progress/docs/anatomy.svg @@ -7,21 +7,21 @@ - + Value - + Label - + Loading data… - + 26% @@ -32,13 +32,13 @@ - + Track - + Fill diff --git a/packages/@react-aria/radio/docs/anatomy.svg b/packages/@react-aria/radio/docs/anatomy.svg index b1d1afa2842..16f67ba6a7c 100644 --- a/packages/@react-aria/radio/docs/anatomy.svg +++ b/packages/@react-aria/radio/docs/anatomy.svg @@ -1,58 +1,62 @@ - + Radio group anatomy diagram Shows a radio group component with labels pointing to its parts, including the radio group label, and radio group element containing three radios with input and label elements. - - - Cat - - - - + + + + Cat + + + + + - - - - Dog - - - - + + + Dog + + + + + + + + Dragon + + + + + + + + Favorite Pet + - - + + Input - - Favorite Pet - - - + + + Radio group label - - - Dragon - - - - - - + Radio group - - + + - - + + - - + + Radio label diff --git a/packages/@react-aria/searchfield/docs/anatomy.svg b/packages/@react-aria/searchfield/docs/anatomy.svg index 96a70b6a425..2bdea710381 100644 --- a/packages/@react-aria/searchfield/docs/anatomy.svg +++ b/packages/@react-aria/searchfield/docs/anatomy.svg @@ -7,28 +7,28 @@ - + Value - + Label - + Input - + Label - + Clear button diff --git a/packages/@react-aria/select/docs/anatomy.svg b/packages/@react-aria/select/docs/anatomy.svg index ea971870f37..85e525571fa 100644 --- a/packages/@react-aria/select/docs/anatomy.svg +++ b/packages/@react-aria/select/docs/anatomy.svg @@ -10,9 +10,9 @@ - + Option 1 - + Option 1 @@ -20,43 +20,43 @@ - + Label - + Label - + Option 1 - + Option 2 - + Option 3 - + Value - + Trigger - + Label - + Label - + Menu diff --git a/packages/@react-aria/slider/docs/anatomy.svg b/packages/@react-aria/slider/docs/anatomy.svg index 8a7e3d8d1f3..7228f59dc37 100644 --- a/packages/@react-aria/slider/docs/anatomy.svg +++ b/packages/@react-aria/slider/docs/anatomy.svg @@ -3,22 +3,22 @@ Shows a slider with labels pointing to its parts including the label, group, track, thumb, and output elements. - + Output - + Label - + Label - + Label - + 24 @@ -28,13 +28,13 @@ - + Track - + Thumb @@ -44,7 +44,7 @@ - + Group diff --git a/packages/@react-aria/switch/docs/anatomy.svg b/packages/@react-aria/switch/docs/anatomy.svg index 77a2fc5dcf8..999759a962e 100644 --- a/packages/@react-aria/switch/docs/anatomy.svg +++ b/packages/@react-aria/switch/docs/anatomy.svg @@ -4,7 +4,7 @@ - + Low power mode @@ -13,12 +13,12 @@ - + Input - + Label diff --git a/packages/@react-aria/table/docs/TableAnatomy.svg b/packages/@react-aria/table/docs/TableAnatomy.svg index 175ee06273e..cc85d3eb63f 100644 --- a/packages/@react-aria/table/docs/TableAnatomy.svg +++ b/packages/@react-aria/table/docs/TableAnatomy.svg @@ -3,7 +3,7 @@ Shows a table component with labels pointing to its parts, including the row, column, column header, and cell elements. - + Column header @@ -14,30 +14,30 @@ - + 214 KB - + 120 KB - + 139 KB - + 24 KB - + Proposal - + Budget - + Welcome - + Onboarding FILE NAME - + Cell @@ -92,19 +92,19 @@ - + Select all checkbox - + Selection checkbox - + Row group @@ -113,7 +113,7 @@ - + Header row @@ -122,7 +122,7 @@ - + Row @@ -150,7 +150,7 @@ - + Row group diff --git a/packages/@react-aria/tabs/docs/anatomy.svg b/packages/@react-aria/tabs/docs/anatomy.svg index 27a57d4fb36..b9564a3b636 100644 --- a/packages/@react-aria/tabs/docs/anatomy.svg +++ b/packages/@react-aria/tabs/docs/anatomy.svg @@ -4,10 +4,10 @@ - Section 1 + Section 1 - Section 2 + Section 2 @@ -15,20 +15,20 @@ - Tab + Tab - Tab (selected) + Tab (selected) - Tab list + Tab list - Tab panel + Tab panel diff --git a/packages/@react-aria/tag/docs/anatomy.svg b/packages/@react-aria/tag/docs/anatomy.svg index 9b2792c0d4f..6795f8880a9 100644 --- a/packages/@react-aria/tag/docs/anatomy.svg +++ b/packages/@react-aria/tag/docs/anatomy.svg @@ -1,11 +1,11 @@ - + - Traveling + Traveling @@ -15,14 +15,14 @@ - Grid row + Grid row - Grid cell - Tag label + Grid cell + Tag label @@ -35,7 +35,7 @@ - Hiking + Hiking @@ -45,21 +45,21 @@ - Remove button + Remove button - Tag group + Tag group - Categories + Categories - Group label + Group label diff --git a/packages/@react-aria/textfield/docs/anatomy.svg b/packages/@react-aria/textfield/docs/anatomy.svg index dbba3b128bf..c53ebdb22b8 100644 --- a/packages/@react-aria/textfield/docs/anatomy.svg +++ b/packages/@react-aria/textfield/docs/anatomy.svg @@ -7,31 +7,31 @@ - + Value - + Label - + Input - + Label - + Help text - + Description or error message diff --git a/packages/@react-aria/toast/docs/toast-anatomy.svg b/packages/@react-aria/toast/docs/toast-anatomy.svg index 6d7deb9967c..464d5e32f04 100644 --- a/packages/@react-aria/toast/docs/toast-anatomy.svg +++ b/packages/@react-aria/toast/docs/toast-anatomy.svg @@ -12,29 +12,29 @@ - Analysis complete + Analysis complete - Title + Title - Close button + Close button - Toast + Toast - Region + Region diff --git a/packages/@react-aria/toolbar/docs/toolbar-anatomy.svg b/packages/@react-aria/toolbar/docs/toolbar-anatomy.svg index 2366cff1e9d..44cc446eabe 100644 --- a/packages/@react-aria/toolbar/docs/toolbar-anatomy.svg +++ b/packages/@react-aria/toolbar/docs/toolbar-anatomy.svg @@ -1,4 +1,4 @@ - + @@ -9,7 +9,7 @@ - Toolbar + Toolbar @@ -21,39 +21,39 @@ - Group + Group - Cut - Cut + Cut + Cut - Cut - Cut + Cut + Cut - Cut - Paste + Cut + Paste - Copy + Copy - Button + Button @@ -74,8 +74,8 @@ - Cut - Cut + Cut + Cut @@ -132,8 +132,8 @@ - Cut - Cut + Cut + Cut @@ -187,7 +187,7 @@ - Group + Group @@ -200,7 +200,7 @@ - Separator + Separator diff --git a/packages/@react-aria/tooltip/docs/anatomy.svg b/packages/@react-aria/tooltip/docs/anatomy.svg index 8522a119868..95ee95c4a19 100644 --- a/packages/@react-aria/tooltip/docs/anatomy.svg +++ b/packages/@react-aria/tooltip/docs/anatomy.svg @@ -7,12 +7,12 @@ - + Flip - + Tooltip @@ -57,12 +57,12 @@ - + Tooltip - + Trigger diff --git a/packages/@react-spectrum/actionbar/docs/ActionBarAnatomy.svg b/packages/@react-spectrum/actionbar/docs/ActionBarAnatomy.svg index 416c6938ca0..c865c5c6796 100644 --- a/packages/@react-spectrum/actionbar/docs/ActionBarAnatomy.svg +++ b/packages/@react-spectrum/actionbar/docs/ActionBarAnatomy.svg @@ -26,7 +26,7 @@ - 224 selected + 224 selected @@ -41,7 +41,7 @@ - Delete + Delete @@ -50,7 +50,7 @@ - Edit + Edit @@ -79,11 +79,11 @@ - Copy + Copy - Action group (quiet) - Item counter + Action group (quiet) + Item counter @@ -94,7 +94,7 @@ - Close button + Close button diff --git a/packages/@react-spectrum/dialog/docs/images/DialogAnatomy.svg b/packages/@react-spectrum/dialog/docs/images/DialogAnatomy.svg index bf9c962f43a..ad749734d41 100644 --- a/packages/@react-spectrum/dialog/docs/images/DialogAnatomy.svg +++ b/packages/@react-spectrum/dialog/docs/images/DialogAnatomy.svg @@ -9,7 +9,7 @@ - Body area + Body area @@ -26,13 +26,13 @@ - Title area - Footer content area (optional) - Header content area (optional) - Button group area - Header - Footer - Body + Title area + Footer content area (optional) + Header content area (optional) + Button group area + Header + Footer + Body @@ -51,7 +51,7 @@ - Divider + Divider diff --git a/packages/@react-spectrum/list/docs/anatomy.svg b/packages/@react-spectrum/list/docs/anatomy.svg index 99d63a0bc6f..e39ead923eb 100644 --- a/packages/@react-spectrum/list/docs/anatomy.svg +++ b/packages/@react-spectrum/list/docs/anatomy.svg @@ -20,15 +20,15 @@ Actions(optional) - Justify end → - ← Justify start +(optional)" transform="translate(467 122)" fill="var(--anatomy-gray-900)" font-size="12" font-family="var(--anatomy-font)" font-style="italic">Actions(optional) + Justify end → + ← Justify start Context area(optional) +(optional)" transform="translate(187 66)" fill="var(--anatomy-gray-900)" font-size="12" font-family="var(--anatomy-font)" font-style="italic">Context area(optional) Navigation icon(optional) +(optional)" transform="translate(533.5 66)" fill="var(--anatomy-gray-900)" font-size="12" font-family="var(--anatomy-font)" font-style="italic">Navigation icon(optional) Checkbox(optional) +(optional)" transform="translate(171 66)" fill="var(--anatomy-gray-900)" font-size="12" font-family="var(--anatomy-font)" font-style="italic">Checkbox(optional) @@ -43,7 +43,7 @@ Drag icon(optional) +(optional)" transform="translate(77 122)" fill="var(--anatomy-gray-900)" font-size="12" font-family="var(--anatomy-font)" font-style="italic">Drag icon(optional) @@ -73,8 +73,8 @@ - Label area - Description area (optional) + Label area + Description area (optional) diff --git a/packages/@react-spectrum/s2/src/Card.tsx b/packages/@react-spectrum/s2/src/Card.tsx index a847f9f8fe2..ddc211234c2 100644 --- a/packages/@react-spectrum/s2/src/Card.tsx +++ b/packages/@react-spectrum/s2/src/Card.tsx @@ -253,7 +253,11 @@ let preview = style({ const image = style({ width: 'full', - aspectRatio: '3/2', + aspectRatio: { + layout: { + grid: '3/2' + } + }, objectFit: 'cover', userSelect: 'none', pointerEvents: 'none' @@ -346,7 +350,10 @@ let footer = style({ paddingTop: 'calc(var(--card-spacing) * 1.5 / 2)' }); -export const InternalCardViewContext = createContext<'div' | typeof GridListItem>('div'); +export const InternalCardViewContext = createContext({ + ElementType: 'div' as 'div' | typeof GridListItem, + layout: 'grid' as 'grid' | 'waterfall' +}); export const CardContext = createContext, DOMRefValue>>(null); interface InternalCardContextValue { @@ -377,8 +384,12 @@ const actionButtonSize = { XL: 'L' } as const; +/** + * A Card summarizes an object that a user can select or navigate to. + */ export const Card = forwardRef(function Card(props: CardProps, ref: DOMRef) { [props] = useSpectrumContextProps(props, ref, CardContext); + let {ElementType, layout} = useContext(InternalCardViewContext); let domRef = useDOMRef(ref); let {density = 'regular', size = 'M', variant = 'primary', UNSAFE_className = '', UNSAFE_style, styles, id, ...otherProps} = props; let isQuiet = variant === 'quiet'; @@ -386,7 +397,7 @@ export const Card = forwardRef(function Card(props: CardProps, ref: DOMRef ); - let ElementType = useContext(InternalCardViewContext); if (ElementType === 'div' || isSkeleton) { return (
{} export const AssetCard = forwardRef(function AssetCard(props: AssetCardProps, ref: DOMRef) { + let {layout} = useContext(InternalCardViewContext); return ( {composeRenderProps(props.children, children => ( @@ -569,11 +580,15 @@ export const AssetCard = forwardRef(function AssetCard(props: AssetCardProps, re alt: '', styles: style({ width: 'full', - aspectRatio: 'square', + aspectRatio: { + layout: { + grid: 'square' + } + }, objectFit: 'contain', pointerEvents: 'none', userSelect: 'none' - }) + })({layout}) }], [IllustrationContext, { render(icon) { diff --git a/packages/@react-spectrum/s2/src/CardView.tsx b/packages/@react-spectrum/s2/src/CardView.tsx index fc77dc69052..e589a1cbd4a 100644 --- a/packages/@react-spectrum/s2/src/CardView.tsx +++ b/packages/@react-spectrum/s2/src/CardView.tsx @@ -192,6 +192,9 @@ const wrapperStyles = style({ export const CardViewContext = createContext>, DOMRefValue>>(null); +/** + * A CardView displays a group of related objects, with support for selection and bulk actions. + */ export const CardView = /*#__PURE__*/ (forwardRef as forwardRefType)(function CardView(props: CardViewProps, ref: DOMRef) { [props, ref] = useSpectrumContextProps(props, ref, CardViewContext); let { @@ -282,9 +285,14 @@ export const CardView = /*#__PURE__*/ (forwardRef as forwardRefType)(function Ca } } : undefined; + let cardViewCtx = useMemo(() => ({ + layout: layoutName, + ElementType: GridListItem + }), [layoutName]); + let cardView = ( - + extends Omit, 'children' | 'className' | 'style' | keyof GlobalDOMAttributes>, - Pick, 'createCalendar' | 'pageBehavior' | 'isDateUnavailable'>, + Pick, 'createCalendar' | 'pageBehavior' | 'firstDayOfWeek' | 'isDateUnavailable'>, StyleProps, SpectrumLabelableProps, HelpTextProps { diff --git a/packages/@react-spectrum/s2/src/DateRangePicker.tsx b/packages/@react-spectrum/s2/src/DateRangePicker.tsx index df36c7ff6ad..25e0ba7ec87 100644 --- a/packages/@react-spectrum/s2/src/DateRangePicker.tsx +++ b/packages/@react-spectrum/s2/src/DateRangePicker.tsx @@ -33,7 +33,7 @@ import {useSpectrumContextProps} from './useSpectrumContextProps'; export interface DateRangePickerProps extends Omit, 'children' | 'className' | 'style' | keyof GlobalDOMAttributes>, - Pick, 'createCalendar' | 'pageBehavior' | 'isDateUnavailable'>, + Pick, 'createCalendar' | 'pageBehavior' | 'firstDayOfWeek' | 'isDateUnavailable'>, StyleProps, SpectrumLabelableProps, HelpTextProps { diff --git a/packages/@react-spectrum/s2/src/DropZone.tsx b/packages/@react-spectrum/s2/src/DropZone.tsx index 3e755938ede..1c1cc3a4e21 100644 --- a/packages/@react-spectrum/s2/src/DropZone.tsx +++ b/packages/@react-spectrum/s2/src/DropZone.tsx @@ -29,14 +29,17 @@ export interface DropZoneProps extends Omit, DOMRefValue>>(null); diff --git a/packages/@react-spectrum/s2/src/Image.tsx b/packages/@react-spectrum/s2/src/Image.tsx index 246a98106ce..de31eaadf01 100644 --- a/packages/@react-spectrum/s2/src/Image.tsx +++ b/packages/@react-spectrum/s2/src/Image.tsx @@ -1,5 +1,5 @@ import {ContextValue, SlotProps} from 'react-aria-components'; -import {createContext, ForwardedRef, forwardRef, HTMLAttributeReferrerPolicy, ReactNode, useCallback, useContext, useMemo, useReducer, useRef, version} from 'react'; +import {createContext, ForwardedRef, forwardRef, HTMLAttributeReferrerPolicy, JSX, ReactNode, useCallback, useContext, useMemo, useReducer, useRef, version} from 'react'; import {DefaultImageGroup, ImageGroup} from './ImageCoordinator'; import {loadingStyle, useIsSkeleton, useLoadingAnimation} from './Skeleton'; import {mergeStyles} from '../style/runtime'; @@ -42,6 +42,16 @@ export interface ImageProps extends UnsafeStyles, SlotProps { * [See MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img#referrerpolicy). */ referrerPolicy?: HTMLAttributeReferrerPolicy, + /** + * The intrinsic width of the image. + * [See MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/img#width). + */ + width?: number, + /** + * The intrinsic height of the image. + * [See MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/img#height). + */ + height?: number, /** Spectrum-defined styles, returned by the `style()` macro. */ styles?: StyleString, /** A function that is called to render a fallback when the image fails to load. */ @@ -133,7 +143,10 @@ const imgStyles = style({ transitionDuration: 500 }); -export const Image = forwardRef(function Image(props: ImageProps, domRef: ForwardedRef) { +/** + * An image with support for skeleton loading and custom error states. + */ +export const Image = forwardRef(function Image(props: ImageProps, domRef: ForwardedRef): JSX.Element | null { [props, domRef] = useSpectrumContextProps(props, domRef, ImageContext); let { @@ -152,7 +165,9 @@ export const Image = forwardRef(function Image(props: ImageProps, domRef: Forwar fetchPriority, loading, referrerPolicy, - slot + slot, + width, + height } = props; let hidden = (props as ImageContextValue).hidden; @@ -198,10 +213,15 @@ export const Image = forwardRef(function Image(props: ImageProps, domRef: Forwar } // If the image is already loaded, update state immediately instead of waiting for onLoad. - if (state === 'loading' && imgRef.current?.complete) { - // Queue a microtask so we don't hit React's update limit. - // TODO: is this necessary? - queueMicrotask(onLoad); + let img = imgRef.current; + if (state === 'loading' && img?.complete) { + if (img.naturalWidth === 0 && img.naturalHeight === 0) { + // Queue a microtask so we don't hit React's update limit. + // TODO: is this necessary? + queueMicrotask(onError); + } else { + queueMicrotask(onLoad); + } } animation(domRef.current); @@ -234,13 +254,15 @@ export const Image = forwardRef(function Image(props: ImageProps, domRef: Forwar decoding={decoding} loading={loading} referrerPolicy={referrerPolicy} + width={width} + height={height} ref={imgRef} onLoad={onLoad} onError={onError} className={imgStyles({isRevealed, isTransitioning})} /> )}
- ), [slot, hidden, domRef, UNSAFE_style, UNSAFE_className, styles, isAnimating, errorState, src, alt, crossOrigin, decoding, fetchPriority, loading, referrerPolicy, onLoad, onError, isRevealed, isTransitioning]); + ), [slot, hidden, domRef, UNSAFE_style, UNSAFE_className, styles, isAnimating, errorState, src, alt, crossOrigin, decoding, fetchPriority, loading, referrerPolicy, width, height, onLoad, onError, isRevealed, isTransitioning]); }); function getFetchPriorityProp(fetchPriority?: 'high' | 'low' | 'auto'): Record { diff --git a/packages/@react-spectrum/s2/src/Menu.tsx b/packages/@react-spectrum/s2/src/Menu.tsx index c816be04c0e..69b84df057f 100644 --- a/packages/@react-spectrum/s2/src/Menu.tsx +++ b/packages/@react-spectrum/s2/src/Menu.tsx @@ -41,10 +41,10 @@ import {forwardRefType} from './types'; import {HeaderContext, HeadingContext, KeyboardContext, Text, TextContext} from './Content'; import {IconContext} from './Icon'; // chevron right removed?? import {ImageContext} from './Image'; +import {InPopoverContext, PopoverBase, PopoverContext} from './Popover'; import LinkOutIcon from '../ui-icons/LinkOut'; import {mergeStyles} from '../style/runtime'; import {Placement, useLocale} from 'react-aria'; -import {PopoverBase} from './Popover'; import {PressResponder} from '@react-aria/interactions'; import {pressScale} from './pressScale'; import {useGlobalListeners} from '@react-aria/utils'; @@ -335,27 +335,9 @@ export const Menu = /*#__PURE__*/ (forwardRef as forwardRefType)(function Menu + className={menu({size, isPopover}, isPopover ? null : styles)}> {children} ); - if (ctx || isSubmenu) { + if (isPopover) { return ( @@ -564,6 +540,21 @@ function MenuTrigger(props: MenuTriggerProps): ReactNode { }, {once: true, capture: true}); }; + let {align = 'start', direction = 'bottom', shouldFlip} = props; + let placement: Placement; + switch (direction) { + case 'left': + case 'right': + case 'start': + case 'end': + placement = `${direction} ${align === 'end' ? 'bottom' : 'top'}` as Placement; + break; + case 'bottom': + case 'top': + default: + placement = `${direction} ${align}` as Placement; + } + return ( - - - {props.children} - - + + + + {props.children} + + + ); } export interface SubmenuTriggerProps extends Omit {} -const SubmenuTrigger = AriaSubmenuTrigger as (props: SubmenuTriggerProps) => JSX.Element | null; +function SubmenuTrigger(props: SubmenuTriggerProps): JSX.Element { + // For submenus, the offset from the edge of the popover should be 10px. + // Subtract 8px for the padding around the parent menu. + // Offset by padding + border so that the first item in a submenu lines up with the parent menu item. + return ( + + {props.children[0]} + + {props.children[1]} + + + ); +} export {MenuTrigger, SubmenuTrigger}; diff --git a/packages/@react-spectrum/s2/src/Popover.tsx b/packages/@react-spectrum/s2/src/Popover.tsx index 2a2164d1527..b9c4ab4d119 100644 --- a/packages/@react-spectrum/s2/src/Popover.tsx +++ b/packages/@react-spectrum/s2/src/Popover.tsx @@ -14,6 +14,7 @@ import { Popover as AriaPopover, PopoverProps as AriaPopoverProps, composeRenderProps, + ContextValue, Dialog, DialogProps, OverlayArrow, @@ -22,12 +23,13 @@ import { } from 'react-aria-components'; import {colorScheme, getAllowedOverrides, StyleProps, UnsafeStyles} from './style-utils' with {type: 'macro'}; import {ColorSchemeContext} from './Provider'; -import {DOMRef, GlobalDOMAttributes} from '@react-types/shared'; -import {forwardRef, MutableRefObject, useCallback, useContext} from 'react'; +import {createContext, forwardRef, MutableRefObject, useCallback, useContext} from 'react'; +import {DOMRef, DOMRefValue, GlobalDOMAttributes} from '@react-types/shared'; import {mergeStyles} from '../style/runtime'; import {style} from '../style' with {type: 'macro'}; import {StyleString} from '../style/types' with {type: 'macro'}; import {useDOMRef} from '@react-spectrum/utils'; +import {useSpectrumContextProps} from './useSpectrumContextProps'; export interface PopoverProps extends UnsafeStyles, Omit { styles?: StyleString, @@ -150,7 +152,11 @@ let arrow = style({ } }); +export const PopoverContext = createContext>>(null); +export const InPopoverContext = createContext(false); + export const PopoverBase = forwardRef(function PopoverBase(props: PopoverProps, ref: DOMRef) { + [props, ref] = useSpectrumContextProps(props, ref, PopoverContext); let { hideArrow = false, UNSAFE_className = '', @@ -214,7 +220,9 @@ export const PopoverBase = forwardRef(function PopoverBase(props: PopoverProps, )} - {children} + + {children} + ))} diff --git a/packages/@react-spectrum/s2/src/Provider.tsx b/packages/@react-spectrum/s2/src/Provider.tsx index 19f76b05b69..a17ab40fe55 100644 --- a/packages/@react-spectrum/s2/src/Provider.tsx +++ b/packages/@react-spectrum/s2/src/Provider.tsx @@ -51,7 +51,7 @@ export interface ProviderProps extends UnsafeStyles { export const ColorSchemeContext = createContext(null); -export function Provider(props: ProviderProps): ReactNode { +export function Provider(props: ProviderProps): JSX.Element { let result = ; let parentColorScheme = useContext(ColorSchemeContext); let colorScheme = props.colorScheme || parentColorScheme; diff --git a/packages/@react-spectrum/s2/src/SelectBoxGroup.tsx b/packages/@react-spectrum/s2/src/SelectBoxGroup.tsx index 6bdadab9128..fc5a6c8ef9d 100644 --- a/packages/@react-spectrum/s2/src/SelectBoxGroup.tsx +++ b/packages/@react-spectrum/s2/src/SelectBoxGroup.tsx @@ -394,15 +394,15 @@ export const SelectBoxGroup = /*#__PURE__*/ forwardRef(function SelectBoxGroup - + + {children} - - + + ); }); diff --git a/packages/@react-spectrum/s2/src/TableView.tsx b/packages/@react-spectrum/s2/src/TableView.tsx index 27c8cb292ac..4ee43b7698d 100644 --- a/packages/@react-spectrum/s2/src/TableView.tsx +++ b/packages/@react-spectrum/s2/src/TableView.tsx @@ -55,7 +55,6 @@ import {IconContext} from './Icon'; import intlMessages from '../intl/*.json'; import {LayoutNode} from '@react-stately/layout'; import {Menu, MenuItem, MenuSection, MenuTrigger} from './Menu'; -import {mergeStyles} from '../style/runtime'; import Nubbin from '../ui-icons/S2_MoveHorizontalTableWidget.svg'; import {ProgressCircle} from './ProgressCircle'; import {raw} from '../style/style-macro' with {type: 'macro'}; @@ -125,10 +124,12 @@ const tableWrapper = style({ position: 'relative', // Clip ActionBar animation. overflow: 'clip' -}); +}, getAllowedOverrides({height: true})); const table = style({ width: 'full', + height: 'full', + boxSizing: 'border-box', userSelect: 'none', minHeight: 0, minWidth: 0, @@ -163,7 +164,7 @@ const table = style - {children} + {typeof children === 'string' ? {children} : children} {isFocusVisible && isDetached &&
}
diff --git a/packages/@react-spectrum/s2/src/index.ts b/packages/@react-spectrum/s2/src/index.ts index e01c99482ac..bccfb56a2f3 100644 --- a/packages/@react-spectrum/s2/src/index.ts +++ b/packages/@react-spectrum/s2/src/index.ts @@ -94,6 +94,7 @@ export {pressScale} from './pressScale'; export {Autocomplete} from 'react-aria-components'; export {Collection} from 'react-aria-components'; export {FileTrigger} from 'react-aria-components'; +export {parseColor} from 'react-aria-components'; export type {AccordionProps} from './Accordion'; export type {ActionBarProps} from './ActionBar'; @@ -167,4 +168,4 @@ export type {ToggleButtonProps} from './ToggleButton'; export type {ToggleButtonGroupProps} from './ToggleButtonGroup'; export type {TooltipProps} from './Tooltip'; export type {TreeViewProps, TreeViewItemProps, TreeViewItemContentProps, TreeViewLoadMoreItemProps} from './TreeView'; -export type {AutocompleteProps, FileTriggerProps, TooltipTriggerComponentProps as TooltipTriggerProps, SortDescriptor} from 'react-aria-components'; +export type {AutocompleteProps, FileTriggerProps, TooltipTriggerComponentProps as TooltipTriggerProps, SortDescriptor, Color, Key, Selection} from 'react-aria-components'; diff --git a/packages/@react-stately/toggle/src/useToggleGroupState.ts b/packages/@react-stately/toggle/src/useToggleGroupState.ts index 7e5c3b5d529..00225db3d0a 100644 --- a/packages/@react-stately/toggle/src/useToggleGroupState.ts +++ b/packages/@react-stately/toggle/src/useToggleGroupState.ts @@ -15,7 +15,10 @@ import {useControlledState} from '@react-stately/utils'; import {useMemo} from 'react'; export interface ToggleGroupProps { - /** Whether single or multiple selection is enabled. */ + /** + * Whether single or multiple selection is enabled. + * @default 'single' + */ selectionMode?: 'single' | 'multiple', /** Whether the collection allows empty selection. */ disallowEmptySelection?: boolean, diff --git a/packages/@react-types/datepicker/src/index.d.ts b/packages/@react-types/datepicker/src/index.d.ts index 652ca80f50b..1f7950072f6 100644 --- a/packages/@react-types/datepicker/src/index.d.ts +++ b/packages/@react-types/datepicker/src/index.d.ts @@ -109,7 +109,7 @@ export interface DateRangePickerProps extends Omit extends Omit, 'validate'>, DateRangePickerProps {} +export interface AriaDateRangePickerProps extends Omit, 'validate' | 'name'>, DateRangePickerProps {} interface SpectrumDateFieldBase extends SpectrumLabelableProps, HelpTextProps, SpectrumFieldValidation>, StyleProps { /** diff --git a/packages/@react-types/searchfield/src/index.d.ts b/packages/@react-types/searchfield/src/index.d.ts index d907324757f..fd575ce5b04 100644 --- a/packages/@react-types/searchfield/src/index.d.ts +++ b/packages/@react-types/searchfield/src/index.d.ts @@ -21,10 +21,15 @@ export interface SearchFieldProps extends TextFieldProps { onClear?: () => void } -export interface AriaSearchFieldProps extends SearchFieldProps, AriaTextFieldProps { +export interface AriaSearchFieldProps extends SearchFieldProps, Omit { /** * An enumerated attribute that defines what action label or icon to preset for the enter key on virtual keyboards. See [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/enterkeyhint). */ - enterKeyHint?: 'enter' | 'done' | 'go' | 'next' | 'previous' | 'search' | 'send' + enterKeyHint?: 'enter' | 'done' | 'go' | 'next' | 'previous' | 'search' | 'send', + /** + * The type of input to render. See [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#htmlattrdeftype). + * @default 'search' + */ + type?: 'text' | 'search' | 'url' | 'tel' | 'email' | 'password' | (string & {}) } export interface SpectrumSearchFieldProps extends SpectrumTextInputBase, Omit, SpectrumTextFieldProps {} diff --git a/packages/@react-types/shared/src/dom.d.ts b/packages/@react-types/shared/src/dom.d.ts index 0d65ea7ce6c..5c36c80cd7e 100644 --- a/packages/@react-types/shared/src/dom.d.ts +++ b/packages/@react-types/shared/src/dom.d.ts @@ -173,6 +173,7 @@ export interface TextInputDOMProps extends DOMProps, InputDOMProps, TextInputDOM /** * The type of input to render. See [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#htmlattrdeftype). + * @default 'text' */ type?: 'text' | 'search' | 'url' | 'tel' | 'email' | 'password' | (string & {}), diff --git a/packages/@react-types/tooltip/src/index.d.ts b/packages/@react-types/tooltip/src/index.d.ts index 46c527973bd..c544fc0bac7 100644 --- a/packages/@react-types/tooltip/src/index.d.ts +++ b/packages/@react-types/tooltip/src/index.d.ts @@ -34,8 +34,9 @@ export interface TooltipTriggerProps extends OverlayTriggerProps { /** * By default, opens for both focus and hover. Can be made to open only for focus. + * @default 'hover' */ - trigger?: 'focus' + trigger?: 'hover' | 'focus' } export interface SpectrumTooltipTriggerProps extends Omit, PositionProps { diff --git a/packages/dev/docs/pages/assets/component-illustrations/ActionButton.svg b/packages/dev/docs/pages/assets/component-illustrations/ActionButton.svg index 3f8eff828d3..09f5ca4e9a0 100644 --- a/packages/dev/docs/pages/assets/component-illustrations/ActionButton.svg +++ b/packages/dev/docs/pages/assets/component-illustrations/ActionButton.svg @@ -8,5 +8,5 @@
- Edit + Edit diff --git a/packages/dev/docs/pages/assets/component-illustrations/Badge.svg b/packages/dev/docs/pages/assets/component-illustrations/Badge.svg index c31ffec7c67..7cdd20c30fd 100644 --- a/packages/dev/docs/pages/assets/component-illustrations/Badge.svg +++ b/packages/dev/docs/pages/assets/component-illustrations/Badge.svg @@ -1,5 +1,5 @@ - Approved + Approved diff --git a/packages/dev/docs/pages/assets/component-illustrations/Breadcrumbs.svg b/packages/dev/docs/pages/assets/component-illustrations/Breadcrumbs.svg index fabf49c25aa..39ab75feb3d 100644 --- a/packages/dev/docs/pages/assets/component-illustrations/Breadcrumbs.svg +++ b/packages/dev/docs/pages/assets/component-illustrations/Breadcrumbs.svg @@ -5,9 +5,9 @@
- Home - Assets - Photos + Home + Assets + Photos diff --git a/packages/dev/docs/pages/assets/component-illustrations/Button.svg b/packages/dev/docs/pages/assets/component-illustrations/Button.svg index da40b64eff0..c088165951b 100644 --- a/packages/dev/docs/pages/assets/component-illustrations/Button.svg +++ b/packages/dev/docs/pages/assets/component-illustrations/Button.svg @@ -7,5 +7,5 @@ - Save + Save diff --git a/packages/dev/docs/pages/assets/component-illustrations/ButtonGroup.svg b/packages/dev/docs/pages/assets/component-illustrations/ButtonGroup.svg index aa06a661d1d..030f68440b5 100644 --- a/packages/dev/docs/pages/assets/component-illustrations/ButtonGroup.svg +++ b/packages/dev/docs/pages/assets/component-illustrations/ButtonGroup.svg @@ -6,7 +6,7 @@ - Cancel + Cancel @@ -14,6 +14,6 @@ - Submit + Submit diff --git a/packages/dev/docs/pages/assets/component-illustrations/Calendar.svg b/packages/dev/docs/pages/assets/component-illustrations/Calendar.svg index b57b69350d9..5cb7dd5fd1a 100644 --- a/packages/dev/docs/pages/assets/component-illustrations/Calendar.svg +++ b/packages/dev/docs/pages/assets/component-illustrations/Calendar.svg @@ -1,47 +1,47 @@ - September 2021 - S - M - T - W - T - F - 5 - 7 - 8 - 9 - 10 - 13 - 14 - 15 - 16 - 19 - 20 - 21 - 22 - 23 - 24 - 1 - 2 - 3 + September 2021 + S + M + T + W + T + F + 5 + 7 + 8 + 9 + 10 + 13 + 14 + 15 + 16 + 19 + 20 + 21 + 22 + 23 + 24 + 1 + 2 + 3 - 26 - 27 - 29 - 30 - 6 - 28 + 26 + 27 + 29 + 30 + 6 + 28 - S - 11 - 18 - 25 - 4 + S + 11 + 18 + 25 + 4 - 12 - 17 + 12 + 17 - 6 + 6 diff --git a/packages/dev/docs/pages/assets/component-illustrations/Checkbox.svg b/packages/dev/docs/pages/assets/component-illustrations/Checkbox.svg index 472b2c8d164..b7d82c47465 100644 --- a/packages/dev/docs/pages/assets/component-illustrations/Checkbox.svg +++ b/packages/dev/docs/pages/assets/component-illustrations/Checkbox.svg @@ -14,5 +14,5 @@ - Subscribe + Subscribe diff --git a/packages/dev/docs/pages/assets/component-illustrations/CheckboxGroup.svg b/packages/dev/docs/pages/assets/component-illustrations/CheckboxGroup.svg index 30849c13675..43eb524c6a4 100644 --- a/packages/dev/docs/pages/assets/component-illustrations/CheckboxGroup.svg +++ b/packages/dev/docs/pages/assets/component-illustrations/CheckboxGroup.svg @@ -7,7 +7,7 @@ - Travel + Travel @@ -16,7 +16,7 @@ - Music + Music @@ -24,11 +24,11 @@ - Shopping + Shopping - Interests + Interests diff --git a/packages/dev/docs/pages/assets/component-illustrations/ColorField.svg b/packages/dev/docs/pages/assets/component-illustrations/ColorField.svg index eaee4495cec..4eb5b4aa89c 100644 --- a/packages/dev/docs/pages/assets/component-illustrations/ColorField.svg +++ b/packages/dev/docs/pages/assets/component-illustrations/ColorField.svg @@ -2,11 +2,11 @@ - Background + Background - #ABCDEF + #ABCDEF diff --git a/packages/dev/docs/pages/assets/component-illustrations/ColorPicker.svg b/packages/dev/docs/pages/assets/component-illustrations/ColorPicker.svg index 1e2ec967d66..2c141b60017 100644 --- a/packages/dev/docs/pages/assets/component-illustrations/ColorPicker.svg +++ b/packages/dev/docs/pages/assets/component-illustrations/ColorPicker.svg @@ -81,7 +81,7 @@ - #ABCDEF + #ABCDEF diff --git a/packages/dev/docs/pages/assets/component-illustrations/ComboBox.svg b/packages/dev/docs/pages/assets/component-illustrations/ComboBox.svg index f9be42aa17c..f97574a4bb4 100644 --- a/packages/dev/docs/pages/assets/component-illustrations/ComboBox.svg +++ b/packages/dev/docs/pages/assets/component-illustrations/ComboBox.svg @@ -14,14 +14,14 @@ - Favorite animal + Favorite animal - Ca + Ca @@ -52,22 +52,22 @@ - Camel + Camel - Capybara + Capybara - Caribou + Caribou - Cat + Cat diff --git a/packages/dev/docs/pages/assets/component-illustrations/ComingSoon.svg b/packages/dev/docs/pages/assets/component-illustrations/ComingSoon.svg new file mode 100644 index 00000000000..66e8701aa2c --- /dev/null +++ b/packages/dev/docs/pages/assets/component-illustrations/ComingSoon.svg @@ -0,0 +1,3 @@ + + Image Coming Soon + diff --git a/packages/dev/docs/pages/assets/component-illustrations/ContextualHelp.svg b/packages/dev/docs/pages/assets/component-illustrations/ContextualHelp.svg index e9e62fbba57..2eb332c6406 100644 --- a/packages/dev/docs/pages/assets/component-illustrations/ContextualHelp.svg +++ b/packages/dev/docs/pages/assets/component-illustrations/ContextualHelp.svg @@ -15,7 +15,7 @@ - Permission required + Permission required @@ -27,7 +27,7 @@ - Your admin must grant you permission before you can create a segment. - Learn about permissions + Your admin must grant you permission before you can create a segment. + Learn about permissions diff --git a/packages/dev/docs/pages/assets/component-illustrations/DateField.svg b/packages/dev/docs/pages/assets/component-illustrations/DateField.svg index c0bc6df9fe6..d3c32143db3 100644 --- a/packages/dev/docs/pages/assets/component-illustrations/DateField.svg +++ b/packages/dev/docs/pages/assets/component-illustrations/DateField.svg @@ -6,9 +6,9 @@ - Event date + Event date - 8 / 15 / 2022 + 8 / 15 / 2022 diff --git a/packages/dev/docs/pages/assets/component-illustrations/DatePicker.svg b/packages/dev/docs/pages/assets/component-illustrations/DatePicker.svg index 2be322b45cc..5097b1fa8a8 100644 --- a/packages/dev/docs/pages/assets/component-illustrations/DatePicker.svg +++ b/packages/dev/docs/pages/assets/component-illustrations/DatePicker.svg @@ -15,10 +15,10 @@ - Event date + Event date - 9 / 10 / 2021 + 9 / 10 / 2021 @@ -96,46 +96,46 @@ - September 2021 - S - M - T - W - T - F - 5 - 7 - 8 - 9 - 10 - 13 - 14 - 15 - 16 - 19 - 20 - 21 - 22 - 23 - 24 - 1 - 2 - 3 + September 2021 + S + M + T + W + T + F + 5 + 7 + 8 + 9 + 10 + 13 + 14 + 15 + 16 + 19 + 20 + 21 + 22 + 23 + 24 + 1 + 2 + 3 - 26 - 27 - 29 - 30 - 6 - 28 - S - 11 - 18 - 25 - 4 + 26 + 27 + 29 + 30 + 6 + 28 + S + 11 + 18 + 25 + 4 - 12 + 12 - 10 + 10 diff --git a/packages/dev/docs/pages/assets/component-illustrations/DateRangePicker.svg b/packages/dev/docs/pages/assets/component-illustrations/DateRangePicker.svg index 15f12bb3caa..c33a1cd2b07 100644 --- a/packages/dev/docs/pages/assets/component-illustrations/DateRangePicker.svg +++ b/packages/dev/docs/pages/assets/component-illustrations/DateRangePicker.svg @@ -27,53 +27,53 @@ - September 2021 - S - M - T - W - T - F - 5 - 7 - 8 - 9 - 10 - 13 - 14 - 15 - 16 - 19 - 20 - 21 - 22 - 23 - 24 - 1 - 2 - 3 + September 2021 + S + M + T + W + T + F + 5 + 7 + 8 + 9 + 10 + 13 + 14 + 15 + 16 + 19 + 20 + 21 + 22 + 23 + 24 + 1 + 2 + 3 - 26 - 27 - 29 - 30 - 6 - 28 - S - 11 - 18 - 25 - 4 + 26 + 27 + 29 + 30 + 6 + 28 + S + 11 + 18 + 25 + 4 - 12 - 17 - 6 + 12 + 17 + 6 - Event date + Event date @@ -145,11 +145,11 @@ - 9 / 8 / 2021 + 9 / 8 / 2021 - 9 / 3 / 2021 – + 9 / 3 / 2021 – diff --git a/packages/dev/docs/pages/assets/component-illustrations/Dialog.svg b/packages/dev/docs/pages/assets/component-illustrations/Dialog.svg index 1ea1e435244..e3254cc37f8 100644 --- a/packages/dev/docs/pages/assets/component-illustrations/Dialog.svg +++ b/packages/dev/docs/pages/assets/component-illustrations/Dialog.svg @@ -1,12 +1,12 @@ - Delete file + Delete file - Are you sure you want to delete "budget.xls"? It cannot be recovered. + Are you sure you want to delete "budget.xls"? It cannot be recovered. @@ -15,7 +15,7 @@ - Cancel + Cancel @@ -23,7 +23,7 @@ - Delete + Delete diff --git a/packages/dev/docs/pages/assets/component-illustrations/Disclosure.svg b/packages/dev/docs/pages/assets/component-illustrations/Disclosure.svg index 61196f4c651..624589b1b6b 100644 --- a/packages/dev/docs/pages/assets/component-illustrations/Disclosure.svg +++ b/packages/dev/docs/pages/assets/component-illustrations/Disclosure.svg @@ -1,5 +1,5 @@ - Recent + Recent diff --git a/packages/dev/docs/pages/assets/component-illustrations/DisclosureGroup.svg b/packages/dev/docs/pages/assets/component-illustrations/DisclosureGroup.svg index a9ab5792ddc..18b9174c876 100644 --- a/packages/dev/docs/pages/assets/component-illustrations/DisclosureGroup.svg +++ b/packages/dev/docs/pages/assets/component-illustrations/DisclosureGroup.svg @@ -5,6 +5,6 @@ - Recent - Abstract + Recent + Abstract diff --git a/packages/dev/docs/pages/assets/component-illustrations/DragAndDrop.svg b/packages/dev/docs/pages/assets/component-illustrations/DragAndDrop.svg index e16e45eab56..fa69c1060b4 100644 --- a/packages/dev/docs/pages/assets/component-illustrations/DragAndDrop.svg +++ b/packages/dev/docs/pages/assets/component-illustrations/DragAndDrop.svg @@ -14,7 +14,7 @@ - Applications + Applications @@ -22,7 +22,7 @@ - Pictures + Pictures @@ -30,7 +30,7 @@ - Downloads + Downloads @@ -41,7 +41,7 @@ - Shared + Shared @@ -71,7 +71,7 @@ - Music + Music @@ -80,7 +80,7 @@ - 2 + 2 diff --git a/packages/dev/docs/pages/assets/component-illustrations/DropZone.svg b/packages/dev/docs/pages/assets/component-illustrations/DropZone.svg index 2b9b5589623..0d7a4989000 100644 --- a/packages/dev/docs/pages/assets/component-illustrations/DropZone.svg +++ b/packages/dev/docs/pages/assets/component-illustrations/DropZone.svg @@ -262,7 +262,7 @@ - Drag and drop your file + Drag and drop your file diff --git a/packages/dev/docs/pages/assets/component-illustrations/FileTrigger.svg b/packages/dev/docs/pages/assets/component-illustrations/FileTrigger.svg index 87a7237919d..6d95f1dd31a 100644 --- a/packages/dev/docs/pages/assets/component-illustrations/FileTrigger.svg +++ b/packages/dev/docs/pages/assets/component-illustrations/FileTrigger.svg @@ -3,7 +3,7 @@ - + Select a file diff --git a/packages/dev/docs/pages/assets/component-illustrations/FocusScope.svg b/packages/dev/docs/pages/assets/component-illustrations/FocusScope.svg index 25996cc9a7c..02f2c3005e9 100644 --- a/packages/dev/docs/pages/assets/component-illustrations/FocusScope.svg +++ b/packages/dev/docs/pages/assets/component-illustrations/FocusScope.svg @@ -21,7 +21,7 @@ - + @@ -30,7 +30,7 @@ - + diff --git a/packages/dev/docs/pages/assets/component-illustrations/Form.svg b/packages/dev/docs/pages/assets/component-illustrations/Form.svg index 134d34f9411..d638b381220 100644 --- a/packages/dev/docs/pages/assets/component-illustrations/Form.svg +++ b/packages/dev/docs/pages/assets/component-illustrations/Form.svg @@ -4,13 +4,13 @@ - Email + Email - someone@example.com + someone@example.com @@ -19,13 +19,13 @@ - Password + Password - •••••••• + •••••••• @@ -33,11 +33,11 @@ - Remember me + Remember me - This account does not exist. + This account does not exist. @@ -45,7 +45,7 @@ - Sign In + Sign In diff --git a/packages/dev/docs/pages/assets/component-illustrations/Input.svg b/packages/dev/docs/pages/assets/component-illustrations/Input.svg index 49dc292dcae..c7ac57e545c 100644 --- a/packages/dev/docs/pages/assets/component-illustrations/Input.svg +++ b/packages/dev/docs/pages/assets/component-illustrations/Input.svg @@ -4,5 +4,5 @@ - 123 Any St. + 123 Any St. diff --git a/packages/dev/docs/pages/assets/component-illustrations/Label.svg b/packages/dev/docs/pages/assets/component-illustrations/Label.svg index 615a0639faf..35690f6b7a2 100644 --- a/packages/dev/docs/pages/assets/component-illustrations/Label.svg +++ b/packages/dev/docs/pages/assets/component-illustrations/Label.svg @@ -1,3 +1,3 @@ - Address + Address diff --git a/packages/dev/docs/pages/assets/component-illustrations/LabeledValue.svg b/packages/dev/docs/pages/assets/component-illustrations/LabeledValue.svg index feaef078440..7a7091d86ed 100644 --- a/packages/dev/docs/pages/assets/component-illustrations/LabeledValue.svg +++ b/packages/dev/docs/pages/assets/component-illustrations/LabeledValue.svg @@ -1,7 +1,7 @@ - Aperture + Aperture - f/1.5 + f/1.5 diff --git a/packages/dev/docs/pages/assets/component-illustrations/Link.svg b/packages/dev/docs/pages/assets/component-illustrations/Link.svg index 65fa4ed0766..941e3e0de70 100644 --- a/packages/dev/docs/pages/assets/component-illustrations/Link.svg +++ b/packages/dev/docs/pages/assets/component-illustrations/Link.svg @@ -1,3 +1,3 @@ - About + About diff --git a/packages/dev/docs/pages/assets/component-illustrations/ListBox.svg b/packages/dev/docs/pages/assets/component-illustrations/ListBox.svg index 9c001a792f2..85c8ce744a7 100644 --- a/packages/dev/docs/pages/assets/component-illustrations/ListBox.svg +++ b/packages/dev/docs/pages/assets/component-illustrations/ListBox.svg @@ -8,16 +8,16 @@ - Option 1 - Option 2 + Option 1 + Option 2 - Description - Description - Option 3 - Description - SECTION TITLE + Description + Description + Option 3 + Description + SECTION TITLE diff --git a/packages/dev/docs/pages/assets/component-illustrations/ListView.svg b/packages/dev/docs/pages/assets/component-illustrations/ListView.svg index b57a6e2f456..0fa77307f4f 100644 --- a/packages/dev/docs/pages/assets/component-illustrations/ListView.svg +++ b/packages/dev/docs/pages/assets/component-illustrations/ListView.svg @@ -9,7 +9,7 @@ - Documents + Documents @@ -131,13 +131,13 @@ - 12 items - Onboarding - PDF - Budget - XLS - Sales Pitch - PPT + 12 items + Onboarding + PDF + Budget + XLS + Sales Pitch + PPT diff --git a/packages/dev/docs/pages/assets/component-illustrations/Menu.svg b/packages/dev/docs/pages/assets/component-illustrations/Menu.svg index e4601df2b35..7bd8f3ad1f3 100644 --- a/packages/dev/docs/pages/assets/component-illustrations/Menu.svg +++ b/packages/dev/docs/pages/assets/component-illustrations/Menu.svg @@ -32,11 +32,11 @@ - Edit… + Edit… - Rename… + Rename… - Delete… + Delete… diff --git a/packages/dev/docs/pages/assets/component-illustrations/Meter.svg b/packages/dev/docs/pages/assets/component-illustrations/Meter.svg index 49b8684bca6..767da3db1c0 100644 --- a/packages/dev/docs/pages/assets/component-illustrations/Meter.svg +++ b/packages/dev/docs/pages/assets/component-illustrations/Meter.svg @@ -2,6 +2,6 @@ - Storage space - 30% + Storage space + 30% diff --git a/packages/dev/docs/pages/assets/component-illustrations/NumberField.svg b/packages/dev/docs/pages/assets/component-illustrations/NumberField.svg index 992008e634b..78764d80fb0 100644 --- a/packages/dev/docs/pages/assets/component-illustrations/NumberField.svg +++ b/packages/dev/docs/pages/assets/component-illustrations/NumberField.svg @@ -2,13 +2,13 @@ - Width + Width - 4 in + 4 in diff --git a/packages/dev/docs/pages/assets/component-illustrations/Picker.svg b/packages/dev/docs/pages/assets/component-illustrations/Picker.svg index e635f781955..96211c84bc9 100644 --- a/packages/dev/docs/pages/assets/component-illustrations/Picker.svg +++ b/packages/dev/docs/pages/assets/component-illustrations/Picker.svg @@ -10,12 +10,12 @@ - Favorite color + Favorite color - Orange + Orange @@ -30,13 +30,13 @@ - Red + Red - Orange + Orange - Yellow + Yellow - Green + Green diff --git a/packages/dev/docs/pages/assets/component-illustrations/Popover.svg b/packages/dev/docs/pages/assets/component-illustrations/Popover.svg index 559ddbdb66a..85ee3c140f0 100644 --- a/packages/dev/docs/pages/assets/component-illustrations/Popover.svg +++ b/packages/dev/docs/pages/assets/component-illustrations/Popover.svg @@ -15,7 +15,7 @@ - Properties + Properties @@ -33,25 +33,25 @@ - Width + Width - 250 px + 250 px - Height + Height - 100 px + 100 px diff --git a/packages/dev/docs/pages/assets/component-illustrations/ProgressBar.svg b/packages/dev/docs/pages/assets/component-illustrations/ProgressBar.svg index 74868a70a47..4a3251123c3 100644 --- a/packages/dev/docs/pages/assets/component-illustrations/ProgressBar.svg +++ b/packages/dev/docs/pages/assets/component-illustrations/ProgressBar.svg @@ -2,6 +2,6 @@ - Loading... - 60% + Loading... + 60% diff --git a/packages/dev/docs/pages/assets/component-illustrations/RadioGroup.svg b/packages/dev/docs/pages/assets/component-illustrations/RadioGroup.svg index 7dbf9c88282..ee64202a2db 100644 --- a/packages/dev/docs/pages/assets/component-illustrations/RadioGroup.svg +++ b/packages/dev/docs/pages/assets/component-illustrations/RadioGroup.svg @@ -6,7 +6,7 @@ - Small + Small @@ -14,7 +14,7 @@ - Medium + Medium @@ -22,11 +22,11 @@ - Large + Large - Size + Size diff --git a/packages/dev/docs/pages/assets/component-illustrations/RangeCalendar.svg b/packages/dev/docs/pages/assets/component-illustrations/RangeCalendar.svg index 25f1b8c5b34..7d46c67c25e 100644 --- a/packages/dev/docs/pages/assets/component-illustrations/RangeCalendar.svg +++ b/packages/dev/docs/pages/assets/component-illustrations/RangeCalendar.svg @@ -5,49 +5,49 @@ - September 2021 - S - M - T - W - T - F - 5 - 7 - 8 - 9 - 10 - 13 - 14 - 15 - 16 - 19 - 20 - 21 - 22 - 23 - 24 - 1 - 2 - 3 + September 2021 + S + M + T + W + T + F + 5 + 7 + 8 + 9 + 10 + 13 + 14 + 15 + 16 + 19 + 20 + 21 + 22 + 23 + 24 + 1 + 2 + 3 - 26 - 27 - 29 - 30 - 6 - 28 + 26 + 27 + 29 + 30 + 6 + 28 - S - 11 - 18 - 25 - 4 + S + 11 + 18 + 25 + 4 - 12 + 12 - 17 + 17 - 6 + 6 diff --git a/packages/dev/docs/pages/assets/component-illustrations/RangeSlider.svg b/packages/dev/docs/pages/assets/component-illustrations/RangeSlider.svg index 72851c02d40..ee40e5c7a68 100644 --- a/packages/dev/docs/pages/assets/component-illustrations/RangeSlider.svg +++ b/packages/dev/docs/pages/assets/component-illustrations/RangeSlider.svg @@ -1,6 +1,6 @@ - Price range + Price range @@ -9,7 +9,7 @@ - $100 – $300 + $100 – $300 diff --git a/packages/dev/docs/pages/assets/component-illustrations/SearchField.svg b/packages/dev/docs/pages/assets/component-illustrations/SearchField.svg index 201e83fc5a2..a6cae39f9cf 100644 --- a/packages/dev/docs/pages/assets/component-illustrations/SearchField.svg +++ b/packages/dev/docs/pages/assets/component-illustrations/SearchField.svg @@ -2,13 +2,13 @@ - Search + Search - Hawaii + Hawaii diff --git a/packages/dev/docs/pages/assets/component-illustrations/Slider.svg b/packages/dev/docs/pages/assets/component-illustrations/Slider.svg index 44e7ee497cd..cd71823662c 100644 --- a/packages/dev/docs/pages/assets/component-illustrations/Slider.svg +++ b/packages/dev/docs/pages/assets/component-illustrations/Slider.svg @@ -1,6 +1,6 @@ - Exposure + Exposure @@ -9,5 +9,5 @@ - +20 + +20 diff --git a/packages/dev/docs/pages/assets/component-illustrations/StatusLight.svg b/packages/dev/docs/pages/assets/component-illustrations/StatusLight.svg index 4b117fe2b73..489e922d277 100644 --- a/packages/dev/docs/pages/assets/component-illustrations/StatusLight.svg +++ b/packages/dev/docs/pages/assets/component-illustrations/StatusLight.svg @@ -1,5 +1,5 @@ - Draft + Draft diff --git a/packages/dev/docs/pages/assets/component-illustrations/Switch.svg b/packages/dev/docs/pages/assets/component-illustrations/Switch.svg index abcd125cd3e..02e3bcef7ef 100644 --- a/packages/dev/docs/pages/assets/component-illustrations/Switch.svg +++ b/packages/dev/docs/pages/assets/component-illustrations/Switch.svg @@ -5,5 +5,5 @@ - Low power mode + Low power mode diff --git a/packages/dev/docs/pages/assets/component-illustrations/Table.svg b/packages/dev/docs/pages/assets/component-illustrations/Table.svg index d18701ae257..bac963c39ca 100644 --- a/packages/dev/docs/pages/assets/component-illustrations/Table.svg +++ b/packages/dev/docs/pages/assets/component-illustrations/Table.svg @@ -1,21 +1,21 @@ - SIZE + SIZE - 214 KB + 214 KB - 120 KB - 139 KB - Proposal - Budget - Onboarding - FILE NAME + 120 KB + 139 KB + Proposal + Budget + Onboarding + FILE NAME diff --git a/packages/dev/docs/pages/assets/component-illustrations/Tabs.svg b/packages/dev/docs/pages/assets/component-illustrations/Tabs.svg index 6890f2a820b..1f7e751a41d 100644 --- a/packages/dev/docs/pages/assets/component-illustrations/Tabs.svg +++ b/packages/dev/docs/pages/assets/component-illustrations/Tabs.svg @@ -7,7 +7,7 @@ - Photos + Photos @@ -16,7 +16,7 @@ - Videos + Videos @@ -24,7 +24,7 @@ - Documents + Documents diff --git a/packages/dev/docs/pages/assets/component-illustrations/TagGroup.svg b/packages/dev/docs/pages/assets/component-illustrations/TagGroup.svg index 8fa0a398f6d..9b3c6cd559a 100644 --- a/packages/dev/docs/pages/assets/component-illustrations/TagGroup.svg +++ b/packages/dev/docs/pages/assets/component-illustrations/TagGroup.svg @@ -5,7 +5,7 @@ - Traveling + Traveling @@ -17,13 +17,13 @@ - Hiking + Hiking - Categories + Categories diff --git a/packages/dev/docs/pages/assets/component-illustrations/TextArea.svg b/packages/dev/docs/pages/assets/component-illustrations/TextArea.svg index 475aaa71f64..e39c5a7e41e 100644 --- a/packages/dev/docs/pages/assets/component-illustrations/TextArea.svg +++ b/packages/dev/docs/pages/assets/component-illustrations/TextArea.svg @@ -2,11 +2,11 @@ - Comment + Comment - Lorem ipsum dolor sit amet, consectetur + Lorem ipsum dolor sit amet, consectetur diff --git a/packages/dev/docs/pages/assets/component-illustrations/TextField.svg b/packages/dev/docs/pages/assets/component-illustrations/TextField.svg index 0df9d2992d0..b70633092f1 100644 --- a/packages/dev/docs/pages/assets/component-illustrations/TextField.svg +++ b/packages/dev/docs/pages/assets/component-illustrations/TextField.svg @@ -2,11 +2,11 @@ - Address + Address - 123 Any St. + 123 Any St. diff --git a/packages/dev/docs/pages/assets/component-illustrations/TimeField.svg b/packages/dev/docs/pages/assets/component-illustrations/TimeField.svg index f0d1036a961..35bf06b273b 100644 --- a/packages/dev/docs/pages/assets/component-illustrations/TimeField.svg +++ b/packages/dev/docs/pages/assets/component-illustrations/TimeField.svg @@ -6,9 +6,9 @@ - Appointment time + Appointment time - 12 : 45 PM + 12 : 45 PM diff --git a/packages/dev/docs/pages/assets/component-illustrations/Toast.svg b/packages/dev/docs/pages/assets/component-illustrations/Toast.svg index 5251da7415f..c14aed2d0c6 100644 --- a/packages/dev/docs/pages/assets/component-illustrations/Toast.svg +++ b/packages/dev/docs/pages/assets/component-illustrations/Toast.svg @@ -8,7 +8,7 @@ - + Analysis complete! - Pin + Pin diff --git a/packages/dev/docs/pages/assets/component-illustrations/Tooltip.svg b/packages/dev/docs/pages/assets/component-illustrations/Tooltip.svg index eda6569ec3e..1facfa8d52e 100644 --- a/packages/dev/docs/pages/assets/component-illustrations/Tooltip.svg +++ b/packages/dev/docs/pages/assets/component-illustrations/Tooltip.svg @@ -4,7 +4,7 @@ - Edit + Edit diff --git a/packages/dev/docs/pages/assets/component-illustrations/Tree.svg b/packages/dev/docs/pages/assets/component-illustrations/Tree.svg index 11283245e7a..0f4b4558c3c 100644 --- a/packages/dev/docs/pages/assets/component-illustrations/Tree.svg +++ b/packages/dev/docs/pages/assets/component-illustrations/Tree.svg @@ -13,7 +13,7 @@ - Documents + Documents @@ -55,25 +55,25 @@ - 12 items + 12 items - Onboarding - PDF + Onboarding + PDF - Budget - XLS + Budget + XLS - Sales Pitch - PPT + Sales Pitch + PPT @@ -99,7 +99,7 @@ - Documents + Documents @@ -141,25 +141,25 @@ - 12 items + 12 items - Onboarding - PDF + Onboarding + PDF - Budget - XLS + Budget + XLS - Sales Pitch - PPT + Sales Pitch + PPT diff --git a/packages/dev/docs/pages/assets/component-illustrations/useFocus.svg b/packages/dev/docs/pages/assets/component-illustrations/useFocus.svg index 54f8876e28a..4041d0a4941 100644 --- a/packages/dev/docs/pages/assets/component-illustrations/useFocus.svg +++ b/packages/dev/docs/pages/assets/component-illustrations/useFocus.svg @@ -4,6 +4,6 @@ - + diff --git a/packages/dev/docs/pages/assets/component-illustrations/useFocusWithin.svg b/packages/dev/docs/pages/assets/component-illustrations/useFocusWithin.svg index 2784a2d4382..84096897256 100644 --- a/packages/dev/docs/pages/assets/component-illustrations/useFocusWithin.svg +++ b/packages/dev/docs/pages/assets/component-illustrations/useFocusWithin.svg @@ -18,7 +18,7 @@ - + diff --git a/packages/dev/docs/pages/assets/daterangepicker-anatomy.svg b/packages/dev/docs/pages/assets/daterangepicker-anatomy.svg index fc0fc0bba8f..f03ddde5199 100644 --- a/packages/dev/docs/pages/assets/daterangepicker-anatomy.svg +++ b/packages/dev/docs/pages/assets/daterangepicker-anatomy.svg @@ -26,59 +26,59 @@ - September 2021 - S - M - T - W - T - F - 5 - 7 - 8 - 9 - 10 - 13 - 14 - 15 - 16 - 19 - 20 - 21 - 22 - 23 - 24 - 1 - 2 - 3 + September 2021 + S + M + T + W + T + F + 5 + 7 + 8 + 9 + 10 + 13 + 14 + 15 + 16 + 19 + 20 + 21 + 22 + 23 + 24 + 1 + 2 + 3 - 26 - 27 - 29 - 30 - 6 - 28 + 26 + 27 + 29 + 30 + 6 + 28 - S - 11 - 18 - 25 - 4 + S + 11 + 18 + 25 + 4 - 12 + 12 - 17 + 17 - 6 + 6 - Event date + Event date - Group + Group @@ -86,7 +86,7 @@ - Label + Label @@ -159,36 +159,36 @@ - Button + Button - Start field + Start field - End field + End field - Calendar + Calendar - Dialog + Dialog - 9 / 17 / 2021 + 9 / 17 / 2021 - 9 / 6 / 2021 – + 9 / 6 / 2021 – diff --git a/packages/dev/docs/pages/assets/rtl-actual-placeholder.svg b/packages/dev/docs/pages/assets/rtl-actual-placeholder.svg index f781bed83e4..f5ff855aafb 100644 --- a/packages/dev/docs/pages/assets/rtl-actual-placeholder.svg +++ b/packages/dev/docs/pages/assets/rtl-actual-placeholder.svg @@ -4,30 +4,29 @@ - Date + Date - ۸:۴۵ , ۱۳۹۹/۱۲/۲۴ + ۸:۴۵ , ۱۳۹۹/۱۲/۲۴ - With actual values (fa-AF) + With actual values (fa-AF) - With placeholder values (fa-AF) + With placeholder values (fa-AF) - Date + Date - —:— , روز/ماه/سال + —:— , روز/ماه/سال - Hour:Minute Year/Month/Day - Minute:Hour Day/Month/Year + Hour:Minute Year/Month/Day + Minute:Hour Day/Month/Year - diff --git a/packages/dev/docs/pages/assets/rtl-timefield.svg b/packages/dev/docs/pages/assets/rtl-timefield.svg index df6e5ba9d92..ea621765b97 100644 --- a/packages/dev/docs/pages/assets/rtl-timefield.svg +++ b/packages/dev/docs/pages/assets/rtl-timefield.svg @@ -1,33 +1,30 @@ - Incorrect (he-IL) + Incorrect (he-IL) - Start Date + Start Date - 45:8 , 2025.1.31 + 45:8 , 2025.1.31 - Start Date + Start Date - 8:45 , 31.1.2025 + 8:45 , 31.1.2025 - Correct (he-IL) + Correct (he-IL) - - - diff --git a/packages/dev/docs/pages/assets/submenu-atan2-from-pointer.svg b/packages/dev/docs/pages/assets/submenu-atan2-from-pointer.svg index 7f173d1fd51..e6dc0b22830 100644 --- a/packages/dev/docs/pages/assets/submenu-atan2-from-pointer.svg +++ b/packages/dev/docs/pages/assets/submenu-atan2-from-pointer.svg @@ -34,9 +34,9 @@ - Θtop - Θbottom - Θpointer + Θtop + Θbottom + Θpointer diff --git a/packages/dev/docs/pages/assets/submenu-atan2.svg b/packages/dev/docs/pages/assets/submenu-atan2.svg index 5df0d7f3f12..3aed2369b62 100644 --- a/packages/dev/docs/pages/assets/submenu-atan2.svg +++ b/packages/dev/docs/pages/assets/submenu-atan2.svg @@ -20,9 +20,9 @@ - Θ = atan2(y,x) + Θ = atan2(y,x) - (x,y) + (x,y) diff --git a/packages/dev/docs/pages/assets/submenu-safe-area.svg b/packages/dev/docs/pages/assets/submenu-safe-area.svg index b6d622d3484..bae8b3e89b4 100644 --- a/packages/dev/docs/pages/assets/submenu-safe-area.svg +++ b/packages/dev/docs/pages/assets/submenu-safe-area.svg @@ -38,18 +38,18 @@ - More Actions + More Actions - Option 5 - Option 4 - Option 3 - Option 2 - Option 1 + Option 5 + Option 4 + Option 3 + Option 2 + Option 1 @@ -63,11 +63,11 @@ - Submenu Option 3 - Submenu Option 4 - Submenu Option 5 - Submenu Option 2 - Submenu Option 1 + Submenu Option 3 + Submenu Option 4 + Submenu Option 5 + Submenu Option 2 + Submenu Option 1 diff --git a/packages/dev/docs/src/docs.css b/packages/dev/docs/src/docs.css index 0aa8e6e5aeb..02cb18777f1 100644 --- a/packages/dev/docs/src/docs.css +++ b/packages/dev/docs/src/docs.css @@ -152,6 +152,7 @@ html, body { --anatomy-gray-50: #FFFFFF; --docsearch-logo-color: #5468FF; --anatomy-radius: 4px; + --anatomy-font: adobe-clean; } .dark { diff --git a/packages/dev/mcp/package.json b/packages/dev/mcp/package.json new file mode 100644 index 00000000000..521fd96c3b4 --- /dev/null +++ b/packages/dev/mcp/package.json @@ -0,0 +1,44 @@ +{ + "name": "@react-spectrum/mcp", + "version": "0.1.0", + "description": "MCP server for React Spectrum (S2) and React Aria documentation", + "type": "module", + "bin": "dist/index.js", + "scripts": { + "build": "tsc -p tsconfig.json", + "start": "node dist/index.js", + "dev": "node --enable-source-maps dist/index.js" + }, + "dependencies": { + "@modelcontextprotocol/sdk": "^1.17.3", + "@swc/helpers": "^0.5.0", + "fast-glob": "^3.3.3", + "zod": "^3.23.8" + }, + "devDependencies": { + "@adobe/spectrum-css-temp": "3.0.0-alpha.1", + "typescript": "^5.8.2" + }, + "engines": { + "node": ">=18" + }, + "license": "Apache-2.0", + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "https://github.com/adobe/react-spectrum" + }, + "main": "dist/main.js", + "module": "dist/module.js", + "types": "dist/types.d.ts", + "source": "src/index.ts", + "files": [ + "dist", + "src" + ], + "sideEffects": [ + "*.css" + ] +} diff --git a/packages/dev/mcp/scripts/smoke-list-pages.mjs b/packages/dev/mcp/scripts/smoke-list-pages.mjs new file mode 100644 index 00000000000..d666846d990 --- /dev/null +++ b/packages/dev/mcp/scripts/smoke-list-pages.mjs @@ -0,0 +1,28 @@ +#!/usr/bin/env node +import {Client} from '@modelcontextprotocol/sdk/client/index.js'; +import {StdioClientTransport} from '@modelcontextprotocol/sdk/client/stdio.js'; + +async function main() { + const subcommand = process.argv[2] || 's2'; + const transport = new StdioClientTransport({ + command: 'node', + args: [new URL('../dist/index.js', import.meta.url).pathname, subcommand] + }); + + const client = new Client({name: 's2-docs-smoke', version: '0.0.0'}); + await client.connect(transport); + + const result = await client.callTool({ + name: 'list_pages', + arguments: {includeDescription: true} + }); + + const text = result?.content?.[0]?.text ?? ''; + console.log(text); + process.exit(0); +} + +main().catch((err) => { + console.error(err?.stack || String(err)); + process.exit(1); +}); diff --git a/packages/dev/mcp/src/index.ts b/packages/dev/mcp/src/index.ts new file mode 100644 index 00000000000..b978b110221 --- /dev/null +++ b/packages/dev/mcp/src/index.ts @@ -0,0 +1,404 @@ +#!/usr/bin/env node +import fg from 'fast-glob'; +import {fileURLToPath, pathToFileURL} from 'url'; +import fs from 'fs'; +import {McpServer} from '@modelcontextprotocol/sdk/server/mcp.js'; +import path from 'path'; +import {StdioServerTransport} from '@modelcontextprotocol/sdk/server/stdio.js'; +import {z} from 'zod'; + +type SectionInfo = { + name: string, + startLine: number, // 0-based index where section heading starts + endLine: number // exclusive end line index for section content +}; + +type PageInfo = { + key: string, // e.g. "s2/Button" + title: string, // from top-level heading + description?: string, // first paragraph after title + filePath: string, // absolute path to markdown file + sections: SectionInfo[] +}; + +type Library = 's2' | 'react-aria'; + +function errorToString(err: unknown): string { + if (err && typeof err === 'object' && 'stack' in err && typeof (err as any).stack === 'string') { + return (err as any).stack as string; + } + if (err && typeof err === 'object' && 'message' in err && typeof (err as any).message === 'string') { + return (err as any).message as string; + } + try { + return JSON.stringify(err); + } catch { + return String(err); + } +} + +// Resolve docs dist root based on this file location +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); +const DOCS_DIST_ROOT = path.resolve(__dirname, '../../s2-docs/dist'); + +function assertDocsExist() { + if (!fs.existsSync(DOCS_DIST_ROOT)) { + const hint = path.resolve(__dirname, '../../s2-docs/scripts/generateMarkdownDocs.mjs'); + throw new Error(`S2 docs dist not found at ${DOCS_DIST_ROOT}. Build them first via: yarn workspace @react-spectrum/s2-docs generate:md (script: ${hint})`); + } +} + +// Cache of parsed pages +const pageCache = new Map(); + +const ICONS_DIR = path.resolve(__dirname, '../../../@react-spectrum/s2/s2wf-icons'); +let iconIdCache: string[] | null = null; +const ILLUSTRATIONS_DIR = path.resolve(__dirname, '../../../@react-spectrum/s2/spectrum-illustrations/linear'); +let illustrationIdCache: string[] | null = null; +let iconAliasesCache: Record | null = null; +let illustrationAliasesCache: Record | null = null; + +function ensureIconsExist() { + if (!fs.existsSync(ICONS_DIR)) { + throw new Error(`S2 icons directory not found at ${ICONS_DIR}`); + } +} + +function listIconNames(): string[] { + if (iconIdCache) {return iconIdCache;} + ensureIconsExist(); + const files = fg.sync('*.svg', {cwd: ICONS_DIR, absolute: false, suppressErrors: true}); + const ids = Array.from(new Set( + files.map(f => f.replace(/\.svg$/i, '') + // Mirror IconPicker.tsx regex to derive the id from the filename + .replace(/^S2_Icon_(.*?)(Size\d+)?_2.*/, '$1')) + )).sort((a, b) => a.localeCompare(b)); + iconIdCache = ids; + return ids; +} + +function ensureIllustrationsExist() { + if (!fs.existsSync(ILLUSTRATIONS_DIR)) { + throw new Error(`S2 illustrations directory not found at ${ILLUSTRATIONS_DIR}`); + } +} + +function listIllustrationNames(): string[] { + if (illustrationIdCache) {return illustrationIdCache;} + ensureIllustrationsExist(); + // linear directory may contain multiple sizes per illustration name + const files = fg.sync('**/*.svg', {cwd: ILLUSTRATIONS_DIR, absolute: false, suppressErrors: true}); + const ids = Array.from(new Set( + files.map(f => { + const base = f.replace(/\.svg$/i, '') + // Pattern: S2_lin__ + .replace(/^S2_lin_(.*)_\d+$/, '$1'); + return base ? (base.charAt(0).toUpperCase() + base.slice(1)) : base; + }) + )).sort((a, b) => a.localeCompare(b)); + illustrationIdCache = ids; + return ids; +} + +async function loadIconAliases(): Promise> { + if (iconAliasesCache) {return iconAliasesCache;} + const aliasesPath = path.resolve(__dirname, '../../s2-docs/src/iconAliases.js'); + if (!fs.existsSync(aliasesPath)) {return iconAliasesCache = {};} + const mod = await import(pathToFileURL(aliasesPath).href); + return (iconAliasesCache = (mod.iconAliases ?? {})); +} + +async function loadIllustrationAliases(): Promise> { + if (illustrationAliasesCache) {return illustrationAliasesCache;} + const aliasesPath = path.resolve(__dirname, '../../s2-docs/src/illustrationAliases.js'); + if (!fs.existsSync(aliasesPath)) {return illustrationAliasesCache = {};} + const mod = await import(pathToFileURL(aliasesPath).href); + return (illustrationAliasesCache = (mod.illustrationAliases ?? {})); +} + +function readAllPagesFor(library: Library): PageInfo[] { + assertDocsExist(); + const pattern = `${library}/**/*.md`; + const absFiles = fg.sync([pattern], {cwd: DOCS_DIST_ROOT, absolute: true, suppressErrors: true}); + const pages: PageInfo[] = []; + for (const absPath of absFiles) { + if (path.basename(absPath).toLowerCase() === 'llms.txt') {continue;} + const rel = path.relative(DOCS_DIST_ROOT, absPath); + const key = rel.replace(/\\/g, '/').replace(/\.md$/i, ''); + const info = parsePage(absPath, key); + pages.push(info); + pageCache.set(info.key, info); + } + return pages; +} + +function parsePage(absPath: string, keyFromPath?: string): PageInfo { + const raw = fs.readFileSync(absPath, 'utf8'); + const lines = raw.split(/\r?\n/); + + let title = ''; + let description: string | undefined = undefined; + let i = 0; + // Find first H1 (title) + for (; i < lines.length; i++) { + const line = lines[i]; + if (line.startsWith('# ')) { + title = line.replace(/^#\s+/, '').trim(); + i++; + break; + } + } + + // Collect first paragraph as description (non-empty text until blank line) + let descLines: string[] = []; + let inCode = false; + for (; i < lines.length; i++) { + const line = lines[i]; + if (/^```/.test(line.trim())) {inCode = !inCode;} + if (inCode) {continue;} + if (line.trim() === '') { + if (descLines.length > 0) {break;} else {continue;} + } + // ignore headings and HTML-like tags if they appear before paragraph + if (/^#{1,6}\s/.test(line) || /^ 0) { + description = descLines.join('\n').trim(); + } + + // Parse sections (## ...) + const sections: SectionInfo[] = []; + inCode = false; + for (let idx = 0; idx < lines.length; idx++) { + const line = lines[idx]; + if (/^```/.test(line.trim())) {inCode = !inCode;} + if (inCode) {continue;} + if (line.startsWith('## ')) { + const name = line.replace(/^##\s+/, '').trim(); + sections.push({name, startLine: idx, endLine: lines.length}); + } + } + // Compute endLine for each section as start of next section + for (let s = 0; s < sections.length - 1; s++) { + sections[s].endLine = sections[s + 1].startLine; + } + + const rel = path.relative(DOCS_DIST_ROOT, absPath).replace(/\\/g, '/'); + const key = keyFromPath ?? rel.replace(/\.md$/i, ''); + return {key, title, description, filePath: absPath, sections}; +} + +function resolvePagePathFor(library: Library, pageName: string): PageInfo { + // Accept keys like "s2/Button" or plain "Button" but restrict to the selected library + assertDocsExist(); + + if (pageCache.has(pageName)) { + return pageCache.get(pageName)!; + } + + if (pageName.includes('/')) { + const normalized = pageName.replace(/\\/g, '/'); + const prefix = normalized.split('/', 1)[0]; + if (prefix !== library) { + throw new Error(`Page '${pageName}' is not in the '${library}' library.`); + } + const abs = path.join(DOCS_DIST_ROOT, `${normalized}.md`); + if (!fs.existsSync(abs)) { + throw new Error(`Page not found: ${pageName}`); + } + const info = parsePage(abs, normalized); + pageCache.set(normalized, info); + return info; + } + + const abs = path.join(DOCS_DIST_ROOT, library, `${pageName}.md`); + if (!fs.existsSync(abs)) { + throw new Error(`Page not found in '${library}': ${pageName}`); + } + const key = `${library}/${pageName}`; + const info = parsePage(abs, key); + pageCache.set(info.key, info); + return info; +} + +function readPageContent(filePath: string): string { + return fs.readFileSync(filePath, 'utf8'); +} + +async function startServer(library: Library) { + const server = new McpServer({ + name: library === 's2' ? 's2-docs-server' : 'react-aria-docs-server', + version: '0.1.0' + }); + + // list_pages tool + server.registerTool( + 'list_pages', + { + title: library === 's2' ? 'List React Spectrum (@react-spectrum/s2) docs pages' : 'List React Aria docs pages', + description: `Returns a list of available pages in the ${library} docs.`, + inputSchema: {includeDescription: z.boolean().optional()} + }, + async ({includeDescription}) => { + const pages = readAllPagesFor(library); + const items = pages + .sort((a, b) => a.key.localeCompare(b.key)) + .map(p => includeDescription ? {key: p.key, title: p.title, description: p.description ?? ''} : {key: p.key, title: p.title}); + return { + content: [{type: 'text', text: JSON.stringify(items, null, 2)}] + }; + } + ); + + // get_page_info tool + server.registerTool( + 'get_page_info', + { + title: 'Get page info', + description: 'Returns page description and list of sections for a given page.', + inputSchema: {page_name: z.string()} + }, + async ({page_name}) => { + const info = resolvePagePathFor(library, page_name); + const out = { + key: info.key, + title: info.title, + description: info.description ?? '', + sections: info.sections.map(s => s.name) + }; + return {content: [{type: 'text', text: JSON.stringify(out, null, 2)}]}; + } + ); + + // get_page tool + server.registerTool( + 'get_page', + { + title: 'Get page markdown', + description: 'Returns the full markdown content for a page, or a specific section if provided.', + inputSchema: {page_name: z.string(), section_name: z.string().optional()} + }, + async ({page_name, section_name}) => { + const info = resolvePagePathFor(library, page_name); + let text: string; + if (!section_name) { + text = readPageContent(info.filePath); + } else { + // Find section by exact title match (case-sensitive first, then case-insensitive) + let section = info.sections.find(s => s.name === section_name); + if (!section) { + section = info.sections.find(s => s.name.toLowerCase() === section_name.toLowerCase()); + } + if (!section) { + const available = info.sections.map(s => s.name).join(', '); + throw new Error(`Section '${section_name}' not found in ${info.key}. Available: ${available}`); + } + const lines = fs.readFileSync(info.filePath, 'utf8').split(/\r?\n/); + text = lines.slice(section.startLine, section.endLine).join('\n'); + } + return {content: [{type: 'text', text}]} as const; + } + ); + + if (library === 's2') { + // search_icons tool + server.registerTool( + 'search_icons', + { + title: 'Search S2 icons', + description: 'Searches the S2 workflow icon set by one or more terms; returns matching icon names.', + inputSchema: {terms: z.union([z.string(), z.array(z.string())])} + }, + async ({terms}) => { + const allNames = listIconNames(); + const nameSet = new Set(allNames); + const aliases = await loadIconAliases(); + const rawTerms = Array.isArray(terms) ? terms : [terms]; + const normalized = Array.from(new Set(rawTerms.map(t => String(t ?? '').trim().toLowerCase()).filter(Boolean))); + if (normalized.length === 0) { + throw new Error('Provide at least one non-empty search term.'); + } + // direct name matches + const results = new Set(allNames.filter(name => { + const nameLower = name.toLowerCase(); + return normalized.some(term => nameLower.includes(term)); + })); + // alias matches + for (const [aliasKey, targets] of Object.entries(aliases)) { + if (!targets || targets.length === 0) {continue;} + const aliasLower = aliasKey.toLowerCase(); + if (normalized.some(term => aliasLower.includes(term) || term.includes(aliasLower))) { + for (const t of targets) { + const n = String(t); + if (nameSet.has(n)) {results.add(n);} + } + } + } + return {content: [{type: 'text', text: JSON.stringify(Array.from(results).sort((a, b) => a.localeCompare(b)), null, 2)}]}; + } + ); + + // search_illustrations tool + server.registerTool( + 'search_illustrations', + { + title: 'Search S2 illustrations', + description: 'Searches the S2 illustrations set by one or more terms; returns matching illustration names.', + inputSchema: {terms: z.union([z.string(), z.array(z.string())])} + }, + async ({terms}) => { + const allNames = listIllustrationNames(); + const nameSet = new Set(allNames); + const aliases = await loadIllustrationAliases(); + const rawTerms = Array.isArray(terms) ? terms : [terms]; + const normalized = Array.from(new Set(rawTerms.map(t => String(t ?? '').trim().toLowerCase()).filter(Boolean))); + if (normalized.length === 0) { + throw new Error('Provide at least one non-empty search term.'); + } + // direct name matches + const results = new Set(allNames.filter(name => { + const nameLower = name.toLowerCase(); + return normalized.some(term => nameLower.includes(term)); + })); + // alias matches + for (const [aliasKey, targets] of Object.entries(aliases)) { + if (!targets || targets.length === 0) {continue;} + const aliasLower = aliasKey.toLowerCase(); + if (normalized.some(term => aliasLower.includes(term) || term.includes(aliasLower))) { + for (const t of targets) { + const n = String(t); + if (nameSet.has(n)) {results.add(n);} + } + } + } + return {content: [{type: 'text', text: JSON.stringify(Array.from(results).sort((a, b) => a.localeCompare(b)), null, 2)}]}; + } + ); + } + + const transport = new StdioServerTransport(); + await server.connect(transport); +} + +function printUsage() { + const usage = 'Usage: mcp \n\nSubcommands:\n s2 Start MCP server for React Spectrum S2 docs\n react-aria Start MCP server for React Aria docs\n\nExamples:\n npx @react-spectrum/mcp s2\n npx @react-spectrum/mcp react-aria'; + console.log(usage); +} + +// CLI entry +(async () => { + try { + const arg = (process.argv[2] || '').trim(); + if (arg === '--help' || arg === '-h' || arg === 'help') { + printUsage(); + process.exit(0); + } + const library: Library = arg === 'react-aria' ? 'react-aria' : 's2'; + await startServer(library); + } catch (err) { + console.error(errorToString(err)); + process.exit(1); + } +})(); diff --git a/packages/dev/mcp/tsconfig.json b/packages/dev/mcp/tsconfig.json new file mode 100644 index 00000000000..fb0111899fa --- /dev/null +++ b/packages/dev/mcp/tsconfig.json @@ -0,0 +1,17 @@ +{ + "extends": "../../..//tsconfig.json", + "compilerOptions": { + "outDir": "dist", + "rootDir": "src", + "noEmit": false, + "module": "esnext", + "moduleResolution": "bundler", + "target": "es2018", + "types": [], + "declaration": false, + "sourceMap": true + }, + "include": ["src/**/*"] +} + + diff --git a/packages/dev/parcel-packager-docs/DocsPackager.js b/packages/dev/parcel-packager-docs/DocsPackager.js index 9fe846793de..8f243bd0ef7 100644 --- a/packages/dev/parcel-packager-docs/DocsPackager.js +++ b/packages/dev/parcel-packager-docs/DocsPackager.js @@ -13,17 +13,21 @@ const {Packager} = require('@parcel/plugin'); const v8 = require('v8'); +let cache = new Map(); +let nodes = {}; + module.exports = new Packager({ + async loadBundleConfig() { + cache = new Map(); + nodes = {}; + }, async package({bundle, bundleGraph, options}) { let promises = []; bundle.traverseAssets(asset => { promises.push(parse(asset)); }); - let nodes = {}; - let code = new Map(await Promise.all(promises)); - let cache = new Map(); try { var result = processAsset(bundle.getEntryAssets()[0]); } catch (err) { diff --git a/packages/dev/s2-docs/.parcelrc-s2-docs b/packages/dev/s2-docs/.parcelrc-s2-docs index f9f23683849..14b1fa12c78 100644 --- a/packages/dev/s2-docs/.parcelrc-s2-docs +++ b/packages/dev/s2-docs/.parcelrc-s2-docs @@ -1,14 +1,16 @@ { "extends": "@parcel/config-default", - "resolvers": ["@parcel/resolver-glob", "parcel-resolver-docs", "..."], + "resolvers": ["@react-aria/parcel-resolver-optimize-locales", "@parcel/resolver-glob", "parcel-resolver-docs", "..."], "transformers": { "docs:*.{js,ts,tsx,json}": ["parcel-transformer-docs", "@parcel/transformer-inline"], "docs-json:*.{js,ts,tsx,json}": ["parcel-transformer-docs"], "illustration:*.svg": ["@react-spectrum/parcel-transformer-s2-icon"], + "url:*.svg": ["@parcel/transformer-raw"], "packages/@react-spectrum/s2/s2wf-icons/**/*.svg": ["@react-spectrum/parcel-transformer-s2-icon"], "packages/*/*/intl/*.json": ["parcel-transformer-intl"], "starters/tailwind/**/*.css": ["@parcel/transformer-postcss", "..."], "packages/dev/s2-docs/tailwind/*.css": ["@parcel/transformer-postcss", "..."], + "*.mdx": ["./MDXTransformer.mjs", "..."], // Disable PostCSS from running over style macro output "*.css": ["@parcel/transformer-css"], "*.svg": ["@parcel/transformer-svg-react"], diff --git a/packages/dev/s2-docs/MDXTransformer.mjs b/packages/dev/s2-docs/MDXTransformer.mjs new file mode 100644 index 00000000000..e7cdc08c83a --- /dev/null +++ b/packages/dev/s2-docs/MDXTransformer.mjs @@ -0,0 +1,26 @@ +import json5 from 'json5'; +import {Transformer} from '@parcel/plugin'; + +export default new Transformer({ + async transform({asset}) { + let code = await asset.getCode(); + + let replaced = false; + code = code.replace(/()((?:.|\n)*?)<\/ExampleSwitcher>/g, (m, start, examples, inner) => { + if (inner.includes('COMPONENT')) { + replaced = true; + let components = json5.parse(examples); + inner = components.map(component => inner.replace(/COMPONENT/g, component)).join('\n\n'); + return start + inner + ''; + } + + return m; + }); + + if (replaced) { + asset.setCode(code); + } + + return [asset]; + } +}); diff --git a/packages/dev/s2-docs/package.json b/packages/dev/s2-docs/package.json index 3cf8e59d53f..96cc4502816 100644 --- a/packages/dev/s2-docs/package.json +++ b/packages/dev/s2-docs/package.json @@ -5,8 +5,8 @@ "scripts": { "start": "DOCS_ENV=dev parcel --config .parcelrc-s2-docs", "build": "DOCS_ENV=staging parcel build --config .parcelrc-s2-docs", - "generate:og": "node scripts/generateOg.mjs", - "generate:md": "node scripts/generateMd.mjs" + "generate:og": "node scripts/generateOGImages.mjs", + "generate:md": "node scripts/generateMarkdownDocs.mjs" }, "targets": { "react-static": { @@ -20,11 +20,14 @@ ] }, "includeNodeModules": { - "tree-sitter-highlight": false + "tree-sitter-highlight": false, + "json5": false, + "globals-docs": false } } }, "dependencies": { + "@parcel/plugin": "^2.15.4", "@parcel/rsc": "^2.15.4", "@react-aria/focus": "^3.20.4", "@react-aria/i18n": "^3.12.10", @@ -37,6 +40,7 @@ "fast-glob": "^3.3.3", "globals-docs": "^2.4.1", "gray-matter": "^4.0.3", + "json5": "^2.2.3", "lz-string": "^1.5.0", "markdown-to-jsx": "^6.11.0", "react": "^19", @@ -47,7 +51,7 @@ "remark-mdx": "^3.1.0", "remark-parse": "^11.0.0", "remark-stringify": "^11.0.0", - "satori": "^0.15.2", + "satori": "^0.16.1", "sharp": "^0.33.5", "tree-sitter-highlight": "^1.0.1", "ts-morph": "^26.0.0", diff --git a/packages/dev/s2-docs/pages/react-aria/Autocomplete.mdx b/packages/dev/s2-docs/pages/react-aria/Autocomplete.mdx new file mode 100644 index 00000000000..e76026b6351 --- /dev/null +++ b/packages/dev/s2-docs/pages/react-aria/Autocomplete.mdx @@ -0,0 +1,113 @@ +import {Layout} from '../../src/Layout'; +export default Layout; + +import docs from 'docs:react-aria-components'; +import vanillaDocs from 'docs:vanilla-starter/Autocomplete'; +import '../../tailwind/tailwind.css'; + +# Autocomplete + +{docs.exports.Autocomplete.description} + + + ```tsx render docs={vanillaDocs.exports.Autocomplete} links={vanillaDocs.links} props={['label', 'disableAutoFocusFirst']} initialProps={{label: 'Commands'}} type="vanilla" files={["starters/docs/src/Autocomplete.tsx", "starters/docs/src/Autocomplete.css"]} + "use client"; + import {Autocomplete} from 'vanilla-starter/Autocomplete'; + import {MenuItem} from 'vanilla-starter/Menu'; + + + Create new file... + Create new folder... + Assign to... + Assign to me + Change status... + Change priority... + Add label... + Remove label... + + ``` + + ```tsx render docs={vanillaDocs.exports.Autocomplete} links={vanillaDocs.links} props={['label', 'disableAutoFocusFirst']} initialProps={{label: 'Commands'}} type="tailwind" files={["starters/tailwind/src/Autocomplete.tsx"]} + "use client"; + import {Autocomplete, AutocompleteItem} from 'tailwind-starter/Autocomplete'; + + + Create new file... + Create new folder... + Assign to... + Assign to me + Change status... + Change priority... + Add label... + Remove label... + + ``` + + + +## Content + +Autocomplete filters a [Menu](Menu.html) or [ListBox](ListBox.html) using a [TextField](TextField.html) or [SearchField](SearchField.html). It can be used to build UI patterns such as command palettes, searchable menus, and filterable selects, and supports features such as static and dynamic collections, sections, disabled items, links, etc. + +### Asynchronous loading + +When the `filter` prop is not set, the items are controlled. This example uses a backend API to perform searching instead of filtering a static list on the client. + +```tsx render +"use client"; +import {Autocomplete} from 'vanilla-starter/Autocomplete'; +import {MenuItem} from 'vanilla-starter/Menu'; +import {useAsyncList} from 'react-stately'; + +function AsyncLoadingExample() { + let list = useAsyncList<{name: string}>({ + async load({signal, filterText}) { + let res = await fetch( + `https://swapi.py4e.com/api/people/?search=${filterText}`, + {signal} + ); + + let json = await res.json(); + return { + items: json.results + }; + } + }); + + return ( + 'No results found.'}> + {(item) => ( + + {item.name} + + )} + + ); +} +``` + +## API + +```tsx links={{Autocomplete: '#autocomplete', SearchField: 'SearchField.html', TextField: 'TextField.html', Menu: 'Menu.html', ListBox: 'ListBox.html'}} + + or + or + +``` + +### Autocomplete + + diff --git a/packages/dev/s2-docs/pages/react-aria/Breadcrumbs.mdx b/packages/dev/s2-docs/pages/react-aria/Breadcrumbs.mdx new file mode 100644 index 00000000000..40c907ba6f5 --- /dev/null +++ b/packages/dev/s2-docs/pages/react-aria/Breadcrumbs.mdx @@ -0,0 +1,95 @@ +import {Layout} from '../../src/Layout'; +export default Layout; + +import docs from 'docs:react-aria-components'; +import '../../tailwind/tailwind.css'; +import Anatomy from '@react-aria/breadcrumbs/docs/anatomy.svg'; +import {InlineAlert, Heading, Content} from '@react-spectrum/s2'; + +# Breadcrumbs + +{docs.exports.Breadcrumbs.description} + + + ```tsx render docs={docs.exports.Breadcrumbs} links={docs.links} props={['isDisabled']} type="vanilla" files={["starters/docs/src/Breadcrumbs.tsx", "starters/docs/src/Breadcrumbs.css"]} + "use client"; + import {Breadcrumbs, Breadcrumb} from 'vanilla-starter/Breadcrumbs'; + + + Home + React Aria + Breadcrumbs + + ``` + + ```tsx render docs={docs.exports.Breadcrumbs} links={docs.links} props={['isDisabled']} type="tailwind" files={["starters/tailwind/src/Breadcrumbs.tsx"]} + "use client"; + import {Breadcrumbs, Breadcrumb} from 'tailwind-starter/Breadcrumbs'; + + + Home + React Aria + Breadcrumbs + + ``` + + + +## Content + +`Breadcrumbs` follows the [Collection Components API](collections.html?component=Breadcrumbs), accepting both static and dynamic collections. This example shows a dynamic collection, passing a list of objects to the `items` prop, and a function to render the children. The `onAction` event is called when a user presses a breadcrumb. + +```tsx render +"use client"; +import type {Key} from 'react-aria-components'; +import {Breadcrumbs, Breadcrumb} from 'vanilla-starter/Breadcrumbs'; +import {useState} from 'react'; + +function Example() { + let [breadcrumbs, setBreadcrumbs] = useState([ + {id: 1, label: 'Home'}, + {id: 2, label: 'Trendy'}, + {id: 3, label: 'March 2022 Assets'} + ]); + + let navigate = (id: Key) => { + let i = breadcrumbs.findIndex(item => item.id === id); + setBreadcrumbs(breadcrumbs.slice(0, i + 1)); + }; + + return ( + /*- begin highlight -*/ + + {item => {item.label}} + + /*- end highlight -*/ + ); +} +``` + + + Accessibility + When breadcrumbs are used as a main navigation element for a page, they can be placed in a [navigation landmark](https://www.w3.org/WAI/ARIA/apg/patterns/landmarks/examples/navigation.html). Landmarks help assistive technology users quickly find major sections of a page. Place breadcrumbs inside a `