@sendbird/uikit-react
Version: 
Sendbird UIKit for React: A feature-rich and customizable chat UI kit with messaging, channel management, and user authentication.
986 lines (972 loc) • 116 kB
JavaScript
import React__default, { createContext, useState, useCallback, useContext, useRef, useMemo, useLayoutEffect, useEffect } from 'react';
var ComponentType;
(function (ComponentType) {
    ComponentType["Box"] = "box";
    ComponentType["Text"] = "text";
    ComponentType["Image"] = "image";
    ComponentType["TextButton"] = "textButton";
    ComponentType["ImageButton"] = "imageButton";
    ComponentType["Carousel"] = "carouselView";
    ComponentType["Cascade"] = "cascadeView";
})(ComponentType || (ComponentType = {}));
const outSingle$1 = (key, obj) => {
    if (typeof obj[key] !== 'string')
        return {};
    return { [key]: argbToRgba(obj[key]) };
};
function argbToRgba(string) {
    if (!string.startsWith('#')) {
        return string;
    }
    if (string.length === 9) {
        return `#${string.slice(3)}${string[1]}${string[2]}`;
    }
    if (string.length === 5) {
        return `#${string.slice(2)}${string[1]}`;
    }
    return string;
}
const outViewStyle$1 = (viewStyle) => {
    if (!viewStyle)
        return {};
    return {
        viewStyle: Object.assign(Object.assign(Object.assign({}, viewStyle), outSingle$1('backgroundColor', viewStyle)), outSingle$1('borderColor', viewStyle)),
    };
};
const outTextStyle$1 = (textStyle) => {
    if (!textStyle)
        return {};
    return {
        textStyle: Object.assign(Object.assign({}, textStyle), outSingle$1('color', textStyle)),
    };
};
const outImageStyle = (imageStyle) => {
    if (!imageStyle)
        return {};
    return {
        imageStyle: Object.assign(Object.assign({}, imageStyle), outSingle$1('tintColor', imageStyle)),
    };
};
const colorTransform = {
    run(prop) {
        if (prop.type === ComponentType.Text || prop.type === ComponentType.TextButton) {
            return Object.assign(Object.assign(Object.assign({}, prop), outViewStyle$1(prop.viewStyle)), outTextStyle$1(prop.textStyle));
        }
        if (prop.type === ComponentType.ImageButton || prop.type === ComponentType.Image) {
            return Object.assign(Object.assign(Object.assign({}, prop), outViewStyle$1(prop.viewStyle)), outImageStyle(prop.imageStyle));
        }
        return Object.assign(Object.assign({}, prop), outViewStyle$1(prop.viewStyle));
    },
};
const isNumber = (val) => {
    if (typeof val === 'string') {
        return !Number.isNaN(Number(val));
    }
    return typeof val === 'number' && !Number.isNaN(val);
};
const outSingle = (key, obj) => {
    if (obj[key] === undefined || obj[key] === null)
        return {};
    return isNumber(obj[key]) ? { [key]: Number(obj[key]) } : {};
};
const outSpacing = (key, spacing) => {
    if (!spacing)
        return {};
    return {
        [key]: {
            left: isNumber(spacing.left) ? Number(spacing.left) : spacing.left,
            right: isNumber(spacing.right) ? Number(spacing.right) : spacing.right,
            top: isNumber(spacing.top) ? Number(spacing.top) : spacing.top,
            bottom: isNumber(spacing.bottom) ? Number(spacing.bottom) : spacing.bottom,
        },
    };
};
const outSize = (key, size) => {
    if (!size)
        return {};
    return {
        [key]: {
            type: size.type,
            value: isNumber(size.value) ? Number(size.value) : size.value,
        },
    };
};
const outMetadata = (metaData) => {
    if (!metaData)
        return {};
    return {
        metaData: {
            pixelWidth: isNumber(metaData.pixelWidth) ? Number(metaData.pixelWidth) : metaData.pixelWidth,
            pixelHeight: isNumber(metaData.pixelHeight) ? Number(metaData.pixelHeight) : metaData.pixelHeight,
        },
    };
};
const outViewStyle = (viewStyle) => {
    if (!viewStyle)
        return {};
    return {
        viewStyle: Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, viewStyle), outSingle('borderWidth', viewStyle)), outSingle('radius', viewStyle)), outSpacing('margin', viewStyle.margin)), outSpacing('padding', viewStyle.padding)),
    };
};
const outTextStyle = (textStyle) => {
    if (!textStyle)
        return {};
    return {
        textStyle: Object.assign(Object.assign(Object.assign({}, textStyle), outSingle('size', textStyle)), outSingle('weight', textStyle)),
    };
};
const outCarouselStyle = (carouselstyle) => {
    if (!carouselstyle)
        return {};
    return {
        carouselStyle: Object.assign(Object.assign(Object.assign({}, carouselstyle), outSingle('spacing', carouselstyle)), outSingle('maxChildWidth', carouselstyle)),
    };
};
const outCascadeStyle = (cascadeStyle) => {
    if (!cascadeStyle)
        return {};
    return {
        cascadeStyle: Object.assign(Object.assign({}, cascadeStyle), outSingle('spacing', cascadeStyle)),
    };
};
const outViewProps = (view) => {
    return Object.assign(Object.assign(Object.assign({}, outSize('width', view.width)), outSize('height', view.height)), outViewStyle(view.viewStyle));
};
const outTextProps = (text) => {
    return Object.assign(Object.assign(Object.assign({}, outViewProps(text)), outTextStyle(text.textStyle)), outSingle('maxTextLines', text));
};
const outImageProps = (image) => {
    return Object.assign(Object.assign({}, outViewProps(image)), outMetadata(image.metaData));
};
const outCarouselProps = (carousel) => {
    return Object.assign(Object.assign(Object.assign({}, outViewProps(carousel)), outCarouselStyle(carousel.carouselStyle)), { 
        // Convert only top-level items to find has fill width values.
        items: carousel.items.map((item) => (Object.assign(Object.assign({}, item), { body: Object.assign(Object.assign({}, item.body), { items: item.body.items.map((it) => numberTransform.run(it)) }) }))) });
};
const outCascadeProps = (cascade) => {
    return Object.assign(Object.assign(Object.assign({}, outViewProps(cascade)), outCascadeStyle(cascade.cascadeStyle)), { 
        // Convert only top-level items to find has fill width values.
        items: cascade.items.map((item) => (Object.assign(Object.assign({}, item), { body: Object.assign(Object.assign({}, item.body), { items: item.body.items.map((it) => numberTransform.run(it)) }) }))) });
};
const numberTransform = {
    run(prop) {
        if (prop.type === ComponentType.Text || prop.type === ComponentType.TextButton) {
            return Object.assign(Object.assign({}, prop), outTextProps(prop));
        }
        if (prop.type === ComponentType.ImageButton || prop.type === ComponentType.Image) {
            return Object.assign(Object.assign({}, prop), outImageProps(prop));
        }
        if (prop.type === ComponentType.Carousel) {
            return Object.assign(Object.assign({}, prop), outCarouselProps(prop));
        }
        if (prop.type === ComponentType.Cascade) {
            return Object.assign(Object.assign({}, prop), outCascadeProps(prop));
        }
        return Object.assign(Object.assign({}, prop), outViewProps(prop));
    },
};
// -------- Set property mapper
const MAPPER = () => undefined;
const createParser = (params) => {
    var _a;
    const defaultMapper = (params === null || params === void 0 ? void 0 : params.defaultMapper) || MAPPER;
    const mapper = {
        defaultMapper,
        mapBoxProps: (params === null || params === void 0 ? void 0 : params.mapBoxProps) || defaultMapper,
        mapTextProps: (params === null || params === void 0 ? void 0 : params.mapTextProps) || defaultMapper,
        mapImageProps: (params === null || params === void 0 ? void 0 : params.mapImageProps) || defaultMapper,
        mapTextButtonProps: (params === null || params === void 0 ? void 0 : params.mapTextButtonProps) || defaultMapper,
        mapImageButtonProps: (params === null || params === void 0 ? void 0 : params.mapImageButtonProps) || defaultMapper,
        mapCarouselProps: (params === null || params === void 0 ? void 0 : params.mapCarouselProps) || defaultMapper,
        mapCascadeProps: (params === null || params === void 0 ? void 0 : params.mapCascadeProps) || defaultMapper,
    };
    const transforms = [colorTransform, numberTransform, ...((_a = params === null || params === void 0 ? void 0 : params.transforms) !== null && _a !== void 0 ? _a : [])];
    return {
        setTransforms(newTransforms) {
            transforms.length = 0;
            transforms.push(...newTransforms);
        },
        addTransforms(newTransforms) {
            transforms.push(...newTransforms);
        },
        parse(rawItem, options) {
            const item = transforms.reduce((it, transform) => transform.run(it), rawItem);
            switch (item.type) {
                case ComponentType.Box: {
                    return { transformed: item, properties: mapper.mapBoxProps(item, options) };
                }
                case ComponentType.Text: {
                    return { transformed: item, properties: mapper.mapTextProps(item, options) };
                }
                case ComponentType.Image: {
                    return { transformed: item, properties: mapper.mapImageProps(item, options) };
                }
                case ComponentType.TextButton: {
                    return { transformed: item, properties: mapper.mapTextButtonProps(item, options) };
                }
                case ComponentType.ImageButton: {
                    return { transformed: item, properties: mapper.mapImageButtonProps(item, options) };
                }
                case ComponentType.Carousel: {
                    return { transformed: item, properties: mapper.mapCarouselProps(item, options) };
                }
                case ComponentType.Cascade: {
                    return { transformed: item, properties: mapper.mapCascadeProps(item, options) };
                }
                default:
                    return { transformed: item, properties: undefined };
            }
        },
    };
};
const FRAGMENT = ({ children }) => React__default.createElement(React__default.Fragment, null, children);
function createRenderer(params) {
    var _a, _b, _c, _d, _e, _f, _g;
    return {
        box: ((_a = params === null || params === void 0 ? void 0 : params.views) === null || _a === void 0 ? void 0 : _a.box) || FRAGMENT,
        text: ((_b = params === null || params === void 0 ? void 0 : params.views) === null || _b === void 0 ? void 0 : _b.text) || FRAGMENT,
        image: ((_c = params === null || params === void 0 ? void 0 : params.views) === null || _c === void 0 ? void 0 : _c.image) || FRAGMENT,
        imageButton: ((_d = params === null || params === void 0 ? void 0 : params.views) === null || _d === void 0 ? void 0 : _d.imageButton) || FRAGMENT,
        textButton: ((_e = params === null || params === void 0 ? void 0 : params.views) === null || _e === void 0 ? void 0 : _e.textButton) || FRAGMENT,
        carouselView: ((_f = params === null || params === void 0 ? void 0 : params.views) === null || _f === void 0 ? void 0 : _f.carouselView) || FRAGMENT,
        cascadeView: ((_g = params === null || params === void 0 ? void 0 : params.views) === null || _g === void 0 ? void 0 : _g.cascadeView) || FRAGMENT,
    };
}
var __rest$5 = (undefined && undefined.__rest) || function (s, e) {
    var t = {};
    for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
        t[p] = s[p];
    if (s != null && typeof Object.getOwnPropertySymbols === "function")
        for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
            if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
                t[p[i]] = s[p[i]];
        }
    return t;
};
const SizeContext = createContext({
    sizes: {},
    updateSize: () => { },
});
const SizeContextProvider = ({ children }) => {
    const [sizes, setSizes] = useState({});
    const updateSize = useCallback((_a) => {
        var { id } = _a, rest = __rest$5(_a, ["id"]);
        if (id) {
            setSizes((prevSizes) => (Object.assign(Object.assign({}, prevSizes), { [id]: rest })));
        }
    }, []);
    return React__default.createElement(SizeContext.Provider, { value: { sizes, updateSize } }, children);
};
const useSizeContext = () => useContext(SizeContext);
var Layout;
(function (Layout) {
    Layout["Row"] = "row";
    Layout["Column"] = "column";
})(Layout || (Layout = {}));
var AlignValue;
(function (AlignValue) {
    AlignValue["Center"] = "center";
    AlignValue["Left"] = "left";
    AlignValue["Right"] = "right";
    AlignValue["Top"] = "top";
    AlignValue["Bottom"] = "bottom";
})(AlignValue || (AlignValue = {}));
/**
 * @description
 * Caution: Numbers are passed as string types in the message template builder.
 * Use `==` comparison instead of `===` comparison when using a regular enum instead of a string enum.
 */
