@brandsync/wc 1.8.0 → 1.10.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/custom-elements.json +4493 -3458
- package/dist/brandsync-wc/brandsync-wc.esm.js +1 -1
- package/dist/brandsync-wc/{p-c4de155c.entry.js → p-0132a2d1.entry.js} +1 -1
- package/dist/brandsync-wc/{p-051d3064.entry.js → p-041776c0.entry.js} +1 -1
- package/dist/brandsync-wc/{p-a09e157f.entry.js → p-08c99a60.entry.js} +1 -1
- package/dist/brandsync-wc/{p-70f64b25.entry.js → p-18c3c22c.entry.js} +1 -1
- package/dist/brandsync-wc/p-1c3a43c7.entry.js +1 -0
- package/dist/brandsync-wc/{p-fddc7bd1.entry.js → p-1c427ffb.entry.js} +1 -1
- package/dist/brandsync-wc/p-2181378f.entry.js +1 -0
- package/dist/brandsync-wc/{p-29027559.entry.js → p-2e958566.entry.js} +1 -1
- package/dist/brandsync-wc/{p-235ae012.entry.js → p-301b2455.entry.js} +1 -1
- package/dist/brandsync-wc/{p-8ee0153b.entry.js → p-32cd69f1.entry.js} +1 -1
- package/dist/brandsync-wc/p-4f2c4929.entry.js +1 -0
- package/dist/brandsync-wc/{p-a0d5a620.entry.js → p-50a251a4.entry.js} +1 -1
- package/dist/brandsync-wc/{p-0e39b9cc.entry.js → p-5f3cd501.entry.js} +1 -1
- package/dist/brandsync-wc/p-701ebf4a.entry.js +1 -0
- package/dist/brandsync-wc/p-763876f5.entry.js +1 -0
- package/dist/brandsync-wc/{p-f7d47c17.entry.js → p-76e1c295.entry.js} +1 -1
- package/dist/brandsync-wc/p-790db8b3.entry.js +1 -0
- package/dist/brandsync-wc/{p-4e5dcaff.entry.js → p-796a1860.entry.js} +1 -1
- package/dist/brandsync-wc/p-806a5347.entry.js +1 -0
- package/dist/brandsync-wc/{p-6331de9c.entry.js → p-8eba7f90.entry.js} +1 -1
- package/dist/brandsync-wc/p-96ed9386.entry.js +1 -0
- package/dist/brandsync-wc/{p-cfcf3f0a.entry.js → p-9e88f19c.entry.js} +1 -1
- package/dist/brandsync-wc/p-9f6fe37d.entry.js +1 -0
- package/dist/brandsync-wc/{p-de7c946d.entry.js → p-a71d2811.entry.js} +1 -1
- package/dist/brandsync-wc/{p-33e44094.entry.js → p-a8e2a829.entry.js} +1 -1
- package/dist/brandsync-wc/p-addfa0a0.entry.js +1 -0
- package/dist/brandsync-wc/{p-4574a707.entry.js → p-af2bf957.entry.js} +1 -1
- package/dist/brandsync-wc/{p-6bf2f116.entry.js → p-b2074a32.entry.js} +1 -1
- package/dist/brandsync-wc/{p-03b08508.entry.js → p-c3f72584.entry.js} +1 -1
- package/dist/brandsync-wc/{p-7c94e6ae.entry.js → p-c99b6a66.entry.js} +1 -1
- package/dist/brandsync-wc/{p-2891d40b.entry.js → p-c9a72416.entry.js} +1 -1
- package/dist/brandsync-wc/{p-9f65f998.entry.js → p-d3f44cb7.entry.js} +1 -1
- package/dist/brandsync-wc/p-d42b1c2b.entry.js +1 -0
- package/dist/brandsync-wc/{p-3ec74d35.entry.js → p-daab6b22.entry.js} +1 -1
- package/dist/brandsync-wc/{p-ee7da23d.entry.js → p-dbcbe682.entry.js} +1 -1
- package/dist/brandsync-wc/{p-3176d1d3.entry.js → p-e8a5b8eb.entry.js} +1 -1
- package/dist/brandsync-wc/{p-062cfa34.entry.js → p-ea4e20ef.entry.js} +1 -1
- package/dist/brandsync-wc/p-f370b8fa.entry.js +1 -0
- package/dist/brandsync-wc/{p-05c7de28.entry.js → p-f89de457.entry.js} +1 -1
- package/dist/brandsync-wc/{p-114d2fd8.entry.js → p-fd254972.entry.js} +1 -1
- package/dist/cjs/brandsync-wc.cjs.js +1 -1
- package/dist/cjs/bs-ai-disclaimer.cjs.entry.js +1 -1
- package/dist/cjs/bs-ai-greeting.cjs.entry.js +1 -1
- package/dist/cjs/bs-ai-thinking.cjs.entry.js +1 -1
- package/dist/cjs/bs-attachment-list.cjs.entry.js +1 -1
- package/dist/cjs/bs-breadcrumb-overflow.cjs.entry.js +13 -1
- package/dist/cjs/bs-breadcrumb.cjs.entry.js +15 -1
- package/dist/cjs/bs-breadcrumbs.cjs.entry.js +1 -1
- package/dist/cjs/bs-button-skeleton.cjs.entry.js +1 -1
- package/dist/cjs/bs-chatbot-feedback.cjs.entry.js +1 -1
- package/dist/cjs/bs-chatbot-header.cjs.entry.js +1 -1
- package/dist/cjs/bs-chatbot-response-action.cjs.entry.js +1 -1
- package/dist/cjs/bs-chatbot-sources-drawer.cjs.entry.js +1 -1
- package/dist/cjs/bs-chatbot-suggestion-button.cjs.entry.js +1 -1
- package/dist/cjs/bs-checkbox-skeleton.cjs.entry.js +1 -1
- package/dist/cjs/bs-data-table.cjs.entry.js +18 -4
- package/dist/cjs/bs-datepicker.cjs.entry.js +410 -0
- package/dist/cjs/bs-file-upload-item.cjs.entry.js +1 -1
- package/dist/cjs/bs-file-upload.cjs.entry.js +1 -1
- package/dist/cjs/bs-icon-button.cjs.entry.js +2 -2
- package/dist/cjs/bs-inline-tab.cjs.entry.js +5 -1
- package/dist/cjs/{bs-input.cjs.entry.js → bs-input_2.cjs.entry.js} +37 -4
- package/dist/cjs/bs-menu.cjs.entry.js +1 -1
- package/dist/cjs/bs-navigation-drawer-item.cjs.entry.js +1 -1
- package/dist/cjs/bs-navigation-drawer.cjs.entry.js +118 -5
- package/dist/cjs/bs-navigation-header.cjs.entry.js +2 -2
- package/dist/cjs/bs-pagination.cjs.entry.js +1 -1
- package/dist/cjs/bs-progress-linear.cjs.entry.js +2 -2
- package/dist/cjs/bs-progress.cjs.entry.js +2 -2
- package/dist/cjs/bs-radio.cjs.entry.js +1 -1
- package/dist/cjs/bs-slider.cjs.entry.js +1 -1
- package/dist/cjs/bs-snackbar.cjs.entry.js +1 -1
- package/dist/cjs/bs-source-link.cjs.entry.js +2 -2
- package/dist/cjs/bs-stepper-step.cjs.entry.js +1 -1
- package/dist/cjs/bs-stepper.cjs.entry.js +1 -1
- package/dist/cjs/bs-switch.cjs.entry.js +1 -1
- package/dist/cjs/bs-tab.cjs.entry.js +5 -1
- package/dist/cjs/bs-tabs.cjs.entry.js +47 -2
- package/dist/cjs/bs-timepicker.cjs.entry.js +209 -0
- package/dist/cjs/bs-toast.cjs.entry.js +1 -1
- package/dist/cjs/bs-tooltip.cjs.entry.js +1 -1
- package/dist/cjs/loader.cjs.js +1 -1
- package/dist/collection/collection-manifest.json +2 -0
- package/dist/collection/components/bs-a11y.cmp.test.js +4 -0
- package/dist/collection/components/bs-ai-disclaimer/bs-ai-disclaimer.js +1 -1
- package/dist/collection/components/bs-ai-greeting/bs-ai-greeting.js +1 -1
- package/dist/collection/components/bs-ai-thinking/bs-ai-thinking.js +1 -1
- package/dist/collection/components/bs-attachment-list/bs-attachment-list.js +1 -1
- package/dist/collection/components/bs-breadcrumb/bs-breadcrumb/bs-breadcrumb.cmp.test.js +63 -0
- package/dist/collection/components/bs-breadcrumb/bs-breadcrumb/bs-breadcrumb.js +32 -1
- package/dist/collection/components/bs-breadcrumb/bs-breadcrumb-overflow/bs-breadcrumb-overflow.cmp.test.js +45 -0
- package/dist/collection/components/bs-breadcrumb/bs-breadcrumb-overflow/bs-breadcrumb-overflow.js +30 -1
- package/dist/collection/components/bs-breadcrumb/bs-breadcrumbs/bs-breadcrumbs.js +1 -1
- package/dist/collection/components/bs-button/bs-icon-button/bs-icon-button.cmp.test.js +20 -0
- package/dist/collection/components/bs-button/bs-icon-button/bs-icon-button.css +21 -4
- package/dist/collection/components/bs-button/bs-icon-button/bs-icon-button.js +3 -2
- package/dist/collection/components/bs-button/bs-icon-button/bs-icon-button.stories.js +10 -0
- package/dist/collection/components/bs-button-skeleton/bs-button-skeleton.js +1 -1
- package/dist/collection/components/bs-chatbot-feedback/bs-chatbot-feedback.js +1 -1
- package/dist/collection/components/bs-chatbot-header/bs-chatbot-header.js +1 -1
- package/dist/collection/components/bs-chatbot-response-action/bs-chatbot-response-action.js +1 -1
- package/dist/collection/components/bs-chatbot-sources-drawer/bs-chatbot-sources-drawer.js +1 -1
- package/dist/collection/components/bs-chatbot-suggestion-button/bs-chatbot-suggestion-button.js +1 -1
- package/dist/collection/components/bs-checkbox/bs-checkbox-skeleton/bs-checkbox-skeleton.js +1 -1
- package/dist/collection/components/bs-data-table/bs-data-table.cmp.test.js +19 -0
- package/dist/collection/components/bs-data-table/bs-data-table.js +19 -5
- package/dist/collection/components/bs-data-table/bs-data-table.stories.js +8 -1
- package/dist/collection/components/bs-datepicker/bs-datepicker.cmp.test.js +182 -0
- package/dist/collection/components/bs-datepicker/bs-datepicker.css +315 -0
- package/dist/collection/components/bs-datepicker/bs-datepicker.js +782 -0
- package/dist/collection/components/bs-datepicker/bs-datepicker.stories.js +63 -0
- package/dist/collection/components/bs-file-upload/bs-file-upload.js +1 -1
- package/dist/collection/components/bs-file-upload-item/bs-file-upload-item.js +1 -1
- package/dist/collection/components/bs-input/bs-input.js +7 -4
- package/dist/collection/components/bs-logo/bs-logo.cmp.test.js +52 -3
- package/dist/collection/components/bs-menu/bs-menu.js +1 -1
- package/dist/collection/components/bs-menu/bs-menu.stories.js +54 -0
- package/dist/collection/components/bs-menu-item/bs-menu-item.js +1 -1
- package/dist/collection/components/bs-pagination/bs-pagination.js +1 -1
- package/dist/collection/components/bs-progress/bs-progress.js +2 -2
- package/dist/collection/components/bs-progress-linear/bs-progress-linear.js +2 -2
- package/dist/collection/components/bs-radio/bs-radio.js +1 -1
- package/dist/collection/components/bs-slider/bs-slider.js +1 -1
- package/dist/collection/components/bs-snackbar/bs-snackbar.js +1 -1
- package/dist/collection/components/bs-source-link/bs-source-link.js +2 -2
- package/dist/collection/components/bs-stepper/bs-stepper/bs-stepper.js +1 -1
- package/dist/collection/components/bs-stepper/bs-stepper-step/bs-stepper-step.js +1 -1
- package/dist/collection/components/bs-switch/bs-switch.js +1 -1
- package/dist/collection/components/bs-tab/bs-inline-tab/bs-inline-tab.js +24 -1
- package/dist/collection/components/bs-tab/bs-tab/bs-tab.js +24 -1
- package/dist/collection/components/bs-tab/bs-tabs/bs-tabs.cmp.test.js +88 -0
- package/dist/collection/components/bs-tab/bs-tabs/bs-tabs.js +83 -2
- package/dist/collection/components/bs-tab/bs-tabs/bs-tabs.stories.js +24 -0
- package/dist/collection/components/bs-timepicker/bs-timepicker.cmp.test.js +141 -0
- package/dist/collection/components/bs-timepicker/bs-timepicker.css +200 -0
- package/dist/collection/components/bs-timepicker/bs-timepicker.js +509 -0
- package/dist/collection/components/bs-timepicker/bs-timepicker.stories.js +44 -0
- package/dist/collection/components/bs-toast/bs-toast.js +1 -1
- package/dist/collection/components/bs-tooltip/bs-tooltip.js +1 -1
- package/dist/collection/components/ui-shell/bs-navigation-drawer/bs-navigation-drawer/bs-navigation-drawer.cmp.test.js +173 -5
- package/dist/collection/components/ui-shell/bs-navigation-drawer/bs-navigation-drawer/bs-navigation-drawer.css +106 -34
- package/dist/collection/components/ui-shell/bs-navigation-drawer/bs-navigation-drawer/bs-navigation-drawer.js +181 -5
- package/dist/collection/components/ui-shell/bs-navigation-drawer/bs-navigation-drawer/bs-navigation-drawer.stories.js +48 -0
- package/dist/collection/components/ui-shell/bs-navigation-drawer/bs-navigation-drawer-item/bs-navigation-drawer-item.js +1 -1
- package/dist/collection/components/ui-shell/bs-navigation-header/bs-navigation-header/bs-navigation-header.cmp.test.js +68 -0
- package/dist/collection/components/ui-shell/bs-navigation-header/bs-navigation-header/bs-navigation-header.css +31 -17
- package/dist/collection/components/ui-shell/bs-navigation-header/bs-navigation-header/bs-navigation-header.js +1 -1
- package/dist/components/bs-ai-disclaimer.js +1 -1
- package/dist/components/bs-ai-greeting.js +1 -1
- package/dist/components/bs-ai-thinking.js +1 -1
- package/dist/components/bs-attachment-list.js +1 -1
- package/dist/components/bs-attachment.js +1 -1
- package/dist/components/bs-breadcrumb-overflow.js +1 -1
- package/dist/components/bs-breadcrumb.js +1 -1
- package/dist/components/bs-breadcrumbs.js +1 -1
- package/dist/components/bs-button-skeleton.js +1 -1
- package/dist/components/bs-carousel.js +1 -1
- package/dist/components/bs-chatbot-feedback.js +1 -1
- package/dist/components/bs-chatbot-header.js +1 -1
- package/dist/components/bs-chatbot-response-action.js +1 -1
- package/dist/components/bs-chatbot-sources-drawer.js +1 -1
- package/dist/components/bs-chatbot-suggestion-button.js +1 -1
- package/dist/components/bs-checkbox-skeleton.js +1 -1
- package/dist/components/bs-data-table.js +1 -1
- package/dist/components/bs-datepicker.d.ts +11 -0
- package/dist/components/bs-datepicker.js +1 -0
- package/dist/components/bs-dialog.js +1 -1
- package/dist/components/bs-file-upload-item.js +1 -1
- package/dist/components/bs-file-upload.js +1 -1
- package/dist/components/bs-icon-button.js +1 -1
- package/dist/components/bs-inline-tab.js +1 -1
- package/dist/components/bs-input.js +1 -1
- package/dist/components/bs-menu-item.js +1 -1
- package/dist/components/bs-menu.js +1 -1
- package/dist/components/bs-navigation-drawer-item.js +1 -1
- package/dist/components/bs-navigation-drawer.js +1 -1
- package/dist/components/bs-navigation-header.js +1 -1
- package/dist/components/bs-pagination.js +1 -1
- package/dist/components/bs-progress-linear.js +1 -1
- package/dist/components/bs-progress.js +1 -1
- package/dist/components/bs-radio.js +1 -1
- package/dist/components/bs-slider.js +1 -1
- package/dist/components/bs-snackbar.js +1 -1
- package/dist/components/bs-source-link.js +1 -1
- package/dist/components/bs-stepper-step.js +1 -1
- package/dist/components/bs-stepper.js +1 -1
- package/dist/components/bs-switch.js +1 -1
- package/dist/components/bs-tab.js +1 -1
- package/dist/components/bs-tabs.js +1 -1
- package/dist/components/bs-timepicker.d.ts +11 -0
- package/dist/components/bs-timepicker.js +1 -0
- package/dist/components/bs-toast.js +1 -1
- package/dist/components/bs-tooltip.js +1 -1
- package/dist/components/{p-BA3c9Rom.js → p-B7Icv1ho.js} +1 -1
- package/dist/components/{p-wei0Ija2.js → p-BTvme8CE.js} +1 -1
- package/dist/components/p-BYR_ZC8v.js +1 -0
- package/dist/components/p-Ba860ej1.js +1 -0
- package/dist/components/p-CPvqZNO8.js +1 -0
- package/dist/components/{p-EtXc94lJ.js → p-DkIVyFOP.js} +1 -1
- package/dist/components/{p-BfEyD6Ku.js → p-ZK8p5zax.js} +1 -1
- package/dist/components/p-jDO25SfF.js +1 -0
- package/dist/esm/brandsync-wc.js +1 -1
- package/dist/esm/bs-ai-disclaimer.entry.js +1 -1
- package/dist/esm/bs-ai-greeting.entry.js +1 -1
- package/dist/esm/bs-ai-thinking.entry.js +1 -1
- package/dist/esm/bs-attachment-list.entry.js +1 -1
- package/dist/esm/bs-breadcrumb-overflow.entry.js +14 -2
- package/dist/esm/bs-breadcrumb.entry.js +16 -2
- package/dist/esm/bs-breadcrumbs.entry.js +1 -1
- package/dist/esm/bs-button-skeleton.entry.js +1 -1
- package/dist/esm/bs-chatbot-feedback.entry.js +1 -1
- package/dist/esm/bs-chatbot-header.entry.js +1 -1
- package/dist/esm/bs-chatbot-response-action.entry.js +1 -1
- package/dist/esm/bs-chatbot-sources-drawer.entry.js +1 -1
- package/dist/esm/bs-chatbot-suggestion-button.entry.js +1 -1
- package/dist/esm/bs-checkbox-skeleton.entry.js +1 -1
- package/dist/esm/bs-data-table.entry.js +18 -4
- package/dist/esm/bs-datepicker.entry.js +408 -0
- package/dist/esm/bs-file-upload-item.entry.js +1 -1
- package/dist/esm/bs-file-upload.entry.js +1 -1
- package/dist/esm/bs-icon-button.entry.js +2 -2
- package/dist/esm/bs-inline-tab.entry.js +5 -1
- package/dist/esm/{bs-input.entry.js → bs-input_2.entry.js} +37 -5
- package/dist/esm/bs-menu.entry.js +1 -1
- package/dist/esm/bs-navigation-drawer-item.entry.js +1 -1
- package/dist/esm/bs-navigation-drawer.entry.js +119 -6
- package/dist/esm/bs-navigation-header.entry.js +2 -2
- package/dist/esm/bs-pagination.entry.js +1 -1
- package/dist/esm/bs-progress-linear.entry.js +2 -2
- package/dist/esm/bs-progress.entry.js +2 -2
- package/dist/esm/bs-radio.entry.js +1 -1
- package/dist/esm/bs-slider.entry.js +1 -1
- package/dist/esm/bs-snackbar.entry.js +1 -1
- package/dist/esm/bs-source-link.entry.js +2 -2
- package/dist/esm/bs-stepper-step.entry.js +1 -1
- package/dist/esm/bs-stepper.entry.js +1 -1
- package/dist/esm/bs-switch.entry.js +1 -1
- package/dist/esm/bs-tab.entry.js +5 -1
- package/dist/esm/bs-tabs.entry.js +48 -3
- package/dist/esm/bs-timepicker.entry.js +207 -0
- package/dist/esm/bs-toast.entry.js +1 -1
- package/dist/esm/bs-tooltip.entry.js +1 -1
- package/dist/esm/loader.js +1 -1
- package/dist/types/components/bs-breadcrumb/bs-breadcrumb/bs-breadcrumb.d.ts +10 -0
- package/dist/types/components/bs-breadcrumb/bs-breadcrumb-overflow/bs-breadcrumb-overflow.d.ts +8 -0
- package/dist/types/components/bs-button/bs-icon-button/bs-icon-button.d.ts +2 -1
- package/dist/types/components/bs-button/bs-icon-button/bs-icon-button.stories.d.ts +1 -0
- package/dist/types/components/bs-data-table/bs-data-table.d.ts +16 -2
- package/dist/types/components/bs-datepicker/bs-datepicker.cmp.test.d.ts +1 -0
- package/dist/types/components/bs-datepicker/bs-datepicker.d.ts +136 -0
- package/dist/types/components/bs-datepicker/bs-datepicker.stories.d.ts +20 -0
- package/dist/types/components/bs-menu/bs-menu.stories.d.ts +1 -0
- package/dist/types/components/bs-tab/bs-inline-tab/bs-inline-tab.d.ts +4 -0
- package/dist/types/components/bs-tab/bs-tab/bs-tab.d.ts +4 -0
- package/dist/types/components/bs-tab/bs-tabs/bs-tabs.d.ts +17 -0
- package/dist/types/components/bs-tab/bs-tabs/bs-tabs.stories.d.ts +1 -0
- package/dist/types/components/bs-timepicker/bs-timepicker.cmp.test.d.ts +1 -0
- package/dist/types/components/bs-timepicker/bs-timepicker.d.ts +101 -0
- package/dist/types/components/bs-timepicker/bs-timepicker.stories.d.ts +14 -0
- package/dist/types/components/ui-shell/bs-navigation-drawer/bs-navigation-drawer/bs-navigation-drawer.d.ts +50 -1
- package/dist/types/components/ui-shell/bs-navigation-drawer/bs-navigation-drawer/bs-navigation-drawer.stories.d.ts +2 -0
- package/dist/types/components.d.ts +645 -2
- package/package.json +1 -1
- package/dist/brandsync-wc/p-002d258d.entry.js +0 -1
- package/dist/brandsync-wc/p-153da845.entry.js +0 -1
- package/dist/brandsync-wc/p-2e7a1082.entry.js +0 -1
- package/dist/brandsync-wc/p-612cf79c.entry.js +0 -1
- package/dist/brandsync-wc/p-652d4068.entry.js +0 -1
- package/dist/brandsync-wc/p-7b00dd36.entry.js +0 -1
- package/dist/brandsync-wc/p-ae978c9a.entry.js +0 -1
- package/dist/brandsync-wc/p-bc69a96c.entry.js +0 -1
- package/dist/brandsync-wc/p-bf53ad52.entry.js +0 -1
- package/dist/brandsync-wc/p-c10d2529.entry.js +0 -1
- package/dist/brandsync-wc/p-c7f4c114.entry.js +0 -1
- package/dist/cjs/bs-menu-item.cjs.entry.js +0 -34
- package/dist/components/p-BkHYJIyj.js +0 -1
- package/dist/components/p-Buly0d5G.js +0 -1
- package/dist/esm/bs-menu-item.entry.js +0 -32
|
@@ -58,4 +58,92 @@ describe('bs-tabs', () => {
|
|
|
58
58
|
expect(first.selected).toBe(true);
|
|
59
59
|
expect(second.selected).toBe(false);
|
|
60
60
|
});
|
|
61
|
+
describe('value and bsChange', () => {
|
|
62
|
+
const btn = (el) => el.shadowRoot.querySelector('button');
|
|
63
|
+
const key = (el, k) => el.dispatchEvent(new KeyboardEvent('keydown', { key: k, bubbles: true, composed: true, cancelable: true }));
|
|
64
|
+
const group = () => (h("bs-tabs", null, h("bs-tab", { value: "overview" }, "Overview"), h("bs-tab", { value: "details" }, "Details"), h("bs-tab", { value: "history" }, "History")));
|
|
65
|
+
it('a click selects the tab, updates the group value and emits bsChange with it', async () => {
|
|
66
|
+
const { root, waitForChanges, spyOnEvent } = await render(group());
|
|
67
|
+
const spy = spyOnEvent('bsChange');
|
|
68
|
+
const tabs = Array.from(root.querySelectorAll('bs-tab'));
|
|
69
|
+
btn(tabs[1]).click();
|
|
70
|
+
await waitForChanges();
|
|
71
|
+
expect(root.value).toBe('details');
|
|
72
|
+
expect(root.getAttribute('value')).toBe('details'); // reflected
|
|
73
|
+
expect(tabs[1].selected).toBe(true);
|
|
74
|
+
expect(spy).toHaveReceivedEventTimes(1);
|
|
75
|
+
expect(spy).toHaveReceivedEventDetail({ value: 'details' });
|
|
76
|
+
});
|
|
77
|
+
it('does not emit again when the already-selected tab is clicked', async () => {
|
|
78
|
+
const { root, waitForChanges, spyOnEvent } = await render(group());
|
|
79
|
+
const spy = spyOnEvent('bsChange');
|
|
80
|
+
const tabs = Array.from(root.querySelectorAll('bs-tab'));
|
|
81
|
+
btn(tabs[1]).click();
|
|
82
|
+
await waitForChanges();
|
|
83
|
+
btn(tabs[1]).click();
|
|
84
|
+
await waitForChanges();
|
|
85
|
+
expect(spy).toHaveReceivedEventTimes(1);
|
|
86
|
+
});
|
|
87
|
+
it('a tab without a value is identified by its zero-based index as a string', async () => {
|
|
88
|
+
const { root, waitForChanges, spyOnEvent } = await render(h("bs-tabs", null, h("bs-tab", null, "One"), h("bs-tab", null, "Two")));
|
|
89
|
+
const spy = spyOnEvent('bsChange');
|
|
90
|
+
btn(root.querySelectorAll('bs-tab')[1]).click();
|
|
91
|
+
await waitForChanges();
|
|
92
|
+
expect(spy).toHaveReceivedEventDetail({ value: '1' });
|
|
93
|
+
expect(root.value).toBe('1');
|
|
94
|
+
});
|
|
95
|
+
it('an initial value selects the matching tab on load', async () => {
|
|
96
|
+
const { root, waitForChanges } = await render(h("bs-tabs", { value: "history" }, h("bs-tab", { value: "overview" }, "Overview"), h("bs-tab", { value: "details" }, "Details"), h("bs-tab", { value: "history" }, "History")));
|
|
97
|
+
await waitForChanges();
|
|
98
|
+
const tabs = Array.from(root.querySelectorAll('bs-tab'));
|
|
99
|
+
expect(tabs.map(t => t.selected)).toEqual([false, false, true]);
|
|
100
|
+
// roving tabindex follows the selection
|
|
101
|
+
expect(btn(tabs[2]).tabIndex).toBe(0);
|
|
102
|
+
expect(btn(tabs[0]).tabIndex).toBe(-1);
|
|
103
|
+
});
|
|
104
|
+
it('setting value from outside selects the matching tab and does NOT emit bsChange', async () => {
|
|
105
|
+
const { root, waitForChanges, spyOnEvent } = await render(group());
|
|
106
|
+
const spy = spyOnEvent('bsChange');
|
|
107
|
+
root.value = 'details';
|
|
108
|
+
await waitForChanges();
|
|
109
|
+
const tabs = Array.from(root.querySelectorAll('bs-tab'));
|
|
110
|
+
expect(tabs.map(t => t.selected)).toEqual([false, true, false]);
|
|
111
|
+
expect(spy).not.toHaveReceivedEvent();
|
|
112
|
+
});
|
|
113
|
+
it('with no value set, reports the tab the consumer already marked selected (without emitting)', async () => {
|
|
114
|
+
const { root, waitForChanges, spyOnEvent } = await render(h("bs-tabs", null, h("bs-tab", { value: "a" }, "A"), h("bs-tab", { value: "b", selected: true }, "B")));
|
|
115
|
+
const spy = spyOnEvent('bsChange');
|
|
116
|
+
await waitForChanges();
|
|
117
|
+
expect(root.value).toBe('b');
|
|
118
|
+
expect(spy).not.toHaveReceivedEvent();
|
|
119
|
+
});
|
|
120
|
+
it('keyboard navigation emits bsChange too (arrow keys select the next tab)', async () => {
|
|
121
|
+
const { root, waitForChanges, spyOnEvent } = await render(group());
|
|
122
|
+
const spy = spyOnEvent('bsChange');
|
|
123
|
+
const tabs = Array.from(root.querySelectorAll('bs-tab'));
|
|
124
|
+
btn(tabs[0]).click();
|
|
125
|
+
await waitForChanges();
|
|
126
|
+
key(btn(tabs[0]), 'ArrowRight');
|
|
127
|
+
await waitForChanges();
|
|
128
|
+
expect(spy).toHaveReceivedEventDetail({ value: 'details' });
|
|
129
|
+
});
|
|
130
|
+
it('still emits bsSelect on the tab itself', async () => {
|
|
131
|
+
const { root, waitForChanges, spyOnEvent } = await render(group());
|
|
132
|
+
const spy = spyOnEvent('bsSelect');
|
|
133
|
+
btn(root.querySelectorAll('bs-tab')[2]).click();
|
|
134
|
+
await waitForChanges();
|
|
135
|
+
expect(spy).toHaveReceivedEventTimes(1);
|
|
136
|
+
});
|
|
137
|
+
it('works for bs-inline-tab groups', async () => {
|
|
138
|
+
const { root, waitForChanges, spyOnEvent } = await render(h("bs-tabs", { type: "bs-inline-tab" }, h("bs-inline-tab", { value: "x" }, "X"), h("bs-inline-tab", { value: "y" }, "Y")));
|
|
139
|
+
const spy = spyOnEvent('bsChange');
|
|
140
|
+
btn(root.querySelectorAll('bs-inline-tab')[1]).click();
|
|
141
|
+
await waitForChanges();
|
|
142
|
+
expect(spy).toHaveReceivedEventDetail({ value: 'y' });
|
|
143
|
+
});
|
|
144
|
+
it('a tab\'s value prop is reflected as an attribute', async () => {
|
|
145
|
+
const { root } = await render(group());
|
|
146
|
+
expect(root.querySelector('bs-tab').getAttribute('value')).toBe('overview');
|
|
147
|
+
});
|
|
148
|
+
});
|
|
61
149
|
});
|
|
@@ -35,6 +35,16 @@ export class BsTabs {
|
|
|
35
35
|
/** Layout direction of the tab bar itself. Sets `aria-orientation` on the internal wrapper and
|
|
36
36
|
* switches `flex-direction`. */
|
|
37
37
|
orientation = 'horizontal';
|
|
38
|
+
/** The selected tab's `value`. Mutable and reflected: it follows the user's selection, and
|
|
39
|
+
* setting it from outside (attribute or property) selects the matching tab -- without emitting
|
|
40
|
+
* `bsChange`, which only fires for user-driven changes. A tab's value is its own `value` prop,
|
|
41
|
+
* or, for a tab without one, its zero-based position in the group as a string (`"0"`, `"1"`...).
|
|
42
|
+
* If unset, it is read from whichever tab is already `selected` once the group loads. */
|
|
43
|
+
value;
|
|
44
|
+
/** Fires when the user selects a different tab (click, or arrow/Home/End), with the new
|
|
45
|
+
* `value`. Does not fire when `value` is set programmatically. `bsSelect` on the individual tab
|
|
46
|
+
* still fires as before. */
|
|
47
|
+
bsChange;
|
|
38
48
|
/**
|
|
39
49
|
* Catches `bsSelect` bubbling up from any slotted `<bs-tab>`/`<bs-inline-tab>` (Stencil's
|
|
40
50
|
* `@Event()` defaults to `bubbles: true, composed: true`, and `@Listen` without a target listens
|
|
@@ -43,15 +53,46 @@ export class BsTabs {
|
|
|
43
53
|
* `if (this.disabled) return;`), so no special-casing is needed here.
|
|
44
54
|
*/
|
|
45
55
|
onTabSelect(ev) {
|
|
46
|
-
const tabs = this.
|
|
56
|
+
const tabs = this.tabs();
|
|
47
57
|
tabs.forEach(tab => {
|
|
48
58
|
tab.selected = tab === ev.target;
|
|
49
59
|
});
|
|
50
60
|
this.syncRovingTabindex();
|
|
61
|
+
const index = tabs.findIndex(tab => tab === ev.target);
|
|
62
|
+
if (index === -1)
|
|
63
|
+
return;
|
|
64
|
+
const value = this.tabValue(tabs[index], index);
|
|
65
|
+
if (value !== this.value) {
|
|
66
|
+
this.value = value;
|
|
67
|
+
this.bsChange.emit({ value });
|
|
68
|
+
}
|
|
51
69
|
}
|
|
52
70
|
componentDidLoad() {
|
|
71
|
+
if (this.value !== undefined) {
|
|
72
|
+
this.applyValue();
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
// Uncontrolled: report whichever tab the consumer already marked `selected`.
|
|
76
|
+
const tabs = this.tabs();
|
|
77
|
+
const index = tabs.findIndex(t => t.selected);
|
|
78
|
+
if (index !== -1)
|
|
79
|
+
this.value = this.tabValue(tabs[index], index);
|
|
80
|
+
}
|
|
53
81
|
this.syncRovingTabindex();
|
|
54
82
|
}
|
|
83
|
+
tabValue(tab, index) {
|
|
84
|
+
return tab.value ?? String(index);
|
|
85
|
+
}
|
|
86
|
+
/** Selects the tab whose value matches `this.value` (and deselects the rest). */
|
|
87
|
+
applyValue() {
|
|
88
|
+
this.tabs().forEach((tab, i) => {
|
|
89
|
+
tab.selected = this.tabValue(tab, i) === this.value;
|
|
90
|
+
});
|
|
91
|
+
this.syncRovingTabindex();
|
|
92
|
+
}
|
|
93
|
+
onValueChange() {
|
|
94
|
+
this.applyValue();
|
|
95
|
+
}
|
|
55
96
|
syncRovingTabindex() {
|
|
56
97
|
const tabs = this.tabs();
|
|
57
98
|
const anySelected = tabs.some(t => t.selected);
|
|
@@ -94,7 +135,7 @@ export class BsTabs {
|
|
|
94
135
|
}
|
|
95
136
|
render() {
|
|
96
137
|
const vertical = this.orientation === 'vertical';
|
|
97
|
-
return (h("div", { key: '
|
|
138
|
+
return (h("div", { key: 'b47d3502305490c9098b825f1eb8c60f45dad5d8', part: "tablist", role: "tablist", "aria-orientation": this.orientation, class: `bs-tabs bs-tabs--${this.type} ${vertical ? 'bs-tabs--vertical' : ''}` }, h("slot", { key: '133cf0b2ea93354a664bb304579fa59d85e53edf', onSlotchange: () => this.syncRovingTabindex() })));
|
|
98
139
|
}
|
|
99
140
|
static get is() { return "bs-tabs"; }
|
|
100
141
|
static get encapsulation() { return "shadow"; }
|
|
@@ -161,12 +202,52 @@ export class BsTabs {
|
|
|
161
202
|
"reflect": false,
|
|
162
203
|
"attribute": "orientation",
|
|
163
204
|
"defaultValue": "'horizontal'"
|
|
205
|
+
},
|
|
206
|
+
"value": {
|
|
207
|
+
"type": "string",
|
|
208
|
+
"mutable": true,
|
|
209
|
+
"complexType": {
|
|
210
|
+
"original": "string",
|
|
211
|
+
"resolved": "string",
|
|
212
|
+
"references": {}
|
|
213
|
+
},
|
|
214
|
+
"required": false,
|
|
215
|
+
"optional": true,
|
|
216
|
+
"docs": {
|
|
217
|
+
"tags": [],
|
|
218
|
+
"text": "The selected tab's `value`. Mutable and reflected: it follows the user's selection, and\nsetting it from outside (attribute or property) selects the matching tab -- without emitting\n`bsChange`, which only fires for user-driven changes. A tab's value is its own `value` prop,\nor, for a tab without one, its zero-based position in the group as a string (`\"0\"`, `\"1\"`...).\nIf unset, it is read from whichever tab is already `selected` once the group loads."
|
|
219
|
+
},
|
|
220
|
+
"getter": false,
|
|
221
|
+
"setter": false,
|
|
222
|
+
"reflect": true,
|
|
223
|
+
"attribute": "value"
|
|
164
224
|
}
|
|
165
225
|
};
|
|
166
226
|
}
|
|
227
|
+
static get events() {
|
|
228
|
+
return [{
|
|
229
|
+
"method": "bsChange",
|
|
230
|
+
"name": "bsChange",
|
|
231
|
+
"bubbles": true,
|
|
232
|
+
"cancelable": true,
|
|
233
|
+
"composed": true,
|
|
234
|
+
"docs": {
|
|
235
|
+
"tags": [],
|
|
236
|
+
"text": "Fires when the user selects a different tab (click, or arrow/Home/End), with the new\n`value`. Does not fire when `value` is set programmatically. `bsSelect` on the individual tab\nstill fires as before."
|
|
237
|
+
},
|
|
238
|
+
"complexType": {
|
|
239
|
+
"original": "{ value: string }",
|
|
240
|
+
"resolved": "{ value: string; }",
|
|
241
|
+
"references": {}
|
|
242
|
+
}
|
|
243
|
+
}];
|
|
244
|
+
}
|
|
167
245
|
static get elementRef() { return "el"; }
|
|
168
246
|
static get watchers() {
|
|
169
247
|
return [{
|
|
248
|
+
"propName": "value",
|
|
249
|
+
"methodName": "onValueChange"
|
|
250
|
+
}, {
|
|
170
251
|
"propName": "orientation",
|
|
171
252
|
"methodName": "syncRovingTabindex"
|
|
172
253
|
}];
|
|
@@ -37,3 +37,27 @@ export const InlineTabGroup = {
|
|
|
37
37
|
export const Vertical = {
|
|
38
38
|
args: { orientation: 'vertical' },
|
|
39
39
|
};
|
|
40
|
+
// The group's `value` follows the selection, and `bsChange` reports user-driven changes: the panel
|
|
41
|
+
// below switches in response to it, with no per-tab selection wiring.
|
|
42
|
+
export const WithValueAndPanels = {
|
|
43
|
+
name: 'With value and panels',
|
|
44
|
+
render: () => {
|
|
45
|
+
const panels = {
|
|
46
|
+
overview: 'Overview content',
|
|
47
|
+
details: 'Details content',
|
|
48
|
+
history: 'History content',
|
|
49
|
+
};
|
|
50
|
+
const onChange = (ev) => {
|
|
51
|
+
const panel = ev.currentTarget.nextElementSibling;
|
|
52
|
+
panel.textContent = panels[ev.detail.value];
|
|
53
|
+
};
|
|
54
|
+
return html `
|
|
55
|
+
<bs-tabs value="overview" @bsChange=${onChange}>
|
|
56
|
+
<bs-tab value="overview">Overview</bs-tab>
|
|
57
|
+
<bs-tab value="details">Details</bs-tab>
|
|
58
|
+
<bs-tab value="history">History</bs-tab>
|
|
59
|
+
</bs-tabs>
|
|
60
|
+
<p role="tabpanel" style="margin: 16px 0 0;">Overview content</p>
|
|
61
|
+
`;
|
|
62
|
+
},
|
|
63
|
+
};
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { render, h, describe, it, expect } from "@stencil/vitest";
|
|
2
|
+
const sr = (root) => root.shadowRoot;
|
|
3
|
+
const spin = (root, label) => sr(root).querySelector(`[role="spinbutton"][aria-label="${label}"]`);
|
|
4
|
+
const text = (root, label) => spin(root, label).textContent;
|
|
5
|
+
const key = (el, k) => el.dispatchEvent(new KeyboardEvent('keydown', { key: k, bubbles: true }));
|
|
6
|
+
const steps = (root) => Array.from(sr(root).querySelectorAll('[part="step"]'));
|
|
7
|
+
// order: hour up, hour down, minute up, minute down
|
|
8
|
+
const period = (root) => sr(root).querySelector('[part="period"]');
|
|
9
|
+
describe('bs-timepicker', () => {
|
|
10
|
+
it('defaults to 12h, 12:00 AM with no value', async () => {
|
|
11
|
+
const { root } = await render(h("bs-timepicker", null));
|
|
12
|
+
expect(text(root, 'Hour')).toBe('12');
|
|
13
|
+
expect(text(root, 'Minute')).toBe('00');
|
|
14
|
+
expect(period(root).value).toBe('AM');
|
|
15
|
+
});
|
|
16
|
+
it('shows a 24-hour value as 12h with PM', async () => {
|
|
17
|
+
const { root } = await render(h("bs-timepicker", { value: "14:05" }));
|
|
18
|
+
expect(text(root, 'Hour')).toBe('02');
|
|
19
|
+
expect(text(root, 'Minute')).toBe('05');
|
|
20
|
+
expect(period(root).value).toBe('PM');
|
|
21
|
+
});
|
|
22
|
+
it('shows 00-23 and no AM/PM in 24h format', async () => {
|
|
23
|
+
const { root } = await render(h("bs-timepicker", { format: "24h", value: "14:05" }));
|
|
24
|
+
expect(text(root, 'Hour')).toBe('14');
|
|
25
|
+
expect(period(root)).toBeNull();
|
|
26
|
+
});
|
|
27
|
+
it('has hour/minute spinbuttons with ARIA values', async () => {
|
|
28
|
+
const { root } = await render(h("bs-timepicker", { format: "24h", value: "14:05" }));
|
|
29
|
+
const hourEl = spin(root, 'Hour');
|
|
30
|
+
expect(hourEl.getAttribute('aria-valuenow')).toBe('14');
|
|
31
|
+
expect(hourEl.getAttribute('aria-valuemin')).toBe('0');
|
|
32
|
+
expect(hourEl.getAttribute('aria-valuemax')).toBe('23');
|
|
33
|
+
expect(spin(root, 'Minute').getAttribute('aria-valuemax')).toBe('59');
|
|
34
|
+
});
|
|
35
|
+
it('caret buttons step and wrap the hour (12h: 12 -> 1, keeps PM)', async () => {
|
|
36
|
+
const { root, waitForChanges } = await render(h("bs-timepicker", { value: "12:00" }));
|
|
37
|
+
expect(period(root).value).toBe('PM');
|
|
38
|
+
steps(root)[0].click();
|
|
39
|
+
await waitForChanges();
|
|
40
|
+
expect(text(root, 'Hour')).toBe('01');
|
|
41
|
+
expect(period(root).value).toBe('PM');
|
|
42
|
+
steps(root)[1].click();
|
|
43
|
+
await waitForChanges();
|
|
44
|
+
expect(text(root, 'Hour')).toBe('12');
|
|
45
|
+
});
|
|
46
|
+
it('minutes wrap without touching the hour', async () => {
|
|
47
|
+
const { root, waitForChanges } = await render(h("bs-timepicker", { format: "24h", value: "09:59" }));
|
|
48
|
+
steps(root)[2].click();
|
|
49
|
+
await waitForChanges();
|
|
50
|
+
expect(text(root, 'Minute')).toBe('00');
|
|
51
|
+
expect(text(root, 'Hour')).toBe('09');
|
|
52
|
+
});
|
|
53
|
+
it('honours minuteStep', async () => {
|
|
54
|
+
const { root, waitForChanges } = await render(h("bs-timepicker", { format: "24h", value: "09:00", minuteStep: 15 }));
|
|
55
|
+
steps(root)[2].click();
|
|
56
|
+
await waitForChanges();
|
|
57
|
+
expect(text(root, 'Minute')).toBe('15');
|
|
58
|
+
steps(root)[3].click();
|
|
59
|
+
steps(root)[3].click();
|
|
60
|
+
await waitForChanges();
|
|
61
|
+
expect(text(root, 'Minute')).toBe('45');
|
|
62
|
+
});
|
|
63
|
+
it('ArrowUp/ArrowDown/Home/End work on a focused value', async () => {
|
|
64
|
+
const { root, waitForChanges } = await render(h("bs-timepicker", { format: "24h", value: "09:30" }));
|
|
65
|
+
key(spin(root, 'Hour'), 'ArrowUp');
|
|
66
|
+
await waitForChanges();
|
|
67
|
+
expect(text(root, 'Hour')).toBe('10');
|
|
68
|
+
key(spin(root, 'Hour'), 'End');
|
|
69
|
+
await waitForChanges();
|
|
70
|
+
expect(text(root, 'Hour')).toBe('23');
|
|
71
|
+
key(spin(root, 'Hour'), 'ArrowUp');
|
|
72
|
+
await waitForChanges();
|
|
73
|
+
expect(text(root, 'Hour')).toBe('00');
|
|
74
|
+
});
|
|
75
|
+
it('typing digits sets the value', async () => {
|
|
76
|
+
const { root, waitForChanges } = await render(h("bs-timepicker", { format: "24h", value: "00:00" }));
|
|
77
|
+
key(spin(root, 'Hour'), '1');
|
|
78
|
+
key(spin(root, 'Hour'), '7');
|
|
79
|
+
await waitForChanges();
|
|
80
|
+
expect(text(root, 'Hour')).toBe('17');
|
|
81
|
+
// 9 can't start a valid 24h hour pair beyond 9x, but 9 itself is valid.
|
|
82
|
+
key(spin(root, 'Minute'), '4');
|
|
83
|
+
key(spin(root, 'Minute'), '2');
|
|
84
|
+
await waitForChanges();
|
|
85
|
+
expect(text(root, 'Minute')).toBe('42');
|
|
86
|
+
});
|
|
87
|
+
it('the AM/PM dropdown flips the period without changing the displayed hour', async () => {
|
|
88
|
+
const { root, waitForChanges } = await render(h("bs-timepicker", { value: "09:15" }));
|
|
89
|
+
period(root).dispatchEvent(new CustomEvent('bsChange', { detail: 'PM' }));
|
|
90
|
+
await waitForChanges();
|
|
91
|
+
expect(period(root).value).toBe('PM');
|
|
92
|
+
expect(text(root, 'Hour')).toBe('09');
|
|
93
|
+
});
|
|
94
|
+
it('the 24h switch converts the display without changing the time', async () => {
|
|
95
|
+
const { root, waitForChanges } = await render(h("bs-timepicker", { value: "14:30" }));
|
|
96
|
+
sr(root).querySelector('bs-switch').dispatchEvent(new CustomEvent('bsChange', { detail: true }));
|
|
97
|
+
await waitForChanges();
|
|
98
|
+
expect(root).toEqualAttribute('format', '24h');
|
|
99
|
+
expect(text(root, 'Hour')).toBe('14');
|
|
100
|
+
});
|
|
101
|
+
it('nothing is committed until Confirm, which emits 24-hour HH:mm', async () => {
|
|
102
|
+
const { root, waitForChanges } = await render(h("bs-timepicker", { value: "09:15" }));
|
|
103
|
+
const events = [];
|
|
104
|
+
root.addEventListener('bsChange', (e) => events.push(e.detail));
|
|
105
|
+
period(root).dispatchEvent(new CustomEvent('bsChange', { detail: 'PM' }));
|
|
106
|
+
steps(root)[0].click();
|
|
107
|
+
await waitForChanges();
|
|
108
|
+
expect(root.value).toBe('09:15');
|
|
109
|
+
expect(events).toEqual([]);
|
|
110
|
+
sr(root).querySelector('[part="confirm"]').click();
|
|
111
|
+
await waitForChanges();
|
|
112
|
+
expect(events).toEqual([{ value: '22:15' }]);
|
|
113
|
+
expect(root.value).toBe('22:15');
|
|
114
|
+
});
|
|
115
|
+
it('Cancel discards the draft and emits bsCancel', async () => {
|
|
116
|
+
const { root, waitForChanges } = await render(h("bs-timepicker", { format: "24h", value: "09:15" }));
|
|
117
|
+
let cancelled = 0;
|
|
118
|
+
root.addEventListener('bsCancel', () => cancelled++);
|
|
119
|
+
steps(root)[0].click();
|
|
120
|
+
await waitForChanges();
|
|
121
|
+
expect(text(root, 'Hour')).toBe('10');
|
|
122
|
+
sr(root).querySelector('[part="cancel"]').click();
|
|
123
|
+
await waitForChanges();
|
|
124
|
+
expect(cancelled).toBe(1);
|
|
125
|
+
expect(text(root, 'Hour')).toBe('09');
|
|
126
|
+
expect(root.value).toBe('09:15');
|
|
127
|
+
});
|
|
128
|
+
it('setting value programmatically updates the display without emitting', async () => {
|
|
129
|
+
const { root, waitForChanges } = await render(h("bs-timepicker", { format: "24h", value: "09:15" }));
|
|
130
|
+
let fired = 0;
|
|
131
|
+
root.addEventListener('bsChange', () => fired++);
|
|
132
|
+
root.value = '18:45';
|
|
133
|
+
await waitForChanges();
|
|
134
|
+
expect(text(root, 'Hour')).toBe('18');
|
|
135
|
+
expect(fired).toBe(0);
|
|
136
|
+
});
|
|
137
|
+
it('ignores an invalid value', async () => {
|
|
138
|
+
const { root } = await render(h("bs-timepicker", { format: "24h", value: "25:99" }));
|
|
139
|
+
expect(text(root, 'Hour')).toBe('00');
|
|
140
|
+
});
|
|
141
|
+
});
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @prop --bs-timepicker-width: Width of the card. 294px, exact match to Figma.
|
|
3
|
+
* @prop --bs-timepicker-bg: Card background. Aliased to --bs-surface-raised.
|
|
4
|
+
* @prop --bs-timepicker-radius: Card corner radius. Aliased to --bs-border-radius-100.
|
|
5
|
+
* @prop --bs-timepicker-padding-y: Vertical padding of the card. Aliased to --bs-spacing-200.
|
|
6
|
+
* @prop --bs-timepicker-padding-x: Horizontal padding of each section. Aliased to --bs-spacing-200.
|
|
7
|
+
* @prop --bs-timepicker-gap: Vertical gap between sections. Aliased to --bs-spacing-200.
|
|
8
|
+
* @prop --bs-timepicker-shadow: Card shadow. Aliased to --bs-shadow-md.
|
|
9
|
+
* @prop --bs-timepicker-title-size: Heading font size. Aliased to --bs-font-size-2xl.
|
|
10
|
+
* @prop --bs-timepicker-title-line-height: Heading line height. Aliased to --bs-line-height-heading-h6.
|
|
11
|
+
* @prop --bs-timepicker-color: Heading and value color. Aliased to --bs-text-default.
|
|
12
|
+
* @prop --bs-timepicker-color-secondary: Color of the 24h label and the step carets. Aliased to --bs-text-secondary.
|
|
13
|
+
* @prop --bs-timepicker-divider: Divider color. Aliased to --bs-border-neutral-container.
|
|
14
|
+
* @prop --bs-timepicker-cell-size: Width/height of a step button and a value. Aliased to --bs-spacing-550 (44px).
|
|
15
|
+
* @prop --bs-timepicker-cell-radius: Corner radius of a step button. Aliased to --bs-border-radius-100.
|
|
16
|
+
* @prop --bs-timepicker-value-radius: Corner radius of the focus ring on a value. Aliased to --bs-border-radius-50.
|
|
17
|
+
* @prop --bs-timepicker-hover: Background of a step button or value on hover. Aliased to --bs-surface-hover.
|
|
18
|
+
* @prop --bs-timepicker-pressed: Background of a step button or value when pressed. Aliased to --bs-surface-pressed.
|
|
19
|
+
* @prop --bs-timepicker-focus-ring-color: Focus ring color. Aliased to --bs-border-neutral-container-focused.
|
|
20
|
+
*/
|
|
21
|
+
:host {
|
|
22
|
+
display: inline-block;
|
|
23
|
+
|
|
24
|
+
--bs-timepicker-width: 294px;
|
|
25
|
+
--bs-timepicker-bg: var(--bs-surface-raised);
|
|
26
|
+
--bs-timepicker-radius: var(--bs-border-radius-100);
|
|
27
|
+
--bs-timepicker-padding-y: var(--bs-spacing-200);
|
|
28
|
+
--bs-timepicker-padding-x: var(--bs-spacing-200);
|
|
29
|
+
--bs-timepicker-gap: var(--bs-spacing-200);
|
|
30
|
+
--bs-timepicker-shadow: var(--bs-shadow-md);
|
|
31
|
+
|
|
32
|
+
--bs-timepicker-title-size: var(--bs-font-size-2xl);
|
|
33
|
+
--bs-timepicker-title-line-height: var(--bs-line-height-heading-h6);
|
|
34
|
+
--bs-timepicker-color: var(--bs-text-default);
|
|
35
|
+
--bs-timepicker-color-secondary: var(--bs-text-secondary);
|
|
36
|
+
--bs-timepicker-divider: var(--bs-border-neutral-container);
|
|
37
|
+
|
|
38
|
+
--bs-timepicker-cell-size: var(--bs-spacing-550);
|
|
39
|
+
--bs-timepicker-cell-radius: var(--bs-border-radius-100);
|
|
40
|
+
--bs-timepicker-value-radius: var(--bs-border-radius-50);
|
|
41
|
+
--bs-timepicker-hover: var(--bs-surface-hover);
|
|
42
|
+
--bs-timepicker-pressed: var(--bs-surface-pressed);
|
|
43
|
+
--bs-timepicker-focus-ring-color: var(--bs-border-neutral-container-focused);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.bs-timepicker {
|
|
47
|
+
box-sizing: border-box;
|
|
48
|
+
display: flex;
|
|
49
|
+
flex-direction: column;
|
|
50
|
+
gap: var(--bs-timepicker-gap);
|
|
51
|
+
width: var(--bs-timepicker-width);
|
|
52
|
+
max-width: 100%;
|
|
53
|
+
padding: var(--bs-timepicker-padding-y) 0;
|
|
54
|
+
border-radius: var(--bs-timepicker-radius);
|
|
55
|
+
background: var(--bs-timepicker-bg);
|
|
56
|
+
box-shadow: var(--bs-timepicker-shadow);
|
|
57
|
+
color: var(--bs-timepicker-color);
|
|
58
|
+
font-family: inherit;
|
|
59
|
+
font-size: var(--bs-font-size-md);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.bs-timepicker__header {
|
|
63
|
+
display: flex;
|
|
64
|
+
align-items: center;
|
|
65
|
+
gap: var(--bs-spacing-100);
|
|
66
|
+
padding: 0 var(--bs-timepicker-padding-x);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.bs-timepicker__title {
|
|
70
|
+
flex: 1 1 0;
|
|
71
|
+
min-width: 0;
|
|
72
|
+
font-size: var(--bs-timepicker-title-size);
|
|
73
|
+
font-weight: var(--bs-font-weight-bold);
|
|
74
|
+
line-height: calc(var(--bs-timepicker-title-line-height) * 1px);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.bs-timepicker__format {
|
|
78
|
+
display: flex;
|
|
79
|
+
align-items: center;
|
|
80
|
+
gap: var(--bs-spacing-50);
|
|
81
|
+
color: var(--bs-timepicker-color-secondary);
|
|
82
|
+
line-height: calc(var(--bs-line-height-body-md) * 1px);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/* Full-bleed: the divider ignores the section padding, like the Figma's. */
|
|
86
|
+
.bs-timepicker__divider {
|
|
87
|
+
height: 1px;
|
|
88
|
+
background: var(--bs-timepicker-divider);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
.bs-timepicker__selector {
|
|
92
|
+
display: flex;
|
|
93
|
+
align-items: center;
|
|
94
|
+
justify-content: center;
|
|
95
|
+
gap: var(--bs-spacing-200);
|
|
96
|
+
padding: 0 var(--bs-timepicker-padding-x);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
.bs-timepicker__spinner {
|
|
100
|
+
display: flex;
|
|
101
|
+
flex-direction: column;
|
|
102
|
+
align-items: center;
|
|
103
|
+
gap: var(--bs-spacing-100);
|
|
104
|
+
width: var(--bs-timepicker-cell-size);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
.bs-timepicker__step,
|
|
108
|
+
.bs-timepicker__value {
|
|
109
|
+
display: flex;
|
|
110
|
+
align-items: center;
|
|
111
|
+
justify-content: center;
|
|
112
|
+
box-sizing: border-box;
|
|
113
|
+
width: var(--bs-timepicker-cell-size);
|
|
114
|
+
height: var(--bs-timepicker-cell-size);
|
|
115
|
+
padding: 0;
|
|
116
|
+
border: none;
|
|
117
|
+
background: transparent;
|
|
118
|
+
font-family: inherit;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
.bs-timepicker__step {
|
|
122
|
+
border-radius: var(--bs-timepicker-cell-radius);
|
|
123
|
+
color: var(--bs-timepicker-color-secondary);
|
|
124
|
+
cursor: pointer;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
.bs-timepicker__step svg {
|
|
128
|
+
width: 24px;
|
|
129
|
+
height: 24px;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
.bs-timepicker__value {
|
|
133
|
+
border-radius: var(--bs-timepicker-value-radius);
|
|
134
|
+
color: var(--bs-timepicker-color);
|
|
135
|
+
font-size: var(--bs-timepicker-title-size);
|
|
136
|
+
font-weight: var(--bs-font-weight-bold);
|
|
137
|
+
line-height: calc(var(--bs-timepicker-title-line-height) * 1px);
|
|
138
|
+
font-variant-numeric: tabular-nums;
|
|
139
|
+
cursor: pointer;
|
|
140
|
+
user-select: none;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
.bs-timepicker__step:hover,
|
|
144
|
+
.bs-timepicker__value:hover {
|
|
145
|
+
background: var(--bs-timepicker-hover);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
.bs-timepicker__step:active,
|
|
149
|
+
.bs-timepicker__value:active {
|
|
150
|
+
background: var(--bs-timepicker-pressed);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/* Figma focus state: a 2px ring flush against the block's edge. */
|
|
154
|
+
.bs-timepicker__step:focus-visible,
|
|
155
|
+
.bs-timepicker__value:focus-visible {
|
|
156
|
+
outline: 2px solid var(--bs-timepicker-focus-ring-color);
|
|
157
|
+
outline-offset: 0;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
.bs-timepicker__separator {
|
|
161
|
+
display: flex;
|
|
162
|
+
align-items: center;
|
|
163
|
+
color: var(--bs-timepicker-color);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
.bs-timepicker__separator svg {
|
|
167
|
+
width: 4px;
|
|
168
|
+
height: 32px;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/* The Figma has no visible label on the AM/PM field; bs-input only names its field through its
|
|
172
|
+
label, so keep the label for assistive tech and hide it visually. */
|
|
173
|
+
.bs-timepicker__period::part(label) {
|
|
174
|
+
position: absolute;
|
|
175
|
+
width: 1px;
|
|
176
|
+
height: 1px;
|
|
177
|
+
margin: -1px;
|
|
178
|
+
overflow: hidden;
|
|
179
|
+
clip-path: inset(50%);
|
|
180
|
+
white-space: nowrap;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
.bs-timepicker__period {
|
|
184
|
+
width: 112px;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/* bs-input's dropdown trigger is a read-only text input: no text caret, and a pointer cursor. */
|
|
188
|
+
.bs-timepicker__period::part(control) {
|
|
189
|
+
caret-color: transparent;
|
|
190
|
+
cursor: pointer;
|
|
191
|
+
text-overflow: clip;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
.bs-timepicker__footer {
|
|
195
|
+
display: flex;
|
|
196
|
+
align-items: flex-start;
|
|
197
|
+
justify-content: flex-end;
|
|
198
|
+
gap: var(--bs-spacing-100);
|
|
199
|
+
padding: 0 var(--bs-timepicker-padding-x);
|
|
200
|
+
}
|