@innspel/react-native 0.9.0 → 0.9.2

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/README.md CHANGED
@@ -73,6 +73,18 @@ innsenderen får se før hun skriver.
73
73
  Utenfor React — en navigasjonshandler, en krasjlytter — bruker du klienten
74
74
  direkte: `innspel.openFeedback({ screen: 'Dørlista' })`.
75
75
 
76
+ Lukking — X, eller Android-tilbake på første steg — beholder det innsenderen har
77
+ skrevet til widgeten åpnes igjen; bare en fullført innsending nullstiller. Åpner du med
78
+ `track` mens det står et utkast, står hun der hun var. `view: 'mine'` legges over
79
+ utkastet, og «Tilbake» i lista lukker.
80
+
81
+ **Legg provideren rundt appen, ikke inni en `ScrollView`.** Arket er en `Modal`, men
82
+ React Natives trykkhåndtering går gjennom React-treet: en `ScrollView` over provideren
83
+ med `keyboardShouldPersistTaps` på standardverdien tar første trykk mens tastaturet er
84
+ oppe, og bruker det til å lukke tastaturet. Send teller det trykket likevel; de andre
85
+ knappene i arket gjør ikke. Må provideren stå inni en scrollflate, gi den
86
+ `keyboardShouldPersistTaps="handled"`.
87
+
76
88
  ## Token-endepunktet
77
89
 
78
90
  Det eneste du må bygge selv. Se
package/dist/index.cjs CHANGED
@@ -407,11 +407,14 @@ var arrow_back_outline_default = '<svg xmlns="http://www.w3.org/2000/svg" viewBo
407
407
  // ../../node_modules/ionicons/dist/svg/brush-outline.svg
408
408
  var brush_outline_default = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" class="ionicon"><path d="M452.37 59.63a40.49 40.49 0 0 0-57.26 0L184 294.74c23.08 4.7 46.12 27.29 49.26 49.26l219.11-227.11a40.49 40.49 0 0 0 0-57.26M138 336c-29.88 0-54 24.5-54 54.86 0 23.95-20.88 36.57-36 36.57C64.56 449.74 92.82 464 120 464c39.78 0 72-32.73 72-73.14 0-30.36-24.12-54.86-54-54.86" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32px"/></svg>';
409
409
 
410
+ // ../../node_modules/ionicons/dist/svg/bug.svg
411
+ var bug_default = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" class="ionicon"><path d="M463.55 272.13H400v-48.2q0-4.32-.27-8.47c29.57-27.88 32.25-64.63 32.27-103 0-8.61-6.64-16-15.25-16.41A16 16 0 0 0 400 112c0 28-1.86 48.15-9.9 63.84-19.22-41.15-65.78-63.91-134.1-63.91-39.8 0-74.19 9.13-99.43 26.39-14.9 10.19-26.2 22.91-33.7 37.72C114 160.65 112 141 112 112.46c0-8.61-6.6-16-15.2-16.44A16 16 0 0 0 80 112c0 37.63 2.61 73.73 32.44 101.63q-.43 5.06-.44 10.3v48.2H48.45c-8.61 0-16 6.62-16.43 15.23a16 16 0 0 0 16 16.77h64V320a143.3 143.3 0 0 0 10.39 53.69C96.74 396.64 80.18 422 80 463.34c0 8.74 6.62 16.3 15.36 16.65A16 16 0 0 0 112 464c0-27.66 9.1-44.71 26.17-61.32A144.37 144.37 0 0 0 220 459.42a16 16 0 0 0 20-15.49V192.45c0-8.61 6.62-16 15.23-16.43A16 16 0 0 1 272 192v251.93a16 16 0 0 0 20 15.49 144.4 144.4 0 0 0 81.82-56.74c17 16.54 26.09 33.52 26.17 60.95a16.27 16.27 0 0 0 15.1 16.37A16 16 0 0 0 432 464c0-41.68-16.6-67.23-42.39-90.31A143.3 143.3 0 0 0 400 320v-15.87h64a16 16 0 0 0 16-16.77c-.42-8.61-7.84-15.23-16.45-15.23"/><path d="m321.39 104 .32.09c13.57 3.8 25.07-10.55 18.2-22.85A95.86 95.86 0 0 0 256.21 32h-.42a95.87 95.87 0 0 0-84.19 50.13c-6.84 12.58 5.14 27 18.84 22.86 19.71-6 41.79-9.06 65.56-9.06 24.09 0 46.09 2.72 65.39 8.07"/></svg>';
412
+
410
413
  // ../../node_modules/ionicons/dist/svg/bug-outline.svg
