@dodlhuat/basix 1.2.2 → 1.2.4

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 +45 -1
  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 +32 -21
  44. package/js/timepicker.ts +29 -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
@@ -1,4 +1,4 @@
1
- # Basix 1.2.1
1
+ # Basix 1.2.4
2
2
 
3
3
  Basix is intended as a starter for the rapid development of a design. Each design element can be added individually to
4
4
  include only the data required. It is using plain javascript / typescript and therefore is not dependent on any plugin.
@@ -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.
@@ -739,6 +781,8 @@ The TimeSpanPicker component provides a paired start/end time input for selectin
739
781
  const picker = new TimeSpanPicker('my-container', {
740
782
  defaultStart: '09:00',
741
783
  defaultEnd: '17:00',
784
+ fromString: 'Von', // optional — defaults to 'From'
785
+ toString: 'Bis', // optional — defaults to 'To'
742
786
  onChange: (start, end) => console.log(start, end),
743
787
  });
744
788
 
@@ -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 */