@wildwinter/app-shell 0.46.4 → 0.46.5

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.
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/util.ts"],"names":[],"mappings":"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","file":"chunk-P6WLAEKZ.js","sourcesContent":["// ---------------------------------------------------------------------------\n// The small idioms both apps wrote by hand and never gave a name: the plural\n// suffix (about forty sites), the debounce (eight copies), \"is the focus in a\n// field\" (four copies that disagreed about <select>), the count with grouping\n// separators, clipboard copy with the `.copied` revert (three timings), and\n// relative time (two wordings). One answer each, here.\n//\n// DOM-free except where the idiom is about the DOM (isEditableTarget,\n// copyWithFeedback), so main-process code can import the rest.\n// ---------------------------------------------------------------------------\n\n/** \"1 link\" / \"3 links\". The plural form defaults to `noun + \"s\"`; pass the\n * irregular one (\"entry\", \"entries\") when that is wrong. */\nexport function plural(n: number, noun: string, pluralForm = `${noun}s`): string {\n return `${n} ${n === 1 ? noun : pluralForm}`;\n}\n\nexport interface Debounced<A extends unknown[]> {\n (...args: A): void;\n /** Drop the pending call. */\n cancel(): void;\n /** Run the pending call now, if there is one. */\n flush(): void;\n}\n\n/** Trailing-edge debounce: the call runs `ms` after the LAST call. */\nexport function debounce<A extends unknown[]>(fn: (...args: A) => void, ms: number): Debounced<A> {\n let timer: ReturnType<typeof setTimeout> | undefined;\n let pending: A | undefined;\n const run = (): void => {\n timer = undefined;\n if (pending === undefined) return;\n const args = pending;\n pending = undefined;\n fn(...args);\n };\n const debounced = ((...args: A): void => {\n pending = args;\n if (timer !== undefined) clearTimeout(timer);\n timer = setTimeout(run, ms);\n }) as Debounced<A>;\n debounced.cancel = () => { if (timer !== undefined) clearTimeout(timer); timer = undefined; pending = undefined; };\n debounced.flush = () => { if (timer !== undefined) clearTimeout(timer); run(); };\n return debounced;\n}\n\n/**\n * Is the keyboard's focus in a field? The one agreed answer: an input, a\n * textarea, a select, or anything contenteditable (the attribute is read as\n * well as `isContentEditable`, which jsdom does not implement). A window-level\n * shortcut checks this before acting, so a bare letter typed into a field\n * stays a letter.\n */\nexport function isEditableTarget(t: EventTarget | null | undefined): boolean {\n if (!(t instanceof Element)) return false;\n if (t instanceof HTMLInputElement || t instanceof HTMLTextAreaElement || t instanceof HTMLSelectElement) return true;\n if (t instanceof HTMLElement && t.isContentEditable === true) return true;\n const attr = t.getAttribute(\"contenteditable\");\n return attr !== null && attr !== \"false\";\n}\n\n/** A count for reading: grouping separators in the user's locale. */\nexport function formatCount(n: number): string {\n return n.toLocaleString();\n}\n\nconst copyTimers = new WeakMap<Element, ReturnType<typeof setTimeout>>();\n\n/**\n * Copy `text` to the clipboard and light `el` with `.copied` for `ms` (the\n * family's 1000). A second click restarts the timer rather than stacking a\n * second revert under the first. Resolves when the clipboard write has.\n */\nexport function copyWithFeedback(el: Element, text: string, ms = 1000): Promise<void> {\n const write = typeof navigator !== \"undefined\" && navigator.clipboard\n ? navigator.clipboard.writeText(text).catch(() => {})\n : Promise.resolve();\n el.classList.add(\"copied\");\n const prior = copyTimers.get(el);\n if (prior !== undefined) clearTimeout(prior);\n copyTimers.set(el, setTimeout(() => { el.classList.remove(\"copied\"); copyTimers.delete(el); }, ms));\n return write;\n}\n\n/**\n * How long ago, in one wording: \"just now\", \"4 minutes ago\", \"an hour ago\",\n * \"3 hours ago\", \"yesterday\", \"5 days ago\", and past a week the date itself.\n * Coarse on purpose: the question a reader has is whether the thing is from\n * this sitting, not how many seconds ago it was. A future date is \"just now\".\n */\nexport function relativeTime(date: Date | number | string, now: number = Date.now()): string {\n const then = date instanceof Date ? date.getTime() : new Date(date).getTime();\n if (!Number.isFinite(then)) return \"\";\n const mins = Math.floor((now - then) / 60000);\n if (mins < 1) return \"just now\";\n if (mins < 60) return `${plural(mins, \"minute\")} ago`;\n const hours = Math.floor(mins / 60);\n if (hours === 1) return \"an hour ago\";\n if (hours < 24) return `${hours} hours ago`;\n const days = Math.floor(hours / 24);\n if (days === 1) return \"yesterday\";\n if (days < 7) return `${days} days ago`;\n return new Date(then).toLocaleDateString(undefined, { day: \"numeric\", month: \"short\", year: \"numeric\" });\n}\n"]}