Skip to content

feat: add new components, Sidebar, TreeView, Pagination, Progress Stepper, File Upload#73

Open
ross-nics wants to merge 15 commits into
mainfrom
feat/add-components-202606
Open

feat: add new components, Sidebar, TreeView, Pagination, Progress Stepper, File Upload#73
ross-nics wants to merge 15 commits into
mainfrom
feat/add-components-202606

Conversation

@ross-nics

Copy link
Copy Markdown

新增五個元件

本 PR 為設計指引新增五個無障礙元件,皆遵循原生 HTML 語意搭配 ARIA 補強、不僅依賴色彩傳達資訊、並符合最小點擊區域(2.5rem)與漸進增強原則。所有元件成熟度標示為 new

元件清單

元件 說明 變體
檔案上傳 (File Upload) 支援「點擊選擇」與「拖曳上傳」兩種方式,建構於原生 <input type="file"> 之上 預設、多檔案、已選取清單、錯誤狀態
分頁 (Pagination) 7 元素等寬等距排列,用於長內容清單導覽 已知總頁數、未知總頁數、簡易分頁
步驟指示器 (Progress Stepper) 呈現多步驟流程進度,使用 <ol>aria-current="step" 含標籤、含編號、無標籤
側邊導覽 (Side Navigation) 可展開/收合的階層式導覽,支援多層巢狀 基本、多層巢狀
樹狀檢視 (Tree View) 階層資料呈現,採 Roving tabindex 與完整鍵盤操作,遵循 WAI-ARIA APG 基本範例

主要變更內容

  • 內容文件:新增 5 份 content/components/*/_index.md,包含說明、變體、CSS 類別、使用規範、親和力與參考資料。
  • 樣式:新增 file-upload.scsspagination.scssprogress-stepper.scssside-navigation.scsstree-view.scss,並於 main.scss 匯入。
  • 範例 Partials:新增各元件的 live-example partial(含多種變體)。
  • JavaScript
    • side-navigation.js:切換 <button>aria-expanded 狀態。
    • tree-view.js:Roving tabindex 焦點管理與方向鍵展開/收合等完整鍵盤操作。

無障礙重點

  • File Upload:裝飾內容以 aria-hidden="true" 隱藏避免重複朗讀,錯誤以 aria-invalid 標示。
  • Pagination:<nav> 地標 + aria-current="page",省略符號以 aria-hidden 隱藏並補語意標籤。
  • Progress Stepper:aria-current="step" 與視覺隱藏的完成狀態文字。
  • Side Navigation:原生 <nav>/<ul>/<button> + aria-expanded/aria-current,當前頁面同時以粗體與左側邊框指示。
  • Tree View:role="tree"/group/treeitemaria-levelaria-labelledby(修正 VoiceOver 相容性)。

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces several new accessible UI components, including side navigation, tree view, pagination, progress stepper, and file upload, complete with SCSS styles, JavaScript behavior, HTML partials, and documentation. Feedback on these additions highlights opportunities to improve accessibility and robustness: specifically, refining the tree view click handler to target labels and prioritizing selected nodes for roving tabindex, adding outline: none to the transparent file input to prevent overlapping focus rings, ensuring progressive enhancement for the side navigation when JavaScript is disabled, and ensuring pre-selected tree view nodes are visible by default by expanding their parent elements.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread static/js/components/tree-view.js
Comment thread assets/css/components/file-upload.scss
Comment thread assets/css/components/side-navigation.scss Outdated
Comment on lines +44 to +52
function ensureSingleTabstop () {
const all = items()
if (all.length === 0) return
const hasFocusable = all.some(it => it.tabIndex === 0)
all.forEach(it => {
if (it.tabIndex !== 0 && it.tabIndex !== -1) it.tabIndex = -1
})
if (!hasFocusable) all[0].tabIndex = 0
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

ensureSingleTabstop() 中,若目前沒有可聚焦的節點,預設會將第一個節點(all[0])設為 tabIndex = 0。然而,如果樹狀檢視中已經有被選取的節點(aria-selected="true"),根據 WAI-ARIA APG 最佳實踐,應優先將焦點停靠點設在該選取節點上,以提供更好的鍵盤操作體驗。

  function ensureSingleTabstop () {
    const all = items()
    if (all.length === 0) return
    const hasFocusable = all.some(it => it.tabIndex === 0)
    all.forEach(it => {
      if (it.tabIndex !== 0 && it.tabIndex !== -1) it.tabIndex = -1
    })
    if (!hasFocusable) {
      const selected = all.find(it => it.getAttribute('aria-selected') === 'true')
      if (selected) {
        selected.tabIndex = 0
      } else {
        all[0].tabIndex = 0
      }
    }
  }

Comment on lines +15 to +22
<li
role="treeitem"
aria-expanded="false"
aria-level="2"
aria-selected="false"
aria-labelledby="tvb-js"
tabindex="-1"
>

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

在此基本範例中,子節點「共同投標」預設為選取狀態(aria-selected="true"),但其父節點「採購作業」卻預設為收合狀態(aria-expanded="false")。這會導致頁面載入時,當前選取的活動節點被隱藏,使用者無法直觀地看到自己目前所在的位置。建議將父節點的預設狀態改為展開(aria-expanded="true")。

Suggested change
<li
role="treeitem"
aria-expanded="false"
aria-level="2"
aria-selected="false"
aria-labelledby="tvb-js"
tabindex="-1"
>
<li
role="treeitem"
aria-expanded="true"
aria-level="2"
aria-selected="false"
aria-labelledby="tvb-js"
tabindex="-1"
>

@nonumpa nonumpa added the ci-lighthouse trigger lighthouse check label Jun 9, 2026
@ross-nics ross-nics force-pushed the feat/add-components-202606 branch from 0ba1e2f to bb4b232 Compare June 9, 2026 07:21
@github-actions

github-actions Bot commented Jun 9, 2026

Copy link
Copy Markdown

- tree-view: restrict click handling to .tree-view__label to avoid parent node mis-selection on nested group whitespace
- tree-view: prefer aria-selected node for initial roving tabstop (WAI-ARIA APG)
- file-upload: hide native input default focus ring (outline: none); focus shown on button via :focus-within
- side-navigation: gate collapsed-submenu hiding behind [data-js-enhanced] for progressive enhancement
@ross-nics ross-nics added ci-lighthouse trigger lighthouse check and removed ci-lighthouse trigger lighthouse check labels Jun 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci-lighthouse trigger lighthouse check

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants