Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: the-guild-org/docs
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: @theguild/components@9.6.0
Choose a base ref
...
head repository: the-guild-org/docs
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: @theguild/components@9.7.0
Choose a head ref
  • 2 commits
  • 12 files changed
  • 3 contributors

Commits on Apr 3, 2025

  1. Input (#2059)

    hasparus authored Apr 3, 2025

    Verified

    This commit was signed with the committer’s verified signature. The key has expired.
    penguinpee Sandro
    Copy the full SHA
    1dfb18f View commit details

Commits on Apr 4, 2025

  1. Upcoming Release Changes (#2060)

    Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
    github-actions[bot] and github-actions[bot] authored Apr 4, 2025
    Copy the full SHA
    4c3bab5 View commit details
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -29,12 +29,13 @@
"@storybook/addon-links": "8.4.2",
"@storybook/core-common": "8.4.2",
"@storybook/nextjs": "8.4.2",
"@storybook/preview-api": "8.4.2",
"@storybook/react": "8.4.2",
"@storybook/theming": "8.4.2",
"@svgr/webpack": "8.1.0",
"@theguild/eslint-config": "0.13.2",
"@theguild/prettier-config": "3.0.0",
"@theguild/tailwind-config": "0.6.2",
"@theguild/tailwind-config": "0.6.3",
"@types/jest-image-snapshot": "6.4.0",
"@types/react": "18.3.18",
"@types/react-paginate": "7.1.4",
8 changes: 8 additions & 0 deletions packages/components/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# @theguild/components

## 9.7.0

### Minor Changes

- [#2059](https://github.com/the-guild-org/docs/pull/2059)
[`1dfb18f`](https://github.com/the-guild-org/docs/commit/1dfb18f79fbb1443c1c68aff7d57b5f52015e38e)
Thanks [@hasparus](https://github.com/hasparus)! - Add Input component

## 9.6.0

### Minor Changes
6 changes: 3 additions & 3 deletions packages/components/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@theguild/components",
"version": "9.6.0",
"version": "9.7.0",
"repository": {
"url": "https://github.com/the-guild-org/docs",
"directory": "packages/components"
@@ -44,7 +44,7 @@
"types:check": "tsc --noEmit"
},
"peerDependencies": {
"@theguild/tailwind-config": "^0.6.2",
"@theguild/tailwind-config": "^0.6.3",
"next": "^13 || ^14 || ^15.0.0",
"react": "^18.2.0",
"react-dom": "^18.2.0"
@@ -68,7 +68,7 @@
"devDependencies": {
"@svgr/plugin-svgo": "^8.1.0",
"@theguild/editor": "workspace:*",
"@theguild/tailwind-config": "0.6.2",
"@theguild/tailwind-config": "0.6.3",
"@types/dedent": "0.7.2",
"@types/mdast": "4.0.4",
"@types/react": "18.3.18",
2 changes: 2 additions & 0 deletions packages/components/src/components/heading.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Meta, StoryObj } from '@storybook/react';
import { hiveThemeDecorator } from '../../../../.storybook/hive-theme-decorator';
import { Heading as _Heading, HeadingProps } from './heading';

export default {
@@ -23,6 +24,7 @@ export default {
parameters: {
padding: true,
},
decorators: [hiveThemeDecorator],
} satisfies Meta<HeadingProps>;

export const Heading: StoryObj<HeadingProps> = {
1 change: 1 addition & 0 deletions packages/components/src/components/index.ts
Original file line number Diff line number Diff line change
@@ -9,6 +9,7 @@ export { HeroVideo } from './hero-video';
export * from './icons';
export { Image } from './image';
export { InfoList } from './info-list';
export { Input } from './input';
export { LegacyPackageCmd } from './legacy-package-cmd';
export { MarketplaceList } from './marketplace-list';
export { MarketplaceSearch } from './marketplace-search';
56 changes: 56 additions & 0 deletions packages/components/src/components/input/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { cn } from '../../cn';
import { Severity } from '../../types/severity';
import { InputShake } from './input-shake';

export interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> {
severity?: Severity;
message?: string;
}

export function Input({ severity, message, ...props }: InputProps) {
return (
<div
// todo: discuss colors with designers.
// dark mode colors are kinda bad, but we don't really need
// them just yet as this is used on yellow backgrounds
className={cn(
'rounded-[9px] border border-blue-400 bg-white outline-offset-2 focus-within:outline focus-within:outline-2 dark:border-neutral-400 dark:bg-neutral-800',
'focus-visible:outline-green-800/40',
'[&:focus-within:has([aria-invalid],:invalid)]:outline-critical-dark [&:has([aria-invalid],:invalid)]:border-critical-dark/50',
severity === 'warning' &&
'border-warning-bright/50 outline-warning-bright dark:border-warning-bright/50',
severity === 'positive' &&
'border-positive-dark/50 outline-positive-dark dark:border-positive-dark/50',
)}
>
<InputShake severity={severity} />
<input
aria-invalid={severity === 'critical' ? true : undefined}
className={cn(
'w-full rounded-lg bg-white py-3 indent-4 font-medium transition-[background-color,padding] placeholder:text-green-800 placeholder-shown:bg-blue-100 autofill:shadow-[inset_0_0_0px_1000px_rgb(255,255,255)] autofill:[-webkit-text-fill-color:theme(colors.green.1000)] autofill:first-line:font-sans hover:bg-white focus:bg-white focus-visible:outline-none focus-visible:ring-0 dark:bg-neutral-800 dark:text-white dark:placeholder:text-neutral-300 dark:placeholder-shown:bg-neutral-900 dark:hover:bg-neutral-800 dark:focus:bg-neutral-800',
message && 'rounded-b-none py-2',
props.className,
)}
{...props}
/>
<div
style={{ height: message ? '25px' : '0px' }}
className={cn(
'overflow-hidden rounded-b-lg pl-4 pr-1 text-sm transition-all *:animate-in *:fade-in',
severity === 'critical' && 'bg-critical-dark/10 dark:bg-critical-bright/20',
severity === 'warning' && 'bg-warning-bright/10',
severity === 'positive' && 'bg-positive-dark/10',
)}
>
{message &&
(severity === 'critical' ? (
<p className="py-0.5 text-sm text-critical-dark dark:text-white">{message}</p>
) : severity === 'warning' ? (
<p className="py-0.5 text-sm text-warning-bright">{message}</p>
) : (
<p className="py-0.5 text-sm text-positive-dark">{message}</p>
))}
</div>
</div>
);
}
31 changes: 31 additions & 0 deletions packages/components/src/components/input/input-shake.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
'use client';

import { useEffect, useRef } from 'react';
import { Severity } from '../../types/severity';

interface InputShakeProps {
severity?: Severity;
}

/**
* We need this hack to avoid shaking the input when it's first rendered
* already as critical.
*/
export function InputShake({ severity }: InputShakeProps) {
const ref = useRef<HTMLDivElement>(null);
const prevSeverityRef = useRef<Severity | undefined>(severity);

useEffect(() => {
const shouldShake = prevSeverityRef.current !== 'critical' && severity === 'critical';

prevSeverityRef.current = severity;
const container = ref.current?.parentElement;
if (container && shouldShake) {
container.classList.add('animate-shake');
const cleanUp = () => container.classList.remove('animate-shake');
container.addEventListener('animationend', cleanUp, { once: true });
}
}, [severity]);

return <div ref={ref} className="hidden" />;
}
107 changes: 107 additions & 0 deletions packages/components/src/components/input/input.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import { useArgs } from '@storybook/preview-api';
import { Meta, StoryObj } from '@storybook/react';
import { Input, InputProps } from '.';
import { hiveThemeDecorator } from '../../../../../.storybook/hive-theme-decorator';

export default {
title: 'Components/Input',
component: Input,
argTypes: {
severity: {
control: 'select',
options: ['critical', 'warning', 'positive', undefined],
},
message: {
control: 'text',
},
type: {
control: 'select',
options: ['text', 'email', 'password', 'number'],
},
disabled: {
control: 'boolean',
},
required: {
control: 'boolean',
},
},
parameters: {
padding: true,
},
decorators: [
hiveThemeDecorator,
(Story: React.FC) => (
<div className="max-w-xl">
<Story />
</div>
),
],
} satisfies Meta<InputProps>;

export const Default: StoryObj<InputProps> = {
args: {
placeholder: 'Email',
type: 'text',
},
};

export const Critical: StoryObj<InputProps> = {
args: {
severity: 'critical',
message: 'Please enter a valid email address',
type: 'email',
value: '+48 222 500 151',
},
render: () => {
const [args, update] = useArgs<InputProps>();

return (
<Input
{...args}
onChange={event => {
if (
event.target.value.toString().match(/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/)
) {
update({ severity: undefined, message: undefined });
} else {
update({ severity: 'critical', message: 'Please enter a valid email address' });
}

update({ value: event.target.value });
}}
/>
);
},
};

export const Warning: StoryObj<InputProps> = {
args: {
severity: 'warning',
message: 'Weak password',
type: 'password',
value: '1234',
},
};

export const Positive: StoryObj<InputProps> = {
args: {
severity: 'positive',
message: 'Very strong password',
type: 'password',
value: 'Wednesday, 2 April 2025, GraphQL will prevail!',
},
};

export const Disabled: StoryObj<InputProps> = {
args: {
disabled: true,
placeholder: 'Disabled input',
},
};

export const Required: StoryObj<InputProps> = {
args: {
required: true,
placeholder: 'This should not be empty',
},
};
1 change: 1 addition & 0 deletions packages/components/src/types/severity.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export type Severity = 'critical' | 'positive' | 'warning';
59 changes: 59 additions & 0 deletions packages/components/style.css
Original file line number Diff line number Diff line change
@@ -149,3 +149,62 @@
--nextra-navbar-height: 64px;
}
}

:root {
--hive-ease-overshoot-far: linear(
0 0%,
0.5007 7.21%,
0.7803 12.29%,
0.8883 14.93%,
0.9724 17.63%,
1.0343 20.44%,
1.0754 23.44%,
1.0898 25.22%,
1.0984 27.11%,
1.1014 29.15%,
1.0989 31.4%,
1.0854 35.23%,
1.0196 48.86%,
1.0043 54.06%,
0.9956 59.6%,
0.9925 68.11%,
1 100%
);

--hive-ease-overshoot-a-bit: linear(
0 0%,
0.5007 7.21%,
0.7803 12.29%,
0.8883 14.93%,
0.9724 17.63%,
1.011319 20.44%,
1.024882 23.44%,
1.029634 25.22%,
1.032472 27.11%,
1.033462 29.15%,
1.032637 31.4%,
1.028182 35.23%,
1.006468 48.86%,
1.001419 54.06%,
0.9956 59.6%,
0.9925 68.11%,
1 100%
);
}

@keyframes hive-shake {
0%,
100% {
transform: translateX(0);
}
25% {
transform: rotate(-0.4deg);
}
75% {
transform: rotate(0.3deg);
}
}

.animate-shake:not(:focus-within) {
animation: hive-shake 0.3s ease;
}
Loading