@devvit/ui-renderer 0.10.20-next-2024-04-26-62f55e1ef.0 → 0.10.20-next-2024-04-29-43d2ba7f8.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.
Files changed (37) hide show
  1. package/client/formbuilder/components/image-field/devvit-image-field.d.ts +24 -0
  2. package/client/formbuilder/components/image-field/devvit-image-field.d.ts.map +1 -0
  3. package/client/formbuilder/components/image-field/devvit-image-field.js +158 -0
  4. package/client/formbuilder/components/image-field/drag-and-drop-controller.d.ts +19 -0
  5. package/client/formbuilder/components/image-field/drag-and-drop-controller.d.ts.map +1 -0
  6. package/client/formbuilder/components/image-field/drag-and-drop-controller.js +113 -0
  7. package/client/formbuilder/components/image-field/media-controller.d.ts +59 -0
  8. package/client/formbuilder/components/image-field/media-controller.d.ts.map +1 -0
  9. package/client/formbuilder/components/image-field/media-controller.js +207 -0
  10. package/client/formbuilder/components/image-field/render-empty-state.d.ts +15 -0
  11. package/client/formbuilder/components/image-field/render-empty-state.d.ts.map +1 -0
  12. package/client/formbuilder/components/image-field/render-empty-state.js +46 -0
  13. package/client/formbuilder/components/image-field/render-loading-state.d.ts +9 -0
  14. package/client/formbuilder/components/image-field/render-loading-state.d.ts.map +1 -0
  15. package/client/formbuilder/components/image-field/render-loading-state.js +27 -0
  16. package/client/formbuilder/components/image-field/render-media-carousel.d.ts +5 -0
  17. package/client/formbuilder/components/image-field/render-media-carousel.d.ts.map +1 -0
  18. package/client/formbuilder/components/image-field/render-media-carousel.js +92 -0
  19. package/client/formbuilder/components/image-field/render-media-preview.d.ts +15 -0
  20. package/client/formbuilder/components/image-field/render-media-preview.d.ts.map +1 -0
  21. package/client/formbuilder/components/image-field/render-media-preview.js +39 -0
  22. package/client/formbuilder/components/image-field/validate-image-size.d.ts +14 -0
  23. package/client/formbuilder/components/image-field/validate-image-size.d.ts.map +1 -0
  24. package/client/formbuilder/components/image-field/validate-image-size.js +47 -0
  25. package/client/formbuilder/components/image-field/validateMedia.d.ts +13 -0
  26. package/client/formbuilder/components/image-field/validateMedia.d.ts.map +1 -0
  27. package/client/formbuilder/components/image-field/validateMedia.js +29 -0
  28. package/client/formbuilder/fields/renderFieldLabel.d.ts +1 -1
  29. package/client/formbuilder/fields/renderFieldLabel.d.ts.map +1 -1
  30. package/client/formbuilder/fields/renderFieldLabel.js +3 -1
  31. package/client/formbuilder/fields/renderFormFields.d.ts.map +1 -1
  32. package/client/formbuilder/fields/renderFormFields.js +2 -1
  33. package/client/formbuilder/fields/renderImageField.d.ts +5 -0
  34. package/client/formbuilder/fields/renderImageField.d.ts.map +1 -0
  35. package/client/formbuilder/fields/renderImageField.js +26 -0
  36. package/package.json +8 -8
  37. package/styles.js +1 -1
