diff --git a/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages.json b/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages.json new file mode 100644 index 00000000000..d8845d0a69a --- /dev/null +++ b/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages.json @@ -0,0 +1,7 @@ +{ + "keyboardDeselect": "Press Enter or Space to deselect row", + "keyboardSelect": "Press Enter or Space to select row", + "row": "row", + "selected": "selected", + "unselected": "unselected" +} diff --git a/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_ar.json b/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_ar.json new file mode 100644 index 00000000000..d8845d0a69a --- /dev/null +++ b/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_ar.json @@ -0,0 +1,7 @@ +{ + "keyboardDeselect": "Press Enter or Space to deselect row", + "keyboardSelect": "Press Enter or Space to select row", + "row": "row", + "selected": "selected", + "unselected": "unselected" +} diff --git a/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_bg.json b/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_bg.json new file mode 100644 index 00000000000..d8845d0a69a --- /dev/null +++ b/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_bg.json @@ -0,0 +1,7 @@ +{ + "keyboardDeselect": "Press Enter or Space to deselect row", + "keyboardSelect": "Press Enter or Space to select row", + "row": "row", + "selected": "selected", + "unselected": "unselected" +} diff --git a/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_bs.json b/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_bs.json new file mode 100644 index 00000000000..d8845d0a69a --- /dev/null +++ b/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_bs.json @@ -0,0 +1,7 @@ +{ + "keyboardDeselect": "Press Enter or Space to deselect row", + "keyboardSelect": "Press Enter or Space to select row", + "row": "row", + "selected": "selected", + "unselected": "unselected" +} diff --git a/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_ca.json b/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_ca.json new file mode 100644 index 00000000000..d8845d0a69a --- /dev/null +++ b/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_ca.json @@ -0,0 +1,7 @@ +{ + "keyboardDeselect": "Press Enter or Space to deselect row", + "keyboardSelect": "Press Enter or Space to select row", + "row": "row", + "selected": "selected", + "unselected": "unselected" +} diff --git a/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_cs.json b/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_cs.json new file mode 100644 index 00000000000..d8845d0a69a --- /dev/null +++ b/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_cs.json @@ -0,0 +1,7 @@ +{ + "keyboardDeselect": "Press Enter or Space to deselect row", + "keyboardSelect": "Press Enter or Space to select row", + "row": "row", + "selected": "selected", + "unselected": "unselected" +} diff --git a/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_da.json b/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_da.json new file mode 100644 index 00000000000..d8845d0a69a --- /dev/null +++ b/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_da.json @@ -0,0 +1,7 @@ +{ + "keyboardDeselect": "Press Enter or Space to deselect row", + "keyboardSelect": "Press Enter or Space to select row", + "row": "row", + "selected": "selected", + "unselected": "unselected" +} diff --git a/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_de.json b/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_de.json new file mode 100644 index 00000000000..d8845d0a69a --- /dev/null +++ b/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_de.json @@ -0,0 +1,7 @@ +{ + "keyboardDeselect": "Press Enter or Space to deselect row", + "keyboardSelect": "Press Enter or Space to select row", + "row": "row", + "selected": "selected", + "unselected": "unselected" +} diff --git a/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_el.json b/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_el.json new file mode 100644 index 00000000000..d8845d0a69a --- /dev/null +++ b/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_el.json @@ -0,0 +1,7 @@ +{ + "keyboardDeselect": "Press Enter or Space to deselect row", + "keyboardSelect": "Press Enter or Space to select row", + "row": "row", + "selected": "selected", + "unselected": "unselected" +} diff --git a/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_en.json b/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_en.json new file mode 100644 index 00000000000..d8845d0a69a --- /dev/null +++ b/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_en.json @@ -0,0 +1,7 @@ +{ + "keyboardDeselect": "Press Enter or Space to deselect row", + "keyboardSelect": "Press Enter or Space to select row", + "row": "row", + "selected": "selected", + "unselected": "unselected" +} diff --git a/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_es.json b/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_es.json new file mode 100644 index 00000000000..d8845d0a69a --- /dev/null +++ b/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_es.json @@ -0,0 +1,7 @@ +{ + "keyboardDeselect": "Press Enter or Space to deselect row", + "keyboardSelect": "Press Enter or Space to select row", + "row": "row", + "selected": "selected", + "unselected": "unselected" +} diff --git a/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_et.json b/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_et.json new file mode 100644 index 00000000000..d8845d0a69a --- /dev/null +++ b/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_et.json @@ -0,0 +1,7 @@ +{ + "keyboardDeselect": "Press Enter or Space to deselect row", + "keyboardSelect": "Press Enter or Space to select row", + "row": "row", + "selected": "selected", + "unselected": "unselected" +} diff --git a/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_fi.json b/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_fi.json new file mode 100644 index 00000000000..d8845d0a69a --- /dev/null +++ b/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_fi.json @@ -0,0 +1,7 @@ +{ + "keyboardDeselect": "Press Enter or Space to deselect row", + "keyboardSelect": "Press Enter or Space to select row", + "row": "row", + "selected": "selected", + "unselected": "unselected" +} diff --git a/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_fr.json b/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_fr.json new file mode 100644 index 00000000000..d8845d0a69a --- /dev/null +++ b/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_fr.json @@ -0,0 +1,7 @@ +{ + "keyboardDeselect": "Press Enter or Space to deselect row", + "keyboardSelect": "Press Enter or Space to select row", + "row": "row", + "selected": "selected", + "unselected": "unselected" +} diff --git a/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_he.json b/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_he.json new file mode 100644 index 00000000000..d8845d0a69a --- /dev/null +++ b/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_he.json @@ -0,0 +1,7 @@ +{ + "keyboardDeselect": "Press Enter or Space to deselect row", + "keyboardSelect": "Press Enter or Space to select row", + "row": "row", + "selected": "selected", + "unselected": "unselected" +} diff --git a/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_hr.json b/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_hr.json new file mode 100644 index 00000000000..d8845d0a69a --- /dev/null +++ b/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_hr.json @@ -0,0 +1,7 @@ +{ + "keyboardDeselect": "Press Enter or Space to deselect row", + "keyboardSelect": "Press Enter or Space to select row", + "row": "row", + "selected": "selected", + "unselected": "unselected" +} diff --git a/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_hu.json b/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_hu.json new file mode 100644 index 00000000000..d8845d0a69a --- /dev/null +++ b/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_hu.json @@ -0,0 +1,7 @@ +{ + "keyboardDeselect": "Press Enter or Space to deselect row", + "keyboardSelect": "Press Enter or Space to select row", + "row": "row", + "selected": "selected", + "unselected": "unselected" +} diff --git a/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_id.json b/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_id.json new file mode 100644 index 00000000000..d8845d0a69a --- /dev/null +++ b/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_id.json @@ -0,0 +1,7 @@ +{ + "keyboardDeselect": "Press Enter or Space to deselect row", + "keyboardSelect": "Press Enter or Space to select row", + "row": "row", + "selected": "selected", + "unselected": "unselected" +} diff --git a/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_it.json b/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_it.json new file mode 100644 index 00000000000..d8845d0a69a --- /dev/null +++ b/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_it.json @@ -0,0 +1,7 @@ +{ + "keyboardDeselect": "Press Enter or Space to deselect row", + "keyboardSelect": "Press Enter or Space to select row", + "row": "row", + "selected": "selected", + "unselected": "unselected" +} diff --git a/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_ja.json b/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_ja.json new file mode 100644 index 00000000000..d8845d0a69a --- /dev/null +++ b/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_ja.json @@ -0,0 +1,7 @@ +{ + "keyboardDeselect": "Press Enter or Space to deselect row", + "keyboardSelect": "Press Enter or Space to select row", + "row": "row", + "selected": "selected", + "unselected": "unselected" +} diff --git a/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_ko.json b/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_ko.json new file mode 100644 index 00000000000..d8845d0a69a --- /dev/null +++ b/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_ko.json @@ -0,0 +1,7 @@ +{ + "keyboardDeselect": "Press Enter or Space to deselect row", + "keyboardSelect": "Press Enter or Space to select row", + "row": "row", + "selected": "selected", + "unselected": "unselected" +} diff --git a/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_lt.json b/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_lt.json new file mode 100644 index 00000000000..d8845d0a69a --- /dev/null +++ b/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_lt.json @@ -0,0 +1,7 @@ +{ + "keyboardDeselect": "Press Enter or Space to deselect row", + "keyboardSelect": "Press Enter or Space to select row", + "row": "row", + "selected": "selected", + "unselected": "unselected" +} diff --git a/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_lv.json b/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_lv.json new file mode 100644 index 00000000000..d8845d0a69a --- /dev/null +++ b/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_lv.json @@ -0,0 +1,7 @@ +{ + "keyboardDeselect": "Press Enter or Space to deselect row", + "keyboardSelect": "Press Enter or Space to select row", + "row": "row", + "selected": "selected", + "unselected": "unselected" +} diff --git a/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_nl.json b/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_nl.json new file mode 100644 index 00000000000..d8845d0a69a --- /dev/null +++ b/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_nl.json @@ -0,0 +1,7 @@ +{ + "keyboardDeselect": "Press Enter or Space to deselect row", + "keyboardSelect": "Press Enter or Space to select row", + "row": "row", + "selected": "selected", + "unselected": "unselected" +} diff --git a/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_no.json b/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_no.json new file mode 100644 index 00000000000..d8845d0a69a --- /dev/null +++ b/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_no.json @@ -0,0 +1,7 @@ +{ + "keyboardDeselect": "Press Enter or Space to deselect row", + "keyboardSelect": "Press Enter or Space to select row", + "row": "row", + "selected": "selected", + "unselected": "unselected" +} diff --git a/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_pl.json b/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_pl.json new file mode 100644 index 00000000000..d8845d0a69a --- /dev/null +++ b/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_pl.json @@ -0,0 +1,7 @@ +{ + "keyboardDeselect": "Press Enter or Space to deselect row", + "keyboardSelect": "Press Enter or Space to select row", + "row": "row", + "selected": "selected", + "unselected": "unselected" +} diff --git a/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_pt-BR.json b/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_pt-BR.json new file mode 100644 index 00000000000..d8845d0a69a --- /dev/null +++ b/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_pt-BR.json @@ -0,0 +1,7 @@ +{ + "keyboardDeselect": "Press Enter or Space to deselect row", + "keyboardSelect": "Press Enter or Space to select row", + "row": "row", + "selected": "selected", + "unselected": "unselected" +} diff --git a/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_pt-PT.json b/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_pt-PT.json new file mode 100644 index 00000000000..d8845d0a69a --- /dev/null +++ b/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_pt-PT.json @@ -0,0 +1,7 @@ +{ + "keyboardDeselect": "Press Enter or Space to deselect row", + "keyboardSelect": "Press Enter or Space to select row", + "row": "row", + "selected": "selected", + "unselected": "unselected" +} diff --git a/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_ro.json b/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_ro.json new file mode 100644 index 00000000000..d8845d0a69a --- /dev/null +++ b/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_ro.json @@ -0,0 +1,7 @@ +{ + "keyboardDeselect": "Press Enter or Space to deselect row", + "keyboardSelect": "Press Enter or Space to select row", + "row": "row", + "selected": "selected", + "unselected": "unselected" +} diff --git a/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_ru.json b/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_ru.json new file mode 100644 index 00000000000..d8845d0a69a --- /dev/null +++ b/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_ru.json @@ -0,0 +1,7 @@ +{ + "keyboardDeselect": "Press Enter or Space to deselect row", + "keyboardSelect": "Press Enter or Space to select row", + "row": "row", + "selected": "selected", + "unselected": "unselected" +} diff --git a/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_sk.json b/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_sk.json new file mode 100644 index 00000000000..d8845d0a69a --- /dev/null +++ b/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_sk.json @@ -0,0 +1,7 @@ +{ + "keyboardDeselect": "Press Enter or Space to deselect row", + "keyboardSelect": "Press Enter or Space to select row", + "row": "row", + "selected": "selected", + "unselected": "unselected" +} diff --git a/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_sl.json b/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_sl.json new file mode 100644 index 00000000000..d8845d0a69a --- /dev/null +++ b/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_sl.json @@ -0,0 +1,7 @@ +{ + "keyboardDeselect": "Press Enter or Space to deselect row", + "keyboardSelect": "Press Enter or Space to select row", + "row": "row", + "selected": "selected", + "unselected": "unselected" +} diff --git a/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_sr.json b/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_sr.json new file mode 100644 index 00000000000..d8845d0a69a --- /dev/null +++ b/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_sr.json @@ -0,0 +1,7 @@ +{ + "keyboardDeselect": "Press Enter or Space to deselect row", + "keyboardSelect": "Press Enter or Space to select row", + "row": "row", + "selected": "selected", + "unselected": "unselected" +} diff --git a/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_sv.json b/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_sv.json new file mode 100644 index 00000000000..d8845d0a69a --- /dev/null +++ b/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_sv.json @@ -0,0 +1,7 @@ +{ + "keyboardDeselect": "Press Enter or Space to deselect row", + "keyboardSelect": "Press Enter or Space to select row", + "row": "row", + "selected": "selected", + "unselected": "unselected" +} diff --git a/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_th.json b/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_th.json new file mode 100644 index 00000000000..d8845d0a69a --- /dev/null +++ b/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_th.json @@ -0,0 +1,7 @@ +{ + "keyboardDeselect": "Press Enter or Space to deselect row", + "keyboardSelect": "Press Enter or Space to select row", + "row": "row", + "selected": "selected", + "unselected": "unselected" +} diff --git a/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_tr.json b/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_tr.json new file mode 100644 index 00000000000..d8845d0a69a --- /dev/null +++ b/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_tr.json @@ -0,0 +1,7 @@ +{ + "keyboardDeselect": "Press Enter or Space to deselect row", + "keyboardSelect": "Press Enter or Space to select row", + "row": "row", + "selected": "selected", + "unselected": "unselected" +} diff --git a/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_uk.json b/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_uk.json new file mode 100644 index 00000000000..d8845d0a69a --- /dev/null +++ b/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_uk.json @@ -0,0 +1,7 @@ +{ + "keyboardDeselect": "Press Enter or Space to deselect row", + "keyboardSelect": "Press Enter or Space to select row", + "row": "row", + "selected": "selected", + "unselected": "unselected" +} diff --git a/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_vi.json b/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_vi.json new file mode 100644 index 00000000000..d8845d0a69a --- /dev/null +++ b/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_vi.json @@ -0,0 +1,7 @@ +{ + "keyboardDeselect": "Press Enter or Space to deselect row", + "keyboardSelect": "Press Enter or Space to select row", + "row": "row", + "selected": "selected", + "unselected": "unselected" +} diff --git a/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_zh-CN.json b/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_zh-CN.json new file mode 100644 index 00000000000..d8845d0a69a --- /dev/null +++ b/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_zh-CN.json @@ -0,0 +1,7 @@ +{ + "keyboardDeselect": "Press Enter or Space to deselect row", + "keyboardSelect": "Press Enter or Space to select row", + "row": "row", + "selected": "selected", + "unselected": "unselected" +} diff --git a/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_zh-HK.json b/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_zh-HK.json new file mode 100644 index 00000000000..d8845d0a69a --- /dev/null +++ b/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_zh-HK.json @@ -0,0 +1,7 @@ +{ + "keyboardDeselect": "Press Enter or Space to deselect row", + "keyboardSelect": "Press Enter or Space to select row", + "row": "row", + "selected": "selected", + "unselected": "unselected" +} diff --git a/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_zh-TW.json b/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_zh-TW.json new file mode 100644 index 00000000000..d8845d0a69a --- /dev/null +++ b/packages/calcite-components/src/components/table-cell/assets/table-cell/t9n/messages_zh-TW.json @@ -0,0 +1,7 @@ +{ + "keyboardDeselect": "Press Enter or Space to deselect row", + "keyboardSelect": "Press Enter or Space to select row", + "row": "row", + "selected": "selected", + "unselected": "unselected" +} diff --git a/packages/calcite-components/src/components/table-cell/readme.md b/packages/calcite-components/src/components/table-cell/readme.md new file mode 100644 index 00000000000..7c9c20fd6bc --- /dev/null +++ b/packages/calcite-components/src/components/table-cell/readme.md @@ -0,0 +1,55 @@ +# calcite-table-cell + + + +## Properties + +| Property | Attribute | Description | Type | Default | +| ------------------ | ----------- | ----------------------------------------------------------------------------------------- | ------------------------------ | ----------- | +| `alignment` | `alignment` | Specifies the alignment of the component. | `"center" \| "end" \| "start"` | `"start"` | +| `colSpan` | `col-span` | | `number` | `undefined` | +| `messageOverrides` | -- | Use this property to override individual strings used by the component. | `{ focusReadout?: string; }` | `undefined` | +| `rowSpan` | `row-span` | | `number` | `undefined` | +| `scale` | `scale` | Specifies the size of the component. | `"l" \| "m" \| "s"` | `"m"` | +| `value` | `value` | Provide a value to the component - used to sort when table header is sortable and active. | `""` | `undefined` | + +## Methods + +### `setFocus() => Promise` + +Sets focus on the component's first focusable element. + +#### Returns + +Type: `Promise` + +## Slots + +| Slot | Description | +| ---- | ------------------------------------------------ | +| | A slot for adding content, usually text content. | + +## CSS Custom Properties + +| Name | Description | +| ----------------------------------- | ------------------------------------------------ | +| `--calcite-table-cell-background` | Specifies the background color of the component. | +| `--calcite-table-cell-border-color` | Specifies the border color of the component. | + +## Dependencies + +### Used by + +- [calcite-table-row](../table-row) + +### Graph + +```mermaid +graph TD; + calcite-table-row --> calcite-table-cell + style calcite-table-cell fill:#f9f,stroke:#333,stroke-width:4px +``` + +--- + +_Built with [StencilJS](https://stenciljs.com/)_ diff --git a/packages/calcite-components/src/components/table-cell/resources.ts b/packages/calcite-components/src/components/table-cell/resources.ts new file mode 100644 index 00000000000..14f52645e9b --- /dev/null +++ b/packages/calcite-components/src/components/table-cell/resources.ts @@ -0,0 +1,7 @@ +export const CSS = { + numberCell: "number-cell", + footerCell: "footer-cell", + selectionCell: "selection-cell", + selectedCell: "selected-cell", + assistiveText: "assistive-text", +}; diff --git a/packages/calcite-components/src/components/table-cell/table-cell.scss b/packages/calcite-components/src/components/table-cell/table-cell.scss new file mode 100644 index 00000000000..66f70c60228 --- /dev/null +++ b/packages/calcite-components/src/components/table-cell/table-cell.scss @@ -0,0 +1,77 @@ +/** + * CSS Custom Properties + * + * These properties can be overridden using the component's tag as selector. + * + * @prop --calcite-table-cell-background: Specifies the background color of the component. + * @prop --calcite-table-cell-border-color: Specifies the border color of the component. + */ + +:host { + --calcite-internal-table-cell-background-internal: var(--calcite-table-cell-background, transparent); + --calcite-internal-table-cell-border-color-internal: var(--calcite-table-cell-border-color, transparent); + @apply contents; +} + +:host([alignment="center"]) td { + @apply text-center; +} + +:host([alignment="end"]) td { + @apply text-end; +} + +.assistive-text { + @apply sr-only; +} + +td { + @apply text-start focus-base align-middle text-color-1; + background: var(--calcite-internal-table-cell-background); + border-inline-end: 1px solid var(--calcite-ui-border-3); + font-size: var(--calcite-internal-table-cell-font-size); + &:focus { + @apply focus-inset; + } + padding: var(--calcite-internal-table-cell-padding); +} + +.number-cell { + @apply bg-foreground-2; +} + +.footer-cell { + @apply bg-background font-medium text-color-1; + border-block-start: 1px solid var(--calcite-ui-border-3); +} + +.number-cell, +.selection-cell { + border-inline-end: 1px solid var(--calcite-ui-border-3); + inline-size: 2rem; + min-inline-size: 2rem; +} + +.selection-cell { + @apply cursor-pointer text-color-3; + inset-inline-start: 2rem; +} + +.selected-cell:not(.number-cell):not(.footer-cell) { + --calcite-table-cell-background: var(--calcite-ui-foreground-current); + background: var(--calcite-ui-foreground-current); +} + +.selection-cell.selected-cell { + box-shadow: inset 0.25rem 0 0 0 var(--calcite-ui-brand); + color: var(--calcite-ui-brand); + & calcite-icon { + color: var(--calcite-ui-brand); + } +} +.selection-cell { + @apply align-middle; + & ::slotted(calcite-icon) { + @apply pointer-events-none mt-1; + } +} diff --git a/packages/calcite-components/src/components/table-cell/table-cell.tsx b/packages/calcite-components/src/components/table-cell/table-cell.tsx new file mode 100644 index 00000000000..15d34f01ca7 --- /dev/null +++ b/packages/calcite-components/src/components/table-cell/table-cell.tsx @@ -0,0 +1,238 @@ +import { Component, Element, h, Host, Method, Prop, State, VNode, Watch } from "@stencil/core"; +import { Alignment, Scale } from "../interfaces"; +import { + componentFocusable, + LoadableComponent, + setComponentLoaded, + setUpLoadableComponent, +} from "../../utils/loadable"; +import { + connectMessages, + disconnectMessages, + setUpMessages, + T9nComponent, + updateMessages, +} from "../../utils/t9n"; +import { + connectInteractive, + disconnectInteractive, + InteractiveComponent, + updateHostInteraction, +} from "../../utils/interactive"; + +import { connectLocalized, disconnectLocalized, LocalizedComponent } from "../../utils/locale"; +import { TableCellMessages } from "./assets/table-cell/t9n"; +import { CSS } from "./resources"; +import { RowType } from "../table/interfaces"; + +/** + * @slot - A slot for adding content, usually text content. + */ +@Component({ + tag: "calcite-table-cell", + styleUrl: "table-cell.scss", + shadow: true, + assetsDirs: ["assets"], +}) +export class TableCell + implements InteractiveComponent, LocalizedComponent, LoadableComponent, T9nComponent +{ + //-------------------------------------------------------------------------- + // + // Properties + // + //-------------------------------------------------------------------------- + + /** Specifies the alignment of the component. */ + @Prop({ reflect: true }) alignment: Alignment = "start"; + + /** Specifies the number of columns the component should span. */ + @Prop({ reflect: true }) colSpan: number; + + /** Specifies the number of rows the component should span. */ + @Prop({ reflect: true }) rowSpan: number; + + /** @internal */ + @Prop() disabled: boolean; + + /** @internal */ + @Prop() numberCell: boolean; + + /** @internal */ + @Prop() parentRowIsSelected: boolean; + + @Watch("parentRowIsSelected") + onSelectedChange(): void { + this.updateScreenReaderSelectionText(); + } + + /** @internal */ + @Prop() parentRowPositionLocalized: string; + + /** @internal */ + @Prop() parentRowType: RowType; + + /** @internal */ + @Prop() positionInRow: number; + + /** @internal */ + @Prop() readCellContentsToAT: boolean; + + /** @internal */ + @Prop() scale: Scale = "m"; + + /** @internal */ + @Prop() selectionCell: boolean; + + /** + * Made into a prop for testing purposes only + * + * @internal + */ + // eslint-disable-next-line @stencil-community/strict-mutable -- updated by t9n module + @Prop({ mutable: true }) messages: TableCellMessages; + + /** + * Use this property to override individual strings used by the component. + */ + // eslint-disable-next-line @stencil-community/strict-mutable -- updated by t9n module + @Prop({ mutable: true }) messageOverrides: Partial; + + @Watch("messageOverrides") + onMessagesChange(): void { + /* wired up by t9n util */ + } + + // -------------------------------------------------------------------------- + // + // Private Properties + // + // -------------------------------------------------------------------------- + + @Element() el: HTMLCalciteTableCellElement; + + @State() contentsText = ""; + + @State() defaultMessages: TableCellMessages; + + @State() focused = false; + + @State() selectionText = ""; + + @State() effectiveLocale = ""; + + @Watch("effectiveLocale") + effectiveLocaleChange(): void { + updateMessages(this, this.effectiveLocale); + } + + private containerEl: HTMLTableCellElement; + + // -------------------------------------------------------------------------- + // + // Lifecycle + // + // -------------------------------------------------------------------------- + + async componentWillLoad(): Promise { + setUpLoadableComponent(this); + await setUpMessages(this); + this.updateScreenReaderContentsText(); + this.updateScreenReaderSelectionText(); + } + + componentDidLoad(): void { + setComponentLoaded(this); + } + + connectedCallback(): void { + connectLocalized(this); + connectMessages(this); + connectInteractive(this); + } + + componentDidRender(): void { + updateHostInteraction(this); + } + + disconnectedCallback(): void { + disconnectLocalized(this); + disconnectMessages(this); + disconnectInteractive(this); + } + + //-------------------------------------------------------------------------- + // + // Public Methods + // + // -------------------------------------------------------------------------- + + /** Sets focus on the component. */ + @Method() + async setFocus(): Promise { + await componentFocusable(this); + this.containerEl.focus(); + } + + // -------------------------------------------------------------------------- + // + // Private Methods + // + // -------------------------------------------------------------------------- + + private updateScreenReaderSelectionText(): void { + const selectedText = `${this.messages?.row} ${this.parentRowPositionLocalized} ${this.messages?.selected} ${this.messages?.keyboardDeselect}`; + const unselectedText = `${this.messages?.row} ${this.parentRowPositionLocalized} ${this.messages?.unselected} ${this.messages?.keyboardSelect}`; + this.selectionText = this.parentRowIsSelected ? selectedText : unselectedText; + } + + private updateScreenReaderContentsText = (): void => { + this.contentsText = this.el.textContent; + }; + + private onContainerBlur = (): void => { + this.focused = false; + }; + + private onContainerFocus = (): void => { + this.focused = true; + }; + + //-------------------------------------------------------------------------- + // + // Render Methods + // + //-------------------------------------------------------------------------- + + render(): VNode { + return ( + + (this.containerEl = el)} + > + {(this.selectionCell || this.readCellContentsToAT) && this.focused && ( + + {this.selectionCell && this.selectionText} + {this.readCellContentsToAT && !this.selectionCell && this.contentsText} + + )} + + + + ); + } +} diff --git a/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages.json b/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages.json new file mode 100644 index 00000000000..b73b48a09cf --- /dev/null +++ b/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages.json @@ -0,0 +1,8 @@ +{ + "all": "all", + "keyboardDeselectAll": "Press Enter or Space to deselect all rows", + "keyboardSelectAll": "Press Enter or Space to select all rows", + "rowNumber": "Row number", + "selected": "rows selected", + "selectionColumn": "Selection column" +} diff --git a/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_ar.json b/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_ar.json new file mode 100644 index 00000000000..b73b48a09cf --- /dev/null +++ b/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_ar.json @@ -0,0 +1,8 @@ +{ + "all": "all", + "keyboardDeselectAll": "Press Enter or Space to deselect all rows", + "keyboardSelectAll": "Press Enter or Space to select all rows", + "rowNumber": "Row number", + "selected": "rows selected", + "selectionColumn": "Selection column" +} diff --git a/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_bg.json b/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_bg.json new file mode 100644 index 00000000000..b73b48a09cf --- /dev/null +++ b/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_bg.json @@ -0,0 +1,8 @@ +{ + "all": "all", + "keyboardDeselectAll": "Press Enter or Space to deselect all rows", + "keyboardSelectAll": "Press Enter or Space to select all rows", + "rowNumber": "Row number", + "selected": "rows selected", + "selectionColumn": "Selection column" +} diff --git a/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_bs.json b/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_bs.json new file mode 100644 index 00000000000..b73b48a09cf --- /dev/null +++ b/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_bs.json @@ -0,0 +1,8 @@ +{ + "all": "all", + "keyboardDeselectAll": "Press Enter or Space to deselect all rows", + "keyboardSelectAll": "Press Enter or Space to select all rows", + "rowNumber": "Row number", + "selected": "rows selected", + "selectionColumn": "Selection column" +} diff --git a/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_ca.json b/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_ca.json new file mode 100644 index 00000000000..b73b48a09cf --- /dev/null +++ b/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_ca.json @@ -0,0 +1,8 @@ +{ + "all": "all", + "keyboardDeselectAll": "Press Enter or Space to deselect all rows", + "keyboardSelectAll": "Press Enter or Space to select all rows", + "rowNumber": "Row number", + "selected": "rows selected", + "selectionColumn": "Selection column" +} diff --git a/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_cs.json b/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_cs.json new file mode 100644 index 00000000000..b73b48a09cf --- /dev/null +++ b/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_cs.json @@ -0,0 +1,8 @@ +{ + "all": "all", + "keyboardDeselectAll": "Press Enter or Space to deselect all rows", + "keyboardSelectAll": "Press Enter or Space to select all rows", + "rowNumber": "Row number", + "selected": "rows selected", + "selectionColumn": "Selection column" +} diff --git a/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_da.json b/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_da.json new file mode 100644 index 00000000000..b73b48a09cf --- /dev/null +++ b/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_da.json @@ -0,0 +1,8 @@ +{ + "all": "all", + "keyboardDeselectAll": "Press Enter or Space to deselect all rows", + "keyboardSelectAll": "Press Enter or Space to select all rows", + "rowNumber": "Row number", + "selected": "rows selected", + "selectionColumn": "Selection column" +} diff --git a/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_de.json b/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_de.json new file mode 100644 index 00000000000..b73b48a09cf --- /dev/null +++ b/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_de.json @@ -0,0 +1,8 @@ +{ + "all": "all", + "keyboardDeselectAll": "Press Enter or Space to deselect all rows", + "keyboardSelectAll": "Press Enter or Space to select all rows", + "rowNumber": "Row number", + "selected": "rows selected", + "selectionColumn": "Selection column" +} diff --git a/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_el.json b/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_el.json new file mode 100644 index 00000000000..b73b48a09cf --- /dev/null +++ b/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_el.json @@ -0,0 +1,8 @@ +{ + "all": "all", + "keyboardDeselectAll": "Press Enter or Space to deselect all rows", + "keyboardSelectAll": "Press Enter or Space to select all rows", + "rowNumber": "Row number", + "selected": "rows selected", + "selectionColumn": "Selection column" +} diff --git a/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_en.json b/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_en.json new file mode 100644 index 00000000000..b73b48a09cf --- /dev/null +++ b/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_en.json @@ -0,0 +1,8 @@ +{ + "all": "all", + "keyboardDeselectAll": "Press Enter or Space to deselect all rows", + "keyboardSelectAll": "Press Enter or Space to select all rows", + "rowNumber": "Row number", + "selected": "rows selected", + "selectionColumn": "Selection column" +} diff --git a/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_es.json b/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_es.json new file mode 100644 index 00000000000..b73b48a09cf --- /dev/null +++ b/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_es.json @@ -0,0 +1,8 @@ +{ + "all": "all", + "keyboardDeselectAll": "Press Enter or Space to deselect all rows", + "keyboardSelectAll": "Press Enter or Space to select all rows", + "rowNumber": "Row number", + "selected": "rows selected", + "selectionColumn": "Selection column" +} diff --git a/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_et.json b/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_et.json new file mode 100644 index 00000000000..b73b48a09cf --- /dev/null +++ b/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_et.json @@ -0,0 +1,8 @@ +{ + "all": "all", + "keyboardDeselectAll": "Press Enter or Space to deselect all rows", + "keyboardSelectAll": "Press Enter or Space to select all rows", + "rowNumber": "Row number", + "selected": "rows selected", + "selectionColumn": "Selection column" +} diff --git a/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_fi.json b/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_fi.json new file mode 100644 index 00000000000..b73b48a09cf --- /dev/null +++ b/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_fi.json @@ -0,0 +1,8 @@ +{ + "all": "all", + "keyboardDeselectAll": "Press Enter or Space to deselect all rows", + "keyboardSelectAll": "Press Enter or Space to select all rows", + "rowNumber": "Row number", + "selected": "rows selected", + "selectionColumn": "Selection column" +} diff --git a/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_fr.json b/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_fr.json new file mode 100644 index 00000000000..b73b48a09cf --- /dev/null +++ b/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_fr.json @@ -0,0 +1,8 @@ +{ + "all": "all", + "keyboardDeselectAll": "Press Enter or Space to deselect all rows", + "keyboardSelectAll": "Press Enter or Space to select all rows", + "rowNumber": "Row number", + "selected": "rows selected", + "selectionColumn": "Selection column" +} diff --git a/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_he.json b/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_he.json new file mode 100644 index 00000000000..b73b48a09cf --- /dev/null +++ b/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_he.json @@ -0,0 +1,8 @@ +{ + "all": "all", + "keyboardDeselectAll": "Press Enter or Space to deselect all rows", + "keyboardSelectAll": "Press Enter or Space to select all rows", + "rowNumber": "Row number", + "selected": "rows selected", + "selectionColumn": "Selection column" +} diff --git a/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_hr.json b/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_hr.json new file mode 100644 index 00000000000..b73b48a09cf --- /dev/null +++ b/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_hr.json @@ -0,0 +1,8 @@ +{ + "all": "all", + "keyboardDeselectAll": "Press Enter or Space to deselect all rows", + "keyboardSelectAll": "Press Enter or Space to select all rows", + "rowNumber": "Row number", + "selected": "rows selected", + "selectionColumn": "Selection column" +} diff --git a/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_hu.json b/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_hu.json new file mode 100644 index 00000000000..b73b48a09cf --- /dev/null +++ b/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_hu.json @@ -0,0 +1,8 @@ +{ + "all": "all", + "keyboardDeselectAll": "Press Enter or Space to deselect all rows", + "keyboardSelectAll": "Press Enter or Space to select all rows", + "rowNumber": "Row number", + "selected": "rows selected", + "selectionColumn": "Selection column" +} diff --git a/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_id.json b/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_id.json new file mode 100644 index 00000000000..b73b48a09cf --- /dev/null +++ b/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_id.json @@ -0,0 +1,8 @@ +{ + "all": "all", + "keyboardDeselectAll": "Press Enter or Space to deselect all rows", + "keyboardSelectAll": "Press Enter or Space to select all rows", + "rowNumber": "Row number", + "selected": "rows selected", + "selectionColumn": "Selection column" +} diff --git a/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_it.json b/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_it.json new file mode 100644 index 00000000000..b73b48a09cf --- /dev/null +++ b/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_it.json @@ -0,0 +1,8 @@ +{ + "all": "all", + "keyboardDeselectAll": "Press Enter or Space to deselect all rows", + "keyboardSelectAll": "Press Enter or Space to select all rows", + "rowNumber": "Row number", + "selected": "rows selected", + "selectionColumn": "Selection column" +} diff --git a/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_ja.json b/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_ja.json new file mode 100644 index 00000000000..b73b48a09cf --- /dev/null +++ b/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_ja.json @@ -0,0 +1,8 @@ +{ + "all": "all", + "keyboardDeselectAll": "Press Enter or Space to deselect all rows", + "keyboardSelectAll": "Press Enter or Space to select all rows", + "rowNumber": "Row number", + "selected": "rows selected", + "selectionColumn": "Selection column" +} diff --git a/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_ko.json b/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_ko.json new file mode 100644 index 00000000000..b73b48a09cf --- /dev/null +++ b/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_ko.json @@ -0,0 +1,8 @@ +{ + "all": "all", + "keyboardDeselectAll": "Press Enter or Space to deselect all rows", + "keyboardSelectAll": "Press Enter or Space to select all rows", + "rowNumber": "Row number", + "selected": "rows selected", + "selectionColumn": "Selection column" +} diff --git a/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_lt.json b/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_lt.json new file mode 100644 index 00000000000..b73b48a09cf --- /dev/null +++ b/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_lt.json @@ -0,0 +1,8 @@ +{ + "all": "all", + "keyboardDeselectAll": "Press Enter or Space to deselect all rows", + "keyboardSelectAll": "Press Enter or Space to select all rows", + "rowNumber": "Row number", + "selected": "rows selected", + "selectionColumn": "Selection column" +} diff --git a/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_lv.json b/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_lv.json new file mode 100644 index 00000000000..b73b48a09cf --- /dev/null +++ b/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_lv.json @@ -0,0 +1,8 @@ +{ + "all": "all", + "keyboardDeselectAll": "Press Enter or Space to deselect all rows", + "keyboardSelectAll": "Press Enter or Space to select all rows", + "rowNumber": "Row number", + "selected": "rows selected", + "selectionColumn": "Selection column" +} diff --git a/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_nl.json b/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_nl.json new file mode 100644 index 00000000000..b73b48a09cf --- /dev/null +++ b/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_nl.json @@ -0,0 +1,8 @@ +{ + "all": "all", + "keyboardDeselectAll": "Press Enter or Space to deselect all rows", + "keyboardSelectAll": "Press Enter or Space to select all rows", + "rowNumber": "Row number", + "selected": "rows selected", + "selectionColumn": "Selection column" +} diff --git a/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_no.json b/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_no.json new file mode 100644 index 00000000000..b73b48a09cf --- /dev/null +++ b/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_no.json @@ -0,0 +1,8 @@ +{ + "all": "all", + "keyboardDeselectAll": "Press Enter or Space to deselect all rows", + "keyboardSelectAll": "Press Enter or Space to select all rows", + "rowNumber": "Row number", + "selected": "rows selected", + "selectionColumn": "Selection column" +} diff --git a/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_pl.json b/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_pl.json new file mode 100644 index 00000000000..b73b48a09cf --- /dev/null +++ b/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_pl.json @@ -0,0 +1,8 @@ +{ + "all": "all", + "keyboardDeselectAll": "Press Enter or Space to deselect all rows", + "keyboardSelectAll": "Press Enter or Space to select all rows", + "rowNumber": "Row number", + "selected": "rows selected", + "selectionColumn": "Selection column" +} diff --git a/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_pt-BR.json b/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_pt-BR.json new file mode 100644 index 00000000000..b73b48a09cf --- /dev/null +++ b/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_pt-BR.json @@ -0,0 +1,8 @@ +{ + "all": "all", + "keyboardDeselectAll": "Press Enter or Space to deselect all rows", + "keyboardSelectAll": "Press Enter or Space to select all rows", + "rowNumber": "Row number", + "selected": "rows selected", + "selectionColumn": "Selection column" +} diff --git a/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_pt-PT.json b/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_pt-PT.json new file mode 100644 index 00000000000..b73b48a09cf --- /dev/null +++ b/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_pt-PT.json @@ -0,0 +1,8 @@ +{ + "all": "all", + "keyboardDeselectAll": "Press Enter or Space to deselect all rows", + "keyboardSelectAll": "Press Enter or Space to select all rows", + "rowNumber": "Row number", + "selected": "rows selected", + "selectionColumn": "Selection column" +} diff --git a/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_ro.json b/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_ro.json new file mode 100644 index 00000000000..b73b48a09cf --- /dev/null +++ b/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_ro.json @@ -0,0 +1,8 @@ +{ + "all": "all", + "keyboardDeselectAll": "Press Enter or Space to deselect all rows", + "keyboardSelectAll": "Press Enter or Space to select all rows", + "rowNumber": "Row number", + "selected": "rows selected", + "selectionColumn": "Selection column" +} diff --git a/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_ru.json b/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_ru.json new file mode 100644 index 00000000000..b73b48a09cf --- /dev/null +++ b/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_ru.json @@ -0,0 +1,8 @@ +{ + "all": "all", + "keyboardDeselectAll": "Press Enter or Space to deselect all rows", + "keyboardSelectAll": "Press Enter or Space to select all rows", + "rowNumber": "Row number", + "selected": "rows selected", + "selectionColumn": "Selection column" +} diff --git a/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_sk.json b/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_sk.json new file mode 100644 index 00000000000..b73b48a09cf --- /dev/null +++ b/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_sk.json @@ -0,0 +1,8 @@ +{ + "all": "all", + "keyboardDeselectAll": "Press Enter or Space to deselect all rows", + "keyboardSelectAll": "Press Enter or Space to select all rows", + "rowNumber": "Row number", + "selected": "rows selected", + "selectionColumn": "Selection column" +} diff --git a/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_sl.json b/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_sl.json new file mode 100644 index 00000000000..b73b48a09cf --- /dev/null +++ b/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_sl.json @@ -0,0 +1,8 @@ +{ + "all": "all", + "keyboardDeselectAll": "Press Enter or Space to deselect all rows", + "keyboardSelectAll": "Press Enter or Space to select all rows", + "rowNumber": "Row number", + "selected": "rows selected", + "selectionColumn": "Selection column" +} diff --git a/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_sr.json b/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_sr.json new file mode 100644 index 00000000000..b73b48a09cf --- /dev/null +++ b/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_sr.json @@ -0,0 +1,8 @@ +{ + "all": "all", + "keyboardDeselectAll": "Press Enter or Space to deselect all rows", + "keyboardSelectAll": "Press Enter or Space to select all rows", + "rowNumber": "Row number", + "selected": "rows selected", + "selectionColumn": "Selection column" +} diff --git a/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_sv.json b/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_sv.json new file mode 100644 index 00000000000..b73b48a09cf --- /dev/null +++ b/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_sv.json @@ -0,0 +1,8 @@ +{ + "all": "all", + "keyboardDeselectAll": "Press Enter or Space to deselect all rows", + "keyboardSelectAll": "Press Enter or Space to select all rows", + "rowNumber": "Row number", + "selected": "rows selected", + "selectionColumn": "Selection column" +} diff --git a/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_th.json b/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_th.json new file mode 100644 index 00000000000..b73b48a09cf --- /dev/null +++ b/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_th.json @@ -0,0 +1,8 @@ +{ + "all": "all", + "keyboardDeselectAll": "Press Enter or Space to deselect all rows", + "keyboardSelectAll": "Press Enter or Space to select all rows", + "rowNumber": "Row number", + "selected": "rows selected", + "selectionColumn": "Selection column" +} diff --git a/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_tr.json b/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_tr.json new file mode 100644 index 00000000000..b73b48a09cf --- /dev/null +++ b/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_tr.json @@ -0,0 +1,8 @@ +{ + "all": "all", + "keyboardDeselectAll": "Press Enter or Space to deselect all rows", + "keyboardSelectAll": "Press Enter or Space to select all rows", + "rowNumber": "Row number", + "selected": "rows selected", + "selectionColumn": "Selection column" +} diff --git a/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_uk.json b/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_uk.json new file mode 100644 index 00000000000..b73b48a09cf --- /dev/null +++ b/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_uk.json @@ -0,0 +1,8 @@ +{ + "all": "all", + "keyboardDeselectAll": "Press Enter or Space to deselect all rows", + "keyboardSelectAll": "Press Enter or Space to select all rows", + "rowNumber": "Row number", + "selected": "rows selected", + "selectionColumn": "Selection column" +} diff --git a/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_vi.json b/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_vi.json new file mode 100644 index 00000000000..b73b48a09cf --- /dev/null +++ b/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_vi.json @@ -0,0 +1,8 @@ +{ + "all": "all", + "keyboardDeselectAll": "Press Enter or Space to deselect all rows", + "keyboardSelectAll": "Press Enter or Space to select all rows", + "rowNumber": "Row number", + "selected": "rows selected", + "selectionColumn": "Selection column" +} diff --git a/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_zh-CN.json b/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_zh-CN.json new file mode 100644 index 00000000000..b73b48a09cf --- /dev/null +++ b/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_zh-CN.json @@ -0,0 +1,8 @@ +{ + "all": "all", + "keyboardDeselectAll": "Press Enter or Space to deselect all rows", + "keyboardSelectAll": "Press Enter or Space to select all rows", + "rowNumber": "Row number", + "selected": "rows selected", + "selectionColumn": "Selection column" +} diff --git a/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_zh-HK.json b/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_zh-HK.json new file mode 100644 index 00000000000..b73b48a09cf --- /dev/null +++ b/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_zh-HK.json @@ -0,0 +1,8 @@ +{ + "all": "all", + "keyboardDeselectAll": "Press Enter or Space to deselect all rows", + "keyboardSelectAll": "Press Enter or Space to select all rows", + "rowNumber": "Row number", + "selected": "rows selected", + "selectionColumn": "Selection column" +} diff --git a/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_zh-TW.json b/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_zh-TW.json new file mode 100644 index 00000000000..b73b48a09cf --- /dev/null +++ b/packages/calcite-components/src/components/table-header/assets/table-header/t9n/messages_zh-TW.json @@ -0,0 +1,8 @@ +{ + "all": "all", + "keyboardDeselectAll": "Press Enter or Space to deselect all rows", + "keyboardSelectAll": "Press Enter or Space to select all rows", + "rowNumber": "Row number", + "selected": "rows selected", + "selectionColumn": "Selection column" +} diff --git a/packages/calcite-components/src/components/table-header/readme.md b/packages/calcite-components/src/components/table-header/readme.md new file mode 100644 index 00000000000..308975e0e20 --- /dev/null +++ b/packages/calcite-components/src/components/table-header/readme.md @@ -0,0 +1,63 @@ +# calcite-table-header + + + +## Properties + +| Property | Attribute | Description | Type | Default | +| ------------------ | ------------- | --------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------ | ----------- | +| `alignment` | `alignment` | Specifies the alignment of the component. | `"center" \| "end" \| "start"` | `"start"` | +| `colSpan` | `col-span` | | `number` | `undefined` | +| `description` | `description` | A description to display beneath heading content. | `string` | `undefined` | +| `heading` | `heading` | A heading to display above description content. | `string` | `undefined` | +| `label` | `label` | | `string` | `""` | +| `messageOverrides` | -- | Use this property to override individual strings used by the component. | `{ focusReadout?: string; sortAscending?: string; sortDescending?: string; sortNone?: string; }` | `undefined` | +| `rowSpan` | `row-span` | | `number` | `undefined` | +| `scale` | `scale` | Specifies the size of the component. | `"l" \| "m" \| "s"` | `"m"` | +| `sortable` | `sortable` | Specifies if the component should be able to sort associated `calcite-table-cell` ascending or descending | `boolean` | `false` | + +## Methods + +### `setFocus() => Promise` + +Sets focus on the component's first focusable element. + +#### Returns + +Type: `Promise` + +## Slots + +| Slot | Description | +| --------------- | ------------------------------------------------ | +| `"actions-end"` | A slot for adding content, usually text content. | + +## CSS Custom Properties + +| Name | Description | +| ------------------------------------- | ------------------------------------------------ | +| `--calcite-table-header-background` | Specifies the background color of the component. | +| `--calcite-table-header-border-color` | Specifies the border color of the component. | + +## Dependencies + +### Used by + +- [calcite-table-row](../table-row) + +### Depends on + +- [calcite-icon](../icon) + +### Graph + +```mermaid +graph TD; + calcite-table-header --> calcite-icon + calcite-table-row --> calcite-table-header + style calcite-table-header fill:#f9f,stroke:#333,stroke-width:4px +``` + +--- + +_Built with [StencilJS](https://stenciljs.com/)_ diff --git a/packages/calcite-components/src/components/table-header/resources.ts b/packages/calcite-components/src/components/table-header/resources.ts new file mode 100644 index 00000000000..23a28bf059d --- /dev/null +++ b/packages/calcite-components/src/components/table-header/resources.ts @@ -0,0 +1,11 @@ +export const CSS = { + numberCell: "number-cell", + selectionCell: "selection-cell", + bodyRow: "body-row", + footerRow: "footer-row", + heading: "heading", + description: "description", + multipleSelectionCell: "cell--multiple-selection", + assistiveText: "assistive-text", + active: "active", +}; diff --git a/packages/calcite-components/src/components/table-header/table-header.scss b/packages/calcite-components/src/components/table-header/table-header.scss new file mode 100644 index 00000000000..bd167b5d4ea --- /dev/null +++ b/packages/calcite-components/src/components/table-header/table-header.scss @@ -0,0 +1,77 @@ +/** + * CSS Custom Properties + * + * These properties can be overridden using the component's tag as selector. + * + * @prop --calcite-table-header-background: Specifies the background color of the component. + * @prop --calcite-table-header-border-color: Specifies the border color of the component. + */ + +:host { + --calcite-internal-table-header-background: var(--calcite-table-header-background, var(--calcite-ui-foreground-2)); + --calcite-internal-table-header-border-color: var(--calcite-table-border-color, var(--calcite-ui-border-3)); + @apply contents; +} + +:host([alignment="center"]) th { + @apply text-center; +} + +:host([alignment="end"]) th { + @apply text-end; +} + +.assistive-text { + @apply sr-only; +} + +th { + @apply text-color-1 focus-base text-start font-medium align-top; + font-size: var(--calcite-internal-table-cell-font-size); + border-inline-end: 1px solid var(--calcite-internal-table-header-border-color); + border-block-end: 1px solid var(--calcite-internal-table-header-border-color); + padding-block: calc(var(--calcite-internal-table-cell-padding) * 1.5); + padding-inline: var(--calcite-internal-table-cell-padding); + background-color: var(--calcite-internal-table-header-background); + &:focus-within { + @apply focus-inset; + } +} + +th.body-row, +th.footer-row { + @apply align-middle; + border-block-end: 0; +} + +th.footer-row { + border-block-start: 1px solid var(--calcite-internal-table-header-border-color); +} + +.cell--multiple-selection { + @apply cursor-pointer align-middle text-color-3; +} + +.number-cell, +.selection-cell { + @apply text-color-2; + inline-size: 2rem; + min-inline-size: 2rem; +} + +.selection-cell calcite-icon.active { + color: var(--calcite-ui-brand); +} +.number-cell calcite-icon, +.selection-cell calcite-icon { + @apply ms-auto me-auto align-middle; +} + +.heading { + @apply text-color-1; +} + +.description { + @apply text-color-3; + font-size: var(--calcite-internal-table-cell-font-size-secondary); +} diff --git a/packages/calcite-components/src/components/table-header/table-header.tsx b/packages/calcite-components/src/components/table-header/table-header.tsx new file mode 100644 index 00000000000..f28eede7402 --- /dev/null +++ b/packages/calcite-components/src/components/table-header/table-header.tsx @@ -0,0 +1,239 @@ +import { Component, Element, h, Host, Method, Prop, State, VNode, Watch } from "@stencil/core"; +import { + componentFocusable, + LoadableComponent, + setComponentLoaded, + setUpLoadableComponent, +} from "../../utils/loadable"; +import { + connectMessages, + disconnectMessages, + setUpMessages, + T9nComponent, + updateMessages, +} from "../../utils/t9n"; +import { connectLocalized, disconnectLocalized, LocalizedComponent } from "../../utils/locale"; +import { Alignment, Scale, SelectionMode } from "../interfaces"; +import { TableHeaderMessages } from "./assets/table-header/t9n"; +import { CSS } from "./resources"; +import { RowType } from "../table/interfaces"; + +@Component({ + tag: "calcite-table-header", + styleUrl: "table-header.scss", + shadow: true, + assetsDirs: ["assets"], +}) +export class TableHeader implements LocalizedComponent, LoadableComponent, T9nComponent { + //-------------------------------------------------------------------------- + // + // Properties + // + //-------------------------------------------------------------------------- + + /** Specifies the alignment of the component. */ + @Prop({ reflect: true }) alignment: Alignment = "start"; + + /** Specifies the number of columns the component should span. */ + @Prop({ reflect: true }) colSpan: number; + + /** A description to display beneath heading content. */ + @Prop({ reflect: true }) description: string; + + /** A heading to display above description content. */ + @Prop({ reflect: true }) heading: string; + + /** Specifies the number of rows the component should span. */ + @Prop({ reflect: true }) rowSpan: number; + + /** @internal */ + @Prop() numberCell = false; + + /** @internal */ + @Prop() parentRowPosition: number; + + /** @internal */ + @Prop() parentRowType: RowType; + + /** @internal */ + @Prop() positionInRow: number; + + /** @internal */ + @Prop() scale: Scale; + + /** @internal */ + @Prop() selectedRowCount: number; + + /** @internal */ + @Prop() selectedRowCountLocalized: string; + + @Watch("selectedRowCount") + @Watch("selectedRowCountLocalized") + onSelectedChange(): void { + this.updateScreenReaderText(); + } + + /** @internal */ + @Prop() selectionCell = false; + + /** @internal */ + @Prop() selectionMode: SelectionMode; + + /** @internal */ + @Prop() bodyRowCount: number; + + /** + * Made into a prop for testing purposes only + * + * @internal + */ + // eslint-disable-next-line @stencil-community/strict-mutable -- updated by t9n module + @Prop({ mutable: true }) messages: TableHeaderMessages; + + /** + * Use this property to override individual strings used by the component. + */ + // eslint-disable-next-line @stencil-community/strict-mutable -- updated by t9n module + @Prop({ mutable: true }) messageOverrides: Partial; + + @Watch("messageOverrides") + onMessagesChange(): void { + /* wired up by t9n util */ + } + + // -------------------------------------------------------------------------- + // + // Lifecycle + // + // -------------------------------------------------------------------------- + + async componentWillLoad(): Promise { + setUpLoadableComponent(this); + await setUpMessages(this); + this.updateScreenReaderText(); + } + + componentDidLoad(): void { + setComponentLoaded(this); + } + + connectedCallback(): void { + connectLocalized(this); + connectMessages(this); + } + + disconnectedCallback(): void { + disconnectLocalized(this); + disconnectMessages(this); + } + + // -------------------------------------------------------------------------- + // + // Private Properties + // + // -------------------------------------------------------------------------- + @Element() el: HTMLCalciteTableHeaderElement; + + @State() defaultMessages: TableHeaderMessages; + + @State() screenReaderText = ""; + + @State() effectiveLocale = ""; + + @Watch("effectiveLocale") + effectiveLocaleChange(): void { + updateMessages(this, this.effectiveLocale); + } + + private containerEl: HTMLTableCellElement; + + // -------------------------------------------------------------------------- + // + // Public Methods + // + // -------------------------------------------------------------------------- + + /** Sets focus on the component. */ + @Method() + async setFocus(): Promise { + await componentFocusable(this); + this.containerEl.focus(); + } + + // -------------------------------------------------------------------------- + // + // Private Methods + // + // -------------------------------------------------------------------------- + + private updateScreenReaderText(): void { + let text = ""; + const sharedText = `${this.selectedRowCountLocalized} ${this.messages?.selected}`; + if (this.numberCell) { + text = this.messages?.rowNumber; + } else if (this.selectionMode === "single") { + text = `${this.messages?.selectionColumn}. ${sharedText}`; + } else if (this.bodyRowCount === this.selectedRowCount) { + text = `${this.messages?.selectionColumn}. ${this.messages?.all} ${sharedText} ${this.messages?.keyboardDeselectAll}`; + } else { + text = `${this.messages?.selectionColumn}. ${sharedText} ${this.messages?.keyboardSelectAll}`; + } + this.screenReaderText = text; + } + + //-------------------------------------------------------------------------- + // + // Render Methods + // + //-------------------------------------------------------------------------- + + render(): VNode { + const scope = this.rowSpan + ? "rowgroup" + : this.colSpan + ? "colgroup" + : this.parentRowType === "body" + ? "row" + : "col"; + + const allSelected = this.selectedRowCount === this.bodyRowCount; + const selectionIcon = allSelected ? "check-square-f" : "check-square"; + + return ( + + (this.containerEl = el)} + > + {this.heading &&
{this.heading}
} + {this.description &&
{this.description}
} + {this.selectionCell && this.selectionMode === "multiple" && ( + + )} + {(this.selectionCell || this.numberCell) && ( + + {this.screenReaderText} + + )} + +
+ ); + } +} diff --git a/packages/calcite-components/src/components/table-row/readme.md b/packages/calcite-components/src/components/table-row/readme.md new file mode 100644 index 00000000000..48216d72890 --- /dev/null +++ b/packages/calcite-components/src/components/table-row/readme.md @@ -0,0 +1,53 @@ +# calcite-table-row + + + +## Properties + +| Property | Attribute | Description | Type | Default | +| ---------- | ---------- | ---------------------------------------------------------------------------------------- | ------------------- | ------- | +| `disabled` | `disabled` | When `true`, interaction is prevented and the component is displayed with lower opacity. | `boolean` | `false` | +| `scale` | `scale` | Specifies the size of the component. | `"l" \| "m" \| "s"` | `"m"` | +| `selected` | `selected` | Is the component selected. | `boolean` | `false` | + +## Events + +| Event | Description | Type | +| ----------------------- | ------------------------------------------------------- | ------------------- | +| `calciteTableRowSelect` | Fires when the selected state of the component changes. | `CustomEvent` | + +## Slots + +| Slot | Description | +| ---- | -------------------------------------------------------------------------- | +| | A slot for adding `calcite-table-cell` or `calcite-table-header` elements. | + +## CSS Custom Properties + +| Name | Description | +| ---------------------------------- | ------------------------------------------------ | +| `--calcite-table-row-background` | Specifies the background color of the component. | +| `--calcite-table-row-border-color` | Specifies the border color of the component. | + +## Dependencies + +### Depends on + +- [calcite-icon](../icon) +- [calcite-table-header](../table-header) +- [calcite-table-cell](../table-cell) + +### Graph + +```mermaid +graph TD; + calcite-table-row --> calcite-icon + calcite-table-row --> calcite-table-header + calcite-table-row --> calcite-table-cell + calcite-table-header --> calcite-icon + style calcite-table-row fill:#f9f,stroke:#333,stroke-width:4px +``` + +--- + +_Built with [StencilJS](https://stenciljs.com/)_ diff --git a/packages/calcite-components/src/components/table-row/table-row.scss b/packages/calcite-components/src/components/table-row/table-row.scss new file mode 100644 index 00000000000..4b2454beb89 --- /dev/null +++ b/packages/calcite-components/src/components/table-row/table-row.scss @@ -0,0 +1,27 @@ +/** + * CSS Custom Properties + * + * These properties can be overridden using the component's tag as selector. + * + * @prop --calcite-table-row-background: Specifies the background color of the component. + * @prop --calcite-table-row-border-color: Specifies the border color of the component. + */ + +:host { + --calcite-internal-table-row-background: var(--calcite-table-row-background, var(--calcite-ui-foreground-1)); + --calcite-internal-table-row-border-color: var(--calcite-table-row-border-color, transparent); + @apply contents; +} + +@include base-component(); + +@include disabled() { + tr { + @apply opacity-disabled pointer-events-none; + } +} + +tr { + border-block-end: 1px solid var(--calcite-internal-table-row-border-color); + background-color: var(--calcite-internal-table-row-background); +} diff --git a/packages/calcite-components/src/components/table-row/table-row.tsx b/packages/calcite-components/src/components/table-row/table-row.tsx new file mode 100644 index 00000000000..79be55a2f7b --- /dev/null +++ b/packages/calcite-components/src/components/table-row/table-row.tsx @@ -0,0 +1,393 @@ +import { + Component, + Element, + Event, + EventEmitter, + h, + Host, + Listen, + Prop, + State, + VNode, + Watch, +} from "@stencil/core"; +import { LocalizedComponent } from "../../utils/locale"; +import { Scale, SelectionMode } from "../interfaces"; +import { focusElementInGroup, FocusElementInGroupDestination } from "../../utils/dom"; +import { RowType, TableRowFocusEvent } from "../table/interfaces"; +import { isActivationKey } from "../../utils/key"; +import { + connectInteractive, + disconnectInteractive, + InteractiveComponent, + updateHostInteraction, +} from "../../utils/interactive"; + +/** + * @slot - A slot for adding `calcite-table-cell` or `calcite-table-header` elements. + */ + +@Component({ + tag: "calcite-table-row", + styleUrl: "table-row.scss", + shadow: true, +}) +export class TableRow implements InteractiveComponent, LocalizedComponent { + //-------------------------------------------------------------------------- + // + // Properties + // + //-------------------------------------------------------------------------- + + /** When `true`, interaction is prevented and the component is displayed with lower opacity. */ + @Prop({ reflect: true }) disabled = false; + + /** When `true`, the component is selected. */ + @Prop({ reflect: true }) selected = false; + + /** @internal */ + @Prop({ mutable: true }) cellCount: number; + + /** @internal */ + @Prop() rowType: RowType; + + /** @internal */ + @Prop() numbered = false; + + /** @internal */ + @Prop() positionSection: number; + + /** @internal */ + @Prop() positionSectionLocalized: string; + + /** @internal */ + @Prop() positionAll: number; + + /** @internal */ + @Prop() readCellContentsToAT: boolean; + + /** @internal */ + @Prop() scale: Scale; + + /** @internal */ + @Prop() selectionMode: Extract<"multiple" | "single" | "none", SelectionMode> = "none"; + + /** @internal */ + @Prop() selectedRowCount: number; + + /** @internal */ + @Prop() selectedRowCountLocalized: string; + + /** @internal */ + @Prop() bodyRowCount: number; + + @Watch("bodyRowCount") + @Watch("scale") + @Watch("selected") + @Watch("selectedRowCount") + handleCellChanges(): void { + if (this.tableRowEl && this.rowCells.length > 0) { + this.updateCells(); + } + } + + @Watch("numbered") + @Watch("selectionMode") + handleDelayedCellChanges(): void { + if (this.tableRowEl && this.rowCells.length > 0) { + requestAnimationFrame(() => this.updateCells()); + } + } + + //-------------------------------------------------------------------------- + // + // Lifecycle + // + //-------------------------------------------------------------------------- + + componentDidLoad(): void { + if (this.tableRowEl && this.rowCells.length > 0) { + this.updateCells(); + } + } + + connectedCallback(): void { + connectInteractive(this); + } + + componentDidRender(): void { + updateHostInteraction(this); + } + + disconnectedCallback(): void { + disconnectInteractive(this); + } + + //-------------------------------------------------------------------------- + // + // Private Properties + // + //-------------------------------------------------------------------------- + + @Element() el: HTMLCalciteTableRowElement; + + private rowCells: (HTMLCalciteTableCellElement | HTMLCalciteTableHeaderElement)[] = []; + + private tableRowEl: HTMLTableRowElement; + + private tableRowSlotEl: HTMLSlotElement; + + @State() effectiveLocale = ""; + + // -------------------------------------------------------------------------- + // + // Events + // + // -------------------------------------------------------------------------- + + /** + * Fires when the selected state of the component changes. + */ + @Event({ cancelable: false }) calciteTableRowSelect: EventEmitter; + + /** @internal */ + @Event({ cancelable: false }) + calciteInternalTableRowFocusRequest: EventEmitter; + + //-------------------------------------------------------------------------- + // + // Event Listeners + // + //-------------------------------------------------------------------------- + + @Listen("calciteInternalTableRowFocusChange", { target: "document" }) + calciteInternalTableRowFocusChangeHandler(event: CustomEvent): void { + if ((event.target as Element).contains(this.el)) { + const position = event.detail.cellPosition; + const rowPosition = event.detail.rowPosition; + const destination = event.detail.destination; + const lastCell = event.detail.lastCell; + + if (rowPosition === this.positionAll) { + if (this.disabled) { + const deflectDirection = + destination === "last" ? "previous" : destination === "first" ? "next" : destination; + this.emitTableRowFocusRequest(position, this.positionAll, deflectDirection); + return; + } + const cellPosition = lastCell + ? this.rowCells[this.rowCells.length - 1] + : this.rowCells?.find((_, index) => index + 1 === position); + + if (cellPosition) { + cellPosition.setFocus(); + } + } + } + } + + //-------------------------------------------------------------------------- + // + // Private Methods + // + //-------------------------------------------------------------------------- + + private keyDownHandler(event: KeyboardEvent): void { + const el = event.target as HTMLCalciteTableCellElement | HTMLCalciteTableHeaderElement; + const key = event.key; + const isControl = event.ctrlKey; + const cells = this.rowCells; + if (el.matches("calcite-table-cell") || el.matches("calcite-table-header")) { + switch (key) { + case "ArrowUp": + this.emitTableRowFocusRequest(el.positionInRow, this.positionAll, "previous"); + event.preventDefault(); + break; + case "ArrowDown": + this.emitTableRowFocusRequest(el.positionInRow, this.positionAll, "next"); + event.preventDefault(); + break; + case "PageUp": + this.emitTableRowFocusRequest(el.positionInRow, this.positionAll, "first"); + event.preventDefault(); + break; + case "PageDown": + this.emitTableRowFocusRequest(el.positionInRow, this.positionAll, "last"); + event.preventDefault(); + break; + case "ArrowLeft": + focusElementInGroup(cells, el, "previous", false); + event.preventDefault(); + break; + case "ArrowRight": + focusElementInGroup(cells, el, "next", false); + event.preventDefault(); + break; + case "Home": + if (isControl) { + this.emitTableRowFocusRequest(1, this.positionAll, "first"); + event.preventDefault(); + } else { + focusElementInGroup(cells, el, "first", false); + event.preventDefault(); + } + break; + case "End": + if (isControl) { + this.emitTableRowFocusRequest(this.rowCells?.length, this.positionAll, "last", true); + event.preventDefault(); + } else { + focusElementInGroup(cells, el, "last", false); + event.preventDefault(); + } + break; + } + } + } + + private emitTableRowFocusRequest = ( + cellPosition: number, + rowPosition: number, + destination: FocusElementInGroupDestination, + lastCell?: boolean + ): void => { + this.calciteInternalTableRowFocusRequest.emit({ + cellPosition, + rowPosition, + destination, + lastCell, + }); + }; + + private updateCells = (): void => { + const slottedCells = this.tableRowSlotEl + ?.assignedElements({ flatten: true }) + ?.filter( + (el: HTMLCalciteTableCellElement | HTMLCalciteTableHeaderElement) => + el.matches("calcite-table-cell") || el.matches("calcite-table-header") + ); + + const renderedCells = Array.from( + this.tableRowEl?.querySelectorAll("calcite-table-header, calcite-table-cell") + )?.filter( + (el: HTMLCalciteTableCellElement | HTMLCalciteTableHeaderElement) => + el.numberCell || el.selectionCell + ); + + const cells = renderedCells ? renderedCells.concat(slottedCells) : slottedCells; + + if (cells.length > 0) { + cells?.forEach((cell: HTMLCalciteTableCellElement | HTMLCalciteTableHeaderElement, index) => { + cell.positionInRow = index + 1; + cell.parentRowType = this.rowType; + cell.scale = this.scale; + + if (cell.nodeName === "CALCITE-TABLE-CELL") { + (cell as HTMLCalciteTableCellElement).readCellContentsToAT = this.readCellContentsToAT; + (cell as HTMLCalciteTableCellElement).disabled = this.disabled; + (cell as HTMLCalciteTableCellElement).parentRowIsSelected = this.selected; + } + }); + } + + this.rowCells = + (cells as (HTMLCalciteTableCellElement | HTMLCalciteTableHeaderElement)[]) || []; + this.cellCount = cells?.length; + }; + + private handleSelectionOfRow = (): void => { + this.calciteTableRowSelect.emit(); + }; + + private handleKeyboardSelection = (event: KeyboardEvent): void => { + if (isActivationKey(event.key)) { + if (event.key === " ") { + event.preventDefault(); + } + this.handleSelectionOfRow(); + } + }; + + //-------------------------------------------------------------------------- + // + // Render Methods + // + //-------------------------------------------------------------------------- + + renderSelectionIcon(): VNode { + const icon = + this.selectionMode === "multiple" && this.selected + ? "check-square-f" + : this.selectionMode === "multiple" + ? "square" + : this.selected + ? "circle-f" + : "circle"; + + return ; + } + + renderSelectableCell(): VNode { + return this.rowType === "head" ? ( + + ) : this.rowType === "body" ? ( + + {this.renderSelectionIcon()} + + ) : ( + + ); + } + + renderNumberedCell(): VNode { + return this.rowType === "head" ? ( + + ) : this.rowType === "body" ? ( + + {this.positionSectionLocalized} + + ) : ( + + ); + } + + render(): VNode { + return ( + + this.keyDownHandler(event)} + // eslint-disable-next-line react/jsx-sort-props -- ref should be last so node attrs/props are in sync (see https://github.com/Esri/calcite-design-system/pull/6530) + ref={(el) => (this.tableRowEl = el)} + > + {this.numbered && this.renderNumberedCell()} + {this.selectionMode !== "none" && this.renderSelectableCell()} + (this.tableRowSlotEl = el as HTMLSlotElement)} + /> + + + ); + } +} diff --git a/packages/calcite-components/src/components/table/assets/table/t9n/messages.json b/packages/calcite-components/src/components/table/assets/table/t9n/messages.json new file mode 100644 index 00000000000..76931e75ab2 --- /dev/null +++ b/packages/calcite-components/src/components/table/assets/table/t9n/messages.json @@ -0,0 +1,7 @@ +{ + "clear": "Clear", + "hiddenSelected": "Rows selected but out of view", + "page": "Page", + "row": "Row", + "selected": "Selected" +} diff --git a/packages/calcite-components/src/components/table/assets/table/t9n/messages_ar.json b/packages/calcite-components/src/components/table/assets/table/t9n/messages_ar.json new file mode 100644 index 00000000000..76931e75ab2 --- /dev/null +++ b/packages/calcite-components/src/components/table/assets/table/t9n/messages_ar.json @@ -0,0 +1,7 @@ +{ + "clear": "Clear", + "hiddenSelected": "Rows selected but out of view", + "page": "Page", + "row": "Row", + "selected": "Selected" +} diff --git a/packages/calcite-components/src/components/table/assets/table/t9n/messages_bg.json b/packages/calcite-components/src/components/table/assets/table/t9n/messages_bg.json new file mode 100644 index 00000000000..76931e75ab2 --- /dev/null +++ b/packages/calcite-components/src/components/table/assets/table/t9n/messages_bg.json @@ -0,0 +1,7 @@ +{ + "clear": "Clear", + "hiddenSelected": "Rows selected but out of view", + "page": "Page", + "row": "Row", + "selected": "Selected" +} diff --git a/packages/calcite-components/src/components/table/assets/table/t9n/messages_bs.json b/packages/calcite-components/src/components/table/assets/table/t9n/messages_bs.json new file mode 100644 index 00000000000..76931e75ab2 --- /dev/null +++ b/packages/calcite-components/src/components/table/assets/table/t9n/messages_bs.json @@ -0,0 +1,7 @@ +{ + "clear": "Clear", + "hiddenSelected": "Rows selected but out of view", + "page": "Page", + "row": "Row", + "selected": "Selected" +} diff --git a/packages/calcite-components/src/components/table/assets/table/t9n/messages_ca.json b/packages/calcite-components/src/components/table/assets/table/t9n/messages_ca.json new file mode 100644 index 00000000000..76931e75ab2 --- /dev/null +++ b/packages/calcite-components/src/components/table/assets/table/t9n/messages_ca.json @@ -0,0 +1,7 @@ +{ + "clear": "Clear", + "hiddenSelected": "Rows selected but out of view", + "page": "Page", + "row": "Row", + "selected": "Selected" +} diff --git a/packages/calcite-components/src/components/table/assets/table/t9n/messages_cs.json b/packages/calcite-components/src/components/table/assets/table/t9n/messages_cs.json new file mode 100644 index 00000000000..76931e75ab2 --- /dev/null +++ b/packages/calcite-components/src/components/table/assets/table/t9n/messages_cs.json @@ -0,0 +1,7 @@ +{ + "clear": "Clear", + "hiddenSelected": "Rows selected but out of view", + "page": "Page", + "row": "Row", + "selected": "Selected" +} diff --git a/packages/calcite-components/src/components/table/assets/table/t9n/messages_da.json b/packages/calcite-components/src/components/table/assets/table/t9n/messages_da.json new file mode 100644 index 00000000000..76931e75ab2 --- /dev/null +++ b/packages/calcite-components/src/components/table/assets/table/t9n/messages_da.json @@ -0,0 +1,7 @@ +{ + "clear": "Clear", + "hiddenSelected": "Rows selected but out of view", + "page": "Page", + "row": "Row", + "selected": "Selected" +} diff --git a/packages/calcite-components/src/components/table/assets/table/t9n/messages_de.json b/packages/calcite-components/src/components/table/assets/table/t9n/messages_de.json new file mode 100644 index 00000000000..76931e75ab2 --- /dev/null +++ b/packages/calcite-components/src/components/table/assets/table/t9n/messages_de.json @@ -0,0 +1,7 @@ +{ + "clear": "Clear", + "hiddenSelected": "Rows selected but out of view", + "page": "Page", + "row": "Row", + "selected": "Selected" +} diff --git a/packages/calcite-components/src/components/table/assets/table/t9n/messages_el.json b/packages/calcite-components/src/components/table/assets/table/t9n/messages_el.json new file mode 100644 index 00000000000..76931e75ab2 --- /dev/null +++ b/packages/calcite-components/src/components/table/assets/table/t9n/messages_el.json @@ -0,0 +1,7 @@ +{ + "clear": "Clear", + "hiddenSelected": "Rows selected but out of view", + "page": "Page", + "row": "Row", + "selected": "Selected" +} diff --git a/packages/calcite-components/src/components/table/assets/table/t9n/messages_en.json b/packages/calcite-components/src/components/table/assets/table/t9n/messages_en.json new file mode 100644 index 00000000000..76931e75ab2 --- /dev/null +++ b/packages/calcite-components/src/components/table/assets/table/t9n/messages_en.json @@ -0,0 +1,7 @@ +{ + "clear": "Clear", + "hiddenSelected": "Rows selected but out of view", + "page": "Page", + "row": "Row", + "selected": "Selected" +} diff --git a/packages/calcite-components/src/components/table/assets/table/t9n/messages_es.json b/packages/calcite-components/src/components/table/assets/table/t9n/messages_es.json new file mode 100644 index 00000000000..76931e75ab2 --- /dev/null +++ b/packages/calcite-components/src/components/table/assets/table/t9n/messages_es.json @@ -0,0 +1,7 @@ +{ + "clear": "Clear", + "hiddenSelected": "Rows selected but out of view", + "page": "Page", + "row": "Row", + "selected": "Selected" +} diff --git a/packages/calcite-components/src/components/table/assets/table/t9n/messages_et.json b/packages/calcite-components/src/components/table/assets/table/t9n/messages_et.json new file mode 100644 index 00000000000..76931e75ab2 --- /dev/null +++ b/packages/calcite-components/src/components/table/assets/table/t9n/messages_et.json @@ -0,0 +1,7 @@ +{ + "clear": "Clear", + "hiddenSelected": "Rows selected but out of view", + "page": "Page", + "row": "Row", + "selected": "Selected" +} diff --git a/packages/calcite-components/src/components/table/assets/table/t9n/messages_fi.json b/packages/calcite-components/src/components/table/assets/table/t9n/messages_fi.json new file mode 100644 index 00000000000..76931e75ab2 --- /dev/null +++ b/packages/calcite-components/src/components/table/assets/table/t9n/messages_fi.json @@ -0,0 +1,7 @@ +{ + "clear": "Clear", + "hiddenSelected": "Rows selected but out of view", + "page": "Page", + "row": "Row", + "selected": "Selected" +} diff --git a/packages/calcite-components/src/components/table/assets/table/t9n/messages_fr.json b/packages/calcite-components/src/components/table/assets/table/t9n/messages_fr.json new file mode 100644 index 00000000000..76931e75ab2 --- /dev/null +++ b/packages/calcite-components/src/components/table/assets/table/t9n/messages_fr.json @@ -0,0 +1,7 @@ +{ + "clear": "Clear", + "hiddenSelected": "Rows selected but out of view", + "page": "Page", + "row": "Row", + "selected": "Selected" +} diff --git a/packages/calcite-components/src/components/table/assets/table/t9n/messages_he.json b/packages/calcite-components/src/components/table/assets/table/t9n/messages_he.json new file mode 100644 index 00000000000..76931e75ab2 --- /dev/null +++ b/packages/calcite-components/src/components/table/assets/table/t9n/messages_he.json @@ -0,0 +1,7 @@ +{ + "clear": "Clear", + "hiddenSelected": "Rows selected but out of view", + "page": "Page", + "row": "Row", + "selected": "Selected" +} diff --git a/packages/calcite-components/src/components/table/assets/table/t9n/messages_hr.json b/packages/calcite-components/src/components/table/assets/table/t9n/messages_hr.json new file mode 100644 index 00000000000..76931e75ab2 --- /dev/null +++ b/packages/calcite-components/src/components/table/assets/table/t9n/messages_hr.json @@ -0,0 +1,7 @@ +{ + "clear": "Clear", + "hiddenSelected": "Rows selected but out of view", + "page": "Page", + "row": "Row", + "selected": "Selected" +} diff --git a/packages/calcite-components/src/components/table/assets/table/t9n/messages_hu.json b/packages/calcite-components/src/components/table/assets/table/t9n/messages_hu.json new file mode 100644 index 00000000000..76931e75ab2 --- /dev/null +++ b/packages/calcite-components/src/components/table/assets/table/t9n/messages_hu.json @@ -0,0 +1,7 @@ +{ + "clear": "Clear", + "hiddenSelected": "Rows selected but out of view", + "page": "Page", + "row": "Row", + "selected": "Selected" +} diff --git a/packages/calcite-components/src/components/table/assets/table/t9n/messages_id.json b/packages/calcite-components/src/components/table/assets/table/t9n/messages_id.json new file mode 100644 index 00000000000..76931e75ab2 --- /dev/null +++ b/packages/calcite-components/src/components/table/assets/table/t9n/messages_id.json @@ -0,0 +1,7 @@ +{ + "clear": "Clear", + "hiddenSelected": "Rows selected but out of view", + "page": "Page", + "row": "Row", + "selected": "Selected" +} diff --git a/packages/calcite-components/src/components/table/assets/table/t9n/messages_it.json b/packages/calcite-components/src/components/table/assets/table/t9n/messages_it.json new file mode 100644 index 00000000000..76931e75ab2 --- /dev/null +++ b/packages/calcite-components/src/components/table/assets/table/t9n/messages_it.json @@ -0,0 +1,7 @@ +{ + "clear": "Clear", + "hiddenSelected": "Rows selected but out of view", + "page": "Page", + "row": "Row", + "selected": "Selected" +} diff --git a/packages/calcite-components/src/components/table/assets/table/t9n/messages_ja.json b/packages/calcite-components/src/components/table/assets/table/t9n/messages_ja.json new file mode 100644 index 00000000000..76931e75ab2 --- /dev/null +++ b/packages/calcite-components/src/components/table/assets/table/t9n/messages_ja.json @@ -0,0 +1,7 @@ +{ + "clear": "Clear", + "hiddenSelected": "Rows selected but out of view", + "page": "Page", + "row": "Row", + "selected": "Selected" +} diff --git a/packages/calcite-components/src/components/table/assets/table/t9n/messages_ko.json b/packages/calcite-components/src/components/table/assets/table/t9n/messages_ko.json new file mode 100644 index 00000000000..76931e75ab2 --- /dev/null +++ b/packages/calcite-components/src/components/table/assets/table/t9n/messages_ko.json @@ -0,0 +1,7 @@ +{ + "clear": "Clear", + "hiddenSelected": "Rows selected but out of view", + "page": "Page", + "row": "Row", + "selected": "Selected" +} diff --git a/packages/calcite-components/src/components/table/assets/table/t9n/messages_lt.json b/packages/calcite-components/src/components/table/assets/table/t9n/messages_lt.json new file mode 100644 index 00000000000..76931e75ab2 --- /dev/null +++ b/packages/calcite-components/src/components/table/assets/table/t9n/messages_lt.json @@ -0,0 +1,7 @@ +{ + "clear": "Clear", + "hiddenSelected": "Rows selected but out of view", + "page": "Page", + "row": "Row", + "selected": "Selected" +} diff --git a/packages/calcite-components/src/components/table/assets/table/t9n/messages_lv.json b/packages/calcite-components/src/components/table/assets/table/t9n/messages_lv.json new file mode 100644 index 00000000000..76931e75ab2 --- /dev/null +++ b/packages/calcite-components/src/components/table/assets/table/t9n/messages_lv.json @@ -0,0 +1,7 @@ +{ + "clear": "Clear", + "hiddenSelected": "Rows selected but out of view", + "page": "Page", + "row": "Row", + "selected": "Selected" +} diff --git a/packages/calcite-components/src/components/table/assets/table/t9n/messages_nl.json b/packages/calcite-components/src/components/table/assets/table/t9n/messages_nl.json new file mode 100644 index 00000000000..76931e75ab2 --- /dev/null +++ b/packages/calcite-components/src/components/table/assets/table/t9n/messages_nl.json @@ -0,0 +1,7 @@ +{ + "clear": "Clear", + "hiddenSelected": "Rows selected but out of view", + "page": "Page", + "row": "Row", + "selected": "Selected" +} diff --git a/packages/calcite-components/src/components/table/assets/table/t9n/messages_no.json b/packages/calcite-components/src/components/table/assets/table/t9n/messages_no.json new file mode 100644 index 00000000000..76931e75ab2 --- /dev/null +++ b/packages/calcite-components/src/components/table/assets/table/t9n/messages_no.json @@ -0,0 +1,7 @@ +{ + "clear": "Clear", + "hiddenSelected": "Rows selected but out of view", + "page": "Page", + "row": "Row", + "selected": "Selected" +} diff --git a/packages/calcite-components/src/components/table/assets/table/t9n/messages_pl.json b/packages/calcite-components/src/components/table/assets/table/t9n/messages_pl.json new file mode 100644 index 00000000000..76931e75ab2 --- /dev/null +++ b/packages/calcite-components/src/components/table/assets/table/t9n/messages_pl.json @@ -0,0 +1,7 @@ +{ + "clear": "Clear", + "hiddenSelected": "Rows selected but out of view", + "page": "Page", + "row": "Row", + "selected": "Selected" +} diff --git a/packages/calcite-components/src/components/table/assets/table/t9n/messages_pt-BR.json b/packages/calcite-components/src/components/table/assets/table/t9n/messages_pt-BR.json new file mode 100644 index 00000000000..76931e75ab2 --- /dev/null +++ b/packages/calcite-components/src/components/table/assets/table/t9n/messages_pt-BR.json @@ -0,0 +1,7 @@ +{ + "clear": "Clear", + "hiddenSelected": "Rows selected but out of view", + "page": "Page", + "row": "Row", + "selected": "Selected" +} diff --git a/packages/calcite-components/src/components/table/assets/table/t9n/messages_pt-PT.json b/packages/calcite-components/src/components/table/assets/table/t9n/messages_pt-PT.json new file mode 100644 index 00000000000..76931e75ab2 --- /dev/null +++ b/packages/calcite-components/src/components/table/assets/table/t9n/messages_pt-PT.json @@ -0,0 +1,7 @@ +{ + "clear": "Clear", + "hiddenSelected": "Rows selected but out of view", + "page": "Page", + "row": "Row", + "selected": "Selected" +} diff --git a/packages/calcite-components/src/components/table/assets/table/t9n/messages_ro.json b/packages/calcite-components/src/components/table/assets/table/t9n/messages_ro.json new file mode 100644 index 00000000000..76931e75ab2 --- /dev/null +++ b/packages/calcite-components/src/components/table/assets/table/t9n/messages_ro.json @@ -0,0 +1,7 @@ +{ + "clear": "Clear", + "hiddenSelected": "Rows selected but out of view", + "page": "Page", + "row": "Row", + "selected": "Selected" +} diff --git a/packages/calcite-components/src/components/table/assets/table/t9n/messages_ru.json b/packages/calcite-components/src/components/table/assets/table/t9n/messages_ru.json new file mode 100644 index 00000000000..76931e75ab2 --- /dev/null +++ b/packages/calcite-components/src/components/table/assets/table/t9n/messages_ru.json @@ -0,0 +1,7 @@ +{ + "clear": "Clear", + "hiddenSelected": "Rows selected but out of view", + "page": "Page", + "row": "Row", + "selected": "Selected" +} diff --git a/packages/calcite-components/src/components/table/assets/table/t9n/messages_sk.json b/packages/calcite-components/src/components/table/assets/table/t9n/messages_sk.json new file mode 100644 index 00000000000..76931e75ab2 --- /dev/null +++ b/packages/calcite-components/src/components/table/assets/table/t9n/messages_sk.json @@ -0,0 +1,7 @@ +{ + "clear": "Clear", + "hiddenSelected": "Rows selected but out of view", + "page": "Page", + "row": "Row", + "selected": "Selected" +} diff --git a/packages/calcite-components/src/components/table/assets/table/t9n/messages_sl.json b/packages/calcite-components/src/components/table/assets/table/t9n/messages_sl.json new file mode 100644 index 00000000000..76931e75ab2 --- /dev/null +++ b/packages/calcite-components/src/components/table/assets/table/t9n/messages_sl.json @@ -0,0 +1,7 @@ +{ + "clear": "Clear", + "hiddenSelected": "Rows selected but out of view", + "page": "Page", + "row": "Row", + "selected": "Selected" +} diff --git a/packages/calcite-components/src/components/table/assets/table/t9n/messages_sr.json b/packages/calcite-components/src/components/table/assets/table/t9n/messages_sr.json new file mode 100644 index 00000000000..76931e75ab2 --- /dev/null +++ b/packages/calcite-components/src/components/table/assets/table/t9n/messages_sr.json @@ -0,0 +1,7 @@ +{ + "clear": "Clear", + "hiddenSelected": "Rows selected but out of view", + "page": "Page", + "row": "Row", + "selected": "Selected" +} diff --git a/packages/calcite-components/src/components/table/assets/table/t9n/messages_sv.json b/packages/calcite-components/src/components/table/assets/table/t9n/messages_sv.json new file mode 100644 index 00000000000..76931e75ab2 --- /dev/null +++ b/packages/calcite-components/src/components/table/assets/table/t9n/messages_sv.json @@ -0,0 +1,7 @@ +{ + "clear": "Clear", + "hiddenSelected": "Rows selected but out of view", + "page": "Page", + "row": "Row", + "selected": "Selected" +} diff --git a/packages/calcite-components/src/components/table/assets/table/t9n/messages_th.json b/packages/calcite-components/src/components/table/assets/table/t9n/messages_th.json new file mode 100644 index 00000000000..76931e75ab2 --- /dev/null +++ b/packages/calcite-components/src/components/table/assets/table/t9n/messages_th.json @@ -0,0 +1,7 @@ +{ + "clear": "Clear", + "hiddenSelected": "Rows selected but out of view", + "page": "Page", + "row": "Row", + "selected": "Selected" +} diff --git a/packages/calcite-components/src/components/table/assets/table/t9n/messages_tr.json b/packages/calcite-components/src/components/table/assets/table/t9n/messages_tr.json new file mode 100644 index 00000000000..76931e75ab2 --- /dev/null +++ b/packages/calcite-components/src/components/table/assets/table/t9n/messages_tr.json @@ -0,0 +1,7 @@ +{ + "clear": "Clear", + "hiddenSelected": "Rows selected but out of view", + "page": "Page", + "row": "Row", + "selected": "Selected" +} diff --git a/packages/calcite-components/src/components/table/assets/table/t9n/messages_uk.json b/packages/calcite-components/src/components/table/assets/table/t9n/messages_uk.json new file mode 100644 index 00000000000..76931e75ab2 --- /dev/null +++ b/packages/calcite-components/src/components/table/assets/table/t9n/messages_uk.json @@ -0,0 +1,7 @@ +{ + "clear": "Clear", + "hiddenSelected": "Rows selected but out of view", + "page": "Page", + "row": "Row", + "selected": "Selected" +} diff --git a/packages/calcite-components/src/components/table/assets/table/t9n/messages_vi.json b/packages/calcite-components/src/components/table/assets/table/t9n/messages_vi.json new file mode 100644 index 00000000000..76931e75ab2 --- /dev/null +++ b/packages/calcite-components/src/components/table/assets/table/t9n/messages_vi.json @@ -0,0 +1,7 @@ +{ + "clear": "Clear", + "hiddenSelected": "Rows selected but out of view", + "page": "Page", + "row": "Row", + "selected": "Selected" +} diff --git a/packages/calcite-components/src/components/table/assets/table/t9n/messages_zh-CN.json b/packages/calcite-components/src/components/table/assets/table/t9n/messages_zh-CN.json new file mode 100644 index 00000000000..76931e75ab2 --- /dev/null +++ b/packages/calcite-components/src/components/table/assets/table/t9n/messages_zh-CN.json @@ -0,0 +1,7 @@ +{ + "clear": "Clear", + "hiddenSelected": "Rows selected but out of view", + "page": "Page", + "row": "Row", + "selected": "Selected" +} diff --git a/packages/calcite-components/src/components/table/assets/table/t9n/messages_zh-HK.json b/packages/calcite-components/src/components/table/assets/table/t9n/messages_zh-HK.json new file mode 100644 index 00000000000..76931e75ab2 --- /dev/null +++ b/packages/calcite-components/src/components/table/assets/table/t9n/messages_zh-HK.json @@ -0,0 +1,7 @@ +{ + "clear": "Clear", + "hiddenSelected": "Rows selected but out of view", + "page": "Page", + "row": "Row", + "selected": "Selected" +} diff --git a/packages/calcite-components/src/components/table/assets/table/t9n/messages_zh-TW.json b/packages/calcite-components/src/components/table/assets/table/t9n/messages_zh-TW.json new file mode 100644 index 00000000000..76931e75ab2 --- /dev/null +++ b/packages/calcite-components/src/components/table/assets/table/t9n/messages_zh-TW.json @@ -0,0 +1,7 @@ +{ + "clear": "Clear", + "hiddenSelected": "Rows selected but out of view", + "page": "Page", + "row": "Row", + "selected": "Selected" +} diff --git a/packages/calcite-components/src/components/table/interfaces.ts b/packages/calcite-components/src/components/table/interfaces.ts new file mode 100644 index 00000000000..90f24e94c7f --- /dev/null +++ b/packages/calcite-components/src/components/table/interfaces.ts @@ -0,0 +1,14 @@ +import { FocusElementInGroupDestination } from "../../utils/dom"; + +export interface TableRowFocusEvent { + cellPosition: number; + rowPosition: number; + destination: FocusElementInGroupDestination; + lastCell: boolean; +} + +export type RowType = "head" | "body" | "foot"; + +export type TableAppearance = "bordered" | "simple" | "bordered-zebra" | "simple-zebra"; + +export type TableLayout = "auto" | "fixed"; diff --git a/packages/calcite-components/src/components/table/readme.md b/packages/calcite-components/src/components/table/readme.md new file mode 100644 index 00000000000..06294a8a158 --- /dev/null +++ b/packages/calcite-components/src/components/table/readme.md @@ -0,0 +1,50 @@ +# calcite-table + + + +## Properties + +| Property | Attribute | Description | Type | Default | +| ---------------------- | ---------------- | ------------------------------------------------------------- | -------------------------------------------------------------- | ----------- | +| `appearance` | `appearance` | Specifies the appearance of the component. | `"bordered" \| "bordered-zebra" \| "simple" \| "simple-zebra"` | `"simple"` | +| `caption` _(required)_ | `caption` | Specifies an accessible title for the component. | `string` | `undefined` | +| `layout` | `layout` | Specifies the layout of the component. | `"auto" \| "fixed"` | `"auto"` | +| `numbered` | `numbered` | When `true`, displays the position of the row in numeric form | `boolean` | `false` | +| `scale` | `scale` | Specifies the size of the component. | `"l" \| "m" \| "s"` | `"m"` | +| `selectedItems` | -- | Specifies the component's selected items. | `HTMLCalciteTableRowElement[]` | `[]` | +| `selectionMode` | `selection-mode` | Specifies the selection mode of the component. | `"multiple" \| "none" \| "single"` | `"none"` | + +## Events + +| Event | Description | Type | +| -------------------- | --------------------------------------------- | ------------------- | +| `calciteTableSelect` | Emits when the component's selection changes. | `CustomEvent` | + +## Slots + +| Slot | Description | +| ----------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- | +| | A slot for adding `calcite-table-row` or nested `calcite-table` elements. Content placed here will be rendered in a `table-body` tag. | +| `"selection-actions"` | A slot for adding a `calcite-action` or other element to display when `selectionMode !== "none"` and `calcite-table-row` are selected. | +| `"selection-actions"` | A slot for adding a `calcite-action` or other element to display when `selectionMode !== "none"` and `calcite-table-row` are selected. | +| `"table-foot- A slot for adding `calcite-table-row`and nested`calcite-table-header` elements."` | | +| `"table-head- A slot for adding `calcite-table-row`and nested`calcite-table-header` elements."` | | + +## Dependencies + +### Depends on + +- [calcite-chip](../chip) + +### Graph + +```mermaid +graph TD; + calcite-table --> calcite-chip + calcite-chip --> calcite-icon + style calcite-table fill:#f9f,stroke:#333,stroke-width:4px +``` + +--- + +_Built with [StencilJS](https://stenciljs.com/)_ diff --git a/packages/calcite-components/src/components/table/resources.ts b/packages/calcite-components/src/components/table/resources.ts new file mode 100644 index 00000000000..93646dda10f --- /dev/null +++ b/packages/calcite-components/src/components/table/resources.ts @@ -0,0 +1,17 @@ +export const CSS = { + bordered: "bordered", + zebra: "zebra", + selectionArea: "selection-area", + paginationArea: "pagination-area", + container: "container", + tableContainer: "table-container", + tableFixed: "table--fixed", + assistiveText: "assistive-text", + selectionActions: "selection-actions", +}; + +export const SLOTS = { + selectionActions: "selection-actions", + tableHeader: "table-header", + tableFooter: "table-footer", +}; diff --git a/packages/calcite-components/src/components/table/table.e2e.ts b/packages/calcite-components/src/components/table/table.e2e.ts new file mode 100644 index 00000000000..407f0868e34 --- /dev/null +++ b/packages/calcite-components/src/components/table/table.e2e.ts @@ -0,0 +1,2427 @@ +import { E2EPage, newE2EPage } from "@stencil/core/testing"; +import { html } from "../../../support/formatting"; +import { accessible, renders, hidden, defaults, reflects } from "../../tests/commonTests"; +import { GlobalTestProps, getFocusedElementProp } from "../../tests/utils"; +import { CSS } from "../table-header/resources"; +import { CSS as CELL_CSS } from "../table-cell/resources"; +import { SLOTS } from "../table/resources"; + +describe("calcite-table", () => { + describe("renders", () => { + renders( + html` + + + + + + cell + cell + + + cell + cell + + + cell + cell + + `, + { display: "table" } + ); + }); + + describe("defaults", () => { + defaults("calcite-table", [ + { + propertyName: "bordered", + defaultValue: false, + }, + { + propertyName: "groupSeparator", + defaultValue: false, + }, + { + propertyName: "layout", + defaultValue: "auto", + }, + { + propertyName: "numbered", + defaultValue: false, + }, + { + propertyName: "pageSize", + defaultValue: 0, + }, + { + propertyName: "scale", + defaultValue: "m", + }, + { + propertyName: "selectionMode", + defaultValue: "none", + }, + { + propertyName: "zebra", + defaultValue: false, + }, + ]); + }); + + describe("reflects", () => { + reflects("calcite-table", [ + { + propertyName: "layout", + value: "auto", + }, + { + propertyName: "scale", + value: "m", + }, + { + propertyName: "selectionMode", + value: "none", + }, + ]); + }); + + describe("hidden", () => { + hidden("calcite-table"); + }); + + describe("accessible", () => { + describe("is accessible simple", () => { + accessible( + html` + + + + + + cell + cell + + + cell + cell + + + cell + cell + + ` + ); + }); + + describe("is accessible with selection mode multiple", () => { + accessible( + html` + + + + + + cell + cell + + + cell + cell + + + cell + cell + + ` + ); + }); + + describe("is accessible with selection mode multiple selected at load", () => { + accessible( + html` + + + + + + cell + cell + + + cell + cell + + + cell + cell + + ` + ); + }); + + describe("is accessible with selection mode single", () => { + accessible( + html` + + + + + + cell + cell + + + cell + cell + + + cell + cell + + ` + ); + }); + + describe("is accessible with numbered", () => { + accessible( + html` + + + + + + cell + cell + + + cell + cell + + + cell + cell + + ` + ); + }); + + describe("is accessible with numbered and selection", () => { + accessible( + html` + + + + + + cell + cell + + + cell + cell + + + cell + cell + + ` + ); + }); + + describe("is accessible with pagination", () => { + accessible( + html` + + + + + + cell + cell + + + cell + cell + + + cell + cell + + + cell + cell + + + cell + cell + + + cell + cell + + + cell + cell + + ` + ); + }); + + describe("is accessible with pagination and selection mode", () => { + accessible( + html` + + + + + + cell + cell + + + cell + cell + + + cell + cell + + + cell + cell + + + cell + cell + + + cell + cell + + + cell + cell + + ` + ); + }); + }); +}); + +describe("selection modes", () => { + it("selection mode single allows one or no rows to be selected", async () => { + const page = await newE2EPage(); + await page.setContent( + html` + + + + + + cell + cell + + + cell + cell + + + cell + cell + + ` + ); + + await assertSelectedItems.setUpEvents(page); + + const element = await page.find("calcite-table"); + const row1 = await page.find("#row-1"); + const row2 = await page.find("#row-2"); + const row3 = await page.find("#row-3"); + + const tableSelectSpy = await element.spyOnEvent("calciteTableSelect"); + const rowSelectSpy1 = await row1.spyOnEvent("calciteTableRowSelect"); + const rowSelectSpy2 = await row2.spyOnEvent("calciteTableRowSelect"); + const rowSelectSpy3 = await row3.spyOnEvent("calciteTableRowSelect"); + + await page.waitForChanges(); + expect(tableSelectSpy).toHaveReceivedEventTimes(0); + expect(rowSelectSpy1).toHaveReceivedEventTimes(0); + expect(rowSelectSpy2).toHaveReceivedEventTimes(0); + expect(rowSelectSpy3).toHaveReceivedEventTimes(0); + + expect(await element.getProperty("selectedItems")).toHaveLength(1); + await assertSelectedItems(page, { expectedItemIds: [row3.id] }); + + await page.$eval("calcite-table", () => { + const row = document.getElementById("row-1"); + const cell = row.shadowRoot.querySelector("calcite-table-cell:first-child"); + + cell.click(); + }); + + await page.waitForChanges(); + expect(await tableSelectSpy).toHaveReceivedEventTimes(1); + expect(await rowSelectSpy1).toHaveReceivedEventTimes(1); + expect(await rowSelectSpy2).toHaveReceivedEventTimes(0); + expect(await rowSelectSpy3).toHaveReceivedEventTimes(0); + expect(await row1.getProperty("selected")).toBe(true); + expect(await row2.getProperty("selected")).toBe(false); + expect(await row3.getProperty("selected")).toBe(false); + expect(await element.getProperty("selectedItems")).toHaveLength(1); + await assertSelectedItems(page, { expectedItemIds: [row1.id] }); + + await page.$eval("calcite-table", () => { + const row = document.getElementById("row-2"); + const cell = row.shadowRoot.querySelector("calcite-table-cell:first-child"); + cell.click(); + }); + + await page.waitForChanges(); + expect(tableSelectSpy).toHaveReceivedEventTimes(2); + expect(rowSelectSpy1).toHaveReceivedEventTimes(1); + expect(rowSelectSpy2).toHaveReceivedEventTimes(1); + expect(rowSelectSpy3).toHaveReceivedEventTimes(0); + expect(await row1.getProperty("selected")).toBe(false); + expect(await row2.getProperty("selected")).toBe(true); + expect(await row3.getProperty("selected")).toBe(false); + expect(await element.getProperty("selectedItems")).toHaveLength(1); + await assertSelectedItems(page, { expectedItemIds: [row2.id] }); + + await page.$eval("calcite-table", () => { + const row = document.getElementById("row-3"); + const cell = row.shadowRoot.querySelector("calcite-table-cell:first-child"); + cell.click(); + }); + + await page.waitForChanges(); + expect(tableSelectSpy).toHaveReceivedEventTimes(3); + expect(rowSelectSpy1).toHaveReceivedEventTimes(1); + expect(rowSelectSpy2).toHaveReceivedEventTimes(1); + expect(rowSelectSpy3).toHaveReceivedEventTimes(1); + expect(await row1.getProperty("selected")).toBe(false); + expect(await row2.getProperty("selected")).toBe(false); + expect(await row3.getProperty("selected")).toBe(true); + expect(await element.getProperty("selectedItems")).toHaveLength(1); + await assertSelectedItems(page, { expectedItemIds: [row3.id] }); + + await page.$eval("calcite-table", () => { + const row = document.getElementById("row-3"); + const cell = row.shadowRoot.querySelector("calcite-table-cell:first-child"); + cell.click(); + }); + + await page.waitForChanges(); + expect(tableSelectSpy).toHaveReceivedEventTimes(4); + expect(rowSelectSpy1).toHaveReceivedEventTimes(1); + expect(rowSelectSpy2).toHaveReceivedEventTimes(1); + expect(rowSelectSpy3).toHaveReceivedEventTimes(2); + expect(await row1.getProperty("selected")).toBe(false); + expect(await row2.getProperty("selected")).toBe(false); + expect(await row3.getProperty("selected")).toBe(false); + + expect(await element.getProperty("selectedItems")).toEqual([]); + await assertSelectedItems(page, { expectedItemIds: [] }); + }); + + it("selection mode multiple allows one, multiple, or no rows to be selected", async () => { + const page = await newE2EPage(); + await page.setContent( + html` + + + + + + cell + cell + + + cell + cell + + + cell + cell + + ` + ); + + await assertSelectedItems.setUpEvents(page); + + const element = await page.find("calcite-table"); + const row1 = await page.find("#row-1"); + const row2 = await page.find("#row-2"); + const row3 = await page.find("#row-3"); + + const tableSelectSpy = await element.spyOnEvent("calciteTableSelect"); + const rowSelectSpy1 = await row1.spyOnEvent("calciteTableRowSelect"); + const rowSelectSpy2 = await row2.spyOnEvent("calciteTableRowSelect"); + const rowSelectSpy3 = await row3.spyOnEvent("calciteTableRowSelect"); + + await page.waitForChanges(); + + expect(tableSelectSpy).toHaveReceivedEventTimes(0); + expect(rowSelectSpy1).toHaveReceivedEventTimes(0); + expect(rowSelectSpy2).toHaveReceivedEventTimes(0); + expect(rowSelectSpy3).toHaveReceivedEventTimes(0); + + expect(await element.getProperty("selectedItems")).toHaveLength(2); + await assertSelectedItems(page, { expectedItemIds: [row2.id, row3.id] }); + + await page.$eval("calcite-table", () => { + const row = document.getElementById("row-1"); + const cell = row.shadowRoot.querySelector("calcite-table-cell:first-child"); + cell.click(); + }); + + await page.waitForChanges(); + expect(await tableSelectSpy).toHaveReceivedEventTimes(1); + expect(await rowSelectSpy1).toHaveReceivedEventTimes(1); + expect(await rowSelectSpy2).toHaveReceivedEventTimes(0); + expect(await rowSelectSpy3).toHaveReceivedEventTimes(0); + expect(await row1.getProperty("selected")).toBe(true); + expect(await row2.getProperty("selected")).toBe(true); + expect(await row3.getProperty("selected")).toBe(true); + expect(await element.getProperty("selectedItems")).toHaveLength(3); + await assertSelectedItems(page, { expectedItemIds: [row1.id, row2.id, row3.id] }); + + await page.$eval("calcite-table", () => { + const row = document.getElementById("row-2"); + const cell = row.shadowRoot.querySelector("calcite-table-cell:first-child"); + cell.click(); + }); + + await page.waitForChanges(); + expect(tableSelectSpy).toHaveReceivedEventTimes(2); + expect(rowSelectSpy1).toHaveReceivedEventTimes(1); + expect(rowSelectSpy2).toHaveReceivedEventTimes(1); + expect(rowSelectSpy3).toHaveReceivedEventTimes(0); + expect(await row1.getProperty("selected")).toBe(true); + expect(await row2.getProperty("selected")).toBe(false); + expect(await row3.getProperty("selected")).toBe(true); + expect(await element.getProperty("selectedItems")).toHaveLength(2); + await assertSelectedItems(page, { expectedItemIds: [row1.id, row3.id] }); + + await page.$eval("calcite-table", () => { + const row = document.getElementById("row-3"); + const cell = row.shadowRoot.querySelector("calcite-table-cell:first-child"); + cell.click(); + }); + + await page.waitForChanges(); + expect(tableSelectSpy).toHaveReceivedEventTimes(3); + expect(rowSelectSpy1).toHaveReceivedEventTimes(1); + expect(rowSelectSpy2).toHaveReceivedEventTimes(1); + expect(rowSelectSpy3).toHaveReceivedEventTimes(1); + expect(await row1.getProperty("selected")).toBe(true); + expect(await row2.getProperty("selected")).toBe(false); + expect(await row3.getProperty("selected")).toBe(false); + expect(await element.getProperty("selectedItems")).toHaveLength(1); + await assertSelectedItems(page, { expectedItemIds: [row1.id] }); + + await page.$eval("calcite-table", () => { + const row = document.getElementById("row-1"); + const cell = row.shadowRoot.querySelector("calcite-table-cell:first-child"); + cell.click(); + }); + + await page.waitForChanges(); + expect(tableSelectSpy).toHaveReceivedEventTimes(4); + expect(rowSelectSpy1).toHaveReceivedEventTimes(2); + expect(rowSelectSpy2).toHaveReceivedEventTimes(1); + expect(rowSelectSpy3).toHaveReceivedEventTimes(1); + expect(await row1.getProperty("selected")).toBe(false); + expect(await row2.getProperty("selected")).toBe(false); + expect(await row3.getProperty("selected")).toBe(false); + + expect(await element.getProperty("selectedItems")).toEqual([]); + await assertSelectedItems(page, { expectedItemIds: [] }); + }); + + it("selection mode single allows one or no rows to be selected with keyboard", async () => { + const page = await newE2EPage(); + await page.setContent( + html` + + + + + + cell + cell + + + cell + cell + + + cell + cell + + ` + ); + + await assertSelectedItems.setUpEvents(page); + + const element = await page.find("calcite-table"); + const row1 = await page.find("#row-1"); + const row2 = await page.find("#row-2"); + const row3 = await page.find("#row-3"); + + const selectionCell1 = await page.find("#row-1 >>> calcite-table-cell:first-child"); + const selectionCell2 = await page.find("#row-2 >>> calcite-table-cell:first-child"); + const selectionCell3 = await page.find("#row-3 >>> calcite-table-cell:first-child"); + + const tableSelectSpy = await element.spyOnEvent("calciteTableSelect"); + const rowSelectSpy1 = await row1.spyOnEvent("calciteTableRowSelect"); + const rowSelectSpy2 = await row2.spyOnEvent("calciteTableRowSelect"); + const rowSelectSpy3 = await row3.spyOnEvent("calciteTableRowSelect"); + + await page.waitForChanges(); + expect(tableSelectSpy).toHaveReceivedEventTimes(0); + expect(rowSelectSpy1).toHaveReceivedEventTimes(0); + expect(rowSelectSpy2).toHaveReceivedEventTimes(0); + expect(rowSelectSpy3).toHaveReceivedEventTimes(0); + + expect(await element.getProperty("selectedItems")).toHaveLength(1); + await assertSelectedItems(page, { expectedItemIds: [row3.id] }); + await selectionCell1.callMethod("setFocus"); + await page.waitForChanges(); + + await page.keyboard.press("Space"); + await page.waitForChanges(); + + expect(await tableSelectSpy).toHaveReceivedEventTimes(1); + expect(await rowSelectSpy1).toHaveReceivedEventTimes(1); + expect(await rowSelectSpy2).toHaveReceivedEventTimes(0); + expect(await rowSelectSpy3).toHaveReceivedEventTimes(0); + expect(await row1.getProperty("selected")).toBe(true); + expect(await row2.getProperty("selected")).toBe(false); + expect(await row3.getProperty("selected")).toBe(false); + expect(await element.getProperty("selectedItems")).toHaveLength(1); + await assertSelectedItems(page, { expectedItemIds: [row1.id] }); + + await selectionCell2.callMethod("setFocus"); + await page.waitForChanges(); + await page.keyboard.press("Enter"); + await page.waitForChanges(); + + expect(tableSelectSpy).toHaveReceivedEventTimes(2); + expect(rowSelectSpy1).toHaveReceivedEventTimes(1); + expect(rowSelectSpy2).toHaveReceivedEventTimes(1); + expect(rowSelectSpy3).toHaveReceivedEventTimes(0); + expect(await row1.getProperty("selected")).toBe(false); + expect(await row2.getProperty("selected")).toBe(true); + expect(await row3.getProperty("selected")).toBe(false); + expect(await element.getProperty("selectedItems")).toHaveLength(1); + await assertSelectedItems(page, { expectedItemIds: [row2.id] }); + + await selectionCell3.callMethod("setFocus"); + await page.waitForChanges(); + await page.keyboard.press("Enter"); + await page.waitForChanges(); + + expect(tableSelectSpy).toHaveReceivedEventTimes(3); + expect(rowSelectSpy1).toHaveReceivedEventTimes(1); + expect(rowSelectSpy2).toHaveReceivedEventTimes(1); + expect(rowSelectSpy3).toHaveReceivedEventTimes(1); + expect(await row1.getProperty("selected")).toBe(false); + expect(await row2.getProperty("selected")).toBe(false); + expect(await row3.getProperty("selected")).toBe(true); + expect(await element.getProperty("selectedItems")).toHaveLength(1); + await assertSelectedItems(page, { expectedItemIds: [row3.id] }); + + await selectionCell3.callMethod("setFocus"); + + await page.waitForChanges(); + await page.keyboard.press("Space"); + await page.waitForChanges(); + expect(tableSelectSpy).toHaveReceivedEventTimes(4); + expect(rowSelectSpy1).toHaveReceivedEventTimes(1); + expect(rowSelectSpy2).toHaveReceivedEventTimes(1); + expect(rowSelectSpy3).toHaveReceivedEventTimes(2); + expect(await row1.getProperty("selected")).toBe(false); + expect(await row2.getProperty("selected")).toBe(false); + expect(await row3.getProperty("selected")).toBe(false); + + expect(await element.getProperty("selectedItems")).toEqual([]); + await assertSelectedItems(page, { expectedItemIds: [] }); + }); + + it("selection mode multiple allows one, multiple, or no rows to be selected with keyboard", async () => { + const page = await newE2EPage(); + await page.setContent( + html` + + + + + + cell + cell + + + cell + cell + + + cell + cell + + ` + ); + + await assertSelectedItems.setUpEvents(page); + + const element = await page.find("calcite-table"); + const row1 = await page.find("#row-1"); + const row2 = await page.find("#row-2"); + const row3 = await page.find("#row-3"); + const selectionCell1 = await page.find("#row-1 >>> calcite-table-cell:first-child"); + const selectionCell2 = await page.find("#row-2 >>> calcite-table-cell:first-child"); + const selectionCell3 = await page.find("#row-3 >>> calcite-table-cell:first-child"); + + const tableSelectSpy = await element.spyOnEvent("calciteTableSelect"); + const rowSelectSpy1 = await row1.spyOnEvent("calciteTableRowSelect"); + const rowSelectSpy2 = await row2.spyOnEvent("calciteTableRowSelect"); + const rowSelectSpy3 = await row3.spyOnEvent("calciteTableRowSelect"); + + await page.waitForChanges(); + + expect(tableSelectSpy).toHaveReceivedEventTimes(0); + expect(rowSelectSpy1).toHaveReceivedEventTimes(0); + expect(rowSelectSpy2).toHaveReceivedEventTimes(0); + expect(rowSelectSpy3).toHaveReceivedEventTimes(0); + + expect(await element.getProperty("selectedItems")).toHaveLength(2); + await assertSelectedItems(page, { expectedItemIds: [row2.id, row3.id] }); + + await selectionCell1.callMethod("setFocus"); + + await page.waitForChanges(); + await page.keyboard.press("Enter"); + await page.waitForChanges(); + expect(await tableSelectSpy).toHaveReceivedEventTimes(1); + expect(await rowSelectSpy1).toHaveReceivedEventTimes(1); + expect(await rowSelectSpy2).toHaveReceivedEventTimes(0); + expect(await rowSelectSpy3).toHaveReceivedEventTimes(0); + expect(await row1.getProperty("selected")).toBe(true); + expect(await row2.getProperty("selected")).toBe(true); + expect(await row3.getProperty("selected")).toBe(true); + expect(await element.getProperty("selectedItems")).toHaveLength(3); + await assertSelectedItems(page, { expectedItemIds: [row1.id, row2.id, row3.id] }); + + await selectionCell2.callMethod("setFocus"); + + await page.waitForChanges(); + await page.keyboard.press("Space"); + await page.waitForChanges(); + expect(tableSelectSpy).toHaveReceivedEventTimes(2); + expect(rowSelectSpy1).toHaveReceivedEventTimes(1); + expect(rowSelectSpy2).toHaveReceivedEventTimes(1); + expect(rowSelectSpy3).toHaveReceivedEventTimes(0); + expect(await row1.getProperty("selected")).toBe(true); + expect(await row2.getProperty("selected")).toBe(false); + expect(await row3.getProperty("selected")).toBe(true); + expect(await element.getProperty("selectedItems")).toHaveLength(2); + await assertSelectedItems(page, { expectedItemIds: [row1.id, row3.id] }); + + await selectionCell3.callMethod("setFocus"); + + await page.waitForChanges(); + await page.keyboard.press("Enter"); + await page.waitForChanges(); + expect(tableSelectSpy).toHaveReceivedEventTimes(3); + expect(rowSelectSpy1).toHaveReceivedEventTimes(1); + expect(rowSelectSpy2).toHaveReceivedEventTimes(1); + expect(rowSelectSpy3).toHaveReceivedEventTimes(1); + expect(await row1.getProperty("selected")).toBe(true); + expect(await row2.getProperty("selected")).toBe(false); + expect(await row3.getProperty("selected")).toBe(false); + expect(await element.getProperty("selectedItems")).toHaveLength(1); + await assertSelectedItems(page, { expectedItemIds: [row1.id] }); + + await selectionCell1.callMethod("setFocus"); + + await page.waitForChanges(); + await page.keyboard.press("Space"); + await page.waitForChanges(); + expect(tableSelectSpy).toHaveReceivedEventTimes(4); + expect(rowSelectSpy1).toHaveReceivedEventTimes(2); + expect(rowSelectSpy2).toHaveReceivedEventTimes(1); + expect(rowSelectSpy3).toHaveReceivedEventTimes(1); + expect(await row1.getProperty("selected")).toBe(false); + expect(await row2.getProperty("selected")).toBe(false); + expect(await row3.getProperty("selected")).toBe(false); + + expect(await element.getProperty("selectedItems")).toEqual([]); + await assertSelectedItems(page, { expectedItemIds: [] }); + }); + it("correctly has no selected items after user clears selection via clear button", async () => { + const page = await newE2EPage(); + await page.setContent( + html` + + + + + + cell + cell + + + cell + cell + + + cell + cell + + ` + ); + + await assertSelectedItems.setUpEvents(page); + const element = await page.find("calcite-table"); + const row1 = await page.find("#row-1"); + const row2 = await page.find("#row-2"); + const row3 = await page.find("#row-3"); + + const tableSelectSpy = await element.spyOnEvent("calciteTableSelect"); + await page.waitForChanges(); + + expect(tableSelectSpy).toHaveReceivedEventTimes(0); + expect(await element.getProperty("selectedItems")).toHaveLength(2); + await assertSelectedItems(page, { expectedItemIds: [row2.id, row3.id] }); + + await page.$eval("calcite-table", () => { + const table = document.querySelector("calcite-table"); + const button = table.shadowRoot.querySelector("calcite-button"); + button?.click(); + }); + + await page.waitForChanges(); + expect(tableSelectSpy).toHaveReceivedEventTimes(1); + expect(await row1.getProperty("selected")).toBe(false); + expect(await row2.getProperty("selected")).toBe(false); + expect(await row3.getProperty("selected")).toBe(false); + expect(await element.getProperty("selectedItems")).toHaveLength(0); + await assertSelectedItems(page, { expectedItemIds: [] }); + }); + + it("correctly has all items selected after user uses select all cell while none selected", async () => { + const page = await newE2EPage(); + await page.setContent( + html` + + + + + + cell + cell + + + cell + cell + + + cell + cell + + ` + ); + + await assertSelectedItems.setUpEvents(page); + const element = await page.find("calcite-table"); + const row1 = await page.find("#row-1"); + const row2 = await page.find("#row-2"); + const row3 = await page.find("#row-3"); + + const tableSelectSpy = await element.spyOnEvent("calciteTableSelect"); + await page.waitForChanges(); + + expect(tableSelectSpy).toHaveReceivedEventTimes(0); + expect(await element.getProperty("selectedItems")).toHaveLength(0); + await assertSelectedItems(page, { expectedItemIds: [] }); + + await page.$eval("calcite-table", () => { + const row = document.getElementById("row-head"); + const cell = row.shadowRoot.querySelector("calcite-table-header:first-child"); + cell.click(); + }); + + await page.waitForChanges(); + expect(tableSelectSpy).toHaveReceivedEventTimes(1); + expect(await row1.getProperty("selected")).toBe(true); + expect(await row2.getProperty("selected")).toBe(true); + expect(await row3.getProperty("selected")).toBe(true); + expect(await element.getProperty("selectedItems")).toHaveLength(3); + await assertSelectedItems(page, { expectedItemIds: [row1.id, row2.id, row3.id] }); + }); + + it("correctly has all items selected after user uses select all cell while none selected and multiple pages", async () => { + const page = await newE2EPage(); + await page.setContent( + html` + + + + + + cell + cell + + + cell + cell + + + cell + cell + + ` + ); + + await assertSelectedItems.setUpEvents(page); + const element = await page.find("calcite-table"); + const row1 = await page.find("#row-1"); + const row2 = await page.find("#row-2"); + const row3 = await page.find("#row-3"); + + const tableSelectSpy = await element.spyOnEvent("calciteTableSelect"); + await page.waitForChanges(); + + expect(tableSelectSpy).toHaveReceivedEventTimes(0); + expect(await element.getProperty("selectedItems")).toHaveLength(0); + await assertSelectedItems(page, { expectedItemIds: [] }); + + await page.$eval("calcite-table", () => { + const row = document.getElementById("row-head"); + const cell = row.shadowRoot.querySelector("calcite-table-header:first-child"); + cell.click(); + }); + + await page.waitForChanges(); + expect(tableSelectSpy).toHaveReceivedEventTimes(1); + expect(await row1.getProperty("selected")).toBe(true); + expect(await row2.getProperty("selected")).toBe(true); + expect(await row3.getProperty("selected")).toBe(true); + expect(await element.getProperty("selectedItems")).toHaveLength(3); + await assertSelectedItems(page, { expectedItemIds: [row1.id, row2.id, row3.id] }); + }); + + it("correctly has all items selected after user uses select all cell while some selected", async () => { + const page = await newE2EPage(); + await page.setContent( + html` + + + + + + cell + cell + + + cell + cell + + + cell + cell + + ` + ); + + await assertSelectedItems.setUpEvents(page); + const element = await page.find("calcite-table"); + const row1 = await page.find("#row-1"); + const row2 = await page.find("#row-2"); + const row3 = await page.find("#row-3"); + + const tableSelectSpy = await element.spyOnEvent("calciteTableSelect"); + await page.waitForChanges(); + + expect(tableSelectSpy).toHaveReceivedEventTimes(0); + expect(await row1.getProperty("selected")).toBe(false); + expect(await row2.getProperty("selected")).toBe(true); + expect(await row3.getProperty("selected")).toBe(false); + expect(await element.getProperty("selectedItems")).toHaveLength(1); + await assertSelectedItems(page, { expectedItemIds: [row2.id] }); + + await page.$eval("calcite-table", () => { + const row = document.getElementById("row-head"); + const cell = row.shadowRoot.querySelector("calcite-table-header:first-child"); + cell.click(); + }); + + await page.waitForChanges(); + expect(await tableSelectSpy).toHaveReceivedEventTimes(1); + expect(await row1.getProperty("selected")).toBe(true); + expect(await row2.getProperty("selected")).toBe(true); + expect(await row3.getProperty("selected")).toBe(true); + expect(await element.getProperty("selectedItems")).toHaveLength(3); + await assertSelectedItems(page, { expectedItemIds: [row1.id, row2.id, row3.id] }); + }); + + it("correctly has no items selected after user uses select none cell while all selected", async () => { + const page = await newE2EPage(); + await page.setContent( + html` + + + + + + cell + cell + + + cell + cell + + + cell + cell + + ` + ); + + await assertSelectedItems.setUpEvents(page); + const element = await page.find("calcite-table"); + const row1 = await page.find("#row-1"); + const row2 = await page.find("#row-2"); + const row3 = await page.find("#row-3"); + + const tableSelectSpy = await element.spyOnEvent("calciteTableSelect"); + await page.waitForChanges(); + + expect(tableSelectSpy).toHaveReceivedEventTimes(0); + expect(await row1.getProperty("selected")).toBe(true); + expect(await row2.getProperty("selected")).toBe(true); + expect(await row3.getProperty("selected")).toBe(true); + expect(await element.getProperty("selectedItems")).toHaveLength(3); + await assertSelectedItems(page, { expectedItemIds: [row1.id, row2.id, row3.id] }); + + await page.$eval("calcite-table", () => { + const row = document.getElementById("row-head"); + const cell = row.shadowRoot.querySelector("calcite-table-header:first-child"); + cell.click(); + }); + + await page.waitForChanges(); + expect(await tableSelectSpy).toHaveReceivedEventTimes(1); + expect(await row1.getProperty("selected")).toBe(false); + expect(await row2.getProperty("selected")).toBe(false); + expect(await row3.getProperty("selected")).toBe(false); + expect(await element.getProperty("selectedItems")).toHaveLength(0); + await assertSelectedItems(page, { expectedItemIds: [] }); + }); + + it("correctly maintains selected items if they are paginated out of view", async () => { + const page = await newE2EPage(); + await page.setContent( + html` + + + + + + cell + cell + + + cell + cell + + + cell + cell + + ` + ); + + await assertSelectedItems.setUpEvents(page); + const element = await page.find("calcite-table"); + const row1 = await page.find("#row-1"); + const row2 = await page.find("#row-2"); + const row3 = await page.find("#row-3"); + + const tableSelectSpy = await element.spyOnEvent("calciteTableSelect"); + const tablePaginateSpy = await element.spyOnEvent("calciteTablePageChange"); + + await page.waitForChanges(); + + expect(tableSelectSpy).toHaveReceivedEventTimes(0); + expect(tablePaginateSpy).toHaveReceivedEventTimes(0); + expect(await row1.getProperty("selected")).toBe(true); + expect(await row2.getProperty("selected")).toBe(false); + expect(await row3.getProperty("selected")).toBe(false); + expect(await element.getProperty("selectedItems")).toHaveLength(1); + await assertSelectedItems(page, { expectedItemIds: [row1.id] }); + + await page.$eval("calcite-table", () => { + const table = document.querySelector("calcite-table"); + const pagination = table.shadowRoot.querySelector("calcite-pagination"); + const button = pagination.shadowRoot.querySelector("button.page:nth-of-type(2)"); + + button?.click(); + }); + + await page.waitForChanges(); + expect(tableSelectSpy).toHaveReceivedEventTimes(0); + expect(tablePaginateSpy).toHaveReceivedEventTimes(1); + expect(await row1.getProperty("selected")).toBe(true); + expect(await row2.getProperty("selected")).toBe(false); + expect(await row3.getProperty("selected")).toBe(false); + expect(await element.getProperty("selectedItems")).toHaveLength(1); + await assertSelectedItems(page, { expectedItemIds: [row1.id] }); + }); +}); + +describe("pagination event", () => { + it("correctly emits pagination event", async () => { + const page = await newE2EPage(); + await page.setContent( + html` + + + + + + cell + cell + + + cell + cell + + + cell + cell + + ` + ); + + await assertSelectedItems.setUpEvents(page); + const element = await page.find("calcite-table"); + const tablePaginateSpy = await element.spyOnEvent("calciteTablePageChange"); + await page.waitForChanges(); + + expect(tablePaginateSpy).toHaveReceivedEventTimes(0); + + await page.$eval("calcite-table", () => { + const table = document.querySelector("calcite-table"); + const pagination = table.shadowRoot.querySelector("calcite-pagination"); + const button = pagination.shadowRoot.querySelector("button.page:nth-of-type(2)"); + + button?.click(); + }); + + await page.waitForChanges(); + expect(tablePaginateSpy).toHaveReceivedEventTimes(1); + + await page.$eval("calcite-table", () => { + const table = document.querySelector("calcite-table"); + const pagination = table.shadowRoot.querySelector("calcite-pagination"); + const button = pagination.shadowRoot.querySelector("button.page:nth-of-type(3)"); + + button?.click(); + }); + + await page.waitForChanges(); + expect(tablePaginateSpy).toHaveReceivedEventTimes(2); + + await page.$eval("calcite-table", () => { + const table = document.querySelector("calcite-table"); + const pagination = table.shadowRoot.querySelector("calcite-pagination"); + const button = pagination.shadowRoot.querySelector("button.page:nth-of-type(4)"); + + button?.click(); + }); + + await page.waitForChanges(); + expect(tablePaginateSpy).toHaveReceivedEventTimes(3); + }); +}); + +describe("keyboard navigation", () => { + it("navigates correctly when no pagination or selection present", async () => { + const page = await newE2EPage(); + await page.setContent( + html` + + + + + + cell + cell + + + cell + cell + + + cell + cell + + ` + ); + + await page.keyboard.press("Tab"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("head-1a"); + await page.keyboard.press("ArrowRight"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("head-1b"); + await page.keyboard.press("PageDown"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("cell-3b"); + await page.keyboard.press("Home"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("cell-3a"); + await page.keyboard.press("PageUp"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("head-1a"); + await page.keyboard.press("PageUp"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("head-1a"); + await page.keyboard.press("ArrowDown"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("cell-1a"); + await page.keyboard.press("ArrowDown"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("cell-2a"); + await page.keyboard.press("End"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("cell-2b"); + await page.keyboard.press("Home"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("cell-2a"); + page.keyboard.press("ControlLeft"); + await page.keyboard.press("End"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("cell-3b"); + page.keyboard.press("ControlLeft"); + await page.keyboard.press("Home"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("head-1a"); + page.keyboard.press("ControlRight"); + await page.keyboard.press("End"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("cell-3b"); + page.keyboard.press("ControlRight"); + await page.keyboard.press("Home"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("head-1a"); + }); + + it("navigates correctly when pagination present and first page displayed", async () => { + const page = await newE2EPage(); + await page.setContent( + html` + + + + + + cell + cell + + + cell + cell + + + cell + cell + + + cell + cell + + + cell + cell + + ` + ); + + await page.keyboard.press("Tab"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("head-1a"); + await page.keyboard.press("ArrowRight"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("head-1b"); + await page.keyboard.press("PageDown"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("cell-2b"); + await page.keyboard.press("Home"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("cell-2a"); + await page.keyboard.press("PageUp"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("head-1a"); + await page.keyboard.press("PageUp"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("head-1a"); + await page.keyboard.press("ArrowDown"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("cell-1a"); + await page.keyboard.press("ArrowDown"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("cell-2a"); + await page.keyboard.press("ArrowDown"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("cell-2a"); + await page.keyboard.press("End"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("cell-2b"); + page.keyboard.press("ControlLeft"); + await page.keyboard.press("End"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("cell-2b"); + page.keyboard.press("ControlLeft"); + await page.keyboard.press("Home"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("head-1a"); + }); + + it("navigates correctly when pagination present, and navigation to two other pages occurs", async () => { + const page = await newE2EPage(); + await page.setContent( + html` + + + + + + cell + cell + + + cell + cell + + + cell + cell + + + cell + cell + + + cell + cell + + ` + ); + + await page.keyboard.press("Tab"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("head-1a"); + await page.keyboard.press("ArrowRight"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("head-1b"); + await page.keyboard.press("PageDown"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("cell-2b"); + await page.keyboard.press("Home"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("cell-2a"); + await page.keyboard.press("PageUp"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("head-1a"); + await page.keyboard.press("PageUp"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("head-1a"); + await page.keyboard.press("ArrowDown"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("cell-1a"); + await page.keyboard.press("ArrowDown"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("cell-2a"); + await page.keyboard.press("ArrowDown"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("cell-2a"); + await page.keyboard.press("End"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("cell-2b"); + page.keyboard.press("ControlLeft"); + await page.keyboard.press("End"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("cell-2b"); + page.keyboard.press("ControlLeft"); + await page.keyboard.press("Home"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("head-1a"); + + await page.$eval("calcite-table", () => { + const table = document.querySelector("calcite-table"); + const headerCell = document.getElementById("head-1a"); + + const pagination = table.shadowRoot.querySelector("calcite-pagination"); + const button = pagination.shadowRoot.querySelector("button.page:nth-of-type(3)"); + button?.click(); + (headerCell as HTMLCalciteTableHeaderElement).setFocus(); + }); + + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("head-1a"); + await page.keyboard.press("ArrowRight"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("head-1b"); + await page.keyboard.press("PageDown"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("cell-4b"); + await page.keyboard.press("Home"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("cell-4a"); + await page.keyboard.press("PageUp"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("head-1a"); + await page.keyboard.press("PageUp"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("head-1a"); + await page.keyboard.press("ArrowDown"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("cell-3a"); + await page.keyboard.press("ArrowDown"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("cell-4a"); + await page.keyboard.press("ArrowDown"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("cell-4a"); + await page.keyboard.press("End"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("cell-4b"); + page.keyboard.press("ControlRight"); + await page.keyboard.press("Home"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("head-1a"); + page.keyboard.press("ControlRight"); + await page.keyboard.press("End"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("cell-4b"); + + await page.$eval("calcite-table", () => { + const table = document.querySelector("calcite-table"); + const headerCell = document.getElementById("head-1a"); + + const pagination = table.shadowRoot.querySelector("calcite-pagination"); + const button = pagination.shadowRoot.querySelector("button.page:nth-of-type(4)"); + + button?.click(); + (headerCell as HTMLCalciteTableHeaderElement).setFocus(); + }); + + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("head-1a"); + await page.keyboard.press("ArrowRight"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("head-1b"); + await page.keyboard.press("PageDown"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("cell-5b"); + await page.keyboard.press("Home"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("cell-5a"); + await page.keyboard.press("PageUp"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("head-1a"); + await page.keyboard.press("PageUp"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("head-1a"); + await page.keyboard.press("ArrowDown"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("cell-5a"); + await page.keyboard.press("ArrowDown"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("cell-5a"); + await page.keyboard.press("ArrowDown"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("cell-5a"); + await page.keyboard.press("End"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("cell-5b"); + page.keyboard.press("ControlRight"); + await page.keyboard.press("Home"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("head-1a"); + page.keyboard.press("ControlRight"); + await page.keyboard.press("End"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("cell-5b"); + }); + + it("navigates correctly skipping disabled rows", async () => { + const page = await newE2EPage(); + await page.setContent( + html` + + + + + + cell + cell + + + cell + cell + + + cell + cell + + + cell + cell + + ` + ); + + await page.keyboard.press("Tab"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("head-1a"); + await page.keyboard.press("ArrowRight"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("head-1b"); + await page.keyboard.press("PageDown"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("cell-4b"); + await page.keyboard.press("Home"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("cell-4a"); + await page.keyboard.press("ArrowUp"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("cell-1a"); + await page.keyboard.press("End"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("cell-1b"); + await page.keyboard.press("ArrowDown"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("cell-4b"); + await page.keyboard.press("ArrowUp"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("cell-1b"); + }); + + it("navigates correctly skipping disabled rows when disabled rows in last body position", async () => { + const page = await newE2EPage(); + await page.setContent( + html` + + + + + + cell + cell + + + cell + cell + + + cell + cell + + + cell + cell + + ` + ); + + await page.keyboard.press("Tab"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("head-1a"); + await page.keyboard.press("ArrowRight"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("head-1b"); + await page.keyboard.press("PageDown"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("cell-3b"); + await page.keyboard.press("Home"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("cell-3a"); + await page.keyboard.press("ArrowUp"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("cell-1a"); + await page.keyboard.press("End"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("cell-1b"); + await page.keyboard.press("ArrowDown"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("cell-3b"); + await page.keyboard.press("ArrowDown"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("cell-3b"); + await page.keyboard.press("PageUp"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("head-1b"); + page.keyboard.press("ControlRight"); + await page.keyboard.press("End"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("cell-3b"); + }); + + it("navigates correctly when multiple header and multiple footer rows", async () => { + const page = await newE2EPage(); + await page.setContent( + html` + + + + + + + + + + + + cell + cell + + + cell + cell + + + cell + cell + + + cell + cell + + + foot + foot + foot + foot + + + foot + foot + + + >;` + ); + + await page.keyboard.press("Tab"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("head-1a"); + await page.keyboard.press("ArrowRight"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("head-1b"); + await page.keyboard.press("PageDown"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("foot-2b"); + await page.keyboard.press("Home"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("foot-2a"); + await page.keyboard.press("ArrowUp"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("foot-1a"); + await page.keyboard.press("ArrowUp"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("cell-4a"); + await page.keyboard.press("ArrowUp"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("cell-3a"); + await page.keyboard.press("ArrowUp"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("cell-2a"); + await page.keyboard.press("ArrowUp"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("cell-1a"); + await page.keyboard.press("ArrowUp"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("head-2a"); + await page.keyboard.press("End"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("head-2d"); + page.keyboard.press("ControlRight"); + await page.keyboard.press("End"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("foot-2b"); + await page.keyboard.press("PageUp"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("head-1b"); + await page.keyboard.press("ArrowDown"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("head-2b"); + await page.keyboard.press("ArrowDown"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("cell-1b"); + await page.keyboard.press("ArrowDown"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("cell-2b"); + page.keyboard.press("ControlRight"); + await page.keyboard.press("Home"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("head-1a"); + }); + + it("navigates correctly when multiple header and multiple footer rows, pagination present, and navigation to other page occurs", async () => { + const page = await newE2EPage(); + await page.setContent( + html` + + + + + + + + + + + + cell + cell + + + cell + cell + + + cell + cell + + + cell + cell + + + foot + foot + foot + foot + + + foot + foot + + + >;` + ); + + await page.keyboard.press("Tab"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("head-1a"); + await page.keyboard.press("ArrowRight"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("head-1b"); + await page.keyboard.press("PageDown"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("foot-2b"); + await page.keyboard.press("Home"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("foot-2a"); + await page.keyboard.press("ArrowUp"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("foot-1a"); + await page.keyboard.press("ArrowUp"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("cell-2a"); + await page.keyboard.press("ArrowUp"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("cell-1a"); + await page.keyboard.press("ArrowUp"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("head-2a"); + await page.keyboard.press("ArrowUp"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("head-1a"); + await page.keyboard.press("ArrowDown"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("head-2a"); + await page.keyboard.press("ArrowDown"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("cell-1a"); + await page.keyboard.press("ArrowUp"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("head-2a"); + await page.keyboard.press("End"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("head-2d"); + page.keyboard.press("ControlRight"); + await page.keyboard.press("End"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("foot-2b"); + await page.keyboard.press("Home"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("foot-2a"); + await page.keyboard.press("ArrowDown"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("foot-2a"); + await page.keyboard.press("ArrowUp"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("foot-1a"); + await page.keyboard.press("ArrowUp"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("cell-2a"); + await page.keyboard.press("ArrowUp"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("cell-1a"); + await page.keyboard.press("ArrowUp"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("head-2a"); + page.keyboard.press("ControlRight"); + await page.keyboard.press("Home"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("head-1a"); + page.keyboard.press("ControlRight"); + await page.keyboard.press("End"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("foot-2b"); + + await page.$eval("calcite-table", () => { + const table = document.querySelector("calcite-table"); + const headerCell = document.getElementById("head-1a"); + + const pagination = table.shadowRoot.querySelector("calcite-pagination"); + const button = pagination.shadowRoot.querySelector("button.page:nth-of-type(3)"); + + button?.click(); + (headerCell as HTMLCalciteTableHeaderElement).setFocus(); + }); + + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("head-1a"); + await page.keyboard.press("ArrowRight"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("head-1b"); + await page.keyboard.press("PageDown"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("foot-2b"); + await page.keyboard.press("Home"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("foot-2a"); + await page.keyboard.press("ArrowUp"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("foot-1a"); + await page.keyboard.press("ArrowUp"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("cell-4a"); + await page.keyboard.press("ArrowUp"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("cell-3a"); + await page.keyboard.press("ArrowUp"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("head-2a"); + await page.keyboard.press("ArrowDown"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("cell-3a"); + await page.keyboard.press("ArrowUp"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("head-2a"); + await page.keyboard.press("End"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("head-2d"); + page.keyboard.press("ControlRight"); + await page.keyboard.press("End"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("foot-2b"); + await page.keyboard.press("Home"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("foot-2a"); + await page.keyboard.press("ArrowDown"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("foot-2a"); + await page.keyboard.press("ArrowUp"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("foot-1a"); + await page.keyboard.press("ArrowUp"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("cell-4a"); + await page.keyboard.press("ArrowDown"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("foot-1a"); + await page.keyboard.press("ArrowDown"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("foot-2a"); + await page.keyboard.press("End"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("foot-2b"); + page.keyboard.press("ControlRight"); + await page.keyboard.press("Home"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("head-1a"); + await page.keyboard.press("ArrowDown"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("head-2a"); + await page.keyboard.press("ArrowDown"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("cell-3a"); + }); + + it("navigates correctly when selection column present", async () => { + const page = await newE2EPage(); + await page.setContent( + html` + + + + + + cell + cell + + + cell + cell + + + cell + cell + + + foot + foot + + ` + ); + + const rowHead = await page.find("#row-head"); + const rowFoot = await page.find("#row-foot"); + const row3 = await page.find("#row-3"); + + await page.keyboard.press("Tab"); + await page.waitForChanges(); + + expect( + await page.$eval(`#${rowHead.id}`, (el) => el.shadowRoot?.activeElement.shadowRoot?.querySelector("th").classList) + ).toEqual({ "0": CSS.selectionCell, "1": CSS.multipleSelectionCell }); + + await page.keyboard.press("ArrowRight"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("head-1a"); + + await page.keyboard.press("ArrowRight"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("head-1b"); + + await page.keyboard.press("Home"); + await page.waitForChanges(); + expect( + await page.$eval(`#${rowHead.id}`, (el) => el.shadowRoot?.activeElement.shadowRoot?.querySelector("th").classList) + ).toEqual({ "0": CSS.selectionCell, "1": CSS.multipleSelectionCell }); + + await page.keyboard.press("PageDown"); + await page.waitForChanges(); + expect( + await page.$eval(`#${rowFoot.id}`, (el) => el.shadowRoot?.activeElement.shadowRoot?.querySelector("td").classList) + ).toEqual({ "0": CELL_CSS.footerCell, "1": CSS.selectionCell }); + + await page.keyboard.press("ArrowUp"); + await page.waitForChanges(); + expect( + await page.$eval(`#${row3.id}`, (el) => el.shadowRoot?.activeElement.shadowRoot?.querySelector("td").classList) + ).toEqual({ "0": CSS.selectionCell }); + + await page.keyboard.press("ArrowRight"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("cell-3a"); + + page.keyboard.press("ControlRight"); + await page.keyboard.press("End"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("foot-1b"); + + page.keyboard.press("ControlLeft"); + await page.keyboard.press("Home"); + await page.waitForChanges(); + expect( + await page.$eval(`#${rowHead.id}`, (el) => el.shadowRoot?.activeElement.shadowRoot?.querySelector("th").classList) + ).toEqual({ "0": CSS.selectionCell, "1": CSS.multipleSelectionCell }); + }); + + it("navigates correctly when number column present", async () => { + const page = await newE2EPage(); + await page.setContent( + html` + + + + + + cell + cell + + + cell + cell + + + cell + cell + + + foot + foot + + ` + ); + + const rowHead = await page.find("#row-head"); + const rowFoot = await page.find("#row-foot"); + const row3 = await page.find("#row-3"); + + await page.keyboard.press("Tab"); + await page.waitForChanges(); + + expect( + await page.$eval(`#${rowHead.id}`, (el) => el.shadowRoot?.activeElement.shadowRoot?.querySelector("th").classList) + ).toEqual({ "0": CSS.numberCell }); + + await page.keyboard.press("ArrowRight"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("head-1a"); + + await page.keyboard.press("ArrowRight"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("head-1b"); + + await page.keyboard.press("Home"); + await page.waitForChanges(); + expect( + await page.$eval(`#${rowHead.id}`, (el) => el.shadowRoot?.activeElement.shadowRoot?.querySelector("th").classList) + ).toEqual({ "0": CSS.numberCell }); + + await page.keyboard.press("PageDown"); + await page.waitForChanges(); + expect( + await page.$eval(`#${rowFoot.id}`, (el) => el.shadowRoot?.activeElement.shadowRoot?.querySelector("td").classList) + ).toEqual({ "0": CELL_CSS.footerCell, "1": CSS.numberCell }); + + await page.keyboard.press("ArrowUp"); + await page.waitForChanges(); + expect( + await page.$eval(`#${row3.id}`, (el) => el.shadowRoot?.activeElement.shadowRoot?.querySelector("td").classList) + ).toEqual({ "0": CSS.numberCell }); + + await page.keyboard.press("ArrowRight"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("cell-3a"); + + page.keyboard.press("ControlRight"); + await page.keyboard.press("End"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("foot-1b"); + + page.keyboard.press("ControlLeft"); + await page.keyboard.press("Home"); + await page.waitForChanges(); + expect( + await page.$eval(`#${rowHead.id}`, (el) => el.shadowRoot?.activeElement.shadowRoot?.querySelector("th").classList) + ).toEqual({ "0": CSS.numberCell }); + }); + + it("navigates correctly when number and selection column present numbered", async () => { + const page = await newE2EPage(); + await page.setContent( + html` + + + + + + cell + cell + + + cell + cell + + + cell + cell + + + foot + foot + + ` + ); + + const rowHead = await page.find("#row-head"); + const rowFoot = await page.find("#row-foot"); + const row3 = await page.find("#row-3"); + + await page.keyboard.press("Tab"); + await page.waitForChanges(); + + expect( + await page.$eval(`#${rowHead.id}`, (el) => el.shadowRoot?.activeElement.shadowRoot?.querySelector("th").classList) + ).toEqual({ "0": CSS.numberCell }); + + await page.keyboard.press("ArrowRight"); + await page.waitForChanges(); + + expect( + await page.$eval(`#${rowHead.id}`, (el) => el.shadowRoot?.activeElement.shadowRoot?.querySelector("th").classList) + ).toEqual({ "0": CSS.selectionCell }); + + await page.keyboard.press("ArrowRight"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("head-1a"); + + await page.keyboard.press("ArrowLeft"); + await page.waitForChanges(); + expect( + await page.$eval(`#${rowHead.id}`, (el) => el.shadowRoot?.activeElement.shadowRoot?.querySelector("th").classList) + ).toEqual({ "0": CSS.selectionCell }); + + await page.keyboard.press("PageDown"); + await page.waitForChanges(); + expect( + await page.$eval(`#${rowFoot.id}`, (el) => el.shadowRoot?.activeElement.shadowRoot?.querySelector("td").classList) + ).toEqual({ "0": CELL_CSS.footerCell, "1": CSS.selectionCell }); + + await page.keyboard.press("ArrowUp"); + await page.waitForChanges(); + expect( + await page.$eval(`#${row3.id}`, (el) => el.shadowRoot?.activeElement.shadowRoot?.querySelector("td").classList) + ).toEqual({ "0": CSS.selectionCell }); + + await page.keyboard.press("ArrowLeft"); + await page.waitForChanges(); + expect( + await page.$eval(`#${row3.id}`, (el) => el.shadowRoot?.activeElement.shadowRoot?.querySelector("td").classList) + ).toEqual({ "0": CSS.numberCell }); + + await page.keyboard.press("ArrowRight"); + await page.waitForChanges(); + await page.keyboard.press("ArrowRight"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("cell-3a"); + + page.keyboard.press("ControlRight"); + await page.keyboard.press("Home"); + await page.waitForChanges(); + expect( + await page.$eval(`#${rowHead.id}`, (el) => el.shadowRoot?.activeElement.shadowRoot?.querySelector("th").classList) + ).toEqual({ "0": CSS.numberCell }); + }); + + it("navigates correctly when pagination present and selection and number and first page displayed", async () => { + const page = await newE2EPage(); + await page.setContent( + html` + + + + + + cell + cell + + + cell + cell + + + cell + cell + + + cell + cell + + + foot + foot + + ` + ); + + const rowHead = await page.find("#row-head"); + const rowFoot = await page.find("#row-foot"); + const row2 = await page.find("#row-2"); + + await page.keyboard.press("Tab"); + await page.waitForChanges(); + + expect( + await page.$eval(`#${rowHead.id}`, (el) => el.shadowRoot?.activeElement.shadowRoot?.querySelector("th").classList) + ).toEqual({ "0": CSS.numberCell }); + + await page.keyboard.press("ArrowRight"); + await page.waitForChanges(); + + expect( + await page.$eval(`#${rowHead.id}`, (el) => el.shadowRoot?.activeElement.shadowRoot?.querySelector("th").classList) + ).toEqual({ "0": CSS.selectionCell, "1": CSS.multipleSelectionCell }); + + await page.keyboard.press("ArrowRight"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("head-1a"); + + await page.keyboard.press("ArrowLeft"); + await page.waitForChanges(); + expect( + await page.$eval(`#${rowHead.id}`, (el) => el.shadowRoot?.activeElement.shadowRoot?.querySelector("th").classList) + ).toEqual({ "0": CSS.selectionCell, "1": CSS.multipleSelectionCell }); + + await page.keyboard.press("PageDown"); + await page.waitForChanges(); + expect( + await page.$eval(`#${rowFoot.id}`, (el) => el.shadowRoot?.activeElement.shadowRoot?.querySelector("td").classList) + ).toEqual({ "0": CELL_CSS.footerCell, "1": CSS.selectionCell }); + + await page.keyboard.press("ArrowUp"); + await page.waitForChanges(); + expect( + await page.$eval(`#${row2.id}`, (el) => el.shadowRoot?.activeElement.shadowRoot?.querySelector("td").classList) + ).toEqual({ "0": CSS.selectionCell }); + + await page.keyboard.press("ArrowRight"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("cell-2a"); + + page.keyboard.press("ControlRight"); + await page.keyboard.press("End"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("foot-1b"); + + await page.keyboard.press("Home"); + await page.waitForChanges(); + expect( + await page.$eval(`#${rowFoot.id}`, (el) => el.shadowRoot?.activeElement.shadowRoot?.querySelector("td").classList) + ).toEqual({ "0": CELL_CSS.footerCell, "1": CSS.numberCell }); + + page.keyboard.press("ControlLeft"); + await page.keyboard.press("Home"); + await page.waitForChanges(); + expect( + await page.$eval(`#${rowHead.id}`, (el) => el.shadowRoot?.activeElement.shadowRoot?.querySelector("th").classList) + ).toEqual({ "0": CSS.numberCell }); + }); + + it("navigates correctly when pagination present, and selection and number and navigation to two other pages occurs", async () => { + const page = await newE2EPage(); + await page.setContent( + html` + + + + + + cell + cell + + + cell + cell + + + cell + cell + + + cell + cell + + + foot + foot + + ` + ); + + const rowHead = await page.find("#row-head"); + const rowFoot = await page.find("#row-foot"); + const row1 = await page.find("#row-1"); + const row2 = await page.find("#row-2"); + const row3 = await page.find("#row-3"); + const row4 = await page.find("#row-4"); + + await page.keyboard.press("Tab"); + await page.waitForChanges(); + + expect( + await page.$eval(`#${rowHead.id}`, (el) => el.shadowRoot?.activeElement.shadowRoot?.querySelector("th").classList) + ).toEqual({ "0": CSS.numberCell }); + + await page.keyboard.press("ArrowRight"); + await page.waitForChanges(); + + expect( + await page.$eval(`#${rowHead.id}`, (el) => el.shadowRoot?.activeElement.shadowRoot?.querySelector("th").classList) + ).toEqual({ "0": CSS.selectionCell }); + + await page.keyboard.press("ArrowRight"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("head-1a"); + + await page.keyboard.press("ArrowLeft"); + await page.waitForChanges(); + expect( + await page.$eval(`#${rowHead.id}`, (el) => el.shadowRoot?.activeElement.shadowRoot?.querySelector("th").classList) + ).toEqual({ "0": CSS.selectionCell }); + + await page.keyboard.press("ArrowDown"); + await page.waitForChanges(); + expect( + await page.$eval(`#${row1.id}`, (el) => el.shadowRoot?.activeElement.shadowRoot?.querySelector("td").classList) + ).toEqual({ "0": CSS.selectionCell }); + + await page.keyboard.press("ArrowLeft"); + await page.waitForChanges(); + expect( + await page.$eval(`#${row1.id}`, (el) => el.shadowRoot?.activeElement.shadowRoot?.querySelector("td").classList) + ).toEqual({ "0": CSS.numberCell }); + + await page.keyboard.press("PageDown"); + await page.waitForChanges(); + expect( + await page.$eval(`#${rowFoot.id}`, (el) => el.shadowRoot?.activeElement.shadowRoot?.querySelector("td").classList) + ).toEqual({ "0": CELL_CSS.footerCell, "1": CSS.numberCell }); + + await page.keyboard.press("ArrowUp"); + await page.waitForChanges(); + expect( + await page.$eval(`#${row2.id}`, (el) => el.shadowRoot?.activeElement.shadowRoot?.querySelector("td").classList) + ).toEqual({ "0": CSS.numberCell }); + + await page.keyboard.press("ArrowRight"); + await page.waitForChanges(); + expect( + await page.$eval(`#${row2.id}`, (el) => el.shadowRoot?.activeElement.shadowRoot?.querySelector("td").classList) + ).toEqual({ "0": CSS.selectionCell }); + + page.keyboard.press("ControlRight"); + await page.keyboard.press("End"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("foot-1b"); + + await page.keyboard.press("Home"); + await page.waitForChanges(); + expect( + await page.$eval(`#${rowFoot.id}`, (el) => el.shadowRoot?.activeElement.shadowRoot?.querySelector("td").classList) + ).toEqual({ "0": CELL_CSS.footerCell, "1": CSS.numberCell }); + + page.keyboard.press("ControlRight"); + + await page.keyboard.press("Home"); + await page.waitForChanges(); + expect( + await page.$eval(`#${rowHead.id}`, (el) => el.shadowRoot?.activeElement.shadowRoot?.querySelector("th").classList) + ).toEqual({ "0": CSS.numberCell }); + + await page.$eval("calcite-table", () => { + const table = document.querySelector("calcite-table"); + const headerCell = document.getElementById("head-1a"); + + const pagination = table.shadowRoot.querySelector("calcite-pagination"); + const button = pagination.shadowRoot.querySelector("button.page:nth-of-type(3)"); + button?.click(); + (headerCell as HTMLCalciteTableHeaderElement).setFocus(); + }); + + await page.waitForChanges(); + + await page.keyboard.press("ArrowRight"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("head-1b"); + + await page.keyboard.press("Home"); + await page.waitForChanges(); + expect( + await page.$eval(`#${rowHead.id}`, (el) => el.shadowRoot?.activeElement.shadowRoot?.querySelector("th").classList) + ).toEqual({ "0": CSS.numberCell }); + + await page.keyboard.press("ArrowDown"); + await page.waitForChanges(); + expect( + await page.$eval(`#${row3.id}`, (el) => el.shadowRoot?.activeElement.shadowRoot?.querySelector("td").classList) + ).toEqual({ "0": CSS.numberCell }); + + await page.keyboard.press("ArrowRight"); + await page.waitForChanges(); + expect( + await page.$eval(`#${row3.id}`, (el) => el.shadowRoot?.activeElement.shadowRoot?.querySelector("td").classList) + ).toEqual({ "0": CSS.selectionCell }); + + await page.keyboard.press("PageDown"); + await page.waitForChanges(); + expect( + await page.$eval(`#${rowFoot.id}`, (el) => el.shadowRoot?.activeElement.shadowRoot?.querySelector("td").classList) + ).toEqual({ "0": CELL_CSS.footerCell, "1": CSS.selectionCell }); + + await page.keyboard.press("ArrowUp"); + await page.waitForChanges(); + expect( + await page.$eval(`#${row4.id}`, (el) => el.shadowRoot?.activeElement.shadowRoot?.querySelector("td").classList) + ).toEqual({ "0": CSS.selectionCell }); + + await page.keyboard.press("ArrowLeft"); + await page.waitForChanges(); + expect( + await page.$eval(`#${row4.id}`, (el) => el.shadowRoot?.activeElement.shadowRoot?.querySelector("td").classList) + ).toEqual({ "0": CSS.numberCell }); + + page.keyboard.press("ControlRight"); + await page.keyboard.press("End"); + await page.waitForChanges(); + expect(await getFocusedElementProp(page, "id")).toBe("foot-1b"); + + await page.keyboard.press("Home"); + await page.waitForChanges(); + expect( + await page.$eval(`#${rowFoot.id}`, (el) => el.shadowRoot?.activeElement.shadowRoot?.querySelector("td").classList) + ).toEqual({ "0": CELL_CSS.footerCell, "1": CSS.numberCell }); + }); +}); + +// Borrowed from Dropdown until a generic utility is set up. +interface SelectedItemsAssertionOptions { + /** + * IDs from items to assert selection + */ + expectedItemIds: string[]; +} + +/** + * Test helper for selected calcite-table-row items. Expects items to have IDs to test against. + * + * Note: assertSelectedItems.setUpEvents must be called before using this method + * + * @param page + * @param root0 + * @param root0.expectedItemIds + */ +async function assertSelectedItems(page: E2EPage, { expectedItemIds }: SelectedItemsAssertionOptions): Promise { + await page.waitForTimeout(100); + const selectedItemIds = await page.evaluate(() => { + const table = document.querySelector("calcite-table"); + return table.selectedItems.map((item) => item.id); + }); + + expect(selectedItemIds).toHaveLength(expectedItemIds.length); + + expectedItemIds.forEach((itemId, index) => expect(selectedItemIds[index]).toEqual(itemId)); +} + +type SelectionEventTestWindow = GlobalTestProps<{ eventDetail: Selection }>; + +/** + * Helper to wire up the page to assert on the event detail + * + * @param page + */ +assertSelectedItems.setUpEvents = async (page: E2EPage) => { + await page.evaluate(() => { + document.addEventListener("calciteTableSelect", ({ detail }: CustomEvent) => { + (window as SelectionEventTestWindow).eventDetail = detail; + }); + }); +}; diff --git a/packages/calcite-components/src/components/table/table.scss b/packages/calcite-components/src/components/table/table.scss new file mode 100644 index 00000000000..9e69391bfa0 --- /dev/null +++ b/packages/calcite-components/src/components/table/table.scss @@ -0,0 +1,92 @@ +:host([scale="s"]) { + --calcite-internal-table-cell-padding: 0.25rem; + --calcite-internal-table-cell-font-size: var(--calcite-font-size--2); + --calcite-internal-table-cell-font-size-secondary: var(--calcite-font-size--3); +} +:host([scale="m"]) { + --calcite-internal-table-cell-padding: 0.5rem; + --calcite-internal-table-cell-font-size: var(--calcite-font-size--1); + --calcite-internal-table-cell-font-size-secondary: var(--calcite-font-size--2); +} +:host([scale="l"]) { + --calcite-internal-table-cell-padding: 1rem; + --calcite-internal-table-cell-font-size: var(--calcite-font-size-0); + --calcite-internal-table-cell-font-size-secondary: var(--calcite-font-size--1); +} + +:host { + @apply table; +} + +.container { + max-inline-size: 100vw; + inline-size: 100%; +} + +.table-container { + @apply overflow-x-scroll whitespace-nowrap; +} + +.table-container:not(.bordered) { + border-block-end: 1px solid var(--calcite-ui-border-3); +} + +.assistive-text { + @apply sr-only; +} + +table { + @apply w-full border-collapse; + overflow-x: scroll; + border-block-start: 1px solid var(--calcite-ui-border-3); + border-inline-start: 1px solid var(--calcite-ui-border-3); + border-block-end: 1px solid var(--calcite-ui-border-3); +} + +tbody { + border-block-end: 1px solid var(--calcite-ui-border-3); +} + +.table--fixed { + @apply table-fixed; +} + +.bordered { + ::slotted(calcite-table-row) { + --calcite-table-row-border-color: var(--calcite-ui-border-3); + } +} + +.zebra { + ::slotted(calcite-table-row:nth-child(2n + 1)) { + --calcite-table-row-background: var(--calcite-ui-foreground-2); + } +} +.selection-actions { + @apply flex flex-row; + margin-inline-start: auto; +} + +.selection-area { + @apply flex flex-row items-center; + padding-block: var(--calcite-internal-table-cell-padding); +} + +.selection-area calcite-chip:last-of-type { + @apply me-2; +} + +.selection-area calcite-chip:last-of-type:not(:first-of-type) { + @apply ms-2; +} + +.selection-area calcite-button { + @apply me-4; +} + +.pagination-area { + @apply flex flex-row w-full justify-center; + padding-block: var(--calcite-internal-table-cell-padding); +} + +@include base-component(); diff --git a/packages/calcite-components/src/components/table/table.stories.ts b/packages/calcite-components/src/components/table/table.stories.ts new file mode 100644 index 00000000000..cf2fdd79ab1 --- /dev/null +++ b/packages/calcite-components/src/components/table/table.stories.ts @@ -0,0 +1,912 @@ +import { storyFilters, boolean } from "../../../.storybook/helpers"; +import readme from "./readme.md"; +import { html } from "../../../support/formatting"; +import { modesDarkDefault } from "../../../.storybook/utils"; +import { number, select, text } from "@storybook/addon-knobs"; + +export default { + title: "Components/Table", + parameters: { + notes: readme, + }, + ...storyFilters(), +}; + +export const simple = (): string => + html` + + + + + + + + cell + cell + cell + cell + + + cell + cell + cell + cell + + + cell + cell + cell + cell + + `; + +export const simpleZebra_TestOnly = (): string => html` + + + + + + + + cell + cell + cell + cell + + + cell + cell + cell + cell + + + cell + cell + cell + cell + +`; + +export const bordered_TestOnly = (): string => html` + + + + + + + + cell + cell + cell + cell + + + cell + cell + cell + cell + + + cell + cell + cell + cell + +`; + +export const borderedZebra_TestOnly = (): string => html` + + + + + + + + cell + cell + cell + cell + + + cell + cell + cell + cell + + + cell + cell + cell + cell + +`; + +export const alignments_TestOnly = (): string => html` + + + + + + + + cell + cell + cell + cell + + + cell + cell + cell + cell + + + cell + cell + cell + cell + +`; + +export const disabledRows_TestOnly = (): string => html` + + + + + + + + cell + cell + cell + cell + + + cell + cell + cell + cell + + + cell + cell + cell + cell + +`; + +export const numbered_TestOnly = (): string => html` + + + + + + + + cell + cell + cell + cell + + + cell + cell + cell + cell + + + cell + cell + cell + cell + +`; + +export const richCellContent_TestOnly = (): string => html` + + + + + + + + + Chip + + cell + + + cell + + Chipbutton + chip + + + cell + chip + + chipchip + +`; + +export const layoutFixed_TestOnly = (): string => html` + + + + + + + + cell + cell + cell + cell + + + cell + cell + cell + cell + + + cell + cell + cell + cell + +`; + +export const rowSpanAndColSpan_TestOnly = (): string => html` + + + + + + cell + cell + + + cell + cell + + + cell + cell + cell + cell + cell + + + cell + cell + cell + cell + cell + cell + + + cell + cell + cell + cell + +`; + +export const rowSpanAndColSpanNumbered_TestOnly = (): string => html` + + + + + + cell + cell + + + cell + cell + + + cell + cell + cell + cell + cell + + + cell + cell + cell + cell + cell + cell + + + cell + cell + cell + cell + +`; + +export const rowSpanAndColSpan3_TestOnly = (): string => html` + + + + + + cell + cell + + + cell + cell + + + cell + cell + + + cell + cell + cell + + + cell + cell + cell + + + cell + cell + + + cell + cell + + + cell + cell + +`; + +export const complexWithFooter_TestOnly = (): string => html` + + + + + + + + + + + + cell + cell + + + cell + cell + + + cell + cell + + + cell + cell + cell + + + cell + cell + cell + + + cell + cell + + + cell + cell + + + cell + cell + + + foot + foot + foot + foot + + + foot + foot + +`; + +export const headersInRows_TestOnly = (): string => html` + + + cell + cell + cell + + + + cell + cell + cell + + + + cell + cell + cell + + + + cell + cell + cell + +`; + +export const headersInRowsAndHeadAndFooter_TestOnly = (): string => html` + + + + + + + + + cell + cell + cell + + + + cell + cell + cell + + + + cell + cell + cell + + + + cell + cell + cell + + + foot + foot + foot + foot + +`; + +export const singleSelection_TestOnly = (): string => html` + + + + + + + + + + + + cell + cell + cell + cell + + + cell + cell + cell + cell + + + cell + cell + cell + cell + +`; + +export const selectionModeMultipleAndSelectedOnLoad_TestOnly = (): string => html` + + + + + + + + + + + + cell + cell + cell + cell + + + cell + cell + cell + cell + + + cell + cell + cell + cell + + + cell + cell + cell + cell + + + cell + cell + cell + cell + + + cell + cell + cell + cell + + + cell + cell + cell + cell + + + cell + cell + cell + cell + +`; + +export const selectionModeMultipleAndSelectedOnLoadWithMultipleFooterAndHeader_TestOnly = + (): string => html` + + + + + + + + + + + + + + + + cell + cell + cell + cell + + + cell + cell + cell + cell + + + cell + cell + cell + cell + + + cell + cell + cell + cell + + + cell + cell + cell + cell + + + cell + cell + cell + cell + + + cell + cell + cell + cell + + + cell + cell + cell + cell + + + + 58% happiness + + + + 24,212 + 58% happiness + + + `; + +export const localized_TestOnly = (): string => html` + + + + + + + + + slot + + + + + + + + + cell + cell + cell + cell + cell + 34 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + 53 + Happy + + Another thing + + cell + cell + cell + cell + cell + 25 + Happy + + Another thing + + cell + cell + cell + cell + cell + 63 + Happy + + Another thing + + cell + cell + cell + cell + cell + 1643 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + 63 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + 62 + Happy + + Another thing + + cell + cell + cell + cell + cell + 6 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + 262 + Sad + + Another thing + + + + cell + cell + cell + cell + cell + 63 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + 120 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + 987 + Happy + + Another thing + + +`; + +export const darkModeRTL_TestOnly = (): string => + html` + + + + + + + + cell + cell + cell + cell + + + cell + cell + cell + cell + + + cell + cell + cell + cell + + `; + +darkModeRTL_TestOnly.parameters = { modes: modesDarkDefault }; diff --git a/packages/calcite-components/src/components/table/table.tsx b/packages/calcite-components/src/components/table/table.tsx new file mode 100644 index 00000000000..cebaa86c466 --- /dev/null +++ b/packages/calcite-components/src/components/table/table.tsx @@ -0,0 +1,525 @@ +import { + Component, + Element, + Event, + EventEmitter, + h, + Host, + Listen, + Prop, + State, + VNode, + Watch, +} from "@stencil/core"; +import { Scale, SelectionMode } from "../interfaces"; +import { + LoadableComponent, + setComponentLoaded, + setUpLoadableComponent, +} from "../../utils/loadable"; +import { + connectMessages, + disconnectMessages, + setUpMessages, + T9nComponent, + updateMessages, +} from "../../utils/t9n"; +import { + connectLocalized, + disconnectLocalized, + LocalizedComponent, + numberStringFormatter, + NumberingSystem, +} from "../../utils/locale"; +import { TableLayout, TableRowFocusEvent } from "./interfaces"; +import { CSS, SLOTS } from "./resources"; +import { TableMessages } from "./assets/table/t9n"; +import { getUserAgentString } from "../../utils/browser"; + +/** + * @slot - A slot for adding `calcite-table-row` or nested `calcite-table` elements. + * @slot table-header - A slot for adding `calcite-table-row` containing `calcite-table-header` elements. + * @slot table-footer - A slot for adding `calcite-table-row` containing `calcite-table-cell` or `calcite-table-header` elements. + * @slot selection-actions - A slot for adding a `calcite-action-bar` or other components to display when `selectionMode` is not `"none"` and one or more `calcite-table-row` is selected. + */ + +@Component({ + tag: "calcite-table", + styleUrl: "table.scss", + shadow: true, + assetsDirs: ["assets"], +}) +export class Table implements LocalizedComponent, LoadableComponent, T9nComponent { + //-------------------------------------------------------------------------- + // + // Properties + // + //-------------------------------------------------------------------------- + + /** When `true`, displays borders in the component. */ + @Prop({ reflect: true }) bordered = false; + + /** Specifies an accessible title for the component. */ + @Prop() caption!: string; + + /** When `true`, number values are displayed with a group separator corresponding to the language and country format. */ + @Prop({ reflect: true }) groupSeparator = false; + + /** Specifies the layout of the component. */ + @Prop({ reflect: true }) layout: TableLayout = "auto"; + + /** When `true`, displays the position of the row in numeric form. */ + @Prop({ reflect: true }) numbered = false; + + /** Specifies the Unicode numeral system used by the component for localization. */ + @Prop({ reflect: true }) numberingSystem?: NumberingSystem; + + /** Specifies the page size of the component. When `true`, renders `calcite-pagination` */ + @Prop({ reflect: true }) pageSize = 0; + + /** Specifies the size of the component. */ + @Prop({ reflect: true }) scale: Scale = "m"; + + /** Specifies the selection mode of the component. */ + @Prop({ reflect: true }) selectionMode: Extract<"none" | "multiple" | "single", SelectionMode> = + "none"; + + /** When `true`, displays zebra styling in the component. */ + @Prop({ reflect: true }) zebra = false; + + @Watch("groupSeparator") + @Watch("numbered") + @Watch("numberingSystem") + @Watch("pageSize") + @Watch("scale") + @Watch("selectionMode") + handleNumberedChange(): void { + this.updateRows(); + } + + /** + * Specifies the component's selected items. + * + * @readonly + */ + @Prop({ mutable: true }) selectedItems: HTMLCalciteTableRowElement[] = []; + + /** + * Made into a prop for testing purposes only + * + * @internal + */ + // eslint-disable-next-line @stencil-community/strict-mutable -- updated by t9n module + @Prop({ mutable: true }) messages: TableMessages; + + /** + * Use this property to override individual strings used by the component. + */ + // eslint-disable-next-line @stencil-community/strict-mutable -- updated by t9n module + @Prop({ mutable: true }) messageOverrides: Partial; + + @Watch("messageOverrides") + onMessagesChange(): void { + /* wired up by t9n util */ + } + + // -------------------------------------------------------------------------- + // + // Private Properties + // + // -------------------------------------------------------------------------- + + @Element() el: HTMLCalciteTableElement; + + @State() colCount = 0; + + @State() pageStartRow = 1; + + @State() selectedCount = 0; + + /* Workaround for Safari https://bugs.webkit.org/show_bug.cgi?id=258430 https://bugs.webkit.org/show_bug.cgi?id=239478 */ + // ⚠️ browser-sniffing is not a best practice and should be avoided ⚠️ + @State() readCellContentsToAT: boolean; + + @State() defaultMessages: TableMessages; + + @State() effectiveLocale = ""; + + @Watch("effectiveLocale") + effectiveLocaleChange(): void { + updateMessages(this, this.effectiveLocale); + } + + private allRows: HTMLCalciteTableRowElement[]; + + private bodyRows: HTMLCalciteTableRowElement[]; + + private headRows: HTMLCalciteTableRowElement[]; + + private footRows: HTMLCalciteTableRowElement[]; + + private paginationEl: HTMLCalcitePaginationElement; + + private tableBodySlotEl: HTMLSlotElement; + + private tableHeadSlotEl: HTMLSlotElement; + + private tableFootSlotEl: HTMLSlotElement; + + //-------------------------------------------------------------------------- + // + // Lifecycle + // + //-------------------------------------------------------------------------- + + async componentWillLoad(): Promise { + setUpLoadableComponent(this); + await setUpMessages(this); + this.readCellContentsToAT = /safari/i.test(getUserAgentString()); + this.updateRows(); + } + + componentDidLoad(): void { + setComponentLoaded(this); + } + + connectedCallback(): void { + connectLocalized(this); + connectMessages(this); + } + + disconnectedCallback(): void { + disconnectLocalized(this); + disconnectMessages(this); + } + //-------------------------------------------------------------------------- + // + // Events + // + //-------------------------------------------------------------------------- + + /** Emits when the component's selected rows change. */ + @Event({ cancelable: false }) calciteTableSelect: EventEmitter; + + /** Emits when the component's page selection changes. */ + @Event({ cancelable: false }) calciteTablePageChange: EventEmitter; + + /** @internal */ + @Event({ cancelable: false }) + calciteInternalTableRowFocusChange: EventEmitter; + + //-------------------------------------------------------------------------- + // + // Event Listeners + // + //-------------------------------------------------------------------------- + + @Listen("calciteTableRowSelect") + calciteChipSelectListener(event: CustomEvent): void { + if (event.composedPath().includes(this.el)) { + this.setSelectedItems(event.target as HTMLCalciteTableRowElement); + } + } + + @Listen("calciteInternalTableRowFocusRequest") + calciteInternalTableRowFocusEvent(event: TableRowFocusEvent): void { + const cellPosition = event["detail"].cellPosition; + const rowPos = event["detail"].rowPosition; + const destination = event["detail"].destination; + const lastCell = event["detail"].lastCell; + + const visibleBody = this.bodyRows?.filter((row) => !row.hidden); + const visibleAll = this.allRows?.filter((row) => !row.hidden); + + const lastHeadRow = this.headRows[this.headRows.length - 1]?.positionAll; + const firstBodyRow = visibleBody[0]?.positionAll; + const lastBodyRow = visibleBody[visibleBody.length - 1]?.positionAll; + const firstFootRow = this.footRows[0]?.positionAll; + const lastTableRow = visibleAll[visibleAll.length - 1]?.positionAll; + + const leavingHeader = destination === "next" && rowPos === lastHeadRow; + const leavingFooter = destination === "previous" && rowPos === firstFootRow; + const enteringHeader = destination === "previous" && rowPos === firstBodyRow; + const enteringFooter = destination === "next" && rowPos === lastBodyRow; + + let rowPosition: number; + + switch (destination) { + case "first": + rowPosition = 0; + break; + case "last": + rowPosition = lastTableRow; + break; + case "next": + rowPosition = leavingHeader ? firstBodyRow : enteringFooter ? firstFootRow : rowPos + 1; + break; + case "previous": + rowPosition = leavingFooter ? lastBodyRow : enteringHeader ? lastHeadRow : rowPos - 1; + break; + } + + const destinationCount = this.allRows?.find( + (row) => row.positionAll === rowPosition + )?.cellCount; + + const adjustedPos = cellPosition > destinationCount ? destinationCount : cellPosition; + + if (rowPosition !== undefined) { + this.calciteInternalTableRowFocusChange.emit({ + cellPosition: adjustedPos, + rowPosition, + destination, + lastCell, + }); + } + } + // -------------------------------------------------------------------------- + // + // Private Methods + // + // -------------------------------------------------------------------------- + + private getSlottedRows = (el: HTMLSlotElement): HTMLCalciteTableRowElement[] => { + return el + ?.assignedElements({ flatten: true }) + ?.filter((el) => el?.matches("calcite-table-row")) as HTMLCalciteTableRowElement[]; + }; + + private updateRows = (): void => { + const headRows = this.getSlottedRows(this.tableHeadSlotEl) || []; + const bodyRows = this.getSlottedRows(this.tableBodySlotEl) || []; + const footRows = this.getSlottedRows(this.tableFootSlotEl) || []; + const allRows = [...headRows, ...bodyRows, ...footRows]; + + headRows?.forEach((row) => { + const position = headRows?.indexOf(row); + row.rowType = "head"; + row.positionSection = position; + row.positionSectionLocalized = this.localizeNumber((position + 1).toString()); + }); + + bodyRows?.forEach((row) => { + const position = bodyRows?.indexOf(row); + row.rowType = "body"; + row.positionSection = position; + row.positionSectionLocalized = this.localizeNumber((position + 1).toString()); + }); + + footRows?.forEach((row) => { + const position = footRows?.indexOf(row); + row.rowType = "foot"; + row.positionSection = position; + row.positionSectionLocalized = this.localizeNumber((position + 1).toString()); + }); + + allRows?.forEach((row) => { + row.selectionMode = this.selectionMode; + row.bodyRowCount = bodyRows?.length; + row.positionAll = allRows?.indexOf(row); + row.numbered = this.numbered; + row.scale = this.scale; + row.readCellContentsToAT = this.readCellContentsToAT; + }); + + const colCount = + headRows[0]?.cellCount || headRows[0]?.querySelectorAll("calcite-table-header")?.length; + + this.colCount = colCount; + this.headRows = headRows; + this.bodyRows = bodyRows; + this.footRows = footRows; + this.allRows = allRows; + + this.updateSelectedItems(); + this.paginateRows(); + }; + + private handlePaginationChange = (): void => { + const requestedItem = this.paginationEl?.startItem; + this.pageStartRow = requestedItem || 1; + this.calciteTablePageChange.emit(); + this.updateRows(); + }; + + private paginateRows = (): void => { + this.bodyRows?.forEach((row) => { + const rowPos = row.positionSection + 1; + const inView = rowPos >= this.pageStartRow && rowPos < this.pageStartRow + this.pageSize; + row.hidden = this.pageSize > 0 && !inView && !this.footRows.includes(row); + }); + }; + + private updateSelectedItems = (emit?: boolean): void => { + const selectedItems = this.bodyRows?.filter((el) => el.selected); + this.selectedItems = selectedItems; + this.selectedCount = selectedItems?.length; + this.allRows?.forEach((row) => { + row.selectedRowCount = this.selectedCount; + row.selectedRowCountLocalized = this.localizeNumber(this.selectedCount); + }); + if (emit) { + this.calciteTableSelect.emit(); + } + }; + + private handleDeselectAllRows = (): void => { + this.bodyRows?.forEach((row) => { + row.selected = false; + }); + this.updateSelectedItems(true); + }; + + private setSelectedItems = (elToMatch?: HTMLCalciteTableRowElement): void => { + this.bodyRows?.forEach((el) => { + if (elToMatch?.rowType === "head") { + el.selected = this.selectedCount !== this.bodyRows?.length; + } else { + el.selected = + elToMatch === el ? !el.selected : this.selectionMode === "multiple" ? el.selected : false; + } + }); + this.updateSelectedItems(true); + }; + + private localizeNumber = (value: number | string): string => { + numberStringFormatter.numberFormatOptions = { + locale: this.effectiveLocale, + numberingSystem: this.numberingSystem, + useGrouping: this.groupSeparator, + }; + + return numberStringFormatter.localize(value.toString()); + }; + + // -------------------------------------------------------------------------- + // + // Render Methods + // + // -------------------------------------------------------------------------- + + renderSelectionArea(): VNode { + const outOfViewCount = this.selectedItems?.filter((el) => el.hidden)?.length; + const localizedOutOfView = this.localizeNumber(outOfViewCount?.toString()); + const localizedSelectedCount = this.localizeNumber(this.selectedCount?.toString()); + const selectionText = `${localizedSelectedCount} ${this.messages.selected}`; + const outOfView = `${localizedOutOfView} ${this.messages.hiddenSelected}`; + + return ( +
+ 0 ? "brand" : "neutral"} + scale={this.scale} + value={selectionText} + > + {selectionText} + + {outOfViewCount > 0 && ( + + {localizedOutOfView} + + )} + {this.selectedCount > 0 && ( + + {this.messages.clear} + + )} +
+ +
+
+ ); + } + + renderPaginationArea(): VNode { + return ( +
+ (this.paginationEl = el)} + /> +
+ ); + } + + renderTHead(): VNode { + return ( + + (this.tableHeadSlotEl = el as HTMLSlotElement)} + /> + + ); + } + + renderTBody(): VNode { + return ( + + (this.tableBodySlotEl = el as HTMLSlotElement)} + /> + + ); + } + + renderTFoot(): VNode { + return ( + + (this.tableFootSlotEl = el as HTMLSlotElement)} + /> + + ); + } + + render(): VNode { + return ( + +
+ {this.selectionMode !== "none" && this.renderSelectionArea()} +
+ + + {this.renderTHead()} + {this.renderTBody()} + {this.renderTFoot()} +
{this.caption}
+
+ {this.pageSize > 0 && this.renderPaginationArea()} +
+
+ ); + } +} diff --git a/packages/calcite-components/src/components/table/usage/Advanced.md b/packages/calcite-components/src/components/table/usage/Advanced.md new file mode 100644 index 00000000000..1fe9eb68b24 --- /dev/null +++ b/packages/calcite-components/src/components/table/usage/Advanced.md @@ -0,0 +1,70 @@ +A complex table component, with selection modes and slotted actions, pagination, and various display options configured. + +```html + + + + + + + + + + + + + cell + cell + cell + cell + + + cell + cell + cell + cell + + + cell + cell + cell + cell + + + cell + cell + cell + cell + + + cell + cell + cell + cell + + + cell + cell + cell + cell + + + cell + cell + cell + cell + + + cell + cell + cell + cell + + + + 24,212 + 58% happiness + + + +``` diff --git a/packages/calcite-components/src/components/table/usage/Basic.md b/packages/calcite-components/src/components/table/usage/Basic.md new file mode 100644 index 00000000000..46f49fa287b --- /dev/null +++ b/packages/calcite-components/src/components/table/usage/Basic.md @@ -0,0 +1,30 @@ +A simple meter component. + +```html + + + + + + + + + cell + cell + cell + cell + + + cell + cell + cell + cell + + + cell + cell + cell + cell + + +``` diff --git a/packages/calcite-components/src/demos/table.html b/packages/calcite-components/src/demos/table.html new file mode 100644 index 00000000000..e402b84e3ad --- /dev/null +++ b/packages/calcite-components/src/demos/table.html @@ -0,0 +1,3990 @@ + + + + + + + Table + + + + + + + +

