@fristil/designsystem 0.4.0 → 0.5.1
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/CHANGELOG.md +136 -0
- package/README.md +22 -7
- package/dist/components/frittstaende/connection-status/connection-status.d.ts +28 -0
- package/dist/components/frittstaende/connection-status/connection-status.d.ts.map +1 -0
- package/dist/components/frittstaende/connection-status/connection-status.js +22 -0
- package/dist/components/frittstaende/connection-status/connection-status.js.map +1 -0
- package/dist/components/frittstaende/connection-status/fs-connection-status.d.ts +54 -0
- package/dist/components/frittstaende/connection-status/fs-connection-status.d.ts.map +1 -0
- package/dist/components/frittstaende/connection-status/fs-connection-status.js +123 -0
- package/dist/components/frittstaende/connection-status/fs-connection-status.js.map +1 -0
- package/dist/components/frittstaende/session-timeout/fs-session-timeout.d.ts +56 -0
- package/dist/components/frittstaende/session-timeout/fs-session-timeout.d.ts.map +1 -0
- package/dist/components/frittstaende/session-timeout/fs-session-timeout.js +183 -0
- package/dist/components/frittstaende/session-timeout/fs-session-timeout.js.map +1 -0
- package/dist/components/frittstaende/session-timeout/session-timeout.d.ts +28 -0
- package/dist/components/frittstaende/session-timeout/session-timeout.d.ts.map +1 -0
- package/dist/components/frittstaende/session-timeout/session-timeout.js +22 -0
- package/dist/components/frittstaende/session-timeout/session-timeout.js.map +1 -0
- package/dist/components/frittstaende/toast/fs-toast.d.ts +16 -22
- package/dist/components/frittstaende/toast/fs-toast.d.ts.map +1 -1
- package/dist/components/frittstaende/toast/fs-toast.js +38 -27
- package/dist/components/frittstaende/toast/fs-toast.js.map +1 -1
- package/dist/components/frittstaende/toast/toast.d.ts +34 -0
- package/dist/components/frittstaende/toast/toast.d.ts.map +1 -0
- package/dist/components/frittstaende/toast/toast.js +26 -0
- package/dist/components/frittstaende/toast/toast.js.map +1 -0
- package/dist/components/ramme/error-summary/error-summary.d.ts +39 -0
- package/dist/components/ramme/error-summary/error-summary.d.ts.map +1 -0
- package/dist/components/ramme/error-summary/error-summary.js +31 -0
- package/dist/components/ramme/error-summary/error-summary.js.map +1 -0
- package/dist/components/ramme/error-summary/fs-error-summary.d.ts +16 -42
- package/dist/components/ramme/error-summary/fs-error-summary.d.ts.map +1 -1
- package/dist/components/ramme/error-summary/fs-error-summary.js +57 -92
- package/dist/components/ramme/error-summary/fs-error-summary.js.map +1 -1
- package/dist/components/ramme/field/field-core.d.ts +37 -0
- package/dist/components/ramme/field/field-core.d.ts.map +1 -1
- package/dist/components/ramme/field/field-core.js +37 -0
- package/dist/components/ramme/field/field-core.js.map +1 -1
- package/dist/components/ramme/field/fs-field.d.ts +39 -40
- package/dist/components/ramme/field/fs-field.d.ts.map +1 -1
- package/dist/components/ramme/field/fs-field.js +128 -54
- package/dist/components/ramme/field/fs-field.js.map +1 -1
- package/dist/components/ramme/popover/fs-popover.d.ts +20 -27
- package/dist/components/ramme/popover/fs-popover.d.ts.map +1 -1
- package/dist/components/ramme/popover/fs-popover.js +68 -54
- package/dist/components/ramme/popover/fs-popover.js.map +1 -1
- package/dist/components/ramme/popover/popover.d.ts +43 -0
- package/dist/components/ramme/popover/popover.d.ts.map +1 -0
- package/dist/components/ramme/popover/popover.js +49 -0
- package/dist/components/ramme/popover/popover.js.map +1 -0
- package/dist/components/ramme/suggestion/fs-suggestion.d.ts +75 -0
- package/dist/components/ramme/suggestion/fs-suggestion.d.ts.map +1 -0
- package/dist/components/ramme/suggestion/fs-suggestion.js +232 -0
- package/dist/components/ramme/suggestion/fs-suggestion.js.map +1 -0
- package/dist/components/ramme/suggestion/suggestion.d.ts +97 -0
- package/dist/components/ramme/suggestion/suggestion.d.ts.map +1 -0
- package/dist/components/ramme/suggestion/suggestion.js +79 -0
- package/dist/components/ramme/suggestion/suggestion.js.map +1 -0
- package/dist/components/ramme/tabs/fs-tabs.d.ts +31 -36
- package/dist/components/ramme/tabs/fs-tabs.d.ts.map +1 -1
- package/dist/components/ramme/tabs/fs-tabs.js +62 -84
- package/dist/components/ramme/tabs/fs-tabs.js.map +1 -1
- package/dist/components/ramme/tabs/tabs.d.ts +50 -0
- package/dist/components/ramme/tabs/tabs.d.ts.map +1 -0
- package/dist/components/ramme/tabs/tabs.js +54 -0
- package/dist/components/ramme/tabs/tabs.js.map +1 -0
- package/dist/fs.d.ts +94 -0
- package/dist/fs.d.ts.map +1 -1
- package/dist/fs.js +42 -0
- package/dist/fs.js.map +1 -1
- package/dist/index.d.ts +10 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10 -3
- package/dist/index.js.map +1 -1
- package/dist/jsx/react.d.ts +35 -50
- package/dist/jsx/react.d.ts.map +1 -1
- package/dist/react.d.ts +142 -1
- package/dist/react.d.ts.map +1 -1
- package/dist/react.js +77 -2
- package/dist/react.js.map +1 -1
- package/package.json +15 -18
- package/src/components/frittstaende/connection-status/connection-status.css +33 -0
- package/src/components/frittstaende/connection-status/connection-status.ts +41 -0
- package/src/components/frittstaende/connection-status/fs-connection-status.ts +144 -0
- package/src/components/frittstaende/session-timeout/fs-session-timeout.ts +216 -0
- package/src/components/frittstaende/session-timeout/session-timeout.css +43 -0
- package/src/components/frittstaende/session-timeout/session-timeout.ts +42 -0
- package/src/components/frittstaende/toast/fs-toast.ts +39 -30
- package/src/components/frittstaende/toast/toast.ts +45 -0
- package/src/components/ramme/error-summary/error-summary.ts +55 -0
- package/src/components/ramme/error-summary/fs-error-summary.ts +62 -119
- package/src/components/ramme/field/field-core.ts +38 -0
- package/src/components/ramme/field/fs-field.ts +145 -61
- package/src/components/ramme/popover/fs-popover.ts +78 -72
- package/src/components/ramme/popover/popover.ts +79 -0
- package/src/components/ramme/suggestion/fs-suggestion.ts +265 -0
- package/src/components/ramme/suggestion/suggestion.ts +105 -0
- package/src/components/ramme/tabs/fs-tabs.ts +67 -98
- package/src/components/ramme/tabs/tabs.ts +104 -0
- package/dist/components/frittstaende/calendar/fs-calendar.d.ts +0 -52
- package/dist/components/frittstaende/calendar/fs-calendar.d.ts.map +0 -1
- package/dist/components/frittstaende/calendar/fs-calendar.js +0 -462
- package/dist/components/frittstaende/calendar/fs-calendar.js.map +0 -1
- package/dist/components/frittstaende/date-field/fs-date-field.d.ts +0 -110
- package/dist/components/frittstaende/date-field/fs-date-field.d.ts.map +0 -1
- package/dist/components/frittstaende/date-field/fs-date-field.js +0 -264
- package/dist/components/frittstaende/date-field/fs-date-field.js.map +0 -1
- package/dist/components/frittstaende/suggestion/fs-suggestion.d.ts +0 -133
- package/dist/components/frittstaende/suggestion/fs-suggestion.d.ts.map +0 -1
- package/dist/components/frittstaende/suggestion/fs-suggestion.js +0 -280
- package/dist/components/frittstaende/suggestion/fs-suggestion.js.map +0 -1
- package/src/components/frittstaende/calendar/fs-calendar.ts +0 -525
- package/src/components/frittstaende/date-field/date-field.css +0 -54
- package/src/components/frittstaende/date-field/fs-date-field.ts +0 -309
- package/src/components/frittstaende/suggestion/fs-suggestion.ts +0 -333
- /package/src/components/{frittstaende → ramme}/suggestion/suggestion.css +0 -0
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { attributes } from "../../css/shared.js";
|
|
2
|
+
export const POPOVER_CLASS = "fs-popover";
|
|
3
|
+
/**
|
|
4
|
+
* Attributtene for et sprettoppvindu.
|
|
5
|
+
*
|
|
6
|
+
* Serveren skriver både knappen og panelet med koblingen mellom dem.
|
|
7
|
+
* `<fs-popover>` regner ut posisjonen og lukker ved klikk utenfor.
|
|
8
|
+
*
|
|
9
|
+
* ```ts
|
|
10
|
+
* const boks = fs.popover({ id: "hjelp" })
|
|
11
|
+
* ```
|
|
12
|
+
* ```html
|
|
13
|
+
* <fs-popover>
|
|
14
|
+
* <button {...boks.trigger}>Hva betyr dette?</button>
|
|
15
|
+
* <div {...boks.panel}>Vi bruker fødselsdatoen til å finne riktig sats.</div>
|
|
16
|
+
* </fs-popover>
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
export const popover = ({ id, open = false, }) => ({
|
|
20
|
+
// Om panelet er åpent står som `open` på verten, og det er brukerens
|
|
21
|
+
// tilstand, ikke serverens. Uten dette lukker morfingen panelet i det
|
|
22
|
+
// serveren patcher området rundt.
|
|
23
|
+
host: attributes({
|
|
24
|
+
// `open` må stå på verten, ikke bare i knappens aria-expanded. Uten det
|
|
25
|
+
// sa markupen at panelet var åpent mens komponenten mente det var lukket.
|
|
26
|
+
open: open ? "" : undefined,
|
|
27
|
+
"data-preserve-attr": "open",
|
|
28
|
+
}),
|
|
29
|
+
trigger: attributes({
|
|
30
|
+
slot: "trigger",
|
|
31
|
+
"aria-expanded": (open ? "true" : "false"),
|
|
32
|
+
"aria-controls": id,
|
|
33
|
+
// Komponenten endrer aria-expanded når panelet åpnes. Uten dette fjerner
|
|
34
|
+
// Datastars morfing det igjen, siden serverens utgave sier noe annet.
|
|
35
|
+
"data-preserve-attr": "aria-expanded",
|
|
36
|
+
}),
|
|
37
|
+
panel: attributes({
|
|
38
|
+
class: POPOVER_CLASS,
|
|
39
|
+
id,
|
|
40
|
+
// `manual` og ikke `auto`: komponenten lukker selv, slik at knappen kan
|
|
41
|
+
// brukes til å lukke igjen uten at nettleseren rekker å lukke først.
|
|
42
|
+
popover: "manual",
|
|
43
|
+
// Posisjonen regnes ut mot knappens plass på skjermen og settes som
|
|
44
|
+
// `--fs-popover-top` og `--fs-popover-left` i style-attributtet. Uten
|
|
45
|
+
// dette river morfingen posisjonen bort, og panelet hopper til hjørnet.
|
|
46
|
+
"data-preserve-attr": "style",
|
|
47
|
+
}),
|
|
48
|
+
});
|
|
49
|
+
//# sourceMappingURL=popover.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"popover.js","sourceRoot":"","sources":["../../../../src/components/ramme/popover/popover.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAA;AAEhD,MAAM,CAAC,MAAM,aAAa,GAAG,YAAqB,CAAA;AA4BlD;;;;;;;;;;;;;;;GAeG;AACH,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC,EACtB,EAAE,EACF,IAAI,GAAG,KAAK,GACG,EAAqB,EAAE,CAAC,CAAC;IACxC,qEAAqE;IACrE,sEAAsE;IACtE,kCAAkC;IAClC,IAAI,EAAE,UAAU,CAAC;QACf,wEAAwE;QACxE,0EAA0E;QAC1E,IAAI,EAAE,IAAI,CAAC,CAAC,CAAE,EAAY,CAAC,CAAC,CAAC,SAAS;QACtC,oBAAoB,EAAE,MAAe;KACtC,CAAC;IACF,OAAO,EAAE,UAAU,CAAC;QAClB,IAAI,EAAE,SAAkB;QACxB,eAAe,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAqB;QAC9D,eAAe,EAAE,EAAE;QACnB,yEAAyE;QACzE,sEAAsE;QACtE,oBAAoB,EAAE,eAAwB;KAC/C,CAAC;IACF,KAAK,EAAE,UAAU,CAAC;QAChB,KAAK,EAAE,aAAa;QACpB,EAAE;QACF,wEAAwE;QACxE,qEAAqE;QACrE,OAAO,EAAE,QAAiB;QAC1B,oEAAoE;QACpE,sEAAsE;QACtE,wEAAwE;QACxE,oBAAoB,EAAE,OAAgB;KACvC,CAAC;CACH,CAAC,CAAA"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
export declare const FS_SUGGESTION_TAG: "fs-suggestion";
|
|
2
|
+
/**
|
|
3
|
+
* Tastaturet og filtreringen i et felt med forslagsliste.
|
|
4
|
+
*
|
|
5
|
+
* Serveren skriver feltet og lista med `fs.suggestion()`. Komponenten rendrer
|
|
6
|
+
* ingenting. Den lagde tidligere hele feltet selv, og da fantes det verken
|
|
7
|
+
* ledetekst eller inndatafelt før skriptet hadde kjørt, og ingenting ble med
|
|
8
|
+
* i innsendingen.
|
|
9
|
+
*
|
|
10
|
+
* Det komponenten gjør er det nettleseren ikke gjør: filtrerer alternativene
|
|
11
|
+
* mens brukeren skriver, flytter markeringen med piltastene, og holder
|
|
12
|
+
* `aria-activedescendant` i synk slik at skjermleseren leser opp alternativet
|
|
13
|
+
* uten at fokus forlater feltet.
|
|
14
|
+
*
|
|
15
|
+
* Patcher serveren lista selv, som i en Datastar-app, slår filtreringen seg
|
|
16
|
+
* av: da er det serveren som bestemmer hva som vises.
|
|
17
|
+
*
|
|
18
|
+
* ```html
|
|
19
|
+
* <fs-suggestion>
|
|
20
|
+
* <label class="fs-label" for="kommune">Kommune</label>
|
|
21
|
+
* <div class="fs-suggestion__field">
|
|
22
|
+
* <input class="fs-input" id="kommune" role="combobox" aria-controls="kommune-list"
|
|
23
|
+
* aria-expanded="false" data-preserve-attr="aria-expanded aria-activedescendant">
|
|
24
|
+
* <ul class="fs-suggestion__list" id="kommune-list" role="listbox" hidden
|
|
25
|
+
* data-preserve-attr="hidden">
|
|
26
|
+
* <li class="fs-suggestion__option" id="kommune-option-0" role="option">Bergen</li>
|
|
27
|
+
* </ul>
|
|
28
|
+
* </div>
|
|
29
|
+
* </fs-suggestion>
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
export declare class FsSuggestion extends HTMLElement {
|
|
33
|
+
static observedAttributes: string[];
|
|
34
|
+
private activeIndex;
|
|
35
|
+
private observer?;
|
|
36
|
+
private control?;
|
|
37
|
+
/** Alternativene som alt har fått lytteren sin. */
|
|
38
|
+
private readonly bundne;
|
|
39
|
+
/** Sant mens komponenten selv sender hendelser, så den ikke svarer seg selv. */
|
|
40
|
+
private choosing;
|
|
41
|
+
connectedCallback(): void;
|
|
42
|
+
disconnectedCallback(): void;
|
|
43
|
+
/** Slår av filtreringen på klienten. Da er det serveren som bestemmer. */
|
|
44
|
+
get serverFiltered(): boolean;
|
|
45
|
+
private get listElement();
|
|
46
|
+
private get options();
|
|
47
|
+
/** Alternativene som er synlige nå. */
|
|
48
|
+
private get visible();
|
|
49
|
+
private unbind;
|
|
50
|
+
private bind;
|
|
51
|
+
private setOpen;
|
|
52
|
+
private filter;
|
|
53
|
+
/**
|
|
54
|
+
* Melder antall treff.
|
|
55
|
+
*
|
|
56
|
+
* Uten dette får den som ikke ser skjermen ingen beskjed om at lista
|
|
57
|
+
* snevret seg inn mens hun skrev. Teksten er klientgenerert, så elementet
|
|
58
|
+
* har `data-ignore-morph` fra byggeren.
|
|
59
|
+
*/
|
|
60
|
+
private announce;
|
|
61
|
+
private markActive;
|
|
62
|
+
private choose;
|
|
63
|
+
private handleInput;
|
|
64
|
+
private handleFocus;
|
|
65
|
+
private handleKeydown;
|
|
66
|
+
private handleOptionMouseDown;
|
|
67
|
+
private handleOutsideClick;
|
|
68
|
+
}
|
|
69
|
+
declare global {
|
|
70
|
+
interface HTMLElementTagNameMap {
|
|
71
|
+
"fs-suggestion": FsSuggestion;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
export declare function defineFsSuggestion(tagName?: "fs-suggestion"): void;
|
|
75
|
+
//# sourceMappingURL=fs-suggestion.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fs-suggestion.d.ts","sourceRoot":"","sources":["../../../../src/components/ramme/suggestion/fs-suggestion.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,iBAAiB,EAAG,eAAwB,CAAA;AAEzD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,qBAAa,YAAa,SAAQ,WAAW;IAC3C,MAAM,CAAC,kBAAkB,WAAsB;IAE/C,OAAO,CAAC,WAAW,CAAK;IACxB,OAAO,CAAC,QAAQ,CAAC,CAAkB;IACnC,OAAO,CAAC,OAAO,CAAC,CAAkB;IAClC,mDAAmD;IACnD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA6B;IACpD,gFAAgF;IAChF,OAAO,CAAC,QAAQ,CAAQ;IAExB,iBAAiB,IAAI,IAAI;IAOzB,oBAAoB,IAAI,IAAI;IAO5B,0EAA0E;IAC1E,IAAI,cAAc,IAAI,OAAO,CAE5B;IAED,OAAO,KAAK,WAAW,GAEtB;IAED,OAAO,KAAK,OAAO,GAIlB;IAED,uCAAuC;IACvC,OAAO,KAAK,OAAO,GAElB;IAED,OAAO,CAAC,MAAM;IASd,OAAO,CAAC,IAAI;IAuBZ,OAAO,CAAC,OAAO;IAgBf,OAAO,CAAC,MAAM;IAgBd;;;;;;OAMG;IACH,OAAO,CAAC,QAAQ;IAUhB,OAAO,CAAC,UAAU;IAmBlB,OAAO,CAAC,MAAM;IAyBd,OAAO,CAAC,WAAW,CAIlB;IAED,OAAO,CAAC,WAAW,CAGlB;IAED,OAAO,CAAC,aAAa,CAqBpB;IAED,OAAO,CAAC,qBAAqB,CAK5B;IAED,OAAO,CAAC,kBAAkB,CAGzB;CACF;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,eAAe,EAAE,YAAY,CAAA;KAC9B;CACF;AAED,wBAAgB,kBAAkB,CAAC,OAAO,kBAAoB,GAAG,IAAI,CAIpE"}
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
import { SUGGESTION_EMPTY_CLASS, SUGGESTION_OPTION_CLASS, } from "./suggestion.js";
|
|
2
|
+
export const FS_SUGGESTION_TAG = "fs-suggestion";
|
|
3
|
+
/**
|
|
4
|
+
* Tastaturet og filtreringen i et felt med forslagsliste.
|
|
5
|
+
*
|
|
6
|
+
* Serveren skriver feltet og lista med `fs.suggestion()`. Komponenten rendrer
|
|
7
|
+
* ingenting. Den lagde tidligere hele feltet selv, og da fantes det verken
|
|
8
|
+
* ledetekst eller inndatafelt før skriptet hadde kjørt, og ingenting ble med
|
|
9
|
+
* i innsendingen.
|
|
10
|
+
*
|
|
11
|
+
* Det komponenten gjør er det nettleseren ikke gjør: filtrerer alternativene
|
|
12
|
+
* mens brukeren skriver, flytter markeringen med piltastene, og holder
|
|
13
|
+
* `aria-activedescendant` i synk slik at skjermleseren leser opp alternativet
|
|
14
|
+
* uten at fokus forlater feltet.
|
|
15
|
+
*
|
|
16
|
+
* Patcher serveren lista selv, som i en Datastar-app, slår filtreringen seg
|
|
17
|
+
* av: da er det serveren som bestemmer hva som vises.
|
|
18
|
+
*
|
|
19
|
+
* ```html
|
|
20
|
+
* <fs-suggestion>
|
|
21
|
+
* <label class="fs-label" for="kommune">Kommune</label>
|
|
22
|
+
* <div class="fs-suggestion__field">
|
|
23
|
+
* <input class="fs-input" id="kommune" role="combobox" aria-controls="kommune-list"
|
|
24
|
+
* aria-expanded="false" data-preserve-attr="aria-expanded aria-activedescendant">
|
|
25
|
+
* <ul class="fs-suggestion__list" id="kommune-list" role="listbox" hidden
|
|
26
|
+
* data-preserve-attr="hidden">
|
|
27
|
+
* <li class="fs-suggestion__option" id="kommune-option-0" role="option">Bergen</li>
|
|
28
|
+
* </ul>
|
|
29
|
+
* </div>
|
|
30
|
+
* </fs-suggestion>
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
export class FsSuggestion extends HTMLElement {
|
|
34
|
+
constructor() {
|
|
35
|
+
super(...arguments);
|
|
36
|
+
this.activeIndex = -1;
|
|
37
|
+
/** Alternativene som alt har fått lytteren sin. */
|
|
38
|
+
this.bundne = new WeakSet();
|
|
39
|
+
/** Sant mens komponenten selv sender hendelser, så den ikke svarer seg selv. */
|
|
40
|
+
this.choosing = false;
|
|
41
|
+
this.handleInput = () => {
|
|
42
|
+
if (this.choosing)
|
|
43
|
+
return;
|
|
44
|
+
this.filter();
|
|
45
|
+
this.setOpen(true);
|
|
46
|
+
};
|
|
47
|
+
this.handleFocus = () => {
|
|
48
|
+
this.filter();
|
|
49
|
+
this.setOpen(true);
|
|
50
|
+
};
|
|
51
|
+
this.handleKeydown = (event) => {
|
|
52
|
+
const åpen = this.listElement?.hidden === false;
|
|
53
|
+
if (event.key === "ArrowDown") {
|
|
54
|
+
event.preventDefault();
|
|
55
|
+
if (!åpen) {
|
|
56
|
+
this.filter();
|
|
57
|
+
this.setOpen(true);
|
|
58
|
+
}
|
|
59
|
+
this.markActive(this.activeIndex + 1);
|
|
60
|
+
}
|
|
61
|
+
else if (event.key === "ArrowUp") {
|
|
62
|
+
event.preventDefault();
|
|
63
|
+
this.markActive(this.activeIndex - 1);
|
|
64
|
+
}
|
|
65
|
+
else if (event.key === "Enter" && åpen && this.activeIndex >= 0) {
|
|
66
|
+
event.preventDefault();
|
|
67
|
+
const valgt = this.visible[this.activeIndex];
|
|
68
|
+
if (valgt)
|
|
69
|
+
this.choose(valgt);
|
|
70
|
+
}
|
|
71
|
+
else if (event.key === "Escape" && åpen) {
|
|
72
|
+
event.preventDefault();
|
|
73
|
+
this.setOpen(false);
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
this.handleOptionMouseDown = (event) => {
|
|
77
|
+
// mousedown og ikke click: feltet mister ellers fokus før valget rekker
|
|
78
|
+
// å skje, og lista lukker seg først.
|
|
79
|
+
event.preventDefault();
|
|
80
|
+
this.choose(event.currentTarget);
|
|
81
|
+
};
|
|
82
|
+
this.handleOutsideClick = (event) => {
|
|
83
|
+
if (this.contains(event.target))
|
|
84
|
+
return;
|
|
85
|
+
this.setOpen(false);
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
connectedCallback() {
|
|
89
|
+
this.observer = new MutationObserver(() => this.bind());
|
|
90
|
+
this.observer.observe(this, { childList: true, subtree: true });
|
|
91
|
+
this.bind();
|
|
92
|
+
document.addEventListener("click", this.handleOutsideClick, true);
|
|
93
|
+
}
|
|
94
|
+
disconnectedCallback() {
|
|
95
|
+
document.removeEventListener("click", this.handleOutsideClick, true);
|
|
96
|
+
this.observer?.disconnect();
|
|
97
|
+
this.observer = undefined;
|
|
98
|
+
this.unbind();
|
|
99
|
+
}
|
|
100
|
+
/** Slår av filtreringen på klienten. Da er det serveren som bestemmer. */
|
|
101
|
+
get serverFiltered() {
|
|
102
|
+
return this.hasAttribute("server-filtered");
|
|
103
|
+
}
|
|
104
|
+
get listElement() {
|
|
105
|
+
return this.querySelector("[role='listbox']");
|
|
106
|
+
}
|
|
107
|
+
get options() {
|
|
108
|
+
return [
|
|
109
|
+
...this.querySelectorAll(`.${SUGGESTION_OPTION_CLASS}`),
|
|
110
|
+
];
|
|
111
|
+
}
|
|
112
|
+
/** Alternativene som er synlige nå. */
|
|
113
|
+
get visible() {
|
|
114
|
+
return this.options.filter((option) => !option.hidden);
|
|
115
|
+
}
|
|
116
|
+
unbind() {
|
|
117
|
+
const control = this.control;
|
|
118
|
+
if (!control)
|
|
119
|
+
return;
|
|
120
|
+
control.removeEventListener("input", this.handleInput);
|
|
121
|
+
control.removeEventListener("keydown", this.handleKeydown);
|
|
122
|
+
control.removeEventListener("focus", this.handleFocus);
|
|
123
|
+
this.control = undefined;
|
|
124
|
+
}
|
|
125
|
+
bind() {
|
|
126
|
+
const control = this.querySelector("[role='combobox']");
|
|
127
|
+
if (!control)
|
|
128
|
+
return;
|
|
129
|
+
if (control !== this.control) {
|
|
130
|
+
this.unbind();
|
|
131
|
+
control.addEventListener("input", this.handleInput);
|
|
132
|
+
control.addEventListener("keydown", this.handleKeydown);
|
|
133
|
+
control.addEventListener("focus", this.handleFocus);
|
|
134
|
+
this.control = control;
|
|
135
|
+
}
|
|
136
|
+
// Alternativene byttes ut uavhengig av feltet: i en Datastar-app sender
|
|
137
|
+
// serveren en ny liste mens brukeren skriver. Lå dette bak sjekken over,
|
|
138
|
+
// fikk de nye alternativene aldri lytteren sin, og valg med mus sluttet
|
|
139
|
+
// å virke etter første oppdatering.
|
|
140
|
+
for (const option of this.options) {
|
|
141
|
+
if (this.bundne.has(option))
|
|
142
|
+
continue;
|
|
143
|
+
option.addEventListener("mousedown", this.handleOptionMouseDown);
|
|
144
|
+
this.bundne.add(option);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
setOpen(open) {
|
|
148
|
+
const list = this.listElement;
|
|
149
|
+
if (!list || !this.control)
|
|
150
|
+
return;
|
|
151
|
+
list.hidden = !open;
|
|
152
|
+
this.control.setAttribute("aria-expanded", String(open));
|
|
153
|
+
if (!open) {
|
|
154
|
+
this.activeIndex = -1;
|
|
155
|
+
this.control.removeAttribute("aria-activedescendant");
|
|
156
|
+
for (const option of this.options) {
|
|
157
|
+
option.setAttribute("aria-selected", "false");
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
filter() {
|
|
162
|
+
if (this.serverFiltered)
|
|
163
|
+
return;
|
|
164
|
+
const query = (this.control?.value ?? "").trim().toLowerCase();
|
|
165
|
+
for (const option of this.options) {
|
|
166
|
+
const label = (option.textContent ?? "").trim().toLowerCase();
|
|
167
|
+
option.hidden = query !== "" && !label.includes(query);
|
|
168
|
+
}
|
|
169
|
+
const treff = this.visible.length;
|
|
170
|
+
const empty = this.querySelector(`.${SUGGESTION_EMPTY_CLASS}`);
|
|
171
|
+
if (empty)
|
|
172
|
+
empty.hidden = treff > 0;
|
|
173
|
+
this.announce(treff);
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Melder antall treff.
|
|
177
|
+
*
|
|
178
|
+
* Uten dette får den som ikke ser skjermen ingen beskjed om at lista
|
|
179
|
+
* snevret seg inn mens hun skrev. Teksten er klientgenerert, så elementet
|
|
180
|
+
* har `data-ignore-morph` fra byggeren.
|
|
181
|
+
*/
|
|
182
|
+
announce(treff) {
|
|
183
|
+
const status = this.querySelector("[role='status']");
|
|
184
|
+
if (!status)
|
|
185
|
+
return;
|
|
186
|
+
const tekst = treff === 0 ? "Ingen treff" : treff === 1 ? "Ett treff" : `${treff} treff`;
|
|
187
|
+
if (status.textContent !== tekst)
|
|
188
|
+
status.textContent = tekst;
|
|
189
|
+
}
|
|
190
|
+
markActive(index) {
|
|
191
|
+
const synlige = this.visible;
|
|
192
|
+
if (synlige.length === 0 || !this.control)
|
|
193
|
+
return;
|
|
194
|
+
const neste = (index + synlige.length) % synlige.length;
|
|
195
|
+
this.activeIndex = neste;
|
|
196
|
+
for (const option of this.options) {
|
|
197
|
+
option.setAttribute("aria-selected", "false");
|
|
198
|
+
}
|
|
199
|
+
const aktiv = synlige[neste];
|
|
200
|
+
aktiv.setAttribute("aria-selected", "true");
|
|
201
|
+
// aria-activedescendant flytter skjermleserens lesepunkt uten at fokus
|
|
202
|
+
// forlater feltet. Uten den leses alternativet aldri opp.
|
|
203
|
+
this.control.setAttribute("aria-activedescendant", aktiv.id);
|
|
204
|
+
aktiv.scrollIntoView({ block: "nearest" });
|
|
205
|
+
}
|
|
206
|
+
choose(option) {
|
|
207
|
+
if (!this.control)
|
|
208
|
+
return;
|
|
209
|
+
const value = option.getAttribute("data-value") ?? (option.textContent ?? "").trim();
|
|
210
|
+
this.control.value = value;
|
|
211
|
+
// Flagget må stå før hendelsene sendes. `input` er den samme hendelsen
|
|
212
|
+
// komponenten selv lytter på, så uten dette åpner lista seg igjen i det
|
|
213
|
+
// øyeblikket brukeren har valgt noe.
|
|
214
|
+
this.choosing = true;
|
|
215
|
+
this.control.dispatchEvent(new Event("input", { bubbles: true }));
|
|
216
|
+
this.control.dispatchEvent(new Event("change", { bubbles: true }));
|
|
217
|
+
this.choosing = false;
|
|
218
|
+
this.setOpen(false);
|
|
219
|
+
this.dispatchEvent(new CustomEvent("suggestion-select", {
|
|
220
|
+
detail: { value },
|
|
221
|
+
bubbles: true,
|
|
222
|
+
composed: true,
|
|
223
|
+
}));
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
FsSuggestion.observedAttributes = ["server-filtered"];
|
|
227
|
+
export function defineFsSuggestion(tagName = FS_SUGGESTION_TAG) {
|
|
228
|
+
if (!customElements.get(tagName)) {
|
|
229
|
+
customElements.define(tagName, FsSuggestion);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
//# sourceMappingURL=fs-suggestion.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fs-suggestion.js","sourceRoot":"","sources":["../../../../src/components/ramme/suggestion/fs-suggestion.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { type FieldOptions } from "../field/field-core.js";
|
|
2
|
+
export declare const SUGGESTION_CLASS: "fs-suggestion";
|
|
3
|
+
export declare const SUGGESTION_FIELD_CLASS: "fs-suggestion__field";
|
|
4
|
+
export declare const SUGGESTION_LIST_CLASS: "fs-suggestion__list";
|
|
5
|
+
export declare const SUGGESTION_OPTION_CLASS: "fs-suggestion__option";
|
|
6
|
+
export declare const SUGGESTION_EMPTY_CLASS: "fs-suggestion__empty";
|
|
7
|
+
export declare const SUGGESTION_STATUS_CLASS: "fs-sr-only";
|
|
8
|
+
export type SuggestionOptions = Omit<FieldOptions, "id"> & {
|
|
9
|
+
/** Felles id-stamme. Kontrollen blir `${id}`, lista `${id}-list`. */
|
|
10
|
+
id: string;
|
|
11
|
+
/** Antall alternativer serveren sender med. Standard: 0. */
|
|
12
|
+
count?: number;
|
|
13
|
+
/** Alternativet som er markert med piltastene. Standard: ingen. */
|
|
14
|
+
activeIndex?: number;
|
|
15
|
+
/** Lista er åpen. Standard: lukket. */
|
|
16
|
+
open?: boolean;
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Attributtene for et felt med forslagsliste.
|
|
20
|
+
*
|
|
21
|
+
* Serveren skriver både feltet og lista. Komponenten filtrerer, tar
|
|
22
|
+
* piltastene og holder `aria-activedescendant` i synk. Den rendrer ingenting:
|
|
23
|
+
* tidligere lagde den hele feltet selv, og da fantes det ikke noe å fylle ut
|
|
24
|
+
* før skriptet hadde kjørt.
|
|
25
|
+
*
|
|
26
|
+
* Attributtene som endrer seg mens brukeren skriver står i
|
|
27
|
+
* `data-preserve-attr`, ellers river Datastars morfing dem bort.
|
|
28
|
+
*/
|
|
29
|
+
export declare const suggestion: ({ id, count, activeIndex, open, ...field }: SuggestionOptions) => {
|
|
30
|
+
label: {
|
|
31
|
+
class: "fs-label";
|
|
32
|
+
for: string;
|
|
33
|
+
"data-required"?: import("../../css/shared.js").RequiredMarker;
|
|
34
|
+
"data-optional"?: "";
|
|
35
|
+
"aria-disabled"?: "true";
|
|
36
|
+
};
|
|
37
|
+
field: {
|
|
38
|
+
class: "fs-suggestion__field";
|
|
39
|
+
};
|
|
40
|
+
control: {
|
|
41
|
+
class: "fs-input";
|
|
42
|
+
type: "text";
|
|
43
|
+
role: "combobox";
|
|
44
|
+
autocomplete: "off";
|
|
45
|
+
"aria-expanded": "true" | "false";
|
|
46
|
+
"aria-controls": string;
|
|
47
|
+
"aria-describedby": string;
|
|
48
|
+
"aria-autocomplete": "list";
|
|
49
|
+
"aria-activedescendant": string | undefined;
|
|
50
|
+
"data-preserve-attr": "aria-expanded aria-activedescendant";
|
|
51
|
+
id: string;
|
|
52
|
+
"aria-invalid"?: "true";
|
|
53
|
+
"data-state"?: "invalid";
|
|
54
|
+
disabled?: true;
|
|
55
|
+
};
|
|
56
|
+
list: {
|
|
57
|
+
class: "fs-suggestion__list";
|
|
58
|
+
id: string;
|
|
59
|
+
role: "listbox";
|
|
60
|
+
hidden: true | undefined;
|
|
61
|
+
"data-preserve-attr": "hidden";
|
|
62
|
+
};
|
|
63
|
+
options: {
|
|
64
|
+
class: "fs-suggestion__option";
|
|
65
|
+
id: string;
|
|
66
|
+
role: "option";
|
|
67
|
+
"aria-selected": "true" | "false";
|
|
68
|
+
"data-preserve-attr": "aria-selected hidden";
|
|
69
|
+
}[];
|
|
70
|
+
empty: {
|
|
71
|
+
class: "fs-suggestion__empty";
|
|
72
|
+
};
|
|
73
|
+
/**
|
|
74
|
+
* Området som melder antall treff til skjermlesere.
|
|
75
|
+
*
|
|
76
|
+
* Teksten skrives av komponenten mens brukeren taster, så den finnes ikke
|
|
77
|
+
* i serverens utgave. `data-ignore-morph` hindrer at neste patch tømmer
|
|
78
|
+
* den. Elementet må likevel stå i markupen serveren sender, ellers finnes
|
|
79
|
+
* det ikke noe å melde i før skriptet har kjørt.
|
|
80
|
+
*/
|
|
81
|
+
status: {
|
|
82
|
+
class: "fs-sr-only";
|
|
83
|
+
id: string;
|
|
84
|
+
role: "status";
|
|
85
|
+
"aria-live": "polite";
|
|
86
|
+
"data-ignore-morph": "";
|
|
87
|
+
};
|
|
88
|
+
help: {
|
|
89
|
+
id: string;
|
|
90
|
+
};
|
|
91
|
+
error: {
|
|
92
|
+
id: string;
|
|
93
|
+
hidden?: true;
|
|
94
|
+
};
|
|
95
|
+
state: "default" | "success" | "invalid";
|
|
96
|
+
};
|
|
97
|
+
//# sourceMappingURL=suggestion.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"suggestion.d.ts","sourceRoot":"","sources":["../../../../src/components/ramme/suggestion/suggestion.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,KAAK,YAAY,EAClB,MAAM,wBAAwB,CAAA;AAE/B,eAAO,MAAM,gBAAgB,EAAG,eAAwB,CAAA;AACxD,eAAO,MAAM,sBAAsB,EAAG,sBAA+B,CAAA;AACrE,eAAO,MAAM,qBAAqB,EAAG,qBAA8B,CAAA;AACnE,eAAO,MAAM,uBAAuB,EAAG,uBAAgC,CAAA;AACvE,eAAO,MAAM,sBAAsB,EAAG,sBAA+B,CAAA;AACrE,eAAO,MAAM,uBAAuB,EAAG,YAAqB,CAAA;AAE5D,MAAM,MAAM,iBAAiB,GAAG,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,GAAG;IACzD,qEAAqE;IACrE,EAAE,EAAE,MAAM,CAAA;IACV,4DAA4D;IAC5D,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,mEAAmE;IACnE,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,uCAAuC;IACvC,IAAI,CAAC,EAAE,OAAO,CAAA;CACf,CAAA;AAED;;;;;;;;;;GAUG;AACH,eAAO,MAAM,UAAU,GAAI,4CAMxB,iBAAiB;;;;;;;;;;;;;;;;yBAgBgC,MAAM,GAAG,OAAO;;;;;;;;;;;;;;;;;;;;;;yBAsBxD,MAAM,GACN,OAAO;;;;;;IAKf;;;;;;;OAOG;;;;;;;;;;;;;;;;CAYN,CAAA"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { attributes } from "../../css/shared.js";
|
|
2
|
+
import { computeFieldAttributes, } from "../field/field-core.js";
|
|
3
|
+
export const SUGGESTION_CLASS = "fs-suggestion";
|
|
4
|
+
export const SUGGESTION_FIELD_CLASS = "fs-suggestion__field";
|
|
5
|
+
export const SUGGESTION_LIST_CLASS = "fs-suggestion__list";
|
|
6
|
+
export const SUGGESTION_OPTION_CLASS = "fs-suggestion__option";
|
|
7
|
+
export const SUGGESTION_EMPTY_CLASS = "fs-suggestion__empty";
|
|
8
|
+
export const SUGGESTION_STATUS_CLASS = "fs-sr-only";
|
|
9
|
+
/**
|
|
10
|
+
* Attributtene for et felt med forslagsliste.
|
|
11
|
+
*
|
|
12
|
+
* Serveren skriver både feltet og lista. Komponenten filtrerer, tar
|
|
13
|
+
* piltastene og holder `aria-activedescendant` i synk. Den rendrer ingenting:
|
|
14
|
+
* tidligere lagde den hele feltet selv, og da fantes det ikke noe å fylle ut
|
|
15
|
+
* før skriptet hadde kjørt.
|
|
16
|
+
*
|
|
17
|
+
* Attributtene som endrer seg mens brukeren skriver står i
|
|
18
|
+
* `data-preserve-attr`, ellers river Datastars morfing dem bort.
|
|
19
|
+
*/
|
|
20
|
+
export const suggestion = ({ id, count = 0, activeIndex = -1, open = false, ...field }) => {
|
|
21
|
+
const computed = computeFieldAttributes({ ...field, id });
|
|
22
|
+
const listId = `${id}-list`;
|
|
23
|
+
const statusId = `${id}-status`;
|
|
24
|
+
const optionId = (index) => `${id}-option-${index}`;
|
|
25
|
+
const aktiv = open && activeIndex >= 0 && activeIndex < count;
|
|
26
|
+
return {
|
|
27
|
+
label: computed.label,
|
|
28
|
+
field: { class: SUGGESTION_FIELD_CLASS },
|
|
29
|
+
control: attributes({
|
|
30
|
+
...computed.control,
|
|
31
|
+
class: "fs-input",
|
|
32
|
+
type: "text",
|
|
33
|
+
role: "combobox",
|
|
34
|
+
autocomplete: "off",
|
|
35
|
+
"aria-expanded": (open ? "true" : "false"),
|
|
36
|
+
"aria-controls": listId,
|
|
37
|
+
"aria-describedby": [computed.control["aria-describedby"], statusId]
|
|
38
|
+
.filter(Boolean)
|
|
39
|
+
.join(" "),
|
|
40
|
+
"aria-autocomplete": "list",
|
|
41
|
+
"aria-activedescendant": aktiv ? optionId(activeIndex) : undefined,
|
|
42
|
+
"data-preserve-attr": "aria-expanded aria-activedescendant",
|
|
43
|
+
}),
|
|
44
|
+
list: attributes({
|
|
45
|
+
class: SUGGESTION_LIST_CLASS,
|
|
46
|
+
id: listId,
|
|
47
|
+
role: "listbox",
|
|
48
|
+
hidden: open ? undefined : true,
|
|
49
|
+
"data-preserve-attr": "hidden",
|
|
50
|
+
}),
|
|
51
|
+
options: Array.from({ length: count }, (_, index) => attributes({
|
|
52
|
+
class: SUGGESTION_OPTION_CLASS,
|
|
53
|
+
id: optionId(index),
|
|
54
|
+
role: "option",
|
|
55
|
+
"aria-selected": (index === activeIndex ? "true" : "false"),
|
|
56
|
+
"data-preserve-attr": "aria-selected hidden",
|
|
57
|
+
})),
|
|
58
|
+
empty: { class: SUGGESTION_EMPTY_CLASS },
|
|
59
|
+
/**
|
|
60
|
+
* Området som melder antall treff til skjermlesere.
|
|
61
|
+
*
|
|
62
|
+
* Teksten skrives av komponenten mens brukeren taster, så den finnes ikke
|
|
63
|
+
* i serverens utgave. `data-ignore-morph` hindrer at neste patch tømmer
|
|
64
|
+
* den. Elementet må likevel stå i markupen serveren sender, ellers finnes
|
|
65
|
+
* det ikke noe å melde i før skriptet har kjørt.
|
|
66
|
+
*/
|
|
67
|
+
status: {
|
|
68
|
+
class: SUGGESTION_STATUS_CLASS,
|
|
69
|
+
id: statusId,
|
|
70
|
+
role: "status",
|
|
71
|
+
"aria-live": "polite",
|
|
72
|
+
"data-ignore-morph": "",
|
|
73
|
+
},
|
|
74
|
+
help: computed.help,
|
|
75
|
+
error: computed.error,
|
|
76
|
+
state: computed.state,
|
|
77
|
+
};
|
|
78
|
+
};
|
|
79
|
+
//# sourceMappingURL=suggestion.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"suggestion.js","sourceRoot":"","sources":["../../../../src/components/ramme/suggestion/suggestion.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,52 +1,47 @@
|
|
|
1
|
-
import { LitElement } from "lit";
|
|
2
1
|
export declare const FS_TABS_TAG: "fs-tabs";
|
|
3
|
-
export declare const TABS_LIST_CLASS: "fs-tabs__list";
|
|
4
|
-
export declare const TABS_PANEL_CLASS: "fs-tabs__panel";
|
|
5
2
|
/**
|
|
6
|
-
*
|
|
3
|
+
* Tastaturet i en fanerad.
|
|
7
4
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
5
|
+
* Serveren skriver rollene, `aria-controls` og `hidden` med `fs.tabs()`.
|
|
6
|
+
* Gjorde komponenten det, ville alle panelene vises til skriptet hadde kjørt,
|
|
7
|
+
* og innholdet hoppe når panelene skjulte seg selv. I en Datastar-app ville
|
|
8
|
+
* de dessuten komme tilbake ved hver patch.
|
|
11
9
|
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
10
|
+
* Det komponenten gjør er det nettleseren ikke gjør selv: Tab hopper forbi
|
|
11
|
+
* hele raden og inn i panelet, mens piltastene flytter mellom fanene. Et sett
|
|
12
|
+
* knapper uten dette gir én tabbestopp per fane, og skjermleseren sier
|
|
13
|
+
* «knapp» der den skulle sagt «fane, 2 av 3, valgt».
|
|
14
|
+
*
|
|
15
|
+
* Attributtene som endrer seg når brukeren velger, altså `aria-selected`,
|
|
16
|
+
* `tabindex` og `hidden`, står i `data-preserve-attr` fra byggeren.
|
|
16
17
|
*
|
|
17
18
|
* ```html
|
|
18
19
|
* <fs-tabs>
|
|
19
|
-
* <div class="fs-tabs__list">
|
|
20
|
-
* <button
|
|
21
|
-
*
|
|
20
|
+
* <div class="fs-tabs__list" role="tablist">
|
|
21
|
+
* <button id="sak-tab-0" role="tab" aria-selected="true" aria-controls="sak-panel-0"
|
|
22
|
+
* tabindex="0" data-preserve-attr="aria-selected tabindex">Søknaden</button>
|
|
22
23
|
* </div>
|
|
23
|
-
* <div class="fs-tabs__panel"
|
|
24
|
-
*
|
|
24
|
+
* <div id="sak-panel-0" class="fs-tabs__panel" role="tabpanel"
|
|
25
|
+
* aria-labelledby="sak-tab-0" tabindex="0" data-preserve-attr="hidden">…</div>
|
|
25
26
|
* </fs-tabs>
|
|
26
27
|
* ```
|
|
27
28
|
*/
|
|
28
|
-
export declare class FsTabs extends
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
selected: number;
|
|
40
|
-
/** Tekst som sier hva fanene velger mellom. Blir `aria-label` på raden. */
|
|
41
|
-
label?: string;
|
|
42
|
-
createRenderRoot(): this;
|
|
43
|
-
render(): import("lit").TemplateResult<1>;
|
|
44
|
-
firstUpdated(): void;
|
|
45
|
-
updated(): void;
|
|
46
|
-
private handleSlotChange;
|
|
29
|
+
export declare class FsTabs extends HTMLElement {
|
|
30
|
+
/**
|
|
31
|
+
* Ingen attributter. Hvilken fane som er valgt står i markupen serveren
|
|
32
|
+
* sendte, som `aria-selected` på fanen og `hidden` på panelene, og leses
|
|
33
|
+
* derfra. Et eget `selected` ville vært en parallell utgave av det samme.
|
|
34
|
+
*/
|
|
35
|
+
static observedAttributes: string[];
|
|
36
|
+
private readonly bound;
|
|
37
|
+
private observer?;
|
|
38
|
+
connectedCallback(): void;
|
|
39
|
+
disconnectedCallback(): void;
|
|
47
40
|
private get tabs();
|
|
48
41
|
private get panels();
|
|
49
|
-
|
|
42
|
+
/** Indeksen på fanen serveren har markert som valgt. */
|
|
43
|
+
get selected(): number;
|
|
44
|
+
private bind;
|
|
50
45
|
private handleClick;
|
|
51
46
|
private handleKeydown;
|
|
52
47
|
/** Velger en fane og melder fra. */
|