@@ -0,0 +1,46 @@
1
+ import { IconSize } from '@reddit/faceplate-ui/lib/IconSize.js';
2
+ import { ButtonSize, button } from '@reddit/faceplate-ui/templates/button.js';
3
+ import IconUploadOutline from '@reddit/faceplate-ui/templates/client/icons/icon-upload-outline.js';
4
+ import { msg } from '@lit/localize';
5
+ import { html } from 'lit';
6
+ import { DragState } from './drag-and-drop-controller.js';
7
+ export function renderEmptyState({ allowImages, allowVideos, inputDragState, }) {
8
+ let label;
9
+ if (allowImages && allowVideos) {
10
+ label = msg('Drag and Drop images or videos or', {
11
+ desc: 'Label for file drag and drop files',
12
+ });
13
+ }
14
+ else if (allowImages) {
15
+ label = msg('Drag and Drop images or', { desc: 'Label for file drag and drop images' });
16
+ }
17
+ else {
18
+ label = msg('Drag and Drop videos or', { desc: 'Label for file drag and drop videos' });
19
+ }
20
+ if (inputDragState === DragState.IN_FRAME) {
21
+ label = msg('Drop here to upload', {
22
+ desc: 'Drop files here to upload.',
23
+ });
24
+ }
25
+ return html `
26
+ <div class="w-full flex items-center justify-center">
27
+ <div id="inputInfo" class="flex flex-row gap-xs items-center">
28
+ ${label}
29
+ ${button({
30
+ size: ButtonSize.Small,
31
+ shape: 'pill',
32
+ appearance: 'secondary',
33
+ attributes: {
34
+ type: 'button',
35
+ className: 'upload-media action',
36
+ id: 'device-upload-button',
37
+ },
38
+ leadingIcon: IconUploadOutline({
39
+ size: IconSize.Small,
40
+ }),
41
+ screenReaderContent: '',
42
+ })}
43
+ </div>
44
+ </div>
45
+ `;
46
+ }
@@ -0,0 +1,9 @@
1
+ import type { TemplateResult } from 'lit';
2
+ import type { MediaItem } from './media-controller.js';
3
+ /**
4
+ * This entire file was copied from shreddit
5
+ * I removed some parts of it that were too "shreddit post creation" focused, but kept the original code style
6
+ * Eventually we will remove it in favour of faceplate-ui image upload component, but for now we have this
7
+ */
8
+ export declare function renderLoadingState(media: MediaItem): TemplateResult<1>;
9
+ //# sourceMappingURL=render-loading-state.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render-loading-state.d.ts","sourceRoot":"","sources":["../../../../../library/src/client/formbuilder/components/image-field/render-loading-state.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,KAAK,CAAC;AAG1C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAEvD;;;;GAIG;AAEH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,SAAS,GAAG,cAAc,CAAC,CAAC,CAAC,CAmBtE"}
@@ -0,0 +1,27 @@
1
+ import { msg } from '@lit/localize';
2
+ import { html } from 'lit';
3
+ /**
4
+ * This entire file was copied from shreddit
5
+ * I removed some parts of it that were too "shreddit post creation" focused, but kept the original code style
6
+ * Eventually we will remove it in favour of faceplate-ui image upload component, but for now we have this
7
+ */
8
+ export function renderLoadingState(media) {
9
+ return html `
10
+ <div class="loading-state w-full h-full flex flex-col flex-1">
11
+ <div class="flex flex-col flex-1 justify-center items-center bg-neutral-background-weak">
12
+ <faceplate-progress
13
+ value="85"
14
+ class="animate-spin"
15
+ style="--loader-size: 1rem"
16
+ aria-label="${msg('Uploading media', { desc: 'Uploading media' })}"
17
+ ></faceplate-progress>
18
+ </div>
19
+ <div
20
+ class="border-neutral-border border-solid border-0 border-t-sm py-xs px-sm flex flex-col items-start"
21
+ >
22
+ <p class="selected-file-name m-0 text-12 line-clamp-1">${media?.file?.name}</p>
23
+ <p class="m-0 text-12">${msg('Uploading...', { desc: 'Uploading media' })}</p>
24
+ </div>
25
+ </div>
26
+ `;
27
+ }
@@ -0,0 +1,5 @@
1
+ import type { TemplateResult } from 'lit';
2
+ import type { MediaController, MediaItem } from './media-controller.js';
3
+ export declare function renderUploaderState(media: MediaItem): TemplateResult<1>;
4
+ export declare function renderCarousel(mediaController: MediaController): TemplateResult<1>;
5
+ //# sourceMappingURL=render-media-carousel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render-media-carousel.d.ts","sourceRoot":"","sources":["../../../../../library/src/client/formbuilder/components/image-field/render-media-carousel.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,KAAK,CAAC;AAE1C,OAAO,KAAK,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAwCxE,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,SAAS,GAAG,cAAc,CAAC,CAAC,CAAC,CAMvE;AAED,wBAAgB,cAAc,CAAC,eAAe,EAAE,eAAe,GAAG,cAAc,CAAC,CAAC,CAAC,CA4ClF"}
@@ -0,0 +1,92 @@
1
+ import { NAVIGATION_PLACEMENT, PAGINATION_PLACEMENT, } from '@reddit/faceplate-ui/components/faceplate-carousel.js';
2
+ import { IconSize } from '@reddit/faceplate-ui/lib/IconSize.js';
3
+ import { button, ButtonSize } from '@reddit/faceplate-ui/templates/button.js';
4
+ import IconDeleteOutline from '@reddit/faceplate-ui/templates/client/icons/icon-delete-outline.js';
5
+ import IconLeftFill from '@reddit/faceplate-ui/templates/client/icons/icon-left-fill.js';
6
+ import IconRightFill from '@reddit/faceplate-ui/templates/client/icons/icon-right-fill.js';
7
+ import { html } from 'lit';
8
+ import { renderLoadingState } from './render-loading-state.js';
9
+ import { renderMediaPreview } from './render-media-preview.js';
10
+ /**
11
+ * This entire file was copied from shreddit
12
+ * I removed some parts of it that were too "shreddit post creation" focused, but kept the original code style
13
+ * Eventually we will remove it in favour of faceplate-ui image upload component, but for now we have this
14
+ */
15
+ function renderDeleteButton(disabled) {
16
+ return button({
17
+ size: ButtonSize.Small,
18
+ shape: 'pill',
19
+ appearance: 'media',
20
+ attributes: {
21
+ type: 'button',
22
+ disabled,
23
+ className: 'remove-media remove action invisible group-hover:visible',
24
+ },
25
+ leadingIcon: IconDeleteOutline({
26
+ size: IconSize.Small,
27
+ }),
28
+ screenReaderContent: '',
29
+ });
30
+ }
31
+ function renderTopLeftActions() {
32
+ return html `
33
+ <div class="absolute top-xs left-xs">
34
+ <div class="flex gap-md"></div>
35
+ </div>
36
+ `;
37
+ }
38
+ function renderTopRightActions(disabled) {
39
+ return html `<div class="absolute top-xs right-xs">${renderDeleteButton(disabled)}</div> `;
40
+ }
41
+ export function renderUploaderState(media) {
42
+ if (media.status === 'loading') {
43
+ return renderLoadingState(media);
44
+ }
45
+ else {
46
+ return renderMediaPreview(media);
47
+ }
48
+ }
49
+ export function renderCarousel(mediaController) {
50
+ const hasLoadingMedia = mediaController.hasLoadingMedia();
51
+ return html `
52
+ <div class="w-full relative flex rounded-dx-md overflow-hidden">
53
+ <faceplate-carousel
54
+ autoplay="off"
55
+ nav-placement="${NAVIGATION_PLACEMENT.INSIDE}"
56
+ pagination-placement="${PAGINATION_PLACEMENT.OFF}"
57
+ advance-animation="true"
58
+ >
59
+ <span slot="prevButton">
60
+ ${button({
61
+ appearance: 'media',
62
+ size: ButtonSize.Small,
63
+ leadingIcon: IconLeftFill({ size: IconSize.Small }),
64
+ attributes: {
65
+ type: 'button',
66
+ id: 'media-carousel-prev',
67
+ },
68
+ })}
69
+ </span>
70
+ <ul>
71
+ ${mediaController.media.map((value) => {
72
+ return html `<li class="m-0 text-center rounded-dx-md">
73
+ ${renderUploaderState(value)}
74
+ </li>`;
75
+ })}
76
+ </ul>
77
+ <span slot="nextButton">
78
+ ${button({
79
+ appearance: 'media',
80
+ size: ButtonSize.Small,
81
+ leadingIcon: IconRightFill({ size: IconSize.Small }),
82
+ attributes: {
83
+ type: 'button',
84
+ id: 'media-carousel-next',
85
+ },
86
+ })}
87
+ </span>
88
+ </faceplate-carousel>
89
+ ${renderTopLeftActions()} ${renderTopRightActions(hasLoadingMedia)}
90
+ </div>
91
+ `;
92
+ }
@@ -0,0 +1,15 @@
1
+ import type { TemplateResult } from 'lit';
2
+ import type { MediaItem } from './media-controller.js';
3
+ /**
4
+ * This entire file was copied from shreddit
5
+ * I removed some parts of it that were too "shreddit post creation" focused, but kept the original code style
6
+ * Eventually we will remove it in favour of faceplate-ui image upload component, but for now we have this
7
+ */
8
+ export interface RenderMediaPreview {
9
+ handleRemoveClick: (event: Event, index: number) => void;
10
+ itemIndex: number;
11
+ }
12
+ export declare function renderImagePreview(image: MediaItem): TemplateResult<1>;
13
+ export declare function renderVideoPreview(video: MediaItem): TemplateResult<1>;
14
+ export declare function renderMediaPreview(media: MediaItem): TemplateResult<1>;
15
+ //# sourceMappingURL=render-media-preview.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render-media-preview.d.ts","sourceRoot":"","sources":["../../../../../library/src/client/formbuilder/components/image-field/render-media-preview.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,KAAK,CAAC;AAI1C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAEvD;;;;GAIG;AAEH,MAAM,WAAW,kBAAkB;IACjC,iBAAiB,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACzD,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,SAAS,GAAG,cAAc,CAAC,CAAC,CAAC,CAatE;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,SAAS,GAAG,cAAc,CAAC,CAAC,CAAC,CAetE;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,SAAS,GAAG,cAAc,CAAC,CAAC,CAAC,CAMtE"}
@@ -0,0 +1,39 @@
1
+ import { html } from 'lit';
2
+ import { ifDefined } from 'lit/directives/if-defined.js';
3
+ export function renderImagePreview(image) {
4
+ const { src } = image;
5
+ return html `
6
+ <div class="max-h-[min(20vw,150px)]">
7
+ <img src="${src}" class="w-full h-full" alt="" />
8
+ <img
9
+ src="${src}"
10
+ class="absolute top-0 left-0 w-full h-full object-cover object-center opacity-30 -z-10"
11
+ style="filter: blur(24px);"
12
+ alt=""
13
+ />
14
+ </div>
15
+ `;
16
+ }
17
+ export function renderVideoPreview(video) {
18
+ const { src, posterSrc, file } = video;
19
+ return html `
20
+ <div class="max-h-[max(23vw,250px)] w-full">
21
+ <shreddit-player
22
+ autoplay-pref
23
+ ui="desktop"
24
+ src="${src}"
25
+ class="w-full h-full"
26
+ poster="${ifDefined(posterSrc)}"
27
+ >
28
+ <source src="${src}" type="${file.type}" />
29
+ </shreddit-player>
30
+ </div>
31
+ `;
32
+ }
33
+ export function renderMediaPreview(media) {
34
+ return html `
35
+ <div class="flex relative justify-center align-center w-full h-full items-center flex-col">
36
+ ${media.type === 'video' ? renderVideoPreview(media) : renderImagePreview(media)}
37
+ </div>
38
+ `;
39
+ }
@@ -0,0 +1,14 @@
1
+ export type ValidationResult = {
2
+ valid: boolean;
3
+ error: string | null;
4
+ reason?: ImageValidationErrorReason | VideoValidationErrorReason;
5
+ };
6
+ type ImageValidationErrorReason = 'IMAGE_SIZE_LIMIT_EXCEEDED_ERROR';
7
+ type VideoValidationErrorReason = 'VIDEO_SIZE_LIMIT_EXCEEDED_ERROR';
8
+ interface FileInfo {
9
+ type: string;
10
+ size: number;
11
+ }
12
+ export declare function validateImageFileSize(file: FileInfo): ValidationResult;
13
+ export {};
14
+ //# sourceMappingURL=validate-image-size.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate-image-size.d.ts","sourceRoot":"","sources":["../../../../../library/src/client/formbuilder/components/image-field/validate-image-size.ts"],"names":[],"mappings":"AAgBA,MAAM,MAAM,gBAAgB,GAAG;IAC7B,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,MAAM,CAAC,EAAE,0BAA0B,GAAG,0BAA0B,CAAC;CAClE,CAAC;AAEF,KAAK,0BAA0B,GAAG,iCAAiC,CAAC;AACpE,KAAK,0BAA0B,GAAG,iCAAiC,CAAC;AAEpE,UAAU,QAAQ;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAGD,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,QAAQ,GAAG,gBAAgB,CAoDtE"}
@@ -0,0 +1,47 @@
1
+ import { msg, str } from '@lit/localize';
2
+ /**
3
+ * This entire file was copied from shreddit
4
+ * I removed some parts of it that were too "shreddit post creation" focused, but kept the original code style
5
+ * Eventually we will remove it in favour of faceplate-ui image upload component, but for now we have this
6
+ */
7
+ const KILOBYTE = 1024;
8
+ const MEGABYTE = KILOBYTE * KILOBYTE;
9
+ const GIGABYTE = KILOBYTE * MEGABYTE;
10
+ const MAX_IMAGE_FILE_SIZE = 2 * MEGABYTE; // 2MB
11
+ const MAX_GIF_FILE_SIZE = 2 * MEGABYTE; // 2MB
12
+ const MAX_VIDEO_FILE_SIZE = 1 * GIGABYTE; // 1GB
13
+ // TODO(ADE-7032): Rename to validateMediaFileSize
14
+ export function validateImageFileSize(file) {
15
+ const mimetype = file.type;
16
+ if (mimetype === 'image/gif' && file.size > MAX_GIF_FILE_SIZE) {
17
+ return {
18
+ valid: false,
19
+ error: msg(str `Upload failed, GIF size should be less than ${Math.floor(MAX_GIF_FILE_SIZE / MEGABYTE)}MB.`, {
20
+ desc: 'Error: gif size limit exceeded',
21
+ }),
22
+ reason: 'IMAGE_SIZE_LIMIT_EXCEEDED_ERROR',
23
+ };
24
+ }
25
+ if (mimetype.includes('image/') && mimetype !== 'image/gif' && file.size > MAX_IMAGE_FILE_SIZE) {
26
+ return {
27
+ valid: false,
28
+ error: msg(str `Upload failed, Image size should be less than ${Math.floor(MAX_IMAGE_FILE_SIZE / MEGABYTE)}MB.`, {
29
+ desc: 'Error: image size limit exceeded',
30
+ }),
31
+ reason: 'IMAGE_SIZE_LIMIT_EXCEEDED_ERROR',
32
+ };
33
+ }
34
+ if (mimetype.includes('video/') && file.size > MAX_VIDEO_FILE_SIZE) {
35
+ return {
36
+ valid: false,
37
+ error: msg(str `Upload failed, Video size should be less than ${Math.floor(MAX_VIDEO_FILE_SIZE / GIGABYTE)}GB.`, {
38
+ desc: 'Error: video size limit exceeded',
39
+ }),
40
+ reason: 'VIDEO_SIZE_LIMIT_EXCEEDED_ERROR',
41
+ };
42
+ }
43
+ return {
44
+ valid: true,
45
+ error: null,
46
+ };
47
+ }
@@ -0,0 +1,13 @@
1
+ export declare const MAX_VIDEO_FILE_SIZE: number;
2
+ export declare const MAX_VIDEO_DURATION: number;
3
+ export declare const MIN_VIDEO_DURATION = 2;
4
+ export declare const MIN_VIDEO_WIDTH = 50;
5
+ export declare const MIN_VIDEO_HEIGHT = 50;
6
+ export declare const ALLOWED_IMAGE_MIMETYPES: string[];
7
+ export declare const ALLOWED_VIDEO_MIMETYPES: string[];
8
+ export type ValidationResult = {
9
+ valid: boolean;
10
+ error: string | null;
11
+ };
12
+ export declare function validateImageFile(file: File): ValidationResult;
13
+ //# sourceMappingURL=validateMedia.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validateMedia.d.ts","sourceRoot":"","sources":["../../../../../library/src/client/formbuilder/components/image-field/validateMedia.ts"],"names":[],"mappings":"AAcA,eAAO,MAAM,mBAAmB,QAAe,CAAC;AAChD,eAAO,MAAM,kBAAkB,QAAU,CAAC;AAC1C,eAAO,MAAM,kBAAkB,IAAI,CAAC;AACpC,eAAO,MAAM,eAAe,KAAK,CAAC;AAClC,eAAO,MAAM,gBAAgB,KAAK,CAAC;AAEnC,eAAO,MAAM,uBAAuB,UAAyD,CAAC;AAC9F,eAAO,MAAM,uBAAuB,UAAmC,CAAC;AAExE,MAAM,MAAM,gBAAgB,GAAG;IAC7B,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB,CAAC;AAEF,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,IAAI,GAAG,gBAAgB,CAa9D"}
@@ -0,0 +1,29 @@
1
+ import { msg } from '@lit/localize/lit-localize.js';
2
+ import { validateImageFileSize } from './validate-image-size.js';
3
+ /**
4
+ * This entire file was copied from shreddit
5
+ * I removed some parts of it that were too "shreddit post creation" focused, but kept the original code style
6
+ * Eventually we will remove it in favour of faceplate-ui image upload component, but for now we have this
7
+ */
8
+ const KILOBYTE = 1024;
9
+ const MEGABYTE = KILOBYTE * KILOBYTE;
10
+ const GIGABYTE = KILOBYTE * MEGABYTE;
11
+ export const MAX_VIDEO_FILE_SIZE = 1 * GIGABYTE; // 1GB
12
+ export const MAX_VIDEO_DURATION = 60 * 15;
13
+ export const MIN_VIDEO_DURATION = 2; // 2 seconds
14
+ export const MIN_VIDEO_WIDTH = 50;
15
+ export const MIN_VIDEO_HEIGHT = 50;
16
+ export const ALLOWED_IMAGE_MIMETYPES = ['image/png', 'image/gif', 'image/jpeg', 'image/webp'];
17
+ export const ALLOWED_VIDEO_MIMETYPES = ['video/mp4', 'video/quicktime'];
18
+ export function validateImageFile(file) {
19
+ const mimetype = file.type;
20
+ if (!ALLOWED_IMAGE_MIMETYPES.includes(mimetype)) {
21
+ return {
22
+ valid: false,
23
+ error: msg('Sorry, we accept only files (.png, .jpeg, .gif, .webp).', {
24
+ desc: 'Error: invalid media type',
25
+ }),
26
+ };
27
+ }
28
+ return validateImageFileSize(file);
29
+ }
@@ -1,4 +1,4 @@
1
1
  import type { FormField } from '@devvit/protos';
