Skip to content

Commit 25fef8b

Browse files
committed
feat(plugins): extract cloud image editor as a plugin
1 parent bd486c0 commit 25fef8b

File tree

10 files changed

+330
-10
lines changed

10 files changed

+330
-10
lines changed
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
<!doctype html>
2+
<head>
3+
<meta name="viewport" content="width=device-width, initial-scale=1">
4+
<style>
5+
body {
6+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
7+
margin: 24px;
8+
line-height: 1.5;
9+
}
10+
h1 {
11+
font-size: 22px;
12+
margin: 0 0 12px;
13+
}
14+
p {
15+
margin: 0 0 12px;
16+
color: #374151;
17+
}
18+
@media (prefers-color-scheme: dark) {
19+
body { background: #0f1115; color: #f9fafb; }
20+
p { color: #9ca3af; }
21+
}
22+
</style>
23+
<link
24+
rel="stylesheet"
25+
href="https://cdn.jsdelivr.net/npm/@uploadcare/file-uploader@1.27.0-alpha.1/dist/core.css"
26+
/>
27+
<script type="module">
28+
import * as UC from 'https://cdn.jsdelivr.net/npm/@uploadcare/file-uploader@1.27.0-alpha.1/dist/core.js';
29+
30+
UC.defineComponents(UC);
31+
</script>
32+
</head>
33+
<body>
34+
<h1>Cloud Image Editor Plugin (CDN demo)</h1>
35+
<p>Load the built-in cloud editor as a plugin and use the edit action on uploaded images.</p>
36+
37+
<uc-file-uploader-regular ctx-name="cloud-editor-demo"></uc-file-uploader-regular>
38+
<uc-config
39+
ctx-name="cloud-editor-demo"
40+
pubkey="demopublickey"
41+
debug
42+
quality-insights="false"
43+
test-mode
44+
source-list="local, url, camera, dropbox, gdrive"
45+
use-cloud-image-editor="false"
46+
></uc-config>
47+
<uc-upload-ctx-provider ctx-name="cloud-editor-demo"></uc-upload-ctx-provider>
48+
</body>
49+
</html>
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
<!doctype html>
2+
<head>
3+
<meta name="viewport" content="width=device-width, initial-scale=1">
4+
<style>
5+
body {
6+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
7+
margin: 24px;
8+
line-height: 1.5;
9+
}
10+
h1 {
11+
font-size: 22px;
12+
margin: 0 0 12px;
13+
}
14+
p {
15+
margin: 0 0 12px;
16+
color: #374151;
17+
}
18+
@media (prefers-color-scheme: dark) {
19+
body { background: #0f1115; color: #f9fafb; }
20+
p { color: #9ca3af; }
21+
}
22+
</style>
23+
<script type="module">
24+
import '@/solutions/file-uploader/regular/index.css';
25+
import * as UC from '@/core';
26+
27+
UC.defineComponents(UC);
28+
</script>
29+
</head>
30+
<body>
31+
<h1>Cloud Image Editor Plugin</h1>
32+
<p>Load the built-in cloud editor as a plugin and use the edit action on uploaded images.</p>
33+
34+
<uc-file-uploader-regular ctx-name="cloud-editor-demo"></uc-file-uploader-regular>
35+
<uc-config
36+
ctx-name="cloud-editor-demo"
37+
pubkey="demopublickey"
38+
debug
39+
quality-insights="false"
40+
test-mode
41+
source-list="local, url, camera, dropbox, gdrive"
42+
use-cloud-image-editor="true"
43+
></uc-config>
44+
<uc-upload-ctx-provider ctx-name="cloud-editor-demo"></uc-upload-ctx-provider>
45+
</body>
46+
</html>

package.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,12 @@
4646
"browser": "./dist/index.js",
4747
"default": "./dist/index.js"
4848
},
49+
"./core": {
50+
"types": "./dist/core.d.ts",
51+
"node": "./dist/index.ssr.js",
52+
"browser": "./dist/core.js",
53+
"default": "./dist/core.js"
54+
},
4955
"./index.css": {
5056
"types": "./types/css.d.ts",
5157
"default": "./dist/index.css"
@@ -170,6 +176,10 @@
170176
"nanostores": "^1.1.0"
171177
},
172178
"size-limit": [
179+
{
180+
"path": "dist/core.js",
181+
"limit": "100 KB"
182+
},
173183
{
174184
"path": "dist/index.js",
175185
"limit": "100 KB"

scripts/build-items.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,19 @@ export interface BuildItem {
2121
cssFilename?: string;
2222
bundleExternalDependencies: boolean;
2323
mangleProps?: boolean;
24+
codeSplitting?: boolean;
2425
}
2526

2627
export const buildItems: BuildItem[] = [
28+
{
29+
entry: [srcPath('./core.ts')],
30+
outDir: outPath('./dist/'),
31+
format: 'esm',
32+
minify: true,
33+
bundleExternalDependencies: true,
34+
mangleProps: false,
35+
codeSplitting: true,
36+
},
2737
{
2838
entry: [
2939
srcPath('./index.ts'),

scripts/build.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,12 +53,16 @@ async function build(buildItem: BuildItem) {
5353
if (buildItem.mangleProps) {
5454
options.mangleProps = /^_/;
5555
}
56+
if (buildItem.codeSplitting) {
57+
options.splitting = true;
58+
options.supported = { 'dynamic-import': true };
59+
}
5660
},
5761
esbuildPlugins: buildItem.minify ? [minifyTemplates(), writeFiles()] : [],
5862
noExternal: buildItem.bundleExternalDependencies ? [/.*/] : undefined,
5963
globalName: buildItem.format === 'iife' ? 'UC' : undefined,
6064
keepNames: buildItem.format === 'iife' ? true : undefined,
61-
splitting: false,
65+
splitting: buildItem.codeSplitting ?? false,
6266
treeshake: true,
6367
shims: false,
6468
dts: true,

src/blocks/CloudImageEditorActivity/CloudImageEditorActivity.ts

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,6 @@ type EditorTemplateConfig = {
2020
};
2121

2222
export class CloudImageEditorActivity extends LitUploaderBlock {
23-
public override couldBeCtxOwner = true;
24-
public override activityType = LitActivityBlock.activities.CLOUD_IMG_EDIT;
25-
2623
private _entry?: TypedData<UploadEntryData>;
2724

2825
@state()
@@ -40,11 +37,6 @@ export class CloudImageEditorActivity extends LitUploaderBlock {
4037
public override initCallback(): void {
4138
super.initCallback();
4239

43-
this.registerActivity(this.activityType, {
44-
onActivate: () => this._mountEditor(),
45-
onDeactivate: () => this._unmountEditor(),
46-
});
47-
4840
this.subConfigValue('cropPreset', (cropPreset) => {
4941
if (!this._editorConfig) {
5042
return;
@@ -70,6 +62,13 @@ export class CloudImageEditorActivity extends LitUploaderBlock {
7062
tabs,
7163
};
7264
});
65+
66+
this._mountEditor();
67+
}
68+
69+
public override disconnectedCallback(): void {
70+
super.disconnectedCallback();
71+
this._unmountEditor();
7372
}
7473

7574
private _handleApply(e: CustomEvent<ApplyResult>): void {

src/blocks/CloudImageEditorActivity/cloud-image-editor-activity.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
background-color: var(--uc-background);
99
}
1010

11-
[uc-modal] > dialog:has(uc-cloud-image-editor-activity[active]) {
11+
[uc-modal] > dialog:has([activity="cloud-image-edit"][active]) {
1212
width: 100%;
1313
height: 100%;
1414
}

src/blocks/Config/computed-properties.ts

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { getPrefixedCdnBaseAsync, isPrefixedCdnBase } from '@uploadcare/cname-prefix/async';
2+
import type { UploaderPlugin } from '../../abstract/managers/plugin';
23
import type { ConfigType } from '../../types/index';
34
import { deserializeCsv, serializeCsv } from '../../utils/comma-separated';
45
import { isPromiseLike } from '../../utils/isPromiseLike';
@@ -73,6 +74,45 @@ const COMPUTED_PROPERTIES = [
7374
return cdnCname;
7475
},
7576
}),
77+
defineComputedProperty({
78+
key: 'plugins',
79+
deps: ['useCloudImageEditor'] as const,
80+
fn: async ({ plugins, useCloudImageEditor }, { signal }) => {
81+
const CLOUD_EDITOR_PLUGIN_ID = 'cloud-image-editor';
82+
const basePlugins: UploaderPlugin[] = Array.isArray(plugins)
83+
? plugins.filter((p) => p?.id !== CLOUD_EDITOR_PLUGIN_ID)
84+
: [];
85+
86+
if (!useCloudImageEditor) {
87+
return basePlugins;
88+
}
89+
90+
try {
91+
const module = await import('../../plugins/cloudImageEditorPlugin');
92+
if (signal.aborted) return basePlugins;
93+
94+
const plugin: UploaderPlugin | undefined =
95+
(module as { cloudImageEditorPlugin?: UploaderPlugin }).cloudImageEditorPlugin ??
96+
(module as { default?: UploaderPlugin }).default;
97+
98+
if (!plugin) {
99+
console.warn('[CloudImageEditorPlugin] Plugin module did not export a plugin');
100+
return basePlugins;
101+
}
102+
103+
if (basePlugins.some((p) => p.id === plugin.id)) {
104+
return basePlugins;
105+
}
106+
107+
return [...basePlugins, plugin];
108+
} catch (error) {
109+
if (!signal.aborted) {
110+
console.warn('[CloudImageEditorPlugin] Failed to load plugin', error);
111+
}
112+
return basePlugins;
113+
}
114+
},
115+
}),
76116
];
77117

78118
type ConfigSetter = <TSetValue extends ConfigKey>(key: TSetValue, value: ConfigValue<TSetValue>) => void;
@@ -107,6 +147,7 @@ export const computeProperty = <TKey extends ConfigKey>({
107147

108148
let result: ConfigValue<typeof computed.key> | Promise<ConfigValue<typeof computed.key>>;
109149
try {
150+
// @ts-expect-error - TODO: try to fix those types
110151
result = computed.fn(args as ComputedPropertyArgs<typeof computed.key, typeof computed.deps>, {
111152
signal: abortController.signal,
112153
});

src/core.ts

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/** biome-ignore-all assist/source/organizeImports: Order should be pretty */
2+
import './blocks/themes/uc-basic/index.css';
3+
4+
// Symbiote.js
5+
export { PubSub as Data } from './lit/PubSubCompat';
6+
export { BaseComponent } from './lit/BaseComponent';
7+
export { UID } from './utils/UID';
8+
9+
// Utils:
10+
export { defineComponents } from './abstract/defineComponents';
11+
export { loadFileUploaderFrom } from './abstract/loadFileUploaderFrom';
12+
export { defineLocale } from './abstract/localeRegistry';
13+
export { ModalEvents, type ModalId } from './abstract/managers/ModalManager';
14+
export { toKebabCase } from './utils/toKebabCase';
15+
16+
// Abstract:
17+
export { LitBlock as Block } from './lit/LitBlock';
18+
export { LitSolutionBlock as SolutionBlock } from './lit/LitSolutionBlock';
19+
export { LitUploaderBlock as UploaderBlock } from './lit/LitUploaderBlock';
20+
export { LitActivityBlock as ActivityBlock } from './lit/LitActivityBlock';
21+
22+
// Shared:
23+
export { Icon } from './blocks/Icon/Icon';
24+
export { Img } from './blocks/Img/Img';
25+
export { Modal } from './blocks/Modal/Modal';
26+
export { FormInput } from './blocks/FormInput/FormInput';
27+
export { Copyright } from './blocks/Copyright/Copyright';
28+
export { ProgressBar } from './blocks/ProgressBar/ProgressBar';
29+
export { ProgressBarCommon } from './blocks/ProgressBarCommon/ProgressBarCommon';
30+
export { Select } from './blocks/Select/Select';
31+
export { SourceBtn } from './blocks/SourceBtn/SourceBtn';
32+
export { SourceList } from './blocks/SourceList/SourceList';
33+
export { Spinner } from './blocks/Spinner/Spinner';
34+
export { Thumb } from './blocks/Thumb/Thumb';
35+
export { ActivityHeader } from './blocks/ActivityHeader/ActivityHeader';
36+
37+
// Composed:
38+
export { StartFrom } from './blocks/StartFrom/StartFrom';
39+
export { UploadCtxProvider } from './blocks/UploadCtxProvider/UploadCtxProvider';
40+
export { UploadList } from './blocks/UploadList/UploadList';
41+
export { UrlSource } from './blocks/UrlSource/UrlSource';
42+
export { CameraSource } from './blocks/CameraSource/CameraSource';
43+
export { Config } from './blocks/Config/Config';
44+
export { DropArea } from './blocks/DropArea/DropArea';
45+
export { ExternalSource } from './blocks/ExternalSource/ExternalSource';
46+
export { FileItem } from './blocks/FileItem/FileItem';
47+
export { ExternalUploadSource, UploadSource } from './utils/UploadSource';
48+
export { SimpleBtn } from './blocks/SimpleBtn/SimpleBtn';
49+
export { PluginActivityRenderer, PluginActivityHost } from './blocks/PluginActivityRenderer';
50+
51+
// Solutions:
52+
export { FileUploaderRegular } from './solutions/file-uploader/regular/FileUploaderRegular';
53+
export { FileUploaderInline } from './solutions/file-uploader/inline/FileUploaderInline';
54+
export { FileUploaderMinimal } from './solutions/file-uploader/minimal/FileUploaderMinimal';
55+
56+
// Types
57+
export * from './types/index';
58+
59+
// Other
60+
export * from './env';

0 commit comments

Comments
 (0)