A11y testing

+ + + + + + + + + + + slot + + + + + + + + + cell + cell + cell + cell + cell + test 1 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + test 2 + Happy + + Another thing + + cell + cell + cell + cell + cell + test 3 + Happy + + Another thing + + cell + cell + cell + cell + cell + test 4 + Happy + + Another thing + + cell + cell + cell + cell + cell + test 5 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + test 6 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + test 7 + Happy + + Another thing + + cell + cell + cell + cell + cell + test 8 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + test 9 + Sad + + Another thing + + + + cell + cell + cell + cell + cell + test 10 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + test 11 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + test 12 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + test 13 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + test 14 + Happy + + Another thing + + cell + cell + cell + cell + cell + test 15 + Happy + + Another thing + + cell + cell + cell + cell + cell + test 16 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + test 17 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + test 18 + Happy + + Another thing + + cell + cell + cell + cell + cell + test 19 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + test 20 + Sad + + Another thing + + + + cell + cell + cell + cell + cell + test 21 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + test 22 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + test 23 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + 12 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + 78 + Happy + + Another thing + + cell + cell + cell + cell + cell + 62 + Happy + + Another thing + + cell + cell + cell + cell + cell + 63 + Happy + + Another thing + + cell + cell + cell + cell + cell + 1643 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + 63 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + 62 + Happy + + Another thing + + cell + cell + cell + cell + cell + 6 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + 262 + Sad + + Another thing + + + + cell + cell + cell + cell + cell + 63 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + 53 + Happy + + Another thing + + cell + cell + cell + cell + cell + 25 + Happy + + Another thing + + cell + cell + cell + cell + cell + 63 + Happy + + Another thing + + cell + cell + cell + cell + cell + 1643 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + 63 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + 62 + Happy + + Another thing + + cell + cell + cell + cell + cell + 6 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + 262 + Sad + + Another thing + + + + cell + cell + cell + cell + cell + 63 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + 120 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + 987 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + 12 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + 78 + Happy + + Another thing + + cell + cell + cell + cell + cell + 63 + Happy + + Another thing + + cell + cell + cell + cell + cell + 1643 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + 63 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + 62 + Happy + + Another thing + + cell + cell + cell + cell + cell + 6 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + 262 + Sad + + Another thing + + + + cell + cell + cell + cell + cell + 63 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + 120 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + 987 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + 12 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + 78 + Happy + + Another thing + + cell + cell + cell + cell + cell + 62 + Happy + + Another thing + + cell + cell + cell + cell + cell + 63 + Happy + + Another thing + + cell + cell + cell + cell + cell + 1643 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + 63 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + 62 + Happy + + Another thing + + cell + cell + cell + cell + cell + 6 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + 262 + Sad + + Another thing + + + + cell + cell + cell + cell + cell + 63 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + 53 + Happy + + Another thing + + cell + cell + cell + cell + cell + 25 + Happy + + Another thing + + cell + cell + cell + cell + cell + 63 + Happy + + Another thing + + cell + cell + cell + cell + cell + 1643 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + 63 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + 62 + Happy + + Another thing + + cell + cell + cell + cell + cell + 6 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + 262 + Sad + + Another thing + + + + cell + cell + cell + cell + cell + 63 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + 120 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + 987 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + 12 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + 78 + Happy + + Another thing + + cell + cell + cell + cell + cell + 63 + Happy + + Another thing + + cell + cell + cell + cell + cell + 1643 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + 63 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + 62 + Happy + + Another thing + + cell + cell + cell + cell + cell + 6 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + 262 + Sad + + Another thing + + + + cell + cell + cell + cell + cell + 63 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + 120 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + 987 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + 12 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + 78 + Happy + + Another thing + + cell + cell + cell + cell + cell + 62 + Happy + + Another thing + + cell + cell + cell + cell + cell + 63 + Happy + + Another thing + + cell + cell + cell + cell + cell + 1643 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + 63 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + 62 + Happy + + Another thing + + cell + cell + cell + cell + cell + 6 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + 262 + Sad + + Another thing + + + + cell + cell + cell + cell + cell + 63 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + 120 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + 987 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + 12 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + 78 + Happy + + Another thing + + + + +

