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