Skip to content

Commit 8afa735

Browse files
authored
docs: migrate blog posts (#9125)
* init blog posts * more blog post content * more blog edits * add hero image to introducing-react-spectrum.mdx * add remaining videos * fix DragBetweenListsExample to use RAC * Revert "add remaining videos" This reverts commit 4e436bb. * add posts to 'Blog' section * Revert "Revert "add remaining videos"" This reverts commit 6d2b667. * fix broken links * fix video widths * add bylines * fix layout * fix nested p tags * fix video widths * improve DnD example * fix caption fonts * fix remaining font issues
1 parent 3949d95 commit 8afa735

21 files changed

+2164
-5
lines changed

packages/dev/docs/pages/blog/building-a-combobox.mdx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,14 @@ export default BlogPostLayout;
1919

2020
---
2121
keywords: [combobox, accessibility, mobile, react spectrum, react, spectrum, interactions, touch]
22-
description: After many months of research, development, and testing, we’re excited to announce that the React Spectrum [ComboBox](../react-spectrum/ComboBox.html) component and React Aria [useComboBox](../react-aria/useComboBox.html) hook are now available! In this post we'll take a deeper look into some of the challenges we faced when building an accessible and mobile friendly ComboBox.
22+
description: After many months of research, development, and testing, we’re excited to announce that the React Spectrum [ComboBox](../../s2/ComboBox.html) component and React Aria [useComboBox](../useComboBox.html) hook are now available! In this post we'll take a deeper look into some of the challenges we faced when building an accessible and mobile friendly ComboBox.
2323
date: 2021-07-13
2424
author: '[Daniel Lu](https://github.com/LFDanLu)'
2525
---
2626

2727
# Creating an accessible autocomplete experience
2828

29-
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](../react-spectrum/ComboBox.html) component and React Aria [useComboBox](../react-aria/useComboBox.html) hook are now available! We’ve focused on the following areas to help you build quality autocomplete experiences.
29+
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](../useComboBox.html) hook are now available! We’ve focused on the following areas to help you build quality autocomplete experiences.
3030

3131
- **Accessibility** — Our ComboBox has been tested with screen readers across desktop and mobile devices, and with many different input methods including mouse, touch, and keyboard. We encountered many screen reader differences, and worked hard to ensure announcements are clear and consistent.
3232
- **Mobile** — On small screens, the React Spectrum ComboBox is automatically displayed in a tray, which improves the user experience by giving them a larger area to scroll. We also optimized our experience for touch screen interactions and on screen keyboards.
@@ -133,7 +133,7 @@ Special care was taken such that the messages themselves only contained relevant
133133
When the user then moves to a different option in the same section, only the newly focused item name is announced. Similarly, the total option count is only announced when number of options available in the listbox changes. Since many of these messages were added to fill in gaps in VoiceOver's announcement,
134134
we only trigger the `LiveAnnouncer` on Apple devices to avoid announcement overlap on other screen readers.
135135

