├── .npmignore ├── docs ├── ellipsis.jpeg └── example.jpeg ├── android ├── src │ └── main │ │ ├── AndroidManifestNew.xml │ │ ├── AndroidManifest.xml │ │ └── java │ │ └── com │ │ └── stroketext │ │ ├── StrokeTextPackage.java │ │ ├── FontUtil.java │ │ ├── StrokeTextViewManager.java │ │ └── StrokeTextView.java ├── gradle.properties └── build.gradle ├── .prettierrc.js ├── ios ├── StrokeText-Bridging-Header.h ├── StrokeTextViewManager.swift ├── StrokeTextViewManager.m ├── StrokedTextLabel.swift └── StrokeTextView.swift ├── .github └── workflows │ └── npm-publish.yml ├── src └── index.tsx ├── package.json ├── .gitignore ├── LICENSE ├── tsconfig.json ├── react-native-stroke-text.podspec ├── README.md └── yarn.lock /.npmignore: -------------------------------------------------------------------------------- 1 | /docs 2 | -------------------------------------------------------------------------------- /docs/ellipsis.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/charmy/react-native-stroke-text/HEAD/docs/ellipsis.jpeg -------------------------------------------------------------------------------- /docs/example.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/charmy/react-native-stroke-text/HEAD/docs/example.jpeg -------------------------------------------------------------------------------- /android/src/main/AndroidManifestNew.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /android/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | -------------------------------------------------------------------------------- /.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | printWidth: 120, 3 | tabWidth: 2, 4 | useTabs: false, 5 | semi: true, 6 | singleQuote: false, 7 | trailingComma: "all", 8 | }; 9 | -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | StrokeText_kotlinVersion=1.7.0 2 | StrokeText_minSdkVersion=21 3 | StrokeText_targetSdkVersion=31 4 | StrokeText_compileSdkVersion=31 5 | StrokeText_ndkversion=21.4.7075529 6 | -------------------------------------------------------------------------------- /ios/StrokeText-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | #import 4 | #import 5 | #import 6 | #import 7 | -------------------------------------------------------------------------------- /ios/StrokeTextViewManager.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import UIKit 3 | 4 | @objc(StrokeTextViewManager) 5 | class StrokeTextViewManager: RCTViewManager { 6 | 7 | override func view() -> UIView! { 8 | let newView = StrokeTextView(bridge: self.bridge) 9 | return newView 10 | } 11 | 12 | @objc override static func requiresMainQueueSetup() -> Bool { 13 | return false 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /ios/StrokeTextViewManager.m: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface RCT_EXTERN_MODULE(StrokeTextViewManager, RCTViewManager) 4 | 5 | RCT_EXPORT_VIEW_PROPERTY(width, NSNumber) 6 | RCT_EXPORT_VIEW_PROPERTY(text, NSString) 7 | RCT_EXPORT_VIEW_PROPERTY(fontSize, NSNumber) 8 | RCT_EXPORT_VIEW_PROPERTY(color, NSString) 9 | RCT_EXPORT_VIEW_PROPERTY(strokeColor, NSString) 10 | RCT_EXPORT_VIEW_PROPERTY(strokeWidth, NSNumber) 11 | RCT_EXPORT_VIEW_PROPERTY(fontFamily, NSString) 12 | RCT_EXPORT_VIEW_PROPERTY(align, NSString) 13 | RCT_EXPORT_VIEW_PROPERTY(ellipsis, BOOL) 14 | RCT_EXPORT_VIEW_PROPERTY(numberOfLines, NSNumber) 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /.github/workflows/npm-publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish CI 2 | 3 | on: 4 | release: 5 | types: [created] 6 | 7 | jobs: 8 | publish-npm: 9 | runs-on: ubuntu-latest 10 | permissions: 11 | contents: read 12 | id-token: write 13 | steps: 14 | - uses: actions/checkout@v4 15 | - uses: actions/setup-node@v4 16 | with: 17 | node-version: 18 18 | registry-url: https://registry.npmjs.org/ 19 | - name: Build 20 | run: | 21 | yarn install 22 | yarn run build 23 | - run: npm publish --provenance --access public 24 | env: 25 | NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}} 26 | -------------------------------------------------------------------------------- /src/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { requireNativeComponent } from "react-native"; 3 | 4 | const ComponentName = "StrokeTextView"; 5 | 6 | type TextAlign = "center" | "left" | "right" 7 | 8 | export interface StrokeTextProps { 9 | width?: number; 10 | text: string; 11 | fontSize?: number; 12 | color?: string; 13 | strokeColor?: string; 14 | strokeWidth?: number; 15 | fontFamily?: string; 16 | align?: TextAlign; 17 | numberOfLines?: number; 18 | ellipsis?: boolean; 19 | } 20 | 21 | const NativeStrokeText = requireNativeComponent(ComponentName); 22 | 23 | export const StrokeText = (props: StrokeTextProps) => { 24 | return ; 25 | }; 26 | -------------------------------------------------------------------------------- /android/src/main/java/com/stroketext/StrokeTextPackage.java: -------------------------------------------------------------------------------- 1 | package com.stroketext; 2 | 3 | import com.facebook.react.ReactPackage; 4 | import com.facebook.react.bridge.NativeModule; 5 | import com.facebook.react.bridge.ReactApplicationContext; 6 | import com.facebook.react.uimanager.ViewManager; 7 | 8 | import java.util.Arrays; 9 | import java.util.Collections; 10 | import java.util.List; 11 | 12 | public class StrokeTextPackage implements ReactPackage { 13 | @Override 14 | public List createNativeModules(ReactApplicationContext reactContext) { 15 | return Collections.emptyList(); 16 | } 17 | 18 | @Override 19 | public List createViewManagers(ReactApplicationContext reactContext) { 20 | return Arrays.asList(new StrokeTextViewManager()); 21 | } 22 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@charmy.tech/react-native-stroke-text", 3 | "version": "1.2.3", 4 | "description": "React Native Stroke/Outline Text", 5 | "main": "build/index.js", 6 | "source": "./src/", 7 | "author": "Charmy Inc. (https://github.com/charmy)", 8 | "license": "MIT", 9 | "homepage": "https://github.com/charmy/react-native-stroke-text#readme", 10 | "repository": "https://github.com/charmy/react-native-stroke-text", 11 | "bugs": { 12 | "url": "https://github.com/charmy/react-native-stroke-text" 13 | }, 14 | "keywords": [ 15 | "react-native", 16 | "stroke", 17 | "text", 18 | "outline" 19 | ], 20 | "scripts": { 21 | "build": "tsc" 22 | }, 23 | "devDependencies": { 24 | "@babel/core": "^7.21.3", 25 | "@babel/runtime": "^7.21.0", 26 | "@types/node": "^18.15.3", 27 | "@types/react": "^18.0.28", 28 | "@types/react-native": "^0.71.3", 29 | "prettier": "^2.8.5", 30 | "typescript": "^5.0.2" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # OSX 2 | # 3 | .DS_Store 4 | 5 | # XDE 6 | .expo/ 7 | 8 | # VSCode 9 | .vscode/ 10 | jsconfig.json 11 | 12 | # Xcode 13 | # 14 | build/ 15 | *.pbxuser 16 | !default.pbxuser 17 | *.mode1v3 18 | !default.mode1v3 19 | *.mode2v3 20 | !default.mode2v3 21 | *.perspectivev3 22 | !default.perspectivev3 23 | xcuserdata 24 | *.xccheckout 25 | *.moved-aside 26 | DerivedData 27 | *.hmap 28 | *.ipa 29 | *.xcuserstate 30 | project.xcworkspace 31 | 32 | # Android/IJ 33 | # 34 | .classpath 35 | .cxx 36 | .gradle 37 | .idea 38 | .project 39 | .settings 40 | local.properties 41 | android.iml 42 | 43 | # Cocoapods 44 | # 45 | example/ios/Pods 46 | 47 | # Ruby 48 | example/vendor/ 49 | 50 | # node.js 51 | # 52 | node_modules/ 53 | npm-debug.log 54 | yarn-debug.log 55 | yarn-error.log 56 | 57 | # BUCK 58 | buck-out/ 59 | \.buckd/ 60 | android/app/libs 61 | android/keystores/debug.keystore 62 | 63 | # Yarn 64 | .yarn/* 65 | !.yarn/patches 66 | !.yarn/plugins 67 | !.yarn/releases 68 | !.yarn/sdks 69 | !.yarn/versions 70 | 71 | # Expo 72 | .expo/ 73 | 74 | # Turborepo 75 | .turbo/ 76 | 77 | /build 78 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Charmy 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "esnext", 4 | "module": "es6", 5 | "lib": ["es6"], 6 | "allowJs": true, 7 | "jsx": "react-native", 8 | "noImplicitAny": false, 9 | "incremental": true /* Enable incremental compilation */, 10 | "isolatedModules": true, 11 | "strict": true, 12 | "moduleResolution": "node", 13 | "baseUrl": "./", 14 | "outDir": "build", 15 | "noEmitHelpers": true, 16 | "alwaysStrict": true, 17 | "strictFunctionTypes": true, 18 | "resolveJsonModule": true, 19 | "importHelpers": false, 20 | "experimentalDecorators": true, 21 | "strictPropertyInitialization": false, 22 | "allowSyntheticDefaultImports": true, 23 | "strictNullChecks": true, 24 | "skipDefaultLibCheck": true, 25 | "skipLibCheck": true, 26 | "esModuleInterop": true, 27 | "typeRoots": ["./node_modules/@types", "./@types"], 28 | "declaration": true /* Generates corresponding '.d.ts' file. */, 29 | "sourceMap": true /* Generates corresponding '.map' file. */ 30 | }, 31 | "exclude": [ 32 | "node_modules", 33 | "build", 34 | ] 35 | } 36 | -------------------------------------------------------------------------------- /android/src/main/java/com/stroketext/FontUtil.java: -------------------------------------------------------------------------------- 1 | package com.stroketext; 2 | 3 | import android.content.Context; 4 | import android.graphics.Typeface; 5 | 6 | import com.facebook.react.views.text.ReactFontManager; 7 | 8 | import java.io.IOException; 9 | 10 | public class FontUtil { 11 | 12 | public static Typeface getFont(Context context, String fontFamily) { 13 | Typeface typeface = getFontFromAssets(context, fontFamily); 14 | if (typeface == null) { 15 | typeface = getFontFromReactFontManager(context, fontFamily); 16 | } 17 | return typeface; 18 | } 19 | 20 | private static Typeface getFontFromAssets(Context context, String fontFamily) { 21 | String fontPath = findFontFile(context, "fonts/", fontFamily); 22 | if (fontPath != null) { 23 | return Typeface.createFromAsset(context.getAssets(), fontPath); 24 | } 25 | return null; 26 | } 27 | 28 | private static Typeface getFontFromReactFontManager(Context context, String fontFamily) { 29 | return ReactFontManager.getInstance().getTypeface(fontFamily, 0, context.getAssets()); 30 | } 31 | 32 | private static String findFontFile(Context context, String folderPath, String fontName) { 33 | try { 34 | String[] files = context.getAssets().list(folderPath); 35 | for (String file : files) { 36 | if (file.startsWith(fontName) && (file.endsWith(".ttf") || file.endsWith(".otf"))) { 37 | return folderPath + file; 38 | } 39 | } 40 | } catch (IOException e) { 41 | e.printStackTrace(); 42 | } 43 | return null; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /react-native-stroke-text.podspec: -------------------------------------------------------------------------------- 1 | require "json" 2 | 3 | package = JSON.parse(File.read(File.join(__dir__, "package.json"))) 4 | folly_compiler_flags = '-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1 -Wno-comma -Wno-shorten-64-to-32' 5 | 6 | Pod::Spec.new do |s| 7 | s.name = "react-native-stroke-text" 8 | s.version = package["version"] 9 | s.summary = package["description"] 10 | s.homepage = package["homepage"] 11 | s.license = package["license"] 12 | s.authors = package["author"] 13 | 14 | s.platforms = { :ios => "11.0" } 15 | s.source = { :git => ".git", :tag => "#{s.version}" } 16 | 17 | s.source_files = "ios/**/*.{h,m,mm,swift}" 18 | 19 | # Use install_modules_dependencies helper to install the dependencies if React Native version >=0.71.0. 20 | # See https://github.com/facebook/react-native/blob/febf6b7f33fdb4904669f99d795eba4c0f95d7bf/scripts/cocoapods/new_architecture.rb#L79. 21 | if respond_to?(:install_modules_dependencies, true) 22 | install_modules_dependencies(s) 23 | else 24 | s.dependency "React-Core" 25 | 26 | # Don't install the dependencies when we run `pod install` in the old architecture. 27 | if ENV['RCT_NEW_ARCH_ENABLED'] == '1' then 28 | s.compiler_flags = folly_compiler_flags + " -DRCT_NEW_ARCH_ENABLED=1" 29 | s.pod_target_xcconfig = { 30 | "HEADER_SEARCH_PATHS" => "\"$(PODS_ROOT)/boost\"", 31 | "OTHER_CPLUSPLUSFLAGS" => "-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1", 32 | "CLANG_CXX_LANGUAGE_STANDARD" => "c++17" 33 | } 34 | s.dependency "React-RCTFabric" 35 | s.dependency "React-Codegen" 36 | s.dependency "RCT-Folly" 37 | s.dependency "RCTRequired" 38 | s.dependency "RCTTypeSafety" 39 | s.dependency "ReactCommon/turbomodule/core" 40 | end 41 | end 42 | end 43 | -------------------------------------------------------------------------------- /ios/StrokedTextLabel.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | class StrokedTextLabel: UILabel { 4 | required init?(coder: NSCoder) { 5 | fatalError("init(coder:) has not been implemented") 6 | } 7 | 8 | override init(frame: CGRect) { 9 | super.init(frame: frame) 10 | self.numberOfLines = 0 11 | } 12 | 13 | private var textInsets: UIEdgeInsets = .zero 14 | 15 | public func updateTextInsets() { 16 | textInsets = UIEdgeInsets(top: outlineWidth, left: outlineWidth, bottom: outlineWidth, right: outlineWidth) 17 | } 18 | 19 | var outlineWidth: CGFloat = 0 20 | var outlineColor: UIColor = .clear 21 | var align: NSTextAlignment = .center 22 | var customWidth: CGFloat = 0 23 | var ellipsis: Bool = false 24 | 25 | 26 | override func drawText(in rect: CGRect) { 27 | let shadowOffset = self.shadowOffset 28 | let textColor = self.textColor 29 | 30 | self.lineBreakMode = ellipsis ? .byTruncatingTail : .byWordWrapping 31 | 32 | let adjustedRect = rect.inset(by: textInsets) 33 | 34 | let context = UIGraphicsGetCurrentContext() 35 | context?.setLineWidth(outlineWidth) 36 | context?.setLineJoin(.round) 37 | context?.setTextDrawingMode(.stroke) 38 | self.textAlignment = align 39 | self.textColor = outlineColor 40 | 41 | super.drawText(in: adjustedRect) 42 | 43 | context?.setTextDrawingMode(.fill) 44 | self.textColor = textColor 45 | self.shadowOffset = CGSize(width: 0, height: 0) 46 | super.drawText(in: adjustedRect) 47 | 48 | self.shadowOffset = shadowOffset 49 | } 50 | 51 | override var intrinsicContentSize: CGSize { 52 | var contentSize = super.intrinsicContentSize 53 | if customWidth > 0 { 54 | contentSize.width = customWidth 55 | } else { 56 | contentSize.width += outlineWidth 57 | } 58 | 59 | contentSize.height += outlineWidth 60 | return contentSize 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | google() 4 | mavenCentral() 5 | } 6 | 7 | dependencies { 8 | classpath "com.android.tools.build:gradle:7.2.1" 9 | } 10 | } 11 | 12 | def isNewArchitectureEnabled() { 13 | return rootProject.hasProperty("newArchEnabled") && rootProject.getProperty("newArchEnabled") == "true" 14 | } 15 | 16 | apply plugin: "com.android.library" 17 | 18 | if (isNewArchitectureEnabled()) { 19 | apply plugin: "com.facebook.react" 20 | } 21 | 22 | def getExtOrDefault(name) { 23 | return rootProject.ext.has(name) ? rootProject.ext.get(name) : project.properties["StrokeText_" + name] 24 | } 25 | 26 | def getExtOrIntegerDefault(name) { 27 | return rootProject.ext.has(name) ? rootProject.ext.get(name) : (project.properties["StrokeText_" + name]).toInteger() 28 | } 29 | 30 | def supportsNamespace() { 31 | def parsed = com.android.Version.ANDROID_GRADLE_PLUGIN_VERSION.tokenize('.') 32 | def major = parsed[0].toInteger() 33 | def minor = parsed[1].toInteger() 34 | 35 | // Namespace support was added in 7.3.0 36 | return (major == 7 && minor >= 3) || major >= 8 37 | } 38 | 39 | android { 40 | if (supportsNamespace()) { 41 | namespace "com.stroketext" 42 | 43 | sourceSets { 44 | main { 45 | manifest.srcFile "src/main/AndroidManifestNew.xml" 46 | } 47 | } 48 | } 49 | 50 | compileSdkVersion getExtOrIntegerDefault("compileSdkVersion") 51 | 52 | defaultConfig { 53 | minSdkVersion getExtOrIntegerDefault("minSdkVersion") 54 | targetSdkVersion getExtOrIntegerDefault("targetSdkVersion") 55 | 56 | } 57 | 58 | buildTypes { 59 | release { 60 | minifyEnabled false 61 | } 62 | } 63 | 64 | lintOptions { 65 | disable "GradleCompatible" 66 | } 67 | 68 | compileOptions { 69 | sourceCompatibility JavaVersion.VERSION_1_8 70 | targetCompatibility JavaVersion.VERSION_1_8 71 | } 72 | } 73 | 74 | repositories { 75 | mavenCentral() 76 | google() 77 | } 78 | 79 | 80 | dependencies { 81 | // For < 0.71, this will be from the local maven repo 82 | // For > 0.71, this will be replaced by `com.facebook.react:react-android:$version` by react gradle plugin 83 | //noinspection GradleDynamicVersion 84 | implementation "com.facebook.react:react-native:+" 85 | } 86 | 87 | -------------------------------------------------------------------------------- /android/src/main/java/com/stroketext/StrokeTextViewManager.java: -------------------------------------------------------------------------------- 1 | package com.stroketext; 2 | 3 | import android.view.View; 4 | 5 | import com.facebook.react.uimanager.SimpleViewManager; 6 | import com.facebook.react.uimanager.ThemedReactContext; 7 | import com.facebook.react.uimanager.annotations.ReactProp; 8 | 9 | public class StrokeTextViewManager extends SimpleViewManager { 10 | public static final String REACT_CLASS = "StrokeTextView"; 11 | 12 | @Override 13 | public String getName() { 14 | return REACT_CLASS; 15 | } 16 | 17 | @Override 18 | public View createViewInstance(ThemedReactContext reactContext) { 19 | return new StrokeTextView(reactContext); 20 | } 21 | 22 | @ReactProp(name = "text") 23 | public void setText(StrokeTextView view, String text) { 24 | view.setText(text); 25 | } 26 | 27 | @ReactProp(name = "fontSize") 28 | public void setFontSize(StrokeTextView view, float fontSize) { 29 | view.setFontSize(fontSize); 30 | } 31 | 32 | @ReactProp(name = "color") 33 | public void setColor(StrokeTextView view, String color) { 34 | view.setTextColor(color); 35 | } 36 | 37 | @ReactProp(name = "strokeColor") 38 | public void setStrokeColor(StrokeTextView view, String strokeColor) { 39 | view.setStrokeColor(strokeColor); 40 | } 41 | 42 | @ReactProp(name = "strokeWidth") 43 | public void setStrokeWidth(StrokeTextView view, float strokeWidth) { 44 | view.setStrokeWidth(strokeWidth); 45 | } 46 | 47 | @ReactProp(name = "fontFamily") 48 | public void setFontFamily(StrokeTextView view, String fontFamily) { 49 | view.setFontFamily(fontFamily); 50 | } 51 | 52 | @ReactProp(name = "align") 53 | public void setTextAlignment(StrokeTextView view, String align) { 54 | view.setTextAlignment(align); 55 | } 56 | 57 | @ReactProp(name = "numberOfLines") 58 | public void setNumberOfLines(StrokeTextView view, int numberOfLines) { 59 | view.setNumberOfLines(numberOfLines); 60 | } 61 | 62 | @ReactProp(name = "ellipsis") 63 | public void setEllipsis(StrokeTextView view, boolean ellipsis) { 64 | view.setEllipsis(ellipsis); 65 | } 66 | 67 | @ReactProp(name = "width") 68 | public void setWidth(StrokeTextView view, float width) { 69 | view.setCustomWidth(width); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # React Native Stroke/Outline Text 2 | 3 | [![npm version](https://badge.fury.io/js/@charmy.tech%2Freact-native-stroke-text.svg)](https://badge.fury.io/js/@charmy.tech%2Freact-native-stroke-text) 4 | 5 | Allows you to add stylish text with stroke effects to your mobile applications. It is perfect for creating visually 6 | appealing text elements with outline effects. 7 | 8 |

