@inizioevoke/astro-core 2.2.9 → 2.3.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,187 @@
1
+ # BottomISI
2
+
3
+ The BottomISI component renders a custom element (`<evo-isi>`) that displays Important Safety Information anchored to the bottom of the page. It supports two modes:
4
+
5
+ - **Full-only** — the ISI is hidden by default (collapsed to `--evo-isi-collapsed-height`) and a single toggle button expands/collapses it.
6
+ - **Partial + Full** — a short teaser excerpt (`partial-isi` slot) stays visible at all times. Clicking its toggle expands the full ISI overlay on top; clicking the full ISI toggle collapses back to the partial view.
7
+
8
+ The full ISI content is wrapped in a [ScrollContainer](./ScrollContainer.md) by default. Transitions are animated with configurable duration.
9
+
10
+ ## Props
11
+
12
+ | Prop | Type | Default | Description |
13
+ |------|------|---------|-------------|
14
+ | `partial` | `object` | — | Options for the partial (teaser) panel. Only relevant when the `partial-isi` slot is used |
15
+ | `partial.renderButton` | `boolean` | `true` | Whether to render the built-in expand toggle inside the partial panel |
16
+ | `partial.buttonAttrs` | `HTMLAttributes<'button'>` | — | Additional HTML attributes spread onto the partial toggle button |
17
+ | `full` | `object` | — | Options for the full ISI panel |
18
+ | `full.renderButton` | `boolean` | `true` | Whether to render the built-in collapse/toggle button inside the full panel |
19
+ | `full.buttonAttrs` | `HTMLAttributes<'button'>` | — | Additional HTML attributes spread onto the full-panel toggle button |
20
+ | `full.scrollContainer` | `ScrollContainerProps \| false` | — | Props forwarded to the inner `ScrollContainer`. Pass `false` to render the ISI content without a scroll container |
21
+ | `transitionDuration` | `number` | — | Expand/collapse animation duration in milliseconds. Overrides `--evo-isi-transition-duration` via inline style |
22
+ | `...rest` | `HTMLAttributes<'div'>` | — | Any additional HTML attributes are passed to the `<evo-isi>` element |
23
+
24
+ ## Slots
25
+
26
+ | Slot | Description |
27
+ |------|-------------|
28
+ | *(default)* | The full ISI content. Rendered inside a `ScrollContainer` unless `full.scrollContainer` is `false` |
29
+ | `partial-isi` | Short teaser ISI content shown at the bottom at all times. When present, enables partial+full mode |
30
+ | `partial-toggle` | Custom element to replace the built-in expand button in the partial panel |
31
+ | `full-toggle` | Custom element to replace the built-in collapse/toggle button in the full panel |
32
+
33
+ ## CSS Custom Properties
34
+
35
+ | Property | Default | Description |
36
+ |----------|---------|-------------|
37
+ | `--evo-isi-collapsed-height` | `0px` | Height of `<evo-isi>` when collapsed (full-only mode) or height of the full panel before it is expanded (partial mode) |
38
+ | `--evo-isi-expanded-height` | `auto` | Target height for the full ISI panel when expanded. `auto` resolves at runtime to `min(body height, screen.availHeight)` |
39
+ | `--evo-isi-expanded-height-adjust` | `0px` | Amount subtracted from `--evo-isi-expanded-height` when expanded — useful for offsetting surrounding chrome (e.g. a sticky header) |
40
+ | `--evo-isi-transition-duration` | `333ms` | Duration for expand/collapse transitions |
41
+ | `--evo-isi-bottom` | `0px` | Bottom offset of the absolutely-positioned full panel |
42
+ | `--evo-isi-collapse-transition` | — | Full `transition` shorthand used during collapse |
43
+ | `--evo-isi-expand-transition` | — | Full `transition` shorthand used during expand |
44
+
45
+ ## JavaScript API
46
+
47
+ ### Element methods
48
+
49
+ Access the `<evo-isi>` element directly to call these methods:
50
+
51
+ | Method | Signature | Description |
52
+ |--------|-----------|-------------|
53
+ | `expand` | `() => Promise<void>` | Expands the ISI to its full height. Resolves after the transition completes. No-op if already expanded. |
54
+ | `collapse` | `() => Promise<void>` | Collapses the ISI. Scrolls the inner scroll container back to the top. Resolves after the transition completes. No-op if already collapsed. |
55
+ | `toggle` | `() => Promise<void>` | Calls `expand()` if collapsed or `collapse()` if expanded. |
56
+
57
+ ---
58
+
59
+ ## Examples
60
+
61
+ ### Full ISI only (no partial)
62
+
63
+ The ISI starts collapsed to zero height. The built-in button toggles it open and closed.
64
+
65
+ ```astro
66
+ ---
67
+ import { BottomISI } from '@inizioevoke/astro-core';
68
+ ---
69
+ <footer>
70
+ <BottomISI>
71
+ <h2>Important Safety Information</h2>
72
+ <p>Full ISI content here...</p>
73
+ </BottomISI>
74
+ </footer>
75
+ ```
76
+
77
+ ### With a partial teaser
78
+
79
+ The partial excerpt is always visible. Clicking it expands the full ISI on top.
80
+
81
+ ```astro
82
+ ---
83
+ import { BottomISI } from '@inizioevoke/astro-core';
84
+ ---
85
+ <footer>
86
+ <BottomISI>
87
+ <Fragment slot="partial-isi">
88
+ <h2>Important Safety Information</h2>
89
+ <p>Brief teaser excerpt...</p>
90
+ </Fragment>
91
+
92
+ <h2>Important Safety Information</h2>
93
+ <p>Complete ISI content...</p>
94
+ </BottomISI>
95
+ </footer>
96
+ ```
97
+
98
+ ### Fixed collapsed height (IVA / kiosk)
99
+
100
+ Set a visible collapsed height so the ISI is always partially shown even before expanding.
101
+
102
+ ```astro
103
+ ---
104
+ import { BottomISI } from '@inizioevoke/astro-core';
105
+ ---
106
+ <style>
107
+ footer evo-isi {
108
+ --evo-isi-collapsed-height: 150px;
109
+ --evo-isi-expanded-height: calc(1024px - 2rem);
110
+ }
111
+ </style>
112
+ <footer style="position: absolute; bottom: 0; width: 100%;">
113
+ <BottomISI>
114
+ <h2>Important Safety Information</h2>
115
+ <p>ISI content...</p>
116
+ </BottomISI>
117
+ </footer>
118
+ ```
119
+
120
+ ### Disable the scroll container
121
+
122
+ Render the full ISI content directly without a scroll container.
123
+
124
+ ```astro
125
+ <BottomISI full={{ scrollContainer: false }}>
126
+ <p>ISI content...</p>
127
+ </BottomISI>
128
+ ```
129
+
130
+ ### Custom toggle buttons
131
+
132
+ Replace the built-in toggle with your own markup using the named slots.
133
+
134
+ ```astro
135
+ <BottomISI partial={{ renderButton: false }} full={{ renderButton: false }}>
136
+ <Fragment slot="partial-toggle">
137
+ <button class="my-expand-btn">Show Full ISI ▲</button>
138
+ </Fragment>
139
+ <Fragment slot="full-toggle">
140
+ <button class="my-collapse-btn">Close ▼</button>
141
+ </Fragment>
142
+
143
+ <Fragment slot="partial-isi">
144
+ <p>Teaser content...</p>
145
+ </Fragment>
146
+
147
+ <p>Full ISI content...</p>
148
+ </BottomISI>
149
+ ```
150
+
151
+ ### Programmatic control
152
+
153
+ ```astro
154
+ <BottomISI id="page-isi">
155
+ <p>ISI content...</p>
156
+ </BottomISI>
157
+
158
+ <script>
159
+ import type { IEvoIsiElement } from '@inizioevoke/astro-core';
160
+
161
+ const isi = document.querySelector<IEvoIsiElement>('#page-isi');
162
+
163
+ document.querySelector('#open-btn').addEventListener('click', () => {
164
+ isi?.expand();
165
+ });
166
+
167
+ document.querySelector('#close-btn').addEventListener('click', () => {
168
+ isi?.collapse();
169
+ });
170
+ </script>
171
+ ```
172
+
173
+ ### Custom transition duration
174
+
175
+ ```astro
176
+ <!-- Via prop (sets inline CSS variable) -->
177
+ <BottomISI transitionDuration={500}>
178
+ <p>ISI content...</p>
179
+ </BottomISI>
180
+
181
+ <!-- Via CSS -->
182
+ <style>
183
+ evo-isi {
184
+ --evo-isi-transition-duration: 500ms;
185
+ }
186
+ </style>
187
+ ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inizioevoke/astro-core",
3
- "version": "2.2.9",
3
+ "version": "2.3.1",
4
4
  "description": "",
5
5
  "license": "ISC",
6
6
  "author": "",
@@ -11,11 +11,12 @@
11
11
  "./integrations": "./src/integrations/index.ts",
12
12
  "./lib": "./src/lib/index.ts",
13
13
  "./lib/FlipCard": "./src/components/FlipCard/index.ts",
14
- "./lib/ISI": "./src/components/ISI/index.ts",
14
+ "./lib/BottomISI": "./src/components/BottomISI/index.ts",
15
15
  "./lib/Modal": "./src/components/Modal/index.ts",
16
16
  "./lib/PdfViewer": "./src/components/PdfViewer/index.ts",
17
17
  "./lib/ScrollContainer": "./src/components/ScrollContainer/index.ts",
18
- "./lib/gestures": "./src/lib/gestures/index.ts"
18
+ "./lib/gestures": "./src/lib/gestures/index.ts",
19
+ "./server": "./src/server/index.ts"
19
20
  },
20
21
  "scripts": {
21
22
  "postinstall": "node postinstall.mjs"
@@ -0,0 +1,85 @@
1
+ ---
2
+ import type { HTMLAttributes, HTMLTag } from 'astro/types';
3
+ import { addCssClassToAttrs } from '@/server/index';
4
+ import ScrollContainer, { type Props as ScrollContainerProps } from '../../ScrollContainer/ScrollContainer.astro';
5
+ import './BottomISI.css';
6
+
7
+ export interface Props extends HTMLAttributes<'div'> {
8
+ partial?: {
9
+ renderButton?: boolean;
10
+ buttonAttrs?: HTMLAttributes<'button'>;
11
+ }
12
+ full?: {
13
+ renderButton?: boolean;
14
+ buttonAttrs?: HTMLAttributes<'button'>;
15
+ scrollContainer?: false | ScrollContainerProps;
16
+ }
17
+ transitionDuration?: number;
18
+ }
19
+
20
+ const {
21
+ partial,
22
+ full,
23
+ transitionDuration,
24
+ ...rest
25
+ } = Astro.props;
26
+
27
+ const attrs: HTMLAttributes<'div'> = {
28
+ ...rest
29
+ };
30
+
31
+ const style = [];
32
+ if (typeof transitionDuration == 'number') {
33
+ style.push(`--evo-isi-transition-duration:${transitionDuration}ms`);
34
+ }
35
+ if (typeof attrs.style == 'string') {
36
+ style.push(attrs.style);
37
+ if (!attrs.style.endsWith(';')) {
38
+ style.push('');
39
+ }
40
+ } else {
41
+ style.push('');
42
+ }
43
+ attrs.style = style.join(';');
44
+
45
+ const partialButtonAttrs: HTMLAttributes<'button'> = {...partial?.buttonAttrs};
46
+ addCssClassToAttrs(partialButtonAttrs, 'evo-isi-toggle');
47
+
48
+ const fullButtonAttrs: HTMLAttributes<'button'> = {...full?.buttonAttrs};
49
+ addCssClassToAttrs(fullButtonAttrs, 'evo-isi-toggle');
50
+
51
+ ---
52
+ <evo-isi {...attrs}>
53
+ { Astro.slots.has('partial-isi') &&
54
+ <div class="evo-isi-partial-wrapper">
55
+ <div class="evo-isi-toggle-wrapper">
56
+ {partial?.renderButton !== false &&
57
+ <slot name="partial-toggle"><button {...partialButtonAttrs}></button></slot>
58
+ }
59
+ </div>
60
+ <div class="evo-isi-text">
61
+ <slot name="partial-isi" />
62
+ </div>
63
+ </div>
64
+ }
65
+ <div class="evo-isi-full-wrapper">
66
+ <div class="evo-isi-toggle-wrapper">
67
+ {full?.renderButton !== false &&
68
+ <slot name="full-toggle"><button {...fullButtonAttrs}></button></slot>
69
+ }
70
+ </div>
71
+ <div class="evo-isi-text">
72
+ { full?.scrollContainer !== false &&
73
+ <ScrollContainer {...full?.scrollContainer}>
74
+ <slot />
75
+ </ScrollContainer>
76
+ }
77
+ { full?.scrollContainer === false &&
78
+ <slot />
79
+ }
80
+ </div>
81
+ </div>
82
+ </evo-isi>
83
+ <script>
84
+ import './BottomISI';
85
+ </script>
@@ -0,0 +1,161 @@
1
+ @layer inizioevoke-astro-components {
2
+ :root {
3
+ --evo-isi-collapsed-height: 0px;
4
+ --evo-isi-expanded-height: auto;
5
+ --evo-isi-expanded-height-adjust: 0px;
6
+
7
+ --evo-isi-transition-duration: 333ms;
8
+
9
+ --evo-isi-bottom: 0px;
10
+ --evo-isi-height: var(--evo-isi-collapsed-height);
11
+
12
+
13
+ --evo-isi-collapse-transition-height: height var(--evo-isi-transition-duration) linear;
14
+ --evo-isi-collapse-transition: var(--evo-isi-collapse-transition-height), top var(--evo-isi-transition-duration) linear, opacity calc(var(--evo-isi-transition-duration) / 3) linear calc(var(--evo-isi-transition-duration) / 3 * 2);
15
+
16
+ --evo-isi-expand-transition-height: height var(--evo-isi-transition-duration) linear;
17
+ --evo-isi-expand-transition: var(--evo-isi-expand-transition-height), top var(--evo-isi-transition-duration) linear, opacity calc(var(--evo-isi-transition-duration) / 3) linear;
18
+ }
19
+ evo-isi {
20
+ position: relative;
21
+ left: 0;
22
+ top: 0;
23
+ display: block;
24
+ width: 100%;
25
+ height: auto;
26
+
27
+ .evo-isi-partial-wrapper {
28
+ position: relative;
29
+ background-color: white;
30
+ z-index: 1;
31
+ .evo-isi-toggle-wrapper {
32
+ .evo-isi-toggle {
33
+ position: absolute;
34
+ right: 24px;
35
+ top: 0px;
36
+ width: 24px;
37
+ height: 24px;
38
+ margin: 0;
39
+ padding: 0;
40
+ text-align: left;
41
+ text-indent: -9999px;
42
+ border: 2px solid black;
43
+ border-radius: 50%;
44
+ background-color: white;
45
+ cursor: pointer;
46
+ z-index: 1;
47
+ &::before {
48
+ content: '';
49
+ position: absolute;
50
+ left: calc(50% - 6px);
51
+ top: calc(50% - 1px);
52
+ width: 12px;
53
+ height: 2px;
54
+ background-color: black;
55
+ }
56
+ &::after {
57
+ content: '';
58
+ position: absolute;
59
+ left: calc(50% - 1px);
60
+ top: calc(50% - 6px);
61
+ width: 2px;
62
+ height: 12px;
63
+ background-color: black;
64
+ }
65
+ }
66
+ }
67
+
68
+ .evo-isi-text {
69
+ }
70
+ }
71
+
72
+ .evo-isi-full-wrapper {
73
+ position: absolute;
74
+ bottom: var(--evo-isi-bottom);
75
+ height: var(--evo-isi-height);
76
+ overflow: hidden;
77
+ background-color: white;
78
+ opacity: 0;
79
+ transition: var(--evo-isi-collapse-transition);
80
+ z-index: 2;
81
+
82
+ .evo-isi-toggle-wrapper {
83
+ .evo-isi-toggle {
84
+ position: absolute;
85
+ right: 24px;
86
+ top: 0px;
87
+ width: 24px;
88
+ height: 24px;
89
+ margin: 0;
90
+ padding: 0;
91
+ text-align: left;
92
+ text-indent: -9999px;
93
+ border: 2px solid black;
94
+ border-radius: 50%;
95
+ background-color: white;
96
+ cursor: pointer;
97
+ z-index: 1;
98
+ &::before {
99
+ content: '';
100
+ position: absolute;
101
+ left: calc(50% - 6px);
102
+ top: calc(50% - 1px);
103
+ width: 12px;
104
+ height: 2px;
105
+ background-color: black;
106
+ }
107
+ }
108
+ }
109
+
110
+ .evo-isi-text {
111
+ /* height: var(--evo-isi-height); */
112
+ overflow: hidden;
113
+
114
+ .evo-scroll-container {
115
+ height: var(--evo-isi-height);
116
+ transition: var(--evo-isi-collapse-transition-height);
117
+ }
118
+ }
119
+ }
120
+
121
+
122
+ &:not(:has(.evo-isi-partial-wrapper)) {
123
+ --evo-isi-height: var(--evo-isi-collapsed-height);
124
+ height: var(--evo-isi-height);
125
+
126
+ .evo-isi-full-wrapper {
127
+ opacity: 1;
128
+ .evo-isi-toggle-wrapper {
129
+ .evo-isi-toggle {
130
+ &::after {
131
+ content: '';
132
+ position: absolute;
133
+ left: calc(50% - 1px);
134
+ top: calc(50% - 6px);
135
+ width: 2px;
136
+ height: 12px;
137
+ background-color: black;
138
+ }
139
+ }
140
+ }
141
+ }
142
+ }
143
+
144
+ &.evo-isi-expand {
145
+
146
+ .evo-isi-full-wrapper {
147
+ --evo-isi-height: calc(var(--evo-isi-expanded-height) - var(--evo-isi-expanded-height-adjust));
148
+ opacity: 1;
149
+
150
+ transition: var(--evo-isi-expand-transition);
151
+ .evo-isi-text {
152
+ transition: var(--evo-isi-expand-transition-height);
153
+
154
+ .evo-scroll-container {
155
+ /* height: var(--evo-isi-expanded-height); */
156
+ }
157
+ }
158
+ }
159
+ }
160
+ }
161
+ }
@@ -0,0 +1,113 @@
1
+ import { EvoScrollContainerElement } from '../../ScrollContainer/ScrollContainer';
2
+ import type { IEvoIsiElement } from '../index.d.ts';
3
+
4
+ const TAG_NAME = 'evo-isi';
5
+
6
+ export { IEvoIsiElement };
7
+ export class EvoIsiElement extends HTMLElement implements IEvoIsiElement {
8
+ #scrollContainer: EvoScrollContainerElement | null = null;
9
+ #transitionDuration: number | null = null;
10
+
11
+ constructor() {
12
+ super();
13
+
14
+ window.addEventListener('DOMContentLoaded', () => {
15
+ });
16
+ }
17
+
18
+ connectedCallback() {
19
+ this.#scrollContainer = this.querySelector<EvoScrollContainerElement>('.evo-scroll-container');
20
+
21
+ const partialWrapper = this.querySelector<HTMLElement>('.evo-isi-partial-wrapper');
22
+
23
+ partialWrapper?.querySelector<HTMLElement>('.evo-isi-toggle-wrapper')?.querySelector<HTMLElement>('button, [role="button"]')?.addEventListener('click', (e) => {
24
+ e.preventDefault();
25
+ this.expand();
26
+ });
27
+
28
+ this.querySelector<HTMLElement>('.evo-isi-full-wrapper .evo-isi-toggle-wrapper')?.querySelector<HTMLElement>('button, [role="button"]')?.addEventListener('click', (e) => {
29
+ e.preventDefault();
30
+ partialWrapper ? this.collapse() : this.toggle();
31
+ });
32
+ }
33
+
34
+ toggle() {
35
+ if (!this.classList.contains('evo-isi-expand')) {
36
+ return this.expand();
37
+ } else {
38
+ return this.collapse();
39
+ }
40
+ }
41
+
42
+ expand() {
43
+ return new Promise<void>((resolve) => {
44
+ if (!this.classList.contains('evo-isi-expand')) {
45
+ const style = getComputedStyle(this);
46
+ this.#initTransitionDuration(style);
47
+ if (style.getPropertyValue('--evo-isi-expanded-height') === 'auto') {
48
+ this.style.setProperty('--evo-isi-expanded-height', `${Math.min(parseInt(getComputedStyle(document.body).height, 10), screen.availHeight)}px`);
49
+ }
50
+
51
+ this.classList.add('evo-isi-expand');
52
+ let animating = true;
53
+ if (this.#scrollContainer) {
54
+ const refresh = () => {
55
+ if (animating) {
56
+ this.#scrollContainer!.refresh();
57
+ requestAnimationFrame(refresh);
58
+ }
59
+ }
60
+ refresh();
61
+ }
62
+ setTimeout(() => {
63
+ animating = false;
64
+ resolve();
65
+ }, this.#transitionDuration);
66
+ } else {
67
+ resolve();
68
+ }
69
+ });
70
+ }
71
+
72
+ collapse() {
73
+ return new Promise<void>((resolve) => {
74
+ if (this.classList.contains('evo-isi-expand')) {
75
+ this.#initTransitionDuration();
76
+
77
+ this.classList.remove('evo-isi-expand');
78
+ let animating = true;
79
+ if (this.#scrollContainer) {
80
+ this.#scrollContainer.scrollTo({ top: 0, behavior: 'smooth' });
81
+ const refresh = () => {
82
+ if (animating) {
83
+ this.#scrollContainer!.refresh();
84
+ requestAnimationFrame(refresh);
85
+ }
86
+ }
87
+ refresh();
88
+ }
89
+ setTimeout(() => {
90
+ animating = false;
91
+ resolve();
92
+ }, this.#transitionDuration);
93
+ } else {
94
+ resolve();
95
+ }
96
+ });
97
+ }
98
+
99
+ #initTransitionDuration(style?: CSSStyleDeclaration) {
100
+ if (!this.#transitionDuration) {
101
+ style = style ?? getComputedStyle(this);
102
+ const duration = style.getPropertyValue('--evo-isi-transition-duration');
103
+ if (duration) {
104
+ this.#transitionDuration = parseInt(duration, 10) * (/\d+ms/.test(duration) ? 1 : 1000);
105
+ } else {
106
+ this.#transitionDuration = 500;
107
+ }
108
+ }
109
+ }
110
+ }
111
+ if (!customElements.get(TAG_NAME)) {
112
+ customElements.define(TAG_NAME, EvoIsiElement);
113
+ }
@@ -0,0 +1,68 @@
1
+ ---
2
+ import type { HTMLAttributes } from 'astro/types';
3
+ import ScrollContainer, { type Props as ScrollContainerProps } from '../../ScrollContainer/ScrollContainer.astro';
4
+ import './BottomScrollableISI.css';
5
+
6
+ export interface Props extends HTMLAttributes<'div'> {
7
+ scrollContainer?: false | ScrollContainerProps;
8
+ toggleButton?: boolean;
9
+ transitionDuration?: number;
10
+ height?: number | string;
11
+ }
12
+
13
+ const {
14
+ scrollContainer,
15
+ toggleButton,
16
+ transitionDuration,
17
+ height,
18
+ ...rest
19
+ } = Astro.props;
20
+
21
+ const attrs: HTMLAttributes<'div'> = {
22
+ ...rest
23
+ };
24
+
25
+ const style = [];
26
+ if (typeof transitionDuration == 'number') {
27
+ style.push(`--evo-isi-transition-duration:${transitionDuration}ms`);
28
+ }
29
+ if (height) {
30
+ style.push(`height:${typeof height == 'number' ? `${height}px` : height}`);
31
+ }
32
+ if (typeof attrs.style == 'string') {
33
+ style.push(attrs.style);
34
+ if (!attrs.style.endsWith(';')) {
35
+ style.push('');
36
+ }
37
+ } else {
38
+ style.push('');
39
+ }
40
+ attrs.style = style.join(';');
41
+
42
+ const scrollContainerProps = {...scrollContainer};
43
+ if (!scrollContainerProps.height) {
44
+ scrollContainerProps.height = height;
45
+ }
46
+ ---
47
+ <evo-isi {...attrs}>
48
+ <div class="evo-isi-wrapper">
49
+ <div class="evo-isi-toggle-wrapper">
50
+ {toggleButton !== false &&
51
+ <slot name="toggle"><button class="evo-isi-toggle"></button></slot>
52
+ }
53
+ </div>
54
+ <div class="evo-isi-text">
55
+ {scrollContainer !== false &&
56
+ <ScrollContainer {...scrollContainerProps}>
57
+ <slot />
58
+ </ScrollContainer>
59
+ }
60
+ {scrollContainer === false &&
61
+ <slot />
62
+ }
63
+ </div>
64
+ </div>
65
+ </evo-isi>
66
+ <script>
67
+ import './BottomScrollableISI';
68
+ </script>
@@ -0,0 +1,110 @@
1
+ @layer inizioevoke-astro-components {
2
+ :root {
3
+ --evo-isi-collapsed-height: 200px;
4
+ --evo-isi-collapsed-top: 0px;
5
+ --evo-isi-expanded-height: 976px;
6
+ --evo-isi-expanded-top: -776px;
7
+ --evo-isi-transition-duration: 350ms;
8
+ --evo-isi-height: var(--evo-isi-collapsed-height);
9
+ --evo-isi-top: var(--evo-isi-collapsed-top);
10
+ }
11
+ evo-isi {
12
+ position: absolute;
13
+ left: 0;
14
+ top: var(--evo-isi-top);
15
+ display: block;
16
+ width: 100%;
17
+ height: var(--evo-isi-height);
18
+ transition-duration: var(--evo-isi-transition-duration);
19
+ transition-property: top, height;
20
+ transition-timing-function: ease-out;
21
+ background-color: white;
22
+
23
+ .evo-isi-wrapper {
24
+ position: relative;
25
+ .evo-isi-toggle-wrapper {
26
+ .evo-isi-toggle {
27
+ position: absolute;
28
+ right: 24px;
29
+ top: 0px;
30
+ width: 24px;
31
+ height: 24px;
32
+ margin: 0;
33
+ padding: 0;
34
+ text-align: left;
35
+ text-indent: -9999px;
36
+ border: 2px solid black;
37
+ border-radius: 50%;
38
+ background-color: transparent;
39
+ cursor: pointer;
40
+ z-index: 1;
41
+ &::before {
42
+ content: '';
43
+ position: absolute;
44
+ left: calc(50% - 6px);
45
+ top: calc(50% - 1px);
46
+ width: 12px;
47
+ height: 2px;
48
+ background-color: black;
49
+ transform: rotate(0deg);
50
+ transform-origin: center center;
51
+ transition-duration: var(--evo-isi-transition-duration);
52
+ transition-property: transform;
53
+ transition-timing-function: ease-out;
54
+ }
55
+ &::after {
56
+ content: '';
57
+ position: absolute;
58
+ left: calc(50% - 1px);
59
+ top: calc(50% - 6px);
60
+ width: 2px;
61
+ height: 12px;
62
+ background-color: black;
63
+ transform: rotate(0deg);
64
+ transform-origin: center center;
65
+ transition-duration: var(--evo-isi-transition-duration);
66
+ transition-property: transform;
67
+ transition-timing-function: ease-out;
68
+ }
69
+ }
70
+ }
71
+
72
+ .evo-isi-text {
73
+ /* height: var(--evo-isi-height); */
74
+ overflow: hidden;
75
+
76
+ .evo-scroll-container {
77
+ height: var(--evo-isi-height);
78
+ transition-duration: var(--evo-isi-transition-duration);
79
+ transition-property: height;
80
+ transition-timing-function: ease-out;
81
+ }
82
+ }
83
+ }
84
+
85
+ &.evo-isi-expand {
86
+ --evo-isi-height: var(--evo-isi-expanded-height);
87
+ --evo-isi-top: var(--evo-isi-expanded-top);
88
+
89
+ .evo-isi-wrapper {
90
+ .evo-isi-toggle-wrapper {
91
+ .evo-isi-toggle {
92
+ &::before {
93
+ transform: rotate(180deg);
94
+ }
95
+ &::after {
96
+ transform: rotate(90deg);
97
+ }
98
+ }
99
+ }
100
+ .evo-isi-text {
101
+ /* height: var(--evo-isi-expanded-height); */
102
+
103
+ .evo-scroll-container {
104
+ /* height: var(--evo-isi-expanded-height); */
105
+ }
106
+ }
107
+ }
108
+ }
109
+ }
110
+ }
@@ -0,0 +1,89 @@
1
+ import { EvoScrollContainerElement } from '../../ScrollContainer/ScrollContainer';
2
+ import type { IEvoIsiElement } from '../index.d.ts';
3
+
4
+ const TAG_NAME = 'evo-isi';
5
+
6
+ export class EvoIsiElement extends HTMLElement implements IEvoIsiElement {
7
+ #scrollContainer: EvoScrollContainerElement | null = null;
8
+ #transitionDuration = 500;
9
+
10
+ constructor() {
11
+ super();
12
+
13
+ window.addEventListener('DOMContentLoaded', () => {
14
+ const style = getComputedStyle(this);
15
+ const duration = style.getPropertyValue('--evo-isi-transition-duration');
16
+ if (duration) {
17
+ this.#transitionDuration = parseInt(duration, 10) * (/\d+ms/.test(duration) ? 1 : 1000);
18
+ }
19
+ });
20
+ }
21
+
22
+ connectedCallback() {
23
+ this.#scrollContainer = this.querySelector<EvoScrollContainerElement>('.evo-scroll-container');
24
+ this.querySelector<HTMLElement>('.evo-isi-toggle-wrapper')?.querySelector<HTMLElement>('button, [role="button"]')?.addEventListener('click', (e) => {
25
+ e.preventDefault();
26
+ this.toggle();
27
+ });
28
+ }
29
+
30
+ toggle() {
31
+ if (!this.classList.contains('evo-isi-expand')) {
32
+ return this.expand();
33
+ } else {
34
+ return this.collapse();
35
+ }
36
+ }
37
+
38
+ expand() {
39
+ return new Promise<void>((resolve) => {
40
+ if (!this.classList.contains('evo-isi-expand')) {
41
+ this.classList.add('evo-isi-expand');
42
+ let animating = true;
43
+ if (this.#scrollContainer) {
44
+ const refresh = () => {
45
+ if (animating) {
46
+ this.#scrollContainer!.refresh();
47
+ requestAnimationFrame(refresh);
48
+ }
49
+ }
50
+ refresh();
51
+ }
52
+ setTimeout(() => {
53
+ animating = false;
54
+ resolve();
55
+ }, this.#transitionDuration);
56
+ } else {
57
+ resolve();
58
+ }
59
+ });
60
+ }
61
+
62
+ collapse() {
63
+ return new Promise<void>((resolve) => {
64
+ if (this.classList.contains('evo-isi-expand')) {
65
+ this.classList.remove('evo-isi-expand');
66
+ let animating = true;
67
+ if (this.#scrollContainer) {
68
+ this.#scrollContainer.scrollTo({ top: 0, behavior: 'smooth' });
69
+ const refresh = () => {
70
+ if (animating) {
71
+ this.#scrollContainer!.refresh();
72
+ requestAnimationFrame(refresh);
73
+ }
74
+ }
75
+ refresh();
76
+ }
77
+ setTimeout(() => {
78
+ animating = false;
79
+ resolve();
80
+ }, this.#transitionDuration);
81
+ } else {
82
+ resolve();
83
+ }
84
+ });
85
+ }
86
+ }
87
+ if (!customElements.get(TAG_NAME)) {
88
+ customElements.define(TAG_NAME, EvoIsiElement);
89
+ }
@@ -0,0 +1 @@
1
+ export * from './BottomISI';
@@ -6,7 +6,7 @@ import './RightISI.css';
6
6
  export interface Props extends HTMLAttributes<'div'> {
7
7
  scrollContainer?: ScrollContainerProps;
8
8
  headerButton?: boolean;
9
- transitionDuration?: number
9
+ transitionDuration?: number;
10
10
  }
11
11
 
12
12
  const {
@@ -32,7 +32,7 @@ const renderHeader = Astro.slots.has('header') || renderHeaderButton;
32
32
  <slot name="header" />
33
33
  {renderHeaderButton &&
34
34
  <div class="evo-isi-header-button">
35
- <slot name="header-button"><button class="evo-isi-toggle">Expand</button></slot>
35
+ <slot name="header-button"><button class="evo-isi-toggle"></button></slot>
36
36
  </div>}
37
37
  </div>}
38
38
  <div class="evo-isi-text">
@@ -33,6 +33,9 @@
33
33
  .evo-isi-header {
34
34
  height: var(--evo-isi-header-height);
35
35
  }
36
+ .evo-isi-toggle::before {
37
+ content: "\21D4";
38
+ }
36
39
  .evo-isi-text {
37
40
  height: calc(
38
41
  var(--evo-isi-height) -
@@ -45,9 +48,6 @@
45
48
  var(--evo-isi-footer-padding-top) -
46
49
  var(--evo-isi-footer-padding-bottom)
47
50
  );
48
- evo-scroll-container {
49
-
50
- }
51
51
  }
52
52
  .evo-isi-footer {
53
53
  height: var(--evo-isi-footer-height);
@@ -1,8 +1,9 @@
1
1
  import { EvoScrollContainerElement } from '../../ScrollContainer/ScrollContainer';
2
- import type { IEvoIsiElement } from '../index';
2
+ import type { IEvoIsiElement } from '../index.d.ts';
3
3
 
4
4
  const TAG_NAME = 'evo-isi';
5
5
 
6
+ export { IEvoIsiElement };
6
7
  export class EvoIsiElement extends HTMLElement implements IEvoIsiElement {
7
8
  #scrollContainer!: EvoScrollContainerElement;
8
9
  #transitionDuration = 500;
@@ -0,0 +1,5 @@
1
+ export interface IEvoIsiElement {
2
+ toggle: () => Promise<void>;
3
+ expand: () => Promise<void>;
4
+ collapse: () => Promise<void>;
5
+ }
@@ -88,6 +88,7 @@ const scrollContainerScrolling: Scrolling = toolbar === undefined || (toolbar &&
88
88
  <slot name="toolbar-zoom-out">
89
89
  <svg class="evo-pdf-viewer-toolbar-icon" width="16px" height="16px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
90
90
  <path d="M6 12L18 12" stroke="#000000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
91
+ </svg>
91
92
  </slot>
92
93
  </button>
93
94
  <button class="evo-pdf-viewer-toolbar-zoom-in" title="Zoom in">
@@ -16,10 +16,20 @@ export {
16
16
  type Props as FlipCardProps,
17
17
  } from "./FlipCard/FlipCard.astro";
18
18
 
19
+ export {
20
+ default as BottomISI,
21
+ type Props as BottomISIProps
22
+ } from "./ISI/BottomISI/BottomISI.astro";
23
+
24
+ // export {
25
+ // default as BottomScrollableISI,
26
+ // type Props as BottomScrollableISIProps
27
+ // } from "./ISI/Bottom/BottomScrollableISI.astro";
28
+
19
29
  export {
20
30
  default as RightISI,
21
31
  type Props as RightISIProps,
22
- } from "./ISI/Right/RightISI.astro";
32
+ } from "./ISI/RightISI/RightISI.astro";
23
33
 
24
34
  export {
25
35
  default as Modal,
@@ -0,0 +1,12 @@
1
+ import type { HTMLAttributes, HTMLTag } from 'astro/types';
2
+
3
+ export function addCssClassToAttrs<T extends HTMLTag>(attrs: HTMLAttributes<T>, cssClass: string | string[]) {
4
+ if (attrs['class:list']) {
5
+ attrs['class:list'] = [attrs['class:list'], ...(typeof cssClass == 'string' ? [cssClass] : cssClass)];
6
+ } else if (attrs['class']) {
7
+ attrs['class:list'] = [attrs['class'], ...(typeof cssClass == 'string' ? [cssClass] : cssClass)];
8
+ delete attrs['class'];
9
+ } else {
10
+ attrs['class:list'] = typeof cssClass == 'string' ? [cssClass] : cssClass;
11
+ }
12
+ }
@@ -1,5 +0,0 @@
1
- export interface IEvoIsiElement {
2
- toggle: () => void;
3
- expand: () => void;
4
- collapse: () => void;
5
- }
File without changes