Skip to content

Commit

Permalink
Add <Icon /> component and icon prop to <Button /> (#43)
Browse files Browse the repository at this point in the history
* Update svg.d.ts

* Clean up

* PR feedback
  • Loading branch information
dgca authored Aug 19, 2024
1 parent 97eb592 commit adb79db
Show file tree
Hide file tree
Showing 15 changed files with 2,511 additions and 177 deletions.
2,254 changes: 2,154 additions & 100 deletions package-lock.json

Large diffs are not rendered by default.

22 changes: 20 additions & 2 deletions packages/mobile-app/app/(tabs)/ui.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,26 @@ export default function UiKit() {
padding: 10,
}}
>
<Button label="Medium button" />
<Button label="Small button" size="sm" />
{/* Solid */}
<Button label="Click me" />

{/* Solid with icon */}
<Button iconLeft="arrow-left-bottom" label="Click me" />

{/* Solid small */}
<Button label="Click me" size="sm" />

{/* Solid disabled */}
<Button iconLeft="arrow-left-bottom" label="Click me" disabled />

{/* Outline */}
<Button label="Click me" variant="outline" />

{/* Outline with icon */}
<Button iconLeft="arrow-left-bottom" label="Click me" variant="outline" />

{/* Outline small */}
<Button label="Click me" size="sm" variant="outline" />
</View>
);
}
106 changes: 56 additions & 50 deletions packages/mobile-app/metro.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,22 +9,6 @@ const path = require("path");
const projectRoot = __dirname;
const monorepoRoot = path.resolve(projectRoot, "../..");

const config = getDefaultConfig(projectRoot);

config.watchFolders = [monorepoRoot];

config.resolver.nodeModulesPaths = [
path.resolve(projectRoot, "node_modules"),
path.resolve(monorepoRoot, "node_modules"),
];

config.resolver.disableHierarchicalLookup = true;

config.transformer = {
...config.transformer,
unstable_allowRequireContext: true,
};