var FlexSizeSpecValue;
(function (FlexSizeSpecValue) {
    FlexSizeSpecValue[FlexSizeSpecValue["FillParent"] = 0] = "FillParent";
    FlexSizeSpecValue[FlexSizeSpecValue["WrapContent"] = 1] = "WrapContent";
})(FlexSizeSpecValue || (FlexSizeSpecValue = {}));
var FontWeight;
(function (FontWeight) {
    FontWeight["Normal"] = "normal";
    FontWeight["Bold"] = "bold";
})(FontWeight || (FontWeight = {}));
var MediaContentMode;
(function (MediaContentMode) {
    MediaContentMode["AspectFit"] = "aspectFit";
    MediaContentMode["AspectFill"] = "aspectFill";
    MediaContentMode["ScalesToFill"] = "scalesToFill";
})(MediaContentMode || (MediaContentMode = {}));
const SUPPORTED_TEMPLATE_VERSIONS = [
    1,
    2, // Composite templates: Carousel
];
const alignInFlex = (align) => {
    switch (align) {
        case AlignValue.Right:
        case AlignValue.Bottom:
            return 'flex-end';
        case AlignValue.Center:
            return 'center';
        case AlignValue.Left:
        case AlignValue.Top:
        default:
            return 'flex-start';
    }
};
const isTemplateVersionSupported = (templateVersion) => {
    if (!templateVersion)
        return true;
    return SUPPORTED_TEMPLATE_VERSIONS.includes(Number(templateVersion));
};
const memoize = (fn) => {
    const cache = new Map();
    const cached = function (val) {
        return cache.has(val) ? cache.get(val) : cache.set(val, fn.call(this, val)) && cache.get(val);
    };
    cached.cache = cache;
    return cached;
};
/**
 * Generate each item's id by each item's array depth
 */
