@ai-matrx/design-system 0.86.365 → 0.86.367

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.
Files changed (75) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/carousel.js +3 -3
  3. package/dist/{chunk-RO5CRIOL.js → chunk-3JEAXZKX.js} +2 -2
  4. package/dist/{chunk-HS6GMHKZ.js → chunk-CZGTZJPS.js} +3 -3
  5. package/dist/chunk-CZGTZJPS.js.map +1 -0
  6. package/dist/{chunk-5Z5GTXKL.js → chunk-FEITX4L3.js} +2 -2
  7. package/dist/{chunk-GUGBVQ4T.js → chunk-OAK4ENIP.js} +3 -3
  8. package/dist/{chunk-UGUVTE77.js → chunk-QEQDJBNK.js} +2 -2
  9. package/dist/{chunk-QJ6SQNXD.js → chunk-TBWKBTPM.js} +2 -2
  10. package/dist/{chunk-2QFA6CK4.js → chunk-UAIBCPMB.js} +2 -2
  11. package/dist/{chunk-VOLSYNJY.js → chunk-VG765KBC.js} +2 -2
  12. package/dist/content-transfer.css +3 -1
  13. package/dist/controls.cjs +2 -2
  14. package/dist/controls.cjs.map +1 -1
  15. package/dist/controls.css +7 -2
  16. package/dist/controls.js +3 -3
  17. package/dist/data-table/data-row-inspector.cjs +2 -2
  18. package/dist/data-table/data-row-inspector.cjs.map +1 -1
  19. package/dist/data-table/data-row-inspector.js +3 -3
  20. package/dist/data-table/data-row-window.cjs +2 -2
  21. package/dist/data-table/data-row-window.cjs.map +1 -1
  22. package/dist/data-table/data-row-window.js +4 -4
  23. package/dist/data-table/drill-chart.cjs +2 -2
  24. package/dist/data-table/drill-chart.cjs.map +1 -1
  25. package/dist/data-table/drill-chart.js +2 -2
  26. package/dist/data-table/index.cjs +8 -3
  27. package/dist/data-table/index.cjs.map +1 -1
  28. package/dist/data-table/index.d.cts +7 -0
  29. package/dist/data-table/index.d.ts +7 -0
  30. package/dist/data-table/index.js +11 -6
  31. package/dist/data-table/index.js.map +1 -1
  32. package/dist/data-table/types.cjs.map +1 -1
  33. package/dist/data-table/types.d.cts +7 -0
  34. package/dist/data-table/types.d.ts +7 -0
  35. package/dist/data-table/uuid-cell.cjs +2 -2
  36. package/dist/data-table/uuid-cell.cjs.map +1 -1
  37. package/dist/data-table/uuid-cell.js +2 -2
  38. package/dist/desktop.cjs +2 -2
  39. package/dist/desktop.cjs.map +1 -1
  40. package/dist/desktop.js +3 -3
  41. package/dist/email-input-dialog.cjs +2 -2
  42. package/dist/email-input-dialog.cjs.map +1 -1
  43. package/dist/email-input-dialog.js +2 -2
  44. package/dist/error-sentence.cjs +2 -2
  45. package/dist/error-sentence.cjs.map +1 -1
  46. package/dist/error-sentence.js +1 -1
  47. package/dist/index.cjs +55 -31
  48. package/dist/index.cjs.map +1 -1
  49. package/dist/index.d.cts +19 -4
  50. package/dist/index.d.ts +19 -4
  51. package/dist/index.js +59 -35
  52. package/dist/index.js.map +1 -1
  53. package/dist/lite-table.cjs +2 -2
  54. package/dist/lite-table.cjs.map +1 -1
  55. package/dist/lite-table.js +3 -3
  56. package/dist/record-list.cjs +2 -2
  57. package/dist/record-list.cjs.map +1 -1
  58. package/dist/record-list.js +3 -3
  59. package/dist/swipe-deck.cjs +3 -3
  60. package/dist/swipe-deck.cjs.map +1 -1
  61. package/dist/swipe-deck.css +9 -0
  62. package/dist/swipe-deck.js +3 -3
  63. package/dist/swipe-deck.js.map +1 -1
  64. package/dist/text-input-dialog.cjs +2 -2
  65. package/dist/text-input-dialog.cjs.map +1 -1
  66. package/dist/text-input-dialog.js +2 -2
  67. package/package.json +2 -2
  68. package/dist/chunk-HS6GMHKZ.js.map +0 -1
  69. /package/dist/{chunk-RO5CRIOL.js.map → chunk-3JEAXZKX.js.map} +0 -0
  70. /package/dist/{chunk-5Z5GTXKL.js.map → chunk-FEITX4L3.js.map} +0 -0
  71. /package/dist/{chunk-GUGBVQ4T.js.map → chunk-OAK4ENIP.js.map} +0 -0
  72. /package/dist/{chunk-UGUVTE77.js.map → chunk-QEQDJBNK.js.map} +0 -0
  73. /package/dist/{chunk-QJ6SQNXD.js.map → chunk-TBWKBTPM.js.map} +0 -0
  74. /package/dist/{chunk-2QFA6CK4.js.map → chunk-UAIBCPMB.js.map} +0 -0
  75. /package/dist/{chunk-VOLSYNJY.js.map → chunk-VG765KBC.js.map} +0 -0
@@ -7,7 +7,7 @@ import {
7
7
  } from "./chunk-XERGQT2M.js";
