al-design-system 1.8.0 → 1.9.0

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/README.md CHANGED
@@ -10,7 +10,7 @@ An open-source design system, from Figma to code. Plain CSS, a little vanilla Ja
10
10
 
11
11
  ## What it is
12
12
 
13
- - **Foundation + 32 components**, designed in Figma and coded from the same tokens.
13
+ - **Foundation + 33 components**, designed in Figma and coded from the same tokens.
14
14
  - **Light and dark themes** built in. It follows the operating system by default, and you can force one.
15
15
  - **Accessibility is checked by the build.** Every rendered combination (variant × state × theme) is measured for contrast against the background it actually sits on, and each component's markup contract is verified. If something fails, the build stops.
16
16
  - **Nothing is typed by hand.** Tokens, CSS variables, `tokens.json` and the documentation tables are all generated from one source.
@@ -44,6 +44,7 @@ An open-source design system, from Figma to code. Plain CSS, a little vanilla Ja
44
44
  | | Drawer | ✓ | [guidelines](src/components/drawer/guidelines.md) |
45
45
  | Navigation | Sidebar | ✓ | [guidelines](src/components/sidebar/guidelines.md) |
46
46
  | | Breadcrumb | ✓ | [guidelines](src/components/breadcrumb/guidelines.md) |
47
+ | | Carousel | ✓ | [guidelines](src/components/carousel/guidelines.md) |
47
48
  | | Pagination | | [guidelines](src/components/pagination/guidelines.md) |
48
49
  | | Stepper | | [guidelines](src/components/stepper/guidelines.md) |
49
50
  | Feedback | Tooltip | ✓ | [guidelines](src/components/tooltip/guidelines.md) |
@@ -63,7 +64,7 @@ npm install al-design-system
63
64
  Or straight from a CDN, pinned to a version:
64
65
 
65
66
  ```html
66
- <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/al-design-system@1.8.0/dist/al.css">
67
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/al-design-system@1.9.0/dist/al.css">
67
68
  ```
68
69
 
