ããã«ã¡ã¯ãDOGOï¼ã©ããï¼ãã¼ã ã®ã¾ã£ã¤ã¼ï¼@ryo-manbaï¼ã§ããDOGO ãã¼ã ã§ã¯ãããµã¤ãã¦ãº Officeã ã®ããã³ãã¨ã³ãå·æ°ãè¡ã£ã¦ãã¾ãããã®è¨äºã§ã¯ãããã³ãã¨ã³ãå·æ°ãé²ãã¦ããä¸ã§åãçµãã§ããã¢ã¯ã»ã·ããªãã£æ¹åã«ã¤ãã¦ç´¹ä»ãã¾ãã
â» ãã®è¨äºã¯ Cybozu Frontend Advent Calendar 2023 ã® 1æ¥ç®ã®è¨äºã§ãã
DOGO ã¨ã¯
DOGO ã¯ããµã¤ãã¦ãº Office ã®ããã³ãã¨ã³ããå·æ°ããããã¸ã§ã¯ãã§ããç¬èªã®ã¹ã¯ãªããè¨èªã§æ¸ããã MPAï¼Multi-Page Applicationï¼ããNext.js ã® App Router ã«ç»é¢åä½ã§ç½®ãæãã¦ãã¾ããç¾å¨ãã¨ã³ã¸ãã¢7å㨠QA 2åã®è¨9åã§é²è¡ä¸ã§ãã詳細ã¯ä»¥ä¸ã®ãªã³ã¯ããã確èªããã ãã¾ãã
ããã¾ã§ã«6ç»é¢ã®ãªãªã¼ã¹ãå®äºãã¦ããããã®éç¨ã§ã¢ã¯ã»ã·ããªãã£ã®æ¹åã«ãåãçµãã§ãã¾ãã
å·æ°åã®åé¡ç¹
ãµã¤ãã¦ãº Officeã®ããã³ãã¨ã³ãå·æ°ã«ããããã¢ã¯ã»ã·ããªãã£ã®åä¸ã¯éè¦ãªèª²é¡ã§ãããããã¾ã§æ¨ªæçãªã¢ã¯ã»ã·ããªãã£ã®åä¸ãç®çã¨ãã Poca11yï¼ãã«ãªï¼ãã¼ã ãä¸å¿ã«å¤ãã®æ¹åããªããã¦ãã¾ãããããããã»ãã³ãã£ãã¯ãªãã¼ã¯ã¢ããã W3C ãæ¨å¥¨ãããã¼ãã¼ããµãã¼ããWAI-ARIA å±æ§ã®è¨å®ãªã©ããããªãæ¹è¯ã®ä½å°ãæ®ããã¦ãã¾ããããã§ãå·æ°ã®éã«ãããã®è¦ç´ ãæ¹åãããã¨ãç®æ¨ã«æ²ãã¾ããã
ããããå·æ°ã®ä¸»ç®çã¯å ¨ç»é¢ã®è¿ éãªç½®ãæãã§ãããããä¸ã¤ã®ç»é¢ã«å²ããæéã¯éããã¦ãã¾ããå ãã¦ãDOGO ãã¼ã ã¯å°äººæ°ã§æ§æãããkintone ã®ããã«ãã¶ã¤ã³ã·ã¹ãã å°éãã¼ã ã®ãµãã¼ãã¯ããã¾ããã§ããããã®ãããå°äººæ°ã§ãå¹ççã«é²ããããã¢ã¯ã»ã·ããªãã£æ¹åã®åãçµã¿ãæ±ãããã¾ããã
ã¢ã¯ã»ã·ããªãã£æ¹åã®åãçµã¿
輪èªä¼ã®å®æ½
ãã¼ã ã¡ã³ãã¼ã®åæç¥èã®çµ±ä¸ã¨ç解ãæ·±ããããã«ãWebã¢ããªã±ã¼ã·ã§ã³ã¢ã¯ã»ã·ããªãã£ã®è¼ªèªä¼ãéå¬ãã¾ããããã®è¼ªèªä¼ã¯é±ã«1åè¡ãããäºåã«æå®ãããç« ãèªã¿é²ããå½¢å¼ã§é²è¡ãã¾ãããååã§ã¯ããã¡ã·ãªãã¼ã¿ã¼ããã®ç« ã®æ¦è¦ãããããããå¾ãåå è ãææ³ãèããå ±æãã¾ããã
éè¦ãªã®ã¯ãå ·ä½ç㪠Tips ããããã©ã®ãããªç¶æ ãã¢ã¯ã»ã·ãã«ã§ããããã©ã®ãããªç¶æ³ã§è£½åã使ç¨ããããã«é¢ããå ±éã®ç解ãæ·±ãããã¨ã§ãããå人çã«ç¹ã«å°è±¡ã«æ®ã£ãã®ã¯ãä¸æçãªé害ã«ãã£ã¦ãã¦ã¼ã¶ã¼ä½é¨ãã©ã®ããã«å¤ãããã«ã¤ãã¦ã®èªèã§ããä¾ãã°ãè¦è¦ã«é¢é£ãã¦ã¯ãã¡ã¬ããå¿ããå ´åããè´è¦ã«é¢é£ãã¦ã¯ãBluetooth ã¤ã¤ãã³ã®å é»ãåããå ´åãã¨ãã£ãã·ããªãªãéãã¦ãã¢ã¯ã»ã·ããªãã£ã¯ä¸é¨ã®äººã ã ãã§ãªããåºç¯ãªã¦ã¼ã¶ã¼ã«å½±é¿ãåã¼ããã¨ãç解ãã¾ããããã®ãããªå ±éèªèããã¼ã å ã§å½¢æããããã¨ã¯ãããã¸ã§ã¯ãã«ã¨ã£ã¦å¤§ããªåé²ã ã£ãããã«æãã¾ãã
OSS ããã«æ´»ç¨ããã³ã³ãã¼ãã³ãå®è£
å°äººæ°ã®ãã¼ã ã§ã¢ã¯ã»ã·ããªãã£ã®æ¹åã«å¹ççã«åãçµãããã«ãOSS ã® Headless UI ã©ã¤ãã©ãªã®å°å ¥ãæ¤è¨ãã¾ãããHeadless UI ã©ã¤ãã©ãªã¨ã¯è¦ãç®ã«é¢ããã¹ã¿ã¤ã«ã¯æä¾ããã主ã«ã¢ã¯ã»ã·ããªãã£å¯¾å¿ã®ããã®ãã¸ãã¯ãæä¾ããã©ã¤ãã©ãªã§ããå ·ä½çã«ã¯ Radix UI ã Headless UI ã®ãããªã©ã¤ãã©ãªãããã¾ãããããã® Headless UI ã©ã¤ãã©ãªç¾¤ã¨ DOM 以å¤ã®æ¯ãèãã¨ã¢ã¯ã»ã·ããªãã£ãæ ã React Aria ã Zag.js ã® Pros/ Cons ãåæããADRï¼Architecture Decision Recordï¼ãåºã«ãã¼ã å ã§è°è«ãã¾ãããæçµçã«ãæè»ãªã«ã¹ã¿ãã¤ãºãå¯è½ãª Hooks å½¢å¼ã® React Aria ã®å°å ¥ã決å®ãã¾ããã
å°å ¥ã«ãããããã¼ã å 㧠React Ariaã®ããã¥ã¡ã³ããå®è£ ã«åºã¥ãåå¼·ä¼ãå®æ½ãã¾ãããããã«ãããä¸å®ã®å¦ç¿ã³ã¹ãã¯ããããã®ã®ããã以ä¸ã«å¾ãããæ©æµã®ã»ãã大ããã¨å¤æããä¸é¨ã®ã³ã³ãã¼ãã³ãã®ã¿ã§ã¯ãªããå ¨é¢çãªå°å ¥ã«è¸ã¿åããã¨ãã§ãã¾ããã
ããã«ãReact Aria ã® Hooks ãå©ç¨ãã Headless UI ã©ã¤ãã©ãªã§ãã React Aria Components ããªãªã¼ã¹åè£ï¼RCï¼ã«éãããã¨ããã*1ãReact Aria Components ã使ç¨ããã³ã³ãã¼ãã³ãã®ç½®ãæããé²è¡ä¸ã§ããã¾ã RC 段éã® OSS ã©ã¤ãã©ãªãæ¡ç¨ããã«è³ã£ãèæ¯ã«ã¯ãåã« OSS ãå©ç¨ããã ãã§ãªããç©æ¥µçã« upstream ã¸ã®è²¢ç®ãç®æãã¨ãããã¼ã ã®æ¹éã«åºã¥ããã®ã§ãããç¾ã«å©ç¨ãå§ãã¦ããåå¹´ç¨åº¦ã§8件ãã®ã³ã³ããªãã¥ã¼ã·ã§ã³ãè¡ã£ã¦ãã¾ãã
æ¹åäºä¾ï¼DatePicker
æ¹åäºä¾ã¨ãã¦ãDatePickerã³ã³ãã¼ãã³ããæ°ãã«å®è£ ãã¾ãããå·æ°åã®ç»é¢ã§ã¯ table ãç¨ããã¹ã¿ã¤ã«èª¿æ´ã主ã§ããã¼ãã¼ãæä½ã WAI-ARIA å±æ§ã®è¨å®ãä¸ååã§ãããä¾ãã°ãæ¥ä»é¸æã®ããã®ãã¼ãã¼ãæä½ã Tab ãã¼ã«éå®ããã¦ããããã¨ã¹ã±ã¼ããã¼ã§ã«ã¬ã³ãã¼ãã¤ã¢ãã°ãéãããã¨ãã§ããªããªã©ãã¦ã¼ã¶ããªãã£ã®è¦³ç¹ããæ¹åã®ä½å°ãããã¾ããã
React Aria ã®å°å ¥ã«ãããAPGï¼W3Cãæä¾ããã¢ã¯ã»ã·ããªãã£åä¸ã®ããã®ã¬ã¤ãã©ã¤ã³ï¼ã«æ²¿ã£ããã¼ãã¼ããµãã¼ããå®ç¾ãããã¨ãå¯è½ã«ãªãã¾ãããå ·ä½çã«ã¯ãååãã¼ã«ããæ¥ä»ã»ã«ã®ç§»åãã¨ã¹ã±ã¼ããã¼ã使ã£ã¦ãã¤ã¢ãã°ãéããæ©è½ãªã©ã追å ãããããç´æçã«æä½ãã§ããããã«æ¹åããã¦ãã¾ãã
å ãã¦ãé©å㪠WAI-ARIA ãæ½ããã¨ã§ã¢ã¯ã»ã·ãã«ãªã³ã³ãã¼ãã³ãã®å®ç¾ãå³ãã¾ãããããã«ãããDatePicker ã®è¦ãç®ã¯ããã¾ã§ã¨å¤§ããªå¤æ´ã¯ãªããã®ã®ããã¾ãã¾ãªã¦ã¼ã¶ã¼ãæä½ããããå½¢ã«æ¹åããã¾ããã
åè¿°ã® Poca11yãã¼ã ããã®ãã£ã¼ãããã¯ãåãã¦ãããªãæ¹åç¹ãçºè¦ããReact Aria ã«å¯¾ãã¦ãè²¢ç®ãããã¨ãã§ãã¾ããã
Poca11y ãã¼ã ã¨ã®åå
Poca11y ãã¼ã ã¨ã®é£æºã大ããªæ¯ãã¨ãªã£ã¦ãã¾ãã社å ã§ãã¤ã§ãç¸è«ã§ããç°å¢ããããã¢ããªã±ã¼ã·ã§ã³åºæã®äºæ ã§ç¹æ®ãªãã¼ã¯ã¢ãããå¿ è¦ã¨ãªã£ãå ´åããããã¢ã¯ã»ã·ãã«ã«ããããã®æ¹åæ¹æ³ãªã©ã®ç¸è«ã«ä¹ã£ã¦ãããããã¼ã ã¯ã¼ã¯ã§ããè¯ãå·æ°ãè¡ããã¨ãã§ãã¦ãã¾ãã
å
·ä½çãªäºä¾ã§ã¯ãèªã¿è¾¼ã¿ç¶æ
ã表示ãã Loading Indicator ã®å®è£
ãããã¾ãã
ã¢ã¯ã»ã·ããªãã£ãèæ
®ããå®è£
ã«ã¤ãã¦èª¿ã¹ã¦ã¿ãã¨ãrole
ãaria-busy
ãaria-live
ãªã©ãã¾ãã¾ãª WAI-ARIA å±æ§ãåè£ã¨ãã¦æããã¾ãããç¹ã« aria-busy="true"
㨠aria-live="polite"
ã®çµã¿åãããã¾ã㯠role="alert"
㨠aria-live="assertive"
ã®ããããã®ä½¿ç¨ã«ã¤ãã¦æ¤è¨ãã¦ãã¾ããã
ããããã©ã¡ãã®å®è£
ã«ã¤ãã¦ã確信ãæã¦ãªãã£ããããPoca11y ãã¼ã ã«ç¸è«ãã¾ããããã®çµæãaria-busy
å±æ§ã¯ãã¼ãã¼ã«å¯¾ãã¦ã§ã¯ãªããæ´æ°ä¸ã®è¦ç´ ã«å¯¾ãã¦ä½¿ç¨ãã¹ãã§ãããã¨ãã¾ã aria-live="assertive"
ã¯ç·æ¥æ§ã®é«ãæ
å ±ã«é©ãã¦ãããããLoading Indicator ã«ã¯é©ããªããã¨ãåããã¾ããããããã®å©è¨ãåããæçµçã« role="status" aria-live="polite"
ãç¨ããå®è£
ã«è½ã¡çããããåªããã¦ã¼ã¶ã¼ä½é¨ãæä¾ãããã¨ã«ç¹ããã¾ããã
ãã®ããã«ã¢ã¯ã»ã·ããªãã£ã®å°éãã¼ã ã«ãããæ¹åæ¡ãææ¡ãã¦ããããã®ã¯ãDOGO ãã¼ã ã«ã¨ã£ã¦ã大ããªå¦ã³ã®æ©ä¼ã§ããã¢ã¯ã»ã·ããªãã£ã«é¢ãããã¬ã³ããææ³ãç¶ç¶çã«å¦ã¶ãã¨ãã§ããã¡ã³ãã¼ã®ã¹ãã«ã¢ããã«ãç¹ãã£ã¦ãã¾ãã
ãããã«
DOGO ãã¼ã ã§ã¯å·æ°ã«ããããåãªããã¬ã¼ã ã¯ã¼ã¯ã®ç½®ãæãã«çã¾ãããã¢ã¯ã»ã·ããªãã£ã®æ¹åãå§ãã¨ãã製åãããè¯ãã使ããããããããã®åãçµã¿ãè¡ã£ã¦ãã¾ããã¾ãç¾å¨ QA ãã¢ã¯ã»ã·ããªãã£ã®ãã§ãã¯ã·ã¼ããä½æãã¦ããããã¼ã å ¨ä½ã§ã¢ã¯ã»ã·ããªãã£æ¹åã®åãçµã¿ãé²ãã¦ããäºå®ã§ããå°ããªãã¼ã ã§ã¯ããã¾ãããä»å¾ãç¶ç¶çãªæ¹åãç®æãã¦ãã¾ãã
â¼Cybozu Frontend Advent Calendar ã¯ãã¡ã
*1:2023å¹´11ææ«æç¹ã§ã® React Aria Components ã®ã¡ã³ããã¼ã® X ã®ãã¹ãã«ããã¨ã2023 å¹´ä¸ã«ã¯ stable ã® v1 ããªãªã¼ã¹äºå®