├── .gitignore ├── App.js ├── Button.js ├── Calendar.js ├── ComboBox.js ├── DateField.js ├── DatePicker.js ├── Dialog.js ├── Group.js ├── Heading.js ├── Input.js ├── Label.js ├── ListBox.js ├── Menu.js ├── NumberField.js ├── Popover.js ├── Select.js ├── Separator.js ├── Slider.js ├── Tooltip.js ├── index.css ├── index.html ├── index.js ├── package.json ├── utils.js └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | .parcel-cache 2 | dist 3 | node_modules 4 | -------------------------------------------------------------------------------- /App.js: -------------------------------------------------------------------------------- 1 | import {Item, Section} from 'react-stately'; 2 | import {MenuTrigger, Menu, MenuSection, MenuItem} from './Menu'; 3 | import { Separator } from "./Separator"; 4 | import {Button} from './Button'; 5 | import {Popover} from './Popover'; 6 | import clsx from 'clsx'; 7 | import {OverlayProvider} from 'react-aria'; 8 | import {Select, SelectValue} from './Select'; 9 | import {ListBox, Option} from './ListBox'; 10 | import {ComboBox} from './ComboBox'; 11 | import {Input} from './Input'; 12 | import {Label} from './Label'; 13 | import {Slider, Track, Thumb, Output} from './Slider'; 14 | import {DialogTrigger, Modal, Dialog} from './Dialog'; 15 | import {TooltipTrigger, Tooltip, Arrow} from './Tooltip'; 16 | import {NumberField, IncrementButton, DecrementButton} from './NumberField'; 17 | import {Group} from './Group'; 18 | import {Calendar, RangeCalendar, CalendarHeader, CalendarGrid, CalendarNextButton, CalendarPreviousButton} from './Calendar'; 19 | import {DateField, TimeField, DateInput, DateSegment} from './DateField'; 20 | import {DatePicker, DateRangePicker, StartDateInput, EndDateInput} from './DatePicker'; 21 | 22 | function MyListBox(props) { 23 | return ( 24 | ( 28 | 31 | )} /> 32 | ); 33 | } 34 | 35 | function MyComboBox({label, items, children, ...props}) { 36 | return ( 37 | 38 | 39 |
40 | 41 | 44 |
45 | 46 | ( 49 | 52 | )}> 53 | {children} 54 | 55 | 56 |
57 | ); 58 | } 59 | 60 | function MyMenu(props) { 61 | return ( 62 | ( 66 | 67 | {section.rendered} 68 | 69 | )} 70 | renderSeparator={() => } 71 | renderItem={item => ( 72 | 73 | )} /> 74 | ); 75 | } 76 | 77 | import React from 'react'; 78 | import { Heading } from './Heading'; 79 | function Example() { 80 | let options = [ 81 | {id: 1, name: 'Aerospace'}, 82 | {id: 2, name: 'Mechanical'}, 83 | {id: 3, name: 'Civil'}, 84 | {id: 4, name: 'Biomedical'}, 85 | {id: 5, name: 'Nuclear'}, 86 | {id: 6, name: 'Industrial'}, 87 | {id: 7, name: 'Chemical'}, 88 | {id: 8, name: 'Agricultural'}, 89 | {id: 9, name: 'Electrical'} 90 | ]; 91 | let [majorId, setMajorId] = React.useState(); 92 | 93 | return ( 94 | <> 95 | 99 | {(item) => {item.name}} 100 | 101 |

Selected topic id: {majorId}

102 | 103 | ); 104 | } 105 | 106 | export function App() { 107 | return ( 108 | 109 | 110 | 111 | 112 | 113 | 114 |
Section 1} className="group"> 115 | Foo 116 | Bar 117 | Baz 118 |
119 | 120 |
Section 2} className="group"> 121 | Foo 122 | Bar 123 | Baz 124 |
125 |
126 |
127 |
128 | 129 | 130 | 131 | 132 |
133 | Foo 134 | Bar 135 | Baz 136 |
137 | 138 |
139 | Foo 140 | Bar 141 | Baz 142 |
143 |
144 |
145 |
146 | 160 | 161 | 162 |
163 | 164 | 167 |
168 | 169 | 170 | Foo 171 | Bar 172 | Baz 173 | 174 | 175 |
176 | 177 | One 178 | Two 179 | Three 180 | 181 | 182 | Foo 183 | Bar 184 | Baz 185 | 186 | 187 | One 188 | Two 189 | Three 190 | 191 | 201 |
202 | 203 | 204 | {state => `${state.getThumbValueLabel(0)} - ${state.getThumbValueLabel(1)}`} 205 | 206 |
207 | 213 |
221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | - 229 | 230 | + 231 | 232 | 233 | 234 | 235 | 248 | 254 | {({close}) => ( 255 |
256 | Sign up 257 | 260 | 263 | 266 |
267 | )} 268 |
269 |
270 |
271 | 272 | 273 | 274 | 280 | {({close}) => ( 281 |
282 | 285 | 288 | 291 |
292 | )} 293 |
294 |
295 |
296 | 297 | 298 | 306 | 307 | 308 | 309 | 310 | 311 | I am a tooltip 312 | 313 | 314 | 315 |
316 | < 317 | 318 | > 319 |
320 | 321 | {({ formattedDate, isSelected, isOutsideVisibleRange }) => ( 322 | 325 | )} 326 | 327 |
328 | 329 |
330 | < 331 | 332 | > 333 |
334 | 335 | {({ formattedDate, isSelected, isOutsideVisibleRange }) => ( 336 | 339 | )} 340 | 341 |
342 | 343 | 344 | 345 | {segment => } 346 | 347 | 348 | 349 | 350 | 351 | {segment => } 352 | 353 | 354 | 355 | 356 | 357 | 358 | {segment => } 359 | 360 | 361 | 362 | 368 | 369 |
370 | < 371 | 372 | > 373 |
374 | 375 | {({ formattedDate, isSelected, isOutsideVisibleRange }) => ( 376 | 379 | )} 380 | 381 |
382 |
383 |
384 | 385 | 386 | 387 |
388 | 389 | {segment => } 390 | 391 | 392 | 393 | {segment => } 394 | 395 |
396 | 397 |
398 | 404 | 405 |
406 | < 407 | 408 | > 409 |
410 | 411 | {({ formattedDate, isSelected, isOutsideVisibleRange }) => ( 412 | 415 | )} 416 | 417 |
418 |
419 |
420 | 421 | ); 422 | } 423 | 424 | function itemClass({isFocused, isSelected}) { 425 | return clsx('item', { 426 | focused: isFocused, 427 | selected: isSelected 428 | }) 429 | } 430 | 431 | function CustomThumb({index}) { 432 | return ( 433 | ({ 436 | width: 20, 437 | height: 20, 438 | borderRadius: '50%', 439 | top: '50%', 440 | backgroundColor: isFocusVisible ? 'orange' : isDragging 441 | ? 'dimgrey' 442 | : 'gray' 443 | })} /> 444 | ) 445 | } 446 | -------------------------------------------------------------------------------- /Button.js: -------------------------------------------------------------------------------- 1 | import {useRef, createContext, useContext} from 'react'; 2 | import {useButton, mergeProps} from 'react-aria'; 3 | 4 | export const ButtonContext = createContext({}); 5 | 6 | export function Button(props) { 7 | let bp = useContext(ButtonContext); 8 | props = mergeProps(bp, props); 9 | let ref = useRef(); 10 | ref = props.buttonRef || ref; 11 | let {buttonProps} = useButton(props, ref); 12 | return ( 13 | 18 | ); 19 | } 20 | -------------------------------------------------------------------------------- /Calendar.js: -------------------------------------------------------------------------------- 1 | import {useRef, cloneElement, createContext, useContext, useMemo} from 'react'; 2 | import {useCalendarState, useRangeCalendarState} from 'react-stately'; 3 | import {useCalendar, useRangeCalendar, useCalendarGrid, useCalendarCell} from 'react-aria'; 4 | import {useLocale, VisuallyHidden, useDateFormatter, mergeProps} from 'react-aria'; 5 | import {createCalendar, startOfWeek, getWeeksInMonth} from '@internationalized/date'; 6 | import {Button} from './Button'; 7 | import {useRenderProps} from './utils'; 8 | 9 | export const CalendarContext = createContext({}); 10 | const InternalCalendarContext = createContext(); 11 | 12 | export function Calendar(props) { 13 | let propsFromDatePicker = useContext(CalendarContext); 14 | props = mergeProps(propsFromDatePicker, props); 15 | let { locale } = useLocale(); 16 | let state = useCalendarState({ 17 | ...props, 18 | locale, 19 | createCalendar 20 | }); 21 | 22 | let ref = useRef(); 23 | let { calendarProps, prevButtonProps, nextButtonProps, title } = useCalendar( 24 | props, 25 | state, 26 | ref 27 | ); 28 | 29 | return ( 30 |
31 | 40 | 41 |

{calendarProps['aria-label']}

42 |
43 | {props.children} 44 | 45 |
49 | ); 50 | } 51 | 52 | export function RangeCalendar(props) { 53 | let propsFromDatePicker = useContext(CalendarContext); 54 | props = mergeProps(propsFromDatePicker, props); 55 | let { locale } = useLocale(); 56 | let state = useRangeCalendarState({ 57 | ...props, 58 | locale, 59 | createCalendar 60 | }); 61 | 62 | let ref = useRef(); 63 | let { calendarProps, prevButtonProps, nextButtonProps, title } = useRangeCalendar( 64 | props, 65 | state, 66 | ref 67 | ); 68 | 69 | return ( 70 |
71 | 80 | 81 |

{calendarProps['aria-label']}

82 |
83 | {props.children} 84 | 85 |
89 | ); 90 | } 91 | 92 | export function CalendarHeader(props) { 93 | let { state, title } = useContext(InternalCalendarContext); 94 | let renderProps = useRenderProps({ 95 | ...props, 96 | values: {state}, 97 | defaultChildren: title 98 | }); 99 | 100 | return ( 101 |