411
414
  var bug_outline_default = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" class="ionicon"><path d="M370 378c28.89 23.52 46 46.07 46 86M142 378c-28.89 23.52-46 46.06-46 86M384 208c28.89-23.52 32-56.07 32-96M128 206c-28.89-23.52-32-54.06-32-94M464 288.13h-80M128 288.13H48M256 192v256" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32px"/><path d="M256 448c-70.4 0-128-57.6-128-128v-96.07c0-65.07 57.6-96 128-96h0c70.4 0 128 25.6 128 96V320c0 70.4-57.6 128-128 128" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32px"/><path d="M179.43 143.52a49.1 49.1 0 0 1-3.43-15.73A80 80 0 0 1 255.79 48h.42A80 80 0 0 1 336 127.79a41.9 41.9 0 0 1-3.12 14.3" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32px"/></svg>';
412
415
 
413
- // ../../node_modules/ionicons/dist/svg/bulb-outline.svg
414
- var bulb_outline_default = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" class="ionicon"><path d="M304 384v-24c0-29 31.54-56.43 52-76 28.84-27.57 44-64.61 44-108 0-80-63.73-144-144-144a143.6 143.6 0 0 0-144 144c0 41.84 15.81 81.39 44 108 20.35 19.21 52 46.7 52 76v24M224 480h64M208 432h96M256 384V256" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32px"/><path d="M294 240s-21.51 16-38 16-38-16-38-16" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32px"/></svg>';
416
+ // ../../node_modules/ionicons/dist/svg/bulb.svg
417
+ var bulb_default = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" class="ionicon"><path d="M288 464h-64a16 16 0 0 0 0 32h64a16 16 0 0 0 0-32M304 416h-96a16 16 0 0 0 0 32h96a16 16 0 0 0 0-32M369.42 62.69C339.35 32.58 299.07 16 256 16A159.62 159.62 0 0 0 96 176c0 46.62 17.87 90.23 49 119.64l4.36 4.09C167.37 316.57 192 339.64 192 360v24a16 16 0 0 0 16 16h24a8 8 0 0 0 8-8V274.82a8 8 0 0 0-5.13-7.47A130.7 130.7 0 0 1 208.71 253a16 16 0 1 1 18.58-26c7.4 5.24 21.65 13 28.71 13s21.31-7.78 28.73-13a16 16 0 0 1 18.56 26 130.7 130.7 0 0 1-26.16 14.32 8 8 0 0 0-5.13 7.47V392a8 8 0 0 0 8 8h24a16 16 0 0 0 16-16v-24c0-19.88 24.36-42.93 42.15-59.77l4.91-4.66C399.08 265 416 223.61 416 176a159.16 159.16 0 0 0-46.58-113.31"/></svg>';
415
418
 
416
419
  // ../../node_modules/ionicons/dist/svg/calendar-outline.svg
417
420
  var calendar_outline_default = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" class="ionicon"><rect width="416" height="384" x="48" y="80" fill="none" stroke="currentColor" stroke-linejoin="round" stroke-width="32" rx="48"/><circle cx="296" cy="232" r="24"/><circle cx="376" cy="232" r="24"/><circle cx="296" cy="312" r="24"/><circle cx="376" cy="312" r="24"/><circle cx="136" cy="312" r="24"/><circle cx="216" cy="312" r="24"/><circle cx="136" cy="392" r="24"/><circle cx="216" cy="392" r="24"/><circle cx="296" cy="392" r="24"/><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32" d="M128 48v32M384 48v32"/><path fill="none" stroke="currentColor" stroke-linejoin="round" stroke-width="32" d="M464 160H48"/></svg>';