2
2
  import type { TemplateResult } from 'lit';
3
- export declare const renderFieldLabel: (field: FormField) => TemplateResult;
3
+ export declare const renderFieldLabel: (field: FormField, classnames?: string) => TemplateResult;
4
4
  //# sourceMappingURL=renderFieldLabel.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"renderFieldLabel.d.ts","sourceRoot":"","sources":["../../../../library/src/client/formbuilder/fields/renderFieldLabel.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,KAAK,CAAC;AAK1C,eAAO,MAAM,gBAAgB,UAAW,SAAS,KAAG,cAC4B,CAAC"}
1
+ {"version":3,"file":"renderFieldLabel.d.ts","sourceRoot":"","sources":["../../../../library/src/client/formbuilder/fields/renderFieldLabel.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,KAAK,CAAC;AAK1C,eAAO,MAAM,gBAAgB,UAAW,SAAS,eAAe,MAAM,KAAG,cAGrE,CAAC"}
@@ -1,3 +1,5 @@
1
1
  import { html } from '@reddit/faceplate-ui/templateRenderingStrategy/clientStrategy.js';
2
2
  const isRequired = (field) => field.required === true ? html `<span class="text-danger-content">*</span>` : html ``;
3
- export const renderFieldLabel = (field) => html `<label for="${field.fieldId}">${field.label}${isRequired(field)}</label>`;
3
+ export const renderFieldLabel = (field, classnames) => html `<label for="${field.fieldId}" class="${classnames || ''}"
4
+ >${field.label}${isRequired(field)}</label
5
+ >`;
@@ -1 +1 @@
1
- {"version":3,"file":"renderFormFields.d.ts","sourceRoot":"","sources":["../../../../library/src/client/formbuilder/fields/renderFormFields.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,KAAK,CAAC;AAK1C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAuBhD,eAAO,MAAM,gBAAgB,WAAY,SAAS,EAAE,KAAG,cAEtD,CAAC"}
1
+ {"version":3,"file":"renderFormFields.d.ts","sourceRoot":"","sources":["../../../../library/src/client/formbuilder/fields/renderFormFields.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,KAAK,CAAC;AAK1C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAwBhD,eAAO,MAAM,gBAAgB,WAAY,SAAS,EAAE,KAAG,cAEtD,CAAC"}
@@ -7,10 +7,11 @@ import { renderGroupField } from './renderGroupField.js';
7
7
  import { renderSelectionField } from './renderSelectionField.js';
8
8
  import { renderNumberField } from './renderNumberField.js';
9
9
  import { renderParagraphField } from './renderParagraphField.js';
10
+ import { renderImageField } from './renderImageField.js';
10
11
  const renderFormField = (field) => html `
11
12
  ${choose(field.fieldType, [
12
13
  [FormFieldType.STRING, () => renderStringField(field)],
13
- // [FormFieldType.IMAGE, () => renderImageField(field)], // TODO Image support goes here! DX-6082/6083
14
+ [FormFieldType.IMAGE, () => renderImageField(field)],
14
15
  [FormFieldType.PARAGRAPH, () => renderParagraphField(field)],
15
16
  [FormFieldType.NUMBER, () => renderNumberField(field)],
16
17
  [FormFieldType.BOOLEAN, () => renderBooleanField(field)],
@@ -0,0 +1,5 @@
1
+ import type { FormField } from '@devvit/protos';
2
+ import '../components/image-field/devvit-image-field.js';
3
+ import type { TemplateResult } from 'lit';
4
+ export declare const renderImageField: (field: FormField) => TemplateResult;
5
+ //# sourceMappingURL=renderImageField.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"renderImageField.d.ts","sourceRoot":"","sources":["../../../../library/src/client/formbuilder/fields/renderImageField.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAKhD,OAAO,iDAAiD,CAAC;AACzD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,KAAK,CAAC;AAI1C,eAAO,MAAM,gBAAgB,UAAW,SAAS,KAAG,cAoBnD,CAAC"}
@@ -0,0 +1,26 @@
1
+ import { html } from '@reddit/faceplate-ui/templateRenderingStrategy/clientStrategy.js';
2
+ import { renderFieldLabel } from './renderFieldLabel.js';
3
+ import '../components/image-field/devvit-image-field.js';
4
+ import { renderHelpText } from './renderHelpText.js';
5
+ import { msg } from '@lit/localize';
6
+ export const renderImageField = (field) => {
7
+ return html ` <div>
8
+ ${renderFieldLabel(field, 'font-semibold text-14 text-neutral-content-strong')}
9
+ ${renderHelpText(field.helpText)}
10
+ <devvit-form-image-field
11
+ class="flex mt-xs"
12
+ name="${field.fieldId}"
13
+ .field="${field}"
14
+ ></devvit-form-image-field>
15
+ <div class="flex flex-row justify-between text-12 text-neutral-content-weak mt-xs">
16
+ <span
17
+ >${msg('Formats: JPG, PNG, GIF, WEBP', {
18
+ desc: 'Supported formats for image upload',
19
+ })}</span
20
+ >
21
+ <span
22
+ >${msg('Max size: 2 MB', { desc: 'Max file size for image upload is 2 megabytes' })}</span
23
+ >
24
+ </div>
25
+ </div>`;
26
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@devvit/ui-renderer",
3
- "version": "0.10.20-next-2024-04-26-62f55e1ef.0",
3
+ "version": "0.10.20-next-2024-04-29-43d2ba7f8.0",
4
4
  "license": "BSD-3-Clause",
5
5
  "repository": {
6
6
  "type": "git",
@@ -55,10 +55,10 @@
55
55
  },
56
56
  "types": "./index.d.ts",
57
57
  "dependencies": {
58
- "@devvit/protos": "0.10.20-next-2024-04-26-62f55e1ef.0",
59
- "@devvit/runtime-lite": "0.10.20-next-2024-04-26-62f55e1ef.0",
60
- "@devvit/runtimes": "0.10.20-next-2024-04-26-62f55e1ef.0",
61
- "@devvit/shared-types": "0.10.20-next-2024-04-26-62f55e1ef.0",
58
+ "@devvit/protos": "0.10.20-next-2024-04-29-43d2ba7f8.0",
59
+ "@devvit/runtime-lite": "0.10.20-next-2024-04-29-43d2ba7f8.0",
60
+ "@devvit/runtimes": "0.10.20-next-2024-04-29-43d2ba7f8.0",
61
+ "@devvit/shared-types": "0.10.20-next-2024-04-29-43d2ba7f8.0",
62
62
  "@dotlottie/player-component": "2.7.2",
63
63
  "nice-grpc-web": "3.3.3",
64
64
  "p-queue": "7.3.4",
@@ -85,9 +85,9 @@
85
85
  },
86
86
  "devDependencies": {
87
87
  "@devvit/eslint-config": "0.10.19",
88
- "@devvit/public-api": "0.10.20-next-2024-04-26-62f55e1ef.0",
88
+ "@devvit/public-api": "0.10.20-next-2024-04-29-43d2ba7f8.0",
89
89
  "@devvit/repo-tools": "0.10.19",
90
- "@devvit/tsconfig": "0.10.20-next-2024-04-26-62f55e1ef.0",
90
+ "@devvit/tsconfig": "0.10.20-next-2024-04-29-43d2ba7f8.0",
91
91
  "@lit-labs/ssr": "^2.2.3",
92
92
  "@lit/localize": "0.11.4",
93
93
  "@open-wc/testing-helpers": "2.3.0",
@@ -119,5 +119,5 @@
119
119
  "directory": "dist"
120
120
  },
121
121
  "source": "./src/index.ts",
122
- "gitHead": "54561cf807ae5ee9fdfb6446e53d13504f6f89e7"
122
+ "gitHead": "72891389be34e9ce8222c37ec3fe6abda8ff9eef"
123
123
  }