@extrachill/components 0.3.0 → 0.4.0
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/ImagePreview.d.ts +10 -0
- package/dist/ImagePreview.d.ts.map +1 -0
- package/dist/ImagePreview.js +4 -0
- package/dist/MediaField.d.ts +18 -0
- package/dist/MediaField.d.ts.map +1 -0
- package/dist/MediaField.js +14 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/package.json +1 -1
- package/src/ImagePreview.tsx +24 -0
- package/src/MediaField.tsx +70 -0
- package/src/index.tsx +2 -0
- package/styles/components.scss +64 -0
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
export interface ImagePreviewProps {
|
|
3
|
+
src: string;
|
|
4
|
+
alt?: string;
|
|
5
|
+
className?: string;
|
|
6
|
+
classPrefix?: string;
|
|
7
|
+
overlay?: ReactNode;
|
|
8
|
+
}
|
|
9
|
+
export declare function ImagePreview({ src, alt, className, classPrefix, overlay, }: ImagePreviewProps): import("react/jsx-runtime").JSX.Element;
|
|
10
|
+
//# sourceMappingURL=ImagePreview.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ImagePreview.d.ts","sourceRoot":"","sources":["../src/ImagePreview.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC,MAAM,WAAW,iBAAiB;IACjC,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,SAAS,CAAC;CACpB;AAED,wBAAgB,YAAY,CAAE,EAC7B,GAAG,EACH,GAAQ,EACR,SAAc,EACd,WAAgC,EAChC,OAAO,GACP,EAAE,iBAAiB,2CAOnB"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
export function ImagePreview({ src, alt = '', className = '', classPrefix = 'ec-image-preview', overlay, }) {
|
|
3
|
+
return (_jsxs("div", { className: [classPrefix, className].filter(Boolean).join(' '), children: [_jsx("img", { src: src, alt: alt, className: `${classPrefix}__image` }), overlay ? _jsx("div", { className: `${classPrefix}__overlay`, children: overlay }) : null] }));
|
|
4
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
export interface MediaFieldProps {
|
|
3
|
+
label?: ReactNode;
|
|
4
|
+
help?: ReactNode;
|
|
5
|
+
error?: ReactNode;
|
|
6
|
+
required?: boolean;
|
|
7
|
+
htmlFor?: string;
|
|
8
|
+
previewUrl?: string | null;
|
|
9
|
+
previewAlt?: string;
|
|
10
|
+
preview?: ReactNode;
|
|
11
|
+
empty?: ReactNode;
|
|
12
|
+
actions?: ReactNode;
|
|
13
|
+
children?: ReactNode;
|
|
14
|
+
className?: string;
|
|
15
|
+
classPrefix?: string;
|
|
16
|
+
}
|
|
17
|
+
export declare function MediaField({ label, help, error, required, htmlFor, previewUrl, previewAlt, preview, empty, actions, children, className, classPrefix, }: MediaFieldProps): import("react/jsx-runtime").JSX.Element;
|
|
18
|
+
//# sourceMappingURL=MediaField.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MediaField.d.ts","sourceRoot":"","sources":["../src/MediaField.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAKvC,MAAM,WAAW,eAAe;IAC/B,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,SAAS,CAAC;IACpB,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,OAAO,CAAC,EAAE,SAAS,CAAC;IACpB,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,wBAAgB,UAAU,CAAE,EAC3B,KAAK,EACL,IAAI,EACJ,KAAK,EACL,QAAgB,EAChB,OAAO,EACP,UAAU,EACV,UAAe,EACf,OAAO,EACP,KAAK,EACL,OAAO,EACP,QAAQ,EACR,SAAc,EACd,WAA8B,GAC9B,EAAE,eAAe,2CAkCjB"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { ActionRow } from "./ActionRow.js";
|
|
3
|
+
import { FieldGroup } from "./FieldGroup.js";
|
|
4
|
+
import { ImagePreview } from "./ImagePreview.js";
|
|
5
|
+
export function MediaField({ label, help, error, required = false, htmlFor, previewUrl, previewAlt = '', preview, empty, actions, children, className = '', classPrefix = 'ec-media-field', }) {
|
|
6
|
+
const mediaClassName = [classPrefix, className].filter(Boolean).join(' ');
|
|
7
|
+
const hasMeta = Boolean(label || help || error || required);
|
|
8
|
+
const previewContent = preview || (previewUrl ? _jsx(ImagePreview, { src: previewUrl, alt: previewAlt }) : null);
|
|
9
|
+
const body = (_jsxs(_Fragment, { children: [children ? _jsx("div", { className: `${classPrefix}__input`, children: children }) : null, _jsx("div", { className: `${classPrefix}__surface`, children: previewContent ? (_jsx("div", { className: `${classPrefix}__preview`, children: previewContent })) : empty ? (_jsx("div", { className: `${classPrefix}__empty`, children: empty })) : null }), actions ? _jsx(ActionRow, { className: `${classPrefix}__actions`, children: actions }) : null] }));
|
|
10
|
+
if (hasMeta) {
|
|
11
|
+
return (_jsx(FieldGroup, { label: label, help: help, error: error, required: required, htmlFor: htmlFor, className: mediaClassName, children: body }));
|
|
12
|
+
}
|
|
13
|
+
return _jsx("div", { className: mediaClassName, children: body });
|
|
14
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -13,4 +13,6 @@ export { PanelHeader, type PanelHeaderProps } from './PanelHeader.tsx';
|
|
|
13
13
|
export { ActionRow, type ActionRowProps } from './ActionRow.tsx';
|
|
14
14
|
export { FieldGroup, type FieldGroupProps } from './FieldGroup.tsx';
|
|
15
15
|
export { InlineStatus, type InlineStatusProps } from './InlineStatus.tsx';
|
|
16
|
+
export { ImagePreview, type ImagePreviewProps } from './ImagePreview.tsx';
|
|
17
|
+
export { MediaField, type MediaFieldProps } from './MediaField.tsx';
|
|
16
18
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,SAAS,EAAE,KAAK,cAAc,EAAE,KAAK,eAAe,EAAE,MAAM,iBAAiB,CAAC;AACvF,OAAO,EAAE,UAAU,EAAE,KAAK,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACpE,OAAO,EAAE,SAAS,EAAE,KAAK,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACjE,OAAO,EAAE,KAAK,EAAE,KAAK,UAAU,EAAE,MAAM,aAAa,CAAC;AACrD,OAAO,EAAE,IAAI,EAAE,KAAK,SAAS,EAAE,KAAK,OAAO,EAAE,MAAM,YAAY,CAAC;AAChE,OAAO,EAAE,KAAK,EAAE,KAAK,UAAU,EAAE,MAAM,aAAa,CAAC;AACrD,OAAO,EAAE,WAAW,EAAE,KAAK,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACvE,OAAO,EAAE,SAAS,EAAE,KAAK,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACjE,OAAO,EAAE,UAAU,EAAE,KAAK,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACpE,OAAO,EAAE,YAAY,EAAE,KAAK,iBAAiB,EAAE,MAAM,oBAAoB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,SAAS,EAAE,KAAK,cAAc,EAAE,KAAK,eAAe,EAAE,MAAM,iBAAiB,CAAC;AACvF,OAAO,EAAE,UAAU,EAAE,KAAK,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACpE,OAAO,EAAE,SAAS,EAAE,KAAK,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACjE,OAAO,EAAE,KAAK,EAAE,KAAK,UAAU,EAAE,MAAM,aAAa,CAAC;AACrD,OAAO,EAAE,IAAI,EAAE,KAAK,SAAS,EAAE,KAAK,OAAO,EAAE,MAAM,YAAY,CAAC;AAChE,OAAO,EAAE,KAAK,EAAE,KAAK,UAAU,EAAE,MAAM,aAAa,CAAC;AACrD,OAAO,EAAE,WAAW,EAAE,KAAK,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACvE,OAAO,EAAE,SAAS,EAAE,KAAK,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACjE,OAAO,EAAE,UAAU,EAAE,KAAK,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACpE,OAAO,EAAE,YAAY,EAAE,KAAK,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAC1E,OAAO,EAAE,YAAY,EAAE,KAAK,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAC1E,OAAO,EAAE,UAAU,EAAE,KAAK,eAAe,EAAE,MAAM,kBAAkB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -13,3 +13,5 @@ export { PanelHeader } from "./PanelHeader.js";
|
|
|
13
13
|
export { ActionRow } from "./ActionRow.js";
|
|
14
14
|
export { FieldGroup } from "./FieldGroup.js";
|
|
15
15
|
export { InlineStatus } from "./InlineStatus.js";
|
|
16
|
+
export { ImagePreview } from "./ImagePreview.js";
|
|
17
|
+
export { MediaField } from "./MediaField.js";
|
package/package.json
CHANGED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
|
|
3
|
+
export interface ImagePreviewProps {
|
|
4
|
+
src: string;
|
|
5
|
+
alt?: string;
|
|
6
|
+
className?: string;
|
|
7
|
+
classPrefix?: string;
|
|
8
|
+
overlay?: ReactNode;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function ImagePreview( {
|
|
12
|
+
src,
|
|
13
|
+
alt = '',
|
|
14
|
+
className = '',
|
|
15
|
+
classPrefix = 'ec-image-preview',
|
|
16
|
+
overlay,
|
|
17
|
+
}: ImagePreviewProps ) {
|
|
18
|
+
return (
|
|
19
|
+
<div className={ [ classPrefix, className ].filter( Boolean ).join( ' ' ) }>
|
|
20
|
+
<img src={ src } alt={ alt } className={ `${ classPrefix }__image` } />
|
|
21
|
+
{ overlay ? <div className={ `${ classPrefix }__overlay` }>{ overlay }</div> : null }
|
|
22
|
+
</div>
|
|
23
|
+
);
|
|
24
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
import { ActionRow } from './ActionRow.tsx';
|
|
3
|
+
import { FieldGroup } from './FieldGroup.tsx';
|
|
4
|
+
import { ImagePreview } from './ImagePreview.tsx';
|
|
5
|
+
|
|
6
|
+
export interface MediaFieldProps {
|
|
7
|
+
label?: ReactNode;
|
|
8
|
+
help?: ReactNode;
|
|
9
|
+
error?: ReactNode;
|
|
10
|
+
required?: boolean;
|
|
11
|
+
htmlFor?: string;
|
|
12
|
+
previewUrl?: string | null;
|
|
13
|
+
previewAlt?: string;
|
|
14
|
+
preview?: ReactNode;
|
|
15
|
+
empty?: ReactNode;
|
|
16
|
+
actions?: ReactNode;
|
|
17
|
+
children?: ReactNode;
|
|
18
|
+
className?: string;
|
|
19
|
+
classPrefix?: string;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function MediaField( {
|
|
23
|
+
label,
|
|
24
|
+
help,
|
|
25
|
+
error,
|
|
26
|
+
required = false,
|
|
27
|
+
htmlFor,
|
|
28
|
+
previewUrl,
|
|
29
|
+
previewAlt = '',
|
|
30
|
+
preview,
|
|
31
|
+
empty,
|
|
32
|
+
actions,
|
|
33
|
+
children,
|
|
34
|
+
className = '',
|
|
35
|
+
classPrefix = 'ec-media-field',
|
|
36
|
+
}: MediaFieldProps ) {
|
|
37
|
+
const mediaClassName = [ classPrefix, className ].filter( Boolean ).join( ' ' );
|
|
38
|
+
const hasMeta = Boolean( label || help || error || required );
|
|
39
|
+
const previewContent = preview || ( previewUrl ? <ImagePreview src={ previewUrl } alt={ previewAlt } /> : null );
|
|
40
|
+
const body = (
|
|
41
|
+
<>
|
|
42
|
+
{ children ? <div className={ `${ classPrefix }__input` }>{ children }</div> : null }
|
|
43
|
+
<div className={ `${ classPrefix }__surface` }>
|
|
44
|
+
{ previewContent ? (
|
|
45
|
+
<div className={ `${ classPrefix }__preview` }>{ previewContent }</div>
|
|
46
|
+
) : empty ? (
|
|
47
|
+
<div className={ `${ classPrefix }__empty` }>{ empty }</div>
|
|
48
|
+
) : null }
|
|
49
|
+
</div>
|
|
50
|
+
{ actions ? <ActionRow className={ `${ classPrefix }__actions` }>{ actions }</ActionRow> : null }
|
|
51
|
+
</>
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
if ( hasMeta ) {
|
|
55
|
+
return (
|
|
56
|
+
<FieldGroup
|
|
57
|
+
label={ label }
|
|
58
|
+
help={ help }
|
|
59
|
+
error={ error }
|
|
60
|
+
required={ required }
|
|
61
|
+
htmlFor={ htmlFor }
|
|
62
|
+
className={ mediaClassName }
|
|
63
|
+
>
|
|
64
|
+
{ body }
|
|
65
|
+
</FieldGroup>
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return <div className={ mediaClassName }>{ body }</div>;
|
|
70
|
+
}
|
package/src/index.tsx
CHANGED
|
@@ -14,3 +14,5 @@ export { PanelHeader, type PanelHeaderProps } from './PanelHeader.tsx';
|
|
|
14
14
|
export { ActionRow, type ActionRowProps } from './ActionRow.tsx';
|
|
15
15
|
export { FieldGroup, type FieldGroupProps } from './FieldGroup.tsx';
|
|
16
16
|
export { InlineStatus, type InlineStatusProps } from './InlineStatus.tsx';
|
|
17
|
+
export { ImagePreview, type ImagePreviewProps } from './ImagePreview.tsx';
|
|
18
|
+
export { MediaField, type MediaFieldProps } from './MediaField.tsx';
|
package/styles/components.scss
CHANGED
|
@@ -249,6 +249,70 @@
|
|
|
249
249
|
color: #004085;
|
|
250
250
|
}
|
|
251
251
|
|
|
252
|
+
// Image Preview
|
|
253
|
+
.ec-image-preview {
|
|
254
|
+
display: inline-flex;
|
|
255
|
+
align-items: center;
|
|
256
|
+
justify-content: center;
|
|
257
|
+
position: relative;
|
|
258
|
+
max-width: 100%;
|
|
259
|
+
overflow: hidden;
|
|
260
|
+
border: 1px solid var(--border-color, #ddd);
|
|
261
|
+
border-radius: var(--border-radius-md, 6px);
|
|
262
|
+
background: var(--background-color, #fff);
|
|
263
|
+
padding: var(--spacing-xs, 0.25rem);
|
|
264
|
+
box-sizing: border-box;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
.ec-image-preview__image {
|
|
268
|
+
display: block;
|
|
269
|
+
max-width: min(100%, var(--ec-image-preview-max-width, 220px));
|
|
270
|
+
width: auto;
|
|
271
|
+
height: auto;
|
|
272
|
+
border-radius: inherit;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
.ec-image-preview__overlay {
|
|
276
|
+
position: absolute;
|
|
277
|
+
inset: 0;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
// Media Field
|
|
281
|
+
.ec-media-field {
|
|
282
|
+
display: grid;
|
|
283
|
+
gap: var(--spacing-sm, 0.5rem);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
.ec-media-field__input {
|
|
287
|
+
display: grid;
|
|
288
|
+
gap: var(--spacing-xs, 0.25rem);
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
.ec-media-field__surface {
|
|
292
|
+
display: grid;
|
|
293
|
+
gap: var(--spacing-sm, 0.5rem);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
.ec-media-field__preview,
|
|
297
|
+
.ec-media-field__empty {
|
|
298
|
+
display: grid;
|
|
299
|
+
gap: var(--spacing-sm, 0.5rem);
|
|
300
|
+
justify-items: start;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
.ec-media-field__empty {
|
|
304
|
+
padding: var(--spacing-md, 1rem);
|
|
305
|
+
border: 1px dashed var(--border-color, #ddd);
|
|
306
|
+
border-radius: var(--border-radius-md, 6px);
|
|
307
|
+
background: var(--background-color, #fff);
|
|
308
|
+
color: var(--muted-text, #666);
|
|
309
|
+
font-size: var(--font-size-sm, 0.875rem);
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
.ec-media-field__actions {
|
|
313
|
+
margin-top: 0;
|
|
314
|
+
}
|
|
315
|
+
|
|
252
316
|
// Badges (commonly used with tables)
|
|
253
317
|
.ec-badge {
|
|
254
318
|
display: inline-block;
|