@nordhealth/components 1.8.3 → 1.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/custom-elements.json +5326 -5085
- package/lib/Badge.js +1 -1
- package/lib/Badge.js.map +1 -1
- package/lib/Checkbox.js +1 -1
- package/lib/DatePicker.js +1 -1
- package/lib/DatePicker.js.map +1 -1
- package/lib/Divider.js +2 -0
- package/lib/Divider.js.map +1 -0
- package/lib/Dropdown.js +1 -1
- package/lib/Dropdown.js.map +1 -1
- package/lib/FormAssociatedMixin-d0d98a92.js +2 -0
- package/lib/FormAssociatedMixin-d0d98a92.js.map +1 -0
- package/lib/Input.js +1 -1
- package/lib/Input.js.map +1 -1
- package/lib/Layout.js +1 -1
- package/lib/Layout.js.map +1 -1
- package/lib/Modal.js +1 -1
- package/lib/Modal.js.map +1 -1
- package/lib/Radio.js +1 -1
- package/lib/Select.js +1 -1
- package/lib/Select.js.map +1 -1
- package/lib/Textarea.js +1 -1
- package/lib/Textarea.js.map +1 -1
- package/lib/Toast.js +2 -0
- package/lib/Toast.js.map +1 -0
- package/lib/ToastGroup.js +2 -0
- package/lib/ToastGroup.js.map +1 -0
- package/lib/Toggle.js +1 -1
- package/lib/bundle.js +3 -3
- package/lib/bundle.js.map +1 -1
- package/lib/index.js +1 -1
- package/lib/interface-close-small-44ababc3.js +2 -0
- package/lib/interface-close-small-44ababc3.js.map +1 -0
- package/lib/src/common/controllers/ScrollbarController.d.ts +1 -0
- package/lib/src/divider/Divider.d.ts +25 -0
- package/lib/src/divider/Divider.test.d.ts +2 -0
- package/lib/src/dropdown/Dropdown.d.ts +3 -1
- package/lib/src/index.d.ts +3 -0
- package/lib/src/input/Input.d.ts +4 -0
- package/lib/src/modal/Modal.d.ts +0 -1
- package/lib/src/select/Select.d.ts +4 -0
- package/lib/src/textarea/Textarea.d.ts +4 -0
- package/lib/src/toast/Toast.d.ts +40 -0
- package/lib/src/toast/Toast.test.d.ts +2 -0
- package/lib/src/toast-group/ToastGroup.d.ts +28 -0
- package/lib/src/toast-group/ToastGroup.test.d.ts +2 -0
- package/package.json +2 -2
- package/lib/FormAssociatedMixin-d3124755.js +0 -2
- package/lib/FormAssociatedMixin-d3124755.js.map +0 -1
package/lib/Modal.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{_ as t,n as o}from"./query-assigned-elements-ef860822.js";import{r as e,$ as s,s as i}from"./lit-element-67e6cd99.js";import{e as
|
|
1
|
+
import{_ as t,n as o}from"./query-assigned-elements-ef860822.js";import{r as e,$ as s,s as i}from"./lit-element-67e6cd99.js";import{e as r}from"./property-03f59dce.js";import{i as n}from"./query-2d22378e.js";import{c as a}from"./interface-close-small-44ababc3.js";import l from"./Icon.js";import{E as d}from"./EventController-d99ebeef.js";import{L as c}from"./LightDismissController-a2645ae6.js";import{S as h}from"./SlotController-ea6eff46.js";import{o as p}from"./observe-a9c6dfb6.js";import{N as m}from"./events-731d0007.js";import{D as u}from"./DraftComponentMixin-9e4b7b34.js";import{s as v}from"./Component-a61df53a.js";import{LocalizeController as f}from"./LocalizeController.js";import"./state-70f38ceb.js";import"./if-defined-fe1a64e3.js";import"./unsafe-html-61a04601.js";import"./directive-de55b00a.js";import"./cond-97c45476.js";import"./ShortcutController-87615e31.js";import"./tinykeys.module-84e6cc41.js";import"./translation.js";import"./en-us.js";import"./localization.js";import"./localization2.js";import"./localization3.js";import"./localization4.js";class b{constructor(t,o=(()=>t)){this.boundary=o,this.lastScrollY=0,this.handleFocusOut=t=>{this.lastFocused=t.target,t.relatedTarget===this.boundary()&&this.recaptureFocus()},this.handleFocusIn=t=>{!t.composedPath().includes(this.boundary())&&this.recaptureFocus()},this.restoreScroll=()=>{window.scrollTo(window.scrollX,this.lastScrollY)},t.addController(this)}hostDisconnected(){this.release()}trap(){this.lastScrollY=window.scrollY,this.boundary().addEventListener("focusout",this.handleFocusOut),window.addEventListener("scroll",this.restoreScroll),window.addEventListener("focusin",this.handleFocusIn)}release(){this.lastScrollY=0,this.lastFocused=void 0,this.boundary().removeEventListener("focusout",this.handleFocusOut),window.removeEventListener("scroll",this.restoreScroll),window.removeEventListener("focusin",this.handleFocusIn)}recaptureFocus(){var t;null===(t=this.lastFocused)||void 0===t||t.focus({preventScroll:!0})}}class y{constructor(t,o=document.body){this.scroller=o,this.resets=new Set,t.addController(this)}hostDisconnected(){this.restore()}get width(){const t=document.documentElement.clientWidth;return Math.abs(window.innerWidth-t)}hide(){this.restore();const{width:t}=this,o=getComputedStyle(this.scroller),e=parseInt(o.paddingRight,10)||0;this.setStyle("--n-scrollbar-gutter",`${t+e}px`),this.setStyle("overflow","hidden"),this.setStyle("padding-right","var(--n-scrollbar-gutter)")}restore(){this.resets.forEach((t=>t())),this.resets.clear()}setStyle(t,o){const{style:e}=this.scroller,s=this.scroller.style.getPropertyValue(t);e.setProperty(t,o),this.resets.add((()=>e.setProperty(t,s)))}}const g=e`:host{--n-modal-padding-inline:var(--n-space-m);--n-modal-padding-block:var(--n-space-m);--n-modal-focus-ring:0 0 0 2px var(--n-color-accent);color:var(--n-color-text);position:fixed;inset:0;visibility:hidden;transition:visibility var(--n-transition-slowly);z-index:var(--n-index-overlay)}:host([open]){transition-property:none;visibility:visible}.n-modal-backdrop{position:fixed;inset:0;background:var(--n-color-overlay);transition:opacity var(--n-transition-slowly);padding:var(--n-space-l);padding-block-start:clamp(var(--n-space-l),min(10vh,10vw) - 1em,calc(var(--n-space-xxl) + var(--n-space-s)));overflow-y:auto}:host(:not([open])) .n-modal-backdrop{opacity:0}.n-modal{position:relative;display:flex;flex-direction:column;inline-size:100%;max-inline-size:var(--n-modal-max-width,620px);margin:auto;background:var(--n-color-surface);box-shadow:var(--n-box-shadow-modal);border-radius:var(--n-border-radius);transition:opacity var(--n-transition-slowly),transform var(--n-transition-slowly)}.n-rounded-top{border-radius:var(--n-border-radius) var(--n-border-radius) 0 0}:host(:not([open])) .n-modal{transform:translateY(-10px) scale(.97);opacity:0}.n-modal:focus{outline:0}.n-modal-body{flex:1}.n-body-padded{display:block;padding:var(--n-space-l) var(--n-modal-padding-inline) var(--n-space-xl)}.n-modal-header{display:flex;gap:var(--n-space-m);align-items:start;background:var(--n-color-nav-surface);border-block-end:1px solid var(--n-color-border)}.n-modal-footer{border-block-start:1px solid var(--n-color-border)}.n-padded{padding:var(--n-modal-padding-block) var(--n-modal-padding-inline)}.n-close{border:none;display:flex;justify-content:center;align-items:center;block-size:var(--n-space-xl);inline-size:var(--n-space-xl);background-color:transparent;border-radius:var(--n-border-radius);inset-block-start:var(--n-space-s);inset-inline-end:var(--n-space-s);color:var(--n-color-text);cursor:pointer;transition:color var(--n-transition-quickly);position:relative}.n-close::after{content:"";position:absolute;display:block;inset:calc(var(--n-space-s) * -1);border-radius:var(--n-border-radius)}.n-close:not(:hover){color:var(--n-color-icon)}.n-close:active{transform:translateY(1px)}.n-close:focus{outline:0;box-shadow:var(--n-modal-focus-ring)}@supports selector(:focus-visible){.n-close:focus{box-shadow:none}.n-close:focus-visible{box-shadow:var(--n-modal-focus-ring)}}:host([scrollable]) .n-modal{max-block-size:100%}:host([scrollable]) .n-modal-body{overflow-y:auto}@media (min-width:489px){:host{--n-modal-padding-inline:var(--n-space-l)}:host([size="s"]){--n-modal-padding-inline:var(--n-space-m);--n-modal-max-width:440px}:host([size="l"]){--n-modal-padding-inline:var(--n-space-l);--n-modal-max-width:1320px}}slot[name]{display:flex}slot[name=header]{flex:1}slot[name=header]::slotted(*){margin:0!important;padding:0!important;font-size:var(--n-font-size-l)!important;font-weight:var(--n-font-weight-heading)!important;line-height:var(--n-line-height-heading)!important}slot[name=footer]{gap:calc(var(--n-space-s)/ 2);flex-direction:column}@media (min-width:489px){slot[name=footer]{gap:var(--n-space-s);flex-direction:row;justify-content:flex-end;align-items:center}}slot[name=feature]{overflow:hidden}slot[name=feature]::slotted(*){inline-size:100%;block-size:auto}`;l.registerIcon(a);let w=class extends(u(i)){constructor(){super(...arguments),this.headerSlot=new h(this,"header"),this.featureSlot=new h(this,"feature"),this.footerSlot=new h(this,"footer"),this.scrollBar=new y(this),this.focusTrap=new b(this,(()=>this.modal)),this.localize=new f(this),this.events=new d(this),this.lightDismiss=new c(this,{isOpen:()=>this.open,isDismissible:t=>t!==this.modal,onDismiss:()=>this.handleDismiss()}),this.open=!1,this.size="m",this.returnValue="",this.scrollable=!1,this.enableScroll=t=>{this.open||t.target!==this.backdrop||this.scrollBar.restore()},this.trackLastButton=t=>{const o=t.target;"button"===o.localName&&(this.lastButton=o)},this.polyfillSubmitter=t=>{t.submitter=this.lastButton},this.handleSubmit=t=>{this.lastButton=void 0;const o=t.target,e=t.submitter,s="dialog"===o.method,i="dialog"===o.getAttribute("method");i&&!s&&t.preventDefault(),(i||s)&&this.close(null==e?void 0:e.value)}}connectedCallback(){super.connectedCallback(),this.setAttribute("role","dialog"),this.setAttribute("aria-modal","true"),window.SubmitEvent||(this.events.listen(this,"click",this.trackLastButton,!0),this.events.listen(this,"submit",this.polyfillSubmitter,!0))}showModal(){this.open=!0}close(t){this.open=!1,null!=t&&(this.returnValue=t),this.dispatchEvent(new m("close"))}focus(t){this.modal.focus({preventScroll:!0,...t})}render(){return s`<div class="n-modal-backdrop" @transitionend="${this.enableScroll}"><div class="n-modal" tabindex="0" @submit="${this.handleSubmit}"><div class="n-modal-header n-rounded-top" ?hidden="${this.headerSlot.isEmpty}"><slot class="n-padded" name="${this.headerSlot.slotName}"></slot><button class="n-close" @click="${this.handleDismiss}"><nord-icon name="interface-close-small" size="s" label="${this.localize.term("closeLabel")}"></nord-icon></button></div><div class="n-modal-body"><slot name="${this.featureSlot.slotName}" class="${this.headerSlot.isEmpty?"n-rounded-top":""}" ?hidden="${this.featureSlot.isEmpty}"></slot><slot class="n-body-padded"></slot></div><div class="n-modal-footer n-padded" ?hidden="${this.footerSlot.isEmpty}"><slot name="${this.footerSlot.slotName}"></slot></div></div></div>`}handleOpenUpdated(){var t;if(this.open){this.scrollBar.hide(),this.trigger=document.activeElement;(this.querySelector("[autofocus]")||this).focus(),this.focusTrap.trap()}else this.backdrop.scrollTop=0,this.focusTrap.release(),null===(t=this.trigger)||void 0===t||t.focus(),this.trigger=void 0}handleDismiss(){this.dispatchEvent(new m("cancel",{cancelable:!0}))&&this.close()}};w.styles=[v,g],t([n(".n-modal",!0)],w.prototype,"modal",void 0),t([n(".n-modal-backdrop",!0)],w.prototype,"backdrop",void 0),t([r({type:Boolean,reflect:!0})],w.prototype,"open",void 0),t([r({reflect:!0})],w.prototype,"size",void 0),t([r({attribute:!1})],w.prototype,"returnValue",void 0),t([r({type:Boolean,reflect:!0})],w.prototype,"scrollable",void 0),t([p("open","updated")],w.prototype,"handleOpenUpdated",null),w=t([o("nord-modal")],w);var x=w;export{x as default};
|
|
2
2
|
//# sourceMappingURL=Modal.js.map
|
package/lib/Modal.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Modal.js","sources":["../src/common/controllers/FocusTrapController.ts","../src/common/controllers/ScrollbarController.ts","../src/modal/Modal.ts"],"sourcesContent":["import { ReactiveController, ReactiveControllerHost } from \"lit\"\n\nexport class FocusTrapController implements ReactiveController {\n private lastScrollY = 0\n private lastFocused?: HTMLElement\n\n constructor(host: ReactiveControllerHost & HTMLElement, private boundary: () => HTMLElement = () => host) {\n host.addController(this)\n }\n\n hostDisconnected() {\n this.release()\n }\n\n trap() {\n this.lastScrollY = window.scrollY\n this.boundary().addEventListener(\"focusout\", this.handleFocusOut)\n window.addEventListener(\"scroll\", this.restoreScroll)\n window.addEventListener(\"focusin\", this.handleFocusIn)\n }\n\n release() {\n this.lastScrollY = 0\n this.lastFocused = undefined\n\n this.boundary().removeEventListener(\"focusout\", this.handleFocusOut)\n window.removeEventListener(\"scroll\", this.restoreScroll)\n window.removeEventListener(\"focusin\", this.handleFocusIn)\n }\n\n private handleFocusOut = (e: FocusEvent) => {\n this.lastFocused = e.target as HTMLElement\n\n if (e.relatedTarget === this.boundary()) {\n this.recaptureFocus()\n }\n }\n\n private handleFocusIn = (e: FocusEvent) => {\n const isOutside = !e.composedPath().includes(this.boundary())\n\n if (isOutside) {\n this.recaptureFocus()\n }\n }\n\n private recaptureFocus() {\n this.lastFocused?.focus({ preventScroll: true })\n }\n\n private restoreScroll = () => {\n window.scrollTo(window.scrollX, this.lastScrollY)\n }\n}\n","import { ReactiveController, ReactiveControllerHost } from \"lit\"\n\nfunction setStyle<P extends keyof CSSStyleDeclaration, V extends CSSStyleDeclaration[P]>(\n { style }: HTMLElement,\n property: P,\n value: V\n) {\n const previous = style[property]\n style[property] = value\n\n return () => {\n style[property] = previous\n }\n}\n\nexport class ScrollbarController implements ReactiveController {\n private resets = new Set<() => void>()\n\n constructor(host: ReactiveControllerHost)\n constructor(host: ReactiveControllerHost, scroller: HTMLElement)\n constructor(host: ReactiveControllerHost, private scroller = document.body) {\n host.addController(this)\n }\n\n hostDisconnected() {\n this.restore()\n }\n\n // eslint-disable-next-line class-methods-use-this\n get width() {\n const documentWidth = document.documentElement.clientWidth\n return Math.abs(window.innerWidth - documentWidth)\n }\n\n hide() {\n // in case hide() is called twice in succession\n this.restore()\n\n const { width } = this\n const computedStyle = getComputedStyle(this.scroller)\n const paddingRight = parseInt(computedStyle.paddingRight, 10) || 0\n\n this.resets.add(setStyle(this.scroller, \"overflow\", \"hidden\"))\n this.resets.add(setStyle(this.scroller, \"paddingRight\", `${width + paddingRight}px`))\n }\n\n restore() {\n this.resets.forEach(reset => reset())\n this.resets.clear()\n }\n}\n","import { LitElement, html } from \"lit\"\nimport { customElement, property, query } from \"lit/decorators.js\"\n\nimport \"../icon/Icon.js\"\nimport { EventController } from \"../common/controllers/EventController.js\"\nimport { FocusTrapController } from \"../common/controllers/FocusTrapController.js\"\nimport { LightDismissController } from \"../common/controllers/LightDismissController.js\"\nimport { ScrollbarController } from \"../common/controllers/ScrollbarController.js\"\nimport { SlotController } from \"../common/controllers/SlotController.js\"\nimport { observe } from \"../common/decorators/observe.js\"\nimport { NordEvent } from \"../common/events.js\"\nimport { DraftComponentMixin } from \"../common/mixins/DraftComponentMixin.js\"\n\nimport componentStyle from \"../common/styles/Component.css\"\nimport { LocalizeController } from \"../localization/LocalizeController.js\"\nimport style from \"./Modal.css\"\n\nconst isButton = (element: Element): element is HTMLButtonElement => element.localName === \"button\"\n\n/**\n * Modal component is used to display content that temporarily blocks interactions\n * with the main view of an application. Modal should be used sparingly and\n * only when necessary.\n *\n * @status draft\n * @category overlay\n * @slot - Default slot\n * @slot header - Slot which holds the header of the modal, positioned next to the close button.\n * @slot footer - Slot which is typically used to hold call to action buttons, but can also be used to build custom footers.\n * @fires cancel - Dispatched before the modal has closed when a user attempts to dismiss a modal. Call `preventDefault()` on the event to prevent the modal closing.\n * @fires close - Dispatched when a modal is closed for any reason.\n */\n@customElement(\"nord-modal\")\nexport default class Modal extends DraftComponentMixin(LitElement) {\n static styles = [componentStyle, style]\n\n @query(\".n-modal\", true) private modal!: HTMLDivElement\n @query(\".n-modal-backdrop\", true) private backdrop!: HTMLDivElement\n\n private trigger?: HTMLElement\n private lastButton?: HTMLButtonElement\n\n private headerSlot = new SlotController(this, \"header\")\n private featureSlot = new SlotController(this, \"feature\")\n private footerSlot = new SlotController(this, \"footer\")\n\n private scrollBar = new ScrollbarController(this)\n private focusTrap = new FocusTrapController(this, () => this.modal)\n private localize = new LocalizeController<\"nord-modal\">(this)\n private events = new EventController(this)\n private lightDismiss = new LightDismissController(this, {\n isOpen: () => this.open,\n isDismissible: node => node !== this.modal,\n onDismiss: () => this.handleDismiss(),\n })\n\n /**\n * Controls whether the modal is open or not.\n */\n @property({ type: Boolean, reflect: true }) open = false\n\n /**\n * Controls the max-width of the modal when open.\n */\n @property({ reflect: true }) size: \"s\" | \"m\" | \"l\" = \"m\"\n\n /**\n * The reason why the modal was closed. This typically indicates\n * which button the user pressed to close the modal, though any value\n * can be supplied if the modal is programmatically closed.\n */\n @property({ attribute: false }) returnValue: string = \"\"\n\n /**\n * By default if a modal is too big for the browser window,\n * the entire modal will scroll. This setting changes that behavior\n * so that the body of the modal scrolls instead, with the modal\n * itself remaining fixed.\n */\n @property({ type: Boolean, reflect: true }) scrollable = false\n\n connectedCallback(): void {\n super.connectedCallback()\n\n this.setAttribute(\"role\", \"dialog\")\n this.setAttribute(\"aria-modal\", \"true\")\n\n // if submit event is not supported, let's do a basic polyfill\n if (!window.SubmitEvent) {\n this.events.listen(this, \"click\", this.trackLastButton, true)\n this.events.listen(this, \"submit\", this.polyfillSubmitter, true)\n }\n }\n\n /**\n * Show the modal, automatically moving focus to the modal or a child\n * element with an `autofocus` attribute.\n */\n showModal() {\n this.open = true\n }\n\n /**\n * Programmatically close the modal.\n * @param returnValue An optional value to indicate why the modal was closed.\n */\n close(returnValue?: string) {\n this.open = false\n\n if (returnValue != null) {\n this.returnValue = returnValue\n }\n\n this.dispatchEvent(new NordEvent(\"close\"))\n }\n\n /**\n * Programmatically focus the modal.\n * @param options An object which controls aspects of the focusing process.\n */\n focus(options?: FocusOptions) {\n this.modal.focus({ preventScroll: true, ...options })\n }\n\n render() {\n return html`\n <div class=\"n-modal-backdrop\" @transitionend=${this.enableScroll}>\n <div class=\"n-modal\" tabindex=\"0\" @submit=${this.handleSubmit}>\n <div class=\"n-modal-header n-rounded-top\" ?hidden=${this.headerSlot.isEmpty}>\n <slot class=\"n-padded\" name=${this.headerSlot.slotName}></slot>\n <button class=\"n-close\" @click=${this.handleDismiss}>\n <nord-icon name=\"interface-close-small\" size=\"s\" label=${this.localize.term(\"closeLabel\")}></nord-icon>\n </button>\n </div>\n\n <div class=\"n-modal-body\">\n <slot\n name=${this.featureSlot.slotName}\n class=${this.headerSlot.isEmpty ? \"n-rounded-top\" : \"\"}\n ?hidden=${this.featureSlot.isEmpty}\n ></slot>\n <slot class=\"n-body-padded\"></slot>\n </div>\n\n <div class=\"n-modal-footer n-padded\" ?hidden=${this.footerSlot.isEmpty}>\n <slot name=${this.footerSlot.slotName}></slot>\n </div>\n </div>\n </div>\n `\n }\n\n @observe(\"open\", \"updated\")\n protected handleOpenUpdated() {\n // the order which things happen here is important!\n\n if (this.open) {\n // hide scrollbar and prevent scroll on body\n this.scrollBar.hide()\n\n // store the element that was focused prior to modal opening\n this.trigger = document.activeElement as HTMLElement\n\n // handle initial (auto)focus\n const focusTarget = this.querySelector<HTMLElement>(\"[autofocus]\") || this\n focusTarget.focus()\n\n // finally, we should enable the focus trap\n this.focusTrap.trap()\n } else {\n // ensure modal is scrolled to top ready for re-open\n this.backdrop.scrollTop = 0\n\n // we need to release the focus trap...\n this.focusTrap.release()\n\n // ...before we can return focus to the trigger button\n this.trigger?.focus()\n this.trigger = undefined\n }\n }\n\n private enableScroll = (e: TransitionEvent) => {\n // scrollbar should only be restored when the backdrop has transitioned\n // that way we avoid awkward double scrollbars.\n if (!this.open && e.target === this.backdrop) {\n this.scrollBar.restore()\n }\n }\n\n private handleDismiss() {\n // allow cancelling of close\n const allowed = this.dispatchEvent(new NordEvent(\"cancel\", { cancelable: true }))\n\n if (allowed) {\n this.close()\n }\n }\n\n /**\n * capture the last button clicked, so that we can polyfill `submitter` property in submit event\n */\n private trackLastButton = (e: Event) => {\n const target = e.target as HTMLElement\n\n if (isButton(target)) {\n this.lastButton = target\n }\n }\n\n private polyfillSubmitter = (e: Event) => {\n // @ts-expect-error submitter is readonly, but this is only called if SubmitEvent is not supported\n e.submitter = this.lastButton\n }\n\n private handleSubmit = (e: SubmitEvent) => {\n this.lastButton = undefined\n\n const target = e.target as HTMLFormElement\n const submitter = e.submitter as HTMLButtonElement\n\n const isDialogProperty = target.method === \"dialog\"\n const isDialogAttr = target.getAttribute(\"method\") === \"dialog\"\n\n // if they mismatch, it means \"dialog\" method is not supported,\n // so we should polyfill the fact it does not do a full submit\n if (isDialogAttr && !isDialogProperty) {\n e.preventDefault()\n }\n\n if (isDialogAttr || isDialogProperty) {\n this.close(submitter?.value)\n }\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"nord-modal\": Modal\n }\n}\n"],"names":["FocusTrapController","constructor","host","boundary","this","lastScrollY","handleFocusOut","e","lastFocused","target","relatedTarget","recaptureFocus","handleFocusIn","composedPath","includes","restoreScroll","window","scrollTo","scrollX","addController","hostDisconnected","release","trap","scrollY","addEventListener","undefined","removeEventListener","_a","focus","preventScroll","setStyle","style","property","value","previous","ScrollbarController","scroller","document","body","resets","Set","restore","width","documentWidth","documentElement","clientWidth","Math","abs","innerWidth","hide","computedStyle","getComputedStyle","paddingRight","parseInt","add","forEach","reset","clear","Modal","DraftComponentMixin","LitElement","headerSlot","SlotController","featureSlot","footerSlot","scrollBar","focusTrap","modal","localize","LocalizeController","events","EventController","lightDismiss","LightDismissController","isOpen","open","isDismissible","node","onDismiss","handleDismiss","size","returnValue","scrollable","enableScroll","backdrop","trackLastButton","localName","lastButton","polyfillSubmitter","submitter","handleSubmit","isDialogProperty","method","isDialogAttr","getAttribute","preventDefault","close","connectedCallback","super","setAttribute","SubmitEvent","listen","showModal","dispatchEvent","NordEvent","options","render","html","isEmpty","slotName","term","handleOpenUpdated","trigger","activeElement","querySelector","scrollTop","cancelable","styles","componentStyle","__decorate","query","prototype","type","Boolean","reflect","attribute","observe","customElement"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Modal.js","sources":["../src/common/controllers/FocusTrapController.ts","../src/common/controllers/ScrollbarController.ts","../src/modal/Modal.ts"],"sourcesContent":["import { ReactiveController, ReactiveControllerHost } from \"lit\"\n\nexport class FocusTrapController implements ReactiveController {\n private lastScrollY = 0\n private lastFocused?: HTMLElement\n\n constructor(host: ReactiveControllerHost & HTMLElement, private boundary: () => HTMLElement = () => host) {\n host.addController(this)\n }\n\n hostDisconnected() {\n this.release()\n }\n\n trap() {\n this.lastScrollY = window.scrollY\n this.boundary().addEventListener(\"focusout\", this.handleFocusOut)\n window.addEventListener(\"scroll\", this.restoreScroll)\n window.addEventListener(\"focusin\", this.handleFocusIn)\n }\n\n release() {\n this.lastScrollY = 0\n this.lastFocused = undefined\n\n this.boundary().removeEventListener(\"focusout\", this.handleFocusOut)\n window.removeEventListener(\"scroll\", this.restoreScroll)\n window.removeEventListener(\"focusin\", this.handleFocusIn)\n }\n\n private handleFocusOut = (e: FocusEvent) => {\n this.lastFocused = e.target as HTMLElement\n\n if (e.relatedTarget === this.boundary()) {\n this.recaptureFocus()\n }\n }\n\n private handleFocusIn = (e: FocusEvent) => {\n const isOutside = !e.composedPath().includes(this.boundary())\n\n if (isOutside) {\n this.recaptureFocus()\n }\n }\n\n private recaptureFocus() {\n this.lastFocused?.focus({ preventScroll: true })\n }\n\n private restoreScroll = () => {\n window.scrollTo(window.scrollX, this.lastScrollY)\n }\n}\n","import { ReactiveController, ReactiveControllerHost } from \"lit\"\n\nexport class ScrollbarController implements ReactiveController {\n private resets = new Set<() => void>()\n\n constructor(host: ReactiveControllerHost)\n constructor(host: ReactiveControllerHost, scroller: HTMLElement)\n\n constructor(host: ReactiveControllerHost, private scroller = document.body) {\n host.addController(this)\n }\n\n hostDisconnected() {\n this.restore()\n }\n\n // eslint-disable-next-line class-methods-use-this\n get width() {\n const documentWidth = document.documentElement.clientWidth\n return Math.abs(window.innerWidth - documentWidth)\n }\n\n hide() {\n // in case hide() is called twice in succession\n this.restore()\n\n const { width } = this\n const computedStyle = getComputedStyle(this.scroller)\n const paddingRight = parseInt(computedStyle.paddingRight, 10) || 0\n\n // hiding the scrollbar slightly increases the width of the inner viewport.\n // this is fine for the modal, since it is accounted for there. but it causes layout shift for any other fixed position components/elements.\n // so we define a custom property here for the gutter value, since it can be inherited/used by any other component that has a fixed position e.g. toast-group.\n this.setStyle(\"--n-scrollbar-gutter\", `${width + paddingRight}px`)\n this.setStyle(\"overflow\", \"hidden\")\n this.setStyle(\"padding-right\", `var(--n-scrollbar-gutter)`)\n }\n\n restore() {\n this.resets.forEach(reset => reset())\n this.resets.clear()\n }\n\n private setStyle(property: string, value: string) {\n const { style } = this.scroller\n const previous = this.scroller.style.getPropertyValue(property)\n\n style.setProperty(property, value)\n this.resets.add(() => style.setProperty(property, previous))\n }\n}\n","import { LitElement, html } from \"lit\"\nimport { customElement, property, query } from \"lit/decorators.js\"\nimport * as closeIcon from \"@nordhealth/icons/lib/assets/interface-close-small.js\"\n\nimport Icon from \"../icon/Icon.js\"\nimport { EventController } from \"../common/controllers/EventController.js\"\nimport { FocusTrapController } from \"../common/controllers/FocusTrapController.js\"\nimport { LightDismissController } from \"../common/controllers/LightDismissController.js\"\nimport { ScrollbarController } from \"../common/controllers/ScrollbarController.js\"\nimport { SlotController } from \"../common/controllers/SlotController.js\"\nimport { observe } from \"../common/decorators/observe.js\"\nimport { NordEvent } from \"../common/events.js\"\nimport { DraftComponentMixin } from \"../common/mixins/DraftComponentMixin.js\"\n\nimport componentStyle from \"../common/styles/Component.css\"\nimport { LocalizeController } from \"../localization/LocalizeController.js\"\nimport style from \"./Modal.css\"\n\nIcon.registerIcon(closeIcon)\n\nconst isButton = (element: Element): element is HTMLButtonElement => element.localName === \"button\"\n\n/**\n * Modal component is used to display content that temporarily blocks interactions\n * with the main view of an application. Modal should be used sparingly and\n * only when necessary.\n *\n * @status draft\n * @category overlay\n * @slot - Default slot\n * @slot header - Slot which holds the header of the modal, positioned next to the close button.\n * @slot footer - Slot which is typically used to hold call to action buttons, but can also be used to build custom footers.\n * @fires cancel - Dispatched before the modal has closed when a user attempts to dismiss a modal. Call `preventDefault()` on the event to prevent the modal closing.\n * @fires close - Dispatched when a modal is closed for any reason.\n */\n@customElement(\"nord-modal\")\nexport default class Modal extends DraftComponentMixin(LitElement) {\n static styles = [componentStyle, style]\n\n @query(\".n-modal\", true) private modal!: HTMLDivElement\n @query(\".n-modal-backdrop\", true) private backdrop!: HTMLDivElement\n\n private trigger?: HTMLElement\n private lastButton?: HTMLButtonElement\n\n private headerSlot = new SlotController(this, \"header\")\n private featureSlot = new SlotController(this, \"feature\")\n private footerSlot = new SlotController(this, \"footer\")\n\n private scrollBar = new ScrollbarController(this)\n private focusTrap = new FocusTrapController(this, () => this.modal)\n private localize = new LocalizeController<\"nord-modal\">(this)\n private events = new EventController(this)\n private lightDismiss = new LightDismissController(this, {\n isOpen: () => this.open,\n isDismissible: node => node !== this.modal,\n onDismiss: () => this.handleDismiss(),\n })\n\n /**\n * Controls whether the modal is open or not.\n */\n @property({ type: Boolean, reflect: true }) open = false\n\n /**\n * Controls the max-width of the modal when open.\n */\n @property({ reflect: true }) size: \"s\" | \"m\" | \"l\" = \"m\"\n\n /**\n * The reason why the modal was closed. This typically indicates\n * which button the user pressed to close the modal, though any value\n * can be supplied if the modal is programmatically closed.\n */\n @property({ attribute: false }) returnValue: string = \"\"\n\n /**\n * By default if a modal is too big for the browser window,\n * the entire modal will scroll. This setting changes that behavior\n * so that the body of the modal scrolls instead, with the modal\n * itself remaining fixed.\n */\n @property({ type: Boolean, reflect: true }) scrollable = false\n\n connectedCallback(): void {\n super.connectedCallback()\n\n this.setAttribute(\"role\", \"dialog\")\n this.setAttribute(\"aria-modal\", \"true\")\n\n // if submit event is not supported, let's do a basic polyfill\n if (!window.SubmitEvent) {\n this.events.listen(this, \"click\", this.trackLastButton, true)\n this.events.listen(this, \"submit\", this.polyfillSubmitter, true)\n }\n }\n\n /**\n * Show the modal, automatically moving focus to the modal or a child\n * element with an `autofocus` attribute.\n */\n showModal() {\n this.open = true\n }\n\n /**\n * Programmatically close the modal.\n * @param returnValue An optional value to indicate why the modal was closed.\n */\n close(returnValue?: string) {\n this.open = false\n\n if (returnValue != null) {\n this.returnValue = returnValue\n }\n\n this.dispatchEvent(new NordEvent(\"close\"))\n }\n\n /**\n * Programmatically focus the modal.\n * @param options An object which controls aspects of the focusing process.\n */\n focus(options?: FocusOptions) {\n this.modal.focus({ preventScroll: true, ...options })\n }\n\n render() {\n return html`\n <div class=\"n-modal-backdrop\" @transitionend=${this.enableScroll}>\n <div class=\"n-modal\" tabindex=\"0\" @submit=${this.handleSubmit}>\n <div class=\"n-modal-header n-rounded-top\" ?hidden=${this.headerSlot.isEmpty}>\n <slot class=\"n-padded\" name=${this.headerSlot.slotName}></slot>\n <button class=\"n-close\" @click=${this.handleDismiss}>\n <nord-icon name=\"interface-close-small\" size=\"s\" label=${this.localize.term(\"closeLabel\")}></nord-icon>\n </button>\n </div>\n\n <div class=\"n-modal-body\">\n <slot\n name=${this.featureSlot.slotName}\n class=${this.headerSlot.isEmpty ? \"n-rounded-top\" : \"\"}\n ?hidden=${this.featureSlot.isEmpty}\n ></slot>\n <slot class=\"n-body-padded\"></slot>\n </div>\n\n <div class=\"n-modal-footer n-padded\" ?hidden=${this.footerSlot.isEmpty}>\n <slot name=${this.footerSlot.slotName}></slot>\n </div>\n </div>\n </div>\n `\n }\n\n @observe(\"open\", \"updated\")\n protected handleOpenUpdated() {\n // the order which things happen here is important!\n\n if (this.open) {\n // hide scrollbar and prevent scroll on body\n this.scrollBar.hide()\n\n // store the element that was focused prior to modal opening\n this.trigger = document.activeElement as HTMLElement\n\n // handle initial (auto)focus\n const focusTarget = this.querySelector<HTMLElement>(\"[autofocus]\") || this\n focusTarget.focus()\n\n // finally, we should enable the focus trap\n this.focusTrap.trap()\n } else {\n // ensure modal is scrolled to top ready for re-open\n this.backdrop.scrollTop = 0\n\n // we need to release the focus trap...\n this.focusTrap.release()\n\n // ...before we can return focus to the trigger button\n this.trigger?.focus()\n this.trigger = undefined\n }\n }\n\n private enableScroll = (e: TransitionEvent) => {\n // scrollbar should only be restored when the backdrop has transitioned\n // that way we avoid awkward double scrollbars.\n if (!this.open && e.target === this.backdrop) {\n this.scrollBar.restore()\n }\n }\n\n private handleDismiss() {\n // allow cancelling of close\n const allowed = this.dispatchEvent(new NordEvent(\"cancel\", { cancelable: true }))\n\n if (allowed) {\n this.close()\n }\n }\n\n /**\n * capture the last button clicked, so that we can polyfill `submitter` property in submit event\n */\n private trackLastButton = (e: Event) => {\n const target = e.target as HTMLElement\n\n if (isButton(target)) {\n this.lastButton = target\n }\n }\n\n private polyfillSubmitter = (e: Event) => {\n // @ts-expect-error submitter is readonly, but this is only called if SubmitEvent is not supported\n e.submitter = this.lastButton\n }\n\n private handleSubmit = (e: SubmitEvent) => {\n this.lastButton = undefined\n\n const target = e.target as HTMLFormElement\n const submitter = e.submitter as HTMLButtonElement\n\n const isDialogProperty = target.method === \"dialog\"\n const isDialogAttr = target.getAttribute(\"method\") === \"dialog\"\n\n // if they mismatch, it means \"dialog\" method is not supported,\n // so we should polyfill the fact it does not do a full submit\n if (isDialogAttr && !isDialogProperty) {\n e.preventDefault()\n }\n\n if (isDialogAttr || isDialogProperty) {\n this.close(submitter?.value)\n }\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"nord-modal\": Modal\n }\n}\n"],"names":["FocusTrapController","constructor","host","boundary","this","lastScrollY","handleFocusOut","e","lastFocused","target","relatedTarget","recaptureFocus","handleFocusIn","composedPath","includes","restoreScroll","window","scrollTo","scrollX","addController","hostDisconnected","release","trap","scrollY","addEventListener","undefined","removeEventListener","_a","focus","preventScroll","ScrollbarController","scroller","document","body","resets","Set","restore","width","documentWidth","documentElement","clientWidth","Math","abs","innerWidth","hide","computedStyle","getComputedStyle","paddingRight","parseInt","setStyle","forEach","reset","clear","property","value","style","previous","getPropertyValue","setProperty","add","Icon","registerIcon","closeIcon","Modal","DraftComponentMixin","LitElement","headerSlot","SlotController","featureSlot","footerSlot","scrollBar","focusTrap","modal","localize","LocalizeController","events","EventController","lightDismiss","LightDismissController","isOpen","open","isDismissible","node","onDismiss","handleDismiss","size","returnValue","scrollable","enableScroll","backdrop","trackLastButton","localName","lastButton","polyfillSubmitter","submitter","handleSubmit","isDialogProperty","method","isDialogAttr","getAttribute","preventDefault","close","connectedCallback","super","setAttribute","SubmitEvent","listen","showModal","dispatchEvent","NordEvent","options","render","html","isEmpty","slotName","term","handleOpenUpdated","trigger","activeElement","querySelector","scrollTop","cancelable","styles","componentStyle","__decorate","query","prototype","type","Boolean","reflect","attribute","observe","customElement"],"mappings":"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"}
|
package/lib/Radio.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{_ as e,n as t}from"./query-assigned-elements-ef860822.js";import{w as o,r as n,$ as i,s as r}from"./lit-element-67e6cd99.js";import{e as a}from"./property-03f59dce.js";import{n as s}from"./ref-57ff8ffc.js";import{L as l}from"./LightDomController-6d26dea2.js";import{S as d}from"./SlotController-ea6eff46.js";import{o as c}from"./observe-a9c6dfb6.js";import{c as h}from"./cond-97c45476.js";import{F as p}from"./FocusableMixin-175ea4d7.js";import{F as m}from"./FormAssociatedMixin-
|
|
1
|
+
import{_ as e,n as t}from"./query-assigned-elements-ef860822.js";import{w as o,r as n,$ as i,s as r}from"./lit-element-67e6cd99.js";import{e as a}from"./property-03f59dce.js";import{n as s}from"./ref-57ff8ffc.js";import{L as l}from"./LightDomController-6d26dea2.js";import{S as d}from"./SlotController-ea6eff46.js";import{o as c}from"./observe-a9c6dfb6.js";import{c as h}from"./cond-97c45476.js";import{F as p}from"./FocusableMixin-175ea4d7.js";import{F as m}from"./FormAssociatedMixin-d0d98a92.js";import{I as u}from"./InputMixin-9334d385.js";import{s as v}from"./Component-a61df53a.js";import{s as b}from"./FormField-d3767c2e.js";import"./directive-de55b00a.js";import"./EventController-d99ebeef.js";import"./events-731d0007.js";import"./VisuallyHidden.js";class f extends d{constructor(e,t){super(e,t.slotName),this.options=t,this.onChange=()=>{this.syncLightDom()},this.renderHook=document.createComment(this.slotName),this.lightDom=new l(e,{render:()=>this.hasContent?o:this.options.render(),renderOptions:{renderBefore:this.renderHook}})}hostConnected(){super.hostConnected(),this.host.appendChild(this.renderHook),this.syncLightDom()}hostDisconnected(){this.renderHook.remove()}syncLightDom(){const e=this.content;e&&this.options.syncLightDom(e)}}const g=n`:host{--n-radio-size:calc(var(--n-space-m) * 1.25);display:inline-block;line-height:var(--n-line-height)}.n-flex{display:flex}.n-expand{flex:1}.n-input-container{position:relative}::slotted(input){--n-radio-accent-color:var(--n-color-accent);-moz-appearance:none;-webkit-appearance:none;appearance:none;margin:0!important;padding:0!important;border:1px solid var(--n-radio-border-color,var(--n-color-border-hover))!important;border-radius:var(--n-border-radius-circle)!important;transition:none!important;display:block!important;inline-size:var(--n-radio-size)!important;block-size:var(--n-radio-size)!important;cursor:pointer}::slotted(input:checked){--n-radio-border-color:var(--n-color-accent);background:var(--n-radio-accent-color)!important}::slotted(input[aria-invalid]){--n-radio-accent-color:var(--n-color-status-danger);--n-radio-border-color:var(--n-radio-accent-color)}::slotted(input:active){opacity:.8}::slotted(input:focus-visible){outline:0!important}::slotted(input:focus){outline:0!important;box-shadow:0 0 0 1px var(--n-color-surface),0 0 0 3px var(--n-color-accent)!important}:host([disabled]) ::slotted(input){--n-radio-accent-color:var(--n-color-border-strong);--n-radio-border-color:var(--n-radio-accent-color);background:var(--n-radio-accent-color);cursor:default;opacity:1}:host([disabled]) ::slotted(label){color:var(--n-color-text-weaker);cursor:default}.n-dot{--n-radio-dot-size:var(--n-space-s);--n-radio-dot-inset:calc((var(--n-radio-size) - var(--n-radio-dot-size)) / 2);position:absolute;border-radius:var(--n-border-radius-circle);inline-size:var(--n-radio-dot-size);block-size:var(--n-radio-dot-size);background-color:var(--n-color-text-on-accent);inset-inline-start:var(--n-radio-dot-inset);inset-block-start:var(--n-radio-dot-inset);z-index:var(--n-index-default);pointer-events:none}.n-label-container{padding-block-end:0}::slotted(label){-webkit-user-select:none;user-select:none;font-weight:var(--n-font-weight)!important;line-height:var(--n-line-height-l)!important;padding-inline-start:var(--n-space-s)!important;cursor:pointer}.n-hint{padding-inline-start:var(--n-space-s)}.n-error{margin-block-start:calc(var(--n-space-s)/ 2);padding-inline-start:var(--n-space-s)}`;let k=0;const $=e=>`nord-radio-${e}-${k++}`;let y=class extends(m(u(p(r)))){constructor(){super(...arguments),this.inputId=$("input"),this.hintId=$("hint"),this.errorId=$("error"),this.hintSlot=new f(this,{slotName:"hint",render:()=>this.hint?i`<div slot="hint-internal" id="${this.hintId}">${this.hint}</div>`:o,syncLightDom:e=>{e.id=this.hintId}}),this.labelSlot=new f(this,{slotName:"label",render:()=>this.label?i`<label slot="label-internal" for="${this.inputId}">${this.label}</label>`:o,syncLightDom:e=>{!function(e){return"label"===e.localName}(e)?console.warn('NORD: Only <label> elements should be placed in radio\'s "label" slot'):e.htmlFor=this.inputId}}),this.errorSlot=new f(this,{slotName:"error",render:()=>this.error?i`<div slot="error-internal" id="${this.errorId}">${this.error}</div>`:o,syncLightDom:e=>{e.id=this.hintId}}),this.inputSlot=new l(this,{render:()=>i`<input slot="input" @blur="${this.handleBlur}" @focus="${this.handleFocus}" ${s(this.focusableRef)} class="n-input" id="${this.inputId}" type="radio" name="${h(this.name)}" .value="${h(this.value)}" .checked="${this.checked}" ?disabled="${this.disabled}" ?required="${this.required}" aria-describedby="${h(this.getDescribedBy())}" aria-invalid="${h(this.getInvalid())}" form="${h(this.getAttribute("form")||void 0)}">`}),this.checked=!1,this.handleBlur=e=>{e.stopPropagation(),this.dispatchEvent(new Event("blur",{bubbles:!1,cancelable:!0}))},this.handleFocus=e=>{e.stopPropagation(),this.dispatchEvent(new Event("focus",{bubbles:!1,cancelable:!0}))}}get formValue(){}render(){return i`<div class="n-flex"><div class="n-input-container" @change="${this.handleChange}"><slot name="input"></slot>${this.checked?i`<div class="n-dot"></div>`:o}</div><div class="n-expand"><div class="n-label-container">${e=this.hideLabel,t=()=>i`<slot name="label"></slot><slot name="label-internal"></slot>`,n=e=>i`<nord-visually-hidden>${e}</nord-visually-hidden>`,e?n(t()):t()}<div class="n-caption n-hint" ?hidden="${!this.hasHint}"><slot name="hint"></slot><slot name="hint-internal"></slot></div></div><div class="n-caption n-error" role="alert" ?hidden="${!this.hasError}"><slot name="error"></slot><slot name="error-internal"></slot></div></div></div>`;var e,t,n}handleCheckedChange(e){!e&&this.checked&&this.uncheckSiblings()}uncheckSiblings(){this.getRootNode().querySelectorAll(`nord-radio[name="${this.name}"]`).forEach((e=>{e!==this&&(e.checked=!1)}))}handleChange(e){e.stopPropagation();const t=e.target;this.checked=t.checked,super.handleChange(e)}};y.styles=[v,b,g],e([a({type:Boolean,reflect:!0})],y.prototype,"checked",void 0),e([c("checked")],y.prototype,"handleCheckedChange",null),y=e([t("nord-radio")],y);var x=y;export{x as default};
|
|
2
2
|
//# sourceMappingURL=Radio.js.map
|
package/lib/Select.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{_ as e,n as t}from"./query-assigned-elements-ef860822.js";import{r as o,$ as n,s as r}from"./lit-element-67e6cd99.js";import{
|
|
1
|
+
import{_ as e,n as t}from"./query-assigned-elements-ef860822.js";import{r as o,$ as n,s as r}from"./lit-element-67e6cd99.js";import{e as i}from"./property-03f59dce.js";import{l as s}from"./if-defined-fe1a64e3.js";import{n as a}from"./ref-57ff8ffc.js";import{o as l}from"./unsafe-html-61a04601.js";import"./Button.js";import{I as d}from"./InputMixin-9334d385.js";import{F as c}from"./FocusableMixin-175ea4d7.js";import{F as p}from"./FormAssociatedMixin-d0d98a92.js";import{s as u}from"./Component-a61df53a.js";import{s as h}from"./FormField-d3767c2e.js";import{S as m}from"./SlotController-ea6eff46.js";import"./directive-de55b00a.js";import"./EventController-d99ebeef.js";import"./LightDomController-6d26dea2.js";import"./cond-97c45476.js";import"./events-731d0007.js";import"./VisuallyHidden.js";const v=o`.n-select-container{position:relative;inline-size:fit-content}:host([expand]){inline-size:100%}:host([expand]) .n-select-container{inline-size:100%}select{-webkit-appearance:none;appearance:none;position:absolute;font-size:var(--n-font-size-m);font-family:var(--n-font-family);color:var(--n-color-text);inline-size:100%;opacity:.0001;cursor:pointer;background:0 0;border:0;block-size:var(--n-space-xl);inset-block-end:0;inset-inline-start:0;z-index:2}nord-button{--n-button-text-align:start}.n-label-container:hover+.n-select-container nord-button,select:hover+nord-button{--n-button-background-color:var(--n-color-button-hover);--n-button-border-color:var(--n-color-border-hover)}.n-label-container:hover+.n-select-container nord-button svg,select:hover+nord-button svg{color:var(--n-color-icon-hover)}select:focus+nord-button{--n-button-border-color:var(--n-color-accent);--n-button-box-shadow:0 0 0 1px var(--n-button-border-color)}:host([disabled]){cursor:auto;pointer-events:none}::slotted(:not([slot])){display:none}[slot=end] svg{color:var(--n-color-icon);min-inline-size:calc(var(--n-space-l)/ 2.2);max-inline-size:calc(var(--n-space-l)/ 2.2)}::slotted([slot=start]){margin-inline-start:calc(var(--n-space-s) * -1);margin-inline-end:var(--n-space-s)}select[aria-invalid=true]+nord-button{--n-button-border-color:var(--n-color-status-danger)}`;let b=class extends(p(d(c(r)))){constructor(){super(...arguments),this.defaultSlot=new m(this),this.inputId="select",this.expand=!1}get formValue(){return this.value||void 0}render(){const e=this.options,t=this.getButtonText(e);return n`<slot></slot>${this.renderLabel()}<div class="n-select-container"><select ${a(this.focusableRef)} id="${this.inputId}" ?disabled="${this.disabled}" ?required="${this.required}" name="${s(this.name)}" @change="${this.handleChange}" @input="${this.handleInput}" aria-describedby="${s(this.getDescribedBy())}" aria-invalid="${s(this.getInvalid())}">${this.placeholder&&n`<option value="" disabled="disabled" ?selected="${!this.value}">${this.placeholder}</option>`} ${e.map((e=>this.renderOption(e)))}</select><nord-button tabindex="-1" ?disabled="${this.disabled}" ?expand="${this.expand}" aria-hidden="true" type="button"><slot slot="start" name="start"></slot>${t}<div slot="end">${l('<svg viewBox="0 0 140 140" xmlns="http://www.w3.org/2000/svg"><path fill="currentColor" d="M105 56a10.416 10.416 0 0 1-7.42-3.08L72.478 27.818a3.528 3.528 0 0 0-4.956 0L42.42 52.92a10.5 10.5 0 0 1-14.84-14.84l35-35a10.486 10.486 0 0 1 14.84 0l35 35A10.5 10.5 0 0 1 105 56zm-35 84a10.416 10.416 0 0 1-7.42-3.08l-35-35a10.5 10.5 0 0 1 14.84-14.84l25.102 25.102a3.528 3.528 0 0 0 4.956 0L97.58 87.08a10.5 10.5 0 1 1 14.84 14.84l-35 35A10.416 10.416 0 0 1 70 140z"/></svg>')}</div></nord-button></div>${this.renderError()}`}get options(){return Array.from(this.querySelectorAll("option"))}getButtonText(e){const t=e.find((e=>e.value===this.value.toString()));return t?t.text:this.placeholder?this.placeholder:e[0]?e[0].text:""}renderOption(e){return n`<option value="${s(e.value)}" ?disabled="${e.disabled}" .selected="${e.value===this.value.toString()}">${e.text}</option>`}};b.styles=[u,h,v],e([i({reflect:!0,type:Boolean})],b.prototype,"expand",void 0),b=e([t("nord-select")],b);var f=b;export{f as default};
|
|
2
2
|
//# sourceMappingURL=Select.js.map
|
package/lib/Select.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Select.js","sources":["../src/select/Select.ts","../../icons/lib/assets/interface-dropdown-small.js"],"sourcesContent":["/* eslint-disable lit-a11y/no-invalid-change-handler */\nimport { LitElement, html } from \"lit\"\nimport { customElement } from \"lit/decorators.js\"\nimport { ifDefined } from \"lit/directives/if-defined.js\"\nimport { ref } from \"lit/directives/ref.js\"\nimport { unsafeHTML } from \"lit/directives/unsafe-html.js\"\n\nimport \"../button/Button.js\"\n\nimport dropdownIcon from \"@nordhealth/icons/lib/assets/interface-dropdown-small.js\"\nimport { InputMixin } from \"../common/mixins/InputMixin.js\"\nimport { FocusableMixin } from \"../common/mixins/FocusableMixin.js\"\nimport { FormAssociatedMixin } from \"../common/mixins/FormAssociatedMixin.js\"\n\nimport componentStyle from \"../common/styles/Component.css\"\nimport formFieldStyle from \"../common/styles/FormField.css\"\nimport style from \"./Select.css\"\nimport { SlotController } from \"../common/controllers/SlotController.js\"\n\n/**\n * Select lets users choose one option from an options menu.\n * Consider using select when you have 5 or more options to choose from.\n *\n * @status ready\n * @category form\n * @slot - Default slot for holding <option> elements.\n * @slot label - Use when a label requires more than plain text.\n * @slot hint - Use when a hint requires more than plain text.\n * @slot error - Optional slot that holds error text for the input.\n */\n@customElement(\"nord-select\")\nexport default class Select extends FormAssociatedMixin(InputMixin(FocusableMixin(LitElement))) {\n static styles = [componentStyle, formFieldStyle, style]\n\n protected override get formValue() {\n return this.value || undefined\n }\n\n private defaultSlot = new SlotController(this)\n\n protected inputId = \"select\"\n\n render() {\n const slottedOptions = this.options\n const buttonText = this.getButtonText(slottedOptions)\n\n return html`\n <slot></slot>\n ${this.renderLabel()}\n\n <div class=\"n-select-container\">\n <select\n ${ref(this.focusableRef)}\n id=${this.inputId}\n ?disabled=${this.disabled}\n ?required=${this.required}\n name=${ifDefined(this.name)}\n @change=${this.handleChange}\n @input=${this.handleInput}\n aria-describedby=${ifDefined(this.getDescribedBy())}\n aria-invalid=${ifDefined(this.getInvalid())}\n >\n ${this.placeholder && html`<option value=\"\" disabled ?selected=${!this.value}>${this.placeholder}</option>`}\n ${slottedOptions.map(option => this.renderOption(option))}\n </select>\n\n <nord-button tabindex=\"-1\" ?disabled=${this.disabled} ?expand=${this.expand} aria-hidden=\"true\" type=\"button\">\n <slot slot=\"start\" name=\"start\"></slot>\n ${buttonText}\n <div slot=\"end\">${unsafeHTML(dropdownIcon)}</div>\n </nord-button>\n </div>\n\n ${this.renderError()}\n `\n }\n\n private get options() {\n return Array.from(this.querySelectorAll(\"option\"))\n }\n\n private getButtonText(options: HTMLOptionElement[]): string {\n const selected = options.find(option => option.value === this.value.toString())\n\n if (selected) {\n return selected.text\n }\n\n if (this.placeholder) {\n return this.placeholder\n }\n\n if (options[0]) {\n return options[0].text\n }\n\n return \"\"\n }\n\n private renderOption(option: HTMLOptionElement) {\n return html`\n <option\n value=${ifDefined(option.value)}\n ?disabled=${option.disabled}\n .selected=${option.value === this.value.toString()}\n >\n ${option.text}\n </option>\n `\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"nord-select\": Select\n }\n}\n","export default '<svg viewBox=\"0 0 140 140\" xmlns=\"http://www.w3.org/2000/svg\"><path fill=\"currentColor\" d=\"M105 56a10.416 10.416 0 0 1-7.42-3.08L72.478 27.818a3.528 3.528 0 0 0-4.956 0L42.42 52.92a10.5 10.5 0 0 1-14.84-14.84l35-35a10.486 10.486 0 0 1 14.84 0l35 35A10.5 10.5 0 0 1 105 56zm-35 84a10.416 10.416 0 0 1-7.42-3.08l-35-35a10.5 10.5 0 0 1 14.84-14.84l25.102 25.102a3.528 3.528 0 0 0 4.956 0L97.58 87.08a10.5 10.5 0 1 1 14.84 14.84l-35 35A10.416 10.416 0 0 1 70 140z\"/></svg>'\nexport const title = \"interface-dropdown-small\"\nexport const tags = \"nordicon small interface dropdown select arrow up down caret triangle chevron\"\n"],"names":["Select","FormAssociatedMixin","InputMixin","FocusableMixin","LitElement","constructor","this","defaultSlot","SlotController","inputId","formValue","value","undefined","render","slottedOptions","options","buttonText","getButtonText","html","renderLabel","ref","focusableRef","disabled","required","ifDefined","name","handleChange","handleInput","getDescribedBy","getInvalid","placeholder","map","option","renderOption","
|
|
1
|
+
{"version":3,"file":"Select.js","sources":["../src/select/Select.ts","../../icons/lib/assets/interface-dropdown-small.js"],"sourcesContent":["/* eslint-disable lit-a11y/no-invalid-change-handler */\nimport { LitElement, html } from \"lit\"\nimport { customElement, property } from \"lit/decorators.js\"\nimport { ifDefined } from \"lit/directives/if-defined.js\"\nimport { ref } from \"lit/directives/ref.js\"\nimport { unsafeHTML } from \"lit/directives/unsafe-html.js\"\n\nimport \"../button/Button.js\"\n\nimport dropdownIcon from \"@nordhealth/icons/lib/assets/interface-dropdown-small.js\"\nimport { InputMixin } from \"../common/mixins/InputMixin.js\"\nimport { FocusableMixin } from \"../common/mixins/FocusableMixin.js\"\nimport { FormAssociatedMixin } from \"../common/mixins/FormAssociatedMixin.js\"\n\nimport componentStyle from \"../common/styles/Component.css\"\nimport formFieldStyle from \"../common/styles/FormField.css\"\nimport style from \"./Select.css\"\nimport { SlotController } from \"../common/controllers/SlotController.js\"\n\n/**\n * Select lets users choose one option from an options menu.\n * Consider using select when you have 5 or more options to choose from.\n *\n * @status ready\n * @category form\n * @slot - Default slot for holding <option> elements.\n * @slot label - Use when a label requires more than plain text.\n * @slot hint - Use when a hint requires more than plain text.\n * @slot error - Optional slot that holds error text for the input.\n */\n@customElement(\"nord-select\")\nexport default class Select extends FormAssociatedMixin(InputMixin(FocusableMixin(LitElement))) {\n static styles = [componentStyle, formFieldStyle, style]\n\n protected override get formValue() {\n return this.value || undefined\n }\n\n private defaultSlot = new SlotController(this)\n\n protected inputId = \"select\"\n\n /**\n * Controls whether the select expands to fill the width of its container.\n */\n @property({ reflect: true, type: Boolean }) expand = false\n\n render() {\n const slottedOptions = this.options\n const buttonText = this.getButtonText(slottedOptions)\n\n return html`\n <slot></slot>\n ${this.renderLabel()}\n\n <div class=\"n-select-container\">\n <select\n ${ref(this.focusableRef)}\n id=${this.inputId}\n ?disabled=${this.disabled}\n ?required=${this.required}\n name=${ifDefined(this.name)}\n @change=${this.handleChange}\n @input=${this.handleInput}\n aria-describedby=${ifDefined(this.getDescribedBy())}\n aria-invalid=${ifDefined(this.getInvalid())}\n >\n ${this.placeholder && html`<option value=\"\" disabled ?selected=${!this.value}>${this.placeholder}</option>`}\n ${slottedOptions.map(option => this.renderOption(option))}\n </select>\n\n <nord-button tabindex=\"-1\" ?disabled=${this.disabled} ?expand=${this.expand} aria-hidden=\"true\" type=\"button\">\n <slot slot=\"start\" name=\"start\"></slot>\n ${buttonText}\n <div slot=\"end\">${unsafeHTML(dropdownIcon)}</div>\n </nord-button>\n </div>\n\n ${this.renderError()}\n `\n }\n\n private get options() {\n return Array.from(this.querySelectorAll(\"option\"))\n }\n\n private getButtonText(options: HTMLOptionElement[]): string {\n const selected = options.find(option => option.value === this.value.toString())\n\n if (selected) {\n return selected.text\n }\n\n if (this.placeholder) {\n return this.placeholder\n }\n\n if (options[0]) {\n return options[0].text\n }\n\n return \"\"\n }\n\n private renderOption(option: HTMLOptionElement) {\n return html`\n <option\n value=${ifDefined(option.value)}\n ?disabled=${option.disabled}\n .selected=${option.value === this.value.toString()}\n >\n ${option.text}\n </option>\n `\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"nord-select\": Select\n }\n}\n","export default '<svg viewBox=\"0 0 140 140\" xmlns=\"http://www.w3.org/2000/svg\"><path fill=\"currentColor\" d=\"M105 56a10.416 10.416 0 0 1-7.42-3.08L72.478 27.818a3.528 3.528 0 0 0-4.956 0L42.42 52.92a10.5 10.5 0 0 1-14.84-14.84l35-35a10.486 10.486 0 0 1 14.84 0l35 35A10.5 10.5 0 0 1 105 56zm-35 84a10.416 10.416 0 0 1-7.42-3.08l-35-35a10.5 10.5 0 0 1 14.84-14.84l25.102 25.102a3.528 3.528 0 0 0 4.956 0L97.58 87.08a10.5 10.5 0 1 1 14.84 14.84l-35 35A10.416 10.416 0 0 1 70 140z\"/></svg>'\nexport const title = \"interface-dropdown-small\"\nexport const tags = \"nordicon small interface dropdown select arrow up down caret triangle chevron\"\n"],"names":["Select","FormAssociatedMixin","InputMixin","FocusableMixin","LitElement","constructor","this","defaultSlot","SlotController","inputId","expand","formValue","value","undefined","render","slottedOptions","options","buttonText","getButtonText","html","renderLabel","ref","focusableRef","disabled","required","ifDefined","name","handleChange","handleInput","getDescribedBy","getInvalid","placeholder","map","option","renderOption","unsafeHTML","renderError","Array","from","querySelectorAll","selected","find","toString","text","styles","componentStyle","formFieldStyle","style","__decorate","property","reflect","type","Boolean","prototype","customElement"],"mappings":"8mEA+BA,IAAqBA,EAArB,cAAoCC,EAAoBC,EAAWC,EAAeC,MAAlFC,kCAOUC,KAAAC,YAAc,IAAIC,EAAeF,MAE/BA,KAAOG,QAAG,SAKwBH,KAAMI,QAAG,EAX9BC,gBACrB,OAAOL,KAAKM,YAASC,EAYvBC,SACE,MAAMC,EAAiBT,KAAKU,QACtBC,EAAaX,KAAKY,cAAcH,GAEtC,OAAOI,CAAI,gBAEPb,KAAKc,wDAIDC,EAAIf,KAAKgB,qBACNhB,KAAKG,uBACEH,KAAKiB,wBACLjB,KAAKkB,mBACVC,EAAUnB,KAAKoB,mBACZpB,KAAKqB,yBACNrB,KAAKsB,kCACKH,EAAUnB,KAAKuB,oCACnBJ,EAAUnB,KAAKwB,kBAE5BxB,KAAKyB,aAAeZ,CAAI,oDAAwCb,KAAKM,UAASN,KAAKyB,0BACnFhB,EAAeiB,KAAIC,GAAU3B,KAAK4B,aAAaD,sDAGZ3B,KAAKiB,sBAAoBjB,KAAKI,mFAEjEO,oBACgBkB,EC1Eb,ofD8EP7B,KAAK8B,gBAICpB,cACV,OAAOqB,MAAMC,KAAKhC,KAAKiC,iBAAiB,WAGlCrB,cAAcF,GACpB,MAAMwB,EAAWxB,EAAQyB,MAAKR,GAAUA,EAAOrB,QAAUN,KAAKM,MAAM8B,aAEpE,OAAIF,EACKA,EAASG,KAGdrC,KAAKyB,YACAzB,KAAKyB,YAGVf,EAAQ,GACHA,EAAQ,GAAG2B,KAGb,GAGDT,aAAaD,GACnB,OAAOd,CAAI,kBAECM,EAAUQ,EAAOrB,sBACbqB,EAAOV,wBACPU,EAAOrB,QAAUN,KAAKM,MAAM8B,eAEtCT,EAAOU,kBA/ER3C,EAAM4C,OAAG,CAACC,EAAgBC,EAAgBC,GAaLC,EAAA,CAA3CC,EAAS,CAAEC,SAAS,EAAMC,KAAMC,WAAyBpD,EAAAqD,UAAA,cAAA,GAdvCrD,EAAMgD,EAAA,CAD1BM,EAAc,gBACMtD,SAAAA"}
|
package/lib/Textarea.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{_ as e,n as t}from"./query-assigned-elements-ef860822.js";import{r as i,$ as r,s}from"./lit-element-67e6cd99.js";import{e as o}from"./property-03f59dce.js";import{l as a}from"./if-defined-fe1a64e3.js";import{n}from"./ref-57ff8ffc.js";import{o as
|
|
1
|
+
import{_ as e,n as t}from"./query-assigned-elements-ef860822.js";import{r as i,$ as r,s}from"./lit-element-67e6cd99.js";import{e as o}from"./property-03f59dce.js";import{l as a}from"./if-defined-fe1a64e3.js";import{n}from"./ref-57ff8ffc.js";import{o as d}from"./observe-a9c6dfb6.js";import{F as l}from"./FocusableMixin-175ea4d7.js";import{F as p}from"./FormAssociatedMixin-d0d98a92.js";import{I as m}from"./InputMixin-9334d385.js";import{s as f}from"./Component-a61df53a.js";import{s as h}from"./FormField-d3767c2e.js";import{s as u}from"./TextField-93a3922f.js";import"./directive-de55b00a.js";import"./EventController-d99ebeef.js";import"./SlotController-ea6eff46.js";import"./events-731d0007.js";import"./VisuallyHidden.js";const c=i`.n-input{min-block-size:var(--n-textarea-height,76px);transition:border var(--n-transition-slowly),box-shadow var(--n-transition-slowly),background var(--n-transition-slowly);display:block;resize:vertical}:host([resize=auto]) .n-input{resize:none;overflow:hidden}`;let v=class extends(p(m(l(s)))){constructor(){super(...arguments),this.inputId="textarea",this.resize="vertical",this.expand=!1}render(){var e;return r`${this.renderLabel()}<div class="n-input-container"><textarea ${n(this.focusableRef)} id="${this.inputId}" class="n-input" ?disabled="${this.disabled}" ?required="${this.required}" name="${a(this.name)}" .value="${null!==(e=this.value)&&void 0!==e?e:""}" placeholder="${a(this.placeholder)}" @change="${this.handleChange}" @input="${this.handleInput}" aria-describedby="${a(this.getDescribedBy())}" aria-invalid="${a(this.getInvalid())}"></textarea></div>${this.renderError()}`}resizeToFitContent(){const e=this.focusableRef.value;e&&("auto"===this.resize?(e.style.height="auto",e.style.height=`${e.scrollHeight}px`):e.style.height=null)}};v.styles=[f,h,u,c],e([o({reflect:!0})],v.prototype,"resize",void 0),e([o({reflect:!0,type:Boolean})],v.prototype,"expand",void 0),e([d("resize","updated"),d("value","updated")],v.prototype,"resizeToFitContent",null),v=e([t("nord-textarea")],v);var b=v;export{b as default};
|
|
2
2
|
//# sourceMappingURL=Textarea.js.map
|
package/lib/Textarea.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Textarea.js","sources":["../src/textarea/Textarea.ts"],"sourcesContent":["import { LitElement, html } from \"lit\"\nimport { customElement, property } from \"lit/decorators.js\"\nimport { ifDefined } from \"lit/directives/if-defined.js\"\nimport { ref } from \"lit/directives/ref.js\"\nimport { observe } from \"../common/decorators/observe.js\"\n\nimport { FocusableMixin } from \"../common/mixins/FocusableMixin.js\"\nimport { FormAssociatedMixin } from \"../common/mixins/FormAssociatedMixin.js\"\nimport { InputMixin } from \"../common/mixins/InputMixin.js\"\n\nimport componentStyle from \"../common/styles/Component.css\"\nimport formFieldStyle from \"../common/styles/FormField.css\"\nimport textFieldStyle from \"../common/styles/TextField.css\"\nimport style from \"./Textarea.css\"\n\n/**\n * Textarea is a component that allows user to write text over\n * multiple rows. Used when the expected user input is long.\n * For shorter input, use the Input component.\n *\n * @status ready\n * @category form\n * @slot label - Use when a label requires more than plain text.\n * @slot hint - Optional slot that holds hint text for the textarea.\n * @slot error - Optional slot that holds error text for the textarea.\n */\n@customElement(\"nord-textarea\")\nexport default class Textarea extends FormAssociatedMixin(InputMixin(FocusableMixin(LitElement))) {\n static styles = [componentStyle, formFieldStyle, textFieldStyle, style]\n\n protected inputId = \"textarea\"\n\n /**\n * Controls whether the textarea is resizable.\n * By default is manually resizable vertically.\n * Set to \"auto\" to enable auto-resizing as content grows.\n */\n @property({ reflect: true }) resize: \"vertical\" | \"auto\" = \"vertical\"\n\n render() {\n return html`\n ${this.renderLabel()}\n\n <div class=\"n-input-container\">\n <textarea\n ${ref(this.focusableRef)}\n id=${this.inputId}\n class=\"n-input\"\n ?disabled=${this.disabled}\n ?required=${this.required}\n name=${ifDefined(this.name)}\n .value=${this.value ?? \"\"}\n placeholder=${ifDefined(this.placeholder)}\n @change=${this.handleChange}\n @input=${this.handleInput}\n aria-describedby=${ifDefined(this.getDescribedBy())}\n aria-invalid=${ifDefined(this.getInvalid())}\n ></textarea>\n </div>\n\n ${this.renderError()}\n `\n }\n\n @observe(\"resize\", \"updated\")\n @observe(\"value\", \"updated\")\n protected resizeToFitContent() {\n const textarea = this.focusableRef.value\n\n if (!textarea) {\n return\n }\n\n if (this.resize === \"auto\") {\n textarea.style.height = \"auto\"\n textarea.style.height = `${textarea.scrollHeight}px`\n } else {\n // @ts-expect-error this is actually fine, and removes the style value\n textarea.style.height = null\n }\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"nord-textarea\": Textarea\n }\n}\n"],"names":["Textarea","FormAssociatedMixin","InputMixin","FocusableMixin","LitElement","constructor","this","inputId","resize","render","html","renderLabel","ref","focusableRef","disabled","required","ifDefined","name","_a","value","placeholder","handleChange","handleInput","getDescribedBy","getInvalid","renderError","resizeToFitContent","textarea","style","height","scrollHeight","styles","componentStyle","formFieldStyle","textFieldStyle","__decorate","property","reflect","prototype","observe","customElement"],"mappings":"0+BA2BA,IAAqBA,EAArB,cAAsCC,EAAoBC,EAAWC,EAAeC,MAApFC,kCAGYC,KAAOC,QAAG,WAOSD,KAAME,OAAwB,
|
|
1
|
+
{"version":3,"file":"Textarea.js","sources":["../src/textarea/Textarea.ts"],"sourcesContent":["import { LitElement, html } from \"lit\"\nimport { customElement, property } from \"lit/decorators.js\"\nimport { ifDefined } from \"lit/directives/if-defined.js\"\nimport { ref } from \"lit/directives/ref.js\"\nimport { observe } from \"../common/decorators/observe.js\"\n\nimport { FocusableMixin } from \"../common/mixins/FocusableMixin.js\"\nimport { FormAssociatedMixin } from \"../common/mixins/FormAssociatedMixin.js\"\nimport { InputMixin } from \"../common/mixins/InputMixin.js\"\n\nimport componentStyle from \"../common/styles/Component.css\"\nimport formFieldStyle from \"../common/styles/FormField.css\"\nimport textFieldStyle from \"../common/styles/TextField.css\"\nimport style from \"./Textarea.css\"\n\n/**\n * Textarea is a component that allows user to write text over\n * multiple rows. Used when the expected user input is long.\n * For shorter input, use the Input component.\n *\n * @status ready\n * @category form\n * @slot label - Use when a label requires more than plain text.\n * @slot hint - Optional slot that holds hint text for the textarea.\n * @slot error - Optional slot that holds error text for the textarea.\n */\n@customElement(\"nord-textarea\")\nexport default class Textarea extends FormAssociatedMixin(InputMixin(FocusableMixin(LitElement))) {\n static styles = [componentStyle, formFieldStyle, textFieldStyle, style]\n\n protected inputId = \"textarea\"\n\n /**\n * Controls whether the textarea is resizable.\n * By default is manually resizable vertically.\n * Set to \"auto\" to enable auto-resizing as content grows.\n */\n @property({ reflect: true }) resize: \"vertical\" | \"auto\" = \"vertical\"\n\n /**\n * Controls whether the textarea expands to fill the width of its container.\n */\n @property({ reflect: true, type: Boolean }) expand = false\n\n render() {\n return html`\n ${this.renderLabel()}\n\n <div class=\"n-input-container\">\n <textarea\n ${ref(this.focusableRef)}\n id=${this.inputId}\n class=\"n-input\"\n ?disabled=${this.disabled}\n ?required=${this.required}\n name=${ifDefined(this.name)}\n .value=${this.value ?? \"\"}\n placeholder=${ifDefined(this.placeholder)}\n @change=${this.handleChange}\n @input=${this.handleInput}\n aria-describedby=${ifDefined(this.getDescribedBy())}\n aria-invalid=${ifDefined(this.getInvalid())}\n ></textarea>\n </div>\n\n ${this.renderError()}\n `\n }\n\n @observe(\"resize\", \"updated\")\n @observe(\"value\", \"updated\")\n protected resizeToFitContent() {\n const textarea = this.focusableRef.value\n\n if (!textarea) {\n return\n }\n\n if (this.resize === \"auto\") {\n textarea.style.height = \"auto\"\n textarea.style.height = `${textarea.scrollHeight}px`\n } else {\n // @ts-expect-error this is actually fine, and removes the style value\n textarea.style.height = null\n }\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"nord-textarea\": Textarea\n }\n}\n"],"names":["Textarea","FormAssociatedMixin","InputMixin","FocusableMixin","LitElement","constructor","this","inputId","resize","expand","render","html","renderLabel","ref","focusableRef","disabled","required","ifDefined","name","_a","value","placeholder","handleChange","handleInput","getDescribedBy","getInvalid","renderError","resizeToFitContent","textarea","style","height","scrollHeight","styles","componentStyle","formFieldStyle","textFieldStyle","__decorate","property","reflect","prototype","type","Boolean","observe","customElement"],"mappings":"0+BA2BA,IAAqBA,EAArB,cAAsCC,EAAoBC,EAAWC,EAAeC,MAApFC,kCAGYC,KAAOC,QAAG,WAOSD,KAAME,OAAwB,WAKfF,KAAMG,QAAG,EAErDC,eACE,OAAOC,CAAI,GACPL,KAAKM,yDAIDC,EAAIP,KAAKQ,qBACNR,KAAKC,uCAEED,KAAKS,wBACLT,KAAKU,mBACVC,EAAUX,KAAKY,kBACH,QAAVC,EAAAb,KAAKc,aAAK,IAAAD,EAAAA,EAAI,oBACTF,EAAUX,KAAKe,0BACnBf,KAAKgB,yBACNhB,KAAKiB,kCACKN,EAAUX,KAAKkB,oCACnBP,EAAUX,KAAKmB,mCAIhCnB,KAAKoB,gBAMDC,qBACR,MAAMC,EAAWtB,KAAKQ,aAAaM,MAE9BQ,IAIe,SAAhBtB,KAAKE,QACPoB,EAASC,MAAMC,OAAS,OACxBF,EAASC,MAAMC,OAAS,GAAGF,EAASG,kBAGpCH,EAASC,MAAMC,OAAS,QAvDrB9B,EAAMgC,OAAG,CAACC,EAAgBC,EAAgBC,EAAgBN,GASpCO,EAAA,CAA5BC,EAAS,CAAEC,SAAS,KAAgDtC,EAAAuC,UAAA,cAAA,GAKzBH,EAAA,CAA3CC,EAAS,CAAEC,SAAS,EAAME,KAAMC,WAAyBzC,EAAAuC,UAAA,cAAA,GA6B1DH,EAAA,CAFCM,EAAQ,SAAU,WAClBA,EAAQ,QAAS,YAejB1C,EAAAuC,UAAA,qBAAA,MA1DkBvC,EAAQoC,EAAA,CAD5BO,EAAc,kBACM3C,SAAAA"}
|
package/lib/Toast.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{_ as s,n as o}from"./query-assigned-elements-ef860822.js";import{r as t,$ as i,s as e}from"./lit-element-67e6cd99.js";import{o as r}from"./class-map-f1b6f1fa.js";import{e as n}from"./property-03f59dce.js";import{t as a}from"./state-70f38ceb.js";import{i as d}from"./query-2d22378e.js";import{D as c}from"./DraftComponentMixin-9e4b7b34.js";import l from"./Icon.js";import{s as m}from"./Component-a61df53a.js";import{N as p}from"./events-731d0007.js";import{E as u}from"./EventController-d99ebeef.js";import{o as f}from"./observe-a9c6dfb6.js";import"./directive-de55b00a.js";import"./if-defined-fe1a64e3.js";import"./unsafe-html-61a04601.js";import"./cond-97c45476.js";var v=Object.freeze({__proto__:null,default:'<svg viewBox="0 0 140 140" xmlns="http://www.w3.org/2000/svg"><path d="M133 7 7 133M7 7l126 126" stroke-width="14" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/></svg>',title:"interface-close",tags:"nordicon interface close cross remove delete erase symbol"});const b=t`:host{--n-toast-color:var(--n-color-surface);--n-toast-background-color:var(--n-color-text)}.n-toast{display:flex;gap:var(--n-space-l);align-items:flex-start;background-color:var(--n-toast-background-color);color:var(--n-toast-color);border-radius:var(--n-border-radius);animation:n-enter var(--n-transition-slowly) forwards 1;z-index:var(--n-index-toast);box-shadow:var(--n-box-shadow-popout)}.n-dismissed{animation-name:n-exit}@keyframes n-enter{from{transform:translateY(50%);opacity:0}}@keyframes n-exit{to{transform:scale(.97);opacity:0}}.n-toast-inner{padding:var(--n-space-m);flex:1}.n-dismiss{--n-toast-focus-ring:0 0 0 2px var(--n-color-accent);border:none;display:flex;justify-content:center;align-items:center;block-size:var(--n-space-xl);inline-size:var(--n-space-xl);position:relative;inset-inline-end:var(--n-space-s);inset-block-start:var(--n-space-s);background-color:transparent;border-radius:var(--n-border-radius);cursor:pointer}.n-dismiss::after,.n-dismiss::before{content:"";position:absolute;display:block;border-radius:var(--n-border-radius)}.n-dismiss::before{inset:0;background:var(--n-toast-color);transition:opacity var(--n-transition-quickly);opacity:0}.n-dismiss:is(:hover,:focus)::before{opacity:.06}.n-dismiss::after{inset:calc(var(--n-space-s) * -1)}.n-dismiss:active{transform:translateY(1px)}.n-dismiss:focus{outline:0;box-shadow:var(--n-toast-focus-ring)}@supports selector(:focus-visible){.n-dismiss:focus{box-shadow:none}.n-dismiss:focus-visible{box-shadow:var(--n-toast-focus-ring)}}.n-dismiss nord-icon{opacity:.53;transition:opacity var(--n-transition-quickly);color:var(--n-toast-color)}.n-dismiss:is(:hover,:focus) nord-icon{opacity:1}:host([variant=danger]){--n-toast-background-color:var(--n-color-status-danger);--n-toast-color:var(--n-color-text-on-accent)}`;l.registerIcon(v);let h=class extends(c(e)){constructor(){super(...arguments),this.events=new u(this),this.dismissed=!1,this.variant="default",this.autoDismiss=1e4}disconnectedCallback(){super.disconnectedCallback(),clearTimeout(this.timeoutId)}dismiss(){return this.dismissed=!0,clearTimeout(this.timeoutId),new Promise((s=>{this.events.listen(this.toast,"animationend",(()=>{this.dispatchEvent(new p("dismiss")),s()}),{once:!0})}))}render(){return i`<div class="${r({"n-toast":!0,"n-dismissed":this.dismissed})}"><div class="n-toast-inner"><slot></slot></div><button class="n-dismiss" @click="${this.dismiss}" aria-hidden="true"><nord-icon name="interface-close" size="s"></nord-icon></button></div>`}handleAutoDismissChange(){clearTimeout(this.timeoutId),null!=this.autoDismiss&&this.autoDismiss>=0&&setTimeout((()=>this.dismiss()),this.autoDismiss)}};h.styles=[m,b],s([d(".n-toast",!0)],h.prototype,"toast",void 0),s([a()],h.prototype,"dismissed",void 0),s([n({reflect:!0})],h.prototype,"variant",void 0),s([n({type:Number,attribute:"auto-dismiss"})],h.prototype,"autoDismiss",void 0),s([f("autoDismiss")],h.prototype,"handleAutoDismissChange",null),h=s([o("nord-toast")],h);var y=h;export{y as default};
|
|
2
|
+
//# sourceMappingURL=Toast.js.map
|
package/lib/Toast.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Toast.js","sources":["../../icons/lib/assets/interface-close.js","../src/toast/Toast.ts"],"sourcesContent":["export default '<svg viewBox=\"0 0 140 140\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M133 7 7 133M7 7l126 126\" stroke-width=\"14\" fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/></svg>'\nexport const title = \"interface-close\"\nexport const tags = \"nordicon interface close cross remove delete erase symbol\"\n","import { LitElement, html } from \"lit\"\nimport { classMap } from \"lit/directives/class-map.js\"\nimport { customElement, property, query, state } from \"lit/decorators.js\"\nimport * as closeIcon from \"@nordhealth/icons/lib/assets/interface-close.js\"\n\nimport { DraftComponentMixin } from \"../common/mixins/DraftComponentMixin.js\"\nimport Icon from \"../icon/Icon.js\"\nimport componentStyle from \"../common/styles/Component.css\"\nimport style from \"./Toast.css\"\nimport { NordEvent } from \"../common/events.js\"\nimport { EventController } from \"../common/controllers/EventController.js\"\nimport { observe } from \"../common/decorators/observe.js\"\n\nIcon.registerIcon(closeIcon)\n\n/**\n * Toasts are non-disruptive messages that appear in the interface\n * to provide quick, at-a-glance feedback on the outcome of an action.\n *\n * @status draft\n * @category feedback\n * @slot - Default slot used for the toast text/message.\n * @fires dismiss - Fired when the toast is dismissed (via user action or auto-dismiss), and its exit animation has completed. This event should be used to remove the dismissed toast from the DOM.\n */\n@customElement(\"nord-toast\")\nexport default class Toast extends DraftComponentMixin(LitElement) {\n static styles = [componentStyle, style]\n\n private timeoutId?: ReturnType<typeof setTimeout>\n private events = new EventController(this)\n\n @query(\".n-toast\", true) private toast!: HTMLElement\n @state() private dismissed = false\n\n /**\n * The style variant of the toast.\n */\n @property({ reflect: true }) variant: \"default\" | \"danger\" = \"default\"\n\n /**\n * Timeout in milliseconds before the toast is automatically dismissed.\n */\n @property({ type: Number, attribute: \"auto-dismiss\" }) autoDismiss? = 10000\n\n disconnectedCallback() {\n super.disconnectedCallback()\n clearTimeout(this.timeoutId)\n }\n\n /**\n * Programmatically dismiss the toast.\n * The returned promise resolves when toast's exit animation is complete.\n */\n dismiss() {\n this.dismissed = true\n clearTimeout(this.timeoutId)\n\n return new Promise<void>(resolve => {\n this.events.listen(\n this.toast,\n \"animationend\",\n () => {\n this.dispatchEvent(new NordEvent(\"dismiss\"))\n resolve()\n },\n { once: true }\n )\n })\n }\n\n render() {\n return html`\n <div class=${classMap({ \"n-toast\": true, \"n-dismissed\": this.dismissed })}>\n <div class=\"n-toast-inner\">\n <slot></slot>\n </div>\n\n <button class=\"n-dismiss\" @click=${this.dismiss} aria-hidden=\"true\">\n <nord-icon name=\"interface-close\" size=\"s\"></nord-icon>\n </button>\n </div>\n `\n }\n\n @observe(\"autoDismiss\")\n protected handleAutoDismissChange() {\n clearTimeout(this.timeoutId)\n\n if (this.autoDismiss != null && this.autoDismiss >= 0) {\n setTimeout(() => this.dismiss(), this.autoDismiss)\n }\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"nord-toast\": Toast\n }\n}\n"],"names":["Icon","registerIcon","closeIcon","Toast","DraftComponentMixin","LitElement","constructor","this","events","EventController","dismissed","variant","autoDismiss","disconnectedCallback","super","clearTimeout","timeoutId","dismiss","Promise","resolve","listen","toast","dispatchEvent","NordEvent","once","render","html","classMap","handleAutoDismissChange","setTimeout","styles","componentStyle","style","__decorate","query","prototype","state","property","reflect","type","Number","attribute","observe","customElement"],"mappings":"8sBAAe,oNACM,uBACD,q1DCWpBA,EAAKC,aAAaC,GAYlB,IAAqBC,EAArB,cAAmCC,EAAoBC,IAAvDC,kCAIUC,KAAAC,OAAS,IAAIC,EAAgBF,MAGpBA,KAASG,WAAG,EAKAH,KAAOI,QAAyB,UAKNJ,KAAWK,YAAI,IAEtEC,uBACEC,MAAMD,uBACNE,aAAaR,KAAKS,WAOpBC,UAIE,OAHAV,KAAKG,WAAY,EACjBK,aAAaR,KAAKS,WAEX,IAAIE,SAAcC,IACvBZ,KAAKC,OAAOY,OACVb,KAAKc,MACL,gBACA,KACEd,KAAKe,cAAc,IAAIC,EAAU,YACjCJ,MAEF,CAAEK,MAAM,OAKdC,SACE,OAAOC,CAAI,eACIC,EAAS,CAAE,WAAW,EAAM,cAAepB,KAAKG,gGAKxBH,KAAKU,qGAQpCW,0BACRb,aAAaR,KAAKS,WAEM,MAApBT,KAAKK,aAAuBL,KAAKK,aAAe,GAClDiB,YAAW,IAAMtB,KAAKU,WAAWV,KAAKK,eA/DnCT,EAAA2B,OAAS,CAACC,EAAgBC,GAKRC,EAAA,CAAxBC,EAAM,YAAY,IAAiC/B,EAAAgC,UAAA,aAAA,GAC3CF,EAAA,CAARG,KAAiCjC,EAAAgC,UAAA,iBAAA,GAKLF,EAAA,CAA5BI,EAAS,CAAEC,SAAS,KAAiDnC,EAAAgC,UAAA,eAAA,GAKfF,EAAA,CAAtDI,EAAS,CAAEE,KAAMC,OAAQC,UAAW,kBAAsCtC,EAAAgC,UAAA,mBAAA,GA2C3EF,EAAA,CADCS,EAAQ,gBAORvC,EAAAgC,UAAA,0BAAA,MAlEkBhC,EAAK8B,EAAA,CADzBU,EAAc,eACMxC,SAAAA"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{_ as t,n as e}from"./query-assigned-elements-ef860822.js";import{r as n,$ as s,s as o}from"./lit-element-67e6cd99.js";import{D as a}from"./DraftComponentMixin-9e4b7b34.js";import{s as i}from"./Component-a61df53a.js";const r=n`.n-toast-group{display:flex;flex-direction:column;gap:var(--n-space-s);position:fixed;z-index:var(--n-index-toast);inset:0;inset-block-start:auto;inset-inline-end:var(--n-scrollbar-gutter,0);margin:1em;pointer-events:none}::slotted(nord-toast){max-inline-size:calc(var(--n-space-xxl) * 5);inline-size:100%;margin-inline:auto;pointer-events:auto}`;let l=class extends(a(o)){render(){return s`<div class="n-toast-group" role="log" aria-relevant="additions"><slot></slot></div>`}addToast(t,e={}){const{variant:n,autoDismiss:s}=e,o=document.createElement("nord-toast");return n&&(o.variant=n),null!=s&&(o.autoDismiss=s),o.textContent=t,this.appendChild(o),o}};l.styles=[i,r],l=t([e("nord-toast-group")],l);var d=l;export{d as default};
|
|
2
|
+
//# sourceMappingURL=ToastGroup.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ToastGroup.js","sources":["../src/toast-group/ToastGroup.ts"],"sourcesContent":["import { LitElement, html } from \"lit\"\nimport { customElement } from \"lit/decorators.js\"\nimport { DraftComponentMixin } from \"../common/mixins/DraftComponentMixin.js\"\n\nimport componentStyle from \"../common/styles/Component.css\"\nimport Toast from \"../toast/Toast.js\"\nimport style from \"./ToastGroup.css\"\n\ntype ToastOptions = Partial<Pick<Toast, \"variant\" | \"autoDismiss\">>\n\n/**\n * Toast group is used to position and style a group of toasts, whilst ensuring they are announced by screen readers.\n *\n * @status draft\n * @category feedback\n * @slot - Default slot in which to place toasts.\n */\n@customElement(\"nord-toast-group\")\nexport default class ToastGroup extends DraftComponentMixin(LitElement) {\n static styles = [componentStyle, style]\n\n render() {\n return html`\n <div class=\"n-toast-group\" role=\"log\" aria-relevant=\"additions\">\n <slot></slot>\n </div>\n `\n }\n\n /**\n * Convenience method for creating and adding a toast to the group.\n * @param {string} text - The text/message of the toast.\n * @param options - An optional object for configuring the toast's `variant` and `autoDismiss`.\n * @returns The toast instance.\n */\n addToast(text: string, options: ToastOptions = {}) {\n const { variant, autoDismiss } = options\n const toast = document.createElement(\"nord-toast\")\n\n if (variant) {\n toast.variant = variant\n }\n\n if (autoDismiss != null) {\n toast.autoDismiss = autoDismiss\n }\n\n toast.textContent = text\n this.appendChild(toast)\n\n return toast\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"nord-toast-group\": ToastGroup\n }\n}\n"],"names":["ToastGroup","DraftComponentMixin","LitElement","render","html","addToast","text","options","variant","autoDismiss","toast","document","createElement","textContent","this","appendChild","styles","componentStyle","style","__decorate","customElement"],"mappings":"okBAkBA,IAAqBA,EAArB,cAAwCC,EAAoBC,IAG1DC,SACE,OAAOC,CAAI,sFAabC,SAASC,EAAcC,EAAwB,IAC7C,MAAMC,QAAEA,EAAOC,YAAEA,GAAgBF,EAC3BG,EAAQC,SAASC,cAAc,cAarC,OAXIJ,IACFE,EAAMF,QAAUA,GAGC,MAAfC,IACFC,EAAMD,YAAcA,GAGtBC,EAAMG,YAAcP,EACpBQ,KAAKC,YAAYL,GAEVA,IA/BFV,EAAAgB,OAAS,CAACC,EAAgBC,GADdlB,EAAUmB,EAAA,CAD9BC,EAAc,qBACMpB,SAAAA"}
|
package/lib/Toggle.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{_ as e,n}from"./query-assigned-elements-ef860822.js";import{r as i,$ as r,s as t}from"./lit-element-67e6cd99.js";import{e as o}from"./property-03f59dce.js";import{l as a}from"./if-defined-fe1a64e3.js";import{n as s}from"./ref-57ff8ffc.js";import{F as l}from"./FocusableMixin-175ea4d7.js";import{F as
|
|
1
|
+
import{_ as e,n}from"./query-assigned-elements-ef860822.js";import{r as i,$ as r,s as t}from"./lit-element-67e6cd99.js";import{e as o}from"./property-03f59dce.js";import{l as a}from"./if-defined-fe1a64e3.js";import{n as s}from"./ref-57ff8ffc.js";import{F as l}from"./FocusableMixin-175ea4d7.js";import{F as d}from"./FormAssociatedMixin-d0d98a92.js";import{I as c}from"./InputMixin-9334d385.js";import{s as g}from"./Component-a61df53a.js";import{s as p}from"./FormField-d3767c2e.js";import"./directive-de55b00a.js";import"./EventController-d99ebeef.js";import"./SlotController-ea6eff46.js";import"./events-731d0007.js";import"./VisuallyHidden.js";const h=i`:host{display:inline-block;font-size:var(--n-font-size-m);--n-toggle-inline-size:3.2143em;--n-toggle-block-size:calc(var(--n-toggle-inline-size) / 1.6);--n-toggle-thumb-margin:0.35em}.n-flex{display:flex}.n-expand{flex:1;display:flex;justify-content:center;align-items:flex-start;flex-direction:column;min-block-size:100%}.n-input-container{position:relative}.n-toggle{-webkit-appearance:none;appearance:none;display:inline-flex;align-items:center;inline-size:var(--n-toggle-inline-size);block-size:var(--n-toggle-block-size);border-radius:var(--n-border-radius-pill);background:var(--n-toggle-background,var(--n-color-border-strong));cursor:pointer;transition:background var(--n-transition-slowly);font-size:var(--n-toggle-size,var(--n-font-size-m))}.n-toggle::before{content:"";display:block;aspect-ratio:1/1;block-size:calc(100% - 2 * var(--n-toggle-thumb-margin));background:var(--n-color-text-on-accent);border-radius:var(--n-border-radius-circle);transition:margin;transition-duration:inherit;margin-inline-start:var(--n-toggle-thumb-margin);box-shadow:var(--n-box-shadow)}input:checked{--n-toggle-background:var(--n-color-text-link)}input:checked::before{margin-inline-start:calc(var(--n-toggle-inline-size) - var(--n-toggle-block-size) + var(--n-toggle-thumb-margin))}input:checked[aria-invalid]{--n-toggle-background:var(--n-color-status-danger)}input:focus{outline:0;box-shadow:0 0 0 1px var(--n-color-surface),0 0 0 3px var(--n-color-accent)}:host([disabled]) label{color:var(--n-color-text-weaker);cursor:default}:host([disabled]) input{opacity:.3;cursor:not-allowed}.n-label-container{padding-block-end:0}label{-webkit-user-select:none;user-select:none;font-weight:var(--n-font-weight)!important;line-height:var(--n-line-height-l);padding-inline-start:var(--n-space-s);cursor:pointer}.n-hint{padding-inline-start:var(--n-space-s)}.n-error{margin-block-start:calc(var(--n-space-s)/ 2);padding-inline-start:var(--n-space-s)}:host([reverse]) .n-error,:host([reverse]) .n-hint,:host([reverse]) label{padding-inline-start:0;padding-inline-end:var(--n-space-s)}:host([size="s"]) .n-toggle{--n-toggle-size:var(--n-font-size-xs)}:host([size="l"]) .n-toggle{--n-toggle-size:var(--n-font-size-xl)}`;let v=class extends(d(c(l(t)))){constructor(){super(...arguments),this.checked=!1,this.reverse=!1,this.size="m"}get formValue(){return this.checked?this.value||"on":void 0}render(){const e=r`<div class="n-expand">${this.renderLabel()} ${this.renderError()}</div>`,n=r`<div class="n-input-container"><input ${s(this.focusableRef)} class="n-toggle" id="${this.inputId}" type="checkbox" role="switch" name="${a(this.name)}" .value="${this.value}" .checked="${this.checked}" ?disabled="${this.disabled}" ?required="${this.required}" aria-describedby="${a(this.getDescribedBy())}" aria-invalid="${a(this.getInvalid())}" @change="${this.handleChange}"></div>`;return r`<div class="n-flex">${this.reverse?[e,n]:[n,e]}</div>`}handleChange(e){const n=e.target;this.checked=n.checked,super.handleChange(e)}};v.styles=[g,p,h],e([o({type:Boolean})],v.prototype,"checked",void 0),e([o({type:Boolean})],v.prototype,"reverse",void 0),e([o({reflect:!0})],v.prototype,"size",void 0),v=e([n("nord-toggle")],v);var m=v;export{m as default};
|
|
2
2
|
//# sourceMappingURL=Toggle.js.map
|