@dodlhuat/basix 1.2.2 → 1.2.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 (55) hide show
  1. package/README.md +42 -0
  2. package/css/lightbox.scss +272 -0
  3. package/css/style.css +263 -3
  4. package/css/style.css.map +1 -1
  5. package/css/style.scss +1 -0
  6. package/js/bottom-sheet.js +4 -3
  7. package/js/bottom-sheet.ts +5 -3
  8. package/js/calendar.js +9 -5
  9. package/js/calendar.ts +7 -2
  10. package/js/carousel.js +15 -11
  11. package/js/carousel.ts +16 -11
  12. package/js/chart.js +4 -4
  13. package/js/chart.ts +5 -3
  14. package/js/datepicker.js +11 -3
  15. package/js/datepicker.ts +13 -3
  16. package/js/docs-nav.js +1 -0
  17. package/js/editor.js +28 -20
  18. package/js/editor.ts +28 -20
  19. package/js/file-uploader.js +6 -10
  20. package/js/file-uploader.ts +7 -11
  21. package/js/flyout-menu.js +8 -2
  22. package/js/flyout-menu.ts +7 -2
  23. package/js/gallery.js +6 -13
  24. package/js/gallery.ts +8 -16
  25. package/js/group-picker.js +10 -7
  26. package/js/group-picker.ts +11 -7
  27. package/js/lightbox.js +277 -0
  28. package/js/lightbox.ts +331 -0
  29. package/js/modal.js +5 -4
  30. package/js/modal.ts +6 -4
  31. package/js/popover.js +4 -2
  32. package/js/popover.ts +4 -2
  33. package/js/push-menu.js +3 -2
  34. package/js/push-menu.ts +4 -2
  35. package/js/scrollbar.js +31 -23
  36. package/js/scrollbar.ts +36 -26
  37. package/js/select.js +23 -9
  38. package/js/select.ts +29 -11
  39. package/js/stepper.js +5 -1
  40. package/js/stepper.ts +6 -1
  41. package/js/table.js +8 -3
  42. package/js/table.ts +9 -3
  43. package/js/timepicker.js +20 -21
  44. package/js/timepicker.ts +23 -21
  45. package/js/toast.js +3 -7
  46. package/js/toast.ts +4 -8
  47. package/js/tooltip.js +13 -4
  48. package/js/tooltip.ts +16 -4
  49. package/js/tree.js +4 -0
  50. package/js/tree.ts +5 -0
  51. package/js/utils.js +29 -1
  52. package/js/utils.ts +36 -1
  53. package/js/virtual-dropdown.js +4 -8
  54. package/js/virtual-dropdown.ts +5 -9
  55. package/package.json +1 -1
package/README.md CHANGED
@@ -280,6 +280,48 @@ sheet.hide();
280
280
  sheet.snapTo('full');
