Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
2feba1e
init
pqoqubbw Jan 22, 2026
66baeae
accordion + badge
pqoqubbw Jan 22, 2026
578e9a7
remove banner
pqoqubbw Jan 22, 2026
64ee67f
callout
pqoqubbw Jan 22, 2026
32d4c84
card
pqoqubbw Jan 22, 2026
e019b03
color
pqoqubbw Jan 22, 2026
0b57914
columns
pqoqubbw Jan 22, 2026
6340637
frame
pqoqubbw Jan 22, 2026
133b909
icon
pqoqubbw Jan 22, 2026
90a1994
mermaid
pqoqubbw Jan 22, 2026
db1c668
panel, property
pqoqubbw Jan 22, 2026
6bdb845
steps, tabs, tile
pqoqubbw Jan 22, 2026
e1cf8ec
rest
pqoqubbw Jan 22, 2026
0a2fff4
autofix
pqoqubbw Jan 22, 2026
94356c5
renames
pqoqubbw Jan 22, 2026
e816632
fix stoybook import
pqoqubbw Jan 22, 2026
d469c9e
fix cursor comment
pqoqubbw Jan 22, 2026
58df402
fix cursor comment
pqoqubbw Jan 22, 2026
392ce4a
add Update component
pqoqubbw Jan 22, 2026
edf8193
Merge branch 'main' of https://github.com/mintlify/components into dm…
pqoqubbw Jan 22, 2026
42e4a0a
Merge branch 'main' of https://github.com/mintlify/components into dm…
pqoqubbw Jan 22, 2026
611da6b
fix bugbot comments
pqoqubbw Jan 22, 2026
99ab791
update pnpm-lock
pqoqubbw Jan 22, 2026
b82656a
remove isLivePreview
pqoqubbw Jan 22, 2026
82494e2
fix comment
pqoqubbw Jan 22, 2026
bf53f6c
Merge branch 'main' of https://github.com/mintlify/components into dm…
pqoqubbw Jan 22, 2026
fec59fb
fix comment
pqoqubbw Jan 22, 2026
b7c85cc
fix tags duplication
pqoqubbw Jan 22, 2026
6da4bde
fix lint
pqoqubbw Jan 22, 2026
eef6360
fix comments
pqoqubbw Jan 22, 2026
481bfac
fix
pqoqubbw Jan 23, 2026
1e05b45
fix
pqoqubbw Jan 23, 2026
e3a0b70
Merge branch 'main' of https://github.com/mintlify/components into dm…
pqoqubbw Jan 23, 2026
efb00e7
fix
pqoqubbw Jan 23, 2026
6d9000f
cursor please stop
pqoqubbw Jan 23, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/components/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@
"lodash": "^4.17.21",
"lucide-react": "^0.453.0",
"mermaid": "^11.12.2",
"react-use-rect": "^2.0.6",
"shiki": "^3.17.0",
"tailwind-merge": "^2.6.0"
},
Expand Down
89 changes: 87 additions & 2 deletions packages/components/src/components/update/update.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,99 @@ const meta: Meta<typeof Update> = {
title: "Components/Update",
component: Update,
parameters: {
layout: "centered",
layout: "padded",
},
tags: ["autodocs"],
args: {
isVisible: true,
},
};

export default meta;
type Story = StoryObj<typeof Update>;

export const Default: Story = {
args: {},
args: {
id: "update-1",
label: "Jan 15, 2024",
children: <p>Added support for dark mode across all components.</p>,
},
};

export const WithDescription: Story = {
args: {
id: "update-2",
label: "Jan 10, 2024",
description: "Bug fixes and improvements",
children: (
<p>
Resolved a bug where search results were not being properly filtered
when using special characters.
</p>
),
},
};

export const WithTags: Story = {
args: {
id: "update-3",
label: "Jan 5, 2024",
tags: ["performance", "backend"],
children: (
<p>Optimized database queries to improve response times by 40%.</p>
),
},
};

export const WithAllFeatures: Story = {
args: {
id: "update-4",
label: "Jan 1, 2024",
description: "Major release",
tags: ["release", "breaking"],
children: (
<div>
<p>Implemented new features:</p>
<ul>
<li>Redesigned user interface</li>
<li>New API endpoints</li>
<li>Improved performance</li>
</ul>
</div>
),
},
};