Interactive

+ +
+
+ Features + + Numbered + Zebra + Bordered + +
+
+ Selection Mode + + none + single + multiple + +
+
+ Scale + + S + M + L + +
+
+ Layout + + Auto + Fixed + +
+
+ pageSize + + + +
+ +
+ Themes + + Calcite (Default) + Mint Glacier + Ranger Station + Lavender Field + +
+
+ + + + + + + + + + + slot + + + + + + + + + cell + cell + cell + cell + cell + test 1 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + test 2 + Happy + + Another thing + + cell + cell + cell + cell + cell + test 3 + Happy + + Another thing + + cell + cell + cell + cell + cell + test 4 + Happy + + Another thing + + cell + cell + cell + cell + cell + test 5 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + test 6 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + test 7 + Happy + + Another thing + + cell + cell + cell + cell + cell + test 8 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + test 9 + Sad + + Another thing + + + + cell + cell + cell + cell + cell + test 10 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + test 11 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + test 12 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + test 13 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + test 14 + Happy + + Another thing + + cell + cell + cell + cell + cell + test 15 + Happy + + Another thing + + cell + cell + cell + cell + cell + test 16 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + test 17 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + test 18 + Happy + + Another thing + + cell + cell + cell + cell + cell + test 19 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + test 20 + Sad + + Another thing + + + + cell + cell + cell + cell + cell + test 21 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + test 22 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + test 23 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + 12 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + 78 + Happy + + Another thing + + cell + cell + cell + cell + cell + 62 + Happy + + Another thing + + cell + cell + cell + cell + cell + 63 + Happy + + Another thing + + cell + cell + cell + cell + cell + 1643 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + 63 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + 62 + Happy + + Another thing + + cell + cell + cell + cell + cell + 6 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + 262 + Sad + + Another thing + + + + cell + cell + cell + cell + cell + 63 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + 53 + Happy + + Another thing + + cell + cell + cell + cell + cell + 25 + Happy + + Another thing + + cell + cell + cell + cell + cell + 63 + Happy + + Another thing + + cell + cell + cell + cell + cell + 1643 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + 63 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + 62 + Happy + + Another thing + + cell + cell + cell + cell + cell + 6 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + 262 + Sad + + Another thing + + + + cell + cell + cell + cell + cell + 63 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + 120 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + 987 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + 12 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + 78 + Happy + + Another thing + + cell + cell + cell + cell + cell + 63 + Happy + + Another thing + + cell + cell + cell + cell + cell + 1643 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + 63 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + 62 + Happy + + Another thing + + cell + cell + cell + cell + cell + 6 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + 262 + Sad + + Another thing + + + + cell + cell + cell + cell + cell + 63 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + 120 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + 987 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + 12 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + 78 + Happy + + Another thing + + cell + cell + cell + cell + cell + 62 + Happy + + Another thing + + cell + cell + cell + cell + cell + 63 + Happy + + Another thing + + cell + cell + cell + cell + cell + 1643 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + 63 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + 62 + Happy + + Another thing + + cell + cell + cell + cell + cell + 6 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + 262 + Sad + + Another thing + + + + cell + cell + cell + cell + cell + 63 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + 53 + Happy + + Another thing + + cell + cell + cell + cell + cell + 25 + Happy + + Another thing + + cell + cell + cell + cell + cell + 63 + Happy + + Another thing + + cell + cell + cell + cell + cell + 1643 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + 63 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + 62 + Happy + + Another thing + + cell + cell + cell + cell + cell + 6 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + 262 + Sad + + Another thing + + + + cell + cell + cell + cell + cell + 63 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + 120 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + 987 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + 12 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + 78 + Happy + + Another thing + + cell + cell + cell + cell + cell + 63 + Happy + + Another thing + + cell + cell + cell + cell + cell + 1643 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + 63 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + 62 + Happy + + Another thing + + cell + cell + cell + cell + cell + 6 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + 262 + Sad + + Another thing + + + + cell + cell + cell + cell + cell + 63 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + 120 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + 987 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + 12 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + 78 + Happy + + Another thing + + cell + cell + cell + cell + cell + 62 + Happy + + Another thing + + cell + cell + cell + cell + cell + 63 + Happy + + Another thing + + cell + cell + cell + cell + cell + 1643 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + 63 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + 62 + Happy + + Another thing + + cell + cell + cell + cell + cell + 6 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + 262 + Sad + + Another thing + + + + cell + cell + cell + cell + cell + 63 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + 120 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + 987 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + 12 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + 78 + Happy + + Another thing + + + + +

