@ai-matrx/design-system 0.86.364 → 0.86.366
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/CHANGELOG.md +14 -1
- package/dist/carousel.js +3 -3
- package/dist/{chunk-RO5CRIOL.js → chunk-3JEAXZKX.js} +2 -2
- package/dist/{chunk-HS6GMHKZ.js → chunk-CZGTZJPS.js} +3 -3
- package/dist/chunk-CZGTZJPS.js.map +1 -0
- package/dist/{chunk-5Z5GTXKL.js → chunk-FEITX4L3.js} +2 -2
- package/dist/{chunk-GUGBVQ4T.js → chunk-OAK4ENIP.js} +3 -3
- package/dist/{chunk-UGUVTE77.js → chunk-QEQDJBNK.js} +2 -2
- package/dist/{chunk-QJ6SQNXD.js → chunk-TBWKBTPM.js} +2 -2
- package/dist/{chunk-2QFA6CK4.js → chunk-UAIBCPMB.js} +2 -2
- package/dist/{chunk-VOLSYNJY.js → chunk-VG765KBC.js} +2 -2
- package/dist/controls.cjs +2 -2
- package/dist/controls.cjs.map +1 -1
- package/dist/controls.js +3 -3
- package/dist/data-table/data-row-inspector.cjs +2 -2
- package/dist/data-table/data-row-inspector.cjs.map +1 -1
- package/dist/data-table/data-row-inspector.js +3 -3
- package/dist/data-table/data-row-window.cjs +2 -2
- package/dist/data-table/data-row-window.cjs.map +1 -1
- package/dist/data-table/data-row-window.js +4 -4
- package/dist/data-table/drill-chart.cjs +2 -2
- package/dist/data-table/drill-chart.cjs.map +1 -1
- package/dist/data-table/drill-chart.js +2 -2
- package/dist/data-table/index.cjs +2 -2
- package/dist/data-table/index.cjs.map +1 -1
- package/dist/data-table/index.js +5 -5
- package/dist/data-table/uuid-cell.cjs +2 -2
- package/dist/data-table/uuid-cell.cjs.map +1 -1
- package/dist/data-table/uuid-cell.js +2 -2
- package/dist/desktop.cjs +2 -2
- package/dist/desktop.cjs.map +1 -1
- package/dist/desktop.js +3 -3
- package/dist/email-input-dialog.cjs +2 -2
- package/dist/email-input-dialog.cjs.map +1 -1
- package/dist/email-input-dialog.js +2 -2
- package/dist/error-sentence.cjs +2 -2
- package/dist/error-sentence.cjs.map +1 -1
- package/dist/error-sentence.js +1 -1
- package/dist/index.cjs +54 -12
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +7 -2
- package/dist/index.d.ts +7 -2
- package/dist/index.js +58 -16
- package/dist/index.js.map +1 -1
- package/dist/lite-table.cjs +2 -2
- package/dist/lite-table.cjs.map +1 -1
- package/dist/lite-table.js +3 -3
- package/dist/record-list.cjs +2 -2
- package/dist/record-list.cjs.map +1 -1
- package/dist/record-list.js +3 -3
- package/dist/swipe-deck.cjs +14 -5
- package/dist/swipe-deck.cjs.map +1 -1
- package/dist/swipe-deck.css +6 -0
- package/dist/swipe-deck.d.cts +11 -0
- package/dist/swipe-deck.d.ts +11 -0
- package/dist/swipe-deck.js +14 -5
- package/dist/swipe-deck.js.map +1 -1
- package/dist/text-input-dialog.cjs +2 -2
- package/dist/text-input-dialog.cjs.map +1 -1
- package/dist/text-input-dialog.js +2 -2
- package/package.json +2 -2
- package/dist/chunk-HS6GMHKZ.js.map +0 -1
- /package/dist/{chunk-RO5CRIOL.js.map → chunk-3JEAXZKX.js.map} +0 -0
- /package/dist/{chunk-5Z5GTXKL.js.map → chunk-FEITX4L3.js.map} +0 -0
- /package/dist/{chunk-GUGBVQ4T.js.map → chunk-OAK4ENIP.js.map} +0 -0
- /package/dist/{chunk-UGUVTE77.js.map → chunk-QEQDJBNK.js.map} +0 -0
- /package/dist/{chunk-QJ6SQNXD.js.map → chunk-TBWKBTPM.js.map} +0 -0
- /package/dist/{chunk-2QFA6CK4.js.map → chunk-UAIBCPMB.js.map} +0 -0
- /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-
|
|
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-
|
|
24
|
+
import "./chunk-CZGTZJPS.js";
|
|
25
25
|
import "./chunk-WFITMVDB.js";
|
|
26
26
|
import "./chunk-WAT2XW7L.js";
|
|
27
27
|
import {
|
package/dist/error-sentence.cjs
CHANGED
|
@@ -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":"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","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":[]}
|
package/dist/error-sentence.js
CHANGED
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
|
});
|
|
@@ -13314,6 +13314,20 @@ function RowLink({ href, children }) {
|
|
|
13314
13314
|
}
|
|
13315
13315
|
return /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("a", { href, className, onClick: stop, children });
|
|
13316
13316
|
}
|
|
13317
|
+
function RowAction({ onSelect, children }) {
|
|
13318
|
+
return /* @__PURE__ */ (0, import_jsx_runtime89.jsx)(
|
|
13319
|
+
"button",
|
|
13320
|
+
{
|
|
13321
|
+
type: "button",
|
|
13322
|
+
className: "max-w-full truncate text-left text-primary underline-offset-2 hover:underline",
|
|
13323
|
+
onClick: (event) => {
|
|
13324
|
+
event.stopPropagation();
|
|
13325
|
+
onSelect();
|
|
13326
|
+
},
|
|
13327
|
+
children
|
|
13328
|
+
}
|
|
13329
|
+
);
|
|
13330
|
+
}
|
|
13317
13331
|
function PeekCardRows({ rows, numbered = false, limit }) {
|
|
13318
13332
|
const shown = limit && rows.length > limit ? rows.slice(0, limit) : rows;
|
|
13319
13333
|
const rest = rows.length - shown.length;
|
|
@@ -13327,7 +13341,7 @@ function PeekCardRows({ rows, numbered = false, limit }) {
|
|
|
13327
13341
|
row.tone ? /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("span", { "aria-hidden": true, className: cn("mt-[7px] size-1.5 shrink-0 rounded-full", TONE_FILL[row.tone]) }) : null,
|
|
13328
13342
|
row.glyph ? /* @__PURE__ */ (0, import_jsx_runtime89.jsx)(row.glyph, { className: cn("mt-0.5 size-3.5 shrink-0 text-muted-foreground", lead) }) : null,
|
|
13329
13343
|
/* @__PURE__ */ (0, import_jsx_runtime89.jsxs)("div", { className: "flex min-w-0 flex-1 flex-col", children: [
|
|
13330
|
-
/* @__PURE__ */ (0, import_jsx_runtime89.jsx)("span", { className: "type-secondary min-w-0 truncate text-foreground", title: row.title, children: row.href ? /* @__PURE__ */ (0, import_jsx_runtime89.jsx)(RowLink, { href: row.href, children: row.text }) : row.text }),
|
|
13344
|
+
/* @__PURE__ */ (0, import_jsx_runtime89.jsx)("span", { className: "type-secondary min-w-0 truncate text-foreground", title: row.title, children: row.onSelect ? /* @__PURE__ */ (0, import_jsx_runtime89.jsx)(RowAction, { onSelect: row.onSelect, children: row.text }) : row.href ? /* @__PURE__ */ (0, import_jsx_runtime89.jsx)(RowLink, { href: row.href, children: row.text }) : row.text }),
|
|
13331
13345
|
row.detail ? /* @__PURE__ */ (0, import_jsx_runtime89.jsx)("span", { className: "type-meta break-words text-muted-foreground", children: row.detail }) : null
|
|
13332
13346
|
] }),
|
|
13333
13347
|
row.status ? /* @__PURE__ */ (0, import_jsx_runtime89.jsx)(
|
|
@@ -14059,6 +14073,7 @@ function Block({ block }) {
|
|
|
14059
14073
|
glyph: row.glyph,
|
|
14060
14074
|
tone: row.tone,
|
|
14061
14075
|
href: row.entity ? void 0 : row.href,
|
|
14076
|
+
onSelect: row.entity ? void 0 : row.onSelect,
|
|
14062
14077
|
status: row.status,
|
|
14063
14078
|
doors: row.doors
|
|
14064
14079
|
}))
|
|
@@ -14516,12 +14531,16 @@ function compactCount(n) {
|
|
|
14516
14531
|
var import_jsx_runtime92 = require("react/jsx-runtime");
|
|
14517
14532
|
var HostContext2 = React61.createContext({});
|
|
14518
14533
|
function ContactValuesHostProvider({ children, ...host }) {
|
|
14519
|
-
const value = React61.useMemo(() => host, [host.validateAddress]);
|
|
14534
|
+
const value = React61.useMemo(() => host, [host.validateAddress, host.searchWeb]);
|
|
14520
14535
|
return /* @__PURE__ */ (0, import_jsx_runtime92.jsx)(HostContext2.Provider, { value, children });
|
|
14521
14536
|
}
|
|
14522
14537
|
function useContactValuesHost() {
|
|
14523
14538
|
return React61.useContext(HostContext2);
|
|
14524
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) };
|
|
14543
|
+
}
|
|
14525
14544
|
var markCache = /* @__PURE__ */ new Map();
|
|
14526
14545
|
function markFor(platform) {
|
|
14527
14546
|
let glyph = markCache.get(platform);
|
|
@@ -14589,9 +14608,23 @@ function usePinnedHover() {
|
|
|
14589
14608
|
}, [pinned]);
|
|
14590
14609
|
return { open: hovered || held || pinned, setHovered, setHeld, setPinned, trigger };
|
|
14591
14610
|
}
|
|
14611
|
+
function closingOnSelect(record, close) {
|
|
14612
|
+
if (!record.body?.length) return record;
|
|
14613
|
+
const body = record.body.map(
|
|
14614
|
+
(block) => typeof block === "object" && block !== null && "rows" in block && Array.isArray(block.rows) ? { ...block, rows: block.rows.map((row) => row.onSelect ? { ...row, onSelect: () => {
|
|
14615
|
+
close();
|
|
14616
|
+
row.onSelect();
|
|
14617
|
+
} } : row) } : block
|
|
14618
|
+
);
|
|
14619
|
+
return { ...record, body };
|
|
14620
|
+
}
|
|
14592
14621
|
function ValueShell({ kind, glyph: Glyph, text, copy, state, record: own, peek, wrap, about }) {
|
|
14593
|
-
const record = withAbout(own, about);
|
|
14594
14622
|
const { open, setHovered, setHeld, setPinned, trigger } = usePinnedHover();
|
|
14623
|
+
const record = closingOnSelect(withAbout(own, about), () => {
|
|
14624
|
+
setPinned(false);
|
|
14625
|
+
setHeld(false);
|
|
14626
|
+
setHovered(false);
|
|
14627
|
+
});
|
|
14595
14628
|
const off = state !== "ok";
|
|
14596
14629
|
const value = /* @__PURE__ */ (0, import_jsx_runtime92.jsx)("span", { className: cn("min-w-0", wrap ? "whitespace-pre-line break-words" : "truncate", off ? "text-muted-foreground line-through" : "text-foreground"), children: text });
|
|
14597
14630
|
const status = off ? /* @__PURE__ */ (0, import_jsx_runtime92.jsx)("span", { className: "shrink-0 text-muted-foreground no-underline", children: `\xB7 ${CONTACT_STATE_LABEL[state]}` }) : null;
|
|
@@ -14654,6 +14687,7 @@ var actions = (rows) => ({
|
|
|
14654
14687
|
});
|
|
14655
14688
|
function EmailValue({ email, owner, state = "ok", peek = true, about }) {
|
|
14656
14689
|
const parsed = parseEmail(email);
|
|
14690
|
+
const searchRow = useSearchRow();
|
|
14657
14691
|
const ok = state === "ok" && parsed.valid;
|
|
14658
14692
|
const site = parsed.domain ? parseUrl(parsed.domain) : null;
|
|
14659
14693
|
const record = {
|
|
@@ -14667,7 +14701,7 @@ function EmailValue({ email, owner, state = "ok", peek = true, about }) {
|
|
|
14667
14701
|
...!parsed.valid && state === "ok" ? [{ fact: "Not a complete email address", glyph: LinkOffGlyph, muted: true }] : [],
|
|
14668
14702
|
...parsed.domain ? [{ property: "Domain", value: parsed.domain, ...ok && site?.href ? { href: site.href } : {} }] : [],
|
|
14669
14703
|
actions([
|
|
14670
|
-
|
|
14704
|
+
searchRow(`"${parsed.address}"`)
|
|
14671
14705
|
])
|
|
14672
14706
|
],
|
|
14673
14707
|
...ok ? { primary: { label: "Send email", onSelect: () => window.location.assign(mailtoHref(parsed.address)) } } : {},
|
|
@@ -14675,8 +14709,13 @@ function EmailValue({ email, owner, state = "ok", peek = true, about }) {
|
|
|
14675
14709
|
};
|
|
14676
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 } : {} });
|
|
14677
14711
|
}
|
|
14712
|
+
function phoneSearchText(parsed) {
|
|
14713
|
+
const na = parsed.e164?.match(/^\+1(\d{3})(\d{3})(\d{4})$/);
|
|
14714
|
+
return na ? `${na[1]}-${na[2]}-${na[3]}` : parsed.display;
|
|
14715
|
+
}
|
|
14678
14716
|
function PhoneValue({ phone, owner, state = "ok", peek = true, defaultCallingCode = "1", about }) {
|
|
14679
14717
|
const parsed = parsePhone(phone, defaultCallingCode);
|
|
14718
|
+
const searchRow = useSearchRow();
|
|
14680
14719
|
const ok = state === "ok" && parsed.valid;
|
|
14681
14720
|
const record = {
|
|
14682
14721
|
kind: "Phone number",
|
|
@@ -14692,7 +14731,7 @@ function PhoneValue({ phone, owner, state = "ok", peek = true, defaultCallingCod
|
|
|
14692
14731
|
...parsed.extension ? [{ property: "Extension", value: parsed.extension }] : [],
|
|
14693
14732
|
actions([
|
|
14694
14733
|
ok && { text: "Send a text", glyph: MessageSquareGlyph, href: smsHref(parsed) },
|
|
14695
|
-
|
|
14734
|
+
searchRow(phoneSearchText(parsed))
|
|
14696
14735
|
])
|
|
14697
14736
|
],
|
|
14698
14737
|
...ok ? { primary: { label: "Call", onSelect: () => window.location.assign(telHref(parsed)) } } : {},
|
|
@@ -14706,6 +14745,7 @@ function AddressValue({ address, owner, state = "ok", peek = true, multiline = f
|
|
|
14706
14745
|
const one = addressText(address);
|
|
14707
14746
|
const lines = typeof address === "string" ? address.split(/\n+/).map((l) => l.trim()).filter(Boolean) : address.map((l) => (l ?? "").trim()).filter(Boolean);
|
|
14708
14747
|
const { validateAddress } = useContactValuesHost();
|
|
14748
|
+
const searchRow = useSearchRow();
|
|
14709
14749
|
const [validation, setValidation] = React61.useState({ phase: "idle" });
|
|
14710
14750
|
React61.useEffect(() => setValidation({ phase: "idle" }), [one]);
|
|
14711
14751
|
const ok = state === "ok" && one.length > 0;
|
|
@@ -14741,7 +14781,7 @@ function AddressValue({ address, owner, state = "ok", peek = true, multiline = f
|
|
|
14741
14781
|
...validationBlock ? [validationBlock] : [],
|
|
14742
14782
|
actions([
|
|
14743
14783
|
ok && validateAddress && validation.phase !== "done" && { text: "Open in maps", glyph: MapPinGlyph, href: mapsHref(one) },
|
|
14744
|
-
|
|
14784
|
+
searchRow(one)
|
|
14745
14785
|
])
|
|
14746
14786
|
],
|
|
14747
14787
|
...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)) } } : {},
|
|
@@ -14762,7 +14802,7 @@ function AddressValue({ address, owner, state = "ok", peek = true, multiline = f
|
|
|
14762
14802
|
}
|
|
14763
14803
|
);
|
|
14764
14804
|
}
|
|
14765
|
-
function socialRecord(parsed, props, glyph) {
|
|
14805
|
+
function socialRecord(parsed, props, glyph, searchRow) {
|
|
14766
14806
|
const state = props.state ?? "ok";
|
|
14767
14807
|
const ok = state === "ok" && Boolean(parsed.href);
|
|
14768
14808
|
return {
|
|
@@ -14778,7 +14818,7 @@ function socialRecord(parsed, props, glyph) {
|
|
|
14778
14818
|
...props.followers != null ? [{ fact: `${compactCount(props.followers)} followers`, glyph: UsersIcon }] : [],
|
|
14779
14819
|
...props.owner ? [{ property: "For", value: props.owner }] : [],
|
|
14780
14820
|
actions([
|
|
14781
|
-
|
|
14821
|
+
searchRow(`${parsed.display} ${parsed.platformName}`)
|
|
14782
14822
|
])
|
|
14783
14823
|
],
|
|
14784
14824
|
...ok ? { primary: { label: "Open profile", onSelect: () => (0, import_outbound2.openOutbound)(parsed.href) } } : {},
|
|
@@ -14788,6 +14828,7 @@ function socialRecord(parsed, props, glyph) {
|
|
|
14788
14828
|
function SocialHandleValue(props) {
|
|
14789
14829
|
const { value, platform, state = "ok", peek = true } = props;
|
|
14790
14830
|
const parsed = parseSocial(value, platform);
|
|
14831
|
+
const searchRow = useSearchRow();
|
|
14791
14832
|
const glyph = parsed.platform === "other" ? AtSignGlyph : markFor(parsed.platform);
|
|
14792
14833
|
return /* @__PURE__ */ (0, import_jsx_runtime92.jsx)(
|
|
14793
14834
|
ValueShell,
|
|
@@ -14797,7 +14838,7 @@ function SocialHandleValue(props) {
|
|
|
14797
14838
|
text: parsed.display,
|
|
14798
14839
|
copy: parsed.handle ? parsed.display : parsed.href ?? parsed.display,
|
|
14799
14840
|
state,
|
|
14800
|
-
record: socialRecord(parsed, props, glyph),
|
|
14841
|
+
record: socialRecord(parsed, props, glyph, searchRow),
|
|
14801
14842
|
peek,
|
|
14802
14843
|
...props.about !== void 0 ? { about: props.about } : {}
|
|
14803
14844
|
}
|
|
@@ -14805,6 +14846,7 @@ function SocialHandleValue(props) {
|
|
|
14805
14846
|
}
|
|
14806
14847
|
function UrlValue({ url, title, owner, state = "ok", peek = true, icon = true, about }) {
|
|
14807
14848
|
const parsed = parseUrl(url);
|
|
14849
|
+
const searchRow = useSearchRow();
|
|
14808
14850
|
const ok = state === "ok" && Boolean(parsed.href);
|
|
14809
14851
|
const record = {
|
|
14810
14852
|
kind: "Web address",
|
|
@@ -14817,7 +14859,7 @@ function UrlValue({ url, title, owner, state = "ok", peek = true, icon = true, a
|
|
|
14817
14859
|
{ property: "Domain", value: parsed.domain },
|
|
14818
14860
|
...owner && title ? [{ property: "For", value: owner }] : [],
|
|
14819
14861
|
actions([
|
|
14820
|
-
|
|
14862
|
+
searchRow(parsed.domain)
|
|
14821
14863
|
])
|
|
14822
14864
|
],
|
|
14823
14865
|
...ok ? { primary: { label: "Open", onSelect: () => (0, import_outbound2.openOutbound)(parsed.href) } } : {},
|