preact-missing-hooks 4.2.0 → 4.4.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/dist/react.js CHANGED
@@ -1692,6 +1692,90 @@ function useLLMMetadata(config) {
1692
1692
  ]);
1693
1693
  }
1694
1694
 
1695
+ const PRINT_CLASS = "use-ref-print-target";
1696
+ const PRINT_STYLE_ID = "use-ref-print-styles";
1697
+ const PRINT_CSS = `
1698
+ @media print {
1699
+ body * {
1700
+ visibility: hidden;
1701
+ }
1702
+ .${PRINT_CLASS},
1703
+ .${PRINT_CLASS} * {
1704
+ visibility: visible;
1705
+ }
1706
+ .${PRINT_CLASS} {
1707
+ position: absolute !important;
1708
+ left: 0 !important;
1709
+ top: 0 !important;
1710
+ width: 100% !important;
1711
+ }
1712
+ }
1713
+ `;
1714
+ /**
1715
+ * A Preact hook that binds a ref to a printable section and provides a function
1716
+ * to print only that section using the native window.print() and @media print CSS.
1717
+ * When print() is called (or user presses Ctrl+P after focusing that section), only
1718
+ * the ref section is visible in the print layout. User can then print or save as PDF.
1719
+ *
1720
+ * @param printRef - Ref to the DOM element (e.g. a div) that should be printed.
1721
+ * @param options - Optional: downloadAsPdf hint, documentTitle for the print document.
1722
+ * @returns Object with a print() function.
1723
+ *
1724
+ * @example
1725
+ * ```tsx
1726
+ * function Report() {
1727
+ * const printRef = useRef<HTMLDivElement>(null);
1728
+ * const { print } = useRefPrint(printRef, { documentTitle: 'Report', downloadAsPdf: true });
1729
+ * return (
1730
+ * <div>
1731
+ * <div ref={printRef}>Content to print or save as PDF</div>
1732
+ * <button onClick={print}>Print / Save as PDF</button>
1733
+ * </div>
1734
+ * );
1735
+ * }
1736
+ * ```
1737
+ */
1738
+ function useRefPrint(printRef, options = {}) {
1739
+ const { documentTitle } = options;
1740
+ const originalTitleRef = react.useRef("");
1741
+ const print = react.useCallback(() => {
1742
+ const el = printRef.current;
1743
+ if (!el || typeof window === "undefined" || !window.print) {
1744
+ return;
1745
+ }
1746
+ // Ensure print-only styles exist (once per document)
1747
+ let styleEl = document.getElementById(PRINT_STYLE_ID);
1748
+ if (!styleEl) {
1749
+ styleEl = document.createElement("style");
1750
+ styleEl.id = PRINT_STYLE_ID;
1751
+ styleEl.textContent = PRINT_CSS;
1752
+ document.head.appendChild(styleEl);
1753
+ }
1754
+ el.classList.add(PRINT_CLASS);
1755
+ if (documentTitle) {
1756
+ originalTitleRef.current = document.title;
1757
+ document.title = documentTitle;
1758
+ }
1759
+ const cleanup = () => {
1760
+ el.classList.remove(PRINT_CLASS);
1761
+ if (documentTitle && originalTitleRef.current !== undefined) {
1762
+ document.title = originalTitleRef.current;
1763
+ }
1764
+ };
1765
+ if ("onafterprint" in window) {
1766
+ const onAfterPrint = () => {
1767
+ cleanup();
1768
+ window.removeEventListener("afterprint", onAfterPrint);
1769
+ };
1770
+ window.addEventListener("afterprint", onAfterPrint);
1771
+ }
1772
+ window.print();
1773
+ // Fallback cleanup if afterprint is not fired (e.g. user cancels)
1774
+ setTimeout(cleanup, 1000);
1775
+ }, [printRef, documentTitle]);
1776
+ return { print };
1777
+ }
1778
+
1695
1779
  exports.useClipboard = useClipboard;
1696
1780
  exports.useEventBus = useEventBus;
1697
1781
  exports.useIndexedDB = useIndexedDB;
@@ -1700,6 +1784,7 @@ exports.useMutationObserver = useMutationObserver;
1700
1784
  exports.useNetworkState = useNetworkState;
1701
1785
  exports.usePreferredTheme = usePreferredTheme;
1702
1786
  exports.useRageClick = useRageClick;
1787
+ exports.useRefPrint = useRefPrint;
1703
1788
  exports.useThreadedWorker = useThreadedWorker;
1704
1789
  exports.useTransition = useTransition;
1705
1790
  exports.useWasmCompute = useWasmCompute;