Localized numbers

+ + + + + + + + + + + slot + + + + + + + + + cell + cell + cell + cell + cell + 34 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + 53 + Happy + + Another thing + + cell + cell + cell + cell + cell + 25 + Happy + + Another thing + + cell + cell + cell + cell + cell + 63 + Happy + + Another thing + + cell + cell + cell + cell + cell + 1643 + Happy + + Another thing + + + + + cell + cell + cell + cell + 63 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + 62 + Happy + + Another thing + + cell + cell + cell + cell + cell + 6 + Happy + + Another thing + + + + + cell + cell + cell + cell + 262 + Sad + + Another thing + + + + cell + cell + cell + cell + cell + 63 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + 120 + Happy + + Another thing + + + + cell + cell + cell + cell + cell + 987 + Happy + + Another thing + + + +

Simple

+ + + + + + + + + cell + cell + cell + cell + + + cell + cell + cell + cell + + + cell + cell + cell + cell + + + +

zebra

+ + + + + + + + + cell + cell + cell + cell + + + cell + cell + cell + cell + + + cell + cell + cell + cell + + + +

Bordered

+ + + + + + + + + cell + cell + cell + cell + + + cell + cell + cell + cell + + + cell + cell + cell + cell + + + +

Bordered-zebra

+ + + + + + + + + cell + cell + cell + cell + + + cell + cell + cell + cell + + + cell + cell + cell + cell + + + +

