[WEB-5602] feat: new design system (#8220)

* chore: init tailwind v4

* chore: update all configs

* chore: add source to parse monorepo packages

* chore: combine all css files

* feat: added extended colors

* chore: update typography

* chore: update extended color var names

* refactor: remove initial spacing variable and update dark mode selector

* chore: update css files

* chore: update animations

* chore: remove spacing tokens

* fix: external css files

* chore: update tailwind-merge version

* chore: update font family

* chore: added brief agents.md and story for new design system

* chore: enhance design system documentation with rare exceptions for visual separation

* chore: add fontsource package for typography

* chore: material symbols font added

* chore: update shadow default

* chore: add stroke and outline theme vars

* chore: update ring and fill colors

* chore: overwrite tailwind typography tokens

* chore: add high contrast mode tokens

* chore: update scrollbar colors

* chore: backward compatibility for buttons and placeholders

* chore: add priority colors

* chore: update urgent priority color

* chore: update plan colors

* chore: add missing utility class

* chore: update height and padding classes

* chore: update label colors

* chore: add missing utlity

* chore: add typography plugin to space app

* chore: replace existing classNames with new design system tokens #8244 (#8278)

* chore: update border colors

* chore: update all borders

* chore: update text colors

* chore: update css variables

* chore: update font sizes and weights

* chore: update bg colors

* chore: sync changes

* fix: uncomment spacing-1200 variable in variables.css

* chore: update primary colors

* refactor: updated border to border-subtle

* refactor: update various components and improve UI consistency across the application

* updated classnames

* updated classnames

* refactor: update color-related class names to use new design system variables for consistency

* chore: default automations

* chore: update text sizes

* chore: home and power k

* chore: home and power k

* chore: replace ui package button components

* chore: update text sizes

* chore: updated issue identifier (#8275)

* refactor: top navigation and sidebar design token (#8276)

* chore: update all button components (#8277)

* chore: new button component

* chore: update existing buttons

* chore: overwrite tailwind typography tokens

* fix: twMerge config + fixed cn instances

* refactor: toast design token updated (#8279)

* chore: update existing buttons

* chore: tooltip design token updatged (#8280)

* chore: moved cn utility to propel (#8281)

* chore: update space app UI (#8285)

* chore; update space app filters component

* fix: button whitespace wrap

* chore: space app votes

* chore: update dropdown components

* refactor: auth, onboarding, sidebar, and common component design token migration (#8291)

* chore: checkbox component design token updated

* chore: indicator and oauth component design token updated

* chore: sidebar design token updated

* chore: auth and onboarding design token updated

* chore: update divider color

* style: update background colors and hover effects across list components

* fix: tailwind merge

* refactor: toggle switch design token migration and header utility classname added (#8295)

* chore: toggle component design token updated

* chore: h-header utility class added

* chore: updated color tokens for work item detail page (#8296)

* chore: update react-day-picker UI

* refactor: update button sizes and styles in filters components

* refactor: breadcrumbs design token updated (#8297)

* chore: update priority icon colors

* refactor: updated layout variables

* chore: update plan card primary CTA

* Chore update editor design system (#8299)

* refactor: update styles for callout, color selector, logo selector, and image uploader

* refactor:fix image

* chore: update settings UI

* chore: updated notifications color and size tokens (#8302)

* chore: update sm button border radius

* fix: logo renderer

* chore: icon button component

* chore: remove deprecated classes

* chore: remove deprecated classes

* chore: update editor list spacing

* fix: icon button size

* chore: improvements (#8309)

* chore: update cycles and modules pages

* refactor: update background styles across various components to use new design system colors

* fix: button type errors

* chore: update modals design system (#8310)

* refactor: callout bg

* refactor: code  bg

* refactor: modal size and variant

---------

Co-authored-by: Aaryan Khandelwal <aaryankhandu123@gmail.com>

* chore: update next-themes

* design: update billing and plans component styles and remove unused utility functions (#8313)

* refactor: empty state design token migration and improvements (#8315)

* fix: profile page

* refactor: tabs design token updated (#8316)

* chore: updated buttons and tokens for work items (#8317)

* fix: adjust trial button spacing in checkout modal

* chore: update add button hover state

* fix: type error (#8318)

* fix: type error

* chore: code refactor

* refactor: update button sizes and background styles in rich filters components

* refactor: update editor bg

* refactor: enhance Gantt chart sidebar functionality and styling

- Removed unused  prop from .
- Updated  to include new props for better block management and scrolling behavior.
- Improved auto-scroll functionality for Gantt chart items.
- Adjusted styles in  component for consistent design.

* regression: gantt design

* chore: new badge component

* fix: favorite star

* chore: update backgroung, typography and button sizes across workspace settings general and members pages

* fix: header button sizes

* fix: emoji icon logo (#8323)

* more fixes

* chore: update settings sidebar

* refactor: avatar component

* chore: updated work item detail sidebar (#8327)

* refactor: update link preview

* fix: work item property dropdowns

* fix: dropdown buttons border radius

* chore: update power k translation

* chore: updated profile activity design (#8328)

* chore: update settings pages

* chore: update work item sidebar alignments (#8330)

* refactor: admin design system

* chore: update page header

---------

Co-authored-by: Jayash Tripathy <76092296+JayashTripathy@users.noreply.github.com>
Co-authored-by: VipinDevelops <vipinchaudhary1809@gmail.com>
Co-authored-by: Vamsi Krishna <46787868+vamsikrishnamathala@users.noreply.github.com>
Co-authored-by: Anmol Singh Bhatia <121005188+anmolsinghbhatia@users.noreply.github.com>
Co-authored-by: gakshita <akshitagoyal1516@gmail.com>
Co-authored-by: Palanikannan M <akashmalinimurugu@gmail.com>
Co-authored-by: Prateek Shourya <prateekshourya29@gmail.com>
Co-authored-by: b-saikrishnakanth <bsaikrishnakanth97@gmail.com>
Co-authored-by: M. Palanikannan <73993394+Palanikannan1437@users.noreply.github.com>

* fix: formatting

* reexport types

* fix: lint error

---------

Co-authored-by: Jayash Tripathy <76092296+JayashTripathy@users.noreply.github.com>
Co-authored-by: VipinDevelops <vipinchaudhary1809@gmail.com>
Co-authored-by: Vamsi Krishna <46787868+vamsikrishnamathala@users.noreply.github.com>
Co-authored-by: Anmol Singh Bhatia <121005188+anmolsinghbhatia@users.noreply.github.com>
Co-authored-by: gakshita <akshitagoyal1516@gmail.com>
Co-authored-by: Palanikannan M <akashmalinimurugu@gmail.com>
Co-authored-by: Prateek Shourya <prateekshourya29@gmail.com>
Co-authored-by: b-saikrishnakanth <bsaikrishnakanth97@gmail.com>
Co-authored-by: M. Palanikannan <73993394+Palanikannan1437@users.noreply.github.com>
This commit is contained in:
Aaryan Khandelwal 2025-12-12 20:50:14 +05:30 committed by GitHub
parent d86418aad8
commit 22339b9786
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
1342 changed files with 14227 additions and 15119 deletions

View file

@ -1,8 +1,8 @@
import type { TChartColorScheme } from "@plane/types";
import { ChartXAxisProperty } from "@plane/types";
export const LABEL_CLASSNAME = "uppercase text-custom-text-300/60 text-sm tracking-wide";
export const AXIS_LABEL_CLASSNAME = "uppercase text-custom-text-300/60 text-sm tracking-wide";
export const LABEL_CLASSNAME = "uppercase text-tertiary/60 text-13 tracking-wide";
export const AXIS_LABEL_CLASSNAME = "uppercase text-tertiary/60 text-13 tracking-wide";
export enum ChartXAxisDateGrouping {
DAY = "DAY",

View file

@ -36,7 +36,7 @@ export const CYCLE_STATUS: {
value: "draft",
i18n_title: "project_cycles.status.draft",
color: "#525252",
textColor: "text-custom-text-300",
bgColor: "bg-custom-background-90",
textColor: "text-tertiary",
bgColor: "bg-surface-2",
},
];

View file

@ -1,7 +1,7 @@
export const CHARTS_THEME = {
background: "transparent",
text: {
color: "rgb(var(--color-text-200))",
color: "var(--text-color-secondary)",
},
axis: {
domain: {
@ -14,14 +14,14 @@ export const CHARTS_THEME = {
tooltip: {
container: {
background: "rgb(var(--color-background-80))",
color: "rgb(var(--color-text-200))",
color: "var(--text-color-secondary)",
fontSize: "0.8rem",
border: "1px solid rgb(var(--color-border-300))",
border: "1px solid var(--border-color-strong)",
},
},
grid: {
line: {
stroke: "rgb(var(--color-border-100))",
stroke: "var(--border-color-subtle)",
},
},
};

View file

@ -61,31 +61,31 @@ export const ISSUE_PRIORITY_FILTERS: TIssueFilterPriorityObject[] = [
{
key: "urgent",
titleTranslationKey: "issue.priority.urgent",
className: "bg-red-500 border-red-500 text-white",
className: "bg-layer-2 text-priority-urgent border-strong",
icon: "error",
},
{
key: "high",
titleTranslationKey: "issue.priority.high",
className: "text-orange-500 border-custom-border-300",
className: "bg-layer-2 text-priority-high border-strong",
icon: "signal_cellular_alt",
},
{
key: "medium",
titleTranslationKey: "issue.priority.medium",
className: "text-yellow-500 border-custom-border-300",
className: "bg-layer-2 text-priority-medium border-strong",
icon: "signal_cellular_alt_2_bar",
},
{
key: "low",
titleTranslationKey: "issue.priority.low",
className: "text-green-500 border-custom-border-300",
className: "bg-layer-2 text-priority-low border-strong",
icon: "signal_cellular_alt_1_bar",
},
{
key: "none",
titleTranslationKey: "common.none",
className: "text-gray-500 border-custom-border-300",
className: "bg-layer-2 text-priority-none border-strong",
icon: "block",
},
];

View file

@ -23,8 +23,8 @@ export const MODULE_STATUS: {
i18n_label: "project_modules.status.backlog",
value: "backlog",
color: MODULE_STATUS_COLORS.backlog,
textColor: "text-custom-text-400",
bgColor: "bg-custom-background-80",
textColor: "text-placeholder",
bgColor: "bg-layer-1",
},
{
i18n_label: "project_modules.status.planned",
@ -44,8 +44,8 @@ export const MODULE_STATUS: {
i18n_label: "project_modules.status.paused",
value: "paused",
color: MODULE_STATUS_COLORS.paused,
textColor: "text-custom-text-300",
bgColor: "bg-custom-background-90",
textColor: "text-tertiary",
bgColor: "bg-surface-2",
},
{
i18n_label: "project_modules.status.completed",

View file

@ -1,9 +1,3 @@
// If you want to use other PostCSS plugins, see the following:
// https://tailwindcss.com/docs/using-with-preprocessors
import postcssConfig from "@plane/tailwind-config/postcss.config.js";
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
};
export default postcssConfig;

View file

@ -17,11 +17,11 @@ type InputViewProps = {
function InputView({ label, value, placeholder, onChange, autoFocus }: InputViewProps) {
return (
<div className="flex flex-col gap-1">
<label className="inline-block font-semibold text-xs text-custom-text-400">{label}</label>
<label className="inline-block font-semibold text-11 text-placeholder">{label}</label>
<input
placeholder={placeholder}
onClick={(e) => e.stopPropagation()}
className="w-[280px] outline-none bg-custom-background-90 text-custom-text-900 text-sm border border-custom-border-300 rounded-md p-2"
className="w-[280px] outline-none bg-layer-1 text-primary text-13 border border-strong rounded-md p-2"
value={value}
onChange={(e) => onChange(e.target.value)}
autoFocus={autoFocus}
@ -132,7 +132,7 @@ export function LinkEditView({ viewProps }: LinkEditViewProps) {
return (
<div
onKeyDown={handleKeyDown}
className="shadow-md rounded p-2 flex flex-col gap-3 bg-custom-background-90 border-custom-border-100 border-2 animate-in fade-in translate-y-1"
className="shadow-md rounded-sm p-2 flex flex-col gap-3 bg-layer-1 border-subtle border-2 animate-in fade-in translate-y-1"
style={{
transition: "all 0.1s cubic-bezier(.55, .085, .68, .53)",
}}
@ -140,10 +140,10 @@ export function LinkEditView({ viewProps }: LinkEditViewProps) {
>
<InputView label="URL" placeholder="Enter or paste URL" value={localUrl} onChange={setLocalUrl} autoFocus />
<InputView label="Text" placeholder="Enter Text to display" value={localText} onChange={handleTextChange} />
<div className="mb-1 bg-custom-border-300 h-[1px] w-full gap-2" />
<div className="flex text-sm text-custom-text-800 gap-2 items-center">
<div className="mb-1 bg-strong h-[1px] w-full gap-2" />
<div className="flex text-13 text-secondary gap-2 items-center">
<Link2Off size={14} className="inline-block" />
<button onClick={removeLink} className="cursor-pointer hover:text-custom-text-400 transition-colors">
<button onClick={removeLink} className="cursor-pointer hover:text-placeholder transition-colors">
Remove Link
</button>
</div>

View file

@ -28,22 +28,22 @@ export function LinkPreview({
transition: "all 0.2s cubic-bezier(.55, .085, .68, .53)",
}}
>
<div className="shadow-md items-center rounded p-2 flex gap-3 bg-custom-background-90 border-custom-border-100 border-2 text-custom-text-300 text-xs">
<div className="shadow-md items-center rounded-sm p-2 flex gap-3 bg-layer-1 border-subtle border-2 text-tertiary text-11">
<GlobeIcon size={14} className="inline-block" />
<p>{url?.length > 40 ? url.slice(0, 40) + "..." : url}</p>
<div className="flex gap-2">
<button onClick={copyLinkToClipboard} className="cursor-pointer hover:text-custom-text-100 transition-colors">
<button onClick={copyLinkToClipboard} className="cursor-pointer hover:text-primary transition-colors">
<Copy size={14} className="inline-block" />
</button>
{editor.isEditable && (
<>
<button
onClick={() => switchView("LinkEditView")}
className="cursor-pointer hover:text-custom-text-100 transition-colors"
className="cursor-pointer hover:text-primary transition-colors"
>
<PencilIcon size={14} className="inline-block" />
</button>
<button onClick={removeLink} className="cursor-pointer hover:text-custom-text-100 transition-colors">
<button onClick={removeLink} className="cursor-pointer hover:text-primary transition-colors">
<Link2Off size={14} className="inline-block" />
</button>
</>

View file

@ -216,7 +216,7 @@ export function BlockMenu(props: Props) {
zIndex: 100,
}}
className={cn(
"max-h-60 min-w-[7rem] overflow-y-scroll rounded-lg border border-custom-border-200 bg-custom-background-100 p-1.5 shadow-custom-shadow-rg",
"max-h-60 min-w-[7rem] overflow-y-scroll rounded-lg border border-subtle bg-surface-1 p-1.5 shadow-custom-shadow-rg",
"transition-all duration-300 transform origin-top-right",
isAnimatedIn ? "opacity-100 scale-100" : "opacity-0 scale-75"
)}
@ -229,7 +229,7 @@ export function BlockMenu(props: Props) {
<button
key={item.key}
type="button"
className="flex w-full items-center gap-1.5 truncate rounded px-1 py-1.5 text-xs text-custom-text-200 hover:bg-custom-background-90"
className="flex w-full items-center gap-1.5 truncate rounded-sm px-1 py-1.5 text-11 text-secondary hover:bg-layer-1"
onClick={(e) => {
item.onClick(e);
e.preventDefault();

View file

@ -69,9 +69,9 @@ export function TextAlignmentSelector(props: Props) {
item.command();
}}
className={cn(
"size-7 grid place-items-center rounded text-custom-text-300 hover:bg-custom-background-80 active:bg-custom-background-80 transition-colors",
"size-7 grid place-items-center rounded-sm text-tertiary hover:bg-layer-1 active:bg-layer-1 transition-colors",
{
"bg-custom-background-80 text-custom-text-100": item.isActive(),
"bg-layer-1 text-primary": item.isActive(),
}
)}
>

View file

@ -30,25 +30,22 @@ export function BubbleMenuColorSelector(props: Props) {
classNames={{
buttonContainer: "h-full",
button:
"flex items-center gap-1 h-full whitespace-nowrap px-3 text-sm font-medium text-custom-text-300 hover:bg-custom-background-80 active:bg-custom-background-80 rounded transition-colors",
"flex items-center gap-1 h-full whitespace-nowrap px-3 text-13 font-medium text-tertiary hover:bg-layer-1 active:bg-layer-1 rounded-sm transition-colors",
}}
menuButton={
<>
<span>Color</span>
<span
className={cn(
"flex-shrink-0 size-6 grid place-items-center rounded border-[0.5px] border-custom-border-300",
{
"bg-custom-background-100": !activeBackgroundColor,
}
)}
className={cn("flex-shrink-0 size-6 grid place-items-center rounded-sm border-[0.5px] border-strong", {
"bg-surface-1": !activeBackgroundColor,
})}
style={{
backgroundColor: activeBackgroundColor ? activeBackgroundColor.backgroundColor : "transparent",
}}
>
<ALargeSmall
className={cn("size-3.5", {
"text-custom-text-100": !activeTextColor,
"text-primary": !activeTextColor,
})}
style={{
color: activeTextColor ? activeTextColor.textColor : "inherit",
@ -61,15 +58,15 @@ export function BubbleMenuColorSelector(props: Props) {
getFloatingProps={getFloatingProps}
getReferenceProps={getReferenceProps}
>
<section className="mt-1 rounded-md border-[0.5px] border-custom-border-300 bg-custom-background-100 p-2 space-y-2 shadow-custom-shadow-rg">
<section className="mt-1 rounded-md border-[0.5px] border-strong bg-surface-1 p-2 space-y-2 shadow-custom-shadow-rg">
<div className="space-y-1.5">
<p className="text-xs text-custom-text-300 font-semibold">Text colors</p>
<p className="text-11 text-tertiary font-semibold">Text colors</p>
<div className="flex items-center gap-2">
{COLORS_LIST.map((color) => (
<button
key={color.key}
type="button"
className="flex-shrink-0 size-6 rounded border-[0.5px] border-custom-border-400 hover:opacity-60 transition-opacity"
className="flex-shrink-0 size-6 rounded-sm border-[0.5px] border-strong-1 hover:opacity-60 transition-opacity"
style={{
backgroundColor: color.textColor,
}}
@ -78,7 +75,7 @@ export function BubbleMenuColorSelector(props: Props) {
))}
<button
type="button"
className="flex-shrink-0 size-6 grid place-items-center rounded text-custom-text-300 border-[0.5px] border-custom-border-400 hover:bg-custom-background-80 transition-colors"
className="flex-shrink-0 size-6 grid place-items-center rounded-sm text-tertiary border-[0.5px] border-strong-1 hover:bg-layer-1 transition-colors"
onClick={() => TextColorItem(editor).command({ color: undefined })}
>
<Ban className="size-4" />
@ -86,13 +83,13 @@ export function BubbleMenuColorSelector(props: Props) {
</div>
</div>
<div className="space-y-1.5">
<p className="text-xs text-custom-text-300 font-semibold">Background colors</p>
<p className="text-11 text-tertiary font-semibold">Background colors</p>
<div className="flex items-center gap-2">
{COLORS_LIST.map((color) => (
<button
key={color.key}
type="button"
className="flex-shrink-0 size-6 rounded border-[0.5px] border-custom-border-400 hover:opacity-60 transition-opacity"
className="flex-shrink-0 size-6 rounded-sm border-[0.5px] border-strong-1 hover:opacity-60 transition-opacity"
style={{
backgroundColor: color.backgroundColor,
}}
@ -101,7 +98,7 @@ export function BubbleMenuColorSelector(props: Props) {
))}
<button
type="button"
className="flex-shrink-0 size-6 grid place-items-center rounded text-custom-text-300 border-[0.5px] border-custom-border-400 hover:bg-custom-background-80 transition-colors"
className="flex-shrink-0 size-6 grid place-items-center rounded-sm text-tertiary border-[0.5px] border-strong-1 hover:bg-layer-1 transition-colors"
onClick={() => BackgroundColorItem(editor).command({ color: undefined })}
>
<Ban className="size-4" />

View file

@ -46,10 +46,10 @@ export function BubbleMenuLinkSelector(props: Props) {
classNames={{
buttonContainer: "h-full",
button: cn(
"h-full flex items-center gap-1 px-3 text-sm font-medium text-custom-text-300 hover:bg-custom-background-80 active:bg-custom-background-80 rounded whitespace-nowrap transition-colors",
"h-full flex items-center gap-1 px-3 text-13 font-medium text-tertiary hover:bg-layer-1 active:bg-layer-1 rounded-sm whitespace-nowrap transition-colors",
{
"bg-custom-background-80": context.open,
"text-custom-text-100": editor.isActive(CORE_EXTENSIONS.CUSTOM_LINK),
"bg-layer-1": context.open,
"text-primary": editor.isActive(CORE_EXTENSIONS.CUSTOM_LINK),
}
),
}}
@ -63,9 +63,9 @@ export function BubbleMenuLinkSelector(props: Props) {
}
options={options}
>
<div className="w-60 mt-1 rounded-md bg-custom-background-100 shadow-custom-shadow-rg">
<div className="w-60 mt-1 rounded-md bg-surface-1 shadow-custom-shadow-rg">
<div
className={cn("flex rounded border-[0.5px] border-custom-border-300 transition-colors", {
className={cn("flex rounded-sm border-[0.5px] border-strong transition-colors", {
"border-red-500": error,
})}
>
@ -74,7 +74,7 @@ export function BubbleMenuLinkSelector(props: Props) {
type="url"
placeholder="Enter or paste a link"
onClick={(e) => e.stopPropagation()}
className="flex-1 border-r-[0.5px] border-custom-border-300 bg-custom-background-100 py-2 px-1.5 text-xs outline-none placeholder:text-custom-text-400 rounded"
className="flex-1 border-r-[0.5px] border-strong bg-surface-1 py-2 px-1.5 text-11 outline-none placeholder:text-placeholder rounded-sm"
defaultValue={editor.getAttributes("link").href || ""}
onKeyDown={(e) => {
setError(false);
@ -89,7 +89,7 @@ export function BubbleMenuLinkSelector(props: Props) {
{editor.getAttributes("link").href ? (
<button
type="button"
className="grid place-items-center rounded-sm p-1 text-red-500 hover:bg-red-500/20 transition-all"
className="grid place-items-center rounded-xs p-1 text-red-500 hover:bg-red-500/20 transition-all"
onClick={(e) => {
unsetLinkEditor(editor);
e.stopPropagation();
@ -101,7 +101,7 @@ export function BubbleMenuLinkSelector(props: Props) {
) : (
<button
type="button"
className="h-full aspect-square grid place-items-center p-1 rounded-sm text-custom-text-300 hover:bg-custom-background-80 transition-all"
className="h-full aspect-square grid place-items-center p-1 rounded-xs text-tertiary hover:bg-layer-1 transition-all"
onClick={(e) => {
e.stopPropagation();
handleLinkSubmit();
@ -112,7 +112,7 @@ export function BubbleMenuLinkSelector(props: Props) {
)}
</div>
{error && (
<p className="text-xs text-red-500 my-1 px-2 pointer-events-none animate-in fade-in slide-in-from-top-0">
<p className="text-11 text-red-500 my-1 px-2 pointer-events-none animate-in fade-in slide-in-from-top-0">
Please enter a valid URL
</p>
)}

View file

@ -59,9 +59,9 @@ export function BubbleMenuNodeSelector(props: Props) {
classNames={{
buttonContainer: "h-full",
button: cn(
"h-full flex items-center gap-1 px-3 text-sm font-medium text-custom-text-300 hover:bg-custom-background-80 active:bg-custom-background-80 rounded whitespace-nowrap transition-colors",
"h-full flex items-center gap-1 px-3 text-13 font-medium text-tertiary hover:bg-layer-1 active:bg-layer-1 rounded-sm whitespace-nowrap transition-colors",
{
"bg-custom-background-80": context.open,
"bg-layer-1": context.open,
}
),
}}
@ -75,7 +75,7 @@ export function BubbleMenuNodeSelector(props: Props) {
getFloatingProps={getFloatingProps}
getReferenceProps={getReferenceProps}
>
<section className="w-48 max-h-[90vh] mt-1 flex flex-col overflow-y-scroll rounded-md border-[0.5px] border-custom-border-300 bg-custom-background-100 px-2 py-2.5 shadow-custom-shadow-rg">
<section className="w-48 max-h-[90vh] mt-1 flex flex-col overflow-y-scroll rounded-md border-[0.5px] border-strong bg-surface-1 px-2 py-2.5 shadow-custom-shadow-rg">
{items.map((item) => (
<button
key={item.name}
@ -86,9 +86,9 @@ export function BubbleMenuNodeSelector(props: Props) {
e.stopPropagation();
}}
className={cn(
"flex items-center justify-between rounded px-1 py-1.5 text-sm text-custom-text-200 hover:bg-custom-background-80",
"flex items-center justify-between rounded-sm px-1 py-1.5 text-13 text-secondary hover:bg-layer-1",
{
"bg-custom-background-80": activeItem.name === item.name,
"bg-layer-1": activeItem.name === item.name,
}
)}
>
@ -96,7 +96,7 @@ export function BubbleMenuNodeSelector(props: Props) {
<item.icon className="size-3 flex-shrink-0" />
<span>{item.name}</span>
</div>
{activeItem.name === item.name && <Check className="size-3 text-custom-text-300 flex-shrink-0" />}
{activeItem.name === item.name && <Check className="size-3 text-tertiary flex-shrink-0" />}
</button>
))}
</section>

View file

@ -186,7 +186,7 @@ export function EditorBubbleMenu(props: Props) {
{!isSelecting && (
<div
ref={menuRef}
className="flex py-2 divide-x divide-custom-border-200 rounded-lg border border-custom-border-200 bg-custom-background-100 shadow-custom-shadow-rg overflow-x-scroll horizontal-scrollbar scrollbar-xs"
className="flex py-2 divide-x divide-subtle-1 rounded-lg border border-subtle bg-surface-1 shadow-custom-shadow-rg overflow-x-scroll horizontal-scrollbar scrollbar-xs"
>
<div className="px-2">
<BubbleMenuNodeSelector editor={editor} />
@ -211,9 +211,9 @@ export function EditorBubbleMenu(props: Props) {
e.stopPropagation();
}}
className={cn(
"size-7 grid place-items-center rounded text-custom-text-300 hover:bg-custom-background-80 active:bg-custom-background-80 transition-colors",
"size-7 grid place-items-center rounded-sm text-tertiary hover:bg-layer-1 active:bg-layer-1 transition-colors",
{
"bg-custom-background-80 text-custom-text-100": editorState[item.key],
"bg-layer-1 text-primary": editorState[item.key],
}
)}
>

View file

@ -1,6 +1,6 @@
import type { NodeViewProps } from "@tiptap/react";
import { NodeViewContent, NodeViewWrapper } from "@tiptap/react";
import React, { useState } from "react";
import { useState } from "react";
// constants
import { COLORS_LIST } from "@/constants/common";
// local components
@ -29,7 +29,7 @@ export function CustomCalloutBlock(props: CustomCalloutNodeViewProps) {
return (
<NodeViewWrapper
className="editor-callout-component group/callout-node relative bg-custom-background-90 rounded-lg text-custom-text-100 p-4 my-2 flex items-start gap-4 transition-colors duration-500 break-words"
className="editor-callout-component group/callout-node relative bg-layer-2 rounded-lg text-primary p-4 my-2 flex items-start gap-4 transition-colors duration-500 break-words"
style={{
backgroundColor: activeBackgroundColor,
}}

View file

@ -36,24 +36,24 @@ export function CalloutBlockColorSelector(props: Props) {
e.stopPropagation();
}}
className={cn(
"flex items-center gap-1 h-full whitespace-nowrap py-1 px-2.5 text-sm font-medium text-custom-text-300 hover:bg-white/10 active:bg-custom-background-80 rounded transition-colors",
"flex items-center gap-1 h-full whitespace-nowrap py-1 px-2.5 text-13 font-medium text-tertiary hover:bg-layer-1-hover active:bg-layer-1-active rounded-sm transition-colors",
{
"bg-white/10": isOpen,
"bg-layer-1": isOpen,
}
)}
disabled={disabled}
>
<span>Color</span>
<span className="text-12">Color</span>
<ChevronDownIcon className="flex-shrink-0 size-3" />
</button>
{isOpen && (
<section className="absolute top-full right-0 z-10 mt-1 rounded-md border-[0.5px] border-custom-border-300 bg-custom-background-100 p-2 shadow-custom-shadow-rg animate-in fade-in slide-in-from-top-1">
<section className="absolute top-full right-0 z-10 mt-1 rounded-md border-[0.5px] border-strong bg-surface-1 p-2 shadow-custom-shadow-rg animate-in fade-in slide-in-from-top-1">
<div className="flex items-center gap-2">
{COLORS_LIST.map((color) => (
<button
key={color.key}
type="button"
className="flex-shrink-0 size-6 rounded border-[0.5px] border-custom-border-400 hover:opacity-60 transition-opacity"
className="flex-shrink-0 size-6 rounded-sm border-[0.5px] border-strong-1 hover:opacity-60 transition-opacity"
style={{
backgroundColor: color.backgroundColor,
}}
@ -62,7 +62,7 @@ export function CalloutBlockColorSelector(props: Props) {
))}
<button
type="button"
className="flex-shrink-0 size-6 grid place-items-center rounded text-custom-text-300 border-[0.5px] border-custom-border-400 hover:bg-custom-background-80 transition-colors"
className="flex-shrink-0 size-6 grid place-items-center rounded-sm text-tertiary border-[0.5px] border-strong-1 hover:bg-layer-1-hover transition-colors"
onClick={() => handleColorSelect(null)}
>
<Ban className="size-4" />

View file

@ -37,8 +37,8 @@ export function CalloutBlockLogoSelector(props: Props) {
isOpen={isOpen}
handleToggle={handleOpen}
className="flex-shrink-0 grid place-items-center"
buttonClassName={cn("flex-shrink-0 size-8 grid place-items-center rounded-lg", {
"hover:bg-white/10": !disabled,
buttonClassName={cn("flex-shrink-0 size-8 grid place-items-center rounded-lg text-primary", {
"hover:bg-layer-1-hover": !disabled,
})}
label={<Logo logo={logoValue} size={18} type="lucide" />}
onChange={(val) => {

View file

@ -35,7 +35,7 @@ export const CustomCodeInlineExtension = Mark.create<InlineCodeOptions>({
return {
HTMLAttributes: {
class:
"rounded bg-custom-background-80 px-[6px] py-[1.5px] font-mono font-medium text-orange-500 border-[0.5px] border-custom-border-200",
"rounded-sm bg-layer-1 px-[6px] py-[1.5px] font-mono font-medium text-orange-500 border-[0.5px] border-subtle",
spellcheck: "false",
},
};

View file

@ -38,7 +38,7 @@ export function CodeBlockComponent({ node }: Props) {
<button
type="button"
className={cn(
"group/button hidden group-hover/code:flex items-center justify-center absolute top-2 right-2 z-10 size-8 rounded-md bg-custom-background-80 border border-custom-border-200 transition duration-150 ease-in-out backdrop-blur-sm",
"group/button hidden group-hover/code:flex items-center justify-center absolute top-2 right-2 z-10 size-8 rounded-md bg-layer-2 border border-subtle transition duration-150 ease-in-out backdrop-blur-sm",
{
"bg-green-500/30 hover:bg-green-500/30 active:bg-green-500/30": copied,
}
@ -48,12 +48,12 @@ export function CodeBlockComponent({ node }: Props) {
{copied ? (
<CheckIcon className="h-3 w-3 text-green-500" strokeWidth={3} />
) : (
<CopyIcon className="h-3 w-3 text-custom-text-300 group-hover/button:text-custom-text-100" />
<CopyIcon className="h-3 w-3 text-tertiary group-hover/button:text-primary" />
)}
</button>
</Tooltip>
<pre className="bg-custom-background-90 text-custom-text-100 rounded-lg p-4 my-2">
<pre className="bg-layer-2 text-primary rounded-lg p-4 my-2">
<NodeViewContent as="code" className="whitespace-pre-wrap" />
</pre>
</NodeViewWrapper>

View file

@ -234,10 +234,7 @@ export function CustomImageBlock(props: CustomImageBlockProps) {
}}
>
{showImageLoader && (
<div
className="animate-pulse bg-custom-background-80 rounded-md"
style={{ width: size.width, height: size.height }}
/>
<div className="animate-pulse bg-layer-2 rounded-md" style={{ width: size.width, height: size.height }} />
)}
<img
ref={imageRef}
@ -307,13 +304,13 @@ export function CustomImageBlock(props: CustomImageBlockProps) {
/>
)}
{selected && displayedImageSrc === resolvedImageSrc && (
<div className="absolute inset-0 size-full bg-custom-primary-500/30 pointer-events-none" />
<div className="absolute inset-0 size-full bg-accent-primary/30 pointer-events-none" />
)}
{showImageResizer && (
<>
<div
className={cn(
"absolute inset-0 border-2 border-custom-primary-100 pointer-events-none rounded-md transition-opacity duration-100 ease-in-out",
"absolute inset-0 border-2 border-accent-strong pointer-events-none rounded-md transition-opacity duration-100 ease-in-out",
{
"opacity-100": isResizing,
"opacity-0 group-hover/image-component:opacity-100": !isResizing,
@ -322,7 +319,7 @@ export function CustomImageBlock(props: CustomImageBlockProps) {
/>
<div
className={cn(
"absolute bottom-0 translate-y-1/2 size-4 rounded-full bg-custom-primary-100 border-2 border-white transition-opacity duration-100 ease-in-out",
"absolute bottom-0 translate-y-1/2 size-4 rounded-full bg-accent-primary border-2 border-white transition-opacity duration-100 ease-in-out",
{
"opacity-100 pointer-events-auto": isResizing,
"opacity-0 pointer-events-none group-hover/image-component:opacity-100 group-hover/image-component:pointer-events-auto":

View file

@ -34,7 +34,7 @@ export function ImageAlignmentAction(props: Props) {
<Tooltip disabled={isTouchDevice} tooltipContent="Align">
<button
type="button"
className="h-full flex items-center gap-1 text-white/60 hover:text-white transition-colors"
className="h-full flex items-center gap-1 text-on-color/60 hover:text-on-color transition-colors"
onClick={() => setIsDropdownOpen((prev) => !prev)}
>
{activeAlignmentDetails && <activeAlignmentDetails.icon className="flex-shrink-0 size-3" />}
@ -42,12 +42,12 @@ export function ImageAlignmentAction(props: Props) {
</button>
</Tooltip>
{isDropdownOpen && (
<div className="absolute top-full left-1/2 -translate-x-1/2 mt-0.5 h-7 bg-black/80 flex items-center gap-2 px-2 rounded">
<div className="absolute top-full left-1/2 -translate-x-1/2 mt-0.5 h-7 bg-black/80 flex items-center gap-2 px-2 rounded-sm">
{IMAGE_ALIGNMENT_OPTIONS.map((option) => (
<Tooltip disabled={isTouchDevice} key={option.value} tooltipContent={option.label}>
<button
type="button"
className="flex-shrink-0 h-full grid place-items-center text-white/60 hover:text-white transition-colors"
className="flex-shrink-0 h-full grid place-items-center text-on-color/60 hover:text-on-color transition-colors"
onClick={() => {
handleChange(option.value);
setIsDropdownOpen(false);

View file

@ -14,7 +14,7 @@ export function ImageDownloadAction(props: Props) {
<button
type="button"
onClick={() => window.open(src, "_blank")}
className="flex-shrink-0 h-full grid place-items-center text-white/60 hover:text-white transition-colors"
className="flex-shrink-0 h-full grid place-items-center text-on-color/60 hover:text-on-color transition-colors"
aria-label="Download image"
>
<Download className="size-3" />

View file

@ -213,7 +213,7 @@ function ImageFullScreenModalWithoutPortal(props: Props) {
className="absolute top-10 right-10 size-8 grid place-items-center"
aria-label="Close image viewer"
>
<CloseIcon className="size-8 text-white/60 hover:text-white transition-colors" />
<CloseIcon className="size-8 text-on-color/60 hover:text-on-color transition-colors" />
</button>
<img
ref={setImageRef}
@ -242,13 +242,13 @@ function ImageFullScreenModalWithoutPortal(props: Props) {
}
handleMagnification("decrease");
}}
className="size-6 grid place-items-center text-white/60 hover:text-white disabled:text-white/30 transition-colors duration-200"
className="size-6 grid place-items-center text-on-color/60 hover:text-on-color disabled:text-on-color/30 transition-colors duration-200"
disabled={magnification <= MIN_ZOOM}
aria-label="Zoom out"
>
<Minus className="size-4" />
</button>
<span className="text-sm w-12 text-center text-white">{Math.round(100 * magnification)}%</span>
<span className="text-13 w-12 text-center text-on-color">{Math.round(100 * magnification)}%</span>
<button
type="button"
onClick={(e) => {
@ -258,7 +258,7 @@ function ImageFullScreenModalWithoutPortal(props: Props) {
}
handleMagnification("increase");
}}
className="size-6 grid place-items-center text-white/60 hover:text-white disabled:text-white/30 transition-colors duration-200"
className="size-6 grid place-items-center text-on-color/60 hover:text-on-color disabled:text-on-color/30 transition-colors duration-200"
disabled={magnification >= MAX_ZOOM}
aria-label="Zoom in"
>
@ -269,7 +269,7 @@ function ImageFullScreenModalWithoutPortal(props: Props) {
<button
type="button"
onClick={() => window.open(downloadSrc, "_blank")}
className="flex-shrink-0 size-8 grid place-items-center text-white/60 hover:text-white transition-colors duration-200"
className="flex-shrink-0 size-8 grid place-items-center text-on-color/60 hover:text-on-color transition-colors duration-200"
aria-label="Download image"
>
<Download className="size-4" />
@ -279,7 +279,7 @@ function ImageFullScreenModalWithoutPortal(props: Props) {
<button
type="button"
onClick={() => window.open(src, "_blank")}
className="flex-shrink-0 size-8 grid place-items-center text-white/60 hover:text-white transition-colors duration-200"
className="flex-shrink-0 size-8 grid place-items-center text-on-color/60 hover:text-on-color transition-colors duration-200"
aria-label="Open image in new tab"
>
<ExternalLink className="size-4" />

View file

@ -47,7 +47,7 @@ export function ImageFullScreenActionRoot(props: Props) {
e.stopPropagation();
setIsFullScreenEnabled(true);
}}
className="flex-shrink-0 h-full grid place-items-center text-white/60 hover:text-white transition-colors"
className="flex-shrink-0 h-full grid place-items-center text-on-color/60 hover:text-on-color transition-colors"
aria-label="View image in full screen"
>
<Maximize className="size-3" />

View file

@ -31,7 +31,7 @@ export function ImageToolbarRoot(props: Props) {
<>
<div
className={cn(
"absolute top-1 right-1 h-7 z-20 bg-black/80 rounded flex items-center gap-2 px-2 opacity-0 pointer-events-none group-hover/image-component:opacity-100 group-hover/image-component:pointer-events-auto transition-opacity",
"absolute top-1 right-1 h-7 z-20 bg-black/80 rounded-sm flex items-center gap-2 px-2 opacity-0 pointer-events-none group-hover/image-component:opacity-100 group-hover/image-component:pointer-events-auto transition-opacity",
{
"opacity-100 pointer-events-auto": shouldShowToolbar,
}

View file

@ -53,7 +53,7 @@ export function ImageUploadStatus(props: Props) {
if (uploadStatus === undefined) return null;
return (
<div className="absolute top-1 right-1 z-20 bg-black/60 rounded text-xs font-medium w-10 text-center">
<div className="absolute top-1 right-1 z-20 bg-black/60 rounded-sm text-11 font-medium w-10 text-center">
{displayStatus}%
</div>
);

View file

@ -168,9 +168,16 @@ export function CustomImageUploader(props: CustomImageUploaderProps) {
[uploadFile, editor, getPos]
);
const isErrorState = failedToLoadImage || hasDuplicationFailed;
const borderColor =
selected && editor.isEditable && !isErrorState
? "color-mix(in srgb, var(--border-color-accent-strong) 20%, transparent)"
: undefined;
const getDisplayMessage = useCallback(() => {
const isUploading = isImageBeingUploaded;
if (failedToLoadImage || hasDuplicationFailed) {
if (isErrorState) {
return "Error loading image";
}
@ -183,7 +190,7 @@ export function CustomImageUploader(props: CustomImageUploaderProps) {
}
return "Add an image";
}, [draggedInside, editor.isEditable, failedToLoadImage, isImageBeingUploaded, hasDuplicationFailed]);
}, [draggedInside, editor.isEditable, isErrorState, isImageBeingUploaded]);
const handleRetryClick = useCallback(
(e: React.MouseEvent) => {
@ -198,18 +205,20 @@ export function CustomImageUploader(props: CustomImageUploaderProps) {
return (
<div
className={cn(
"image-upload-component flex items-center justify-start gap-2 py-3 px-2 rounded-lg text-custom-text-300 bg-custom-background-90 border border-dashed border-custom-border-300 transition-all duration-200 ease-in-out cursor-default",
"image-upload-component flex items-center justify-start gap-2 py-3 px-2 rounded-lg text-tertiary bg-layer-2 border border-dashed transition-all duration-200 ease-in-out cursor-default",
{
"hover:text-custom-text-200 hover:bg-custom-background-80 cursor-pointer": editor.isEditable,
"bg-custom-background-80 text-custom-text-200": draggedInside && editor.isEditable,
"text-custom-primary-200 bg-custom-primary-100/10 border-custom-primary-200/10 hover:bg-custom-primary-100/10 hover:text-custom-primary-200":
selected && editor.isEditable,
"text-red-500 cursor-default": failedToLoadImage || hasDuplicationFailed,
"hover:text-red-500": (failedToLoadImage || hasDuplicationFailed) && editor.isEditable,
"bg-red-500/10": (failedToLoadImage || hasDuplicationFailed) && selected,
"hover:bg-red-500/10": (failedToLoadImage || hasDuplicationFailed) && selected && editor.isEditable,
"border-subtle": !(selected && editor.isEditable && !isErrorState),
"hover:text-secondary hover:bg-layer-2-hover cursor-pointer": editor.isEditable && !isErrorState,
"bg-layer-2-hover text-secondary": draggedInside && editor.isEditable && !isErrorState,
"text-accent-secondary bg-accent-primary/10 hover:bg-accent-primary/10 hover:text-accent-secondary":
selected && editor.isEditable && !isErrorState,
"text-red-500 cursor-default": isErrorState,
"hover:text-red-500 hover:bg-red-500/10": isErrorState && editor.isEditable,
"bg-red-500/10": isErrorState && selected,
"hover:bg-red-500/20": isErrorState && selected && editor.isEditable,
}
)}
style={borderColor ? { borderColor } : undefined}
onDrop={onDrop}
onDragOver={onDragEnter}
onDragLeave={onDragLeave}
@ -221,13 +230,13 @@ export function CustomImageUploader(props: CustomImageUploaderProps) {
}}
>
<ImageIcon className="size-4" />
<div className="text-base font-medium flex-1">{getDisplayMessage()}</div>
<div className="text-14 font-medium flex-1">{getDisplayMessage()}</div>
{hasDuplicationFailed && editor.isEditable && (
<button
type="button"
onClick={handleRetryClick}
className={cn(
"flex items-center gap-1 px-2 py-1 text-xs font-medium text-custom-text-300 hover:bg-custom-background-90 hover:text-custom-text-200 rounded-md transition-all duration-200 ease-in-out",
"flex items-center gap-1 px-2 py-1 font-medium text-red-500 rounded-md transition-all duration-200 ease-in-out hover:bg-red-500/20 hover:text-red-500",
{
"hover:bg-red-500/20": selected,
}
@ -235,7 +244,7 @@ export function CustomImageUploader(props: CustomImageUploaderProps) {
title="Retry duplication"
>
<RotateCcw className="size-3" />
Retry
<span className="text-11">Retry</span>
</button>
)}
<input

View file

@ -124,7 +124,7 @@ export const CustomLinkExtension = Mark.create<LinkOptions, CustomLinkStorage>({
target: "_blank",
rel: "noopener noreferrer nofollow",
class:
"text-custom-primary-300 underline underline-offset-[3px] hover:text-custom-primary-500 transition-colors cursor-pointer",
"text-accent-secondary underline underline-offset-[3px] hover:text-custom-primary-500 transition-colors cursor-pointer",
},
validate: (url: string) => isValidHttpUrl(url).isValid,
};

View file

@ -124,7 +124,7 @@ export const EmojisListDropdown = forwardRef(function EmojisListDropdown(
<div
ref={dropdownContainerRef}
className={cn(
"relative max-h-80 w-[14rem] overflow-y-auto rounded-md border-[0.5px] border-custom-border-300 bg-custom-background-100 px-2 py-2.5 shadow-custom-shadow-rg space-y-2 opacity-0 invisible transition-opacity",
"relative max-h-80 w-[14rem] overflow-y-auto rounded-md border-[0.5px] border-strong bg-surface-1 px-2 py-2.5 shadow-custom-shadow-rg space-y-2 opacity-0 invisible transition-opacity",
{
"opacity-100 visible": isVisible,
}
@ -150,15 +150,15 @@ export const EmojisListDropdown = forwardRef(function EmojisListDropdown(
id={`emoji-item-${index}`}
type="button"
className={cn(
"flex items-center gap-2 w-full rounded px-2 py-1.5 text-sm text-left truncate text-custom-text-200 hover:bg-custom-background-80 transition-colors duration-150",
"flex items-center gap-2 w-full rounded-sm px-2 py-1.5 text-13 text-left truncate text-secondary hover:bg-layer-1-hover transition-colors duration-150",
{
"bg-custom-background-80": isSelected,
"bg-layer-1-hover": isSelected,
}
)}
onClick={() => selectItem(index)}
onMouseEnter={() => setSelectedIndex(index)}
>
<span className="size-5 grid place-items-center flex-shrink-0 text-base">{item.emoji}</span>
<span className="size-5 grid place-items-center flex-shrink-0 text-14">{item.emoji}</span>
<span className="flex-grow truncate">
<span className="font-medium">:{item.name}:</span>
</span>
@ -166,7 +166,7 @@ export const EmojisListDropdown = forwardRef(function EmojisListDropdown(
);
})
) : (
<div className="text-center text-sm text-custom-text-400 py-2">No emojis found</div>
<div className="text-center text-13 text-placeholder py-2">No emojis found</div>
)}
</div>
</>

View file

@ -25,7 +25,7 @@ export const CustomHorizontalRule = Node.create<HorizontalRuleOptions>({
addOptions() {
return {
HTMLAttributes: {
class: "py-4 border-custom-border-400",
class: "py-4 border-strong-1",
},
};
},

View file

@ -124,7 +124,7 @@ export const MentionsListDropdown = forwardRef(function MentionsListDropdown(pro
/>
<div
ref={dropdownContainer}
className="relative max-h-80 w-[14rem] overflow-y-auto rounded-md border-[0.5px] border-custom-border-300 bg-custom-background-100 px-2 py-2.5 shadow-custom-shadow-rg space-y-2"
className="relative max-h-80 w-[14rem] overflow-y-auto rounded-md border-[0.5px] border-strong bg-surface-1 px-2 py-2.5 shadow-custom-shadow-rg space-y-2"
style={{
zIndex: 100,
}}
@ -136,11 +136,11 @@ export const MentionsListDropdown = forwardRef(function MentionsListDropdown(pro
}}
>
{isLoading ? (
<div className="text-center text-sm text-custom-text-400">Loading...</div>
<div className="text-center text-13 text-placeholder">Loading...</div>
) : sections.length ? (
sections.map((section, sectionIndex) => (
<div key={section.key} className="space-y-2">
{section.title && <h6 className="text-xs font-semibold text-custom-text-300">{section.title}</h6>}
{section.title && <h6 className="text-11 font-semibold text-tertiary">{section.title}</h6>}
{section.items.map((item, itemIndex) => {
const isSelected = sectionIndex === selectedIndex.section && itemIndex === selectedIndex.item;
@ -150,9 +150,9 @@ export const MentionsListDropdown = forwardRef(function MentionsListDropdown(pro
id={`mention-item-${sectionIndex}-${itemIndex}`}
type="button"
className={cn(
"flex items-center gap-2 w-full rounded px-1 py-1.5 text-xs text-left truncate text-custom-text-200",
"flex items-center gap-2 w-full rounded-sm px-1 py-1.5 text-11 text-left truncate text-secondary hover:bg-layer-1-hover",
{
"bg-custom-background-80": isSelected,
"bg-layer-1-hover": isSelected,
}
)}
onClick={(e) => {
@ -169,7 +169,7 @@ export const MentionsListDropdown = forwardRef(function MentionsListDropdown(pro
>
<span className="size-5 grid place-items-center flex-shrink-0">{item.icon}</span>
{item.subTitle && (
<h5 className="whitespace-nowrap text-xs text-custom-text-300 flex-shrink-0">{item.subTitle}</h5>
<h5 className="whitespace-nowrap text-11 text-tertiary flex-shrink-0">{item.subTitle}</h5>
)}
<p className="flex-grow truncate">{item.title}</p>
</button>
@ -178,7 +178,7 @@ export const MentionsListDropdown = forwardRef(function MentionsListDropdown(pro
</div>
))
) : (
<div className="text-center text-sm text-custom-text-400">No results</div>
<div className="text-center text-13 text-placeholder">No results</div>
)}
</div>
</>

View file

@ -215,14 +215,7 @@ export const getSlashCommandFilteredSections =
title: "Default",
description: "Change text color",
searchTerms: ["color", "text", "default"],
icon: (
<ALargeSmall
className="size-3.5"
style={{
color: "rgba(var(--color-text-100))",
}}
/>
),
icon: <ALargeSmall className="size-3.5 text-primary" />,
command: ({ editor, range }) => toggleTextColor(undefined, editor, range),
},
...COLORS_LIST.map(
@ -262,7 +255,7 @@ export const getSlashCommandFilteredSections =
iconContainerStyle: {
borderRadius: "4px",
backgroundColor: "rgba(var(--color-background-100))",
border: "1px solid rgba(var(--color-border-300))",
border: "1px solid var(--border-color-strong)",
},
command: ({ editor, range }) => toggleTextColor(undefined, editor, range),
},

View file

@ -30,7 +30,7 @@ const highlightMatch = (text: string, query: string): React.ReactNode => {
return (
<>
{before}
<span className="font-medium text-custom-text-100">{match}</span>
<span className="font-medium text-primary">{match}</span>
{after}
</>
);
@ -48,9 +48,9 @@ export function CommandMenuItem(props: Props) {
type="button"
id={`item-${sectionIndex}-${itemIndex}`}
className={cn(
"flex items-center gap-2 w-full rounded px-1 py-1.5 text-sm text-left truncate text-custom-text-200",
"flex items-center gap-2 w-full rounded-sm px-1 py-1.5 text-13 text-left truncate text-secondary hover:bg-layer-1-hover",
{
"bg-custom-background-80": isSelected,
"bg-layer-1-hover": isSelected,
}
)}
onClick={onClick}
@ -59,7 +59,7 @@ export function CommandMenuItem(props: Props) {
<span className="size-5 grid place-items-center flex-shrink-0" style={item.iconContainerStyle}>
{item.icon}
</span>
<p className="flex-grow truncate">{query ? highlightMatch(item.title, query) : item.title}</p>
<p className="flex-grow truncate text-12">{query ? highlightMatch(item.title, query) : item.title}</p>
{item.badge}
</button>
);

View file

@ -131,7 +131,7 @@ export const SlashCommandsMenu = forwardRef(function SlashCommandsMenu(props: Sl
<div
id="slash-command"
ref={commandListContainer}
className="relative max-h-80 min-w-[12rem] overflow-y-auto rounded-md border-[0.5px] border-custom-border-300 bg-custom-background-100 px-2 py-2.5 shadow-custom-shadow-rg space-y-2"
className="relative max-h-80 min-w-[12rem] overflow-y-auto rounded-md border-[0.5px] border-strong bg-surface-1 px-2 py-2.5 shadow-custom-shadow-rg space-y-2"
style={{
zIndex: 100,
}}
@ -144,7 +144,7 @@ export const SlashCommandsMenu = forwardRef(function SlashCommandsMenu(props: Sl
>
{sections.map((section, sectionIndex) => (
<div key={section.key} className="space-y-2">
{section.title && <h6 className="text-xs font-semibold text-custom-text-300">{section.title}</h6>}
{section.title && <h6 className="text-11 font-semibold text-tertiary">{section.title}</h6>}
<div>
{section.items?.map((item, itemIndex) => (
<CommandMenuItem

View file

@ -10,12 +10,12 @@ export const CustomStarterKitExtension = (args: TArgs) => {
return StarterKit.configure({
bulletList: {
HTMLAttributes: {
class: "list-disc pl-7 space-y-[--list-spacing-y]",
class: "list-disc pl-7 space-y-(--list-spacing-y)",
},
},
orderedList: {
HTMLAttributes: {
class: "list-decimal pl-7 space-y-[--list-spacing-y]",
class: "list-decimal pl-7 space-y-(--list-spacing-y)",
},
},
listItem: {
@ -39,7 +39,7 @@ export const CustomStarterKitExtension = (args: TArgs) => {
},
dropcursor: {
class:
"text-custom-text-300 transition-all motion-reduce:transition-none motion-reduce:hover:transform-none duration-200 ease-[cubic-bezier(0.165, 0.84, 0.44, 1)]",
"text-tertiary transition-all motion-reduce:transition-none motion-reduce:hover:transform-none duration-200 ease-[cubic-bezier(0.165, 0.84, 0.44, 1)]",
},
...(enableHistory ? {} : { history: false }),
});

View file

@ -43,7 +43,7 @@ export function TableDragHandleDropdownColorSelector(props: Props) {
<Disclosure.Button
as="button"
type="button"
className="flex items-center justify-between gap-2 w-full rounded px-1 py-1.5 text-xs text-left truncate text-custom-text-200 hover:bg-custom-background-80"
className="flex items-center justify-between gap-2 w-full rounded-sm px-1 py-1.5 text-11 text-left truncate text-secondary hover:bg-layer-1"
>
{({ open }) => (
<>
@ -61,13 +61,13 @@ export function TableDragHandleDropdownColorSelector(props: Props) {
</Disclosure.Button>
<Disclosure.Panel className="p-1 space-y-2 mb-1.5">
{/* <div className="space-y-1.5">
<p className="text-xs text-custom-text-300 font-semibold">Text colors</p>
<p className="text-11 text-tertiary font-semibold">Text colors</p>
<div className="flex items-center flex-wrap gap-2">
{COLORS_LIST.map((color) => (
<button
key={color.key}
type="button"
className="flex-shrink-0 size-6 rounded border-[0.5px] border-custom-border-400 hover:opacity-60 transition-opacity"
className="flex-shrink-0 size-6 rounded-sm border-[0.5px] border-strong-1 hover:opacity-60 transition-opacity"
style={{
backgroundColor: color.textColor,
}}
@ -76,7 +76,7 @@ export function TableDragHandleDropdownColorSelector(props: Props) {
))}
<button
type="button"
className="flex-shrink-0 size-6 grid place-items-center rounded text-custom-text-300 border-[0.5px] border-custom-border-400 hover:bg-custom-background-80 transition-colors"
className="flex-shrink-0 size-6 grid place-items-center rounded-sm text-tertiary border-[0.5px] border-strong-1 hover:bg-layer-1 transition-colors"
onClick={() => handleTextColorChange(editor, null)}
>
<Ban className="size-4" />
@ -84,13 +84,13 @@ export function TableDragHandleDropdownColorSelector(props: Props) {
</div>
</div> */}
<div className="space-y-1">
<p className="text-xs text-custom-text-300 font-semibold">Background colors</p>
<p className="text-11 text-tertiary font-semibold">Background colors</p>
<div className="flex items-center flex-wrap gap-2">
{COLORS_LIST.map((color) => (
<button
key={color.key}
type="button"
className="flex-shrink-0 size-6 rounded border-[0.5px] border-custom-border-400 hover:opacity-60 transition-opacity"
className="flex-shrink-0 size-6 rounded-sm border-[0.5px] border-strong-1 hover:opacity-60 transition-opacity"
style={{
backgroundColor: color.backgroundColor,
}}
@ -102,7 +102,7 @@ export function TableDragHandleDropdownColorSelector(props: Props) {
))}
<button
type="button"
className="flex-shrink-0 size-6 grid place-items-center rounded text-custom-text-300 border-[0.5px] border-custom-border-400 hover:bg-custom-background-80 transition-colors"
className="flex-shrink-0 size-6 grid place-items-center rounded-sm text-tertiary border-[0.5px] border-strong-1 hover:bg-layer-1-hover transition-colors"
onClick={() => {
handleBackgroundColorChange(editor, null);
onSelect(null);

View file

@ -187,15 +187,12 @@ export function ColumnDragHandle(props: ColumnDragHandleProps) {
{...getReferenceProps()}
type="button"
onMouseDown={handleMouseDown}
className={cn(
"px-1 bg-custom-background-90 border border-custom-border-400 rounded outline-none transition-all duration-200",
{
"!opacity-100 bg-custom-primary-100 border-custom-primary-100": isDropdownOpen,
"hover:bg-custom-background-80": !isDropdownOpen,
}
)}
className={cn("px-1 bg-layer-1 border border-strong-1 rounded-sm outline-none transition-all duration-200", {
"!opacity-100 bg-accent-primary border-accent-strong": isDropdownOpen,
"hover:bg-layer-1-hover": !isDropdownOpen,
})}
>
<Ellipsis className="size-4 text-custom-text-100" />
<Ellipsis className="size-4 text-primary" />
</button>
</div>
{isDropdownOpen && (
@ -208,7 +205,7 @@ export function ColumnDragHandle(props: ColumnDragHandleProps) {
lockScroll
/>
<div
className="max-h-[90vh] w-[12rem] overflow-y-auto rounded-md border-[0.5px] border-custom-border-300 bg-custom-background-100 px-2 py-2.5 shadow-custom-shadow-rg"
className="max-h-[90vh] w-[12rem] overflow-y-auto rounded-md border-[0.5px] border-strong bg-surface-1 px-2 py-2.5 shadow-custom-shadow-rg"
ref={refs.setFloating}
{...getFloatingProps()}
style={{

View file

@ -69,7 +69,7 @@ export function ColumnOptionsDropdown(props: Props) {
<>
<button
type="button"
className="flex items-center justify-between gap-2 w-full rounded px-1 py-1.5 text-xs text-left truncate text-custom-text-200 hover:bg-custom-background-80"
className="flex items-center justify-between gap-2 w-full rounded-sm px-1 py-1.5 text-11 text-left truncate text-secondary hover:bg-layer-1"
onClick={(e) => {
e.preventDefault();
e.stopPropagation();
@ -80,13 +80,13 @@ export function ColumnOptionsDropdown(props: Props) {
<div className="flex-grow truncate">Header column</div>
<ToggleRight className="shrink-0 size-3" />
</button>
<hr className="my-2 border-custom-border-200" />
<hr className="my-2 border-subtle" />
<TableDragHandleDropdownColorSelector editor={editor} onSelect={onClose} />
{DROPDOWN_ITEMS.map((item) => (
<button
key={item.key}
type="button"
className="flex items-center gap-2 w-full rounded px-1 py-1.5 text-xs text-left truncate text-custom-text-200 hover:bg-custom-background-80"
className="flex items-center gap-2 w-full rounded-sm px-1 py-1.5 text-11 text-left truncate text-secondary hover:bg-layer-1"
onClick={(e) => {
e.preventDefault();
e.stopPropagation();

View file

@ -186,15 +186,12 @@ export function RowDragHandle(props: RowDragHandleProps) {
{...getReferenceProps()}
type="button"
onMouseDown={handleMouseDown}
className={cn(
"py-1 bg-custom-background-90 border border-custom-border-400 rounded outline-none transition-all duration-200",
{
"!opacity-100 bg-custom-primary-100 border-custom-primary-100": isDropdownOpen,
"hover:bg-custom-background-80": !isDropdownOpen,
}
)}
className={cn("py-1 bg-layer-1 border border-strong-1 rounded-sm outline-none transition-all duration-200", {
"!opacity-100 bg-accent-primary border-accent-strong": isDropdownOpen,
"hover:bg-layer-1-hover": !isDropdownOpen,
})}
>
<Ellipsis className="size-4 text-custom-text-100 rotate-90" />
<Ellipsis className="size-4 text-primary rotate-90" />
</button>
</div>
{isDropdownOpen && (
@ -207,7 +204,7 @@ export function RowDragHandle(props: RowDragHandleProps) {
lockScroll
/>
<div
className="max-h-[90vh] w-[12rem] overflow-y-auto rounded-md border-[0.5px] border-custom-border-300 bg-custom-background-100 px-2 py-2.5 shadow-custom-shadow-rg"
className="max-h-[90vh] w-[12rem] overflow-y-auto rounded-md border-[0.5px] border-strong bg-surface-1 px-2 py-2.5 shadow-custom-shadow-rg"
ref={refs.setFloating}
{...getFloatingProps()}
style={{

View file

@ -69,7 +69,7 @@ export function RowOptionsDropdown(props: Props) {
<>
<button
type="button"
className="flex items-center justify-between gap-2 w-full rounded px-1 py-1.5 text-xs text-left truncate text-custom-text-200 hover:bg-custom-background-80"
className="flex items-center justify-between gap-2 w-full rounded-sm px-1 py-1.5 text-11 text-left truncate text-secondary hover:bg-layer-1"
onClick={(e) => {
e.preventDefault();
e.stopPropagation();
@ -80,13 +80,13 @@ export function RowOptionsDropdown(props: Props) {
<div className="flex-grow truncate">Header row</div>
<ToggleRight className="shrink-0 size-3" />
</button>
<hr className="my-2 border-custom-border-200" />
<hr className="my-2 border-subtle" />
<TableDragHandleDropdownColorSelector editor={editor} onSelect={onClose} />
{DROPDOWN_ITEMS.map((item) => (
<button
key={item.key}
type="button"
className="flex items-center gap-2 w-full rounded px-1 py-1.5 text-xs text-left truncate text-custom-text-200 hover:bg-custom-background-80"
className="flex items-center gap-2 w-full rounded-sm px-1 py-1.5 text-11 text-left truncate text-secondary hover:bg-layer-1"
onClick={(e) => {
e.preventDefault();
e.stopPropagation();

View file

@ -13,7 +13,7 @@ export const constructDragPreviewTable = (): {
} => {
const tableElement = document.createElement("table");
tableElement.classList.add("table-drag-preview");
tableElement.classList.add("bg-custom-background-100");
tableElement.classList.add("bg-surface-1");
tableElement.style.opacity = "0.9";
const tableBodyElement = document.createElement("tbody");
tableElement.appendChild(tableBodyElement);

View file

@ -15,8 +15,8 @@ export const getEditorClassNames = ({ noBorder, borderOnFocus, containerClassNam
cn(
"w-full max-w-full sm:rounded-lg focus:outline-none focus:border-0",
{
"border border-custom-border-200": !noBorder,
"focus:border border-custom-border-300": borderOnFocus,
"border border-subtle-1": !noBorder,
"focus:border border-strong": borderOnFocus,
},
containerClassName
);

View file

@ -88,7 +88,7 @@ export const AIHandlePlugin = (options: SideMenuPluginProps): SideMenuHandleOpti
const view = (view: EditorView, sideMenu: HTMLDivElement | null) => {
// create handle element
const className =
"grid place-items-center font-medium size-5 aspect-square text-xs text-custom-text-300 hover:bg-custom-background-80 rounded-sm opacity-100 !outline-none z-[5] transition-[background-color,_opacity] duration-200 ease-linear";
"grid place-items-center font-medium size-5 aspect-square text-11 text-tertiary hover:bg-layer-1 rounded-xs opacity-100 !outline-none z-[5] transition-[background-color,_opacity] duration-200 ease-linear";
aiHandleElement = document.createElement("button");
aiHandleElement.type = "button";
aiHandleElement.id = "ai-handle";

View file

@ -42,13 +42,13 @@ const createDragHandleElement = (): HTMLElement => {
dragHandleElement.draggable = true;
dragHandleElement.dataset.dragHandle = "";
dragHandleElement.classList.value =
"hidden sm:flex items-center size-5 aspect-square rounded-sm cursor-grab outline-none hover:bg-custom-background-80 active:bg-custom-background-80 active:cursor-grabbing transition-[background-color,_opacity] duration-200 ease-linear";
"hidden sm:flex items-center size-5 aspect-square rounded-xs cursor-grab outline-none hover:bg-layer-1-hover active:bg-layer-1 active:cursor-grabbing transition-[background-color,_opacity] duration-200 ease-linear";
const iconElement1 = document.createElement("span");
iconElement1.classList.value = "pointer-events-none text-custom-text-300";
iconElement1.classList.value = "pointer-events-none text-tertiary";
iconElement1.innerHTML = verticalEllipsisIcon;
const iconElement2 = document.createElement("span");
iconElement2.classList.value = "pointer-events-none text-custom-text-300 -ml-2.5";
iconElement2.classList.value = "pointer-events-none text-tertiary -ml-2.5";
iconElement2.innerHTML = verticalEllipsisIcon;
dragHandleElement.appendChild(iconElement1);

View file

@ -48,7 +48,7 @@
.ProseMirror blockquote {
font-style: normal;
font-weight: 400;
border-left: 3px solid rgb(var(--color-border-300));
@apply border-l-[3px] border-strong;
}
.ProseMirror blockquote p::before,
@ -84,7 +84,7 @@
/* Custom gap cursor styles */
.ProseMirror-gapcursor::after {
border-top: 1px solid rgb(var(--color-text-100)) !important;
@apply border-t! border-strong!;
}
/* to-do list */
@ -105,14 +105,14 @@ ul[data-type="taskList"] li > div {
}
ul[data-type="taskList"] li > label input[type="checkbox"] {
border: 1px solid rgba(var(--color-text-100), 0.2) !important;
@apply border! border-strong/20!;
outline: none;
border-radius: 2px;
transform: scale(1.05);
}
.ProseMirror[contenteditable="true"] input[type="checkbox"]:hover {
background-color: rgba(var(--color-text-100), 0.1);
background-color: color-mix(in srgb, var(--text-color-primary) 10%, transparent);
}
.ProseMirror[contenteditable="false"] input[type="checkbox"] {
@ -120,14 +120,14 @@ ul[data-type="taskList"] li > label input[type="checkbox"] {
}
ul[data-type="taskList"] li > label input[type="checkbox"]:checked {
background-color: rgba(var(--color-primary-100)) !important;
border-color: rgba(var(--color-primary-100)) !important;
background-color: var(--background-color-accent-primary) !important;
border-color: var(--border-color-accent-strong) !important;
color: white !important;
}
ul[data-type="taskList"] li > label input[type="checkbox"]:checked:hover {
background-color: rgba(var(--color-primary-300)) !important;
border-color: rgba(var(--color-primary-300)) !important;
background-color: var(--background-color-accent-primary-hover) !important;
border-color: var(--border-color-accent-strong) !important;
}
@media screen and (max-width: 768px) {
@ -151,12 +151,12 @@ ul[data-type="taskList"] li > label input[type="checkbox"] {
width: 0.8rem;
height: 0.8rem;
position: relative;
border: 1.5px solid rgb(var(--color-text-100));
@apply border-md border-subtle-1;
margin-right: 0.2rem;
margin-top: 0.15rem;
&:active {
background-color: rgb(var(--color-background-90));
background-color: var(--background-color-layer-1);
}
/* check sign */
@ -257,7 +257,7 @@ div[data-type="horizontalRule"] {
margin-bottom: 0;
& > div {
border-bottom: 2px solid rgb(var(--color-border-200));
@apply border-b-lg border-subtle-1;
}
}

View file

@ -3,17 +3,16 @@
padding-bottom: 26px;
table {
position: relative;
border-collapse: collapse;
table-layout: fixed;
margin: 0.5rem 0 0 0;
border: 1px solid rgba(var(--color-border-200));
@apply relative border border-subtle;
width: 100%;
td,
th {
min-width: 1em;
border: 1px solid rgba(var(--color-border-300));
@apply border border-strong;
padding: 7px 10px;
vertical-align: top;
box-sizing: border-box;
@ -38,19 +37,19 @@
}
&.selectedCell-border-top::after {
border-top: 2px solid rgba(var(--color-primary-100));
border-top: 2px solid var(--border-color-accent-strong);
}
&.selectedCell-border-left::after {
border-left: 2px solid rgba(var(--color-primary-100));
border-left: 2px solid var(--border-color-accent-strong);
}
&.selectedCell-border-bottom::after {
border-bottom: 2px solid rgba(var(--color-primary-100));
border-bottom: 2px solid var(--border-color-accent-strong);
}
&.selectedCell-border-right::after {
border-right: 2px solid rgba(var(--color-primary-100));
border-right: 2px solid var(--border-color-accent-strong);
}
}
/* End selected cell outline */
@ -81,34 +80,31 @@
}
th {
font-weight: 500;
text-align: left;
@apply font-medium text-left;
}
tr[background="none"],
tr:not([background]) {
th {
background-color: rgba(var(--color-background-90));
@apply bg-layer-2;
}
}
.table-drop-marker {
background-color: rgba(var(--color-primary-100));
position: absolute;
z-index: 10;
background-color: var(--border-color-accent-strong);
@apply absolute z-10;
&.hidden {
display: none;
@apply hidden;
}
}
.table-col-drag-marker,
.table-row-drag-marker {
position: absolute;
z-index: 10;
@apply absolute z-10;
&.hidden {
display: none;
@apply hidden;
}
}
@ -124,7 +120,7 @@
/* Selected status */
&.ProseMirror-selectednode {
table {
background-color: rgba(var(--color-primary-100), 0.2);
background-color: color-mix(in srgb, var(--background-color-accent-primary) 20%, transparent);
}
}
/* End selected status */
@ -138,7 +134,7 @@
width: 2px;
height: calc(100% + 2px);
z-index: 5;
background-color: rgba(var(--color-primary-100));
background-color: var(--border-color-accent-strong);
pointer-events: none;
}
/* End column resizer */
@ -156,9 +152,8 @@
.table-column-insert-button,
.table-row-insert-button {
position: absolute;
background-color: rgba(var(--color-background-90));
color: rgba(var(--color-text-300));
border: 1px solid rgba(var(--color-border-200));
background-color: var(--background-color-layer-1);
@apply text-tertiary border border-subtle-1;
border-radius: 4px;
display: grid;
place-items: center;
@ -169,15 +164,15 @@
transition: all 0.2s ease;
&:hover {
background-color: rgba(var(--color-background-80));
color: rgba(var(--color-text-100));
background-color: var(--background-color-layer-1-hover);
@apply text-primary;
}
&.dragging {
opacity: 1;
pointer-events: auto;
background-color: rgba(var(--color-primary-100), 0.2);
color: rgba(var(--color-text-100));
background-color: color-mix(in srgb, var(--background-color-accent-primary) 20%, transparent);
@apply text-primary;
}
svg {

View file

@ -1,3 +0,0 @@
@tailwind base;
@tailwind components;
@tailwind utilities;

View file

@ -43,7 +43,7 @@
/* font size and style */
.editor-container {
--color-placeholder: rgba(var(--color-text-100), 0.5);
--color-placeholder: --alpha(var(--text-color-primary) / 50%);
/* font sizes and line heights */
&.large-font {

View file

@ -1,6 +0,0 @@
import sharedConfig from "@plane/tailwind-config/tailwind.config.js";
export default {
// prefix ui lib classes to avoid conflicting with the app
...sharedConfig,
};

View file

@ -840,7 +840,7 @@ export default {
label: "Remove parent work item",
},
},
new: "New Work item",
new: "New work item",
adding: "Adding work item",
create: {
success: "Work item created successfully",
@ -2627,6 +2627,7 @@ export default {
copy_current_page_url: "Copy current page URL",
copy_current_page_url_toast_success: "Current page URL copied to clipboard.",
copy_current_page_url_toast_error: "Some error occurred while copying the current page URL to clipboard.",
focus_top_nav_search: "Focus search input",
},
preferences_actions: {
update_theme: "Change interface theme",

View file

@ -1,6 +1,5 @@
import type { Preview } from "@storybook/react-vite";
import "@plane/tailwind-config/global.css";
import "../src/styles/react-day-picker.css";
import "./tailwind.css";
const parameters: Preview["parameters"] = {
controls: {

View file

@ -0,0 +1,2 @@
@import "@plane/tailwind-config/index.css";
@import "../src/styles/react-day-picker.css";

View file

@ -20,6 +20,7 @@
"./accordion": "./dist/accordion/index.js",
"./animated-counter": "./dist/animated-counter/index.js",
"./avatar": "./dist/avatar/index.js",
"./badge": "./dist/badge/index.js",
"./banner": "./dist/banner/index.js",
"./button": "./dist/button/index.js",
"./calendar": "./dist/calendar/index.js",
@ -39,6 +40,7 @@
"./emoji-icon-picker": "./dist/emoji-icon-picker/index.js",
"./emoji-reaction": "./dist/emoji-reaction/index.js",
"./empty-state": "./dist/empty-state/index.js",
"./icon-button": "./dist/icon-button/index.js",
"./icons": "./dist/icons/index.js",
"./input": "./dist/input/index.js",
"./menu": "./dist/menu/index.js",
@ -66,8 +68,9 @@
"@plane/constants": "workspace:*",
"@plane/hooks": "workspace:*",
"@plane/types": "workspace:*",
"@plane/utils": "workspace:*",
"@tanstack/react-table": "^8.21.3",
"class-variance-authority": "^0.7.1",
"class-variance-authority": "0.7.1",
"clsx": "^2.1.1",
"cmdk": "^1.1.1",
"framer-motion": "^12.23.0",
@ -77,7 +80,7 @@
"react-day-picker": "9.5.0",
"react-dom": "catalog:",
"recharts": "^2.15.1",
"tailwind-merge": "^3.3.1",
"tailwind-merge": "3.4.0",
"use-font-face-observer": "^1.3.0"
},
"devDependencies": {

View file

@ -1 +1,3 @@
module.exports = require("@plane/tailwind-config/postcss.config.js");
import postcssConfig from "@plane/tailwind-config/postcss.config.js";
export default postcssConfig;

View file

@ -176,7 +176,7 @@ export const AsChildTrigger: Story = {
<Accordion.Root className="w-96">
<Accordion.Item value="item-1">
<Accordion.Trigger asChild>
<button className="w-full rounded-md bg-blue-500 px-4 py-2 text-left text-white hover:bg-blue-600">
<button className="w-full rounded-md bg-blue-500 px-4 py-2 text-left text-on-color hover:bg-blue-600">
Custom Button Trigger
</button>
</Accordion.Trigger>
@ -186,7 +186,7 @@ export const AsChildTrigger: Story = {
</Accordion.Item>
<Accordion.Item value="item-2">
<Accordion.Trigger asChild>
<button className="w-full rounded-md bg-green-500 px-4 py-2 text-left text-white hover:bg-green-600">
<button className="w-full rounded-md bg-green-500 px-4 py-2 text-left text-on-color hover:bg-green-600">
Another Custom Trigger
</button>
</Accordion.Trigger>

View file

@ -32,7 +32,7 @@ export interface AccordionContentProps {
function AccordionRoot({ defaultValue = [], allowMultiple = false, className = "", children }: AccordionRootProps) {
return (
<BaseAccordion.Root defaultValue={defaultValue} openMultiple={allowMultiple} className={`text-base ${className}`}>
<BaseAccordion.Root defaultValue={defaultValue} openMultiple={allowMultiple} className={`text-14 ${className}`}>
{children}
</BaseAccordion.Root>
);

View file

@ -26,7 +26,7 @@ export const Default: Story = {
<div className="space-y-6 p-4">
<div className="flex items-center justify-center gap-6">
<button
className="px-4 py-2 bg-red-500 text-white font-medium rounded-lg hover:bg-red-600 focus:outline-none focus:ring-2 focus:ring-red-400 focus:ring-offset-2 transition-colors shadow-md"
className="px-4 py-2 bg-red-500 text-on-color font-medium rounded-lg hover:bg-red-600 focus:outline-none focus:ring-2 focus:ring-red-400 focus:ring-offset-2 transition-colors shadow-md"
onClick={() => setCount((prev) => Math.max(0, prev - 1))}
>
-1
@ -35,7 +35,7 @@ export const Default: Story = {
<AnimatedCounter {...args} count={count} />
</div>
<button
className="px-4 py-2 bg-green-500 text-white font-medium rounded-lg hover:bg-green-600 focus:outline-none focus:ring-2 focus:ring-green-400 focus:ring-offset-2 transition-colors shadow-md"
className="px-4 py-2 bg-green-500 text-on-color font-medium rounded-lg hover:bg-green-600 focus:outline-none focus:ring-2 focus:ring-green-400 focus:ring-offset-2 transition-colors shadow-md"
onClick={() => setCount((prev) => prev + 1)}
>
+1
@ -54,13 +54,13 @@ export const Sizes: Story = {
<div className="space-y-6 p-4">
<div className="flex items-center gap-4">
<button
className="px-3 py-1 bg-custom-background-80 text-sm rounded hover:bg-custom-background-90"
className="px-3 py-1 bg-layer-1 text-13 rounded-sm hover:bg-surface-2"
onClick={() => setCount((prev) => Math.max(0, prev - 1))}
>
-1
</button>
<button
className="px-3 py-1 bg-custom-background-80 text-sm rounded hover:bg-custom-background-90"
className="px-3 py-1 bg-layer-1 text-13 rounded-sm hover:bg-surface-2"
onClick={() => setCount((prev) => prev + 1)}
>
+1
@ -68,20 +68,20 @@ export const Sizes: Story = {
</div>
<div className="flex flex-col gap-4">
<div className="flex items-center gap-4">
<span className="text-sm text-custom-text-400 w-20">Small:</span>
<div className="flex items-center justify-center min-w-[40px] h-8 bg-custom-background-80 border border-custom-border-200 rounded">
<span className="text-13 text-placeholder w-20">Small:</span>
<div className="flex items-center justify-center min-w-[40px] h-8 bg-layer-1 border border-subtle rounded-sm">
<AnimatedCounter count={count} size="sm" />
</div>
</div>
<div className="flex items-center gap-4">
<span className="text-sm text-custom-text-400 w-20">Medium:</span>
<div className="flex items-center justify-center min-w-[50px] h-10 bg-custom-background-80 border border-custom-border-200 rounded">
<span className="text-13 text-placeholder w-20">Medium:</span>
<div className="flex items-center justify-center min-w-[50px] h-10 bg-layer-1 border border-subtle rounded-sm">
<AnimatedCounter count={count} size="md" />
</div>
</div>
<div className="flex items-center gap-4">
<span className="text-sm text-custom-text-400 w-20">Large:</span>
<div className="flex items-center justify-center min-w-[60px] h-12 bg-custom-background-80 border border-custom-border-200 rounded">
<span className="text-13 text-placeholder w-20">Large:</span>
<div className="flex items-center justify-center min-w-[60px] h-12 bg-layer-1 border border-subtle rounded-sm">
<AnimatedCounter count={count} size="lg" />
</div>
</div>
@ -99,19 +99,19 @@ export const LargeNumbers: Story = {
<div className="space-y-6 p-4">
<div className="flex items-center gap-4">
<button
className="px-3 py-1 bg-red-500 text-white text-sm rounded hover:bg-red-600"
className="px-3 py-1 bg-red-500 text-on-color text-13 rounded-sm hover:bg-red-600"
onClick={() => setCount((prev) => Math.max(0, prev - 1000))}
>
-1000
</button>
<button
className="px-3 py-1 bg-green-500 text-white text-sm rounded hover:bg-green-600"
className="px-3 py-1 bg-green-500 text-on-color text-13 rounded-sm hover:bg-green-600"
onClick={() => setCount((prev) => prev + 1000)}
>
+1000
</button>
</div>
<div className="flex items-center justify-center min-w-[100px] h-12 bg-custom-background-80 border border-custom-border-200 rounded-lg">
<div className="flex items-center justify-center min-w-[100px] h-12 bg-layer-1 border border-subtle rounded-lg">
<AnimatedCounter count={count} size="lg" />
</div>
</div>
@ -142,11 +142,11 @@ export const Countdown: Story = {
return (
<div className="space-y-6 p-4">
<div className="flex flex-col items-center gap-4">
<div className="flex items-center justify-center min-w-[60px] h-16 bg-custom-background-80 border-2 border-custom-border-200 rounded-lg">
<AnimatedCounter count={count} size="lg" className="text-2xl" />
<div className="flex items-center justify-center min-w-[60px] h-16 bg-layer-1 border-2 border-subtle rounded-lg">
<AnimatedCounter count={count} size="lg" className="text-20" />
</div>
<button
className="px-6 py-2 bg-custom-primary-100 text-white font-medium rounded-lg hover:bg-custom-primary-200"
className="px-6 py-2 bg-accent-primary text-on-color font-medium rounded-lg hover:bg-accent-primary/80"
onClick={handleStart}
disabled={isRunning}
>
@ -173,26 +173,26 @@ export const LiveCounter: Story = {
return (
<div className="space-y-6 p-4">
<div className="flex flex-col items-center gap-4">
<div className="flex items-center justify-center min-w-[80px] h-16 bg-custom-background-80 border-2 border-custom-border-200 rounded-lg">
<AnimatedCounter count={count} size="lg" className="text-2xl" />
<div className="flex items-center justify-center min-w-[80px] h-16 bg-layer-1 border-2 border-subtle rounded-lg">
<AnimatedCounter count={count} size="lg" className="text-20" />
</div>
<div className="flex gap-2">
<button
className="px-4 py-2 bg-green-500 text-white font-medium rounded hover:bg-green-600"
className="px-4 py-2 bg-green-500 text-on-color font-medium rounded-sm hover:bg-green-600"
onClick={() => setIsRunning(true)}
disabled={isRunning}
>
Start
</button>
<button
className="px-4 py-2 bg-red-500 text-white font-medium rounded hover:bg-red-600"
className="px-4 py-2 bg-red-500 text-on-color font-medium rounded-sm hover:bg-red-600"
onClick={() => setIsRunning(false)}
disabled={!isRunning}
>
Stop
</button>
<button
className="px-4 py-2 bg-gray-500 text-white font-medium rounded hover:bg-gray-600"
className="px-4 py-2 bg-gray-500 text-on-color font-medium rounded-sm hover:bg-gray-600"
onClick={() => {
setIsRunning(false);
setCount(0);
@ -215,49 +215,49 @@ export const MultipleCounters: Story = {
return (
<div className="space-y-6 p-4">
<div className="max-w-md border border-custom-border-200 rounded-lg p-4">
<div className="max-w-md border border-subtle rounded-lg p-4">
<div className="flex items-center justify-between mb-4">
<h3 className="font-medium">Engagement Stats</h3>
</div>
<div className="flex gap-4">
<div className="flex-1 flex flex-col items-center gap-2">
<div className="text-custom-text-400 text-sm">Likes</div>
<div className="text-placeholder text-13">Likes</div>
<div className="flex items-center gap-2">
<button
className="w-8 h-8 flex items-center justify-center bg-custom-background-80 rounded hover:bg-custom-background-90"
className="w-8 h-8 flex items-center justify-center bg-layer-1 rounded-sm hover:bg-surface-2"
onClick={() => setLikes((prev) => prev + 1)}
>
+
</button>
<div className="flex items-center justify-center min-w-[40px] h-10 bg-custom-background-80 border border-custom-border-200 rounded">
<div className="flex items-center justify-center min-w-[40px] h-10 bg-layer-1 border border-subtle rounded-sm">
<AnimatedCounter count={likes} size="md" />
</div>
</div>
</div>
<div className="flex-1 flex flex-col items-center gap-2">
<div className="text-custom-text-400 text-sm">Comments</div>
<div className="text-placeholder text-13">Comments</div>
<div className="flex items-center gap-2">
<button
className="w-8 h-8 flex items-center justify-center bg-custom-background-80 rounded hover:bg-custom-background-90"
className="w-8 h-8 flex items-center justify-center bg-layer-1 rounded-sm hover:bg-surface-2"
onClick={() => setComments((prev) => prev + 1)}
>
+
</button>
<div className="flex items-center justify-center min-w-[40px] h-10 bg-custom-background-80 border border-custom-border-200 rounded">
<div className="flex items-center justify-center min-w-[40px] h-10 bg-layer-1 border border-subtle rounded-sm">
<AnimatedCounter count={comments} size="md" />
</div>
</div>
</div>
<div className="flex-1 flex flex-col items-center gap-2">
<div className="text-custom-text-400 text-sm">Shares</div>
<div className="text-placeholder text-13">Shares</div>
<div className="flex items-center gap-2">
<button
className="w-8 h-8 flex items-center justify-center bg-custom-background-80 rounded hover:bg-custom-background-90"
className="w-8 h-8 flex items-center justify-center bg-layer-1 rounded-sm hover:bg-surface-2"
onClick={() => setShares((prev) => prev + 1)}
>
+
</button>
<div className="flex items-center justify-center min-w-[40px] h-10 bg-custom-background-80 border border-custom-border-200 rounded">
<div className="flex items-center justify-center min-w-[40px] h-10 bg-layer-1 border border-subtle rounded-sm">
<AnimatedCounter count={shares} size="md" />
</div>
</div>
@ -277,15 +277,13 @@ export const InBadge: Story = {
<div className="space-y-6 p-4">
<div className="flex flex-col items-center gap-4">
<div className="relative">
<button className="px-4 py-2 bg-custom-background-80 border border-custom-border-200 rounded-lg">
Notifications
</button>
<div className="absolute -top-2 -right-2 min-w-[24px] h-6 flex items-center justify-center bg-red-500 text-white rounded-full px-1.5">
<AnimatedCounter count={notifications} size="sm" className="text-xs font-medium" />
<button className="px-4 py-2 bg-layer-1 border border-subtle rounded-lg">Notifications</button>
<div className="absolute -top-2 -right-2 min-w-[24px] h-6 flex items-center justify-center bg-red-500 text-on-color rounded-full px-1.5">
<AnimatedCounter count={notifications} size="sm" className="text-11 font-medium" />
</div>
</div>
<button
className="px-4 py-2 bg-custom-primary-100 text-white rounded hover:bg-custom-primary-200"
className="px-4 py-2 bg-accent-primary text-on-color rounded-sm hover:bg-accent-primary/80"
onClick={() => setNotifications((prev) => prev + 1)}
>
Add Notification
@ -309,20 +307,17 @@ export const FastAnimation: Story = {
return (
<div className="space-y-6 p-4">
<div className="flex flex-col items-center gap-4">
<div className="flex items-center justify-center min-w-[60px] h-12 bg-custom-background-80 border border-custom-border-200 rounded-lg">
<div className="flex items-center justify-center min-w-[60px] h-12 bg-layer-1 border border-subtle rounded-lg">
<AnimatedCounter count={count} size="lg" />
</div>
<div className="flex gap-2">
<button
className="px-4 py-2 bg-custom-primary-100 text-white rounded hover:bg-custom-primary-200"
className="px-4 py-2 bg-accent-primary text-on-color rounded-sm hover:bg-accent-primary/80"
onClick={incrementFast}
>
+10 Fast
</button>
<button
className="px-4 py-2 bg-custom-background-80 rounded hover:bg-custom-background-90"
onClick={() => setCount(0)}
>
<button className="px-4 py-2 bg-layer-1 rounded-sm hover:bg-surface-2" onClick={() => setCount(0)}>
Reset
</button>
</div>

View file

@ -8,9 +8,9 @@ export interface AnimatedCounterProps {
}
const sizeClasses = {
sm: "text-xs",
md: "text-sm",
lg: "text-base",
sm: "text-11",
md: "text-13",
lg: "text-14",
};
export function AnimatedCounter({ count, className, size = "md" }: AnimatedCounterProps) {
@ -51,17 +51,15 @@ export function AnimatedCounter({ count, className, size = "md" }: AnimatedCount
key={`prev-${animationKey}`}
className={cn(
"absolute inset-0 flex items-center justify-center font-medium",
"animate-[slideOut_0.25s_ease-out_forwards]",
"animate-slide-out",
direction === "up" && "[--slide-out-dir:-100%]",
direction === "down" && "[--slide-out-dir:100%]",
sizeClass
sizeClass,
{
"animate-slide-out animate-fade-out": isAnimating && direction === "up",
"animate-slide-out-down animate-fade-out": isAnimating && direction === "down",
}
)}
style={{
animation:
direction === "up"
? "slideOut 0.25s ease-out forwards, fadeOut 0.25s ease-out forwards"
: "slideOutDown 0.25s ease-out forwards, fadeOut 0.25s ease-out forwards",
}}
>
{prevCount}
</span>
@ -72,21 +70,14 @@ export function AnimatedCounter({ count, className, size = "md" }: AnimatedCount
key={`current-${animationKey}`}
className={cn(
"flex items-center justify-center font-medium",
isAnimating && "animate-[slideIn_0.25s_ease-out_forwards]",
!isAnimating && "opacity-100",
sizeClass,
{
"animate-slide-in-from-bottom": isAnimating && direction === "up",
"animate-slide-in-from-top": isAnimating && direction === "down",
},
className
)}
style={
isAnimating
? {
animation:
direction === "up"
? "slideInFromBottom 0.25s ease-out forwards"
: "slideInFromTop 0.25s ease-out forwards",
}
: undefined
}
>
{displayCount}
</span>

View file

@ -26,31 +26,31 @@ export const getSizeInfo = (size: TAvatarSize) => {
case "sm":
return {
avatarSize: "h-4 w-4",
fontSize: "text-xs",
fontSize: "text-11",
spacing: "-space-x-1",
};
case "md":
return {
avatarSize: "h-5 w-5",
fontSize: "text-xs",
fontSize: "text-11",
spacing: "-space-x-1",
};
case "base":
return {
avatarSize: "h-6 w-6",
fontSize: "text-sm",
fontSize: "text-13",
spacing: "-space-x-1.5",
};
case "lg":
return {
avatarSize: "h-7 w-7",
fontSize: "text-sm",
fontSize: "text-13",
spacing: "-space-x-1.5",
};
default:
return {
avatarSize: "h-5 w-5",
fontSize: "text-xs",
fontSize: "text-11",
spacing: "-space-x-1",
};
}
@ -66,7 +66,7 @@ export const getBorderRadius = (shape: "circle" | "square") => {
case "circle":
return "rounded-full";
case "square":
return "rounded";
return "rounded-sm";
default:
return "rounded-full";
}

View file

@ -0,0 +1,148 @@
import type { Meta, StoryObj } from "@storybook/react-vite";
import { Badge } from "./badge";
const meta = {
title: "Components/Badge",
component: Badge,
parameters: {
layout: "centered",
},
tags: ["autodocs"],
args: {
children: "Badge",
},
} satisfies Meta<typeof Badge>;
export default meta;
type Story = StoryObj<typeof meta>;
export const Default: Story = {};
export const Neutral: Story = {
args: {
variant: "neutral",
children: "Neutral Badge",
},
};
export const Brand: Story = {
args: {
variant: "brand",
children: "Brand Badge",
},
};
export const Warning: Story = {
args: {
variant: "warning",
children: "Warning Badge",
},
};
export const Success: Story = {
args: {
variant: "success",
children: "Success Badge",
},
};
export const Danger: Story = {
args: {
variant: "danger",
children: "Danger Badge",
},
};
export const Small: Story = {
args: {
size: "sm",
children: "Small Badge",
},
};
export const Base: Story = {
args: {
size: "base",
children: "Base Badge",
},
};
export const Large: Story = {
args: {
size: "lg",
children: "Large Badge",
},
};
export const WithPrependIcon: Story = {
args: {
prependIcon: (
<svg
width="16"
height="16"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
>
<path d="M12 5v14m-7-7h14" />
</svg>
),
children: "With Prepend Icon",
},
};
export const WithAppendIcon: Story = {
args: {
appendIcon: (
<svg
width="16"
height="16"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
>
<path d="M9 5l7 7-7 7" />
</svg>
),
children: "With Append Icon",
},
};
export const AllVariants: Story = {
render() {
return (
<div className="space-y-4">
<div className="space-y-2">
<h3 className="text-16 font-semibold">Primary Variants</h3>
<div className="flex flex-wrap gap-2">
<Badge variant="neutral">Neutral</Badge>
<Badge variant="brand">Brand</Badge>
<Badge variant="warning">Warning</Badge>
<Badge variant="success">Success</Badge>
<Badge variant="danger">Danger</Badge>
</div>
</div>
</div>
);
},
};
export const AllSizes: Story = {
render() {
return (
<div className="space-y-4">
<div className="flex items-center gap-2">
<Badge size="sm">Small</Badge>
<Badge size="base">Base</Badge>
<Badge size="lg">Large</Badge>
</div>
</div>
);
},
};

View file

@ -0,0 +1,22 @@
import * as React from "react";
import { cn } from "../utils";
import type { BadgeProps } from "./helper";
import { getBadgeIconStyling, badgeVariants } from "./helper";
const Badge = React.forwardRef(function Badge(props: BadgeProps, ref: React.ForwardedRef<HTMLSpanElement>) {
const { variant = "neutral", size = "base", prependIcon = null, appendIcon = null, children, ...rest } = props;
const badgeIconStyle = getBadgeIconStyling(size ?? "base");
return (
<span ref={ref} className={cn(badgeVariants({ variant, size }))} {...rest}>
{prependIcon && React.cloneElement(prependIcon, { className: cn("shrink-0", badgeIconStyle), strokeWidth: 2 })}
{children}
{appendIcon && React.cloneElement(appendIcon, { className: cn("shrink-0", badgeIconStyle), strokeWidth: 2 })}
</span>
);
});
Badge.displayName = "plane-ui-badge";
export { Badge };

View file

@ -0,0 +1,46 @@
import type { VariantProps } from "class-variance-authority";
import { cva } from "class-variance-authority";
export const badgeVariants = cva("inline-flex items-center justify-center gap-1 whitespace-nowrap transition-colors", {
variants: {
variant: {
neutral: "bg-layer-3 text-tertiary",
brand: "bg-accent-subtle-hover text-accent-primary",
warning: "bg-warning-subtle text-warning",
success: "bg-success-subtle-1 text-success",
danger: "bg-danger-subtle text-danger",
},
size: {
sm: "h-4 px-1 text-caption-sm-medium rounded-sm",
base: "h-5 px-1.5 text-caption-sm-medium rounded-md",
lg: "h-6 px-2 text-caption-md-medium rounded-md",
},
},
defaultVariants: {
variant: "neutral",
size: "base",
},
});
export type BadgeProps = Omit<React.HTMLAttributes<HTMLSpanElement>, "className"> &
VariantProps<typeof badgeVariants> & {
appendIcon?: React.ReactElement;
prependIcon?: React.ReactElement;
};
export type TBadgeVariant = NonNullable<BadgeProps["variant"]>;
export type TBadgeSize = NonNullable<BadgeProps["size"]>;
const badgeIconStyling: Record<TBadgeSize, string> = {
sm: "size-3.5",
base: "size-3.5",
lg: "size-4",
};
export function getBadgeIconStyling(size: TBadgeSize): string {
return badgeIconStyling[size];
}
export function getBadgeStyling(variant: TBadgeVariant, size: TBadgeSize): string {
return badgeVariants({ variant, size });
}

View file

@ -0,0 +1,3 @@
export { Badge } from "./badge";
export { getBadgeStyling } from "./helper";
export type { BadgeProps, TBadgeVariant, TBadgeSize } from "./helper";

View file

@ -116,7 +116,7 @@ function CloseButton({ onClick }: { onClick?: () => void }) {
return (
<button
onClick={onClick}
className="rounded p-1 hover:bg-black/5 dark:hover:bg-white/5 transition-colors"
className="rounded-sm p-1 hover:bg-black/5 dark:hover:bg-white/5 transition-colors"
aria-label="Dismiss"
>
<svg

View file

@ -7,7 +7,7 @@ export interface IBannerStyling {
export const bannerSizeStyling = {
container: "py-3 px-6 h-12",
icon: "w-5 h-5",
title: "text-sm",
title: "text-13",
action: "gap-2",
};
@ -33,14 +33,14 @@ export const getBannerStyling = (variant: TBannerVariant): string => {
// Get title styling
export const getBannerTitleStyling = (): string =>
`font-medium text-custom-text-200 flex-1 min-w-0 ${bannerSizeStyling.title}`;
`font-medium text-secondary flex-1 min-w-0 ${bannerSizeStyling.title}`;
// Get action container styling
export const getBannerActionStyling = (): string => `flex items-center flex-shrink-0 ${bannerSizeStyling.action}`;
// Get dismiss button styling
export const getBannerDismissStyling = (): string =>
"rounded p-1 hover:bg-custom-background-90 transition-colors flex-shrink-0";
"rounded-sm p-1 hover:bg-surface-2 transition-colors flex-shrink-0";
// Get dismiss icon styling
export const getBannerDismissIconStyling = (): string => "text-custom-text-200";
export const getBannerDismissIconStyling = (): string => "text-secondary";

View file

@ -25,73 +25,45 @@ export const Primary: Story = {
},
};
export const AccentPrimary: Story = {
export const ErrorFill: Story = {
args: {
variant: "accent-primary",
children: "Accent Primary Button",
variant: "error-fill",
children: "Error Button",
},
};
export const OutlinePrimary: Story = {
export const ErrorOutline: Story = {
args: {
variant: "outline-primary",
children: "Outline Primary Button",
variant: "error-outline",
children: "Error Outline Button",
},
};
export const NeutralPrimary: Story = {
export const Secondary: Story = {
args: {
variant: "neutral-primary",
children: "Neutral Primary Button",
variant: "secondary",
children: "Secondary Button",
},
};
export const LinkPrimary: Story = {
export const Tertiary: Story = {
args: {
variant: "link-primary",
children: "Link Primary Button",
variant: "tertiary",
children: "Tertiary Button",
},
};
export const Danger: Story = {
export const Ghost: Story = {
args: {
variant: "danger",
children: "Danger Button",
variant: "ghost",
children: "Ghost Button",
},
};
export const AccentDanger: Story = {
export const Link: Story = {
args: {
variant: "accent-danger",
children: "Accent Danger Button",
},
};
export const OutlineDanger: Story = {
args: {
variant: "outline-danger",
children: "Outline Danger Button",
},
};
export const LinkDanger: Story = {
args: {
variant: "link-danger",
children: "Link Danger Button",
},
};
export const TertiaryDanger: Story = {
args: {
variant: "tertiary-danger",
children: "Tertiary Danger Button",
},
};
export const LinkNeutral: Story = {
args: {
variant: "link-neutral",
children: "Link Neutral Button",
variant: "link",
children: "Link Button",
},
};
@ -102,10 +74,10 @@ export const Small: Story = {
},
};
export const Medium: Story = {
export const Base: Story = {
args: {
size: "md",
children: "Medium Button",
size: "base",
children: "Base Button",
},
};
@ -182,29 +154,15 @@ export const AllVariants: Story = {
return (
<div className="space-y-4">
<div className="space-y-2">
<h3 className="text-lg font-semibold">Primary Variants</h3>
<h3 className="text-16 font-semibold">Primary Variants</h3>
<div className="flex flex-wrap gap-2">
<Button variant="primary">Primary</Button>
<Button variant="accent-primary">Accent Primary</Button>
<Button variant="outline-primary">Outline Primary</Button>
<Button variant="neutral-primary">Neutral Primary</Button>
<Button variant="link-primary">Link Primary</Button>
</div>
</div>
<div className="space-y-2">
<h3 className="text-lg font-semibold">Danger Variants</h3>
<div className="flex flex-wrap gap-2">
<Button variant="danger">Danger</Button>
<Button variant="accent-danger">Accent Danger</Button>
<Button variant="outline-danger">Outline Danger</Button>
<Button variant="link-danger">Link Danger</Button>
<Button variant="tertiary-danger">Tertiary Danger</Button>
</div>
</div>
<div className="space-y-2">
<h3 className="text-lg font-semibold">Other Variants</h3>
<div className="flex flex-wrap gap-2">
<Button variant="link-neutral">Link Neutral</Button>
<Button variant="error-fill">Error Fill</Button>
<Button variant="error-outline">Error Outline</Button>
<Button variant="secondary">Secondary</Button>
<Button variant="tertiary">Tertiary</Button>
<Button variant="ghost">Ghost</Button>
<Button variant="link">Link</Button>
</div>
</div>
</div>
@ -218,7 +176,7 @@ export const AllSizes: Story = {
<div className="space-y-4">
<div className="flex items-center gap-2">
<Button size="sm">Small</Button>
<Button size="md">Medium</Button>
<Button size="base">Base</Button>
<Button size="lg">Large</Button>
<Button size="xl">Extra Large</Button>
</div>
@ -232,7 +190,7 @@ export const AllStates: Story = {
return (
<div className="space-y-4">
<div className="space-y-2">
<h3 className="text-lg font-semibold">Button States</h3>
<h3 className="text-16 font-semibold">Button States</h3>
<div className="flex flex-wrap gap-2">
<Button>Default</Button>
<Button loading>Loading</Button>

View file

@ -1,23 +1,12 @@
import * as React from "react";
import { cn } from "../utils";
import type { TButtonVariant, TButtonSizes } from "./helper";
import { getIconStyling, getButtonStyling } from "./helper";
export interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
variant?: TButtonVariant;
size?: TButtonSizes;
className?: string;
loading?: boolean;
disabled?: boolean;
appendIcon?: any;
prependIcon?: any;
children: React.ReactNode;
}
import type { ButtonProps } from "./helper";
import { getIconStyling, buttonVariants } from "./helper";
const Button = React.forwardRef(function Button(props: ButtonProps, ref: React.ForwardedRef<HTMLButtonElement>) {
const {
variant = "primary",
size = "md",
size = "base",
className = "",
type = "button",
loading = false,
@ -28,14 +17,19 @@ const Button = React.forwardRef(function Button(props: ButtonProps, ref: React.F
...rest
} = props;
const buttonStyle = getButtonStyling(variant, size, disabled || loading);
const buttonIconStyle = getIconStyling(size);
const buttonIconStyle = getIconStyling(size ?? "base");
return (
<button ref={ref} type={type} className={cn(buttonStyle, className)} disabled={disabled || loading} {...rest}>
{prependIcon && <div className={buttonIconStyle}>{React.cloneElement(prependIcon, { strokeWidth: 2 })}</div>}
<button
ref={ref}
type={type}
className={cn(buttonVariants({ variant, size }), className)}
disabled={disabled || loading}
{...rest}
>
{prependIcon && React.cloneElement(prependIcon, { className: cn("shrink-0", buttonIconStyle), strokeWidth: 2 })}
{children}
{appendIcon && <div className={buttonIconStyle}>{React.cloneElement(appendIcon, { strokeWidth: 2 })}</div>}
{appendIcon && React.cloneElement(appendIcon, { className: cn("shrink-0", buttonIconStyle), strokeWidth: 2 })}
</button>
);
});

View file

@ -1,126 +1,60 @@
export type TButtonVariant =
| "primary"
| "accent-primary"
| "outline-primary"
| "neutral-primary"
| "link-primary"
| "danger"
| "accent-danger"
| "outline-danger"
| "link-danger"
| "tertiary-danger"
| "link-neutral";
import type { VariantProps } from "class-variance-authority";
import { cva } from "class-variance-authority";
export type TButtonSizes = "sm" | "md" | "lg" | "xl";
export const buttonVariants = cva(
"inline-flex items-center justify-center gap-1 whitespace-nowrap transition-colors focus-visible:outline-none disabled:pointer-events-none",
{
variants: {
variant: {
primary:
"bg-accent-primary hover:bg-accent-primary-hover active:bg-accent-primary-active focus:bg-accent-primary-active disabled:bg-layer-disabled text-on-color disabled:text-disabled",
"error-fill":
"bg-danger-primary hover:bg-danger-primary-hover active:bg-danger-primary-active focus:bg-danger-primary-active disabled:bg-layer-disabled text-on-color disabled:text-disabled",
"error-outline":
"bg-layer-2 hover:bg-danger-subtle active:bg-danger-subtle-hover focus:bg-danger-subtle-hover disabled:bg-layer-2 text-danger disabled:text-disabled border border-danger-strong disabled:border-subtle-1",
secondary:
"bg-layer-2 hover:bg-layer-2-hover active:bg-layer-2-active focus:bg-layer-2-active disabled:bg-layer-transparent text-secondary disabled:text-disabled border border-strong disabled:border-subtle-1 shadow-raised-100",
tertiary:
"bg-layer-3 hover:bg-layer-3-hover active:bg-layer-3-active focus:bg-layer-3-active disabled:bg-layer-transparent text-secondary disabled:text-disabled",
ghost:
"bg-layer-transparent hover:bg-layer-transparent-hover active:bg-layer-transparent-active focus:bg-layer-transparent-active disabled:bg-layer-transparent text-secondary disabled:text-disabled",
link: "px-0 underline text-link-primary hover:text-link-primary-hover active:text-link-primary-hover focus:text-link-primary-hover disabled:text-disabled",
},
size: {
sm: "h-5 px-1.5 text-caption-md-medium rounded-sm",
base: "h-6 px-2 text-body-xs-medium rounded-md",
lg: "h-7 px-2 text-body-xs-medium rounded-md",
xl: "h-8 px-2 text-body-sm-medium rounded-md",
},
},
defaultVariants: {
variant: "primary",
size: "base",
},
}
);
export interface IButtonStyling {
[key: string]: {
default: string;
hover: string;
pressed: string;
disabled: string;
export type ButtonProps = React.ButtonHTMLAttributes<HTMLButtonElement> &
VariantProps<typeof buttonVariants> & {
appendIcon?: React.ReactElement;
loading?: boolean;
prependIcon?: React.ReactElement;
};
}
enum buttonSizeStyling {
sm = `px-3 py-1.5 font-medium text-xs rounded flex items-center gap-1.5 whitespace-nowrap transition-all justify-center`,
md = `px-4 py-1.5 font-medium text-sm rounded flex items-center gap-1.5 whitespace-nowrap transition-all justify-center`,
lg = `px-5 py-2 font-medium text-sm rounded flex items-center gap-1.5 whitespace-nowrap transition-all justify-center`,
xl = `px-5 py-3.5 font-medium text-sm rounded flex items-center gap-1.5 whitespace-nowrap transition-all justify-center`,
}
export type TButtonVariant = NonNullable<ButtonProps["variant"]>;
export type TButtonSize = NonNullable<ButtonProps["size"]>;
enum buttonIconStyling {
sm = "h-3 w-3 flex justify-center items-center overflow-hidden my-0.5 flex-shrink-0",
md = "h-3.5 w-3.5 flex justify-center items-center overflow-hidden my-0.5 flex-shrink-0",
lg = "h-4 w-4 flex justify-center items-center overflow-hidden my-0.5 flex-shrink-0",
xl = "h-4 w-4 flex justify-center items-center overflow-hidden my-0.5 flex-shrink-0 ",
}
export const buttonStyling: IButtonStyling = {
primary: {
default: `text-white bg-custom-primary-100`,
hover: `hover:bg-custom-primary-200`,
pressed: `focus:text-custom-brand-40 focus:bg-custom-primary-200`,
disabled: `cursor-not-allowed !bg-custom-primary-60 hover:bg-custom-primary-60`,
},
"accent-primary": {
default: `bg-custom-primary-100/20 text-custom-primary-100`,
hover: `hover:bg-custom-primary-100/10 hover:text-custom-primary-200`,
pressed: `focus:bg-custom-primary-100/10`,
disabled: `cursor-not-allowed !text-custom-primary-60`,
},
"outline-primary": {
default: `text-custom-primary-100 bg-transparent border border-custom-primary-100`,
hover: `hover:bg-custom-primary-100/20`,
pressed: `focus:text-custom-primary-100 focus:bg-custom-primary-100/30`,
disabled: `cursor-not-allowed !text-custom-primary-60 !border-custom-primary-60 `,
},
"neutral-primary": {
default: `text-custom-text-200 bg-custom-background-100 border border-custom-border-200`,
hover: `hover:bg-custom-background-90`,
pressed: `focus:text-custom-text-300 focus:bg-custom-background-90`,
disabled: `cursor-not-allowed !text-custom-text-400`,
},
"link-primary": {
default: `text-custom-primary-100 bg-custom-background-100`,
hover: `hover:text-custom-primary-200`,
pressed: `focus:text-custom-primary-80 `,
disabled: `cursor-not-allowed !text-custom-primary-60`,
},
danger: {
default: `text-white bg-red-500`,
hover: ` hover:bg-red-600`,
pressed: `focus:text-red-200 focus:bg-red-600`,
disabled: `cursor-not-allowed !bg-red-300`,
},
"accent-danger": {
default: `text-red-500 bg-red-50`,
hover: `hover:text-red-600 hover:bg-red-100`,
pressed: `focus:text-red-500 focus:bg-red-100`,
disabled: `cursor-not-allowed !text-red-300`,
},
"outline-danger": {
default: `text-red-500 bg-transparent border border-red-500`,
hover: `hover:text-red-400 hover:border-red-400`,
pressed: `focus:text-red-400 focus:border-red-400`,
disabled: `cursor-not-allowed !text-red-300 !border-red-300`,
},
"link-danger": {
default: `text-red-500 bg-custom-background-100`,
hover: `hover:text-red-400`,
pressed: `focus:text-red-400`,
disabled: `cursor-not-allowed !text-red-300`,
},
"tertiary-danger": {
default: `text-red-500 bg-custom-background-100 border border-red-200`,
hover: `hover:bg-red-50 hover:border-red-300`,
pressed: `focus:text-red-400`,
disabled: `cursor-not-allowed !text-red-300`,
},
"link-neutral": {
default: `text-custom-text-300`,
hover: `hover:text-custom-text-200`,
pressed: `focus:text-custom-text-100`,
disabled: `cursor-not-allowed !text-custom-text-400`,
},
const buttonIconStyling: Record<TButtonSize, string> = {
sm: "size-3.5",
base: "size-3.5",
lg: "size-4",
xl: "size-4 ",
};
export const getButtonStyling = (variant: TButtonVariant, size: TButtonSizes, disabled: boolean = false): string => {
let tempVariant: string = ``;
const currentVariant = buttonStyling[variant];
export function getIconStyling(size: TButtonSize): string {
return buttonIconStyling[size];
}
tempVariant = `${currentVariant.default} ${disabled ? currentVariant.disabled : currentVariant.hover} ${
currentVariant.pressed
}`;
let tempSize: string = ``;
if (size) tempSize = buttonSizeStyling[size];
return `${tempVariant} ${tempSize}`;
};
export const getIconStyling = (size: TButtonSizes): string => {
let icon: string = ``;
if (size) icon = buttonIconStyling[size];
return icon;
};
export function getButtonStyling(variant: TButtonVariant, size: TButtonSize): string {
return buttonVariants({ variant, size });
}

View file

@ -1,3 +1,3 @@
export { Button } from "./button";
export * from "./helper";
export type { ButtonProps } from "./button";
export { getButtonStyling } from "./helper";
export type { ButtonProps, TButtonVariant, TButtonSize } from "./helper";

View file

@ -1,6 +1,6 @@
import * as React from "react";
import { DayPicker } from "react-day-picker";
import { ChevronLeftIcon } from "../icons";
import { ChevronLeftIcon } from "../icons/arrows/chevron-left";
import { cn } from "../utils";

View file

@ -11,8 +11,8 @@ const meta = {
args: {
children: (
<>
<h3 className="text-lg font-semibold">Card Title</h3>
<p className="text-sm text-gray-600">This is a default card with shadow and large spacing.</p>
<h3 className="text-16 font-semibold">Card Title</h3>
<p className="text-13 text-gray-600">This is a default card with shadow and large spacing.</p>
</>
),
},
@ -28,8 +28,8 @@ export const WithShadow: Story = {
variant: ECardVariant.WITH_SHADOW,
children: (
<>
<h3 className="text-lg font-semibold">Card with Shadow</h3>
<p className="text-sm text-gray-600">Hover over this card to see the shadow effect.</p>
<h3 className="text-16 font-semibold">Card with Shadow</h3>
<p className="text-13 text-gray-600">Hover over this card to see the shadow effect.</p>
</>
),
},
@ -40,8 +40,8 @@ export const WithoutShadow: Story = {
variant: ECardVariant.WITHOUT_SHADOW,
children: (
<>
<h3 className="text-lg font-semibold">Card without Shadow</h3>
<p className="text-sm text-gray-600">This card has no shadow effect on hover.</p>
<h3 className="text-16 font-semibold">Card without Shadow</h3>
<p className="text-13 text-gray-600">This card has no shadow effect on hover.</p>
</>
),
},
@ -52,8 +52,8 @@ export const SmallSpacing: Story = {
spacing: ECardSpacing.SM,
children: (
<>
<h3 className="text-lg font-semibold">Small Spacing</h3>
<p className="text-sm text-gray-600">This card uses small spacing (p-4).</p>
<h3 className="text-16 font-semibold">Small Spacing</h3>
<p className="text-13 text-gray-600">This card uses small spacing (p-4).</p>
</>
),
},
@ -64,8 +64,8 @@ export const LargeSpacing: Story = {
spacing: ECardSpacing.LG,
children: (
<>
<h3 className="text-lg font-semibold">Large Spacing</h3>
<p className="text-sm text-gray-600">This card uses large spacing (p-6).</p>
<h3 className="text-16 font-semibold">Large Spacing</h3>
<p className="text-13 text-gray-600">This card uses large spacing (p-6).</p>
</>
),
},
@ -76,9 +76,9 @@ export const ColumnDirection: Story = {
direction: ECardDirection.COLUMN,
children: (
<>
<h3 className="text-lg font-semibold">Column Direction</h3>
<p className="text-sm text-gray-600">Content is arranged vertically.</p>
<button className="rounded bg-blue-500 px-4 py-2 text-white">Action</button>
<h3 className="text-16 font-semibold">Column Direction</h3>
<p className="text-13 text-gray-600">Content is arranged vertically.</p>
<button className="rounded-sm bg-blue-500 px-4 py-2 text-on-color">Action</button>
</>
),
},
@ -90,11 +90,11 @@ export const RowDirection: Story = {
children: (
<>
<div className="flex-shrink-0">
<div className="h-12 w-12 rounded bg-blue-500" />
<div className="h-12 w-12 rounded-sm bg-blue-500" />
</div>
<div className="flex-1">
<h3 className="text-lg font-semibold">Row Direction</h3>
<p className="text-sm text-gray-600">Content is arranged horizontally.</p>
<h3 className="text-16 font-semibold">Row Direction</h3>
<p className="text-13 text-gray-600">Content is arranged horizontally.</p>
</div>
</>
),
@ -108,12 +108,12 @@ export const ProductCard: Story = {
direction: ECardDirection.COLUMN,
children: (
<>
<div className="h-48 w-full rounded bg-gray-200" />
<h3 className="text-xl font-bold">Product Name</h3>
<p className="text-sm text-gray-600">A brief description of the product goes here.</p>
<div className="h-48 w-full rounded-sm bg-gray-200" />
<h3 className="text-18 font-bold">Product Name</h3>
<p className="text-13 text-gray-600">A brief description of the product goes here.</p>
<div className="flex items-center justify-between">
<span className="text-lg font-semibold">$99.99</span>
<button className="rounded bg-blue-500 px-4 py-2 text-white hover:bg-blue-600">Add to Cart</button>
<span className="text-16 font-semibold">$99.99</span>
<button className="rounded-sm bg-blue-500 px-4 py-2 text-on-color hover:bg-blue-600">Add to Cart</button>
</div>
</>
),
@ -129,9 +129,9 @@ export const UserCard: Story = {
<>
<div className="h-16 w-16 flex-shrink-0 rounded-full bg-blue-500" />
<div className="flex-1">
<h3 className="text-lg font-semibold">John Doe</h3>
<p className="text-sm text-gray-600">Software Engineer</p>
<p className="text-xs text-gray-500">john.doe@example.com</p>
<h3 className="text-16 font-semibold">John Doe</h3>
<p className="text-13 text-gray-600">Software Engineer</p>
<p className="text-11 text-gray-500">john.doe@example.com</p>
</div>
</>
),
@ -147,9 +147,9 @@ export const NotificationCard: Story = {
<>
<div className="flex items-start justify-between">
<h4 className="font-semibold">New Message</h4>
<span className="text-xs text-gray-500">2m ago</span>
<span className="text-11 text-gray-500">2m ago</span>
</div>
<p className="text-sm text-gray-600">You have received a new message from Alice.</p>
<p className="text-13 text-gray-600">You have received a new message from Alice.</p>
</>
),
},
@ -161,11 +161,11 @@ export const AllVariants: Story = {
<div className="space-y-4">
<Card variant={ECardVariant.WITH_SHADOW}>
<h3 className="font-semibold">With Shadow</h3>
<p className="text-sm text-gray-600">Hover to see the shadow effect</p>
<p className="text-13 text-gray-600">Hover to see the shadow effect</p>
</Card>
<Card variant={ECardVariant.WITHOUT_SHADOW}>
<h3 className="font-semibold">Without Shadow</h3>
<p className="text-sm text-gray-600">No shadow on hover</p>
<p className="text-13 text-gray-600">No shadow on hover</p>
</Card>
</div>
);
@ -178,11 +178,11 @@ export const AllSpacings: Story = {
<div className="space-y-4">
<Card spacing={ECardSpacing.SM}>
<h3 className="font-semibold">Small Spacing (p-4)</h3>
<p className="text-sm text-gray-600">Compact padding</p>
<p className="text-13 text-gray-600">Compact padding</p>
</Card>
<Card spacing={ECardSpacing.LG}>
<h3 className="font-semibold">Large Spacing (p-6)</h3>
<p className="text-sm text-gray-600">More generous padding</p>
<p className="text-13 text-gray-600">More generous padding</p>
</Card>
</div>
);
@ -195,14 +195,14 @@ export const AllDirections: Story = {
<div className="space-y-4">
<Card direction={ECardDirection.COLUMN}>
<h3 className="font-semibold">Column Direction</h3>
<p className="text-sm text-gray-600">Vertical layout</p>
<button className="w-fit rounded bg-blue-500 px-4 py-2 text-white">Button</button>
<p className="text-13 text-gray-600">Vertical layout</p>
<button className="w-fit rounded-sm bg-blue-500 px-4 py-2 text-on-color">Button</button>
</Card>
<Card direction={ECardDirection.ROW}>
<div className="h-12 w-12 flex-shrink-0 rounded bg-blue-500" />
<div className="h-12 w-12 flex-shrink-0 rounded-sm bg-blue-500" />
<div>
<h3 className="font-semibold">Row Direction</h3>
<p className="text-sm text-gray-600">Horizontal layout</p>
<p className="text-13 text-gray-600">Horizontal layout</p>
</div>
</Card>
</div>

View file

@ -18,8 +18,7 @@ export interface ICardProperties {
[key: string]: string;
}
const DEFAULT_STYLE =
"bg-custom-background-100 rounded-lg border-[0.5px] border-custom-border-200 w-full flex flex-col";
const DEFAULT_STYLE = "bg-surface-1 rounded-lg border-[0.5px] border-subtle w-full flex flex-col";
export const containerStyle: ICardProperties = {
[ECardVariant.WITHOUT_SHADOW]: "",
[ECardVariant.WITH_SHADOW]: "hover:shadow-custom-shadow-4xl duration-300",

View file

@ -112,7 +112,7 @@ export const AreaChart = React.memo(function AreaChart<K extends string, T exten
left: margin?.left === undefined ? 20 : margin.left,
}}
>
<CartesianGrid stroke="rgba(var(--color-border-100), 0.8)" vertical={false} />
<CartesianGrid stroke="--alpha(var(--border-color-subtle) / 80%)" vertical={false} />
<XAxis
dataKey={xAxis.key}
tick={(props) => {
@ -163,7 +163,7 @@ export const AreaChart = React.memo(function AreaChart<K extends string, T exten
{showTooltip && (
<Tooltip
cursor={{
stroke: "rgba(var(--color-text-300))",
stroke: "var(--text-color-tertiary)",
strokeDasharray: "4 4",
}}
wrapperStyle={{

View file

@ -66,7 +66,7 @@ function PercentageText({
className?: string;
}) {
return (
<text x={x} y={y} textAnchor="middle" className={cn("text-xs font-medium", className)} fill="currentColor">
<text x={x} y={y} textAnchor="middle" className={cn("text-11 font-medium", className)} fill="currentColor">
{percentage}%
</text>
);
@ -176,7 +176,7 @@ export const barShapeVariants: Record<
TBarChartShapeVariant,
(props: TShapeProps, bar: TBarItem<string>, stackKeys: string[]) => React.ReactNode
> = {
bar: createShapeVariant(CustomBar), // Standard bar with rounded corners
bar: createShapeVariant(CustomBar), // Standard bar with rounded-sm corners
lollipop: createShapeVariant(CustomBarLollipop), // Line with circle at top
"lollipop-dotted": createShapeVariant(CustomBarLollipop, { dotted: true }), // Dotted line lollipop variant
};

View file

@ -129,7 +129,7 @@ export const BarChart = React.memo(function BarChart<K extends string, T extends
barSize={barSize}
className="recharts-wrapper"
>
<CartesianGrid stroke="rgba(var(--color-border-100), 0.8)" vertical={false} />
<CartesianGrid stroke="--alpha(var(--border-color-subtle) / 80%)" vertical={false} />
<XAxis
dataKey={xAxis.key}
tick={(props) => {

View file

@ -51,7 +51,7 @@ const CustomLegend = React.forwardRef(function CustomLegend(
{payload.map((item, index) => (
<div
key={item.value}
className={cn("flex items-center gap-1.5 text-custom-text-300 text-sm font-medium whitespace-nowrap", {
className={cn("flex items-center gap-1.5 text-tertiary text-13 font-medium whitespace-nowrap", {
"px-2": layout === "horizontal",
"py-2": layout === "vertical",
"pl-0 pt-0": index === 0,
@ -63,7 +63,7 @@ const CustomLegend = React.forwardRef(function CustomLegend(
onMouseLeave={(e) => onMouseLeave?.(item, index, e)}
>
<div
className="flex-shrink-0 size-2 rounded-sm"
className="flex-shrink-0 size-2 rounded-xs"
style={{
backgroundColor: item.color,
}}

View file

@ -2,7 +2,7 @@
import React from "react";
// Common classnames
const AXIS_TICK_CLASSNAME = "fill-custom-text-300 text-sm";
const AXIS_TICK_CLASSNAME = "fill-tertiary text-13";
export const CustomXAxisTick = React.memo(function CustomXAxisTick({ x, y, payload, getLabel }: any) {
return (

View file

@ -25,31 +25,29 @@ export const CustomTooltip = React.memo(function CustomTooltip(props: Props) {
className="flex flex-col max-h-[40vh] w-[12rem] overflow-y-scroll vertical-scrollbar scrollbar-sm"
spacing={ECardSpacing.SM}
>
<p className="flex-shrink-0 text-xs text-custom-text-100 font-medium border-b border-custom-border-200 pb-2 truncate">
{label}
</p>
<p className="flex-shrink-0 text-11 text-primary font-medium border-b border-subtle pb-2 truncate">{label}</p>
{filteredPayload.map((item) => {
if (!item.dataKey) return null;
return (
<div
key={item?.dataKey}
className={cn("flex items-center gap-2 text-xs transition-opacity", {
className={cn("flex items-center gap-2 text-11 transition-opacity", {
"opacity-20": activeKey && item.dataKey !== activeKey,
})}
>
<div className="flex items-center gap-2 truncate">
{itemDotColors[item?.dataKey] && (
<div
className="flex-shrink-0 size-2 rounded-sm"
className="flex-shrink-0 size-2 rounded-xs"
style={{
backgroundColor: itemDotColors[item?.dataKey],
}}
/>
)}
<span className="text-custom-text-300 truncate">{itemLabels[item?.dataKey]}:</span>
<span className="text-tertiary truncate">{itemLabels[item?.dataKey]}:</span>
</div>
<span className="flex-shrink-0 font-medium text-custom-text-200">{item?.value}</span>
<span className="flex-shrink-0 font-medium text-secondary">{item?.value}</span>
</div>
);
})}

View file

@ -98,7 +98,7 @@ export const LineChart = React.memo(function LineChart<K extends string, T exten
left: margin?.left === undefined ? 20 : margin.left,
}}
>
<CartesianGrid stroke="rgba(var(--color-border-100), 0.8)" vertical={false} />
<CartesianGrid stroke="--alpha(var(--border-color-subtle) / 80%)" vertical={false} />
<XAxis
dataKey={xAxis.key}
tick={(props) => {
@ -149,7 +149,7 @@ export const LineChart = React.memo(function LineChart<K extends string, T exten
{showTooltip && (
<Tooltip
cursor={{
stroke: "rgba(var(--color-text-300))",
stroke: "var(--text-color-tertiary)",
strokeDasharray: "4 4",
}}
wrapperStyle={{

View file

@ -77,7 +77,7 @@ export const PieChart = React.memo(function PieChart<K extends string, T extends
showLabel
? ({ payload, ...props }) => (
<text
className="text-sm font-medium transition-opacity duration-200"
className="text-13 font-medium transition-opacity duration-200"
cx={props.cx}
cy={props.cy}
x={props.x}

View file

@ -17,21 +17,19 @@ export const CustomPieChartTooltip = React.memo(function CustomPieChartTooltip(p
className="flex flex-col max-h-[40vh] w-[12rem] overflow-y-scroll vertical-scrollbar scrollbar-sm"
spacing={ECardSpacing.SM}
>
<p className="flex-shrink-0 text-xs text-custom-text-100 font-medium border-b border-custom-border-200 pb-2 truncate">
{label}
</p>
<p className="flex-shrink-0 text-11 text-primary font-medium border-b border-subtle pb-2 truncate">{label}</p>
{payload?.map((item) => (
<div key={item?.dataKey} className="flex items-center gap-2 text-xs capitalize">
<div key={item?.dataKey} className="flex items-center gap-2 text-11 capitalize">
<div className="flex items-center gap-2 truncate">
<div
className="flex-shrink-0 size-2 rounded-sm"
className="flex-shrink-0 size-2 rounded-xs"
style={{
backgroundColor: dotColor,
}}
/>
<span className="text-custom-text-300 truncate">{item?.name}:</span>
<span className="text-tertiary truncate">{item?.name}:</span>
</div>
<span className="flex-shrink-0 font-medium text-custom-text-200">{item?.value}</span>
<span className="flex-shrink-0 font-medium text-secondary">{item?.value}</span>
</div>
))}
</Card>

View file

@ -37,12 +37,12 @@ function RadarChart<T extends string, K extends string>(props: TRadarChartProps<
<div className={className}>
<ResponsiveContainer width="100%" height="100%">
<CoreRadarChart cx="50%" cy="50%" outerRadius="80%" data={data} margin={margin}>
<PolarGrid stroke="rgba(var(--color-border-100), 0.9)" />
<PolarGrid stroke="--alpha(var(--border-color-subtle) / 90%)" />
<PolarAngleAxis dataKey={angleAxis.key} tick={(props) => <CustomRadarAxisTick {...props} />} />
{showTooltip && (
<Tooltip
cursor={{
stroke: "rgba(var(--color-text-300))",
stroke: "var(--text-color-tertiary)",
strokeDasharray: "4 4",
}}
wrapperStyle={{

View file

@ -82,7 +82,7 @@ export const ScatterChart = React.memo(function ScatterChart<K extends string, T
left: margin?.left === undefined ? 20 : margin.left,
}}
>
<CartesianGrid stroke="rgba(var(--color-border-100), 0.8)" vertical={false} />
<CartesianGrid stroke="--alpha(var(--border-color-subtle) / 80%)" vertical={false} />
<XAxis
dataKey={xAxis.key}
tick={(props) => {
@ -133,7 +133,7 @@ export const ScatterChart = React.memo(function ScatterChart<K extends string, T
{showTooltip && (
<Tooltip
cursor={{
stroke: "rgba(var(--color-text-300))",
stroke: "var(--text-color-tertiary)",
strokeDasharray: "4 4",
}}
wrapperStyle={{

View file

@ -208,7 +208,7 @@ export function CustomTreeMapContent({
y={pY + LAYOUT.TEXT.PADDING_LEFT}
width={LAYOUT.ICON.SIZE}
height={LAYOUT.ICON.SIZE}
className={textClassName || "text-custom-text-300"}
className={textClassName || "text-tertiary"}
>
{React.cloneElement(icon, {
className: cn("size-4", icon?.props?.className),
@ -221,10 +221,7 @@ export function CustomTreeMapContent({
x={pX + LAYOUT.TEXT.PADDING_LEFT + iconSpace}
y={pY + LAYOUT.TEXT.VERTICAL_OFFSET}
textAnchor="start"
className={cn(
"text-sm font-extralight tracking-wider select-none",
textClassName || "text-custom-text-300"
)}
className={cn("text-13 font-light tracking-wider select-none", textClassName || "text-tertiary")}
fill="currentColor"
>
{top.nameTruncated ? truncateText(name, availableTextWidth, LAYOUT.TEXT.FONT_SIZES.SM, iconSpace) : name}
@ -240,10 +237,7 @@ export function CustomTreeMapContent({
x={pX + LAYOUT.TEXT.PADDING_LEFT}
y={pY + pHeight - LAYOUT.TEXT.PADDING_LEFT}
textAnchor="start"
className={cn(
"text-sm font-extralight tracking-wider select-none",
textClassName || "text-custom-text-300"
)}
className={cn("text-13 font-light tracking-wider select-none", textClassName || "text-tertiary")}
fill="currentColor"
>
{value.toLocaleString()}

View file

@ -17,7 +17,7 @@ export const TreeMapChart = React.memo(function TreeMapChart(props: TreeMapChart
nameKey="name"
dataKey="value"
stroke="currentColor"
className="text-custom-background-100 bg-custom-background-100"
className="text-custom-background-100 bg-surface-1"
content={<CustomTreeMapContent />}
animationEasing="ease-out"
isUpdateAnimationActive={isAnimationActive}

View file

@ -14,11 +14,11 @@ export const TreeMapTooltip = React.memo(function TreeMapTooltip({ active, paylo
return (
<Card className="flex flex-col space-y-1.5" spacing={ECardSpacing.SM}>
<div className="flex items-center gap-2 border-b border-custom-border-200 pb-2.5">
<div className="flex items-center gap-2 border-b border-subtle pb-2.5">
{data?.icon}
<p className="text-xs text-custom-text-100 font-medium capitalize">{data?.name}</p>
<p className="text-11 text-primary font-medium capitalize">{data?.name}</p>
</div>
<span className="text-xs font-medium text-custom-text-200">
<span className="text-11 font-medium text-secondary">
{data?.value.toLocaleString()}
{data.label && ` ${data.label}`}
</span>

View file

@ -32,7 +32,7 @@ const meta = {
</Collapsible.CollapsibleTrigger>
<Collapsible.CollapsibleContent className="mt-2">
<div className="rounded-md border border-gray-200 p-4">
<p className="text-sm">This is the collapsible content that can be shown or hidden.</p>
<p className="text-13">This is the collapsible content that can be shown or hidden.</p>
</div>
</Collapsible.CollapsibleContent>
</Collapsible.CollapsibleRoot>
@ -56,13 +56,16 @@ export const Controlled: Story = {
return (
<div className="space-y-4">
<div className="flex gap-2">
<button onClick={() => setIsOpen(true)} className="rounded bg-blue-500 px-4 py-2 text-sm text-white">
<button onClick={() => setIsOpen(true)} className="rounded-sm bg-blue-500 px-4 py-2 text-13 text-on-color">
Open
</button>
<button onClick={() => setIsOpen(false)} className="rounded bg-gray-500 px-4 py-2 text-sm text-white">
<button onClick={() => setIsOpen(false)} className="rounded-sm bg-gray-500 px-4 py-2 text-13 text-on-color">
Close
</button>
<button onClick={() => setIsOpen(!isOpen)} className="rounded bg-green-500 px-4 py-2 text-sm text-white">
<button
onClick={() => setIsOpen(!isOpen)}
className="rounded-sm bg-green-500 px-4 py-2 text-13 text-on-color"
>
Toggle
</button>
</div>
@ -73,8 +76,8 @@ export const Controlled: Story = {
</Collapsible.CollapsibleTrigger>
<Collapsible.CollapsibleContent className="mt-2">
<div className="rounded-md border border-gray-200 p-4">
<p className="text-sm">This collapsible is controlled by external state.</p>
<p className="mt-2 text-sm">Current state: {isOpen ? "Open" : "Closed"}</p>
<p className="text-13">This collapsible is controlled by external state.</p>
<p className="mt-2 text-13">Current state: {isOpen ? "Open" : "Closed"}</p>
</div>
</Collapsible.CollapsibleContent>
</Collapsible.CollapsibleRoot>
@ -95,10 +98,10 @@ export const NestedContent: Story = {
<Collapsible.CollapsibleContent className="mt-2">
<div className="space-y-2 rounded-md border border-gray-200 p-4">
<h4 className="font-semibold">Section 1</h4>
<p className="text-sm">This is some content in the first section.</p>
<p className="text-13">This is some content in the first section.</p>
<h4 className="font-semibold">Section 2</h4>
<p className="text-sm">This is some content in the second section.</p>
<ul className="list-inside list-disc text-sm">
<p className="text-13">This is some content in the second section.</p>
<ul className="list-inside list-disc text-13">
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
@ -115,8 +118,8 @@ export const CustomStyling: Story = {
const [isOpen, setIsOpen] = useState(args.isOpen);
return (
<Collapsible.CollapsibleRoot {...args} isOpen={isOpen} onToggle={() => setIsOpen(!isOpen)} className="w-96">
<Collapsible.CollapsibleTrigger className="flex w-full items-center justify-between rounded-lg bg-gradient-to-r from-purple-500 to-pink-500 px-6 py-3 text-white shadow-lg transition-all hover:shadow-xl">
<span className="text-lg font-bold">Custom Styled Trigger</span>
<Collapsible.CollapsibleTrigger className="flex w-full items-center justify-between rounded-lg bg-gradient-to-r from-purple-500 to-pink-500 px-6 py-3 text-on-color shadow-lg transition-all hover:shadow-xl">
<span className="text-16 font-bold">Custom Styled Trigger</span>
<ChevronDownIcon className="h-5 w-5 transition-transform group-data-[panel-open]:rotate-180" />
</Collapsible.CollapsibleTrigger>
<Collapsible.CollapsibleContent className="mt-4">
@ -140,7 +143,7 @@ export const MultipleCollapsibles: Story = {
</Collapsible.CollapsibleTrigger>
<Collapsible.CollapsibleContent className="mt-2">
<div className="rounded-md border border-gray-200 p-4">
<p className="text-sm">Content for the first item.</p>
<p className="text-13">Content for the first item.</p>
</div>
</Collapsible.CollapsibleContent>
</Collapsible.CollapsibleRoot>
@ -152,7 +155,7 @@ export const MultipleCollapsibles: Story = {
</Collapsible.CollapsibleTrigger>
<Collapsible.CollapsibleContent className="mt-2">
<div className="rounded-md border border-gray-200 p-4">
<p className="text-sm">Content for the second item.</p>
<p className="text-13">Content for the second item.</p>
</div>
</Collapsible.CollapsibleContent>
</Collapsible.CollapsibleRoot>
@ -164,7 +167,7 @@ export const MultipleCollapsibles: Story = {
</Collapsible.CollapsibleTrigger>
<Collapsible.CollapsibleContent className="mt-2">
<div className="rounded-md border border-gray-200 p-4">
<p className="text-sm">Content for the third item.</p>
<p className="text-13">Content for the third item.</p>
</div>
</Collapsible.CollapsibleContent>
</Collapsible.CollapsibleRoot>

View file

@ -85,7 +85,7 @@ function Content({ children, className }: ContentProps) {
return (
<BaseCollapsible.Panel
className={clsx(
"flex h-[var(--collapsible-panel-height)] flex-col overflow-hidden text-sm transition-all ease-out data-[ending-style]:h-0 data-[starting-style]:h-0",
"flex h-[var(--collapsible-panel-height)] flex-col overflow-hidden text-13 transition-all ease-out data-[ending-style]:h-0 data-[starting-style]:h-0",
className
)}
>

View file

@ -142,7 +142,7 @@ export const MultiSelectWithLimit: Story = {
))}
</Combobox.Options>
</Combobox>
<p className="text-xs text-gray-500">Maximum 3 selections allowed</p>
<p className="text-11 text-gray-500">Maximum 3 selections allowed</p>
</div>
);
},

View file

@ -168,13 +168,13 @@ function ComboboxOptions({
<BaseCombobox.Portal>
<BaseCombobox.Positioner sideOffset={8} className={positionerClassName}>
<BaseCombobox.Popup
className={cn("rounded-md border border-custom-border-200 bg-custom-background-100 p-1 shadow-lg", className)}
className={cn("rounded-md border border-subtle bg-surface-1 p-1 shadow-lg", className)}
data-prevent-outside-click={dataPreventOutsideClick}
>
<div className="flex flex-col gap-1">
{showSearch && (
<div className="relative">
<Search className="absolute left-2 top-1/2 h-4 w-4 -translate-y-1/2 text-custom-text-400" />
<Search className="absolute left-2 top-1/2 h-4 w-4 -translate-y-1/2 text-placeholder" />
<input
type="text"
placeholder={searchPlaceholder}
@ -182,7 +182,7 @@ function ComboboxOptions({
onChange={(e) => setSearchQuery(e.target.value)}
onKeyDown={onSearchQueryKeyDown}
className={cn(
"w-full rounded border border-custom-border-100 bg-custom-background-90 py-1.5 pl-8 pr-2 text-sm outline-none placeholder:text-custom-text-400",
"w-full rounded-sm border border-subtle bg-surface-2 py-1.5 pl-8 pr-2 text-13 outline-none placeholder:text-placeholder",
inputClassName
)}
/>
@ -198,7 +198,7 @@ function ComboboxOptions({
React.Children.toArray(filteredChildren).filter(
(child) => React.isValidElement(child) && child.type === ComboboxOption
)
) === 0 && <div className="px-2 py-1.5 text-sm text-custom-text-400">{emptyMessage}</div>}
) === 0 && <div className="px-2 py-1.5 text-13 text-placeholder">{emptyMessage}</div>}
</BaseCombobox.List>
</div>
</BaseCombobox.Popup>
@ -213,7 +213,7 @@ function ComboboxOption({ value, children, disabled, className }: ComboboxOption
<BaseCombobox.Item
value={value}
disabled={disabled}
className={cn("cursor-pointer rounded px-2 py-1.5 text-sm outline-none transition-colors", className)}
className={cn("cursor-pointer rounded-sm px-2 py-1.5 text-13 outline-none transition-colors", className)}
>
{children}
</BaseCombobox.Item>

View file

@ -24,13 +24,13 @@ export const Default: Story = {
render() {
return (
<Command className="w-96 rounded-lg border border-gray-200 p-2">
<Command.Input placeholder="Search..." className="h-9 w-full bg-transparent py-3 text-sm outline-none" />
<Command.Input placeholder="Search..." className="h-9 w-full bg-transparent py-3 text-13 outline-none" />
<Command.List className="max-h-80 overflow-auto py-2">
<Command.Item className="cursor-pointer rounded px-3 py-2 hover:bg-gray-100">Item 1</Command.Item>
<Command.Item className="cursor-pointer rounded px-3 py-2 hover:bg-gray-100">Item 2</Command.Item>
<Command.Item className="cursor-pointer rounded px-3 py-2 hover:bg-gray-100">Item 3</Command.Item>
<Command.Item className="cursor-pointer rounded-sm px-3 py-2 hover:bg-gray-100">Item 1</Command.Item>
<Command.Item className="cursor-pointer rounded-sm px-3 py-2 hover:bg-gray-100">Item 2</Command.Item>
<Command.Item className="cursor-pointer rounded-sm px-3 py-2 hover:bg-gray-100">Item 3</Command.Item>
</Command.List>
<Command.Empty className="py-6 text-center text-sm text-gray-500">No results found.</Command.Empty>
<Command.Empty className="py-6 text-center text-13 text-gray-500">No results found.</Command.Empty>
</Command>
);
},
@ -42,27 +42,27 @@ export const WithIcons: Story = {
<Command className="w-96 rounded-lg border border-gray-200 p-2">
<Command.Input
placeholder="Search files and folders..."
className="h-9 w-full bg-transparent py-3 text-sm outline-none"
className="h-9 w-full bg-transparent py-3 text-13 outline-none"
/>
<Command.List className="max-h-80 overflow-auto py-2">
<Command.Item className="flex cursor-pointer items-center gap-2 rounded px-3 py-2 hover:bg-gray-100">
<Command.Item className="flex cursor-pointer items-center gap-2 rounded-sm px-3 py-2 hover:bg-gray-100">
<Folder className="h-4 w-4" />
<span>Documents</span>
</Command.Item>
<Command.Item className="flex cursor-pointer items-center gap-2 rounded px-3 py-2 hover:bg-gray-100">
<Command.Item className="flex cursor-pointer items-center gap-2 rounded-sm px-3 py-2 hover:bg-gray-100">
<Folder className="h-4 w-4" />
<span>Downloads</span>
</Command.Item>
<Command.Item className="flex cursor-pointer items-center gap-2 rounded px-3 py-2 hover:bg-gray-100">
<Command.Item className="flex cursor-pointer items-center gap-2 rounded-sm px-3 py-2 hover:bg-gray-100">
<File className="h-4 w-4" />
<span>README.md</span>
</Command.Item>
<Command.Item className="flex cursor-pointer items-center gap-2 rounded px-3 py-2 hover:bg-gray-100">
<Command.Item className="flex cursor-pointer items-center gap-2 rounded-sm px-3 py-2 hover:bg-gray-100">
<File className="h-4 w-4" />
<span>package.json</span>
</Command.Item>
</Command.List>
<Command.Empty className="py-6 text-center text-sm text-gray-500">No files or folders found.</Command.Empty>
<Command.Empty className="py-6 text-center text-13 text-gray-500">No files or folders found.</Command.Empty>
</Command>
);
},
@ -74,30 +74,30 @@ export const WithCategories: Story = {
<Command className="w-96 rounded-lg border border-gray-200 p-2">
<Command.Input
placeholder="Search commands..."
className="h-9 w-full bg-transparent py-3 text-sm outline-none"
className="h-9 w-full bg-transparent py-3 text-13 outline-none"
/>
<Command.List className="max-h-80 overflow-auto py-2">
<div className="px-2 py-1.5 text-xs font-semibold text-gray-500">User</div>
<Command.Item className="flex cursor-pointer items-center gap-2 rounded px-3 py-2 hover:bg-gray-100">
<div className="px-2 py-1.5 text-11 font-semibold text-gray-500">User</div>
<Command.Item className="flex cursor-pointer items-center gap-2 rounded-sm px-3 py-2 hover:bg-gray-100">
<User className="h-4 w-4" />
<span>Profile</span>
</Command.Item>
<Command.Item className="flex cursor-pointer items-center gap-2 rounded px-3 py-2 hover:bg-gray-100">
<Command.Item className="flex cursor-pointer items-center gap-2 rounded-sm px-3 py-2 hover:bg-gray-100">
<Settings className="h-4 w-4" />
<span>Settings</span>
</Command.Item>
<div className="mt-2 px-2 py-1.5 text-xs font-semibold text-gray-500">Files</div>
<Command.Item className="flex cursor-pointer items-center gap-2 rounded px-3 py-2 hover:bg-gray-100">
<div className="mt-2 px-2 py-1.5 text-11 font-semibold text-gray-500">Files</div>
<Command.Item className="flex cursor-pointer items-center gap-2 rounded-sm px-3 py-2 hover:bg-gray-100">
<Folder className="h-4 w-4" />
<span>Open Folder</span>
</Command.Item>
<Command.Item className="flex cursor-pointer items-center gap-2 rounded px-3 py-2 hover:bg-gray-100">
<Command.Item className="flex cursor-pointer items-center gap-2 rounded-sm px-3 py-2 hover:bg-gray-100">
<File className="h-4 w-4" />
<span>New File</span>
</Command.Item>
</Command.List>
<Command.Empty className="py-6 text-center text-sm text-gray-500">No commands found.</Command.Empty>
<Command.Empty className="py-6 text-center text-13 text-gray-500">No commands found.</Command.Empty>
</Command>
);
},
@ -107,11 +107,11 @@ export const EmptyState: Story = {
render() {
return (
<Command className="w-96 rounded-lg border border-gray-200 p-2">
<Command.Input placeholder="Search..." className="h-9 w-full bg-transparent py-3 text-sm outline-none" />
<Command.Input placeholder="Search..." className="h-9 w-full bg-transparent py-3 text-13 outline-none" />
<Command.List className="max-h-80 overflow-auto py-2">{/* No items - will show empty state */}</Command.List>
<Command.Empty className="py-6 text-center text-sm text-gray-500">
<Command.Empty className="py-6 text-center text-13 text-gray-500">
<p className="font-semibold">No results found</p>
<p className="mt-1 text-xs">Try searching for something else</p>
<p className="mt-1 text-11">Try searching for something else</p>
</Command.Empty>
</Command>
);
@ -122,15 +122,15 @@ export const LongList: Story = {
render() {
return (
<Command className="w-96 rounded-lg border border-gray-200 p-2">
<Command.Input placeholder="Search items..." className="h-9 w-full bg-transparent py-3 text-sm outline-none" />
<Command.Input placeholder="Search items..." className="h-9 w-full bg-transparent py-3 text-13 outline-none" />
<Command.List className="max-h-60 overflow-auto py-2">
{Array.from({ length: 20 }, (_, i) => (
<Command.Item key={i} className="cursor-pointer rounded px-3 py-2 hover:bg-gray-100">
<Command.Item key={i} className="cursor-pointer rounded-sm px-3 py-2 hover:bg-gray-100">
Item {i + 1}
</Command.Item>
))}
</Command.List>
<Command.Empty className="py-6 text-center text-sm text-gray-500">No results found.</Command.Empty>
<Command.Empty className="py-6 text-center text-13 text-gray-500">No results found.</Command.Empty>
</Command>
);
},
@ -141,15 +141,15 @@ export const WithoutSearch: Story = {
return (
<Command className="w-96 rounded-lg border border-gray-200 p-2">
<Command.List className="max-h-80 overflow-auto py-2">
<Command.Item className="flex cursor-pointer items-center gap-2 rounded px-3 py-2 hover:bg-gray-100">
<Command.Item className="flex cursor-pointer items-center gap-2 rounded-sm px-3 py-2 hover:bg-gray-100">
<User className="h-4 w-4" />
<span>Profile</span>
</Command.Item>
<Command.Item className="flex cursor-pointer items-center gap-2 rounded px-3 py-2 hover:bg-gray-100">
<Command.Item className="flex cursor-pointer items-center gap-2 rounded-sm px-3 py-2 hover:bg-gray-100">
<Settings className="h-4 w-4" />
<span>Settings</span>
</Command.Item>
<Command.Item className="flex cursor-pointer items-center gap-2 rounded px-3 py-2 hover:bg-gray-100">
<Command.Item className="flex cursor-pointer items-center gap-2 rounded-sm px-3 py-2 hover:bg-gray-100">
<Folder className="h-4 w-4" />
<span>Files</span>
</Command.Item>
@ -165,20 +165,20 @@ export const CustomStyling: Story = {
<Command className="w-96 rounded-lg border-2 border-blue-300 bg-blue-50 p-2 shadow-lg">
<Command.Input
placeholder="Search with custom styling..."
className="h-9 w-full bg-transparent py-3 text-sm text-blue-900 outline-none placeholder:text-blue-400"
className="h-9 w-full bg-transparent py-3 text-13 text-blue-900 outline-none placeholder:text-blue-400"
/>
<Command.List className="max-h-80 overflow-auto py-2">
<Command.Item className="cursor-pointer rounded px-3 py-2 text-blue-900 hover:bg-blue-200">
<Command.Item className="cursor-pointer rounded-sm px-3 py-2 text-blue-900 hover:bg-blue-200">
Custom Item 1
</Command.Item>
<Command.Item className="cursor-pointer rounded px-3 py-2 text-blue-900 hover:bg-blue-200">
<Command.Item className="cursor-pointer rounded-sm px-3 py-2 text-blue-900 hover:bg-blue-200">
Custom Item 2
</Command.Item>
<Command.Item className="cursor-pointer rounded px-3 py-2 text-blue-900 hover:bg-blue-200">
<Command.Item className="cursor-pointer rounded-sm px-3 py-2 text-blue-900 hover:bg-blue-200">
Custom Item 3
</Command.Item>
</Command.List>
<Command.Empty className="py-6 text-center text-sm text-blue-500">No matching items found.</Command.Empty>
<Command.Empty className="py-6 text-center text-13 text-blue-500">No matching items found.</Command.Empty>
</Command>
);
},
@ -188,15 +188,15 @@ export const DisabledItems: Story = {
render() {
return (
<Command className="w-96 rounded-lg border border-gray-200 p-2">
<Command.Input placeholder="Search..." className="h-9 w-full bg-transparent py-3 text-sm outline-none" />
<Command.Input placeholder="Search..." className="h-9 w-full bg-transparent py-3 text-13 outline-none" />
<Command.List className="max-h-80 overflow-auto py-2">
<Command.Item className="cursor-pointer rounded px-3 py-2 hover:bg-gray-100">Active Item 1</Command.Item>
<Command.Item disabled className="cursor-not-allowed rounded px-3 py-2 opacity-50">
<Command.Item className="cursor-pointer rounded-sm px-3 py-2 hover:bg-gray-100">Active Item 1</Command.Item>
<Command.Item disabled className="cursor-not-allowed rounded-sm px-3 py-2 opacity-50">
Disabled Item
</Command.Item>
<Command.Item className="cursor-pointer rounded px-3 py-2 hover:bg-gray-100">Active Item 2</Command.Item>
<Command.Item className="cursor-pointer rounded-sm px-3 py-2 hover:bg-gray-100">Active Item 2</Command.Item>
</Command.List>
<Command.Empty className="py-6 text-center text-sm text-gray-500">No results found.</Command.Empty>
<Command.Empty className="py-6 text-center text-13 text-gray-500">No results found.</Command.Empty>
</Command>
);
},

View file

@ -11,9 +11,9 @@ function CommandInput({ className, ...props }: React.ComponentProps<typeof Comma
return (
<div
data-slot="command-input-wrapper"
className="flex items-center gap-1.5 rounded border border-custom-border-100 bg-custom-background-90 px-2"
className="flex items-center gap-1.5 rounded-sm border border-subtle bg-surface-2 px-2"
>
<SearchIcon className="size-3.5 flex-shrink-0 text-custom-text-400" strokeWidth={1.5} />
<SearchIcon className="size-3.5 flex-shrink-0 text-placeholder" strokeWidth={1.5} />
<CommandPrimitive.Input data-slot="command-input" className={cn(className)} {...props} />
</div>
);

View file

@ -33,7 +33,7 @@ export const Default: Story = {
return (
<ContextMenu>
<ContextMenu.Trigger>
<div className="flex h-[150px] w-[300px] items-center justify-center rounded-md border border-dashed border-custom-border-300 text-sm">
<div className="flex h-[150px] w-[300px] items-center justify-center rounded-md border border-dashed border-strong text-13">
Right click here
</div>
</ContextMenu.Trigger>
@ -56,7 +56,7 @@ export const WithIcons: Story = {
return (
<ContextMenu>
<ContextMenu.Trigger>
<div className="flex h-[150px] w-[300px] items-center justify-center rounded-md border border-dashed border-custom-border-300 text-sm">
<div className="flex h-[150px] w-[300px] items-center justify-center rounded-md border border-dashed border-strong text-13">
Right click here
</div>
</ContextMenu.Trigger>
@ -95,7 +95,7 @@ export const WithSubmenus: Story = {
return (
<ContextMenu>
<ContextMenu.Trigger>
<div className="flex h-[150px] w-[300px] items-center justify-center rounded-md border border-dashed border-custom-border-300 text-sm">
<div className="flex h-[150px] w-[300px] items-center justify-center rounded-md border border-dashed border-strong text-13">
Right click here
</div>
</ContextMenu.Trigger>
@ -141,7 +141,7 @@ export const DisabledItems: Story = {
return (
<ContextMenu>
<ContextMenu.Trigger>
<div className="flex h-[150px] w-[300px] items-center justify-center rounded-md border border-dashed border-custom-border-300 text-sm">
<div className="flex h-[150px] w-[300px] items-center justify-center rounded-md border border-dashed border-strong text-13">
Right click here
</div>
</ContextMenu.Trigger>
@ -180,14 +180,14 @@ export const OnFileCard: Story = {
return (
<ContextMenu>
<ContextMenu.Trigger>
<div className="w-64 p-4 border border-custom-border-200 rounded-lg hover:bg-custom-background-80 cursor-pointer">
<div className="w-64 p-4 border border-subtle rounded-lg hover:bg-layer-1 cursor-pointer">
<div className="flex items-center gap-3">
<div className="w-12 h-12 bg-custom-primary-100 rounded flex items-center justify-center text-white text-lg">
<div className="w-12 h-12 bg-accent-primary rounded-sm flex items-center justify-center text-on-color text-16">
📄
</div>
<div className="flex-1">
<div className="font-medium">Document.pdf</div>
<div className="text-sm text-custom-text-400">2.4 MB</div>
<div className="text-13 text-placeholder">2.4 MB</div>
</div>
</div>
</div>
@ -227,10 +227,8 @@ export const OnImage: Story = {
return (
<ContextMenu>
<ContextMenu.Trigger>
<div className="relative w-80 h-56 bg-custom-background-80 rounded-lg overflow-hidden cursor-pointer">
<div className="absolute inset-0 flex items-center justify-center text-custom-text-400">
Image Placeholder
</div>
<div className="relative w-80 h-56 bg-layer-1 rounded-lg overflow-hidden cursor-pointer">
<div className="absolute inset-0 flex items-center justify-center text-placeholder">Image Placeholder</div>
</div>
</ContextMenu.Trigger>
<ContextMenu.Portal>
@ -261,9 +259,9 @@ export const OnText: Story = {
return (
<ContextMenu>
<ContextMenu.Trigger>
<div className="w-96 p-6 border border-custom-border-200 rounded-lg">
<h3 className="text-lg font-semibold mb-2">Context Menu on Text</h3>
<p className="text-custom-text-300">
<div className="w-96 p-6 border border-subtle rounded-lg">
<h3 className="text-16 font-semibold mb-2">Context Menu on Text</h3>
<p className="text-tertiary">
Right click anywhere on this text area to see the context menu. This demonstrates how context menus can be
applied to text content areas.
</p>
@ -293,7 +291,7 @@ export const NestedSubmenus: Story = {
return (
<ContextMenu>
<ContextMenu.Trigger>
<div className="flex h-[150px] w-[300px] items-center justify-center rounded-md border border-dashed border-custom-border-300 text-sm">
<div className="flex h-[150px] w-[300px] items-center justify-center rounded-md border border-dashed border-strong text-13">
Right click here
</div>
</ContextMenu.Trigger>
@ -344,7 +342,7 @@ export const WithKeyboardShortcuts: Story = {
return (
<ContextMenu>
<ContextMenu.Trigger>
<div className="flex h-[150px] w-[300px] items-center justify-center rounded-md border border-dashed border-custom-border-300 text-sm">
<div className="flex h-[150px] w-[300px] items-center justify-center rounded-md border border-dashed border-strong text-13">
Right click here
</div>
</ContextMenu.Trigger>
@ -353,23 +351,23 @@ export const WithKeyboardShortcuts: Story = {
<ContextMenu.Item>
<Copy className="mr-2 h-4 w-4" />
Copy
<span className="ml-auto text-xs text-custom-text-400">C</span>
<span className="ml-auto text-11 text-placeholder">C</span>
</ContextMenu.Item>
<ContextMenu.Item>
<Edit className="mr-2 h-4 w-4" />
Edit
<span className="ml-auto text-xs text-custom-text-400">E</span>
<span className="ml-auto text-11 text-placeholder">E</span>
</ContextMenu.Item>
<ContextMenu.Item>
<Download className="mr-2 h-4 w-4" />
Download
<span className="ml-auto text-xs text-custom-text-400">D</span>
<span className="ml-auto text-11 text-placeholder">D</span>
</ContextMenu.Item>
<ContextMenu.Separator />
<ContextMenu.Item>
<Trash className="mr-2 h-4 w-4 text-red-500" />
<span className="text-red-500">Delete</span>
<span className="ml-auto text-xs text-custom-text-400"></span>
<span className="ml-auto text-11 text-placeholder"></span>
</ContextMenu.Item>
</ContextMenu.Content>
</ContextMenu.Portal>

View file

@ -59,7 +59,7 @@ const ContextMenuContent = React.forwardRef(function ContextMenuContent(
>
<ContextMenuPrimitive.Popup
className={cn(
"z-50 min-w-32 overflow-hidden rounded-md border border-custom-border-200 bg-custom-background-100 p-1 shadow-md",
"z-50 min-w-32 overflow-hidden rounded-md border border-subtle bg-surface-1 p-1 shadow-md",
"data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
"data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95",
"data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2",
@ -81,8 +81,8 @@ const ContextMenuItem = React.forwardRef(function ContextMenuItem(
<ContextMenuPrimitive.Item
ref={ref}
className={cn(
"relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none",
"focus:bg-custom-background-90 focus:text-custom-text-100",
"relative flex cursor-default select-none items-center rounded-xs px-2 py-1.5 text-13 outline-none",
"focus:bg-surface-2 focus:text-primary",
"data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
className
)}
@ -99,11 +99,7 @@ const ContextMenuSeparator = React.forwardRef(function ContextMenuSeparator(
ref: React.ForwardedRef<React.ElementRef<typeof ContextMenuPrimitive.Separator>>
) {
return (
<ContextMenuPrimitive.Separator
ref={ref}
className={cn("-mx-1 my-1 h-px bg-custom-border-200", className)}
{...props}
/>
<ContextMenuPrimitive.Separator ref={ref} className={cn("-mx-1 my-1 h-px bg-subtle-1", className)} {...props} />
);
});
@ -117,8 +113,8 @@ const ContextMenuSubmenuTrigger = React.forwardRef(function ContextMenuSubmenuTr
<ContextMenuPrimitive.SubmenuTrigger
ref={ref}
className={cn(
"flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:outline-none",
"focus:bg-custom-background-90 data-[state=open]:bg-custom-background-90",
"flex cursor-default select-none items-center rounded-xs px-2 py-1.5 text-13 outline-none focus:outline-none",
"focus:bg-surface-2 data-[state=open]:bg-surface-2",
className
)}
{...props}

View file

@ -0,0 +1,428 @@
import React from "react";
import type { Meta, StoryObj } from "@storybook/react-vite";
const meta = {
title: "Design System/Philosophy",
parameters: {
layout: "fullscreen",
docs: {
description: {
component: `
# Design System Philosophy
Reusable, composable Storybook stories that demonstrate Canvas, Surface, and Layer concepts.
Key concepts and rules are preserved, but the implementation is componentized for DRYness and clarity.
`,
},
},
},
tags: ["autodocs"],
} satisfies Meta;
export default meta;
export type Story = StoryObj<typeof meta>;
/* -----------------------------
Reusable UI building blocks
-----------------------------*/
type ContainerProps = {
children?: React.ReactNode;
className?: string;
};
const DemoRoot: React.FC<ContainerProps> = ({ children, className = "" }) => (
<div className={`p-8 ${className}`}>{children}</div>
);
const Info: React.FC<{ title: string; children?: React.ReactNode; tone?: "info" | "warn" }> = ({
title,
children,
tone = "info",
}) => (
<div
className={`mb-4 rounded-md border ${tone === "warn" ? "border-red-500 bg-red-50 p-4" : "border-subtle bg-layer-1 p-4"}`}
>
<h3 className={`text-primary mb-2 text-16 font-semibold`}>{title}</h3>
<div className="text-secondary text-13">{children}</div>
</div>
);
const Surface: React.FC<ContainerProps> = ({ children, className = "bg-surface-1 rounded-md p-6" }) => (
<div className={className}>{children}</div>
);
const Layer: React.FC<ContainerProps & { hover?: boolean }> = ({
children,
className = "bg-layer-1 hover:bg-layer-1-hover rounded-md p-4",
}) => <div className={`${className} transition-colors`}>{children}</div>;
/* Small helpers to keep stories concise */
const TwoColGrid: React.FC<{ children: React.ReactNode }> = ({ children }) => (
<div className="grid grid-cols-2 gap-6">{children}</div>
);
/* -----------------------------
Stories (using the building blocks)
-----------------------------*/
export const ApplicationRoot: Story = {
render: () => (
<DemoRoot>
<Info title="✅ Application Root Pattern">
This is the <strong>bg-canvas</strong> - the application-level background. It should only appear{" "}
<strong>once</strong> in your entire application at the root level.
</Info>
<Surface>
<h4 className="text-primary mb-2 font-semibold">Page Content (bg-surface-1)</h4>
<p className="text-secondary text-13">Pages use surfaces, not canvas. This is a typical page layout.</p>
</Surface>
</DemoRoot>
),
};
export const SurfaceSiblings: Story = {
render: () => (
<DemoRoot>
<Info title="✅ Surface Siblings Pattern">
Surfaces are <strong>siblings</strong>, not nested.
</Info>
<TwoColGrid>
<Surface>
<h4 className="text-primary mb-2 font-semibold">Surface 1</h4>
<p className="text-secondary text-13">This is bg-surface-1 - a primary surface</p>
</Surface>
<Surface className="bg-surface-2 rounded-md p-6">
<h4 className="text-primary mb-2 font-semibold">Surface 2</h4>
<p className="text-secondary text-13">This is bg-surface-2 - a secondary surface (sibling to surface-1)</p>
</Surface>
</TwoColGrid>
</DemoRoot>
),
};
export const LayerStacking: Story = {
render: () => (
<DemoRoot>
<Info title="✅ Layer Stacking Pattern">Layers stack to create depth: Surface Layer 1 Layer 2 Layer 3</Info>
<Surface>
<h4 className="text-primary mb-3 font-semibold">Surface 1</h4>
<Layer className="bg-layer-1 hover:bg-layer-1-hover mb-4 rounded-md p-4">
<h5 className="text-primary mb-2 font-medium">Layer 1 (First level of depth)</h5>
<p className="text-secondary mb-3 text-13">Hover over me to see the hover state</p>
<Layer className="bg-layer-2 hover:bg-layer-2-hover rounded-md p-3">
<h6 className="text-primary mb-2 text-13 font-medium">Layer 2 (Second level)</h6>
<p className="text-secondary mb-2 text-13">Nested within Layer 1</p>
<Layer className="bg-layer-3 hover:bg-layer-3-hover rounded-md p-2" hover>
<p className="text-primary text-11 font-medium">Layer 3 (Third level)</p>
<p className="text-secondary text-11">Deepest nesting level</p>
</Layer>
</Layer>
</Layer>
</Surface>
</DemoRoot>
),
};
export const SurfaceLayerAssociation: Story = {
render: () => (
<DemoRoot>
<Info title="✅ Surface-Layer Association">
Each surface should use its corresponding layer: surface-1 layer-1, surface-2 layer-2. Very rare exception:
inputs/buttons can go one level above for visual separation.
</Info>
<TwoColGrid>
<Surface>
<h4 className="text-primary mb-3 font-semibold">Surface 1</h4>
<Layer className="bg-layer-1 hover:bg-layer-1-hover rounded-md p-4">
<h5 className="text-primary mb-1 font-medium">Layer 1</h5>
<p className="text-secondary text-13">Correctly using layer-1 with surface-1</p>
</Layer>
</Surface>
<Surface className="bg-surface-2 rounded-md p-6">
<h4 className="text-primary mb-3 font-semibold">Surface 2</h4>
<Layer className="bg-layer-2 hover:bg-layer-2-hover rounded-md p-4">
<h5 className="text-primary mb-1 font-medium">Layer 2</h5>
<p className="text-secondary text-13">Correctly using layer-2 with surface-2</p>
</Layer>
</Surface>
</TwoColGrid>
<div className="mt-6">
<Info title="✅ Rare Exception: Visual Separation for Form Elements">
In very rare cases, form elements (inputs, buttons, switches) can use one level above for visual separation.
</Info>
<Surface>
<h4 className="text-primary mb-3 font-semibold">Modal with Input (Rare Exception)</h4>
<div className="space-y-3">
<div>
<label htmlFor="example-input" className="text-secondary text-13">
Name
</label>
<input
id="example-input"
className="w-full bg-layer-2 border border-subtle rounded-md px-3 py-2 text-primary mt-1"
placeholder="Input uses layer-2 for visual separation"
/>
<p className="text-tertiary text-11 mt-1">
Input uses bg-layer-2 (one level above) for visual separation from modal surface
</p>
</div>
</div>
</Surface>
</div>
</DemoRoot>
),
};
export const ModalException: Story = {
render: () => (
<DemoRoot>
<Info title="✅ Modal Exception Pattern">
Modals exist on a <strong>different plane</strong>, so they can use surfaces even when there&apos;s a surface
below
</Info>
<Surface>
<h4 className="text-primary mb-2 font-semibold">Main Page Content</h4>
<p className="text-secondary text-13">This is the main page using bg-surface-1</p>
</Surface>
<div className="fixed inset-0 z-50 flex items-center justify-center">
<div className="bg-backdrop absolute inset-0" />
<div className="bg-surface-1 relative z-10 max-w-md rounded-lg p-6 shadow-lg">
<h4 className="text-primary mb-3 font-semibold">Modal Dialog</h4>
<p className="text-secondary mb-4 text-13">
This modal uses bg-surface-1 even though the page below also uses bg-surface-1. This is allowed because
they&apos;re on different planes.
</p>
<Layer className="bg-layer-1 hover:bg-layer-1-hover rounded-md p-3">
<p className="text-primary text-13">Modal content can use layers as normal</p>
</Layer>
</div>
</div>
</DemoRoot>
),
};
export const CardListPattern: Story = {
render: () => (
<DemoRoot>
<Info title="✅ Card List Pattern">Common pattern: Surface containing multiple layer-1 cards</Info>
<Surface>
<h4 className="text-primary mb-4 font-semibold">Task List</h4>
<div className="space-y-3">
{[1, 2, 3].map((item) => (
<Layer key={item} className="bg-layer-1 hover:bg-layer-1-hover rounded-md p-4">
<h5 className="text-primary mb-1 font-medium">Task {item}</h5>
<p className="text-secondary text-13">This is a task card using bg-layer-1 with hover state</p>
</Layer>
))}
</div>
</Surface>
</DemoRoot>
),
};
export const SidebarLayoutPattern: Story = {
render: () => (
<DemoRoot>
<Info title="✅ Sidebar Layout Pattern">
Sidebar and main content are both part of the same surface. Sidebar menu items use transparent backgrounds with
hover states.
</Info>
<Surface className="bg-surface-1 flex rounded-md">
<aside className="border-subtle w-64 border-r p-4">
<h4 className="text-primary mb-3 font-semibold">Sidebar</h4>
<div className="space-y-2">
{["Home", "Projects", "Settings"].map((item) => (
<div key={item} className="hover:bg-layer-1-hover rounded-md p-2 transition-colors">
<p className="text-primary text-13">{item}</p>
</div>
))}
</div>
</aside>
<main className="flex-1 p-6">
<h4 className="text-primary mb-3 font-semibold">Main Content</h4>
<Layer className="bg-layer-1 hover:bg-layer-1-hover rounded-md p-4">
<p className="text-primary">Content card using layer-1</p>
</Layer>
</main>
</Surface>
</DemoRoot>
),
};
export const StateVariants: Story = {
render: () => (
<DemoRoot>
<Info title="✅ State Variants">Demonstrating hover, active, and selected states</Info>
<Surface>
<div className="space-y-4">
<Layer className="bg-layer-1 hover:bg-layer-1-hover rounded-md p-4">
<h5 className="text-primary mb-1 font-medium">Hover State</h5>
<p className="text-secondary text-13">Hover over me to see bg-layer-1-hover</p>
</Layer>
<div className="bg-layer-1-active rounded-md p-4">
<h5 className="text-primary mb-1 font-medium">Active State</h5>
<p className="text-secondary text-13">Using bg-layer-1-active (pressed/active)</p>
</div>
<div className="bg-layer-1-selected rounded-md p-4">
<h5 className="text-primary mb-1 font-medium">Selected State</h5>
<p className="text-secondary text-13">Using bg-layer-1-selected (when selected)</p>
</div>
</div>
</Surface>
</DemoRoot>
),
};
export const TextColorHierarchy: Story = {
render: () => (
<DemoRoot>
<Info title="✅ Text Color Hierarchy">Semantic text colors for different importance levels</Info>
<Surface>
<div className="bg-layer-1 rounded-md p-4">
<h4 className="text-primary mb-3 text-16 font-semibold">Primary Text</h4>
<p className="text-secondary mb-3">Secondary text for descriptions and supporting content</p>
<p className="text-tertiary mb-3 text-13">Tertiary text for labels and metadata</p>
<input
className="placeholder-placeholder border-subtle rounded border px-3 py-2"
placeholder="Placeholder text for inputs"
/>
</div>
</Surface>
</DemoRoot>
),
};
export const CompleteExample: Story = {
render: () => (
<DemoRoot>
<Info title="✅ Complete Example">A realistic dashboard layout using all design system concepts</Info>
<div className="bg-surface-1 mb-6 rounded-md">
<div className="border-subtle border-b p-4">
<h1 className="text-primary text-18 font-bold">Dashboard</h1>
</div>
</div>
<div className="grid grid-cols-3 gap-6">
{[
{ label: "Total Users", value: "1,234" },
{ label: "Active Projects", value: "42" },
{ label: "Completed Tasks", value: "856" },
].map((stat, idx) => (
<Surface key={idx}>
<Layer className="bg-layer-1 hover:bg-layer-1-hover rounded-md p-4">
<p className="text-tertiary mb-1 text-13">{stat.label}</p>
<p className="text-primary text-20 font-bold">{stat.value}</p>
</Layer>
</Surface>
))}
</div>
<div className="mt-6 grid grid-cols-2 gap-6">
<Surface>
<h3 className="text-primary mb-4 font-semibold">Recent Activity</h3>
<div className="space-y-2">
{[1, 2, 3].map((item) => (
<Layer key={item} className="bg-layer-1 hover:bg-layer-1-hover rounded-md p-3">
<p className="text-primary mb-1 text-13 font-medium">Activity {item}</p>
<p className="text-secondary text-11">Description of the activity</p>
</Layer>
))}
</div>
</Surface>
<Surface className="bg-surface-2 rounded-md p-6">
<h3 className="text-primary mb-4 font-semibold">Quick Actions</h3>
<div className="space-y-2">
{["Create Project", "Invite Team", "View Reports"].map((action) => (
<Layer key={action} className="bg-layer-2 hover:bg-layer-2-hover rounded-md p-3">
<p className="text-primary text-13">{action}</p>
</Layer>
))}
</div>
</Surface>
</div>
</DemoRoot>
),
};
export const CommonMistakes: Story = {
render: () => (
<DemoRoot>
<Info title="❌ Common Mistakes to Avoid" tone="warn">
These examples show incorrect usage patterns
</Info>
<div className="space-y-6">
<div className="border-2 border-red-500 rounded-md p-4">
<h4 className="text-primary mb-2 font-semibold"> Mistake 1: Nested Surfaces (Same Plane)</h4>
<Surface>
<p className="text-secondary mb-2 text-13">Surface 1</p>
<div className="bg-surface-2 rounded-md p-4">
<p className="text-secondary text-13">Surface 2 nested inside Surface 1 - WRONG!</p>
</div>
</Surface>
<p className="text-tertiary mt-2 text-11">
Fix: Use bg-layer-1 for nested elements, or make them sibling surfaces
</p>
</div>
<div className="border-2 border-red-500 rounded-md p-4">
<h4 className="text-primary mb-2 font-semibold"> Mistake 2: Wrong Layer-Surface Association</h4>
<Surface>
<p className="text-secondary mb-2 text-13">Surface 1</p>
<div className="bg-layer-2 rounded-md p-4">
<p className="text-secondary text-13">Using layer-2 with surface-1 for content box - WRONG!</p>
</div>
</Surface>
<p className="text-tertiary mt-2 text-11">
Fix: Use bg-layer-1 with bg-surface-1 for content boxes. Exception: Very rare cases for inputs/buttons
that need visual separation (e.g., input in modal can use bg-layer-2 for separation).
</p>
</div>
<div className="border-2 border-red-500 rounded-md p-4">
<h4 className="text-primary mb-2 font-semibold"> Mistake 3: Mismatched Hover State</h4>
<Surface>
<div className="bg-layer-1 hover:bg-layer-2-hover rounded-md p-4 transition-colors">
<p className="text-secondary text-13">bg-layer-1 with hover:bg-layer-2-hover - WRONG!</p>
</div>
</Surface>
<p className="text-tertiary mt-2 text-11"> Fix: Use bg-layer-1 hover:bg-layer-1-hover</p>
</div>
<div className="border-2 border-red-500 rounded-md p-4">
<h4 className="text-primary mb-2 font-semibold"> Mistake 4: Canvas for Pages</h4>
<div className="bg-canvas rounded-md p-4">
<p className="text-secondary text-13">Using bg-canvas for a page or component - WRONG!</p>
</div>
<p className="text-tertiary mt-2 text-11">
Fix: Canvas should only be at application root. Use bg-surface-1 for pages
</p>
</div>
</div>
</DemoRoot>
),
};

View file

@ -26,7 +26,10 @@ const meta = {
return (
<>
<button onClick={() => setOpen(true)} className="rounded bg-blue-500 px-4 py-2 text-white hover:bg-blue-600">
<button
onClick={() => setOpen(true)}
className="rounded-sm bg-blue-500 px-4 py-2 text-on-color hover:bg-blue-600"
>
Open Dialog
</button>
{open && (
@ -35,18 +38,18 @@ const meta = {
<div className="p-6">
<Dialog.Title>Dialog Title</Dialog.Title>
<div className="mt-4">
<p className="text-sm text-gray-600">This is the dialog content. You can put any content here.</p>
<p className="text-13 text-gray-600">This is the dialog content. You can put any content here.</p>
</div>
<div className="mt-6 flex justify-end gap-2">
<button
onClick={() => setOpen(false)}
className="rounded bg-gray-200 px-4 py-2 text-sm hover:bg-gray-300"
className="rounded-sm bg-gray-200 px-4 py-2 text-13 hover:bg-gray-300"
>
Cancel
</button>
<button
onClick={() => setOpen(false)}
className="rounded bg-blue-500 px-4 py-2 text-sm text-white hover:bg-blue-600"
className="rounded-sm bg-blue-500 px-4 py-2 text-13 text-on-color hover:bg-blue-600"
>
Confirm
</button>
@ -74,7 +77,10 @@ export const TopPosition: Story = {
const [open, setOpen] = useState(args.open);
return (
<>
<button onClick={() => setOpen(true)} className="rounded bg-blue-500 px-4 py-2 text-white hover:bg-blue-600">
<button
onClick={() => setOpen(true)}
className="rounded-sm bg-blue-500 px-4 py-2 text-on-color hover:bg-blue-600"
>
Open Dialog (Top)
</button>
{open && (
@ -83,14 +89,14 @@ export const TopPosition: Story = {
<div className="p-6">
<Dialog.Title>Top Positioned Dialog</Dialog.Title>
<div className="mt-4">
<p className="text-sm text-gray-600">
<p className="text-13 text-gray-600">
This dialog appears at the top of the screen instead of centered.
</p>
</div>
<div className="mt-6 flex justify-end gap-2">
<button
onClick={() => setOpen(false)}
className="rounded bg-gray-200 px-4 py-2 text-sm hover:bg-gray-300"
className="rounded-sm bg-gray-200 px-4 py-2 text-13 hover:bg-gray-300"
>
Close
</button>
@ -109,7 +115,10 @@ export const SmallWidth: Story = {
const [open, setOpen] = useState(args.open);
return (
<>
<button onClick={() => setOpen(true)} className="rounded bg-blue-500 px-4 py-2 text-white hover:bg-blue-600">
<button
onClick={() => setOpen(true)}
className="rounded-sm bg-blue-500 px-4 py-2 text-on-color hover:bg-blue-600"
>
Open Small Dialog
</button>
{open && (
@ -118,12 +127,12 @@ export const SmallWidth: Story = {
<div className="p-6">
<Dialog.Title>Small Dialog</Dialog.Title>
<div className="mt-4">
<p className="text-sm text-gray-600">This is a small dialog.</p>
<p className="text-13 text-gray-600">This is a small dialog.</p>
</div>
<div className="mt-6 flex justify-end">
<button
onClick={() => setOpen(false)}
className="rounded bg-blue-500 px-4 py-2 text-sm text-white hover:bg-blue-600"
className="rounded-sm bg-blue-500 px-4 py-2 text-13 text-on-color hover:bg-blue-600"
>
Close
</button>
@ -142,7 +151,10 @@ export const LargeWidth: Story = {
const [open, setOpen] = useState(args.open);
return (
<>
<button onClick={() => setOpen(true)} className="rounded bg-blue-500 px-4 py-2 text-white hover:bg-blue-600">
<button
onClick={() => setOpen(true)}
className="rounded-sm bg-blue-500 px-4 py-2 text-on-color hover:bg-blue-600"
>
Open Large Dialog
</button>
{open && (
@ -151,14 +163,14 @@ export const LargeWidth: Story = {
<div className="p-6">
<Dialog.Title>Large Dialog</Dialog.Title>
<div className="mt-4">
<p className="text-sm text-gray-600">
<p className="text-13 text-gray-600">
This is a large dialog with more horizontal space for content.
</p>
</div>
<div className="mt-6 flex justify-end">
<button
onClick={() => setOpen(false)}
className="rounded bg-blue-500 px-4 py-2 text-sm text-white hover:bg-blue-600"
className="rounded-sm bg-blue-500 px-4 py-2 text-13 text-on-color hover:bg-blue-600"
>
Close
</button>
@ -177,7 +189,10 @@ export const WithCloseButton: Story = {
const [open, setOpen] = useState(args.open);
return (
<>
<button onClick={() => setOpen(true)} className="rounded bg-blue-500 px-4 py-2 text-white hover:bg-blue-600">
<button
onClick={() => setOpen(true)}
className="rounded-sm bg-blue-500 px-4 py-2 text-on-color hover:bg-blue-600"
>
Open Dialog with Close Button
</button>
{open && (
@ -191,7 +206,7 @@ export const WithCloseButton: Story = {
</button>
</div>
<div className="mt-4">
<p className="text-sm text-gray-600">This dialog has a close button in the header.</p>
<p className="text-13 text-gray-600">This dialog has a close button in the header.</p>
</div>
</div>
</Dialog.Panel>
@ -211,7 +226,10 @@ export const ConfirmationDialog: Story = {
};
return (
<>
<button onClick={() => setOpen(true)} className="rounded bg-red-500 px-4 py-2 text-white hover:bg-red-600">
<button
onClick={() => setOpen(true)}
className="rounded-sm bg-red-500 px-4 py-2 text-on-color hover:bg-red-600"
>
Delete Item
</button>
{open && (
@ -220,20 +238,20 @@ export const ConfirmationDialog: Story = {
<div className="p-6">
<Dialog.Title>Confirm Deletion</Dialog.Title>
<div className="mt-4">
<p className="text-sm text-gray-600">
<p className="text-13 text-gray-600">
Are you sure you want to delete this item? This action cannot be undone.
</p>
</div>
<div className="mt-6 flex justify-end gap-2">
<button
onClick={() => setOpen(false)}
className="rounded bg-gray-200 px-4 py-2 text-sm hover:bg-gray-300"
className="rounded-sm bg-gray-200 px-4 py-2 text-13 hover:bg-gray-300"
>
Cancel
</button>
<button
onClick={handleConfirm}
className="rounded bg-red-500 px-4 py-2 text-sm text-white hover:bg-red-600"
className="rounded-sm bg-red-500 px-4 py-2 text-13 text-on-color hover:bg-red-600"
>
Delete
</button>
@ -257,7 +275,10 @@ export const FormDialog: Story = {
};
return (
<>
<button onClick={() => setOpen(true)} className="rounded bg-blue-500 px-4 py-2 text-white hover:bg-blue-600">
<button
onClick={() => setOpen(true)}
className="rounded-sm bg-blue-500 px-4 py-2 text-on-color hover:bg-blue-600"
>
Open Form
</button>
{open && (
@ -267,24 +288,24 @@ export const FormDialog: Story = {
<Dialog.Title>Create New Item</Dialog.Title>
<div className="mt-4 space-y-4">
<div>
<label htmlFor="name" className="block text-sm font-medium text-gray-700">
<label htmlFor="name" className="block text-13 font-medium text-gray-700">
Name
</label>
<input
type="text"
id="name"
className="mt-1 w-full rounded border border-gray-300 px-3 py-2 text-sm"
className="mt-1 w-full rounded-sm border border-gray-300 px-3 py-2 text-13"
placeholder="Enter name"
/>
</div>
<div>
<label htmlFor="description" className="block text-sm font-medium text-gray-700">
<label htmlFor="description" className="block text-13 font-medium text-gray-700">
Description
</label>
<textarea
id="description"
rows={3}
className="mt-1 w-full rounded border border-gray-300 px-3 py-2 text-sm"
className="mt-1 w-full rounded-sm border border-gray-300 px-3 py-2 text-13"
placeholder="Enter description"
/>
</div>
@ -293,11 +314,14 @@ export const FormDialog: Story = {
<button
type="button"
onClick={() => setOpen(false)}
className="rounded bg-gray-200 px-4 py-2 text-sm hover:bg-gray-300"
className="rounded-sm bg-gray-200 px-4 py-2 text-13 hover:bg-gray-300"
>
Cancel
</button>
<button type="submit" className="rounded bg-blue-500 px-4 py-2 text-sm text-white hover:bg-blue-600">
<button
type="submit"
className="rounded-sm bg-blue-500 px-4 py-2 text-13 text-on-color hover:bg-blue-600"
>
Create
</button>
</div>
@ -315,7 +339,10 @@ export const ScrollableContent: Story = {
const [open, setOpen] = useState(args.open);
return (
<>
<button onClick={() => setOpen(true)} className="rounded bg-blue-500 px-4 py-2 text-white hover:bg-blue-600">
<button
onClick={() => setOpen(true)}
className="rounded-sm bg-blue-500 px-4 py-2 text-on-color hover:bg-blue-600"
>
Open Scrollable Dialog
</button>
{open && (
@ -325,7 +352,7 @@ export const ScrollableContent: Story = {
<Dialog.Title>Scrollable Content</Dialog.Title>
<div className="mt-4 max-h-96 overflow-y-auto">
{Array.from({ length: 20 }, (_, i) => (
<p key={i} className="mb-2 text-sm text-gray-600">
<p key={i} className="mb-2 text-13 text-gray-600">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut
labore et dolore magna aliqua.
</p>
@ -334,7 +361,7 @@ export const ScrollableContent: Story = {
<div className="mt-6 flex justify-end">
<button
onClick={() => setOpen(false)}
className="rounded bg-blue-500 px-4 py-2 text-sm text-white hover:bg-blue-600"
className="rounded-sm bg-blue-500 px-4 py-2 text-13 text-on-color hover:bg-blue-600"
>
Close
</button>
@ -368,7 +395,7 @@ export const AllWidths: Story = {
<button
key={width}
onClick={() => setOpenWidth(width)}
className="rounded bg-blue-500 px-4 py-2 text-sm text-white hover:bg-blue-600"
className="rounded-sm bg-blue-500 px-4 py-2 text-13 text-on-color hover:bg-blue-600"
>
{label}
</button>
@ -379,12 +406,12 @@ export const AllWidths: Story = {
<div className="p-6">
<Dialog.Title>{label} Dialog</Dialog.Title>
<div className="mt-4">
<p className="text-sm text-gray-600">This dialog uses the {label} width variant.</p>
<p className="text-13 text-gray-600">This dialog uses the {label} width variant.</p>
</div>
<div className="mt-6 flex justify-end">
<button
onClick={() => setOpenWidth(null)}
className="rounded bg-blue-500 px-4 py-2 text-sm text-white hover:bg-blue-600"
className="rounded-sm bg-blue-500 px-4 py-2 text-13 text-on-color hover:bg-blue-600"
>
Close
</button>

View file

@ -35,8 +35,8 @@ export interface DialogTitleProps extends React.ComponentProps<typeof BaseDialog
}
// Constants
const OVERLAY_CLASSNAME = cn("fixed inset-0 z-backdrop bg-custom-backdrop");
const BASE_CLASSNAME = "relative text-left bg-custom-background-100 rounded-lg shadow-md w-full z-modal";
const OVERLAY_CLASSNAME = cn("fixed inset-0 z-backdrop bg-backdrop");
const BASE_CLASSNAME = "relative text-left bg-surface-1 rounded-lg shadow-md w-full z-modal";
// Utility functions
const getPositionClassNames = (position: DialogPosition) =>
@ -113,7 +113,7 @@ const DialogTitle = memo(function DialogTitle({ className, children, ...props }:
return (
<BaseDialog.Title
data-slot="dialog-title"
className={cn("text-lg leading-none font-semibold", className)}
className={cn("text-16 leading-none font-semibold", className)}
{...props}
>
{children}

View file

@ -38,9 +38,9 @@ export const Default: Story = {
closeOnSelect
/>
{selectedValue && (
<div className="text-sm p-4 bg-custom-background-80 rounded border border-custom-border-200">
<div className="text-13 p-4 bg-layer-1 rounded-sm border border-subtle">
<div className="font-medium mb-2">Selected:</div>
<pre className="text-xs">{JSON.stringify(selectedValue, null, 2)}</pre>
<pre className="text-11">{JSON.stringify(selectedValue, null, 2)}</pre>
</div>
)}
</div>
@ -70,7 +70,7 @@ export const OpenToEmojiTab: Story = {
closeOnSelect
/>
{selectedValue && (
<div className="text-sm">Selected: {selectedValue.type === "emoji" ? selectedValue.value : "Icon"}</div>
<div className="text-13">Selected: {selectedValue.type === "emoji" ? selectedValue.value : "Icon"}</div>
)}
</div>
);
@ -99,7 +99,7 @@ export const OpenToIconTab: Story = {
closeOnSelect
/>
{selectedValue && (
<div className="text-sm">
<div className="text-13">
Selected:{" "}
{selectedValue.type === "icon" && typeof selectedValue.value === "object"
? selectedValue.value.name
@ -134,9 +134,9 @@ export const LucideIcons: Story = {
iconType="lucide"
/>
{selectedValue && (
<div className="text-sm p-4 bg-custom-background-80 rounded border border-custom-border-200">
<div className="text-13 p-4 bg-layer-1 rounded-sm border border-subtle">
<div className="font-medium mb-2">Selected Icon:</div>
<pre className="text-xs">{JSON.stringify(selectedValue, null, 2)}</pre>
<pre className="text-11">{JSON.stringify(selectedValue, null, 2)}</pre>
</div>
)}
</div>
@ -167,9 +167,9 @@ export const MaterialIcons: Story = {
iconType="material"
/>
{selectedValue && (
<div className="text-sm p-4 bg-custom-background-80 rounded border border-custom-border-200">
<div className="text-13 p-4 bg-layer-1 rounded-sm border border-subtle">
<div className="font-medium mb-2">Selected Icon:</div>
<pre className="text-xs">{JSON.stringify(selectedValue, null, 2)}</pre>
<pre className="text-11">{JSON.stringify(selectedValue, null, 2)}</pre>
</div>
)}
</div>
@ -204,18 +204,18 @@ export const CloseOnSelectDisabled: Story = {
closeOnSelect={false}
/>
<button
className="px-3 py-1.5 text-sm bg-custom-background-80 rounded hover:bg-custom-background-90"
className="px-3 py-1.5 text-13 bg-layer-1 rounded-sm hover:bg-surface-2"
onClick={() => setSelectedValues([])}
>
Clear
</button>
</div>
{selectedValues.length > 0 && (
<div className="text-sm p-4 bg-custom-background-80 rounded border border-custom-border-200">
<div className="text-13 p-4 bg-layer-1 rounded-sm border border-subtle">
<div className="font-medium mb-2">Selected ({selectedValues.length}):</div>
<div className="flex gap-2 flex-wrap">
{selectedValues.map((val, idx) => (
<span key={idx} className="text-lg">
<span key={idx} className="text-16">
{val.type === "emoji" ? val.value : "🎨"}
</span>
))}
@ -249,7 +249,7 @@ export const CustomSearchPlaceholder: Story = {
closeOnSelect
searchPlaceholder="Type to find emojis..."
/>
{selectedValue && <div className="text-sm">Selected: {JSON.stringify(selectedValue)}</div>}
{selectedValue && <div className="text-13">Selected: {JSON.stringify(selectedValue)}</div>}
</div>
);
},
@ -277,7 +277,7 @@ export const SearchDisabled: Story = {
closeOnSelect
searchDisabled
/>
{selectedValue && <div className="text-sm">Selected: {JSON.stringify(selectedValue)}</div>}
{selectedValue && <div className="text-13">Selected: {JSON.stringify(selectedValue)}</div>}
</div>
);
},
@ -306,8 +306,8 @@ export const CustomIconColor: Story = {
defaultIconColor="#FF5733"
/>
{selectedValue && (
<div className="text-sm p-4 bg-custom-background-80 rounded border border-custom-border-200">
<pre className="text-xs">{JSON.stringify(selectedValue, null, 2)}</pre>
<div className="text-13 p-4 bg-layer-1 rounded-sm border border-subtle">
<pre className="text-11">{JSON.stringify(selectedValue, null, 2)}</pre>
</div>
)}
</div>
@ -331,7 +331,7 @@ export const DifferentPlacements: Story = {
return (
<div className="p-8 space-y-8">
<div className="flex gap-4 items-center">
<span className="text-sm w-32">Bottom Start:</span>
<span className="text-13 w-32">Bottom Start:</span>
<EmojiPicker
isOpen={isOpen1}
handleToggle={setIsOpen1}
@ -341,7 +341,7 @@ export const DifferentPlacements: Story = {
/>
</div>
<div className="flex gap-4 items-center">
<span className="text-sm w-32">Bottom End:</span>
<span className="text-13 w-32">Bottom End:</span>
<EmojiPicker
isOpen={isOpen2}
handleToggle={setIsOpen2}
@ -351,7 +351,7 @@ export const DifferentPlacements: Story = {
/>
</div>
<div className="flex gap-4 items-center">
<span className="text-sm w-32">Top Start:</span>
<span className="text-13 w-32">Top Start:</span>
<EmojiPicker
isOpen={isOpen3}
handleToggle={setIsOpen3}
@ -361,7 +361,7 @@ export const DifferentPlacements: Story = {
/>
</div>
<div className="flex gap-4 items-center">
<span className="text-sm w-32">Top End:</span>
<span className="text-13 w-32">Top End:</span>
<EmojiPicker
isOpen={isOpen4}
handleToggle={setIsOpen4}
@ -400,19 +400,19 @@ export const InFormContext: Story = {
return (
<div className="max-w-md p-4">
<form onSubmit={handleSubmit} className="space-y-4 p-6 border border-custom-border-200 rounded-lg">
<form onSubmit={handleSubmit} className="space-y-4 p-6 border border-subtle rounded-lg">
<div>
<label className="block text-sm font-medium mb-2">Project Title</label>
<label className="block text-13 font-medium mb-2">Project Title</label>
<input
type="text"
value={formData.title}
onChange={(e) => setFormData((prev) => ({ ...prev, title: e.target.value }))}
className="w-full px-3 py-2 bg-custom-background-80 border border-custom-border-200 rounded"
className="w-full px-3 py-2 bg-layer-1 border border-subtle rounded-sm"
placeholder="Enter project title"
/>
</div>
<div>
<label className="block text-sm font-medium mb-2">Project Icon</label>
<label className="block text-13 font-medium mb-2">Project Icon</label>
<EmojiPicker
isOpen={isOpen}
handleToggle={setIsOpen}
@ -420,12 +420,12 @@ export const InFormContext: Story = {
label={formData.emoji && formData.emoji.type === "emoji" ? formData.emoji.value : "Click to select icon"}
defaultOpen={EmojiIconPickerTypes.EMOJI}
closeOnSelect
buttonClassName="px-4 py-2 bg-custom-background-80 border border-custom-border-200 rounded hover:bg-custom-background-90 w-full text-left"
buttonClassName="px-4 py-2 bg-layer-1 border border-subtle rounded-sm hover:bg-surface-2 w-full text-left"
/>
</div>
<button
type="submit"
className="w-full px-4 py-2 bg-custom-primary-100 text-white rounded hover:bg-custom-primary-200"
className="w-full px-4 py-2 bg-accent-primary text-on-color rounded-sm hover:bg-accent-primary/80"
>
Create Project
</button>

View file

@ -100,10 +100,7 @@ export function EmojiPicker(props: TCustomEmojiPicker) {
</Popover.Button>
<Popover.Panel
positionerClassName="z-50"
className={cn(
"w-80 bg-custom-background-100 rounded-md border-[0.5px] border-custom-border-300 overflow-hidden",
dropdownClassName
)}
className={cn("w-80 bg-surface-1 rounded-md border-[0.5px] border-strong overflow-hidden", dropdownClassName)}
side={finalSide}
align={finalAlign}
sideOffset={8}
@ -129,9 +126,9 @@ export function EmojiPicker(props: TCustomEmojiPicker) {
key={tab.key}
value={tab.key}
className={({ selected }) =>
cn("py-1 text-sm rounded border border-custom-border-200 bg-custom-background-80", {
"bg-custom-background-100 text-custom-text-100": selected,
"text-custom-text-400 hover:text-custom-text-300 hover:bg-custom-background-80/60": !selected,
cn("py-1 text-13 rounded-sm border border-subtle bg-layer-1", {
"bg-surface-1 text-primary": selected,
"text-placeholder hover:text-tertiary hover:bg-layer-1/60": !selected,
})
}
>

View file

@ -31,17 +31,17 @@ export function EmojiRoot(props: EmojiRootProps) {
className="isolate flex flex-col rounded-md h-full w-full border-none p-2"
onEmojiSelect={(val) => onChange(val.emoji)}
>
<div className="flex items-center gap-2 justify-between [&>[data-slot='emoji-picker-search-wrapper']]:flex-grow [&>[data-slot='emoji-picker-search-wrapper']]:p-0 px-1.5 py-2 sticky top-0 z-10 bg-custom-background-100">
<div className="flex items-center gap-2 justify-between [&>[data-slot='emoji-picker-search-wrapper']]:flex-grow [&>[data-slot='emoji-picker-search-wrapper']]:p-0 px-1.5 py-2 sticky top-0 z-10 bg-surface-1">
<div ref={searchWrapperRef} data-slot="emoji-picker-search-wrapper" className="p-2">
<EmojiPicker.Search
placeholder={searchPlaceholder}
disabled={searchDisabled}
className="block rounded-md bg-transparent placeholder-custom-text-400 focus:outline-none px-3 py-2 border-[0.5px] border-custom-border-200 text-[1rem] p-0 h-full w-full flex-grow-0 focus:border-custom-primary-100"
className="block rounded-md bg-transparent placeholder-custom-text-400 focus:outline-none px-3 py-2 border-[0.5px] border-subtle text-16 p-0 h-full w-full flex-grow-0 focus:border-accent-strong"
/>
</div>
<EmojiPicker.SkinToneSelector
data-slot="emoji-picker-skin-tone-selector"
className="bg-custom-background-100 hover:bg-accent mx-2 mb-1.5 size-8 rounded-md text-lg flex-shrink-0"
className="bg-surface-1 hover:bg-accent mx-2 mb-1.5 size-8 rounded-md text-16 flex-shrink-0"
/>
</div>
<EmojiPicker.Viewport data-slot="emoji-picker-content" className={cn("relative flex-1 outline-none")}>
@ -52,7 +52,7 @@ export function EmojiRoot(props: EmojiRootProps) {
CategoryHeader: ({ category, ...props }) => (
<div
data-slot="emoji-picker-list-category-header"
className="bg-custom-background-100 text-custom-text-300 px-3 pb-1.5 text-xs font-medium"
className="bg-surface-1 text-tertiary px-3 pb-1.5 text-11 font-medium"
{...props}
>
{category.label}
@ -68,7 +68,7 @@ export function EmojiRoot(props: EmojiRootProps) {
type="button"
aria-label={emoji?.label ?? emoji?.emoji}
data-slot="emoji-picker-list-emoji"
className="data-active:bg-accent flex size-8 items-center justify-center rounded-md text-lg"
className="data-active:bg-accent flex size-8 items-center justify-center rounded-md text-16"
{...props}
>
{emoji.emoji}

Some files were not shown because too many files have changed in this diff Show more