Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
f1c7ced
fix: tw-plugin-peer-next implementation for Tailwind@4
FRSgit Oct 30, 2025
ebb4108
chore: dedupe tailwindcss dep in yarn.lock
FRSgit Oct 30, 2025
508fde3
feat: add array handling to useTwMergeRoot
FRSgit Oct 30, 2025
42d5af0
fix: base component styling
FRSgit Oct 30, 2025
80a44dd
chore: add & reword changesets
FRSgit Oct 30, 2025
a1202bf
feat: redo showcases with new tailwind
FRSgit Nov 3, 2025
a526b4e
chore: lint autofix
FRSgit Nov 3, 2025
73d9ebe
Merge branch 'v2-develop' into feat/redo-showcases-with-new-tailwind
FRSgit Nov 3, 2025
4f0b437
feat!: migrate to react 19
FRSgit Nov 6, 2025
2acd0f4
fix: form showcases
FRSgit Nov 6, 2025
ec10676
fix: quantity selector rounding
FRSgit Nov 6, 2025
771594d
chore: change icons example border
FRSgit Nov 6, 2025
a5ac27a
chore: fix breadcrumbs showcases
FRSgit Nov 6, 2025
a37a81e
fix: breakpoint definitions
FRSgit Nov 6, 2025
3142a5b
chore: remove leftover
FRSgit Nov 6, 2025
306c326
Merge branch 'feat/redo-showcases-with-new-tailwind' into chore/migra…
FRSgit Nov 6, 2025
939a982
chore: upgrade to react 19
FRSgit Nov 6, 2025
5656fa8
chore: merge branch 'v2-develop' into chore/migrate-to-react-19
FRSgit Nov 16, 2025
ff08d55
chore: update tests
FRSgit Nov 16, 2025
89bb381
Merge pull request #3344 from vuestorefront/v2
github-actions[bot] Dec 17, 2025
e279e01
chore: upgrade csstype lib
jagoral Jan 7, 2026
79ebcdb
Merge branch 'v2-develop' of github.com:vuestorefront/storefront-ui i…
jagoral Jan 7, 2026
614bb7b
chore: rc mode
Szymon-dziewonski Jan 9, 2026
f6b8ba4
ci: version packages (rc)
github-actions[bot] Jan 9, 2026
e7cc71d
ci: version packages (rc)
Szymon-dziewonski Jan 9, 2026
cc272c4
feat: add better data-testid handling to sfCheckbox (#3321)
FRSgit Nov 19, 2025
aa2054d
chore: add changeset
Szymon-dziewonski Jan 12, 2026
84dde51
ci: version packages (rc) (#3351)
github-actions[bot] Jan 12, 2026
68feebc
chore: exit pre mode
Szymon-dziewonski Jan 13, 2026
632bb56
Merge branch 'v2-release/4.0.0' of github.com:vuestorefront/storefron…
Szymon-dziewonski Jan 13, 2026
7302a96
ci: version packages (#3352)
github-actions[bot] Jan 13, 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
16 changes: 16 additions & 0 deletions .cursor/commands/create-pr.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Open a PR

- Check that I'm in a branch other than `main`, `staging` or `dev`. If not, bail and explain.
- DO NOT create a new branch, use existing one
- Check the diff between my branch and the base branch (usually `dev`)
- If there's unstaged or staged work that hasn't been commited, commit all the relevant code first
(Use `gh` in case it's installed)
- Write up a quick PR description in the following format
<TLDR> (no more than 2 sentences)

<Description>
- 1~3 bullet points explaining what's changing

- Always use semantic convention as github title. For instance `docs(AT-737): multiple cms-es guide`, `feat(AT-712): add typedApiClient`. Ticket number should be present in the branch name, if not - skip it
- Always paste the link to the PR in your response so I can click it easily
- Prepend GIT_EDITOR=true to all git commands you run, so you can avoid getting blocked as you execute commands
3 changes: 2 additions & 1 deletion _templates/component/new/react_component.ejs.t
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@
to: packages/sfui/frameworks/react/components/<%= name %>/<%= name %>.tsx
force: false
---
import React from 'react';
<% Props = name + 'Props' %>import type { <%= Props %> } from './types';

export default function <%= name %>({
...attributes
}: <%= Props %>): JSX.Element {
}: <%= Props %>): React.JSX.Element {
return (

);
Expand Down
4 changes: 2 additions & 2 deletions apps/preview/next/components/utils/Controls.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import classNames from 'classnames';
import { ChangeEvent, useState } from 'react';
import React, { ChangeEvent, useState } from 'react';
import { SfButton, SfButtonVariant, SfButtonSize, SfIconExpandLess, SfIconExpandMore } from '@storefront-ui/react';
import { useControlsSearchParams } from '../../composables/utils/useControlsSearchParams';
import { ControlOptionBind, ControlsProps, ControlsType } from './types';
Expand Down Expand Up @@ -100,7 +100,7 @@ export default function Controls<T extends { [k: string]: any }>({ controls, sta
<span id={control.modelName}>{control.modelName}</span>
</td>
<td className="value">
{((): JSX.Element | JSX.Element[] => {
{((): React.JSX.Element | React.JSX.Element[] => {
switch (control.type) {
case 'select':
return (
Expand Down
8 changes: 4 additions & 4 deletions apps/preview/next/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@
"classnames": "^2.5.1",
"lodash-es": "^4.17.21",
"next": "^14.2.32",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"react-transition-group": "^4.4.5",
"react-use": "^17.5.1",
"swr": "^2.2.5"
Expand All @@ -36,8 +36,8 @@
"@tailwindcss/typography": "^0.5.19",
"@types/lodash-es": "^4.17.12",
"@types/node": "^20.12.7",
"@types/react": "^18.0.28",
"@types/react-dom": "^18.0.11",
"@types/react": "^19.0.0",
"@types/react-dom": "^19.0.0",
"@types/react-transition-group": "^4.4.5",
"glob-promise": "^6.0.7",
"prettier": "^3.0.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ const options = [
export default function DrawerWithTransition() {
const [open, setOpen] = useState(false);
const [placement, setPlacement] = useState<`${SfDrawerPlacement}`>('left');
const nodeRef = useRef(null);
const drawerRef = useRef(null);
const nodeRef = useRef<Transition<HTMLElement | undefined>>(null);
const drawerRef = useRef<HTMLElement>(null);

useTrapFocus(drawerRef, { activeState: open });

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import { ShowcasePageLayout } from '../../showcases';

// #region source
import { useRef, useState } from 'react';
import { type RefObject, useRef, useState } from 'react';
import { useIntersection } from 'react-use';
import {
SfScrollable,
Expand Down Expand Up @@ -36,13 +36,13 @@ export default function GalleryVertical() {
const firstThumbRef = useRef<HTMLButtonElement>(null);
const [activeIndex, setActiveIndex] = useState(0);

const firstThumbVisible = useIntersection(firstThumbRef, {
const firstThumbVisible = useIntersection(firstThumbRef as RefObject<HTMLElement>, {
root: thumbsRef.current,
rootMargin: '0px',
threshold: 1,
});

const lastThumbVisible = useIntersection(lastThumbRef, {
const lastThumbVisible = useIntersection(lastThumbRef as RefObject<HTMLElement>, {
root: thumbsRef.current,
rootMargin: '0px',
threshold: 1,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -392,7 +392,7 @@ export default function MegaMenuNavigation() {
const [inputValue, setInputValue] = useState('');

const refsByKey = useMemo(() => {
const buttonRefs: Record<string, RefObject<HTMLButtonElement>> = {};
const buttonRefs: Record<string, RefObject<HTMLButtonElement | null>> = {};
content.children?.forEach((item) => {
buttonRefs[item.key] = createRef();
});
Expand Down
8 changes: 2 additions & 6 deletions apps/preview/next/pages/showcases/ProductSlider/Basic.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ const products = Array.from(Array(10), (_, i) => ({
},
}));

function ButtonPrev({ disabled, ...attributes }: { disabled?: boolean }) {
function ButtonPrev({ disabled = false, ...attributes }: { disabled?: boolean }) {
return (
<SfButton
className={classNames('absolute !rounded-full z-10 left-4 bg-white hidden md:block', {
Expand All @@ -39,9 +39,7 @@ function ButtonPrev({ disabled, ...attributes }: { disabled?: boolean }) {
);
}

ButtonPrev.defaultProps = { disabled: false };

function ButtonNext({ disabled, ...attributes }: { disabled?: boolean }) {
function ButtonNext({ disabled = false, ...attributes }: { disabled?: boolean }) {
return (
<SfButton
className={classNames('absolute !rounded-full z-10 right-4 bg-white hidden md:block', {
Expand All @@ -57,8 +55,6 @@ function ButtonNext({ disabled, ...attributes }: { disabled?: boolean }) {
);
}

ButtonNext.defaultProps = { disabled: false };

export default function ProductSliderBasic() {
return (
<SfScrollable
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
/* eslint-disable no-console */
import { ShowcasePageLayout } from '../../showcases';
// #region source
import { type ChangeEvent, type FormEvent, type KeyboardEvent, useState, useRef } from 'react';
import React, { type ChangeEvent, type FormEvent, type KeyboardEvent, useState, useRef } from 'react';
import { useDebounce } from 'react-use';
import { offset } from '@floating-ui/react-dom';
import {
Expand All @@ -21,7 +21,7 @@ import {
interface Product {
id: string;
name: string;
thumbnail?: JSX.Element;
thumbnail?: React.JSX.Element;
image?: string;
}

Expand Down
8 changes: 4 additions & 4 deletions apps/test/react/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@
"test:ci:react": "yarn test:ci && CYPRESS_COVERAGE=true yarn cypress run --component && yarn generate-coverage"
},
"dependencies": {
"react": "^18.3.1",
"react-dom": "^18.3.1"
"react": "^19.0.0",
"react-dom": "^19.0.0"
},
"devDependencies": {
"@cypress/code-coverage": "3.13.4",
Expand All @@ -37,8 +37,8 @@
"@storefront-ui/typography": "workspace:*",
"@tailwindcss/postcss": "^4.1.14",
"@tailwindcss/typography": "^0.5.19",
"@types/react": "^18.0.28",
"@types/react-dom": "^18.0.11",
"@types/react": "^19.0.0",
"@types/react-dom": "^19.0.0",
"@vitejs/plugin-react": "^4.3.1",
"autoprefixer": "^10.4.19",
"chokidar-cli": "^3.0.0",
Expand Down
22 changes: 22 additions & 0 deletions packages/sfui/frameworks/react/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,27 @@
# @storefront-ui/react

## 4.0.0

### Major Changes

- [#3316](https://github.com/vuestorefront/storefront-ui/pull/3316) [`939a982`](https://github.com/vuestorefront/storefront-ui/commit/939a9821c0cfd69d876994182b2442aa2cf7f4d6) Thanks [@FRSgit](https://github.com/FRSgit)! - - **[BREAKING][CHANGED]** upgrade to React 19. There are no breaking changes specific to SFUI library itself. To upgrade, please [follow official React guide](https://react.dev/blog/2024/04/25/react-19-upgrade-guide).

### Patch Changes

- [#3350](https://github.com/vuestorefront/storefront-ui/pull/3350) [`aa2054d`](https://github.com/vuestorefront/storefront-ui/commit/aa2054da417f3d82601d35846511a3b36997c5f6) Thanks [@Szymon-dziewonski](https://github.com/Szymon-dziewonski)! - [UPDATED] add better data-testid handling to sfCheckbox

## 4.0.0-rc.1

### Patch Changes

- [#3350](https://github.com/vuestorefront/storefront-ui/pull/3350) [`aa2054d`](https://github.com/vuestorefront/storefront-ui/commit/aa2054da417f3d82601d35846511a3b36997c5f6) Thanks [@Szymon-dziewonski](https://github.com/Szymon-dziewonski)! - [UPDATED] add better data-testid handling to sfCheckbox

## 4.0.0-rc.0

### Major Changes

- [#3316](https://github.com/vuestorefront/storefront-ui/pull/3316) [`939a982`](https://github.com/vuestorefront/storefront-ui/commit/939a9821c0cfd69d876994182b2442aa2cf7f4d6) Thanks [@FRSgit](https://github.com/FRSgit)! - - **[BREAKING][CHANGED]** upgrade to React 19. There are no breaking changes specific to SFUI library itself. To upgrade, please [follow official React guide](https://react.dev/blog/2024/04/25/react-19-upgrade-guide).

## 3.1.0

### Minor Changes
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import React from 'react';
import { SfBadgePlacement } from '@storefront-ui/shared';
import { twMerge, type SfBadgeProps } from '@storefront-ui/react';

Expand All @@ -8,7 +9,7 @@ export default function SfBadge({
placement = SfBadgePlacement['top-right'],
className,
...attributes
}: SfBadgeProps): JSX.Element {
}: SfBadgeProps): React.JSX.Element {
const isDot = variant === 'dot';
let displayValue = content;
if (isDot) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useRef, useEffect, useState } from 'react';
import React, { useRef, useEffect, useState } from 'react';
import {
mergeRefs,
SfIconCheckBox,
Expand All @@ -13,9 +13,9 @@ const defaultWrapperTag = 'label';

const SfCheckbox = polymorphicForwardRef<'input', SfCheckboxProps>(
(
{ wrapperAs, invalid, className, indeterminate: indeterminateProp, wrapperClassName, ...attributes },
{ wrapperAs, invalid, className, indeterminate: indeterminateProp, wrapperClassName, 'data-testid': dataTestId, ...attributes },
ref,
): JSX.Element => {
): React.JSX.Element => {
const inputRef = useRef<HTMLInputElement>(null);
const WrapperTag = wrapperAs || defaultWrapperTag;
const [isIndeterminate, setIsIndeterminate] = useState(indeterminateProp || false);
Expand Down Expand Up @@ -47,7 +47,7 @@ const SfCheckbox = polymorphicForwardRef<'input', SfCheckboxProps>(
},
wrapperClassName,
)}
data-testid="checkbox"
data-testid={dataTestId ?? "checkbox"}
>
<input
className={twMerge('sr-only', className)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@ export interface SfCheckboxProps extends PropsWithStyle, InputHTMLAttributes<HTM
invalid?: boolean;
wrapperAs?: ElementType<any> | undefined;
wrapperClassName?: string;
'data-testid'?: string;
indeterminate?: boolean;
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import React from 'react';
import type { SfCounterProps } from '@storefront-ui/react';
import { SfCounterSize, twMerge } from '@storefront-ui/react';

Expand All @@ -7,7 +8,7 @@ export default function SfCounter({
children,
className,
...attributes
}: SfCounterProps): JSX.Element {
}: SfCounterProps): React.JSX.Element {
const sizeClasses: Record<SfCounterSize, string> = {
[SfCounterSize['3xs']]: twMerge('text-3xs', { 'px-1': pill }),
[SfCounterSize['2xs']]: twMerge('text-2xs', { 'px-1.5': pill }),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import React from 'react';
import { SfLoaderSize, twMerge } from '@storefront-ui/react';
import type { SfLoaderCircularProps } from '@storefront-ui/react';

Expand Down Expand Up @@ -29,7 +30,7 @@ export default function SfLoaderCircular({
className,
circleClassName,
...attributes
}: SfLoaderCircularProps): JSX.Element {
}: SfLoaderCircularProps): React.JSX.Element {
return (
<svg
className={twMerge(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import React from 'react';
import { SfLoaderLinearSize, SfLoaderSize, twMerge } from '@storefront-ui/react';
import type { SfLoaderLinearProps } from '@storefront-ui/react';

Expand All @@ -18,7 +19,7 @@ export default function SfLoaderLinear({
ariaLabel = 'loading',
className,
...attributes
}: SfLoaderLinearProps): JSX.Element {
}: SfLoaderLinearProps): React.JSX.Element {
return (
<span
className={twMerge(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import React from 'react';
import { SfProgressSize, twMerge } from '@storefront-ui/react';
import type { SfProgressCircularProps } from '@storefront-ui/react';

Expand Down Expand Up @@ -31,7 +32,7 @@ export default function SfProgressCircular({
className,
circleClassName,
...attributes
}: SfProgressCircularProps): JSX.Element {
}: SfProgressCircularProps): React.JSX.Element {
const strokeDasharray = `${(value / 100) * 151}, 150`;
return (
<svg
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import React from 'react';
import { SfProgressSize, SfProgressLinearSize, twMerge } from '@storefront-ui/react';
import type { SfProgressLinearProps } from '@storefront-ui/react';

Expand All @@ -19,7 +20,7 @@ export default function SfProgressLinear({
ariaLabel = 'Progress element',
className,
...attributes
}: SfProgressLinearProps): JSX.Element {
}: SfProgressLinearProps): React.JSX.Element {
return (
<progress
data-testid="progress-linear"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
'use client';
import { useState, type ChangeEvent } from 'react';
import React, { useState, type ChangeEvent } from 'react';
import classnames from 'classnames';
import {
SfIconStar,
Expand Down Expand Up @@ -50,7 +50,7 @@ export default function SfRatingButton({
getLabelText = defaultLabelText,
children = renderDefaultIcon,
...attributes
}: SfRatingButtonProps): JSX.Element {
}: SfRatingButtonProps): React.JSX.Element {
const [hoverValue, setHoverValue] = useState(0);
const icons = Array.from({ length: Math.floor(Math.abs(max)) }, (_, index) => index + 1);
const isIconFilled = (ratingValue: number) => ratingValue <= hoverValue || (hoverValue === 0 && ratingValue <= value);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { forwardRef } from 'react';
import React, { forwardRef } from 'react';
import { twMerge, type SfSwitchProps } from '@storefront-ui/react';

const SfSwitch = forwardRef<HTMLInputElement, SfSwitchProps>(
({ invalid, className, ...attributes }, ref): JSX.Element => (
({ invalid, className, ...attributes }, ref): React.JSX.Element => (
<input
ref={ref}
className={twMerge(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
'use client';
import { SfTextareaSize, twMerge, useFocusVisible } from '@storefront-ui/react';
import { forwardRef } from 'react';
import React, { forwardRef } from 'react';
import type { SfTextareaProps } from './types';

const sizeClasses = {
Expand All @@ -10,7 +10,7 @@ const sizeClasses = {
};

export default forwardRef<HTMLTextAreaElement, SfTextareaProps>(
({ size = SfTextareaSize.base, invalid = false, className, ...attributes }, ref): JSX.Element => {
({ size = SfTextareaSize.base, invalid = false, className, ...attributes }, ref): React.JSX.Element => {
const { isFocusVisible } = useFocusVisible({ isTextInput: true });

return (
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import React from 'react';
import { SfThumbnailProps, SfThumbnailSize, twMerge } from '@storefront-ui/react';

const sizeClasses = {
Expand All @@ -12,7 +13,7 @@ export default function SfThumbnail({
children,
className,
...attributes
}: SfThumbnailProps): JSX.Element {
}: SfThumbnailProps): React.JSX.Element {
return (
<div
className={twMerge('rounded-full overflow-hidden bg-clip-content p-0.5', sizeClasses[size], className)}
Expand Down
Loading
Loading