@zinejs/core 0.8.0 → 0.8.2
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/controls/styles.d.ts +1 -1
- package/dist/controls/types.d.ts +7 -2
- package/dist/{controls-Djjk8Yac.js → controls-DgEXR2zi.js} +69 -57
- package/dist/controls-DgEXR2zi.js.map +1 -0
- package/dist/index.js +188 -175
- package/dist/index.js.map +1 -1
- package/dist/index.umd.js +36 -7
- package/dist/index.umd.js.map +1 -1
- package/dist/loading/loading.d.ts +1 -1
- package/dist/{loading-C0qbANt2.js → loading-BBK6YbSW.js} +2 -2
- package/dist/loading-BBK6YbSW.js.map +1 -0
- package/dist/{share-DXAfK9rJ.js → share-WXdscwp3.js} +2 -2
- package/dist/{share-DXAfK9rJ.js.map → share-WXdscwp3.js.map} +1 -1
- package/dist/styles-B8fFoYm_.js +40 -0
- package/dist/styles-B8fFoYm_.js.map +1 -0
- package/package.json +1 -1
- package/dist/controls-Djjk8Yac.js.map +0 -1
- package/dist/loading-C0qbANt2.js.map +0 -1
- package/dist/styles-CgCzjFUk.js +0 -40
- package/dist/styles-CgCzjFUk.js.map +0 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export declare const CSS = "\n/* Docked mode wraps the book so the bar can sit beside it without shrinking the container,\n whose measured box the renderer and hit-testing both depend on.\n The wrapper deliberately does not stretch or grow its children: the container keeps whatever\n width, aspect-ratio and auto-margins the consumer's own CSS gave it. */\n.zine-controls-wrap { display: flex; }\n/* Stacked: children keep their own width (so a percentage or auto-margin still resolves against\n the wrapper) and take only the height they ask for. */\n.zine-controls-wrap-top,\n.zine-controls-wrap-bottom { flex-direction: column; align-items: stretch; }\n/* Side by side: the bar is only as wide as its buttons, and both are vertically centred. */\n.zine-controls-wrap-left,\n.zine-controls-wrap-right { flex-direction: row; align-items: center; }\n/* min-height:0 matters as much as min-width here. A flex item's automatic minimum size floors it\n at its content, so once the canvas has grown for a taller layout the book cannot shrink back \u2014\n its aspect-ratio is restored but ignored, leaving the extra height behind. */\n.zine-controls-wrap > * { flex: 0 0 auto; min-width: 0; min-height: 0; }\n\n.zine-controls {\n position: relative;\n display: flex;\n gap: 4px;\n padding: 5px;\n z-index: 2;\n box-sizing: border-box;\n font: 500 12px/1.2 system-ui, sans-serif;\n color: var(--zine-controls-fg, light-dark(#18181b, #f4f4f5));\n touch-action: auto;\n -webkit-user-select: none;\n user-select: none;\n}\n.zine-controls-docked { flex: 0 0 auto; justify-content: center; align-items: center; }\n.zine-controls-floating {\n position: absolute;\n /* Transparent to the book except on the buttons themselves, so gaps stay draggable. */\n pointer-events: none;\n}\n.zine-controls-bar {\n display: flex;\n align-items: center;\n gap: 1px;\n padding: 3px;\n border-radius: 8px;\n pointer-events: auto;\n background: var(--zine-controls-bg, light-dark(rgba(255, 255, 255, 0.94), rgba(24, 24, 27, 0.82)));\n backdrop-filter: blur(8px);\n}\n/* Floating: lifted off the page it covers. Docked: flat, with an outline so it reads as a\n control strip rather than a shadow hanging in empty space. */\n.zine-controls-floating .zine-controls-bar { box-shadow: 0 2px 12px rgba(0, 0, 0, 0.28); }\n.zine-controls-docked .zine-controls-bar {\n border: 1px solid var(--zine-controls-hover, light-dark(rgba(0, 0, 0, 0.08), rgba(255, 255, 255, 0.14)));\n}\n.zine-controls-floating.zine-controls-bottom { inset: auto 0 0 0; justify-content: center; }\n.zine-controls-floating.zine-controls-top { inset: 0 0 auto 0; justify-content: center; }\n.zine-controls-floating.zine-controls-left { inset: 0 auto 0 0; align-items: center; }\n.zine-controls-floating.zine-controls-right { inset: 0 0 0 auto; align-items: center; }\n/* A bar on a vertical edge stacks its buttons, docked or floating. */\n.zine-controls-left .zine-controls-bar,\n.zine-controls-right .zine-controls-bar { flex-direction: column; }\n\n.zine-controls-btn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 26px;\n height: 26px;\n padding: 0;\n border: 0;\n border-radius: 6px;\n background: transparent;\n color: inherit;\n cursor: pointer;\n font: inherit;\n}\n.zine-controls-btn svg { width: 15px; height: 15px; }\n.zine-controls-btn:hover:not(:disabled) { background: var(--zine-controls-hover, light-dark(rgba(0,0,0,0.08), rgba(255,255,255,0.14))); }\n.zine-controls-btn:focus-visible {\n outline: 2px solid var(--zine-controls-accent, light-dark(#0284c7, #7dd3fc));\n outline-offset: 1px;\n}\n.zine-controls-btn:disabled { opacity: 0.38; cursor: default; }\n/* A custom widget cannot always be disabled itself, so it is marked instead and reads the same. */\n.zine-controls-off { opacity: 0.38; }\n.zine-controls-off[aria-disabled='true'] { pointer-events: none; }\n.zine-controls-btn[aria-pressed=\"true\"],\n.zine-controls-btn[aria-expanded=\"true\"] { background: var(--zine-controls-hover, light-dark(rgba(0,0,0,0.08), rgba(255,255,255,0.14))); }\n\n.zine-controls-sep {\n width: 1px;\n align-self: stretch;\n margin: 3px 3px;\n background: currentColor;\n opacity: 0.22;\n}\n.zine-controls-left .zine-controls-sep,\n.zine-controls-right .zine-controls-sep { width: auto; height: 1px; margin: 3px 3px; }\n\n.zine-controls-page {\n display: inline-flex;\n align-items: center;\n gap: 3px;\n padding: 0 3px;\n pointer-events: auto;\n white-space: nowrap;\n}\n.zine-controls-page input {\n width: 2.2em;\n padding: 2px 3px;\n border: 1px solid var(--zine-controls-hover, light-dark(rgba(0,0,0,0.14), rgba(255,255,255,0.2)));\n border-radius: 4px;\n background: light-dark(rgba(0, 0, 0, 0.05), rgba(0, 0, 0, 0.25));\n color: inherit;\n font: inherit;\n text-align: center;\n -moz-appearance: textfield;\n}\n.zine-controls-page input::-webkit-outer-spin-button,\n.zine-controls-page input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }\n.zine-controls-page input:focus-visible {\n outline: 2px solid var(--zine-controls-accent, light-dark(#0284c7, #7dd3fc));\n outline-offset: 0;\n}\n\n.zine-controls-menu {\n position: absolute;\n display: flex;\n flex-direction: column;\n gap: 1px;\n min-width: 152px;\n padding: 4px;\n border-radius: 8px;\n pointer-events: auto;\n background: var(--zine-controls-bg, light-dark(rgba(255, 255, 255, 0.94), rgba(24, 24, 27, 0.94)));\n box-shadow: 0 6px 22px rgba(0, 0, 0, 0.36);\n backdrop-filter: blur(8px);\n}\n.zine-controls-menu .zine-controls-btn {\n width: 100%;\n height: auto;\n gap: 8px;\n padding: 6px 8px;\n justify-content: flex-start;\n}\n\n/* Search shares the rail: a query field pinned at the top over a scrolling list of hits. */\n.zine-search { gap: 0; overflow: hidden; }\n.zine-search-input {\n flex: 0 0 auto;\n width: 100%;\n padding: 6px 8px;\n border: 1px solid var(--zine-controls-hover, light-dark(rgba(0,0,0,0.14), rgba(255,255,255,0.2)));\n border-radius: 6px;\n background: light-dark(rgba(0, 0, 0, 0.05), rgba(0, 0, 0, 0.25));\n color: inherit;\n font: inherit;\n box-sizing: border-box;\n}\n/* Replace the browser's default (white) focus ring with the accent ring the other controls use. */\n.zine-search-input:focus-visible {\n outline: none;\n border-color: var(--zine-controls-accent, light-dark(#0284c7, #7dd3fc));\n box-shadow: 0 0 0 1px var(--zine-controls-accent, light-dark(#0284c7, #7dd3fc));\n}\n.zine-search-hits {\n flex: 1 1 auto;\n overflow-y: auto;\n /* Chain overscroll up to the page: once the list is at its end (or too short to scroll at all),\n a further wheel scrolls the page behind, the same as scrolling over the book itself does. */\n overscroll-behavior: auto;\n margin-top: 5px;\n scrollbar-width: thin;\n}\n.zine-search-hit {\n display: block;\n width: 100%;\n padding: 6px 8px;\n border: 0;\n border-radius: 5px;\n background: transparent;\n color: inherit;\n font: inherit;\n text-align: left;\n cursor: pointer;\n box-sizing: border-box;\n}\n.zine-search-hit:hover { background: var(--zine-controls-hover, light-dark(rgba(0,0,0,0.08), rgba(255,255,255,0.14))); }\n.zine-search-hit:focus-visible {\n outline: 2px solid var(--zine-controls-accent, light-dark(#0284c7, #7dd3fc));\n outline-offset: -2px;\n}\n.zine-search-page { display: block; font-size: 0.9em; opacity: 0.85; }\n.zine-search-hit small {\n display: block;\n margin-top: 2px;\n opacity: 0.62;\n line-height: 1.35;\n overflow-wrap: anywhere;\n}\n\n/* Page-turn arrows flanking the book. Like the docked toolbar and the side panels, they sit\n outside the container so they never shrink the book or intercept its gestures. */\n.zine-arrows-wrap {\n display: flex;\n align-items: center;\n gap: 4px;\n min-width: 0;\n}\n.zine-arrows-wrap > *:not(.zine-arrow) { flex: 1 1 auto; min-width: 0; min-height: 0; }\n.zine-arrow {\n flex: 0 0 auto;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 44px;\n height: 44px;\n padding: 0;\n border: 0;\n background: none;\n /* Light on a light page, dark on a dark one. The shadow below carries the contrast. */\n color: var(--zine-controls-fg, light-dark(#f4f4f5, #18181b));\n cursor: pointer;\n -webkit-user-select: none;\n user-select: none;\n /* No grey tap box on touch; the :active tint below is the press feedback instead. */\n -webkit-tap-highlight-color: transparent;\n}\n.zine-arrow svg {\n width: 36px;\n height: 36px;\n stroke-width: 2.25;\n /* No backing disc, so a subtle offset shadow keeps the chevron from disappearing into a\n matching background. It contrasts the fill: a light chevron (light mode) casts a soft dark\n shadow, a dark chevron (dark mode) a soft light one, offset rather than a glowing halo. */\n filter: drop-shadow(0 1px 2px light-dark(rgba(0, 0, 0, 0.5), rgba(255, 255, 255, 0.35)));\n}\n/* Feedback intensifies the chevron toward its extreme (white in light mode, black in dark)\n rather than tinting it, so no new colour is introduced. Not tied to --zine-controls-fg: that\n sets the resting fill, and hover has to differ from it to read as feedback. :active clears on\n release, so tap and click feel the same; :hover is behind (hover: hover) so it never sticks on\n touch. */\n.zine-arrow:active:not(:disabled) { color: light-dark(#ffffff, #000000); }\n@media (hover: hover) {\n .zine-arrow:hover:not(:disabled) { color: light-dark(#ffffff, #000000); }\n}\n.zine-arrow:focus-visible {\n outline: 2px solid var(--zine-controls-accent, light-dark(#0284c7, #7dd3fc));\n outline-offset: 2px;\n border-radius: 8px;\n}\n/* Nothing to turn to: invisible, but still occupying its slot so the book does not slide across\n as the reader reaches a cover. */\n.zine-arrow-hidden { visibility: hidden; }\n/* Device-scoped arrows (controls.arrows: 'desktop' | 'mobile'). The split follows the same 640px\n breakpoint as the flank/overlay layouts below, so the arrows appear and disappear live as the\n window crosses it. */\n@media (max-width: 640px) {\n .zine-arrows-desktop > .zine-arrow { display: none; }\n}\n@media (min-width: 641px) {\n .zine-arrows-mobile > .zine-arrow { display: none; }\n}\n/* Too narrow to flank without squeezing the pages, so overlay the arrows on the book's edges\n instead. The wrap sits outside the container, so painting them over it leaves the container's\n measured box (which sizes the book and maps taps) untouched. */\n@media (max-width: 640px) {\n .zine-arrows-wrap { position: relative; }\n .zine-arrow {\n position: absolute;\n top: 50%;\n transform: translateY(-50%);\n z-index: 2;\n /* Sit back over the page so the reader can look at the book. */\n opacity: 0.7;\n }\n .zine-arrow:first-child { left: -2px; }\n .zine-arrow:last-child { right: -2px; }\n}\n@media (prefers-reduced-motion: no-preference) {\n .zine-arrow { transition: background 120ms ease; }\n}\n\n/* Side panels (thumbnails, outline, search). The rail wraps the book and its docked toolbar so it\n sits beside them as a flex sibling. On a wide screen the book shrinks to make room (below); on a\n narrow one the rail becomes a drawer over the book.\n align-items:flex-start, not stretch: the book sizes its height from its width through its own\n aspect-ratio, and that height is 'auto' from flex's point of view, so a stretch would override it\n and blow the book (and the rail matched to it) up to the flex line's cross size. Left as auto, the\n book keeps its aspect height and the holder alone stretches down to meet it (below). */\n.zine-panel-wrap { display: flex; align-items: flex-start; gap: 8px; position: relative; }\n\n/* The book-side slot (the bare container, or the docked-toolbar wrapper around it) yields space to\n the fixed-width rail instead of overflowing: flex-shrink lets it fall below its own width, and\n min-width:0 removes the automatic content floor that would otherwise stop it. The book only\n actually shrinks if its width is elastic (a %, max-width, or the demo's min(...) with a % term);\n a hard-coded pixel width has nothing for the % to resolve smaller against. */\n.zine-panel-wrap > *:not(.zine-panel-holder):not(.zine-panel-scrim) {\n flex: 0 1 auto;\n min-width: 0;\n}\n/* With a docked toolbar the book lives inside .zine-controls-wrap, whose children are pinned\n flex:0 0 auto (so the bar keeps its size). Inside a panel wrap the book child \u2014 everything but\n the bar itself \u2014 must instead be allowed to shrink, so left/right docking flanks like the rest.\n Top/bottom docking already shrinks through the container's own % width. */\n.zine-panel-wrap .zine-controls-wrap > *:not(.zine-controls) {\n flex: 0 1 auto;\n min-width: 0;\n min-height: 0;\n}\n@media (prefers-reduced-motion: no-preference) {\n .zine-panel-wrap > *:not(.zine-panel-holder):not(.zine-panel-scrim) {\n transition: flex-basis 160ms ease, width 160ms ease;\n }\n}\n\n/* The holder stretches to the book's height; the rail is absolutely positioned inside it so a\n long list scrolls rather than growing the row and running past the bottom of the book. */\n.zine-panel-holder {\n position: relative;\n flex: 0 0 auto;\n align-self: stretch;\n min-height: 0;\n}\n/* The scrim dims the book behind the narrow-screen drawer. It exists on every screen but only\n shows under the breakpoint below, so on a wide screen it takes no flex slot and never intercepts\n a click. */\n.zine-panel-scrim { display: none; }\n.zine-panel {\n position: absolute;\n inset: 0;\n display: flex;\n flex-direction: column;\n gap: 6px;\n overflow-y: auto;\n /* Chain overscroll up to the page: once the list is at its end (or too short to scroll at all),\n a further wheel scrolls the page behind, the same as scrolling over the book itself does. */\n overscroll-behavior: auto;\n /* Reserve the scrollbar's lane whether or not it is showing, so rows never sit under the bar\n and the close button (inset past this lane below) has a fixed edge to clear. */\n scrollbar-gutter: stable;\n padding: 6px;\n box-sizing: border-box;\n border-radius: 8px;\n background: var(--zine-controls-bg, light-dark(rgba(255, 255, 255, 0.94), rgba(24, 24, 27, 0.82)));\n color: var(--zine-controls-fg, light-dark(#18181b, #f4f4f5));\n font: 500 11px/1.2 system-ui, sans-serif;\n scrollbar-width: thin;\n touch-action: auto;\n -webkit-user-select: none;\n user-select: none;\n}\n/* The rail sits flush against the book's reading-start edge (left, or right in RTL), so its outer\n corners there would round away from that edge and leave a gap. Square them; keep the interior\n corners, which face the page, rounded. */\n.zine-panel { border-radius: 0 8px 8px 0; }\n.zine-panel-wrap-rtl .zine-panel { border-radius: 8px 0 0 8px; }\n/* Overlay fallback, used when the container has no parent to wrap. */\n.zine-panel-overlay { position: absolute; inset: 0 auto 0 0; z-index: 3; }\n.zine-panel-active { background: var(--zine-controls-hover, light-dark(rgba(0,0,0,0.08), rgba(255,255,255,0.18))); }\n.zine-panel-note { padding: 8px; opacity: 0.66; line-height: 1.4; }\n/* Discoverable dismiss, floated in the rail's trailing-top (interior) corner, away from the book.\n It sits in the holder above the scrolling list so the list scrolls under it. A translucent\n backdrop keeps the glyph legible over a thumbnail or a line of text. */\n.zine-panel-close {\n position: absolute;\n top: 6px;\n /* Inset past the reserved scrollbar gutter so the button never overlaps the bar. */\n right: 12px;\n z-index: 1;\n display: inline-flex;\n width: 24px;\n height: 24px;\n align-items: center;\n justify-content: center;\n padding: 0;\n border: 0;\n border-radius: 6px;\n /* Opaque so a light thumbnail underneath never shows through and dims the glyph. */\n background: light-dark(#f4f4f5, #27272a);\n color: inherit;\n cursor: pointer;\n}\n.zine-panel-close svg { width: 15px; height: 15px; }\n/* Opaque hover, not the translucent hover token: a see-through backdrop over a light thumbnail\n would wash the glyph out. Solid neutrals keep the X readable in both themes over anything. */\n.zine-panel-close:hover { background: light-dark(#e4e4e7, #3f3f46); }\n.zine-panel-close:focus-visible {\n outline: 2px solid var(--zine-controls-accent, light-dark(#0284c7, #7dd3fc));\n outline-offset: -2px;\n}\n.zine-panel-wrap-rtl .zine-panel-close { right: auto; left: 12px; }\n/* End the search field just before the close button rather than running under it, so the two sit\n side by side and the field's border reads cleanly. The button's inner edge is ~30px from the\n panel's content edge (24px wide, its right edge 6px in once the reserved scrollbar gutter is\n accounted for), so 30px leaves them flush with a hair of breathing room. width:auto lets the\n column's stretch fill the rest, so the margin shortens the field instead of overflowing 100%. */\n.zine-search .zine-search-input { width: auto; align-self: stretch; margin-right: 30px; }\n.zine-panel-wrap-rtl .zine-search .zine-search-input { margin-right: 0; margin-left: 30px; }\n\n/* Overlay panels (outline, search) on a wide screen: float over the book's start edge instead of\n flanking it, so the book never resizes. The wrap drops to a block, laying the book out exactly as\n it was before the panel opened; the holder sits absolute over it at full book height, with a\n shadow so it reads as lifted off the page. thumbnails is not overlaid \u2014 it stays a flex flank and\n shrinks the book only when the two will not otherwise both fit. */\n@media (min-width: 641px) {\n .zine-panel-wrap-overlay { display: block; }\n .zine-panel-wrap-overlay .zine-panel-holder {\n position: absolute;\n inset: 0 auto 0 0;\n z-index: 4;\n box-shadow: 0 0 24px light-dark(rgba(0, 0, 0, 0.22), rgba(0, 0, 0, 0.55));\n }\n .zine-panel-wrap-overlay.zine-panel-wrap-rtl .zine-panel-holder { inset: 0 0 0 auto; }\n /* Opaque over the page it floats on, unlike a flanking rail that sits against empty margin. */\n .zine-panel-wrap-overlay .zine-panel {\n background: var(--zine-controls-bg, light-dark(#ffffff, #18181b));\n }\n /* A click-away layer over the book, so pressing the page behind the floating rail closes it the\n way tapping the scrim does on a narrow screen. Transparent here \u2014 the wide-screen rail only\n covers an edge, so there is no need to dim the page the reader is still looking at. It sits\n under the holder (z-index) so the rail's own rows still take their clicks. */\n .zine-panel-wrap-overlay .zine-panel-scrim {\n display: block;\n position: absolute;\n inset: 0;\n z-index: 3;\n background: transparent;\n }\n}\n@media (min-width: 641px) and (prefers-reduced-motion: no-preference) {\n .zine-panel-wrap-overlay .zine-panel-holder { animation: zine-drawer-in 180ms ease; }\n .zine-panel-wrap-overlay.zine-panel-wrap-rtl .zine-panel-holder { animation-name: zine-drawer-in-rtl; }\n}\n\n/* Narrow screen: no room to flank, so the rail becomes a drawer over the book and the scrim dims\n the page behind it. The wrap is position:relative, so the absolute holder and scrim below are\n measured against it \u2014 i.e. against the book's own box. */\n@media (max-width: 640px) {\n /* No flanking here \u2014 the rail and scrim both overlay absolutely \u2014 so drop the flex row entirely.\n As a plain block wrap the book keeps the exact box it had before a panel opened (its own width,\n margin and aspect-ratio height); a flex row would instead re-resolve the book's width and, with\n it, its aspect-derived height, enlarging the canvas and pushing the page down. */\n .zine-panel-wrap {\n display: block;\n }\n .zine-panel-holder {\n position: absolute;\n inset: 0 auto 0 0;\n z-index: 4;\n /* Cap the drawer so it never eats the whole book; its inline width still applies under this. */\n max-width: 80%;\n box-shadow: 0 0 24px light-dark(rgba(0, 0, 0, 0.3), rgba(0, 0, 0, 0.6));\n }\n /* RTL reads from the right, so the drawer enters from there. */\n .zine-panel-wrap-rtl .zine-panel-holder { inset: 0 0 0 auto; }\n /* Opaque over the page, unlike the wide-screen rail which can sit against empty margin. */\n .zine-panel {\n background: var(--zine-controls-bg, light-dark(#ffffff, #18181b));\n }\n .zine-panel-scrim {\n display: block;\n position: absolute;\n inset: 0;\n z-index: 3;\n background: rgba(0, 0, 0, 0.4);\n }\n}\n@media (max-width: 640px) and (prefers-reduced-motion: no-preference) {\n .zine-panel-holder { animation: zine-drawer-in 180ms ease; }\n .zine-panel-wrap-rtl .zine-panel-holder { animation-name: zine-drawer-in-rtl; }\n .zine-panel-scrim { animation: zine-scrim-in 180ms ease; }\n}\n@keyframes zine-drawer-in { from { transform: translateX(-100%); } to { transform: translateX(0); } }\n@keyframes zine-drawer-in-rtl { from { transform: translateX(100%); } to { transform: translateX(0); } }\n@keyframes zine-scrim-in { from { opacity: 0; } to { opacity: 1; } }\n\n.zine-thumbs { align-items: center; }\n\n.zine-thumbs-row {\n display: flex;\n flex-wrap: wrap;\n justify-content: center;\n gap: 2px;\n width: 100%;\n padding: 4px;\n border: 0;\n border-radius: 6px;\n background: transparent;\n color: inherit;\n font: inherit;\n cursor: pointer;\n box-sizing: border-box;\n}\n.zine-thumbs-row:hover { background: var(--zine-controls-hover, light-dark(rgba(0,0,0,0.08), rgba(255,255,255,0.14))); }\n.zine-thumbs-row:focus-visible {\n outline: 2px solid var(--zine-controls-accent, light-dark(#0284c7, #7dd3fc));\n outline-offset: -2px;\n}\n.zine-thumbs-row.zine-panel-active .zine-thumbs-cell {\n outline: 1px solid var(--zine-controls-accent, light-dark(#0284c7, #7dd3fc));\n}\n\n/* Outline: a single column of headings, indented by depth. */\n/* No gap: a hairline between rows is the separator instead, so a title that wraps to two lines\n still reads as one entry rather than blending into its neighbours. */\n.zine-outline { gap: 0; }\n.zine-outline-row {\n display: block;\n width: 100%;\n padding: 6px 8px;\n border: 0;\n border-bottom: 1px solid var(--zine-controls-divider, light-dark(rgba(0, 0, 0, 0.08), rgba(255, 255, 255, 0.1)));\n border-radius: 5px;\n background: transparent;\n color: inherit;\n font: inherit;\n text-align: left;\n line-height: 1.35;\n cursor: pointer;\n box-sizing: border-box;\n overflow-wrap: anywhere;\n}\n.zine-outline-row:last-child { border-bottom: 0; }\n.zine-outline-row:hover:not(:disabled) {\n background: var(--zine-controls-hover, light-dark(rgba(0,0,0,0.08), rgba(255,255,255,0.14)));\n}\n.zine-outline-row:focus-visible {\n outline: 2px solid var(--zine-controls-accent, light-dark(#0284c7, #7dd3fc));\n outline-offset: -2px;\n}\n/* A heading whose destination could not be resolved: shown, but nothing to click through to. */\n.zine-outline-row:disabled { opacity: 0.5; cursor: default; }\n\n.zine-thumbs-cell {\n flex: 1 1 0;\n min-width: 0;\n min-height: 24px;\n display: flex;\n background: light-dark(rgba(0, 0, 0, 0.08), rgba(0, 0, 0, 0.3));\n border-radius: 2px;\n overflow: hidden;\n}\n/* A lone page in a book that pairs elsewhere (a cover, a back page) keeps one page's width and\n centres, instead of stretching across both columns. */\n.zine-thumbs-row-lone .zine-thumbs-cell { flex: 0 0 calc(50% - 1px); }\n.zine-thumbs-img { display: block; width: 100%; height: auto; }\n.zine-thumbs-caption { flex: 1 0 100%; text-align: center; opacity: 0.7; }\n\n/* Share dialog. Centred over the page rather than in the side rail: a QR and six destinations\n need more room than the rail gives, and sharing is a brief interruption, not a browsing mode. */\n.zine-share-backdrop {\n position: fixed;\n inset: 0;\n z-index: 2147483000;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 16px;\n background: rgba(0, 0, 0, 0.55);\n font: 500 13px/1.4 system-ui, sans-serif;\n color: var(--zine-controls-fg, light-dark(#18181b, #f4f4f5));\n}\n.zine-share {\n width: min(320px, 100%);\n max-height: 100%;\n overflow-y: auto;\n display: flex;\n flex-direction: column;\n gap: 12px;\n padding: 14px;\n border-radius: 12px;\n background: var(--zine-share-bg, light-dark(#ffffff, #1c1c20));\n box-shadow: 0 18px 50px rgba(0, 0, 0, 0.45);\n box-sizing: border-box;\n}\n.zine-share-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; }\n.zine-share-head strong { font-size: 15px; }\n.zine-share-close {\n display: inline-flex;\n width: 26px;\n height: 26px;\n align-items: center;\n justify-content: center;\n padding: 0;\n border: 0;\n border-radius: 6px;\n background: transparent;\n color: inherit;\n cursor: pointer;\n}\n.zine-share-close svg { width: 16px; height: 16px; }\n.zine-share-close:hover { background: var(--zine-controls-hover, light-dark(rgba(0,0,0,0.08), rgba(255,255,255,0.14))); }\n\n.zine-share-qr {\n align-self: center;\n line-height: 0;\n padding: 8px;\n border-radius: 8px;\n background: #fff;\n}\n.zine-share-qr svg { display: block; }\n\n.zine-share-link { display: flex; gap: 6px; }\n.zine-share-link input {\n flex: 1 1 auto;\n min-width: 0;\n padding: 7px 9px;\n border: 1px solid var(--zine-controls-hover, light-dark(rgba(0,0,0,0.14), rgba(255,255,255,0.2)));\n border-radius: 7px;\n background: light-dark(rgba(0, 0, 0, 0.05), rgba(0, 0, 0, 0.3));\n color: inherit;\n font: inherit;\n}\n.zine-share-copy {\n flex: 0 0 auto;\n min-width: 74px;\n padding: 7px 12px;\n border: 0;\n border-radius: 7px;\n background: var(--zine-controls-accent, light-dark(#0284c7, #7dd3fc));\n color: light-dark(#ffffff, #06202c);\n font: inherit;\n font-weight: 600;\n cursor: pointer;\n}\n\n.zine-share-socials { display: flex; flex-wrap: wrap; gap: 6px; justify-content: center; }\n.zine-share-social {\n display: inline-flex;\n width: 38px;\n height: 38px;\n align-items: center;\n justify-content: center;\n border-radius: 8px;\n background: light-dark(rgba(0, 0, 0, 0.06), rgba(255, 255, 255, 0.08));\n color: inherit;\n text-decoration: none;\n}\n.zine-share-social svg { width: 19px; height: 19px; }\n.zine-share-social:hover { background: var(--zine-controls-hover, light-dark(rgba(0,0,0,0.12), rgba(255,255,255,0.18))); }\n.zine-share-close:focus-visible,\n.zine-share-copy:focus-visible,\n.zine-share-social:focus-visible,\n.zine-share-link input:focus-visible {\n outline: 2px solid var(--zine-controls-accent, light-dark(#0284c7, #7dd3fc));\n outline-offset: 2px;\n}\n\n@media (prefers-reduced-motion: no-preference) {\n .zine-controls-btn { transition: background 120ms ease; }\n}\n";
|
|
1
|
+
export declare const CSS = "\n/* Docked mode wraps the book so the bar can sit beside it without shrinking the container,\n whose measured box the renderer and hit-testing both depend on.\n The wrapper deliberately does not stretch or grow its children: the container keeps whatever\n width, aspect-ratio and auto-margins the consumer's own CSS gave it. */\n.zine-controls-wrap { display: flex; }\n/* Stacked: children keep their own width (so a percentage or auto-margin still resolves against\n the wrapper) and take only the height they ask for. */\n.zine-controls-wrap-top,\n.zine-controls-wrap-bottom { flex-direction: column; align-items: stretch; }\n/* Side by side: the bar is only as wide as its buttons, and both are vertically centred. */\n.zine-controls-wrap-left,\n.zine-controls-wrap-right { flex-direction: row; align-items: center; }\n/* min-height:0 matters as much as min-width here. A flex item's automatic minimum size floors it\n at its content, so once the canvas has grown for a taller layout the book cannot shrink back \u2014\n its aspect-ratio is restored but ignored, leaving the extra height behind. */\n.zine-controls-wrap > * { flex: 0 0 auto; min-width: 0; min-height: 0; }\n\n.zine-controls {\n position: relative;\n display: flex;\n gap: 4px;\n padding: 5px;\n z-index: 2;\n box-sizing: border-box;\n font: 500 12px/1.2 system-ui, sans-serif;\n color: var(--zine-controls-fg, light-dark(#18181b, #f4f4f5));\n touch-action: auto;\n -webkit-user-select: none;\n user-select: none;\n}\n.zine-controls-docked { flex: 0 0 auto; justify-content: center; align-items: center; }\n.zine-controls-floating {\n position: absolute;\n /* Transparent to the book except on the buttons themselves, so gaps stay draggable. */\n pointer-events: none;\n}\n.zine-controls-bar {\n display: flex;\n align-items: center;\n gap: 1px;\n padding: 3px;\n border-radius: 8px;\n pointer-events: auto;\n background: var(--zine-controls-bg, light-dark(rgba(255, 255, 255, 0.94), rgba(24, 24, 27, 0.82)));\n backdrop-filter: blur(8px);\n}\n/* Floating: lifted off the page it covers. Docked: flat, with an outline so it reads as a\n control strip rather than a shadow hanging in empty space. */\n.zine-controls-floating .zine-controls-bar { box-shadow: 0 2px 12px rgba(0, 0, 0, 0.28); }\n.zine-controls-docked .zine-controls-bar {\n border: 1px solid var(--zine-controls-hover, light-dark(rgba(0, 0, 0, 0.08), rgba(255, 255, 255, 0.14)));\n}\n.zine-controls-floating.zine-controls-bottom { inset: auto 0 0 0; justify-content: center; }\n.zine-controls-floating.zine-controls-top { inset: 0 0 auto 0; justify-content: center; }\n.zine-controls-floating.zine-controls-left { inset: 0 auto 0 0; align-items: center; }\n.zine-controls-floating.zine-controls-right { inset: 0 0 0 auto; align-items: center; }\n/* A bar on a vertical edge stacks its buttons, docked or floating. */\n.zine-controls-left .zine-controls-bar,\n.zine-controls-right .zine-controls-bar { flex-direction: column; }\n\n.zine-controls-btn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 26px;\n height: 26px;\n padding: 0;\n border: 0;\n border-radius: 6px;\n background: transparent;\n color: inherit;\n cursor: pointer;\n font: inherit;\n}\n.zine-controls-btn svg { width: 15px; height: 15px; }\n.zine-controls-btn:hover:not(:disabled) { background: var(--zine-controls-hover, light-dark(rgba(0,0,0,0.08), rgba(255,255,255,0.14))); }\n.zine-controls-btn:focus-visible {\n outline: 2px solid var(--zine-controls-accent, light-dark(#0284c7, #7dd3fc));\n outline-offset: 1px;\n}\n.zine-controls-btn:disabled { opacity: 0.38; cursor: default; }\n/* A button mid-slow-action (fetching a file to save or print): a spinner, kept full-strength\n rather than dimmed so it reads as \"working\", not \"disabled\". */\n.zine-controls-btn.zine-controls-busy { opacity: 1; cursor: default; position: relative; }\n.zine-controls-btn.zine-controls-busy::after {\n content: '';\n box-sizing: border-box;\n width: 14px;\n height: 14px;\n border: 2px solid currentColor;\n border-top-color: transparent;\n border-radius: 50%;\n opacity: 0.7;\n animation: zine-controls-spin 0.7s linear infinite;\n}\n/* Icon-only bar button: hide the glyph and center the spinner over its place. */\n.zine-controls-btn.zine-controls-busy > svg { visibility: hidden; }\n.zine-controls-btn.zine-controls-busy::after {\n position: absolute;\n top: 50%;\n left: 50%;\n margin: -7px 0 0 -7px;\n}\n/* Menu item (glyph + label): let the glyph and label stand, and trail the spinner after them. */\n.zine-controls-menu .zine-controls-btn.zine-controls-busy > svg { visibility: visible; }\n.zine-controls-menu .zine-controls-btn.zine-controls-busy::after { position: static; }\n@keyframes zine-controls-spin { to { transform: rotate(360deg); } }\n@media (prefers-reduced-motion: reduce) {\n .zine-controls-btn.zine-controls-busy::after { animation-duration: 1.6s; }\n}\n/* A custom widget cannot always be disabled itself, so it is marked instead and reads the same. */\n.zine-controls-off { opacity: 0.38; }\n.zine-controls-off[aria-disabled='true'] { pointer-events: none; }\n.zine-controls-btn[aria-pressed=\"true\"],\n.zine-controls-btn[aria-expanded=\"true\"] { background: var(--zine-controls-hover, light-dark(rgba(0,0,0,0.08), rgba(255,255,255,0.14))); }\n\n.zine-controls-sep {\n width: 1px;\n align-self: stretch;\n margin: 3px 3px;\n background: currentColor;\n opacity: 0.22;\n}\n.zine-controls-left .zine-controls-sep,\n.zine-controls-right .zine-controls-sep { width: auto; height: 1px; margin: 3px 3px; }\n\n.zine-controls-page {\n display: inline-flex;\n align-items: center;\n gap: 3px;\n padding: 0 3px;\n pointer-events: auto;\n white-space: nowrap;\n}\n.zine-controls-page input {\n width: 2.2em;\n padding: 2px 3px;\n border: 1px solid var(--zine-controls-hover, light-dark(rgba(0,0,0,0.14), rgba(255,255,255,0.2)));\n border-radius: 4px;\n background: light-dark(rgba(0, 0, 0, 0.05), rgba(0, 0, 0, 0.25));\n color: inherit;\n font: inherit;\n text-align: center;\n -moz-appearance: textfield;\n}\n.zine-controls-page input::-webkit-outer-spin-button,\n.zine-controls-page input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }\n.zine-controls-page input:focus-visible {\n outline: 2px solid var(--zine-controls-accent, light-dark(#0284c7, #7dd3fc));\n outline-offset: 0;\n}\n\n.zine-controls-menu {\n position: absolute;\n display: flex;\n flex-direction: column;\n gap: 1px;\n min-width: 152px;\n padding: 4px;\n border-radius: 8px;\n pointer-events: auto;\n background: var(--zine-controls-bg, light-dark(rgba(255, 255, 255, 0.94), rgba(24, 24, 27, 0.94)));\n box-shadow: 0 6px 22px rgba(0, 0, 0, 0.36);\n backdrop-filter: blur(8px);\n}\n.zine-controls-menu .zine-controls-btn {\n width: 100%;\n height: auto;\n gap: 8px;\n padding: 6px 8px;\n justify-content: flex-start;\n}\n\n/* Search shares the rail: a query field pinned at the top over a scrolling list of hits. */\n.zine-search { gap: 0; overflow: hidden; }\n.zine-search-input {\n flex: 0 0 auto;\n width: 100%;\n padding: 6px 8px;\n border: 1px solid var(--zine-controls-hover, light-dark(rgba(0,0,0,0.14), rgba(255,255,255,0.2)));\n border-radius: 6px;\n background: light-dark(rgba(0, 0, 0, 0.05), rgba(0, 0, 0, 0.25));\n color: inherit;\n font: inherit;\n box-sizing: border-box;\n}\n/* Replace the browser's default (white) focus ring with the accent ring the other controls use. */\n.zine-search-input:focus-visible {\n outline: none;\n border-color: var(--zine-controls-accent, light-dark(#0284c7, #7dd3fc));\n box-shadow: 0 0 0 1px var(--zine-controls-accent, light-dark(#0284c7, #7dd3fc));\n}\n.zine-search-hits {\n flex: 1 1 auto;\n overflow-y: auto;\n /* Chain overscroll up to the page: once the list is at its end (or too short to scroll at all),\n a further wheel scrolls the page behind, the same as scrolling over the book itself does. */\n overscroll-behavior: auto;\n margin-top: 5px;\n scrollbar-width: thin;\n}\n.zine-search-hit {\n display: block;\n width: 100%;\n padding: 6px 8px;\n border: 0;\n border-radius: 5px;\n background: transparent;\n color: inherit;\n font: inherit;\n text-align: left;\n cursor: pointer;\n box-sizing: border-box;\n}\n.zine-search-hit:hover { background: var(--zine-controls-hover, light-dark(rgba(0,0,0,0.08), rgba(255,255,255,0.14))); }\n.zine-search-hit:focus-visible {\n outline: 2px solid var(--zine-controls-accent, light-dark(#0284c7, #7dd3fc));\n outline-offset: -2px;\n}\n.zine-search-page { display: block; font-size: 0.9em; opacity: 0.85; }\n.zine-search-hit small {\n display: block;\n margin-top: 2px;\n opacity: 0.62;\n line-height: 1.35;\n overflow-wrap: anywhere;\n}\n\n/* Page-turn arrows flanking the book. Like the docked toolbar and the side panels, they sit\n outside the container so they never shrink the book or intercept its gestures. */\n.zine-arrows-wrap {\n display: flex;\n align-items: center;\n gap: 4px;\n min-width: 0;\n}\n.zine-arrows-wrap > *:not(.zine-arrow) { flex: 1 1 auto; min-width: 0; min-height: 0; }\n.zine-arrow {\n flex: 0 0 auto;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 44px;\n height: 44px;\n padding: 0;\n border: 0;\n background: none;\n /* Light on a light page, dark on a dark one. The shadow below carries the contrast. */\n color: var(--zine-controls-fg, light-dark(#f4f4f5, #18181b));\n cursor: pointer;\n -webkit-user-select: none;\n user-select: none;\n /* No grey tap box on touch; the :active tint below is the press feedback instead. */\n -webkit-tap-highlight-color: transparent;\n}\n.zine-arrow svg {\n width: 36px;\n height: 36px;\n stroke-width: 2.25;\n /* No backing disc, so a subtle offset shadow keeps the chevron from disappearing into a\n matching background. It contrasts the fill: a light chevron (light mode) casts a soft dark\n shadow, a dark chevron (dark mode) a soft light one, offset rather than a glowing halo. */\n filter: drop-shadow(0 1px 2px light-dark(rgba(0, 0, 0, 0.5), rgba(255, 255, 255, 0.35)));\n}\n/* Feedback intensifies the chevron toward its extreme (white in light mode, black in dark)\n rather than tinting it, so no new colour is introduced. Not tied to --zine-controls-fg: that\n sets the resting fill, and hover has to differ from it to read as feedback. :active clears on\n release, so tap and click feel the same; :hover is behind (hover: hover) so it never sticks on\n touch. */\n.zine-arrow:active:not(:disabled) { color: light-dark(#ffffff, #000000); }\n@media (hover: hover) {\n .zine-arrow:hover:not(:disabled) { color: light-dark(#ffffff, #000000); }\n}\n.zine-arrow:focus-visible {\n outline: 2px solid var(--zine-controls-accent, light-dark(#0284c7, #7dd3fc));\n outline-offset: 2px;\n border-radius: 8px;\n}\n/* Nothing to turn to: invisible, but still occupying its slot so the book does not slide across\n as the reader reaches a cover. */\n.zine-arrow-hidden { visibility: hidden; }\n/* Device-scoped arrows (controls.arrows: 'desktop' | 'mobile'). The split follows the same 640px\n breakpoint as the flank/overlay layouts below, so the arrows appear and disappear live as the\n window crosses it. */\n@media (max-width: 640px) {\n .zine-arrows-desktop > .zine-arrow { display: none; }\n}\n@media (min-width: 641px) {\n .zine-arrows-mobile > .zine-arrow { display: none; }\n}\n/* Too narrow to flank without squeezing the pages, so overlay the arrows on the book's edges\n instead. The wrap sits outside the container, so painting them over it leaves the container's\n measured box (which sizes the book and maps taps) untouched. */\n@media (max-width: 640px) {\n .zine-arrows-wrap { position: relative; }\n .zine-arrow {\n position: absolute;\n top: 50%;\n transform: translateY(-50%);\n z-index: 2;\n /* Sit back over the page so the reader can look at the book. */\n opacity: 0.7;\n }\n .zine-arrow:first-child { left: -2px; }\n .zine-arrow:last-child { right: -2px; }\n}\n@media (prefers-reduced-motion: no-preference) {\n .zine-arrow { transition: background 120ms ease; }\n}\n\n/* Side panels (thumbnails, outline, search). The rail wraps the book and its docked toolbar so it\n sits beside them as a flex sibling. On a wide screen the book shrinks to make room (below); on a\n narrow one the rail becomes a drawer over the book.\n align-items:flex-start, not stretch: the book sizes its height from its width through its own\n aspect-ratio, and that height is 'auto' from flex's point of view, so a stretch would override it\n and blow the book (and the rail matched to it) up to the flex line's cross size. Left as auto, the\n book keeps its aspect height and the holder alone stretches down to meet it (below). */\n.zine-panel-wrap { display: flex; align-items: flex-start; gap: 8px; position: relative; }\n\n/* The book-side slot (the bare container, or the docked-toolbar wrapper around it) yields space to\n the fixed-width rail instead of overflowing: flex-shrink lets it fall below its own width, and\n min-width:0 removes the automatic content floor that would otherwise stop it. The book only\n actually shrinks if its width is elastic (a %, max-width, or the demo's min(...) with a % term);\n a hard-coded pixel width has nothing for the % to resolve smaller against. */\n.zine-panel-wrap > *:not(.zine-panel-holder):not(.zine-panel-scrim) {\n flex: 0 1 auto;\n min-width: 0;\n}\n/* With a docked toolbar the book lives inside .zine-controls-wrap, whose children are pinned\n flex:0 0 auto (so the bar keeps its size). Inside a panel wrap the book child \u2014 everything but\n the bar itself \u2014 must instead be allowed to shrink, so left/right docking flanks like the rest.\n Top/bottom docking already shrinks through the container's own % width. */\n.zine-panel-wrap .zine-controls-wrap > *:not(.zine-controls) {\n flex: 0 1 auto;\n min-width: 0;\n min-height: 0;\n}\n@media (prefers-reduced-motion: no-preference) {\n .zine-panel-wrap > *:not(.zine-panel-holder):not(.zine-panel-scrim) {\n transition: flex-basis 160ms ease, width 160ms ease;\n }\n}\n\n/* The holder stretches to the book's height; the rail is absolutely positioned inside it so a\n long list scrolls rather than growing the row and running past the bottom of the book. */\n.zine-panel-holder {\n position: relative;\n flex: 0 0 auto;\n align-self: stretch;\n min-height: 0;\n}\n/* The scrim dims the book behind the narrow-screen drawer. It exists on every screen but only\n shows under the breakpoint below, so on a wide screen it takes no flex slot and never intercepts\n a click. */\n.zine-panel-scrim { display: none; }\n.zine-panel {\n position: absolute;\n inset: 0;\n display: flex;\n flex-direction: column;\n gap: 6px;\n overflow-y: auto;\n /* Chain overscroll up to the page: once the list is at its end (or too short to scroll at all),\n a further wheel scrolls the page behind, the same as scrolling over the book itself does. */\n overscroll-behavior: auto;\n /* Reserve the scrollbar's lane whether or not it is showing, so rows never sit under the bar\n and the close button (inset past this lane below) has a fixed edge to clear. */\n scrollbar-gutter: stable;\n padding: 6px;\n box-sizing: border-box;\n border-radius: 8px;\n background: var(--zine-controls-bg, light-dark(rgba(255, 255, 255, 0.94), rgba(24, 24, 27, 0.82)));\n color: var(--zine-controls-fg, light-dark(#18181b, #f4f4f5));\n font: 500 11px/1.2 system-ui, sans-serif;\n scrollbar-width: thin;\n touch-action: auto;\n -webkit-user-select: none;\n user-select: none;\n}\n/* The rail sits flush against the book's reading-start edge (left, or right in RTL), so its outer\n corners there would round away from that edge and leave a gap. Square them; keep the interior\n corners, which face the page, rounded. */\n.zine-panel { border-radius: 0 8px 8px 0; }\n.zine-panel-wrap-rtl .zine-panel { border-radius: 8px 0 0 8px; }\n/* Overlay fallback, used when the container has no parent to wrap. */\n.zine-panel-overlay { position: absolute; inset: 0 auto 0 0; z-index: 3; }\n.zine-panel-active { background: var(--zine-controls-hover, light-dark(rgba(0,0,0,0.08), rgba(255,255,255,0.18))); }\n.zine-panel-note { padding: 8px; opacity: 0.66; line-height: 1.4; }\n/* Discoverable dismiss, floated in the rail's trailing-top (interior) corner, away from the book.\n It sits in the holder above the scrolling list so the list scrolls under it. A translucent\n backdrop keeps the glyph legible over a thumbnail or a line of text. */\n.zine-panel-close {\n position: absolute;\n top: 6px;\n /* Inset past the reserved scrollbar gutter so the button never overlaps the bar. */\n right: 12px;\n z-index: 1;\n display: inline-flex;\n width: 24px;\n height: 24px;\n align-items: center;\n justify-content: center;\n padding: 0;\n border: 0;\n border-radius: 6px;\n /* Opaque so a light thumbnail underneath never shows through and dims the glyph. */\n background: light-dark(#f4f4f5, #27272a);\n color: inherit;\n cursor: pointer;\n}\n.zine-panel-close svg { width: 15px; height: 15px; }\n/* Opaque hover, not the translucent hover token: a see-through backdrop over a light thumbnail\n would wash the glyph out. Solid neutrals keep the X readable in both themes over anything. */\n.zine-panel-close:hover { background: light-dark(#e4e4e7, #3f3f46); }\n.zine-panel-close:focus-visible {\n outline: 2px solid var(--zine-controls-accent, light-dark(#0284c7, #7dd3fc));\n outline-offset: -2px;\n}\n.zine-panel-wrap-rtl .zine-panel-close { right: auto; left: 12px; }\n/* End the search field just before the close button rather than running under it, so the two sit\n side by side and the field's border reads cleanly. The button's inner edge is ~30px from the\n panel's content edge (24px wide, its right edge 6px in once the reserved scrollbar gutter is\n accounted for), so 30px leaves them flush with a hair of breathing room. width:auto lets the\n column's stretch fill the rest, so the margin shortens the field instead of overflowing 100%. */\n.zine-search .zine-search-input { width: auto; align-self: stretch; margin-right: 30px; }\n.zine-panel-wrap-rtl .zine-search .zine-search-input { margin-right: 0; margin-left: 30px; }\n\n/* Overlay panels (outline, search) on a wide screen: float over the book's start edge instead of\n flanking it, so the book never resizes. The wrap drops to a block, laying the book out exactly as\n it was before the panel opened; the holder sits absolute over it at full book height, with a\n shadow so it reads as lifted off the page. thumbnails is not overlaid \u2014 it stays a flex flank and\n shrinks the book only when the two will not otherwise both fit. */\n@media (min-width: 641px) {\n .zine-panel-wrap-overlay { display: block; }\n .zine-panel-wrap-overlay .zine-panel-holder {\n position: absolute;\n inset: 0 auto 0 0;\n z-index: 4;\n box-shadow: 0 0 24px light-dark(rgba(0, 0, 0, 0.22), rgba(0, 0, 0, 0.55));\n }\n .zine-panel-wrap-overlay.zine-panel-wrap-rtl .zine-panel-holder { inset: 0 0 0 auto; }\n /* Opaque over the page it floats on, unlike a flanking rail that sits against empty margin. */\n .zine-panel-wrap-overlay .zine-panel {\n background: var(--zine-controls-bg, light-dark(#ffffff, #18181b));\n }\n /* A click-away layer over the book, so pressing the page behind the floating rail closes it the\n way tapping the scrim does on a narrow screen. Transparent here \u2014 the wide-screen rail only\n covers an edge, so there is no need to dim the page the reader is still looking at. It sits\n under the holder (z-index) so the rail's own rows still take their clicks. */\n .zine-panel-wrap-overlay .zine-panel-scrim {\n display: block;\n position: absolute;\n inset: 0;\n z-index: 3;\n background: transparent;\n }\n}\n@media (min-width: 641px) and (prefers-reduced-motion: no-preference) {\n .zine-panel-wrap-overlay .zine-panel-holder { animation: zine-drawer-in 180ms ease; }\n .zine-panel-wrap-overlay.zine-panel-wrap-rtl .zine-panel-holder { animation-name: zine-drawer-in-rtl; }\n}\n\n/* Narrow screen: no room to flank, so the rail becomes a drawer over the book and the scrim dims\n the page behind it. The wrap is position:relative, so the absolute holder and scrim below are\n measured against it \u2014 i.e. against the book's own box. */\n@media (max-width: 640px) {\n /* No flanking here \u2014 the rail and scrim both overlay absolutely \u2014 so drop the flex row entirely.\n As a plain block wrap the book keeps the exact box it had before a panel opened (its own width,\n margin and aspect-ratio height); a flex row would instead re-resolve the book's width and, with\n it, its aspect-derived height, enlarging the canvas and pushing the page down. */\n .zine-panel-wrap {\n display: block;\n }\n .zine-panel-holder {\n position: absolute;\n inset: 0 auto 0 0;\n z-index: 4;\n /* Cap the drawer so it never eats the whole book; its inline width still applies under this. */\n max-width: 80%;\n box-shadow: 0 0 24px light-dark(rgba(0, 0, 0, 0.3), rgba(0, 0, 0, 0.6));\n }\n /* RTL reads from the right, so the drawer enters from there. */\n .zine-panel-wrap-rtl .zine-panel-holder { inset: 0 0 0 auto; }\n /* Opaque over the page, unlike the wide-screen rail which can sit against empty margin. */\n .zine-panel {\n background: var(--zine-controls-bg, light-dark(#ffffff, #18181b));\n }\n .zine-panel-scrim {\n display: block;\n position: absolute;\n inset: 0;\n z-index: 3;\n background: rgba(0, 0, 0, 0.4);\n }\n}\n@media (max-width: 640px) and (prefers-reduced-motion: no-preference) {\n .zine-panel-holder { animation: zine-drawer-in 180ms ease; }\n .zine-panel-wrap-rtl .zine-panel-holder { animation-name: zine-drawer-in-rtl; }\n .zine-panel-scrim { animation: zine-scrim-in 180ms ease; }\n}\n@keyframes zine-drawer-in { from { transform: translateX(-100%); } to { transform: translateX(0); } }\n@keyframes zine-drawer-in-rtl { from { transform: translateX(100%); } to { transform: translateX(0); } }\n@keyframes zine-scrim-in { from { opacity: 0; } to { opacity: 1; } }\n\n.zine-thumbs { align-items: center; }\n\n.zine-thumbs-row {\n display: flex;\n flex-wrap: wrap;\n justify-content: center;\n gap: 2px;\n width: 100%;\n padding: 4px;\n border: 0;\n border-radius: 6px;\n background: transparent;\n color: inherit;\n font: inherit;\n cursor: pointer;\n box-sizing: border-box;\n}\n.zine-thumbs-row:hover { background: var(--zine-controls-hover, light-dark(rgba(0,0,0,0.08), rgba(255,255,255,0.14))); }\n.zine-thumbs-row:focus-visible {\n outline: 2px solid var(--zine-controls-accent, light-dark(#0284c7, #7dd3fc));\n outline-offset: -2px;\n}\n.zine-thumbs-row.zine-panel-active .zine-thumbs-cell {\n outline: 1px solid var(--zine-controls-accent, light-dark(#0284c7, #7dd3fc));\n}\n\n/* Outline: a single column of headings, indented by depth. */\n/* No gap: a hairline between rows is the separator instead, so a title that wraps to two lines\n still reads as one entry rather than blending into its neighbours. */\n.zine-outline { gap: 0; }\n.zine-outline-row {\n display: block;\n width: 100%;\n padding: 6px 8px;\n border: 0;\n border-bottom: 1px solid var(--zine-controls-divider, light-dark(rgba(0, 0, 0, 0.08), rgba(255, 255, 255, 0.1)));\n border-radius: 5px;\n background: transparent;\n color: inherit;\n font: inherit;\n text-align: left;\n line-height: 1.35;\n cursor: pointer;\n box-sizing: border-box;\n overflow-wrap: anywhere;\n}\n.zine-outline-row:last-child { border-bottom: 0; }\n.zine-outline-row:hover:not(:disabled) {\n background: var(--zine-controls-hover, light-dark(rgba(0,0,0,0.08), rgba(255,255,255,0.14)));\n}\n.zine-outline-row:focus-visible {\n outline: 2px solid var(--zine-controls-accent, light-dark(#0284c7, #7dd3fc));\n outline-offset: -2px;\n}\n/* A heading whose destination could not be resolved: shown, but nothing to click through to. */\n.zine-outline-row:disabled { opacity: 0.5; cursor: default; }\n\n.zine-thumbs-cell {\n flex: 1 1 0;\n min-width: 0;\n min-height: 24px;\n display: flex;\n background: light-dark(rgba(0, 0, 0, 0.08), rgba(0, 0, 0, 0.3));\n border-radius: 2px;\n overflow: hidden;\n}\n/* A lone page in a book that pairs elsewhere (a cover, a back page) keeps one page's width and\n centres, instead of stretching across both columns. */\n.zine-thumbs-row-lone .zine-thumbs-cell { flex: 0 0 calc(50% - 1px); }\n.zine-thumbs-img { display: block; width: 100%; height: auto; }\n.zine-thumbs-caption { flex: 1 0 100%; text-align: center; opacity: 0.7; }\n\n/* Share dialog. Centred over the page rather than in the side rail: a QR and six destinations\n need more room than the rail gives, and sharing is a brief interruption, not a browsing mode. */\n.zine-share-backdrop {\n position: fixed;\n inset: 0;\n z-index: 2147483000;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 16px;\n background: rgba(0, 0, 0, 0.55);\n font: 500 13px/1.4 system-ui, sans-serif;\n color: var(--zine-controls-fg, light-dark(#18181b, #f4f4f5));\n}\n.zine-share {\n width: min(320px, 100%);\n max-height: 100%;\n overflow-y: auto;\n display: flex;\n flex-direction: column;\n gap: 12px;\n padding: 14px;\n border-radius: 12px;\n background: var(--zine-share-bg, light-dark(#ffffff, #1c1c20));\n box-shadow: 0 18px 50px rgba(0, 0, 0, 0.45);\n box-sizing: border-box;\n}\n.zine-share-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; }\n.zine-share-head strong { font-size: 15px; }\n.zine-share-close {\n display: inline-flex;\n width: 26px;\n height: 26px;\n align-items: center;\n justify-content: center;\n padding: 0;\n border: 0;\n border-radius: 6px;\n background: transparent;\n color: inherit;\n cursor: pointer;\n}\n.zine-share-close svg { width: 16px; height: 16px; }\n.zine-share-close:hover { background: var(--zine-controls-hover, light-dark(rgba(0,0,0,0.08), rgba(255,255,255,0.14))); }\n\n.zine-share-qr {\n align-self: center;\n line-height: 0;\n padding: 8px;\n border-radius: 8px;\n background: #fff;\n}\n.zine-share-qr svg { display: block; }\n\n.zine-share-link { display: flex; gap: 6px; }\n.zine-share-link input {\n flex: 1 1 auto;\n min-width: 0;\n padding: 7px 9px;\n border: 1px solid var(--zine-controls-hover, light-dark(rgba(0,0,0,0.14), rgba(255,255,255,0.2)));\n border-radius: 7px;\n background: light-dark(rgba(0, 0, 0, 0.05), rgba(0, 0, 0, 0.3));\n color: inherit;\n font: inherit;\n}\n.zine-share-copy {\n flex: 0 0 auto;\n min-width: 74px;\n padding: 7px 12px;\n border: 0;\n border-radius: 7px;\n background: var(--zine-controls-accent, light-dark(#0284c7, #7dd3fc));\n color: light-dark(#ffffff, #06202c);\n font: inherit;\n font-weight: 600;\n cursor: pointer;\n}\n\n.zine-share-socials { display: flex; flex-wrap: wrap; gap: 6px; justify-content: center; }\n.zine-share-social {\n display: inline-flex;\n width: 38px;\n height: 38px;\n align-items: center;\n justify-content: center;\n border-radius: 8px;\n background: light-dark(rgba(0, 0, 0, 0.06), rgba(255, 255, 255, 0.08));\n color: inherit;\n text-decoration: none;\n}\n.zine-share-social svg { width: 19px; height: 19px; }\n.zine-share-social:hover { background: var(--zine-controls-hover, light-dark(rgba(0,0,0,0.12), rgba(255,255,255,0.18))); }\n.zine-share-close:focus-visible,\n.zine-share-copy:focus-visible,\n.zine-share-social:focus-visible,\n.zine-share-link input:focus-visible {\n outline: 2px solid var(--zine-controls-accent, light-dark(#0284c7, #7dd3fc));\n outline-offset: 2px;\n}\n\n@media (prefers-reduced-motion: no-preference) {\n .zine-controls-btn { transition: background 120ms ease; }\n}\n";
|
|
2
2
|
/** Add the stylesheet to `doc` if it is not already there. */
|
|
3
3
|
export declare function ensureStyles(doc: Document): void;
|
|
4
4
|
/**
|
package/dist/controls/types.d.ts
CHANGED
|
@@ -35,8 +35,13 @@ export interface ControlDef {
|
|
|
35
35
|
readonly icon?: string | ((ctx: ControlContext) => string);
|
|
36
36
|
/** Nested controls. A control with children opens a submenu instead of acting. */
|
|
37
37
|
readonly children?: readonly ControlItem[];
|
|
38
|
-
/**
|
|
39
|
-
|
|
38
|
+
/**
|
|
39
|
+
* What the button does. Ignored when `children` is present. May return a promise: while it is
|
|
40
|
+
* pending the toolbar marks the button busy (a spinner, disabled) and — for a control in a
|
|
41
|
+
* submenu — holds the menu open until it settles, so a slow action (fetching a cross-origin file
|
|
42
|
+
* to download or print) shows progress rather than appearing to do nothing.
|
|
43
|
+
*/
|
|
44
|
+
action?(ctx: ControlContext): void | Promise<void>;
|
|
40
45
|
/** Build a custom element instead of a button — for inputs and other non-button widgets. */
|
|
41
46
|
render?(ctx: ControlContext): HTMLElement;
|
|
42
47
|
/**
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { i as e, n as t, t as n } from "./registry-5nuYFMd4.js";
|
|
2
|
-
import { i as r, n as i, r as a, t as o } from "./styles-
|
|
2
|
+
import { i as r, n as i, r as a, t as o } from "./styles-B8fFoYm_.js";
|
|
3
3
|
//#region src/controls/builtins.ts
|
|
4
4
|
var s = Math.SQRT2, c = (e) => e.zine.container.ownerDocument?.fullscreenElement === e.zine.container;
|
|
5
5
|
function l() {
|
|
@@ -60,7 +60,7 @@ function l() {
|
|
|
60
60
|
title: "Share",
|
|
61
61
|
icon: a.share,
|
|
62
62
|
action: (e) => {
|
|
63
|
-
e.close(), import("./share-
|
|
63
|
+
e.close(), import("./share-WXdscwp3.js").then(({ ShareDialog: t }) => new t(e.zine, e.zine.container, e.colorScheme)).catch(() => {
|
|
64
64
|
navigator.clipboard?.writeText(e.zine.pageLink()).catch(() => {});
|
|
65
65
|
});
|
|
66
66
|
}
|
|
@@ -69,8 +69,8 @@ function l() {
|
|
|
69
69
|
title: "Download PDF",
|
|
70
70
|
icon: a.download,
|
|
71
71
|
isVisible: (e) => e.zine.canDownload(),
|
|
72
|
-
action: (e) => {
|
|
73
|
-
e.zine.download(), e.close();
|
|
72
|
+
action: async (e) => {
|
|
73
|
+
await e.zine.download(), e.close();
|
|
74
74
|
}
|
|
75
75
|
}), t({
|
|
76
76
|
id: "spread",
|
|
@@ -85,8 +85,8 @@ function l() {
|
|
|
85
85
|
title: "Print",
|
|
86
86
|
icon: a.print,
|
|
87
87
|
isVisible: (e) => e.zine.canPrint(),
|
|
88
|
-
action: (e) => {
|
|
89
|
-
e.zine.print(), e.close();
|
|
88
|
+
action: async (e) => {
|
|
89
|
+
await e.zine.print(), e.close();
|
|
90
90
|
}
|
|
91
91
|
}), t({
|
|
92
92
|
id: "menu",
|
|
@@ -264,10 +264,11 @@ var u = class {
|
|
|
264
264
|
#n;
|
|
265
265
|
#r = [];
|
|
266
266
|
#i = [];
|
|
267
|
+
#a;
|
|
267
268
|
constructor(e, t, n = {}) {
|
|
268
269
|
this.#e = e;
|
|
269
270
|
let r = t.ownerDocument;
|
|
270
|
-
this.#t = r, this.#n = new u(r, t, {
|
|
271
|
+
this.#t = r, this.#a = n.onDismiss, this.#n = new u(r, t, {
|
|
271
272
|
className: "zine-outline",
|
|
272
273
|
label: "Outline",
|
|
273
274
|
width: p,
|
|
@@ -275,37 +276,39 @@ var u = class {
|
|
|
275
276
|
rtl: e.getDirection() === "rtl",
|
|
276
277
|
overlay: !0,
|
|
277
278
|
pageBox: () => e.getPageBox()
|
|
278
|
-
}), this.root = this.#n.root, this.#
|
|
279
|
+
}), this.root = this.#n.root, this.#o("Loading…"), this.#s(), this.#i.push(e.on("pageChanged", () => this.#l()));
|
|
279
280
|
}
|
|
280
|
-
#
|
|
281
|
+
#o(e) {
|
|
281
282
|
let t = this.#t.createElement("div");
|
|
282
283
|
t.className = "zine-panel-note", t.textContent = e, this.#n.root.replaceChildren(t);
|
|
283
284
|
}
|
|
284
|
-
async #
|
|
285
|
+
async #s() {
|
|
285
286
|
let e = await this.#e.getOutline();
|
|
286
287
|
if (this.#n.root.isConnected) {
|
|
287
288
|
if (e.length === 0) {
|
|
288
|
-
this.#
|
|
289
|
+
this.#o("This document has no outline.");
|
|
289
290
|
return;
|
|
290
291
|
}
|
|
291
|
-
this.#n.root.replaceChildren(), this.#
|
|
292
|
+
this.#n.root.replaceChildren(), this.#c(e, 0), this.#l();
|
|
292
293
|
}
|
|
293
294
|
}
|
|
294
|
-
#
|
|
295
|
+
#c(e, t) {
|
|
295
296
|
for (let n of e) {
|
|
296
297
|
let e = this.#t.createElement("button");
|
|
297
298
|
if (e.type = "button", e.className = "zine-outline-row", e.setAttribute("role", "option"), e.style.paddingLeft = `${8 + t * m}px`, e.textContent = n.title, e.title = n.title, n.page === null) e.disabled = !0;
|
|
298
299
|
else {
|
|
299
300
|
let t = n.page;
|
|
300
|
-
e.setAttribute("aria-label", `${n.title}, page ${t + 1}`), e.addEventListener("click", () =>
|
|
301
|
+
e.setAttribute("aria-label", `${n.title}, page ${t + 1}`), e.addEventListener("click", () => {
|
|
302
|
+
this.#e.flipTo(t), this.#a?.();
|
|
303
|
+
}), this.#r.push({
|
|
301
304
|
el: e,
|
|
302
305
|
page: t
|
|
303
306
|
});
|
|
304
307
|
}
|
|
305
|
-
this.#n.root.appendChild(e), n.children.length > 0 && this.#
|
|
308
|
+
this.#n.root.appendChild(e), n.children.length > 0 && this.#c(n.children, t + 1);
|
|
306
309
|
}
|
|
307
310
|
}
|
|
308
|
-
#
|
|
311
|
+
#l() {
|
|
309
312
|
let e = this.#e.getPage(), t = null, n = -1;
|
|
310
313
|
for (let { el: r, page: i } of this.#r) r.classList.remove("zine-panel-active"), r.removeAttribute("aria-selected"), i <= e && i >= n && (t = r, n = i);
|
|
311
314
|
t && (t.classList.add("zine-panel-active"), t.setAttribute("aria-selected", "true"), t.scrollIntoView?.({ block: "nearest" }));
|
|
@@ -323,10 +326,11 @@ var u = class {
|
|
|
323
326
|
#i;
|
|
324
327
|
#a = 0;
|
|
325
328
|
#o = null;
|
|
329
|
+
#s;
|
|
326
330
|
constructor(e, t, n = {}) {
|
|
327
331
|
this.#e = e;
|
|
328
332
|
let r = t.ownerDocument;
|
|
329
|
-
this.#t = r, this.#n = new u(r, t, {
|
|
333
|
+
this.#t = r, this.#s = n.onDismiss, this.#n = new u(r, t, {
|
|
330
334
|
className: "zine-search",
|
|
331
335
|
label: "Search results",
|
|
332
336
|
width: g,
|
|
@@ -335,26 +339,26 @@ var u = class {
|
|
|
335
339
|
overlay: !0,
|
|
336
340
|
pageBox: () => e.getPageBox()
|
|
337
341
|
}), this.root = this.#n.root, this.#r = r.createElement("input"), this.#r.type = "search", this.#r.className = "zine-search-input", this.#r.placeholder = "Search…", this.#r.setAttribute("aria-label", "Search the document"), this.#r.addEventListener("input", () => {
|
|
338
|
-
this.#o && clearTimeout(this.#o), this.#o = setTimeout(() => void this.#
|
|
342
|
+
this.#o && clearTimeout(this.#o), this.#o = setTimeout(() => void this.#l(), _);
|
|
339
343
|
}), this.#r.addEventListener("keydown", (e) => {
|
|
340
|
-
e.key === "Enter" && (this.#o && clearTimeout(this.#o), this.#
|
|
344
|
+
e.key === "Enter" && (this.#o && clearTimeout(this.#o), this.#l());
|
|
341
345
|
}), this.#i = r.createElement("div"), this.#i.className = "zine-search-hits", this.#n.root.append(this.#r, this.#i), this.#r.focus();
|
|
342
346
|
}
|
|
343
|
-
#
|
|
347
|
+
#c(e) {
|
|
344
348
|
let t = this.#t.createElement("div");
|
|
345
349
|
t.className = "zine-panel-note", t.textContent = e, this.#i.replaceChildren(t);
|
|
346
350
|
}
|
|
347
|
-
async #
|
|
351
|
+
async #l() {
|
|
348
352
|
let e = this.#r.value.trim(), t = ++this.#a;
|
|
349
353
|
if (e.length < v) {
|
|
350
354
|
this.#i.replaceChildren();
|
|
351
355
|
return;
|
|
352
356
|
}
|
|
353
|
-
this.#
|
|
357
|
+
this.#c("Searching…");
|
|
354
358
|
let n = await this.#e.search(e);
|
|
355
359
|
if (!(t !== this.#a || !this.#n.root.isConnected)) {
|
|
356
360
|
if (n.length === 0) {
|
|
357
|
-
this.#
|
|
361
|
+
this.#c(`No matches for “${e}”`);
|
|
358
362
|
return;
|
|
359
363
|
}
|
|
360
364
|
this.#i.replaceChildren(...n.map((e) => {
|
|
@@ -363,7 +367,9 @@ var u = class {
|
|
|
363
367
|
let n = this.#t.createElement("span");
|
|
364
368
|
n.className = "zine-search-page", n.textContent = `Page ${e.page + 1}`;
|
|
365
369
|
let r = this.#t.createElement("small");
|
|
366
|
-
return r.textContent = e.excerpt, t.append(n, r), t.addEventListener("click", () =>
|
|
370
|
+
return r.textContent = e.excerpt, t.append(n, r), t.addEventListener("click", () => {
|
|
371
|
+
this.#e.flipTo(e.page), this.#s?.();
|
|
372
|
+
}), t;
|
|
367
373
|
}));
|
|
368
374
|
}
|
|
369
375
|
}
|
|
@@ -468,15 +474,15 @@ var u = class {
|
|
|
468
474
|
`zine-controls-${a}`,
|
|
469
475
|
s ? "zine-controls-docked" : "zine-controls-floating",
|
|
470
476
|
n.className
|
|
471
|
-
].filter(Boolean).join(" "), this.#n.setAttribute("role", "toolbar"), this.#n.setAttribute("aria-label", "Flipbook controls"), o(this.#n, this.#m), this.#r = r.createElement("div"), this.#r.className = "zine-controls-bar", this.#n.appendChild(this.#r), this.#n.addEventListener("keydown", (e) => this.#
|
|
477
|
+
].filter(Boolean).join(" "), this.#n.setAttribute("role", "toolbar"), this.#n.setAttribute("aria-label", "Flipbook controls"), o(this.#n, this.#m), this.#r = r.createElement("div"), this.#r.className = "zine-controls-bar", this.#n.appendChild(this.#r), this.#n.addEventListener("keydown", (e) => this.#k(e));
|
|
472
478
|
for (let e of S) this.#n.addEventListener(e, (e) => this.#_(e));
|
|
473
479
|
this.#g(t, a, s);
|
|
474
|
-
let c = () => this.#
|
|
480
|
+
let c = () => this.#A();
|
|
475
481
|
this.#o.push(e.on("pageChanged", c)), this.#o.push(e.on("zoomChanged", c)), this.#o.push(e.on("flipEnd", c));
|
|
476
482
|
let l = (e) => {
|
|
477
483
|
if (!this.#a) return;
|
|
478
484
|
let t = e.target;
|
|
479
|
-
this.#a.el.contains(t) || this.#a.trigger.contains(t) || this.#
|
|
485
|
+
this.#a.el.contains(t) || this.#a.trigger.contains(t) || this.#O();
|
|
480
486
|
};
|
|
481
487
|
r.addEventListener("pointerdown", l, !0), this.#o.push(() => r.removeEventListener("pointerdown", l, !0));
|
|
482
488
|
}
|
|
@@ -496,18 +502,18 @@ var u = class {
|
|
|
496
502
|
mount(e) {
|
|
497
503
|
this.#y(e.items ?? n);
|
|
498
504
|
let t = e.arrows ?? !0;
|
|
499
|
-
t !== !1 && (this.#p = new b(this.#e, this.#l, this.#m, t === !0 ? null : t)), this.#
|
|
505
|
+
t !== !1 && (this.#p = new b(this.#e, this.#l, this.#m, t === !0 ? null : t)), this.#A(), this.#N();
|
|
500
506
|
}
|
|
501
507
|
destroy() {
|
|
502
508
|
for (let e of this.#o) e();
|
|
503
|
-
this.#o = [], this.#
|
|
509
|
+
this.#o = [], this.#O(), this.#u?.destroy(), this.#u = null, this.#d = null, this.#n.remove();
|
|
504
510
|
let e = this.#c;
|
|
505
511
|
e?.parentNode && (e.parentNode.insertBefore(e.firstChild, e), e.remove()), this.#c = null, this.#p?.destroy(), this.#p = null;
|
|
506
512
|
}
|
|
507
513
|
#_(e) {
|
|
508
514
|
e.stopPropagation();
|
|
509
515
|
}
|
|
510
|
-
#v(e = () => this.#
|
|
516
|
+
#v(e = () => this.#O()) {
|
|
511
517
|
return {
|
|
512
518
|
zine: this.#e,
|
|
513
519
|
close: e,
|
|
@@ -546,16 +552,22 @@ var u = class {
|
|
|
546
552
|
}), i;
|
|
547
553
|
}
|
|
548
554
|
#C(e, t) {
|
|
549
|
-
if (
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
}
|
|
554
|
-
e.action?.(this.#v()), this.#k();
|
|
555
|
+
if (e.isDisabled?.(this.#v())) return;
|
|
556
|
+
if (e.children) {
|
|
557
|
+
this.#a?.trigger === t ? this.#O() : this.#T(e, t);
|
|
558
|
+
return;
|
|
555
559
|
}
|
|
560
|
+
if (t.classList.contains("zine-controls-busy")) return;
|
|
561
|
+
let n = e.action?.(this.#v());
|
|
562
|
+
n && typeof n.then == "function" && (this.#w(t, !0), n.finally(() => {
|
|
563
|
+
this.#w(t, !1), this.#A();
|
|
564
|
+
})), this.#A();
|
|
556
565
|
}
|
|
557
|
-
#w(
|
|
558
|
-
|
|
566
|
+
#w(e, t) {
|
|
567
|
+
e.classList.toggle("zine-controls-busy", t), e.setAttribute("aria-busy", String(t)), e.disabled = t;
|
|
568
|
+
}
|
|
569
|
+
#T(t, n) {
|
|
570
|
+
this.#O();
|
|
559
571
|
let r = this.#t.createElement("div");
|
|
560
572
|
r.className = "zine-controls-menu", r.setAttribute("role", "menu");
|
|
561
573
|
let i = this.#v();
|
|
@@ -569,15 +581,15 @@ var u = class {
|
|
|
569
581
|
def: t
|
|
570
582
|
})) : a = this.#S(t, "zine-controls-btn", !0), a.setAttribute("role", "menuitem"), r.appendChild(a);
|
|
571
583
|
}
|
|
572
|
-
this.#
|
|
584
|
+
this.#E(r, n), this.#A(), r.querySelector("button")?.focus();
|
|
573
585
|
}
|
|
574
|
-
#
|
|
586
|
+
#E(e, t) {
|
|
575
587
|
this.#n.appendChild(e), this.#a = {
|
|
576
588
|
el: e,
|
|
577
589
|
trigger: t
|
|
578
|
-
}, t.setAttribute("aria-expanded", "true"), this.#
|
|
590
|
+
}, t.setAttribute("aria-expanded", "true"), this.#D(e, t);
|
|
579
591
|
}
|
|
580
|
-
#
|
|
592
|
+
#D(e, t) {
|
|
581
593
|
let n = this.#n.getBoundingClientRect(), r = t.getBoundingClientRect(), i = e.getBoundingClientRect();
|
|
582
594
|
if (!n.width || !i.width) return;
|
|
583
595
|
let a = r.left - n.left + r.width / 2 - i.width / 2;
|
|
@@ -585,15 +597,15 @@ var u = class {
|
|
|
585
597
|
let o = r.bottom - n.top + 6, s = r.top - n.top - i.height - 6;
|
|
586
598
|
e.style.top = `${this.#h === "bottom" || s >= 0 ? s : o}px`;
|
|
587
599
|
}
|
|
588
|
-
#
|
|
600
|
+
#O() {
|
|
589
601
|
if (!this.#a) return;
|
|
590
602
|
let { el: e, trigger: t } = this.#a;
|
|
591
603
|
this.#a = null, t.removeAttribute("aria-expanded"), this.#i = this.#i.filter((t) => !e.contains(t.el)), e.remove(), this.#t.activeElement && e.contains(this.#t.activeElement) && t.focus();
|
|
592
604
|
}
|
|
593
|
-
#
|
|
605
|
+
#k(e) {
|
|
594
606
|
if (e.key === "Escape" && this.#a) {
|
|
595
607
|
let { trigger: t } = this.#a;
|
|
596
|
-
this.#
|
|
608
|
+
this.#O(), t.focus(), e.preventDefault();
|
|
597
609
|
return;
|
|
598
610
|
}
|
|
599
611
|
let t = [...this.#n.querySelectorAll("button, input")], n = t.indexOf(this.#t.activeElement);
|
|
@@ -601,14 +613,14 @@ var u = class {
|
|
|
601
613
|
let r = e.key === "ArrowRight" || e.key === "ArrowDown" ? 1 : e.key === "ArrowLeft" || e.key === "ArrowUp" ? -1 : 0;
|
|
602
614
|
r !== 0 && (t[(n + r + t.length) % t.length]?.focus(), e.preventDefault());
|
|
603
615
|
}
|
|
604
|
-
#
|
|
616
|
+
#A() {
|
|
605
617
|
let e = this.#v();
|
|
606
618
|
for (let { el: t, def: n } of this.#i) {
|
|
607
|
-
let i = n.children ? this.#
|
|
619
|
+
let i = n.children ? this.#M(n, e) : n.isVisible?.(e);
|
|
608
620
|
i !== void 0 && (t.style.display = i ? "" : "none");
|
|
609
|
-
let a = n.isDisabled?.(e) ?? !1;
|
|
610
|
-
for (let e of this.#
|
|
611
|
-
if (this.#
|
|
621
|
+
let a = t.classList.contains("zine-controls-busy"), o = (n.isDisabled?.(e) ?? !1) || a;
|
|
622
|
+
for (let e of this.#j(t)) e.disabled = o;
|
|
623
|
+
if (this.#j(t).length || t.setAttribute("aria-disabled", String(o)), t.classList.toggle("zine-controls-off", o), n.isActive && t.setAttribute("aria-pressed", String(n.isActive(e))), typeof n.title == "function") {
|
|
612
624
|
let r = n.title(e);
|
|
613
625
|
t.title = r, t.setAttribute("aria-label", r);
|
|
614
626
|
let i = t.querySelector(".zine-controls-label");
|
|
@@ -618,10 +630,10 @@ var u = class {
|
|
|
618
630
|
}
|
|
619
631
|
this.#s && this.#t.activeElement !== this.#s && (this.#s.value = String(this.#e.getPage() + 1));
|
|
620
632
|
}
|
|
621
|
-
#
|
|
633
|
+
#j(e) {
|
|
622
634
|
return e instanceof HTMLButtonElement || e instanceof HTMLInputElement ? [e] : [...e.querySelectorAll("button, input")];
|
|
623
635
|
}
|
|
624
|
-
#
|
|
636
|
+
#M(t, n) {
|
|
625
637
|
return t.isVisible && !t.isVisible(n) ? !1 : (t.children ?? []).some((t) => {
|
|
626
638
|
if (t === "|") return !1;
|
|
627
639
|
let r = e(t);
|
|
@@ -653,20 +665,20 @@ var u = class {
|
|
|
653
665
|
hasOutline() {
|
|
654
666
|
return this.#f === !0;
|
|
655
667
|
}
|
|
656
|
-
#
|
|
668
|
+
#N() {
|
|
657
669
|
this.#f !== null || !this.#e.canOutline() || (this.#f = !1, this.#e.getOutline().then((e) => {
|
|
658
670
|
if (e.length === 0) return;
|
|
659
|
-
this.#f = !0, this.#
|
|
671
|
+
this.#f = !0, this.#A();
|
|
660
672
|
let t = this.#a;
|
|
661
673
|
if (t) {
|
|
662
674
|
let e = this.#i.find((e) => e.el === t.trigger)?.def;
|
|
663
|
-
this.#
|
|
675
|
+
this.#O(), e && this.#T(e, t.trigger);
|
|
664
676
|
}
|
|
665
677
|
}));
|
|
666
678
|
}
|
|
667
679
|
togglePanel(e) {
|
|
668
680
|
let t = this.#d;
|
|
669
|
-
this.#u?.destroy(), this.#u = null, this.#d = null, t !== e && (this.#u = new x[e](this.#e, this.#l, { onDismiss: () => this.togglePanel(e) }), o(this.#u.root, this.#m), this.#d = e), this.#
|
|
681
|
+
this.#u?.destroy(), this.#u = null, this.#d = null, t !== e && (this.#u = new x[e](this.#e, this.#l, { onDismiss: () => this.togglePanel(e) }), o(this.#u.root, this.#m), this.#d = e), this.#A();
|
|
670
682
|
}
|
|
671
683
|
};
|
|
672
684
|
function w(e) {
|
|
@@ -710,4 +722,4 @@ function T(e, t, n = {}) {
|
|
|
710
722
|
//#endregion
|
|
711
723
|
export { T as mountControls };
|
|
712
724
|
|
|
713
|
-
//# sourceMappingURL=controls-
|
|
725
|
+
//# sourceMappingURL=controls-DgEXR2zi.js.map
|