@nordhealth/components 5.0.0 → 5.0.2
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 +26062 -25769
- package/lib/AsideDrawer.js +2 -2
- package/lib/AsideDrawer.js.map +1 -1
- package/lib/AsideTrigger.js +2 -2
- package/lib/AsideTrigger.js.map +1 -1
- package/lib/Autocomplete.js +1 -1
- package/lib/Autocomplete.js.map +1 -1
- package/lib/Button.js +2 -2
- package/lib/Button.js.map +1 -1
- package/lib/Calendar.js +1 -1
- package/lib/Combobox.js +1 -1
- package/lib/Combobox.js.map +1 -1
- package/lib/ComboboxBase.js +1 -1
- package/lib/ComboboxBase.js.map +1 -1
- package/lib/CommandMenu.js +1 -1
- package/lib/CommandMenu.js.map +1 -1
- package/lib/DatePicker.js +1 -1
- package/lib/DatePicker.js.map +1 -1
- package/lib/DateRangePicker.js +1 -1
- package/lib/DateRangePicker.js.map +1 -1
- package/lib/Dropdown.js +1 -1
- package/lib/Dropdown.js.map +1 -1
- package/lib/DropdownSubmenu.js +1 -1
- package/lib/FilterAddButton.js +1 -1
- package/lib/FilterAddButton.js.map +1 -1
- package/lib/FilterDateRange.js +1 -1
- package/lib/FilterDateRange.js.map +1 -1
- package/lib/FilterDropdown.js +1 -1
- package/lib/FilterDropdown.js.map +1 -1
- package/lib/FilterField.js +1 -1
- package/lib/FilterField.js.map +1 -1
- package/lib/FilterInput.js +1 -1
- package/lib/FilterInput.js.map +1 -1
- package/lib/FilterResetButton.js +1 -1
- package/lib/FilterResetButton.js.map +1 -1
- package/lib/Header.js +1 -1
- package/lib/Header.js.map +1 -1
- package/lib/IconManager.js +1 -1
- package/lib/Input.js +1 -1
- package/lib/Item.js +1 -1
- package/lib/Item.js.map +1 -1
- package/lib/Layout.js +1 -1
- package/lib/Layout.js.map +1 -1
- package/lib/LocalizeController.js +1 -1
- package/lib/LocalizeController.js.map +1 -1
- package/lib/Message.js +1 -1
- package/lib/Message.js.map +1 -1
- package/lib/Modal.js +1 -1
- package/lib/Modal.js.map +1 -1
- package/lib/NavGroup.js +1 -1
- package/lib/NavGroup.js.map +1 -1
- package/lib/NavItem.js +1 -1
- package/lib/NavItem.js.map +1 -1
- package/lib/NavToggle-ROsuaJkW.js +2 -0
- package/lib/{NavToggle-BY83xpx0.js.map → NavToggle-ROsuaJkW.js.map} +1 -1
- package/lib/NavToggle.js +1 -1
- package/lib/Navigation.js +1 -1
- package/lib/Navigation.js.map +1 -1
- package/lib/Notification.js +1 -1
- package/lib/Notification.js.map +1 -1
- package/lib/NumberField.js +1 -1
- package/lib/NumberField.js.map +1 -1
- package/lib/OtpField.js +1 -1
- package/lib/OtpField.js.map +1 -1
- package/lib/Outline.js +1 -1
- package/lib/Outline.js.map +1 -1
- package/lib/Pagination.js +1 -1
- package/lib/Pagination.js.map +1 -1
- package/lib/Popout-B6Hirj3y.js +2 -0
- package/lib/{Popout-CFtFoCaA.js.map → Popout-B6Hirj3y.js.map} +1 -1
- package/lib/Popout.js +1 -1
- package/lib/Range.js +1 -1
- package/lib/SegmentedControlItem.js +1 -1
- package/lib/Tag.js +1 -1
- package/lib/Tag.js.map +1 -1
- package/lib/TextField-BYSciLeB.js +2 -0
- package/lib/TextField-BYSciLeB.js.map +1 -0
- package/lib/Textarea.js +1 -1
- package/lib/Textarea.js.map +1 -1
- package/lib/TimePicker.js +1 -1
- package/lib/TimePicker.js.map +1 -1
- package/lib/bundle.js +13 -13
- package/lib/bundle.js.map +1 -1
- package/lib/en-us.js +1 -1
- package/lib/en-us.js.map +1 -1
- package/lib/fi-fi.js +1 -1
- package/lib/fi-fi.js.map +1 -1
- package/lib/index.js +1 -1
- package/lib/localization13.js +1 -1
- package/lib/localization13.js.map +1 -1
- package/lib/localization14.js +1 -1
- package/lib/localization14.js.map +1 -1
- package/lib/localization15.js +1 -1
- package/lib/localization15.js.map +1 -1
- package/lib/localization16.js +1 -1
- package/lib/localization16.js.map +1 -1
- package/lib/localization17.js +1 -1
- package/lib/localization17.js.map +1 -1
- package/lib/localization18.js +1 -1
- package/lib/localization18.js.map +1 -1
- package/lib/localization19.js +1 -1
- package/lib/localization19.js.map +1 -1
- package/lib/localization20.js +1 -1
- package/lib/localization20.js.map +1 -1
- package/lib/localization21.js +1 -1
- package/lib/localization21.js.map +1 -1
- package/lib/localization22.js +1 -1
- package/lib/localization22.js.map +1 -1
- package/lib/localization23.js +1 -1
- package/lib/localization23.js.map +1 -1
- package/lib/localization24.js +2 -0
- package/lib/localization24.js.map +1 -0
- package/lib/nav-context.js +2 -0
- package/lib/nav-context.js.map +1 -0
- package/lib/src/aside-trigger/AsideTrigger.d.ts +28 -2
- package/lib/src/button/Button.d.ts +7 -0
- package/lib/src/dropdown/Dropdown.d.ts +3 -0
- package/lib/src/layout/Layout.d.ts +12 -0
- package/lib/src/layout/localization.d.ts +5 -0
- package/lib/src/localization/en-us.d.ts +4 -0
- package/lib/src/localization/translation.d.ts +4 -0
- package/lib/src/nav-group/NavGroup.d.ts +1 -0
- package/lib/src/nav-group/nav-context.d.ts +11 -0
- package/lib/src/nav-item/NavItem.d.ts +45 -0
- package/lib/src/navigation/Navigation.d.ts +18 -0
- package/lib/translation.js +1 -1
- package/lib/translation.js.map +1 -1
- package/package.json +8 -8
- package/lib/NavToggle-BY83xpx0.js +0 -2
- package/lib/Popout-CFtFoCaA.js +0 -2
- package/lib/TextField-CSKvieoG.js +0 -2
- package/lib/TextField-CSKvieoG.js.map +0 -1
package/lib/FilterDateRange.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{_ as t}from"./tslib.es6-CmLYFWVC.js";import{c as e}from"./interface-calendar-Cw2bJfbS.js";import{css as i,html as o,LitElement as r}from"lit";import{query as a,property as s,customElement as l}from"lit/decorators.js";import{ifDefined as n}from"lit/directives/if-defined.js";import{O as p}from"./OpenStateController-CCnZ7up6.js";import{p as m}from"./dates-C-ZvzXaC.js";import{i as d}from"./light-dom-styles-DXsbiKU9.js";import{D as c}from"./DraftComponentMixin-4qug5Rky.js";import h from"./Icon.js";import{LocalizeController as j}from"./LocalizeController.js";import{FilterDateRangeChangeEvent as f,FilterDateRangeClearEvent as u,FilterDateRangeRemoveEvent as v}from"./FilterDateRangeEvents.js";import"./FilterField.js";import"./Popout-
|
|
1
|
+
import{_ as t}from"./tslib.es6-CmLYFWVC.js";import{c as e}from"./interface-calendar-Cw2bJfbS.js";import{css as i,html as o,LitElement as r}from"lit";import{query as a,property as s,customElement as l}from"lit/decorators.js";import{ifDefined as n}from"lit/directives/if-defined.js";import{O as p}from"./OpenStateController-CCnZ7up6.js";import{p as m}from"./dates-C-ZvzXaC.js";import{i as d}from"./light-dom-styles-DXsbiKU9.js";import{D as c}from"./DraftComponentMixin-4qug5Rky.js";import h from"./Icon.js";import{LocalizeController as j}from"./LocalizeController.js";import{FilterDateRangeChangeEvent as f,FilterDateRangeClearEvent as u,FilterDateRangeRemoveEvent as v}from"./FilterDateRangeEvents.js";import"./FilterField.js";import"./Popout-B6Hirj3y.js";import"./DateRangePicker.js";import"./events-Bv6wNHwJ.js";import"lit/directives/unsafe-html.js";import"./observe-D0n0zOfU.js";import"./cond-CI1KbneT.js";import"./Component-BJ5O5n8k.js";import"./IconManager.js";import"./translation.js";import"./en-us.js";import"./localization.js";import"./localization2.js";import"./localization3.js";import"./localization4.js";import"./localization5.js";import"./localization6.js";import"./localization7.js";import"./localization8.js";import"./localization9.js";import"./localization10.js";import"./localization11.js";import"./localization12.js";import"./localization13.js";import"./localization14.js";import"./localization15.js";import"./localization16.js";import"./localization17.js";import"./localization18.js";import"./localization19.js";import"./localization20.js";import"./localization21.js";import"./localization22.js";import"./localization23.js";import"./localization24.js";import"./interface-close-small-CnpAFMO3.js";import"./interface-filter-CCsx9-u6.js";import"./filter-chip-C97zd4PT.js";import"./FilterFieldEvents.js";import"./Button.js";import"lit/directives/ref.js";import"./EventController-BBOmvfLa.js";import"./LightDomController-DIwtVelV.js";import"./SlotController-Z6eG7LSZ.js";import"./FocusableMixin-BlQLNPdJ.js";import"./InputMixin-LetXsCyv.js";import"./Spinner.js";import"./ButtonGroup.js";import"lit/directives/class-map.js";import"./DirectionController-ChvNGESZ.js";import"./VisuallyHidden.js";import"./positioning-D-K8Mueq.js";import"./LightDismissController-wcL1ziJa.js";import"./ShortcutController-CV5b0BZl.js";import"./tinykeys-DwvDXsEb.js";import"./ScrollbarController-BFC67Y2x.js";import"./interface-dropdown-small-CYvgxudU.js";import"./FormAssociatedMixin-D9aPREgv.js";import"./FormDataController-OUt5L5uC.js";import"./FieldControlMixin-BXNZJXu9.js";import"./context-consumer-BJVUulGf.js";import"./context-request-event-CCRlXoeR.js";import"./field-context.js";import"./create-context-CJ69ntlY.js";import"./ReadonlyMixin-BdJPGtQ3.js";import"./SizeMixin-CU9cLbLC.js";import"./DateRangeChangeEvent.js";import"./Input.js";import"./navigation-search-CBbIGzo2.js";import"lit/directives/style-map.js";import"./ResizeController-14PUwRQy.js";import"./AutocompleteMixin-D8eiOxvO.js";import"./TextSelectableMixin-Cfv__lHS.js";import"./FormField-CMgEFZCK.js";import"./TextField-BYSciLeB.js";import"./Calendar-D47b20IT.js";import"lit/directives/repeat.js";import"./collection-Dvg2XbxV.js";import"./number-Dg2vCfGd.js";import"./DateRangeSelectEvent.js";import"./DateSelectEvent.js";import"./Stack.js";const g=i`nord-filter-date-range{display:inline-flex;max-inline-size:100%}nord-filter-date-range .n-filter-date-range-popout{inline-size:var(--n-filter-date-range-popout-inline-size,max-content);max-inline-size:100%;padding:0}nord-filter-date-range nord-date-range-picker[inline] .n-drp{background:none;border:none;padding:0}`;h.registerIcon(e);let y=1,z=class extends(c(r)){constructor(){super(...arguments),this.filterDateRangeId="nord-filter-date-range-"+y++,this.localize=new j(this),this.openState=new p(this,{isOpen:()=>this.open,setOpen:t=>{this.open=t},popout:()=>this.popout,isInert:()=>this.disabled}),this.label="",this.value="",this.hidePresets=!1,this.removable=!1,this.clearable=!0,this.disabled=!1,this.size="s",this.name="",this.open=!1,this.handleTriggerClick=()=>{this.openState.toggle()},this.handleInnerChange=t=>{t.stopPropagation(),this.disabled||(this.value=t.value,this.dispatchEvent(new f({value:t.value,startDate:t.startDate,endDate:t.endDate})),this.hide())},this.handleInnerInput=t=>{t.stopPropagation()},this.handleClear=t=>{t.stopPropagation(),this.disabled||(this.value="",this.dispatchEvent(new f({value:"",startDate:"",endDate:""})),this.dispatchEvent(new u))},this.handleRemove=t=>{t.stopPropagation(),this.disabled||this.dispatchEvent(new v)}}get startDate(){var t;return null!==(t=this.value.split("/")[0])&&void 0!==t?t:""}get endDate(){var t;return null!==(t=this.value.split("/")[1])&&void 0!==t?t:""}connectedCallback(){super.connectedCallback(),d(this,g)}createRenderRoot(){return this}get displayValue(){if(!this.value)return"";const t=m(this.startDate),e=m(this.endDate);if(!t||!e)return this.value;const i=new Intl.DateTimeFormat(this.localize.resolvedLang,{day:"numeric",month:"short",year:"numeric"});return`${i.format(t)} ${this.localize.term("rangeSeparator")} ${i.format(e)}`}show(){this.openState.show()}hide(){this.openState.hide()}render(){const t=`${this.filterDateRangeId}-popout`;return o`<nord-filter-field aria-controls="${t}" aria-haspopup="dialog" aria-expanded="${this.open?"true":"false"}" label="${this.label}" value="${this.displayValue}" icon="interface-calendar" size="${this.size}" name="${n(this.name||void 0)}" ?removable="${this.removable}" ?clearable="${this.clearable}" ?disabled="${this.disabled}" @click="${this.handleTriggerClick}" @clear="${this.handleClear}" @remove="${this.handleRemove}"></nord-filter-field><nord-popout id="${t}" controlled always-floating @open="${this.openState.onPopoutOpen}" @close="${this.openState.onPopoutClose}"><div class="n-filter-date-range-popout"><nord-date-range-picker inline label="${this.label}" hide-label value="${this.value}" min="${n(this.min)}" max="${n(this.max)}" today="${n(this.today)}" first-day-of-week="${n(this.firstDayOfWeek)}" ?hide-presets="${this.hidePresets}" ?disabled="${this.disabled}" @change="${this.handleInnerChange}" @input="${this.handleInnerInput}"></nord-date-range-picker></div></nord-popout>`}};t([a("nord-popout",!0)],z.prototype,"popout",void 0),t([s({reflect:!0})],z.prototype,"label",void 0),t([s({reflect:!0})],z.prototype,"value",void 0),t([s({reflect:!0})],z.prototype,"min",void 0),t([s({reflect:!0})],z.prototype,"max",void 0),t([s({reflect:!0,type:Boolean,attribute:"hide-presets"})],z.prototype,"hidePresets",void 0),t([s({reflect:!0,type:Number,attribute:"first-day-of-week"})],z.prototype,"firstDayOfWeek",void 0),t([s({reflect:!0})],z.prototype,"today",void 0),t([s({reflect:!0,type:Boolean})],z.prototype,"removable",void 0),t([s({reflect:!0,type:Boolean})],z.prototype,"clearable",void 0),t([s({reflect:!0,type:Boolean})],z.prototype,"disabled",void 0),t([s({reflect:!0})],z.prototype,"size",void 0),t([s({reflect:!0})],z.prototype,"name",void 0),t([s({reflect:!0,type:Boolean})],z.prototype,"open",void 0),z=t([l("nord-filter-date-range")],z);var b=z;export{f as FilterDateRangeChangeEvent,u as FilterDateRangeClearEvent,v as FilterDateRangeRemoveEvent,b as default};
|
|
2
2
|
//# sourceMappingURL=FilterDateRange.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FilterDateRange.js","sources":["../src/filter-date-range/FilterDateRange.ts"],"sourcesContent":["import type { DateRangeChangeEvent } from '../date-range-picker/DateRangeChangeEvent.js'\nimport * as calendarIcon from '@nordhealth/icons/lib/assets/interface-calendar.js'\nimport { html, LitElement } from 'lit'\nimport { customElement, property, query } from 'lit/decorators.js'\nimport { ifDefined } from 'lit/directives/if-defined.js'\n\nimport { OpenStateController } from '../common/controllers/OpenStateController.js'\nimport { parseISODate } from '../common/dates.js'\nimport { injectLightDomStyles } from '../common/light-dom-styles.js'\nimport { DraftComponentMixin } from '../common/mixins/DraftComponentMixin.js'\nimport Icon from '../icon/Icon.js'\nimport { LocalizeController } from '../localization/LocalizeController.js'\nimport style from './FilterDateRange.css'\nimport { FilterDateRangeChangeEvent, FilterDateRangeClearEvent, FilterDateRangeRemoveEvent } from './FilterDateRangeEvents.js'\nimport '../filter-field/FilterField.js'\nimport '../popout/Popout.js'\nimport '../date-range-picker/DateRangePicker.js'\n\nIcon.registerIcon(calendarIcon)\n\nexport {\n FilterDateRangeChangeEvent,\n FilterDateRangeClearEvent,\n FilterDateRangeRemoveEvent,\n} from './FilterDateRangeEvents.js'\n\n/** Per-instance counter so the popout id stays unique in the light DOM. */\nlet filterDateRangeCount = 1\n\n/**\n * Filter Date Range is a self-contained date-range **filter**: a chip that opens\n * a popout containing an inline [Date Range Picker](/components/date-range-picker/)\n * (presets + two-month calendar + Apply). It is the date-range counterpart to\n * [Filter Dropdown](/components/filter-dropdown/) and renders the shared filter\n * chip via [Filter Field](/components/filter-field/).\n *\n * Composition-first: it emits `change`/`clear`/`remove` and leaves the active\n * filters and any URL/query state to your app.\n *\n * @status draft\n * @category form\n * @lightDom true\n *\n * @fires {FilterDateRangeChangeEvent} change - Dispatched when the committed range changes (Apply or clear).\n * @fires {FilterDateRangeClearEvent} clear - Dispatched when the chip's clear affordance is pressed.\n * @fires {FilterDateRangeRemoveEvent} remove - Dispatched when the chip's remove affordance is pressed.\n * @fires {NordEvent} open - Dispatched when the popout is opened.\n * @fires {NordEvent} close - Dispatched when the popout is closed.\n *\n * @localization filterIconLabel - Accessible label for the leading calendar icon.\n * @localization clearLabel - Accessible label for the clear button.\n * @localization removeLabel - Accessible label for the remove button.\n * @localization rangeSeparator - Character shown between the start and end dates on the chip.\n *\n * @cssprop [--n-filter-date-range-popout-inline-size] - Controls the inline size of the popout content.\n *\n * @parent FilterBar\n */\n@customElement('nord-filter-date-range')\nexport default class FilterDateRange extends DraftComponentMixin(LitElement) {\n private filterDateRangeId = `nord-filter-date-range-${filterDateRangeCount++}`\n\n private localize = new LocalizeController<'nord-filter-date-range'>(this)\n\n @query('nord-popout', true) private popout?: HTMLElement & {\n show: () => Promise<unknown>\n hide: (moveFocusToButton?: boolean) => Promise<unknown>\n }\n\n // Coordinates `open` with the popout (drive show/hide, sync from its events,\n // emit one canonical open/close, reject opening while disabled).\n private openState = new OpenStateController(this, {\n isOpen: () => this.open,\n setOpen: (open) => { this.open = open },\n popout: () => this.popout,\n isInert: () => this.disabled,\n })\n\n /** The label naming what this filter targets, shown on the chip. */\n @property({ reflect: true }) label = ''\n\n /**\n * The committed range as an ISO-8601 interval string `YYYY-MM-DD/YYYY-MM-DD`,\n * or `\"\"` for no selection.\n */\n @property({ reflect: true }) value = ''\n\n /** Earliest selectable date (ISO-8601). */\n @property({ reflect: true }) min?: string\n\n /** Latest selectable date (ISO-8601). */\n @property({ reflect: true }) max?: string\n\n /** Hides the built-in preset list, leaving only the calendar. */\n @property({ reflect: true, type: Boolean, attribute: 'hide-presets' }) hidePresets = false\n\n /** First day of the week (0 = Sunday … 6 = Saturday). */\n @property({ reflect: true, type: Number, attribute: 'first-day-of-week' }) firstDayOfWeek?: number\n\n /** Overrides \"today\" (ISO-8601), mainly for deterministic tests/demos. */\n @property({ reflect: true }) today?: string\n\n /**\n * Whether the whole filter can be removed. When `true` the trailing affordance\n * is a remove button that fires `remove`; otherwise it is a clear button.\n */\n @property({ reflect: true, type: Boolean }) removable = false\n\n /** Shows a clear (✕) button while there is a selection. Defaults to `true`. */\n @property({ reflect: true, type: Boolean }) clearable = true\n\n /** Makes the component disabled. */\n @property({ reflect: true, type: Boolean }) disabled = false\n\n /** The size of the chip controls. */\n @property({ reflect: true }) size: 's' | 'm' | 'l' = 's'\n\n /** Identifies the filter (e.g. for your app's active-filter state). */\n @property({ reflect: true }) name = ''\n\n /** Whether the popout is open. */\n @property({ reflect: true, type: Boolean }) open = false\n\n /** The committed start date (ISO-8601), derived from `value`. */\n get startDate(): string {\n return this.value.split('/')[0] ?? ''\n }\n\n /** The committed end date (ISO-8601), derived from `value`. */\n get endDate(): string {\n return this.value.split('/')[1] ?? ''\n }\n\n connectedCallback() {\n super.connectedCallback()\n injectLightDomStyles(this, style)\n }\n\n protected createRenderRoot() {\n return this\n }\n\n /** The chip text: the formatted range, or `\"\"` while inactive. */\n private get displayValue(): string {\n // Genuinely empty → inactive chip.\n if (!this.value) {\n return ''\n }\n const start = parseISODate(this.startDate)\n const end = parseISODate(this.endDate)\n // A non-empty but unparseable/partial `value` still represents an active\n // filter — show it raw rather than silently rendering the chip as inactive.\n if (!start || !end) {\n return this.value\n }\n const fmt = new Intl.DateTimeFormat(this.localize.resolvedLang, { day: 'numeric', month: 'short', year: 'numeric' })\n return `${fmt.format(start)} ${this.localize.term('rangeSeparator')} ${fmt.format(end)}`\n }\n\n /** Open the popout. */\n show() {\n this.openState.show()\n }\n\n /** Close the popout. */\n hide() {\n this.openState.hide()\n }\n\n // The popout is `controlled`, so the chip click is the only thing that opens\n // it — mirror the date-range-picker's trigger. (FilterField stops propagation\n // on its clear/remove buttons, so those don't reach this handler.)\n private handleTriggerClick = () => {\n this.openState.toggle()\n }\n\n // The inline picker commits on Apply (and clears on its Clear); mirror its\n // committed value, re-emit a single canonical `change`, and close.\n private handleInnerChange = (e: DateRangeChangeEvent) => {\n e.stopPropagation()\n if (this.disabled) {\n return\n }\n\n this.value = e.value\n this.dispatchEvent(new FilterDateRangeChangeEvent({ value: e.value, startDate: e.startDate, endDate: e.endDate }))\n this.hide()\n }\n\n // Swallow the inline picker's live `input` so consumers only see our `change`.\n private handleInnerInput = (e: Event) => {\n e.stopPropagation()\n }\n\n private handleClear = (e: Event) => {\n e.stopPropagation()\n if (this.disabled) {\n return\n }\n\n this.value = ''\n this.dispatchEvent(new FilterDateRangeChangeEvent({ value: '', startDate: '', endDate: '' }))\n this.dispatchEvent(new FilterDateRangeClearEvent())\n }\n\n private handleRemove = (e: Event) => {\n e.stopPropagation()\n if (this.disabled) {\n return\n }\n\n this.dispatchEvent(new FilterDateRangeRemoveEvent())\n }\n\n render() {\n const popoutId = `${this.filterDateRangeId}-popout`\n\n return html`\n <nord-filter-field\n aria-controls=${popoutId}\n aria-haspopup=\"dialog\"\n aria-expanded=${this.open ? 'true' : 'false'}\n label=${this.label}\n value=${this.displayValue}\n icon=\"interface-calendar\"\n size=${this.size}\n name=${ifDefined(this.name || undefined)}\n ?removable=${this.removable}\n ?clearable=${this.clearable}\n ?disabled=${this.disabled}\n @click=${this.handleTriggerClick}\n @clear=${this.handleClear}\n @remove=${this.handleRemove}\n ></nord-filter-field>\n\n <nord-popout\n id=${popoutId}\n controlled\n always-floating\n @open=${this.openState.onPopoutOpen}\n @close=${this.openState.onPopoutClose}\n >\n <div class=\"n-filter-date-range-popout\">\n <nord-date-range-picker\n inline\n label=${this.label}\n hide-label\n value=${this.value}\n min=${ifDefined(this.min)}\n max=${ifDefined(this.max)}\n today=${ifDefined(this.today)}\n first-day-of-week=${ifDefined(this.firstDayOfWeek)}\n ?hide-presets=${this.hidePresets}\n ?disabled=${this.disabled}\n @change=${this.handleInnerChange}\n @input=${this.handleInnerInput}\n ></nord-date-range-picker>\n </div>\n </nord-popout>\n `\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'nord-filter-date-range': FilterDateRange\n }\n}\n"],"names":["Icon","registerIcon","calendarIcon","filterDateRangeCount","FilterDateRange","DraftComponentMixin","LitElement","constructor","this","filterDateRangeId","localize","LocalizeController","openState","OpenStateController","isOpen","open","setOpen","popout","isInert","disabled","label","value","hidePresets","removable","clearable","size","name","handleTriggerClick","toggle","handleInnerChange","e","stopPropagation","dispatchEvent","FilterDateRangeChangeEvent","startDate","endDate","hide","handleInnerInput","handleClear","FilterDateRangeClearEvent","handleRemove","FilterDateRangeRemoveEvent","_a","split","connectedCallback","super","injectLightDomStyles","style","createRenderRoot","displayValue","start","parseISODate","end","fmt","Intl","DateTimeFormat","resolvedLang","day","month","year","format","term","show","render","popoutId","html","ifDefined","undefined","onPopoutOpen","onPopoutClose","min","max","today","firstDayOfWeek","__decorate","query","prototype","property","reflect","type","Boolean","attribute","Number","customElement"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"FilterDateRange.js","sources":["../src/filter-date-range/FilterDateRange.ts"],"sourcesContent":["import type { DateRangeChangeEvent } from '../date-range-picker/DateRangeChangeEvent.js'\nimport * as calendarIcon from '@nordhealth/icons/lib/assets/interface-calendar.js'\nimport { html, LitElement } from 'lit'\nimport { customElement, property, query } from 'lit/decorators.js'\nimport { ifDefined } from 'lit/directives/if-defined.js'\n\nimport { OpenStateController } from '../common/controllers/OpenStateController.js'\nimport { parseISODate } from '../common/dates.js'\nimport { injectLightDomStyles } from '../common/light-dom-styles.js'\nimport { DraftComponentMixin } from '../common/mixins/DraftComponentMixin.js'\nimport Icon from '../icon/Icon.js'\nimport { LocalizeController } from '../localization/LocalizeController.js'\nimport style from './FilterDateRange.css'\nimport { FilterDateRangeChangeEvent, FilterDateRangeClearEvent, FilterDateRangeRemoveEvent } from './FilterDateRangeEvents.js'\nimport '../filter-field/FilterField.js'\nimport '../popout/Popout.js'\nimport '../date-range-picker/DateRangePicker.js'\n\nIcon.registerIcon(calendarIcon)\n\nexport {\n FilterDateRangeChangeEvent,\n FilterDateRangeClearEvent,\n FilterDateRangeRemoveEvent,\n} from './FilterDateRangeEvents.js'\n\n/** Per-instance counter so the popout id stays unique in the light DOM. */\nlet filterDateRangeCount = 1\n\n/**\n * Filter Date Range is a self-contained date-range **filter**: a chip that opens\n * a popout containing an inline [Date Range Picker](/components/date-range-picker/)\n * (presets + two-month calendar + Apply). It is the date-range counterpart to\n * [Filter Dropdown](/components/filter-dropdown/) and renders the shared filter\n * chip via [Filter Field](/components/filter-field/).\n *\n * Composition-first: it emits `change`/`clear`/`remove` and leaves the active\n * filters and any URL/query state to your app.\n *\n * @status draft\n * @category form\n * @lightDom true\n *\n * @fires {FilterDateRangeChangeEvent} change - Dispatched when the committed range changes (Apply or clear).\n * @fires {FilterDateRangeClearEvent} clear - Dispatched when the chip's clear affordance is pressed.\n * @fires {FilterDateRangeRemoveEvent} remove - Dispatched when the chip's remove affordance is pressed.\n * @fires {NordEvent} open - Dispatched when the popout is opened.\n * @fires {NordEvent} close - Dispatched when the popout is closed.\n *\n * @localization filterIconLabel - Accessible label for the leading calendar icon.\n * @localization clearLabel - Accessible label for the clear button.\n * @localization removeLabel - Accessible label for the remove button.\n * @localization rangeSeparator - Character shown between the start and end dates on the chip.\n *\n * @cssprop [--n-filter-date-range-popout-inline-size] - Controls the inline size of the popout content.\n *\n * @parent FilterBar\n */\n@customElement('nord-filter-date-range')\nexport default class FilterDateRange extends DraftComponentMixin(LitElement) {\n private filterDateRangeId = `nord-filter-date-range-${filterDateRangeCount++}`\n\n private localize = new LocalizeController<'nord-filter-date-range'>(this)\n\n @query('nord-popout', true) private popout?: HTMLElement & {\n show: () => Promise<unknown>\n hide: (moveFocusToButton?: boolean) => Promise<unknown>\n }\n\n // Coordinates `open` with the popout (drive show/hide, sync from its events,\n // emit one canonical open/close, reject opening while disabled).\n private openState = new OpenStateController(this, {\n isOpen: () => this.open,\n setOpen: (open) => { this.open = open },\n popout: () => this.popout,\n isInert: () => this.disabled,\n })\n\n /** The label naming what this filter targets, shown on the chip. */\n @property({ reflect: true }) label = ''\n\n /**\n * The committed range as an ISO-8601 interval string `YYYY-MM-DD/YYYY-MM-DD`,\n * or `\"\"` for no selection.\n */\n @property({ reflect: true }) value = ''\n\n /** Earliest selectable date (ISO-8601). */\n @property({ reflect: true }) min?: string\n\n /** Latest selectable date (ISO-8601). */\n @property({ reflect: true }) max?: string\n\n /** Hides the built-in preset list, leaving only the calendar. */\n @property({ reflect: true, type: Boolean, attribute: 'hide-presets' }) hidePresets = false\n\n /** First day of the week (0 = Sunday … 6 = Saturday). */\n @property({ reflect: true, type: Number, attribute: 'first-day-of-week' }) firstDayOfWeek?: number\n\n /** Overrides \"today\" (ISO-8601), mainly for deterministic tests/demos. */\n @property({ reflect: true }) today?: string\n\n /**\n * Whether the whole filter can be removed. When `true` the trailing affordance\n * is a remove button that fires `remove`; otherwise it is a clear button.\n */\n @property({ reflect: true, type: Boolean }) removable = false\n\n /** Shows a clear (✕) button while there is a selection. Defaults to `true`. */\n @property({ reflect: true, type: Boolean }) clearable = true\n\n /** Makes the component disabled. */\n @property({ reflect: true, type: Boolean }) disabled = false\n\n /** The size of the chip controls. */\n @property({ reflect: true }) size: 's' | 'm' | 'l' = 's'\n\n /** Identifies the filter (e.g. for your app's active-filter state). */\n @property({ reflect: true }) name = ''\n\n /** Whether the popout is open. */\n @property({ reflect: true, type: Boolean }) open = false\n\n /** The committed start date (ISO-8601), derived from `value`. */\n get startDate(): string {\n return this.value.split('/')[0] ?? ''\n }\n\n /** The committed end date (ISO-8601), derived from `value`. */\n get endDate(): string {\n return this.value.split('/')[1] ?? ''\n }\n\n connectedCallback() {\n super.connectedCallback()\n injectLightDomStyles(this, style)\n }\n\n protected createRenderRoot() {\n return this\n }\n\n /** The chip text: the formatted range, or `\"\"` while inactive. */\n private get displayValue(): string {\n // Genuinely empty → inactive chip.\n if (!this.value) {\n return ''\n }\n const start = parseISODate(this.startDate)\n const end = parseISODate(this.endDate)\n // A non-empty but unparseable/partial `value` still represents an active\n // filter — show it raw rather than silently rendering the chip as inactive.\n if (!start || !end) {\n return this.value\n }\n const fmt = new Intl.DateTimeFormat(this.localize.resolvedLang, { day: 'numeric', month: 'short', year: 'numeric' })\n return `${fmt.format(start)} ${this.localize.term('rangeSeparator')} ${fmt.format(end)}`\n }\n\n /** Open the popout. */\n show() {\n this.openState.show()\n }\n\n /** Close the popout. */\n hide() {\n this.openState.hide()\n }\n\n // The popout is `controlled`, so the chip click is the only thing that opens\n // it — mirror the date-range-picker's trigger. (FilterField stops propagation\n // on its clear/remove buttons, so those don't reach this handler.)\n private handleTriggerClick = () => {\n this.openState.toggle()\n }\n\n // The inline picker commits on Apply (and clears on its Clear); mirror its\n // committed value, re-emit a single canonical `change`, and close.\n private handleInnerChange = (e: DateRangeChangeEvent) => {\n e.stopPropagation()\n if (this.disabled) {\n return\n }\n\n this.value = e.value\n this.dispatchEvent(new FilterDateRangeChangeEvent({ value: e.value, startDate: e.startDate, endDate: e.endDate }))\n this.hide()\n }\n\n // Swallow the inline picker's live `input` so consumers only see our `change`.\n private handleInnerInput = (e: Event) => {\n e.stopPropagation()\n }\n\n private handleClear = (e: Event) => {\n e.stopPropagation()\n if (this.disabled) {\n return\n }\n\n this.value = ''\n this.dispatchEvent(new FilterDateRangeChangeEvent({ value: '', startDate: '', endDate: '' }))\n this.dispatchEvent(new FilterDateRangeClearEvent())\n }\n\n private handleRemove = (e: Event) => {\n e.stopPropagation()\n if (this.disabled) {\n return\n }\n\n this.dispatchEvent(new FilterDateRangeRemoveEvent())\n }\n\n render() {\n const popoutId = `${this.filterDateRangeId}-popout`\n\n return html`\n <nord-filter-field\n aria-controls=${popoutId}\n aria-haspopup=\"dialog\"\n aria-expanded=${this.open ? 'true' : 'false'}\n label=${this.label}\n value=${this.displayValue}\n icon=\"interface-calendar\"\n size=${this.size}\n name=${ifDefined(this.name || undefined)}\n ?removable=${this.removable}\n ?clearable=${this.clearable}\n ?disabled=${this.disabled}\n @click=${this.handleTriggerClick}\n @clear=${this.handleClear}\n @remove=${this.handleRemove}\n ></nord-filter-field>\n\n <nord-popout\n id=${popoutId}\n controlled\n always-floating\n @open=${this.openState.onPopoutOpen}\n @close=${this.openState.onPopoutClose}\n >\n <div class=\"n-filter-date-range-popout\">\n <nord-date-range-picker\n inline\n label=${this.label}\n hide-label\n value=${this.value}\n min=${ifDefined(this.min)}\n max=${ifDefined(this.max)}\n today=${ifDefined(this.today)}\n first-day-of-week=${ifDefined(this.firstDayOfWeek)}\n ?hide-presets=${this.hidePresets}\n ?disabled=${this.disabled}\n @change=${this.handleInnerChange}\n @input=${this.handleInnerInput}\n ></nord-date-range-picker>\n </div>\n </nord-popout>\n `\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'nord-filter-date-range': FilterDateRange\n }\n}\n"],"names":["Icon","registerIcon","calendarIcon","filterDateRangeCount","FilterDateRange","DraftComponentMixin","LitElement","constructor","this","filterDateRangeId","localize","LocalizeController","openState","OpenStateController","isOpen","open","setOpen","popout","isInert","disabled","label","value","hidePresets","removable","clearable","size","name","handleTriggerClick","toggle","handleInnerChange","e","stopPropagation","dispatchEvent","FilterDateRangeChangeEvent","startDate","endDate","hide","handleInnerInput","handleClear","FilterDateRangeClearEvent","handleRemove","FilterDateRangeRemoveEvent","_a","split","connectedCallback","super","injectLightDomStyles","style","createRenderRoot","displayValue","start","parseISODate","end","fmt","Intl","DateTimeFormat","resolvedLang","day","month","year","format","term","show","render","popoutId","html","ifDefined","undefined","onPopoutOpen","onPopoutClose","min","max","today","firstDayOfWeek","__decorate","query","prototype","property","reflect","type","Boolean","attribute","Number","customElement"],"mappings":"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"}
|
package/lib/FilterDropdown.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{_ as e}from"./tslib.es6-CmLYFWVC.js";import{c as t}from"./interface-checked-small-BQmkNgCI.js";import{c as i,A as o}from"./ActiveDescendantController-BnMqM79O.js";import{c as n}from"./interface-close-small-CnpAFMO3.js";import{f as s}from"./interface-filter-CCsx9-u6.js";import{s as r}from"./navigation-search-CBbIGzo2.js";import{css as l,html as a,nothing as d,LitElement as p}from"lit";import{query as c,property as h,state as u,customElement as v}from"lit/decorators.js";import{classMap as f}from"lit/directives/class-map.js";import{createRef as m,ref as b}from"lit/directives/ref.js";import{repeat as g}from"lit/directives/repeat.js";import{L as w}from"./LightDismissController-wcL1ziJa.js";import{O as y}from"./OpenStateController-CCnZ7up6.js";import{i as j}from"./light-dom-styles-DXsbiKU9.js";import{D as z}from"./DraftComponentMixin-4qug5Rky.js";import{s as $}from"./filter-chip-C97zd4PT.js";import k from"./Icon.js";import{LocalizeController as x}from"./LocalizeController.js";import{FilterDropdownRemoveEvent as S,FilterDropdownSearchChangeEvent as A,FilterDropdownLoadMoreEvent as D,FilterDropdownChangeEvent as I,FilterDropdownClearEvent as O}from"./FilterDropdownEvents.js";import"./Button.js";import"./ButtonGroup.js";import"./Input.js";import"./Popout-CFtFoCaA.js";import"./Spinner.js";import"./VisuallyHidden.js";import"./number-Dg2vCfGd.js";import"./EventController-BBOmvfLa.js";import"./ShortcutController-CV5b0BZl.js";import"./tinykeys-DwvDXsEb.js";import"./events-Bv6wNHwJ.js";import"lit/directives/if-defined.js";import"lit/directives/unsafe-html.js";import"./observe-D0n0zOfU.js";import"./cond-CI1KbneT.js";import"./Component-BJ5O5n8k.js";import"./IconManager.js";import"./translation.js";import"./en-us.js";import"./localization.js";import"./localization2.js";import"./localization3.js";import"./localization4.js";import"./localization5.js";import"./localization6.js";import"./localization7.js";import"./localization8.js";import"./localization9.js";import"./localization10.js";import"./localization11.js";import"./localization12.js";import"./localization13.js";import"./localization14.js";import"./localization15.js";import"./localization16.js";import"./localization17.js";import"./localization18.js";import"./localization19.js";import"./localization20.js";import"./localization21.js";import"./localization22.js";import"./localization23.js";import"./LightDomController-DIwtVelV.js";import"./SlotController-Z6eG7LSZ.js";import"./FocusableMixin-BlQLNPdJ.js";import"./InputMixin-LetXsCyv.js";import"./DirectionController-ChvNGESZ.js";import"lit/directives/style-map.js";import"./ResizeController-14PUwRQy.js";import"./AutocompleteMixin-D8eiOxvO.js";import"./FormAssociatedMixin-D9aPREgv.js";import"./FormDataController-OUt5L5uC.js";import"./FieldControlMixin-BXNZJXu9.js";import"./context-consumer-BJVUulGf.js";import"./context-request-event-CCRlXoeR.js";import"./field-context.js";import"./create-context-CJ69ntlY.js";import"./ReadonlyMixin-BdJPGtQ3.js";import"./SizeMixin-CU9cLbLC.js";import"./TextSelectableMixin-Cfv__lHS.js";import"./FormField-CMgEFZCK.js";import"./TextField-CSKvieoG.js";import"./positioning-D-K8Mueq.js";import"./ScrollbarController-BFC67Y2x.js";const C=l`nord-filter-dropdown{--_n-filter-dropdown-list-inline-size:var(--n-filter-dropdown-list-inline-size,250px)}nord-filter-dropdown .n-filter-dropdown-panel{display:flex;flex-direction:column;max-inline-size:calc(var(--_n-filter-dropdown-list-inline-size)*1.5);min-inline-size:var(--_n-filter-dropdown-list-inline-size)}nord-filter-dropdown .n-filter-dropdown-size-s{--_n-filter-dropdown-list-inline-size:var(--n-filter-dropdown-list-inline-size,250px)}nord-filter-dropdown .n-filter-dropdown-size-l{--_n-filter-dropdown-list-inline-size:var(--n-filter-dropdown-list-inline-size,300px)}nord-filter-dropdown .n-filter-dropdown-search{padding-block-end:var(--n-space-xs);padding-block-start:var(--n-space-m);padding-inline-end:var(--n-space-m);padding-inline-start:var(--n-space-m)}nord-filter-dropdown .n-filter-dropdown-select-all{border-block-end:1px solid var(--n-color-border);padding-block-start:0}nord-filter-dropdown .n-filter-dropdown-list,nord-filter-dropdown .n-filter-dropdown-select-all{padding-block-end:var(--n-space-s);padding-inline-end:var(--n-space-s);padding-inline-start:var(--n-space-s)}nord-filter-dropdown .n-filter-dropdown-list{max-block-size:330px;overflow-y:auto;padding-block-start:var(--n-space-s)}nord-filter-dropdown .n-filter-dropdown-list.is-loading-more{opacity:.3;pointer-events:none}@media (width <= 35.9375em){nord-filter-dropdown .n-filter-dropdown-panel{max-inline-size:none}nord-filter-dropdown .n-filter-dropdown-list{max-block-size:70vh}}nord-filter-dropdown .n-filter-dropdown-group{border-block-end:1px solid var(--n-color-border);margin-block-end:var(--n-space-s);padding-block-end:var(--n-space-s)}nord-filter-dropdown .n-filter-dropdown-group:last-child{border-block-end:0;margin-block-end:0;padding-block-end:0}nord-filter-dropdown .n-filter-dropdown-heading{color:var(--n-color-text-weaker);font-size:var(--n-font-size-s);font-weight:var(--n-font-weight-active);padding-block-end:var(--n-space-xs);padding-block-start:var(--n-space-xs);padding-inline-end:var(--n-space-s);padding-inline-start:var(--n-space-s)}nord-filter-dropdown .n-filter-dropdown-option{align-items:center;border-radius:var(--n-border-radius-s);color:var(--n-color-text);cursor:pointer;display:flex;gap:var(--n-space-s);padding-block-end:var(--n-space-s);padding-block-start:var(--n-space-s);padding-inline-end:var(--n-space-s);padding-inline-start:var(--n-space-s);user-select:none}nord-filter-dropdown .n-filter-dropdown-option.is-indented{padding-inline-start:var(--n-space-l)}nord-filter-dropdown .n-filter-dropdown-option.is-active,nord-filter-dropdown .n-filter-dropdown-option:hover{background-color:var(--n-color-active)}nord-filter-dropdown .n-filter-dropdown-option.is-disabled{color:var(--n-color-text-weakest);cursor:not-allowed;pointer-events:none}nord-filter-dropdown .n-filter-dropdown-option-label{flex:1 1 auto;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}nord-filter-dropdown .n-filter-dropdown-checkbox{background-color:var(--n-color-surface);block-size:var(--n-space-m);border:1px solid var(--n-color-border-hover);border-radius:var(--n-border-radius-s);color:var(--n-color-text-on-accent);display:grid;flex:0 0 var(--n-space-m);inline-size:var(--n-space-m);place-items:center}nord-filter-dropdown .n-filter-dropdown-checkbox:has(nord-icon){background-color:var(--n-color-accent);border-color:var(--n-color-accent)}nord-filter-dropdown .n-filter-dropdown-check{block-size:var(--n-space-m);color:var(--n-color-text-highlight);display:grid;flex:0 0 var(--n-space-m);inline-size:var(--n-space-m);place-items:center}nord-filter-dropdown .n-filter-dropdown-empty{color:var(--n-color-text-weaker);display:flex;justify-content:center;padding-block-end:var(--n-space-s);padding-block-start:var(--n-space-s);padding-inline-end:var(--n-space-s);padding-inline-start:var(--n-space-s)}`;k.registerIcon(t),k.registerIcon(i),k.registerIcon(n),k.registerIcon(s),k.registerIcon(r);let L=1;function M(e){return"heading"in e}let R=class extends(z(p)){constructor(){super(...arguments),this.filterDropdownId="nord-filter-dropdown-"+L++,this.localize=new x(this),this.listRef=m(),this.dismiss=new w(this,{isOpen:()=>this.open,onDismiss:()=>this.hide(),isDismissible:e=>e!==this}),this.activeDescendant=new o(this,{count:()=>this.flatOptions.length,isEnabled:e=>{var t;return!(null===(t=this.flatOptions[e])||void 0===t?void 0:t.disabled)},optionId:e=>this.optionId(e)}),this.openState=new y(this,{isOpen:()=>this.open,setOpen:e=>{this.open=e},popout:()=>this.popout,isInert:()=>this.disabled,onOpen:()=>{var e;this.loadMoreRequested=!1,null===(e=this.listRef.value)||void 0===e||e.scrollTo(0,0),this.activeDescendant.reset()},onClose:()=>{this.search&&(this.search=""),this.removable&&this.isInactive&&this.dispatchEvent(new S)}}),this.label="",this.name="",this.icon="interface-filter",this.size="s",this.options=[],this.optionsValueKey="value",this.optionsLabelKey="label",this.value="",this.multiple=!1,this.searchable=!1,this.internalSearch=!0,this.selectAll=!1,this.clearable=!0,this.removable=!1,this.disabled=!1,this.loading=!1,this.open=!1,this.noResultsMessage="",this.labelForUnknown="",this.search="",this.scrollActivePending=!1,this.loadMoreRequested=!1,this.handleTriggerClick=()=>{this.openState.toggle()},this.toggleSelectAll=()=>{!this.disabled&&this.multiple&&this.commit(this.isAllSelected?[]:[...this.allSelectableValues])},this.handleClear=e=>{e.stopPropagation(),this.disabled||(this.clear(),this.focus())},this.handleRemove=e=>{e.stopPropagation(),this.disabled||(this.clear(),this.dispatchEvent(new S))},this.handleSearchInput=e=>{if(e.stopPropagation(),this.disabled)return;const t=e.target;this.search=t.value,this.activeDescendant.reset(),this.scrollActivePending=!0,this.dispatchEvent(new A(this.search))},this.handleListScroll=e=>{if(this.disabled)return;const t=e.target,{scrollTop:i,scrollHeight:o,clientHeight:n}=t;if(o<=n)return;(i+n)/o>.8?this.loading||this.loadMoreRequested||(this.loadMoreRequested=!0,this.dispatchEvent(new D)):this.loadMoreRequested=!1},this.handleKeydown=e=>{if(!this.disabled)switch(e.key){case"ArrowDown":if(e.preventDefault(),!this.open)return void this.show();this.activeDescendant.move(1),this.scrollActivePending=!0;break;case"ArrowUp":if(e.preventDefault(),!this.open)return void this.show();this.activeDescendant.move(-1),this.scrollActivePending=!0;break;case"Home":this.open&&(e.preventDefault(),this.activeDescendant.first(),this.scrollActivePending=!0);break;case"End":this.open&&(e.preventDefault(),this.activeDescendant.last(),this.scrollActivePending=!0);break;case"Enter":{if(!this.open)return e.preventDefault(),void this.show();e.preventDefault();const t=this.flatOptions[this.activeDescendant.activeIndex];t&&this.toggle(t);break}case"Escape":this.open&&(e.preventDefault(),this.hide(),this.focus())}}}connectedCallback(){super.connectedCallback(),j(this,C),j(this,$,"nord-filter-chip")}createRenderRoot(){return this}get valueAsArray(){const{value:e}=this;return Array.isArray(e)?e:e?[e]:[]}get isInactive(){return 0===this.valueAsArray.length}getOptionValue(e){var t;return String(null!==(t=e[this.optionsValueKey])&&void 0!==t?t:"")}getOptionLabel(e){var t;return String(null!==(t=e[this.optionsLabelKey])&&void 0!==t?t:"")}get hasGroupedOptions(){return this.options.some((e=>{var t;return M(e)||Boolean(null===(t=e.children)||void 0===t?void 0:t.length)}))}get needle(){return this.searchable&&this.internalSearch?this.search.trim().toLocaleLowerCase():""}matchesSearch(e){const t=this.needle;return!t||this.getOptionLabel(e).toLocaleLowerCase().includes(t)}get sections(){var e,t;const i=(e,t)=>({value:this.getOptionValue(e),label:this.getOptionLabel(e),disabled:Boolean(e.disabled),indent:t,source:e});if(!this.hasGroupedOptions){const e=this.options.filter((e=>this.matchesSearch(e))).map((e=>i(e,!1)));return e.length?[{options:e}]:[]}const o=[];let n=[];const s=()=>{n.length&&(o.push({options:n}),n=[])};for(const r of this.options)if(M(r)){s();const t=(null!==(e=r.children)&&void 0!==e?e:[]).filter((e=>this.matchesSearch(e))).map((e=>i({...e,disabled:e.disabled||r.disabled},!1)));t.length&&o.push({heading:r.heading,options:t})}else if(null===(t=r.children)||void 0===t?void 0:t.length){const e=this.matchesSearch(r),t=r.children.filter((e=>this.matchesSearch(e)));if(e||t.length){e&&n.push(i(r,!1));for(const e of t)n.push(i(e,!0))}}else this.matchesSearch(r)&&n.push(i(r,!1));return s(),o}get flatOptions(){return this.sections.flatMap((e=>e.options))}get allSelectableValues(){var e,t;const i=[];for(const o of this.options)if(M(o)){if(o.disabled)continue;for(const t of null!==(e=o.children)&&void 0!==e?e:[])t.disabled||i.push(this.getOptionValue(t))}else{o.disabled||i.push(this.getOptionValue(o));for(const e of null!==(t=o.children)&&void 0!==t?t:[])o.disabled||e.disabled||i.push(this.getOptionValue(e))}return i}get isAllSelected(){if(!this.selectAll||!this.multiple)return!1;const e=this.allSelectableValues,t=new Set(this.valueAsArray);return e.length>0&&e.every((e=>t.has(e)))}labelForValue(e){var t,i;for(const o of this.options)if(M(o)){for(const i of null!==(t=o.children)&&void 0!==t?t:[])if(this.getOptionValue(i)===e)return this.getOptionLabel(i)}else{if(this.getOptionValue(o)===e)return this.getOptionLabel(o);for(const t of null!==(i=o.children)&&void 0!==i?i:[])if(this.getOptionValue(t)===e)return this.getOptionLabel(t)}return this.labelForUnknown||this.localize.term("unknown")}get selectionLabel(){const e=this.valueAsArray;if(0===e.length)return"";const t=this.labelForValue(e[0]);return e.length>1?t+this.localize.term("countSuffix",e.length-1):t}isSelected(e){return this.valueAsArray.includes(e)}show(){this.openState.show()}hide(){this.openState.hide()}focus(e){var t;null===(t=this.triggerButton)||void 0===t||t.focus(e)}updated(e){var t,i;super.updated(e),this.scrollActivePending&&(this.scrollActivePending=!1,null===(i=null===(t=this.listRef.value)||void 0===t?void 0:t.querySelector(".n-filter-dropdown-option.is-active"))||void 0===i||i.scrollIntoView({block:"nearest"})),this.loadMoreRequested&&(e.has("loading")||e.has("options"))&&(this.loadMoreRequested=!1),e.has("disabled")&&this.disabled&&(this.activeDescendant.reset(),this.scrollActivePending=!0)}commit(e){this.value=e,this.dispatchEvent(new I(e))}toggle(e){if(this.disabled||e.disabled)return;if(!this.multiple)return this.commit(e.value),void this.hide();const t=this.valueAsArray,i=t.includes(e.value)?t.filter((t=>t!==e.value)):[...t,e.value];this.commit(i)}clear(){this.disabled||(this.search="",this.dispatchEvent(new O),this.commit(this.multiple?[]:""))}get listInlineSizeClass(){return`n-filter-dropdown-size-${this.size}`}renderIndicator(e){const t=this.isSelected(e);return this.multiple?a`<span class="n-filter-dropdown-checkbox">${t?a`<nord-icon name="interface-checked-small" size="xs"></nord-icon>`:d}</span>`:a`<span class="n-filter-dropdown-check">${t?a`<nord-icon name="interface-checked" size="s"></nord-icon>`:d}</span>`}renderOption(e,t){const i=this.isSelected(e.value);return a`<div id="${this.optionId(t)}" class="${f({"n-filter-dropdown-option":!0,"is-active":t===this.activeDescendant.activeIndex,"is-disabled":e.disabled,"is-indented":e.indent})}" role="option" aria-selected="${i?"true":"false"}" aria-disabled="${e.disabled?"true":d}" @click="${()=>this.toggle(e)}" @mousemove="${()=>this.activeDescendant.setActiveIndex(t)}">${this.renderIndicator(e.value)} <span class="n-filter-dropdown-option-label">${e.label}</span></div>`}optionId(e){return`${this.filterDropdownId}-option-${e}`}renderList(){const e=this.sections,t=e.flatMap((e=>e.options));if(this.loading&&0===t.length)return a`<div class="n-filter-dropdown-empty" role="status"><nord-spinner size="s"></nord-spinner></div>`;if(0===t.length)return a`<div class="n-filter-dropdown-empty" role="status">${this.noResultsMessage||this.localize.term("noResults")}</div>`;let i=0;return g(e,((e,t)=>t),((e,t)=>{const o=e.heading?`${this.filterDropdownId}-group-${t}`:void 0;return a`<div class="n-filter-dropdown-group" role="group" aria-labelledby="${null!=o?o:d}">${e.heading?a`<div class="n-filter-dropdown-heading" id="${o}" role="presentation">${e.heading}</div>`:d} ${g(e.options,((e,i)=>`${t}-${i}`),(e=>this.renderOption(e,i++)))}</div>`}))}render(){var e;const t=`${this.filterDropdownId}-popout`,i=`${this.filterDropdownId}-list`,o=!this.isInactive,n=this.removable,s=!n&&this.clearable&&o,r=this.open&&null!==(e=this.activeDescendant.activeDescendant)&&void 0!==e?e:d;return a`<nord-button-group><nord-button class="n-filter-dropdown-trigger" type="button" size="${this.size}" variant="${o?d:"dashed"}" aria-controls="${t}" aria-haspopup="dialog" aria-expanded="${this.open?"true":"false"}" aria-activedescendant="${r}" ?disabled="${this.disabled}" @click="${this.handleTriggerClick}" @keydown="${this.handleKeydown}"><nord-icon slot="start" name="${this.icon}" label="${this.localize.term("filterIconLabel")}"></nord-icon><span class="n-filter-dropdown-label">${o?this.localize.term("selectionLabel",this.label):this.label}</span> ${o?a`<span class="n-filter-dropdown-value">${this.selectionLabel}</span>`:d}</nord-button>${s?a`<nord-button class="n-filter-dropdown-clear" type="button" size="${this.size}" square ?disabled="${this.disabled}" @click="${this.handleClear}"><nord-icon name="interface-close-small" size="xs"></nord-icon><nord-visually-hidden>${this.localize.term("clearLabel")}</nord-visually-hidden></nord-button>`:d} ${n?a`<nord-button class="n-filter-dropdown-remove" type="button" size="${this.size}" square variant="${o?d:"dashed"}" ?disabled="${this.disabled}" @click="${this.handleRemove}"><nord-icon name="interface-close-small" size="xs"></nord-icon><nord-visually-hidden>${this.localize.term("removeLabel")}</nord-visually-hidden></nord-button>`:d}</nord-button-group><nord-popout id="${t}" controlled always-floating @open="${this.openState.onPopoutOpen}" @close="${this.openState.onPopoutClose}"><div class="${f({"n-filter-dropdown-panel":!0,[this.listInlineSizeClass]:!0})}">${this.searchable?a`<div class="n-filter-dropdown-search"><nord-input type="search" label="${this.localize.term("searchLabel")}" hide-label expand size="s" .value="${this.search}" ?disabled="${this.disabled}" @input="${this.handleSearchInput}" @keydown="${this.handleKeydown}"><nord-icon slot="start" name="navigation-search"></nord-icon>${this.loading?a`<nord-spinner slot="end" size="s"></nord-spinner>`:d}</nord-input></div>`:d} ${this.selectAll&&this.multiple?a`<div class="n-filter-dropdown-select-all"><div class="${f({"n-filter-dropdown-option":!0,"is-active":!1})}" role="button" tabindex="0" aria-pressed="${this.isAllSelected?"true":"false"}" aria-disabled="${this.disabled?"true":d}" @click="${this.toggleSelectAll}" @keydown="${e=>{"Enter"!==e.key&&" "!==e.key||(e.preventDefault(),this.toggleSelectAll())}}"><span class="n-filter-dropdown-checkbox">${this.isAllSelected?a`<nord-icon name="interface-checked-small" size="xs"></nord-icon>`:d} </span><span class="n-filter-dropdown-option-label">${this.isAllSelected?this.localize.term("deselectAll"):this.localize.term("selectAll")}</span></div></div>`:d}<div ${b(this.listRef)} id="${i}" class="${f({"n-filter-dropdown-list":!0,"is-loading-more":this.loading&&this.flatOptions.length>0})}" role="listbox" aria-label="${this.label||d}" aria-multiselectable="${this.multiple?"true":"false"}" @scroll="${this.handleListScroll}" @keydown="${this.handleKeydown}">${this.renderList()}</div></div></nord-popout>`}};e([c("nord-popout",!0)],R.prototype,"popout",void 0),e([c(".n-filter-dropdown-trigger")],R.prototype,"triggerButton",void 0),e([h({reflect:!0})],R.prototype,"label",void 0),e([h({reflect:!0})],R.prototype,"name",void 0),e([h({reflect:!0})],R.prototype,"icon",void 0),e([h({reflect:!0})],R.prototype,"size",void 0),e([h({attribute:!1})],R.prototype,"options",void 0),e([h({reflect:!0,attribute:"options-value-key"})],R.prototype,"optionsValueKey",void 0),e([h({reflect:!0,attribute:"options-label-key"})],R.prototype,"optionsLabelKey",void 0),e([h({attribute:!1})],R.prototype,"value",void 0),e([h({reflect:!0,type:Boolean})],R.prototype,"multiple",void 0),e([h({reflect:!0,type:Boolean})],R.prototype,"searchable",void 0),e([h({reflect:!0,type:Boolean,attribute:"internal-search"})],R.prototype,"internalSearch",void 0),e([h({reflect:!0,type:Boolean,attribute:"select-all"})],R.prototype,"selectAll",void 0),e([h({reflect:!0,type:Boolean})],R.prototype,"clearable",void 0),e([h({reflect:!0,type:Boolean})],R.prototype,"removable",void 0),e([h({reflect:!0,type:Boolean})],R.prototype,"disabled",void 0),e([h({reflect:!0,type:Boolean})],R.prototype,"loading",void 0),e([h({reflect:!0,type:Boolean})],R.prototype,"open",void 0),e([h({reflect:!0,attribute:"no-results-message"})],R.prototype,"noResultsMessage",void 0),e([h({reflect:!0,attribute:"label-for-unknown"})],R.prototype,"labelForUnknown",void 0),e([u()],R.prototype,"search",void 0),R=e([v("nord-filter-dropdown")],R);var V=R;export{I as FilterDropdownChangeEvent,O as FilterDropdownClearEvent,D as FilterDropdownLoadMoreEvent,S as FilterDropdownRemoveEvent,A as FilterDropdownSearchChangeEvent,V as default};
|
|
1
|
+
import{_ as e}from"./tslib.es6-CmLYFWVC.js";import{c as t}from"./interface-checked-small-BQmkNgCI.js";import{c as i,A as o}from"./ActiveDescendantController-BnMqM79O.js";import{c as n}from"./interface-close-small-CnpAFMO3.js";import{f as s}from"./interface-filter-CCsx9-u6.js";import{s as r}from"./navigation-search-CBbIGzo2.js";import{css as l,html as a,nothing as d,LitElement as p}from"lit";import{query as c,property as h,state as u,customElement as v}from"lit/decorators.js";import{classMap as f}from"lit/directives/class-map.js";import{createRef as m,ref as b}from"lit/directives/ref.js";import{repeat as g}from"lit/directives/repeat.js";import{L as w}from"./LightDismissController-wcL1ziJa.js";import{O as y}from"./OpenStateController-CCnZ7up6.js";import{i as j}from"./light-dom-styles-DXsbiKU9.js";import{D as z}from"./DraftComponentMixin-4qug5Rky.js";import{s as $}from"./filter-chip-C97zd4PT.js";import k from"./Icon.js";import{LocalizeController as x}from"./LocalizeController.js";import{FilterDropdownRemoveEvent as S,FilterDropdownSearchChangeEvent as A,FilterDropdownLoadMoreEvent as D,FilterDropdownChangeEvent as I,FilterDropdownClearEvent as O}from"./FilterDropdownEvents.js";import"./Button.js";import"./ButtonGroup.js";import"./Input.js";import"./Popout-B6Hirj3y.js";import"./Spinner.js";import"./VisuallyHidden.js";import"./number-Dg2vCfGd.js";import"./EventController-BBOmvfLa.js";import"./ShortcutController-CV5b0BZl.js";import"./tinykeys-DwvDXsEb.js";import"./events-Bv6wNHwJ.js";import"lit/directives/if-defined.js";import"lit/directives/unsafe-html.js";import"./observe-D0n0zOfU.js";import"./cond-CI1KbneT.js";import"./Component-BJ5O5n8k.js";import"./IconManager.js";import"./translation.js";import"./en-us.js";import"./localization.js";import"./localization2.js";import"./localization3.js";import"./localization4.js";import"./localization5.js";import"./localization6.js";import"./localization7.js";import"./localization8.js";import"./localization9.js";import"./localization10.js";import"./localization11.js";import"./localization12.js";import"./localization13.js";import"./localization14.js";import"./localization15.js";import"./localization16.js";import"./localization17.js";import"./localization18.js";import"./localization19.js";import"./localization20.js";import"./localization21.js";import"./localization22.js";import"./localization23.js";import"./localization24.js";import"./LightDomController-DIwtVelV.js";import"./SlotController-Z6eG7LSZ.js";import"./FocusableMixin-BlQLNPdJ.js";import"./InputMixin-LetXsCyv.js";import"./DirectionController-ChvNGESZ.js";import"lit/directives/style-map.js";import"./ResizeController-14PUwRQy.js";import"./AutocompleteMixin-D8eiOxvO.js";import"./FormAssociatedMixin-D9aPREgv.js";import"./FormDataController-OUt5L5uC.js";import"./FieldControlMixin-BXNZJXu9.js";import"./context-consumer-BJVUulGf.js";import"./context-request-event-CCRlXoeR.js";import"./field-context.js";import"./create-context-CJ69ntlY.js";import"./ReadonlyMixin-BdJPGtQ3.js";import"./SizeMixin-CU9cLbLC.js";import"./TextSelectableMixin-Cfv__lHS.js";import"./FormField-CMgEFZCK.js";import"./TextField-BYSciLeB.js";import"./positioning-D-K8Mueq.js";import"./ScrollbarController-BFC67Y2x.js";const C=l`nord-filter-dropdown{--_n-filter-dropdown-list-inline-size:var(--n-filter-dropdown-list-inline-size,250px)}nord-filter-dropdown .n-filter-dropdown-panel{display:flex;flex-direction:column;max-inline-size:calc(var(--_n-filter-dropdown-list-inline-size)*1.5);min-inline-size:var(--_n-filter-dropdown-list-inline-size)}nord-filter-dropdown .n-filter-dropdown-size-s{--_n-filter-dropdown-list-inline-size:var(--n-filter-dropdown-list-inline-size,250px)}nord-filter-dropdown .n-filter-dropdown-size-l{--_n-filter-dropdown-list-inline-size:var(--n-filter-dropdown-list-inline-size,300px)}nord-filter-dropdown .n-filter-dropdown-search{padding-block-end:var(--n-space-xs);padding-block-start:var(--n-space-m);padding-inline-end:var(--n-space-m);padding-inline-start:var(--n-space-m)}nord-filter-dropdown .n-filter-dropdown-select-all{border-block-end:1px solid var(--n-color-border);padding-block-start:0}nord-filter-dropdown .n-filter-dropdown-list,nord-filter-dropdown .n-filter-dropdown-select-all{padding-block-end:var(--n-space-s);padding-inline-end:var(--n-space-s);padding-inline-start:var(--n-space-s)}nord-filter-dropdown .n-filter-dropdown-list{max-block-size:330px;overflow-y:auto;padding-block-start:var(--n-space-s)}nord-filter-dropdown .n-filter-dropdown-list.is-loading-more{opacity:.3;pointer-events:none}@media (width <= 35.9375em){nord-filter-dropdown .n-filter-dropdown-panel{max-inline-size:none}nord-filter-dropdown .n-filter-dropdown-list{max-block-size:70vh}}nord-filter-dropdown .n-filter-dropdown-group{border-block-end:1px solid var(--n-color-border);margin-block-end:var(--n-space-s);padding-block-end:var(--n-space-s)}nord-filter-dropdown .n-filter-dropdown-group:last-child{border-block-end:0;margin-block-end:0;padding-block-end:0}nord-filter-dropdown .n-filter-dropdown-heading{color:var(--n-color-text-weaker);font-size:var(--n-font-size-s);font-weight:var(--n-font-weight-active);padding-block-end:var(--n-space-xs);padding-block-start:var(--n-space-xs);padding-inline-end:var(--n-space-s);padding-inline-start:var(--n-space-s)}nord-filter-dropdown .n-filter-dropdown-option{align-items:center;border-radius:var(--n-border-radius-s);color:var(--n-color-text);cursor:pointer;display:flex;gap:var(--n-space-s);padding-block-end:var(--n-space-s);padding-block-start:var(--n-space-s);padding-inline-end:var(--n-space-s);padding-inline-start:var(--n-space-s);user-select:none}nord-filter-dropdown .n-filter-dropdown-option.is-indented{padding-inline-start:var(--n-space-l)}nord-filter-dropdown .n-filter-dropdown-option.is-active,nord-filter-dropdown .n-filter-dropdown-option:hover{background-color:var(--n-color-active)}nord-filter-dropdown .n-filter-dropdown-option.is-disabled{color:var(--n-color-text-weakest);cursor:not-allowed;pointer-events:none}nord-filter-dropdown .n-filter-dropdown-option-label{flex:1 1 auto;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}nord-filter-dropdown .n-filter-dropdown-checkbox{background-color:var(--n-color-surface);block-size:var(--n-space-m);border:1px solid var(--n-color-border-hover);border-radius:var(--n-border-radius-s);color:var(--n-color-text-on-accent);display:grid;flex:0 0 var(--n-space-m);inline-size:var(--n-space-m);place-items:center}nord-filter-dropdown .n-filter-dropdown-checkbox:has(nord-icon){background-color:var(--n-color-accent);border-color:var(--n-color-accent)}nord-filter-dropdown .n-filter-dropdown-check{block-size:var(--n-space-m);color:var(--n-color-text-highlight);display:grid;flex:0 0 var(--n-space-m);inline-size:var(--n-space-m);place-items:center}nord-filter-dropdown .n-filter-dropdown-empty{color:var(--n-color-text-weaker);display:flex;justify-content:center;padding-block-end:var(--n-space-s);padding-block-start:var(--n-space-s);padding-inline-end:var(--n-space-s);padding-inline-start:var(--n-space-s)}`;k.registerIcon(t),k.registerIcon(i),k.registerIcon(n),k.registerIcon(s),k.registerIcon(r);let L=1;function M(e){return"heading"in e}let R=class extends(z(p)){constructor(){super(...arguments),this.filterDropdownId="nord-filter-dropdown-"+L++,this.localize=new x(this),this.listRef=m(),this.dismiss=new w(this,{isOpen:()=>this.open,onDismiss:()=>this.hide(),isDismissible:e=>e!==this}),this.activeDescendant=new o(this,{count:()=>this.flatOptions.length,isEnabled:e=>{var t;return!(null===(t=this.flatOptions[e])||void 0===t?void 0:t.disabled)},optionId:e=>this.optionId(e)}),this.openState=new y(this,{isOpen:()=>this.open,setOpen:e=>{this.open=e},popout:()=>this.popout,isInert:()=>this.disabled,onOpen:()=>{var e;this.loadMoreRequested=!1,null===(e=this.listRef.value)||void 0===e||e.scrollTo(0,0),this.activeDescendant.reset()},onClose:()=>{this.search&&(this.search=""),this.removable&&this.isInactive&&this.dispatchEvent(new S)}}),this.label="",this.name="",this.icon="interface-filter",this.size="s",this.options=[],this.optionsValueKey="value",this.optionsLabelKey="label",this.value="",this.multiple=!1,this.searchable=!1,this.internalSearch=!0,this.selectAll=!1,this.clearable=!0,this.removable=!1,this.disabled=!1,this.loading=!1,this.open=!1,this.noResultsMessage="",this.labelForUnknown="",this.search="",this.scrollActivePending=!1,this.loadMoreRequested=!1,this.handleTriggerClick=()=>{this.openState.toggle()},this.toggleSelectAll=()=>{!this.disabled&&this.multiple&&this.commit(this.isAllSelected?[]:[...this.allSelectableValues])},this.handleClear=e=>{e.stopPropagation(),this.disabled||(this.clear(),this.focus())},this.handleRemove=e=>{e.stopPropagation(),this.disabled||(this.clear(),this.dispatchEvent(new S))},this.handleSearchInput=e=>{if(e.stopPropagation(),this.disabled)return;const t=e.target;this.search=t.value,this.activeDescendant.reset(),this.scrollActivePending=!0,this.dispatchEvent(new A(this.search))},this.handleListScroll=e=>{if(this.disabled)return;const t=e.target,{scrollTop:i,scrollHeight:o,clientHeight:n}=t;if(o<=n)return;(i+n)/o>.8?this.loading||this.loadMoreRequested||(this.loadMoreRequested=!0,this.dispatchEvent(new D)):this.loadMoreRequested=!1},this.handleKeydown=e=>{if(!this.disabled)switch(e.key){case"ArrowDown":if(e.preventDefault(),!this.open)return void this.show();this.activeDescendant.move(1),this.scrollActivePending=!0;break;case"ArrowUp":if(e.preventDefault(),!this.open)return void this.show();this.activeDescendant.move(-1),this.scrollActivePending=!0;break;case"Home":this.open&&(e.preventDefault(),this.activeDescendant.first(),this.scrollActivePending=!0);break;case"End":this.open&&(e.preventDefault(),this.activeDescendant.last(),this.scrollActivePending=!0);break;case"Enter":{if(!this.open)return e.preventDefault(),void this.show();e.preventDefault();const t=this.flatOptions[this.activeDescendant.activeIndex];t&&this.toggle(t);break}case"Escape":this.open&&(e.preventDefault(),this.hide(),this.focus())}}}connectedCallback(){super.connectedCallback(),j(this,C),j(this,$,"nord-filter-chip")}createRenderRoot(){return this}get valueAsArray(){const{value:e}=this;return Array.isArray(e)?e:e?[e]:[]}get isInactive(){return 0===this.valueAsArray.length}getOptionValue(e){var t;return String(null!==(t=e[this.optionsValueKey])&&void 0!==t?t:"")}getOptionLabel(e){var t;return String(null!==(t=e[this.optionsLabelKey])&&void 0!==t?t:"")}get hasGroupedOptions(){return this.options.some((e=>{var t;return M(e)||Boolean(null===(t=e.children)||void 0===t?void 0:t.length)}))}get needle(){return this.searchable&&this.internalSearch?this.search.trim().toLocaleLowerCase():""}matchesSearch(e){const t=this.needle;return!t||this.getOptionLabel(e).toLocaleLowerCase().includes(t)}get sections(){var e,t;const i=(e,t)=>({value:this.getOptionValue(e),label:this.getOptionLabel(e),disabled:Boolean(e.disabled),indent:t,source:e});if(!this.hasGroupedOptions){const e=this.options.filter((e=>this.matchesSearch(e))).map((e=>i(e,!1)));return e.length?[{options:e}]:[]}const o=[];let n=[];const s=()=>{n.length&&(o.push({options:n}),n=[])};for(const r of this.options)if(M(r)){s();const t=(null!==(e=r.children)&&void 0!==e?e:[]).filter((e=>this.matchesSearch(e))).map((e=>i({...e,disabled:e.disabled||r.disabled},!1)));t.length&&o.push({heading:r.heading,options:t})}else if(null===(t=r.children)||void 0===t?void 0:t.length){const e=this.matchesSearch(r),t=r.children.filter((e=>this.matchesSearch(e)));if(e||t.length){e&&n.push(i(r,!1));for(const e of t)n.push(i(e,!0))}}else this.matchesSearch(r)&&n.push(i(r,!1));return s(),o}get flatOptions(){return this.sections.flatMap((e=>e.options))}get allSelectableValues(){var e,t;const i=[];for(const o of this.options)if(M(o)){if(o.disabled)continue;for(const t of null!==(e=o.children)&&void 0!==e?e:[])t.disabled||i.push(this.getOptionValue(t))}else{o.disabled||i.push(this.getOptionValue(o));for(const e of null!==(t=o.children)&&void 0!==t?t:[])o.disabled||e.disabled||i.push(this.getOptionValue(e))}return i}get isAllSelected(){if(!this.selectAll||!this.multiple)return!1;const e=this.allSelectableValues,t=new Set(this.valueAsArray);return e.length>0&&e.every((e=>t.has(e)))}labelForValue(e){var t,i;for(const o of this.options)if(M(o)){for(const i of null!==(t=o.children)&&void 0!==t?t:[])if(this.getOptionValue(i)===e)return this.getOptionLabel(i)}else{if(this.getOptionValue(o)===e)return this.getOptionLabel(o);for(const t of null!==(i=o.children)&&void 0!==i?i:[])if(this.getOptionValue(t)===e)return this.getOptionLabel(t)}return this.labelForUnknown||this.localize.term("unknown")}get selectionLabel(){const e=this.valueAsArray;if(0===e.length)return"";const t=this.labelForValue(e[0]);return e.length>1?t+this.localize.term("countSuffix",e.length-1):t}isSelected(e){return this.valueAsArray.includes(e)}show(){this.openState.show()}hide(){this.openState.hide()}focus(e){var t;null===(t=this.triggerButton)||void 0===t||t.focus(e)}updated(e){var t,i;super.updated(e),this.scrollActivePending&&(this.scrollActivePending=!1,null===(i=null===(t=this.listRef.value)||void 0===t?void 0:t.querySelector(".n-filter-dropdown-option.is-active"))||void 0===i||i.scrollIntoView({block:"nearest"})),this.loadMoreRequested&&(e.has("loading")||e.has("options"))&&(this.loadMoreRequested=!1),e.has("disabled")&&this.disabled&&(this.activeDescendant.reset(),this.scrollActivePending=!0)}commit(e){this.value=e,this.dispatchEvent(new I(e))}toggle(e){if(this.disabled||e.disabled)return;if(!this.multiple)return this.commit(e.value),void this.hide();const t=this.valueAsArray,i=t.includes(e.value)?t.filter((t=>t!==e.value)):[...t,e.value];this.commit(i)}clear(){this.disabled||(this.search="",this.dispatchEvent(new O),this.commit(this.multiple?[]:""))}get listInlineSizeClass(){return`n-filter-dropdown-size-${this.size}`}renderIndicator(e){const t=this.isSelected(e);return this.multiple?a`<span class="n-filter-dropdown-checkbox">${t?a`<nord-icon name="interface-checked-small" size="xs"></nord-icon>`:d}</span>`:a`<span class="n-filter-dropdown-check">${t?a`<nord-icon name="interface-checked" size="s"></nord-icon>`:d}</span>`}renderOption(e,t){const i=this.isSelected(e.value);return a`<div id="${this.optionId(t)}" class="${f({"n-filter-dropdown-option":!0,"is-active":t===this.activeDescendant.activeIndex,"is-disabled":e.disabled,"is-indented":e.indent})}" role="option" aria-selected="${i?"true":"false"}" aria-disabled="${e.disabled?"true":d}" @click="${()=>this.toggle(e)}" @mousemove="${()=>this.activeDescendant.setActiveIndex(t)}">${this.renderIndicator(e.value)} <span class="n-filter-dropdown-option-label">${e.label}</span></div>`}optionId(e){return`${this.filterDropdownId}-option-${e}`}renderList(){const e=this.sections,t=e.flatMap((e=>e.options));if(this.loading&&0===t.length)return a`<div class="n-filter-dropdown-empty" role="status"><nord-spinner size="s"></nord-spinner></div>`;if(0===t.length)return a`<div class="n-filter-dropdown-empty" role="status">${this.noResultsMessage||this.localize.term("noResults")}</div>`;let i=0;return g(e,((e,t)=>t),((e,t)=>{const o=e.heading?`${this.filterDropdownId}-group-${t}`:void 0;return a`<div class="n-filter-dropdown-group" role="group" aria-labelledby="${null!=o?o:d}">${e.heading?a`<div class="n-filter-dropdown-heading" id="${o}" role="presentation">${e.heading}</div>`:d} ${g(e.options,((e,i)=>`${t}-${i}`),(e=>this.renderOption(e,i++)))}</div>`}))}render(){var e;const t=`${this.filterDropdownId}-popout`,i=`${this.filterDropdownId}-list`,o=!this.isInactive,n=this.removable,s=!n&&this.clearable&&o,r=this.open&&null!==(e=this.activeDescendant.activeDescendant)&&void 0!==e?e:d;return a`<nord-button-group><nord-button class="n-filter-dropdown-trigger" type="button" size="${this.size}" variant="${o?d:"dashed"}" aria-controls="${t}" aria-haspopup="dialog" aria-expanded="${this.open?"true":"false"}" aria-activedescendant="${r}" ?disabled="${this.disabled}" @click="${this.handleTriggerClick}" @keydown="${this.handleKeydown}"><nord-icon slot="start" name="${this.icon}" label="${this.localize.term("filterIconLabel")}"></nord-icon><span class="n-filter-dropdown-label">${o?this.localize.term("selectionLabel",this.label):this.label}</span> ${o?a`<span class="n-filter-dropdown-value">${this.selectionLabel}</span>`:d}</nord-button>${s?a`<nord-button class="n-filter-dropdown-clear" type="button" size="${this.size}" square ?disabled="${this.disabled}" @click="${this.handleClear}"><nord-icon name="interface-close-small" size="xs"></nord-icon><nord-visually-hidden>${this.localize.term("clearLabel")}</nord-visually-hidden></nord-button>`:d} ${n?a`<nord-button class="n-filter-dropdown-remove" type="button" size="${this.size}" square variant="${o?d:"dashed"}" ?disabled="${this.disabled}" @click="${this.handleRemove}"><nord-icon name="interface-close-small" size="xs"></nord-icon><nord-visually-hidden>${this.localize.term("removeLabel")}</nord-visually-hidden></nord-button>`:d}</nord-button-group><nord-popout id="${t}" controlled always-floating @open="${this.openState.onPopoutOpen}" @close="${this.openState.onPopoutClose}"><div class="${f({"n-filter-dropdown-panel":!0,[this.listInlineSizeClass]:!0})}">${this.searchable?a`<div class="n-filter-dropdown-search"><nord-input type="search" label="${this.localize.term("searchLabel")}" hide-label expand size="s" .value="${this.search}" ?disabled="${this.disabled}" @input="${this.handleSearchInput}" @keydown="${this.handleKeydown}"><nord-icon slot="start" name="navigation-search"></nord-icon>${this.loading?a`<nord-spinner slot="end" size="s"></nord-spinner>`:d}</nord-input></div>`:d} ${this.selectAll&&this.multiple?a`<div class="n-filter-dropdown-select-all"><div class="${f({"n-filter-dropdown-option":!0,"is-active":!1})}" role="button" tabindex="0" aria-pressed="${this.isAllSelected?"true":"false"}" aria-disabled="${this.disabled?"true":d}" @click="${this.toggleSelectAll}" @keydown="${e=>{"Enter"!==e.key&&" "!==e.key||(e.preventDefault(),this.toggleSelectAll())}}"><span class="n-filter-dropdown-checkbox">${this.isAllSelected?a`<nord-icon name="interface-checked-small" size="xs"></nord-icon>`:d} </span><span class="n-filter-dropdown-option-label">${this.isAllSelected?this.localize.term("deselectAll"):this.localize.term("selectAll")}</span></div></div>`:d}<div ${b(this.listRef)} id="${i}" class="${f({"n-filter-dropdown-list":!0,"is-loading-more":this.loading&&this.flatOptions.length>0})}" role="listbox" aria-label="${this.label||d}" aria-multiselectable="${this.multiple?"true":"false"}" @scroll="${this.handleListScroll}" @keydown="${this.handleKeydown}">${this.renderList()}</div></div></nord-popout>`}};e([c("nord-popout",!0)],R.prototype,"popout",void 0),e([c(".n-filter-dropdown-trigger")],R.prototype,"triggerButton",void 0),e([h({reflect:!0})],R.prototype,"label",void 0),e([h({reflect:!0})],R.prototype,"name",void 0),e([h({reflect:!0})],R.prototype,"icon",void 0),e([h({reflect:!0})],R.prototype,"size",void 0),e([h({attribute:!1})],R.prototype,"options",void 0),e([h({reflect:!0,attribute:"options-value-key"})],R.prototype,"optionsValueKey",void 0),e([h({reflect:!0,attribute:"options-label-key"})],R.prototype,"optionsLabelKey",void 0),e([h({attribute:!1})],R.prototype,"value",void 0),e([h({reflect:!0,type:Boolean})],R.prototype,"multiple",void 0),e([h({reflect:!0,type:Boolean})],R.prototype,"searchable",void 0),e([h({reflect:!0,type:Boolean,attribute:"internal-search"})],R.prototype,"internalSearch",void 0),e([h({reflect:!0,type:Boolean,attribute:"select-all"})],R.prototype,"selectAll",void 0),e([h({reflect:!0,type:Boolean})],R.prototype,"clearable",void 0),e([h({reflect:!0,type:Boolean})],R.prototype,"removable",void 0),e([h({reflect:!0,type:Boolean})],R.prototype,"disabled",void 0),e([h({reflect:!0,type:Boolean})],R.prototype,"loading",void 0),e([h({reflect:!0,type:Boolean})],R.prototype,"open",void 0),e([h({reflect:!0,attribute:"no-results-message"})],R.prototype,"noResultsMessage",void 0),e([h({reflect:!0,attribute:"label-for-unknown"})],R.prototype,"labelForUnknown",void 0),e([u()],R.prototype,"search",void 0),R=e([v("nord-filter-dropdown")],R);var V=R;export{I as FilterDropdownChangeEvent,O as FilterDropdownClearEvent,D as FilterDropdownLoadMoreEvent,S as FilterDropdownRemoveEvent,A as FilterDropdownSearchChangeEvent,V as default};
|
|
2
2
|
//# sourceMappingURL=FilterDropdown.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FilterDropdown.js","sources":["../src/filter-dropdown/FilterDropdown.ts"],"sourcesContent":["// The trigger `nord-button` carries `aria-activedescendant` while the popout is\n// open (it keeps DOM focus, delegating to its inner focusable `<button>`), so it\n// is a valid tab stop. The lint rule cannot statically resolve tabbability\n// through a custom element, so it is disabled for this file.\n/* eslint-disable lit-a11y/aria-activedescendant-has-tabindex */\nimport type { PropertyValues, TemplateResult } from 'lit'\nimport * as checkedSmallIcon from '@nordhealth/icons/lib/assets/interface-checked-small.js'\nimport * as checkedIcon from '@nordhealth/icons/lib/assets/interface-checked.js'\nimport * as closeIcon from '@nordhealth/icons/lib/assets/interface-close-small.js'\nimport * as filterIcon from '@nordhealth/icons/lib/assets/interface-filter.js'\nimport * as searchIcon from '@nordhealth/icons/lib/assets/navigation-search.js'\nimport { html, LitElement, nothing } from 'lit'\nimport { customElement, property, query, state } from 'lit/decorators.js'\nimport { classMap } from 'lit/directives/class-map.js'\nimport { createRef, ref } from 'lit/directives/ref.js'\nimport { repeat } from 'lit/directives/repeat.js'\n\nimport { ActiveDescendantController } from '../common/controllers/ActiveDescendantController.js'\nimport { LightDismissController } from '../common/controllers/LightDismissController.js'\nimport { OpenStateController } from '../common/controllers/OpenStateController.js'\nimport { injectLightDomStyles } from '../common/light-dom-styles.js'\nimport { DraftComponentMixin } from '../common/mixins/DraftComponentMixin.js'\nimport chipStyle from '../common/styles/filter-chip.css'\nimport Icon from '../icon/Icon.js'\nimport { LocalizeController } from '../localization/LocalizeController.js'\nimport style from './FilterDropdown.css'\nimport {\n FilterDropdownChangeEvent,\n FilterDropdownClearEvent,\n FilterDropdownLoadMoreEvent,\n FilterDropdownRemoveEvent,\n FilterDropdownSearchChangeEvent,\n} from './FilterDropdownEvents.js'\nimport '../button/Button.js'\nimport '../button-group/ButtonGroup.js'\nimport '../input/Input.js'\nimport '../popout/Popout.js'\nimport '../spinner/Spinner.js'\nimport '../visually-hidden/VisuallyHidden.js'\n\nIcon.registerIcon(checkedSmallIcon)\nIcon.registerIcon(checkedIcon)\nIcon.registerIcon(closeIcon)\nIcon.registerIcon(filterIcon)\nIcon.registerIcon(searchIcon)\n\nexport {\n FilterDropdownChangeEvent,\n FilterDropdownClearEvent,\n FilterDropdownLoadMoreEvent,\n FilterDropdownRemoveEvent,\n FilterDropdownSearchChangeEvent,\n} from './FilterDropdownEvents.js'\n\n/** Per-instance counter so the popout/trigger ids stay unique in the light DOM. */\nlet filterDropdownCount = 1\n\n/** The size of the trigger and popout. */\nexport type FilterDropdownSize = 's' | 'm' | 'l'\n\n/**\n * A flat, selectable option. With `children` it becomes a tree-style option: the\n * parent stays selectable and the children render indented beneath it.\n */\nexport interface FilterDropdownSelectableOption {\n /** The value submitted with `change` and tracked in `value`. */\n value: string\n /** The human-readable text shown in the list. */\n label: string\n /** When `true`, the option cannot be selected. */\n disabled?: boolean\n /** Tree-style child options, rendered indented under this option. */\n children?: FilterDropdownSelectableOption[]\n /** Arbitrary data; lets `optionsValueKey`/`optionsLabelKey` overrides work. */\n [key: string]: unknown\n}\n\n/** A heading-labelled cluster of options, rendered with a divider. */\nexport interface FilterDropdownGroupOption {\n /** The heading shown above the group's options. */\n heading: string\n /** The options within the group. */\n children: FilterDropdownSelectableOption[]\n /** When `true`, all options within the group cannot be selected. */\n disabled?: boolean\n}\n\n/** Any option shape accepted by the dropdown: flat, grouped, or tree. */\nexport type FilterDropdownOption = FilterDropdownSelectableOption | FilterDropdownGroupOption\n\n/** A flattened, render-ready selectable option (tree children carry `indent`). */\ninterface FlatOption {\n value: string\n label: string\n disabled: boolean\n /** Children are rendered indented under their parent. */\n indent: boolean\n /** The original option, for arbitrary data. */\n source: FilterDropdownSelectableOption\n}\n\n/** A rendered section of the list: a heading group, or a run of flat options. */\ninterface RenderSection {\n heading?: string\n options: FlatOption[]\n}\n\nfunction isGroup(option: FilterDropdownOption): option is FilterDropdownGroupOption {\n return 'heading' in option\n}\n\n/**\n * Filter Dropdown is a full-featured filter control: a chip trigger that opens a\n * popout list of options. It owns its selection and tracks `value`, unlike the\n * composition-first [Filter Field](/components/filter-field/) — pass it `options`\n * and listen for `change`. It ports the Provet Cloud filter dropdown.\n *\n * Options come in three shapes: a flat list (`{ value, label }`), groups\n * (`{ heading, children }`) rendered with dividers, and tree-style options\n * (a selectable option with `children`) where the parent stays selectable and the\n * children render indented. Single mode tracks a string value and closes on\n * select; `multiple` tracks an array, shows checkboxes and keeps the popout open.\n *\n * @status draft\n * @category form\n * @lightDom true\n *\n * @fires {FilterDropdownChangeEvent} change - Dispatched when the committed selection changes via user interaction.\n * @fires {FilterDropdownSearchChangeEvent} search-change - Dispatched as the user types when `searchable` (use with `internal-search=\"false\"` for async search).\n * @fires {FilterDropdownClearEvent} clear - Dispatched when the selection is cleared, before `change`.\n * @fires {FilterDropdownRemoveEvent} remove - Dispatched when the filter is removed (only when `removable`).\n * @fires {FilterDropdownLoadMoreEvent} load-more - Dispatched when the list is scrolled near its end (infinite scroll).\n * @fires {NordEvent} open - Dispatched when the popout is opened.\n * @fires {NordEvent} close - Dispatched when the popout is closed.\n *\n * @localization filterIconLabel - Accessible label for the leading filter icon.\n * @localization selectionLabel - The chip prefix shown before the highlighted value (e.g. \"Status is\").\n * @localization searchLabel - Accessible label for the search input.\n * @localization clearLabel - Accessible label for the clear button.\n * @localization removeLabel - Accessible label for the remove button.\n * @localization selectAll - Label for the select-all row.\n * @localization deselectAll - Label for the select-all row when everything is selected.\n * @localization noResults - Message shown when no options match the search.\n * @localization unknown - Fallback label for a selected value with no matching option.\n * @localization countSuffix - Suffix appended to the first label when several options are selected.\n *\n * @cssprop [--n-filter-dropdown-list-inline-size=250px] - Controls the inline size, or width, of the popout list. Defaults vary by `size`.\n *\n * @parent FilterBar\n */\n@customElement('nord-filter-dropdown')\nexport default class FilterDropdown extends DraftComponentMixin(LitElement) {\n private filterDropdownId = `nord-filter-dropdown-${filterDropdownCount++}`\n\n private localize = new LocalizeController<'nord-filter-dropdown'>(this)\n\n private listRef = createRef<HTMLDivElement>()\n\n @query('nord-popout', true) private popout?: HTMLElement & {\n show: () => Promise<unknown>\n hide: (moveFocusToButton?: boolean) => Promise<unknown>\n }\n\n @query('.n-filter-dropdown-trigger') private triggerButton?: HTMLElement\n\n private dismiss = new LightDismissController(this, {\n isOpen: () => this.open,\n onDismiss: () => this.hide(),\n isDismissible: node => node !== this,\n })\n\n // Tracks the virtual-focus active row (the trigger keeps DOM focus and carries\n // `aria-activedescendant`). Centralises the nextEnabledIndex/move/wrap math.\n private activeDescendant = new ActiveDescendantController(this, {\n count: () => this.flatOptions.length,\n isEnabled: i => !this.flatOptions[i]?.disabled,\n optionId: i => this.optionId(i),\n })\n\n // Coordinates `open` with the popout (drive show/hide, sync from its events,\n // emit one canonical open/close, reject opening while disabled).\n private openState = new OpenStateController(this, {\n isOpen: () => this.open,\n setOpen: (open) => { this.open = open },\n popout: () => this.popout,\n isInert: () => this.disabled,\n onOpen: () => {\n // Reset the list scroll and active row to the top each time it opens, and\n // re-arm infinite scroll so a stale request from a prior open can't block it.\n this.loadMoreRequested = false\n this.listRef.value?.scrollTo(0, 0)\n this.activeDescendant.reset()\n },\n onClose: () => {\n // Discard an abandoned search so the next open shows the full list.\n if (this.search) {\n this.search = ''\n }\n // Removing a removable filter that ends up with no selection mirrors the\n // Provet behaviour of removing it on close when nothing is selected.\n if (this.removable && this.isInactive) {\n this.dispatchEvent(new FilterDropdownRemoveEvent())\n }\n },\n })\n\n /**\n * The label naming what this filter targets, shown on the chip.\n */\n @property({ reflect: true }) label = ''\n\n /**\n * A name identifying what this dropdown filters, for form/identification.\n */\n @property({ reflect: true }) name = ''\n\n /**\n * The icon shown on the trigger.\n */\n @property({ reflect: true }) icon = 'interface-filter'\n\n /**\n * The size of the trigger and popout. Defaults to `s` to match the other\n * filter controls.\n */\n @property({ reflect: true }) size: FilterDropdownSize = 's'\n\n /**\n * The options to show. Either a flat list (`{ value, label }`), groups\n * (`{ heading, children }`), or tree-style options (a selectable option with\n * `children`).\n */\n @property({ attribute: false }) options: FilterDropdownOption[] = []\n\n /**\n * The key on each option object to read the value from. Defaults to `value`.\n */\n @property({ reflect: true, attribute: 'options-value-key' }) optionsValueKey = 'value'\n\n /**\n * The key on each option object to read the label from. Defaults to `label`.\n */\n @property({ reflect: true, attribute: 'options-label-key' }) optionsLabelKey = 'label'\n\n /**\n * The committed value. A single string in single-select mode, or an array of\n * strings when `multiple`.\n */\n @property({ attribute: false }) value: string | string[] = ''\n\n /**\n * Allows selecting more than one option. Selected options show a checkbox\n * indicator and the popout stays open after each selection.\n */\n @property({ reflect: true, type: Boolean }) multiple = false\n\n /**\n * Shows a search input at the top of the popout to filter the options.\n */\n @property({ reflect: true, type: Boolean }) searchable = false\n\n /**\n * Whether options are filtered client-side by their label. Defaults to `true`.\n * Set to `false` for async search: the component then emits `search-change` and\n * leaves filtering to the consumer (who updates `options`).\n */\n @property({ reflect: true, type: Boolean, attribute: 'internal-search' }) internalSearch = true\n\n /**\n * Shows a \"Select all\" control at the top of the popout. Only applies with\n * `multiple`.\n */\n @property({ reflect: true, type: Boolean, attribute: 'select-all' }) selectAll = false\n\n /**\n * Shows a clear (✕) button while there is a selection. Pressing it clears the\n * value (firing `clear` then `change`) without removing the dropdown.\n */\n @property({ reflect: true, type: Boolean }) clearable = true\n\n /**\n * Whether the whole dropdown can be removed. When `true` the trailing\n * affordance clears the value and fires `remove`; the consumer removes the\n * dropdown from the DOM. Takes precedence over `clearable`.\n */\n @property({ reflect: true, type: Boolean }) removable = false\n\n /**\n * Makes the component disabled. This prevents users from being able to\n * interact with it and conveys its inactive state to assistive technologies.\n */\n @property({ reflect: true, type: Boolean }) disabled = false\n\n /**\n * Shows a spinner in the popout while asynchronous results are loading. Pair\n * with `internal-search=\"false\"` for async search.\n */\n @property({ reflect: true, type: Boolean }) loading = false\n\n /**\n * Whether the popout is open. Set it to open or close the popout\n * programmatically.\n */\n @property({ reflect: true, type: Boolean }) open = false\n\n /**\n * Message shown when no options match the search. Defaults to \"No results.\".\n */\n @property({ reflect: true, attribute: 'no-results-message' }) noResultsMessage = ''\n\n /**\n * Fallback label shown for a selected value that has no matching option.\n */\n @property({ reflect: true, attribute: 'label-for-unknown' }) labelForUnknown = ''\n\n /** The current search text. */\n @state() private search = ''\n\n /** Set after a keyboard move so the active row is scrolled into view. */\n private scrollActivePending = false\n\n /**\n * Set once a near-end scroll has emitted `load-more`; blocks further emits\n * from the same gesture until the consumer responds (by toggling `loading` or\n * appending to `options`). Cleared in `updated` when either changes.\n */\n private loadMoreRequested = false\n\n connectedCallback() {\n super.connectedCallback()\n injectLightDomStyles(this, style)\n injectLightDomStyles(this, chipStyle, 'nord-filter-chip')\n }\n\n protected createRenderRoot() {\n return this\n }\n\n // ---------------------------------------------------------------------------\n // Selection helpers\n // ---------------------------------------------------------------------------\n\n /** Normalises `value` to an array regardless of single/multiple shape. */\n private get valueAsArray(): string[] {\n const { value } = this\n if (Array.isArray(value)) {\n return value\n }\n return value ? [value] : []\n }\n\n /** Whether there is any committed selection. */\n private get isInactive(): boolean {\n return this.valueAsArray.length === 0\n }\n\n private getOptionValue(option: FilterDropdownSelectableOption): string {\n return String(option[this.optionsValueKey] ?? '')\n }\n\n private getOptionLabel(option: FilterDropdownSelectableOption): string {\n return String(option[this.optionsLabelKey] ?? '')\n }\n\n // ---------------------------------------------------------------------------\n // Flattening + filtering (mirrors the Provet flattenedOptions logic)\n // ---------------------------------------------------------------------------\n\n /** Whether any option is a group (has a heading) or a tree (has children). */\n private get hasGroupedOptions(): boolean {\n return this.options.some(option => isGroup(option) || Boolean(option.children?.length))\n }\n\n /** Lowercased search needle, or empty when not filtering internally. */\n private get needle(): string {\n return this.searchable && this.internalSearch ? this.search.trim().toLocaleLowerCase() : ''\n }\n\n private matchesSearch(option: FilterDropdownSelectableOption): boolean {\n const needle = this.needle\n if (!needle) {\n return true\n }\n return this.getOptionLabel(option).toLocaleLowerCase().includes(needle)\n }\n\n /**\n * Flattens grouped/tree options into render sections while preserving visual\n * hierarchy: groups keep their heading; tree children are emitted right after\n * their (still-selectable) parent and marked `indent`. Runs of standalone\n * options are coalesced into one section so no divider appears between them.\n * Applies the internal search filter as it goes.\n */\n private get sections(): RenderSection[] {\n const toFlat = (option: FilterDropdownSelectableOption, indent: boolean): FlatOption => ({\n value: this.getOptionValue(option),\n label: this.getOptionLabel(option),\n disabled: Boolean(option.disabled),\n indent,\n source: option,\n })\n\n if (!this.hasGroupedOptions) {\n const flat = (this.options as FilterDropdownSelectableOption[])\n .filter(option => this.matchesSearch(option))\n .map(option => toFlat(option, false))\n return flat.length ? [{ options: flat }] : []\n }\n\n const sections: RenderSection[] = []\n let run: FlatOption[] = []\n\n const flushRun = () => {\n if (run.length) {\n sections.push({ options: run })\n run = []\n }\n }\n\n for (const option of this.options) {\n if (isGroup(option)) {\n flushRun()\n const children = (option.children ?? [])\n .filter(child => this.matchesSearch(child))\n .map(child => toFlat({ ...child, disabled: child.disabled || option.disabled }, false))\n if (children.length) {\n sections.push({ heading: option.heading, options: children })\n }\n continue\n }\n\n // Tree-style option: parent stays selectable, children render indented.\n if (option.children?.length) {\n const parentMatches = this.matchesSearch(option)\n const children = option.children.filter(child => this.matchesSearch(child))\n if (parentMatches || children.length) {\n if (parentMatches) {\n run.push(toFlat(option, false))\n }\n for (const child of children) {\n run.push(toFlat(child, true))\n }\n }\n continue\n }\n\n // Standalone option.\n if (this.matchesSearch(option)) {\n run.push(toFlat(option, false))\n }\n }\n\n flushRun()\n return sections\n }\n\n /** The flat option list in render order, used for keyboard navigation. */\n private get flatOptions(): FlatOption[] {\n return this.sections.flatMap(section => section.options)\n }\n\n /** Every selectable value (skipping disabled options), for select-all. */\n private get allSelectableValues(): string[] {\n const values: string[] = []\n for (const option of this.options) {\n if (isGroup(option)) {\n if (option.disabled) {\n continue\n }\n for (const child of option.children ?? []) {\n if (!child.disabled) {\n values.push(this.getOptionValue(child))\n }\n }\n continue\n }\n if (!option.disabled) {\n values.push(this.getOptionValue(option))\n }\n for (const child of option.children ?? []) {\n if (!option.disabled && !child.disabled) {\n values.push(this.getOptionValue(child))\n }\n }\n }\n return values\n }\n\n private get isAllSelected(): boolean {\n if (!this.selectAll || !this.multiple) {\n return false\n }\n const all = this.allSelectableValues\n const selected = new Set(this.valueAsArray)\n return all.length > 0 && all.every(value => selected.has(value))\n }\n\n /** Resolves a value to its label across flat, grouped and tree options. */\n private labelForValue(key: string): string {\n for (const option of this.options) {\n if (isGroup(option)) {\n for (const child of option.children ?? []) {\n if (this.getOptionValue(child) === key) {\n return this.getOptionLabel(child)\n }\n }\n continue\n }\n if (this.getOptionValue(option) === key) {\n return this.getOptionLabel(option)\n }\n for (const child of option.children ?? []) {\n if (this.getOptionValue(child) === key) {\n return this.getOptionLabel(child)\n }\n }\n }\n return this.labelForUnknown || this.localize.term('unknown')\n }\n\n /** The summary shown on the chip when there is a selection. */\n private get selectionLabel(): string {\n const values = this.valueAsArray\n if (values.length === 0) {\n return ''\n }\n const first = this.labelForValue(values[0]!)\n if (values.length > 1) {\n return first + this.localize.term('countSuffix', values.length - 1)\n }\n return first\n }\n\n private isSelected(value: string): boolean {\n return this.valueAsArray.includes(value)\n }\n\n // ---------------------------------------------------------------------------\n // Open / close\n // ---------------------------------------------------------------------------\n\n /** Open the popout. */\n show() {\n this.openState.show()\n }\n\n /** Close the popout. */\n hide() {\n this.openState.hide()\n }\n\n /** Focus the trigger button. */\n focus(options?: FocusOptions) {\n this.triggerButton?.focus(options)\n }\n\n private handleTriggerClick = () => {\n this.openState.toggle()\n }\n\n protected updated(changed: PropertyValues) {\n super.updated(changed)\n if (this.scrollActivePending) {\n this.scrollActivePending = false\n this.listRef.value?.querySelector('.n-filter-dropdown-option.is-active')?.scrollIntoView({ block: 'nearest' })\n }\n // The consumer has responded to a `load-more` (toggled `loading` or appended\n // options), so allow the next near-end gesture to request again.\n if (this.loadMoreRequested && (changed.has('loading') || changed.has('options'))) {\n this.loadMoreRequested = false\n }\n if (changed.has('disabled') && this.disabled) {\n this.activeDescendant.reset()\n this.scrollActivePending = true\n }\n }\n\n // ---------------------------------------------------------------------------\n // Selection actions\n // ---------------------------------------------------------------------------\n\n private commit(value: string | string[]) {\n this.value = value\n /** Dispatched when the committed value changes via user interaction. */\n this.dispatchEvent(new FilterDropdownChangeEvent(value))\n }\n\n private toggle(option: FlatOption) {\n if (this.disabled || option.disabled) {\n return\n }\n\n if (!this.multiple) {\n this.commit(option.value)\n this.hide()\n return\n }\n\n const current = this.valueAsArray\n const next = current.includes(option.value)\n ? current.filter(value => value !== option.value)\n : [...current, option.value]\n this.commit(next)\n }\n\n private toggleSelectAll = () => {\n if (this.disabled || !this.multiple) {\n return\n }\n this.commit(this.isAllSelected ? [] : [...this.allSelectableValues])\n }\n\n private clear() {\n if (this.disabled) {\n return\n }\n\n this.search = ''\n this.dispatchEvent(new FilterDropdownClearEvent())\n this.commit(this.multiple ? [] : '')\n }\n\n private handleClear = (e: Event) => {\n e.stopPropagation()\n if (this.disabled) {\n return\n }\n\n this.clear()\n this.focus()\n }\n\n private handleRemove = (e: Event) => {\n e.stopPropagation()\n if (this.disabled) {\n return\n }\n\n this.clear()\n /** Dispatched when the filter is removed. */\n this.dispatchEvent(new FilterDropdownRemoveEvent())\n }\n\n private handleSearchInput = (e: Event) => {\n e.stopPropagation()\n if (this.disabled) {\n return\n }\n\n const input = e.target as HTMLInputElement & { value: string }\n this.search = input.value\n this.activeDescendant.reset()\n this.scrollActivePending = true\n /** Dispatched as the user types into the search input. */\n this.dispatchEvent(new FilterDropdownSearchChangeEvent(this.search))\n }\n\n private handleListScroll = (e: Event) => {\n if (this.disabled) {\n return\n }\n\n const target = e.target as HTMLElement\n const { scrollTop, scrollHeight, clientHeight } = target\n if (scrollHeight <= clientHeight) {\n return\n }\n const nearEnd = (scrollTop + clientHeight) / scrollHeight > 0.8\n\n // Re-arm once the user scrolls back up away from the end, so a fresh near-end\n // gesture can request more even when the consumer answered the previous\n // `load-more` without changing `loading`/`options` (e.g. an exhausted or\n // empty page). Otherwise the flag could stick `true` forever.\n if (!nearEnd) {\n this.loadMoreRequested = false\n return\n }\n\n // While a load is in flight, or a previous near-end gesture has already\n // requested more, swallow the scroll so one gesture cannot emit a burst of\n // duplicate `load-more` events before `options`/`loading` have caught up.\n if (this.loading || this.loadMoreRequested) {\n return\n }\n\n this.loadMoreRequested = true\n /** Dispatched when the list is scrolled near its end. */\n this.dispatchEvent(new FilterDropdownLoadMoreEvent())\n }\n\n // ---------------------------------------------------------------------------\n // Keyboard navigation (mirrors ComboboxBase)\n // ---------------------------------------------------------------------------\n\n private handleKeydown = (e: KeyboardEvent) => {\n if (this.disabled) {\n return\n }\n\n switch (e.key) {\n case 'ArrowDown':\n e.preventDefault()\n if (!this.open) {\n this.show()\n return\n }\n this.activeDescendant.move(1)\n this.scrollActivePending = true\n break\n case 'ArrowUp':\n e.preventDefault()\n if (!this.open) {\n this.show()\n return\n }\n this.activeDescendant.move(-1)\n this.scrollActivePending = true\n break\n case 'Home':\n if (this.open) {\n e.preventDefault()\n this.activeDescendant.first()\n this.scrollActivePending = true\n }\n break\n case 'End':\n if (this.open) {\n e.preventDefault()\n this.activeDescendant.last()\n this.scrollActivePending = true\n }\n break\n case 'Enter': {\n if (!this.open) {\n // Prevent the native button click that Enter would also fire, which\n // would run handleTriggerClick with open already true and close it again.\n e.preventDefault()\n this.show()\n return\n }\n // While open, Enter belongs to the list (commit the active option, or a\n // no-op) — never let it submit a surrounding form.\n e.preventDefault()\n const option = this.flatOptions[this.activeDescendant.activeIndex]\n if (option) {\n this.toggle(option)\n }\n break\n }\n case 'Escape':\n if (this.open) {\n e.preventDefault()\n this.hide()\n this.focus()\n }\n break\n default:\n break\n }\n }\n\n // ---------------------------------------------------------------------------\n // Rendering\n // ---------------------------------------------------------------------------\n\n private get listInlineSizeClass(): string {\n return `n-filter-dropdown-size-${this.size}`\n }\n\n private renderIndicator(value: string): TemplateResult {\n const selected = this.isSelected(value)\n if (this.multiple) {\n return html`\n <span class=\"n-filter-dropdown-checkbox\">\n ${selected\n ? html`<nord-icon name=\"interface-checked-small\" size=\"xs\"></nord-icon>`\n : nothing}\n </span>\n `\n }\n return html`\n <span class=\"n-filter-dropdown-check\">\n ${selected ? html`<nord-icon name=\"interface-checked\" size=\"s\"></nord-icon>` : nothing}\n </span>\n `\n }\n\n private renderOption(option: FlatOption, index: number): TemplateResult {\n const selected = this.isSelected(option.value)\n return html`\n <div\n id=${this.optionId(index)}\n class=${classMap({\n 'n-filter-dropdown-option': true,\n 'is-active': index === this.activeDescendant.activeIndex,\n 'is-disabled': option.disabled,\n 'is-indented': option.indent,\n })}\n role=\"option\"\n aria-selected=${selected ? 'true' : 'false'}\n aria-disabled=${option.disabled ? 'true' : nothing}\n @click=${() => this.toggle(option)}\n @mousemove=${() => this.activeDescendant.setActiveIndex(index)}\n >\n ${this.renderIndicator(option.value)}\n <span class=\"n-filter-dropdown-option-label\">${option.label}</span>\n </div>\n `\n }\n\n private optionId(index: number): string {\n return `${this.filterDropdownId}-option-${index}`\n }\n\n private renderList(): unknown {\n const sections = this.sections\n // Derive the flat list from THIS `sections` instance — `this.flatOptions`\n // re-invokes the `sections` getter and produces fresh option objects, which\n // would mean the indices below no longer line up with the rendered rows.\n const flat = sections.flatMap(section => section.options)\n\n if (this.loading && flat.length === 0) {\n return html`\n <div class=\"n-filter-dropdown-empty\" role=\"status\">\n <nord-spinner size=\"s\"></nord-spinner>\n </div>\n `\n }\n\n if (flat.length === 0) {\n return html`\n <div class=\"n-filter-dropdown-empty\" role=\"status\">\n ${this.noResultsMessage || this.localize.term('noResults')}\n </div>\n `\n }\n\n // Render order is the source of truth for the navigable index. Thread a\n // running counter through the sections so each rendered row gets its true\n // flat-list position — a value→index lookup would collapse duplicate values\n // that appear in more than one group or tree branch onto a single index.\n let flatIndex = 0\n\n return repeat(\n sections,\n (_section, index) => index,\n (section, index) => {\n const headingId = section.heading ? `${this.filterDropdownId}-group-${index}` : undefined\n return html`\n <div\n class=\"n-filter-dropdown-group\"\n role=\"group\"\n aria-labelledby=${headingId ?? nothing}\n >\n ${section.heading\n ? html`<div class=\"n-filter-dropdown-heading\" id=${headingId} role=\"presentation\">${section.heading}</div>`\n : nothing}\n ${repeat(\n section.options,\n (_option, i) => `${index}-${i}`,\n option => this.renderOption(option, flatIndex++),\n )}\n </div>\n `\n },\n )\n }\n\n render() {\n const popoutId = `${this.filterDropdownId}-popout`\n const listId = `${this.filterDropdownId}-list`\n const active = !this.isInactive\n const showRemove = this.removable\n const showClear = !showRemove && this.clearable && active\n // The trigger keeps DOM focus while the popout is open, so it carries\n // `aria-activedescendant` pointing at the highlighted option row. Cleared\n // (set to `nothing`) when closed or when nothing is active.\n const activeDescendant\n = this.open ? this.activeDescendant.activeDescendant ?? nothing : nothing\n\n return html`\n <nord-button-group>\n <nord-button\n class=\"n-filter-dropdown-trigger\"\n type=\"button\"\n size=${this.size}\n variant=${active ? nothing : 'dashed'}\n aria-controls=${popoutId}\n aria-haspopup=\"dialog\"\n aria-expanded=${this.open ? 'true' : 'false'}\n aria-activedescendant=${activeDescendant}\n ?disabled=${this.disabled}\n @click=${this.handleTriggerClick}\n @keydown=${this.handleKeydown}\n >\n <nord-icon\n slot=\"start\"\n name=${this.icon}\n label=${this.localize.term('filterIconLabel')}\n ></nord-icon>\n <span class=\"n-filter-dropdown-label\">${active ? this.localize.term('selectionLabel', this.label) : this.label}</span>\n ${active\n ? html`<span class=\"n-filter-dropdown-value\">${this.selectionLabel}</span>`\n : nothing}\n </nord-button>\n\n ${showClear\n ? html`\n <nord-button\n class=\"n-filter-dropdown-clear\"\n type=\"button\"\n size=${this.size}\n square\n ?disabled=${this.disabled}\n @click=${this.handleClear}\n >\n <nord-icon name=\"interface-close-small\" size=\"xs\"></nord-icon>\n <nord-visually-hidden>${this.localize.term('clearLabel')}</nord-visually-hidden>\n </nord-button>\n `\n : nothing}\n ${showRemove\n ? html`\n <nord-button\n class=\"n-filter-dropdown-remove\"\n type=\"button\"\n size=${this.size}\n square\n variant=${active ? nothing : 'dashed'}\n ?disabled=${this.disabled}\n @click=${this.handleRemove}\n >\n <nord-icon name=\"interface-close-small\" size=\"xs\"></nord-icon>\n <nord-visually-hidden>${this.localize.term('removeLabel')}</nord-visually-hidden>\n </nord-button>\n `\n : nothing}\n </nord-button-group>\n\n <nord-popout\n id=${popoutId}\n controlled\n always-floating\n @open=${this.openState.onPopoutOpen}\n @close=${this.openState.onPopoutClose}\n >\n <div class=${classMap({ 'n-filter-dropdown-panel': true, [this.listInlineSizeClass]: true })}>\n ${this.searchable\n ? html`\n <div class=\"n-filter-dropdown-search\">\n <nord-input\n type=\"search\"\n label=${this.localize.term('searchLabel')}\n hide-label\n expand\n size=\"s\"\n .value=${this.search}\n ?disabled=${this.disabled}\n @input=${this.handleSearchInput}\n @keydown=${this.handleKeydown}\n >\n <nord-icon slot=\"start\" name=\"navigation-search\"></nord-icon>\n ${this.loading ? html`<nord-spinner slot=\"end\" size=\"s\"></nord-spinner>` : nothing}\n </nord-input>\n </div>\n `\n : nothing}\n\n ${this.selectAll && this.multiple\n ? html`\n <div class=\"n-filter-dropdown-select-all\">\n <div\n class=${classMap({\n 'n-filter-dropdown-option': true,\n 'is-active': false,\n })}\n role=\"button\"\n tabindex=\"0\"\n aria-pressed=${this.isAllSelected ? 'true' : 'false'}\n aria-disabled=${this.disabled ? 'true' : nothing}\n @click=${this.toggleSelectAll}\n @keydown=${(e: KeyboardEvent) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault()\n this.toggleSelectAll()\n }\n }}\n >\n <span class=\"n-filter-dropdown-checkbox\">\n ${this.isAllSelected\n ? html`<nord-icon name=\"interface-checked-small\" size=\"xs\"></nord-icon>`\n : nothing}\n </span>\n <span class=\"n-filter-dropdown-option-label\">\n ${this.isAllSelected ? this.localize.term('deselectAll') : this.localize.term('selectAll')}\n </span>\n </div>\n </div>\n `\n : nothing}\n\n <div\n ${ref(this.listRef)}\n id=${listId}\n class=${classMap({ 'n-filter-dropdown-list': true, 'is-loading-more': this.loading && this.flatOptions.length > 0 })}\n role=\"listbox\"\n aria-label=${this.label || nothing}\n aria-multiselectable=${this.multiple ? 'true' : 'false'}\n @scroll=${this.handleListScroll}\n @keydown=${this.handleKeydown}\n >\n ${this.renderList()}\n </div>\n </div>\n </nord-popout>\n `\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'nord-filter-dropdown': FilterDropdown\n }\n}\n"],"names":["Icon","registerIcon","checkedSmallIcon","checkedIcon","closeIcon","filterIcon","searchIcon","filterDropdownCount","isGroup","option","FilterDropdown","DraftComponentMixin","LitElement","constructor","this","filterDropdownId","localize","LocalizeController","listRef","createRef","dismiss","LightDismissController","isOpen","open","onDismiss","hide","isDismissible","node","activeDescendant","ActiveDescendantController","count","flatOptions","length","isEnabled","i","_a","disabled","optionId","openState","OpenStateController","setOpen","popout","isInert","onOpen","loadMoreRequested","value","scrollTo","reset","onClose","search","removable","isInactive","dispatchEvent","FilterDropdownRemoveEvent","label","name","icon","size","options","optionsValueKey","optionsLabelKey","multiple","searchable","internalSearch","selectAll","clearable","loading","noResultsMessage","labelForUnknown","scrollActivePending","handleTriggerClick","toggle","toggleSelectAll","commit","isAllSelected","allSelectableValues","handleClear","e","stopPropagation","clear","focus","handleRemove","handleSearchInput","input","target","FilterDropdownSearchChangeEvent","handleListScroll","scrollTop","scrollHeight","clientHeight","FilterDropdownLoadMoreEvent","handleKeydown","key","preventDefault","show","move","first","last","activeIndex","connectedCallback","super","injectLightDomStyles","style","chipStyle","createRenderRoot","valueAsArray","Array","isArray","getOptionValue","String","getOptionLabel","hasGroupedOptions","some","Boolean","children","needle","trim","toLocaleLowerCase","matchesSearch","includes","sections","toFlat","indent","source","flat","filter","map","run","flushRun","push","child","heading","_b","parentMatches","flatMap","section","values","all","selected","Set","every","has","labelForValue","term","selectionLabel","isSelected","triggerButton","updated","changed","querySelector","scrollIntoView","block","FilterDropdownChangeEvent","current","next","FilterDropdownClearEvent","listInlineSizeClass","renderIndicator","html","nothing","renderOption","index","classMap","setActiveIndex","renderList","flatIndex","repeat","_section","headingId","undefined","_option","render","popoutId","listId","active","showRemove","showClear","onPopoutOpen","onPopoutClose","ref","__decorate","query","prototype","property","reflect","attribute","type","state","customElement"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"FilterDropdown.js","sources":["../src/filter-dropdown/FilterDropdown.ts"],"sourcesContent":["// The trigger `nord-button` carries `aria-activedescendant` while the popout is\n// open (it keeps DOM focus, delegating to its inner focusable `<button>`), so it\n// is a valid tab stop. The lint rule cannot statically resolve tabbability\n// through a custom element, so it is disabled for this file.\n/* eslint-disable lit-a11y/aria-activedescendant-has-tabindex */\nimport type { PropertyValues, TemplateResult } from 'lit'\nimport * as checkedSmallIcon from '@nordhealth/icons/lib/assets/interface-checked-small.js'\nimport * as checkedIcon from '@nordhealth/icons/lib/assets/interface-checked.js'\nimport * as closeIcon from '@nordhealth/icons/lib/assets/interface-close-small.js'\nimport * as filterIcon from '@nordhealth/icons/lib/assets/interface-filter.js'\nimport * as searchIcon from '@nordhealth/icons/lib/assets/navigation-search.js'\nimport { html, LitElement, nothing } from 'lit'\nimport { customElement, property, query, state } from 'lit/decorators.js'\nimport { classMap } from 'lit/directives/class-map.js'\nimport { createRef, ref } from 'lit/directives/ref.js'\nimport { repeat } from 'lit/directives/repeat.js'\n\nimport { ActiveDescendantController } from '../common/controllers/ActiveDescendantController.js'\nimport { LightDismissController } from '../common/controllers/LightDismissController.js'\nimport { OpenStateController } from '../common/controllers/OpenStateController.js'\nimport { injectLightDomStyles } from '../common/light-dom-styles.js'\nimport { DraftComponentMixin } from '../common/mixins/DraftComponentMixin.js'\nimport chipStyle from '../common/styles/filter-chip.css'\nimport Icon from '../icon/Icon.js'\nimport { LocalizeController } from '../localization/LocalizeController.js'\nimport style from './FilterDropdown.css'\nimport {\n FilterDropdownChangeEvent,\n FilterDropdownClearEvent,\n FilterDropdownLoadMoreEvent,\n FilterDropdownRemoveEvent,\n FilterDropdownSearchChangeEvent,\n} from './FilterDropdownEvents.js'\nimport '../button/Button.js'\nimport '../button-group/ButtonGroup.js'\nimport '../input/Input.js'\nimport '../popout/Popout.js'\nimport '../spinner/Spinner.js'\nimport '../visually-hidden/VisuallyHidden.js'\n\nIcon.registerIcon(checkedSmallIcon)\nIcon.registerIcon(checkedIcon)\nIcon.registerIcon(closeIcon)\nIcon.registerIcon(filterIcon)\nIcon.registerIcon(searchIcon)\n\nexport {\n FilterDropdownChangeEvent,\n FilterDropdownClearEvent,\n FilterDropdownLoadMoreEvent,\n FilterDropdownRemoveEvent,\n FilterDropdownSearchChangeEvent,\n} from './FilterDropdownEvents.js'\n\n/** Per-instance counter so the popout/trigger ids stay unique in the light DOM. */\nlet filterDropdownCount = 1\n\n/** The size of the trigger and popout. */\nexport type FilterDropdownSize = 's' | 'm' | 'l'\n\n/**\n * A flat, selectable option. With `children` it becomes a tree-style option: the\n * parent stays selectable and the children render indented beneath it.\n */\nexport interface FilterDropdownSelectableOption {\n /** The value submitted with `change` and tracked in `value`. */\n value: string\n /** The human-readable text shown in the list. */\n label: string\n /** When `true`, the option cannot be selected. */\n disabled?: boolean\n /** Tree-style child options, rendered indented under this option. */\n children?: FilterDropdownSelectableOption[]\n /** Arbitrary data; lets `optionsValueKey`/`optionsLabelKey` overrides work. */\n [key: string]: unknown\n}\n\n/** A heading-labelled cluster of options, rendered with a divider. */\nexport interface FilterDropdownGroupOption {\n /** The heading shown above the group's options. */\n heading: string\n /** The options within the group. */\n children: FilterDropdownSelectableOption[]\n /** When `true`, all options within the group cannot be selected. */\n disabled?: boolean\n}\n\n/** Any option shape accepted by the dropdown: flat, grouped, or tree. */\nexport type FilterDropdownOption = FilterDropdownSelectableOption | FilterDropdownGroupOption\n\n/** A flattened, render-ready selectable option (tree children carry `indent`). */\ninterface FlatOption {\n value: string\n label: string\n disabled: boolean\n /** Children are rendered indented under their parent. */\n indent: boolean\n /** The original option, for arbitrary data. */\n source: FilterDropdownSelectableOption\n}\n\n/** A rendered section of the list: a heading group, or a run of flat options. */\ninterface RenderSection {\n heading?: string\n options: FlatOption[]\n}\n\nfunction isGroup(option: FilterDropdownOption): option is FilterDropdownGroupOption {\n return 'heading' in option\n}\n\n/**\n * Filter Dropdown is a full-featured filter control: a chip trigger that opens a\n * popout list of options. It owns its selection and tracks `value`, unlike the\n * composition-first [Filter Field](/components/filter-field/) — pass it `options`\n * and listen for `change`. It ports the Provet Cloud filter dropdown.\n *\n * Options come in three shapes: a flat list (`{ value, label }`), groups\n * (`{ heading, children }`) rendered with dividers, and tree-style options\n * (a selectable option with `children`) where the parent stays selectable and the\n * children render indented. Single mode tracks a string value and closes on\n * select; `multiple` tracks an array, shows checkboxes and keeps the popout open.\n *\n * @status draft\n * @category form\n * @lightDom true\n *\n * @fires {FilterDropdownChangeEvent} change - Dispatched when the committed selection changes via user interaction.\n * @fires {FilterDropdownSearchChangeEvent} search-change - Dispatched as the user types when `searchable` (use with `internal-search=\"false\"` for async search).\n * @fires {FilterDropdownClearEvent} clear - Dispatched when the selection is cleared, before `change`.\n * @fires {FilterDropdownRemoveEvent} remove - Dispatched when the filter is removed (only when `removable`).\n * @fires {FilterDropdownLoadMoreEvent} load-more - Dispatched when the list is scrolled near its end (infinite scroll).\n * @fires {NordEvent} open - Dispatched when the popout is opened.\n * @fires {NordEvent} close - Dispatched when the popout is closed.\n *\n * @localization filterIconLabel - Accessible label for the leading filter icon.\n * @localization selectionLabel - The chip prefix shown before the highlighted value (e.g. \"Status is\").\n * @localization searchLabel - Accessible label for the search input.\n * @localization clearLabel - Accessible label for the clear button.\n * @localization removeLabel - Accessible label for the remove button.\n * @localization selectAll - Label for the select-all row.\n * @localization deselectAll - Label for the select-all row when everything is selected.\n * @localization noResults - Message shown when no options match the search.\n * @localization unknown - Fallback label for a selected value with no matching option.\n * @localization countSuffix - Suffix appended to the first label when several options are selected.\n *\n * @cssprop [--n-filter-dropdown-list-inline-size=250px] - Controls the inline size, or width, of the popout list. Defaults vary by `size`.\n *\n * @parent FilterBar\n */\n@customElement('nord-filter-dropdown')\nexport default class FilterDropdown extends DraftComponentMixin(LitElement) {\n private filterDropdownId = `nord-filter-dropdown-${filterDropdownCount++}`\n\n private localize = new LocalizeController<'nord-filter-dropdown'>(this)\n\n private listRef = createRef<HTMLDivElement>()\n\n @query('nord-popout', true) private popout?: HTMLElement & {\n show: () => Promise<unknown>\n hide: (moveFocusToButton?: boolean) => Promise<unknown>\n }\n\n @query('.n-filter-dropdown-trigger') private triggerButton?: HTMLElement\n\n private dismiss = new LightDismissController(this, {\n isOpen: () => this.open,\n onDismiss: () => this.hide(),\n isDismissible: node => node !== this,\n })\n\n // Tracks the virtual-focus active row (the trigger keeps DOM focus and carries\n // `aria-activedescendant`). Centralises the nextEnabledIndex/move/wrap math.\n private activeDescendant = new ActiveDescendantController(this, {\n count: () => this.flatOptions.length,\n isEnabled: i => !this.flatOptions[i]?.disabled,\n optionId: i => this.optionId(i),\n })\n\n // Coordinates `open` with the popout (drive show/hide, sync from its events,\n // emit one canonical open/close, reject opening while disabled).\n private openState = new OpenStateController(this, {\n isOpen: () => this.open,\n setOpen: (open) => { this.open = open },\n popout: () => this.popout,\n isInert: () => this.disabled,\n onOpen: () => {\n // Reset the list scroll and active row to the top each time it opens, and\n // re-arm infinite scroll so a stale request from a prior open can't block it.\n this.loadMoreRequested = false\n this.listRef.value?.scrollTo(0, 0)\n this.activeDescendant.reset()\n },\n onClose: () => {\n // Discard an abandoned search so the next open shows the full list.\n if (this.search) {\n this.search = ''\n }\n // Removing a removable filter that ends up with no selection mirrors the\n // Provet behaviour of removing it on close when nothing is selected.\n if (this.removable && this.isInactive) {\n this.dispatchEvent(new FilterDropdownRemoveEvent())\n }\n },\n })\n\n /**\n * The label naming what this filter targets, shown on the chip.\n */\n @property({ reflect: true }) label = ''\n\n /**\n * A name identifying what this dropdown filters, for form/identification.\n */\n @property({ reflect: true }) name = ''\n\n /**\n * The icon shown on the trigger.\n */\n @property({ reflect: true }) icon = 'interface-filter'\n\n /**\n * The size of the trigger and popout. Defaults to `s` to match the other\n * filter controls.\n */\n @property({ reflect: true }) size: FilterDropdownSize = 's'\n\n /**\n * The options to show. Either a flat list (`{ value, label }`), groups\n * (`{ heading, children }`), or tree-style options (a selectable option with\n * `children`).\n */\n @property({ attribute: false }) options: FilterDropdownOption[] = []\n\n /**\n * The key on each option object to read the value from. Defaults to `value`.\n */\n @property({ reflect: true, attribute: 'options-value-key' }) optionsValueKey = 'value'\n\n /**\n * The key on each option object to read the label from. Defaults to `label`.\n */\n @property({ reflect: true, attribute: 'options-label-key' }) optionsLabelKey = 'label'\n\n /**\n * The committed value. A single string in single-select mode, or an array of\n * strings when `multiple`.\n */\n @property({ attribute: false }) value: string | string[] = ''\n\n /**\n * Allows selecting more than one option. Selected options show a checkbox\n * indicator and the popout stays open after each selection.\n */\n @property({ reflect: true, type: Boolean }) multiple = false\n\n /**\n * Shows a search input at the top of the popout to filter the options.\n */\n @property({ reflect: true, type: Boolean }) searchable = false\n\n /**\n * Whether options are filtered client-side by their label. Defaults to `true`.\n * Set to `false` for async search: the component then emits `search-change` and\n * leaves filtering to the consumer (who updates `options`).\n */\n @property({ reflect: true, type: Boolean, attribute: 'internal-search' }) internalSearch = true\n\n /**\n * Shows a \"Select all\" control at the top of the popout. Only applies with\n * `multiple`.\n */\n @property({ reflect: true, type: Boolean, attribute: 'select-all' }) selectAll = false\n\n /**\n * Shows a clear (✕) button while there is a selection. Pressing it clears the\n * value (firing `clear` then `change`) without removing the dropdown.\n */\n @property({ reflect: true, type: Boolean }) clearable = true\n\n /**\n * Whether the whole dropdown can be removed. When `true` the trailing\n * affordance clears the value and fires `remove`; the consumer removes the\n * dropdown from the DOM. Takes precedence over `clearable`.\n */\n @property({ reflect: true, type: Boolean }) removable = false\n\n /**\n * Makes the component disabled. This prevents users from being able to\n * interact with it and conveys its inactive state to assistive technologies.\n */\n @property({ reflect: true, type: Boolean }) disabled = false\n\n /**\n * Shows a spinner in the popout while asynchronous results are loading. Pair\n * with `internal-search=\"false\"` for async search.\n */\n @property({ reflect: true, type: Boolean }) loading = false\n\n /**\n * Whether the popout is open. Set it to open or close the popout\n * programmatically.\n */\n @property({ reflect: true, type: Boolean }) open = false\n\n /**\n * Message shown when no options match the search. Defaults to \"No results.\".\n */\n @property({ reflect: true, attribute: 'no-results-message' }) noResultsMessage = ''\n\n /**\n * Fallback label shown for a selected value that has no matching option.\n */\n @property({ reflect: true, attribute: 'label-for-unknown' }) labelForUnknown = ''\n\n /** The current search text. */\n @state() private search = ''\n\n /** Set after a keyboard move so the active row is scrolled into view. */\n private scrollActivePending = false\n\n /**\n * Set once a near-end scroll has emitted `load-more`; blocks further emits\n * from the same gesture until the consumer responds (by toggling `loading` or\n * appending to `options`). Cleared in `updated` when either changes.\n */\n private loadMoreRequested = false\n\n connectedCallback() {\n super.connectedCallback()\n injectLightDomStyles(this, style)\n injectLightDomStyles(this, chipStyle, 'nord-filter-chip')\n }\n\n protected createRenderRoot() {\n return this\n }\n\n // ---------------------------------------------------------------------------\n // Selection helpers\n // ---------------------------------------------------------------------------\n\n /** Normalises `value` to an array regardless of single/multiple shape. */\n private get valueAsArray(): string[] {\n const { value } = this\n if (Array.isArray(value)) {\n return value\n }\n return value ? [value] : []\n }\n\n /** Whether there is any committed selection. */\n private get isInactive(): boolean {\n return this.valueAsArray.length === 0\n }\n\n private getOptionValue(option: FilterDropdownSelectableOption): string {\n return String(option[this.optionsValueKey] ?? '')\n }\n\n private getOptionLabel(option: FilterDropdownSelectableOption): string {\n return String(option[this.optionsLabelKey] ?? '')\n }\n\n // ---------------------------------------------------------------------------\n // Flattening + filtering (mirrors the Provet flattenedOptions logic)\n // ---------------------------------------------------------------------------\n\n /** Whether any option is a group (has a heading) or a tree (has children). */\n private get hasGroupedOptions(): boolean {\n return this.options.some(option => isGroup(option) || Boolean(option.children?.length))\n }\n\n /** Lowercased search needle, or empty when not filtering internally. */\n private get needle(): string {\n return this.searchable && this.internalSearch ? this.search.trim().toLocaleLowerCase() : ''\n }\n\n private matchesSearch(option: FilterDropdownSelectableOption): boolean {\n const needle = this.needle\n if (!needle) {\n return true\n }\n return this.getOptionLabel(option).toLocaleLowerCase().includes(needle)\n }\n\n /**\n * Flattens grouped/tree options into render sections while preserving visual\n * hierarchy: groups keep their heading; tree children are emitted right after\n * their (still-selectable) parent and marked `indent`. Runs of standalone\n * options are coalesced into one section so no divider appears between them.\n * Applies the internal search filter as it goes.\n */\n private get sections(): RenderSection[] {\n const toFlat = (option: FilterDropdownSelectableOption, indent: boolean): FlatOption => ({\n value: this.getOptionValue(option),\n label: this.getOptionLabel(option),\n disabled: Boolean(option.disabled),\n indent,\n source: option,\n })\n\n if (!this.hasGroupedOptions) {\n const flat = (this.options as FilterDropdownSelectableOption[])\n .filter(option => this.matchesSearch(option))\n .map(option => toFlat(option, false))\n return flat.length ? [{ options: flat }] : []\n }\n\n const sections: RenderSection[] = []\n let run: FlatOption[] = []\n\n const flushRun = () => {\n if (run.length) {\n sections.push({ options: run })\n run = []\n }\n }\n\n for (const option of this.options) {\n if (isGroup(option)) {\n flushRun()\n const children = (option.children ?? [])\n .filter(child => this.matchesSearch(child))\n .map(child => toFlat({ ...child, disabled: child.disabled || option.disabled }, false))\n if (children.length) {\n sections.push({ heading: option.heading, options: children })\n }\n continue\n }\n\n // Tree-style option: parent stays selectable, children render indented.\n if (option.children?.length) {\n const parentMatches = this.matchesSearch(option)\n const children = option.children.filter(child => this.matchesSearch(child))\n if (parentMatches || children.length) {\n if (parentMatches) {\n run.push(toFlat(option, false))\n }\n for (const child of children) {\n run.push(toFlat(child, true))\n }\n }\n continue\n }\n\n // Standalone option.\n if (this.matchesSearch(option)) {\n run.push(toFlat(option, false))\n }\n }\n\n flushRun()\n return sections\n }\n\n /** The flat option list in render order, used for keyboard navigation. */\n private get flatOptions(): FlatOption[] {\n return this.sections.flatMap(section => section.options)\n }\n\n /** Every selectable value (skipping disabled options), for select-all. */\n private get allSelectableValues(): string[] {\n const values: string[] = []\n for (const option of this.options) {\n if (isGroup(option)) {\n if (option.disabled) {\n continue\n }\n for (const child of option.children ?? []) {\n if (!child.disabled) {\n values.push(this.getOptionValue(child))\n }\n }\n continue\n }\n if (!option.disabled) {\n values.push(this.getOptionValue(option))\n }\n for (const child of option.children ?? []) {\n if (!option.disabled && !child.disabled) {\n values.push(this.getOptionValue(child))\n }\n }\n }\n return values\n }\n\n private get isAllSelected(): boolean {\n if (!this.selectAll || !this.multiple) {\n return false\n }\n const all = this.allSelectableValues\n const selected = new Set(this.valueAsArray)\n return all.length > 0 && all.every(value => selected.has(value))\n }\n\n /** Resolves a value to its label across flat, grouped and tree options. */\n private labelForValue(key: string): string {\n for (const option of this.options) {\n if (isGroup(option)) {\n for (const child of option.children ?? []) {\n if (this.getOptionValue(child) === key) {\n return this.getOptionLabel(child)\n }\n }\n continue\n }\n if (this.getOptionValue(option) === key) {\n return this.getOptionLabel(option)\n }\n for (const child of option.children ?? []) {\n if (this.getOptionValue(child) === key) {\n return this.getOptionLabel(child)\n }\n }\n }\n return this.labelForUnknown || this.localize.term('unknown')\n }\n\n /** The summary shown on the chip when there is a selection. */\n private get selectionLabel(): string {\n const values = this.valueAsArray\n if (values.length === 0) {\n return ''\n }\n const first = this.labelForValue(values[0]!)\n if (values.length > 1) {\n return first + this.localize.term('countSuffix', values.length - 1)\n }\n return first\n }\n\n private isSelected(value: string): boolean {\n return this.valueAsArray.includes(value)\n }\n\n // ---------------------------------------------------------------------------\n // Open / close\n // ---------------------------------------------------------------------------\n\n /** Open the popout. */\n show() {\n this.openState.show()\n }\n\n /** Close the popout. */\n hide() {\n this.openState.hide()\n }\n\n /** Focus the trigger button. */\n focus(options?: FocusOptions) {\n this.triggerButton?.focus(options)\n }\n\n private handleTriggerClick = () => {\n this.openState.toggle()\n }\n\n protected updated(changed: PropertyValues) {\n super.updated(changed)\n if (this.scrollActivePending) {\n this.scrollActivePending = false\n this.listRef.value?.querySelector('.n-filter-dropdown-option.is-active')?.scrollIntoView({ block: 'nearest' })\n }\n // The consumer has responded to a `load-more` (toggled `loading` or appended\n // options), so allow the next near-end gesture to request again.\n if (this.loadMoreRequested && (changed.has('loading') || changed.has('options'))) {\n this.loadMoreRequested = false\n }\n if (changed.has('disabled') && this.disabled) {\n this.activeDescendant.reset()\n this.scrollActivePending = true\n }\n }\n\n // ---------------------------------------------------------------------------\n // Selection actions\n // ---------------------------------------------------------------------------\n\n private commit(value: string | string[]) {\n this.value = value\n /** Dispatched when the committed value changes via user interaction. */\n this.dispatchEvent(new FilterDropdownChangeEvent(value))\n }\n\n private toggle(option: FlatOption) {\n if (this.disabled || option.disabled) {\n return\n }\n\n if (!this.multiple) {\n this.commit(option.value)\n this.hide()\n return\n }\n\n const current = this.valueAsArray\n const next = current.includes(option.value)\n ? current.filter(value => value !== option.value)\n : [...current, option.value]\n this.commit(next)\n }\n\n private toggleSelectAll = () => {\n if (this.disabled || !this.multiple) {\n return\n }\n this.commit(this.isAllSelected ? [] : [...this.allSelectableValues])\n }\n\n private clear() {\n if (this.disabled) {\n return\n }\n\n this.search = ''\n this.dispatchEvent(new FilterDropdownClearEvent())\n this.commit(this.multiple ? [] : '')\n }\n\n private handleClear = (e: Event) => {\n e.stopPropagation()\n if (this.disabled) {\n return\n }\n\n this.clear()\n this.focus()\n }\n\n private handleRemove = (e: Event) => {\n e.stopPropagation()\n if (this.disabled) {\n return\n }\n\n this.clear()\n /** Dispatched when the filter is removed. */\n this.dispatchEvent(new FilterDropdownRemoveEvent())\n }\n\n private handleSearchInput = (e: Event) => {\n e.stopPropagation()\n if (this.disabled) {\n return\n }\n\n const input = e.target as HTMLInputElement & { value: string }\n this.search = input.value\n this.activeDescendant.reset()\n this.scrollActivePending = true\n /** Dispatched as the user types into the search input. */\n this.dispatchEvent(new FilterDropdownSearchChangeEvent(this.search))\n }\n\n private handleListScroll = (e: Event) => {\n if (this.disabled) {\n return\n }\n\n const target = e.target as HTMLElement\n const { scrollTop, scrollHeight, clientHeight } = target\n if (scrollHeight <= clientHeight) {\n return\n }\n const nearEnd = (scrollTop + clientHeight) / scrollHeight > 0.8\n\n // Re-arm once the user scrolls back up away from the end, so a fresh near-end\n // gesture can request more even when the consumer answered the previous\n // `load-more` without changing `loading`/`options` (e.g. an exhausted or\n // empty page). Otherwise the flag could stick `true` forever.\n if (!nearEnd) {\n this.loadMoreRequested = false\n return\n }\n\n // While a load is in flight, or a previous near-end gesture has already\n // requested more, swallow the scroll so one gesture cannot emit a burst of\n // duplicate `load-more` events before `options`/`loading` have caught up.\n if (this.loading || this.loadMoreRequested) {\n return\n }\n\n this.loadMoreRequested = true\n /** Dispatched when the list is scrolled near its end. */\n this.dispatchEvent(new FilterDropdownLoadMoreEvent())\n }\n\n // ---------------------------------------------------------------------------\n // Keyboard navigation (mirrors ComboboxBase)\n // ---------------------------------------------------------------------------\n\n private handleKeydown = (e: KeyboardEvent) => {\n if (this.disabled) {\n return\n }\n\n switch (e.key) {\n case 'ArrowDown':\n e.preventDefault()\n if (!this.open) {\n this.show()\n return\n }\n this.activeDescendant.move(1)\n this.scrollActivePending = true\n break\n case 'ArrowUp':\n e.preventDefault()\n if (!this.open) {\n this.show()\n return\n }\n this.activeDescendant.move(-1)\n this.scrollActivePending = true\n break\n case 'Home':\n if (this.open) {\n e.preventDefault()\n this.activeDescendant.first()\n this.scrollActivePending = true\n }\n break\n case 'End':\n if (this.open) {\n e.preventDefault()\n this.activeDescendant.last()\n this.scrollActivePending = true\n }\n break\n case 'Enter': {\n if (!this.open) {\n // Prevent the native button click that Enter would also fire, which\n // would run handleTriggerClick with open already true and close it again.\n e.preventDefault()\n this.show()\n return\n }\n // While open, Enter belongs to the list (commit the active option, or a\n // no-op) — never let it submit a surrounding form.\n e.preventDefault()\n const option = this.flatOptions[this.activeDescendant.activeIndex]\n if (option) {\n this.toggle(option)\n }\n break\n }\n case 'Escape':\n if (this.open) {\n e.preventDefault()\n this.hide()\n this.focus()\n }\n break\n default:\n break\n }\n }\n\n // ---------------------------------------------------------------------------\n // Rendering\n // ---------------------------------------------------------------------------\n\n private get listInlineSizeClass(): string {\n return `n-filter-dropdown-size-${this.size}`\n }\n\n private renderIndicator(value: string): TemplateResult {\n const selected = this.isSelected(value)\n if (this.multiple) {\n return html`\n <span class=\"n-filter-dropdown-checkbox\">\n ${selected\n ? html`<nord-icon name=\"interface-checked-small\" size=\"xs\"></nord-icon>`\n : nothing}\n </span>\n `\n }\n return html`\n <span class=\"n-filter-dropdown-check\">\n ${selected ? html`<nord-icon name=\"interface-checked\" size=\"s\"></nord-icon>` : nothing}\n </span>\n `\n }\n\n private renderOption(option: FlatOption, index: number): TemplateResult {\n const selected = this.isSelected(option.value)\n return html`\n <div\n id=${this.optionId(index)}\n class=${classMap({\n 'n-filter-dropdown-option': true,\n 'is-active': index === this.activeDescendant.activeIndex,\n 'is-disabled': option.disabled,\n 'is-indented': option.indent,\n })}\n role=\"option\"\n aria-selected=${selected ? 'true' : 'false'}\n aria-disabled=${option.disabled ? 'true' : nothing}\n @click=${() => this.toggle(option)}\n @mousemove=${() => this.activeDescendant.setActiveIndex(index)}\n >\n ${this.renderIndicator(option.value)}\n <span class=\"n-filter-dropdown-option-label\">${option.label}</span>\n </div>\n `\n }\n\n private optionId(index: number): string {\n return `${this.filterDropdownId}-option-${index}`\n }\n\n private renderList(): unknown {\n const sections = this.sections\n // Derive the flat list from THIS `sections` instance — `this.flatOptions`\n // re-invokes the `sections` getter and produces fresh option objects, which\n // would mean the indices below no longer line up with the rendered rows.\n const flat = sections.flatMap(section => section.options)\n\n if (this.loading && flat.length === 0) {\n return html`\n <div class=\"n-filter-dropdown-empty\" role=\"status\">\n <nord-spinner size=\"s\"></nord-spinner>\n </div>\n `\n }\n\n if (flat.length === 0) {\n return html`\n <div class=\"n-filter-dropdown-empty\" role=\"status\">\n ${this.noResultsMessage || this.localize.term('noResults')}\n </div>\n `\n }\n\n // Render order is the source of truth for the navigable index. Thread a\n // running counter through the sections so each rendered row gets its true\n // flat-list position — a value→index lookup would collapse duplicate values\n // that appear in more than one group or tree branch onto a single index.\n let flatIndex = 0\n\n return repeat(\n sections,\n (_section, index) => index,\n (section, index) => {\n const headingId = section.heading ? `${this.filterDropdownId}-group-${index}` : undefined\n return html`\n <div\n class=\"n-filter-dropdown-group\"\n role=\"group\"\n aria-labelledby=${headingId ?? nothing}\n >\n ${section.heading\n ? html`<div class=\"n-filter-dropdown-heading\" id=${headingId} role=\"presentation\">${section.heading}</div>`\n : nothing}\n ${repeat(\n section.options,\n (_option, i) => `${index}-${i}`,\n option => this.renderOption(option, flatIndex++),\n )}\n </div>\n `\n },\n )\n }\n\n render() {\n const popoutId = `${this.filterDropdownId}-popout`\n const listId = `${this.filterDropdownId}-list`\n const active = !this.isInactive\n const showRemove = this.removable\n const showClear = !showRemove && this.clearable && active\n // The trigger keeps DOM focus while the popout is open, so it carries\n // `aria-activedescendant` pointing at the highlighted option row. Cleared\n // (set to `nothing`) when closed or when nothing is active.\n const activeDescendant\n = this.open ? this.activeDescendant.activeDescendant ?? nothing : nothing\n\n return html`\n <nord-button-group>\n <nord-button\n class=\"n-filter-dropdown-trigger\"\n type=\"button\"\n size=${this.size}\n variant=${active ? nothing : 'dashed'}\n aria-controls=${popoutId}\n aria-haspopup=\"dialog\"\n aria-expanded=${this.open ? 'true' : 'false'}\n aria-activedescendant=${activeDescendant}\n ?disabled=${this.disabled}\n @click=${this.handleTriggerClick}\n @keydown=${this.handleKeydown}\n >\n <nord-icon\n slot=\"start\"\n name=${this.icon}\n label=${this.localize.term('filterIconLabel')}\n ></nord-icon>\n <span class=\"n-filter-dropdown-label\">${active ? this.localize.term('selectionLabel', this.label) : this.label}</span>\n ${active\n ? html`<span class=\"n-filter-dropdown-value\">${this.selectionLabel}</span>`\n : nothing}\n </nord-button>\n\n ${showClear\n ? html`\n <nord-button\n class=\"n-filter-dropdown-clear\"\n type=\"button\"\n size=${this.size}\n square\n ?disabled=${this.disabled}\n @click=${this.handleClear}\n >\n <nord-icon name=\"interface-close-small\" size=\"xs\"></nord-icon>\n <nord-visually-hidden>${this.localize.term('clearLabel')}</nord-visually-hidden>\n </nord-button>\n `\n : nothing}\n ${showRemove\n ? html`\n <nord-button\n class=\"n-filter-dropdown-remove\"\n type=\"button\"\n size=${this.size}\n square\n variant=${active ? nothing : 'dashed'}\n ?disabled=${this.disabled}\n @click=${this.handleRemove}\n >\n <nord-icon name=\"interface-close-small\" size=\"xs\"></nord-icon>\n <nord-visually-hidden>${this.localize.term('removeLabel')}</nord-visually-hidden>\n </nord-button>\n `\n : nothing}\n </nord-button-group>\n\n <nord-popout\n id=${popoutId}\n controlled\n always-floating\n @open=${this.openState.onPopoutOpen}\n @close=${this.openState.onPopoutClose}\n >\n <div class=${classMap({ 'n-filter-dropdown-panel': true, [this.listInlineSizeClass]: true })}>\n ${this.searchable\n ? html`\n <div class=\"n-filter-dropdown-search\">\n <nord-input\n type=\"search\"\n label=${this.localize.term('searchLabel')}\n hide-label\n expand\n size=\"s\"\n .value=${this.search}\n ?disabled=${this.disabled}\n @input=${this.handleSearchInput}\n @keydown=${this.handleKeydown}\n >\n <nord-icon slot=\"start\" name=\"navigation-search\"></nord-icon>\n ${this.loading ? html`<nord-spinner slot=\"end\" size=\"s\"></nord-spinner>` : nothing}\n </nord-input>\n </div>\n `\n : nothing}\n\n ${this.selectAll && this.multiple\n ? html`\n <div class=\"n-filter-dropdown-select-all\">\n <div\n class=${classMap({\n 'n-filter-dropdown-option': true,\n 'is-active': false,\n })}\n role=\"button\"\n tabindex=\"0\"\n aria-pressed=${this.isAllSelected ? 'true' : 'false'}\n aria-disabled=${this.disabled ? 'true' : nothing}\n @click=${this.toggleSelectAll}\n @keydown=${(e: KeyboardEvent) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault()\n this.toggleSelectAll()\n }\n }}\n >\n <span class=\"n-filter-dropdown-checkbox\">\n ${this.isAllSelected\n ? html`<nord-icon name=\"interface-checked-small\" size=\"xs\"></nord-icon>`\n : nothing}\n </span>\n <span class=\"n-filter-dropdown-option-label\">\n ${this.isAllSelected ? this.localize.term('deselectAll') : this.localize.term('selectAll')}\n </span>\n </div>\n </div>\n `\n : nothing}\n\n <div\n ${ref(this.listRef)}\n id=${listId}\n class=${classMap({ 'n-filter-dropdown-list': true, 'is-loading-more': this.loading && this.flatOptions.length > 0 })}\n role=\"listbox\"\n aria-label=${this.label || nothing}\n aria-multiselectable=${this.multiple ? 'true' : 'false'}\n @scroll=${this.handleListScroll}\n @keydown=${this.handleKeydown}\n >\n ${this.renderList()}\n </div>\n </div>\n </nord-popout>\n `\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'nord-filter-dropdown': FilterDropdown\n }\n}\n"],"names":["Icon","registerIcon","checkedSmallIcon","checkedIcon","closeIcon","filterIcon","searchIcon","filterDropdownCount","isGroup","option","FilterDropdown","DraftComponentMixin","LitElement","constructor","this","filterDropdownId","localize","LocalizeController","listRef","createRef","dismiss","LightDismissController","isOpen","open","onDismiss","hide","isDismissible","node","activeDescendant","ActiveDescendantController","count","flatOptions","length","isEnabled","i","_a","disabled","optionId","openState","OpenStateController","setOpen","popout","isInert","onOpen","loadMoreRequested","value","scrollTo","reset","onClose","search","removable","isInactive","dispatchEvent","FilterDropdownRemoveEvent","label","name","icon","size","options","optionsValueKey","optionsLabelKey","multiple","searchable","internalSearch","selectAll","clearable","loading","noResultsMessage","labelForUnknown","scrollActivePending","handleTriggerClick","toggle","toggleSelectAll","commit","isAllSelected","allSelectableValues","handleClear","e","stopPropagation","clear","focus","handleRemove","handleSearchInput","input","target","FilterDropdownSearchChangeEvent","handleListScroll","scrollTop","scrollHeight","clientHeight","FilterDropdownLoadMoreEvent","handleKeydown","key","preventDefault","show","move","first","last","activeIndex","connectedCallback","super","injectLightDomStyles","style","chipStyle","createRenderRoot","valueAsArray","Array","isArray","getOptionValue","String","getOptionLabel","hasGroupedOptions","some","Boolean","children","needle","trim","toLocaleLowerCase","matchesSearch","includes","sections","toFlat","indent","source","flat","filter","map","run","flushRun","push","child","heading","_b","parentMatches","flatMap","section","values","all","selected","Set","every","has","labelForValue","term","selectionLabel","isSelected","triggerButton","updated","changed","querySelector","scrollIntoView","block","FilterDropdownChangeEvent","current","next","FilterDropdownClearEvent","listInlineSizeClass","renderIndicator","html","nothing","renderOption","index","classMap","setActiveIndex","renderList","flatIndex","repeat","_section","headingId","undefined","_option","render","popoutId","listId","active","showRemove","showClear","onPopoutOpen","onPopoutClose","ref","__decorate","query","prototype","property","reflect","attribute","type","state","customElement"],"mappings":"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"}
|
package/lib/FilterField.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{_ as t}from"./tslib.es6-CmLYFWVC.js";import{c as i}from"./interface-close-small-CnpAFMO3.js";import{f as o}from"./interface-filter-CCsx9-u6.js";import{html as e,nothing as r,LitElement as s}from"lit";import{query as l,property as a,customElement as n}from"lit/decorators.js";import{i as c}from"./light-dom-styles-DXsbiKU9.js";import{D as p}from"./DraftComponentMixin-4qug5Rky.js";import{s as d}from"./filter-chip-C97zd4PT.js";import m from"./Icon.js";import{LocalizeController as h}from"./LocalizeController.js";import{FilterFieldClearEvent as f,FilterFieldRemoveEvent as j}from"./FilterFieldEvents.js";import"./Button.js";import"./ButtonGroup.js";import"./VisuallyHidden.js";import"lit/directives/if-defined.js";import"lit/directives/unsafe-html.js";import"./observe-D0n0zOfU.js";import"./cond-CI1KbneT.js";import"./Component-BJ5O5n8k.js";import"./IconManager.js";import"./translation.js";import"./en-us.js";import"./localization.js";import"./localization2.js";import"./localization3.js";import"./localization4.js";import"./localization5.js";import"./localization6.js";import"./localization7.js";import"./localization8.js";import"./localization9.js";import"./localization10.js";import"./localization11.js";import"./localization12.js";import"./localization13.js";import"./localization14.js";import"./localization15.js";import"./localization16.js";import"./localization17.js";import"./localization18.js";import"./localization19.js";import"./localization20.js";import"./localization21.js";import"./localization22.js";import"./localization23.js";import"./events-Bv6wNHwJ.js";import"lit/directives/ref.js";import"./EventController-BBOmvfLa.js";import"./LightDomController-DIwtVelV.js";import"./SlotController-Z6eG7LSZ.js";import"./FocusableMixin-BlQLNPdJ.js";import"./InputMixin-LetXsCyv.js";import"./Spinner.js";import"lit/directives/class-map.js";import"./DirectionController-ChvNGESZ.js";m.registerIcon(i),m.registerIcon(o);const b=["aria-controls","aria-haspopup","aria-expanded"];let u=class extends(p(s)){constructor(){super(...arguments),this.localize=new h(this),this.label="",this.value="",this.active=!1,this.clearable=!0,this.icon="interface-filter",this.name="",this.removable=!1,this.disabled=!1,this.size="s",this.handleClear=t=>{t.stopPropagation(),this.dispatchEvent(new f)},this.handleRemove=t=>{t.stopPropagation(),this.dispatchEvent(new j)}}connectedCallback(){super.connectedCallback(),c(this,d,"nord-filter-chip"),this.ariaObserver=new MutationObserver((()=>this.forwardAria())),this.ariaObserver.observe(this,{attributes:!0,attributeFilter:[...b]})}disconnectedCallback(){var t;super.disconnectedCallback(),null===(t=this.ariaObserver)||void 0===t||t.disconnect()}createRenderRoot(){return this}updated(){this.forwardAria()}forwardAria(){const t=this.triggerButton;if(t)for(const i of b){const o=this.getAttribute(i);null==o?t.removeAttribute(i):t.setAttribute(i,o)}}get isActive(){return this.active||this.value.length>0}render(){const t=this.isActive;return e`<nord-button-group><nord-button class="n-filter-field-trigger" type="button" size="${this.size}" variant="${t?r:"dashed"}" ?disabled="${this.disabled}"><nord-icon slot="start" name="${this.icon}" label="${this.localize.term("filterIconLabel")}"></nord-icon>${t&&this.value?e`<span class="n-filter-field-label">${this.localize.term("selectionLabel",this.label)}</span> <span class="n-filter-field-value">${this.value}</span>`:e`<span class="n-filter-field-label">${this.label}</span>`}</nord-button>${this.removable?e`<nord-button class="n-filter-field-remove" type="button" size="${this.size}" square variant="${t?r:"dashed"}" ?disabled="${this.disabled}" @click="${this.handleRemove}"><nord-icon name="interface-close-small" size="xs"></nord-icon><nord-visually-hidden>${this.localize.term("removeLabel")}</nord-visually-hidden></nord-button>`:t&&this.clearable?e`<nord-button class="n-filter-field-clear" type="button" size="${this.size}" square ?disabled="${this.disabled}" @click="${this.handleClear}"><nord-icon name="interface-close-small" size="xs"></nord-icon><nord-visually-hidden>${this.localize.term("clearLabel")}</nord-visually-hidden></nord-button>`:r}</nord-button-group>`}};t([l(".n-filter-field-trigger")],u.prototype,"triggerButton",void 0),t([a({reflect:!0})],u.prototype,"label",void 0),t([a({reflect:!0})],u.prototype,"value",void 0),t([a({reflect:!0,type:Boolean})],u.prototype,"active",void 0),t([a({reflect:!0,type:Boolean})],u.prototype,"clearable",void 0),t([a({reflect:!0})],u.prototype,"icon",void 0),t([a({reflect:!0})],u.prototype,"name",void 0),t([a({reflect:!0,type:Boolean})],u.prototype,"removable",void 0),t([a({reflect:!0,type:Boolean})],u.prototype,"disabled",void 0),t([a({reflect:!0})],u.prototype,"size",void 0),u=t([n("nord-filter-field")],u);var v=u;export{f as FilterFieldClearEvent,j as FilterFieldRemoveEvent,v as default};
|
|
1
|
+
import{_ as t}from"./tslib.es6-CmLYFWVC.js";import{c as i}from"./interface-close-small-CnpAFMO3.js";import{f as o}from"./interface-filter-CCsx9-u6.js";import{html as e,nothing as r,LitElement as s}from"lit";import{query as l,property as a,customElement as n}from"lit/decorators.js";import{i as c}from"./light-dom-styles-DXsbiKU9.js";import{D as p}from"./DraftComponentMixin-4qug5Rky.js";import{s as d}from"./filter-chip-C97zd4PT.js";import m from"./Icon.js";import{LocalizeController as h}from"./LocalizeController.js";import{FilterFieldClearEvent as f,FilterFieldRemoveEvent as j}from"./FilterFieldEvents.js";import"./Button.js";import"./ButtonGroup.js";import"./VisuallyHidden.js";import"lit/directives/if-defined.js";import"lit/directives/unsafe-html.js";import"./observe-D0n0zOfU.js";import"./cond-CI1KbneT.js";import"./Component-BJ5O5n8k.js";import"./IconManager.js";import"./translation.js";import"./en-us.js";import"./localization.js";import"./localization2.js";import"./localization3.js";import"./localization4.js";import"./localization5.js";import"./localization6.js";import"./localization7.js";import"./localization8.js";import"./localization9.js";import"./localization10.js";import"./localization11.js";import"./localization12.js";import"./localization13.js";import"./localization14.js";import"./localization15.js";import"./localization16.js";import"./localization17.js";import"./localization18.js";import"./localization19.js";import"./localization20.js";import"./localization21.js";import"./localization22.js";import"./localization23.js";import"./localization24.js";import"./events-Bv6wNHwJ.js";import"lit/directives/ref.js";import"./EventController-BBOmvfLa.js";import"./LightDomController-DIwtVelV.js";import"./SlotController-Z6eG7LSZ.js";import"./FocusableMixin-BlQLNPdJ.js";import"./InputMixin-LetXsCyv.js";import"./Spinner.js";import"lit/directives/class-map.js";import"./DirectionController-ChvNGESZ.js";m.registerIcon(i),m.registerIcon(o);const b=["aria-controls","aria-haspopup","aria-expanded"];let u=class extends(p(s)){constructor(){super(...arguments),this.localize=new h(this),this.label="",this.value="",this.active=!1,this.clearable=!0,this.icon="interface-filter",this.name="",this.removable=!1,this.disabled=!1,this.size="s",this.handleClear=t=>{t.stopPropagation(),this.dispatchEvent(new f)},this.handleRemove=t=>{t.stopPropagation(),this.dispatchEvent(new j)}}connectedCallback(){super.connectedCallback(),c(this,d,"nord-filter-chip"),this.ariaObserver=new MutationObserver((()=>this.forwardAria())),this.ariaObserver.observe(this,{attributes:!0,attributeFilter:[...b]})}disconnectedCallback(){var t;super.disconnectedCallback(),null===(t=this.ariaObserver)||void 0===t||t.disconnect()}createRenderRoot(){return this}updated(){this.forwardAria()}forwardAria(){const t=this.triggerButton;if(t)for(const i of b){const o=this.getAttribute(i);null==o?t.removeAttribute(i):t.setAttribute(i,o)}}get isActive(){return this.active||this.value.length>0}render(){const t=this.isActive;return e`<nord-button-group><nord-button class="n-filter-field-trigger" type="button" size="${this.size}" variant="${t?r:"dashed"}" ?disabled="${this.disabled}"><nord-icon slot="start" name="${this.icon}" label="${this.localize.term("filterIconLabel")}"></nord-icon>${t&&this.value?e`<span class="n-filter-field-label">${this.localize.term("selectionLabel",this.label)}</span> <span class="n-filter-field-value">${this.value}</span>`:e`<span class="n-filter-field-label">${this.label}</span>`}</nord-button>${this.removable?e`<nord-button class="n-filter-field-remove" type="button" size="${this.size}" square variant="${t?r:"dashed"}" ?disabled="${this.disabled}" @click="${this.handleRemove}"><nord-icon name="interface-close-small" size="xs"></nord-icon><nord-visually-hidden>${this.localize.term("removeLabel")}</nord-visually-hidden></nord-button>`:t&&this.clearable?e`<nord-button class="n-filter-field-clear" type="button" size="${this.size}" square ?disabled="${this.disabled}" @click="${this.handleClear}"><nord-icon name="interface-close-small" size="xs"></nord-icon><nord-visually-hidden>${this.localize.term("clearLabel")}</nord-visually-hidden></nord-button>`:r}</nord-button-group>`}};t([l(".n-filter-field-trigger")],u.prototype,"triggerButton",void 0),t([a({reflect:!0})],u.prototype,"label",void 0),t([a({reflect:!0})],u.prototype,"value",void 0),t([a({reflect:!0,type:Boolean})],u.prototype,"active",void 0),t([a({reflect:!0,type:Boolean})],u.prototype,"clearable",void 0),t([a({reflect:!0})],u.prototype,"icon",void 0),t([a({reflect:!0})],u.prototype,"name",void 0),t([a({reflect:!0,type:Boolean})],u.prototype,"removable",void 0),t([a({reflect:!0,type:Boolean})],u.prototype,"disabled",void 0),t([a({reflect:!0})],u.prototype,"size",void 0),u=t([n("nord-filter-field")],u);var v=u;export{f as FilterFieldClearEvent,j as FilterFieldRemoveEvent,v as default};
|
|
2
2
|
//# sourceMappingURL=FilterField.js.map
|