form-fields.stories.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560
  1. import {action} from '@storybook/addon-actions';
  2. import NewBooleanField from 'sentry/components/forms/booleanField';
  3. import CheckboxField from 'sentry/components/forms/checkboxField';
  4. import CompactSelect from 'sentry/components/forms/compactSelect';
  5. import CompositeSelect from 'sentry/components/forms/compositeSelect';
  6. import RadioGroup from 'sentry/components/forms/controls/radioGroup';
  7. import RangeSlider from 'sentry/components/forms/controls/rangeSlider';
  8. import DatePickerField from 'sentry/components/forms/datePickerField';
  9. import FileField from 'sentry/components/forms/fileField';
  10. import Form from 'sentry/components/forms/form';
  11. import FormField from 'sentry/components/forms/formField';
  12. import MultipleCheckboxField from 'sentry/components/forms/MultipleCheckboxField';
  13. import RadioBooleanField from 'sentry/components/forms/radioBooleanField';
  14. import RadioField from 'sentry/components/forms/radioField';
  15. import SelectField from 'sentry/components/forms/selectField';
  16. import TextareaField from 'sentry/components/forms/textareaField';
  17. import TextCopyInput from 'sentry/components/forms/textCopyInput';
  18. import TextField from 'sentry/components/forms/textField';
  19. import {Panel} from 'sentry/components/panels';
  20. import {RadioGroupRating} from 'sentry/components/radioGroupRating';
  21. import Switch from 'sentry/components/switchButton';
  22. export default {
  23. title: 'Components/Forms/Fields',
  24. };
  25. export const _TextField = () => (
  26. <Panel>
  27. <Form initialData={{context: {location: 'cat'}}}>
  28. <TextField
  29. name="simpletextfieldvalue"
  30. label="Simple Text Field with Value"
  31. placeholder="Simple Text Field"
  32. defaultValue="With a value present"
  33. />
  34. <TextField
  35. name="simpletextfieldplaceholder"
  36. label="Simple Text Field with Placeholder"
  37. placeholder="This is placeholder text"
  38. />
  39. <TextField
  40. name="simpletextfieldvaluedisabled"
  41. label="Disabled - Simple Text Field with Value"
  42. placeholder="Simple Text Field"
  43. defaultValue="With a value present"
  44. disabled
  45. />
  46. <TextField
  47. name="simpletextfieldplaceholderdisabled"
  48. label="Disabled - Simple Text Field with Placeholder"
  49. placeholder="This is placeholder text in a disabled field"
  50. disabled
  51. />
  52. <TextField
  53. name="textfieldwithreturnsubmit"
  54. label="Text Field With Return Submit"
  55. placeholder="Type here to show the return button"
  56. showReturnButton
  57. />
  58. <TextField
  59. name="textfieldflexiblecontrol"
  60. label="Text Field With Flexible Control State Size"
  61. placeholder="Type text and then delete it"
  62. required
  63. flexibleControlStateSize
  64. />
  65. <TextField
  66. name="textfielddisabled"
  67. label="Text field with disabled reason"
  68. placeholder="I am disabled"
  69. disabled
  70. disabledReason="This is the reason this field is disabled"
  71. />
  72. </Form>
  73. </Panel>
  74. );
  75. _TextField.storyName = 'Text';
  76. _TextField.parameters = {
  77. docs: {
  78. description: {
  79. story: 'Simple text field',
  80. },
  81. },
  82. };
  83. export const _TextareaField = ({autosize, rows}) => (
  84. <Panel>
  85. <Form initialData={{context: {location: 'cat'}}}>
  86. <TextareaField
  87. name="simpletextfieldvalue"
  88. label="Simple Textarea Field with Value"
  89. help="Additional help text"
  90. placeholder="Simple Textarea Field"
  91. defaultValue="With a value present"
  92. />
  93. <TextareaField
  94. name="simpletextfieldautosize"
  95. autosize={autosize}
  96. label="Textarea field with autosize"
  97. rows={rows}
  98. placeholder="Use knobs to control rows and autosize setting"
  99. />
  100. <TextareaField
  101. name="simpletextfieldvaluedisabled"
  102. label="Disabled - Simple Textarea Field with Value"
  103. placeholder="Simple Textarea Field"
  104. defaultValue="With a value present"
  105. disabled
  106. />
  107. <TextareaField
  108. name="simpletextfieldplaceholderdisabled"
  109. label="Disabled - Simple Textarea Field with Placeholder"
  110. placeholder="This is placeholder text in a disabled field"
  111. disabled
  112. />
  113. <TextareaField
  114. name="textfieldwithreturnsubmit"
  115. label="Textarea Field With Return Submit"
  116. placeholder="Type here to show the return button"
  117. showReturnButton
  118. />
  119. <TextareaField
  120. name="textfieldflexiblecontrol"
  121. label="Textarea Field With Flexible Control State Size"
  122. placeholder="Type text and then delete it"
  123. required
  124. flexibleControlStateSize
  125. />
  126. <TextareaField
  127. name="textfielddisabled"
  128. label="Textarea Field with disabled reason"
  129. placeholder="I am disabled"
  130. disabled
  131. disabledReason="This is the reason this field is disabled"
  132. />
  133. <TextareaField
  134. name="textareafielderror"
  135. label="Textarea Field with error"
  136. placeholder="I have an error"
  137. error="An error has occurred"
  138. />
  139. </Form>
  140. </Panel>
  141. );
  142. _TextareaField.storyName = 'Textarea';
  143. _TextareaField.args = {
  144. autosize: true,
  145. rows: 1,
  146. };
  147. export const __BooleanField = () => (
  148. <Form>
  149. <NewBooleanField name="field" label="New Boolean Field" />
  150. </Form>
  151. );
  152. __BooleanField.storyName = 'Boolean';
  153. export const _CheckboxField = () => (
  154. <Form>
  155. <CheckboxField key="agree" name="agree" id="agree" label="Do you agree?" />
  156. <CheckboxField
  157. key="compelled"
  158. name="compelled"
  159. id="compelled"
  160. label="You are compelled to agree"
  161. help="More content to help you decide."
  162. required
  163. />
  164. </Form>
  165. );
  166. _CheckboxField.storyName = 'Checkbox';
  167. export const _MultipleCheckboxField = () => (
  168. <Form>
  169. <MultipleCheckboxField
  170. choices={[
  171. {title: 'Checkbox', value: 0},
  172. {title: 'Disabled Checkbox', value: 1},
  173. {title: 'Checked Checkbox', value: 2, checked: true},
  174. {title: 'Intermediate Checkbox', value: 3, intermediate: true},
  175. {title: 'Disabled Checked Checkbox', value: 4, checked: true, disabled: true},
  176. {
  177. title: 'Disabled Intermediate Checkbox',
  178. value: 5,
  179. intermediate: true,
  180. disabled: true,
  181. },
  182. ]}
  183. />
  184. </Form>
  185. );
  186. _MultipleCheckboxField.storyName = 'MultipleCheckbox';
  187. export const _DatePickerField = () => (
  188. <Form>
  189. <DatePickerField name="field" label="Date Picker Field" />
  190. </Form>
  191. );
  192. _DatePickerField.storyName = 'Datepicker';
  193. export const _RadioField = () => (
  194. <Form>
  195. <RadioField
  196. name="radio"
  197. label="Radio Field"
  198. choices={[
  199. ['choice_one', 'Choice One'],
  200. ['choice_two', 'Choice Two'],
  201. ['choice_three', 'Choice Three'],
  202. ]}
  203. />
  204. <RadioField
  205. orientInline
  206. name="inline-radio"
  207. label="Inline Radios"
  208. choices={[
  209. ['choice_one', 'Choice One'],
  210. ['choice_two', 'Choice Two'],
  211. ]}
  212. />
  213. </Form>
  214. );
  215. export const __FileField = () => (
  216. <Form>
  217. <FileField name="field" label="File Field" />
  218. </Form>
  219. );
  220. __FileField.storyName = 'File';
  221. _RadioField.storyName = 'Radio';
  222. export const _RadioBooleanField = ({disabled}) => (
  223. <Form>
  224. <RadioBooleanField
  225. name="subscribe"
  226. yesLabel="Yes, I would like to receive updates via email"
  227. noLabel="No, I'd prefer not to receive these updates"
  228. help="Help text for making an informed decision"
  229. disabled={disabled}
  230. />
  231. </Form>
  232. );
  233. _RadioBooleanField.storyName = 'Radio - Boolean';
  234. _RadioBooleanField.args = {
  235. disabled: false,
  236. };
  237. export const _SelectField = () => (
  238. <Form>
  239. <SelectField
  240. name="select"
  241. label="Select Field"
  242. choices={[
  243. ['choice_one', 'Choice One'],
  244. ['choice_two', 'Choice Two'],
  245. ['choice_three', 'Choice Three'],
  246. ]}
  247. />
  248. </Form>
  249. );
  250. _SelectField.storyName = 'Select';
  251. export const SelectFieldMultiple = () => (
  252. <Form>
  253. <SelectField
  254. name="select"
  255. label="Multi Select"
  256. multiple
  257. choices={[
  258. ['choice_one', 'Choice One'],
  259. ['choice_two', 'Choice Two'],
  260. ['choice_three', 'Choice Three'],
  261. ]}
  262. />
  263. </Form>
  264. );
  265. SelectFieldMultiple.storyName = 'Select - Multiple';
  266. export const SelectFieldGrouped = () => (
  267. <Form>
  268. <SelectField
  269. name="select"
  270. label="Grouped Select"
  271. options={[
  272. {
  273. label: 'Group 1',
  274. options: [
  275. {value: 'choice_one', label: 'Choice One'},
  276. {value: 'choice_two', label: 'Choice Two'},
  277. ],
  278. },
  279. {
  280. label: 'Group 2',
  281. options: [
  282. {value: 'choice_three', label: 'Choice Three'},
  283. {value: 'choice_four', label: 'Choice Four'},
  284. ],
  285. },
  286. ]}
  287. />
  288. </Form>
  289. );
  290. SelectFieldGrouped.storyName = 'Select - Grouped';
  291. export const SelectFieldInFieldLabel = () => (
  292. <Form>
  293. <SelectField
  294. name="select"
  295. label="Select With Label In Field"
  296. inFieldLabel="Label: "
  297. choices={[
  298. ['choice_one', 'Choice One'],
  299. ['choice_two', 'Choice Two'],
  300. ['choice_three', 'Choice Three'],
  301. ]}
  302. />
  303. </Form>
  304. );
  305. SelectFieldInFieldLabel.storyName = 'Select - Label in Field';
  306. SelectFieldInFieldLabel.parameters = {
  307. docs: {
  308. description: {
  309. story: 'Select Control w/ Label In Field',
  310. },
  311. },
  312. };
  313. export const CompactSelectField = props => (
  314. <CompactSelect
  315. defaultValue="opt_one"
  316. options={[
  317. {value: 'opt_one', label: 'Option One'},
  318. {value: 'opt_two', label: 'Option Two'},
  319. ]}
  320. {...props}
  321. />
  322. );
  323. CompactSelectField.storyName = 'Select - Compact';
  324. CompactSelectField.parameters = {
  325. docs: {
  326. description: {
  327. story: 'Compact',
  328. },
  329. },
  330. };
  331. CompactSelectField.args = {
  332. size: 'md',
  333. menuTitle: '',
  334. isSearchable: false,
  335. isDisabled: false,
  336. isClearable: false,
  337. isLoading: false,
  338. multiple: false,
  339. placeholder: 'Search…',
  340. closeOnSelect: true,
  341. shouldCloseOnBlur: true,
  342. isDismissable: true,
  343. offset: 8,
  344. crossOffset: 0,
  345. containerPadding: 8,
  346. placement: 'bottom left',
  347. triggerProps: {
  348. prefix: 'Prefix',
  349. },
  350. };
  351. CompactSelectField.argTypes = {
  352. placement: {
  353. options: [
  354. 'top',
  355. 'bottom',
  356. 'left',
  357. 'right',
  358. 'top left',
  359. 'top right',
  360. 'bottom left',
  361. 'bottom right',
  362. 'left top',
  363. 'left bottom',
  364. 'right top',
  365. 'right bottom',
  366. ],
  367. control: {type: 'radio'},
  368. },
  369. size: {
  370. options: ['md', 'sm', 'xs'],
  371. control: {type: 'radio'},
  372. },
  373. };
  374. export const CompositeSelectField = props => (
  375. <CompositeSelect
  376. sections={[
  377. {
  378. label: 'Group 1',
  379. value: 'group_1',
  380. defaultValue: 'choice_one',
  381. options: [
  382. {value: 'choice_one', label: 'Choice One'},
  383. {value: 'choice_two', label: 'Choice Two'},
  384. ],
  385. },
  386. {
  387. label: 'Group 2',
  388. value: 'group_2',
  389. defaultValue: ['choice_three'],
  390. multiple: true,
  391. options: [
  392. {value: 'choice_three', label: 'Choice Three'},
  393. {value: 'choice_four', label: 'Choice Four'},
  394. ],
  395. },
  396. ]}
  397. {...props}
  398. />
  399. );
  400. CompositeSelectField.storyName = 'Select - Composite';
  401. CompositeSelectField.args = {...CompactSelectField.args};
  402. delete CompositeSelectField.args.multiple;
  403. CompositeSelectField.argTypes = CompactSelectField.argTypes;
  404. export const NonInlineField = () => (
  405. <Form>
  406. <FormField name="radio" label="Radio Field" inline={false}>
  407. {({value, label, onChange}) => (
  408. <RadioGroup
  409. onChange={onChange}
  410. label={label}
  411. value={value}
  412. choices={[
  413. ['choice_one', 'Choice One', 'Description for Choice One'],
  414. ['choice_two', 'Choice Two', 'Description for Choice Two'],
  415. ['choice_three', 'Choice Three'],
  416. ]}
  417. />
  418. )}
  419. </FormField>
  420. </Form>
  421. );
  422. NonInlineField.storyName = 'Non-inline';
  423. NonInlineField.parameters = {
  424. docs: {
  425. description: {
  426. story: 'Radio Group used w/ FormField',
  427. },
  428. },
  429. };
  430. export const _RadioGroupRating = () => (
  431. <RadioGroupRating
  432. name="feelingIfFeatureNotAvailableRating"
  433. options={{
  434. 0: {
  435. label: 'Very Dissatisfied',
  436. description: "Not disappointed (It isn't really useful)",
  437. },
  438. 1: {
  439. label: 'Dissatisfied',
  440. },
  441. 2: {
  442. label: 'Neutral',
  443. },
  444. 3: {
  445. label: 'Satisfied',
  446. },
  447. 4: {
  448. description: "Very disappointed (It's a deal breaker)",
  449. label: 'Very Satisfied',
  450. },
  451. }}
  452. label="How satisfied are you with this feature?"
  453. inline={false}
  454. stacked
  455. />
  456. );
  457. _RadioGroupRating.storyName = 'Radio Group Rating';
  458. _RadioGroupRating.parameters = {
  459. docs: {
  460. description: {
  461. story: 'Used to provide insights regarding opinions and experiences',
  462. },
  463. },
  464. };
  465. export const _RangeSlider = () => (
  466. <div style={{backgroundColor: '#fff', padding: 20}}>
  467. <RangeSlider
  468. name="rangeField"
  469. min={1}
  470. max={10}
  471. step={1}
  472. value={1}
  473. formatLabel={value => {
  474. return `${value} Toaster Strudle${value > 1 ? 's' : ''}`;
  475. }}
  476. />
  477. </div>
  478. );
  479. _RangeSlider.storyName = 'Range Slider';
  480. export const WithoutAParentForm = ({onChange}) => {
  481. return (
  482. <div>
  483. <TextField
  484. name="simpletextfield"
  485. label="Simple Text Field"
  486. placeholder="Simple Text Field"
  487. onChange={onChange}
  488. />
  489. <NewBooleanField name="field" label="New Boolean Field" onChange={onChange} />
  490. <RadioField
  491. name="radio"
  492. label="Radio Field"
  493. onChange={onChange}
  494. choices={[
  495. ['choice_one', 'Choice One'],
  496. ['choice_two', 'Choice Two'],
  497. ['choice_three', 'Choice Three'],
  498. ]}
  499. />
  500. <Switch id="test" />
  501. </div>
  502. );
  503. };
  504. WithoutAParentForm.storyName = 'Without a Parent Form';
  505. WithoutAParentForm.argTypes = {
  506. onChange: {action: 'onChange'},
  507. };
  508. WithoutAParentForm.parameters = {
  509. docs: {
  510. description: {
  511. story: 'New form fields used without having a parent Form',
  512. },
  513. },
  514. };
  515. export const __TextCopyInput = () => (
  516. <TextCopyInput onCopy={action('Copied!')}>Value to be copied </TextCopyInput>
  517. );
  518. __TextCopyInput.storyName = 'Text Copy';