Various alignments

+ + + + + + + + + cell + cell + cell + cell + + + cell + cell + cell + cell + + + cell + cell + cell + cell + + + +

Disabled rows

+ + + + + + + + + cell + cell + cell + cell + + + cell + cell + cell + cell + + + cell + cell + cell + cell + + + cell + cell + cell + cell + + + cell + cell + cell + cell + + + cell + cell + cell + cell + + + cell + cell + cell + cell + + + cell + cell + cell + cell + + + +

Numbered

+ + + + + + + + + cell + cell + cell + cell + + + cell + cell + cell + cell + + + cell + cell + cell + cell + + + +

Numbered

+ + + + + + + + + cell + cell + cell + cell + + + cell + cell + cell + cell + + + cell + cell + cell + cell + + + foot + foot + foot + foot + + + +

With rich cell content

+ + + + + + + + + + Chip + + cell + + + cell + + Chipbutton + chip + + + cell + chip + + chipchip + + + foot + foot + foot + foot + + + +

Layout fixed

+ + + + + + + + + cell + cell + cell + cell + + + cell + cell + cell + cell + + + cell + cell + cell + cell + + + +

Using row-span and col-span

+ + + + + + + cell + cell + + + cell + cell + + + cell + cell + cell + cell + cell + + + cell + cell + cell + cell + cell + cell + + + cell + cell + cell + cell + + + +

