@nordhealth/components 1.0.0-beta.11 → 1.0.0-beta.12
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 +68 -68
- package/lib/Button.js +1 -1
- package/lib/Button.js.map +1 -1
- package/lib/CommandMenu.js +1 -1
- package/lib/CommandMenu.js.map +1 -1
- package/lib/bundle.js +2 -2
- package/lib/bundle.js.map +1 -1
- package/package.json +2 -2
package/custom-elements.json
CHANGED
|
@@ -420,6 +420,74 @@
|
|
|
420
420
|
],
|
|
421
421
|
"readme": "## Usage\n\nThis section includes guidelines for designers and developers about the usage of this component in different contexts.\n\n<div class=\"n-usage n-usage-do\">\n\n### Do\n\n- Use to show a status update on a piece of information or action.\n- Use to mark something as a “draft” or “new”.\n- Use when you want to highlight something that has been added recently.\n- Use established color patterns so that users can clearly identify the importance level.\n- Always position badge so that it’s clear to understand what object it’s related to.\n\n</div>\n<div class=\"n-usage n-usage-dont\">\n\n### Don’t\n\n- Don’t make badges clickable. Instead use button component’s small variant.\n- Don’t use alternatives to existing badge variants.\n\n</div>\n\n---\n\n## Content guidelines\n\nBadge labels should use a single word to describe the status of an object. Only use two words if you need to describe a complex state:\n\n<div class=\"n-usage n-usage-do\">Complete</div>\n<div class=\"n-usage n-usage-dont\">Action completed</div>\n\nWhen writing badge labels, always write them in sentence case, not title case. The first word should be capitalized and the rest lowercase (unless a proper noun):\n\n<div class=\"n-usage n-usage-do\">Partially refunded</div>\n<div class=\"n-usage n-usage-dont\">Partially Refunded</div>\n\nAvoid unnecessary words and articles in badge labels, such as “is”, “the”, “an” or “a”:\n\n<div class=\"n-usage n-usage-do\">Pending</div>\n<div class=\"n-usage n-usage-dont\">Item is pending</div>\n\nAlways describe the status in the past tense:\n\n<div class=\"n-usage n-usage-do\">Refunded</div>\n<div class=\"n-usage n-usage-dont\">Refund</div>\n\n---\n\n## Variants\n\nThis section describes the different component variants, their purpose, and when to use each variant.\n\n| Name | Purpose |\n| ----------- | --------------------------------------------------------------------------------------------------------------------------------------- |\n| `info` | The default variant. Used to convey general information that isn’t critical. |\n| `success` | Used to convey success states. For example, you might want to show a badge that tells the user a payment was successful. |\n| `highlight` | Used to highlight specific items in the interface, like notifications. |\n| `danger` | Used to communicate problems that have to be resolved so that user can continue forward. Should always be used for highlighting errors. |\n| `warning` | Used to display information that needs a user’s attention attention and may require further steps. |\n"
|
|
422
422
|
},
|
|
423
|
+
{
|
|
424
|
+
"kind": "javascript-module",
|
|
425
|
+
"path": "src/banner/Banner.ts",
|
|
426
|
+
"declarations": [
|
|
427
|
+
{
|
|
428
|
+
"kind": "class",
|
|
429
|
+
"description": "Banner informs users about important changes or conditions in the\ninterface. Use this component if you need to communicate to users\nin a prominent way.",
|
|
430
|
+
"name": "Banner",
|
|
431
|
+
"slots": [
|
|
432
|
+
{
|
|
433
|
+
"description": "default slot",
|
|
434
|
+
"name": ""
|
|
435
|
+
}
|
|
436
|
+
],
|
|
437
|
+
"members": [
|
|
438
|
+
{
|
|
439
|
+
"kind": "field",
|
|
440
|
+
"name": "variant",
|
|
441
|
+
"type": {
|
|
442
|
+
"text": "\"info\" | \"danger\" | \"success\" | \"warning\""
|
|
443
|
+
},
|
|
444
|
+
"default": "\"info\"",
|
|
445
|
+
"description": "The style variant of the banner.",
|
|
446
|
+
"attribute": "variant",
|
|
447
|
+
"reflects": true
|
|
448
|
+
}
|
|
449
|
+
],
|
|
450
|
+
"attributes": [
|
|
451
|
+
{
|
|
452
|
+
"name": "variant",
|
|
453
|
+
"type": {
|
|
454
|
+
"text": "\"info\" | \"danger\" | \"success\" | \"warning\""
|
|
455
|
+
},
|
|
456
|
+
"default": "\"info\"",
|
|
457
|
+
"description": "The style variant of the banner.",
|
|
458
|
+
"fieldName": "variant"
|
|
459
|
+
}
|
|
460
|
+
],
|
|
461
|
+
"superclass": {
|
|
462
|
+
"name": "LitElement",
|
|
463
|
+
"package": "lit"
|
|
464
|
+
},
|
|
465
|
+
"status": "new",
|
|
466
|
+
"category": "feedback",
|
|
467
|
+
"tagName": "nord-banner",
|
|
468
|
+
"customElement": true
|
|
469
|
+
}
|
|
470
|
+
],
|
|
471
|
+
"exports": [
|
|
472
|
+
{
|
|
473
|
+
"kind": "js",
|
|
474
|
+
"name": "default",
|
|
475
|
+
"declaration": {
|
|
476
|
+
"name": "Banner",
|
|
477
|
+
"module": "src/banner/Banner.ts"
|
|
478
|
+
}
|
|
479
|
+
},
|
|
480
|
+
{
|
|
481
|
+
"kind": "custom-element-definition",
|
|
482
|
+
"name": "nord-banner",
|
|
483
|
+
"declaration": {
|
|
484
|
+
"name": "Banner",
|
|
485
|
+
"module": "src/banner/Banner.ts"
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
],
|
|
489
|
+
"readme": "## Usage\n\nThis section includes guidelines for designers and developers about the usage of this component in different contexts.\n\n<div class=\"n-usage n-usage-do\">\n\n### Do\n\n- Use this component if you need to communicate in a prominent way.\n- Place banner at the top of the section it applies to.\n- Use for highlighting errors and success statuses.\n- Put banner close to the context it’s referring to.\n- Move focus to the banner if it’s relevant to the current workflow.\n\n</div>\n<div class=\"n-usage n-usage-dont\">\n\n### Don’t\n\n- Move focus to banner if it appears on page load.\n- Use for highlighting general content or as a banner.\n- Use to replace an error page.\n\n</div>\n\n---\n\n## Content guidelines\n\nBanner content should be clear, accurate and easy to understand:\n\n<div class=\"n-usage n-usage-do\">We’re experiencing an incident. Please see our status page for more details.</div>\n<div class=\"n-usage n-usage-dont\">There was an error.</div>\n\nWhen writing banner content, always write it in sentence case, not title case. The first word should be capitalized and the rest lowercase (unless a proper noun):\n\n<div class=\"n-usage n-usage-do\">We’re experiencing an incident.</div>\n<div class=\"n-usage n-usage-dont\">We’re Experiencing An Incident.</div>\n\nAlways end in punctuation:\n\n<div class=\"n-usage n-usage-do\">We’re experiencing an incident.</div>\n<div class=\"n-usage n-usage-dont\">We’re experiencing an incident</div>\n"
|
|
490
|
+
},
|
|
423
491
|
{
|
|
424
492
|
"kind": "javascript-module",
|
|
425
493
|
"path": "src/calendar/Calendar.ts",
|
|
@@ -879,74 +947,6 @@
|
|
|
879
947
|
],
|
|
880
948
|
"readme": "## Usage\n\nThis section includes guidelines for designers and developers about the usage of this component in different contexts.\n\n<div class=\"n-usage n-usage-do\">\n\n### Do\n\n- Use when the user needs to choose a single date or a date range.\n- Close calendar after a single date is selected, unless a range with a start and end date is required.\n\n</div>\n<div class=\"n-usage n-usage-dont\">\n\n### Don’t\n\n- Don’t use for entering date of birth. Use input component instead.\n- Don’t use for choosing a date that is over 10 years in the future or the past.\n\n</div>\n\n---\n\n## Keyboard accessibility\n\nCalendar component is built to closely follow [W3C Date Picker Dialog example](https://www.w3.org/TR/wai-aria-practices/examples/dialog-modal/datepicker-dialog.html) with some small exceptions to e.g. better support iOS VoiceOver and Android TalkBack.\n\n### Month/year buttons\n\n- `Space, Enter`: Changes the month and/or year displayed.\n\n### Calendar grid\n\n- `Space, Enter`: Selects a date.\n- `Arrow up`: Moves focus to the same day of the previous week.\n- `Arrow down`: Moves focus to the same day of the next week.\n- `Arrow right`: Moves focus to the next day. In right-to-left languages, moves focus to the previous day.\n- `Arrow left`: Moves focus to the previous day. In right-to-left languages, moves focus to the next day.\n- `Home`: Moves focus to the first day (e.g Monday) of the current week.\n- `End`: Moves focus to the last day (e.g. Sunday) of the current week.\n- `Page Up`: Changes the grid of dates to the previous month and sets focus on the same day of the same week.\n- `Shift + Page Up`: Changes the grid of dates to the previous year and sets focus on the same day of the same week.\n- `Page Down`: Changes the grid of dates to the next month and sets focus on the same day of the same week.\n- `Shift + Page Down`: Changes the grid of dates to the next year and sets focus on the same day of the same week.\n"
|
|
881
949
|
},
|
|
882
|
-
{
|
|
883
|
-
"kind": "javascript-module",
|
|
884
|
-
"path": "src/banner/Banner.ts",
|
|
885
|
-
"declarations": [
|
|
886
|
-
{
|
|
887
|
-
"kind": "class",
|
|
888
|
-
"description": "Banner informs users about important changes or conditions in the\ninterface. Use this component if you need to communicate to users\nin a prominent way.",
|
|
889
|
-
"name": "Banner",
|
|
890
|
-
"slots": [
|
|
891
|
-
{
|
|
892
|
-
"description": "default slot",
|
|
893
|
-
"name": ""
|
|
894
|
-
}
|
|
895
|
-
],
|
|
896
|
-
"members": [
|
|
897
|
-
{
|
|
898
|
-
"kind": "field",
|
|
899
|
-
"name": "variant",
|
|
900
|
-
"type": {
|
|
901
|
-
"text": "\"info\" | \"danger\" | \"success\" | \"warning\""
|
|
902
|
-
},
|
|
903
|
-
"default": "\"info\"",
|
|
904
|
-
"description": "The style variant of the banner.",
|
|
905
|
-
"attribute": "variant",
|
|
906
|
-
"reflects": true
|
|
907
|
-
}
|
|
908
|
-
],
|
|
909
|
-
"attributes": [
|
|
910
|
-
{
|
|
911
|
-
"name": "variant",
|
|
912
|
-
"type": {
|
|
913
|
-
"text": "\"info\" | \"danger\" | \"success\" | \"warning\""
|
|
914
|
-
},
|
|
915
|
-
"default": "\"info\"",
|
|
916
|
-
"description": "The style variant of the banner.",
|
|
917
|
-
"fieldName": "variant"
|
|
918
|
-
}
|
|
919
|
-
],
|
|
920
|
-
"superclass": {
|
|
921
|
-
"name": "LitElement",
|
|
922
|
-
"package": "lit"
|
|
923
|
-
},
|
|
924
|
-
"status": "new",
|
|
925
|
-
"category": "feedback",
|
|
926
|
-
"tagName": "nord-banner",
|
|
927
|
-
"customElement": true
|
|
928
|
-
}
|
|
929
|
-
],
|
|
930
|
-
"exports": [
|
|
931
|
-
{
|
|
932
|
-
"kind": "js",
|
|
933
|
-
"name": "default",
|
|
934
|
-
"declaration": {
|
|
935
|
-
"name": "Banner",
|
|
936
|
-
"module": "src/banner/Banner.ts"
|
|
937
|
-
}
|
|
938
|
-
},
|
|
939
|
-
{
|
|
940
|
-
"kind": "custom-element-definition",
|
|
941
|
-
"name": "nord-banner",
|
|
942
|
-
"declaration": {
|
|
943
|
-
"name": "Banner",
|
|
944
|
-
"module": "src/banner/Banner.ts"
|
|
945
|
-
}
|
|
946
|
-
}
|
|
947
|
-
],
|
|
948
|
-
"readme": "## Usage\n\nThis section includes guidelines for designers and developers about the usage of this component in different contexts.\n\n<div class=\"n-usage n-usage-do\">\n\n### Do\n\n- Use this component if you need to communicate in a prominent way.\n- Place banner at the top of the section it applies to.\n- Use for highlighting errors and success statuses.\n- Put banner close to the context it’s referring to.\n- Move focus to the banner if it’s relevant to the current workflow.\n\n</div>\n<div class=\"n-usage n-usage-dont\">\n\n### Don’t\n\n- Move focus to banner if it appears on page load.\n- Use for highlighting general content or as a banner.\n- Use to replace an error page.\n\n</div>\n\n---\n\n## Content guidelines\n\nBanner content should be clear, accurate and easy to understand:\n\n<div class=\"n-usage n-usage-do\">We’re experiencing an incident. Please see our status page for more details.</div>\n<div class=\"n-usage n-usage-dont\">There was an error.</div>\n\nWhen writing banner content, always write it in sentence case, not title case. The first word should be capitalized and the rest lowercase (unless a proper noun):\n\n<div class=\"n-usage n-usage-do\">We’re experiencing an incident.</div>\n<div class=\"n-usage n-usage-dont\">We’re Experiencing An Incident.</div>\n\nAlways end in punctuation:\n\n<div class=\"n-usage n-usage-do\">We’re experiencing an incident.</div>\n<div class=\"n-usage n-usage-dont\">We’re experiencing an incident</div>\n"
|
|
949
|
-
},
|
|
950
950
|
{
|
|
951
951
|
"kind": "javascript-module",
|
|
952
952
|
"path": "src/button/Button.ts",
|
package/lib/Button.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{_ as t,n as o}from"./query-assigned-elements-37b095c4.js";import{r as n,$ as e,w as r,s as a}from"./lit-element-9646ab7e.js";import{e as i}from"./property-03f59dce.js";import{l as s}from"./if-defined-2a4c6dbc.js";import{e as l,n as
|
|
1
|
+
import{_ as t,n as o}from"./query-assigned-elements-37b095c4.js";import{r as n,$ as e,w as r,s as a}from"./lit-element-9646ab7e.js";import{e as i}from"./property-03f59dce.js";import{l as s}from"./if-defined-2a4c6dbc.js";import{e as l,n as b}from"./ref-eb5cfa10.js";import{L as d}from"./LightDomController-f56fa1a4.js";import{F as c}from"./FocusableMixin-98e13999.js";import{I as u}from"./InputMixin-94d15730.js";import{s as h}from"./Component-6762b5eb.js";import"./directive-helpers-e7b6bf4b.js";import"./directive-de55b00a.js";const v=n`:host{display:inline-block}.n-button{-webkit-appearance:none;align-items:center;appearance:none;background:var(--n-button-background-color,var(--n-color-button));border-radius:var(--n-button-border-radius,var(--n-border-radius-s));border:1px var(--n-button-border-style,solid) var(--n-button-border-color,var(--n-color-border-strong));box-shadow:var(--n-button-box-shadow,var(--n-box-shadow));color:var(--n-button-color,var(--n-color-text));cursor:pointer;display:flex;gap:var(--n-button-gap,var(--n-space-s));font-family:var(--n-font-family);font-feature-settings:var(--n-font-features);font-size:var(--n-button-font-size,var(--n-font-size-m));font-weight:var(--n-button-font-weight,var(--n-font-weight));line-height:var(--n-line-height-form);margin:0;min-block-size:var(--n-button-min-height,var(--n-space-xl));padding:var(--n-button-padding-y,calc(var(--n-space-s)/ 1.6)) var(--n-button-padding-x,calc(var(--n-space-m)/ 1.2));text-align:var(--n-button-text-align,center);text-decoration:none;transition:all .1s ease;-webkit-user-select:none;user-select:none;position:relative;inline-size:var(--n-button-width,fit-content)}.n-button::after{content:"";position:absolute;background:0 0;background-image:var(--n-button-gradient,linear-gradient(to bottom,rgba(0,0,0,0) 50%,rgba(0,0,0,.013) 100%));background-repeat:repeat-x;inline-size:100%;inset-inline:0;block-size:100%;inset-block-start:0}:host([expand]){--n-button-width:100%;display:block}.n-content{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;position:relative}.n-button:hover{--n-button-background-color:var(--n-color-button-hover);--n-button-border-color:var(--n-color-border-hover)}.n-button:focus{--n-button-border-color:var(--n-color-primary);--n-button-border-style:solid;--n-button-box-shadow:0 0 0 1px var(--n-button-border-color);outline:0}.n-button:active{opacity:.8;transform:translateY(1px);transition:none}:host([variant=primary]){--n-button-background-color:var(--n-color-primary);--n-button-border-color:transparent;--n-button-box-shadow:none;--n-button-color:var(--n-color-text-inverse);--n-button-font-weight:var(--n-font-weight-active)}:host([variant=primary]) .n-button:focus{--n-button-box-shadow:0 0 0 1px var(--n-color-surface),0 0 0 3px var(--n-button-border-color)}:host([variant=primary]) .n-button:hover{--n-button-background-color:var(--n-color-primary-strong);--n-button-border-color:transparent}:host([variant=dashed]){--n-button-color:var(--n-color-text-weaker);--n-button-border-color:var(--n-color-border-hover);--n-button-border-style:dashed;--n-button-box-shadow:none}:host([variant=dashed]) .n-button:hover{--n-button-color:var(--n-color-text)}:host([variant=dashed]) .n-button::after{display:none}:host([variant=plain]){--n-button-border-color:transparent;--n-button-box-shadow:none}:host([variant=plain]) .n-button:hover{--n-button-border-color:transparent}:host([variant=plain]) .n-button:focus{--n-button-box-shadow:0 0 0 1px var(--n-button-border-color)}:host([variant=plain]) .n-button::after{display:none}:host([variant=danger]){--n-button-border-color:var(--n-color-status-danger);--n-button-color:var(--n-color-text-error);--n-button-font-weight:var(--n-font-weight-active)}:host([variant=danger]) .n-button:hover{--n-button-border-color:var(--n-color-status-danger)}:host([disabled]){--n-button-background-color:var(--n-color-border);--n-button-box-shadow:none;--n-button-border-color:var(--n-button-background-color);--n-button-color:var(--n-color-text-weaker);opacity:.5;pointer-events:none}:host([disabled]) .n-button::after{display:none}:host([size="s"]){--n-button-font-size:var(--n-font-size-s);--n-button-min-height:var(--n-space-l);--n-button-padding-y:calc(var(--n-space-s) / 1.5);--n-button-padding-x:var(--n-space-s);--n-button-gap:calc(var(--n-space-s) / 2)}:host([size="s"]) .n-button{line-height:var(--n-line-height-tight)}:host([size="l"]){--n-button-border-radius:var(--n-border-radius);--n-button-font-size:var(--n-font-size-l);--n-button-min-height:calc(var(--n-space-xxl) - var(--n-space-l));--n-button-padding-x:calc(var(--n-space-l) / 1.3);--n-button-font-weight:var(--n-font-weight-active)}::slotted(*){color:inherit;pointer-events:none}::slotted(svg){color:var(--n-color-icon)}::slotted(button[slot=proxy]){display:none}`;let p=class extends(u(c(a))){constructor(){super(...arguments),this.buttonRef=l(),this.lightDom=new d(this,{render:()=>this.renderLightDom()}),this.variant="default",this.type="submit",this.size="m",this.download=!1,this.target="_self",this.expand=!1,this.handleOuterClick=t=>{t.composedPath().some((t=>t===this.focusableRef.value||t===this.buttonRef.value))||t.stopPropagation()}}connectedCallback(){super.connectedCallback(),this.addEventListener("click",this.handleOuterClick,!0)}disconnectedCallback(){this.removeEventListener("click",this.handleOuterClick,!0)}render(){const t=e`<slot name="before"></slot><div class="n-content"><slot></slot></div><slot name="after"></slot>`;return this.href?this.renderLink(t):this.renderButton(t)}renderLink(t){return e`<a ${b(this.focusableRef)} class="n-button" target="${this.target}" ?download="${this.download}" href="${s(this.disabled?void 0:this.href)}" tabindex="${s(this.disabled?"-1":void 0)}" aria-disabled="${s(this.disabled?"true":void 0)}" role="${s(this.disabled?"link":void 0)}">${t}</a>`}renderButton(t){return e`<slot name="proxy"></slot><button ${b(this.focusableRef)} class="n-button" ?disabled="${this.disabled}" name="${s(this.name||void 0)}" value="${s(this.value||void 0)}" @click="${this.handleClick}">${t}</button>`}renderLightDom(){return this.href||!this.form?r:e`<button ${b(this.buttonRef)} slot="proxy" name="${s(this.name||void 0)}" value="${s(this.value||void 0)}" ?disabled="${this.disabled}" type="${this.type}"></button>`}handleClick(t){this.buttonRef.value&&(t.stopPropagation(),this.buttonRef.value.click())}};p.styles=[h,v],t([i({reflect:!0})],p.prototype,"variant",void 0),t([i({reflect:!0})],p.prototype,"type",void 0),t([i({reflect:!0})],p.prototype,"size",void 0),t([i({reflect:!0})],p.prototype,"href",void 0),t([i({type:Boolean})],p.prototype,"download",void 0),t([i({reflect:!0})],p.prototype,"target",void 0),t([i({reflect:!0,type:Boolean})],p.prototype,"expand",void 0),p=t([o("nord-button")],p);var f=p;export{f as default};
|
|
2
2
|
//# sourceMappingURL=Button.js.map
|
package/lib/Button.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Button.js","sources":["../src/button/Button.ts"],"sourcesContent":["import { LitElement, html, nothing, TemplateResult } from \"lit\"\nimport { customElement, property } from \"lit/decorators.js\"\nimport { ifDefined } from \"lit/directives/if-defined.js\"\nimport { createRef, ref } from \"lit/directives/ref.js\"\nimport { LightDomController } from \"../common/controllers/LightDomController.js\"\n\nimport { FocusableMixin } from \"../common/mixins/FocusableMixin.js\"\nimport { InputMixin } from \"../common/mixins/InputMixin.js\"\nimport componentStyle from \"../common/styles/Component.css\"\nimport style from \"./Button.css\"\n\n/**\n * Buttons are used for interface actions. Primary style should be\n * used only once per section for main call-to-action, while other\n * styles can appear more frequently.\n *\n * @status ready\n * @category action\n * @slot - The button content\n * @slot before - Used to place content before button text. Typically used for icons.\n * @slot after - Used to place content after button text. Typically used for icons.\n */\n@customElement(\"nord-button\")\nexport default class Button extends InputMixin(FocusableMixin(LitElement)) {\n static styles = [componentStyle, style]\n\n private buttonRef = createRef<HTMLButtonElement>()\n private lightDom = new LightDomController(this, {\n render: () => this.renderLightDom(),\n })\n\n /**\n * The style variant of the button.\n */\n @property({ reflect: true }) variant: \"default\" | \"primary\" | \"dashed\" | \"plain\" | \"danger\" = \"default\"\n\n /**\n * The type of the button.\n */\n @property({ reflect: true }) type: \"button\" | \"submit\" | \"reset\" = \"submit\"\n\n /**\n * The size of the button.\n * This affects font-size and padding.\n */\n @property({ reflect: true }) size: \"s\" | \"m\" | \"l\" = \"m\"\n\n /**\n * When provided, renders the button as a link,\n * with its href attribute set to the given value.\n */\n @property({ reflect: true }) href?: string\n\n /**\n * When provided together with a href property, the button will\n * trigger a file download instead of a page visit.\n */\n @property({ type: Boolean }) download = false\n\n /**\n * When provided together with a href property, determines where\n * to open the linked URL. The keywords have special meanings for\n * where to load the URL: “_self” means the current browsing context,\n * “_blank” usually a new tab but users can configure browsers this to\n * open a new window instead, “_parent” means the parent browsing\n * context of the current one, but if no parent exists, behaves as\n * _self, and finally “top” means the topmost browsing context.\n */\n @property({ reflect: true }) target: \"_self\" | \"_blank\" | \"_parent\" | \"_top\" = \"_self\"\n\n /**\n * Controls whether the button expands to fill the width of its container.\n */\n @property({ reflect: true, type: Boolean }) expand = false\n\n connectedCallback() {\n super.connectedCallback()\n this.addEventListener(\"click\", this.handleOuterClick, true)\n }\n\n disconnectedCallback() {\n this.removeEventListener(\"click\", this.handleOuterClick, true)\n }\n\n render() {\n const innards = html`\n <slot name=\"before\"></slot>\n <div class=\"n-content\">\n <slot></slot>\n </div>\n <slot name=\"after\"></slot>\n `\n\n return this.href ? this.renderLink(innards) : this.renderButton(innards)\n }\n\n /**\n * We jump through some hoops here to ensure the link is treated correctly when \"disabled\".\n * Links cannot be disabled natively, so we need to rely on some aria magic to get the correct semantics.\n * Along with the advice in the article below, we also set tabindex to \"-1\", so it is taken out of tab order.\n *\n * @see https://www.scottohara.me/blog/2021/05/28/disabled-links.html\n */\n private renderLink(innards: TemplateResult) {\n return html`\n <a\n ${ref(this.focusableRef)}\n class=\"n-button\"\n target=${this.target}\n ?download=${this.download}\n href=${ifDefined(this.disabled ? undefined : this.href)}\n tabindex=${ifDefined(this.disabled ? \"-1\" : undefined)}\n aria-disabled=${ifDefined(this.disabled ? \"true\" : undefined)}\n role=${ifDefined(this.disabled ? \"link\" : undefined)}\n >${innards}\n </a>\n `\n }\n\n private renderButton(innards: TemplateResult) {\n return html`\n <slot name=\"proxy\"></slot>\n <button\n ${ref(this.focusableRef)}\n class=\"n-button\"\n ?disabled=${this.disabled}\n name=${ifDefined(this.name || undefined)}\n value=${ifDefined(this.value || undefined)}\n @click=${this.handleClick}\n >\n ${innards}\n </button>\n `\n }\n\n private renderLightDom() {\n if (this.href || !this.form) {\n return nothing\n }\n\n return html`\n <button\n ${ref(this.buttonRef)}\n slot=\"proxy\"\n name=${ifDefined(this.name || undefined)}\n value=${ifDefined(this.value || undefined)}\n ?disabled=${this.disabled}\n type=${this.type}\n ></button>\n `\n }\n\n private handleOuterClick = (e: MouseEvent) => {\n // we want to avoid emitting click events when a click\n // happens in blank space in the host, but not on the button\n // so we stop propagation of any events if click didn't happen on the internal or proxy button\n const isInternalButton = e\n .composedPath()\n .some(node => node === this.focusableRef.value || node === this.buttonRef.value)\n\n if (!isInternalButton) {\n e.stopPropagation()\n }\n }\n\n private handleClick(e: Event) {\n if (this.buttonRef.value) {\n // prevents two events: one from internal button, one from proxy button\n e.stopPropagation()\n this.buttonRef.value.click()\n }\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"nord-button\": Button\n }\n}\n"],"names":["Button","InputMixin","FocusableMixin","LitElement","constructor","this","createRef","LightDomController","render","renderLightDom","e","composedPath","some","node","focusableRef","value","buttonRef","stopPropagation","connectedCallback","super","addEventListener","handleOuterClick","disconnectedCallback","removeEventListener","innards","html","href","renderLink","renderButton","ref","target","download","ifDefined","disabled","undefined","name","handleClick","form","nothing","type","click","componentStyle","style","__decorate","property","reflect","Boolean","customElement"],"mappings":"
|
|
1
|
+
{"version":3,"file":"Button.js","sources":["../src/button/Button.ts"],"sourcesContent":["import { LitElement, html, nothing, TemplateResult } from \"lit\"\nimport { customElement, property } from \"lit/decorators.js\"\nimport { ifDefined } from \"lit/directives/if-defined.js\"\nimport { createRef, ref } from \"lit/directives/ref.js\"\nimport { LightDomController } from \"../common/controllers/LightDomController.js\"\n\nimport { FocusableMixin } from \"../common/mixins/FocusableMixin.js\"\nimport { InputMixin } from \"../common/mixins/InputMixin.js\"\nimport componentStyle from \"../common/styles/Component.css\"\nimport style from \"./Button.css\"\n\n/**\n * Buttons are used for interface actions. Primary style should be\n * used only once per section for main call-to-action, while other\n * styles can appear more frequently.\n *\n * @status ready\n * @category action\n * @slot - The button content\n * @slot before - Used to place content before button text. Typically used for icons.\n * @slot after - Used to place content after button text. Typically used for icons.\n */\n@customElement(\"nord-button\")\nexport default class Button extends InputMixin(FocusableMixin(LitElement)) {\n static styles = [componentStyle, style]\n\n private buttonRef = createRef<HTMLButtonElement>()\n private lightDom = new LightDomController(this, {\n render: () => this.renderLightDom(),\n })\n\n /**\n * The style variant of the button.\n */\n @property({ reflect: true }) variant: \"default\" | \"primary\" | \"dashed\" | \"plain\" | \"danger\" = \"default\"\n\n /**\n * The type of the button.\n */\n @property({ reflect: true }) type: \"button\" | \"submit\" | \"reset\" = \"submit\"\n\n /**\n * The size of the button.\n * This affects font-size and padding.\n */\n @property({ reflect: true }) size: \"s\" | \"m\" | \"l\" = \"m\"\n\n /**\n * When provided, renders the button as a link,\n * with its href attribute set to the given value.\n */\n @property({ reflect: true }) href?: string\n\n /**\n * When provided together with a href property, the button will\n * trigger a file download instead of a page visit.\n */\n @property({ type: Boolean }) download = false\n\n /**\n * When provided together with a href property, determines where\n * to open the linked URL. The keywords have special meanings for\n * where to load the URL: “_self” means the current browsing context,\n * “_blank” usually a new tab but users can configure browsers this to\n * open a new window instead, “_parent” means the parent browsing\n * context of the current one, but if no parent exists, behaves as\n * _self, and finally “top” means the topmost browsing context.\n */\n @property({ reflect: true }) target: \"_self\" | \"_blank\" | \"_parent\" | \"_top\" = \"_self\"\n\n /**\n * Controls whether the button expands to fill the width of its container.\n */\n @property({ reflect: true, type: Boolean }) expand = false\n\n connectedCallback() {\n super.connectedCallback()\n this.addEventListener(\"click\", this.handleOuterClick, true)\n }\n\n disconnectedCallback() {\n this.removeEventListener(\"click\", this.handleOuterClick, true)\n }\n\n render() {\n const innards = html`\n <slot name=\"before\"></slot>\n <div class=\"n-content\">\n <slot></slot>\n </div>\n <slot name=\"after\"></slot>\n `\n\n return this.href ? this.renderLink(innards) : this.renderButton(innards)\n }\n\n /**\n * We jump through some hoops here to ensure the link is treated correctly when \"disabled\".\n * Links cannot be disabled natively, so we need to rely on some aria magic to get the correct semantics.\n * Along with the advice in the article below, we also set tabindex to \"-1\", so it is taken out of tab order.\n *\n * @see https://www.scottohara.me/blog/2021/05/28/disabled-links.html\n */\n private renderLink(innards: TemplateResult) {\n return html`\n <a\n ${ref(this.focusableRef)}\n class=\"n-button\"\n target=${this.target}\n ?download=${this.download}\n href=${ifDefined(this.disabled ? undefined : this.href)}\n tabindex=${ifDefined(this.disabled ? \"-1\" : undefined)}\n aria-disabled=${ifDefined(this.disabled ? \"true\" : undefined)}\n role=${ifDefined(this.disabled ? \"link\" : undefined)}\n >${innards}\n </a>\n `\n }\n\n private renderButton(innards: TemplateResult) {\n return html`\n <slot name=\"proxy\"></slot>\n <button\n ${ref(this.focusableRef)}\n class=\"n-button\"\n ?disabled=${this.disabled}\n name=${ifDefined(this.name || undefined)}\n value=${ifDefined(this.value || undefined)}\n @click=${this.handleClick}\n >\n ${innards}\n </button>\n `\n }\n\n private renderLightDom() {\n if (this.href || !this.form) {\n return nothing\n }\n\n return html`\n <button\n ${ref(this.buttonRef)}\n slot=\"proxy\"\n name=${ifDefined(this.name || undefined)}\n value=${ifDefined(this.value || undefined)}\n ?disabled=${this.disabled}\n type=${this.type}\n ></button>\n `\n }\n\n private handleOuterClick = (e: MouseEvent) => {\n // we want to avoid emitting click events when a click\n // happens in blank space in the host, but not on the button\n // so we stop propagation of any events if click didn't happen on the internal or proxy button\n const isInternalButton = e\n .composedPath()\n .some(node => node === this.focusableRef.value || node === this.buttonRef.value)\n\n if (!isInternalButton) {\n e.stopPropagation()\n }\n }\n\n private handleClick(e: Event) {\n if (this.buttonRef.value) {\n // prevents two events: one from internal button, one from proxy button\n e.stopPropagation()\n this.buttonRef.value.click()\n }\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"nord-button\": Button\n }\n}\n"],"names":["Button","InputMixin","FocusableMixin","LitElement","constructor","this","createRef","LightDomController","render","renderLightDom","e","composedPath","some","node","focusableRef","value","buttonRef","stopPropagation","connectedCallback","super","addEventListener","handleOuterClick","disconnectedCallback","removeEventListener","innards","html","href","renderLink","renderButton","ref","target","download","ifDefined","disabled","undefined","name","handleClick","form","nothing","type","click","componentStyle","style","__decorate","property","reflect","Boolean","customElement"],"mappings":"msJAuBA,IAAqBA,EAArB,cAAoCC,EAAWC,EAAeC,KAA9DC,kCAGUC,eAAYC,IACZD,cAAW,IAAIE,EAAmBF,KAAM,CAC9CG,OAAQ,IAAMH,KAAKI,mBAMQJ,aAAiE,UAKjEA,UAAsC,SAMtCA,UAAwB,IAYxBA,eAAW,EAWXA,YAAkD,QAKnCA,aAAS,EA+E7CA,sBAAoBK,IAIDA,EACtBC,eACAC,MAAKC,GAAQA,IAASR,KAAKS,aAAaC,OAASF,IAASR,KAAKW,UAAUD,SAG1EL,EAAEO,mBAtFNC,oBACEC,MAAMD,oBACNb,KAAKe,iBAAiB,QAASf,KAAKgB,kBAAkB,GAGxDC,uBACEjB,KAAKkB,oBAAoB,QAASlB,KAAKgB,kBAAkB,GAG3Db,SACE,MAAMgB,EAAUC,CAAI,kGAQpB,OAAOpB,KAAKqB,KAAOrB,KAAKsB,WAAWH,GAAWnB,KAAKuB,aAAaJ,GAU1DG,WAAWH,GACjB,OAAOC,CAAI,MAELI,EAAIxB,KAAKS,0CAEFT,KAAKyB,sBACFzB,KAAK0B,mBACVC,EAAU3B,KAAK4B,cAAWC,EAAY7B,KAAKqB,oBACvCM,EAAU3B,KAAK4B,SAAW,UAAOC,sBAC5BF,EAAU3B,KAAK4B,SAAW,YAASC,aAC5CF,EAAU3B,KAAK4B,SAAW,YAASC,OACvCV,QAKDI,aAAaJ,GACnB,OAAOC,CAAI,qCAGLI,EAAIxB,KAAKS,6CAECT,KAAK4B,mBACVD,EAAU3B,KAAK8B,WAAQD,cACtBF,EAAU3B,KAAKU,YAASmB,eACvB7B,KAAK+B,gBAEZZ,aAKAf,iBACN,OAAIJ,KAAKqB,OAASrB,KAAKgC,KACdC,EAGFb,CAAI,WAELI,EAAIxB,KAAKW,iCAEJgB,EAAU3B,KAAK8B,WAAQD,cACtBF,EAAU3B,KAAKU,YAASmB,kBACpB7B,KAAK4B,mBACV5B,KAAKkC,kBAkBVH,YAAY1B,GACdL,KAAKW,UAAUD,QAEjBL,EAAEO,kBACFZ,KAAKW,UAAUD,MAAMyB,WAjJlBxC,SAAS,CAACyC,EAAgBC,GAUJC,GAA5BC,EAAS,CAAEC,SAAS,mCAKQF,GAA5BC,EAAS,CAAEC,SAAS,gCAMQF,GAA5BC,EAAS,CAAEC,SAAS,gCAMQF,GAA5BC,EAAS,CAAEC,SAAS,gCAMQF,GAA5BC,EAAS,CAAEL,KAAMO,0CAWWH,GAA5BC,EAAS,CAAEC,SAAS,kCAKuBF,GAA3CC,EAAS,CAAEC,SAAS,EAAMN,KAAMO,wCAlDd9C,KADpB+C,EAAc,gBACM/C,SAAAA"}
|
package/lib/CommandMenu.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{_ as e,n as o}from"./query-assigned-elements-37b095c4.js";import{r as t,s as n,$ as s,w as r}from"./lit-element-9646ab7e.js";import{e as i}from"./property-03f59dce.js";import{t as a}from"./state-70f38ceb.js";import{c as l,w as d}from"./number-e7cd246c.js";import{e as c,n as p}from"./ref-eb5cfa10.js";import{o as m}from"./class-map-61e9e8c1.js";import{l as h}from"./if-defined-2a4c6dbc.js";import{g as v}from"./collection-f3631dc8.js";import{N as u}from"./events-731d0007.js";import{L as f}from"./LightDismissController-cc5b4bf2.js";import{KeyboardController as b}from"./KeyboardController.js";import g from"./Icon.js";import"./VisuallyHidden.js";import"./CommandMenuAction.js";import{SelectEvent as x}from"./SelectEvent.js";import{s as y}from"./Component-6762b5eb.js";import"./directive-de55b00a.js";import"./directive-helpers-e7b6bf4b.js";import"./ShortcutController-93173ff4.js";import"./tinykeys.module-84e6cc41.js";import"./unsafe-html-4da54dd2.js";const w="keyboard-arrow-up-down";var k=Object.freeze({__proto__:null,default:'<svg viewBox="0 0 140 140" xmlns="http://www.w3.org/2000/svg"><path d="M105.833 24v93m0-93L80 49.833M105.833 24l25.834 25.833M34.167 117V24m0 93L60 91.167M34.167 117 8.333 91.167" fill="none" stroke="currentColor" stroke-width="14" stroke-linecap="round" stroke-linejoin="round"/></svg>',title:w,tags:"nordicon keyboard keys arrow up down shortcut"});var z=Object.freeze({__proto__:null,default:'<svg viewBox="0 0 140 140" xmlns="http://www.w3.org/2000/svg"><g fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="14"><path d="M35 133 7 105l28-28"/><path d="M7 105h112a14 14 0 0 0 14-14V21a14 14 0 0 0-14-14H77"/></g></svg>',title:"keyboard-return",tags:"nordicon keyboard return key shortcut"});const $="keyboard-backspace";var j=Object.freeze({__proto__:null,default:'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path fill="currentColor" fill-rule="evenodd" d="M6.707 4.879A3 3 0 0 1 8.828 4H15a3 3 0 0 1 3 3v6a3 3 0 0 1-3 3H8.828a3 3 0 0 1-2.12-.879l-4.415-4.414a1 1 0 0 1 0-1.414l4.414-4.414zm4 2.414a1 1 0 0 0-1.414 1.414L10.586 10l-1.293 1.293a1 1 0 1 0 1.414 1.414L12 11.414l1.293 1.293a1 1 0 0 0 1.414-1.414L13.414 10l1.293-1.293a1 1 0 0 0-1.414-1.414L12 8.586l-1.293-1.293z" clip-rule="evenodd"/></svg>',title:$,tags:"nordicon keyboard backspace back delete key shortcut"});function C(e){var o;return(null===(o=e.activeElement)||void 0===o?void 0:o.shadowRoot)?C(e.activeElement.shadowRoot):e.activeElement||void 0}const I=t`:host{--n-command-menu-width:640px;--n-command-menu-top:16%;--n-command-menu-height:290px}.n-modal{display:none;position:fixed;pointer-events:none;z-index:var(--n-index-modal);inset-inline-start:0;inset-block-start:0;inline-size:100%;block-size:100%;overflow:auto}.n-modal.n-visible{display:block}.n-modal-content{position:relative;pointer-events:all;inset-block-start:var(--n-command-menu-top);margin:auto;display:flex;flex-direction:column;min-inline-size:0;background:var(--n-color-surface);border-radius:var(--n-border-radius);box-shadow:var(--n-box-shadow-modal);max-inline-size:var(--n-command-menu-width);overflow:hidden}.n-bump{animation:zoom-in-zoom-out var(--n-transition-slowly)}@keyframes zoom-in-zoom-out{0%{transform:translateY(-10px) scale(.97);opacity:0}100%{transform:translateY(0) scale(1.0001);opacity:1}}.n-modal-footer{display:flex;gap:var(--n-space-s);padding:var(--n-space-s) var(--n-space-m);font-size:calc(var(--n-font-size-s) - 1px);color:var(--n-color-text-weaker)}.n-help{display:flex;align-items:center;gap:2px}.n-help+.n-help{padding-inline-start:var(--n-space-s);border-inline-start:1px solid var(--n-color-border-strong)}.n-help nord-icon{--n-icon-size:10px;color:currentColor;margin:3px 4px}.n-help.n-backspace nord-icon{--n-icon-size:12px}.n-search-wrapper{display:flex;border-block-end:1px solid var(--n-color-border)}[role=combobox]{flex:1;font-size:var(--n-font-size-l);font-weight:var(--n-font-weight);font-family:inherit;background:0 0;color:var(--n-color-text);border:none;border-radius:0;appearance:none;outline:0;margin:0;padding:var(--n-space-m)}[role=combobox]::-webkit-input-placeholder{color:var(--n-color-text-weaker);opacity:.6!important}[role=combobox]::-moz-placeholder{color:var(--n-color-text-weaker);opacity:.6!important}[role=combobox]::-ms-input-placeholder{color:var(--n-color-text-weaker);opacity:.6!important}[role=listbox]{max-block-size:var(--n-command-menu-height);overflow:auto;margin:0;padding:0}.n-group-header{line-height:var(--n-line-height);border-block-end:1px solid var(--n-color-border);padding:calc(var(--n-space-s)/ 1.4) var(--n-space-m);text-overflow:ellipsis;white-space:nowrap;overflow:hidden;font-size:var(--n-font-size-s);background:var(--n-color-surface-raised);font-weight:var(--n-font-weight-active);color:var(--n-color-text-weaker)}.n-command-empty{display:flex;flex:1;flex-direction:column;border-inline-start:2px solid transparent;align-items:flex-start;color:var(--n-color-text);border-block-end:1px solid var(--n-color-border);padding:calc(var(--n-space-m)/ 1.5) var(--n-space-m)}.n-command-empty .n-title{flex:1;margin-block-start:var(--n-space-s);margin-inline-end:calc(var(--n-space-s)/ 2);max-inline-size:100%;font-size:var(--n-font-size-m);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.n-command-empty .n-tip{flex:1;margin-block-start:var(--n-space-s);margin-block-end:var(--n-space-m);font-size:var(--n-font-size-s);color:var(--n-color-text-weaker)}`;g.registerIcon(k),g.registerIcon(z),g.registerIcon(j);let E=class extends n{constructor(){super(...arguments),this.inputRef=c(),this.listRef=c(),this.dismissController=new f(this,{isOpen:()=>this.open,onDismiss:()=>this.close()}),this.keyboardController=new b(this,{trigger:()=>this.select(),goBack:()=>this.goBack(),end:()=>this.end(),start:()=>this.start(),next:()=>this.next(),previous:()=>this.previous(),toggleOpen:()=>this.toggleOpen()}),this.open=!1,this.placeholder="Type a command or search...",this.commands=[],this.search="",this.bump=!0,this.selectedIndex=0,this.filteredCommands=[]}get selected(){return this.filteredCommands[this.selectedIndex]}show(e={}){this.open=!0,this.setParent(e.parent),this.dispatchEvent(new u("open"))}close(){var e;this.open=!1,null===(e=this.previousFocus)||void 0===e||e.focus(),this.previousFocus=void 0,this.dispatchEvent(new u("close"))}toggleOpen(){this.open?this.close():this.show()}focus(){var e;null===(e=this.inputRef.value)||void 0===e||e.focus()}willUpdate(e){e.has("commands")&&this.keyboardController.registerCommandShortcuts(),e.has("open")&&this.open&&(this.bump=!0),(e.has("search")||e.has("parent")||e.has("commands"))&&this.filterCommands()}updated(e){e.has("open")&&this.open&&(this.previousFocus=C(document),this.focus(),this.listRef.value&&(this.listRef.value.scrollTop=0))}render(){var e;const o=v(this.filteredCommands,"section"),t=0===this.filteredCommands.length?"no-results":null===(e=this.selected)||void 0===e?void 0:e.id;return s`<div class="${m({"n-visible":this.open,"n-modal":!0})}"><div @animationend="${this.handleAnimationEnd}" class="${m({"n-bump":this.bump,"n-modal-content":!0})}"><div class="n-search-wrapper"><nord-visually-hidden id="instructions">Press 'Enter' to confirm your input or 'Escape' to cancel</nord-visually-hidden><input type="text" id="search" @input="${this.handleInput}" @blur="${this.handleBlur}" ${p(this.inputRef)} placeholder="${this.placeholder}" .value="${this.search}" spellcheck="false" autocomplete="off" autocapitalize="off" aria-label="Type the name of a command to run." aria-autocomplete="list" aria-haspopup="listbox" role="combobox" aria-controls="list" aria-expanded="true" aria-activedescendant="${h(t)}" aria-describedby="instructions"></div><div class="n-modal-body"><div id="list" ${p(this.listRef)} role="listbox">${0===this.filteredCommands.length?this.renderNoResults():Array.from(o,(([e,o])=>this.renderSection(e,o)))}</div></div><slot name="footer"><div class="n-modal-footer" slot="footer"><span class="n-help"><nord-icon label="Arrow keys" name="${w}"></nord-icon>Navigate</span> <span class="n-help"><nord-icon label="Enter key" name="${"keyboard-return"}"></nord-icon>Select</span> <span class="n-help">Esc to dismiss</span> <span class="n-help n-backspace"><nord-icon label="Backspace key" name="${$}"></nord-icon>Move to parent</span></div></slot></div></div>`}renderNoResults(){return s`<div id="no-results" class="n-command-empty" role="option" aria-selected="true"><div class="n-title">No results for “${this.search}”</div><div class="n-tip">Search tips: some search terms require exact match. Try typing the entire command name, or use a different word or phrase.</div></div>`}renderSection(e,o){const t=`section-${e}`;return s`<div role="group" aria-labelledby="${h(e?t:void 0)}">${e?s`<div class="n-group-header" role="presentation" id="${h(t)}">${e}</div>`:r} ${l(o,(e=>e.id),(e=>{var o,t;return s`<nord-command-menu-action id="${e.id}" .command="${e}" ?selected="${e.id===(null===(o=this.selected)||void 0===o?void 0:o.id)}" @click="${()=>this.select(e)}" role="option" aria-selected="${h(e.id===(null===(t=this.selected)||void 0===t?void 0:t.id)||void 0)}"></nord-command-menu-action>`}))}</div>`}handleAnimationEnd(){this.bump=!1}handleBlur(){this.open&&this.focus()}handleInput(e){const o=e.target;this.setSearch(o.value)}select(e=this.selected){var o;this.commands.some((o=>o.parent===e.id))?(this.setParent(e.id),this.bump=!0,this.focus()):this.close(),this.setSearch(""),null===(o=e.handler)||void 0===o||o.call(e,this);const t=new x(e);this.dispatchEvent(t)}start(){this.selectedIndex=0}end(){this.selectedIndex=this.filteredCommands.length-1}next(){this.selectedIndex=d(this.selectedIndex+1,0,this.filteredCommands.length-1)}previous(){this.selectedIndex=d(this.selectedIndex-1,0,this.filteredCommands.length-1)}goBack(){if(!this.search&&this.parent){const e=this.commands.find((e=>e.id===this.parent));this.setParent(null==e?void 0:e.parent)}}setParent(e){this.parent=e,this.setSearch("")}setSearch(e){this.search=e,this.selectedIndex=0}filterCommands(){const e=this.search.toLocaleLowerCase().split(/\s+/);this.filteredCommands=this.commands.filter((({title:o,keywords:t="",parent:n})=>{const s=`${o} ${t}`.toLocaleLowerCase(),r=e.every((e=>s.includes(e)));return(!this.parent&&this.search||n===this.parent)&&r}))}};E.styles=[y,I],e([i({type:Boolean})],E.prototype,"open",void 0),e([i({type:String})],E.prototype,"placeholder",void 0),e([i({type:Array,attribute:!1})],E.prototype,"commands",void 0),e([a()],E.prototype,"parent",void 0),e([a()],E.prototype,"search",void 0),e([a()],E.prototype,"bump",void 0),e([a()],E.prototype,"selectedIndex",void 0),e([a()],E.prototype,"filteredCommands",void 0),E=e([o("nord-command-menu")],E);var _=E;export{_ as default};
|
|
1
|
+
import{_ as e,n as o}from"./query-assigned-elements-37b095c4.js";import{r as t,s as n,$ as s,w as r}from"./lit-element-9646ab7e.js";import{e as i}from"./property-03f59dce.js";import{t as a}from"./state-70f38ceb.js";import{c as l,w as d}from"./number-e7cd246c.js";import{e as c,n as p}from"./ref-eb5cfa10.js";import{o as m}from"./class-map-61e9e8c1.js";import{l as h}from"./if-defined-2a4c6dbc.js";import{g as v}from"./collection-f3631dc8.js";import{N as u}from"./events-731d0007.js";import{L as f}from"./LightDismissController-cc5b4bf2.js";import{KeyboardController as b}from"./KeyboardController.js";import g from"./Icon.js";import"./VisuallyHidden.js";import"./CommandMenuAction.js";import{SelectEvent as x}from"./SelectEvent.js";import{s as y}from"./Component-6762b5eb.js";import"./directive-de55b00a.js";import"./directive-helpers-e7b6bf4b.js";import"./ShortcutController-93173ff4.js";import"./tinykeys.module-84e6cc41.js";import"./unsafe-html-4da54dd2.js";const w="keyboard-arrow-up-down";var k=Object.freeze({__proto__:null,default:'<svg viewBox="0 0 140 140" xmlns="http://www.w3.org/2000/svg"><path d="M105.833 24v93m0-93L80 49.833M105.833 24l25.834 25.833M34.167 117V24m0 93L60 91.167M34.167 117 8.333 91.167" fill="none" stroke="currentColor" stroke-width="14" stroke-linecap="round" stroke-linejoin="round"/></svg>',title:w,tags:"nordicon keyboard keys arrow up down shortcut"});var z=Object.freeze({__proto__:null,default:'<svg viewBox="0 0 140 140" xmlns="http://www.w3.org/2000/svg"><g fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="14"><path d="M35 133 7 105l28-28"/><path d="M7 105h112a14 14 0 0 0 14-14V21a14 14 0 0 0-14-14H77"/></g></svg>',title:"keyboard-return",tags:"nordicon keyboard return key shortcut"});const $="keyboard-backspace";var j=Object.freeze({__proto__:null,default:'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path fill="currentColor" fill-rule="evenodd" d="M6.707 4.879A3 3 0 0 1 8.828 4H15a3 3 0 0 1 3 3v6a3 3 0 0 1-3 3H8.828a3 3 0 0 1-2.12-.879l-4.415-4.414a1 1 0 0 1 0-1.414l4.414-4.414zm4 2.414a1 1 0 0 0-1.414 1.414L10.586 10l-1.293 1.293a1 1 0 1 0 1.414 1.414L12 11.414l1.293 1.293a1 1 0 0 0 1.414-1.414L13.414 10l1.293-1.293a1 1 0 0 0-1.414-1.414L12 8.586l-1.293-1.293z" clip-rule="evenodd"/></svg>',title:$,tags:"nordicon keyboard backspace back delete key shortcut"});function C(e){var o;return(null===(o=e.activeElement)||void 0===o?void 0:o.shadowRoot)?C(e.activeElement.shadowRoot):e.activeElement||void 0}const I=t`:host{--n-command-menu-width:640px;--n-command-menu-top:16%;--n-command-menu-height:290px}.n-modal{display:none;position:fixed;pointer-events:none;z-index:var(--n-index-modal);inset-inline-start:0;inset-block-start:0;inline-size:100%;block-size:100%;overflow:auto}.n-modal.n-visible{display:block}.n-modal-content{position:relative;pointer-events:all;inset-block-start:var(--n-command-menu-top);margin:auto;display:flex;flex-direction:column;min-inline-size:0;background:var(--n-color-surface);border-radius:var(--n-border-radius);box-shadow:var(--n-box-shadow-modal);max-inline-size:var(--n-command-menu-width);overflow:hidden}.n-bump{animation:zoom-in-zoom-out var(--n-transition-slowly)}@keyframes zoom-in-zoom-out{0%{transform:translateY(-10px) scale(.97);opacity:0}100%{transform:translateY(0) scale(1.0001);opacity:1}}.n-modal-footer{display:flex;gap:var(--n-space-s);padding:var(--n-space-s) var(--n-space-m);font-size:calc(var(--n-font-size-s) - 1px);color:var(--n-color-text-weaker)}.n-help{display:flex;align-items:center;gap:2px}.n-help+.n-help{padding-inline-start:var(--n-space-s);border-inline-start:1px solid var(--n-color-border-strong)}.n-help nord-icon{--n-icon-size:10px;color:currentColor;margin:3px 4px}.n-help.n-backspace nord-icon{--n-icon-size:12px}.n-search-wrapper{display:flex;border-block-end:1px solid var(--n-color-border)}[role=combobox]{flex:1;font-size:var(--n-font-size-l);font-weight:var(--n-font-weight);font-family:inherit;background:0 0;color:var(--n-color-text);border:none;border-radius:0;appearance:none;outline:0;margin:0;padding:var(--n-space-m)}[role=combobox]::-webkit-input-placeholder{color:var(--n-color-text-weaker);opacity:.6!important}[role=combobox]::-moz-placeholder{color:var(--n-color-text-weaker);opacity:.6!important}[role=combobox]::-ms-input-placeholder{color:var(--n-color-text-weaker);opacity:.6!important}[role=listbox]{max-block-size:var(--n-command-menu-height);overflow:auto;margin:0;padding:0}.n-group-header{line-height:var(--n-line-height);border-block-end:1px solid var(--n-color-border);padding:calc(var(--n-space-s)/ 1.4) var(--n-space-m);text-overflow:ellipsis;white-space:nowrap;overflow:hidden;font-size:var(--n-font-size-s);background:var(--n-color-surface-raised);font-weight:var(--n-font-weight-active);color:var(--n-color-text-weaker)}.n-command-empty{display:flex;flex:1;flex-direction:column;border-inline-start:2px solid transparent;align-items:flex-start;color:var(--n-color-text);border-block-end:1px solid var(--n-color-border);padding:calc(var(--n-space-m)/ 1.5) var(--n-space-m)}.n-command-empty .n-title{flex:1;margin-block-start:var(--n-space-s);margin-inline-end:calc(var(--n-space-s)/ 2);max-inline-size:100%;font-size:var(--n-font-size-m);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.n-command-empty .n-tip{flex:1;margin-block-start:var(--n-space-s);margin-block-end:var(--n-space-m);font-size:var(--n-font-size-s);color:var(--n-color-text-weaker)}`;g.registerIcon(k),g.registerIcon(z),g.registerIcon(j);let E=class extends n{constructor(){super(...arguments),this.inputRef=c(),this.listRef=c(),this.dismissController=new f(this,{isOpen:()=>this.open,onDismiss:()=>this.close()}),this.keyboardController=new b(this,{trigger:()=>this.select(),goBack:()=>this.goBack(),end:()=>this.end(),start:()=>this.start(),next:()=>this.next(),previous:()=>this.previous(),toggleOpen:()=>this.toggleOpen()}),this.open=!1,this.placeholder="Type a command or search...",this.commands=[],this.search="",this.bump=!0,this.selectedIndex=0,this.filteredCommands=[]}get selected(){return this.filteredCommands[this.selectedIndex]}show(e={}){this.dispatchEvent(new u("open",{cancelable:!0}))&&(this.open=!0,this.setParent(e.parent))}close(){var e;this.open=!1,null===(e=this.previousFocus)||void 0===e||e.focus(),this.previousFocus=void 0,this.dispatchEvent(new u("close"))}toggleOpen(){this.open?this.close():this.show()}focus(){var e;null===(e=this.inputRef.value)||void 0===e||e.focus()}willUpdate(e){e.has("commands")&&this.keyboardController.registerCommandShortcuts(),e.has("open")&&this.open&&(this.bump=!0),(e.has("search")||e.has("parent")||e.has("commands"))&&this.filterCommands()}updated(e){e.has("open")&&this.open&&(this.previousFocus=C(document),this.focus(),this.listRef.value&&(this.listRef.value.scrollTop=0))}render(){var e;const o=v(this.filteredCommands,"section"),t=0===this.filteredCommands.length?"no-results":null===(e=this.selected)||void 0===e?void 0:e.id;return s`<div class="${m({"n-visible":this.open,"n-modal":!0})}"><div @animationend="${this.handleAnimationEnd}" class="${m({"n-bump":this.bump,"n-modal-content":!0})}"><div class="n-search-wrapper"><nord-visually-hidden id="instructions">Press 'Enter' to confirm your input or 'Escape' to cancel</nord-visually-hidden><input type="text" id="search" @input="${this.handleInput}" @blur="${this.handleBlur}" ${p(this.inputRef)} placeholder="${this.placeholder}" .value="${this.search}" spellcheck="false" autocomplete="off" autocapitalize="off" aria-label="Type the name of a command to run." aria-autocomplete="list" aria-haspopup="listbox" role="combobox" aria-controls="list" aria-expanded="true" aria-activedescendant="${h(t)}" aria-describedby="instructions"></div><div class="n-modal-body"><div id="list" ${p(this.listRef)} role="listbox">${0===this.filteredCommands.length?this.renderNoResults():Array.from(o,(([e,o])=>this.renderSection(e,o)))}</div></div><slot name="footer"><div class="n-modal-footer" slot="footer"><span class="n-help"><nord-icon label="Arrow keys" name="${w}"></nord-icon>Navigate</span> <span class="n-help"><nord-icon label="Enter key" name="${"keyboard-return"}"></nord-icon>Select</span> <span class="n-help">Esc to dismiss</span> <span class="n-help n-backspace"><nord-icon label="Backspace key" name="${$}"></nord-icon>Move to parent</span></div></slot></div></div>`}renderNoResults(){return s`<div id="no-results" class="n-command-empty" role="option" aria-selected="true"><div class="n-title">No results for “${this.search}”</div><div class="n-tip">Search tips: some search terms require exact match. Try typing the entire command name, or use a different word or phrase.</div></div>`}renderSection(e,o){const t=`section-${e}`;return s`<div role="group" aria-labelledby="${h(e?t:void 0)}">${e?s`<div class="n-group-header" role="presentation" id="${h(t)}">${e}</div>`:r} ${l(o,(e=>e.id),(e=>{var o,t;return s`<nord-command-menu-action id="${e.id}" .command="${e}" ?selected="${e.id===(null===(o=this.selected)||void 0===o?void 0:o.id)}" @click="${()=>this.select(e)}" role="option" aria-selected="${h(e.id===(null===(t=this.selected)||void 0===t?void 0:t.id)||void 0)}"></nord-command-menu-action>`}))}</div>`}handleAnimationEnd(){this.bump=!1}handleBlur(){this.open&&this.focus()}handleInput(e){const o=e.target;this.setSearch(o.value)}select(e=this.selected){var o;this.commands.some((o=>o.parent===e.id))?(this.setParent(e.id),this.bump=!0,this.focus()):this.close(),this.setSearch(""),null===(o=e.handler)||void 0===o||o.call(e,this);const t=new x(e);this.dispatchEvent(t)}start(){this.selectedIndex=0}end(){this.selectedIndex=this.filteredCommands.length-1}next(){this.selectedIndex=d(this.selectedIndex+1,0,this.filteredCommands.length-1)}previous(){this.selectedIndex=d(this.selectedIndex-1,0,this.filteredCommands.length-1)}goBack(){if(!this.search&&this.parent){const e=this.commands.find((e=>e.id===this.parent));this.setParent(null==e?void 0:e.parent)}}setParent(e){this.parent=e,this.setSearch("")}setSearch(e){this.search=e,this.selectedIndex=0}filterCommands(){const e=this.search.toLocaleLowerCase().split(/\s+/);this.filteredCommands=this.commands.filter((({title:o,keywords:t="",parent:n})=>{const s=`${o} ${t}`.toLocaleLowerCase(),r=e.every((e=>s.includes(e)));return(!this.parent&&this.search||n===this.parent)&&r}))}};E.styles=[y,I],e([i({type:Boolean})],E.prototype,"open",void 0),e([i({type:String})],E.prototype,"placeholder",void 0),e([i({type:Array,attribute:!1})],E.prototype,"commands",void 0),e([a()],E.prototype,"parent",void 0),e([a()],E.prototype,"search",void 0),e([a()],E.prototype,"bump",void 0),e([a()],E.prototype,"selectedIndex",void 0),e([a()],E.prototype,"filteredCommands",void 0),E=e([o("nord-command-menu")],E);var _=E;export{_ as default};
|
|
2
2
|
//# sourceMappingURL=CommandMenu.js.map
|
package/lib/CommandMenu.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CommandMenu.js","sources":["../../icons/lib/assets/keyboard-arrow-up-down.js","../../icons/lib/assets/keyboard-return.js","../../icons/lib/assets/keyboard-backspace.js","../src/common/focus.ts","../src/command-menu/CommandMenu.ts"],"sourcesContent":["export default '<svg viewBox=\"0 0 140 140\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M105.833 24v93m0-93L80 49.833M105.833 24l25.834 25.833M34.167 117V24m0 93L60 91.167M34.167 117 8.333 91.167\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"14\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/></svg>'\nexport const title = \"keyboard-arrow-up-down\"\nexport const tags = \"nordicon keyboard keys arrow up down shortcut\"\n","export default '<svg viewBox=\"0 0 140 140\" xmlns=\"http://www.w3.org/2000/svg\"><g fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"14\"><path d=\"M35 133 7 105l28-28\"/><path d=\"M7 105h112a14 14 0 0 0 14-14V21a14 14 0 0 0-14-14H77\"/></g></svg>'\nexport const title = \"keyboard-return\"\nexport const tags = \"nordicon keyboard return key shortcut\"\n","export default '<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\"><path fill=\"currentColor\" fill-rule=\"evenodd\" d=\"M6.707 4.879A3 3 0 0 1 8.828 4H15a3 3 0 0 1 3 3v6a3 3 0 0 1-3 3H8.828a3 3 0 0 1-2.12-.879l-4.415-4.414a1 1 0 0 1 0-1.414l4.414-4.414zm4 2.414a1 1 0 0 0-1.414 1.414L10.586 10l-1.293 1.293a1 1 0 1 0 1.414 1.414L12 11.414l1.293 1.293a1 1 0 0 0 1.414-1.414L13.414 10l1.293-1.293a1 1 0 0 0-1.414-1.414L12 8.586l-1.293-1.293z\" clip-rule=\"evenodd\"/></svg>'\nexport const title = \"keyboard-backspace\"\nexport const tags = \"nordicon keyboard backspace back delete key shortcut\"\n","/**\n * Gets the currently focused element, taking shadow roots into account.\n */\nexport function getFocusedElement(root: Document | ShadowRoot): Element | undefined {\n if (root.activeElement?.shadowRoot) {\n return getFocusedElement(root.activeElement.shadowRoot)\n }\n\n return root.activeElement || undefined\n}\n","import { LitElement, html, PropertyValues, nothing } from \"lit\"\nimport { customElement, property, state } from \"lit/decorators.js\"\nimport { repeat } from \"lit/directives/repeat.js\"\nimport { createRef, ref } from \"lit/directives/ref.js\"\nimport { classMap } from \"lit/directives/class-map.js\"\nimport { ifDefined } from \"lit/directives/if-defined.js\"\n\nimport * as navigateIcon from \"@nordhealth/icons/lib/assets/keyboard-arrow-up-down.js\"\nimport * as enterIcon from \"@nordhealth/icons/lib/assets/keyboard-return.js\"\nimport * as backspaceIcon from \"@nordhealth/icons/lib/assets/keyboard-backspace.js\"\n\nimport { groupBy } from \"../common/collection.js\"\nimport { wrap } from \"../common/number.js\"\nimport { NordEvent } from \"../common/events.js\"\nimport { getFocusedElement } from \"../common/focus.js\"\nimport { LightDismissController } from \"../common/controllers/LightDismissController.js\"\nimport { KeyboardController } from \"./KeyboardController.js\"\n\nimport Icon from \"../icon/Icon.js\"\nimport \"../visually-hidden/VisuallyHidden.js\"\nimport \"./CommandMenuAction.js\"\nimport { ICommandMenuAction } from \"./ICommandMenuAction.js\"\nimport { SelectEvent } from \"./SelectEvent.js\"\nimport componentStyle from \"../common/styles/Component.css\"\nimport style from \"./CommandMenu.css\"\n\nIcon.registerIcon(navigateIcon)\nIcon.registerIcon(enterIcon)\nIcon.registerIcon(backspaceIcon)\n\n/**\n * Command Menu allows users to navigate and use an app without\n * touching the mouse and helps them transform into “power users”\n * who can harness more advanced features far faster.\n *\n * @status ready\n * @category action\n * @slot footer - Used to replace the default footer contents.\n * @fires open - The command menu was opened.\n * @fires close - The command menu was closed.\n * @fires {SelectEvent} nord-select - User selected a command from the menu.\n */\n@customElement(\"nord-command-menu\")\nexport default class CommandMenu extends LitElement {\n static styles = [componentStyle, style]\n\n private inputRef = createRef<HTMLInputElement>()\n private listRef = createRef<HTMLElement>()\n private previousFocus?: HTMLElement\n\n private dismissController = new LightDismissController(this, {\n isOpen: () => this.open,\n onDismiss: () => this.close(),\n })\n\n private keyboardController = new KeyboardController(this, {\n trigger: () => this.select(),\n goBack: () => this.goBack(),\n end: () => this.end(),\n start: () => this.start(),\n next: () => this.next(),\n previous: () => this.previous(),\n toggleOpen: () => this.toggleOpen(),\n })\n\n /**\n * Show or hide the command menu.\n */\n @property({ type: Boolean }) open = false\n\n /**\n * Hint text to display in the Command Menu search field.\n */\n @property({ type: String }) placeholder = \"Type a command or search...\"\n\n /**\n * Array of commands to be included in the menu.\n * Please see “Commands data” section for more documentation.\n */\n @property({ type: Array, attribute: false }) commands: Array<ICommandMenuAction> = []\n\n @state() private parent?: string\n @state() private search: string = \"\"\n @state() private bump = true\n @state() private selectedIndex = 0\n @state() private filteredCommands: Array<ICommandMenuAction> = []\n\n private get selected(): ICommandMenuAction {\n return this.filteredCommands[this.selectedIndex]\n }\n\n /**\n * Show the command menu programmatically.\n * @param options allows you to open the menu filtered to a specific parent command.\n */\n show(options: { parent?: string } = {}) {\n this.open = true\n this.setParent(options.parent)\n\n this.dispatchEvent(new NordEvent(\"open\"))\n }\n\n /**\n * Close the command menu programmatically.\n */\n close() {\n this.open = false\n this.previousFocus?.focus()\n this.previousFocus = undefined\n\n this.dispatchEvent(new NordEvent(\"close\"))\n }\n\n /**\n * Toggle the open state programmatically.\n */\n toggleOpen() {\n if (this.open) {\n this.close()\n } else {\n this.show()\n }\n }\n\n /**\n * Focus the command menu's input.\n */\n focus() {\n this.inputRef.value?.focus()\n }\n\n override willUpdate(changedProperties: PropertyValues<this>) {\n if (changedProperties.has(\"commands\")) {\n this.keyboardController.registerCommandShortcuts()\n }\n\n if (changedProperties.has(\"open\") && this.open) {\n this.bump = true\n }\n\n if (\n // @ts-expect-error this is a private property so it errors, but it's fine here\n changedProperties.has(\"search\") ||\n // @ts-expect-error this is a private property so it errors, but it's fine here\n changedProperties.has(\"parent\") ||\n changedProperties.has(\"commands\")\n ) {\n this.filterCommands()\n }\n }\n\n override updated(changedProperties: PropertyValues<this>) {\n if (changedProperties.has(\"open\") && this.open) {\n this.previousFocus = getFocusedElement(document) as HTMLElement\n this.focus()\n\n if (this.listRef.value) {\n this.listRef.value.scrollTop = 0\n }\n }\n }\n\n override render() {\n const sections = groupBy(this.filteredCommands, \"section\")\n const activeDescendant = this.filteredCommands.length === 0 ? \"no-results\" : this.selected?.id\n\n return html`\n <div\n class=${classMap({\n \"n-visible\": this.open,\n \"n-modal\": true,\n })}\n >\n <div\n @animationend=${this.handleAnimationEnd}\n class=${classMap({\n \"n-bump\": this.bump,\n \"n-modal-content\": true,\n })}\n >\n <div class=\"n-search-wrapper\">\n <nord-visually-hidden id=\"instructions\">\n Press 'Enter' to confirm your input or 'Escape' to cancel\n </nord-visually-hidden>\n <input\n type=\"text\"\n id=\"search\"\n @input=${this.handleInput}\n @blur=${this.handleBlur}\n ${ref(this.inputRef)}\n placeholder=${this.placeholder}\n .value=${this.search}\n spellcheck=\"false\"\n autocomplete=\"off\"\n autocapitalize=\"off\"\n aria-label=\"Type the name of a command to run.\"\n aria-autocomplete=\"list\"\n aria-haspopup=\"listbox\"\n role=\"combobox\"\n aria-controls=\"list\"\n aria-expanded=\"true\"\n aria-activedescendant=${ifDefined(activeDescendant)}\n aria-describedby=\"instructions\"\n />\n </div>\n\n <div class=\"n-modal-body\">\n <div id=\"list\" ${ref(this.listRef)} role=\"listbox\">\n ${this.filteredCommands.length === 0\n ? this.renderNoResults()\n : Array.from(sections, ([section, commands]) => this.renderSection(section, commands))}\n </div>\n </div>\n <slot name=\"footer\">\n <div class=\"n-modal-footer\" slot=\"footer\">\n <span class=\"n-help\"><nord-icon label=\"Arrow keys\" name=${navigateIcon.title}></nord-icon> Navigate</span>\n <span class=\"n-help\"><nord-icon label=\"Enter key\" name=${enterIcon.title}></nord-icon> Select</span>\n <span class=\"n-help\">Esc to dismiss</span>\n <span class=\"n-help n-backspace\"\n ><nord-icon label=\"Backspace key\" name=${backspaceIcon.title}></nord-icon> Move to parent</span\n >\n </div>\n </slot>\n </div>\n </div>\n `\n }\n\n private renderNoResults() {\n return html`\n <div id=\"no-results\" class=\"n-command-empty\" role=\"option\" aria-selected=\"true\">\n <div class=\"n-title\">No results for “${this.search}”</div>\n <div class=\"n-tip\">\n Search tips: some search terms require exact match. Try typing the entire command name, or use\n a different word or phrase.\n </div>\n </div>\n `\n }\n\n private renderSection(section: string | undefined, commands: ICommandMenuAction[]) {\n const sectionId = `section-${section}`\n\n // TODO: test on latest safari, since it seems to have issues with grouped options\n return html`\n <div role=\"group\" aria-labelledby=${ifDefined(section ? sectionId : undefined)}>\n ${section\n ? html`<div class=\"n-group-header\" role=\"presentation\" id=${ifDefined(sectionId)}>${section}</div>`\n : nothing}\n ${repeat(\n commands,\n command => command.id,\n command => html`\n <nord-command-menu-action\n id=${command.id}\n .command=${command}\n ?selected=${command.id === this.selected?.id}\n @click=${() => this.select(command)}\n role=\"option\"\n aria-selected=${ifDefined(command.id === this.selected?.id || undefined)}\n ></nord-command-menu-action>\n `\n )}\n </div>\n `\n }\n\n private handleAnimationEnd() {\n this.bump = false\n }\n\n private handleBlur() {\n if (this.open) {\n this.focus()\n }\n }\n\n private handleInput(event: KeyboardEvent) {\n const input = event.target as HTMLInputElement\n this.setSearch(input.value)\n }\n\n private select(command: ICommandMenuAction = this.selected) {\n const isParent = this.commands.some(item => item.parent === command.id)\n\n if (isParent) {\n this.setParent(command.id)\n this.bump = true\n this.focus()\n } else {\n this.close()\n }\n\n this.setSearch(\"\")\n command.handler?.(this)\n\n // this is separated into two parts because of a bug in Custom Elements Analyzer, where it gets the event name wrong.\n // TODO: cleanup when bug is fixed.\n const event = new SelectEvent(command)\n this.dispatchEvent(event)\n }\n\n private start() {\n this.selectedIndex = 0\n }\n\n private end() {\n this.selectedIndex = this.filteredCommands.length - 1\n }\n\n private next() {\n this.selectedIndex = wrap(this.selectedIndex + 1, 0, this.filteredCommands.length - 1)\n }\n\n private previous() {\n this.selectedIndex = wrap(this.selectedIndex - 1, 0, this.filteredCommands.length - 1)\n }\n\n private goBack() {\n if (this.search) {\n return\n }\n\n if (this.parent) {\n const parentCommand = this.commands.find(command => command.id === this.parent)\n this.setParent(parentCommand?.parent)\n }\n }\n\n private setParent(parent?: string) {\n this.parent = parent\n this.setSearch(\"\")\n }\n\n private setSearch(str: string) {\n this.search = str\n this.selectedIndex = 0\n }\n\n private filterCommands() {\n const searchTerms = this.search.toLocaleLowerCase().split(/\\s+/)\n\n this.filteredCommands = this.commands.filter(({ title, keywords = \"\", parent }) => {\n const searchSpace = `${title} ${keywords}`.toLocaleLowerCase()\n const matcher = searchTerms.every(term => searchSpace.includes(term))\n\n if (!this.parent && this.search) {\n // global search for items on root\n return matcher\n }\n\n return parent === this.parent && matcher\n })\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"nord-command-menu\": CommandMenu\n }\n}\n"],"names":["title","getFocusedElement","root","activeElement","shadowRoot","undefined","Icon","registerIcon","navigateIcon","enterIcon","backspaceIcon","CommandMenu","LitElement","constructor","this","createRef","LightDismissController","isOpen","open","onDismiss","close","KeyboardController","trigger","select","goBack","end","start","next","previous","toggleOpen","selected","filteredCommands","selectedIndex","show","options","setParent","parent","dispatchEvent","NordEvent","previousFocus","focus","inputRef","value","willUpdate","changedProperties","has","keyboardController","registerCommandShortcuts","bump","filterCommands","updated","document","listRef","scrollTop","render","sections","groupBy","activeDescendant","length","id","html","classMap","handleAnimationEnd","handleInput","handleBlur","ref","placeholder","search","ifDefined","renderNoResults","Array","from","section","commands","renderSection","navigateIcon.title","backspaceIcon.title","sectionId","nothing","repeat","command","event","input","target","setSearch","some","item","handler","SelectEvent","wrap","parentCommand","find","str","searchTerms","toLocaleLowerCase","split","filter","keywords","searchSpace","matcher","every","term","includes","componentStyle","style","__decorate","property","type","Boolean","String","attribute","state","customElement"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"CommandMenu.js","sources":["../../icons/lib/assets/keyboard-arrow-up-down.js","../../icons/lib/assets/keyboard-return.js","../../icons/lib/assets/keyboard-backspace.js","../src/common/focus.ts","../src/command-menu/CommandMenu.ts"],"sourcesContent":["export default '<svg viewBox=\"0 0 140 140\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M105.833 24v93m0-93L80 49.833M105.833 24l25.834 25.833M34.167 117V24m0 93L60 91.167M34.167 117 8.333 91.167\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"14\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/></svg>'\nexport const title = \"keyboard-arrow-up-down\"\nexport const tags = \"nordicon keyboard keys arrow up down shortcut\"\n","export default '<svg viewBox=\"0 0 140 140\" xmlns=\"http://www.w3.org/2000/svg\"><g fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"14\"><path d=\"M35 133 7 105l28-28\"/><path d=\"M7 105h112a14 14 0 0 0 14-14V21a14 14 0 0 0-14-14H77\"/></g></svg>'\nexport const title = \"keyboard-return\"\nexport const tags = \"nordicon keyboard return key shortcut\"\n","export default '<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\"><path fill=\"currentColor\" fill-rule=\"evenodd\" d=\"M6.707 4.879A3 3 0 0 1 8.828 4H15a3 3 0 0 1 3 3v6a3 3 0 0 1-3 3H8.828a3 3 0 0 1-2.12-.879l-4.415-4.414a1 1 0 0 1 0-1.414l4.414-4.414zm4 2.414a1 1 0 0 0-1.414 1.414L10.586 10l-1.293 1.293a1 1 0 1 0 1.414 1.414L12 11.414l1.293 1.293a1 1 0 0 0 1.414-1.414L13.414 10l1.293-1.293a1 1 0 0 0-1.414-1.414L12 8.586l-1.293-1.293z\" clip-rule=\"evenodd\"/></svg>'\nexport const title = \"keyboard-backspace\"\nexport const tags = \"nordicon keyboard backspace back delete key shortcut\"\n","/**\n * Gets the currently focused element, taking shadow roots into account.\n */\nexport function getFocusedElement(root: Document | ShadowRoot): Element | undefined {\n if (root.activeElement?.shadowRoot) {\n return getFocusedElement(root.activeElement.shadowRoot)\n }\n\n return root.activeElement || undefined\n}\n","import { LitElement, html, PropertyValues, nothing } from \"lit\"\nimport { customElement, property, state } from \"lit/decorators.js\"\nimport { repeat } from \"lit/directives/repeat.js\"\nimport { createRef, ref } from \"lit/directives/ref.js\"\nimport { classMap } from \"lit/directives/class-map.js\"\nimport { ifDefined } from \"lit/directives/if-defined.js\"\n\nimport * as navigateIcon from \"@nordhealth/icons/lib/assets/keyboard-arrow-up-down.js\"\nimport * as enterIcon from \"@nordhealth/icons/lib/assets/keyboard-return.js\"\nimport * as backspaceIcon from \"@nordhealth/icons/lib/assets/keyboard-backspace.js\"\n\nimport { groupBy } from \"../common/collection.js\"\nimport { wrap } from \"../common/number.js\"\nimport { NordEvent } from \"../common/events.js\"\nimport { getFocusedElement } from \"../common/focus.js\"\nimport { LightDismissController } from \"../common/controllers/LightDismissController.js\"\nimport { KeyboardController } from \"./KeyboardController.js\"\n\nimport Icon from \"../icon/Icon.js\"\nimport \"../visually-hidden/VisuallyHidden.js\"\nimport \"./CommandMenuAction.js\"\nimport { ICommandMenuAction } from \"./ICommandMenuAction.js\"\nimport { SelectEvent } from \"./SelectEvent.js\"\nimport componentStyle from \"../common/styles/Component.css\"\nimport style from \"./CommandMenu.css\"\n\nIcon.registerIcon(navigateIcon)\nIcon.registerIcon(enterIcon)\nIcon.registerIcon(backspaceIcon)\n\n/**\n * Command Menu allows users to navigate and use an app without\n * touching the mouse and helps them transform into “power users”\n * who can harness more advanced features far faster.\n *\n * @status ready\n * @category action\n * @slot footer - Used to replace the default footer contents.\n * @fires open - The command menu was opened.\n * @fires close - The command menu was closed.\n * @fires {SelectEvent} nord-select - User selected a command from the menu.\n */\n@customElement(\"nord-command-menu\")\nexport default class CommandMenu extends LitElement {\n static styles = [componentStyle, style]\n\n private inputRef = createRef<HTMLInputElement>()\n private listRef = createRef<HTMLElement>()\n private previousFocus?: HTMLElement\n\n private dismissController = new LightDismissController(this, {\n isOpen: () => this.open,\n onDismiss: () => this.close(),\n })\n\n private keyboardController = new KeyboardController(this, {\n trigger: () => this.select(),\n goBack: () => this.goBack(),\n end: () => this.end(),\n start: () => this.start(),\n next: () => this.next(),\n previous: () => this.previous(),\n toggleOpen: () => this.toggleOpen(),\n })\n\n /**\n * Show or hide the command menu.\n */\n @property({ type: Boolean }) open = false\n\n /**\n * Hint text to display in the Command Menu search field.\n */\n @property({ type: String }) placeholder = \"Type a command or search...\"\n\n /**\n * Array of commands to be included in the menu.\n * Please see “Commands data” section for more documentation.\n */\n @property({ type: Array, attribute: false }) commands: Array<ICommandMenuAction> = []\n\n @state() private parent?: string\n @state() private search: string = \"\"\n @state() private bump = true\n @state() private selectedIndex = 0\n @state() private filteredCommands: Array<ICommandMenuAction> = []\n\n private get selected(): ICommandMenuAction {\n return this.filteredCommands[this.selectedIndex]\n }\n\n /**\n * Show the command menu programmatically.\n * @param options allows you to open the menu filtered to a specific parent command.\n */\n show(options: { parent?: string } = {}) {\n const notCancelled = this.dispatchEvent(new NordEvent(\"open\", { cancelable: true }))\n\n if (notCancelled) {\n this.open = true\n this.setParent(options.parent)\n }\n }\n\n /**\n * Close the command menu programmatically.\n */\n close() {\n this.open = false\n this.previousFocus?.focus()\n this.previousFocus = undefined\n\n this.dispatchEvent(new NordEvent(\"close\"))\n }\n\n /**\n * Toggle the open state programmatically.\n */\n toggleOpen() {\n if (this.open) {\n this.close()\n } else {\n this.show()\n }\n }\n\n /**\n * Focus the command menu's input.\n */\n focus() {\n this.inputRef.value?.focus()\n }\n\n override willUpdate(changedProperties: PropertyValues<this>) {\n if (changedProperties.has(\"commands\")) {\n this.keyboardController.registerCommandShortcuts()\n }\n\n if (changedProperties.has(\"open\") && this.open) {\n this.bump = true\n }\n\n if (\n // @ts-expect-error this is a private property so it errors, but it's fine here\n changedProperties.has(\"search\") ||\n // @ts-expect-error this is a private property so it errors, but it's fine here\n changedProperties.has(\"parent\") ||\n changedProperties.has(\"commands\")\n ) {\n this.filterCommands()\n }\n }\n\n override updated(changedProperties: PropertyValues<this>) {\n if (changedProperties.has(\"open\") && this.open) {\n this.previousFocus = getFocusedElement(document) as HTMLElement\n this.focus()\n\n if (this.listRef.value) {\n this.listRef.value.scrollTop = 0\n }\n }\n }\n\n override render() {\n const sections = groupBy(this.filteredCommands, \"section\")\n const activeDescendant = this.filteredCommands.length === 0 ? \"no-results\" : this.selected?.id\n\n return html`\n <div\n class=${classMap({\n \"n-visible\": this.open,\n \"n-modal\": true,\n })}\n >\n <div\n @animationend=${this.handleAnimationEnd}\n class=${classMap({\n \"n-bump\": this.bump,\n \"n-modal-content\": true,\n })}\n >\n <div class=\"n-search-wrapper\">\n <nord-visually-hidden id=\"instructions\">\n Press 'Enter' to confirm your input or 'Escape' to cancel\n </nord-visually-hidden>\n <input\n type=\"text\"\n id=\"search\"\n @input=${this.handleInput}\n @blur=${this.handleBlur}\n ${ref(this.inputRef)}\n placeholder=${this.placeholder}\n .value=${this.search}\n spellcheck=\"false\"\n autocomplete=\"off\"\n autocapitalize=\"off\"\n aria-label=\"Type the name of a command to run.\"\n aria-autocomplete=\"list\"\n aria-haspopup=\"listbox\"\n role=\"combobox\"\n aria-controls=\"list\"\n aria-expanded=\"true\"\n aria-activedescendant=${ifDefined(activeDescendant)}\n aria-describedby=\"instructions\"\n />\n </div>\n\n <div class=\"n-modal-body\">\n <div id=\"list\" ${ref(this.listRef)} role=\"listbox\">\n ${this.filteredCommands.length === 0\n ? this.renderNoResults()\n : Array.from(sections, ([section, commands]) => this.renderSection(section, commands))}\n </div>\n </div>\n <slot name=\"footer\">\n <div class=\"n-modal-footer\" slot=\"footer\">\n <span class=\"n-help\"><nord-icon label=\"Arrow keys\" name=${navigateIcon.title}></nord-icon> Navigate</span>\n <span class=\"n-help\"><nord-icon label=\"Enter key\" name=${enterIcon.title}></nord-icon> Select</span>\n <span class=\"n-help\">Esc to dismiss</span>\n <span class=\"n-help n-backspace\"\n ><nord-icon label=\"Backspace key\" name=${backspaceIcon.title}></nord-icon> Move to parent</span\n >\n </div>\n </slot>\n </div>\n </div>\n `\n }\n\n private renderNoResults() {\n return html`\n <div id=\"no-results\" class=\"n-command-empty\" role=\"option\" aria-selected=\"true\">\n <div class=\"n-title\">No results for “${this.search}”</div>\n <div class=\"n-tip\">\n Search tips: some search terms require exact match. Try typing the entire command name, or use\n a different word or phrase.\n </div>\n </div>\n `\n }\n\n private renderSection(section: string | undefined, commands: ICommandMenuAction[]) {\n const sectionId = `section-${section}`\n\n // TODO: test on latest safari, since it seems to have issues with grouped options\n return html`\n <div role=\"group\" aria-labelledby=${ifDefined(section ? sectionId : undefined)}>\n ${section\n ? html`<div class=\"n-group-header\" role=\"presentation\" id=${ifDefined(sectionId)}>${section}</div>`\n : nothing}\n ${repeat(\n commands,\n command => command.id,\n command => html`\n <nord-command-menu-action\n id=${command.id}\n .command=${command}\n ?selected=${command.id === this.selected?.id}\n @click=${() => this.select(command)}\n role=\"option\"\n aria-selected=${ifDefined(command.id === this.selected?.id || undefined)}\n ></nord-command-menu-action>\n `\n )}\n </div>\n `\n }\n\n private handleAnimationEnd() {\n this.bump = false\n }\n\n private handleBlur() {\n if (this.open) {\n this.focus()\n }\n }\n\n private handleInput(event: KeyboardEvent) {\n const input = event.target as HTMLInputElement\n this.setSearch(input.value)\n }\n\n private select(command: ICommandMenuAction = this.selected) {\n const isParent = this.commands.some(item => item.parent === command.id)\n\n if (isParent) {\n this.setParent(command.id)\n this.bump = true\n this.focus()\n } else {\n this.close()\n }\n\n this.setSearch(\"\")\n command.handler?.(this)\n\n // this is separated into two parts because of a bug in Custom Elements Analyzer, where it gets the event name wrong.\n // TODO: cleanup when bug is fixed.\n const event = new SelectEvent(command)\n this.dispatchEvent(event)\n }\n\n private start() {\n this.selectedIndex = 0\n }\n\n private end() {\n this.selectedIndex = this.filteredCommands.length - 1\n }\n\n private next() {\n this.selectedIndex = wrap(this.selectedIndex + 1, 0, this.filteredCommands.length - 1)\n }\n\n private previous() {\n this.selectedIndex = wrap(this.selectedIndex - 1, 0, this.filteredCommands.length - 1)\n }\n\n private goBack() {\n if (this.search) {\n return\n }\n\n if (this.parent) {\n const parentCommand = this.commands.find(command => command.id === this.parent)\n this.setParent(parentCommand?.parent)\n }\n }\n\n private setParent(parent?: string) {\n this.parent = parent\n this.setSearch(\"\")\n }\n\n private setSearch(str: string) {\n this.search = str\n this.selectedIndex = 0\n }\n\n private filterCommands() {\n const searchTerms = this.search.toLocaleLowerCase().split(/\\s+/)\n\n this.filteredCommands = this.commands.filter(({ title, keywords = \"\", parent }) => {\n const searchSpace = `${title} ${keywords}`.toLocaleLowerCase()\n const matcher = searchTerms.every(term => searchSpace.includes(term))\n\n if (!this.parent && this.search) {\n // global search for items on root\n return matcher\n }\n\n return parent === this.parent && matcher\n })\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"nord-command-menu\": CommandMenu\n }\n}\n"],"names":["title","getFocusedElement","root","activeElement","shadowRoot","undefined","Icon","registerIcon","navigateIcon","enterIcon","backspaceIcon","CommandMenu","LitElement","constructor","this","createRef","LightDismissController","isOpen","open","onDismiss","close","KeyboardController","trigger","select","goBack","end","start","next","previous","toggleOpen","selected","filteredCommands","selectedIndex","show","options","dispatchEvent","NordEvent","cancelable","setParent","parent","previousFocus","focus","inputRef","value","willUpdate","changedProperties","has","keyboardController","registerCommandShortcuts","bump","filterCommands","updated","document","listRef","scrollTop","render","sections","groupBy","activeDescendant","length","id","html","classMap","handleAnimationEnd","handleInput","handleBlur","ref","placeholder","search","ifDefined","renderNoResults","Array","from","section","commands","renderSection","navigateIcon.title","backspaceIcon.title","sectionId","nothing","repeat","command","event","input","target","setSearch","some","item","handler","SelectEvent","wrap","parentCommand","find","str","searchTerms","toLocaleLowerCase","split","filter","keywords","searchSpace","matcher","every","term","includes","componentStyle","style","__decorate","property","type","Boolean","String","attribute","state","customElement"],"mappings":"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"}
|