@gallerist/theme-default 0.3.2 → 0.3.3

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 (2) hide show
  1. package/package.json +1 -1
  2. package/src/base.css +181 -20
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gallerist/theme-default",
3
- "version": "0.3.2",
3
+ "version": "0.3.3",
4
4
  "description": "Default Gallerist theme — pure CSS, no JS dependency. Driven by --gallerist-* custom properties.",
5
5
  "license": "MIT",
6
6
  "sideEffects": [
package/src/base.css CHANGED
@@ -551,8 +551,10 @@
551
551
  padding: 8px;
552
552
  padding-inline-start: 0;
553
553
  }
554
- /* collapsing the rail puts its item stack away too (fullscreen, `t`, rail: 'hidden') */
555
- .gallerist[data-gallerist-rail="collapsed"] .gallerist-thumbs-aside {
554
+ /* collapsing the rail puts its item stack away too (fullscreen, `t`, rail: 'hidden'); a rail switched
555
+ to flat or index leaves the column hidden */
556
+ .gallerist[data-gallerist-rail="collapsed"] .gallerist-thumbs-aside,
557
+ .gallerist-thumbs-aside[hidden] {
556
558
  display: none;
557
559
  }
558
560
  .gallerist-thumb-item {
@@ -859,6 +861,89 @@
859
861
  pointer-events: none;
860
862
  }
861
863
 
864
+ /* ── the View menu (plugin-view): a dropdown under its bar tool ──────────────────── */
865
+ /* The plugin puts it in the viewer root (the toolbar strip scrolls, so it would clip it) and sets its
866
+ top / left under the button; it is as small as its choices, so it covers only the stage's top edge. */
867
+ .gallerist-view-menu {
868
+ position: absolute;
869
+ top: 0;
870
+ left: 0;
871
+ z-index: 10;
872
+ box-sizing: border-box;
873
+ min-width: 168px;
874
+ max-width: calc(100% - 16px);
875
+ overflow-y: auto;
876
+ padding: 4px;
877
+ border: 1px solid var(--gallerist-hairline);
878
+ border-radius: var(--gallerist-radius);
879
+ background: var(--gallerist-panel);
880
+ backdrop-filter: var(--gallerist-blur);
881
+ box-shadow: var(--gallerist-shadow);
882
+ color: var(--gallerist-fg);
883
+ font: 400 14px / 1.3 var(--gallerist-font);
884
+ }
885
+ .gallerist-view-group + .gallerist-view-group {
886
+ margin-block-start: 4px;
887
+ padding-block-start: 4px;
888
+ border-block-start: 1px solid var(--gallerist-hairline);
889
+ }
890
+ .gallerist-view-heading {
891
+ padding: 6px 10px 4px;
892
+ color: var(--gallerist-fg-muted);
893
+ font-size: 11px;
894
+ font-weight: 600;
895
+ letter-spacing: 0.06em;
896
+ text-transform: uppercase;
897
+ }
898
+ .gallerist-view-item {
899
+ display: flex;
900
+ align-items: center;
901
+ gap: 10px;
902
+ min-height: 36px;
903
+ padding-inline: 10px 14px;
904
+ border-radius: min(var(--gallerist-radius), 6px);
905
+ cursor: pointer;
906
+ user-select: none;
907
+ -webkit-user-select: none;
908
+ }
909
+ /* a radio mark: a ring, filled in the selection colour for the checked choice */
910
+ .gallerist-view-item::before {
911
+ content: "";
912
+ flex: none;
913
+ box-sizing: border-box;
914
+ width: 14px;
915
+ height: 14px;
916
+ border: 1.5px solid currentColor;
917
+ border-radius: 50%;
918
+ opacity: 0.6;
919
+ }
920
+ .gallerist-view-item[aria-checked="true"]::before {
921
+ border-color: var(--gallerist-selection);
922
+ background: radial-gradient(circle, var(--gallerist-selection) 0 3px, transparent 3.5px);
923
+ opacity: 1;
924
+ }
925
+ /* the pointer's item takes the tool hover fill, the keyboard's the focus ring: the two never look
926
+ alike (nor like the checked mark) when they are different items */
927
+ .gallerist-view-item:hover {
928
+ background: var(--gallerist-tool-hover-bg);
929
+ }
930
+ .gallerist-view-item:focus {
931
+ outline: none;
932
+ }
933
+ .gallerist-view-item:focus-visible {
934
+ outline: 2px solid var(--gallerist-focus);
935
+ outline-offset: -2px;
936
+ }
937
+ /* its button reads as held while the menu is open */
938
+ .gallerist-bar button[aria-expanded="true"] {
939
+ background: var(--gallerist-tool-hover-bg);
940
+ }
941
+ @media (pointer: coarse) {
942
+ .gallerist-view-item {
943
+ min-height: var(--gallerist-target);
944
+ }
945
+ }
946
+
862
947
  /* ── top bar: counter → title → tools → zoom reset → close ─────────────────────── */
863
948
  .gallerist-bar {
864
949
  grid-area: bar;
@@ -1659,13 +1744,34 @@
1659
1744
  .gallerist-caption {
1660
1745
  transition: opacity var(--gallerist-dur-gentle, 280ms) var(--gallerist-ease-out, ease);
1661
1746
  }
1662
- .gallerist[data-gallerist-idle] .gallerist-bar,
1663
- .gallerist[data-gallerist-idle] .gallerist-controls > button,
1664
- .gallerist[data-gallerist-idle] .gallerist-itemnav,
1665
- .gallerist[data-gallerist-idle] .gallerist-navigator,
1666
- .gallerist[data-gallerist-idle] .gallerist-caption {
1667
- opacity: 0;
1668
- pointer-events: none;
1747
+ /* except what has keyboard focus, and the band holding it (WCAG 2.4.7): a keyboard user who pauses
1748
+ on a control still sees where focus is. Without :has() and :focus-visible (iOS Safari before
1749
+ 15.4) all of it fades, as before; an unforgiving :not() there would drop the whole rule. The
1750
+ exemption sits in :where(), so the rule keeps the specificity host overrides were written for. */
1751
+ @supports not selector(:has(:focus-visible)) {
1752
+ .gallerist[data-gallerist-idle] .gallerist-bar,
1753
+ .gallerist[data-gallerist-idle] .gallerist-controls > button,
1754
+ .gallerist[data-gallerist-idle] .gallerist-itemnav,
1755
+ .gallerist[data-gallerist-idle] .gallerist-navigator,
1756
+ .gallerist[data-gallerist-idle] .gallerist-caption {
1757
+ opacity: 0;
1758
+ pointer-events: none;
1759
+ }
1760
+ }
1761
+ @supports selector(:has(:focus-visible)) {
1762
+ .gallerist[data-gallerist-idle] .gallerist-bar:where(:not(:focus-visible, :has(:focus-visible))),
1763
+ .gallerist[data-gallerist-idle]
1764
+ .gallerist-controls
1765
+ > button:where(:not(:focus-visible, :has(:focus-visible))),
1766
+ .gallerist[data-gallerist-idle]
1767
+ .gallerist-itemnav:where(:not(:focus-visible, :has(:focus-visible))),
1768
+ .gallerist[data-gallerist-idle]
1769
+ .gallerist-navigator:where(:not(:focus-visible, :has(:focus-visible))),
1770
+ .gallerist[data-gallerist-idle]
1771
+ .gallerist-caption:where(:not(:focus-visible, :has(:focus-visible))) {
1772
+ opacity: 0;
1773
+ pointer-events: none;
1774
+ }
1669
1775
  }
1670
1776
 
1671
1777
  /* ── a11y live region (visually hidden) ────────────────────────────────────── */
@@ -1747,10 +1853,20 @@
1747
1853
  pointer-events: none; /* a fading viewer must not take clicks meant for the page */
1748
1854
  }
1749
1855
 
1750
- /* immersive preset: chrome AND the rail fade together on idle (UX-E). */
1751
- .gallerist[data-gallerist-preset="immersive"][data-gallerist-idle] .gallerist-region-thumbnails {
1752
- opacity: 0;
1753
- pointer-events: none;
1856
+ /* immersive preset: chrome AND the rail fade together on idle (UX-E), unless focus is in it (as
1857
+ above: where :has() is unsupported it fades all the same). */
1858
+ @supports not selector(:has(:focus-visible)) {
1859
+ .gallerist[data-gallerist-preset="immersive"][data-gallerist-idle] .gallerist-region-thumbnails {
1860
+ opacity: 0;
1861
+ pointer-events: none;
1862
+ }
1863
+ }
1864
+ @supports selector(:has(:focus-visible)) {
1865
+ .gallerist[data-gallerist-preset="immersive"][data-gallerist-idle]
1866
+ .gallerist-region-thumbnails:where(:not(:has(:focus-visible))) {
1867
+ opacity: 0;
1868
+ pointer-events: none;
1869
+ }
1754
1870
  }
1755
1871
  .gallerist[data-gallerist-preset="immersive"] .gallerist-region-thumbnails {
1756
1872
  transition: opacity var(--gallerist-dur-gentle) var(--gallerist-ease-out);
@@ -1985,23 +2101,68 @@
1985
2101
 
1986
2102
  /* ── docked controls (`arrows: 'docked'`, the reviewer preset): nothing over the media ─────────
1987
2103
  Review needs every pixel, corners included. The group arrows sit in gutters the stage leaves at
1988
- its sides (none on touch, where swipes stand in for them). The item navigator is a grid item of
1989
- the root, the count over ↑ ↓: a header on the aside item column while that shows, else at the
1990
- end of the caption row, which makes room for it. While any group has several items it keeps its
1991
- room on a one-item group, so the stage and the item column hold still. Last in the file, so it
1992
- wins over the arrow layouts and the touch chip above. Where no row or column beside the stage is
1993
- free (immersive) it falls back to the stage's corner; the zoom minimap stays over the media (it
1994
- shows only while zoomed, and is the zoom tool itself). */
2104
+ its sides (on touch, where swipes stand in for them, only while one has keyboard focus). The
2105
+ item navigator is a grid item of the root, the count over ↑ ↓: a header on the aside item column
2106
+ while that shows, else at the end of the caption row, which makes room for it. While any group
2107
+ has several items it keeps its room on a one-item group, so the stage and the item column hold
2108
+ still. Last in the file, so it wins over the arrow layouts and the touch chip above. Where no row
2109
+ or column beside the stage is free (immersive) it falls back to the stage's corner; the zoom
2110
+ minimap stays over the media (it shows only while zoomed, and is the zoom tool itself). */
1995
2111
  .gallerist[data-gallerist-arrows="docked"]:has(.gallerist-prev) .gallerist-stage {
1996
2112
  inset-inline: calc(var(--gallerist-arrow-size) + 24px);
1997
2113
  }
1998
2114
  .gallerist[data-gallerist-arrows="docked"][data-gallerist-axis="vertical"] .gallerist-stage {
1999
2115
  inset-inline-start: 0; /* both group arrows stack at the inline end */
2000
2116
  }
2117
+ /* touch: the stage takes the full width. A keyboard or switch user on touch still reaches the
2118
+ arrows, which then come back beside the media, never over it: the stage makes room for them only
2119
+ while one has keyboard focus (:focus-visible; one focused by a script after a tap stays hidden,
2120
+ and takes no room), as much on each side, so letterboxed media holds still. Held sideways that is
2121
+ a gutter at each side (on a vertical group axis too, where a mouse gets only the end one);
2122
+ upright, where most photos and screenshots leave their spare room above and below, it is a band
2123
+ at the top and the bottom instead, the arrows in the bottom one (↑ in the top one on a vertical
2124
+ axis), 12px from either edge as in a gutter, which leaves the focus ring 8px clear; not in
2125
+ immersive, whose navigator has that corner. Sideways or upright is the screen's, not the
2126
+ viewer's: a container query would follow the viewer, but needs Safari 16. */
2001
2127
  @media (pointer: coarse) {
2002
2128
  .gallerist[data-gallerist-arrows="docked"]:has(.gallerist-prev) .gallerist-stage {
2003
2129
  inset-inline: 0;
2004
2130
  }
2131
+ .gallerist[data-gallerist-arrows="docked"]:has(
2132
+ .gallerist-controls > :is(.gallerist-prev, .gallerist-next):focus-visible
2133
+ )
2134
+ .gallerist-stage {
2135
+ inset-inline: calc(var(--gallerist-arrow-size) + 24px);
2136
+ }
2137
+ }
2138
+ @media (pointer: coarse) and (orientation: portrait) {
2139
+ .gallerist[data-gallerist-arrows="docked"]:not([data-gallerist-preset="immersive"]):has(
2140
+ .gallerist-controls > :is(.gallerist-prev, .gallerist-next):focus-visible
2141
+ )
2142
+ .gallerist-stage {
2143
+ inset: calc(var(--gallerist-arrow-size) + 24px) 0;
2144
+ }
2145
+ .gallerist[data-gallerist-arrows="docked"]:not([data-gallerist-preset="immersive"])
2146
+ .gallerist-controls
2147
+ > :is(.gallerist-prev, .gallerist-next):focus-visible {
2148
+ top: auto;
2149
+ bottom: 12px;
2150
+ transform: none;
2151
+ }
2152
+ .gallerist[data-gallerist-arrows="docked"][data-gallerist-axis="vertical"]:not(
2153
+ [data-gallerist-preset="immersive"]
2154
+ )
2155
+ .gallerist-controls
2156
+ > .gallerist-prev:focus-visible {
2157
+ top: 12px;
2158
+ bottom: auto;
2159
+ }
2160
+ }
2161
+ /* and above the zoom minimap, which can reach a gutter on a short stage */
2162
+ .gallerist[data-gallerist-arrows="docked"]
2163
+ .gallerist-controls
2164
+ > :is(.gallerist-prev, .gallerist-next):focus-visible {
2165
+ z-index: 5;
2005
2166
  }
2006
2167
  /* one group (and no linear walk): the group arrows have nowhere to go, so they and their gutters go */
2007
2168
  .gallerist[data-gallerist-arrows="docked"][data-gallerist-one-group]:not([data-gallerist-linear])