Using row-span and col-span and numbered

+ + + + + + + cell + cell + + + cell + cell + + + cell + cell + cell + cell + cell + + + cell + cell + cell + cell + cell + cell + + + cell + cell + cell + cell + + + +

Using row-span and col-span

+ + + + + + + cell + cell + + + cell + cell + + + cell + cell + + + cell + cell + cell + + + cell + cell + cell + + + cell + cell + + + cell + cell + + + cell + cell + + + +

Multiple headers using col-span

+ + + + + + + + + + + + + cell + cell + cell + cell + + + cell + cell + cell + cell + + + +

Complex keyboard test with multiple headers, selection, pagination using col-span

+ + + + + + + + + + + + + cell + cell + + + cell + cell + + + cell + cell + + + cell + cell + cell + + + cell + cell + cell + + + cell + cell + + + cell + cell + + + cell + cell + + + foot + foot + foot + foot + + + foot + foot + + + +

Headers in rows

+ + + + cell + cell + cell + + + + cell + cell + cell + + + + cell + cell + cell + + + + cell + cell + cell + + + +

Headers in rows and table-head

+ + + + + + + + + + + + + + + + cell + cell + cell + + + + cell + cell + cell + + + + cell + cell + cell + + + + cell + cell + cell + + + + foot + foot + foot + + + + foot + foot + foot + + + +

