@michaelyagi/shoji 0.1.0-alpha.6

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.
Files changed (67) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +81 -0
  3. package/dist/esm/core/EventBus.d.ts +16 -0
  4. package/dist/esm/core/FocusTrap.d.ts +9 -0
  5. package/dist/esm/core/Gallery.d.ts +221 -0
  6. package/dist/esm/core/GestureController.d.ts +50 -0
  7. package/dist/esm/core/LiveRegion.d.ts +6 -0
  8. package/dist/esm/core/SlideManager.d.ts +83 -0
  9. package/dist/esm/core/bodyScrollLock.d.ts +2 -0
  10. package/dist/esm/core/dom.d.ts +27 -0
  11. package/dist/esm/core/icons.d.ts +6 -0
  12. package/dist/esm/core/index.d.ts +5 -0
  13. package/dist/esm/core/index.js +1966 -0
  14. package/dist/esm/core/index.js.map +1 -0
  15. package/dist/esm/core/plugin.d.ts +54 -0
  16. package/dist/esm/core/rotateFlipNormalize.d.ts +19 -0
  17. package/dist/esm/core/scan.d.ts +8 -0
  18. package/dist/esm/core/types.d.ts +268 -0
  19. package/dist/esm/core/zoomTransition.d.ts +33 -0
  20. package/dist/esm/gestures/GestureEngine.d.ts +78 -0
  21. package/dist/esm/index.css +475 -0
  22. package/dist/esm/index.d.ts +32 -0
  23. package/dist/esm/index.js +24 -0
  24. package/dist/esm/index.js.map +1 -0
  25. package/dist/esm/index2.css +22 -0
  26. package/dist/esm/index3.css +166 -0
  27. package/dist/esm/index4.css +27 -0
  28. package/dist/esm/plugins/activeThumbnail/index.d.ts +26 -0
  29. package/dist/esm/plugins/activeThumbnail/index.js +48 -0
  30. package/dist/esm/plugins/activeThumbnail/index.js.map +1 -0
  31. package/dist/esm/plugins/autoplay/icons.d.ts +3 -0
  32. package/dist/esm/plugins/autoplay/index.d.ts +17 -0
  33. package/dist/esm/plugins/autoplay/index.js +177 -0
  34. package/dist/esm/plugins/autoplay/index.js.map +1 -0
  35. package/dist/esm/plugins/fullscreen/icons.d.ts +3 -0
  36. package/dist/esm/plugins/fullscreen/index.d.ts +17 -0
  37. package/dist/esm/plugins/fullscreen/index.js +74 -0
  38. package/dist/esm/plugins/fullscreen/index.js.map +1 -0
  39. package/dist/esm/plugins/layout/index.d.ts +191 -0
  40. package/dist/esm/plugins/layout/index.js +746 -0
  41. package/dist/esm/plugins/layout/index.js.map +1 -0
  42. package/dist/esm/plugins/layout/justified.d.ts +68 -0
  43. package/dist/esm/plugins/layout/masonry.d.ts +92 -0
  44. package/dist/esm/plugins/rotateFlip/icons.d.ts +5 -0
  45. package/dist/esm/plugins/rotateFlip/index.d.ts +17 -0
  46. package/dist/esm/plugins/rotateFlip/index.js +138 -0
  47. package/dist/esm/plugins/rotateFlip/index.js.map +1 -0
  48. package/dist/esm/plugins/video/index.d.ts +13 -0
  49. package/dist/esm/plugins/video/index.js +95 -0
  50. package/dist/esm/plugins/video/index.js.map +1 -0
  51. package/dist/esm/plugins/video/youtube.d.ts +61 -0
  52. package/dist/esm/plugins/zoom/icons.d.ts +4 -0
  53. package/dist/esm/plugins/zoom/index.d.ts +30 -0
  54. package/dist/esm/plugins/zoom/index.js +274 -0
  55. package/dist/esm/plugins/zoom/index.js.map +1 -0
  56. package/dist/esm/plugins/zoom/zoomMath.d.ts +24 -0
  57. package/dist/esm/transitions/SlideTransition.d.ts +25 -0
  58. package/dist/esm/transitions/presets.d.ts +21 -0
  59. package/dist/esm/zoomTransition-bbKHpVpA.js +110 -0
  60. package/dist/esm/zoomTransition-bbKHpVpA.js.map +1 -0
  61. package/dist/shoji.css +690 -0
  62. package/dist/shoji.js +3605 -0
  63. package/dist/shoji.js.map +1 -0
  64. package/dist/shoji.min.css +1 -0
  65. package/dist/shoji.min.js +2 -0
  66. package/dist/shoji.min.js.map +1 -0
  67. package/package.json +77 -0
