forked from Ivasoft/mattermost-mobile
* update dependencies * update dependencies * feedback review * update @mattermost/react-native-turbo-mailer
266 lines
11 KiB
TypeScript
266 lines
11 KiB
TypeScript
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
|
// See LICENSE.txt for license information.
|
|
|
|
import {Platform, StyleProp, StyleSheet, TextStyle} from 'react-native';
|
|
|
|
import {getViewPortWidth} from '@utils/images';
|
|
import {changeOpacity, concatStyles, makeStyleSheetFromTheme} from '@utils/theme';
|
|
import {typography} from '@utils/typography';
|
|
|
|
import type {MarkdownTextStyles} from '@typings/global/markdown';
|
|
|
|
type LanguageObject = {
|
|
[key: string]: {
|
|
name: string;
|
|
extensions: string[];
|
|
aliases?: Set<string>;
|
|
};
|
|
}
|
|
|
|
export function getCodeFont() {
|
|
return Platform.OS === 'ios' ? 'Menlo' : 'monospace';
|
|
}
|
|
|
|
export const getMarkdownTextStyles = makeStyleSheetFromTheme((theme: Theme) => {
|
|
const codeFont = getCodeFont();
|
|
|
|
return {
|
|
emph: {
|
|
fontFamily: 'OpenSans-Italic',
|
|
},
|
|
strong: {
|
|
fontFamily: 'OpenSans-SemiBold',
|
|
fontWeight: '600',
|
|
},
|
|
del: {
|
|
textDecorationLine: 'line-through',
|
|
},
|
|
link: {
|
|
color: theme.linkColor,
|
|
fontFamily: 'OpenSans',
|
|
},
|
|
heading1: {
|
|
...typography('Heading', 700),
|
|
},
|
|
heading1Text: {
|
|
paddingTop: 12,
|
|
paddingBottom: 6,
|
|
},
|
|
heading2: {
|
|
...typography('Heading', 600),
|
|
},
|
|
heading2Text: {
|
|
paddingTop: 12,
|
|
paddingBottom: 6,
|
|
},
|
|
heading3: {
|
|
...typography('Heading', 500),
|
|
},
|
|
heading3Text: {
|
|
paddingTop: 12,
|
|
paddingBottom: 6,
|
|
},
|
|
heading4: {
|
|
...typography('Heading', 400),
|
|
},
|
|
heading4Text: {
|
|
paddingTop: 12,
|
|
paddingBottom: 6,
|
|
},
|
|
heading5: {
|
|
...typography('Heading', 300),
|
|
},
|
|
heading5Text: {
|
|
paddingTop: 12,
|
|
paddingBottom: 6,
|
|
},
|
|
heading6: {
|
|
...typography('Heading', 200),
|
|
},
|
|
heading6Text: {
|
|
paddingTop: 12,
|
|
paddingBottom: 6,
|
|
},
|
|
code: {
|
|
alignSelf: 'center',
|
|
backgroundColor: changeOpacity(theme.centerChannelColor, 0.07),
|
|
fontFamily: codeFont,
|
|
},
|
|
codeBlock: {
|
|
fontFamily: codeFont,
|
|
},
|
|
mention: {
|
|
fontFamily: 'OpenSans',
|
|
color: theme.linkColor,
|
|
},
|
|
error: {
|
|
fontFamily: 'OpenSans',
|
|
color: theme.errorTextColor,
|
|
},
|
|
table_header_row: {
|
|
fontFamily: 'OpenSans-Bold',
|
|
},
|
|
mention_highlight: {
|
|
color: theme.mentionHighlightLink,
|
|
},
|
|
search_highlight: {
|
|
backgroundColor: theme.mentionHighlightBg,
|
|
color: theme.mentionHighlightLink,
|
|
},
|
|
};
|
|
});
|
|
|
|
export const getMarkdownBlockStyles = makeStyleSheetFromTheme((theme: Theme) => {
|
|
return {
|
|
adjacentParagraph: {
|
|
marginTop: 8,
|
|
},
|
|
horizontalRule: {
|
|
backgroundColor: theme.centerChannelColor,
|
|
height: StyleSheet.hairlineWidth,
|
|
marginVertical: 10,
|
|
},
|
|
quoteBlockIcon: {
|
|
color: changeOpacity(theme.centerChannelColor, 0.5),
|
|
},
|
|
};
|
|
});
|
|
|
|
const highlightedLanguages: LanguageObject = {
|
|
actionscript: {name: 'ActionScript', extensions: ['as'], aliases: new Set(['as', 'as3'])},
|
|
applescript: {name: 'AppleScript', extensions: ['applescript', 'osascript', 'scpt']},
|
|
bash: {name: 'Bash', extensions: ['sh'], aliases: new Set('sh')},
|
|
clojure: {name: 'Clojure', extensions: ['clj', 'boot', 'cl2', 'cljc', 'cljs', 'cljs.hl', 'cljscm', 'cljx', 'hic']},
|
|
coffeescript: {name: 'CoffeeScript', extensions: ['coffee', '_coffee', 'cake', 'cjsx', 'cson', 'iced'], aliases: new Set(['coffee', 'coffee-script'])},
|
|
cpp: {name: 'C/C++', extensions: ['cpp', 'c', 'cc', 'h', 'c++', 'h++', 'hpp'], aliases: new Set(['c++', 'c'])},
|
|
cs: {name: 'C#', extensions: ['cs', 'csharp'], aliases: new Set(['c#', 'csharp'])},
|
|
css: {name: 'CSS', extensions: ['css']},
|
|
d: {name: 'D', extensions: ['d', 'di'], aliases: new Set('dlang')},
|
|
dart: {name: 'Dart', extensions: ['dart']},
|
|
delphi: {name: 'Delphi', extensions: ['delphi', 'dpr', 'dfm', 'pas', 'pascal', 'freepascal', 'lazarus', 'lpr', 'lfm']},
|
|
diff: {name: 'Diff', extensions: ['diff', 'patch'], aliases: new Set(['patch', 'udiff'])},
|
|
django: {name: 'Django', extensions: ['django', 'jinja']},
|
|
dockerfile: {name: 'Dockerfile', extensions: ['dockerfile', 'docker'], aliases: new Set('docker')},
|
|
elixir: {name: 'Elixir', extensions: ['ex', 'exs'], aliases: new Set(['ex', 'exs'])},
|
|
erlang: {name: 'Erlang', extensions: ['erl'], aliases: new Set('erl')},
|
|
fortran: {name: 'Fortran', extensions: ['f90', 'f95']},
|
|
fsharp: {name: 'F#', extensions: ['fsharp', 'fs']},
|
|
gcode: {name: 'G-Code', extensions: ['gcode', 'nc']},
|
|
go: {name: 'Go', extensions: ['go'], aliases: new Set('golang')},
|
|
groovy: {name: 'Groovy', extensions: ['groovy']},
|
|
handlebars: {name: 'Handlebars', extensions: ['handlebars', 'hbs', 'html.hbs', 'html.handlebars'], aliases: new Set(['hbs', 'mustache'])},
|
|
haskell: {name: 'Haskell', extensions: ['hs'], aliases: new Set('hs')},
|
|
haxe: {name: 'Haxe', extensions: ['hx']},
|
|
java: {name: 'Java', extensions: ['java', 'jsp']},
|
|
javascript: {name: 'JavaScript', extensions: ['js', 'jsx'], aliases: new Set(['js', 'jsx'])},
|
|
json: {name: 'JSON', extensions: ['json']},
|
|
julia: {name: 'Julia', extensions: ['jl'], aliases: new Set('jl')},
|
|
kotlin: {name: 'Kotlin', extensions: ['kt', 'ktm', 'kts']},
|
|
latex: {name: 'LaTeX', extensions: ['tex'], aliases: new Set('tex')},
|
|
less: {name: 'Less', extensions: ['less']},
|
|
lisp: {name: 'Lisp', extensions: ['lisp']},
|
|
lua: {name: 'Lua', extensions: ['lua']},
|
|
makefile: {name: 'Makefile', extensions: ['mk', 'mak'], aliases: new Set(['make', 'mf', 'gnumake', 'bsdmake'])},
|
|
markdown: {name: 'Markdown', extensions: ['md', 'mkdown', 'mkd'], aliases: new Set(['md', 'mkd'])},
|
|
matlab: {name: 'Matlab', extensions: ['matlab', 'm'], aliases: new Set('m')},
|
|
objectivec: {name: 'Objective C', extensions: ['mm', 'objc', 'obj-c'], aliases: new Set(['objective_c', 'objc'])},
|
|
ocaml: {name: 'OCaml', extensions: ['ml']},
|
|
perl: {name: 'Perl', extensions: ['perl', 'pl'], aliases: new Set('pl')},
|
|
pgsql: {name: 'PostgreSQL', extensions: ['pgsql', 'postgres', 'postgresql'], aliases: new Set(['postgres', 'postgresql'])},
|
|
php: {name: 'PHP', extensions: ['php', 'php3', 'php4', 'php5', 'php6'], aliases: new Set(['php3', 'php4', 'php5'])},
|
|
powershell: {name: 'PowerShell', extensions: ['ps', 'ps1'], aliases: new Set('posh')},
|
|
puppet: {name: 'Puppet', extensions: ['pp'], aliases: new Set('pp')},
|
|
python: {name: 'Python', extensions: ['py', 'gyp'], aliases: new Set('py')},
|
|
r: {name: 'R', extensions: ['r'], aliases: new Set(['r', 's'])},
|
|
ruby: {name: 'Ruby', extensions: ['ruby', 'rb', 'gemspec', 'podspec', 'thor', 'irb'], aliases: new Set('rb')},
|
|
rust: {name: 'Rust', extensions: ['rs'], aliases: new Set('rs')},
|
|
scala: {name: 'Scala', extensions: ['scala']},
|
|
scheme: {name: 'Scheme', extensions: ['scm', 'sld']},
|
|
scss: {name: 'SCSS', extensions: ['scss']},
|
|
smalltalk: {name: 'Smalltalk', extensions: ['st'], aliases: new Set(['st', 'squeak'])},
|
|
sql: {name: 'SQL', extensions: ['sql']},
|
|
stylus: {name: 'Stylus', extensions: ['styl'], aliases: new Set('styl')},
|
|
swift: {name: 'Swift', extensions: ['swift']},
|
|
text: {name: 'Text', extensions: ['txt', 'log']},
|
|
typescript: {name: 'TypeScript', extensions: ['ts', 'tsx'], aliases: new Set(['ts', 'tsx'])},
|
|
vbnet: {name: 'VB.Net', extensions: ['vbnet', 'vb', 'bas'], aliases: new Set(['vb', 'visualbasic'])},
|
|
vbscript: {name: 'VBScript', extensions: ['vbs']},
|
|
verilog: {name: 'Verilog', extensions: ['v', 'veo', 'sv', 'svh']},
|
|
vhdl: {name: 'VHDL', extensions: ['vhd', 'vhdl']},
|
|
xml: {name: 'HTML, XML', extensions: ['xml', 'html', 'xhtml', 'rss', 'atom', 'xsl', 'plist']},
|
|
yaml: {name: 'YAML', extensions: ['yaml'], aliases: new Set('yml')},
|
|
};
|
|
|
|
export function getHighlightLanguageFromNameOrAlias(name: string) {
|
|
const langName: string = name.toLowerCase();
|
|
if (highlightedLanguages[langName]) {
|
|
return langName;
|
|
}
|
|
|
|
return Object.keys(highlightedLanguages).find((key) => {
|
|
return highlightedLanguages[key].aliases?.has(langName);
|
|
}) || '';
|
|
}
|
|
|
|
export function getHighlightLanguageName(language: string): string {
|
|
const name: string | undefined = getHighlightLanguageFromNameOrAlias(language);
|
|
if (!name) {
|
|
return '';
|
|
}
|
|
return highlightedLanguages[name].name || '';
|
|
}
|
|
|
|
export function escapeRegex(text: string) {
|
|
return text.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&');
|
|
}
|
|
|
|
export const getMarkdownImageSize = (
|
|
isReplyPost: boolean,
|
|
isTablet: boolean,
|
|
sourceSize?: SourceSize,
|
|
knownSize?: PostImage,
|
|
layoutWidth?: number,
|
|
layoutHeight?: number,
|
|
) => {
|
|
let ratioW;
|
|
let ratioH;
|
|
|
|
if (sourceSize?.width && sourceSize?.height) {
|
|
// if the source image is set with HxW
|
|
return {width: sourceSize.width, height: sourceSize.height};
|
|
} else if (knownSize?.width && knownSize.height) {
|
|
// If the metadata size is set calculate the ratio
|
|
ratioW = knownSize.width > 0 ? knownSize.height / knownSize.width : 1;
|
|
ratioH = knownSize.height > 0 ? knownSize.width / knownSize.height : 1;
|
|
}
|
|
|
|
if (sourceSize?.width && !sourceSize.height && ratioW) {
|
|
// If source Width is set calculate the height using the ratio
|
|
return {width: sourceSize.width, height: sourceSize.width * ratioW};
|
|
} else if (sourceSize?.height && !sourceSize.width && ratioH) {
|
|
// If source Height is set calculate the width using the ratio
|
|
return {width: sourceSize.height * ratioH, height: sourceSize.height};
|
|
}
|
|
|
|
if (sourceSize?.width || sourceSize?.height) {
|
|
// if at least one size is set and we do not have metadata (svg's)
|
|
const width = sourceSize.width;
|
|
const height = sourceSize.height;
|
|
return {width: width || height, height: height || width};
|
|
}
|
|
|
|
if (knownSize?.width && knownSize.height) {
|
|
// When metadata values are set
|
|
return {width: knownSize.width, height: knownSize.height};
|
|
}
|
|
|
|
// When no metadata and source size is not specified (full size svg's)
|
|
const width = layoutWidth || getViewPortWidth(isReplyPost, isTablet);
|
|
return {width, height: layoutHeight || width};
|
|
};
|
|
|
|
export const computeTextStyle = (textStyles: MarkdownTextStyles, baseStyle: StyleProp<TextStyle>, context: string[]) => {
|
|
const contextStyles: TextStyle[] = context.map((type) => textStyles[type]).filter((f) => f !== undefined);
|
|
return contextStyles.length ? concatStyles(baseStyle, contextStyles) : baseStyle;
|
|
};
|