69
70
  Each [GitHub Release](https://github.com/guilhermedworakowski/al-design-system/releases) also carries the `dist/` folder as a zip.
@@ -72,10 +73,10 @@ Each [GitHub Release](https://github.com/guilhermedworakowski/al-design-system/r
72
73
 
73
74
  | File | What it is |
74
75
  |---|---|
75
- | `al.css` | Foundation + all 32 components, in one file |
76
+ | `al.css` | Foundation + all 33 components, in one file |
76
77
  | `foundation.css` | Only the Foundation: color, typography, spacing, radius, icon size, elevation, focus ring and motion |
77
78
  | `components/<name>.css` | One component (its tokens + its CSS) |
78
- | `components/<name>.js` | The behavior, for the 12 components that have a script |
79
+ | `components/<name>.js` | The behavior, for the 13 components that have a script |
79
80
  | `icons/*.svg`, `icons/icons.json` | The 70 icons |
80
81
  | `tokens.json` | The Foundation tokens, to read from code |
81
82
 
@@ -106,7 +107,7 @@ The exact markup of each component (which element, which attributes) is describe
106
107
 
107
108
  ### Scripts
108
109
 
109
- Password, Number field, Slider, Menu, Tab, Modal, Drawer, Sidebar, Breadcrumb, Tooltip, Toast and Alert need their script, loaded once per page. Each one wires up the components already on the page by itself:
110
+ Password, Number field, Slider, Menu, Tab, Modal, Drawer, Sidebar, Breadcrumb, Carousel, Tooltip, Toast and Alert need their script, loaded once per page. Each one wires up the components already on the page by itself:
110
111
 
111
112
  ```html
112
113
  <script src="node_modules/al-design-system/dist/components/modal.js" defer></script>
package/README.pt-BR.md CHANGED
@@ -10,7 +10,7 @@ Design system open source, do Figma ao código. CSS puro, um pouco de JavaScript
10
10
 
11
11
  ## O que é
12
12
 
13
- - **Foundation + 32 componentes**, desenhados no Figma e codados a partir dos mesmos tokens.
13
+ - **Foundation + 33 componentes**, desenhados no Figma e codados a partir dos mesmos tokens.
14
14
  - **Temas claro e escuro** já incluídos. Por padrão segue o sistema operacional, e dá para forçar um.
15
15
  - **A acessibilidade é conferida no build.** Cada combinação renderizada (variante × estado × tema) tem o contraste medido contra o fundo onde ela realmente aparece, e o contrato de marcação de cada componente é verificado. Se algo reprova, o build para.
16
16
  - **Nada é digitado à mão.** Tokens, variáveis CSS, `tokens.json` e as tabelas da documentação saem todos de uma fonte só.
@@ -44,6 +44,7 @@ Design system open source, do Figma ao código. CSS puro, um pouco de JavaScript
44
44
  | | Drawer | ✓ | [diretrizes](src/components/drawer/guidelines.md) |
45
45
  | Navegação | Sidebar | ✓ | [diretrizes](src/components/sidebar/guidelines.md) |
46
46
  | | Breadcrumb | ✓ | [diretrizes](src/components/breadcrumb/guidelines.md) |
47
+ | | Carousel | ✓ | [diretrizes](src/components/carousel/guidelines.md) |
47
48
  | | Pagination | | [diretrizes](src/components/pagination/guidelines.md) |
48
49
  | | Stepper | | [diretrizes](src/components/stepper/guidelines.md) |
49
50
  | Feedback | Tooltip | ✓ | [diretrizes](src/components/tooltip/guidelines.md) |
@@ -63,7 +64,7 @@ npm install al-design-system
63
64
  Ou direto de uma CDN, fixado numa versão:
64
65
 
65
66
  ```html
66
- <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/al-design-system@1.8.0/dist/al.css">
67
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/al-design-system@1.9.0/dist/al.css">
67
68
  ```
68
69
 
69
70
  Cada [Release no GitHub](https://github.com/guilhermedworakowski/al-design-system/releases) também traz a pasta `dist/` num zip.
@@ -72,10 +73,10 @@ Cada [Release no GitHub](https://github.com/guilhermedworakowski/al-design-syste
72
73
 
73
74
  | Arquivo | O que é |
74
75
  |---|---|
75
- | `al.css` | Foundation + os 32 componentes, num arquivo só |
76
+ | `al.css` | Foundation + os 33 componentes, num arquivo só |
76
77
  | `foundation.css` | Só a Foundation: cor, tipografia, espaçamento, radius, tamanho de ícone, elevação, anel de foco e motion |
77
78
  | `components/<nome>.css` | Um componente (os tokens + o CSS dele) |
78
- | `components/<nome>.js` | O comportamento, para os 12 componentes que têm script |
79
+ | `components/<nome>.js` | O comportamento, para os 13 componentes que têm script |
79
80
  | `icons/*.svg`, `icons/icons.json` | Os 70 ícones |
80
81
  | `tokens.json` | Os tokens da Foundation, para ler por código |
81
82
 
@@ -106,7 +107,7 @@ A marcação exata de cada componente (qual elemento, quais atributos) está des
106
107
 
107
108
  ### Scripts
108
109
 
109
- Password, Number field, Slider, Menu, Tab, Modal, Drawer, Sidebar, Breadcrumb, Tooltip, Toast e Alert precisam do script, carregado uma vez por página. Cada um liga sozinho os componentes que já estão na página:
110
+ Password, Number field, Slider, Menu, Tab, Modal, Drawer, Sidebar, Breadcrumb, Carousel, Tooltip, Toast e Alert precisam do script, carregado uma vez por página. Cada um liga sozinho os componentes que já estão na página:
110
111
 
111
112
  ```html
112
113
  <script src="node_modules/al-design-system/dist/components/modal.js" defer></script>
package/dist/al.css CHANGED
@@ -1,8 +1,8 @@
1
- /* AL Design System 1.8.0 - Foundation + 32 components.
1
+ /* AL Design System 1.9.0 - Foundation + 33 components.
2
2
  * MIT. https://github.com/guilhermedworakowski/al-design-system
3
3
  */
4
4
  /* AL Design System - Foundation
5
- * v1.8.0 - MIT
5
+ * v1.9.0 - MIT
6
6
  * GENERATED by src/foundation/css.py. Do not edit by hand: run the script.
7
7
  */
8
8
 
@@ -8679,3 +8679,173 @@
8679
8679
  @media (prefers-reduced-motion: reduce) {
8680
8680
  .al-rating__glyph { transition: none; }
8681
8681
  }
8682
+
8683
+ /* AL Design System - Carousel tokens
8684
+ * GENERATED by src/components/carousel/tokens.py. Do not edit by hand.
8685
+ *
8686
+ * Every color is a semantic the theme switches on :root.
8687
+ */
8688
+
8689
+ :root {
8690
+ /* color */
8691
+ --al-carousel-dot: var(--al-border-strong);
8692
+ --al-carousel-dot-current: var(--al-bg-brand);
8693
+ --al-carousel-slide-bg: var(--al-bg-subtle);
8694
+
8695
+ /* geometry */
8696
+ --al-carousel-gap: var(--al-space-16);
8697
+ --al-carousel-controls-gap: var(--al-space-16);
8698
+ --al-carousel-nav-gap: var(--al-space-8);
8699
+ --al-carousel-dot-size: var(--al-space-8);
8700
+ --al-carousel-dot-current-width: var(--al-space-24);
8701
+ --al-carousel-dot-gap: var(--al-space-8);
8702
+ --al-carousel-dot-radius: var(--al-radius-full);
8703
+ --al-carousel-slide-radius: var(--al-radius-lg);
8704
+ }
8705
+
8706
+ /* AL Design System - Carousel
8707
+ *
8708
+ * Depends on: al-foundation.css, al-carousel-tokens.css, and the Icon Button
8709
+ * (al-icon-tokens.css + icon.css + al-icon-button-tokens.css + icon-button.css)
8710
+ * for the arrows. Behavior in carousel.js.
8711
+ *
8712
+ * The basic carousel of the APG (usage rules 13-23): previous and next below
8713
+ * the content, disabled at the ends, no loop, no auto-rotation. The dots are
8714
+ * decorative.
8715
+ *
8716
+ * <section class="al-carousel" aria-roledescription="carousel" aria-labelledby="t">
8717
+ * <h2 id="t">Visible title</h2> (rule 9 - the page's heading)
8718
+ * <div class="al-carousel__viewport">
8719
+ * <div class="al-carousel__slide" role="group"
8720
+ * aria-roledescription="slide" aria-label="1 of 5">…</div>
8721
+ * …
8722
+ * </div>
8723
+ * <div class="al-carousel__controls">
8724
+ * <span class="al-carousel__dots" aria-hidden="true">
8725
+ * <span class="al-carousel__dot"></span>… (one per slide, carousel.js marks the current)
8726
+ * </span>
8727
+ * <div class="al-carousel__nav">
8728
+ * <button type="button" class="al-icon-btn al-icon-btn--secondary al-icon-btn--sm"
8729
+ * data-al-carousel="prev" aria-label="Previous slide">…chevron-left…</button>
8730
+ * <button type="button" class="al-icon-btn al-icon-btn--secondary al-icon-btn--sm"
8731
+ * data-al-carousel="next" aria-label="Next slide">…chevron-right…</button>
8732
+ * </div>
8733
+ * </div>
8734
+ * <p class="al-carousel__live" aria-live="polite" aria-atomic="true"></p>
8735
+ * </section>
8736
+ *
8737
+ * SLIDE WIDTH IS THE LAYOUT'S (rule 6): --al-carousel-slide-size is a public
8738
+ * adjustment point, not a token. Default 100% = one slide per view; set it
8739
+ * narrower than the viewport so the next slide shows cut at the edge.
8740
+ *
8741
+ * NO JS NEEDED FOR FOCUS (rule 23): focusing a link inside a slide out of
8742
+ * view scrolls the viewport natively.
8743
+ *
8744
+ * The viewport hides its scrollbar: the arrows, swipe and the trackpad move
8745
+ * it. Smooth scrolling is turned off under prefers-reduced-motion (rule 16).
8746
+ */
8747
+
8748
+ .al-carousel {
8749
+ --al-carousel-slide-size: 100%;
8750
+ display: flex;
8751
+ flex-direction: column;
8752
+ gap: var(--al-carousel-controls-gap);
8753
+ min-inline-size: 0;
8754
+ }
8755
+
8756
+ /* -------------------------------------------------------------- viewport */
8757
+ .al-carousel__viewport {
8758
+ display: flex;
8759
+ gap: var(--al-carousel-gap);
8760
+ overflow-x: auto;
8761
+ overscroll-behavior-x: contain;
8762
+ scroll-snap-type: x mandatory;
8763
+ scroll-behavior: smooth;
8764
+ scrollbar-width: none;
8765
+ }
8766
+
8767
+ .al-carousel__viewport::-webkit-scrollbar {
8768
+ display: none;
8769
+ }
8770
+
8771
+ .al-carousel__slide {
8772
+ flex: 0 0 var(--al-carousel-slide-size);
8773
+ scroll-snap-align: start;
8774
+ overflow: hidden;
8775
+ border-radius: var(--al-carousel-slide-radius);
8776
+ background-color: var(--al-carousel-slide-bg); /* rule 18 - shows only when the image is missing */
8777
+ }
8778
+
8779
+ .al-carousel__slide > img {
8780
+ display: block;
8781
+ inline-size: 100%;
8782
+ block-size: 100%;
8783
+ object-fit: cover;
8784
+ }
8785
+
8786
+ /* -------------------------------------------------------------- controls */
8787
+ .al-carousel__controls {
8788
+ display: flex;
8789
+ align-items: center;
8790
+ justify-content: space-between;
8791
+ }
8792
+
8793
+ .al-carousel__nav {
8794
+ display: flex;
8795
+ gap: var(--al-carousel-nav-gap);
8796
+ margin-inline-start: auto;
8797
+ }
8798
+
8799
+ /* the dots: decorative, shape carries the current one (rule 22) */
8800
+ .al-carousel__dots {
8801
+ display: flex;
8802
+ align-items: center;
8803
+ gap: var(--al-carousel-dot-gap);
8804
+ }
8805
+
8806
+ .al-carousel__dot {
8807
+ inline-size: var(--al-carousel-dot-size);
8808
+ block-size: var(--al-carousel-dot-size);
8809
+ border-radius: var(--al-carousel-dot-radius);
8810
+ background-color: var(--al-carousel-dot);
8811
+ transition:
8812
+ inline-size var(--al-motion-duration-feedback) var(--al-motion-easing-exit),
8813
+ background-color var(--al-motion-duration-feedback) var(--al-motion-easing-exit);
8814
+ }
8815
+
8816
+ .al-carousel__dot[data-current] {
8817
+ inline-size: var(--al-carousel-dot-current-width);
8818
+ background-color: var(--al-carousel-dot-current);
8819
+ transition-timing-function: var(--al-motion-easing-enter);
8820
+ }
8821
+
8822
+ /* the polite region that announces the position after an arrow (rule 21) */
8823
+ .al-carousel__live {
8824
+ position: absolute;
8825
+ inline-size: var(--al-border-width-1);
8826
+ block-size: var(--al-border-width-1);
8827
+ margin: 0;
8828
+ overflow: hidden;
8829
+ clip-path: inset(50%);
8830
+ white-space: nowrap;
8831
+ }
8832
+
8833
+ @media (prefers-reduced-motion: reduce) {
8834
+ .al-carousel__viewport {
8835
+ scroll-behavior: auto;
8836
+ }
8837
+
8838
+ .al-carousel__dot {
8839
+ transition: none;
8840
+ }
8841
+ }
8842
+
8843
+ @media (forced-colors: active) {
8844
+ .al-carousel__dot {
8845
+ background-color: CanvasText;
8846
+ }
8847
+
8848
+ .al-carousel__dot[data-current] {
8849
+ background-color: Highlight;
8850
+ }
8851
+ }
@@ -0,0 +1,169 @@
1
+ /* AL Design System - Carousel tokens
2
+ * GENERATED by src/components/carousel/tokens.py. Do not edit by hand.
3
+ *
4
+ * Every color is a semantic the theme switches on :root.
5
+ */
6
+
7
+ :root {
8
+ /* color */
9
+ --al-carousel-dot: var(--al-border-strong);
10
+ --al-carousel-dot-current: var(--al-bg-brand);
11
+ --al-carousel-slide-bg: var(--al-bg-subtle);
12
+
13
+ /* geometry */
14
+ --al-carousel-gap: var(--al-space-16);
15
+ --al-carousel-controls-gap: var(--al-space-16);
16
+ --al-carousel-nav-gap: var(--al-space-8);
17
+ --al-carousel-dot-size: var(--al-space-8);
18
+ --al-carousel-dot-current-width: var(--al-space-24);
19
+ --al-carousel-dot-gap: var(--al-space-8);
20
+ --al-carousel-dot-radius: var(--al-radius-full);
21
+ --al-carousel-slide-radius: var(--al-radius-lg);
22
+ }
23
+
24
+ /* AL Design System - Carousel
25
+ *
26
+ * Depends on: al-foundation.css, al-carousel-tokens.css, and the Icon Button
27
+ * (al-icon-tokens.css + icon.css + al-icon-button-tokens.css + icon-button.css)
28
+ * for the arrows. Behavior in carousel.js.
29
+ *
30
+ * The basic carousel of the APG (usage rules 13-23): previous and next below
31
+ * the content, disabled at the ends, no loop, no auto-rotation. The dots are
32
+ * decorative.
33
+ *
34
+ * <section class="al-carousel" aria-roledescription="carousel" aria-labelledby="t">
35
+ * <h2 id="t">Visible title</h2> (rule 9 - the page's heading)
36
+ * <div class="al-carousel__viewport">
37
+ * <div class="al-carousel__slide" role="group"
38
+ * aria-roledescription="slide" aria-label="1 of 5">…</div>
39
+ * …
40
+ * </div>
41
+ * <div class="al-carousel__controls">
42
+ * <span class="al-carousel__dots" aria-hidden="true">
43
+ * <span class="al-carousel__dot"></span>… (one per slide, carousel.js marks the current)
44
+ * </span>
45
+ * <div class="al-carousel__nav">
46
+ * <button type="button" class="al-icon-btn al-icon-btn--secondary al-icon-btn--sm"
47
+ * data-al-carousel="prev" aria-label="Previous slide">…chevron-left…</button>
48
+ * <button type="button" class="al-icon-btn al-icon-btn--secondary al-icon-btn--sm"
49
+ * data-al-carousel="next" aria-label="Next slide">…chevron-right…</button>
50
+ * </div>
51
+ * </div>
52
+ * <p class="al-carousel__live" aria-live="polite" aria-atomic="true"></p>
53
+ * </section>
54
+ *
55
+ * SLIDE WIDTH IS THE LAYOUT'S (rule 6): --al-carousel-slide-size is a public
56
+ * adjustment point, not a token. Default 100% = one slide per view; set it
57
+ * narrower than the viewport so the next slide shows cut at the edge.
58
+ *
59
+ * NO JS NEEDED FOR FOCUS (rule 23): focusing a link inside a slide out of
60
+ * view scrolls the viewport natively.
61
+ *
62
+ * The viewport hides its scrollbar: the arrows, swipe and the trackpad move
63
+ * it. Smooth scrolling is turned off under prefers-reduced-motion (rule 16).
64
+ */
65
+
66
+ .al-carousel {
67
+ --al-carousel-slide-size: 100%;
68
+ display: flex;
69
+ flex-direction: column;
70
+ gap: var(--al-carousel-controls-gap);
71
+ min-inline-size: 0;
72
+ }
73
+
74
+ /* -------------------------------------------------------------- viewport */
75
+ .al-carousel__viewport {
76
+ display: flex;
77
+ gap: var(--al-carousel-gap);
78
+ overflow-x: auto;
79
+ overscroll-behavior-x: contain;
80
+ scroll-snap-type: x mandatory;
81
+ scroll-behavior: smooth;
82
+ scrollbar-width: none;
83
+ }
84
+
85
+ .al-carousel__viewport::-webkit-scrollbar {
86
+ display: none;
87
+ }
88
+
89
+ .al-carousel__slide {
90
+ flex: 0 0 var(--al-carousel-slide-size);
91
+ scroll-snap-align: start;
92
+ overflow: hidden;
93
+ border-radius: var(--al-carousel-slide-radius);
94
+ background-color: var(--al-carousel-slide-bg); /* rule 18 - shows only when the image is missing */
95
+ }
96
+
97
+ .al-carousel__slide > img {
98
+ display: block;
99
+ inline-size: 100%;
100
+ block-size: 100%;
101
+ object-fit: cover;
102
+ }
103
+
104
+ /* -------------------------------------------------------------- controls */
105
+ .al-carousel__controls {
106
+ display: flex;
107
+ align-items: center;
108
+ justify-content: space-between;
109
+ }
110
+
111
+ .al-carousel__nav {
112
+ display: flex;
113
+ gap: var(--al-carousel-nav-gap);
114
+ margin-inline-start: auto;
115
+ }
116
+
117
+ /* the dots: decorative, shape carries the current one (rule 22) */
118
+ .al-carousel__dots {
119
+ display: flex;
120
+ align-items: center;
121
+ gap: var(--al-carousel-dot-gap);
122
+ }
123
+
124
+ .al-carousel__dot {
125
+ inline-size: var(--al-carousel-dot-size);
126
+ block-size: var(--al-carousel-dot-size);
127
+ border-radius: var(--al-carousel-dot-radius);
128
+ background-color: var(--al-carousel-dot);
129
+ transition:
130
+ inline-size var(--al-motion-duration-feedback) var(--al-motion-easing-exit),
131
+ background-color var(--al-motion-duration-feedback) var(--al-motion-easing-exit);
132
+ }
133
+
134
+ .al-carousel__dot[data-current] {
135
+ inline-size: var(--al-carousel-dot-current-width);
136
+ background-color: var(--al-carousel-dot-current);
137
+ transition-timing-function: var(--al-motion-easing-enter);
138
+ }
139
+
140
+ /* the polite region that announces the position after an arrow (rule 21) */
141
+ .al-carousel__live {
142
+ position: absolute;
143
+ inline-size: var(--al-border-width-1);
144
+ block-size: var(--al-border-width-1);
145
+ margin: 0;
146
+ overflow: hidden;
147
+ clip-path: inset(50%);
148
+ white-space: nowrap;
149
+ }
150
+
151
+ @media (prefers-reduced-motion: reduce) {
152
+ .al-carousel__viewport {
153
+ scroll-behavior: auto;
154
+ }
155
+
156
+ .al-carousel__dot {
157
+ transition: none;
158
+ }
159
+ }
160
+
161
+ @media (forced-colors: active) {
162
+ .al-carousel__dot {
163
+ background-color: CanvasText;
164
+ }
165
+
166
+ .al-carousel__dot[data-current] {
167
+ background-color: Highlight;
168
+ }
169
+ }
@@ -0,0 +1,137 @@
1
+ /* AL Design System - Carousel, arrows, dots and announcement
2
+ *
3
+ * What it does on every .al-carousel inside `root` (usage rules 13-22):
4
+ * - previous / next scroll by one page (rule 14, A=a): next starts at the
5
+ * first slide not fully in view, so the one cut at the edge is never
6
+ * skipped; previous goes back as far as one viewport allows;
7
+ * - the arrows get `disabled` at the ends - no loop (rule 13). When the
8
+ * arrow that has focus turns disabled, focus moves to the other one, so
9
+ * it never falls back to <body>;
10
+ * - the dot of the first visible slide gets data-current (rule 22);
11
+ * - only after an ARROW, the live region says which slides are in view
12
+ * (rule 21, B=a). Swipe and trackpad announce nothing. The sentence is
13
+ * data-al-live on the .al-carousel, with {first}, {last} and {total}
14
+ * (default "Slides {first} to {last} of {total}"; one slide in view
15
+ * uses data-al-live-one, default "Slide {first} of {total}").
16
+ *
17
+ * Usage:
18
+ * <script src="carousel.js"></script> -> binds itself when the page loads
19
+ * alCarousel.init(container) -> binds content inserted later
20
+ * Binding the same carousel twice duplicates nothing.
21
+ */
22
+ (function () {
23
+ 'use strict';
24
+
25
+ function bind(root) {
26
+ if (root.hasAttribute('data-al-carousel-bound')) return;
27
+ var viewport = root.querySelector('.al-carousel__viewport');
28
+ if (!viewport) return;
29
+ root.setAttribute('data-al-carousel-bound', '');
30
+
31
+ var slides = [].slice.call(viewport.querySelectorAll('.al-carousel__slide'));
32
+ var dots = [].slice.call(root.querySelectorAll('.al-carousel__dot'));
33
+ var prev = root.querySelector('[data-al-carousel="prev"]');
34
+ var next = root.querySelector('[data-al-carousel="next"]');
35
+ var live = root.querySelector('.al-carousel__live');
36
+ var announce = false;
37
+
38
+ // slides fully (or almost fully) inside the viewport, 1-based
39
+ function inView() {
40
+ var v = viewport.getBoundingClientRect();
41
+ var first = 0, last = 0;
42
+ slides.forEach(function (s, i) {
43
+ var r = s.getBoundingClientRect();
44
+ if (r.left >= v.left - 1 && r.right <= v.right + 1) {
45
+ if (!first) first = i + 1;
46
+ last = i + 1;
47
+ }
48
+ });
49
+ return { first: first || 1, last: last || first || 1 };
50
+ }
51
+
52
+ function update() {
53
+ var max = viewport.scrollWidth - viewport.clientWidth;
54
+ var atStart = viewport.scrollLeft <= 1;
55
+ var atEnd = viewport.scrollLeft >= max - 1;
56
+ var lost = document.activeElement;
57
+
58
+ if (prev) prev.disabled = atStart;
59
+ if (next) next.disabled = atEnd;
60
+ if (lost === prev && atStart && next && !atEnd) next.focus();
61
+ if (lost === next && atEnd && prev && !atStart) prev.focus();
62
+
63
+ var pos = inView();
64
+ dots.forEach(function (d, i) {
65
+ if (i === pos.first - 1) d.setAttribute('data-current', '');
66
+ else d.removeAttribute('data-current');
67
+ });
68
+
69
+ if (announce && live) {
70
+ var one = pos.first === pos.last;
71
+ var text = one
72
+ ? root.getAttribute('data-al-live-one') || 'Slide {first} of {total}'
73
+ : root.getAttribute('data-al-live') || 'Slides {first} to {last} of {total}';
74
+ live.textContent = text
75
+ .replace('{first}', pos.first)
76
+ .replace('{last}', pos.last)
77
+ .replace('{total}', slides.length);
78
+ }
79
+ announce = false;
80
+ }
81
+
82
+ // a slide's start, in the viewport's scroll coordinates
83
+ function start(s) { return s.offsetLeft - slides[0].offsetLeft; }
84
+
85
+ // Next: the first slide not fully in view becomes the first one - a slide
86
+ // cut at the edge is never skipped. Previous: the mirror, the earliest
87
+ // slide that still fits one viewport back.
88
+ function page(dir) {
89
+ announce = true;
90
+ var pos = inView();
91
+ var left;
92
+ if (dir > 0) {
93
+ left = start(slides[Math.min(pos.last, slides.length - 1)]);
94
+ } else {
95
+ var floor = viewport.scrollLeft - viewport.clientWidth;
96
+ var target = slides.filter(function (s) { return start(s) >= floor - 1; })[0];
97
+ left = Math.min(start(target), start(slides[Math.max(pos.first - 2, 0)]));
98
+ }
99
+ viewport.scrollTo({ left: left });
100
+ }
101
+
102
+ if (prev) prev.addEventListener('click', function () { page(-1); });
103
+ if (next) next.addEventListener('click', function () { page(1); });
104
+
105
+ // scrollend where it exists; a short quiet period elsewhere (Safari)
106
+ if ('onscrollend' in window) {
107
+ viewport.addEventListener('scrollend', update);
108
+ } else {
109
+ var timer;
110
+ viewport.addEventListener('scroll', function () {
111
+ clearTimeout(timer);
112
+ timer = setTimeout(update, 100);
113
+ });
114
+ }
115
+ // A carousel born hidden (a closed Tab panel, a Modal, an Accordion) has
116
+ // no width yet: both arrows would start disabled. Watching the viewport's
117
+ // size updates it the moment it shows, and on every resize after that.
118
+ if ('ResizeObserver' in window) {
119
+ new ResizeObserver(update).observe(viewport);
120
+ } else {
121
+ window.addEventListener('resize', update);
122
+ }
123
+ update();
124
+ }
125
+
126
+ function init(root) {
127
+ [].slice.call((root || document).querySelectorAll('.al-carousel')).forEach(bind);
128
+ }
129
+
130
+ window.alCarousel = { init: init };
131
+
132
+ if (document.readyState === 'loading') {
133
+ document.addEventListener('DOMContentLoaded', function () { init(); });
134
+ } else {
135
+ init();
136
+ }
137
+ })();
@@ -1,5 +1,5 @@
1
1
  /* AL Design System - Foundation
2
- * v1.8.0 - MIT
2
+ * v1.9.0 - MIT
3
3
  * GENERATED by src/foundation/css.py. Do not edit by hand: run the script.
4
4
  */
5
5
 
package/dist/tokens.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "meta": {
3
3
  "name": "AL Design System",
4
- "version": "1.8.0",
4
+ "version": "1.9.0",
5
5
  "license": "MIT",
6
6
  "brandAnchor": "#FC5000",
7
7
  "colorSpace": "OKLCH",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "al-design-system",
3
- "version": "1.8.0",
3
+ "version": "1.9.0",
4
4
  "description": "AL Design System: Foundation and components in plain CSS, from Figma to code.",
5
5
  "license": "MIT",
6
6
  "author": "Guilherme Domingues",