Skip to content

Commit

Permalink
Added @radix-ui/react-slot to react package and more examples to th…
Browse files Browse the repository at this point in the history
…e website
  • Loading branch information
bring-shrubbery committed Aug 26, 2023
1 parent 6f1b4e5 commit 5ed151e
Show file tree
Hide file tree
Showing 11 changed files with 174 additions and 80 deletions.
2 changes: 2 additions & 0 deletions apps/web/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { LinksSection } from "./sections/LinksSection";
import { UsageSectionReactContent } from "./sections/UsageSectionReactContent";
import { ExampleSectionConstantSizeExample } from "./sections/ExamplesSectionConstantSizeExample";
import { ExamplesSectionDefaultSizeExample } from "./sections/ExamplesSectionDefaultSizeExample";
import { ExamplesSectionAsChildExample } from "./sections/ExamplesSectionAsChildExample";

export default function Page() {
return (
Expand All @@ -20,6 +21,7 @@ export default function Page() {
<ExamplesSection
constantSizeExample={<ExampleSectionConstantSizeExample />}
defaultSizeExample={<ExamplesSectionDefaultSizeExample />}
asChildPropExample={<ExamplesSectionAsChildExample />}
/>
{/* <HowItWorksSection /> */}
<LicenseSection />
Expand Down
6 changes: 5 additions & 1 deletion apps/web/app/sections/ExamplesSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@ import { useAtom } from "jotai";
export const ExamplesSection = ({
constantSizeExample,
defaultSizeExample,
asChildPropExample,
}: {
constantSizeExample: JSX.Element;
defaultSizeExample: JSX.Element;
asChildPropExample: JSX.Element;
}) => {
const [language] = useAtom(LANGUAGE_SELECTOR_ATOM);

Expand All @@ -24,11 +26,13 @@ export const ExamplesSection = ({
<Tabs defaultValue="1" className="w-full flex flex-col items-center">
<TabsList>
<TabsTrigger value="1">Constant size</TabsTrigger>
<TabsTrigger value="2">Default size</TabsTrigger>
<TabsTrigger value="2">Default size (Image Example)</TabsTrigger>
<TabsTrigger value="3">asChild prop</TabsTrigger>
</TabsList>

<TabsContent value="1">{constantSizeExample}</TabsContent>
<TabsContent value="2">{defaultSizeExample}</TabsContent>
<TabsContent value="3">{asChildPropExample}</TabsContent>
</Tabs>
</div>
);
Expand Down
58 changes: 58 additions & 0 deletions apps/web/app/sections/ExamplesSectionAsChildExample.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { Card, CardContent } from "@/components/ui/card";
import { Code } from "@/components/ui/code";
import { Squircle } from "@squircle-js/react";

import Prism from "prismjs";
import "prismjs/components/prism-jsx";
import type { PropsWithChildren } from "react";

const usage = `<Squircle
asChild
cornerRadius={10}
cornerSmoothing={1}
className="bg-black text-white px-2 py-1"
>
<span>Inline Squircle</span>
</Squircle>`;

const highlightedUsage = Prism.highlight(
["...", usage, "..."].join("\n"),
Prism.languages.jsx,
"jsx"
);

export const ExamplesSectionAsChildExample = () => {
return (
<Card className="w-full max-w-[480px] sm:max-w-[508px]">
<CardContent className="py-6 w-full space-y-4">
<h3 className="font-semibold text-lg">Code:</h3>
<p>
You can use <Kode>asChild</Kode> prop to squircle any element. This is
useful when you want to squircle some element that might change size.
By default <Kode>Squircle</Kode> is a <Kode>div</Kode> element, but
you can change it to any other element by nesting that element inside
of <Kode>Squircle</Kode> component and adding <Kode>asChild</Kode>{" "}
prop.
</p>

<Code dangerousHTML={highlightedUsage} raw={usage} />
<h3 className="font-semibold text-lg">Result:</h3>

<Squircle
cornerRadius={10}
cornerSmoothing={1}
asChild
className="bg-black text-white px-2 py-1"
>
<span>Inline Squircle</span>
</Squircle>
</CardContent>
</Card>
);
};

const Kode = ({ children }: PropsWithChildren) => (
<code className="bg-slate-200/50 px-1.5 text-sm py-0.5 rounded-md">
{children}
</code>
);
15 changes: 15 additions & 0 deletions apps/web/app/sections/ExamplesSectionConstantSizeExample.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { Squircle } from "@squircle-js/react";

import Prism from "prismjs";
import "prismjs/components/prism-jsx";
import { PropsWithChildren } from "react";

const usage = `<Squircle
cornerRadius={64}
Expand All @@ -29,6 +30,14 @@ export const ExampleSectionConstantSizeExample = () => {
<Card className="w-full max-w-[480px] sm:max-w-[508px]">
<CardContent className="py-6 w-full space-y-4">
<h3 className="font-semibold text-lg">Code:</h3>

<p>
When you know the exact size you want your squircle to be, you can use{" "}
<Kode>width</Kode> and <Kode>height</Kode> props to specify it. This
is especially useful when you Server Side Render your app, and you
know the size of the image you want to squircle.
</p>

<Code dangerousHTML={highlightedUsage} raw={usage} />
<h3 className="font-semibold text-lg">Result:</h3>

Expand All @@ -49,3 +58,9 @@ export const ExampleSectionConstantSizeExample = () => {
</Card>
);
};

const Kode = ({ children }: PropsWithChildren) => (
<code className="bg-slate-200/50 px-1.5 text-sm py-0.5 rounded-md">
{children}
</code>
);
30 changes: 23 additions & 7 deletions apps/web/app/sections/ExamplesSectionDefaultSizeExample.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,21 @@ import { Squircle } from "@squircle-js/react";
import Prism from "prismjs";
import "prismjs/components/prism-jsx";
import { ExamplesSectionDefaultSizeExampleClientComponent } from "./ExamplesSectionDefaultSizeExampleClientComponent";
import { PropsWithChildren } from "react";

const usage = `<Squircle
cornerRadius={64}
cornerRadius={50}
cornerSmoothing={1}
defaultSize={256}
defaultSize={256}
defaultWidth={320}
defaultHeight={214}
className="bg-slate-100 w-fit h-fit"
asChild
>
<div
className="w-full h-full
bg-gradient-to-br from-indigo-500
via-purple-500 to-pink-500"
<Image
src="/antoni-silvestrovic-baS2vUSSGBY-unsplash.jpg"
width={320}
height={214}
alt="D*ck"
/>
</Squircle>`;

Expand All @@ -34,6 +38,12 @@ export const ExamplesSectionDefaultSizeExample = () => {
For images to work you will need to provide either default size, or
specific size you want the image to be.
</p>
<p>
In this example, we&apos;re using <Kode>defaultWidth</Kode> and{" "}
<Kode>defaultHeight</Kode> to tell Squircle what size we want the{" "}
<Kode>clipPath</Kode> to be initially, afterwards if you resize the
image it will be updated automatically.
</p>
<Code dangerousHTML={highlightedUsage} raw={usage} />
<h3 className="font-semibold text-lg">Result:</h3>

Expand All @@ -42,3 +52,9 @@ export const ExamplesSectionDefaultSizeExample = () => {
</Card>
);
};

const Kode = ({ children }: PropsWithChildren) => (
<code className="bg-slate-200/50 px-1.5 text-sm py-0.5 rounded-md">
{children}
</code>
);
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import { Button } from "@/components/ui/button";
import { Squircle } from "@squircle-js/react";
import { RotateCcwIcon } from "lucide-react";
import Image from "next/image";
import { useEffect, useState } from "react";

export const ExamplesSectionDefaultSizeExampleClientComponent = () => {
Expand Down Expand Up @@ -30,20 +31,14 @@ export const ExamplesSectionDefaultSizeExampleClientComponent = () => {
</Button>
{src && (
<Squircle
cornerRadius={64}
cornerRadius={50}
cornerSmoothing={1}
// width={256}
// height={256}
defaultWidth={256}
defaultHeight={256}
defaultWidth={320}
defaultHeight={214}
className="bg-slate-100 w-fit h-fit"
style={{ paddingBottom: !src ? -1 : 0 }}
as="img"
src={src}
asChild
>
{/* <a href="https://unsplash.com/@bring_shrubbery"> */}

{/* </a> */}
<Image src={src} width={320} height={214} alt="" />
</Squircle>
)}
</div>
Expand Down
10 changes: 5 additions & 5 deletions apps/web/app/sections/SquircleDemoSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,12 @@ export const SquircleDemoSection = () => {
Squircle
</span>{" "}
<Squircle
as="span"
className="bg-black pl-8 pr-8 pt-2 pb-2 text-6xl sm:text-inherit"
asChild
cornerRadius={cornerRadius}
cornerSmoothing={cornerSmoothing}
className="bg-black text-white pl-8 pr-8 pt-2 pb-2 text-6xl"
>
<span className="text-white">Element</span>
<span>Element</span>
</Squircle>
<br />
for{" "}
Expand All @@ -34,12 +34,12 @@ export const SquircleDemoSection = () => {
<div className="text-center text-lg mb-6">
Use{" "}
<Squircle
as="code"
asChild
className="bg-foreground text-white py-1 pl-2 pr-2"
cornerRadius={10}
cornerSmoothing={1}
>
{"<Squircle>"}
<span>{"<Squircle>"}</span>
</Squircle>{" "}
to build your own components.
<br />
Expand Down
1 change: 1 addition & 0 deletions packages/squircle-element-react/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"lint": "tsc"
},
"dependencies": {
"@radix-ui/react-slot": "^1.0.2",
"figma-squircle": "^0.3.0"
},
"peerDependencies": {
Expand Down
16 changes: 9 additions & 7 deletions packages/squircle-element-react/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,25 @@ import { useMemo } from "react";

import { useElementSize } from "./use-element-size";
export { SquircleNoScript } from "./no-js";
import { Slot } from "@radix-ui/react-slot";

interface SquircleProps<E extends React.ElementType> {
cornerSmoothing?: number;
cornerRadius?: number;
as?: E;
asChild?: boolean;
children?: React.ReactNode;

width?: number;
height?: number;

defaultWidth?: number;
defaultHeight?: number;
}

function Squircle<E extends React.ElementType = "div">({
cornerRadius,
cornerSmoothing = 0.6,
as,
asChild,
style,
width: w,
height: h,
Expand All @@ -30,12 +32,12 @@ function Squircle<E extends React.ElementType = "div">({
...props
}: SquircleProps<E> &
Omit<React.ComponentPropsWithoutRef<E>, keyof SquircleProps<E>>) {
const Component = as || "div";
const Component = asChild ? Slot : "div";

// Note: If you need to pass ref, wrap this component in another, and style to full-width/height.
const [ref, { width, height }] = useElementSize<HTMLDivElement>({
width: defaultWidth,
height: defaultHeight,
defaultWidth,
defaultHeight,
});

const actualWidth = w ?? width;
Expand All @@ -57,8 +59,8 @@ function Squircle<E extends React.ElementType = "div">({
style={{
...style,
borderRadius: cornerRadius,
// width: actualWidth,
// height: actualHeight,
width: w ?? defaultWidth,
height: h ?? defaultHeight,
clipPath: `path('${path}')`,
}}
data-squircle={cornerRadius}
Expand Down
8 changes: 4 additions & 4 deletions packages/squircle-element-react/src/use-element-size.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,16 @@ interface Size {
export function useElementSize<
T extends HTMLElement = HTMLDivElement
>(defaultSize: {
width?: number;
height?: number;
defaultWidth?: number;
defaultHeight?: number;
}): [(node: T | null) => void, Size] {
// Mutable values like 'ref.current' aren't valid dependencies
// because mutating them doesn't re-render the component.
// Instead, we use a state as a ref to be reactive.
const [ref, setRef] = useState<T | null>(null);
const [size, setSize] = useState<Size>({
width: defaultSize.width ?? 0,
height: defaultSize.height ?? 0,
width: defaultSize.defaultWidth ?? 0,
height: defaultSize.defaultHeight ?? 0,
});

// Prevent too many rendering using useCallback
Expand Down
Loading

0 comments on commit 5ed151e

Please sign in to comment.