@@ -0,0 +1,191 @@
1
+ import { ShojiPlugin } from '../../core/plugin';
2
+ import { GalleryItem } from '../../core/types';
3
+ /**
4
+ * DESIGN.md §5 — `type: 'grid' | 'masonry' | 'justified'`; masonry supports
5
+ * both `orientation`s, `breakpoints` (§5.4), and `groupBy`/headings (§5.2;
6
+ * see that option's own doc comment for the v1 scope cuts vs. the full
7
+ * spec, including why `groupBy` itself is excluded from `orientation:
8
+ * 'horizontal'`). Deliberately still
9
+ * deferred: jump-free *prepend* coordination (§5.2's scroll-anchoring
10
+ * handoff needs the not-yet-built scroll plugin on the other end —
11
+ * prepending today triggers a full relayout, which can shift scroll
12
+ * position if content above the fold grew).
13
+ */
14
+ export interface LayoutOptions {
15
+ /** Default `'justified'`. */
16
+ type?: 'grid' | 'masonry' | 'justified';
17
+ gutter?: number | {
18
+ x: number;
19
+ y: number;
20
+ };
21
+ /**
22
+ * `type: 'grid'` only — every cell's shape, cropped to fit via
23
+ * `object-fit: cover`; default 1 (square). Deliberately *not* each
24
+ * photo's own aspect ratio: plain CSS grid sizes a row's height to its
25
+ * tallest cell, so per-item ratios leave a visible blank gap under every
26
+ * shorter tile sharing a row with a taller one. Masonry/justified are
27
+ * the two types that preserve true per-photo aspect ratios instead (via
28
+ * their own JS packing, which doesn't have this row-height problem).
29
+ */
30
+ aspectRatio?: number;
31
+ /**
32
+ * `type: 'masonry'` only. `'vertical'` (default): fixed-width columns,
33
+ * tiles stack top-to-bottom, ragged *bottom* edge. `'horizontal'`: fixed-
34
+ * height rows, tiles pack left-to-right, ragged *right* edge — the direct
35
+ * transpose. Both wrap/grow within the container and scroll vertically
36
+ * only, same as every other layout type; neither ever needs horizontal
37
+ * scroll. See `rowHeight` for `'horizontal'`'s one fixed input, and
38
+ * `justified` (a different `type` entirely) for the *opposite* tradeoff —
39
+ * width forced flush, height left to solve for.
40
+ */
41
+ orientation?: 'vertical' | 'horizontal';
42
+ columns?: number | 'auto';
43
+ columnWidth?: number;
44
+ minColumnWidth?: number;
45
+ maxColumnWidth?: number;
46
+ fill?: 'shortest' | 'ordered';
47
+ /** `type: 'justified'`, or `type: 'masonry', orientation: 'horizontal'`. For horizontal masonry this is the row's exact, fixed height (see `orientation`'s doc comment) — `minRowHeight`/`maxRowHeight` don't apply there, since nothing is solved/clamped, only for justified, where it's a *target* a solved-for height converges near. */
48
+ rowHeight?: number;
49
+ minRowHeight?: number;
50
+ maxRowHeight?: number;
51
+ lastRow?: 'justify' | 'left' | 'hide';
52
+ animate?: boolean;
53
+ /**
54
+ * Container-width → partial overrides, applied on top of the base options
55
+ * above whenever the container's current width is <= that key (the
56
+ * *narrowest* matching key wins if more than one applies). Re-evaluated on
57
+ * every relayout, so crossing a threshold while resizing takes effect
58
+ * live. Cannot override `type` or `orientation` — swapping the DOM
59
+ * structure/positioning strategy live is a bigger feature than a sizing
60
+ * tweak; use a media query + two `Shoji` instances if that's genuinely
61
+ * needed.
62
+ */
63
+ breakpoints?: Record<number, Omit<LayoutOptions, 'type' | 'orientation' | 'breakpoints'>>;
64
+ /**
65
+ * Derives a section key per item (e.g. a formatted date) — a heading is
66
+ * inserted whenever the key changes between consecutive items, real
67
+ * "Today / Yesterday / March 2024" (Google Photos-style) sectioning.
68
+ * Items must already be grouped consecutively; a key reappearing later
69
+ * after a different key started a new section anyway.
70
+ *
71
+ * Section boundaries behave differently per `type`: `grid`'s heading is a
72
+ * full-span (`grid-column: 1 / -1`) element, native CSS grid gives it its
73
+ * own row for free. `masonry`'s heading is a full-width blocking element
74
+ * too — each section is its own fresh column-packing pass, no two
75
+ * sections ever share visual space. `justified` is the odd one out, by
76
+ * design (this is the actual Google Photos behavior, not a simplified
77
+ * approximation of it): sections do **not** force a row break. Row
78
+ * *composition* ignores section boundaries entirely — one continuous
79
+ * `layoutJustified` pass packs every item regardless of section, so a
80
+ * section with too few items to reach a full row's target width (a
81
+ * single lone photo, say) shares that row with whatever comes right
82
+ * after it, instead of getting stretched into its own awkward
83
+ * almost-empty row. A heading only marks *where* a new section starts:
84
+ * a compact, inline label sized to its own content (not full width),
85
+ * positioned at the x-coordinate of the tile that starts its section,
86
+ * in a slim label-band above whichever row that tile landed on — more
87
+ * than one label can share the same band if more than one section
88
+ * happens to start within the same row (see `renderHeading`'s
89
+ * `{title, subtitle}` form for exactly this — that's what the reference
90
+ * behavior actually looks like).
91
+ *
92
+ * v1 scope cuts vs. DESIGN.md §5.2's full spec: (1) any items change
93
+ * while `groupBy` is set does a full relayout, same simplification
94
+ * justified's non-grouped path already makes for appends (§5.4) — the
95
+ * "merge across load boundaries" incremental optimization is deferred;
96
+ * (2) headings are always `<h2>`, not a configurable level; (3) not
97
+ * supported with `orientation: 'horizontal'` (warns, ignored) —
98
+ * DESIGN.md itself calls that pairing rare.
99
+ */
100
+ groupBy?: (item: GalleryItem) => string;
101
+ /**
102
+ * Customizes a heading's content; default renders the key as plain text.
103
+ * Three return shapes:
104
+ * - `string` — plain text (default behavior, just with custom content).
105
+ * - `HTMLElement` — full control, own tag/children; the plugin adds its
106
+ * own class/positioning on top of whatever's returned, nothing else.
107
+ * - `{ title: string; subtitle?: string }` — the built-in structured
108
+ * form (bold title + a smaller, muted `subtitle`, e.g. a date + a
109
+ * location) — the only form the plugin can apply automatic overflow
110
+ * handling to (see `headingOverflow`), since it owns the DOM structure
111
+ * (a raw `HTMLElement` is opaque to it, no safe way to guess what's
112
+ * droppable).
113
+ */
114
+ renderHeading?: (key: string, items: GalleryItem[]) => string | HTMLElement | {
115
+ title: string;
116
+ subtitle?: string;
117
+ };
118
+ /**
119
+ * `type: 'justified'` + the `{ title, subtitle }` structured heading
120
+ * form only — controls what happens when a compact label doesn't fit
121
+ * its available width (the gap until the next section's label sharing
122
+ * its row, or the container edge). Ignored otherwise: `grid`/`masonry`
123
+ * headings are full-width and this kind of squeeze can't happen there;
124
+ * a raw `renderHeading`-returned `HTMLElement`/`string` is left exactly
125
+ * as returned regardless, since the plugin has no safe way to guess
126
+ * what's droppable in an opaque element.
127
+ * - `'show'` (default) — always render the full title + subtitle, one
128
+ * line, however wide; a label can visually run past the next
129
+ * section's label or the container edge if the content is long
130
+ * enough. The simple, predictable default — nothing gets silently
131
+ * dropped or reflowed.
132
+ * - `'fit'` — never wraps a label's text. First the subtitle is dropped
133
+ * if title+subtitle together don't fit; if the title *alone* still
134
+ * doesn't fit next to whatever's sharing its row, that section is
135
+ * pushed to start a fresh row instead, giving its label the room it
136
+ * needs — row *composition* responds to label width, not just label
137
+ * content. Real Google Photos behavior; opt in when labels regularly
138
+ * need to share tight row space. The one unavoidable exception is a
139
+ * single label wider than the entire container even alone on its own
140
+ * row — there, nothing left to break onto, so the label is
141
+ * ellipsis-truncated (still one line, never wrapped, never
142
+ * overflowing).
143
+ * - `'wrap'` — the in-between: same continuous row-packing as `'show'`
144
+ * (row *composition* never reacts to label width, unlike `'fit'` — no
145
+ * section is ever pushed to a fresh row), but a label that doesn't fit
146
+ * its available width (same gap `'fit'` measures) wraps its own text
147
+ * onto additional lines instead of running past it. Height is capped
148
+ * at `maxRowHeight` (or its default, 360) — a label tall enough to hit
149
+ * that cap ellipsis-truncates its last visible line rather than
150
+ * growing the row further. Real Google Photos behavior for its date
151
+ * headers; pick this over `'fit'` when you'd rather a label take an
152
+ * extra line than shove a whole section onto its own row.
153
+ */
154
+ headingOverflow?: 'show' | 'fit' | 'wrap';
155
+ /**
156
+ * Pins the active section's heading via `position: sticky`. Only
157
+ * implemented for `type: 'grid'`, where headings sit in normal document
158
+ * flow — masonry/justified headings are absolutely positioned by JS (like
159
+ * their tiles), and `position: sticky` doesn't do anything meaningful
160
+ * layered onto an already explicitly-positioned element. Warns and is
161
+ * ignored for those two types.
162
+ */
163
+ stickyHeadings?: boolean;
164
+ /**
165
+ * When an item is missing `width`/`height`, measure its tile's own `<img>`
166
+ * once it loads (`naturalWidth`/`naturalHeight`) and correct that tile's
167
+ * aspect ratio in place, rather than leaving it at the permanent 4:3
168
+ * placeholder fallback. Default `true`.
169
+ *
170
+ * The *first* layout pass never waits on this — it always uses the 4:3
171
+ * placeholder immediately, same as before this option existed, so opening
172
+ * the gallery is never blocked on image loads (DESIGN.md §5.2's
173
+ * never-measure-mid-layout-pass rule still holds for that first pass).
174
+ * This only ever *corrects* a placeholder after the fact, once a real
175
+ * measurement lands — the same "async correction after an initial
176
+ * synchronous pass" pattern already used for a `containerWidth <= 0`
177
+ * container (§5.4) and the zoom transition's origin-rect race (§2.3b),
178
+ * extended to per-item dimensions. Multiple corrections landing close
179
+ * together (e.g. several cached images resolving in the same tick) are
180
+ * coalesced into one relayout via `requestAnimationFrame`, not one
181
+ * relayout per image.
182
+ *
183
+ * Effectively does automatically, for `thumb`/`poster`/`src`, what a host
184
+ * would otherwise have to do by hand before constructing the gallery
185
+ * (`new Image(); img.onload = () => ...`) — set `false` to keep the old
186
+ * behavior (permanent 4:3 fallback, no self-correction) if you'd rather
187
+ * guarantee zero extra relayouts under any circumstance.
188
+ */
189
+ autoMeasure?: boolean;
190
+ }
191
+ export declare const Layout: ShojiPlugin;