9 | 10 |

11 | 12 | ## Installation 13 | 14 | ```bash 15 | npm install @charmy.tech/react-native-stroke-text 16 | # or 17 | yarn add @charmy.tech/react-native-stroke-text 18 | ``` 19 | 20 | ## Android 21 | min ```compileSdkVersion``` is required to be ```34``` 22 | ## iOS 23 | Go to your ios folder and run: 24 | 25 | ``` 26 | pod install 27 | ``` 28 | 29 | ## Usage 30 | 31 | Here's a quick example to get you started with StrokeText: 32 | 33 | ```jsx 34 | import React from "react"; 35 | import { StrokeText } from "@charmy.tech/react-native-stroke-text"; 36 | import { View } from "react-native"; 37 | 38 | export default function Screen() { 39 | return ( 40 | 41 | 49 | 50 | ); 51 | } 52 | 53 | ``` 54 | 55 | ### Props 56 | 57 | The following table outlines the props available for the `StrokeText` component: 58 | 59 | | Prop | Type | Description | 60 | |-----------------|---------|-----------------------------------------------------------------| 61 | | `text` | string | The text content you want to display. | 62 | | `fontSize` | number | Size of the text font, defining how large the text will be. | 63 | | `color` | string | Color of the text, can use any valid color format. | 64 | | `strokeColor` | string | Color of the stroke (outline) around the text. | 65 | | `strokeWidth` | number | Width of the stroke, determining the thickness of the outline. | 66 | | `fontFamily` | string | Font family for the text, should match available project fonts. | 67 | | `align` | string | Text alignment (default: `center`) | 68 | | `numberOfLines` | number | Number of lines (default: `0`) | 69 | | `ellipsis` | boolean | Ellipsis (...) (default: `false`) | 70 | | `width` | number | Text width to enable ellipsis (default: `undefined`) | 71 | 72 | ## Ellipsis 73 | 74 | ```jsx 75 | 87 | 88 | ``` 89 | 90 |

