Skip to content

Commit

Permalink
feat: add provisional components - avatar, breadcrumbs, dock, image
Browse files Browse the repository at this point in the history
  • Loading branch information
abelflopes committed Feb 26, 2024
1 parent c3d3a6b commit 7559e5f
Show file tree
Hide file tree
Showing 34 changed files with 649 additions and 1 deletion.
6 changes: 6 additions & 0 deletions packages/components/_provisional/.eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/** @type import("eslint").Linter.Config */
const config = {
extends: "../../../.eslintrc.js",
};

module.exports = config;
30 changes: 30 additions & 0 deletions packages/components/_provisional/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# RCK | Provisional Components

> :warning: **WARNING**: This component library is being updated frequently and it's currently unstable due to being in it's early stages, we advice you to use only in production environments only after version **2.0.0**.
Provisional components that are candidates for stable release.

### Installation

To integrate the this component into your React apps, you can install it using npm or yarn: `npm i --save @react-ck/provisional` or `yarn add @react-ck/provisional`.

You will also need to set up the manager, install it using npm or yarn: `npm i --save @react-ck/manager` or `yarn add @react-ck/manager`.

Wrap your app root with the theme provider and use this component:

```tsx
import { Manager } from "@react-ck/manager";
import { SomeComponent } from "@react-ck/provisional";

const myApp = () => (
<Manager>
<SomeComponent ... />
</Manager>
);
```

<!-- storybook-ignore -->

---