@@ -0,0 +1,39 @@
1
+ import type { RefObject } from "preact";
2
+ export interface UseRefPrintOptions {
3
+ /**
4
+ * When true, the print flow is triggered so the user can choose
5
+ * "Save as PDF" in the native print dialog. Uses the same window.print() path.
6
+ */
7
+ downloadAsPdf?: boolean;
8
+ /** Title for the print document (e.g. used when saving as PDF). */
9
+ documentTitle?: string;
10
+ }
11
+ export interface UseRefPrintReturn {
12
+ /** Triggers native print for the section bound to the ref (opens print dialog; only that section is printed via @media print). */
13
+ print: () => void;
14
+ }
15
+ /**
16
+ * A Preact hook that binds a ref to a printable section and provides a function
17
+ * to print only that section using the native window.print() and @media print CSS.
18
+ * When print() is called (or user presses Ctrl+P after focusing that section), only
19
+ * the ref section is visible in the print layout. User can then print or save as PDF.
20
+ *
21
+ * @param printRef - Ref to the DOM element (e.g. a div) that should be printed.
22
+ * @param options - Optional: downloadAsPdf hint, documentTitle for the print document.
23
+ * @returns Object with a print() function.
24
+ *
25
+ * @example
26
+ * ```tsx
27
+ * function Report() {
28
+ * const printRef = useRef<HTMLDivElement>(null);
29
+ * const { print } = useRefPrint(printRef, { documentTitle: 'Report', downloadAsPdf: true });
30
+ * return (
31
+ * <div>
32
+ * <div ref={printRef}>Content to print or save as PDF</div>
33
+ * <button onClick={print}>Print / Save as PDF</button>
34
+ * </div>
35
+ * );
36
+ * }
37
+ * ```
38
+ */
39
+ export declare function useRefPrint(printRef: RefObject<HTMLElement | null>, options?: UseRefPrintOptions): UseRefPrintReturn;
package/docs/main.js CHANGED
@@ -19,6 +19,7 @@ const {
19
19
  useWasmCompute,
20
20
  useWorkerNotifications,
21
21
  useLLMMetadata,
22
+ useRefPrint,
22
23
  } = await import(
23
24
  isLocal ? '../dist/index.module.js' : 'https://unpkg.com/preact-missing-hooks/dist/index.module.js'
24
25
  );
@@ -317,6 +318,29 @@ function DemoWorkerNotifications() {
317
318
  );
318
319
  }
319
320
 
321
+ function DemoRefPrint() {
322
+ const printRef = useRef(null);
323
+ const { print } = useRefPrint(printRef, { documentTitle: 'Preact Missing Hooks — useRefPrint Demo', downloadAsPdf: true });
324
+ return h('div', {},
325
+ h('div', {
326
+ ref: printRef,
327
+ style: {
328
+ padding: '1rem',
329
+ background: 'var(--surface2)',
330
+ borderRadius: '6px',
331
+ marginBottom: '0.75rem',
332
+ border: '1px solid var(--border)',
333
+ },
334
+ }, [
335
+ h('strong', { style: { display: 'block', marginBottom: '0.5rem' } }, 'This section is printable'),
336
+ h('p', { style: { margin: 0, fontSize: '0.9rem', color: 'var(--text2)' } },
337
+ 'Click "Print / Save as PDF" to open the native print dialog. You can print or choose "Save as PDF" as the destination.'
338
+ ),
339
+ ]),
340
+ h('button', { onClick: print }, 'Print / Save as PDF')
341
+ );
342
+ }
343
+
320
344
  function DemoLLMMetadata() {
321
345
  const [route, setRoute] = useState('/');
322
346
  useLLMMetadata({
@@ -452,6 +476,13 @@ const HOOKS = [
452
476
  code: `const stats = useWorkerNotifications(worker, { maxHistory: 100 });\n// stats.progress, stats.runningTasks, stats.throughputPerSecond, ...`,
453
477
  Live: DemoWorkerNotifications,
454
478
  },
479
+ {
480
+ name: 'useRefPrint',
481
+ flow: 'ref + useRefPrint(ref, options?) → print() → native window.print() for that section',
482
+ summary: 'Binds a ref to a printable section and provides print() to open the native print dialog (user can save as PDF).',
483
+ code: `const printRef = useRef(null);\nconst { print } = useRefPrint(printRef, { documentTitle: 'My Doc', downloadAsPdf: true });\n// ... <div ref={printRef}>Content</div> ... <button onClick={print}>Print</button>`,
484
+ Live: DemoRefPrint,
485
+ },
455
486
  {
456
487
  name: 'useLLMMetadata',
457
488
  flow: 'Component → useLLMMetadata({ route, mode, title?, ... } | null) → <script type="application/llm+json" data-llm="true"> in <head>',