@bluevolt-tech/lumen 2.0.1 → 2.2.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/README.md +37 -23
- package/dist/components/_shared/adopt-styles.d.ts +8 -0
- package/dist/components/_shared/date-range-validator.d.ts +86 -0
- package/dist/components/_shared/dropdown-controller.d.ts +60 -0
- package/dist/components/_shared/selectable-card.d.ts +10 -0
- package/dist/components/bv-alert-banner/bv-alert-banner.js +19 -17
- package/dist/components/bv-avatar/bv-avatar.js +19 -11
- package/dist/components/bv-badge/bv-badge.js +19 -11
- package/dist/components/bv-button/bv-button.js +18 -16
- package/dist/components/bv-category-pill/bv-category-pill.js +18 -16
- package/dist/components/bv-checkbox/bv-checkbox.js +19 -11
- package/dist/components/bv-chip/bv-chip.js +19 -11
- package/dist/components/bv-course-detail/bv-course-detail.js +20 -34
- package/dist/components/bv-course-detail-modal/bv-course-detail-modal.js +24 -90
- package/dist/components/bv-course-grid-card/bv-course-grid-card.d.ts +2 -6
- package/dist/components/bv-course-grid-card/bv-course-grid-card.js +98 -105
- package/dist/components/bv-course-list-card/bv-course-list-card.d.ts +2 -6
- package/dist/components/bv-course-list-card/bv-course-list-card.js +98 -105
- package/dist/components/bv-course-outline/bv-course-outline.js +19 -11
- package/dist/components/bv-date-range-input/bv-date-range-input.d.ts +10 -6
- package/dist/components/bv-date-range-input/bv-date-range-input.js +602 -125
- package/dist/components/bv-date-range-picker/bv-date-range-picker.d.ts +71 -4
- package/dist/components/bv-date-range-picker/bv-date-range-picker.js +441 -76
- package/dist/components/bv-empty-state/bv-empty-state.js +20 -28
- package/dist/components/bv-filter-dropdown/bv-filter-dropdown.d.ts +1 -4
- package/dist/components/bv-filter-dropdown/bv-filter-dropdown.js +80 -53
- package/dist/components/bv-filter-panel/bv-filter-panel.js +20 -22
- package/dist/components/bv-icon/bv-icon.js +19 -11
- package/dist/components/bv-input/bv-input.js +18 -16
- package/dist/components/bv-input-dropdown/bv-input-dropdown.d.ts +1 -4
- package/dist/components/bv-input-dropdown/bv-input-dropdown.js +79 -78
- package/dist/components/bv-modal/bv-modal.js +19 -11
- package/dist/components/bv-page-title/bv-page-title.js +19 -6
- package/dist/components/bv-pagination/bv-pagination.d.ts +1 -0
- package/dist/components/bv-pagination/bv-pagination.js +23 -186
- package/dist/components/bv-portal-header/bv-portal-header.js +25 -83
- package/dist/components/bv-portal-layout/bv-portal-layout.js +19 -11
- package/dist/components/bv-progress-bar/bv-progress-bar.js +19 -11
- package/dist/components/bv-promo-banner/bv-promo-banner.js +19 -11
- package/dist/components/bv-radio/bv-radio.js +19 -11
- package/dist/components/bv-searchbox/bv-searchbox.js +19 -11
- package/dist/components/bv-segmented-control/bv-segmented-control.js +18 -16
- package/dist/components/bv-select/bv-select.d.ts +1 -4
- package/dist/components/bv-select/bv-select.js +78 -44
- package/dist/components/bv-split-button/bv-split-button.d.ts +1 -4
- package/dist/components/bv-split-button/bv-split-button.js +78 -42
- package/dist/components/bv-star-rating/bv-star-rating.js +19 -11
- package/dist/components/bv-table/bv-table.d.ts +5 -0
- package/dist/components/bv-table/bv-table.js +70 -19
- package/dist/components/bv-toggle/bv-toggle.js +19 -11
- package/dist/components/bv-tooltip/bv-tooltip.js +20 -17
- package/dist/components/bv-user-row/bv-user-row.js +22 -50
- package/dist/components/bv-view-switcher/bv-view-switcher.js +19 -11
- package/dist/themes/base.css +1 -1
- package/package.json +8 -1
- package/themes/base.css +1 -1
|
@@ -1,5 +1,116 @@
|
|
|
1
1
|
// css-inline:/home/runner/work/BV_lumen/BV_lumen/components/bv-date-range-picker/bv-date-range-picker.css
|
|
2
|
-
var bv_date_range_picker_default = ":host {\n display: inline-block;\n font-family: var(--bv-font-family-base);\n}\n\n/* \u2500\u2500 Picker shell \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.picker {\n display: flex;\n background: var(--bv-color-neutral-0);\n border: 1px solid var(--bv-color-neutral-200);\n border-radius: var(--bv-radius-xl);\n box-shadow: var(--bv-shadow-lg);\n overflow: hidden;\n user-select: none;\n}\n\n/* \u2500\u2500 Sidebar \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.sidebar {\n display: flex;\n flex-direction: column;\n width: 152px;\n flex-shrink: 0;\n padding: var(--bv-spacing-sm) 0;\n border-right: 1px solid var(--bv-color-neutral-200);\n}\n\n.preset-btn {\n display: block;\n width: 100%;\n padding: 10px var(--bv-spacing-md);\n text-align: left;\n background: none;\n border: none;\n font-family: inherit;\n font-size: var(--bv-font-size-sm);\n font-weight: var(--bv-font-weight-regular);\n color: var(--bv-color-neutral-700);\n cursor: pointer;\n transition:\n background var(--bv-transition-fast),\n color var(--bv-transition-fast);\n white-space: nowrap;\n}\n\n.preset-btn:hover {\n background: var(--bv-color-secondary);\n color: var(--bv-color-neutral-900);\n}\n\n.sidebar-sep {\n margin: var(--bv-spacing-xs) 0;\n border: none;\n border-top: 1px solid var(--bv-color-neutral-200);\n}\n\n.preset-btn.active {\n background: var(--bv-color-secondary-light);\n color: var(--bv-color-neutral-900);\n font-weight: var(--bv-font-weight-medium);\n}\n\n/* \u2500\u2500 Main panel \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.main {\n display: flex;\n flex-direction: column;\n flex: 1;\n}\n\n/* \u2500\u2500 Calendars \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.calendars {\n display: flex;\n border-bottom: 1px solid var(--bv-color-neutral-200);\n}\n\n.calendar {\n padding: var(--bv-spacing-md) var(--bv-spacing-lg);\n flex: 1;\n}\n\n.calendar--left {\n border-right: 1px solid var(--bv-color-neutral-200);\n}\n\n/* \u2500\u2500 Calendar header \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.calendar-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n margin-bottom: var(--bv-spacing-md);\n}\n\n.calendar-title {\n font-size: var(--bv-font-size-sm);\n font-weight: var(--bv-font-weight-semibold);\n color: var(--bv-color-neutral-800);\n}\n\n.nav-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n padding: 0;\n background: none;\n border: none;\n border-radius: var(--bv-radius-md);\n color: var(--bv-color-neutral-500);\n cursor: pointer;\n transition:\n background var(--bv-transition-fast),\n color var(--bv-transition-fast);\n flex-shrink: 0;\n}\n\n.nav-btn:hover {\n background: var(--bv-color-secondary);\n color: var(--bv-color-neutral-800);\n}\n\n/* \u2500\u2500 Weekdays row \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.weekdays {\n display: grid;\n grid-template-columns: repeat(7, 36px);\n gap: 0;\n margin-bottom: var(--bv-spacing-xs);\n}\n\n.weekday {\n display: flex;\n align-items: center;\n justify-content: center;\n height: 28px;\n font-size: var(--bv-font-size-xs);\n font-weight: var(--bv-font-weight-medium);\n color: var(--bv-color-neutral-500);\n}\n\n/* \u2500\u2500 Days grid \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.days-grid {\n display: grid;\n grid-template-columns: repeat(7, 36px);\n gap: 0;\n}\n\n/* \u2500\u2500 Day cell \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.day {\n position: relative;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 36px;\n height: 36px;\n padding: 0;\n border: none;\n background: none;\n cursor: pointer;\n font-family: inherit;\n font-size: var(--bv-font-size-sm);\n font-weight: var(--bv-font-weight-regular);\n color: var(--bv-color-neutral-700);\n border-radius: 0;\n transition: background var(--bv-transition-fast);\n}\n\n.day:hover:not(.start):not(.end) .day-inner {\n background: var(--bv-color-secondary);\n color: var(--bv-color-neutral-900);\n}\n\n.day--blank {\n pointer-events: none;\n}\n\n.day.today:not(.start):not(.end) .day-inner::after {\n content: '';\n position: absolute;\n bottom: 2px;\n left: 50%;\n transform: translateX(-50%);\n width: 4px;\n height: 4px;\n border-radius: var(--bv-radius-full);\n background: var(--bv-color-primary);\n}\n\n/* \u2500\u2500 Range band \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.day.in-range {\n background: var(--bv-color-primary-light);\n}\n\n.day.in-range.week-start,\n.day.range-end.week-start {\n border-radius: var(--bv-radius-full) 0 0 var(--bv-radius-full);\n}\n\n.day.in-range.week-end,\n.day.range-start.week-end {\n border-radius: 0 var(--bv-radius-full) var(--bv-radius-full) 0;\n}\n\n.day.range-start {\n background: linear-gradient(to right, transparent 50%, var(--bv-color-primary-light) 50%);\n}\n\n.day.range-end {\n background: linear-gradient(to left, transparent 50%, var(--bv-color-primary-light) 50%);\n}\n\n/* \u2500\u2500 Day inner (circle) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.day-inner {\n position: relative;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 32px;\n height: 32px;\n border-radius: var(--bv-radius-full);\n z-index: 1;\n transition:\n background var(--bv-transition-fast),\n color var(--bv-transition-fast);\n}\n\n.day.start .day-inner,\n.day.end .day-inner {\n background: var(--bv-color-primary);\n color: var(--bv-color-neutral-0);\n font-weight: var(--bv-font-weight-semibold);\n}\n\n.day.start:hover .day-inner,\n.day.end:hover .day-inner {\n background: var(--bv-color-primary-dark);\n}\n\n/* \u2500\u2500 5-year warning banner \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.banner-wrap {\n display: none;\n padding: var(--bv-spacing-lg);\n}\n\n.picker--with-banner .banner-wrap {\n display: block;\n}\n\n/* Footer loses its top padding when the banner is shown above it */\n.picker--with-banner .footer {\n padding-top: 0;\n}\n\n/* \u2500\u2500 Footer \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.footer {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: var(--bv-spacing-lg);\n gap: var(--bv-spacing-md);\n}\n\n/* \u2500\u2500 Date inputs \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.date-inputs {\n display: flex;\n align-items: center;\n gap: var(--bv-spacing-sm);\n}\n\n.date-input {\n width: 112px;\n height: 36px;\n padding: 0 var(--bv-spacing-sm);\n border: 1px solid var(--bv-color-neutral-300);\n border-radius: var(--bv-radius-lg);\n font-family: inherit;\n font-size: var(--bv-font-size-sm);\n color: var(--bv-color-neutral-700);\n text-align: center;\n outline: none;\n transition:\n border-color var(--bv-transition-fast),\n box-shadow var(--bv-transition-fast);\n}\n\n.date-input:focus {\n border-color: var(--bv-color-primary);\n box-shadow: 0 0 0 3px var(--bv-color-primary-light);\n}\n\n.date-input::placeholder {\n color: var(--bv-color-neutral-400);\n}\n\n.date-sep {\n color: var(--bv-color-neutral-400);\n font-size: var(--bv-font-size-sm);\n}\n\n/* \u2500\u2500 Action buttons \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.footer-actions {\n display: flex;\n align-items: center;\n gap: var(--bv-spacing-sm);\n flex-shrink: 0;\n}\n\n.btn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n height: 36px;\n padding: 0 var(--bv-spacing-md);\n border-radius: var(--bv-radius-lg);\n font-family: inherit;\n font-size: var(--bv-font-size-sm);\n font-weight: var(--bv-font-weight-semibold);\n cursor: pointer;\n white-space: nowrap;\n transition:\n background var(--bv-transition-fast),\n border-color var(--bv-transition-fast),\n color var(--bv-transition-fast);\n}\n\n.btn-cancel {\n background: var(--bv-color-neutral-0);\n border: 1px solid var(--bv-color-neutral-300);\n color: var(--bv-color-neutral-700);\n}\n\n.btn-cancel:hover {\n background: var(--bv-color-secondary);\n border-color: var(--bv-color-neutral-400);\n}\n\n.btn-apply {\n background: var(--bv-color-primary);\n border: 1px solid var(--bv-color-primary);\n color: var(--bv-color-neutral-0);\n}\n\n.btn-apply:hover:not(:disabled) {\n background: var(--bv-color-primary-dark);\n border-color: var(--bv-color-primary-dark);\n}\n\n.btn-apply:disabled {\n background: var(--bv-color-neutral-300);\n border-color: var(--bv-color-neutral-300);\n cursor: not-allowed;\n}\n";
|
|
2
|
+
var bv_date_range_picker_default = ":host {\n display: inline-block;\n font-family: var(--bv-font-family-base);\n}\n\n/* \u2500\u2500 Picker shell \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.picker {\n display: flex;\n background: var(--bv-color-neutral-0);\n border: 1px solid var(--bv-color-neutral-200);\n border-radius: var(--bv-radius-xl);\n box-shadow: var(--bv-shadow-lg);\n overflow: hidden;\n user-select: none;\n}\n\n/* \u2500\u2500 Sidebar \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.sidebar {\n display: flex;\n flex-direction: column;\n width: 152px;\n flex-shrink: 0;\n padding: var(--bv-spacing-sm) 0;\n border-right: 1px solid var(--bv-color-neutral-200);\n}\n\n.preset-btn {\n display: block;\n width: 100%;\n padding: 10px var(--bv-spacing-md);\n text-align: left;\n background: none;\n border: none;\n font-family: inherit;\n font-size: var(--bv-font-size-sm);\n font-weight: var(--bv-font-weight-regular);\n color: var(--bv-color-neutral-700);\n cursor: pointer;\n transition:\n background var(--bv-transition-fast),\n color var(--bv-transition-fast);\n white-space: nowrap;\n}\n\n.preset-btn:hover {\n background: var(--bv-color-secondary);\n color: var(--bv-color-neutral-900);\n}\n\n.sidebar-sep {\n margin: var(--bv-spacing-xs) 0;\n border: none;\n border-top: 1px solid var(--bv-color-neutral-200);\n}\n\n.preset-btn.active {\n background: var(--bv-color-secondary-light);\n color: var(--bv-color-neutral-900);\n font-weight: var(--bv-font-weight-medium);\n}\n\n/* \u2500\u2500 Main panel \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.main {\n display: flex;\n flex-direction: column;\n flex: 1;\n}\n\n/* \u2500\u2500 Calendars \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.calendars {\n display: flex;\n border-bottom: 1px solid var(--bv-color-neutral-200);\n}\n\n.calendar {\n padding: var(--bv-spacing-md) var(--bv-spacing-lg);\n flex: 1;\n}\n\n.calendar--left {\n border-right: 1px solid var(--bv-color-neutral-200);\n}\n\n/* \u2500\u2500 Calendar header \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.calendar-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n margin-bottom: var(--bv-spacing-md);\n}\n\n.calendar-title {\n font-size: var(--bv-font-size-sm);\n font-weight: var(--bv-font-weight-semibold);\n color: var(--bv-color-neutral-800);\n}\n\n.nav-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n padding: 0;\n background: none;\n border: none;\n border-radius: var(--bv-radius-md);\n color: var(--bv-color-neutral-500);\n cursor: pointer;\n transition:\n background var(--bv-transition-fast),\n color var(--bv-transition-fast);\n flex-shrink: 0;\n}\n\n.nav-btn:hover {\n background: var(--bv-color-secondary);\n color: var(--bv-color-neutral-800);\n}\n\n/* \u2500\u2500 Weekdays row \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.weekdays {\n display: grid;\n grid-template-columns: repeat(7, 36px);\n gap: 0;\n margin-bottom: var(--bv-spacing-xs);\n}\n\n.weekday {\n display: flex;\n align-items: center;\n justify-content: center;\n height: 28px;\n font-size: var(--bv-font-size-xs);\n font-weight: var(--bv-font-weight-medium);\n color: var(--bv-color-neutral-500);\n}\n\n/* \u2500\u2500 Days grid \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.days-grid {\n display: grid;\n grid-template-columns: repeat(7, 36px);\n gap: 0;\n}\n\n/* \u2500\u2500 Day cell \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.day {\n position: relative;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 36px;\n height: 36px;\n padding: 0;\n border: none;\n background: none;\n cursor: pointer;\n font-family: inherit;\n font-size: var(--bv-font-size-sm);\n font-weight: var(--bv-font-weight-regular);\n color: var(--bv-color-neutral-700);\n border-radius: 0;\n transition: background var(--bv-transition-fast);\n}\n\n.day:hover:not(.start):not(.end) .day-inner {\n background: var(--bv-color-secondary);\n color: var(--bv-color-neutral-900);\n}\n\n.day--blank {\n pointer-events: none;\n}\n\n.day.today:not(.start):not(.end) .day-inner::after {\n content: '';\n position: absolute;\n bottom: 2px;\n left: 50%;\n transform: translateX(-50%);\n width: 4px;\n height: 4px;\n border-radius: var(--bv-radius-full);\n background: var(--bv-color-primary);\n}\n\n/* \u2500\u2500 Range band \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.day.in-range {\n background: var(--bv-color-primary-light);\n}\n\n.day.in-range.week-start,\n.day.range-end.week-start {\n border-radius: var(--bv-radius-full) 0 0 var(--bv-radius-full);\n}\n\n.day.in-range.week-end,\n.day.range-start.week-end {\n border-radius: 0 var(--bv-radius-full) var(--bv-radius-full) 0;\n}\n\n.day.range-start {\n background: linear-gradient(to right, transparent 50%, var(--bv-color-primary-light) 50%);\n}\n\n.day.range-end {\n background: linear-gradient(to left, transparent 50%, var(--bv-color-primary-light) 50%);\n}\n\n/* \u2500\u2500 Day inner (circle) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.day-inner {\n position: relative;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 32px;\n height: 32px;\n border-radius: var(--bv-radius-full);\n z-index: 1;\n transition:\n background var(--bv-transition-fast),\n color var(--bv-transition-fast);\n}\n\n.day.start .day-inner,\n.day.end .day-inner {\n background: var(--bv-color-primary);\n color: var(--bv-color-neutral-0);\n font-weight: var(--bv-font-weight-semibold);\n}\n\n.day.start:hover .day-inner,\n.day.end:hover .day-inner {\n background: var(--bv-color-primary-dark);\n}\n\n/* \u2500\u2500 Alert banner (BTN-10312 \u2014 unified for all validation errors) \u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.banner-wrap {\n display: none;\n padding: var(--bv-spacing-lg);\n}\n\n.picker--with-banner .banner-wrap {\n display: block;\n}\n\n/* Footer loses its top padding when the banner is shown above it */\n.picker--with-banner .footer {\n padding-top: 0;\n}\n\n/* \u2500\u2500 Footer \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.footer {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: var(--bv-spacing-lg);\n gap: var(--bv-spacing-md);\n}\n\n/* \u2500\u2500 Date inputs \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.date-inputs {\n display: flex;\n align-items: center;\n gap: var(--bv-spacing-sm);\n}\n\n.date-input {\n width: 112px;\n height: 36px;\n padding: 0 var(--bv-spacing-sm);\n border: 1px solid var(--bv-color-neutral-300);\n border-radius: var(--bv-radius-lg);\n font-family: inherit;\n font-size: var(--bv-font-size-sm);\n color: var(--bv-color-neutral-700);\n text-align: center;\n outline: none;\n transition:\n border-color var(--bv-transition-fast),\n box-shadow var(--bv-transition-fast);\n}\n\n.date-input:focus {\n border-color: var(--bv-color-primary);\n box-shadow: 0 0 0 3px var(--bv-color-primary-light);\n}\n\n.date-input::placeholder {\n color: var(--bv-color-neutral-400);\n}\n\n.date-sep {\n color: var(--bv-color-neutral-400);\n font-size: var(--bv-font-size-sm);\n}\n\n/* \u2500\u2500 Action buttons \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.footer-actions {\n display: flex;\n align-items: center;\n gap: var(--bv-spacing-sm);\n flex-shrink: 0;\n}\n\n.btn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n height: 36px;\n padding: 0 var(--bv-spacing-md);\n border-radius: var(--bv-radius-lg);\n font-family: inherit;\n font-size: var(--bv-font-size-sm);\n font-weight: var(--bv-font-weight-semibold);\n cursor: pointer;\n white-space: nowrap;\n transition:\n background var(--bv-transition-fast),\n border-color var(--bv-transition-fast),\n color var(--bv-transition-fast);\n}\n\n.btn-cancel {\n background: var(--bv-color-neutral-0);\n border: 1px solid var(--bv-color-neutral-300);\n color: var(--bv-color-neutral-700);\n}\n\n.btn-cancel:hover {\n background: var(--bv-color-secondary);\n border-color: var(--bv-color-neutral-400);\n}\n\n.btn-apply {\n background: var(--bv-color-primary);\n border: 1px solid var(--bv-color-primary);\n color: var(--bv-color-neutral-0);\n}\n\n.btn-apply:hover:not(:disabled) {\n background: var(--bv-color-primary-dark);\n border-color: var(--bv-color-primary-dark);\n}\n\n.btn-apply:disabled {\n background: var(--bv-color-neutral-300);\n border-color: var(--bv-color-neutral-300);\n cursor: not-allowed;\n}\n\n/* \u2500\u2500 Validation error states (BTN-10191 / BTN-10312) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n/*\n * `.invalid` is applied to input fields only when the field's error resolves\n * to severity 'error' (blocking). Non-blocking severities (warning/primary/\n * success) surface via the banner but do not paint the input red.\n */\n.date-input.invalid,\n.date-input.invalid:focus {\n border-color: var(--bv-color-danger);\n box-shadow: 0 0 0 3px var(--bv-color-danger-light);\n}\n\n.day--disabled,\n.day[disabled] {\n color: var(--bv-color-neutral-300);\n cursor: not-allowed;\n pointer-events: none;\n}\n\n.day--disabled .day-inner,\n.day[disabled] .day-inner {\n color: var(--bv-color-neutral-300);\n}\n";
|
|
3
|
+
|
|
4
|
+
// components/_shared/adopt-styles.ts
|
|
5
|
+
var _sheetCache = /* @__PURE__ */ new Map();
|
|
6
|
+
function adoptStyles(shadow, css) {
|
|
7
|
+
if ("adoptedStyleSheets" in ShadowRoot.prototype && typeof CSSStyleSheet !== "undefined" && "replaceSync" in CSSStyleSheet.prototype) {
|
|
8
|
+
let sheet = _sheetCache.get(css);
|
|
9
|
+
if (!sheet) {
|
|
10
|
+
sheet = new CSSStyleSheet();
|
|
11
|
+
sheet.replaceSync(css);
|
|
12
|
+
_sheetCache.set(css, sheet);
|
|
13
|
+
}
|
|
14
|
+
shadow.adoptedStyleSheets = [sheet];
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
const style = document.createElement("style");
|
|
18
|
+
style.textContent = css;
|
|
19
|
+
shadow.appendChild(style);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// components/_shared/date-range-validator.ts
|
|
23
|
+
var ALLOWED_SEVERITIES = ["error", "warning", "primary", "success"];
|
|
24
|
+
function normalizeSeverity(value) {
|
|
25
|
+
if (value && ALLOWED_SEVERITIES.includes(value)) {
|
|
26
|
+
return value;
|
|
27
|
+
}
|
|
28
|
+
return "error";
|
|
29
|
+
}
|
|
30
|
+
function validateDateRange(input, config = {}) {
|
|
31
|
+
const { start, end } = input;
|
|
32
|
+
const { min, max, maxRangeYears, validateOrder, validateFormat } = config;
|
|
33
|
+
const resolvedMax = max === "today" ? isoToday() : max;
|
|
34
|
+
let startError;
|
|
35
|
+
let endError;
|
|
36
|
+
const startDate = start ? parseIso(start) : null;
|
|
37
|
+
const endDate = end ? parseIso(end) : null;
|
|
38
|
+
if (validateFormat) {
|
|
39
|
+
if (start && !startDate) startError = "format";
|
|
40
|
+
if (end && !endDate) endError = "format";
|
|
41
|
+
}
|
|
42
|
+
if (!startError && startDate) {
|
|
43
|
+
if (min && belowMin(startDate, min)) startError = "min";
|
|
44
|
+
else if (resolvedMax && aboveMax(startDate, resolvedMax)) startError = "max";
|
|
45
|
+
}
|
|
46
|
+
if (!endError && endDate) {
|
|
47
|
+
if (min && belowMin(endDate, min)) endError = "min";
|
|
48
|
+
else if (resolvedMax && aboveMax(endDate, resolvedMax)) endError = "max";
|
|
49
|
+
}
|
|
50
|
+
let formError;
|
|
51
|
+
const bothFieldsClean = startDate && endDate && !startError && !endError;
|
|
52
|
+
if (bothFieldsClean) {
|
|
53
|
+
if (validateOrder && startDate > endDate) {
|
|
54
|
+
formError = "order";
|
|
55
|
+
} else if (maxRangeYears !== void 0 && exceedsYearSpan(startDate, endDate, maxRangeYears)) {
|
|
56
|
+
formError = "range-limit";
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
const valid = !startError && !endError && !formError;
|
|
60
|
+
const startSev = startError ? severityOfFieldError(startError, config) : null;
|
|
61
|
+
const endSev = endError ? severityOfFieldError(endError, config) : null;
|
|
62
|
+
const formSev = formError ? severityOfFormError(formError, config) : null;
|
|
63
|
+
const hasBlockingError = startSev === "error" || endSev === "error" || formSev === "error";
|
|
64
|
+
const applyEnabled = !hasBlockingError && !!startDate && !!endDate;
|
|
65
|
+
return {
|
|
66
|
+
valid,
|
|
67
|
+
applyEnabled,
|
|
68
|
+
...startError && { startError },
|
|
69
|
+
...endError && { endError },
|
|
70
|
+
...formError && { formError }
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
function severityOfFieldError(err, config) {
|
|
74
|
+
if (err === "format") return normalizeSeverity(config.formatSeverity);
|
|
75
|
+
if (err === "min") return normalizeSeverity(config.minSeverity);
|
|
76
|
+
return normalizeSeverity(config.maxSeverity);
|
|
77
|
+
}
|
|
78
|
+
function severityOfFormError(err, config) {
|
|
79
|
+
if (err === "order") return normalizeSeverity(config.orderSeverity);
|
|
80
|
+
return normalizeSeverity(config.rangeLimitSeverity);
|
|
81
|
+
}
|
|
82
|
+
function parseIso(s) {
|
|
83
|
+
const m = /^(\d{4})-(\d{2})-(\d{2})$/.exec(s);
|
|
84
|
+
if (!m) return null;
|
|
85
|
+
const [, yStr, mStr, dStr] = m;
|
|
86
|
+
const y = Number(yStr);
|
|
87
|
+
const mo = Number(mStr) - 1;
|
|
88
|
+
const d = Number(dStr);
|
|
89
|
+
const dt = new Date(y, mo, d);
|
|
90
|
+
if (dt.getFullYear() !== y || dt.getMonth() !== mo || dt.getDate() !== d) return null;
|
|
91
|
+
dt.setHours(0, 0, 0, 0);
|
|
92
|
+
return dt;
|
|
93
|
+
}
|
|
94
|
+
function isoToday() {
|
|
95
|
+
const now = /* @__PURE__ */ new Date();
|
|
96
|
+
const y = now.getFullYear();
|
|
97
|
+
const m = String(now.getMonth() + 1).padStart(2, "0");
|
|
98
|
+
const d = String(now.getDate()).padStart(2, "0");
|
|
99
|
+
return `${y}-${m}-${d}`;
|
|
100
|
+
}
|
|
101
|
+
function belowMin(date, minIso) {
|
|
102
|
+
const minDate = parseIso(minIso);
|
|
103
|
+
return !!minDate && date < minDate;
|
|
104
|
+
}
|
|
105
|
+
function aboveMax(date, maxIso) {
|
|
106
|
+
const maxDate = parseIso(maxIso);
|
|
107
|
+
return !!maxDate && date > maxDate;
|
|
108
|
+
}
|
|
109
|
+
function exceedsYearSpan(start, end, years) {
|
|
110
|
+
const cutoff = new Date(start);
|
|
111
|
+
cutoff.setFullYear(cutoff.getFullYear() + years);
|
|
112
|
+
return end > cutoff;
|
|
113
|
+
}
|
|
3
114
|
|
|
4
115
|
// css-inline:/home/runner/work/BV_lumen/BV_lumen/components/bv-alert-banner/bv-alert-banner.css
|
|
5
116
|
var bv_alert_banner_default = ":host {\n --banner-bg: var(--bv-color-neutral-0);\n --banner-border: var(--bv-color-neutral-200);\n --banner-color: var(--bv-color-neutral-700);\n --banner-color-subtle: var(--bv-color-neutral-500);\n --banner-icon-color: var(--bv-color-neutral-500);\n\n display: block;\n font-family: var(--bv-font-family-base);\n}\n\n:host([hidden]) {\n display: none;\n}\n\n:host([variant='primary']) {\n --banner-bg: var(--bv-color-primary-50);\n --banner-border: color-mix(in srgb, var(--bv-color-primary) 40%, var(--bv-color-neutral-0));\n --banner-color: var(--bv-color-primary);\n --banner-color-subtle: var(--bv-color-primary);\n --banner-icon-color: var(--bv-color-primary);\n}\n\n:host([variant='error']) {\n --banner-bg: color-mix(in srgb, var(--bv-color-danger-light) 35%, var(--bv-color-neutral-0));\n --banner-border: color-mix(in srgb, var(--bv-color-danger) 45%, var(--bv-color-neutral-0));\n --banner-color: var(--bv-color-danger-dark);\n --banner-color-subtle: var(--bv-color-danger-dark);\n --banner-icon-color: var(--bv-color-danger);\n}\n\n:host([variant='warning']) {\n --banner-bg: color-mix(in srgb, var(--bv-color-warning-light) 35%, var(--bv-color-neutral-0));\n --banner-border: color-mix(in srgb, var(--bv-color-warning) 50%, var(--bv-color-neutral-0));\n --banner-color: var(--bv-color-warning-dark);\n --banner-color-subtle: var(--bv-color-warning-dark);\n --banner-icon-color: var(--bv-color-warning);\n}\n\n:host([variant='success']) {\n --banner-bg: color-mix(in srgb, var(--bv-color-success-light) 30%, var(--bv-color-neutral-0));\n --banner-border: color-mix(in srgb, var(--bv-color-success) 40%, var(--bv-color-neutral-0));\n --banner-color: var(--bv-color-success-dark);\n --banner-color-subtle: var(--bv-color-success-dark);\n --banner-icon-color: var(--bv-color-success);\n}\n\n/* \u2500\u2500 Banner \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.banner {\n display: flex;\n align-items: flex-start;\n gap: var(--bv-spacing-md);\n padding: var(--bv-spacing-md);\n background: var(--banner-bg);\n border: 1px solid var(--banner-border);\n border-radius: var(--bv-radius-xl);\n}\n\n/* \u2500\u2500 Icon \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.banner-icon {\n display: flex;\n flex-shrink: 0;\n margin-top: 0;\n color: var(--banner-icon-color);\n line-height: 0;\n}\n\n/* \u2500\u2500 Content \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.banner-content {\n flex: 1;\n display: flex;\n flex-direction: column;\n gap: var(--bv-spacing-xs);\n min-width: 0;\n}\n\n.banner-heading {\n margin: 0;\n font-size: var(--bv-font-size-sm);\n font-weight: var(--bv-font-weight-semibold);\n line-height: 20px;\n color: var(--banner-color);\n}\n\n.banner-heading[hidden] {\n display: none;\n}\n\n.banner-message {\n margin: 0;\n font-size: var(--bv-font-size-sm);\n font-weight: var(--bv-font-weight-regular);\n line-height: 20px;\n color: var(--banner-color);\n}\n\n.banner-message[hidden] {\n display: none;\n}\n\n/* \u2500\u2500 Actions \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.banner-actions {\n display: flex;\n align-items: center;\n gap: var(--bv-spacing-md);\n margin-top: var(--bv-spacing-xs);\n}\n\n.banner-actions[hidden] {\n display: none;\n}\n\n.action-btn {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n background: none;\n border: none;\n padding: 0;\n cursor: pointer;\n font-family: inherit;\n font-size: var(--bv-font-size-sm);\n font-weight: var(--bv-font-weight-semibold);\n line-height: 20px;\n color: var(--banner-color);\n transition: opacity 0.15s;\n}\n\n.action-btn[hidden] {\n display: none;\n}\n\n.action-btn:hover {\n opacity: 0.75;\n}\n\n.action-btn:focus-visible {\n outline: 2px solid var(--banner-color);\n outline-offset: 2px;\n border-radius: var(--bv-radius-sm);\n}\n\n/* \u2500\u2500 Close button \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.close-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n width: 32px;\n height: 32px;\n margin: -6px -6px 0 0;\n background: none;\n border: none;\n border-radius: var(--bv-radius-lg);\n cursor: pointer;\n color: var(--banner-icon-color);\n transition: background 0.15s;\n padding: 0;\n}\n\n.close-btn[hidden] {\n display: none;\n}\n\n.close-btn:hover {\n background: color-mix(in srgb, var(--banner-border) 60%, var(--banner-bg));\n}\n\n.close-btn:focus-visible {\n outline: 2px solid var(--banner-color);\n outline-offset: 2px;\n}\n";
|
|
@@ -18,14 +129,6 @@ var VARIANT_ICONS = {
|
|
|
18
129
|
warning: ICON_ALERT_TRIANGLE,
|
|
19
130
|
success: ICON_CHECK_CIRCLE
|
|
20
131
|
};
|
|
21
|
-
var _sheet = null;
|
|
22
|
-
function getSheet() {
|
|
23
|
-
if (!_sheet) {
|
|
24
|
-
_sheet = new CSSStyleSheet();
|
|
25
|
-
_sheet.replaceSync(bv_alert_banner_default);
|
|
26
|
-
}
|
|
27
|
-
return _sheet;
|
|
28
|
-
}
|
|
29
132
|
var BvAlertBanner = class extends HTMLElement {
|
|
30
133
|
static observedAttributes = [
|
|
31
134
|
"variant",
|
|
@@ -45,10 +148,7 @@ var BvAlertBanner = class extends HTMLElement {
|
|
|
45
148
|
_closeBtn = null;
|
|
46
149
|
constructor() {
|
|
47
150
|
super();
|
|
48
|
-
|
|
49
|
-
if ("adoptedStyleSheets" in ShadowRoot.prototype) {
|
|
50
|
-
shadow.adoptedStyleSheets = [getSheet()];
|
|
51
|
-
}
|
|
151
|
+
adoptStyles(this.attachShadow({ mode: "open" }), bv_alert_banner_default);
|
|
52
152
|
}
|
|
53
153
|
get variant() {
|
|
54
154
|
return this.getAttribute("variant") ?? "default";
|
|
@@ -102,11 +202,6 @@ var BvAlertBanner = class extends HTMLElement {
|
|
|
102
202
|
if (this._rendered) return;
|
|
103
203
|
this._rendered = true;
|
|
104
204
|
const shadow = this.shadowRoot;
|
|
105
|
-
if (!shadow.adoptedStyleSheets.length) {
|
|
106
|
-
const s = document.createElement("style");
|
|
107
|
-
s.textContent = bv_alert_banner_default;
|
|
108
|
-
shadow.appendChild(s);
|
|
109
|
-
}
|
|
110
205
|
const banner = document.createElement("div");
|
|
111
206
|
banner.className = "banner";
|
|
112
207
|
banner.setAttribute("role", "alert");
|
|
@@ -233,14 +328,6 @@ var MONTH_NAMES = [
|
|
|
233
328
|
var WEEKDAYS = ["Mo", "Tu", "We", "Th", "Fr", "Sat", "Su"];
|
|
234
329
|
var CHEVRON_LEFT = `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M15 18l-6-6 6-6"/></svg>`;
|
|
235
330
|
var CHEVRON_RIGHT = `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M9 18l6-6-6-6"/></svg>`;
|
|
236
|
-
var _sheet2 = null;
|
|
237
|
-
function getSheet2() {
|
|
238
|
-
if (!_sheet2) {
|
|
239
|
-
_sheet2 = new CSSStyleSheet();
|
|
240
|
-
_sheet2.replaceSync(bv_date_range_picker_default);
|
|
241
|
-
}
|
|
242
|
-
return _sheet2;
|
|
243
|
-
}
|
|
244
331
|
function dateToIso(d) {
|
|
245
332
|
return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}-${String(d.getDate()).padStart(2, "0")}`;
|
|
246
333
|
}
|
|
@@ -256,6 +343,9 @@ function parseDisplay(str) {
|
|
|
256
343
|
const d = match[2].padStart(2, "0");
|
|
257
344
|
return `${match[3]}-${m}-${d}`;
|
|
258
345
|
}
|
|
346
|
+
function capitalize(s) {
|
|
347
|
+
return s.charAt(0).toUpperCase() + s.slice(1);
|
|
348
|
+
}
|
|
259
349
|
function getPresetDates(key) {
|
|
260
350
|
const now = /* @__PURE__ */ new Date();
|
|
261
351
|
now.setHours(0, 0, 0, 0);
|
|
@@ -298,7 +388,31 @@ function getPresetDates(key) {
|
|
|
298
388
|
}
|
|
299
389
|
}
|
|
300
390
|
var BvDateRangePicker = class extends HTMLElement {
|
|
301
|
-
static observedAttributes = [
|
|
391
|
+
static observedAttributes = [
|
|
392
|
+
"start",
|
|
393
|
+
"end",
|
|
394
|
+
"preset",
|
|
395
|
+
// BTN-10191 — opt-in validation config
|
|
396
|
+
"min",
|
|
397
|
+
"max",
|
|
398
|
+
"max-range-years",
|
|
399
|
+
"validate-order",
|
|
400
|
+
"validate-format",
|
|
401
|
+
"show-range-limit-banner",
|
|
402
|
+
// BTN-10191 — configurable error copy (all attributes; defaults apply otherwise)
|
|
403
|
+
"error-min",
|
|
404
|
+
"error-max",
|
|
405
|
+
"error-order",
|
|
406
|
+
"error-format",
|
|
407
|
+
"range-limit-message",
|
|
408
|
+
"range-limit-heading",
|
|
409
|
+
// BTN-10312 — per-error severity (default error = blocks Apply + red banner)
|
|
410
|
+
"error-min-severity",
|
|
411
|
+
"error-max-severity",
|
|
412
|
+
"error-format-severity",
|
|
413
|
+
"error-order-severity",
|
|
414
|
+
"range-limit-severity"
|
|
415
|
+
];
|
|
302
416
|
_rendered = false;
|
|
303
417
|
_today;
|
|
304
418
|
_start = "";
|
|
@@ -308,6 +422,12 @@ var BvDateRangePicker = class extends HTMLElement {
|
|
|
308
422
|
_hover = "";
|
|
309
423
|
_leftYear;
|
|
310
424
|
_leftMonth;
|
|
425
|
+
// BTN-10191 — raw display strings retained when the user types an
|
|
426
|
+
// unparseable value AND `validate-format` is on. Lets V8 fire without
|
|
427
|
+
// corrupting `_start`/`_end` (which stay strictly ISO for consumers).
|
|
428
|
+
_startRawInvalid = "";
|
|
429
|
+
_endRawInvalid = "";
|
|
430
|
+
_validity = { valid: true, applyEnabled: false };
|
|
311
431
|
_leftGrid = null;
|
|
312
432
|
_rightGrid = null;
|
|
313
433
|
_leftTitle = null;
|
|
@@ -315,9 +435,22 @@ var BvDateRangePicker = class extends HTMLElement {
|
|
|
315
435
|
_startInput = null;
|
|
316
436
|
_endInput = null;
|
|
317
437
|
_applyBtn = null;
|
|
318
|
-
|
|
438
|
+
/**
|
|
439
|
+
* Unified alert banner (BTN-10312). Shows AT MOST ONE error at a time. When
|
|
440
|
+
* multiple errors are simultaneously active, the banner reflects the
|
|
441
|
+
* most-recently-edited field (see `_lastEditedField`).
|
|
442
|
+
*/
|
|
443
|
+
_alertBannerEl = null;
|
|
319
444
|
_leftDayMap = /* @__PURE__ */ new Map();
|
|
320
445
|
_rightDayMap = /* @__PURE__ */ new Map();
|
|
446
|
+
/**
|
|
447
|
+
* BTN-10312 — tracks which field the user most-recently interacted with.
|
|
448
|
+
* When both `startError` and `endError` are active, the banner shows the
|
|
449
|
+
* error corresponding to this field. Set to `null` when no field has been
|
|
450
|
+
* touched (initial render, or external attribute set); the resolver falls
|
|
451
|
+
* back to a stable precedence in that case.
|
|
452
|
+
*/
|
|
453
|
+
_lastEditedField = null;
|
|
321
454
|
constructor() {
|
|
322
455
|
super();
|
|
323
456
|
const now = /* @__PURE__ */ new Date();
|
|
@@ -325,10 +458,7 @@ var BvDateRangePicker = class extends HTMLElement {
|
|
|
325
458
|
this._today = dateToIso(now);
|
|
326
459
|
this._leftYear = now.getFullYear();
|
|
327
460
|
this._leftMonth = now.getMonth();
|
|
328
|
-
|
|
329
|
-
if ("adoptedStyleSheets" in ShadowRoot.prototype) {
|
|
330
|
-
shadow.adoptedStyleSheets = [getSheet2()];
|
|
331
|
-
}
|
|
461
|
+
adoptStyles(this.attachShadow({ mode: "open" }), bv_date_range_picker_default);
|
|
332
462
|
}
|
|
333
463
|
get start() {
|
|
334
464
|
return this._start;
|
|
@@ -352,14 +482,48 @@ var BvDateRangePicker = class extends HTMLElement {
|
|
|
352
482
|
this._render();
|
|
353
483
|
}
|
|
354
484
|
attributeChangedCallback(name, _old, val) {
|
|
355
|
-
if (name === "start")
|
|
356
|
-
|
|
485
|
+
if (name === "start") {
|
|
486
|
+
this._start = val ?? "";
|
|
487
|
+
this._startRawInvalid = "";
|
|
488
|
+
this._lastEditedField = null;
|
|
489
|
+
}
|
|
490
|
+
if (name === "end") {
|
|
491
|
+
this._end = val ?? "";
|
|
492
|
+
this._endRawInvalid = "";
|
|
493
|
+
this._lastEditedField = null;
|
|
494
|
+
}
|
|
357
495
|
if (name === "preset") this._preset = val ?? "";
|
|
358
496
|
if (!this._rendered) return;
|
|
497
|
+
if (name === "start" || name === "end" || name === "preset") {
|
|
498
|
+
this._syncCalendars();
|
|
499
|
+
this._syncInputs();
|
|
500
|
+
this._syncPresets();
|
|
501
|
+
}
|
|
502
|
+
this._syncValidity();
|
|
503
|
+
}
|
|
504
|
+
/**
|
|
505
|
+
* BTN-10312 — public reset of the picker's internal draft state to the
|
|
506
|
+
* currently committed `start` / `end` / `preset` attributes. Called by
|
|
507
|
+
* `bv-date-range-input` when the popup closes without Apply (Cancel,
|
|
508
|
+
* Escape, outside-click) so the next open shows the last-committed value
|
|
509
|
+
* cleanly, with no leftover error banners from the discarded edit.
|
|
510
|
+
*
|
|
511
|
+
* The external value is not modified — this only clears the draft.
|
|
512
|
+
*/
|
|
513
|
+
resetDraft() {
|
|
514
|
+
this._start = this.getAttribute("start") ?? "";
|
|
515
|
+
this._end = this.getAttribute("end") ?? "";
|
|
516
|
+
this._preset = this.getAttribute("preset") ?? "";
|
|
517
|
+
this._startRawInvalid = "";
|
|
518
|
+
this._endRawInvalid = "";
|
|
519
|
+
this._picking = false;
|
|
520
|
+
this._hover = "";
|
|
521
|
+
this._lastEditedField = null;
|
|
522
|
+
if (!this._rendered) return;
|
|
359
523
|
this._syncCalendars();
|
|
360
524
|
this._syncInputs();
|
|
361
525
|
this._syncPresets();
|
|
362
|
-
this.
|
|
526
|
+
this._syncValidity();
|
|
363
527
|
}
|
|
364
528
|
_render() {
|
|
365
529
|
if (this._rendered) return;
|
|
@@ -377,11 +541,6 @@ var BvDateRangePicker = class extends HTMLElement {
|
|
|
377
541
|
}
|
|
378
542
|
}
|
|
379
543
|
const shadow = this.shadowRoot;
|
|
380
|
-
if (!shadow.adoptedStyleSheets.length) {
|
|
381
|
-
const s = document.createElement("style");
|
|
382
|
-
s.textContent = bv_date_range_picker_default;
|
|
383
|
-
shadow.appendChild(s);
|
|
384
|
-
}
|
|
385
544
|
const picker = document.createElement("div");
|
|
386
545
|
picker.className = "picker";
|
|
387
546
|
const sidebar = document.createElement("div");
|
|
@@ -452,14 +611,8 @@ var BvDateRangePicker = class extends HTMLElement {
|
|
|
452
611
|
const bannerWrap = document.createElement("div");
|
|
453
612
|
bannerWrap.className = "banner-wrap";
|
|
454
613
|
const banner = document.createElement("bv-alert-banner");
|
|
455
|
-
banner.setAttribute("variant", "warning");
|
|
456
|
-
banner.setAttribute("heading", "Date range exceeds 5 years");
|
|
457
|
-
banner.setAttribute(
|
|
458
|
-
"message",
|
|
459
|
-
"Only CSV download is available for this date range. Live report generation is not supported."
|
|
460
|
-
);
|
|
461
614
|
banner.hidden = true;
|
|
462
|
-
this.
|
|
615
|
+
this._alertBannerEl = banner;
|
|
463
616
|
bannerWrap.appendChild(banner);
|
|
464
617
|
main.append(calsWrap, bannerWrap, footer);
|
|
465
618
|
picker.append(sidebar, main);
|
|
@@ -467,8 +620,7 @@ var BvDateRangePicker = class extends HTMLElement {
|
|
|
467
620
|
this._syncCalendars();
|
|
468
621
|
this._syncInputs();
|
|
469
622
|
this._syncPresets();
|
|
470
|
-
this.
|
|
471
|
-
this._syncBanner();
|
|
623
|
+
this._syncValidity();
|
|
472
624
|
}
|
|
473
625
|
_buildCalendarShell(side) {
|
|
474
626
|
const cal = document.createElement("div");
|
|
@@ -633,6 +785,7 @@ var BvDateRangePicker = class extends HTMLElement {
|
|
|
633
785
|
this._preset = "custom";
|
|
634
786
|
this._picking = true;
|
|
635
787
|
this._hover = "";
|
|
788
|
+
this._lastEditedField = "start";
|
|
636
789
|
} else {
|
|
637
790
|
if (iso < this._start) {
|
|
638
791
|
this._end = this._start;
|
|
@@ -643,12 +796,14 @@ var BvDateRangePicker = class extends HTMLElement {
|
|
|
643
796
|
this._picking = false;
|
|
644
797
|
this._hover = "";
|
|
645
798
|
this._preset = "custom";
|
|
799
|
+
this._lastEditedField = "end";
|
|
646
800
|
}
|
|
801
|
+
this._startRawInvalid = "";
|
|
802
|
+
this._endRawInvalid = "";
|
|
647
803
|
this._syncCalendars();
|
|
648
804
|
this._syncInputs();
|
|
649
805
|
this._syncPresets();
|
|
650
|
-
this.
|
|
651
|
-
this._syncBanner();
|
|
806
|
+
this._syncValidity();
|
|
652
807
|
}
|
|
653
808
|
_selectPreset(key) {
|
|
654
809
|
if (key === "custom") {
|
|
@@ -664,6 +819,9 @@ var BvDateRangePicker = class extends HTMLElement {
|
|
|
664
819
|
this._preset = key;
|
|
665
820
|
this._picking = false;
|
|
666
821
|
this._hover = "";
|
|
822
|
+
this._startRawInvalid = "";
|
|
823
|
+
this._endRawInvalid = "";
|
|
824
|
+
this._lastEditedField = null;
|
|
667
825
|
if (start) {
|
|
668
826
|
const parts = start.split("-");
|
|
669
827
|
const y = parseInt(parts[0], 10);
|
|
@@ -676,21 +834,48 @@ var BvDateRangePicker = class extends HTMLElement {
|
|
|
676
834
|
this._syncCalendars();
|
|
677
835
|
this._syncInputs();
|
|
678
836
|
this._syncPresets();
|
|
679
|
-
this.
|
|
680
|
-
this._syncBanner();
|
|
837
|
+
this._syncValidity();
|
|
681
838
|
}
|
|
682
839
|
_onInputBlur(input, field) {
|
|
683
|
-
|
|
840
|
+
this._lastEditedField = field;
|
|
841
|
+
const raw = input.value;
|
|
842
|
+
if (raw === "") {
|
|
843
|
+
if (field === "start") {
|
|
844
|
+
this._start = "";
|
|
845
|
+
this._startRawInvalid = "";
|
|
846
|
+
} else {
|
|
847
|
+
this._end = "";
|
|
848
|
+
this._endRawInvalid = "";
|
|
849
|
+
}
|
|
850
|
+
this._syncCalendars();
|
|
851
|
+
this._syncPresets();
|
|
852
|
+
this._syncValidity();
|
|
853
|
+
return;
|
|
854
|
+
}
|
|
855
|
+
const iso = parseDisplay(raw);
|
|
684
856
|
if (iso) {
|
|
685
|
-
if (field === "start")
|
|
686
|
-
|
|
857
|
+
if (field === "start") {
|
|
858
|
+
this._start = iso;
|
|
859
|
+
this._startRawInvalid = "";
|
|
860
|
+
} else {
|
|
861
|
+
this._end = iso;
|
|
862
|
+
this._endRawInvalid = "";
|
|
863
|
+
}
|
|
687
864
|
this._picking = false;
|
|
688
865
|
this._hover = "";
|
|
689
866
|
this._preset = "custom";
|
|
690
867
|
this._syncCalendars();
|
|
691
868
|
this._syncPresets();
|
|
692
|
-
this.
|
|
693
|
-
|
|
869
|
+
this._syncValidity();
|
|
870
|
+
} else if (this.hasAttribute("validate-format")) {
|
|
871
|
+
if (field === "start") {
|
|
872
|
+
this._start = "";
|
|
873
|
+
this._startRawInvalid = raw;
|
|
874
|
+
} else {
|
|
875
|
+
this._end = "";
|
|
876
|
+
this._endRawInvalid = raw;
|
|
877
|
+
}
|
|
878
|
+
this._syncValidity();
|
|
694
879
|
} else {
|
|
695
880
|
input.value = formatDisplay(field === "start" ? this._start : this._end);
|
|
696
881
|
}
|
|
@@ -705,33 +890,211 @@ var BvDateRangePicker = class extends HTMLElement {
|
|
|
705
890
|
btn.classList.toggle("active", btn.dataset["preset"] === this._preset);
|
|
706
891
|
});
|
|
707
892
|
}
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
893
|
+
// ── BTN-10191 — validation orchestrator ──────────────────────────────
|
|
894
|
+
_syncValidity() {
|
|
895
|
+
const cfg = this._readConfig();
|
|
896
|
+
const previous = this._validity;
|
|
897
|
+
this._validity = validateDateRange(
|
|
898
|
+
{
|
|
899
|
+
start: this._start || this._startRawInvalid,
|
|
900
|
+
end: this._end || this._endRawInvalid
|
|
901
|
+
},
|
|
902
|
+
cfg
|
|
903
|
+
);
|
|
904
|
+
this._paintInputInvalidState();
|
|
905
|
+
this._applyAlertBanner(cfg);
|
|
906
|
+
this._applyApplyState();
|
|
907
|
+
this._applyCalendarDisabledState();
|
|
908
|
+
if (previous.valid !== this._validity.valid || previous.applyEnabled !== this._validity.applyEnabled || previous.startError !== this._validity.startError || previous.endError !== this._validity.endError || previous.formError !== this._validity.formError) {
|
|
909
|
+
this.dispatchEvent(
|
|
910
|
+
new CustomEvent("bv-validity-change", {
|
|
911
|
+
bubbles: true,
|
|
912
|
+
composed: true,
|
|
913
|
+
detail: { ...this._validity }
|
|
914
|
+
})
|
|
915
|
+
);
|
|
916
|
+
}
|
|
917
|
+
}
|
|
918
|
+
_readConfig() {
|
|
919
|
+
const min = this.getAttribute("min") || void 0;
|
|
920
|
+
const max = this.getAttribute("max") || void 0;
|
|
921
|
+
const mryStr = this.getAttribute("max-range-years");
|
|
922
|
+
const maxRangeYears = mryStr !== null && mryStr !== "" ? Number(mryStr) : void 0;
|
|
923
|
+
return {
|
|
924
|
+
min,
|
|
925
|
+
max,
|
|
926
|
+
maxRangeYears: Number.isFinite(maxRangeYears) ? maxRangeYears : void 0,
|
|
927
|
+
validateOrder: this.hasAttribute("validate-order"),
|
|
928
|
+
validateFormat: this.hasAttribute("validate-format"),
|
|
929
|
+
minSeverity: normalizeSeverity(this.getAttribute("error-min-severity")),
|
|
930
|
+
maxSeverity: normalizeSeverity(this.getAttribute("error-max-severity")),
|
|
931
|
+
formatSeverity: normalizeSeverity(this.getAttribute("error-format-severity")),
|
|
932
|
+
orderSeverity: normalizeSeverity(this.getAttribute("error-order-severity")),
|
|
933
|
+
rangeLimitSeverity: normalizeSeverity(this.getAttribute("range-limit-severity"))
|
|
934
|
+
};
|
|
935
|
+
}
|
|
936
|
+
/**
|
|
937
|
+
* BTN-10312 — apply the `.invalid` + `aria-invalid` state to input fields
|
|
938
|
+
* whose field-level error is currently blocking (severity `'error'`).
|
|
939
|
+
* Non-blocking severities (warning/primary/success) do not paint the input
|
|
940
|
+
* red so the visual matches the semantic ("not a fatal error").
|
|
941
|
+
*/
|
|
942
|
+
_paintInputInvalidState() {
|
|
943
|
+
const v = this._validity;
|
|
944
|
+
const cfg = this._readConfig();
|
|
945
|
+
this._paintOne(this._startInput, v.startError ? severityOfFieldError(v.startError, cfg) : null);
|
|
946
|
+
this._paintOne(this._endInput, v.endError ? severityOfFieldError(v.endError, cfg) : null);
|
|
947
|
+
}
|
|
948
|
+
_paintOne(input, sev) {
|
|
949
|
+
if (!input) return;
|
|
950
|
+
if (sev === "error") {
|
|
951
|
+
input.classList.add("invalid");
|
|
952
|
+
input.setAttribute("aria-invalid", "true");
|
|
953
|
+
} else {
|
|
954
|
+
input.classList.remove("invalid");
|
|
955
|
+
input.removeAttribute("aria-invalid");
|
|
711
956
|
}
|
|
712
957
|
}
|
|
713
|
-
|
|
714
|
-
|
|
958
|
+
/**
|
|
959
|
+
* BTN-10312 — single alert banner. Picks the "active" error following the
|
|
960
|
+
* precedence:
|
|
961
|
+
*
|
|
962
|
+
* 1. If a form error is active, show it (form errors don't coexist with
|
|
963
|
+
* field errors by validator design).
|
|
964
|
+
* 2. If both field errors are active, show the one for
|
|
965
|
+
* `_lastEditedField` (falling back to `start` if `null`).
|
|
966
|
+
* 3. Else show whichever single field error is active.
|
|
967
|
+
* 4. Else hide the banner.
|
|
968
|
+
*
|
|
969
|
+
* `show-range-limit-banner="false"` still suppresses the range-limit
|
|
970
|
+
* banner specifically (existing consumer contract from BTN-10191).
|
|
971
|
+
*/
|
|
972
|
+
_applyAlertBanner(cfg) {
|
|
973
|
+
if (!this._alertBannerEl) return;
|
|
715
974
|
const pickerEl = this.shadowRoot.querySelector(".picker");
|
|
716
|
-
|
|
717
|
-
|
|
975
|
+
const active = this._resolveActiveError();
|
|
976
|
+
if (!active) {
|
|
977
|
+
this._alertBannerEl.hidden = true;
|
|
978
|
+
this._alertBannerEl.removeAttribute("heading");
|
|
979
|
+
this._alertBannerEl.removeAttribute("message");
|
|
718
980
|
pickerEl == null ? void 0 : pickerEl.classList.remove("picker--with-banner");
|
|
719
981
|
return;
|
|
720
982
|
}
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
983
|
+
if (active.kind === "form" && active.error === "range-limit" && this.getAttribute("show-range-limit-banner") === "false") {
|
|
984
|
+
this._alertBannerEl.hidden = true;
|
|
985
|
+
pickerEl == null ? void 0 : pickerEl.classList.remove("picker--with-banner");
|
|
986
|
+
return;
|
|
987
|
+
}
|
|
988
|
+
const variant = active.kind === "field" ? severityOfFieldError(active.error, cfg) : severityOfFormError(active.error, cfg);
|
|
989
|
+
this._alertBannerEl.setAttribute("variant", variant);
|
|
990
|
+
if (active.kind === "form" && active.error === "range-limit") {
|
|
991
|
+
const yearsAttr = this.getAttribute("max-range-years") ?? "";
|
|
992
|
+
const heading = this.getAttribute("range-limit-heading") || (yearsAttr ? `Date range exceeds ${yearsAttr} years` : "Date range exceeds the maximum");
|
|
993
|
+
const message = this.getAttribute("range-limit-message") || "Only CSV download is available for this date range. Live report generation is not supported.";
|
|
994
|
+
this._alertBannerEl.setAttribute("heading", heading.replace(/\{N\}/g, yearsAttr));
|
|
995
|
+
this._alertBannerEl.setAttribute("message", message.replace(/\{N\}/g, yearsAttr));
|
|
996
|
+
} else {
|
|
997
|
+
this._alertBannerEl.removeAttribute("heading");
|
|
998
|
+
const message = active.kind === "field" ? this._resolveFieldError(active.error, active.field) : this._resolveOrderError();
|
|
999
|
+
this._alertBannerEl.setAttribute("message", message);
|
|
1000
|
+
}
|
|
1001
|
+
this._alertBannerEl.hidden = false;
|
|
1002
|
+
pickerEl == null ? void 0 : pickerEl.classList.add("picker--with-banner");
|
|
1003
|
+
}
|
|
1004
|
+
/**
|
|
1005
|
+
* Pick which error the banner should reflect. See `_applyAlertBanner` for
|
|
1006
|
+
* the precedence rules.
|
|
1007
|
+
*/
|
|
1008
|
+
_resolveActiveError() {
|
|
1009
|
+
const v = this._validity;
|
|
1010
|
+
if (v.formError) return { kind: "form", error: v.formError };
|
|
1011
|
+
if (v.startError && v.endError) {
|
|
1012
|
+
const winner = this._lastEditedField ?? "start";
|
|
1013
|
+
return {
|
|
1014
|
+
kind: "field",
|
|
1015
|
+
error: winner === "start" ? v.startError : v.endError,
|
|
1016
|
+
field: winner
|
|
1017
|
+
};
|
|
1018
|
+
}
|
|
1019
|
+
if (v.startError) return { kind: "field", error: v.startError, field: "start" };
|
|
1020
|
+
if (v.endError) return { kind: "field", error: v.endError, field: "end" };
|
|
1021
|
+
return null;
|
|
1022
|
+
}
|
|
1023
|
+
_resolveFieldError(err, field) {
|
|
1024
|
+
if (err === "format") {
|
|
1025
|
+
const custom2 = this.getAttribute("error-format");
|
|
1026
|
+
if (custom2) return this._interpolateField(custom2, field);
|
|
1027
|
+
return `Enter a valid ${field} date`;
|
|
1028
|
+
}
|
|
1029
|
+
if (err === "min") {
|
|
1030
|
+
const minIso = this.getAttribute("min") ?? "";
|
|
1031
|
+
const minDisplay = formatDisplay(minIso);
|
|
1032
|
+
const custom2 = this.getAttribute("error-min");
|
|
1033
|
+
if (custom2) return this._interpolateField(custom2, field).replace(/\{min\}/g, minDisplay);
|
|
1034
|
+
return `${capitalize(field)} date must be on or after ${minDisplay}`;
|
|
1035
|
+
}
|
|
1036
|
+
const maxAttr = this.getAttribute("max") ?? "";
|
|
1037
|
+
const resolvedMax = maxAttr === "today" ? isoToday() : maxAttr;
|
|
1038
|
+
const maxDisplay = formatDisplay(resolvedMax);
|
|
1039
|
+
const custom = this.getAttribute("error-max");
|
|
1040
|
+
if (custom) return this._interpolateField(custom, field).replace(/\{max\}/g, maxDisplay);
|
|
1041
|
+
if (maxAttr === "today") return `${capitalize(field)} date cannot be in the future`;
|
|
1042
|
+
return `${capitalize(field)} date cannot be after ${maxDisplay}`;
|
|
1043
|
+
}
|
|
1044
|
+
/**
|
|
1045
|
+
* BTN-10312 — interpolate `{field}` (always lowercase) and `{Field}` (always
|
|
1046
|
+
* capitalized) in a user-provided template. Before this change, the historical
|
|
1047
|
+
* behavior was that `{field}` in custom copy resolved lowercase while the
|
|
1048
|
+
* built-in defaults capitalized inline — inconsistent. Now the split is
|
|
1049
|
+
* explicit: `{field}` = lowercase, `{Field}` = capitalized.
|
|
1050
|
+
*/
|
|
1051
|
+
_interpolateField(template, field) {
|
|
1052
|
+
return template.replace(/\{Field\}/g, capitalize(field)).replace(/\{field\}/g, field);
|
|
1053
|
+
}
|
|
1054
|
+
_resolveOrderError() {
|
|
1055
|
+
return this.getAttribute("error-order") || "Start date must be on or before end date";
|
|
1056
|
+
}
|
|
1057
|
+
_applyApplyState() {
|
|
1058
|
+
if (this._applyBtn) {
|
|
1059
|
+
this._applyBtn.disabled = !this._validity.applyEnabled;
|
|
1060
|
+
}
|
|
1061
|
+
}
|
|
1062
|
+
_applyCalendarDisabledState() {
|
|
1063
|
+
const minIso = this.getAttribute("min") || "";
|
|
1064
|
+
const maxAttr = this.getAttribute("max") || "";
|
|
1065
|
+
const maxIso = maxAttr === "today" ? isoToday() : maxAttr;
|
|
1066
|
+
if (!minIso && !maxIso) {
|
|
1067
|
+
this._leftDayMap.forEach((btn) => this._resetDayDisabled(btn));
|
|
1068
|
+
this._rightDayMap.forEach((btn) => this._resetDayDisabled(btn));
|
|
1069
|
+
return;
|
|
1070
|
+
}
|
|
1071
|
+
const paint = (btn, iso) => {
|
|
1072
|
+
const outOfRange = !!minIso && iso < minIso || !!maxIso && iso > maxIso;
|
|
1073
|
+
if (outOfRange) {
|
|
1074
|
+
btn.disabled = true;
|
|
1075
|
+
btn.setAttribute("aria-disabled", "true");
|
|
1076
|
+
btn.classList.add("day--disabled");
|
|
1077
|
+
} else {
|
|
1078
|
+
this._resetDayDisabled(btn);
|
|
1079
|
+
}
|
|
1080
|
+
};
|
|
1081
|
+
this._leftDayMap.forEach(paint);
|
|
1082
|
+
this._rightDayMap.forEach(paint);
|
|
1083
|
+
}
|
|
1084
|
+
_resetDayDisabled(btn) {
|
|
1085
|
+
btn.disabled = false;
|
|
1086
|
+
btn.removeAttribute("aria-disabled");
|
|
1087
|
+
btn.classList.remove("day--disabled");
|
|
727
1088
|
}
|
|
728
1089
|
// Auto-insert slashes after MM and DD digits while the user types forward.
|
|
729
|
-
// Also
|
|
1090
|
+
// Also runs full validity sync on every keystroke — this is what clears the
|
|
1091
|
+
// error state immediately on correction (per BTN-10191 a11y requirement).
|
|
730
1092
|
_setupDateMask(input, field) {
|
|
731
1093
|
input.addEventListener("input", (e) => {
|
|
732
1094
|
var _a;
|
|
733
1095
|
const ev = e;
|
|
734
1096
|
if ((_a = ev.inputType) == null ? void 0 : _a.startsWith("delete")) return;
|
|
1097
|
+
this._lastEditedField = field;
|
|
735
1098
|
const digits = input.value.replace(/[^\d]/g, "");
|
|
736
1099
|
let formatted;
|
|
737
1100
|
if (digits.length <= 2) {
|
|
@@ -743,17 +1106,19 @@ var BvDateRangePicker = class extends HTMLElement {
|
|
|
743
1106
|
formatted = digits.slice(0, 2) + "/" + digits.slice(2, 4) + "/" + digits.slice(4, 8);
|
|
744
1107
|
}
|
|
745
1108
|
input.value = formatted;
|
|
1109
|
+
if (field === "start") this._startRawInvalid = "";
|
|
1110
|
+
else this._endRawInvalid = "";
|
|
746
1111
|
if (formatted.length === 10) {
|
|
747
1112
|
const iso = parseDisplay(formatted);
|
|
748
1113
|
if (iso) {
|
|
749
1114
|
if (field === "start") this._start = iso;
|
|
750
1115
|
else this._end = iso;
|
|
751
|
-
this._syncBanner();
|
|
752
1116
|
}
|
|
753
|
-
} else
|
|
754
|
-
this._start = "";
|
|
755
|
-
this.
|
|
1117
|
+
} else {
|
|
1118
|
+
if (field === "start") this._start = "";
|
|
1119
|
+
else this._end = "";
|
|
756
1120
|
}
|
|
1121
|
+
this._syncValidity();
|
|
757
1122
|
});
|
|
758
1123
|
}
|
|
759
1124
|
_apply() {
|