diff --git a/Makefile b/Makefile
index e72170a0147..ffd71f5e5a1 100644
--- a/Makefile
+++ b/Makefile
@@ -156,6 +156,7 @@ build-s2-docs:
yarn workspace @react-spectrum/s2-docs generate:og
REGISTRY_URL=$(PUBLIC_URL)/registry node scripts/buildRegistry.mjs
REGISTRY_URL=$(PUBLIC_URL)/registry yarn build:s2-docs --public-url $(PUBLIC_URL)
+ node scripts/createFeedS2.mjs
mkdir -p $(DIST_DIR)
mv packages/dev/s2-docs/dist/* $(DIST_DIR)
mkdir -p $(DIST_DIR)/registry
diff --git a/package.json b/package.json
index f77ecdaec3e..d3420e1df55 100644
--- a/package.json
+++ b/package.json
@@ -185,6 +185,7 @@
"recast": "^0.23",
"recursive-readdir": "^2.2.2",
"regenerator-runtime": "0.13.3",
+ "rehype-stringify": "^9.0.4",
"rimraf": "^6.0.1",
"sharp": "^0.33.5",
"storybook": "^8.6.14",
diff --git a/packages/@react-aria/dnd/intl/es-ES.json b/packages/@react-aria/dnd/intl/es-ES.json
index 797bb4886e9..489c6f15c47 100644
--- a/packages/@react-aria/dnd/intl/es-ES.json
+++ b/packages/@react-aria/dnd/intl/es-ES.json
@@ -9,9 +9,9 @@
"dragSelectedKeyboard": "Pulse Intro para arrastrar {count, plural, one {# elemento seleccionado} other {# elementos seleccionados}}.",
"dragSelectedKeyboardAlt": "Pulse Alt + Intro para arrastrar {count, plural, one {# elemento seleccionado} other {# elementos seleccionados}}.",
"dragSelectedLongPress": "Mantenga pulsado para arrastrar {count, plural, one {# elemento seleccionado} other {# elementos seleccionados}}.",
- "dragStartedKeyboard": "Se ha empezado a arrastrar. Pulse el tabulador para ir al público destinatario donde se vaya a colocar y, a continuación, pulse Intro para soltar, o pulse Escape para cancelar.",
- "dragStartedTouch": "Se ha empezado a arrastrar. Vaya al público destinatario donde se vaya a colocar y, a continuación, pulse dos veces para soltar.",
- "dragStartedVirtual": "Se ha empezado a arrastrar. Vaya al público destinatario donde se vaya a colocar y, a continuación, haga clic o pulse Intro para soltar.",
+ "dragStartedKeyboard": "Se ha empezado a arrastrar. Pulse el tabulador para ir al destino donde se vaya a colocar y, a continuación, pulse Intro para soltar, o pulse Escape para cancelar.",
+ "dragStartedTouch": "Se ha empezado a arrastrar. Vaya al destino donde se vaya a colocar y, a continuación, pulse dos veces para soltar.",
+ "dragStartedVirtual": "Se ha empezado a arrastrar. Vaya al destino donde se vaya a colocar y, a continuación, haga clic o pulse Intro para soltar.",
"dropCanceled": "Se ha cancelado la colocación.",
"dropComplete": "Colocación finalizada.",
"dropDescriptionKeyboard": "Pulse Intro para soltar. Pulse Escape para cancelar el arrastre.",
diff --git a/packages/@react-aria/menu/intl/it-IT.json b/packages/@react-aria/menu/intl/it-IT.json
index 3e0f7886700..f689d27d88f 100644
--- a/packages/@react-aria/menu/intl/it-IT.json
+++ b/packages/@react-aria/menu/intl/it-IT.json
@@ -1,3 +1,3 @@
{
- "longPressMessage": "Premere a lungo o premere Alt + Freccia giù per aprire il menu"
+ "longPressMessage": "Premi a lungo o premi Alt + Freccia giù per aprire il menu"
}
diff --git a/packages/@react-spectrum/s2/chromatic/Accordion.stories.tsx b/packages/@react-spectrum/s2/chromatic/Accordion.stories.tsx
index 3ac77693a82..34feeb88b57 100644
--- a/packages/@react-spectrum/s2/chromatic/Accordion.stories.tsx
+++ b/packages/@react-spectrum/s2/chromatic/Accordion.stories.tsx
@@ -10,7 +10,7 @@
* governing permissions and limitations under the License.
*/
-import {Accordion, ActionButton, Disclosure, DisclosureHeader, DisclosurePanel, DisclosureTitle, TextField} from '../src';
+import {Accordion, AccordionItem, AccordionItemHeader, AccordionItemPanel, AccordionItemTitle, ActionButton, TextField} from '../src';
import type {Meta, StoryObj} from '@storybook/react';
import NewIcon from '../s2wf-icons/S2_Icon_New_20_N.svg';
import React from 'react';
@@ -32,22 +32,22 @@ export const Example: Story = {
return (
-
-
+
+
Files
-
-
+
+
Files content
-
-
-
-
+
+
+
+
People
-
-
+
+
-
-
+
+
);
@@ -59,57 +59,57 @@ export const WithLongTitle: Story = {
return (
-
-
+
+
Files
-
-
+
+
Files content
-
-
-
-
+
+
+
+
People
-
-
+
+
People content
-
-
-
-
+
+
+
+
Very very very very very long title that wraps
-
-
+
+
Accordion content
-
-
+
+
);
}
};
-export const WithDisabledDisclosure: Story = {
+export const WithDisabledItem: Story = {
render: (args) => {
return (
-
-
+
+
Files
-
-
+
+
Files content
-
-
-
-
+
+
+
+
People
-
-
+
+
-
-
+
+
);
@@ -122,7 +122,7 @@ WithLongTitle.parameters = {
}
};
-WithDisabledDisclosure.parameters = {
+WithDisabledItem.parameters = {
docs: {
disable: true
}
@@ -133,28 +133,28 @@ export const WithActionButton: Story = {
return (
-
-
-
+
+
+
Files
-
+
-
-
+
+
Files content
-
-
-
-
-
+
+
+
+
+
People
-
+
-
-
+
+
-
-
+
+
);
diff --git a/packages/@react-spectrum/s2/intl/ar-AE.json b/packages/@react-spectrum/s2/intl/ar-AE.json
index 977a05e0096..8545d91acfd 100644
--- a/packages/@react-spectrum/s2/intl/ar-AE.json
+++ b/packages/@react-spectrum/s2/intl/ar-AE.json
@@ -26,7 +26,7 @@
"notificationbadge.indicatorOnly": "نشاط جديد",
"notificationbadge.plus": "{notifications}+",
"picker.placeholder": "تحديد…",
- "picker.selectedCount": "{count, plural, =0 {لم يتم تحديد عناصر} one {# عنصر محدد} other {# عنصر محدد}}",
+ "picker.selectedCount": "{count, plural, =0 {لم يتم تحديد أي عنصر} one {تم تحديد عنصر واحد} two {تم تحديد عنصرين} few {تم تحديد # عناصر} other {تم تحديد # عنصر}}",
"slider.maximum": "أقصى",
"slider.minimum": "أدنى",
"table.cancel": "إلغاء",
diff --git a/packages/@react-spectrum/s2/intl/bg-BG.json b/packages/@react-spectrum/s2/intl/bg-BG.json
index 57a159b530a..02ecdbc3019 100644
--- a/packages/@react-spectrum/s2/intl/bg-BG.json
+++ b/packages/@react-spectrum/s2/intl/bg-BG.json
@@ -26,12 +26,15 @@
"notificationbadge.indicatorOnly": "Нова дейност",
"notificationbadge.plus": "{notifications}+",
"picker.placeholder": "Изберете…",
- "picker.selectedCount": "{count, plural, =0 {Няма избрани елементи} one {# избран елемент} other {# избрани елементи}}",
+ "picker.selectedCount": "{count, plural, =0 {Няма избрани елементи} one {# избран елемент} other {# избрани елемента}}",
"slider.maximum": "Максимум",
"slider.minimum": "Минимум",
+ "table.cancel": "Отказ",
+ "table.editCell": "Редактиране на клетка",
"table.loading": "Зареждане...",
"table.loadingMore": "Зареждане на още...",
"table.resizeColumn": "Преоразмеряване на колона",
+ "table.save": "Запазване",
"table.sortAscending": "Възходящо сортиране",
"table.sortDescending": "Низходящо сортиране ",
"tag.actions": "Действия",
diff --git a/packages/@react-spectrum/s2/intl/cs-CZ.json b/packages/@react-spectrum/s2/intl/cs-CZ.json
index cafc3d9afbb..daa436a2556 100644
--- a/packages/@react-spectrum/s2/intl/cs-CZ.json
+++ b/packages/@react-spectrum/s2/intl/cs-CZ.json
@@ -26,12 +26,15 @@
"notificationbadge.indicatorOnly": "Nová aktivita",
"notificationbadge.plus": "{notifications}+",
"picker.placeholder": "Vybrat…",
- "picker.selectedCount": "{count, plural, =0 {Nevybrány žádné položky} one {Vybrána # položka} other {Vybráno # položek}}",
+ "picker.selectedCount": "{count, plural, =0 {Nevybrány žádné položky} one {Vybrána # položka} few {Vybrány # položky} other {Vybráno # položek}}",
"slider.maximum": "Maximum",
"slider.minimum": "Minimum",
+ "table.cancel": "Zrušit",
+ "table.editCell": "Upravit buňku",
"table.loading": "Načítání...",
"table.loadingMore": "Načítání dalších...",
"table.resizeColumn": "Změnit velikost sloupce",
+ "table.save": "Uložit",
"table.sortAscending": "Seřadit vzestupně",
"table.sortDescending": "Seřadit sestupně",
"tag.actions": "Akce",
diff --git a/packages/@react-spectrum/s2/intl/da-DK.json b/packages/@react-spectrum/s2/intl/da-DK.json
index 796047f0199..e6f272123a3 100644
--- a/packages/@react-spectrum/s2/intl/da-DK.json
+++ b/packages/@react-spectrum/s2/intl/da-DK.json
@@ -29,9 +29,12 @@
"picker.selectedCount": "{count, plural, =0 {Ingen elementer valgt} one {# element valgt} other {# elementer valgt}}",
"slider.maximum": "Maksimum",
"slider.minimum": "Minimum",
+ "table.cancel": "Annuller",
+ "table.editCell": "Rediger celle",
"table.loading": "Indlæser...",
"table.loadingMore": "Indlæser flere...",
"table.resizeColumn": "Tilpas størrelse på kolonne",
+ "table.save": "Gem",
"table.sortAscending": "Sorter stigende",
"table.sortDescending": "Sorter faldende",
"tag.actions": "Handlinger",
diff --git a/packages/@react-spectrum/s2/intl/de-DE.json b/packages/@react-spectrum/s2/intl/de-DE.json
index df797d68c2e..7256c4790e7 100644
--- a/packages/@react-spectrum/s2/intl/de-DE.json
+++ b/packages/@react-spectrum/s2/intl/de-DE.json
@@ -29,9 +29,12 @@
"picker.selectedCount": "{count, plural, =0 {Keine Elemente ausgewählt} one {# Element ausgewählt} other {# Elemente ausgewählt}}",
"slider.maximum": "Maximum",
"slider.minimum": "Minimum",
+ "table.cancel": "Abbrechen",
+ "table.editCell": "Zelle bearbeiten",
"table.loading": "Laden...",
"table.loadingMore": "Mehr laden ...",
"table.resizeColumn": "Spaltengröße ändern",
+ "table.save": "Speichern",
"table.sortAscending": "Aufsteigend sortieren",
"table.sortDescending": "Absteigend sortieren",
"tag.actions": "Aktionen",
diff --git a/packages/@react-spectrum/s2/intl/el-GR.json b/packages/@react-spectrum/s2/intl/el-GR.json
index a1381bae42d..90a98fb862e 100644
--- a/packages/@react-spectrum/s2/intl/el-GR.json
+++ b/packages/@react-spectrum/s2/intl/el-GR.json
@@ -29,9 +29,12 @@
"picker.selectedCount": "{count, plural, =0 {Δεν επιλέχθηκαν στοιχεία} one {Επιλέχθηκε # στοιχείο} other {Επιλέχθηκαν # στοιχεία}}",
"slider.maximum": "Μέγιστο",
"slider.minimum": "Ελάχιστο",
+ "table.cancel": "Ακύρωση",
+ "table.editCell": "Επεξεργασία κελιού",
"table.loading": "Φόρτωση...",
"table.loadingMore": "Φόρτωση περισσότερων...",
"table.resizeColumn": "Αλλαγή μεγέθους στήλης",
+ "table.save": "Αποθήκευση",
"table.sortAscending": "Ταξινόμηση κατά αύξουσα σειρά",
"table.sortDescending": "Ταξινόμηση κατά φθίνουσα σειρά",
"tag.actions": "Ενέργειες",
diff --git a/packages/@react-spectrum/s2/intl/es-ES.json b/packages/@react-spectrum/s2/intl/es-ES.json
index 2dfcc26a3f7..feffd69320b 100644
--- a/packages/@react-spectrum/s2/intl/es-ES.json
+++ b/packages/@react-spectrum/s2/intl/es-ES.json
@@ -29,9 +29,12 @@
"picker.selectedCount": "{count, plural, =0 {Ningún elemento seleccionado} one {# elemento seleccionado} other {# elementos seleccionados}}",
"slider.maximum": "Máximo",
"slider.minimum": "Mínimo",
+ "table.cancel": "Cancelar",
+ "table.editCell": "Editar celda",
"table.loading": "Cargando…",
"table.loadingMore": "Cargando más…",
"table.resizeColumn": "Cambiar el tamaño de la columna",
+ "table.save": "Guardar",
"table.sortAscending": "Orden ascendente",
"table.sortDescending": "Orden descendente",
"tag.actions": "Acciones",
diff --git a/packages/@react-spectrum/s2/intl/et-EE.json b/packages/@react-spectrum/s2/intl/et-EE.json
index 0961526bc2c..3ee0a81aa6e 100644
--- a/packages/@react-spectrum/s2/intl/et-EE.json
+++ b/packages/@react-spectrum/s2/intl/et-EE.json
@@ -26,12 +26,15 @@
"notificationbadge.indicatorOnly": "Uus tegevus",
"notificationbadge.plus": "{notifications}+",
"picker.placeholder": "Valige…",
- "picker.selectedCount": "{count, plural, =0 {Üksusi pole valitud} one {# üksus valitud} other {# üksust valitud}}",
+ "picker.selectedCount": "{count, plural, =0 {üksuseid pole valitud} one {# üksus valitud} other {# üksust valitud}}",
"slider.maximum": "Maksimaalne",
"slider.minimum": "Minimaalne",
+ "table.cancel": "Tühista",
+ "table.editCell": "Muuda lahtrit",
"table.loading": "Laadimine...",
"table.loadingMore": "Laadi rohkem...",
"table.resizeColumn": "Muuda veeru suurust",
+ "table.save": "Salvesta",
"table.sortAscending": "Sordi kasvavalt",
"table.sortDescending": "Sordi kahanevalt",
"tag.actions": "Toimingud",
diff --git a/packages/@react-spectrum/s2/intl/fi-FI.json b/packages/@react-spectrum/s2/intl/fi-FI.json
index 3c841a3fe38..e541ada653f 100644
--- a/packages/@react-spectrum/s2/intl/fi-FI.json
+++ b/packages/@react-spectrum/s2/intl/fi-FI.json
@@ -26,12 +26,15 @@
"notificationbadge.indicatorOnly": "Uusi toiminta",
"notificationbadge.plus": "{notifications}+",
"picker.placeholder": "Valitse…",
- "picker.selectedCount": "{count, plural, =0 {Ei yhtään kohdetta valittu} one {# kohde valittu} other {# kohdetta valittu}}",
+ "picker.selectedCount": "{count, plural, =0 {Kohteita ei ole valittu} one {# kohde valittu} other {# kohdetta valittu}}",
"slider.maximum": "Maksimi",
"slider.minimum": "Minimi",
+ "table.cancel": "Peruuta",
+ "table.editCell": "Muokkaa solua",
"table.loading": "Ladataan…",
"table.loadingMore": "Ladataan lisää…",
"table.resizeColumn": "Muuta sarakkeen kokoa",
+ "table.save": "Tallenna",
"table.sortAscending": "Lajittelujärjestys: nouseva",
"table.sortDescending": "Lajittelujärjestys: laskeva",
"tag.actions": "Toiminnot",
diff --git a/packages/@react-spectrum/s2/intl/fr-FR.json b/packages/@react-spectrum/s2/intl/fr-FR.json
index e67742c73a6..e298543e539 100644
--- a/packages/@react-spectrum/s2/intl/fr-FR.json
+++ b/packages/@react-spectrum/s2/intl/fr-FR.json
@@ -29,9 +29,12 @@
"picker.selectedCount": "{count, plural, =0 {Aucun élément sélectionné} one {# élément sélectionné} other {# éléments sélectionnés}}",
"slider.maximum": "Maximum",
"slider.minimum": "Minimum",
+ "table.cancel": "Annuler",
+ "table.editCell": "Modifier la cellule",
"table.loading": "Chargement...",
"table.loadingMore": "Chargement supplémentaire...",
"table.resizeColumn": "Redimensionner la colonne",
+ "table.save": "Enregistrer",
"table.sortAscending": "Trier par ordre croissant",
"table.sortDescending": "Trier par ordre décroissant",
"tag.actions": "Actions",
diff --git a/packages/@react-spectrum/s2/intl/he-IL.json b/packages/@react-spectrum/s2/intl/he-IL.json
index caae5e3ac7d..cac33237926 100644
--- a/packages/@react-spectrum/s2/intl/he-IL.json
+++ b/packages/@react-spectrum/s2/intl/he-IL.json
@@ -29,9 +29,12 @@
"picker.selectedCount": "{count, plural, =0 {לא נבחרו פריטים} one {פריט # נבחר} other {# פריטים נבחרו}}",
"slider.maximum": "מקסימום",
"slider.minimum": "מינימום",
+ "table.cancel": "ביטול",
+ "table.editCell": "עריכת תא",
"table.loading": "טוען...",
"table.loadingMore": "טוען עוד...",
"table.resizeColumn": "שנה את גודל העמודה",
+ "table.save": "שמירה",
"table.sortAscending": "מיין בסדר עולה",
"table.sortDescending": "מיין בסדר יורד",
"tag.actions": "פעולות",
diff --git a/packages/@react-spectrum/s2/intl/hr-HR.json b/packages/@react-spectrum/s2/intl/hr-HR.json
index 3b98a57760d..d785dc1390b 100644
--- a/packages/@react-spectrum/s2/intl/hr-HR.json
+++ b/packages/@react-spectrum/s2/intl/hr-HR.json
@@ -29,9 +29,12 @@
"picker.selectedCount": "{count, plural, =0 {Nije odabrana nijedna stavka} one {Odabrana je # stavka} other {Odabrano je # stavki}}",
"slider.maximum": "Najviše",
"slider.minimum": "Najmanje",
+ "table.cancel": "Poništi",
+ "table.editCell": "Uredi ćeliju",
"table.loading": "Učitavam...",
"table.loadingMore": "Učitavam još...",
"table.resizeColumn": "Promijeni veličinu stupca",
+ "table.save": "Spremi",
"table.sortAscending": "Sortiraj uzlazno",
"table.sortDescending": "Sortiraj silazno",
"tag.actions": "Radnje",
diff --git a/packages/@react-spectrum/s2/intl/hu-HU.json b/packages/@react-spectrum/s2/intl/hu-HU.json
index 3c2e6052c59..6d826f1259e 100644
--- a/packages/@react-spectrum/s2/intl/hu-HU.json
+++ b/packages/@react-spectrum/s2/intl/hu-HU.json
@@ -26,12 +26,15 @@
"notificationbadge.indicatorOnly": "Új tevékenység",
"notificationbadge.plus": "{notifications}+",
"picker.placeholder": "Kiválasztás…",
- "picker.selectedCount": "{count, plural, =0 {Egy elem sincs kijelölve} one {# elem kijelölve} other {# elem kijelölve}}",
+ "picker.selectedCount": "{count, plural, =0 {Nincs kijelölve elem} one {# elem kijelölve} other {# elem kijelölve}}",
"slider.maximum": "Maximum",
"slider.minimum": "Minimum",
+ "table.cancel": "Mégse",
+ "table.editCell": "Cella szerkesztése",
"table.loading": "Betöltés folyamatban…",
"table.loadingMore": "Továbbiak betöltése folyamatban…",
"table.resizeColumn": "Oszlop átméretezése",
+ "table.save": "Mentés",
"table.sortAscending": "Növekvő rendezés",
"table.sortDescending": "Csökkenő rendezés",
"tag.actions": "Műveletek",
diff --git a/packages/@react-spectrum/s2/intl/it-IT.json b/packages/@react-spectrum/s2/intl/it-IT.json
index c2995e56129..87cb218475e 100644
--- a/packages/@react-spectrum/s2/intl/it-IT.json
+++ b/packages/@react-spectrum/s2/intl/it-IT.json
@@ -29,9 +29,12 @@
"picker.selectedCount": "{count, plural, =0 {Nessun elemento selezionato} one {# elemento selezionato} other {# elementi selezionati}}",
"slider.maximum": "Massimo",
"slider.minimum": "Minimo",
+ "table.cancel": "Annulla",
+ "table.editCell": "Modifica cella",
"table.loading": "Caricamento...",
"table.loadingMore": "Caricamento altri...",
"table.resizeColumn": "Ridimensiona colonna",
+ "table.save": "Salva",
"table.sortAscending": "Ordinamento crescente",
"table.sortDescending": "Ordinamento decrescente",
"tag.actions": "Azioni",
diff --git a/packages/@react-spectrum/s2/intl/ja-JP.json b/packages/@react-spectrum/s2/intl/ja-JP.json
index e62d9e3cdc1..4f7c3e0e6e2 100644
--- a/packages/@react-spectrum/s2/intl/ja-JP.json
+++ b/packages/@react-spectrum/s2/intl/ja-JP.json
@@ -29,9 +29,12 @@
"picker.selectedCount": "{count, plural, =0 {項目が選択されていません} one {# 項目を選択しました} other {# 項目を選択しました}}",
"slider.maximum": "最大",
"slider.minimum": "最小",
+ "table.cancel": "キャンセル",
+ "table.editCell": "セルを編集",
"table.loading": "読み込み中...",
"table.loadingMore": "さらに読み込み中...",
"table.resizeColumn": "列幅を変更",
+ "table.save": "保存",
"table.sortAscending": "昇順に並べ替え",
"table.sortDescending": "降順に並べ替え",
"tag.actions": "アクション",
diff --git a/packages/@react-spectrum/s2/intl/ko-KR.json b/packages/@react-spectrum/s2/intl/ko-KR.json
index 0b73bddd9ed..2d5e859ba29 100644
--- a/packages/@react-spectrum/s2/intl/ko-KR.json
+++ b/packages/@react-spectrum/s2/intl/ko-KR.json
@@ -26,12 +26,15 @@
"notificationbadge.indicatorOnly": "새로운 활동",
"notificationbadge.plus": "{notifications}+",
"picker.placeholder": "선택…",
- "picker.selectedCount": "{count, plural, =0 {선택된 항목이 없습니다} one {#개 항목이 선택되었습니다} other {#개 항목이 선택되었습니다}}",
+ "picker.selectedCount": "{count, plural, =0 {선택한 항목 없음} one {#개 항목 선택됨} other {#개 항목 선택됨}}",
"slider.maximum": "최대",
"slider.minimum": "최소",
+ "table.cancel": "취소",
+ "table.editCell": "셀 편집",
"table.loading": "로드 중…",
"table.loadingMore": "추가 로드 중…",
"table.resizeColumn": "열 크기 조정",
+ "table.save": "저장",
"table.sortAscending": "오름차순 정렬",
"table.sortDescending": "내림차순 정렬",
"tag.actions": "액션",
diff --git a/packages/@react-spectrum/s2/intl/lt-LT.json b/packages/@react-spectrum/s2/intl/lt-LT.json
index b51bce6380b..7429827c18b 100644
--- a/packages/@react-spectrum/s2/intl/lt-LT.json
+++ b/packages/@react-spectrum/s2/intl/lt-LT.json
@@ -29,9 +29,12 @@
"picker.selectedCount": "{count, plural, =0 {Nepasirinktas nė vienas elementas} one {Pasirinktas # elementas} other {Pasirinkta elementų: #}}",
"slider.maximum": "Daugiausia",
"slider.minimum": "Mažiausia",
+ "table.cancel": "Atšaukti",
+ "table.editCell": "Redaguoti langelį",
"table.loading": "Įkeliama...",
"table.loadingMore": "Įkeliama daugiau...",
"table.resizeColumn": "Keisti stulpelio dydį",
+ "table.save": "Įrašyti",
"table.sortAscending": "Rikiuoti didėjimo tvarka",
"table.sortDescending": "Rikiuoti mažėjimo tvarka",
"tag.actions": "Veiksmai",
diff --git a/packages/@react-spectrum/s2/intl/lv-LV.json b/packages/@react-spectrum/s2/intl/lv-LV.json
index e3f7a7ea231..d8ebbec139d 100644
--- a/packages/@react-spectrum/s2/intl/lv-LV.json
+++ b/packages/@react-spectrum/s2/intl/lv-LV.json
@@ -26,12 +26,15 @@
"notificationbadge.indicatorOnly": "Jauna aktivitāte",
"notificationbadge.plus": "{notifications}+",
"picker.placeholder": "Izvēlēties…",
- "picker.selectedCount": "{count, plural, =0 {Nav atlasīts neviens vienums} one {Atlasīto vienumu skaits: #} other {Atlasīto vienumu skaits: #}}",
+ "picker.selectedCount": "{count, plural, =0 {Nav atlasīts neviens vienums} one {# vienums atlasīts} other {# ieraksti vienumi}}",
"slider.maximum": "Maksimālā vērtība",
"slider.minimum": "Minimālā vērtība",
+ "table.cancel": "Atcelt",
+ "table.editCell": "Rediģēt šūnu",
"table.loading": "Notiek ielāde...",
"table.loadingMore": "Tiek ielādēts vēl...",
"table.resizeColumn": "Mainīt kolonnas lielumu",
+ "table.save": "Saglabāt",
"table.sortAscending": "Kārtot augošā secībā",
"table.sortDescending": "Kārtot dilstošā secībā",
"tag.actions": "Darbības",
diff --git a/packages/@react-spectrum/s2/intl/nb-NO.json b/packages/@react-spectrum/s2/intl/nb-NO.json
index 74a143762ca..22f1735a94a 100644
--- a/packages/@react-spectrum/s2/intl/nb-NO.json
+++ b/packages/@react-spectrum/s2/intl/nb-NO.json
@@ -29,9 +29,12 @@
"picker.selectedCount": "{count, plural, =0 {Ingen elementer er valgt} one {# element er valgt} other {# elementer er valgt}}",
"slider.maximum": "Maksimum",
"slider.minimum": "Minimum",
+ "table.cancel": "Avbryt",
+ "table.editCell": "Rediger celle",
"table.loading": "Laster inn...",
"table.loadingMore": "Laster inn flere...",
"table.resizeColumn": "Endre størrelse på kolonne",
+ "table.save": "Lagre",
"table.sortAscending": "Sorter stigende",
"table.sortDescending": "Sorter synkende",
"tag.actions": "Handlinger",
diff --git a/packages/@react-spectrum/s2/intl/nl-NL.json b/packages/@react-spectrum/s2/intl/nl-NL.json
index 0db747b6997..ecf1ac9e266 100644
--- a/packages/@react-spectrum/s2/intl/nl-NL.json
+++ b/packages/@react-spectrum/s2/intl/nl-NL.json
@@ -29,9 +29,12 @@
"picker.selectedCount": "{count, plural, =0 {Geen items geselecteerd} one {# item geselecteerd} other {# items geselecteerd}}",
"slider.maximum": "Maximum",
"slider.minimum": "Minimum",
+ "table.cancel": "Annuleren",
+ "table.editCell": "Cel bewerken",
"table.loading": "Laden...",
"table.loadingMore": "Meer laden...",
"table.resizeColumn": "Kolomgrootte wijzigen",
+ "table.save": "Opslaan",
"table.sortAscending": "Oplopend sorteren",
"table.sortDescending": "Aflopend sorteren",
"tag.actions": "Acties",
diff --git a/packages/@react-spectrum/s2/intl/pl-PL.json b/packages/@react-spectrum/s2/intl/pl-PL.json
index 66d29db7d34..f32cae48324 100644
--- a/packages/@react-spectrum/s2/intl/pl-PL.json
+++ b/packages/@react-spectrum/s2/intl/pl-PL.json
@@ -26,12 +26,15 @@
"notificationbadge.indicatorOnly": "Nowa aktywność",
"notificationbadge.plus": "{notifications}+",
"picker.placeholder": "Zaznacz…",
- "picker.selectedCount": "{count, plural, =0 {Nie zaznaczono żadnych elementów} one {# zaznaczony element} other {# zaznaczonych elementów}}",
+ "picker.selectedCount": "{count, plural, =0 {Nie zaznaczono żadnych elementów} one {# zaznaczony element} few {# zaznaczone elementy} many {# zaznaczonych elementów} other {# zaznaczonych elementów}}",
"slider.maximum": "Maksimum",
"slider.minimum": "Minimum",
+ "table.cancel": "Anuluj",
+ "table.editCell": "Edytuj komórkę",
"table.loading": "Wczytywanie...",
"table.loadingMore": "Wczytywanie większej liczby...",
"table.resizeColumn": "Zmień rozmiar kolumny",
+ "table.save": "Zapisz",
"table.sortAscending": "Sortuj rosnąco",
"table.sortDescending": "Sortuj malejąco",
"tag.actions": "Działania",
diff --git a/packages/@react-spectrum/s2/intl/pt-BR.json b/packages/@react-spectrum/s2/intl/pt-BR.json
index ac628a96544..cad34acb6ba 100644
--- a/packages/@react-spectrum/s2/intl/pt-BR.json
+++ b/packages/@react-spectrum/s2/intl/pt-BR.json
@@ -29,9 +29,12 @@
"picker.selectedCount": "{count, plural, =0 {Nenhum item selecionado} one {# item selecionado} other {# itens selecionados}}",
"slider.maximum": "Máximo",
"slider.minimum": "Mínimo",
+ "table.cancel": "Cancelar",
+ "table.editCell": "Editar célula",
"table.loading": "Carregando...",
"table.loadingMore": "Carregando mais...",
"table.resizeColumn": "Redimensionar coluna",
+ "table.save": "Salvar",
"table.sortAscending": "Ordenar por ordem crescente",
"table.sortDescending": "Ordenar por ordem decrescente",
"tag.actions": "Ações",
diff --git a/packages/@react-spectrum/s2/intl/pt-PT.json b/packages/@react-spectrum/s2/intl/pt-PT.json
index 4678701584b..5d688a911fe 100644
--- a/packages/@react-spectrum/s2/intl/pt-PT.json
+++ b/packages/@react-spectrum/s2/intl/pt-PT.json
@@ -26,12 +26,15 @@
"notificationbadge.indicatorOnly": "Nova atividade",
"notificationbadge.plus": "{notifications}+",
"picker.placeholder": "Selecionar…",
- "picker.selectedCount": "{count, plural, =0 {Nenhum item selecionado} one {# item selecionado} other {# itens selecionados}}",
+ "picker.selectedCount": "{count, plural, =0 {Nenhum item selecionado} one {# item selecionado} other {# itens selecionados}}.",
"slider.maximum": "Máximo",
"slider.minimum": "Mínimo",
+ "table.cancel": "Cancelar",
+ "table.editCell": "Editar célula",
"table.loading": "A carregar...",
"table.loadingMore": "A carregar mais...",
"table.resizeColumn": "Redimensionar coluna",
+ "table.save": "Guardar",
"table.sortAscending": "Ordenar por ordem ascendente",
"table.sortDescending": "Ordenar por ordem decrescente",
"tag.actions": "Ações",
diff --git a/packages/@react-spectrum/s2/intl/ro-RO.json b/packages/@react-spectrum/s2/intl/ro-RO.json
index df2a88359ce..2ac95333790 100644
--- a/packages/@react-spectrum/s2/intl/ro-RO.json
+++ b/packages/@react-spectrum/s2/intl/ro-RO.json
@@ -26,12 +26,15 @@
"notificationbadge.indicatorOnly": "Activitate nouă",
"notificationbadge.plus": "{notifications}+",
"picker.placeholder": "Selectați…",
- "picker.selectedCount": "{count, plural, =0 {Niciun element selectat} one {# element selectat} other {# elemente selectate}}",
+ "picker.selectedCount": "{count, plural, =0 {Niciun articol selectat} one {# articol selectat} other {# articole selectate}}",
"slider.maximum": "Maximum",
"slider.minimum": "Minimum",
+ "table.cancel": "Anulare",
+ "table.editCell": "Editați celula",
"table.loading": "Se încarcă...",
"table.loadingMore": "Se încarcă mai multe...",
"table.resizeColumn": "Redimensionați coloana",
+ "table.save": "Salvați",
"table.sortAscending": "Sortați crescător",
"table.sortDescending": "Sortați descrescător",
"tag.actions": "Acțiuni",
diff --git a/packages/@react-spectrum/s2/intl/ru-RU.json b/packages/@react-spectrum/s2/intl/ru-RU.json
index dd877691be5..e6548526d1a 100644
--- a/packages/@react-spectrum/s2/intl/ru-RU.json
+++ b/packages/@react-spectrum/s2/intl/ru-RU.json
@@ -2,11 +2,11 @@
"actionbar.actions": "Действия",
"actionbar.actionsAvailable": "Действия доступны.",
"actionbar.clearSelection": "Очистить выбор",
- "actionbar.selected": "Выбрано: {count}",
+ "actionbar.selected": "{count, plural, =0 {Не выбрано} other {Выбрано #}}",
"actionbar.selectedAll": "Выбрано все",
"breadcrumbs.more": "Дополнительные элементы",
"button.pending": "в ожидании",
- "calendar.invalidSelection": "Выбранные {selectedCount, plural, one {дата} other {даты}} недоступны.",
+ "calendar.invalidSelection": "{selectedCount, plural, one {Выбранная дата недоступна} other {Выбранные даты недоступны}}.",
"combobox.noResults": "Результаты отсутствуют",
"contextualhelp.help": "Справка",
"contextualhelp.info": "Информация",
@@ -26,12 +26,15 @@
"notificationbadge.indicatorOnly": "Новая активность",
"notificationbadge.plus": "{notifications}+",
"picker.placeholder": "Выбрать…",
- "picker.selectedCount": "{count, plural, =0 {Нет выбранных элементов} one {# элемент выбран} other {# элементов выбрано}}",
+ "picker.selectedCount": "{count, plural, =0 {Нет выбранных элементов} one {# элемент выбран} other {# эл. выбрано}}",
"slider.maximum": "Максимум",
"slider.minimum": "Минимум",
+ "table.cancel": "Отмена",
+ "table.editCell": "Редактировать ячейку",
"table.loading": "Загрузка...",
"table.loadingMore": "Дополнительная загрузка...",
"table.resizeColumn": "Изменить размер столбца",
+ "table.save": "Сохранить",
"table.sortAscending": "Сортировать по возрастанию",
"table.sortDescending": "Сортировать по убыванию",
"tag.actions": "Действия",
diff --git a/packages/@react-spectrum/s2/intl/sk-SK.json b/packages/@react-spectrum/s2/intl/sk-SK.json
index 35616f124e2..001ccfea64d 100644
--- a/packages/@react-spectrum/s2/intl/sk-SK.json
+++ b/packages/@react-spectrum/s2/intl/sk-SK.json
@@ -26,12 +26,15 @@
"notificationbadge.indicatorOnly": "Nová aktivita",
"notificationbadge.plus": "{notifications}+",
"picker.placeholder": "Vybrať…",
- "picker.selectedCount": "{count, plural, =0 {Žiadne vybraté položky} one {# vybratá položka} other {Počet vybratých položiek:#}}",
+ "picker.selectedCount": "{count, plural, =0 {Žiadne vybraté položky} one {# vybratá položka} other {Počet vybratých položiek #}}",
"slider.maximum": "Maximum",
"slider.minimum": "Minimum",
+ "table.cancel": "Zrušiť",
+ "table.editCell": "Upraviť bunku",
"table.loading": "Načítava sa...",
"table.loadingMore": "Načítava sa viac...",
"table.resizeColumn": "Zmeniť veľkosť stĺpca",
+ "table.save": "Uložiť",
"table.sortAscending": "Zoradiť vzostupne",
"table.sortDescending": "Zoradiť zostupne",
"tag.actions": "Akcie",
diff --git a/packages/@react-spectrum/s2/intl/sl-SI.json b/packages/@react-spectrum/s2/intl/sl-SI.json
index 83336132f92..f48cd9f05fa 100644
--- a/packages/@react-spectrum/s2/intl/sl-SI.json
+++ b/packages/@react-spectrum/s2/intl/sl-SI.json
@@ -26,12 +26,15 @@
"notificationbadge.indicatorOnly": "Nova dejavnost",
"notificationbadge.plus": "{notifications}+",
"picker.placeholder": "Izberite…",
- "picker.selectedCount": "{count, plural, =0 {Noben element ni izbran} one {# element je izbran} other {# elementov je izbranih}}",
+ "picker.selectedCount": "{count, plural, =0 {Ni izbranih elementov} one {izbran je # element} other {izbranih je # elementov}}.",
"slider.maximum": "Največji",
"slider.minimum": "Najmanj",
+ "table.cancel": "Prekliči",
+ "table.editCell": "Uredi celico",
"table.loading": "Nalaganje...",
"table.loadingMore": "Nalaganje več vsebine...",
"table.resizeColumn": "Spremeni velikost stolpca",
+ "table.save": "Shrani",
"table.sortAscending": "Razvrsti naraščajoče",
"table.sortDescending": "Razvrsti padajoče",
"tag.actions": "Dejanja",
diff --git a/packages/@react-spectrum/s2/intl/sr-SP.json b/packages/@react-spectrum/s2/intl/sr-SP.json
index cad130e5cb4..70fa7c74cb5 100644
--- a/packages/@react-spectrum/s2/intl/sr-SP.json
+++ b/packages/@react-spectrum/s2/intl/sr-SP.json
@@ -26,12 +26,15 @@
"notificationbadge.indicatorOnly": "Nova aktivnost",
"notificationbadge.plus": "{notifications}+",
"picker.placeholder": "Izaberite...",
- "picker.selectedCount": "{count, plural, =0 {Nije izabrana nijedna stavka} one {Izabrana je # stavka} other {Izabrano je # stavki}}",
+ "picker.selectedCount": "{count, plural, =0 {No items selected} one {# item selected} other {# items selected}}",
"slider.maximum": "Najviše",
"slider.minimum": "Najmanje",
+ "table.cancel": "Otkaži",
+ "table.editCell": "Uredi ćeliju",
"table.loading": "Učitavam...",
"table.loadingMore": "Učitavam još...",
"table.resizeColumn": "Promeni veličinu kolone",
+ "table.save": "Sačuvaj",
"table.sortAscending": "Sortiraj po rastućem redosledu",
"table.sortDescending": "Sortiraj po opadajućem redosledu",
"tag.actions": "Radnje",
diff --git a/packages/@react-spectrum/s2/intl/sv-SE.json b/packages/@react-spectrum/s2/intl/sv-SE.json
index a7d5a894872..2caf584ba88 100644
--- a/packages/@react-spectrum/s2/intl/sv-SE.json
+++ b/packages/@react-spectrum/s2/intl/sv-SE.json
@@ -26,12 +26,15 @@
"notificationbadge.indicatorOnly": "Ny aktivitet",
"notificationbadge.plus": "{notifications}+",
"picker.placeholder": "Välj…",
- "picker.selectedCount": "{count, plural, =0 {Inga markerade objekt} one {# markerat objekt} other {# markerade objekt}}",
+ "picker.selectedCount": "{count, plural, =0 {Inga objekt markerade} one {# objekt markerat} other {# objekt markerade}}.",
"slider.maximum": "Maximum",
"slider.minimum": "Minimum",
+ "table.cancel": "Avbryt",
+ "table.editCell": "Redigera cell",
"table.loading": "Läser in...",
"table.loadingMore": "Läser in mer...",
"table.resizeColumn": "Ändra storlek på kolumn",
+ "table.save": "Spara",
"table.sortAscending": "Sortera i stigande ordning",
"table.sortDescending": "Sortera i fallande ordning",
"tag.actions": "Åtgärder",
diff --git a/packages/@react-spectrum/s2/intl/tr-TR.json b/packages/@react-spectrum/s2/intl/tr-TR.json
index f9aa48680a0..cbb84153287 100644
--- a/packages/@react-spectrum/s2/intl/tr-TR.json
+++ b/packages/@react-spectrum/s2/intl/tr-TR.json
@@ -29,9 +29,12 @@
"picker.selectedCount": "{count, plural, =0 {Hiçbir öge seçilmedi} one {# öge seçildi} other {# öge seçildi}}",
"slider.maximum": "Maksimum",
"slider.minimum": "Minimum",
+ "table.cancel": "İptal et",
+ "table.editCell": "Hücreyi düzenle",
"table.loading": "Yükleniyor...",
"table.loadingMore": "Daha fazla yükleniyor...",
"table.resizeColumn": "Sütunu yeniden boyutlandır",
+ "table.save": "Kaydet",
"table.sortAscending": "Artan Sıralama",
"table.sortDescending": "Azalan Sıralama",
"tag.actions": "Eylemler",
diff --git a/packages/@react-spectrum/s2/intl/uk-UA.json b/packages/@react-spectrum/s2/intl/uk-UA.json
index c78c03d9ce6..ff7025bd7da 100644
--- a/packages/@react-spectrum/s2/intl/uk-UA.json
+++ b/packages/@react-spectrum/s2/intl/uk-UA.json
@@ -29,9 +29,12 @@
"picker.selectedCount": "{count, plural, =0 {Жодних елементів не вибрано} one {# елемент вибрано} other {Вибрано елементів: #}}",
"slider.maximum": "Максимум",
"slider.minimum": "Мінімум",
+ "table.cancel": "Скасувати",
+ "table.editCell": "Редагувати клітинку",
"table.loading": "Завантаження…",
"table.loadingMore": "Завантаження інших об’єктів...",
"table.resizeColumn": "Змінити розмір стовпця",
+ "table.save": "Зберегти",
"table.sortAscending": "Сортувати за зростанням",
"table.sortDescending": "Сортувати за спаданням",
"tag.actions": "Дії",
diff --git a/packages/@react-spectrum/s2/intl/zh-CN.json b/packages/@react-spectrum/s2/intl/zh-CN.json
index 83fb0898fb1..9c94e3a820a 100644
--- a/packages/@react-spectrum/s2/intl/zh-CN.json
+++ b/packages/@react-spectrum/s2/intl/zh-CN.json
@@ -26,12 +26,15 @@
"notificationbadge.indicatorOnly": "新活动",
"notificationbadge.plus": "{notifications}+",
"picker.placeholder": "选择...",
- "picker.selectedCount": "{count, plural, =0 {未选择项目} one {已选择 # 个项目} other {已选择 # 个项目}}",
+ "picker.selectedCount": "{count, plural, =0 {未选择任何项} one {已选择 # 个项} other {已选择 # 个项}}",
"slider.maximum": "最大",
"slider.minimum": "最小",
+ "table.cancel": "取消",
+ "table.editCell": "编辑单元格",
"table.loading": "正在加载...",
"table.loadingMore": "正在加载更多...",
"table.resizeColumn": "调整列大小",
+ "table.save": "保存",
"table.sortAscending": "升序排序",
"table.sortDescending": "降序排序",
"tag.actions": "操作",
diff --git a/packages/@react-spectrum/s2/intl/zh-TW.json b/packages/@react-spectrum/s2/intl/zh-TW.json
index e098b8c221e..8496c287826 100644
--- a/packages/@react-spectrum/s2/intl/zh-TW.json
+++ b/packages/@react-spectrum/s2/intl/zh-TW.json
@@ -29,9 +29,12 @@
"picker.selectedCount": "{count, plural, =0 {未選取任何項目} one {已選取 # 個項目} other {已選取 # 個項目}}",
"slider.maximum": "最大值",
"slider.minimum": "最小值",
+ "table.cancel": "取消",
+ "table.editCell": "編輯儲存格",
"table.loading": "載入中…",
"table.loadingMore": "正在載入更多…",
"table.resizeColumn": "調整欄大小",
+ "table.save": "儲存",
"table.sortAscending": "升序排序",
"table.sortDescending": "降序排序",
"tag.actions": "動作",
diff --git a/packages/@react-spectrum/s2/src/Accordion.tsx b/packages/@react-spectrum/s2/src/Accordion.tsx
index 07f2763055b..554d6e5d482 100644
--- a/packages/@react-spectrum/s2/src/Accordion.tsx
+++ b/packages/@react-spectrum/s2/src/Accordion.tsx
@@ -11,10 +11,19 @@
*/
import {ContextValue, DisclosureGroup, DisclosureGroupProps, SlotProps} from 'react-aria-components';
-import {DisclosureContext} from './Disclosure';
+import {
+ Disclosure,
+ DisclosureContext,
+ DisclosureHeader,
+ DisclosurePanel,
+ DisclosurePanelProps,
+ DisclosureProps,
+ DisclosureTitle,
+ DisclosureTitleProps
+} from './Disclosure';
import {DOMProps, DOMRef, DOMRefValue, GlobalDOMAttributes} from '@react-types/shared';
import {getAllowedOverrides, StylesPropWithHeight, UnsafeStyles} from './style-utils' with { type: 'macro' };
-import React, {createContext, forwardRef} from 'react';
+import React, {createContext, forwardRef, ReactNode} from 'react';
import {style} from '../style' with { type: 'macro' };
import {useDOMRef} from '@react-spectrum/utils';
import {useSpectrumContextProps} from './useSpectrumContextProps';
@@ -70,3 +79,40 @@ export const Accordion = forwardRef(function Accordion(props: AccordionProps, re
);
});
+
+export interface AccordionItemProps extends DisclosureProps {
+ /** The contents of the accordion, consisting of a AccordionItemTitle and AccordionItemPanel. */
+ children: ReactNode
+}
+/**
+ * A accordion item is a collapsible section of content. It is composed of a header with a heading and trigger button, and a panel that contains the content.
+ */
+export const AccordionItem = forwardRef(function AccordionItem(props: AccordionItemProps, ref: DOMRef) {
+ return ;
+});
+
+export interface AccordionItemTitleProps extends DisclosureTitleProps {}
+/**
+ * An accordion item title consisting of a heading and a trigger button to expand/collapse the panel.
+ */
+export const AccordionItemTitle = forwardRef(function AccordionItemTitle(props: AccordionItemTitleProps, ref: DOMRef) {
+ return ;
+});
+
+export interface AccordionItemHeaderProps extends UnsafeStyles, DOMProps {
+ children: React.ReactNode
+}
+/**
+ * A wrapper element for the accordion item title that can contain other elements not part of the trigger.
+ */
+export const AccordionItemHeader = forwardRef(function AccordionItemHeader(props: AccordionItemHeaderProps, ref: DOMRef) {
+ return ;
+});
+
+export interface AccordionItemPanelProps extends DisclosurePanelProps {}
+/**
+ * An accordion item panel is a collapsible section of content that is hidden until the accordion item is expanded.
+ */
+export const AccordionItemPanel = forwardRef(function AccordionItemPanel(props: AccordionItemPanelProps, ref: DOMRef) {
+ return ;
+});
diff --git a/packages/@react-spectrum/s2/src/Content.tsx b/packages/@react-spectrum/s2/src/Content.tsx
index e7086d4a568..662dff0a2a2 100644
--- a/packages/@react-spectrum/s2/src/Content.tsx
+++ b/packages/@react-spectrum/s2/src/Content.tsx
@@ -24,7 +24,12 @@ interface ContentProps extends UnsafeStyles, SlotProps {
children: ReactNode,
styles?: StyleString,
isHidden?: boolean,
- id?: string
+ id?: string,
+ itemProp?: string,
+ itemScope?: boolean,
+ itemType?: string,
+ itemID?: string,
+ itemRef?: string
}
interface HeadingProps extends Omit {
diff --git a/packages/@react-spectrum/s2/src/Disclosure.tsx b/packages/@react-spectrum/s2/src/Disclosure.tsx
index 08a1d6cab8d..be518872495 100644
--- a/packages/@react-spectrum/s2/src/Disclosure.tsx
+++ b/packages/@react-spectrum/s2/src/Disclosure.tsx
@@ -66,7 +66,7 @@ const disclosure = style({
}, getAllowedOverrides());
/**
- * A disclosure is a collapsible section of content. It is composed of a a header with a heading and trigger button, and a panel that contains the content.
+ * A disclosure is a collapsible section of content. It is composed of a header with a heading and trigger button, and a panel that contains the content.
*/
export const Disclosure = forwardRef(function Disclosure(props: DisclosureProps, ref: DOMRef) {
[props, ref] = useSpectrumContextProps(props, ref, DisclosureContext);
@@ -99,7 +99,7 @@ export const Disclosure = forwardRef(function Disclosure(props: DisclosureProps,
export interface DisclosureTitleProps extends UnsafeStyles, DOMProps {
/** The heading level of the disclosure header.
- *
+ *
* @default 3
*/
level?: number,
@@ -342,4 +342,3 @@ export const DisclosurePanel = forwardRef(function DisclosurePanel(props: Disclo
);
});
-
diff --git a/packages/@react-spectrum/s2/src/index.ts b/packages/@react-spectrum/s2/src/index.ts
index 25629e375f2..9543dc1fc2b 100644
--- a/packages/@react-spectrum/s2/src/index.ts
+++ b/packages/@react-spectrum/s2/src/index.ts
@@ -12,7 +12,7 @@
'use client';
-export {Accordion, AccordionContext} from './Accordion';
+export {Accordion, AccordionContext, AccordionItem, AccordionItemHeader, AccordionItemTitle, AccordionItemPanel} from './Accordion';
export {ActionBar, ActionBarContext} from './ActionBar';
export {ActionButton, ActionButtonContext} from './ActionButton';
export {ActionButtonGroup, ActionButtonGroupContext} from './ActionButtonGroup';
@@ -96,7 +96,7 @@ 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 {AccordionProps, AccordionItemProps, AccordionItemHeaderProps, AccordionItemTitleProps, AccordionItemPanelProps} from './Accordion';
export type {ActionBarProps} from './ActionBar';
export type {ActionButtonProps} from './ActionButton';
export type {ActionButtonGroupProps} from './ActionButtonGroup';
diff --git a/packages/@react-spectrum/s2/stories/Accordion.stories.tsx b/packages/@react-spectrum/s2/stories/Accordion.stories.tsx
index a655b90d5a6..2d38fedbec3 100644
--- a/packages/@react-spectrum/s2/stories/Accordion.stories.tsx
+++ b/packages/@react-spectrum/s2/stories/Accordion.stories.tsx
@@ -10,7 +10,7 @@
* governing permissions and limitations under the License.
*/
-import {Accordion, ActionButton, Disclosure, DisclosureHeader, DisclosurePanel, DisclosureTitle, TextField} from '../src';
+import {Accordion, AccordionItem, AccordionItemHeader, AccordionItemPanel, AccordionItemTitle, ActionButton, TextField} from '../src';
import {Key} from 'react-aria';
import type {Meta, StoryObj} from '@storybook/react';
import NewIcon from '../s2wf-icons/S2_Icon_New_20_N.svg';
@@ -38,22 +38,22 @@ export const Example: Story = {
return (
-
-
+
+
Files
-
-
+
+
Files content
-
-
-
-
+
+
+
+
People
-
-
+
+
-
-
+
+
);
@@ -65,57 +65,57 @@ export const WithLongTitle: Story = {
return (
-
-
+
+
Files
-
-
+
+
Files content
-
-
-
-
+
+
+
+
People
-
-
+
+
People content
-
-
-
-
+
+
+
+
Very very very very very long title that wraps
-
-
+
+
Accordion content
-
-
+
+
);
}
};
-export const WithDisabledDisclosure: Story = {
+export const WithDisabledItem: Story = {
render: (args) => {
return (
-
-
+
+
Files
-
-
+
+
Files content
-
-
-
-
+
+
+
+
People
-
-
+
+
-
-
+
+
);
@@ -128,7 +128,7 @@ WithLongTitle.parameters = {
}
};
-WithDisabledDisclosure.parameters = {
+WithDisabledItem.parameters = {
docs: {
disable: true
}
@@ -142,22 +142,22 @@ function ControlledAccordion(props) {
onExpandedChange={setExpandedKeys}
expandedKeys={expandedKeys}
{...props}>
-
-
+
+
Files
-
-
+
+
Files content
-
-
-
-
+
+
+
+
People
-
-
+
+
-
-
+
+
Expanded keys: {expandedKeys.size ? Array.from(expandedKeys).join(', ') : 'none'}
@@ -180,22 +180,22 @@ export const ControlledOpen: Story = {
-
-
+
+
Files
-
-
+
+
Files content
-
-
-
-
+
+
+
+
People
-
-
+
+
-
-
+
+
);
}
@@ -212,28 +212,28 @@ export const WithActionButton: Story = {
return (
-
-
-
+
+
+
Files
-
+
-
-
+
+
Files content
-
-
-
-
-
+
+
+
+
+
People
-
+
-
-
+
+
-
-
+
+
);
diff --git a/packages/@react-spectrum/s2/style/spectrum-theme.ts b/packages/@react-spectrum/s2/style/spectrum-theme.ts
index 2db0fe14fa6..e38a203845d 100644
--- a/packages/@react-spectrum/s2/style/spectrum-theme.ts
+++ b/packages/@react-spectrum/s2/style/spectrum-theme.ts
@@ -395,7 +395,7 @@ const radius = {
};
type GridTrack = 'none' | 'subgrid' | (string & {}) | readonly GridTrackSize[];
-type GridTrackSize = 'auto' | 'min-content' | 'max-content' | `${number}fr` | `minmax(${string}, ${string})` | keyof typeof baseSpacing | (string & {});
+type GridTrackSize = 'auto' | 'min-content' | 'max-content' | `${number}fr` | `minmax(${string}, ${string})` | number | (string & {});
let gridTrack = (value: GridTrack) => {
if (typeof value === 'string') {
@@ -405,7 +405,7 @@ let gridTrack = (value: GridTrack) => {
};
let gridTrackSize = (value: GridTrackSize) => {
- return value in baseSpacing ? baseSpacing[value] : value;
+ return typeof value === 'number' ? size(value) : value;
};
const transitionProperty = {
diff --git a/packages/@react-stately/datepicker/intl/ko-KR.json b/packages/@react-stately/datepicker/intl/ko-KR.json
index c676bc10a3d..4b813ba32d0 100644
--- a/packages/@react-stately/datepicker/intl/ko-KR.json
+++ b/packages/@react-stately/datepicker/intl/ko-KR.json
@@ -1,6 +1,6 @@
{
"rangeOverflow": "값은 {maxValue} 이전이어야 합니다.",
"rangeReversed": "시작일은 종료일 이전이어야 합니다.",
- "rangeUnderflow": "값은 {minValue} 이상이어야 합니다.",
+ "rangeUnderflow": "값은 {minValue} 이후여야 합니다.",
"unavailableDate": "선택한 날짜를 사용할 수 없습니다."
}
diff --git a/packages/dev/docs/pages/assets/rtl-actual-placeholder.svg b/packages/dev/docs/pages/assets/rtl-actual-placeholder.svg
index f5ff855aafb..3cbbf951f0b 100644
--- a/packages/dev/docs/pages/assets/rtl-actual-placeholder.svg
+++ b/packages/dev/docs/pages/assets/rtl-actual-placeholder.svg
@@ -1,4 +1,4 @@
-
+
diff --git a/packages/dev/docs/pages/assets/rtl-timefield.svg b/packages/dev/docs/pages/assets/rtl-timefield.svg
index ea621765b97..35ab77640e8 100644
--- a/packages/dev/docs/pages/assets/rtl-timefield.svg
+++ b/packages/dev/docs/pages/assets/rtl-timefield.svg
@@ -1,4 +1,4 @@
-
+
Incorrect (he-IL)
diff --git a/packages/dev/docs/pages/react-aria/home/ExampleApp.tsx b/packages/dev/docs/pages/react-aria/home/ExampleApp.tsx
index c7b0ccf8594..5fdeae863f8 100644
--- a/packages/dev/docs/pages/react-aria/home/ExampleApp.tsx
+++ b/packages/dev/docs/pages/react-aria/home/ExampleApp.tsx
@@ -174,11 +174,11 @@ export function ExampleApp(): React.ReactNode {
return (
-
+
-
-
+
+
{filters > 0 && {filters}
}
Filters
@@ -186,7 +186,7 @@ export function ExampleApp(): React.ReactNode {
Filters
- {filters > 0 && Clear }
+ {filters > 0 && Clear }
Favorite
@@ -209,7 +209,7 @@ export function ExampleApp(): React.ReactNode {
-
+
Columns
@@ -222,7 +222,7 @@ export function ExampleApp(): React.ReactNode {
-
+
@@ -237,9 +237,9 @@ export function ExampleApp(): React.ReactNode {
{item.common_name}
-
{item.scientific_name}
+
{item.scientific_name}
-
+
onAction(item, action)}>
{item.isFavorite ? 'Unfavorite' : 'Favorite'}
Edit…
@@ -283,7 +283,7 @@ export function ExampleApp(): React.ReactNode {
{item.common_name}
-
{item.scientific_name}
+
{item.scientific_name}
);
@@ -297,7 +297,7 @@ export function ExampleApp(): React.ReactNode {
return (
-
+
onAction(item, action)}>
@@ -340,7 +340,7 @@ export function ExampleApp(): React.ReactNode {
}
const labelStyles = {
- gray: 'bg-gray-100 text-gray-600 border-gray-200 dark:bg-zinc-700 dark:text-zinc-300 dark:border-zinc-600',
+ gray: 'bg-neutral-100 text-neutral-600 border-neutral-200 dark:bg-neutral-700 dark:text-neutral-300 dark:border-neutral-600',
green: 'bg-green-100 text-green-700 border-green-200 dark:bg-green-300/20 dark:text-green-400 dark:border-green-300/10',
yellow: 'bg-yellow-100 text-yellow-700 border-yellow-200 dark:bg-yellow-300/20 dark:text-yellow-400 dark:border-yellow-300/10',
blue: 'bg-blue-100 text-blue-700 border-blue-200 dark:bg-blue-400/20 dark:text-blue-300 dark:border-blue-400/10'
@@ -399,7 +399,7 @@ function PlantDialog({item, onSave}: {item?: Plant | null, onSave: (item: Plant)
<>
+ className="text-2xl font-semibold leading-6 my-0 text-neutral-700 dark:text-neutral-300">
{item ? 'Edit Plant' : 'Add Plant'}
|
@@ -527,10 +527,10 @@ function PlantModal(props: ModalOverlayProps) {
Dialog
DropZone
- Select
- DatePicker
- ComboBox
- TextField
+ Select
+ DatePicker
+ ComboBox
+ TextField
Form
@@ -539,7 +539,7 @@ function PlantModal(props: ModalOverlayProps) {
{...props}
ref={ref}
className={({isEntering, isExiting}) => `
- w-full max-w-md max-h-full overflow-auto rounded-2xl bg-white dark:bg-zinc-800/70 dark:backdrop-blur-2xl dark:backdrop-saturate-200 forced-colors:!bg-[Canvas] box-border p-6 border-box text-left align-middle shadow-2xl bg-clip-padding border border-black/10 dark:border-white/10
+ w-full max-w-md max-h-full overflow-auto rounded-2xl bg-white dark:bg-neutral-800/70 dark:backdrop-blur-2xl dark:backdrop-saturate-200 forced-colors:!bg-[Canvas] box-border p-6 border-box text-left align-middle shadow-2xl bg-clip-padding border border-black/10 dark:border-white/10
${isEntering ? 'animate-in zoom-in-105 ease-out duration-200' : ''}
${isExiting ? 'animate-out zoom-out-95 ease-in duration-200' : ''}
`} />
@@ -554,8 +554,8 @@ const favoriteButtonStyles = tv({
base: 'group cursor-default align-middle rounded-sm border-0 bg-transparent p-0',
variants: {
isSelected: {
- false: 'text-gray-500 dark:text-zinc-400 pressed:text-gray-600 dark:pressed:text-zinc-300',
- true: 'text-gray-700 dark:text-slate-300 pressed:text-gray-800 dark:pressed:text-slate-200'
+ false: 'text-neutral-500 dark:text-neutral-400 pressed:text-neutral-600 dark:pressed:text-neutral-300',
+ true: 'text-neutral-700 dark:text-neutral-300 pressed:text-neutral-800 dark:pressed:text-neutral-200'
}
}
});
@@ -563,7 +563,7 @@ const favoriteButtonStyles = tv({
function FavoriteButton(props: ToggleButtonProps) {
return (
-
+
);
}
diff --git a/packages/dev/docs/pages/react-aria/home/FocusExample.tsx b/packages/dev/docs/pages/react-aria/home/FocusExample.tsx
index 1b5020db603..ea411c5060d 100644
--- a/packages/dev/docs/pages/react-aria/home/FocusExample.tsx
+++ b/packages/dev/docs/pages/react-aria/home/FocusExample.tsx
@@ -21,7 +21,7 @@ export function FocusExample() {
return (
-
+
Your Account
diff --git a/packages/dev/docs/pages/react-aria/home/MouseAnimation.tsx b/packages/dev/docs/pages/react-aria/home/MouseAnimation.tsx
index 3810e59ae75..67a377c28f4 100644
--- a/packages/dev/docs/pages/react-aria/home/MouseAnimation.tsx
+++ b/packages/dev/docs/pages/react-aria/home/MouseAnimation.tsx
@@ -60,7 +60,7 @@ export function MouseAnimation(): ReactNode {
mouseRef.current!.animate({
transform: [
'translate(10px, 10px)',
- 'translate(110px, 14px)'
+ 'translate(105px, 14px)'
]
}, {duration: 2000, fill: 'forwards', easing: 'ease-in-out'});
}
@@ -97,7 +97,7 @@ export function MouseAnimation(): ReactNode {
perform() {
mouseRef.current!.animate({
transform: [
- 'translate(110px, 14px)',
+ 'translate(105px, 14px)',
'translate(170px, 150px)'
]
}, {duration: 1500, fill: 'forwards', easing: 'ease-in-out'});
@@ -151,20 +151,20 @@ export function MouseAnimation(): ReactNode {
onOpenChange('edit', o)}>
-
+
Edit
onOpenChange('share', o)}>
-
+
Share
onOpenChange('settings', o)}>
-
+
diff --git a/packages/dev/s2-docs/pages/react-aria/Menu.mdx b/packages/dev/s2-docs/pages/react-aria/Menu.mdx
index 9208e444b51..264fd6ee0c5 100644
--- a/packages/dev/s2-docs/pages/react-aria/Menu.mdx
+++ b/packages/dev/s2-docs/pages/react-aria/Menu.mdx
@@ -18,8 +18,6 @@ export const relatedPages = [{'title': 'useMenu', 'url': 'https://react-spectrum
"use client";
import {MenuTrigger, SubmenuTrigger, Menu, MenuItem, MenuSection} from 'vanilla-starter/Menu';
import {Separator, Text, Keyboard} from 'react-aria-components';
- import {Popover} from 'vanilla-starter/Popover';
- import {Button} from 'vanilla-starter/Button';
import {Button} from 'vanilla-starter/Button';
import {Ellipsis, FolderOpen, Pencil, Copy, Trash, Share, Mail, Smartphone, Instagram} from 'lucide-react';
@@ -27,57 +25,55 @@ export const relatedPages = [{'title': 'useMenu', 'url': 'https://react-spectrum
-
-
-
- alert('open')}>
-
- Open
- ⌘O
-
- alert('rename')}>
-
- Rename…
- ⌘R
-
- alert('duplicate')}>
-
- Duplicate
- ⌘D
-
- alert('delete')}>
-
- Delete…
- ⌘⌫
+
+
+ alert('open')}>
+
+ Open
+ ⌘O
+
+ alert('rename')}>
+
+ Rename…
+ ⌘R
+
+ alert('duplicate')}>
+
+ Duplicate
+ ⌘D
+
+ alert('delete')}>
+
+ Delete…
+ ⌘⌫
+
+
+
+
+ Share
-
+
-
- Share
+
+ Email
-
-
-
- Email
-
-
-
- SMS
-
-
-
- Instagram
-
-
-
-
-
-
- Show files
- Show folders
-
-
-
+
+
+ SMS
+
+
+
+ Instagram
+
+
+
+
+
+
+ Show files
+ Show folders
+
+
```
@@ -122,7 +118,6 @@ export const relatedPages = [{'title': 'useMenu', 'url': 'https://react-spectrum
```tsx render hideImports
"use client";
import {MenuTrigger, Menu, MenuItem} from 'vanilla-starter/Menu';
-import {Popover} from 'vanilla-starter/Popover';
import {Button} from 'vanilla-starter/Button';
function Example() {
@@ -141,13 +136,11 @@ function Example() {
return (
File
-
- {/*- begin highlight -*/}
-
- {(item) => {item.name} }
-
- {/*- end highlight -*/}
-
+ {/*- begin highlight -*/}
+
+ {(item) => {item.name} }
+
+ {/*- end highlight -*/}
);
}
@@ -161,32 +154,29 @@ Use the `"label"` and `"description"` slots to separate primary and secondary co
"use client";
import {MenuTrigger, Menu, MenuItem} from 'vanilla-starter/Menu';
import {Text, Keyboard} from 'react-aria-components';
-import {Popover} from 'vanilla-starter/Popover';
import {Button} from 'vanilla-starter/Button';
Permissions
-
-
-
- {/*- begin highlight -*/}
- Copy
- Copy the selected text
- {/*- end highlight -*/}
- ⌘C
-
-
- Cut
- Cut the selected text
- ⌘X
-
-
- Paste
- Paste the copied text
- ⌘V
-
-
-
+
+
+ {/*- begin highlight -*/}
+ Copy
+ Copy the selected text
+ {/*- end highlight -*/}
+ ⌘C
+
+
+ Cut
+ Cut the selected text
+ ⌘X
+
+
+ Paste
+ Paste the copied text
+ ⌘V
+
+
```
@@ -203,67 +193,61 @@ Use the `` component to group options. A `` element may als
"use client";
import {Header} from 'react-aria-components';
import {MenuTrigger, Menu, MenuItem, MenuSection} from 'vanilla-starter/Menu';
-import {Popover} from 'vanilla-starter/Popover';
import {Button} from 'vanilla-starter/Button';
Publish
-
-
- {/*- begin highlight -*/}
-
-
- {/*- end highlight -*/}
- Image…
- Video…
- Text…
-
-
-
- YouTube…
- Instagram…
- Email…
-
-
-
+
+ {/*- begin highlight -*/}
+
+
+ {/*- end highlight -*/}
+ Image…
+ Video…
+ Text…
+
+
+
+ YouTube…
+ Instagram…
+ Email…
+
+
```
### Submenus
-Wrap a `` and a `` with a `` to create a submenu.
+Wrap a `` with a `` to create a submenu.
```tsx render hideImports
"use client";
import {MenuTrigger, SubmenuTrigger, Menu, MenuItem, MenuSection} from 'vanilla-starter/Menu';
-import {Popover} from 'vanilla-starter/Popover';
import {Button} from 'vanilla-starter/Button';
Actions
-
-
- Cut
- Copy
- Delete
- {/*- begin highlight -*/}
-
- Share
- {/*- end highlight -*/}
-
- SMS
- Instagram
-
- Email
-
- Work
- Personal
-
-
-
-
-
-
+
+ Cut
+ Copy
+ Delete
+ {/*- begin highlight -*/}
+
+ Share
+ {/*- end highlight -*/}
+
+ SMS
+ Instagram
+
+ Email
+
+ Work
+ Personal
+
+
+
+
+
```
@@ -275,26 +259,23 @@ Separators may be added between menu items or sections in order to create non-la
"use client";
import {MenuTrigger, Menu, MenuItem, MenuSection} from 'vanilla-starter/Menu';
import {Separator} from 'react-aria-components';
-import {Popover} from 'vanilla-starter/Popover';
import {Button} from 'vanilla-starter/Button';
Actions
-
-
- New…
- Open…
- {/*- begin highlight -*/}
-
- {/*- end highlight -*/}
- Save
- Save as…
- Rename…
-
- Page setup…
- Print…
-
-
+
+ New…
+ Open…
+ {/*- begin highlight -*/}
+
+ {/*- end highlight -*/}
+ Save
+ Save as…
+ Rename…
+
+ Page setup…
+ Print…
+
```
@@ -305,21 +286,18 @@ Use the `href` prop on a `` to create a link. See the **client side ro
```tsx render hideImports
"use client";
import {MenuTrigger, Menu, MenuItem, MenuSection} from 'vanilla-starter/Menu';
-import {Popover} from 'vanilla-starter/Popover';
import {Button} from 'vanilla-starter/Button';
Links
-
-
- {/*- begin highlight -*/}
- Adobe
- {/*- end highlight -*/}
- Apple
- Google
- Microsoft
-
-
+
+ {/*- begin highlight -*/}
+ Adobe
+ {/*- end highlight -*/}
+ Apple
+ Google
+ Microsoft
+
```
@@ -332,7 +310,6 @@ Popovers can include additional components as siblings of a menu. This example u
import {Autocomplete, useFilter} from 'react-aria-components';
import {MenuTrigger, Menu, MenuItem} from 'vanilla-starter/Menu';
import {Button} from 'vanilla-starter/Button';
-import {Popover} from 'vanilla-starter/Popover';
import {SearchField} from 'vanilla-starter/SearchField';
function Example() {
@@ -341,7 +318,7 @@ function Example() {
return (
Add tag...
-
+
{/*- begin highlight -*/}
@@ -358,7 +335,7 @@ function Example() {
Science
-
+
);
}
@@ -373,7 +350,6 @@ Use the `selectionMode` prop to enable single or multiple selection. The selecte
import type {Selection} from 'react-aria-components';
import {MenuTrigger, Menu, MenuItem} from 'vanilla-starter/Menu';
import {Button} from 'vanilla-starter/Button';
-import {Popover} from 'vanilla-starter/Popover';
import {useState} from 'react';
function Example(props) {
@@ -383,22 +359,19 @@ function Example(props) {
<>
View
-
-
- Pixel grid
- Rulers
-
- Layout guides
- Toolbar
-
-
+
+ {/*- end highlight -*/}
+ Pixel grid
+ Rulers
+
+ Layout guides
+ Toolbar
+
Current selection: {selected === 'all' ? 'all' : [...selected].join(', ')}
>
@@ -416,7 +389,6 @@ import type {Selection} from 'react-aria-components';
import {Header} from 'react-aria-components';
import {MenuTrigger, Menu, MenuItem, MenuSection} from 'vanilla-starter/Menu';
import {Button} from 'vanilla-starter/Button';
-import {Popover} from 'vanilla-starter/Popover';
import {useState} from 'react';
function Example() {
@@ -425,33 +397,31 @@ function Example() {
return (
Edit
-
-
-
-
- Cut
- Copy
- Paste
-
- {/*- begin highlight -*/}
-
- {/*- end highlight -*/}
-
- Bold
- Italic
- Underline
-
-
-
- Left
- Center
- Right
-
-
-
+
+
+
+ Cut
+ Copy
+ Paste
+
+ {/*- begin highlight -*/}
+
+ {/*- end highlight -*/}
+
+ Bold
+ Italic
+ Underline
+
+
+
+ Left
+ Center
+ Right
+
+
);
}
@@ -468,7 +438,6 @@ function Example() {
import {Pressable} from 'react-aria-components';
import {MenuTrigger, Menu, MenuItem} from 'vanilla-starter/Menu';
import {Button} from 'vanilla-starter/Button';
-import {Popover} from 'vanilla-starter/Popover';
{/*- begin highlight -*/}
@@ -476,14 +445,12 @@ import {Popover} from 'vanilla-starter/Popover';
Custom trigger
{/*- end highlight -*/}
-
-
- Open
- Rename…
- Duplicate
- Delete…
-
-
+
+ Open
+ Rename…
+ Duplicate
+ Delete…
+
```
@@ -506,7 +473,6 @@ Use `trigger="longPress"` to open the menu on long press instead of on click/tap
"use client";
import {MenuTrigger, Menu, MenuItem} from 'vanilla-starter/Menu';
import {Button} from 'vanilla-starter/Button';
-import {Popover} from 'vanilla-starter/Popover';
import {ChevronDown} from 'lucide-react';
@@ -514,13 +480,11 @@ import {ChevronDown} from 'lucide-react';
Crop
-
-
- Rotate
- Slice
- Clone stamp
-
-
+
+ Rotate
+ Slice
+ Clone stamp
+
```
diff --git a/packages/dev/s2-docs/pages/react-aria/Modal.mdx b/packages/dev/s2-docs/pages/react-aria/Modal.mdx
index 14e1876af64..b0e5dc0b981 100644
--- a/packages/dev/s2-docs/pages/react-aria/Modal.mdx
+++ b/packages/dev/s2-docs/pages/react-aria/Modal.mdx
@@ -62,11 +62,15 @@ export const relatedPages = [{'title': 'useModalOverlay', 'url': 'https://react-
Sign up…
+ Subscribe to our newsletter
+ Enter your information to subscribe to our newsletter and receive updates about new features and announcements.
@@ -104,7 +108,7 @@ Use the `isOpen` prop to show a modal programmatically or mount in a different p
"use client";
import {useState} from 'react';
import {Heading} from 'react-aria-components';
-import {MenuButton, MenuItem} from 'vanilla-starter/Menu';
+import {MenuTrigger, Menu, MenuItem} from 'vanilla-starter/Menu';
import {Modal} from 'vanilla-starter/Modal';
import {Dialog} from 'vanilla-starter/Dialog';
import {Button} from 'vanilla-starter/Button';
@@ -114,9 +118,12 @@ function Example() {
return (
<>
-
- setOpen(true)}>Open dialog…
-
+
+ Menu
+
+ setOpen(true)}>Open dialog…
+
+
Notice
diff --git a/packages/dev/s2-docs/pages/react-aria/Toolbar.mdx b/packages/dev/s2-docs/pages/react-aria/Toolbar.mdx
index 70e749ceef1..96ea1c026e0 100644
--- a/packages/dev/s2-docs/pages/react-aria/Toolbar.mdx
+++ b/packages/dev/s2-docs/pages/react-aria/Toolbar.mdx
@@ -78,7 +78,7 @@ export const relatedPages = [{'title': 'useToolbar', 'url': 'https://react-spect
-
+
diff --git a/packages/dev/s2-docs/pages/react-aria/blog/ColorEditorExample.tsx b/packages/dev/s2-docs/pages/react-aria/blog/ColorEditorExample.tsx
index 2794f68a93d..df70de58d99 100644
--- a/packages/dev/s2-docs/pages/react-aria/blog/ColorEditorExample.tsx
+++ b/packages/dev/s2-docs/pages/react-aria/blog/ColorEditorExample.tsx
@@ -75,7 +75,9 @@ export function ColorEditorExample() {
padding: {
default: 12,
lg: 24
- }
+ },
+ maxWidth: '--text-width',
+ marginX: 'auto'
})}>
{({color}) => (
diff --git a/packages/dev/s2-docs/pages/react-aria/blog/SubmenuAnimation.tsx b/packages/dev/s2-docs/pages/react-aria/blog/SubmenuAnimation.tsx
index 2114063e38d..f34749333b6 100644
--- a/packages/dev/s2-docs/pages/react-aria/blog/SubmenuAnimation.tsx
+++ b/packages/dev/s2-docs/pages/react-aria/blog/SubmenuAnimation.tsx
@@ -120,7 +120,6 @@ export function SubmenuAnimation(): JSX.Element {
className={style({
backgroundColor: 'layer-1',
borderRadius: 'xl',
- marginY: 32,
padding: {
default: 12,
lg: 24
diff --git a/packages/dev/s2-docs/pages/react-aria/blog/accessible-color-descriptions.mdx b/packages/dev/s2-docs/pages/react-aria/blog/accessible-color-descriptions.mdx
index db256aee4e8..fad57e3c933 100644
--- a/packages/dev/s2-docs/pages/react-aria/blog/accessible-color-descriptions.mdx
+++ b/packages/dev/s2-docs/pages/react-aria/blog/accessible-color-descriptions.mdx
@@ -16,7 +16,6 @@ export default Layout;
import docs from 'docs:@react-spectrum/s2';
import React from 'react';
-import {Byline} from '../../../src/BlogList';
import {ColorEditorExample} from './ColorEditorExample';
export const hideNav = true;
@@ -29,7 +28,6 @@ export const section = 'Blog';
export const isSubpage = true;
# Accessible Color Descriptions for Improved Color Pickers
-
Recently, we released a suite of color picker components in React Aria and React Spectrum. These components help users choose a color in various ways, including a 2D [ColorArea](../ColorArea.html), channel-based [ColorSlider](../ColorSlider.html), circular [ColorWheel](../ColorWheel.html), preset [ColorSwatchPicker](../ColorSwatchPicker.html), and a hex value [ColorField](../ColorField.html). You can compose these individual pieces together to create a full [ColorPicker](../ColorPicker.html) with whatever custom layout or configuration you need.
diff --git a/packages/dev/s2-docs/pages/react-aria/blog/building-a-button-part-1.mdx b/packages/dev/s2-docs/pages/react-aria/blog/building-a-button-part-1.mdx
index 689c04abd07..4f4caff2327 100644
--- a/packages/dev/s2-docs/pages/react-aria/blog/building-a-button-part-1.mdx
+++ b/packages/dev/s2-docs/pages/react-aria/blog/building-a-button-part-1.mdx
@@ -16,7 +16,6 @@ export default Layout;
import docs from 'docs:@react-spectrum/s2';
import React from 'react';
-import {Byline} from '../../../src/BlogList';
export const hideNav = true;
export const tags = ['react aria', 'react spectrum', 'react', 'spectrum', 'interactions', 'button', 'touch'];
@@ -28,7 +27,6 @@ export const section = 'Blog';
export const isSubpage = true;
# Building a Button Part 1: Press Events
-
UI development is really hard. While building components has become much easier with modern UI frameworks like React, handling interactions across devices and supporting proper accessibility and internationalization is still extraordinarily difficult. Building UIs has a very [long tail](https://en.wikipedia.org/wiki/Long_tail): it's fairly easy to get the basics for a given component working, but there are many details to consider, and these add up to a majority of the work.
diff --git a/packages/dev/s2-docs/pages/react-aria/blog/building-a-button-part-2.mdx b/packages/dev/s2-docs/pages/react-aria/blog/building-a-button-part-2.mdx
index 260b201ccf0..55394c6e9ed 100644
--- a/packages/dev/s2-docs/pages/react-aria/blog/building-a-button-part-2.mdx
+++ b/packages/dev/s2-docs/pages/react-aria/blog/building-a-button-part-2.mdx
@@ -15,7 +15,6 @@ export default Layout;
import docs from 'docs:@react-spectrum/s2';
import React from 'react';
-import {Byline} from '../../../src/BlogList';
export const hideNav = true;
export const tags = ['react aria', 'react spectrum', 'react', 'interactions', 'button', 'touch', 'hover', 'web development', 'javascript', 'css'];
@@ -27,7 +26,6 @@ export const section = 'Blog';
export const isSubpage = true;
# Building a Button Part 2: Hover Interactions
-
This is the second post in our three part series on building a button component. In the [first post](building-a-button-part-1.html), we covered how React Spectrum and React Aria implement adaptive press events across mouse, touch, keyboard, and screen readers. Today, we'll cover hover interactions.
diff --git a/packages/dev/s2-docs/pages/react-aria/blog/building-a-button-part-3.mdx b/packages/dev/s2-docs/pages/react-aria/blog/building-a-button-part-3.mdx
index fa696c101b3..d30bcc62e88 100644
--- a/packages/dev/s2-docs/pages/react-aria/blog/building-a-button-part-3.mdx
+++ b/packages/dev/s2-docs/pages/react-aria/blog/building-a-button-part-3.mdx
@@ -15,7 +15,6 @@ export default Layout;
import docs from 'docs:@react-spectrum/s2';
import React from 'react';
-import {Byline} from '../../../src/BlogList';
export const hideNav = true;
export const tags = ['react aria', 'react spectrum', 'react', 'interactions', 'button', 'keyboard', 'focus', 'web development', 'javascript', 'css'];
@@ -27,7 +26,6 @@ export const section = 'Blog';
export const isSubpage = true;
# Building a Button Part 3: Keyboard Focus Behavior
-
This is the last post in our three part series on building a button component. In the [first post](building-a-button-part-1.html), we covered how React Spectrum and React Aria implement adaptive press events across mouse, touch, keyboard, and screen readers. In the [second post](building-a-button-part-2.html), we covered hover interactions. Today, we'll cover keyboard focus behavior.
diff --git a/packages/dev/s2-docs/pages/react-aria/blog/building-a-combobox.mdx b/packages/dev/s2-docs/pages/react-aria/blog/building-a-combobox.mdx
index 165ce6d7250..ca6f56e6074 100644
--- a/packages/dev/s2-docs/pages/react-aria/blog/building-a-combobox.mdx
+++ b/packages/dev/s2-docs/pages/react-aria/blog/building-a-combobox.mdx
@@ -19,7 +19,6 @@ export default Layout;
import docs from 'docs:@react-spectrum/s2';
import React from 'react';
-import {Byline} from '../../../src/BlogList';
export const hideNav = true;
export const tags = ['combobox', 'accessibility', 'mobile', 'react spectrum', 'react', 'spectrum', 'interactions', 'touch'];
@@ -31,7 +30,6 @@ export const section = 'Blog';
export const isSubpage = true;
# Creating an accessible autocomplete experience
-
After many months of research, development, and extensive testing across browsers, devices, and assistive technology, we're excited to announce that the React Spectrum [ComboBox](../../s2/ComboBox.html) component and React Aria [useComboBox](https://react-spectrum.adobe.com/react-aria/useComboBox.html) hook are now available! We've focused on the following areas to help you build quality autocomplete experiences.
diff --git a/packages/dev/s2-docs/pages/react-aria/blog/creating-a-pointer-friendly-submenu-experience.mdx b/packages/dev/s2-docs/pages/react-aria/blog/creating-a-pointer-friendly-submenu-experience.mdx
index ddf143f1433..b49c8240a21 100644
--- a/packages/dev/s2-docs/pages/react-aria/blog/creating-a-pointer-friendly-submenu-experience.mdx
+++ b/packages/dev/s2-docs/pages/react-aria/blog/creating-a-pointer-friendly-submenu-experience.mdx
@@ -17,7 +17,6 @@ export default Layout;
import docs from 'docs:@react-spectrum/s2';
import React from 'react';
-import {Byline} from '../../../src/BlogList';
export const hideNav = true;
export const tags = ['react aria', 'react spectrum', 'react', 'spectrum', 'interactions', 'submenu', 'pointer'];
@@ -29,7 +28,6 @@ export const section = 'Blog';
export const isSubpage = true;
# Creating a pointer-friendly submenu experience
-
We are excited to announce support of submenus in the latest release of [React Spectrum](../../s2/Menu.html#submenus) and [React Aria](../Menu.html#submenus)! In the process of adding this feature, we found ourselves solving some unique challenges while working to make submenus user-friendly and accessible across an array of devices and input types. In doing so, we wanted to share our thought process in solving one of the challenges we faced along the way.
diff --git a/packages/dev/s2-docs/pages/react-aria/blog/date-and-time-pickers-for-all.mdx b/packages/dev/s2-docs/pages/react-aria/blog/date-and-time-pickers-for-all.mdx
index d949f021ff2..9908aebd1e4 100644
--- a/packages/dev/s2-docs/pages/react-aria/blog/date-and-time-pickers-for-all.mdx
+++ b/packages/dev/s2-docs/pages/react-aria/blog/date-and-time-pickers-for-all.mdx
@@ -18,7 +18,6 @@ export default Layout;
import docs from 'docs:@react-spectrum/s2';
import React from 'react';
-import {Byline} from '../../../src/BlogList';
import {DateField, RangeCalendar} from '@react-spectrum/s2';
import {today, getLocalTimeZone} from '@internationalized/date';
import RangeCalendarExample from './RangeCalendarExample';
@@ -34,7 +33,6 @@ export const section = 'Blog';
export const isSubpage = true;
# Date and Time Pickers for All
-
We are very excited to announce the release of the [React Aria](https://react-spectrum.adobe.com/react-aria/useNumberField.html) and [React Spectrum](../../s2/DatePicker.html) date and time picker components! This includes a full suite of fully featured components and hooks including calendars, date and time fields, and range pickers, all with a focus on internationalization and accessibility. It also includes [@internationalized/date](../../internationalized/date/index.html), a brand new framework-agnostic library for locale-aware date and time manipulation.
diff --git a/packages/dev/s2-docs/pages/react-aria/blog/drag-and-drop.mdx b/packages/dev/s2-docs/pages/react-aria/blog/drag-and-drop.mdx
index ce7b80f9b79..316a3001653 100644
--- a/packages/dev/s2-docs/pages/react-aria/blog/drag-and-drop.mdx
+++ b/packages/dev/s2-docs/pages/react-aria/blog/drag-and-drop.mdx
@@ -22,7 +22,6 @@ export default Layout;
import docs from 'docs:@react-spectrum/s2';
import React from 'react';
-import {Byline} from '../../../src/BlogList';
export const hideNav = true;
export const tags = ['drag and drop', 'dnd', 'components', 'accessibility', 'keyboard', 'mobile', 'react spectrum', 'react', 'spectrum', 'interactions', 'touch'];
@@ -34,7 +33,6 @@ export const section = 'Blog';
export const isSubpage = true;
# Taming the dragon: Accessible drag and drop
-
We are excited to announce the release of drag and drop support in [React Aria](../dnd.html) and [React Spectrum](../../s2/dnd.html)! This includes a suite of hooks for implementing drag and drop interactions, with support for both mouse and touch, as well as full parity for keyboard and screen reader input. We've designed these hooks with the following features in mind:
@@ -59,7 +57,9 @@ After years of research, development, and extensive testing across many devices
Drag and drop starts with a drag source, implemented using the [useDrag](../useDrag.html) hook, which provides data to be dragged. Multiple items can be dragged at once, and each item can include several representations in different data formats so that they can be dropped in many compatible locations. The [useDrop](../useDrop.html) hook can be used to implement a drop target, which accepts dragged items containing specific data types.
-
+
For mouse and touch screen users, React Aria uses the native [HTML drag and drop API](https://developer.mozilla.org/en-US/docs/Web/API/HTML_Drag_and_Drop_API) under the hood. This means items can be dragged within the browser window, between browser windows, or even outside the browser into external native applications (e.g. email programs). External items such as files or directories from the user's device may also be dragged in.
@@ -82,7 +82,7 @@ All of these accessibility features are implemented behind the scenes using the
Collection components such as lists or tables are treated as a single drop target, so that users can easily tab past them to get to the next drop target without going through every item. Within a droppable collection, keys such as `ArrowDown` and `ArrowUp` can be used to select a drop position, such as on the collection itself, on an item, or between items. Drop indicator elements may be added between items to show the user where dropped data will be inserted, and include accessibility labels such as "Insert between item A and item B".
-
+
diff --git a/packages/dev/s2-docs/pages/react-aria/blog/how-we-internationalized-our-numberfield.mdx b/packages/dev/s2-docs/pages/react-aria/blog/how-we-internationalized-our-numberfield.mdx
index aab5a684550..c6f7b191a37 100644
--- a/packages/dev/s2-docs/pages/react-aria/blog/how-we-internationalized-our-numberfield.mdx
+++ b/packages/dev/s2-docs/pages/react-aria/blog/how-we-internationalized-our-numberfield.mdx
@@ -19,7 +19,6 @@ export default Layout;
import docs from 'docs:@react-spectrum/s2';
import React from 'react';
-import {Byline} from '../../../src/BlogList';
import {NumberField} from '@react-spectrum/s2';
export const hideNav = true;
@@ -32,7 +31,6 @@ export const section = 'Blog';
export const isSubpage = true;
# How we internationalized our number field
-
Number fields are commonly used form components, but are frequently not a great user experience. They often lack support for advanced formatting, such as currency and unit values, and do not provide a localized experience for users around the world. In this post, we'll discuss how we approached building our number field component with support for formatting and internationalization in mind.
diff --git a/packages/dev/s2-docs/pages/react-aria/blog/index.mdx b/packages/dev/s2-docs/pages/react-aria/blog/index.mdx
index afaa1cca139..dd6e3fcb049 100644
--- a/packages/dev/s2-docs/pages/react-aria/blog/index.mdx
+++ b/packages/dev/s2-docs/pages/react-aria/blog/index.mdx
@@ -8,7 +8,7 @@ OF ANY KIND, either express or implied. See the License for the specific languag
governing permissions and limitations under the License. */}
import {Layout} from '../../../src/Layout';
-import {BlogList} from '../../../src/BlogList';
+import {PostList} from '../../../src/PostList';
export default Layout;
@@ -17,8 +17,9 @@ export const section = 'Blog';
export const title = 'Blog';
export const hideFromSearch = true;
export const tags = ['blog', 'articles', 'posts'];
+export const isPostList = true;
# Blog
-
page.name.startsWith('react-aria/blog/') && !page.name.endsWith('index.html')) ?? []} />
+ page.name.startsWith('react-aria/blog/') && !page.name.endsWith('index.html')) ?? []} />
diff --git a/packages/dev/s2-docs/pages/react-aria/blog/intl/he-IL.json b/packages/dev/s2-docs/pages/react-aria/blog/intl/he-IL.json
index 53b2f3e5e80..e03b62a9028 100644
--- a/packages/dev/s2-docs/pages/react-aria/blog/intl/he-IL.json
+++ b/packages/dev/s2-docs/pages/react-aria/blog/intl/he-IL.json
@@ -1,6 +1,6 @@
{
"colorFormat": "פורמט צבע",
- "hex": "משושה",
+ "hex": "Hex",
"hsb": "HSB",
"hsl": "HSL",
"rgb": "RGB"
diff --git a/packages/dev/s2-docs/pages/react-aria/blog/rtl-date-time.mdx b/packages/dev/s2-docs/pages/react-aria/blog/rtl-date-time.mdx
index d11503ebaee..9f0f2912ed1 100644
--- a/packages/dev/s2-docs/pages/react-aria/blog/rtl-date-time.mdx
+++ b/packages/dev/s2-docs/pages/react-aria/blog/rtl-date-time.mdx
@@ -18,7 +18,6 @@ export default Layout;
import docs from 'docs:@react-spectrum/s2';
import React from 'react';
-import {Byline} from '../../../src/BlogList';
export const hideNav = true;
export const tags = ['date picker', 'date', 'time', 'calendar', 'components', 'accessibility', 'react spectrum', 'react', 'spectrum'];
@@ -30,7 +29,6 @@ export const section = 'Blog';
export const isSubpage = true;
# Improving Internationalization Support in Our Date and Time Components
-
Internationalization is a core feature of our Date and Time components. We support 13 different calendar systems as well as locale-specific formatting, number systems, and 12 and 24 hour time. However, we identified an issue in our support for several right-to-left (RTL) languages where in some, the format of the date and time fields was incorrect. While investigating this bug, we faced several challenges in ensuring accurate date and time representation in RTL languages and implemented various strategies that we'd like to share.
diff --git a/packages/dev/s2-docs/pages/react-aria/collections.mdx b/packages/dev/s2-docs/pages/react-aria/collections.mdx
index 844be2dbf00..470c5e7ef89 100644
--- a/packages/dev/s2-docs/pages/react-aria/collections.mdx
+++ b/packages/dev/s2-docs/pages/react-aria/collections.mdx
@@ -17,13 +17,17 @@ A **static collection** is a collection that does not change over time (e.g. har
```tsx render
"use client";
-import {MenuButton, MenuItem} from 'vanilla-starter/Menu';
+import {MenuTrigger, Menu, MenuItem} from 'vanilla-starter/Menu';
+import {Button} from 'vanilla-starter/Button';
-
- Open
- Edit
- Delete
-
+
+ Menu
+
+ Open
+ Edit
+ Delete
+
+
```
### Sections
@@ -34,24 +38,28 @@ Sections or groups of items can be constructed by wrapping the items in a sectio
```tsx render
"use client";
-import {MenuButton, MenuItem, MenuSection} from 'vanilla-starter/Menu';
+import {MenuTrigger, Menu, MenuItem, MenuSection} from 'vanilla-starter/Menu';
+import {Button} from 'vanilla-starter/Button';
import {Header} from 'react-aria-components';
-
- {/*- begin highlight -*/}
-
-
- {/*- end highlight -*/}
- Bold
- Underline
-
-
-
- Left
- Middle
- Right
-
-
+
+ Menu
+
+ {/*- begin highlight -*/}
+
+
+ {/*- end highlight -*/}
+ Bold
+ Underline
+
+
+
+ Left
+ Middle
+ Right
+
+
+
```
```tsx render
diff --git a/packages/dev/s2-docs/pages/react-aria/examples/crud.mdx b/packages/dev/s2-docs/pages/react-aria/examples/crud.mdx
index a95ecbf1479..c1520d9b46e 100644
--- a/packages/dev/s2-docs/pages/react-aria/examples/crud.mdx
+++ b/packages/dev/s2-docs/pages/react-aria/examples/crud.mdx
@@ -8,6 +8,7 @@ import {ExampleApp} from '../../../src/ExampleApp';
import {ComponentList} from '../../../src/ComponentCard';
export const hideNav = true;
+export const isSubpage = true;
export const section = 'Examples';
export const keywords = ['react-aria', 'example', 'table', 'search', 'filters', 'taggroup', 'actions', 'form', 'menu', 'popover', 'searchfield', 'dropzone', 'crud'];
export const description = 'Table with search, filters, column resizing, and form validation.';
diff --git a/packages/dev/s2-docs/pages/react-aria/examples/emoji-picker.mdx b/packages/dev/s2-docs/pages/react-aria/examples/emoji-picker.mdx
index e0867069831..05b9e2648a3 100644
--- a/packages/dev/s2-docs/pages/react-aria/examples/emoji-picker.mdx
+++ b/packages/dev/s2-docs/pages/react-aria/examples/emoji-picker.mdx
@@ -4,6 +4,7 @@ export default Layout;
import {ComponentList} from '../../../src/ComponentCard';
export const hideNav = true;
+export const isSubpage = true;
export const section = 'Examples';
export const keywords = ['react-aria', 'example', 'select', 'popover', 'autocomplete', 'search', 'searchfield', 'virtualizer', 'listbox'];
export const description = 'With autocomplete, virtualized scrolling, and keyboard navigation.';
diff --git a/packages/dev/s2-docs/pages/react-aria/examples/index.mdx b/packages/dev/s2-docs/pages/react-aria/examples/index.mdx
index 7d7bb8bdba7..202a3363822 100644
--- a/packages/dev/s2-docs/pages/react-aria/examples/index.mdx
+++ b/packages/dev/s2-docs/pages/react-aria/examples/index.mdx
@@ -4,6 +4,7 @@ export default Layout;
export const section = 'Overview';
export const hideFromSearch = true;
export const title = 'Examples';
+export const isPostList = true;
# Examples
diff --git a/packages/dev/s2-docs/pages/react-aria/examples/ios-list.mdx b/packages/dev/s2-docs/pages/react-aria/examples/ios-list.mdx
index cb9cbac4b31..545494c7ead 100644
--- a/packages/dev/s2-docs/pages/react-aria/examples/ios-list.mdx
+++ b/packages/dev/s2-docs/pages/react-aria/examples/ios-list.mdx
@@ -5,6 +5,7 @@ import '../../../tailwind/tailwind.css';
import {ComponentList} from '../../../src/ComponentCard';
export const hideNav = true;
+export const isSubpage = true;
export const section = 'Examples';
export const keywords = ['react-aria', 'example', 'gridlist', 'gesture', 'framer motion', 'tailwind'];
export const description = 'A GridList with Framer Motion swipe gestures and layout animations.';
diff --git a/packages/dev/s2-docs/pages/react-aria/examples/kanban.mdx b/packages/dev/s2-docs/pages/react-aria/examples/kanban.mdx
index 8f4a7984ba6..27348081c72 100644
--- a/packages/dev/s2-docs/pages/react-aria/examples/kanban.mdx
+++ b/packages/dev/s2-docs/pages/react-aria/examples/kanban.mdx
@@ -5,6 +5,7 @@ import '../../../tailwind/tailwind.css';
import {ComponentList} from '../../../src/ComponentCard';
export const hideNav = true;
+export const isSubpage = true;
export const section = 'Examples';
export const keywords = ['react-aria', 'example', 'gridlist', 'kanban', 'drag and drop', 'tailwind'];
export const description = 'A kanban board with accessible drag and drop, styled with Tailwind CSS.';
diff --git a/packages/dev/s2-docs/pages/react-aria/examples/photos.mdx b/packages/dev/s2-docs/pages/react-aria/examples/photos.mdx
index c1c7a744713..d1463b67e33 100644
--- a/packages/dev/s2-docs/pages/react-aria/examples/photos.mdx
+++ b/packages/dev/s2-docs/pages/react-aria/examples/photos.mdx
@@ -6,6 +6,7 @@ import {ExampleApp} from '../../../src/ExampleApp';
import {ComponentList} from '../../../src/ComponentCard';
export const hideNav = true;
+export const isSubpage = true;
export const section = 'Examples';
export const keywords = ['react-aria', 'example', 'gridlist', 'autocomplete', 'searchfield', 'virtualizer', 'view transition', 'tree', 'selection', 'drag and drop', 'slider'];
export const description = 'Virtualized photo grid, view transitions, folder tree, search, and drag and drop.';
diff --git a/packages/dev/s2-docs/pages/react-aria/examples/plants/App.tsx b/packages/dev/s2-docs/pages/react-aria/examples/plants/App.tsx
index f0476177764..f3d152ca4d1 100644
--- a/packages/dev/s2-docs/pages/react-aria/examples/plants/App.tsx
+++ b/packages/dev/s2-docs/pages/react-aria/examples/plants/App.tsx
@@ -124,7 +124,8 @@ export default function App(): React.ReactNode {
@@ -132,8 +133,8 @@ export default function App(): React.ReactNode {
{/* Filters */}
-
-
+
+
{filters > 0 && {filters}
}
Filters
@@ -141,7 +142,7 @@ export default function App(): React.ReactNode {
Filters
- {filters > 0 && Clear }
+ {filters > 0 && Clear }
Favorite
@@ -166,7 +167,7 @@ export default function App(): React.ReactNode {
{/* Columns */}
-
+
Columns
@@ -180,7 +181,7 @@ export default function App(): React.ReactNode {
-
+
diff --git a/packages/dev/s2-docs/pages/react-aria/examples/plants/PlantActionMenu.tsx b/packages/dev/s2-docs/pages/react-aria/examples/plants/PlantActionMenu.tsx
index 0488dfb4988..c01d9e582bb 100644
--- a/packages/dev/s2-docs/pages/react-aria/examples/plants/PlantActionMenu.tsx
+++ b/packages/dev/s2-docs/pages/react-aria/examples/plants/PlantActionMenu.tsx
@@ -14,7 +14,7 @@ export function PlantActionMenu(props: PlantActionMenuProps) {
let {item, onFavoriteChange, onEdit, onDelete} = props;
return (
-
+
diff --git a/packages/dev/s2-docs/pages/react-aria/examples/plants/PlantDialog.tsx b/packages/dev/s2-docs/pages/react-aria/examples/plants/PlantDialog.tsx
index a98e9b72e7a..855d82409d5 100644
--- a/packages/dev/s2-docs/pages/react-aria/examples/plants/PlantDialog.tsx
+++ b/packages/dev/s2-docs/pages/react-aria/examples/plants/PlantDialog.tsx
@@ -51,10 +51,10 @@ export function PlantDialog({item, onSave}: {item?: Plant | null, onSave: (item:
-
+
{plant => {plant.common_name} }
-
+
diff --git a/packages/dev/s2-docs/pages/react-aria/examples/ripple-button.mdx b/packages/dev/s2-docs/pages/react-aria/examples/ripple-button.mdx
index a5f4cb02242..fdec2c85b16 100644
--- a/packages/dev/s2-docs/pages/react-aria/examples/ripple-button.mdx
+++ b/packages/dev/s2-docs/pages/react-aria/examples/ripple-button.mdx
@@ -5,6 +5,7 @@ import '../../../tailwind/tailwind.css';
import {ComponentList} from '../../../src/ComponentCard';
export const hideNav = true;
+export const isSubpage = true;
export const section = 'Examples';
export const keywords = ['react-aria', 'example', 'button', 'tailwind'];
export const description = 'A button with an animated ripple effect styled with Tailwind CSS.';
diff --git a/packages/dev/s2-docs/pages/react-aria/examples/sheet.mdx b/packages/dev/s2-docs/pages/react-aria/examples/sheet.mdx
index 14f22ae7bd6..10f888d7247 100644
--- a/packages/dev/s2-docs/pages/react-aria/examples/sheet.mdx
+++ b/packages/dev/s2-docs/pages/react-aria/examples/sheet.mdx
@@ -5,6 +5,7 @@ import '../../../tailwind/tailwind.css';
import {ComponentList} from '../../../src/ComponentCard';
export const hideNav = true;
+export const isSubpage = true;
export const section = 'Examples';
export const keywords = ['react-aria', 'example', 'dialog', 'modal', 'sheet', 'motion', 'tailwind'];
export const description = 'An iOS-style gesture driven modal sheet built with Framer Motion.';
diff --git a/packages/dev/s2-docs/pages/react-aria/examples/swipeable-tabs.mdx b/packages/dev/s2-docs/pages/react-aria/examples/swipeable-tabs.mdx
index b0639e51ff4..57fc6c3c085 100644
--- a/packages/dev/s2-docs/pages/react-aria/examples/swipeable-tabs.mdx
+++ b/packages/dev/s2-docs/pages/react-aria/examples/swipeable-tabs.mdx
@@ -5,6 +5,7 @@ import '../../../tailwind/tailwind.css';
import {ComponentList} from '../../../src/ComponentCard';
export const hideNav = true;
+export const isSubpage = true;
export const section = 'Examples';
export const keywords = ['react-aria', 'example', 'tabs', 'tailwind'];
export const description = 'With CSS scroll snapping, scroll-driven animations, and anchor positioning.';
diff --git a/packages/dev/s2-docs/pages/react-aria/getting-started.mdx b/packages/dev/s2-docs/pages/react-aria/getting-started.mdx
index f57833a2d0a..54e186253b1 100644
--- a/packages/dev/s2-docs/pages/react-aria/getting-started.mdx
+++ b/packages/dev/s2-docs/pages/react-aria/getting-started.mdx
@@ -74,7 +74,7 @@ If you're building a full component library, download a pre-built [Storybook](ht
### Working with AI
-Use the menu at the top of each page in the docs to open or copy it into your favorite AI assistant. We also have an [MCP server](mcp.html) which can be used directly in your IDE, and lms.txt which can help AI agents navigate the docs.
+Use the menu on each page in the docs to open or copy it into your favorite AI assistant. We also have an [MCP server](mcp.html) which can be used directly in your IDE, and lms.txt which can help AI agents navigate the docs.
## Build a component from scratch
diff --git a/packages/dev/s2-docs/pages/react-aria/index.mdx b/packages/dev/s2-docs/pages/react-aria/index.mdx
index 1d8ea951a54..92a588f780e 100644
--- a/packages/dev/s2-docs/pages/react-aria/index.mdx
+++ b/packages/dev/s2-docs/pages/react-aria/index.mdx
@@ -49,9 +49,9 @@ export const hideFromSearch = true;
dangerouslySetInnerHTML={{__html: JSON.stringify(
{
'@context': 'http://schema.org',
- '@type': 'Article',
+ '@type': 'WebPage',
author: 'Adobe Inc',
- headline: 'React Aria',
+ name: 'React Aria',
description: 'Craft world-class accessible components with custom styles.',
image: ogImage,
publisher: {
@@ -139,6 +139,9 @@ export const hideFromSearch = true;
Menu
+
@@ -301,6 +304,7 @@ export const hideFromSearch = true;
Make your web app feel native with rich interactions that adapt to the device, platform, and user. React Aria supports advanced features like accessible drag and drop, keyboard multi-selection, built-in form validation, table column resizing, and a ton more.
+
View example source
@@ -384,7 +388,7 @@ export const hideFromSearch = true;
Customizable to the max.
React Aria offers a flexible and scalable API that lets you dive as deep into the details as you like. Start with high-level components with a built-in DOM structure and simple styling API, compose custom patterns with contexts, and for the ultimate control, drop down to the low-level Hook-based API. Mix and match as needed.
-
+
diff --git a/packages/dev/s2-docs/pages/react-aria/releases/index.mdx b/packages/dev/s2-docs/pages/react-aria/releases/index.mdx
index d9478e971c2..f10e1b48439 100644
--- a/packages/dev/s2-docs/pages/react-aria/releases/index.mdx
+++ b/packages/dev/s2-docs/pages/react-aria/releases/index.mdx
@@ -8,7 +8,7 @@ OF ANY KIND, either express or implied. See the License for the specific languag
governing permissions and limitations under the License. */}
import {Layout} from '../../../src/Layout';
-import {ReleasesList} from '../../../src/ReleasesList';
+import {PostList} from '../../../src/PostList';
export default Layout;
export const hideNav = true;
@@ -16,7 +16,10 @@ export const section = 'Releases';
export const tags = ['changelog', 'versions', 'updates'];
export const title = 'Releases';
export const hideFromSearch = true;
+export const isPostList = true;
# Releases
- page.name.includes('react-aria') && page.name.includes('releases') && !page.name.includes('index.html')) ?? []} />
+ page.name.includes('react-aria') && page.name.includes('releases') && !page.name.includes('index.html')) ?? []} />
+
+For all previous releases, see the [Archived releases](https://react-spectrum.adobe.com/releases/index.html) page.
diff --git a/packages/dev/s2-docs/pages/react-aria/releases/v1-0-0.mdx b/packages/dev/s2-docs/pages/react-aria/releases/v1-0-0.mdx
index 5f7a1811a0f..4f113cc3894 100644
--- a/packages/dev/s2-docs/pages/react-aria/releases/v1-0-0.mdx
+++ b/packages/dev/s2-docs/pages/react-aria/releases/v1-0-0.mdx
@@ -11,7 +11,6 @@ import {Layout} from '../../../src/Layout';
export default Layout;
import docs from 'docs:@react-spectrum/s2';
-import {Time} from '../../../src/ReleasesList';
export const hideNav = true;
export const section = 'Releases';
@@ -22,7 +21,6 @@ export const description = 'In this release, we\'re promoting React Aria Compone
export const isSubpage = true;
# v1.0.0
-
Welcome to the last release of the year! After a year of work, we are happy to announce the GA release of React Aria Components 🎉 This component library, built on top of our React Aria hooks, provides a simpler way to craft world-class accessible components with custom styles. See our new React Aria [landing page](https://react-spectrum.adobe.com/react-aria/index.html) for all of the details, including interactive examples. To help get you started even faster, we now also have a downloadable Storybook [starter kit](../getting-started.html#starter-kit) including an example CSS theme.
diff --git a/packages/dev/s2-docs/pages/react-aria/releases/v1-1-0.mdx b/packages/dev/s2-docs/pages/react-aria/releases/v1-1-0.mdx
index 448bd6555ff..586962a8d40 100644
--- a/packages/dev/s2-docs/pages/react-aria/releases/v1-1-0.mdx
+++ b/packages/dev/s2-docs/pages/react-aria/releases/v1-1-0.mdx
@@ -11,7 +11,6 @@ import {Layout} from '../../../src/Layout';
export default Layout;
import docs from 'docs:@react-spectrum/s2';
-import {Time} from '../../../src/ReleasesList';
export const hideNav = true;
export const section = 'Releases';
@@ -22,7 +21,6 @@ export const description = 'Welcome to the first release of the new year! We hav
export const isSubpage = true;
# v1.1.0
-
Welcome to the first release of the new year! We have had a great response to our GA release of React Aria Components. If you haven't tried it out, visit [our docs](https://react-spectrum.adobe.com/react-aria/index.html) to explore the examples. To help get you started, we have also created a few starter kits. These downloadable [starter kits](../getting-started.html#starter-kits) contain beautifully styled implementations of every available component and includes a working storybook. Available in vanilla and Tailwind CSS!
diff --git a/packages/dev/s2-docs/pages/react-aria/releases/v1-10-0.mdx b/packages/dev/s2-docs/pages/react-aria/releases/v1-10-0.mdx
index 93da0024d22..d08a5ad83f7 100644
--- a/packages/dev/s2-docs/pages/react-aria/releases/v1-10-0.mdx
+++ b/packages/dev/s2-docs/pages/react-aria/releases/v1-10-0.mdx
@@ -11,7 +11,6 @@ import {Layout} from '../../../src/Layout';
export default Layout;
import docs from 'docs:@react-spectrum/s2';
-import {Time} from '../../../src/ReleasesList';
export const hideNav = true;
export const section = 'Releases';
@@ -22,7 +21,6 @@ export const description = 'Drop everything! Drag and drop support in React Aria
export const isSubpage = true;
# v1.10.0
-
Drop everything! Drag and drop support in React Aria Tree has been released! 🫳🎤 This supports moving items within a tree or between collection components, with full keyboard and screen reader accessibility. It's interoperable with our existing drag and drop support in components like Table and GridList, and with third party apps via native HTML APIs. Check out our [previous blog post](../blog/drag-and-drop.html) on drag and drop to learn about the interactions, and our new [Tree drag and drop documentation](../Tree.html#drag-and-drop).
diff --git a/packages/dev/s2-docs/pages/react-aria/releases/v1-11-0.mdx b/packages/dev/s2-docs/pages/react-aria/releases/v1-11-0.mdx
index dc3a7edea81..d9ac3d4a0be 100644
--- a/packages/dev/s2-docs/pages/react-aria/releases/v1-11-0.mdx
+++ b/packages/dev/s2-docs/pages/react-aria/releases/v1-11-0.mdx
@@ -11,7 +11,6 @@ import {Layout} from '../../../src/Layout';
export default Layout;
import docs from 'docs:@react-spectrum/s2';
-import {Time} from '../../../src/ReleasesList';
export const hideNav = true;
export const section = 'Releases';
@@ -22,7 +21,6 @@ export const description = 'Happy summer! This release adds support for async lo
export const isSubpage = true;
# v1.11.0
-
Happy summer! This release adds support for async loading and infinite scrolling, improves form integration and drag and drop interactions, and adds support for additional DOM events and attributes.
diff --git a/packages/dev/s2-docs/pages/react-aria/releases/v1-12-0.mdx b/packages/dev/s2-docs/pages/react-aria/releases/v1-12-0.mdx
index 3c878883282..cdd643efe8e 100644
--- a/packages/dev/s2-docs/pages/react-aria/releases/v1-12-0.mdx
+++ b/packages/dev/s2-docs/pages/react-aria/releases/v1-12-0.mdx
@@ -11,7 +11,6 @@ import {Layout} from '../../../src/Layout';
export default Layout;
import docs from 'docs:@react-spectrum/s2';
-import {Time} from '../../../src/ReleasesList';
export const hideNav = true;
export const section = 'Releases';
@@ -22,7 +21,6 @@ export const description = 'Summer might be winding down but we\'re definitely n
export const isSubpage = true;
# v1.12.0
-
Summer might be winding down but we're definitely not! Back with another release, we have added support for origin-aware overlay animations in [Popover](../Popover.html) and [Tooltip](../Tooltip.html), which enable scale transitions to appear as if they are emerging from the trigger. We have also advanced Autocomplete to RC, and added support for filtering GridList, Table, and TagGroup (virtual focus support is still to come). Section support in [GridList](../GridList.html#sections) has also been added as an alpha, laying the groundwork for similar support in Tree and Table.
diff --git a/packages/dev/s2-docs/pages/react-aria/releases/v1-13-0.mdx b/packages/dev/s2-docs/pages/react-aria/releases/v1-13-0.mdx
index 5d30f1bdde8..7d84d4cd28f 100644
--- a/packages/dev/s2-docs/pages/react-aria/releases/v1-13-0.mdx
+++ b/packages/dev/s2-docs/pages/react-aria/releases/v1-13-0.mdx
@@ -11,8 +11,6 @@ import {Layout} from '../../../src/Layout';
export default Layout;
import docs from 'docs:@react-spectrum/s2';
-import {Time} from '../../../src/ReleasesList';
-import {ReleasedVersions} from '../../../src/ReleasesList';
export const hideNav = true;
export const section = 'Releases';
@@ -23,7 +21,6 @@ export const description = 'Happy fall! This release brings some long-awaited fe
export const isSubpage = true;
# v1.13.0
-
Happy fall! This release brings some long-awaited features, including multi-selection in [React Aria Select](../Select.html#multiple-selection) and enhanced animation support across our components. For example, [Disclosure](../Disclosure.html) now provides CSS variables to easily animate expanding and collapsing. We’ve also added a new `` component that can be used within components that support single selection such as [Tabs](../Tabs.html) and [ToggleButtonGroup](../ToggleButtonGroup.html#animation) to animate selection changes. In addition, we have significantly improved the behavior of scrolling modals on iOS 26. Lastly, `onAction` can now be used on a [`ComboBoxItem`](../ComboBox.html#item-actions), enabling you to add a “create” option.
diff --git a/packages/dev/s2-docs/pages/react-aria/releases/v1-2-0.mdx b/packages/dev/s2-docs/pages/react-aria/releases/v1-2-0.mdx
index 677f2069037..82664323df6 100644
--- a/packages/dev/s2-docs/pages/react-aria/releases/v1-2-0.mdx
+++ b/packages/dev/s2-docs/pages/react-aria/releases/v1-2-0.mdx
@@ -11,7 +11,6 @@ import {Layout} from '../../../src/Layout';
export default Layout;
import docs from 'docs:@react-spectrum/s2';
-import {Time} from '../../../src/ReleasesList';
export const hideNav = true;
export const section = 'Releases';
@@ -22,7 +21,6 @@ export const description = 'We have a huge release! Submenu, unavailable menu it
export const isSubpage = true;
# v1.2.0
-
We have a huge release today! Its a GA bonanza 🎊 – [Submenu](../Menu.html#submenus), [unavailable menu items](../Menu.html#unavailable-items), [DropZone](../DropZone.html) and [FileTrigger](../FileTrigger.html) components are now in GA. Check our [blog post](/blog/creating-a-pointer-friendly-submenu-experience.html) on the intricacies of the submenu interactions and how we handled them.
diff --git a/packages/dev/s2-docs/pages/react-aria/releases/v1-3-0.mdx b/packages/dev/s2-docs/pages/react-aria/releases/v1-3-0.mdx
index 1177bbf361e..7f76109d96e 100644
--- a/packages/dev/s2-docs/pages/react-aria/releases/v1-3-0.mdx
+++ b/packages/dev/s2-docs/pages/react-aria/releases/v1-3-0.mdx
@@ -11,7 +11,6 @@ import {Layout} from '../../../src/Layout';
export default Layout;
import docs from 'docs:@react-spectrum/s2';
-import {Time} from '../../../src/ReleasesList';
export const hideNav = true;
export const section = 'Releases';
@@ -22,7 +21,6 @@ export const description = 'For this summer release, we have been busy working o
export const isSubpage = true;
# v1.3.0
-
For this summer release, we have been busy working on improving virtualization in many of our Spectrum components including TableView, ListView, and ListBox. We have significantly reduced the complexity of our implementation, resulting in smaller bundle size, better performance, and improved stability. In our testing, this resulted in 14x faster per-frame render times on large tables due to better reuse of DOM nodes as you scroll. We are also working on bringing virtualization support to React Aria Components, which is available as an unstable API in this version.
diff --git a/packages/dev/s2-docs/pages/react-aria/releases/v1-4-0.mdx b/packages/dev/s2-docs/pages/react-aria/releases/v1-4-0.mdx
index 251cb90a016..752938d29a4 100644
--- a/packages/dev/s2-docs/pages/react-aria/releases/v1-4-0.mdx
+++ b/packages/dev/s2-docs/pages/react-aria/releases/v1-4-0.mdx
@@ -11,7 +11,6 @@ import {Layout} from '../../../src/Layout';
export default Layout;
import docs from 'docs:@react-spectrum/s2';
-import {Time} from '../../../src/ReleasesList';
export const hideNav = true;
export const section = 'Releases';
@@ -22,7 +21,6 @@ export const description = 'Happy fall! 🍁 We\'re excited to announce that our
export const isSubpage = true;
# v1.4.0
-
Happy fall! 🍁 We're excited to announce that our color picker components are now generally available! This includes [ColorPicker](../ColorPicker.html), [ColorArea](../ColorArea.html), [ColorField](../ColorField.html), [ColorSlider](../ColorSlider.html), [ColorSwatch](../ColorSwatch.html), [ColorSwatchPicker](../ColorSwatchPicker.html), and [ColorWheel](../ColorWheel.html). These enable you to build fully customizable color pickers, including accessible color descriptions for screen reader support.
diff --git a/packages/dev/s2-docs/pages/react-aria/releases/v1-5-0.mdx b/packages/dev/s2-docs/pages/react-aria/releases/v1-5-0.mdx
index 3caf3deb4a0..de52da9d90f 100644
--- a/packages/dev/s2-docs/pages/react-aria/releases/v1-5-0.mdx
+++ b/packages/dev/s2-docs/pages/react-aria/releases/v1-5-0.mdx
@@ -11,7 +11,6 @@ import {Layout} from '../../../src/Layout';
export default Layout;
import docs from 'docs:@react-spectrum/s2';
-import {Time} from '../../../src/ReleasesList';
export const hideNav = true;
export const section = 'Releases';
@@ -22,7 +21,6 @@ export const description = 'We\'re excited to announce that our Disclosure compo
export const isSubpage = true;
# v1.5.0
-
We're excited to announce that our Disclosure components are now generally available! This includes [Disclosure](../Disclosure.html) and [DisclosureGroup](../DisclosureGroup.html) in React Aria. These components now also use the `hidden="until-found"` API currently supported in Chrome to enable searching collapsed content with ctrl + F.
diff --git a/packages/dev/s2-docs/pages/react-aria/releases/v1-6-0.mdx b/packages/dev/s2-docs/pages/react-aria/releases/v1-6-0.mdx
index e4093f02ca8..a346a0356a7 100644
--- a/packages/dev/s2-docs/pages/react-aria/releases/v1-6-0.mdx
+++ b/packages/dev/s2-docs/pages/react-aria/releases/v1-6-0.mdx
@@ -11,7 +11,6 @@ import {Layout} from '../../../src/Layout';
export default Layout;
import docs from 'docs:@react-spectrum/s2';
-import {Time} from '../../../src/ReleasesList';
export const hideNav = true;
export const section = 'Releases';
@@ -22,7 +21,6 @@ export const description = 'Happy New Year! Our first release of 2025 includes a
export const isSubpage = true;
# v1.6.0
-
Happy New Year! Our first release of 2025 includes a new [firstDayOfWeek](../Calendar.html#custom-first-day-of-week) prop for our calendar and date picker components, support for [CSS transitions](../styling.html#animation) in our overlay components, a new [Autocomplete](../Autocomplete.html) component in alpha, and a new [React Aria test utils](../testing.html#react-aria-test-utils) package.
As always, a huge shoutout to everyone in the community for their feedback and contributions!
diff --git a/packages/dev/s2-docs/pages/react-aria/releases/v1-7-0.mdx b/packages/dev/s2-docs/pages/react-aria/releases/v1-7-0.mdx
index 2360275fa2c..0fd9ddbaeab 100644
--- a/packages/dev/s2-docs/pages/react-aria/releases/v1-7-0.mdx
+++ b/packages/dev/s2-docs/pages/react-aria/releases/v1-7-0.mdx
@@ -11,7 +11,6 @@ import {Layout} from '../../../src/Layout';
export default Layout;
import docs from 'docs:@react-spectrum/s2';
-import {Time} from '../../../src/ReleasesList';
import datepickerImage from 'url:../assets/datepicker-rtl.png';
export const hideNav = true;
@@ -23,7 +22,6 @@ export const description = 'Buckle in because this is a big one! In this React A
export const isSubpage = true;
# v1.7.0
-
Buckle in because this is a big one! In this React Aria release, we’re excited to announce three new components: [Toast](../Toast.html), [Tree](../Tree.html), and [Virtualizer](../Virtualizer.html). In addition, we have improved [Autocomplete](../Autocomplete.html) to enable UI patterns like [Searchable Menus](../Menu.html#complex-content), [Searchable Selects](../examples/searchable-select.html), and [Command Palettes](../examples/command-palette.html), added support for custom [Menu](../Menu.html#custom-trigger), [Popover](../Popover.html#custom-trigger), and [Tooltip](../Tooltip.html#custom-trigger) triggers, introduced `colSpan` support in Table, and upgraded to Tailwind CSS v4. Last but not least, we have a major refactor of [usePress](../usePress.html), which fixes many longstanding issues and improves compatibility with third party libraries.
diff --git a/packages/dev/s2-docs/pages/react-aria/releases/v1-8-0.mdx b/packages/dev/s2-docs/pages/react-aria/releases/v1-8-0.mdx
index 99629c9c136..b7efed617a1 100644
--- a/packages/dev/s2-docs/pages/react-aria/releases/v1-8-0.mdx
+++ b/packages/dev/s2-docs/pages/react-aria/releases/v1-8-0.mdx
@@ -11,7 +11,6 @@ import {Layout} from '../../../src/Layout';
export default Layout;
import docs from 'docs:@react-spectrum/s2';
-import {Time} from '../../../src/ReleasesList';
export const hideNav = true;
export const section = 'Releases';
@@ -22,7 +21,6 @@ export const description = 'In today\'s release we are excited to announce custo
export const isSubpage = true;
# v1.8.0
-
In today's release, we are excited to announce custom calendar support in React Aria Components! This feature allows you to create your own calendar that implements custom business logic, such as a [4-5-4 fiscal calendar](https://nrf.com/resources/4-5-4-calendar), either by extending an existing Calendar implementation or building from scratch. Please see the [React Aria docs](../Calendar.html#custom-calendar-systems) for an example implementation. A special shout out to [@ToyWalrus](https://github.com/ToyWalrus) for all the hard work that went into this contribution!
diff --git a/packages/dev/s2-docs/pages/react-aria/releases/v1-9-0.mdx b/packages/dev/s2-docs/pages/react-aria/releases/v1-9-0.mdx
index fa905d92c5d..abe78b0fbf4 100644
--- a/packages/dev/s2-docs/pages/react-aria/releases/v1-9-0.mdx
+++ b/packages/dev/s2-docs/pages/react-aria/releases/v1-9-0.mdx
@@ -11,7 +11,6 @@ import {Layout} from '../../../src/Layout';
export default Layout;
import docs from 'docs:@react-spectrum/s2';
-import {Time} from '../../../src/ReleasesList';
export const hideNav = true;
export const section = 'Releases';
@@ -22,7 +21,6 @@ export const description = 'This release includes a range of enhancements and fi
export const isSubpage = true;
# v1.9.0
-
This release includes a range of enhancements and fixes such as improved keyboard accessibility in TagGroup and increased stability for dynamic table updates. It also brings support for React 19's ref cleanup behavior, performance improvements for collection updates in React transitions and pressable elements, and TypeScript updates including backwards compatibility with older TypeScript and `@types/react` versions.
diff --git a/packages/dev/s2-docs/pages/s2/Accordion.mdx b/packages/dev/s2-docs/pages/s2/Accordion.mdx
index 5ca3f9cbe99..305acb95dd3 100644
--- a/packages/dev/s2-docs/pages/s2/Accordion.mdx
+++ b/packages/dev/s2-docs/pages/s2/Accordion.mdx
@@ -11,28 +11,28 @@ export const tags = ['collapsible', 'expandable', 'disclosure'];
```tsx render docs={docs.exports.Accordion} links={docs.links} props={['size', 'density', 'isQuiet', 'isDisabled', 'allowsMultipleExpanded']} type="s2"
"use client";
-import {Accordion, Disclosure, DisclosureTitle, DisclosurePanel} from '@react-spectrum/s2';
+import {Accordion, AccordionItem, AccordionItemTitle, AccordionItemPanel} from '@react-spectrum/s2';
import {style} from '@react-spectrum/s2/style' with {type: 'macro'};
-
- Personal Information
- Personal information form here.
-
-
- Billing Address
- Billing address form here.
-
+
+ Personal Information
+ Personal information form here.
+
+
+ Billing Address
+ Billing address form here.
+
```
## Expanding
-Use the `defaultExpandedKeys` or `expandedKeys` prop to set the expanded items, and `onExpandedChange` to handle user interactions. The expanded keys correspond to the `id` prop of each ``.
+Use the `defaultExpandedKeys` or `expandedKeys` prop to set the expanded items, and `onExpandedChange` to handle user interactions. The expanded keys correspond to the `id` prop of each ``.
```tsx render
"use client";
-import {Accordion, Disclosure, DisclosureTitle, DisclosurePanel, type Key} from '@react-spectrum/s2';
+import {Accordion, AccordionItem, AccordionItemTitle, AccordionItemPanel, type Key} from '@react-spectrum/s2';
import {useState} from 'react';
function Example() {
@@ -44,31 +44,80 @@ function Example() {
expandedKeys={expandedKeys}
onExpandedChange={setExpandedKeys}>
{/*- end highlight -*/}
-
- Settings
- Application settings content
-
-
- Preferences
- User preferences content
-
-
- Advanced
- Advanced configuration options
-
+
+ Settings
+ Application settings content
+
+
+ Preferences
+ User preferences content
+
+
+ Advanced
+ Advanced configuration options
+
);
}
```
+## Content
+
+Use `AccordionItemHeader` to add additional elements alongside the title, such as action buttons or icons.
+
+```tsx render
+"use client";
+import {Accordion, AccordionItem, AccordionItemTitle, AccordionItemPanel, AccordionItemHeader, ActionButton} from '@react-spectrum/s2';
+import {style} from '@react-spectrum/s2/style' with {type: 'macro'};
+
+
+
+ {/*- begin highlight -*/}
+
+ Project Settings
+ Edit
+
+ {/*- end highlight -*/}
+
+ Configure your project settings including name, description, and permissions.
+
+
+
+ Preferences
+ User preferences content
+
+
+```
+
## API
-```tsx links={{Accordion: '#accordion', Disclosure: 'Disclosure.html'}}
+```tsx links={{Accordion: '#accordion', AccordionItem: '#accordionitem', AccordionItemHeader: '#accordionitemheader', AccordionItemTitle: '#accordionitemtitle', AccordionItemPanel: '#accordionitempanel'}}
-
+
+
+
+
+
+
```
### Accordion
+
+### AccordionItem
+
+
+
+### AccordionItemHeader
+
+
+
+### AccordionItemTitle
+
+
+
+### AccordionItemPanel
+
+
diff --git a/packages/dev/s2-docs/pages/s2/Menu.mdx b/packages/dev/s2-docs/pages/s2/Menu.mdx
index 52a030e27bb..1c7e7407e6f 100644
--- a/packages/dev/s2-docs/pages/s2/Menu.mdx
+++ b/packages/dev/s2-docs/pages/s2/Menu.mdx
@@ -222,7 +222,7 @@ Wrap a `` and a `` with a `` to create a submenu
```tsx render
"use client";
-import {Menu, MenuTrigger, MenuItem, SubmenuTrigger, Popover, ActionButton} from '@react-spectrum/s2';
+import {Menu, MenuTrigger, MenuItem, SubmenuTrigger, ActionButton} from '@react-spectrum/s2';
Actions
@@ -233,14 +233,12 @@ import {Menu, MenuTrigger, MenuItem, SubmenuTrigger, Popover, ActionButton} from
{/*- begin highlight -*/}
Share
-
{/*- end highlight -*/}
Email
SMS
Copy Link
-
diff --git a/packages/dev/s2-docs/pages/s2/releases/index.mdx b/packages/dev/s2-docs/pages/s2/releases/index.mdx
index 65e91946075..873bffb49a0 100644
--- a/packages/dev/s2-docs/pages/s2/releases/index.mdx
+++ b/packages/dev/s2-docs/pages/s2/releases/index.mdx
@@ -8,7 +8,7 @@ OF ANY KIND, either express or implied. See the License for the specific languag
governing permissions and limitations under the License. */}
import {Layout} from '../../../src/Layout';
-import {ReleasesList} from '../../../src/ReleasesList';
+import {PostList} from '../../../src/PostList';
export default Layout;
export const hideNav = true;
@@ -16,7 +16,10 @@ export const section = 'Releases';
export const tags = ['changelog', 'versions', 'updates'];
export const title = 'Releases';
export const hideFromSearch = true;
+export const isPostList = true;
# Releases
- page.name.includes('s2') && page.name.includes('releases') && !page.name.includes('index.html')) ?? []} />
+ page.name.includes('s2') && page.name.includes('releases') && !page.name.includes('index.html')) ?? []} />
+
+For all previous releases of React Spectrum v3, see the [Archived releases](https://react-spectrum.adobe.com/releases/index.html) page.
diff --git a/packages/dev/s2-docs/pages/s2/releases/v0-1-0.mdx b/packages/dev/s2-docs/pages/s2/releases/v0-1-0.mdx
index 015c5413369..f513ec44fa5 100644
--- a/packages/dev/s2-docs/pages/s2/releases/v0-1-0.mdx
+++ b/packages/dev/s2-docs/pages/s2/releases/v0-1-0.mdx
@@ -11,7 +11,6 @@ import {Layout} from '../../../src/Layout';
export default Layout;
import docs from 'docs:@react-spectrum/s2';
-import {Time} from '../../../src/ReleasesList';
export const hideNav = true;
export const section = 'Releases';
@@ -22,7 +21,6 @@ export const description = 'Version 0.1.0 introduces the first version of Spectr
export const isSubpage = true;
# v0.1.0
-
Version 0.1.0 introduces the first version of Spectrum 2, including new Badge, ComboBox, Meter, and Picker components.
diff --git a/packages/dev/s2-docs/pages/s2/releases/v0-10-0.mdx b/packages/dev/s2-docs/pages/s2/releases/v0-10-0.mdx
index 5ea8ead3d99..8686f8b7549 100644
--- a/packages/dev/s2-docs/pages/s2/releases/v0-10-0.mdx
+++ b/packages/dev/s2-docs/pages/s2/releases/v0-10-0.mdx
@@ -11,7 +11,6 @@ import {Layout} from '../../../src/Layout';
export default Layout;
import docs from 'docs:@react-spectrum/s2';
-import {Time} from '../../../src/ReleasesList';
export const hideNav = true;
export const section = 'Releases';
@@ -22,7 +21,6 @@ export const description = 'Version 0.10.0 introduces a new font for Spectrum 2:
export const isSubpage = true;
# v0.10.0
-
Version 0.10.0 introduces a new font for Spectrum 2: Adobe Clean Spectrum VF, along with new date and time components including Calendar, DatePicker, DateRangePicker, and TimeField. This release also includes various component improvements and bug fixes.
diff --git a/packages/dev/s2-docs/pages/s2/releases/v0-11-0.mdx b/packages/dev/s2-docs/pages/s2/releases/v0-11-0.mdx
index 4ba1ada5fff..2bb4bcddf3f 100644
--- a/packages/dev/s2-docs/pages/s2/releases/v0-11-0.mdx
+++ b/packages/dev/s2-docs/pages/s2/releases/v0-11-0.mdx
@@ -11,7 +11,6 @@ import {Layout} from '../../../src/Layout';
export default Layout;
import docs from 'docs:@react-spectrum/s2';
-import {Time} from '../../../src/ReleasesList';
export const hideNav = true;
export const section = 'Releases';
@@ -22,7 +21,6 @@ export const description = 'Version 0.11.0 introduces the new SelectBoxGroup com
export const isSubpage = true;
# v0.11.0
-
Version 0.11.0 introduces the new SelectBoxGroup component (alpha), fixes ComboBox empty state rendering, improves Picker dropdown styling, and adds support for custom tab layouts with collapse behavior.
diff --git a/packages/dev/s2-docs/pages/s2/releases/v0-12-0.mdx b/packages/dev/s2-docs/pages/s2/releases/v0-12-0.mdx
index e60e7382390..f1042a3b3c2 100644
--- a/packages/dev/s2-docs/pages/s2/releases/v0-12-0.mdx
+++ b/packages/dev/s2-docs/pages/s2/releases/v0-12-0.mdx
@@ -11,7 +11,6 @@ import {Layout} from '../../../src/Layout';
export default Layout;
import docs from 'docs:@react-spectrum/s2';
-import {Time} from '../../../src/ReleasesList';
export const hideNav = true;
export const section = 'Releases';
@@ -22,7 +21,6 @@ export const description = 'Version 0.12.0 adds pending states to ActionButton,
export const isSubpage = true;
# v0.12.0
-
Version 0.12.0 adds pending states to ActionButton, avatar support in ComboBox and Picker, Dialog XL size, and Popover styling improvements. This release also includes RTL fixes, placeholder support across components, and various component enhancements.
diff --git a/packages/dev/s2-docs/pages/s2/releases/v0-2-0.mdx b/packages/dev/s2-docs/pages/s2/releases/v0-2-0.mdx
index bf5d31a257a..c578643685e 100644
--- a/packages/dev/s2-docs/pages/s2/releases/v0-2-0.mdx
+++ b/packages/dev/s2-docs/pages/s2/releases/v0-2-0.mdx
@@ -11,7 +11,6 @@ import {Layout} from '../../../src/Layout';
export default Layout;
import docs from 'docs:@react-spectrum/s2';
-import {Time} from '../../../src/ReleasesList';
export const hideNav = true;
export const section = 'Releases';
@@ -22,7 +21,6 @@ export const description = 'Version 0.2.0 introduces new color and range compone
export const isSubpage = true;
# v0.2.0
-
Version 0.2.0 introduces new color and range components, adds ESBuild starter, updates InlineAlert iconography, and includes CSS processing updates.
diff --git a/packages/dev/s2-docs/pages/s2/releases/v0-3-0.mdx b/packages/dev/s2-docs/pages/s2/releases/v0-3-0.mdx
index 720a482fbe2..f044a23d2ed 100644
--- a/packages/dev/s2-docs/pages/s2/releases/v0-3-0.mdx
+++ b/packages/dev/s2-docs/pages/s2/releases/v0-3-0.mdx
@@ -11,7 +11,6 @@ import {Layout} from '../../../src/Layout';
export default Layout;
import docs from 'docs:@react-spectrum/s2';
-import {Time} from '../../../src/ReleasesList';
export const hideNav = true;
export const section = 'Releases';
@@ -22,7 +21,6 @@ export const description = 'Version 0.3.0 introduces NumberField, AlertDialog, a
export const isSubpage = true;
# v0.3.0
-
Version 0.3.0 introduces NumberField, AlertDialog, and Tabs components, along with new linear and gradient illustrations. This release includes TagGroup enhancements, updated workflow icons with name changes, and comprehensive translations for all components.
diff --git a/packages/dev/s2-docs/pages/s2/releases/v0-4-0.mdx b/packages/dev/s2-docs/pages/s2/releases/v0-4-0.mdx
index f3375ae9eac..47abbc89185 100644
--- a/packages/dev/s2-docs/pages/s2/releases/v0-4-0.mdx
+++ b/packages/dev/s2-docs/pages/s2/releases/v0-4-0.mdx
@@ -11,7 +11,6 @@ import {Layout} from '../../../src/Layout';
export default Layout;
import docs from 'docs:@react-spectrum/s2';
-import {Time} from '../../../src/ReleasesList';
export const hideNav = true;
export const section = 'Releases';
@@ -22,7 +21,6 @@ export const description = 'Version 0.4.0 introduces six new components includin
export const isSubpage = true;
# v0.4.0
-
Version 0.4.0 introduces six new components including Accordion, Card, CardView, and TableView. This release includes ProgressBar and Badge enhancements, Button pending state support, and various component improvements.
diff --git a/packages/dev/s2-docs/pages/s2/releases/v0-5-0.mdx b/packages/dev/s2-docs/pages/s2/releases/v0-5-0.mdx
index abfc9cb9418..dc25844a51d 100644
--- a/packages/dev/s2-docs/pages/s2/releases/v0-5-0.mdx
+++ b/packages/dev/s2-docs/pages/s2/releases/v0-5-0.mdx
@@ -11,7 +11,6 @@ import {Layout} from '../../../src/Layout';
export default Layout;
import docs from 'docs:@react-spectrum/s2';
-import {Time} from '../../../src/ReleasesList';
export const hideNav = true;
export const section = 'Releases';
@@ -22,7 +21,6 @@ export const description = 'Version 0.5.0 includes major updates to Dialog and D
export const isSubpage = true;
# v0.5.0
-
Version 0.5.0 includes major updates to Dialog and DialogTrigger APIs with four new dialog components: Dialog, FullscreenDialog, CustomDialog, and Popover. This release also improves style macro documentation and adds support for arbitrary pixel sizing.
diff --git a/packages/dev/s2-docs/pages/s2/releases/v0-6-0.mdx b/packages/dev/s2-docs/pages/s2/releases/v0-6-0.mdx
index 3e093a32d82..4a515806d82 100644
--- a/packages/dev/s2-docs/pages/s2/releases/v0-6-0.mdx
+++ b/packages/dev/s2-docs/pages/s2/releases/v0-6-0.mdx
@@ -11,7 +11,6 @@ import {Layout} from '../../../src/Layout';
export default Layout;
import docs from 'docs:@react-spectrum/s2';
-import {Time} from '../../../src/ReleasesList';
export const hideNav = true;
export const section = 'Releases';
@@ -22,7 +21,6 @@ export const description = 'Version 0.6.0 introduces the ActionBar component and
export const isSubpage = true;
# v0.6.0
-
Version 0.6.0 introduces the ActionBar component and adds staticColor="auto" support to multiple components. This release includes Button gradient variants, Menu improvements, and various component fixes.
diff --git a/packages/dev/s2-docs/pages/s2/releases/v0-7-0.mdx b/packages/dev/s2-docs/pages/s2/releases/v0-7-0.mdx
index 2bae58416f1..a217db10d2c 100644
--- a/packages/dev/s2-docs/pages/s2/releases/v0-7-0.mdx
+++ b/packages/dev/s2-docs/pages/s2/releases/v0-7-0.mdx
@@ -11,7 +11,6 @@ import {Layout} from '../../../src/Layout';
export default Layout;
import docs from 'docs:@react-spectrum/s2';
-import {Time} from '../../../src/ReleasesList';
export const hideNav = true;
export const section = 'Releases';
@@ -22,7 +21,6 @@ export const description = 'Version 0.7.0 introduces the TreeView component and
export const isSubpage = true;
# v0.7.0
-
Version 0.7.0 introduces the TreeView component and includes important CSS updates to fix Safari issues. This release removes all: revert-layer from the style macro and includes Badge improvements, Tabs collapse behavior, and updated codemods.
diff --git a/packages/dev/s2-docs/pages/s2/releases/v0-8-0.mdx b/packages/dev/s2-docs/pages/s2/releases/v0-8-0.mdx
index 6c6e2f1d760..39b489c501d 100644
--- a/packages/dev/s2-docs/pages/s2/releases/v0-8-0.mdx
+++ b/packages/dev/s2-docs/pages/s2/releases/v0-8-0.mdx
@@ -11,7 +11,6 @@ import {Layout} from '../../../src/Layout';
export default Layout;
import docs from 'docs:@react-spectrum/s2';
-import {Time} from '../../../src/ReleasesList';
export const hideNav = true;
export const section = 'Releases';
@@ -22,7 +21,6 @@ export const description = 'Version 0.8.0 introduces NotificationBadge and Toast
export const isSubpage = true;
# v0.8.0
-
Version 0.8.0 introduces NotificationBadge and Toast (alpha) components, along with updates to Disclosure design sizing. This release also includes various component improvements and new exports.
diff --git a/packages/dev/s2-docs/pages/s2/releases/v0-9-0.mdx b/packages/dev/s2-docs/pages/s2/releases/v0-9-0.mdx
index 6403ec25b1e..f23615c2306 100644
--- a/packages/dev/s2-docs/pages/s2/releases/v0-9-0.mdx
+++ b/packages/dev/s2-docs/pages/s2/releases/v0-9-0.mdx
@@ -11,7 +11,6 @@ import {Layout} from '../../../src/Layout';
export default Layout;
import docs from 'docs:@react-spectrum/s2';
-import {Time} from '../../../src/ReleasesList';
export const hideNav = true;
export const section = 'Releases';
@@ -22,7 +21,6 @@ export const description = 'Version 0.9.0 adds virtualization and async loading
export const isSubpage = true;
# v0.9.0
-
Version 0.9.0 adds virtualization and async loading support to ComboBox and Picker, updates Dialog sizes, and introduces important TypeScript changes for UNSAFE_className. This release also includes significant style macro updates.
diff --git a/packages/dev/s2-docs/pages/s2/releases/v0-9-1.mdx b/packages/dev/s2-docs/pages/s2/releases/v0-9-1.mdx
index e1cd95ad9a0..28bee306148 100644
--- a/packages/dev/s2-docs/pages/s2/releases/v0-9-1.mdx
+++ b/packages/dev/s2-docs/pages/s2/releases/v0-9-1.mdx
@@ -11,7 +11,6 @@ import {Layout} from '../../../src/Layout';
export default Layout;
import docs from 'docs:@react-spectrum/s2';
-import {Time} from '../../../src/ReleasesList';
export const hideNav = true;
export const section = 'Releases';
@@ -22,7 +21,6 @@ export const description = 'Version 0.9.1 is a patch release that fixes focus vi
export const isSubpage = true;
# v0.9.1
-
Version 0.9.1 is a patch release that fixes focus visible styles in Button and TagGroup, updates ContextualHelp width, and improves Tabs selection indicator behavior.
diff --git a/packages/dev/s2-docs/src/BlogList.tsx b/packages/dev/s2-docs/src/BlogList.tsx
deleted file mode 100644
index 8dfbe64df0a..00000000000
--- a/packages/dev/s2-docs/src/BlogList.tsx
+++ /dev/null
@@ -1,41 +0,0 @@
-import {Link} from './Link';
-import type {Page} from '@parcel/rsc';
-import React from 'react';
-import {renderHTMLfromMarkdown} from './types';
-import {style} from '@react-spectrum/s2/style' with {type: 'macro'};
-
-export function BlogList({pages}: {pages: Page[]}) {
- let blogPosts = pages.sort((a, b) => {
- return new Date(b.exports?.date).getTime() - new Date(a.exports?.date).getTime();
- });
-
- return (
-
- {blogPosts.map(post => (
-
-
- {post.tableOfContents?.[0]?.title || post.exports?.title}
-
-
-
{renderHTMLfromMarkdown(post.exports?.description, {forceInline: true, forceBlock: false})}
-
- ))}
-
- );
-}
-
-export function Byline({author, authorLink, date}: {author?: string, authorLink?: string, date: string}) {
- let formattedDate = new Date(date).toLocaleDateString('en-US', {year: 'numeric', month: 'long', day: 'numeric'});
-
- return (
-
- {author && (
- <>
- By {authorLink ? {author} : author}
- {' · '}
- >
- )}
- {formattedDate}
-
- );
-}
diff --git a/packages/dev/s2-docs/src/Code.tsx b/packages/dev/s2-docs/src/Code.tsx
index 68852870fc8..38d6effd006 100644
--- a/packages/dev/s2-docs/src/Code.tsx
+++ b/packages/dev/s2-docs/src/Code.tsx
@@ -1,10 +1,12 @@
+import {CodeClient} from './CodeClient';
import {CodeFold} from './CodeFold';
import {CodeLink} from './Link';
import {CodeProps} from './VisualExampleClient';
import {HastNode, HastTextNode, highlightHast, Language} from 'tree-sitter-highlight';
-import React, {ReactNode} from 'react';
+import React, {cache} from 'react';
import {style, StyleString} from '@react-spectrum/s2/style' with {type: 'macro'};
import {TabLink} from './FileTabs';
+import {Token, TokenType} from './CodeToken';
const property = style({color: 'indigo-1000'});
const fn = style({color: 'red-1000'});
@@ -36,14 +38,18 @@ const mark = style({
color: 'inherit'
});
-function Highlight({children}) {
- return {children} ;
+function Highlight({tokens}) {
+ return ;
+}
+
+function Focus({tokens}) {
+ return ;
}
const groupings = {
highlight: Highlight,
collapse: CodeFold,
- focus: 'span'
+ focus: Focus
};
type Links = {[name: string]: string};
@@ -57,65 +63,17 @@ export interface ICodeProps {
export function Code({children, lang, hideImports = true, links, styles}: ICodeProps) {
if (lang) {
- // @ts-ignore
- let highlighted = highlightHast(children, Language[lang === 'json' ? 'JS' : lang.toUpperCase()]);
- let lineNodes = lines(highlighted);
- let idx = lineNodes.findIndex(line => !/^(["']use client["']|(\s*$))/.test(text(line)));
- if (idx > 0) {
- lineNodes = lineNodes.slice(idx);
- }
-
- if (hideImports) {
- // Group into hidden and visible nodes.
- // Hidden nodes will include all import statements. If a highlighted block is seen,
- // then we'll hide all the lines up until 2 lines before this.
- let hidden: HastNode[] = [];
- let visible: HastNode[] = [];
- let seenNonImportLine = false;
- let hasHighlight = false;
- for (let line of lineNodes) {
- if (!seenNonImportLine && /^(["']use client["']|@?import|(\s*$))/.test(text(line))) {
- hidden.push(line);
- } else {
- seenNonImportLine = true;
- visible.push(line);
- }
-
- if ((line.tagName === 'highlight' || line.tagName === 'focus') && !hasHighlight) {
- hasHighlight = true;
- // Center highlighted lines within collapsed window (~8 lines).
- let highlightedLines = line.children.length;
- let contextLines = highlightedLines < 6
- ? Math.floor((8 - highlightedLines) / 2)
- : 2;
- contextLines++;
- hidden.push(...visible.slice(0, -contextLines));
- visible = visible.slice(-contextLines);
- }
- }
-
- if (hidden.length && visible.length) {
- lineNodes = [
- {
- type: 'element',
- tagName: 'span',
- children: hidden,
- properties: {
- className: 'import'
- }
- },
- ...visible
- ];
- }
- }
-
- return {renderChildren(lineNodes, '0', links)};
+ return (
+
+
+
+ );
}
return (
{
+ // @ts-ignore
+ let highlighted = highlightHast(children, Language[lang === 'json' ? 'JS' : lang.toUpperCase()]);
+ let lineNodes = lines(highlighted);
+ let idx = lineNodes.findIndex(line => !/^(["']use client["']|(\s*$))/.test(text(line)));
+ if (idx > 0) {
+ lineNodes = lineNodes.slice(idx);
+ }
+
+ if (hideImports) {
+ // Group into hidden and visible nodes.
+ // Hidden nodes will include all import statements. If a highlighted block is seen,
+ // then we'll hide all the lines up until 2 lines before this.
+ let hidden: HastNode[] = [];
+ let visible: HastNode[] = [];
+ let seenNonImportLine = false;
+ let hasHighlight = false;
+ for (let line of lineNodes) {
+ if (!seenNonImportLine && /^(["']use client["']|@?import|(\s*$))/.test(text(line))) {
+ hidden.push(line);
+ } else {
+ seenNonImportLine = true;
+ visible.push(line);
+ }
+
+ if ((line.tagName === 'highlight' || line.tagName === 'focus') && !hasHighlight) {
+ hasHighlight = true;
+ // Center highlighted lines within collapsed window (~8 lines).
+ let highlightedLines = line.children.length;
+ let contextLines = highlightedLines < 6
+ ? Math.floor((8 - highlightedLines) / 2)
+ : 2;
+ contextLines++;
+ hidden.push(...visible.slice(0, -contextLines));
+ visible = visible.slice(-contextLines);
+ }
+ }
+
+ if (hidden.length && visible.length) {
+ lineNodes = [
+ {
+ type: 'element',
+ tagName: 'span',
+ children: hidden,
+ properties: {
+ className: 'import'
+ }
+ },
+ ...visible
+ ];
+ }
+ }
+
+ return renderChildren(lineNodes, '0', links);
+});
+
function lines(node: HastNode) {
let resultLines: HastNode[] = [];
let currentLine: (HastNode | HastTextNode)[] = [];
@@ -210,47 +224,57 @@ function lines(node: HastNode) {
return resultLines;
}
-function renderHast(node: HastNode | HastTextNode, key: string, links?: Links, indent = ''): ReactNode {
+// Renders a Hast Node to a list of tokens. A token is either a string, a React element, or a token type (number) + string.
+// These are flattened into an array that gets sent to the client. This format significantly reduces the payload size vs JSX.
+function renderHast(node: HastNode | HastTextNode, key: string, links?: Links, indent = ''): Token | Token[] {
if (node.type === 'element' && 'children' in node) {
- let childArray: ReactNode[] = renderChildren(node.children, key, links);
+ let childArray: Token[] = renderChildren(node.children, key, links);
if (node.tagName === 'div') {
- if (typeof childArray.at(-1) === 'string') {
+ if (typeof childArray.at(-1) === 'string' && typeof childArray.at(-2) !== 'number') {
childArray[childArray.length - 1] += '\n';
} else {
childArray.push('\n');
}
}
- let children = childArray.length === 1 ? childArray[0] : childArray;
- let className = node.properties?.className.split(' ').map(c => styles[c]).filter(Boolean).join(' ') || undefined;
+ let tokenType = node.properties?.className.split(' ').map(c => TokenType[c]).filter(v => v != null) || [];
if (node.properties?.className === 'comment' && text(node) === '/* PROPS */') {
return ;
}
// CodeProps includes the indent and newlines in case there are no props to show.
if (node.tagName === 'div' && typeof childArray[0] === 'string' && /^\s+$/.test(childArray[0]) && React.isValidElement(childArray[1]) && childArray[1].type === CodeProps) {
- children = childArray.slice(1);
+ childArray = childArray.slice(1);
}
+ let children = childArray.length === 1 ? childArray[0] : childArray;
let tagName: any = node.tagName;
let properties: any = node.properties;
if (links && typeof children === 'string' && links[children]) {
let link = links[children];
- tagName = CodeLink;
- properties = {...properties, href: link};
+ return (
+
+ {children}
+
+ );
}
// Link to imported files.
if (properties?.className === 'string' && typeof children === 'string' && /^['"]\.\//.test(children)) {
- tagName = TabLink;
- properties = {...properties, name: children.slice(3, -1)};
+ return (
+
+
+
+ );
}
- if (tagName === 'span' && !className) {
- return children;
- }
-
- if (tagName === 'div' && !className) {
+ if ((tagName === 'div' || tagName === 'span') && tokenType.length === 0) {
return children;
}
@@ -260,24 +284,56 @@ function renderHast(node: HastNode | HastTextNode, key: string, links?: Links, i
type = 'span';
}
- return React.createElement(type, {...properties, className, key}, children);
+ if (type === 'span') {
+ return [tokenType[0], children];
+ }
+
+ let className = node.properties?.className.split(' ').map(c => styles[c]).filter(Boolean).join(' ') || undefined;
+ return React.createElement(type, {...properties, className, key, tokens: childArray});
} else {
// @ts-ignore
return node.value;
}
}
-function renderChildren(children: (HastNode | HastTextNode)[], key: string, links?: Links) {
- let childArray: ReactNode[] = [];
+function renderChildren(children: (HastNode | HastTextNode)[], key: string, links?: Links): Token[] {
+ let childArray: Token[] = [];
+ let type = -1;
+ let stringIndex = -1;
for (let [i, child] of children.entries()) {
- let indent = i === 1 && typeof childArray[0] === 'string' && /^\s+$/.test(childArray[0]) ? childArray[0] : '';
+ let indent = i === 1 && stringIndex >= 0 && /^\s+$/.test(childArray[stringIndex] as string) ? childArray[stringIndex] as string : '';
let childNode = renderHast(child, `${key}.${i}`, links, indent);
let childNodes = Array.isArray(childNode) ? childNode : [childNode];
- for (let childNode of childNodes) {
- if (typeof childNode === 'string' && typeof childArray.at(-1) === 'string') {
- childArray[childArray.length - 1] += childNode;
+ let childIndex = 0;
+ while (childIndex < childNodes.length) {
+ let child = childNodes[childIndex++];
+ let childType = -1;
+ if (typeof child === 'number') {
+ // A number represents a token type. Consume the next value.
+ childType = child;
+ child = childNodes[childIndex++];
+ if (childType !== type) {
+ childArray.push(childType);
+ }
+ }
+
+ // If this is a string, either append to the previous string if it is
+ // the same token type, or push a new string.
+ if (typeof child === 'string') {
+ if (childType !== type) {
+ type = childType;
+ stringIndex = childArray.length;
+ childArray.push(child);
+ } else if (stringIndex >= 0) {
+ childArray[stringIndex] += child;
+ } else {
+ stringIndex = childArray.length;
+ childArray.push(child);
+ }
} else {
- childArray.push(childNode);
+ type = -1;
+ stringIndex = -1;
+ childArray.push(child);
}
}
}
diff --git a/packages/dev/s2-docs/src/CodeBlock.tsx b/packages/dev/s2-docs/src/CodeBlock.tsx
index 4e7973e1a2b..918f4d32a95 100644
--- a/packages/dev/s2-docs/src/CodeBlock.tsx
+++ b/packages/dev/s2-docs/src/CodeBlock.tsx
@@ -23,7 +23,9 @@ const example = style({
padding: {
default: 12,
lg: 24
- }
+ },
+ maxWidth: '--text-width',
+ marginX: 'auto'
});
const standaloneCode = style({
@@ -49,7 +51,9 @@ const standaloneCode = style({
default: 'code-xs',
lg: 'code-sm'
},
- overflow: 'auto'
+ overflow: 'auto',
+ maxWidth: '--text-width',
+ marginX: 'auto'
});
interface CodeBlockProps extends VisualExampleProps {
@@ -132,7 +136,7 @@ export function CodeBlockBase({children, lang}: {children: string, lang: string}
let highlighted = highlight(children, Language[lang.toUpperCase()]);
return (
-
+
);
}
@@ -164,7 +168,7 @@ function TruncatedCode({children, maxLines = 6, ...props}: TruncatedCodeProps) {
interface FilesProps {
children?: ReactNode,
files: string[],
- downloadFiles?: {[name: string]: string},
+ downloadFiles?: DownloadFiles['files'],
type?: 'vanilla' | 'tailwind' | 's2',
defaultSelected?: string,
maxLines?: number
@@ -182,7 +186,7 @@ export function Files({children, files, downloadFiles, type, defaultSelected, ma
if (!files[name]) {
extraFiles[name] = (
- {downloadFiles[name]}
+ {downloadFiles[name].contents}
);
}
@@ -213,21 +217,25 @@ export function File({filename, maxLines, type}: {filename: string, maxLines?: n
);
}
+const readFileReplace = cache((file: string) => {
+ let contents = readFile(file)
+ .replace(/(vanilla-starter|tailwind-starter)\//g, './')
+ .replace(/import (.*?) from ['"]url:(.*?)['"]/g, (_, name, specifier) => {
+ return `const ${name} = '${resolveUrl(specifier, file)}'`;
+ });
+ return {contents};
+});
+
// Reads files, parses imports, and loads recursively.
-export function getFiles(files: string[], type: string | undefined, npmDeps = {}) {
- let fileContents = {};
+export function getFiles(files: string[], type: string | undefined, npmDeps = {}): DownloadFiles {
+ let fileContents: DownloadFiles['files'] = {};
for (let file of findAllFiles(files, npmDeps)) {
let name = path.basename(file);
- let contents = readFile(file);
- fileContents[name] = contents
- .replace(/(vanilla-starter|tailwind-starter)\//g, './')
- .replace(/import (.*?) from ['"]url:(.*?)['"]/g, (_, name, specifier) => {
- return `const ${name} = '${resolveUrl(specifier, file)}'`;
- });
+ fileContents[name] = readFileReplace(file);
}
if (type === 'tailwind' && !fileContents['index.css']) {
- fileContents['index.css'] = readFile(path.resolve('../../../starters/tailwind/src/index.css'));
+ fileContents['index.css'] = readFileReplace(path.resolve('../../../starters/tailwind/src/index.css'));
}
return {files: fileContents, deps: npmDeps};
@@ -286,7 +294,19 @@ function parseFile(file: string, contents: string, npmDeps = {}, urls = {}) {
return deps;
}
-function getExampleFiles(file: string, contents: string, type: string | undefined) {
+export interface DownloadFiles {
+ files: {
+ [name: string]: {contents: string}
+ },
+ deps: {
+ [name: string]: string
+ },
+ urls?: {
+ [url: string]: string
+ }
+}
+
+function getExampleFiles(file: string, contents: string, type: string | undefined): DownloadFiles {
let npmDeps = {};
let urls = {};
let fileDeps = parseFile(file, contents, npmDeps, urls);
diff --git a/packages/dev/s2-docs/src/CodeClient.tsx b/packages/dev/s2-docs/src/CodeClient.tsx
new file mode 100644
index 00000000000..918ab700911
--- /dev/null
+++ b/packages/dev/s2-docs/src/CodeClient.tsx
@@ -0,0 +1,41 @@
+'use client';
+import {ReactNode} from 'react';
+import {style} from '@react-spectrum/s2/style' with {type: 'macro'};
+import {Token} from './CodeToken';
+
+const styles = [
+ style({color: 'magenta-1000'}), // keyword
+ style({color: 'green-1000'}), // string
+ style({color: 'pink-1000'}), // number
+ style({color: 'indigo-1000'}), // property
+ style({color: 'red-1000'}), // function
+ style({color: 'gray-700'}), // comment
+ style({color: 'fuchsia-1000'}), // variable
+ style({display: '--import-display'}) // import
+];
+
+interface CodeClientProps {
+ tokens: Token[]
+}
+
+export function CodeClient({tokens}: CodeClientProps) {
+ let i = 0;
+ let children: ReactNode[] = [];
+ while (i < tokens.length) {
+ let value = tokens[i++];
+ if (typeof value === 'number') {
+ // A number represents a token type. The following value is its children.
+ let type = value;
+ value = tokens[i++];
+ let child = Array.isArray(value) ? : value;
+ children.push({child} );
+ } else if (Array.isArray(value)) {
+ // A nested array of tokens.
+ children.push( );
+ } else {
+ children.push(value);
+ }
+ }
+
+ return children;
+}
diff --git a/packages/dev/s2-docs/src/CodeFold.tsx b/packages/dev/s2-docs/src/CodeFold.tsx
index befa0424a86..9f4e1d2ef98 100644
--- a/packages/dev/s2-docs/src/CodeFold.tsx
+++ b/packages/dev/s2-docs/src/CodeFold.tsx
@@ -3,9 +3,11 @@
import {baseColor, focusRing, space, style} from '@react-spectrum/s2/style' with {type: 'macro'};
import {Button, Disclosure, DisclosurePanel} from 'react-aria-components';
import Chevron from '../../../@react-spectrum/s2/ui-icons/Chevron';
+import {CodeClient} from './CodeClient';
import More from '@react-spectrum/s2/icons/More';
import {pressScale} from '@react-spectrum/s2';
-import {ReactNode, useMemo, useRef} from 'react';
+import {Token} from './CodeToken';
+import {useMemo, useRef} from 'react';
const trigger = style({
...focusRing(),
@@ -16,7 +18,8 @@ const trigger = style({
borderStyle: 'none',
whiteSpace: 'inherit',
fontFamily: 'inherit',
- fontSize: 'inherit'
+ fontSize: 'inherit',
+ color: 'inherit'
});
const chevronStyles = style({
@@ -51,26 +54,26 @@ const more = style({
}
});
-export function CodeFold({children}) {
+export function CodeFold({tokens}) {
let ref = useRef(null);
let [firstLine, collapsed, lastLine] = useMemo(() => {
- let firstLine: ReactNode[] = [];
- let collapsed: ReactNode[] = [];
- let lastLine: ReactNode[] = [];
+ let firstLine: Token[] = [];
+ let collapsed: Token[] = [];
+ let lastLine: Token[] = [];
// Iterate forward to find the first newline.
- for (let [i, child] of children.entries()) {
+ for (let [i, child] of tokens.entries()) {
if (typeof child === 'string') {
let index = child.indexOf('\n');
if (index === 0) {
- collapsed = children.slice(i);
+ collapsed = tokens.slice(i);
break;
} else if (index > 0) {
firstLine.push(child.slice(0, index));
if (index < child.length) {
collapsed.push(child.slice(index));
}
- collapsed.push(...children.slice(i + 1));
+ collapsed.push(...tokens.slice(i + 1));
break;
}
}
@@ -108,7 +111,7 @@ export function CodeFold({children}) {
}
return [firstLine, collapsed, lastLine];
- }, [children]);
+ }, [tokens]);
return (
@@ -118,12 +121,15 @@ export function CodeFold({children}) {
className={trigger}>
{({isHovered, isPressed, isFocusVisible}) => (<>
- {firstLine}{!isExpanded
- ? <> {lastLine}>
+
+ {!isExpanded
+ ? <> >
: null}
>)}
- {collapsed}
+
+
+
>)}
);
diff --git a/packages/dev/s2-docs/src/CodePlatter.tsx b/packages/dev/s2-docs/src/CodePlatter.tsx
index d9bf921bfe7..6c36048ff9c 100644
--- a/packages/dev/s2-docs/src/CodePlatter.tsx
+++ b/packages/dev/s2-docs/src/CodePlatter.tsx
@@ -5,6 +5,7 @@ import {CopyButton} from './CopyButton';
import {createCodeSandbox, getCodeSandboxFiles} from './CodeSandbox';
import {createStackBlitz} from './StackBlitz';
import Download from '@react-spectrum/s2/icons/Download';
+import type {DownloadFiles} from './CodeBlock';
import {keyframes} from '../../../@react-spectrum/s2/style/style-macro' with {type: 'macro'};
import {Library} from './library';
import LinkIcon from '@react-spectrum/s2/icons/Link';
@@ -49,10 +50,7 @@ export function CodePlatterProvider(props: CodePlatterContextValue & {children:
return {props.children} ;
}
-interface FileProviderContextValue {
- files?: {[name: string]: string},
- deps?: {[name: string]: string},
- urls?: {[url: string]: string},
+interface FileProviderContextValue extends DownloadFiles {
entry?: string
}
@@ -225,11 +223,11 @@ export function Pre({children}) {
);
}
-function getExampleFiles(codeRef: RefObject, files: {[name: string]: string}, urls: {[name: string]: string}, entry: string | undefined) {
+function getExampleFiles(codeRef: RefObject, files: DownloadFiles['files'], urls: {[name: string]: string}, entry: string | undefined): DownloadFiles['files'] {
if (!entry) {
return {
...files,
- 'Example.tsx': getExampleCode(codeRef, urls)
+ 'Example.tsx': {contents: getExampleCode(codeRef, urls)}
};
}
diff --git a/packages/dev/s2-docs/src/CodeSandbox.tsx b/packages/dev/s2-docs/src/CodeSandbox.tsx
index 9783bd0db39..1f7b32ce9cb 100644
--- a/packages/dev/s2-docs/src/CodeSandbox.tsx
+++ b/packages/dev/s2-docs/src/CodeSandbox.tsx
@@ -1,8 +1,9 @@
+import type {DownloadFiles} from './CodeBlock';
import LZString from 'lz-string';
export function createCodeSandbox(
- files: {[name: string]: string},
- deps: {[name: string]: string},
+ files: DownloadFiles['files'],
+ deps: DownloadFiles['deps'],
type: 'vanilla' | 'tailwind' | 's2' = 'vanilla',
entry: string = 'Example'
) {
@@ -65,8 +66,8 @@ const devDependencies = {
};
export function getCodeSandboxFiles(
- files: {[name: string]: string},
- deps: {[name: string]: string},
+ files: DownloadFiles['files'],
+ deps: DownloadFiles['deps'],
type: 'vanilla' | 'tailwind' | 's2' = 'vanilla',
entry: string = 'Example'
) {
@@ -164,6 +165,6 @@ createRoot(document.getElementById('root')!).render(<${entryName} />);
'include': ['src']
}, null, 2) + '\n'
},
- ...Object.fromEntries(Object.entries(files).map(([name, content]) => ['src/' + name, {content}]))
+ ...Object.fromEntries(Object.entries(files).map(([name, file]) => ['src/' + name, {content: file.contents}]))
};
}
diff --git a/packages/dev/s2-docs/src/CodeToken.ts b/packages/dev/s2-docs/src/CodeToken.ts
new file mode 100644
index 00000000000..e746a7100c4
--- /dev/null
+++ b/packages/dev/s2-docs/src/CodeToken.ts
@@ -0,0 +1,17 @@
+import {ReactElement} from 'react';
+
+export enum TokenType {
+ keyword = 0,
+ string = 1,
+ number = 2,
+ property = 3,
+ attribute = property,
+ function = 4,
+ tag = TokenType.function,
+ constructor = tag,
+ comment = 5,
+ variable = 6,
+ import = 7
+}
+
+export type Token = TokenType | string | ReactElement;
diff --git a/packages/dev/s2-docs/src/ComponentCardView.tsx b/packages/dev/s2-docs/src/ComponentCardView.tsx
index 1e860142961..48524833142 100644
--- a/packages/dev/s2-docs/src/ComponentCardView.tsx
+++ b/packages/dev/s2-docs/src/ComponentCardView.tsx
@@ -3,7 +3,7 @@
import {ComponentCard} from './ComponentCard';
import {InternalCardViewContext} from '../../../@react-spectrum/s2/src/Card';
import {Key, ListBox, ListBoxItem} from 'react-aria-components';
-import React from 'react';
+import React, {useCallback} from 'react';
import {style} from '@react-spectrum/s2/style' with {type: 'macro'};
export interface ComponentCardItem {
@@ -17,17 +17,29 @@ interface ComponentCardGridProps {
items: ComponentCardItem[],
ariaLabel?: string,
size?: 'S' | 'M' | 'L',
+ currentUrl?: string,
onAction?: (key: Key) => void,
renderEmptyState?: () => React.ReactNode
}
-export function ComponentCardView({items, ariaLabel = 'Items', size = 'S', onAction, renderEmptyState}: ComponentCardGridProps) {
+export function ComponentCardView({items, ariaLabel = 'Items', size = 'S', currentUrl, onAction, renderEmptyState}: ComponentCardGridProps) {
return (
{
+ if (el && currentUrl) {
+ // Wait for extra collection render.
+ requestAnimationFrame(() => {
+ let link = el.querySelector(`[href="${CSS.escape(currentUrl)}"]`);
+ if (link) {
+ el.scrollTo({top: link.offsetTop - 8});
+ }
+ });
+ }
+ }, [currentUrl])}
className={style({
display: {
default: 'grid',
@@ -43,6 +55,7 @@ export function ComponentCardView({items, ariaLabel = 'Items', size = 'S', onAct
default: 12,
md: 16
},
+ scrollPadding: 8,
marginX: {
default: -12,
md: 0
@@ -55,7 +68,8 @@ export function ComponentCardView({items, ariaLabel = 'Items', size = 'S', onAct
isEmpty: 'center'
},
overflow: 'auto',
- flexGrow: 1
+ flexGrow: 1,
+ position: 'relative'
})}
renderEmptyState={renderEmptyState}
items={items}>
diff --git a/packages/dev/s2-docs/src/ExampleApp.tsx b/packages/dev/s2-docs/src/ExampleApp.tsx
index 3d813885942..c0a15ceca5f 100644
--- a/packages/dev/s2-docs/src/ExampleApp.tsx
+++ b/packages/dev/s2-docs/src/ExampleApp.tsx
@@ -13,7 +13,8 @@ export async function ExampleApp({dir, defaultSelected, type}: {dir: string, def
diff --git a/packages/dev/s2-docs/src/ExampleList.tsx b/packages/dev/s2-docs/src/ExampleList.tsx
index 6a4d34a2b02..0a4f99e02fd 100644
--- a/packages/dev/s2-docs/src/ExampleList.tsx
+++ b/packages/dev/s2-docs/src/ExampleList.tsx
@@ -35,6 +35,8 @@ export function ExampleList({tag, pages}) {
return (
@@ -85,7 +99,7 @@ export function ExampleImage({name}) {
-
+
);
}
diff --git a/packages/dev/s2-docs/src/Header.tsx b/packages/dev/s2-docs/src/Header.tsx
index 2e17a36d7fb..7c340e94b44 100644
--- a/packages/dev/s2-docs/src/Header.tsx
+++ b/packages/dev/s2-docs/src/Header.tsx
@@ -102,13 +102,6 @@ export default function Header(props: PageProps) {
});
};
- let handleActionButtonKeyDown = (e: React.KeyboardEvent) => {
- if (e.key === 'ArrowDown' && !searchOpen) {
- e.preventDefault();
- openSearchMenu();
- }
- };
-
let library = getLibraryFromPage(currentPage);
let subdirectory = 's2';
if (library === 'internationalized' || library === 'react-aria') {
@@ -148,11 +141,7 @@ export default function Header(props: PageProps) {
})}>
libraryStyles({...renderProps})}>
diff --git a/packages/dev/s2-docs/src/Headings.tsx b/packages/dev/s2-docs/src/Headings.tsx
index 92b1d0fc140..fbb54899562 100644
--- a/packages/dev/s2-docs/src/Headings.tsx
+++ b/packages/dev/s2-docs/src/Headings.tsx
@@ -1,5 +1,6 @@
'use client';
+import {getTextWidth} from './textWidth';
import {iconStyle, style} from '@react-spectrum/s2/style' with {type: 'macro'};
import {Link} from '@react-spectrum/s2';
import LinkIcon from '@react-spectrum/s2/icons/Link';
@@ -30,6 +31,7 @@ function AnchorLink({anchorId, isHovered, level, headingText}) {
+ {children}
+
+ );
+}
+
export function H2({children, ...props}) {
let {hoverProps, isHovered} = useHover({});
let id = anchorId(children);
return (
-
+
{children}
@@ -68,7 +98,7 @@ export function H3({children, ...props}) {
let {hoverProps, isHovered} = useHover({});
let id = anchorId(children);
return (
-
+
{children}
@@ -79,7 +109,7 @@ export function H4({children, ...props}) {
let {hoverProps, isHovered} = useHover({});
let id = anchorId(children);
return (
-
+
{children}
diff --git a/packages/dev/s2-docs/src/Layout.tsx b/packages/dev/s2-docs/src/Layout.tsx
index f4221173737..6960c8ab4f7 100644
--- a/packages/dev/s2-docs/src/Layout.tsx
+++ b/packages/dev/s2-docs/src/Layout.tsx
@@ -1,9 +1,9 @@
+import {Byline, Time} from './PostList';
import {ExampleList} from './ExampleList';
import {Nav} from '../src/Nav';
import {OptimisticMobileToc, OptimisticToc} from './OptimisticToc';
import type {Page, PageProps} from '@parcel/rsc';
-import React, {ReactElement} from 'react';
-// @ts-ignore
+import React, {ReactElement, ReactNode} from 'react';
import '../src/client';
// @ts-ignore
import internationalizedFavicon from 'url:../assets/internationalized.ico';
@@ -19,8 +19,7 @@ import {CodePlatterProvider} from './CodePlatter';
import {Divider, Provider, UNSTABLE_ToastContainer as ToastContainer} from '@react-spectrum/s2';
import {ExampleSwitcher} from './ExampleSwitcher';
import {getLibraryFromPage, getLibraryFromUrl, getLibraryLabel} from './library';
-import {getTextWidth} from './textWidth';
-import {H2, H3, H4} from './Headings';
+import {H1, H2, H3, H4} from './Headings';
import Header from './Header';
import {iconStyle, style} from '@react-spectrum/s2/style' with {type: 'macro'};
import {Link, TitleLink} from './Link';
@@ -32,31 +31,49 @@ import {TypeLink} from './types';
import {VersionBadge} from './VersionBadge';
import {VisualExample} from './VisualExample';
-const h1 = style({
- font: 'heading-3xl',
- fontSize: {
- // On mobile, adjust heading to fit in the viewport, and clamp between a min and max font size.
- default: 'clamp(35px, (100vw - 32px) / var(--width-per-em), 55px)',
- lg: 'heading-3xl'
+const p = style({
+ font: 'body-lg',
+ fontFamily: {
+ default: 'sans',
+ isLongForm: 'serif'
+ },
+ textWrap: 'pretty',
+ marginY: '[1lh]',
+ maxWidth: '--text-width',
+ marginX: 'auto'
+});
+
+const li = style({
+ font: 'body-lg',
+ fontFamily: {
+ default: 'sans',
+ isLongForm: 'serif'
+ },
+ textWrap: 'pretty',
+ marginY: {
+ default: 0,
+ isLongForm: 8
},
- marginY: 0
+ maxWidth: '--text-width',
+ marginX: 'auto'
});
-const components = {
- h1: ({children, ...props}) => {children} ,
+const components = (isLongForm?: boolean) => ({
+ // h1 is rendered separately
+ h1: () => null,
h2: H2,
h3: H3,
h4: H4,
- p: ({children, ...props}) => {children}
,
+ p: ({children, ...props}) => {children}
,
ul: (props) => ,
- li: ({children, ...props}) => {children} ,
+ li: ({children, ...props}) => {children} ,
Figure: (props) => ,
Caption: (props) => ,
CodeBlock: CodeBlock,
code: (props) => ,
strong: ({children, ...props}) => {children} ,
a: (props) => ,
- PageDescription: ({children, ...props}) => {children}
,
+ PageDescription: ({children, ...props}) => {children}
,
VisualExample,
Keyboard: (props) => ,
PropTable,
@@ -65,19 +82,6 @@ const components = {
ExampleSwitcher,
TypeLink,
ExampleList
-};
-
-const subPageComponents = (previousPage?: Page) => ({
- ...components,
- h1: ({children, ...props}) => (
-
-
- {previousPage?.exports?.title}
-
-
-
{children}
-
- )
});
const getTitle = (currentPage: Page): string => {
@@ -131,11 +135,21 @@ const getFaviconUrl = (currentPage: Page): string => {
let articleStyles = style({
maxWidth: {
- default: 'none',
- isWithToC: 768
+ default: 768,
+ isWide: 'none',
+ isLongForm: 900
},
+ marginX: 'auto',
width: 'full',
- height: 'fit'
+ height: 'fit',
+ flexGrow: 1,
+ '--text-width': {
+ type: 'width',
+ value: {
+ default: 'auto',
+ isLongForm: 600 // ~80 characters at body font size
+ }
+ }
});
function Footer() {
@@ -170,16 +184,21 @@ function Footer() {
export function Layout(props: PageProps & {children: ReactElement}) {
let {pages, currentPage, children} = props;
- let hasToC = !currentPage.exports?.hideNav && currentPage.tableOfContents?.[0]?.children && currentPage.tableOfContents?.[0]?.children?.length > 0;
+ let isSubpage = currentPage.exports?.isSubpage;
+ let section = currentPage.exports?.section;
+ let isLongForm = isSubpage && section === 'Blog';
+ let hasToC = (!currentPage.exports?.hideNav || section === 'Blog' || section === 'Releases') && currentPage.tableOfContents?.[0]?.children && currentPage.tableOfContents?.[0]?.children?.length > 0;
+ let isWide = !hasToC && !isLongForm && section !== 'Blog' && section !== 'Releases';
let library = getLibraryLabel(getLibraryFromPage(currentPage));
let keywords = [...new Set((currentPage.exports?.keywords ?? []).concat([library]).filter(k => !!k))];
let ogImage = getOgImageUrl(currentPage);
let title = getTitle(currentPage);
let description = getDescription(currentPage);
- let isSubpage = currentPage.exports?.isSubpage;
let parentPage = pages.find(p => {
return p.url === currentPage.url.replace(/\/[^/]+\.html$/, '/index.html');
});
+ let isPostList = currentPage.exports?.isPostList;
+ let Content = isPostList ? PostListContainer : Article;
return (
@@ -199,24 +218,6 @@ export function Layout(props: PageProps & {children: ReactElement}) {
-
}) {
alignItems: 'center',
maxWidth: {
default: 'full',
- lg: 1280
+ lg: 1440
},
marginX: 'auto',
marginY: 0,
@@ -282,6 +283,10 @@ export function Layout(props: PageProps & {children: ReactElement}) {
flexGrow: 1,
display: 'flex',
justifyContent: 'space-between',
+ columnGap: {
+ default: 12,
+ lg: 40
+ },
position: 'relative',
height: {
lg: '[calc(100vh - 72px)]'
@@ -295,23 +300,17 @@ export function Layout(props: PageProps & {children: ReactElement}) {
display: 'flex',
flexDirection: 'column',
flexGrow: 1,
+ minWidth: 0,
width: 'full'
})}>
-
- {currentPage.exports?.version && }
+
{React.cloneElement(children, {
- components: isSubpage ?
- subPageComponents(parentPage) :
- components,
+ components: components(isLongForm),
pages
})}
- {currentPage.exports?.relatedPages && (
-
- )}
-
+
@@ -320,12 +319,8 @@ export function Layout(props: PageProps & {children: ReactElement}) {
className={style({
position: 'sticky',
top: 0,
- height: {
- default: 'fit',
- lg: '[calc(100vh - 72px)]'
- },
- paddingY: 32,
- paddingX: 4,
+ paddingTop: 32,
+ marginBottom: -40,
boxSizing: 'border-box',
width: 180,
flexShrink: 0,
@@ -346,11 +341,75 @@ export function Layout(props: PageProps & {children: ReactElement}) {
);
}
-function MobileRelatedPages({pages}: {pages: Array<{title: string, url: string}>}) {
- const P = components.p;
- const Li = components.li;
- const Ul = components.ul;
+interface ArticleProps {
+ page: Page,
+ parentPage?: Page,
+ children: ReactNode,
+ isLongForm?: boolean,
+ isWide?: boolean
+}
+
+function Article({page, parentPage, children, isLongForm, isWide}: ArticleProps) {
+ let section = page.exports?.section;
+ return (
+
+
+
+
+
+
+
+
+ {page.exports?.version && }
+ {page.exports?.isSubpage
+ ?
+ : page.tableOfContents?.[0].level === 1 && {page.tableOfContents?.[0].title}
+ }
+
+ {children}
+
+ {page.exports?.relatedPages && (
+
+ )}
+
+ );
+}
+
+function PostListContainer({page, children, isLongForm, isWide}: ArticleProps) {
+ return (
+
+ {page.tableOfContents?.[0].level === 1 &&
{page.tableOfContents?.[0].title} }
+ {children}
+
+ );
+}
+
+interface SubpageHeaderProps {
+ currentPage: Page,
+ parentPage?: Page,
+ isLongForm?: boolean
+}
+
+function SubpageHeader({currentPage, parentPage, isLongForm}: SubpageHeaderProps) {
+ return (
+
+
+ {parentPage?.exports?.title}
+
+
+
{currentPage.tableOfContents?.[0].title}
+ {currentPage.exports?.author &&
}
+ {currentPage.exports?.date && !currentPage.exports?.author &&
}
+
+ );
+}
+function MobileRelatedPages({pages}: {pages: Array<{title: string, url: string}>}) {
return (
}
})}>
Related pages
-
+
{pages.map((page, i) => (
-
-
-
- {page.title}
-
-
-
+
+
+ {page.title}
+
+
))}
-
+
);
}
-
-export function Time({date}: {date: string}) {
- let dateObj = new Date(date);
- return (
-
- {dateObj.toLocaleDateString('en-US', {year: 'numeric', month: 'long', day: 'numeric'})}
-
- );
-}
diff --git a/packages/dev/s2-docs/src/Link.tsx b/packages/dev/s2-docs/src/Link.tsx
index 53f77133cbe..2a99483483b 100644
--- a/packages/dev/s2-docs/src/Link.tsx
+++ b/packages/dev/s2-docs/src/Link.tsx
@@ -50,12 +50,7 @@ export function CodeLink(props: RACLinkProps) {
const titleLink = style({
...focusRing(),
- font: 'heading',
- fontSize: {
- // On mobile, adjust heading to fit in the viewport, and clamp between a min and max font size.
- default: 'clamp(35px, (100vw - 32px) / var(--width-per-em), 55px)',
- lg: 'heading'
- },
+ font: 'title',
marginY: 0,
color: {
default: 'heading',
diff --git a/packages/dev/s2-docs/src/MarkdownMenu.tsx b/packages/dev/s2-docs/src/MarkdownMenu.tsx
index b32798b561e..7391e0d5213 100644
--- a/packages/dev/s2-docs/src/MarkdownMenu.tsx
+++ b/packages/dev/s2-docs/src/MarkdownMenu.tsx
@@ -61,7 +61,7 @@ export function MarkdownMenu({url}: MarkdownMenuProps) {
{isCopied ? : }
Copy for LLM
-
+
diff --git a/packages/dev/s2-docs/src/MobileHeader.tsx b/packages/dev/s2-docs/src/MobileHeader.tsx
index b282ea81512..662dd678c2b 100644
--- a/packages/dev/s2-docs/src/MobileHeader.tsx
+++ b/packages/dev/s2-docs/src/MobileHeader.tsx
@@ -1,12 +1,13 @@
'use client';
-import {ActionButton, DialogTrigger} from '@react-spectrum/s2';
+import {ActionButton, DialogTrigger, pressScale} from '@react-spectrum/s2';
+import {focusRing, style} from '@react-spectrum/s2/style' with {type: 'macro'};
import {getLibraryFromPage} from './library';
import {keyframes} from '../../../@react-spectrum/s2/style/style-macro' with {type: 'macro'};
+import {Link} from 'react-aria-components';
import MenuHamburger from '@react-spectrum/s2/icons/MenuHamburger';
import {Modal} from '../../../@react-spectrum/s2/src/Modal';
import React, {CSSProperties, lazy, useEffect, useRef} from 'react';
-import {style} from '@react-spectrum/s2/style' with {type: 'macro'};
import {TAB_DEFS} from './constants';
const MobileSearchMenu = lazy(() => import('./SearchMenu').then(({MobileSearchMenu}) => ({default: MobileSearchMenu})));
@@ -20,6 +21,7 @@ let fadeOut = keyframes(`
100% {
opacity: 0;
transform: translateY(calc(-100% - 12px));
+ width: 0px;
}
`);
@@ -61,6 +63,7 @@ const animationRange = '24px 64px';
export function MobileHeader({toc, pages, currentPage}) {
let ref = useRef(null);
+ let linkRef = useRef(null);
useEffect(() => {
// Tiny polyfill for scroll driven animations.
@@ -81,8 +84,21 @@ export function MobileHeader({toc, pages, currentPage}) {
}
}, []);
- let currentLibrary = getLibraryFromPage(currentPage);
- let icon = TAB_DEFS[currentLibrary].icon;
+ let library = getLibraryFromPage(currentPage);
+ let icon = TAB_DEFS[library].icon;
+ let subdirectory = 's2';
+ if (library === 'internationalized' || library === 'react-aria') {
+ // the internationalized library has no homepage so i've chosen to route it to the react aria homepage
+ subdirectory = 'react-aria';
+ }
+
+ let homepage = '';
+ for (let page of pages) {
+ if (page.name.includes(subdirectory) && page.name.includes('index.html') && !page.name.includes('releases') && !page.name.includes('blog') && !page.name.includes('examples')) {
+ homepage = page.url;
+ break;
+ }
+ }
return (
-
- {icon}
-
+
- {TAB_DEFS[currentLibrary].label}
-
+ ...focusRing(),
+ display: 'flex',
+ alignItems: 'center',
+ width: 'fit',
+ gap: 12,
+ borderRadius: 'default',
+ textDecoration: 'none',
+ transition: 'default',
+ disableTapHighlight: true
+ })}>
+ {icon}
+
+ {TAB_DEFS[library].label}
+
+
{toc && (
import('./IconSearchView').then(({IconSearchVi
const stickySearchContainer = style({
width: 'full',
- position: 'sticky',
- top: 64,
- zIndex: 1,
- backgroundColor: 'layer-2',
display: 'flex',
flexDirection: 'column',
gap: 8,
- paddingTop: 8
+ paddingTop: 8,
+ flexShrink: 0,
+ overflow: 'auto'
});
function MobileTab(props: Omit
& {children: ReactNode}) {
@@ -204,10 +202,10 @@ function MobileTabPanel(props: Omit & {children: R
);
}
-export function MobileSearchMenu({pages, currentPage}: {pages: Page[], currentPage: Page}) {
+export function MobileSearchMenu({pages, currentPage, initialTag}: {pages: Page[], currentPage: Page, initialTag?: string}) {
return (
-
+
);
}
@@ -226,7 +224,7 @@ const MobileCustomDialog = function MobileCustomDialog(props: MobileDialogProps)
);
};
-function MobileNav({pages, currentPage}: {pages: Page[], currentPage: Page}) {
+function MobileNav({pages, currentPage, initialTag}: {pages: Page[], currentPage: Page, initialTag?: string}) {
let overlayTriggerState = useContext(OverlayTriggerStateContext);
let [searchFocused, setSearchFocused] = useState(false);
let [searchValue, setSearchValue] = useState('');
@@ -367,8 +365,8 @@ function MobileNav({pages, currentPage}: {pages: Page[], currentPage: Page}) {
const initialSelectedSection = useMemo(() => {
const section = currentPage.exports?.section;
const firstSection = currentLibrarySections[0]?.toLowerCase() || 'components';
- return section ? section.toLowerCase() : firstSection;
- }, [currentPage, currentLibrarySections]);
+ return initialTag || (section ? section.toLowerCase() : firstSection);
+ }, [initialTag, currentPage, currentLibrarySections]);
const resourceTags = useMemo(() => getResourceTags(selectedLibrary), [selectedLibrary]);
@@ -411,9 +409,10 @@ function MobileNav({pages, currentPage}: {pages: Page[], currentPage: Page}) {
}, [selectedSection, selectedLibrary, searchValue]);
return (
-
+
{
@@ -478,6 +477,7 @@ function MobileNav({pages, currentPage}: {pages: Page[], currentPage: Page}) {
) : (
{
setSearchValue('');
overlayTriggerState?.close();
diff --git a/packages/dev/s2-docs/src/NavigationSuspense.tsx b/packages/dev/s2-docs/src/NavigationSuspense.tsx
index f06d0c2d979..02aeb6869e2 100644
--- a/packages/dev/s2-docs/src/NavigationSuspense.tsx
+++ b/packages/dev/s2-docs/src/NavigationSuspense.tsx
@@ -90,7 +90,7 @@ export function getPageFromPathname(pages: Page[], pathname: string | null): Pag
return targetPage ?? null;
}
-function getPageInfo(pages: Page[], pathname: string | null): {title?: string, section?: string, hasToC?: boolean} {
+function getPageInfo(pages: Page[], pathname: string | null) {
const targetPage = getPageFromPathname(pages, pathname);
if (!targetPage) {
@@ -100,8 +100,11 @@ function getPageInfo(pages: Page[], pathname: string | null): {title?: string, s
const title = getPageTitle(targetPage);
const section = (targetPage.exports?.section as string) || 'Components';
const hasToC = !targetPage.exports?.hideNav && targetPage.tableOfContents?.[0]?.children && targetPage.tableOfContents?.[0]?.children?.length > 0;
-
- return {title, section, hasToC};
+ let isSubpage = targetPage.exports?.isSubpage;
+ let isLongForm = isSubpage && section === 'Blog';
+ let isWide = !hasToC && !isLongForm && section !== 'Blog' && section !== 'Releases';
+
+ return {title, section, hasToC, isLongForm, isWide};
}
function NavigationContent({children}: {children: React.ReactNode}) {
@@ -130,9 +133,9 @@ export function NavigationSuspense({children, pages}: {children: React.ReactNode
// Subscribe to get the latest targetPathname for skeleton page info
const snapshot = useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
const pageInfo = getPageInfo(pages, snapshot.pathname);
-
+
return (
- }>
+ }>
{children}
);
diff --git a/packages/dev/s2-docs/src/PageSkeleton.tsx b/packages/dev/s2-docs/src/PageSkeleton.tsx
index ba149d626a1..ea7db651320 100644
--- a/packages/dev/s2-docs/src/PageSkeleton.tsx
+++ b/packages/dev/s2-docs/src/PageSkeleton.tsx
@@ -8,30 +8,42 @@ import {style} from '@react-spectrum/s2/style' with {type: 'macro'};
const h1 = style({
font: 'heading-3xl',
fontSize: {
- // On mobile, adjust heading to fit in the viewport, and clamp between a min and max font size.
- default: 'clamp(35px, (100vw - 32px) / var(--width-per-em), 55px)',
- lg: 'heading-3xl'
+ default: {
+ // On mobile, adjust heading to fit in the viewport, and clamp between a min and max font size.
+ default: 'clamp(35px, (100vw - 32px) / var(--width-per-em), 55px)',
+ isLongForm: 'heading-xl'
+ },
+ lg: {
+ default: 'heading-3xl',
+ isLongForm: 'heading-2xl'
+ }
},
- marginY: 0
+ textWrap: 'balance',
+ marginY: 0,
+ maxWidth: '--text-width',
+ marginX: 'auto'
});
const skeletonPageDescription = style({
font: {default: 'body-lg', lg: 'body-xl'},
marginY: 24,
- width: '100%'
+ maxWidth: '--text-width',
+ marginX: 'auto'
});
const skeletonParagraph = style({
font: {default: 'body', lg: 'body-lg'},
- marginY: 24,
- width: '100%'
+ marginY: '[1lh]',
+ maxWidth: '--text-width',
+ marginX: 'auto'
});
const skeletonH2 = style({
font: 'heading-xl',
marginTop: 48,
- marginBottom: 16,
- width: '40%'
+ marginBottom: 24,
+ maxWidth: '--text-width',
+ marginX: 'auto'
});
function SkeletonVisualExample() {
@@ -61,26 +73,35 @@ function SkeletonVisualExample() {
const skeletonArticle = style({
maxWidth: {
- default: 'none',
- isWithToC: 768
+ default: 768,
+ isWide: 'none',
+ isLongForm: 900
},
+ marginX: 'auto',
width: 'full',
- height: 'fit'
+ height: 'fit',
+ '--text-width': {
+ type: 'width',
+ value: {
+ default: 'auto',
+ isLongForm: 600 // ~80 characters at body font size
+ }
+ }
});
-export function PageSkeleton({title, section, hasToC}: {title?: string, section?: string, hasToC?: boolean}) {
+export function PageSkeleton({title, section, hasToC, isLongForm, isWide}: {title?: string, section?: string, hasToC?: boolean, isLongForm?: boolean, isWide?: boolean}) {
const isComponents = section === 'Components';
return (
-
+
{title && (
-
+
{title}
)}
{!title && (
-
+
Page Title
)}
diff --git a/packages/dev/s2-docs/src/PostList.tsx b/packages/dev/s2-docs/src/PostList.tsx
new file mode 100644
index 00000000000..b27c2107916
--- /dev/null
+++ b/packages/dev/s2-docs/src/PostList.tsx
@@ -0,0 +1,92 @@
+import {getLibraryFromPage, getLibraryLabel} from './library';
+import {Link} from './Link';
+import type {Page} from '@parcel/rsc';
+import {renderHTMLfromMarkdown} from './types';
+import {style} from '@react-spectrum/s2/style' with {type: 'macro'};
+
+export function PostList({currentPage, pages}: {currentPage: Page, pages: Page[]}) {
+ let posts = pages.sort((a, b) => {
+ return new Date(b.exports?.date).getTime() - new Date(a.exports?.date).getTime();
+ });
+ let feedUrl = currentPage.url.replace(/\/(index.html)?$/, '.xml');
+
+ return (
+ <>
+ {/* React hoists this into the */}
+
+
+
+
+
+ Subscribe
+
+
+
+
+
+
+
+
+
+ {posts.map(post => (
+
+
+
+ {post.tableOfContents?.[0]?.title || post.exports?.title}
+
+ {post.exports?.author && }
+ {post.exports?.date && !post.exports.author && }
+
+
+ {renderHTMLfromMarkdown(post.exports?.description, {forceInline: true, forceBlock: false})}
+
+ ))}
+
+ >
+ );
+}
+
+export function Byline({author, authorLink, date}: {author?: string, authorLink?: string, date: string}) {
+ let formattedDate = new Date(date).toLocaleDateString('en-US', {year: 'numeric', month: 'long', day: 'numeric'});
+
+ return (
+
+ {author && (
+ <>
+ {'By '}
+
+ {authorLink ? (<>
+
+
+ {author}
+
+ >) : {author} }
+
+ {' · '}
+ >
+ )}
+ {formattedDate}
+
+ );
+}
+
+export function Time({date}: {date: string}) {
+ return {new Date(date).toLocaleDateString('en-US', {year: 'numeric', month: 'long', day: 'numeric'})} ;
+}
+
+function RSSIcon() {
+ return (
+
+
+
+
+
+ );
+}
diff --git a/packages/dev/s2-docs/src/PropTable.tsx b/packages/dev/s2-docs/src/PropTable.tsx
index 2c9b0b69399..97344a2748f 100644
--- a/packages/dev/s2-docs/src/PropTable.tsx
+++ b/packages/dev/s2-docs/src/PropTable.tsx
@@ -29,7 +29,7 @@ const GROUPS = {
/^on[A-Z]/
],
Links: [
- 'href', 'hrefLang', 'target', 'rel', 'download', 'ping', 'referrerPolicy', 'routerOptions'
+ 'href', 'hrefLang', 'target', 'rel', 'download', 'ping', 'referrerPolicy', 'itemProp', 'routerOptions'
],
Styling: [
'style', 'className'
@@ -51,7 +51,7 @@ const DEFAULT_EXPANDED = new Set([
'Value'
]);
-const codeStyle = style({font: {default: 'code-xs', lg: 'code-sm'}});
+const codeStyle = style({font: {default: 'code-xs', lg: 'code-sm'}, wordBreak: 'break-word'});
interface PropTableProps {
component: TComponent,
diff --git a/packages/dev/s2-docs/src/ReleasesList.tsx b/packages/dev/s2-docs/src/ReleasesList.tsx
deleted file mode 100644
index ac43d7829a0..00000000000
--- a/packages/dev/s2-docs/src/ReleasesList.tsx
+++ /dev/null
@@ -1,29 +0,0 @@
-
-import {Link} from './Link';
-import type {Page} from '@parcel/rsc';
-import {renderHTMLfromMarkdown} from './types';
-import {style} from '@react-spectrum/s2/style' with {type: 'macro'};
-
-export function ReleasesList({pages}: {pages: Page[]}) {
- let releases = pages.sort((a, b) => {
- return new Date(b.exports?.date).getTime() - new Date(a.exports?.date).getTime();
- });
- return (
-
- {releases.map(release => (
-
-
- {release.exports?.title}
-
-
-
{renderHTMLfromMarkdown(release.exports?.description, {})}
-
- ))}
- For all previous releases of React Spectrum v3, see the Archived releases page.
-
- );
-}
-
-export function Time({date}: {date: string}) {
- return {new Date(date).toLocaleDateString('en-US', {year: 'numeric', month: 'long', day: 'numeric'})} ;
-}
diff --git a/packages/dev/s2-docs/src/SearchMenu.tsx b/packages/dev/s2-docs/src/SearchMenu.tsx
index 0db6893ea4d..21a60d570df 100644
--- a/packages/dev/s2-docs/src/SearchMenu.tsx
+++ b/packages/dev/s2-docs/src/SearchMenu.tsx
@@ -57,6 +57,7 @@ interface SearchMenuProps {
onClose: () => void,
overlayId?: string,
initialSearchValue: string,
+ initialTag?: string,
isSearchOpen: boolean
}
@@ -146,7 +147,7 @@ export function SearchMenu(props: SearchMenuProps) {
searchValue,
sectionTags,
resourceTags,
- currentPage.exports?.section?.toLowerCase() || 'components'
+ props.initialTag || currentPage.exports?.section?.toLowerCase() || 'components'
);
const filteredIcons = useFilteredIcons(searchValue);
@@ -311,6 +312,7 @@ export function SearchMenu(props: SearchMenuProps) {
) : (
({
id: item.id,
diff --git a/packages/dev/s2-docs/src/SearchMenuWrapper.tsx b/packages/dev/s2-docs/src/SearchMenuWrapper.tsx
index 527b4866c00..1f752ba361d 100644
--- a/packages/dev/s2-docs/src/SearchMenuWrapper.tsx
+++ b/packages/dev/s2-docs/src/SearchMenuWrapper.tsx
@@ -6,9 +6,9 @@ import {flushSync} from 'react-dom';
import {preloadSearchMenu} from './SearchMenuTrigger';
import React, {lazy, useState} from 'react';
import {Modal as S2Modal} from '../../../@react-spectrum/s2/src/Modal';
-import {SearchMenu} from './SearchMenu';
import {style} from '@react-spectrum/s2/style' with { type: 'macro' };
+const SearchMenu = lazy(() => import('./SearchMenu').then(({SearchMenu}) => ({default: SearchMenu})));
const MobileSearchMenu = lazy(() => import('./SearchMenu').then(({MobileSearchMenu}) => ({default: MobileSearchMenu})));
let underlayStyle = style({
@@ -87,7 +87,7 @@ export default function SearchMenuWrapper({pages, currentPage}) {
<>
{openSearchMenu();}} >
- Explore Components
+ preloadSearchMenu()} className="font-spectrum no-underline bg-white/60 border border-black/10 bg-clip-padding text-base md:text-lg font-bold text-slate-800 px-8 py-3 rounded-full backdrop-saturate-150 backdrop-brightness-125 transition hover:bg-white/60 focus-ring dark:outline-white outline-offset-2 pressed:scale-95 cursor-pointer">Explore Components
@@ -105,9 +106,9 @@ export default function SearchMenuWrapper({pages, currentPage}) {
- Explore Components
+ Explore Components
-
+
diff --git a/packages/dev/s2-docs/src/StackBlitz.tsx b/packages/dev/s2-docs/src/StackBlitz.tsx
index 524c85823e8..7d4edaac323 100644
--- a/packages/dev/s2-docs/src/StackBlitz.tsx
+++ b/packages/dev/s2-docs/src/StackBlitz.tsx
@@ -1,6 +1,8 @@
+import type {DownloadFiles} from './CodeBlock';
+
export function createStackBlitz(
- files: {[name: string]: string},
- deps: {[name: string]: string},
+ files: DownloadFiles['files'],
+ deps: DownloadFiles['deps'],
type: 'vanilla' | 'tailwind' | 's2' = 'vanilla',
entry: string = 'Example'
) {
@@ -43,8 +45,8 @@ export function createStackBlitz(
}
function getFiles(
- files: {[name: string]: string},
- deps: {[name: string]: string},
+ files: DownloadFiles['files'],
+ deps: DownloadFiles['deps'],
type: 'vanilla' | 'tailwind' | 's2' = 'vanilla',
entry: string = 'Example'
) {
@@ -127,6 +129,6 @@ createRoot(document.getElementById('root')!).render(<${entryName} />);
},
'include': ['src']
}, null, 2) + '\n',
- ...Object.fromEntries(Object.entries(files).map(([name, contents]) => ['src/' + name, contents]))
+ ...Object.fromEntries(Object.entries(files).map(([name, file]) => ['src/' + name, file.contents]))
};
}
diff --git a/packages/dev/s2-docs/src/VisualExample.tsx b/packages/dev/s2-docs/src/VisualExample.tsx
index bb768d6ddc8..06431a572ab 100644
--- a/packages/dev/s2-docs/src/VisualExample.tsx
+++ b/packages/dev/s2-docs/src/VisualExample.tsx
@@ -1,6 +1,6 @@
import {CodeOutput, Control, Output, VisualExampleClient} from './VisualExampleClient';
+import {DownloadFiles, Files, getFiles} from './CodeBlock';
import {FileProvider, ShadcnProvider} from './CodePlatter';
-import {Files, getFiles} from './CodeBlock';
import json5 from 'json5';
import path from 'path';
import React, {ReactNode} from 'react';
@@ -87,7 +87,7 @@ export interface VisualExampleProps {
importSource?: string,
/** When provided, the source code for the listed filenames will be included as tabs. */
files?: string[],
- downloadFiles?: {files?: {[name: string]: string}, deps?: {[name: string]: string}},
+ downloadFiles?: DownloadFiles,
type?: 'vanilla' | 'tailwind' | 's2',
code?: ReactNode,
wide?: boolean,
@@ -162,7 +162,7 @@ export function VisualExample({component, docs, links, importSource, props, init
if (files) {
downloadFiles = getFiles(files, type);
} else {
- downloadFiles = {};
+ downloadFiles = {files: {}, deps: {}};
}
}
diff --git a/packages/dev/s2-docs/src/VisualExampleClient.tsx b/packages/dev/s2-docs/src/VisualExampleClient.tsx
index 9c1e9f85643..830df817e0d 100644
--- a/packages/dev/s2-docs/src/VisualExampleClient.tsx
+++ b/packages/dev/s2-docs/src/VisualExampleClient.tsx
@@ -13,6 +13,7 @@ import {mergeStyles} from '../../../@react-spectrum/s2/style/runtime';
import type {PropControl} from './VisualExample';
import React, {createContext, Fragment, isValidElement, lazy, ReactNode, Ref, useContext, useEffect, useMemo, useRef, useState} from 'react';
import RemoveCircle from '@react-spectrum/s2/icons/RemoveCircle';
+import {TabLink} from './FileTabs';
import {useLocale} from 'react-aria';
export const IconPicker = lazy(() => import('./IconPicker').then(({IconPicker}) => ({default: IconPicker})));
@@ -393,7 +394,23 @@ function renderImports(name: string, importSource: string, props: Props) {
}
function renderImport(name, from, isDefault = false) {
- return import {isDefault ? null : '{'}{name}{isDefault ? null : '}'} from '{from}' ; ;
+ return (
+
+ import
+ {' '}
+ {isDefault ? null : '{'}
+ {name}
+ {isDefault ? null : '}'}
+ {' '}
+ from
+ {' '}
+ {from.startsWith('./')
+ ? '{from}'
+ : '{from}'
+ }
+ {';'}
+
+ );
}
export function Control({name}: {name: string}) {
@@ -1008,7 +1025,10 @@ function PlacementControl({control, value, onChange}) {
disallowEmptySelection
selectedKeys={[value]}
onSelectionChange={keys => onChange([...keys][0])}
- className=""
+ className={style({
+ gridTemplateColumns: [25, 24, 24, 25, 24],
+ gridTemplateRows: [25, 24, 24, 25, 24]
+ })}
style={{
display: 'grid',
gridTemplateAreas: `
@@ -1017,9 +1037,7 @@ function PlacementControl({control, value, onChange}) {
"sc . . . ec"
"sb . . . eb"
". bs bc be . "
- `,
- gridTemplateColumns: 'calc(25px * var(--s2-scale)) calc(24px * var(--s2-scale)) calc(24px * var(--s2-scale)) calc(25px * var(--s2-scale)) calc(24px * var(--s2-scale))',
- gridTemplateRows: 'calc(25px * var(--s2-scale)) calc(24px * var(--s2-scale)) calc(24px * var(--s2-scale)) calc(25px * var(--s2-scale)) calc(24px * var(--s2-scale))'
+ `
}}>
diff --git a/packages/dev/s2-docs/src/icons/AdobeLogo.tsx b/packages/dev/s2-docs/src/icons/AdobeLogo.tsx
index 53bb1d72b72..32b516d43e9 100644
--- a/packages/dev/s2-docs/src/icons/AdobeLogo.tsx
+++ b/packages/dev/s2-docs/src/icons/AdobeLogo.tsx
@@ -7,7 +7,7 @@ export const AdobeLogo = ({className = '', size = 32}) => {
className={className}
style={{width: size, height: size}}
xmlns="http://www.w3.org/2000/svg"
- data-name="Layer 2"
+ aria-hidden
viewBox="0 0 501.71 444.05">
{
return (
diff --git a/packages/dev/s2-docs/src/icons/ReactAriaLogo.tsx b/packages/dev/s2-docs/src/icons/ReactAriaLogo.tsx
index da4733d1b0f..3cb509e03b9 100644
--- a/packages/dev/s2-docs/src/icons/ReactAriaLogo.tsx
+++ b/packages/dev/s2-docs/src/icons/ReactAriaLogo.tsx
@@ -4,7 +4,7 @@ export const ReactAriaLogo = ({size = 32}) => {
const clipPathId = `react-aria-logo-clip-${useId()}`;
return (
-
+
(null);
/**
- * An autocomplete combines a TextField or SearchField with a Menu or ListBox, allowing users to search or filter a list of suggestions.
+ * An autocomplete allows users to search or filter a list of suggestions.
*/
export function Autocomplete(props: AutocompleteProps): JSX.Element {
let ctx = useSlottedContext(AutocompleteContext, props.slot);
diff --git a/packages/react-aria-components/src/Group.tsx b/packages/react-aria-components/src/Group.tsx
index 2e4e5acae38..7d84b88a8f1 100644
--- a/packages/react-aria-components/src/Group.tsx
+++ b/packages/react-aria-components/src/Group.tsx
@@ -80,15 +80,14 @@ export const GroupContext = createContext) {
[props, ref] = useContextProps(props, ref, GroupContext);
let {isDisabled, isInvalid, isReadOnly, onHoverStart, onHoverChange, onHoverEnd, ...otherProps} = props;
+ isDisabled ??= !!props['aria-disabled'] && props['aria-disabled'] !== 'false';
+ isInvalid ??= !!props['aria-invalid'] && props['aria-invalid'] !== 'false';
let {hoverProps, isHovered} = useHover({onHoverStart, onHoverChange, onHoverEnd, isDisabled});
let {isFocused, isFocusVisible, focusProps} = useFocusRing({
within: true
});
- isDisabled ??= !!props['aria-disabled'] && props['aria-disabled'] !== 'false';
- isInvalid ??= !!props['aria-invalid'] && props['aria-invalid'] !== 'false';
-
let renderProps = useRenderProps({
...props,
values: {isHovered, isFocusWithin: isFocused, isFocusVisible, isDisabled, isInvalid},
diff --git a/packages/react-aria-components/src/Input.tsx b/packages/react-aria-components/src/Input.tsx
index 09bf47eb63b..48f1bd6a41b 100644
--- a/packages/react-aria-components/src/Input.tsx
+++ b/packages/react-aria-components/src/Input.tsx
@@ -76,7 +76,10 @@ let filterHoverProps = (props: InputProps) => {
export const Input = /*#__PURE__*/ createHideableComponent(function Input(props: InputProps, ref: ForwardedRef) {
[props, ref] = useContextProps(props, ref, InputContext);
- let {hoverProps, isHovered} = useHover(props);
+ let {hoverProps, isHovered} = useHover({
+ ...props,
+ isDisabled: props.disabled
+ });
let {isFocused, isFocusVisible, focusProps} = useFocusRing({
isTextInput: true,
autoFocus: props.autoFocus
diff --git a/packages/react-aria-components/src/ToggleButtonGroup.tsx b/packages/react-aria-components/src/ToggleButtonGroup.tsx
index b2800af9843..462763c0837 100644
--- a/packages/react-aria-components/src/ToggleButtonGroup.tsx
+++ b/packages/react-aria-components/src/ToggleButtonGroup.tsx
@@ -19,12 +19,17 @@ import {
useRenderProps
} from './utils';
import {filterDOMProps, mergeProps} from '@react-aria/utils';
-import {forwardRefType, GlobalDOMAttributes} from '@react-types/shared';
+import {forwardRefType, GlobalDOMAttributes, Orientation} from '@react-types/shared';
import React, {createContext, ForwardedRef, forwardRef} from 'react';
import {SharedElementTransition} from './SharedElementTransition';
import {ToggleGroupState, useToggleGroupState} from 'react-stately';
export interface ToggleButtonGroupRenderProps {
+ /**
+ * The orientation of the toggle button group.
+ * @selector [data-orientation="horizontal | vertical"]
+ */
+ orientation: Orientation,
/**
* Whether the toggle button group is disabled.
* @selector [data-disabled]
@@ -58,6 +63,7 @@ export const ToggleButtonGroup = /*#__PURE__*/ (forwardRef as forwardRefType)(fu
let renderProps = useRenderProps({
...props,
values: {
+ orientation: props.orientation || 'horizontal',
isDisabled: state.isDisabled,
state
},
diff --git a/scripts/createFeedS2.mjs b/scripts/createFeedS2.mjs
new file mode 100644
index 00000000000..922155e3acf
--- /dev/null
+++ b/scripts/createFeedS2.mjs
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2025 Adobe. All rights reserved.
+ * This file is licensed to you under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License. You may obtain a copy
+ * of the License at http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under
+ * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
+ * OF ANY KIND, either express or implied. See the License for the specific language
+ * governing permissions and limitations under the License.
+ */
+
+import {basename} from 'path';
+import fs from 'fs';
+import {globSync} from 'glob';
+import rehypeStringify from 'rehype-stringify';
+import remarkMdx from 'remark-mdx';
+import remarkParse from 'remark-parse';
+import remarkRehype from 'remark-rehype';
+import {unified} from 'unified';
+import {visit} from 'unist-util-visit';
+import xml from 'xml';
+
+const publicUrl = process.env.PUBLIC_URL || 'http://localhost:1234';
+
+createFeed('react-aria/blog', 'React Aria Blog');
+createFeed('react-aria/releases', 'React Aria Releases');
+createFeed('s2/releases', 'React Spectrum Releases');
+
+function createFeed(type, title) {
+ let files = globSync(`packages/dev/s2-docs/pages/${type}/*.mdx`, {ignore: [`packages/dev/s2-docs/pages/${type}/index.mdx`]});
+ let posts = [];
+
+ for (let file of files) {
+ let contents = fs.readFileSync(file, 'utf8');
+ let tree = unified().use(remarkParse).use(remarkMdx).parse(contents);
+
+ let exports = {};
+ visit(tree, 'mdxjsEsm', node => {
+ for (let stmt of node.data.estree.body) {
+ if (stmt.type === 'ExportNamedDeclaration') {
+ for (let decl of stmt.declaration.declarations) {
+ if (decl.init.type === 'Literal') {
+ exports[decl.id.name] = decl.init.value;
+ }
+ }
+ }
+ }
+ });
+
+ let title;
+ visit(tree, 'heading', node => {
+ if (node.depth === 1) {
+ title = node.children[0].value;
+ }
+ });
+
+ let summary = unified()
+ .use(remarkParse)
+ .use(remarkMdx)
+ .use(remarkRehype)
+ .use(rehypeStringify)
+ .processSync({value: exports.description})
+ .value;
+
+ let entry = [
+ {title},
+ {link: [{_attr: {rel: 'alternate', type: 'text/html', href: `${publicUrl}/${type}/${basename(file, '.mdx')}.html`}}]},
+ {id: basename(file, '.mdx')},
+ {updated: new Date(exports.date).toISOString()},
+ {published: new Date(exports.date).toISOString()},
+ {summary: [{_attr: {type: 'text/html'}}, summary]},
+ ];
+
+ if (exports.author) {
+ entry.push({
+ author: [
+ {name: exports.author},
+ {uri: exports.authorLink}
+ ]
+ });
+ }
+
+ posts.push({
+ entry
+ });
+ }
+
+ posts = posts.sort((a, b) => a.entry[3].updated < b.entry[3].updated ? 1 : -1);
+ let feed = xml({
+ feed: [
+ {_attr: {xmlns: 'http://www.w3.org/2005/Atom'}},
+ {title},
+ {link: `${publicUrl}/${type}/`},
+ {updated: posts[0].entry[3].updated},
+ {id: `${publicUrl}/${type}.xml`},
+ ...posts
+ ]
+ });
+
+ fs.writeFileSync(`packages/dev/s2-docs/dist/${type}.xml`, feed);
+}
diff --git a/starters/docs/src/DateField.css b/starters/docs/src/DateField.css
index bd77ef98d74..2e1445a0860 100644
--- a/starters/docs/src/DateField.css
+++ b/starters/docs/src/DateField.css
@@ -30,6 +30,7 @@
&[data-disabled] {
color: var(--text-color-disabled);
+ cursor: default;
}
}
diff --git a/starters/docs/src/Menu.tsx b/starters/docs/src/Menu.tsx
index 8e06978b03f..4ae23c6b02e 100644
--- a/starters/docs/src/Menu.tsx
+++ b/starters/docs/src/Menu.tsx
@@ -18,28 +18,16 @@ import { Text } from './Content';
import React from 'react';
import './Menu.css';
-export interface MenuButtonProps
- extends MenuProps, Omit {
- label?: string;
-}
-
-export function MenuButton(
- { label, children, ...props }: MenuButtonProps
-) {
+export function MenuTrigger(props: MenuTriggerProps) {
+ let [trigger, menu] = React.Children.toArray(props.children) as [React.ReactElement, React.ReactElement];
return (
-
- {label}
-
-
- {children}
-
+
+ {trigger}
+
+ {menu}
-
- );
-}
-
-export function MenuTrigger(props: MenuTriggerProps) {
- return ;
+
+ )
}
export function Menu(props: MenuProps) {
@@ -51,11 +39,8 @@ export function Menu(props: MenuProps) {
);
}
-export function MenuItem(
- props: Omit & { children?: React.ReactNode }
-) {
- let textValue = props.textValue ||
- (typeof props.children === 'string' ? props.children : undefined);
+export function MenuItem(props: Omit & { children?: React.ReactNode }) {
+ let textValue = props.textValue || (typeof props.children === 'string' ? props.children : undefined);
return (
(
@@ -78,9 +63,7 @@ export function MenuSection(props: MenuSectionProps) {
return ;
}
-export function SubmenuTrigger(
- props: SubmenuTriggerProps
-) {
+export function SubmenuTrigger(props: SubmenuTriggerProps) {
let [trigger, menu] = React.Children.toArray(props.children) as [React.ReactElement, React.ReactElement];
return (
diff --git a/starters/tailwind/src/AlertDialog.tsx b/starters/tailwind/src/AlertDialog.tsx
index 8576971fa7e..8811d9ddedd 100644
--- a/starters/tailwind/src/AlertDialog.tsx
+++ b/starters/tailwind/src/AlertDialog.tsx
@@ -36,7 +36,7 @@ export function AlertDialog({
{variant === 'destructive' ?
:
}
-
+
{children}
diff --git a/starters/tailwind/src/Breadcrumbs.tsx b/starters/tailwind/src/Breadcrumbs.tsx
index 508f2dcb6b3..9f7e281d606 100644
--- a/starters/tailwind/src/Breadcrumbs.tsx
+++ b/starters/tailwind/src/Breadcrumbs.tsx
@@ -15,7 +15,7 @@ export function Breadcrumb(props: BreadcrumbProps & Omit
{({isCurrent}) => (<>
- {!isCurrent && }
+ {!isCurrent && }
>)}
);
diff --git a/starters/tailwind/src/Button.tsx b/starters/tailwind/src/Button.tsx
index 053e35a2c52..a00db610de1 100644
--- a/starters/tailwind/src/Button.tsx
+++ b/starters/tailwind/src/Button.tsx
@@ -6,20 +6,21 @@ import { focusRing } from './utils';
export interface ButtonProps extends RACButtonProps {
/** @default 'primary' */
- variant?: 'primary' | 'secondary' | 'destructive'
+ variant?: 'primary' | 'secondary' | 'destructive' | 'quiet'
}
let button = tv({
extend: focusRing,
- base: 'relative inline-flex items-center border-0 px-5 [&:has(svg:only-child)]:px-2 py-2 font-sans text-sm text-center transition rounded-lg border border-black/10 dark:border-white/10 shadow-[inset_0_1px_0_0_rgba(255,255,255,0.1)] dark:shadow-none cursor-default',
+ base: 'relative inline-flex items-center justify-center gap-2 border border-transparent dark:border-white/10 h-9 box-border px-3.5 py-0 [&:has(>svg:only-child)]:px-0 [&:has(>svg:only-child)]:h-8 [&:has(>svg:only-child)]:aspect-square font-sans text-sm text-center transition rounded-lg cursor-default',
variants: {
variant: {
primary: 'bg-blue-600 hover:bg-blue-700 pressed:bg-blue-800 text-white',
- secondary: 'bg-gray-50 hover:bg-gray-100 pressed:bg-gray-200 text-gray-800 dark:bg-zinc-600 dark:hover:bg-zinc-500 dark:pressed:bg-zinc-400 dark:text-zinc-100',
- destructive: 'bg-red-700 hover:bg-red-800 pressed:bg-red-900 text-white'
+ secondary: 'border-black/10 bg-neutral-50 hover:bg-neutral-100 pressed:bg-neutral-200 text-neutral-800 dark:bg-neutral-700 dark:hover:bg-neutral-600 dark:pressed:bg-neutral-500 dark:text-neutral-100',
+ destructive: 'bg-red-700 hover:bg-red-800 pressed:bg-red-900 text-white',
+ quiet: 'border-0 bg-transparent hover:bg-neutral-200 pressed:bg-neutral-300 text-neutral-800 dark:hover:bg-neutral-700 dark:pressed:bg-neutral-600 dark:text-neutral-100'
},
isDisabled: {
- true: 'bg-gray-100 dark:bg-zinc-800 text-gray-300 dark:text-zinc-600 forced-colors:text-[GrayText] border-black/5 dark:border-white/5'
+ true: 'border-transparent dark:border-transparent bg-neutral-100 dark:bg-neutral-800 text-neutral-300 dark:text-neutral-600 forced-colors:text-[GrayText]'
},
isPending: {
true: 'text-transparent'
@@ -27,7 +28,14 @@ let button = tv({
},
defaultVariants: {
variant: 'primary'
- }
+ },
+ compoundVariants: [
+ {
+ variant: 'quiet',
+ isDisabled: true,
+ class: 'bg-transparent dark:bg-transparent'
+ }
+ ]
});
export function Button(props: ButtonProps) {
@@ -44,9 +52,9 @@ export function Button(props: ButtonProps) {
{children}
{isPending && (
-
-
-
+
+
+
)}
diff --git a/starters/tailwind/src/Calendar.tsx b/starters/tailwind/src/Calendar.tsx
index 50c683f2683..fc575371d33 100644
--- a/starters/tailwind/src/Calendar.tsx
+++ b/starters/tailwind/src/Calendar.tsx
@@ -23,11 +23,11 @@ const cellStyles = tv({
base: 'w-9 h-9 text-sm cursor-default rounded-full flex items-center justify-center forced-color-adjust-none',
variants: {
isSelected: {
- false: 'text-zinc-900 dark:text-zinc-200 hover:bg-gray-100 dark:hover:bg-zinc-700 pressed:bg-gray-200 dark:pressed:bg-zinc-600',
+ false: 'text-neutral-900 dark:text-neutral-200 hover:bg-neutral-200 dark:hover:bg-neutral-700 pressed:bg-neutral-300 dark:pressed:bg-neutral-600',
true: 'bg-blue-600 invalid:bg-red-600 text-white forced-colors:bg-[Highlight] forced-colors:invalid:bg-[Mark] forced-colors:text-[HighlightText]'
},
isDisabled: {
- true: 'text-gray-300 dark:text-zinc-600 forced-colors:text-[GrayText]'
+ true: 'text-neutral-300 dark:text-neutral-600 forced-colors:text-[GrayText]'
}
}
});
@@ -58,11 +58,11 @@ export function CalendarHeader() {
return (
-
+
{direction === 'rtl' ? : }
-
-
+
+
{direction === 'rtl' ? : }
@@ -73,7 +73,7 @@ export function CalendarGridHeader() {
return (
{(day) => (
-
+
{day}
)}
diff --git a/starters/tailwind/src/Checkbox.tsx b/starters/tailwind/src/Checkbox.tsx
index bf030006906..6df736ea9c3 100644
--- a/starters/tailwind/src/Checkbox.tsx
+++ b/starters/tailwind/src/Checkbox.tsx
@@ -28,30 +28,30 @@ const checkboxStyles = tv({
base: 'flex gap-2 items-center group font-sans text-sm transition relative',
variants: {
isDisabled: {
- false: 'text-gray-800 dark:text-zinc-200',
- true: 'text-gray-300 dark:text-zinc-600 forced-colors:text-[GrayText]'
+ false: 'text-neutral-800 dark:text-neutral-200',
+ true: 'text-neutral-300 dark:text-neutral-600 forced-colors:text-[GrayText]'
}
}
});
const boxStyles = tv({
extend: focusRing,
- base: 'w-5 h-5 box-border shrink-0 rounded-sm flex items-center justify-center border-2 transition',
+ base: 'w-4.5 h-4.5 box-border shrink-0 rounded-sm flex items-center justify-center border transition',
variants: {
isSelected: {
- false: 'bg-white dark:bg-zinc-900 border-(--color) [--color:var(--color-gray-400)] dark:[--color:var(--color-zinc-400)] group-pressed:[--color:var(--color-gray-500)] dark:group-pressed:[--color:var(--color-zinc-300)]',
- true: 'bg-(--color) border-(--color) [--color:var(--color-gray-700)] group-pressed:[--color:var(--color-gray-800)] dark:[--color:var(--color-slate-300)] dark:group-pressed:[--color:var(--color-slate-200)] forced-colors:[--color:Highlight]!'
+ false: 'bg-white dark:bg-neutral-900 border-(--color) [--color:var(--color-neutral-400)] dark:[--color:var(--color-neutral-400)] group-pressed:[--color:var(--color-neutral-500)] dark:group-pressed:[--color:var(--color-neutral-300)]',
+ true: 'bg-(--color) border-(--color) [--color:var(--color-neutral-700)] group-pressed:[--color:var(--color-neutral-800)] dark:[--color:var(--color-neutral-300)] dark:group-pressed:[--color:var(--color-neutral-200)] forced-colors:[--color:Highlight]!'
},
isInvalid: {
true: '[--color:var(--color-red-700)] dark:[--color:var(--color-red-600)] forced-colors:[--color:Mark]! group-pressed:[--color:var(--color-red-800)] dark:group-pressed:[--color:var(--color-red-700)]'
},
isDisabled: {
- true: '[--color:var(--color-gray-200)] dark:[--color:var(--color-zinc-700)] forced-colors:[--color:GrayText]!'
+ true: '[--color:var(--color-neutral-200)] dark:[--color:var(--color-neutral-700)] forced-colors:[--color:GrayText]!'
}
}
});
-const iconStyles = 'w-4 h-4 text-white group-disabled:text-gray-400 dark:text-slate-900 dark:group-disabled:text-slate-600 forced-colors:text-[HighlightText]';
+const iconStyles = 'w-3.5 h-3.5 text-white group-disabled:text-neutral-400 dark:text-neutral-900 dark:group-disabled:text-neutral-600 forced-colors:text-[HighlightText]';
export function Checkbox(props: CheckboxProps) {
return (
diff --git a/starters/tailwind/src/ColorArea.tsx b/starters/tailwind/src/ColorArea.tsx
index 12d9ab2c422..e8084a92c13 100644
--- a/starters/tailwind/src/ColorArea.tsx
+++ b/starters/tailwind/src/ColorArea.tsx
@@ -13,7 +13,7 @@ export function ColorArea(props: ColorAreaProps) {
return (
({
...defaultStyle,
background: isDisabled ? undefined : defaultStyle.background
diff --git a/starters/tailwind/src/ColorField.tsx b/starters/tailwind/src/ColorField.tsx
index 78da5d85e1d..9387ae3bf2a 100644
--- a/starters/tailwind/src/ColorField.tsx
+++ b/starters/tailwind/src/ColorField.tsx
@@ -11,10 +11,11 @@ import { composeTailwindRenderProps, focusRing } from './utils';
const inputStyles = tv({
extend: focusRing,
- base: 'border-2 rounded-lg',
+ base: 'border-1 rounded-lg min-h-9 font-sans py-0 px-3 box-border transition',
variants: {
isFocused: fieldBorderStyles.variants.isFocusWithin,
- ...fieldBorderStyles.variants,
+ isInvalid: fieldBorderStyles.variants.isInvalid,
+ isDisabled: fieldBorderStyles.variants.isDisabled
}
});
diff --git a/starters/tailwind/src/ColorPicker.tsx b/starters/tailwind/src/ColorPicker.tsx
index 8525c399662..8dcf2f81f5e 100644
--- a/starters/tailwind/src/ColorPicker.tsx
+++ b/starters/tailwind/src/ColorPicker.tsx
@@ -12,7 +12,7 @@ import { focusRing } from './utils';
const buttonStyles = tv({
extend: focusRing,
- base: 'border-0 bg-transparent flex gap-2 items-center cursor-default rounded-xs font-sans text-sm text-gray-800 dark:text-gray-200'
+ base: 'border-0 bg-transparent flex gap-2 items-center cursor-default rounded-xs font-sans text-sm text-neutral-800 dark:text-neutral-200'
});
export interface ColorPickerProps extends Omit {
diff --git a/starters/tailwind/src/ColorSlider.tsx b/starters/tailwind/src/ColorSlider.tsx
index 60960ed339c..aa8a3779c88 100644
--- a/starters/tailwind/src/ColorSlider.tsx
+++ b/starters/tailwind/src/ColorSlider.tsx
@@ -12,14 +12,14 @@ import { composeTailwindRenderProps } from './utils';
import { ColorThumb } from './ColorThumb';
const trackStyles = tv({
- base: 'group col-span-2 orientation-horizontal:h-6 rounded-lg',
+ base: 'group col-span-2 orientation-horizontal:h-6 rounded-md',
variants: {
orientation: {
horizontal: 'w-full h-6',
vertical: 'w-6 h-56 ml-[50%] -translate-x-[50%]'
},
isDisabled: {
- true: 'bg-gray-300 dark:bg-zinc-800 forced-colors:bg-[GrayText]'
+ true: 'bg-neutral-300 dark:bg-neutral-800 forced-colors:bg-[GrayText]'
}
}
});
@@ -32,7 +32,7 @@ export function ColorSlider({ label, ...props }: ColorSliderProps) {
return (
{label}
-
+
({
diff --git a/starters/tailwind/src/ColorSwatch.tsx b/starters/tailwind/src/ColorSwatch.tsx
index 4e198abee88..fbb665f7df4 100644
--- a/starters/tailwind/src/ColorSwatch.tsx
+++ b/starters/tailwind/src/ColorSwatch.tsx
@@ -7,7 +7,7 @@ export function ColorSwatch(props: ColorSwatchProps) {
return (
({
background: `linear-gradient(${color}, ${color}),
repeating-conic-gradient(#CCC 0% 25%, white 0% 50%) 50% / 16px 16px`
diff --git a/starters/tailwind/src/ColorSwatchPicker.tsx b/starters/tailwind/src/ColorSwatchPicker.tsx
index 53e2e28ab13..d9b4301453d 100644
--- a/starters/tailwind/src/ColorSwatchPicker.tsx
+++ b/starters/tailwind/src/ColorSwatchPicker.tsx
@@ -41,7 +41,7 @@ export function ColorSwatchPickerItem(props: ColorSwatchPickerItemProps) {
{({isSelected}) => <>
- {isSelected &&
}
+ {isSelected &&
}
>}
);
diff --git a/starters/tailwind/src/ColorThumb.tsx b/starters/tailwind/src/ColorThumb.tsx
index 3ca027a5888..cdb10770a46 100644
--- a/starters/tailwind/src/ColorThumb.tsx
+++ b/starters/tailwind/src/ColorThumb.tsx
@@ -10,10 +10,10 @@ const thumbStyles = tv({
true: 'w-8 h-8'
},
isDragging: {
- true: 'bg-gray-700 dark:bg-gray-300 forced-colors:bg-[ButtonBorder]'
+ true: 'bg-neutral-700 dark:bg-neutral-300 forced-colors:bg-[ButtonBorder]'
},
isDisabled: {
- true: 'border-gray-300 dark:border-zinc-700 forced-colors:border-[GrayText] bg-gray-300 dark:bg-zinc-800 forced-colors:bg-[GrayText]'
+ true: 'border-neutral-300 dark:border-neutral-700 forced-colors:border-[GrayText] bg-neutral-300 dark:bg-neutral-800 forced-colors:bg-[GrayText]'
}
}
});
diff --git a/starters/tailwind/src/ColorWheel.tsx b/starters/tailwind/src/ColorWheel.tsx
index 0c855797986..3966450d3ad 100644
--- a/starters/tailwind/src/ColorWheel.tsx
+++ b/starters/tailwind/src/ColorWheel.tsx
@@ -9,7 +9,7 @@ export function ColorWheel(props: ColorWheelProps) {
return (
({
...defaultStyle,
background: isDisabled ? undefined : `${defaultStyle.background}, repeating-conic-gradient(#CCC 0% 25%, white 0% 50%) 50% / 16px 16px`
diff --git a/starters/tailwind/src/ComboBox.tsx b/starters/tailwind/src/ComboBox.tsx
index 2628a49fafb..468b5e0d7fa 100644
--- a/starters/tailwind/src/ComboBox.tsx
+++ b/starters/tailwind/src/ComboBox.tsx
@@ -18,6 +18,7 @@ export interface ComboBoxProps extends Omit string);
+ placeholder?: string;
children: React.ReactNode | ((item: T) => React.ReactNode);
}
@@ -28,8 +29,8 @@ export function ComboBox(
{label}
-
-
+
+
diff --git a/starters/tailwind/src/DateField.tsx b/starters/tailwind/src/DateField.tsx
index 6b5dd4da5bf..e20e416de03 100644
--- a/starters/tailwind/src/DateField.tsx
+++ b/starters/tailwind/src/DateField.tsx
@@ -33,13 +33,13 @@ export function DateField(
}
const segmentStyles = tv({
- base: 'inline p-0.5 type-literal:px-0 rounded-xs outline outline-0 forced-color-adjust-none caret-transparent text-gray-800 dark:text-zinc-200 forced-colors:text-[ButtonText]',
+ base: 'inline p-0.5 type-literal:p-0 rounded-xs outline outline-0 forced-color-adjust-none caret-transparent text-neutral-800 dark:text-neutral-200 forced-colors:text-[ButtonText]',
variants: {
isPlaceholder: {
- true: 'text-gray-600 dark:text-zinc-400 italic'
+ true: 'text-neutral-600 dark:text-neutral-400'
},
isDisabled: {
- true: 'text-gray-200 dark:text-zinc-600 forced-colors:text-[GrayText]'
+ true: 'text-neutral-200 dark:text-neutral-600 forced-colors:text-[GrayText]'
},
isFocused: {
true: 'bg-blue-600 text-white dark:text-white forced-colors:bg-[Highlight] forced-colors:text-[HighlightText]'
@@ -49,7 +49,7 @@ const segmentStyles = tv({
export function DateInput(props: Omit) {
return (
- fieldGroupStyles({...renderProps, class: 'inline min-w-[150px] px-2 py-1.5 text-sm font-sans whitespace-nowrap overflow-x-auto [scrollbar-width:none]'})} {...props}>
+ fieldGroupStyles({...renderProps, class: 'inline min-w-[150px] px-3 h-9 text-sm leading-8.5 font-sans cursor-text disabled:cursor-default whitespace-nowrap overflow-x-auto [scrollbar-width:none]'})} {...props}>
{(segment) => }
);
diff --git a/starters/tailwind/src/DatePicker.tsx b/starters/tailwind/src/DatePicker.tsx
index e1f4cf5f8d9..63acaa7d610 100644
--- a/starters/tailwind/src/DatePicker.tsx
+++ b/starters/tailwind/src/DatePicker.tsx
@@ -28,9 +28,9 @@ export function DatePicker(
return (
{label && {label} }
-
-
-
+
+
+
diff --git a/starters/tailwind/src/DateRangePicker.tsx b/starters/tailwind/src/DateRangePicker.tsx
index feb6cf8f5a9..ad117f4b3aa 100644
--- a/starters/tailwind/src/DateRangePicker.tsx
+++ b/starters/tailwind/src/DateRangePicker.tsx
@@ -28,11 +28,11 @@ export function DateRangePicker(
return (
{label && {label} }
-
-
- –
-
-
+
+
+ –
+
+
diff --git a/starters/tailwind/src/Disclosure.tsx b/starters/tailwind/src/Disclosure.tsx
index e49228c4a42..6d0c067828a 100644
--- a/starters/tailwind/src/Disclosure.tsx
+++ b/starters/tailwind/src/Disclosure.tsx
@@ -9,44 +9,25 @@ import {
DisclosurePanelProps as AriaDisclosurePanelProps,
composeRenderProps,
Heading,
- Button,
DisclosureStateContext,
} from "react-aria-components";
+import { Button } from './Button';
import { tv } from "tailwind-variants";
import { ChevronRight } from "lucide-react";
-import { composeTailwindRenderProps, focusRing } from "./utils";
-import { DisclosureGroupStateContext } from "react-aria-components";
+import { composeTailwindRenderProps } from "./utils";
const disclosure = tv({
- base: "group min-w-64 bg-white font-sans dark:bg-gray-900 border border-gray-300 dark:border-zinc-600 rounded-lg text-gray-900 dark:text-zinc-200",
- variants: {
- isInGroup: {
- true: "border-0 border-b last:border-b-0 rounded-b-none last:rounded-b-lg",
- }
- }
-});
-
-const disclosureButton = tv({
- extend: focusRing,
- base: "bg-transparent border-0 rounded-lg flex gap-2 items-center w-full text-start p-2 cursor-default",
- variants: {
- isDisabled: {
- true: 'text-gray-300 dark:text-zinc-600 forced-colors:text-[GrayText]'
- },
- isInGroup: {
- true: "-outline-offset-2 rounded-none group-first:rounded-t-lg group-last:rounded-b-lg",
- }
- }
+ base: "group min-w-64 font-sans rounded-lg text-neutral-900 dark:text-neutral-200"
});
const chevron = tv({
- base: "w-5 h-5 text-gray-500 dark:text-gray-400 transition-transform duration-200 ease-in-out",
+ base: "w-4 h-4 text-neutral-500 dark:text-neutral-400 transition-transform duration-200 ease-in-out",
variants: {
isExpanded: {
true: "transform rotate-90",
},
isDisabled: {
- true: 'text-gray-300 dark:text-zinc-600 forced-colors:text-[GrayText]'
+ true: 'text-neutral-300 dark:text-neutral-600 forced-colors:text-[GrayText]'
}
}
});
@@ -56,11 +37,10 @@ export interface DisclosureProps extends AriaDisclosureProps {
}
export function Disclosure({ children, ...props }: DisclosureProps) {
- let isInGroup = useContext(DisclosureGroupStateContext) !== null;
return (
disclosure({ ...renderProps, isInGroup, className }))}
+ className={composeRenderProps(props.className, (className, renderProps) => disclosure({ ...renderProps, className }))}
>
{children}
@@ -73,17 +53,16 @@ export interface DisclosureHeaderProps {
export function DisclosureHeader({ children }: DisclosureHeaderProps) {
let { isExpanded } = useContext(DisclosureStateContext)!;
- let isInGroup = useContext(DisclosureGroupStateContext) !== null;
return (
disclosureButton({ ...renderProps, isInGroup })}
- >
+ variant="quiet"
+ className="w-full justify-start font-medium">
{({isDisabled}) => (
<>
- {children}
+ {children}
>
)}
@@ -109,7 +88,7 @@ export interface DisclosureGroupProps extends AriaDisclosureGroupProps {
export function DisclosureGroup({ children, ...props }: DisclosureGroupProps) {
return (
-
+
{children}
);
diff --git a/starters/tailwind/src/DropZone.tsx b/starters/tailwind/src/DropZone.tsx
index 322dd967803..dc197617f0b 100644
--- a/starters/tailwind/src/DropZone.tsx
+++ b/starters/tailwind/src/DropZone.tsx
@@ -4,7 +4,7 @@ import {composeRenderProps, DropZoneProps, DropZone as RACDropZone} from 'react-
import { tv } from "tailwind-variants";
const dropZone = tv({
- base: "flex items-center justify-center p-8 min-h-24 w-[30%] font-sans text-base text-balance text-center rounded-lg border border-1 border-gray-300 dark:border-zinc-800 bg-white dark:bg-zinc-900",
+ base: "flex items-center justify-center p-8 min-h-24 w-[30%] font-sans text-base text-balance text-center rounded-lg border border-1 border-neutral-300 dark:border-neutral-800 bg-white dark:bg-neutral-900",
variants: {
isFocusVisible: {
true: "outline outline-2 -outline-offset-1 outline-blue-600 dark:outline-blue-500 forced-colors:outline-[Highlight]"
diff --git a/starters/tailwind/src/Field.tsx b/starters/tailwind/src/Field.tsx
index 885efb00752..37f85290605 100644
--- a/starters/tailwind/src/Field.tsx
+++ b/starters/tailwind/src/Field.tsx
@@ -6,11 +6,11 @@ import { tv } from 'tailwind-variants';
import { composeTailwindRenderProps, focusRing } from "./utils";
export function Label(props: LabelProps) {
- return ;
+ return ;
}
export function Description(props: TextProps) {
- return ;
+ return ;
}
export function FieldError(props: FieldErrorProps) {
@@ -18,23 +18,24 @@ export function FieldError(props: FieldErrorProps) {
}
export const fieldBorderStyles = tv({
+ base: 'transition',
variants: {
isFocusWithin: {
- false: 'border-gray-300 dark:border-zinc-500 forced-colors:border-[ButtonBorder]',
- true: 'border-gray-600 dark:border-zinc-300 forced-colors:border-[Highlight]',
+ false: 'border-neutral-300 hover:border-neutral-400 dark:border-neutral-600 dark:hover:border-neutral-500 forced-colors:border-[ButtonBorder]',
+ true: 'border-neutral-600 dark:border-neutral-300 forced-colors:border-[Highlight]',
},
isInvalid: {
true: 'border-red-600 dark:border-red-600 forced-colors:border-[Mark]'
},
isDisabled: {
- true: 'border-gray-200 dark:border-zinc-700 forced-colors:border-[GrayText]'
+ true: 'border-neutral-200 dark:border-neutral-700 forced-colors:border-[GrayText]'
}
}
});
export const fieldGroupStyles = tv({
extend: focusRing,
- base: 'group flex items-center h-9 box-border bg-white dark:bg-zinc-900 forced-colors:bg-[Field] border-2 rounded-lg overflow-hidden',
+ base: 'group flex items-center h-9 box-border bg-white dark:bg-neutral-900 forced-colors:bg-[Field] border rounded-lg overflow-hidden transition',
variants: fieldBorderStyles.variants
});
@@ -43,5 +44,5 @@ export function FieldGroup(props: GroupProps) {
}
export function Input(props: InputProps) {
- return
+ return
}
diff --git a/starters/tailwind/src/FieldButton.tsx b/starters/tailwind/src/FieldButton.tsx
index 93d6532001f..9a1c129ce50 100644
--- a/starters/tailwind/src/FieldButton.tsx
+++ b/starters/tailwind/src/FieldButton.tsx
@@ -11,10 +11,10 @@ export interface ButtonProps extends RACButtonProps {
let button = tv({
extend: focusRing,
- base: 'relative inline-flex items-center border-0 font-sans text-sm text-center transition rounded-lg cursor-default p-1 flex items-center justify-center text-gray-600 bg-transparent hover:bg-black/[5%] pressed:bg-black/10 dark:text-zinc-400 dark:hover:bg-white/10 dark:pressed:bg-white/20 disabled:bg-transparent',
+ base: 'relative inline-flex items-center border-0 font-sans text-sm text-center transition rounded-md cursor-default p-1 flex items-center justify-center text-neutral-600 bg-transparent hover:bg-black/[5%] pressed:bg-black/10 dark:text-neutral-400 dark:hover:bg-white/10 dark:pressed:bg-white/20 disabled:bg-transparent',
variants: {
isDisabled: {
- true: 'bg-gray-100 dark:bg-zinc-800 text-gray-300 dark:text-zinc-600 forced-colors:text-[GrayText] border-black/5 dark:border-white/5'
+ true: 'bg-neutral-100 dark:bg-neutral-800 text-neutral-300 dark:text-neutral-600 forced-colors:text-[GrayText] border-black/5 dark:border-white/5'
}
}
});
diff --git a/starters/tailwind/src/Form.tsx b/starters/tailwind/src/Form.tsx
index d85437e9320..af0a7496bf3 100644
--- a/starters/tailwind/src/Form.tsx
+++ b/starters/tailwind/src/Form.tsx
@@ -4,5 +4,5 @@ import { FormProps, Form as RACForm } from 'react-aria-components';
import { twMerge } from 'tailwind-merge';
export function Form(props: FormProps) {
- return ;
+ return ;
}
diff --git a/starters/tailwind/src/GridList.tsx b/starters/tailwind/src/GridList.tsx
index 2a38a7d4374..b4c5afd05f6 100644
--- a/starters/tailwind/src/GridList.tsx
+++ b/starters/tailwind/src/GridList.tsx
@@ -16,7 +16,7 @@ export function GridList(
{ children, ...props }: GridListProps
) {
return (
-
+
{children}
);
@@ -24,14 +24,14 @@ export function GridList(
const itemStyles = tv({
extend: focusRing,
- base: 'relative flex gap-3 cursor-default select-none py-2 px-3 text-sm text-gray-900 dark:text-zinc-200 border-y dark:border-y-zinc-700 border-transparent first:border-t-0 last:border-b-0 first:rounded-t-lg last:rounded-b-lg -mb-px last:mb-0 -outline-offset-2',
+ base: 'relative flex gap-3 cursor-default select-none py-2 px-3 text-sm text-neutral-900 dark:text-neutral-200 border-y dark:border-y-neutral-700 border-transparent first:border-t-0 last:border-b-0 first:rounded-t-lg last:rounded-b-lg -mb-px last:mb-0 -outline-offset-2',
variants: {
isSelected: {
- false: 'hover:bg-gray-100 dark:hover:bg-zinc-700/60',
+ false: 'hover:bg-neutral-100 dark:hover:bg-neutral-700/60',
true: 'bg-blue-100 dark:bg-blue-700/30 hover:bg-blue-200 dark:hover:bg-blue-700/40 border-y-blue-200 dark:border-y-blue-900 z-20'
},
isDisabled: {
- true: 'text-slate-300 dark:text-zinc-600 forced-colors:text-[GrayText] z-10'
+ true: 'text-neutral-300 dark:text-neutral-600 forced-colors:text-[GrayText] z-10'
}
}
});
@@ -44,7 +44,7 @@ export function GridListItem({ children, ...props }: GridListItemProps) {
<>
{/* Add elements for drag and drop and selection. */}
{allowsDragging && ≡ }
- {selectionMode === 'multiple' && selectionBehavior === 'toggle' && (
+ {selectionMode !== 'none' && selectionBehavior === 'toggle' && (
)}
{children}
diff --git a/starters/tailwind/src/Link.tsx b/starters/tailwind/src/Link.tsx
index 051f93be07d..b85d20087a0 100644
--- a/starters/tailwind/src/Link.tsx
+++ b/starters/tailwind/src/Link.tsx
@@ -14,7 +14,7 @@ const styles = tv({
variants: {
variant: {
primary: 'text-blue-600 dark:text-blue-500 underline decoration-blue-600/60 hover:decoration-blue-600 dark:decoration-blue-500/60 dark:hover:decoration-blue-500',
- secondary: 'text-gray-700 dark:text-zinc-300 underline decoration-gray-700/50 hover:decoration-gray-700 dark:decoration-zinc-300/70 dark:hover:decoration-zinc-300'
+ secondary: 'text-neutral-700 dark:text-neutral-300 underline decoration-neutral-700/50 hover:decoration-neutral-700 dark:decoration-neutral-300/70 dark:hover:decoration-neutral-300'
}
},
defaultVariants: {
diff --git a/starters/tailwind/src/ListBox.tsx b/starters/tailwind/src/ListBox.tsx
index 97309a8fd00..bc62b7253f3 100644
--- a/starters/tailwind/src/ListBox.tsx
+++ b/starters/tailwind/src/ListBox.tsx
@@ -21,7 +21,7 @@ export function ListBox(
{ children, ...props }: ListBoxProps
) {
return (
-
+
{children}
);
@@ -32,11 +32,11 @@ export const itemStyles = tv({
base: 'group relative flex items-center gap-8 cursor-default select-none py-1.5 px-2.5 rounded-md will-change-transform text-sm forced-color-adjust-none',
variants: {
isSelected: {
- false: 'text-slate-700 dark:text-zinc-300 hover:bg-slate-200 dark:hover:bg-zinc-700 -outline-offset-2',
+ false: 'text-neutral-700 dark:text-neutral-300 hover:bg-neutral-100 dark:hover:bg-neutral-800 -outline-offset-2',
true: 'bg-blue-600 text-white forced-colors:bg-[Highlight] forced-colors:text-[HighlightText] [&:has(+[data-selected])]:rounded-b-none [&+[data-selected]]:rounded-t-none -outline-offset-4 outline-white dark:outline-white forced-colors:outline-[HighlightText]'
},
isDisabled: {
- true: 'text-slate-300 dark:text-zinc-600 forced-colors:text-[GrayText]'
+ true: 'text-neutral-300 dark:text-neutral-600 forced-colors:text-[GrayText]'
}
}
});
@@ -57,8 +57,8 @@ export const dropdownItemStyles = tv({
base: 'group flex items-center gap-4 cursor-default select-none py-2 pl-3 pr-1 rounded-lg outline outline-0 text-sm forced-color-adjust-none no-underline [&[href]]:cursor-pointer',
variants: {
isDisabled: {
- false: 'text-gray-900 dark:text-zinc-100',
- true: 'text-gray-300 dark:text-zinc-600 forced-colors:text-[GrayText]'
+ false: 'text-neutral-900 dark:text-neutral-100',
+ true: 'text-neutral-300 dark:text-neutral-600 forced-colors:text-[GrayText]'
},
isFocused: {
true: 'bg-blue-600 text-white forced-colors:bg-[Highlight] forced-colors:text-[HighlightText]'
@@ -68,7 +68,7 @@ export const dropdownItemStyles = tv({
{
isFocused: false,
isOpen: true,
- className: 'bg-gray-100 dark:bg-zinc-700/60'
+ className: 'bg-neutral-100 dark:bg-neutral-700/60'
}
]
});
@@ -97,7 +97,7 @@ export interface DropdownSectionProps extends SectionProps {
export function DropdownSection(props: DropdownSectionProps) {
return (
-
+
{props.children}
diff --git a/starters/tailwind/src/Menu.tsx b/starters/tailwind/src/Menu.tsx
index 22ab332abaa..01dfcd08b81 100644
--- a/starters/tailwind/src/Menu.tsx
+++ b/starters/tailwind/src/Menu.tsx
@@ -49,7 +49,7 @@ export function MenuItem(props: MenuItemProps) {
}
export function MenuSeparator(props: SeparatorProps) {
- return
+ return
}
export interface MenuSectionProps extends AriaMenuSectionProps {
@@ -60,7 +60,7 @@ export interface MenuSectionProps extends AriaMenuSectionProps {
export function MenuSection(props: MenuSectionProps) {
return (
- {props.title && }
+ {props.title && }
{props.children}
diff --git a/starters/tailwind/src/Meter.tsx b/starters/tailwind/src/Meter.tsx
index 382f2c7efb9..8006f986c96 100644
--- a/starters/tailwind/src/Meter.tsx
+++ b/starters/tailwind/src/Meter.tsx
@@ -19,12 +19,12 @@ export function Meter({ label, ...props }: MeterProps) {
<>
{label}
-
= 80 ? 'text-red-600 dark:text-red-500' : 'text-gray-600 dark:text-zinc-400'}`}>
+ = 80 ? 'text-red-600 dark:text-red-500' : 'text-neutral-600 dark:text-neutral-400'}`}>
{percentage >= 80 && }
{' ' + valueText}
-
+
>
diff --git a/starters/tailwind/src/Modal.tsx b/starters/tailwind/src/Modal.tsx
index 0384db68b23..80269f61b5b 100644
--- a/starters/tailwind/src/Modal.tsx
+++ b/starters/tailwind/src/Modal.tsx
@@ -16,7 +16,7 @@ const overlayStyles = tv({
});
const modalStyles = tv({
- base: 'font-sans w-full max-w-[min(90vw,450px)] max-h-[calc(var(--visual-viewport-height)*.9)] rounded-2xl bg-white dark:bg-zinc-800/70 dark:backdrop-blur-2xl dark:backdrop-saturate-200 forced-colors:bg-[Canvas] text-left align-middle text-slate-700 dark:text-zinc-300 shadow-2xl bg-clip-padding border border-black/10 dark:border-white/10',
+ base: 'font-sans w-full max-w-[min(90vw,450px)] max-h-[calc(var(--visual-viewport-height)*.9)] rounded-2xl bg-white dark:bg-neutral-800/70 dark:backdrop-blur-2xl dark:backdrop-saturate-200 forced-colors:bg-[Canvas] text-left align-middle text-neutral-700 dark:text-neutral-300 shadow-2xl bg-clip-padding border border-black/10 dark:border-white/10',
variants: {
isEntering: {
true: 'animate-in zoom-in-105 ease-out duration-200'
diff --git a/starters/tailwind/src/NumberField.tsx b/starters/tailwind/src/NumberField.tsx
index ac51df05f28..0f911aba6e6 100644
--- a/starters/tailwind/src/NumberField.tsx
+++ b/starters/tailwind/src/NumberField.tsx
@@ -25,12 +25,12 @@ export function NumberField(
{label}
{renderProps => (<>
-
-
+
+
-
+
@@ -44,5 +44,5 @@ export function NumberField(
}
function StepperButton(props: ButtonProps) {
- return
+ return
}
diff --git a/starters/tailwind/src/Popover.tsx b/starters/tailwind/src/Popover.tsx
index c0f471bd838..a24a628cd51 100644
--- a/starters/tailwind/src/Popover.tsx
+++ b/starters/tailwind/src/Popover.tsx
@@ -16,7 +16,7 @@ export interface PopoverProps extends Omit
{
}
const styles = tv({
- base: 'font-sans bg-white dark:bg-zinc-900/70 dark:backdrop-blur-2xl dark:backdrop-saturate-200 forced-colors:bg-[Canvas] shadow-2xl rounded-xl bg-clip-padding border border-black/10 dark:border-white/[15%] text-slate-700 dark:text-zinc-300 outline-0',
+ base: 'font-sans bg-white dark:bg-neutral-900/70 dark:backdrop-blur-2xl dark:backdrop-saturate-200 forced-colors:bg-[Canvas] shadow-2xl rounded-xl bg-clip-padding border border-black/10 dark:border-white/10 text-neutral-700 dark:text-neutral-300 outline-0',
variants: {
isEntering: {
true: 'animate-in fade-in placement-bottom:slide-in-from-top-1 placement-top:slide-in-from-bottom-1 placement-left:slide-in-from-right-1 placement-right:slide-in-from-left-1 ease-out duration-200'
@@ -36,7 +36,7 @@ export function Popover({ children, showArrow, className, ...props }: PopoverPro
className={composeRenderProps(className, (className, renderProps) => styles({...renderProps, className}))}>
{showArrow &&
-
+
diff --git a/starters/tailwind/src/ProgressBar.tsx b/starters/tailwind/src/ProgressBar.tsx
index 3108725237a..41c454203d6 100644
--- a/starters/tailwind/src/ProgressBar.tsx
+++ b/starters/tailwind/src/ProgressBar.tsx
@@ -18,10 +18,10 @@ export function ProgressBar({ label, ...props }: ProgressBarProps) {
<>
{label}
- {valueText}
+ {valueText}
-
-
+
>
)}
diff --git a/starters/tailwind/src/RadioGroup.tsx b/starters/tailwind/src/RadioGroup.tsx
index 67efc464df1..68d60e70f77 100644
--- a/starters/tailwind/src/RadioGroup.tsx
+++ b/starters/tailwind/src/RadioGroup.tsx
@@ -27,24 +27,24 @@ export function RadioGroup(props: RadioGroupProps) {
const styles = tv({
extend: focusRing,
- base: 'w-5 h-5 box-border rounded-full border-2 bg-white dark:bg-zinc-900 transition-all',
+ base: 'w-4.5 h-4.5 box-border rounded-full border bg-white dark:bg-neutral-900 transition-all',
variants: {
isSelected: {
- false: 'border-gray-400 dark:border-zinc-400 group-pressed:border-gray-500 dark:group-pressed:border-zinc-300',
- true: 'border-[7px] border-gray-700 dark:border-slate-300 forced-colors:border-[Highlight]! group-pressed:border-gray-800 dark:group-pressed:border-slate-200'
+ false: 'border-neutral-400 dark:border-neutral-400 group-pressed:border-neutral-500 dark:group-pressed:border-neutral-300',
+ true: 'border-[6px] border-neutral-700 dark:border-neutral-300 forced-colors:border-[Highlight]! group-pressed:border-neutral-800 dark:group-pressed:border-neutral-200'
},
isInvalid: {
true: 'border-red-700 dark:border-red-600 group-pressed:border-red-800 dark:group-pressed:border-red-700 forced-colors:border-[Mark]!'
},
isDisabled: {
- true: 'border-gray-200 dark:border-zinc-700 forced-colors:border-[GrayText]!'
+ true: 'border-neutral-200 dark:border-neutral-700 forced-colors:border-[GrayText]!'
}
}
});
export function Radio(props: RadioProps) {
return (
-
+
{composeRenderProps(props.children, (children, renderProps) => <>
{children}
diff --git a/starters/tailwind/src/RangeCalendar.tsx b/starters/tailwind/src/RangeCalendar.tsx
index d3423713fbc..fba146d73a3 100644
--- a/starters/tailwind/src/RangeCalendar.tsx
+++ b/starters/tailwind/src/RangeCalendar.tsx
@@ -19,10 +19,10 @@ export interface RangeCalendarProps extends Omit(
- {(date) =>
+ {(date) =>
{({formattedDate, isSelected, isSelectionStart, isSelectionEnd, isFocusVisible, isDisabled}) =>
{label && {label} }
-
-
+
+
diff --git a/starters/tailwind/src/Select.tsx b/starters/tailwind/src/Select.tsx
index 6975e187c29..e8f53163dd6 100644
--- a/starters/tailwind/src/Select.tsx
+++ b/starters/tailwind/src/Select.tsx
@@ -18,11 +18,11 @@ import { composeTailwindRenderProps, focusRing } from './utils';
const styles = tv({
extend: focusRing,
- base: 'flex items-center text-start gap-4 w-full cursor-default border border-black/10 dark:border-white/10 shadow-[inset_0_1px_0_0_rgba(255,255,255,0.1)] dark:shadow-none rounded-lg pl-3 pr-2 py-2 min-w-[150px] transition bg-gray-50 dark:bg-zinc-900',
+ base: 'flex items-center text-start gap-4 w-full font-sans border border-black/10 dark:border-white/10 cursor-default rounded-lg pl-3 pr-2 h-9 min-w-[180px] transition bg-neutral-50 dark:bg-neutral-700',
variants: {
isDisabled: {
- false: 'text-gray-800 dark:text-zinc-300 hover:bg-gray-100 pressed:bg-gray-200 dark:hover:bg-zinc-800 dark:pressed:bg-zinc-700 group-invalid:border-red-600 forced-colors:group-invalid:border-[Mark]',
- true: 'text-gray-200 dark:text-zinc-600 forced-colors:text-[GrayText] dark:bg-zinc-800 dark:border-white/5 forced-colors:border-[GrayText]'
+ false: 'text-neutral-800 dark:text-neutral-300 hover:bg-neutral-100 pressed:bg-neutral-200 dark:hover:bg-neutral-600 dark:pressed:bg-neutral-500 group-invalid:outline group-invalid:outline-red-600 forced-colors:group-invalid:outline-[Mark]',
+ true: 'border-transparent dark:border-transparent text-neutral-200 dark:text-neutral-600 forced-colors:text-[GrayText] bg-neutral-100 dark:bg-neutral-800'
}
}
});
@@ -42,10 +42,10 @@ export function Select(
{label && {label} }
-
+
{({selectedText, defaultChildren}) => selectedText || defaultChildren}
-
+
{description && {description} }
{errorMessage}
diff --git a/starters/tailwind/src/Separator.tsx b/starters/tailwind/src/Separator.tsx
index 80a8a9b8068..f4ac33b5f11 100644
--- a/starters/tailwind/src/Separator.tsx
+++ b/starters/tailwind/src/Separator.tsx
@@ -4,7 +4,7 @@ import { Separator as RACSeparator, SeparatorProps } from 'react-aria-components
import { tv } from 'tailwind-variants';
const styles = tv({
- base: 'bg-gray-300 dark:bg-zinc-600 forced-colors:bg-[ButtonBorder]',
+ base: 'bg-neutral-300 dark:bg-neutral-600 forced-colors:bg-[ButtonBorder]',
variants: {
orientation: {
horizontal: 'h-px w-full',
diff --git a/starters/tailwind/src/Slider.tsx b/starters/tailwind/src/Slider.tsx
index 66c96ce635d..866afe343b1 100644
--- a/starters/tailwind/src/Slider.tsx
+++ b/starters/tailwind/src/Slider.tsx
@@ -19,21 +19,35 @@ const trackStyles = tv({
vertical: 'h-full w-[6px] ml-[50%] -translate-x-[50%]'
},
isDisabled: {
- false: 'bg-gray-300 dark:bg-zinc-500 forced-colors:bg-[ButtonBorder]',
- true: 'bg-gray-200 dark:bg-zinc-800 forced-colors:bg-[GrayText]'
+ false: 'bg-neutral-300 dark:bg-neutral-700 forced-colors:bg-[ButtonBorder]',
+ true: 'bg-neutral-200 dark:bg-neutral-800 forced-colors:bg-[ButtonBorder]'
+ }
+ }
+});
+
+const fillStyles = tv({
+ base: 'absolute rounded-full',
+ variants: {
+ orientation: {
+ horizontal: 'w-(--size) h-[6px] start-(--start,0)',
+ vertical: 'h-(--size) w-[6px] bottom-(--start,0) ml-[50%] -translate-x-[50%]'
+ },
+ isDisabled: {
+ false: 'bg-blue-500 forced-colors:bg-[Highlight]',
+ true: 'bg-neutral-300 dark:bg-neutral-600 forced-colors:bg-[GrayText]'
}
}
});
const thumbStyles = tv({
extend: focusRing,
- base: 'w-5 h-5 group-orientation-horizontal:mt-6 group-orientation-vertical:ml-3 rounded-full bg-gray-50 dark:bg-zinc-900 border-2 border-gray-700 dark:border-gray-300',
+ base: 'w-4.5 h-4.5 group-orientation-horizontal:mt-5 group-orientation-vertical:ml-2.5 rounded-full bg-neutral-50 dark:bg-neutral-900 border border-neutral-700 dark:border-neutral-300',
variants: {
isDragging: {
- true: 'bg-gray-700 dark:bg-gray-300 forced-colors:bg-[ButtonBorder]'
+ true: 'bg-neutral-700 dark:bg-neutral-300 forced-colors:bg-[ButtonBorder]'
},
isDisabled: {
- true: 'border-gray-300 dark:border-zinc-700 forced-colors:border-[GrayText]'
+ true: 'border-neutral-300 dark:border-neutral-700 forced-colors:border-[GrayText]'
}
}
});
@@ -49,12 +63,23 @@ export function Slider(
return (
{label}
-
+
{({ state }) => state.values.map((_, i) => state.getThumbValueLabel(i)).join(' – ')}
{({ state, ...renderProps }) => <>
+ {state.values.length === 1
+ // Single thumb, render fill from the end
+ ?
+ : state.values.length === 2
+ // Range slider, render fill between the thumbs
+ ?
+ : null}
{state.values.map((_, i) => )}
>}
diff --git a/starters/tailwind/src/Switch.tsx b/starters/tailwind/src/Switch.tsx
index f9edef5afaf..b07c26727d5 100644
--- a/starters/tailwind/src/Switch.tsx
+++ b/starters/tailwind/src/Switch.tsx
@@ -13,34 +13,46 @@ export interface SwitchProps extends Omit {
const track = tv({
extend: focusRing,
- base: 'flex h-4 w-7 box-border px-px items-center shrink-0 cursor-default rounded-full transition duration-200 ease-in-out shadow-inner border border-transparent font-sans',
+ base: 'flex h-5 w-9 box-border px-px items-center shrink-0 cursor-default rounded-full transition duration-200 ease-in-out shadow-inner border border-transparent font-sans',
variants: {
isSelected: {
- false: 'bg-gray-400 dark:bg-zinc-400 group-pressed:bg-gray-500 dark:group-pressed:bg-zinc-300',
- true: 'bg-gray-700 dark:bg-zinc-300 forced-colors:bg-[Highlight]! group-pressed:bg-gray-800 dark:group-pressed:bg-zinc-200',
+ false: 'bg-neutral-100 dark:bg-neutral-800 group-pressed:bg-neutral-200 dark:group-pressed:bg-neutral-700 border-neutral-400 dark:border-neutral-400',
+ true: 'bg-neutral-700 dark:bg-neutral-300 forced-colors:bg-[Highlight]! group-pressed:bg-neutral-800 dark:group-pressed:bg-neutral-200',
},
isDisabled: {
- true: 'bg-gray-200 dark:bg-zinc-700 forced-colors:group-selected:bg-[GrayText]! forced-colors:border-[GrayText]',
+ true: 'bg-neutral-100 dark:bg-neutral-800 group-selected:bg-neutral-300 dark:group-selected:bg-neutral-800 forced-colors:group-selected:bg-[GrayText]! border-neutral-300 dark:border-neutral-900 forced-colors:border-[GrayText]',
}
}
});
const handle = tv({
- base: 'h-3 w-3 transform rounded-full bg-white dark:bg-zinc-900 outline outline-1 -outline-offset-1 outline-transparent shadow-xs transition duration-200 ease-in-out',
+ base: 'h-4 w-4 transform rounded-full outline outline-1 -outline-offset-1 outline-transparent shadow-xs transition duration-200 ease-in-out',
variants: {
isSelected: {
- false: 'translate-x-0',
- true: 'translate-x-[100%]'
+ false: 'translate-x-0 bg-neutral-900 dark:bg-neutral-300',
+ true: 'translate-x-[100%] bg-white dark:bg-neutral-900'
},
isDisabled: {
true: 'forced-colors:outline-[GrayText]'
}
- }
+ },
+ compoundVariants: [
+ {
+ isSelected: false,
+ isDisabled: true,
+ class: 'bg-neutral-300 dark:bg-neutral-700'
+ },
+ {
+ isSelected: true,
+ isDisabled: true,
+ class: 'bg-neutral-50 dark:bg-neutral-700'
+ }
+ ]
});
export function Switch({ children, ...props }: SwitchProps) {
return (
-
+
{(renderProps) => (
<>
diff --git a/starters/tailwind/src/Table.tsx b/starters/tailwind/src/Table.tsx
index 62298acabc5..a1455d41cca 100644
--- a/starters/tailwind/src/Table.tsx
+++ b/starters/tailwind/src/Table.tsx
@@ -33,7 +33,7 @@ interface TableProps extends Omit
{
export function Table(props: TableProps) {
return (
-
+
);
@@ -46,12 +46,12 @@ const columnStyles = tv({
const resizerStyles = tv({
extend: focusRing,
- base: 'w-px px-[8px] translate-x-[8px] box-content py-1 h-5 bg-clip-content bg-gray-400 dark:bg-zinc-500 forced-colors:bg-[ButtonBorder] cursor-col-resize rounded-xs resizing:bg-blue-600 forced-colors:resizing:bg-[Highlight] resizing:w-[2px] resizing:pl-[7px] -outline-offset-2'
+ base: 'w-px px-[8px] translate-x-[8px] box-content py-1 h-5 bg-clip-content bg-neutral-400 dark:bg-neutral-500 forced-colors:bg-[ButtonBorder] cursor-col-resize rounded-xs resizing:bg-blue-600 forced-colors:resizing:bg-[Highlight] resizing:w-[2px] resizing:pl-[7px] -outline-offset-2'
});
export function Column(props: ColumnProps) {
return (
-
+
{composeRenderProps(props.children, (children, { allowsSorting, sortDirection }) => (
- {sortDirection && }
+ {sortDirection && }
)}
@@ -81,7 +81,7 @@ export function TableHeader
(props: TableHeaderProps) {
let { selectionBehavior, selectionMode, allowsDragging } = useTableOptions();
return (
-
+
{/* Add extra columns for drag and drop and selection. */}
{allowsDragging && }
{selectionBehavior === 'toggle' && (
@@ -106,7 +106,7 @@ export function TableBody(props: TableBodyProps) {
const rowStyles = tv({
extend: focusRing,
- base: 'group/row relative cursor-default select-none -outline-offset-2 text-gray-900 disabled:text-gray-300 dark:text-zinc-200 dark:disabled:text-zinc-600 text-sm hover:bg-gray-100 dark:hover:bg-zinc-700/60 selected:bg-blue-100 selected:hover:bg-blue-200 dark:selected:bg-blue-700/30 dark:selected:hover:bg-blue-700/40'
+ base: 'group/row relative cursor-default select-none -outline-offset-2 text-neutral-900 disabled:text-neutral-300 dark:text-neutral-200 dark:disabled:text-neutral-600 text-sm hover:bg-neutral-100 dark:hover:bg-neutral-800 selected:bg-blue-100 selected:hover:bg-blue-200 dark:selected:bg-blue-700/30 dark:selected:hover:bg-blue-700/40'
});
export function Row(
@@ -135,7 +135,7 @@ export function Row(
const cellStyles = tv({
extend: focusRing,
- base: 'box-border border-b border-b-gray-200 dark:border-b-zinc-700 group-last/row:border-b-0 [--selected-border:var(--color-blue-200)] dark:[--selected-border:var(--color-blue-900)] group-selected/row:border-(--selected-border) in-[:has(+[data-selected])]:border-(--selected-border) p-2 truncate -outline-offset-2'
+ base: 'box-border border-b border-b-neutral-200 dark:border-b-neutral-700 group-last/row:border-b-0 [--selected-border:var(--color-blue-200)] dark:[--selected-border:var(--color-blue-900)] group-selected/row:border-(--selected-border) in-[:has(+[data-selected])]:border-(--selected-border) p-2 truncate -outline-offset-2'
});
export function Cell(props: CellProps) {
diff --git a/starters/tailwind/src/Tabs.tsx b/starters/tailwind/src/Tabs.tsx
index 9440dac0420..9855d8094c1 100644
--- a/starters/tailwind/src/Tabs.tsx
+++ b/starters/tailwind/src/Tabs.tsx
@@ -65,7 +65,7 @@ const tabProps = tv({
base: 'group relative flex items-center cursor-default rounded-full px-4 py-1.5 text-sm font-medium transition forced-color-adjust-none',
variants: {
isDisabled: {
- true: 'text-gray-200 dark:text-zinc-600 forced-colors:text-[GrayText] selected:text-white dark:selected:text-zinc-500 forced-colors:selected:text-[HighlightText] selected:bg-gray-200 dark:selected:bg-zinc-600 forced-colors:selected:bg-[GrayText]'
+ true: 'text-neutral-200 dark:text-neutral-600 forced-colors:text-[GrayText] selected:text-white dark:selected:text-neutral-500 forced-colors:selected:text-[HighlightText] selected:bg-neutral-200 dark:selected:bg-neutral-600 forced-colors:selected:bg-[GrayText]'
}
}
});
@@ -80,7 +80,7 @@ export function Tab(props: TabProps) {
)}>
{composeRenderProps(props.children, children => (<>
{children}
-
+
>))}
);
@@ -96,7 +96,7 @@ export function TabPanels(props: TabPanelsProps) {
const tabPanelStyles = tv({
extend: focusRing,
- base: 'flex-1 box-border p-4 text-sm text-gray-900 dark:text-zinc-100 transition entering:opacity-0 exiting:opacity-0 exiting:absolute exiting:top-0 exiting:left-0 exiting:w-full'
+ base: 'flex-1 box-border p-4 text-sm text-neutral-900 dark:text-neutral-100 transition entering:opacity-0 exiting:opacity-0 exiting:absolute exiting:top-0 exiting:left-0 exiting:w-full'
});
export function TabPanel(props: TabPanelProps) {
diff --git a/starters/tailwind/src/TagGroup.tsx b/starters/tailwind/src/TagGroup.tsx
index 883c3b58088..a71acf60850 100644
--- a/starters/tailwind/src/TagGroup.tsx
+++ b/starters/tailwind/src/TagGroup.tsx
@@ -18,7 +18,7 @@ import { Description, Label } from './Field';
import { focusRing } from './utils';
const colors = {
- gray: 'bg-white text-gray-600 border-gray-200 hover:border-gray-300 dark:bg-zinc-900 dark:text-zinc-300 dark:border-zinc-600 dark:hover:border-zinc-500',
+ gray: 'bg-white text-neutral-600 border-neutral-200 hover:border-neutral-300 dark:bg-neutral-900 dark:text-neutral-300 dark:border-neutral-600 dark:hover:border-neutral-500',
green: 'bg-green-100 text-green-700 border-green-200 hover:border-green-300 dark:bg-green-300/20 dark:text-green-400 dark:border-green-300/10 dark:hover:border-green-300/20',
yellow: 'bg-yellow-100 text-yellow-700 border-yellow-200 hover:border-yellow-300 dark:bg-yellow-300/20 dark:text-yellow-400 dark:border-yellow-300/10 dark:hover:border-yellow-300/20',
blue: 'bg-blue-100 text-blue-700 border-blue-200 hover:border-blue-300 dark:bg-blue-400/20 dark:text-blue-300 dark:border-blue-400/10 dark:hover:border-blue-400/20'
@@ -44,7 +44,7 @@ const tagStyles = tv({
true: 'bg-blue-600 text-white border-transparent forced-colors:bg-[Highlight] forced-colors:text-[HighlightText] forced-color-adjust-none'
},
isDisabled: {
- true: 'bg-gray-100 dark:bg-transparent dark:border-white/20 text-gray-300 dark:text-zinc-600 forced-colors:text-[GrayText]'
+ true: 'bg-neutral-100 dark:bg-transparent dark:border-white/20 text-neutral-300 dark:text-neutral-600 forced-colors:text-[GrayText]'
}
},
compoundVariants: (Object.keys(colors) as Color[]).map((color) => ({
diff --git a/starters/tailwind/src/TextField.tsx b/starters/tailwind/src/TextField.tsx
index 012d7cf7ff8..40606b5a5cc 100644
--- a/starters/tailwind/src/TextField.tsx
+++ b/starters/tailwind/src/TextField.tsx
@@ -11,7 +11,7 @@ import { composeTailwindRenderProps, focusRing } from './utils';
const inputStyles = tv({
extend: focusRing,
- base: 'border-2 rounded-lg',
+ base: 'border-1 rounded-lg min-h-9 font-sans py-0 px-3 box-border transition',
variants: {
isFocused: fieldBorderStyles.variants.isFocusWithin,
isInvalid: fieldBorderStyles.variants.isInvalid,
@@ -22,6 +22,7 @@ const inputStyles = tv({
export interface TextFieldProps extends AriaTextFieldProps {
label?: string;
description?: string;
+ placeholder?: string;
errorMessage?: string | ((validation: ValidationResult) => string);
}
diff --git a/starters/tailwind/src/ToggleButton.tsx b/starters/tailwind/src/ToggleButton.tsx
index e2a18c062e1..8d07377891e 100644
--- a/starters/tailwind/src/ToggleButton.tsx
+++ b/starters/tailwind/src/ToggleButton.tsx
@@ -6,14 +6,14 @@ import { focusRing } from './utils';
let styles = tv({
extend: focusRing,
- base: 'font-sans px-5 py-2 [&:has(svg:only-child)]:px-2 inline-flex items-center text-sm text-center transition rounded-lg border border-black/10 dark:border-white/10 forced-colors:border-[ButtonBorder] shadow-[inset_0_1px_0_0_rgba(255,255,255,0.1)] dark:shadow-none cursor-default forced-color-adjust-none',
+ base: 'relative inline-flex items-center justify-center gap-2 border border-black/10 dark:border-white/10 h-9 box-border px-3.5 [&:has(>svg:only-child)]:px-0 [&:has(>svg:only-child)]:h-8 [&:has(>svg:only-child)]:aspect-square font-sans text-sm text-center transition rounded-lg cursor-default forced-color-adjust-none',
variants: {
isSelected: {
- false: 'bg-gray-50 hover:bg-gray-100 pressed:bg-gray-200 text-gray-800 dark:bg-zinc-600 dark:hover:bg-zinc-500 dark:pressed:bg-zinc-400 dark:text-zinc-100 forced-colors:bg-[ButtonFace]! forced-colors:text-[ButtonText]!',
- true: 'bg-gray-700 hover:bg-gray-800 pressed:bg-gray-900 text-white dark:bg-slate-300 dark:hover:bg-slate-200 dark:pressed:bg-slate-100 dark:text-black forced-colors:bg-[Highlight]! forced-colors:text-[HighlightText]!'
+ false: 'bg-neutral-50 hover:bg-neutral-100 pressed:bg-neutral-200 text-neutral-800 dark:bg-neutral-700 dark:hover:bg-neutral-600 dark:pressed:bg-neutral-500 dark:text-neutral-100 forced-colors:bg-[ButtonFace]! forced-colors:text-[ButtonText]!',
+ true: 'bg-neutral-700 hover:bg-neutral-800 pressed:bg-neutral-900 text-white dark:bg-neutral-300 dark:hover:bg-neutral-200 dark:pressed:bg-neutral-100 dark:text-black forced-colors:bg-[Highlight]! forced-colors:text-[HighlightText]!'
},
isDisabled: {
- true: 'bg-gray-100 dark:bg-zinc-800 forced-colors:bg-[ButtonFace]! text-gray-300 dark:text-zinc-600 forced-colors:text-[GrayText]! border-black/5 dark:border-white/5 forced-colors:border-[GrayText]'
+ true: 'border-transparent dark:border-transparent bg-neutral-100 dark:bg-neutral-800 forced-colors:bg-[ButtonFace]! text-neutral-300 dark:text-neutral-600 forced-colors:text-[GrayText]!'
}
}
});
diff --git a/starters/tailwind/src/ToggleButtonGroup.tsx b/starters/tailwind/src/ToggleButtonGroup.tsx
index 71402bebc03..bc45c9f82f4 100644
--- a/starters/tailwind/src/ToggleButtonGroup.tsx
+++ b/starters/tailwind/src/ToggleButtonGroup.tsx
@@ -17,6 +17,6 @@ export function ToggleButtonGroup(props: ToggleButtonGroupProps) {
return (
styles({orientation: props.orientation || 'horizontal', className}))} />
+ className={composeRenderProps(props.className, (className, renderProps) => styles({...renderProps, className}))} />
);
}
diff --git a/starters/tailwind/src/Toolbar.tsx b/starters/tailwind/src/Toolbar.tsx
index ad965ae47a7..68717897c33 100644
--- a/starters/tailwind/src/Toolbar.tsx
+++ b/starters/tailwind/src/Toolbar.tsx
@@ -1,6 +1,6 @@
'use client';
import React from 'react';
-import { Toolbar as RACToolbar, ToolbarProps, composeRenderProps } from 'react-aria-components';
+import { Toolbar as RACToolbar, ToggleButtonGroupContext, ToolbarProps, composeRenderProps } from 'react-aria-components';
import { tv } from 'tailwind-variants';
const styles = tv({
@@ -15,11 +15,13 @@ const styles = tv({
export function Toolbar(props: ToolbarProps) {
return (
- styles({...renderProps, className})
- )} />
+
+ styles({...renderProps, className})
+ )} />
+
);
}
diff --git a/starters/tailwind/src/Tooltip.tsx b/starters/tailwind/src/Tooltip.tsx
index d42140bb2a7..f1995988a20 100644
--- a/starters/tailwind/src/Tooltip.tsx
+++ b/starters/tailwind/src/Tooltip.tsx
@@ -13,7 +13,7 @@ export interface TooltipProps extends Omit {
}
const styles = tv({
- base: 'group bg-slate-700 dark:bg-slate-600 border border-slate-800 dark:border-white/10 shadow-[inset_0_1px_0_0_var(--color-gray-600)] dark:shadow-none font-sans text-white text-sm rounded-lg drop-shadow-lg will-change-transform px-3 py-1 box-border',
+ base: 'group bg-neutral-700 dark:bg-neutral-600 border border-neutral-800 dark:border-white/10 font-sans text-xs text-white rounded-lg drop-shadow-lg will-change-transform px-3 py-1.5 box-border',
variants: {
isEntering: {
true: 'animate-in fade-in placement-bottom:slide-in-from-top-0.5 placement-top:slide-in-from-bottom-0.5 placement-left:slide-in-from-right-0.5 placement-right:slide-in-from-left-0.5 ease-out duration-200'
@@ -28,7 +28,7 @@ export function Tooltip({ children, ...props }: TooltipProps) {
return (
styles({...renderProps, className}))}>
-
+
diff --git a/starters/tailwind/src/Tree.tsx b/starters/tailwind/src/Tree.tsx
index 703c25209c8..bd821a6036a 100644
--- a/starters/tailwind/src/Tree.tsx
+++ b/starters/tailwind/src/Tree.tsx
@@ -16,14 +16,14 @@ import { composeTailwindRenderProps, focusRing } from './utils';
const itemStyles = tv({
extend: focusRing,
- base: 'relative font-sans w-48 flex group gap-3 cursor-default select-none py-1 px-3 text-sm text-gray-900 dark:text-zinc-200 bg-white dark:bg-zinc-900 border-y dark:border-y-zinc-700 border-transparent first:border-t-0 last:border-b-0 -mb-px last:mb-0 -outline-offset-2',
+ base: 'relative font-sans w-48 flex group gap-3 cursor-default select-none py-1 px-3 text-sm text-neutral-900 dark:text-neutral-200 bg-white dark:bg-neutral-900 border-y dark:border-y-neutral-700 border-transparent first:border-t-0 last:border-b-0 -mb-px last:mb-0 -outline-offset-2',
variants: {
isSelected: {
- false: 'hover:bg-gray-100 dark:hover:bg-zinc-700/60',
+ false: 'hover:bg-neutral-100 dark:hover:bg-neutral-800',
true: 'bg-blue-100 dark:bg-blue-700/30 hover:bg-blue-200 dark:hover:bg-blue-700/40 border-y-blue-200 dark:border-y-blue-900 z-20'
},
isDisabled: {
- true: 'text-slate-300 dark:text-zinc-600 forced-colors:text-[GrayText] z-10'
+ true: 'text-neutral-300 dark:text-neutral-600 forced-colors:text-[GrayText] z-10'
}
}
});
@@ -32,7 +32,7 @@ export function Tree(
{ children, ...props }: TreeProps
) {
return (
-
+
{children}
);
@@ -43,19 +43,19 @@ const expandButton = tv({
base: "border-0 p-0 bg-transparent shrink-0 w-8 h-8 rounded-lg flex items-center justify-center text-start cursor-default",
variants: {
isDisabled: {
- true: 'text-gray-300 dark:text-zinc-600 forced-colors:text-[GrayText]'
+ true: 'text-neutral-300 dark:text-neutral-600 forced-colors:text-[GrayText]'
}
}
});
const chevron = tv({
- base: "w-5 h-5 text-gray-500 dark:text-gray-400 transition-transform duration-200 ease-in-out",
+ base: "w-4.5 h-4.5 text-neutral-500 dark:text-neutral-400 transition-transform duration-200 ease-in-out",
variants: {
isExpanded: {
true: "transform rotate-90",
},
isDisabled: {
- true: 'text-gray-300 dark:text-zinc-600 forced-colors:text-[GrayText]'
+ true: 'text-neutral-300 dark:text-neutral-600 forced-colors:text-[GrayText]'
}
}
});
@@ -70,7 +70,7 @@ export function TreeItem(props: TreeItemProps) {
{({ selectionMode, selectionBehavior, hasChildItems, isExpanded, isDisabled }) => (
- {selectionMode === 'multiple' && selectionBehavior === 'toggle' && (
+ {selectionMode !== 'none' && selectionBehavior === 'toggle' && (
)}
diff --git a/starters/tailwind/src/index.css b/starters/tailwind/src/index.css
index 660c03d7239..6aae06b15a6 100644
--- a/starters/tailwind/src/index.css
+++ b/starters/tailwind/src/index.css
@@ -15,6 +15,6 @@
}
body {
- @apply bg-white dark:bg-zinc-900;
+ @apply bg-white dark:bg-neutral-900;
color-scheme: dark light;
}
diff --git a/yarn.lock b/yarn.lock
index d2748c1e4b3..a0603f25eaa 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -10631,6 +10631,13 @@ __metadata:
languageName: node
linkType: hard
+"@types/parse5@npm:^6.0.0":
+ version: 6.0.3
+ resolution: "@types/parse5@npm:6.0.3"
+ checksum: 10c0/a7c7ef6625974b74b93c1105953003a2291897e453369efcadc569b907de2784d61d4e6905de3ef959fa07f3278f41ed0c22ead0173776023fc43b6ed31042d0
+ languageName: node
+ linkType: hard
+
"@types/react-dom@npm:19.1.6":
version: 19.1.6
resolution: "@types/react-dom@npm:19.1.6"
@@ -12957,6 +12964,13 @@ __metadata:
languageName: node
linkType: hard
+"ccount@npm:^2.0.0":
+ version: 2.0.1
+ resolution: "ccount@npm:2.0.1"
+ checksum: 10c0/3939b1664390174484322bc3f45b798462e6c07ee6384cb3d645e0aa2f318502d174845198c1561930e1d431087f74cf1fe291ae9a4722821a9f4ba67e574350
+ languageName: node
+ linkType: hard
+
"chai@npm:^5.1.1":
version: 5.2.0
resolution: "chai@npm:5.2.0"
@@ -17697,6 +17711,49 @@ __metadata:
languageName: node
linkType: hard
+"hast-util-from-parse5@npm:^7.0.0":
+ version: 7.1.2
+ resolution: "hast-util-from-parse5@npm:7.1.2"
+ dependencies:
+ "@types/hast": "npm:^2.0.0"
+ "@types/unist": "npm:^2.0.0"
+ hastscript: "npm:^7.0.0"
+ property-information: "npm:^6.0.0"
+ vfile: "npm:^5.0.0"
+ vfile-location: "npm:^4.0.0"
+ web-namespaces: "npm:^2.0.0"
+ checksum: 10c0/c1002816d0235ff0a1e888d71c191d3ecfbaba510aaef86eec00edcba8803a3e0ad901bb0e5430a9d2aee2d52c31aabacae8282394dc519c333017a46c68d1c8
+ languageName: node
+ linkType: hard
+
+"hast-util-parse-selector@npm:^3.0.0":
+ version: 3.1.1
+ resolution: "hast-util-parse-selector@npm:3.1.1"
+ dependencies:
+ "@types/hast": "npm:^2.0.0"
+ checksum: 10c0/34ac1707a477fd9764e328087163f1f21857bdb0f8d425bf41f6def7baf840e50e4bca2eb03072e3da4e39856de28893c4b688dcba0cc305160d53afcece4df4
+ languageName: node
+ linkType: hard
+
+"hast-util-raw@npm:^7.0.0":
+ version: 7.2.3
+ resolution: "hast-util-raw@npm:7.2.3"
+ dependencies:
+ "@types/hast": "npm:^2.0.0"
+ "@types/parse5": "npm:^6.0.0"
+ hast-util-from-parse5: "npm:^7.0.0"
+ hast-util-to-parse5: "npm:^7.0.0"
+ html-void-elements: "npm:^2.0.0"
+ parse5: "npm:^6.0.0"
+ unist-util-position: "npm:^4.0.0"
+ unist-util-visit: "npm:^4.0.0"
+ vfile: "npm:^5.0.0"
+ web-namespaces: "npm:^2.0.0"
+ zwitch: "npm:^2.0.0"
+ checksum: 10c0/c7bf994938cbc1acaaeb337f99773773b51ad77695b559c6352cba5c35b26610e6de2936b5086ef8bc53b436dd8032a3860e7357f28b6bb0365f751919745398
+ languageName: node
+ linkType: hard
+
"hast-util-to-estree@npm:^2.0.0":
version: 2.0.2
resolution: "hast-util-to-estree@npm:2.0.2"
@@ -17719,6 +17776,39 @@ __metadata:
languageName: node
linkType: hard
+"hast-util-to-html@npm:^8.0.0":
+ version: 8.0.4
+ resolution: "hast-util-to-html@npm:8.0.4"
+ dependencies:
+ "@types/hast": "npm:^2.0.0"
+ "@types/unist": "npm:^2.0.0"
+ ccount: "npm:^2.0.0"
+ comma-separated-tokens: "npm:^2.0.0"
+ hast-util-raw: "npm:^7.0.0"
+ hast-util-whitespace: "npm:^2.0.0"
+ html-void-elements: "npm:^2.0.0"
+ property-information: "npm:^6.0.0"
+ space-separated-tokens: "npm:^2.0.0"
+ stringify-entities: "npm:^4.0.0"
+ zwitch: "npm:^2.0.4"
+ checksum: 10c0/a9dd87cdd710dcd151d144152ec6d2c6d20377b8258b31776e1387868fab8e3e0552d237c337d84dc94407b935a47e2e344b1cf8bd3ce16541c934004879c33f
+ languageName: node
+ linkType: hard
+
+"hast-util-to-parse5@npm:^7.0.0":
+ version: 7.1.0
+ resolution: "hast-util-to-parse5@npm:7.1.0"
+ dependencies:
+ "@types/hast": "npm:^2.0.0"
+ comma-separated-tokens: "npm:^2.0.0"
+ property-information: "npm:^6.0.0"
+ space-separated-tokens: "npm:^2.0.0"
+ web-namespaces: "npm:^2.0.0"
+ zwitch: "npm:^2.0.0"
+ checksum: 10c0/2a96302b8f25fa2d5b657a94bb20a3d9a1a81e66c2f81582a242c5634dd850e3bd95313a7471eef8282b597f2129551fef5a1631f4ce14c41aab646281b339a0
+ languageName: node
+ linkType: hard
+
"hast-util-whitespace@npm:^2.0.0":
version: 2.0.0
resolution: "hast-util-whitespace@npm:2.0.0"
@@ -17726,6 +17816,19 @@ __metadata:
languageName: node
linkType: hard
+"hastscript@npm:^7.0.0":
+ version: 7.2.0
+ resolution: "hastscript@npm:7.2.0"
+ dependencies:
+ "@types/hast": "npm:^2.0.0"
+ comma-separated-tokens: "npm:^2.0.0"
+ hast-util-parse-selector: "npm:^3.0.0"
+ property-information: "npm:^6.0.0"
+ space-separated-tokens: "npm:^2.0.0"
+ checksum: 10c0/579912b03ff4a5b19eb609df7403c6dba2505ef1a1e2bc47cbf467cbd7cffcd51df40e74d882de1ccdda40aaf18487f82619eb9cb9f2077cba778017e95e868e
+ languageName: node
+ linkType: hard
+
"hermes-estree@npm:0.25.1":
version: 0.25.1
resolution: "hermes-estree@npm:0.25.1"
@@ -17802,6 +17905,13 @@ __metadata:
languageName: node
linkType: hard
+"html-void-elements@npm:^2.0.0":
+ version: 2.0.1
+ resolution: "html-void-elements@npm:2.0.1"
+ checksum: 10c0/1079c9e9fdb3b6a2481f2a282098a0183f3d45bf2b9d76c7dfc1671ee1857d7bacdd04fd8c6e2418f5ff550c30cabf97a010fe31ec402d0c89189807b48e6d79
+ languageName: node
+ linkType: hard
+
"htmlparser2@npm:^3.9.2":
version: 3.10.1
resolution: "htmlparser2@npm:3.10.1"
@@ -23531,6 +23641,13 @@ __metadata:
languageName: node
linkType: hard
+"parse5@npm:^6.0.0":
+ version: 6.0.1
+ resolution: "parse5@npm:6.0.1"
+ checksum: 10c0/595821edc094ecbcfb9ddcb46a3e1fe3a718540f8320eff08b8cf6742a5114cce2d46d45f95c26191c11b184dcaf4e2960abcd9c5ed9eb9393ac9a37efcfdecb
+ languageName: node
+ linkType: hard
+
"parse5@npm:^7.0.0, parse5@npm:^7.1.1":
version: 7.1.2
resolution: "parse5@npm:7.1.2"
@@ -24704,6 +24821,7 @@ __metadata:
recast: "npm:^0.23"
recursive-readdir: "npm:^2.2.2"
regenerator-runtime: "npm:0.13.3"
+ rehype-stringify: "npm:^9.0.4"
rimraf: "npm:^6.0.1"
sharp: "npm:^0.33.5"
storybook: "npm:^8.6.14"
@@ -25169,6 +25287,17 @@ __metadata:
languageName: node
linkType: hard
+"rehype-stringify@npm:^9.0.4":
+ version: 9.0.4
+ resolution: "rehype-stringify@npm:9.0.4"
+ dependencies:
+ "@types/hast": "npm:^2.0.0"
+ hast-util-to-html: "npm:^8.0.0"
+ unified: "npm:^10.0.0"
+ checksum: 10c0/8c8bc118c3e3242a6126456c35af5f902a168ec8daab7b97f6bfeafa5ced2c23fbe2807776908ecec8ed17a9ef67c6f6d473ff54c28c1d6a711624505a551078
+ languageName: node
+ linkType: hard
+
"release-zalgo@npm:^1.0.0":
version: 1.0.0
resolution: "release-zalgo@npm:1.0.0"
@@ -28832,6 +28961,16 @@ __metadata:
languageName: node
linkType: hard
+"vfile-location@npm:^4.0.0":
+ version: 4.1.0
+ resolution: "vfile-location@npm:4.1.0"
+ dependencies:
+ "@types/unist": "npm:^2.0.0"
+ vfile: "npm:^5.0.0"
+ checksum: 10c0/77097e819579214d3346aaa2b06e4d23e2413221ac4914679d312cf64973011b76f0e2424fa8f18987befcd6ed60f4f6c4c6ebd5d5326062173a95f6b4445a96
+ languageName: node
+ linkType: hard
+
"vfile-message@npm:^3.0.0":
version: 3.0.2
resolution: "vfile-message@npm:3.0.2"
@@ -29018,6 +29157,13 @@ __metadata:
languageName: node
linkType: hard
+"web-namespaces@npm:^2.0.0":
+ version: 2.0.1
+ resolution: "web-namespaces@npm:2.0.1"
+ checksum: 10c0/df245f466ad83bd5cd80bfffc1674c7f64b7b84d1de0e4d2c0934fb0782e0a599164e7197a4bce310ee3342fd61817b8047ff04f076a1ce12dd470584142a4bd
+ languageName: node
+ linkType: hard
+
"webidl-conversions@npm:^3.0.0":
version: 3.0.1
resolution: "webidl-conversions@npm:3.0.1"
@@ -29623,3 +29769,10 @@ __metadata:
checksum: 10c0/9424cade91458ceb4288cc9cbc76d9d055686de3cd5aa13bf447aed2d1ebd98ebb517c9d871e9f9bd92a44e0d63a0491d560adb0bd7e4d0de42c99320d9e04a4
languageName: node
linkType: hard
+
+"zwitch@npm:^2.0.4":
+ version: 2.0.4
+ resolution: "zwitch@npm:2.0.4"
+ checksum: 10c0/3c7830cdd3378667e058ffdb4cf2bb78ac5711214e2725900873accb23f3dfe5f9e7e5a06dcdc5f29605da976fc45c26d9a13ca334d6eea2245a15e77b8fc06e
+ languageName: node
+ linkType: hard