diff --git a/.changeset/config.json b/.changeset/config.json index e992182..0628006 100644 --- a/.changeset/config.json +++ b/.changeset/config.json @@ -8,7 +8,7 @@ "baseBranch": "main", "updateInternalDependencies": "patch", "ignore": [ - "@oktaytest/native", + "@oktaytest/react-native-app", "@oktaytest/next", "@oktaytest/nuxt-app", "@oktaytest/rollup-react", diff --git a/apps/native/babel.config.js b/apps/native/babel.config.js deleted file mode 100644 index 73ebf58..0000000 --- a/apps/native/babel.config.js +++ /dev/null @@ -1,6 +0,0 @@ -module.exports = function (api) { - api.cache(true); - return { - presets: ["babel-preset-expo"], - }; -}; diff --git a/apps/native/.expo-shared/assets.json b/apps/react-native-app/.expo-shared/assets.json similarity index 100% rename from apps/native/.expo-shared/assets.json rename to apps/react-native-app/.expo-shared/assets.json diff --git a/apps/native/.gitignore b/apps/react-native-app/.gitignore similarity index 100% rename from apps/native/.gitignore rename to apps/react-native-app/.gitignore diff --git a/apps/native/App.tsx b/apps/react-native-app/App.tsx similarity index 91% rename from apps/native/App.tsx rename to apps/react-native-app/App.tsx index 58b9d7d..78d4a0d 100644 --- a/apps/native/App.tsx +++ b/apps/react-native-app/App.tsx @@ -1,6 +1,6 @@ import React from "react"; import { StyleSheet, View } from "react-native"; -import { Iconify } from "@oktaytest/ui"; +import { Iconify } from "@oktaytest/native"; export default function App() { return ( diff --git a/apps/native/README.md b/apps/react-native-app/README.md similarity index 100% rename from apps/native/README.md rename to apps/react-native-app/README.md diff --git a/apps/native/app.json b/apps/react-native-app/app.json similarity index 100% rename from apps/native/app.json rename to apps/react-native-app/app.json diff --git a/apps/native/assets/adaptive-icon.png b/apps/react-native-app/assets/adaptive-icon.png similarity index 100% rename from apps/native/assets/adaptive-icon.png rename to apps/react-native-app/assets/adaptive-icon.png diff --git a/apps/native/assets/favicon.png b/apps/react-native-app/assets/favicon.png similarity index 100% rename from apps/native/assets/favicon.png rename to apps/react-native-app/assets/favicon.png diff --git a/apps/native/assets/icon.png b/apps/react-native-app/assets/icon.png similarity index 100% rename from apps/native/assets/icon.png rename to apps/react-native-app/assets/icon.png diff --git a/apps/native/assets/splash.png b/apps/react-native-app/assets/splash.png similarity index 100% rename from apps/native/assets/splash.png rename to apps/react-native-app/assets/splash.png diff --git a/apps/react-native-app/babel.config.js b/apps/react-native-app/babel.config.js new file mode 100644 index 0000000..82a51cc --- /dev/null +++ b/apps/react-native-app/babel.config.js @@ -0,0 +1,23 @@ +module.exports = function (api) { + api.cache(true); + return { + presets: ["babel-preset-expo"], + plugins: [ + [ + "@oktaytest/babel-plugin", + { + icons: [ + "mdi:home", + "mdi:account", + "mdi:account-badge-outline", + "feather:activity", + "feather:alert-circle", + "logos:active-campaign", + "logos:apache-superset-icon", + ], + outputFileName: "react-native-app", + }, + ], + ], + }; +}; diff --git a/apps/native/index.js b/apps/react-native-app/index.js similarity index 100% rename from apps/native/index.js rename to apps/react-native-app/index.js diff --git a/apps/native/metro.config.js b/apps/react-native-app/metro.config.js similarity index 96% rename from apps/native/metro.config.js rename to apps/react-native-app/metro.config.js index de295f8..bb4c14e 100644 --- a/apps/native/metro.config.js +++ b/apps/react-native-app/metro.config.js @@ -19,7 +19,7 @@ const configWithIconify = withIconify(config, { "logos:active-campaign", "logos:apache-superset-icon", ], - outputFileName: "native", + outputFileName: "react-native-app", }); // 1. Watch all files within the monorepo diff --git a/apps/native/package.json b/apps/react-native-app/package.json similarity index 91% rename from apps/native/package.json rename to apps/react-native-app/package.json index a53e227..beb6780 100644 --- a/apps/native/package.json +++ b/apps/react-native-app/package.json @@ -1,5 +1,5 @@ { - "name": "@oktaytest/native", + "name": "@oktaytest/react-native-app", "version": "0.0.0", "private": true, "main": "index.js", @@ -12,7 +12,7 @@ }, "dependencies": { "@oktaytest/metro": "*", - "@oktaytest/ui": "*", + "@oktaytest/native": "*", "@oktaytest/webpack": "*", "@oktaytest/babel-plugin": "*", "expo": "^49.0.21", diff --git a/apps/native/tsconfig.json b/apps/react-native-app/tsconfig.json similarity index 100% rename from apps/native/tsconfig.json rename to apps/react-native-app/tsconfig.json diff --git a/apps/native/webpack.config.js b/apps/react-native-app/webpack.config.js similarity index 92% rename from apps/native/webpack.config.js rename to apps/react-native-app/webpack.config.js index b27a137..bc70a1c 100644 --- a/apps/native/webpack.config.js +++ b/apps/react-native-app/webpack.config.js @@ -15,7 +15,7 @@ module.exports = async function (env, argv) { "logos:active-campaign", "logos:apache-superset-icon", ], - outputFileName: "native-web", + outputFileName: "react-native-app", }) ); diff --git a/package.json b/package.json index 69d7aa9..471e838 100644 --- a/package.json +++ b/package.json @@ -1,4 +1,29 @@ { - "name": "monicon", - "version": "0.0.0" + "name": "react-native-iconify", + "private": true, + "workspaces": [ + "apps/*", + "packages/*" + ], + "files": [], + "scripts": { + "dev": "turbo run dev", + "build": "turbo run build", + "build:pkgs": "turbo run build --filter='./packages/*'", + "clean": "turbo run clean && rm -rf node_modules", + "format": "prettier --write \"**/*.{ts,tsx,js,jsx,json,md}\" --ignore-path .gitignore", + "changeset": "changeset", + "version": "changeset version", + "release": "yarn build:pkgs && changeset publish" + }, + "devDependencies": { + "@changesets/cli": "^2.27.9", + "prettier": "^3.1.1", + "turbo": "^2.1.3" + }, + "packageManager": "yarn@1.22.19", + "engines": { + "node": ">=18" + }, + "version": "0.0.119" } diff --git a/packages/core/package.json b/packages/core/package.json index 1c9585d..4eb1955 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -9,11 +9,13 @@ "exports": { ".": { "import": "./dist/index.mjs", - "require": "./dist/index.js" + "require": "./dist/index.js", + "types": "./dist/index.d.ts" }, "./constants": { "import": "./dist/constants.mjs", - "require": "./dist/constants.js" + "require": "./dist/constants.js", + "types": "./dist/constants.d.mts" } }, "publishConfig": { diff --git a/packages/native/.gitignore b/packages/native/.gitignore new file mode 100644 index 0000000..cf309c2 --- /dev/null +++ b/packages/native/.gitignore @@ -0,0 +1,28 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +node_modules +.pnp +.pnp.js + + +# misc +.DS_Store +*.pem + +# build +dist + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# local env files +.env.local +.env.development.local +.env.test.local +.env.production.local + +# turbo +.turbo \ No newline at end of file diff --git a/packages/native/CHANGELOG.md b/packages/native/CHANGELOG.md new file mode 100644 index 0000000..5a24960 --- /dev/null +++ b/packages/native/CHANGELOG.md @@ -0,0 +1,27 @@ +# @oktaytest/ui + +## 0.0.119 + +### Patch Changes + +- add svelte support +- Updated dependencies + - @oktaytest/core@0.0.119 + +## 0.0.118 + +### Patch Changes + +- add prepack scripts +- 47ee90f: add prepack scripts +- Updated dependencies +- Updated dependencies [47ee90f] + - @oktaytest/core@0.0.118 + +## 0.0.114 + +### Patch Changes + +- add vite and nuxt support +- Updated dependencies + - @oktaytest/core@0.0.114 diff --git a/packages/native/package.json b/packages/native/package.json new file mode 100644 index 0000000..85b674b --- /dev/null +++ b/packages/native/package.json @@ -0,0 +1,45 @@ +{ + "name": "@oktaytest/native", + "version": "0.0.119", + "main": "./dist/index.js", + "module": "./dist/index.mjs", + "types": "./dist/index.d.ts", + "files": [ + "dist" + ], + "publishConfig": { + "access": "public" + }, + "exports": { + ".": { + "import": "./dist/index.mjs", + "require": "./dist/index.js" + }, + "./iconify": { + "import": "./dist/iconify.mjs", + "require": "./dist/iconify.js" + } + }, + "scripts": { + "build": "tsup", + "dev": "tsup --watch", + "clean": "rm -rf dist", + "prepack": "yarn build" + }, + "devDependencies": { + "@oktaytest/typescript-config": "*", + "@types/react": "^18.2.46", + "@types/react-native": "^0.73.0", + "tsup": "^8.0.1", + "typescript": "^5.3.3" + }, + "dependencies": { + "html-react-parser": "^5.1.16", + "@oktaytest/core": "*" + }, + "peerDependencies": { + "react": ">=18.2.0", + "react-native": ">=0.63.0", + "react-native-svg": ">=13.2.0" + } +} diff --git a/packages/native/src/constants.ts b/packages/native/src/constants.ts new file mode 100644 index 0000000..dc04ecf --- /dev/null +++ b/packages/native/src/constants.ts @@ -0,0 +1,5 @@ +export const fallbackIcon = { + svg: ' ', + width: 32, + height: 32, +}; diff --git a/packages/native/src/iconify.tsx b/packages/native/src/iconify.tsx new file mode 100644 index 0000000..89be245 --- /dev/null +++ b/packages/native/src/iconify.tsx @@ -0,0 +1,95 @@ +import React, { useState, useEffect, ReactNode } from "react"; + +import { IconifyProps, RuntimeIcon, RuntimeIconifyProps } from "./types"; +import { setAttributes } from "./utils"; +import { fallbackIcon } from "./constants"; + +const isReactNative = async () => { + try { + if (typeof navigator === "undefined") return true; + + require("react-native"); + + return true; + } catch (error) { + return false; + } +}; + +const getIcon = (iconName: string) => + new Promise(async (resolve, reject) => { + try { + // todo: add error handling + // @ts-ignore + const iconsImport = await import("oktay"); + + const icons = iconsImport.default ?? iconsImport; + + let icon = icons[iconName]; + + if (!icon) { + console.warn( + `[Iconify] The icon "${iconName}" is missing from the configuration. To resolve this, ensure it is added to the 'icons' array within the Iconify plugin's configuration.` + ); + + icon = fallbackIcon; + } + + resolve(icon); + } catch (error) { + reject(error); + } + }); + +const nativeIcon = async (props: RuntimeIconifyProps) => { + const { SvgXml } = require("react-native-svg"); + + return ( + + ); +}; + +const webIcon = async (props: RuntimeIconifyProps) => { + // @ts-ignore + const parse = await import("html-react-parser"); + + return parse.default(props.icon.svg); +}; + +const getComponent = async (props: RuntimeIconifyProps) => { + const formatted = setAttributes(props); + + const isNative = await isReactNative(); + + if (isNative) return nativeIcon(formatted); + + return webIcon(formatted); +}; + +export const Iconify = (props: IconifyProps) => { + const [Component, setComponent] = useState(null); + + const renderIcon = async () => { + const icon = await getIcon(props.name); + + const component = await getComponent({ + ...props, + icon, + }); + + setComponent(component); + }; + + useEffect(() => { + renderIcon(); + }, [props]); + + return Component; +}; + +export default Iconify; diff --git a/packages/native/src/index.tsx b/packages/native/src/index.tsx new file mode 100644 index 0000000..9aa0657 --- /dev/null +++ b/packages/native/src/index.tsx @@ -0,0 +1,2 @@ +export { Iconify } from "./iconify"; +export { type IconifyProps } from "./types"; diff --git a/packages/native/src/types.ts b/packages/native/src/types.ts new file mode 100644 index 0000000..8bbbaac --- /dev/null +++ b/packages/native/src/types.ts @@ -0,0 +1,15 @@ +export interface IconifyProps { + name: string; + size?: number; + color?: string; +} + +export interface RuntimeIcon { + svg: string; + width: number; + height: number; +} + +export interface RuntimeIconifyProps extends IconifyProps { + icon: RuntimeIcon; +} diff --git a/packages/native/src/utils.ts b/packages/native/src/utils.ts new file mode 100644 index 0000000..e3c4b4c --- /dev/null +++ b/packages/native/src/utils.ts @@ -0,0 +1,30 @@ +import { RuntimeIconifyProps } from "./types"; + +export const setAttributes = ( + props: RuntimeIconifyProps +): RuntimeIconifyProps => { + const ratio = props.icon.width / props.icon.height; + + let svg = props.icon.svg; + + const height = props.size ? props.size : props.icon.height; + const width = props.size ? props.size * ratio : props.icon.width; + + svg = svg + .replace(/width="([^"]+)"/, `width="${width}"`) + .replace(/height="([^"]+)"/, `height="${height}"`); + + if (props.color) { + svg = svg.replace(/fill="([^"]+)"/, `fill="${props.color}"`); + } + + return { + ...props, + icon: { + ...props.icon, + svg, + height, + width, + }, + }; +}; diff --git a/packages/native/tsconfig.json b/packages/native/tsconfig.json new file mode 100644 index 0000000..a75b0c7 --- /dev/null +++ b/packages/native/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "@oktaytest/typescript-config/react-native-library", + "include": ["."], + "exclude": ["dist", "build", "node_modules"], + "compilerOptions": { + "strict": true + } +} diff --git a/packages/native/tsup.config.ts b/packages/native/tsup.config.ts new file mode 100644 index 0000000..952d05a --- /dev/null +++ b/packages/native/tsup.config.ts @@ -0,0 +1,13 @@ +import { defineConfig, Options } from "tsup"; + +export default defineConfig((options: Options) => ({ + entry: ["src/index.tsx", "src/iconify.tsx"], + banner: { + js: "'use client'", + }, + clean: true, + format: ["cjs", "esm"], + external: ["react", "oktay", "react-native"], + dts: true, + ...options, +})); diff --git a/turbo.json b/turbo.json index dbd8dc8..b2b75d2 100644 --- a/turbo.json +++ b/turbo.json @@ -11,17 +11,26 @@ "ui#build": { "dependsOn": ["core#build"] }, - - "babel-plugin#build": { + "native#build": { "dependsOn": ["core#build"] }, "vue#build": { "dependsOn": ["core#build"] }, - "metro#build": { + "vite#build": { "dependsOn": ["core#build"] }, - "vite#build": { + "nuxt#build": { + "dependsOn": ["vue#build"] + }, + "svelte#build": { + "dependsOn": ["vite#build"] + }, + + "babel-plugin#build": { + "dependsOn": ["core#build"] + }, + "metro#build": { "dependsOn": ["core#build"] }, "rollup#build": { @@ -36,19 +45,13 @@ "rspack#build": { "dependsOn": ["webpack#build"] }, - "nuxt#build": { - "dependsOn": ["vue#build"] - }, - "svelte#build": { - "dependsOn": ["vite#build"] - }, - "native#build": { + "react-native-app#build": { "dependsOn": [ "babel-plugin#build", "metro#build", "webpack#build", - "ui#build" + "native#build" ] }, "next#build": {