Check the documentation website - [react-ck.js.org](https://react-ck.js.org).
3 changes: 3 additions & 0 deletions packages/components/_provisional/babel.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module.exports = {
extends: "@react-ck/babel-config",
};
4 changes: 4 additions & 0 deletions packages/components/_provisional/declarations.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
declare module "*.module.scss" {
const content: Record<string, string>;
export default content;
}
2 changes: 2 additions & 0 deletions packages/components/_provisional/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// Hack for module resolution of non built packages
export * from "./src/index";
38 changes: 38 additions & 0 deletions packages/components/_provisional/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{
"name": "@react-ck/provisional",
"private": false,
"version": "1.0.0",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"files": [
"/dist"
],
"homepage": "https://github.com/abelflopes/react-ck/tree/master/packages/components/provisional#readme",
"repository": {
"type": "git",
"url": "git+https://github.com/abelflopes/react-ck.git"
},
"scripts": {
"build": "NODE_ENV=production webpack",
"lint:typescript": "tsc --noEmit",
"lint:code": "eslint . --ext ts,tsx --cache"
},
"devDependencies": {
"@react-ck/babel-config": "*",
"@react-ck/typescript-config": "*",
"@react-ck/webpack-config": "*",
"@types/react": "^18.2.33"
},
"peerDependencies": {
"react": "^18.2.0"
},
"dependencies": {
"@react-ck/button": "*",
"@react-ck/icon": "*",
"@react-ck/skeleton": "*",
"@react-ck/react-utils": "*",
"@react-ck/scss-utils": "*",
"@react-ck/text": "*",
"classnames": "*"
}
}
32 changes: 32 additions & 0 deletions packages/components/_provisional/src/avatar/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import React from "react";
import styles from "./styles/index.module.scss";
import classNames from "classnames";
import { Image } from "../image";

export interface AvatarProps extends React.HTMLAttributes<HTMLElement> {
name: string;
image?: string;
size?: "s" | "m" | "l";
}

export const Avatar = ({
name,
image,
size = "m",
className,
...otherProps
}: Readonly<AvatarProps>): React.ReactElement => {
const initials = name
.split(" ")
.map((i) => i[0])
.filter((_, k, arr) => k === 0 || k === arr.length - 1)
.join("")
.toUpperCase();

return (
<figure className={classNames(styles.root, styles[`size_${size}`], className)} {...otherProps}>
{!image && <figcaption>{initials}</figcaption>}
{image ? <Image alt={name} src={image} className={styles.image} /> : null}
</figure>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
@import "@react-ck/theme";

$avatar-sizes: (
s: get-spacing(2),
m: get-spacing(5),
l: get-spacing(8),
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
@import "@react-ck/theme";
@import "@react-ck/text";
@import "variables";

.root {
@include text-base;
@include text-type(soft);

position: relative;
display: flex;
align-items: center;
justify-content: center;
height: get-css-var(avatar, size);
width: get-css-var(avatar, size);
border-radius: 50%;
background-color: get-color(neutral-light-2);
overflow: hidden;
margin: 0;

@each $key, $value in $avatar-sizes {
&.size_#{$key} {
@include define-css-var(avatar, size, $value);
}
}

.image {
position: absolute;
top: 0;
left: 0;
height: 100%;
width: 100%;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import React from "react";
import styles from "./styles/item.module.scss";
import classNames from "classnames";

export interface BreadcrumbItemProps extends React.HTMLAttributes<HTMLElement> {
active?: boolean;
}

export const BreadcrumbItem = ({
active,
className,
children,
...otherProps
}: Readonly<BreadcrumbItemProps>): React.ReactElement => (
<span className={classNames(styles.root, active && styles.active, className)} {...otherProps}>
{children}
</span>
);
30 changes: 30 additions & 0 deletions packages/components/_provisional/src/breadcrumbs/Breadcrumbs.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import React, { useMemo } from "react";
import styles from "./styles/index.module.scss";
import classNames from "classnames";
import { Icon } from "@react-ck/icon";
import { BreadcrumbItem } from "./BreadcrumbItem";

interface BreadcrumbsProps extends Omit<React.HTMLAttributes<HTMLElement>, "children"> {
items: React.ReactNode[];
}

const Breadcrumbs = ({
items,
className,
...otherProps
}: Readonly<BreadcrumbsProps>): React.ReactElement => {
const computedItems = useMemo(
() => items.flatMap((i, k) => (k === 0 ? i : [<Icon key="_" name="chevron-right" />, i])),
[items],
);

return (
<nav className={classNames(styles.root, className)} {...otherProps}>
{computedItems}
</nav>
);
};

Breadcrumbs.Item = BreadcrumbItem;

export { Breadcrumbs, type BreadcrumbsProps };
1 change: 1 addition & 0 deletions packages/components/_provisional/src/breadcrumbs/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./Breadcrumbs";
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
@import "@react-ck/theme";

.root {
display: flex;
gap: get-spacing(1);
align-items: center;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
@import "@react-ck/theme";
@import "@react-ck/text";

.root {
@include text-base;

&.active {
@include text-variation(bold);
}
}
46 changes: 46 additions & 0 deletions packages/components/_provisional/src/dock/Dock.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import classNames from "classnames";
import styles from "./styles/dock.module.scss";
import React, { useMemo } from "react";
import { DockContext, type DockContextProps } from "./context";
import { DockItem } from "./DockItem";
import { DockMainItem } from "./DockMainItem";

interface DockProps extends React.HTMLAttributes<HTMLElement> {
header?: React.ReactNode;
footer?: React.ReactNode;
expanded?: boolean;
}

// TODO: add a11y https://react.dev/reference/react-dom/createPortal#rendering-a-dock-dialog-with-a-portal

const Dock = ({
header,
footer,
expanded = false,
children,
className,
...otherProps
}: Readonly<DockProps>): React.ReactNode => {
const contextValue = useMemo<DockContextProps>(
() => ({
expanded,
}),
[expanded],
);

return (
<DockContext.Provider value={contextValue}>
<nav className={classNames(styles.root, className)} {...otherProps}>
{header ? <div className={styles.header}>{header}</div> : null}
<div className={styles.content}>{children}</div>
{footer ? <div className={styles.footer}>{footer}</div> : null}
</nav>
</DockContext.Provider>
);
};

Dock.Item = DockItem;

Dock.MainItem = DockMainItem;

export { Dock };
33 changes: 33 additions & 0 deletions packages/components/_provisional/src/dock/DockItem.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import React, { useContext } from "react";
import { DockContext } from "./context";
import { Button, type ButtonProps } from "@react-ck/button";
import styles from "./styles/dock-item.module.scss";
import classNames from "classnames";

export interface DockItemProps extends Omit<ButtonProps, "children" | "skin" | "icon"> {
icon: NonNullable<React.ReactNode>;
label: string;
active: boolean;
}

export const DockItem = ({
icon,
label,
active,
className,
...otherProps
}: Readonly<DockItemProps>): React.ReactElement => {
const { expanded } = useContext(DockContext);

return (
<Button
className={classNames(styles.root, expanded && styles.expanded, className)}
size={expanded ? "m" : "l"}
skin={active ? "primary" : "ghost"}
title={expanded ? undefined : label}
icon={icon}
{...otherProps}>
{expanded ? label : null}
</Button>
);
};
30 changes: 30 additions & 0 deletions packages/components/_provisional/src/dock/DockMainItem.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import React, { useContext } from "react";
import { DockContext } from "./context";
import styles from "./styles/dock-main-item.module.scss";
import classNames from "classnames";
import { Avatar, type AvatarProps } from "../avatar";

export interface DockMainItemProps extends React.HTMLAttributes<HTMLSpanElement> {
image: AvatarProps["image"];
label: AvatarProps["name"];
}

export const DockMainItem = ({
image,
label,
className,
...otherProps
}: Readonly<DockMainItemProps>): React.ReactElement => {
const { expanded } = useContext(DockContext);

return (
<span
className={classNames(styles.root, expanded && styles.expanded, className)}
title={expanded ? undefined : label}
{...otherProps}>
<Avatar name={label} image={image} />

{expanded ? label : null}
</span>
);
};
9 changes: 9 additions & 0 deletions packages/components/_provisional/src/dock/context.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import React from "react";

export interface DockContextProps {
expanded: boolean;
}

export const DockContext = React.createContext<DockContextProps>({
expanded: false,
});
1 change: 1 addition & 0 deletions packages/components/_provisional/src/dock/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./Dock";
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
@import "@react-ck/theme";

.root {
border-radius: get-spacing(1);

&.expanded {
justify-content: flex-start;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
@import "@react-ck/theme";
@import "@react-ck/text";

.root {
@include text-base;
@include text-type(h3);

display: flex;
justify-content: center;
align-items: center;
gap: get-spacing(1);

&.expanded {
justify-content: flex-start;
padding-right: get-spacing(1);
}
}
Loading

0 comments on commit 7559e5f

Please sign in to comment.