Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
3,454 changes: 1,760 additions & 1,694 deletions pnpm-lock.yaml

Large diffs are not rendered by default.

6 changes: 6 additions & 0 deletions semcore/base-components/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@

CHANGELOG.md standards are inspired by [keepachangelog.com](https://keepachangelog.com/en/1.0.0/).

## [17.0.0] - 2026-02-02

### BREAK

- Removed using `getNodeByRef` in `Portal`, `OutsideClick`, `ScrollArea` components. Use `React.RefObject` instead.

## [16.4.2] - 2025-12-01

### Fixed
Expand Down
2 changes: 1 addition & 1 deletion semcore/base-components/__tests__/Portal.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ describe('Portal', () => {
});

test.concurrent('Verify render change containerNode', () => {
const containerRef = React.createRef<any>();
const containerRef = React.createRef<HTMLDivElement>();
const { getByTestId } = render(
<>
<div data-testid='container' ref={containerRef} />
Expand Down
4 changes: 2 additions & 2 deletions semcore/base-components/__tests__/outside-click.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ describe('OutsideClick', () => {
</div>
<OutsideClick
onOutsideClick={onOutsideClick}
excludeRefs={[outsideRef1, outsideRef2, document.body]}
excludeRefs={[outsideRef1, outsideRef2, { current: document.body }]}
>
<div data-testid='child'>test</div>
</OutsideClick>
Expand Down Expand Up @@ -66,7 +66,7 @@ describe('OutsideClick', () => {
const onOutsideClick = vi.fn();
render(
<>
<OutsideClick onOutsideClick={onOutsideClick} excludeRefs={[document.body]} />
<OutsideClick onOutsideClick={onOutsideClick} excludeRefs={[{ current: document.body }]} />
</>,
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ test.describe(`${TAG.FUNCTIONAL}`, () => {

await expect
.poll(async () => await checkAriaMaxValue(scrollBar))
.toBeGreaterThan(initialMax);
.toBeGreaterThanOrEqual(initialMax);

await grid.focus();
await page.keyboard.press('ArrowDown');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { createComponent, type Intergalactic, type IRootComponentProps } from '@
import { getEventTarget } from '@semcore/core/lib/utils/getEventTarget';
import getOriginChildren from '@semcore/core/lib/utils/getOriginChildren';
import ownerDocument from '@semcore/core/lib/utils/ownerDocument';
import { getNodeByRef, type NodeByRef, useForkRef } from '@semcore/core/lib/utils/ref';
import { useForkRef } from '@semcore/core/lib/utils/ref';
import useEventCallback from '@semcore/core/lib/utils/use/useEventCallback';
import React, { cloneElement } from 'react';

Expand All @@ -17,12 +17,12 @@ export type OutsideClickProps = {
* List of refs that will not trigger `onOutsideClick` when clicked
* @default []
*/
excludeRefs?: Array<NodeByRef>;
excludeRefs?: Array<React.RefObject<HTMLElement>>;

/** Root element
* @default document
* */
root?: NodeByRef;
root?: React.RefObject<HTMLElement>;
};

type OutsideClickEvents = { [key in 'mouseup' | 'mousedown']: EventListenerOrEventListenerObject };
Expand All @@ -38,7 +38,7 @@ function OutsideClickRoot(props: OutsideClickProps & IRootComponentProps) {
const handleRef = useForkRef(children ? children.ref : null, nodeRef, forwardRef!);

const handleOutsideClick = useEventCallback((event: any) => {
const nodesToCheck = [...(excludeRefs as any), nodeRef].map((ref) => getNodeByRef(ref));
const nodesToCheck = [...excludeRefs, nodeRef].map((ref) => ref?.current);
const eventTarget = getEventTarget(event) as Node | null;

const isTargetEvent = nodesToCheck.some(
Expand All @@ -51,7 +51,7 @@ function OutsideClickRoot(props: OutsideClickProps & IRootComponentProps) {
});

const handleMouseDown = useEventCallback((event: any) => {
const nodesToCheck = [...(excludeRefs as any), nodeRef].map((ref) => getNodeByRef(ref));
const nodesToCheck = [...excludeRefs, nodeRef].map((ref) => ref?.current);
const eventTarget = getEventTarget(event) as Node | null;

mouseDownInside.current = nodesToCheck.some((node) => node?.contains(eventTarget));
Expand All @@ -73,7 +73,7 @@ function OutsideClickRoot(props: OutsideClickProps & IRootComponentProps) {
};

React.useEffect(() => {
const outsideRoot = root ? getNodeByRef(root) : ownerDocument(nodeRef.current as any);
const outsideRoot = root ? root.current : ownerDocument(nodeRef.current as any);

// disable previous events
toggleEvents(false, outsideRoot);
Expand Down
13 changes: 7 additions & 6 deletions semcore/base-components/src/components/portal/Portal.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { createComponent, register, type Intergalactic, type UnknownProperties } from '@semcore/core';
import { createComponent, register, type Intergalactic } from '@semcore/core';
import canUseDOM from '@semcore/core/lib/utils/canUseDOM';
import { getNodeByRef, type NodeByRef } from '@semcore/core/lib/utils/ref';
import React from 'react';
import { createPortal } from 'react-dom';

Expand All @@ -12,13 +11,15 @@ export type PortalProps = {
/** Called when portal mount state changes */
onMount?: (mounted: boolean) => void;
/** Manually set node to mount portal content */
nodeToMount?: NodeByRef;
nodeToMount?: HTMLElement;
};

type PortalContextType = React.RefObject<HTMLElement | null> | HTMLElement | null;

const PortalContext = register.get(
'portal-context',

React.createContext<NodeByRef>((canUseDOM() ? document.body : null) as any),
React.createContext<PortalContextType>(canUseDOM() ? document.body : null),
);

function Portal(props: PortalProps & { Children: React.FC }) {
Expand All @@ -34,10 +35,10 @@ function Portal(props: PortalProps & { Children: React.FC }) {
return;
}
if (nodeToMount) {
setMountNode(getNodeByRef(nodeToMount));
setMountNode(nodeToMount);
return;
}
setMountNode(getNodeByRef(container));
setMountNode((container && 'current' in container) ? container.current : container);
}, [container, disablePortal, onMount, nodeToMount]);

if (disablePortal) {
Expand Down
22 changes: 10 additions & 12 deletions semcore/base-components/src/components/scroll-area/ScrollArea.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,8 @@ import canUseDOM from '@semcore/core/lib/utils/canUseDOM';
import keyboardFocusEnhance from '@semcore/core/lib/utils/enhances/keyboardFocusEnhance';
import { isAdvanceMode } from '@semcore/core/lib/utils/findComponent';
import trottle from '@semcore/core/lib/utils/rafTrottle';
import { getNodeByRef } from '@semcore/core/lib/utils/ref';
import uniqueIDEnhancement from '@semcore/core/lib/utils/uniqueID';
import React, { type ForwardedRef } from 'react';
import { findDOMNode } from 'react-dom';

import { Box } from '../flex-box';
import { setAreaValue, ScrollBar } from './ScrollBar';
Expand All @@ -33,8 +31,8 @@ type State = {
};

type DefaultProps = {
container: React.Ref<HTMLElement>;
inner: React.Ref<HTMLElement>;
container: React.Ref<HTMLElement | null>;
inner: React.Ref<HTMLElement | null>;
tabIndex: number;
observeParentSize: boolean;
disableAutofocusToContent: boolean;
Expand All @@ -51,8 +49,8 @@ class ScrollAreaRoot extends Component<ScrollAreaProps, typeof ScrollAreaRoot.en
static enhance = [uniqueIDEnhancement(), keyboardFocusEnhance()] as const;

static defaultProps: () => DefaultProps = () => ({
container: React.createRef(),
inner: React.createRef(),
container: React.createRef<HTMLElement | null>(),
inner: React.createRef<HTMLElement | null>(),
tabIndex: 0,
observeParentSize: false,
disableAutofocusToContent: false,
Expand All @@ -68,15 +66,15 @@ class ScrollAreaRoot extends Component<ScrollAreaProps, typeof ScrollAreaRoot.en
verticalBarRef = React.createRef<HTMLElement>();

get $container(): HTMLElement | null {
const element = getNodeByRef(this.asProps.container!);
const element = this.asProps.container.current;

return element instanceof HTMLElement ? element : null;
return element;
}

get $inner(): HTMLElement | null {
const element = getNodeByRef(this.asProps.inner!);
const element = this.asProps.inner.current;

return element instanceof HTMLElement ? element : null;
return element;
}

state: State = {
Expand All @@ -92,8 +90,8 @@ class ScrollAreaRoot extends Component<ScrollAreaProps, typeof ScrollAreaRoot.en
}
}

refWrapper = (node: HTMLElement) => {
this.$wrapper = findDOMNode(node) as HTMLElement;
refWrapper = (node: HTMLElement | null) => {
this.$wrapper = node;
};

setStyleSizeProperty = (element: HTMLElement, propertyKey: string, value: string | number) => {
Expand Down
41 changes: 24 additions & 17 deletions semcore/base-components/src/components/scroll-area/ScrollBar.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import { createComponent, sstyled, Component, Root } from '@semcore/core';
import contextEnhance from '@semcore/core/lib/utils/enhances/contextEnhance';
import { getNodeByRef } from '@semcore/core/lib/utils/ref';
import React from 'react';
import { findDOMNode } from 'react-dom';

import { Box } from '../flex-box';
import type { ScrollBar as ScrollBarType, ScrollBarProps } from './ScrollBar.types';
Expand Down Expand Up @@ -33,7 +31,11 @@ const setAriaValues = (
}
};

class ScrollBarRoot extends Component<ScrollBarProps, typeof ScrollBarRoot.enhance> {
type State = {
visibleScroll: boolean;
};

class ScrollBarRoot extends Component<ScrollBarProps, typeof ScrollBarRoot.enhance, {}, { container: React.RefObject<HTMLElement> | null }, State> {
static displayName = 'Bar';

static style = style;
Expand All @@ -43,7 +45,7 @@ class ScrollBarRoot extends Component<ScrollBarProps, typeof ScrollBarRoot.enhan

static defaultProps = () => {
return {
container: React.createRef(),
container: React.createRef<HTMLElement | null>(),
children: <ScrollBar.Slider />,
};
};
Expand All @@ -59,27 +61,30 @@ class ScrollBarRoot extends Component<ScrollBarProps, typeof ScrollBarRoot.enhan
_scroll = { left: 0, top: 0 };
_mouse = { pageX: 0, pageY: 0 };

state = {
state: State = {
visibleScroll: false,
};

get $container(): Element {
return getNodeByRef(this.asProps.container!)!;
get $container(): Element | null {
return this.asProps.container.current;
}

refBar = (node: HTMLElement) => {
const domNode = findDOMNode(node) as HTMLElement;
this.$bar = domNode;
const orientation = this.getOrientation();
const { horizontalBarRef, verticalBarRef } = this.asProps;
if (orientation === 'horizontal' && horizontalBarRef) horizontalBarRef.current = domNode;
if (orientation === 'vertical' && verticalBarRef) verticalBarRef.current = domNode;
refBar = (domNode: HTMLElement | null) => {
if (domNode !== null) {
this.$bar = domNode;
const orientation = this.getOrientation();
const { horizontalBarRef, verticalBarRef } = this.asProps;
if (orientation === 'horizontal' && horizontalBarRef) horizontalBarRef.current = domNode;
if (orientation === 'vertical' && verticalBarRef) verticalBarRef.current = domNode;

setAriaValues(this.$container, horizontalBarRef?.current, verticalBarRef?.current);
setAriaValues(this.$container, horizontalBarRef?.current, verticalBarRef?.current);
}
};

refSlider = (node: HTMLElement) => {
this.$slider = findDOMNode(node) as HTMLElement;
refSlider = (node: HTMLElement | null) => {
if (node) {
this.$slider = node;
}
};

calculateVisibleScroll() {
Expand Down Expand Up @@ -245,6 +250,8 @@ class ScrollBarRoot extends Component<ScrollBarProps, typeof ScrollBarRoot.enhan
};

handleMouseDownBar = (e: MouseEvent) => {
if (!this.$container) return;

// cancellation of the ascent as in a real scroll
e.stopPropagation();

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import type { PropGetterFn, Intergalactic, UnknownProperties } from '@semcore/core';
import type { NodeByRef } from '@semcore/core/lib/utils/ref';
import type { PropGetterFn, Intergalactic } from '@semcore/core';

import type { Box, BoxProps } from '../flex-box';

Expand All @@ -11,9 +10,9 @@ export type ScrollAreaProps = BoxProps & {
/** Scroll direction */
orientation?: 'horizontal' | 'vertical';
/** Link to the dom element, which will be a container with overflow */
container?: NodeByRef;
container?: React.RefObject<HTMLElement | null>;
/** Link to the dom element that will be stretched along with the content */
inner?: NodeByRef;
inner?: React.RefObject<HTMLElement | null>;
/** Callback executed when container change size */
onResize?: ResizeObserverCallback;
/** Called every time user scrolls area */
Expand Down Expand Up @@ -62,7 +61,7 @@ export type ScrollBarProps = BoxProps & {
/** The direction of the scroll that can be calculated automatically */
orientation?: 'horizontal' | 'vertical';
/** Reference to the scrollable container element */
container?: React.RefObject<HTMLElement>;
container?: React.RefObject<HTMLElement | null>;
};

export type ScrollBarContext = ScrollBarProps & {
Expand Down
4 changes: 1 addition & 3 deletions semcore/checkbox/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,7 @@
"@semcore/typography": "16.3.1"
},
"peerDependencies": {
"@semcore/base-components": "^16.0.0",
"react": "16.8 - 18",
"react-dom": "16.8 - 18"
"@semcore/base-components": "^16.0.0"
},
"repository": {
"type": "git",
Expand Down
10 changes: 10 additions & 0 deletions semcore/core/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,16 @@

CHANGELOG.md standards are inspired by [keepachangelog.com](https://keepachangelog.com/en/1.0.0/).

## [17.0.0] - 2026-02-02

### BREAK

- Removed `WithI18n`. Use `useI18n`.
- Removed `WithCSS`. Use `useCss`.
- Removed `WithAutoFocus`. Use `autoFocusEnhance`.
- Removed `WithKeyboardFocus`. Just don't use.
- Removed `WithRef`. Use `useForkRef`.

## [16.5.1] - 2025-10-30

### Fixed
Expand Down
17 changes: 1 addition & 16 deletions semcore/core/__tests__/utils.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import getInputProps, { inputProps } from '../src/utils/inputProps';
import isNode from '../src/utils/isNode';
import propsForElement, { validAttr } from '../src/utils/propsForElement';
import reactToText from '../src/utils/reactToText';
import { getRef, setRef, getNodeByRef } from '../src/utils/ref';
import { getRef, setRef } from '../src/utils/ref';
import useCss from '../src/utils/use/useCss';

describe('Utils CSS in JS', () => {
Expand Down Expand Up @@ -424,21 +424,6 @@ describe('Utils ref', () => {
setRef(fn, div);
expect(fn).toHaveBeenCalledWith(div);
});

test.concurrent('[getNodeByRef] support function', () => {
const div = document.createElement('div');
const fn = vi.fn(() => div);
// setRef(fn, div)
expect(getNodeByRef(fn)).toBe(div);
});

test.concurrent('[getNodeByRef] support ref', () => {
const div = document.createElement('div');
const ref = React.createRef<HTMLDivElement>();
// @ts-ignore
ref.current = div;
expect(getNodeByRef(ref)).toBe(div);
});
});

describe('Enhances - keyboardFocusEnhances', () => {
Expand Down
4 changes: 2 additions & 2 deletions semcore/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -315,8 +315,8 @@
"@babel/runtime": "7.27.6"
},
"peerDependencies": {
"react": "16.8 - 18",
"react-dom": "16.8 - 18"
"react": "16.8 - 19",
"react-dom": "16.8 - 19"
},
"repository": {
"type": "git",
Expand Down
Loading
Loading