@@ -23,12 +23,10 @@ import {
2323 MdDelete ,
2424 MdEdit ,
2525 MdRemove ,
26+ MdHelp ,
2627} from 'react-icons/md' ;
2728import { BadVisual } from '../../components/examples/link' ;
28- import {
29- ExampleContainer ,
30- FieldWithBadErrorMessage ,
31- } from '../../components/examples' ;
29+ import { ExampleContainer } from '../../components/examples' ;
3230import { styled } from 'styled-components' ;
3331
3432const SmallButton = styled . button `
@@ -62,6 +60,51 @@ const GrayText = styled.p`
6260 color: #999;
6361` ;
6462
63+ const ErrorMessage = styled ( P ) `
64+ color: #dc1e32;
65+ ` ;
66+
67+ const HelpIcon = styled . span `
68+ color: #8c8989;
69+ font-size: 1.5em;
70+ margin-left: 0.25em;
71+ cursor: pointer;
72+ position: relative;
73+ display: inline-block;
74+ ` ;
75+ const Help = styled . span `
76+ display: none;
77+ position: absolute;
78+ bottom: calc(100% + 0.5rem);
79+ color: #323232;
80+ left: -1.25rem;
81+ background-color: #fff;
82+ border: 1px solid #d7d2d2;
83+ padding: 0.5em;
84+ border-radius: 0.25em;
85+ box-shadow: 1px 2px 4px 0 rgba(0, 0, 0, 0.3);
86+ z-index: 1;
87+ width: 20rem;
88+ font-size: 0.75rem;
89+ font-weight: normal;
90+ &:before {
91+ content: '';
92+ position: absolute;
93+ top: 100%;
94+ left: calc(1.5rem - 2px);
95+ border: calc(0.5em + 2px) solid transparent;
96+ border-top-color: #d7d2d2;
97+ }
98+ &:after {
99+ content: '';
100+ position: absolute;
101+ top: 100%;
102+ left: 1.5rem;
103+ border: 0.5em solid transparent;
104+ border-top-color: #fff;
105+ }
106+ ` ;
107+
65108const Practice = ( ) : JSX . Element => {
66109 React . useEffect ( ( ) => {
67110 const html = document . getElementsByTagName ( 'html' ) [ 0 ] ;
@@ -87,6 +130,11 @@ const Practice = (): JSX.Element => {
87130 | 'overseas'
88131 > ( ) ;
89132 const [ counter , setCounter ] = React . useState ( 12345 ) ;
133+ const [ postalCode , setPostalCode ] = React . useState ( '' ) ;
134+ const postalCodeTouchedRef = React . useRef ( false ) ;
135+ const [ postalCodeMessage , setPostalCodeMessage ] = React . useState ( '' ) ;
136+ const [ helpHover , setHelpHover ] = React . useState ( false ) ;
137+ const [ agree , setAgree ] = React . useState ( false ) ;
90138
91139 return (
92140 < >
@@ -164,7 +212,24 @@ const Practice = (): JSX.Element => {
164212 as = "span"
165213 />
166214 </ ExampleContainer >
167- < H4 > カウンター</ H4 >
215+ < H4 >
216+ カウンター
217+ < HelpIcon >
218+ < MdHelp
219+ role = "img"
220+ aria-label = "ヘルプ"
221+ onMouseEnter = { ( ) => setHelpHover ( true ) }
222+ onMouseLeave = { ( ) => setHelpHover ( false ) }
223+ onFocus = { ( ) => setHelpHover ( true ) }
224+ onBlur = { ( ) => setHelpHover ( false ) }
225+ tabIndex = { 0 }
226+ />
227+ < Help style = { { display : helpHover ? 'block' : 'none' } } >
228+ カウンターの値を増減するボタンです。ボタンを押すとカウンターの値が増減します。
229+ 詳しくは < TextLink href = "http://example.com/" > こちら</ TextLink >
230+ </ Help >
231+ </ HelpIcon >
232+ </ H4 >
168233 < ExampleContainer >
169234 < SmallButton
170235 onClick = { ( ) => setCounter ( counter + 1 ) }
@@ -381,25 +446,95 @@ const Practice = (): JSX.Element => {
381446 </ fieldset >
382447 </ FormItem >
383448 < FormItem >
384- < CheckBox name = "toc" value = "agree" >
385- 利用規約に同意する
386- </ CheckBox >
449+ < label htmlFor = "postal_code" >
450+ < FormLabel > 郵便番号</ FormLabel >
451+ </ label >
452+ < TextField
453+ type = "text"
454+ value = { postalCode }
455+ onFocus = { ( ) => {
456+ postalCodeTouchedRef . current = true ;
457+ setPostalCodeMessage (
458+ postalCodeTouchedRef . current &&
459+ ! postalCode . match ( / ^ [ 0 - 9 ] { 3 } - [ 0 - 9 ] { 4 } $ / )
460+ ? '入力形式が正しくありません'
461+ : ''
462+ ) ;
463+ } }
464+ onChange = { ( e ) => {
465+ const value = e . target . value ;
466+ setPostalCode ( value ) ;
467+ setPostalCodeMessage (
468+ postalCodeTouchedRef . current &&
469+ ! value . match ( / ^ [ 0 - 9 ] { 3 } - [ 0 - 9 ] { 4 } $ / )
470+ ? '入力形式が正しくありません'
471+ : ''
472+ ) ;
473+ } }
474+ placeholder = "141-0032"
475+ aria-label = "postal_code"
476+ id = "postal_code"
477+ />
478+ { postalCodeMessage && (
479+ < ErrorMessage > { postalCodeMessage } </ ErrorMessage >
480+ ) }
387481 </ FormItem >
388- </ ExampleContainer >
389- < ExampleContainer >
390- < FieldWithBadErrorMessage fieldAriaLabel = "postal-code" />
391- </ ExampleContainer >
392- < div style = { { marginTop : '1rem' } } >
393- < Button
394- onMouseDown = { ( ) => {
395- window . alert ( '送信しました' ) ;
482+ < div
483+ style = { {
484+ display : 'flex' ,
485+ alignItems : 'start' ,
486+ flexDirection : 'column-reverse' ,
487+ marginBottom : '1rem' ,
488+ gap : '1rem'
396489 } }
397- as = "span"
398- tabIndex = { 0 }
399490 >
400- 送信
401- </ Button >
402- </ div >
491+ < FormItem >
492+ < label htmlFor = "address" >
493+ < FormLabel > 住所</ FormLabel >
494+ </ label >
495+ < TextField type = "text" id = "address" />
496+ </ FormItem >
497+ < FormItem >
498+ < label htmlFor = "city" >
499+ < FormLabel > 市区町村</ FormLabel >
500+ </ label >
501+ < TextField type = "text" id = "city" />
502+ </ FormItem >
503+ < FormItem >
504+ < label htmlFor = "prefecture" >
505+ < FormLabel > 都道府県</ FormLabel >
506+ </ label >
507+ < TextField type = "text" id = "prefecture" />
508+ </ FormItem >
509+ </ div >
510+ < FormItem >
511+ < Button
512+ onMouseDown = { ( ) => {
513+ window . alert (
514+ postalCodeMessage
515+ ? '送信できません。入力内容を確認してください' :
516+ ! agree || ! postalCode ? '入力が不正です'
517+ : '送信しました'
518+ ) ;
519+ } }
520+ as = "span"
521+ tabIndex = { 0 }
522+ >
523+ 送信
524+ </ Button >
525+
526+ < div style = { { display : 'inline-block' , marginLeft : '1rem' } } >
527+ < CheckBox
528+ name = "tos"
529+ value = "agree"
530+ checked = { agree }
531+ onChange = { ( e ) => setAgree ( e . target . checked ) }
532+ >
533+ 利用規約に同意する
534+ </ CheckBox >
535+ </ div >
536+ </ FormItem >
537+ </ ExampleContainer >
403538 </ >
404539 ) ;
405540} ;
0 commit comments