UNPKG

jsx-slack

Version:

Build JSON object for Slack Block Kit surfaces from JSX

507 lines (506 loc) 22.4 kB
import { OptgroupProps } from './block-kit/composition/Optgroup'; import { OptionProps } from './block-kit/composition/Option'; import { ButtonProps } from './block-kit/elements/Button'; import { SelectProps } from './block-kit/elements/Select'; import { AutoFocusibleIntrinsicProps } from './block-kit/elements/utils'; import { TextareaProps } from './block-kit/input/Textarea'; import { DividerProps } from './block-kit/layout/Divider'; import { HeaderProps } from './block-kit/layout/Header'; import { ImageProps } from './block-kit/layout/Image'; import { InputProps } from './block-kit/layout/Input'; import { SectionProps } from './block-kit/layout/Section'; import { VideoProps } from './block-kit/layout/Video'; /** * The helper function to cast the output type from JSX element to `any`. Just * returns the passed value with no operations. * * This function is provided for TypeScript user and migrated user from * jsx-slack v1. * * @param element - JSX element * @return The passed JSX element with no-ops */ export declare function JSXSlack(element: JSXSlack.JSX.Element): any; export declare namespace JSXSlack { interface StringLike { toString: () => string; } /** A element allowed as a child. */ export type ChildElement = Node | string | StringLike | ChildElement[] | boolean | null | undefined; /** Elements allowed as children. */ export type ChildElements = ChildElement | ChildElement[]; /** Similar to `ChildElement`, but excluded string and string-like object. */ export type ChildNode = Node | ChildNode[] | boolean | null | undefined; /** Similar to `ChildElements`, but excluded string and string-like object. */ export type ChildNodes = ChildNode | ChildNode[]; type FilteredChild = Node | string | StringLike; type MapCallbackFn<T> = (this: FilteredChild | null, child: FilteredChild | null, index: number) => T; export type PropsWithChildren<P extends {} = {}> = { children?: ChildElements; } & P; export type FunctionComponent<P extends {} = {}> = (props: P) => Node<P> | null; export type FC<P extends {} = {}> = FunctionComponent<P>; export interface Node<P extends {} = {}> { /** * @internal * **⚠️ This is an internal member of jsx-slack. ⚠️** Not recommend to use. */ readonly $$jsxslack: { type: FC<P> | string; props: P; children: ChildElement[]; }; } /** * Verify the passed object is a jsx-slack element. * * @param element - An object to verify * @return `true` if the passed object was a jsx-slack element, otherwise * `false` */ export const isValidElement: (obj: unknown) => obj is JSX.Element; /** * Create and return a new jsx-slack element of the given type. * * The `type` argument can be either a component function, a tag name string * such as `'strong'` or `'em'`, and a fragment (`JSXSlack.Fragment`). * * **NOTE**: _You won't typically invoke this directly if you are using JSX._ * * @param type - A component function, fragment, or intrinsic HTML tag name * @param props - Property values to pass into the element for creation * @param children - Children elements of a new jsx-slack element * @return A new jsx-slack element */ export const createElement: <P extends {} = {}>(type: FC<P> | keyof JSX.IntrinsicElements, props?: P | null, ...children: ChildElement[]) => JSX.Element | null; /** An alias into `JSXSlack.createElement`. */ export const h: <P extends {} = {}>(type: FC<P> | keyof JSX.IntrinsicElements, props?: P | null, ...children: ChildElement[]) => JSX.Element | null; /** * Group a list of JSX elements. * * Typically the component for jsx-slack should return a single JSX element. * Wrapping multiple elements in `JSXSlack.Fragment` lets you return a list of * children. */ export const Fragment: import("./jsx-internals").BuiltInComponent<{ children: ChildElements; }>; /** * Provide utilities for dealing with the `props.children` opaque data * structure. */ export const Children: Readonly<{ /** * Return the total number of elements in `children`. * * It would be same as the number of times `JSXSlack.Children.map()` would * invoke the callback. * * @param children - The target element(s) to count * @return The total number of elements in the passed children */ count: (children: ChildElements) => number; /** * Like `JSXSlack.Children.map()`, but no return value. * * @param children - The target element(s) to traverse * @param callbackFn - Callback function */ forEach: (children: ChildElements, callbackFn: MapCallbackFn<void>) => void; /** * Invoke callback function on every immediate child in `children`. * * The callback function allows up to 2 arguments compatible with * `Array.prototype.map()`, and `this` will be a traversed child. The * callback can return any value for transforming, or the nullish value for * to skip mapping. * * @remarks * When the passed `children` is `null` or `undefined`, this function * returns the passed value instead of an array as it is. * * If `JSXSlack.Fragment` was passed as `children`, it will be treated as _a * single child_. The callback won't invoke with every child of the * fragment. * * @param children - The target element(s) to traverse * @param callbackFn - Callback function * @return An array of the value returned by callback function, or nullish * value when passed `null` or `undefined`. */ map: <T>(children: ChildElements, callbackFn: MapCallbackFn<T>) => Exclude<T, null | undefined>[] | null | undefined; /** * Verify whether `children` has an only one child of jsx-slack element and * return it. Otherwise, throw an error. * * @remarks * Even if passed a single jsx-slack element, this method may throw an error * when the component returned `null` or any primitive value such as string, * number, etc. * * @param children - The target element(s) * @return A single jsx-slack element if verified * @throws Will throw an error if `children` is not a single JSX element */ only: (children: ChildElements) => JSX.Element; /** * Return an array made flatten the `children` opaque data structure. * * Useful for manipulating or re-ordering collection of children passed to * the component. * * @remarks * If an array in the children could be a subset of JSON payload, such as a * returned array from the built-in component, it would not be flatten. * * @param children - The target element(s) * @return A flatten array consisted of JSX elements */ toArray: (children: ChildElements) => FilteredChild[]; }>; /** * Set the state of the exact mode, to enable or disable forcible styling in * rendered Slack mrkdwn. * * Some special characters to style text will work only in the break of words. * By turning the exact mode on, jsx-slack will insert zero-width space around * special chars generated by HTML-like elements (`<b>`, `<i>`, `<s>`, etc), * to enable styling forcibly. * * @remarks * __Exact mode is the last resort__, because zero-width space included text * may confuse a reader when editing the copied message. _You should consider * to deal with inserting whitespaces around the styled text manually instead * of turning on exact mode._ * * @param mode - A boolean value to indicate whether turning on exact mode * @return The current state of exact mode */ export const exactMode: (mode?: boolean) => boolean; export namespace JSX { export interface Element extends Node<any> { } export interface IntrinsicElements { /** An HTML-compatible alias into `<Header>` layout block. */ header: HeaderProps; /** An HTML-compatible alias into `<Divider>` layout block. */ hr: DividerProps; /** * A HTML-compatible alias into `<Image>` layout block and block element. */ img: ImageProps; /** A HTML-compatible alias into `<Section>` layout block. */ section: SectionProps; /** A HTML-compatible alias into `<Button>` block element. */ button: ButtonProps; /** A HTML-compatible alias into `<Textarea>` input component. */ textarea: TextareaProps & AutoFocusibleIntrinsicProps; /** * A HTML-compatible alias into `<Input>` layout block, input component, * and helpers for some surfaces. */ input: InputProps & AutoFocusibleIntrinsicProps; /** * A HTML-compatible alias into `<Optgroup>` component for composition * object. */ optgroup: OptgroupProps; /** * A HTML-compatible alias into `<Option>` component for composition * object. */ option: OptionProps; /** * A HTML-compatible alias into `<Select>` block element and input * component. */ select: SelectProps & AutoFocusibleIntrinsicProps; /** A HTML-compatible alias into `<Video>` layout block. */ video: VideoProps; /** * Creates a hyperlink to the external web pages, email addresses, public * Slack channels, and Slack users with mention. * * ### Slack-specifics * * Keep in mind that the custom contents in children of `<a>` tag cannot * render when using Slack-specific features. Slack will fill the content * by own. * * In following cases, `<a>` tag would accept the void element `<a />` * unlike HTML specification. * * #### Link to public Slack channel * * jsx-slack can create [a link to the Slack channel](https://api.slack.com/reference/surfaces/formatting#linking-channels) * by specifying hash-prefixed ID for the public channel: * `<a href="#C0123456789" />` _(Notice that it is not the channel name)_ * * Slack's link syntax _only accepts the public channel_. Channels in * private won't make a link. * * #### Mention to user and user group * * You can send a mention the specified user by ID through similar syntax * `<a href="@U0123456789" />`. * * jsx-slack can detect atmark-prefixed user ID `@U`, the user ID for * Enterprise Grid `@W`, and the user-group ID `@S`. * * #### Special mentions * * You can also use these [special mentions](https://api.slack.com/reference/surfaces/formatting#special-mentions) * to send widely (but typically they should be used carefully): * * - `<a href="@here" />` * - `<a href="@channel" />` * - `<a href="@everyone" />` */ a: { children?: ChildElements; /** * Either one of the URL for the created hyperlink, hash-prefixed public * channel ID, or atmark-prefixed ID of the target to mention. */ href: string; }; /** * Style the content with bold through generating the text surrounded by * `*`. * * @remarks * Depending on contents around the element, styling may not apply * correctly due to the restriction of mrkdwn that _special character will * only work in a word boundary_. Make sure that the element is surrounded * by word boundaries (e.g. Whitespaces). * * Not recommended but you can also deal it with turning on exact mode via * `JSXSlack.exactMode(true)`. */ b: {}; /** * Create the block for the quotation. Slack renders the content with the * gray line on the left. */ blockquote: {}; /** * Add a line-break. * * Any break characters in JSX are ignored and collapsed to single * whitespace so you should always use `<br />` for line-break. */ br: { children?: never; }; /** * Make the inline code element through generating the text surrounded by * `` ` ``, to indicate that is a short fragment of computer code. * * In the content of `<code>`, all basic text stylings by both raw mrkdwn * and JSX are ignored. * * @remarks * Depending on contents around the element, styling may not apply * correctly due to the restriction of mrkdwn that _special character will * only work in a word boundary_. Make sure that the element is surrounded * by word boundaries (e.g. Whitespaces). * * Not recommended but you can also deal it with turning on exact mode via * `JSXSlack.exactMode(true)`. */ code: {}; /** An alias into `<s>`. */ del: {}; /** An alias into `<i>`. */ em: {}; /** * Style the content with italic through generating the text surrounded by * `_`. * * @remarks * Depending on contents around the element, styling may not apply * correctly due to the restriction of mrkdwn that _special character will * only work in a word boundary_. Make sure that the element is surrounded * by word boundaries (e.g. Whitespaces). * * Not recommended but you can also deal it with turning on exact mode via * `JSXSlack.exactMode(true)`. */ i: {}; /** * Define an item of the list. * * This element has to be contained in children of `<ul>` and `<ol>`. */ li: { children: ChildElements; /** * Set the ordinal value of the current list item for the ordered list. */ value?: number; }; /** * Create the ordered list. * * Slack mrkdwn does not support list but jsx-slack can imitate HTML-style * list by generating list-like plain text. It should contain list items * provided by `<li>` element. */ ol: { children: ChildElements; /** A number of the beginning count for the first list item. */ start?: number; /** * Set the type of the number for list item markers. * * - `1`: Arabic numerals (default: 1, 2, 3...) * - `a`: Alphabetical numerals with lowercase letters (a, b, c...) * - `A`: Alphabetical numerals with uppercase letters (A, B, C...) * - `i`: Roman numerals with lowercase letters (i, ii, iii...) * - `I`: Roman numerals with uppercase letters (I, II, III...) */ type?: '1' | 'a' | 'A' | 'i' | 'I'; }; /** Make a paragraph. */ p: {}; /** * Create the block for multiline pre-formatted text. * * Whitespaces and line-breaks in the content of `<pre>` element will * render as are written. * * @example * ```jsx * const preformatted = '1\n2\n3' * * console.log( * <Mrkdwn> * <pre>{preformatted}</pre> * </Mrkdwn> * ) * ``` * * `<pre>` in JSX has well-known pitfall: Whitespaces in the contents * written as same as other elements will be collapsed by JSX transpiler. * You should pass string value through JSX interpolation by expression to * keep pre-formatted text. */ pre: {}; /** * Style the content with strikethrough through generating the text * surrounded by `~`. * * @remarks * Depending on contents around the element, styling may not apply * correctly due to the restriction of mrkdwn that _special character will * only work in a word boundary_. Make sure that the element is surrounded * by word boundaries (e.g. Whitespaces). * * Not recommended but you can also deal it with turning on exact mode via * `JSXSlack.exactMode(true)`. */ s: {}; /** * Redirect contents in its children to the description of `<Checkbox>` * and `<RadioButton>`. * * It provides ergonomic templating instead of using JSX interpolation to * `description` prop. * * ```jsx * <Checkbox value="check"> * <b>Checkbox</b> * <small> * It's a <i>description</i> * </small> * </Checkbox> * ``` * * _This element is only available in `<Checkbox>` and `<RadioButton>`._ * It would be ignored in other components because Slack cannot change * font size in a part of the text. */ small: {}; /** * Divide mrkdwn text explicitly in `<Context>`. * * Usually text contents in `<Context>` will merge in pertinent mrkdwn * elements automatically, but you can also apply manual dividation via * `<span>` (or `<Mrkdwn>`) to get effective rendering in Slack client. * * _This element is only available in `<Context>`._ It has no effect even * if used in other components. */ span: {}; /** An alias into `<s>`. */ strike: {}; /** An alias into `<b>`. */ strong: {}; /** * Render a specific date and time, with defined format for Slack. * * It makes easy to render the formatted date and time with localized * timezone for each Slack user. * [Learn about date formatting in Slack documentation.](https://api.slack.com/reference/surfaces/formatting#date-formatting) * * ```jsx * <time dateTime="1392734382">{'Posted {date_num} {time_secs}'}</time> * // <!date^1392734382^Posted {date_num} {time_secs}|Posted 2014-02-18 14:39:42 PM> * * <time dateTime={1392734382}>{'{date} at {time}'}</time> * // <!date^1392734382^{date} at {time}|February 18th, 2014 at 14:39 PM> * * <a href="https://example.com/"> * <time dateTime={new Date(Date.UTC(2014, 1, 18, 14, 39, 42))} fallback="Feb 18, 2014 PST"> * {'{date_short}'} * </time> * </a> * // <!date^1392734382^{date_short}^https://example.com/|Feb 18, 2014 PST> * ``` * * We have very similar definition to HTML5 `<time>` tag, but _there is * not-compatible attribute with HTML_: `fallback` to define the fallback * text for not-supported Slack client. */ time: (TimeIntrinsicElementProps & Required<Pick<TimeIntrinsicElementProps, 'dateTime'>>) | (TimeIntrinsicElementProps & Required<Pick<TimeIntrinsicElementProps, 'datetime'>>); /** * Create the unordered list. * * Slack mrkdwn does not support list but jsx-slack can imitate HTML-style * list by generating list-like plain text. It should contain list items * provided by `<li>` element. */ ul: {}; } export interface ElementChildrenAttribute { children: {}; } type TimeIntrinsicElementProps = { children?: ChildElements; /** * Set the value of date and time to render. * * jsx-slack accepts either of a parsable string as date, UNIX timestamp * _in second_, or JavaScript `Date` instance. */ dateTime?: string | number | Date; /** * An alias into `dateTime` attribute. */ datetime?: string | number | Date; /** * Define the fallback text, may render when the client cannot parse * specified date and format. * * If not defined, jsx-slack tries to generate the fallback text * automatically from the specified date and format. _Please note that a * timezone for the generated text is always UTC._ * * __NOTE__: This prop is not-compatible with HTML. */ fallback?: string; }; export {}; } export {}; }