// Modules in our node_modules that are used and require React Native-specific overrides
// (whether because we need them in React Native, or because they're executed when code is required in @ironfish/sdk)
const shims = {
Expand Down Expand Up @@ -56,41 +40,63 @@ const emptyModules = new Set([
"sqlite3",
]);

config.resolver.resolveRequest = (context, moduleName, platform) => {
if (shims[moduleName]) {
return shims[moduleName];
}
module.exports = (() => {
const config = getDefaultConfig(projectRoot);
const { transformer, resolver } = config;

if (emptyModules.has(moduleName)) {
return {
type: "empty",
};
}
config.watchFolders = [monorepoRoot];

// Optionally, chain to the standard Metro resolver.
return context.resolveRequest(context, moduleName, platform);
};
config.resolver = {
...resolver,
nodeModulesPaths: [
path.resolve(projectRoot, "node_modules"),
path.resolve(monorepoRoot, "node_modules"),
],
disableHierarchicalLookup: true,
resolveRequest: (context, moduleName, platform) => {
if (shims[moduleName]) {
return shims[moduleName];
}

// Node.js built-in modules that are unused.
// These will only be replaced with empty modules if they can't be found in the project's node_modules.
// If the project includes a module with the same name, it will be used instead.
// Modules with slashes in the name need to go in emptyModules instead.
config.resolver.extraNodeModules = {
...config.resolver.extraNodeModules,
assert: config.resolver.emptyModulePath,
child_process: config.resolver.emptyModulePath,
crypto: config.resolver.emptyModulePath,
events: config.resolver.emptyModulePath,
fs: config.resolver.emptyModulePath,
http: config.resolver.emptyModulePath,
net: config.resolver.emptyModulePath,
os: config.resolver.emptyModulePath,
stream: config.resolver.emptyModulePath,
tls: config.resolver.emptyModulePath,
url: config.resolver.emptyModulePath,
util: config.resolver.emptyModulePath,
worker_threads: config.resolver.emptyModulePath,
v8: config.resolver.emptyModulePath,
};
if (emptyModules.has(moduleName)) {
return {
type: "empty",
};
}

// Optionally, chain to the standard Metro resolver.
return context.resolveRequest(context, moduleName, platform);
},
// Node.js built-in modules that are unused.
// These will only be replaced with empty modules if they can't be found in the project's node_modules.
// If the project includes a module with the same name, it will be used instead.
// Modules with slashes in the name need to go in emptyModules instead.
extraNodeModules: {
...resolver.extraNodeModules,
assert: resolver.emptyModulePath,
child_process: resolver.emptyModulePath,
crypto: resolver.emptyModulePath,
events: resolver.emptyModulePath,
fs: resolver.emptyModulePath,
http: resolver.emptyModulePath,
net: resolver.emptyModulePath,
os: resolver.emptyModulePath,
stream: resolver.emptyModulePath,
tls: resolver.emptyModulePath,
url: resolver.emptyModulePath,
util: resolver.emptyModulePath,
worker_threads: resolver.emptyModulePath,
v8: resolver.emptyModulePath,
},
assetExts: resolver.assetExts.filter((ext) => ext !== "svg"),
sourceExts: [...resolver.sourceExts, "svg"],
};

config.transformer = {
...transformer,
unstable_allowRequireContext: true,
babelTransformerPath: require.resolve("react-native-svg-transformer/expo"),
};

module.exports = config;
return config;
})();
5 changes: 4 additions & 1 deletion packages/mobile-app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,18 @@
"react-native": "0.74.3",
"react-native-safe-area-context": "4.10.8",
"react-native-screens": "3.32.0",
"react-native-svg": "15.2.0",
"zod": "^3.22.4"
},
"devDependencies": {
"@babel/core": "^7.20.0",
"@svgr/webpack": "^8.1.0",
"@types/react": "~18.2.79",
"eslint-config-expo": "^7.0.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-prettier": "^5.1.3",
"prettier": "^3.3.2"
"prettier": "^3.3.2",
"react-native-svg-transformer": "^1.5.0"
},
"private": true
}
1 change: 1 addition & 0 deletions packages/ui-kit/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/icons
1 change: 1 addition & 0 deletions packages/ui-kit/.storybook/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const config: StorybookConfig = {
"@storybook/addon-essentials",
"@chromatic-com/storybook",
"@storybook/addon-interactions",
"@newhighsco/storybook-addon-svgr",
],
framework: {
name: "@storybook/react-webpack5",
Expand Down
13 changes: 9 additions & 4 deletions packages/ui-kit/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@
"main": "dist/index.js",
"types": "dist/index.d.ts",
"scripts": {
"build": "tsc -p tsconfig.build.json",
"dev": "tsc -p tsconfig.build.json --watch",
"clean": "rimraf dist icons",
"build": "npm run clean && tsc -p tsconfig.build.json && npm run copy-icons",
"dev": "npm run clean && npm run copy-icons && tsc -p tsconfig.build.json --watch",
"storybook": "storybook dev -p 6006",
"build-storybook": "storybook build",
"copy-icons": "cpx 'src/components/Icon/**/*.svg' dist/components/Icon",
"typecheck": "tsc --noEmit"
},
"dependencies": {
Expand All @@ -20,23 +22,26 @@
},
"devDependencies": {
"@chromatic-com/storybook": "^1.6.1",
"@newhighsco/storybook-addon-svgr": "^2.0.24",
"@storybook/addon-essentials": "^8.2.9",
"@storybook/addon-interactions": "^8.2.9",
"@storybook/addon-links": "^8.2.9",
"@storybook/addon-onboarding": "^8.2.9",
"@storybook/addon-webpack5-compiler-swc": "^1.0.5",
"@storybook/blocks": "^8.2.9",
"@storybook/react-webpack5": "^8.2.9",
"@storybook/react": "^8.2.9",
"@storybook/react-webpack5": "^8.2.9",
"@storybook/test": "^8.2.9",
"@types/react": "~18.2.79",
"babel-loader": "^9.1.3",
"babel-plugin-react-native-web": "^0.19.12",
"eslint-plugin-storybook": "^0.8.0",
"cpx": "^1.5.0",
"eslint": "8.56.0",
"eslint-plugin-storybook": "^0.8.0",
"react": "18.2.0",
"react-dom": "18.2.0",
"react-native": "0.74.3",
"rimraf": "^6.0.1",
"storybook": "^8.2.9",
"typescript": "5.1.3"
}
Expand Down
51 changes: 46 additions & 5 deletions packages/ui-kit/src/components/Button/Button.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import React from "react";
import type { Meta, StoryObj } from "@storybook/react";
import { fn } from "@storybook/test";
import { Button } from "./Button";
import { Icon } from "../Icon/Icon";

// More on how to set up stories at: https://storybook.js.org/docs/writing-stories#default-export
const meta = {
title: "Example/Button",
title: "Components/Button",
component: Button,
parameters: {
// Optional parameter to center the component in the Canvas. More info: https://storybook.js.org/docs/configure/story-layout
Expand All @@ -15,6 +17,7 @@ const meta = {
// More on argTypes: https://storybook.js.org/docs/api/argtypes
argTypes: {
label: { control: "text" },
variant: { options: ["outline", "solid"] },
},
// Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked: https://storybook.js.org/docs/essentials/actions#action-args
args: { onPress: fn() },
Expand All @@ -23,15 +26,53 @@ const meta = {
export default meta;
type Story = StoryObj<typeof meta>;

export const Primary: Story = {
export const Solid: Story = {
args: {
label: "Medium button",
label: "Click me",
},
};

export const Secondary: Story = {
export const SolidWithIcon: Story = {
args: {
label: "Small button",
iconLeft: "arrow-left-bottom",
label: "Click me",
},
};

export const SolidSmall: Story = {
args: {
label: "Click me",
size: "sm",
},
};

export const SolidDisabled: Story = {
args: {
iconLeft: "arrow-left-bottom",
label: "Click me",
disabled: true,
},
};

export const Outline: Story = {
args: {
label: "Click me",
variant: "outline",
},
};

export const OutlineWithIcon: Story = {
args: {
iconLeft: "arrow-left-bottom",
label: "Click me",
variant: "outline",
},
};

export const OutlineSmall: Story = {
args: {
label: "Click me",
size: "sm",
variant: "outline",
},
};
Loading

0 comments on commit adb79db

Please sign in to comment.