lapikit 0.4.7 → 0.4.9

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.
@@ -4,7 +4,10 @@ const lapikitComponents = [
4
4
  'btn',
5
5
  'icon',
6
6
  'avatar',
7
+ 'aspect-ratio',
7
8
  'spacer',
8
- 'separator'
9
+ 'separator',
10
+ 'chip',
11
+ 'card'
9
12
  ];
10
13
  export default lapikitComponents;
@@ -0,0 +1,130 @@
1
+ <script lang="ts">
2
+ import { useClassName, useStyles } from '../../utils/index.js';
3
+ import { makeComponentProps } from '../../compiler/mapped-code.js';
4
+ import type { AspectRatioFit, AspectRatioProps, AspectRatioValue } from './aspect-ratio.types.js';
5
+
6
+ const FALLBACK_RATIO = 16 / 9;
7
+ const FALLBACK_FIT: AspectRatioFit = 'cover';
8
+
9
+ function resolveRatio(value: AspectRatioValue | undefined): number {
10
+ if (typeof value === 'number') {
11
+ return Number.isFinite(value) && value > 0 ? value : FALLBACK_RATIO;
12
+ }
13
+
14
+ if (typeof value !== 'string') {
15
+ return FALLBACK_RATIO;
16
+ }
17
+
18
+ const normalized = value.trim();
19
+ if (!normalized) {
20
+ return FALLBACK_RATIO;
21
+ }
22
+
23
+ if (normalized.includes('/') || normalized.includes(':')) {
24
+ const separator = normalized.includes('/') ? '/' : ':';
25
+ const [w, h] = normalized.split(separator).map((part) => Number(part.trim()));
26
+
27
+ if (Number.isFinite(w) && Number.isFinite(h) && w > 0 && h > 0) {
28
+ return w / h;
29
+ }
30
+ }
31
+
32
+ const asNumber = Number(normalized);
33
+ return Number.isFinite(asNumber) && asNumber > 0 ? asNumber : FALLBACK_RATIO;
34
+ }
35
+
36
+ function resolveFit(value: AspectRatioFit | undefined): AspectRatioFit {
37
+ return value === 'cover' || value === 'contain' || value === 'fill' ? value : FALLBACK_FIT;
38
+ }
39
+
40
+ let {
41
+ ref = $bindable(),
42
+ is = 'div',
43
+ children = undefined,
44
+ class: className = '',
45
+ style: styleAttr = '',
46
+ 's-class': sClass,
47
+ 's-style': sStyle,
48
+ ratio = undefined,
49
+ aspectRatio = undefined,
50
+ fit = 'cover',
51
+ inline = false,
52
+ ...rest
53
+ }: AspectRatioProps = $props();
54
+
55
+ let { classProps, styleProps, restProps } = $derived(
56
+ makeComponentProps(rest as Record<string, unknown>)
57
+ );
58
+
59
+ let componentClass = $derived(
60
+ useClassName({
61
+ baseClass: 'kit-aspect-ratio',
62
+ className: `${className ?? ''}`.trim(),
63
+ sClass,
64
+ classProps
65
+ })
66
+ );
67
+
68
+ let componentStyle = $derived(
69
+ useStyles({
70
+ styleAttr,
71
+ sStyle,
72
+ styleProps
73
+ })
74
+ );
75
+
76
+ let resolvedRatio = $derived(resolveRatio(ratio ?? aspectRatio));
77
+ let resolvedFit = $derived(resolveFit(fit));
78
+ let mergedStyle = $derived(
79
+ [componentStyle, `--kit-aspect-ratio: ${resolvedRatio}`, `--kit-aspect-fit: ${resolvedFit}`]
80
+ .filter(Boolean)
81
+ .join('; ')
82
+ );
83
+ </script>
84
+
85
+ <svelte:element
86
+ this={is}
87
+ bind:this={ref}
88
+ class={componentClass}
89
+ style={mergedStyle}
90
+ data-inline={inline}
91
+ {...restProps}
92
+ >
93
+ <div class="kit-aspect-ratio__inner">
94
+ {@render children?.()}
95
+ </div>
96
+ </svelte:element>
97
+
98
+ <style>
99
+ .kit-aspect-ratio {
100
+ display: block;
101
+ position: relative;
102
+ width: 100%;
103
+ max-width: 100%;
104
+ overflow: hidden;
105
+ aspect-ratio: var(--kit-aspect-ratio, 1.7777777778);
106
+ }
107
+
108
+ .kit-aspect-ratio[data-inline='true'] {
109
+ display: inline-block;
110
+ width: auto;
111
+ }
112
+
113
+ .kit-aspect-ratio__inner {
114
+ position: absolute;
115
+ inset: 0;
116
+ width: 100%;
117
+ height: 100%;
118
+ }
119
+
120
+ .kit-aspect-ratio :global(img),
121
+ .kit-aspect-ratio :global(video),
122
+ .kit-aspect-ratio :global(iframe),
123
+ .kit-aspect-ratio :global(canvas),
124
+ .kit-aspect-ratio :global(svg) {
125
+ display: block;
126
+ width: 100%;
127
+ height: 100%;
128
+ object-fit: var(--kit-aspect-fit, cover);
129
+ }
130
+ </style>
@@ -0,0 +1,4 @@
1
+ import type { AspectRatioProps } from './aspect-ratio.types.ts';
2
+ declare const AspectRatio: import("svelte").Component<AspectRatioProps, {}, "ref">;
3
+ type AspectRatio = ReturnType<typeof AspectRatio>;
4
+ export default AspectRatio;
@@ -0,0 +1,11 @@
1
+ import type { Component } from '../../utils/types/index.js';
2
+ export type AspectRatioValue = string | number;
3
+ export type AspectRatioFit = 'cover' | 'contain' | 'fill';
4
+ export interface AspectRatioProps extends Component {
5
+ ref?: HTMLElement | null;
6
+ is?: 'div' | 'span' | 'figure' | 'section' | 'article';
7
+ ratio?: AspectRatioValue;
8
+ aspectRatio?: AspectRatioValue;
9
+ fit?: AspectRatioFit;
10
+ inline?: boolean;
11
+ }
@@ -0,0 +1,287 @@
1
+ <script lang="ts">
2
+ import { useClassName, useStyles } from '../../utils/index.js';
3
+ import { makeComponentProps } from '../../compiler/mapped-code.js';
4
+ import { ripple } from '../../animations/index.js';
5
+ import type { CardProps } from './card.types.js';
6
+
7
+ let {
8
+ ref = $bindable(),
9
+ is = 'div',
10
+ children,
11
+ class: className = '',
12
+ style: styleAttr = '',
13
+ 's-class': sClass,
14
+ 's-style': sStyle,
15
+ href,
16
+ type,
17
+ variant = 'filled',
18
+ density = 'default',
19
+ rounded = 'md',
20
+ interactive = false,
21
+ active = false,
22
+ disabled = false,
23
+ noRipple,
24
+ ...rest
25
+ }: CardProps = $props();
26
+
27
+ let safeVariant = $derived(
28
+ variant === 'filled' || variant === 'outline' || variant === 'text' ? variant : 'filled'
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);
54
+ let isDisabled = $derived(!!disabled);
55
+ let resolvedHref = $derived(tag === 'a' && !isDisabled ? href : undefined);
56
+ let resolvedType = $derived(tag === 'button' ? (type ?? 'button') : undefined);
57
+ let resolvedDisabled = $derived(tag === 'button' ? isDisabled : undefined);
58
+ let resolvedTabIndex = $derived(tag === 'a' && isDisabled ? -1 : undefined);
59
+
60
+ let { classProps, styleProps, restProps } = $derived(
61
+ makeComponentProps(rest as Record<string, unknown>)
62
+ );
63
+
64
+ let componentClass = $derived(
65
+ useClassName({
66
+ baseClass: 'kit-card',
67
+ className: `${className ?? ''} kit-card--${safeVariant}`.trim(),
68
+ sClass,
69
+ classProps
70
+ })
71
+ );
72
+
73
+ let componentStyle = $derived(
74
+ useStyles({
75
+ styleAttr,
76
+ sStyle,
77
+ styleProps
78
+ })
79
+ );
80
+ </script>
81
+
82
+ <svelte:element
83
+ this={tag}
84
+ bind:this={ref}
85
+ class={componentClass}
86
+ style={componentStyle}
87
+ href={resolvedHref}
88
+ type={resolvedType}
89
+ disabled={resolvedDisabled}
90
+ tabindex={resolvedTabIndex}
91
+ data-density={safeDensity}
92
+ data-rounded={rounded}
93
+ data-interactive={isInteractive}
94
+ data-active={active}
95
+ data-disabled={isDisabled}
96
+ aria-disabled={isDisabled || undefined}
97
+ use:ripple={{
98
+ component: 'card',
99
+ disabled: noRipple || disabled || !isInteractive
100
+ }}
101
+ {...restProps}
102
+ >
103
+ {#if safeVariant === 'outline'}
104
+ <span class="outline"></span>
105
+ {/if}
106
+
107
+ {@render children?.()}
108
+ </svelte:element>
109
+
110
+ <style>
111
+ .kit-card {
112
+ --kit-card-bg: var(--kit-surface-2);
113
+ --kit-card-fg: var(--kit-fg);
114
+ --kit-card-outline-color: var(--kit-border);
115
+ --kit-card-radius: var(--kit-radius-2);
116
+ --kit-card-padding-compact: var(--kit-space-1);
117
+ --kit-card-padding-default: var(--kit-space-2);
118
+ --kit-card-padding-comfortable: var(--kit-space-3);
119
+
120
+ --card-shape: var(--kit-card-radius);
121
+ --card-bg: var(--kit-card-bg);
122
+ --card-fg: var(--kit-card-fg);
123
+ --card-hover-bg: color-mix(in oklab, var(--card-bg), var(--card-fg) 6%);
124
+ --card-active-bg: color-mix(in oklab, var(--card-bg), var(--card-fg) 10%);
125
+ --card-hover-fg: var(--card-fg);
126
+ --card-active-fg: var(--card-fg);
127
+
128
+ display: flex;
129
+ flex-direction: column;
130
+ gap: var(--kit-space-2);
131
+ background: var(--card-bg);
132
+ color: var(--card-fg);
133
+ border: 0;
134
+ border-radius: var(--kit-card-radius);
135
+ box-sizing: border-box;
136
+ position: relative;
137
+ transition:
138
+ background 140ms ease,
139
+ color 140ms ease,
140
+ box-shadow 140ms ease,
141
+ translate 140ms ease;
142
+ }
143
+
144
+ a.kit-card {
145
+ text-decoration: none;
146
+ }
147
+
148
+ button.kit-card {
149
+ appearance: none;
150
+ border: 0;
151
+ background: none;
152
+ font: inherit;
153
+ text-align: inherit;
154
+ }
155
+
156
+ .kit-card[data-rounded='0'] {
157
+ --kit-card-radius: 0;
158
+ }
159
+ .kit-card[data-rounded='xs'] {
160
+ --kit-card-radius: 4px;
161
+ }
162
+ .kit-card[data-rounded='sm'] {
163
+ --kit-card-radius: 6px;
164
+ }
165
+ .kit-card[data-rounded='md'] {
166
+ --kit-card-radius: 10px;
167
+ }
168
+ .kit-card[data-rounded='lg'] {
169
+ --kit-card-radius: 14px;
170
+ }
171
+ .kit-card[data-rounded='xl'] {
172
+ --kit-card-radius: 18px;
173
+ }
174
+
175
+ .kit-card[data-density='compact'] {
176
+ padding: var(--kit-card-padding-compact);
177
+ }
178
+ .kit-card[data-density='default'] {
179
+ padding: var(--kit-card-padding-default);
180
+ }
181
+ .kit-card[data-density='comfortable'] {
182
+ padding: var(--kit-card-padding-comfortable);
183
+ }
184
+
185
+ .kit-card--outline {
186
+ --outline-color: var(--kit-accent);
187
+ --card-bg: transparent;
188
+ --card-fg: var(--kit-accent);
189
+ --card-hover-bg: color-mix(in oklab, var(--kit-accent), transparent 80%);
190
+ --card-active-bg: color-mix(in oklab, var(--kit-accent), transparent 92%);
191
+ --kit-card-outline-color: var(--outline-color);
192
+ }
193
+
194
+ .kit-card--filled {
195
+ --card-bg: var(--kit-accent);
196
+ --card-fg: white;
197
+ --card-hover-bg: color-mix(in oklab, var(--kit-accent), black 10%);
198
+ --card-active-bg: color-mix(in oklab, var(--kit-accent), black 16%);
199
+ }
200
+
201
+ .kit-card--text {
202
+ background: transparent;
203
+ --card-bg: transparent;
204
+ --card-fg: var(--kit-accent);
205
+ --card-hover-bg: color-mix(in oklab, var(--kit-accent), transparent 80%);
206
+ --card-active-bg: color-mix(in oklab, var(--kit-accent), transparent 92%);
207
+ }
208
+
209
+ .kit-card[data-interactive='true'][data-disabled='false'] {
210
+ cursor: pointer;
211
+ }
212
+
213
+ .kit-card[data-interactive='true'][data-disabled='false']:hover {
214
+ translate: 0 -1px;
215
+ background: var(--card-hover-bg);
216
+ color: var(--card-hover-fg);
217
+ box-shadow: 0 10px 28px hsl(220 35% 8% / 0.12);
218
+ }
219
+
220
+ .kit-card--text[data-interactive='true'][data-disabled='false']:hover {
221
+ background: var(--card-hover-bg);
222
+ color: var(--card-hover-fg);
223
+ }
224
+
225
+ .kit-card[data-interactive='true'][data-active='true'][data-disabled='false'],
226
+ .kit-card[data-interactive='true'][data-disabled='false']:active {
227
+ translate: 0 0;
228
+ background: var(--card-active-bg);
229
+ color: var(--card-active-fg);
230
+ box-shadow: 0 4px 14px hsl(220 35% 8% / 0.1);
231
+ }
232
+
233
+ .kit-card--text[data-interactive='true'][data-active='true'][data-disabled='false'],
234
+ .kit-card--text[data-interactive='true'][data-disabled='false']:active {
235
+ background: var(--card-active-bg);
236
+ color: var(--card-active-fg);
237
+ }
238
+
239
+ .kit-card[data-interactive='true'][data-disabled='false']:focus-visible {
240
+ outline: 2px solid var(--kit-focus);
241
+ outline-offset: 2px;
242
+ }
243
+
244
+ .kit-card[data-disabled='true'] {
245
+ opacity: var(--kit-disabled-opacity, 0.55);
246
+ pointer-events: none;
247
+ }
248
+
249
+ .kit-card .outline {
250
+ --outline-color: var(--kit-card-outline-color);
251
+ --btn-radius: var(--kit-card-radius);
252
+ pointer-events: none;
253
+ }
254
+
255
+ .kit-card__media {
256
+ overflow: hidden;
257
+ border-radius: calc(var(--kit-card-radius) - 2px);
258
+ }
259
+
260
+ .kit-card__header {
261
+ font-weight: 600;
262
+ line-height: 1.3;
263
+ }
264
+
265
+ .kit-card__body {
266
+ display: block;
267
+ line-height: 1.45;
268
+ }
269
+
270
+ .kit-card__footer {
271
+ display: flex;
272
+ align-items: center;
273
+ justify-content: space-between;
274
+ gap: var(--kit-space-2);
275
+ flex-wrap: wrap;
276
+ }
277
+
278
+ .kit-card__footer-content {
279
+ color: var(--kit-muted);
280
+ }
281
+
282
+ .kit-card__actions {
283
+ display: inline-flex;
284
+ align-items: center;
285
+ gap: var(--kit-space-1);
286
+ }
287
+ </style>
@@ -0,0 +1,4 @@
1
+ import type { CardProps } from './card.types.ts';
2
+ declare const Card: import("svelte").Component<CardProps, {}, "ref">;
3
+ type Card = ReturnType<typeof Card>;
4
+ export default Card;
@@ -0,0 +1,14 @@
1
+ import type { Component, RoundedType } from '../../utils/types/index.js';
2
+ export interface CardProps extends Component {
3
+ ref?: HTMLElement | null;
4
+ is?: 'div' | 'article' | 'section' | 'aside' | 'a' | 'button';
5
+ href?: string;
6
+ type?: 'button' | 'submit' | 'reset';
7
+ variant?: 'filled' | 'outline' | 'text';
8
+ density?: 'compact' | 'default' | 'comfortable';
9
+ rounded?: RoundedType;
10
+ interactive?: boolean;
11
+ active?: boolean;
12
+ disabled?: boolean;
13
+ noRipple?: boolean;
14
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,501 @@
1
+ <script lang="ts">
2
+ import { useClassName, useStyles } from '../../utils/index.js';
3
+ import { makeComponentProps } from '../../compiler/mapped-code.js';
4
+ import { ripple } from '../../animations/index.js';
5
+ import type { ChipProps } from './chip.types.js';
6
+
7
+ let {
8
+ ref = $bindable(),
9
+ is = 'div',
10
+ children,
11
+ class: className = '',
12
+ style: styleAttr = '',
13
+ 's-class': sClass,
14
+ 's-style': sStyle,
15
+ variant = 'filled',
16
+ density = 'default',
17
+ loading,
18
+ active = false,
19
+ size = 'default',
20
+ labelStyle = false,
21
+ disabled = false,
22
+ href,
23
+ input,
24
+ type,
25
+ checked,
26
+ value,
27
+ label,
28
+ noRipple,
29
+ load,
30
+ append,
31
+ prepend,
32
+ readonly = false,
33
+ ...rest
34
+ }: ChipProps = $props();
35
+
36
+ let safeVariant = $derived(
37
+ variant === 'filled' || variant === 'outline' || variant === 'text' || variant === 'link'
38
+ ? variant
39
+ : 'filled'
40
+ );
41
+ let safeSize = $derived(
42
+ size === 'default'
43
+ ? 'md'
44
+ : size === 'xs' || size === 'sm' || size === 'md' || size === 'lg' || size === 'xl'
45
+ ? size
46
+ : 'md'
47
+ );
48
+ let safeDensity = $derived(
49
+ density === 'compact' || density === 'comfortable' || density === 'default'
50
+ ? density
51
+ : 'default'
52
+ );
53
+
54
+ let { classProps, styleProps, restProps } = $derived(
55
+ makeComponentProps(rest as Record<string, unknown>)
56
+ );
57
+
58
+ let componentClass = $derived(
59
+ useClassName({
60
+ baseClass: 'kit-chip',
61
+ className: `${className ?? ''} kit-chip--${safeVariant}`.trim(),
62
+ sClass,
63
+ classProps
64
+ })
65
+ );
66
+
67
+ let componentStyle = $derived(
68
+ useStyles({
69
+ styleAttr,
70
+ sStyle,
71
+ styleProps
72
+ })
73
+ );
74
+
75
+ const isInput = $derived(!!input);
76
+ const isDisabled = $derived(!!disabled);
77
+ const isReadonly = $derived(!!readonly);
78
+ const isLocked = $derived(isDisabled || isReadonly);
79
+
80
+ const hasOnClick = $derived(typeof restProps.onclick === 'function');
81
+ const hasOnKeyDown = $derived(typeof restProps.onkeydown === 'function');
82
+ const hasOnKeyUp = $derived(typeof restProps.onkeyup === 'function');
83
+ const hasOnPressHandler = $derived(hasOnClick || hasOnKeyDown || hasOnKeyUp);
84
+ const wantsActionTag = $derived(is === 'button' || is === 'a' || is === 'input');
85
+
86
+ const tag = $derived(
87
+ (href && 'a') ||
88
+ (isInput && 'input') ||
89
+ (wantsActionTag && is) ||
90
+ (hasOnPressHandler && 'button') ||
91
+ 'div'
92
+ );
93
+
94
+ const isInteractive = $derived(
95
+ (tag === 'button' || tag === 'a' || isInput || hasOnPressHandler) && !isLocked
96
+ );
97
+ const inputWrapperTag = $derived(type === 'checkbox' || type === 'radio' ? 'label' : 'div');
98
+ const resolvedHref = $derived(isLocked ? undefined : href);
99
+ const resolvedDisabled = $derived((tag === 'button' && isLocked) || undefined);
100
+
101
+ const resolvedType = $derived(tag !== 'button' ? type : (type ?? 'button'));
102
+ </script>
103
+
104
+ {#if isInput}
105
+ <svelte:element
106
+ this={inputWrapperTag}
107
+ bind:this={ref}
108
+ class={componentClass}
109
+ style={componentStyle}
110
+ data-size={safeSize}
111
+ data-variant={safeVariant}
112
+ data-loading={loading}
113
+ data-active={active}
114
+ data-disabled={isDisabled}
115
+ data-readonly={isReadonly}
116
+ data-density={safeDensity}
117
+ data-label-style={labelStyle}
118
+ data-interactive={isInteractive}
119
+ aria-busy={loading}
120
+ aria-disabled={isLocked || undefined}
121
+ use:ripple={{
122
+ component: 'chip',
123
+ disabled: noRipple || isLocked
124
+ }}
125
+ >
126
+ {#if safeVariant === 'outline'}
127
+ <span class="outline"></span>
128
+ {/if}
129
+ <input
130
+ {...restProps}
131
+ type={type || 'button'}
132
+ {checked}
133
+ {value}
134
+ aria-label={String(label || value)}
135
+ disabled={isLocked}
136
+ />
137
+ {#if loading}
138
+ <span class="spinner">
139
+ {#if load}
140
+ {@render load?.()}
141
+ {:else}
142
+ ...
143
+ {/if}
144
+ </span>
145
+ {/if}
146
+ </svelte:element>
147
+ {:else}
148
+ <svelte:element
149
+ this={tag}
150
+ bind:this={ref}
151
+ class={componentClass}
152
+ style={componentStyle}
153
+ {...restProps}
154
+ type={resolvedType}
155
+ href={resolvedHref}
156
+ data-size={safeSize}
157
+ data-variant={safeVariant}
158
+ data-loading={loading}
159
+ data-active={active}
160
+ data-disabled={isDisabled}
161
+ data-readonly={isReadonly}
162
+ data-density={safeDensity}
163
+ data-label-style={labelStyle}
164
+ data-interactive={isInteractive}
165
+ disabled={resolvedDisabled}
166
+ aria-busy={loading}
167
+ aria-disabled={((tag === 'a' || tag === 'div') && isLocked) || undefined}
168
+ tabindex={tag === 'a' && isLocked ? -1 : undefined}
169
+ use:ripple={{
170
+ component: 'chip',
171
+ disabled: noRipple || !isInteractive
172
+ }}
173
+ >
174
+ {#if safeVariant === 'outline'}
175
+ <span class="outline"></span>
176
+ {/if}
177
+
178
+ <span class="kit-chip__inner">
179
+ {#if prepend}
180
+ <span class="kit-chip__prepend">
181
+ {@render prepend?.()}
182
+ </span>
183
+ {/if}
184
+ <span class="kit-chip__content">
185
+ {@render children?.()}
186
+ </span>
187
+ {#if append}
188
+ <span class="kit-chip__append">
189
+ {@render append?.()}
190
+ </span>
191
+ {/if}
192
+ </span>
193
+
194
+ {#if loading}
195
+ <span class="spinner">
196
+ {#if load}
197
+ {@render load?.()}
198
+ {:else}
199
+ ...
200
+ {/if}
201
+ </span>
202
+ {/if}
203
+ </svelte:element>
204
+ {/if}
205
+
206
+ <style>
207
+ input {
208
+ border: 0;
209
+ padding: 0;
210
+ background: transparent;
211
+ color: inherit;
212
+ cursor: pointer;
213
+ }
214
+
215
+ button,
216
+ input,
217
+ select,
218
+ textarea {
219
+ font: inherit;
220
+ color: inherit;
221
+ }
222
+
223
+ button {
224
+ appearance: none;
225
+ background: none;
226
+ border: none;
227
+ }
228
+
229
+ .kit-chip {
230
+ --kit-chip-bg: var(--kit-surface-2);
231
+ --kit-chip-fg: var(--kit-fg);
232
+ --kit-chip-bd: var(--kit-border);
233
+ --kit-chip-bg--hover: color-mix(in oklab, var(--kit-chip-bg), var(--kit-chip-fg) 6%);
234
+ --kit-chip-bg--active: color-mix(in oklab, var(--kit-chip-bg), var(--kit-chip-fg) 10%);
235
+ --kit-chip-font: var(--kit-font);
236
+ --kit-chip-h-xs: 24px;
237
+ --kit-chip-h-sm: 28px;
238
+ --kit-chip-h-md: 32px;
239
+ --kit-chip-h-lg: 36px;
240
+ --kit-chip-h-xl: 40px;
241
+ --kit-chip-px-xs: 8px;
242
+ --kit-chip-px-sm: 10px;
243
+ --kit-chip-px-md: 12px;
244
+ --kit-chip-px-lg: 14px;
245
+ --kit-chip-px-xl: 16px;
246
+ --chip-density-scale: 1;
247
+ --chip-density-height-scale: 1;
248
+ --chip-radius: 99999px;
249
+ --kit-chip-gap: 0.35em;
250
+
251
+ position: relative;
252
+ display: inline-flex;
253
+ box-sizing: border-box;
254
+ align-items: center;
255
+ justify-content: center;
256
+ font-family: var(--kit-chip-font);
257
+ background: var(--chip-bg);
258
+ color: var(--chip-fg);
259
+ height: max(24px, calc(var(--chip-h) * var(--chip-density-height-scale)));
260
+ padding-inline: calc(var(--chip-px) * var(--chip-density-scale));
261
+ border-radius: var(--chip-radius);
262
+ text-decoration: none;
263
+ white-space: nowrap;
264
+ user-select: none;
265
+ cursor: default;
266
+ border: 0;
267
+ transition:
268
+ background 150ms ease,
269
+ transform 50ms ease;
270
+ }
271
+
272
+ .kit-chip[data-interactive='true'] {
273
+ cursor: pointer;
274
+ }
275
+
276
+ .kit-chip[data-interactive='true']:hover {
277
+ background: var(--chip-hover-bg);
278
+ color: var(--chip-hover-fg);
279
+ text-decoration: var(--chip-decoration);
280
+ }
281
+
282
+ .kit-chip[data-interactive='true']:active,
283
+ .kit-chip[data-active='true'] {
284
+ background: var(--chip-active-bg);
285
+ color: var(--chip-active-fg);
286
+ text-decoration: var(--chip-decoration);
287
+ transform: translateY(1px);
288
+ }
289
+
290
+ .kit-chip[data-active='true'][data-interactive='true']:hover {
291
+ background: var(--chip-hover-bg);
292
+ color: var(--chip-hover-fg);
293
+ text-decoration: var(--chip-decoration);
294
+ }
295
+
296
+ :is(.kit-chip:focus-visible, .kit-chip:has(> input:focus-visible)) {
297
+ outline: 2px solid var(--kit-focus);
298
+ outline-offset: 2px;
299
+ }
300
+
301
+ .kit-chip > input:focus-visible {
302
+ outline: none;
303
+ box-shadow: none;
304
+ }
305
+
306
+ .kit-chip > :is(input[type='checkbox'], input[type='radio']) {
307
+ appearance: none;
308
+ margin: 0;
309
+ cursor: pointer;
310
+ }
311
+
312
+ .kit-chip > :is(input[type='checkbox'], input[type='radio']):after {
313
+ --chip-content: attr(aria-label);
314
+ content: var(--chip-content);
315
+ cursor: pointer;
316
+ }
317
+
318
+ .kit-chip[data-variant='filled'] {
319
+ --chip-bg: var(--kit-accent);
320
+ --chip-fg: white;
321
+ --chip-hover-bg: color-mix(in oklab, var(--kit-accent), black 10%);
322
+ --chip-hover-fg: var(--chip-fg);
323
+ --chip-active-bg: color-mix(in oklab, var(--kit-accent), black 16%);
324
+ --chip-active-fg: var(--chip-fg);
325
+ }
326
+
327
+ .kit-chip[data-variant='outline'] {
328
+ --outline-color: var(--kit-accent);
329
+ }
330
+
331
+ .kit-chip[data-variant='outline'],
332
+ .kit-chip[data-variant='text'] {
333
+ --chip-bg: transparent;
334
+ --chip-fg: var(--kit-accent);
335
+ --chip-hover-bg: color-mix(in oklab, var(--kit-accent), transparent 80%);
336
+ --chip-hover-fg: var(--chip-fg);
337
+ --chip-active-bg: color-mix(in oklab, var(--kit-accent), transparent 92%);
338
+ --chip-active-fg: var(--chip-fg);
339
+ }
340
+
341
+ .kit-chip[data-variant='link'] {
342
+ --chip-bg: transparent;
343
+ --chip-fg: var(--kit-accent);
344
+ --chip-hover-fg: var(--chip-fg);
345
+ --chip-active-fg: var(--chip-fg);
346
+ --chip-decoration: underline;
347
+ height: inherit;
348
+ padding: 0;
349
+ }
350
+
351
+ .kit-chip[data-size='xs'] {
352
+ --chip-h: var(--kit-chip-h-xs);
353
+ --chip-px: var(--kit-chip-px-xs);
354
+ font-size: 12px;
355
+ }
356
+ .kit-chip[data-size='xs'] :global(.kit-icon:not([data-size])) {
357
+ --kit-icon-current-size: var(--kit-icon-size-xs);
358
+ }
359
+
360
+ .kit-chip[data-size='sm'] {
361
+ --chip-h: var(--kit-chip-h-sm);
362
+ --chip-px: var(--kit-chip-px-sm);
363
+ font-size: 13px;
364
+ }
365
+ .kit-chip[data-size='sm'] :global(.kit-icon:not([data-size])) {
366
+ --kit-icon-current-size: var(--kit-icon-size-sm);
367
+ }
368
+
369
+ .kit-chip[data-size='md'] {
370
+ --chip-h: var(--kit-chip-h-md);
371
+ --chip-px: var(--kit-chip-px-md);
372
+ font-size: 14px;
373
+ }
374
+ .kit-chip[data-size='md'] :global(.kit-icon:not([data-size])) {
375
+ --kit-icon-current-size: var(--kit-icon-size-md);
376
+ }
377
+
378
+ .kit-chip[data-size='lg'] {
379
+ --chip-h: var(--kit-chip-h-lg);
380
+ --chip-px: var(--kit-chip-px-lg);
381
+ font-size: 15px;
382
+ }
383
+ .kit-chip[data-size='lg'] :global(.kit-icon:not([data-size])) {
384
+ --kit-icon-current-size: var(--kit-icon-size-lg);
385
+ }
386
+
387
+ .kit-chip[data-size='xl'] {
388
+ --chip-h: var(--kit-chip-h-xl);
389
+ --chip-px: var(--kit-chip-px-xl);
390
+ font-size: 16px;
391
+ }
392
+ .kit-chip[data-size='xl'] :global(.kit-icon:not([data-size])) {
393
+ --kit-icon-current-size: var(--kit-icon-size-xl);
394
+ }
395
+
396
+ .kit-chip[data-density='default'] {
397
+ --chip-density-scale: 1;
398
+ --chip-density-height-scale: 1;
399
+ }
400
+
401
+ .kit-chip[data-density='compact'] {
402
+ --chip-density-scale: 0.92;
403
+ --chip-density-height-scale: 0.9;
404
+ }
405
+
406
+ .kit-chip[data-density='comfortable'] {
407
+ --chip-density-scale: 1.08;
408
+ --chip-density-height-scale: 1.08;
409
+ }
410
+
411
+ .kit-chip[data-label-style='true'] {
412
+ font-weight: 600;
413
+ letter-spacing: 0.01em;
414
+ text-transform: uppercase;
415
+ }
416
+
417
+ .kit-chip .outline {
418
+ pointer-events: none;
419
+ }
420
+
421
+ .kit-chip__inner {
422
+ display: inline-flex;
423
+ align-items: center;
424
+ justify-content: center;
425
+ gap: var(--kit-chip-gap);
426
+ line-height: 1;
427
+ }
428
+
429
+ .kit-chip__content,
430
+ .kit-chip__prepend,
431
+ .kit-chip__append {
432
+ display: inline-flex;
433
+ align-items: center;
434
+ justify-content: center;
435
+ line-height: 1;
436
+ }
437
+
438
+ .kit-chip__content :global(.kit-icon),
439
+ .kit-chip__prepend :global(.kit-icon),
440
+ .kit-chip__append :global(.kit-icon) {
441
+ display: inline-flex;
442
+ align-items: center;
443
+ justify-content: center;
444
+ vertical-align: middle;
445
+ }
446
+
447
+ .kit-chip__content :global(svg),
448
+ .kit-chip__prepend :global(svg),
449
+ .kit-chip__append :global(svg),
450
+ .kit-chip__content :global(img),
451
+ .kit-chip__prepend :global(img),
452
+ .kit-chip__append :global(img) {
453
+ display: block;
454
+ }
455
+
456
+ .kit-chip[data-loading='true'] .kit-chip__inner,
457
+ .kit-chip[data-loading='true'] input {
458
+ opacity: 0;
459
+ }
460
+
461
+ .kit-chip[data-loading='true'] {
462
+ pointer-events: none;
463
+ user-select: none;
464
+ }
465
+
466
+ .spinner {
467
+ position: absolute;
468
+ inset: 0;
469
+ display: flex;
470
+ align-items: center;
471
+ justify-content: center;
472
+ }
473
+
474
+ .kit-chip[data-readonly='true'],
475
+ .kit-chip[data-disabled='true'] {
476
+ pointer-events: none;
477
+ user-select: none;
478
+ cursor: default;
479
+ }
480
+
481
+ .kit-chip[data-disabled='true'] {
482
+ background: color-mix(in oklab, var(--chip-bg), transparent 70%);
483
+ color: color-mix(in oklab, var(--chip-fg), transparent 45%);
484
+ }
485
+
486
+ .kit-chip[data-disabled='true'] :global(.kit-icon),
487
+ .kit-chip[data-readonly='true'] :global(.kit-icon) {
488
+ color: color-mix(in oklab, var(--chip-fg), transparent 45%) !important;
489
+ --kit-icon-color: color-mix(in oklab, var(--chip-fg), transparent 45%) !important;
490
+ }
491
+
492
+ .kit-chip[data-disabled='true'] :global(.kit-icon img),
493
+ .kit-chip[data-disabled='true'] :global(.kit-icon .kit-icon__mask) {
494
+ opacity: 0.7;
495
+ filter: grayscale(0.2);
496
+ }
497
+ .kit-chip[data-readonly='true'] > input,
498
+ .kit-chip[data-disabled='true'] > input {
499
+ cursor: default;
500
+ }
501
+ </style>
@@ -0,0 +1,4 @@
1
+ import type { ChipProps } from './chip.types.ts';
2
+ declare const Chip: import("svelte").Component<ChipProps, {}, "ref">;
3
+ type Chip = ReturnType<typeof Chip>;
4
+ export default Chip;
@@ -0,0 +1,24 @@
1
+ import type { Component, SizeType } from '../../utils/types/index.js';
2
+ import type { Snippet } from 'svelte';
3
+ export interface ChipProps extends Component {
4
+ ref?: HTMLElement | null;
5
+ is?: 'div' | 'a' | 'input' | 'button';
6
+ input?: boolean;
7
+ href?: string;
8
+ variant?: 'outline' | 'text' | 'filled' | 'link';
9
+ density?: 'compact' | 'comfortable' | 'default';
10
+ active?: boolean;
11
+ loading?: boolean;
12
+ disabled?: boolean;
13
+ checked?: boolean;
14
+ size?: SizeType;
15
+ labelStyle?: boolean;
16
+ type?: 'button' | 'submit' | 'reset' | 'checkbox' | 'radio';
17
+ value?: string | number | boolean;
18
+ label?: string;
19
+ noRipple?: boolean;
20
+ readonly?: boolean;
21
+ load?: Snippet;
22
+ append?: Snippet;
23
+ prepend?: Snippet;
24
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -2,6 +2,9 @@ export { default as KitSheet } from './sheet/sheet.svelte';
2
2
  export { default as KitApp } from './app/app.svelte';
3
3
  export { default as KitBtn } from './btn/btn.svelte';
4
4
  export { default as KitIcon } from './icon/icon.svelte';
5
+ export { default as KitCard } from './card/card.svelte';
6
+ export { default as KitChip } from './chip/chip.svelte';
5
7
  export { default as KitAvatar } from './avatar/avatar.svelte';
8
+ export { default as KitAspectRatio } from './aspect-ratio/aspect-ratio.svelte';
6
9
  export { default as KitSpacer } from './spacer/spacer.svelte';
7
10
  export { default as KitSeparator } from './separator/separator.svelte';
@@ -3,6 +3,9 @@ export { default as KitSheet } from './sheet/sheet.svelte';
3
3
  export { default as KitApp } from './app/app.svelte';
4
4
  export { default as KitBtn } from './btn/btn.svelte';
5
5
  export { default as KitIcon } from './icon/icon.svelte';
6
+ export { default as KitCard } from './card/card.svelte';
7
+ export { default as KitChip } from './chip/chip.svelte';
6
8
  export { default as KitAvatar } from './avatar/avatar.svelte';
9
+ export { default as KitAspectRatio } from './aspect-ratio/aspect-ratio.svelte';
7
10
  export { default as KitSpacer } from './spacer/spacer.svelte';
8
11
  export { default as KitSeparator } from './separator/separator.svelte';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lapikit",
3
- "version": "0.4.7",
3
+ "version": "0.4.9",
4
4
  "license": "MIT",
5
5
  "publishConfig": {
6
6
  "access": "public"