@@ -495,8 +498,10 @@ var IKONER = Object.fromEntries(
495
498
  Object.entries({
496
499
  "arrow-back-outline": arrow_back_outline_default,
497
500
  "brush-outline": brush_outline_default,
501
+ // Fylte varianter: bare på sporvalgets to kort (DD-63), der ikonet bærer stemningen.
502
+ bug: bug_default,
503
+ bulb: bulb_default,
498
504
  "bug-outline": bug_outline_default,
499
- "bulb-outline": bulb_outline_default,
500
505
  "calendar-outline": calendar_outline_default,
501
506
  "camera-outline": camera_outline_default,
502
507
  "checkmark-circle-outline": checkmark_circle_outline_default,
@@ -542,6 +547,7 @@ function Ikon({
542
547
  width: maal,
543
548
  height: maal,
544
549
  color: farge ?? tema.color.textPrimary,
550
+ fill: farge ?? tema.color.textPrimary,
545
551
  accessibilityElementsHidden: true,
546
552
  importantForAccessibility: "no"
547
553
  }
@@ -566,10 +572,12 @@ function Btn({
566
572
  accessibilityLabel,
567
573
  grow,
568
574
  testID,
569
- busy
575
+ busy,
576
+ trykkForbiForelder
570
577
  }) {
571
578
  const tema = useTema();
572
579
  const c = tema.color;
580
+ const forbi = useTrykkForbiForelder(onPress, !!disabled, tema.touch / 2);
573
581
  const bakgrunn = variant === "primary" ? c.actionPrimary : variant === "secondary" ? c.surfaceRaised : "transparent";
574
582
  const tekstfarge = variant === "primary" ? c.onActionPrimary : variant === "danger" ? c.danger : c.actionSecondaryText;
575
583
  const kant = variant === "ghost" ? "transparent" : variant === "primary" ? c.actionPrimary : c.actionSecondaryBorder;
@@ -583,6 +591,7 @@ function Btn({
583
591
  accessibilityState: { disabled: !!disabled, busy: !!busy },
584
592
  disabled,
585
593
  onPress,
594
+ ...trykkForbiForelder ? forbi : {},
586
595
  style: {
587
596
  minHeight: tema.touch,
588
597
  borderRadius: tema.radius.md,
@@ -615,6 +624,37 @@ function Btn({
615
624
  hint ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Hint, { children: hint }) : null
616
625
  ] });
617
626
  }
627
+ function useTrykkForbiForelder(onPress, laast, slingring) {
628
+ const start = (0, import_react4.useRef)(null);
629
+ const fikkResponder = (0, import_react4.useRef)(false);
630
+ const siste = (0, import_react4.useRef)({ onPress, laast });
631
+ siste.current = { onPress, laast };
632
+ return (0, import_react4.useMemo)(
633
+ () => ({
634
+ onPressIn: () => {
635
+ fikkResponder.current = true;
636
+ },
637
+ onTouchStart: (e) => {
638
+ start.current = { x: e.nativeEvent.pageX, y: e.nativeEvent.pageY };
639
+ },
640
+ onTouchEnd: (e) => {
641
+ const s = start.current;
642
+ start.current = null;
643
+ const innenfor = s !== null && Math.abs(e.nativeEvent.pageX - s.x) <= slingring && Math.abs(e.nativeEvent.pageY - s.y) <= slingring;
644
+ setTimeout(() => {
645
+ const tatt = fikkResponder.current;
646
+ fikkResponder.current = false;
647
+ if (!tatt && innenfor && !siste.current.laast) siste.current.onPress?.();
648
+ }, 0);
649
+ },
650
+ onTouchCancel: () => {
651
+ start.current = null;
652
+ fikkResponder.current = false;
653
+ }
654
+ }),
655
+ [slingring]
656
+ );
657
+ }
618
658
  function H({ children, sub }) {
619
659
  const tema = useTema();
620
660
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native2.View, { style: { gap: tema.space.xs }, children: [
@@ -749,7 +789,8 @@ function Banner({
749
789
  // src/widget/tekster.ts
750
790
  function saksnr(id) {
751
791
  const i = id.indexOf("_");
752
- return i >= 0 ? id.slice(i + 1) : id;
792
+ const rest = i >= 0 ? id.slice(i + 1) : id;
793
+ return rest.length > 8 ? rest.slice(-4) : rest;
753
794
  }
754
795
  var stor = (s) => s ? s.charAt(0).toUpperCase() + s.slice(1) : s;
755
796
  var tekst = {
@@ -1248,7 +1289,8 @@ function Felt({
1248
1289
  disabled: forKort || sender,
1249
1290
  busy: sender,
1250
1291
  hint: forKort ? tekst.forKort(minTextLength) : harVedlegg ? tekst.sendHintMedBilde : void 0,
1251
- onPress: onSend
1292
+ onPress: onSend,
1293
+ trykkForbiForelder: true
1252
1294
  }
1253
1295
  ) })
1254
1296
  ] });
@@ -1280,7 +1322,21 @@ function Valg({ onVelg }) {
1280
1322
  padding: tema.space.md
1281
1323
  },
1282
1324
  children: [
1283
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Ikon, { navn: ikon, storrelse: "stor", farge: tema.color.textPrimary }),
1325
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1326
+ import_react_native4.View,
1327
+ {
1328
+ testID: `spor-${spor}-ikonflate`,
1329
+ style: {
1330
+ width: 2 * tema.icon.inline + 2 * tema.space.md,
1331
+ height: 2 * tema.icon.inline + 2 * tema.space.md,
1332
+ borderRadius: tema.radius.pill,
1333
+ backgroundColor: tema.color.brandBg,
1334
+ alignItems: "center",
1335
+ justifyContent: "center"
1336
+ },
1337
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Ikon, { navn: ikon, storrelse: "stor", farge: tema.color.brand })
1338
+ }
1339
+ ),
1284
1340
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1285
1341
  import_react_native4.Text,
1286
1342
  {
@@ -1300,8 +1356,8 @@ function Valg({ onVelg }) {
1300
1356
  return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react_native4.View, { style: { flex: 1, gap: tema.space.lg }, children: [
1301
1357
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(H, { children: tekst.valgTittel }),
1302
1358
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native4.View, { style: { flex: 1, justifyContent: "flex-end" }, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react_native4.View, { style: { flexDirection: "row", gap: tema.space.md }, children: [
1303
- flate("feil", "bug-outline", tekst.sporFeil, tekst.sporFeilUnder),
1304
- flate("onske", "bulb-outline", tekst.sporOnske, tekst.sporOnskeUnder)
1359
+ flate("feil", "bug", tekst.sporFeil, tekst.sporFeilUnder),
1360
+ flate("onske", "bulb", tekst.sporOnske, tekst.sporOnskeUnder)
1305
1361
  ] }) })
1306
1362
  ] });
1307
1363
  }
@@ -1850,9 +1906,23 @@ function Widget({
1850
1906
  setVedlegg(void 0);
1851
1907
  setKomponerer(false);
1852
1908
  }, []);
1909
+ const [mineDirekte, setMineDirekte] = (0, import_react11.useState)(false);
1910
+ const [stegForMine, setStegForMine] = (0, import_react11.useState)("valg");
1911
+ const stegRef = (0, import_react11.useRef)(steg);
1912
+ stegRef.current = steg;
1913
+ const harUtkast = verdi.trim().length > 0 || vedlegg !== void 0;
1853
1914
  const lukk = (0, import_react11.useCallback)(() => {
1915
+ onLukk();
1916
+ if (stegRef.current === "mine" && mineDirekte) {
1917
+ setSteg(stegForMine);
1918
+ setMineDirekte(false);
1919
+ }
1920
+ }, [onLukk, mineDirekte, stegForMine]);
1921
+ const lukkOgNullstill = (0, import_react11.useCallback)(() => {
1854
1922
  onLukk();
1855
1923
  nullstill();
1924
+ setMineDirekte(false);
1925
+ setStegForMine("valg");
1856
1926
  }, [onLukk, nullstill]);
1857
1927
  (0, import_react11.useEffect)(() => {
1858
1928
  if (!synlig) return;
@@ -1862,8 +1932,8 @@ function Widget({
1862
1932
  if (!client.isAnonymous) {
1863
1933
  void client.subjects.submissions().then(setMine).catch(() => void 0);
1864
1934
  }
1865
- if (apneOpsjoner?.view === "mine" && !client.isAnonymous) void visMine();
1866
- else if (apneOpsjoner?.track) velgSpor(apneOpsjoner.track);
1935
+ if (apneOpsjoner?.view === "mine" && !client.isAnonymous) void visMine(true);
1936
+ else if (apneOpsjoner?.track && !harUtkast) void velgSpor(apneOpsjoner.track);
1867
1937
  }, [synlig]);
1868
1938
  const hentKort = (0, import_react11.useCallback)(async () => {
1869
1939
  setLasterKort(true);
@@ -1961,6 +2031,11 @@ function Widget({
1961
2031
  }, []);
1962
2032
  const gaaTilbake = (0, import_react11.useCallback)(() => {
1963
2033
  setFeil(void 0);
2034
+ if (steg === "mine") {
2035
+ if (mineDirekte) lukk();
2036
+ else setSteg("valg");
2037
+ return;
2038
+ }
1964
2039
  if (steg === "skjermbilde") {
1965
2040
  setBilde(void 0);
1966
2041
  setAutomasker([]);
@@ -1972,7 +2047,12 @@ function Widget({
1972
2047
  return;
1973
2048
  }
1974
2049
  setSteg("valg");
1975
- }, [steg, spor, kort.length]);
2050
+ }, [steg, spor, kort.length, mineDirekte, lukk]);
2051
+ const androidTilbake = (0, import_react11.useCallback)(() => {
2052
+ if (steg === "valg") lukk();
2053
+ else if (steg === "kvittering") lukkOgNullstill();
2054
+ else gaaTilbake();
2055
+ }, [steg, lukk, lukkOgNullstill, gaaTilbake]);
1976
2056
  const send = (0, import_react11.useCallback)(async () => {
1977
2057
  setSender(true);
1978
2058
  setFeil(void 0);
@@ -2019,7 +2099,13 @@ function Widget({
2019
2099
  },
2020
2100
  [client]
2021
2101
  );
2022
- const visMine = (0, import_react11.useCallback)(async () => {
2102
+ const visMine = (0, import_react11.useCallback)(async (direkte = false) => {
2103
+ if (direkte) {
2104
+ if (stegRef.current !== "mine") setStegForMine(stegRef.current);
2105
+ } else {
2106
+ setStegForMine("valg");
2107
+ }
2108
+ setMineDirekte(direkte);
2023
2109
  setSteg("mine");
2024
2110
  setLasterMine(true);
2025
2111
  try {
@@ -2030,13 +2116,18 @@ function Widget({
2030
2116
  setLasterMine(false);
2031
2117
  }
2032
2118
  }, [client]);
2119
+ const nyttFraMine = (0, import_react11.useCallback)(() => {
2120
+ setMineDirekte(false);
2121
+ if (harUtkast) setSteg(stegForMine);
2122
+ else nullstill();
2123
+ }, [harUtkast, stegForMine, nullstill]);
2033
2124
  return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2034
2125
  import_react_native9.Modal,
2035
2126
  {
2036
2127
  visible: synlig,
2037
2128
  transparent: true,
2038
2129
  animationType: "slide",
2039
- onRequestClose: lukk,
2130
+ onRequestClose: androidTilbake,
2040
2131
  accessibilityViewIsModal: true,
2041
2132
  children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2042
2133
  import_react_native9.KeyboardAvoidingView,
@@ -2074,7 +2165,7 @@ function Widget({
2074
2165
  testID: "lukk",
2075
2166
  accessibilityRole: "button",
2076
2167
  accessibilityLabel: tekst.lukk,
2077
- onPress: lukk,
2168
+ onPress: steg === "kvittering" ? lukkOgNullstill : lukk,
2078
2169
  style: { minWidth: tema.touch, minHeight: tema.touch, alignItems: "center", justifyContent: "center" },
2079
2170
  children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Ikon, { navn: "close-outline", farge: tema.color.textSecondary })
2080
2171
  }
@@ -2092,7 +2183,7 @@ function Widget({
2092
2183
  ikon: "list-outline",
2093
2184
  label: mine.length > 0 ? tekst.mineMedAntall(mine.length) : tekst.mineTittel,
2094
2185
  accessibilityLabel: mine.length > 0 ? tekst.mineEtikett(mine.length) : tekst.mineTittel,
2095
- onPress: visMine
2186
+ onPress: () => void visMine()
2096
2187
  }
2097
2188
  ) : null
2098
2189
  ] }) : null,
@@ -2156,7 +2247,7 @@ function Widget({
2156
2247
  ...kvittering.nr ? { saksnummer: kvittering.nr } : {},
2157
2248
  ...kvittering.vedlegg ? { vedlegg: kvittering.vedlegg } : {},
2158
2249
  ...kvittering.frist ? { frist: kvittering.frist } : {},
2159
- onLukk: lukk
2250
+ onLukk: lukkOgNullstill
2160
2251
  }
2161
2252
  ) : null,
2162
2253
  steg === "mine" ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
@@ -2165,7 +2256,7 @@ function Widget({
2165
2256
  rader: mine,
2166
2257
  laster: lasterMine,
2167
2258
  ...tenantName ? { tenantName } : {},
2168
- onNytt: nullstill
2259
+ onNytt: nyttFraMine
2169
2260
  }
2170
2261
  ) : null
2171
2262
  ]