@bluevolt-tech/lumen 2.1.0 → 2.3.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.
@@ -15,9 +15,14 @@
15
15
  * 4. Feature limit (V6) — last, only when both fields are individually
16
16
  * valid AND the cross-field check passes.
17
17
  *
18
+ * Per BTN-10312 each rule has a **severity** (`error` / `warning` / `primary` /
19
+ * `success`). Only `error` blocks Apply. Default severity is `error` for every
20
+ * rule so the behavior of consumers not opting in is preserved.
21
+ *
18
22
  * The consumer decides how to render each error — this module has no strings
19
23
  * and no DOM.
20
24
  */
25
+ export type ErrorSeverity = 'error' | 'warning' | 'primary' | 'success';
21
26
  export interface DateRangeConfig {
22
27
  /** ISO date string (YYYY-MM-DD). Enables V1/V2 (lower bound) when set. */
23
28
  min?: string;
@@ -29,6 +34,16 @@ export interface DateRangeConfig {
29
34
  validateOrder?: boolean;
30
35
  /** Opt-in to V8 (format guard — non-parseable strings become field errors). */
31
36
  validateFormat?: boolean;
37
+ /** Severity of `min` field error. Default `'error'` (blocks Apply). */
38
+ minSeverity?: ErrorSeverity;
39
+ /** Severity of `max` field error. Default `'error'` (blocks Apply). */
40
+ maxSeverity?: ErrorSeverity;
41
+ /** Severity of `format` field error. Default `'error'` (blocks Apply). */
42
+ formatSeverity?: ErrorSeverity;
43
+ /** Severity of `order` form error. Default `'error'` (blocks Apply). */
44
+ orderSeverity?: ErrorSeverity;
45
+ /** Severity of `range-limit` form error. Default `'error'` (blocks Apply). */
46
+ rangeLimitSeverity?: ErrorSeverity;
32
47
  }
33
48
  export interface DateRangeInput {
34
49
  /** Raw ISO string (YYYY-MM-DD) or empty. Non-empty non-parseable strings become format errors when V8 is on. */
@@ -46,13 +61,23 @@ export type FormError = 'order' | 'range-limit';
46
61
  export interface DateRangeValidity {
47
62
  /** True when NO rule fires (field-level or form-level). Does not consider whether both dates are set. */
48
63
  valid: boolean;
49
- /** True when `valid` AND both `start` and `end` parse to real dates. Consumer disables Apply when this is false. */
64
+ /**
65
+ * True when no *blocking* error is active AND both `start` and `end` parse to real dates.
66
+ * An error is blocking iff its resolved severity is `'error'`. Consumer disables Apply
67
+ * when this is false.
68
+ */
50
69
  applyEnabled: boolean;
51
70
  startError?: FieldError;
52
71
  endError?: FieldError;
53
72
  formError?: FormError;
54
73
  }
74
+ /** Coerce an unknown value to a valid severity, defaulting to `'error'`. */
75
+ export declare function normalizeSeverity(value: string | ErrorSeverity | undefined | null): ErrorSeverity;
55
76
  export declare function validateDateRange(input: DateRangeInput, config?: DateRangeConfig): DateRangeValidity;
77
+ /** Resolve the configured severity for a field error kind. */
78
+ export declare function severityOfFieldError(err: FieldError, config: DateRangeConfig): ErrorSeverity;
79
+ /** Resolve the configured severity for a form error kind. */
80
+ export declare function severityOfFormError(err: FormError, config: DateRangeConfig): ErrorSeverity;
56
81
  /**
57
82
  * Strict ISO parser. Accepts `YYYY-MM-DD` where every field is a real calendar
58
83
  * date. Rejects `2026-02-30` (JS Date would auto-correct it to 2026-03-02).
@@ -1,8 +1,37 @@
1
+ /**
2
+ * Why the dropdown is closing:
3
+ * - `'escape'` — user pressed Escape.
4
+ * - `'outside-click'` — user clicked outside the host.
5
+ * - `'programmatic'` — consumer called `close()` or `toggle()`, or the user
6
+ * clicked the trigger to close it (also routed through `toggle()`). This
7
+ * also covers the Apply / Cancel path in `bv-date-range-input`, which
8
+ * listens for `bv-change` / `bv-cancel` from the internal picker and
9
+ * calls `close()` on the controller.
10
+ *
11
+ * Consumers use `reason` in their `canClose` gate to distinguish implicit
12
+ * dismissals (Escape / outside-click) from explicit user actions
13
+ * (Cancel button, Apply, trigger toggle). A validity gate typically wants
14
+ * to block only implicit dismissals so the user can always intentionally
15
+ * back out of an invalid state.
16
+ */
17
+ export type CloseReason = 'escape' | 'outside-click' | 'programmatic';
1
18
  export interface DropdownControllerOptions {
2
19
  /** Element whose `aria-expanded` should mirror the open state — usually the trigger. */
3
20
  trigger?: HTMLElement | null;
4
21
  /** Called just before opening. Use for lazy state seeding (e.g. syncing an internal picker). */
5
22
  onBeforeOpen?: () => void;
23
+ /**
24
+ * Called just before closing. Return `false` to prevent the close.
25
+ * `reason` (BTN-10312 refinement) lets the consumer gate only implicit
26
+ * dismissals (Escape / outside-click) while still allowing explicit user
27
+ * actions (Cancel / Apply / trigger toggle) to close.
28
+ */
29
+ canClose?: (reason: CloseReason) => boolean;
30
+ /**
31
+ * Called immediately after a successful close. Use for cleanup that should run
32
+ * on every close path (e.g. resetting an internal draft state).
33
+ */
34
+ onAfterClose?: () => void;
6
35
  }
7
36
  export interface DropdownController {
8
37
  open: () => void;
@@ -21,6 +50,22 @@ export interface DropdownController {
21
50
  * the state. The controller is the single source of truth; consuming
22
51
  * components must NOT duplicate this sync in their own attributeChangedCallback.
23
52
  * - `bv-open` is dispatched from the host when opening via `open()`/`toggle()`.
53
+ * - `bv-dropdown-close` is dispatched from the host on every successful close,
54
+ * with `detail: { reason }` matching the `CloseReason` union — consumers can
55
+ * use it to close sibling dropdowns or release focus/scroll locks. The name
56
+ * is prefixed to avoid colliding with `bv-modal` / `bv-course-detail-modal`,
57
+ * which dispatch a bare `bv-close` on dismissal — a plain `bv-close` here
58
+ * would bubble into ancestor `bv-close` listeners (e.g. a modal that
59
+ * contains a dropdown) and fire spuriously on every dropdown dismissal.
60
+ *
61
+ * **Consumers MUST NOT call `e.stopPropagation()` on the trigger click**
62
+ * (BTN-10408). The outside-click listener attached here on `document` uses
63
+ * `composedPath().includes(host)` to skip clicks that originated inside its
64
+ * own host — so it already ignores the trigger click without needing the
65
+ * event to be swallowed. Stopping propagation on the trigger prevents the
66
+ * `document`-level listeners attached by *sibling* controllers from
67
+ * receiving the click at all, which is why opening one dropdown while
68
+ * another is open used to leave both visible.
24
69
  *
25
70
  * The controller mutates the `open` attribute on the host. Consumers should
26
71
  * drive their visual state (`.panel` visibility, focus management) from that
@@ -1,12 +1,18 @@
1
1
  import '../bv-date-range-picker/bv-date-range-picker.ts';
2
2
  export declare class BvDateRangeInput extends HTMLElement {
3
- static readonly observedAttributes: readonly ["label", "start", "end", "placeholder", "required", "min", "max", "max-range-years", "validate-order", "validate-format", "show-range-limit-banner", "error-min", "error-max", "error-order", "error-format", "range-limit-message", "range-limit-heading"];
3
+ static readonly observedAttributes: readonly ["label", "start", "end", "placeholder", "required", "keep-open-while-invalid", "min", "max", "max-range-years", "validate-order", "validate-format", "show-range-limit-banner", "error-min", "error-max", "error-order", "error-format", "range-limit-message", "range-limit-heading", "error-min-severity", "error-max-severity", "error-format-severity", "error-order-severity", "range-limit-severity"];
4
4
  private _rendered;
5
5
  private _labelEl;
6
6
  private _displayEl;
7
7
  private _triggerEl;
8
8
  private _pickerEl;
9
9
  private _dropdown;
10
+ /**
11
+ * BTN-10312 — cached validity from the internal picker. `canClose` on the
12
+ * dropdown controller consults this to gate popup close when
13
+ * `keep-open-while-invalid` is set.
14
+ */
15
+ private _pickerValidity;
10
16
  constructor();
11
17
  get start(): string;
12
18
  set start(v: string);