91 | 92 |

93 | 94 | ## Custom Font 95 | 96 | ### Bare React Native 97 | 98 | Create a `react-native.config.js` file in the root directory 99 | 100 | ```javascript 101 | module.exports = { 102 | project: { 103 | ios: {}, 104 | android: {}, 105 | }, 106 | assets: ['/assets/fonts'], // or './src/assets/fonts' 107 | }; 108 | ``` 109 | 110 | ### Expo ([expo-font](https://docs.expo.dev/versions/latest/sdk/font/)) 111 | 112 | ```tsx 113 | import { useFonts } from "expo-font"; 114 | import { Dosis_400Regular } from "@expo-google-fonts/dosis"; 115 | 116 | 117 | const [fontsLoaded, fontError] = useFonts({ 118 | Danfo: require("./src/assets/fonts/Danfo-Regular.ttf"), 119 | "Dosis-Regular": Dosis_400Regular, 120 | }); 121 | ``` 122 | 123 | ## Contributing 124 | 125 | We welcome contributions to improve this component. Feel free to submit issues and enhancement requests. 126 | 127 | ## License 128 | 129 | Please refer to the project's license for usage rights and limitations. 130 | -------------------------------------------------------------------------------- /ios/StrokeTextView.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import Foundation 3 | 4 | class StrokeTextView: RCTView { 5 | public var label: StrokedTextLabel 6 | weak var bridge: RCTBridge? 7 | 8 | private var fontCache: [String: UIFont] = [:] 9 | 10 | init(bridge: RCTBridge) { 11 | label = StrokedTextLabel() 12 | self.bridge = bridge 13 | super.init(frame: .zero) 14 | label.textColor = colorStringToUIColor(colorString: color) 15 | label.outlineColor = colorStringToUIColor(colorString: strokeColor) 16 | label.translatesAutoresizingMaskIntoConstraints = false 17 | self.addSubview(label) 18 | NSLayoutConstraint.activate([ 19 | label.centerXAnchor.constraint(equalTo: self.centerXAnchor), 20 | label.centerYAnchor.constraint(equalTo: self.centerYAnchor) 21 | ]) 22 | } 23 | 24 | override func layoutSubviews() { 25 | super.layoutSubviews() 26 | self.bridge?.uiManager.setSize(label.intrinsicContentSize, for: self) 27 | } 28 | 29 | required init?(coder aDecoder: NSCoder) { 30 | fatalError("init(coder:) has not been implemented") 31 | } 32 | 33 | @objc var width: NSNumber = 0 { 34 | didSet { 35 | if width != oldValue { 36 | self.label.customWidth = CGFloat(truncating: width) 37 | label.setNeedsDisplay() 38 | } 39 | } 40 | } 41 | 42 | @objc var text: String = "" { 43 | didSet { 44 | if text != oldValue { 45 | label.text = text 46 | label.setNeedsDisplay() 47 | } 48 | } 49 | } 50 | 51 | @objc var fontSize: NSNumber = 14 { 52 | didSet { 53 | if fontSize != oldValue { 54 | label.font = label.font.withSize(CGFloat(truncating: fontSize)) 55 | label.setNeedsDisplay() 56 | } 57 | } 58 | } 59 | 60 | @objc var color: String = "#000000" { 61 | didSet { 62 | if color != oldValue { 63 | label.textColor = colorStringToUIColor(colorString: color) 64 | label.setNeedsDisplay() 65 | } 66 | } 67 | } 68 | 69 | @objc var strokeColor: String = "#FFFFFF" { 70 | didSet { 71 | if strokeColor != oldValue { 72 | label.outlineColor = colorStringToUIColor(colorString: strokeColor) 73 | label.setNeedsDisplay() 74 | } 75 | } 76 | } 77 | 78 | @objc var strokeWidth: NSNumber = 1 { 79 | didSet { 80 | if strokeWidth != oldValue { 81 | label.outlineWidth = CGFloat(truncating: strokeWidth) 82 | label.setNeedsDisplay() 83 | } 84 | } 85 | } 86 | 87 | @objc var fontFamily: String = "Helvetica" { 88 | didSet { 89 | if fontFamily != oldValue { 90 | let cacheKey = "\(fontFamily)-\(fontSize)" 91 | if let cachedFont = fontCache[cacheKey] { 92 | label.font = cachedFont 93 | } else { 94 | let newFont: UIFont? 95 | if let reactFont = RCTFont.update(nil, withFamily: fontFamily){ 96 | newFont = reactFont.withSize(CGFloat(truncating: fontSize)) 97 | } else { 98 | newFont = UIFont(name: fontFamily, size: CGFloat(truncating: fontSize)) 99 | } 100 | if let validFont = newFont { 101 | fontCache[cacheKey] = validFont 102 | label.font = validFont 103 | } 104 | } 105 | 106 | label.setNeedsDisplay() 107 | } 108 | } 109 | } 110 | 111 | @objc var align: String = "center" { 112 | didSet { 113 | if align != oldValue { 114 | if align == "left" { 115 | label.align = .left 116 | } else if align == "right" { 117 | label.align = .right 118 | } else { 119 | label.align = .center 120 | } 121 | 122 | label.setNeedsDisplay() 123 | } 124 | } 125 | } 126 | 127 | @objc var ellipsis: Bool = false { 128 | didSet { 129 | if ellipsis != oldValue { 130 | label.ellipsis = ellipsis 131 | label.setNeedsDisplay() 132 | } 133 | } 134 | } 135 | 136 | @objc var numberOfLines: NSNumber = 0 { 137 | didSet { 138 | if numberOfLines != oldValue { 139 | label.numberOfLines = Int(truncating: numberOfLines) 140 | label.setNeedsDisplay() 141 | } 142 | } 143 | } 144 | 145 | private func colorStringToUIColor(colorString: String) -> UIColor { 146 | var string = colorString.trimmingCharacters(in: .whitespacesAndNewlines).uppercased() 147 | 148 | if string.hasPrefix("#") { 149 | if string.count == 4 { 150 | string = "#" + string.dropFirst().map { "\($0)\($0)" }.joined() 151 | } 152 | if string.count == 7 { 153 | var rgbValue: UInt64 = 0 154 | Scanner(string: String(string.dropFirst())).scanHexInt64(&rgbValue) 155 | return UIColor( 156 | red: CGFloat((rgbValue & 0xFF0000) >> 16) / 255.0, 157 | green: CGFloat((rgbValue & 0x00FF00) >> 8) / 255.0, 158 | blue: CGFloat(rgbValue & 0x0000FF) / 255.0, 159 | alpha: 1.0 160 | ) 161 | } 162 | } else if string.hasPrefix("RGBA") { 163 | let components = string.dropFirst(5).dropLast(1).split(separator: ",").map { CGFloat(Double($0.trimmingCharacters(in: .whitespaces)) ?? 0) } 164 | if components.count == 4 { 165 | return UIColor(red: components[0] / 255.0, green: components[1] / 255.0, blue: components[2] / 255.0, alpha: components[3]) 166 | } 167 | } else if string.hasPrefix("RGB") { 168 | let components = string.dropFirst(4).dropLast(1).split(separator: ",").map { CGFloat(Double($0.trimmingCharacters(in: .whitespaces)) ?? 0) } 169 | if components.count == 3 { 170 | return UIColor(red: components[0] / 255.0, green: components[1] / 255.0, blue: components[2] / 255.0, alpha: 1.0) 171 | } 172 | } 173 | 174 | return UIColor.gray 175 | } 176 | } 177 | -------------------------------------------------------------------------------- /android/src/main/java/com/stroketext/StrokeTextView.java: -------------------------------------------------------------------------------- 1 | package com.stroketext; 2 | 3 | import android.graphics.Canvas; 4 | import android.graphics.Color; 5 | import android.graphics.Paint; 6 | import android.graphics.Typeface; 7 | import android.text.Layout; 8 | import android.text.StaticLayout; 9 | import android.text.TextPaint; 10 | import android.text.TextUtils; 11 | import android.util.TypedValue; 12 | import android.view.View; 13 | 14 | import com.facebook.react.bridge.ReactContext; 15 | import com.facebook.react.uimanager.ThemedReactContext; 16 | import com.facebook.react.uimanager.UIManagerModule; 17 | 18 | import java.util.HashMap; 19 | import java.util.Map; 20 | 21 | class StrokeTextView extends View { 22 | private String text = ""; 23 | private float fontSize = 14; 24 | private int textColor = 0xFF000000; 25 | private int strokeColor = 0xFFFFFFFF; 26 | private float strokeWidth = 1; 27 | private String fontFamily = "sans-serif"; 28 | private int numberOfLines = 0; 29 | private boolean ellipsis = false; 30 | private final TextPaint textPaint; 31 | private final TextPaint strokePaint; 32 | private Layout.Alignment alignment = Layout.Alignment.ALIGN_CENTER; 33 | private StaticLayout textLayout; 34 | private StaticLayout strokeLayout; 35 | private boolean layoutDirty = true; 36 | private float customWidth = 0; 37 | private final Map fontCache = new HashMap<>(); 38 | 39 | public StrokeTextView(ThemedReactContext context) { 40 | super(context); 41 | textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); 42 | strokePaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); 43 | } 44 | 45 | private void ensureLayout() { 46 | if (layoutDirty) { 47 | Typeface typeface = getFont(fontFamily); 48 | textPaint.setTypeface(typeface); 49 | textPaint.setTextSize(fontSize); 50 | textPaint.setColor(textColor); 51 | strokePaint.setStyle(Paint.Style.STROKE); 52 | strokePaint.setStrokeJoin(Paint.Join.ROUND); 53 | strokePaint.setStrokeCap(Paint.Cap.ROUND); 54 | strokePaint.setStrokeWidth(strokeWidth); 55 | strokePaint.setColor(strokeColor); 56 | strokePaint.setTypeface(typeface); 57 | strokePaint.setTextSize(fontSize); 58 | 59 | int width = (int) getCanvasWidth(); 60 | CharSequence ellipsizedText = ellipsis ? TextUtils.ellipsize(text, textPaint, width, TextUtils.TruncateAt.END) : text; 61 | textLayout = new StaticLayout(ellipsizedText, textPaint, width, alignment, 1.0f, 0.0f, false); 62 | if (numberOfLines > 0 && numberOfLines < textLayout.getLineCount()) { 63 | int lineEnd = textLayout.getLineEnd(numberOfLines - 1); 64 | ellipsizedText = ellipsizedText.subSequence(0, lineEnd); 65 | textLayout = new StaticLayout(ellipsizedText, textPaint, width, alignment, 1.0f, 0.0f, false); 66 | } 67 | strokeLayout = new StaticLayout(ellipsizedText, strokePaint, width, alignment, 1.0f, 0.0f, false); 68 | 69 | layoutDirty = false; 70 | } 71 | } 72 | 73 | @Override 74 | protected void onSizeChanged(int w, int h, int oldw, int oldh) { 75 | layoutDirty = true; 76 | ensureLayout(); 77 | } 78 | 79 | private float getCanvasWidth() { 80 | if (customWidth > 0) { 81 | return getScaledSize(customWidth); 82 | } 83 | 84 | String[] lines = text.split("\n"); 85 | float maxLineWidth = 0; 86 | for (String line : lines) { 87 | float lineWidth = textPaint.measureText(line); 88 | if (lineWidth > maxLineWidth) { 89 | maxLineWidth = lineWidth; 90 | } 91 | } 92 | 93 | maxLineWidth += getScaledSize(strokeWidth) / 2; 94 | return maxLineWidth; 95 | } 96 | 97 | @Override 98 | protected void onDraw(Canvas canvas) { 99 | super.onDraw(canvas); 100 | ensureLayout(); 101 | strokeLayout.draw(canvas); 102 | textLayout.draw(canvas); 103 | updateSize(textLayout.getWidth(), textLayout.getHeight()); 104 | } 105 | 106 | private float getScaledSize(float size) { 107 | return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, size, getResources().getDisplayMetrics()); 108 | } 109 | 110 | private void updateSize(int width, int height) { 111 | ReactContext reactContext = (ReactContext) getContext(); 112 | reactContext.runOnNativeModulesQueueThread( 113 | new Runnable() { 114 | @Override 115 | public void run() { 116 | UIManagerModule uiManager = reactContext.getNativeModule(UIManagerModule.class); 117 | if (uiManager != null) { 118 | uiManager.updateNodeSize(getId(), width, height); 119 | } 120 | } 121 | }); 122 | } 123 | 124 | public void setText(String text) { 125 | if (!this.text.equals(text)) { 126 | this.text = text; 127 | layoutDirty = true; 128 | invalidate(); 129 | } 130 | } 131 | 132 | public void setFontSize(float fontSize) { 133 | float scaledFontSize = getScaledSize(fontSize); 134 | if (this.fontSize != scaledFontSize) { 135 | this.fontSize = scaledFontSize; 136 | layoutDirty = true; 137 | invalidate(); 138 | } 139 | } 140 | 141 | public void setTextColor(String color) { 142 | int parsedColor = parseColor(color); 143 | if (this.textColor != parsedColor) { 144 | this.textColor = parsedColor; 145 | layoutDirty = true; 146 | invalidate(); 147 | } 148 | } 149 | 150 | public void setStrokeColor(String color) { 151 | int parsedColor = parseColor(color); 152 | if (this.strokeColor != parsedColor) { 153 | this.strokeColor = parsedColor; 154 | layoutDirty = true; 155 | invalidate(); 156 | } 157 | } 158 | 159 | public void setStrokeWidth(float strokeWidth) { 160 | float scaledStrokeWidth = getScaledSize(strokeWidth); 161 | if (this.strokeWidth != scaledStrokeWidth) { 162 | this.strokeWidth = scaledStrokeWidth; 163 | layoutDirty = true; 164 | invalidate(); 165 | } 166 | } 167 | 168 | public void setFontFamily(String fontFamily) { 169 | if (!this.fontFamily.equals(fontFamily)) { 170 | this.fontFamily = fontFamily; 171 | layoutDirty = true; 172 | invalidate(); 173 | } 174 | } 175 | 176 | public void setTextAlignment(String alignment) { 177 | Layout.Alignment newAlignment; 178 | if ("left".equals(alignment)) { 179 | newAlignment = Layout.Alignment.ALIGN_NORMAL; 180 | } else if ("right".equals(alignment)) { 181 | newAlignment = Layout.Alignment.ALIGN_OPPOSITE; 182 | } else if ("center".equals(alignment)) { 183 | newAlignment = Layout.Alignment.ALIGN_CENTER; 184 | } else { 185 | newAlignment = this.alignment; 186 | } 187 | if (this.alignment != newAlignment) { 188 | this.alignment = newAlignment; 189 | layoutDirty = true; 190 | invalidate(); 191 | } 192 | } 193 | 194 | public void setNumberOfLines(int numberOfLines) { 195 | if (this.numberOfLines != numberOfLines) { 196 | this.numberOfLines = numberOfLines; 197 | layoutDirty = true; 198 | invalidate(); 199 | } 200 | } 201 | 202 | public void setEllipsis(boolean ellipsis) { 203 | if (this.ellipsis != ellipsis) { 204 | this.ellipsis = ellipsis; 205 | layoutDirty = true; 206 | invalidate(); 207 | } 208 | } 209 | 210 | public void setCustomWidth(float width) { 211 | if (!(this.customWidth == width)) { 212 | this.customWidth = width; 213 | layoutDirty = true; 214 | invalidate(); 215 | } 216 | } 217 | 218 | private int parseColor(String color) { 219 | if (color.startsWith("#")) { 220 | return Color.parseColor(color); 221 | } else if (color.startsWith("rgb")) { 222 | return parseRgbColor(color); 223 | } 224 | 225 | return 0xFF000000; 226 | } 227 | 228 | private int parseRgbColor(String color) { 229 | String[] parts = color.replaceAll("[rgba()\\s]", "").split(","); 230 | int r = Integer.parseInt(parts[0]); 231 | int g = Integer.parseInt(parts[1]); 232 | int b = Integer.parseInt(parts[2]); 233 | int a = parts.length > 3 ? (int) (Float.parseFloat(parts[3]) * 255) : 255; 234 | return Color.argb(a, r, g, b); 235 | } 236 | 237 | private Typeface getFont(String fontFamily) { 238 | if (fontCache.containsKey(fontFamily)) { 239 | return fontCache.get(fontFamily); 240 | } else { 241 | Typeface typeface = FontUtil.getFont(getContext(), fontFamily); 242 | fontCache.put(fontFamily, typeface); 243 | return typeface; 244 | } 245 | } 246 | } 247 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | "@ampproject/remapping@^2.2.0": 6 | version "2.2.1" 7 | resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.2.1.tgz#99e8e11851128b8702cd57c33684f1d0f260b630" 8 | integrity sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg== 9 | dependencies: 10 | "@jridgewell/gen-mapping" "^0.3.0" 11 | "@jridgewell/trace-mapping" "^0.3.9" 12 | 13 | "@babel/code-frame@^7.22.13", "@babel/code-frame@^7.23.5": 14 | version "7.23.5" 15 | resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.23.5.tgz#9009b69a8c602293476ad598ff53e4562e15c244" 16 | integrity sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA== 17 | dependencies: 18 | "@babel/highlight" "^7.23.4" 19 | chalk "^2.4.2" 20 | 21 | "@babel/compat-data@^7.23.5": 22 | version "7.23.5" 23 | resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.23.5.tgz#ffb878728bb6bdcb6f4510aa51b1be9afb8cfd98" 24 | integrity sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw== 25 | 26 | "@babel/core@^7.21.3": 27 | version "7.23.7" 28 | resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.23.7.tgz#4d8016e06a14b5f92530a13ed0561730b5c6483f" 29 | integrity sha512-+UpDgowcmqe36d4NwqvKsyPMlOLNGMsfMmQ5WGCu+siCe3t3dfe9njrzGfdN4qq+bcNUt0+Vw6haRxBOycs4dw== 30 | dependencies: 31 | "@ampproject/remapping" "^2.2.0" 32 | "@babel/code-frame" "^7.23.5" 33 | "@babel/generator" "^7.23.6" 34 | "@babel/helper-compilation-targets" "^7.23.6" 35 | "@babel/helper-module-transforms" "^7.23.3" 36 | "@babel/helpers" "^7.23.7" 37 | "@babel/parser" "^7.23.6" 38 | "@babel/template" "^7.22.15" 39 | "@babel/traverse" "^7.23.7" 40 | "@babel/types" "^7.23.6" 41 | convert-source-map "^2.0.0" 42 | debug "^4.1.0" 43 | gensync "^1.0.0-beta.2" 44 | json5 "^2.2.3" 45 | semver "^6.3.1" 46 | 47 | "@babel/generator@^7.23.6": 48 | version "7.23.6" 49 | resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.23.6.tgz#9e1fca4811c77a10580d17d26b57b036133f3c2e" 50 | integrity sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw== 51 | dependencies: 52 | "@babel/types" "^7.23.6" 53 | "@jridgewell/gen-mapping" "^0.3.2" 54 | "@jridgewell/trace-mapping" "^0.3.17" 55 | jsesc "^2.5.1" 56 | 57 | "@babel/helper-compilation-targets@^7.23.6": 58 | version "7.23.6" 59 | resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.23.6.tgz#4d79069b16cbcf1461289eccfbbd81501ae39991" 60 | integrity sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ== 61 | dependencies: 62 | "@babel/compat-data" "^7.23.5" 63 | "@babel/helper-validator-option" "^7.23.5" 64 | browserslist "^4.22.2" 65 | lru-cache "^5.1.1" 66 | semver "^6.3.1" 67 | 68 | "@babel/helper-environment-visitor@^7.22.20": 69 | version "7.22.20" 70 | resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz#96159db61d34a29dba454c959f5ae4a649ba9167" 71 | integrity sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA== 72 | 73 | "@babel/helper-function-name@^7.23.0": 74 | version "7.23.0" 75 | resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz#1f9a3cdbd5b2698a670c30d2735f9af95ed52759" 76 | integrity sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw== 77 | dependencies: 78 | "@babel/template" "^7.22.15" 79 | "@babel/types" "^7.23.0" 80 | 81 | "@babel/helper-hoist-variables@^7.22.5": 82 | version "7.22.5" 83 | resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz#c01a007dac05c085914e8fb652b339db50d823bb" 84 | integrity sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw== 85 | dependencies: 86 | "@babel/types" "^7.22.5" 87 | 88 | "@babel/helper-module-imports@^7.22.15": 89 | version "7.22.15" 90 | resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz#16146307acdc40cc00c3b2c647713076464bdbf0" 91 | integrity sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w== 92 | dependencies: 93 | "@babel/types" "^7.22.15" 94 | 95 | "@babel/helper-module-transforms@^7.23.3": 96 | version "7.23.3" 97 | resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz#d7d12c3c5d30af5b3c0fcab2a6d5217773e2d0f1" 98 | integrity sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ== 99 | dependencies: 100 | "@babel/helper-environment-visitor" "^7.22.20" 101 | "@babel/helper-module-imports" "^7.22.15" 102 | "@babel/helper-simple-access" "^7.22.5" 103 | "@babel/helper-split-export-declaration" "^7.22.6" 104 | "@babel/helper-validator-identifier" "^7.22.20" 105 | 106 | "@babel/helper-simple-access@^7.22.5": 107 | version "7.22.5" 108 | resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz#4938357dc7d782b80ed6dbb03a0fba3d22b1d5de" 109 | integrity sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w== 110 | dependencies: 111 | "@babel/types" "^7.22.5" 112 | 113 | "@babel/helper-split-export-declaration@^7.22.6": 114 | version "7.22.6" 115 | resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz#322c61b7310c0997fe4c323955667f18fcefb91c" 116 | integrity sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g== 117 | dependencies: 118 | "@babel/types" "^7.22.5" 119 | 120 | "@babel/helper-string-parser@^7.23.4": 121 | version "7.23.4" 122 | resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz#9478c707febcbbe1ddb38a3d91a2e054ae622d83" 123 | integrity sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ== 124 | 125 | "@babel/helper-validator-identifier@^7.22.20": 126 | version "7.22.20" 127 | resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz#c4ae002c61d2879e724581d96665583dbc1dc0e0" 128 | integrity sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A== 129 | 130 | "@babel/helper-validator-option@^7.23.5": 131 | version "7.23.5" 132 | resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz#907a3fbd4523426285365d1206c423c4c5520307" 133 | integrity sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw== 134 | 135 | "@babel/helpers@^7.23.7": 136 | version "7.23.8" 137 | resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.23.8.tgz#fc6b2d65b16847fd50adddbd4232c76378959e34" 138 | integrity sha512-KDqYz4PiOWvDFrdHLPhKtCThtIcKVy6avWD2oG4GEvyQ+XDZwHD4YQd+H2vNMnq2rkdxsDkU82T+Vk8U/WXHRQ== 139 | dependencies: 140 | "@babel/template" "^7.22.15" 141 | "@babel/traverse" "^7.23.7" 142 | "@babel/types" "^7.23.6" 143 | 144 | "@babel/highlight@^7.23.4": 145 | version "7.23.4" 146 | resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.23.4.tgz#edaadf4d8232e1a961432db785091207ead0621b" 147 | integrity sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A== 148 | dependencies: 149 | "@babel/helper-validator-identifier" "^7.22.20" 150 | chalk "^2.4.2" 151 | js-tokens "^4.0.0" 152 | 153 | "@babel/parser@^7.22.15", "@babel/parser@^7.23.6": 154 | version "7.23.6" 155 | resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.23.6.tgz#ba1c9e512bda72a47e285ae42aff9d2a635a9e3b" 156 | integrity sha512-Z2uID7YJ7oNvAI20O9X0bblw7Qqs8Q2hFy0R9tAfnfLkp5MW0UH9eUvnDSnFwKZ0AvgS1ucqR4KzvVHgnke1VQ== 157 | 158 | "@babel/runtime@^7.21.0": 159 | version "7.23.8" 160 | resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.23.8.tgz#8ee6fe1ac47add7122902f257b8ddf55c898f650" 161 | integrity sha512-Y7KbAP984rn1VGMbGqKmBLio9V7y5Je9GvU4rQPCPinCyNfUcToxIXl06d59URp/F3LwinvODxab5N/G6qggkw== 162 | dependencies: 163 | regenerator-runtime "^0.14.0" 164 | 165 | "@babel/template@^7.22.15": 166 | version "7.22.15" 167 | resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.22.15.tgz#09576efc3830f0430f4548ef971dde1350ef2f38" 168 | integrity sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w== 169 | dependencies: 170 | "@babel/code-frame" "^7.22.13" 171 | "@babel/parser" "^7.22.15" 172 | "@babel/types" "^7.22.15" 173 | 174 | "@babel/traverse@^7.23.7": 175 | version "7.23.7" 176 | resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.23.7.tgz#9a7bf285c928cb99b5ead19c3b1ce5b310c9c305" 177 | integrity sha512-tY3mM8rH9jM0YHFGyfC0/xf+SB5eKUu7HPj7/k3fpi9dAlsMc5YbQvDi0Sh2QTPXqMhyaAtzAr807TIyfQrmyg== 178 | dependencies: 179 | "@babel/code-frame" "^7.23.5" 180 | "@babel/generator" "^7.23.6" 181 | "@babel/helper-environment-visitor" "^7.22.20" 182 | "@babel/helper-function-name" "^7.23.0" 183 | "@babel/helper-hoist-variables" "^7.22.5" 184 | "@babel/helper-split-export-declaration" "^7.22.6" 185 | "@babel/parser" "^7.23.6" 186 | "@babel/types" "^7.23.6" 187 | debug "^4.3.1" 188 | globals "^11.1.0" 189 | 190 | "@babel/types@^7.22.15", "@babel/types@^7.22.5", "@babel/types@^7.23.0", "@babel/types@^7.23.6": 191 | version "7.23.6" 192 | resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.23.6.tgz#be33fdb151e1f5a56877d704492c240fc71c7ccd" 193 | integrity sha512-+uarb83brBzPKN38NX1MkB6vb6+mwvR6amUulqAE7ccQw1pEl+bCia9TbdG1lsnFP7lZySvUn37CHyXQdfTwzg== 194 | dependencies: 195 | "@babel/helper-string-parser" "^7.23.4" 196 | "@babel/helper-validator-identifier" "^7.22.20" 197 | to-fast-properties "^2.0.0" 198 | 199 | "@jridgewell/gen-mapping@^0.3.0", "@jridgewell/gen-mapping@^0.3.2": 200 | version "0.3.3" 201 | resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz#7e02e6eb5df901aaedb08514203b096614024098" 202 | integrity sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ== 203 | dependencies: 204 | "@jridgewell/set-array" "^1.0.1" 205 | "@jridgewell/sourcemap-codec" "^1.4.10" 206 | "@jridgewell/trace-mapping" "^0.3.9" 207 | 208 | "@jridgewell/resolve-uri@^3.1.0": 209 | version "3.1.1" 210 | resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz#c08679063f279615a3326583ba3a90d1d82cc721" 211 | integrity sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA== 212 | 213 | "@jridgewell/set-array@^1.0.1": 214 | version "1.1.2" 215 | resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72" 216 | integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw== 217 | 218 | "@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14": 219 | version "1.4.15" 220 | resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32" 221 | integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== 222 | 223 | "@jridgewell/trace-mapping@^0.3.17", "@jridgewell/trace-mapping@^0.3.9": 224 | version "0.3.21" 225 | resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.21.tgz#5dc1df7b3dc4a6209e503a924e1ca56097a2bb15" 226 | integrity sha512-SRfKmRe1KvYnxjEMtxEr+J4HIeMX5YBg/qhRHpxEIGjhX1rshcHlnFUE9K0GazhVKWM7B+nARSkV8LuvJdJ5/g== 227 | dependencies: 228 | "@jridgewell/resolve-uri" "^3.1.0" 229 | "@jridgewell/sourcemap-codec" "^1.4.14" 230 | 231 | "@types/node@^18.15.3": 232 | version "18.19.8" 233 | resolved "https://registry.yarnpkg.com/@types/node/-/node-18.19.8.tgz#c1e42b165e5a526caf1f010747e0522cb2c9c36a" 234 | integrity sha512-g1pZtPhsvGVTwmeVoexWZLTQaOvXwoSq//pTL0DHeNzUDrFnir4fgETdhjhIxjVnN+hKOuh98+E1eMLnUXstFg== 235 | dependencies: 236 | undici-types "~5.26.4" 237 | 238 | "@types/prop-types@*": 239 | version "15.7.11" 240 | resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.11.tgz#2596fb352ee96a1379c657734d4b913a613ad563" 241 | integrity sha512-ga8y9v9uyeiLdpKddhxYQkxNDrfvuPrlFb0N1qnZZByvcElJaXthF1UhvCh9TLWJBEHeNtdnbysW7Y6Uq8CVng== 242 | 243 | "@types/react-native@^0.71.3": 244 | version "0.71.13" 245 | resolved "https://registry.yarnpkg.com/@types/react-native/-/react-native-0.71.13.tgz#5d9f154aa7808fbff8d5ad399812e21f434fd7da" 246 | integrity sha512-UBYrqo7AFmQdABbx0yuygRkLpTUsoWaERgvFCU4OxsY8SnYmS+n6ACbWV+GuUY8eBIcbfgrbPAVuwTW/1fpRYQ== 247 | dependencies: 248 | "@types/react" "*" 249 | 250 | "@types/react@*", "@types/react@^18.0.28": 251 | version "18.2.48" 252 | resolved "https://registry.yarnpkg.com/@types/react/-/react-18.2.48.tgz#11df5664642d0bd879c1f58bc1d37205b064e8f1" 253 | integrity sha512-qboRCl6Ie70DQQG9hhNREz81jqC1cs9EVNcjQ1AU+jH6NFfSAhVVbrrY/+nSF+Bsk4AOwm9Qa61InvMCyV+H3w== 254 | dependencies: 255 | "@types/prop-types" "*" 256 | "@types/scheduler" "*" 257 | csstype "^3.0.2" 258 | 259 | "@types/scheduler@*": 260 | version "0.16.8" 261 | resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.8.tgz#ce5ace04cfeabe7ef87c0091e50752e36707deff" 262 | integrity sha512-WZLiwShhwLRmeV6zH+GkbOFT6Z6VklCItrDioxUnv+u4Ll+8vKeFySoFyK/0ctcRpOmwAicELfmys1sDc/Rw+A== 263 | 264 | ansi-styles@^3.2.1: 265 | version "3.2.1" 266 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" 267 | integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== 268 | dependencies: 269 | color-convert "^1.9.0" 270 | 271 | browserslist@^4.22.2: 272 | version "4.22.2" 273 | resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.22.2.tgz#704c4943072bd81ea18997f3bd2180e89c77874b" 274 | integrity sha512-0UgcrvQmBDvZHFGdYUehrCNIazki7/lUP3kkoi/r3YB2amZbFM9J43ZRkJTXBUZK4gmx56+Sqk9+Vs9mwZx9+A== 275 | dependencies: 276 | caniuse-lite "^1.0.30001565" 277 | electron-to-chromium "^1.4.601" 278 | node-releases "^2.0.14" 279 | update-browserslist-db "^1.0.13" 280 | 281 | caniuse-lite@^1.0.30001565: 282 | version "1.0.30001579" 283 | resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001579.tgz#45c065216110f46d6274311a4b3fcf6278e0852a" 284 | integrity sha512-u5AUVkixruKHJjw/pj9wISlcMpgFWzSrczLZbrqBSxukQixmg0SJ5sZTpvaFvxU0HoQKd4yoyAogyrAz9pzJnA== 285 | 286 | chalk@^2.4.2: 287 | version "2.4.2" 288 | resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" 289 | integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== 290 | dependencies: 291 | ansi-styles "^3.2.1" 292 | escape-string-regexp "^1.0.5" 293 | supports-color "^5.3.0" 294 | 295 | color-convert@^1.9.0: 296 | version "1.9.3" 297 | resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" 298 | integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== 299 | dependencies: 300 | color-name "1.1.3" 301 | 302 | color-name@1.1.3: 303 | version "1.1.3" 304 | resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" 305 | integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== 306 | 307 | convert-source-map@^2.0.0: 308 | version "2.0.0" 309 | resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a" 310 | integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== 311 | 312 | csstype@^3.0.2: 313 | version "3.1.3" 314 | resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.3.tgz#d80ff294d114fb0e6ac500fbf85b60137d7eff81" 315 | integrity sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw== 316 | 317 | debug@^4.1.0, debug@^4.3.1: 318 | version "4.3.4" 319 | resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" 320 | integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== 321 | dependencies: 322 | ms "2.1.2" 323 | 324 | electron-to-chromium@^1.4.601: 325 | version "1.4.638" 326 | resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.638.tgz#5564b750c2ceb64c0d2ef5a22b0748f63b66e0a3" 327 | integrity sha512-gpmbAG2LbfPKcDaL5m9IKutKjUx4ZRkvGNkgL/8nKqxkXsBVYykVULboWlqCrHsh3razucgDJDuKoWJmGPdItA== 328 | 329 | escalade@^3.1.1: 330 | version "3.1.1" 331 | resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" 332 | integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== 333 | 334 | escape-string-regexp@^1.0.5: 335 | version "1.0.5" 336 | resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" 337 | integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== 338 | 339 | gensync@^1.0.0-beta.2: 340 | version "1.0.0-beta.2" 341 | resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" 342 | integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== 343 | 344 | globals@^11.1.0: 345 | version "11.12.0" 346 | resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" 347 | integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== 348 | 349 | has-flag@^3.0.0: 350 | version "3.0.0" 351 | resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" 352 | integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== 353 | 354 | js-tokens@^4.0.0: 355 | version "4.0.0" 356 | resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" 357 | integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== 358 | 359 | jsesc@^2.5.1: 360 | version "2.5.2" 361 | resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" 362 | integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== 363 | 364 | json5@^2.2.3: 365 | version "2.2.3" 366 | resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" 367 | integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== 368 | 369 | lru-cache@^5.1.1: 370 | version "5.1.1" 371 | resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" 372 | integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== 373 | dependencies: 374 | yallist "^3.0.2" 375 | 376 | ms@2.1.2: 377 | version "2.1.2" 378 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" 379 | integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== 380 | 381 | node-releases@^2.0.14: 382 | version "2.0.14" 383 | resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.14.tgz#2ffb053bceb8b2be8495ece1ab6ce600c4461b0b" 384 | integrity sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw== 385 | 386 | picocolors@^1.0.0: 387 | version "1.0.0" 388 | resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" 389 | integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== 390 | 391 | prettier@^2.8.5: 392 | version "2.8.8" 393 | resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.8.tgz#e8c5d7e98a4305ffe3de2e1fc4aca1a71c28b1da" 394 | integrity sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q== 395 | 396 | regenerator-runtime@^0.14.0: 397 | version "0.14.1" 398 | resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz#356ade10263f685dda125100cd862c1db895327f" 399 | integrity sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw== 400 | 401 | semver@^6.3.1: 402 | version "6.3.1" 403 | resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" 404 | integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== 405 | 406 | supports-color@^5.3.0: 407 | version "5.5.0" 408 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" 409 | integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== 410 | dependencies: 411 | has-flag "^3.0.0" 412 | 413 | to-fast-properties@^2.0.0: 414 | version "2.0.0" 415 | resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" 416 | integrity sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog== 417 | 418 | typescript@^5.0.2: 419 | version "5.3.3" 420 | resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.3.3.tgz#b3ce6ba258e72e6305ba66f5c9b452aaee3ffe37" 421 | integrity sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw== 422 | 423 | undici-types@~5.26.4: 424 | version "5.26.5" 425 | resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617" 426 | integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA== 427 | 428 | update-browserslist-db@^1.0.13: 429 | version "1.0.13" 430 | resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz#3c5e4f5c083661bd38ef64b6328c26ed6c8248c4" 431 | integrity sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg== 432 | dependencies: 433 | escalade "^3.1.1" 434 | picocolors "^1.0.0" 435 | 436 | yallist@^3.0.2: 437 | version "3.1.1" 438 | resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" 439 | integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== 440 | --------------------------------------------------------------------------------