const setTemplateItemId = memoize((data) => {
    const addIdRecursively = (item, id) => {
        if ('items' in item && (item === null || item === void 0 ? void 0 : item.items) != null) {
            item.items.forEach((subItem, subIdx) => {
                const subId = `${id}-${subIdx}`;
                subItem.id = subId;
                addIdRecursively(subItem, subId);
            });
        }
    };
    data.forEach((item, idx) => {
        const id = `${idx}`;
        item.id = id;
        addIdRecursively(item, id);
    });
    return data;
});
const defaultProperties = {
    rootLayout: Layout.Column,
    view: {
        size: {
            width: { type: 'flex', value: FlexSizeSpecValue.FillParent },
            height: { type: 'flex', value: FlexSizeSpecValue.WrapContent },
        },
    },
    box: {
        layout: Layout.Row,
        align: { vertical: AlignValue.Top, horizontal: AlignValue.Left },
    },
    textButton: {
        maxTextLines: 1,
    },
    carousel: {
        style: {
            spacing: 10,
            maxChildWidth: 240,
        },
    },
    cascade: {
        layout: Layout.Column,
        style: {
            spacing: 10,
        },
    },
};
const createMessageTemplate = (opts) => {
    const Container = opts.Container || React__default.Fragment;
    const UnknownMessage = opts.UnknownMessage || (() => null);
    const parser = opts.parser || createParser();
    const renderer = opts.renderer || createRenderer();
    const MessageTemplateBase = ({ templateItems, templateVersion, parentLayout = defaultProperties.box.layout, depth = 0, }) => {
        if (!isTemplateVersionSupported(templateVersion)) {
            throw new Error(`Cannot parse template item due to unsupported template version: ${templateVersion}, ${SUPPORTED_TEMPLATE_VERSIONS}`);
        }
        return (React__default.createElement(React__default.Fragment, null, templateItems.map((rawProperties, index, siblings) => {
            const result = parser.parse(rawProperties, { parentLayout, depth, elemIdx: index, siblings });
            const item = result.transformed;
            const rendererProps = {
                key: index,
                siblings,
                parentLayout,
                parsedProperties: result.properties,
                rawProperties,
            };
            switch (item.type) {
                case ComponentType.Carousel: {
                    if (!Array.isArray(item.items)) {
                        throw new Error('Cannot parse template item as Carousel if carousel has no items.');
                    }
                    return (React__default.createElement(renderer.carouselView, Object.assign({}, item, rendererProps), item.items.map((template, index) => (React__default.createElement(MessageTemplateBase, { key: index, templateItems: template.body.items || [], depth: depth + 1, templateVersion: template.version })))));
                }
                case ComponentType.Cascade: {
                    if (!Array.isArray(item.items)) {
                        throw new Error('Cannot parse template item as Cascade if cascade has no items.');
                    }
                    return (React__default.createElement(renderer.cascadeView, Object.assign({}, item, rendererProps), item.items.map((template, index) => (React__default.createElement(MessageTemplateBase, { key: index, templateItems: template.body.items || [], depth: depth + 1, templateVersion: template.version })))));
                }
                case ComponentType.Box: {
                    return (React__default.createElement(renderer.box, Object.assign({}, item, rendererProps),
                        React__default.createElement(MessageTemplateBase, { templateItems: item.items || [], parentLayout: item.layout, depth: depth + 1, templateVersion: templateVersion })));
                }
                case ComponentType.Text: {
                    return React__default.createElement(renderer.text, Object.assign({}, item, rendererProps));
                }
                case ComponentType.Image: {
                    return React__default.createElement(renderer.image, Object.assign({}, item, rendererProps));
                }
                case ComponentType.TextButton: {
                    return React__default.createElement(renderer.textButton, Object.assign({}, item, rendererProps));
                }
                case ComponentType.ImageButton: {
                    return React__default.createElement(renderer.imageButton, Object.assign({}, item, rendererProps));
                }
                default: {
                    // or throw new Error('Cannot parse template item')
                    return React__default.createElement(UnknownMessage, { item: item });
                }
            }
        })));
    };
    return {
        MessageTemplate: ({ templateVersion, templateItems, parentLayout = defaultProperties.rootLayout, }) => {
            const items = setTemplateItemId(templateItems);
            return (React__default.createElement(SizeContextProvider, null,
                React__default.createElement(Container, { className: 'sb-message-template__parent' },
                    React__default.createElement(MessageTemplateBase, { isRoot: true, parentLayout: parentLayout, templateItems: items, templateVersion: templateVersion }))));
        },
        MessageTemplateBase,
    };
};
var ActionType;
(function (ActionType) {
    ActionType["Web"] = "web";
    ActionType["Custom"] = "custom";
    ActionType["UIKit"] = "uikit";
    ActionType["Internal"] = "internal";
})(ActionType || (ActionType = {}));
({
    version: 1,
    body: {
        items: [
            {
                type: ComponentType.Image,
                action: { type: ActionType.Web, data: 'https://docs.sendbird.com' },
                height: { type: 'fixed', value: 236 },
                viewStyle: {
                    padding: {
                        left: 4,
                        right: 4,
                        top: 4,
                        bottom: 4,
                    },
                },
                imageUrl: 'https://cdn.pixabay.com/photo/2022/10/12/10/45/bird-7516219_1280.jpg',
                imageStyle: { contentMode: MediaContentMode.AspectFill },
            },
            {
                type: ComponentType.Box,
                layout: Layout.Column,
                width: { type: 'flex', value: FlexSizeSpecValue.FillParent },
                height: { type: 'fixed', value: 200 },
                items: [
                    {
                        type: ComponentType.Box,
                        width: { type: 'flex', value: FlexSizeSpecValue.FillParent },
                        height: { type: 'flex', value: FlexSizeSpecValue.FillParent },
                        viewStyle: { backgroundColor: '#fa6464' },
                    },
                    {
                        type: ComponentType.Box,
                        layout: Layout.Column,
                        width: { type: 'flex', value: FlexSizeSpecValue.FillParent },
                        height: { type: 'flex', value: FlexSizeSpecValue.WrapContent },
                        viewStyle: { backgroundColor: '#ffaf5c' },
                        items: [
                            {
                                type: ComponentType.Text,
                                text: 'Message',
                                align: { horizontal: AlignValue.Center, vertical: AlignValue.Center },
                                width: { type: 'flex', value: FlexSizeSpecValue.FillParent },
                                height: { type: 'fixed', value: 50 },
                            },
                            {
                                type: ComponentType.Image,
                                action: { type: ActionType.Web, data: 'https://docs.sendbird.com' },
                                width: { type: 'flex', value: FlexSizeSpecValue.FillParent },
                                height: { type: 'fixed', value: 50 },
                                imageUrl: 'https://cdn.pixabay.com/photo/2022/10/12/10/45/bird-7516219_1280.jpg',
                                imageStyle: { contentMode: MediaContentMode.AspectFill },
                            },
                        ],
                    },
                    {
                        type: ComponentType.Box,
                        width: { type: 'flex', value: FlexSizeSpecValue.FillParent },
                        height: { type: 'fixed', value: 20 },
                        viewStyle: { backgroundColor: '#ffe450' },
                    },
                    {
                        type: ComponentType.Box,
                        width: { type: 'flex', value: FlexSizeSpecValue.FillParent },
                        height: { type: 'flex', value: FlexSizeSpecValue.FillParent },
                        viewStyle: { backgroundColor: '#329a1b' },
                    },
                ],
            },
            {
                type: ComponentType.Box,
                viewStyle: { padding: { top: 12, bottom: 12, left: 12, right: 12 } },
                layout: Layout.Column,
                items: [
                    {
                        type: ComponentType.Box,
                        align: { horizontal: AlignValue.Left, vertical: AlignValue.Center },
                        layout: Layout.Row,
                        viewStyle: {
                            borderWidth: 1,
                            borderColor: '#72723f',
                        },
                        width: { type: 'flex', value: FlexSizeSpecValue.FillParent },
                        height: { type: 'fixed', value: 150 },
                        items: [
                            {
                                type: ComponentType.Text,
                                width: { type: 'flex', value: FlexSizeSpecValue.FillParent },
                                height: { type: 'fixed', value: 50 },
                                text: 'Sample1 text',
                                maxTextLines: 1,
                                align: { vertical: AlignValue.Center, horizontal: AlignValue.Left },
                                viewStyle: {
                                    backgroundColor: '#cc4400',
                                },
                                textStyle: {
                                    size: 16,
                                    color: '#f8f8f8',
                                    weight: FontWeight.Bold,
                                },
                            },
                            {
                                type: ComponentType.ImageButton,
                                action: { type: ActionType.UIKit, data: 'uikit://delete' },
                                width: { type: 'fixed', value: 20 },
                                height: { type: 'fixed', value: 20 },
                                imageUrl: 'https://file-ap-1.sendbird.com/5b5379aa73fd460da22ffaf9a61d0d7f.png',
                                imageStyle: { contentMode: MediaContentMode.AspectFit },
                            },
                        ],
                    },
                    {
                        type: ComponentType.Text,
                        viewStyle: { padding: { top: 6, bottom: 12, left: 0, right: 0 } },
                        text: 'Esse eu esse duis ipsum et dolor eu ut sit amet consectetur cillum velit officia. Ex adipisicing elit quis ea sit. Occaecat in eu aliqua nulla magna id ut excepteur minim.',
                        maxTextLines: 2,
                        textStyle: { size: 14, color: '#e10000' },
                        width: { type: 'fixed', value: 200 },
                        height: { type: 'fixed', value: 50 },
                    },
                    {
                        type: ComponentType.TextButton,
                        action: { type: ActionType.Web, data: 'https://www.daum.net' },
                        text: 'Button 3',
                        textStyle: { size: 14, color: '#742ddd', weight: FontWeight.Bold },
                    },
                ],
            },
        ],
    },
});
({
    'version': 1,
    'body': {
        'items': [
            {
                'type': ComponentType.Image,
                'action': { 'type': ActionType.Web, 'data': 'https://www.naver.com/' },
                'height': { 'type': 'fixed', 'value': 136 },
                'imageUrl': 'https://cdn.pixabay.com/photo/2022/10/12/10/45/bird-7516219_1280.jpg',
                'imageStyle': { 'contentMode': MediaContentMode.AspectFill },
            },
            {
                'type': ComponentType.Box,
                'viewStyle': { 'padding': { 'top': 12, 'bottom': 12, 'left': 12, 'right': 12 }, backgroundColor: '#cccccc' },
                'layout': Layout.Column,
                width: { type: 'flex', value: FlexSizeSpecValue.FillParent },
                'items': [
                    {
                        'type': ComponentType.Box,
                        width: { type: 'flex', value: FlexSizeSpecValue.FillParent },
                        'layout': Layout.Row,
                        'items': [
                            {
                                'type': ComponentType.TextButton,
                                'action': { 'type': ActionType.Web, 'data': 'https://www.daum.net' },
                                width: { type: 'fixed', value: 150 },
                                'viewStyle': { 'margin': { 'top': 0, 'bottom': 0, 'left': 0, 'right': 4 } },
                                'text': 'Button 2',
                                'textStyle': { 'size': 14, 'weight': FontWeight.Bold },
                            },
                            {
                                'type': ComponentType.TextButton,
                                'action': { 'type': ActionType.Web, 'data': 'https://www.daum.net' },
                                width: { type: 'flex', value: FlexSizeSpecValue.FillParent },
                                'viewStyle': { 'margin': { 'top': 0, 'bottom': 0, 'left': 4, 'right': 0 } },
                                'text': 'Button 3',
                                'textStyle': { 'size': 14, 'weight': FontWeight.Bold },
                            },
                        ],
                    },
                    {
                        'type': ComponentType.Box,
                        width: { type: 'flex', value: FlexSizeSpecValue.FillParent },
                        'layout': Layout.Row,
                        'items': [
                            {
                                'type': ComponentType.Text,
                                'text': 'Sample2 text',
                                'width': { 'type': 'flex', 'value': FlexSizeSpecValue.FillParent },
                                'maxTextLines': 1,
                                'textStyle': { 'size': 16, 'weight': FontWeight.Bold },
                            },
                            {
                                'type': ComponentType.ImageButton,
                                'action': { 'type': ActionType.UIKit, 'data': 'uikit://delete' },
                                'width': { 'type': 'fixed', 'value': 20 },
                                'height': { 'type': 'fixed', 'value': 20 },
                                'imageUrl': 'https://file-ap-1.sendbird.com/5b5379aa73fd460da22ffaf9a61d0d7f.png',
                                'imageStyle': { 'contentMode': MediaContentMode.AspectFit },
                            },
                        ],
                    },
                    {
                        'type': ComponentType.Text,
                        'viewStyle': { 'padding': { 'top': 6, 'bottom': 12, 'left': 0, 'right': 0 } },
                        'text': 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aui',
                        'textStyle': { 'size': 14 },
                    },
                ],
            },
        ],
    },
});
({
    'version': 1,
    'body': {
        'items': [
            {
                'type': ComponentType.Box,
                'viewStyle': { 'backgroundColor': '#ffffff', 'borderWidth': 1, 'borderColor': '#eeeeee', 'radius': 16 },
                'layout': Layout.Column,
                'items': [
                    {
                        'type': ComponentType.Image,
                        'height': { 'type': 'fixed', 'value': 200 },
                        'imageUrl': 'https://img.freepik.com/free-vector/cartoon-happy-hours-background_52683-81243.jpg?w=2000&t=st=1666689198~exp=1666689798~hmac=23109d44ba03deee7aee069cbeebfcb48fa27f85e53c1cafc5d5d7345f1a2041',
                        'imageStyle': { 'contentMode': MediaContentMode.AspectFill },
                    },
                    {
                        'type': ComponentType.Box,
                        'viewStyle': { 'padding': { 'top': 15, 'bottom': 15, 'left': 15, 'right': 15 } },
                        'layout': Layout.Column,
                        'items': [
                            {
                                'type': ComponentType.Text,
                                'text': "Don't miss these deals today",
                                'maxTextLines': 1,
                                'textStyle': { 'size': 20, 'color': '#e10000', 'weight': FontWeight.Bold },
                            },
                            {
                                'type': ComponentType.Text,
                                'viewStyle': { 'margin': { 'top': 5, 'bottom': 0, 'left': 0, 'right': 0 } },
                                'text': 'Pay with Maya and get cashback!',
                                'maxTextLines': 1,
                                'textStyle': { 'size': 14, 'color': '#e10000' },
                            },
                            {
                                'type': ComponentType.Box,
                                'align': { 'horizontal': AlignValue.Left, 'vertical': AlignValue.Center },
                                'viewStyle': { 'margin': { 'top': 10, 'bottom': 0, 'left': 0, 'right': 0 } },
                                'layout': Layout.Row,
                                'items': [
                                    {
                                        'type': ComponentType.Image,
                                        'width': { 'type': 'fixed', 'value': 50 },
                                        'height': { 'type': 'fixed', 'value': 50 },
                                        'viewStyle': {
                                            'backgroundColor': '#ffffff',
                                            'borderWidth': 1,
                                            'borderColor': '#eeeeee',
                                            'radius': 25,
                                        },
                                        'imageUrl': 'https://yt3.ggpht.com/ytc/AMLnZu8Kg89ymE7qt5bsS9vMqi9h2aHiN6m9ID-IgxR6-Q=s900-c-k-c0x00ffffff-no-rj',
                                        'imageStyle': { 'contentMode': MediaContentMode.AspectFill },
                                    },
                                    {
                                        'type': ComponentType.Box,
                                        'align': { 'horizontal': AlignValue.Left, 'vertical': AlignValue.Center },
                                        'viewStyle': { 'margin': { 'top': 0, 'bottom': 0, 'left': 15, 'right': 0 } },
                                        'layout': Layout.Column,
                                        'items': [
                                            {
                                                'type': ComponentType.Text,
                                                'text': 'Meralco',
                                                'maxTextLines': 1,
                                                'textStyle': { 'size': 16, 'color': '#e10000', 'weight': FontWeight.Bold },
                                            },
                                            {
                                                'type': ComponentType.Text,
                                                'viewStyle': { 'margin': { 'top': 3, 'bottom': 0, 'left': 0, 'right': 0 } },
                                                'text': '30% cashback, P300 min spend',
                                                'maxTextLines': 1,
                                                'textStyle': { 'size': 12, 'color': '#610000', 'weight': FontWeight.Bold },
                                            },
                                        ],
                                    },
                                ],
                            },
                            {
                                'type': ComponentType.Box,
                                'align': { 'horizontal': AlignValue.Left, 'vertical': AlignValue.Center },
                                'viewStyle': { 'margin': { 'top': 10, 'bottom': 0, 'left': 0, 'right': 0 } },
                                'layout': Layout.Row,
                                'items': [
                                    {
                                        'type': ComponentType.Image,
                                        'width': { 'type': 'fixed', 'value': 50 },
                                        'height': { 'type': 'fixed', 'value': 50 },
                                        'viewStyle': {
                                            'backgroundColor': '#ffffff',
                                            'borderWidth': 1,
                                            'borderColor': '#eeeeee',
                                            'radius': 25,
                                        },
                                        'imageUrl': 'https://1000logos.net/wp-content/uploads/2021/12/Globe-Telecom-logo.png',
                                        'imageStyle': { 'contentMode': MediaContentMode.AspectFill, tintColor: '#a49a9a' },
                                    },
                                    {
                                        'type': ComponentType.Box,
                                        'align': { 'horizontal': AlignValue.Left, 'vertical': AlignValue.Center },
                                        'viewStyle': { 'margin': { 'top': 0, 'bottom': 0, 'left': 15, 'right': 0 } },
                                        'layout': Layout.Column,
                                        'items': [
                                            {
                                                'type': ComponentType.Text,
                                                'text': 'Globe',
                                                'maxTextLines': 1,
                                                'textStyle': { 'size': 16, 'color': '#e10000', 'weight': FontWeight.Bold },
                                            },
                                            {
                                                'type': ComponentType.Text,
                                                'viewStyle': { 'margin': { 'top': 3, 'bottom': 0, 'left': 0, 'right': 0 } },
                                                'text': '30% cashback, P300 min spend',
                                                'maxTextLines': 1,
                                                'textStyle': { 'size': 12, 'color': '#610000', 'weight': FontWeight.Bold },
                                            },
                                        ],
                                    },
                                ],
                            },
                            {
                                'type': ComponentType.Box,
                                'align': { 'horizontal': AlignValue.Left, 'vertical': AlignValue.Center },
                                'viewStyle': { 'margin': { 'top': 10, 'bottom': 0, 'left': 0, 'right': 0 } },
                                'layout': Layout.Row,
                                'items': [
                                    {
                                        'type': ComponentType.Image,
                                        'width': { 'type': 'fixed', 'value': 50 },
                                        'height': { 'type': 'fixed', 'value': 50 },
                                        'viewStyle': {
                                            'backgroundColor': '#ffffff',
                                            'borderWidth': 1,
                                            'borderColor': '#eeeeee',
                                            'radius': 25,
                                        },
                                        'imageUrl': 'https://upload.wikimedia.org/wikipedia/commons/thumb/4/41/Cignal.svg/640px-Cignal.svg.png',
                                        'imageStyle': { 'contentMode': MediaContentMode.AspectFill },
                                    },
                                    {
                                        'type': ComponentType.Box,
                                        'align': { 'horizontal': AlignValue.Left, 'vertical': AlignValue.Center },
                                        'viewStyle': { 'margin': { 'top': 0, 'bottom': 0, 'left': 15, 'right': 0 } },
                                        'layout': Layout.Column,
                                        'items': [
                                            {
                                                'type': ComponentType.Text,
                                                'text': 'Cignal',
                                                'maxTextLines': 1,
                                                'textStyle': { 'size': 16, 'color': '#e10000', 'weight': FontWeight.Bold },
                                            },
                                            {
                                                'type': ComponentType.Text,
                                                'viewStyle': { 'margin': { 'top': 3, 'bottom': 0, 'left': 0, 'right': 0 } },
                                                'text': '30% cashback, P300 min spend',
                                                'maxTextLines': 1,
                                                'textStyle': { 'size': 12, 'color': '#610000', 'weight': FontWeight.Bold },
                                            },
                                        ],
                                    },
                                ],
                            },
                            {
                                'type': ComponentType.Box,
                                'align': { 'horizontal': AlignValue.Left, 'vertical': AlignValue.Center },
                                'viewStyle': { 'margin': { 'top': 10, 'bottom': 0, 'left': 0, 'right': 0 } },
                                'layout': Layout.Row,
                                'items': [
                                    {
                                        'type': ComponentType.TextButton,
                                        'action': { 'type': ActionType.Web, 'data': 'https://www.daum.net' },
                                        'viewStyle': {
                                            'backgroundColor': '#e0e0e0',
                                            'radius': 16,
                                            'margin': { 'top': 0, 'bottom': 0, 'left': 0, 'right': 4 },
                                            'padding': { 'top': 12, 'bottom': 12, 'left': 12, 'right': 12 },
                                        },
                                        'text': 'Learn more',
                                        'textStyle': { 'size': 15, 'color': '#e10000', 'weight': FontWeight.Bold },
                                    },
                                    {
                                        'type': ComponentType.TextButton,
                                        'action': { 'type': ActionType.Web, 'data': 'https://www.daum.net' },
                                        'viewStyle': {
                                            'backgroundColor': '#e10000',
                                            'radius': 16,
                                            'margin': { 'top': 0, 'bottom': 0, 'left': 4, 'right': 0 },
                                            'padding': { 'top': 12, 'bottom': 12, 'left': 12, 'right': 12 },
                                        },
                                        'text': 'Pay now',
                                        'textStyle': { 'size': 15, 'color': '#ffffff', 'weight': FontWeight.Bold },
                                    },
                                ],
                            },
                        ],
                    },
                ],
            },
        ],
    },
});
({
    'version': 1,
    'body': {
        'items': [
            {
                'type': ComponentType.Box,
                'layout': Layout.Column,
                'items': [
                    {
                        'type': ComponentType.Image,
                        'imageUrl': 'https://static.sendbird.com/sample/profiles/profile_40_512px.png',
                        'metaData': {
                            'pixelWidth': 512,
                            'pixelHeight': 512,
                        },
                        'imageStyle': {
                            'tintColor': '#44ff1188',
                        },
                        viewStyle: {
                            'padding': {
                                'top': 12,
                                'right': 12,
                                'bottom': 12,
                                'left': 12,
                            },
                        },
                    },
                    {
                        'type': ComponentType.Box,
                        'viewStyle': {
                            'padding': {
                                'top': 12,
                                'right': 12,
                                'bottom': 12,
                                'left': 12,
                            },
                        },
                        'layout': Layout.Column,
                        'items': [
                            {
                                'type': ComponentType.Box,
                                'layout': Layout.Row,
                                'items': [
                                    {
                                        'type': ComponentType.Box,
                                        'layout': Layout.Column,
                                        'items': [
                                            {
                                                'type': ComponentType.Text,
                                                'text': 'hi',
                                                'maxTextLines': 3,
                                                'viewStyle': {
                                                    'padding': {
                                                        'top': 0,
                                                        'bottom': 6,
                                                        'left': 0,
                                                        'right': 0,
                                                    },
                                                },
                                                'textStyle': {
                                                    'size': 16,
                                                    'weight': FontWeight.Bold,
                                                },
                                            },
                                            {
                                                'type': ComponentType.Text,
                                                'text': 'bye',
                                                'maxTextLines': 10,
                                                'textStyle': {
                                                    'size': 14,
                                                },
                                            },
                                        ],
                                    },
                                    {
                                        'type': ComponentType.ImageButton,
                                        'action': {
                                            'type': ActionType.UIKit,
                                            'data': 'sendbirduikit://delete',
                                        },
                                        'width': {
                                            'type': 'fixed',
                                            'value': 20,
                                        },
                                        'height': {
                                            'type': 'fixed',
                                            'value': 20,
                                        },
                                        'metaData': {
                                            'pixelWidth': 60,
                                            'pixelHeight': 60,
                                        },
                                        'imageUrl': 'https://dxstmhyqfqr1o.cloudfront.net/sendbird-message-builder/icon-more.png',
                                        'imageStyle': {
                                            'tintColor': '#ff8d5a',
                                        },
                                    },
                                ],
                            },
                            {
                                'type': ComponentType.Box,
                                'layout': Layout.Column,
                                'items': [
                                    {
                                        'type': ComponentType.Box,
                                        'viewStyle': {
                                            'margin': {
                                                'top': 16,
                                                'bottom': 0,
                                                'left': 0,
                                                'right': 0,
                                            },
                                        },
                                        'align': {
                                            'horizontal': AlignValue.Left,
                                            'vertical': AlignValue.Center,
                                        },
                                        'layout': Layout.Row,
                                        'items': [
                                            {
                                                'type': ComponentType.Image,
                                                'imageUrl': 'https://ca.slack-edge.com/T0ADCTNEL-ULE240VNV-83fd5776e78e-512',
                                                'width': {
                                                    'type': 'fixed',
                                                    'value': 40,
                                                },