136-
If you are interested in using this `LiveAnnouncer` yourself, check out [LiveAnnouncer](https://github.com/adobe/react-spectrum/blob/main/packages/@react-aria/live-announcer/src/LiveAnnouncer.tsx) in `@react-aria/live-announcer`. Otherwise, the [useComboBox](../react-aria/useComboBox.html) hook provides you with all of the custom messaging out of the box. See the video below for a sneak peek!
136+
If you are interested in using this `LiveAnnouncer` yourself, check out [LiveAnnouncer](https://github.com/adobe/react-spectrum/blob/main/packages/@react-aria/live-announcer/src/LiveAnnouncer.tsx) in `@react-aria/live-announcer`. Otherwise, the [useComboBox](../useComboBox.html) hook provides you with all of the custom messaging out of the box. See the video below for a sneak peek!
137137

138138
<Video src={comboboxAccessibilityUrl} alt="Demo of VoiceOver announcement in ComboBox" style={{maxWidth: 'min(100%, 700px)', display: 'block', margin: '20px auto'}} controls />
139139

packages/dev/s2-docs/pages/internationalized/number/NumberParser.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ Numbers can be formatted in many different ways, including percentages, units, d
2626

2727
Parsing numbers while taking into account all locale-specific detail is quite complex and error-prone. `NumberParser` uses information about the locale and expected format for a number in order to parse it correctly. This means it is somewhat strict about the accepted formats. It is not designed to handle use cases where the user can enter numbers in an unknown format (e.g. either a unit value _or_ a percentage), this must be known up front or selected via an external UI control.
2828

29-
Read our [blog post](https://react-spectrum.adobe.com/blog/how-we-internationalized-our-numberfield.html) for more details on how the number parser is implemented.
29+
Read our [blog post](how-we-internationalized-our-numberfield.html) for more details on how the number parser is implemented.
3030

3131
### Example
3232

packages/dev/s2-docs/pages/react-aria/Button.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ export const tags = ['btn'];
4545

4646
## Events
4747

48-
Use the `onPress` prop to handle interactions via mouse, keyboard, and touch. This is similar to `onClick`, but normalized for consistency across browsers, devices, and interaction methods. Read our [blog post](https://react-spectrum.adobe.com/blog/building-a-button-part-1.html) to learn more.
48+
Use the `onPress` prop to handle interactions via mouse, keyboard, and touch. This is similar to `onClick`, but normalized for consistency across browsers, devices, and interaction methods. Read our [blog post](building-a-button-part-1.html) to learn more.
4949

5050
The `onPressStart`, `onPressEnd`, and `onPressChange` events are also emitted as the user interacts with the button. Each of these handlers receives a <TypeLink links={typesDocs.links} type={typesDocs.exports.PressEvent} />, which provides information about the target and interaction method. See [usePress](https://react-spectrum.adobe.com/react-aria/usePress.html) for more details.
5151

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
'use client';
2+
3+
import {Calendar, Picker, PickerItem, Provider} from '@react-spectrum/s2';
4+
import React from 'react';
5+
import {useLocale} from '@react-aria/i18n';
6+
import {style} from '@react-spectrum/s2/style' with {type: 'macro'};
7+
8+
export default function CalendarSystems() {
9+
let [calendar, setCalendar] = React.useState('gregory');
10+
let {locale} = useLocale();
11+
const calendars = [
12+
{key: 'gregory', name: 'Gregorian'},
13+
{key: 'japanese', name: 'Japanese'},
14+
{key: 'buddhist', name: 'Buddhist'},
15+
{key: 'roc', name: 'Taiwan'},
16+
{key: 'persian', name: 'Persian'},
17+
{key: 'indian', name: 'Indian'},
18+
{key: 'islamic-umalqura', name: 'Islamic (Umm al-Qura)'},
19+
{key: 'islamic-civil', name: 'Islamic Civil'},
20+
{key: 'islamic-tbla', name: 'Islamic Tabular'},
21+
{key: 'hebrew', name: 'Hebrew'},
22+
{key: 'coptic', name: 'Coptic'},
23+
{key: 'ethiopic', name: 'Ethiopic'},
24+
{key: 'ethioaa', name: 'Ethiopic (Amete Alem)'}
25+
];
26+
27+
return (
28+
<div className={style({display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 8})}>
29+
<Picker label="Calendar system" items={calendars} value={calendar} onChange={setCalendar}>
30+
{item => <PickerItem>{item.name}</PickerItem>}
31+
</Picker>
32+
<Provider locale={`${locale}-u-ca-${calendar}`}>
33+
<Calendar aria-label="Date" />
34+
</Provider>
35+
</div>
36+
)
37+
}
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
'use client';
2+
3+
import {ListBox, ListBoxItem} from 'vanilla-starter/ListBox';
4+
import {Folder, File} from 'lucide-react';
5+
import {useDragAndDrop, isTextDropItem} from 'react-aria-components';
6+
import {useListData} from 'react-stately';
7+
import React from 'react';
8+
9+
function BidirectionalDnDListBox(props) {
10+
let {list} = props;
11+
let {dragAndDropHooks} = useDragAndDrop({
12+
acceptedDragTypes: ['custom-app-type-bidirectional'],
13+
// Only allow move operations
14+
getAllowedDropOperations: () => ['move'],
15+
getItems(keys) {
16+
return [...keys].map(key => {
17+
let item = list.getItem(key);
18+
// Setup the drag types and associated info for each dragged item.
19+
return {
20+
'custom-app-type-bidirectional': JSON.stringify(item),
21+
'text/plain': item.name
22+
};
23+
});
24+
},
25+
onInsert: async (e) => {
26+
let {
27+
items,
28+
target
29+
} = e;
30+
let processedItems = await Promise.all(
31+
items
32+
.filter(isTextDropItem)
33+
.map(async item => JSON.parse(await item.getText('custom-app-type-bidirectional')))
34+
);
35+
if (target.dropPosition === 'before') {
36+
list.insertBefore(target.key, ...processedItems);
37+
} else if (target.dropPosition === 'after') {
38+
list.insertAfter(target.key, ...processedItems);
39+
}
40+
},
41+
onReorder: (e) => {
42+
let {
43+
keys,
44+
target
45+
} = e;
46+
47+
if (target.dropPosition === 'before') {
48+
list.moveBefore(target.key, [...keys]);
49+
} else if (target.dropPosition === 'after') {
50+
list.moveAfter(target.key, [...keys]);
51+
}
52+
},
53+
onRootDrop: async (e) => {
54+
let {
55+
items
56+
} = e;
57+
let processedItems = await Promise.all(
58+
items
59+
.filter(isTextDropItem)
60+
.map(async item => JSON.parse(await item.getText('custom-app-type-bidirectional')))
61+
);
62+
list.append(...processedItems);
63+
},
64+
/*- begin highlight -*/
65+
onDragEnd: (e) => {
66+
let {
67+
dropOperation,
68+
keys,
69+
isInternal
70+
} = e;
71+
// Only remove the dragged items if they aren't dropped inside the source list
72+
if (dropOperation === 'move' && !isInternal) {
73+
list.remove(...keys);
74+
}
75+
}
76+
/*- end highlight -*/
77+
});
78+
79+
return (
80+
<ListBox
81+
aria-label={props['aria-label']}
82+
selectionMode="multiple"
83+
items={list.items}
84+
dragAndDropHooks={dragAndDropHooks}
85+
style={{width: 300, height: 300, overflow: 'auto'}}>
86+
{item => (
87+
<ListBoxItem textValue={item.name} style={{display: 'flex', alignItems: 'center', gap: 8, flexDirection: 'row', justifyContent: 'flex-start'}}>
88+
{item.type === 'folder' ? <Folder /> : <File />}
89+
<span>{item.name}</span>
90+
</ListBoxItem>
91+
)}
92+
</ListBox>
93+
);
94+
}
95+
96+
export default function DragBetweenListsExample() {
97+
let list1 = useListData({
98+
initialItems: [
99+
{id: '1', type: 'file', name: 'Adobe Photoshop'},
100+
{id: '2', type: 'file', name: 'Adobe XD'},
101+
{id: '3', type: 'folder', name: 'Documents'},
102+
{id: '4', type: 'file', name: 'Adobe InDesign'},
103+
{id: '5', type: 'folder', name: 'Utilities'},
104+
{id: '6', type: 'file', name: 'Adobe AfterEffects'}
105+
]
106+
});
107+
108+
let list2 = useListData({
109+
initialItems: [
110+
{id: '7', type: 'folder', name: 'Pictures'},
111+
{id: '8', type: 'file', name: 'Adobe Fresco'},
112+
{id: '9', type: 'folder', name: 'Apps'},
113+
{id: '10', type: 'file', name: 'Adobe Illustrator'},
114+
{id: '11', type: 'file', name: 'Adobe Lightroom'},
115+
{id: '12', type: 'file', name: 'Adobe Dreamweaver'}
116+
]
117+
});
118+
119+
120+
return (
121+
<div style={{display: 'flex', justifyContent: 'center', flexWrap: 'wrap', gap: 8}}>
122+
<BidirectionalDnDListBox list={list1} aria-label="First ListBox in drag between list example" />
123+
<BidirectionalDnDListBox list={list2} aria-label="Second ListBox in drag between list example" />
124+
</div>
125+
);
126+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
'use client';
2+
3+
import {today, getLocalTimeZone} from '@internationalized/date';
4+
import {RangeCalendar} from '@react-spectrum/s2';
5+
import React from 'react';
6+
import {style} from '@react-spectrum/s2/style' with {type: 'macro'};
7+
8+
export default function RangeCalendarExample() {
9+
let now = today(getLocalTimeZone()).set({day: 8});
10+
let disabledRanges = [
11+
[now, now.add({days: 2})],
12+
[now.add({days: 10}), now.add({days: 14})],
13+
[now.add({days: 23}), now.add({days: 28})],
14+
];
15+
16+
let isDateUnavailable = (date) => disabledRanges.some((interval) => date.compare(interval[0]) >= 0 && date.compare(interval[1]) <= 0);
17+
18+
return (
19+
<div className={style({display: 'flex', flexDirection: 'column', alignItems: 'center'})}>
20+
<RangeCalendar
21+
aria-label="Trip dates"
22+
minValue={now}
23+
isDateUnavailable={isDateUnavailable}
24+
defaultValue={{start: now.add({days: 5}), end: now.add({days: 8})}} />
25+
</div>
26+
);
27+
}

0 commit comments

Comments
 (0)