Skip to content
Open
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
2 changes: 1 addition & 1 deletion semcore/pills/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"author": "UI-kit team <ui-kit-team@semrush.com>",
"license": "MIT",
"scripts": {
"build": "pnpm semcore-builder --source=js && pnpm vite build"
"build": "pnpm semcore-builder && pnpm vite build"
},
"exports": {
"require": "./lib/cjs/index.js",
Expand Down
102 changes: 48 additions & 54 deletions semcore/pills/src/Pills.jsx → semcore/pills/src/Pills.tsx
Original file line number Diff line number Diff line change
@@ -1,58 +1,63 @@
import { NeighborLocation, Box, useNeighborLocationDetect } from '@semcore/base-components';
import type { Intergalactic, IRootComponentProps } from '@semcore/core';
import { createComponent, Component, sstyled, Root } from '@semcore/core';
import addonTextChildren from '@semcore/core/lib/utils/addonTextChildren';
import a11yEnhance from '@semcore/core/lib/utils/enhances/a11yEnhance';
import React from 'react';

import type { IntergalacticPillsComponent, PillProps, PillsComponent, PillsHandlers, PillsProps } from './Pills.type';
import style from './style/pills.shadow.css';

const optionsA11yEnhance = {
onNeighborChange: (neighborElement, props) => {
if (neighborElement) {
neighborElement.focus();
if (props.behavior === 'auto') {
neighborElement.click();
}
}
},
childSelector: (props) =>
props.behavior === 'auto' ? ['role', 'radio'] : ['role', 'tab'],
};

class RootPills extends Component {
class RootPills extends Component<PillsProps, typeof RootPills.enhance, PillsHandlers> {
static displayName = 'Pills';
static style = style;
static defaultProps = ({ behavior }) => ({
static defaultProps = ({ behavior }: PillsProps) => ({
size: 'm',
defaultValue: null,
behavior: behavior ?? 'auto',
});

itemValues = [];
static enhance = [a11yEnhance(optionsA11yEnhance)];
itemValues: Array<PillProps['value']> = [];

static enhance = [a11yEnhance({
onNeighborChange: (neighborElement, props) => {
if (neighborElement) {
neighborElement.focus();
if (props.behavior === 'auto') {
neighborElement.click();
}
}
},
childSelector: (props) => {
const selector = props.behavior === 'auto' ? ['role', 'radio'] : ['role', 'tab'];

return selector as [string, string];
},
})] as const;

uncontrolledProps() {
return {
value: null,
};
}

bindHandlerClick = (value) => (e) => {
bindHandlerClick = (value: PillProps['value']) => (e: React.MouseEvent) => {
this.handlers.value(value, e);
};

bindHandleKeyDown = (value) => (event) => {
if (event.key === 'Enter' || event.key === ' ') {
event.preventDefault();
this.handlers.value(value, event);
bindHandleKeyDown = (value: PillProps['value']) => (e: React.KeyboardEvent) => {
if (e.key === 'Enter' || e.key === ' ') {
e.preventDefault();
this.handlers.value(value, e);
}
};

getItemProps(props, index) {
getItemProps(props: PillProps, index: number) {
const { value, size, disabled, behavior } = this.asProps;
const isSelected = value === props.value;

this.itemValues[index] = props.value;

return {
index: index,
size,
Expand All @@ -65,23 +70,6 @@ class RootPills extends Component {
};
}

changeIndex = (startIndex, type) => {
let selectable = false;

while (!selectable && startIndex >= 0 && startIndex < this.itemValues.length) {
if (type === 'increment') startIndex++;
if (type === 'decrement') startIndex--;

const element = this.itemRefs[startIndex];

if (element?.disabled === false) {
selectable = true;
}
}

return startIndex >= 0 && startIndex < this.itemValues.length ? startIndex : undefined;
};

render() {
const SPills = Root;
const { Children, styles, controlsLength, disabled, behavior, value } = this.asProps;
Expand All @@ -101,18 +89,19 @@ class RootPills extends Component {
}
}

function Pill(props) {
type PillPropsFromRoot = ReturnType<InstanceType<typeof RootPills>['getItemProps']>;

function Pill(props: PillPropsFromRoot & PillProps & IRootComponentProps) {
const SPill = Root;
const { Children, styles, addonLeft, addonRight, selected, disabled, index, behavior } = props;
const neighborLocation = useNeighborLocationDetect(index);
const roleAreaProps = {};
if (behavior === 'auto') {
roleAreaProps.role = 'radio';
roleAreaProps['aria-checked'] = selected;
} else {
roleAreaProps.role = 'tab';
roleAreaProps['aria-selected'] = selected;
}

const roleAreaProps = {
'role': behavior === 'auto' ? 'radio' : 'tab',
'aria-checked': behavior === 'auto' ? selected : undefined,
'aria-selected': behavior !== 'auto' ? selected : undefined,
};

return sstyled(styles)(
<SPill
render={Box}
Expand All @@ -130,20 +119,25 @@ function Pill(props) {
);
}

function Text(props) {
function Text(props: IRootComponentProps) {
const SText = Root;
return sstyled(props.styles)(<SText render={Box} tag='span' />);
}

function Addon(props) {
function Addon(props: IRootComponentProps) {
const SAddon = Root;
return sstyled(props.styles)(<SAddon render={Box} tag='span' />);
}

export const wrapPills = <PropsExtending extends {}>(wrapper: (
props: Intergalactic.InternalTypings.UntypeRefAndTag<
Intergalactic.InternalTypings.ComponentPropsNesting<IntergalacticPillsComponent>
> &
PropsExtending,
) => React.ReactNode) => wrapper as IntergalacticPillsComponent<PropsExtending>;

const Pills = createComponent(RootPills, {
Item: [Pill, { Text, Addon }],
});

export const wrapPills = (wrapper) => wrapper;
}) as unknown as PillsComponent;

export default Pills;
18 changes: 3 additions & 15 deletions semcore/pills/src/index.d.ts → semcore/pills/src/Pills.type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,10 @@ export type PillsContext = {
};

export type PillsHandlers = {
value: (value: PillsValue) => void;
value: PillsValue;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

not sure abouh this...

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

uncontrolledProps() {
    return {
      value: null,
    };
  }

is it should be a function?

};

type IntergalacticPillsComponent<PropsExtending = {}> = (<
export type IntergalacticPillsComponent<PropsExtending = {}> = (<
Value extends PillsValue,
Tag extends Intergalactic.Tag = 'div',
>(
Expand All @@ -68,21 +68,9 @@ type IntergalacticPillsComponent<PropsExtending = {}> = (<
) => Intergalactic.InternalTypings.ComponentRenderingResults) &
Intergalactic.InternalTypings.ComponentAdditive<'div', 'div', PillsProps>;

declare const Pills: IntergalacticPillsComponent & {
export type PillsComponent = IntergalacticPillsComponent & {
Item: Intergalactic.Component<'button', PillProps, [handlers: PillsHandlers]> & {
Text: typeof Box;
Addon: typeof Box;
};
};

declare const wrapPills: <PropsExtending extends {}>(
wrapper: (
props: Intergalactic.InternalTypings.UntypeRefAndTag<
Intergalactic.InternalTypings.ComponentPropsNesting<IntergalacticPillsComponent>
> &
PropsExtending,
) => React.ReactNode,
) => IntergalacticPillsComponent<PropsExtending>;
export { wrapPills };

export default Pills;
2 changes: 0 additions & 2 deletions semcore/pills/src/index.js

This file was deleted.

2 changes: 2 additions & 0 deletions semcore/pills/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { default, wrapPills } from './Pills';
export * from './Pills.type';
2 changes: 1 addition & 1 deletion semcore/pills/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export default mergeConfig(
defineConfig({
build: {
lib: {
entry: './src/index.js',
entry: './src/index.ts',
},
rollupOptions: {
external: ['react', 'react-dom', 'react/jsx-runtime', /@babel\/runtime\/*/, /@semcore\/*/],
Expand Down
Loading