@xplortech/apollo-core 3.3.0 → 3.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +17 -0
- package/build/components/dropdown.css +1 -1
- package/build/components/icon.css +1 -1
- package/build/components/nav-item.css +1 -1
- package/build/components/secondary-nav.css +1 -1
- package/build/components/top-nav.css +1 -1
- package/build/core.css +1 -1
- package/build/style.css +1 -1
- package/build/variables/apollo.css +1 -0
- package/build/variables/field-edge.css +1 -0
- package/build/vendor/flatpickr.css +1 -1
- package/dist/apollo-core/apollo-core.css +1 -1
- package/dist/apollo-core/apollo-core.esm.js +1 -1
- package/dist/apollo-core/{p-18486aba.entry.js → p-00e96d61.entry.js} +1 -1
- package/dist/apollo-core/{p-439d5cdd.entry.js → p-02a2d1a3.entry.js} +1 -1
- package/dist/apollo-core/{p-d204ed1a.entry.js → p-035ed1ad.entry.js} +1 -1
- package/dist/apollo-core/{p-af188297.entry.js → p-066d3199.entry.js} +1 -1
- package/dist/apollo-core/{p-9955c4f2.entry.js → p-066eccd6.entry.js} +1 -1
- package/dist/apollo-core/{p-2b813212.entry.js → p-0e8514ff.entry.js} +1 -1
- package/dist/apollo-core/{p-a73b0ca4.entry.js → p-18115cd4.entry.js} +1 -1
- package/dist/apollo-core/{p-79d306a2.entry.js → p-19d22455.entry.js} +1 -1
- package/dist/apollo-core/{p-9d091b05.entry.js → p-1b00e924.entry.js} +1 -1
- package/dist/apollo-core/{p-19fb0e5f.entry.js → p-1ca46c11.entry.js} +1 -1
- package/dist/apollo-core/{p-7fd3da3a.entry.js → p-1e07745c.entry.js} +1 -1
- package/dist/apollo-core/{p-3e3ab332.entry.js → p-31cbb36f.entry.js} +1 -1
- package/dist/apollo-core/{p-cfb00d23.entry.js → p-321319c0.entry.js} +1 -1
- package/dist/apollo-core/{p-325a3b43.entry.js → p-3222e5a7.entry.js} +1 -1
- package/dist/apollo-core/{p-aece2c3d.entry.js → p-325466bf.entry.js} +1 -1
- package/dist/apollo-core/{p-cab7d816.entry.js → p-32ac676a.entry.js} +1 -1
- package/dist/apollo-core/{p-6de10879.entry.js → p-33063e8c.entry.js} +1 -1
- package/dist/apollo-core/{p-4249ee9b.entry.js → p-34d84be8.entry.js} +1 -1
- package/dist/apollo-core/{p-08ea8939.entry.js → p-36965939.entry.js} +1 -1
- package/dist/apollo-core/{p-2111cc38.entry.js → p-43fbf2aa.entry.js} +1 -1
- package/dist/apollo-core/{p-d1571245.entry.js → p-44a1fd8b.entry.js} +1 -1
- package/dist/apollo-core/{p-d9f78325.entry.js → p-462a804c.entry.js} +1 -1
- package/dist/apollo-core/{p-38fa8398.entry.js → p-47a4f0a8.entry.js} +1 -1
- package/dist/apollo-core/{p-01c55c74.entry.js → p-5cf30b9d.entry.js} +1 -1
- package/dist/apollo-core/{p-7f00b542.entry.js → p-606153e1.entry.js} +1 -1
- package/dist/apollo-core/{p-17e38eaf.entry.js → p-60e3a798.entry.js} +1 -1
- package/dist/apollo-core/{p-a149351a.entry.js → p-663e9521.entry.js} +1 -1
- package/dist/apollo-core/{p-b9c85394.entry.js → p-6e22ab86.entry.js} +1 -1
- package/dist/apollo-core/{p-fdd1b7da.entry.js → p-7781b569.entry.js} +1 -1
- package/dist/apollo-core/{p-73a1c68d.entry.js → p-787a361c.entry.js} +1 -1
- package/dist/apollo-core/{p-fc73497e.entry.js → p-7b46b656.entry.js} +1 -1
- package/dist/apollo-core/{p-9b757459.entry.js → p-7bfd9cfb.entry.js} +1 -1
- package/dist/apollo-core/{p-4b949aeb.entry.js → p-8127dd6b.entry.js} +1 -1
- package/dist/apollo-core/{p-3d4a6de1.entry.js → p-88367287.entry.js} +1 -1
- package/dist/apollo-core/{p-d13a07ea.entry.js → p-8a59605f.entry.js} +1 -1
- package/dist/apollo-core/p-8df2b9e8.entry.js +1 -0
- package/dist/apollo-core/{p-e99503a2.entry.js → p-9466f566.entry.js} +1 -1
- package/dist/apollo-core/{p-620fc472.entry.js → p-95b6e6e6.entry.js} +1 -1
- package/dist/apollo-core/{p-14f5d98a.entry.js → p-966f3702.entry.js} +1 -1
- package/dist/apollo-core/{p-cca0f1a2.entry.js → p-9d7ead72.entry.js} +1 -1
- package/dist/apollo-core/p-CgJEmBQY.js +3 -0
- package/dist/apollo-core/{p-b2dcdb19.entry.js → p-a21c7976.entry.js} +1 -1
- package/dist/apollo-core/{p-d060572b.entry.js → p-a30b51c8.entry.js} +1 -1
- package/dist/apollo-core/{p-b55951a2.entry.js → p-a3537a74.entry.js} +1 -1
- package/dist/apollo-core/{p-6aee7d6b.entry.js → p-ac105b6c.entry.js} +1 -1
- package/dist/apollo-core/{p-cd2d73ee.entry.js → p-adc14e6e.entry.js} +1 -1
- package/dist/apollo-core/{p-c4fd031e.entry.js → p-b41b7950.entry.js} +1 -1
- package/dist/apollo-core/{p-0a7d57ab.entry.js → p-b44a72e9.entry.js} +1 -1
- package/dist/apollo-core/{p-e21af3d1.entry.js → p-b6f20359.entry.js} +1 -1
- package/dist/apollo-core/{p-dad5d377.entry.js → p-b7f75498.entry.js} +1 -1
- package/dist/apollo-core/{p-890c641b.entry.js → p-b9136f21.entry.js} +1 -1
- package/dist/apollo-core/{p-e7145461.entry.js → p-c526f16d.entry.js} +1 -1
- package/dist/apollo-core/{p-3f8dc5b9.entry.js → p-c7b8a325.entry.js} +1 -1
- package/dist/apollo-core/{p-1c2135e3.entry.js → p-c9246567.entry.js} +1 -1
- package/dist/apollo-core/{p-b7b91f27.entry.js → p-cc04d4e7.entry.js} +1 -1
- package/dist/apollo-core/{p-13253d8f.entry.js → p-cc27a41f.entry.js} +1 -1
- package/dist/apollo-core/{p-01ed2bb5.entry.js → p-d58523b6.entry.js} +1 -1
- package/dist/apollo-core/{p-a5ddb3c4.entry.js → p-d7fba438.entry.js} +1 -1
- package/dist/apollo-core/p-db998e2a.entry.js +1 -0
- package/dist/apollo-core/{p-9c7a0229.entry.js → p-e1f095dd.entry.js} +1 -1
- package/dist/apollo-core/{p-651b49c3.entry.js → p-e30d204d.entry.js} +1 -1
- package/dist/apollo-core/{p-54053547.entry.js → p-e4649020.entry.js} +1 -1
- package/dist/apollo-core/{p-9c41d07f.entry.js → p-ebe6a1d6.entry.js} +1 -1
- package/dist/apollo-core/{p-d3720611.entry.js → p-f0897ee2.entry.js} +1 -1
- package/dist/apollo-core/{p-ba85f686.entry.js → p-f13e14bd.entry.js} +1 -1
- package/dist/apollo-core/{p-38a6a53d.entry.js → p-f88eefaf.entry.js} +1 -1
- package/dist/apollo-core/{p-9832bc63.entry.js → p-fd2e7bb0.entry.js} +1 -1
- package/dist/cjs/apollo-core.cjs.js +1 -1
- package/dist/cjs/{index-EdmnG7t8.js → index-CQbPtJas.js} +1 -154
- package/dist/cjs/loader.cjs.js +1 -1
- package/dist/cjs/xpl-accordion.cjs.entry.js +1 -1
- package/dist/cjs/xpl-application-shell.cjs.entry.js +1 -1
- package/dist/cjs/xpl-avatar_3.cjs.entry.js +1 -1
- package/dist/cjs/xpl-backdrop.cjs.entry.js +1 -1
- package/dist/cjs/xpl-badge.cjs.entry.js +1 -1
- package/dist/cjs/xpl-banner.cjs.entry.js +1 -1
- package/dist/cjs/xpl-breadcrumb-item.cjs.entry.js +1 -1
- package/dist/cjs/xpl-breadcrumbs.cjs.entry.js +1 -1
- package/dist/cjs/xpl-button-row.cjs.entry.js +1 -1
- package/dist/cjs/xpl-button.cjs.entry.js +1 -1
- package/dist/cjs/xpl-calendar.cjs.entry.js +2 -2
- package/dist/cjs/xpl-checkbox.cjs.entry.js +1 -1
- package/dist/cjs/xpl-choicelist.cjs.entry.js +1 -1
- package/dist/cjs/xpl-content-area.cjs.entry.js +1 -1
- package/dist/cjs/xpl-dashboard.cjs.entry.js +1 -1
- package/dist/cjs/xpl-data-card.cjs.entry.js +3 -3
- package/dist/cjs/xpl-dropdown_4.cjs.entry.js +1 -1
- package/dist/cjs/xpl-dynamic-table-cell.cjs.entry.js +1 -1
- package/dist/cjs/xpl-dynamic-table-row.cjs.entry.js +1 -1
- package/dist/cjs/xpl-dynamic-table.cjs.entry.js +1 -1
- package/dist/cjs/xpl-grid-item.cjs.entry.js +1 -1
- package/dist/cjs/xpl-grid.cjs.entry.js +1 -1
- package/dist/cjs/xpl-header-accordion.cjs.entry.js +1 -1
- package/dist/cjs/xpl-icon.cjs.entry.js +3 -6
- package/dist/cjs/xpl-input-color.cjs.entry.js +9 -9
- package/dist/cjs/xpl-input-phone.cjs.entry.js +1 -1
- package/dist/cjs/xpl-input-time.cjs.entry.js +1 -1
- package/dist/cjs/xpl-input_4.cjs.entry.js +4 -4
- package/dist/cjs/xpl-large-card.cjs.entry.js +2 -2
- package/dist/cjs/xpl-list-item.cjs.entry.js +1 -1
- package/dist/cjs/xpl-list.cjs.entry.js +3 -3
- package/dist/cjs/xpl-main-nav.cjs.entry.js +1 -1
- package/dist/cjs/xpl-modal.cjs.entry.js +1 -1
- package/dist/cjs/xpl-nav-header-menu.cjs.entry.js +3 -3
- package/dist/cjs/xpl-nav-item.cjs.entry.js +1 -1
- package/dist/cjs/xpl-pagination.cjs.entry.js +1 -1
- package/dist/cjs/xpl-panel.cjs.entry.js +1 -1
- package/dist/cjs/xpl-popover.cjs.entry.js +1 -1
- package/dist/cjs/xpl-progress-bar.cjs.entry.js +1 -1
- package/dist/cjs/xpl-progress-indicator.cjs.entry.js +1 -1
- package/dist/cjs/xpl-secondary-nav.cjs.entry.js +1 -1
- package/dist/cjs/xpl-select_2.cjs.entry.js +1 -1
- package/dist/cjs/xpl-side-nav-header-item.cjs.entry.js +1 -1
- package/dist/cjs/xpl-side-nav-item.cjs.entry.js +1 -1
- package/dist/cjs/xpl-side-nav-section.cjs.entry.js +1 -1
- package/dist/cjs/xpl-side-nav.cjs.entry.js +3 -3
- package/dist/cjs/xpl-skeleton.cjs.entry.js +1 -1
- package/dist/cjs/xpl-slideout.cjs.entry.js +1 -1
- package/dist/cjs/xpl-spotlight.cjs.entry.js +1 -1
- package/dist/cjs/xpl-tab-panel.cjs.entry.js +3 -3
- package/dist/cjs/xpl-tab.cjs.entry.js +1 -1
- package/dist/cjs/xpl-table-body.cjs.entry.js +1 -1
- package/dist/cjs/xpl-table-cell_3.cjs.entry.js +1 -1
- package/dist/cjs/xpl-table-footer.cjs.entry.js +1 -1
- package/dist/cjs/xpl-table-header.cjs.entry.js +1 -1
- package/dist/cjs/xpl-table-row.cjs.entry.js +1 -1
- package/dist/cjs/xpl-table.cjs.entry.js +1 -1
- package/dist/cjs/xpl-tabs.cjs.entry.js +1 -1
- package/dist/cjs/xpl-toast.cjs.entry.js +1 -1
- package/dist/cjs/xpl-toggle.cjs.entry.js +1 -1
- package/dist/cjs/xpl-toolbar.cjs.entry.js +1 -1
- package/dist/cjs/xpl-tooltip.cjs.entry.js +1 -1
- package/dist/cjs/xpl-top-nav-item.cjs.entry.js +3 -3
- package/dist/cjs/xpl-top-nav-menu.cjs.entry.js +3 -3
- package/dist/cjs/xpl-top-nav.cjs.entry.js +6 -6
- package/dist/cjs/xpl-utility-bar.cjs.entry.js +1 -1
- package/dist/collection/components/xpl-avatar/xpl-avatar.js +8 -8
- package/dist/collection/components/xpl-badge/xpl-badge.js +2 -2
- package/dist/collection/components/xpl-calendar/xpl-calendar.js +1 -1
- package/dist/collection/components/xpl-choicelist/xpl-choicelist.js +1 -1
- package/dist/collection/components/xpl-data-card/xpl-data-card.js +2 -2
- package/dist/collection/components/xpl-dropdown/xpl-dropdown-group/xpl-dropdown-group.js +1 -1
- package/dist/collection/components/xpl-dropdown/xpl-dropdown.js +6 -6
- package/dist/collection/components/xpl-icon/xpl-icon.js +2 -12
- package/dist/collection/components/xpl-input/xpl-input-color/xpl-input-color.js +8 -8
- package/dist/collection/components/xpl-input/xpl-input-date/xpl-input-date.js +3 -3
- package/dist/collection/components/xpl-large-card/xpl-large-card.js +1 -1
- package/dist/collection/components/xpl-list/xpl-list-item/xpl-list-item.js +2 -2
- package/dist/collection/components/xpl-list/xpl-list.js +4 -4
- package/dist/collection/components/xpl-popover/xpl-popover.js +2 -2
- package/dist/collection/components/xpl-select/xpl-select.js +1 -1
- package/dist/collection/components/xpl-side-nav/xpl-side-nav.js +2 -2
- package/dist/collection/components/xpl-spotlight/xpl-spotlight.js +4 -4
- package/dist/collection/components/xpl-tab/xpl-tab.js +2 -2
- package/dist/collection/components/xpl-tab-panel/xpl-tab-panel.js +3 -3
- package/dist/collection/components/xpl-table/xpl-table-header-cell/xpl-table-header-cell.js +2 -2
- package/dist/collection/components/xpl-table/xpl-table.js +4 -4
- package/dist/collection/components/xpl-tag/xpl-tag.js +4 -4
- package/dist/collection/components/xpl-top-nav/xpl-nav-header-menu/xpl-nav-header-menu.js +2 -2
- package/dist/collection/components/xpl-top-nav/xpl-top-nav-item/xpl-top-nav-item.js +2 -2
- package/dist/collection/components/xpl-top-nav/xpl-top-nav-menu/xpl-top-nav-menu.js +2 -2
- package/dist/collection/components/xpl-top-nav/xpl-top-nav.js +5 -5
- package/dist/components/index.js +1 -1
- package/dist/components/{p-Bh-U2qmp.js → p-6-DvgBzG.js} +1 -1
- package/dist/components/{p-DHxDWgLP.js → p-B54F4o_Z.js} +1 -1
- package/dist/components/{p-Cop4KmAG.js → p-BFUtaXqX.js} +1 -1
- package/dist/components/{p-3R1VKKds.js → p-BHRO2whA.js} +1 -1
- package/dist/components/{p-CZg3Gb0I.js → p-BKajYWw6.js} +1 -1
- package/dist/components/{p-rQFFXcXl.js → p-BU4pW_6c.js} +1 -1
- package/dist/components/p-B_6p2HCL.js +1 -0
- package/dist/components/{p-BowQ58XR.js → p-Biie85R2.js} +1 -1
- package/dist/components/{p-CetimlcM.js → p-CIcKTXQj.js} +1 -1
- package/dist/components/{p-n-yq7lf4.js → p-COq-vU2g.js} +1 -1
- package/dist/components/{p-ClLyaOG7.js → p-CTy7V3XS.js} +1 -1
- package/dist/components/{p-JjlTuq8d.js → p-Cq8V05oj.js} +1 -1
- package/dist/components/{p-BZrSTAV1.js → p-CthHapLu.js} +1 -1
- package/dist/components/{p-DbN9vTl7.js → p-DGxQJj8d.js} +1 -1
- package/dist/components/{p-CcPrBo53.js → p-Dn1Qsv0Y.js} +1 -1
- package/dist/components/{p-d4i2Qqvl.js → p-Dn6HsGUr.js} +1 -1
- package/dist/components/{p-BNOkHymY.js → p-DxjcChRd.js} +1 -1
- package/dist/components/{p-2XxO7M15.js → p-FS6KZMQV.js} +1 -1
- package/dist/components/{p-BWAytJnz.js → p-Fj_zi29t.js} +1 -1
- package/dist/components/{p-CjzUVpyd.js → p-L9wSxXlk.js} +1 -1
- package/dist/components/{p-DORBnmT4.js → p-ULcrhk_V.js} +1 -1
- package/dist/components/{p-Dl__XgUD.js → p-WTdJQHaL.js} +1 -1
- package/dist/components/{p-CWXfIUHo.js → p-fstojyQr.js} +1 -1
- package/dist/components/{p-CfZI7bBe.js → p-gs07oY0j.js} +1 -1
- package/dist/components/{p-sjDW_E4p.js → p-nRygucMK.js} +1 -1
- package/dist/components/{p-yc1qXhah.js → p-q4zX9LQ0.js} +1 -1
- package/dist/components/xpl-accordion.js +1 -1
- package/dist/components/xpl-application-shell.js +1 -1
- package/dist/components/xpl-avatar.js +1 -1
- package/dist/components/xpl-backdrop.js +1 -1
- package/dist/components/xpl-badge.js +1 -1
- package/dist/components/xpl-banner.js +1 -1
- package/dist/components/xpl-breadcrumb-item.js +1 -1
- package/dist/components/xpl-breadcrumbs.js +1 -1
- package/dist/components/xpl-button-row.js +1 -1
- package/dist/components/xpl-button.js +1 -1
- package/dist/components/xpl-calendar.js +1 -1
- package/dist/components/xpl-checkbox.js +1 -1
- package/dist/components/xpl-choicelist.js +1 -1
- package/dist/components/xpl-content-area.js +1 -1
- package/dist/components/xpl-dashboard.js +1 -1
- package/dist/components/xpl-data-card.js +1 -1
- package/dist/components/xpl-divider.js +1 -1
- package/dist/components/xpl-dropdown-group.js +1 -1
- package/dist/components/xpl-dropdown-heading.js +1 -1
- package/dist/components/xpl-dropdown-option.js +1 -1
- package/dist/components/xpl-dropdown.js +1 -1
- package/dist/components/xpl-dynamic-table-cell.js +1 -1
- package/dist/components/xpl-dynamic-table-row.js +1 -1
- package/dist/components/xpl-dynamic-table.js +1 -1
- package/dist/components/xpl-grid-item.js +1 -1
- package/dist/components/xpl-grid.js +1 -1
- package/dist/components/xpl-header-accordion.js +1 -1
- package/dist/components/xpl-icon.js +1 -1
- package/dist/components/xpl-input-color.js +1 -1
- package/dist/components/xpl-input-date.js +1 -1
- package/dist/components/xpl-input-file.js +1 -1
- package/dist/components/xpl-input-phone.js +1 -1
- package/dist/components/xpl-input-search.js +1 -1
- package/dist/components/xpl-input-time.js +1 -1
- package/dist/components/xpl-input.js +1 -1
- package/dist/components/xpl-large-card.js +1 -1
- package/dist/components/xpl-list-item.js +1 -1
- package/dist/components/xpl-list.js +1 -1
- package/dist/components/xpl-main-nav.js +1 -1
- package/dist/components/xpl-modal.js +1 -1
- package/dist/components/xpl-nav-header-menu.js +1 -1
- package/dist/components/xpl-nav-item.js +1 -1
- package/dist/components/xpl-pagination.js +1 -1
- package/dist/components/xpl-panel.js +1 -1
- package/dist/components/xpl-popover.js +1 -1
- package/dist/components/xpl-progress-bar.js +1 -1
- package/dist/components/xpl-progress-indicator.js +1 -1
- package/dist/components/xpl-radio.js +1 -1
- package/dist/components/xpl-secondary-nav.js +1 -1
- package/dist/components/xpl-select.js +1 -1
- package/dist/components/xpl-side-nav-header-item.js +1 -1
- package/dist/components/xpl-side-nav-item.js +1 -1
- package/dist/components/xpl-side-nav-section.js +1 -1
- package/dist/components/xpl-side-nav.js +1 -1
- package/dist/components/xpl-skeleton.js +1 -1
- package/dist/components/xpl-slideout.js +1 -1
- package/dist/components/xpl-spotlight.js +1 -1
- package/dist/components/xpl-tab-panel.js +1 -1
- package/dist/components/xpl-tab.js +1 -1
- package/dist/components/xpl-table-body.js +1 -1
- package/dist/components/xpl-table-cell.js +1 -1
- package/dist/components/xpl-table-footer-cell.js +1 -1
- package/dist/components/xpl-table-footer.js +1 -1
- package/dist/components/xpl-table-header-cell.js +1 -1
- package/dist/components/xpl-table-header.js +1 -1
- package/dist/components/xpl-table-row.js +1 -1
- package/dist/components/xpl-table.js +1 -1
- package/dist/components/xpl-tabs.js +1 -1
- package/dist/components/xpl-tag.js +1 -1
- package/dist/components/xpl-toast.js +1 -1
- package/dist/components/xpl-toggle.js +1 -1
- package/dist/components/xpl-toolbar.js +1 -1
- package/dist/components/xpl-tooltip.js +1 -1
- package/dist/components/xpl-top-nav-item.js +1 -1
- package/dist/components/xpl-top-nav-menu.js +1 -1
- package/dist/components/xpl-top-nav.js +1 -1
- package/dist/components/xpl-utility-bar.js +1 -1
- package/dist/docs/xpl-avatar/readme.md +1 -1
- package/dist/docs/xpl-dropdown/readme.md +10 -1
- package/dist/docs/xpl-list/readme.md +1 -1
- package/dist/docs/xpl-nav-item/readme.md +1 -1
- package/dist/docs/xpl-pagination/readme.md +1 -1
- package/dist/docs/xpl-secondary-nav/readme.md +4 -2
- package/dist/docs/xpl-toolbar/readme.md +1 -1
- package/dist/docs/xpl-top-nav/xpl-nav-header-menu/readme.md +1 -1
- package/dist/docs.json +168 -168
- package/dist/esm/apollo-core.js +2 -2
- package/dist/esm/{index-CJABLO_1.js → index-CgJEmBQY.js} +1 -154
- package/dist/esm/loader.js +2 -2
- package/dist/esm/xpl-accordion.entry.js +1 -1
- package/dist/esm/xpl-application-shell.entry.js +1 -1
- package/dist/esm/xpl-avatar_3.entry.js +1 -1
- package/dist/esm/xpl-backdrop.entry.js +1 -1
- package/dist/esm/xpl-badge.entry.js +1 -1
- package/dist/esm/xpl-banner.entry.js +1 -1
- package/dist/esm/xpl-breadcrumb-item.entry.js +1 -1
- package/dist/esm/xpl-breadcrumbs.entry.js +1 -1
- package/dist/esm/xpl-button-row.entry.js +1 -1
- package/dist/esm/xpl-button.entry.js +1 -1
- package/dist/esm/xpl-calendar.entry.js +2 -2
- package/dist/esm/xpl-checkbox.entry.js +1 -1
- package/dist/esm/xpl-choicelist.entry.js +1 -1
- package/dist/esm/xpl-content-area.entry.js +1 -1
- package/dist/esm/xpl-dashboard.entry.js +1 -1
- package/dist/esm/xpl-data-card.entry.js +3 -3
- package/dist/esm/xpl-dropdown_4.entry.js +1 -1
- package/dist/esm/xpl-dynamic-table-cell.entry.js +1 -1
- package/dist/esm/xpl-dynamic-table-row.entry.js +1 -1
- package/dist/esm/xpl-dynamic-table.entry.js +1 -1
- package/dist/esm/xpl-grid-item.entry.js +1 -1
- package/dist/esm/xpl-grid.entry.js +1 -1
- package/dist/esm/xpl-header-accordion.entry.js +1 -1
- package/dist/esm/xpl-icon.entry.js +3 -6
- package/dist/esm/xpl-input-color.entry.js +9 -9
- package/dist/esm/xpl-input-phone.entry.js +1 -1
- package/dist/esm/xpl-input-time.entry.js +1 -1
- package/dist/esm/xpl-input_4.entry.js +4 -4
- package/dist/esm/xpl-large-card.entry.js +2 -2
- package/dist/esm/xpl-list-item.entry.js +1 -1
- package/dist/esm/xpl-list.entry.js +3 -3
- package/dist/esm/xpl-main-nav.entry.js +1 -1
- package/dist/esm/xpl-modal.entry.js +1 -1
- package/dist/esm/xpl-nav-header-menu.entry.js +3 -3
- package/dist/esm/xpl-nav-item.entry.js +1 -1
- package/dist/esm/xpl-pagination.entry.js +1 -1
- package/dist/esm/xpl-panel.entry.js +1 -1
- package/dist/esm/xpl-popover.entry.js +1 -1
- package/dist/esm/xpl-progress-bar.entry.js +1 -1
- package/dist/esm/xpl-progress-indicator.entry.js +1 -1
- package/dist/esm/xpl-secondary-nav.entry.js +1 -1
- package/dist/esm/xpl-select_2.entry.js +1 -1
- package/dist/esm/xpl-side-nav-header-item.entry.js +1 -1
- package/dist/esm/xpl-side-nav-item.entry.js +1 -1
- package/dist/esm/xpl-side-nav-section.entry.js +1 -1
- package/dist/esm/xpl-side-nav.entry.js +3 -3
- package/dist/esm/xpl-skeleton.entry.js +1 -1
- package/dist/esm/xpl-slideout.entry.js +1 -1
- package/dist/esm/xpl-spotlight.entry.js +1 -1
- package/dist/esm/xpl-tab-panel.entry.js +3 -3
- package/dist/esm/xpl-tab.entry.js +1 -1
- package/dist/esm/xpl-table-body.entry.js +1 -1
- package/dist/esm/xpl-table-cell_3.entry.js +1 -1
- package/dist/esm/xpl-table-footer.entry.js +1 -1
- package/dist/esm/xpl-table-header.entry.js +1 -1
- package/dist/esm/xpl-table-row.entry.js +1 -1
- package/dist/esm/xpl-table.entry.js +1 -1
- package/dist/esm/xpl-tabs.entry.js +1 -1
- package/dist/esm/xpl-toast.entry.js +1 -1
- package/dist/esm/xpl-toggle.entry.js +1 -1
- package/dist/esm/xpl-toolbar.entry.js +1 -1
- package/dist/esm/xpl-tooltip.entry.js +1 -1
- package/dist/esm/xpl-top-nav-item.entry.js +3 -3
- package/dist/esm/xpl-top-nav-menu.entry.js +3 -3
- package/dist/esm/xpl-top-nav.entry.js +6 -6
- package/dist/esm/xpl-utility-bar.entry.js +1 -1
- package/hydrate/index.js +35 -145
- package/hydrate/index.mjs +35 -145
- package/package.json +11 -11
- package/dist/apollo-core/p-CJABLO_1.js +0 -3
- package/dist/apollo-core/p-a2c3a38a.entry.js +0 -1
- package/dist/apollo-core/p-ec99c433.entry.js +0 -1
- package/dist/collection/components/xpl-icon/xpl-icon.css +0 -5
- package/dist/components/p-BqhTjJWq.js +0 -1
- /package/dist/{utils → collection/utils}/form-bindings.js +0 -0
- /package/dist/{utils → collection/utils}/story-vrt.js +0 -0
- /package/dist/types/{third-party.d.ts → types/third-party.d.ts} +0 -0
- /package/dist/types/{home/runner/work/apollo/apollo/packages/apollo-core/.stencil/utils → utils}/form-bindings.d.ts +0 -0
- /package/dist/types/{home/runner/work/apollo/apollo/packages/apollo-core/.stencil/utils → utils}/story-vrt.d.ts +0 -0
package/dist/docs.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"timestamp": "2026-09-
|
|
2
|
+
"timestamp": "2026-09-22T15:57:00",
|
|
3
3
|
"compiler": {
|
|
4
4
|
"name": "@stencil/core",
|
|
5
5
|
"version": "4.44.2",
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
},
|
|
8
8
|
"components": [
|
|
9
9
|
{
|
|
10
|
-
"filePath": "src/components/
|
|
10
|
+
"filePath": "src/components/xpl-accordion/xpl-accordion.tsx",
|
|
11
11
|
"encapsulation": "none",
|
|
12
12
|
"tag": "xpl-accordion",
|
|
13
13
|
"readme": "# xpl-accordion\n\nAccordions are collapsable containers and allow users to collapse or expand the container. Useful when many items are present in a section and users may benefit from closing content to gain more space or focus on content that is most important to them. \n\nUse the content slot in the opened state to swap in Apollo components or make your own local component with groups of Apollo components or custom content.\n\nNote: Users will often miss any content that is hidden behind an interaction. If it is important that users see the content, use an accordion's open state on load `initialExpanded`, or use another pattern.\n",
|
|
@@ -291,7 +291,7 @@
|
|
|
291
291
|
}
|
|
292
292
|
},
|
|
293
293
|
{
|
|
294
|
-
"filePath": "src/components/
|
|
294
|
+
"filePath": "src/components/xpl-application-shell/xpl-application-shell.tsx",
|
|
295
295
|
"encapsulation": "none",
|
|
296
296
|
"tag": "xpl-application-shell",
|
|
297
297
|
"readme": "# xpl-application-shell\n\n`xpl-application-shell` is the top-level layout container for an Apollo application. It arranges the main navigation rail, an optional utility bar, an optional secondary navigation column, and the page content into a responsive CSS grid, and drives the CSS-only open/close animation of the navigation rail.\n\n## Usage\n\n```html\n<xpl-application-shell with-subnav is-nav-open-at-startup=\"true\">\n <xpl-main-nav slot=\"nav\" width=\"default\"><!-- ... --></xpl-main-nav>\n <xpl-utility-bar slot=\"utility\"><!-- ... --></xpl-utility-bar>\n <xpl-secondary-nav slot=\"subnav\"><!-- ... --></xpl-secondary-nav>\n <xpl-content-area slot=\"content\"><!-- ... --></xpl-content-area>\n</xpl-application-shell>\n```\n\n## Design Tokens\n\nTokens used by this component from `@xplortech/apollo-foundation`. All purpose-specific tokens theme automatically in dark mode (no `.dark` overrides in the CSS).\n\n**Color**\n\n| Element | Property | Token | Resolves (light / dark) |\n| --- | --- | --- | --- |\n| Host nav rail | `background-color` | `--xpl-background-surface-inverse-on-light` | neutral-1000 / neutral-1000 (always dark) |\n| `&__subnav` | `background-color` | `--xpl-background-surface-default` | neutral-0 / neutral-1000 |\n| `&__content` | `background-color` | `--xpl-background-surface-subtlest` | neutral-50 / neutral-900 |\n| `&__subnav`, `&__content` | `color` (on-surface text) | `--xpl-text-default` | neutral-900 / neutral-50 |\n| `&__subnav` (top), `&__content` (left/top), `&__utility` (left) | `border-color` | `--xpl-border-default` | neutral-400 / neutral-600 |\n\n**Border width**\n\n- `--xpl-border-small` (0.0625rem / 1px) — all shell dividers.\n\n**Layout literals (not themeable)**\n\nThe nav rail widths / transforms (`74px`, `112px`, `240px`) drive the CSS-only open/close animation and are kept as literals; no Foundation size token set covers animated grid-track widths. `grid-template`, `100vh`, and `-webkit-fill-available` are also kept as literals. See `TECH_DEBT.md`.\n",
|
|
@@ -504,10 +504,10 @@
|
|
|
504
504
|
}
|
|
505
505
|
},
|
|
506
506
|
{
|
|
507
|
-
"filePath": "src/components/
|
|
507
|
+
"filePath": "src/components/xpl-avatar/xpl-avatar.tsx",
|
|
508
508
|
"encapsulation": "none",
|
|
509
509
|
"tag": "xpl-avatar",
|
|
510
|
-
"readme": "# xpl-avatar\n\nThe **Avatar** component shows a person or entity: a photo, initials on a colored surface, or custom slot content. It aligns with Apollo’s Figma patterns for default avatars, profile layouts, stacked groups, and rows with supporting text.\n\n## When to use\n\n- **Default (no `variant`)** — Inline UI: tables, nav, comments, lists. Supports image (`src`), initials from `name`, and an optional status dot (`status`).\n- **Profile (`variant=\"profile\"`)** — Large avatars for profile pages and settings surfaces; optional `status` dot uses the same badge palette as the default avatar.\n- **Group (`variant=\"group\"`)** — Stacked avatar groups with overflow count (`+N`). The `status` prop is not used (status dots are not shown for groups).\n- **With Text (`variant=\"with-text\"`)** — Horizontal layout with avatar paired with name and optional sub-text; optional `status` on the avatar image.\n\n\n| Variant | Purpose | `status` dot |\n| ----------- | ------------------------------------------------------ | ------------ |\n| *(none)* | Standard single avatar | Supported |\n| `profile` | Larger profile-sized avatar for settings/profile pages | Supported |\n| `group` | Stacked avatar group with overflow count (`+N`) | Not shown |\n| `with-text` | Avatar paired with name and optional sub-text | Supported |\n\n\n---\n\n## Quick Start\n\n### Basic Avatar (Image)\n\n```html\n<xpl-avatar name=\"Katie Wilson\" src=\"https://example.com/photo.jpg\"></xpl-avatar>\n```\n\n### Initials Placeholder (No Image)\n\n```html\n<!-- Automatic initials from name -->\n<xpl-avatar name=\"Katie Wilson\" color=\"green\"></xpl-avatar>\n\n<!-- Custom initials via slot -->\n<xpl-avatar color=\"primary\">KW</xpl-avatar>\n```\n\n### With Status Dot\n\nStatus dots are rendered with [`xpl-badge`] using `dot-only` and `bordered`. The `status` prop sets the badge **variant** , so avatar status colors stay aligned with badge semantics across the system.\n\n**Where `status` applies:** default (no `variant`), `profile`, and `with-text`. It does **not** apply to `group` — stacked groups ignore `status`.\n\n**`status` values** (same names as `xpl-badge` `variant` palette values):\n\n\n| `status` | Badge palette | Typical meaning (choose per product copy) |\n| -------- | ---------------- | ----------------------------------------- |\n| `purple` | Purple (default) | Default / general presence |\n| `green` | Green | Positive, available, success-aligned |\n| `yellow` | Yellow | Caution, pending, away, warning-aligned |\n| `orange` | Orange | Attention, busy, secondary emphasis |\n| `gray` | Gray | Neutral, offline, inactive |\n| `red` | Red | Error, do not disturb, critical |\n| `blue` | Blue | Informational, notifications |\n\n\n```html\n<xpl-avatar name=\"Alex Chen\" src=\"photo.jpg\" status=\"green\"></xpl-avatar>\n<xpl-avatar name=\"Jordan Lee\" status=\"red\"></xpl-avatar>\n<xpl-avatar name=\"Sam Smith\" status=\"gray\"></xpl-avatar>\n<xpl-avatar variant=\"with-text\" name=\"Riley Park\" sub-text=\"Designer\" src=\"photo.jpg\" status=\"blue\"></xpl-avatar>\n```\n\n### Clickable Avatar (Link)\n\n```html\n<xpl-avatar name=\"Profile\" src=\"photo.jpg\" href=\"/profile\" target=\"_blank\"></xpl-avatar>\n```\n\n---\n\n## Variant Examples\n\n### Profile Avatar (Larger Size)\n\nFor profile pages and settings surfaces. Optional `status` uses the same badge palette as other non-group variants.\n\n```html\n<!-- Large profile avatar (144px) -->\n<xpl-avatar variant=\"profile\" name=\"Katie Wilson\" src=\"photo.jpg\"></xpl-avatar>\n\n<!-- With status dot -->\n<xpl-avatar variant=\"profile\" name=\"Katie Wilson\" src=\"photo.jpg\" status=\"green\"></xpl-avatar>\n\n<!-- Small profile avatar (80px) -->\n<xpl-avatar variant=\"profile\" name=\"Jordan Lee\" size=\"sm\"></xpl-avatar>\n```\n\n### Avatar Group (Stacked)\n\nDisplays up to 4 visible avatars with a `+N` overflow pill for additional members. The `status` prop is not used in this layout (no per-avatar or group-level status dot).\n\n```html\n<!-- Basic group with JSON data -->\n<xpl-avatar\n variant=\"group\"\n group-data='[\n {\"name\": \"Alex\", \"color\": \"green\"},\n {\"name\": \"Jordan\", \"color\": \"yellow\"},\n {\"name\": \"Sam\", \"color\": \"pink\"},\n {\"src\": \"https://example.com/photo.jpg\", \"name\": \"Dana\"},\n {\"name\": \"Extra User\"}\n ]'\n></xpl-avatar>\n\n<!-- Medium group -->\n<xpl-avatar variant=\"group\" size=\"md\" group-data='[...]'></xpl-avatar>\n\n<!-- Small group -->\n<xpl-avatar variant=\"group\" size=\"sm\" group-data='[...]'></xpl-avatar>\n```\n\n**Group data format:**\n\n```typescript\ninterface AvatarGroupItem {\n src?: string; // Image URL (optional)\n name?: string; // Used for initials and alt text\n color?: 'green' | 'yellow' | 'pink' | 'primary' | 'secondary';\n}\n```\n\n### Avatar with Text\n\nHorizontal layout with avatar + name + optional sub-text (e.g., email).\n\n```html\n<!-- Basic with-text -->\n<xpl-avatar\n variant=\"with-text\"\n name=\"Katie Wilson\"\n sub-text=\"katie@example.com\"\n src=\"photo.jpg\"\n></xpl-avatar>\n\n<!-- Clickable version -->\n<xpl-avatar\n variant=\"with-text\"\n name=\"View Profile\"\n sub-text=\"Product Designer\"\n src=\"photo.jpg\"\n href=\"/profile\"\n></xpl-avatar>\n\n<!-- With status dot on the avatar -->\n<xpl-avatar\n variant=\"with-text\"\n name=\"Katie Wilson\"\n sub-text=\"katie@example.com\"\n src=\"photo.jpg\"\n status=\"green\"\n></xpl-avatar>\n```\n\n---\n\n## Size Options\n\n\n| Size | Default Avatar | Profile Avatar | Group |\n| -------- | -------------- | -------------- | ------------------ |\n| *(none)* | 40×40px | 144×144px | 40×40px per avatar |\n| `md` | 32×32px | — | 32×32px per avatar |\n| `sm` | 24×24px | 80×80px | 24×24px per avatar |\n\n\n---\n\n## Status vs placeholder `color`\n\n- **`status`** — Badge palette for the **status dot** (`purple` | `green` | `yellow` | `orange` | `gray` | `red` | `blue`). Passed through to `xpl-badge` as `variant`. Not used when `variant=\"group\"`.\n- **`color`** — Placeholder **surface** behind initials when there is no `src` (`green` | `yellow` | `pink` | `primary` | `secondary`). Unrelated to the status dot.\n\n## Color Options (Placeholder Backgrounds)\n\nUse `color` when no `src` is provided to set the placeholder background:\n\n- `green` — Positive accent\n- `yellow` — Highlight accent\n- `pink` — Pink accent\n- `primary` — Brand primary\n- `secondary` — Action primary (purple)\n\n---\n\n## Design tokens\n\nThese are the main Apollo Foundation tokens used in `packages/apollo-core/src/css/avatar.css`. Use them when overriding or migrating styles.\n\n| Role | Token(s) |\n| ---- | -------- |\n| Circular shape | `var(--xpl-border-radius-full)` |\n| Placeholder surface (default) | `var(--xpl-background-brand-secondary)`, `var(--xpl-text-inverse)` |\n| Placeholder `green` / `yellow` / `pink` | `var(--xpl-background-accent-positive)` / `var(--xpl-background-accent-highlight)` / `var(--xpl-background-accent-pink)` with `var(--xpl-text-inverse-on-light)` where applicable |\n| Placeholder `primary` / `secondary` | `var(--xpl-background-accent-brand)` / `var(--xpl-background-brand-secondary)` |\n| Link hover overlay | `var(--xpl-background-surface-transparent-25)` |\n| Focus outline | `var(--xpl-border-accent-default)` base; `color` modifiers use `var(--xpl-border-positive)`, `var(--xpl-border-accent-highlight)`, `var(--xpl-border-accent-brand)`, etc. (`outline` / `outline-offset` per `avatar.css`) |\n| With-text primary line | `var(--xpl-text-strong)`, `var(--xpl-font-size-title-5)`, `var(--xpl-font-weight-medium)` |\n| With-text secondary line | `var(--xpl-text-subdued)`, `var(--xpl-font-size-body)` |\n| Group overflow pill | `var(--xpl-background-surface-subtle)`, `var(--xpl-text-subdued)` |\n| Group avatar ring | `box-shadow` using `var(--xpl-border-large)` and `var(--xpl-background-surface-default)` |\n| Width / height | `var(--xpl-size-*)` for standard sizes; profile default uses `var(--xpl-size-900)` (144px) |\n| Spacing & overlap | `var(--xpl-space-*)`, `var(--xpl-z-index-*)` |\n\n**Status dots** are styled by `xpl-badge`; see [`xpl-badge` readme](../xpl-badge/readme.md) for badge token usage.\n\n---\n\n## Accessibility\n\n- `name` is required for proper `alt` text on images and screen reader announcements\n- **Status dots** are implemented via `xpl-badge` and marked `aria-hidden` (purely visual); convey meaning in surrounding UI copy or labels if required\n- **Group overflow** includes `aria-label=\"{count} more\"` for screen readers\n- **Links** use native `<a>` elements with full keyboard support\n- **Disabled state**: Use `disabled` prop to disable link behavior while keeping visual styles\n- **Focus management**: All interactive avatars (links) use `:focus-visible` for keyboard focus indicators\n\n---\n\n## Best Practices\n\n1. **Always provide `name`** — Essential for accessibility (alt text and screen readers; for placeholder initials, slot input has higher priority than the value passed in `name`)\n2. **Use `color` for placeholder consistency** — Assign consistent colors to users based on ID or name hash\n3. **Limit group data** — While the component handles any number, consider capping at reasonable numbers for UX\n4. **Slot content** — Use the default slot sparingly; prefer `name` prop for consistent initials generation\n\n---\n\n## Migration Notes\n\n### Status Dot Implementation:\n\n**What changed:** Status dots are implemented with `xpl-badge` (`dot-only` + `bordered`). The `status` prop uses the **badge color palette** (`purple`, `green`, `yellow`, `orange`, `gray`, `red`, `blue`) — the same names as `xpl-badge` `variant` — so avatar status stays consistent with badge semantics.\n\n**Impact:**\n\n- **Internal markup:** The status dot renders as `<xpl-badge dot-only bordered variant=\"...\">` (with `variant` from `status`), not legacy `.xpl-avatar__dot--` classes.\n- **CSS targeting:** Custom selectors like `.xpl-avatar__dot--active` / `--warning` / `--inactive` are not used. Target `.xpl-avatar .xpl-badge--dot-only` if you must override styles.\n- **Prop values:** Use palette names above. Older examples sometimes used labels like `active` / `warning` / `inactive`; map those concepts to the palette (e.g. available → `green`, caution → `yellow`, offline → `gray`) per your design guidelines.\n\n**Recommended migration:**\n\n1. Replace custom CSS on `.xpl-avatar__dot--` with `.xpl-avatar .xpl-badge--dot-only` if needed\n2. Set `status` to the badge palette value that matches the intended color (see the status table in this readme)\n3. Remember `status` applies to default, `profile`, and `with-text` only — not `group`\n\n### Legacy `status` values — scheduled for removal (next major release)\n\n**These legacy string values are deprecated.** They exist only for backward compatibility with older integrations. They **will be removed** in the **next major** version of `@xplortech/apollo-core`. Plan your migration now; do not introduce new usage of the legacy names.\n\n| Deprecated `status` | Current mapping (temporary) | Replace with (badge palette) |\n| ------------------- | --------------------------- | ---------------------------- |\n| `active` | `green` | `green` |\n| `inactive` | `gray` | `gray` |\n| `warning` | `red` | `red` |\n\n**Why:** Status dots use the same vocabulary as `xpl-badge` variants (`purple`, `green`, `yellow`, `orange`, `gray`, `red`, `blue`). The old semantic aliases (`active` / `warning` / `inactive`) duplicate that meaning with different names and increase maintenance cost, so they are being dropped from the public API.\n\n**Action items before the major release:**\n\n1. Search your codebase for `status=\"active\"`, `status=\"inactive\"`, and `status=\"warning\"` on `<xpl-avatar>` (and framework wrappers).\n2. Replace each with the **`green`**, **`gray`**, or **`red`** value from the table above, matching your product intent.\n3. Re-test visuals: the mapped colors are unchanged today; after removal, only palette names will be accepted.\n\n### Component Dependency\n\nThis component now depends on `xpl-badge`. Ensure `xpl-badge` is loaded in your application when using avatars with status dots.\n\n",
|
|
510
|
+
"readme": "# xpl-avatar\n\nThe **Avatar** component shows a person or entity: a photo, initials on a colored surface, or custom slot content. It aligns with Apollo’s Figma patterns for default avatars, profile layouts, stacked groups, and rows with supporting text.\n\n## When to use\n\n- **Default (no `variant`)** — Inline UI: tables, nav, comments, lists. Supports image (`src`), initials from `name`, and an optional status dot (`status`).\n- **Profile (`variant=\"profile\"`)** — Large avatars for profile pages and settings surfaces; optional `status` dot uses the same badge palette as the default avatar.\n- **Group (`variant=\"group\"`)** — Stacked avatar groups with overflow count (`+N`). The `status` prop is not used (status dots are not shown for groups).\n- **With Text (`variant=\"with-text\"`)** — Horizontal layout with avatar paired with name and optional sub-text; optional `status` on the avatar image.\n\n\n| Variant | Purpose | `status` dot |\n| ----------- | ------------------------------------------------------ | ------------ |\n| *(none)* | Standard single avatar | Supported |\n| `profile` | Larger profile-sized avatar for settings/profile pages | Supported |\n| `group` | Stacked avatar group with overflow count (`+N`) | Not shown |\n| `with-text` | Avatar paired with name and optional sub-text | Supported |\n\n\n---\n\n## Quick Start\n\n### Basic Avatar (Image)\n\n```html\n<xpl-avatar name=\"Katie Wilson\" src=\"https://example.com/photo.jpg\"></xpl-avatar>\n```\n\n### Initials Placeholder (No Image)\n\n```html\n<!-- Automatic initials from name -->\n<xpl-avatar name=\"Katie Wilson\" color=\"green\"></xpl-avatar>\n\n<!-- Custom initials via slot -->\n<xpl-avatar color=\"primary\">KW</xpl-avatar>\n```\n\n### With Status Dot\n\nStatus dots are rendered with [`xpl-badge`] using `dot-only` and `bordered`. The `status` prop sets the badge **variant** , so avatar status colors stay aligned with badge semantics across the system.\n\n**Where `status` applies:** default (no `variant`), `profile`, and `with-text`. It does **not** apply to `group` — stacked groups ignore `status`.\n\n**`status` values** (same names as `xpl-badge` `variant` palette values):\n\n\n| `status` | Badge palette | Typical meaning (choose per product copy) |\n| -------- | ---------------- | ----------------------------------------- |\n| `purple` | Purple (default) | Default / general presence |\n| `green` | Green | Positive, available, success-aligned |\n| `yellow` | Yellow | Caution, pending, away, warning-aligned |\n| `orange` | Orange | Attention, busy, secondary emphasis |\n| `gray` | Gray | Neutral, offline, inactive |\n| `red` | Red | Error, do not disturb, critical |\n| `blue` | Blue | Informational, notifications |\n\n\n```html\n<xpl-avatar name=\"Alex Chen\" src=\"photo.jpg\" status=\"green\"></xpl-avatar>\n<xpl-avatar name=\"Jordan Lee\" status=\"red\"></xpl-avatar>\n<xpl-avatar name=\"Sam Smith\" status=\"gray\"></xpl-avatar>\n<xpl-avatar variant=\"with-text\" name=\"Riley Park\" sub-text=\"Designer\" src=\"photo.jpg\" status=\"blue\"></xpl-avatar>\n```\n\n### Clickable Avatar (Link)\n\n```html\n<xpl-avatar name=\"Profile\" src=\"photo.jpg\" href=\"/profile\" target=\"_blank\"></xpl-avatar>\n```\n\n---\n\n## Variant Examples\n\n### Profile Avatar (Larger Size)\n\nFor profile pages and settings surfaces. Optional `status` uses the same badge palette as other non-group variants.\n\n```html\n<!-- Large profile avatar (144px) -->\n<xpl-avatar variant=\"profile\" name=\"Katie Wilson\" src=\"photo.jpg\"></xpl-avatar>\n\n<!-- With status dot -->\n<xpl-avatar variant=\"profile\" name=\"Katie Wilson\" src=\"photo.jpg\" status=\"green\"></xpl-avatar>\n\n<!-- Small profile avatar (80px) -->\n<xpl-avatar variant=\"profile\" name=\"Jordan Lee\" size=\"sm\"></xpl-avatar>\n```\n\n### Avatar Group (Stacked)\n\nDisplays up to 4 visible avatars with a `+N` overflow pill for additional members. The `status` prop is not used in this layout (no per-avatar or group-level status dot).\n\n```html\n<!-- Basic group with JSON data -->\n<xpl-avatar\n variant=\"group\"\n group-data='[\n {\"name\": \"Alex\", \"color\": \"green\"},\n {\"name\": \"Jordan\", \"color\": \"yellow\"},\n {\"name\": \"Sam\", \"color\": \"pink\"},\n {\"src\": \"https://example.com/photo.jpg\", \"name\": \"Dana\"},\n {\"name\": \"Extra User\"}\n ]'\n></xpl-avatar>\n\n<!-- Medium group -->\n<xpl-avatar variant=\"group\" size=\"md\" group-data='[...]'></xpl-avatar>\n\n<!-- Small group -->\n<xpl-avatar variant=\"group\" size=\"sm\" group-data='[...]'></xpl-avatar>\n```\n\n**Group data format:**\n\n```typescript\ninterface AvatarGroupItem {\n src?: string; // Image URL (optional)\n name?: string; // Used for initials and alt text\n color?: 'green' | 'yellow' | 'pink' | 'primary' | 'secondary';\n}\n```\n\n### Avatar with Text\n\nHorizontal layout with avatar + name + optional sub-text (e.g., email).\n\n```html\n<!-- Basic with-text -->\n<xpl-avatar\n variant=\"with-text\"\n name=\"Katie Wilson\"\n sub-text=\"katie@example.com\"\n src=\"photo.jpg\"\n></xpl-avatar>\n\n<!-- Clickable version -->\n<xpl-avatar\n variant=\"with-text\"\n name=\"View Profile\"\n sub-text=\"Product Designer\"\n src=\"photo.jpg\"\n href=\"/profile\"\n></xpl-avatar>\n\n<!-- With status dot on the avatar -->\n<xpl-avatar\n variant=\"with-text\"\n name=\"Katie Wilson\"\n sub-text=\"katie@example.com\"\n src=\"photo.jpg\"\n status=\"green\"\n></xpl-avatar>\n```\n\n---\n\n## Size Options\n\n\n| Size | Default Avatar | Profile Avatar | Group |\n| -------- | -------------- | -------------- | ------------------ |\n| *(none)* | 40×40px | 144×144px | 40×40px per avatar |\n| `md` | 32×32px | — | 32×32px per avatar |\n| `sm` | 24×24px | 80×80px | 24×24px per avatar |\n\n\n---\n\n## Status vs placeholder `color`\n\n- **`status`** — Badge palette for the **status dot** (`purple` | `green` | `yellow` | `orange` | `gray` | `red` | `blue`). Passed through to `xpl-badge` as `variant`. Not used when `variant=\"group\"`.\n- **`color`** — Placeholder **surface** behind initials when there is no `src` (`green` | `yellow` | `pink` | `primary` | `secondary`). Unrelated to the status dot.\n\n## Color Options (Placeholder Backgrounds)\n\nUse `color` when no `src` is provided to set the placeholder background:\n\n- `green` — Positive accent\n- `yellow` — Highlight accent\n- `pink` — Pink accent\n- `primary` — Brand primary\n- `secondary` — Action primary (purple)\n\n---\n\n## Design tokens\n\nThese are the main Apollo Foundation tokens used in `packages/apollo-core/src/components/xpl-avatar/avatar.css`. Use them when overriding or migrating styles.\n\n| Role | Token(s) |\n| ---- | -------- |\n| Circular shape | `var(--xpl-border-radius-full)` |\n| Placeholder surface (default) | `var(--xpl-background-brand-secondary)`, `var(--xpl-text-inverse)` |\n| Placeholder `green` / `yellow` / `pink` | `var(--xpl-background-accent-positive)` / `var(--xpl-background-accent-highlight)` / `var(--xpl-background-accent-pink)` with `var(--xpl-text-inverse-on-light)` where applicable |\n| Placeholder `primary` / `secondary` | `var(--xpl-background-accent-brand)` / `var(--xpl-background-brand-secondary)` |\n| Link hover overlay | `var(--xpl-background-surface-transparent-25)` |\n| Focus outline | `var(--xpl-border-accent-default)` base; `color` modifiers use `var(--xpl-border-positive)`, `var(--xpl-border-accent-highlight)`, `var(--xpl-border-accent-brand)`, etc. (`outline` / `outline-offset` per `avatar.css`) |\n| With-text primary line | `var(--xpl-text-strong)`, `var(--xpl-font-size-title-5)`, `var(--xpl-font-weight-medium)` |\n| With-text secondary line | `var(--xpl-text-subdued)`, `var(--xpl-font-size-body)` |\n| Group overflow pill | `var(--xpl-background-surface-subtle)`, `var(--xpl-text-subdued)` |\n| Group avatar ring | `box-shadow` using `var(--xpl-border-large)` and `var(--xpl-background-surface-default)` |\n| Width / height | `var(--xpl-size-*)` for standard sizes; profile default uses `var(--xpl-size-900)` (144px) |\n| Spacing & overlap | `var(--xpl-space-*)`, `var(--xpl-z-index-*)` |\n\n**Status dots** are styled by `xpl-badge`; see [`xpl-badge` readme](../xpl-badge/readme.md) for badge token usage.\n\n---\n\n## Accessibility\n\n- `name` is required for proper `alt` text on images and screen reader announcements\n- **Status dots** are implemented via `xpl-badge` and marked `aria-hidden` (purely visual); convey meaning in surrounding UI copy or labels if required\n- **Group overflow** includes `aria-label=\"{count} more\"` for screen readers\n- **Links** use native `<a>` elements with full keyboard support\n- **Disabled state**: Use `disabled` prop to disable link behavior while keeping visual styles\n- **Focus management**: All interactive avatars (links) use `:focus-visible` for keyboard focus indicators\n\n---\n\n## Best Practices\n\n1. **Always provide `name`** — Essential for accessibility (alt text and screen readers; for placeholder initials, slot input has higher priority than the value passed in `name`)\n2. **Use `color` for placeholder consistency** — Assign consistent colors to users based on ID or name hash\n3. **Limit group data** — While the component handles any number, consider capping at reasonable numbers for UX\n4. **Slot content** — Use the default slot sparingly; prefer `name` prop for consistent initials generation\n\n---\n\n## Migration Notes\n\n### Status Dot Implementation:\n\n**What changed:** Status dots are implemented with `xpl-badge` (`dot-only` + `bordered`). The `status` prop uses the **badge color palette** (`purple`, `green`, `yellow`, `orange`, `gray`, `red`, `blue`) — the same names as `xpl-badge` `variant` — so avatar status stays consistent with badge semantics.\n\n**Impact:**\n\n- **Internal markup:** The status dot renders as `<xpl-badge dot-only bordered variant=\"...\">` (with `variant` from `status`), not legacy `.xpl-avatar__dot--` classes.\n- **CSS targeting:** Custom selectors like `.xpl-avatar__dot--active` / `--warning` / `--inactive` are not used. Target `.xpl-avatar .xpl-badge--dot-only` if you must override styles.\n- **Prop values:** Use palette names above. Older examples sometimes used labels like `active` / `warning` / `inactive`; map those concepts to the palette (e.g. available → `green`, caution → `yellow`, offline → `gray`) per your design guidelines.\n\n**Recommended migration:**\n\n1. Replace custom CSS on `.xpl-avatar__dot--` with `.xpl-avatar .xpl-badge--dot-only` if needed\n2. Set `status` to the badge palette value that matches the intended color (see the status table in this readme)\n3. Remember `status` applies to default, `profile`, and `with-text` only — not `group`\n\n### Legacy `status` values — scheduled for removal (next major release)\n\n**These legacy string values are deprecated.** They exist only for backward compatibility with older integrations. They **will be removed** in the **next major** version of `@xplortech/apollo-core`. Plan your migration now; do not introduce new usage of the legacy names.\n\n| Deprecated `status` | Current mapping (temporary) | Replace with (badge palette) |\n| ------------------- | --------------------------- | ---------------------------- |\n| `active` | `green` | `green` |\n| `inactive` | `gray` | `gray` |\n| `warning` | `red` | `red` |\n\n**Why:** Status dots use the same vocabulary as `xpl-badge` variants (`purple`, `green`, `yellow`, `orange`, `gray`, `red`, `blue`). The old semantic aliases (`active` / `warning` / `inactive`) duplicate that meaning with different names and increase maintenance cost, so they are being dropped from the public API.\n\n**Action items before the major release:**\n\n1. Search your codebase for `status=\"active\"`, `status=\"inactive\"`, and `status=\"warning\"` on `<xpl-avatar>` (and framework wrappers).\n2. Replace each with the **`green`**, **`gray`**, or **`red`** value from the table above, matching your product intent.\n3. Re-test visuals: the mapped colors are unchanged today; after removal, only palette names will be accepted.\n\n### Component Dependency\n\nThis component now depends on `xpl-badge`. Ensure `xpl-badge` is loaded in your application when using avatars with status dots.\n\n",
|
|
511
511
|
"docs": "The **Avatar** component shows a person or entity: a photo, initials on a colored surface, or custom slot content. It aligns with Apollo’s Figma patterns for default avatars, profile layouts, stacked groups, and rows with supporting text.",
|
|
512
512
|
"docsTags": [
|
|
513
513
|
{
|
|
@@ -530,8 +530,8 @@
|
|
|
530
530
|
"references": {
|
|
531
531
|
"AvatarColor": {
|
|
532
532
|
"location": "local",
|
|
533
|
-
"path": "/home/runner/work/apollo/apollo/packages/apollo-core/src/components/
|
|
534
|
-
"id": "src/components/
|
|
533
|
+
"path": "/home/runner/work/apollo/apollo/packages/apollo-core/src/components/xpl-avatar/xpl-avatar.tsx",
|
|
534
|
+
"id": "src/components/xpl-avatar/xpl-avatar.tsx::AvatarColor"
|
|
535
535
|
}
|
|
536
536
|
}
|
|
537
537
|
},
|
|
@@ -605,8 +605,8 @@
|
|
|
605
605
|
"references": {
|
|
606
606
|
"AvatarGroupItem": {
|
|
607
607
|
"location": "local",
|
|
608
|
-
"path": "/home/runner/work/apollo/apollo/packages/apollo-core/src/components/
|
|
609
|
-
"id": "src/components/
|
|
608
|
+
"path": "/home/runner/work/apollo/apollo/packages/apollo-core/src/components/xpl-avatar/xpl-avatar.tsx",
|
|
609
|
+
"id": "src/components/xpl-avatar/xpl-avatar.tsx::AvatarGroupItem"
|
|
610
610
|
}
|
|
611
611
|
}
|
|
612
612
|
},
|
|
@@ -734,8 +734,8 @@
|
|
|
734
734
|
"references": {
|
|
735
735
|
"AvatarStatus": {
|
|
736
736
|
"location": "local",
|
|
737
|
-
"path": "/home/runner/work/apollo/apollo/packages/apollo-core/src/components/
|
|
738
|
-
"id": "src/components/
|
|
737
|
+
"path": "/home/runner/work/apollo/apollo/packages/apollo-core/src/components/xpl-avatar/xpl-avatar.tsx",
|
|
738
|
+
"id": "src/components/xpl-avatar/xpl-avatar.tsx::AvatarStatus"
|
|
739
739
|
}
|
|
740
740
|
}
|
|
741
741
|
},
|
|
@@ -852,8 +852,8 @@
|
|
|
852
852
|
"references": {
|
|
853
853
|
"AvatarVariant": {
|
|
854
854
|
"location": "local",
|
|
855
|
-
"path": "/home/runner/work/apollo/apollo/packages/apollo-core/src/components/
|
|
856
|
-
"id": "src/components/
|
|
855
|
+
"path": "/home/runner/work/apollo/apollo/packages/apollo-core/src/components/xpl-avatar/xpl-avatar.tsx",
|
|
856
|
+
"id": "src/components/xpl-avatar/xpl-avatar.tsx::AvatarVariant"
|
|
857
857
|
}
|
|
858
858
|
}
|
|
859
859
|
},
|
|
@@ -910,7 +910,7 @@
|
|
|
910
910
|
}
|
|
911
911
|
},
|
|
912
912
|
{
|
|
913
|
-
"filePath": "src/components/
|
|
913
|
+
"filePath": "src/components/xpl-backdrop/xpl-backdrop.tsx",
|
|
914
914
|
"encapsulation": "none",
|
|
915
915
|
"tag": "xpl-backdrop",
|
|
916
916
|
"readme": "# xpl-backdrop\n\nThis backdrop is used to add a transparent darker layer on top of the content area to focus the user’s attention. Typically used when a dialog such as a modal or slide out panel is active. \n\n### Design Tokens\n\nTokens used by this component from `@xplortech/apollo-foundation`.\n\n**Color**\n- `--xpl-background-surface-backdrop` — backdrop scrim fill. The token bakes the neutral alpha into the color (`rgba(48 45 59 / 0.5)` light / `rgba(48 45 59 / 0.75)` dark), so the standalone `opacity` property was removed to avoid double-dimming. It themes automatically — no `.dark` override.\n",
|
|
@@ -987,7 +987,7 @@
|
|
|
987
987
|
}
|
|
988
988
|
},
|
|
989
989
|
{
|
|
990
|
-
"filePath": "src/components/
|
|
990
|
+
"filePath": "src/components/xpl-badge/xpl-badge.tsx",
|
|
991
991
|
"encapsulation": "none",
|
|
992
992
|
"tag": "xpl-badge",
|
|
993
993
|
"readme": "# xpl-badge\n\n`xpl-badge` is a small, non-interactive status indicator used to communicate counts, states, or supplementary information next to another element. Badges are **never clickable** – use a button or link if you need interaction.\n\nBadges support multiple **variants** (colors), **sizes**, **shapes**, and **dot styles**, so they can be used both as pill labels and as compact status / notification indicators.\n\n## Usage\n\n```html\n<xpl-badge variant=\"green\">Active</xpl-badge>\n<xpl-badge variant=\"yellow\">Pending</xpl-badge>\n<xpl-badge variant=\"red\">Error</xpl-badge>\n<xpl-badge variant=\"gray\" size=\"small\">Draft</xpl-badge>\n```\n\nAttach badges close to the item they describe (a label, row, chip, or control). Prefer **short labels** (often one or two words) for readability.\n\n### Label text and overflow\n\nSlot content is rendered inside an internal `.xpl-badge__label` wrapper (you do not add this in your markup). Labels are **single-line**: text does not wrap to multiple lines. When horizontal space is tight (for example a narrow column or flex layout), overflowing text **truncates with an ellipsis** (`…`). The host respects the parent width (`max-width: 100%`). If truncation makes a label hard to read, shorten the copy or widen the layout; use a tooltip or similar only if your product needs the full string on hover.\n\n## Sizes & shapes\n\n- **size**\n - `default` (default): `24px` tall pill, used for most cases.\n - `small`: `20px` tall, more compact for dense UIs or table rows.\n- **shape**\n - `rounded` (default): full pill with fully rounded ends.\n - `boxy`: rounded corners but not a full pill; better for more neutral / data-heavy contexts.\n\n```html\n<xpl-badge size=\"default\" shape=\"rounded\">Default pill</xpl-badge>\n<xpl-badge size=\"small\" shape=\"boxy\">Small boxy</xpl-badge>\n```\n\n## Dots and dot-only badges\n\n### Dot badge (pill with leading dot)\n\nSet `dot` to add a colored dot before the text, inside the pill:\n\n```html\n<xpl-badge variant=\"green\" dot>Online</xpl-badge>\n<xpl-badge variant=\"yellow\" dot>Syncing</xpl-badge>\n<xpl-badge variant=\"red\" dot>Error</xpl-badge>\n```\n\n### Dot-only badge (compact status / count)\n\n> [!IMPORTANT]\n> Dot-only badges are meant to be used with **numeric values** (or very short strings). For longer text labels, use the standard badge (without `dot-only`).\n\n- When overlaying another element with a background color, use the `bordered` property so the badge separates clearly from what is behind it.\n\nSet `dot-only` when you want a badge built around the dot:\n\n- With **no children**: renders a small circular status dot.\n- With **children**: renders a compact pill with text or a number inside (for example an unread count).\n- **Notification-style counts** are often appended to a label or another component. Dot-only label text follows the same **single-line truncation** rules as standard badges when space is limited.\n- Use **`bordered`** to toggle a ring around the dot badge for separation from an avatar or similar surface.\n\n```html\n<!-- Status dot only -->\n<xpl-badge variant=\"green\" dot-only></xpl-badge>\n\n<!-- Dot with count / text -->\n<xpl-badge variant=\"red\" dot-only>3</xpl-badge>\n<xpl-badge variant=\"blue\" dot-only>99+</xpl-badge>\n```\n\n## Variants\n\nUse variants to communicate state or category. Preferred values for `variant`:\n\n- `purple` (default)\n- `green`\n- `yellow`\n- `orange`\n- `gray`\n- `red`\n- `blue`\n\nThe legacy semantic names `success`, `warning`, `inactive`, and `error` are still accepted and map to `green`, `yellow`, `gray`, and `red` respectively. Prefer the color names for new code.\n\n```html\n<xpl-badge variant=\"purple\">Default</xpl-badge>\n<xpl-badge variant=\"orange\" dot>In progress</xpl-badge>\n<xpl-badge variant=\"blue\" dot-only>12</xpl-badge>\n```\n\n- Each dot has **stronger solid color** for dot-only badges, with dark-mode adjustments handled by CSS.\n\n- Each variant uses Apollo Foundation badge tokens (`--xpl-background-badge-`*, `--xpl-border-badge-*`, `--xpl-icon-badge-*`, `--xpl-text-badge-*`) that auto-switch between light and dark modes. Dot-only badges use the corresponding `--xpl-icon-badge-*` accent color for their solid fill.\n\n### Design Tokens\n\nTokens used by this component from `@xplortech/apollo-foundation`.\n\n**Color**\n- `--xpl-background-badge-{default,green,yellow,grey,blue,red}` — variant backgrounds\n- `--xpl-border-badge-{purple,green,yellow,grey,blue,red}` — variant borders\n- `--xpl-text-badge-{default,green,yellow,gray,blue,red}` — variant text colors\n- `--xpl-icon-badge-{default,green,yellow,grey,blue,red}` — dot / dot-only fill\n- `--xpl-text-inverse` — dot-only text (green, blue, red)\n- `--xpl-text-strong` — orange variant text\n- `--xpl-border-inverse` — dot-only bordered ring\n- `--xpl-color-transparent-0` — dot-only / orange transparent border\n- `--xpl-color-neutral-1100` — dot-only text on yellow, gray, orange\n- `--xpl-background-surface-transparent-0` — orange background (dark mode)\n- `--xpl-background-accent-brand` — orange dot/dot-only fill (tech debt)\n- `--xpl-color-orange-{100,300}` — orange variant primitives (tech debt)\n\n**Spacing**\n- `--xpl-space-{2,4,8,12}` — padding variants\n\n**Sizing**\n- `--xpl-size-{150,125,050}` — height / dot sizes\n- `0.875rem` literal — dot-only badge height/min-width (no 14px Foundation token; tech debt)\n\n**Typography**\n- `--xpl-font-family-default` — font family\n- Default badge extends `.xpl-text-title-5` (Figma `Title/5`); small badge extends `.xpl-text-callout-bold` (Figma `Callout/Bold`)\n- `0.5rem` literal — dot-only (number) badge font-size/line-height (no 8px Foundation token or typography level; tech debt)\n\n**Border**\n- `--xpl-border-small` — border width (1px)\n- `--xpl-border-radius-{full,small}` — shape variants\n",
|
|
@@ -1162,8 +1162,8 @@
|
|
|
1162
1162
|
"references": {
|
|
1163
1163
|
"BadgeVariantProp": {
|
|
1164
1164
|
"location": "local",
|
|
1165
|
-
"path": "/home/runner/work/apollo/apollo/packages/apollo-core/src/components/
|
|
1166
|
-
"id": "src/components/
|
|
1165
|
+
"path": "/home/runner/work/apollo/apollo/packages/apollo-core/src/components/xpl-badge/xpl-badge.tsx",
|
|
1166
|
+
"id": "src/components/xpl-badge/xpl-badge.tsx::BadgeVariantProp"
|
|
1167
1167
|
}
|
|
1168
1168
|
}
|
|
1169
1169
|
},
|
|
@@ -1261,7 +1261,7 @@
|
|
|
1261
1261
|
}
|
|
1262
1262
|
},
|
|
1263
1263
|
{
|
|
1264
|
-
"filePath": "src/components/
|
|
1264
|
+
"filePath": "src/components/xpl-banner/xpl-banner.tsx",
|
|
1265
1265
|
"encapsulation": "none",
|
|
1266
1266
|
"tag": "xpl-banner",
|
|
1267
1267
|
"readme": "# xpl-banner\n\nBanners display a system level or page level message at the top of the screen. The section-banner variant displays important messages inline within a section.\n\n## Usage\n\n### Web component (`<xpl-banner>`)\n\nBar layout (default) with heading, description, primary action, and dismiss:\n\n```html\n<xpl-banner\n appearance=\"information\"\n heading=\"Your session will expire soon.\"\n description=\"Save your work to avoid losing changes.\"\n action-text=\"Extend session\"\n is-dismissible=\"true\"\n></xpl-banner>\n```\n\nSection layout with optional secondary action and no leading icon:\n\n```html\n<xpl-banner\n appearance=\"positive\"\n is-section=\"true\"\n has-icon=\"false\"\n heading=\"Changes saved\"\n description=\"Your updates are stored.\"\n action-text=\"View details\"\n secondary-action-text=\"Undo\"\n></xpl-banner>\n```\n\n### Plain HTML (BEM classes)\n\nUse the same structure when styling with `banner.css` without the Stencil component. Switch bar vs section with host modifiers (`xpl-banner--section`, `xpl-banner--no-icon`, `xpl-banner--{appearance}`).\n\n## Accessibility\n\n`xpl-banner` uses `role=\"region\"` so the banner is a navigable landmark.\n\n**`aria-label` on the host (never empty):**\n\n| Layout | `aria-label` source |\n| ------ | ------------------- |\n| Bar (default) | Fixed label from `appearance`: `\"Information banner\"`, `\"Positive banner\"`, `\"Warning banner\"`, or `\"Error banner\"`. |\n| Section | Trimmed `heading` when present; otherwise `\"Section banner\"`. |\n\nKeyboard: **Tab** moves focus to action buttons and the dismiss control; **Enter** and **Space** activate `xpl-button` actions and the dismiss button. Focus rings use `:focus-visible` (dismiss uses appearance-specific outline tokens in CSS; actions use `xpl-button` focus styles).\n\n- The leading icon wrapper carries `aria-hidden=\"true\"` — the icon is decorative; the message text is the accessible content.\n- The dismiss `<xpl-icon>` inside the dismiss button also carries `aria-hidden=\"true\"` so the decorative icon is not announced in addition to the button label.\n- The dismiss button `aria-label` is `\"Dismiss banner\"` in bar layout and `\"Dismiss section banner\"` when `is-section` is true.\n\n## Token Use\n\n- `information`\n - Background: `--xpl-background-messaging-information`\n - Border: `--xpl-border-accent-information`\n - Icon: `--xpl-icon-default`\n - Main text: `--xpl-text-strong` (with `--xpl-text-default` fallback)\n - Detail text: `--xpl-text-default`\n- `warning`\n - Background: `--xpl-background-messaging-warning`\n - Border: `--xpl-border-accent-warning`\n - Icon: `--xpl-icon-default`\n - Main text: `--xpl-text-strong` (with `--xpl-text-default` fallback)\n - Detail text: `--xpl-text-default`\n - Dismiss focus ring: `--xpl-border-accent-warning`\n- `positive`\n - Background: `--xpl-background-messaging-positive`\n - Border: `--xpl-border-positive`\n - Icon: `--xpl-icon-default`\n - Main text: `--xpl-text-strong` (with `--xpl-text-default` fallback)\n - Detail text: `--xpl-text-default`\n- `error`\n - Background: `--xpl-background-messaging-negative-bold`\n - Border: `--xpl-border-negative`\n - Icon and text: `--xpl-text-inverse-on-dark`\n - Dismiss focus ring: `--xpl-text-inverse-on-dark`\n- Dismiss button follows the same icon token as the current appearance.\n- `information` dismiss focus ring uses `--xpl-border-accent-information`.\n\nLight and dark mode are handled by Apollo Foundation token definitions. `xpl-banner` does not use component-level `.dark` token overrides.\n\n## Icon Mapping\n\nEach `appearance` value maps to a fixed `xpl-icon` name. When building the component in plain HTML, use the icon from this table:\n\n| `appearance` | `xpl-icon` name |\n| ------------- | ------------------ |\n| `information` | `circle-info` |\n| `warning` | `triangle-warning` |\n| `positive` | `circle-check` |\n| `error` | `octagon-warning` |\n\n## Actions\n\nUse `actionText` and `secondaryActionText` to render up to two `xpl-button` actions in the banner.\nBoth action buttons always render at `size=\"xs\"` to match compact banner spacing.\n\nThe `variant` and `state` attributes on the action buttons depend on both `appearance` and layout:\n\n| Layout | `appearance` | `variant` | `state` |\n| --------- | ------------- | ----------- | ----------- |\n| bar | `information` | `subtle` | — |\n| bar | `warning` | `subtle` | — |\n| bar | `positive` | `subtle` | — |\n| bar | `error` | `primary` | `warning` |\n| section | `information` | `subtle` | — |\n| section | `warning` | `subtle` | — |\n| section | `positive` | `subtle` | `success` |\n| section | `error` | `subtle` | `warning` |\n\n## Section Layout\n\nSet `is-section` to render the section-banner layout:\n- Header row with icon, heading, and optional dismiss\n- Description below the header (2-line clamp by default)\n- Actions below description\n\nSet `has-icon=\"false\"` to hide the leading icon in the section layout. This applies `xpl-banner--no-icon` on the host, which shifts heading, description, and actions to start in the first grid column instead of the second. In bar layout the icon always renders regardless of `hasIcon`.\n\nBar and section variants share the same DOM shape. Plain-HTML example (classes only):\n\n```html\n<!-- Bar variant -->\n<div class=\"xpl-banner xpl-banner--information\">\n <div class=\"xpl-banner__icon\" aria-hidden=\"true\">\n <xpl-icon icon=\"circle-info\" size=\"24\"></xpl-icon>\n </div>\n <div class=\"xpl-banner__body\">\n <p class=\"xpl-banner__heading\">Heading</p>\n <p class=\"xpl-banner__description\">Description text</p>\n </div>\n <div class=\"xpl-banner__actions\">\n <xpl-button size=\"xs\" variant=\"subtle\">Action</xpl-button>\n </div>\n <button class=\"xpl-banner__dismiss\" type=\"button\" aria-label=\"Dismiss banner\">\n <xpl-icon icon=\"xmark\" size=\"24\" aria-hidden=\"true\"></xpl-icon>\n </button>\n</div>\n\n<!-- Section variant — add xpl-banner--section; same markup otherwise -->\n<div class=\"xpl-banner xpl-banner--section xpl-banner--information\">\n ...\n</div>\n\n<!-- Section variant without icon -->\n<div class=\"xpl-banner xpl-banner--section xpl-banner--no-icon xpl-banner--information\">\n <!-- omit .xpl-banner__icon -->\n <div class=\"xpl-banner__body\">...</div>\n ...\n</div>\n```\n",
|
|
@@ -1591,7 +1591,7 @@
|
|
|
1591
1591
|
}
|
|
1592
1592
|
},
|
|
1593
1593
|
{
|
|
1594
|
-
"filePath": "src/components/
|
|
1594
|
+
"filePath": "src/components/xpl-breadcrumbs/xpl-breadcrumb-item/xpl-breadcrumb-item.tsx",
|
|
1595
1595
|
"encapsulation": "none",
|
|
1596
1596
|
"tag": "xpl-breadcrumb-item",
|
|
1597
1597
|
"readme": "# xpl-breadcrumb-item\n\nThe `<xpl-breadcrumb-item>` component has a role of `listitem`. This component should only be used in combination with `<xpl-breadcrumbs>`.\nThis component yields an unnamed slot. Only links and buttons (styled as links) should be used within this component.\n\n",
|
|
@@ -1625,7 +1625,7 @@
|
|
|
1625
1625
|
"dependencyGraph": {}
|
|
1626
1626
|
},
|
|
1627
1627
|
{
|
|
1628
|
-
"filePath": "src/components/
|
|
1628
|
+
"filePath": "src/components/xpl-breadcrumbs/xpl-breadcrumbs/xpl-breadcrumbs.tsx",
|
|
1629
1629
|
"encapsulation": "none",
|
|
1630
1630
|
"tag": "xpl-breadcrumbs",
|
|
1631
1631
|
"readme": "# xpl-breadcrumbs\n\nThe `xpl-breadcrumbs` component is a navigation group. It yields an unnamed slot that is rendered inside a `<ol></ol>` element.\n\nThis component can be used as a wrapper to `<xpl-breadcrumb-item>` components.\n\nThe number of items is not restricted, although per Apollo's design guidelines, a maximum of three items should be used.\nIn small screens (xs), only the 2 deepest items will be visible, even if 3 items are provided.\n\n### Design Tokens\n\nTokens used by this component from `@xplortech/apollo-foundation` (light/dark handled automatically — no `.dark` overrides).\n\n**Color**\n- `--xpl-text-subdued` — breadcrumb list text and the separator glyph\n- `--xpl-text-link-hovered` — hovered breadcrumb item (per Figma node 1536:178167 UX note)\n- `--xpl-text-default` — current page (last item)\n",
|
|
@@ -1659,7 +1659,7 @@
|
|
|
1659
1659
|
"dependencyGraph": {}
|
|
1660
1660
|
},
|
|
1661
1661
|
{
|
|
1662
|
-
"filePath": "src/components/
|
|
1662
|
+
"filePath": "src/components/xpl-button/xpl-button.tsx",
|
|
1663
1663
|
"encapsulation": "none",
|
|
1664
1664
|
"tag": "xpl-button",
|
|
1665
1665
|
"readme": "# xpl-button\n\nButtons allow users to take an action with clear visual hierarchy (variant), semantic meaning (sentiment), and size.\n\n## Usage\n\n> [!IMPORTANT]\n> Older props such as `state` still work, but we recommend using the sentiment described below.\n\n\n### Basic button\n\nPass button text via the default slot (same as native `<button>`):\n\n```html\n<xpl-button>Primary action</xpl-button>\n```\n\n### Variant and sentiment\n\nUse `variant` for style (primary, secondary, tertiary) and `sentiment` for intent (default, positive, negative):\n\n```html\n<xpl-button variant=\"secondary\">Secondary</xpl-button>\n<xpl-button variant=\"tertiary\" sentiment=\"positive\">Positive action</xpl-button>\n<xpl-button sentiment=\"negative\">Destructive</xpl-button>\n```\n\n### Size\n\nUse **`size`** for button size: `default`, `sm` (small), or `xs` (extra small):\n\n```html\n<xpl-button size=\"sm\">Small</xpl-button>\n<xpl-button size=\"xs\">Extra small</xpl-button>\n```\n\n### Icon from Apollo icon library\n\nUse `icon` with a name from the xpl-icon library; use `icon-position` to place the icon at start or end:\n\n```html\n<xpl-button icon=\"download\" icon-position=\"end\">\n Download\n</xpl-button>\n```\n\n### Icon-only button\n\nUse `icon-only` when the button shows only an icon (no label). Always set `icon` and use a descriptive `aria-label` on the host or inner button for accessibility:\n\n```html\n<xpl-button icon-only icon=\"xmark\" aria-label=\"Close\"></xpl-button>\n```\n\n### Loading state\n\nWhen `is-loading` is true, the button shows a spinner, hides the label and icon, stays the same size, and is non-interactive:\n\n```html\n<xpl-button is-loading>Submitting</xpl-button>\n```\n\n### Form submission\n\nThe component renders a native `<button>`. Use `type` (`submit`, `reset`, or `button`), `name`, `value`, and `form` for form behaviour:\n\n```html\n<form id=\"my-form\">\n <xpl-button type=\"submit\" name=\"action\" value=\"save\">Save</xpl-button>\n</form>\n```\n\n### Disabled\n\nUse the `disabled` prop to disable the button (same as native `disabled`):\n\n```html\n<xpl-button disabled>Disabled</xpl-button>\n```\n\n## DOM classes\n\nThe host element includes BEM-style classes, including:\n\n- **Size:** `xpl-button--default` | `xpl-button--sm` | `xpl-button--xs`\n- **Variant:** `xpl-button--primary` | `xpl-button--secondary` | `xpl-button--tertiary` (and `xpl-button--subtle` while that value is still supported)\n- **Sentiment:** `xpl-button--neutral` | `xpl-button--positive` | `xpl-button--negative` when using `sentiment`\n- **Deprecated `state`:** if set, legacy classes `xpl-button--neutral` | `xpl-button--warning` | `xpl-button--success` are applied instead of the sentiment-based classes above (see migration)\n\nPrefer targeting **`sentiment`** + **`variant`** + **`size`** in new code; avoid relying on deprecated `state` class names for new selectors.\n\n## Migration Notes:\n\nThe class **`xpl-button--default`** on the host continues to mean **size** (`size=\"default\"`), not sentiment.\n\n### Deprecated `state` prop\n\nThe **`state`** prop (`neutral` | `warning` | `success`) is deprecated. Use **`sentiment`** instead:\n\n| Old `state` | New `sentiment` |\n| ------------- | ----------------- |\n| `neutral` | `neutral` (default) |\n| `warning` | `negative` |\n| `success` | `positive` |\n\n**Backward compatibility:** if **`state`** is set, it controls the sentiment segment of the host class list (`xpl-button--neutral`, `xpl-button--warning`, `xpl-button--success`) so existing styles or tests that key off those class names can keep working. New work should use **`sentiment`** only (`neutral` | `negative` | `positive`).\n\n### Deprecated `variant=\"subtle\"` → `tertiary`\n\n**`variant=\"subtle\"`** is deprecated and retained only for backward compatibility, applying the **`xpl-button--subtle`** class. Use **`variant=\"tertiary\"`** instead, which applies **`xpl-button--tertiary`**.\n\n### Other API notes\n\n- **`isLoading` / `is-loading`:** loading UI without forcing the disabled (gray) visual treatment.\n- **`icon`**, **`icon-position`**, **`icon-only`:** use Apollo icon names; no inline SVGs required.\n- **`data-*`, `aria-*`, and `role` on the host:** mirrored onto the inner `<button>` after render for accessibility and testing tools. After forwarding, these attributes are removed from the host element. Avoid relying on `role` on the host for external selectors.\n\n## Guidelines\n\n- **Pass button content via the default slot:** `<xpl-button>Save</xpl-button>`. Slots support rich content (formatted text, inline icons, etc.).\n- Use **`iconOnly`** for icon-only buttons and provide an **`aria-label`** (or ensure the inner button has an accessible name).\n- Use **`icon`** for icon names from the xpl-icon library; use **`icon-position`** to place the icon at start or end of the slot content.\n\n## Accessibility\n\n- The component renders a native `<button>`, so it is focusable and keyboard-activable by default.\n- When **`is-loading`** is true, the inner button has `aria-busy=\"true\"` and the loading spinner is marked **`aria-hidden=\"true\"`** so the label remains the accessible name.\n- For **icon-only** buttons, provide an accessible name via **`aria-label`** on the host (e.g. `<xpl-button icon-only icon=\"xmark\" aria-label=\"Close\">`) so screen readers announce the action.\n- For **WAI-ARIA composite widgets** (like tabs), use the **`controlAttrs`** prop to apply `id`, `role`, `aria-controls`, `aria-selected`, and `aria-current` directly to the inner `<button>`. This is preferred over setting these attributes on the host, which would be forwarded and removed from the host.\n",
|
|
@@ -2231,7 +2231,7 @@
|
|
|
2231
2231
|
}
|
|
2232
2232
|
},
|
|
2233
2233
|
{
|
|
2234
|
-
"filePath": "src/components/
|
|
2234
|
+
"filePath": "src/components/xpl-button-row/xpl-button-row.tsx",
|
|
2235
2235
|
"encapsulation": "none",
|
|
2236
2236
|
"tag": "xpl-button-row",
|
|
2237
2237
|
"readme": "# xpl-button-row\n\n\n\n### Design Tokens\n\nTokens used by this component from `@xplortech/apollo-foundation`.\n\n**Color**\n- `--xpl-border-default` — top border color\n\n**Spacing**\n- `--xpl-space-{0,16,24}` — padding / margins\n\n**Border**\n- `--xpl-border-small` — top border width (1px)\n",
|
|
@@ -2381,7 +2381,7 @@
|
|
|
2381
2381
|
}
|
|
2382
2382
|
},
|
|
2383
2383
|
{
|
|
2384
|
-
"filePath": "src/components/
|
|
2384
|
+
"filePath": "src/components/xpl-calendar/xpl-calendar.tsx",
|
|
2385
2385
|
"encapsulation": "none",
|
|
2386
2386
|
"tag": "xpl-calendar",
|
|
2387
2387
|
"readme": "# xpl-calendar\n\nCalendars allow users to view and select dates. Use XPL-Calendar when date picking is needed on a page or in a in a container.\nIf a calendar is needed within a form, use [XPL-Datepicker](https://apollo.xplordocs.com/?path=/story/components-input--datepicker).\n",
|
|
@@ -2624,7 +2624,7 @@
|
|
|
2624
2624
|
"dependencyGraph": {}
|
|
2625
2625
|
},
|
|
2626
2626
|
{
|
|
2627
|
-
"filePath": "src/components/
|
|
2627
|
+
"filePath": "src/components/xpl-checkbox/xpl-checkbox.tsx",
|
|
2628
2628
|
"encapsulation": "none",
|
|
2629
2629
|
"tag": "xpl-checkbox",
|
|
2630
2630
|
"readme": "# xpl-checkbox\n\nCheckboxes allow users to make selections or choices. Checkboxes can be multi-select, and also act as controls.\n\nProvide visible label text in the default slot, or set `aria-label` when the checkbox has no adjacent label (for example, icon-only toolbars or table selection cells).\n\n## Design Tokens\n\nThe checkbox component uses the following Apollo Foundation tokens:\n\n| Token | Usage |\n|-------|-------|\n| `--xpl-background-surface-default` | Default checkbox background; styled label background (resting/hover/focused) |\n| `--xpl-background-action-primary-default` | Checked/indeterminate state background and border |\n| `--xpl-background-action-disabled` | Disabled state background; disabled label background (styled variant) |\n| `--xpl-background-surface-information` | Checked/indeterminate label background (styled variant) |\n| `--xpl-text-inverse` | Checkmark and indeterminate icon color (checked / indeterminate states; inverse foreground on primary fill) |\n| `--xpl-icon-disabled` | Checkmark and indeterminate icon color (disabled state) |\n| `--xpl-border-strong` | Resting (unchecked) border color |\n| `--xpl-border-hover` | Hover, checked, and indeterminate border color; styled container hover/focus border |\n| `--xpl-border-default` | Styled container border; disabled state border |\n| `--xpl-border-focus` | Focus visible outline |\n| `--xpl-border-radius-small` | Checkbox corner radius and styled container corner radius (4px) |\n| `--xpl-border-small` | Border width (1px) |\n| `--xpl-size-100` | Checkbox dimensions (16px) |\n\n### Label tokens (shared `label.css`)\n\nThe checkbox label and description are styled by the shared `.xpl-label` / `.xpl-description` classes.\n\n| Token | Usage |\n|-------|-------|\n| `--xpl-text-strong` | Label text color (matches `.xpl-input-label`; resolves to white in dark mode) |\n| `--xpl-text-disabled` | Disabled label text color |\n| `--xpl-text-subdued` | Description text color (enabled and disabled) |\n| `.xpl-text-body` | Label typography: `--xpl-font-size-body` (14px) / normal / 1.4286 line-height |\n| `.xpl-text-callout` | Description typography: `--xpl-font-size-callout` (12px) / normal / 1.3333 line-height |\n",
|
|
@@ -2924,7 +2924,7 @@
|
|
|
2924
2924
|
}
|
|
2925
2925
|
},
|
|
2926
2926
|
{
|
|
2927
|
-
"filePath": "src/components/
|
|
2927
|
+
"filePath": "src/components/xpl-choicelist/xpl-choicelist.tsx",
|
|
2928
2928
|
"encapsulation": "none",
|
|
2929
2929
|
"tag": "xpl-choicelist",
|
|
2930
2930
|
"readme": "# xpl-choicelist\n\nA Choice List allows users to make single or multiple selections from a list of choices. This component is meant to consume the radio and checkbox components, either styled or unstyled, then allow for customizing an option list very quickly.\n\n## Design Tokens\n\nTokens used by this component from `@xplortech/apollo-foundation`.\n\n| Token | Usage |\n|-------|-------|\n| `--xpl-text-strong` | Heading (`h3`) text color |\n| `--xpl-text-subdued` | Description (`p`) text color |\n| `--xpl-background-surface-information` | Selected row background (styled variant) — matches the `xpl-checkbox` / `xpl-radio` styled selected state |\n| `--xpl-border-default` | Styled container border and per-row dividers — matches the `xpl-checkbox` / `xpl-radio` styled card border |\n| `--xpl-border-radius-small` | Styled container corner radius (4px) — matches the `xpl-checkbox` / `xpl-radio` styled card |\n| `--xpl-border-small` | Border width (1px) |\n| `--xpl-border-none` | Removes the divider on the last styled row (0) |\n| `.xpl-text-title-5` | Heading typography: `--xpl-font-size-title-5` (14px) / medium (500) / 1.4286 line-height |\n| `.xpl-text-callout` | Description typography: `--xpl-font-size-callout` (12px) / normal / 1.3333 line-height |\n| `--xpl-space-{8,12,16}` | Heading, row, and styled input/label spacing |\n| `--xpl-size-100` | Control width used to offset the styled label padding (16px) |\n\nChoice item labels and descriptions inherit their text tokens from the shared `label.css` (see `xpl-checkbox` / `xpl-radio`).\n",
|
|
@@ -2947,7 +2947,7 @@
|
|
|
2947
2947
|
"Choice": {
|
|
2948
2948
|
"location": "import",
|
|
2949
2949
|
"path": "./choice",
|
|
2950
|
-
"id": "src/components/
|
|
2950
|
+
"id": "src/components/xpl-choicelist/choice.ts::Choice",
|
|
2951
2951
|
"referenceLocation": "Choice"
|
|
2952
2952
|
}
|
|
2953
2953
|
}
|
|
@@ -3137,7 +3137,7 @@
|
|
|
3137
3137
|
}
|
|
3138
3138
|
},
|
|
3139
3139
|
{
|
|
3140
|
-
"filePath": "src/components/
|
|
3140
|
+
"filePath": "src/components/xpl-content-area/xpl-content-area.tsx",
|
|
3141
3141
|
"encapsulation": "none",
|
|
3142
3142
|
"tag": "xpl-content-area",
|
|
3143
3143
|
"readme": "# xpl-content-area\n\nThe `<xpl-content-area>` sets up the area for the main content of the page. This component renders a `<main>` element with an unnamed `<slot>`, and should not be combined with another `<main>` in the same page.\n\n### Design Tokens\n\nTokens used by this component from `@xplortech/apollo-foundation`.\n\n**Color**\n- `--xpl-background-surface-subtlest` — page surface behind the content (neutral-50 light / neutral-900 dark). Themes automatically — no `.dark` override. Matches the intended application-shell content surface.\n- `--xpl-text-default` — default text color (neutral-900 light / neutral-50 dark).\n",
|
|
@@ -3214,7 +3214,7 @@
|
|
|
3214
3214
|
"dependencyGraph": {}
|
|
3215
3215
|
},
|
|
3216
3216
|
{
|
|
3217
|
-
"filePath": "src/components/
|
|
3217
|
+
"filePath": "src/components/xpl-dashboard/xpl-dashboard.tsx",
|
|
3218
3218
|
"encapsulation": "none",
|
|
3219
3219
|
"tag": "xpl-dashboard",
|
|
3220
3220
|
"readme": "# xpl-dashboard\n\nThe XPL-Dashboard component is a code-only utility component for responsive layouts using the XPL-Data Card component. \n",
|
|
@@ -3248,7 +3248,7 @@
|
|
|
3248
3248
|
"dependencyGraph": {}
|
|
3249
3249
|
},
|
|
3250
3250
|
{
|
|
3251
|
-
"filePath": "src/components/
|
|
3251
|
+
"filePath": "src/components/xpl-data-card/xpl-data-card.tsx",
|
|
3252
3252
|
"encapsulation": "none",
|
|
3253
3253
|
"tag": "xpl-data-card",
|
|
3254
3254
|
"readme": "# xpl-data-card\n\nData Cards display snippets of information and can be linked to larger data sets. Data Cards give users \"at a glance\" information about their data.\n\nThe `icon` and `smallStatIcon` properties accept icon names as strings. See [xpl-icon available icons](../xpl-icon/ICONS.md) for the complete list.\n\n## Design Tokens\n\nThe card is styled entirely with Apollo Foundation purpose-specific tokens (dark mode is automatic — no `.dark` overrides).\n\n| Element / state | Property | Token |\n| --- | --- | --- |\n| Host surface | `background-color` | `--xpl-background-surface-default` |\n| Host / anchor border | `border-color` | `--xpl-border-default` |\n| Host, header, stats text | `color` | `--xpl-text-default` |\n| Header arrow (chevron) icon | `color` | `--xpl-icon-default` |\n| Detail text | `color` | `--xpl-text-subdued` |\n| `.positive` stat | `color` | `--xpl-text-positive` |\n| `.negative` stat | `color` | `--xpl-text-negative` |\n| `.neutral` stat | `color` | `--xpl-text-subdued` |\n| Primary leading icon | `color` | `--xpl-icon-brand` (orange) |\n| Secondary leading icon | `color` | `--xpl-background-action-primary-default` (purple) |\n| Anchor hover / active border | `border` | `--xpl-border-small` + `--xpl-background-action-primary-default` |\n| Anchor focus-visible border | `border` | `--xpl-border-small` + `--xpl-border-focus` (purple) |\n| Anchor focus-visible outline | `outline` | `--xpl-border-focus`, 2px width / 2px offset |\n| Anchor hover / focus-visible radius | `border-radius` | `--xpl-border-radius-default` |\n| Anchor hover shadow | `box-shadow` | `--xpl-elevation-2` (theme-aware) |\n| Header / stat spacing | `margin` | `--xpl-space-4`, `--xpl-space-6` |\n| Container-query stat | `font-size` | `--xpl-font-size-title-2` |\n| Container-query stat | `line-height` | `--xpl-line-height-title-2` |\n\nThe resting anchor overlay keeps a `0.375rem` (6px) radius to match the card's `rounded-md`; Foundation has no 6px radius token (see `TECH_DEBT.md`).\n",
|
|
@@ -3630,7 +3630,7 @@
|
|
|
3630
3630
|
}
|
|
3631
3631
|
},
|
|
3632
3632
|
{
|
|
3633
|
-
"filePath": "src/components/
|
|
3633
|
+
"filePath": "src/components/xpl-divider/xpl-divider.tsx",
|
|
3634
3634
|
"encapsulation": "none",
|
|
3635
3635
|
"tag": "xpl-divider",
|
|
3636
3636
|
"readme": "# xpl-divider\n\nAllows for easy separation and titling of sections within forms or other content.\n\n### Design Tokens\n\nTokens used by this component from `@xplortech/apollo-foundation`.\n\n**Color**\n- `--xpl-border-default` — divider line color\n- `--xpl-text-default` — label text color\n\n**Spacing**\n- `--xpl-space-{0,4,16}` — padding / margin\n\n**Typography**\n- `--xpl-font-size-body` — base label font size\n- Tier typography extends the shared type scale from `typography.css`: tier 3 → `.xpl-text-title-3`, tier 2 → `.xpl-text-title-4`, tier 1 → `.xpl-text-title-5`\n\n**Border**\n- `--xpl-border-small` — line width (1px)\n",
|
|
@@ -3698,10 +3698,10 @@
|
|
|
3698
3698
|
}
|
|
3699
3699
|
},
|
|
3700
3700
|
{
|
|
3701
|
-
"filePath": "src/components/
|
|
3701
|
+
"filePath": "src/components/xpl-dropdown/xpl-dropdown.tsx",
|
|
3702
3702
|
"encapsulation": "none",
|
|
3703
3703
|
"tag": "xpl-dropdown",
|
|
3704
|
-
"readme": "# xpl-dropdown\n\nA Dropdown is a menu with a list of actions a user can take. Use a dropdown when you want to present a list of actions in a limited space. Dropdowns are single-select ***actions***, can be presented in groups, and can be triggered by other elements such as a button, icon, text etc. \nA selection within a dropdown does not change the parent trigger.\n\n***If you want to present a list of **options** a user can select, or multi-select options, please use [XPL-Select](https://apollo.xplordocs.com/?path=/story/components-select--select).***\n\n### Design Tokens\n\nTokens used by this component from `@xplortech/apollo-foundation`. The panel surface and border are aligned with the migrated [xpl-popover](../xpl-popover).\n\n**Color**\n- `--xpl-background-surface-default` — panel background\n- `--xpl-text-default` — panel text color (inherited default), option label color, and heading color\n- `--xpl-icon-default` — leading option icon color (`--xpl-icon` via the `icon` prop)\n- `--xpl-border-default` — panel border and heading bottom border\n- `--xpl-text-subdued` — list-item subtitle color\n- `--xpl-background-action-tertiary-hover` — option `:focus` background\n- `--xpl-background-surface-subtlest` — option `:hover` background (neutral subtle surface)\n- `--xpl-background-surface-information` — `--selected` background (purple-50 light / neutral-700 dark)\n- `--xpl-background-action-primary-default` — `--selected` right accent border color\n\n**Border**\n- `--xpl-border-small` — panel and heading border width (1px)\n- `--xpl-border-
|
|
3704
|
+
"readme": "# xpl-dropdown\n\nA Dropdown is a menu with a list of actions a user can take. Use a dropdown when you want to present a list of actions in a limited space. Dropdowns are single-select ***actions***, can be presented in groups, and can be triggered by other elements such as a button, icon, text etc. \nA selection within a dropdown does not change the parent trigger.\n\n***If you want to present a list of **options** a user can select, or multi-select options, please use [XPL-Select](https://apollo.xplordocs.com/?path=/story/components-select--select).***\n\n### Design Tokens\n\nTokens used by this component from `@xplortech/apollo-foundation`. The panel surface and border are aligned with the migrated [xpl-popover](../xpl-popover).\n\n**Color**\n- `--xpl-background-surface-default` — panel background\n- `--xpl-text-default` — panel text color (inherited default), option label color, and heading color\n- `--xpl-icon-default` — leading option icon color (`--xpl-icon` via the `icon` prop)\n- `--xpl-border-default` — panel border and heading bottom border\n- `--xpl-text-subdued` — list-item subtitle color\n- `--xpl-background-action-tertiary-hover` — option `:focus` background\n- `--xpl-background-surface-subtlest` — option `:hover` background (neutral subtle surface)\n- `--xpl-background-surface-information` — `--selected` background (purple-50 light / neutral-700 dark)\n- `--xpl-background-action-primary-default` — `--selected` right accent border color\n- `--xpl-icon-information` — multi-select checkmark color (purple in both light and dark mode)\n\n**Border**\n- `--xpl-border-small` — panel and heading border width (1px)\n- `--xpl-border-xlarge` — 4px `--selected` accent border\n- `--xpl-border-radius-small` — panel corner radius (4px), matching the anchored `xpl-select` trigger\n\n**Spacing / Sizing**\n- `--xpl-space-16` — multi-select checkmark right offset\n- `--xpl-size-075` — multi-select checkmark size (12px)\n- `--xpl-dropdown-list-max-height` — component custom property for the options list max-height (default 300px)\n\n**Elevation**\n- `--xpl-elevation-2` — panel drop shadow\n\n**Typography**\n- `@extend .xpl-text-callout-bold` — heading: 12px / semibold weight / line-height 1.3333\n- `@extend .xpl-text-callout` — list-item subtitle: 12px / normal weight / line-height 1.3333\n\n**Note:** The multi-select checkmark is a data-URI SVG whose `fill` cannot be themed by a CSS variable, so a `.dark` override supplies the dark-mode glyph; and the disabled option keeps `opacity-60`. Both are tracked in `TECH_DEBT.md`.\n",
|
|
3705
3705
|
"docs": "A Dropdown is a menu with a list of actions a user can take. Use a dropdown when you want to present a list of actions in a limited space. Dropdowns are single-select ***actions***, can be presented in groups, and can be triggered by other elements such as a button, icon, text etc. \nA selection within a dropdown does not change the parent trigger.\n\n***If you want to present a list of **options** a user can select, or multi-select options, please use [XPL-Select](https://apollo.xplordocs.com/?path=/story/components-select--select).***",
|
|
3706
3706
|
"docsTags": [
|
|
3707
3707
|
{
|
|
@@ -3787,7 +3787,7 @@
|
|
|
3787
3787
|
"Placement": {
|
|
3788
3788
|
"location": "import",
|
|
3789
3789
|
"path": "../../utils/floating",
|
|
3790
|
-
"id": "src/
|
|
3790
|
+
"id": "src/utils/floating.ts::Placement",
|
|
3791
3791
|
"referenceLocation": "Placement"
|
|
3792
3792
|
}
|
|
3793
3793
|
}
|
|
@@ -3879,7 +3879,7 @@
|
|
|
3879
3879
|
"DropdownItem": {
|
|
3880
3880
|
"location": "import",
|
|
3881
3881
|
"path": "./dropdown-option",
|
|
3882
|
-
"id": "src/components/
|
|
3882
|
+
"id": "src/components/xpl-dropdown/dropdown-option.ts::DropdownItem",
|
|
3883
3883
|
"referenceLocation": "DropdownItem"
|
|
3884
3884
|
}
|
|
3885
3885
|
}
|
|
@@ -3908,7 +3908,7 @@
|
|
|
3908
3908
|
"Placement": {
|
|
3909
3909
|
"location": "import",
|
|
3910
3910
|
"path": "../../utils/floating",
|
|
3911
|
-
"id": "src/
|
|
3911
|
+
"id": "src/utils/floating.ts::Placement",
|
|
3912
3912
|
"referenceLocation": "Placement"
|
|
3913
3913
|
}
|
|
3914
3914
|
}
|
|
@@ -4072,8 +4072,8 @@
|
|
|
4072
4072
|
},
|
|
4073
4073
|
"Dropdown": {
|
|
4074
4074
|
"location": "local",
|
|
4075
|
-
"path": "/home/runner/work/apollo/apollo/packages/apollo-core/src/components/
|
|
4076
|
-
"id": "src/components/
|
|
4075
|
+
"path": "/home/runner/work/apollo/apollo/packages/apollo-core/src/components/xpl-dropdown/xpl-dropdown.tsx",
|
|
4076
|
+
"id": "src/components/xpl-dropdown/xpl-dropdown.tsx::Dropdown"
|
|
4077
4077
|
}
|
|
4078
4078
|
}
|
|
4079
4079
|
},
|
|
@@ -4131,7 +4131,7 @@
|
|
|
4131
4131
|
"DropdownItem": {
|
|
4132
4132
|
"location": "import",
|
|
4133
4133
|
"path": "./dropdown-option",
|
|
4134
|
-
"id": "src/components/
|
|
4134
|
+
"id": "src/components/xpl-dropdown/dropdown-option.ts::DropdownItem",
|
|
4135
4135
|
"referenceLocation": "DropdownItem"
|
|
4136
4136
|
},
|
|
4137
4137
|
"HTMLXplDropdownOptionElement": {
|
|
@@ -4222,7 +4222,7 @@
|
|
|
4222
4222
|
}
|
|
4223
4223
|
},
|
|
4224
4224
|
{
|
|
4225
|
-
"filePath": "src/components/
|
|
4225
|
+
"filePath": "src/components/xpl-dropdown/xpl-dropdown-group/xpl-dropdown-group.tsx",
|
|
4226
4226
|
"encapsulation": "none",
|
|
4227
4227
|
"tag": "xpl-dropdown-group",
|
|
4228
4228
|
"readme": "# xpl-dropdown-group\n\n\n",
|
|
@@ -4268,7 +4268,7 @@
|
|
|
4268
4268
|
"DropdownOptionGroup": {
|
|
4269
4269
|
"location": "import",
|
|
4270
4270
|
"path": "../dropdown-option",
|
|
4271
|
-
"id": "src/components/
|
|
4271
|
+
"id": "src/components/xpl-dropdown/dropdown-option.ts::DropdownOptionGroup",
|
|
4272
4272
|
"referenceLocation": "DropdownOptionGroup"
|
|
4273
4273
|
}
|
|
4274
4274
|
}
|
|
@@ -4322,7 +4322,7 @@
|
|
|
4322
4322
|
}
|
|
4323
4323
|
},
|
|
4324
4324
|
{
|
|
4325
|
-
"filePath": "src/components/
|
|
4325
|
+
"filePath": "src/components/xpl-dropdown/xpl-dropdown-heading/xpl-dropdown-heading.tsx",
|
|
4326
4326
|
"encapsulation": "none",
|
|
4327
4327
|
"tag": "xpl-dropdown-heading",
|
|
4328
4328
|
"readme": "# xpl-dropdown-heading\n\n\n",
|
|
@@ -4382,7 +4382,7 @@
|
|
|
4382
4382
|
}
|
|
4383
4383
|
},
|
|
4384
4384
|
{
|
|
4385
|
-
"filePath": "src/components/
|
|
4385
|
+
"filePath": "src/components/xpl-dropdown/xpl-dropdown-option/xpl-dropdown-option.tsx",
|
|
4386
4386
|
"encapsulation": "none",
|
|
4387
4387
|
"tag": "xpl-dropdown-option",
|
|
4388
4388
|
"readme": "# xpl-dropdown-option\n\n\n",
|
|
@@ -4566,7 +4566,7 @@
|
|
|
4566
4566
|
}
|
|
4567
4567
|
},
|
|
4568
4568
|
{
|
|
4569
|
-
"filePath": "src/components/
|
|
4569
|
+
"filePath": "src/components/xpl-dynamic-table/xpl-dynamic-table.tsx",
|
|
4570
4570
|
"encapsulation": "none",
|
|
4571
4571
|
"tag": "xpl-dynamic-table",
|
|
4572
4572
|
"readme": "# xpl-dynamic-table\n\n> **Note:** This component is currently in beta. Use with caution as it may have breaking changes in future releases.\n\nThe Dynamic Table is a rich content table that can accommodate multiple types of data.\n\n> **[DEPRECATED]** Use the compositional `<xpl-table>` API instead.\n> This component will be removed in a future major release.\n\n## Design Tokens\n\nThe table, cells, and rows use Apollo Foundation purpose-specific tokens (light / dark resolve automatically — no `.dark` overrides):\n\n**Table** (`.xpl-dynamic-table`)\n\n| Element | Property | Token |\n| --- | --- | --- |\n| Grid columns | `grid-template-columns` | `--xpl-column-widths` (set at runtime from header cell widths) |\n| Row gap (with accordions) | `row-gap` (8px) | `--xpl-space-8` |\n\n**Cell** (`.xpl-dynamic-table-cell`)\n\n| Element | Property | Token |\n| --- | --- | --- |\n| Cell | Background | `--xpl-background-surface-default` |\n| Cell | Border | `--xpl-border-default` |\n| Cell | Text | `--xpl-text-default` |\n| Cell | Typography (title-5 / medium / 1.4286) | `@extend .xpl-text-title-5` |\n| Cell | Height (56px) | `--xpl-size-350` |\n| Cell | Min width (48px) | `--xpl-size-300` |\n| Cell rounded corners | Border radius (8px) | `--xpl-border-radius-default` |\n| Cell icons (chevron, kebab) | Color | `--xpl-icon-default` |\n| Dropdown button (`:focus-visible`) | Inset ring | `--xpl-border-focus` |\n\n**Row** (`.xpl-dynamic-table-row`)\n\n| State | Property | Token |\n| --- | --- | --- |\n| First cell | Left border | `--xpl-border-default` |\n| Selected | Cell background | `--xpl-background-surface-information` |\n| Disabled | Cell background | `--xpl-background-surface-subtlest` |\n| Disabled | Cell / badge text | `--xpl-text-disabled` |\n| Disabled | Cell icons | `--xpl-icon-disabled` |\n",
|
|
@@ -4636,7 +4636,7 @@
|
|
|
4636
4636
|
"dependencyGraph": {}
|
|
4637
4637
|
},
|
|
4638
4638
|
{
|
|
4639
|
-
"filePath": "src/components/
|
|
4639
|
+
"filePath": "src/components/xpl-dynamic-table-cell/xpl-dynamic-table-cell.tsx",
|
|
4640
4640
|
"encapsulation": "none",
|
|
4641
4641
|
"tag": "xpl-dynamic-table-cell",
|
|
4642
4642
|
"readme": "# xpl-dynamic-table-cell\n\n> **Note:** This component is currently in beta. Use with caution as it may have breaking changes in future releases.\n\n> **[DEPRECATED]** Use `<xpl-table-cell>` instead.\n> This component will be removed in a future major release.\n",
|
|
@@ -4700,7 +4700,7 @@
|
|
|
4700
4700
|
"dependencyGraph": {}
|
|
4701
4701
|
},
|
|
4702
4702
|
{
|
|
4703
|
-
"filePath": "src/components/
|
|
4703
|
+
"filePath": "src/components/xpl-dynamic-table-row/xpl-dynamic-table-row.tsx",
|
|
4704
4704
|
"encapsulation": "none",
|
|
4705
4705
|
"tag": "xpl-dynamic-table-row",
|
|
4706
4706
|
"readme": "# xpl-dynamic-table-row\n\n> **Note:** This component is currently in beta. Use with caution as it may have breaking changes in future releases.\n\n> **[DEPRECATED]** Use `<xpl-table-row>` instead.\n> This component will be removed in a future major release.\n",
|
|
@@ -4793,7 +4793,7 @@
|
|
|
4793
4793
|
"dependencyGraph": {}
|
|
4794
4794
|
},
|
|
4795
4795
|
{
|
|
4796
|
-
"filePath": "src/components/
|
|
4796
|
+
"filePath": "src/components/xpl-grid/xpl-grid.tsx",
|
|
4797
4797
|
"encapsulation": "none",
|
|
4798
4798
|
"tag": "xpl-grid",
|
|
4799
4799
|
"readme": "# xpl-grid\n\nXPL-Grid is a code only utility component to help with responsive layouts. \n",
|
|
@@ -4818,7 +4818,7 @@
|
|
|
4818
4818
|
"dependencyGraph": {}
|
|
4819
4819
|
},
|
|
4820
4820
|
{
|
|
4821
|
-
"filePath": "src/components/
|
|
4821
|
+
"filePath": "src/components/xpl-grid-item/xpl-grid-item.tsx",
|
|
4822
4822
|
"encapsulation": "none",
|
|
4823
4823
|
"tag": "xpl-grid-item",
|
|
4824
4824
|
"readme": "# xpl-grid-item\n\n\n",
|
|
@@ -4969,7 +4969,7 @@
|
|
|
4969
4969
|
"dependencyGraph": {}
|
|
4970
4970
|
},
|
|
4971
4971
|
{
|
|
4972
|
-
"filePath": "src/components/
|
|
4972
|
+
"filePath": "src/components/xpl-header-accordion/xpl-header-accordion.tsx",
|
|
4973
4973
|
"encapsulation": "none",
|
|
4974
4974
|
"tag": "xpl-header-accordion",
|
|
4975
4975
|
"readme": "# xpl-header-accordion\n\nThe toolbar component allows users to manipulate selections within the Dynamic Table. It is only visible when a row or cell is in the selected state and bulk actions can be taken on that row or cell. \n\n> **Note:** This component is currently in beta. Use with caution as it may have breaking changes in future releases.\n\n## Design Tokens\n\nThe header uses Apollo Foundation purpose-specific tokens (light / dark resolve automatically — no `.dark` overrides):\n\n| Element | Property | Token |\n| --- | --- | --- |\n| Header bar | Background | `--xpl-background-surface-subtlest` |\n| Header bar | Border | `--xpl-border-default` |\n| Header bar | Text | `--xpl-text-subdued` |\n| Header bar | Typography (title-5 / medium / 1.4286) | `@extend .xpl-text-title-5` |\n| Header bar | Min height (56px) | `--xpl-size-350` |\n| Header bar corners | Border radius (8px) | `--xpl-border-radius-default` |\n| Toggle area (`:focus-visible`) | Outline color | `--xpl-border-focus` |\n| Chevron icon | Color | `--xpl-icon-default` |\n| Content panel | Background | `--xpl-background-surface-default` |\n| Content panel | Border | `--xpl-border-default` |\n| Content panel | Text | `--xpl-text-link-default` |\n| Content grid | `grid-template-columns` | `--xpl-column-widths` (set at runtime by `xpl-dynamic-table`) |\n",
|
|
@@ -5165,7 +5165,7 @@
|
|
|
5165
5165
|
}
|
|
5166
5166
|
},
|
|
5167
5167
|
{
|
|
5168
|
-
"filePath": "src/components/
|
|
5168
|
+
"filePath": "src/components/xpl-icon/xpl-icon.tsx",
|
|
5169
5169
|
"encapsulation": "none",
|
|
5170
5170
|
"tag": "xpl-icon",
|
|
5171
5171
|
"readme": "# xpl-icon\n\n## Available Icons\n\nFor a complete list of available icon names, see [ICONS.md](./ICONS.md) (554 icons).\n\nYou can also browse icons visually in [Storybook](?path=/story/components-icons--icons) with search functionality.\n\n## Usage\n\n```html\n<xpl-icon icon=\"rocket\" size=\"24\"></xpl-icon>\n```\n\nThe `icon` property accepts any icon name as a string. See the links above for the full list of available icons.\n\n### Design Tokens\n\nTokens used by this component from `@xplortech/apollo-foundation`.\n\n**Color — icon accent backgrounds (`&--with-background`)**\n\nSubtle per-hue accent tints use primitive color tokens (`-50` light / `-900` dark). Foundation has no purpose-specific token for these subtle tints (`--xpl-background-accent-*` are far bolder), so primitives are used and the `.dark` overrides are **deliberately retained** to swap the dark value. This is a documented exception to the \"no `.dark`\" migration DoD (tracked in `TECH_DEBT.md`).\n\n- `--xpl-icon-default` — fallback glyph color for accent-background icons (neutral-900 light / neutral-50 dark). Set explicitly so the glyph themes with the background instead of relying on inherited `currentColor` (which left a dark glyph on the dark `-900` tint in dark mode). Note: `xpl-data-card` also uses the accent-background prop and overrides the glyph color with a hue-matched value directly on `.xpl-icon`, so it is unaffected by this fallback.\n- `--xpl-color-neutral-50` / `--xpl-color-neutral-900` — `--gray` background\n- `--xpl-color-orange-50` / `--xpl-color-orange-900` — `--orange` background\n- `--xpl-color-purple-50` / `--xpl-color-purple-900` — `--purple` background\n- `--xpl-color-red-50` / `--xpl-color-red-900` — `--red` background\n- `--xpl-color-yellow-50` / `--xpl-color-yellow-900` — `--yellow` background\n\n---\n",
|
|
@@ -5403,7 +5403,7 @@
|
|
|
5403
5403
|
}
|
|
5404
5404
|
},
|
|
5405
5405
|
{
|
|
5406
|
-
"filePath": "src/components/
|
|
5406
|
+
"filePath": "src/components/xpl-input/xpl-input.tsx",
|
|
5407
5407
|
"encapsulation": "none",
|
|
5408
5408
|
"tag": "xpl-input",
|
|
5409
5409
|
"readme": "# xpl-input\n\nA flexible form input that supports multiple `type` values: `text`, `number`, `password`, `date`, `time`, `file`, `color`, `phone`, and `search`. Each type delegates to a dedicated sub-component (`xpl-input-date`, `xpl-input-time`, `xpl-input-phone`, `xpl-input-search`, etc.) while sharing a common label, description, and error-message wrapper.\n\nFor `type=\"phone\"`, the value is always emitted in **E.164** format (e.g. `+14155551234`). See [`xpl-input-phone`](xpl-input-phone) for full phone-input documentation.\n\n## Design Tokens\n\nThe `xpl-input` component uses Apollo Foundation tokens for consistent theming across light and dark modes:\n\n| Element | Property | Token |\n|---------|----------|-------|\n| Input wrapper border (default) | `border-color` | `var(--xpl-border-default)` |\n| Input wrapper border (focus) | `border-color` | `var(--xpl-border-focus)` |\n| Input wrapper border (error) | `border-color` | `var(--xpl-border-negative)` |\n| Input wrapper background (default) | `background-color` | `var(--xpl-background-surface-default)` |\n| Input/textarea background | `background-color` | `var(--xpl-background-surface-transparent-0)` |\n| Disabled/readonly wrapper background | `background-color` | `var(--xpl-background-action-disabled)` |\n| Post element background | `background-color` | `var(--xpl-background-surface-subtle)` |\n| Input text | `color` | `var(--xpl-text-default)` |\n| Disabled/readonly text | `color` | `var(--xpl-text-disabled)` |\n| Label text | `color` | `var(--xpl-text-strong)` |\n| Description text | `color` | `var(--xpl-text-subdued)` |\n| Error text | `color` | `var(--xpl-text-negative)` |\n| Character counter background (default) | `background-color` | `var(--xpl-background-surface-default)` |\n| Character counter background (disabled/readonly) | `background-color` | `var(--xpl-background-action-disabled)` |\n| Character counter text | `color` | `var(--xpl-text-subdued)` |\n| Calendar/password icon | `color` | `var(--xpl-icon-default)` |\n\n### Spacing Tokens\n\n| Element | Property | Token |\n|---------|----------|-------|\n| Input | `padding-right` | `var(--xpl-space-8)` |\n| Textarea | `padding-top` | `var(--xpl-space-12)` |\n| Textarea | `padding-bottom` | `var(--xpl-space-8)` |\n| Wrapper | `padding-left` | `var(--xpl-space-12)` |\n| Pre element (leading icon/text) | `padding-right` | `var(--xpl-space-8)` |\n| Post element (trailing unit / AM-PM) | `padding-left`, `padding-right` | `var(--xpl-space-12)` |\n| Label | `padding-bottom` | `var(--xpl-space-4)` |\n| Character counter | `padding` | `var(--xpl-space-8) var(--xpl-space-12)` |\n| Error message | `padding`, `gap` | `var(--xpl-space-4)` |\n| Calendar icon | `right` | `var(--xpl-space-12)` |\n| Password button | `padding-left`, `padding-right` | `var(--xpl-space-12)` |\n\n### Dimension Tokens\n\n| Element | Property | Token |\n|---------|----------|-------|\n| Input | `height` | `var(--xpl-size-250)` (40px; matches Figma `form/height`) |\n| Textarea | `min-height` | `var(--xpl-size-250)` (40px) |\n| Textarea | `height` | `var(--xpl-size-700)` (112px; rounded up from 98px) |\n| Wrapper | `border-width` | `var(--xpl-border-small)` |\n| Wrapper | `border-radius` | `var(--xpl-border-radius-small)` (4px; matches Figma `border/radius/small`) |\n| Post element | `height` | `var(--xpl-size-250)` (40px; vertically centered via flex) |\n| Post element | `border-left-width` | `var(--xpl-border-small)` |\n\n### Delegated types (`search`, `phone`, `date`, `time`, …)\n\n`valueChange`, `inputEvent`, `focusEvent`, and `blurEvent` are emitted by the inner component and **bubble** to `<xpl-input>`. For **`type=\"search\"`**, **`focusEvent`** and **`blurEvent`** are **re-emitted from `<xpl-input>`** (parent uses **`onFocusEvent`** / **`onBlurEvent`** on **`<xpl-input-search>`** with **`stopPropagation`**) so **`event.target`** matches **`type=\"text\"`**. For **`valueChange`** and **`inputEvent`** on search, events still **bubble** from **`xpl-input-search`** without parent re-emission; **`event.target`** may be the inner host—prefer **`event.detail`** (the string) or **`event.currentTarget`** when you attach the listener on **`<xpl-input>`**. Other delegated types follow the same **`event.detail`** / **`event.currentTarget`** guidance.\n\nFor **`type=\"search\"`** commit: **`<xpl-input-search>`** defines a Stencil **`@Event() search`** (trimmed query in **`detail`**). **`<xpl-input>`** listens with **`onSearch`** on the inner tag, **`stopPropagation`s**, then **`this.search.emit(detail)`** so the canonical **`search`** **`@Event`** stays on **`<xpl-input>`** and listeners are not doubled. **`setFocus()`** on **`<xpl-input>`** uses a **`ref`** to the inner component to delegate focus.\n",
|
|
@@ -6521,7 +6521,7 @@
|
|
|
6521
6521
|
}
|
|
6522
6522
|
},
|
|
6523
6523
|
{
|
|
6524
|
-
"filePath": "src/components/
|
|
6524
|
+
"filePath": "src/components/xpl-input/xpl-input-color/xpl-input-color.tsx",
|
|
6525
6525
|
"encapsulation": "none",
|
|
6526
6526
|
"tag": "xpl-input-color",
|
|
6527
6527
|
"readme": "# xpl-input-color\n\n\n\n### Design Tokens\n\nTokens used by this component from `@xplortech/apollo-foundation`.\n\n**Color**\n- `--xpl-border-default` — display and swatch border\n- `--xpl-text-default` — display text color\n- `--xpl-text-subdued` — placeholder text color\n- `--xpl-background-action-disabled` — disabled display background\n- `--xpl-border-negative` — error state border color (unified with input-date / input-time)\n- `--xpl-icon-default` — toggle icon color\n- `--xpl-background-action-primary-default` — toggle icon hover color (purple; intentionally not `--xpl-icon-brand`, which is orange)\n- `--xpl-border-subtle` — picker saturation/lightness grid, preview, and range-track borders\n- `--xpl-color-neutral-0`, `--xpl-color-neutral-600` — fixed-color picker thumb ring/shadow (functional, non-themeable)\n\n**Typography**\n- `__placeholder`, `__value` — `@extend .xpl-text-body` (14 px normal)\n",
|
|
@@ -6738,7 +6738,7 @@
|
|
|
6738
6738
|
}
|
|
6739
6739
|
},
|
|
6740
6740
|
{
|
|
6741
|
-
"filePath": "src/components/
|
|
6741
|
+
"filePath": "src/components/xpl-input/xpl-input-date/xpl-input-date.tsx",
|
|
6742
6742
|
"encapsulation": "none",
|
|
6743
6743
|
"tag": "xpl-input-date",
|
|
6744
6744
|
"readme": "# xpl-input-date\n\n\n\n### Design Tokens\n\nTokens used by this component from `@xplortech/apollo-foundation`.\n\n**Color**\n- `--xpl-border-negative` — error state border color\n",
|
|
@@ -7140,7 +7140,7 @@
|
|
|
7140
7140
|
}
|
|
7141
7141
|
},
|
|
7142
7142
|
{
|
|
7143
|
-
"filePath": "src/components/
|
|
7143
|
+
"filePath": "src/components/xpl-input/xpl-input-file/xpl-input-file.tsx",
|
|
7144
7144
|
"encapsulation": "none",
|
|
7145
7145
|
"tag": "xpl-input-file",
|
|
7146
7146
|
"readme": "# xpl-file-upload\n\n\n\n### Design Tokens\n\nTokens used by this component from `@xplortech/apollo-foundation`.\n\n**Color**\n- `--xpl-text-default` — selected file list text color\n- `--xpl-text-subdued` — accepted-types (help) text color\n- `--xpl-icon-default` — remove (x-circle) icon color\n\n**Typography**\n- `__file-name` — `@extend .xpl-text-callout` (12 px normal) — uploaded file names\n- `__accept` — `@extend .xpl-text-caption` (10 px normal) — accepted file types help text\n",
|
|
@@ -7456,7 +7456,7 @@
|
|
|
7456
7456
|
}
|
|
7457
7457
|
},
|
|
7458
7458
|
{
|
|
7459
|
-
"filePath": "src/components/
|
|
7459
|
+
"filePath": "src/components/xpl-input/xpl-input-phone/xpl-input-phone.tsx",
|
|
7460
7460
|
"encapsulation": "none",
|
|
7461
7461
|
"tag": "xpl-input-phone",
|
|
7462
7462
|
"readme": "# xpl-input-phone\n\nThe Phone Input Field allows users to input properly formatted phone numbers. It supports two modes: **international** (country selector + dial code prefix) and **domestic** (single country, no selector). Used as a subcomponent of `xpl-input` when `type=\"phone\"`. The value is always emitted in **E.164** format (e.g. `+14155551234`).\n\n## Usage\n\n### International mode (default)\n\nUse via the parent component for full international support with a country selector:\n\n```html\n<xpl-input type=\"phone\" label=\"Phone number\" name=\"phone\"></xpl-input>\n```\n\nWith preferred countries pinned to the top of the list:\n\n```html\n<xpl-input\n type=\"phone\"\n label=\"Phone number\"\n name=\"phone\"\n preferred-countries='[\"US\",\"CA\",\"GB\"]'\n></xpl-input>\n```\n\n### Domestic mode\n\nSet `is-international=\"false\"` to lock the input to a single country. The country selector trigger and dropdown are hidden, and no dial code is shown in the input. The emitted value is still E.164.\n\n```html\n<xpl-input\n type=\"phone\"\n label=\"Phone number\"\n name=\"phone\"\n default-country=\"US\"\n is-international=\"false\"\n></xpl-input>\n```\n\n### Pre-populating a value\n\nPass an E.164 string to `value`. The component parses it into the correct country and national number:\n\n```html\n<xpl-input type=\"phone\" label=\"Phone\" value=\"+14155551234\"></xpl-input>\n```\n\n## Value format\n\n- **value** / **valueChange**: E.164 string (e.g. `+14155551234`). You can set `value` to pre-fill; the component parses it into country and national number.\n- **defaultCountry**: ISO 3166-1 alpha-2 code (e.g. `\"US\"`) used when value is empty. In domestic mode, this locks the country permanently.\n- **preferredCountries**: Optional array of country codes to show at the top of the country list (international mode only).\n- **isInternational**: When `true` (default), the full international UI is shown. When `false`, the component is a simple domestic phone input locked to `defaultCountry`.\n\n## Design and behaviour\n\n### Country selector (international mode)\n\n- The **trigger** displays a country flag icon (`xpl-icon`) and a chevron-down icon.\n- Clicking the trigger opens an `xpl-dropdown` panel containing a **type-ahead search** field and a scrollable list of countries. Each option shows its flag icon, name, and dial code.\n- Search filters by country name, dial code, or ISO country code.\n- When a country is selected, focus returns to the phone input and the cursor is positioned after the dial code.\n- Countries sharing a dial code (e.g. US and Canada both use `+1`) are handled correctly: changing the country in the dropdown preserves the selection even when the dial code is the same.\n\n### Domestic mode\n\nNo country selector is rendered. The input behaves as a standard phone field with country-specific formatting and validation based on `defaultCountry`. The dial code is not displayed in the input, but the emitted value is still E.164.\n\n### Input handling\n\n- **Sanitization**: Non-numeric characters are automatically stripped on every keystroke, paste, or autofill. The input only accepts digits.\n- **Max length**: Enforced per country based on the national number format (e.g. 10 digits for US/CA, 9 for AU/FR).\n- **Cursor protection** (international mode): The dial code prefix (e.g. `+1 `) is read-only within the input. Users cannot backspace into it, click before it, or use Home/ArrowLeft to move the cursor before it.\n- **Clear button**: A clear (`x-circle`) button appears when there is input and the field is not disabled or readonly.\n\n### Phone formatting\n\nThe national number is formatted as the user types (e.g. US: `415 555 1234`, FR: `6 12 34 56 78`). The stored and emitted value remains E.164. Cursor position is intelligently preserved during formatting so it does not jump.\n\nCountries with custom formatters: US/CA, GB, AU, DE/AT/CH, FR, BR, MX, JP, CN, IN, KR. All other countries use a generic grouping format.\n\n### Validation and errors\n\n- When `required` is set, the component emits a `hasErrorStateChanged` event with `\"required\"` if the national number is empty on change.\n- The parent `xpl-input` can pass an `error` prop for external error messages (e.g. server-side validation).\n- The component applies `xpl-input-phone--error` to the host when an internal error state is active.\n\n### Accessibility\n\n- The country selector trigger has `aria-haspopup=\"listbox\"` and `aria-expanded`.\n- The country selector trigger has `aria-label=\"Select country\"` for screen-reader clarity.\n- The dropdown panel has `aria-label=\"Country\"`.\n- The clear button has `aria-label=\"Clear phone number\"`.\n- The input uses `inputmode=\"numeric\"` to hint a numeric keyboard on mobile and `autocomplete=\"tel-national\"` (international) or `autocomplete=\"tel\"` (domestic).\n- The input sets `aria-invalid=\"true\"` when in an error state (e.g. required field left empty).\n- Decorative icons (flag, chevron) use `aria-hidden=\"true\"` to avoid screen reader noise.\n\n## Supported countries\n\n28 countries are currently supported. See `phone-country-data.ts` for the full list. Countries with custom number formatting are noted above. To add a new country, add an entry to the `PHONE_COUNTRIES` array and optionally add a formatter in `phone-format.ts`.\n\n### Design Tokens\n\nTokens used by this component from `@xplortech/apollo-foundation`.\n\n**Color**\n- `--xpl-background-surface-subtlest` — trigger background\n- `--xpl-background-surface-information` — trigger hover / open background\n- `--xpl-border-negative` — error state border\n- `--xpl-border-focus` — wrapper and trigger focus outline\n- `--xpl-border-default` — trigger divider, search border\n- `--xpl-text-default` — trigger text, dial code\n- `--xpl-text-subdued` — clear button color\n- `--xpl-icon-default` — search icon\n\n**Border**\n- `--xpl-border-small` — trigger divider width (1px)\n\n**Focus**\n- `--xpl-border-focus` — `:focus-visible` outline (inset, 2px)\n",
|
|
@@ -7816,7 +7816,7 @@
|
|
|
7816
7816
|
}
|
|
7817
7817
|
},
|
|
7818
7818
|
{
|
|
7819
|
-
"filePath": "src/components/
|
|
7819
|
+
"filePath": "src/components/xpl-input/xpl-input-search/xpl-input-search.tsx",
|
|
7820
7820
|
"encapsulation": "none",
|
|
7821
7821
|
"tag": "xpl-input-search",
|
|
7822
7822
|
"readme": "# xpl-input-search\n\nInner search field used by [`xpl-input`](../readme.md) when `type=\"search\"`. It provides a leading magnifier, a native text field with `role=\"searchbox\"`, an optional clear control, and a `shape` shell (`rounded` pill vs `box`). You normally consume search through **`xpl-input`**; use `xpl-input-search` only when composing a custom shell that still matches Apollo search visuals.\n\n## Usage\n\n### Recommended: `xpl-input` with `type=\"search\"`\n\nDefault pill shell (`shape` defaults to `rounded`), placeholder, and optional `name` for forms:\n\n```html\n<xpl-input type=\"search\" name=\"q\" placeholder=\"Search products\"></xpl-input>\n```\n\nVisible label, description, `box` shape, and `autocomplete`:\n\n```html\n<xpl-input\n type=\"search\"\n label=\"Search catalog\"\n description=\"SKU or product name\"\n name=\"q\"\n placeholder=\"SKU or name\"\n shape=\"box\"\n autocomplete=\"search\"\n></xpl-input>\n```\n\nWhen there is no visible label, set `aria-label` on `xpl-input` (forwarded to the inner field for assistive naming):\n\n```html\n<xpl-input type=\"search\" aria-label=\"Search help topics\" placeholder=\"Search…\"></xpl-input>\n```\n\nError state (border, `aria-invalid`, and error text on the parent) and an initial value (clear control appears when there is text):\n\n```html\n<xpl-input type=\"search\" shape=\"box\" error=\"Invalid query\" value=\"abc\"></xpl-input>\n```\n\nListening for submit and live updates (vanilla JS):\n\n```html\n<xpl-input id=\"search\" type=\"search\" placeholder=\"Search\"></xpl-input>\n<script type=\"module\">\n const el = document.getElementById('search');\n el.addEventListener('search', (e) => {\n console.log('submit', e.detail); // trimmed string\n });\n el.addEventListener('valueChange', (e) => {\n console.log('value', e.detail); // raw string\n });\n</script>\n```\n\n### Events on `<xpl-input type=\"search\">`\n\n`valueChange`, `inputEvent`, `focusEvent`, and `blurEvent` are Stencil **`@Event`s** on **`xpl-input-search`** and **bubble** to the **`<xpl-input>`** host. **`focusEvent`** / **`blurEvent`** are also **re-emitted from `<xpl-input>`** so **`event.target`** matches **`type=\"text\"`** (see **`xpl-input`** readme). **`valueChange`** / **`inputEvent`** are **not** re-emitted by the parent; use **`event.detail`** for the string if you do not want to depend on **`event.target`**.\n\nThe **commit** signal is a Stencil **`search`** **`@Event`** on **`xpl-input-search`** (trimmed query in **`detail`**). **`xpl-input`** wires **`onSearch`** on the inner tag, **`stopPropagation`s**, and **`this.search.emit(detail)`** so the public **`search`** **`@Event`** remains on **`<xpl-input>`**. **`setFocus()`** on **`<xpl-input>`** uses a **`ref`** to call the inner **`setFocus()`** only.\n\nFor advanced composition you can render `<xpl-input-search>` directly. You must pass **`input-id`** (matches a `<label for=\"…\">` when used with a visible label). Set **`disabled`** and **`has-error`** (plus **`error-message-id`** when invalid) for both accessibility and visuals: the host adds `xpl-input-search--disabled` / `xpl-input-search--error` so disabled and error chrome match the wrapped `xpl-input` case. When nested under `xpl-input type=\"search\"`, those props are set for you from the parent.\n\n```html\n<label class=\"xpl-input-label\" for=\"sid\">Search</label>\n<xpl-input-search input-id=\"sid\" name=\"q\" placeholder=\"Search…\"></xpl-input-search>\n```\n\n## Design tokens\n\n| Part | Token |\n| ---- | ----- |\n| Host text (input inherits) | `--xpl-text-default` |\n| Shell layout | `gap`: `--xpl-space-12`; horizontal padding: `--xpl-space-12`; `min-height` / `max-height`: `--xpl-size-250` |\n| Shell fill (resting) | `--xpl-background-surface-default` |\n| Shell `border-radius` (pill, default `shape=\"rounded\"`) | `--xpl-border-radius-button` |\n| Shell `border-radius` (`shape=\"box\"`) | `--xpl-border-radius-small` |\n| Shell border (resting) | `--xpl-border-default` |\n| Shell border (input focus, empty) | `--xpl-border-active` |\n| Shell border (input focus, with value) | `--xpl-border-focus` |\n| Shell border (error, from parent `xpl-input`) | `--xpl-border-negative` |\n| Disabled shell (parent) | `--xpl-background-action-disabled` |\n| Input typography | `--xpl-font-family-default`, `--xpl-font-size-body`, `--xpl-font-weight-normal` |\n| Placeholder | `--xpl-text-subdued` |\n| Disabled text / placeholder (parent) | `--xpl-text-disabled` |\n| Leading icon | `--xpl-icon-default` / `--xpl-icon-disabled` |\n| Clear icon | `--xpl-icon-subtle` |\n| Caret (focus, with value) | `--xpl-border-focus` |\n| Caret (focus, error, parent) | `--xpl-border-negative` |\n\nLight and dark mode use Foundation purpose-specific tokens only (no component `.dark` overrides).\n\n## Icon mapping\n\n| Role | When | `xpl-icon` name | `size` |\n| ---- | ---- | ----------------- | ------ |\n| Leading search | Always (when the control renders) | `magnifier` | 20 |\n| Clear | Value non-empty and not `disabled` | `circle-xmark` | 16 |\n\n## Accessibility\n\n- **Role and naming:** The field uses a native `<input type=\"text\">` with `role=\"searchbox\"`. `type=\"text\"` avoids browser search-field chrome that would clash with the design-system clear control. When the parent does not render a visible label, `aria-label` on the inner input defaults to `\"Search\"` unless `ariaLabel` / parent `aria-label` overrides it. With a visible label, the input is named via `<label for=\"…\">` and redundant `aria-label` on the input is omitted.\n- **`autocomplete`:** Default `off` is typical for inline search; set `autocomplete` on `xpl-input` for search fields when you need a specific token.\n- **Errors:** With `xpl-input`, non-empty `error` sets `aria-invalid`, links the message with `aria-describedby`, and styles the shell from the parent host.\n- **Keyboard — standalone `xpl-input-search`:** An inner `<form>` wraps the shell when the host is not already inside a `<form>`. **Enter** submits that inner form (default prevented); the host emits a Stencil **`search`** event (trimmed value in **`detail`**). Listen with **`addEventListener('search', …)`** on **`xpl-input-search`**. **Tab** visits the input and the clear control when visible.\n- **Keyboard — inside a parent `<form>`:** The inner `<form>` is omitted. **Enter** uses native form submission; listen on the parent form’s **`submit`**. Use **`valueChange`** / **`inputEvent`** for live typing.\n- **Clear control:** The clear button exposes **`aria-label=\"Clear search\"`**. Activating it clears the value, emits **`valueChange`** / **`inputEvent`** with `''`, and refocuses the input. When **`disabled`** or **`readonly`** is true, the clear control is hidden and inert (no value mutation).\n",
|
|
@@ -8316,7 +8316,7 @@
|
|
|
8316
8316
|
}
|
|
8317
8317
|
},
|
|
8318
8318
|
{
|
|
8319
|
-
"filePath": "src/components/
|
|
8319
|
+
"filePath": "src/components/xpl-input/xpl-input-time/xpl-input-time.tsx",
|
|
8320
8320
|
"encapsulation": "none",
|
|
8321
8321
|
"tag": "xpl-input-time",
|
|
8322
8322
|
"readme": "# xpl-input-time\n\n\n\n### Design Tokens\n\nTokens used by this component from `@xplortech/apollo-foundation`.\n\n**Color**\n- `--xpl-border-negative` — error state border color (unified with input-date / input-color)\n- `--xpl-icon-default` — leading clock icon color (matches input-date's calendar icon)\n- `--xpl-elevation-2` — time dropdown box-shadow (theme-aware; references the surface-transparent tokens, which flip to white-based transparency in dark mode)\n",
|
|
@@ -8763,7 +8763,7 @@
|
|
|
8763
8763
|
}
|
|
8764
8764
|
},
|
|
8765
8765
|
{
|
|
8766
|
-
"filePath": "src/components/
|
|
8766
|
+
"filePath": "src/components/xpl-large-card/xpl-large-card.tsx",
|
|
8767
8767
|
"encapsulation": "none",
|
|
8768
8768
|
"tag": "xpl-large-card",
|
|
8769
8769
|
"readme": "# xpl-large-card\n\nA card is a container and can contain any type of information. Cards contain actions and a content slot. Cards are flexible and can be arranged in grids or lists.\n\n## Design Tokens\n\nThe card is styled entirely with Apollo Foundation purpose-specific tokens (dark mode is automatic — no `.dark` overrides).\n\n| Element / state | Property | Token |\n| --- | --- | --- |\n| Host surface | `background-color` | `--xpl-background-surface-default` |\n| Host / anchor border | `border-color` | `--xpl-border-default` |\n| Host, header text | `color` | `--xpl-text-default` |\n| Header arrow (chevron) icon | `color` | `--xpl-icon-default` |\n| Description text | `color` | `--xpl-text-subdued` |\n| Anchor hover / active border | `border` | `--xpl-border-small` + `--xpl-background-action-primary-default` |\n| Anchor focus-visible border | `border` | `--xpl-border-small` + `--xpl-border-focus` (purple) |\n| Anchor focus-visible outline | `outline` | `--xpl-border-focus`, 2px width / 2px offset |\n| Anchor hover / focus-visible radius | `border-radius` | `--xpl-border-radius-default` |\n| Anchor hover shadow | `box-shadow` | `--xpl-elevation-2` (theme-aware) |\n| Header / tooltip / icon spacing | `margin` | `--xpl-space-4`, `--xpl-space-6`, `--xpl-space-8` |\n",
|
|
@@ -8881,10 +8881,10 @@
|
|
|
8881
8881
|
}
|
|
8882
8882
|
},
|
|
8883
8883
|
{
|
|
8884
|
-
"filePath": "src/components/
|
|
8884
|
+
"filePath": "src/components/xpl-list/xpl-list.tsx",
|
|
8885
8885
|
"encapsulation": "none",
|
|
8886
8886
|
"tag": "xpl-list",
|
|
8887
|
-
"readme": "# xpl-list\n\n## Description\n\n**`xpl-list`** is the list **container** (`role=\"list\"`). It coordinates **single selection** (shared radio group), **reordering** (drag-and-drop and keyboard), and assigns default **`item-id`** values when missing.\n\n**`xpl-list-item`** is one **row**. In **slot-based** mode, `role=\"listitem\"` is on the row surface inside the host (not on `<xpl-list-item>`), so list semantics work with the host’s `display: contents` layout. Legacy **`item`** rows keep `role=\"listitem\"` on the host. Place items **inside** **`xpl-list`** (default slot). Compose each row with **named slots** (recommended) or use the **legacy** `item` prop / list-level `items` array. Row-level props, events, and dependencies: [xpl-list-item readme](./xpl-list-item/readme.md).\n\nWhen the list is **`selectable`**, pressing **Escape** while focus is on the **selected** row clears the radio selection (same as **`clearSelection()`**). Clicking elsewhere does not clear selection. Row radios use the **title** slot for their accessible name when present; with no title slot, the label is **`Select <item-id>`** when **`item-id`** or **`id`** is set, otherwise a generic default.\n\n**Single-select vs multi-select:** **`selectable`** on **`xpl-list`** is for **exactly one chosen row** (implemented with **`xpl-radio`** and a shared group **`name`**). For **multi-select** or **independent** toggles per row, do **not** use this flag; compose **`xpl-checkbox`** (or your own controls) in row slots and manage state in the app.\n\n---\n\n## Slot-based vs legacy integration\n\n\n| | **Slot-based (recommended)** | **Legacy prop-based (deprecated)** |\n| ----------------------- | ------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- |\n| **Where content lives** | Light DOM: named slots on each `<xpl-list-item>` | Data: `items` on `<xpl-list>` and/or `item` on `<xpl-list-item>` |\n| **Row markup** | You author `<xpl-list-item>` children with `slot=\"…\"` content | List renders rows from `items`, or item renders from `item` object |\n| **Flexibility** | Full UI composition (avatar, actions, errors, extras) | Fixed layout from `ListItem` fields |\n| **Identity** | Set `item-id` (or `id`) on each row | Legacy rows from `items` use `ListItem.id` when set, else `item-0`, `item-1`, … |\n| **Reordering** | `reorderable` on `xpl-list`: drag handle + keyboard on each slot row | **No reorder UI:** legacy `items` / `item` rows do not render a handle; use slots if you need reorder. |\n| **Notes** | Do not set `item` on rows in this mode | `items` logs a console warning when non-empty; mixing `items` **and** slotted children renders **both** (legacy rows first) |\n\n\n---\n\n## Slot-based integration\n\nPut one or more `<xpl-list-item>` elements **inside** `<xpl-list>`. Do **not** set the **`item`** prop on a row when using slots—if `item` is set, that row uses **legacy** rendering and ignores slot composition.\n\nOn **`xpl-list`**, set `selectable` and/or `reorderable` as needed; the list mirrors `radio-name`, `reorderable`, and `keyboard-active` onto **slot-based** direct child rows only (nested lists in slots are unchanged). Rows using the deprecated **`item`** prop or list-level **`items`** array are **legacy** markup: the list does **not** set `selectable`, `radio-name`, or `reorderable` on them, because that UI exists only in slot-based mode—migrate to slotted `<xpl-list-item>` children if you need selection or reorder.\n\n### Slots (on `xpl-list-item`)\n\nAll slots are **named**. Use `slot=\"<name>\"` on light-DOM children.\n\n\n| Slot | Role | HTML example |\n| ----------------- | --------------------------------------------------------- | ----------------------------------------------------------------- |\n| `title` | Primary title line | `<span slot=\"title\">Account name</span>` |\n| `metadata` | Secondary lines under the title | `<ul slot=\"metadata\"><li>Line one</li></ul>` |\n| `avatar` | Leading avatar or custom media | `<xpl-avatar slot=\"avatar\" name=\"JD\"></xpl-avatar>` |\n| `details` | Right column: supporting text | `<span slot=\"details\">Last updated</span>` |\n| `badges` | Right column: badges / tags | `<span slot=\"badges\"><xpl-badge>New</xpl-badge></span>` |\n| `actions` | Trailing actions; clicks do **not** follow `href` | `<span slot=\"actions\"><xpl-button type=\"button\" variant=\"tertiary\" size=\"sm\">Edit</xpl-button></span>` |\n| `error-text` | Message below the row; affects error styling when present | `<span slot=\"error-text\">This field is required.</span>` |\n| `stacked-extra-1` | Optional stacked block | `<div slot=\"stacked-extra-1\">Extra block 1</div>` |\n| `stacked-extra-2` | Second optional stacked block | `<div slot=\"stacked-extra-2\">Extra block 2</div>` |\n| `stacked-extra-3` | Third optional stacked block | `<div slot=\"stacked-extra-3\">Extra block 3</div>` |\n\n\n**Dot badge next to the title:** set **`title-badge-variant`** on **`xpl-list-item`** (same variants as `xpl-badge`), not inside the title slot.\n\n**Divider under the title row:** set **`show-divider`** on **`xpl-list-item`**.\n\n**Minimal example:**\n\n```html\n<xpl-list selectable reorderable>\n <xpl-list-item item-id=\"row-1\" href=\"/settings\">\n <xpl-avatar slot=\"avatar\" name=\"AC\"></xpl-avatar>\n <span slot=\"title\">Settings</span>\n <span slot=\"metadata\">Workspace</span>\n <span slot=\"details\">Updated today</span>\n <span slot=\"actions\"><xpl-button type=\"button\" variant=\"tertiary\" size=\"sm\">Open</xpl-button></span>\n </xpl-list-item>\n</xpl-list>\n```\n\n---\n\n### Attributes: where to set them\n\n#### `xpl-list` (container)\n\n\n| Attribute | Purpose |\n| -------------- | ------------------------------------------------------------------------------------------------------------------------------------ |\n| `label` | Accessible name: sets `aria-label` on the list host when there is no visible heading. **Not used** if `labelled-by` is also set. |\n| `labelled-by` | Space-separated element ids: sets `aria-labelledby` on the host. Takes precedence over `label` so both are never applied together. |\n| `selectable` | Enables radio selection; list assigns shared `radio-name`. **Escape** on the **selected** row clears selection (no extra attribute). |\n| `reorderable` | Enables drag handles and reorder behavior on **slot-based** rows only (see legacy section). |\n\nUse **`label`** *or* **`labelled-by`**, not both. If both attributes are present, only **`labelled-by`** affects the accessible name.\n\n\n#### `xpl-list-item` (row, slot mode — omit `item`)\n\n\n| Attribute | Purpose |\n| ----------------------------- | -------------------------------------------------------------------------------------------------------------------- |\n| `item-id` | Stable id for selection and reorder events (or use host `id`). If omitted, the list may assign `item-0`, `item-1`, … |\n| `href` | Optional: row acts as a link; `actions` / `avatar` clicks do not navigate. |\n| `disabled`, `error` | Row state: non-interactive row and/or error styling (border, `error-text` slot). |\n| `hidden` | Hides the row from layout and from visible-only list behavior; see **Hidden rows** below. |\n| `selected` | Controlled selected state when the list is `selectable`. |\n| `show-divider` | Divider under the title area. |\n| `title-badge-variant` | Dot badge beside the title. |\n\n\n#### Usually set by `xpl-list` on items (avoid overriding unless needed)\n\n\n| Attribute | Meaning |\n| --------------------------- | --------------------------------------------------- |\n| `selectable`, `reorderable` | Mirrored from the list (**slot-based** rows only; not legacy `item` / `items` rows). |\n| `radio-name` | Shared radio group when the list is `selectable` (slot-based rows only). |\n| `keyboard-active` | Set on the row in keyboard reorder mode (slot-based rows only). |\n\n\n### Hidden rows\n\nSet the **`hidden`** attribute (or **`hidden`** prop) on **`xpl-list-item`** when a row should not appear in the list or take up space, but you still want it in the DOM. Typical use cases:\n\n- **Filtering or search** — hide rows that do not match without tearing down markup or losing local state.\n- **Progressive disclosure or permissions** — keep a stable **`item-id`** and show the row only when a condition becomes true.\n- **Temporary removal** — same as filtering when the row may return without re-creating the element.\n\n**List behavior:** Hidden rows are omitted from **`orderChange`**’s **`orderedItemIds`** and from drag-and-drop / keyboard reorder among **visible** rows only (see tests and list implementation). They do not receive focus while hidden.\n\n**Accessibility:** Native **`hidden`** removes the row from the accessibility tree while it is hidden. If users need an equivalent announcement elsewhere (for example, “3 results hidden by filter”), provide that in your application UI.\n\n---\n\n### Events and programmatic API\n\n#### `xpl-list` — listen on the list host\n\n\n| Event | When | `detail` |\n| ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------- |\n| `itemSelect` | Radio selection changes; when clearing via **`clearSelection()`** or **Escape** on the selected row, emitted **once per** previously selected row (typically one) | `{ itemId?: string }` |\n| `orderChange` | After a successful reorder (drag/drop or keyboard); DOM is already updated | `{ itemId?: string; direction: 'up' \\| 'down'; orderedItemIds: string[] }` |\n\n\n**`orderedItemIds`:** visible rows only (DOM order); hidden `xpl-list-item` rows are omitted.\n\n**TypeScript:** `orderChange` detail is typed as **`XplListOrderChangeDetail`** (exported from `@xplortech/apollo-core` alongside **`ListItem`**).\n\n**Legacy:** `xplListReorder` may also fire (bubbles, composed). Prefer **`orderChange`** for new code. Legacy `detail` includes `orderedItemIds` as well.\n\n\n| Method | Notes |\n| ------------------ | --------------------------------------------------------------------------------------------------- |\n| `clearSelection()` | Promise. Clears radios when `selectable`. Same effect as **Escape** with focus on the selected row. |\n\n\n```html\n<xpl-list id=\"my-list\" selectable reorderable>...</xpl-list>\n<script type=\"module\">\n const list = document.getElementById('my-list');\n list.addEventListener('itemSelect', (e) => {\n /* handle selection: */ void e.detail.itemId;\n });\n list.addEventListener('orderChange', (e) => {\n /* handle reorder: */ void e.detail.direction;\n void e.detail.orderedItemIds;\n });\n</script>\n```\n\n#### `xpl-list-item` — optional row-level listeners\n\n\n| Event | When | `detail` |\n| --------------- | ---------------------------------------------- | ---------------------------------------- |\n| `itemSelect` | Radio change on this row | `{ itemId?: string }` |\n| `itemDragStart` | Drag started from reorder handle | `{ itemId?: string; item: HTMLElement }` |\n| `itemDragEnd` | Drag ended on this row (after drop or cancel) | `{ itemId?: string; item: HTMLElement }` |\n| `itemDrop` | Drop target during reorder | `{ itemId?: string; item: HTMLElement }` |\n\n\n---\n\n## Legacy prop-based integration\n\nUse only for migration or data-driven rows. **Prefer slots for new work.**\n\n### At-a-glance migration\n\n| | **Before (deprecated)** | **After (recommended)** |\n| --- | --- | --- |\n| **Data** | `items` array on `xpl-list`, or `item` object on each row | Light DOM: `<xpl-list-item>` children with named slots |\n| **Identity** | Optional `ListItem.id`; else `item-0`, `item-1`, … | Explicit `item-id` (or host `id`) per row |\n\n```html\n<!-- Before: data-driven rows -->\n<xpl-list id=\"legacy-list\"></xpl-list>\n<script type=\"module\">\n document.getElementById('legacy-list').items = [{ title: 'Acme Co.', href: '/acme' }];\n</script>\n\n<!-- After: slot-based rows -->\n<xpl-list>\n <xpl-list-item item-id=\"acme\" href=\"/acme\">\n <span slot=\"title\">Acme Co.</span>\n </xpl-list-item>\n</xpl-list>\n```\n\n### `xpl-list` — `items` (deprecated)\n\n\n| Prop | Type | Description |\n| ------- | ------------ | ------------------------------------------------------------------------------------------------------- |\n| `items` | `ListItem[]` | **Deprecated.** Renders internal `<xpl-list-item>` rows with `item={...}` and ids `item-0`, `item-1`, … |\n\n\nA **console warning** runs when `items` is non-empty. Using **`items`** and slotted children renders **both**.\n\n### `xpl-list-item` — `item` (deprecated)\n\n\n| Prop | Type | Description |\n| ------ | ---------- | ---------------------------------------------------------------------------- |\n| `item` | `ListItem` | **Deprecated.** Prop-driven row; **no named slots**. Prefer slot-based rows. |\n\n\n### `ListItem` (`listitem.ts`, deprecated)\n\n\n| Field | Type | Notes |\n| ---------- | -------------------------------- | ---------------------- |\n| `id` | `string` | Optional stable row id (`item-id` when rendered from `items`) |\n| `title` | `string` | Required |\n| `href` | `string` | Optional |\n| `avatar` | `string` | Image URL or icon name |\n| `metadata` | `string[]` or `{ icon, text }[]` | |\n| `subtext` | `string` | |\n| `avatars` | `string[]` | |\n| `badges` | `string[]` or badge objects | |\n\n\n**Legacy layout:** Rows rendered from the deprecated `item` / inner `.xpl-list-item` flex markup use the **same layout at all viewport widths** (there is no dedicated narrow-viewport stacking breakpoint in `list-item.css`). If you need stacked mobile behavior for legacy lists, handle it in the app (e.g. layout wrapper or scoped CSS).\n\n**Legacy reordering:** The list does **not** set `reorderable` (or `selectable` / `radio-name`) on legacy **`items`** / **`item`** rows—there is **no** drag handle or keyboard reorder entry point in prop-driven mode. Only **slot-composed** rows participate in reorder and list-level selection UI; migrate from `items` / `item` to slotted `<xpl-list-item>` children if you need those features.\n\n---\n\n## Dependencies\n\n- **Rows:** `xpl-list-item` uses [xpl-avatar](../xpl-avatar), [xpl-icon](../xpl-icon), [xpl-badge](../xpl-badge), [xpl-divider](../xpl-divider).\n\n```mermaid\ngraph TD;\n xpl-list-item --> xpl-avatar\n xpl-list-item --> xpl-icon\n xpl-list-item --> xpl-badge\n xpl-list-item --> xpl-divider\n xpl-list --> xpl-list-item\n```\n\n\n\n## Design tokens\n\nList styling is split across [`list.css`](https://github.com/xplor/apollo/blob/main/packages/apollo-core/src/css/list.css) (the `xpl-list` host), [`list-item.css`](https://github.com/xplor/apollo/blob/main/packages/apollo-core/src/css/list-item.css) (legacy vs slot-based row layout, error/disabled/hidden, title/metadata columns), and [`list-action.css`](https://github.com/xplor/apollo/blob/main/packages/apollo-core/src/css/list-action.css) (reorder handle, selectable radio chrome, legacy action-button modifiers). All are imported from the package `style` entry. Visual values use **Apollo Foundation** CSS variables (`--xpl-*`); no raw hex colors in those stylesheets.\n\n\n| Category | Tokens (representative) |\n| -------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| **Layout / spacing** | `--xpl-space-4`, `--xpl-space-8`, `--xpl-space-12`, `--xpl-space-16`, `--xpl-space-40` |\n| **Sizing** | `--xpl-size-050`, `--xpl-size-075`, `--xpl-size-350` |\n| **Borders** | `--xpl-border-small`, `--xpl-border-large`, `--xpl-border-default`, `--xpl-border-hover`, `--xpl-border-focus`, `--xpl-border-negative`, `--xpl-border-subtle`, `--xpl-border-strong` |\n| **Radius** | `--xpl-border-radius-default`, `--xpl-border-radius-small`, `--xpl-border-radius-full` |\n| **Text** | `--xpl-text-default`, `--xpl-text-subdued`, `--xpl-text-disabled`, `--xpl-text-negative` |\n| **Icons / surfaces** | `--xpl-icon-default`, `--xpl-icon-subtle`, `--xpl-background-surface-default`, `--xpl-background-action-disabled`, `--xpl-background-surface-subtle` |\n| **Typography** | `--xpl-font-family-default`, `--xpl-font-size-body`, `--xpl-font-size-title-5`, `--xpl-font-size-callout`, `--xpl-font-size-caption`, `--xpl-font-weight-normal`, `--xpl-font-weight-medium` |\n\n\n## Accessibility\n\n- **`xpl-list`** sets `role=\"list\"` on the host. Use **`label`** / **`labelled-by`** when the list has no visible caption.\n- **`xpl-list-item`**: **`role=\"listitem\"`** is on the **inner row surface** in **slot-based** mode (see intro above); **legacy** `item` rows keep it on the **host**. When the list is **`selectable`**, the row renders **`xpl-radio`** with a shared group **`name`** and visually hidden label text (from the title slot when present, else a default).\n- With **`selectable`**, **Escape** while focus is on the **selected** row **clears selection** (same behavior as **`clearSelection()`**).\n- **Reorder**: the drag handle is a native **`<button>`** inside **`xpl-button`** (focusable, with **`aria-pressed`** in keyboard reorder mode and **`aria-label`** instructions for keyboard vs drag). Row links use `:focus-visible` for focus indication.\n- **`hidden`** on a row removes it from layout and visible reorder semantics; see **[Hidden rows](#hidden-rows)** for use cases and accessibility notes.\n\n---\n",
|
|
8887
|
+
"readme": "# xpl-list\n\n## Description\n\n**`xpl-list`** is the list **container** (`role=\"list\"`). It coordinates **single selection** (shared radio group), **reordering** (drag-and-drop and keyboard), and assigns default **`item-id`** values when missing.\n\n**`xpl-list-item`** is one **row**. In **slot-based** mode, `role=\"listitem\"` is on the row surface inside the host (not on `<xpl-list-item>`), so list semantics work with the host’s `display: contents` layout. Legacy **`item`** rows keep `role=\"listitem\"` on the host. Place items **inside** **`xpl-list`** (default slot). Compose each row with **named slots** (recommended) or use the **legacy** `item` prop / list-level `items` array. Row-level props, events, and dependencies: [xpl-list-item readme](./xpl-list-item/readme.md).\n\nWhen the list is **`selectable`**, pressing **Escape** while focus is on the **selected** row clears the radio selection (same as **`clearSelection()`**). Clicking elsewhere does not clear selection. Row radios use the **title** slot for their accessible name when present; with no title slot, the label is **`Select <item-id>`** when **`item-id`** or **`id`** is set, otherwise a generic default.\n\n**Single-select vs multi-select:** **`selectable`** on **`xpl-list`** is for **exactly one chosen row** (implemented with **`xpl-radio`** and a shared group **`name`**). For **multi-select** or **independent** toggles per row, do **not** use this flag; compose **`xpl-checkbox`** (or your own controls) in row slots and manage state in the app.\n\n---\n\n## Slot-based vs legacy integration\n\n\n| | **Slot-based (recommended)** | **Legacy prop-based (deprecated)** |\n| ----------------------- | ------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- |\n| **Where content lives** | Light DOM: named slots on each `<xpl-list-item>` | Data: `items` on `<xpl-list>` and/or `item` on `<xpl-list-item>` |\n| **Row markup** | You author `<xpl-list-item>` children with `slot=\"…\"` content | List renders rows from `items`, or item renders from `item` object |\n| **Flexibility** | Full UI composition (avatar, actions, errors, extras) | Fixed layout from `ListItem` fields |\n| **Identity** | Set `item-id` (or `id`) on each row | Legacy rows from `items` use `ListItem.id` when set, else `item-0`, `item-1`, … |\n| **Reordering** | `reorderable` on `xpl-list`: drag handle + keyboard on each slot row | **No reorder UI:** legacy `items` / `item` rows do not render a handle; use slots if you need reorder. |\n| **Notes** | Do not set `item` on rows in this mode | `items` logs a console warning when non-empty; mixing `items` **and** slotted children renders **both** (legacy rows first) |\n\n\n---\n\n## Slot-based integration\n\nPut one or more `<xpl-list-item>` elements **inside** `<xpl-list>`. Do **not** set the **`item`** prop on a row when using slots—if `item` is set, that row uses **legacy** rendering and ignores slot composition.\n\nOn **`xpl-list`**, set `selectable` and/or `reorderable` as needed; the list mirrors `radio-name`, `reorderable`, and `keyboard-active` onto **slot-based** direct child rows only (nested lists in slots are unchanged). Rows using the deprecated **`item`** prop or list-level **`items`** array are **legacy** markup: the list does **not** set `selectable`, `radio-name`, or `reorderable` on them, because that UI exists only in slot-based mode—migrate to slotted `<xpl-list-item>` children if you need selection or reorder.\n\n### Slots (on `xpl-list-item`)\n\nAll slots are **named**. Use `slot=\"<name>\"` on light-DOM children.\n\n\n| Slot | Role | HTML example |\n| ----------------- | --------------------------------------------------------- | ----------------------------------------------------------------- |\n| `title` | Primary title line | `<span slot=\"title\">Account name</span>` |\n| `metadata` | Secondary lines under the title | `<ul slot=\"metadata\"><li>Line one</li></ul>` |\n| `avatar` | Leading avatar or custom media | `<xpl-avatar slot=\"avatar\" name=\"JD\"></xpl-avatar>` |\n| `details` | Right column: supporting text | `<span slot=\"details\">Last updated</span>` |\n| `badges` | Right column: badges / tags | `<span slot=\"badges\"><xpl-badge>New</xpl-badge></span>` |\n| `actions` | Trailing actions; clicks do **not** follow `href` | `<span slot=\"actions\"><xpl-button type=\"button\" variant=\"tertiary\" size=\"sm\">Edit</xpl-button></span>` |\n| `error-text` | Message below the row; affects error styling when present | `<span slot=\"error-text\">This field is required.</span>` |\n| `stacked-extra-1` | Optional stacked block | `<div slot=\"stacked-extra-1\">Extra block 1</div>` |\n| `stacked-extra-2` | Second optional stacked block | `<div slot=\"stacked-extra-2\">Extra block 2</div>` |\n| `stacked-extra-3` | Third optional stacked block | `<div slot=\"stacked-extra-3\">Extra block 3</div>` |\n\n\n**Dot badge next to the title:** set **`title-badge-variant`** on **`xpl-list-item`** (same variants as `xpl-badge`), not inside the title slot.\n\n**Divider under the title row:** set **`show-divider`** on **`xpl-list-item`**.\n\n**Minimal example:**\n\n```html\n<xpl-list selectable reorderable>\n <xpl-list-item item-id=\"row-1\" href=\"/settings\">\n <xpl-avatar slot=\"avatar\" name=\"AC\"></xpl-avatar>\n <span slot=\"title\">Settings</span>\n <span slot=\"metadata\">Workspace</span>\n <span slot=\"details\">Updated today</span>\n <span slot=\"actions\"><xpl-button type=\"button\" variant=\"tertiary\" size=\"sm\">Open</xpl-button></span>\n </xpl-list-item>\n</xpl-list>\n```\n\n---\n\n### Attributes: where to set them\n\n#### `xpl-list` (container)\n\n\n| Attribute | Purpose |\n| -------------- | ------------------------------------------------------------------------------------------------------------------------------------ |\n| `label` | Accessible name: sets `aria-label` on the list host when there is no visible heading. **Not used** if `labelled-by` is also set. |\n| `labelled-by` | Space-separated element ids: sets `aria-labelledby` on the host. Takes precedence over `label` so both are never applied together. |\n| `selectable` | Enables radio selection; list assigns shared `radio-name`. **Escape** on the **selected** row clears selection (no extra attribute). |\n| `reorderable` | Enables drag handles and reorder behavior on **slot-based** rows only (see legacy section). |\n\nUse **`label`** *or* **`labelled-by`**, not both. If both attributes are present, only **`labelled-by`** affects the accessible name.\n\n\n#### `xpl-list-item` (row, slot mode — omit `item`)\n\n\n| Attribute | Purpose |\n| ----------------------------- | -------------------------------------------------------------------------------------------------------------------- |\n| `item-id` | Stable id for selection and reorder events (or use host `id`). If omitted, the list may assign `item-0`, `item-1`, … |\n| `href` | Optional: row acts as a link; `actions` / `avatar` clicks do not navigate. |\n| `disabled`, `error` | Row state: non-interactive row and/or error styling (border, `error-text` slot). |\n| `hidden` | Hides the row from layout and from visible-only list behavior; see **Hidden rows** below. |\n| `selected` | Controlled selected state when the list is `selectable`. |\n| `show-divider` | Divider under the title area. |\n| `title-badge-variant` | Dot badge beside the title. |\n\n\n#### Usually set by `xpl-list` on items (avoid overriding unless needed)\n\n\n| Attribute | Meaning |\n| --------------------------- | --------------------------------------------------- |\n| `selectable`, `reorderable` | Mirrored from the list (**slot-based** rows only; not legacy `item` / `items` rows). |\n| `radio-name` | Shared radio group when the list is `selectable` (slot-based rows only). |\n| `keyboard-active` | Set on the row in keyboard reorder mode (slot-based rows only). |\n\n\n### Hidden rows\n\nSet the **`hidden`** attribute (or **`hidden`** prop) on **`xpl-list-item`** when a row should not appear in the list or take up space, but you still want it in the DOM. Typical use cases:\n\n- **Filtering or search** — hide rows that do not match without tearing down markup or losing local state.\n- **Progressive disclosure or permissions** — keep a stable **`item-id`** and show the row only when a condition becomes true.\n- **Temporary removal** — same as filtering when the row may return without re-creating the element.\n\n**List behavior:** Hidden rows are omitted from **`orderChange`**’s **`orderedItemIds`** and from drag-and-drop / keyboard reorder among **visible** rows only (see tests and list implementation). They do not receive focus while hidden.\n\n**Accessibility:** Native **`hidden`** removes the row from the accessibility tree while it is hidden. If users need an equivalent announcement elsewhere (for example, “3 results hidden by filter”), provide that in your application UI.\n\n---\n\n### Events and programmatic API\n\n#### `xpl-list` — listen on the list host\n\n\n| Event | When | `detail` |\n| ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------- |\n| `itemSelect` | Radio selection changes; when clearing via **`clearSelection()`** or **Escape** on the selected row, emitted **once per** previously selected row (typically one) | `{ itemId?: string }` |\n| `orderChange` | After a successful reorder (drag/drop or keyboard); DOM is already updated | `{ itemId?: string; direction: 'up' \\| 'down'; orderedItemIds: string[] }` |\n\n\n**`orderedItemIds`:** visible rows only (DOM order); hidden `xpl-list-item` rows are omitted.\n\n**TypeScript:** `orderChange` detail is typed as **`XplListOrderChangeDetail`** (exported from `@xplortech/apollo-core` alongside **`ListItem`**).\n\n**Legacy:** `xplListReorder` may also fire (bubbles, composed). Prefer **`orderChange`** for new code. Legacy `detail` includes `orderedItemIds` as well.\n\n\n| Method | Notes |\n| ------------------ | --------------------------------------------------------------------------------------------------- |\n| `clearSelection()` | Promise. Clears radios when `selectable`. Same effect as **Escape** with focus on the selected row. |\n\n\n```html\n<xpl-list id=\"my-list\" selectable reorderable>...</xpl-list>\n<script type=\"module\">\n const list = document.getElementById('my-list');\n list.addEventListener('itemSelect', (e) => {\n /* handle selection: */ void e.detail.itemId;\n });\n list.addEventListener('orderChange', (e) => {\n /* handle reorder: */ void e.detail.direction;\n void e.detail.orderedItemIds;\n });\n</script>\n```\n\n#### `xpl-list-item` — optional row-level listeners\n\n\n| Event | When | `detail` |\n| --------------- | ---------------------------------------------- | ---------------------------------------- |\n| `itemSelect` | Radio change on this row | `{ itemId?: string }` |\n| `itemDragStart` | Drag started from reorder handle | `{ itemId?: string; item: HTMLElement }` |\n| `itemDragEnd` | Drag ended on this row (after drop or cancel) | `{ itemId?: string; item: HTMLElement }` |\n| `itemDrop` | Drop target during reorder | `{ itemId?: string; item: HTMLElement }` |\n\n\n---\n\n## Legacy prop-based integration\n\nUse only for migration or data-driven rows. **Prefer slots for new work.**\n\n### At-a-glance migration\n\n| | **Before (deprecated)** | **After (recommended)** |\n| --- | --- | --- |\n| **Data** | `items` array on `xpl-list`, or `item` object on each row | Light DOM: `<xpl-list-item>` children with named slots |\n| **Identity** | Optional `ListItem.id`; else `item-0`, `item-1`, … | Explicit `item-id` (or host `id`) per row |\n\n```html\n<!-- Before: data-driven rows -->\n<xpl-list id=\"legacy-list\"></xpl-list>\n<script type=\"module\">\n document.getElementById('legacy-list').items = [{ title: 'Acme Co.', href: '/acme' }];\n</script>\n\n<!-- After: slot-based rows -->\n<xpl-list>\n <xpl-list-item item-id=\"acme\" href=\"/acme\">\n <span slot=\"title\">Acme Co.</span>\n </xpl-list-item>\n</xpl-list>\n```\n\n### `xpl-list` — `items` (deprecated)\n\n\n| Prop | Type | Description |\n| ------- | ------------ | ------------------------------------------------------------------------------------------------------- |\n| `items` | `ListItem[]` | **Deprecated.** Renders internal `<xpl-list-item>` rows with `item={...}` and ids `item-0`, `item-1`, … |\n\n\nA **console warning** runs when `items` is non-empty. Using **`items`** and slotted children renders **both**.\n\n### `xpl-list-item` — `item` (deprecated)\n\n\n| Prop | Type | Description |\n| ------ | ---------- | ---------------------------------------------------------------------------- |\n| `item` | `ListItem` | **Deprecated.** Prop-driven row; **no named slots**. Prefer slot-based rows. |\n\n\n### `ListItem` (`listitem.ts`, deprecated)\n\n\n| Field | Type | Notes |\n| ---------- | -------------------------------- | ---------------------- |\n| `id` | `string` | Optional stable row id (`item-id` when rendered from `items`) |\n| `title` | `string` | Required |\n| `href` | `string` | Optional |\n| `avatar` | `string` | Image URL or icon name |\n| `metadata` | `string[]` or `{ icon, text }[]` | |\n| `subtext` | `string` | |\n| `avatars` | `string[]` | |\n| `badges` | `string[]` or badge objects | |\n\n\n**Legacy layout:** Rows rendered from the deprecated `item` / inner `.xpl-list-item` flex markup use the **same layout at all viewport widths** (there is no dedicated narrow-viewport stacking breakpoint in `list-item.css`). If you need stacked mobile behavior for legacy lists, handle it in the app (e.g. layout wrapper or scoped CSS).\n\n**Legacy reordering:** The list does **not** set `reorderable` (or `selectable` / `radio-name`) on legacy **`items`** / **`item`** rows—there is **no** drag handle or keyboard reorder entry point in prop-driven mode. Only **slot-composed** rows participate in reorder and list-level selection UI; migrate from `items` / `item` to slotted `<xpl-list-item>` children if you need those features.\n\n---\n\n## Dependencies\n\n- **Rows:** `xpl-list-item` uses [xpl-avatar](../xpl-avatar), [xpl-icon](../xpl-icon), [xpl-badge](../xpl-badge), [xpl-divider](../xpl-divider).\n\n```mermaid\ngraph TD;\n xpl-list-item --> xpl-avatar\n xpl-list-item --> xpl-icon\n xpl-list-item --> xpl-badge\n xpl-list-item --> xpl-divider\n xpl-list --> xpl-list-item\n```\n\n\n\n## Design tokens\n\nList styling is split across [`list.css`](https://github.com/xplor/apollo/blob/main/packages/apollo-core/src/components/xpl-list/list.css) (the `xpl-list` host), [`list-item.css`](https://github.com/xplor/apollo/blob/main/packages/apollo-core/src/components/xpl-list/xpl-list-item/list-item.css) (legacy vs slot-based row layout, error/disabled/hidden, title/metadata columns), and [`list-action.css`](https://github.com/xplor/apollo/blob/main/packages/apollo-core/src/components/xpl-list/list-action.css) (reorder handle, selectable radio chrome, legacy action-button modifiers). All are imported from the package `style` entry. Visual values use **Apollo Foundation** CSS variables (`--xpl-*`); no raw hex colors in those stylesheets.\n\n\n| Category | Tokens (representative) |\n| -------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| **Layout / spacing** | `--xpl-space-4`, `--xpl-space-8`, `--xpl-space-12`, `--xpl-space-16`, `--xpl-space-40` |\n| **Sizing** | `--xpl-size-050`, `--xpl-size-075`, `--xpl-size-350` |\n| **Borders** | `--xpl-border-small`, `--xpl-border-large`, `--xpl-border-default`, `--xpl-border-hover`, `--xpl-border-focus`, `--xpl-border-negative`, `--xpl-border-subtle`, `--xpl-border-strong` |\n| **Radius** | `--xpl-border-radius-default`, `--xpl-border-radius-small`, `--xpl-border-radius-full` |\n| **Text** | `--xpl-text-default`, `--xpl-text-subdued`, `--xpl-text-disabled`, `--xpl-text-negative` |\n| **Icons / surfaces** | `--xpl-icon-default`, `--xpl-icon-subtle`, `--xpl-background-surface-default`, `--xpl-background-action-disabled`, `--xpl-background-surface-subtle` |\n| **Typography** | `--xpl-font-family-default`, `--xpl-font-size-body`, `--xpl-font-size-title-5`, `--xpl-font-size-callout`, `--xpl-font-size-caption`, `--xpl-font-weight-normal`, `--xpl-font-weight-medium` |\n\n\n## Accessibility\n\n- **`xpl-list`** sets `role=\"list\"` on the host. Use **`label`** / **`labelled-by`** when the list has no visible caption.\n- **`xpl-list-item`**: **`role=\"listitem\"`** is on the **inner row surface** in **slot-based** mode (see intro above); **legacy** `item` rows keep it on the **host**. When the list is **`selectable`**, the row renders **`xpl-radio`** with a shared group **`name`** and visually hidden label text (from the title slot when present, else a default).\n- With **`selectable`**, **Escape** while focus is on the **selected** row **clears selection** (same behavior as **`clearSelection()`**).\n- **Reorder**: the drag handle is a native **`<button>`** inside **`xpl-button`** (focusable, with **`aria-pressed`** in keyboard reorder mode and **`aria-label`** instructions for keyboard vs drag). Row links use `:focus-visible` for focus indication.\n- **`hidden`** on a row removes it from layout and visible reorder semantics; see **[Hidden rows](#hidden-rows)** for use cases and accessibility notes.\n\n---\n",
|
|
8888
8888
|
"docs": "",
|
|
8889
8889
|
"docsTags": [
|
|
8890
8890
|
{
|
|
@@ -8908,7 +8908,7 @@
|
|
|
8908
8908
|
"ListItem": {
|
|
8909
8909
|
"location": "import",
|
|
8910
8910
|
"path": "./listitem",
|
|
8911
|
-
"id": "src/components/
|
|
8911
|
+
"id": "src/components/xpl-list/listitem.ts::ListItem",
|
|
8912
8912
|
"referenceLocation": "ListItem"
|
|
8913
8913
|
}
|
|
8914
8914
|
}
|
|
@@ -9088,7 +9088,7 @@
|
|
|
9088
9088
|
"XplListOrderChangeDetail": {
|
|
9089
9089
|
"location": "import",
|
|
9090
9090
|
"path": "./listitem",
|
|
9091
|
-
"id": "src/components/
|
|
9091
|
+
"id": "src/components/xpl-list/listitem.ts::XplListOrderChangeDetail",
|
|
9092
9092
|
"referenceLocation": "XplListOrderChangeDetail"
|
|
9093
9093
|
}
|
|
9094
9094
|
}
|
|
@@ -9170,7 +9170,7 @@
|
|
|
9170
9170
|
}
|
|
9171
9171
|
},
|
|
9172
9172
|
{
|
|
9173
|
-
"filePath": "src/components/
|
|
9173
|
+
"filePath": "src/components/xpl-list/xpl-list-item/xpl-list-item.tsx",
|
|
9174
9174
|
"encapsulation": "none",
|
|
9175
9175
|
"tag": "xpl-list-item",
|
|
9176
9176
|
"readme": "# xpl-list-item\n\nSingle row for [`xpl-list`](../xpl-list/readme.md). **Slot-based** rows expose `role=\"listitem\"` on the inner row surface (`.xpl-list-item__wrapper` or `.xpl-list-item__listitem-shell` when `href` is set); **legacy** `item` rows use `role=\"listitem\"` on the host. Hand-written integration notes for slots, attributes, and events live in the [list readme](../xpl-list/readme.md); the section below is Stencil-generated API for this component.\n\n**Reorder handle (slot mode):** When `reorderable` is enabled and the row uses **slot-based** content, the handle is an **`xpl-button`** wrapping a native **`<button>`**. Reorder logic is wired on the **`xpl-button` host** (`mousedown` / `keydown`); those events originate on the inner `<button>` and **bubble** to the host, which is how the list item receives them today. If `xpl-button` ever stopped bubbling for those events, reorder handlers would need to attach directly to the inner button (similar to `componentDidRender` syncing `aria-*` on that element).\n\n**Legacy `item` prop:** Prop-driven rows **do not** render the reorder handle, radios, or keyboard reorder affordances. Parent `xpl-list` **does not** set `selectable`, `radio-name`, or `reorderable` on those rows (those attributes are removed so they are not mistaken for supported behavior). Use slots if you need selection, drag, or keyboard reorder.\n\n### Accessibility\n\n- **`role=\"listitem\"`** is on the inner row surface (`.xpl-list-item__wrapper` for non-link rows, `.xpl-list-item__listitem-shell` for link rows), not on the `<xpl-list-item>` host. This avoids older browser issues with `display: contents` and ARIA.\n- **Hidden rows** render an empty host with the native `hidden` attribute only — no `role=\"listitem\"` — so hidden rows are removed from the accessibility tree entirely.\n- **Selectable rows** render `xpl-radio` with an accessible label derived from the **title** slot text, falling back to `Select <item-id>`, then `Select list item`.\n- **Reorder handle** (`xpl-button`) syncs `aria-label` and `aria-pressed` on the inner native `<button>` via `componentDidRender`. Labels change between drag and keyboard modes.\n- **Focus indicators** use `:focus-visible` with `outline-color: var(--xpl-border-focus)` and `outline-2 outline-offset-2`.\n- **Disabled rows** use `--xpl-background-action-disabled` and `--xpl-text-disabled`; link anchors get `pointer-events: none`.\n- **Keyboard reorder**: Enter/Space activates mode, ArrowUp/ArrowDown moves the row, Escape exits.\n\n### Design tokens\n\n| Role | Token |\n|------|-------|\n| Row background | `--xpl-background-surface-default` |\n| Row border | `--xpl-border-default` (default), `--xpl-border-hover` (hover), `--xpl-border-negative` (error), `--xpl-border-focus` (focus/drag-over) |\n| Row border-radius | `--xpl-border-radius-default` |\n| Text | `--xpl-text-default` (primary), `--xpl-text-subdued` (metadata/details), `--xpl-text-negative` (error), `--xpl-text-disabled` |\n| Icon | `--xpl-icon-subtle` (chevron) |\n| Spacing | `--xpl-space-4` through `--xpl-space-40` (padding, gap, margins) |\n| Sizing | `--xpl-size-050` (dot badge), `--xpl-size-350` (min-height) |\n| Typography | `--xpl-font-size-body`, `--xpl-font-size-title-5`, `--xpl-font-size-callout`, `--xpl-font-size-caption` |\n| Disabled background | `--xpl-background-action-disabled` |\n| Selected background | `--xpl-background-surface-subtle` |\n| Drag opacity | `--xpl-opacity-75` (custom token in `:root`) |\n",
|
|
@@ -9339,7 +9339,7 @@
|
|
|
9339
9339
|
"ListItem": {
|
|
9340
9340
|
"location": "import",
|
|
9341
9341
|
"path": "../listitem",
|
|
9342
|
-
"id": "src/components/
|
|
9342
|
+
"id": "src/components/xpl-list/listitem.ts::ListItem",
|
|
9343
9343
|
"referenceLocation": "ListItem"
|
|
9344
9344
|
}
|
|
9345
9345
|
}
|
|
@@ -9559,7 +9559,7 @@
|
|
|
9559
9559
|
"BadgeVariantProp": {
|
|
9560
9560
|
"location": "import",
|
|
9561
9561
|
"path": "../../xpl-badge/xpl-badge",
|
|
9562
|
-
"id": "src/components/
|
|
9562
|
+
"id": "src/components/xpl-badge/xpl-badge.tsx::BadgeVariantProp",
|
|
9563
9563
|
"referenceLocation": "BadgeVariantProp"
|
|
9564
9564
|
}
|
|
9565
9565
|
}
|
|
@@ -9779,7 +9779,7 @@
|
|
|
9779
9779
|
}
|
|
9780
9780
|
},
|
|
9781
9781
|
{
|
|
9782
|
-
"filePath": "src/components/
|
|
9782
|
+
"filePath": "src/components/xpl-main-nav/xpl-main-nav.tsx",
|
|
9783
9783
|
"encapsulation": "none",
|
|
9784
9784
|
"tag": "xpl-main-nav",
|
|
9785
9785
|
"readme": "# xpl-main-nav\n\nThe Main Nav component contains is split in 3 areas. The top area is where the branding goes. It's divided into 2 slots `logo` and `brand-name`.\nThe middle area is where the main navigation links go. It's a `<nav>` tag with a slot named `navigation`, where a `<ul slot=\"navigation\">` with `<xpl-nav-items>` should be rendered.\n\nThe bottom area is fixed to the bottom and should be used for actions. To render content within this area use the slot `footer` with a `<ul slot=\"footer\">` tag.\n\n### Design Tokens\n\n`xpl-main-nav` is the legacy always-dark side-nav rail; its surface never mode-switches, so colors resolve to the same dark-appropriate value in both page themes.\n\n**Color**\n- `--xpl-background-surface-inverse-on-light` — rail surface (neutral-1000, both modes; matches the application-shell nav host)\n- `--xpl-color-neutral-1100` — footer surface (primitive; no purpose token — see `TECH_DEBT.md`)\n- `--xpl-text-subdued` — rail on-surface base text and nav-item rest label (neutral-600 light / neutral-500 dark; Figma-confirmed; keeps text off the ambient page color on the dark rail)\n- `--xpl-text-inverse-on-dark` — brand name + footer primary text (white, both modes)\n- `--xpl-icon-subtle` — muted footer icon (neutral-500, both modes)\n\n**Typography**\n- `--xpl-font-size-body` — collapsed (`sm`/`md`) nav item label size\n- `--xpl-line-height-body` — collapsed (`sm`/`md`) nav item label line height\n- `--xpl-line-height-title-4` — brand lockup text line height (title-4)\n\n**Layout**\n- Collapse-state widths (240 / 112 / 74px) and the 42px brand logo box are raw literals — no matching Foundation size token (see `TECH_DEBT.md`)\n",
|
|
@@ -9900,7 +9900,7 @@
|
|
|
9900
9900
|
"dependencyGraph": {}
|
|
9901
9901
|
},
|
|
9902
9902
|
{
|
|
9903
|
-
"filePath": "src/components/
|
|
9903
|
+
"filePath": "src/components/xpl-modal/xpl-modal.tsx",
|
|
9904
9904
|
"encapsulation": "none",
|
|
9905
9905
|
"tag": "xpl-modal",
|
|
9906
9906
|
"readme": "# xpl-modal\n\nModals are dialogs that focus the user’s attention exclusively on one task or piece of information via a window layer above the current content.\n\nModals are disruptive and should only be used when disrupting the user’s flow is desired.\n\n## Token Use\n\n`xpl-modal` uses Apollo Foundation purpose-specific tokens; light and dark mode are handled by the token definitions, so the component has no `.dark` overrides.\n\n| Element | Property | Token |\n| ------- | -------- | ----- |\n| `&__dialog` | background | `--xpl-background-surface-default` |\n| `&__dialog` | text color | `--xpl-text-default` |\n| `&__dialog` | radius | `--xpl-border-radius-large` |\n| `&__dialog` | shadow | `--xpl-elevation-4` (theme-aware) |\n| `&__title` | typography (size / weight / line-height) | `@extend .xpl-text-title-3` → `title-3` / `bold` / `1.4` |\n| `&__subtitle` | color | `--xpl-text-subdued` |\n| `&__subtitle` | typography (size / weight / line-height) | `@extend .xpl-text-callout` → `callout` / `normal` / `1.3333` |\n| `&__body` | typography (size / weight / line-height) | `@extend .xpl-text-body` → `body` / `normal` / `1.4286` |\n| `&__alert-icon` | color | `--xpl-icon-negative` |\n\nModal widths are documented CSS literals: small `400px`, medium `600px`, large `800px`, mobile `350px` (see `modal.css` and `TECH_DEBT.md`).\n\n> **Elevation shadow:** the dialog uses `--xpl-elevation-4` (theme-aware), which matches Figma's \"Shadow 4\" style (`y=20`, `blur=25`, color `background-surface-transparent-10`). See `TECH_DEBT.md`.\n\n## Accessibility\n\n`xpl-modal` renders a native `<dialog>` shown via `showModal()`: focus is trapped inside the modal while it is open, and `Escape` closes it (emitting `modalClosed`).\n\nKeyboard tab order follows the DOM order of the footer slots: **close (×) → `primary` → `secondary` → `tertiary` → back to ×**. The footer's visual layout (tertiary pinned far-left, secondary and primary right-aligned) is produced with CSS `order` in `modal.css`, so the visual arrangement and the tab order are independent by design — do not reorder the `<slot>` elements in the component template to change the layout.\n\n### Accessible names\n\nThe dialog is named by the `title` slot: the component wraps that slot in `.xpl-modal__title-text`, gives it a per-instance id, and points the dialog's `aria-labelledby` at it. Always provide a `title` slot — without one the dialog is announced only as \"dialog\". The label deliberately references the title text rather than the whole `.xpl-modal__title` row, which would fold the close button's own name into the dialog's name.\n\nThe close (×) button carries `aria-label=\"Close modal\"`, so screen readers announce its purpose instead of the underlying icon name.\n\n## Mounting and unmounting\n\n`showModal()` promotes the dialog into the browser's top layer, where it survives the removal of its host element. `xpl-modal` closes the dialog when the host disconnects so a removed modal cannot leave a blocking overlay behind, and re-opens it — reattaching the `Escape` and backdrop listeners — if the host is connected again while `isOpen` is still `true`. Frameworks that move or reparent DOM nodes therefore get consistent state without extra work from the consumer.\n",
|
|
@@ -10104,10 +10104,10 @@
|
|
|
10104
10104
|
}
|
|
10105
10105
|
},
|
|
10106
10106
|
{
|
|
10107
|
-
"filePath": "src/components/
|
|
10107
|
+
"filePath": "src/components/xpl-top-nav/xpl-nav-header-menu/xpl-nav-header-menu.tsx",
|
|
10108
10108
|
"encapsulation": "none",
|
|
10109
10109
|
"tag": "xpl-nav-header-menu",
|
|
10110
|
-
"readme": "# xpl-nav-header-menu\n\nProfile block (username, email) and a default slot for menu rows. Typically inside **`xpl-popover`** or **`xpl-dropdown`** under a user trigger.\n\n**Styles** for this component live in **`packages/apollo-core/src/
|
|
10110
|
+
"readme": "# xpl-nav-header-menu\n\nProfile block (username, email) and a default slot for menu rows. Typically inside **`xpl-popover`** or **`xpl-dropdown`** under a user trigger.\n\n**Styles** for this component live in **`packages/apollo-core/src/components/xpl-top-nav/top-nav.css`** (with **`xpl-top-nav-item`** rules in the same file).\n\n## Usage\n\n```html\n<xpl-nav-header-menu username=\"Katie Wilson\" email=\"katie@example.com\">\n <xpl-top-nav-item label=\"View account\" icon=\"house-4\" href=\"/account\"></xpl-top-nav-item>\n <xpl-top-nav-item label=\"Log out\" icon=\"open-rect-arrow-out\" href=\"/logout\"></xpl-top-nav-item>\n</xpl-nav-header-menu>\n```\n\nOptional narrow-only duplicate of bar actions (e.g. Inbox) between the profile block and the list — use **`slot=\"right-aside-mobile\"`** with **`xpl-top-nav-item`** or **`xpl-button`**. That strip is visible by default only on **narrow viewports** (one pixel below Tailwind **`md`** — see **`top-nav.css`**).\n\n```html\n<xpl-nav-header-menu username=\"Katie Wilson\" email=\"katie@example.com\">\n <xpl-top-nav-item slot=\"right-aside-mobile\" label=\"Inbox\" icon=\"mail-1\" href=\"/inbox\"></xpl-top-nav-item>\n <xpl-top-nav-item label=\"Log out\" icon=\"open-rect-arrow-out\" href=\"/logout\"></xpl-top-nav-item>\n</xpl-nav-header-menu>\n```\n\n## Token Use\n\nSpacing, typography, and colors use Apollo Foundation **`var(--xpl-*)`** tokens (e.g. **`--xpl-text-strong`**, **`--xpl-space-*`**, **`--xpl-font-size-*`**). Panel width uses the component-scoped custom property **`--xpl-top-nav-panel-width`** on **`xpl-top-nav`** / **`xpl-nav-header-menu`** hosts (composed from **`--xpl-size-*`** in **`top-nav.css`**).\n\n## Accessibility\n\n- The default slot is wrapped in a container with **`role=\"list\"`**. Use **`xpl-top-nav-item`** for rows so each item exposes **`role=\"listitem\"`** and keyboard/focus behavior from **`xpl-top-nav-item`** (including **`Enter`** / **`Space`** on non-link controls and **`:focus-visible`** outline on the inner control).\n- The host may include Foundation’s **`dark`** class so purpose tokens match account menu contrast when the page root is light.\n- **`slot=\"right-aside-mobile\"`** is not a list; do not rely on **`role=\"list\"`** for that block.\n\n## Events\n\nThis component does not emit custom events. Use **`xpl-top-nav-item`** **`navItemClick`** (or native link navigation) for row actions.\n",
|
|
10111
10111
|
"docs": "Profile / account block (username, email, default slot for **`xpl-top-nav-item`** / **`xpl-divider`**).\nTag **`xpl-nav-header-menu`**; implementation folder **`xpl-nav-header-menu`**. **`.xpl-nav-header-menu__slot`** is\n**`role=\"list\"`** for slotted **`xpl-top-nav-item`** (**`role=\"listitem\"`**).\n\n**Slotted content:** do not add **`xpl-nav-header-menu__*`** BEM classes on nodes you pass into the default slot —\nprofile, list shell, and **`xpl-top-nav-item`** **`role=\"listitem\"`** are handled by the component. Use\n**`xpl-top-nav-item`** (or plain elements that are not Apollo **`xpl-*`** BEM hooks) in the slot only.\n\n**`slot=\"right-aside-mobile\"`** — optional block **between** the profile header and the default-slot list (e.g. narrow-only\nduplicate of **every** **`slot=\"right-aside\"`** control per Figma when **`xpl-top-nav`** hides **`right-aside`** on narrow viewports (always)).\nNot **`role=\"list\"`**; use **`xpl-button`** / **`xpl-top-nav-item`** as needed. Shown only on **narrow viewports** (one pixel below Tailwind **`md`** — **`top-nav.css`**) so bar actions stay in **`slot=\"right-aside\"`** on wider viewports.\nLight-DOM **`slotchange`** is unreliable; a host **`MutationObserver`** (child / subtree / **`slot`** attribute) keeps\n**`xpl-nav-header-menu--has-right-aside-mobile`** in sync when nodes are added or retargeted after mount (same pattern as **`xpl-top-nav`**).\nStencil **`newSpecPage`** / mock-doc does not define **`MutationObserver`**; slot presence still updates on the next\ndeferred flush (**`setTimeout(0)`** coalesced with **`componentDidRender`**). In real browsers the observer handles child /\n**`slot`** mutations without stacking uncancellable microtasks.\n\n**Theming:** The host always includes Foundation’s **`dark`** class so **`--xpl-*`** purpose tokens resolve to dark-mode\nvalues even when the page root is light (same contract as **`xpl-top-nav`** / **`xpl-top-nav-item`**).",
|
|
10112
10112
|
"docsTags": [
|
|
10113
10113
|
{
|
|
@@ -10189,10 +10189,10 @@
|
|
|
10189
10189
|
"dependencyGraph": {}
|
|
10190
10190
|
},
|
|
10191
10191
|
{
|
|
10192
|
-
"filePath": "src/components/
|
|
10192
|
+
"filePath": "src/components/xpl-nav-item/xpl-nav-item.tsx",
|
|
10193
10193
|
"encapsulation": "none",
|
|
10194
10194
|
"tag": "xpl-nav-item",
|
|
10195
|
-
"readme": "# xpl-nav-item\n\nThis component should be used within sections of the `<xpl-main-nav>`. This component yields a slot named `link`, where a `<a>` tag should be used. Within the `<a>` tag, there are two slots, one named `icon`, where any svg can be placed. An an unnamed slot, where the link text should be placed.\n\n### Design Tokens\n\n`xpl-nav-item` renders on the legacy always-dark side-nav rail, so its colors resolve to the same dark-appropriate value in both light and dark page themes.\n\n**Color**\n- `--xpl-icon-subtle` — rest icon (neutral-500, both modes)\n- `--xpl-text-subdued` — rest label text (neutral-600 light / neutral-500 dark; Figma-confirmed)\n- `--xpl-text-inverse-on-dark` / `--xpl-icon-inverse-on-dark` — hover / focus / active / selected label and icon (white, both modes)\n- `--xpl-color-neutral-1200` — hover / focus / active background (primitive; no purpose token — see `TECH_DEBT.md`)\n- `--xpl-color-orange-400` — active brand accent border + icon (primitive; consult-Figma — see `TECH_DEBT.md`)\n\n**Border**\n-
|
|
10195
|
+
"readme": "# xpl-nav-item\n\nThis component should be used within sections of the `<xpl-main-nav>`. This component yields a slot named `link`, where a `<a>` tag should be used. Within the `<a>` tag, there are two slots, one named `icon`, where any svg can be placed. An an unnamed slot, where the link text should be placed.\n\n### Design Tokens\n\n`xpl-nav-item` renders on the legacy always-dark side-nav rail, so its colors resolve to the same dark-appropriate value in both light and dark page themes.\n\n**Color**\n- `--xpl-icon-subtle` — rest icon (neutral-500, both modes)\n- `--xpl-text-subdued` — rest label text (neutral-600 light / neutral-500 dark; Figma-confirmed)\n- `--xpl-text-inverse-on-dark` / `--xpl-icon-inverse-on-dark` — hover / focus / active / selected label and icon (white, both modes)\n- `--xpl-color-neutral-1200` — hover / focus / active background (primitive; no purpose token — see `TECH_DEBT.md`)\n- `--xpl-color-orange-400` — active brand accent border + icon (primitive; consult-Figma — see `TECH_DEBT.md`)\n\n**Border**\n- `--xpl-border-xlarge` — 4px active accent border width\n",
|
|
10196
10196
|
"docs": "This component should be used within sections of the `<xpl-main-nav>`. This component yields a slot named `link`, where a `<a>` tag should be used. Within the `<a>` tag, there are two slots, one named `icon`, where any svg can be placed. An an unnamed slot, where the link text should be placed.",
|
|
10197
10197
|
"docsTags": [
|
|
10198
10198
|
{
|
|
@@ -10293,10 +10293,10 @@
|
|
|
10293
10293
|
"dependencyGraph": {}
|
|
10294
10294
|
},
|
|
10295
10295
|
{
|
|
10296
|
-
"filePath": "src/components/
|
|
10296
|
+
"filePath": "src/components/xpl-pagination/xpl-pagination.tsx",
|
|
10297
10297
|
"encapsulation": "none",
|
|
10298
10298
|
"tag": "xpl-pagination",
|
|
10299
|
-
"readme": "# xpl-pagination\n\nPagination bar allows users to navigate pages of content.\n\n> **Note:** This component is in beta. Use with caution and expect updates before the full release.\n\n## Design Tokens\n\nPagination themes with the app (light/dark) using Apollo Foundation tokens\n(`packages/apollo-core/src/
|
|
10299
|
+
"readme": "# xpl-pagination\n\nPagination bar allows users to navigate pages of content.\n\n> **Note:** This component is in beta. Use with caution and expect updates before the full release.\n\n## Design Tokens\n\nPagination themes with the app (light/dark) using Apollo Foundation tokens\n(`packages/apollo-core/src/components/xpl-pagination/pagination.css`):\n\n| Element / state | Property | Token | Resolves (light / dark) |\n| --- | --- | --- | --- |\n| Pager button surface | `background-color` | `--xpl-background-action-secondary-default` | neutral-0 / neutral-1000 |\n| Pager button border | `border-color` | `--xpl-border-strong` | neutral-600 / neutral-400 |\n| Pager arrow icon | `color` (icon) | `--xpl-icon-default` | neutral-1000 / neutral-0 |\n| Pager button hover/active border | `border-color` | `--xpl-background-action-primary-default` | purple-700 / purple-300 |\n| Pager button focus | `outline-color` | `--xpl-border-focus` (2px, 2px offset) | purple-800 / purple-400 |\n| Pager button disabled icon | `color` (icon) | `--xpl-icon-disabled` | neutral-600 / neutral-500 |\n| Pager button disabled bg | `background-color` | `--xpl-background-action-disabled` | neutral-100 / neutral-800 |\n| Pager container text | `color` | `--xpl-text-default` | neutral-900 / neutral-50 |\n| Rows-per-page label | `color` | `--xpl-text-default` | neutral-900 / neutral-50 |\n| Rows-per-page label | `font-size` / `font-weight` / `line-height` | `@extend .xpl-text-body` (14px, normal, 1.4286) | — |\n| Go-to-page value | `color` | `--xpl-text-link-default` | purple-700 / purple-300 |\n| Active page background | `background-color` | `--xpl-background-brand-secondary-surface` | purple-50 / purple-900 |\n| Pager button / page size | `width` / `height` | `--xpl-size-250` | 40px |\n| Prev / next radius | `border-radius` | `--xpl-border-radius-full` | pill |\n\n> **Accessibility:** keyboard focus uses the Foundation `:focus-visible` outline pattern\n> (`--xpl-border-focus`, 2px outline + 2px offset) instead of a Tailwind `ring`, so the\n> focus ring stays visible on the pager buttons in both themes.\n>\n> **Note:** the rows-per-page (72px), page-select (88px), and page-info (70px) min-widths\n> have no matching Foundation size token and remain literals — see `TECH_DEBT.md`.\n",
|
|
10300
10300
|
"docs": "Pagination bar allows users to navigate pages of content.\n\n> **Note:** This component is in beta. Use with caution and expect updates before the full release.",
|
|
10301
10301
|
"docsTags": [
|
|
10302
10302
|
{
|
|
@@ -10521,7 +10521,7 @@
|
|
|
10521
10521
|
}
|
|
10522
10522
|
},
|
|
10523
10523
|
{
|
|
10524
|
-
"filePath": "src/components/
|
|
10524
|
+
"filePath": "src/components/xpl-panel/xpl-panel.tsx",
|
|
10525
10525
|
"encapsulation": "none",
|
|
10526
10526
|
"tag": "xpl-panel",
|
|
10527
10527
|
"readme": "# xpl-panel\n\n`xpl-panel` is a stateless, composable container that defines a section on a page and can house any type of content. Panels are not dismissible and may show a colored top accent bar. Padding is applied evenly to **`.xpl-panel__content`** (all sides use the same spacing token).\n\n## Accessibility\n\nThe panel is a generic layout container: it does not define a landmark role or trap focus. Place interactive controls in the default slot. For a named region, wrap the panel (or its content) in an element with `role=\"region\"` and an accessible name (e.g. `aria-label`) when the panel represents a distinct section.\n\nWhen an accent is present, the accent bar is a decorative `div` with `aria-hidden=\"true\"` so assistive technologies ignore it; meaning comes from slot content.\n\n## Token use\n\n**Host (surface)**\n\n\n| Property | Token |\n| ------------- | --------------------------------------- |\n| Background | `var(--xpl-background-surface-default)` |\n| Border color | `var(--xpl-border-default)` |\n| Border width | `var(--xpl-border-small)` |\n| Border radius | `var(--xpl-border-radius-default)` |\n\n\n**Accent bar** (`accent` ≠ `none`): height `var(--xpl-size-050)`; top radii `var(--xpl-border-radius-default)`, bottom `var(--xpl-border-radius-none)`.\n\n\n| `accent` | Background token |\n| ----------- | ---------------------------------------- |\n| `primary` | `var(--xpl-background-brand-primary)` |\n| `secondary` | `var(--xpl-background-brand-secondary)` |\n| `positive` | `var(--xpl-background-accent-positive)` |\n| `negative` | `var(--xpl-background-accent-negative)` |\n| `highlight` | `var(--xpl-background-accent-highlight)` |\n\n\nLight and dark mode follow Apollo Foundation purpose-specific tokens; the component does not use `.dark` overrides in its CSS.\n\n## Content padding by viewport\n\nThe `padding` prop sets **content** padding via `var(--xpl-space-*)` on `.xpl-panel__content`. Two `max-width` media queries step values down on smaller viewports (`panel.css`).\n\n### Matrix: `padding` × viewport\n\n\n| Viewport | Approx. width | `padding=\"default\"` | `padding=\"tight\"` | `padding=\"loose\"` |\n| ---------- | ------------------- | ---------------------------- | ---------------------------- | ---------------------------- |\n| **Large** | > 768px | `var(--xpl-space-24)` · 24px | `var(--xpl-space-16)` · 16px | `var(--xpl-space-40)` · 40px |\n| **Tablet** | ≤ 768px and > 480px | same as large | same as large | `var(--xpl-space-32)` · 32px |\n| **Mobile** | ≤ 480px | `var(--xpl-space-16)` · 16px | `var(--xpl-space-8)` · 8px | `var(--xpl-space-24)` · 24px |\n\n\n**How the breakpoints stack**\n\n1. Base rules apply the **Large** row for all widths.\n2. At `max-width: 768px`, only **loose** changes (tablet row for that column).\n3. At `max-width: 480px`, **default**, **tight**, and **loose** all use the **Mobile** row.\n\nPixel values match the Foundation `space/`* scale; if tokens change in a future Foundation release, spacing updates without component code changes.\n\n## Usage\n\n### Web component\n\n```html\n<xpl-panel>\n <p>Any content goes here.</p>\n</xpl-panel>\n```\n\n```html\n<xpl-panel accent=\"primary\">\n <p>Content with a primary accent bar.</p>\n</xpl-panel>\n```\n\nAvailable accent values: `none` (default), `primary`, `secondary`, `positive`, `negative`, `highlight`.\n\n### Padding density\n\n```html\n<xpl-panel padding=\"tight\">\n <p>Tighter padding on small screens (see content padding matrix).</p>\n</xpl-panel>\n```\n\nUse `padding=\"default\"` | `\"tight\"` | `\"loose\"`. **default** and **tight** keep the same values from large screens through tablet; only at **≤480px** do they step down. **loose** steps down at **≤768px** (tablet) and again at **≤480px** (mobile).\n\n### HTML/CSS (no Stencil)\n\nUse the same BEM classes the component applies on the host. The accent bar must stay decorative (`aria-hidden=\"true\"`).\n\n```html\n<div class=\"xpl-panel xpl-panel--accent-primary xpl-panel--padding-default\">\n <div aria-hidden=\"true\" class=\"xpl-panel__accent\"></div>\n <div class=\"xpl-panel__content\">\n <p>Panel body</p>\n </div>\n</div>\n```\n\nOmit `xpl-panel--accent-*` when `accent` is `none`; do not render `.xpl-panel__accent`.\n\n### Composing with other components\n\n```html\n<xpl-panel accent=\"secondary\" padding=\"loose\">\n <xpl-accordion header=\"Details\">\n <div slot=\"content\">Accordion inside a panel.</div>\n </xpl-accordion>\n</xpl-panel>\n```\n\n### Content styling\n\nThe panel intentionally does **not** apply default typography or color styles to slotted content. It provides the surface (background, border, accent) and content padding — nothing more. This means text inside the panel inherits whatever styles the surrounding page defines.\n\nTo ensure consistent, theme-aware content you should use Apollo Foundation tokens on elements inside the slot:\n\n```html\n<xpl-panel>\n <h3 class=\"xpl-text-title-4\" style=\"color: var(--xpl-text-strong)\">Section title</h3>\n <p class=\"xpl-text-body\" style=\"color: var(--xpl-text-default)\">\n Body copy that adapts to light and dark mode automatically.\n </p>\n <p class=\"xpl-text-caption\" style=\"color: var(--xpl-text-subdued)\">\n Subdued helper text.\n </p>\n</xpl-panel>\n```\n\n| Purpose | Recommended token |\n| ------- | ----------------- |\n| Primary text | `var(--xpl-text-default)` |\n| Headings / emphasis | `var(--xpl-text-strong)` |\n| Secondary / helper text | `var(--xpl-text-subdued)` |\n| Disabled text | `var(--xpl-text-disabled)` |\n| Links | `var(--xpl-text-link-default)` |\n\nUsing purpose-specific text tokens guarantees content switches correctly in dark mode. If slot content uses raw colors (e.g. `color: #333`) or relies on browser defaults, text will **not** adapt when the panel's ancestor has the `dark` class.\n\n### Dark mode\n\nUse an ancestor with the `dark` class — surface, border, and accent tokens update via Foundation.\n\n## Design\n\n- [Figma: xpl-panel](https://www.figma.com/design/MjjYek73MFnHmVNdm45Sd1/Apollo-Web?node-id=1546-136120&p=f)\n",
|
|
@@ -10644,7 +10644,7 @@
|
|
|
10644
10644
|
"dependencyGraph": {}
|
|
10645
10645
|
},
|
|
10646
10646
|
{
|
|
10647
|
-
"filePath": "src/components/
|
|
10647
|
+
"filePath": "src/components/xpl-popover/xpl-popover.tsx",
|
|
10648
10648
|
"encapsulation": "none",
|
|
10649
10649
|
"tag": "xpl-popover",
|
|
10650
10650
|
"readme": "# xpl-popover\n\nA popover is an overlay that pops up over all other layers and is triggered by a click or tap, and dismissed by clicking outside the popover or a dismiss icon. Popovers can contain additional actions and allow those actions to be triggered.\n\n\n### Design Tokens\n\nTokens used by this component from `@xplortech/apollo-foundation`.\n\n**Color**\n- `--xpl-background-surface-default` — content panel background and arrow fill\n- `--xpl-elevation-2` — content panel shadow (theme-aware)\n- `--xpl-text-default` — content text color\n- `--xpl-border-default` — content panel border and arrow stroke\n\n**Spacing**\n- `--xpl-space-8` — popover margin (offset from trigger), via `--xpl-popover-margin`\n- `--xpl-space-16` — content panel padding (Figma `padding/tight`; corrected from the legacy 24px during the Foundation migration — see `TECH_DEBT.md`)\n\n**Border**\n- `--xpl-border-small` — border width (1px)\n- `--xpl-border-radius-default` — content panel corner radius (8px)\n\n**Z-index**\n- `--xpl-z-index-100` — content panel stacking order\n- `--xpl-z-index-900` — arrow stacking order\n",
|
|
@@ -10766,8 +10766,8 @@
|
|
|
10766
10766
|
"references": {
|
|
10767
10767
|
"PopoverPosition": {
|
|
10768
10768
|
"location": "local",
|
|
10769
|
-
"path": "/home/runner/work/apollo/apollo/packages/apollo-core/src/components/
|
|
10770
|
-
"id": "src/components/
|
|
10769
|
+
"path": "/home/runner/work/apollo/apollo/packages/apollo-core/src/components/xpl-popover/xpl-popover.tsx",
|
|
10770
|
+
"id": "src/components/xpl-popover/xpl-popover.tsx::PopoverPosition"
|
|
10771
10771
|
}
|
|
10772
10772
|
}
|
|
10773
10773
|
},
|
|
@@ -10888,7 +10888,7 @@
|
|
|
10888
10888
|
}
|
|
10889
10889
|
},
|
|
10890
10890
|
{
|
|
10891
|
-
"filePath": "src/components/
|
|
10891
|
+
"filePath": "src/components/xpl-progress-bar/xpl-progress-bar.tsx",
|
|
10892
10892
|
"encapsulation": "none",
|
|
10893
10893
|
"tag": "xpl-progress-bar",
|
|
10894
10894
|
"readme": "# xpl-progress-bar\n\nThe `xpl-progress-bar` component displays the progress of an operation, such as file uploads, form completion, or loading states. It supports multiple visual variants including default, success, error, and indeterminate states, with optional label and helper text.\n\n## Usage\n\n### Basic progress bar\n\n```html\n<xpl-progress-bar label=\"Uploading...\" value=\"45\"></xpl-progress-bar>\n```\n\n### With helper text\n\n```html\n<xpl-progress-bar\n label=\"Uploading file...\"\n value=\"65\"\n helper-text=\"2.4 MB of 5 MB\">\n</xpl-progress-bar>\n```\n\n### Error state\n\n```html\n<xpl-progress-bar\n label=\"Upload failed\"\n value=\"30\"\n variant=\"error\"\n helper-text=\"Network error. Please check your connection.\">\n</xpl-progress-bar>\n```\n\n### Indeterminate loading\n\n```html\n<xpl-progress-bar label=\"Processing...\" variant=\"indeterminate\"></xpl-progress-bar>\n```\n\n### Small size\n\n```html\n<xpl-progress-bar value=\"60\" size=\"sm\"></xpl-progress-bar>\n```\n\n### Custom max value\n\n```html\n<xpl-progress-bar value=\"75\" max=\"150\" label=\"75 of 150 items\"></xpl-progress-bar>\n```\n\n## Variants\n\n| Variant | Description |\n|---------|-------------|\n| `default` | Standard progress bar with accent color fill. Shows a checkmark icon when value reaches max. |\n| `success` | Explicit success state with positive color. Shows a checkmark icon. |\n| `error` | Error state with negative color. Shows an error (x-mark) icon. Helper text is recommended for this state. |\n| `indeterminate` | Used when the progress duration is unknown. Displays an animated sliding bar instead of a fill percentage. |\n\n## Sizes\n\n- `lg` (default): 6px height\n- `sm`: 4px height\n\n## Icon Mapping\n\nThe component automatically renders status icons based on the variant or completion state:\n\n| State | xpl-icon name |\n|-------|---------------|\n| Complete (default variant when value equals max) | `circle-check-1` |\n| Success variant | `circle-check-1` |\n| Error variant | `circle-xmark-1` |\n\n## Design Tokens\n\nThe following Apollo Foundation tokens are used by this component:\n\n### Background Colors (Fill)\n- `--xpl-background-accent-default` - Default variant fill\n- `--xpl-background-accent-positive-bold` - Success/complete fill\n- `--xpl-background-accent-negative-bold` - Error fill\n- `--xpl-background-accent-neutral` - Track background\n\n### Icon Colors\n- `--xpl-icon-positive` - Success/complete icon\n- `--xpl-icon-negative` - Error icon\n\n### Text Colors\n- `--xpl-text-default` - Label text\n- `--xpl-text-subdued` - Helper text\n- `--xpl-text-negative` - Error helper text\n\n### Typography\n- `--xpl-font-size-callout` - Label font size\n- `--xpl-font-size-caption` - Helper text font size\n- `--xpl-font-weight-normal` - Label and helper font weight\n\n### Spacing & Sizing\n- `--xpl-space-8` - Gap between elements\n- `--xpl-size-025` (4px) - Small bar height\n- `--xpl-size-0375` (6px) - Large bar height\n- `--xpl-border-radius-full` - Bar border radius\n\n## Accessibility\n\n- **Determinate variants** (default, success, error) use the native HTML `<progress>` element, which provides:\n - Native `role=\"progressbar\"` semantics\n - Automatic `aria-valuenow`, `aria-valuemin`, `aria-valuemax` handling\n - Native value/max API with built-in clamping\n- **Indeterminate variant** uses a custom `<div role=\"progressbar\">` since native `<progress>` indeterminate state cannot be styled cross-browser\n- The `aria-label` is set from the `label` prop, or falls back to `'Progress'` when no label is provided\n",
|
|
@@ -11100,7 +11100,7 @@
|
|
|
11100
11100
|
}
|
|
11101
11101
|
},
|
|
11102
11102
|
{
|
|
11103
|
-
"filePath": "src/components/
|
|
11103
|
+
"filePath": "src/components/xpl-progress-indicator/xpl-progress-indicator.tsx",
|
|
11104
11104
|
"encapsulation": "none",
|
|
11105
11105
|
"tag": "xpl-progress-indicator",
|
|
11106
11106
|
"readme": "# xpl-progress-indicator\n\nA progress indicator that guides users through linear, multi-step tasks by displaying completed, current, and future steps. Progress indicators help manage user expectations by showing their position in a multi-step process, the total number of steps, and overall progress toward task completion.\n\n## Usage\n\n```html\n<!-- Basic horizontal progress with numbered steps -->\n<xpl-progress-indicator steps='[\"Details\", \"Location\", \"Review\"]' current-step=\"1\"></xpl-progress-indicator>\n\n<!-- Vertical layout for side navigation -->\n<xpl-progress-indicator steps='[\"Step 1\", \"Step 2\", \"Step 3\"]' current-step=\"0\" layout=\"vertical\"></xpl-progress-indicator>\n\n<!-- Dots only (no numbers) with labels -->\n<xpl-progress-indicator steps='[\"Upload\", \"Process\", \"Complete\"]' current-step=\"1\" show-numbers=\"false\"></xpl-progress-indicator>\n\n<!-- Numbers only (no labels) -->\n<xpl-progress-indicator steps='[\"Step 1\", \"Step 2\", \"Step 3\"]' current-step=\"1\" show-labels=\"false\"></xpl-progress-indicator>\n\n<!-- Minimal dots only -->\n<xpl-progress-indicator steps='[\"Step 1\", \"Step 2\", \"Step 3\"]' current-step=\"1\" show-numbers=\"false\" show-labels=\"false\"></xpl-progress-indicator>\n```\n\n## Layouts\n\n### Horizontal (Default)\n\nThe horizontal layout displays steps in a row with a 16px gap between each step. Steps are connected by absolute-positioned lines that maintain consistent spacing from circle edges. Step labels appear below the circles and wrap naturally when the container narrows. This layout is ideal for page headers and top-level step navigation in desktop applications.\n\nThe layout is responsive: steps distribute equally via `flex: 1`, with a minimum width of 32px (the circle size) to prevent overlap. Labels wrap within their column using `overflow-wrap: break-word`. When the container becomes too narrow for all steps, the progress indicator will overflow horizontally rather than squashing elements together.\n\n```html\n<xpl-progress-indicator steps='[\"Details\", \"Location\", \"Instructor\", \"Review\"]' current-step=\"1\"></xpl-progress-indicator>\n```\n\n### Vertical\n\nThe vertical layout stacks steps vertically with connecting lines running downward. Labels appear to the right of each circle. This layout works well for side navigation panels and narrow spaces.\n\n```html\n<xpl-progress-indicator steps='[\"Step 1\", \"Step 2\", \"Step 3\"]' current-step=\"1\" layout=\"vertical\"></xpl-progress-indicator>\n```\n\n## Display Options\n\n### Step Numbers\n\nBy default, each step circle displays its index number (1, 2, 3, etc.). Set `show-numbers=\"false\"` to display dots instead of numbers for a more minimal appearance.\n\n| Option | Visual |\n|--------|--------|\n| `show-numbers=\"true\"` (default) | Numbered circles |\n| `show-numbers=\"false\"` | Dots for waiting/active, checkmark for finished |\n\n### Step Labels\n\nStep labels appear below (horizontal) or beside (vertical) each circle by default. Set `show-labels=\"false\"` to hide labels and show only the step indicators.\n\nIn horizontal mode, labels are constrained to the width of their step column and will wrap naturally using `overflow-wrap: break-word` when the container narrows. This prevents labels from colliding with neighboring steps.\n\n| Option | Horizontal | Vertical |\n|--------|------------|----------|\n| `show-labels=\"true\"` (default) | Labels below circles, wrap when narrow | Labels beside circles |\n| `show-labels=\"false\"` | Circles only | Circles only |\n\n## Step States\n\nEach step can be in one of three states, determined by comparing the step index to `current-step`:\n\n| State | Visual | Description |\n|-------|--------|-------------|\n| **Waiting** | Gray circle/dot | Steps after the current step |\n| **Active** | Purple bordered circle | The current step (`current-step` index) |\n| **Finished** | Filled purple circle with checkmark | Steps before the current step |\n\n## Icon Mapping\n\nThe progress component uses `xpl-icon` for the finished step indicator:\n\n| State | Icon Name |\n|-------|-----------|\n| Finished | `check-2` |\n\n## Design Tokens\n\nThe progress component uses the following Apollo Foundation tokens:\n\n### Horizontal Layout\n\n| Element | Property | Token/Value |\n|---------|----------|-------------|\n| Container | Min width | `0px` (fluid) |\n| | Width | `100%` |\n| | Padding horizontal | `--xpl-space-16` (16px) |\n| | Gap (between steps) | `--xpl-space-16` (16px) |\n| | Flex | `1` (equal width distribution) |\n| Step Circle | Width/Height | `--xpl-size-200` (32px) |\n| | Border | `--xpl-border-default` (waiting), `--xpl-border-focus` (active) |\n| | Border radius | `--xpl-border-radius-full` |\n| | Font size | `--xpl-font-size-title-5` |\n| | Font weight | `--xpl-font-weight-medium` |\n| Connector Line | Position | Absolute, from circle edge to edge |\n| | Height | `--xpl-size-0125` (2px) |\n| | Margins | `--xpl-space-4` (4px) from circle edges |\n| | Color (waiting) | `--xpl-border-default` |\n| | Color (finished) | `--xpl-background-action-primary-default` |\n| Step Label | Font size | `--xpl-font-size-title-5` |\n| | Color (waiting) | `--xpl-text-subdued` |\n| | Color (active) | `--xpl-text-default` |\n| | Layout | In normal flow, wraps at narrow widths |\n| | Max width | `100%` of step column |\n\n### Vertical Layout\n\n| Element | Property | Token/Value |\n|---------|----------|-------------|\n| Container | Min width | `--xpl-size-0` (0px) |\n| | Min height | `0px` (fluid) |\n| | Height | `100%` |\n| Connector Line | Width | `--xpl-size-0125` (2px) |\n| | Color (waiting) | `--xpl-border-default` |\n| | Color (finished) | `--xpl-background-action-primary-default` |\n| Step Label | Margin left | `--xpl-space-8` (8px) |\n\n### Step States\n\n| State | Circle Background | Circle Border | Circle Text |\n|-------|-------------------|---------------|-------------|\n| Waiting | Transparent | `--xpl-border-default` | `--xpl-text-subdued` |\n| Active | Transparent | `--xpl-border-focus` | `--xpl-text-link-default` |\n| Finished | `--xpl-background-action-primary-default` | `--xpl-border-accent-default` | `--xpl-text-inverse` |\n\n## Accessibility\n\n### ARIA structure\n\nThe host element uses `role=\"group\"` with a dynamic `aria-label` that announces the current position:\n\n| Condition | `aria-label` value |\n|-----------|-------------------|\n| Steps in progress | `\"Progress: step 2 of 5\"` |\n| All steps complete | `\"Progress: all 5 steps complete\"` |\n| No steps provided | `\"Progress\"` |\n\nSteps are wrapped in a container with `role=\"list\"`, and each step is a `role=\"listitem\"`. The active step receives `aria-current=\"step\"`; non-active steps do not carry `aria-current`.\n\n### Keyboard interaction\n\nThis component is a display-only progress indicator and does not require keyboard interaction. It is typically used alongside form navigation controls (e.g., Previous/Next buttons) that manage step changes.\n\n### Visual distinction\n\n- State changes use both color and shape differences (numbered circles, dots, and checkmark icons) to support colorblind users.\n- The `xpl-icon` component with icon `check-2` provides the finished-step checkmark at an accessible size (20px).\n\n## HTML/CSS Usage\n\nWhen building the progress component in plain HTML, use the following structure:\n\n```html\n<!-- Horizontal progress -->\n<div class=\"xpl-progress-indicator xpl-progress-indicator-horizontal\" role=\"group\" aria-label=\"Progress: step 2 of 3\">\n<div class=\"xpl-progress-indicator-container\" role=\"list\">\n <!-- Step 1: Finished -->\n<div class=\"xpl-progress-indicator-step xpl-progress-indicator-step-finished\" role=\"listitem\" aria-label=\"Details, completed\">\n<div class=\"xpl-progress-indicator-step-content\">\n<div class=\"xpl-progress-indicator-step-circle\">\n <xpl-icon icon=\"check-2\" size=\"20\"></xpl-icon>\n </div>\n<div class=\"xpl-progress-indicator-step-text\">Details</div>\n </div>\n </div>\n <!-- Step 2: Active -->\n<div class=\"xpl-progress-indicator-step xpl-progress-indicator-step-active\" role=\"listitem\" aria-label=\"Location, current\" aria-current=\"step\">\n<div class=\"xpl-progress-indicator-step-content\">\n<div class=\"xpl-progress-indicator-step-circle\">2</div>\n<div class=\"xpl-progress-indicator-step-text\">Location</div>\n </div>\n </div>\n <!-- Step 3: Waiting -->\n<div class=\"xpl-progress-indicator-step\" role=\"listitem\" aria-label=\"Review, upcoming\">\n<div class=\"xpl-progress-indicator-step-content\">\n<div class=\"xpl-progress-indicator-step-circle\">3</div>\n<div class=\"xpl-progress-indicator-step-text\">Review</div>\n </div>\n </div>\n </div>\n</div>\n\n<!-- Vertical progress -->\n<div class=\"xpl-progress-indicator xpl-progress-indicator-vertical\" role=\"group\" aria-label=\"Progress: step 2 of 3\">\n<div class=\"xpl-progress-indicator-container\" role=\"list\">\n <!-- Step 1: Finished -->\n<div class=\"xpl-progress-indicator-step xpl-progress-indicator-step-finished\" role=\"listitem\" aria-label=\"Step 1, completed\">\n<div class=\"xpl-progress-indicator-step-circle\">\n <xpl-icon icon=\"check-2\" size=\"20\"></xpl-icon>\n </div>\n<div class=\"xpl-progress-indicator-step-text\">Step 1</div>\n </div>\n <!-- ... additional steps ... -->\n </div>\n</div>\n```\n",
|
|
@@ -11275,7 +11275,7 @@
|
|
|
11275
11275
|
}
|
|
11276
11276
|
},
|
|
11277
11277
|
{
|
|
11278
|
-
"filePath": "src/components/
|
|
11278
|
+
"filePath": "src/components/xpl-radio/xpl-radio.tsx",
|
|
11279
11279
|
"encapsulation": "none",
|
|
11280
11280
|
"tag": "xpl-radio",
|
|
11281
11281
|
"readme": "# xpl-radio\n\nRadio buttons allow users to make selections or choices. Radios are always single select, and can also act as controls.\n\n## Design Tokens\n\nThe radio component uses the following Apollo Foundation tokens:\n\n| Token | Usage |\n|-------|-------|\n| `--xpl-background-surface-default` | Disabled checked state background; styled label background (resting/hover/focused) |\n| `--xpl-background-action-disabled` | Disabled state background; disabled label background (styled variant) |\n| `--xpl-background-surface-information` | Checked label background (styled variant) |\n| `--xpl-border-strong` | Resting (unchecked) border color |\n| `--xpl-border-hover` | Checked/hover/active border color; styled container hover/focus border |\n| `--xpl-border-default` | Disabled state border color |\n| `--xpl-border-focus` | Focus visible outline |\n| `--xpl-border-radius-small` | Styled container corner radius (4px) |\n| `--xpl-border-small` | Default border width (1px) |\n| `--xpl-size-100` | Radio dimensions (16px) |\n\n### Label tokens (shared `label.css`)\n\nThe radio label and description are styled by the shared `.xpl-label` / `.xpl-description` classes.\n\n| Token | Usage |\n|-------|-------|\n| `--xpl-text-strong` | Label text color (matches `.xpl-input-label`; resolves to white in dark mode) |\n| `--xpl-text-disabled` | Disabled label text color |\n| `--xpl-text-subdued` | Description text color (enabled and disabled) |\n| `.xpl-text-body` | Label typography: `--xpl-font-size-body` (14px) / normal / 1.4286 line-height |\n| `.xpl-text-callout` | Description typography: `--xpl-font-size-callout` (12px) / normal / 1.3333 line-height |\n",
|
|
@@ -11519,10 +11519,10 @@
|
|
|
11519
11519
|
}
|
|
11520
11520
|
},
|
|
11521
11521
|
{
|
|
11522
|
-
"filePath": "src/components/
|
|
11522
|
+
"filePath": "src/components/xpl-secondary-nav/xpl-secondary-nav.tsx",
|
|
11523
11523
|
"encapsulation": "none",
|
|
11524
11524
|
"tag": "xpl-secondary-nav",
|
|
11525
|
-
"readme": "# secondary-nav\n\nThe Secondary Nav component is a component that allows navigation within the content area. It yields one slot where a <ul> element with <xpl-nav-item> elements should be rendered.\n\n## Design Tokens\n\nThe secondary nav uses Apollo Foundation purpose-specific tokens, which theme automatically in light and dark mode (no `.dark` overrides).\n\n| Element / state | Property | Token |\n| --- | --- | --- |\n| `nav`, `ul`, host, item | `background` | `--xpl-background-surface-default` |\n| item (default) | `color` | `--xpl-text-subdued` |\n| item | `font-size` | `--xpl-font-size-body` (0.875rem / 14px) |\n| item | `font-weight` | `--xpl-font-weight-normal` (400) |\n| item hover | `color` | `--xpl-text-strong` |\n| item hover | `background` | `--xpl-background-surface-transparent-0` |\n| item active | `color` | `--xpl-text-strong` |\n| item active | `background` | `--xpl-background-brand-primary-surface` |\n| item active | accent `border-color` | `--xpl-border-accent-brand` |\n| item `:focus-visible` | `outline-color` | `--xpl-border-focus` |\n| item `:focus-visible` | `z-index` (above scroll fade) | `--xpl-z-index-200` |\n| item accent border | `border-width` (
|
|
11525
|
+
"readme": "# secondary-nav\n\nThe Secondary Nav component is a component that allows navigation within the content area. It yields one slot where a <ul> element with <xpl-nav-item> elements should be rendered.\n\n## Design Tokens\n\nThe secondary nav uses Apollo Foundation purpose-specific tokens, which theme automatically in light and dark mode (no `.dark` overrides).\n\n| Element / state | Property | Token |\n| --- | --- | --- |\n| `nav`, `ul`, host, item | `background` | `--xpl-background-surface-default` |\n| item (default) | `color` | `--xpl-text-subdued` |\n| item | `font-size` | `--xpl-font-size-body` (0.875rem / 14px) |\n| item | `font-weight` | `--xpl-font-weight-normal` (400) |\n| item hover | `color` | `--xpl-text-strong` |\n| item hover | `background` | `--xpl-background-surface-transparent-0` |\n| item active | `color` | `--xpl-text-strong` |\n| item active | `background` | `--xpl-background-brand-primary-surface` |\n| item active | accent `border-color` | `--xpl-border-accent-brand` |\n| item `:focus-visible` | `outline-color` | `--xpl-border-focus` |\n| item `:focus-visible` | `z-index` (above scroll fade) | `--xpl-z-index-200` |\n| item | `padding` | `--xpl-space-16` / `--xpl-space-24` |\n| item accent border (inactive) | `border-width` (0) | `--xpl-border-none` |\n| item accent border | `border-width` (4px) | `--xpl-border-xlarge` |\n| item (desktop) | `height` (48px) | `--xpl-size-300` |\n| scroll fade `nav::after` | `z-index` (below focused item) | `--xpl-z-index-100` |\n\nThe horizontal-scroll fade (`nav::after`, mobile only) fills a strip with `--xpl-background-surface-default` and fades it out with an alpha-only `mask-image`, so it blends into the themed nav background in both modes. It is `pointer-events: none` and sits at `--xpl-z-index-100`, below a keyboard-focused item (`--xpl-z-index-200`), so it never intercepts taps or hides an item's `:focus-visible` ring.\n\n**Known token gaps** (see [`TECH_DEBT.md`](../../../../../../TECH_DEBT.md)): the item `height` (52px) and desktop `width` (200px) have no matching Foundation size token; the scroll-fade gradient stops have no dedicated Foundation tokens.\n",
|
|
11526
11526
|
"docs": "The Secondary Nav component is a component that allows navigation within the content area. It yields one slot where a <ul> element with <xpl-nav-item> elements should be rendered.",
|
|
11527
11527
|
"docsTags": [
|
|
11528
11528
|
{
|
|
@@ -11553,7 +11553,7 @@
|
|
|
11553
11553
|
"dependencyGraph": {}
|
|
11554
11554
|
},
|
|
11555
11555
|
{
|
|
11556
|
-
"filePath": "src/components/
|
|
11556
|
+
"filePath": "src/components/xpl-select/xpl-select.tsx",
|
|
11557
11557
|
"encapsulation": "none",
|
|
11558
11558
|
"tag": "xpl-select",
|
|
11559
11559
|
"readme": "# xpl-select\n\nSelect allows users to make a single selection or multiple selections from a list of options. Items can be a simple list, grouped, simple multi-select. User selections typically appear within the Select Box once created unless multiple selections are made, where truncation or another method of showing these selections is required.\n\n***When the list of options contains “Actions”, use a ***[Dropdown component](https://apollo.xplordocs.com/?path=/story/components-dropdown--simple).\n\nThe `selectIcon` property accepts icon names as strings. See [xpl-icon available icons](../xpl-icon/ICONS.md) for the complete list.\n\n---\n\n### Design Tokens\n\nTokens used by this component from `@xplortech/apollo-foundation`.\n\n**Color**\n- `--xpl-icon-default` — chevron icon color\n- `--xpl-text-subdued` — trigger and placeholder value color (empty state)\n- `--xpl-text-default` — selected value color (`.has-value`)\n\nThe options panel surface, borders, and option states are styled by [xpl-dropdown](../xpl-dropdown) — see its Design Tokens section.\n\n**Note:** the trigger `height` (44px) and `.xpl-input-wrapper` `min-height` (46px) are kept as literals — no `--xpl-size` token matches (250 = 40px, 300 = 48px). See `TECH_DEBT.md`.\n",
|
|
@@ -11580,7 +11580,7 @@
|
|
|
11580
11580
|
"DropdownItem": {
|
|
11581
11581
|
"location": "import",
|
|
11582
11582
|
"path": "../xpl-dropdown/dropdown-option",
|
|
11583
|
-
"id": "src/components/
|
|
11583
|
+
"id": "src/components/xpl-dropdown/dropdown-option.ts::DropdownItem",
|
|
11584
11584
|
"referenceLocation": "DropdownItem"
|
|
11585
11585
|
}
|
|
11586
11586
|
}
|
|
@@ -12168,7 +12168,7 @@
|
|
|
12168
12168
|
}
|
|
12169
12169
|
},
|
|
12170
12170
|
{
|
|
12171
|
-
"filePath": "src/components/
|
|
12171
|
+
"filePath": "src/components/xpl-side-nav/xpl-side-nav.tsx",
|
|
12172
12172
|
"encapsulation": "none",
|
|
12173
12173
|
"tag": "xpl-side-nav",
|
|
12174
12174
|
"readme": "# xpl-side-nav\n\nSlot-based sidebar for app navigation: a scrollable `nav-header` + `section` area and a fixed footer. Compose with [`xpl-side-nav-item`](./xpl-side-nav-item) for rows in the section and footer.\n\n## Slots\n\n| Slot | Description |\n| ---- | ----------- |\n| `nav-header` | Optional header row — place an [`xpl-side-nav-header-item`](./xpl-side-nav-header-item) inside. Hidden entirely (no wrapper, no border) when the slot is empty. |\n| `section` | Primary navigation. Place `xpl-side-nav-item` elements (or wrappers) inside this slot; layout uses internal section markup. |\n| `nav-footer` | Footer actions (e.g. Help, Logout). Same item component; typically smaller label styling via CSS. |\n\n## Usage\n\nUse the **`label`** prop for a unique accessible name on the `<nav>` when multiple landmarks exist on the page (see **Multi-Navigation Layouts** below).\n\n```html\n<xpl-side-nav label=\"Main navigation\">\n <div slot=\"nav-header\">\n <xpl-side-nav-header-item type=\"sub-account\" label=\"Acme Inc\" icon=\"office-3\"></xpl-side-nav-header-item>\n </div>\n <div slot=\"section\">\n <xpl-side-nav-item label=\"Dashboard\" icon=\"house-4\" selected></xpl-side-nav-item>\n <xpl-side-nav-item has-children label=\"Settings\" expanded>\n <xpl-side-nav-item label=\"Profile\"></xpl-side-nav-item>\n </xpl-side-nav-item>\n </div>\n <div slot=\"nav-footer\">\n <xpl-side-nav-item label=\"Help\" icon=\"headset\"></xpl-side-nav-item>\n </div>\n</xpl-side-nav>\n```\n\n**Link rows:** use `xpl-side-nav-item` with `link` when the row needs to be a real `<a>` element (framework router components, right-click / open-in-new-tab, semantic link role). For typical in-app navigation, the default button mode is simpler. See [xpl-side-nav-item](./xpl-side-nav-item) **Link mode** for usage and styling guidance.\n\n## Mobile behavior\n\nBelow the Tailwind `md` breakpoint (768px) the sidebar collapses to a ~56px top bar with a built-in toggle button (`sidebar-left-show` / `sidebar-left-hide`). Activating the toggle opens a drawer containing the `section` + `nav-footer` content over an [`xpl-backdrop`](../xpl-backdrop) scrim. Above `md` the toggle and backdrop are hidden and the sidebar renders inline — no markup changes are needed for either layout.\n\n**Keyboard / focus:**\n- **Escape** closes the drawer and returns focus to the toggle.\n- A **backdrop click** closes the drawer.\n- **Focus is trapped** inside the open drawer — Tab cycles only through the toggle and drawer rows.\n- The toggle exposes `aria-expanded` and a dynamic `aria-label` (\"Open/Close navigation menu\").\n\n**Row-level responsive scaling (applied automatically inside the drawer):**\n\n| Property | Desktop (≥ 768px) | Mobile (< 768px) |\n|---|---|---|\n| Tap target (`xpl-side-nav-item` wrapper) | — (inner button sized by content) | `min-height: 48px; padding: 6px 8px` |\n| Leading / trailing icon size | 16px | 24px |\n| Top-level label typography | `title-4` (16px, medium) | `title-3` (20px, medium) |\n| Child item label typography | `title-5` | `title-4` (16px, medium) |\n| Footer item label typography | `title-5` | `title-4` (16px, medium) |\n| Footer row min-height | `28px` | `--xpl-size-200` (32px) |\n| Footer leading / trailing icon | 16px | 20px |\n\nNo markup or props are needed for these changes — they are driven entirely by CSS.\n\n### Open state API\n\nThe `open` prop, `openChange` event, and `toggle()` / `setOpen()` methods control and observe the drawer. The component works **uncontrolled** (the built-in toggle flips `open`) or **controlled** (the consumer owns `open`).\n\n**Uncontrolled** — the built-in toggle manages everything; listen to `openChange` if you need to react:\n\n```html\n<xpl-side-nav label=\"Main navigation\" id=\"nav\">\n <div slot=\"section\">…</div>\n <div slot=\"nav-footer\">…</div>\n</xpl-side-nav>\n<script>\n document.getElementById('nav').addEventListener('openChange', (e) => {\n console.log('drawer open:', e.detail);\n });\n</script>\n```\n\n**Controlled** — own `open` and update it from `openChange` (and/or the imperative methods):\n\n```html\n<xpl-side-nav label=\"Main navigation\" id=\"nav\" open>…</xpl-side-nav>\n<script>\n const nav = document.getElementById('nav');\n // Keep your state in sync with user-driven changes (toggle, Escape, backdrop):\n nav.addEventListener('openChange', (e) => {\n nav.open = e.detail;\n });\n // Programmatic control:\n await nav.toggle();\n await nav.setOpen(false);\n</script>\n```\n\n> **v2 breaking change (beta):** the mobile toggle + drawer are now built in. Consumers who previously wrapped their own toggle around `xpl-side-nav` should remove it.\n\n### Implementation details (mobile drawer)\n\n- **Host class hooks** — when the drawer is open the host carries `xpl-side-nav--open` alongside `xpl-side-nav`. Useful for app-level CSS that needs to react (e.g. lock body scroll).\n- **Drawer transition** — `transform` + `opacity` + `visibility` over **300 ms** with `ease-out`. Closed state is `translateX(-100%)` + `opacity: 0` + `visibility: hidden`; the `visibility` flip is delayed 300 ms on close so the slide is visible.\n- **Backdrop transition** — `opacity` + `visibility` over **500 ms** with `ease-in-out`. Open state uses `opacity-50` (matches the native `xpl-backdrop` value, not full opaque). Visibility delayed 500 ms on close. `pointer-events: none` applies immediately on close so page content is tappable while the scrim fades out.\n- **Drawer geometry** — width `80vw` with a `min-width: 300px` floor (Figma spec; no Foundation token yet — see `TECH_DEBT.md`). The remaining `20vw` shows the backdrop scrim.\n- **Toggle styling overrides** — the built-in `xpl-button` toggle uses `padding-inline: var(--xpl-space-12)` on its inner `<button>` and renders its icon at `var(--xpl-size-200)` (32 px) so the icon's left edge aligns with the drawer's nav-item icon column.\n\n### Multi-Navigation Layouts (Accessibility)\n\nWhen multiple navigation landmarks exist on a page (e.g., side nav, top nav, breadcrumbs), use the `label` prop to provide a unique accessible name for each `<nav>` element. This helps screen reader users distinguish between them.\n\n```html\n<!-- Main side navigation -->\n<xpl-side-nav label=\"Main navigation\">\n ...\n</xpl-side-nav>\n\n<!-- Top navigation (different component) -->\n<xpl-top-nav label=\"User menu\">\n ...\n</xpl-top-nav>\n\n<!-- Breadcrumbs (different component) -->\n<xpl-breadcrumbs label=\"Breadcrumb\">\n ...\n</xpl-breadcrumbs>\n```\n\n**WCAG Note:** When a page has multiple `<nav>` landmarks, each should have a unique accessible name via `aria-label`.\n\n## Related components\n\n- [xpl-side-nav-item](./xpl-side-nav-item) — Navigation rows for section and footer: leaf button, expandable parent, or link (real `<a>`) mode.\n",
|
|
@@ -12354,7 +12354,7 @@
|
|
|
12354
12354
|
}
|
|
12355
12355
|
},
|
|
12356
12356
|
{
|
|
12357
|
-
"filePath": "src/components/
|
|
12357
|
+
"filePath": "src/components/xpl-side-nav/xpl-side-nav-header-item/xpl-side-nav-header-item.tsx",
|
|
12358
12358
|
"encapsulation": "none",
|
|
12359
12359
|
"tag": "xpl-side-nav-header-item",
|
|
12360
12360
|
"readme": "# xpl-side-nav-header-item\n\nHeader row sub-component for [`xpl-side-nav`](../xpl-side-nav)'s `slot=\"nav-header\"` (Figma navHeaderItem, node `51299-9007`).\n\n## Usage\n\n### Product label (static)\n\n```html\n<xpl-side-nav-header-item type=\"product-label\" label=\"My Product\"></xpl-side-nav-header-item>\n```\n\n### Sub account (interactive)\n\n```html\n<xpl-side-nav-header-item\n type=\"sub-account\"\n label=\"Acme Inc\"\n icon=\"pin\"\n></xpl-side-nav-header-item>\n<script>\n document\n .querySelector('xpl-side-nav-header-item[type=\"sub-account\"]')\n .addEventListener('navigate', () => {\n // open a location / account switcher, e.g. a modal\n });\n</script>\n```\n\n### Selected sub account\n\n```html\n<xpl-side-nav-header-item\n type=\"sub-account\"\n label=\"Acme Inc\"\n selected\n></xpl-side-nav-header-item>\n```\n\n### Custom trailing icon (replaces the auto chevron)\n\n```html\n<xpl-side-nav-header-item type=\"sub-account\" label=\"Xplor Growth\">\n <xpl-icon slot=\"trailing\" icon=\"external-link\" size=\"16\" aria-hidden=\"true\"></xpl-icon>\n</xpl-side-nav-header-item>\n```\n\n## Rules\n\n| Topic | Behavior |\n|---|---|\n| **Leading / trailing columns** | Unlike `xpl-side-nav-item`, these are **not** unconditionally reserved — they only render when there is an `icon` prop or slotted content, matching the Figma variants where the leading icon is an optional toggle. |\n| **Auto chevron** | `sub-account` auto-renders `chevron-expand-y` (a static dual-arrow glyph) in the trailing column when no `slot=\"trailing\"` content is provided. It does not rotate. |\n| **`selected`** | Only meaningful on `sub-account` — wraps the label + trailing chevron in an information-surface pill. Ignored on `product-label`. |\n| **Selected + leading icon** | Figma's selected variant absolute-positions the leading icon over the pill's edge (an auto-layout artifact, not a deliberate detail). This component keeps the leading icon in normal flow outside the pill for a simpler, more maintainable DOM structure. |\n\n## Accessibility\n\n- `product-label` renders a plain, non-interactive `<div>` — no button semantics, since there is nothing to activate.\n- `sub-account` renders a real `<button type=\"button\">`, so Enter/Space activation and focus are native. Activation emits the `navigate` event (pointer or keyboard).\n- **Selected state** — a selected `sub-account` exposes `aria-current=\"true\"` on the button so assistive tech announces which sub-account is active (the pill is a visual-only cue). `'true'` is used rather than `'page'` because a sub-account switcher is not a page.\n- **Accessible name** — the `label` supplies the button's accessible name, so a `label` is strongly recommended for `sub-account`. When `label` is omitted (icon-only), the leading icon is decorative and the auto chevron is `aria-hidden`, so the component falls back to `aria-label=\"Sub-account\"` to guarantee the button is never unnamed. Provide a meaningful `label` for a better experience.\n- The decorative auto chevron carries `aria-hidden=\"true\"`; a custom `slot=\"trailing\"` icon is left to the consumer to label appropriately.\n\n## Token reference\n\n| Token | Usage |\n|---|---|\n| `--xpl-text-subdued` | `product-label` label color |\n| `--xpl-text-strong` | `sub-account` label color |\n| `--xpl-icon-default` | Leading / non-auto trailing icon color |\n| `--xpl-icon-subtle` | Auto chevron color |\n| `--xpl-background-surface-information` | Selected pill background |\n| `--xpl-background-surface-transparent-10` | `sub-account` hover background |\n| `--xpl-border-focus` | Focus outline color |\n| `--xpl-space-4` / `--xpl-space-8` / `--xpl-space-16` | Row / pill padding and gap |\n| `--xpl-size-100` / `--xpl-size-150` | Leading/trailing icon box: 16px desktop, 24px mobile |\n| `--xpl-size-200` | Row `min-height` (32px) |\n\n## Related\n\n- [xpl-side-nav](../xpl-side-nav) — Sidebar container.\n- [xpl-side-nav-item](../xpl-side-nav-item) — Navigation row (shares the leading/trailing slot + icon-prop convention).\n",
|
|
@@ -12523,7 +12523,7 @@
|
|
|
12523
12523
|
}
|
|
12524
12524
|
},
|
|
12525
12525
|
{
|
|
12526
|
-
"filePath": "src/components/
|
|
12526
|
+
"filePath": "src/components/xpl-side-nav/xpl-side-nav-item/xpl-side-nav-item.tsx",
|
|
12527
12527
|
"encapsulation": "none",
|
|
12528
12528
|
"tag": "xpl-side-nav-item",
|
|
12529
12529
|
"readme": "# xpl-side-nav-item\n\nRow for [`xpl-side-nav`](../xpl-side-nav): place items in `slot=\"section\"` or `slot=\"nav-footer\"`. Supports **leaf** (button), **expandable** (`has-children`), and **link** (slot-only) modes, plus `selected`, `disabled`, and `hidden`.\n\n## Changes in v2 (breaking)\n\n`xpl-side-nav` is in **beta**. v2 makes the following breaking changes — no compat shims are provided.\n\n### Migration table\n\n| API | v1 (before) | v2 (after) | Action required |\n|---|---|---|---|\n| Leading icon slot | `slot=\"icon\"` | `slot=\"leading\"` | Rename the `slot` attribute on slotted icon elements |\n| Parent leading icon | Not rendered (chevron only) | Rendered alongside the trailing chevron | Pass `icon` prop or `slot=\"leading\"` content to parent rows |\n| Trailing slot | Not available | `slot=\"trailing\"` | Add to leaf items for custom trailing content |\n| Chevron position | Leading (left side) | Trailing (right side), auto-rendered for parents | No action needed for auto chevron; remove manual chevron markup if any |\n| Chevron override | Not possible | `slot=\"trailing\"` content replaces auto chevron on parents | Pass `slot=\"trailing\"` to customize the trailing column on a parent |\n| Leaf click event | `navClick` event | `navigate` event | Rename listeners: `navClick` → `navigate` (React `onNavClick` → `onNavigate`) |\n\n### Before / after examples\n\n**Leading icon slot rename:**\n```html\n<!-- v1 -->\n<xpl-side-nav-item label=\"Dashboard\">\n <xpl-icon slot=\"icon\" icon=\"house-4\" size=\"16\"></xpl-icon>\n</xpl-side-nav-item>\n\n<!-- v2 -->\n<xpl-side-nav-item label=\"Dashboard\">\n <xpl-icon slot=\"leading\" icon=\"house-4\" size=\"16\"></xpl-icon>\n</xpl-side-nav-item>\n<!-- or use the icon prop shorthand -->\n<xpl-side-nav-item label=\"Dashboard\" icon=\"house-4\"></xpl-side-nav-item>\n```\n\n**Parent rows now show leading icon + chevron:**\n```html\n<!-- v1: icon prop was ignored on parents -->\n<xpl-side-nav-item has-children label=\"Settings\" icon=\"gear\">...</xpl-side-nav-item>\n\n<!-- v2: icon prop renders in the leading slot; chevron auto-renders in trailing -->\n<xpl-side-nav-item has-children label=\"Settings\" icon=\"gear\">...</xpl-side-nav-item>\n```\n\n**Adding a trailing icon to a leaf item:**\n```html\n<!-- v2: slot=\"trailing\" for custom trailing content -->\n<xpl-side-nav-item label=\"Xplor Growth\" icon=\"chart-line-up\">\n <xpl-icon slot=\"trailing\" icon=\"external-link\" size=\"16\" aria-hidden=\"true\"></xpl-icon>\n</xpl-side-nav-item>\n```\n\n**Leaf click event rename:**\n```js\n// v1\nitem.addEventListener('navClick', handler);\n// v2\nitem.addEventListener('navigate', handler);\n```\nIn React the prop changes from `onNavClick` to `onNavigate`.\n\n---\n\n## Modes\n\n- **Leaf (default)** — Button with optional `label`, `icon` prop / `slot=\"leading\"`, and `slot=\"trailing\"`. Activation (click or keyboard) emits **`navigate`**.\n- **Expandable (`has-children`)** — Put nested `xpl-side-nav-item` elements in the **default slot**. Row renders **leading icon** (from `icon` prop or `slot=\"leading\"`) **+ label + auto chevron** in the trailing position (**`chevron-down`** when collapsed, **`chevron-up`** when expanded). The chevron is replaced if `slot=\"trailing\"` content is provided. Click toggles **`expanded`** and emits **`expandedChange`**.\n- **Link (`link`)** — **Default slot only**: renders a bare `<slot>` with no inner button. Use when the row must be a real `<a>` element — for framework router components, browser right-click / open-in-new-tab behaviour, or when semantic link vs. button distinction matters for screen readers. For typical in-app navigation the default button mode is simpler. The `label` and `icon` props are ignored in link mode; supply all content in your slotted anchor. **Cannot** be combined with `has-children`.\n\n## Rules\n\n| Topic | Behavior |\n|---|---|\n| **`link` vs `has-children`** | Mutually exclusive. When **`link`** is true, **`hasChildren`** is always false; if both attributes appear in markup, `has-children` is cleared. |\n| **Leading icon** | `icon` prop / `slot=\"leading\"` apply to all item types including parents. Nested sub-items (inside a parent) have the leading column hidden in CSS — use label only. |\n| **Trailing chevron** | Auto-rendered for `has-children` items when `slot=\"trailing\"` is empty. Providing `slot=\"trailing\"` content replaces the auto chevron. |\n| **Events** | **`navigate`** — leaf button rows (pointer or keyboard activation). **`expandedChange`** — expandable rows only (detail = new `expanded` boolean). |\n\n## Usage\n\n### Leaf (icon prop)\n```html\n<xpl-side-nav-item label=\"Dashboard\" icon=\"house-4\" selected></xpl-side-nav-item>\n```\n\n### Leaf (slot=\"leading\")\n```html\n<xpl-side-nav-item label=\"Dashboard\">\n <xpl-icon slot=\"leading\" icon=\"house-4\" size=\"16\"></xpl-icon>\n</xpl-side-nav-item>\n```\n\n### Leaf with trailing icon\n```html\n<xpl-side-nav-item label=\"Xplor Growth\" icon=\"chart-line-up\">\n <xpl-icon slot=\"trailing\" icon=\"external-link\" size=\"16\" aria-hidden=\"true\"></xpl-icon>\n</xpl-side-nav-item>\n```\n\n### Expandable parent (leading icon + auto chevron)\n```html\n<xpl-side-nav-item has-children label=\"Settings\" icon=\"gear\" expanded>\n <xpl-side-nav-item label=\"Profile\"></xpl-side-nav-item>\n <xpl-side-nav-item label=\"Billing\"></xpl-side-nav-item>\n</xpl-side-nav-item>\n```\n\n### Link (slot-only)\n\nWrap the anchor's children in the component CSS classes to match the icon color, label color, and spacing of button-mode items. Avoid whitespace text nodes between flex children — they render as a space character and add an unwanted gap.\n\n```html\n<xpl-side-nav-item link>\n <!-- No whitespace between __leading / __label spans and the closing </a> -->\n <a href=\"/reports\" class=\"xpl-side-nav-item__link\"><span class=\"xpl-side-nav-item__leading\"><xpl-icon icon=\"chart-line\" size=\"16\"></xpl-icon></span><span class=\"xpl-side-nav-item__label\">Reports</span></a>\n</xpl-side-nav-item>\n```\n\n### Disabled and hidden\n```html\n<xpl-side-nav-item label=\"Disabled\" disabled></xpl-side-nav-item>\n<xpl-side-nav-item label=\"Hidden\" hidden></xpl-side-nav-item>\n```\n\n## Slots\n\n| Slot | Description |\n|---|---|\n| `leading` | Leading icon column. Default content is an `xpl-icon` from the `icon` prop. Override with slotted content. Applies to all item types including parents. Renamed from `icon` in v2. |\n| `trailing` | Trailing content (e.g. `xpl-icon icon=\"external-link\"`). On `has-children` items, the auto chevron is rendered here when this slot is empty (`chevron-down` collapsed, `chevron-up` expanded); slotted content replaces the chevron. |\n| *(default)* | **`has-children`:** nested `xpl-side-nav-item` children. **`link`:** one `<a>` (or router link component) containing all row content. Unused in leaf button mode. |\n\n## Link mode checklist\n\n- Do **not** use `label` or `icon` props — they are ignored in link mode. Put all text and icons inside your slotted anchor.\n- Use **`class=\"xpl-side-nav-item__link\"`** on the anchor, **`class=\"xpl-side-nav-item__leading\"`** on the icon wrapper, and **`class=\"xpl-side-nav-item__label\"`** on the text span for consistent icon color, label typography, hover, and focus styling.\n- **No whitespace between flex children** — ensure no newlines or spaces sit between `__leading`, `__label`, and the `</a>` tag. Whitespace between flex items renders as a space character and shifts the label to the right.\n- Set **`aria-current=\"page\"`** on the anchor (not the host) when the route is active.\n- For **disabled** links: set `disabled` on the host and `aria-disabled=\"true\"` + `tabindex=\"-1\"` on the anchor (see **Accessibility**).\n\n## Accessibility\n\n- **Selected (non-link):** `aria-current=\"page\"` on the `button` (leaf or expandable row).\n- **Selected (link):** set `aria-current=\"page\"` on your slotted anchor.\n- **Expandable:** `aria-expanded` on the parent `button` matches `expanded`.\n- **Trailing decorative icons:** add `aria-hidden=\"true\"` to trailing `xpl-icon` elements. If the trailing icon conveys meaning (e.g. external link), provide accessible labeling in the surrounding context.\n- **Disabled:** use the `disabled` prop on non-link rows; for link mode, coordinate host `disabled` with the anchor as above.\n- **Hidden:** `hidden` hides the row; it does not disable interaction by itself — use `disabled` when appropriate.\n\n## Mobile behavior (below `md` / 768px)\n\nInside the `xpl-side-nav` mobile drawer, items are automatically restyled by CSS — no props or markup changes needed.\n\n| Property | Desktop | Mobile |\n|---|---|---|\n| Outer wrapper tap target | — | `min-height: 48px; padding: 6px 8px` |\n| Inner button `min-height` | 32px | 0 (tap target comes from wrapper) |\n| Leading / trailing icon size | 16px (`--xpl-size-100`) | 24px (`--xpl-size-150`) |\n| Top-level label | `title-4` (16px, medium, lh 1.5) | `title-3` (20px, medium, lh 1.4) |\n| Child item label | `title-5` | `title-4` (16px, medium, lh 1.5) |\n| Footer item label | `title-5` | `title-4` (16px, medium, lh 1.5) |\n| Footer row min-height | `28px` (one step smaller than section rows) | `--xpl-size-200` (32px) |\n| Footer leading / trailing icon | 16px (`--xpl-size-100`) | 20px (`--xpl-size-125`) |\n| Child label alignment offset | `padding-left: var(--xpl-side-nav-child-indent)` (32px) | Same — child labels stay aligned with the parent label column on every viewport |\n\n**Link mode and mobile icons:** in button mode the component automatically adjusts the `xpl-icon` `size` prop to 24 below `md`. In link mode, where the consumer controls the anchor content, the CSS scales the `svg` element inside `__leading` / `__trailing` via a presentational-attribute override — no `size` prop change needed.\n\n## Token reference\n\n| Token | Usage |\n|---|---|\n| `--xpl-icon-default` | Leading and trailing icon color (default, hover, selected) |\n| `--xpl-icon-disabled` | Leading, trailing, and label color when disabled |\n| `--xpl-text-strong` | Label color |\n| `--xpl-text-disabled` | Label color when disabled |\n| `--xpl-background-brand-secondary-surface` | Selected row background |\n| `--xpl-background-surface-transparent-10` | Hover row background |\n| `--xpl-border-focus` | Focus outline color |\n| `--xpl-space-8` | `margin-right` on the leading icon box (spacing between icon and label); `margin-left` on the trailing box |\n| `--xpl-size-100` | Leading / trailing icon box: 16px on desktop |\n| `--xpl-size-150` | Leading / trailing icon box on mobile (overrides `--xpl-size-100` below `md`) |\n| `--xpl-size-200` | `min-height` of the inner link / button (32px desktop) |\n| `--xpl-size-300` | `min-height` of the outer row wrapper on mobile (48px tap target) |\n\n## Related\n\n- [xpl-side-nav](../xpl-side-nav) — Sidebar container (`slot=\"section\"`, `slot=\"nav-footer\"`).\n",
|
|
@@ -12825,7 +12825,7 @@
|
|
|
12825
12825
|
}
|
|
12826
12826
|
},
|
|
12827
12827
|
{
|
|
12828
|
-
"filePath": "src/components/
|
|
12828
|
+
"filePath": "src/components/xpl-side-nav/xpl-side-nav-section/xpl-side-nav-section.tsx",
|
|
12829
12829
|
"encapsulation": "none",
|
|
12830
12830
|
"tag": "xpl-side-nav-section",
|
|
12831
12831
|
"readme": "# xpl-side-nav-section\n\nGrouping / accordion header for [`xpl-side-nav`](../xpl-side-nav). Wraps nested `xpl-side-nav-item` (and optional divider separators) elements in the default slot and collapses them as a unit.\n\n## Usage\n\n### Collapsible (default)\n\n```html\n<xpl-side-nav-section heading=\"Settings\">\n <xpl-side-nav-item label=\"Location\" icon=\"pin\"></xpl-side-nav-item>\n <xpl-side-nav-item label=\"Schedule\" icon=\"calendar\"></xpl-side-nav-item>\n</xpl-side-nav-section>\n```\n\n### Static (label only, `collapsible=false`)\n\n```html\n<xpl-side-nav-section heading=\"Product\" collapsible=\"false\">\n <xpl-side-nav-item label=\"Location\" icon=\"pin\"></xpl-side-nav-item>\n</xpl-side-nav-section>\n```\n\n### With a badge (`slot=\"badge\"`)\n\nCompose the existing `xpl-badge` — there is no `badge` boolean prop. The wrapper is suppressed automatically when the slot is empty.\n\n```html\n<xpl-side-nav-section heading=\"Updates\">\n <xpl-badge slot=\"badge\" variant=\"purple\" size=\"small\">4</xpl-badge>\n <xpl-side-nav-item label=\"Webhooks\"></xpl-side-nav-item>\n</xpl-side-nav-section>\n```\n\n## Rules\n\n| Topic | Behavior |\n|---|---|\n| **Child indent** | Unlike `xpl-side-nav-item[has-children]`, section children are **not indented** — they align with top-level items at the same leading-icon column, and keep their own leading icon. |\n| **Dividers** | Sections do **not** render their own dividers. Place an `<hr class=\"xpl-side-nav-divider\">` as a sibling (e.g. above and below a closed section) when a visual break is needed — no dedicated component. |\n| **Coordination** | Sections behave independently — there is no built-in single-open accordion coordination between sibling sections. |\n| **Chevron** | Auto-rendered for collapsible sections: `chevron-right` collapsed / `chevron-down` expanded (the glyph swaps, no rotation). Not rendered when `collapsible=\"false\"`. |\n\n## Accessibility\n\n- The collapsible header is a real `<button type=\"button\">` with `aria-expanded` (mirrors `expanded`) and `aria-controls` pointing to the children region's `id`.\n- The button's accessible name comes from the visible `heading` text or `slot=\"badge\"` content. It falls back to `aria-label=\"Toggle section\"` only when both are absent or whitespace-only; the chevron is `aria-hidden`.\n- The decorative chevron carries `aria-hidden=\"true\"` — the button's `aria-expanded` already conveys state.\n- Collapsed children are marked `inert`, removing them from the tab order (not just visually hidden) — same pattern as `xpl-side-nav-item[has-children]`.\n- The static variant (`collapsible=\"false\"`) renders a plain `<div>` header — no button semantics, since there is nothing to toggle.\n\n## Token reference\n\n| Token | Usage |\n|---|---|\n| `--xpl-text-subdued` | Title color |\n| `--xpl-icon-subtle` | Chevron color |\n| `--xpl-font-weight-bold` | Title font weight (extends `.xpl-text-callout` for size/line-height) |\n| `--xpl-space-8` | Title-row gap; horizontal header padding (desktop, reconciled against the parent section's own 8px padding) |\n| `--xpl-space-24` / `--xpl-space-4` | Header vertical padding (closed: 24/24; expanded or static: 24/4) |\n| `--xpl-size-100` / `--xpl-size-150` | Chevron box: 16px desktop, 24px mobile |\n| `--xpl-size-250` | Header `min-height` (40px) |\n| `--xpl-border-focus` | Focus outline color |\n\n## Related\n\n- [xpl-side-nav](../xpl-side-nav) — Sidebar container (`slot=\"section\"`, `slot=\"nav-footer\"`).\n- [xpl-side-nav-item](../xpl-side-nav-item) — Navigation row.\n- `<hr class=\"xpl-side-nav-divider\">` — Standalone separator (no dedicated component), often placed around a section.\n- [xpl-badge](../../xpl-badge) — Composed via `slot=\"badge\"`.\n",
|
|
@@ -12966,7 +12966,7 @@
|
|
|
12966
12966
|
}
|
|
12967
12967
|
},
|
|
12968
12968
|
{
|
|
12969
|
-
"filePath": "src/components/
|
|
12969
|
+
"filePath": "src/components/xpl-skeleton/xpl-skeleton.tsx",
|
|
12970
12970
|
"encapsulation": "none",
|
|
12971
12971
|
"tag": "xpl-skeleton",
|
|
12972
12972
|
"readme": "# xpl-skeleton\n\nSkeleton components are progress indicators used for full page loading states that reduce the perception of long loading times and provide both reassurance to the user as well as clues for how the page will ultimately look. \n\nIncludes:\nComponents - Text, Shape, Data\nVariants - Text: Display, Title, Body Shape: rectangle, pill, circle, square\nProperties - Text/Body: show 1, 2 or 3 lines\n\n**Note: The “shimmer” effect uses Tailwind’s `animated-pulse` for the duration skeletons are present. The [animated pulse](https://tailwindcss.com/docs/animation#adding-a-pulse-animation) animates the color between our `color-background-surface-transparent-10` and `color-background-surface-transparent-5` variables. \n\n",
|
|
@@ -13218,7 +13218,7 @@
|
|
|
13218
13218
|
"dependencyGraph": {}
|
|
13219
13219
|
},
|
|
13220
13220
|
{
|
|
13221
|
-
"filePath": "src/components/
|
|
13221
|
+
"filePath": "src/components/xpl-slideout/xpl-slideout.tsx",
|
|
13222
13222
|
"encapsulation": "none",
|
|
13223
13223
|
"tag": "xpl-slideout",
|
|
13224
13224
|
"readme": "# xpl-slideout\n\nContent and Footer subcomponents are optional and can be hidden. Slideout always has a header with an X close button upper right. Slide Out Panel OPTIONALLY uses the [<xpl-backdrop>](https://apollo.xplordocs.com/?path=/story/components-backdrop--backdrop) component to overlay content and create focus on the Slide Out Panel content.\n\n## Token Use\n\n`xpl-slideout` uses Apollo Foundation purpose-specific tokens; light and dark mode are handled by the token definitions, so the component has no `.dark` overrides.\n\n| Element | Property | Token |\n| ------- | -------- | ----- |\n| `.slideout` | background | `--xpl-background-surface-default` |\n| `.slideout` | shadow color | `--xpl-color-transparent-neutral-10` / `--xpl-color-transparent-neutral-5` |\n| `.title` | color | `--xpl-text-default` |\n| `.title` | typography (size / weight / line-height) | `@extend .xpl-text-title-3` → `title-3` / `bold` / `1.4` |\n| `.subtitle` | color | `--xpl-text-subdued` |\n| `.subtitle` | typography (size / weight / line-height) | `@extend .xpl-text-body` → `body` / `normal` / `1.4286` |\n| `.content` | text color | `--xpl-text-default` |\n| `.content.has-shadow` | scroll-overflow shadow (top/bottom only) | `--xpl-color-transparent-neutral-10` / `--xpl-color-transparent-neutral-5` |\n| search `.xpl-input-wrapper` | background | `--xpl-background-surface-default` |\n| search `input` | color | `--xpl-text-default` |\n\nPanel widths are documented CSS literals: `min-width: 21.5rem`, `max-width: 37.5rem` (see `slideout.css` and `TECH_DEBT.md`).\n\nThe `.content.has-shadow` shadow is a scroll affordance applied only to the top and bottom edges (per Figma node 52462-9896) to signal that content is hidden behind the header/footer when it overflows.\n\n> **Elevation shadow (documented deviation):** the panel shadow is a custom single-edge shadow cast left onto the page content (`-10px 0 15px -3px`, `4px 0 6px -2px` over `--xpl-color-transparent-neutral-10 / -5`). Figma specs a leading-edge-only shadow for this right-anchored panel; the shared `--xpl-elevation-*` tokens are vertical (bottom-cast) and do not fit a side-anchored panel, so the hand-authored geometry is kept — see `TECH_DEBT.md`.\n",
|
|
@@ -13459,7 +13459,7 @@
|
|
|
13459
13459
|
}
|
|
13460
13460
|
},
|
|
13461
13461
|
{
|
|
13462
|
-
"filePath": "src/components/
|
|
13462
|
+
"filePath": "src/components/xpl-spotlight/xpl-spotlight.tsx",
|
|
13463
13463
|
"encapsulation": "none",
|
|
13464
13464
|
"tag": "xpl-spotlight",
|
|
13465
13465
|
"readme": "# xpl-spotlight\n\n`xpl-spotlight` renders a guided-tour callout with an anchor dot, optional media, step messaging, and prop-driven footer actions. It can either render inline using the requested `anchorPosition` or attach to a target element with Floating UI when `target` is provided.\n\n## Usage Examples\n\nUse the built-in title/body props and default actions for a simple tour step:\n\n```html\n<xpl-spotlight\n heading=\"Review recent activity\"\n body=\"Check status updates here before moving to the next step.\"\n action-layout=\"default\"\n anchor-position=\"top-right\"\n current-step=\"2\"\n total-steps=\"5\"\n is-dismissible=\"true\"\n is-open=\"true\"\n primary-action-label=\"Next\"\n secondary-action-label=\"Back\"\n show-actions=\"true\"\n show-image=\"true\"\n show-steps=\"true\"\n target=\"\"\n></xpl-spotlight>\n```\n\nAnchor the spotlight to a specific element and provide custom media content:\n\n```html\n<button id=\"dashboard-filter-button\" type=\"button\">Filters</button>\n\n<xpl-spotlight\n target=\"#dashboard-filter-button\"\n heading=\"Narrow the results\"\n body=\"Use filters to focus on the accounts or activity that matter most.\"\n current-step=\"1\"\n total-steps=\"3\"\n primary-action-label=\"Next\"\n secondary-action-label=\"Skip\"\n>\n <div slot=\"image\">\n <img src=\"/assets/spotlight-filter-preview.png\" alt=\"Preview of filter controls\" />\n </div>\n</xpl-spotlight>\n```\n\n\nControl visibility from the parent with `is-open` and close it by responding to `dismiss`:\n\n```html\n<xpl-spotlight\n id=\"guided-tour-step\"\n is-open=\"true\"\n heading=\"Review recent activity\"\n body=\"Check status updates here before moving to the next step.\"\n></xpl-spotlight>\n\n<script>\n const spotlight = document.getElementById('guided-tour-step');\n\n spotlight?.addEventListener('dismiss', () => {\n spotlight.setAttribute('is-open', 'false');\n });\n</script>\n```\n\nMirror the same layout in plain HTML when documenting or prototyping the component structure outside the custom element:\n\n```html\n<div class=\"xpl-spotlight xpl-spotlight--top-left xpl-spotlight--visible\"\n role=\"dialog\" aria-modal=\"false\" aria-labelledby=\"spotlight-title\" tabindex=\"-1\">\n <button type=\"button\" class=\"xpl-spotlight__target\" aria-label=\"Spotlight indicator\">\n <div class=\"xpl-spotlight__target-outer\"></div>\n <div class=\"xpl-spotlight__target-inner\"></div>\n </button>\n <div class=\"xpl-spotlight__dismiss\">\n <xpl-button variant=\"secondary\" size=\"sm\" icon-only aria-label=\"Dismiss tour step\">\n <xpl-icon icon=\"xmark\" size=\"16\"></xpl-icon>\n </xpl-button>\n </div>\n <div class=\"xpl-spotlight__frame\">\n <div class=\"xpl-spotlight__image-container\">\n <img src=\"/assets/spotlight-preview.png\" alt=\"Feature preview\" />\n </div>\n <div class=\"xpl-spotlight__content\">\n <div class=\"xpl-spotlight__header\">\n <span class=\"xpl-spotlight__title\" id=\"spotlight-title\">Tour Title</span>\n <p class=\"xpl-spotlight__body\">Copy about the feature and/or functionality the dot is pointing to.</p>\n </div>\n <div class=\"xpl-spotlight__actions xpl-spotlight__actions--dual xpl-spotlight__actions--with-steps\">\n <div class=\"xpl-spotlight__action-slot xpl-spotlight__action-slot--secondary\">\n <xpl-button variant=\"secondary\">Back</xpl-button>\n </div>\n <span class=\"xpl-spotlight__step-text\">2 of 5</span>\n <div class=\"xpl-spotlight__action-slot xpl-spotlight__action-slot--primary\">\n <xpl-button variant=\"primary\">Next</xpl-button>\n </div>\n </div>\n </div>\n </div>\n</div>\n```\n\n## Accessibility\n\n`xpl-spotlight` renders with `role=\"dialog\"` and `aria-modal=\"false\"` so assistive technologies treat it as a **non-modal** tour callout: focus is not trapped inside the card, and users can tab to the rest of the page while the step is open. The accessible name comes from the title region:\n\n- When the default title is used, the generated heading element receives the internal `aria-labelledby` id.\n- When a custom `title` slot is provided, the component assigns that same id to the first slotted title element if it does not already have one. If the slotted element already has an `id`, that value is kept and `aria-labelledby` references it (the host does not point at a missing id).\n- When neither a `heading` prop nor a `title` slot is provided, the dialog falls back to `aria-label=\"Tour step\"` so that assistive technologies always have an accessible name.\n\n### Keyboard navigation\n\n| Key | Behavior |\n|-----|----------|\n| `Tab` / `Shift+Tab` | Moves focus between interactive controls (dismiss button, secondary action, primary action). Focus is **not** trapped — users can tab out of the spotlight to the rest of the page. |\n| `Escape` | Emits `dismiss` when `isDismissible` is true and focus is inside the spotlight. Does nothing when focus is outside the component or the spotlight is closed. |\n| `Enter` / `Space` | Activates the focused button (dismiss, primary, or secondary action) via standard `xpl-button` behavior. |\n\n### Focus management\n\n- **On open:** focus moves automatically to the dismiss button (if `isDismissible` is true) or the first action button. When neither a dismiss button nor action buttons are rendered, the host element itself receives focus via `tabindex=\"-1\"`.\n- **On close:** focus returns to the element that was focused before the spotlight opened, provided that element is still in the DOM.\n- The decorative anchor dot (`.xpl-spotlight__target`) is marked `aria-hidden=\"true\"` so it is not announced or focusable.\n\n\n## Design Tokens\n\nThe component relies on Foundation purpose tokens in `spotlight.css` so light/dark mode works without component-level `.dark` overrides.\n\n| Property | Token |\n|----------|-------|\n| Card width | `var(--xpl-spotlight-width)` on the host (defined in `spotlight.css`; design-specific width until shared layout tokens exist — see `TECH_DEBT.md`) |\n| Image region min-height | `var(--xpl-spotlight-image-min-height)` on `.xpl-spotlight__image-container` (same note as card width) |\n| Card background | `var(--xpl-background-surface-default)` |\n| Card shadow | `var(--xpl-elevation-3)` (theme-aware elevation token) |\n| Host stacking | `var(--xpl-z-index-800)` |\n| Placeholder pattern | `var(--xpl-background-surface-subtle)` |\n| Heading text | `var(--xpl-text-default)` |\n| Heading line-height | `var(--xpl-line-height-title-3)` (title-3) |\n| Body text | `var(--xpl-text-default)` |\n| Step text | `var(--xpl-text-subdued)` |\n| Open/closed visibility | `opacity` transition on `.xpl-spotlight--visible` |\n| Anchor outer ring | `var(--xpl-background-surface-information-bold)` |\n| Anchor inner dot | `var(--xpl-background-accent-default)` |\n| Image placeholder icon/text | `var(--xpl-icon-subtle)` |\n| Focus outline | `var(--xpl-border-focus)` |\n| Anchored host (when `target` is set) | `position: fixed` via `.xpl-spotlight--anchored`; `left` / `top` set from Floating UI (`strategy: 'fixed'`) |\n\n## Icon Mapping\n\n`xpl-spotlight` uses Apollo icons for fixed controls and fallback media placeholders:\n\n| UI area | `xpl-icon` name |\n|---------|------------------|\n| Dismiss button | `xmark` |\n| Empty image placeholder, image affordance | `photo` |\n| Empty image placeholder, video affordance | `video` |\n\n## Deprecated props\n\nNone.\n\n## Notes\n\n- `showImage=\"false\"` hides the media region even if `slot=\"image\"` content is present.\n- When `showImage` is left enabled and no `slot=\"image\"` content is provided, the component renders the built-in placeholder instead of collapsing the media region.\n- `showActions=\"false\"` removes the default actions row entirely.\n- `is-open=\"false\"` keeps the host element mounted but renders no spotlight UI until it is opened again.\n- `action-layout` defaults to `\"default\"`. `action-layout=\"default\"` renders the Back/Next pair with **disabled** edge buttons at step boundaries (Back disabled on step 1, Next disabled on the last step). `action-layout=\"dual\"` renders the Back/Next pair with **hidden** edge buttons at step boundaries. `action-layout=\"single\"` renders a single primary action.\n- `primary-action-label` and `secondary-action-label` control the default button text without needing action slots.\n- `target` enables Floating UI positioning with `offset`, `flip`, `shift`, and `autoUpdate` so the spotlight follows the referenced element on resize and scroll. Default offset and shift padding match Foundation spacing (`--xpl-space-12` / `--xpl-space-8`).\n- If `target` is missing or contains an invalid CSS selector, the component safely falls back to the requested `anchor-position` instead of throwing.\n- **Storybook:** open **Components → Spotlight** to adjust props via controls. Set `target` to `#spotlight-story-anchor` to preview Floating UI anchoring against the demo button on the canvas. The **Design** addon links to the Apollo Web Figma file (replace the `node-id` in Storybook with the Spotlight frame when Design publishes a dedicated link).\n",
|
|
@@ -13493,8 +13493,8 @@
|
|
|
13493
13493
|
"references": {
|
|
13494
13494
|
"SpotlightActionLayout": {
|
|
13495
13495
|
"location": "local",
|
|
13496
|
-
"path": "/home/runner/work/apollo/apollo/packages/apollo-core/src/components/
|
|
13497
|
-
"id": "src/components/
|
|
13496
|
+
"path": "/home/runner/work/apollo/apollo/packages/apollo-core/src/components/xpl-spotlight/xpl-spotlight.tsx",
|
|
13497
|
+
"id": "src/components/xpl-spotlight/xpl-spotlight.tsx::SpotlightActionLayout"
|
|
13498
13498
|
}
|
|
13499
13499
|
}
|
|
13500
13500
|
},
|
|
@@ -13537,8 +13537,8 @@
|
|
|
13537
13537
|
"references": {
|
|
13538
13538
|
"SpotlightAnchorPosition": {
|
|
13539
13539
|
"location": "local",
|
|
13540
|
-
"path": "/home/runner/work/apollo/apollo/packages/apollo-core/src/components/
|
|
13541
|
-
"id": "src/components/
|
|
13540
|
+
"path": "/home/runner/work/apollo/apollo/packages/apollo-core/src/components/xpl-spotlight/xpl-spotlight.tsx",
|
|
13541
|
+
"id": "src/components/xpl-spotlight/xpl-spotlight.tsx::SpotlightAnchorPosition"
|
|
13542
13542
|
}
|
|
13543
13543
|
}
|
|
13544
13544
|
},
|
|
@@ -14007,7 +14007,7 @@
|
|
|
14007
14007
|
}
|
|
14008
14008
|
},
|
|
14009
14009
|
{
|
|
14010
|
-
"filePath": "src/components/
|
|
14010
|
+
"filePath": "src/components/xpl-tab/xpl-tab.tsx",
|
|
14011
14011
|
"encapsulation": "none",
|
|
14012
14012
|
"tag": "xpl-tab",
|
|
14013
14013
|
"readme": "# xpl-tab\n\n`xpl-tab` is the **label / trigger** for one tab in an `xpl-tabs` group. Place each instance in the **`heading`** slot of `xpl-tabs`. The **`target`** string links this tab to the matching **`xpl-tab-panel`** (same `target` value). The parent sets **`selected`** and syncs **`value`**; you normally do not set `selected` by hand.\n\nUnderline tabs render a native **`<button role=\"tab\">`**; segment tabs render **`xpl-button`** with the same tab semantics on the inner control. For variant-specific examples, icon usage, and token tables, see the matching section on the **Tabs** or **Segment control** Storybook page.\n\n**`group-disabled`** is applied by `xpl-tabs` when the group has **`disabled`**; it keeps pills and underline buttons in a disabled state together with the parent.\n\n## Accessibility\n\n- **IDs and ARIA:** With a parent **`xpl-tabs`**, the tab control and matching **`xpl-tab-panel`** share scoped DOM ids derived from **`data-tabs-instance-id`** on the group and each pair’s **`target`** (see **`xpl-tabs`** accessibility notes). Underline tabs set **`id`**, **`role=\"tab\"`**, **`aria-controls`**, and **`aria-selected`** on the native `<button>`. Segment tabs wrap **`xpl-button`**, which forwards **`id`**, **`role`**, and **`aria-*`** attributes to its inner `<button>` so focus and **`aria-labelledby`** stay correct.\n- Underline tabs expose a **single focusable button** per tab.\n- Segment tabs delegate rendering to **`xpl-button`** with the same tab semantics as underline mode; activation follows the same **`tabChange`** event.\n- Disabled tabs are skipped when moving with arrow keys.\n",
|
|
@@ -14057,7 +14057,7 @@
|
|
|
14057
14057
|
"BadgePalette": {
|
|
14058
14058
|
"location": "import",
|
|
14059
14059
|
"path": "../xpl-badge/xpl-badge",
|
|
14060
|
-
"id": "src/components/
|
|
14060
|
+
"id": "src/components/xpl-badge/xpl-badge.tsx::BadgePalette",
|
|
14061
14061
|
"referenceLocation": "BadgePalette"
|
|
14062
14062
|
}
|
|
14063
14063
|
}
|
|
@@ -14321,7 +14321,7 @@
|
|
|
14321
14321
|
}
|
|
14322
14322
|
},
|
|
14323
14323
|
{
|
|
14324
|
-
"filePath": "src/components/
|
|
14324
|
+
"filePath": "src/components/xpl-tab-panel/xpl-tab-panel.tsx",
|
|
14325
14325
|
"encapsulation": "none",
|
|
14326
14326
|
"tag": "xpl-tab-panel",
|
|
14327
14327
|
"readme": "# xpl-tab-panel\n\n`xpl-tab-panel` is the **content region** for one tab. Place each panel in the **`panel`** slot of `xpl-tabs` and set **`target`** to the same string as its paired **`xpl-tab`**. Only the panel whose `target` matches the group’s selection is visible; others stay hidden via CSS until selected.\n\n## When to use\n\n- One panel per tab in the same `xpl-tabs` as the corresponding `xpl-tab`.\n- Put any markup or other components in the **default slot** (panel body).\n\n## Usage\n\n```html\n<xpl-tabs value=\"overview\">\n <xpl-tab slot=\"heading\" target=\"overview\">Overview</xpl-tab>\n <xpl-tab slot=\"heading\" target=\"activity\">Activity</xpl-tab>\n <xpl-tab-panel slot=\"panel\" target=\"overview\">\n <p class=\"xpl-text-body\">Overview content.</p>\n </xpl-tab-panel>\n <xpl-tab-panel slot=\"panel\" target=\"activity\">\n <p class=\"xpl-text-body\">Activity content.</p>\n </xpl-tab-panel>\n</xpl-tabs>\n```\n\nThe parent **`xpl-tabs`** updates each panel’s **`selected`** state from **`value`** / user interaction; consumers typically only set **`target`** and slot content.\n\n## Accessibility\n\n- The host sets **`role=\"tabpanel\"`**, a stable **`id`** (`…-panel-<target>` scoped by the parent **`xpl-tabs`** instance), and **`aria-labelledby`** referencing the paired tab control’s **`id`**. Use the same **`target`** on **`xpl-tab`** and **`xpl-tab-panel`** so the references stay aligned (see **`xpl-tabs`** accessibility section for the full id pattern).\n- Hidden panels use display toggling (`xpl-tab-panel` / `--selected` in `tabs.css`), not `aria-hidden` on the host; panel content stays in the DOM for simpler state sync.\n\n## Token use\n\n| Part | Token / approach |\n| ---- | ---------------- |\n| Panel visibility | `tabs.css`: hidden unless `xpl-tab-panel--selected` (`display` via Tailwind `@apply`) |\n| Default padding | `py-6` in `tabs.css` on `.xpl-tab-panel` |\n| Inner content | Use typography classes (`xpl-text-body`, etc.) and Foundation tokens as elsewhere in Apollo |\n",
|
|
@@ -14408,7 +14408,7 @@
|
|
|
14408
14408
|
"dependencyGraph": {}
|
|
14409
14409
|
},
|
|
14410
14410
|
{
|
|
14411
|
-
"filePath": "src/components/
|
|
14411
|
+
"filePath": "src/components/xpl-table/xpl-table.tsx",
|
|
14412
14412
|
"encapsulation": "none",
|
|
14413
14413
|
"tag": "xpl-table",
|
|
14414
14414
|
"readme": "# xpl-table\r\n\r\nTables are used to organize and display information from a data set.\r\n\r\n## Rendering modes\r\n\r\n1. **Compositional (recommended)** — Provide `xpl-table-header`, `xpl-table-body`, and optional `xpl-table-footer` with `xpl-table-row` / `xpl-table-header-cell` / `xpl-table-cell` / `xpl-table-footer-cell`. The host uses CSS grid (`role=\"grid\"`). Column widths come from each **`xpl-table-header-cell`** (`width` in px, or `column-width` for any grid track; default `auto` / content-sized). Use `label` for an accessible name. **Sorting:** set `sortable` (and optional `sort-key`) on label header cells; `xpl-table` emits **`sortChanged`** with sort-key slugs → `asc` / `desc` / `null`. The host does **not** reorder row DOM — listen and update your data (or reorder nodes yourself), same as the main Table Storybook demo.\r\n2. **Legacy data-driven** — Set `columns`, `data`, and optionally `footer` for a built-in `<table>` implementation. That path supports `isSortable` / `sortableColumns`, `multiselect`, and emits `sortChanged` / `tableSelect` (legacy can reorder rows unless you `preventDefault`). Prefer compositional markup for new work.\r\n\r\nComposable **selection** (`selectable`), **toolbar**, and copy-paste examples live under **[Usage](#usage)** below (read the breaking-change note first if you are migrating from auto-injected selection cells).\r\n\r\n### Breaking change — global table class names (Apollo Core 3.0.0)\r\n\r\nApollo Core 3.0.0 introduced the compositional table ([#982](https://github.com/xplor/apollo/pull/982)) and ships global CSS for `.xpl-table`, `.xpl-table-row`, `.xpl-table-cell`, `.xpl-table-header-*`, `.xpl-table-body`, and `.xpl-table-footer-*`. In 2.x many of these class names had **no Apollo styles** (or only applied on native `<table>` via `.xpl-table`). These styles are **not scoped** to the `<xpl-table>` element — any element carrying these class names picks them up. If your application used these names as styling hooks on its own native table markup, upgrading to 3.x can break layout.\r\n\r\n| Symptom | Typical cause | Fix |\r\n| --- | --- | --- |\r\n| All table rows render side by side in one line | `xpl-table-row` class hook on native `<tr>` applies `display: contents` | Remove the hook class from native rows, or migrate to `<xpl-table-row>` inside `<xpl-table>` |\r\n| Native `<table class=\"xpl-table\">` layout is destroyed | Compositional grid targets the `.xpl-table` **class** (`display: grid` + `grid-template-columns`), so it also matches native `<table class=\"xpl-table\">` | Add `xpl-table--legacy`: `<table class=\"xpl-table xpl-table--legacy\">` |\r\n| Sticky freeze column lost on native tables | Compositional `.xpl-table--freeze` sticky rules target compositional cell classes (`.xpl-table-cell` etc.); the 2.x native-table freeze lives under `.xpl-table--legacy.xpl-table--freeze` | Add `xpl-table--legacy` to the native `<table>` |\r\n\r\n**`xpl-table--legacy`:** opt-in class for native `<table>` markup (or the deprecated `columns` / `data` render path) that restores pre-compositional Apollo table styling. Scheduled for removal in **Apollo Core 4.0.0** — migrate to compositional `<xpl-table>` or application-owned table styles before then.\r\n\r\n### Row reorder (`row-reorderable`, managed grip column)\r\n\r\nWhen `row-reorderable` is set, Apollo can **inject** a leading reorder column with a native **button** + optional `xpl-icon` on each body row (unless you author that column yourself). Keyboard and pointer reorder share the same grip; **keyboard mode** is indicated by `aria-pressed`, updated labels, the class `xpl-table__row-drag-handle--keyboard-mode`, and optionally a **different icon**.\r\n\r\n**Pointer drag (full row):** Body rows use CSS **`subgrid`** so `xpl-table-row` is a real grid box (like `xpl-list-item`’s row surface). When `CSS.supports('grid-template-columns','subgrid')` is true, **`draggable`** is set on **`xpl-table-row`** so the browser’s drag image matches the whole row; drag still **starts only from the grip** (pointer-down there sets the drag token—dragging from other cells is ignored). Engines without subgrid keep **`draggable`** on the grip button only.\r\n\r\n| Attribute | When it applies | Purpose |\r\n| --------- | ---------------- | ------- |\r\n| `reorder-handle-icon` | Default / drag affordance | Icon name for `xpl-icon` (default `grip-dots-vertical`). Use `reorder-handle-icon=\"\"` to omit the injected icon and use CSS or your own markup in a **custom** reorder cell instead. |\r\n| `reorder-handle-icon-keyboard` | While that row is in **keyboard reorder mode** (Enter or Space on the grip) | Icon name for the same grip when the user is using **Arrow Up/Down** to move the row (default `caret-expand-y`, matching `xpl-list`). Use `reorder-handle-icon-keyboard=\"\"` to show **no** icon in keyboard mode only. |\r\n\r\n**Recommended for product UIs:** Set **both** attributes to your design-system icon names so drag vs keyboard modes are visually distinct. You can still add styles targeting `.xpl-table__row-drag-handle--keyboard-mode` (e.g. outline) for extra clarity.\r\n\r\n**Interaction:** Focus the grip → **Enter** or **Space** → **Arrow Up/Down** to reorder → **Escape** to exit. Pointer down on the row exits keyboard mode; starting a drag also exits keyboard mode.\r\n\r\n**Custom reorder column:** If you add reorder cells in your own template (not injected), **you** own icons, keyboard behavior, and `rowOrderChange` — these attributes apply only to **managed** injected grips.\r\n\r\n## Usage\r\n\r\n### Breaking change — compositional `selectable`\r\n\r\n**Before:** Setting `selectable` alone caused the table to **inject** selection header/body/footer cells into the light DOM (including nodes marked `data-xpl-selection-managed`).\r\n\r\n**After:** You **must** add the selection column in your own markup (see **Selection** below). `xpl-table` no longer creates or removes those cells; it only syncs selection state and emits events. If you previously relied on automatic injection, add the header checkbox column, per-row checkbox cells, and (when using a footer) leading footer cells so column counts match.\r\n\r\n### Selection (`selectable`) and `rowSelectionChange`\r\n\r\nSet `selectable` on `xpl-table` and **author the selection column in your template** so the framework that renders the table owns every cell node.\r\n\r\n**Required pieces:**\r\n\r\n- **Header:** one [`xpl-table-header-cell`](xpl-table-header-cell) with `type=\"checkbox\"` (tri-state “select all”).\r\n- **Body:** in each `xpl-table-row`, a cell aligned with that column containing **`xpl-checkbox`** (value is driven from `row-id` on the row).\r\n- **Footer:** if you use `xpl-table-footer`, add a leading `xpl-table-footer-cell` per row for the selection column (often empty) so column counts stay aligned.\r\n\r\n**Behavior:** After `customElements.whenDefined('xpl-table')`, listen for **`rowSelectionChange`** on the **same** `<xpl-table>` element (`bubbles: false`, `composed: true`). The event payload is `{ selectedRowIds: string[] }`. The host maintains `selectedRowIds`, syncs `checked` / `indeterminate` on the header and row checkboxes, sets `selected` on rows, and shows the bulk toolbar while at least one row is selected. Row checkbox **`aria-label`** is derived from the first **non-selection** data cell in that row (e.g. `Select row, Jordan Lee`); the header uses “Select all rows” unless you set **`checkbox-aria-label`** on the checkbox header cell.\r\n\r\n**Example (web component):**\r\n\r\n```html\r\n<xpl-table id=\"roster\" selectable label=\"Team roster\">\r\n <xpl-table-header>\r\n <xpl-table-row>\r\n <xpl-table-header-cell type=\"checkbox\"></xpl-table-header-cell>\r\n <xpl-table-header-cell label=\"Name\" sortable sort-key=\"name\"></xpl-table-header-cell>\r\n </xpl-table-row>\r\n </xpl-table-header>\r\n <xpl-table-body>\r\n <xpl-table-row row-id=\"1\">\r\n <xpl-table-cell><xpl-checkbox></xpl-checkbox></xpl-table-cell>\r\n <xpl-table-cell>Ada</xpl-table-cell>\r\n </xpl-table-row>\r\n </xpl-table-body>\r\n</xpl-table>\r\n<script type=\"module\">\r\n await customElements.whenDefined('xpl-table');\r\n document.getElementById('roster')?.addEventListener('rowSelectionChange', (e) => {\r\n console.log(e.detail.selectedRowIds);\r\n });\r\n</script>\r\n```\r\n\r\n#### Framework notes (Vue / React / etc.)\r\n\r\nUse **`xpl-checkbox`** in the selection column so `xpl-table` can sync `checked`, `indeterminate`, and `value` from `row-id`. On **`xpl-table-header-cell`**, the selection header uses **`type=\"checkbox\"`**; the prop is **reflected** to the host attribute so Vue bindings like `:type=\"'checkbox'\"` still expose `type=\"checkbox\"` in the DOM for the table’s column detection and CSS.\r\n\r\n### Legacy (`columns` / `data`)\r\n\r\nSet `columns`, `data`, and optional `footer` as **properties** after `customElements.whenDefined('xpl-table')`, or use attributes where your bundler passes JSON strings.\r\n\r\n```html\r\n<xpl-table id=\"legacy\"></xpl-table>\r\n<script type=\"module\">\r\n await customElements.whenDefined('xpl-table');\r\n const t = document.getElementById('legacy');\r\n t.columns = ['Name', 'Score'];\r\n t.data = [\r\n ['Ada', '100'],\r\n ['Bob', '95'],\r\n ];\r\n t.multiselect = true;\r\n t.addEventListener('tableSelect', (e) => console.log(e.detail));\r\n</script>\r\n```\r\n\r\n## Accessibility\r\n\r\n| Concern | Behavior |\r\n| ------- | -------- |\r\n| Table landmark | Compositional host uses **`role=\"grid\"`**; set **`label`** (maps to `aria-label`). |\r\n| Columns | Header cells use **`role=\"columnheader\"`** with `aria-colindex`; sortable label headers expose sort state via **`aria-sort`**. |\r\n| Selection | Checkbox column: header reflects **checked / mixed** via `aria-checked`; row checkboxes get **`aria-label`** from the first non-selection cell’s text (or override with `checkbox-aria-label` on the checkbox header cell). |\r\n| Sort | Sorting is a **`<button type=\"button\">`** inside the header cell; focus uses **`:focus-visible`** with focus tokens in `table-header-cell.css`. |\r\n| Row reorder | Managed grip is a **`<button>`** with `aria-label` / `aria-pressed` for keyboard reorder mode; live region announces reorder when enabled. |\r\n\r\nKeyboard: **Tab** through sort buttons, checkboxes, reorder grips, and cell actions. **Enter** / **Space** activate sort and the reorder grip per native button semantics.\r\n\r\n## Design Tokens\r\n\r\nCompositional grid layout tokens live in `table.css`; cell, row, header, and toolbar tokens are split across sibling CSS files.\r\n\r\n| Element | Property | Token | Light | Dark |\r\n| ------- | -------- | ----- | ----- | ---- |\r\n| Host (compositional) | border | `--xpl-border-small`, `--xpl-border-default` | neutral-200 | neutral-800 |\r\n| Host (compositional) | border-radius | `--xpl-border-radius-default` | 8px | 8px |\r\n| Host (compositional) | grid columns | `--column-widths` (runtime from header cells) | — | — |\r\n| Selection toolbar | sticky z-index | `--xpl-z-index-200` | 200 | 200 |\r\n| Selection toolbar | min-height | `--xpl-size-350` | 56px | 56px |\r\n| Freeze shadow | gradient | `--xpl-background-surface-transparent-10` → `-0` | near-black 10% | near-white 10% |\r\n| Freeze column | sticky z-index | `--xpl-z-index-100` | 100 | 100 |\r\n| Freeze scroll hint | width | `--xpl-space-24` | 24px | 24px |\r\n| Striped even rows | cell background | `--xpl-background-surface-subtlest` | neutral-50 | neutral-950 |\r\n| Striped + selected | cell background | `--xpl-background-surface-information-bold` | blue-100 | blue-900 |\r\n\r\n## Icon mapping\r\n\r\nWhen Apollo **injects** the reorder column, icons come from table props (override with `\"\"` to omit):\r\n\r\n| Context | Default `xpl-icon` `icon` value |\r\n| ------- | -------------------------------- |\r\n| Pointer / idle grip | `grip-dots-vertical` |\r\n| Keyboard reorder mode | `caret-expand-y` |\r\n\r\nSort direction uses **`xpl-icon`** names from header-cell internals (`graph`, carets, etc.) — see Storybook **Components → Table**.\r\n\r",
|
|
@@ -14826,8 +14826,8 @@
|
|
|
14826
14826
|
"references": {
|
|
14827
14827
|
"XplTableRowOrderChangeDetail": {
|
|
14828
14828
|
"location": "local",
|
|
14829
|
-
"path": "/home/runner/work/apollo/apollo/packages/apollo-core/src/components/
|
|
14830
|
-
"id": "src/components/
|
|
14829
|
+
"path": "/home/runner/work/apollo/apollo/packages/apollo-core/src/components/xpl-table/xpl-table.tsx",
|
|
14830
|
+
"id": "src/components/xpl-table/xpl-table.tsx::XplTableRowOrderChangeDetail"
|
|
14831
14831
|
}
|
|
14832
14832
|
}
|
|
14833
14833
|
},
|
|
@@ -14860,8 +14860,8 @@
|
|
|
14860
14860
|
"references": {
|
|
14861
14861
|
"XplTableSortChangedDetail": {
|
|
14862
14862
|
"location": "local",
|
|
14863
|
-
"path": "/home/runner/work/apollo/apollo/packages/apollo-core/src/components/
|
|
14864
|
-
"id": "src/components/
|
|
14863
|
+
"path": "/home/runner/work/apollo/apollo/packages/apollo-core/src/components/xpl-table/xpl-table.tsx",
|
|
14864
|
+
"id": "src/components/xpl-table/xpl-table.tsx::XplTableSortChangedDetail"
|
|
14865
14865
|
}
|
|
14866
14866
|
}
|
|
14867
14867
|
},
|
|
@@ -14985,7 +14985,7 @@
|
|
|
14985
14985
|
}
|
|
14986
14986
|
},
|
|
14987
14987
|
{
|
|
14988
|
-
"filePath": "src/components/
|
|
14988
|
+
"filePath": "src/components/xpl-table/xpl-table-body/xpl-table-body.tsx",
|
|
14989
14989
|
"encapsulation": "none",
|
|
14990
14990
|
"tag": "xpl-table-body",
|
|
14991
14991
|
"readme": "# xpl-table-body\n\nRow group for compositional table body content. Uses `display: contents` so slotted rows participate in the parent grid layout.\n\n## Design Tokens\n\n| Element | Property | Token | Light | Dark |\n| ------- | -------- | ----- | ----- | ---- |\n| Host | display | — | `contents` | `contents` |\n",
|
|
@@ -15015,7 +15015,7 @@
|
|
|
15015
15015
|
"dependencyGraph": {}
|
|
15016
15016
|
},
|
|
15017
15017
|
{
|
|
15018
|
-
"filePath": "src/components/
|
|
15018
|
+
"filePath": "src/components/xpl-table/xpl-table-cell/xpl-table-cell.tsx",
|
|
15019
15019
|
"encapsulation": "none",
|
|
15020
15020
|
"tag": "xpl-table-cell",
|
|
15021
15021
|
"readme": "# xpl-table-cell\n\nBody cell for compositional [`xpl-table`](../readme.md). Place content in the default slot; use `align`, `bold`, and `underline` for typography. Interactive controls inside the cell inherit `disabled` when the parent [`xpl-table-row`](../xpl-table-row) is disabled.\n\n## Design Tokens\n\nExtends `.xpl-table-cell-base` (`table-cell-base.css`); row states (selected, disabled, striped) are applied from `table-row.css`.\n\n| Element | Property | Token | Light | Dark |\n| ------- | -------- | ----- | ----- | ---- |\n| Cell | background | `--xpl-background-surface-default` | neutral-0 | neutral-1000 |\n| Cell | text | `--xpl-text-default` | neutral-900 | neutral-50 |\n| Cell | border (right/bottom) | `--xpl-border-small`, `--xpl-border-default` | 1px, neutral-200 | 1px, neutral-800 |\n| Cell | padding | `--xpl-space-10`, `--xpl-space-16` | 10px / 16px | 10px / 16px |\n| Cell | min-height | `--xpl-size-350` | 56px | 56px |\n| Cell | typography | `@extend .xpl-text-title-5` | title-5 / medium | title-5 / medium |\n| Bold text | font-weight | `--xpl-font-weight-semibold` | 600 | 600 |\n| Disabled | text | `--xpl-text-disabled` | neutral-400 | neutral-600 |\n| Caption slot | text | `--xpl-text-subdued` | neutral-600 | neutral-400 |\n| Icon | color | `--xpl-icon-default` | neutral-900 | neutral-50 |\n| Reorder grip | color | `--xpl-icon-subtle` | neutral-600 | neutral-400 |\n| Reorder grip focus | outline | `--xpl-border-focus` | purple-500 | purple-400 |\n| Checkbox-only column | padding | `--xpl-space-16` + `--xpl-space-4` | 20px / 16px | 20px / 16px |\n",
|
|
@@ -15177,7 +15177,7 @@
|
|
|
15177
15177
|
}
|
|
15178
15178
|
},
|
|
15179
15179
|
{
|
|
15180
|
-
"filePath": "src/components/
|
|
15180
|
+
"filePath": "src/components/xpl-table/xpl-table-footer/xpl-table-footer.tsx",
|
|
15181
15181
|
"encapsulation": "none",
|
|
15182
15182
|
"tag": "xpl-table-footer",
|
|
15183
15183
|
"readme": "# xpl-table-footer\n\nRow group for compositional table footer content. Uses `display: contents` so slotted footer rows participate in the parent grid layout.\n\n## Design Tokens\n\n| Element | Property | Token | Light | Dark |\n| ------- | -------- | ----- | ----- | ---- |\n| Host | display | — | `contents` | `contents` |\n",
|
|
@@ -15207,7 +15207,7 @@
|
|
|
15207
15207
|
"dependencyGraph": {}
|
|
15208
15208
|
},
|
|
15209
15209
|
{
|
|
15210
|
-
"filePath": "src/components/
|
|
15210
|
+
"filePath": "src/components/xpl-table/xpl-table-footer-cell/xpl-table-footer-cell.tsx",
|
|
15211
15211
|
"encapsulation": "none",
|
|
15212
15212
|
"tag": "xpl-table-footer-cell",
|
|
15213
15213
|
"readme": "# xpl-table-footer-cell\n\nFooter cell for compositional tables. Extends the shared `.xpl-table-cell-base` styles with footer-row border rules from `table.css`.\n\n## Design Tokens\n\n| Element | Property | Token | Light | Dark |\n| ------- | -------- | ----- | ----- | ---- |\n| Cell | extends | `.xpl-table-cell-base` | (shared compositional cell base) | (shared compositional cell base) |\n| Cell | background | `--xpl-background-surface-default` | neutral-0 | neutral-1000 |\n| Cell | text | `--xpl-text-default` | neutral-900 | neutral-50 |\n| Cell | border (right/bottom) | `--xpl-border-small`, `--xpl-border-default` | 1px, neutral-200 | 1px, neutral-800 |\n| Last footer row | border-bottom | none (host draws frame) | — | — |\n",
|
|
@@ -15282,7 +15282,7 @@
|
|
|
15282
15282
|
}
|
|
15283
15283
|
},
|
|
15284
15284
|
{
|
|
15285
|
-
"filePath": "src/components/
|
|
15285
|
+
"filePath": "src/components/xpl-table-header/xpl-table-header.tsx",
|
|
15286
15286
|
"encapsulation": "none",
|
|
15287
15287
|
"tag": "xpl-table-header",
|
|
15288
15288
|
"readme": "# xpl-table-header\n\nComponent parts used to assemble the Dynamic Table.\n\n> **Note:** This component is currently in beta. Use with caution as it may have breaking changes in future releases.\n\n",
|
|
@@ -15316,7 +15316,7 @@
|
|
|
15316
15316
|
"dependencyGraph": {}
|
|
15317
15317
|
},
|
|
15318
15318
|
{
|
|
15319
|
-
"filePath": "src/components/
|
|
15319
|
+
"filePath": "src/components/xpl-table/xpl-table-header-cell/xpl-table-header-cell.tsx",
|
|
15320
15320
|
"encapsulation": "none",
|
|
15321
15321
|
"tag": "xpl-table-header-cell",
|
|
15322
15322
|
"readme": "# xpl-table-header-cell\r\n\r\n> **Note:** This component is currently in beta. Use with caution as it may have breaking changes in future releases.\r\n\r\nThe `icon` property accepts icon names as strings. See [xpl-icon available icons](../xpl-icon/ICONS.md) for the complete list.\r\n\r\nWhen this cell is used inside a compositional [`xpl-table`](../xpl-table) with `selectable`, **you** add a `type=\"checkbox\"` header cell for select-all; `xpl-table` keeps `checked` and `indeterminate` in sync with row selection.\r\n\r\n**Frameworks (Vue / etc.):** `type` is **reflected** to the DOM. You may bind with `:type=\"'checkbox'\"` or `type=\"checkbox\"`; the host will still expose `type=\"checkbox\"` as an attribute so the table’s selection column logic and styles stay correct.\r\n\r\nFor **sortable** columns (`type=\"label\"`), set **`sortable`** and optionally **`sort-key`**; the parent table emits **`sortChanged`** (see [`xpl-table` events](../xpl-table#events)).\r\n\r\n**Column width (compositional grid):** Each header cell defines one grid column on the parent `xpl-table`. By default the track is **`auto`** (sizes from content). Set **`width`** for a fixed pixel width (minimum 48px), or **`column-width`** for any CSS grid track string (`1fr`, `minmax(120px, 1fr)`, etc.). When both are set, **`column-width` wins**.\r\n\r\n## Design Tokens\r\n\r\n| Element | Property | Token | Light | Dark |\r\n| ------- | -------- | ----- | ----- | ---- |\r\n| Cell | background | `--xpl-background-surface-subtlest` | neutral-50 | neutral-950 |\r\n| Cell | text | `--xpl-text-subdued` | neutral-600 | neutral-400 |\r\n| Cell | border (right/bottom) | `--xpl-border-small`, `--xpl-border-default` | 1px, neutral-200 | 1px, neutral-800 |\r\n| Cell | min-width | `--xpl-size-300` | 48px | 48px |\r\n| Cell | min-height | `--xpl-size-350` | 56px | 56px |\r\n| Cell | typography | `@extend .xpl-text-title-5` | title-5 / medium | title-5 / medium |\r\n| Sort button | padding | `--xpl-space-12`, `--xpl-space-16` | 12px / 16px | 12px / 16px |\r\n| Sort button focus | outline | `--xpl-border-focus` | purple-500 | purple-400 |\r\n| Sort icon (default) | color | `--xpl-text-subdued` | neutral-600 | neutral-400 |\r\n| Sort icon (active) | color | `--xpl-icon-information` | blue-500 | blue-400 |\r\n| Checkbox column | padding | `--xpl-space-16` + `--xpl-space-4` | 20px / 16px | 20px / 16px |\r\n\r\n---\r\n\r",
|
|
@@ -15695,8 +15695,8 @@
|
|
|
15695
15695
|
"references": {
|
|
15696
15696
|
"HeaderSortChangeDetail": {
|
|
15697
15697
|
"location": "local",
|
|
15698
|
-
"path": "/home/runner/work/apollo/apollo/packages/apollo-core/src/components/
|
|
15699
|
-
"id": "src/components/
|
|
15698
|
+
"path": "/home/runner/work/apollo/apollo/packages/apollo-core/src/components/xpl-table/xpl-table-header-cell/xpl-table-header-cell.tsx",
|
|
15699
|
+
"id": "src/components/xpl-table/xpl-table-header-cell/xpl-table-header-cell.tsx::HeaderSortChangeDetail"
|
|
15700
15700
|
}
|
|
15701
15701
|
}
|
|
15702
15702
|
},
|
|
@@ -15734,7 +15734,7 @@
|
|
|
15734
15734
|
}
|
|
15735
15735
|
},
|
|
15736
15736
|
{
|
|
15737
|
-
"filePath": "src/components/
|
|
15737
|
+
"filePath": "src/components/xpl-table/xpl-table-row/xpl-table-row.tsx",
|
|
15738
15738
|
"encapsulation": "none",
|
|
15739
15739
|
"tag": "xpl-table-row",
|
|
15740
15740
|
"readme": "# xpl-table-row\n\nData row for compositional tables. Uses `display: contents` by default so cells align to the parent grid; when the body supports subgrid, the row becomes a full-width subgrid for drag interactions.\n\n## Design Tokens\n\nRow state styles target descendant `.xpl-table-cell` nodes (see `table-row.css`).\n\n| Element | Property | Token | Light | Dark |\n| ------- | -------- | ----- | ----- | ---- |\n| Host (default) | display | — | `contents` | `contents` |\n| Host (subgrid body) | display | — | `grid` with `subgrid` | `grid` with `subgrid` |\n| Disabled row | background | `--xpl-background-surface-subtlest` | neutral-50 | neutral-950 |\n| Disabled row | text | `--xpl-text-disabled` | neutral-400 | neutral-600 |\n| Dragging row | background | `--xpl-background-surface-subtle` | neutral-100 | neutral-900 |\n| Dragging row | opacity | `--xpl-opacity-75` | 0.75 | 0.75 |\n| Selected row | background | `--xpl-background-surface-information` | blue-50 | blue-950 |\n| Selected grip (reorder) | icon color | `--xpl-icon-information` | blue-500 | blue-400 |\n| Drag-over outline | inset ring | `--xpl-border-focus`, `--xpl-border-small` | purple-500 | purple-400 |\n| Striped even | background | `--xpl-background-surface-subtlest` | neutral-50 | neutral-950 |\n| Striped selected | background | `--xpl-background-surface-information-bold` | blue-100 | blue-900 |\n| Keyboard reorder grip | outline | `--xpl-border-focus` | purple-500 | purple-400 |\n",
|
|
@@ -15846,7 +15846,7 @@
|
|
|
15846
15846
|
"dependencyGraph": {}
|
|
15847
15847
|
},
|
|
15848
15848
|
{
|
|
15849
|
-
"filePath": "src/components/
|
|
15849
|
+
"filePath": "src/components/xpl-tabs/xpl-tabs.tsx",
|
|
15850
15850
|
"encapsulation": "none",
|
|
15851
15851
|
"tag": "xpl-tabs",
|
|
15852
15852
|
"readme": "# xpl-tabs\n\n`xpl-tabs` groups related views into a single surface: users pick a **tab** to show the matching **panel**. It implements the WAI-ARIA tabs pattern with a horizontal tab list, optional full-width layout, and two visual styles—**underline** (`type=\"tabs\"`, default) and **segment** (`type=\"segment\"`, pill controls in a bordered track)—selected with the **`type`** prop. On narrow viewports the heading row is replaced by an `xpl-select` so the same targets and keyboard behavior stay consistent.\n\nThe **Tabs** and **Segment control** Storybook entries document this **one component** with different defaults and Figma references. Each page adds variant-specific guidance (when to use, examples, tokens); the sections below describe behavior that is **the same for both** styles.\n\nPair **`xpl-tab` (slot `heading`)** with **`xpl-tab-panel` (slot `panel`)** and use the same **`target`** string on each pair so selection stays in sync.\n\n## Usage\n\n### Web component (`<xpl-tabs>`)\n\nMinimal group with two tabs: each `xpl-tab` and `xpl-tab-panel` shares a `target` value. Set `value` on `xpl-tabs` to control the selected tab (defaults to the first tab’s `target` if omitted).\n\n```html\n<xpl-tabs value=\"one\">\n <xpl-tab slot=\"heading\" target=\"one\">First</xpl-tab>\n <xpl-tab slot=\"heading\" target=\"two\">Second</xpl-tab>\n <xpl-tab-panel slot=\"panel\" target=\"one\">Content for first tab.</xpl-tab-panel>\n <xpl-tab-panel slot=\"panel\" target=\"two\">Content for second tab.</xpl-tab-panel>\n</xpl-tabs>\n```\n\nListen for selection changes with the **`tabChange`** event (detail is the selected `target` string):\n\n```html\n<xpl-tabs id=\"demo\" value=\"a\">\n <xpl-tab slot=\"heading\" target=\"a\">A</xpl-tab>\n <xpl-tab slot=\"heading\" target=\"b\">B</xpl-tab>\n <xpl-tab-panel slot=\"panel\" target=\"a\">…</xpl-tab-panel>\n <xpl-tab-panel slot=\"panel\" target=\"b\">…</xpl-tab-panel>\n</xpl-tabs>\n<script>\n document.getElementById('demo').addEventListener('tabChange', (e) => {\n console.log(e.detail); // \"a\" | \"b\"\n });\n</script>\n```\n\nDisable the entire group (headings, mobile select, and segment pills) with **`disabled`** on `xpl-tabs`. Disable individual tabs with **`disabled`** on `xpl-tab`.\n\n### Plain HTML (BEM classes)\n\nWhen styling with `tabs.css` without the Stencil component, mirror the structure: `xpl-tabs`, `xpl-tabs__headings` with `role=\"tablist\"` and `aria-orientation=\"horizontal\"`, `xpl-tabs__active-bar` for the underline variant (position/size normally set by JS), **`button.xpl-tab__button`** with **`role=\"tab\"`** (not links), and **`xpl-tab-panel`** for panels. For **segment** (`xpl-tabs--segment`), each heading is **`xpl-tab.xpl-tab--segment`** wrapping **`xpl-button`** (not `.xpl-tab__button`). On small viewports, include **`xpl-tabs__mobile-select`** with **`xpl-select`** for parity with the component.\n\n## Accessibility\n\n- Each **`xpl-tabs`** root gets a unique **`data-tabs-instance-id`** (for example `xpl-tg-1`). **`xpl-tab`** and **`xpl-tab-panel`** derive matching DOM **`id`** values from that id plus the shared **`target`** string: the tab control is **`…-tab-<target>`**, the panel is **`…-panel-<target>`** (with `target` sanitized for HTML `id` rules). The tab exposes **`aria-controls`** pointing at the panel id, **`aria-selected`**, and the panel uses **`aria-labelledby`** pointing at the tab id. **Segment (pill) tabs** render **`xpl-button`**; because **`xpl-button`** does not forward **`id`** / **`role`** / **`aria-*`** to its inner `<button>`, **`xpl-tab`** sets those on the native button after render so focus order and **`aria-labelledby`** stay correct (same pattern as underline tabs, different host element).\n- The tab list container is **`role=\"tablist\"`** with **`aria-orientation=\"horizontal\"`**. Underline tabs use **`role=\"tab\"`** on the inner `<button>`; panels use **`role=\"tabpanel\"`** on **`xpl-tab-panel`**.\n- **Roving tabindex:** only the active tab’s control is in the tab order (`tabindex=\"0\"`); others use `tabindex=\"-1\"` until focused with arrows.\n- **Keyboard:** **Arrow Left/Right** (and **Arrow Up/Down** as next/previous), **Home**, and **End** move between enabled tabs; **Enter** and **Space** activate (via `xpl-button` in segment mode). Direction mirrors in **RTL**.\n- When **`disabled`** is set on `xpl-tabs`, tab keyboard navigation and selection are suppressed for the group.\n\nVariant-specific Foundation mappings for underline vs. segment live in the **Tabs** and **Segment control** Storybook pages. The **`xpl-select`** mobile row reuses **`xpl-select`** / **`xpl-dropdown`** tokens from those components.\n",
|
|
@@ -16052,7 +16052,7 @@
|
|
|
16052
16052
|
}
|
|
16053
16053
|
},
|
|
16054
16054
|
{
|
|
16055
|
-
"filePath": "src/components/
|
|
16055
|
+
"filePath": "src/components/xpl-tag/xpl-tag.tsx",
|
|
16056
16056
|
"encapsulation": "none",
|
|
16057
16057
|
"tag": "xpl-tag",
|
|
16058
16058
|
"readme": "# xpl-tag\n\nTags represent a set of interactive keywords that help label, organize, and categorize objects. Tags can be added or removed from an object by the user. Unlike Badges, Tags are clickable, used in dropdowns, multi-select, search bars, etc.\n\n## Usage Examples\n\n### Basic tag with dismiss\n\n```html\n<xpl-tag>Label</xpl-tag>\n```\n\n### Small size variant\n\n```html\n<xpl-tag size=\"sm\">Small Tag</xpl-tag>\n```\n\n### Non-dismissible tag (no close button)\n\n```html\n<xpl-tag dismissible=\"false\">Static Tag</xpl-tag>\n```\n\n### Disabled tag\n\n```html\n<xpl-tag disabled>Disabled Tag</xpl-tag>\n```\n\n### Handling events\n\n> **⚠️ Deprecation Notice:** The `close` event is **deprecated** and will be removed in a future major version. Use `tagRemove` for dismiss button clicks only.\n\n#### Why This Change?\n\nThe `close` event name conflicts with a **native HTML event** used by `<dialog>` elements. The React wrapper's `isCoveredByReact()` function detects `onclose` as a native event and passes handlers to React's synthetic event system — but React doesn't actually handle `close` events this way, so handlers silently fail in React applications.\n\n**Why `tagRemove` works:** `ontagremove` is not a native event, so the wrapper correctly falls back to `addEventListener`.\n\n#### Event Behavior\n\n| Interaction | `close` (deprecated) | `tagRemove` (use this) |\n|-------------|------------------------|------------------------|\n| Dismiss (×) button clicked | ✅ Fires | ✅ Fires |\n| Content clicked (non-draggable) | ✅ Fires | ❌ Does NOT fire |\n| Content clicked (draggable) | ❌ Does NOT fire | ❌ Does NOT fire |\n| Keyboard Space/Enter on content (non-draggable) | ✅ Fires | ❌ Does NOT fire |\n| Keyboard Space/Enter on draggable label | ❌ Does NOT fire | ❌ Does NOT fire |\n\n#### Migration Examples\n\n**Before (deprecated):**\n```tsx\n// React — this may silently fail!\n<XplTag onClose={() => tag.remove()}>Label</XplTag>\n\n// Vanilla JS\nconst tag = document.querySelector('xpl-tag');\ntag.addEventListener('close', () => tag.remove());\n```\n\n**After (recommended):**\n```tsx\n// React — works reliably\n<XplTag onTagRemove={() => tag.remove()}>Label</XplTag>\n\n// Vanilla JS — same pattern, clearer intent\nconst tag = document.querySelector('xpl-tag');\ntag.addEventListener('tagRemove', () => tag.remove());\n```\n\n**React with Refs (if you must use deprecated `close`):**\n```tsx\nimport { useEffect, useRef } from 'react';\nimport { XplTag } from '@xplortech/apollo-react';\n\nfunction MyComponent() {\n const tagRef = useRef<HTMLElement | null>(null);\n\n useEffect(() => {\n const el = tagRef.current;\n if (!el) return;\n\n const handleClose = () => el.remove();\n el.addEventListener('close', handleClose);\n return () => el.removeEventListener('close', handleClose);\n }, []);\n\n return <XplTag ref={tagRef}>Label</XplTag>;\n}\n```\n\n## Drag and drop\n\nTags support **native HTML5 drag and drop**. Set the boolean prop **`isDraggable`** (HTML attribute **`is-draggable`**) to enable dragging. Optionally set **`tag-id`** so `dataTransfer` and `tagDragStart` / `tagDragEnd` detail carry a stable id.\n\n### How it works (important for handlers)\n\n- The **drag source** is an inner **label** element (a `div` with `role=\"button\"`), not the `<xpl-tag>` host. Browsers do not start drags reliably on the custom element host; the **`is-draggable`** prop does **not** mirror the native host **`draggable`** attribute (see the `isDraggable` prop docs below).\n- On **`dragstart`**, the component uses **`setDragImage`** so the floating preview (“ghost”) looks like the **whole tag** (label + dismiss control), not only the label strip.\n- **Start the drag from the label text**, not from the dismiss (×) button.\n- In container listeners, **`dragstart`** may bubble with `event.target` equal to that inner node. Resolve the tag with:\n\n```js\nconst tag = event.target instanceof Element ? event.target.closest('xpl-tag') : null;\n```\n\n### Making a tag draggable\n\n```html\n<xpl-tag is-draggable>Draggable tag</xpl-tag>\n\n<xpl-tag is-draggable tag-id=\"my-tag-1\">Design</xpl-tag>\n```\n\n### Reordering tags within a container\n\n```html\n<div id=\"tag-container\" style=\"display: flex; flex-wrap: wrap; gap: 8px\">\n <xpl-tag tag-id=\"t1\" is-draggable>Design</xpl-tag>\n <xpl-tag tag-id=\"t2\" is-draggable>Development</xpl-tag>\n <xpl-tag tag-id=\"t3\" is-draggable>QA</xpl-tag>\n</div>\n\n<script>\n const container = document.getElementById('tag-container');\n let draggedEl = null;\n\n container.addEventListener('dragstart', (e) => {\n const tag = e.target instanceof Element ? e.target.closest('xpl-tag') : null;\n if (tag) draggedEl = tag;\n });\n\n container.addEventListener('dragend', () => {\n draggedEl = null;\n });\n\n container.addEventListener('dragover', (e) => {\n e.preventDefault();\n if (!draggedEl) return;\n const afterEl = getDragAfterElement(container, e.clientX);\n if (afterEl == null) container.appendChild(draggedEl);\n else container.insertBefore(draggedEl, afterEl);\n });\n\n function getDragAfterElement(container, x) {\n const tags = [...container.querySelectorAll('xpl-tag')].filter((el) => el !== draggedEl);\n return tags.reduce(\n (closest, child) => {\n const box = child.getBoundingClientRect();\n const offset = x - box.left - box.width / 2;\n return offset < 0 && offset > closest.offset ? { offset, element: child } : closest;\n },\n { offset: Number.NEGATIVE_INFINITY },\n ).element;\n }\n</script>\n```\n\n### Dragging tags between containers\n\n```html\n<div\n class=\"drop-zone\"\n style=\"display: flex; gap: 8px; padding: 16px; border: 2px dashed var(--xpl-border-default); border-radius: 8px\"\n>\n <xpl-tag tag-id=\"a1\" is-draggable>Frontend</xpl-tag>\n <xpl-tag tag-id=\"a2\" is-draggable>Backend</xpl-tag>\n</div>\n\n<div\n class=\"drop-zone\"\n style=\"\n display: flex;\n gap: 8px;\n padding: 16px;\n border: 2px dashed var(--xpl-border-default);\n border-radius: 8px;\n margin-top: 8px;\n \"\n>\n <xpl-tag tag-id=\"b1\" is-draggable>DevOps</xpl-tag>\n</div>\n\n<script>\n document.querySelectorAll('.drop-zone').forEach((zone) => {\n let draggedEl = null;\n\n zone.addEventListener('dragstart', (e) => {\n const tag = e.target instanceof Element ? e.target.closest('xpl-tag') : null;\n if (tag) draggedEl = tag;\n });\n\n zone.addEventListener('dragend', () => {\n draggedEl = null;\n });\n\n zone.addEventListener('dragover', (e) => e.preventDefault());\n\n zone.addEventListener('drop', (e) => {\n e.preventDefault();\n if (draggedEl && draggedEl.parentNode !== zone) zone.appendChild(draggedEl);\n });\n });\n</script>\n```\n\n### `tagDragStart` / `tagDragEnd` events\n\nThe component emits **`tagDragStart`** and **`tagDragEnd`** (Stencil camelCase). They bubble and are composed.\n\n```html\n<xpl-tag is-draggable tag-id=\"my-tag\">Drag me</xpl-tag>\n\n<script>\n const tag = document.querySelector('xpl-tag[tag-id=\"my-tag\"]');\n\n tag.addEventListener('tagDragStart', (e) => {\n const { tagId, content, originalEvent } = e.detail;\n });\n\n tag.addEventListener('tagDragEnd', (e) => {\n const { dropped, tagId, originalEvent } = e.detail;\n if (dropped) {\n /* dropEffect was 'move' */\n }\n });\n</script>\n```\n\n### React (`@xplortech/apollo-react`)\n\nEnsure the app loads Apollo **defineCustomElements** (see the main React package docs). Import **`XplTag`** and use **`isDraggable`**, **`tagId`**, and children for the label.\n\n`HTMLXplTagElement` is provided by Apollo’s Stencil typings (the same setup that types `defineCustomElements`). If your editor cannot resolve it, use `useRef<HTMLElement | null>(null)` and attach listeners on `ref.current`.\n\n`XplTag` is a thin wrapper around the web component. Custom events use the same names as in the DOM (`tagDragStart`, `tagDragEnd`, `tagRemove`). If your TypeScript definitions use different prop names for listeners, attach them with a **ref** (always works):\n\n```tsx\nimport { useEffect, useRef } from 'react';\nimport { XplTag } from '@xplortech/apollo-react';\n\nfunction TagBoard() {\n const tagRef = useRef<HTMLXplTagElement | null>(null);\n\n useEffect(() => {\n const el = tagRef.current;\n if (!el) return;\n\n const onDragStart = (e: CustomEvent) => {\n const { tagId, content } = e.detail;\n };\n const onDragEnd = (e: CustomEvent) => {\n const { dropped, tagId } = e.detail;\n };\n const onTagRemove = () => {\n el.remove(); // Handle dismiss button click\n };\n\n el.addEventListener('tagDragStart', onDragStart as EventListener);\n el.addEventListener('tagDragEnd', onDragEnd as EventListener);\n el.addEventListener('tagRemove', onTagRemove);\n return () => {\n el.removeEventListener('tagDragStart', onDragStart as EventListener);\n el.removeEventListener('tagDragEnd', onDragEnd as EventListener);\n el.removeEventListener('tagRemove', onTagRemove);\n };\n }, []);\n\n return (\n <XplTag ref={tagRef} isDraggable tagId=\"react-1\">\n Movable\n </XplTag>\n );\n}\n```\n\nReorder / multi-container logic is unchanged: listen for native `dragstart`, `dragover`, `drop` on a React parent `div` (use refs) and call `closest('xpl-tag')` as in the HTML examples.\n\n### `DataTransfer` payload\n\n| MIME type | Value | Purpose |\n|-----------|-------|---------|\n| `application/x-tag-id` | `tag-id` prop, if set | Identify the tag in drop handlers |\n| `text/plain` | Trimmed text content of the tag | Fallback for external targets |\n\n`effectAllowed` is set to `move`.\n\n**`originalEvent` in `tagDragStart` / `tagDragEnd`:** the native `DragEvent` is included for convenience, but browsers may clear `dataTransfer` after the synchronous handler completes. Use `tagId`, `content`, and `dropped` from the custom event detail for anything needed after the current turn; only read `originalEvent.dataTransfer` synchronously in the listener.\n\n### Disabled tags\n\n`disabled` wins: the tag is not draggable and keep using a normal `<button>` label (no HTML5 drag on the host).\n\n```html\n<xpl-tag is-draggable disabled>Cannot drag</xpl-tag>\n```\n\n## Design Tokens\n\n| Property | Token |\n|----------|-------|\n| Border (default) | `var(--xpl-border-accent-information)` |\n| Border (disabled) | `var(--xpl-border-accent-subtle)` |\n| Background (default) | `var(--xpl-background-surface-default)` |\n| Background (hover) | `var(--xpl-background-surface-information-bold)` |\n| Background (disabled) | `var(--xpl-background-surface-subtle)` |\n| Text | `var(--xpl-text-strong)` |\n| Text (disabled) | `var(--xpl-text-disabled)` |\n| Dismiss icon | `var(--xpl-icon-default)` |\n| Dismiss icon (disabled) | `var(--xpl-icon-disabled)` |\n| Spacing (default) | `var(--xpl-space-2)` vertical, `var(--xpl-space-12)` horizontal |\n| Spacing (small) | `var(--xpl-space-2)` vertical, `var(--xpl-space-8)` horizontal |\n| Height (default) | `var(--xpl-size-150)` (24px) |\n| Height (small) | `var(--xpl-size-125)` (20px) |\n| Border radius | `var(--xpl-border-radius-button)` |\n| Typography (default) | `var(--xpl-font-size-body)` / `var(--xpl-font-weight-normal)` / `var(--xpl-line-height-body)` |\n| Typography (small) | `var(--xpl-font-size-callout)` / `var(--xpl-font-weight-semibold)` / `var(--xpl-line-height-callout)` |\n| Background (dragging) | `var(--xpl-background-surface-information-bold)` |\n| Cursor (draggable) | `cursor: grab` → `cursor: grabbing` while dragging |\n\n## Accessibility\n\n### Keyboard Navigation\n\n| Key | Action |\n|-----|--------|\n| Tab | Focus tag content or dismiss button |\n| Enter/Space | Activate the focused control: on **dismiss**, emits deprecated `close` and `tagRemove`; on **content**, emits deprecated `close` only when the tag is **not** in drag mode (native `<button>` behavior). |\n\n### Drag mode\n\n- With `isDraggable`, focus moves to the **label** (`role=\"button\"`). Enter/Space on the label does **not** dismiss the tag (same as click on draggable content).\n- Start drags from the **label**; the dismiss control remains a separate focus stop and is not the drag handle.\n\n### ARIA Attributes\n\n- Dismiss button sets `aria-label` to `Dismiss` plus the host element’s `textContent` (trimmed), or the word `tag` when empty, so multiple tags stay distinguishable in screen readers\n- When `disabled={true}`, buttons have `disabled` attribute preventing interaction\n- When `isDraggable` is set, **`aria-grabbed`** on the **label** reflects drag state (`\"false\"` at rest, `\"true\"` while dragging)\n\n### Icon Mapping\n\n| Element | Icon |\n|---------|------|\n| Dismiss button | `xmark` (size 10) |\n\n## Backward Compatibility (CSS class aliases)\n\nThe refactored component preserves legacy CSS classes so existing consumer selectors keep working:\n\n| Legacy class | Element | Replaces / alias for |\n|---|---|---|\n| `xpl-tag-container` | Host (`<xpl-tag>`) | Old root class — now an alias; styles come from `.xpl-tag` |\n| `xpl-tag` | Content `<button>` / `<div>` | Old content selector (`button.xpl-tag`) — kept so `.xpl-tag-container .xpl-tag` selectors match |\n| `xpl-tag__close` | Dismiss `<button>` | Old dismiss selector — alias for `.xpl-tag__dismiss` |\n\nThese aliases will be removed in a future major version. New code should target `.xpl-tag`, `.xpl-tag__content`, and `.xpl-tag__dismiss`.\n",
|
|
@@ -16246,8 +16246,8 @@
|
|
|
16246
16246
|
"references": {
|
|
16247
16247
|
"TagDragEndDetail": {
|
|
16248
16248
|
"location": "local",
|
|
16249
|
-
"path": "/home/runner/work/apollo/apollo/packages/apollo-core/src/components/
|
|
16250
|
-
"id": "src/components/
|
|
16249
|
+
"path": "/home/runner/work/apollo/apollo/packages/apollo-core/src/components/xpl-tag/xpl-tag.tsx",
|
|
16250
|
+
"id": "src/components/xpl-tag/xpl-tag.tsx::TagDragEndDetail"
|
|
16251
16251
|
}
|
|
16252
16252
|
}
|
|
16253
16253
|
},
|
|
@@ -16266,8 +16266,8 @@
|
|
|
16266
16266
|
"references": {
|
|
16267
16267
|
"TagDragStartDetail": {
|
|
16268
16268
|
"location": "local",
|
|
16269
|
-
"path": "/home/runner/work/apollo/apollo/packages/apollo-core/src/components/
|
|
16270
|
-
"id": "src/components/
|
|
16269
|
+
"path": "/home/runner/work/apollo/apollo/packages/apollo-core/src/components/xpl-tag/xpl-tag.tsx",
|
|
16270
|
+
"id": "src/components/xpl-tag/xpl-tag.tsx::TagDragStartDetail"
|
|
16271
16271
|
}
|
|
16272
16272
|
}
|
|
16273
16273
|
},
|
|
@@ -16317,7 +16317,7 @@
|
|
|
16317
16317
|
}
|
|
16318
16318
|
},
|
|
16319
16319
|
{
|
|
16320
|
-
"filePath": "src/components/
|
|
16320
|
+
"filePath": "src/components/xpl-toast/xpl-toast.tsx",
|
|
16321
16321
|
"encapsulation": "none",
|
|
16322
16322
|
"tag": "xpl-toast",
|
|
16323
16323
|
"readme": "# xpl-toast\n\nToasts are brief, non-disruptive messages that provide quick, at-a-glance feedback. They can have 3 sentiments; neutral, positive and negative and contain actions such as a button or link, or a close button. Messaging can include a title and caption limited to 85 characters. Keep your toast messaging short and to the point and tone in line with the sentiment of the Toast. \n\nThe Toast component is configurable by Sentiment plus show/hide properties for Icon, Caption, Button and Dismissible. Use the nested component’s properties to customize further as needed. \n\nWhen possible, Toasts should auto-dismiss after 8 seconds. When an action is present, it may not be desirable to time out the Toast depending on your specific context. \n\nMatch your messaging with the sentiment of the toast. Most messages will have a neutral sentiment. Reserve negative sentiments for when an explicit failure has occurred. Give users the information they need to correct the issue. \n\nToasts only support a single action and up to 85 characters. If multiple actions can be taken, or the message is longer than a few words, use a [Modal component](https://apollo.xplordocs.com/?path=/story/components-modal--modal) instead.\n\n## Usage\n\n```html\n<!-- Neutral toast with a caption, auto-dismissing after the default 8s -->\n<xpl-toast caption=\"Your changes have been saved.\">\n <p slot=\"title\">Saved</p>\n</xpl-toast>\n\n<!-- With an action. Auto-dismiss is suppressed while the action slot has content -->\n<xpl-toast variant=\"warning\" caption=\"We couldn't reach the server.\">\n <p slot=\"title\">Sync failed</p>\n <xpl-button slot=\"action\" size=\"sm\">Retry</xpl-button>\n</xpl-toast>\n\n<!-- No close button; disable auto-dismiss with timeout=\"0\" -->\n<xpl-toast dismissible=\"false\" timeout=\"0\">\n <p slot=\"title\">Uploading…</p>\n</xpl-toast>\n```\n\n## Deprecations\n\n### `dismissable` → `dismissible`\n\nThe **`dismissable`** prop is misspelled and is **deprecated**. Use **`dismissible`** instead.\n\n```html\n<!-- Before -->\n<xpl-toast dismissable=\"false\">…</xpl-toast>\n\n<!-- After -->\n<xpl-toast dismissible=\"false\">…</xpl-toast>\n```\n\nBoth props are supported during the deprecation window, so no consumer change is required immediately:\n\n| `dismissable` | `dismissible` | Close button shown | Notes |\n| ------------- | ------------- | ------------------ | ----- |\n| unset | unset | ✅ | Default (`dismissible` defaults to `true`) |\n| unset | `false` | ❌ | Recommended usage |\n| `false` | unset | ❌ | Existing markup keeps working |\n| `false` | `true` | ❌ | `dismissable` wins while it exists |\n\n`dismissable` has **no default** (`undefined` when unset) so the component can tell \"not set\" from \"set to `false`\". When it is used, the component logs a one-time deprecation warning to the console. `dismissable` will be removed in the next major version, at which point `dismissible` becomes the only option.\n\n## Positioning\n\nThe default position is arbitrarily set to `40px` from top and `40px` from right of the browser viewport on desktop and bottom-center on mobile. This position should be adjusted to ensure it's not covering your App's header. Apollo, by design, does not prescribe a position for toasts because this will be dependent on the app that it is being used in.\n\nPositioning of toasts should be global to your app. For example, if it is decided that your app will always position the toast in the top right corner, then this convention should be followed throughout. It should not be positioned top-right on one screen and bottom-center on another.\n\n*****Consult your designer for the best placement for your product.**\n\n### Overriding the default position\n\nThe toast uses `position: fixed` and can be repositioned by overriding the `.xpl-toast` CSS class in your app's stylesheet. Set `top`, `right`, `bottom`, and `left` as needed and use `unset` or `initial` to clear any defaults you don't want.\n\n**Top-left example:**\n```css\n.xpl-toast {\n top: 24px;\n right: unset;\n left: 24px;\n}\n```\n\n**Bottom-right example:**\n```css\n.xpl-toast {\n top: unset;\n right: 24px;\n bottom: 24px;\n}\n```\n\n**Centered at the top:**\n```css\n.xpl-toast {\n top: 24px;\n right: unset;\n left: 50%;\n transform: translateX(-50%);\n}\n```\n\nThe mobile breakpoint (≤ 768px) resets the toast to bottom-center. If your app needs a different mobile position, override the media query as well:\n\n```css\n@media screen and (max-width: 768px) {\n .xpl-toast {\n /* your mobile overrides */\n bottom: 16px;\n left: 50%;\n transform: translateX(-50%);\n }\n}\n```\n\n> **Tip:** Place these overrides in a global stylesheet so every toast in your app appears in the same location.\n\n## Token Use\n\n`xpl-toast` follows the same messaging-component token pattern as [`xpl-banner`](../xpl-banner) (background `--xpl-background-messaging-*` + accent/sentiment border). Light and dark mode are handled by the Foundation token definitions, so the component has no `.dark` overrides.\n\n| Variant / element | Property | Token |\n| ----------------- | -------- | ----- |\n| `neutral` (default) | background | `--xpl-background-messaging-information` |\n| `neutral` (default) | border | `--xpl-border-accent-information` |\n| `&--warning` | background | `--xpl-background-messaging-negative` |\n| `&--warning` | border | `--xpl-border-negative` |\n| `&--success` | background | `--xpl-background-messaging-positive` |\n| `&--success` | border | `--xpl-border-positive` |\n| `&__icon--neutral` | color | `--xpl-icon-default` |\n| `&__icon--warning` | color | `--xpl-icon-negative` |\n| `&__icon--success` | color | `--xpl-icon-positive` |\n| `&` | body radius | `--xpl-border-radius-small` |\n| `&` | shadow | `--xpl-elevation-3` (theme-aware) |\n| `&__title` | typography (size / weight / line-height) | `@extend .xpl-text-title-5` → `title-5` / `medium` / `1.4286` |\n| `&__caption` | typography (size / weight / line-height) | `@extend .xpl-text-callout` → `callout` / `normal` / `1.3333` |\n| `&__close` | margin | `@apply ml-4` |\n\nThe close control is an [`xpl-button`](../xpl-button) (`variant=\"tertiary\"`, `size=\"sm\"`, `iconOnly`), so its radius, colors, and hover / focus / active states come from `button.css` rather than `toast.css`.\n\nLike `xpl-banner`, the messaging backgrounds resolve to transparent in dark mode; the sentiment border and page surface carry the visual treatment in that theme.\n\n## Accessibility\n\n- The close control is an [`xpl-button`](../xpl-button), so it is focusable and keyboard-activable (Tab, then Enter or Space) and gets the shared `:focus-visible` outline.\n- It carries `aria-label=\"Dismiss notification\"` and `type=\"button\"` — the explicit type keeps a toast rendered inside a `<form>` from submitting it when the toast is closed.\n- Toast content is projected through the `title` and `action` slots. Provide the title as text (e.g. `<p slot=\"title\">`) so screen readers announce the message.\n- Dismissing runs a fade-out animation and then removes the host element from the DOM, so a dismissed toast leaves nothing behind in the accessibility tree.\n\n> **Elevation shadow:** the toast uses `--xpl-elevation-3` (theme-aware), re-specified by design during the elevation 1–4 formalization — an earlier note citing the single \"Shadow 4\" style was superseded. See `TECH_DEBT.md`.\n",
|
|
@@ -16554,7 +16554,7 @@
|
|
|
16554
16554
|
}
|
|
16555
16555
|
},
|
|
16556
16556
|
{
|
|
16557
|
-
"filePath": "src/components/
|
|
16557
|
+
"filePath": "src/components/xpl-toggle/xpl-toggle.tsx",
|
|
16558
16558
|
"encapsulation": "none",
|
|
16559
16559
|
"tag": "xpl-toggle",
|
|
16560
16560
|
"readme": "# xpl-toggle\n\nA Toggle is a type of form control that is used to switch between enabled and disabled states of an element.\n\n## Usage\n\n```html\n<xpl-toggle heading=\"Notifications\" label=\"Email me\" checked></xpl-toggle>\n<xpl-toggle label=\"Compact\" variant=\"small\"></xpl-toggle>\n<xpl-toggle label=\"Unavailable\" disabled></xpl-toggle>\n```\n\n## Design Tokens\n\nThe toggle uses Apollo Foundation purpose-specific tokens so it themes automatically\nin light and dark mode (no `.dark` overrides).\n\n| Element / state | Property | Token |\n| --- | --- | --- |\n| Track (off) | `background-color` | `--xpl-background-accent-neutral` |\n| Track (off, hover) | `background-color` | `--xpl-background-accent-neutral-bold` |\n| Track (on) | `background-color` | `--xpl-background-action-primary-default` |\n| Track (on, hover) | `background-color` | `--xpl-background-action-primary-hover` |\n| Track (disabled, on/off) | `background-color` | `--xpl-background-action-disabled` |\n| Track border | `border-color` | `--xpl-border-default` |\n| Knob (all states) | `background-color` | `--xpl-background-surface-inverse-on-dark` (always-light — resolves to neutral-0 in both modes) |\n| Knob shadow | `box-shadow` | `--xpl-elevation-1` (theme-aware) |\n| Focus ring | `outline-color` | `--xpl-border-focus` (2px outline, 2px offset) |\n| Heading | `color` | `--xpl-text-strong` |\n| Heading | typography | `@extend .xpl-text-title-5` — 14px / medium / 1.4286 (via shared `label.css`) |\n| Trailing label | `color` | `--xpl-text-strong` |\n| Trailing label | typography | `@extend .xpl-text-body` — 14px / normal / 1.4286 |\n| Label (disabled) | `color` | `--xpl-text-disabled` |\n| Description (`small`) | `color` | `--xpl-text-subdued` |\n| Description (`small`) | typography | `@extend .xpl-text-callout` — 12px / normal / 1.3333 (via shared `label.css`) |\n\n**Sizing:** knob (`--xpl-size-125` / small `--xpl-size-075`), default track height\n(`--xpl-size-150`), small track height/radius (`--xpl-size-100` / `--xpl-border-radius-default`),\ndefault track + knob radius (`--xpl-border-radius-full`), inset (`--xpl-space-2`), knob travel\n(`translateX(--xpl-size-125)` / small `--xpl-size-075`). The `44px`/`28px` track widths have no\nmatching Foundation token and remain literals (see TECH_DEBT.md).\n\nThe knob glyphs (X / check marks) remain hardcoded data-URI SVGs; a `mask-image` +\n`var(--xpl-icon-*)` refactor is tracked in TECH_DEBT.md.\n\n## Accessibility\n\nThe toggle renders a native `<input type=\"checkbox\">`, so it is keyboard-focusable and\noperable with Tab and Space. The `:focus-visible` outline is applied to the control itself.\n",
|
|
@@ -16767,10 +16767,10 @@
|
|
|
16767
16767
|
"dependencyGraph": {}
|
|
16768
16768
|
},
|
|
16769
16769
|
{
|
|
16770
|
-
"filePath": "src/components/
|
|
16770
|
+
"filePath": "src/components/xpl-toolbar/xpl-toolbar.tsx",
|
|
16771
16771
|
"encapsulation": "none",
|
|
16772
16772
|
"tag": "xpl-toolbar",
|
|
16773
|
-
"readme": "# xpl-toolbar\n\n> **Note:** This component is currently in beta. Use with caution as it may have breaking changes in future releases.\n\n## Design Tokens\n\nThe toolbar is an **always-dark** selection bar (nav-rail pattern) — its surface stays dark\nin both light and dark themes. Styling comes from Apollo Foundation tokens\n(`packages/apollo-core/src/
|
|
16773
|
+
"readme": "# xpl-toolbar\n\n> **Note:** This component is currently in beta. Use with caution as it may have breaking changes in future releases.\n\n## Design Tokens\n\nThe toolbar is an **always-dark** selection bar (nav-rail pattern) — its surface stays dark\nin both light and dark themes. Styling comes from Apollo Foundation tokens\n(`packages/apollo-core/src/components/xpl-toolbar/toolbar.css`):\n\n| Element | Property | Token | Resolves (light / dark) |\n| --- | --- | --- | --- |\n| `.toolbar` surface | `background-color` | `--xpl-background-surface-inverse-on-light` | neutral-1000 / neutral-1000 |\n| `.toolbar` top/bottom border | `border-color` | `--xpl-border-default` | neutral-600 (always-dark host) |\n| `.toolbar` elevation | `box-shadow` | `--xpl-elevation-1` | theme-aware (near-black light / near-white dark) |\n| `.toolbar` height | `height` | `--xpl-size-350` | 56px |\n| `.selected-item-count` text | `color` | `--xpl-text-inverse-on-dark` | white / white |\n| `.selected-item-count` divider | `border-color` | `--xpl-border-default` | neutral-600 (always-dark host) |\n| `.selected-item-count` label | `font-size` / `font-weight` / `line-height` | `@extend .xpl-text-title-5` (14px, medium, 1.4286) | — |\n\n> **Design note:** the always-dark surface decision is confirmed (there is no\n> toolbar node in `figma-manifest.json`). The elevation uses the theme-aware\n> `--xpl-elevation-1` token: in dark mode the shadow color flips to near-white, so\n> the always-dark bar gets a light halo beneath it — flagged for design verification\n> (see `TECH_DEBT.md`).\n",
|
|
16774
16774
|
"docs": "> **Note:** This component is currently in beta. Use with caution as it may have breaking changes in future releases.",
|
|
16775
16775
|
"docsTags": [
|
|
16776
16776
|
{
|
|
@@ -16846,7 +16846,7 @@
|
|
|
16846
16846
|
"dependencyGraph": {}
|
|
16847
16847
|
},
|
|
16848
16848
|
{
|
|
16849
|
-
"filePath": "src/components/
|
|
16849
|
+
"filePath": "src/components/xpl-tooltip/xpl-tooltip.tsx",
|
|
16850
16850
|
"encapsulation": "none",
|
|
16851
16851
|
"tag": "xpl-tooltip",
|
|
16852
16852
|
"readme": "# xpl-tooltip\n\nTooltips are intended to be short one to two sentence messages adding contextual information for the user. Keep messages short and to the point. Tooltips are static and do not contain actions, and only appear when the context is hovered.\n\nTooltip variants control one of 8 arrow positions indicating the direction the tooltip will appear in relation to it's trigger:\n\"bottom-left\" | \"bottom-middle\" | \"bottom-right\" | \"left\" | \"right\" | \"top-left\" | \"top-middle\" | \"top-right\"\n\n\n### Design Tokens\n\nTokens used by this component from `@xplortech/apollo-foundation`.\n\n**Color**\n- `--xpl-background-surface-default` — tooltip background and arrow fill\n- `--xpl-elevation-3` — tooltip shadow (theme-aware)\n- `--xpl-text-default` — tooltip text color\n- `--xpl-border-default` — tooltip border and arrow stroke (keeps the arrow edge theme-aware in dark mode)\n\n**Spacing**\n- `--xpl-space-6` — vertical padding\n- `--xpl-space-8` — horizontal padding\n- `--xpl-space-12` — offset from trigger, via `--xpl-tooltip-margin`\n\n**Typography**\n- `.xpl-text-callout` — text style (via `@extend`)\n\n**Border**\n- `--xpl-border-small` — border width (1px)\n- `--xpl-border-radius-small` — corner radius (4px)\n\n**Z-index**\n- `--xpl-z-index-900` — tooltip stacking order\n- `--xpl-z-index-100` — arrow base stacking order (elevated to `--xpl-z-index-900` per position variant)\n",
|
|
@@ -16997,7 +16997,7 @@
|
|
|
16997
16997
|
}
|
|
16998
16998
|
},
|
|
16999
16999
|
{
|
|
17000
|
-
"filePath": "src/components/
|
|
17000
|
+
"filePath": "src/components/xpl-top-nav/xpl-top-nav.tsx",
|
|
17001
17001
|
"encapsulation": "none",
|
|
17002
17002
|
"tag": "xpl-top-nav",
|
|
17003
17003
|
"readme": "# xpl-top-nav\n\nTop navigation shell for navigating between Xplor applications and account controls — brand, cross-app navigation, right-side actions, and an optional account menu. In Xplor's primary use case it switches between Xplor products within one account, while the side navigation handles primary navigation within a single app.\n\n## Usage\n\nUse slots only for layout content. The component provides the internal wrappers for the right rail and user menu. The right side renders `right-aside` then the user menu (built-in trigger + panel). `left-aside` is intended for `xpl-top-nav-item` links (each item should use **`slot=\"left-aside\"`** so they are direct children of the internal **`role=\"list\"`** — avoid wrapping them in a single container with that slot). Set the **`child-account-label`** attribute (or **`childAccountLabel`** in React) for the built-in menu trigger label beside the chevron; use **`slot=\"user-menu-trigger\"`** to replace that trigger entirely. If `brand-href` is set, the brand uses native link navigation. If not, the component emits `brandClick`.\n\n### Web component (typical layout)\n\n```html\n<xpl-top-nav\n brand-name=\"My App\"\n brand-href=\"/\"\n label=\"Main navigation\"\n child-account-label=\"Account\"\n nav-control\n>\n <xpl-top-nav-item slot=\"left-aside\" label=\"Home\" href=\"/\" icon=\"house-4\"></xpl-top-nav-item>\n <xpl-top-nav-item slot=\"left-aside\" label=\"Reports\" href=\"/reports\"></xpl-top-nav-item>\n\n <xpl-button slot=\"right-aside\" variant=\"secondary\">Help</xpl-button>\n <xpl-nav-header-menu slot=\"user-menu\" username=\"Alex User\" email=\"alex@example.com\">\n <xpl-top-nav-item slot=\"right-aside-mobile\" label=\"Help\" href=\"/help\"></xpl-top-nav-item>\n <xpl-top-nav-item label=\"Profile\" href=\"/profile\" icon=\"person-1\"></xpl-top-nav-item>\n <xpl-top-nav-item label=\"Sign out\" href=\"/logout\" icon=\"open-rect-arrow-out\"></xpl-top-nav-item>\n </xpl-nav-header-menu>\n</xpl-top-nav>\n```\n\n### Logo from URL and SPA brand (no `brand-href`)\n\n```html\n<xpl-top-nav brand-logo=\"https://example.com/logo.svg\" brand-name=\"Apollo\">\n <xpl-top-nav-item slot=\"left-aside\" label=\"Dashboard\" href=\"#\"></xpl-top-nav-item>\n</xpl-top-nav>\n```\n\nListen for `brandClick` on the host when `brand-href` is omitted.\n\n### Plain HTML (static documentation)\n\nUse the same tags in any HTML page that loads Apollo styles and the component bundle. Prefer slots and `xpl-top-nav-item` rather than copying internal BEM classes.\n\n## Responsive behavior\n\n- `nav-control` enables the mobile drawer toggle. The control is only visible on **narrow viewports** (see **`top-nav.css`**: one pixel below Tailwind **`md`**; hidden from **`md`** / **768px** width upward at default Tailwind).\n- Below **`md`**, **`slot=\"left-aside\"`** (`.xpl-nav-left`) is **hidden** unless **`nav-control`** is set **and** the drawer is open (`xpl-top-nav--nav-control` + `xpl-top-nav--open`). **Without `nav-control` there is no mobile drawer** — primary links are not shown in the narrow bar (duplicate into **`xpl-nav-header-menu`** or widen the viewport if they must stay reachable).\n- Pressing `Escape` closes nested dropdowns first, then closes the mobile drawer if it is still open (when `nav-control` is set). Focus then returns to the hamburger toggle. **Escape** is ignored for closing the drawer while **any** descendant **`xpl-popover`** is open (including the account menu or a consumer-slotted popover in **`left-aside`** / **`right-aside`**).\n- Opening the built-in **account** popover while the mobile drawer is open **closes the drawer** and emits **`navOpen(false)`** so the two surfaces do not stack.\n- On **narrow viewports**, **`slot=\"right-aside\"`** is hidden in the bar. Duplicate those actions into **`xpl-nav-header-menu`** **`slot=\"right-aside-mobile\"`** (narrow-only strip below profile, above the list) so they stay reachable from the account menu.\n- On **`xpl-top-nav-item`**, use **`selected`** for the current page (**`aria-current=\"page\"`**) and optional **`active`** for extra accent styling; see the item readme for modifier details.\n- **`slot=\"dropdown\"`** does not implement arrow-key roving focus; put focusable elements inside the panel or treat full “menu” keyboard behavior as a future enhancement.\n- **Grouping nav items:** put an **`xpl-top-nav-menu`** in a parent **`xpl-top-nav-item`**'s **`slot=\"dropdown\"`** to render a desktop flyout of **`xpl-top-nav-item`** rows (e.g. grouping by product). The same markup also drives the **mobile cascade** below — see **`xpl-top-nav-menu`**'s readme for the full interaction model (back row, focus management, Escape / drawer-close lifecycle).\n- **Mobile cascade:** below **`md`**, tapping a **`left-aside`** parent that has a menu swaps the drawer's Level 1 list for that group's Level 2 rows **in place** (no second panel) — the group's **`xpl-top-nav-menu`** auto-renders a back row (leading `chevron-left` + its `label`) as the first row. Tapping the back row, or pressing **Escape** once, pops back to Level 1; a second **Escape**, or the hamburger toggle, closes the drawer (and resets any still-drilled-in group so the drawer reopens at Level 1). Cascade depth is capped at 2 levels and is mobile-only — the desktop flyout is always a single level of links.\n- **Child-location context on small screens:** for a \"Change Account\" style row (a plain **`xpl-top-nav-item`** you author in **`slot=\"user-menu\"`**), set **`description`** to the current child-location's name so it reads e.g. \"Change Account\" / \"Acme Corp — Downtown Location\" on narrow viewports where that context isn't otherwise visible in the bar. This is a content pattern (see the **`TopNavigation`** story), not a separate framework feature — **`description`** already exists on **`xpl-top-nav-item`**.\n\n## Theming\n\n- The host applies the Foundation `dark` scope so the bar and its slotted children resolve dark-mode purpose tokens automatically.\n- Floating overlays rendered outside the host, such as teleported popover content, may need their own `dark` class if they should match the shell.\n\n## Icon Mapping\n\n| Location | Icon name | Notes |\n| -------- | --------- | ----- |\n| Mobile nav toggle (`nav-control`) | `menu` | Shown inside the bar control when `nav-control` is set. |\n| Built-in account trigger | `chevron-down` | `xpl-button` `icon` prop (end). |\n| Dropdown row (`xpl-top-nav-item` with `slot=\"dropdown\"`) | `chevron-down` | Trailing indicator on the row control. |\n\nConsumer-provided `icon` props on `xpl-top-nav-item` use names from `@xplortech/apollo-icons`.\n\n## Token use\n\n| Area | Token / variable |\n| ---- | ---------------- |\n| Bar surface | `var(--xpl-background-surface-default)` |\n| Bar text (default) | `var(--xpl-text-subdued)` |\n| Bar height | `var(--xpl-size-350)` |\n| Bar padding | `var(--xpl-space-8)` / `var(--xpl-space-16)` |\n| Bottom border | `var(--xpl-border-small)` `var(--xpl-border-default)` |\n| Focus ring | `var(--xpl-border-focus)` with `outline-2` / `outline-offset-2` (see `top-nav.css`) |\n| Panel / drawer width | `var(--xpl-top-nav-panel-width)` (component custom property in `top-nav.css`) |\n| Account popover offset | `var(--xpl-space-16)` below bar (`margin-top` on menu content) |\n\n## Accessibility\n\n- **`nav` landmark:** The `label` prop maps to `aria-label` on the inner `<nav>`. If omitted, it defaults to **`top-navigation-bar`**. Use a unique label when multiple navigation regions exist (e.g. side nav + top nav).\n- **Mobile control:** With `nav-control`, the toggle is a native `<button>` with `aria-expanded` reflecting the drawer and an accessible name for open/close.\n- **Account menu:** The built-in `xpl-button` trigger sets `aria-haspopup=\"dialog\"` to match the internal `xpl-popover` trigger. Chevron-only mode (no `child-account-label` text) adds `aria-label=\"Open account menu\"`. The popover's internal wrapper `<span>` is hidden via CSS `visibility: hidden` so the `xpl-button` is the **single tab stop** — click and keyboard events still bubble to the popover. Custom triggers via `slot=\"user-menu-trigger\"` should set their own accessible name and `aria-haspopup`.\n- **Primary links:** Brand and items use `xpl-top-nav-item` (native `<a>` or `role=\"button\"`) with keyboard activation (Enter / Space where applicable).\n- **Dropdown items:** Items with `slot=\"dropdown\"` expose `aria-expanded` on the inner control; **Escape** closes the dropdown (document capture). **Escape** on the shell closes the mobile drawer only after dropdowns and **any** open descendant **`xpl-popover`** are closed (document capture vs bubble ordering). Arrow-key navigation within the dropdown panel is not built in.\n- **Icon-only items:** With **`icon`** and no **`label`** or default-slot text, the inner control gets **`aria-label`** (**`item-aria-label`** to override, else **`Navigation item`**).\n- **Lists:** `left-aside` is wrapped in `role=\"list\"`; each primary link `xpl-top-nav-item` uses `role=\"listitem\"`. The built-in brand row (`xpl-top-nav__brand`) omits `listitem` because it sits outside that list; `slot=\"right-aside-mobile\"` rows omit it as well. `xpl-nav-header-menu` default-slot rows still use `listitem` (menu list contract).\n",
|
|
@@ -17254,7 +17254,7 @@
|
|
|
17254
17254
|
}
|
|
17255
17255
|
},
|
|
17256
17256
|
{
|
|
17257
|
-
"filePath": "src/components/
|
|
17257
|
+
"filePath": "src/components/xpl-top-nav/xpl-top-nav-item/xpl-top-nav-item.tsx",
|
|
17258
17258
|
"encapsulation": "none",
|
|
17259
17259
|
"tag": "xpl-top-nav-item",
|
|
17260
17260
|
"readme": "# xpl-top-nav-item\n\n## Behavior\n\n- **Plain item:** **`label`** / **`icon`** (or **`slot=\"leading-icon\"`**), default slot, or **`href`** link. Renders a native **`<button type=\"button\">`** (or **`<a href>`** in link mode) and fires **`navItemClick`** (**`detail`**: **`MouseEvent`**) on click and **Enter** / **Space** — the native button handles keyboard activation, and link-mode **Space** maps to a programmatic **`.click()`**.\n- **Dropdown trigger:** Put content in **`slot=\"dropdown\"`** (e.g. `<xpl-top-nav-menu>`). Shows an auto **`chevron-down`** (unless **`slot=\"trailing-icon\"`** is provided) and toggles **`.xpl-top-nav-item__dropdown`** in the host light DOM — **not** **`xpl-dropdown`** / **`xpl-popover`**; use those for standalone floating menus (e.g. account in top-nav stories). **`navItemClick`** is not emitted. See **`TECH_DEBT.md`** for tradeoffs.\n- **Disclosure ARIA:** A dropdown trigger's inner control carries **`aria-expanded`** (open state), **`aria-haspopup=\"true\"`**, and **`aria-controls`** pointing at the **`.xpl-top-nav-item__dropdown`** panel's generated id. Plain items omit all three. **`aria-haspopup`** is the generic **`true`** (disclosure), not **`menu`** — the panel (**`xpl-top-nav-menu`**) is a **`role=\"list\"`** of link rows navigated by **Tab**, not an ARIA menu with arrow-key roving.\n- **Menu row:** The same component reused inside **`xpl-nav-header-menu`** / **`xpl-top-nav-menu`** — add **`description`** for a two-line row, and **`slot=\"trailing-icon\"`** for a functional icon (e.g. `external-link` for \"opens in new window\").\n- **Open API:** **`open`** (controlled/uncontrolled, reflected) + **`openChange`** event + **`openMenu()`** / **`closeMenu()`** / **`toggleMenu()`** methods — all equivalent ways to drive the dropdown panel.\n- **`openMode`:** **`click`** (default) or **`hover`** — hover only activates on hover-capable, fine-pointer, **`md`**-and-up devices; keyboard (Enter/Space) always toggles regardless.\n- **One open dropdown:** Outside click uses **`ownerDocument`** capture; siblings close via internal **`CustomEvent`** (reliable with JSDOM / **`stopPropagation`**).\n- **Escape:** Document **capture** **`keydown`** — **`preventDefault`** / **`stopPropagation`** so parent shells (**`xpl-top-nav`** mobile drawer, **`xpl-popover`**, modal) do not also react on the same keypress, then returns focus to the trigger control. **`xpl-top-nav`** closes its drawer on **Escape** in **bubble** phase, after this handler runs.\n\n## Host modifier classes (BEM)\n\n| Class | Source |\n| --- | --- |\n| **`xpl-top-nav-item--selected`** | **`selected`** prop |\n| **`xpl-top-nav-item--has-dropdown`** | **`slot=\"dropdown\"`** content present |\n| **`xpl-top-nav-item--dropdown-open`** | Dropdown panel is open (**`open`** prop) |\n| **`xpl-top-nav-item--active`** | **`active`** prop (or add the class on the host for edge cases) |\n| **`xpl-top-nav-item--has-active-descendant`** | A descendant row inside **`slot=\"dropdown\"`** is **`active`** / **`selected`** — accents the trigger like **`--active`**. Synced at connect / load / this item's own re-renders, not via a live descendant-class observer (see the JSDoc on **`hasActiveDescendant`** for why). |\n\n## Slots\n\n| Slot | Description |\n| --- | --- |\n| (default) | Custom trigger when **`label`** is omitted. |\n| `leading-icon` | Illustrative icon before the label. Overrides the **`icon`** prop when present. |\n| `trailing-icon` | Functional icon after the label. Overrides the auto **`chevron-down`** on a dropdown trigger. |\n| `dropdown` | Panel content (e.g. `<xpl-top-nav-menu>…</xpl-top-nav-menu>`). |\n",
|
|
@@ -17673,7 +17673,7 @@
|
|
|
17673
17673
|
}
|
|
17674
17674
|
},
|
|
17675
17675
|
{
|
|
17676
|
-
"filePath": "src/components/
|
|
17676
|
+
"filePath": "src/components/xpl-top-nav/xpl-top-nav-menu/xpl-top-nav-menu.tsx",
|
|
17677
17677
|
"encapsulation": "none",
|
|
17678
17678
|
"tag": "xpl-top-nav-menu",
|
|
17679
17679
|
"readme": "# xpl-top-nav-menu\n\n## Behavior\n\n- **Thin grouping container only.** No item logic lives here — put **`xpl-top-nav-item`** rows in the default slot. This component owns list semantics (**`role=\"list\"`**) and shared panel chrome (width, surface, shadow, radius, padding), nothing else.\n- **One authoring markup, two renderings:** the same **`<xpl-top-nav-menu>`** renders as the **desktop flyout** (nested in a parent **`xpl-top-nav-item`**'s **`slot=\"dropdown\"`** — the panel opens absolutely-positioned under the trigger) and, below the **`md`** breakpoint, drives the **mobile cascade**: the parent's dropdown content swaps in **in place** of the top-level nav list (no second panel), with an auto **back row** as the first row.\n- **`label`** is the accessible name for the list (**`aria-label`**) and, on mobile, the text shown in the auto-rendered back row (leading **`chevron-left`**) when drilling back out of this group. Tapping the back row calls **`closeMenu()`** on the parent trigger (pop to Level 1) and restores focus to it.\n- The back row only renders below **`md`** (synced from a **`matchMedia`** listener) — desktop never sees it, since the flyout there is a single level of links.\n- **Cascade lifecycle** (owned by **`xpl-top-nav`**, the shell): pressing **Escape** while drilled in pops the cascade before it closes the mobile drawer (two separate presses); closing the drawer via the hamburger toggle while still drilled in resets the group closed so the drawer reopens at Level 1 next time.\n\n## Usage\n\n```html\n<xpl-top-nav-item slot=\"left-aside\" label=\"Xplor Ops\" open-mode=\"hover\">\n <xpl-top-nav-menu slot=\"dropdown\" label=\"Xplor Ops\">\n <xpl-top-nav-item label=\"Payroll\" href=\"/payroll\"></xpl-top-nav-item>\n <xpl-top-nav-item label=\"Capital\" href=\"/capital\">\n <xpl-icon slot=\"trailing-icon\" icon=\"open-rect-arrow-out\"></xpl-icon>\n </xpl-top-nav-item>\n </xpl-top-nav-menu>\n</xpl-top-nav-item>\n```\n\n## Host modifier classes (BEM)\n\nNone on the host itself. Row-level state (`active`, `selected`, description, icons) lives entirely on the slotted `xpl-top-nav-item` rows.\n\n| Class | Source |\n| --- | --- |\n| `.xpl-top-nav-menu__back` | Auto-rendered on the back-row `xpl-top-nav-item` (mobile only, `label` set). Not a hook to restyle — it uses the same row treatment as any other `xpl-top-nav-item` in this list. |\n\n## Slots\n\n| Slot | Description |\n| --- | --- |\n| (default) | `xpl-top-nav-item` rows. |\n",
|
|
@@ -17742,7 +17742,7 @@
|
|
|
17742
17742
|
}
|
|
17743
17743
|
},
|
|
17744
17744
|
{
|
|
17745
|
-
"filePath": "src/components/
|
|
17745
|
+
"filePath": "src/components/xpl-utility-bar/xpl-utility-bar.tsx",
|
|
17746
17746
|
"encapsulation": "none",
|
|
17747
17747
|
"tag": "xpl-utility-bar",
|
|
17748
17748
|
"readme": "# xpl-utility-bar\n\nThe utility bar is a top navigation bar. It contains 2 slots:\n\n`<slot name=\"main\"></slot>`\n\n- appears on the left side of the bar\n- items are justified to the start\n\n`<slot name=\"aside\"></slot>`\n\n- appears on the right side of the bar\n- items are justified to the end\n\nThe utility bar can have navigation items in just one or both slots.\nTo add content to the slots, just create a `<ul>` tag and target the desired slot:\n\n`<ul slot=\"main\">...</ul>`\n\n`<ul slot=\"aside\">...</ul>`\n\n## Design Tokens\n\nThe utility bar uses Apollo Foundation purpose-specific tokens, which theme automatically in light and dark mode (no `.dark` overrides).\n\n| Element | Property | Token |\n| --- | --- | --- |\n| `.xpl-utility-bar` | `background-color` | `--xpl-background-surface-default` |\n| `.xpl-utility-bar` | `color` (muted text) | `--xpl-text-subdued` |\n| `.xpl-utility-nav__bars` | `color` (nav-control icon) | `--xpl-icon-default` |\n| `.xpl-utility-nav__bars` | `height` | `--xpl-size-100` |\n| `.xpl-utility-bar__nav-control` `:focus-visible` | `outline-color` | `--xpl-border-focus` |\n",
|
|
@@ -17868,120 +17868,120 @@
|
|
|
17868
17868
|
}
|
|
17869
17869
|
],
|
|
17870
17870
|
"typeLibrary": {
|
|
17871
|
-
"src/components/
|
|
17871
|
+
"src/components/xpl-badge/xpl-badge.tsx::BadgeVariantProp": {
|
|
17872
17872
|
"declaration": "export type BadgeVariantProp = BadgePalette | 'success' | 'warning' | 'inactive' | 'error';",
|
|
17873
17873
|
"docstring": "",
|
|
17874
|
-
"path": "src/components/
|
|
17874
|
+
"path": "src/components/xpl-badge/xpl-badge.tsx"
|
|
17875
17875
|
},
|
|
17876
|
-
"src/components/
|
|
17876
|
+
"src/components/xpl-avatar/xpl-avatar.tsx::AvatarColor": {
|
|
17877
17877
|
"declaration": "export type AvatarColor = 'green' | 'yellow' | 'pink' | 'primary' | 'secondary';",
|
|
17878
17878
|
"docstring": "",
|
|
17879
|
-
"path": "src/components/
|
|
17879
|
+
"path": "src/components/xpl-avatar/xpl-avatar.tsx"
|
|
17880
17880
|
},
|
|
17881
|
-
"src/components/
|
|
17881
|
+
"src/components/xpl-avatar/xpl-avatar.tsx::AvatarGroupItem": {
|
|
17882
17882
|
"declaration": "export interface AvatarGroupItem {\n /** Image URL for this avatar */\n src?: string;\n /** Name used for alt text and initials when no src */\n name?: string;\n /** Placeholder background color when there is no image */\n color?: AvatarColor;\n}",
|
|
17883
17883
|
"docstring": "",
|
|
17884
|
-
"path": "src/components/
|
|
17884
|
+
"path": "src/components/xpl-avatar/xpl-avatar.tsx"
|
|
17885
17885
|
},
|
|
17886
|
-
"src/components/
|
|
17886
|
+
"src/components/xpl-avatar/xpl-avatar.tsx::AvatarStatus": {
|
|
17887
17887
|
"declaration": "export type AvatarStatus = 'active' | 'inactive' | 'warning' | BadgePalette;",
|
|
17888
17888
|
"docstring": "",
|
|
17889
|
-
"path": "src/components/
|
|
17889
|
+
"path": "src/components/xpl-avatar/xpl-avatar.tsx"
|
|
17890
17890
|
},
|
|
17891
|
-
"src/components/
|
|
17891
|
+
"src/components/xpl-avatar/xpl-avatar.tsx::AvatarVariant": {
|
|
17892
17892
|
"declaration": "export type AvatarVariant = 'profile' | 'group' | 'with-text';",
|
|
17893
17893
|
"docstring": "",
|
|
17894
|
-
"path": "src/components/
|
|
17894
|
+
"path": "src/components/xpl-avatar/xpl-avatar.tsx"
|
|
17895
17895
|
},
|
|
17896
|
-
"src/components/
|
|
17896
|
+
"src/components/xpl-choicelist/choice.ts::Choice": {
|
|
17897
17897
|
"declaration": "export interface Choice {\n checked?: boolean;\n children?: Choice[];\n description?: string;\n label?: string;\n value?: string;\n}",
|
|
17898
17898
|
"docstring": "",
|
|
17899
|
-
"path": "src/components/
|
|
17899
|
+
"path": "src/components/xpl-choicelist/choice.ts"
|
|
17900
17900
|
},
|
|
17901
|
-
"src/components/
|
|
17901
|
+
"src/components/xpl-dropdown/dropdown-option.ts::DropdownItem": {
|
|
17902
17902
|
"declaration": "{\n [P in keyof T]?: T[P];\n}",
|
|
17903
17903
|
"docstring": "",
|
|
17904
|
-
"path": "src/components/
|
|
17904
|
+
"path": "src/components/xpl-dropdown/dropdown-option.ts"
|
|
17905
17905
|
},
|
|
17906
|
-
"src/
|
|
17906
|
+
"src/utils/floating.ts::Placement": {
|
|
17907
17907
|
"declaration": "export declare type Placement = Prettify<Side | AlignedPlacement>;",
|
|
17908
17908
|
"docstring": "",
|
|
17909
|
-
"path": "src/
|
|
17909
|
+
"path": "src/utils/floating.ts"
|
|
17910
17910
|
},
|
|
17911
17911
|
"../../node_modules/@stencil/core/internal/stencil-core/index.d.ts::Event": {
|
|
17912
17912
|
"declaration": "interface Event {\n /**\n * Returns true or false depending on how event was initialized. True if event goes through its target's ancestors in reverse tree order, and false otherwise.\n *\n * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/bubbles)\n */\n readonly bubbles: boolean;\n /**\n * @deprecated\n *\n * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/cancelBubble)\n */\n cancelBubble: boolean;\n /**\n * Returns true or false depending on how event was initialized. Its return value does not always carry meaning, but true can indicate that part of the operation during which event was dispatched, can be canceled by invoking the preventDefault() method.\n *\n * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/cancelable)\n */\n readonly cancelable: boolean;\n /**\n * Returns true or false depending on how event was initialized. True if event invokes listeners past a ShadowRoot node that is the root of its target, and false otherwise.\n *\n * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/composed)\n */\n readonly composed: boolean;\n /**\n * Returns the object whose event listener's callback is currently being invoked.\n *\n * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/currentTarget)\n */\n readonly currentTarget: EventTarget | null;\n /**\n * Returns true if preventDefault() was invoked successfully to indicate cancelation, and false otherwise.\n *\n * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/defaultPrevented)\n */\n readonly defaultPrevented: boolean;\n /**\n * Returns the event's phase, which is one of NONE, CAPTURING_PHASE, AT_TARGET, and BUBBLING_PHASE.\n *\n * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/eventPhase)\n */\n readonly eventPhase: number;\n /**\n * Returns true if event was dispatched by the user agent, and false otherwise.\n *\n * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/isTrusted)\n */\n readonly isTrusted: boolean;\n /**\n * @deprecated\n *\n * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/returnValue)\n */\n returnValue: boolean;\n /**\n * @deprecated\n *\n * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/srcElement)\n */\n readonly srcElement: EventTarget | null;\n /**\n * Returns the object to which event is dispatched (its target).\n *\n * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/target)\n */\n readonly target: EventTarget | null;\n /**\n * Returns the event's timestamp as the number of milliseconds measured relative to the time origin.\n *\n * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/timeStamp)\n */\n readonly timeStamp: DOMHighResTimeStamp;\n /**\n * Returns the type of event, e.g. \"click\", \"hashchange\", or \"submit\".\n *\n * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/type)\n */\n readonly type: string;\n /**\n * Returns the invocation target objects of event's path (objects on which listeners will be invoked), except for any nodes in shadow trees of which the shadow root's mode is \"closed\" that are not reachable from event's currentTarget.\n *\n * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/composedPath)\n */\n composedPath(): EventTarget[];\n /**\n * @deprecated\n *\n * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/initEvent)\n */\n initEvent(type: string, bubbles?: boolean, cancelable?: boolean): void;\n /**\n * If invoked when the cancelable attribute value is true, and while executing a listener for the event with passive set to false, signals to the operation that caused event to be dispatched that it needs to be canceled.\n *\n * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/preventDefault)\n */\n preventDefault(): void;\n /**\n * Invoking this method prevents event from reaching any registered event listeners after the current one finishes running and, when dispatched in a tree, also prevents event from reaching any other objects.\n *\n * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/stopImmediatePropagation)\n */\n stopImmediatePropagation(): void;\n /**\n * When dispatched in a tree, invoking this method prevents event from reaching any objects other than the current object.\n *\n * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Event/stopPropagation)\n */\n stopPropagation(): void;\n readonly NONE: 0;\n readonly CAPTURING_PHASE: 1;\n readonly AT_TARGET: 2;\n readonly BUBBLING_PHASE: 3;\n}",
|
|
17913
17913
|
"docstring": "An event which takes place in the DOM.\n\n[MDN Reference](https://developer.mozilla.org/docs/Web/API/Event)",
|
|
17914
17914
|
"path": "../../node_modules/@stencil/core/internal/stencil-core/index.d.ts"
|
|
17915
17915
|
},
|
|
17916
|
-
"src/components/
|
|
17916
|
+
"src/components/xpl-dropdown/xpl-dropdown.tsx::Dropdown": {
|
|
17917
17917
|
"declaration": "@Component({ tag: 'xpl-dropdown' })\nexport class Dropdown {\n /** Exclusive last rendered option index when virtual scrolling is active. */\n @State() private virtualEnd = 0;\n\n /** First rendered option index when virtual scrolling is active. */\n @State() private virtualStart = 0;\n\n /** text to display as heading */\n @Prop({ attribute: 'open', mutable: true, reflect: true }) isOpen = false;\n\n /** options that are listed */\n @Prop() closeOnSelect = true;\n\n /** constant representing number of options that can be selected */\n @Prop() mode: 'single' | 'multi' = 'single';\n\n /** options that are listed */\n @Prop({ mutable: true }) options?: DropdownItem[];\n\n @Watch('options')\n onOptionsChanged() {\n // A selection toggle reassigns `options` with the same length (only\n // `isSelected` flips), whereas a genuinely new dataset changes the\n // count. Track it so only real list replacements recenter — in-place\n // selection updates must never move the user's scroll position (in\n // multi mode that could otherwise jump to the first selected row via\n // `findIndex`).\n const total = this.options?.length ?? 0;\n const listReplaced = total !== this.previousOptionCount;\n this.previousOptionCount = total;\n\n // When the list shrinks, cached range/scroll can point past the new\n // end (render would clamp `start` to `total` and slice to empty, or\n // leave a high scroll offset showing blank space). Reset for\n // non-virtualized lists and otherwise clamp scroll + recompute range.\n if (!this.isVirtualized) {\n this.virtualStart = 0;\n this.virtualEnd = 0;\n return;\n }\n\n const list = this.listEl;\n if (list) {\n const maxScroll = Math.max(0, total * VIRTUAL_LIST.rowHeight - list.clientHeight);\n if (list.scrollTop > maxScroll) {\n list.scrollTop = maxScroll;\n }\n\n // If the menu is open and a newly assigned list left the selected\n // row outside the current window (e.g. a large list assigned\n // asynchronously leaves scrollTop at 0), recenter so the selected\n // option is mounted. Gated on `listReplaced` so selection toggles\n // never trigger it.\n if (this.isOpen && listReplaced) {\n const selectedIndex = this.options?.findIndex((option) => option.isSelected) ?? -1;\n const outOfWindow =\n selectedIndex >= 0 &&\n (selectedIndex < this.virtualStart || selectedIndex >= this.virtualEnd);\n if (outOfWindow) {\n this.scrollSelectedIntoView();\n }\n }\n }\n\n this.updateVirtualRange();\n }\n\n /** whether to anchor the dropdown to the trigger element, requires triggerId to be set */\n @Prop() anchorToTrigger = false;\n\n @Watch('anchorToTrigger')\n onAnchorToTriggerChanged() {\n if (this.isOpen) {\n this.startPositioning();\n }\n }\n\n /**\n * When `anchorToTrigger` is true, additional placements to try when the\n * default `placement` does not fit (passed to Floating UI `flip`).\n */\n @Prop() flipFallbackPlacements?: Placement[];\n\n @Watch('flipFallbackPlacements')\n onFlipFallbackPlacementsChanged() {\n if (this.isOpen && this.anchorToTrigger) {\n this.startPositioning();\n }\n }\n\n /**\n * Floating UI placement when `anchorToTrigger` is true (e.g. `bottom-start`, `top-start`).\n */\n @Prop() placement: Placement = 'bottom-start';\n\n @Watch('placement')\n onPlacementChanged() {\n if (this.isOpen && this.anchorToTrigger) {\n this.startPositioning();\n }\n }\n\n /**\n * The currently selected value(s) in the dropdown.\n */\n @Prop() selectedValues?: string | string[];\n\n /** whether selection should be made when focusing on interactive element */\n @Prop() selectOnFocus = false;\n\n /** the id for the element that triggers the open state */\n @Prop() triggerId: string;\n\n @Watch('triggerId')\n onTriggerIdChanged() {\n if (this.isOpen) {\n this.startPositioning();\n }\n }\n\n /**\n * @callback update\n * @param {Object} e - event object\n * @param {Object} options - component\n */\n /** call back function invoked when a selection is made */\n @Prop() update?: (e: Event | null, context: { component: Dropdown }) => void;\n\n @Element() hostElement: HTMLXplDropdownElement;\n\n /** Emitted when the open state of the dropdown changes. */\n @Event() isOpenChange: EventEmitter<boolean>;\n\n private floating: FloatingController | null = null;\n\n private virtualScrollRaf: number | null = null;\n\n private openAlignmentRaf: number | null = null;\n\n private listEl?: HTMLElement;\n\n private listResizeObserver?: ResizeObserver;\n\n private previousOptionCount = 0;\n\n @Watch('selectedValues')\n onSelectedValuesChanged(newValues: string | string[], initialRender = false) {\n if (this.options && this.options.length > 0) {\n // Flatten options to handle both grouped and individual options\n const flatOptions = this.options.flatMap((curr) =>\n curr.groupName && curr.options ? curr.options : [curr],\n );\n\n // Update isSelected flags based on new selected values\n flatOptions.forEach((option) => {\n const optionValue = option.value || option.label || '';\n\n if (this.mode === 'single') {\n option.isSelected = optionValue === newValues;\n } else {\n const selectedArray = Array.isArray(newValues) ? newValues : [];\n option.isSelected = selectedArray.includes(optionValue);\n }\n });\n\n // Update the options array to trigger re-render\n const mapOptions = (option: DropdownItem): DropdownItem => {\n option.options = option.groupName ? option.options?.map(mapOptions) : undefined;\n return option;\n };\n this.options = this.options.map(mapOptions);\n\n // Call update callback if it exists\n if (this.update && !initialRender) {\n this.update(null, { component: this });\n }\n }\n }\n\n @Watch('isOpen')\n onIsOpenStateChange(newValue: boolean) {\n this.isOpenChange.emit(newValue);\n if (newValue) {\n this.startPositioning();\n this.alignOnOpen();\n } else {\n this.stopPositioning();\n this.cancelVirtualScroll();\n this.virtualStart = 0;\n this.virtualEnd = 0;\n }\n }\n\n connectedCallback() {\n if (!isBrowser()) {\n return;\n }\n\n document.addEventListener('mousedown', this.handleClickOutside);\n document.addEventListener('keydown', this.handleKeyDown);\n }\n\n disconnectedCallback() {\n document.removeEventListener('mousedown', this.handleClickOutside);\n document.removeEventListener('keydown', this.handleKeyDown);\n this.stopPositioning();\n this.cancelVirtualScroll();\n this.listResizeObserver?.disconnect();\n }\n\n componentWillLoad() {\n this.handleSelect = this.handleSelect.bind(this);\n if (this.selectedValues) {\n this.onSelectedValuesChanged(this.selectedValues, true);\n }\n // Seed the baseline so the first in-place selection change isn't\n // mistaken for a list replacement.\n this.previousOptionCount = this.options?.length ?? 0;\n }\n\n componentDidLoad() {\n if (this.isOpen) {\n // The `isOpen` watcher does not fire for an initial `open` attribute,\n // so align here too once the list has rendered.\n this.startPositioning();\n this.alignOnOpen();\n }\n }\n\n /**\n * called on dropdown option click and keydown events to update isSelected states\n */\n @Method()\n async handleSelect(e: Event | null, { component }: DropdownSelectContext): Promise<void> {\n const { hostElement, mode, options, update } = this;\n const isSingle = mode === 'single';\n const isMulti = mode === 'multi';\n\n if (options) {\n const targetValue = component.hostElement.value || component.hostElement.label;\n const hasGroups = options.some((option) => option.groupName);\n\n if (!hasGroups) {\n // Fast path for flat lists (e.g. very large selects): a single\n // linear pass plus a shallow copy to trigger the re-render,\n // instead of flatten + forEach + map over every option.\n options.forEach((option) => {\n const isMatch = (option.value || option.label) === targetValue;\n if (isSingle) {\n option.isSelected = isMatch;\n if (isMatch) component.hostElement.isSelected = true;\n } else if (isMulti && isMatch) {\n option.isSelected = !option.isSelected;\n component.hostElement.isSelected = option.isSelected;\n }\n });\n this.options = [...options];\n } else {\n const flatOptions = options.flatMap((curr) =>\n curr.groupName && curr.options ? curr.options : [curr],\n );\n\n flatOptions.forEach((option) => {\n const isMatch = (option.value || option.label) === targetValue;\n if (isSingle) {\n option.isSelected = isMatch;\n component.hostElement.isSelected = true;\n } else if (isMulti && isMatch) {\n option.isSelected = !option.isSelected;\n component.hostElement.isSelected = option.isSelected;\n }\n });\n\n const mapOptions = (option: DropdownItem): DropdownItem => {\n option.options = option.groupName ? option.options?.map(mapOptions) : undefined;\n return option;\n };\n this.options = options.map(mapOptions);\n }\n } else if (isSingle) {\n const optionNodes = Array.from(\n hostElement.querySelectorAll<HTMLXplDropdownOptionElement>('xpl-dropdown-option'),\n );\n optionNodes.forEach((node) => {\n node.isSelected = node === component.hostElement;\n });\n } else if (isMulti) {\n component.isSelected = !component.isSelected;\n }\n\n if (update) update(e, { component: this });\n }\n\n private startPositioning() {\n if (!this.anchorToTrigger || !this.triggerId) {\n return;\n }\n\n const triggerEl = document.getElementById(this.triggerId);\n if (!triggerEl) return;\n\n this.stopPositioning();\n\n this.floating = startFloating(triggerEl, this.hostElement, {\n placement: this.placement,\n strategy: 'fixed',\n middleware: dropdownMiddleware({\n flipFallbackPlacements: this.flipFallbackPlacements,\n sizeApply: ({ availableHeight, rects }) => {\n const listEl =\n this.hostElement.querySelector<HTMLElement>('.xpl-dropdown-list');\n let usedBeforeList = 0;\n if (listEl) {\n const children = Array.from(this.hostElement.children);\n const listIndex = children.indexOf(listEl);\n children.slice(0, listIndex).forEach((child) => {\n if (child instanceof HTMLElement) {\n usedBeforeList += child.offsetHeight;\n }\n });\n }\n const cs = getComputedStyle(this.hostElement);\n const hostVerticalChrome =\n parseFloat(cs.paddingTop) +\n parseFloat(cs.paddingBottom) +\n parseFloat(cs.borderTopWidth) +\n parseFloat(cs.borderBottomWidth);\n const cssMaxHeight = listEl\n ? parseFloat(\n getComputedStyle(listEl).getPropertyValue(\n '--xpl-dropdown-list-max-height',\n ),\n )\n : Infinity;\n const listMaxHeight = Math.min(\n cssMaxHeight,\n Math.max(0, availableHeight - usedBeforeList - hostVerticalChrome),\n );\n Object.assign(this.hostElement.style, {\n width: `${rects.reference.width}px`,\n });\n if (listEl) {\n listEl.style.maxHeight = `${listMaxHeight}px`;\n }\n },\n }),\n onPosition: ({ x, y, placement: resolvedPlacement }) => {\n if (!this.floating) {\n return;\n }\n\n const isAbove = getSide(resolvedPlacement) === 'top';\n\n Object.assign(this.hostElement.style, {\n left: `${x}px`,\n top: `${y}px`,\n });\n\n this.hostElement.classList.toggle('xpl-dropdown--above', isAbove);\n this.hostElement.classList.toggle('xpl-dropdown--below', !isAbove);\n },\n onReferenceHidden: () => {\n this.isOpen = false;\n return true;\n },\n });\n }\n\n private stopPositioning() {\n this.floating?.stop();\n this.floating = null;\n\n this.hostElement.style.left = '';\n this.hostElement.style.top = '';\n this.hostElement.style.width = '';\n this.hostElement\n .querySelector<HTMLElement>('.xpl-dropdown-list')\n ?.style.removeProperty('max-height');\n this.hostElement.classList.remove('xpl-dropdown--above', 'xpl-dropdown--below');\n }\n\n private handleClickOutside = ({ target }: MouseEvent): void => {\n const { triggerId } = this;\n const targetEl = target as HTMLElement | null;\n const triggerElement = triggerId ? document.getElementById(triggerId) : null;\n const isTriggerOrChild = triggerElement?.contains(targetEl);\n const isInside = this.hostElement.contains(targetEl);\n\n // A `<label for=\"{triggerId}\">` is part of the trigger: clicking it\n // forwards a synthetic click to the trigger to toggle the menu. Treating\n // its `mousedown` as an outside click would close the menu here, and the\n // forwarded click would immediately reopen it — so the label could only\n // ever open, never close. Exclude the associated label from outside detection.\n const labelEl = targetEl?.closest('label');\n const isTriggerLabel =\n !!labelEl && !!triggerId && labelEl.getAttribute('for') === triggerId;\n\n if (!isInside && !isTriggerOrChild && !isTriggerLabel && this.isOpen) {\n this.isOpen = false;\n }\n };\n\n private handleKeyDown = (e: KeyboardEvent) => {\n if (e.key === 'Escape' && this.isOpen) {\n this.isOpen = false;\n }\n };\n\n /**\n * Recomputes the rendered range from the scroll position. Throttled to one\n * update per animation frame.\n */\n private handleVirtualScroll = () => {\n if (this.virtualScrollRaf !== null) return;\n\n this.virtualScrollRaf = requestAnimationFrame(() => {\n this.virtualScrollRaf = null;\n this.updateVirtualRange();\n });\n };\n\n private cancelVirtualScroll() {\n if (this.virtualScrollRaf !== null) {\n cancelAnimationFrame(this.virtualScrollRaf);\n this.virtualScrollRaf = null;\n }\n if (this.openAlignmentRaf !== null) {\n cancelAnimationFrame(this.openAlignmentRaf);\n this.openAlignmentRaf = null;\n }\n }\n\n /**\n * Tracks the list element and observes its size. Floating UI's `size`\n * middleware (and viewport/layout changes) can grow or shrink the list\n * `clientHeight` without firing a scroll event, which would otherwise\n * leave a stale visible range until the user scrolls. Recompute the range\n * (throttled via the tracked scroll scheduler) whenever the list resizes.\n */\n private setListEl = (el?: HTMLElement) => {\n if (el === this.listEl) return;\n\n this.listEl = el;\n this.listResizeObserver?.disconnect();\n\n if (el && typeof ResizeObserver !== 'undefined') {\n this.listResizeObserver ??= new ResizeObserver(() => {\n if (this.isVirtualized) this.handleVirtualScroll();\n });\n this.listResizeObserver.observe(el);\n }\n };\n\n /**\n * Align the virtualized viewport to the selected option when the menu\n * opens. Shared by the `isOpen` watcher and `componentDidLoad` (the watcher\n * does not fire for an initial `open` attribute).\n */\n private alignOnOpen() {\n // Align synchronously so the first paint already renders the window\n // around the selected option. The list is always in the DOM with its\n // CSS max-height applied, so the scroll math is correct for\n // non-anchored lists and a close approximation for anchored ones.\n this.scrollSelectedIntoView();\n this.updateVirtualRange();\n // Re-align after layout, once the size middleware has set the final\n // list height. Routed through the tracked scroll scheduler so the frame\n // is cancelled on close/teardown.\n this.scheduleOpenAlignment();\n }\n\n /**\n * On open, align the viewport to the selected option (once the list has\n * been laid out) and recompute the rendered range. Uses its own tracked\n * frame (not the scroll slot) so the synchronous scroll fired by\n * `scrollSelectedIntoView` cannot let `handleVirtualScroll` preempt it and\n * skip the post-layout centering. Cancelled on close/teardown.\n */\n private scheduleOpenAlignment = () => {\n if (this.openAlignmentRaf !== null) return;\n\n this.openAlignmentRaf = requestAnimationFrame(() => {\n this.openAlignmentRaf = null;\n this.scrollSelectedIntoView();\n this.updateVirtualRange();\n });\n };\n\n /**\n * Scrolls the virtualized list so the selected option is centered in the\n * viewport. No-op for non-virtualized lists (their rows have natural\n * heights and the browser handles visibility).\n */\n private scrollSelectedIntoView() {\n const { listEl: list, options } = this;\n\n if (!list || !options?.length || !this.isVirtualized) return;\n\n const selectedIndex = options.findIndex((option) => option.isSelected);\n if (selectedIndex < 0) return;\n\n const { rowHeight } = VIRTUAL_LIST;\n const centered = selectedIndex * rowHeight - (list.clientHeight - rowHeight) / 2;\n const maxScroll = Math.max(0, options.length * rowHeight - list.clientHeight);\n\n list.scrollTop = Math.max(0, Math.min(centered, maxScroll));\n }\n\n private updateVirtualRange() {\n const list = this.listEl;\n const total = this.options?.length ?? 0;\n\n if (!list || !total) return;\n\n const { rowHeight, overscan } = VIRTUAL_LIST;\n const firstVisible = Math.floor(list.scrollTop / rowHeight);\n const visibleCount = Math.ceil(list.clientHeight / rowHeight) || 1;\n\n const start = Math.max(0, firstVisible - overscan);\n const end = Math.min(total, firstVisible + visibleCount + overscan);\n\n if (start !== this.virtualStart || end !== this.virtualEnd) {\n this.virtualStart = start;\n this.virtualEnd = end;\n }\n }\n\n private get isVirtualized(): boolean {\n const { options } = this;\n\n return (\n !!options &&\n options.length > VIRTUAL_LIST.virtualizeFrom &&\n // Virtualized rows use a fixed `rowHeight` with `overflow: hidden`,\n // which would silently clip subtitles. Exclude grouped and\n // subtitled lists so they keep their natural row height.\n options.every((option) => !option.groupName && !option.subtitle)\n );\n }\n\n render() {\n const { isOpen, mode, options } = this;\n\n const hasOptions = !!(options && options.length);\n const shouldVirtualize = this.isVirtualized;\n\n let listContent;\n if (!hasOptions) {\n listContent = <slot name=\"options\"></slot>;\n } else if (shouldVirtualize) {\n const { rowHeight, overscan } = VIRTUAL_LIST;\n const total = options.length;\n const start = Math.min(this.virtualStart, total);\n\n // Fall back to a sensible window before the list has been measured\n // (e.g. the very first render right after opening).\n const fallbackEnd = Math.min(total, Math.ceil(300 / rowHeight) + overscan * 2);\n const end = this.virtualEnd > start ? this.virtualEnd : fallbackEnd;\n\n listContent = (\n <li\n class=\"xpl-dropdown__virtual-sizer\"\n style={{ height: `${total * rowHeight}px` }}\n >\n {options.slice(start, end).map((option, i) => renderOption(option, start + i))}\n </li>\n );\n } else {\n listContent = options.map((option) => renderOption(option));\n }\n\n return (\n <Host\n aria-expanded={isOpen ? 'true' : 'false'}\n class={{\n 'xpl-dropdown': true,\n 'xpl-dropdown--multi': mode === 'multi',\n 'xpl-dropdown--open': isOpen,\n 'xpl-dropdown--anchor-to-trigger': this.anchorToTrigger,\n 'xpl-dropdown--virtualized': shouldVirtualize,\n }}\n role=\"listbox\"\n >\n <slot name=\"header\"></slot>\n <ul\n class=\"xpl-dropdown-list\"\n ref={(el) => {\n this.setListEl(el);\n }}\n onScroll={shouldVirtualize ? this.handleVirtualScroll : undefined}\n >\n {listContent}\n </ul>\n </Host>\n );\n }\n}",
|
|
17918
17918
|
"docstring": "",
|
|
17919
|
-
"path": "src/components/
|
|
17919
|
+
"path": "src/components/xpl-dropdown/xpl-dropdown.tsx"
|
|
17920
17920
|
},
|
|
17921
|
-
"src/components/
|
|
17921
|
+
"src/components/xpl-dropdown/dropdown-option.ts::DropdownOptionGroup": {
|
|
17922
17922
|
"declaration": "export interface DropdownOptionGroup {\n groupName: string;\n options: DropdownItem[];\n}",
|
|
17923
17923
|
"docstring": "",
|
|
17924
|
-
"path": "src/components/
|
|
17924
|
+
"path": "src/components/xpl-dropdown/dropdown-option.ts"
|
|
17925
17925
|
},
|
|
17926
|
-
"src/components/
|
|
17926
|
+
"src/components/xpl-list/listitem.ts::ListItem": {
|
|
17927
17927
|
"declaration": "export interface ListItem {\n /** Optional stable id for legacy rows (keys and `item-id` when rendering from `items`). */\n id?: string;\n avatar?: string;\n avatars?: string[];\n badges?:\n | string[]\n | {\n dot?: boolean;\n text: string;\n variant?: string;\n }[];\n href?: string;\n title: string;\n metadata?:\n | string[]\n | {\n icon: string;\n text: string;\n }[];\n subtext?: string;\n}",
|
|
17928
17928
|
"docstring": "",
|
|
17929
|
-
"path": "src/components/
|
|
17929
|
+
"path": "src/components/xpl-list/listitem.ts"
|
|
17930
17930
|
},
|
|
17931
|
-
"src/components/
|
|
17931
|
+
"src/components/xpl-list/listitem.ts::XplListOrderChangeDetail": {
|
|
17932
17932
|
"declaration": "export interface XplListOrderChangeDetail {\n /** Identifier of the item that was moved. */\n itemId?: string;\n /** Direction of the move. */\n direction: 'up' | 'down';\n /**\n * Visible row IDs in DOM order after reorder. Hidden `xpl-list-item` rows are omitted.\n */\n orderedItemIds: string[];\n}",
|
|
17933
17933
|
"docstring": "Payload for the `orderChange` event on `xpl-list`.",
|
|
17934
|
-
"path": "src/components/
|
|
17934
|
+
"path": "src/components/xpl-list/listitem.ts"
|
|
17935
17935
|
},
|
|
17936
|
-
"src/components/
|
|
17936
|
+
"src/components/xpl-popover/xpl-popover.tsx::PopoverPosition": {
|
|
17937
17937
|
"declaration": "export type PopoverPosition =\n | 'top-left'\n | 'middle-left'\n | 'bottom-left'\n | 'top-right'\n | 'middle-right'\n | 'bottom-right'\n | 'top-start'\n | 'top-middle'\n | 'top-end'\n | 'bottom-start'\n | 'bottom-middle'\n | 'bottom-end';",
|
|
17938
17938
|
"docstring": "",
|
|
17939
|
-
"path": "src/components/
|
|
17939
|
+
"path": "src/components/xpl-popover/xpl-popover.tsx"
|
|
17940
17940
|
},
|
|
17941
17941
|
"../../node_modules/@floating-ui/dom/dist/floating-ui.dom.d.mts::Placement": {
|
|
17942
17942
|
"declaration": "export declare type Placement = Prettify<Side | AlignedPlacement>;",
|
|
17943
17943
|
"docstring": "",
|
|
17944
17944
|
"path": "../../node_modules/@floating-ui/dom/dist/floating-ui.dom.d.mts"
|
|
17945
17945
|
},
|
|
17946
|
-
"src/components/
|
|
17946
|
+
"src/components/xpl-spotlight/xpl-spotlight.tsx::SpotlightActionLayout": {
|
|
17947
17947
|
"declaration": "export type SpotlightActionLayout = 'default' | 'dual' | 'single';",
|
|
17948
17948
|
"docstring": "",
|
|
17949
|
-
"path": "src/components/
|
|
17949
|
+
"path": "src/components/xpl-spotlight/xpl-spotlight.tsx"
|
|
17950
17950
|
},
|
|
17951
|
-
"src/components/
|
|
17951
|
+
"src/components/xpl-spotlight/xpl-spotlight.tsx::SpotlightAnchorPosition": {
|
|
17952
17952
|
"declaration": "export type SpotlightAnchorPosition = 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';",
|
|
17953
17953
|
"docstring": "",
|
|
17954
|
-
"path": "src/components/
|
|
17954
|
+
"path": "src/components/xpl-spotlight/xpl-spotlight.tsx"
|
|
17955
17955
|
},
|
|
17956
|
-
"src/components/
|
|
17956
|
+
"src/components/xpl-badge/xpl-badge.tsx::BadgePalette": {
|
|
17957
17957
|
"declaration": "export type BadgePalette = 'purple' | 'green' | 'yellow' | 'orange' | 'gray' | 'red' | 'blue';",
|
|
17958
17958
|
"docstring": "",
|
|
17959
|
-
"path": "src/components/
|
|
17959
|
+
"path": "src/components/xpl-badge/xpl-badge.tsx"
|
|
17960
17960
|
},
|
|
17961
|
-
"src/components/
|
|
17961
|
+
"src/components/xpl-table/xpl-table.tsx::XplTableRowOrderChangeDetail": {
|
|
17962
17962
|
"declaration": "export interface XplTableRowOrderChangeDetail {\n /** Stable id of the moved row (`row-id`). */\n rowId: string;\n direction: 'up' | 'down';\n /** Visible body row ids in DOM order after the move. */\n orderedRowIds: string[];\n fromIndex: number;\n toIndex: number;\n}",
|
|
17963
17963
|
"docstring": "",
|
|
17964
|
-
"path": "src/components/
|
|
17964
|
+
"path": "src/components/xpl-table/xpl-table.tsx"
|
|
17965
17965
|
},
|
|
17966
|
-
"src/components/
|
|
17966
|
+
"src/components/xpl-table/xpl-table.tsx::XplTableSortChangedDetail": {
|
|
17967
17967
|
"declaration": "export interface XplTableSortChangedDetail {\n /**\n * @deprecated Prefer slug keys on this object. Index of the column whose sort was toggled (legacy tables).\n */\n colNum?: number;\n /**\n * @deprecated Prefer slug keys. Legacy **slugified** column title for `colNum` (same rules as sort-key slugs).\n */\n colName?: string;\n /**\n * @deprecated Prefer slug keys. Per-column sort state in visual column order (`null` when unsorted / N/A).\n */\n sortTypeArr?: ('asc' | 'desc' | null)[];\n [slug: string]: 'asc' | 'desc' | null | number | string | ('asc' | 'desc' | null)[] | undefined;\n}",
|
|
17968
17968
|
"docstring": "`sortChanged` event detail: sort-key slug → direction, plus **legacy** fields for consumers that\nstill read `colNum` / `colName` / `sortTypeArr` from the data-driven table API.\n\nIndex signature allows slug keys alongside legacy properties (cannot use `Record<>` alone without conflicting\nwith `colNum`).",
|
|
17969
|
-
"path": "src/components/
|
|
17969
|
+
"path": "src/components/xpl-table/xpl-table.tsx"
|
|
17970
17970
|
},
|
|
17971
|
-
"src/components/
|
|
17971
|
+
"src/components/xpl-table/xpl-table-header-cell/xpl-table-header-cell.tsx::HeaderSortChangeDetail": {
|
|
17972
17972
|
"declaration": "export interface HeaderSortChangeDetail {\n columnIndex: number;\n sortKey: string;\n}",
|
|
17973
17973
|
"docstring": "",
|
|
17974
|
-
"path": "src/components/
|
|
17974
|
+
"path": "src/components/xpl-table/xpl-table-header-cell/xpl-table-header-cell.tsx"
|
|
17975
17975
|
},
|
|
17976
|
-
"src/components/
|
|
17976
|
+
"src/components/xpl-tag/xpl-tag.tsx::TagDragEndDetail": {
|
|
17977
17977
|
"declaration": "export interface TagDragEndDetail {\n tagId?: string;\n dropped: boolean;\n originalEvent: DragEvent;\n}",
|
|
17978
17978
|
"docstring": "Detail for drag end event",
|
|
17979
|
-
"path": "src/components/
|
|
17979
|
+
"path": "src/components/xpl-tag/xpl-tag.tsx"
|
|
17980
17980
|
},
|
|
17981
|
-
"src/components/
|
|
17981
|
+
"src/components/xpl-tag/xpl-tag.tsx::TagDragStartDetail": {
|
|
17982
17982
|
"declaration": "export interface TagDragStartDetail {\n tagId?: string;\n content: string;\n originalEvent: DragEvent;\n}",
|
|
17983
17983
|
"docstring": "Detail for drag start event",
|
|
17984
|
-
"path": "src/components/
|
|
17984
|
+
"path": "src/components/xpl-tag/xpl-tag.tsx"
|
|
17985
17985
|
}
|
|
17986
17986
|
}
|
|
17987
17987
|
}
|