export const Changelog: Story = {
render: () => (
<div className="flex flex-col divide-y">
<Update id="v2.1.0" isVisible label="Feb 1, 2024" tags={["feature"]}>
<p>Added new authentication options.</p>
</Update>
<Update
description="Security patch"
id="v2.0.1"
isVisible
label="Jan 20, 2024"
tags={["security"]}
>
<p>Fixed critical vulnerability in session handling.</p>
</Update>
<Update
description="Major release"
id="v2.0.0"
isVisible
label="Jan 1, 2024"
tags={["release", "breaking"]}
>
<div>
<p>Breaking changes:</p>
<ul>
<li>Updated API response format</li>
<li>Removed deprecated endpoints</li>
</ul>
</div>
</Update>
</div>
),
};
174 changes: 172 additions & 2 deletions packages/components/src/components/update/update.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,173 @@
export const Update = () => {
return <div>Update</div>;
import {
type ComponentPropsWithoutRef,
forwardRef,
useCallback,
useEffect,
useMemo,
useState,
} from "react";
import { type Rect, useRect } from "react-use-rect";
import { LinkIcon } from "@/icons";
import { Classes } from "@/lib/local/selectors";
import { cn } from "@/utils/cn";
import { copyToClipboard } from "@/utils/copy-to-clipboard";

type UpdatePropsBase = {
id: string;
label: string;
description?: string;
tags?: string[];
rss?: {
title?: string;
description?: string;
};
onRegisterHeading?: (id: string, rect: Rect) => void;
onUnregisterHeading?: (id: string) => void;
hasContext?: boolean;
isVisible: boolean;
onCopyAnchorLink?: (id: string) => void;
};

type UpdateProps = UpdatePropsBase &
Omit<ComponentPropsWithoutRef<"div">, keyof UpdatePropsBase>;

const Update = forwardRef<HTMLDivElement, UpdateProps>(
(
{
children,
label,
id,
description,
tags,
className,
"aria-label": ariaLabel = "Navigate to changelog",
onRegisterHeading,
onUnregisterHeading,
hasContext,
isVisible,
onCopyAnchorLink,
...props

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Props rss not destructured, will pollute DOM

Medium Severity

The rss prop is defined in UpdatePropsBase but is not destructured from props before spreading ...props onto the div element. When a consumer passes an rss object, it will be spread onto the DOM element, causing React warnings about unknown DOM attributes and polluting the HTML with invalid attributes. Other props like isLivePreview are correctly destructured to prevent this issue.

Additional Locations (1)

Fix in Cursor Fix in Web

},
ref
) => {
const [rect, setRect] = useState<Rect | null>(null);
const [rectRef] = useRect(setRect);
const tagsArray = useMemo(
() => [...new Set((tags ?? []).map((tag) => tag.trim()).filter(Boolean))],
[tags]
);

const copyAnchorLink = useCallback(async () => {
if (typeof window === "undefined") {
return;
}

const result = await copyToClipboard(
`${window.location.href.split("#")[0]}#${encodeURIComponent(id)}`
);

if (result === "success") {
window.location.hash = encodeURIComponent(id);
onCopyAnchorLink?.(id);
}
}, [id, onCopyAnchorLink]);
Comment thread
pqoqubbw marked this conversation as resolved.
Comment thread
pqoqubbw marked this conversation as resolved.
Comment thread
pqoqubbw marked this conversation as resolved.

useEffect(() => {
if (!(hasContext && isVisible && rect)) {
return;
}

onRegisterHeading?.(id, rect);

return () => {
onUnregisterHeading?.(id);
};
}, [
rect,
id,
hasContext,
isVisible,
onRegisterHeading,
onUnregisterHeading,
]);
Comment thread
pqoqubbw marked this conversation as resolved.

if (!isVisible) {
return null;
}

return (
<div
className={cn(
Classes.Update,
"update-container relative flex w-full flex-col items-start gap-2 py-8 lg:flex-row lg:gap-6",
className
)}
id={id}
ref={ref}
{...props}
>
<div className="group top-(--scroll-mt) flex w-full shrink-0 flex-col items-start justify-start lg:sticky lg:w-[160px]">
<div className="absolute">
<a
aria-label={ariaLabel}
className="group/link -ml-10 flex items-center border-0 opacity-0 focus:opacity-100 focus:outline-0 group-hover:opacity-100"
href={`#${encodeURIComponent(id)}`}
>
&#8203;
<div className="flex h-6 w-6 items-center justify-center rounded-md bg-white text-gray-400 shadow-sm ring-1 ring-gray-400/30 hover:ring-gray-400/60 group-focus/link:border-2 group-focus/link:border-primary dark:bg-background-dark dark:text-white/50 dark:ring-1 dark:ring-gray-700/25 dark:brightness-[1.35] dark:group-focus/link:border-primary-light dark:hover:ring-white/20 dark:hover:brightness-150">
<LinkIcon />
</div>
</a>
</div>
{/** biome-ignore lint/a11y/noNoninteractiveElementInteractions: TODO */}
{/** biome-ignore lint/a11y/noStaticElementInteractions: TODO */}
{/** biome-ignore lint/a11y/useKeyWithClickEvents: TODO */}
<div
className="flex grow-0 cursor-pointer items-center justify-center rounded-lg bg-primary/10 px-2 py-1 font-medium text-primary text-sm dark:text-primary-light"
contentEditable={false}
data-component-part="update-label"
onClick={copyAnchorLink}
>
{label}
</div>
{tagsArray.length > 0 && (
<div
className="mt-3 flex flex-wrap gap-2 px-1 text-secondary text-sm dark:text-secondary-light"
data-component-part="update-tag-list"
>
{tagsArray.map((tag) => (
<span
className="inline-block rounded-lg font-medium text-sm"
data-component-part="update-tag"
key={tag}
>
{tag}
</span>
))}
Comment thread
pqoqubbw marked this conversation as resolved.
</div>
)}
{description && (
<div
className="wrap-break-word mt-3 max-w-[160px] px-1 text-secondary text-sm dark:text-secondary-light"
contentEditable={false}
data-component-part="update-description"
>
{description}
</div>
)}
</div>

<div className="max-w-full flex-1 overflow-hidden px-0.5" ref={rectRef}>
<div className="prose-sm" data-component-part="update-content">
{children}
</div>
</div>
</div>
);
}
);

Update.displayName = "Update";

export { Update };
export type { UpdateProps };
12 changes: 12 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.