@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.
- package/docs/components/CssBackgroundImage.md +59 -0
- package/docs/components/CssVariables.md +64 -0
- package/docs/components/FlipCard.md +113 -0
- package/docs/components/Modal.md +211 -0
- package/docs/components/ScrollContainer.md +160 -0
- package/docs/components/Tabs.md +102 -0
- package/docs/integrations/prune-build.md +75 -0
- package/docs/integrations/relative-links.md +53 -0
- package/docs/lib/pinch.md +98 -0
- package/docs/lib/swipe.md +147 -0
- package/package.json +2 -1
- package/src/components/CssBackgroundImage.astro +103 -0
- package/src/components/CssVariables.astro +129 -0
- package/src/components/FlipCard/FlipCard.astro +2 -2
- package/src/components/Modal/Modal.ts +4 -4
- package/src/components/ScrollContainer/ScrollContainer.astro +5 -1
- package/src/components/ScrollContainer/ScrollContainer.ts +13 -22
- package/src/components/Tabs/TabItem.astro +1 -2
- package/src/components/Tabs/Tabs.astro +2 -3
- package/src/components/index.ts +2 -0
- package/src/integrations/prune-build.ts +33 -25
- package/src/lib/gestures/pinch.ts +62 -15
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# Tabs
|
|
2
|
+
|
|
3
|
+
The Tabs component renders a tabbed panel interface. Each tab is defined by a `TabItem` child component. `Tabs` processes its slot at build time, extracts tab metadata from each `TabItem`, and generates the tab list and panels from a single slot.
|
|
4
|
+
|
|
5
|
+
## Components
|
|
6
|
+
|
|
7
|
+
### `Tabs`
|
|
8
|
+
|
|
9
|
+
The outer container that renders the tab list and panels.
|
|
10
|
+
|
|
11
|
+
#### Props
|
|
12
|
+
|
|
13
|
+
| Prop | Type | Default | Description |
|
|
14
|
+
|------|------|---------|-------------|
|
|
15
|
+
| `listType` | `'ul' \| 'none'` | `'ul'` | Controls the tab list element. `'ul'` wraps each tab button in an `<li>` (default); `'none'` renders buttons directly in a `<div>` |
|
|
16
|
+
|
|
17
|
+
#### Slots
|
|
18
|
+
|
|
19
|
+
| Slot | Description |
|
|
20
|
+
|------|-------------|
|
|
21
|
+
| *(default)* | One or more `<TabItem>` components |
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
### `TabItem`
|
|
26
|
+
|
|
27
|
+
Defines a single tab. Rendered as a child of `Tabs`. The tab button label comes from the `title` slot; the panel content comes from the default slot.
|
|
28
|
+
|
|
29
|
+
#### Props
|
|
30
|
+
|
|
31
|
+
| Prop | Type | Default | Description |
|
|
32
|
+
|------|------|---------|-------------|
|
|
33
|
+
| `active` | `true` | — | Marks this tab as the initially active one. Omit on all others. |
|
|
34
|
+
| `tabAttrs` | `HTMLAttributes<'div'>` | — | Attributes spread onto the generated tab button. `title` here sets the button label as a fallback if the `title` slot is empty. |
|
|
35
|
+
| `panelAttrs` | `HTMLAttributes<'div'>` | — | Attributes spread onto the panel `<div role="tabpanel">` |
|
|
36
|
+
|
|
37
|
+
#### Slots
|
|
38
|
+
|
|
39
|
+
| Slot | Description |
|
|
40
|
+
|------|-------------|
|
|
41
|
+
| `title` | The tab button label |
|
|
42
|
+
| *(default)* | The panel content shown when this tab is active |
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## Examples
|
|
47
|
+
|
|
48
|
+
### Basic tabs
|
|
49
|
+
|
|
50
|
+
```astro
|
|
51
|
+
---
|
|
52
|
+
import { Tabs, TabItem } from '@inizioevoke/astro-core';
|
|
53
|
+
---
|
|
54
|
+
<Tabs>
|
|
55
|
+
<TabItem active>
|
|
56
|
+
<span slot="title">First</span>
|
|
57
|
+
<p>Content for the first tab.</p>
|
|
58
|
+
</TabItem>
|
|
59
|
+
<TabItem>
|
|
60
|
+
<span slot="title">Second</span>
|
|
61
|
+
<p>Content for the second tab.</p>
|
|
62
|
+
</TabItem>
|
|
63
|
+
<TabItem>
|
|
64
|
+
<span slot="title">Third</span>
|
|
65
|
+
<p>Content for the third tab.</p>
|
|
66
|
+
</TabItem>
|
|
67
|
+
</Tabs>
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### Button-style tabs (`listType="none"`)
|
|
71
|
+
|
|
72
|
+
Renders tab buttons in a `<div>` instead of a `<ul>/<li>` structure — useful when you want a button-bar style rather than a classic tabbed nav.
|
|
73
|
+
|
|
74
|
+
```astro
|
|
75
|
+
<Tabs listType="none">
|
|
76
|
+
<TabItem active>
|
|
77
|
+
<span slot="title">Overview</span>
|
|
78
|
+
<p>Overview content.</p>
|
|
79
|
+
</TabItem>
|
|
80
|
+
<TabItem>
|
|
81
|
+
<span slot="title">Details</span>
|
|
82
|
+
<p>Details content.</p>
|
|
83
|
+
</TabItem>
|
|
84
|
+
</Tabs>
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Custom attributes on tabs and panels
|
|
88
|
+
|
|
89
|
+
Use `tabAttrs` to add attributes to the tab button (e.g. `id`, `aria-*`), and `panelAttrs` to add attributes to the panel element.
|
|
90
|
+
|
|
91
|
+
```astro
|
|
92
|
+
<Tabs>
|
|
93
|
+
<TabItem
|
|
94
|
+
active
|
|
95
|
+
tabAttrs={{ id: 'tab-1', 'aria-controls': 'panel-1' }}
|
|
96
|
+
panelAttrs={{ id: 'panel-1' }}
|
|
97
|
+
>
|
|
98
|
+
<span slot="title">Tab One</span>
|
|
99
|
+
<p>Panel content.</p>
|
|
100
|
+
</TabItem>
|
|
101
|
+
</Tabs>
|
|
102
|
+
```
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# prune-build
|
|
2
|
+
|
|
3
|
+
An Astro integration that removes unreferenced assets from the build output after `astro build` completes. It scans all `.css`, `.html`, and `.js` files in the output directory and deletes any asset whose filename does not appear in any of those files.
|
|
4
|
+
|
|
5
|
+
## Usage
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
// astro.config.mjs
|
|
9
|
+
import { defineConfig } from 'astro/config';
|
|
10
|
+
import { pruneBuild } from '@inizioevoke/astro-core/integrations';
|
|
11
|
+
|
|
12
|
+
export default defineConfig({
|
|
13
|
+
integrations: [pruneBuild()],
|
|
14
|
+
});
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Options
|
|
18
|
+
|
|
19
|
+
| Option | Type | Default | Description |
|
|
20
|
+
|--------|------|---------|-------------|
|
|
21
|
+
| `enabled` | `boolean` | `true` | Set to `false` to skip pruning entirely. Useful for disabling conditionally (e.g. in dev/preview environments). |
|
|
22
|
+
| `keep` | `(string \| RegExp)[]` | `[]` | Assets to retain even if unreferenced. Strings are matched by exact relative path; RegExps are tested against the relative path. |
|
|
23
|
+
|
|
24
|
+
Relative paths are rooted at the build output directory and begin with `/` (e.g. `/_astro/logo.svg`).
|
|
25
|
+
|
|
26
|
+
## How it works
|
|
27
|
+
|
|
28
|
+
1. After the build completes, all non-HTML files in the output directory are collected as candidate assets.
|
|
29
|
+
2. All `.css`, `.html`, and `.js` files are scanned for any occurrence of each asset's **filename** (basename only, no directory).
|
|
30
|
+
3. Any asset whose filename is not found in any scanned file is deleted, unless it matches an entry in `opts.keep`.
|
|
31
|
+
|
|
32
|
+
## Examples
|
|
33
|
+
|
|
34
|
+
### Default — prune all unreferenced assets
|
|
35
|
+
|
|
36
|
+
```ts
|
|
37
|
+
integrations: [pruneBuild()]
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### Retain specific files
|
|
41
|
+
|
|
42
|
+
Use an exact relative path string to keep a specific file:
|
|
43
|
+
|
|
44
|
+
```ts
|
|
45
|
+
integrations: [
|
|
46
|
+
pruneBuild({
|
|
47
|
+
keep: ['/_astro/logo.svg'],
|
|
48
|
+
}),
|
|
49
|
+
]
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Retain files matching a pattern
|
|
53
|
+
|
|
54
|
+
Use a `RegExp` to keep a set of files by pattern:
|
|
55
|
+
|
|
56
|
+
```ts
|
|
57
|
+
integrations: [
|
|
58
|
+
pruneBuild({
|
|
59
|
+
keep: [/\/_astro\/fonts\//],
|
|
60
|
+
}),
|
|
61
|
+
]
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Mix strings and patterns
|
|
65
|
+
|
|
66
|
+
```ts
|
|
67
|
+
integrations: [
|
|
68
|
+
pruneBuild({
|
|
69
|
+
keep: [
|
|
70
|
+
'/_astro/og-image.png',
|
|
71
|
+
/\/_astro\/icons\//,
|
|
72
|
+
],
|
|
73
|
+
}),
|
|
74
|
+
]
|
|
75
|
+
```
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# relative-links
|
|
2
|
+
|
|
3
|
+
An Astro integration that rewrites absolute asset paths in the build output to relative paths after `astro build` completes. This is useful when deploying to a subdirectory or when the final host path is unknown at build time.
|
|
4
|
+
|
|
5
|
+
## Usage
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
// astro.config.mjs
|
|
9
|
+
import { defineConfig } from 'astro/config';
|
|
10
|
+
import { relativeLinks } from '@inizioevoke/astro-core/integrations';
|
|
11
|
+
|
|
12
|
+
export default defineConfig({
|
|
13
|
+
integrations: [relativeLinks()],
|
|
14
|
+
});
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Options
|
|
18
|
+
|
|
19
|
+
| Option | Type | Default | Description |
|
|
20
|
+
|--------|------|---------|-------------|
|
|
21
|
+
| `enabled` | `boolean` | `true` | Set to `false` to skip processing entirely. Useful for disabling conditionally (e.g. in dev/preview environments). |
|
|
22
|
+
|
|
23
|
+
## How it works
|
|
24
|
+
|
|
25
|
+
1. After the build completes, all `.html` and `.css` files in the output directory are collected.
|
|
26
|
+
2. Each file is scanned for occurrences of the `base` path (from `astro.config.mjs`) in attribute values and `url()` expressions.
|
|
27
|
+
3. Matching absolute references are replaced with a relative path calculated from the file's location up to the output root.
|
|
28
|
+
|
|
29
|
+
### Where replacements are applied in HTML files
|
|
30
|
+
|
|
31
|
+
- Attribute values: `href`, `src`, `srcset`, `poster`, `component-url`, `renderer-url`
|
|
32
|
+
- Inline `style` attribute `url()` expressions
|
|
33
|
+
- `<style>` block `url()` expressions
|
|
34
|
+
|
|
35
|
+
### Where replacements are applied in CSS files
|
|
36
|
+
|
|
37
|
+
- `url()` expressions
|
|
38
|
+
|
|
39
|
+
## Examples
|
|
40
|
+
|
|
41
|
+
### Default — rewrite all absolute paths
|
|
42
|
+
|
|
43
|
+
```ts
|
|
44
|
+
integrations: [relativeLinks()]
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### Disable conditionally
|
|
48
|
+
|
|
49
|
+
```ts
|
|
50
|
+
integrations: [
|
|
51
|
+
relativeLinks({ enabled: process.env.NODE_ENV !== 'development' }),
|
|
52
|
+
]
|
|
53
|
+
```
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# createPinchListener
|
|
2
|
+
|
|
3
|
+
Attaches a two-finger pinch gesture listener to `window`. Tracks cumulative scale across gestures, snapping to `1` when crossing the natural scale boundary. Fires a callback on every move tick where the finger distance changes.
|
|
4
|
+
|
|
5
|
+
## Usage
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
import { createPinchListener } from '@inizioevoke/astro-core/lib/gestures';
|
|
9
|
+
|
|
10
|
+
const pinch = createPinchListener((scale, gesture) => {
|
|
11
|
+
console.log(gesture, scale); // 'spread' 1.23
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
// Later, to clean up:
|
|
15
|
+
pinch.dispose();
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## API
|
|
19
|
+
|
|
20
|
+
### `createPinchListener(onPinch)`
|
|
21
|
+
|
|
22
|
+
| Parameter | Type | Description |
|
|
23
|
+
|-----------|------|-------------|
|
|
24
|
+
| `onPinch` | `(scale: number, gesture: PinchGesture) => void` | Called each time the pinch distance changes. Receives the current cumulative scale and the gesture direction. |
|
|
25
|
+
|
|
26
|
+
**Returns** a `PinchController`.
|
|
27
|
+
|
|
28
|
+
### `PinchController`
|
|
29
|
+
|
|
30
|
+
| Method | Description |
|
|
31
|
+
|--------|-------------|
|
|
32
|
+
| `enable()` | Attaches listeners and begins tracking. Called automatically on creation. |
|
|
33
|
+
| `disable()` | Removes all listeners and resets internal state. Can be re-enabled with `enable()`. |
|
|
34
|
+
| `dispose()` | Alias for `disable()`. Use when tearing down permanently. |
|
|
35
|
+
|
|
36
|
+
### `PinchGesture`
|
|
37
|
+
|
|
38
|
+
```ts
|
|
39
|
+
type PinchGesture = 'spread' | 'pinch'
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
| Value | Description |
|
|
43
|
+
|-------|-------------|
|
|
44
|
+
| `'spread'` | Fingers moving apart |
|
|
45
|
+
| `'pinch'` | Fingers moving together |
|
|
46
|
+
|
|
47
|
+
## Behavior
|
|
48
|
+
|
|
49
|
+
- Requires exactly two simultaneous touch points — single-finger touches are ignored.
|
|
50
|
+
- Scale is **cumulative**: each new gesture continues from where the previous one ended.
|
|
51
|
+
- Snaps to `1` when the scale crosses the natural boundary (e.g. transitioning from `1.2` to `0.9` in a single gesture yields `1` instead of `0.9`).
|
|
52
|
+
- All `touchmove` and `touchend` listeners are added passively and cleaned up automatically when the gesture ends.
|
|
53
|
+
|
|
54
|
+
## Examples
|
|
55
|
+
|
|
56
|
+
### Zoom an element
|
|
57
|
+
|
|
58
|
+
```ts
|
|
59
|
+
import { createPinchListener } from '@inizioevoke/astro-core';
|
|
60
|
+
|
|
61
|
+
const image = document.querySelector('#zoomable') as HTMLElement;
|
|
62
|
+
|
|
63
|
+
const pinch = createPinchListener((scale) => {
|
|
64
|
+
image.style.transform = `scale(${scale})`;
|
|
65
|
+
});
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### React to gesture direction
|
|
69
|
+
|
|
70
|
+
```ts
|
|
71
|
+
import { createPinchListener, type PinchGesture } from '@inizioevoke/astro-core';
|
|
72
|
+
|
|
73
|
+
const pinch = createPinchListener((scale, gesture) => {
|
|
74
|
+
if (gesture === 'spread') {
|
|
75
|
+
// fingers apart — zooming in
|
|
76
|
+
} else {
|
|
77
|
+
// fingers together — zooming out
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### Temporarily pause and resume
|
|
83
|
+
|
|
84
|
+
```ts
|
|
85
|
+
const pinch = createPinchListener((scale, gesture) => { /* ... */ });
|
|
86
|
+
|
|
87
|
+
pinch.disable(); // pause
|
|
88
|
+
pinch.enable(); // resume
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Clean up on component teardown
|
|
92
|
+
|
|
93
|
+
```ts
|
|
94
|
+
const pinch = createPinchListener((scale, gesture) => { /* ... */ });
|
|
95
|
+
|
|
96
|
+
// Astro / vanilla teardown
|
|
97
|
+
document.addEventListener('astro:before-swap', () => pinch.dispose(), { once: true });
|
|
98
|
+
```
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
# createSwipeListener
|
|
2
|
+
|
|
3
|
+
Attaches a touch swipe gesture listener to `window`. Detects directional swipes based on a configurable distance threshold and fires a callback when the gesture completes.
|
|
4
|
+
|
|
5
|
+
## Usage
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
import { createSwipeListener } from '@inizioevoke/astro-core/lib/gestures';
|
|
9
|
+
|
|
10
|
+
const swipe = createSwipeListener('left-right', '1/3', ({ direction, distance, duration }) => {
|
|
11
|
+
console.log(direction, distance.x, duration); // 'left' -180 320
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
// Later, to disable without removing:
|
|
15
|
+
swipe.disable();
|
|
16
|
+
|
|
17
|
+
// Re-enable:
|
|
18
|
+
swipe.enable();
|
|
19
|
+
|
|
20
|
+
// Fully clean up:
|
|
21
|
+
swipe.dispose();
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## API
|
|
25
|
+
|
|
26
|
+
### `createSwipeListener(direction, threshold, handler)`
|
|
27
|
+
|
|
28
|
+
| Parameter | Type | Description |
|
|
29
|
+
|-----------|------|-------------|
|
|
30
|
+
| `direction` | `SwipeDirection` | Which swipe direction(s) to listen for. |
|
|
31
|
+
| `threshold` | `SwipeThreshold` | Minimum swipe distance required to trigger the handler. A fractional string is relative to the screen dimension of the primary axis. |
|
|
32
|
+
| `handler` | `OnSwipeHandler` | Called when a qualifying swipe completes. |
|
|
33
|
+
|
|
34
|
+
**Returns** a `SwipeController` — `{ enable, disable, dispose }` — for managing the listener lifecycle.
|
|
35
|
+
|
|
36
|
+
The listener is **enabled automatically** on creation. `dispose` is an alias for `disable`.
|
|
37
|
+
|
|
38
|
+
### `SwipeDirection`
|
|
39
|
+
|
|
40
|
+
```ts
|
|
41
|
+
type SwipeDirection = 'left' | 'right' | 'left-right' | 'up' | 'down' | 'up-down';
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
| Value | Description |
|
|
45
|
+
|-------|-------------|
|
|
46
|
+
| `'left'` | Rightward-to-leftward horizontal swipe |
|
|
47
|
+
| `'right'` | Leftward-to-rightward horizontal swipe |
|
|
48
|
+
| `'left-right'` | Either horizontal direction |
|
|
49
|
+
| `'up'` | Bottom-to-top vertical swipe |
|
|
50
|
+
| `'down'` | Top-to-bottom vertical swipe |
|
|
51
|
+
| `'up-down'` | Either vertical direction |
|
|
52
|
+
|
|
53
|
+
### `SwipeThreshold`
|
|
54
|
+
|
|
55
|
+
```ts
|
|
56
|
+
type SwipeThreshold = '1/4' | '1/3' | '1/2' | number;
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Fractional strings are converted to a pixel distance at creation time based on the primary axis:
|
|
60
|
+
|
|
61
|
+
- Horizontal swipes (`left`, `right`, `left-right`) use `window.innerWidth`
|
|
62
|
+
- Vertical swipes (`up`, `down`, `up-down`) use `window.innerHeight`
|
|
63
|
+
|
|
64
|
+
Pass a `number` to specify an exact pixel distance.
|
|
65
|
+
|
|
66
|
+
### `OnSwipeHandlerArgs`
|
|
67
|
+
|
|
68
|
+
```ts
|
|
69
|
+
interface OnSwipeHandlerArgs {
|
|
70
|
+
direction: SwipeDirection;
|
|
71
|
+
threshold: number;
|
|
72
|
+
distance: { x: number; y: number };
|
|
73
|
+
duration: number;
|
|
74
|
+
}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
| Field | Description |
|
|
78
|
+
|-------|-------------|
|
|
79
|
+
| `direction` | The resolved direction of the swipe (`'left'`, `'right'`, `'up'`, or `'down'`). |
|
|
80
|
+
| `threshold` | The resolved pixel threshold used for this listener. |
|
|
81
|
+
| `distance.x` | Horizontal delta in pixels (positive = leftward, negative = rightward). |
|
|
82
|
+
| `distance.y` | Vertical delta in pixels (positive = upward, negative = downward). |
|
|
83
|
+
| `duration` | Time in milliseconds from `touchstart` to `touchend`. |
|
|
84
|
+
|
|
85
|
+
### `SwipeController`
|
|
86
|
+
|
|
87
|
+
```ts
|
|
88
|
+
interface SwipeController {
|
|
89
|
+
enable: () => void;
|
|
90
|
+
disable: () => void;
|
|
91
|
+
dispose: () => void;
|
|
92
|
+
}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
| Method | Description |
|
|
96
|
+
|--------|-------------|
|
|
97
|
+
| `enable()` | Attaches touch event listeners. No-op if already enabled. |
|
|
98
|
+
| `disable()` | Detaches touch event listeners. The controller can be re-enabled. |
|
|
99
|
+
| `dispose()` | Alias for `disable()`. |
|
|
100
|
+
|
|
101
|
+
## Behavior
|
|
102
|
+
|
|
103
|
+
- Only single-finger swipes are recognized — multi-touch contacts cancel the active gesture.
|
|
104
|
+
- A swipe is only fired if the gesture is primarily along the primary axis. Off-axis drift must stay below the threshold or the swipe is ignored.
|
|
105
|
+
- The threshold pixel value is computed once at creation — it does not update on orientation change or resize.
|
|
106
|
+
- All touch listeners are added passively.
|
|
107
|
+
|
|
108
|
+
## Examples
|
|
109
|
+
|
|
110
|
+
### Navigate a carousel on horizontal swipe
|
|
111
|
+
|
|
112
|
+
```ts
|
|
113
|
+
import { createSwipeListener } from '@inizioevoke/astro-core';
|
|
114
|
+
|
|
115
|
+
const swipe = createSwipeListener('left-right', '1/3', ({ direction }) => {
|
|
116
|
+
if (direction === 'left') carousel.next();
|
|
117
|
+
else carousel.prev();
|
|
118
|
+
});
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### Dismiss a sheet on downward swipe
|
|
122
|
+
|
|
123
|
+
```ts
|
|
124
|
+
import { createSwipeListener } from '@inizioevoke/astro-core';
|
|
125
|
+
|
|
126
|
+
const swipe = createSwipeListener('down', '1/4', () => {
|
|
127
|
+
sheet.close();
|
|
128
|
+
});
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### Pause detection while a modal is open
|
|
132
|
+
|
|
133
|
+
```ts
|
|
134
|
+
const swipe = createSwipeListener('left-right', '1/3', handler);
|
|
135
|
+
|
|
136
|
+
modal.addEventListener('open', () => swipe.disable());
|
|
137
|
+
modal.addEventListener('close', () => swipe.enable());
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### Clean up on component teardown
|
|
141
|
+
|
|
142
|
+
```ts
|
|
143
|
+
const swipe = createSwipeListener('up', '1/3', handler);
|
|
144
|
+
|
|
145
|
+
// Astro / vanilla teardown
|
|
146
|
+
document.addEventListener('astro:before-swap', swipe.dispose, { once: true });
|
|
147
|
+
```
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@inizioevoke/astro-core",
|
|
3
|
-
"version": "2.1
|
|
3
|
+
"version": "2.2.1",
|
|
4
4
|
"description": "",
|
|
5
5
|
"license": "ISC",
|
|
6
6
|
"author": "",
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
"./lib/gestures": "./src/lib/gestures/index.ts"
|
|
19
19
|
},
|
|
20
20
|
"files": [
|
|
21
|
+
"docs",
|
|
21
22
|
"src",
|
|
22
23
|
"index.ts"
|
|
23
24
|
],
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
---
|
|
2
|
+
// See /docs/components/CssBackgroundImage.md
|
|
3
|
+
import type { ImageMetadata, ImageOutputFormat } from "astro";
|
|
4
|
+
import { getImage } from "astro:assets";
|
|
5
|
+
|
|
6
|
+
type ImageSize = 'contain' | 'cover';
|
|
7
|
+
type ImagePosition = 'left top' | 'left center' | 'left bottom' | 'center top' | 'center center' | 'center bottom' | 'right top' | 'right center' | 'right bottom';
|
|
8
|
+
|
|
9
|
+
interface ImageSrcProps {
|
|
10
|
+
image: ImageMetadata;
|
|
11
|
+
optimize?: boolean;
|
|
12
|
+
format?: ImageOutputFormat;
|
|
13
|
+
quality?: number;
|
|
14
|
+
width?: number;
|
|
15
|
+
height?: number;
|
|
16
|
+
}
|
|
17
|
+
interface BgImageProps extends ImageSrcProps {
|
|
18
|
+
size?: ImageSize | (string & {});
|
|
19
|
+
position?: ImagePosition | (string & {});
|
|
20
|
+
repeat?: 'no-repeat' | 'repeat-x' | 'repeat-y' | 'repeat';
|
|
21
|
+
important?: true;
|
|
22
|
+
}
|
|
23
|
+
export interface Props extends BgImageProps {
|
|
24
|
+
selector?: string;
|
|
25
|
+
|
|
26
|
+
breakpoints?: ({
|
|
27
|
+
minWidth?: string | number;
|
|
28
|
+
maxWidth?: string | number;
|
|
29
|
+
} & BgImageProps)[];
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const {
|
|
33
|
+
selector,
|
|
34
|
+
image,
|
|
35
|
+
optimize = true,
|
|
36
|
+
format,
|
|
37
|
+
quality,
|
|
38
|
+
width,
|
|
39
|
+
height,
|
|
40
|
+
size,
|
|
41
|
+
position,
|
|
42
|
+
repeat,
|
|
43
|
+
important,
|
|
44
|
+
breakpoints = []
|
|
45
|
+
} = Astro.props;
|
|
46
|
+
|
|
47
|
+
const styles: string[] = [];
|
|
48
|
+
|
|
49
|
+
async function getImageSrc({image, format, quality, width, height, optimize}: ImageSrcProps) {
|
|
50
|
+
if (optimize !== false) {
|
|
51
|
+
const img = await getImage({
|
|
52
|
+
src: image,
|
|
53
|
+
format: format ?? image.format,
|
|
54
|
+
quality: quality,
|
|
55
|
+
width,
|
|
56
|
+
height
|
|
57
|
+
});
|
|
58
|
+
return img.src;
|
|
59
|
+
} else {
|
|
60
|
+
return image.src;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (image) {
|
|
65
|
+
const src = await getImageSrc({ image, format, quality, width, height, optimize });
|
|
66
|
+
styles.push(`background-image:url("${src}")${important ? '!important' : ''};`);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
size && styles.push(`background-size:${size}${important ? '!important' : ''};`);
|
|
70
|
+
position && styles.push(`background-position:${position}${important ? '!important' : ''};`);
|
|
71
|
+
repeat && styles.push(`background-repeat:${repeat}${important ? '!important' : ''};`);
|
|
72
|
+
|
|
73
|
+
for (const bp of breakpoints) {
|
|
74
|
+
const widths = [];
|
|
75
|
+
if (bp.minWidth) {
|
|
76
|
+
widths.push(`(min-width:${typeof bp.minWidth == 'number' ? `${bp.minWidth}px` : bp.minWidth})`);
|
|
77
|
+
}
|
|
78
|
+
if (bp.maxWidth) {
|
|
79
|
+
widths.push(`(max-width:${typeof bp.maxWidth == 'number' ? `${bp.maxWidth}px` : bp.maxWidth})`);
|
|
80
|
+
}
|
|
81
|
+
if (widths.length > 0) {
|
|
82
|
+
// const bpImg = await getImage({ src: bp.image });
|
|
83
|
+
styles.push(`@media screen and ${widths.join(' and ')}{`);
|
|
84
|
+
if (bp.image) {
|
|
85
|
+
const src = await getImageSrc(bp);
|
|
86
|
+
styles.push(`background-image:url("${src}")${important ? '!important' : ''};`);
|
|
87
|
+
}
|
|
88
|
+
bp.size && styles.push(`background-size:${bp.size}${important ? '!important' : ''};`);
|
|
89
|
+
bp.position && styles.push(`background-position:${bp.position}${important ? '!important' : ''};`);
|
|
90
|
+
bp.repeat && styles.push(`background-repeat:${bp.repeat}${important ? '!important' : ''};`);
|
|
91
|
+
styles.push('}');
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const html = [`${import.meta.env.PROD ? '' : '\n'}${selector ?? 'body'}{`]
|
|
96
|
+
.concat(styles.map((s) => {
|
|
97
|
+
return `${s}`;
|
|
98
|
+
}))
|
|
99
|
+
.concat(['}'])
|
|
100
|
+
.join(import.meta.env.PROD ? '' : '\n');
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
<style set:html={html} />
|