selection-mode single

+ + + + + + + + + + + + + cell + cell + cell + cell + + + cell + cell + cell + cell + + + cell + cell + cell + cell + + + +

selection-mode multiple with selected at load

+ + + + + + + + + + + + + cell + cell + cell + cell + + + cell + cell + cell + cell + + + cell + cell + cell + cell + + + foot + foot + foot + foot + + + +

selection-mode multiple with multiple headers, footers, pageSize

+ + + + + + + + + + + + + + cell + cell + + + cell + cell + + + cell + cell + + + cell + cell + + + foot + foot + foot + foot + + + foot + foot + + + + foot + foot + foot + + + + foot + + + +

selection-mode multiple and numbered including out of view

+ + + + + + + + + + + + + + cell + cell + cell + cell + + + cell + cell + cell + cell + + + cell + cell + cell + cell + + + cell + cell + cell + cell + + + cell + cell + cell + cell + + + cell + cell + cell + cell + + + cell + cell + cell + cell + + + cell + cell + cell + cell + + + +

selection-mode multiple and numbered including out of view and footer

+ + + + + + + + + + + + + + cell + cell + cell + cell + + + cell + cell + cell + cell + + + cell + cell + cell + cell + + + cell + cell + cell + cell + + + cell + cell + cell + cell + + + cell + cell + cell + cell + + + cell + cell + cell + cell + + + cell + cell + cell + cell + + + + 24,212 + 58% happiness + + + +

