lapikit 0.6.0 → 0.6.2
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/dist/@types/actions.d.ts +13 -0
- package/dist/@types/props.d.ts +8 -0
- package/dist/animations/ripple.d.ts +1 -1
- package/dist/animations/ripple.js +36 -23
- package/dist/components/app/app.svelte +162 -10
- package/dist/components/app/app.svelte.d.ts +2 -4
- package/dist/components/app/app.types.d.ts +4 -0
- package/dist/components/app/app.types.js +1 -0
- package/dist/components/card/card.svelte +57 -98
- package/dist/components/card/card.types.d.ts +23 -2
- package/dist/components/card/modules/card-actions.svelte +53 -0
- package/dist/components/card/modules/card-actions.svelte.d.ts +4 -0
- package/dist/components/card/modules/card-container.svelte +51 -0
- package/dist/components/card/modules/card-container.svelte.d.ts +4 -0
- package/dist/components/card/modules/card-content.svelte +56 -0
- package/dist/components/card/modules/card-content.svelte.d.ts +4 -0
- package/dist/components/card/modules/card-media.svelte +52 -0
- package/dist/components/card/modules/card-media.svelte.d.ts +4 -0
- package/dist/components/card/modules/card-title.svelte +60 -0
- package/dist/components/card/modules/card-title.svelte.d.ts +4 -0
- package/dist/components/index.d.ts +5 -0
- package/dist/components/index.js +5 -0
- package/dist/components/textfield/textfield.svelte.d.ts +1 -1
- package/dist/constants.js +6 -1
- package/dist/hooks/actions.d.ts +2 -0
- package/dist/hooks/actions.js +2 -0
- package/dist/hooks/themes.svelte.d.ts +12 -0
- package/dist/hooks/themes.svelte.js +125 -0
- package/dist/utils/components.d.ts +9 -1
- package/dist/utils/components.js +35 -0
- package/package.json +2 -2
- package/dist/actions.d.ts +0 -2
- package/dist/actions.js +0 -2
- package/dist/utils/themes.d.ts +0 -3
- package/dist/utils/themes.js +0 -21
package/dist/@types/actions.d.ts
CHANGED
|
@@ -1,6 +1,19 @@
|
|
|
1
|
+
import type { Action } from 'svelte/action';
|
|
2
|
+
/** Accordion */
|
|
1
3
|
export type AccordionOptions = {
|
|
2
4
|
multiple?: boolean;
|
|
3
5
|
readOnly?: boolean;
|
|
4
6
|
};
|
|
5
7
|
/**Modal */
|
|
6
8
|
export type ModalState = boolean | 'persistent';
|
|
9
|
+
/**Theme */
|
|
10
|
+
export type ThemeOptions = {
|
|
11
|
+
name?: string;
|
|
12
|
+
key?: string;
|
|
13
|
+
overridden?: boolean;
|
|
14
|
+
};
|
|
15
|
+
export type ThemeAction = {
|
|
16
|
+
action: Action<HTMLElement, ThemeOptions | undefined>;
|
|
17
|
+
set: (name: string) => void;
|
|
18
|
+
readonly active: string;
|
|
19
|
+
};
|
package/dist/@types/props.d.ts
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
1
|
export type PropValue = string | boolean | number | null | undefined;
|
|
2
2
|
export type SizeType = 'default' | 'xs' | 'sm' | 'md' | 'lg' | 'xl';
|
|
3
3
|
export type RoundedType = 0 | '0' | 'xs' | 'sm' | 'md' | 'lg' | 'xl';
|
|
4
|
+
export type DensityType = 'none' | 'compact' | 'default' | 'comfortable';
|
|
5
|
+
export type ElevationType = '0' | '1' | '2' | '3' | '4' | '5';
|
|
6
|
+
export interface ElevationState {
|
|
7
|
+
base?: ElevationType;
|
|
8
|
+
hover?: ElevationType;
|
|
9
|
+
active?: ElevationType;
|
|
10
|
+
}
|
|
11
|
+
export type ElevationProps = ElevationType | ElevationState;
|
|
@@ -1,7 +1,17 @@
|
|
|
1
1
|
const triggerEvents = ['pointerdown', 'touchstart', 'keydown'];
|
|
2
2
|
const cancelEvents = ['mouseleave', 'dragleave', 'touchmove', 'touchcancel', 'pointerup', 'keyup'];
|
|
3
|
+
function resolveDuration(options) {
|
|
4
|
+
return options.duration && options.duration > 0 ? options.duration : undefined;
|
|
5
|
+
}
|
|
6
|
+
function getCoords(e) {
|
|
7
|
+
if (window.TouchEvent && e instanceof TouchEvent) {
|
|
8
|
+
return { x: e.touches[0].clientX, y: e.touches[0].clientY };
|
|
9
|
+
}
|
|
10
|
+
return { x: e.clientX, y: e.clientY };
|
|
11
|
+
}
|
|
3
12
|
export function ripple(el, options = {}) {
|
|
4
13
|
const rippleContainer = document.createElement('div');
|
|
14
|
+
const activeRipples = new Set();
|
|
5
15
|
addClasses();
|
|
6
16
|
setOptions(options);
|
|
7
17
|
function isAriaDisabled() {
|
|
@@ -19,24 +29,22 @@ export function ripple(el, options = {}) {
|
|
|
19
29
|
rippleContainer.classList.add('kit-ripple--center');
|
|
20
30
|
}
|
|
21
31
|
}
|
|
22
|
-
function setOptions(
|
|
23
|
-
if (
|
|
32
|
+
function setOptions(newOptions) {
|
|
33
|
+
if (newOptions.disabled || isAriaDisabled()) {
|
|
24
34
|
rippleContainer.remove();
|
|
25
35
|
}
|
|
26
36
|
else {
|
|
27
37
|
el.appendChild(rippleContainer);
|
|
28
38
|
}
|
|
29
|
-
if (
|
|
30
|
-
|
|
39
|
+
if (newOptions.component) {
|
|
40
|
+
rippleContainer.style.setProperty('--system-ripple-radius', `var(--kit-${newOptions.component}-radius)`);
|
|
31
41
|
}
|
|
32
|
-
if (
|
|
33
|
-
rippleContainer.style.setProperty('--system-ripple-
|
|
42
|
+
if (newOptions.color) {
|
|
43
|
+
rippleContainer.style.setProperty('--system-ripple-color', newOptions.color);
|
|
34
44
|
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
if (options.duration) {
|
|
39
|
-
rippleContainer.style.setProperty('--system-animation-ripple-duration', `${options.duration}ms`);
|
|
45
|
+
const duration = resolveDuration(newOptions);
|
|
46
|
+
if (duration) {
|
|
47
|
+
rippleContainer.style.setProperty('--system-animation-ripple-duration', `${duration}ms`);
|
|
40
48
|
}
|
|
41
49
|
}
|
|
42
50
|
function createRipple(e, center) {
|
|
@@ -54,12 +62,7 @@ export function ripple(el, options = {}) {
|
|
|
54
62
|
}
|
|
55
63
|
addClasses(center);
|
|
56
64
|
const rect = el.getBoundingClientRect();
|
|
57
|
-
const clientX
|
|
58
|
-
? e.touches[0].clientX
|
|
59
|
-
: e.clientX;
|
|
60
|
-
const clientY = window.TouchEvent && e instanceof TouchEvent
|
|
61
|
-
? e.touches[0].clientY
|
|
62
|
-
: e.clientY;
|
|
65
|
+
const { x: clientX, y: clientY } = getCoords(e);
|
|
63
66
|
const x = clientX - rect.left > el.offsetWidth / 2 ? 0 : el.offsetWidth;
|
|
64
67
|
const y = clientY - rect.top > el.offsetHeight / 2 ? 0 : el.offsetHeight;
|
|
65
68
|
const radius = Math.hypot(x - (clientX - rect.left), y - (clientY - rect.top));
|
|
@@ -69,16 +72,23 @@ export function ripple(el, options = {}) {
|
|
|
69
72
|
ripple.style.top = `${clientY - rect.top - radius}px`;
|
|
70
73
|
ripple.style.width = ripple.style.height = `${radius * 2}px`;
|
|
71
74
|
rippleContainer.appendChild(ripple);
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
+
let timeoutId;
|
|
76
|
+
function cleanup() {
|
|
77
|
+
if (timeoutId) {
|
|
78
|
+
clearTimeout(timeoutId);
|
|
75
79
|
}
|
|
80
|
+
cancelEvents.forEach((event) => el.removeEventListener(event, removeRipple));
|
|
81
|
+
ripple.remove();
|
|
82
|
+
}
|
|
83
|
+
function removeRipple() {
|
|
76
84
|
ripple.style.opacity = '0';
|
|
77
|
-
setTimeout(() => {
|
|
78
|
-
ripple.remove();
|
|
79
|
-
}, options.duration || 1000);
|
|
80
85
|
cancelEvents.forEach((event) => el.removeEventListener(event, removeRipple));
|
|
86
|
+
timeoutId = setTimeout(() => {
|
|
87
|
+
ripple.remove();
|
|
88
|
+
activeRipples.delete(cleanup);
|
|
89
|
+
}, resolveDuration(options) || 1000);
|
|
81
90
|
}
|
|
91
|
+
activeRipples.add(cleanup);
|
|
82
92
|
cancelEvents.forEach((event) => el.addEventListener(event, removeRipple, { passive: true }));
|
|
83
93
|
}
|
|
84
94
|
triggerEvents.forEach((event) => el.addEventListener(event, createRipple, { passive: event === 'touchstart' }));
|
|
@@ -87,6 +97,9 @@ export function ripple(el, options = {}) {
|
|
|
87
97
|
triggerEvents.forEach((event) => {
|
|
88
98
|
el.removeEventListener(event, createRipple);
|
|
89
99
|
});
|
|
100
|
+
activeRipples.forEach((cleanup) => cleanup());
|
|
101
|
+
activeRipples.clear();
|
|
102
|
+
rippleContainer.remove();
|
|
90
103
|
},
|
|
91
104
|
update(newOptions) {
|
|
92
105
|
options = newOptions;
|
|
@@ -1,15 +1,121 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
|
|
2
|
+
import { makeComponentProps } from '../../html-mapped';
|
|
3
|
+
import { useClassName, useStyles } from '../../utils';
|
|
4
|
+
import type { AppProps } from './app.types';
|
|
5
|
+
|
|
6
|
+
let {
|
|
7
|
+
ref = $bindable(),
|
|
8
|
+
children,
|
|
9
|
+
class: className = '',
|
|
10
|
+
style: styleAttr = '',
|
|
11
|
+
's-class': sClass,
|
|
12
|
+
's-style': sStyle,
|
|
13
|
+
...rest
|
|
14
|
+
}: AppProps = $props();
|
|
15
|
+
|
|
16
|
+
let { classProps, styleProps, restProps } = $derived(makeComponentProps(rest));
|
|
17
|
+
|
|
18
|
+
let componentClass = $derived(
|
|
19
|
+
useClassName({
|
|
20
|
+
baseClass: 'kit-application',
|
|
21
|
+
className: `${className ?? ''}`.trim(),
|
|
22
|
+
sClass,
|
|
23
|
+
classProps
|
|
24
|
+
})
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
let componentStyle = $derived(
|
|
28
|
+
useStyles({
|
|
29
|
+
styleAttr,
|
|
30
|
+
sStyle,
|
|
31
|
+
styleProps
|
|
32
|
+
})
|
|
33
|
+
);
|
|
3
34
|
</script>
|
|
4
35
|
|
|
5
|
-
<div id="kit-app" bind:this={ref} {
|
|
36
|
+
<div id="kit-app" bind:this={ref} class={componentClass} style={componentStyle} {...restProps}>
|
|
6
37
|
{@render children?.()}
|
|
7
38
|
</div>
|
|
8
39
|
|
|
9
40
|
<style>
|
|
41
|
+
.kit-application {
|
|
42
|
+
--kit-shape-none: 0;
|
|
43
|
+
--kit-shape-xs: 4px;
|
|
44
|
+
--kit-shape-sm: 6px;
|
|
45
|
+
--kit-shape-md: 10px;
|
|
46
|
+
--kit-shape-lg: 14px;
|
|
47
|
+
--kit-shape-xl: 18px;
|
|
48
|
+
|
|
49
|
+
--kit-space-compact: 6px;
|
|
50
|
+
--kit-space-default: 10px;
|
|
51
|
+
--kit-space-comfortable: 14px;
|
|
52
|
+
|
|
53
|
+
--kit-shadow-opacity: 30%;
|
|
54
|
+
--kit-shadow-ambiant-opacity: 15%;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.kit-application,
|
|
58
|
+
:global([data-kit-theme='light']) {
|
|
59
|
+
color-scheme: light;
|
|
60
|
+
--kit-color-bg: hsl(0 0% 100%);
|
|
61
|
+
--kit-color-bg-secondary: hsl(240 15% 96.5%);
|
|
62
|
+
--kit-color-bg-tertiary: hsl(240 10% 93%);
|
|
63
|
+
--kit-color-surface: hsl(0 0% 100%);
|
|
64
|
+
--kit-color-surface-raised: hsl(0 0% 100%);
|
|
65
|
+
|
|
66
|
+
--kit-color-label: hsl(222 20% 10%);
|
|
67
|
+
--kit-color-label-secondary: hsl(220 10% 40%);
|
|
68
|
+
--kit-color-label-tertiary: hsl(220 8% 58%);
|
|
69
|
+
--kit-color-label-quaternary: hsl(220 5% 76%);
|
|
70
|
+
|
|
71
|
+
--kit-color-fill: hsl(240 4% 91%);
|
|
72
|
+
--kit-color-fill-secondary: hsl(240 8% 93%);
|
|
73
|
+
--kit-color-fill-tertiary: hsl(240 11% 95%);
|
|
74
|
+
|
|
75
|
+
--kit-color-separator: hsl(220 16% 88%);
|
|
76
|
+
--kit-color-shadow: hsl(240 3% 11%);
|
|
77
|
+
|
|
78
|
+
--kit-color-accent: hsl(220 90% 56%);
|
|
79
|
+
--kit-color-success: hsl(145 50% 38%);
|
|
80
|
+
--kit-color-warning: hsl(35 80% 45%);
|
|
81
|
+
--kit-color-danger: hsl(5 65% 48%);
|
|
82
|
+
--kit-color-info: hsl(205 60% 42%);
|
|
83
|
+
--kit-color-focus: hsl(35 90% 56%);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
:global([data-kit-theme='dark']) {
|
|
87
|
+
color-scheme: dark;
|
|
88
|
+
|
|
89
|
+
--kit-color-bg: hsl(240 3% 11%);
|
|
90
|
+
--kit-color-bg-secondary: hsl(240 2% 17.5%);
|
|
91
|
+
--kit-color-bg-tertiary: hsl(240 1.5% 23%);
|
|
92
|
+
--kit-color-surface: hsl(240 2% 19%);
|
|
93
|
+
--kit-color-surface-raised: hsl(240 1.5% 25%);
|
|
94
|
+
|
|
95
|
+
--kit-color-label: hsl(0 0% 100%);
|
|
96
|
+
--kit-color-label-secondary: hsl(240 3% 56%);
|
|
97
|
+
--kit-color-label-tertiary: hsl(240 2.5% 38%);
|
|
98
|
+
--kit-color-label-quaternary: hsl(240 1.5% 25%);
|
|
99
|
+
|
|
100
|
+
--kit-color-fill: hsl(240 2.5% 28%);
|
|
101
|
+
--kit-color-fill-secondary: hsl(240 2.5% 24%);
|
|
102
|
+
--kit-color-fill-tertiary: hsl(240 2% 20%);
|
|
103
|
+
|
|
104
|
+
--kit-color-separator: hsl(240 2% 26%);
|
|
105
|
+
--kit-color-shadow: hsl(240 3% 11%);
|
|
106
|
+
|
|
107
|
+
--kit-color-accent: hsl(220 85% 65%);
|
|
108
|
+
--kit-color-success: hsl(145 50% 50%);
|
|
109
|
+
--kit-color-warning: hsl(35 85% 58%);
|
|
110
|
+
--kit-color-danger: hsl(5 70% 60%);
|
|
111
|
+
--kit-color-info: hsl(205 65% 58%);
|
|
112
|
+
--kit-color-focus: hsl(35 90% 62%);
|
|
113
|
+
}
|
|
114
|
+
|
|
10
115
|
.kit-application {
|
|
11
116
|
color-scheme: light;
|
|
12
117
|
|
|
118
|
+
/* Hue vars — used by components for dynamic semantic color calculations */
|
|
13
119
|
--kit-h-neutral: 220;
|
|
14
120
|
--kit-h-success: 145;
|
|
15
121
|
--kit-h-warning: 35;
|
|
@@ -28,16 +134,15 @@
|
|
|
28
134
|
|
|
29
135
|
--kit-accent: hsl(220 90% 56%);
|
|
30
136
|
|
|
137
|
+
--kit-focus: hsl(35, 90%, 56%);
|
|
138
|
+
|
|
139
|
+
/* Layout */
|
|
31
140
|
--kit-radius-1: 8px;
|
|
32
141
|
--kit-radius-2: 12px;
|
|
33
142
|
--kit-space-1: 6px;
|
|
34
143
|
--kit-space-2: 10px;
|
|
35
144
|
--kit-space-3: 14px;
|
|
36
|
-
|
|
37
|
-
--kit-focus: hsl(35, 90%, 56%);
|
|
38
|
-
|
|
39
145
|
--kit-disabled-opacity: 0.55;
|
|
40
|
-
|
|
41
146
|
--kit-font:
|
|
42
147
|
ui-sans-serif, system-ui, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji',
|
|
43
148
|
'Segoe UI Symbol', 'Noto Color Emoji';
|
|
@@ -59,13 +164,10 @@
|
|
|
59
164
|
position: absolute;
|
|
60
165
|
border-radius: 50%;
|
|
61
166
|
pointer-events: none;
|
|
62
|
-
-webkit-transition: 0.6s;
|
|
63
167
|
transition: 0.6s;
|
|
64
|
-
-webkit-animation: animation-l-ripple var(--system-animation-ripple-duration, 0.4s)
|
|
65
|
-
cubic-bezier(0.4, 0, 0.2, 1);
|
|
66
168
|
animation: animation-l-ripple var(--system-animation-ripple-duration, 0.4s)
|
|
67
169
|
cubic-bezier(0.4, 0, 0.2, 1);
|
|
68
|
-
border-radius:
|
|
170
|
+
border-radius: 50%;
|
|
69
171
|
}
|
|
70
172
|
|
|
71
173
|
:global(.kit-ripple--center) {
|
|
@@ -87,6 +189,56 @@
|
|
|
87
189
|
border-radius: var(--system-ripple-radius);
|
|
88
190
|
}
|
|
89
191
|
|
|
192
|
+
:global([data-elevation='0']),
|
|
193
|
+
:global([data-elevation-hover='0']:hover),
|
|
194
|
+
:global([data-elevation-active='0']):active {
|
|
195
|
+
box-shadow: none;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
:global([data-elevation='1']),
|
|
199
|
+
:global([data-elevation-hover='1']:hover),
|
|
200
|
+
:global([data-elevation-active='1']:active) {
|
|
201
|
+
box-shadow:
|
|
202
|
+
0 1px 2px color-mix(in oklab, var(--kit-color-shadow) var(--kit-shadow-opacity), transparent),
|
|
203
|
+
0 3px 8px -2px
|
|
204
|
+
color-mix(in oklab, var(--kit-color-shadow) var(--kit-shadow-ambiant-opacity), transparent);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
:global([data-elevation='2']),
|
|
208
|
+
:global([data-elevation-hover='2']:hover),
|
|
209
|
+
:global([data-elevation-active='2']:active) {
|
|
210
|
+
box-shadow:
|
|
211
|
+
0 1px 3px color-mix(in oklab, var(--kit-color-shadow) var(--kit-shadow-opacity), transparent),
|
|
212
|
+
0 5px 12px -3px
|
|
213
|
+
color-mix(in oklab, var(--kit-color-shadow) var(--kit-shadow-ambiant-opacity), transparent);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
:global([data-elevation='3']),
|
|
217
|
+
:global([data-elevation-hover='3']:hover),
|
|
218
|
+
:global([data-elevation-active='3']:active) {
|
|
219
|
+
box-shadow:
|
|
220
|
+
0 2px 4px color-mix(in oklab, var(--kit-color-shadow) var(--kit-shadow-opacity), transparent),
|
|
221
|
+
0 8px 20px -4px
|
|
222
|
+
color-mix(in oklab, var(--kit-color-shadow) var(--kit-shadow-ambiant-opacity), transparent);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
:global([data-elevation='4']),
|
|
226
|
+
:global([data-elevation-hover='4']):hover,
|
|
227
|
+
:global([data-elevation-active='4']):active {
|
|
228
|
+
box-shadow:
|
|
229
|
+
0 3px 5px color-mix(in oklab, var(--kit-color-shadow) var(--kit-shadow-opacity), transparent),
|
|
230
|
+
0 11px 26px -5px
|
|
231
|
+
color-mix(in oklab, var(--kit-color-shadow) var(--kit-shadow-ambiant-opacity), transparent);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
:global([data-elevation='5']),
|
|
235
|
+
:global([data-elevation-hover='5']:hover),
|
|
236
|
+
:global([data-elevation-active='5']:active) {
|
|
237
|
+
box-shadow:
|
|
238
|
+
0 4px 6px color-mix(in oklab, var(--kit-color-shadow) var(--kit-shadow-opacity), transparent),
|
|
239
|
+
0 14px 32px -6px
|
|
240
|
+
color-mix(in oklab, var(--kit-color-shadow) var(--kit-shadow-ambiant-opacity), transparent);
|
|
241
|
+
}
|
|
90
242
|
@keyframes -global-animation-l-ripple {
|
|
91
243
|
from {
|
|
92
244
|
scale: 0;
|
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
children: any;
|
|
4
|
-
} & Record<string, any>, {}, "ref">;
|
|
1
|
+
import type { AppProps } from './app.types';
|
|
2
|
+
declare const App: import("svelte").Component<AppProps, {}, "ref">;
|
|
5
3
|
type App = ReturnType<typeof App>;
|
|
6
4
|
export default App;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import { useClassName, useStyles } from '../../utils';
|
|
2
|
+
import { useClassName, useElevation, useIsInteractive, useStyles } from '../../utils';
|
|
3
3
|
import { makeComponentProps } from '../../html-mapped';
|
|
4
4
|
import { ripple } from '../../animations';
|
|
5
5
|
import type { CardProps } from './card.types.js';
|
|
@@ -21,45 +21,23 @@
|
|
|
21
21
|
active = false,
|
|
22
22
|
disabled = false,
|
|
23
23
|
noRipple,
|
|
24
|
+
color,
|
|
25
|
+
background,
|
|
26
|
+
elevation,
|
|
24
27
|
...rest
|
|
25
28
|
}: CardProps = $props();
|
|
26
29
|
|
|
27
|
-
let
|
|
28
|
-
|
|
29
|
-
);
|
|
30
|
-
|
|
31
|
-
let safeDensity = $derived(
|
|
32
|
-
density === 'compact' || density === 'default' || density === 'comfortable'
|
|
33
|
-
? density
|
|
34
|
-
: 'default'
|
|
35
|
-
);
|
|
36
|
-
|
|
37
|
-
let safeIs = $derived(
|
|
38
|
-
is === 'div' ||
|
|
39
|
-
is === 'article' ||
|
|
40
|
-
is === 'section' ||
|
|
41
|
-
is === 'aside' ||
|
|
42
|
-
is === 'a' ||
|
|
43
|
-
is === 'button'
|
|
44
|
-
? is
|
|
45
|
-
: 'article'
|
|
46
|
-
);
|
|
47
|
-
let tag = $derived((href && 'a') || safeIs || 'article');
|
|
48
|
-
let hasEventHandler = $derived(
|
|
49
|
-
typeof rest.onclick === 'function' ||
|
|
50
|
-
typeof rest.onpointerdown === 'function' ||
|
|
51
|
-
typeof rest.onkeydown === 'function'
|
|
52
|
-
);
|
|
53
|
-
let isInteractive = $derived(interactive || tag === 'a' || tag === 'button' || hasEventHandler);
|
|
30
|
+
let tag = $derived((href && 'a') || is);
|
|
31
|
+
let isInteractive = $derived(useIsInteractive(rest, tag, ['a', 'button'], interactive));
|
|
54
32
|
let isDisabled = $derived(!!disabled);
|
|
55
33
|
let resolvedHref = $derived(tag === 'a' && !isDisabled ? href : undefined);
|
|
56
34
|
let resolvedType = $derived(tag === 'button' ? (type ?? 'button') : undefined);
|
|
57
35
|
let resolvedDisabled = $derived(tag === 'button' ? isDisabled : undefined);
|
|
58
36
|
let resolvedTabIndex = $derived(tag === 'a' && isDisabled ? -1 : undefined);
|
|
59
37
|
|
|
60
|
-
let { classProps, styleProps, restProps } = $derived(
|
|
61
|
-
|
|
62
|
-
);
|
|
38
|
+
let { classProps, styleProps, restProps } = $derived(makeComponentProps(rest));
|
|
39
|
+
|
|
40
|
+
let elevationState = $derived(useElevation(elevation));
|
|
63
41
|
|
|
64
42
|
let componentClass = $derived(
|
|
65
43
|
useClassName({
|
|
@@ -88,9 +66,12 @@
|
|
|
88
66
|
type={resolvedType}
|
|
89
67
|
disabled={resolvedDisabled}
|
|
90
68
|
tabindex={resolvedTabIndex}
|
|
91
|
-
data-variant={
|
|
92
|
-
data-density={
|
|
69
|
+
data-variant={variant}
|
|
70
|
+
data-density={density}
|
|
93
71
|
data-rounded={rounded}
|
|
72
|
+
data-elevation={elevationState.base}
|
|
73
|
+
data-elevation-hover={elevationState.hover}
|
|
74
|
+
data-elevation-active={elevationState.active}
|
|
94
75
|
data-interactive={isInteractive}
|
|
95
76
|
data-active={active}
|
|
96
77
|
data-disabled={isDisabled}
|
|
@@ -99,9 +80,11 @@
|
|
|
99
80
|
component: 'card',
|
|
100
81
|
disabled: noRipple || disabled || !isInteractive
|
|
101
82
|
}}
|
|
83
|
+
style:--kit-card-fg={color && `var(--kit-color-${color})`}
|
|
84
|
+
style:--kit-card-bg={background && `var(--kit-color-${background})`}
|
|
102
85
|
{...restProps}
|
|
103
86
|
>
|
|
104
|
-
{#if
|
|
87
|
+
{#if variant === 'outline'}
|
|
105
88
|
<span class="outline"></span>
|
|
106
89
|
{/if}
|
|
107
90
|
|
|
@@ -110,25 +93,15 @@
|
|
|
110
93
|
|
|
111
94
|
<style>
|
|
112
95
|
.kit-card {
|
|
113
|
-
--kit-card-bg: var(--kit-surface-2);
|
|
114
|
-
--kit-card-fg: var(--kit-fg);
|
|
115
|
-
--kit-card-bd: var(--kit-border);
|
|
116
|
-
--kit-card-radius: var(--kit-radius-2);
|
|
117
|
-
--kit-card-padding-compact: var(--kit-space-1);
|
|
118
|
-
--kit-card-padding-default: var(--kit-space-2);
|
|
119
|
-
--kit-card-padding-comfortable: var(--kit-space-3);
|
|
120
|
-
--kit-card-hover-bg: color-mix(in oklab, var(--kit-card-bg), var(--kit-card-fg) 6%);
|
|
121
|
-
--kit-card-active-bg: color-mix(in oklab, var(--kit-card-bg), var(--kit-card-fg) 10%);
|
|
122
|
-
|
|
123
96
|
display: flex;
|
|
97
|
+
position: relative;
|
|
124
98
|
flex-direction: column;
|
|
125
|
-
gap: var(--kit-
|
|
99
|
+
gap: var(--kit-card-gap);
|
|
126
100
|
background: var(--kit-card-bg);
|
|
127
101
|
color: var(--kit-card-fg);
|
|
128
|
-
border: 0;
|
|
129
102
|
border-radius: var(--kit-card-radius);
|
|
103
|
+
border: 0;
|
|
130
104
|
box-sizing: border-box;
|
|
131
|
-
position: relative;
|
|
132
105
|
transition:
|
|
133
106
|
background 140ms ease,
|
|
134
107
|
color 140ms ease,
|
|
@@ -148,53 +121,72 @@
|
|
|
148
121
|
text-align: inherit;
|
|
149
122
|
}
|
|
150
123
|
|
|
124
|
+
/**
|
|
125
|
+
* rounded
|
|
126
|
+
* @link ...
|
|
127
|
+
*/
|
|
151
128
|
.kit-card[data-rounded='0'] {
|
|
152
|
-
--kit-card-radius:
|
|
129
|
+
--kit-card-radius: var(--kit-shape-none);
|
|
153
130
|
}
|
|
154
131
|
.kit-card[data-rounded='xs'] {
|
|
155
|
-
--kit-card-radius:
|
|
132
|
+
--kit-card-radius: var(--kit-shape-xs);
|
|
156
133
|
}
|
|
157
134
|
.kit-card[data-rounded='sm'] {
|
|
158
|
-
--kit-card-radius:
|
|
135
|
+
--kit-card-radius: var(--kit-shape-sm);
|
|
159
136
|
}
|
|
160
137
|
.kit-card[data-rounded='md'] {
|
|
161
|
-
--kit-card-radius:
|
|
138
|
+
--kit-card-radius: var(--kit-shape-md);
|
|
162
139
|
}
|
|
163
140
|
.kit-card[data-rounded='lg'] {
|
|
164
|
-
--kit-card-radius:
|
|
141
|
+
--kit-card-radius: var(--kit-shape-lg);
|
|
165
142
|
}
|
|
166
143
|
.kit-card[data-rounded='xl'] {
|
|
167
|
-
--kit-card-radius:
|
|
144
|
+
--kit-card-radius: var(--kit-shape-xl);
|
|
168
145
|
}
|
|
169
146
|
|
|
147
|
+
/**
|
|
148
|
+
* density
|
|
149
|
+
* @link https://lapikit.dev/docs/components/card#density
|
|
150
|
+
*/
|
|
151
|
+
.kit-card[data-density='none'] {
|
|
152
|
+
padding: 0;
|
|
153
|
+
}
|
|
170
154
|
.kit-card[data-density='compact'] {
|
|
171
|
-
|
|
155
|
+
--kit-card-gap: var(--kit-space-compact);
|
|
156
|
+
padding: var(--kit-space-compact);
|
|
172
157
|
}
|
|
173
158
|
.kit-card[data-density='default'] {
|
|
174
|
-
|
|
159
|
+
--kit-card-gap: var(--kit-space-default);
|
|
160
|
+
padding: var(--kit-space-default);
|
|
175
161
|
}
|
|
176
162
|
.kit-card[data-density='comfortable'] {
|
|
177
|
-
|
|
163
|
+
--kit-card-gap: var(--kit-space-comfortable);
|
|
164
|
+
padding: var(--kit-space-comfortable);
|
|
178
165
|
}
|
|
179
166
|
|
|
167
|
+
/**
|
|
168
|
+
* variant
|
|
169
|
+
* @link https://lapikit.dev/docs/components/card#variants
|
|
170
|
+
*/
|
|
180
171
|
.kit-card[data-variant='filled'] {
|
|
181
|
-
--kit-card-bg: var(--kit-
|
|
182
|
-
--kit-card-fg:
|
|
172
|
+
--kit-card-bg: var(--kit-color-surface);
|
|
173
|
+
--kit-card-fg: var(--kit-color-label);
|
|
174
|
+
|
|
183
175
|
--kit-card-hover-bg: color-mix(in oklab, var(--kit-card-bg), black 10%);
|
|
184
176
|
--kit-card-active-bg: color-mix(in oklab, var(--kit-card-bg), black 16%);
|
|
185
177
|
}
|
|
186
|
-
|
|
187
178
|
.kit-card[data-variant='outline'] {
|
|
188
179
|
--kit-card-bg: transparent;
|
|
189
|
-
--kit-card-fg: var(--kit-
|
|
190
|
-
--kit-card-bd: var(--kit-
|
|
180
|
+
--kit-card-fg: var(--kit-color-label);
|
|
181
|
+
--kit-card-bd: var(--kit-card-fg);
|
|
182
|
+
|
|
191
183
|
--kit-card-hover-bg: color-mix(in oklab, var(--kit-card-fg), transparent 80%);
|
|
192
184
|
--kit-card-active-bg: color-mix(in oklab, var(--kit-card-fg), transparent 92%);
|
|
193
185
|
}
|
|
194
|
-
|
|
195
186
|
.kit-card[data-variant='text'] {
|
|
196
187
|
--kit-card-bg: transparent;
|
|
197
|
-
--kit-card-fg: var(--kit-
|
|
188
|
+
--kit-card-fg: var(--kit-color-label);
|
|
189
|
+
|
|
198
190
|
--kit-card-hover-bg: color-mix(in oklab, var(--kit-card-fg), transparent 80%);
|
|
199
191
|
--kit-card-active-bg: color-mix(in oklab, var(--kit-card-fg), transparent 92%);
|
|
200
192
|
}
|
|
@@ -206,7 +198,7 @@
|
|
|
206
198
|
.kit-card[data-interactive='true'][data-disabled='false']:hover {
|
|
207
199
|
translate: 0 -1px;
|
|
208
200
|
background: var(--kit-card-hover-bg);
|
|
209
|
-
box-shadow: 0 10px 28px hsl(220 35% 8% / 0.12);
|
|
201
|
+
/* box-shadow: 0 10px 28px hsl(220 35% 8% / 0.12); */
|
|
210
202
|
}
|
|
211
203
|
|
|
212
204
|
.kit-card[data-variant='text'][data-interactive='true'][data-disabled='false']:hover {
|
|
@@ -217,7 +209,7 @@
|
|
|
217
209
|
.kit-card[data-interactive='true'][data-disabled='false']:active {
|
|
218
210
|
translate: 0 0;
|
|
219
211
|
background: var(--kit-card-active-bg);
|
|
220
|
-
box-shadow: 0 4px 14px hsl(220 35% 8% / 0.1);
|
|
212
|
+
/* box-shadow: 0 4px 14px hsl(220 35% 8% / 0.1); */
|
|
221
213
|
}
|
|
222
214
|
|
|
223
215
|
.kit-card[data-variant='text'][data-interactive='true'][data-active='true'][data-disabled='false'],
|
|
@@ -238,37 +230,4 @@
|
|
|
238
230
|
.kit-card .outline {
|
|
239
231
|
--outline-color: var(--kit-card-bd);
|
|
240
232
|
}
|
|
241
|
-
|
|
242
|
-
.kit-card__media {
|
|
243
|
-
overflow: hidden;
|
|
244
|
-
border-radius: calc(var(--kit-card-radius) - 2px);
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
.kit-card__header {
|
|
248
|
-
font-weight: 600;
|
|
249
|
-
line-height: 1.3;
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
.kit-card__body {
|
|
253
|
-
display: block;
|
|
254
|
-
line-height: 1.45;
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
.kit-card__footer {
|
|
258
|
-
display: flex;
|
|
259
|
-
align-items: center;
|
|
260
|
-
justify-content: space-between;
|
|
261
|
-
gap: var(--kit-space-2);
|
|
262
|
-
flex-wrap: wrap;
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
.kit-card__footer-content {
|
|
266
|
-
color: var(--kit-muted);
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
.kit-card__actions {
|
|
270
|
-
display: inline-flex;
|
|
271
|
-
align-items: center;
|
|
272
|
-
gap: var(--kit-space-1);
|
|
273
|
-
}
|
|
274
233
|
</style>
|
|
@@ -1,14 +1,35 @@
|
|
|
1
|
-
import type { Component, RoundedType } from '../../@types';
|
|
1
|
+
import type { Component, DensityType, ElevationProps, RoundedType } from '../../@types';
|
|
2
2
|
export interface CardProps extends Component {
|
|
3
3
|
ref?: HTMLElement | null;
|
|
4
4
|
is?: 'div' | 'article' | 'section' | 'aside' | 'a' | 'button';
|
|
5
5
|
href?: string;
|
|
6
6
|
type?: 'button' | 'submit' | 'reset';
|
|
7
7
|
variant?: 'filled' | 'outline' | 'text';
|
|
8
|
-
density?:
|
|
8
|
+
density?: DensityType;
|
|
9
9
|
rounded?: RoundedType;
|
|
10
|
+
elevation?: ElevationProps;
|
|
10
11
|
interactive?: boolean;
|
|
11
12
|
active?: boolean;
|
|
12
13
|
disabled?: boolean;
|
|
13
14
|
noRipple?: boolean;
|
|
14
15
|
}
|
|
16
|
+
export interface CardTitleProps extends Component {
|
|
17
|
+
ref?: HTMLElement | null;
|
|
18
|
+
is?: 'div' | 'p' | 'span' | 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6';
|
|
19
|
+
}
|
|
20
|
+
export interface CardContentProps extends Component {
|
|
21
|
+
ref?: HTMLElement | null;
|
|
22
|
+
is?: 'div' | 'p' | 'span' | 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6';
|
|
23
|
+
}
|
|
24
|
+
export interface CardMediaProps extends Component {
|
|
25
|
+
ref?: HTMLElement | null;
|
|
26
|
+
is?: 'div' | 'span';
|
|
27
|
+
}
|
|
28
|
+
export interface CardContainerProps extends Component {
|
|
29
|
+
ref?: HTMLElement | null;
|
|
30
|
+
is?: 'div' | 'span';
|
|
31
|
+
}
|
|
32
|
+
export interface CardActionsProps extends Component {
|
|
33
|
+
ref?: HTMLElement | null;
|
|
34
|
+
is?: 'div' | 'span';
|
|
35
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { CardActionsProps } from '../card.types';
|
|
3
|
+
import { makeComponentProps } from '../../../html-mapped';
|
|
4
|
+
import { useClassName, useStyles } from '../../../utils';
|
|
5
|
+
|
|
6
|
+
let {
|
|
7
|
+
ref = $bindable(),
|
|
8
|
+
is = 'div',
|
|
9
|
+
children,
|
|
10
|
+
class: className = '',
|
|
11
|
+
style: styleAttr = '',
|
|
12
|
+
's-class': sClass,
|
|
13
|
+
's-style': sStyle,
|
|
14
|
+
...rest
|
|
15
|
+
}: CardActionsProps = $props();
|
|
16
|
+
|
|
17
|
+
let { classProps, styleProps, restProps } = $derived(makeComponentProps(rest));
|
|
18
|
+
|
|
19
|
+
let componentClass = $derived(
|
|
20
|
+
useClassName({
|
|
21
|
+
baseClass: 'kit-card-actions',
|
|
22
|
+
className: `${className ?? ''}`.trim(),
|
|
23
|
+
sClass,
|
|
24
|
+
classProps
|
|
25
|
+
})
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
let componentStyle = $derived(
|
|
29
|
+
useStyles({
|
|
30
|
+
styleAttr,
|
|
31
|
+
sStyle,
|
|
32
|
+
styleProps
|
|
33
|
+
})
|
|
34
|
+
);
|
|
35
|
+
</script>
|
|
36
|
+
|
|
37
|
+
<svelte:element
|
|
38
|
+
this={is}
|
|
39
|
+
bind:this={ref}
|
|
40
|
+
class={componentClass}
|
|
41
|
+
style={componentStyle}
|
|
42
|
+
{...restProps}
|
|
43
|
+
>
|
|
44
|
+
{@render children?.()}
|
|
45
|
+
</svelte:element>
|
|
46
|
+
|
|
47
|
+
<style>
|
|
48
|
+
.kit-card-actions {
|
|
49
|
+
display: inline-flex;
|
|
50
|
+
align-items: center;
|
|
51
|
+
gap: var(--kit-space-1);
|
|
52
|
+
}
|
|
53
|
+
</style>
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { CardContainerProps } from '../card.types';
|
|
3
|
+
import { makeComponentProps } from '../../../html-mapped';
|
|
4
|
+
import { useClassName, useStyles } from '../../../utils';
|
|
5
|
+
|
|
6
|
+
let {
|
|
7
|
+
ref = $bindable(),
|
|
8
|
+
is = 'div',
|
|
9
|
+
children,
|
|
10
|
+
class: className = '',
|
|
11
|
+
style: styleAttr = '',
|
|
12
|
+
's-class': sClass,
|
|
13
|
+
's-style': sStyle,
|
|
14
|
+
...rest
|
|
15
|
+
}: CardContainerProps = $props();
|
|
16
|
+
|
|
17
|
+
let { classProps, styleProps, restProps } = $derived(makeComponentProps(rest));
|
|
18
|
+
|
|
19
|
+
let componentClass = $derived(
|
|
20
|
+
useClassName({
|
|
21
|
+
baseClass: 'kit-card-container',
|
|
22
|
+
className: `${className ?? ''}`.trim(),
|
|
23
|
+
sClass,
|
|
24
|
+
classProps
|
|
25
|
+
})
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
let componentStyle = $derived(
|
|
29
|
+
useStyles({
|
|
30
|
+
styleAttr,
|
|
31
|
+
sStyle,
|
|
32
|
+
styleProps
|
|
33
|
+
})
|
|
34
|
+
);
|
|
35
|
+
</script>
|
|
36
|
+
|
|
37
|
+
<svelte:element
|
|
38
|
+
this={is}
|
|
39
|
+
bind:this={ref}
|
|
40
|
+
class={componentClass}
|
|
41
|
+
style={componentStyle}
|
|
42
|
+
{...restProps}
|
|
43
|
+
>
|
|
44
|
+
{@render children?.()}
|
|
45
|
+
</svelte:element>
|
|
46
|
+
|
|
47
|
+
<style>
|
|
48
|
+
.kit-card-container {
|
|
49
|
+
gap: var(--kit-card-gap);
|
|
50
|
+
}
|
|
51
|
+
</style>
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { CardContentProps } from '../card.types';
|
|
3
|
+
import { makeComponentProps } from '../../../html-mapped';
|
|
4
|
+
import { useClassName, useStyles } from '../../../utils';
|
|
5
|
+
|
|
6
|
+
let {
|
|
7
|
+
ref = $bindable(),
|
|
8
|
+
is = 'div',
|
|
9
|
+
children,
|
|
10
|
+
class: className = '',
|
|
11
|
+
style: styleAttr = '',
|
|
12
|
+
's-class': sClass,
|
|
13
|
+
's-style': sStyle,
|
|
14
|
+
...rest
|
|
15
|
+
}: CardContentProps = $props();
|
|
16
|
+
|
|
17
|
+
let { classProps, styleProps, restProps } = $derived(makeComponentProps(rest));
|
|
18
|
+
|
|
19
|
+
let componentClass = $derived(
|
|
20
|
+
useClassName({
|
|
21
|
+
baseClass: 'kit-card-content',
|
|
22
|
+
className: `${className ?? ''}`.trim(),
|
|
23
|
+
sClass,
|
|
24
|
+
classProps
|
|
25
|
+
})
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
let componentStyle = $derived(
|
|
29
|
+
useStyles({
|
|
30
|
+
styleAttr,
|
|
31
|
+
sStyle,
|
|
32
|
+
styleProps
|
|
33
|
+
})
|
|
34
|
+
);
|
|
35
|
+
</script>
|
|
36
|
+
|
|
37
|
+
<svelte:element
|
|
38
|
+
this={is}
|
|
39
|
+
bind:this={ref}
|
|
40
|
+
class={componentClass}
|
|
41
|
+
style={componentStyle}
|
|
42
|
+
{...restProps}
|
|
43
|
+
>
|
|
44
|
+
{@render children?.()}
|
|
45
|
+
</svelte:element>
|
|
46
|
+
|
|
47
|
+
<style>
|
|
48
|
+
.kit-card-content {
|
|
49
|
+
display: block;
|
|
50
|
+
line-height: 1.45;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.kit-card-content > :global(*) {
|
|
54
|
+
margin: 0;
|
|
55
|
+
}
|
|
56
|
+
</style>
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { CardMediaProps } from '../card.types';
|
|
3
|
+
import { makeComponentProps } from '../../../html-mapped';
|
|
4
|
+
import { useClassName, useStyles } from '../../../utils';
|
|
5
|
+
|
|
6
|
+
let {
|
|
7
|
+
ref = $bindable(),
|
|
8
|
+
is = 'div',
|
|
9
|
+
children,
|
|
10
|
+
class: className = '',
|
|
11
|
+
style: styleAttr = '',
|
|
12
|
+
's-class': sClass,
|
|
13
|
+
's-style': sStyle,
|
|
14
|
+
...rest
|
|
15
|
+
}: CardMediaProps = $props();
|
|
16
|
+
|
|
17
|
+
let { classProps, styleProps, restProps } = $derived(makeComponentProps(rest));
|
|
18
|
+
|
|
19
|
+
let componentClass = $derived(
|
|
20
|
+
useClassName({
|
|
21
|
+
baseClass: 'kit-card-media',
|
|
22
|
+
className: `${className ?? ''}`.trim(),
|
|
23
|
+
sClass,
|
|
24
|
+
classProps
|
|
25
|
+
})
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
let componentStyle = $derived(
|
|
29
|
+
useStyles({
|
|
30
|
+
styleAttr,
|
|
31
|
+
sStyle,
|
|
32
|
+
styleProps
|
|
33
|
+
})
|
|
34
|
+
);
|
|
35
|
+
</script>
|
|
36
|
+
|
|
37
|
+
<svelte:element
|
|
38
|
+
this={is}
|
|
39
|
+
bind:this={ref}
|
|
40
|
+
class={componentClass}
|
|
41
|
+
style={componentStyle}
|
|
42
|
+
{...restProps}
|
|
43
|
+
>
|
|
44
|
+
{@render children?.()}
|
|
45
|
+
</svelte:element>
|
|
46
|
+
|
|
47
|
+
<style>
|
|
48
|
+
.kit-card-media {
|
|
49
|
+
overflow: hidden;
|
|
50
|
+
border-radius: calc(var(--kit-card-radius) - 2px);
|
|
51
|
+
}
|
|
52
|
+
</style>
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { CardTitleProps } from '../card.types';
|
|
3
|
+
import { makeComponentProps } from '../../../html-mapped';
|
|
4
|
+
import { useClassName, useStyles } from '../../../utils';
|
|
5
|
+
|
|
6
|
+
let {
|
|
7
|
+
ref = $bindable(),
|
|
8
|
+
is = 'div',
|
|
9
|
+
children,
|
|
10
|
+
class: className = '',
|
|
11
|
+
style: styleAttr = '',
|
|
12
|
+
's-class': sClass,
|
|
13
|
+
's-style': sStyle,
|
|
14
|
+
...rest
|
|
15
|
+
}: CardTitleProps = $props();
|
|
16
|
+
|
|
17
|
+
let { classProps, styleProps, restProps } = $derived(makeComponentProps(rest));
|
|
18
|
+
|
|
19
|
+
let componentClass = $derived(
|
|
20
|
+
useClassName({
|
|
21
|
+
baseClass: 'kit-card-title',
|
|
22
|
+
className: `${className ?? ''}`.trim(),
|
|
23
|
+
sClass,
|
|
24
|
+
classProps
|
|
25
|
+
})
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
let componentStyle = $derived(
|
|
29
|
+
useStyles({
|
|
30
|
+
styleAttr,
|
|
31
|
+
sStyle,
|
|
32
|
+
styleProps
|
|
33
|
+
})
|
|
34
|
+
);
|
|
35
|
+
</script>
|
|
36
|
+
|
|
37
|
+
<svelte:element
|
|
38
|
+
this={is}
|
|
39
|
+
bind:this={ref}
|
|
40
|
+
class={componentClass}
|
|
41
|
+
style={componentStyle}
|
|
42
|
+
{...restProps}
|
|
43
|
+
>
|
|
44
|
+
{@render children?.()}
|
|
45
|
+
</svelte:element>
|
|
46
|
+
|
|
47
|
+
<style>
|
|
48
|
+
.kit-card-title {
|
|
49
|
+
display: flex;
|
|
50
|
+
align-items: center;
|
|
51
|
+
gap: var(--kit-card-gap);
|
|
52
|
+
|
|
53
|
+
font-weight: 600;
|
|
54
|
+
line-height: 1.3;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.kit-card-title > :global(*) {
|
|
58
|
+
margin: 0;
|
|
59
|
+
}
|
|
60
|
+
</style>
|
|
@@ -6,6 +6,11 @@ export { default as KitAppbar } from './appbar/appbar.svelte';
|
|
|
6
6
|
export { default as KitBtn } from './btn/btn.svelte';
|
|
7
7
|
export { default as KitIcon } from './icon/icon.svelte';
|
|
8
8
|
export { default as KitCard } from './card/card.svelte';
|
|
9
|
+
export { default as KitCardMedia } from './card/modules/card-media.svelte';
|
|
10
|
+
export { default as KitCardTitle } from './card/modules/card-title.svelte';
|
|
11
|
+
export { default as KitCardContent } from './card/modules/card-content.svelte';
|
|
12
|
+
export { default as KitCardActions } from './card/modules/card-actions.svelte';
|
|
13
|
+
export { default as KitCardContainer } from './card/modules/card-container.svelte';
|
|
9
14
|
export { default as KitChip } from './chip/chip.svelte';
|
|
10
15
|
export { default as KitAvatar } from './avatar/avatar.svelte';
|
|
11
16
|
export { default as KitDropdown } from './dropdown/dropdown.svelte';
|
package/dist/components/index.js
CHANGED
|
@@ -4,6 +4,11 @@ export { default as KitAppbar } from './appbar/appbar.svelte';
|
|
|
4
4
|
export { default as KitBtn } from './btn/btn.svelte';
|
|
5
5
|
export { default as KitIcon } from './icon/icon.svelte';
|
|
6
6
|
export { default as KitCard } from './card/card.svelte';
|
|
7
|
+
export { default as KitCardMedia } from './card/modules/card-media.svelte';
|
|
8
|
+
export { default as KitCardTitle } from './card/modules/card-title.svelte';
|
|
9
|
+
export { default as KitCardContent } from './card/modules/card-content.svelte';
|
|
10
|
+
export { default as KitCardActions } from './card/modules/card-actions.svelte';
|
|
11
|
+
export { default as KitCardContainer } from './card/modules/card-container.svelte';
|
|
7
12
|
export { default as KitChip } from './chip/chip.svelte';
|
|
8
13
|
export { default as KitAvatar } from './avatar/avatar.svelte';
|
|
9
14
|
export { default as KitDropdown } from './dropdown/dropdown.svelte';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import type { TextfieldProps } from './textfield.types.ts';
|
|
2
|
-
declare const Textfield: import("svelte").Component<TextfieldProps, {}, "
|
|
2
|
+
declare const Textfield: import("svelte").Component<TextfieldProps, {}, "ref" | "value">;
|
|
3
3
|
type Textfield = ReturnType<typeof Textfield>;
|
|
4
4
|
export default Textfield;
|
package/dist/constants.js
CHANGED
|
@@ -28,7 +28,12 @@ export const lapikitComponents = [
|
|
|
28
28
|
'spacer',
|
|
29
29
|
'separator',
|
|
30
30
|
'chip',
|
|
31
|
-
'card'
|
|
31
|
+
'card',
|
|
32
|
+
'card-title',
|
|
33
|
+
'card-content',
|
|
34
|
+
'card-media',
|
|
35
|
+
'card-actions',
|
|
36
|
+
'card-container'
|
|
32
37
|
];
|
|
33
38
|
export const lapikitLabsComponents = ['sheet'];
|
|
34
39
|
export const lapikitPlugins = {
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { ThemeOptions, ThemeAction } from '../@types';
|
|
2
|
+
export declare const useTheme: (name: string) => void;
|
|
3
|
+
export declare function createGlobalTheme(params?: ThemeOptions): {
|
|
4
|
+
readonly active: string;
|
|
5
|
+
};
|
|
6
|
+
export declare function createTheme(): ThemeAction;
|
|
7
|
+
/** LEGACY CODE
|
|
8
|
+
* NEED UPDATE documentation with new theme system before removing this legacy code. The new theme system is designed to be more flexible and easier to use, allowing for better integration with Svelte's reactivity and component structure. It also provides a more consistent API for managing themes across different components and contexts.
|
|
9
|
+
* TODO: Remove this legacy code once the new theme system is fully implemented and tested. This code is kept for backward compatibility with existing components that rely on the old theme system.
|
|
10
|
+
*/
|
|
11
|
+
import { type Writable } from 'svelte/store';
|
|
12
|
+
export declare const theme: Writable<string>;
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
// states
|
|
2
|
+
const isBrowser = typeof window !== 'undefined';
|
|
3
|
+
// presets
|
|
4
|
+
const default_theme = 'light';
|
|
5
|
+
const default_storage_key = '@lapikit/theme';
|
|
6
|
+
function generateGlobalTheme() {
|
|
7
|
+
let active = $state(default_theme);
|
|
8
|
+
let key = default_storage_key;
|
|
9
|
+
let initialized = false;
|
|
10
|
+
function applyToHtml(name) {
|
|
11
|
+
if (!isBrowser)
|
|
12
|
+
return;
|
|
13
|
+
document.documentElement.setAttribute('data-kit-theme', name);
|
|
14
|
+
active = name;
|
|
15
|
+
}
|
|
16
|
+
function set(name) {
|
|
17
|
+
applyToHtml(name);
|
|
18
|
+
if (isBrowser) {
|
|
19
|
+
localStorage.setItem(key, name);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
function init(params = {}) {
|
|
23
|
+
if (initialized)
|
|
24
|
+
return;
|
|
25
|
+
initialized = true;
|
|
26
|
+
key = params.key ?? default_storage_key;
|
|
27
|
+
const stored = isBrowser ? localStorage.getItem(key) : null;
|
|
28
|
+
applyToHtml(stored ?? params.name ?? default_theme);
|
|
29
|
+
}
|
|
30
|
+
return {
|
|
31
|
+
init,
|
|
32
|
+
set,
|
|
33
|
+
get active() {
|
|
34
|
+
return active;
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
const refGlobalTheme = generateGlobalTheme();
|
|
39
|
+
export const useTheme = refGlobalTheme.set;
|
|
40
|
+
export function createGlobalTheme(params) {
|
|
41
|
+
refGlobalTheme.init(params);
|
|
42
|
+
return {
|
|
43
|
+
get active() {
|
|
44
|
+
return refGlobalTheme.active;
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
export function createTheme() {
|
|
49
|
+
let active = $state(default_theme);
|
|
50
|
+
let node;
|
|
51
|
+
let key;
|
|
52
|
+
let overridden = $state(false);
|
|
53
|
+
function applyTheme(name) {
|
|
54
|
+
const target = node;
|
|
55
|
+
if (!target)
|
|
56
|
+
return;
|
|
57
|
+
target.setAttribute('data-kit-theme', name);
|
|
58
|
+
active = name;
|
|
59
|
+
}
|
|
60
|
+
function set(name) {
|
|
61
|
+
applyTheme(name);
|
|
62
|
+
if (isBrowser && key) {
|
|
63
|
+
localStorage.setItem(key, name);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
// skip the effect's first automatic pass so the mount's own initial value (from
|
|
67
|
+
// `name`, storage or default) isn't immediately clobbered by the current global value
|
|
68
|
+
let firstRun = true;
|
|
69
|
+
// re-syncs to the global theme whenever it changes, unless this zone is overridden
|
|
70
|
+
$effect(() => {
|
|
71
|
+
const value = refGlobalTheme.active;
|
|
72
|
+
const isOverridden = overridden;
|
|
73
|
+
const skip = firstRun;
|
|
74
|
+
firstRun = false;
|
|
75
|
+
if (!skip && !isOverridden) {
|
|
76
|
+
applyTheme(value);
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
const action = (n, params = {}) => {
|
|
80
|
+
node = n;
|
|
81
|
+
key = params.key;
|
|
82
|
+
overridden = params.overridden ?? false;
|
|
83
|
+
const stored = isBrowser && key ? localStorage.getItem(key) : null;
|
|
84
|
+
applyTheme(stored ?? params.name ?? (overridden ? default_theme : refGlobalTheme.active));
|
|
85
|
+
return {
|
|
86
|
+
update(newParams = {}) {
|
|
87
|
+
key = newParams.key;
|
|
88
|
+
overridden = newParams.overridden ?? false;
|
|
89
|
+
},
|
|
90
|
+
destroy() {
|
|
91
|
+
node = undefined;
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
};
|
|
95
|
+
return {
|
|
96
|
+
action,
|
|
97
|
+
set,
|
|
98
|
+
get active() {
|
|
99
|
+
return active;
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
/** LEGACY CODE
|
|
104
|
+
* NEED UPDATE documentation with new theme system before removing this legacy code. The new theme system is designed to be more flexible and easier to use, allowing for better integration with Svelte's reactivity and component structure. It also provides a more consistent API for managing themes across different components and contexts.
|
|
105
|
+
* TODO: Remove this legacy code once the new theme system is fully implemented and tested. This code is kept for backward compatibility with existing components that rely on the old theme system.
|
|
106
|
+
*/
|
|
107
|
+
import { writable } from 'svelte/store';
|
|
108
|
+
// presets
|
|
109
|
+
const themeRef = 'light';
|
|
110
|
+
export const theme = writable(themeRef);
|
|
111
|
+
// export function useTheme(name: string, key: string = '@lapikit/theme') {
|
|
112
|
+
// theme.update(() => {
|
|
113
|
+
// if (isBrowser) {
|
|
114
|
+
// const html = document.documentElement;
|
|
115
|
+
// html.classList.forEach((cls) => {
|
|
116
|
+
// if (cls.startsWith('kit-theme--')) {
|
|
117
|
+
// html.classList.remove(cls);
|
|
118
|
+
// }
|
|
119
|
+
// });
|
|
120
|
+
// html.classList.add(`kit-theme--${name}`);
|
|
121
|
+
// localStorage.setItem(key, name);
|
|
122
|
+
// }
|
|
123
|
+
// return name;
|
|
124
|
+
// });
|
|
125
|
+
// }
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { useClassNameProps, useStylesProps } from '../@types';
|
|
1
|
+
import type { ElevationProps, ElevationState, useClassNameProps, useStylesProps } from '../@types';
|
|
2
2
|
/**
|
|
3
3
|
* useClassName - Utility to compute class names for a component.
|
|
4
4
|
* @param baseClass - The base class name for the component.
|
|
@@ -8,6 +8,7 @@ import type { useClassNameProps, useStylesProps } from '../@types';
|
|
|
8
8
|
* @returns A computed class string.
|
|
9
9
|
*/
|
|
10
10
|
export declare function useClassName({ baseClass, className, sClass, classProps }?: useClassNameProps): string;
|
|
11
|
+
export declare function useIsInteractive(props: Record<string, unknown>, tag: string, interactiveTags: readonly string[], interactive?: boolean): boolean;
|
|
11
12
|
/**
|
|
12
13
|
* useStyles - Utility to compute style declarations for a component (optimized pure function).
|
|
13
14
|
* @param styleAttr - Inline style attribute as a string.
|
|
@@ -16,3 +17,10 @@ export declare function useClassName({ baseClass, className, sClass, classProps
|
|
|
16
17
|
* @returns A computed style string.
|
|
17
18
|
*/
|
|
18
19
|
export declare function useStyles({ styleAttr, sStyle, styleProps }?: useStylesProps): string;
|
|
20
|
+
/**
|
|
21
|
+
* useElevation - Utility to resolve the `elevation` prop into its base/hover/active states.
|
|
22
|
+
* @param elevation - Either a single elevation value applied as `base`, or an object with
|
|
23
|
+
* independent `base`, `hover` and `active` values (each key is optional).
|
|
24
|
+
* @returns An object with `base`, `hover` and `active` keys, `undefined` when not provided.
|
|
25
|
+
*/
|
|
26
|
+
export declare function useElevation(elevation?: ElevationProps | null): ElevationState;
|
package/dist/utils/components.js
CHANGED
|
@@ -54,6 +54,22 @@ export function useClassName({ baseClass = '', className, sClass, classProps } =
|
|
|
54
54
|
}
|
|
55
55
|
return classes.filter(Boolean).join(' ');
|
|
56
56
|
}
|
|
57
|
+
/**
|
|
58
|
+
* useIsInteractive - Utility to determine whether a component should behave as interactive:
|
|
59
|
+
* either explicitly flagged, rendered as an interactive tag (e.g. 'a', 'button'), or given
|
|
60
|
+
* one of the standard interactive event handlers (onclick, onpointerdown, onkeydown).
|
|
61
|
+
* @param props - The rest/spread props object of a component.
|
|
62
|
+
* @param tag - The resolved element tag the component renders as.
|
|
63
|
+
* @param interactiveTags - The tags considered interactive for this component (e.g. ['a', 'button']).
|
|
64
|
+
* @param interactive - Explicit interactive flag passed to the component.
|
|
65
|
+
* @returns True if the component should behave as interactive.
|
|
66
|
+
*/
|
|
67
|
+
const interactiveEventKeys = ['onclick', 'onpointerdown', 'onkeydown'];
|
|
68
|
+
export function useIsInteractive(props, tag, interactiveTags, interactive = false) {
|
|
69
|
+
return (interactive ||
|
|
70
|
+
interactiveTags.includes(tag) ||
|
|
71
|
+
interactiveEventKeys.some((key) => typeof props[key] === 'function'));
|
|
72
|
+
}
|
|
57
73
|
/**
|
|
58
74
|
* useStyles - Utility to compute style declarations for a component (optimized pure function).
|
|
59
75
|
* @param styleAttr - Inline style attribute as a string.
|
|
@@ -90,3 +106,22 @@ export function useStyles({ styleAttr, sStyle, styleProps } = {}) {
|
|
|
90
106
|
}
|
|
91
107
|
return styles.filter(Boolean).join('; ');
|
|
92
108
|
}
|
|
109
|
+
/**
|
|
110
|
+
* useElevation - Utility to resolve the `elevation` prop into its base/hover/active states.
|
|
111
|
+
* @param elevation - Either a single elevation value applied as `base`, or an object with
|
|
112
|
+
* independent `base`, `hover` and `active` values (each key is optional).
|
|
113
|
+
* @returns An object with `base`, `hover` and `active` keys, `undefined` when not provided.
|
|
114
|
+
*/
|
|
115
|
+
export function useElevation(elevation) {
|
|
116
|
+
if (elevation === undefined || elevation === null) {
|
|
117
|
+
return { base: undefined, hover: undefined, active: undefined };
|
|
118
|
+
}
|
|
119
|
+
if (typeof elevation === 'string') {
|
|
120
|
+
return { base: elevation, hover: undefined, active: undefined };
|
|
121
|
+
}
|
|
122
|
+
return {
|
|
123
|
+
base: elevation.base,
|
|
124
|
+
hover: elevation.hover,
|
|
125
|
+
active: elevation.active
|
|
126
|
+
};
|
|
127
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lapikit",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.2",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -66,7 +66,7 @@
|
|
|
66
66
|
"default": "./dist/labs/index.js"
|
|
67
67
|
},
|
|
68
68
|
"./actions": {
|
|
69
|
-
"default": "./dist/actions.js"
|
|
69
|
+
"default": "./dist/hooks/actions.js"
|
|
70
70
|
}
|
|
71
71
|
},
|
|
72
72
|
"peerDependencies": {
|
package/dist/actions.d.ts
DELETED
package/dist/actions.js
DELETED
package/dist/utils/themes.d.ts
DELETED
package/dist/utils/themes.js
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { writable } from 'svelte/store';
|
|
2
|
-
// states
|
|
3
|
-
const isBrowser = typeof window !== 'undefined';
|
|
4
|
-
// presets
|
|
5
|
-
const themeRef = 'light';
|
|
6
|
-
export const theme = writable(themeRef);
|
|
7
|
-
export function useTheme(name, key = '@lapikit/theme') {
|
|
8
|
-
theme.update(() => {
|
|
9
|
-
if (isBrowser) {
|
|
10
|
-
const html = document.documentElement;
|
|
11
|
-
html.classList.forEach((cls) => {
|
|
12
|
-
if (cls.startsWith('kit-theme--')) {
|
|
13
|
-
html.classList.remove(cls);
|
|
14
|
-
}
|
|
15
|
-
});
|
|
16
|
-
html.classList.add(`kit-theme--${name}`);
|
|
17
|
-
localStorage.setItem(key, name);
|
|
18
|
-
}
|
|
19
|
-
return name;
|
|
20
|
-
});
|
|
21
|
-
}
|