281
281
  ```
282
282
 
283
+ ### Lightbox
284
+
285
+ The Lightbox component opens images in a fullscreen overlay with an optional gallery mode. Supports keyboard navigation (← →, Escape), touch swipe, click-to-zoom, adjacent image preloading, focus trap, and a static `bind()` method for declarative HTML wiring.
286
+
287
+ | Option | Type | Default | Description |
288
+ |---|---|---|---|
289
+ | `src` | string | — | Image URL for single-image mode |
290
+ | `alt` | string | — | Alt text for the image |
291
+ | `caption` | string | — | Optional caption below the image |
292
+ | `images` | LightboxImage[] | — | Array of `{ src, alt?, caption? }` for gallery mode |
293
+ | `startIndex` | number | `0` | Starting index when opening a gallery |
294
+ | `closeable` | boolean | `true` | Shows × button and enables backdrop/Escape dismissal |
295
+ | `onOpen` | function | — | Callback fired when the lightbox opens |
296
+ | `onClose` | function | — | Callback fired after the close animation completes |
297
+
298
+ ``` js
299
+ import { Lightbox } from '@dodlhuat/basix/js/lightbox.js';
300
+
301
+ // Single image
302
+ new Lightbox({ src: 'photo.jpg', alt: 'A landscape', caption: 'Taken at sunrise' }).show();
303
+
304
+ // Gallery
305
+ new Lightbox({
306
+ images: [
307
+ { src: 'photo1.jpg', alt: 'Photo 1', caption: 'Day one' },
308
+ { src: 'photo2.jpg', alt: 'Photo 2' },
309
+ ],
310
+ startIndex: 0,
311
+ onClose: () => console.log('closed'),
312
+ }).show();
313
+
314
+ // Declarative binding — groups elements by data-lightbox value into galleries
315
+ Lightbox.bind();
316
+ ```
317
+
318
+ ``` html
319
+ <!-- Declarative usage -->
320
+ <a href="full.jpg" data-lightbox="trip" data-lightbox-caption="Arrival day">
321
+ <img src="thumb.jpg" alt="Arrival" />
322
+ </a>
323
+ ```
324
+
283
325
  ### Tooltip
284
326
 
285
327
  The Tooltip component shows contextual information on hover.
@@ -0,0 +1,272 @@
1
+ @use "properties";
2
+ @use "parameters" as *;
3
+
4
+ .lightbox-wrapper {
5
+ position: fixed;
6
+ inset: 0;
7
+ z-index: 999;
8
+ pointer-events: none;
9
+ display: flex;
10
+ align-items: center;
11
+ justify-content: center;
12
+
13
+ &.is-visible {
14
+ pointer-events: auto;
15
+
16
+ .lightbox-background {
17
+ opacity: 1;
18
+ }
19
+
20
+ .lightbox {
21
+ opacity: 1;
22
+ transform: scale(1);
23
+ }
24
+
25
+ .lightbox-close,
26
+ .lightbox-prev,
27
+ .lightbox-next {
28
+ opacity: 1;
29
+ }
30
+ }
31
+ }
32
+
33
+ .lightbox-background {
34
+ position: absolute;
35
+ inset: 0;
36
+ background: rgba(0, 0, 0, 0.88);
37
+ opacity: 0;
38
+ backdrop-filter: blur(8px);
39
+ -webkit-backdrop-filter: blur(8px);
40
+ transition: opacity 0.3s ease;
41
+ }
42
+
43
+ .lightbox-close {
44
+ position: absolute;
45
+ top: $spacing;
46
+ right: $spacing;
47
+ z-index: 1002;
48
+ display: flex;
49
+ align-items: center;
50
+ justify-content: center;
51
+ width: 2.25rem;
52
+ height: 2.25rem;
53
+ border: none;
54
+ border-radius: 50%;
55
+ background: rgba(255, 255, 255, 0.12);
56
+ color: rgba(255, 255, 255, 0.8);
57
+ cursor: pointer;
58
+ opacity: 0;
59
+ transition: background 0.2s ease, color 0.2s ease, opacity 0.3s ease;
60
+ -webkit-tap-highlight-color: transparent;
61
+
62
+ .icon {
63
+ font-size: 1.25rem;
64
+ line-height: 1;
65
+ }
66
+
67
+ &:hover {
68
+ background: rgba(255, 255, 255, 0.22);
69
+ color: #fff;
70
+ }
71
+
72
+ &:focus-visible {
73
+ outline: 2px solid rgba(255, 255, 255, 0.6);
74
+ outline-offset: 2px;
75
+ }
76
+ }
77
+
78
+ .lightbox {
79
+ position: relative;
80
+ z-index: 1000;
81
+ display: flex;
82
+ flex-direction: column;
83
+ align-items: center;
84
+ max-width: min(90vw, 1280px);
85
+ opacity: 0;
86
+ transform: scale(0.97);
87
+ transition: opacity 0.25s ease, transform 0.25s ease;
88
+ }
89
+
90
+ .lightbox-img-wrap {
91
+ position: relative;
92
+ display: flex;
93
+ align-items: center;
94
+ justify-content: center;
95
+ max-width: 100%;
96
+ max-height: calc(90dvh - 3.5rem);
97
+ cursor: zoom-in;
98
+ border-radius: calc($border-radius * 2);
99
+ overflow: hidden;
100
+ background: rgba(255, 255, 255, 0.04);
101
+
102
+ &.is-loading {
103
+ min-width: 6rem;
104
+ min-height: 6rem;
105
+
106
+ .lightbox-img {
107
+ opacity: 0;
108
+ }
109
+
110
+ .lightbox-spinner {
111
+ display: flex;
112
+ }
113
+ }
114
+
115
+ &.is-error {
116
+ min-width: 14rem;
117
+ min-height: 8rem;
118
+ cursor: default;
119
+
120
+ .lightbox-img {
121
+ display: none;
122
+ }
123
+
124
+ .lightbox-spinner {
125
+ display: none;
126
+ }
127
+
128
+ &::after {
129
+ content: 'Failed to load image';
130
+ color: rgba(255, 255, 255, 0.4);
131
+ font-size: 0.875rem;
132
+ padding: $spacing * 2;
133
+ }
134
+ }
135
+
136
+ &.is-zoomed {
137
+ cursor: zoom-out;
138
+ overflow: auto;
139
+ max-height: 90dvh;
140
+ border-radius: 0;
141
+ }
142
+ }
143
+
144
+ .lightbox-spinner {
145
+ position: absolute;
146
+ inset: 0;
147
+ display: none;
148
+ align-items: center;
149
+ justify-content: center;
150
+ z-index: 1;
151
+
152
+ // Override spinner colors for the dark overlay
153
+ .spinner {
154
+ border-color: rgba(255, 255, 255, 0.15);
155
+ border-top-color: rgba(255, 255, 255, 0.7);
156
+ }
157
+ }
158
+
159
+ .lightbox-img {
160
+ display: block;
161
+ max-width: 100%;
162
+ max-height: calc(90dvh - 3.5rem);
163
+ object-fit: contain;
164
+ opacity: 0;
165
+ transition: opacity 0.25s ease;
166
+ border-radius: calc($border-radius * 2);
167
+ user-select: none;
168
+ -webkit-user-drag: none;
169
+
170
+ &.is-loaded {
171
+ opacity: 1;
172
+ }
173
+
174
+ &.is-zoomed {
175
+ max-width: none;
176
+ max-height: none;
177
+ border-radius: 0;
178
+ }
179
+ }
180
+
181
+ .lightbox-caption {
182
+ margin: calc($spacing * 0.6) 0 0;
183
+ color: rgba(255, 255, 255, 0.6);
184
+ font-size: 0.875rem;
185
+ text-align: center;
186
+ max-width: 60ch;
187
+ line-height: 1.5;
188
+ }
189
+
190
+ .lightbox-counter {
191
+ margin-top: calc($spacing * 0.5);
192
+ color: rgba(255, 255, 255, 0.4);
193
+ font-size: 0.75rem;
194
+ letter-spacing: 0.04em;
195
+ text-align: center;
196
+ user-select: none;
197
+ }
198
+
199
+ // Prev/Next buttons — glass pill, matches carousel style
200
+ .lightbox-prev,
201
+ .lightbox-next {
202
+ position: fixed;
203
+ top: 50%;
204
+ transform: translateY(-50%);
205
+ z-index: 1001;
206
+ display: flex;
207
+ align-items: center;
208
+ justify-content: center;
209
+ width: 2.5rem;
210
+ height: 2.5rem;
211
+ border: none;
212
+ border-radius: 50%;
213
+ background: rgba(0, 0, 0, 0.32);
214
+ backdrop-filter: blur(8px);
215
+ -webkit-backdrop-filter: blur(8px);
216
+ color: rgba(255, 255, 255, 0.92);
217
+ cursor: pointer;
218
+ opacity: 0;
219
+ transition: background 0.2s ease,
220
+ opacity 0.3s ease,
221
+ transform 0.2s ease;
222
+ -webkit-tap-highlight-color: transparent;
223
+
224
+ .icon {
225
+ font-size: 1.5rem;
226
+ line-height: 1;
227
+ }
228
+
229
+ &:hover {
230
+ background: rgba(0, 0, 0, 0.55);
231
+ }
232
+
233
+ &:active {
234
+ transform: translateY(-50%) scale(0.93);
235
+ }
236
+
237
+ &:focus-visible {
238
+ outline: 2px solid rgba(255, 255, 255, 0.6);
239
+ outline-offset: 2px;
240
+ }
241
+ }
242
+
243
+ .lightbox-prev { left: $spacing; }
244
+ .lightbox-next { right: $spacing; }
245
+
246
+ @media (max-width: 768px) {
247
+ .lightbox-prev,
248
+ .lightbox-next {
249
+ width: 2rem;
250
+ height: 2rem;
251
+
252
+ .icon { font-size: 1.25rem; }
253
+ }
254
+
255
+ .lightbox-prev { left: calc($spacing * 0.5); }
256
+ .lightbox-next { right: calc($spacing * 0.5); }
257
+
258
+ .lightbox {
259
+ max-width: 100vw;
260
+ }
261
+
262
+ .lightbox-img,
263
+ .lightbox-img-wrap {
264
+ max-height: 82dvh;
265
+ border-radius: $border-radius;
266
+ }
267
+
268
+ .lightbox-close {
269
+ top: calc($spacing * 0.75);
270
+ right: calc($spacing * 0.75);
271
+ }
272
+ }
package/css/style.css CHANGED
@@ -1844,6 +1844,260 @@ button.button-error:active:not(:disabled) {
1844
1844
  border-radius: 0;
1845
1845
  }
1846
1846
  }
1847
+ .lightbox-wrapper {
1848
+ position: fixed;
1849
+ inset: 0;
1850
+ z-index: 999;
1851
+ pointer-events: none;
1852
+ display: flex;
1853
+ align-items: center;
1854
+ justify-content: center;
1855
+ }
1856
+ .lightbox-wrapper.is-visible {
1857
+ pointer-events: auto;
1858
+ }
1859
+ .lightbox-wrapper.is-visible .lightbox-background {
1860
+ opacity: 1;
1861
+ }
1862
+ .lightbox-wrapper.is-visible .lightbox {
1863
+ opacity: 1;
1864
+ transform: scale(1);
1865
+ }
1866
+ .lightbox-wrapper.is-visible .lightbox-close,
1867
+ .lightbox-wrapper.is-visible .lightbox-prev,
1868
+ .lightbox-wrapper.is-visible .lightbox-next {
1869
+ opacity: 1;
1870
+ }
1871
+
1872
+ .lightbox-background {
1873
+ position: absolute;
1874
+ inset: 0;
1875
+ background: rgba(0, 0, 0, 0.88);
1876
+ opacity: 0;
1877
+ backdrop-filter: blur(8px);
1878
+ -webkit-backdrop-filter: blur(8px);
1879
+ transition: opacity 0.3s ease;
1880
+ }
1881
+
1882
+ .lightbox-close {
1883
+ position: absolute;
1884
+ top: 1rem;
1885
+ right: 1rem;
1886
+ z-index: 1002;
1887
+ display: flex;
1888
+ align-items: center;
1889
+ justify-content: center;
1890
+ width: 2.25rem;
1891
+ height: 2.25rem;
1892
+ border: none;
1893
+ border-radius: 50%;
1894
+ background: rgba(255, 255, 255, 0.12);
1895
+ color: rgba(255, 255, 255, 0.8);
1896
+ cursor: pointer;
1897
+ opacity: 0;
1898
+ transition: background 0.2s ease, color 0.2s ease, opacity 0.3s ease;
1899
+ -webkit-tap-highlight-color: transparent;
1900
+ }
1901
+ .lightbox-close .icon {
1902
+ font-size: 1.25rem;
1903
+ line-height: 1;
1904
+ }
1905
+ .lightbox-close:hover {
1906
+ background: rgba(255, 255, 255, 0.22);
1907
+ color: #fff;
1908
+ }
1909
+ .lightbox-close:focus-visible {
1910
+ outline: 2px solid rgba(255, 255, 255, 0.6);
1911
+ outline-offset: 2px;
1912
+ }
1913
+
1914
+ .lightbox {
1915
+ position: relative;
1916
+ z-index: 1000;
1917
+ display: flex;
1918
+ flex-direction: column;
1919
+ align-items: center;
1920
+ max-width: min(90vw, 1280px);
1921
+ opacity: 0;
1922
+ transform: scale(0.97);
1923
+ transition: opacity 0.25s ease, transform 0.25s ease;
1924
+ }
1925
+
1926
+ .lightbox-img-wrap {
1927
+ position: relative;
1928
+ display: flex;
1929
+ align-items: center;
1930
+ justify-content: center;
1931
+ max-width: 100%;
1932
+ max-height: calc(90dvh - 3.5rem);
1933
+ cursor: zoom-in;
1934
+ border-radius: 0.8rem;
1935
+ overflow: hidden;
1936
+ background: rgba(255, 255, 255, 0.04);
1937
+ }
1938
+ .lightbox-img-wrap.is-loading {
1939
+ min-width: 6rem;
1940
+ min-height: 6rem;
1941
+ }
1942
+ .lightbox-img-wrap.is-loading .lightbox-img {
1943
+ opacity: 0;
1944
+ }
1945
+ .lightbox-img-wrap.is-loading .lightbox-spinner {
1946
+ display: flex;
1947
+ }
1948
+ .lightbox-img-wrap.is-error {
1949
+ min-width: 14rem;
1950
+ min-height: 8rem;
1951
+ cursor: default;
1952
+ }
1953
+ .lightbox-img-wrap.is-error .lightbox-img {
1954
+ display: none;
1955
+ }
1956
+ .lightbox-img-wrap.is-error .lightbox-spinner {
1957
+ display: none;
1958
+ }
1959
+ .lightbox-img-wrap.is-error::after {
1960
+ content: "Failed to load image";
1961
+ color: rgba(255, 255, 255, 0.4);
1962
+ font-size: 0.875rem;
1963
+ padding: 2rem;
1964
+ }
1965
+ .lightbox-img-wrap.is-zoomed {
1966
+ cursor: zoom-out;
1967
+ overflow: auto;
1968
+ max-height: 90dvh;
1969
+ border-radius: 0;
1970
+ }
1971
+
1972
+ .lightbox-spinner {
1973
+ position: absolute;
1974
+ inset: 0;
1975
+ display: none;
1976
+ align-items: center;
1977
+ justify-content: center;
1978
+ z-index: 1;
1979
+ }
1980
+ .lightbox-spinner .spinner {
1981
+ border-color: rgba(255, 255, 255, 0.15);
1982
+ border-top-color: rgba(255, 255, 255, 0.7);
1983
+ }
1984
+
1985
+ .lightbox-img {
1986
+ display: block;
1987
+ max-width: 100%;
1988
+ max-height: calc(90dvh - 3.5rem);
1989
+ object-fit: contain;
1990
+ opacity: 0;
1991
+ transition: opacity 0.25s ease;
1992
+ border-radius: 0.8rem;
1993
+ user-select: none;
1994
+ -webkit-user-drag: none;
1995
+ }
1996
+ .lightbox-img.is-loaded {
1997
+ opacity: 1;
1998
+ }
1999
+ .lightbox-img.is-zoomed {
2000
+ max-width: none;
2001
+ max-height: none;
2002
+ border-radius: 0;
2003
+ }
2004
+
2005
+ .lightbox-caption {
2006
+ margin: 0.6rem 0 0;
2007
+ color: rgba(255, 255, 255, 0.6);
2008
+ font-size: 0.875rem;
2009
+ text-align: center;
2010
+ max-width: 60ch;
2011
+ line-height: 1.5;
2012
+ }
2013
+
2014
+ .lightbox-counter {
2015
+ margin-top: 0.5rem;
2016
+ color: rgba(255, 255, 255, 0.4);
2017
+ font-size: 0.75rem;
2018
+ letter-spacing: 0.04em;
2019
+ text-align: center;
2020
+ user-select: none;
2021
+ }
2022
+
2023
+ .lightbox-prev,
2024
+ .lightbox-next {
2025
+ position: fixed;
2026
+ top: 50%;
2027
+ transform: translateY(-50%);
2028
+ z-index: 1001;
2029
+ display: flex;
2030
+ align-items: center;
2031
+ justify-content: center;
2032
+ width: 2.5rem;
2033
+ height: 2.5rem;
2034
+ border: none;
2035
+ border-radius: 50%;
2036
+ background: rgba(0, 0, 0, 0.32);
2037
+ backdrop-filter: blur(8px);
2038
+ -webkit-backdrop-filter: blur(8px);
2039
+ color: rgba(255, 255, 255, 0.92);
2040
+ cursor: pointer;
2041
+ opacity: 0;
2042
+ transition: background 0.2s ease, opacity 0.3s ease, transform 0.2s ease;
2043
+ -webkit-tap-highlight-color: transparent;
2044
+ }
2045
+ .lightbox-prev .icon,
2046
+ .lightbox-next .icon {
2047
+ font-size: 1.5rem;
2048
+ line-height: 1;
2049
+ }
2050
+ .lightbox-prev:hover,
2051
+ .lightbox-next:hover {
2052
+ background: rgba(0, 0, 0, 0.55);
2053
+ }
2054
+ .lightbox-prev:active,
2055
+ .lightbox-next:active {
2056
+ transform: translateY(-50%) scale(0.93);
2057
+ }
2058
+ .lightbox-prev:focus-visible,
2059
+ .lightbox-next:focus-visible {
2060
+ outline: 2px solid rgba(255, 255, 255, 0.6);
2061
+ outline-offset: 2px;
2062
+ }
2063
+
2064
+ .lightbox-prev {
2065
+ left: 1rem;
2066
+ }
2067
+
2068
+ .lightbox-next {
2069
+ right: 1rem;
2070
+ }
2071
+
2072
+ @media (max-width: 768px) {
2073
+ .lightbox-prev,
2074
+ .lightbox-next {
2075
+ width: 2rem;
2076
+ height: 2rem;
2077
+ }
2078
+ .lightbox-prev .icon,
2079
+ .lightbox-next .icon {
2080
+ font-size: 1.25rem;
2081
+ }
2082
+ .lightbox-prev {
2083
+ left: 0.5rem;
2084
+ }
2085
+ .lightbox-next {
2086
+ right: 0.5rem;
2087
+ }
2088
+ .lightbox {
2089
+ max-width: 100vw;
2090
+ }
2091
+ .lightbox-img,
2092
+ .lightbox-img-wrap {
2093
+ max-height: 82dvh;
2094
+ border-radius: 0.4rem;
2095
+ }
2096
+ .lightbox-close {
2097
+ top: 0.75rem;
2098
+ right: 0.75rem;
2099
+ }
2100
+ }
1847
2101
  .popover {
1848
2102
  position: fixed;
1849
2103
  z-index: 900;
@@ -8102,14 +8356,18 @@ body {
8102
8356
  left: 0;
8103
8357
  top: 0;
8104
8358
  height: 100vh;
8105
- overflow-y: auto;
8106
8359
  background: var(--primary-bg);
8107
8360
  border-right: 1px solid var(--divider);
8108
8361
  display: flex;
8109
8362
  flex-direction: column;
8110
8363
  z-index: 100;
8111
- scrollbar-width: thin;
8112
- scrollbar-color: var(--divider) transparent;
8364
+ }
8365
+ .sidebar-nav .sidebar-scroll {
8366
+ flex: 1;
8367
+ min-height: 0;
8368
+ background: none;
8369
+ border-radius: 0;
8370
+ box-shadow: none;
8113
8371
  }
8114
8372
 
8115
8373
  .sidebar-main {
@@ -8675,3 +8933,5 @@ body {
8675
8933
  display: flex;
8676
8934
  gap: 1.25rem;
8677
8935
  }
8936
+
8937
+ /*# sourceMappingURL=style.css.map */