@inizioevoke/astro-core 2.1.2 → 2.2.1

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.
@@ -0,0 +1,59 @@
1
+ # CssBackgroundImage
2
+
3
+ The CssBackgroundImage component renders a style element on the page with the given selector and background image. This is useful to quickly set the `background-image` of an element to an imported image url without all the extra inline styles that Astro inserts when using `<style define:vars={{}} />`. This component will also let you use breakpoints to set the `background-image` based on the screen width. If the `selector` parameter is not given the default selector is `body`. This component should be rendered inside your layout. Use a `<slot />` to specify where to inject it.
4
+
5
+ ## Image optimization
6
+
7
+ The image will be optimized by default. Optimization options include `format`, `quality`, `width`, `height`. To turn off image optimization, set `optimize={false}`.
8
+
9
+ ## Example
10
+
11
+ ```html
12
+ <!-- Layout -->
13
+ <html>
14
+ <head>
15
+ <slot name="styles" />
16
+ </head>
17
+ <body>
18
+ <slot />
19
+ </body>
20
+ </html>
21
+ ```
22
+ ```html
23
+ <!-- Astro Page -->
24
+ ---
25
+ import { CssBackgroundImage } from '@inizioevoke/astro-core';
26
+ import Layout from '../layouts/Layout.astro';
27
+ import bgImg_m from '../assets/img/background-m.jpg';
28
+ import bgImg_d from '../assets/img/background-d.jpg';
29
+ ---
30
+ <Layout>
31
+ <CssBackgroundImage
32
+ slot="styles"
33
+ selector="body"
34
+ image={bgImg_m}
35
+ breakpoints={[{
36
+ minWidth: 1200,
37
+ image: bgImg_d
38
+ }]}
39
+ />
40
+ </Layout>
41
+ ```
42
+ Output
43
+ ```html
44
+ <html>
45
+ <head>
46
+ <style>
47
+ body {
48
+ background-image: url("/[ASSETS]/background-m.jpg");
49
+ @media screen and (min-width: 1200px) {
50
+ background-image: url("/[ASSETS]/background-d.jpg");
51
+ }
52
+ }
53
+ </style>
54
+ </head>
55
+ <body>
56
+ ...
57
+ </body>
58
+ </html>
59
+ ```
@@ -0,0 +1,64 @@
1
+ # CssVariables
2
+
3
+ The CssVariables component creates variables in a style element on the page with the given names and values. This is especially useful when you want to set a variable to an imported image url without all the extra inline styles that Astro inserts when using `<style define:vars={{}} />`. This component will also let you use breakpoints to override the variables based on the screen width. If the `selector` parameter is not given the default selector is `:root`. This component should be rendered inside your layout. Use a `<slot />` to specify where to inject it.
4
+
5
+ ## Image optimization
6
+
7
+ The image will be optimized by default. Optimization options include `format`, `quality`, `width`, `height`. To turn off image optimization, set `optimize={false}`.
8
+
9
+ ## Example
10
+
11
+ ```html
12
+ <!-- Layout -->
13
+ <html>
14
+ <head>
15
+ <slot name="cssvars" />
16
+ </head>
17
+ <body>
18
+ <slot />
19
+ </body>
20
+ </html>
21
+ ```
22
+ ```html
23
+ <!-- Astro Page -->
24
+ ---
25
+ import { CssVariables } from '@inizioevoke/astro-core';
26
+ import Layout from '../layouts/Layout.astro';
27
+ import bgImg_m from '../assets/img/background-m.jpg';
28
+ import bgImg_d from '../assets/img/background-d.jpg';
29
+ ---
30
+ <Layout>
31
+ <CssVariables
32
+ slot="cssvars"
33
+ selector=":root"
34
+ variables={[{
35
+ name: 'bgImg',
36
+ type: 'url',
37
+ value: bgImg_m,
38
+ breakpoints: [{
39
+ minWidth: 1200,
40
+ value: bgImg_d
41
+ }]
42
+ }]}
43
+ />
44
+ </Layout>
45
+ ```
46
+ Output
47
+ ```html
48
+ <html>
49
+ <head>
50
+ <style>
51
+ :root {
52
+ --bgImg: url("/[ASSETS]/background-m.jpg");
53
+ @media screen and (min-width: 1200px) {
54
+ --bgImg: url("/[ASSETS]/background-d.jpg");
55
+ }
56
+ }
57
+ </style>
58
+ </head>
59
+ <body>
60
+ ...
61
+ </body>
62
+ </html>
63
+
64
+ ```
@@ -0,0 +1,113 @@
1
+ # FlipCard
2
+
3
+ The FlipCard component renders a 3D flip card with a front and back face. A trigger button (top-right corner of each face) toggles the flip animation. The component is a custom element (`<evo-flip-card>`) with a JavaScript API for programmatic control.
4
+
5
+ ## Props
6
+
7
+ | Prop | Type | Default | Description |
8
+ |------|------|---------|-------------|
9
+ | `width` | `number` | `640` | Card width in pixels (sets `--evo-flip-card-width`) |
10
+ | `height` | `number` | `360` | Card height in pixels (sets `--evo-flip-card-height`) |
11
+ | `...rest` | `HTMLAttributes<'div'>` | — | Any additional HTML attributes are passed to the `<evo-flip-card>` element |
12
+
13
+ ## Slots
14
+
15
+ | Slot | Description |
16
+ |------|-------------|
17
+ | `front` | Content rendered on the front face |
18
+ | `back` | Content rendered on the back face |
19
+ | `trigger` | Custom trigger button content used on **both** faces (overrides the default ↻ icon) |
20
+ | `front-trigger` | Custom trigger button content for the front face only (takes precedence over `trigger`) |
21
+ | `back-trigger` | Custom trigger button content for the back face only (takes precedence over `trigger`) |
22
+
23
+ ## CSS Custom Properties
24
+
25
+ | Property | Default | Description |
26
+ |----------|---------|-------------|
27
+ | `--evo-flip-card-width` | `640px` | Width of the card |
28
+ | `--evo-flip-card-height` | `360px` | Height of the card |
29
+ | `--evo-flip-card-duration` | `0.6s` | Duration of the flip transition |
30
+
31
+ ## JavaScript API
32
+
33
+ The underlying `<evo-flip-card>` custom element exposes the following API for programmatic control:
34
+
35
+ | Member | Type | Description |
36
+ |--------|------|-------------|
37
+ | `isFlipped` | `boolean` (get/set) | Current flip state. Setting this toggles the card. |
38
+ | `toggle()` | `method` | Toggles between front and back |
39
+ | `flipFront()` | `method` | Shows the front face |
40
+ | `flipBack()` | `method` | Shows the back face |
41
+
42
+ ## Examples
43
+
44
+ ### Basic usage
45
+
46
+ ```astro
47
+ ---
48
+ import { FlipCard } from '@inizioevoke/astro-core';
49
+ ---
50
+ <FlipCard width={400} height={300}>
51
+ <div slot="front">
52
+ <h2>Front</h2>
53
+ <p>Click the button to flip.</p>
54
+ </div>
55
+ <div slot="back">
56
+ <h2>Back</h2>
57
+ <p>Click the button to flip back.</p>
58
+ </div>
59
+ </FlipCard>
60
+ ```
61
+
62
+ ### Custom trigger buttons
63
+
64
+ Use `trigger` to set the same custom button content on both faces, or use `front-trigger` / `back-trigger` to set them independently.
65
+
66
+ ```astro
67
+ <FlipCard>
68
+ <span slot="trigger">Flip ↔</span>
69
+ <div slot="front">Front content</div>
70
+ <div slot="back">Back content</div>
71
+ </FlipCard>
72
+ ```
73
+
74
+ ```astro
75
+ <FlipCard>
76
+ <span slot="front-trigger">See details →</span>
77
+ <span slot="back-trigger">← Go back</span>
78
+ <div slot="front">Front content</div>
79
+ <div slot="back">Back content</div>
80
+ </FlipCard>
81
+ ```
82
+
83
+ ### Programmatic control
84
+
85
+ Access the custom element directly to control the card from JavaScript.
86
+
87
+ ```astro
88
+ <FlipCard id="my-card">
89
+ <div slot="front">Front</div>
90
+ <div slot="back">Back</div>
91
+ </FlipCard>
92
+
93
+ <button id="flip-btn">Flip programmatically</button>
94
+
95
+ <script>
96
+ const card = document.querySelector('#my-card');
97
+ document.querySelector('#flip-btn').addEventListener('click', () => {
98
+ card.toggle();
99
+ });
100
+ </script>
101
+ ```
102
+
103
+ ### Overriding dimensions via CSS
104
+
105
+ You can also control card dimensions with CSS custom properties directly.
106
+
107
+ ```css
108
+ evo-flip-card {
109
+ --evo-flip-card-width: 100%;
110
+ --evo-flip-card-height: 480px;
111
+ --evo-flip-card-duration: 0.4s;
112
+ }
113
+ ```
@@ -0,0 +1,211 @@
1
+ # Modal
2
+
3
+ The Modal component system renders a custom element (`<evo-modal>`) that is hidden by default and shown/hidden programmatically or via trigger elements. It ships with three companion components — `ModalTrigger` and `ModalOverlay` — and a JavaScript utility API.
4
+
5
+ When a modal opens it automatically closes any other currently visible modal. Clicking the overlay (or the built-in close button) hides the active modal. An overlay `<div>` is injected automatically into `<body>` on `DOMContentLoaded` if `ModalOverlay` is not present in the page.
6
+
7
+ ## Components
8
+
9
+ ### `Modal`
10
+
11
+ The modal panel itself.
12
+
13
+ #### Props
14
+
15
+ | Prop | Type | Default | Description |
16
+ |------|------|---------|-------------|
17
+ | `id` | `string` | **required** | Unique id used to target the modal from triggers and the JS API |
18
+ | `closeButton` | `'default' \| 'minimal' \| 'none' \| 'false' \| false` | `'default'` | Controls the built-in close button. `'default'` renders a styled ✕ circle; `'minimal'` renders unstyled; `'none'` / `false` removes it entirely |
19
+ | `closeButtonAtts` | `Record<string, string>` | — | Additional HTML attributes spread onto the close button element |
20
+ | `...rest` | `HTMLAttributes<'div'>` | — | Any additional HTML attributes are passed to the `<evo-modal>` element |
21
+
22
+ #### Slots
23
+
24
+ | Slot | Description |
25
+ |------|-------------|
26
+ | *(default)* | Main modal content, rendered inside the padded `.evo-modal-wrapper` |
27
+ | `close` | Custom label/icon for the close button (default is `X`) |
28
+ | `outer` | Content rendered outside the `.evo-modal-wrapper`, between the close button and the wrapper (useful for full-bleed media) |
29
+
30
+ ---
31
+
32
+ ### `ModalTrigger`
33
+
34
+ A `<button>` that opens a modal when clicked. Uses `data-evo-modal-show` under the hood, so plain HTML elements with that attribute also work (see [Data attribute triggers](#data-attribute-triggers)).
35
+
36
+ #### Props
37
+
38
+ | Prop | Type | Default | Description |
39
+ |------|------|---------|-------------|
40
+ | `modal` | `string` | **required** | The `id` of the modal to open |
41
+ | `animation` | `'fade' \| 'none'` | `'fade'` | Animation to use when opening |
42
+ | `...rest` | `HTMLAttributes<'button'>` | — | Any additional attributes are spread onto the button |
43
+
44
+ ---
45
+
46
+ ### `ModalOverlay`
47
+
48
+ An optional backdrop element. If omitted, the script creates one automatically. Include it explicitly when you need to place or style the overlay yourself.
49
+
50
+ #### Props
51
+
52
+ | Prop | Type | Description |
53
+ |------|------|-------------|
54
+ | `class` | `string` | Additional CSS class(es) appended to the overlay element |
55
+ | `...rest` | `HTMLAttributes<'div'>` | Any additional attributes are spread onto the div |
56
+
57
+ ---
58
+
59
+ ## CSS Custom Properties
60
+
61
+ | Property | Default | Description |
62
+ |----------|---------|-------------|
63
+ | `--evo-modal-width` | `800px` | Width of the modal |
64
+ | `--evo-modal-height` | `450px` | Height of the modal |
65
+ | `--evo-modal-position` | `absolute` | CSS `position` of the modal element |
66
+ | `--evo-modal-viewport-width` | `100vw` | Viewport width used to center the modal |
67
+ | `--evo-modal-viewport-height` | `100vh` | Viewport height used to center the modal |
68
+ | `--evo-modal-animation-duration` | `300ms` | Duration of show/hide animations (also read by JS) |
69
+ | `--evo-modal-z-index` | `99` | `z-index` of the modal; overlay is `z-index - 1` |
70
+ | `--evo-modal-overlay-blur` | `2px` | `backdrop-filter: blur()` value on the overlay |
71
+
72
+ ---
73
+
74
+ ## JavaScript API
75
+
76
+ ### Element methods
77
+
78
+ Access the `<evo-modal>` element directly to call these methods:
79
+
80
+ | Method | Signature | Description |
81
+ |--------|-----------|-------------|
82
+ | `showModal` | `(opts?: { animation?: ModalAnimation }) => Promise<void>` | Shows the modal. Resolves after the animation completes. |
83
+ | `hideModal` | `(opts?: { animation?: ModalAnimation }) => Promise<void>` | Hides the modal. Resolves after the animation completes. |
84
+
85
+ `ModalAnimation` is `'fade' | 'none'`. When omitted, `showModal` defaults to `'fade'` and `hideModal` reuses the animation that was used to show it.
86
+
87
+ ### Utility functions
88
+
89
+ Importable from the package entry point for use in client scripts.
90
+
91
+ ```ts
92
+ import { showModal, hideModal, hideModals, showOverlay, hideOverlay, bindTriggers } from '@inizioevoke/astro-core';
93
+ ```
94
+
95
+ | Function | Signature | Description |
96
+ |----------|-----------|-------------|
97
+ | `showModal` | `(selector: string \| HTMLElement, opts?) => Promise<EvoModalElement \| undefined>` | Shows a modal by id, CSS selector, or element reference. `opts` accepts `animation`, `onShow`, and `onHide` one-time callbacks. |
98
+ | `hideModal` | `(selector: string \| HTMLElement, animation?) => Promise<void>` | Hides a specific modal. |
99
+ | `hideModals` | `(animation?) => Promise<void>` | Hides all currently visible modals. |
100
+ | `showOverlay` | `(animation?) => void` | Shows the overlay independently. |
101
+ | `hideOverlay` | `(opts?) => void` | Hides the overlay independently. |
102
+ | `bindTriggers` | `(container?) => void` | Binds click handlers to `[data-evo-modal-show]` elements. Call this after dynamically inserting trigger elements into the DOM. |
103
+
104
+ ### Custom events
105
+
106
+ Both events bubble and are composed (cross shadow DOM). Listen on the `<evo-modal>` element or any ancestor.
107
+
108
+ | Event | Detail | Fires when |
109
+ |-------|--------|------------|
110
+ | `evomodal-visible` | `{ modal: EvoModalElement }` | Modal has finished showing |
111
+ | `evomodal-hidden` | `{ modal: EvoModalElement, replacedBy?: EvoModalElement }` | Modal has finished hiding. `replacedBy` is set when another modal opened in its place. |
112
+
113
+ ---
114
+
115
+ ## Data attribute triggers
116
+
117
+ Any element with `data-evo-modal-show` will open the target modal on click — no `ModalTrigger` component required. `bindTriggers()` is called automatically on `DOMContentLoaded`; call it manually for dynamically added elements.
118
+
119
+ ```html
120
+ <button data-evo-modal-show="my-modal" data-evo-modal-animation="fade">Open</button>
121
+ ```
122
+
123
+ | Attribute | Description |
124
+ |-----------|-------------|
125
+ | `data-evo-modal-show` | Id of the modal to open (or a CSS selector prefixed with `#` or `.`) |
126
+ | `data-evo-modal-animation` | Optional animation override (`'fade'` or `'none'`) |
127
+
128
+ Any element with the class `evo-modal-action-hide` inside a modal will close it when clicked (the built-in close button uses this class).
129
+
130
+ ---
131
+
132
+ ## Examples
133
+
134
+ ### Basic modal with trigger
135
+
136
+ ```astro
137
+ ---
138
+ import { Modal, ModalTrigger } from '@inizioevoke/astro-core';
139
+ ---
140
+ <ModalTrigger modal="info-modal">Open modal</ModalTrigger>
141
+
142
+ <Modal id="info-modal">
143
+ <h2>Hello</h2>
144
+ <p>This is the modal content.</p>
145
+ </Modal>
146
+ ```
147
+
148
+ ### Custom close button label
149
+
150
+ ```astro
151
+ <Modal id="info-modal">
152
+ <span slot="close">Close ✕</span>
153
+ <p>Content here.</p>
154
+ </Modal>
155
+ ```
156
+
157
+ ### No close button
158
+
159
+ ```astro
160
+ <Modal id="info-modal" closeButton="none">
161
+ <p>Close me with a trigger inside or via JS.</p>
162
+ <button class="evo-modal-action-hide">Dismiss</button>
163
+ </Modal>
164
+ ```
165
+
166
+ ### Full-bleed outer slot
167
+
168
+ ```astro
169
+ <Modal id="media-modal">
170
+ <img slot="outer" src="/hero.jpg" alt="" style="width:100%;display:block;" />
171
+ <p>Caption below the image.</p>
172
+ </Modal>
173
+ ```
174
+
175
+ ### Programmatic control with callbacks
176
+
177
+ ```astro
178
+ <script>
179
+ import { showModal } from '@inizioevoke/astro-core';
180
+
181
+ document.querySelector('#open-btn').addEventListener('click', () => {
182
+ showModal('info-modal', {
183
+ animation: 'fade',
184
+ onShow: (e) => console.log('modal visible', e.detail.modal),
185
+ onHide: (e) => console.log('modal hidden', e.detail.modal),
186
+ });
187
+ });
188
+ </script>
189
+ ```
190
+
191
+ ### Binding dynamically added triggers
192
+
193
+ ```ts
194
+ import { bindTriggers } from '@inizioevoke/astro-core';
195
+
196
+ // After inserting new trigger elements into the DOM:
197
+ bindTriggers(myContainer);
198
+ ```
199
+
200
+ ### Explicit overlay with custom styling
201
+
202
+ ```astro
203
+ ---
204
+ import { Modal, ModalOverlay } from '@inizioevoke/astro-core';
205
+ ---
206
+ <ModalOverlay class="my-overlay" />
207
+
208
+ <Modal id="info-modal">
209
+ <p>Content</p>
210
+ </Modal>
211
+ ```
@@ -0,0 +1,160 @@
1
+ # ScrollContainer
2
+
3
+ The ScrollContainer component renders a custom element (`<evo-scroll-container>`) that replaces the browser's native scrollbar with a styled, draggable custom scrollbar. It supports vertical, horizontal, or both-axis scrolling.
4
+
5
+ The scrollbar auto-hides when content fits within the container and reappears when content overflows. Thumb size is calculated proportionally to the visible content ratio and automatically updates on window resize, DOM mutation, and intersection visibility changes.
6
+
7
+ ## Props
8
+
9
+ | Prop | Type | Default | Description |
10
+ |------|------|---------|-------------|
11
+ | `width` | `string \| number` | — | Container width. Plain numbers are treated as pixels; strings are used as-is (e.g. `'100%'`) |
12
+ | `height` | `string \| number` | — | Container height. Plain numbers are treated as pixels; strings are used as-is |
13
+ | `scrolling` | `'vertical' \| 'horizontal' \| 'both'` | `'vertical'` | Axis or axes to enable scrolling on |
14
+ | `...rest` | `HTMLAttributes<'div'>` | — | Any additional HTML attributes are passed to the `<evo-scroll-container>` element |
15
+
16
+ ## Slots
17
+
18
+ | Slot | Description |
19
+ |------|-------------|
20
+ | *(default)* | The scrollable content |
21
+
22
+ ## CSS Custom Properties
23
+
24
+ | Property | Default | Description |
25
+ |----------|---------|-------------|
26
+ | `--evo-scroll-container-track-width` | `8px` | Width/height of the scrollbar track |
27
+ | `--evo-scroll-container-track-color` | `#dddddd` | Track background color |
28
+ | `--evo-scroll-container-thumb-color` | `#666666` | Thumb background color |
29
+ | `--evo-scroll-container-thumb-border-width` | `0px` | Border width on the thumb |
30
+ | `--evo-scroll-container-thumb-border-color` | same as track | Border color on the thumb |
31
+ | `--evo-scroll-container-border-radius` | `track-width / 2` | Border radius for track and thumb |
32
+ | `--evo-scroll-container-track-vert-top` | `0px` | Offset from the top of the vertical track |
33
+ | `--evo-scroll-container-track-vert-bottom` | `0px` | Offset from the bottom of the vertical track |
34
+ | `--evo-scroll-container-track-vert-right` | `0px` | Offset from the right edge for the vertical track |
35
+ | `--evo-scroll-container-track-horz-bottom` | `0px` | Offset from the bottom edge for the horizontal track |
36
+ | `--evo-scroll-container-track-horz-left` | `0px` | Left offset of the horizontal track |
37
+ | `--evo-scroll-container-track-horz-right` | `0px` | Right offset of the horizontal track |
38
+ | `--evo-scroll-container-width-offset` | same as `track-width` | Extra horizontal space reserved for the vertical scrollbar |
39
+ | `--evo-scroll-container-height-offset` | same as `track-width` | Extra vertical space reserved for the horizontal scrollbar |
40
+
41
+ ## JavaScript API
42
+
43
+ ### Element properties and methods
44
+
45
+ Access the `<evo-scroll-container>` element directly to use these members:
46
+
47
+ | Member | Type | Description |
48
+ |--------|------|-------------|
49
+ | `content` | `HTMLElement` (get) | The inner `.evo-scroll-content` element |
50
+ | `scrollLeft` | `number` (get/set) | Horizontal scroll position |
51
+ | `scrollTop` | `number` (get/set) | Vertical scroll position |
52
+ | `scrollWidth` | `number` (get) | Full scrollable width of the content |
53
+ | `scrollHeight` | `number` (get) | Full scrollable height of the content |
54
+ | `scroll(opts?)` | method | Scroll to a position (`ScrollToOptions` or `(x, y)`) |
55
+ | `scrollTo(opts?)` | method | Alias for `scroll()` |
56
+ | `scrollBy(opts?)` | method | Scroll by a delta (`ScrollToOptions` or `(x, y)`) |
57
+ | `getScroll()` | `() => { left, top }` | Returns current scroll position |
58
+ | `resize({ height })` | method | Sets the container height in pixels and refreshes the scrollbar |
59
+ | `configureScrollbar(settings)` | method | Overrides scrollbar appearance. Accepts `{ trackVisible?: boolean, thumbHeight?: number }` |
60
+ | `resetScrollbar()` | method | Resets scrollbar to automatic sizing |
61
+ | `refresh()` | method | Recalculates and repaints thumb sizes. Call after external layout changes. |
62
+
63
+ `scroll`, `scrollTo`, and `scrollBy` proxy directly to the inner content element. `scroll` and `scrollend` events also delegate to the inner content element automatically.
64
+
65
+ ### Utility functions
66
+
67
+ Importable from the package entry point for use in client scripts.
68
+
69
+ ```ts
70
+ import { resize, refresh, getScroll, scroll, getScrollContainer } from '@inizioevoke/astro-core';
71
+ ```
72
+
73
+ | Function | Signature | Description |
74
+ |----------|-----------|-------------|
75
+ | `resize` | `(selector, { height }) => void` | Sets the height of a scroll container by selector or element reference |
76
+ | `refresh` | `(selector?) => void` | Refreshes one container (by selector/element) or all containers if no argument is given |
77
+ | `getScroll` | `(selector) => { left, top } \| undefined` | Returns the current scroll position of a container |
78
+ | `scroll` | `(selector, { left?, top?, behavior? }) => void` | Scrolls a container to a position. Unspecified axes retain their current position. |
79
+ | `getScrollContainer` | `(selector) => IScrollContainer \| undefined` | Returns the `EvoScrollContainerElement` instance for a selector or element |
80
+
81
+ ---
82
+
83
+ ## Examples
84
+
85
+ ### Vertical scroll (default)
86
+
87
+ ```astro
88
+ ---
89
+ import { ScrollContainer } from '@inizioevoke/astro-core';
90
+ ---
91
+ <ScrollContainer height={400}>
92
+ <p>Line 1</p>
93
+ <p>Line 2</p>
94
+ <!-- ... more content ... -->
95
+ </ScrollContainer>
96
+ ```
97
+
98
+ ### Horizontal scroll
99
+
100
+ ```astro
101
+ <ScrollContainer scrolling="horizontal" height={200}>
102
+ <div style="display:flex; gap:1rem; width:max-content;">
103
+ <img src="/a.jpg" />
104
+ <img src="/b.jpg" />
105
+ <img src="/c.jpg" />
106
+ </div>
107
+ </ScrollContainer>
108
+ ```
109
+
110
+ ### Both axes
111
+
112
+ ```astro
113
+ <ScrollContainer scrolling="both" width={600} height={400}>
114
+ <div style="width:1200px;">
115
+ <!-- wide + tall content -->
116
+ </div>
117
+ </ScrollContainer>
118
+ ```
119
+
120
+ ### Programmatic scroll
121
+
122
+ ```astro
123
+ <ScrollContainer id="my-scroll" height={300}>
124
+ <!-- content -->
125
+ </ScrollContainer>
126
+
127
+ <script>
128
+ const sc = document.querySelector('#my-scroll');
129
+ sc.scroll({ top: 200, behavior: 'smooth' });
130
+ </script>
131
+ ```
132
+
133
+ ### Using utility functions
134
+
135
+ ```ts
136
+ import { scroll, refresh } from '@inizioevoke/astro-core';
137
+
138
+ // Smooth-scroll to position
139
+ scroll('#my-scroll', { top: 200, behavior: 'smooth' });
140
+
141
+ // Force refresh after dynamic content insertion
142
+ refresh('#my-scroll');
143
+ ```
144
+
145
+ ### Custom scrollbar styling
146
+
147
+ ```css
148
+ evo-scroll-container {
149
+ --evo-scroll-container-track-width: 12px;
150
+ --evo-scroll-container-track-color: transparent;
151
+ --evo-scroll-container-thumb-color: rgba(0, 0, 0, 0.4);
152
+ }
153
+ ```
154
+
155
+ ### Force scrollbar visible
156
+
157
+ ```ts
158
+ const sc = document.querySelector('#my-scroll');
159
+ sc.configureScrollbar({ trackVisible: true });
160
+ ```