@innspel/react-native 0.10.0 → 0.10.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -663,7 +663,10 @@ declare const tekst: {
663
663
  readonly lagtTil: "Lagt til";
664
664
  readonly tilleggTak: "Du har lagt til tre ganger. Har du mer, send et nytt innspill.";
665
665
  readonly tilleggLukket: "Saken er avsluttet — send et nytt innspill.";
666
+ /** F34: serverens egen setning (InnspelApiError) — aldri en rå feil. */
666
667
  readonly tilleggFeil: (arsak: string) => string;
668
+ readonly tilleggIngenNett: "Ingen nett. Teksten din er beholdt — prøv igjen når du er på nett.";
669
+ readonly tilleggFeilGenerisk: "Kunne ikke legge til. Teksten din er beholdt — prøv igjen.";
667
670
  readonly sendNytt: "Send nytt innspill";
668
671
  /** Tom tilstand: det finnes ikke noe «nytt» å sende når ingenting er sendt. */
669
672
  readonly sendForste: "Send innspill";
package/dist/index.d.ts CHANGED
@@ -663,7 +663,10 @@ declare const tekst: {
663
663
  readonly lagtTil: "Lagt til";
664
664
  readonly tilleggTak: "Du har lagt til tre ganger. Har du mer, send et nytt innspill.";
665
665
  readonly tilleggLukket: "Saken er avsluttet — send et nytt innspill.";
666
+ /** F34: serverens egen setning (InnspelApiError) — aldri en rå feil. */
666
667
  readonly tilleggFeil: (arsak: string) => string;
668
+ readonly tilleggIngenNett: "Ingen nett. Teksten din er beholdt — prøv igjen når du er på nett.";
669
+ readonly tilleggFeilGenerisk: "Kunne ikke legge til. Teksten din er beholdt — prøv igjen.";
667
670
  readonly sendNytt: "Send nytt innspill";
668
671
  /** Tom tilstand: det finnes ikke noe «nytt» å sende når ingenting er sendt. */
669
672
  readonly sendForste: "Send innspill";
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  // src/InnspelProvider.tsx
2
- import { createContext as createContext3, useCallback as useCallback3, useContext as useContext4, useMemo as useMemo4, useRef as useRef4, useState as useState5 } from "react";
2
+ import { createContext as createContext3, useCallback as useCallback3, useContext as useContext4, useMemo as useMemo4, useRef as useRef5, useState as useState5 } from "react";
3
3
  import { View as View9 } from "react-native";
4
4
 
5
5
  // src/skjermbilde.ts
@@ -355,7 +355,7 @@ import {
355
355
  InnspelApiError as InnspelApiError2,
356
356
  InnspelQueueFullError
357
357
  } from "@innspel/core";
358
- import { useCallback as useCallback2, useContext as useContext3, useEffect as useEffect2, useRef as useRef3, useState as useState4 } from "react";
358
+ import { useCallback as useCallback2, useContext as useContext3, useEffect as useEffect2, useRef as useRef4, useState as useState4 } from "react";
359
359
  import { KeyboardAvoidingView, Modal, Pressable as Pressable6, View as View8 } from "react-native";
360
360
  import { initialWindowMetrics, SafeAreaInsetsContext } from "react-native-safe-area-context";
361
361
 
@@ -882,7 +882,10 @@ var tekst = {
882
882
  lagtTil: "Lagt til",
883
883
  tilleggTak: "Du har lagt til tre ganger. Har du mer, send et nytt innspill.",
884
884
  tilleggLukket: "Saken er avsluttet \u2014 send et nytt innspill.",
885
+ /** F34: serverens egen setning (InnspelApiError) — aldri en rå feil. */
885
886
  tilleggFeil: (arsak) => `Kunne ikke legge til: ${arsak} Teksten din er beholdt.`,
887
+ tilleggIngenNett: "Ingen nett. Teksten din er beholdt \u2014 pr\xF8v igjen n\xE5r du er p\xE5 nett.",
888
+ tilleggFeilGenerisk: "Kunne ikke legge til. Teksten din er beholdt \u2014 pr\xF8v igjen.",
886
889
  sendNytt: "Send nytt innspill",
887
890
  /** Tom tilstand: det finnes ikke noe «nytt» å sende når ingenting er sendt. */
888
891
  sendForste: "Send innspill",
@@ -1533,9 +1536,9 @@ function Kvittering({
1533
1536
  }
1534
1537
 
1535
1538
  // src/widget/MineInnspill.tsx
1536
- import { InnspelApiError } from "@innspel/core";
1537
- import { useEffect, useState as useState2 } from "react";
1538
- import { ActivityIndicator as ActivityIndicator2, Pressable as Pressable4, ScrollView as ScrollView3, Text as Text6, TextInput as TextInput2, View as View6 } from "react-native";
1539
+ import { InnspelApiError, NettverksFeil } from "@innspel/core";
1540
+ import { forwardRef, useEffect, useImperativeHandle, useRef as useRef2, useState as useState2 } from "react";
1541
+ import { ActivityIndicator as ActivityIndicator2, Keyboard, Pressable as Pressable4, ScrollView as ScrollView3, Text as Text6, TextInput as TextInput2, View as View6 } from "react-native";
1539
1542
 
1540
1543
  // src/widget/nyttSvar.ts
1541
1544
  var N\u00D8KKEL = "innspel:svar-sett";
@@ -1559,7 +1562,7 @@ async function markerSvarSett(storage, n\u00E5 = Date.now()) {
1559
1562
 
1560
1563
  // src/widget/MineInnspill.tsx
1561
1564
  import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
1562
- function MineInnspill({
1565
+ var MineInnspill = forwardRef(function MineInnspill2({
1563
1566
  rader,
1564
1567
  laster,
1565
1568
  tenantName,
@@ -1568,8 +1571,9 @@ function MineInnspill({
1568
1571
  leggTil,
1569
1572
  onOppdatert,
1570
1573
  minTextLength,
1571
- textMaxLength
1572
- }) {
1574
+ textMaxLength,
1575
+ utkastLager
1576
+ }, ref) {
1573
1577
  const tema = useTema();
1574
1578
  const min = minTextLength ?? 10;
1575
1579
  const maks = textMaxLength ?? 280;
@@ -1578,6 +1582,35 @@ function MineInnspill({
1578
1582
  const [sender, setSender] = useState2(false);
1579
1583
  const [feil, setFeil] = useState2();
1580
1584
  const [lagtTil, setLagtTil] = useState2();
1585
+ const egetLager = useRef2(/* @__PURE__ */ new Map());
1586
+ const lager = utkastLager ?? egetLager.current;
1587
+ const rulleRef = useRef2(null);
1588
+ const kortY = useRef2(/* @__PURE__ */ new Map());
1589
+ const apneFelt = (id) => {
1590
+ setApen(id);
1591
+ setUtkast(lager.get(id) ?? "");
1592
+ setFeil(void 0);
1593
+ setLagtTil(void 0);
1594
+ const y = kortY.current.get(id);
1595
+ if (y !== void 0) rulleRef.current?.scrollTo({ y, animated: true });
1596
+ };
1597
+ const lukkFelt = () => {
1598
+ if (apen === null) return false;
1599
+ Keyboard.dismiss();
1600
+ if (utkast.trim()) lager.set(apen, utkast);
1601
+ else lager.delete(apen);
1602
+ setApen(null);
1603
+ setUtkast("");
1604
+ setFeil(void 0);
1605
+ return true;
1606
+ };
1607
+ const avbryt = () => {
1608
+ if (apen !== null) lager.delete(apen);
1609
+ setApen(null);
1610
+ setUtkast("");
1611
+ setFeil(void 0);
1612
+ };
1613
+ useImperativeHandle(ref, () => ({ lukkFelt }));
1581
1614
  const send = async (id) => {
1582
1615
  if (!leggTil) return;
1583
1616
  setSender(true);
@@ -1585,12 +1618,13 @@ function MineInnspill({
1585
1618
  try {
1586
1619
  const sak = await leggTil(id, utkast.trim());
1587
1620
  onOppdatert?.(sak);
1621
+ lager.delete(id);
1588
1622
  setApen(null);
1589
1623
  setUtkast("");
1590
1624
  setLagtTil(id);
1591
1625
  } catch (e) {
1592
1626
  const kode = e instanceof InnspelApiError ? e.code : void 0;
1593
- const tekstFeil = kode === "addendum_limit_reached" ? tekst.tilleggTak : kode === "submission_closed" ? tekst.tilleggLukket : tekst.tilleggFeil(e instanceof Error && e.message ? e.message : "ukjent feil.");
1627
+ const tekstFeil = kode === "addendum_limit_reached" ? tekst.tilleggTak : kode === "submission_closed" ? tekst.tilleggLukket : e instanceof InnspelApiError && e.message ? tekst.tilleggFeil(e.message) : e instanceof NettverksFeil ? tekst.tilleggIngenNett : tekst.tilleggFeilGenerisk;
1594
1628
  setFeil({ id, tekst: tekstFeil });
1595
1629
  } finally {
1596
1630
  setSender(false);
@@ -1613,7 +1647,7 @@ function MineInnspill({
1613
1647
  }, [storage, laster, rader]);
1614
1648
  return /* @__PURE__ */ jsxs6(View6, { style: { flex: 1, gap: tema.space.md }, children: [
1615
1649
  /* @__PURE__ */ jsx7(H, { sub: tekst.mineUnder, children: tekst.mineTittel }),
1616
- laster ? /* @__PURE__ */ jsx7(ActivityIndicator2, { accessibilityLabel: "Henter innspillene dine", color: tema.color.textSecondary }) : rader.length === 0 ? /* @__PURE__ */ jsx7(Hint, { children: tekst.mineTom }) : /* @__PURE__ */ jsx7(ScrollView3, { style: { flex: 1 }, contentContainerStyle: { gap: tema.space.sm }, children: visning.map(({ rad, nytt }) => {
1650
+ laster ? /* @__PURE__ */ jsx7(ActivityIndicator2, { accessibilityLabel: "Henter innspillene dine", color: tema.color.textSecondary }) : rader.length === 0 ? /* @__PURE__ */ jsx7(Hint, { children: tekst.mineTom }) : /* @__PURE__ */ jsx7(ScrollView3, { ref: rulleRef, style: { flex: 1 }, contentContainerStyle: { gap: tema.space.sm }, keyboardShouldPersistTaps: "handled", children: visning.map(({ rad, nytt }) => {
1617
1651
  const venter = rad.pending === true;
1618
1652
  const v = venter ? venterVisning : statusVisning(rad.status, rad.type, rad.deadlineAt);
1619
1653
  const nokkel = venter ? rad.clientRef : rad.id;
@@ -1624,194 +1658,188 @@ function MineInnspill({
1624
1658
  const taketN\u00E5dd = !venter && rad.canAddAddendum === false && tillegg.length >= 3;
1625
1659
  const feltApent = sakId !== void 0 && apen === sakId;
1626
1660
  const brukt = utkast.length;
1627
- const forKort = brukt < min;
1628
1661
  const full = brukt >= maks;
1629
1662
  const visTeller = brukt >= maks * 0.8;
1630
- return /* @__PURE__ */ jsxs6(Card, { dashed: venter, children: [
1631
- /* @__PURE__ */ jsxs6(View6, { style: { flexDirection: "row", alignItems: "center", gap: tema.space.xs, flexWrap: "wrap" }, children: [
1632
- /* @__PURE__ */ jsx7(Hint, { children: venter ? `${tekst.mineIkkeSendt} \xB7 ${rad.type === "onske" ? tekst.onske : tekst.feil}` : tekst.sakHode(rad.type === "onske" ? tekst.onske : tekst.feil, rad.id) }),
1633
- nytt ? /* @__PURE__ */ jsx7(
1634
- Text6,
1635
- {
1636
- testID: "nytt-svar",
1637
- style: {
1638
- color: tema.color.info,
1639
- backgroundColor: tema.color.infoBg,
1640
- fontSize: tema.font.tiny,
1641
- fontWeight: tema.weight.semibold,
1642
- borderRadius: tema.radius.pill,
1643
- paddingHorizontal: tema.space.sm
1644
- },
1645
- children: tekst.nyttSvar
1646
- }
1647
- ) : null
1648
- ] }),
1649
- /* @__PURE__ */ jsx7(
1650
- Text6,
1651
- {
1652
- style: {
1653
- color: tema.color.textPrimary,
1654
- fontSize: tema.font.body,
1655
- lineHeight: tema.lineHeight.body
1656
- },
1657
- children: rad.text
1658
- }
1659
- ),
1660
- tillegg.length > 0 ? /* @__PURE__ */ jsx7(View6, { testID: `tillegg-${sakId}`, style: { gap: tema.space.xs }, children: tillegg.map((a) => /* @__PURE__ */ jsxs6(
1661
- View6,
1662
- {
1663
- style: {
1664
- borderLeftWidth: tema.hairline * 2,
1665
- borderLeftColor: tema.color.border,
1666
- paddingLeft: tema.space.sm,
1667
- gap: tema.space.xs
1668
- },
1669
- children: [
1670
- /* @__PURE__ */ jsxs6(View6, { style: { flexDirection: "row", alignItems: "center", gap: tema.space.xs }, children: [
1671
- /* @__PURE__ */ jsx7(Ikon, { navn: "add-outline", storrelse: "minste", farge: tema.color.textSecondary }),
1672
- /* @__PURE__ */ jsx7(Text6, { style: { color: tema.color.textSecondary, fontSize: tema.font.small }, children: tekst.duLaTil(formaterFrist(a.createdAt)) })
1673
- ] }),
1674
- /* @__PURE__ */ jsx7(Text6, { style: { color: tema.color.textPrimary, fontSize: tema.font.small, lineHeight: tema.lineHeight.small }, children: a.text })
1675
- ]
1663
+ return /* @__PURE__ */ jsx7(
1664
+ View6,
1665
+ {
1666
+ onLayout: (e) => {
1667
+ if (sakId !== void 0) kortY.current.set(sakId, e.nativeEvent.layout.y);
1676
1668
  },
1677
- a.id
1678
- )) }) : null,
1679
- /* @__PURE__ */ jsxs6(View6, { style: { gap: tema.space.xs }, children: [
1680
- /* @__PURE__ */ jsx7(StatusPill, { ikon: v.ikon, etikett: v.etikett, fg: v.fg, bg: v.bg }),
1681
- /* @__PURE__ */ jsx7(Hint, { children: v.lofte })
1682
- ] }),
1683
- sakId !== void 0 && lagtTil === sakId ? /* @__PURE__ */ jsx7(Text6, { accessibilityLiveRegion: "polite", testID: `lagt-til-${sakId}`, style: { color: tema.color.success, fontSize: tema.font.small }, children: tekst.lagtTil }) : null,
1684
- feltApent ? /* @__PURE__ */ jsxs6(View6, { testID: `tillegg-felt-${sakId}`, style: { gap: tema.space.sm }, children: [
1685
- /* @__PURE__ */ jsx7(Text6, { style: { color: tema.color.textSecondary, fontSize: tema.font.small }, children: tekst.leggTilMerLabel }),
1686
- /* @__PURE__ */ jsx7(
1687
- TextInput2,
1688
- {
1689
- testID: "tillegg-tekst",
1690
- accessibilityLabel: tekst.leggTilMerLabel,
1691
- value: utkast,
1692
- onChangeText: setUtkast,
1693
- maxLength: maks,
1694
- multiline: true,
1695
- numberOfLines: 3,
1696
- autoFocus: true,
1697
- placeholder: tekst.leggTilMerPlaceholder,
1698
- placeholderTextColor: tema.color.textMuted,
1699
- style: {
1700
- backgroundColor: tema.color.surfaceRaised,
1701
- borderWidth: tema.hairline,
1702
- borderColor: full ? tema.color.warning : tema.color.borderStrong,
1703
- borderRadius: tema.radius.md,
1704
- padding: tema.space.md,
1705
- color: tema.color.textPrimary,
1706
- fontSize: tema.font.body,
1707
- lineHeight: tema.lineHeight.body,
1708
- minHeight: tema.touch * 2,
1709
- textAlignVertical: "top"
1710
- }
1711
- }
1712
- ),
1713
- visTeller ? /* @__PURE__ */ jsxs6(
1714
- Text6,
1715
- {
1716
- testID: "tillegg-teller",
1717
- accessibilityLiveRegion: full ? "assertive" : "polite",
1718
- style: { alignSelf: "flex-end", color: full ? tema.color.warning : tema.color.textMuted, fontSize: tema.font.small },
1719
- children: [
1720
- brukt,
1721
- " / ",
1722
- maks,
1723
- full ? tekst.tellerFull : ""
1724
- ]
1725
- }
1726
- ) : null,
1727
- feil?.id === sakId ? /* @__PURE__ */ jsx7(Text6, { accessibilityLiveRegion: "assertive", testID: `tillegg-feil-${sakId}`, style: { color: tema.color.danger, fontSize: tema.font.small, lineHeight: tema.lineHeight.small }, children: feil.tekst }) : null,
1728
- /* @__PURE__ */ jsxs6(View6, { style: { flexDirection: "row", gap: tema.space.sm }, children: [
1669
+ children: /* @__PURE__ */ jsxs6(Card, { dashed: venter, children: [
1670
+ /* @__PURE__ */ jsxs6(View6, { style: { flexDirection: "row", alignItems: "center", gap: tema.space.xs, flexWrap: "wrap" }, children: [
1671
+ /* @__PURE__ */ jsx7(Hint, { children: venter ? `${tekst.mineIkkeSendt} \xB7 ${rad.type === "onske" ? tekst.onske : tekst.feil}` : tekst.sakHode(rad.type === "onske" ? tekst.onske : tekst.feil, rad.id) }),
1672
+ nytt ? /* @__PURE__ */ jsx7(
1673
+ Text6,
1674
+ {
1675
+ testID: "nytt-svar",
1676
+ style: {
1677
+ color: tema.color.info,
1678
+ backgroundColor: tema.color.infoBg,
1679
+ fontSize: tema.font.tiny,
1680
+ fontWeight: tema.weight.semibold,
1681
+ borderRadius: tema.radius.pill,
1682
+ paddingHorizontal: tema.space.sm
1683
+ },
1684
+ children: tekst.nyttSvar
1685
+ }
1686
+ ) : null
1687
+ ] }),
1729
1688
  /* @__PURE__ */ jsx7(
1730
- Btn,
1689
+ Text6,
1731
1690
  {
1732
- testID: "tillegg-send",
1733
- label: sender ? tekst.sender : tekst.send,
1734
- disabled: forKort || sender,
1735
- busy: sender,
1736
- ...forKort ? { hint: tekst.forKort(min) } : {},
1737
- onPress: () => sakId !== void 0 && void send(sakId),
1738
- grow: true
1691
+ style: {
1692
+ color: tema.color.textPrimary,
1693
+ fontSize: tema.font.body,
1694
+ lineHeight: tema.lineHeight.body
1695
+ },
1696
+ children: rad.text
1739
1697
  }
1740
1698
  ),
1741
- /* @__PURE__ */ jsx7(
1742
- Btn,
1699
+ tillegg.length > 0 ? /* @__PURE__ */ jsx7(View6, { testID: `tillegg-${sakId}`, style: { gap: tema.space.xs }, children: tillegg.map((a) => /* @__PURE__ */ jsxs6(
1700
+ View6,
1743
1701
  {
1744
- testID: "tillegg-avbryt",
1745
- label: tekst.avbryt,
1746
- variant: "secondary",
1747
- onPress: () => {
1748
- setApen(null);
1749
- setUtkast("");
1750
- setFeil(void 0);
1702
+ style: {
1703
+ borderLeftWidth: tema.hairline * 2,
1704
+ borderLeftColor: tema.color.border,
1705
+ paddingLeft: tema.space.sm,
1706
+ gap: tema.space.xs
1751
1707
  },
1752
- grow: true
1753
- }
1754
- )
1755
- ] }),
1756
- /* @__PURE__ */ jsx7(Hint, { children: tekst.leggTilMerHint })
1757
- ] }) : kanLeggeTil ? /* @__PURE__ */ jsxs6(
1758
- Pressable4,
1759
- {
1760
- testID: `legg-til-mer-${sakId}`,
1761
- accessibilityRole: "button",
1762
- accessibilityLabel: tekst.leggTilMerLabel,
1763
- onPress: () => {
1764
- if (sakId === void 0) return;
1765
- setApen(sakId);
1766
- setUtkast("");
1767
- setFeil(void 0);
1768
- setLagtTil(void 0);
1769
- },
1770
- style: { alignSelf: "flex-start", minHeight: tema.touch, flexDirection: "row", alignItems: "center", gap: tema.space.xs, paddingHorizontal: tema.space.sm },
1771
- children: [
1772
- /* @__PURE__ */ jsx7(Ikon, { navn: "add-outline", storrelse: "minste", farge: tema.color.actionSecondaryText }),
1773
- /* @__PURE__ */ jsx7(Text6, { style: { color: tema.color.actionSecondaryText, fontSize: tema.font.body, fontWeight: tema.weight.semibold }, children: tekst.leggTilMer })
1774
- ]
1775
- }
1776
- ) : taketN\u00E5dd ? /* @__PURE__ */ jsx7(Hint, { children: tekst.tilleggTak }) : null,
1777
- !venter && rad.attachmentRemoved ? /* @__PURE__ */ jsxs6(View6, { testID: `bilde-fjernet-${rad.id}`, style: { flexDirection: "row", gap: tema.space.xs, alignItems: "center" }, children: [
1778
- /* @__PURE__ */ jsx7(Ikon, { navn: "trash-outline", storrelse: "minste", farge: tema.color.textMuted }),
1779
- /* @__PURE__ */ jsx7(Hint, { children: tekst.bildeFjernet })
1780
- ] }) : null,
1781
- svar ? /* @__PURE__ */ jsxs6(
1782
- View6,
1783
- {
1784
- style: {
1785
- borderLeftWidth: tema.hairline * 2,
1786
- borderLeftColor: tema.color.brand,
1787
- paddingLeft: tema.space.sm,
1788
- gap: tema.space.xs
1789
- },
1790
- children: [
1791
- /* @__PURE__ */ jsx7(Text6, { style: { color: tema.color.textSecondary, fontSize: tema.font.small }, children: tenantName ? tekst.svarFra(tenantName) : tekst.svarFraGenerisk }),
1708
+ children: [
1709
+ /* @__PURE__ */ jsxs6(View6, { style: { flexDirection: "row", alignItems: "center", gap: tema.space.xs }, children: [
1710
+ /* @__PURE__ */ jsx7(Ikon, { navn: "add-outline", storrelse: "minste", farge: tema.color.textSecondary }),
1711
+ /* @__PURE__ */ jsx7(Text6, { style: { color: tema.color.textSecondary, fontSize: tema.font.small }, children: tekst.duLaTil(formaterFrist(a.createdAt)) })
1712
+ ] }),
1713
+ /* @__PURE__ */ jsx7(Text6, { style: { color: tema.color.textPrimary, fontSize: tema.font.small, lineHeight: tema.lineHeight.small }, children: a.text })
1714
+ ]
1715
+ },
1716
+ a.id
1717
+ )) }) : null,
1718
+ /* @__PURE__ */ jsxs6(View6, { style: { gap: tema.space.xs }, children: [
1719
+ /* @__PURE__ */ jsx7(StatusPill, { ikon: v.ikon, etikett: v.etikett, fg: v.fg, bg: v.bg }),
1720
+ /* @__PURE__ */ jsx7(Hint, { children: v.lofte })
1721
+ ] }),
1722
+ sakId !== void 0 && lagtTil === sakId ? /* @__PURE__ */ jsx7(Text6, { accessibilityLiveRegion: "polite", testID: `lagt-til-${sakId}`, style: { color: tema.color.success, fontSize: tema.font.small }, children: tekst.lagtTil }) : null,
1723
+ feltApent ? /* @__PURE__ */ jsxs6(View6, { testID: `tillegg-felt-${sakId}`, style: { gap: tema.space.sm }, children: [
1724
+ /* @__PURE__ */ jsx7(Text6, { style: { color: tema.color.textSecondary, fontSize: tema.font.small }, children: tekst.leggTilMerLabel }),
1792
1725
  /* @__PURE__ */ jsx7(
1793
- Text6,
1726
+ TextInput2,
1794
1727
  {
1728
+ testID: "tillegg-tekst",
1729
+ accessibilityLabel: tekst.leggTilMerLabel,
1730
+ value: utkast,
1731
+ onChangeText: setUtkast,
1732
+ maxLength: maks,
1733
+ multiline: true,
1734
+ numberOfLines: 3,
1735
+ autoFocus: true,
1736
+ placeholder: tekst.leggTilMerPlaceholder,
1737
+ placeholderTextColor: tema.color.textMuted,
1795
1738
  style: {
1739
+ backgroundColor: tema.color.surfaceRaised,
1740
+ borderWidth: tema.hairline,
1741
+ borderColor: full ? tema.color.warning : tema.color.borderStrong,
1742
+ borderRadius: tema.radius.md,
1743
+ padding: tema.space.md,
1796
1744
  color: tema.color.textPrimary,
1797
- fontSize: tema.font.small,
1798
- lineHeight: tema.lineHeight.small
1799
- },
1800
- children: svar.text
1745
+ fontSize: tema.font.body,
1746
+ lineHeight: tema.lineHeight.body,
1747
+ minHeight: tema.touch * 2,
1748
+ textAlignVertical: "top"
1749
+ }
1801
1750
  }
1802
- )
1803
- ]
1804
- }
1805
- ) : null
1806
- ] }, nokkel);
1751
+ ),
1752
+ visTeller ? /* @__PURE__ */ jsxs6(
1753
+ Text6,
1754
+ {
1755
+ testID: "tillegg-teller",
1756
+ accessibilityLiveRegion: full ? "assertive" : "polite",
1757
+ style: { alignSelf: "flex-end", color: full ? tema.color.warning : tema.color.textMuted, fontSize: tema.font.small },
1758
+ children: [
1759
+ brukt,
1760
+ " / ",
1761
+ maks,
1762
+ full ? tekst.tellerFull : ""
1763
+ ]
1764
+ }
1765
+ ) : null,
1766
+ feil?.id === sakId ? /* @__PURE__ */ jsx7(Text6, { accessibilityLiveRegion: "assertive", testID: `tillegg-feil-${sakId}`, style: { color: tema.color.danger, fontSize: tema.font.small, lineHeight: tema.lineHeight.small }, children: feil.tekst }) : null
1767
+ ] }) : kanLeggeTil ? /* @__PURE__ */ jsxs6(
1768
+ Pressable4,
1769
+ {
1770
+ testID: `legg-til-mer-${sakId}`,
1771
+ accessibilityRole: "button",
1772
+ accessibilityLabel: tekst.leggTilMerLabel,
1773
+ onPress: () => sakId !== void 0 && apneFelt(sakId),
1774
+ style: { alignSelf: "flex-start", minHeight: tema.touch, flexDirection: "row", alignItems: "center", gap: tema.space.xs, paddingHorizontal: tema.space.sm },
1775
+ children: [
1776
+ /* @__PURE__ */ jsx7(Ikon, { navn: "add-outline", storrelse: "minste", farge: tema.color.actionSecondaryText }),
1777
+ /* @__PURE__ */ jsx7(Text6, { style: { color: tema.color.actionSecondaryText, fontSize: tema.font.body, fontWeight: tema.weight.semibold }, children: tekst.leggTilMer })
1778
+ ]
1779
+ }
1780
+ ) : taketN\u00E5dd ? /* @__PURE__ */ jsx7(Hint, { children: tekst.tilleggTak }) : null,
1781
+ !venter && rad.attachmentRemoved ? /* @__PURE__ */ jsxs6(View6, { testID: `bilde-fjernet-${rad.id}`, style: { flexDirection: "row", gap: tema.space.xs, alignItems: "center" }, children: [
1782
+ /* @__PURE__ */ jsx7(Ikon, { navn: "trash-outline", storrelse: "minste", farge: tema.color.textMuted }),
1783
+ /* @__PURE__ */ jsx7(Hint, { children: tekst.bildeFjernet })
1784
+ ] }) : null,
1785
+ svar ? /* @__PURE__ */ jsxs6(
1786
+ View6,
1787
+ {
1788
+ style: {
1789
+ borderLeftWidth: tema.hairline * 2,
1790
+ borderLeftColor: tema.color.brand,
1791
+ paddingLeft: tema.space.sm,
1792
+ gap: tema.space.xs
1793
+ },
1794
+ children: [
1795
+ /* @__PURE__ */ jsx7(Text6, { style: { color: tema.color.textSecondary, fontSize: tema.font.small }, children: tenantName ? tekst.svarFra(tenantName) : tekst.svarFraGenerisk }),
1796
+ /* @__PURE__ */ jsx7(
1797
+ Text6,
1798
+ {
1799
+ style: {
1800
+ color: tema.color.textPrimary,
1801
+ fontSize: tema.font.small,
1802
+ lineHeight: tema.lineHeight.small
1803
+ },
1804
+ children: svar.text
1805
+ }
1806
+ )
1807
+ ]
1808
+ }
1809
+ ) : null
1810
+ ] })
1811
+ },
1812
+ nokkel
1813
+ );
1807
1814
  }) }),
1808
- /* @__PURE__ */ jsx7(Btn, { testID: "send-nytt", label: rader.length === 0 ? tekst.sendForste : tekst.sendNytt, onPress: onNytt })
1815
+ apen !== null ? (
1816
+ // F32: fotens plass — én primærhandling om gangen. «Send nytt innspill» er borte til
1817
+ // tillegget er sendt eller avbrutt, så første trykk aldri treffer feil knapp.
1818
+ /* @__PURE__ */ jsxs6(View6, { testID: "tillegg-fot", style: { gap: tema.space.sm }, children: [
1819
+ /* @__PURE__ */ jsxs6(View6, { style: { flexDirection: "row", gap: tema.space.sm }, children: [
1820
+ /* @__PURE__ */ jsx7(
1821
+ Btn,
1822
+ {
1823
+ testID: "tillegg-send",
1824
+ label: sender ? tekst.sender : tekst.send,
1825
+ disabled: utkast.length < min || sender,
1826
+ busy: sender,
1827
+ ...utkast.length < min ? { hint: tekst.forKort(min) } : {},
1828
+ onPress: () => void send(apen),
1829
+ grow: true
1830
+ }
1831
+ ),
1832
+ /* @__PURE__ */ jsx7(Btn, { testID: "tillegg-avbryt", label: tekst.avbryt, variant: "secondary", onPress: avbryt, grow: true })
1833
+ ] }),
1834
+ /* @__PURE__ */ jsx7(Hint, { children: tekst.leggTilMerHint })
1835
+ ] })
1836
+ ) : /* @__PURE__ */ jsx7(Btn, { testID: "send-nytt", label: rader.length === 0 ? tekst.sendForste : tekst.sendNytt, onPress: onNytt })
1809
1837
  ] });
1810
- }
1838
+ });
1811
1839
 
1812
1840
  // src/widget/Skjermbilde.tsx
1813
1841
  import { skaler, strokTilRekter, treffer, trykkTilRekt } from "@innspel/core";
1814
- import { useCallback, useMemo as useMemo3, useRef as useRef2, useState as useState3 } from "react";
1842
+ import { useCallback, useMemo as useMemo3, useRef as useRef3, useState as useState3 } from "react";
1815
1843
  import { Image as Image2, Pressable as Pressable5, StyleSheet, Text as Text7, View as View7 } from "react-native";
1816
1844
  import { jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
1817
1845
  function Skjermbilde({
@@ -1830,7 +1858,7 @@ function Skjermbilde({
1830
1858
  const [allTekst, setAllTekst] = useState3(false);
1831
1859
  const [egne, setEgne] = useState3([]);
1832
1860
  const [ramme, setRamme] = useState3(null);
1833
- const strok = useRef2([]);
1861
+ const strok = useRef3([]);
1834
1862
  const visning = useMemo3(() => {
1835
1863
  if (!ramme) return null;
1836
1864
  const s = Math.min(ramme.width / bilde.width, ramme.height / bilde.height);
@@ -2054,7 +2082,7 @@ function Widget({
2054
2082
  const tema = useTema();
2055
2083
  const insets = useContext3(SafeAreaInsetsContext) ?? initialWindowMetrics?.insets ?? { top: 0, bottom: 0, left: 0, right: 0 };
2056
2084
  const skjermbilde = useSkjermbilde();
2057
- const previewRef = useRef3(null);
2085
+ const previewRef = useRef4(null);
2058
2086
  const [steg, setSteg] = useState4("valg");
2059
2087
  const [spor, setSpor] = useState4("feil");
2060
2088
  const [verdi, setVerdi] = useState4("");
@@ -2097,7 +2125,7 @@ function Widget({
2097
2125
  }, []);
2098
2126
  const [mineDirekte, setMineDirekte] = useState4(false);
2099
2127
  const [stegForMine, setStegForMine] = useState4("valg");
2100
- const stegRef = useRef3(steg);
2128
+ const stegRef = useRef4(steg);
2101
2129
  stegRef.current = steg;
2102
2130
  const harUtkast = verdi.trim().length > 0 || vedlegg !== void 0;
2103
2131
  const lukk = useCallback2(() => {
@@ -2218,9 +2246,12 @@ function Widget({
2218
2246
  setVedlegg(void 0);
2219
2247
  setSteg("felt");
2220
2248
  }, []);
2249
+ const mineRef = useRef4(null);
2250
+ const tilleggUtkast = useRef4(/* @__PURE__ */ new Map());
2221
2251
  const gaaTilbake = useCallback2(() => {
2222
2252
  setFeil(void 0);
2223
2253
  if (steg === "mine") {
2254
+ if (mineRef.current?.lukkFelt()) return;
2224
2255
  if (mineDirekte) lukk();
2225
2256
  else setSteg("valg");
2226
2257
  return;
@@ -2443,6 +2474,8 @@ function Widget({
2443
2474
  steg === "mine" ? /* @__PURE__ */ jsx9(
2444
2475
  MineInnspill,
2445
2476
  {
2477
+ ref: mineRef,
2478
+ utkastLager: tilleggUtkast.current,
2446
2479
  storage: client.storage,
2447
2480
  rader: mine,
2448
2481
  laster: lasterMine,
@@ -2496,8 +2529,8 @@ function InnspelProvider({
2496
2529
  }) {
2497
2530
  const [synlig, setSynlig] = useState5(false);
2498
2531
  const [apneOpsjoner, setApneOpsjoner] = useState5();
2499
- const registrert = useRef4(false);
2500
- const rootRef = useRef4(null);
2532
+ const registrert = useRef5(false);
2533
+ const rootRef = useRef5(null);
2501
2534
  const privat = useMemo4(createPrivateRegistry, []);
2502
2535
  const open = useCallback3(
2503
2536
  async (options) => {
@@ -2544,11 +2577,11 @@ function useInnspel() {
2544
2577
  }
2545
2578
 
2546
2579
  // src/InnspelPrivate.tsx
2547
- import { useEffect as useEffect3, useRef as useRef5 } from "react";
2580
+ import { useEffect as useEffect3, useRef as useRef6 } from "react";
2548
2581
  import { View as View10 } from "react-native";
2549
2582
  import { jsx as jsx11 } from "react/jsx-runtime";
2550
2583
  function InnspelPrivate({ children, style }) {
2551
- const ref = useRef5(null);
2584
+ const ref = useRef6(null);
2552
2585
  const kontekst = useSkjermbilde();
2553
2586
  const registrer = kontekst?.privat.register;
2554
2587
  useEffect3(() => {