efficient-shell 4.134.0 → 4.137.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +81 -7
- package/dist/{Browser-O3QZGUF2.js → Browser-ZNX4WFUH.js} +11 -11
- package/dist/{Browser-O3QZGUF2.js.map → Browser-ZNX4WFUH.js.map} +1 -1
- package/dist/{Calculator-L6N5X3KU.js → Calculator-6FGNKOXU.js} +10 -10
- package/dist/{Calculator-L6N5X3KU.js.map → Calculator-6FGNKOXU.js.map} +1 -1
- package/dist/ConfirmDialog-NPQMIGUR.js +4 -0
- package/dist/{ConfirmDialog-LYSSZSUD.js.map → ConfirmDialog-NPQMIGUR.js.map} +1 -1
- package/dist/{CurrencyConverter-64MKXB3D.js → CurrencyConverter-FF7EXRYL.js} +10 -10
- package/dist/{CurrencyConverter-64MKXB3D.js.map → CurrencyConverter-FF7EXRYL.js.map} +1 -1
- package/dist/{Documents-5WXXYCLI.js → Documents-H3R7XSBH.js} +12 -12
- package/dist/{Documents-5WXXYCLI.js.map → Documents-H3R7XSBH.js.map} +1 -1
- package/dist/{Files-AUURUUDN.js → Files-ZHJIAUC2.js} +15 -15
- package/dist/{Files-AUURUUDN.js.map → Files-ZHJIAUC2.js.map} +1 -1
- package/dist/{Notepad-GPXJVPB7.js → Notepad-VE7ISWRQ.js} +13 -13
- package/dist/{Notepad-GPXJVPB7.js.map → Notepad-VE7ISWRQ.js.map} +1 -1
- package/dist/PdfViewer-SQBFYAGW.js +5 -0
- package/dist/{PdfViewer-HKO6P4SR.js.map → PdfViewer-SQBFYAGW.js.map} +1 -1
- package/dist/{PomodoroTimer-4TQBWLP2.js → PomodoroTimer-IR3WREED.js} +12 -12
- package/dist/{PomodoroTimer-4TQBWLP2.js.map → PomodoroTimer-IR3WREED.js.map} +1 -1
- package/dist/{Preview-FOZYPKM2.js → Preview-DAQGRNRM.js} +14 -14
- package/dist/{Preview-FOZYPKM2.js.map → Preview-DAQGRNRM.js.map} +1 -1
- package/dist/{Sidebar-BPU7RCZP.js → Sidebar-YW6H4NDJ.js} +3 -3
- package/dist/{Sidebar-BPU7RCZP.js.map → Sidebar-YW6H4NDJ.js.map} +1 -1
- package/dist/{Spreadsheet-3C66BBBF.js → Spreadsheet-HOCPHJOC.js} +12 -12
- package/dist/{Spreadsheet-3C66BBBF.js.map → Spreadsheet-HOCPHJOC.js.map} +1 -1
- package/dist/{Stock-IF4IHYLU.js → Stock-LVRQPURG.js} +10 -10
- package/dist/{Stock-IF4IHYLU.js.map → Stock-LVRQPURG.js.map} +1 -1
- package/dist/{Weather-725PFR7T.js → Weather-LZQGVDJL.js} +10 -10
- package/dist/{Weather-725PFR7T.js.map → Weather-LZQGVDJL.js.map} +1 -1
- package/dist/{WorldClock-UU4NZIQ7.js → WorldClock-XPD7WOZT.js} +10 -10
- package/dist/{WorldClock-UU4NZIQ7.js.map → WorldClock-XPD7WOZT.js.map} +1 -1
- package/dist/apps/index.js +23 -23
- package/dist/brand.css +1 -1
- package/dist/{chunk-GIGV2ZRW.js → chunk-5RPTS3BT.js} +3 -3
- package/dist/{chunk-GIGV2ZRW.js.map → chunk-5RPTS3BT.js.map} +1 -1
- package/dist/{chunk-D276EMXS.js → chunk-6XJEJWNJ.js} +7 -3
- package/dist/chunk-6XJEJWNJ.js.map +1 -0
- package/dist/{chunk-IULP5BCD.js → chunk-COWYSHG2.js} +4 -4
- package/dist/{chunk-IULP5BCD.js.map → chunk-COWYSHG2.js.map} +1 -1
- package/dist/{chunk-R4OQIQYX.js → chunk-E7TB6WD2.js} +4 -4
- package/dist/{chunk-R4OQIQYX.js.map → chunk-E7TB6WD2.js.map} +1 -1
- package/dist/{chunk-X4Q6G253.js → chunk-FIHOGVUP.js} +3 -3
- package/dist/{chunk-X4Q6G253.js.map → chunk-FIHOGVUP.js.map} +1 -1
- package/dist/{chunk-2TPTHAKI.js → chunk-HUBJAUGG.js} +3 -3
- package/dist/{chunk-2TPTHAKI.js.map → chunk-HUBJAUGG.js.map} +1 -1
- package/dist/{chunk-W622KQTD.js → chunk-I2TAAJHS.js} +3 -3
- package/dist/{chunk-W622KQTD.js.map → chunk-I2TAAJHS.js.map} +1 -1
- package/dist/{chunk-Q3LT745N.js → chunk-ICTRCKUE.js} +7 -7
- package/dist/{chunk-Q3LT745N.js.map → chunk-ICTRCKUE.js.map} +1 -1
- package/dist/{chunk-QRL64J5F.js → chunk-JOPU6WPY.js} +7 -6
- package/dist/chunk-JOPU6WPY.js.map +1 -0
- package/dist/{chunk-PIGDNN5F.js → chunk-PVPPAWVM.js} +3 -3
- package/dist/{chunk-PIGDNN5F.js.map → chunk-PVPPAWVM.js.map} +1 -1
- package/dist/{chunk-ET6ID4LP.js → chunk-R7QGMK6N.js} +3 -3
- package/dist/{chunk-ET6ID4LP.js.map → chunk-R7QGMK6N.js.map} +1 -1
- package/dist/{chunk-4P44JXDS.js → chunk-UTYKLGGT.js} +3 -3
- package/dist/{chunk-4P44JXDS.js.map → chunk-UTYKLGGT.js.map} +1 -1
- package/dist/{chunk-T4VQHMG4.js → chunk-VNJJCH5A.js} +3 -3
- package/dist/{chunk-T4VQHMG4.js.map → chunk-VNJJCH5A.js.map} +1 -1
- package/dist/{chunk-QSKCQUZE.js → chunk-XJHZWSKV.js} +3 -3
- package/dist/{chunk-QSKCQUZE.js.map → chunk-XJHZWSKV.js.map} +1 -1
- package/dist/{chunk-SHQM5CK3.js → chunk-Y3GYJ7YR.js} +4 -4
- package/dist/{chunk-SHQM5CK3.js.map → chunk-Y3GYJ7YR.js.map} +1 -1
- package/dist/{chunk-OLJDJYSU.js → chunk-YA4EE7ST.js} +574 -145
- package/dist/chunk-YA4EE7ST.js.map +1 -0
- package/dist/{chunk-QAGQRNKI.js → chunk-YDHXWCCJ.js} +3 -3
- package/dist/{chunk-QAGQRNKI.js.map → chunk-YDHXWCCJ.js.map} +1 -1
- package/dist/{chunk-72CQWN7O.js → chunk-YE6GUDGP.js} +3 -2
- package/dist/chunk-YE6GUDGP.js.map +1 -0
- package/dist/chunk-ZS7PMGUW.js +7 -0
- package/dist/{chunk-Q2MJVSJT.js.map → chunk-ZS7PMGUW.js.map} +1 -1
- package/dist/file-intake/index.js +2 -2
- package/dist/{index-DZ7E7bCl.d.ts → index-DVI9DMSu.d.ts} +189 -18
- package/dist/index.d.ts +2 -2
- package/dist/index.js +31 -31
- package/dist/page-tabs/index.js +5 -5
- package/dist/ui/index.d.ts +1 -1
- package/dist/ui/index.js +13 -13
- package/dist/ui.css +78 -10
- package/package.json +1 -1
- package/dist/ConfirmDialog-LYSSZSUD.js +0 -4
- package/dist/PdfViewer-HKO6P4SR.js +0 -5
- package/dist/chunk-72CQWN7O.js.map +0 -1
- package/dist/chunk-D276EMXS.js.map +0 -1
- package/dist/chunk-OLJDJYSU.js.map +0 -1
- package/dist/chunk-Q2MJVSJT.js +0 -7
- package/dist/chunk-QRL64J5F.js.map +0 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { DEFAULT_SHELL_STRINGS, useShellStrings } from './chunk-
|
|
1
|
+
import { DEFAULT_SHELL_STRINGS, useShellStrings } from './chunk-YE6GUDGP.js';
|
|
2
2
|
import { useRef, useState, useCallback } from 'react';
|
|
3
3
|
import { jsx } from 'react/jsx-runtime';
|
|
4
4
|
|
|
@@ -141,5 +141,5 @@ function FileIntakeAlert({ rejections, className = "mt-2" }) {
|
|
|
141
141
|
}
|
|
142
142
|
|
|
143
143
|
export { FileIntakeAlert, acceptsFile, humanSize, useFileIntake };
|
|
144
|
-
//# sourceMappingURL=chunk-
|
|
145
|
-
//# sourceMappingURL=chunk-
|
|
144
|
+
//# sourceMappingURL=chunk-YDHXWCCJ.js.map
|
|
145
|
+
//# sourceMappingURL=chunk-YDHXWCCJ.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/forms/useFileIntake.tsx"],"names":[],"mappings":"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","file":"chunk-QAGQRNKI.js","sourcesContent":["/**\n * useFileIntake — the one way a file gets INTO a kit primitive.\n *\n * Every upload surface in the kit (`FilePicker`, `MediaUploadField`,\n * `MediaUploadGrid`, `BrandAssetEditor`, `BulkImportGrid`) takes files through\n * this hook, so the three gestures — the native file dialog, a drop onto the\n * zone, a paste into a composer — share ONE intake path and ONE set of checks.\n *\n * Before this each primitive owned its own hidden `<input type=file>`, its own\n * drag-over state and its own idea of what to check: `accept` reached the\n * native dialog only, so a file dropped onto the zone bypassed it entirely;\n * a multi-file drop onto a gallery kept the first file and lost the rest\n * without a word; and a rejected file was listed in plain red text that no\n * screen reader announced. The portals then copied the hidden-input block\n * nineteen more times. This hook is the fix at the narrowest layer that can\n * hold it (harness UI-15 / PAT-10).\n *\n * The hook validates and hands back `File[]`. It never uploads — transport\n * belongs to the consumer, for the reasons `FilePicker`'s header gives.\n *\n * Its rejection sentences and size units are the catalog's `files` section, so\n * a translated app says why a file was refused in the reader's language. The\n * catalog module imports nothing but React, which keeps this entry React-only.\n */\nimport {\n useCallback, useRef, useState,\n type ChangeEvent, type ClipboardEvent, type DragEvent, type ReactNode,\n} from 'react';\nimport { DEFAULT_SHELL_STRINGS, useShellStrings, type ShellStrings } from '../shell/strings';\n\nexport type FileRejectionReason = 'type' | 'size' | 'count';\n\nexport interface FileRejection {\n file: File;\n reason: FileRejectionReason;\n /** Human sentence naming the file and the rule it broke. */\n message: string;\n}\n\nexport interface FileIntakeLimits {\n /**\n * Native `accept` string — `image/*`, `.pdf,application/pdf`, … Enforced on\n * EVERY gesture, not only the dialog: a dropped or pasted file that fails it\n * is rejected with a reason. Empty or `*` accepts anything.\n */\n accept?: string;\n /** Rejected above this many bytes, with the reason shown. */\n maxSizeBytes?: number;\n /** Rejected once this many files are held in total (see `currentCount`). */\n maxFiles?: number;\n}\n\nexport interface FileIntakeOptions extends FileIntakeLimits {\n /** Receives the files that passed every check. Never called with an empty list. */\n onAccept: (files: File[]) => void;\n /** `false` takes the first candidate only — a single slot. Default `true`. */\n multiple?: boolean;\n /** Files the surface already holds, so `maxFiles` counts the total. Default 0. */\n currentCount?: number;\n /** Short kind hint for the type-rejection sentence, e.g. \"PNG · JPG\". */\n acceptHint?: ReactNode;\n disabled?: boolean;\n}\n\n/**\n * Does `file` satisfy a native `accept` string? Extension rules match the\n * name, `type/*` rules match the MIME prefix, anything else is an exact MIME.\n * A browser reports several media types for one `.ico` file and sometimes\n * none at all, which is why an extension rule exists at all.\n */\nexport function acceptsFile(file: File, accept?: string): boolean {\n const rules = (accept ?? '').split(',').map(rule => rule.trim().toLocaleLowerCase()).filter(Boolean);\n if (rules.length === 0 || rules.includes('*') || rules.includes('*/*')) return true;\n const fileName = file.name.toLocaleLowerCase();\n const fileType = file.type.toLocaleLowerCase();\n return rules.some(rule => {\n if (rule.startsWith('.')) return fileName.endsWith(rule);\n if (rule.endsWith('/*')) return fileType.startsWith(rule.slice(0, -1));\n return fileType === rule;\n });\n}\n\n/** `812 B`, `14 KB`, `6.2 MB` — the units, and their digits, from the catalog. */\nexport const humanSize = (bytes: number, strings: ShellStrings['files'] = DEFAULT_SHELL_STRINGS.files): string => {\n if (bytes < 1024) return strings.bytes(bytes);\n if (bytes < 1024 * 1024) return strings.kilobytes(Math.round(bytes / 1024));\n return strings.megabytes(bytes / (1024 * 1024));\n};\n\n/** Is this drag carrying files (as opposed to text, a URL, or an in-page reorder)? */\nexport const isFileDrag = (e: DragEvent): boolean =>\n Array.from(e.dataTransfer?.types ?? []).includes('Files');\n\n/** Files on a clipboard event, if the paste carried any. */\nexport function pastedFiles(e: ClipboardEvent): File[] {\n const data = e.clipboardData;\n if (!data) return [];\n if (data.files && data.files.length > 0) return Array.from(data.files);\n const out: File[] = [];\n for (const item of Array.from(data.items ?? [])) {\n if (item.kind === 'file') {\n const file = item.getAsFile();\n if (file) out.push(file);\n }\n }\n return out;\n}\n\nexport function useFileIntake({\n onAccept, accept, maxSizeBytes, maxFiles, multiple = true, currentCount = 0,\n acceptHint, disabled = false,\n}: FileIntakeOptions) {\n const strings = useShellStrings().files;\n const inputRef = useRef<HTMLInputElement>(null);\n const [dragOver, setDragOver] = useState(false);\n const [rejections, setRejections] = useState<FileRejection[]>([]);\n // A drag passes over every child of the zone, firing leave/enter pairs; a\n // depth counter is what keeps the highlight steady across them.\n const depthRef = useRef(0);\n\n const hintText = typeof acceptHint === 'string' ? acceptHint : '';\n\n /** Run every candidate through the checks; deliver the survivors. */\n const take = useCallback((incoming: FileList | File[] | null | undefined) => {\n if (disabled || !incoming) return;\n const candidates = Array.from(incoming);\n if (candidates.length === 0) return;\n const accepted: File[] = [];\n const rejected: FileRejection[] = [];\n for (const file of multiple ? candidates : candidates.slice(0, 1)) {\n if (!acceptsFile(file, accept)) {\n rejected.push({\n file, reason: 'type',\n message: strings.notAccepted(file.name, hintText),\n });\n continue;\n }\n if (maxSizeBytes != null && file.size > maxSizeBytes) {\n rejected.push({\n file, reason: 'size',\n message: strings.tooLarge(file.name, humanSize(file.size, strings), humanSize(maxSizeBytes, strings)),\n });\n continue;\n }\n if (multiple && maxFiles != null && currentCount + accepted.length >= maxFiles) {\n rejected.push({\n file, reason: 'count',\n message: strings.tooMany(file.name, maxFiles),\n });\n continue;\n }\n accepted.push(file);\n }\n setRejections(rejected);\n if (accepted.length) onAccept(accepted);\n // Reset the native input so re-picking the SAME file fires change again —\n // without this, removing a file and re-adding it appears to do nothing.\n if (inputRef.current) inputRef.current.value = '';\n }, [disabled, multiple, accept, hintText, maxSizeBytes, maxFiles, currentCount, onAccept, strings]);\n\n const open = useCallback(() => {\n if (!disabled) inputRef.current?.click();\n }, [disabled]);\n\n const clearRejections = useCallback(() => setRejections([]), []);\n\n /** Spread onto the hidden native input. It is never a tab stop and never the visible control. */\n const inputProps = {\n ref: inputRef,\n type: 'file' as const,\n accept: accept || undefined,\n multiple,\n disabled,\n tabIndex: -1,\n 'aria-hidden': true as const,\n className: 'hidden',\n onChange: (e: ChangeEvent<HTMLInputElement>) => take(e.target.files),\n };\n\n /** Spread onto the drop target. Only a drag carrying files lights it up. */\n const zoneProps = disabled\n ? {}\n : {\n onDragEnter: (e: DragEvent) => {\n if (!isFileDrag(e)) return;\n e.preventDefault();\n depthRef.current += 1;\n setDragOver(true);\n },\n onDragOver: (e: DragEvent) => {\n if (!isFileDrag(e)) return;\n e.preventDefault();\n if (!dragOver) setDragOver(true);\n },\n onDragLeave: (e: DragEvent) => {\n if (!isFileDrag(e)) return;\n depthRef.current = Math.max(0, depthRef.current - 1);\n if (depthRef.current === 0) setDragOver(false);\n },\n onDrop: (e: DragEvent) => {\n if (!isFileDrag(e)) return;\n e.preventDefault();\n depthRef.current = 0;\n setDragOver(false);\n take(e.dataTransfer.files);\n },\n };\n\n /** Spread onto a composer's text area: a paste that carries files is taken, one of text is left alone. */\n const pasteProps = disabled\n ? {}\n : {\n onPaste: (e: ClipboardEvent) => {\n const files = pastedFiles(e);\n if (files.length === 0) return;\n e.preventDefault();\n take(files);\n },\n };\n\n return { inputRef, inputProps, zoneProps, pasteProps, open, take, dragOver, rejections, clearRejections };\n}\n\n/**\n * The rejection list, announced. `role=\"alert\"` is what tells a screen-reader\n * user why the drop did nothing; the sighted user sees the same sentences.\n * Renders nothing while there is nothing to say.\n */\nexport function FileIntakeAlert({ rejections, className = 'mt-2' }: { rejections: FileRejection[]; className?: string }) {\n if (rejections.length === 0) return null;\n return (\n <ul role=\"alert\" className={`${className} flex flex-col gap-0.5`}>\n {rejections.map(({ file, message }, i) => (\n <li key={`${file.name}-${i}`} className=\"text-xs text-red-600\">{message}</li>\n ))}\n </ul>\n );\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/forms/useFileIntake.tsx"],"names":[],"mappings":"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","file":"chunk-YDHXWCCJ.js","sourcesContent":["/**\n * useFileIntake — the one way a file gets INTO a kit primitive.\n *\n * Every upload surface in the kit (`FilePicker`, `MediaUploadField`,\n * `MediaUploadGrid`, `BrandAssetEditor`, `BulkImportGrid`) takes files through\n * this hook, so the three gestures — the native file dialog, a drop onto the\n * zone, a paste into a composer — share ONE intake path and ONE set of checks.\n *\n * Before this each primitive owned its own hidden `<input type=file>`, its own\n * drag-over state and its own idea of what to check: `accept` reached the\n * native dialog only, so a file dropped onto the zone bypassed it entirely;\n * a multi-file drop onto a gallery kept the first file and lost the rest\n * without a word; and a rejected file was listed in plain red text that no\n * screen reader announced. The portals then copied the hidden-input block\n * nineteen more times. This hook is the fix at the narrowest layer that can\n * hold it (harness UI-15 / PAT-10).\n *\n * The hook validates and hands back `File[]`. It never uploads — transport\n * belongs to the consumer, for the reasons `FilePicker`'s header gives.\n *\n * Its rejection sentences and size units are the catalog's `files` section, so\n * a translated app says why a file was refused in the reader's language. The\n * catalog module imports nothing but React, which keeps this entry React-only.\n */\nimport {\n useCallback, useRef, useState,\n type ChangeEvent, type ClipboardEvent, type DragEvent, type ReactNode,\n} from 'react';\nimport { DEFAULT_SHELL_STRINGS, useShellStrings, type ShellStrings } from '../shell/strings';\n\nexport type FileRejectionReason = 'type' | 'size' | 'count';\n\nexport interface FileRejection {\n file: File;\n reason: FileRejectionReason;\n /** Human sentence naming the file and the rule it broke. */\n message: string;\n}\n\nexport interface FileIntakeLimits {\n /**\n * Native `accept` string — `image/*`, `.pdf,application/pdf`, … Enforced on\n * EVERY gesture, not only the dialog: a dropped or pasted file that fails it\n * is rejected with a reason. Empty or `*` accepts anything.\n */\n accept?: string;\n /** Rejected above this many bytes, with the reason shown. */\n maxSizeBytes?: number;\n /** Rejected once this many files are held in total (see `currentCount`). */\n maxFiles?: number;\n}\n\nexport interface FileIntakeOptions extends FileIntakeLimits {\n /** Receives the files that passed every check. Never called with an empty list. */\n onAccept: (files: File[]) => void;\n /** `false` takes the first candidate only — a single slot. Default `true`. */\n multiple?: boolean;\n /** Files the surface already holds, so `maxFiles` counts the total. Default 0. */\n currentCount?: number;\n /** Short kind hint for the type-rejection sentence, e.g. \"PNG · JPG\". */\n acceptHint?: ReactNode;\n disabled?: boolean;\n}\n\n/**\n * Does `file` satisfy a native `accept` string? Extension rules match the\n * name, `type/*` rules match the MIME prefix, anything else is an exact MIME.\n * A browser reports several media types for one `.ico` file and sometimes\n * none at all, which is why an extension rule exists at all.\n */\nexport function acceptsFile(file: File, accept?: string): boolean {\n const rules = (accept ?? '').split(',').map(rule => rule.trim().toLocaleLowerCase()).filter(Boolean);\n if (rules.length === 0 || rules.includes('*') || rules.includes('*/*')) return true;\n const fileName = file.name.toLocaleLowerCase();\n const fileType = file.type.toLocaleLowerCase();\n return rules.some(rule => {\n if (rule.startsWith('.')) return fileName.endsWith(rule);\n if (rule.endsWith('/*')) return fileType.startsWith(rule.slice(0, -1));\n return fileType === rule;\n });\n}\n\n/** `812 B`, `14 KB`, `6.2 MB` — the units, and their digits, from the catalog. */\nexport const humanSize = (bytes: number, strings: ShellStrings['files'] = DEFAULT_SHELL_STRINGS.files): string => {\n if (bytes < 1024) return strings.bytes(bytes);\n if (bytes < 1024 * 1024) return strings.kilobytes(Math.round(bytes / 1024));\n return strings.megabytes(bytes / (1024 * 1024));\n};\n\n/** Is this drag carrying files (as opposed to text, a URL, or an in-page reorder)? */\nexport const isFileDrag = (e: DragEvent): boolean =>\n Array.from(e.dataTransfer?.types ?? []).includes('Files');\n\n/** Files on a clipboard event, if the paste carried any. */\nexport function pastedFiles(e: ClipboardEvent): File[] {\n const data = e.clipboardData;\n if (!data) return [];\n if (data.files && data.files.length > 0) return Array.from(data.files);\n const out: File[] = [];\n for (const item of Array.from(data.items ?? [])) {\n if (item.kind === 'file') {\n const file = item.getAsFile();\n if (file) out.push(file);\n }\n }\n return out;\n}\n\nexport function useFileIntake({\n onAccept, accept, maxSizeBytes, maxFiles, multiple = true, currentCount = 0,\n acceptHint, disabled = false,\n}: FileIntakeOptions) {\n const strings = useShellStrings().files;\n const inputRef = useRef<HTMLInputElement>(null);\n const [dragOver, setDragOver] = useState(false);\n const [rejections, setRejections] = useState<FileRejection[]>([]);\n // A drag passes over every child of the zone, firing leave/enter pairs; a\n // depth counter is what keeps the highlight steady across them.\n const depthRef = useRef(0);\n\n const hintText = typeof acceptHint === 'string' ? acceptHint : '';\n\n /** Run every candidate through the checks; deliver the survivors. */\n const take = useCallback((incoming: FileList | File[] | null | undefined) => {\n if (disabled || !incoming) return;\n const candidates = Array.from(incoming);\n if (candidates.length === 0) return;\n const accepted: File[] = [];\n const rejected: FileRejection[] = [];\n for (const file of multiple ? candidates : candidates.slice(0, 1)) {\n if (!acceptsFile(file, accept)) {\n rejected.push({\n file, reason: 'type',\n message: strings.notAccepted(file.name, hintText),\n });\n continue;\n }\n if (maxSizeBytes != null && file.size > maxSizeBytes) {\n rejected.push({\n file, reason: 'size',\n message: strings.tooLarge(file.name, humanSize(file.size, strings), humanSize(maxSizeBytes, strings)),\n });\n continue;\n }\n if (multiple && maxFiles != null && currentCount + accepted.length >= maxFiles) {\n rejected.push({\n file, reason: 'count',\n message: strings.tooMany(file.name, maxFiles),\n });\n continue;\n }\n accepted.push(file);\n }\n setRejections(rejected);\n if (accepted.length) onAccept(accepted);\n // Reset the native input so re-picking the SAME file fires change again —\n // without this, removing a file and re-adding it appears to do nothing.\n if (inputRef.current) inputRef.current.value = '';\n }, [disabled, multiple, accept, hintText, maxSizeBytes, maxFiles, currentCount, onAccept, strings]);\n\n const open = useCallback(() => {\n if (!disabled) inputRef.current?.click();\n }, [disabled]);\n\n const clearRejections = useCallback(() => setRejections([]), []);\n\n /** Spread onto the hidden native input. It is never a tab stop and never the visible control. */\n const inputProps = {\n ref: inputRef,\n type: 'file' as const,\n accept: accept || undefined,\n multiple,\n disabled,\n tabIndex: -1,\n 'aria-hidden': true as const,\n className: 'hidden',\n onChange: (e: ChangeEvent<HTMLInputElement>) => take(e.target.files),\n };\n\n /** Spread onto the drop target. Only a drag carrying files lights it up. */\n const zoneProps = disabled\n ? {}\n : {\n onDragEnter: (e: DragEvent) => {\n if (!isFileDrag(e)) return;\n e.preventDefault();\n depthRef.current += 1;\n setDragOver(true);\n },\n onDragOver: (e: DragEvent) => {\n if (!isFileDrag(e)) return;\n e.preventDefault();\n if (!dragOver) setDragOver(true);\n },\n onDragLeave: (e: DragEvent) => {\n if (!isFileDrag(e)) return;\n depthRef.current = Math.max(0, depthRef.current - 1);\n if (depthRef.current === 0) setDragOver(false);\n },\n onDrop: (e: DragEvent) => {\n if (!isFileDrag(e)) return;\n e.preventDefault();\n depthRef.current = 0;\n setDragOver(false);\n take(e.dataTransfer.files);\n },\n };\n\n /** Spread onto a composer's text area: a paste that carries files is taken, one of text is left alone. */\n const pasteProps = disabled\n ? {}\n : {\n onPaste: (e: ClipboardEvent) => {\n const files = pastedFiles(e);\n if (files.length === 0) return;\n e.preventDefault();\n take(files);\n },\n };\n\n return { inputRef, inputProps, zoneProps, pasteProps, open, take, dragOver, rejections, clearRejections };\n}\n\n/**\n * The rejection list, announced. `role=\"alert\"` is what tells a screen-reader\n * user why the drop did nothing; the sighted user sees the same sentences.\n * Renders nothing while there is nothing to say.\n */\nexport function FileIntakeAlert({ rejections, className = 'mt-2' }: { rejections: FileRejection[]; className?: string }) {\n if (rejections.length === 0) return null;\n return (\n <ul role=\"alert\" className={`${className} flex flex-col gap-0.5`}>\n {rejections.map(({ file, message }, i) => (\n <li key={`${file.name}-${i}`} className=\"text-xs text-red-600\">{message}</li>\n ))}\n </ul>\n );\n}\n"]}
|
|
@@ -173,6 +173,7 @@ function englishStrings(locale) {
|
|
|
173
173
|
end: "End",
|
|
174
174
|
fromOnly: (date) => `From ${date}`,
|
|
175
175
|
toOnly: (date) => `To ${date}`,
|
|
176
|
+
range: (from, to) => `${from} to ${to}`,
|
|
176
177
|
last2Weeks: "Last 2 Weeks",
|
|
177
178
|
lastMonth: "Last Month",
|
|
178
179
|
last3Months: "Last 3 Months",
|
|
@@ -543,5 +544,5 @@ function splitAround(sentence) {
|
|
|
543
544
|
}
|
|
544
545
|
|
|
545
546
|
export { DEFAULT_SHELL_STRINGS, ShellStringsProvider, currentShellStrings, formatFixed, formatPercent, formatPlain, splitAround, useShellLocale, useShellStrings };
|
|
546
|
-
//# sourceMappingURL=chunk-
|
|
547
|
-
//# sourceMappingURL=chunk-
|
|
547
|
+
//# sourceMappingURL=chunk-YE6GUDGP.js.map
|
|
548
|
+
//# sourceMappingURL=chunk-YE6GUDGP.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/utils/number.ts","../src/shell/strings.tsx"],"names":[],"mappings":"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","file":"chunk-YE6GUDGP.js","sourcesContent":["/**\n * Numbers in the host's locale — or exactly as the kit printed them before it\n * had a locale to print them in.\n *\n * Every helper takes the BCP 47 tag `ShellStringsProvider` was given (read with\n * `useShellLocale`), and every one has two halves. With a tag, `Intl` writes the\n * number the way that locale does: `1.234,5` in German, a narrow space before\n * the percent sign in French. Without one, the helper returns what its call\n * sites used to compute inline — `String(v)`, `v.toFixed(d)`,\n * `v.toLocaleString()` — character for character.\n *\n * The second half is the contract, and the reason the fallbacks are spelled out\n * rather than left to an `Intl` default: `new Intl.NumberFormat()` with no tag\n * is the RUNTIME's locale, and a hard-coded `'en-US'` is somebody else's. An app\n * that never mounts a provider, or mounts one without a locale, must not see a\n * digit move — a table whose totals regrouped themselves on upgrade is a bug\n * report, not a feature.\n *\n * Kit-safe: no React, no DOM.\n */\n\n/** Building an `Intl.NumberFormat` is the expensive part of using one, and a\n * chart formats every tick of every axis on every render. One per locale and\n * option set, for the life of the page. */\nconst formats = new Map<string, Intl.NumberFormat>();\n\nfunction numberFormat(locale: string, options: Intl.NumberFormatOptions): Intl.NumberFormat {\n const key = `${locale}|${JSON.stringify(options)}`;\n let format = formats.get(key);\n if (!format) {\n format = new Intl.NumberFormat(locale, options);\n formats.set(key, format);\n }\n return format;\n}\n\n/**\n * A number as written — `String(v)` without a locale. With one, every digit the\n * value has is kept (up to `Intl`'s ceiling of 20), because the call sites this\n * replaces never rounded: a chart whose caller passed 0.125 printed `0.125`, and\n * `Intl`'s default of three fraction digits would quietly print `0.125` but\n * `0.1235` for 0.12345.\n */\nexport function formatPlain(value: number, locale?: string): string {\n return locale ? numberFormat(locale, { maximumFractionDigits: 20 }).format(value) : String(value);\n}\n\n/** A count with thousands separators — `v.toLocaleString()` without a locale,\n * which is the runtime's own grouping, exactly as before. */\nexport function formatGrouped(value: number, locale?: string): string {\n return locale ? numberFormat(locale, {}).format(value) : value.toLocaleString();\n}\n\n/** Exactly `digits` decimals — `v.toFixed(digits)` without a locale. */\nexport function formatFixed(value: number, digits: number, locale?: string): string {\n return locale\n ? numberFormat(locale, { minimumFractionDigits: digits, maximumFractionDigits: digits }).format(value)\n : value.toFixed(digits);\n}\n\n/**\n * A PERCENTAGE — `37.5`, not the fraction `0.375` — with `digits` decimals:\n * `${p.toFixed(digits)}%` without a locale, the locale's own percent with one\n * (`37,5 %`, `%37,5`).\n *\n * It takes the percentage rather than the fraction because that is what every\n * call site already had in hand: they computed `(share * 100).toFixed(1)`, and\n * passing that same product through keeps the no-locale output identical down to\n * the last floating-point digit.\n */\nexport function formatPercent(percent: number, digits: number, locale?: string): string {\n return locale\n ? numberFormat(locale, {\n style: 'percent', minimumFractionDigits: digits, maximumFractionDigits: digits,\n }).format(percent / 100)\n : `${percent.toFixed(digits)}%`;\n}\n","/**\n * ShellStrings — the shell's user-facing strings, in one typed catalog.\n *\n * Every string here was hardcoded English at its call site, which made the\n * shell untranslatable no matter what the consuming portal did. The catalog\n * is the fix's whole shape: components read strings through `useShellStrings`\n * (which works with NO provider — the English defaults are the context\n * default), and a consumer that wants another language mounts\n * `ShellStringsProvider` once with a partial override. Overrides merge per\n * SECTION, so translating the window controls does not oblige anyone to\n * translate the help viewer.\n *\n * This is deliberately not an i18n library: no message IDs, no interpolation\n * DSL, no plural rules. The shell's strings are labels and short sentences;\n * a typed object keeps them discoverable and lets TypeScript flag a\n * translation that goes stale when a string is added.\n *\n * ── Sentences that carry a value are functions ──\n * \"3 of 40 records\", \"Remove invoice.pdf\", \"Choose a year, currently 2026\".\n * A string with a hole in it would need a template syntax, and a template\n * syntax would need plural rules the moment a count went into the hole —\n * which is the i18n library this file refuses to be. So those entries are\n * plain functions, and the host writes them with whatever it already has:\n * `Intl.PluralRules`, its own message catalog, a ternary.\n *\n * Two rules keep the functions predictable:\n * - A COUNT arrives as a `number`, unformatted, because the words depend on\n * it (\"1 file\", \"2 files\", \"5 файлов\") and a plural rule needs the number.\n * The host formats it; the English defaults do, in the provider's `locale`.\n * - A VALUE the kit already formatted — a date, a caller's `formatValue`\n * output, a file size — arrives as the `string` that would be printed.\n *\n * A few older entries are halves the caller concatenates (`select.remove` +\n * a label, `pageTabs.discardMany` after a count). They stay, so no existing\n * catalog breaks, and each has an optional function beside it that wins when\n * supplied — word order differs between languages, and a concatenation cannot.\n *\n * ── Locale ──\n * `ShellStringsProvider` also takes a `locale` (a BCP 47 tag). It is not a\n * string section, it is how numbers and dates are WRITTEN: month and weekday\n * names in the pickers, `formatDate`, the digits in a list footer or a chart\n * axis. With no locale the kit writes exactly what it always wrote — the same\n * English month names, `toLocaleString()` with no argument, `String(v)` — so\n * mounting the provider for its strings alone changes no number on screen.\n * `useShellLocale` reads it; `src/utils/number.ts` and `calendarNames` in\n * `src/utils/date.ts` are the two halves that honour it.\n *\n * Prop-level text (a `emptyText` prop, a `placeholder`) always wins over the\n * catalog — the catalog replaces hardcoded DEFAULTS, never a caller's words.\n *\n * Kit-safe: no window-manager import, so `efficient-shell/ui` consumers get it\n * too.\n */\nimport { createContext, useContext, useEffect, useMemo, type ReactNode } from 'react';\nimport { formatFixed, formatGrouped, formatPercent, formatPlain } from '../utils/number';\n\nexport interface ShellStrings {\n /** Window chrome: control tooltips and the title bar's accessible name. */\n window: {\n minimize: string;\n /** Bring a hand-minimized window back — the tab's own control. */\n restore: string;\n maximize: string;\n windowed: string;\n pinOnTop: string;\n unpin: string;\n close: string;\n /** Suffix of the title bar's aria-label: `\"{title} — {windowSuffix}\"`. */\n windowSuffix: string;\n prev: string;\n next: string;\n snapLayouts: string;\n snapLeft: string;\n snapRight: string;\n snapTopLeft: string;\n snapTopRight: string;\n snapBottomLeft: string;\n snapBottomRight: string;\n };\n /** Taskbar and exposé. */\n taskbar: {\n closeWindow: string;\n offscreenHint: string;\n offscreenDot: string;\n expose: string;\n addToDesktop: string;\n removeFromDesktop: string;\n /** Group menu — a taskbar tab standing for more than one window. The\n * count is appended by the caller, e.g. \"Close all (3)\". */\n minimizeAllWindows: string;\n restoreAllWindows: string;\n closeAllWindows: string;\n };\n /** The logout cover. */\n logout: {\n goodbye: string;\n seeYou: string;\n };\n /** About + What's New dialogs. */\n about: {\n aboutPrefix: string;\n thisApp: string;\n openSourceLicenses: string;\n whatsNew: string;\n noChangelog: string;\n };\n /** Data-display defaults (DataTable, lists). */\n table: {\n empty: string;\n loading: string;\n selectAll: string;\n selectRow: string;\n };\n /** Picker defaults (SearchableSelect, TagInput). */\n select: {\n none: string;\n noMatches: string;\n allSelected: string;\n clear: string;\n /** aria-label of a TagInput chip's remove button: `\"{remove} {label}\"`. */\n remove: string;\n /** The whole chip label, when the word order is not \"{remove} {label}\".\n * Wins over `remove` when supplied. */\n removeItem?: (label: string) => string;\n };\n /** Notification bell + popup. */\n notifications: {\n title: string;\n markAllRead: string;\n dnd: string;\n dndOn: string;\n caughtUp: string;\n empty: string;\n viewAll: string;\n cardLabel: string;\n dismiss: string;\n };\n /** Form-level messages. */\n form: {\n errorSummaryTitle: string;\n };\n /** HelpCenter chrome. */\n help: {\n title: string;\n searchPlaceholder: string;\n empty: string;\n noResults: string;\n loading: string;\n pickArticle: string;\n noBody: string;\n draft: string;\n newArticle: string;\n edit: string;\n };\n /** The app-update banner (a deploy happened under a long-lived tab). */\n update: {\n available: string;\n refreshNow: string;\n };\n /** The page-tab strip (`efficient-shell/page-tabs`). */\n pageTabs: {\n /** The strip's accessible name. */\n label: string;\n /** A tab's close button, and the menu item: `\"{close} {title}\"` for the button. */\n close: string;\n /** The close button's whole label, when the word order is not\n * \"{close} {title}\". Wins over `close` for the button when supplied. */\n closeTab?: (title: string) => string;\n closeOthers: string;\n closeRight: string;\n closeAll: string;\n /** Marks a tab with unsaved changes (the dot's accessible text). */\n unsaved: string;\n /** Asked before a tab with unsaved changes closes. */\n discardTitle: string;\n discardOne: string;\n /** Several at once — the count is prefixed by the caller: \"3 pages have…\". */\n discardMany: string;\n /** The whole several-at-once sentence, for a language whose noun follows\n * the count's plural form. Wins over `discardMany` when supplied. */\n discardCount?: (count: number) => string;\n discardConfirm: string;\n keepEditing: string;\n };\n /** `Dialog` and `Drawer`'s close control, and the dialogs behind `confirm`,\n * `confirmDestructive` and `prompt` (each option a caller passes wins). */\n dialog: {\n close: string;\n cancel: string;\n ok: string;\n /** `confirm`'s heading when the caller gives no `title`. */\n confirmTitle: string;\n /** `confirmDestructive`'s heading, cancel and confirm defaults. */\n destructiveTitle: string;\n destructiveCancel: string;\n destructiveConfirm: string;\n /** The line over the type-to-confirm box; the word is drawn in a `<kbd>`\n * wherever the sentence puts it. */\n typeToConfirm: (word: string) => string;\n /** `prompt`'s heading when the caller gives no `title`. */\n promptTitle: string;\n };\n /** The month grid (`Calendar`, and the pickers that open it). Month and\n * weekday NAMES are not here — they come from `locale`. */\n calendar: {\n previousMonth: string;\n nextMonth: string;\n previousYear: string;\n nextYear: string;\n previousYears: string;\n nextYears: string;\n /** The month and year panels' accessible names. */\n monthPanel: string;\n yearPanel: string;\n /** The heading's month button. */\n chooseMonth: (month: string) => string;\n /** The heading's year button. */\n chooseYear: (year: number) => string;\n };\n /** `DatePicker`'s trigger and popover. */\n datePicker: {\n placeholder: string;\n /** The popover's accessible name when the field has no `aria-label`. */\n dialog: string;\n clear: string;\n today: string;\n };\n /** `DateRangePicker`. */\n dateRange: {\n placeholder: string;\n /** The trigger's × button. */\n clearRange: string;\n /** The popover's and the grid's accessible name. */\n dialog: string;\n from: string;\n to: string;\n /** The From/To boxes before a day is chosen. */\n start: string;\n end: string;\n /** The trigger with only one end of the range set. */\n fromOnly: (date: string) => string;\n toOnly: (date: string) => string;\n /**\n * The whole range as a sentence — what a labelled trigger is DESCRIBED\n * as, after its label names it (\"Period, button, 1 August 2026 to\n * 3 October 2026\"). Both dates arrive spelled out in the locale.\n */\n range: (from: string, to: string) => string;\n last2Weeks: string;\n lastMonth: string;\n last3Months: string;\n last6Months: string;\n last12Months: string;\n custom: string;\n clear: string;\n cancel: string;\n apply: string;\n };\n /** `Pagination` (and `DataTable`'s pager). */\n pagination: {\n label: string;\n first: string;\n previous: string;\n next: string;\n last: string;\n };\n /** `ListFooter` and `ListLoadError`. `label` is the caller's own noun\n * (\"records\"); the counts are numbers, for the plural. */\n list: {\n /** Before the em dash: \"3 selected — 40 records\". */\n selected: (count: number) => string;\n allLoaded: (total: number, label: string) => string;\n count: (total: number, label: string) => string;\n loadedOf: (loaded: number, total: number, label: string) => string;\n /** After a middle dot: \"40 of 900 records · Loading more...\". */\n loadingMore: string;\n loadError: string;\n loadErrorMessage: string;\n retry: string;\n };\n /** `Kanban`'s defaults (its own props win). */\n kanban: {\n loading: string;\n empty: string;\n dropHere: string;\n addItem: string;\n };\n /** File intake: `FilePicker`, `ComposerAttachments`, and the rejection\n * messages every upload control shares. */\n files: {\n attach: string;\n drop: string;\n remove: (name: string) => string;\n chooseMany: string;\n chooseOne: string;\n /** After the choose link, in the same line. */\n dragMany: string;\n dragOne: string;\n /** `hint` is the caller's `acceptHint` when it is a string, else ''. */\n notAccepted: (name: string, hint: string) => string;\n /** `size` and `limit` arrive written out — \"6.2 MB\". */\n tooLarge: (name: string, size: string, limit: string) => string;\n tooMany: (name: string, max: number) => string;\n bytes: (value: number) => string;\n kilobytes: (value: number) => string;\n megabytes: (value: number) => string;\n };\n /** `MediaUploadField` and `MediaUploadGrid`. */\n media: {\n uploadImage: string;\n uploadVideo: string;\n uploadFile: string;\n /** The drop zone's accessible name when its prompt is not a string. */\n upload: string;\n cta: string;\n replace: string;\n remove: string;\n uploading: string;\n cover: string;\n add: string;\n addMedia: string;\n empty: string;\n removeItem: (name: string) => string;\n /** A reorderable thumbnail's accessible name. */\n reorder: (name: string, position: number, total: number) => string;\n };\n /** `BrandAssetEditor`. `noun` is the last word of `assetName`, lower-cased\n * (\"Portal logo\" → \"logo\"); a translation that cannot use it has\n * `assetName` itself. */\n brandAsset: {\n save: (noun: string, assetName: string) => string;\n remove: (noun: string, assetName: string) => string;\n discard: string;\n saveFailed: (noun: string, assetName: string) => string;\n removeFailed: (noun: string, assetName: string) => string;\n region: (assetName: string, subjectName: string) => string;\n usedFor: (subjectName: string) => string;\n previews: (assetName: string) => string;\n preview: string;\n alt: (subjectName: string, assetName: string) => string;\n };\n /** `Snippet`'s copy button, and the clipboard's toasts. */\n copy: {\n copy: string;\n copyLabel: (label: string) => string;\n /** Snippet's spoken confirmation. */\n copied: string;\n /** `copyToClipboard`'s success toast; `label` names what was copied. */\n copiedLabel: (label: string) => string;\n failed: string;\n };\n /** `NumericKeypad`. */\n keypad: {\n backspace: string;\n enter: string;\n };\n /** `Banner`. */\n banner: {\n dismiss: string;\n };\n /** A closable `ColoredBadge`'s × (its `closeLabel` wins). */\n badge: {\n /** When the badge's content is not plain text. */\n remove: string;\n removeItem: (label: string) => string;\n };\n /** `Breadcrumbs`. */\n breadcrumbs: {\n label: string;\n /** The ellipsis standing for the crumbs `maxItems` folded away. */\n hidden: string;\n };\n /** `EmptyState`'s line when the caller gives neither a title nor a message. */\n emptyState: {\n message: string;\n };\n /** `ErrorPage`, `ErrorBoundary` and `Result`'s status defaults. */\n errors: {\n notFound: string;\n notFoundBody: string;\n forbidden: string;\n forbiddenBody: string;\n /** `Result status=\"403\"`'s title — gentler than `ErrorPage`'s. */\n noAccess: string;\n serverError: string;\n serverErrorBody: string;\n retry: string;\n details: string;\n };\n /** `GlobalSearch`. */\n search: {\n placeholder: string;\n /** The key cap beside the input. */\n escBadge: string;\n searching: string;\n noResults: string;\n minChars: (min: number) => string;\n navigate: string;\n open: string;\n close: string;\n enterKey: string;\n escKey: string;\n };\n /** `EditableGrid`. */\n grid: {\n selectAll: string;\n insertRowAbove: string;\n insertRowBelow: string;\n deleteRow: (row: number) => string;\n insertColumnLeft: string;\n insertColumnRight: string;\n deleteColumn: (column: string) => string;\n resize: string;\n fill: string;\n };\n /** `SidebarLayout`'s resize handle. */\n sidebar: {\n resize: string;\n };\n /** `MarkdownLite`. */\n markdown: {\n /** Before an image placeholder's caption, with an em dash between. */\n screenshot: string;\n };\n /** The word a severity marker is spoken and tooltipped with. */\n severity: {\n success: string;\n warning: string;\n danger: string;\n /** A token that is not one of the three, as received. */\n unrecognised: (token: string) => string;\n };\n /** `MetricBar` and `BudgetBar`. */\n meter: {\n noData: string;\n warningAt: (bound: number) => string;\n criticalAt: (bound: number) => string;\n noReading: string;\n noBudget: string;\n /** The meter's spoken value: \"84% of budget\". */\n ofBudget: (value: string) => string;\n /** The deadline marker's tooltip. */\n budget: string;\n hoursMinutes: (hours: number, minutes: number) => string;\n minutesSeconds: (minutes: number, seconds: number) => string;\n seconds: (seconds: number) => string;\n };\n /** The chart family. Series, axis and category names are the caller's. */\n charts: {\n showTable: string;\n loading: string;\n noData: string;\n windowStart: string;\n windowEnd: string;\n window: (from: string, to: string, count: number) => string;\n overIntervals: (series: string[], count: number) => string;\n acrossCategories: (series: string[], count: number) => string;\n acrossMeasures: (series: string[], count: number) => string;\n /** The pie's accessible name; `total` is written by the caller's `formatValue`. */\n breakdown: (total: string, segments: number) => string;\n funnel: (stages: number, first: string, last: string) => string;\n radialTrack: (count: number) => string;\n radialCycle: (count: number) => string;\n /** Column heads of the screen-reader tables some charts carry. */\n tableFrom: string;\n tableTo: string;\n tableItem: string;\n tableLevel: string;\n tableSeries: string;\n inBucket: (total: string) => string;\n inCategory: (total: string) => string;\n value: string;\n share: string;\n count: string;\n flow: string;\n totalFlow: string;\n throughput: string;\n open: string;\n high: string;\n low: string;\n close: string;\n maximum: string;\n q3: string;\n median: string;\n q1: string;\n minimum: string;\n distribution: string;\n fiveNumber: (label: string, count: number) => string;\n outliers: (count: number) => string;\n price: string;\n ohlc: (label: string, count: number) => string;\n closedAbove: string;\n closedBelow: string;\n noFlows: string;\n chord: (count: number) => string;\n noStages: string;\n ofFirstStage: string;\n droppedHere: string;\n intensity: string;\n noActivity: string;\n heatmap: (label: string, rows: number, columns: number) => string;\n /** A histogram's y-axis title. */\n countAxis: string;\n histogram: (label: string, bins: number, observations: number) => string;\n observations: string;\n /** `Meter` with no value to judge. */\n notEnough: string;\n objectiveMet: (objective: string) => string;\n objectiveMissed: (objective: string) => string;\n nothingToPlot: string;\n nothingToCompare: string;\n /** The pie slice the small segments are folded into. */\n other: string;\n nothingToBreakDown: string;\n range: string;\n rangeLabel: (label: string, count: number) => string;\n nothingToRank: string;\n /** Spoken after the emphasised row of `RankedBars`. */\n emphasised: string;\n sankey: (nodes: number, links: number) => string;\n noObservations: string;\n xAxis: string;\n yAxis: string;\n size: string;\n scatter: (series: string[], yLabel: string, xLabel: string) => string;\n outsideRange: (count: number) => string;\n waterfall: (steps: number, from: string, to: string) => string;\n balance: string;\n increase: string;\n decrease: string;\n runningTotal: string;\n sunburst: (total: string, depth: number) => string;\n treemap: (count: number) => string;\n /** `StatTile`'s delta direction, spoken after the arrow glyph. */\n trendUp: string;\n trendDown: string;\n trendFlat: string;\n };\n /** `TimelineTrack` and `MilestoneTimeline`. */\n timeline: {\n /** A cut in the axis: \"412 days\". */\n days: (count: number) => string;\n daysToToday: (count: number) => string;\n notReached: string;\n /** Before the first pending entry, with a middle dot after it. */\n next: string;\n more: (count: number) => string;\n today: string;\n todayTitle: (date: string) => string;\n open: (name: string) => string;\n openButton: string;\n scrub: string;\n alsoToCome: (names: string[]) => string;\n start: (date: string) => string;\n /** A folded run of marks: its count, then each member's own name. */\n events: (count: number, names: string[]) => string;\n started: (date: string) => string;\n duration: (days: number) => string;\n reached: (dated: number, total: number) => string;\n milestones: (title: string) => string;\n };\n /** `ProductionTimeline`. */\n production: {\n heading: string;\n /** The synthetic report standing for the production start. */\n start: string;\n /** The synthetic report between two real ones. */\n estimated: string;\n estimatedCompletion: string;\n estDone: string;\n play: string;\n pause: string;\n playTitle: string;\n backTo: (report: string) => string;\n /** The report is drawn bold wherever the sentence puts it. */\n showing: (report: string) => string;\n overall: (percent: number) => string;\n inStock: (pieces: number) => string;\n noReport: string;\n leadTime: (days: number) => string;\n report: string;\n shipment: string;\n inspection: string;\n invoice: string;\n scrub: string;\n label: (from: string, to: string) => string;\n };\n /** `ContainerFillChart`. Volumes are cubic metres. */\n containers: {\n items: (count: number) => string;\n pieces: (count: number) => string;\n split: (instructed: number, loaded: number) => string;\n added: (count: number, pieces: number) => string;\n fill: (volume: number, capacity: number) => string;\n total: string;\n instructed: (volume: number) => string;\n loaded: (volume: number) => string;\n volume: (volume: number) => string;\n noVolume: string;\n };\n /** `toast.notify`'s card. */\n toast: {\n notification: string;\n };\n}\n\n/**\n * The English catalog, with its numbers written for `locale`.\n *\n * A function, not a literal, because the defaults that carry a count have to\n * write it the way the provider's locale does — `1.234 records` is still the\n * English default, in a German-formatted app — and the locale is not known\n * until a provider says so. With no locale every number is written exactly as\n * the component wrote it inline before (`toLocaleString()` where it grouped,\n * a bare interpolation where it did not), which is what makes\n * `DEFAULT_SHELL_STRINGS` byte-identical to the strings it replaced.\n */\nfunction englishStrings(locale?: string): ShellStrings {\n const plain = (v: number) => formatPlain(v, locale);\n const grouped = (v: number) => formatGrouped(v, locale);\n const fixed = (v: number, digits: number) => formatFixed(v, digits, locale);\n const percent = (p: number, digits: number) => formatPercent(p, digits, locale);\n return {\n window: {\n minimize: 'Minimize',\n restore: 'Restore',\n maximize: 'Maximize',\n windowed: 'Windowed',\n pinOnTop: 'Pin on top',\n unpin: 'Unpin from top',\n close: 'Close',\n windowSuffix: 'window',\n prev: 'Prev',\n next: 'Next',\n snapLayouts: 'Snap layouts',\n snapLeft: 'Snap left half',\n snapRight: 'Snap right half',\n snapTopLeft: 'Snap top-left quarter',\n snapTopRight: 'Snap top-right quarter',\n snapBottomLeft: 'Snap bottom-left quarter',\n snapBottomRight: 'Snap bottom-right quarter',\n },\n taskbar: {\n closeWindow: 'Close window',\n offscreenHint: 'This window is off screen — click to bring it back',\n offscreenDot: 'Off screen — click to bring this window back',\n expose: 'Exposé — show all open windows as thumbnails',\n addToDesktop: 'Add to desktop',\n removeFromDesktop: 'Remove from desktop',\n minimizeAllWindows: 'Minimize all',\n restoreAllWindows: 'Restore all',\n closeAllWindows: 'Close all',\n },\n logout: {\n goodbye: 'Goodbye',\n seeYou: 'See you next time',\n },\n about: {\n aboutPrefix: 'About',\n thisApp: 'this app',\n openSourceLicenses: 'Open Source Licenses',\n whatsNew: \"What's New\",\n noChangelog: 'No changelog available.',\n },\n table: {\n empty: 'Nothing to show',\n loading: 'Loading',\n selectAll: 'Select all rows',\n selectRow: 'Select row',\n },\n select: {\n none: '— None —',\n noMatches: 'No matches',\n allSelected: 'All options selected',\n clear: 'Clear selection',\n remove: 'Remove',\n },\n notifications: {\n title: 'Notifications',\n markAllRead: 'Mark all read',\n dnd: 'Do not disturb',\n dndOn: 'Do not disturb is on',\n caughtUp: 'All caught up',\n empty: 'No notifications yet',\n viewAll: 'View all notifications',\n cardLabel: 'Notification',\n dismiss: 'Dismiss notification',\n },\n form: {\n errorSummaryTitle: 'There is a problem',\n },\n help: {\n title: 'Help',\n searchPlaceholder: 'Search help…',\n empty: 'No help articles yet.',\n noResults: 'No articles match your search.',\n loading: 'Loading…',\n pickArticle: 'Pick a help article from the left.',\n noBody: 'This article has no body yet.',\n draft: 'Draft',\n newArticle: '+ New',\n edit: 'Edit',\n },\n update: {\n available: 'A new version is available.',\n refreshNow: 'Refresh now',\n },\n pageTabs: {\n label: 'Open pages',\n close: 'Close',\n closeOthers: 'Close other tabs',\n closeRight: 'Close tabs to the right',\n closeAll: 'Close all tabs',\n unsaved: 'Unsaved changes',\n discardTitle: 'Discard unsaved changes?',\n discardOne: 'This page has changes that have not been saved. Close it anyway?',\n discardMany: 'pages have changes that have not been saved. Close them anyway?',\n discardConfirm: 'Discard and close',\n keepEditing: 'Keep editing',\n },\n dialog: {\n close: 'Close',\n cancel: 'Cancel',\n ok: 'OK',\n confirmTitle: 'Confirm',\n destructiveTitle: 'Confirm Action',\n destructiveCancel: 'Dismiss',\n destructiveConfirm: 'Delete',\n typeToConfirm: word => `Type ${word} to confirm:`,\n promptTitle: 'Enter a value',\n },\n calendar: {\n previousMonth: 'Previous month',\n nextMonth: 'Next month',\n previousYear: 'Previous year',\n nextYear: 'Next year',\n previousYears: 'Previous years',\n nextYears: 'Next years',\n monthPanel: 'Choose a month',\n yearPanel: 'Choose a year',\n chooseMonth: month => `Choose a month, currently ${month}`,\n // A year is never grouped: \"2,026\" is a quantity, not a year.\n chooseYear: year => `Choose a year, currently ${year}`,\n },\n datePicker: {\n placeholder: 'Select a date',\n dialog: 'Choose a date',\n clear: 'Clear',\n today: 'Today',\n },\n dateRange: {\n placeholder: 'Date Range',\n clearRange: 'Clear date range',\n dialog: 'Date range',\n from: 'From',\n to: 'To',\n start: 'Start',\n end: 'End',\n fromOnly: date => `From ${date}`,\n toOnly: date => `To ${date}`,\n range: (from, to) => `${from} to ${to}`,\n last2Weeks: 'Last 2 Weeks',\n lastMonth: 'Last Month',\n last3Months: 'Last 3 Months',\n last6Months: 'Last 6 Months',\n last12Months: 'Last 12 Months',\n custom: 'Custom',\n clear: 'Clear',\n cancel: 'Cancel',\n apply: 'Apply',\n },\n pagination: {\n label: 'Pagination',\n first: 'First page',\n previous: 'Previous page',\n next: 'Next page',\n last: 'Last page',\n },\n list: {\n selected: count => `${plain(count)} selected`,\n allLoaded: (total, label) => `All ${grouped(total)} ${label} loaded`,\n count: (total, label) => `${grouped(total)} ${label}`,\n loadedOf: (loaded, total, label) => `${grouped(loaded)} of ${grouped(total)} ${label}`,\n loadingMore: 'Loading more...',\n loadError: \"Couldn't load this list\",\n loadErrorMessage: 'Something went wrong fetching these records. Check your connection and try again.',\n retry: 'Try again',\n },\n kanban: {\n loading: 'Loading…',\n empty: 'No items.',\n dropHere: 'Drop here',\n addItem: 'Add item',\n },\n files: {\n attach: 'Attach files',\n drop: 'Drop files to attach',\n remove: name => `Remove ${name}`,\n chooseMany: 'Choose files',\n chooseOne: 'Choose a file',\n dragMany: 'or drag them here',\n dragOne: 'or drag it here',\n notAccepted: (name, hint) => `${name} is not an accepted file type${hint ? ` (${hint})` : ''}`,\n tooLarge: (name, size, limit) => `${name} is ${size} — the limit is ${limit}`,\n tooMany: (name, max) => `${name} was not added — ${plain(max)} ${max === 1 ? 'file' : 'files'} is the limit`,\n bytes: value => `${plain(value)} B`,\n kilobytes: value => `${plain(value)} KB`,\n megabytes: value => `${fixed(value, 1)} MB`,\n },\n media: {\n uploadImage: 'Upload an image',\n uploadVideo: 'Upload a video',\n uploadFile: 'Upload a file',\n upload: 'Upload media',\n cta: 'Choose from library or upload',\n replace: 'Replace',\n remove: 'Remove',\n uploading: 'Uploading…',\n cover: 'Cover',\n add: 'Add',\n addMedia: 'Add media',\n empty: 'No media.',\n removeItem: name => `Remove ${name}`,\n reorder: (name, position, total) =>\n `${name}, item ${plain(position)} of ${plain(total)}. Use arrow keys to reorder.`,\n },\n brandAsset: {\n save: noun => `Save ${noun}`,\n remove: noun => `Remove ${noun}`,\n discard: 'Discard change',\n saveFailed: noun => `Could not save ${noun}.`,\n removeFailed: noun => `Could not remove ${noun}.`,\n region: (assetName, subjectName) => `${assetName} for ${subjectName}`,\n usedFor: subjectName => `Used for ${subjectName}.`,\n previews: assetName => `${assetName} previews`,\n preview: 'Preview',\n alt: (subjectName, assetName) => `${subjectName} ${assetName}`,\n },\n copy: {\n copy: 'Copy',\n copyLabel: label => `Copy ${label}`,\n copied: 'Copied',\n copiedLabel: label => `${label} copied`,\n failed: 'Could not copy to the clipboard',\n },\n keypad: {\n backspace: 'Backspace',\n enter: 'Enter',\n },\n banner: {\n dismiss: 'Dismiss',\n },\n badge: {\n remove: 'Remove',\n removeItem: label => `Remove ${label}`,\n },\n breadcrumbs: {\n label: 'Breadcrumb',\n hidden: 'Hidden crumbs',\n },\n emptyState: {\n message: 'Nothing here yet.',\n },\n errors: {\n notFound: 'Page not found',\n notFoundBody: \"The page you're looking for doesn't exist or was moved.\",\n forbidden: 'Access denied',\n forbiddenBody: \"You don't have permission to view this page.\",\n noAccess: \"You don't have access to this\",\n serverError: 'Something went wrong',\n serverErrorBody: 'An unexpected error occurred. Please try again.',\n retry: 'Try again',\n details: 'Error details',\n },\n search: {\n placeholder: 'Search...',\n escBadge: 'ESC',\n searching: 'Searching...',\n noResults: 'No results found.',\n minChars: min => `Type at least ${plain(min)} characters to search...`,\n navigate: 'navigate',\n open: 'open',\n close: 'close',\n enterKey: 'Enter',\n escKey: 'Esc',\n },\n grid: {\n selectAll: 'Select all',\n insertRowAbove: 'Insert row above',\n insertRowBelow: 'Insert row below',\n // A row NUMBER, as the grid's own row header prints it — never grouped.\n deleteRow: row => `Delete row ${row}`,\n insertColumnLeft: 'Insert column left',\n insertColumnRight: 'Insert column right',\n deleteColumn: column => `Delete column ${column}`,\n resize: 'Drag to resize · double-click to auto-fit',\n fill: 'Drag to fill',\n },\n sidebar: {\n resize: 'Drag to resize · double-click to reset',\n },\n markdown: {\n screenshot: 'Screenshot',\n },\n severity: {\n success: 'ok',\n warning: 'warning',\n danger: 'critical',\n unrecognised: token => `unrecognised severity ${token}`,\n },\n meter: {\n noData: 'no data',\n warningAt: bound => `warning ≥ ${plain(bound)}`,\n criticalAt: bound => `critical ≥ ${plain(bound)}`,\n noReading: 'no reading',\n noBudget: 'no budget',\n ofBudget: value => `${value} of budget`,\n budget: 'budget',\n hoursMinutes: (hours, minutes) => `${plain(hours)}h ${plain(minutes)}m`,\n minutesSeconds: (minutes, seconds) => `${plain(minutes)}m ${plain(seconds)}s`,\n seconds: seconds => `${plain(seconds)}s`,\n },\n charts: {\n showTable: 'Show the data as a table',\n loading: 'Loading chart data',\n noData: 'No data in this window.',\n windowStart: 'Window start',\n windowEnd: 'Window end',\n window: (from, to, count) => `Time window — showing ${from} to ${to} of ${plain(count)} intervals`,\n overIntervals: (series, count) => `${series.join(', ')} over ${plain(count)} intervals`,\n acrossCategories: (series, count) => `${series.join(', ')} across ${plain(count)} categories`,\n acrossMeasures: (series, count) => `${series.join(', ')} across ${plain(count)} measures`,\n breakdown: (total, segments) => `Breakdown of ${total} across ${plain(segments)} segments`,\n funnel: (stages, first, last) => `Funnel of ${plain(stages)} stages, ${first} down to ${last}`,\n radialTrack: count => `${plain(count)} categories, as concentric proportions`,\n radialCycle: count => `${plain(count)} categories, around a cycle`,\n tableFrom: 'From',\n tableTo: 'To',\n tableItem: 'Item',\n tableLevel: 'Level',\n tableSeries: 'Series',\n inBucket: total => `${total} in this bucket`,\n inCategory: total => `${total} in this category`,\n value: 'Value',\n share: 'Share',\n count: 'Count',\n flow: 'Flow',\n totalFlow: 'Total flow',\n throughput: 'Throughput',\n open: 'Open',\n high: 'High',\n low: 'Low',\n close: 'Close',\n maximum: 'Maximum',\n q3: 'Q3',\n median: 'Median',\n q1: 'Q1',\n minimum: 'Minimum',\n distribution: 'Distribution',\n fiveNumber: (label, count) => `${label}: five-number summary for ${plain(count)} categories`,\n outliers: count => `${plain(count)} outlier${count > 1 ? 's' : ''} beyond the whiskers`,\n price: 'Price',\n ohlc: (label, count) => `${label}: open, high, low and close across ${plain(count)} periods`,\n closedAbove: 'Closed above its open',\n closedBelow: 'Closed below its open',\n noFlows: 'No flows to chart.',\n chord: count => `Flows between ${plain(count)} participants`,\n noStages: 'No stages to chart.',\n ofFirstStage: 'Of first stage',\n droppedHere: 'Dropped here',\n intensity: 'Intensity',\n noActivity: 'No activity in this window.',\n heatmap: (label, rows, columns) => `${label} across ${plain(rows)} rows and ${plain(columns)} columns`,\n countAxis: 'count',\n histogram: (label, bins, observations) =>\n `${label}: ${plain(bins)} bins over ${plain(observations)} observations`,\n observations: 'Observations',\n notEnough: 'Not enough eligible requests to judge.',\n objectiveMet: objective => `objective ${objective} met`,\n objectiveMissed: objective => `objective ${objective} missed`,\n nothingToPlot: 'Nothing to plot.',\n nothingToCompare: 'Nothing to compare.',\n other: 'Other',\n nothingToBreakDown: 'Nothing to break down.',\n range: 'Range',\n rangeLabel: (label, count) => `${label}: low and high across ${plain(count)} categories`,\n nothingToRank: 'Nothing to rank in this window.',\n emphasised: '(emphasised)',\n sankey: (nodes, links) => `Flow between ${plain(nodes)} nodes over ${plain(links)} links`,\n noObservations: 'No observations in this window.',\n xAxis: 'x',\n yAxis: 'y',\n size: 'Size',\n scatter: (series, yLabel, xLabel) => `${series.join(', ')}: ${yLabel} against ${xLabel}`,\n outsideRange: count => `${plain(count)} ${count === 1 ? 'point' : 'points'} outside the shown range`,\n waterfall: (steps, from, to) => `Waterfall of ${plain(steps)} steps from ${from} to ${to}`,\n balance: 'Balance',\n increase: 'Increase',\n decrease: 'Decrease',\n runningTotal: 'Running total',\n sunburst: (total, depth) => `Hierarchy of ${total} across ${plain(depth)} levels`,\n treemap: count => `Treemap of ${plain(count)} items`,\n trendUp: 'up',\n trendDown: 'down',\n trendFlat: 'flat',\n },\n timeline: {\n days: count => `${grouped(count)} days`,\n daysToToday: count => `${grouped(count)} days to today`,\n notReached: 'Not yet reached',\n next: 'Next',\n more: count => `+${plain(count)} more`,\n today: 'Today',\n todayTitle: date => `Today — ${date}`,\n open: name => `Open ${name}`,\n openButton: 'Open',\n scrub: 'Scrub the timeline',\n alsoToCome: names => `Also to come: ${names.join(', ')}`,\n start: date => `Start · ${date}`,\n events: (count, names) => `${plain(count)} events · ${names.join(', ')}`,\n started: date => `started ${date}`,\n duration: days => `${grouped(days)} day${days === 1 ? '' : 's'}`,\n reached: (dated, total) => `${plain(dated)} of ${plain(total)} milestones`,\n milestones: title => `${title} milestones`,\n },\n production: {\n heading: 'Production progress',\n start: 'Start',\n estimated: 'Estimated',\n estimatedCompletion: 'Estimated completion',\n estDone: 'Est. done',\n play: 'Play',\n pause: 'Pause',\n playTitle: 'Play the timeline, report by report',\n backTo: report => `Back to ${report}`,\n showing: report => `Showing ${report}`,\n overall: p => `${percent(p, 0)} overall`,\n inStock: pieces => `${grouped(pieces)} pc in stock`,\n noReport: 'No production report filed yet',\n leadTime: days => `${grouped(days)} day${days === 1 ? '' : 's'} lead time`,\n report: 'Production report',\n shipment: 'Shipment',\n inspection: 'Inspection',\n invoice: 'Invoice',\n scrub: 'Scrub the production timeline',\n label: (from, to) => `Production reports and events, ${from} to ${to}`,\n },\n containers: {\n items: count => `${plain(count)} items`,\n pieces: count => `${plain(count)} pcs`,\n split: (instructed, loaded) => `(${plain(instructed)} instr / ${plain(loaded)} loaded)`,\n added: (count, pieces) => `${plain(count)} new (${plain(pieces)} pcs)`,\n fill: (volume, capacity) => `${fixed(volume, 1)} / ${plain(capacity)} m³`,\n total: 'Total:',\n instructed: volume => `${fixed(volume, 2)} m³ instruction`,\n loaded: volume => `${fixed(volume, 2)} m³ loaded`,\n volume: volume => `${fixed(volume, 2)} m³`,\n noVolume: 'Volume: N/A (no volume data for these part numbers)',\n },\n toast: {\n notification: 'Notification',\n },\n };\n}\n\nexport const DEFAULT_SHELL_STRINGS: ShellStrings = englishStrings();\n\n/** The English defaults per locale — a provider re-rendering with the same\n * locale gets the same object, so its merge memo holds. */\nconst localisedDefaults = new Map<string, ShellStrings>();\n\nfunction defaultsFor(locale: string | undefined): ShellStrings {\n if (!locale) return DEFAULT_SHELL_STRINGS;\n let defaults = localisedDefaults.get(locale);\n if (!defaults) {\n defaults = englishStrings(locale);\n localisedDefaults.set(locale, defaults);\n }\n return defaults;\n}\n\n/** A per-section partial: override any subset of a section's strings. */\nexport type ShellStringsOverride = {\n [S in keyof ShellStrings]?: Partial<ShellStrings[S]>;\n};\n\nconst ShellStringsContext = createContext<ShellStrings>(DEFAULT_SHELL_STRINGS);\n\n/** `null` outside any provider — which is how a provider tells it is nested. */\nconst ShellLocaleContext = createContext<{ locale: string | undefined } | null>(null);\n\nconst reportedLocales = new Set<string>();\n\n/**\n * The tag in canonical form, or `undefined` for one `Intl` refuses.\n *\n * Refused here, once, rather than at every formatter: `new Intl.DateTimeFormat\n * ('en_US')` throws, and a malformed tag would otherwise take down whichever\n * component formatted a number first — in render, where the error boundary is\n * the only thing left to catch it. A tag that is well formed but names nothing\n * the runtime has (`xx-YY`) is not an error: `Intl` falls back on its own.\n */\nfunction canonicalLocale(tag: string | undefined): string | undefined {\n if (!tag) return undefined;\n try {\n return Intl.getCanonicalLocales(tag)[0];\n } catch {\n if (!reportedLocales.has(tag)) {\n reportedLocales.add(tag);\n console.error(\n `[efficient-shell] ShellStringsProvider: locale=\"${tag}\" is not a BCP 47 language tag, so it is ` +\n 'ignored and numbers and dates keep their default formatting. Pass a tag such as \"de-DE\" or \"ja\".',\n );\n }\n return undefined;\n }\n}\n\n/**\n * The catalog for code that runs outside React — `toast` builds its DOM by\n * hand, long after any render. It follows the OUTERMOST mounted provider (the\n * app's own, not a subtree's), and is the English defaults when none is\n * mounted. Not part of the public surface: components read `useShellStrings`.\n */\nlet outermost: ShellStrings = DEFAULT_SHELL_STRINGS;\n\n/** One empty override for every provider given none — a fresh `{}` per render\n * would re-merge, and re-render every reader, each time the provider did. */\nconst NO_OVERRIDE: ShellStringsOverride = {};\n\nexport function currentShellStrings(): ShellStrings {\n return outermost;\n}\n\n/**\n * Mount once, near the top of the app. `value` is a partial — sections and\n * keys you do not translate keep their English defaults, so a catalog never\n * breaks by falling behind a release.\n *\n * `locale` is a BCP 47 tag (`'de-DE'`, `'ja'`, `'zh-Hant'`) for how numbers and\n * dates are written; omit it and they are written exactly as without a\n * provider. A nested provider without a `locale` keeps its parent's — a subtree\n * that overrides one string should not lose the app's number format. Strings\n * do not cascade that way: a nested provider's `value` merges onto the English\n * defaults, as it always has.\n */\nexport function ShellStringsProvider({ value = NO_OVERRIDE, locale, children }: {\n value?: ShellStringsOverride;\n locale?: string;\n children: ReactNode;\n}) {\n const parent = useContext(ShellLocaleContext);\n const own = useMemo(() => canonicalLocale(locale), [locale]);\n const active = locale === undefined ? parent?.locale : own;\n const merged = useMemo<ShellStrings>(() => {\n const base = defaultsFor(active);\n const out = {} as ShellStrings;\n for (const key of Object.keys(base) as (keyof ShellStrings)[]) {\n out[key] = { ...base[key], ...(value[key] ?? {}) } as never;\n }\n return out;\n }, [value, active]);\n const localeValue = useMemo(() => ({ locale: active }), [active]);\n\n const nested = parent !== null;\n useEffect(() => {\n if (nested) return;\n outermost = merged;\n return () => {\n if (outermost === merged) outermost = DEFAULT_SHELL_STRINGS;\n };\n }, [merged, nested]);\n\n return (\n <ShellLocaleContext.Provider value={localeValue}>\n <ShellStringsContext.Provider value={merged}>{children}</ShellStringsContext.Provider>\n </ShellLocaleContext.Provider>\n );\n}\n\n/** The active catalog — English defaults when no provider is mounted. */\nexport function useShellStrings(): ShellStrings {\n return useContext(ShellStringsContext);\n}\n\n/**\n * The provider's `locale`, canonicalised — `undefined` when there is no\n * provider or it was given none. Hand it to `formatDate(value, { locale })`,\n * `fmtSliderDate(ms, locale)`, or `Intl` directly, so a host's own cells write\n * numbers and dates the way the kit's do.\n */\nexport function useShellLocale(): string | undefined {\n return useContext(ShellLocaleContext)?.locale;\n}\n\n/**\n * The text either side of the value in a catalog sentence, for the few\n * sentences that wrap their value in markup of its own — \"Type <kbd>DELETE</kbd>\n * to confirm:\", \"Showing <b>PR-7</b>\".\n *\n * The entry stays a plain `(word) => string`, so a translator writes a sentence\n * and puts the word wherever their language does; the kit calls it with a\n * marker no sentence contains and splits there. A sentence that leaves the word\n * out entirely comes back whole, as the text before it.\n */\nexport function splitAround(sentence: (slot: string) => string): [string, string] {\n const MARK = '\\u0000';\n const [before = '', ...after] = sentence(MARK).split(MARK);\n return [before, after.join('')];\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/version.ts"],"names":[],"mappings":";AAIO,IAAM,OAAA,GAAwD,SAAA;AAG9D,IAAM,WAAA,GAAc","file":"chunk-
|
|
1
|
+
{"version":3,"sources":["../src/version.ts"],"names":[],"mappings":";AAIO,IAAM,OAAA,GAAwD,SAAA;AAG9D,IAAM,WAAA,GAAc","file":"chunk-ZS7PMGUW.js","sourcesContent":["declare const __PKG_VERSION__: string | undefined;\n\n/** Package version, injected by tsup at build time. Stays as an empty\n * string when the source is consumed without a build (e.g. tests). */\nexport const VERSION: string = typeof __PKG_VERSION__ === 'string' ? __PKG_VERSION__ : '';\n\n/** Legacy alias kept so existing consumers do not break. */\nexport const APP_VERSION = VERSION;\n"]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
export { FileIntakeAlert, acceptsFile, useFileIntake } from '../chunk-
|
|
3
|
-
import '../chunk-
|
|
2
|
+
export { FileIntakeAlert, acceptsFile, useFileIntake } from '../chunk-YDHXWCCJ.js';
|
|
3
|
+
import '../chunk-YE6GUDGP.js';
|
|
4
4
|
//# sourceMappingURL=index.js.map
|
|
5
5
|
//# sourceMappingURL=index.js.map
|