@sendbird/react-uikit-message-template-view
Advanced tools
Comparing version 0.0.2 to 0.0.3
@@ -6,2 +6,13 @@ # Change Log | ||
## [0.0.3](https://github.com/sendbird/sendbird-uikit-core-ts/compare/v0.0.2...v0.0.3) (2024-10-08) | ||
### Features | ||
* added highlight interface to MessageProvider ([9b9abd0](https://github.com/sendbird/sendbird-uikit-core-ts/commit/9b9abd0a4d39d72beda8a88f4f2b543b4bbd764d)) | ||
## [0.0.2](https://github.com/sendbird/sendbird-uikit-core-ts/compare/v0.0.1-alpha.79...v0.0.2) (2024-09-20) | ||
@@ -8,0 +19,0 @@ |
import React from 'react'; | ||
import type { BaseMessage } from '@sendbird/chat/message'; | ||
import type { Action } from '@sendbird/uikit-message-template'; | ||
import type { Action, ComponentsUnion } from '@sendbird/uikit-message-template'; | ||
export type MessageContextProps = React.PropsWithChildren<{ | ||
@@ -9,6 +9,15 @@ message: BaseMessage; | ||
handlePredefinedAction?(event: React.SyntheticEvent, action: Action, message: BaseMessage): null; | ||
/** | ||
* @internal DO NOT USE THIS, this is for internal use only. | ||
* This interface allows for detecting and injecting highlight styles into areas that include variables. | ||
*/ | ||
highlight?: { | ||
getContainerClassName?(raw: ComponentsUnion['properties']): string; | ||
getContainerInlineStyle?(raw: ComponentsUnion['properties']): React.CSSProperties; | ||
renderText?(text: string): React.ReactNode; | ||
}; | ||
}>; | ||
export type MessageContextInterface = Omit<MessageContextProps, 'children'>; | ||
declare const MessageProvider: (props: MessageContextProps) => React.JSX.Element; | ||
declare const MessageProvider: ({ message, handleWebAction, handleCustomAction, handlePredefinedAction, highlight, children, }: MessageContextProps) => React.JSX.Element; | ||
declare const useMessageContext: () => MessageContextInterface; | ||
export { MessageProvider, useMessageContext }; |
@@ -5,4 +5,3 @@ // create a context provider for MessageComponent | ||
const MessageContext = React.createContext(null); | ||
const MessageProvider = (props) => { | ||
const { message, handleWebAction, handleCustomAction, handlePredefinedAction, children } = props; | ||
const MessageProvider = ({ message, handleWebAction, handleCustomAction, handlePredefinedAction, highlight, children, }) => { | ||
const value = React.useMemo(() => ({ | ||
@@ -13,3 +12,4 @@ message, | ||
handlePredefinedAction, | ||
}), [message === null || message === void 0 ? void 0 : message.updatedAt]); | ||
highlight, | ||
}), [message === null || message === void 0 ? void 0 : message.updatedAt, highlight === null || highlight === void 0 ? void 0 : highlight.getContainerClassName, highlight === null || highlight === void 0 ? void 0 : highlight.getContainerInlineStyle, highlight === null || highlight === void 0 ? void 0 : highlight.renderText]); | ||
return React.createElement(MessageContext.Provider, { value: value }, children); | ||
@@ -16,0 +16,0 @@ }; |
@@ -49,2 +49,5 @@ import { ComponentType, FlexSizeSpecValue, Layout, MediaContentMode, alignInFlex, defaultProperties, } from '@sendbird/uikit-message-template'; | ||
else if (width.type === 'fixed' && width.value >= 0) { | ||
if (parentLayout === Layout.Row) { | ||
style['flexShrink'] = 0; | ||
} | ||
style['width'] = width.value; | ||
@@ -59,2 +62,5 @@ } | ||
else if (height.type === 'fixed' && height.value >= 0) { | ||
if (parentLayout === Layout.Column) { | ||
style['flexShrink'] = 0; | ||
} | ||
style['height'] = height.value; | ||
@@ -61,0 +67,0 @@ } |
@@ -10,3 +10,4 @@ import React from 'react'; | ||
elementId?: string; | ||
inlineStyle?: React.CSSProperties; | ||
}>; | ||
export declare const ActionHandler: ({ children, props, className, style }: ActionHandlerProps) => React.JSX.Element; | ||
export declare const ActionHandler: ({ children, props, className, style, inlineStyle }: ActionHandlerProps) => React.JSX.Element; |
@@ -16,20 +16,5 @@ var __rest = (this && this.__rest) || function (s, e) { | ||
import { useRecalculateWidth } from '../hook/useRecalculationSize'; | ||
const hasValidUrlProtocol = (url = '') => ['http://', 'https://', 'ftp://'].some((protocol) => url.startsWith(protocol)); | ||
/** | ||
* @param url - url to be checked | ||
* @returns url with http:// protocol if it doesn't have any protocol | ||
* @example | ||
* returnUrl('www.sendbird.com') // returns 'http://www.sendbird.com' | ||
* returnUrl('https://www.sendbird.com') // returns 'https://www.sendbird.com' | ||
* returnUrl('ftp://www.sendbird.com') // returns 'ftp://www.sendbird.com' | ||
* returnUrl('sendbird.com') // returns 'https://sendbird.com' | ||
**/ | ||
const returnUrl = (url = '') => { | ||
if (hasValidUrlProtocol(url)) { | ||
return url; | ||
} | ||
return `https://${url}`; | ||
}; | ||
import { clx, getValidURL } from '../util'; | ||
// todo: semantic html here is not perfect, need to revisit. Same for Button | ||
export const ActionHandler = ({ children, props, className, style }) => { | ||
export const ActionHandler = ({ children, props, className, style, inlineStyle }) => { | ||
var _a, _b, _c, _d, _e, _f, _g, _h, _j; | ||
@@ -52,3 +37,3 @@ const { recalculatedStyle, elemRef } = useRecalculateWidth({ style, props }); | ||
else { | ||
(_c = window === null || window === void 0 ? void 0 : window.open(returnUrl((_b = props === null || props === void 0 ? void 0 : props.action) === null || _b === void 0 ? void 0 : _b.data), '_blank', 'noopener noreferrer')) === null || _c === void 0 ? void 0 : _c.focus(); | ||
(_c = window === null || window === void 0 ? void 0 : window.open(getValidURL((_b = props === null || props === void 0 ? void 0 : props.action) === null || _b === void 0 ? void 0 : _b.data), '_blank', 'noopener noreferrer')) === null || _c === void 0 ? void 0 : _c.focus(); | ||
} | ||
@@ -61,3 +46,3 @@ } | ||
else { | ||
(_f = window === null || window === void 0 ? void 0 : window.open(returnUrl((_e = props === null || props === void 0 ? void 0 : props.action) === null || _e === void 0 ? void 0 : _e.data), '_blank', 'noopener noreferrer')) === null || _f === void 0 ? void 0 : _f.focus(); | ||
(_f = window === null || window === void 0 ? void 0 : window.open(getValidURL((_e = props === null || props === void 0 ? void 0 : props.action) === null || _e === void 0 ? void 0 : _e.data), '_blank', 'noopener noreferrer')) === null || _f === void 0 ? void 0 : _f.focus(); | ||
} | ||
@@ -70,6 +55,6 @@ } | ||
if (props.type === ComponentType.TextButton) { | ||
return (React.createElement("button", { className: clx(className, borderClass), "data-sb-template-id": props.elementId, style: Object.assign(Object.assign({}, style), paddingStyles), onClick: onClick }, children)); | ||
return (React.createElement("button", { className: clx(className, borderClass), "data-sb-template-id": props.elementId, style: Object.assign(Object.assign(Object.assign({}, style), paddingStyles), inlineStyle), onClick: onClick }, children)); | ||
} | ||
const { display, flexDirection, justifyContent, alignItems, objectFit } = recalculatedStyle, wrapperStyles = __rest(recalculatedStyle, ["display", "flexDirection", "justifyContent", "alignItems", "objectFit"]); | ||
return (React.createElement("div", { ref: elemRef, className: clx(className, borderClass, props.action && 'sb-message-template__action'), "data-sb-template-id": props.elementId, style: wrapperStyles, onClick: onClick }, | ||
return (React.createElement("div", { ref: elemRef, className: clx(className, borderClass, props.action && 'sb-message-template__action'), "data-sb-template-id": props.elementId, style: Object.assign(Object.assign({}, wrapperStyles), inlineStyle), onClick: onClick }, | ||
React.createElement("div", { style: Object.assign({ display, | ||
@@ -81,4 +66,1 @@ flexDirection, | ||
}; | ||
function clx(...names) { | ||
return names.filter((it) => !!it).join(' '); | ||
} |
import React from 'react'; | ||
import { type MessageTemplateProps } from '@sendbird/uikit-message-template'; | ||
import '../index.css'; | ||
import { ReactParsedProperties } from '../styles'; | ||
export declare const renderer: import("@sendbird/uikit-message-template").Renderer<ReactParsedProperties>; | ||
export declare const parser: import("@sendbird/uikit-message-template").Parser<ReactParsedProperties>; | ||
export declare const MessageTemplate: ({ templateVersion, templateItems, parentLayout, }: MessageTemplateProps) => React.JSX.Element; | ||
export { parser } from './parser'; | ||
export { renderer } from './renderer'; | ||
export declare const MessageTemplate: ({ templateVersion, templateItems, parentLayout, }: import("@sendbird/uikit-message-template").MessageTemplateProps) => React.JSX.Element; |
import React from 'react'; | ||
import { FlexSizeSpecValue, Layout, createMessageTemplate, createParser, createRenderer, defaultProperties, } from '@sendbird/uikit-message-template'; | ||
import { Carousel } from '../components/Carousel'; | ||
import ReactMessageTemplateImage from '../components/ReactMessageTemplateImage'; | ||
import { createMessageTemplate } from '@sendbird/uikit-message-template'; | ||
import '../index.css'; | ||
import { getDefaultStyles, setAlign, setImageAspectRatio, setImageStyle, setTextAlign, setTextStyle, setViewProps, webkitLineClampStyles, } from '../styles'; | ||
import { ActionHandler } from './ActionHandler'; | ||
/** | ||
* Text that is fixed or fill parent should be wrapped in a div with max-width: 100% and max-height: 100% | ||
* This is to prevent text from overflowing the padding of the container | ||
*/ | ||
function isFixedOrFill(view) { | ||
var _a, _b, _c, _d; | ||
const heightType = (_a = view === null || view === void 0 ? void 0 : view.height) === null || _a === void 0 ? void 0 : _a.type; | ||
const widthType = (_b = view === null || view === void 0 ? void 0 : view.width) === null || _b === void 0 ? void 0 : _b.type; | ||
const isFixedDiamension = heightType === 'fixed' || widthType === 'fixed'; | ||
const isFill = (heightType === 'flex' && ((_c = view === null || view === void 0 ? void 0 : view.height) === null || _c === void 0 ? void 0 : _c.value) === FlexSizeSpecValue.FillParent) || | ||
(widthType === 'flex' && ((_d = view === null || view === void 0 ? void 0 : view.width) === null || _d === void 0 ? void 0 : _d.value) === FlexSizeSpecValue.FillParent); | ||
return isFixedDiamension || isFill; | ||
} | ||
function convertNewlinesToBr(text) { | ||
return text.split('\n').map((line, index) => (React.createElement(React.Fragment, { key: index }, | ||
line, | ||
React.createElement("br", null)))); | ||
} | ||
function renderText(view) { | ||
const { text, maxTextLines } = view; | ||
const isToBeWrapped = isFixedOrFill(view); | ||
const hasMaxLines = typeof maxTextLines === 'number' && maxTextLines > 0; | ||
const convertedText = convertNewlinesToBr(text); | ||
if (hasMaxLines || isToBeWrapped) { | ||
const wrapperStyling = Object.assign(Object.assign({}, ((hasMaxLines || isToBeWrapped) && { maxWidth: '100%' })), (isToBeWrapped && { maxHeight: '100%', overflow: 'hidden' })); | ||
return (React.createElement("div", { style: wrapperStyling }, hasMaxLines ? React.createElement("div", { style: webkitLineClampStyles(maxTextLines) }, convertedText) : convertedText)); | ||
} | ||
return hasMaxLines ? React.createElement("div", { style: webkitLineClampStyles(maxTextLines) }, convertedText) : convertedText; | ||
} | ||
export const renderer = createRenderer({ | ||
views: { | ||
box(props) { | ||
return (React.createElement(ActionHandler, { className: "sb-message-template__box", elementId: props.elementId, style: props.parsedProperties, props: props }, props.children)); | ||
}, | ||
text(props) { | ||
return (React.createElement(ActionHandler, { className: "sb-message-template__text", elementId: props.elementId, style: props.parsedProperties, props: props }, renderText(props))); | ||
}, | ||
image(props) { | ||
var _a; | ||
// todo: add image backup | ||
return (React.createElement(ActionHandler, { className: "sb-message-template__image-container", elementId: props.elementId, style: props.parsedProperties, props: props }, | ||
React.createElement(ReactMessageTemplateImage, { className: "sb-message-template__image", alt: "image", src: props.imageUrl, style: { width: '100%', height: '100%', aspectRatio: 'inherit', objectFit: 'inherit' }, tintColor: (_a = props.imageStyle) === null || _a === void 0 ? void 0 : _a.tintColor, metaData: props.metaData }))); | ||
}, | ||
textButton(props) { | ||
return (React.createElement(ActionHandler, { className: "sb-message-template__text-button", elementId: props.elementId, style: props.parsedProperties, props: props }, renderText(Object.assign({ maxTextLines: defaultProperties.textButton.maxTextLines }, props)))); | ||
}, | ||
imageButton(props) { | ||
var _a; | ||
return (React.createElement(ActionHandler, { className: "sb-message-template__image-container sb-message-template__image-button", elementId: props.elementId, style: props.parsedProperties, props: props }, | ||
React.createElement(ReactMessageTemplateImage, { className: "sb-message-template__image", alt: "image-button", src: props.imageUrl, style: { width: '100%', height: '100%', aspectRatio: 'inherit', objectFit: 'inherit' }, tintColor: (_a = props.imageStyle) === null || _a === void 0 ? void 0 : _a.tintColor, metaData: props.metaData }))); | ||
}, | ||
carouselView(props) { | ||
var _a, _b; | ||
return (React.createElement(Carousel, { maxChildWidth: (_a = props.carouselStyle) === null || _a === void 0 ? void 0 : _a.maxChildWidth, spacing: (_b = props.carouselStyle) === null || _b === void 0 ? void 0 : _b.spacing, style: props.parsedProperties }, props.children)); | ||
}, | ||
}, | ||
}); | ||
export const parser = createParser({ | ||
mapBoxProps(props, options) { | ||
const styles = getDefaultStyles(); | ||
setViewProps(styles, props, options); | ||
setAlign(styles, props.layout, props.align); | ||
return styles; | ||
}, | ||
mapTextProps(props, options) { | ||
var _a; | ||
const styles = getDefaultStyles({ whiteSpace: 'pre-line', wordBreak: 'break-word' }); | ||
// Better not set flex 1 to text | ||
setViewProps(styles, props, options); | ||
setTextStyle(styles, props, options); | ||
setAlign(styles, Layout.Row, props.align); | ||
setTextAlign(styles, (_a = props.align) === null || _a === void 0 ? void 0 : _a.horizontal); | ||
return styles; | ||
}, | ||
mapImageProps(props, options) { | ||
const styles = getDefaultStyles(); | ||
setViewProps(styles, props, options); | ||
setImageStyle(styles, props.imageStyle); | ||
setImageAspectRatio(styles, props); | ||
return styles; | ||
}, | ||
mapTextButtonProps(props, options) { | ||
const styles = getDefaultStyles({ whiteSpace: 'pre-line', alignItems: 'center', justifyContent: 'center' }); | ||
setViewProps(styles, props, options); | ||
setTextStyle(styles, props, options); | ||
return styles; | ||
}, | ||
mapImageButtonProps(props, options) { | ||
const styles = getDefaultStyles(); | ||
setViewProps(styles, props, options); | ||
setImageStyle(styles, props.imageStyle); | ||
setImageAspectRatio(styles, props); | ||
return styles; | ||
}, | ||
mapCarouselProps(props, options) { | ||
var _a, _b, _c, _d, _e, _f, _g, _h; | ||
const styles = getDefaultStyles(); | ||
setViewProps(styles, props, options); | ||
styles['paddingBlockStart'] = (_b = (_a = props.viewStyle) === null || _a === void 0 ? void 0 : _a.padding) === null || _b === void 0 ? void 0 : _b.top; | ||
styles['paddingBlockEnd'] = (_d = (_c = props.viewStyle) === null || _c === void 0 ? void 0 : _c.padding) === null || _d === void 0 ? void 0 : _d.bottom; | ||
styles['paddingInlineStart'] = (_f = (_e = props.viewStyle) === null || _e === void 0 ? void 0 : _e.padding) === null || _f === void 0 ? void 0 : _f.left; | ||
styles['paddingInlineEnd'] = (_h = (_g = props.viewStyle) === null || _g === void 0 ? void 0 : _g.padding) === null || _h === void 0 ? void 0 : _h.right; | ||
return styles; | ||
}, | ||
}); | ||
import { parser } from './parser'; | ||
import { renderer } from './renderer'; | ||
export { parser } from './parser'; | ||
export { renderer } from './renderer'; | ||
export const { MessageTemplate } = createMessageTemplate({ | ||
@@ -117,9 +12,4 @@ renderer, | ||
Container: ({ children, className }) => { | ||
return (React.createElement("div", { className: `sb-message-template__parent ${className}`, style: { | ||
display: 'flex', | ||
flexDirection: 'column', | ||
maxWidth: 400, | ||
marginBlockEnd: 24, | ||
} }, children)); | ||
return (React.createElement("div", { className: `sb-message-template__parent ${className}`, style: { display: 'flex', flexDirection: 'column', maxWidth: 400, marginBlockEnd: 24 } }, children)); | ||
}, | ||
}); |
@@ -9,1 +9,13 @@ import { SizeSpec, View } from '@sendbird/uikit-message-template'; | ||
export declare const isNumber: (val?: string | number | null) => val is number; | ||
export declare const clx: (...names: (undefined | string)[]) => string; | ||
export declare const hasValidURLProtocol: (url?: string) => boolean; | ||
/** | ||
* @param url - url to be checked | ||
* @returns url with http:// protocol if it doesn't have any protocol | ||
* @example | ||
* returnUrl('www.sendbird.com') // returns 'http://www.sendbird.com' | ||
* returnUrl('https://www.sendbird.com') // returns 'https://www.sendbird.com' | ||
* returnUrl('ftp://www.sendbird.com') // returns 'ftp://www.sendbird.com' | ||
* returnUrl('sendbird.com') // returns 'https://sendbird.com' | ||
**/ | ||
export declare const getValidURL: (url?: string) => string; |
@@ -29,1 +29,21 @@ import { ComponentType, FlexSizeSpecValue } from '@sendbird/uikit-message-template'; | ||
}; | ||
export const clx = (...names) => { | ||
return names.filter((it) => !!it).join(' '); | ||
}; | ||
export const hasValidURLProtocol = (url = '') => { | ||
return ['http://', 'https://', 'ftp://'].some((protocol) => url.startsWith(protocol)); | ||
}; | ||
/** | ||
* @param url - url to be checked | ||
* @returns url with http:// protocol if it doesn't have any protocol | ||
* @example | ||
* returnUrl('www.sendbird.com') // returns 'http://www.sendbird.com' | ||
* returnUrl('https://www.sendbird.com') // returns 'https://www.sendbird.com' | ||
* returnUrl('ftp://www.sendbird.com') // returns 'ftp://www.sendbird.com' | ||
* returnUrl('sendbird.com') // returns 'https://sendbird.com' | ||
**/ | ||
export const getValidURL = (url = '') => { | ||
if (hasValidURLProtocol(url)) | ||
return url; | ||
return `https://${url}`; | ||
}; |
{ | ||
"name": "@sendbird/react-uikit-message-template-view", | ||
"version": "0.0.2", | ||
"version": "0.0.3", | ||
"publishConfig": { | ||
@@ -43,5 +43,5 @@ "registry": "https://registry.npmjs.org/", | ||
"dependencies": { | ||
"@sendbird/uikit-message-template": "^0.0.2" | ||
"@sendbird/uikit-message-template": "^0.0.3" | ||
}, | ||
"gitHead": "dcd044768de8cca0a69e7bbb6a33c95ce6223972" | ||
"gitHead": "14d7cfa0fe6e0311fdc46b00a44468a0856cd435" | ||
} |
@@ -98,2 +98,5 @@ import type { CSSProperties } from 'react'; | ||
} else if (width.type === 'fixed' && width.value >= 0) { | ||
if (parentLayout === Layout.Row) { | ||
style['flexShrink'] = 0; | ||
} | ||
style['width'] = width.value; | ||
@@ -108,2 +111,5 @@ } | ||
} else if (height.type === 'fixed' && height.value >= 0) { | ||
if (parentLayout === Layout.Column) { | ||
style['flexShrink'] = 0; | ||
} | ||
style['height'] = height.value; | ||
@@ -110,0 +116,0 @@ } |
@@ -38,1 +38,23 @@ import { ComponentType, FlexSizeSpecValue, SizeSpec, View } from '@sendbird/uikit-message-template'; | ||
}; | ||
export const clx = (...names: (undefined | string)[]) => { | ||
return names.filter((it) => !!it).join(' '); | ||
}; | ||
export const hasValidURLProtocol = (url = '') => { | ||
return ['http://', 'https://', 'ftp://'].some((protocol) => url.startsWith(protocol)); | ||
}; | ||
/** | ||
* @param url - url to be checked | ||
* @returns url with http:// protocol if it doesn't have any protocol | ||
* @example | ||
* returnUrl('www.sendbird.com') // returns 'http://www.sendbird.com' | ||
* returnUrl('https://www.sendbird.com') // returns 'https://www.sendbird.com' | ||
* returnUrl('ftp://www.sendbird.com') // returns 'ftp://www.sendbird.com' | ||
* returnUrl('sendbird.com') // returns 'https://sendbird.com' | ||
**/ | ||
export const getValidURL = (url = '') => { | ||
if (hasValidURLProtocol(url)) return url; | ||
return `https://${url}`; | ||
}; |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
271590
66
4205
+ Added@sendbird/uikit-message-template@0.0.3(transitive)
- Removed@sendbird/uikit-message-template@0.0.2(transitive)