@innspel/react-native 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js ADDED
@@ -0,0 +1,1361 @@
1
+ // src/InnspelProvider.tsx
2
+ import { createContext as createContext2, useCallback as useCallback2, useContext as useContext2, useMemo as useMemo2, useRef, useState as useState3 } from "react";
3
+
4
+ // src/tema.ts
5
+ import { createContext, useContext } from "react";
6
+
7
+ // src/generated/tokens.ts
8
+ var t = {
9
+ color: {
10
+ bg: "#111417",
11
+ surface: "#1A1E22",
12
+ surfaceRaised: "#232830",
13
+ border: "#2E343B",
14
+ borderStrong: "#3D444D",
15
+ borderInteractive: "#7C8894",
16
+ textPrimary: "#F2F4F6",
17
+ textSecondary: "#B4BCC5",
18
+ textMuted: "#8D96A1",
19
+ textDisabled: "#5A626B",
20
+ actionPrimary: "#5AD3E2",
21
+ onActionPrimary: "#04252A",
22
+ actionSecondaryBorder: "#7C8894",
23
+ actionSecondaryText: "#F2F4F6",
24
+ brand: "#5AD3E2",
25
+ onBrand: "#04252A",
26
+ brandFill: "#0E7C8C",
27
+ onBrandFill: "#FFFFFF",
28
+ brandBg: "#0C2A30",
29
+ danger: "#FF7A8C",
30
+ dangerFill: "#C4001F",
31
+ onDangerFill: "#FFFFFF",
32
+ dangerBg: "#2C1116",
33
+ success: "#3ED88A",
34
+ onSuccess: "#062015",
35
+ successBg: "#0E2A1E",
36
+ warning: "#FFC24D",
37
+ onWarning: "#2A1C02",
38
+ warningBg: "#2C2107",
39
+ info: "#5CC0FF",
40
+ onInfo: "#04222F",
41
+ infoBg: "#0E2531",
42
+ neutral: "#A3ACB6",
43
+ onNeutral: "#111417",
44
+ neutralBg: "#242A31",
45
+ scrim: "rgba(0, 0, 0, 0.72)"
46
+ },
47
+ space: {
48
+ xs: 4,
49
+ sm: 8,
50
+ md: 16,
51
+ lg: 24,
52
+ xl: 32,
53
+ xxl: 48
54
+ },
55
+ radius: {
56
+ sm: 6,
57
+ md: 8,
58
+ lg: 12,
59
+ pill: 999
60
+ },
61
+ font: {
62
+ h1: 24,
63
+ h2: 21,
64
+ h3: 18,
65
+ body: 16,
66
+ small: 13,
67
+ tiny: 11
68
+ },
69
+ lineHeight: {
70
+ h1: 30,
71
+ h2: 27,
72
+ h3: 24,
73
+ body: 24,
74
+ small: 18,
75
+ tiny: 16
76
+ },
77
+ weight: {
78
+ regular: "400",
79
+ medium: "500",
80
+ semibold: "600",
81
+ bold: "700"
82
+ },
83
+ motion: {
84
+ fast: 120,
85
+ base: 200,
86
+ slow: 320
87
+ },
88
+ touch: 48,
89
+ screenPadding: 24,
90
+ hairline: 1
91
+ };
92
+ var light = {
93
+ color: {
94
+ bg: "#F6F7F9",
95
+ surface: "#FFFFFF",
96
+ surfaceRaised: "#EDEFF3",
97
+ border: "#D2D7DE",
98
+ borderStrong: "#B9C0C9",
99
+ borderInteractive: "#6F7883",
100
+ textPrimary: "#14181D",
101
+ textSecondary: "#454D57",
102
+ textMuted: "#5C6470",
103
+ textDisabled: "#9AA2AD",
104
+ actionPrimary: "#0A6673",
105
+ onActionPrimary: "#FFFFFF",
106
+ actionSecondaryBorder: "#6F7883",
107
+ actionSecondaryText: "#14181D",
108
+ brand: "#0A6673",
109
+ onBrand: "#FFFFFF",
110
+ brandFill: "#0A6673",
111
+ onBrandFill: "#FFFFFF",
112
+ brandBg: "#E0F0F2",
113
+ danger: "#B3001B",
114
+ dangerFill: "#B3001B",
115
+ onDangerFill: "#FFFFFF",
116
+ dangerBg: "#FCE8EA",
117
+ success: "#04693C",
118
+ onSuccess: "#FFFFFF",
119
+ successBg: "#E4F4EC",
120
+ warning: "#7A5200",
121
+ onWarning: "#FFFFFF",
122
+ warningBg: "#FBF1DE",
123
+ info: "#00588F",
124
+ onInfo: "#FFFFFF",
125
+ infoBg: "#E4F0F8",
126
+ neutral: "#5C6470",
127
+ onNeutral: "#FFFFFF",
128
+ neutralBg: "#EEF0F3",
129
+ scrim: "rgba(10, 14, 18, 0.45)"
130
+ },
131
+ space: {
132
+ xs: 4,
133
+ sm: 8,
134
+ md: 16,
135
+ lg: 24,
136
+ xl: 32,
137
+ xxl: 48
138
+ },
139
+ radius: {
140
+ sm: 6,
141
+ md: 8,
142
+ lg: 12,
143
+ pill: 999
144
+ },
145
+ font: {
146
+ h1: 24,
147
+ h2: 21,
148
+ h3: 18,
149
+ body: 16,
150
+ small: 13,
151
+ tiny: 11
152
+ },
153
+ lineHeight: {
154
+ h1: 30,
155
+ h2: 27,
156
+ h3: 24,
157
+ body: 24,
158
+ small: 18,
159
+ tiny: 16
160
+ },
161
+ weight: {
162
+ regular: "400",
163
+ medium: "500",
164
+ semibold: "600",
165
+ bold: "700"
166
+ },
167
+ motion: {
168
+ fast: 120,
169
+ base: 200,
170
+ slow: 320
171
+ },
172
+ touch: 48,
173
+ screenPadding: 24,
174
+ hairline: 1
175
+ };
176
+ var screenRules = {
177
+ brushFill: "#E5007D",
178
+ autoMaskFill: "#101114",
179
+ autoMaskStroke: "#E5007D",
180
+ previewBackdrop: "#000000"
181
+ };
182
+
183
+ // src/tema.ts
184
+ function byggTema(vertens, palett = "dark") {
185
+ const bunn = palett === "light" ? light : t;
186
+ if (!vertens) return bunn;
187
+ return {
188
+ ...bunn,
189
+ ...vertens,
190
+ color: { ...bunn.color, ...vertens.color }
191
+ };
192
+ }
193
+ var TemaContext = createContext(t);
194
+ var TemaProvider = TemaContext.Provider;
195
+ function useTema() {
196
+ return useContext(TemaContext);
197
+ }
198
+
199
+ // src/widget/Widget.tsx
200
+ import {
201
+ InnspelApiError,
202
+ InnspelQueueFullError
203
+ } from "@innspel/core";
204
+ import { useCallback, useEffect, useState as useState2 } from "react";
205
+ import { Modal, Pressable as Pressable4, Text as Text7, View as View7 } from "react-native";
206
+
207
+ // src/widget/Felt.tsx
208
+ import { useMemo, useState } from "react";
209
+ import { Pressable as Pressable2, Text as Text2, TextInput, View as View2 } from "react-native";
210
+
211
+ // src/widget/primitiver.tsx
212
+ import "react";
213
+ import { Pressable, Text, View } from "react-native";
214
+ import { jsx, jsxs } from "react/jsx-runtime";
215
+ function Btn({
216
+ label,
217
+ onPress,
218
+ variant = "primary",
219
+ ikon,
220
+ hint,
221
+ disabled,
222
+ accessibilityLabel,
223
+ grow,
224
+ testID
225
+ }) {
226
+ const tema = useTema();
227
+ const c = tema.color;
228
+ const bakgrunn = variant === "primary" ? c.actionPrimary : variant === "secondary" ? c.surfaceRaised : "transparent";
229
+ const tekstfarge = variant === "primary" ? c.onActionPrimary : variant === "danger" ? c.danger : c.actionSecondaryText;
230
+ const kant = variant === "ghost" ? "transparent" : variant === "primary" ? c.actionPrimary : c.actionSecondaryBorder;
231
+ return /* @__PURE__ */ jsxs(View, { style: grow ? { flex: 1 } : void 0, children: [
232
+ /* @__PURE__ */ jsxs(
233
+ Pressable,
234
+ {
235
+ testID,
236
+ accessibilityRole: "button",
237
+ accessibilityLabel: accessibilityLabel ?? (hint ? `${label}. ${hint}` : label),
238
+ accessibilityState: { disabled: !!disabled },
239
+ disabled,
240
+ onPress,
241
+ style: {
242
+ minHeight: tema.touch,
243
+ borderRadius: tema.radius.md,
244
+ borderWidth: tema.hairline,
245
+ borderColor: kant,
246
+ backgroundColor: disabled ? c.surface : bakgrunn,
247
+ paddingHorizontal: tema.space.md,
248
+ alignItems: "center",
249
+ justifyContent: "center",
250
+ flexDirection: "row",
251
+ gap: tema.space.sm,
252
+ opacity: disabled ? 0.6 : 1
253
+ },
254
+ children: [
255
+ ikon ? /* @__PURE__ */ jsx(Text, { accessibilityElementsHidden: true, importantForAccessibility: "no", style: { fontSize: tema.font.body }, children: ikon }) : null,
256
+ /* @__PURE__ */ jsx(
257
+ Text,
258
+ {
259
+ style: {
260
+ color: disabled ? c.textDisabled : tekstfarge,
261
+ fontSize: tema.font.body,
262
+ fontWeight: tema.weight.semibold
263
+ },
264
+ children: label
265
+ }
266
+ )
267
+ ]
268
+ }
269
+ ),
270
+ hint ? /* @__PURE__ */ jsx(Hint, { children: hint }) : null
271
+ ] });
272
+ }
273
+ function H({ children, sub }) {
274
+ const tema = useTema();
275
+ return /* @__PURE__ */ jsxs(View, { style: { gap: tema.space.xs }, children: [
276
+ /* @__PURE__ */ jsx(
277
+ Text,
278
+ {
279
+ accessibilityRole: "header",
280
+ style: {
281
+ color: tema.color.textPrimary,
282
+ fontSize: tema.font.h2,
283
+ lineHeight: tema.lineHeight.h2,
284
+ fontWeight: tema.weight.semibold
285
+ },
286
+ children
287
+ }
288
+ ),
289
+ sub ? /* @__PURE__ */ jsx(
290
+ Text,
291
+ {
292
+ style: {
293
+ color: tema.color.textSecondary,
294
+ fontSize: tema.font.small,
295
+ lineHeight: tema.lineHeight.small
296
+ },
297
+ children: sub
298
+ }
299
+ ) : null
300
+ ] });
301
+ }
302
+ function Hint({ children }) {
303
+ const tema = useTema();
304
+ return /* @__PURE__ */ jsx(
305
+ Text,
306
+ {
307
+ style: {
308
+ color: tema.color.textMuted,
309
+ fontSize: tema.font.small,
310
+ lineHeight: tema.lineHeight.small
311
+ },
312
+ children
313
+ }
314
+ );
315
+ }
316
+ function Card({
317
+ children,
318
+ dashed,
319
+ style
320
+ }) {
321
+ const tema = useTema();
322
+ return /* @__PURE__ */ jsx(
323
+ View,
324
+ {
325
+ style: [
326
+ {
327
+ backgroundColor: tema.color.surface,
328
+ borderRadius: tema.radius.lg,
329
+ borderWidth: tema.hairline,
330
+ borderColor: tema.color.border,
331
+ borderStyle: dashed ? "dashed" : "solid",
332
+ padding: tema.space.md,
333
+ gap: tema.space.sm
334
+ },
335
+ style
336
+ ],
337
+ children
338
+ }
339
+ );
340
+ }
341
+ function StatusPill({
342
+ ikon,
343
+ etikett,
344
+ farge
345
+ }) {
346
+ const tema = useTema();
347
+ return /* @__PURE__ */ jsxs(
348
+ View,
349
+ {
350
+ style: {
351
+ flexDirection: "row",
352
+ alignItems: "center",
353
+ gap: tema.space.xs,
354
+ alignSelf: "flex-start",
355
+ paddingHorizontal: tema.space.sm,
356
+ paddingVertical: tema.space.xs,
357
+ borderRadius: tema.radius.pill,
358
+ backgroundColor: tema.color[`${farge}Bg`]
359
+ },
360
+ children: [
361
+ /* @__PURE__ */ jsx(Text, { accessibilityElementsHidden: true, importantForAccessibility: "no", style: { fontSize: tema.font.small }, children: ikon }),
362
+ /* @__PURE__ */ jsx(Text, { style: { color: tema.color[farge], fontSize: tema.font.small, fontWeight: tema.weight.medium }, children: etikett })
363
+ ]
364
+ }
365
+ );
366
+ }
367
+ function Banner({
368
+ ikon,
369
+ tone,
370
+ children,
371
+ live
372
+ }) {
373
+ const tema = useTema();
374
+ return /* @__PURE__ */ jsxs(
375
+ View,
376
+ {
377
+ style: {
378
+ flexDirection: "row",
379
+ gap: tema.space.sm,
380
+ backgroundColor: tema.color[`${tone}Bg`],
381
+ borderRadius: tema.radius.md,
382
+ padding: tema.space.md
383
+ },
384
+ children: [
385
+ /* @__PURE__ */ jsx(Text, { accessibilityElementsHidden: true, importantForAccessibility: "no", style: { fontSize: tema.font.body }, children: ikon }),
386
+ /* @__PURE__ */ jsx(
387
+ Text,
388
+ {
389
+ accessibilityRole: "alert",
390
+ accessibilityLiveRegion: live ? "polite" : "none",
391
+ style: {
392
+ flex: 1,
393
+ color: tema.color[tone],
394
+ fontSize: tema.font.small,
395
+ lineHeight: tema.lineHeight.small
396
+ },
397
+ children
398
+ }
399
+ )
400
+ ]
401
+ }
402
+ );
403
+ }
404
+
405
+ // src/widget/tekster.ts
406
+ var tekst = {
407
+ // 2b — første valg
408
+ valgTittel: "Hva gjelder det?",
409
+ valgUnder: "Ett valg. Vi sp\xF8r aldri om kategori eller alvorlighet.",
410
+ sporFeil: "Noe virker ikke",
411
+ sporFeilUnder: "Feilsporet \u2014 kontekst legges ved",
412
+ sporOnske: "Jeg \xF8nsker meg noe",
413
+ sporOnskeUnder: "\xD8nskesporet \u2014 aldri sp\xF8rsm\xE5l om reproduksjon",
414
+ // 2c — kjente feil (DD-29, DD-30)
415
+ kjenteFeilTittelFeil: "Er det dette du ser?",
416
+ kjenteFeilUnderFeil: "\xABJa\xBB registrerer deg p\xE5 saken. \xABLigner\xBB sender ditt eget med lenke.",
417
+ kjenteFeilTittelOnske: "Har noen \xF8nsket dette?",
418
+ kjenteFeilUnderOnske: "Ett trykk legger deg til p\xE5 \xF8nsket \u2014 ingen ny sak.",
419
+ svarJa: "Ja, jeg ogs\xE5",
420
+ svarLigner: "Ligner, men ikke helt",
421
+ svarNei: "Nei, det er noe annet",
422
+ omvei: "Omvei:",
423
+ rettesI: (versjon) => `Rettes i ${versjon}`,
424
+ rettetI: (versjon) => `Rettet i ${versjon}`,
425
+ // 2d + 2e — feltet og kontekstlinja
426
+ feltLabelFeil: "Din feil",
427
+ feltLabelOnske: "Ditt \xF8nske",
428
+ /** DD-45: to spørsmål i feilsporet. Kilde: Sentry «What's the bug? What did you expect?» */
429
+ placeholderFeil: "Hva skjedde? Hva forventet du?",
430
+ placeholderOnske: "Hva \xF8nsker du deg?",
431
+ send: "Send",
432
+ nesteOnske: "Neste \u2014 sjekk om noen har \xF8nsket dette",
433
+ /** DD-44: minimum tegn er det ENESTE kravet. */
434
+ forKort: (min) => `Minst ${min} tegn. Ingenting annet er obligatorisk.`,
435
+ tellerFull: " \u2014 kort og konkret holder",
436
+ kontekstLinje: "Legges ved: skjerm, appversjon, plattform, OS",
437
+ kontekstVis: " \u2014 Vis",
438
+ kontekstFjern: "Fjern",
439
+ kontekstAldri: "Aldri: navn, e-post, telefon, posisjon eller det som st\xE5r p\xE5 skjermen.",
440
+ lenketTil: (tittel) => `Lenket til: \xAB${tittel}\xBB`,
441
+ fjernLenke: "Fjern lenken til den kjente feilen",
442
+ // DD-46 — mønstervarsel. Aldri stille redaksjon.
443
+ monsterSpm: {
444
+ email: "Dette ser ut som en e-postadresse. Vil du fjerne den?",
445
+ phone: "Dette ser ut som et telefonnummer. Vil du fjerne det?",
446
+ card: "Dette ser ut som et kortnummer. Vil du fjerne det?",
447
+ ip: "Dette ser ut som en IP-adresse. Vil du fjerne den?",
448
+ token: "Dette ser ut som en tilgangsn\xF8kkel. Vil du fjerne den?"
449
+ },
450
+ monsterFjern: "Fjern",
451
+ monsterBehold: "Behold",
452
+ monsterForklaring: "Teksten endres bare hvis du trykker Fjern. Vi fjerner aldri noe stille.",
453
+ // 2g — kvittering
454
+ kvitteringSendt: "Sendt",
455
+ kvitteringRegistrert: "Registrert",
456
+ kvitteringFeil: "Du f\xE5r beskjed n\xE5r den er rettet, eller hvis vi trenger mer.",
457
+ kvitteringOnske: "Vurderes innen 90 dager. Du f\xE5r et personlig svar \u2014 ogs\xE5 hvis det er nei.",
458
+ kvitteringJaOgsa: "Du f\xE5r beskjed n\xE5r den er rettet.",
459
+ saksnummer: (nr) => `Saksnummer ${nr} \u2014 vis dette hvis du sp\xF8r support.`,
460
+ tilbakeTilAppen: "Tilbake til appen",
461
+ // 2i — tilstander
462
+ offlineTittel: "Ingen nett",
463
+ offlineBanner: "Ingen nett. Lagres og sendes automatisk \u2014 du ser det under \xABMine innspill\xBB til det er sendt.",
464
+ offlineLagre: "Lagre \u2014 sendes automatisk",
465
+ sendefeilBanner: (arsak) => `Kunne ikke sende: ${arsak} Teksten din er beholdt.`,
466
+ provIgjen: "Pr\xF8v igjen",
467
+ // 2j — mine innspill
468
+ mineTittel: "Mine innspill",
469
+ mineUnder: "Status og hva du kan vente deg \u2014 samme l\xF8fte som i kvitteringen.",
470
+ mineTom: "Du har ikke sendt noe enn\xE5.",
471
+ mineIkkeSendt: "Ikke sendt enn\xE5",
472
+ mineSak: (nr) => `Sak ${nr}`,
473
+ svarFra: (leietaker) => `Svar fra ${leietaker}`,
474
+ svarFraGenerisk: "Svar",
475
+ sendNytt: "Send nytt innspill",
476
+ // Felles
477
+ tilbake: "Tilbake",
478
+ lukk: "Lukk",
479
+ venterPaaNett: "Venter p\xE5 nett \u2014 sendes automatisk"
480
+ };
481
+ var lofte = {
482
+ venterNett: "Sendes automatisk n\xE5r du er p\xE5 nett \u2014 kvitteringen kommer da.",
483
+ vurderes: (frist) => `Svar innen ${frist} \u2014 ogs\xE5 hvis det er nei.`,
484
+ vurderesUtenFrist: "Du f\xE5r svar \u2014 ogs\xE5 hvis det er nei.",
485
+ bygges: "Du f\xE5r beskjed n\xE5r den er rettet.",
486
+ planlagt: "Du f\xE5r beskjed n\xE5r den er rettet.",
487
+ rettet: "Ferdig. Ser du feilen igjen, send et nytt innspill.",
488
+ levert: "Ferdig. Takk for \xF8nsket.",
489
+ ny: "Vi har f\xE5tt den. Du h\xF8rer fra oss.",
490
+ kjentFeil: "Kjent feil. Du f\xE5r beskjed n\xE5r den er rettet.",
491
+ duplikat: "Sl\xE5tt sammen med et innspill som ligner.",
492
+ avvist: "Vi har svart p\xE5 denne."
493
+ };
494
+
495
+ // src/widget/Felt.tsx
496
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
497
+ function Felt({
498
+ spor,
499
+ verdi,
500
+ onEndre,
501
+ minTextLength,
502
+ textMaxLength,
503
+ kontekst,
504
+ fjernedeFelter,
505
+ onFjernKontekst,
506
+ lenketTil,
507
+ onFjernLenke,
508
+ funn,
509
+ onSend,
510
+ sender
511
+ }) {
512
+ const tema = useTema();
513
+ const [apen, setApen] = useState(false);
514
+ const [beholdt, setBeholdt] = useState([]);
515
+ const brukt = verdi.length;
516
+ const forKort = brukt < minTextLength;
517
+ const full = brukt >= textMaxLength;
518
+ const visTeller = brukt >= textMaxLength * 0.8;
519
+ const uavklart = funn.find((f) => !beholdt.includes(f.match));
520
+ const linjer = useMemo(() => {
521
+ const etiketter = {
522
+ screen: "Skjerm",
523
+ appVersion: "Appversjon",
524
+ platform: "Plattform",
525
+ os: "OS",
526
+ build: "Bygg",
527
+ locale: "Spr\xE5k"
528
+ };
529
+ return Object.entries(etiketter).map(([felt, etikett]) => {
530
+ const verdi2 = kontekst[felt];
531
+ return verdi2 && !fjernedeFelter.includes(felt) ? { felt, etikett, verdi: verdi2 } : null;
532
+ }).filter((x) => x !== null);
533
+ }, [kontekst, fjernedeFelter]);
534
+ return /* @__PURE__ */ jsxs2(View2, { style: { flex: 1, gap: tema.space.md }, children: [
535
+ lenketTil ? /* @__PURE__ */ jsxs2(
536
+ View2,
537
+ {
538
+ style: {
539
+ flexDirection: "row",
540
+ alignItems: "center",
541
+ gap: tema.space.sm,
542
+ minHeight: tema.touch,
543
+ borderWidth: tema.hairline,
544
+ borderColor: tema.color.borderInteractive,
545
+ borderRadius: tema.radius.pill,
546
+ paddingLeft: tema.space.md,
547
+ paddingRight: tema.space.xs
548
+ },
549
+ children: [
550
+ /* @__PURE__ */ jsx2(Text2, { style: { flex: 1, color: tema.color.textPrimary, fontSize: tema.font.small }, children: tekst.lenketTil(lenketTil.title) }),
551
+ /* @__PURE__ */ jsx2(
552
+ Pressable2,
553
+ {
554
+ testID: "fjern-lenke",
555
+ accessibilityRole: "button",
556
+ accessibilityLabel: tekst.fjernLenke,
557
+ onPress: onFjernLenke,
558
+ style: { minWidth: tema.touch, minHeight: tema.touch, alignItems: "center", justifyContent: "center" },
559
+ children: /* @__PURE__ */ jsx2(Text2, { style: { color: tema.color.textSecondary, fontSize: tema.font.small }, children: "\u2715" })
560
+ }
561
+ )
562
+ ]
563
+ }
564
+ ) : null,
565
+ uavklart ? /* @__PURE__ */ jsxs2(
566
+ View2,
567
+ {
568
+ style: {
569
+ gap: tema.space.sm,
570
+ backgroundColor: tema.color.warningBg,
571
+ borderRadius: tema.radius.md,
572
+ padding: tema.space.md
573
+ },
574
+ children: [
575
+ /* @__PURE__ */ jsx2(
576
+ Text2,
577
+ {
578
+ accessibilityRole: "alert",
579
+ accessibilityLiveRegion: "polite",
580
+ style: {
581
+ color: tema.color.warning,
582
+ fontSize: tema.font.small,
583
+ lineHeight: tema.lineHeight.small,
584
+ fontWeight: tema.weight.medium
585
+ },
586
+ children: tekst.monsterSpm[uavklart.kind]
587
+ }
588
+ ),
589
+ /* @__PURE__ */ jsxs2(View2, { style: { flexDirection: "row", gap: tema.space.sm }, children: [
590
+ /* @__PURE__ */ jsx2(
591
+ Btn,
592
+ {
593
+ grow: true,
594
+ variant: "secondary",
595
+ testID: "monster-fjern",
596
+ label: tekst.monsterFjern,
597
+ onPress: () => onEndre(verdi.slice(0, uavklart.start) + verdi.slice(uavklart.end))
598
+ }
599
+ ),
600
+ /* @__PURE__ */ jsx2(
601
+ Btn,
602
+ {
603
+ grow: true,
604
+ variant: "ghost",
605
+ testID: "monster-behold",
606
+ label: tekst.monsterBehold,
607
+ onPress: () => setBeholdt((b) => [...b, uavklart.match])
608
+ }
609
+ )
610
+ ] }),
611
+ /* @__PURE__ */ jsx2(Hint, { children: tekst.monsterForklaring })
612
+ ]
613
+ }
614
+ ) : null,
615
+ /* @__PURE__ */ jsx2(H, { children: spor === "onske" ? tekst.feltLabelOnske : tekst.feltLabelFeil }),
616
+ /* @__PURE__ */ jsx2(
617
+ TextInput,
618
+ {
619
+ testID: "innspill-tekst",
620
+ accessibilityLabel: spor === "onske" ? tekst.feltLabelOnske : tekst.feltLabelFeil,
621
+ value: verdi,
622
+ onChangeText: onEndre,
623
+ maxLength: textMaxLength,
624
+ multiline: true,
625
+ numberOfLines: 4,
626
+ placeholder: spor === "onske" ? tekst.placeholderOnske : tekst.placeholderFeil,
627
+ placeholderTextColor: tema.color.textMuted,
628
+ style: {
629
+ backgroundColor: tema.color.surfaceRaised,
630
+ borderWidth: tema.hairline,
631
+ borderColor: full ? tema.color.warning : tema.color.borderStrong,
632
+ borderRadius: tema.radius.md,
633
+ padding: tema.space.md,
634
+ color: tema.color.textPrimary,
635
+ fontSize: tema.font.body,
636
+ lineHeight: tema.lineHeight.body,
637
+ minHeight: tema.touch * 2,
638
+ textAlignVertical: "top"
639
+ }
640
+ }
641
+ ),
642
+ visTeller ? /* @__PURE__ */ jsxs2(
643
+ Text2,
644
+ {
645
+ testID: "teller",
646
+ accessibilityLiveRegion: full ? "assertive" : "polite",
647
+ style: {
648
+ alignSelf: "flex-end",
649
+ color: full ? tema.color.warning : tema.color.textMuted,
650
+ fontSize: tema.font.small
651
+ },
652
+ children: [
653
+ brukt,
654
+ " / ",
655
+ textMaxLength,
656
+ full ? tekst.tellerFull : ""
657
+ ]
658
+ }
659
+ ) : null,
660
+ /* @__PURE__ */ jsxs2(View2, { style: { borderTopWidth: tema.hairline, borderTopColor: tema.color.border, paddingTop: tema.space.sm }, children: [
661
+ /* @__PURE__ */ jsx2(
662
+ Pressable2,
663
+ {
664
+ testID: "kontekst-bryter",
665
+ accessibilityRole: "button",
666
+ accessibilityState: { expanded: apen },
667
+ accessibilityLabel: `${tekst.kontekstLinje}${apen ? "" : tekst.kontekstVis}`,
668
+ onPress: () => setApen((a) => !a),
669
+ style: { minHeight: tema.touch, justifyContent: "center" },
670
+ children: /* @__PURE__ */ jsxs2(Text2, { style: { color: tema.color.textSecondary, fontSize: tema.font.small }, children: [
671
+ apen ? "\u25B4" : "\u25BE",
672
+ " ",
673
+ tekst.kontekstLinje,
674
+ apen ? "" : tekst.kontekstVis
675
+ ] })
676
+ }
677
+ ),
678
+ apen ? /* @__PURE__ */ jsxs2(View2, { children: [
679
+ linjer.map((l) => /* @__PURE__ */ jsxs2(
680
+ View2,
681
+ {
682
+ style: {
683
+ flexDirection: "row",
684
+ alignItems: "center",
685
+ gap: tema.space.sm,
686
+ minHeight: tema.touch,
687
+ borderBottomWidth: tema.hairline,
688
+ borderBottomColor: tema.color.border
689
+ },
690
+ children: [
691
+ /* @__PURE__ */ jsx2(Text2, { style: { color: tema.color.textMuted, fontSize: tema.font.small, minWidth: tema.touch * 2 }, children: l.etikett }),
692
+ /* @__PURE__ */ jsx2(Text2, { style: { flex: 1, color: tema.color.textPrimary, fontSize: tema.font.small }, children: l.verdi }),
693
+ /* @__PURE__ */ jsx2(
694
+ Pressable2,
695
+ {
696
+ testID: `fjern-${l.felt}`,
697
+ accessibilityRole: "button",
698
+ accessibilityLabel: `${tekst.kontekstFjern} ${l.etikett.toLowerCase()} fra innsendingen`,
699
+ onPress: () => onFjernKontekst(l.felt),
700
+ style: { minWidth: tema.touch, minHeight: tema.touch, alignItems: "center", justifyContent: "center" },
701
+ children: /* @__PURE__ */ jsxs2(Text2, { style: { color: tema.color.textSecondary, fontSize: tema.font.small }, children: [
702
+ "\u2715 ",
703
+ tekst.kontekstFjern
704
+ ] })
705
+ }
706
+ )
707
+ ]
708
+ },
709
+ l.felt
710
+ )),
711
+ /* @__PURE__ */ jsx2(View2, { style: { paddingTop: tema.space.sm }, children: /* @__PURE__ */ jsx2(Hint, { children: tekst.kontekstAldri }) })
712
+ ] }) : null
713
+ ] }),
714
+ /* @__PURE__ */ jsx2(View2, { style: { flex: 1, justifyContent: "flex-end" }, children: /* @__PURE__ */ jsx2(
715
+ Btn,
716
+ {
717
+ testID: "send",
718
+ label: spor === "onske" && !forKort ? tekst.nesteOnske : tekst.send,
719
+ disabled: forKort || sender,
720
+ hint: forKort ? tekst.forKort(minTextLength) : void 0,
721
+ onPress: onSend
722
+ }
723
+ ) })
724
+ ] });
725
+ }
726
+
727
+ // src/widget/Valg.tsx
728
+ import "react";
729
+ import { Pressable as Pressable3, Text as Text3, View as View3 } from "react-native";
730
+ import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
731
+ function Valg({ onVelg }) {
732
+ const tema = useTema();
733
+ const flate = (spor, ikon, label, under) => /* @__PURE__ */ jsxs3(
734
+ Pressable3,
735
+ {
736
+ testID: `spor-${spor}`,
737
+ accessibilityRole: "button",
738
+ accessibilityLabel: `${label}. ${under}`,
739
+ onPress: () => onVelg(spor),
740
+ style: {
741
+ flex: 1,
742
+ minHeight: tema.touch * 3,
743
+ backgroundColor: tema.color.surface,
744
+ borderWidth: tema.hairline,
745
+ borderColor: tema.color.borderStrong,
746
+ borderRadius: tema.radius.lg,
747
+ alignItems: "center",
748
+ justifyContent: "center",
749
+ gap: tema.space.sm,
750
+ padding: tema.space.md
751
+ },
752
+ children: [
753
+ /* @__PURE__ */ jsx3(Text3, { accessibilityElementsHidden: true, importantForAccessibility: "no", style: { fontSize: tema.font.h1 }, children: ikon }),
754
+ /* @__PURE__ */ jsx3(
755
+ Text3,
756
+ {
757
+ style: {
758
+ color: tema.color.textPrimary,
759
+ fontSize: tema.font.h3,
760
+ fontWeight: tema.weight.semibold,
761
+ textAlign: "center"
762
+ },
763
+ children: label
764
+ }
765
+ ),
766
+ /* @__PURE__ */ jsx3(Text3, { style: { color: tema.color.textMuted, fontSize: tema.font.small, textAlign: "center" }, children: under })
767
+ ]
768
+ }
769
+ );
770
+ return /* @__PURE__ */ jsxs3(View3, { style: { flex: 1, gap: tema.space.lg }, children: [
771
+ /* @__PURE__ */ jsx3(H, { sub: tekst.valgUnder, children: tekst.valgTittel }),
772
+ /* @__PURE__ */ jsx3(View3, { style: { flex: 1, justifyContent: "flex-end" }, children: /* @__PURE__ */ jsxs3(View3, { style: { flexDirection: "row", gap: tema.space.md }, children: [
773
+ flate("feil", "\u{1F41E}", tekst.sporFeil, tekst.sporFeilUnder),
774
+ flate("onske", "\u{1F4A1}", tekst.sporOnske, tekst.sporOnskeUnder)
775
+ ] }) })
776
+ ] });
777
+ }
778
+
779
+ // src/widget/KjenteFeil.tsx
780
+ import "react";
781
+ import { ActivityIndicator, Text as Text4, View as View4 } from "react-native";
782
+ import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
783
+ function KjenteFeil({
784
+ kort,
785
+ spor,
786
+ laster,
787
+ onJaOgsa,
788
+ onLigner,
789
+ onNei
790
+ }) {
791
+ const tema = useTema();
792
+ if (laster) {
793
+ return /* @__PURE__ */ jsxs4(View4, { style: { flex: 1, gap: tema.space.md }, children: [
794
+ /* @__PURE__ */ jsx4(H, { sub: spor === "onske" ? tekst.kjenteFeilUnderOnske : tekst.kjenteFeilUnderFeil, children: spor === "onske" ? tekst.kjenteFeilTittelOnske : tekst.kjenteFeilTittelFeil }),
795
+ /* @__PURE__ */ jsx4(ActivityIndicator, { accessibilityLabel: "Sjekker kjente feil", color: tema.color.textSecondary })
796
+ ] });
797
+ }
798
+ return /* @__PURE__ */ jsxs4(View4, { style: { flex: 1, gap: tema.space.md }, children: [
799
+ /* @__PURE__ */ jsx4(H, { sub: spor === "onske" ? tekst.kjenteFeilUnderOnske : tekst.kjenteFeilUnderFeil, children: spor === "onske" ? tekst.kjenteFeilTittelOnske : tekst.kjenteFeilTittelFeil }),
800
+ kort.map((k) => {
801
+ const versjon = k.fixedIn ? k.status === "fikset" ? tekst.rettetI(k.fixedIn) : tekst.rettesI(k.fixedIn) : void 0;
802
+ const kontekst = versjon ? `${k.title}. ${versjon}` : k.title;
803
+ return /* @__PURE__ */ jsxs4(Card, { children: [
804
+ /* @__PURE__ */ jsx4(
805
+ Text4,
806
+ {
807
+ style: {
808
+ color: tema.color.textPrimary,
809
+ fontSize: tema.font.body,
810
+ lineHeight: tema.lineHeight.body,
811
+ fontWeight: tema.weight.medium
812
+ },
813
+ children: k.title
814
+ }
815
+ ),
816
+ k.workaround ? /* @__PURE__ */ jsxs4(
817
+ Text4,
818
+ {
819
+ style: {
820
+ color: tema.color.textSecondary,
821
+ fontSize: tema.font.small,
822
+ lineHeight: tema.lineHeight.small
823
+ },
824
+ children: [
825
+ tekst.omvei,
826
+ " ",
827
+ k.workaround
828
+ ]
829
+ }
830
+ ) : null,
831
+ versjon ? /* @__PURE__ */ jsx4(
832
+ StatusPill,
833
+ {
834
+ ikon: k.status === "fikset" ? "\u2713" : "\u{1F527}",
835
+ etikett: versjon,
836
+ farge: k.status === "fikset" ? "success" : "info"
837
+ }
838
+ ) : null,
839
+ /* @__PURE__ */ jsxs4(View4, { style: { flexDirection: "row", gap: tema.space.sm }, children: [
840
+ /* @__PURE__ */ jsx4(
841
+ Btn,
842
+ {
843
+ grow: true,
844
+ testID: `ja-ogsa-${k.id}`,
845
+ label: tekst.svarJa,
846
+ accessibilityLabel: `${tekst.svarJa}. ${kontekst}`,
847
+ onPress: () => onJaOgsa(k)
848
+ }
849
+ ),
850
+ /* @__PURE__ */ jsx4(
851
+ Btn,
852
+ {
853
+ grow: true,
854
+ variant: "secondary",
855
+ testID: `ligner-${k.id}`,
856
+ label: tekst.svarLigner,
857
+ accessibilityLabel: `${tekst.svarLigner}. ${kontekst}`,
858
+ onPress: () => onLigner(k)
859
+ }
860
+ )
861
+ ] })
862
+ ] }, k.id);
863
+ }),
864
+ /* @__PURE__ */ jsx4(Btn, { variant: "secondary", testID: "nei-noe-annet", label: tekst.svarNei, onPress: onNei })
865
+ ] });
866
+ }
867
+
868
+ // src/widget/Kvittering.tsx
869
+ import "react";
870
+ import { Text as Text5, View as View5 } from "react-native";
871
+ import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
872
+ function Kvittering({
873
+ art,
874
+ saksnummer,
875
+ onLukk
876
+ }) {
877
+ const tema = useTema();
878
+ const innhold = {
879
+ feil: { h: tekst.kvitteringSendt, p: tekst.kvitteringFeil },
880
+ onske: { h: tekst.kvitteringSendt, p: tekst.kvitteringOnske },
881
+ jaOgsa: { h: tekst.kvitteringRegistrert, p: tekst.kvitteringJaOgsa },
882
+ // Køet offline: kvitteringen kan IKKE love svar på noe som ikke er sendt
883
+ // (DD-41 presiserer DD-07). Den lover bare at det sendes.
884
+ k\u00F8: { h: tekst.offlineTittel, p: tekst.offlineBanner }
885
+ }[art];
886
+ return /* @__PURE__ */ jsxs5(View5, { style: { flex: 1, justifyContent: "center", gap: tema.space.lg }, children: [
887
+ /* @__PURE__ */ jsxs5(View5, { style: { alignItems: "center", gap: tema.space.md }, children: [
888
+ /* @__PURE__ */ jsx5(
889
+ Text5,
890
+ {
891
+ accessibilityElementsHidden: true,
892
+ importantForAccessibility: "no",
893
+ style: { fontSize: tema.font.h1 * 2, color: art === "k\xF8" ? tema.color.neutral : tema.color.success },
894
+ children: art === "k\xF8" ? "\u21C5" : "\u2713"
895
+ }
896
+ ),
897
+ /* @__PURE__ */ jsx5(H, { children: innhold.h }),
898
+ /* @__PURE__ */ jsx5(
899
+ Text5,
900
+ {
901
+ testID: "kvittering-tekst",
902
+ accessibilityRole: "alert",
903
+ accessibilityLiveRegion: "polite",
904
+ style: {
905
+ color: tema.color.textPrimary,
906
+ fontSize: tema.font.body,
907
+ lineHeight: tema.lineHeight.body,
908
+ textAlign: "center"
909
+ },
910
+ children: innhold.p
911
+ }
912
+ ),
913
+ saksnummer ? /* @__PURE__ */ jsx5(Hint, { children: tekst.saksnummer(saksnummer) }) : null
914
+ ] }),
915
+ /* @__PURE__ */ jsx5(Btn, { testID: "tilbake-til-appen", label: tekst.tilbakeTilAppen, onPress: onLukk })
916
+ ] });
917
+ }
918
+
919
+ // src/widget/MineInnspill.tsx
920
+ import "react";
921
+ import { ActivityIndicator as ActivityIndicator2, ScrollView, Text as Text6, View as View6 } from "react-native";
922
+
923
+ // src/widget/status.ts
924
+ var IKON = {
925
+ ny: "\u23F1",
926
+ vurderes: "\u23F1",
927
+ planlagt: "\u{1F4C5}",
928
+ bygges: "\u{1F527}",
929
+ levert: "\u2713",
930
+ kjent_feil: "\u{1F441}",
931
+ duplikat: "\u2715",
932
+ avvist: "\u2715",
933
+ venterNett: "\u23F3"
934
+ };
935
+ function formaterFrist(iso) {
936
+ const d = new Date(iso);
937
+ if (Number.isNaN(d.getTime())) return iso;
938
+ return new Intl.DateTimeFormat("nb-NO", { day: "numeric", month: "long" }).format(d);
939
+ }
940
+ function statusVisning(status, type, deadlineAt) {
941
+ switch (status) {
942
+ case "ny":
943
+ return { ikon: IKON.ny, etikett: "Mottatt", farge: "neutral", lofte: lofte.ny };
944
+ case "vurderes":
945
+ return {
946
+ ikon: IKON.vurderes,
947
+ etikett: "Vurderes",
948
+ farge: "warning",
949
+ lofte: deadlineAt ? lofte.vurderes(formaterFrist(deadlineAt)) : lofte.vurderesUtenFrist
950
+ };
951
+ case "planlagt":
952
+ return { ikon: IKON.planlagt, etikett: "Planlagt", farge: "success", lofte: lofte.planlagt };
953
+ case "bygges":
954
+ return { ikon: IKON.bygges, etikett: "Retter n\xE5", farge: "info", lofte: lofte.bygges };
955
+ case "levert":
956
+ return type === "onske" ? { ikon: IKON.levert, etikett: "Levert", farge: "success", lofte: lofte.levert } : { ikon: IKON.levert, etikett: "Rettet", farge: "success", lofte: lofte.rettet };
957
+ case "kjent_feil":
958
+ return {
959
+ ikon: IKON.kjent_feil,
960
+ etikett: "Kjent, ikke planlagt",
961
+ farge: "neutral",
962
+ lofte: lofte.kjentFeil
963
+ };
964
+ case "duplikat":
965
+ return { ikon: IKON.duplikat, etikett: "Sl\xE5tt sammen", farge: "neutral", lofte: lofte.duplikat };
966
+ case "avvist":
967
+ return { ikon: IKON.avvist, etikett: "Avvist", farge: "danger", lofte: lofte.avvist };
968
+ }
969
+ }
970
+ var venterVisning = {
971
+ ikon: IKON.venterNett,
972
+ etikett: "Venter p\xE5 nett",
973
+ farge: "neutral",
974
+ lofte: lofte.venterNett
975
+ };
976
+
977
+ // src/widget/MineInnspill.tsx
978
+ import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
979
+ function MineInnspill({
980
+ rader,
981
+ laster,
982
+ tenantName,
983
+ onNytt
984
+ }) {
985
+ const tema = useTema();
986
+ return /* @__PURE__ */ jsxs6(View6, { style: { flex: 1, gap: tema.space.md }, children: [
987
+ /* @__PURE__ */ jsx6(H, { sub: tekst.mineUnder, children: tekst.mineTittel }),
988
+ laster ? /* @__PURE__ */ jsx6(ActivityIndicator2, { accessibilityLabel: "Henter innspillene dine", color: tema.color.textSecondary }) : rader.length === 0 ? /* @__PURE__ */ jsx6(Hint, { children: tekst.mineTom }) : /* @__PURE__ */ jsx6(ScrollView, { style: { flex: 1 }, contentContainerStyle: { gap: tema.space.sm }, children: rader.map((rad) => {
989
+ const venter = rad.pending === true;
990
+ const v = venter ? venterVisning : statusVisning(rad.status, rad.type, rad.deadlineAt);
991
+ const nokkel = venter ? rad.clientRef : rad.id;
992
+ const svar = venter ? void 0 : rad.reply;
993
+ return /* @__PURE__ */ jsxs6(Card, { dashed: venter, children: [
994
+ /* @__PURE__ */ jsxs6(Hint, { children: [
995
+ venter ? tekst.mineIkkeSendt : tekst.mineSak(rad.id),
996
+ " \xB7",
997
+ " ",
998
+ rad.type === "onske" ? "\xF8nske" : "feil"
999
+ ] }),
1000
+ /* @__PURE__ */ jsx6(
1001
+ Text6,
1002
+ {
1003
+ style: {
1004
+ color: tema.color.textPrimary,
1005
+ fontSize: tema.font.body,
1006
+ lineHeight: tema.lineHeight.body
1007
+ },
1008
+ children: rad.text
1009
+ }
1010
+ ),
1011
+ /* @__PURE__ */ jsxs6(View6, { style: { gap: tema.space.xs }, children: [
1012
+ /* @__PURE__ */ jsx6(StatusPill, { ikon: v.ikon, etikett: v.etikett, farge: v.farge }),
1013
+ /* @__PURE__ */ jsx6(Hint, { children: v.lofte })
1014
+ ] }),
1015
+ svar ? /* @__PURE__ */ jsxs6(
1016
+ View6,
1017
+ {
1018
+ style: {
1019
+ borderLeftWidth: tema.hairline * 2,
1020
+ borderLeftColor: tema.color.brand,
1021
+ paddingLeft: tema.space.sm,
1022
+ gap: tema.space.xs
1023
+ },
1024
+ children: [
1025
+ /* @__PURE__ */ jsx6(Text6, { style: { color: tema.color.textSecondary, fontSize: tema.font.small }, children: tenantName ? tekst.svarFra(tenantName) : tekst.svarFraGenerisk }),
1026
+ /* @__PURE__ */ jsx6(
1027
+ Text6,
1028
+ {
1029
+ style: {
1030
+ color: tema.color.textPrimary,
1031
+ fontSize: tema.font.small,
1032
+ lineHeight: tema.lineHeight.small
1033
+ },
1034
+ children: svar.text
1035
+ }
1036
+ )
1037
+ ]
1038
+ }
1039
+ ) : null
1040
+ ] }, nokkel);
1041
+ }) }),
1042
+ /* @__PURE__ */ jsx6(Btn, { testID: "send-nytt", label: tekst.sendNytt, onPress: onNytt })
1043
+ ] });
1044
+ }
1045
+
1046
+ // src/widget/Widget.tsx
1047
+ import { Fragment, jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
1048
+ function Widget({
1049
+ client,
1050
+ synlig,
1051
+ apneOpsjoner,
1052
+ onLukk,
1053
+ tenantName
1054
+ }) {
1055
+ const tema = useTema();
1056
+ const [steg, setSteg] = useState2("valg");
1057
+ const [spor, setSpor] = useState2("feil");
1058
+ const [verdi, setVerdi] = useState2("");
1059
+ const [kort, setKort] = useState2([]);
1060
+ const [lasterKort, setLasterKort] = useState2(false);
1061
+ const [lenketTil, setLenketTil] = useState2();
1062
+ const [funn, setFunn] = useState2([]);
1063
+ const [fjernede, setFjernede] = useState2([]);
1064
+ const [sender, setSender] = useState2(false);
1065
+ const [feil, setFeil] = useState2();
1066
+ const [kvittering, setKvittering] = useState2();
1067
+ const [mine, setMine] = useState2([]);
1068
+ const [lasterMine, setLasterMine] = useState2(false);
1069
+ const nullstill = useCallback(() => {
1070
+ setSteg("valg");
1071
+ setSpor("feil");
1072
+ setVerdi("");
1073
+ setKort([]);
1074
+ setLenketTil(void 0);
1075
+ setFunn([]);
1076
+ setFjernede([]);
1077
+ setFeil(void 0);
1078
+ setKvittering(void 0);
1079
+ }, []);
1080
+ const lukk = useCallback(() => {
1081
+ onLukk();
1082
+ nullstill();
1083
+ }, [onLukk, nullstill]);
1084
+ useEffect(() => {
1085
+ if (!synlig) return;
1086
+ client.track({ name: "widget_opened" });
1087
+ void client.queue.flush().catch(() => void 0);
1088
+ if (apneOpsjoner?.track) velgSpor(apneOpsjoner.track);
1089
+ }, [synlig]);
1090
+ const hentKort = useCallback(async () => {
1091
+ setLasterKort(true);
1092
+ try {
1093
+ const q = apneOpsjoner?.screen ? { screen: apneOpsjoner.screen } : {};
1094
+ setKort(await client.knownIssues.for(q));
1095
+ } finally {
1096
+ setLasterKort(false);
1097
+ }
1098
+ }, [client, apneOpsjoner?.screen]);
1099
+ const velgSpor = useCallback(
1100
+ async (valgt) => {
1101
+ setSpor(valgt);
1102
+ client.track({ name: "track_selected", type: valgt });
1103
+ if (valgt === "onske") {
1104
+ setSteg("felt");
1105
+ return;
1106
+ }
1107
+ setSteg("kjenteFeil");
1108
+ await hentKort();
1109
+ },
1110
+ [client, hentKort]
1111
+ );
1112
+ useEffect(() => {
1113
+ if (steg === "kjenteFeil" && !lasterKort && kort.length === 0) setSteg("felt");
1114
+ }, [steg, lasterKort, kort.length]);
1115
+ const endreTekst = useCallback(
1116
+ (v) => {
1117
+ setVerdi(v);
1118
+ setFunn(client.scanText(v));
1119
+ },
1120
+ [client]
1121
+ );
1122
+ const send = useCallback(async () => {
1123
+ if (spor === "onske" && steg === "felt" && kort.length === 0 && !lasterKort) {
1124
+ setSteg("kjenteFeil");
1125
+ await hentKort();
1126
+ return;
1127
+ }
1128
+ setSender(true);
1129
+ setFeil(void 0);
1130
+ try {
1131
+ const res = await client.capture({
1132
+ type: spor,
1133
+ text: verdi,
1134
+ ...spor === "feil" && lenketTil ? { relatedKnownIssueId: lenketTil.id } : {},
1135
+ ...fjernede.length ? { context: fjernetKontekst(client, fjernede) } : {}
1136
+ });
1137
+ if (res.status === "queued") {
1138
+ setKvittering({ art: "k\xF8" });
1139
+ } else {
1140
+ setKvittering({ art: spor, nr: res.submission.id });
1141
+ }
1142
+ setSteg("kvittering");
1143
+ } catch (e) {
1144
+ if (e instanceof InnspelQueueFullError) setFeil(e.userMessage);
1145
+ else if (e instanceof InnspelApiError) setFeil(e.message);
1146
+ else setFeil("tjeneren svarte ikke.");
1147
+ } finally {
1148
+ setSender(false);
1149
+ }
1150
+ }, [client, spor, steg, verdi, lenketTil, fjernede, kort.length, lasterKort, hentKort]);
1151
+ const jaOgsa = useCallback(
1152
+ async (k) => {
1153
+ setSender(true);
1154
+ try {
1155
+ const res = await client.knownIssues.confirm(k.id);
1156
+ setKvittering({ art: "jaOgsa", nr: res.id });
1157
+ setSteg("kvittering");
1158
+ } catch (e) {
1159
+ setFeil(e instanceof InnspelApiError ? e.message : "tjeneren svarte ikke.");
1160
+ } finally {
1161
+ setSender(false);
1162
+ }
1163
+ },
1164
+ [client]
1165
+ );
1166
+ const visMine = useCallback(async () => {
1167
+ setSteg("mine");
1168
+ setLasterMine(true);
1169
+ try {
1170
+ setMine(await client.subjects.submissions());
1171
+ } catch {
1172
+ setMine([]);
1173
+ } finally {
1174
+ setLasterMine(false);
1175
+ }
1176
+ }, [client]);
1177
+ return /* @__PURE__ */ jsx7(
1178
+ Modal,
1179
+ {
1180
+ visible: synlig,
1181
+ transparent: true,
1182
+ animationType: "slide",
1183
+ onRequestClose: lukk,
1184
+ accessibilityViewIsModal: true,
1185
+ children: /* @__PURE__ */ jsx7(View7, { style: { flex: 1, backgroundColor: tema.color.scrim, justifyContent: "flex-end" }, children: /* @__PURE__ */ jsxs7(
1186
+ View7,
1187
+ {
1188
+ testID: "innspel-widget",
1189
+ accessibilityViewIsModal: true,
1190
+ accessibilityRole: "none",
1191
+ style: {
1192
+ backgroundColor: tema.color.bg,
1193
+ borderTopLeftRadius: tema.radius.lg * 2,
1194
+ borderTopRightRadius: tema.radius.lg * 2,
1195
+ padding: tema.screenPadding,
1196
+ gap: tema.space.md,
1197
+ maxHeight: "92%",
1198
+ minHeight: "60%"
1199
+ },
1200
+ children: [
1201
+ /* @__PURE__ */ jsxs7(View7, { style: { flexDirection: "row", justifyContent: "space-between", alignItems: "center" }, children: [
1202
+ steg !== "valg" && steg !== "kvittering" ? /* @__PURE__ */ jsx7(Btn, { variant: "ghost", testID: "tilbake", ikon: "\u2190", label: tekst.tilbake, onPress: nullstill }) : /* @__PURE__ */ jsx7(View7, {}),
1203
+ /* @__PURE__ */ jsx7(
1204
+ Pressable4,
1205
+ {
1206
+ testID: "lukk",
1207
+ accessibilityRole: "button",
1208
+ accessibilityLabel: tekst.lukk,
1209
+ onPress: lukk,
1210
+ style: { minWidth: tema.touch, minHeight: tema.touch, alignItems: "center", justifyContent: "center" },
1211
+ children: /* @__PURE__ */ jsx7(Text7, { style: { color: tema.color.textSecondary, fontSize: tema.font.body }, children: "\u2715" })
1212
+ }
1213
+ )
1214
+ ] }),
1215
+ feil ? /* @__PURE__ */ jsx7(Banner, { live: true, ikon: "\u26A0", tone: "danger", children: tekst.sendefeilBanner(feil) }) : null,
1216
+ steg === "valg" ? /* @__PURE__ */ jsxs7(Fragment, { children: [
1217
+ /* @__PURE__ */ jsx7(Valg, { onVelg: velgSpor }),
1218
+ /* @__PURE__ */ jsx7(Btn, { variant: "ghost", testID: "mine-innspill", ikon: "\u{1F4CB}", label: tekst.mineTittel, onPress: visMine })
1219
+ ] }) : null,
1220
+ steg === "kjenteFeil" ? /* @__PURE__ */ jsx7(
1221
+ KjenteFeil,
1222
+ {
1223
+ kort,
1224
+ spor,
1225
+ laster: lasterKort,
1226
+ onJaOgsa: jaOgsa,
1227
+ onLigner: (k) => {
1228
+ setLenketTil(k);
1229
+ setSteg("felt");
1230
+ },
1231
+ onNei: () => spor === "onske" ? void send() : setSteg("felt")
1232
+ }
1233
+ ) : null,
1234
+ steg === "felt" ? /* @__PURE__ */ jsx7(
1235
+ Felt,
1236
+ {
1237
+ spor,
1238
+ verdi,
1239
+ onEndre: endreTekst,
1240
+ minTextLength: client.settings.minTextLength,
1241
+ textMaxLength: client.settings.textMaxLength,
1242
+ kontekst: client.context,
1243
+ fjernedeFelter: fjernede,
1244
+ onFjernKontekst: (f) => setFjernede((x) => [...x, f]),
1245
+ ...lenketTil ? { lenketTil, onFjernLenke: () => setLenketTil(void 0) } : {},
1246
+ funn,
1247
+ onSend: send,
1248
+ sender
1249
+ }
1250
+ ) : null,
1251
+ steg === "kvittering" && kvittering ? /* @__PURE__ */ jsx7(Kvittering, { art: kvittering.art, ...kvittering.nr ? { saksnummer: kvittering.nr } : {}, onLukk: lukk }) : null,
1252
+ steg === "mine" ? /* @__PURE__ */ jsx7(
1253
+ MineInnspill,
1254
+ {
1255
+ rader: mine,
1256
+ laster: lasterMine,
1257
+ ...tenantName ? { tenantName } : {},
1258
+ onNytt: nullstill
1259
+ }
1260
+ ) : null
1261
+ ]
1262
+ }
1263
+ ) })
1264
+ }
1265
+ );
1266
+ }
1267
+ function fjernetKontekst(client, fjernede) {
1268
+ const ut = {};
1269
+ for (const [k, v] of Object.entries(client.context)) {
1270
+ if (k !== "sdkVersion" && !fjernede.includes(k)) ut[k] = v;
1271
+ }
1272
+ return ut;
1273
+ }
1274
+
1275
+ // src/InnspelProvider.tsx
1276
+ import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
1277
+ var Kontekst = createContext2(null);
1278
+ function InnspelProvider({
1279
+ client,
1280
+ children,
1281
+ theme,
1282
+ colorScheme = "dark",
1283
+ tenantName
1284
+ }) {
1285
+ const [synlig, setSynlig] = useState3(false);
1286
+ const [apneOpsjoner, setApneOpsjoner] = useState3();
1287
+ const registrert = useRef(false);
1288
+ const open = useCallback2(
1289
+ async (options) => {
1290
+ setApneOpsjoner(options);
1291
+ setSynlig(true);
1292
+ },
1293
+ []
1294
+ );
1295
+ const close = useCallback2(() => setSynlig(false), []);
1296
+ if (!registrert.current) {
1297
+ client.registerPresenter({ open });
1298
+ registrert.current = true;
1299
+ }
1300
+ const tema = useMemo2(() => byggTema(theme, colorScheme), [theme, colorScheme]);
1301
+ const verdi = useMemo2(() => ({ client, open, close }), [client, open, close]);
1302
+ return /* @__PURE__ */ jsx8(Kontekst.Provider, { value: verdi, children: /* @__PURE__ */ jsxs8(TemaProvider, { value: tema, children: [
1303
+ children,
1304
+ /* @__PURE__ */ jsx8(
1305
+ Widget,
1306
+ {
1307
+ client,
1308
+ synlig,
1309
+ ...apneOpsjoner ? { apneOpsjoner } : {},
1310
+ ...tenantName ? { tenantName } : {},
1311
+ onLukk: close
1312
+ }
1313
+ )
1314
+ ] }) });
1315
+ }
1316
+ function useInnspel() {
1317
+ const k = useContext2(Kontekst);
1318
+ if (!k) {
1319
+ throw new Error(
1320
+ "[innspel] useInnspel() ble kalt utenfor <InnspelProvider>. Pakk appen din i den \u2014 se README.md."
1321
+ );
1322
+ }
1323
+ return k;
1324
+ }
1325
+
1326
+ // src/lagring.ts
1327
+ function createStorage(pakke) {
1328
+ return {
1329
+ get: (key) => pakke.getItem(key),
1330
+ set: (key, value) => pakke.setItem(key, value),
1331
+ remove: (key) => pakke.removeItem(key)
1332
+ };
1333
+ }
1334
+ function createMemoryStorage() {
1335
+ const rader = /* @__PURE__ */ new Map();
1336
+ return {
1337
+ get: async (key) => rader.get(key) ?? null,
1338
+ set: async (key, value) => {
1339
+ rader.set(key, value);
1340
+ },
1341
+ remove: async (key) => {
1342
+ rader.delete(key);
1343
+ }
1344
+ };
1345
+ }
1346
+ export {
1347
+ InnspelProvider,
1348
+ byggTema,
1349
+ createMemoryStorage,
1350
+ createStorage,
1351
+ t as darkTokens,
1352
+ light,
1353
+ lofte,
1354
+ screenRules,
1355
+ statusVisning,
1356
+ tekst,
1357
+ useInnspel,
1358
+ useTema,
1359
+ venterVisning
1360
+ };
1361
+ //# sourceMappingURL=index.js.map