8
8
  import {
9
9
  ErrorActions
10
- } from "./chunk-5Z5GTXKL.js";
10
+ } from "./chunk-FEITX4L3.js";
11
11
  import {
12
12
  Dialog,
13
13
  DialogContent,
@@ -21,7 +21,7 @@ import "./chunk-U24MOJWK.js";
21
21
  import "./chunk-NDTDBBMM.js";
22
22
  import "./chunk-BKCJUFD3.js";
23
23
  import "./chunk-MOZRIHJF.js";
24
- import "./chunk-HS6GMHKZ.js";
24
+ import "./chunk-CZGTZJPS.js";
25
25
  import "./chunk-WFITMVDB.js";
26
26
  import "./chunk-WAT2XW7L.js";
27
27
  import {
@@ -38,7 +38,7 @@ var RULES = [
38
38
  { code: "EACCES", test: /\bEACCES\b|\bEPERM\b|permission denied|operation not permitted|not authori[sz]ed by the user/i, cause: "Matrx isn't allowed to do that. Grant access in System Settings \u203A Privacy & Security, then try again." },
39
39
  { code: "EADDRINUSE", test: /\bEADDRINUSE\b|address already in use|port .* (is )?(already )?in use/i, cause: "Another program is already using that port. Stop it, or choose another port." },
40
40
  { code: "ECONNREFUSED", test: /\bECONNREFUSED\b|connection refused/i, cause: "The service isn't answering. It may have stopped; start it again." },
41
- { code: "OFFLINE", test: /\bENOTFOUND\b|\bEAI_AGAIN\b|\bENETUNREACH\b|getaddrinfo|network (is )?unreachable|failed to fetch|offline/i, cause: "Can't reach the internet. Check the connection and try again." },
41
+ { code: "OFFLINE", test: /\bENOTFOUND\b|\bEAI_AGAIN\b|\bENETUNREACH\b|getaddrinfo|network (is )?unreachable|failed to fetch|offline|(?:could ?n[o']t|cannot|can't) be reached/i, cause: "Can't reach the internet. Check the connection and try again." },
42
42
  { code: "TIMEOUT", test: /\bETIMEDOUT\b|timed? ?out|\bTIMEOUT\b|deadline exceeded/i, cause: "It took too long to answer. Try again in a moment." },
43
43
  { code: "ENOSPC", test: /\bENOSPC\b|no space left/i, cause: "The disk is full. Free some space, then try again." },
44
44
  { code: "ENOMEM", test: /\bENOMEM\b|out of memory|cannot allocate memory/i, cause: "The computer ran out of memory. Close something and try again." },
@@ -106,7 +106,7 @@ function offlineText(text) {
106
106
  return t !== "" && (describeError(t).code === "OFFLINE" || /networkerror|network request failed|load failed/i.test(t));
107
107
  }
108
108
  var ANY_HOST_CODES = /* @__PURE__ */ new Set(["OFFLINE", "TIMEOUT", "UNAUTHORIZED", "FORBIDDEN", "NOT_FOUND", "RATE_LIMIT", "SERVER"]);
109
- var MACHINE_PREFIX = /^\s*(?:\[[\w./-]+\]\s*|[a-z][\w]*(?:[._][\w]+)+:\s+)/;
109
+ var MACHINE_PREFIX = /^\s*(?:\[[\w./-]+\]\s*|[a-z][\w]*(?:[._][\w]+)+:\s+|[a-z]+(?:[A-Z][a-z0-9]*)+:\s+)/;
110
110
  var RAW_TEXT = /\b(?:Type|Reference|Syntax|Range|Internal|Eval|URI)Error\b|\bat\s+[\w$.<>]+\s*\(|\.(?:[cm]?[jt]sx?|py):\d+|(?:^|[\s(])(?:\/[\w.@-]+){2,}|\bundefined is not\b|\bcannot read propert(?:y|ies)\b|\bis not a function\b|\bunexpected token\b/i;
111
111
  function isRawErrorText(text) {
112
112
  return MACHINE_PREFIX.test(text) || RAW_TEXT.test(text);
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/error-sentence.ts","../src/desktop/errors.ts"],"sourcesContent":["/**\n * THE SENTENCE A PERSON READS FOR AN ERROR — the one funnel every error surface draws through\n * (ErrorNotice, ErrorBox, the desktop Banner). Raw error text never reaches the screen: no\n * \"TypeError: Failed to fetch\", no `sidebar_conversations:` RPC prefix, no stack frame or file\n * path (Arman, 2026-10-24: notices are small and plain). The raw error still travels to the\n * Alchemy Menu / AI payload through the `error` prop; only the screen gets the sentence.\n *\n * The wording table is desktop/errors.ts `describeError` (one table for every screen); this file\n * adds what decides WHEN a sentence must go through it, narrow enough that an app's own sentence\n * (\"PDF too large\") passes untouched.\n */\nimport { describeError } from \"./desktop/errors\";\n\n/**\n * The sentence an error carries: its own message (string, Error, or any\n * object with a `message`). Empty when it has none.\n */\nexport function errorSentenceOf(error: unknown): string {\n if (error == null || error === true || error === false) return \"\";\n if (typeof error === \"string\") return error;\n if (typeof error !== \"object\") return String(error);\n const message = (error as { message?: unknown }).message;\n return typeof message === \"string\" ? message : \"\";\n}\n\n/**\n * What a person reads when the store cancelled a call at its statement timeout\n * (SQLSTATE 57014). Postgres' own \"canceling statement due to statement\n * timeout\" is about the database, not the person; the cancelled call rolled\n * back, so nothing was written (lane AT-SLOW, 2026-10-19). The same sentence\n * @ai-matrx/records' `TIMED_OUT_MESSAGE` gives.\n */\nexport const TIMED_OUT_SENTENCE = \"That took too long. Nothing was lost; try again.\";\n\n/** What a person reads when an error says nothing a person can use. */\nexport const FALLBACK_ERROR_SENTENCE = \"Something went wrong. Try again.\";\n\n/**\n * A notice CARD's words (the web toast, Matrx 2's floating card): a card is ~22 rem at most and its\n * action shares the row, so a line is a few words (notice-stack.ts NOTICE_TEXT_BUDGET). The same\n * causes as the sentences above, said short enough to fit at the smallest window, never cut by \"…\".\n */\nexport const CARD_ERROR_LINE = {\n OFFLINE: \"No connection\",\n TIMEOUT: \"Took too long. Nothing was lost.\",\n UNAUTHORIZED: \"Signed out. Sign in again.\",\n FORBIDDEN: \"Not allowed for this account\",\n NOT_FOUND: \"Not found. Refresh and retry.\",\n RATE_LIMIT: \"Too many requests. Wait a moment.\",\n SERVER: \"Server problem. Try again soon.\",\n FALLBACK: \"Something went wrong\",\n} as const;\n\n/** True when an error, its code, or its sentence is the store's statement timeout. */\nexport function isTimedOutError(error: unknown, message?: string | null, code?: string | number): boolean {\n if (code === \"57014\" || code === \"timed_out\") return true;\n if (error && typeof error === \"object\") {\n const o = error as { code?: unknown; sqlstate?: unknown };\n if (o.code === \"57014\" || o.code === \"timed_out\" || o.sqlstate === \"57014\") return true;\n }\n const text = `${message ?? \"\"} ${errorSentenceOf(error)}`;\n return /canceling statement due to statement timeout/i.test(text);\n}\n\n/** True when the call failed because the device is offline or the network never answered. */\nexport function isOfflineError(error: unknown, message?: string | null): boolean {\n if (typeof navigator !== \"undefined\" && navigator.onLine === false) return true;\n return offlineText(`${message ?? \"\"} ${errorSentenceOf(error)}`);\n}\n\nfunction offlineText(text: string): boolean {\n const t = text.trim();\n return t !== \"\" && (describeError(t).code === \"OFFLINE\" || /networkerror|network request failed|load failed/i.test(t));\n}\n\n/** describeError's causes that hold on every host (its process codes — ENOENT, EACCES, ports — are\n * the desktop's words for a local program and would mislead on a database refusal). */\nconst ANY_HOST_CODES = new Set([\"OFFLINE\", \"TIMEOUT\", \"UNAUTHORIZED\", \"FORBIDDEN\", \"NOT_FOUND\", \"RATE_LIMIT\", \"SERVER\"]);\n\n/** A leading machine label: `sidebar_conversations: …`, `chat.rpc_name: …`, `[chat-sidebar] …`. */\nconst MACHINE_PREFIX = /^\\s*(?:\\[[\\w./-]+\\]\\s*|[a-z][\\w]*(?:[._][\\w]+)+:\\s+)/;\n/** Text no person should read: JS error class names, stack frames, source paths. */\nconst RAW_TEXT =\n /\\b(?:Type|Reference|Syntax|Range|Internal|Eval|URI)Error\\b|\\bat\\s+[\\w$.<>]+\\s*\\(|\\.(?:[cm]?[jt]sx?|py):\\d+|(?:^|[\\s(])(?:\\/[\\w.@-]+){2,}|\\bundefined is not\\b|\\bcannot read propert(?:y|ies)\\b|\\bis not a function\\b|\\bunexpected token\\b/i;\n\n/** True when a sentence carries raw error text or a code path (what the guard refuses on screen). */\nexport function isRawErrorText(text: string): boolean {\n return MACHINE_PREFIX.test(text) || RAW_TEXT.test(text);\n}\n\n/**\n * `card: true` = the short CARD_ERROR_LINE words for a notice card. Otherwise:\n * the sentence for the screen: the timeout sentence for a statement timeout; a caller's plain\n * sentence as is; a machine label stripped from the front; anything raw or offline worded by\n * `describeError` (its table, else `fallback`).\n */\nexport function peopleErrorSentence(\n error: unknown,\n message?: string | null,\n options: { code?: string | number | undefined; fallback?: string | undefined; card?: boolean | undefined } = {},\n): string {\n const card = options.card === true;\n if (isTimedOutError(error, message, options.code)) return card ? CARD_ERROR_LINE.TIMEOUT : TIMED_OUT_SENTENCE;\n const fallback = options.fallback ?? (card ? CARD_ERROR_LINE.FALLBACK : FALLBACK_ERROR_SENTENCE);\n const raw = message?.trim() || errorSentenceOf(error).trim();\n if (!raw) return fallback;\n let text = raw;\n for (let i = 0; i < 3 && MACHINE_PREFIX.test(text); i++) text = text.replace(MACHINE_PREFIX, \"\").trim();\n if (!text) return fallback;\n if (offlineText(text) || RAW_TEXT.test(text) || text !== raw) {\n const said = describeError(text, fallback);\n if (!said.code || !ANY_HOST_CODES.has(said.code)) return fallback;\n return card ? CARD_ERROR_LINE[said.code as keyof typeof CARD_ERROR_LINE] : said.cause;\n }\n return text;\n}\n","/**\n * THE error-wording layer. A failure is shown as a cause the person can act on (\"A program it\n * needs isn't installed\"), never as the raw text a process threw (\"spawn uv ENOENT\"). The raw text\n * is kept, whole, as `detail` — the banner offers it behind Copy details and a tooltip, for a bug\n * report or an agent. One table, so every screen and every service says the same thing.\n */\n\nexport interface DescribedError {\n /** One plain sentence: what went wrong and, where it helps, what to do. */\n cause: string;\n /** The raw text, unedited (empty when it would only repeat `cause`). */\n detail: string;\n /** A short machine code when one was recognized (\"ENOENT\", \"TIMEOUT\"). */\n code?: string;\n}\n\ninterface Rule {\n code: string;\n test: RegExp;\n cause: string;\n}\n\n/** Ordered: the first rule whose pattern matches the raw text wins. */\nconst RULES: ReadonlyArray<Rule> = [\n { code: \"ENOENT\", test: /\\b(spawn\\s+\\S+\\s+)?ENOENT\\b|command not found|no such file or directory/i, cause: \"A program or file it needs isn't on this computer. Install it or update Matrx, then try again.\" },\n { code: \"EACCES\", test: /\\bEACCES\\b|\\bEPERM\\b|permission denied|operation not permitted|not authori[sz]ed by the user/i, cause: \"Matrx isn't allowed to do that. Grant access in System Settings › Privacy & Security, then try again.\" },\n { code: \"EADDRINUSE\", test: /\\bEADDRINUSE\\b|address already in use|port .* (is )?(already )?in use/i, cause: \"Another program is already using that port. Stop it, or choose another port.\" },\n { code: \"ECONNREFUSED\", test: /\\bECONNREFUSED\\b|connection refused/i, cause: \"The service isn't answering. It may have stopped; start it again.\" },\n { code: \"OFFLINE\", test: /\\bENOTFOUND\\b|\\bEAI_AGAIN\\b|\\bENETUNREACH\\b|getaddrinfo|network (is )?unreachable|failed to fetch|offline/i, cause: \"Can't reach the internet. Check the connection and try again.\" },\n { code: \"TIMEOUT\", test: /\\bETIMEDOUT\\b|timed? ?out|\\bTIMEOUT\\b|deadline exceeded/i, cause: \"It took too long to answer. Try again in a moment.\" },\n { code: \"ENOSPC\", test: /\\bENOSPC\\b|no space left/i, cause: \"The disk is full. Free some space, then try again.\" },\n { code: \"ENOMEM\", test: /\\bENOMEM\\b|out of memory|cannot allocate memory/i, cause: \"The computer ran out of memory. Close something and try again.\" },\n { code: \"UNAUTHORIZED\", test: /\\b401\\b|unauthori[sz]ed|invalid (api )?key|not signed in|jwt expired|session expired/i, cause: \"You're signed out, or the key was refused. Sign in again.\" },\n { code: \"FORBIDDEN\", test: /\\b403\\b|forbidden/i, cause: \"This account isn't allowed to do that.\" },\n { code: \"NOT_FOUND\", test: /\\b404\\b|not found/i, cause: \"It isn't there any more. Refresh and try again.\" },\n { code: \"RATE_LIMIT\", test: /\\b429\\b|rate.?limit|too many requests/i, cause: \"Too many requests just now. Wait a moment and try again.\" },\n { code: \"SERVER\", test: /\\b5\\d\\d\\b|internal server error|bad gateway|service unavailable/i, cause: \"The server had a problem. Try again in a moment.\" },\n { code: \"EXITED\", test: /exited with code|process exited|crashed|SIGKILL|SIGSEGV|SIGTERM/i, cause: \"The service stopped unexpectedly. Start it again; Copy details if it keeps happening.\" },\n];\n\nconst RAW = /\\b[A-Z]{2,}[A-Z_]*\\b|[\\\\/][\\w.-]+[\\\\/]|\\bat \\S+ \\(|\\{|\\}|errno|stack|undefined|null|\\bspawn\\b/;\n\nfunction rawText(error: unknown): string {\n if (error instanceof Error) return error.message || error.name;\n if (typeof error === \"string\") return error;\n if (error && typeof error === \"object\" && \"message\" in error && typeof (error as { message: unknown }).message === \"string\") {\n return (error as { message: string }).message;\n }\n return \"\";\n}\n\n/**\n * Turn any thrown or returned error into words a person can act on. Already-humane text (a full\n * sentence the app wrote itself, with no codes, paths or stack) passes through unchanged.\n */\nexport function describeError(error: unknown, fallback = \"Something went wrong. Try again.\"): DescribedError {\n const detail = rawText(error).trim();\n if (!detail) return { cause: fallback, detail: \"\" };\n for (const rule of RULES) {\n if (rule.test.test(detail)) return { cause: rule.cause, detail, code: rule.code };\n }\n if (!RAW.test(detail) && detail.length <= 160) return { cause: detail, detail: \"\" };\n return { cause: fallback, detail };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACuBA,IAAM,QAA6B;AAAA,EACjC,EAAE,MAAM,UAAU,MAAM,4EAA4E,OAAO,iGAAiG;AAAA,EAC5M,EAAE,MAAM,UAAU,MAAM,iGAAiG,OAAO,6GAAwG;AAAA,EACxO,EAAE,MAAM,cAAc,MAAM,0EAA0E,OAAO,+EAA+E;AAAA,EAC5L,EAAE,MAAM,gBAAgB,MAAM,wCAAwC,OAAO,oEAAoE;AAAA,EACjJ,EAAE,MAAM,WAAW,MAAM,8GAA8G,OAAO,gEAAgE;AAAA,EAC9M,EAAE,MAAM,WAAW,MAAM,4DAA4D,OAAO,qDAAqD;AAAA,EACjJ,EAAE,MAAM,UAAU,MAAM,6BAA6B,OAAO,qDAAqD;AAAA,EACjH,EAAE,MAAM,UAAU,MAAM,oDAAoD,OAAO,iEAAiE;AAAA,EACpJ,EAAE,MAAM,gBAAgB,MAAM,yFAAyF,OAAO,4DAA4D;AAAA,EAC1L,EAAE,MAAM,aAAa,MAAM,sBAAsB,OAAO,yCAAyC;AAAA,EACjG,EAAE,MAAM,aAAa,MAAM,sBAAsB,OAAO,kDAAkD;AAAA,EAC1G,EAAE,MAAM,cAAc,MAAM,0CAA0C,OAAO,2DAA2D;AAAA,EACxI,EAAE,MAAM,UAAU,MAAM,oEAAoE,OAAO,mDAAmD;AAAA,EACtJ,EAAE,MAAM,UAAU,MAAM,oEAAoE,OAAO,wFAAwF;AAC7L;AAEA,IAAM,MAAM;AAEZ,SAAS,QAAQ,OAAwB;AACvC,MAAI,iBAAiB,MAAO,QAAO,MAAM,WAAW,MAAM;AAC1D,MAAI,OAAO,UAAU,SAAU,QAAO;AACtC,MAAI,SAAS,OAAO,UAAU,YAAY,aAAa,SAAS,OAAQ,MAA+B,YAAY,UAAU;AAC3H,WAAQ,MAA8B;AAAA,EACxC;AACA,SAAO;AACT;AAMO,SAAS,cAAc,OAAgB,WAAW,oCAAoD;AAC3G,QAAM,SAAS,QAAQ,KAAK,EAAE,KAAK;AACnC,MAAI,CAAC,OAAQ,QAAO,EAAE,OAAO,UAAU,QAAQ,GAAG;AAClD,aAAW,QAAQ,OAAO;AACxB,QAAI,KAAK,KAAK,KAAK,MAAM,EAAG,QAAO,EAAE,OAAO,KAAK,OAAO,QAAQ,MAAM,KAAK,KAAK;AAAA,EAClF;AACA,MAAI,CAAC,IAAI,KAAK,MAAM,KAAK,OAAO,UAAU,IAAK,QAAO,EAAE,OAAO,QAAQ,QAAQ,GAAG;AAClF,SAAO,EAAE,OAAO,UAAU,OAAO;AACnC;;;AD9CO,SAAS,gBAAgB,OAAwB;AACtD,MAAI,SAAS,QAAQ,UAAU,QAAQ,UAAU,MAAO,QAAO;AAC/D,MAAI,OAAO,UAAU,SAAU,QAAO;AACtC,MAAI,OAAO,UAAU,SAAU,QAAO,OAAO,KAAK;AAClD,QAAM,UAAW,MAAgC;AACjD,SAAO,OAAO,YAAY,WAAW,UAAU;AACjD;AASO,IAAM,qBAAqB;AAG3B,IAAM,0BAA0B;AAOhC,IAAM,kBAAkB;AAAA,EAC7B,SAAS;AAAA,EACT,SAAS;AAAA,EACT,cAAc;AAAA,EACd,WAAW;AAAA,EACX,WAAW;AAAA,EACX,YAAY;AAAA,EACZ,QAAQ;AAAA,EACR,UAAU;AACZ;AAGO,SAAS,gBAAgB,OAAgB,SAAyB,MAAiC;AACxG,MAAI,SAAS,WAAW,SAAS,YAAa,QAAO;AACrD,MAAI,SAAS,OAAO,UAAU,UAAU;AACtC,UAAM,IAAI;AACV,QAAI,EAAE,SAAS,WAAW,EAAE,SAAS,eAAe,EAAE,aAAa,QAAS,QAAO;AAAA,EACrF;AACA,QAAM,OAAO,GAAG,WAAW,EAAE,IAAI,gBAAgB,KAAK,CAAC;AACvD,SAAO,gDAAgD,KAAK,IAAI;AAClE;AAGO,SAAS,eAAe,OAAgB,SAAkC;AAC/E,MAAI,OAAO,cAAc,eAAe,UAAU,WAAW,MAAO,QAAO;AAC3E,SAAO,YAAY,GAAG,WAAW,EAAE,IAAI,gBAAgB,KAAK,CAAC,EAAE;AACjE;AAEA,SAAS,YAAY,MAAuB;AAC1C,QAAM,IAAI,KAAK,KAAK;AACpB,SAAO,MAAM,OAAO,cAAc,CAAC,EAAE,SAAS,aAAa,mDAAmD,KAAK,CAAC;AACtH;AAIA,IAAM,iBAAiB,oBAAI,IAAI,CAAC,WAAW,WAAW,gBAAgB,aAAa,aAAa,cAAc,QAAQ,CAAC;AAGvH,IAAM,iBAAiB;AAEvB,IAAM,WACJ;AAGK,SAAS,eAAe,MAAuB;AACpD,SAAO,eAAe,KAAK,IAAI,KAAK,SAAS,KAAK,IAAI;AACxD;AAQO,SAAS,oBACd,OACA,SACA,UAA6G,CAAC,GACtG;AACR,QAAM,OAAO,QAAQ,SAAS;AAC9B,MAAI,gBAAgB,OAAO,SAAS,QAAQ,IAAI,EAAG,QAAO,OAAO,gBAAgB,UAAU;AAC3F,QAAM,WAAW,QAAQ,aAAa,OAAO,gBAAgB,WAAW;AACxE,QAAM,MAAM,SAAS,KAAK,KAAK,gBAAgB,KAAK,EAAE,KAAK;AAC3D,MAAI,CAAC,IAAK,QAAO;AACjB,MAAI,OAAO;AACX,WAAS,IAAI,GAAG,IAAI,KAAK,eAAe,KAAK,IAAI,GAAG,IAAK,QAAO,KAAK,QAAQ,gBAAgB,EAAE,EAAE,KAAK;AACtG,MAAI,CAAC,KAAM,QAAO;AAClB,MAAI,YAAY,IAAI,KAAK,SAAS,KAAK,IAAI,KAAK,SAAS,KAAK;AAC5D,UAAM,OAAO,cAAc,MAAM,QAAQ;AACzC,QAAI,CAAC,KAAK,QAAQ,CAAC,eAAe,IAAI,KAAK,IAAI,EAAG,QAAO;AACzD,WAAO,OAAO,gBAAgB,KAAK,IAAoC,IAAI,KAAK;AAAA,EAClF;AACA,SAAO;AACT;","names":[]}
1
+ {"version":3,"sources":["../src/error-sentence.ts","../src/desktop/errors.ts"],"sourcesContent":["/**\n * THE SENTENCE A PERSON READS FOR AN ERROR — the one funnel every error surface draws through\n * (ErrorNotice, ErrorBox, the desktop Banner). Raw error text never reaches the screen: no\n * \"TypeError: Failed to fetch\", no `sidebar_conversations:` RPC prefix, no stack frame or file\n * path (Arman, 2026-10-24: notices are small and plain). The raw error still travels to the\n * Alchemy Menu / AI payload through the `error` prop; only the screen gets the sentence.\n *\n * The wording table is desktop/errors.ts `describeError` (one table for every screen); this file\n * adds what decides WHEN a sentence must go through it, narrow enough that an app's own sentence\n * (\"PDF too large\") passes untouched.\n */\nimport { describeError } from \"./desktop/errors\";\n\n/**\n * The sentence an error carries: its own message (string, Error, or any\n * object with a `message`). Empty when it has none.\n */\nexport function errorSentenceOf(error: unknown): string {\n if (error == null || error === true || error === false) return \"\";\n if (typeof error === \"string\") return error;\n if (typeof error !== \"object\") return String(error);\n const message = (error as { message?: unknown }).message;\n return typeof message === \"string\" ? message : \"\";\n}\n\n/**\n * What a person reads when the store cancelled a call at its statement timeout\n * (SQLSTATE 57014). Postgres' own \"canceling statement due to statement\n * timeout\" is about the database, not the person; the cancelled call rolled\n * back, so nothing was written (lane AT-SLOW, 2026-10-19). The same sentence\n * @ai-matrx/records' `TIMED_OUT_MESSAGE` gives.\n */\nexport const TIMED_OUT_SENTENCE = \"That took too long. Nothing was lost; try again.\";\n\n/** What a person reads when an error says nothing a person can use. */\nexport const FALLBACK_ERROR_SENTENCE = \"Something went wrong. Try again.\";\n\n/**\n * A notice CARD's words (the web toast, Matrx 2's floating card): a card is ~22 rem at most and its\n * action shares the row, so a line is a few words (notice-stack.ts NOTICE_TEXT_BUDGET). The same\n * causes as the sentences above, said short enough to fit at the smallest window, never cut by \"…\".\n */\nexport const CARD_ERROR_LINE = {\n OFFLINE: \"No connection\",\n TIMEOUT: \"Took too long. Nothing was lost.\",\n UNAUTHORIZED: \"Signed out. Sign in again.\",\n FORBIDDEN: \"Not allowed for this account\",\n NOT_FOUND: \"Not found. Refresh and retry.\",\n RATE_LIMIT: \"Too many requests. Wait a moment.\",\n SERVER: \"Server problem. Try again soon.\",\n FALLBACK: \"Something went wrong\",\n} as const;\n\n/** True when an error, its code, or its sentence is the store's statement timeout. */\nexport function isTimedOutError(error: unknown, message?: string | null, code?: string | number): boolean {\n if (code === \"57014\" || code === \"timed_out\") return true;\n if (error && typeof error === \"object\") {\n const o = error as { code?: unknown; sqlstate?: unknown };\n if (o.code === \"57014\" || o.code === \"timed_out\" || o.sqlstate === \"57014\") return true;\n }\n const text = `${message ?? \"\"} ${errorSentenceOf(error)}`;\n return /canceling statement due to statement timeout/i.test(text);\n}\n\n/** True when the call failed because the device is offline or the network never answered. */\nexport function isOfflineError(error: unknown, message?: string | null): boolean {\n if (typeof navigator !== \"undefined\" && navigator.onLine === false) return true;\n return offlineText(`${message ?? \"\"} ${errorSentenceOf(error)}`);\n}\n\nfunction offlineText(text: string): boolean {\n const t = text.trim();\n return t !== \"\" && (describeError(t).code === \"OFFLINE\" || /networkerror|network request failed|load failed/i.test(t));\n}\n\n/** describeError's causes that hold on every host (its process codes — ENOENT, EACCES, ports — are\n * the desktop's words for a local program and would mislead on a database refusal). */\nconst ANY_HOST_CODES = new Set([\"OFFLINE\", \"TIMEOUT\", \"UNAUTHORIZED\", \"FORBIDDEN\", \"NOT_FOUND\", \"RATE_LIMIT\", \"SERVER\"]);\n\n/** A leading machine label: `sidebar_conversations: …`, `chat.rpc_name: …`, `[chat-sidebar] …`,\n * or a camelCase operation name (`unreadByKind: …`, `pendingSoftExpiries: …`). */\nconst MACHINE_PREFIX = /^\\s*(?:\\[[\\w./-]+\\]\\s*|[a-z][\\w]*(?:[._][\\w]+)+:\\s+|[a-z]+(?:[A-Z][a-z0-9]*)+:\\s+)/;\n/** Text no person should read: JS error class names, stack frames, source paths. */\nconst RAW_TEXT =\n /\\b(?:Type|Reference|Syntax|Range|Internal|Eval|URI)Error\\b|\\bat\\s+[\\w$.<>]+\\s*\\(|\\.(?:[cm]?[jt]sx?|py):\\d+|(?:^|[\\s(])(?:\\/[\\w.@-]+){2,}|\\bundefined is not\\b|\\bcannot read propert(?:y|ies)\\b|\\bis not a function\\b|\\bunexpected token\\b/i;\n\n/** True when a sentence carries raw error text or a code path (what the guard refuses on screen). */\nexport function isRawErrorText(text: string): boolean {\n return MACHINE_PREFIX.test(text) || RAW_TEXT.test(text);\n}\n\n/**\n * `card: true` = the short CARD_ERROR_LINE words for a notice card. Otherwise:\n * the sentence for the screen: the timeout sentence for a statement timeout; a caller's plain\n * sentence as is; a machine label stripped from the front; anything raw or offline worded by\n * `describeError` (its table, else `fallback`).\n */\nexport function peopleErrorSentence(\n error: unknown,\n message?: string | null,\n options: { code?: string | number | undefined; fallback?: string | undefined; card?: boolean | undefined } = {},\n): string {\n const card = options.card === true;\n if (isTimedOutError(error, message, options.code)) return card ? CARD_ERROR_LINE.TIMEOUT : TIMED_OUT_SENTENCE;\n const fallback = options.fallback ?? (card ? CARD_ERROR_LINE.FALLBACK : FALLBACK_ERROR_SENTENCE);\n const raw = message?.trim() || errorSentenceOf(error).trim();\n if (!raw) return fallback;\n let text = raw;\n for (let i = 0; i < 3 && MACHINE_PREFIX.test(text); i++) text = text.replace(MACHINE_PREFIX, \"\").trim();\n if (!text) return fallback;\n if (offlineText(text) || RAW_TEXT.test(text) || text !== raw) {\n const said = describeError(text, fallback);\n if (!said.code || !ANY_HOST_CODES.has(said.code)) return fallback;\n return card ? CARD_ERROR_LINE[said.code as keyof typeof CARD_ERROR_LINE] : said.cause;\n }\n return text;\n}\n","/**\n * THE error-wording layer. A failure is shown as a cause the person can act on (\"A program it\n * needs isn't installed\"), never as the raw text a process threw (\"spawn uv ENOENT\"). The raw text\n * is kept, whole, as `detail` — the banner offers it behind Copy details and a tooltip, for a bug\n * report or an agent. One table, so every screen and every service says the same thing.\n */\n\nexport interface DescribedError {\n /** One plain sentence: what went wrong and, where it helps, what to do. */\n cause: string;\n /** The raw text, unedited (empty when it would only repeat `cause`). */\n detail: string;\n /** A short machine code when one was recognized (\"ENOENT\", \"TIMEOUT\"). */\n code?: string;\n}\n\ninterface Rule {\n code: string;\n test: RegExp;\n cause: string;\n}\n\n/** Ordered: the first rule whose pattern matches the raw text wins. */\nconst RULES: ReadonlyArray<Rule> = [\n { code: \"ENOENT\", test: /\\b(spawn\\s+\\S+\\s+)?ENOENT\\b|command not found|no such file or directory/i, cause: \"A program or file it needs isn't on this computer. Install it or update Matrx, then try again.\" },\n { code: \"EACCES\", test: /\\bEACCES\\b|\\bEPERM\\b|permission denied|operation not permitted|not authori[sz]ed by the user/i, cause: \"Matrx isn't allowed to do that. Grant access in System Settings › Privacy & Security, then try again.\" },\n { code: \"EADDRINUSE\", test: /\\bEADDRINUSE\\b|address already in use|port .* (is )?(already )?in use/i, cause: \"Another program is already using that port. Stop it, or choose another port.\" },\n { code: \"ECONNREFUSED\", test: /\\bECONNREFUSED\\b|connection refused/i, cause: \"The service isn't answering. It may have stopped; start it again.\" },\n { code: \"OFFLINE\", test: /\\bENOTFOUND\\b|\\bEAI_AGAIN\\b|\\bENETUNREACH\\b|getaddrinfo|network (is )?unreachable|failed to fetch|offline|(?:could ?n[o']t|cannot|can't) be reached/i, cause: \"Can't reach the internet. Check the connection and try again.\" },\n { code: \"TIMEOUT\", test: /\\bETIMEDOUT\\b|timed? ?out|\\bTIMEOUT\\b|deadline exceeded/i, cause: \"It took too long to answer. Try again in a moment.\" },\n { code: \"ENOSPC\", test: /\\bENOSPC\\b|no space left/i, cause: \"The disk is full. Free some space, then try again.\" },\n { code: \"ENOMEM\", test: /\\bENOMEM\\b|out of memory|cannot allocate memory/i, cause: \"The computer ran out of memory. Close something and try again.\" },\n { code: \"UNAUTHORIZED\", test: /\\b401\\b|unauthori[sz]ed|invalid (api )?key|not signed in|jwt expired|session expired/i, cause: \"You're signed out, or the key was refused. Sign in again.\" },\n { code: \"FORBIDDEN\", test: /\\b403\\b|forbidden/i, cause: \"This account isn't allowed to do that.\" },\n { code: \"NOT_FOUND\", test: /\\b404\\b|not found/i, cause: \"It isn't there any more. Refresh and try again.\" },\n { code: \"RATE_LIMIT\", test: /\\b429\\b|rate.?limit|too many requests/i, cause: \"Too many requests just now. Wait a moment and try again.\" },\n { code: \"SERVER\", test: /\\b5\\d\\d\\b|internal server error|bad gateway|service unavailable/i, cause: \"The server had a problem. Try again in a moment.\" },\n { code: \"EXITED\", test: /exited with code|process exited|crashed|SIGKILL|SIGSEGV|SIGTERM/i, cause: \"The service stopped unexpectedly. Start it again; Copy details if it keeps happening.\" },\n];\n\nconst RAW = /\\b[A-Z]{2,}[A-Z_]*\\b|[\\\\/][\\w.-]+[\\\\/]|\\bat \\S+ \\(|\\{|\\}|errno|stack|undefined|null|\\bspawn\\b/;\n\nfunction rawText(error: unknown): string {\n if (error instanceof Error) return error.message || error.name;\n if (typeof error === \"string\") return error;\n if (error && typeof error === \"object\" && \"message\" in error && typeof (error as { message: unknown }).message === \"string\") {\n return (error as { message: string }).message;\n }\n return \"\";\n}\n\n/**\n * Turn any thrown or returned error into words a person can act on. Already-humane text (a full\n * sentence the app wrote itself, with no codes, paths or stack) passes through unchanged.\n */\nexport function describeError(error: unknown, fallback = \"Something went wrong. Try again.\"): DescribedError {\n const detail = rawText(error).trim();\n if (!detail) return { cause: fallback, detail: \"\" };\n for (const rule of RULES) {\n if (rule.test.test(detail)) return { cause: rule.cause, detail, code: rule.code };\n }\n if (!RAW.test(detail) && detail.length <= 160) return { cause: detail, detail: \"\" };\n return { cause: fallback, detail };\n}\n"],"mappings":"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","names":[]}
@@ -8,7 +8,7 @@ import {
8
8
  isRawErrorText,
9
9
  isTimedOutError,
10
10
  peopleErrorSentence
11
- } from "./chunk-HS6GMHKZ.js";
11
+ } from "./chunk-CZGTZJPS.js";
12
12
  export {
13
13
  CARD_ERROR_LINE,
14
14
  FALLBACK_ERROR_SENTENCE,
package/dist/index.cjs CHANGED
@@ -1346,7 +1346,7 @@ var init_errors = __esm({
1346
1346
  { code: "EACCES", test: /\bEACCES\b|\bEPERM\b|permission denied|operation not permitted|not authori[sz]ed by the user/i, cause: "Matrx isn't allowed to do that. Grant access in System Settings \u203A Privacy & Security, then try again." },
1347
1347
  { code: "EADDRINUSE", test: /\bEADDRINUSE\b|address already in use|port .* (is )?(already )?in use/i, cause: "Another program is already using that port. Stop it, or choose another port." },
1348
1348
  { code: "ECONNREFUSED", test: /\bECONNREFUSED\b|connection refused/i, cause: "The service isn't answering. It may have stopped; start it again." },
1349
- { code: "OFFLINE", test: /\bENOTFOUND\b|\bEAI_AGAIN\b|\bENETUNREACH\b|getaddrinfo|network (is )?unreachable|failed to fetch|offline/i, cause: "Can't reach the internet. Check the connection and try again." },
1349
+ { code: "OFFLINE", test: /\bENOTFOUND\b|\bEAI_AGAIN\b|\bENETUNREACH\b|getaddrinfo|network (is )?unreachable|failed to fetch|offline|(?:could ?n[o']t|cannot|can't) be reached/i, cause: "Can't reach the internet. Check the connection and try again." },
1350
1350
  { code: "TIMEOUT", test: /\bETIMEDOUT\b|timed? ?out|\bTIMEOUT\b|deadline exceeded/i, cause: "It took too long to answer. Try again in a moment." },
1351
1351
  { code: "ENOSPC", test: /\bENOSPC\b|no space left/i, cause: "The disk is full. Free some space, then try again." },
1352
1352
  { code: "ENOMEM", test: /\bENOMEM\b|out of memory|cannot allocate memory/i, cause: "The computer ran out of memory. Close something and try again." },
@@ -1423,7 +1423,7 @@ var init_error_sentence = __esm({
1423
1423
  FALLBACK: "Something went wrong"
1424
1424
  };
1425
1425
  ANY_HOST_CODES = /* @__PURE__ */ new Set(["OFFLINE", "TIMEOUT", "UNAUTHORIZED", "FORBIDDEN", "NOT_FOUND", "RATE_LIMIT", "SERVER"]);
1426
- MACHINE_PREFIX = /^\s*(?:\[[\w./-]+\]\s*|[a-z][\w]*(?:[._][\w]+)+:\s+)/;
1426
+ MACHINE_PREFIX = /^\s*(?:\[[\w./-]+\]\s*|[a-z][\w]*(?:[._][\w]+)+:\s+|[a-z]+(?:[A-Z][a-z0-9]*)+:\s+)/;
1427
1427
  RAW_TEXT = /\b(?:Type|Reference|Syntax|Range|Internal|Eval|URI)Error\b|\bat\s+[\w$.<>]+\s*\(|\.(?:[cm]?[jt]sx?|py):\d+|(?:^|[\s(])(?:\/[\w.@-]+){2,}|\bundefined is not\b|\bcannot read propert(?:y|ies)\b|\bis not a function\b|\bunexpected token\b/i;
1428
1428
  }
1429
1429
  });
@@ -14531,15 +14531,49 @@ function compactCount(n) {
14531
14531
  var import_jsx_runtime92 = require("react/jsx-runtime");
14532
14532
  var HostContext2 = React61.createContext({});
14533
14533
  function ContactValuesHostProvider({ children, ...host }) {
14534
- const value = React61.useMemo(() => host, [host.validateAddress, host.searchWeb]);
14534
+ const value = React61.useMemo(() => host, [host.validateAddress, host.searchWeb, host.prefetchWebSearch]);
14535
14535
  return /* @__PURE__ */ (0, import_jsx_runtime92.jsx)(HostContext2.Provider, { value, children });
14536
14536
  }
14537
14537
  function useContactValuesHost() {
14538
14538
  return React61.useContext(HostContext2);
14539
14539
  }
14540
- function useSearchRow() {
14541
- const { searchWeb } = useContactValuesHost();
14542
- return (query) => searchWeb ? { text: "Search the web", glyph: SearchIcon, onSelect: () => searchWeb(query) } : { text: "Search the web", glyph: SearchIcon, href: webSearchHref(query) };
14540
+ var NO_STATUS = { phase: "error", count: null };
14541
+ var NO_PREFETCH = {
14542
+ get: () => NO_STATUS,
14543
+ subscribe: () => () => {
14544
+ }
14545
+ };
14546
+ function useSearchRow(query, open) {
14547
+ const { searchWeb, prefetchWebSearch } = useContactValuesHost();
14548
+ const [prefetch, setPrefetch] = React61.useState(null);
14549
+ React61.useEffect(() => {
14550
+ if (open && query && prefetchWebSearch) setPrefetch(prefetchWebSearch(query));
14551
+ }, [open, query, prefetchWebSearch]);
14552
+ const handle = prefetch ?? NO_PREFETCH;
14553
+ const status = React61.useSyncExternalStore(handle.subscribe, handle.get, handle.get);
14554
+ if (!query) return { row: null, answer: null };
14555
+ if (!searchWeb) return { row: { text: "Search the web", glyph: SearchIcon, href: webSearchHref(query) }, answer: null };
14556
+ const tag = !prefetch ? null : status.phase === "searching" ? { text: "Searching\u2026" } : status.answering ? { text: "Writing answer\u2026" } : status.phase === "ready" && status.count != null ? { text: `${status.count} results`, tone: "success" } : status.phase === "empty" ? { text: "No results" } : null;
14557
+ const answerText = prefetch && status.answer ? status.answer : null;
14558
+ return {
14559
+ // With the answer on the card, the press is for everything else the web has.
14560
+ row: { text: answerText ? "Full search results" : "Search the web", glyph: SearchIcon, onSelect: () => searchWeb(query), ...tag ? { status: tag } : {} },
14561
+ answer: answerText ? { section: "From the web", glyph: SearchIcon, text: answerText, markdown: true, clamp: 6 } : null
14562
+ };
14563
+ }
14564
+ function withSearchRow(record, { row, answer }) {
14565
+ if (!row) return record;
14566
+ const body = [...record.body ?? []];
14567
+ let at = body.findIndex((b) => typeof b === "object" && b !== null && "section" in b && b.section === "Actions");
14568
+ if (at < 0) {
14569
+ body.push({ section: "Actions", rows: [row] });
14570
+ at = body.length - 1;
14571
+ } else {
14572
+ const block = body[at];
14573
+ body[at] = { ...block, rows: [...block.rows ?? [], row] };
14574
+ }
14575
+ if (answer) body.splice(at, 0, answer);
14576
+ return { ...record, body };
14543
14577
  }
14544
14578
  var markCache = /* @__PURE__ */ new Map();
14545
14579
  function markFor(platform) {
@@ -14618,9 +14652,10 @@ function closingOnSelect(record, close) {
14618
14652
  );
14619
14653
  return { ...record, body };
14620
14654
  }
14621
- function ValueShell({ kind, glyph: Glyph, text, copy, state, record: own, peek, wrap, about }) {
14655
+ function ValueShell({ kind, glyph: Glyph, text, copy, state, record: own, peek, wrap, about, webSearch }) {
14622
14656
  const { open, setHovered, setHeld, setPinned, trigger } = usePinnedHover();
14623
- const record = closingOnSelect(withAbout(own, about), () => {
14657
+ const searchRow = useSearchRow(webSearch, open);
14658
+ const record = closingOnSelect(withSearchRow(withAbout(own, about), searchRow), () => {
14624
14659
  setPinned(false);
14625
14660
  setHeld(false);
14626
14661
  setHovered(false);
@@ -14687,7 +14722,6 @@ var actions = (rows) => ({
14687
14722
  });
14688
14723
  function EmailValue({ email, owner, state = "ok", peek = true, about }) {
14689
14724
  const parsed = parseEmail(email);
14690
- const searchRow = useSearchRow();
14691
14725
  const ok = state === "ok" && parsed.valid;
14692
14726
  const site = parsed.domain ? parseUrl(parsed.domain) : null;
14693
14727
  const record = {
@@ -14700,14 +14734,12 @@ function EmailValue({ email, owner, state = "ok", peek = true, about }) {
14700
14734
  body: [
14701
14735
  ...!parsed.valid && state === "ok" ? [{ fact: "Not a complete email address", glyph: LinkOffGlyph, muted: true }] : [],
14702
14736
  ...parsed.domain ? [{ property: "Domain", value: parsed.domain, ...ok && site?.href ? { href: site.href } : {} }] : [],
14703
- actions([
14704
- searchRow(`"${parsed.address}"`)
14705
- ])
14737
+ actions([])
14706
14738
  ],
14707
14739
  ...ok ? { primary: { label: "Send email", onSelect: () => window.location.assign(mailtoHref(parsed.address)) } } : {},
14708
14740
  copyData: { email: parsed.address, ...owner ? { owner } : {} }
14709
14741
  };
14710
- return /* @__PURE__ */ (0, import_jsx_runtime92.jsx)(ValueShell, { kind: "email", glyph: MailGlyph, text: parsed.address, copy: parsed.address, state, record, peek, ...about !== void 0 ? { about } : {} });
14742
+ return /* @__PURE__ */ (0, import_jsx_runtime92.jsx)(ValueShell, { kind: "email", glyph: MailGlyph, text: parsed.address, copy: parsed.address, state, record, peek, webSearch: `"${parsed.address}"`, ...about !== void 0 ? { about } : {} });
14711
14743
  }
14712
14744
  function phoneSearchText(parsed) {
14713
14745
  const na = parsed.e164?.match(/^\+1(\d{3})(\d{3})(\d{4})$/);
@@ -14715,7 +14747,6 @@ function phoneSearchText(parsed) {
14715
14747
  }
14716
14748
  function PhoneValue({ phone, owner, state = "ok", peek = true, defaultCallingCode = "1", about }) {
14717
14749
  const parsed = parsePhone(phone, defaultCallingCode);
14718
- const searchRow = useSearchRow();
14719
14750
  const ok = state === "ok" && parsed.valid;
14720
14751
  const record = {
14721
14752
  kind: "Phone number",
@@ -14730,14 +14761,13 @@ function PhoneValue({ phone, owner, state = "ok", peek = true, defaultCallingCod
14730
14761
  ...parsed.region ? [{ property: "Region", value: parsed.region }] : [],
14731
14762
  ...parsed.extension ? [{ property: "Extension", value: parsed.extension }] : [],
14732
14763
  actions([
14733
- ok && { text: "Send a text", glyph: MessageSquareGlyph, href: smsHref(parsed) },
14734
- searchRow(phoneSearchText(parsed))
14764
+ ok && { text: "Send a text", glyph: MessageSquareGlyph, href: smsHref(parsed) }
14735
14765
  ])
14736
14766
  ],
14737
14767
  ...ok ? { primary: { label: "Call", onSelect: () => window.location.assign(telHref(parsed)) } } : {},
14738
14768
  copyData: { phone: parsed.e164 ?? parsed.raw, display: parsed.display, ...parsed.region ? { region: parsed.region } : {}, ...owner ? { owner } : {} }
14739
14769
  };
14740
- return /* @__PURE__ */ (0, import_jsx_runtime92.jsx)(ValueShell, { kind: "phone number", glyph: PhoneGlyph, text: parsed.display, copy: parsed.e164 ?? parsed.raw, state, record, peek, ...about !== void 0 ? { about } : {} });
14770
+ return /* @__PURE__ */ (0, import_jsx_runtime92.jsx)(ValueShell, { kind: "phone number", glyph: PhoneGlyph, text: parsed.display, copy: parsed.e164 ?? parsed.raw, state, record, peek, webSearch: phoneSearchText(parsed), ...about !== void 0 ? { about } : {} });
14741
14771
  }
14742
14772
  var VALIDATION_TONE = { verified: "success", partial: "warning", unknown: "danger" };
14743
14773
  var VALIDATION_TEXT = { verified: "Verified address", partial: "Partly matched", unknown: "No match found" };
@@ -14745,7 +14775,6 @@ function AddressValue({ address, owner, state = "ok", peek = true, multiline = f
14745
14775
  const one = addressText(address);
14746
14776
  const lines = typeof address === "string" ? address.split(/\n+/).map((l) => l.trim()).filter(Boolean) : address.map((l) => (l ?? "").trim()).filter(Boolean);
14747
14777
  const { validateAddress } = useContactValuesHost();
14748
- const searchRow = useSearchRow();
14749
14778
  const [validation, setValidation] = React61.useState({ phase: "idle" });
14750
14779
  React61.useEffect(() => setValidation({ phase: "idle" }), [one]);
14751
14780
  const ok = state === "ok" && one.length > 0;
@@ -14780,8 +14809,7 @@ function AddressValue({ address, owner, state = "ok", peek = true, multiline = f
14780
14809
  ...owner && lines.length > 1 ? [{ property: "For", value: owner }] : [],
14781
14810
  ...validationBlock ? [validationBlock] : [],
14782
14811
  actions([
14783
- ok && validateAddress && validation.phase !== "done" && { text: "Open in maps", glyph: MapPinGlyph, href: mapsHref(one) },
14784
- searchRow(one)
14812
+ ok && validateAddress && validation.phase !== "done" && { text: "Open in maps", glyph: MapPinGlyph, href: mapsHref(one) }
14785
14813
  ])
14786
14814
  ],
14787
14815
  ...ok && validateAddress && validation.phase !== "done" ? { primary: { label: validation.phase === "checking" ? "Checking\u2026" : "Validate", onSelect: validate } } : ok ? { primary: { label: "Open in maps", onSelect: () => (0, import_outbound2.openOutbound)(mapsHref(validation.phase === "done" && validation.result.formatted ? validation.result.formatted : one)) } } : {},
@@ -14792,6 +14820,7 @@ function AddressValue({ address, owner, state = "ok", peek = true, multiline = f
14792
14820
  {
14793
14821
  kind: "address",
14794
14822
  glyph: MapPinGlyph,
14823
+ webSearch: one,
14795
14824
  text: multiline ? lines.join("\n") : one,
14796
14825
  copy: lines.join("\n"),
14797
14826
  state,
@@ -14802,7 +14831,7 @@ function AddressValue({ address, owner, state = "ok", peek = true, multiline = f
14802
14831
  }
14803
14832
  );
14804
14833
  }
14805
- function socialRecord(parsed, props, glyph, searchRow) {
14834
+ function socialRecord(parsed, props, glyph) {
14806
14835
  const state = props.state ?? "ok";
14807
14836
  const ok = state === "ok" && Boolean(parsed.href);
14808
14837
  return {
@@ -14817,9 +14846,7 @@ function socialRecord(parsed, props, glyph, searchRow) {
14817
14846
  ...parsed.handle ? [{ property: "Handle", value: parsed.display }] : [],
14818
14847
  ...props.followers != null ? [{ fact: `${compactCount(props.followers)} followers`, glyph: UsersIcon }] : [],
14819
14848
  ...props.owner ? [{ property: "For", value: props.owner }] : [],
14820
- actions([
14821
- searchRow(`${parsed.display} ${parsed.platformName}`)
14822
- ])
14849
+ actions([])
14823
14850
  ],
14824
14851
  ...ok ? { primary: { label: "Open profile", onSelect: () => (0, import_outbound2.openOutbound)(parsed.href) } } : {},
14825
14852
  copyData: { platform: parsed.platformName, handle: parsed.display, ...parsed.href ? { url: parsed.href } : {}, ...props.followers != null ? { followers: props.followers } : {} }
@@ -14828,7 +14855,6 @@ function socialRecord(parsed, props, glyph, searchRow) {
14828
14855
  function SocialHandleValue(props) {
14829
14856
  const { value, platform, state = "ok", peek = true } = props;
14830
14857
  const parsed = parseSocial(value, platform);
14831
- const searchRow = useSearchRow();
14832
14858
  const glyph = parsed.platform === "other" ? AtSignGlyph : markFor(parsed.platform);
14833
14859
  return /* @__PURE__ */ (0, import_jsx_runtime92.jsx)(
14834
14860
  ValueShell,
@@ -14838,7 +14864,8 @@ function SocialHandleValue(props) {
14838
14864
  text: parsed.display,
14839
14865
  copy: parsed.handle ? parsed.display : parsed.href ?? parsed.display,
14840
14866
  state,
14841
- record: socialRecord(parsed, props, glyph, searchRow),
14867
+ record: socialRecord(parsed, props, glyph),
14868
+ webSearch: `${parsed.display} ${parsed.platformName}`,
14842
14869
  peek,
14843
14870
  ...props.about !== void 0 ? { about: props.about } : {}
14844
14871
  }
@@ -14846,7 +14873,6 @@ function SocialHandleValue(props) {
14846
14873
  }
14847
14874
  function UrlValue({ url, title, owner, state = "ok", peek = true, icon = true, about }) {
14848
14875
  const parsed = parseUrl(url);
14849
- const searchRow = useSearchRow();
14850
14876
  const ok = state === "ok" && Boolean(parsed.href);
14851
14877
  const record = {
14852
14878
  kind: "Web address",
@@ -14858,14 +14884,12 @@ function UrlValue({ url, title, owner, state = "ok", peek = true, icon = true, a
14858
14884
  body: [
14859
14885
  { property: "Domain", value: parsed.domain },
14860
14886
  ...owner && title ? [{ property: "For", value: owner }] : [],
14861
- actions([
14862
- searchRow(parsed.domain)
14863
- ])
14887
+ actions([])
14864
14888
  ],
14865
14889
  ...ok ? { primary: { label: "Open", onSelect: () => (0, import_outbound2.openOutbound)(parsed.href) } } : {},
14866
14890
  copyData: { url: parsed.href ?? url, domain: parsed.domain, ...title ? { title } : {} }
14867
14891
  };
14868
- return /* @__PURE__ */ (0, import_jsx_runtime92.jsx)(ValueShell, { kind: "link", ...icon ? { glyph: GlobeIcon } : {}, text: parsed.display, copy: parsed.href ?? url, state, record, peek, ...about !== void 0 ? { about } : {} });
14892
+ return /* @__PURE__ */ (0, import_jsx_runtime92.jsx)(ValueShell, { kind: "link", ...icon ? { glyph: GlobeIcon } : {}, text: parsed.display, copy: parsed.href ?? url, state, record, peek, webSearch: parsed.domain, ...about !== void 0 ? { about } : {} });
14869
14893
  }
14870
14894
  function ContactValue({ type, value, platform, followers, title, icon, ...common }) {
14871
14895
  switch (type) {