selection-mode multiple and numbered including out of view and multiple header and footer

+ + + + + + + + + + + + + + + + + + cell + cell + cell + cell + + + cell + cell + cell + cell + + + cell + cell + cell + cell + + + cell + cell + cell + cell + + + cell + cell + cell + cell + + + cell + cell + cell + cell + + + cell + cell + cell + cell + + + cell + cell + cell + cell + + + + 58% happiness + + + + 24,212 + 58% happiness + + + +

With selection-mode multiple and rich cell content

+ + + + + + + + + + Chip + + cell + + + cell + + Chipbutton + chip + + + cell + chip + + chipchip + + + +

Handle keyboard navigation with disabled rows in various places

+

+ Expect up / down to skip to next non-disabled - expect "page up / down / cntrl home + end" to focus next + available non-disabled +

+ + + + + + + + + + + + + + cell + cell + cell + cell + + + cell + cell + cell + cell + + + cell + cell + cell + cell + + + cell + cell + cell + cell + + + cell + cell + cell + cell + + + cell + cell + cell + cell + + + cell + cell + cell + cell + + +
+ + + diff --git a/packages/calcite-components/src/index.html b/packages/calcite-components/src/index.html index 55485167f6b..e2bed63436e 100644 --- a/packages/calcite-components/src/index.html +++ b/packages/calcite-components/src/index.html @@ -431,6 +431,12 @@

Calcite demo

+
+ + + +
+
diff --git a/t9nmanifest.txt b/t9nmanifest.txt index 0fa58306416..38bb14869aa 100644 --- a/t9nmanifest.txt +++ b/t9nmanifest.txt @@ -34,6 +34,9 @@ packages\calcite-components\src\components\rating\assets\rating\t9n packages\calcite-components\src\components\scrim\assets\scrim\t9n packages\calcite-components\src\components\shell-panel\assets\shell-panel\t9n packages\calcite-components\src\components\tab-title\assets\tab-title\t9n +packages\calcite-components\src\components\table\assets\table\t9n +packages\calcite-components\src\components\table-cell\assets\table-cell\t9n +packages\calcite-components\src\components\table-header\assets\table-header\t9n packages\calcite-components\src\components\text-area\assets\text-area\t9n packages\calcite-components\src\components\time-picker\assets\time-picker\t9n packages\calcite-components\src\components\tip\assets\tip\t9n