diff --git a/playground/entries/ColorPicker.tsx b/playground/entries/ColorPicker.tsx index 2b88a124d3..97dde7487c 100644 --- a/playground/entries/ColorPicker.tsx +++ b/playground/entries/ColorPicker.tsx @@ -1,4 +1,4 @@ -import type { ColorPickerProps } from '@semcore/ui/color-picker'; +import type { NSColorPicker } from '@semcore/ui/color-picker'; import ColorPicker from '@semcore/ui/color-picker'; import React from 'react'; @@ -6,7 +6,7 @@ import type { JSXProps } from '../types/JSXProps'; import type { PlaygroundEntry } from '../types/Playground'; import createGithubLink from '../utils/createGHLink'; -export type ColorPickerJSXProps = JSXProps; +export type ColorPickerJSXProps = JSXProps; function getJSX({ handleControlChange, ...colorPickerProps }: ColorPickerJSXProps) { return ; diff --git a/playground/entries/Counter.tsx b/playground/entries/Counter.tsx index c53dd66795..c36a9d363e 100644 --- a/playground/entries/Counter.tsx +++ b/playground/entries/Counter.tsx @@ -1,4 +1,4 @@ -import type { CounterProps } from '@semcore/ui/counter'; +import type { NSCounter } from '@semcore/ui/counter'; import Counter from '@semcore/ui/counter'; import React from 'react'; @@ -6,7 +6,7 @@ import type { JSXProps } from '../types/JSXProps'; import type { PlaygroundEntry } from '../types/Playground'; import createGithubLink from '../utils/createGHLink'; -export type CounterJSXProps = JSXProps; +export type CounterJSXProps = JSXProps; function getJSX({ handleControlChange, ...counterProps }: CounterJSXProps) { return ; diff --git a/semcore/accordion/src/Accordion.tsx b/semcore/accordion/src/Accordion.tsx index d371e7157c..d164a445d5 100644 --- a/semcore/accordion/src/Accordion.tsx +++ b/semcore/accordion/src/Accordion.tsx @@ -14,13 +14,16 @@ import style from './style/accordion.shadow.css'; class RootAccordion extends Component< Intergalactic.InternalTypings.InferComponentProps, typeof RootAccordion.enhance, - NSAccordion.Handlers + NSAccordion.Handlers, + {}, + {}, + NSAccordion.DefaultProps > { static displayName = 'Accordion'; static style = style; static defaultProps = { defaultValue: [], - use: 'secondary', + use: 'secondary' as const, }; static enhance = [ @@ -209,16 +212,22 @@ function Collapse( ); } -const Item = createComponent(RootItem, { +const Item = createComponent< + NSAccordion.Item.Component, + typeof RootItem +>(RootItem, { Toggle, Chevron, ToggleButton, Collapse, -}) as NSAccordion.Item.Component; +}); -const Accordion = createComponent(RootAccordion, { +const Accordion = createComponent< + NSAccordion.Component, + typeof RootAccordion +>(RootAccordion, { Item, -}) as unknown as NSAccordion.Component; +}); export const wrapAccordion = ( wrapper: ( diff --git a/semcore/accordion/src/Accordion.type.ts b/semcore/accordion/src/Accordion.type.ts index b66a4ededf..822bce476d 100644 --- a/semcore/accordion/src/Accordion.type.ts +++ b/semcore/accordion/src/Accordion.type.ts @@ -8,23 +8,23 @@ declare namespace NSAccordion { type Value = null | number | string | Array; type Props = FlexProps & { /** Value for the active tab. Can be set as stroke, number, null or as array. - * @type AccordionValue + * @type NSAccordion.Value * */ value?: V; /** * Value of the active tabs selected by default - * @type AccordionValue + * @type NSAccordion.Value * @default [] */ defaultValue?: V; /** Called when the selection is changed - * @type (value: AccordionValue, event?: React.SyntheticEvent) => void + * @type (value: NSAccordion.Value, event?: React.SyntheticEvent) => void * */ onChange?: | ((value: V, event?: React.SyntheticEvent) => void) | React.Dispatch>; /** Animation duration of each Accordion.Item inside - * @default 350 */ + * @default 200 */ duration?: number; /** * Changes the visual appearance of the component @@ -38,6 +38,10 @@ declare namespace NSAccordion { type Handlers = { value: Props['value']; }; + type DefaultProps = { + defaultValue: Value; + use: 'secondary'; + }; namespace Item { type Props = { /** Tab value */ diff --git a/semcore/add-filter/package.json b/semcore/add-filter/package.json index 0ccda3eb2c..b61a6146f2 100644 --- a/semcore/add-filter/package.json +++ b/semcore/add-filter/package.json @@ -9,7 +9,7 @@ "author": "UI-kit team ", "license": "MIT", "scripts": { - "build": "pnpm semcore-builder --source=ts && pnpm vite build" + "build": "pnpm semcore-builder && pnpm vite build" }, "exports": { "types": "./lib/types/index.d.ts", diff --git a/semcore/add-filter/src/AddFilter.tsx b/semcore/add-filter/src/AddFilter.tsx index 019528f4e7..c15853ffc3 100644 --- a/semcore/add-filter/src/AddFilter.tsx +++ b/semcore/add-filter/src/AddFilter.tsx @@ -1,6 +1,7 @@ import { Flex, ScreenReaderOnly } from '@semcore/base-components'; import Button from '@semcore/button'; import { createComponent, Component, Root, lastInteraction } from '@semcore/core'; +import type { WithI18nEnhanceProps } from '@semcore/core/lib/utils/enhances/i18nEnhance'; import i18nEnhance from '@semcore/core/lib/utils/enhances/i18nEnhance'; import { extractFrom } from '@semcore/core/lib/utils/findComponent'; import DropdownMenu from '@semcore/dropdown-menu'; @@ -9,7 +10,7 @@ import MathPlusM from '@semcore/icon/MathPlus/m'; import type { SelectProps } from '@semcore/select'; import React from 'react'; -import type { AddFilterType, AddFilterProps, AddFilterItemProps, AddFilterKey } from './AddFilter.types'; +import type { AddFilterType, AddFilterProps, AddFilterItemProps, AddFilterKey, AddFilterDefaultProps } from './AddFilter.types'; import AddFilterDropdown from './components/AddFilterDropdown'; import AddFilterInput from './components/AddFilterInput'; import AddFilterSelect from './components/AddFilterSelect'; @@ -39,10 +40,9 @@ class RootAddFilter extends Component< AddFilterProps, typeof RootAddFilter.enhance, { visibleFilters: null }, - { - visibleFilters: Exclude; - }, - AddFilterState + WithI18nEnhanceProps, + AddFilterState, + AddFilterDefaultProps > { addFilterTrigger = React.createRef(); filtersFocusMap: Map = new Map(); @@ -51,7 +51,8 @@ class RootAddFilter extends Component< static displayName = 'AddFilter'; static enhance = [i18nEnhance(localizedMessages)] as const; - static defaultProps = { + + static defaultProps: AddFilterDefaultProps = { i18n: localizedMessages, locale: 'en', defaultVisibleFilters: [], @@ -305,10 +306,13 @@ function ClearAllFilters({ hasFilterData, clearAll, getI18nText }: ClearAllFilte : null; } -const AddFilter = createComponent(RootAddFilter, { +const AddFilter = createComponent< + AddFilterType, + typeof RootAddFilter +>(RootAddFilter, { Select: AddFilterSelect, Input: AddFilterInput, Dropdown: AddFilterDropdown, -}) as AddFilterType; +}); export default AddFilter; diff --git a/semcore/add-filter/src/AddFilter.types.ts b/semcore/add-filter/src/AddFilter.types.ts index b267470f82..ec85b31b32 100644 --- a/semcore/add-filter/src/AddFilter.types.ts +++ b/semcore/add-filter/src/AddFilter.types.ts @@ -7,6 +7,8 @@ import type { DropdownTriggerProps } from '@semcore/dropdown'; import type Input from '@semcore/input'; import type Select from '@semcore/select'; +import type { LocalizedMessages } from './translations/__intergalactic-dynamic-locales'; + export type AddFilterKey = string; export type AddFilterItemProps = { @@ -74,6 +76,11 @@ export type AddFilterProps = FlexProps & { */ onVisibleFiltersChange?: (visibleFilters: AddFilterKey[]) => void; }; +export type AddFilterDefaultProps = { + i18n: LocalizedMessages; + locale: 'en'; + defaultVisibleFilters: AddFilterProps['visibleFilters']; +}; export type AddFilterType = Intergalactic.Component<'div', AddFilterProps> & { Dropdown: typeof AddFilterDropdownType; diff --git a/semcore/add-filter/src/components/AddFilterDropdown.tsx b/semcore/add-filter/src/components/AddFilterDropdown.tsx index 2e479f4295..2d8db4b5fb 100644 --- a/semcore/add-filter/src/components/AddFilterDropdown.tsx +++ b/semcore/add-filter/src/components/AddFilterDropdown.tsx @@ -3,7 +3,7 @@ import { createComponent, Component, Root } from '@semcore/core'; import Dropdown from '@semcore/dropdown'; import React from 'react'; -import type { AddFilterItemProps } from '../AddFilter.types'; +import type { AddFilterDropdownType, AddFilterItemProps } from '../AddFilter.types'; type AsPropsTypeWithHandlers = T & { onClear: () => void; @@ -11,14 +11,22 @@ type AsPropsTypeWithHandlers = T & { setFocusRef: (el: HTMLElement) => {}; }; -class AddFilterDropdownRoot extends Component { +type DefaultProps = { + defaultVisible: true; +}; +class AddFilterDropdownRoot extends Component< + AddFilterItemProps, + [], + { visible: null }, + {}, + {}, + DefaultProps +> { static displayName = 'AddFilterDropdown'; - static defaultProps = () => { - return { - defaultVisible: true, - }; - }; + static defaultProps = { + defaultVisible: true, + } as const; uncontrolledProps() { return { @@ -64,7 +72,10 @@ class AddFilterDropdownRoot extends Component(AddFilterDropdownRoot, { Trigger: Dropdown.Trigger, Popper: Dropdown.Popper, }); diff --git a/semcore/add-filter/src/components/AddFilterInput.tsx b/semcore/add-filter/src/components/AddFilterInput.tsx index 12196b2d92..fc207be17d 100644 --- a/semcore/add-filter/src/components/AddFilterInput.tsx +++ b/semcore/add-filter/src/components/AddFilterInput.tsx @@ -4,7 +4,7 @@ import Input from '@semcore/input'; import type { InputValueProps } from '@semcore/input'; import React from 'react'; -import type { AddFilterItemProps } from '../AddFilter.types'; +import type { AddFilterInputType, AddFilterItemProps } from '../AddFilter.types'; type AsPropsWithOnClear = T & { onClear: () => void; @@ -55,7 +55,10 @@ function Clear() { return ; } -const AddFilterInput = createComponent(AddFilterInputRoot, { +const AddFilterInput = createComponent< + typeof AddFilterInputType, + typeof AddFilterInputRoot +>(AddFilterInputRoot, { Value: Input.Value, Addon: Input.Addon, Clear, diff --git a/semcore/add-filter/src/components/AddFilterSelect.tsx b/semcore/add-filter/src/components/AddFilterSelect.tsx index e3c2adb7b5..3e79871769 100644 --- a/semcore/add-filter/src/components/AddFilterSelect.tsx +++ b/semcore/add-filter/src/components/AddFilterSelect.tsx @@ -10,14 +10,24 @@ type AsPropsWithOnClear = T & { unsetFocusRef: () => void; setFocusRef: (el: HTMLElement) => {}; }; -class AddFilterSelectRoot extends Component { + +type DefaultProps = { + defaultVisible: true; +}; + +class AddFilterSelectRoot extends Component< + SelectProps & AddFilterItemProps, + [], + { visible: null }, + {}, + {}, + DefaultProps +> { static displayName = 'AddFilterSelect'; - static defaultProps = () => { - return { - defaultVisible: true, - }; - }; + static defaultProps = { + defaultVisible: true, + } as const; componentWillUnmount() { this.asProps.onUnmount?.(); @@ -64,7 +74,10 @@ class AddFilterSelectRoot extends Component(AddFilterSelectRoot, { Trigger: Select.Trigger, Menu: Select.Menu, Option: [ @@ -76,6 +89,6 @@ const AddFilterSelect = createComponent(AddFilterSelectRoot, { List: Select.List, Popper: Select.Popper, InputSearch: Select.InputSearch, -}) as typeof AddFilterSelectType; +}); export default AddFilterSelect; diff --git a/semcore/add-filter/src/translations/__intergalactic-dynamic-locales.ts b/semcore/add-filter/src/translations/__intergalactic-dynamic-locales.ts index ccae777b73..65cdb67688 100644 --- a/semcore/add-filter/src/translations/__intergalactic-dynamic-locales.ts +++ b/semcore/add-filter/src/translations/__intergalactic-dynamic-locales.ts @@ -29,3 +29,5 @@ export const localizedMessages = { pl, sv, }; + +export type LocalizedMessages = typeof localizedMessages; diff --git a/semcore/badge/src/Badge.tsx b/semcore/badge/src/Badge.tsx index 78750e53c8..37d8245cfa 100644 --- a/semcore/badge/src/Badge.tsx +++ b/semcore/badge/src/Badge.tsx @@ -1,5 +1,6 @@ import type { BoxProps } from '@semcore/base-components'; import { Box } from '@semcore/base-components'; +import type { Intergalactic } from '@semcore/core'; import { createComponent, Component, Root, sstyled } from '@semcore/core'; import i18nEnhance from '@semcore/core/lib/utils/enhances/i18nEnhance'; import resolveColorEnhance from '@semcore/core/lib/utils/enhances/resolveColorEnhance'; @@ -49,6 +50,8 @@ export type BadgeProps = BadgeMargins & { color?: 'white' | 'gray20' | string; }; +type BadgeComponent = Intergalactic.Component<'span', BadgeProps>; + class RootBadge extends Component { static displayName = 'Badge'; static style = style; @@ -115,4 +118,7 @@ class RootBadge extends Component { } } -export const Badge = createComponent<'span', BadgeProps>(RootBadge); +export const Badge = createComponent< + BadgeComponent, + typeof RootBadge +>(RootBadge); diff --git a/semcore/base-components/src/components/animation/Animation.tsx b/semcore/base-components/src/components/animation/Animation.tsx index 688e417147..4cec926f0c 100644 --- a/semcore/base-components/src/components/animation/Animation.tsx +++ b/semcore/base-components/src/components/animation/Animation.tsx @@ -1,25 +1,30 @@ -// @ts-nocheck import { createComponent, sstyled, Root, Component } from '@semcore/core'; import contextEnhance from '@semcore/core/lib/utils/enhances/contextEnhance'; import React from 'react'; import { Box } from '../flex-box'; -import type { AnimationContext, AnimationProps } from './Animation.types'; +import type { AnimationContext, AnimationProps, Animation as AnimationComponent, AnimationDefaultProps } from './Animation.types'; import style from './style/animate.shadow.css'; -function propToArray(prop: any[]) { +type State = { + animationRunning: boolean; + render: AnimationProps['visible'] | AnimationProps['preserveNode']; + wasInvisible: AnimationProps['visible']; +}; + +function propToArray(prop: any) { return Array.isArray(prop) ? prop : [prop, prop]; } const makeAnimationContextValue = () => { - const context = { + const context: AnimationContext = { onAnimationStartSubscribers: [], - onAnimationStart: (callback: any) => { + onAnimationStart: (callback) => { context.onAnimationStartSubscribers.push(callback); return () => context.onAnimationStartSubscribers.filter((cb) => cb !== callback); }, onAnimationEndSubscribers: [], - onAnimationEnd: (callback: any) => { + onAnimationEnd: (callback) => { context.onAnimationEndSubscribers.push(callback); return () => context.onAnimationEndSubscribers.filter((cb) => cb !== callback); }, @@ -28,14 +33,21 @@ const makeAnimationContextValue = () => { }; export const animationContext = React.createContext(null); -class Animation extends Component { +class Animation extends Component< + AnimationProps, + typeof Animation.enhance, + {}, + { parentAnimationContext: AnimationContext }, + State, + AnimationDefaultProps +> { static displayName = 'Animation'; static style = style; - static defaultProps = { + static defaultProps: AnimationDefaultProps = { visible: false, duration: 0, delay: 0, - keyframes: [], + keyframes: ['', ''], initialAnimation: false, timingFunction: 'ease-out', animationsDisabled: false, @@ -43,7 +55,7 @@ class Animation extends Component { static enhance = [contextEnhance(animationContext, 'parentAnimationContext')]; - static getDerivedStateFromProps(props, state) { + static getDerivedStateFromProps(props: AnimationProps, state: State) { const wasInvisible = state.wasInvisible || !props.visible; if (props.visible || props.preserveNode || state.wasInvisible !== wasInvisible) { return { render: true, wasInvisible }; @@ -51,7 +63,7 @@ class Animation extends Component { return state; } - state = { + state: State = { animationRunning: false, render: this.props.visible || this.props.preserveNode, wasInvisible: !this.props.visible, @@ -85,9 +97,13 @@ class Animation extends Component { animationEventFallback = () => { if (!this.state.render) return; if (this.animationSupported) return; - const delayArr = this.asProps.animationsDisabled ? [0, 0] : propToArray(this.asProps.delay); - const delay = this.asProps.visible ? delayArr[0] : delayArr[1]; - const duration = this.asProps.animationsDisabled ? 0 : this.asProps.duration + 100; + const { animationsDisabled, visible } = this.asProps; + + const delayArr = animationsDisabled ? [0, 0] : propToArray(this.asProps.delay); + const durationArr = animationsDisabled ? [0, 0] : propToArray(this.asProps.duration); + const delay = visible ? delayArr[0] : delayArr[1]; + const duration = visible ? durationArr[0] + 100 : durationArr[1] + 100; + setTimeout(() => { if (this.animationSupported) return; this.handleAnimationEnd(); @@ -98,7 +114,7 @@ class Animation extends Component { this.animationEventFallback(); } - componentDidUpdate(prevProps, prevState) { + componentDidUpdate(prevProps: AnimationProps, prevState: State) { if (prevProps.visible !== this.props.visible || prevState.render !== this.state.render) { this.animationEventFallback(); } @@ -144,4 +160,4 @@ class Animation extends Component { } } -export default createComponent<'div', AnimationProps>(Animation); +export default createComponent(Animation); diff --git a/semcore/base-components/src/components/animation/Animation.types.ts b/semcore/base-components/src/components/animation/Animation.types.ts index e1186089a1..821d9b4e5f 100644 --- a/semcore/base-components/src/components/animation/Animation.types.ts +++ b/semcore/base-components/src/components/animation/Animation.types.ts @@ -51,6 +51,16 @@ export type AnimationProps = BoxProps & { transformEnd?: string; }; +export type AnimationDefaultProps = { + visible: false; + duration: 0; + delay: 0; + keyframes: AnimationProps['keyframes']; + initialAnimation: false; + timingFunction: 'ease-out'; + animationsDisabled: false; +}; + export type CollapseProps = AnimationProps & { /** * Add overflow=clip when passing animation @@ -63,6 +73,11 @@ export type CollapseProps = AnimationProps & { * @default auto */ defaultHeight?: 'auto' | '100%'; + + /** @deprecated It will be removed in v18. */ + onAnimationStart?: React.AnimationEventHandler; + /** @deprecated It will be removed in v18. */ + onAnimationEnd?: React.AnimationEventHandler; }; export type FadeInOutProps = AnimationProps & {}; @@ -96,9 +111,14 @@ export type SlideProps = AnimationProps & { type DisposeSubscription = () => void; -export type AnimationContext = { - onAnimationStart: (callback: (duration: number) => void) => DisposeSubscription; - onAnimationEnd: (callback: () => void) => DisposeSubscription; +export type AnimationContext< + AnimationStartCb = (duration: number) => void, + AnimationEndCb = () => void, +> = { + onAnimationStart: (callback: AnimationStartCb) => DisposeSubscription; + onAnimationEnd: (callback: AnimationEndCb) => DisposeSubscription; + onAnimationStartSubscribers: Array; + onAnimationEndSubscribers: Array; }; export type animationContext = React.Context; diff --git a/semcore/base-components/src/components/animation/Collapse.tsx b/semcore/base-components/src/components/animation/Collapse.tsx index e3831d5737..2952f198a2 100644 --- a/semcore/base-components/src/components/animation/Collapse.tsx +++ b/semcore/base-components/src/components/animation/Collapse.tsx @@ -1,5 +1,4 @@ -// @ts-nocheck -import { createBaseComponent, sstyled } from '@semcore/core'; +import { sstyled, createBaseComponent, type Intergalactic } from '@semcore/core'; import { useForkRef } from '@semcore/core/lib/utils/ref'; import useEnhancedEffect from '@semcore/core/lib/utils/use/useEnhancedEffect'; import React from 'react'; @@ -9,12 +8,12 @@ import type { CollapseProps } from './Animation.types'; import style from './style/keyframes.shadow.css'; function Collapse( - { onAnimationStart, onAnimationEnd, overflowHidden = true, defaultHeight = 'auto', ...props }, - ref, + { onAnimationStart, onAnimationEnd, overflowHidden = true, defaultHeight = 'auto', ...props }: CollapseProps, + ref: React.Ref, ) { const SCollapse = Animation; const overflowRef = React.useRef('initial'); - const innerRef = React.useRef(null); + const innerRef = React.useRef(null); const forkedRef = useForkRef(innerRef, ref); useEnhancedEffect(() => { @@ -32,7 +31,7 @@ function Collapse( }, []); const handleAnimationStart = React.useCallback( - (event) => { + (event: React.AnimationEvent) => { if (event.currentTarget !== event.target) return; if (onAnimationStart) onAnimationStart(event); if (overflowHidden) { @@ -48,7 +47,7 @@ function Collapse( const visibleRef = React.useRef(props.visible); visibleRef.current = props.visible; - const handleAnimationEnd = React.useCallback((event) => { + const handleAnimationEnd = React.useCallback((event: React.AnimationEvent) => { if (event.currentTarget !== event.target) return; if (onAnimationEnd) onAnimationEnd(event); const element = event.currentTarget; @@ -77,4 +76,6 @@ function Collapse( Collapse.displayName = 'Collapse'; -export default createBaseComponent<'div', CollapseProps>(Collapse); +type CollapseComponent = Intergalactic.Component<'div', CollapseProps>; + +export default createBaseComponent(Collapse); diff --git a/semcore/base-components/src/components/animation/FadeInOut.tsx b/semcore/base-components/src/components/animation/FadeInOut.tsx index 9910fa5f9a..83f0af3b1f 100644 --- a/semcore/base-components/src/components/animation/FadeInOut.tsx +++ b/semcore/base-components/src/components/animation/FadeInOut.tsx @@ -1,4 +1,4 @@ -import { createBaseComponent, sstyled } from '@semcore/core'; +import { sstyled, createBaseComponent, type Intergalactic } from '@semcore/core'; import React from 'react'; import Animation from './Animation'; @@ -17,4 +17,6 @@ function FadeInOut(props: FadeInOutProps, ref: React.Ref) { FadeInOut.displayName = 'FadeInOut'; -export default createBaseComponent<'div', FadeInOutProps>(FadeInOut); +type FadeInOutComponent = Intergalactic.Component<'div', FadeInOutProps>; + +export default createBaseComponent(FadeInOut); diff --git a/semcore/base-components/src/components/animation/Scale.tsx b/semcore/base-components/src/components/animation/Scale.tsx index 55782fd6b0..c540f5333b 100644 --- a/semcore/base-components/src/components/animation/Scale.tsx +++ b/semcore/base-components/src/components/animation/Scale.tsx @@ -1,3 +1,4 @@ +import type { Intergalactic } from '@semcore/core'; import { createBaseComponent, sstyled } from '@semcore/core'; import { useForkRef } from '@semcore/core/lib/utils/ref'; import React from 'react'; @@ -42,4 +43,6 @@ function Scale(props: ScaleProps, ref: React.Ref) { Scale.displayName = 'Scale'; -export default createBaseComponent<'div', ScaleProps>(Scale); +type ScaleComponent = Intergalactic.Component<'div', ScaleProps>; + +export default createBaseComponent(Scale); diff --git a/semcore/base-components/src/components/animation/Slide.tsx b/semcore/base-components/src/components/animation/Slide.tsx index 3c038cf60b..ec259ad606 100644 --- a/semcore/base-components/src/components/animation/Slide.tsx +++ b/semcore/base-components/src/components/animation/Slide.tsx @@ -1,3 +1,4 @@ +import type { Intergalactic } from '@semcore/core'; import { createBaseComponent, sstyled } from '@semcore/core'; import React from 'react'; @@ -20,4 +21,6 @@ function Slide(props: SlideProps, ref: React.Ref) { Slide.displayName = 'Slide'; -export default createBaseComponent<'div', SlideProps>(Slide); +type SlideComponent = Intergalactic.Component<'div', SlideProps>; + +export default createBaseComponent(Slide); diff --git a/semcore/base-components/src/components/animation/Transform.tsx b/semcore/base-components/src/components/animation/Transform.tsx index 932148b638..3a526f5c0b 100644 --- a/semcore/base-components/src/components/animation/Transform.tsx +++ b/semcore/base-components/src/components/animation/Transform.tsx @@ -1,3 +1,4 @@ +import type { Intergalactic } from '@semcore/core'; import { createBaseComponent, sstyled } from '@semcore/core'; import React from 'react'; @@ -21,4 +22,5 @@ function Transform(props: TransformProps, ref: React.Ref) { Transform.displayName = 'Transform'; -export default createBaseComponent<'div', TransformProps>(Transform); +type TransformComponent = Intergalactic.Component<'div', TransformProps>; +export default createBaseComponent(Transform); diff --git a/semcore/base-components/src/components/flex-box/Box/index.tsx b/semcore/base-components/src/components/flex-box/Box/index.tsx index a5ee433a71..37dd83ca8b 100644 --- a/semcore/base-components/src/components/flex-box/Box/index.tsx +++ b/semcore/base-components/src/components/flex-box/Box/index.tsx @@ -15,4 +15,6 @@ function Box(props: any, ref: any) { Box.displayName = 'Box'; -export default createBaseComponent(Box) as any as Intergalactic.Component<'div', BoxProps>; +type BoxComponent = Intergalactic.Component<'div', BoxProps>; + +export default createBaseComponent(Box); diff --git a/semcore/base-components/src/components/flex-box/Flex/index.tsx b/semcore/base-components/src/components/flex-box/Flex/index.tsx index c735f579a4..9fb00744cf 100644 --- a/semcore/base-components/src/components/flex-box/Flex/index.tsx +++ b/semcore/base-components/src/components/flex-box/Flex/index.tsx @@ -10,4 +10,6 @@ function Flex(props: any, ref: any) { Flex.displayName = 'Flex'; -export default createBaseComponent(Flex) as any as Intergalactic.Component<'div', FlexProps>; +type FlexComponent = Intergalactic.Component<'div', FlexProps>; + +export default createBaseComponent(Flex); diff --git a/semcore/base-components/src/components/flex-box/invalid-state-box/InvalidStateBox.tsx b/semcore/base-components/src/components/flex-box/invalid-state-box/InvalidStateBox.tsx index b21f58f70b..175e67995a 100644 --- a/semcore/base-components/src/components/flex-box/invalid-state-box/InvalidStateBox.tsx +++ b/semcore/base-components/src/components/flex-box/invalid-state-box/InvalidStateBox.tsx @@ -4,12 +4,17 @@ import React from 'react'; import style from './invalidStateBox.shadow.css'; import Box from '../Box'; -function InvalidStatePatternComponent() { +type InvalidStatePatternComponent = typeof Box; + +function InvalidStatePatternRoot() { const SPattern = Root; return sstyled(style)(); }; -export const InvalidStateBox = createComponent(InvalidStatePatternComponent); +export const InvalidStateBox = createComponent< + InvalidStatePatternComponent, + typeof InvalidStatePatternRoot +>(InvalidStatePatternRoot); export default InvalidStateBox; diff --git a/semcore/base-components/src/components/flex-box/screen-reader-only-box/ScreenReaderOnlyBox.tsx b/semcore/base-components/src/components/flex-box/screen-reader-only-box/ScreenReaderOnlyBox.tsx index 17630678b8..603df2d322 100644 --- a/semcore/base-components/src/components/flex-box/screen-reader-only-box/ScreenReaderOnlyBox.tsx +++ b/semcore/base-components/src/components/flex-box/screen-reader-only-box/ScreenReaderOnlyBox.tsx @@ -12,6 +12,9 @@ function ScreenReaderOnlyComponent() { type ScreenReaderOnlyType = Intergalactic.Component<'span'>; -export const ScreenReaderOnly: ScreenReaderOnlyType = createComponent(ScreenReaderOnlyComponent); +export const ScreenReaderOnly = createComponent< + ScreenReaderOnlyType, + typeof ScreenReaderOnlyComponent +>(ScreenReaderOnlyComponent); export default ScreenReaderOnly; diff --git a/semcore/base-components/src/components/grid/Grid.tsx b/semcore/base-components/src/components/grid/Grid.tsx index 3199a4fdaa..b2c2a130b8 100644 --- a/semcore/base-components/src/components/grid/Grid.tsx +++ b/semcore/base-components/src/components/grid/Grid.tsx @@ -2,15 +2,22 @@ import { createComponent, Component, Root, sstyled } from '@semcore/core'; import React from 'react'; import { Box, Flex } from '../flex-box'; -import type { RowProps, ColProps, RowType, GridContext } from './Grid.types'; +import type { RowProps, ColProps, RowType, GridContext, RowDefaultProps } from './Grid.types'; import style from './style/grid.shadow.css'; -class RowRoot extends Component { +class RowRoot extends Component< + RowProps, + [], + {}, + GridContext, + {}, + RowDefaultProps +> { static displayName = 'Row'; static style = style; static defaultProps = { gutter: 0, - }; + } as const; getColProps() { const { gutter } = this.asProps; @@ -68,6 +75,9 @@ function Col(props: ColProps) { ); } -const Row = createComponent(RowRoot, { Col }) as RowType; +const Row = createComponent< + RowType, + typeof RowRoot +>(RowRoot, { Col }); export default Row; diff --git a/semcore/base-components/src/components/grid/Grid.types.ts b/semcore/base-components/src/components/grid/Grid.types.ts index b881e15f54..ffd5f0db06 100644 --- a/semcore/base-components/src/components/grid/Grid.types.ts +++ b/semcore/base-components/src/components/grid/Grid.types.ts @@ -31,6 +31,10 @@ export type RowProps = FlexProps & { gutter?: number; }; +export type RowDefaultProps = { + gutter: 0; +}; + export type GridContext = { getColProps: PropGetterFn; }; diff --git a/semcore/base-components/src/components/hint/Hint.tsx b/semcore/base-components/src/components/hint/Hint.tsx index c3778cbd64..ca479f4e20 100644 --- a/semcore/base-components/src/components/hint/Hint.tsx +++ b/semcore/base-components/src/components/hint/Hint.tsx @@ -1,5 +1,6 @@ import { computePosition, flip, offset, shift, type Placement } from '@floating-ui/dom'; import { createComponent, Root, sstyled, Component, lastInteraction } from '@semcore/core'; +import type { Intergalactic } from '@semcore/core'; import canUseDOM from '@semcore/core/lib/utils/canUseDOM'; import { getAccessibleName } from '@semcore/core/lib/utils/getAccessibleName'; import { cssVariableEnhance } from '@semcore/core/lib/utils/useCssVariable'; @@ -50,6 +51,10 @@ export type SimpleHintPopperProps = { ignorePortalsStacking?: boolean; }; +type InnerProps = { + timingFunction: DataType.EasingFunction; +}; + type DefaultProps = { defaultVisible?: boolean; timeout: number | [number, number]; @@ -63,6 +68,8 @@ type State = { calculatedPlacement?: Placement; }; +type SimpleHintPopperComponent = Intergalactic.Component<'div', SimpleHintPopperProps>; + const enhances = [ zIndexStackingEnhance('z-index-tooltip'), cssVariableEnhance({ @@ -91,7 +98,14 @@ function propToArray(prop: number | [number, number]): [number, number] { const keyframesMap = new Map(); -class HintPopperRoot extends Component { +class HintPopperRoot extends Component< + SimpleHintPopperProps, + typeof enhances, + Handlers, + InnerProps, + State, + DefaultProps +> { public readonly hintRef = React.createRef(); static style = Object.assign(keyframes, styles); @@ -367,4 +381,7 @@ class HintPopperRoot extends Component(HintPopperRoot); +export const Hint = createComponent< + SimpleHintPopperComponent, + typeof HintPopperRoot +>(HintPopperRoot); diff --git a/semcore/base-components/src/components/neighbor-location/NeighborLocation.tsx b/semcore/base-components/src/components/neighbor-location/NeighborLocation.tsx index f651215cf4..e5e13ee97c 100644 --- a/semcore/base-components/src/components/neighbor-location/NeighborLocation.tsx +++ b/semcore/base-components/src/components/neighbor-location/NeighborLocation.tsx @@ -123,7 +123,10 @@ function useNeighborLocationDetect(index: number) { return calculateNeighborLocation(controlsLengthRef.current, index); } -export const NeighborLocation = createComponent( +export const NeighborLocation = createComponent< + typeof NeighborLocationType, + typeof NeighborLocationRoot +>( NeighborLocationRoot, { Detect: Detect, @@ -131,6 +134,6 @@ export const NeighborLocation = createComponent( { context: Context, }, -) as typeof NeighborLocationType; +); export { useNeighborLocationDetect }; diff --git a/semcore/base-components/src/components/outside-click/OutsideClick.tsx b/semcore/base-components/src/components/outside-click/OutsideClick.tsx index c0743ca231..a36ec071f3 100644 --- a/semcore/base-components/src/components/outside-click/OutsideClick.tsx +++ b/semcore/base-components/src/components/outside-click/OutsideClick.tsx @@ -25,6 +25,11 @@ export type OutsideClickProps = { root?: React.RefObject; }; +type OutsideClickComponent = Intergalactic.Component< + Intergalactic.Tag, + OutsideClickProps +>; + type OutsideClickEvents = { [key in 'mouseup' | 'mousedown']: EventListenerOrEventListenerObject }; type RootEventsPair = [Element | Document, OutsideClickEvents]; @@ -111,7 +116,7 @@ function OutsideClickRoot(props: OutsideClickProps & IRootComponentProps) { OutsideClickRoot.displayName = 'OutsideClick'; OutsideClickRoot.eventsMap = [] as RootEventsPair[]; -export const OutsideClick = createComponent(OutsideClickRoot) as Intergalactic.Component< - Intergalactic.Tag, - OutsideClickProps ->; +export const OutsideClick = createComponent< + OutsideClickComponent, + typeof OutsideClickRoot +>(OutsideClickRoot); diff --git a/semcore/base-components/src/components/popper/Popper.tsx b/semcore/base-components/src/components/popper/Popper.tsx index 94152bcb1f..6717c731c4 100644 --- a/semcore/base-components/src/components/popper/Popper.tsx +++ b/semcore/base-components/src/components/popper/Popper.tsx @@ -43,6 +43,7 @@ import type { PopperPopperProps, PopperProps, PopperTriggerProps, + PopperDefaultProps, } from './Popper.types'; import style from './style/popper.shadow.css'; @@ -89,12 +90,19 @@ const MODIFIERS_OPTIONS = [ 'cursorAnchoring', ] as const; -class PopperRoot extends Component { +class PopperRoot extends Component< + PopperProps, + typeof PopperRoot.enhance, + { visible: null }, + {}, + {}, + PopperDefaultProps +> { static displayName = 'Popper'; static style = style; - static defaultProps = { + static defaultProps: PopperDefaultProps = { defaultVisible: false, placement: 'auto', modifiers: [], @@ -779,7 +787,10 @@ function PopperPopper(props: PopperPopperProps & IRootComponentProps & InnerPopp ); } -export const Popper = createComponent(PopperRoot, { +export const Popper = createComponent< + typeof PopperType, + typeof PopperRoot +>(PopperRoot, { Trigger, Popper: PopperPopper, -}) as typeof PopperType; +}); diff --git a/semcore/base-components/src/components/popper/Popper.types.ts b/semcore/base-components/src/components/popper/Popper.types.ts index 155c6ac727..0ab1389221 100644 --- a/semcore/base-components/src/components/popper/Popper.types.ts +++ b/semcore/base-components/src/components/popper/Popper.types.ts @@ -100,6 +100,21 @@ export type PopperProps = OutsideClickProps & popperMargin?: number; }; +export type PopperDefaultProps = { + defaultVisible: false; + placement: 'auto'; + modifiers: PopperProps['modifiers']; + arrow: { + padding: 6; + }; + strategy: 'absolute'; + interaction: 'click'; + timeout: 0; + excludeRefs: PopperProps['excludeRefs']; + focusLoop: true; + cursorAnchoring: false; +}; + export type PopperTriggerProps = BoxProps & { /** * Disabled focus trap, autofocus and focus return diff --git a/semcore/base-components/src/components/portal/Portal.tsx b/semcore/base-components/src/components/portal/Portal.tsx index 3f408d5298..4c90eb8f10 100644 --- a/semcore/base-components/src/components/portal/Portal.tsx +++ b/semcore/base-components/src/components/portal/Portal.tsx @@ -16,6 +16,8 @@ export type PortalProps = { type PortalContextType = React.RefObject | HTMLElement | null; +type PortalComponent = Intergalactic.Component; + const PortalContext = register.get( 'portal-context', @@ -52,4 +54,7 @@ Portal.displayName = 'Portal'; const { Provider: PortalProvider } = PortalContext; export { PortalProvider, PortalContext }; -export default createComponent(Portal) as Intergalactic.Component; +export default createComponent< + PortalComponent, + typeof Portal +>(Portal); diff --git a/semcore/base-components/src/components/scroll-area/ScrollArea.tsx b/semcore/base-components/src/components/scroll-area/ScrollArea.tsx index 517e1ee2ae..cdb97ddfeb 100644 --- a/semcore/base-components/src/components/scroll-area/ScrollArea.tsx +++ b/semcore/base-components/src/components/scroll-area/ScrollArea.tsx @@ -12,6 +12,7 @@ import type { ScrollAreaProps, ScrollArea as ScrollAreaType, ScrollAreaContainerProps, + ScrollAreaDefaultProps, } from './ScrollBar.types'; import style from './style/scroll-area.shadow.css'; @@ -29,25 +30,22 @@ type State = { shadowVertical: boolean | string; }; -type DefaultProps = { - container: React.Ref; - inner: React.Ref; - tabIndex: number; - observeParentSize: boolean; - disableAutofocusToContent: boolean; - shadowSize: Exclude; - shadowTheme: Exclude, undefined>; -}; - const DEFAULT_SHADOW_THEME = 'dark'; -class ScrollAreaRoot extends Component { +class ScrollAreaRoot extends Component< + ScrollAreaProps, + typeof ScrollAreaRoot.enhance, + {}, + {}, + State, + ScrollAreaDefaultProps +> { static displayName = 'ScrollArea'; static style = style; static enhance = [uniqueIDEnhancement()] as const; - static defaultProps: () => DefaultProps = () => ({ + static defaultProps = () => ({ container: React.createRef(), inner: React.createRef(), tabIndex: 0, @@ -55,7 +53,7 @@ class ScrollAreaRoot extends Component(ScrollAreaRoot, { Container: ContainerRoot, Bar: ScrollBar, -}) as typeof ScrollAreaType; +}); // TODO: remove named ScrollArea export export { eventCalculate, ScrollArea }; diff --git a/semcore/base-components/src/components/scroll-area/ScrollBar.tsx b/semcore/base-components/src/components/scroll-area/ScrollBar.tsx index 711c70e762..1f8083ebbb 100644 --- a/semcore/base-components/src/components/scroll-area/ScrollBar.tsx +++ b/semcore/base-components/src/components/scroll-area/ScrollBar.tsx @@ -3,7 +3,7 @@ import contextEnhance from '@semcore/core/lib/utils/enhances/contextEnhance'; import React from 'react'; import { Box } from '../flex-box'; -import type { ScrollBar as ScrollBarType, ScrollBarProps } from './ScrollBar.types'; +import type { ScrollBar as ScrollBarType, ScrollBarProps, ScrollBarDefaultProps } from './ScrollBar.types'; import style from './style/scroll-bar.shadow.css'; export const hideScrollBarsFromScreenReadersContext = React.createContext(false); @@ -35,7 +35,14 @@ type State = { visibleScroll: boolean; }; -class ScrollBarRoot extends Component | null }, State> { +class ScrollBarRoot extends Component< + ScrollBarProps, + typeof ScrollBarRoot.enhance, + {}, + { container: React.RefObject }, + State, + ScrollBarDefaultProps +> { static displayName = 'Bar'; static style = style; @@ -395,8 +402,11 @@ function Slider(props: ScrollBarProps) { return sstyled(styles)( false} />); } -export const ScrollBar = createComponent(ScrollBarRoot, { +export const ScrollBar = createComponent< + typeof ScrollBarType, + typeof ScrollBarRoot +>(ScrollBarRoot, { Slider, -}) as typeof ScrollBarType; +}); export { setAriaValues as setAreaValue }; diff --git a/semcore/base-components/src/components/scroll-area/ScrollBar.types.ts b/semcore/base-components/src/components/scroll-area/ScrollBar.types.ts index 114623dc68..046a492b12 100644 --- a/semcore/base-components/src/components/scroll-area/ScrollBar.types.ts +++ b/semcore/base-components/src/components/scroll-area/ScrollBar.types.ts @@ -18,7 +18,7 @@ export type ScrollAreaProps = BoxProps & { /** Called every time user scrolls area */ onScroll?: (event: React.SyntheticEvent) => void; /** Tab index that is being bypassed to the scroll container. */ - tabIndex?: number | null; + tabIndex?: number; /** * Flag to enable resizing if the parent of ScrollArea is resized * @default false @@ -52,6 +52,16 @@ export type ScrollAreaProps = BoxProps & { shadowTheme?: ShadowTheme | { horizontalTop?: ShadowTheme; horizontalBottom?: ShadowTheme; verticalLeft?: ShadowTheme; verticalRight?: ShadowTheme }; }; +export type ScrollAreaDefaultProps = { + container: React.RefObject; + inner: React.RefObject; + tabIndex: 0; + observeParentSize: false; + disableAutofocusToContent: false; + shadowSize: 5; + shadowTheme: 'dark'; +}; + export type ScrollAreaContext = ScrollAreaProps & { getContainerProps: PropGetterFn; getBarProps: PropGetterFn; @@ -64,6 +74,11 @@ export type ScrollBarProps = BoxProps & { container?: React.RefObject; }; +export type ScrollBarDefaultProps = { + container: React.RefObject; + children: React.JSX.Element; +}; + export type ScrollBarContext = ScrollBarProps & { getSliderProps: PropGetterFn; }; diff --git a/semcore/base-trigger/src/index.d.ts b/semcore/base-trigger/src/index.d.ts index 960185d6dd..5b5b751ef3 100644 --- a/semcore/base-trigger/src/index.d.ts +++ b/semcore/base-trigger/src/index.d.ts @@ -2,7 +2,7 @@ import type { Box, BoxProps, NeighborItemProps } from '@semcore/base-components' import type { ButtonLinkProps, ButtonLink } from '@semcore/button'; import type { Intergalactic } from '@semcore/core'; import type { WithAnimatedSizeEnhanceProps } from '@semcore/core/lib/utils/enhances/animatedSizeEnhance'; -import type { CounterProps } from '@semcore/counter'; +import type { NSCounter } from '@semcore/counter'; import type { Text } from '@semcore/typography'; import type React from 'react'; @@ -89,7 +89,7 @@ declare const LinkTrigger: Intergalactic.Component<'div', LinkTriggerProps> & { declare const FilterTrigger: Intergalactic.Component<'div', FilterTriggerProps> & { Text: typeof BaseTrigger.Text; Addon: typeof BaseTrigger.Addon; - Counter: Intergalactic.Component<'div', CounterProps & FilterTriggerCounterProps>; + Counter: Intergalactic.Component<'div', NSCounter.Props & FilterTriggerCounterProps>; TriggerButton: typeof BaseTrigger; ClearButton: typeof BaseTrigger; }; diff --git a/semcore/bulk-textarea/src/BulkTextarea.tsx b/semcore/bulk-textarea/src/BulkTextarea.tsx index b59dae87d9..992bbc7a49 100644 --- a/semcore/bulk-textarea/src/BulkTextarea.tsx +++ b/semcore/bulk-textarea/src/BulkTextarea.tsx @@ -1,10 +1,11 @@ import { Box } from '@semcore/base-components'; import { createComponent, Component, Root, lastInteraction } from '@semcore/core'; +import type { WithI18nEnhanceProps } from '@semcore/core/lib/utils/enhances/i18nEnhance'; import i18nEnhance from '@semcore/core/lib/utils/enhances/i18nEnhance'; import uniqueIdEnhance from '@semcore/core/lib/utils/uniqueID'; import React from 'react'; -import type { BulkTextareaType, BulkTextareaProps } from './BulkTextarea.types'; +import type { BulkTextareaType, BulkTextareaProps, BulkTextareaDefaultProps } from './BulkTextarea.types'; import { ClearAll } from './components/ClearAll'; import { Counter } from './components/Counter'; import { ErrorsNavigation } from './components/ErrorsNavigation'; @@ -28,18 +29,19 @@ class BulkTextareaRoot extends Component< showErrors: null; errors: null; }, - {}, - State + WithI18nEnhanceProps, + State, + BulkTextareaDefaultProps > { static displayName = 'BulkTextarea'; - static defaultProps = { + static defaultProps: BulkTextareaDefaultProps = { defaultValue: '', size: 'm', defaultState: 'normal', minRows: 2, maxRows: 10, maxLines: 100, - validateOn: 'blur', + validateOn: ['blur'], locale: 'en', defaultErrors: [], defaultShowErrors: false, @@ -280,11 +282,11 @@ class BulkTextareaRoot extends Component< } const BulkTextarea = (() => - createComponent(BulkTextareaRoot, { + createComponent, typeof BulkTextareaRoot>(BulkTextareaRoot, { InputField, Counter, ClearAll, ErrorsNavigation, - }) as unknown as BulkTextareaType)(); + }))(); export default BulkTextarea; diff --git a/semcore/bulk-textarea/src/BulkTextarea.types.ts b/semcore/bulk-textarea/src/BulkTextarea.types.ts index 28513df1a6..5ca2408d4b 100644 --- a/semcore/bulk-textarea/src/BulkTextarea.types.ts +++ b/semcore/bulk-textarea/src/BulkTextarea.types.ts @@ -50,6 +50,19 @@ export type BulkTextareaProps = { onImmediatelyChange?: InputFieldProps['onImmediatelyChange']; }; +export type BulkTextareaDefaultProps = { + defaultValue: T; + size: 'm'; + defaultState: 'normal'; + minRows: 2; + maxRows: 10; + maxLines: 100; + validateOn: BulkTextareaProps['validateOn']; + locale: 'en'; + defaultErrors: BulkTextareaProps['errors']; + defaultShowErrors: false; +}; + type BulkTextareaComponent = (( props: Intergalactic.InternalTypings.ComponentProps< 'div', diff --git a/semcore/bulk-textarea/src/components/Counter.tsx b/semcore/bulk-textarea/src/components/Counter.tsx index 00b086b5dd..07134c035d 100644 --- a/semcore/bulk-textarea/src/components/Counter.tsx +++ b/semcore/bulk-textarea/src/components/Counter.tsx @@ -1,11 +1,11 @@ import { ScreenReaderOnly } from '@semcore/base-components'; import { Root } from '@semcore/core'; import type { useI18n } from '@semcore/core/lib/utils/enhances/WithI18n'; -import CounterKit, { type CounterProps as CounterPropsKit } from '@semcore/counter'; +import CounterKit, { type NSCounter } from '@semcore/counter'; import React from 'react'; export type CounterProps = { - theme: CounterPropsKit['theme']; + theme: NSCounter.Props['theme']; linesCount: number; maxLines: number; getI18nText: ReturnType; diff --git a/semcore/button/src/component/Button/Button.tsx b/semcore/button/src/component/Button/Button.tsx index 08c1486a32..3cbf407c5c 100644 --- a/semcore/button/src/component/Button/Button.tsx +++ b/semcore/button/src/component/Button/Button.tsx @@ -7,7 +7,7 @@ import { Text } from '@semcore/typography'; import React from 'react'; import style from './button.shadow.css'; -import type { ButtonProps, ButtonAddonProps, ButtonTextProps, ButtonComponent } from './Button.type'; +import type { ButtonProps, ButtonAddonProps, ButtonTextProps, ButtonComponent, ButtonDefaultProps } from './Button.type'; import SpinButton from './SpinButton'; export const MAP_USE_DEFAULT_THEME: Record = { @@ -20,13 +20,20 @@ type State = { ariaLabelledByContent: null | string; }; -export class RootButton extends Component { +export class RootButton extends Component< + ButtonProps, + [], + never, + {}, + State, + ButtonDefaultProps +> { static displayName = 'Button'; static style = style; static defaultProps = { use: 'secondary', size: 'm', - }; + } as const; containerRef = React.createRef(); @@ -167,9 +174,12 @@ function Addon(props: ButtonAddonProps) { return sstyled(props.styles)(); } -const Button = createComponent(RootButton, { +const Button = createComponent< + ButtonComponent, + typeof RootButton +>(RootButton, { Text: ButtonText, Addon, -}) as ButtonComponent; +}); export default Button; diff --git a/semcore/button/src/component/Button/Button.type.ts b/semcore/button/src/component/Button/Button.type.ts index 64302c3325..8c04a0f7a4 100644 --- a/semcore/button/src/component/Button/Button.type.ts +++ b/semcore/button/src/component/Button/Button.type.ts @@ -35,6 +35,11 @@ export type ButtonProps = BoxProps & theme?: 'info' | 'success' | 'brand' | 'danger' | 'muted' | 'invert'; }; +export type ButtonDefaultProps = { + use: 'secondary'; + size: 'm'; +}; + export type ButtonTextProps = NSText.Props; export type ButtonAddonProps = BoxProps; diff --git a/semcore/button/src/component/ButtonLink/ButtonLink.tsx b/semcore/button/src/component/ButtonLink/ButtonLink.tsx index 342ae1a3c7..ee023a7115 100644 --- a/semcore/button/src/component/ButtonLink/ButtonLink.tsx +++ b/semcore/button/src/component/ButtonLink/ButtonLink.tsx @@ -3,15 +3,22 @@ import Link from '@semcore/link'; import React from 'react'; import style from './buttonLink.shadow.css'; -import type { ButtonLinkComponent, ButtonLinkProps } from './ButtonLink.type'; +import type { ButtonLinkComponent, ButtonLinkDefaultProps, ButtonLinkProps } from './ButtonLink.type'; -class RootButtonLink extends Component { +class RootButtonLink extends Component< + ButtonLinkProps, + [], + {}, + {}, + {}, + ButtonLinkDefaultProps +> { static displayName = 'ButtonLink'; static style = style; static defaultProps = { use: 'primary', size: 200, - }; + } as const; render(): React.ReactNode { const SButtonLink = Root; @@ -29,9 +36,13 @@ class RootButtonLink extends Component { } } -export const ButtonLink = createComponent(RootButtonLink, { - Text: Link.Text, - Addon: Link.Addon, -}, { - parent: Link, -}) as ButtonLinkComponent; +export const ButtonLink = createComponent( + RootButtonLink, + { + Text: Link.Text, + Addon: Link.Addon, + }, + { + parent: Link, + }, +); diff --git a/semcore/button/src/component/ButtonLink/ButtonLink.type.ts b/semcore/button/src/component/ButtonLink/ButtonLink.type.ts index 1d711d9e92..df6bffbc83 100644 --- a/semcore/button/src/component/ButtonLink/ButtonLink.type.ts +++ b/semcore/button/src/component/ButtonLink/ButtonLink.type.ts @@ -13,6 +13,11 @@ export type ButtonLinkProps = Intergalactic.InternalTypings.EfficientOmit); } -const Card = createComponent(CardRoot, { +const Card = createComponent< + NSCard.Component, + typeof CardRoot +>(CardRoot, { Title, Description, Header, Body, -}) as NSCard.Component; +}); export default Card; diff --git a/semcore/carousel/src/Carousel.tsx b/semcore/carousel/src/Carousel.tsx index 92624c5836..15ff4ef1c0 100644 --- a/semcore/carousel/src/Carousel.tsx +++ b/semcore/carousel/src/Carousel.tsx @@ -2,6 +2,7 @@ import { createBreakpoints, Box, Flex } from '@semcore/base-components'; import type { BoxProps } from '@semcore/base-components'; import Button from '@semcore/button'; import { createComponent, Component, sstyled, Root } from '@semcore/core'; +import type { WithI18nEnhanceProps } from '@semcore/core/lib/utils/enhances/i18nEnhance'; import i18nEnhance from '@semcore/core/lib/utils/enhances/i18nEnhance'; import { findAllComponents } from '@semcore/core/lib/utils/findComponent'; import logger from '@semcore/core/lib/utils/logger'; @@ -21,6 +22,7 @@ import type { CarouselButtonProps, CarouselIndicatorsProps, CarouselIndicatorProps, + CarouselDefaultProps, } from './Carousel.types'; import style from './style/carousel.shadow.css'; import { localizedMessages } from './translations/__intergalactic-dynamic-locales'; @@ -39,8 +41,9 @@ class CarouselRoot extends Component< CarouselProps, typeof enhance, { index: any }, - CarouselContext, - CarouselState + CarouselContext & WithI18nEnhanceProps, + CarouselState, + CarouselDefaultProps > { static displayName = 'Carousel'; static defaultProps = { @@ -51,7 +54,7 @@ class CarouselRoot extends Component< i18n: localizedMessages, locale: 'en', indicators: 'default', - }; + } as const; static style = style; static enhance = enhance; @@ -735,7 +738,7 @@ function Indicators({ items, styles, Children, inverted }: CarouselIndicatorsPro ); }; -function Indicator({ styles, Children, inverted }: CarouselIndicatorProps) { +function Indicator({ styles, Children }: CarouselIndicatorProps) { const SIndicator = Root; return sstyled(styles)( @@ -744,7 +747,10 @@ function Indicator({ styles, Children, inverted }: CarouselIndicatorProps) { ); }; -const Carousel = createComponent(CarouselRoot, { +const Carousel = createComponent< + typeof CarouselType, + typeof CarouselRoot +>(CarouselRoot, { Container, ContentBox, Indicators, @@ -752,6 +758,6 @@ const Carousel = createComponent(CarouselRoot, { Item, Prev, Next, -}) as typeof CarouselType; +}); export default Carousel; diff --git a/semcore/carousel/src/Carousel.types.ts b/semcore/carousel/src/Carousel.types.ts index b93ebf868a..63766d98f9 100644 --- a/semcore/carousel/src/Carousel.types.ts +++ b/semcore/carousel/src/Carousel.types.ts @@ -1,6 +1,8 @@ import type { BoxProps } from '@semcore/base-components'; import type { PropGetterFn, Intergalactic, IRootComponentProps } from '@semcore/core'; +import type { LocalizedMessages } from './translations/__intergalactic-dynamic-locales'; + export type CarouselProps = BoxProps & { /** Index active item */ index?: number; @@ -29,6 +31,16 @@ export type CarouselProps = BoxProps & { indicators?: 'default' | 'hide' | 'preview'; }; +export type CarouselDefaultProps = { + defaultIndex: 0; + duration: 350; + step: 100; + bounded: false; + i18n: LocalizedMessages; + locale: 'en'; + indicators: 'default'; +}; + export type CarouselContext = { getContainerProps: PropGetterFn; getItemProps: PropGetterFn; diff --git a/semcore/carousel/src/translations/__intergalactic-dynamic-locales.ts b/semcore/carousel/src/translations/__intergalactic-dynamic-locales.ts index ccae777b73..65cdb67688 100644 --- a/semcore/carousel/src/translations/__intergalactic-dynamic-locales.ts +++ b/semcore/carousel/src/translations/__intergalactic-dynamic-locales.ts @@ -29,3 +29,5 @@ export const localizedMessages = { pl, sv, }; + +export type LocalizedMessages = typeof localizedMessages; diff --git a/semcore/checkbox/src/Checkbox.tsx b/semcore/checkbox/src/Checkbox.tsx index ebdd6340b9..fc69147ecc 100644 --- a/semcore/checkbox/src/Checkbox.tsx +++ b/semcore/checkbox/src/Checkbox.tsx @@ -18,9 +18,11 @@ type State = { class CheckboxRoot extends Component< Intergalactic.InternalTypings.InferComponentProps, - never, + [], {}, - State + {}, + State, + NSCheckbox.DefaultProps > { static displayName = 'Checkbox'; static style = style; @@ -29,7 +31,7 @@ class CheckboxRoot extends Component< size: 'm', state: 'normal', defaultChecked: false, - }; + } as const; state = { hoistedDisabled: undefined, @@ -113,7 +115,10 @@ class CheckboxRoot extends Component< class ValueRoot extends Component< Intergalactic.InternalTypings.InferChildComponentProps, typeof ValueRoot.enhance, - { checked: (e: React.ChangeEvent) => boolean } + NSCheckbox.Value.Handlers, + NSCheckbox.Value.InnerProps, + {}, + NSCheckbox.Value.DefaultProps > { static defaultProps = () => { return { @@ -256,14 +261,20 @@ function Text(props: Intergalactic.InternalTypings.InferChildComponentProps(ValueRoot, { Control, CheckMark, -}) as NSCheckbox.Value.Component; +}); -const Checkbox = createComponent(CheckboxRoot, { +const Checkbox = createComponent< + NSCheckbox.Component, + typeof CheckboxRoot +>(CheckboxRoot, { Text, Value, -}) as NSCheckbox.Component; +}); export default Checkbox; diff --git a/semcore/checkbox/src/Checkbox.type.ts b/semcore/checkbox/src/Checkbox.type.ts index 3a1bd15245..756d435f2b 100644 --- a/semcore/checkbox/src/Checkbox.type.ts +++ b/semcore/checkbox/src/Checkbox.type.ts @@ -33,6 +33,11 @@ declare namespace NSCheckbox { */ theme?: string; }; + type DefaultProps = { + size: 'm'; + state: 'normal'; + defaultChecked: false; + }; type Ctx = { getTextProps: PropGetterFn; getValueProps: PropGetterFn; @@ -40,6 +45,15 @@ declare namespace NSCheckbox { namespace Value { type Props = FlexProps; + type InnerProps = { + includeInputProps: string[]; + }; + type DefaultProps = { + includeInputProps: InnerProps['includeInputProps']; + }; + type Handlers = { + checked: (e: React.ChangeEvent) => boolean; + }; namespace Control { type Props = {}; diff --git a/semcore/color-picker/src/ColorPicker.tsx b/semcore/color-picker/src/ColorPicker.tsx index e8a3be83c0..8ce0eefa89 100644 --- a/semcore/color-picker/src/ColorPicker.tsx +++ b/semcore/color-picker/src/ColorPicker.tsx @@ -1,12 +1,15 @@ import { Box, Flex } from '@semcore/base-components'; +import type { Intergalactic } from '@semcore/core'; import { createComponent, Component, sstyled, Root } from '@semcore/core'; +import type { WithI18nEnhanceProps } from '@semcore/core/lib/utils/enhances/i18nEnhance'; import i18nEnhance from '@semcore/core/lib/utils/enhances/i18nEnhance'; import Dropdown from '@semcore/dropdown'; import ChevronDownM from '@semcore/icon/ChevronDown/m'; import React from 'react'; -import { Item, Colors, ColorsCustom, InputColor } from './components'; -import PaletteManagerRoot from './PaletteManager'; +import type { NSColorPicker } from './ColorPicker.type'; +import Item from './components/Item'; +import type { ItemProps } from './components/Item.type'; import style from './style/color-picker.shadow.css'; import { localizedMessages } from './translations/__intergalactic-dynamic-locales'; @@ -25,44 +28,18 @@ const defaultColors = [ '#C7EE96', ]; -type RootAsProps = { - defaultVisible?: boolean; - visible?: boolean; - defaultValue?: string; - value?: string; - onChange?: (value: string, event: React.ChangeEvent) => void; - colors?: string[]; - onColorsChange?: (value: string, event: React.ChangeEvent) => void; - displayLabel?: boolean; - styles?: React.CSSProperties; - Children: React.FC; - getI18nText: (messageId: string, values?: { [key: string]: string | number }) => string; -}; - -type TriggerAsProps = { - styles?: React.CSSProperties; - value?: string; - popperVisible: boolean; - Children: React.FC; - getI18nText: (messageId: string, values?: { [key: string]: string | number }) => string; -}; - -type PopperAsProps = { - styles?: React.CSSProperties; - Children: React.FC; - children?: React.ReactNode; - getI18nText: (messageId: string, values?: { [key: string]: string | number }) => string; -}; - -type ItemAsProps = { - value: string; -}; - -class ColorPickerRoot extends Component { +class ColorPickerRoot extends Component< + Intergalactic.InternalTypings.InferComponentProps, + typeof ColorPickerRoot.enhance, + NSColorPicker.Handlers, + WithI18nEnhanceProps, + {}, + NSColorPicker.DefaultProps +> { static displayName = 'ColorPicker'; static style = style; - static enhance = [i18nEnhance(localizedMessages)]; + static enhance = [i18nEnhance(localizedMessages)] as const; static defaultProps = () => ({ defaultVisible: false, @@ -76,7 +53,7 @@ class ColorPickerRoot extends Component ), - }); + } as const); uncontrolledProps() { return { @@ -85,7 +62,7 @@ class ColorPickerRoot extends Component (event: React.MouseEvent | React.KeyboardEvent) => { + bindHandlerItemClick = (value: ItemProps['value']) => (event: React.MouseEvent | React.KeyboardEvent) => { this.handlers.value(value, event); this.handlers.visible(false, event); event.preventDefault(); @@ -118,11 +95,12 @@ class ColorPickerRoot extends Component { @@ -153,7 +131,9 @@ class ColorPickerRoot extends Component, +) { const { Children, getI18nText, value } = props; const label = React.useMemo(() => { @@ -171,7 +151,10 @@ export function Trigger(props: TriggerAsProps) { ); } -const DefaultTrigger = React.forwardRef(function (props: TriggerAsProps, ref) { +const DefaultTrigger = React.forwardRef(function ( + props: Intergalactic.InternalTypings.InferChildComponentProps, + ref, +) { const { styles, value } = props; const SDefaultTrigger = Root; const STriggerCircle = Flex; @@ -181,32 +164,58 @@ const DefaultTrigger = React.forwardRef(function (props: TriggerAsProps, ref) { , - ) as React.ReactElement; + ); }); -export function Popper(props: PopperAsProps) { +function Popper( + props: Intergalactic.InternalTypings.InferChildComponentProps, +) { const { styles, Children, getI18nText, children } = props; const SColorPickerPopper = Root; return sstyled(styles)( - {children ? : } + {children ? : } , ); } -const ColorPicker = createComponent(ColorPickerRoot, { +function Colors( + props: Intergalactic.InternalTypings.InferChildComponentProps, +) { + const { Children, styles, colors, getI18nText } = props; + const SColors = Root; + + return sstyled(styles)( + + {Children.origin + ? ( + + ) + : ( + // TODO: Re-think the component structure. + // @ts-ignore + colors?.map((color) => ) + )} + , + ); +} + +const ColorPicker = createComponent< + NSColorPicker.Component, + typeof ColorPickerRoot +>(ColorPickerRoot, { Trigger, Popper, - Item, Colors, -}) as any; + Item, +}); -const PaletteManager = createComponent(PaletteManagerRoot, { - Item: ColorPicker.Item, - Colors: ColorsCustom, - InputColor, -}) as any; +export { defaultColors }; -export { PaletteManager, defaultColors }; export default ColorPicker; diff --git a/semcore/color-picker/src/ColorPicker.type.ts b/semcore/color-picker/src/ColorPicker.type.ts new file mode 100644 index 0000000000..4a72c46eab --- /dev/null +++ b/semcore/color-picker/src/ColorPicker.type.ts @@ -0,0 +1,89 @@ +import type { BoxProps, Popper } from '@semcore/base-components'; +import type { PropGetterFn, Intergalactic } from '@semcore/core'; +import type { DropdownProps } from '@semcore/dropdown'; +import type Dropdown from '@semcore/dropdown'; + +import type { LocalizedMessages } from './translations/__intergalactic-dynamic-locales'; + +declare namespace NSColorPicker { + type Props = DropdownProps & { + /** + * Selected color item. Should be used with `onChange` property together + */ + value?: string | null; + /** + * Fired when user selects color item. Should be used with `value` property together + */ + onChange?: (value: string, event: React.ChangeEvent) => void; + /** + * Default value if `value` property is not provided + * @default null + */ + defaultValue?: string | null; + /** + * Array of color items. Should be used with `onColorsChange` property together + * @default defaultColors + */ + colors?: (string | null)[]; + /** + * Fired when user changes color items. Should be used with `colors` property together + */ + onColorsChange?: (value: string[], event: React.ChangeEvent) => void; + /** + * Shows label `A` as text color icon inside all color items + * @default false + */ + displayLabel?: boolean; + }; + type DefaultProps = { + defaultVisible: false; + defaultValue: null; + colors: Props['colors']; + i18n: LocalizedMessages; + locale: 'en'; + children: React.JSX.Element; + }; + type Ctx = { + getTriggerProps: PropGetterFn; + getColorsProps: PropGetterFn; + getItemProps: PropGetterFn; + }; + type Handlers = { + value: Props['value']; + visible: boolean; + }; + + namespace Trigger { + type Component = typeof Dropdown.Trigger; + } + + namespace Popper { + type Component = typeof Popper.Popper; + } + + namespace Colors { + type Props = BoxProps & { + /** + * Array of color items + */ + colors?: Array; + }; + + type Component = Intergalactic.Component<'div', Props>; + } + + type Component = Intergalactic.Component<'div', Props, Ctx, [handlers: Handlers]> & { + Trigger: Trigger.Component; + Popper: Popper.Component; + Colors: Colors.Component; + }; +} + +/** @deprecated It will be removed in v18. */ +export type ColorsProps = NSColorPicker.Colors.Props; +/** @deprecated It will be removed in v18. */ +export type ColorPickerProps = NSColorPicker.Props; +/** @deprecated It will be removed in v18. */ +export type ColorPickerHandlers = NSColorPicker.Handlers; + +export type { NSColorPicker }; diff --git a/semcore/color-picker/src/PaletteManager.tsx b/semcore/color-picker/src/PaletteManager.tsx index e40365e756..03dc213ce4 100644 --- a/semcore/color-picker/src/PaletteManager.tsx +++ b/semcore/color-picker/src/PaletteManager.tsx @@ -1,35 +1,45 @@ -import { Component, sstyled, CORE_INSTANCE } from '@semcore/core'; +import { Box, Flex } from '@semcore/base-components'; +import { ButtonLink } from '@semcore/button'; +import type { Intergalactic } from '@semcore/core'; +import { Component, sstyled, createComponent, Root } from '@semcore/core'; +import type { WithI18nEnhanceProps } from '@semcore/core/lib/utils/enhances/i18nEnhance'; import i18nEnhance from '@semcore/core/lib/utils/enhances/i18nEnhance'; import uniqueIdEnhance from '@semcore/core/lib/utils/uniqueID'; import Divider from '@semcore/divider'; +import CheckM from '@semcore/icon/Check/m'; +import CloseM from '@semcore/icon/Close/m'; +import MathPlusM from '@semcore/icon/MathPlus/m'; +import Input from '@semcore/input'; import React from 'react'; +import ColorPicker from './ColorPicker'; +import Item from './components/Item'; +import type { ItemProps } from './components/Item.type'; +import type { NSPaletteManager } from './PaletteManager.type'; import style from './style/color-picker.shadow.css'; import { localizedMessages } from './translations/__intergalactic-dynamic-locales'; - -type RootAsProps = { - defaultColors?: string[]; - colors?: string[]; - onColorsChange?: (value: string, event: React.ChangeEvent) => void; - styles?: React.CSSProperties; - Children: React.FC; - getI18nText: (messageId: string, values?: { [key: string]: string | number }) => string; -}; +import debounce from './utils/debounce'; +import isValidHex from './utils/isValidHex'; type State = { focus: boolean }; -const enhance = [i18nEnhance(localizedMessages), uniqueIdEnhance()] as const; - -class PaletteManagerRoot extends Component { +class PaletteManagerRoot extends Component< + Intergalactic.InternalTypings.InferComponentProps, + typeof PaletteManagerRoot.enhance, + NSPaletteManager.Handlers, + WithI18nEnhanceProps, + State, + NSPaletteManager.DefaultProps +> { static displayName = 'PaletteManager'; static style = style; - static enhance = enhance; + static enhance = [i18nEnhance(localizedMessages), uniqueIdEnhance()] as const; static defaultProps = { defaultColors: [], i18n: localizedMessages, - locale: 'en', + locale: 'en' as const, }; refInput = React.createRef(); @@ -44,7 +54,7 @@ class PaletteManagerRoot extends Component (event: React.MouseEvent) => { + bindHandlerItemRemove = (value: ItemProps['value']) => (event: React.MouseEvent | React.KeyboardEvent) => { event.stopPropagation(); const { colors = [] } = this.asProps; this.handlers.colors( @@ -76,7 +86,7 @@ class PaletteManagerRoot extends Component @@ -125,4 +133,172 @@ class PaletteManagerRoot extends Component, +) { + const { Children, styles, colors, onPlusButtonClick, getI18nText } = props; + const SColors = Root; + const SColorsContainer = Flex; + const SPlusButton = 'div'; + + return sstyled(styles)( + + + {Children.origin + ? ( + + ) + : ( + // TODO: Re-think the component structure. + // @ts-ignore + colors.map((color) => ) + )} + + + + + , + ); +} + +class InputColor extends Component< + Intergalactic.InternalTypings.InferChildComponentProps, + [], + NSPaletteManager.InputColor.Handlers, + {}, + {}, + NSPaletteManager.InputColor.DefaultProps +> { + static displayName = 'InputColor'; + + static style = style; + + static defaultProps = { + defaultValue: '', + defaultState: 'normal', + } as const; + + uncontrolledProps() { + return { + value: '', + state: null, + }; + } + + handlerAdd = (event: React.MouseEvent | React.KeyboardEvent) => { + const { value, state } = this.asProps as any; + + if (value.length !== 0 && state === 'normal') { + if (value[0] === '#') { + this.asProps?.onAdd?.(value.toLowerCase(), event); + } else { + this.asProps?.onAdd?.(`#${value.toLowerCase()}`, event); + } + this.handlers.value('', event); + } + }; + + handlerCancel = (event: React.MouseEvent) => { + this.handlers.value('', event); + this.handlers.state('normal'); + }; + + handlerChange = debounce((value: string) => { + if (value.length !== 0) { + if (isValidHex(value)) { + this.handlers.state('normal'); + } else { + this.handlers.state('invalid'); + } + } else { + this.handlers.state('normal'); + } + }, 300); + + handlekeyDown = (event: React.KeyboardEvent) => { + if (event.key === 'Enter') { + event.preventDefault(); + this.handlerAdd(event); + } + }; + + render() { + const { styles, state, value, onFocus, onBlur, focus, getI18nText, size } = this.asProps; + + const SPaletteManager = Box; + const SInputValue = Root; + const SInput = 'div'; + const SInputContainer = 'div'; + const SConfirmColor = Input.Addon; + const SClearConfirm = Input.Addon; + const SItemColor = Box; + const valueColor = value?.[0] === '#' ? value : value ? `#${value}` : null; + + return sstyled(styles)( + + + + + + + + + + + + + , + ); + } +} + +export const PaletteManager = createComponent< + NSPaletteManager.Component, + typeof PaletteManagerRoot +>(PaletteManagerRoot, { + Colors, + InputColor, + // @ts-ignore + Item: ColorPicker.Item, +}); diff --git a/semcore/color-picker/src/PaletteManager.type.ts b/semcore/color-picker/src/PaletteManager.type.ts new file mode 100644 index 0000000000..ee00db5f20 --- /dev/null +++ b/semcore/color-picker/src/PaletteManager.type.ts @@ -0,0 +1,100 @@ +import type { PropGetterFn, Intergalactic } from '@semcore/core'; +import type { InputProps } from '@semcore/input'; + +import type { NSColorPicker } from './ColorPicker.type'; +import type { LocalizedMessages } from './translations/__intergalactic-dynamic-locales'; + +declare namespace NSPaletteManager { + type Props = { + /** + * Array of color items. Should be used with `onColorsChange` property together + * @default [] + */ + colors?: string[]; + /** + * Default value if `colors` property is not provided + * @default [] + */ + defaultColors?: string[]; + /** + * Fired when user adds or removes color items. Should be used with `colors` property together + */ + onColorsChange?: (value: string[], event: React.ChangeEvent) => void; + }; + type DefaultProps = { + defaultColors: Props['defaultColors']; + i18n: LocalizedMessages; + locale: 'en'; + }; + type Ctx = { + getInputColorProps: PropGetterFn; + getColorsProps: PropGetterFn; + getItemProps: PropGetterFn; + }; + type Handlers = { colors: Props['colors'] }; + + namespace Colors { + type Props = NSColorPicker.Colors.Props & { + /** + * Fired when user clicks on the plus icon in Palette Manager - focuses the input component + */ + onPlusButtonClick?: React.MouseEventHandler; + }; + + type Component = Intergalactic.Component<'div', Props>; + } + + namespace InputColor { + type Props = InputProps & { + /** + * Text value of input + */ + value?: string; + /** + * Default value if `value` property is not provided + * @default null + */ + defaultValue?: string | null; + /** + * Uncontrolled visual state of input + * @default normal + */ + state?: 'normal' | 'valid' | 'invalid'; + /** + * Array of color items + */ + colors?: string[]; + /** + * Fired with entered value when user clicks on the check icon or hits `Enter` or `Space` + */ + onAdd?: (value: string, event: React.MouseEvent | React.KeyboardEvent) => void; + /** + * Handle changes of state + */ + onStateChange?: (state: 'normal' | 'valid' | 'invalid') => void; + }; + type DefaultProps = { + defaultValue: ''; + defaultState: 'normal'; + }; + type Handlers = { value: string; state: null }; + + type Component = Intergalactic.Component<'div', Props>; + } + + type Component = Intergalactic.Component<'div', Props, Ctx, [handlers: Handlers]> & { + Colors: Colors.Component; + InputColor: InputColor.Component; + }; +} + +/** @deprecated It will be removed in v18. */ +export type PaletteManagerProps = NSPaletteManager.Props; +/** @deprecated It will be removed in v18. */ +export type PaletteManagerHandlers = NSPaletteManager.Handlers; +/** @deprecated It will be removed in v18. */ +export type ColorsCustomProps = NSPaletteManager.Colors.Props; +/** @deprecated It will be removed in v18. */ +export type InputColorProps = NSPaletteManager.InputColor.Props; + +export type { NSPaletteManager }; diff --git a/semcore/color-picker/src/components/InputColor.tsx b/semcore/color-picker/src/components/InputColor.tsx deleted file mode 100644 index 5bf8842333..0000000000 --- a/semcore/color-picker/src/components/InputColor.tsx +++ /dev/null @@ -1,163 +0,0 @@ -import { Box } from '@semcore/base-components'; -import { ButtonLink } from '@semcore/button'; -import { createComponent, Component, sstyled, Root } from '@semcore/core'; -import CheckM from '@semcore/icon/Check/m'; -import CloseM from '@semcore/icon/Close/m'; -import Input from '@semcore/input'; -import type { InputSize } from '@semcore/input'; -import React from 'react'; - -import style from '../style/color-picker.shadow.css'; - -type InputColorAsProps = { - styles?: React.CSSProperties; - defaultValue?: string; - defaultState?: string; - value?: string; - state?: 'normal' | 'valid' | 'invalid'; - colors?: string[]; - onAdd?: (value: string, event: React.MouseEvent | React.KeyboardEvent) => void; - focus?: boolean; - Children: any; - getI18nText: (messageId: string, values?: { [key: string]: string | number }) => string; - size?: InputSize; -}; - -function isValidHex(hex: string) { - if (hex[0] !== '#' && hex.length === 7) return false; - - const reg = /^#([0-9a-f]{3,4}){1,2}$/i; - return hex[0] === '#' ? reg.test(hex) : reg.test(`#${hex}`); -} - -function debounce(this: any, func: (...args: any[]) => void, timeout: number) { - let timer: any; - return (...args: any[]) => { - clearTimeout(timer); - timer = setTimeout(() => { - func.apply(this, args); - }, timeout); - }; -} - -class InputColorRoot extends Component { - static displayName = 'InputColor'; - - static style = style; - - static defaultProps = { - defaultValue: '', - defaultState: 'normal', - }; - - uncontrolledProps() { - return { - value: '', - state: null, - }; - } - - handlerAdd = (event: React.MouseEvent | React.KeyboardEvent) => { - const { value, state } = this.asProps as any; - - if (value.length !== 0 && state === 'normal') { - if (value[0] === '#') { - this.asProps?.onAdd?.(value.toLowerCase(), event); - } else { - this.asProps?.onAdd?.(`#${value.toLowerCase()}`, event); - } - this.handlers.value('', event); - } - }; - - handlerCancel = (event: React.MouseEvent) => { - this.handlers.value('', event); - this.handlers.state('normal'); - }; - - handlerChange = debounce((value: string) => { - if (value.length !== 0) { - if (isValidHex(value)) { - this.handlers.state('normal'); - } else { - this.handlers.state('invalid'); - } - } else { - this.handlers.state('normal'); - } - }, 300); - - handlekeyDown = (event: React.KeyboardEvent) => { - if (event.key === 'Enter') { - event.preventDefault(); - this.handlerAdd(event); - } - }; - - render() { - const { styles, state, value, onFocus, onBlur, focus, getI18nText, size } = this.asProps; - - const SPaletteManager = Box; - const SInputValue = Root; - const SInput = 'div'; - const SInputContainer = 'div'; - const SConfirmColor = Input.Addon; - const SClearConfirm = Input.Addon; - const SItemColor = Box; - const valueColor = value?.[0] === '#' ? value : value ? `#${value}` : null; - - return sstyled(styles)( - - - - - - - - - - - - - , - ) as React.ReactElement; - } -} - -export const InputColor = createComponent(InputColorRoot); diff --git a/semcore/color-picker/src/components/Item.tsx b/semcore/color-picker/src/components/Item.tsx index a395cdd8a0..a05bdb98b6 100644 --- a/semcore/color-picker/src/components/Item.tsx +++ b/semcore/color-picker/src/components/Item.tsx @@ -26,7 +26,7 @@ const interaction = { ], }; -export function Item(props: ItemAsProps) { +export default function Item(props: ItemAsProps) { const { Children, styles, value, displayLabel, editable, selected, onRemove, getI18nText, uid } = props as any; const SItemContainer = Root; @@ -76,5 +76,5 @@ export function Item(props: ItemAsProps) { {value ?? getI18nText('clearColor')} , - ) as React.ReactElement; + ); } diff --git a/semcore/color-picker/src/components/Item.type.ts b/semcore/color-picker/src/components/Item.type.ts new file mode 100644 index 0000000000..5a11c8c98a --- /dev/null +++ b/semcore/color-picker/src/components/Item.type.ts @@ -0,0 +1,26 @@ +import type { BoxProps } from '@semcore/base-components'; + +/** TODO: revise component structure */ +/** @deprecated It will be removed in v18. */ +export type ItemProps = BoxProps & { + /** + * Color item in hexadecimal format. + */ + value?: string | null; + /** + * Shows label `A` as text color icon inside all color items + */ + displayLabel?: boolean; + /** + * Property enabling the ability to remove a color item on click + */ + editable?: boolean; + /** + * Shows if color item is selected + */ + selected?: boolean; + /** + * Fired with color item when user clicks on the close icon + */ + onRemove?: React.MouseEventHandler; +}; diff --git a/semcore/color-picker/src/components/colors.tsx b/semcore/color-picker/src/components/colors.tsx deleted file mode 100644 index b6f9673a0a..0000000000 --- a/semcore/color-picker/src/components/colors.tsx +++ /dev/null @@ -1,68 +0,0 @@ -import { Box, Flex } from '@semcore/base-components'; -import { Root, sstyled } from '@semcore/core'; -import MathPlusM from '@semcore/icon/MathPlus/m'; -import React from 'react'; - -import ColorPicker, { PaletteManager } from '../ColorPicker'; - -type ColorsAsProps = { - styles?: React.CSSProperties; - colors?: string[]; - Children: any; - getI18nText: (messageId: string, values?: { [key: string]: string | number }) => string; -}; - -type ColorsCustomAsProps = ColorsAsProps & { - onPlusButtonClick?: React.MouseEventHandler; -}; - -export function Colors(props: ColorsAsProps) { - const { Children, styles, colors, getI18nText } = props; - const SColors = Root; - - return sstyled(styles)( - - {Children.origin - ? ( - - ) - : ( - colors?.map((color) => ) - )} - , - ) as React.ReactElement; -} - -export function ColorsCustom(props: ColorsCustomAsProps) { - const { Children, styles, colors, onPlusButtonClick, getI18nText } = props; - const SColors = Root; - const SColorsContainer = Flex; - const SPlusButton = 'div'; - - return sstyled(styles)( - - - {Children.origin - ? ( - - ) - : ( - colors?.map((color) => ) - )} - - - - - , - ) as React.ReactElement; -} diff --git a/semcore/color-picker/src/components/index.ts b/semcore/color-picker/src/components/index.ts deleted file mode 100644 index 190d095418..0000000000 --- a/semcore/color-picker/src/components/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from './Item'; -export { InputColor } from './InputColor'; -export * from './colors'; diff --git a/semcore/color-picker/src/index.d.ts b/semcore/color-picker/src/index.d.ts deleted file mode 100644 index 776f3d623c..0000000000 --- a/semcore/color-picker/src/index.d.ts +++ /dev/null @@ -1,162 +0,0 @@ -import type { BoxProps } from '@semcore/base-components'; -import type Popper from '@semcore/base-components'; -import type { PropGetterFn, UnknownProperties, Intergalactic } from '@semcore/core'; -import type { DropdownProps, DropdownHandlers } from '@semcore/dropdown'; -import type Dropdown from '@semcore/dropdown'; -import type { InputProps } from '@semcore/input'; - -export type ItemProps = BoxProps & { - /** - * Color item in hexadecimal format. - */ - value?: string | null; - /** - * Shows label `A` as text color icon inside all color items - */ - displayLabel?: boolean; - /** - * Property enabling the ability to remove a color item on click - */ - editable?: boolean; - /** - * Shows if color item is selected - */ - selected?: boolean; - /** - * Fired with color item when user clicks on the close icon - */ - onRemove?: React.MouseEventHandler; -}; - -export type ColorsProps = BoxProps & { - /** - * Array of color items - */ - colors?: Array; -}; - -export type ColorsCustomProps = ColorsProps & - BoxProps & { - /** - * Fired when user clicks on the plus icon in Palette Manager - focuses the input component - */ - onPlusButtonClick?: React.MouseEventHandler; - }; - -export type InputColorProps = InputProps & { - /** - * Text value of input - */ - value?: string; - /** - * Default value if `value` property is not provided - * @default null - */ - defaultValue?: string | null; - /** - * Uncontrolled visual state of input - * @default normal - */ - state?: 'normal' | 'valid' | 'invalid'; - /** - * Array of color items - */ - colors?: string[]; - /** - * Fired with entered value when user clicks on the check icon or hits `Enter` or `Space` - */ - onAdd?: (value: string, event: React.MouseEvent | React.KeyboardEvent) => void; - /** - * Handle changes of state - */ - onStateChange?: (state: 'normal' | 'valid' | 'invalid') => void; -}; - -export type ColorPickerProps = DropdownProps & { - /** - * Selected color item. Should be used with `onChange` property together - */ - value?: string | null; - /** - * Fired when user selects color item. Should be used with `value` property together - */ - onChange?: (value: string, event: React.ChangeEvent) => void; - /** - * Default value if `value` property is not provided - * @default null - */ - defaultValue?: string | null; - /** - * Array of color items. Should be used with `onColorsChange` property together - * @default defaultColors - */ - colors?: string[]; - /** - * Fired when user changes color items. Should be used with `colors` property together - */ - onColorsChange?: (value: string[], event: React.ChangeEvent) => void; - /** - * Shows label `A` as text color icon inside all color items - * @default false - */ - displayLabel?: boolean; -}; - -export type PaletteManagerProps = { - /** - * Array of color items. Should be used with `onColorsChange` property together - * @default [] - */ - colors?: string[]; - /** - * Default value if `colors` property is not provided - * @default [] - */ - defaultColors?: string[]; - /** - * Fired when user adds or removes color items. Should be used with `colors` property together - */ - onColorsChange?: (value: string[], event: React.ChangeEvent) => void; -}; - -export type ColorPickerHandlers = DropdownHandlers & {}; - -export type PaletteManagerHandlers = DropdownHandlers & {}; - -type ColorPickerContext = { - getTriggerProps: PropGetterFn; - getColorsProps: PropGetterFn; - getItemProps: PropGetterFn; -}; - -type PaletteManagerContext = { - getInputColorProps: PropGetterFn; - getColorsProps: PropGetterFn; - getItemProps: PropGetterFn; -}; - -declare const defaultColors: string[]; - -declare const PaletteManager: Intergalactic.Component< - 'div', - PaletteManagerProps, - PaletteManagerContext, - [handlers: PaletteManagerHandlers] -> & { - Colors: Intergalactic.Component<'div', ColorsCustomProps>; - InputColor: Intergalactic.Component<'div', InputColorProps>; -}; - -declare const ColorPicker: Intergalactic.Component< - 'div', - ColorPickerProps, - ColorPickerContext, - [handlers: ColorPickerHandlers] -> & { - Trigger: typeof Dropdown.Trigger; - Popper: typeof Popper.Popper; - Colors: Intergalactic.Component<'div', ColorsProps>; -}; - -export { PaletteManager, defaultColors }; -export default ColorPicker; diff --git a/semcore/color-picker/src/index.js b/semcore/color-picker/src/index.js deleted file mode 100644 index f388c08436..0000000000 --- a/semcore/color-picker/src/index.js +++ /dev/null @@ -1,2 +0,0 @@ -export { default } from './ColorPicker'; -export * from './ColorPicker'; diff --git a/semcore/color-picker/src/index.ts b/semcore/color-picker/src/index.ts new file mode 100644 index 0000000000..f2debaaacc --- /dev/null +++ b/semcore/color-picker/src/index.ts @@ -0,0 +1,5 @@ +export { default, defaultColors } from './ColorPicker'; +export * from './ColorPicker.type'; +export { PaletteManager } from './PaletteManager'; +export * from './PaletteManager.type'; +export * from './components/Item.type'; diff --git a/semcore/color-picker/src/translations/__intergalactic-dynamic-locales.ts b/semcore/color-picker/src/translations/__intergalactic-dynamic-locales.ts index ccae777b73..65cdb67688 100644 --- a/semcore/color-picker/src/translations/__intergalactic-dynamic-locales.ts +++ b/semcore/color-picker/src/translations/__intergalactic-dynamic-locales.ts @@ -29,3 +29,5 @@ export const localizedMessages = { pl, sv, }; + +export type LocalizedMessages = typeof localizedMessages; diff --git a/semcore/color-picker/src/utils/debounce.ts b/semcore/color-picker/src/utils/debounce.ts new file mode 100644 index 0000000000..9348134880 --- /dev/null +++ b/semcore/color-picker/src/utils/debounce.ts @@ -0,0 +1,11 @@ +function debounce(this: any, func: (...args: any[]) => void, timeout: number) { + let timer: any; + return (...args: any[]) => { + clearTimeout(timer); + timer = setTimeout(() => { + func.apply(this, args); + }, timeout); + }; +} + +export default debounce; diff --git a/semcore/color-picker/src/utils/isValidHex.ts b/semcore/color-picker/src/utils/isValidHex.ts new file mode 100644 index 0000000000..a494ad59bf --- /dev/null +++ b/semcore/color-picker/src/utils/isValidHex.ts @@ -0,0 +1,8 @@ +function isValidHex(hex: string) { + if (hex[0] !== '#' && hex.length === 7) return false; + + const reg = /^#([0-9a-f]{3,4}){1,2}$/i; + return hex[0] === '#' ? reg.test(hex) : reg.test(`#${hex}`); +} + +export default isValidHex; diff --git a/semcore/core/__tests__/Core.test.tsx b/semcore/core/__tests__/Core.test.tsx index 7bbc93e4eb..ad06b01c35 100644 --- a/semcore/core/__tests__/Core.test.tsx +++ b/semcore/core/__tests__/Core.test.tsx @@ -66,7 +66,7 @@ type ItemType = { Item: HTMLAttributes }; function shouldSupportRender(RootComponent: any, typeRootComponent: any) { test(`Should support just render ${typeRootComponent}`, () => { - const Test = createComponent<'div', CompType>(RootComponent); + const Test = createComponent(RootComponent); const { getByTestId } = render(test); expect(getByTestId('core').innerHTML).toBe('test'); }); @@ -78,11 +78,10 @@ function shouldSupportRenderChildrenRoot( description: any, ) { test(`Should support render children root ${description}`, () => { - const Item = createComponent<'div', ItemType['Item']>(ChildrenComponent); - const Test = createComponent<'div', CompType, ItemType>(RootComponent, { Item }); + const Item = createComponent(ChildrenComponent); + const Test = createComponent(RootComponent, { Item }); const { getByTestId } = render( - {/* @ts-ignore */} test , ); @@ -92,13 +91,11 @@ function shouldSupportRenderChildrenRoot( function shouldSupportChildren(ChildrenComponent: any, typeChildrenComponent: any) { test(`Should support children components ${typeChildrenComponent}`, () => { - const Test = createComponent<'div', CompType, ItemType>(RootTestClass, { + const Test = createComponent(RootTestClass, { Item: ChildrenComponent, }); - // @ts-ignore expect(Test.Item).not.toBeNull(); - // @ts-ignore expect(Test.Item.displayName).toBe(`${Test.displayName}.Item`); }); } @@ -111,7 +108,7 @@ function shouldSupportCallEnhance(RootComponent: any, typeRootComponent: any) { return props; }; RootComponent.enhance = [enhance]; - const Test = createComponent(RootComponent); + const Test = createComponent(RootComponent); render(); expect(spy).toHaveBeenCalledTimes(1); }); @@ -129,7 +126,7 @@ function shouldSupportCallEnhanceWithProps(RootComponent: any, typeRootComponent return props; }; RootComponent.enhance = [enhance]; - const Test = createComponent(RootComponent); + const Test = createComponent(RootComponent); render(); expect(spy).toHaveBeenCalledTimes(1); expect(spy).toHaveBeenCalledWith({ @@ -158,7 +155,7 @@ describe('Core', () => { 'Root Function inside Root Function', ); - shouldSupportRef(createComponent(RootTestClass)); + shouldSupportRef(createComponent(RootTestClass)); shouldSupportCallEnhance(RootTestClass, 'Class'); shouldSupportCallEnhance(RootTestFunc, 'Function'); @@ -170,10 +167,10 @@ describe('Core', () => { shouldSupportChildren(ChildrenTestFunc, 'Function'); test('Should support custom props name', () => { - const Test = createComponent(RootTestClass); - const TestWithChildren = createComponent(RootTestClass, { + const Test = createComponent(RootTestClass); + const TestWithChildren = createComponent(RootTestClass, { Item: ChildrenTestFunc, - }) as any; + }); const { getByTestId } = render( <> @@ -187,7 +184,7 @@ describe('Core', () => { }); test('Should support set data-ui-name', () => { - const InheritTest = createComponent(RootTestClass); + const InheritTest = createComponent(RootTestClass); class TestClass extends Component { static displayName = 'TestClass'; @@ -198,7 +195,7 @@ describe('Core', () => { } } - const Test = createComponent(TestClass); + const Test = createComponent(TestClass); const { queryByTestId } = render(); expect((queryByTestId('test')?.attributes as any)['data-ui-name'].value).toBe('TestClass'); @@ -222,7 +219,7 @@ describe('Root', () => { } } - const Test = createComponent(TestRoot); + const Test = createComponent(TestRoot); const { queryByTestId } = render(); expect(queryByTestId('root')?.id).toBe('test'); @@ -252,7 +249,7 @@ describe('Root', () => { const spyClick = vi.fn(); const spyRef = vi.fn(); - const Test = createComponent(TestRoot); + const Test = createComponent(TestRoot); const { queryByTestId } = render( { class RootTestClass extends Component< IRootComponentProps & { value?: number; defaultValue?: number }, [], - { value: null } + { value: null }, + {}, + {}, + { defaultValue: 5 } > { static defaultProps = { defaultValue: 5, - }; + } as const; uncontrolledProps() { return { value: null }; @@ -305,7 +305,7 @@ describe('Controll/Uncontroll mode', () => { } } - const Test = createComponent(RootTestClass); + const Test = createComponent(RootTestClass); render(); expect(spy).toHaveBeenCalledTimes(1); @@ -317,11 +317,14 @@ describe('Controll/Uncontroll mode', () => { class RootTestClass extends Component< IRootComponentProps & { value?: any; defaultValue?: any }, [], - { value: any } + { value: any }, + {}, + {}, + { defaultValue: '' } > { static defaultProps = { defaultValue: '', - }; + } as const; uncontrolledProps() { return { value: [(e: any) => e.currentTarget.value, (value: any) => spy(value)] }; @@ -333,7 +336,7 @@ describe('Controll/Uncontroll mode', () => { } } - const Test = createComponent(RootTestClass); + const Test = createComponent(RootTestClass); const { getByTestId } = render(); const TextareaDom = getByTestId('textarea'); fireEvent.change(TextareaDom, { target: { value: 'test' } }); @@ -368,7 +371,7 @@ describe('Getter props function', () => { const spy = vi.fn(); - const Test = createComponent(RootTestClass, { Item: ChildrenTestClass }) as any; + const Test = createComponent(RootTestClass, { Item: ChildrenTestClass }); render( @@ -397,7 +400,7 @@ describe('Getter props function', () => { } const spy = vi.fn(); - const Test = createComponent(RootTestClass, { Item: ChildrenTestFunc }) as any; + const Test = createComponent(RootTestClass, { Item: ChildrenTestFunc }); render( @@ -421,10 +424,9 @@ describe('Getter props function', () => { const spy = vi.fn(); - const Test = createComponent<'div', CompType, ItemType>(RootTestClass, { Item: ChildrenTestFunc }); + const Test = createComponent(RootTestClass, { Item: ChildrenTestFunc }); render( - {/* @ts-ignore */} , ); @@ -456,7 +458,7 @@ describe('Getter props function', () => { const spyClick = vi.fn(); const spyRef = vi.fn(); - const Test = createComponent(RootTestClass, { Item: ChildrenTestFunc }) as any; + const Test = createComponent(RootTestClass, { Item: ChildrenTestFunc }); const { queryByTestId } = render( { const spy = vi.fn(); - const Test = createComponent<'div', CompType, ItemType>(RootTestClass, { Item: ChildrenTestFunc }); + const Test = createComponent(RootTestClass, { Item: ChildrenTestFunc }); render( - {/* @ts-ignore */} - {/* @ts-ignore */} , ); @@ -521,7 +521,7 @@ describe('Getter props function', () => { describe('Props from context', () => { beforeEach(cleanup); test('Should support props forwarding', () => { - const Test = createComponent<'div', { custom: string }>(RootTestClass); + const Test = createComponent(RootTestClass); render( {(props: any) => { @@ -533,9 +533,9 @@ describe('Props from context', () => { }); test('Should support props forwarding children and not overwrite', () => { - const Test = createComponent(RootTestClass, { + const Test = createComponent(RootTestClass, { Item: ChildrenTestFunc, - }) as any; + }); render( @@ -559,9 +559,9 @@ describe('Props from context', () => { } } - const Test = createComponent(TestRoot, { + const Test = createComponent(TestRoot, { Item: [ChildrenTestClass, { Value: ChildrenTestClass }], - }) as any; + }); const { getByTestId } = render( @@ -586,11 +586,14 @@ describe('Option "parent"', () => { class RootTestParent extends Component< IRootComponentProps & { value?: number; defaultValue?: number }, [], - { value: null } + { value: null }, + {}, + {}, + { defaultValue: 5 } > { static defaultProps = { defaultValue: 5, - }; + } as const; uncontrolledProps() { return { value: null }; @@ -609,8 +612,8 @@ describe('Option "parent"', () => { } } - const TestParent = createComponent(RootTestParent); - const Test = createComponent( + const TestParent = createComponent(RootTestParent); + const Test = createComponent( RootTest, {}, { @@ -648,7 +651,7 @@ describe('Option "parent"', () => { } } - return createComponent(ComponentRoot, { Item }, { parent: render }); + return createComponent(ComponentRoot, { Item }, { parent: render }); } const First = createMockComponent('First', undefined); @@ -708,7 +711,7 @@ describe('Option "parent"', () => { } } - return createComponent(ComponentRoot, { Item }, { parent: render }); + return createComponent(ComponentRoot, { Item }, { parent: render }); } const clickSpy = vi.fn(); @@ -763,17 +766,17 @@ describe('createBaseComponent', () => { TestFuncWithRef.displayName = 'TestFuncWithRef'; test('Should support symbol CORE_COMPONENT', () => { - const Test = createBaseComponent(TestFuncWithRef); + const Test = createBaseComponent(TestFuncWithRef); expect(Test[CORE_COMPONENT]).toBe(true); }); test('Should support data-ui-name', () => { - const Test = createBaseComponent(TestFuncWithRef); + const Test = createBaseComponent(TestFuncWithRef); const { getByTestId } = render(); expect(getByTestId('test').dataset.uiName).toBe(Test.displayName); }); test('Should support ref', () => { - const Test = createBaseComponent(TestFuncWithRef); + const Test = createBaseComponent(TestFuncWithRef); const ref = React.createRef(); render(); expect(ref.current?.nodeName).toBe('DIV'); diff --git a/semcore/core/src/core-types/Component.ts b/semcore/core/src/core-types/Component.ts index 7a0defac38..9830df4078 100644 --- a/semcore/core/src/core-types/Component.ts +++ b/semcore/core/src/core-types/Component.ts @@ -52,24 +52,46 @@ type UncontrolledPropValue = | ((value: V, e?: any) => void | boolean | V)[] | ((e?: any) => void | boolean | V); +export interface IComponent< + C, + /* + * Infered this way since `Props` within `Component` abstract class + * is used in multiple places in different variance positions + * causing the final type to be `never`. + * */ + P = C extends { props: Readonly } ? P : never, + DP = C extends Component ? + DP extends never + ? never + : DP + : never, +> { + new (...args: any[]): C; + defaultProps?: DP | ((props: P) => DP) | (() => DP); +} export abstract class Component< Props = {}, Enhance extends readonly ((...args: any[]) => any)[] = [], Uncontrolled extends Readonly<{ [key in keyof Props]?: UncontrolledPropValue }> = never, InnerProps = {}, State = {}, + DefaultProps extends Intergalactic.InternalTypings.ValidDefaultProps = never, > extends PureComponent { + protected __defaultProps: DefaultProps = {} as DefaultProps; + protected uncontrolledProps(): [Uncontrolled] extends [never] ? never : Uncontrolled { // @ts-ignore. This is a default value. Should be defined in related classes. return {}; - }; + } protected get handlers(): Readonly<{ [key in keyof Uncontrolled]: key extends keyof Props - ? Uncontrolled[key] extends (null | Props[key]) + ? Uncontrolled[key] extends null | Props[key] ? (value: Props[key], e?: any) => void - : Uncontrolled[key] extends Array ? Uncontrolled[key][0] : Uncontrolled[key] - : never + : Uncontrolled[key] extends Array + ? Uncontrolled[key][0] + : Uncontrolled[key] + : never; }> { // @ts-ignore. The body will be generated in factory return {}; @@ -77,9 +99,12 @@ export abstract class Component< protected get asProps() { return {} as Readonly< - { Root: RootResult } & - BaseAsProps & - Intergalactic.InternalTypings.EfficientOmit, keyof BaseAsProps> + { Root: RootResult } & BaseAsProps & + Intergalactic.InternalTypings.EfficientOmit< + AllHTMLAttributes, + keyof BaseAsProps + > & + ([DefaultProps] extends [never] ? {} : Intergalactic.InternalTypings.MappedDefaultProps) >; } @@ -119,6 +144,24 @@ export namespace Intergalactic { /** @private */ // eslint-disable-next-line @typescript-eslint/no-namespace export namespace InternalTypings { + type StripDefaultPrefix = K extends `default${infer Rest}` ? Uncapitalize : K; + + export type ValidDefaultProps = { + [K in keyof DefaultProps]: K extends keyof MergedProps + ? MergedProps[K] + : StripDefaultPrefix extends keyof MergedProps + ? MergedProps[StripDefaultPrefix] + : never; + }; + + export type MappedDefaultProps = { + [K in keyof DefaultProps as StripDefaultPrefix]: K extends keyof MergedProps + ? Required[K] + : StripDefaultPrefix extends keyof MergedProps + ? Required[StripDefaultPrefix] + : never; + }; + type MergeChildProps = { [K in keyof Root | keyof Component]: K extends keyof Root diff --git a/semcore/core/src/coreFactory.tsx b/semcore/core/src/coreFactory.tsx index 46bb6fbb94..a848b1adf1 100644 --- a/semcore/core/src/coreFactory.tsx +++ b/semcore/core/src/coreFactory.tsx @@ -1,7 +1,8 @@ import hoistNonReactStatics from 'hoist-non-react-statics'; import React from 'react'; -import { type Intergalactic, Component } from './core-types/Component'; +import type { IComponent, Intergalactic } from './core-types/Component'; +import { Component } from './core-types/Component'; import { CONTEXT_COMPONENT, CORE_AS_PROPS, @@ -281,17 +282,30 @@ export function assignProps(p1: any, p2: any) { return _assignProps(p2, p1); } -function createComponent = never[]>( - OriginComponent: any, +type ClassComponent = new (...args: any[]) => Component; +type FunctionComponent = React.FunctionComponent; + +type OriginComponent = + OC extends FunctionComponent + ? FunctionComponent + : OC extends ClassComponent + ? IComponent> + : never; + +function createComponent< + C = never, + OC extends ClassComponent | FunctionComponent = never, +>( + OriginComponent: OriginComponent, childComponents: any = {}, options: { - context?: React.Context; + context?: React.Context; parent?: Intergalactic.Component | Intergalactic.Component[]; enhancements?: [any]; } = {}, -): Intergalactic.Component { +): C { const { - context = React.createContext({} as ContextType), + context = React.createContext({}), parent = [], enhancements = [], } = options; @@ -341,29 +355,35 @@ function createComponent(_OriginComponent, _childComponents, _options); }; Component.newInstance = function ( _OriginComponent = OriginComponent, _childComponents = childComponents, _options = options, ) { - return createComponent(_OriginComponent, _childComponents, _options); + return createComponent(_OriginComponent, _childComponents, _options); }; Component[CORE_COMPONENT] = true; return Component; } -function createBaseComponent(OriginComponent: React.ForwardRefRenderFunction, P>) { - const Component = React.forwardRef, P>(OriginComponent) as unknown as Intergalactic.Component; +function createBaseComponent< + C = never, + OC extends React.ForwardRefRenderFunction = never, + OCRef = OC extends React.ForwardRefRenderFunction ? Ref : never, + OCProps = OC extends React.ForwardRefRenderFunction ? Props : never, +>(OriginComponent: React.ForwardRefRenderFunction): C { + const Component = React.forwardRef(OriginComponent); Component.displayName = OriginComponent.displayName ?? ''; - // @ts-ignore Component.defaultProps = { + // @ts-ignore 'data-ui-name': OriginComponent.displayName, }; + // @ts-ignore Component[CORE_COMPONENT] = true; - return Component; + return Component as C; } export { createComponent, createBaseComponent }; diff --git a/semcore/counter/package.json b/semcore/counter/package.json index 61400d444b..ff15eba8db 100644 --- a/semcore/counter/package.json +++ b/semcore/counter/package.json @@ -9,7 +9,7 @@ "sideEffects": false, "license": "MIT", "scripts": { - "build": "pnpm semcore-builder --source=js && pnpm vite build" + "build": "pnpm semcore-builder && pnpm vite build" }, "exports": { "types": "./lib/types/index.d.ts", diff --git a/semcore/counter/src/AnimatedNumber.tsx b/semcore/counter/src/AnimatedNumber.tsx index b73bbf1dce..999137ea13 100644 --- a/semcore/counter/src/AnimatedNumber.tsx +++ b/semcore/counter/src/AnimatedNumber.tsx @@ -1,9 +1,8 @@ -import type { Intergalactic } from '@semcore/core'; import useEnhancedEffect from '@semcore/core/lib/utils/use/useEnhancedEffect'; import { useCssVariable } from '@semcore/core/lib/utils/useCssVariable'; import React from 'react'; -import type { AnimatedNumberBaseProps } from './index'; +import type { NSAnimatedNumber } from './AnimatedNumber.type'; const easeInOutSine = (t: number) => -(Math.cos(Math.PI * t) - 1) / 2; const defaultFormatValue = (value: number) => value.toFixed(2); @@ -62,4 +61,4 @@ export const AnimatedNumber = ((props) => { {formatValue(value)} ); -}) as Intergalactic.Component<'div', AnimatedNumberBaseProps>; +}) as NSAnimatedNumber.Component; diff --git a/semcore/counter/src/AnimatedNumber.type.ts b/semcore/counter/src/AnimatedNumber.type.ts new file mode 100644 index 0000000000..33a89dcd1d --- /dev/null +++ b/semcore/counter/src/AnimatedNumber.type.ts @@ -0,0 +1,34 @@ +import type { Intergalactic } from '@semcore/core'; + +declare namespace NSAnimatedNumber { + type Props = { + /** Animates number change, receives value between 0 and 1 and returns value in range from 0 to 1, e.g. for linear easing pass (t) => t */ + easing?: (t: number) => number; + /** Stringify number, receives a fraction value */ + formatValue?: (value: number) => string; + /** + * Duration time in ms + * @default 200 + * */ + duration?: number; + /** + * Delay before animation in ms + * @default 0 + * */ + delay?: number; + /** + * The value from which to start the animation + * @default 0 + * */ + initValue?: number; + /** The value by which to end the animation */ + value: number; + }; + + type Component = Intergalactic.Component<'div', Props>; +} + +/** @deprecated It will be removed in v18. */ +export type AnimatedNumberBaseProps = NSAnimatedNumber.Props; + +export type { NSAnimatedNumber }; diff --git a/semcore/counter/src/Counter.tsx b/semcore/counter/src/Counter.tsx index 538a3cbf8f..58d3b9b101 100644 --- a/semcore/counter/src/Counter.tsx +++ b/semcore/counter/src/Counter.tsx @@ -1,14 +1,22 @@ import { Box } from '@semcore/base-components'; +import type { Intergalactic } from '@semcore/core'; import { createComponent, Component, sstyled, Root } from '@semcore/core'; import resolveColorEnhance from '@semcore/core/lib/utils/enhances/resolveColorEnhance'; import React from 'react'; -import type { CounterProps } from './index'; +import type { NSCounter } from './Counter.type'; import style from './style/counter.shadow.css'; const enhance = [resolveColorEnhance()] as const; -class Counter extends Component { +class Counter extends Component< + Intergalactic.InternalTypings.InferComponentProps, + typeof enhance, + {}, + {}, + {}, + NSCounter.DefaultProps +> { static displayName = 'Counter'; static enhance = enhance; @@ -16,7 +24,7 @@ class Counter extends Component { static defaultProps = { size: 's', - }; + } as const; render() { const SCounter = Root; @@ -35,5 +43,7 @@ class Counter extends Component { } } -export default createComponent(Counter); -export * from './AnimatedNumber'; +export default createComponent< + NSCounter.Component, + typeof Counter +>(Counter); diff --git a/semcore/counter/src/Counter.type.ts b/semcore/counter/src/Counter.type.ts new file mode 100644 index 0000000000..40dd080152 --- /dev/null +++ b/semcore/counter/src/Counter.type.ts @@ -0,0 +1,23 @@ +import type { BoxProps } from '@semcore/base-components'; +import type { Intergalactic } from '@semcore/core'; + +declare namespace NSCounter { + type Props = BoxProps & { + /** Counter theme or custom color */ + theme?: 'warning' | 'danger' | 'info' | string; + + /** Counter size + * @default s */ + size?: 's' | 'm' | 'l'; + }; + type DefaultProps = { + size: 's'; + }; + + type Component = Intergalactic.Component<'div', Props>; +} + +/** @deprecated It will be removed in v18. */ +export type CounterProps = NSCounter.Props; + +export type { NSCounter }; diff --git a/semcore/counter/src/index.d.ts b/semcore/counter/src/index.d.ts deleted file mode 100644 index 04c72b669e..0000000000 --- a/semcore/counter/src/index.d.ts +++ /dev/null @@ -1,41 +0,0 @@ -import type { BoxProps } from '@semcore/base-components'; -import type { Intergalactic } from '@semcore/core'; - -export type CounterProps = BoxProps & { - /** Counter theme or custom color */ - theme?: 'warning' | 'danger' | 'info' | string; - - /** Counter size - * @default s */ - size?: 's' | 'm' | 'l'; -}; - -declare const Counter: Intergalactic.Component<'div', CounterProps>; - -export type AnimatedNumberBaseProps = { - /** Animates number change, receives value between 0 and 1 and returns value in range from 0 to 1, e.g. for linear easing pass (t) => t */ - easing?: (t: number) => number; - /** Stringify number, receives a fraction value */ - formatValue?: (value: number) => string; - /** - * Duration time in ms - * @default 200 - * */ - duration?: number; - /** - * Delay before animation in ms - * @default 0 - * */ - delay?: number; - /** - * The value from which to start the animation - * @default 0 - * */ - initValue?: number; - /** The value by which to end the animation */ - value: number; -}; - -export declare const AnimatedNumber: Intergalactic.Component<'div', AnimatedNumberBaseProps>; - -export default Counter; diff --git a/semcore/counter/src/index.js b/semcore/counter/src/index.js deleted file mode 100644 index c92954926c..0000000000 --- a/semcore/counter/src/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default, AnimatedNumber } from './Counter'; diff --git a/semcore/counter/src/index.ts b/semcore/counter/src/index.ts new file mode 100644 index 0000000000..832ad3bf2d --- /dev/null +++ b/semcore/counter/src/index.ts @@ -0,0 +1,5 @@ +export { default } from './Counter'; +export { AnimatedNumber } from './AnimatedNumber'; + +export * from './AnimatedNumber.type'; +export * from './Counter.type'; diff --git a/semcore/counter/vite.config.ts b/semcore/counter/vite.config.ts index 0991a16528..90f46b4cb2 100644 --- a/semcore/counter/vite.config.ts +++ b/semcore/counter/vite.config.ts @@ -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\/*/], diff --git a/semcore/d3-chart/src/component/Chart/AbstractChart.tsx b/semcore/d3-chart/src/component/Chart/AbstractChart.tsx index 53751899c6..621bcbbe08 100644 --- a/semcore/d3-chart/src/component/Chart/AbstractChart.tsx +++ b/semcore/d3-chart/src/component/Chart/AbstractChart.tsx @@ -1,4 +1,5 @@ import { Flex, Box } from '@semcore/base-components'; +import type { Intergalactic } from '@semcore/core'; import { Component, Root, sstyled } from '@semcore/core'; import { extractAriaProps } from '@semcore/core/lib/utils/ariaProps'; import { callAllEventHandlers } from '@semcore/core/lib/utils/assignProps'; @@ -31,16 +32,11 @@ export abstract class AbstractChart< Data extends ListData | ObjectData, Props extends BaseChartProps, Enhancers extends readonly ((...args: any[]) => any)[] = [], - DefaultProps = {}, + InnerProps = {}, State extends ChartState = ChartState, -> extends Component, DefaultProps, State> { + DefaultProps extends Intergalactic.InternalTypings.ValidDefaultProps = never, +> extends Component, InnerProps, State, DefaultProps> { public static style = style; - public static defaultProps: Partial> = { - direction: 'column', - showXAxis: true, - showYAxis: true, - showTooltip: true, - }; /** * Padding from the end's of chart to the container (except axis sides) diff --git a/semcore/d3-chart/src/component/Chart/AreaChart.tsx b/semcore/d3-chart/src/component/Chart/AreaChart.tsx index baf4e18ab0..f1d895ed52 100644 --- a/semcore/d3-chart/src/component/Chart/AreaChart.tsx +++ b/semcore/d3-chart/src/component/Chart/AreaChart.tsx @@ -1,4 +1,3 @@ -import { Flex, Box } from '@semcore/base-components'; import { createComponent } from '@semcore/core'; import i18nEnhance from '@semcore/core/lib/utils/enhances/i18nEnhance'; import { type ScaleLinear, scaleLinear, scaleTime } from 'd3-scale'; @@ -6,19 +5,30 @@ import React from 'react'; // @ts-ignore import { Area, minMax, HoverLine, StackedArea } from '../..'; +import type { ChartState } from './AbstractChart'; import { AbstractChart } from './AbstractChart'; -import type { AreaChartData, AreaChartProps, AreaChartType } from './AreaChart.type'; +import type { AreaChartData, AreaChartProps, AreaChartType, AreaChartDefaultProps } from './AreaChart.type'; import { localizedMessages } from '../../translations/__intergalactic-dynamic-locales'; class AreaChartComponent extends AbstractChart< AreaChartData, AreaChartProps, - typeof AreaChartComponent.enhance + typeof AreaChartComponent.enhance, + {}, + ChartState, + AreaChartDefaultProps > { static displayName = 'Chart.Area'; static enhance = [i18nEnhance(localizedMessages)] as const; + static defaultProps = { + direction: 'column', + showXAxis: true, + showYAxis: true, + showTooltip: true, + } as const; + get xScale() { const { xScale, marginY = 40, plotWidth, data, groupKey } = this.asProps; @@ -124,4 +134,7 @@ class AreaChartComponent extends AbstractChart< } } -export const AreaChart: AreaChartType = createComponent(AreaChartComponent); +export const AreaChart = createComponent< + AreaChartType, + typeof AreaChartComponent +>(AreaChartComponent); diff --git a/semcore/d3-chart/src/component/Chart/AreaChart.type.ts b/semcore/d3-chart/src/component/Chart/AreaChart.type.ts index d29d676cf6..edec722ed7 100644 --- a/semcore/d3-chart/src/component/Chart/AreaChart.type.ts +++ b/semcore/d3-chart/src/component/Chart/AreaChart.type.ts @@ -25,4 +25,11 @@ export type AreaChartProps = BaseChartProps & { onClickArea?: (index: number, event: React.SyntheticEvent) => void; }; +export type AreaChartDefaultProps = { + direction: 'column'; + showXAxis: true; + showYAxis: true; + showTooltip: true; +}; + export type AreaChartType = Intergalactic.Component & { showLegend?: boolean } & AriaNameProps>; diff --git a/semcore/d3-chart/src/component/Chart/BarChart.tsx b/semcore/d3-chart/src/component/Chart/BarChart.tsx index 7b0721c677..9854ed090a 100644 --- a/semcore/d3-chart/src/component/Chart/BarChart.tsx +++ b/semcore/d3-chart/src/component/Chart/BarChart.tsx @@ -3,9 +3,10 @@ import i18nEnhance from '@semcore/core/lib/utils/enhances/i18nEnhance'; import { scaleBand, scaleLinear, scaleTime } from 'd3-scale'; import React from 'react'; +import type { ChartState } from './AbstractChart'; import { AbstractChart } from './AbstractChart'; import type { BaseLegendProps } from './AbstractChart.type'; -import type { BarChartData, BarChartProps, BarChartType } from './BarChart.type'; +import type { BarChartData, BarChartProps, BarChartType, BarChartDefaultProps } from './BarChart.type'; // @ts-ignore import { minMax, GroupBar, HoverRect, StackBar, Line, YAxis, XAxis } from '../..'; import { localizedMessages } from '../../translations/__intergalactic-dynamic-locales'; @@ -15,12 +16,22 @@ import type { LegendItemKey } from '../ChartLegend/LegendItem/LegendItem.type'; class BarChartComponent extends AbstractChart< BarChartData, BarChartProps, - typeof BarChartComponent.enhance + typeof BarChartComponent.enhance, + {}, + ChartState, + BarChartDefaultProps > { static displayName = 'Chart.Bar'; static enhance = [i18nEnhance(localizedMessages)] as const; + static defaultProps = { + direction: 'column', + showXAxis: true, + showYAxis: true, + showTooltip: true, + } as const; + get xScale() { const { xScale, invertAxis } = this.asProps; @@ -294,4 +305,7 @@ class BarChartComponent extends AbstractChart< } } -export const BarChart: BarChartType = createComponent(BarChartComponent); +export const BarChart = createComponent< + BarChartType, + typeof BarChartComponent +>(BarChartComponent); diff --git a/semcore/d3-chart/src/component/Chart/BarChart.type.ts b/semcore/d3-chart/src/component/Chart/BarChart.type.ts index fdc14295e3..68f20b2935 100644 --- a/semcore/d3-chart/src/component/Chart/BarChart.type.ts +++ b/semcore/d3-chart/src/component/Chart/BarChart.type.ts @@ -32,4 +32,11 @@ export type BarChartProps = BaseChartProps & { onClickBar?: (barItem: number, barKey: BarKey, e: React.SyntheticEvent) => void; }; +export type BarChartDefaultProps = { + direction: 'column'; + showXAxis: true; + showYAxis: true; + showTooltip: true; +}; + export type BarChartType = Intergalactic.Component; diff --git a/semcore/d3-chart/src/component/Chart/BubbleChart.tsx b/semcore/d3-chart/src/component/Chart/BubbleChart.tsx index c58612130d..26190b3c2c 100644 --- a/semcore/d3-chart/src/component/Chart/BubbleChart.tsx +++ b/semcore/d3-chart/src/component/Chart/BubbleChart.tsx @@ -6,20 +6,31 @@ import React from 'react'; // @ts-ignore import { Bubble, calculateBubbleDomain } from '../..'; +import type { ChartState } from './AbstractChart'; import { AbstractChart } from './AbstractChart'; -import type { BubbleChartData, BubbleChartProps, BubbleChartType } from './BubbleChart.type'; +import type { BubbleChartData, BubbleChartProps, BubbleChartType, BubbleChartDefaultProps } from './BubbleChart.type'; import { localizedMessages } from '../../translations/__intergalactic-dynamic-locales'; import type { LegendItem } from '../ChartLegend/LegendItem/LegendItem.type'; class BubbleChartComponent extends AbstractChart< BubbleChartData, BubbleChartProps, - typeof BubbleChartComponent.enhance + typeof BubbleChartComponent.enhance, + {}, + ChartState, + BubbleChartDefaultProps > { static displayName = 'Chart.Bubble'; static enhance = [i18nEnhance(localizedMessages)] as const; + static defaultProps = { + direction: 'column', + showXAxis: true, + showYAxis: true, + showTooltip: true, + } as const; + protected get dataKeys(): string[] { const { data } = this.props; @@ -141,4 +152,7 @@ class BubbleChartComponent extends AbstractChart< } } -export const BubbleChart: BubbleChartType = createComponent(BubbleChartComponent); +export const BubbleChart = createComponent< + BubbleChartType, + typeof BubbleChartComponent +>(BubbleChartComponent); diff --git a/semcore/d3-chart/src/component/Chart/BubbleChart.type.ts b/semcore/d3-chart/src/component/Chart/BubbleChart.type.ts index d31a916c49..3561b2ebf1 100644 --- a/semcore/d3-chart/src/component/Chart/BubbleChart.type.ts +++ b/semcore/d3-chart/src/component/Chart/BubbleChart.type.ts @@ -31,4 +31,11 @@ export type BubbleChartProps = Intergalactic.InternalTypings.EfficientOmit< onClickBubble?: (index: number, event: React.SyntheticEvent) => void; }; +export type BubbleChartDefaultProps = { + direction: 'column'; + showXAxis: true; + showYAxis: true; + showTooltip: true; +}; + export type BubbleChartType = Intergalactic.Component; diff --git a/semcore/d3-chart/src/component/Chart/CigaretteChart.tsx b/semcore/d3-chart/src/component/Chart/CigaretteChart.tsx index 95b8425f40..b3a5f63f77 100644 --- a/semcore/d3-chart/src/component/Chart/CigaretteChart.tsx +++ b/semcore/d3-chart/src/component/Chart/CigaretteChart.tsx @@ -9,7 +9,7 @@ import { Text } from '@semcore/typography'; import { scaleThreshold, scaleLinear, scaleBand } from 'd3-scale'; import React from 'react'; -import type { CigaretteChartData, CigaretteChartDataKey, CigaretteChartProps, CigaretteChartType } from './CigaretteChart.type'; +import type { CigaretteChartData, CigaretteChartDataKey, CigaretteChartDefaultProps, CigaretteChartProps, CigaretteChartType } from './CigaretteChart.type'; // @ts-ignore import { HoverRect, Plot } from '../..'; import type { ChartState } from './AbstractChart'; @@ -36,15 +36,16 @@ class CigaretteChartComponent extends AbstractChart< CigaretteChartData, CigaretteChartProps, typeof CigaretteChartComponent.enhance, - typeof CigaretteChartComponent.defaultProps, - CigaretteChartState + {}, + CigaretteChartState, + CigaretteChartDefaultProps > { static displayName = 'Cigarette.Bar'; - static defaultProps: any = (props: CigaretteChartProps) => { + static defaultProps = (props: CigaretteChartProps) => { const invertAxis = props.invertAxis ?? true; return { - invertAxis: invertAxis, + invertAxis, showXAxis: false, showYAxis: false, showTooltip: true, @@ -56,7 +57,7 @@ class CigaretteChartComponent extends AbstractChart< plotHeight: invertAxis && !props.plotHeight ? 28 : props.plotHeight, showPercentValueInTooltip: false, minimalBarWidth: DEFAULT_MINIMAL_BAR_WIDTH, - }; + } as const; }; static enhance = [ @@ -124,11 +125,11 @@ class CigaretteChartComponent extends AbstractChart< const [pX, pY] = eventToPoint(event, this.plotRef.current); - this.setState((prevState) => ({ pX, pY })); + this.setState(() => ({ pX, pY })); }); private onPlotMouseLeave = trottle(() => { - this.setState((prevState) => ({ pX: null, pY: null })); + this.setState(() => ({ pX: null, pY: null })); }); protected override totalValue() { @@ -506,4 +507,7 @@ class CigaretteChartComponent extends AbstractChart< } } -export const CigaretteChart: CigaretteChartType = createComponent(CigaretteChartComponent); +export const CigaretteChart = createComponent< + CigaretteChartType, + typeof CigaretteChartComponent +>(CigaretteChartComponent); diff --git a/semcore/d3-chart/src/component/Chart/CigaretteChart.type.ts b/semcore/d3-chart/src/component/Chart/CigaretteChart.type.ts index bcae874b09..01f016423a 100644 --- a/semcore/d3-chart/src/component/Chart/CigaretteChart.type.ts +++ b/semcore/d3-chart/src/component/Chart/CigaretteChart.type.ts @@ -30,4 +30,19 @@ export type CigaretteChartProps = Intergalactic.InternalTypings.EfficientOmit< minimalBarWidth?: number; }; +export type CigaretteChartDefaultProps = { + invertAxis: CigaretteChartProps['invertAxis']; + showXAxis: false; + showYAxis: false; + showTooltip: true; + showLegend: false; + marginX: 0; + marginY: 0; + duration: 500; + plotWidth: CigaretteChartProps['plotWidth']; + plotHeight: CigaretteChartProps['plotHeight']; + showPercentValueInTooltip: false; + minimalBarWidth: 2; +}; + export type CigaretteChartType = Intergalactic.Component<'div', CigaretteChartProps>; diff --git a/semcore/d3-chart/src/component/Chart/CompactHorizontalBarChart.tsx b/semcore/d3-chart/src/component/Chart/CompactHorizontalBarChart.tsx index a3109d2f53..c2f48f41c8 100644 --- a/semcore/d3-chart/src/component/Chart/CompactHorizontalBarChart.tsx +++ b/semcore/d3-chart/src/component/Chart/CompactHorizontalBarChart.tsx @@ -3,30 +3,35 @@ import i18nEnhance from '@semcore/core/lib/utils/enhances/i18nEnhance'; import { scaleBand, scaleLinear } from 'd3-scale'; import React from 'react'; -import type { BaseChartProps, BaseLegendProps } from './AbstractChart.type'; +import type { ChartState } from './AbstractChart'; +import { AbstractChart } from './AbstractChart'; +import type { BaseLegendProps } from './AbstractChart.type'; import type { CompactHorizontalBarChartData, + CompactHorizontalBarChartDefaultProps, CompactHorizontalBarChartProps, CompactHorizontalBarChartType, } from './CompactHorizontalBarChart.type'; // @ts-ignore import { CompactHorizontalBar } from '../..'; -import { AbstractChart } from './AbstractChart'; import { localizedMessages } from '../../translations/__intergalactic-dynamic-locales'; class CompactHorizontalBarChartComponent extends AbstractChart< CompactHorizontalBarChartData, CompactHorizontalBarChartProps, - typeof CompactHorizontalBarChartComponent.enhance + typeof CompactHorizontalBarChartComponent.enhance, + {}, + ChartState, + CompactHorizontalBarChartDefaultProps > { static displayName = 'Chart.CompactHorizontalBar'; - public static defaultProps: Partial> = { + public static defaultProps = { direction: 'column', showXAxis: false, showYAxis: false, showTooltip: true, showLegend: false, - }; + } as const; static enhance = [i18nEnhance(localizedMessages)] as const; @@ -117,6 +122,9 @@ class CompactHorizontalBarChartComponent extends AbstractChart< } } -export const CompactHorizontalBarChart: CompactHorizontalBarChartType = createComponent( +export const CompactHorizontalBarChart = createComponent< + CompactHorizontalBarChartType, + typeof CompactHorizontalBarChartComponent +>( CompactHorizontalBarChartComponent, ); diff --git a/semcore/d3-chart/src/component/Chart/CompactHorizontalBarChart.type.ts b/semcore/d3-chart/src/component/Chart/CompactHorizontalBarChart.type.ts index 5936be9a09..12e0850fa5 100644 --- a/semcore/d3-chart/src/component/Chart/CompactHorizontalBarChart.type.ts +++ b/semcore/d3-chart/src/component/Chart/CompactHorizontalBarChart.type.ts @@ -29,6 +29,14 @@ export type CompactHorizontalBarChartProps = Intergalactic.InternalTypings.Effic onClickBar?: (barItem: number, e: React.SyntheticEvent) => void; }; +export type CompactHorizontalBarChartDefaultProps = { + direction: 'column'; + showXAxis: false; + showYAxis: false; + showTooltip: true; + showLegend: false; +}; + export type CompactHorizontalBarChartType = Intergalactic.Component< typeof Flex, CompactHorizontalBarChartProps diff --git a/semcore/d3-chart/src/component/Chart/DonutChart.tsx b/semcore/d3-chart/src/component/Chart/DonutChart.tsx index 0cf8477480..d9fdadc917 100644 --- a/semcore/d3-chart/src/component/Chart/DonutChart.tsx +++ b/semcore/d3-chart/src/component/Chart/DonutChart.tsx @@ -7,23 +7,27 @@ import React from 'react'; // @ts-ignore import { Donut } from '../..'; +import type { ChartState } from './AbstractChart'; import { AbstractChart } from './AbstractChart'; -import type { DonutChartData, DonutChartProps, DonutChartType } from './DonutChart.type'; +import type { DonutChartData, DonutChartDefaultProps, DonutChartProps, DonutChartType } from './DonutChart.type'; import { localizedMessages } from '../../translations/__intergalactic-dynamic-locales'; class DonutChartComponent extends AbstractChart< DonutChartData, DonutChartProps, - typeof DonutChartComponent.enhance + typeof DonutChartComponent.enhance, + {}, + ChartState, + DonutChartDefaultProps > { static displayName = 'Chart.Donut'; - static defaultProps: Partial = { + static defaultProps = { direction: 'row-reverse', alignItems: 'flex-start', innerRadius: 100, marginX: 0, marginY: 0, - }; + } as const; static enhance = [i18nEnhance(localizedMessages)] as const; @@ -107,4 +111,7 @@ class DonutChartComponent extends AbstractChart< } } -export const DonutChart: DonutChartType = createComponent(DonutChartComponent); +export const DonutChart = createComponent< + DonutChartType, + typeof DonutChartComponent +>(DonutChartComponent); diff --git a/semcore/d3-chart/src/component/Chart/DonutChart.type.ts b/semcore/d3-chart/src/component/Chart/DonutChart.type.ts index 65109d8103..d12edad65d 100644 --- a/semcore/d3-chart/src/component/Chart/DonutChart.type.ts +++ b/semcore/d3-chart/src/component/Chart/DonutChart.type.ts @@ -29,4 +29,12 @@ export type DonutChartProps = Intergalactic.InternalTypings.EfficientOmit< onClickPie?: (key: DataKey, e: React.SyntheticEvent) => void; }; +export type DonutChartDefaultProps = { + direction: 'row-reverse'; + alignItems: 'flex-start'; + innerRadius: 100; + marginX: 0; + marginY: 0; +}; + export type DonutChartType = Intergalactic.Component; diff --git a/semcore/d3-chart/src/component/Chart/HistogramChart.tsx b/semcore/d3-chart/src/component/Chart/HistogramChart.tsx index 687dfa6984..32820ece5b 100644 --- a/semcore/d3-chart/src/component/Chart/HistogramChart.tsx +++ b/semcore/d3-chart/src/component/Chart/HistogramChart.tsx @@ -5,19 +5,30 @@ import React from 'react'; // @ts-ignore import { Bar, minMax, HoverRect, StackBar, type BarProps } from '../..'; +import type { ChartState } from './AbstractChart'; import { AbstractChart } from './AbstractChart'; -import type { HistogramChartData, HistogramChartProps, HistogramChartType } from './HistogramChart.type'; +import type { HistogramChartData, HistogramChartDefaultProps, HistogramChartProps, HistogramChartType } from './HistogramChart.type'; import { localizedMessages } from '../../translations/__intergalactic-dynamic-locales'; class HistogramChartComponent extends AbstractChart< HistogramChartData, HistogramChartProps, - typeof HistogramChartComponent.enhance + typeof HistogramChartComponent.enhance, + {}, + ChartState, + HistogramChartDefaultProps > { static displayName = 'Chart.Histogram'; static enhance = [i18nEnhance(localizedMessages)] as const; + static defaultProps = { + direction: 'column', + showXAxis: true, + showYAxis: true, + showTooltip: true, + } as const; + get xScale() { const { xScale, @@ -173,4 +184,7 @@ class HistogramChartComponent extends AbstractChart< } } -export const HistogramChart: HistogramChartType = createComponent(HistogramChartComponent); +export const HistogramChart = createComponent< + HistogramChartType, + typeof HistogramChartComponent +>(HistogramChartComponent); diff --git a/semcore/d3-chart/src/component/Chart/HistogramChart.type.ts b/semcore/d3-chart/src/component/Chart/HistogramChart.type.ts index ba1d8740b1..4e9ee2e974 100644 --- a/semcore/d3-chart/src/component/Chart/HistogramChart.type.ts +++ b/semcore/d3-chart/src/component/Chart/HistogramChart.type.ts @@ -15,4 +15,11 @@ export type HistogramChartProps = BaseChartProps & { yScale?: ScaleLinear; }; +export type HistogramChartDefaultProps = { + direction: 'column'; + showXAxis: true; + showYAxis: true; + showTooltip: true; +}; + export type HistogramChartType = Intergalactic.Component; diff --git a/semcore/d3-chart/src/component/Chart/LineChart.tsx b/semcore/d3-chart/src/component/Chart/LineChart.tsx index 461f42ecbf..bb8ed8cb5f 100644 --- a/semcore/d3-chart/src/component/Chart/LineChart.tsx +++ b/semcore/d3-chart/src/component/Chart/LineChart.tsx @@ -3,21 +3,32 @@ import i18nEnhance from '@semcore/core/lib/utils/enhances/i18nEnhance'; import { type ScaleLinear, scaleLinear, scaleTime } from 'd3-scale'; import React from 'react'; -import type { LineChartData, LineChartProps, LineChartType } from './LineChart.type'; +import type { LineChartData, LineChartDefaultProps, LineChartProps, LineChartType } from './LineChart.type'; // @ts-ignore import { Line, minMax, HoverLine } from '../..'; +import type { ChartState } from './AbstractChart'; import { AbstractChart } from './AbstractChart'; import { localizedMessages } from '../../translations/__intergalactic-dynamic-locales'; class LineChartComponent extends AbstractChart< LineChartData, LineChartProps, - typeof LineChartComponent.enhance + typeof LineChartComponent.enhance, + {}, + ChartState, + LineChartDefaultProps > { static displayName = 'Chart.Line'; static enhance = [i18nEnhance(localizedMessages)] as const; + static defaultProps = { + direction: 'column', + showXAxis: true, + showYAxis: true, + showTooltip: true, + } as const; + protected get xScale() { const { xScale, marginY = 30, plotWidth, data, groupKey } = this.asProps; @@ -103,4 +114,7 @@ class LineChartComponent extends AbstractChart< } } -export const LineChart: LineChartType = createComponent(LineChartComponent); +export const LineChart = createComponent< + LineChartType, + typeof LineChartComponent +>(LineChartComponent); diff --git a/semcore/d3-chart/src/component/Chart/LineChart.type.ts b/semcore/d3-chart/src/component/Chart/LineChart.type.ts index ea5f4f0453..c932a8cdd0 100644 --- a/semcore/d3-chart/src/component/Chart/LineChart.type.ts +++ b/semcore/d3-chart/src/component/Chart/LineChart.type.ts @@ -34,4 +34,11 @@ export type LineChartProps = BaseChartProps & { onClickLine?: (index: number, event: React.SyntheticEvent) => void; }; +export type LineChartDefaultProps = { + direction: 'column'; + showXAxis: true; + showYAxis: true; + showTooltip: true; +}; + export type LineChartType = Intergalactic.Component; diff --git a/semcore/d3-chart/src/component/Chart/RadarChart.tsx b/semcore/d3-chart/src/component/Chart/RadarChart.tsx index 29cace7f94..1f522e80c7 100644 --- a/semcore/d3-chart/src/component/Chart/RadarChart.tsx +++ b/semcore/d3-chart/src/component/Chart/RadarChart.tsx @@ -3,8 +3,9 @@ import i18nEnhance from '@semcore/core/lib/utils/enhances/i18nEnhance'; import { scaleLinear, type ScaleLinear } from 'd3-scale'; import React from 'react'; +import type { ChartState } from './AbstractChart'; import { AbstractChart } from './AbstractChart'; -import type { RadarChartData, RadarChartProps, RadarChartType } from './RadarChart.type'; +import type { RadarChartData, RadarChartDefaultProps, RadarChartProps, RadarChartType } from './RadarChart.type'; // @ts-ignore import { Radar } from '../..'; import { localizedMessages } from '../../translations/__intergalactic-dynamic-locales'; @@ -12,10 +13,20 @@ import { localizedMessages } from '../../translations/__intergalactic-dynamic-lo class RadarChartComponent extends AbstractChart< RadarChartData, RadarChartProps, - typeof RadarChartComponent.enhance + typeof RadarChartComponent.enhance, + {}, + ChartState, + RadarChartDefaultProps > { static enhance = [i18nEnhance(localizedMessages)] as const; + static defaultProps = { + direction: 'column', + showXAxis: true, + showYAxis: true, + showTooltip: true, + } as const; + protected renderChart(): React.ReactNode { const { groupKey, showDots, circle, onClickRadar } = this.asProps; const { dataDefinitions } = this.state; @@ -107,4 +118,7 @@ class RadarChartComponent extends AbstractChart< } } -export const RadarChart: RadarChartType = createComponent(RadarChartComponent); +export const RadarChart: RadarChartType = createComponent< + RadarChartType, + typeof RadarChartComponent +>(RadarChartComponent); diff --git a/semcore/d3-chart/src/component/Chart/RadarChart.type.ts b/semcore/d3-chart/src/component/Chart/RadarChart.type.ts index 85bac81fc7..2d5746106e 100644 --- a/semcore/d3-chart/src/component/Chart/RadarChart.type.ts +++ b/semcore/d3-chart/src/component/Chart/RadarChart.type.ts @@ -20,4 +20,11 @@ export type RadarChartProps = Intergalactic.InternalTypings.EfficientOmit< onClickRadar?: (index: number, e: React.SyntheticEvent) => void; }; +export type RadarChartDefaultProps = { + direction: 'column'; + showXAxis: true; + showYAxis: true; + showTooltip: true; +}; + export type RadarChartType = Intergalactic.Component; diff --git a/semcore/d3-chart/src/component/Chart/ScatterPlotChart.tsx b/semcore/d3-chart/src/component/Chart/ScatterPlotChart.tsx index 0915337949..0c0800e780 100644 --- a/semcore/d3-chart/src/component/Chart/ScatterPlotChart.tsx +++ b/semcore/d3-chart/src/component/Chart/ScatterPlotChart.tsx @@ -6,10 +6,11 @@ import React from 'react'; // @ts-ignore import { minMax, ScatterPlot, getScatterPlotRadius } from '../..'; +import type { ChartState } from './AbstractChart'; import { AbstractChart } from './AbstractChart'; -import type { BaseChartProps, ListData } from './AbstractChart.type'; import type { ScatterPlotChartData, + ScatterPlotChartDefaultProps, ScatterPlotChartProps, ScatterPlotChartType, } from './ScatterPlotChart.type'; @@ -18,16 +19,19 @@ import { localizedMessages } from '../../translations/__intergalactic-dynamic-lo class ScatterPlotChartComponent extends AbstractChart< ScatterPlotChartData, ScatterPlotChartProps, - typeof ScatterPlotChartComponent.enhance + typeof ScatterPlotChartComponent.enhance, + {}, + ChartState, + ScatterPlotChartDefaultProps > { static displayName = 'Chart.ScatterPlot'; - public static defaultProps: Partial> = { + public static defaultProps = { direction: 'column', showXAxis: true, showYAxis: true, showTooltip: true, showLegend: false, - }; + } as const; static enhance = [i18nEnhance(localizedMessages)] as const; @@ -139,4 +143,7 @@ class ScatterPlotChartComponent extends AbstractChart< } } -export const ScatterPlotChart: ScatterPlotChartType = createComponent(ScatterPlotChartComponent); +export const ScatterPlotChart = createComponent< + ScatterPlotChartType, + typeof ScatterPlotChartComponent +>(ScatterPlotChartComponent); diff --git a/semcore/d3-chart/src/component/Chart/ScatterPlotChart.type.ts b/semcore/d3-chart/src/component/Chart/ScatterPlotChart.type.ts index 6e13ecc24c..ab57525a9e 100644 --- a/semcore/d3-chart/src/component/Chart/ScatterPlotChart.type.ts +++ b/semcore/d3-chart/src/component/Chart/ScatterPlotChart.type.ts @@ -23,4 +23,12 @@ export type ScatterPlotChartProps = Intergalactic.InternalTypings.EfficientOmit< onClickScatterItem?: (index: number, event: React.SyntheticEvent) => void; }; +export type ScatterPlotChartDefaultProps = { + direction: 'column'; + showXAxis: true; + showYAxis: true; + showTooltip: true; + showLegend: false; +}; + export type ScatterPlotChartType = Intergalactic.Component; diff --git a/semcore/d3-chart/src/component/Chart/VennChart.tsx b/semcore/d3-chart/src/component/Chart/VennChart.tsx index e7c063ad42..c842413fe9 100644 --- a/semcore/d3-chart/src/component/Chart/VennChart.tsx +++ b/semcore/d3-chart/src/component/Chart/VennChart.tsx @@ -4,27 +4,30 @@ import { Text } from '@semcore/typography'; import { scaleLinear } from 'd3-scale'; import React from 'react'; -import type { BaseChartProps } from './AbstractChart.type'; // @ts-ignore import { Venn } from '../..'; +import type { ChartState } from './AbstractChart'; import { AbstractChart } from './AbstractChart'; -import type { VennChartData, VennChartProps, VennChartType } from './VennChart.type'; +import type { VennChartData, VennChartDefaultProps, VennChartProps, VennChartType } from './VennChart.type'; import { localizedMessages } from '../../translations/__intergalactic-dynamic-locales'; import type { LegendItem } from '../ChartLegend/LegendItem/LegendItem.type'; class VennChartComponent extends AbstractChart< VennChartData, VennChartProps, - typeof VennChartComponent.enhance + typeof VennChartComponent.enhance, + {}, + ChartState, + VennChartDefaultProps > { static displayName = 'Chart.Venn'; - static defaultProps: Partial> = { + static defaultProps = { direction: 'row-reverse', alignItems: 'flex-start', marginY: 0, marginX: 0, - }; + } as const; static enhance = [i18nEnhance(localizedMessages)] as const; @@ -149,4 +152,7 @@ class VennChartComponent extends AbstractChart< } } -export const VennChart: VennChartType = createComponent(VennChartComponent); +export const VennChart = createComponent< + VennChartType, + typeof VennChartComponent +>(VennChartComponent); diff --git a/semcore/d3-chart/src/component/Chart/VennChart.type.ts b/semcore/d3-chart/src/component/Chart/VennChart.type.ts index 5fa1f2bc13..e8166752db 100644 --- a/semcore/d3-chart/src/component/Chart/VennChart.type.ts +++ b/semcore/d3-chart/src/component/Chart/VennChart.type.ts @@ -22,4 +22,11 @@ export type VennChartProps = Intergalactic.InternalTypings.EfficientOmit< onClickVennItem?: (key: DataKey, e: React.SyntheticEvent) => void; }; +export type VennChartDefaultProps = { + direction: 'row-reverse'; + alignItems: 'flex-start'; + marginY: 0; + marginX: 0; +}; + export type VennChartType = Intergalactic.Component; diff --git a/semcore/d3-chart/src/component/ChartLegend/BaseLegend.tsx b/semcore/d3-chart/src/component/ChartLegend/BaseLegend.tsx index 3e806fce2e..9ec2cdff53 100644 --- a/semcore/d3-chart/src/component/ChartLegend/BaseLegend.tsx +++ b/semcore/d3-chart/src/component/ChartLegend/BaseLegend.tsx @@ -2,15 +2,19 @@ import { Component, type Intergalactic } from '@semcore/core'; import type React from 'react'; import type { LegendProps } from './BaseLegend.type'; -import { StaticShapes, type LegendItemKey, type LegendItemProps, type ShapeType } from './LegendItem/LegendItem.type'; +import { type LegendItemKey, type LegendItemProps, type ShapeType } from './LegendItem/LegendItem.type'; import { makeDataHintsHandlers } from '../../a11y/hints'; -export abstract class BaseLegend any)[] = never[]> extends Component { +export abstract class BaseLegend< + P extends LegendProps, + E extends readonly ((...args: any[]) => any)[] = never[], + DP extends Intergalactic.InternalTypings.ValidDefaultProps = never, +> extends Component { componentDidMount() { this.setHints(); } - componentDidUpdate(prevProps: T) { + componentDidUpdate(prevProps: P) { if (prevProps.items !== this.props.items || prevProps.dataHints !== this.props.dataHints) { this.setHints(); } diff --git a/semcore/d3-chart/src/component/ChartLegend/LegendFlex/LegendFlex.tsx b/semcore/d3-chart/src/component/ChartLegend/LegendFlex/LegendFlex.tsx index dd26aa0493..2593288582 100644 --- a/semcore/d3-chart/src/component/ChartLegend/LegendFlex/LegendFlex.tsx +++ b/semcore/d3-chart/src/component/ChartLegend/LegendFlex/LegendFlex.tsx @@ -6,12 +6,16 @@ import Divider from '@semcore/divider'; import React from 'react'; import style from './legend-flex.shadow.css'; -import type { LegendFlexType, LegendFlexProps, TrendProps } from './LegendFlex.type'; +import type { LegendFlexType, LegendFlexProps, TrendProps, LegendFlexDefaultProps } from './LegendFlex.type'; import { localizedMessages } from '../../../translations/__intergalactic-dynamic-locales'; import { BaseLegend } from '../BaseLegend'; import { LegendItemComponent } from '../LegendItem/LegendItem'; -class LegendFlexRoot extends BaseLegend { +class LegendFlexRoot extends BaseLegend< + LegendFlexProps, + typeof LegendFlexRoot.enhance, + LegendFlexDefaultProps +> { static displayName = 'LegendFlex'; static style = style; @@ -20,7 +24,7 @@ class LegendFlexRoot extends BaseLegend ({ direction: 'row', children: , - }); + } as const); renderTrend() { const { onTrendIsVisibleChange, trendIsVisible, trendLabel, size, getI18nText } = this @@ -55,6 +59,9 @@ class LegendFlexRoot extends BaseLegend(LegendFlexRoot, { LegendItem: LegendItemComponent, -}) as LegendFlexType; +}); diff --git a/semcore/d3-chart/src/component/ChartLegend/LegendFlex/LegendFlex.type.ts b/semcore/d3-chart/src/component/ChartLegend/LegendFlex/LegendFlex.type.ts index 427d11c6a5..64571ee9d2 100644 --- a/semcore/d3-chart/src/component/ChartLegend/LegendFlex/LegendFlex.type.ts +++ b/semcore/d3-chart/src/component/ChartLegend/LegendFlex/LegendFlex.type.ts @@ -34,6 +34,11 @@ type AddonProps = ({ withTrend?: never } & SuffixProps) | ({ suffix?: never } & export type LegendFlexProps = LegendProps & AddonProps & FlexProps; +export type LegendFlexDefaultProps = { + direction: 'row'; + children: React.JSX.Element; +}; + export type LegendFlexType = Intergalactic.Component & { LegendItem: LegendItemType; }; diff --git a/semcore/d3-chart/src/component/ChartLegend/LegendItem/LegendItem.tsx b/semcore/d3-chart/src/component/ChartLegend/LegendItem/LegendItem.tsx index 7d00833d8a..4ce88c24da 100644 --- a/semcore/d3-chart/src/component/ChartLegend/LegendItem/LegendItem.tsx +++ b/semcore/d3-chart/src/component/ChartLegend/LegendItem/LegendItem.tsx @@ -1,25 +1,34 @@ import { Flex, Box } from '@semcore/base-components'; import Checkbox from '@semcore/checkbox'; -import { createComponent, Component, sstyled, Root, type IRootComponentProps } from '@semcore/core'; +import { type Intergalactic, createComponent, Component, sstyled, Root } from '@semcore/core'; import resolveColorEnhance from '@semcore/core/lib/utils/enhances/resolveColorEnhance'; import uniqueIDEnhancement from '@semcore/core/lib/utils/uniqueID'; import { Text as TypographyText } from '@semcore/typography'; -import type { DOMAttributes } from 'react'; import React from 'react'; import style from './legend-item.shadow.css'; import { - type ShapeProps, - type LegendItemProps, + type LegendItemShapeType, + type LegendItemDefaultProps, type LegendItemType, - type LegendItem, StaticShapes, + type LegendItemIconType, + type LegendItemLabelType, + type LegendItemAdditionalLabelType, + type LegendItemCountType, } from './LegendItem.type'; import { PatternSymbol } from '../../../Pattern'; import { getChartDefaultColorName } from '../../../utils'; const enhance = [resolveColorEnhance(), uniqueIDEnhancement()] as const; -class LegendItemRoot extends Component { +class LegendItemRoot extends Component< + Intergalactic.InternalTypings.InferComponentProps, + typeof enhance, + {}, + {}, + {}, + LegendItemDefaultProps +> { static displayName = 'LegendItem'; static style = style; @@ -54,37 +63,55 @@ class LegendItemRoot extends Component { patterns, size, 'onChange': (value: boolean) => { - onChangeLegendItem(id, value); + if (onChangeLegendItem && id) { + onChangeLegendItem(id, value); + } + }, + 'onFocus': () => { + if (onFocusLegendItem && id) { + onFocusLegendItem(id); + } + }, + 'onBlur': () => { + if (onBlurLegendItem && id) { + onBlurLegendItem(id); + } }, - 'onFocus': () => onFocusLegendItem(id), - 'onBlur': () => onBlurLegendItem(id), 'aria-labelledby': shape === 'Checkbox' ? this.getUniqueID() : null, }; } - getIconProps(): LegendItem & IRootComponentProps & { onClick: () => void } { + getIconProps() { const props = this.asProps; return { ...props, children: props.icon, - onClick: () => props.onChangeLegendItem(props.id, !props.checked), + onClick: () => { + if (props.onChangeLegendItem && props.id) { + props.onChangeLegendItem(props.id, !props.checked); + } + }, }; } - getLabelProps(): Omit & IRootComponentProps & { onClick: () => void } { + getLabelProps() { const { id, checked, color: _color, onChangeLegendItem, shape: _shape, ...props } = this.asProps; return { ...props, id: this.getUniqueID(), checked, - onClick: () => onChangeLegendItem(id, !checked), + onClick: () => { + if (onChangeLegendItem && id) { + onChangeLegendItem(id, !checked); + } + }, children: props.label, }; } - getAdditionalLabelProps(): LegendItem & IRootComponentProps & { onClick: () => void } { + getAdditionalLabelProps() { const props = this.asProps; const { additionalInfo, onChangeLegendItem, id, checked } = props; @@ -92,11 +119,15 @@ class LegendItemRoot extends Component { return { ...props, children: additionalInfo && 'label' in additionalInfo ? `${additionalInfo.label}` : undefined, - onClick: () => onChangeLegendItem(id, !checked), + onClick: () => { + if (onChangeLegendItem && id) { + onChangeLegendItem(id, !checked); + } + }, }; } - getCountProps(): LegendItem & IRootComponentProps & { onClick: () => void } { + getCountProps() { const props = this.asProps; const { additionalInfo, onChangeLegendItem, id, checked } = props; @@ -105,7 +136,11 @@ class LegendItemRoot extends Component { ...props, children: additionalInfo && 'count' in additionalInfo ? `(${additionalInfo.count})` : undefined, - onClick: () => onChangeLegendItem(id, !checked), + onClick: () => { + if (onChangeLegendItem && id) { + onChangeLegendItem(id, !checked); + } + }, }; } @@ -124,7 +159,9 @@ class LegendItemRoot extends Component { } } -function Shape(props: IRootComponentProps & ShapeProps & DOMAttributes) { +function Shape( + props: Intergalactic.InternalTypings.InferChildComponentProps, +) { const SPointShape = Root; const SPatternSymbol = PatternSymbol; const { @@ -182,7 +219,10 @@ function Shape(props: IRootComponentProps & ShapeProps & DOMAttributes, +) { + const { styles, children: hasChildren, Children } = props; const SIcon = Root; if (!hasChildren) { @@ -197,7 +237,10 @@ function Icon({ styles, children: hasChildren, Children }: IRootComponentProps) } Icon.displayName = 'Icon'; -function Label({ styles, children: hasChildren, Children }: IRootComponentProps) { +function Label( + props: Intergalactic.InternalTypings.InferChildComponentProps, +) { + const { styles, children: hasChildren, Children } = props; const SLabel = Root; if (!hasChildren) { @@ -212,7 +255,10 @@ function Label({ styles, children: hasChildren, Children }: IRootComponentProps) } Label.displayName = 'Label'; -function AdditionalLabel({ styles, children: hasChildren, Children }: IRootComponentProps) { +function AdditionalLabel( + props: Intergalactic.InternalTypings.InferChildComponentProps, +) { + const { styles, children: hasChildren, Children } = props; const SAdditionalLabel = Root; if (!hasChildren) { @@ -227,7 +273,10 @@ function AdditionalLabel({ styles, children: hasChildren, Children }: IRootCompo } AdditionalLabel.displayName = 'AdditionalLabel'; -function Count({ styles, children: hasChildren, Children }: IRootComponentProps) { +function Count( + props: Intergalactic.InternalTypings.InferChildComponentProps, +) { + const { styles, children: hasChildren, Children } = props; const SCount = Root; if (!hasChildren) { @@ -242,10 +291,13 @@ function Count({ styles, children: hasChildren, Children }: IRootComponentProps) } Count.displayName = 'Count'; -export const LegendItemComponent = createComponent(LegendItemRoot, { +export const LegendItemComponent = createComponent< + LegendItemType, + typeof LegendItemRoot +>(LegendItemRoot, { Shape, Icon, Label, AdditionalLabel, Count, -}) as LegendItemType; +}); diff --git a/semcore/d3-chart/src/component/ChartLegend/LegendItem/LegendItem.type.ts b/semcore/d3-chart/src/component/ChartLegend/LegendItem/LegendItem.type.ts index aaf59db07a..ec211b3f25 100644 --- a/semcore/d3-chart/src/component/ChartLegend/LegendItem/LegendItem.type.ts +++ b/semcore/d3-chart/src/component/ChartLegend/LegendItem/LegendItem.type.ts @@ -1,5 +1,5 @@ -import type { Flex } from '@semcore/base-components'; -import type { Intergalactic, Root } from '@semcore/core'; +import type { Box, Flex } from '@semcore/base-components'; +import type { Intergalactic } from '@semcore/core'; import type Icon from '@semcore/icon'; import type { Text } from '@semcore/typography'; @@ -78,6 +78,10 @@ export type LegendItemProps = LegendItem & { onBlurLegendItem: (id: LegendItemKey) => void; }; +export type LegendItemDefaultProps = { + children: React.JSX.Element; +}; + export type ShapeProps = LegendItem & ( | { @@ -96,10 +100,16 @@ export const StaticShapes = ['Circle', 'Line', 'Square', 'Pattern'] as const; export type ShapeType = 'Checkbox' | typeof StaticShapes[number]; +export type LegendItemShapeType = Intergalactic.Component>; +export type LegendItemIconType = Intergalactic.Component>; ; +export type LegendItemLabelType = Intergalactic.Component>>; ; +export type LegendItemAdditionalLabelType = Intergalactic.Component>; ; +export type LegendItemCountType = Intergalactic.Component>; ; + export type LegendItemType = Intergalactic.Component> & { - Shape: Intergalactic.Component>; - Icon: Intergalactic.Component>; - Label: Intergalactic.Component>>; - AdditionalLabel: Intergalactic.Component>; - Count: Intergalactic.Component>; + Shape: LegendItemShapeType; + Icon: LegendItemIconType; + Label: LegendItemLabelType; + AdditionalLabel: LegendItemAdditionalLabelType; + Count: LegendItemCountType; }; diff --git a/semcore/d3-chart/src/component/ChartLegend/LegendTable/LegendTable.tsx b/semcore/d3-chart/src/component/ChartLegend/LegendTable/LegendTable.tsx index ab7f93cf99..25cab8ab7d 100644 --- a/semcore/d3-chart/src/component/ChartLegend/LegendTable/LegendTable.tsx +++ b/semcore/d3-chart/src/component/ChartLegend/LegendTable/LegendTable.tsx @@ -3,11 +3,11 @@ import { createComponent, sstyled, Root, type IRootComponentProps } from '@semco import React from 'react'; import style from './legend-table.shadow.css'; -import type { LegendTableType, LegendTableProps, LegendColumnProps } from './LegendTable.type'; +import type { LegendTableType, LegendTableProps, LegendColumnProps, LegendTableDefaultProps } from './LegendTable.type'; import { BaseLegend } from '../BaseLegend'; import { LegendItemComponent } from '../LegendItem/LegendItem'; -class LegendTableRoot extends BaseLegend { +class LegendTableRoot extends BaseLegend { static displayName = 'LegendTable'; static style = style; @@ -58,7 +58,10 @@ function ColumnComponent(props: LegendColumnProps & IRootComponentProps) { ); } -export const LegendTable = createComponent(LegendTableRoot, { +export const LegendTable = createComponent< + LegendTableType, + typeof LegendTableRoot +>(LegendTableRoot, { LegendItem: LegendItemComponent, Column: ColumnComponent, -}) as LegendTableType; +}); diff --git a/semcore/d3-chart/src/component/ChartLegend/LegendTable/LegendTable.type.ts b/semcore/d3-chart/src/component/ChartLegend/LegendTable/LegendTable.type.ts index c0f7be4299..0bdb3771cd 100644 --- a/semcore/d3-chart/src/component/ChartLegend/LegendTable/LegendTable.type.ts +++ b/semcore/d3-chart/src/component/ChartLegend/LegendTable/LegendTable.type.ts @@ -12,6 +12,10 @@ export type LegendTableProps = Intergalactic.InternalTypings.EfficientOmit }>; }; +export type LegendTableDefaultProps = { + children: React.JSX.Element; +}; + export type LegendColumnProps = { index: number; size: LSize; diff --git a/semcore/data-table/src/components/Body/Body.tsx b/semcore/data-table/src/components/Body/Body.tsx index 339ef09f79..89c8f92c43 100644 --- a/semcore/data-table/src/components/Body/Body.tsx +++ b/semcore/data-table/src/components/Body/Body.tsx @@ -426,8 +426,13 @@ class BodyRoot extends Component(BodyRoot, { + Row, +}); diff --git a/semcore/data-table/src/components/Body/Cell.tsx b/semcore/data-table/src/components/Body/Cell.tsx index eb3cbc5502..735d3cee01 100644 --- a/semcore/data-table/src/components/Body/Cell.tsx +++ b/semcore/data-table/src/components/Body/Cell.tsx @@ -1,18 +1,21 @@ import { Box, Flex } from '@semcore/base-components'; +import type { Intergalactic } from '@semcore/core'; import { Root, sstyled, createComponent, Component } from '@semcore/core'; import { getFocusableIn } from '@semcore/core/lib/utils/focus-lock/getFocusableIn'; import { isFocusInside } from '@semcore/core/lib/utils/focus-lock/isFocusInside'; import { isInteractiveElement } from '@semcore/core/lib/utils/isInteractiveElement'; import * as React from 'react'; -import type { DataTableCellProps } from './Cell.types'; +import type { DataTableCellProps, DataTableCellType } from './Cell.types'; import { MergedColumnsCell, MergedRowsCell } from './MergedCells'; import styles from './style.shadow.css'; import type { IFocusableCell, LockedCell } from '../../enhancers/focusableCell'; import { handleFocusCell, handleKeydownFocusCell } from '../../enhancers/focusableCell'; import type { DataTableData } from '../DataTable/DataTable.types'; -class CellRoot extends Component> implements IFocusableCell { +class CellRoot + extends Component> + implements IFocusableCell { lockedCell: LockedCell = [null, false]; static displayName = 'Cell'; @@ -138,4 +141,7 @@ class CellRoot extends Component(CellRoot); diff --git a/semcore/data-table/src/components/Body/Cell.types.ts b/semcore/data-table/src/components/Body/Cell.types.ts index c6c49524b7..680dc8e2bf 100644 --- a/semcore/data-table/src/components/Body/Cell.types.ts +++ b/semcore/data-table/src/components/Body/Cell.types.ts @@ -37,3 +37,12 @@ export type DataTableCellProps = Interg } & { 'data-aria-level'?: number; }; + +export type DataTableCellType = (( + props: Intergalactic.InternalTypings.ComponentProps< + Tag, + 'div', + DataTableCellProps + >, +) => Intergalactic.InternalTypings.ComponentRenderingResults) & +Intergalactic.InternalTypings.ComponentAdditive<'div', 'div', DataTableCellProps>; diff --git a/semcore/data-table/src/components/Body/LimitOverlay.tsx b/semcore/data-table/src/components/Body/LimitOverlay.tsx index eb4ab068e7..b1e4146bda 100644 --- a/semcore/data-table/src/components/Body/LimitOverlay.tsx +++ b/semcore/data-table/src/components/Body/LimitOverlay.tsx @@ -146,4 +146,7 @@ type LimitOverlayType = (< ) => Intergalactic.InternalTypings.ComponentRenderingResults) & Intergalactic.InternalTypings.ComponentAdditive<'div', 'div', LimitOverlayProps>; -export const LimitOverlay = createComponent(LimitOverlayRoot) as LimitOverlayType; +export const LimitOverlay = createComponent< + LimitOverlayType, + typeof LimitOverlayRoot +>(LimitOverlayRoot); diff --git a/semcore/data-table/src/components/Body/Row.tsx b/semcore/data-table/src/components/Body/Row.tsx index 21913b64ca..a61f7ce104 100644 --- a/semcore/data-table/src/components/Body/Row.tsx +++ b/semcore/data-table/src/components/Body/Row.tsx @@ -23,7 +23,18 @@ type State = { accordionComponent?: React.ReactNode; }; -export class RowRoot extends Component, [], {}, RowPropsInner, State> { +type DefaultProps = { + 'aria-level': undefined; +}; + +export class RowRoot extends Component< + DataTableRowProps, + [], + {}, + RowPropsInner, + State, + DefaultProps +> { static displayName = 'Row'; static style = style; @@ -659,8 +670,13 @@ export class RowRoot extends Component< } } -export const Row = createComponent(RowRoot, { - Cell, -}) as unknown as DataTableRowType & { +type RowComponent = DataTableRowType & { Cell: any; }; + +export const Row = createComponent< + RowComponent, + typeof RowRoot +>(RowRoot, { + Cell, +}); diff --git a/semcore/data-table/src/components/Body/Row.types.ts b/semcore/data-table/src/components/Body/Row.types.ts index b99675558d..899ac3c7d5 100644 --- a/semcore/data-table/src/components/Body/Row.types.ts +++ b/semcore/data-table/src/components/Body/Row.types.ts @@ -110,6 +110,10 @@ export type RowPropsInner = JSX.Intrins }; export type DataTableRowType = (( - props: Intergalactic.InternalTypings.ComponentProps & Partial>> + props: Intergalactic.InternalTypings.ComponentProps< + Tag, + 'div', + DataTableRowProps & Partial> + >, ) => Intergalactic.InternalTypings.ComponentRenderingResults) & Intergalactic.InternalTypings.ComponentAdditive<'div', 'div', DataTableRowProps>; diff --git a/semcore/data-table/src/components/DataTable/DataTable.tsx b/semcore/data-table/src/components/DataTable/DataTable.tsx index a3e041c5fb..8ba4527486 100644 --- a/semcore/data-table/src/components/DataTable/DataTable.tsx +++ b/semcore/data-table/src/components/DataTable/DataTable.tsx @@ -57,6 +57,17 @@ type State< expandedRows: Set; }; +type DefaultProps = { + use: 'primary'; + defaultGridTemplateColumnWidth: 'auto'; + defaultSelectedRows: undefined; + h: 'fit-content'; + renderEmptyData: () => React.JSX.Element; + variant: 'default'; + accordionAnimationRows: 40; + accordionDuration: 200; +}; + class DataTableRoot< Data extends DataTableData, UniqKey extends (Data[number] extends { [ROW_GROUP]: DataTableData } ? keyof Data[number][typeof ROW_GROUP][number] : keyof Data[number]), @@ -65,8 +76,9 @@ class DataTableRoot< DataTableProps, typeof DataTableRoot.enhance, {}, - typeof DataTableRoot.defaultProps, - State + {}, + State, + DefaultProps > { static displayName = 'DataTable'; static style = style; @@ -85,7 +97,7 @@ class DataTableRoot< variant: 'default', accordionAnimationRows: 40, accordionDuration: 200, - }; + } as const; static getDerivedStateFromProps(props: DataTableProps, state: State) { if (props.expandedRows === state.expandedRows || props.expandedRows === undefined) { @@ -1468,10 +1480,15 @@ class DataTableRoot< } } -export const DataTable = createComponent(DataTableRoot, { - Head, - Body, -}) as unknown as DataTableType & { +type DataTableComponent = DataTableType & { Head: typeof Head; Body: typeof Body; }; + +export const DataTable = createComponent< + DataTableComponent, + typeof DataTableRoot +>(DataTableRoot, { + Head, + Body, +}); diff --git a/semcore/data-table/src/components/Head/Head.tsx b/semcore/data-table/src/components/Head/Head.tsx index 0c87b92029..61d3fa0da3 100644 --- a/semcore/data-table/src/components/Head/Head.tsx +++ b/semcore/data-table/src/components/Head/Head.tsx @@ -286,7 +286,7 @@ class HeadRoot< } } -export const Head = createComponent(HeadRoot, { Column, Group }) as Intergalactic.Component< +type HeadComponent = Intergalactic.Component< 'div', DataTableHeadProps > & { @@ -297,3 +297,8 @@ export const Head = createComponent(HeadRoot, { Column, Group }) as Intergalacti props: Intergalactic.InternalTypings.ComponentProps, ) => Intergalactic.InternalTypings.ComponentRenderingResults; }; + +export const Head = createComponent< + HeadComponent, + typeof HeadRoot +>(HeadRoot, { Column, Group }); diff --git a/semcore/divider/src/Divider.tsx b/semcore/divider/src/Divider.tsx index a1d9b2a316..18127034f0 100644 --- a/semcore/divider/src/Divider.tsx +++ b/semcore/divider/src/Divider.tsx @@ -7,30 +7,35 @@ import React from 'react'; import type { NSDivider } from './Divider.type'; import style from './style/divider.shadow.css'; -class DividerRoot extends Component, typeof DividerRoot.enhance> { +class DividerRoot extends Component< + Intergalactic.InternalTypings.InferComponentProps, + typeof DividerRoot.enhance, + {}, + {}, + {}, + NSDivider.DefaultProps +> { static displayName = 'Divider'; static style = style; static enhance = [resolveColorEnhance()] as const; static defaultProps = { use: 'primary', orientation: 'horizontal', - }; + } as const; render() { const SDivider = Root; const { orientation, resolveColor, theme } = this.asProps; return sstyled(this.asProps.styles)( - , + , ); } } -const Divider = createComponent(DividerRoot) as NSDivider.Component; +const Divider = createComponent< + NSDivider.Component, + typeof DividerRoot +>(DividerRoot); export default Divider; diff --git a/semcore/divider/src/Divider.type.ts b/semcore/divider/src/Divider.type.ts index fee8ab1069..1fa445775b 100644 --- a/semcore/divider/src/Divider.type.ts +++ b/semcore/divider/src/Divider.type.ts @@ -18,6 +18,10 @@ declare namespace NSDivider { */ orientation?: 'horizontal' | 'vertical'; }; + type DefaultProps = { + use: 'primary'; + orientation: 'horizontal'; + }; type Component = Intergalactic.Component<'div', Props>; } diff --git a/semcore/dot/src/Dot.tsx b/semcore/dot/src/Dot.tsx index 2d35517012..63776e89f3 100644 --- a/semcore/dot/src/Dot.tsx +++ b/semcore/dot/src/Dot.tsx @@ -13,13 +13,17 @@ import style from './style/dot.shadow.css'; class DotRoot extends Component< Intergalactic.InternalTypings.InferComponentProps, - typeof DotRoot.enhance + typeof DotRoot.enhance, + {}, + NSDot.InnerProps, + {}, + NSDot.DefaultProps > { static displayName = 'Dot'; static style = style; static defaultProps = { - size: 'm', - keyframes: [style['@enter'], style['@exit']], + size: 'm' as const, + keyframes: [style['@enter'], style['@exit']] as [string, string], }; static enhance = [ @@ -89,6 +93,9 @@ class DotRoot extends Component< } } -const Dot = createComponent(DotRoot) as NSDot.Component; +const Dot = createComponent< + NSDot.Component, + typeof DotRoot +>(DotRoot); export default Dot; diff --git a/semcore/dot/src/Dot.type.ts b/semcore/dot/src/Dot.type.ts index 4dedbb9916..a444b2ec59 100644 --- a/semcore/dot/src/Dot.type.ts +++ b/semcore/dot/src/Dot.type.ts @@ -14,6 +14,13 @@ declare namespace NSDot { /** The property for Dot visibility control */ hidden?: boolean; }; + type InnerProps = { + keyframes: [string, string]; + }; + type DefaultProps = { + size: 'm'; + keyframes: InnerProps['keyframes']; + }; type Component = Intergalactic.Component<'div', Props>; } diff --git a/semcore/drag-and-drop/src/DragAndDrop.tsx b/semcore/drag-and-drop/src/DragAndDrop.tsx index 8035e62a92..2d12ed67c6 100644 --- a/semcore/drag-and-drop/src/DragAndDrop.tsx +++ b/semcore/drag-and-drop/src/DragAndDrop.tsx @@ -1,13 +1,15 @@ import { Box, ScreenReaderOnly } from '@semcore/base-components'; import { createComponent, sstyled, Component, Root } from '@semcore/core'; import canUseDOM from '@semcore/core/lib/utils/canUseDOM'; +import type { WithI18nEnhanceProps } from '@semcore/core/lib/utils/enhances/i18nEnhance'; import i18nEnhance from '@semcore/core/lib/utils/enhances/i18nEnhance'; import uniqueIDEnhance from '@semcore/core/lib/utils/uniqueID'; import useEnhancedEffect from '@semcore/core/lib/utils/use/useEnhancedEffect'; import React from 'react'; -import type { DragAndDropComponent, DragAndDropProps, DropZoneProps } from './DragAndDrop.type'; +import type { DragAndDropComponent, DragAndDropProps, DropZoneProps, DragAndDropDefaultProps } from './DragAndDrop.type'; import style from './style/drag-and-drop.shadow.css'; +import type { LocalizedMessages } from './translations/__intergalactic-dynamic-locales'; import { localizedMessages } from './translations/__intergalactic-dynamic-locales'; type AttachDetails = { @@ -46,15 +48,22 @@ type State = { reversedScaling: boolean; }; -type A11yHintKeys = keyof typeof localizedMessages.en; +type A11yHintKeys = keyof LocalizedMessages['en']; -class DragAndDropRoot extends Component { +class DragAndDropRoot extends Component< + DragAndDropProps, + typeof DragAndDropRoot.enhance, + {}, + WithI18nEnhanceProps, + State, + DragAndDropDefaultProps +> { static displayName = 'DragAndDrop'; static enhance = [i18nEnhance(localizedMessages), uniqueIDEnhance()] as const; static defaultProps = { i18n: localizedMessages, locale: 'en', - }; + } as const; static style = style; @@ -77,8 +86,7 @@ class DragAndDropRoot extends Component i?.zoneName === zoneName); @@ -109,7 +117,8 @@ class DragAndDropRoot extends Component { // because FF and safari can't create visible draggableImage without timeout + setTimeout(() => { + // because FF and safari can't create visible draggableImage without timeout target.style.opacity = '0'; }); } @@ -214,8 +223,7 @@ class DragAndDropRoot extends Component i?.zoneName === zoneName); const itemsCount = zonedItems.length; @@ -459,8 +467,7 @@ class DragAndDropRoot extends Component (e: DragEvent) => this.handleItemDragStart(index, e); - makeItemKeyDownHandler = (index: number) => (event: KeyboardEvent) => - this.handleItemKeyDown(event, index); + makeItemKeyDownHandler = (index: number) => (event: KeyboardEvent) => this.handleItemKeyDown(event, index); getDraggableProps(_: any, index: number) { const { uid } = this.asProps; @@ -494,18 +501,9 @@ class DragAndDropRoot extends Component { + attach = ({ index, children, node, id, draggingAllowed, zoneName, isDropZone }: AttachDetails) => { this.setState((prevState: State) => { - if (prevState.items[index]?.children === children && prevState.items[index]?.node === node) - return prevState; + if (prevState.items[index]?.children === children && prevState.items[index]?.node === node) return prevState; const { items } = prevState; items[index] = { children, node, id, draggingAllowed, zoneName, isDropZone }; return { items: [...items] }; @@ -709,10 +707,13 @@ function DropZone(props: DropZoneProps) { ); }; -const DragAndDrop = createComponent(DragAndDropRoot, { +const DragAndDrop = createComponent< + DragAndDropComponent, + typeof DragAndDropRoot +>(DragAndDropRoot, { Draggable, DropZone, Dropable: DropZone, -}) as DragAndDropComponent; +}); export default DragAndDrop; diff --git a/semcore/drag-and-drop/src/DragAndDrop.type.ts b/semcore/drag-and-drop/src/DragAndDrop.type.ts index 5d8487c6be..148c82d10b 100644 --- a/semcore/drag-and-drop/src/DragAndDrop.type.ts +++ b/semcore/drag-and-drop/src/DragAndDrop.type.ts @@ -1,6 +1,8 @@ import type { Box, BoxProps } from '@semcore/base-components'; import type { PropGetterFn, Intergalactic } from '@semcore/core'; +import type { LocalizedMessages } from './translations/__intergalactic-dynamic-locales'; + /** * DragAndDrop and Draggable containers must have an accessible names (aria-group-name). */ @@ -28,6 +30,11 @@ export type DragAndDropProps = BoxProps & { scrollableContainerRef?: React.MutableRefObject; }; +export type DragAndDropDefaultProps = { + i18n: LocalizedMessages; + locale: 'en'; +}; + export type DraggableProps = BoxProps & { /** Placement of visual drag-and-drop marker * @default right diff --git a/semcore/drag-and-drop/src/translations/__intergalactic-dynamic-locales.ts b/semcore/drag-and-drop/src/translations/__intergalactic-dynamic-locales.ts index ccae777b73..65cdb67688 100644 --- a/semcore/drag-and-drop/src/translations/__intergalactic-dynamic-locales.ts +++ b/semcore/drag-and-drop/src/translations/__intergalactic-dynamic-locales.ts @@ -29,3 +29,5 @@ export const localizedMessages = { pl, sv, }; + +export type LocalizedMessages = typeof localizedMessages; diff --git a/semcore/dropdown-menu/src/components/VirtualList.tsx b/semcore/dropdown-menu/src/components/VirtualList.tsx index dc6ed6aa26..e0cec8de34 100644 --- a/semcore/dropdown-menu/src/components/VirtualList.tsx +++ b/semcore/dropdown-menu/src/components/VirtualList.tsx @@ -23,23 +23,36 @@ type VirtualListProps = { * @default 10 */ rowsBuffer?: number; -} & ([D] extends [never] ? { customData?: undefined } : { + /* + TODO: As of now make it as optional, since TS has troubles with infering type depending on generic default value... + Revise it during refactoring. + */ /** Some custom data for each renderRow function */ - customData: D; -}); + customData?: [D] extends [never] ? undefined : D; +}; + +type VirtualListDefaultProps = { + rowsBuffer: 6; +}; type State = { scrollTop: number; scrollDirection: 'up' | 'down'; }; - -class VirtualListRoot extends Component, [], Readonly<{}>, { rowsBuffer: number; index: number }, State> { +class VirtualListRoot extends Component< + VirtualListProps, + [], + Readonly<{}>, + { index: number }, + State, + VirtualListDefaultProps +> { static displayName = 'VirtualList'; static style = style; static defaultProps = { rowsBuffer: 6, - }; + } as const; containerRef = React.createRef(); listRef = React.createRef(); @@ -86,10 +99,7 @@ class VirtualListRoot extends Component>, 'tag' | 'children'> ) => Intergalactic.InternalTypings.ComponentRenderingResults) & Intergalactic.InternalTypings.ComponentAdditive>; -export const VirtualList = createComponent(VirtualListRoot) as VirtualListComponent; +export const VirtualList = createComponent< + VirtualListComponent, + typeof VirtualListRoot +>(VirtualListRoot); diff --git a/semcore/ellipsis/src/Ellipsis.tsx b/semcore/ellipsis/src/Ellipsis.tsx index 3f113cafe4..25546b86d4 100644 --- a/semcore/ellipsis/src/Ellipsis.tsx +++ b/semcore/ellipsis/src/Ellipsis.tsx @@ -71,6 +71,18 @@ type EllipsisProps = BoxProps & includeTooltipProps?: string[]; }; +type DefaultProps = { + trim: 'end'; + tooltip: true; + includeTooltipProps: typeof defaultTooltipProps; + __excludeProps: AsProps['__excludeProps']; +}; + +type EllipsisComponent = Intergalactic.Component<'div', EllipsisProps> & { + Content: typeof Box; + Popper: typeof Tooltip.Popper; +}; + const defaultTooltipProps = [ 'title', 'theme', @@ -95,12 +107,19 @@ const defaultTooltipProps = [ const forcedAdvancedMode = { forcedAdvancedMode: true } as any; const noAdvancedMode = {} as any; -class RootEllipsis extends Component { +class RootEllipsis extends Component< + AsProps, + [], + {}, + {}, + {}, + DefaultProps +> { static displayName = 'Ellipsis'; static style = style; - static defaultProps: AsProps = { - trim: 'end', - tooltip: true, + static defaultProps = { + trim: 'end' as const, + tooltip: true as const, includeTooltipProps: defaultTooltipProps, __excludeProps: ['title'], }; @@ -322,12 +341,12 @@ function Content({ styles, Children }: EllipsisContentAsProps) { ) as any; } -const Ellipsis = createComponent(RootEllipsis, { +const Ellipsis = createComponent< + EllipsisComponent, + typeof RootEllipsis +>(RootEllipsis, { Content, Popper: Tooltip.Popper, -}) as any as Intergalactic.Component<'div', EllipsisProps> & { - Content: typeof Box; - Popper: typeof Tooltip.Popper; -}; +}); export default Ellipsis; diff --git a/semcore/errors/src/AccessDenied/AccessDenied.tsx b/semcore/errors/src/AccessDenied/AccessDenied.tsx index 3397e0aff8..743d5e0c23 100644 --- a/semcore/errors/src/AccessDenied/AccessDenied.tsx +++ b/semcore/errors/src/AccessDenied/AccessDenied.tsx @@ -10,7 +10,11 @@ import { localizedMessages } from './translations/__intergalactic-dynamic-locale class RootAccessDenied extends Component< Intergalactic.InternalTypings.InferComponentProps, - typeof RootAccessDenied.enhance + typeof RootAccessDenied.enhance, + {}, + {}, + {}, + NSAccessDenied.DefaultProps > { static displayName = 'AccessDenied'; static enhance = [i18nEnhance(localizedMessages)] as const; @@ -20,7 +24,7 @@ class RootAccessDenied extends Component< homeLink: '/', icon: getIconPath('access_denied'), titleTag: 'h2', - }; + } as const; render() { const { Children, getI18nText, homeLink, titleTag } = this.asProps; @@ -39,4 +43,7 @@ class RootAccessDenied extends Component< } } -export default createComponent(RootAccessDenied) as NSAccessDenied.Component; +export default createComponent< + NSAccessDenied.Component, + typeof RootAccessDenied +>(RootAccessDenied); diff --git a/semcore/errors/src/AccessDenied/AccessDenied.type.ts b/semcore/errors/src/AccessDenied/AccessDenied.type.ts index ee58f39906..b92eeec898 100644 --- a/semcore/errors/src/AccessDenied/AccessDenied.type.ts +++ b/semcore/errors/src/AccessDenied/AccessDenied.type.ts @@ -2,6 +2,7 @@ import type { Intergalactic } from '@semcore/core'; import type { WithI18nEnhanceProps } from '@semcore/core/lib/utils/enhances/i18nEnhance'; import type { NSErrors } from '../Error.type'; +import type { LocalizedMessages } from './translations/__intergalactic-dynamic-locales'; declare namespace NSAccessDenied { type Props = WithI18nEnhanceProps & { @@ -16,6 +17,13 @@ declare namespace NSAccessDenied { */ titleTag?: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'p'; }; + type DefaultProps = { + i18n: LocalizedMessages; + locale: 'en'; + homeLink: '/'; + icon: string; + titleTag: 'h2'; + }; type Component = Intergalactic.Component<'div', Props & NSErrors.Props>; } diff --git a/semcore/errors/src/AccessDenied/translations/__intergalactic-dynamic-locales.ts b/semcore/errors/src/AccessDenied/translations/__intergalactic-dynamic-locales.ts index 01fec83b34..2edde3b546 100644 --- a/semcore/errors/src/AccessDenied/translations/__intergalactic-dynamic-locales.ts +++ b/semcore/errors/src/AccessDenied/translations/__intergalactic-dynamic-locales.ts @@ -31,3 +31,5 @@ export const localizedMessages = { pl, sv, }; + +export type LocalizedMessages = typeof localizedMessages; diff --git a/semcore/errors/src/Error.tsx b/semcore/errors/src/Error.tsx index bab962d7d3..76257dd28a 100644 --- a/semcore/errors/src/Error.tsx +++ b/semcore/errors/src/Error.tsx @@ -54,10 +54,13 @@ function Controls(props: Intergalactic.InternalTypings.InferComponentProps); } -const Error = createComponent(RootError, { +const Error = createComponent< + NSErrors.Component, + typeof RootError +>(RootError, { Title, Description, Controls, -}) as NSErrors.Component; +}); export default Error; diff --git a/semcore/errors/src/Maintenance/Maintenance.tsx b/semcore/errors/src/Maintenance/Maintenance.tsx index 68dd63d67a..36e53da4e9 100644 --- a/semcore/errors/src/Maintenance/Maintenance.tsx +++ b/semcore/errors/src/Maintenance/Maintenance.tsx @@ -10,7 +10,11 @@ import { localizedMessages } from './translations/__intergalactic-dynamic-locale class RootMaintenance extends Component< Intergalactic.InternalTypings.InferComponentProps, - typeof RootMaintenance.enhance + typeof RootMaintenance.enhance, + {}, + {}, + {}, + NSMaintenance.DefaultProps > { static displayName = 'Maintenance'; static enhance = [i18nEnhance(localizedMessages)] as const; @@ -20,7 +24,7 @@ class RootMaintenance extends Component< homeLink: '/', icon: getIconPath('maintenance'), titleTag: 'h2', - }; + } as const; render() { const { Children, getI18nText, homeLink, toolName, titleTag } = this.asProps; @@ -40,4 +44,7 @@ class RootMaintenance extends Component< } } -export default createComponent(RootMaintenance) as NSMaintenance.Component; +export default createComponent< + NSMaintenance.Component, + typeof RootMaintenance +>(RootMaintenance); diff --git a/semcore/errors/src/Maintenance/Maintenance.type.ts b/semcore/errors/src/Maintenance/Maintenance.type.ts index ff63d3c002..a1cc938a4c 100644 --- a/semcore/errors/src/Maintenance/Maintenance.type.ts +++ b/semcore/errors/src/Maintenance/Maintenance.type.ts @@ -2,6 +2,7 @@ import type { Intergalactic } from '@semcore/core'; import type { WithI18nEnhanceProps } from '@semcore/core/lib/utils/enhances/i18nEnhance'; import type { NSErrors } from '../Error.type'; +import type { LocalizedMessages } from './translations/__intergalactic-dynamic-locales'; declare namespace NSMaintenance { type Props = WithI18nEnhanceProps & { @@ -20,6 +21,13 @@ declare namespace NSMaintenance { */ titleTag?: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'p'; }; + type DefaultProps = { + i18n: LocalizedMessages; + locale: 'en'; + homeLink: '/'; + icon: string; + titleTag: 'h2'; + }; type Component = Intergalactic.Component<'div', Props & NSErrors.Props>; } diff --git a/semcore/errors/src/Maintenance/translations/__intergalactic-dynamic-locales.ts b/semcore/errors/src/Maintenance/translations/__intergalactic-dynamic-locales.ts index 01fec83b34..2edde3b546 100644 --- a/semcore/errors/src/Maintenance/translations/__intergalactic-dynamic-locales.ts +++ b/semcore/errors/src/Maintenance/translations/__intergalactic-dynamic-locales.ts @@ -31,3 +31,5 @@ export const localizedMessages = { pl, sv, }; + +export type LocalizedMessages = typeof localizedMessages; diff --git a/semcore/errors/src/PageError/PageError.tsx b/semcore/errors/src/PageError/PageError.tsx index 7bd9d90f40..34c367f24c 100644 --- a/semcore/errors/src/PageError/PageError.tsx +++ b/semcore/errors/src/PageError/PageError.tsx @@ -11,7 +11,11 @@ import type { NSPageError } from './PageError.type'; import { localizedMessages } from './translations/__intergalactic-dynamic-locales'; class RootPageError extends Component< Intergalactic.InternalTypings.InferComponentProps, - typeof RootPageError.enhance + typeof RootPageError.enhance, + {}, + {}, + {}, + NSPageError.DefaultProps > { static displayName = 'PageError'; static enhance = [i18nEnhance(localizedMessages)] as const; @@ -20,7 +24,7 @@ class RootPageError extends Component< locale: 'en', icon: getIconPath('page_error'), titleTag: 'h2', - }; + } as const; handleReload = () => { if (canUseDOM()) { @@ -51,4 +55,7 @@ class RootPageError extends Component< } } -export default createComponent(RootPageError) as NSPageError.Component; +export default createComponent< + NSPageError.Component, + typeof RootPageError +>(RootPageError); diff --git a/semcore/errors/src/PageError/PageError.type.ts b/semcore/errors/src/PageError/PageError.type.ts index bbcb870271..4364343587 100644 --- a/semcore/errors/src/PageError/PageError.type.ts +++ b/semcore/errors/src/PageError/PageError.type.ts @@ -2,6 +2,7 @@ import type { Intergalactic } from '@semcore/core'; import type { WithI18nEnhanceProps } from '@semcore/core/lib/utils/enhances/i18nEnhance'; import type { NSErrors } from '../Error.type'; +import type { LocalizedMessages } from './translations/__intergalactic-dynamic-locales'; declare namespace NSPageError { type Props = WithI18nEnhanceProps & { @@ -16,6 +17,12 @@ declare namespace NSPageError { */ titleTag?: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'p'; }; + type DefaultProps = { + i18n: LocalizedMessages; + locale: 'en'; + icon: string; + titleTag: 'h2'; + }; type Component = Intergalactic.Component<'div', Props & NSErrors.Props>; } diff --git a/semcore/errors/src/PageError/translations/__intergalactic-dynamic-locales.ts b/semcore/errors/src/PageError/translations/__intergalactic-dynamic-locales.ts index 01fec83b34..2edde3b546 100644 --- a/semcore/errors/src/PageError/translations/__intergalactic-dynamic-locales.ts +++ b/semcore/errors/src/PageError/translations/__intergalactic-dynamic-locales.ts @@ -31,3 +31,5 @@ export const localizedMessages = { pl, sv, }; + +export type LocalizedMessages = typeof localizedMessages; diff --git a/semcore/errors/src/PageNotFound/PageNotFound.tsx b/semcore/errors/src/PageNotFound/PageNotFound.tsx index 8186eb0648..e1f723a647 100644 --- a/semcore/errors/src/PageNotFound/PageNotFound.tsx +++ b/semcore/errors/src/PageNotFound/PageNotFound.tsx @@ -10,7 +10,11 @@ import { localizedMessages } from './translations/__intergalactic-dynamic-locale class RootPageNotFound extends Component< Intergalactic.InternalTypings.InferComponentProps, - typeof RootPageNotFound.enhance + typeof RootPageNotFound.enhance, + {}, + {}, + {}, + NSPageNotFound.DefaultProps > { static displayName = 'PageNotFound'; static enhance = [i18nEnhance(localizedMessages)] as const; @@ -20,7 +24,7 @@ class RootPageNotFound extends Component< icon: getIconPath('page_not_found'), homeLink: '/', titleTag: 'h2', - }; + } as const; render() { const { Children, getI18nText, homeLink, titleTag } = this.asProps; @@ -40,4 +44,7 @@ class RootPageNotFound extends Component< } } -export default createComponent(RootPageNotFound) as NSPageNotFound.Component; +export default createComponent< + NSPageNotFound.Component, + typeof RootPageNotFound +>(RootPageNotFound); diff --git a/semcore/errors/src/PageNotFound/PageNotFound.type.ts b/semcore/errors/src/PageNotFound/PageNotFound.type.ts index f875262cd5..e4d949f77e 100644 --- a/semcore/errors/src/PageNotFound/PageNotFound.type.ts +++ b/semcore/errors/src/PageNotFound/PageNotFound.type.ts @@ -2,6 +2,7 @@ import type { Intergalactic } from '@semcore/core'; import type { WithI18nEnhanceProps } from '@semcore/core/lib/utils/enhances/i18nEnhance'; import type { NSErrors } from '../Error.type'; +import type { LocalizedMessages } from './translations/__intergalactic-dynamic-locales'; declare namespace NSPageNotFound { type Props = WithI18nEnhanceProps & { @@ -16,6 +17,13 @@ declare namespace NSPageNotFound { */ titleTag?: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'p'; }; + type DefaultProps = { + i18n: LocalizedMessages; + locale: 'en'; + icon: string; + homeLink: '/'; + titleTag: 'h2'; + }; type Component = Intergalactic.Component<'div', Props & NSErrors.Props>; } diff --git a/semcore/errors/src/PageNotFound/translations/__intergalactic-dynamic-locales.ts b/semcore/errors/src/PageNotFound/translations/__intergalactic-dynamic-locales.ts index 01fec83b34..2edde3b546 100644 --- a/semcore/errors/src/PageNotFound/translations/__intergalactic-dynamic-locales.ts +++ b/semcore/errors/src/PageNotFound/translations/__intergalactic-dynamic-locales.ts @@ -31,3 +31,5 @@ export const localizedMessages = { pl, sv, }; + +export type LocalizedMessages = typeof localizedMessages; diff --git a/semcore/errors/src/ProjectNotFound/ProjectNotFound.tsx b/semcore/errors/src/ProjectNotFound/ProjectNotFound.tsx index 553f9441db..e09ab8142d 100644 --- a/semcore/errors/src/ProjectNotFound/ProjectNotFound.tsx +++ b/semcore/errors/src/ProjectNotFound/ProjectNotFound.tsx @@ -11,7 +11,11 @@ import { localizedMessages } from './translations/__intergalactic-dynamic-locale class RootProjectNotFound extends Component< Intergalactic.InternalTypings.InferComponentProps, - typeof RootProjectNotFound.enhance + typeof RootProjectNotFound.enhance, + {}, + {}, + {}, + NSProjectNotFound.DefaultProps > { static displayName = 'ProjectNotFound'; static enhance = [i18nEnhance(localizedMessages)] as const; @@ -23,7 +27,7 @@ class RootProjectNotFound extends Component< contactsLink: '/company/contacts', supportTeamLink: '/company/contacts', titleTag: 'h2', - }; + } as const; render() { const { Children, getI18nText, projectsLink, contactsLink, supportTeamLink, titleTag } = this.asProps; @@ -53,4 +57,7 @@ class RootProjectNotFound extends Component< } } -export default createComponent(RootProjectNotFound) as NSProjectNotFound.Component; +export default createComponent< + NSProjectNotFound.Component, + typeof RootProjectNotFound +>(RootProjectNotFound); diff --git a/semcore/errors/src/ProjectNotFound/ProjectNotFound.type.ts b/semcore/errors/src/ProjectNotFound/ProjectNotFound.type.ts index 1f3e6795f1..f555a0e5c8 100644 --- a/semcore/errors/src/ProjectNotFound/ProjectNotFound.type.ts +++ b/semcore/errors/src/ProjectNotFound/ProjectNotFound.type.ts @@ -2,6 +2,7 @@ import type { Intergalactic } from '@semcore/core'; import type { WithI18nEnhanceProps } from '@semcore/core/lib/utils/enhances/i18nEnhance'; import type { NSErrors } from '../Error.type'; +import type { LocalizedMessages } from './translations/__intergalactic-dynamic-locales'; declare namespace NSProjectNotFound { type Props = WithI18nEnhanceProps & { @@ -26,6 +27,15 @@ declare namespace NSProjectNotFound { */ titleTag?: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'p'; }; + type DefaultProps = { + i18n: LocalizedMessages; + locale: 'en'; + icon: string; + projectsLink: '/projects'; + contactsLink: '/company/contacts'; + supportTeamLink: '/company/contacts'; + titleTag: 'h2'; + }; type Component = Intergalactic.Component<'div', Props & NSErrors.Props>; } diff --git a/semcore/errors/src/ProjectNotFound/translations/__intergalactic-dynamic-locales.ts b/semcore/errors/src/ProjectNotFound/translations/__intergalactic-dynamic-locales.ts index 01fec83b34..2edde3b546 100644 --- a/semcore/errors/src/ProjectNotFound/translations/__intergalactic-dynamic-locales.ts +++ b/semcore/errors/src/ProjectNotFound/translations/__intergalactic-dynamic-locales.ts @@ -31,3 +31,5 @@ export const localizedMessages = { pl, sv, }; + +export type LocalizedMessages = typeof localizedMessages; diff --git a/semcore/feature-highlight/src/components/badge/Badge.tsx b/semcore/feature-highlight/src/components/badge/Badge.tsx index f35e487599..bd8b5092df 100644 --- a/semcore/feature-highlight/src/components/badge/Badge.tsx +++ b/semcore/feature-highlight/src/components/badge/Badge.tsx @@ -1,4 +1,5 @@ import Badge, { type BadgeMargins } from '@semcore/badge'; +import type { Intergalactic } from '@semcore/core'; import { createComponent, Component, Root, sstyled } from '@semcore/core'; import resolveColorEnhance from '@semcore/core/lib/utils/enhances/resolveColorEnhance'; import React from 'react'; @@ -19,13 +20,22 @@ type DefaultProps = { use: BadgeFHUse; }; -class BadgeFHRoot extends Component { +type BadgeFHComponent = Intergalactic.Component<'span', BadgeFHProps>; + +class BadgeFHRoot extends Component< + BadgeFHProps, + typeof BadgeFHRoot.enhance, + {}, + {}, + {}, + DefaultProps +> { static displayName = 'BadgeFH'; static style = style; static enhance = [resolveColorEnhance()] as const; - static defaultProps: DefaultProps = { + static defaultProps = { use: 'accent', - }; + } as const; render() { const SHighlightedBadge = Root; @@ -42,4 +52,7 @@ class BadgeFHRoot extends Component(BadgeFHRoot); +export const BadgeFH = createComponent< + BadgeFHComponent, + typeof BadgeFHRoot +>(BadgeFHRoot); diff --git a/semcore/feature-highlight/src/components/button/Button.tsx b/semcore/feature-highlight/src/components/button/Button.tsx index 9b40132cbc..defcfde0f5 100644 --- a/semcore/feature-highlight/src/components/button/Button.tsx +++ b/semcore/feature-highlight/src/components/button/Button.tsx @@ -1,19 +1,37 @@ +import type { ButtonProps } from '@semcore/button'; import Button from '@semcore/button'; import { createComponent, Root, sstyled, Component, type IRootNodeProps } from '@semcore/core'; import SummaryAI from '@semcore/icon/SummaryAI/m'; import React from 'react'; import style from './button.shadow.css'; -import type { HighLightedButtonAddonProps, HighlightedButtonComponent } from './Button.type'; +import type { HighLightedButtonAddonProps, HighlightedButtonComponent, HighlightedButtonDefaultProps } from './Button.type'; import { AnimatedSparkles } from '../../inner-components/sparkle/AnimatedSparkles'; -class ButtonFHRoot extends Component { +/* + * `highlighted` is an internal-only value and cannot be represented in the public prop type. + * During composition the `highlighted` prop is intentionally stripped, so it never reaches + * the final component interface. Because of that, this implementation relies on the current approach. + * Public props are `ButtonProps`. +*/ +type HighlightedButtonProps = Omit & { + theme?: ButtonProps['theme'] | 'highlighted'; +}; + +class ButtonFHRoot extends Component< + HighlightedButtonProps, + [], + {}, + {}, + {}, + HighlightedButtonDefaultProps +> { static displayName = 'ButtonFH'; static style = style; static defaultProps = { theme: 'highlighted', - }; + } as const; state = { clicked: false, @@ -61,7 +79,10 @@ function HighlightAddon(props: HighLightedButtonAddonProps & { clicked: boolean ); } -export const ButtonFH = createComponent(ButtonFHRoot, { +export const ButtonFH = createComponent< + HighlightedButtonComponent, + typeof ButtonFHRoot +>(ButtonFHRoot, { Addon: HighlightAddon, Text: Button.Text, -}) as HighlightedButtonComponent; +}); diff --git a/semcore/feature-highlight/src/components/button/Button.type.ts b/semcore/feature-highlight/src/components/button/Button.type.ts index 760c0dab43..cfe76583c1 100644 --- a/semcore/feature-highlight/src/components/button/Button.type.ts +++ b/semcore/feature-highlight/src/components/button/Button.type.ts @@ -1,6 +1,10 @@ -import type { ButtonAddonProps, ButtonComponent } from '@semcore/button'; +import type { ButtonAddonProps, ButtonComponent, ButtonProps } from '@semcore/button'; import type { Intergalactic } from '@semcore/core'; +export type HighlightedButtonDefaultProps = { + theme: 'highlighted'; +}; + export type HighLightedButtonAddonProps = ButtonAddonProps & { animatedSparkleCount?: number; }; diff --git a/semcore/feature-highlight/src/components/checkbox/Checkbox.tsx b/semcore/feature-highlight/src/components/checkbox/Checkbox.tsx index 9d87b50755..dd726ac27e 100644 --- a/semcore/feature-highlight/src/components/checkbox/Checkbox.tsx +++ b/semcore/feature-highlight/src/components/checkbox/Checkbox.tsx @@ -54,8 +54,11 @@ class CheckboxFHRoot extends Component { } } -export const CheckboxFH = createComponent(CheckboxFHRoot, { +export const CheckboxFH = createComponent< + HighlightedCheckboxComponent, + typeof CheckboxFHRoot +>(CheckboxFHRoot, { Text: Checkbox.Text, Value: Checkbox.Value, AnimatedSparkles, -}) as HighlightedCheckboxComponent; +}); diff --git a/semcore/feature-highlight/src/components/input/Input.tsx b/semcore/feature-highlight/src/components/input/Input.tsx index db17cd9e4b..c489398401 100644 --- a/semcore/feature-highlight/src/components/input/Input.tsx +++ b/semcore/feature-highlight/src/components/input/Input.tsx @@ -27,7 +27,10 @@ function HighlightAddon(props: IRootComponentProps) { ); } -export const InputFH = createComponent(InputFHRoot, { +export const InputFH = createComponent< + typeof Input, + typeof InputFHRoot +>(InputFHRoot, { Addon: HighlightAddon, Value: Input.Value, -}) as typeof Input; +}); diff --git a/semcore/feature-highlight/src/components/notice/Notice.tsx b/semcore/feature-highlight/src/components/notice/Notice.tsx index 6f44a735ba..3edc1c36d7 100644 --- a/semcore/feature-highlight/src/components/notice/Notice.tsx +++ b/semcore/feature-highlight/src/components/notice/Notice.tsx @@ -57,11 +57,14 @@ class NoticeFHRoot extends Component { } } -export const NoticeFH = createComponent(NoticeFHRoot, { +export const NoticeFH = createComponent< + HighlightedNoticeComponent, + typeof NoticeFHRoot +>(NoticeFHRoot, { Label: Notice.Label, Actions: Notice.Actions, Content: Notice.Content, Title: Notice.Title, Text: Notice.Text, Close: Notice.Close, -}) as HighlightedNoticeComponent; +}); diff --git a/semcore/feature-highlight/src/components/pills/Pills.tsx b/semcore/feature-highlight/src/components/pills/Pills.tsx index a40a6dc8b6..3e679b0945 100644 --- a/semcore/feature-highlight/src/components/pills/Pills.tsx +++ b/semcore/feature-highlight/src/components/pills/Pills.tsx @@ -5,7 +5,7 @@ import Pills from '@semcore/pills'; import React from 'react'; import style from './pills.shadow.css'; -import type { HighlightedItemAddonProps, HighlightedPillComponent } from './Pills.type'; +import type { HighlightedItemAddonProps, HighlightedPillComponent, HighlightedPillItemComponent } from './Pills.type'; import { AnimatedSparkles } from '../../inner-components/sparkle/AnimatedSparkles'; class PillsFHRoot extends Component { @@ -64,7 +64,18 @@ function HighlightedItemAddon(props: HighlightedItemAddonProps & { clicked: bool ); } -export const PillsFH = createComponent(PillsFHRoot, { +const HighlightedItem = createComponent< + HighlightedPillItemComponent, + typeof HighlightedItemRoot +>(HighlightedItemRoot, { + Text: Pills.Item.Text, + Addon: HighlightedItemAddon, +}); + +export const PillsFH = createComponent< + HighlightedPillComponent, + typeof PillsFHRoot +>(PillsFHRoot, { Item: Pills.Item, - HighlightedItem: createComponent(HighlightedItemRoot, { Text: Pills.Item.Text, Addon: HighlightedItemAddon }), -}) as unknown as HighlightedPillComponent; + HighlightedItem, +}); diff --git a/semcore/feature-highlight/src/components/pills/Pills.type.ts b/semcore/feature-highlight/src/components/pills/Pills.type.ts index ec1e5e4808..7057ffb8f2 100644 --- a/semcore/feature-highlight/src/components/pills/Pills.type.ts +++ b/semcore/feature-highlight/src/components/pills/Pills.type.ts @@ -7,9 +7,11 @@ export type HighlightedItemAddonProps = { animatedSparkleCount?: number; }; +export type HighlightedPillItemComponent = Intergalactic.Component<'div', PillProps> & { + Text: typeof Box; + Addon: Intergalactic.Component<'div', HighlightedItemAddonProps>; +}; + export type HighlightedPillComponent = typeof Pills & { - HighlightedItem: Intergalactic.Component<'div', PillProps> & { - Text: typeof Box; - Addon: Intergalactic.Component<'div', HighlightedItemAddonProps>; - }; + HighlightedItem: HighlightedPillItemComponent; }; diff --git a/semcore/feature-highlight/src/components/radio/Radio.tsx b/semcore/feature-highlight/src/components/radio/Radio.tsx index ad08e832ce..2c4e2d57d5 100644 --- a/semcore/feature-highlight/src/components/radio/Radio.tsx +++ b/semcore/feature-highlight/src/components/radio/Radio.tsx @@ -65,8 +65,11 @@ class RadioFHRoot extends Component { } } -export const RadioFH = createComponent(RadioFHRoot, { +export const RadioFH = createComponent< + HighlightedRadioComponent, + typeof RadioFHRoot +>(RadioFHRoot, { Text: Radio.Text, Value: Radio.Value, AnimatedSparkles, -}) as HighlightedRadioComponent; +}); diff --git a/semcore/feature-highlight/src/components/select/Select.tsx b/semcore/feature-highlight/src/components/select/Select.tsx index 97f091eec2..5960570337 100644 --- a/semcore/feature-highlight/src/components/select/Select.tsx +++ b/semcore/feature-highlight/src/components/select/Select.tsx @@ -32,7 +32,10 @@ function Trigger(props: IRootComponentProps) { ); } -export const SelectFH = createComponent(SelectFHRoot, { +export const SelectFH: typeof Select = createComponent< + typeof Select, + typeof SelectFHRoot +>(SelectFHRoot, { Trigger: [Trigger, { Text: ButtonTriggerFH.Text, Addon: ButtonTriggerFH.Addon, @@ -41,4 +44,4 @@ export const SelectFH = createComponent(SelectFHRoot, { Menu: Select.Menu, Option: Select.Option, List: Select.List, -}) as unknown as typeof Select; +}); diff --git a/semcore/feature-highlight/src/components/switch/Switch.tsx b/semcore/feature-highlight/src/components/switch/Switch.tsx index 10fb991b4e..ae92e98926 100644 --- a/semcore/feature-highlight/src/components/switch/Switch.tsx +++ b/semcore/feature-highlight/src/components/switch/Switch.tsx @@ -53,8 +53,11 @@ function Value(props: IRootComponentProps & { onChange: () => void }) { return sstyled(props.styles)(); } -export const SwitchFH = createComponent(SwitchFHRoot, { +export const SwitchFH = createComponent< + HighlightedSwitchComponent, + typeof SwitchFHRoot +>(SwitchFHRoot, { Addon: Switch.Addon, Value: Value, AnimatedSparkles, -}) as HighlightedSwitchComponent; +}); diff --git a/semcore/feature-highlight/src/components/tab-line/TabLine.tsx b/semcore/feature-highlight/src/components/tab-line/TabLine.tsx index b04dfb2d94..07ab1afb0c 100644 --- a/semcore/feature-highlight/src/components/tab-line/TabLine.tsx +++ b/semcore/feature-highlight/src/components/tab-line/TabLine.tsx @@ -5,7 +5,7 @@ import TabLine from '@semcore/tab-line'; import React from 'react'; import style from './tabLine.shadow.css'; -import type { HighlightedTabLineComponent } from './TabLine.type'; +import type { HighlightedTabLineComponent, HighlightedTabLineItemComponent } from './TabLine.type'; import { AnimatedSparkles } from '../../inner-components/sparkle/AnimatedSparkles'; class TabLineFHRoot extends Component { @@ -65,7 +65,12 @@ function HighlightedAddon(props: { animatedSparkleCount?: number; clicked: boole ); } -export const TabLineFH = createComponent(TabLineFHRoot, { +const HighlightedItem = createComponent( + HighlightedItemRoot, + { Text: TabLine.Item.Text, Addon: HighlightedAddon }, +); + +export const TabLineFH = createComponent(TabLineFHRoot, { Item: [TabLine.Item, { Text: TabLine.Item.Text, Addon: TabLine.Item.Addon }], - HighlightedItem: createComponent(HighlightedItemRoot, { Text: TabLine.Item.Text, Addon: HighlightedAddon }), -}) as unknown as HighlightedTabLineComponent; + HighlightedItem, +}); diff --git a/semcore/feature-highlight/src/components/tab-line/TabLine.type.ts b/semcore/feature-highlight/src/components/tab-line/TabLine.type.ts index 782c045ecc..fb84dc9b99 100644 --- a/semcore/feature-highlight/src/components/tab-line/TabLine.type.ts +++ b/semcore/feature-highlight/src/components/tab-line/TabLine.type.ts @@ -1,8 +1,10 @@ import type { Intergalactic } from '@semcore/core'; import type TabLine from '@semcore/tab-line'; +export type HighlightedTabLineItemComponent = typeof TabLine.Item & { + Addon: Intergalactic.Component<'div', { animatedSparkleCount?: number }>; +}; + export type HighlightedTabLineComponent = typeof TabLine & { - HighlightedItem: typeof TabLine.Item & { - Addon: Intergalactic.Component<'div', { animatedSparkleCount?: number }>; - }; + HighlightedItem: HighlightedTabLineItemComponent; }; diff --git a/semcore/feature-highlight/src/inner-components/button-trigger/ButtonTrigger.tsx b/semcore/feature-highlight/src/inner-components/button-trigger/ButtonTrigger.tsx index 028c17ad65..37e3ebd026 100644 --- a/semcore/feature-highlight/src/inner-components/button-trigger/ButtonTrigger.tsx +++ b/semcore/feature-highlight/src/inner-components/button-trigger/ButtonTrigger.tsx @@ -1,5 +1,4 @@ import { ButtonTrigger } from '@semcore/base-trigger'; -import Button from '@semcore/button'; import type { IRootComponentProps } from '@semcore/core'; import { createComponent, Root, sstyled, Component } from '@semcore/core'; import SummaryAI from '@semcore/icon/SummaryAI/m'; @@ -7,7 +6,6 @@ import React from 'react'; import style from './buttonTrigger.shadow.css'; import type { HighlightedButtonTriggerComponent } from './ButtonTrigger.type'; -import { AnimatedSparkles } from '../sparkle/AnimatedSparkles'; class ButtonTriggerFHRoot extends Component { static displayName = 'ButtonTriggerFH'; @@ -36,7 +34,10 @@ function Addon(props: IRootComponentProps) { ); } -export const ButtonTriggerFH = createComponent(ButtonTriggerFHRoot, { +export const ButtonTriggerFH = createComponent< + HighlightedButtonTriggerComponent, + typeof ButtonTriggerFHRoot +>(ButtonTriggerFHRoot, { Text: ButtonTrigger.Text, Addon, -}) as HighlightedButtonTriggerComponent; +}); diff --git a/semcore/feature-highlight/src/inner-components/sparkle/Sparkle.tsx b/semcore/feature-highlight/src/inner-components/sparkle/Sparkle.tsx index 7211ac02b6..3d5d7d3194 100644 --- a/semcore/feature-highlight/src/inner-components/sparkle/Sparkle.tsx +++ b/semcore/feature-highlight/src/inner-components/sparkle/Sparkle.tsx @@ -1,5 +1,6 @@ +import type { Intergalactic } from '@semcore/core'; import { createBaseComponent, Root, sstyled } from '@semcore/core'; -import type { ForwardedRef } from 'react'; +import type { Ref } from 'react'; import React from 'react'; import styles from './style/sparkle.shadow.css'; @@ -12,7 +13,7 @@ type SparkleProps = { left?: string; }; -function SvgSparkle(props: SparkleProps, ref: ForwardedRef) { +function SvgSparkle(props: SparkleProps, ref: Ref) { const SSparkle = Root; const { num, index, curve, left } = props; const rand = Math.floor(Math.random() * 50); @@ -43,4 +44,6 @@ function SvgSparkle(props: SparkleProps, ref: ForwardedRef) { ); } -export default createBaseComponent<'svg', SparkleProps>(SvgSparkle); +type SparkleComponent = Intergalactic.Component<'svg', SparkleProps>; + +export default createBaseComponent(SvgSparkle); diff --git a/semcore/feature-popover/src/FeaturePopover.tsx b/semcore/feature-popover/src/FeaturePopover.tsx index 367a7f82af..28a23e3201 100644 --- a/semcore/feature-popover/src/FeaturePopover.tsx +++ b/semcore/feature-popover/src/FeaturePopover.tsx @@ -1,8 +1,10 @@ +import type { PopperProps } from '@semcore/base-components'; import { Box, Popper, Animation } from '@semcore/base-components'; import Button from '@semcore/button'; import type { IRootComponentProps } from '@semcore/core'; import { createComponent, Root, Component, sstyled } from '@semcore/core'; import { callAllEventHandlers } from '@semcore/core/lib/utils/assignProps'; +import type { WithI18nEnhanceProps } from '@semcore/core/lib/utils/enhances/i18nEnhance'; import i18nEnhance from '@semcore/core/lib/utils/enhances/i18nEnhance'; import CloseIcon from '@semcore/icon/Close/m'; import React from 'react'; @@ -13,6 +15,7 @@ import type { FeaturePopoverSpotProps, FeaturePopoverPopperProps, FeaturePopoverPopperInnerProps, + FeaturePopoverDefaultProps, } from './FeaturePopover.type'; import style from './style/feature-popover.shadow.css'; import { localizedMessages } from './translations/__intergalactic-dynamic-locales'; @@ -45,14 +48,25 @@ const enhance = [ i18nEnhance(localizedMessages), ] as const; -class FeaturePopover extends Component { +type FeaturePopoverInternalProps = { + interaction?: PopperProps['interaction']; +}; + +class FeaturePopover extends Component< + FeaturePopoverProps, + typeof enhance, + { visible: null }, + WithI18nEnhanceProps & FeaturePopoverInternalProps, + {}, + FeaturePopoverDefaultProps +> { static displayName = 'FeaturePopover'; static style = style; - static defaultProps = { + static defaultProps: FeaturePopoverDefaultProps = { offset: [0, 12], placement: 'bottom-start', defaultVisible: false, - onOutsideClick: () => false, + onOutsideClick: () => {}, interaction: 'none', i18n: localizedMessages, locale: 'en', @@ -209,7 +223,10 @@ function Spot(props: IRootComponentProps & FeaturePopoverSpotProps) { return sstyled(styles)(); } -export default createComponent( +export default createComponent< + FeaturePopoverComponent, + typeof FeaturePopover +>( FeaturePopover, { Trigger: Trigger, @@ -218,4 +235,4 @@ export default createComponent( }, // @ts-ignore { parent: Popper }, -) as FeaturePopoverComponent; +); diff --git a/semcore/feature-popover/src/FeaturePopover.type.ts b/semcore/feature-popover/src/FeaturePopover.type.ts index 792386481a..c31fa79089 100644 --- a/semcore/feature-popover/src/FeaturePopover.type.ts +++ b/semcore/feature-popover/src/FeaturePopover.type.ts @@ -15,6 +15,8 @@ import type { Intergalactic, PropGetterFn } from '@semcore/core'; import type { UniqueIDProps } from '@semcore/core/lib/utils/uniqueID'; import type React from 'react'; +import type { LocalizedMessages } from './translations/__intergalactic-dynamic-locales'; + /** * Popper must have an accessible names (aria-group-name). */ @@ -112,6 +114,17 @@ export type FeaturePopoverProps = FPPopperProps & { theme?: 'accent' | 'neutral'; }; +export type FeaturePopoverDefaultProps = { + offset: FPPopperProps['offset']; + placement: 'bottom-start'; + defaultVisible: false; + onOutsideClick: () => void; + interaction: 'none'; + i18n: LocalizedMessages; + locale: 'en'; + theme: 'accent'; +}; + export type FeaturePopoverTriggerProps = BoxProps & { theme?: FeaturePopoverProps['theme']; }; diff --git a/semcore/feature-popover/src/translations/__intergalactic-dynamic-locales.ts b/semcore/feature-popover/src/translations/__intergalactic-dynamic-locales.ts index ccae777b73..65cdb67688 100644 --- a/semcore/feature-popover/src/translations/__intergalactic-dynamic-locales.ts +++ b/semcore/feature-popover/src/translations/__intergalactic-dynamic-locales.ts @@ -29,3 +29,5 @@ export const localizedMessages = { pl, sv, }; + +export type LocalizedMessages = typeof localizedMessages; diff --git a/semcore/feedback-form/src/component/checkbox-button/CheckboxButton.tsx b/semcore/feedback-form/src/component/checkbox-button/CheckboxButton.tsx index 453463da44..15ecd47e3e 100644 --- a/semcore/feedback-form/src/component/checkbox-button/CheckboxButton.tsx +++ b/semcore/feedback-form/src/component/checkbox-button/CheckboxButton.tsx @@ -4,7 +4,7 @@ import { createComponent, Component, Root, sstyled } from '@semcore/core'; import React from 'react'; import style from '../../style/checkbox-button.shadow.css'; -import type { FeedbackRatingCheckboxProps } from '../feedback-rating/FeedbackRating.type'; +import type { FeedbackRatingCheckboxComponent, FeedbackRatingCheckboxProps } from '../feedback-rating/FeedbackRating.type'; class CheckboxButtonRoot extends Component { static style = style; @@ -36,6 +36,9 @@ class CheckboxButtonRoot extends Component { } } -const CheckboxButton = createComponent(CheckboxButtonRoot); +const CheckboxButton = createComponent< + FeedbackRatingCheckboxComponent, + typeof CheckboxButtonRoot +>(CheckboxButtonRoot); export default CheckboxButton; diff --git a/semcore/feedback-form/src/component/feedback-rating/FeedbackRating.tsx b/semcore/feedback-form/src/component/feedback-rating/FeedbackRating.tsx index 6db57f85ba..3f1ce7042c 100644 --- a/semcore/feedback-form/src/component/feedback-rating/FeedbackRating.tsx +++ b/semcore/feedback-form/src/component/feedback-rating/FeedbackRating.tsx @@ -42,8 +42,9 @@ class FeedbackRatingRoot extends Component< FeedbackRatingProps, typeof FeedbackRatingRoot.enhance, {}, - FeedbackRatingDefaultProps, - State + {}, + State, + FeedbackRatingDefaultProps > { static displayName = 'FeedbackRatingForm'; static style = style; @@ -408,12 +409,7 @@ function Header(props: any) { ); } -const FeedbackRating = createComponent<'form', FeedbackRatingProps, {}, typeof FeedbackRatingRoot.enhance>(FeedbackRatingRoot, { - Header, - Item: FeedbackItem, - Checkbox: CheckboxButton, - Submit: SubmitButton, -}) as Intergalactic.Component<'form', FeedbackRatingProps, {}, typeof FeedbackRatingRoot.enhance> & { +type FeedbackRatingComponent = Intergalactic.Component<'form', FeedbackRatingProps, {}, typeof FeedbackRatingRoot.enhance> & { validate: typeof FeedbackRatingRoot.validate; Item: Intergalactic.Component<'div', FeedbackRatingItemProps>; Submit: typeof Button; @@ -421,4 +417,14 @@ const FeedbackRating = createComponent<'form', FeedbackRatingProps, {}, typeof F Header: typeof Text; }; +const FeedbackRating = createComponent< + FeedbackRatingComponent, + typeof FeedbackRatingRoot +>(FeedbackRatingRoot, { + Header, + Item: FeedbackItem, + Checkbox: CheckboxButton, + Submit: SubmitButton, +}); + export default FeedbackRating; diff --git a/semcore/feedback-form/src/component/feedback-rating/FeedbackRating.type.ts b/semcore/feedback-form/src/component/feedback-rating/FeedbackRating.type.ts index f18b255cfe..092d844fd3 100644 --- a/semcore/feedback-form/src/component/feedback-rating/FeedbackRating.type.ts +++ b/semcore/feedback-form/src/component/feedback-rating/FeedbackRating.type.ts @@ -6,7 +6,7 @@ import type React from 'react'; import type { FieldProps } from 'react-final-form'; import type { FeedbackFormProps } from '../../index'; -import type { localizedMessages } from '../../translations/__intergalactic-dynamic-locales'; +import type { LocalizedMessages } from '../../translations/__intergalactic-dynamic-locales'; export type FormConfigItem = { key: string; @@ -74,10 +74,12 @@ export type FeedbackRatingCheckboxProps = Omit & { label: React.ReactNode; }; +export type FeedbackRatingCheckboxComponent = Intergalactic.Component<'div', FeedbackRatingCheckboxProps>; + export type FeedbackRatingDefaultProps = { onSubmit: () => void; - i18n: typeof localizedMessages; + i18n: LocalizedMessages; locale: 'en'; - Illustration: Intergalactic.Component<'svg', IllustrationProps>; - Notice: typeof Notice; + Illustration: FeedbackRatingProps['Illustration']; + Notice: FeedbackRatingProps['Notice']; }; diff --git a/semcore/feedback-form/src/component/slider-rating/SliderRating.tsx b/semcore/feedback-form/src/component/slider-rating/SliderRating.tsx index d99d96ee95..4eac3f9957 100644 --- a/semcore/feedback-form/src/component/slider-rating/SliderRating.tsx +++ b/semcore/feedback-form/src/component/slider-rating/SliderRating.tsx @@ -1,10 +1,12 @@ import { Flex, Box, type BoxProps } from '@semcore/base-components'; import { createComponent, Component, Root, sstyled, type Intergalactic } from '@semcore/core'; +import type { WithI18nEnhanceProps } from '@semcore/core/lib/utils/enhances/i18nEnhance'; import i18nEnhance from '@semcore/core/lib/utils/enhances/i18nEnhance'; import uniqueIDEnhancement from '@semcore/core/lib/utils/uniqueID'; import React from 'react'; import style from '../../style/slider-rating.shadow.css'; +import type { LocalizedMessages } from '../../translations/__intergalactic-dynamic-locales'; import { localizedMessages } from '../../translations/__intergalactic-dynamic-locales'; type SliderRatingProps = { @@ -13,6 +15,11 @@ type SliderRatingProps = { readonly?: boolean; }; +type SliderRatingDefaultProps = { + i18n: LocalizedMessages; + locale: 'en'; +}; + type State = { hoveredIndex: number; clickedIndex: number; @@ -22,6 +29,10 @@ type StarProps = BoxProps & { filled?: boolean; }; +type SliderRatingComponent = Intergalactic.Component & { + Star: Intergalactic.Component; +}; + const MIN = 1; const MAX = 5; @@ -29,8 +40,9 @@ class SliderRatingRoot extends Component< SliderRatingProps, typeof SliderRatingRoot.enhance, {}, - {}, - State + WithI18nEnhanceProps, + State, + SliderRatingDefaultProps > { static displayName = 'SliderRating'; static style = style; @@ -45,7 +57,7 @@ class SliderRatingRoot extends Component< static defaultProps = { i18n: localizedMessages, locale: 'en', - }; + } as const; handleClick = (newValue: number) => (_e: React.SyntheticEvent) => { const { readonly } = this.asProps; @@ -211,10 +223,11 @@ function Star(props: StarProps) { } Star.displayName = 'Star'; -const SliderRating = createComponent(SliderRatingRoot, { +const SliderRating = createComponent< + SliderRatingComponent, + typeof SliderRatingRoot +>(SliderRatingRoot, { Star, -}) as Intergalactic.Component & { - Star: Intergalactic.Component; -}; +}); export default SliderRating; diff --git a/semcore/feedback-form/src/translations/__intergalactic-dynamic-locales.ts b/semcore/feedback-form/src/translations/__intergalactic-dynamic-locales.ts index ccae777b73..65cdb67688 100644 --- a/semcore/feedback-form/src/translations/__intergalactic-dynamic-locales.ts +++ b/semcore/feedback-form/src/translations/__intergalactic-dynamic-locales.ts @@ -29,3 +29,5 @@ export const localizedMessages = { pl, sv, }; + +export type LocalizedMessages = typeof localizedMessages; diff --git a/semcore/icon/src/Icon.tsx b/semcore/icon/src/Icon.tsx index 57dbe82172..3debe9423e 100644 --- a/semcore/icon/src/Icon.tsx +++ b/semcore/icon/src/Icon.tsx @@ -1,3 +1,4 @@ +import type { Intergalactic } from '@semcore/core'; import { createBaseComponent, sstyled } from '@semcore/core'; import { removeUndefinedKeys, getAutoOrScaleIndent } from '@semcore/core/lib/utils/indentStyles'; import propsForElement from '@semcore/core/lib/utils/propsForElement'; @@ -85,7 +86,7 @@ function Icon({ mr, mx, ...props -}: React.SVGProps & IconProps, ref: React.ForwardedRef) { +}: React.SVGProps & IconProps, ref: React.Ref) { const SIcon = 'svg'; const resolveColor = useColorResolver(); @@ -123,4 +124,6 @@ function Icon({ ); } -export default createBaseComponent<'svg', IconProps>(Icon); +type IconComponent = Intergalactic.Component<'svg', IconProps>; + +export default createBaseComponent(Icon); diff --git a/semcore/inline-edit/src/InlineEdit.tsx b/semcore/inline-edit/src/InlineEdit.tsx index dfec98d13c..7fe8d8ae97 100644 --- a/semcore/inline-edit/src/InlineEdit.tsx +++ b/semcore/inline-edit/src/InlineEdit.tsx @@ -7,6 +7,7 @@ import { type Intergalactic, type PropGetterFn, } from '@semcore/core'; +import type { WithI18nEnhanceProps } from '@semcore/core/lib/utils/enhances/i18nEnhance'; import i18nEnhance from '@semcore/core/lib/utils/enhances/i18nEnhance'; import getOriginChildren from '@semcore/core/lib/utils/getOriginChildren'; import reactToText from '@semcore/core/lib/utils/reactToText'; @@ -14,6 +15,7 @@ import { useCssVariable } from '@semcore/core/lib/utils/useCssVariable'; import React from 'react'; import style from './style/inline-edit.shadow.css'; +import type { LocalizedMessages } from './translations/__intergalactic-dynamic-locales'; import { localizedMessages } from './translations/__intergalactic-dynamic-locales'; type AsProps = { @@ -25,7 +27,14 @@ type AsProps = { getI18nText: (messageId: string, values?: { [key: string]: string | number }) => string; }; -class InlineEdit extends Component { +class InlineEdit extends Component< + AsProps, + [], + { editable: null }, + WithI18nEnhanceProps, + {}, + InlineEditDefaultProps +> { static displayName = 'InlineEdit'; static style = style; @@ -35,7 +44,7 @@ class InlineEdit extends Component { defaultEditable: false, i18n: localizedMessages, locale: 'en', - }; + } as const; viewRef = React.createRef(); @@ -183,6 +192,11 @@ type InlineEditProps = BoxProps & { onEdit?: () => void; locale?: string; }; +type InlineEditDefaultProps = { + defaultEditable: false; + i18n: LocalizedMessages; + locale: 'en'; +}; type InlineEditViewProps = BoxProps & FadeInOutProps & {}; type InlineEditEditProps = BoxProps & FadeInOutProps & {}; @@ -191,10 +205,15 @@ type InputCtx = { getEditProps: PropGetterFn; }; -export default createComponent(InlineEdit, { - Edit, - View, -}) as Intergalactic.Component<'div', InlineEditProps, InputCtx> & { +type InlineEditComponent = Intergalactic.Component<'div', InlineEditProps, InputCtx> & { View: Intergalactic.Component<'div', InlineEditViewProps, InlineEditProps>; Edit: Intergalactic.Component<'div', InlineEditEditProps, InlineEditProps>; }; + +export default createComponent< + InlineEditComponent, + typeof InlineEdit +>(InlineEdit, { + Edit, + View, +}); diff --git a/semcore/inline-edit/src/translations/__intergalactic-dynamic-locales.ts b/semcore/inline-edit/src/translations/__intergalactic-dynamic-locales.ts index ccae777b73..65cdb67688 100644 --- a/semcore/inline-edit/src/translations/__intergalactic-dynamic-locales.ts +++ b/semcore/inline-edit/src/translations/__intergalactic-dynamic-locales.ts @@ -29,3 +29,5 @@ export const localizedMessages = { pl, sv, }; + +export type LocalizedMessages = typeof localizedMessages; diff --git a/semcore/inline-input/src/InlineInput.tsx b/semcore/inline-input/src/InlineInput.tsx index 2ebbdcb4b7..76b1e4f2bd 100644 --- a/semcore/inline-input/src/InlineInput.tsx +++ b/semcore/inline-input/src/InlineInput.tsx @@ -1,6 +1,7 @@ import { Box, InvalidStateBox } from '@semcore/base-components'; import { ButtonLink } from '@semcore/button'; import { createComponent, Component, sstyled, Root } from '@semcore/core'; +import type { WithI18nEnhanceProps } from '@semcore/core/lib/utils/enhances/i18nEnhance'; import i18nEnhance from '@semcore/core/lib/utils/enhances/i18nEnhance'; import { hasParent } from '@semcore/core/lib/utils/hasParent'; import CheckM from '@semcore/icon/Check/m'; @@ -12,6 +13,7 @@ import React from 'react'; import type { InlineInputComponent } from './index.type'; import style from './style/inline-input.shadow.css'; +import type { LocalizedMessages } from './translations/__intergalactic-dynamic-locales'; import { localizedMessages } from './translations/__intergalactic-dynamic-locales'; type OnConfirm = ( @@ -75,6 +77,12 @@ type NumberControlsAsProps = ControlAsProps & { increment?: (event: React.SyntheticEvent) => void; decrement?: (event: React.SyntheticEvent) => void; }; +type DefaultProps = { + state: 'normal'; + onBlurBehavior: 'confirm'; + i18n: LocalizedMessages; + locale: 'en'; +}; const pointInsideOfRect = ({ x, @@ -88,7 +96,14 @@ const pointInsideOfRect = ({ return x >= rect.x && x <= rect.x + rect.width && y >= rect.y && y <= rect.y + rect.height; }; -class InlineInputBase extends Component { +class InlineInputBase extends Component< + RootAsProps, + [], + {}, + WithI18nEnhanceProps, + {}, + DefaultProps +> { static displayName = 'InlineInput'; static enhance = [i18nEnhance(localizedMessages)]; @@ -97,7 +112,7 @@ class InlineInputBase extends Component { onBlurBehavior: 'confirm', i18n: localizedMessages, locale: 'en', - }; + } as const; static style = style; @@ -426,13 +441,16 @@ function NumberControls(props: NumberControlsAsProps) { } /** `createComponent` currently exposes unrelated junk instead of typings, that the reason of to any cast */ -const InlineInput = createComponent(InlineInputBase, { +const InlineInput = createComponent< + InlineInputComponent, + typeof InlineInputBase +>(InlineInputBase, { Addon, Value, ConfirmControl, CancelControl, NumberValue, NumberControls, -}) as InlineInputComponent; +}); export default InlineInput; diff --git a/semcore/inline-input/src/translations/__intergalactic-dynamic-locales.ts b/semcore/inline-input/src/translations/__intergalactic-dynamic-locales.ts index ccae777b73..65cdb67688 100644 --- a/semcore/inline-input/src/translations/__intergalactic-dynamic-locales.ts +++ b/semcore/inline-input/src/translations/__intergalactic-dynamic-locales.ts @@ -29,3 +29,5 @@ export const localizedMessages = { pl, sv, }; + +export type LocalizedMessages = typeof localizedMessages; diff --git a/semcore/input-mask/src/InputMask.tsx b/semcore/input-mask/src/InputMask.tsx index 06a12f5a3a..395175e0c1 100644 --- a/semcore/input-mask/src/InputMask.tsx +++ b/semcore/input-mask/src/InputMask.tsx @@ -85,6 +85,11 @@ type InputMaskCtx = { getValueProps: PropGetterFn; }; +type InputMaskComponent = Intergalactic.Component<'div', InputProps, InputMaskCtx> & { + Value: Intergalactic.Component<'input', InputMaskValueProps>; + Addon: typeof Input.Addon; +}; + const { createTextMaskInputElement } = mask; export function getAfterPositionValue(value: string, mask: any = ''): number { @@ -393,10 +398,7 @@ class Value extends Component(InputMask, { Value, Addon: Input.Addon, -}) as any as Intergalactic.Component<'div', InputProps, InputMaskCtx> & { - Value: Intergalactic.Component<'input', InputMaskValueProps>; - Addon: typeof Input.Addon; -}; +}); diff --git a/semcore/input-tags/src/InputTags.tsx b/semcore/input-tags/src/InputTags.tsx index 6f64041b1c..6a97256d0d 100644 --- a/semcore/input-tags/src/InputTags.tsx +++ b/semcore/input-tags/src/InputTags.tsx @@ -9,6 +9,7 @@ import { type Intergalactic, type IRootComponentProps, } from '@semcore/core'; +import type { WithI18nEnhanceProps } from '@semcore/core/lib/utils/enhances/i18nEnhance'; import i18nEnhance from '@semcore/core/lib/utils/enhances/i18nEnhance'; import { extractFrom, isAdvanceMode } from '@semcore/core/lib/utils/findComponent'; import fire from '@semcore/core/lib/utils/fire'; @@ -19,6 +20,7 @@ import Tag, { type TagProps, TagContainer, type TagTextProps, type TagContext } import React from 'react'; import style from './style/input-tag.shadow.css'; +import type { LocalizedMessages } from './translations/__intergalactic-dynamic-locales'; import { localizedMessages } from './translations/__intergalactic-dynamic-locales'; export type InputTagsValueProps = InputValueProps & {}; @@ -44,6 +46,13 @@ export type InputTagsProps = Omit & locale?: string; }; +export type InputTagsDefaultProps = { + size: 'm'; + delimiters: InputTagsProps['delimiters']; + i18n: LocalizedMessages; + locale: 'en'; +}; + export type InputTagsTagProps = TagProps & { /** Property enabling the ability to remove a tag on click */ editable?: boolean; @@ -54,16 +63,35 @@ export type InputTagsContext = InputTagsProps & { getTagProps: PropGetterFn; }; -class InputTagsRoot extends Component { +export type InputTagsComponent = Intergalactic.Component<'div', InputTagsProps, InputTagsContext> & { + Value: typeof Input.Value; + TagsContainer: Intergalactic.Component<'ul'>; + Tag: Intergalactic.Component<'div', InputTagsTagProps> & { + Text: Intergalactic.Component<'div', TagProps, TagContext> & { + Content: Intergalactic.Component<'div', TagTextProps>; + }; + Close: typeof TagContainer.Close; + Addon: typeof Tag.Addon; + Circle: typeof Tag.Circle; + }; +}; + +class InputTagsRoot extends Component< + InputTagsProps, + typeof InputTagsRoot.enhance, + {}, + WithI18nEnhanceProps, + {}, + InputTagsDefaultProps +> { static displayName = 'InputTags'; static style = style; static enhance = [uniqueIDEnhancement(), i18nEnhance(localizedMessages)] as const; static defaultProps = { - size: 'm', + size: 'm' as const, delimiters: [',', ';', '|', 'Enter', 'Tab'], - defaultValue: '', i18n: localizedMessages, - locale: 'en', + locale: 'en' as const, }; inputRef = React.createRef(); @@ -383,7 +411,10 @@ function TagCloseButton(props: IRootComponentProps) { return sstyled(props.styles)(); } -const InputTags = createComponent(InputTagsRoot, { +const InputTags = createComponent< + InputTagsComponent, + typeof InputTagsRoot +>(InputTagsRoot, { Value, TagsContainer: InputTagsContainer, Tag: [ @@ -395,17 +426,6 @@ const InputTags = createComponent(InputTagsRoot, { Circle: TagContainer.Circle, }, ], -}) as Intergalactic.Component<'div', InputTagsProps, InputTagsContext> & { - Value: typeof Input.Value; - TagsContainer: Intergalactic.Component<'ul'>; - Tag: Intergalactic.Component<'div', InputTagsTagProps> & { - Text: Intergalactic.Component<'div', TagProps, TagContext> & { - Content: Intergalactic.Component<'div', TagTextProps>; - }; - Close: typeof TagContainer.Close; - Addon: typeof Tag.Addon; - Circle: typeof Tag.Circle; - }; -}; +}); export default InputTags; diff --git a/semcore/input-tags/src/translations/__intergalactic-dynamic-locales.ts b/semcore/input-tags/src/translations/__intergalactic-dynamic-locales.ts index ccae777b73..65cdb67688 100644 --- a/semcore/input-tags/src/translations/__intergalactic-dynamic-locales.ts +++ b/semcore/input-tags/src/translations/__intergalactic-dynamic-locales.ts @@ -29,3 +29,5 @@ export const localizedMessages = { pl, sv, }; + +export type LocalizedMessages = typeof localizedMessages; diff --git a/semcore/link/src/Link.tsx b/semcore/link/src/Link.tsx index 0cc896ac88..4c0ea6fdbc 100644 --- a/semcore/link/src/Link.tsx +++ b/semcore/link/src/Link.tsx @@ -10,7 +10,7 @@ import type { NSText } from '@semcore/typography'; import { Text } from '@semcore/typography'; import React from 'react'; -import type { LinkProps } from './Link.types'; +import type { LinkComponent, LinkProps } from './Link.types'; import style from './style/link.shadow.css'; type State = { @@ -140,12 +140,9 @@ function Addon(props: IRootComponentProps) { return sstyled(styles)(); } -const Link = createComponent(RootLink, { +const Link = createComponent(RootLink, { Text: LinkText, Addon, -}) as Intergalactic.Component<'a', LinkProps, {}, typeof RootLink.enhance> & { - Text: Intergalactic.Component<'span', NSText.Props>; - Addon: Intergalactic.Component<'span', BoxProps>; -}; +}); export default Link; diff --git a/semcore/link/src/Link.types.ts b/semcore/link/src/Link.types.ts index 2eb444b89c..92eceb3ce9 100644 --- a/semcore/link/src/Link.types.ts +++ b/semcore/link/src/Link.types.ts @@ -1,4 +1,5 @@ import type { BoxProps, SimpleHintPopperProps } from '@semcore/base-components'; +import type { Intergalactic, IRootComponentProps } from '@semcore/core'; import type { NSText } from '@semcore/typography'; import type React from 'react'; @@ -34,3 +35,8 @@ export type LinkProps = BoxProps & NSText.BaseProps & { */ hintPlacement?: SimpleHintPopperProps['placement']; }; + +export type LinkComponent = Intergalactic.Component<'a', LinkProps> & { + Text: Intergalactic.Component<'span', NSText.Props>; + Addon: Intergalactic.Component<'span', BoxProps>; +}; diff --git a/semcore/mini-chart/src/component/score/Donut.tsx b/semcore/mini-chart/src/component/score/Donut.tsx index ba4f37773e..7bda790ee6 100644 --- a/semcore/mini-chart/src/component/score/Donut.tsx +++ b/semcore/mini-chart/src/component/score/Donut.tsx @@ -1,4 +1,5 @@ import { Box, type BoxProps } from '@semcore/base-components'; +import type { Intergalactic } from '@semcore/core'; import { createComponent, Component, Root, sstyled, assignProps } from '@semcore/core'; import { extractAriaProps } from '@semcore/core/lib/utils/ariaProps'; import resolveColorEnhance from '@semcore/core/lib/utils/enhances/resolveColorEnhance'; @@ -11,7 +12,19 @@ import { ScoreDonutUtils } from '../../utils/ScoreDonutUtils'; export type ScoreDonutProps = BoxProps & CommonScoreProps; -class DonutRoot extends Component { +type ScoreDonutDefaultProps = { + animate: true; +}; + +type ScoreDonutComponent = Intergalactic.Component<'svg', ScoreDonutProps, {}, typeof DonutRoot.enhance>; +class DonutRoot extends Component< + ScoreDonutProps, + typeof DonutRoot.enhance, + {}, + {}, + {}, + ScoreDonutDefaultProps +> { static enhance = [ cssVariableEnhance({ variable: '--intergalactic-duration-extra-slow', @@ -26,7 +39,7 @@ class DonutRoot extends Component { static defaultProps = { animate: true, - }; + } as const; render() { const SDonutContainer = Root; @@ -114,11 +127,17 @@ class DonutRoot extends Component { } } -export const ScoreDonut = createComponent<'svg', ScoreDonutProps, {}, typeof DonutRoot.enhance>(DonutRoot); +export const ScoreDonut = createComponent< + ScoreDonutComponent, + typeof DonutRoot +>(DonutRoot); ScoreDonut.displayName = 'MiniChart.ScoreDonut'; -export const ScoreSemiDonut = createComponent<'svg', ScoreDonutProps, {}, typeof DonutRoot.enhance>( +export const ScoreSemiDonut = createComponent< + ScoreDonutComponent, + typeof DonutRoot +>( DonutRoot, {}, { diff --git a/semcore/mini-chart/src/component/score/Line.tsx b/semcore/mini-chart/src/component/score/Line.tsx index 225efb73c4..317e5321fe 100644 --- a/semcore/mini-chart/src/component/score/Line.tsx +++ b/semcore/mini-chart/src/component/score/Line.tsx @@ -9,9 +9,17 @@ import type { ScoreLineGaugeProps, SegmentProps, InnerSegmentProps, + ScoreLineGaugeDefaultProps, } from './Line.types'; -class LineRoot extends Component { +class LineRoot extends Component< + ScoreLineGaugeProps, + typeof LineRoot.enhance, + {}, + {}, + {}, + ScoreLineGaugeDefaultProps +> { static enhance = [resolveColorEnhance()] as const; static displayName = 'ScoreLine'; @@ -19,7 +27,7 @@ class LineRoot extends Component { static defaultProps = { animate: true, - }; + } as const; getSegmentProps(segmentProps: SegmentProps) { const { children, resolveColor } = this.asProps; @@ -114,8 +122,9 @@ function Segment(props: InnerSegmentProps) { } Segment.displayName = 'Segment'; -export const ScoreLine = createComponent(LineRoot, { - Segment, -}) as ScoreLineComponent; +export const ScoreLine = createComponent< + ScoreLineComponent, + typeof LineRoot +>(LineRoot, { Segment }); ScoreLine.displayName = 'MiniChart.ScoreLine'; diff --git a/semcore/mini-chart/src/component/score/Line.types.ts b/semcore/mini-chart/src/component/score/Line.types.ts index e870d2507d..cb111657eb 100644 --- a/semcore/mini-chart/src/component/score/Line.types.ts +++ b/semcore/mini-chart/src/component/score/Line.types.ts @@ -54,6 +54,10 @@ export type ScoreLineGaugeProps = BoxProps & Intergalactic.InternalTypings.EfficientOmit & (ValuedScoreProps | CustomRenderScoreProps); +export type ScoreLineGaugeDefaultProps = { + animate: true; +}; + export type Enhances = [() => { resolveColor: ReturnType; }]; diff --git a/semcore/mini-chart/src/component/trend/Bar.tsx b/semcore/mini-chart/src/component/trend/Bar.tsx index 3c5ba08751..48c001542a 100644 --- a/semcore/mini-chart/src/component/trend/Bar.tsx +++ b/semcore/mini-chart/src/component/trend/Bar.tsx @@ -1,4 +1,5 @@ import { Box } from '@semcore/base-components'; +import type { Intergalactic } from '@semcore/core'; import { createComponent, assignProps, Root, sstyled } from '@semcore/core'; import { extractAriaProps } from '@semcore/core/lib/utils/ariaProps'; import resolveColorEnhance from '@semcore/core/lib/utils/enhances/resolveColorEnhance'; @@ -25,14 +26,20 @@ export type TrendBarProps = CommonTrendProps & { data: BarItem[]; }; -class TrendBarRoot extends Trend { +type TrendBarComponent = Intergalactic.Component<'svg', TrendBarProps, {}, typeof TrendBarRoot.enhance>; + +type TrendBarDefaultProps = { + animate: true; +}; + +class TrendBarRoot extends Trend { static enhance = [resolveColorEnhance()] as const; static style = style; static defaultProps = { animate: true, - }; + } as const; get defaultData(): BarItem[] { return [{ value: 20 }, { value: 80 }, { value: 45 }, { value: 10 }]; @@ -95,11 +102,17 @@ class TrendBarRoot extends Trend { } } -export const TrendBar = createComponent<'svg', TrendBarProps, {}, typeof TrendBarRoot.enhance>(TrendBarRoot); +export const TrendBar = createComponent< + TrendBarComponent, + typeof TrendBarRoot +>(TrendBarRoot); TrendBar.displayName = 'MiniChart.TrendBar'; -export const TrendHistogram = createComponent<'svg', TrendBarProps, {}, typeof TrendBarRoot.enhance>( +export const TrendHistogram = createComponent< + TrendBarComponent, + typeof TrendBarRoot +>( TrendBarRoot, {}, { diff --git a/semcore/mini-chart/src/component/trend/Line.tsx b/semcore/mini-chart/src/component/trend/Line.tsx index 2541c9a798..e41cb5e6fb 100644 --- a/semcore/mini-chart/src/component/trend/Line.tsx +++ b/semcore/mini-chart/src/component/trend/Line.tsx @@ -1,4 +1,5 @@ import { Box } from '@semcore/base-components'; +import type { Intergalactic } from '@semcore/core'; import { createComponent, assignProps, Root, sstyled } from '@semcore/core'; import { extractAriaProps } from '@semcore/core/lib/utils/ariaProps'; import resolveColorEnhance from '@semcore/core/lib/utils/enhances/resolveColorEnhance'; @@ -30,14 +31,20 @@ export type TrendLineProps = CommonTrendProps & { lastPointRadius?: number; }; -class TrendLineRoot extends Trend { +type TrendLineComponent = Intergalactic.Component<'svg', TrendLineProps, {}, typeof TrendLineRoot.enhance>; + +type TrendLineDefaultProps = { + animate: true; +}; + +class TrendLineRoot extends Trend { static enhance = [resolveColorEnhance(), uniqueIDEnhancement()] as const; static style = style; static defaultProps = { animate: true, - }; + } as const; get defaultData(): number[] { return [15, 70, 20, 85, 20]; @@ -143,11 +150,11 @@ class TrendLineRoot extends Trend } } -export const TrendLine = createComponent<'svg', TrendLineProps, {}, typeof TrendLineRoot.enhance>(TrendLineRoot); +export const TrendLine = createComponent(TrendLineRoot); TrendLine.displayName = 'MiniChart.TrendLine'; -export const TrendArea = createComponent<'svg', TrendLineProps, {}, typeof TrendLineRoot.enhance>( +export const TrendArea = createComponent( TrendLineRoot, {}, { diff --git a/semcore/mini-chart/src/component/trend/Trend.tsx b/semcore/mini-chart/src/component/trend/Trend.tsx index adcc485504..9cbef88100 100644 --- a/semcore/mini-chart/src/component/trend/Trend.tsx +++ b/semcore/mini-chart/src/component/trend/Trend.tsx @@ -1,4 +1,5 @@ import type { BoxProps } from '@semcore/base-components'; +import type { Intergalactic } from '@semcore/core'; import { Component } from '@semcore/core'; import React from 'react'; @@ -21,10 +22,13 @@ export type CommonTrendProps = BoxProps & { data: any[]; }; +type CommonTrendState = { width: number; height: number }; + export abstract class Trend< P extends CommonTrendProps, E extends readonly ((...args: any[]) => any)[], -> extends Component, { width: number; height: number }> { + DP extends Intergalactic.InternalTypings.ValidDefaultProps = never, +> extends Component, {}, CommonTrendState, DP> { state = { width: 200, height: 100, diff --git a/semcore/modal/__tests__/index.test.tsx b/semcore/modal/__tests__/index.test.tsx index e9fed6e586..f92772e8ab 100644 --- a/semcore/modal/__tests__/index.test.tsx +++ b/semcore/modal/__tests__/index.test.tsx @@ -80,7 +80,7 @@ describe('Modal', () => { const { getByTestId, queryByText } = render(); getByTestId('close-modal').click(); - await new Promise((r) => setTimeout(r, 50)); + await new Promise((r) => setTimeout(r, 100)); expect(queryByText('Hello world')).toBeNull(); }); diff --git a/semcore/notice-bubble/__tests__/notice-bubble.browser-test.tsx-snapshots/-visual-Verify-notice-with-illustration-1-chromium-linux.png b/semcore/notice-bubble/__tests__/notice-bubble.browser-test.tsx-snapshots/-visual-Verify-notice-with-illustration-1-chromium-linux.png index 6eb14a9070..d8c83b8957 100644 Binary files a/semcore/notice-bubble/__tests__/notice-bubble.browser-test.tsx-snapshots/-visual-Verify-notice-with-illustration-1-chromium-linux.png and b/semcore/notice-bubble/__tests__/notice-bubble.browser-test.tsx-snapshots/-visual-Verify-notice-with-illustration-1-chromium-linux.png differ diff --git a/semcore/notice-bubble/__tests__/notice-bubble.browser-test.tsx-snapshots/-visual-Verify-notice-with-illustration-1-firefox-linux.png b/semcore/notice-bubble/__tests__/notice-bubble.browser-test.tsx-snapshots/-visual-Verify-notice-with-illustration-1-firefox-linux.png index 8878866b6c..defafe29e5 100644 Binary files a/semcore/notice-bubble/__tests__/notice-bubble.browser-test.tsx-snapshots/-visual-Verify-notice-with-illustration-1-firefox-linux.png and b/semcore/notice-bubble/__tests__/notice-bubble.browser-test.tsx-snapshots/-visual-Verify-notice-with-illustration-1-firefox-linux.png differ diff --git a/semcore/notice-bubble/__tests__/notice-bubble.browser-test.tsx-snapshots/-visual-Verify-notice-with-illustration-1-webkit-linux.png b/semcore/notice-bubble/__tests__/notice-bubble.browser-test.tsx-snapshots/-visual-Verify-notice-with-illustration-1-webkit-linux.png index 18488c36eb..fa7ed59f51 100644 Binary files a/semcore/notice-bubble/__tests__/notice-bubble.browser-test.tsx-snapshots/-visual-Verify-notice-with-illustration-1-webkit-linux.png and b/semcore/notice-bubble/__tests__/notice-bubble.browser-test.tsx-snapshots/-visual-Verify-notice-with-illustration-1-webkit-linux.png differ diff --git a/semcore/notice-bubble/src/NoticeBubble.tsx b/semcore/notice-bubble/src/NoticeBubble.tsx index a367b19d0e..85d1be2315 100644 --- a/semcore/notice-bubble/src/NoticeBubble.tsx +++ b/semcore/notice-bubble/src/NoticeBubble.tsx @@ -2,6 +2,7 @@ import { Animation, Box, Flex, Portal } from '@semcore/base-components'; import Button from '@semcore/button'; import { createComponent, Component, sstyled, Root } from '@semcore/core'; import type { Intergalactic } from '@semcore/core'; +import type { WithI18nEnhanceProps } from '@semcore/core/lib/utils/enhances/i18nEnhance'; import i18nEnhance from '@semcore/core/lib/utils/enhances/i18nEnhance'; import fire from '@semcore/core/lib/utils/fire'; import { getFocusableIn } from '@semcore/core/lib/utils/focus-lock/getFocusableIn'; @@ -18,6 +19,7 @@ import CloseIcon from '@semcore/icon/Close/m'; import React from 'react'; import type { + NoticeBubbleContainerDefaultProps, NoticeBubbleContainerProps, NoticeBubbleViewItemProps, } from './NoticeBubble.type'; @@ -33,7 +35,14 @@ type State = { warnings: NoticeItem[]; }; -class NoticeBubbleContainerRoot extends Component { +class NoticeBubbleContainerRoot extends Component< + NoticeBubbleContainerProps, + typeof NoticeBubbleContainerRoot.enhance, + {}, + WithI18nEnhanceProps, + State, + NoticeBubbleContainerDefaultProps +> { static displayName = 'NoticeBubbleContainer'; static style = style; static enhance = [ @@ -347,6 +356,9 @@ class ViewWarning extends ViewInfo { }; } -const NoticeBubbleContainer = createComponent(NoticeBubbleContainerRoot) as Intergalactic.Component<'div', NoticeBubbleContainerProps>; +const NoticeBubbleContainer = createComponent< + Intergalactic.Component<'div', NoticeBubbleContainerProps>, + typeof NoticeBubbleContainerRoot +>(NoticeBubbleContainerRoot); export default NoticeBubbleContainer; diff --git a/semcore/notice-bubble/src/NoticeBubble.type.ts b/semcore/notice-bubble/src/NoticeBubble.type.ts index 497b923445..753501cbad 100644 --- a/semcore/notice-bubble/src/NoticeBubble.type.ts +++ b/semcore/notice-bubble/src/NoticeBubble.type.ts @@ -3,6 +3,9 @@ import type { Intergalactic } from '@semcore/core'; import type { useI18n } from '@semcore/core/lib/utils/enhances/WithI18n'; import type { RefObject } from 'react'; +import type { NoticeBubbleManager, NoticeItem } from './NoticeBubbleManager'; +import type { LocalizedMessages } from './translations/__intergalactic-dynamic-locales'; + /** * @deprecated. Pass noticeBubbleContainer property from window.sm2.getNoticeBubbleContainer() */ @@ -18,6 +21,12 @@ export type NoticeBubbleContainerProps = BoxProps & locale?: string; }; +export type NoticeBubbleContainerDefaultProps = { + manager: NoticeBubbleManagerClass; + i18n: LocalizedMessages; + locale: 'en'; +}; + export type NoticeBubbleViewItemProps = NoticeBubbleProps & { containerNode?: HTMLElement; animationDuration: number; @@ -96,6 +105,8 @@ export type NoticeBubbleManagerClass = { * Replace last notice (if it is existing) */ replaceLast: (props: NoticeBubbleInfoProps | NoticeBubbleWarningProps) => void; + /** Add change listener */ + addListener: (fn: (items: NoticeItem[]) => void) => (() => void); }; export declare const NoticeBubbleContainer: Intergalactic.Component< diff --git a/semcore/notice-bubble/src/translations/__intergalactic-dynamic-locales.ts b/semcore/notice-bubble/src/translations/__intergalactic-dynamic-locales.ts index ccae777b73..65cdb67688 100644 --- a/semcore/notice-bubble/src/translations/__intergalactic-dynamic-locales.ts +++ b/semcore/notice-bubble/src/translations/__intergalactic-dynamic-locales.ts @@ -29,3 +29,5 @@ export const localizedMessages = { pl, sv, }; + +export type LocalizedMessages = typeof localizedMessages; diff --git a/semcore/notice/__tests__/notice.browser-test.tsx-snapshots/-visual-Verify-notice-with-big-illustrations-1-chromium-linux.png b/semcore/notice/__tests__/notice.browser-test.tsx-snapshots/-visual-Verify-notice-with-big-illustrations-1-chromium-linux.png index c4727a11c4..fccf12eb29 100644 Binary files a/semcore/notice/__tests__/notice.browser-test.tsx-snapshots/-visual-Verify-notice-with-big-illustrations-1-chromium-linux.png and b/semcore/notice/__tests__/notice.browser-test.tsx-snapshots/-visual-Verify-notice-with-big-illustrations-1-chromium-linux.png differ diff --git a/semcore/notice/__tests__/notice.browser-test.tsx-snapshots/-visual-Verify-notice-with-big-illustrations-1-firefox-linux.png b/semcore/notice/__tests__/notice.browser-test.tsx-snapshots/-visual-Verify-notice-with-big-illustrations-1-firefox-linux.png index fa9cbc1f8d..f3940707a6 100644 Binary files a/semcore/notice/__tests__/notice.browser-test.tsx-snapshots/-visual-Verify-notice-with-big-illustrations-1-firefox-linux.png and b/semcore/notice/__tests__/notice.browser-test.tsx-snapshots/-visual-Verify-notice-with-big-illustrations-1-firefox-linux.png differ diff --git a/semcore/notice/__tests__/notice.browser-test.tsx-snapshots/-visual-Verify-notice-with-big-illustrations-1-webkit-linux.png b/semcore/notice/__tests__/notice.browser-test.tsx-snapshots/-visual-Verify-notice-with-big-illustrations-1-webkit-linux.png index 1a27c3bb02..fb48ad90ee 100644 Binary files a/semcore/notice/__tests__/notice.browser-test.tsx-snapshots/-visual-Verify-notice-with-big-illustrations-1-webkit-linux.png and b/semcore/notice/__tests__/notice.browser-test.tsx-snapshots/-visual-Verify-notice-with-big-illustrations-1-webkit-linux.png differ diff --git a/semcore/notice/__tests__/notice.browser-test.tsx-snapshots/-visual-Verify-notice-with-medium-illustrations-1-chromium-linux.png b/semcore/notice/__tests__/notice.browser-test.tsx-snapshots/-visual-Verify-notice-with-medium-illustrations-1-chromium-linux.png index 416cfe5533..e7141e7c7e 100644 Binary files a/semcore/notice/__tests__/notice.browser-test.tsx-snapshots/-visual-Verify-notice-with-medium-illustrations-1-chromium-linux.png and b/semcore/notice/__tests__/notice.browser-test.tsx-snapshots/-visual-Verify-notice-with-medium-illustrations-1-chromium-linux.png differ diff --git a/semcore/notice/__tests__/notice.browser-test.tsx-snapshots/-visual-Verify-notice-with-medium-illustrations-1-firefox-linux.png b/semcore/notice/__tests__/notice.browser-test.tsx-snapshots/-visual-Verify-notice-with-medium-illustrations-1-firefox-linux.png index 37355a49e2..ebad5e1cbd 100644 Binary files a/semcore/notice/__tests__/notice.browser-test.tsx-snapshots/-visual-Verify-notice-with-medium-illustrations-1-firefox-linux.png and b/semcore/notice/__tests__/notice.browser-test.tsx-snapshots/-visual-Verify-notice-with-medium-illustrations-1-firefox-linux.png differ diff --git a/semcore/notice/__tests__/notice.browser-test.tsx-snapshots/-visual-Verify-notice-with-medium-illustrations-1-webkit-linux.png b/semcore/notice/__tests__/notice.browser-test.tsx-snapshots/-visual-Verify-notice-with-medium-illustrations-1-webkit-linux.png index 7c07974cb7..834e268299 100644 Binary files a/semcore/notice/__tests__/notice.browser-test.tsx-snapshots/-visual-Verify-notice-with-medium-illustrations-1-webkit-linux.png and b/semcore/notice/__tests__/notice.browser-test.tsx-snapshots/-visual-Verify-notice-with-medium-illustrations-1-webkit-linux.png differ diff --git a/semcore/notice/__tests__/notice.browser-test.tsx-snapshots/-visual-Verify-notice-with-small-illustrations-1-chromium-linux.png b/semcore/notice/__tests__/notice.browser-test.tsx-snapshots/-visual-Verify-notice-with-small-illustrations-1-chromium-linux.png index ee259a83dd..dd938e2f5a 100644 Binary files a/semcore/notice/__tests__/notice.browser-test.tsx-snapshots/-visual-Verify-notice-with-small-illustrations-1-chromium-linux.png and b/semcore/notice/__tests__/notice.browser-test.tsx-snapshots/-visual-Verify-notice-with-small-illustrations-1-chromium-linux.png differ diff --git a/semcore/notice/__tests__/notice.browser-test.tsx-snapshots/-visual-Verify-notice-with-small-illustrations-1-firefox-linux.png b/semcore/notice/__tests__/notice.browser-test.tsx-snapshots/-visual-Verify-notice-with-small-illustrations-1-firefox-linux.png index 32c06c1d2c..fa251b01b9 100644 Binary files a/semcore/notice/__tests__/notice.browser-test.tsx-snapshots/-visual-Verify-notice-with-small-illustrations-1-firefox-linux.png and b/semcore/notice/__tests__/notice.browser-test.tsx-snapshots/-visual-Verify-notice-with-small-illustrations-1-firefox-linux.png differ diff --git a/semcore/notice/__tests__/notice.browser-test.tsx-snapshots/-visual-Verify-notice-with-small-illustrations-1-webkit-linux.png b/semcore/notice/__tests__/notice.browser-test.tsx-snapshots/-visual-Verify-notice-with-small-illustrations-1-webkit-linux.png index 1c158555c5..aa8fade05b 100644 Binary files a/semcore/notice/__tests__/notice.browser-test.tsx-snapshots/-visual-Verify-notice-with-small-illustrations-1-webkit-linux.png and b/semcore/notice/__tests__/notice.browser-test.tsx-snapshots/-visual-Verify-notice-with-small-illustrations-1-webkit-linux.png differ diff --git a/semcore/pills/src/Pills.tsx b/semcore/pills/src/Pills.tsx index d8e1ad6072..027187cc20 100644 --- a/semcore/pills/src/Pills.tsx +++ b/semcore/pills/src/Pills.tsx @@ -11,15 +11,18 @@ import style from './style/pills.shadow.css'; class RootPills extends Component< Intergalactic.InternalTypings.InferComponentProps, typeof RootPills.enhance, - NSPills.Handlers + NSPills.Handlers, + {}, + {}, + NSPills.DefaultProps > { static displayName = 'Pills'; static style = style; - static defaultProps = ({ behavior }: NSPills.Props) => ({ + static defaultProps = ({ behavior }: Intergalactic.InternalTypings.InferComponentProps) => ({ size: 'm', defaultValue: null, behavior: behavior ?? 'auto', - }); + } as const); itemValues: Array = []; @@ -138,8 +141,11 @@ export const wrapPills = (wrapper: ( PropsExtending, ) => React.ReactNode) => wrapper as NSPills.WrapComponent; -const Pills = createComponent(RootPills, { +const Pills = createComponent< + NSPills.Component, + typeof RootPills +>(RootPills, { Item: [Pill, { Text, Addon }], -}) as unknown as NSPills.Component; +}); export default Pills; diff --git a/semcore/pills/src/Pills.type.ts b/semcore/pills/src/Pills.type.ts index bb335ea153..2d77f9545b 100644 --- a/semcore/pills/src/Pills.type.ts +++ b/semcore/pills/src/Pills.type.ts @@ -36,6 +36,11 @@ declare namespace NSPills { type Handlers = { value: (value: Props['value'], event: React.SyntheticEvent) => Props['value']; }; + type DefaultProps = { + size: 'm'; + defaultValue: null; + behavior: Props['behavior']; + }; namespace Pill { type Props = BoxProps & NeighborItemProps & { /** Pill value */ diff --git a/semcore/product-head/src/Info.tsx b/semcore/product-head/src/Info.tsx index aa5f4671c2..f27f0a241a 100644 --- a/semcore/product-head/src/Info.tsx +++ b/semcore/product-head/src/Info.tsx @@ -16,6 +16,12 @@ export type InfoItemProps = BoxProps & { label?: React.ReactNode; }; +type InfoComponent = typeof Box & { + Item: Intergalactic.Component<'div', InfoItemProps> & { + Label: typeof Box; + }; +}; + class InfoRoot extends Component { static displayName = 'Info'; static style = style; @@ -42,17 +48,16 @@ function Label(props: any) { return sstyled(props.styles)(); } -const Info = createComponent(InfoRoot, { +const Info = createComponent< + InfoComponent, + typeof InfoRoot +>(InfoRoot, { Item: [ Item, { Label, }, ], -}) as typeof Box & { - Item: Intergalactic.Component<'div', InfoItemProps> & { - Label: typeof Box; - }; -}; +}); export default Info; diff --git a/semcore/product-head/src/ProductHead.tsx b/semcore/product-head/src/ProductHead.tsx index 88d05d1a51..6bbd751742 100644 --- a/semcore/product-head/src/ProductHead.tsx +++ b/semcore/product-head/src/ProductHead.tsx @@ -4,6 +4,12 @@ import React from 'react'; import style from './style/product-head.shadow.css'; +type HeaderComponent = typeof Box & { + Buttons: typeof Box; + Links: typeof Box; + Row: typeof Box; +}; + class HeaderRoot extends Component { static displayName = 'ProductHead'; static style = style; @@ -29,13 +35,13 @@ function Row(props: any) { return sstyled(props.styles)(); } -const Header = createComponent(HeaderRoot, { +const Header = createComponent< + HeaderComponent, + typeof HeaderRoot +>(HeaderRoot, { Buttons, Links, Row, -}) as typeof Box & { - Buttons: typeof Box; - Links: typeof Box; - Row: typeof Box; -}; +}); + export default Header; diff --git a/semcore/product-head/src/Title.tsx b/semcore/product-head/src/Title.tsx index 338270d5e6..64a1a28ab3 100644 --- a/semcore/product-head/src/Title.tsx +++ b/semcore/product-head/src/Title.tsx @@ -16,6 +16,10 @@ export type HeaderTitleProps = BoxProps & { toolName?: React.ReactNode; }; +type HeaderTitleComponent = Intergalactic.Component<'h1', HeaderTitleProps> & { + Tool: typeof Box; +}; + class TitleRoot extends Component { static displayName = 'Title'; static style = style; @@ -40,10 +44,11 @@ function Tool(props: any) { return sstyled(props.styles)(); } -const Title = createComponent(TitleRoot, { +const Title = createComponent< + HeaderTitleComponent, + typeof TitleRoot +>(TitleRoot, { Tool, -}) as any as Intergalactic.Component<'h1', HeaderTitleProps> & { - Tool: typeof Box; -}; +}); export default Title; diff --git a/semcore/progress-bar/src/ProgressBar.tsx b/semcore/progress-bar/src/ProgressBar.tsx index 5de1aba065..a94be8b0c5 100644 --- a/semcore/progress-bar/src/ProgressBar.tsx +++ b/semcore/progress-bar/src/ProgressBar.tsx @@ -15,7 +15,11 @@ function isCustomTheme(theme?: string) { class ProgressBarRoot extends Component< Intergalactic.InternalTypings.InferComponentProps, - typeof ProgressBarRoot.enhance + typeof ProgressBarRoot.enhance, + {}, + {}, + {}, + NSProgressBar.DefaultProps > { static displayName = 'ProgressBar'; static style = style; @@ -25,7 +29,7 @@ class ProgressBarRoot extends Component< size: 'm', theme: 'invert', children: , - }); + } as const); getValueProps() { const { value, duration, size, resolveColor } = this.asProps; @@ -79,8 +83,11 @@ function Value( ); } -const ProgressBar = createComponent(ProgressBarRoot, { +const ProgressBar = createComponent< + NSProgressBar.Component, + typeof ProgressBarRoot +>(ProgressBarRoot, { Value, -}) as NSProgressBar.Component; +}); export default ProgressBar; diff --git a/semcore/progress-bar/src/ProgressBar.type.ts b/semcore/progress-bar/src/ProgressBar.type.ts index e5ec58f6b5..a94593b7f4 100644 --- a/semcore/progress-bar/src/ProgressBar.type.ts +++ b/semcore/progress-bar/src/ProgressBar.type.ts @@ -20,6 +20,12 @@ declare namespace NSProgressBar { */ duration?: number; }; + type DefaultProps = { + duration: 1000; + size: 'm'; + theme: 'invert'; + children: React.ReactNode; + }; type Ctx = { getValueProps: PropGetterFn; diff --git a/semcore/radio/src/Radio.tsx b/semcore/radio/src/Radio.tsx index abdde146da..fcee5fcbc0 100644 --- a/semcore/radio/src/Radio.tsx +++ b/semcore/radio/src/Radio.tsx @@ -24,17 +24,20 @@ const RadioContext = React.createContext<{ class RadioGroupRoot extends Component< Intergalactic.InternalTypings.InferComponentProps, [], - { value: null } + { value: string }, + {}, + {}, + NSRadio.Group.DefaultProps > { static displayName = 'RadioGroup'; static defaultProps = { - defaultValue: null, - }; + defaultValue: '', + } as const; uncontrolledProps() { return { - value: null, + value: '', }; } @@ -52,17 +55,20 @@ class RadioGroupRoot extends Component< } render() { - const { Children } = this.asProps; + const { Children, value } = this.asProps; return ( - + ); } } -const RadioGroup = createComponent(RadioGroupRoot, {}, { context: RadioContext }) as unknown as NSRadio.Group.Component; +const RadioGroup = createComponent< + NSRadio.Group.Component, + typeof RadioGroupRoot +>(RadioGroupRoot, {}, { context: RadioContext }); class RadioRoot extends Component> { static displayName = 'Radio'; @@ -149,14 +155,17 @@ class RadioRoot extends Component, typeof ValueRoot.enhance, - { checked: (e: React.ChangeEvent) => boolean } + { checked: (e: React.ChangeEvent) => boolean }, + {}, + {}, + NSRadio.Value.DefaultProps > { context: React.ContextType = {}; static defaultProps = { includeInputProps: inputProps, defaultChecked: false, - }; + } as const; static enhance = [resolveColorEnhance()] as const; static displayName = 'Value'; @@ -312,15 +321,21 @@ function Text( } Text.displayName = 'Text'; -const Value = createComponent(ValueRoot, { +const Value = createComponent< + NSRadio.Value.Component, + typeof ValueRoot +>(ValueRoot, { Control, RadioMark, -}) as NSRadio.Value.Component; +}); -const Radio = createComponent(RadioRoot, { +const Radio = createComponent< + NSRadio.Component, + typeof RadioRoot +>(RadioRoot, { Text, Value, -}) as NSRadio.Component; +}); export const wrapRadioGroup = ( wrapper: ( diff --git a/semcore/radio/src/Radio.type.ts b/semcore/radio/src/Radio.type.ts index 5375c9f970..bc88517eac 100644 --- a/semcore/radio/src/Radio.type.ts +++ b/semcore/radio/src/Radio.type.ts @@ -37,6 +37,10 @@ declare namespace NSRadio { /** List of elements that can be put on a hidden input */ includeInputProps?: string[]; }; + type DefaultProps = { + includeInputProps: Props['includeInputProps']; + defaultChecked: false; + }; namespace Control { type Props = {}; type Component = Intergalactic.Component<'input', Props>; @@ -77,6 +81,9 @@ declare namespace NSRadio { /** Blocks access and changes to the form field */ disabled?: boolean; }; + type DefaultProps = { + defaultValue: ''; + }; type Component = (( props: Intergalactic.InternalTypings.ComponentProps> & PropsExtending, ) => Intergalactic.InternalTypings.ComponentRenderingResults) & diff --git a/semcore/skeleton/src/Skeleton.tsx b/semcore/skeleton/src/Skeleton.tsx index 620ca499f6..8693c06d33 100644 --- a/semcore/skeleton/src/Skeleton.tsx +++ b/semcore/skeleton/src/Skeleton.tsx @@ -17,16 +17,18 @@ const MAP_COLOR_THEME = { class SkeletonRoot extends Component< Intergalactic.InternalTypings.InferComponentProps, - typeof SkeletonRoot.enhance + typeof SkeletonRoot.enhance, + {}, + {}, + {}, + NSSkeleton.DefaultProps > { static displayName = 'Skeleton'; static style = style; static enhance = [i18nEnhance(localizedMessages)] as const; static defaultProps = { - width: '100%', - height: '100%', duration: 2000, - }; + } as const; render() { const SSkeleton = Root; @@ -37,6 +39,8 @@ class SkeletonRoot extends Component< return sstyled(styles)( , - typeof SkeletonRoot.enhance + typeof SkeletonRoot.enhance, + never, + {}, + {}, + NSSkeleton.DefaultProps > { static displayName = 'SkeletonSVG'; static enhance = [uniqueIDEnhancement()]; @@ -56,7 +64,7 @@ class SkeletonSVG extends Component< static defaultProps = { theme: 'invert', duration: 2000, - }; + } as const; svgRef = React.createRef(); private observer: ResizeObserver | null = null; @@ -153,10 +161,16 @@ function Text( ); } -const Skeleton = createComponent(SkeletonRoot) as NSSkeleton.RenderComponent; +const Skeleton = createComponent< + NSSkeleton.RenderComponent, + typeof SkeletonRoot +>(SkeletonRoot); export { Skeleton }; -export default createComponent(SkeletonSVG, { +export default createComponent< + NSSkeleton.Component, + typeof SkeletonSVG +>(SkeletonSVG, { Text, -}) as NSSkeleton.Component; +}); diff --git a/semcore/skeleton/src/Skeleton.type.ts b/semcore/skeleton/src/Skeleton.type.ts index 3f7e52a1e3..3e9447b8fc 100644 --- a/semcore/skeleton/src/Skeleton.type.ts +++ b/semcore/skeleton/src/Skeleton.type.ts @@ -30,6 +30,11 @@ declare namespace NSSkeleton { gradientUrl: string; }; + type DefaultProps = { + theme?: 'invert'; + duration: 2000; + }; + namespace Text { type Props = BoxProps & { // TODO: It looks like it should be number (def. not a string...) diff --git a/semcore/skeleton/src/charts/Area/Area.tsx b/semcore/skeleton/src/charts/Area/Area.tsx index 32bc45af69..e30d44ab0c 100644 --- a/semcore/skeleton/src/charts/Area/Area.tsx +++ b/semcore/skeleton/src/charts/Area/Area.tsx @@ -35,4 +35,7 @@ function AreaChartSkeleton(props: Intergalactic.InternalTypings.InferComponentPr ); } -export default createComponent(AreaChartSkeleton) as NSSkeletonAreaChart.Component; +export default createComponent< + NSSkeletonAreaChart.Component, + typeof AreaChartSkeleton +>(AreaChartSkeleton); diff --git a/semcore/skeleton/src/charts/Bar/Bar.tsx b/semcore/skeleton/src/charts/Bar/Bar.tsx index 913fa6df84..0e4e09d5c6 100644 --- a/semcore/skeleton/src/charts/Bar/Bar.tsx +++ b/semcore/skeleton/src/charts/Bar/Bar.tsx @@ -39,4 +39,7 @@ function BarChartSkeleton( ); } -export default createComponent(BarChartSkeleton) as NSSkeletonBarChart.Component; +export default createComponent< + NSSkeletonBarChart.Component, + typeof BarChartSkeleton +>(BarChartSkeleton); diff --git a/semcore/skeleton/src/charts/Bubble/Bubble.tsx b/semcore/skeleton/src/charts/Bubble/Bubble.tsx index bbb95f8bf3..d7f67e36ca 100644 --- a/semcore/skeleton/src/charts/Bubble/Bubble.tsx +++ b/semcore/skeleton/src/charts/Bubble/Bubble.tsx @@ -24,4 +24,7 @@ function BubbleChartSkeleton() { ); } -export default createComponent(BubbleChartSkeleton) as NSSkeletonBubbleChart.Component; +export default createComponent< + NSSkeletonBubbleChart.Component, + typeof BubbleChartSkeleton +>(BubbleChartSkeleton); diff --git a/semcore/skeleton/src/charts/CompactHorizontalBar/CompactHorizontalBar.tsx b/semcore/skeleton/src/charts/CompactHorizontalBar/CompactHorizontalBar.tsx index f76817c12c..bf2b0b2c6f 100644 --- a/semcore/skeleton/src/charts/CompactHorizontalBar/CompactHorizontalBar.tsx +++ b/semcore/skeleton/src/charts/CompactHorizontalBar/CompactHorizontalBar.tsx @@ -24,4 +24,7 @@ function CompactHorizontalBarChartSkeleton() { ); } -export default createComponent(CompactHorizontalBarChartSkeleton) as NSSkeletonCompactHorizontalBar.Component; +export default createComponent< + NSSkeletonCompactHorizontalBar.Component, + typeof CompactHorizontalBarChartSkeleton +>(CompactHorizontalBarChartSkeleton); diff --git a/semcore/skeleton/src/charts/Donut/Donut.tsx b/semcore/skeleton/src/charts/Donut/Donut.tsx index af63ff250d..db8a2d30f3 100644 --- a/semcore/skeleton/src/charts/Donut/Donut.tsx +++ b/semcore/skeleton/src/charts/Donut/Donut.tsx @@ -42,4 +42,7 @@ function DonutChartSkeleton( ); } -export default createComponent(DonutChartSkeleton) as NSSkeletonDonutChart.Component; +export default createComponent< + NSSkeletonDonutChart.Component, + typeof DonutChartSkeleton +>(DonutChartSkeleton); diff --git a/semcore/skeleton/src/charts/Histogram/Histogram.tsx b/semcore/skeleton/src/charts/Histogram/Histogram.tsx index effb4c36b7..852d8f4096 100644 --- a/semcore/skeleton/src/charts/Histogram/Histogram.tsx +++ b/semcore/skeleton/src/charts/Histogram/Histogram.tsx @@ -38,4 +38,7 @@ function HistogramChartSkeleton( ); } -export default createComponent(HistogramChartSkeleton) as NSSkeletonHistogramChart.Component; +export default createComponent< + NSSkeletonHistogramChart.Component, + typeof HistogramChartSkeleton +>(HistogramChartSkeleton); diff --git a/semcore/skeleton/src/charts/Line/Line.tsx b/semcore/skeleton/src/charts/Line/Line.tsx index cbc46956a7..1274481e18 100644 --- a/semcore/skeleton/src/charts/Line/Line.tsx +++ b/semcore/skeleton/src/charts/Line/Line.tsx @@ -38,4 +38,4 @@ function LineChartSkeleton( ); } -export default createComponent(LineChartSkeleton) as NSSkeletonLineChart.Component; +export default createComponent(LineChartSkeleton); diff --git a/semcore/skeleton/src/charts/RadialTree/RadialTree.tsx b/semcore/skeleton/src/charts/RadialTree/RadialTree.tsx index ccb0071c9c..7c7b02aa8b 100644 --- a/semcore/skeleton/src/charts/RadialTree/RadialTree.tsx +++ b/semcore/skeleton/src/charts/RadialTree/RadialTree.tsx @@ -24,4 +24,4 @@ function RadialTreeChartSkeleton() { ); } -export default createComponent(RadialTreeChartSkeleton) as NSSkeletonRadialTreeChart.Component; +export default createComponent(RadialTreeChartSkeleton); diff --git a/semcore/skeleton/src/charts/ScatterPlot/ScatterPlot.tsx b/semcore/skeleton/src/charts/ScatterPlot/ScatterPlot.tsx index c2b18ca0e6..01e7d05118 100644 --- a/semcore/skeleton/src/charts/ScatterPlot/ScatterPlot.tsx +++ b/semcore/skeleton/src/charts/ScatterPlot/ScatterPlot.tsx @@ -24,4 +24,7 @@ function ScatterPlotChartSkeleton() { ); } -export default createComponent(ScatterPlotChartSkeleton) as NSSkeletonScatterPlotChart.Component; +export default createComponent< + NSSkeletonScatterPlotChart.Component, + typeof ScatterPlotChartSkeleton +>(ScatterPlotChartSkeleton); diff --git a/semcore/skeleton/src/charts/Venn/Venn.tsx b/semcore/skeleton/src/charts/Venn/Venn.tsx index 6e2ee38c01..b8badb455d 100644 --- a/semcore/skeleton/src/charts/Venn/Venn.tsx +++ b/semcore/skeleton/src/charts/Venn/Venn.tsx @@ -1,6 +1,7 @@ import { createComponent, Root, sstyled } from '@semcore/core'; import React from 'react'; +import type { NSSkeletonVennChart } from './Venn.type'; import { Skeleton } from '../../Skeleton'; import styles from '../../style/chart.shadow.css'; @@ -23,4 +24,4 @@ function VennChartSkeleton() { ); } -export default createComponent(VennChartSkeleton); +export default createComponent(VennChartSkeleton); diff --git a/semcore/slider/package.json b/semcore/slider/package.json index e76d5b6ca0..145ad141f1 100644 --- a/semcore/slider/package.json +++ b/semcore/slider/package.json @@ -9,7 +9,7 @@ "author": "UI-kit team ", "license": "MIT", "scripts": { - "build": "pnpm semcore-builder --source=js && pnpm vite build" + "build": "pnpm semcore-builder && pnpm vite build" }, "exports": { "types": "./lib/types/index.d.ts", diff --git a/semcore/slider/src/Slider.jsx b/semcore/slider/src/Slider.tsx similarity index 67% rename from semcore/slider/src/Slider.jsx rename to semcore/slider/src/Slider.tsx index 47ba3bc4b7..f62264e3d8 100644 --- a/semcore/slider/src/Slider.jsx +++ b/semcore/slider/src/Slider.tsx @@ -1,21 +1,31 @@ import { Flex, Box } from '@semcore/base-components'; -import { createComponent, Component, sstyled, Root } from '@semcore/core'; +import type { Intergalactic } from '@semcore/core'; +import { sstyled, Root, Component, createComponent } from '@semcore/core'; import reactToText from '@semcore/core/lib/utils/reactToText'; import React from 'react'; +import type { NSSlider } from './Slider.type'; import style from './style/slider.shadow.css'; -const convertValueToPercent = (value, min, max) => { +const FALLBACK_VALUE = 0; + +const convertValueToPercent = (value: number, min: number, max: number) => { if (value > max) return 100; if (value < min) return 0; return ((value - min) / (max - min)) * 100; }; - -class SliderRoot extends Component { +class SliderRoot extends Component< + Intergalactic.InternalTypings.InferComponentProps, + [], + NSSlider.Handlers, + {}, + {}, + NSSlider.DefaultProps +> { static displayName = 'Slider'; static style = style; - sliderRef = React.createRef(null); + sliderRef = React.createRef(); static defaultProps = () => ({ defaultValue: 0, @@ -33,10 +43,6 @@ class SliderRoot extends Component { ), }); - handleRef = (node) => { - this.sliderRef.current = node; - }; - uncontrolledProps() { return { value: null, @@ -73,14 +79,14 @@ class SliderRoot extends Component { return { options }; } - getItemProps(_, index) { + getItemProps(_: NSSlider.Item.Props, index: number) { const { options } = this.asProps; - const option = options[index]; + const option = options?.[index]; return { - key: option.value, - value: option.value, - children: option.label, + key: option?.value, + value: option?.value, + children: option?.label, }; } @@ -92,9 +98,11 @@ class SliderRoot extends Component { document.removeEventListener('touchend', this.handleMouseEnd); }; - handleMouseMove = (event) => { + handleMouseMove = (event: MouseEvent | TouchEvent | React.MouseEvent | React.TouchEvent) => { event.preventDefault(); + if (!this.sliderRef.current) return; + document.addEventListener('touchmove', this.handleMouseMove); document.addEventListener('mousemove', this.handleMouseMove); document.addEventListener('click', this.handleMouseMove); @@ -104,7 +112,7 @@ class SliderRoot extends Component { const { min, max, step, options } = this.asProps; const sliderSize = this.sliderRef.current.offsetWidth; - const clientX = event.clientX ?? event.touches[0].clientX; + const clientX = 'touches' in event ? event.touches[0].clientX : event.clientX; const newLeft = clientX - this.sliderRef.current.getBoundingClientRect().left; if (newLeft <= 0) { @@ -127,7 +135,7 @@ class SliderRoot extends Component { handleDragStart = () => false; - handleKeyDown = (event) => { + handleKeyDown = (event: React.KeyboardEvent) => { if (['ArrowLeft', 'ArrowUp', 'ArrowRight', 'ArrowDown'].includes(event.key)) { this.handleSlideStep(event); } @@ -141,7 +149,7 @@ class SliderRoot extends Component { } }; - handleSlideStep(event) { + handleSlideStep(event: React.KeyboardEvent) { event.preventDefault(); const { min, max, step, options } = this.asProps; @@ -158,11 +166,11 @@ class SliderRoot extends Component { } } - slideToMinValue(event) { + slideToMinValue(event: React.KeyboardEvent) { event.preventDefault(); const { min, options } = this.asProps; - let value = min; + let value: NSSlider.Value = min; if (options) { value = options[0].value; @@ -171,11 +179,11 @@ class SliderRoot extends Component { this.handlers.value(value, event); } - slideToMaxValue(event) { + slideToMaxValue(event: React.KeyboardEvent) { event.preventDefault(); const { max, options } = this.asProps; - let value = max; + let value: NSSlider.Value = max; if (options) { value = options[options.length - 1].value; @@ -184,28 +192,35 @@ class SliderRoot extends Component { this.handlers.value(value, event); } - getNumericValue = () => { + getNumericValue = (): number => { const { value, options, min, max, defaultValue } = this.asProps; if (!options) { - const numericValue = parseInt(value); + const numeric = Number(value); + if (!isNaN(numeric)) return numeric; - return isNaN(numericValue) ? defaultValue : numericValue; - }; + const numericDefault = Number(defaultValue); + if (!isNaN(numericDefault)) return numericDefault; - const resolvedIndex = options.findIndex((option) => option.value === value); - if (resolvedIndex === -1) return defaultValue; - if (resolvedIndex < min) return min; - if (min !== undefined) { - if (resolvedIndex + min > max) return max; - } else { - if (resolvedIndex > max) return max; + return FALLBACK_VALUE; + } + + const index = options.findIndex((option) => option.value === value); + + if (index === -1) { + const numericDefault = Number(defaultValue); + return isNaN(numericDefault) ? FALLBACK_VALUE : numericDefault; } - return resolvedIndex + (min ?? 0); + const result = index + min; + + if (index < min) return min; + if (result > max) return max; + + return result; }; - resolveLabel = (numericValue) => { + resolveLabel = (numericValue: number) => { const { min, options } = this.asProps; if (!options) return undefined; const option = options[numericValue - (min ?? 0)]; @@ -230,7 +245,7 @@ class SliderRoot extends Component { tag='button' type='button' tabIndex={0} - ref={this.handleRef} + ref={this.sliderRef} onMouseDown={this.handleMouseMove} onTouchMove={this.handleMouseMove} onMouseUp={this.handleMouseEnd} @@ -252,14 +267,18 @@ class SliderRoot extends Component { } } -function Bar(props) { +function Bar( + props: Intergalactic.InternalTypings.InferChildComponentProps, +) { const SBar = Root; const { styles, value, min, max } = props; return sstyled(styles)(); } -function Knob(props) { +function Knob( + props: Intergalactic.InternalTypings.InferChildComponentProps, +) { const SKnob = Root; const { styles, value, min, max } = props; @@ -268,7 +287,10 @@ function Knob(props) { ); } -function Options({ styles, options, Children }) { +function Options( + props: Intergalactic.InternalTypings.InferChildComponentProps, +) { + const { styles, options, Children } = props; const SSliderOptions = Root; return sstyled(styles)( @@ -280,7 +302,10 @@ function Options({ styles, options, Children }) { ); } -function Item({ styles, Children }) { +function Item( + props: Intergalactic.InternalTypings.InferChildComponentProps, +) { + const { styles, Children } = props; const SSliderOption = Root; return sstyled(styles)( @@ -290,13 +315,21 @@ function Item({ styles, Children }) { ); } -const Slider = createComponent(SliderRoot, { +const Slider = createComponent< + NSSlider.Component, + typeof SliderRoot +>(SliderRoot, { Bar, Knob, Options, Item, }); -export const wrapSlider = (wrapper) => wrapper; +export const wrapSlider = (wrapper: ( + props: Intergalactic.InternalTypings.UntypeRefAndTag< + Intergalactic.InternalTypings.ComponentPropsNesting + > & + PropsExtending, +) => React.ReactNode) => wrapper as NSSlider.WrapperComponent; export default Slider; diff --git a/semcore/slider/src/Slider.type.ts b/semcore/slider/src/Slider.type.ts new file mode 100644 index 0000000000..fac85e1db4 --- /dev/null +++ b/semcore/slider/src/Slider.type.ts @@ -0,0 +1,101 @@ +import type { Box, BoxProps, FlexProps } from '@semcore/base-components'; +import type { PropGetterFn, Intergalactic } from '@semcore/core'; +import type React from 'react'; + +declare namespace NSSlider { + // TODO: type value accurately depending on `options`. + type Value = string | number; + type Ctx = { + getOptionsProps: PropGetterFn; + getItemProps: PropGetterFn; + }; + type Handlers = { + value: null; + }; + type Option = { + value: V; + label: React.ReactNode; + }; + type Props = BoxProps & { + /** Numeric value + */ + value?: V; + /** Numeric default value + * @default 0 + */ + defaultValue?: V; + /** Minimum value + * @default 0 + */ + min?: number; + /** Maximum value + * @default 100 + */ + max?: number; + /** Value change step + * @default 1 + */ + step?: number; + /** + * Handler for changing the value + */ + onChange?: ((value: V, event: React.SyntheticEvent) => void) | React.Dispatch>; + /** + * Disable element + */ + disabled?: boolean; + /** Predefined slider options */ + options?: NSSlider.Option[]; + }; + + type DefaultProps = { + defaultValue: number; + min: number; + max: number; + step: number; + children: React.ReactNode; + }; + + namespace Knob { + type Component = typeof Box; + } + namespace Bar { + type Component = typeof Box; + } + namespace Options { + type Props = FlexProps; + type Component = Intergalactic.Component< + 'div', + Props, + NSSlider.Ctx, + [handlers: NSSlider.Handlers] + >; + } + namespace Item { + type Props = BoxProps; + type Component = Intergalactic.Component<'div', Props, NSSlider.Ctx, [handlers: NSSlider.Handlers]>; + } + + type WrapperComponent = (< + V extends NSSlider.Value, + Tag extends Intergalactic.Tag = 'div', + >( + props: Intergalactic.InternalTypings.ComponentProps> & + PropsExtending, + ) => Intergalactic.InternalTypings.ComponentRenderingResults) & + Intergalactic.InternalTypings.ComponentAdditive<'div', 'div', NSSlider.Props>; + + type Component = WrapperComponent & { + Knob: Knob.Component; + Bar: Bar.Component; + Options: Options.Component; + Item: Item.Component; + }; +} + +/** @deprecated It will be removed in v18. */ +export type SliderOption = NSSlider.Option; +/** @deprecated It will be removed in v18. */ +export type SliderProps = NSSlider.Props; + +export type { NSSlider }; diff --git a/semcore/slider/src/index.d.ts b/semcore/slider/src/index.d.ts deleted file mode 100644 index 2589b2884a..0000000000 --- a/semcore/slider/src/index.d.ts +++ /dev/null @@ -1,88 +0,0 @@ -import type { Box, BoxProps, FlexProps } from '@semcore/base-components'; -import type { PropGetterFn, Intergalactic } from '@semcore/core'; -import type React from 'react'; - -type SliderValue = string | number; - -type SliderContext = { - getOptionsProps: PropGetterFn; - getItemProps: PropGetterFn; -}; -type SliderHandlers = { - value: (index: SliderValue) => void; -}; - -export type SliderOption = { - value: OptionValue; - label: React.ReactNode; -}; - -export type SliderProps = BoxProps & { - /** Numeric value - */ - value?: Value; - /** Numeric default value - * @default 0 - */ - defaultValue?: Value; - /** Minimum value - * @default 0 - */ - min?: number; - /** Maximum value - * @default 100 - */ - max?: number; - /** Value change step - * @default 1 - */ - step?: number; - /** - * Handler for changing the value - */ - onChange?: - | ((value: Value, event: React.SyntheticEvent) => void) - | React.Dispatch>; - /** - * Disable element - */ - disabled?: boolean; - /** Predefined slider options */ - options?: SliderOption[]; -}; - -type SliderOptionsProps = FlexProps; -type SliderItemProps = BoxProps; - -type IntergalacticSliderComponent = (< - Value extends SliderValue, - Tag extends Intergalactic.Tag = 'div', ->( - props: Intergalactic.InternalTypings.ComponentProps> & - PropsExtending, -) => Intergalactic.InternalTypings.ComponentRenderingResults) & -Intergalactic.InternalTypings.ComponentAdditive<'div', 'div', SliderProps>; - -declare const Slider: IntergalacticSliderComponent & { - Knob: typeof Box; - Bar: typeof Box; - Options: Intergalactic.Component< - 'div', - SliderOptionsProps, - SliderContext, - [handlers: SliderHandlers] - >; - Item: Intergalactic.Component<'div', SliderItemProps, SliderContext, [handlers: SliderHandlers]>; -}; - -declare const wrapSlider: ( - wrapper: ( - props: Intergalactic.InternalTypings.UntypeRefAndTag< - Intergalactic.InternalTypings.ComponentPropsNesting - > & - PropsExtending, - ) => React.ReactNode, -) => IntergalacticSliderComponent; -export { wrapSlider }; - -export default Slider; diff --git a/semcore/slider/src/index.js b/semcore/slider/src/index.js deleted file mode 100644 index 006f966fe2..0000000000 --- a/semcore/slider/src/index.js +++ /dev/null @@ -1,2 +0,0 @@ -export { default } from './Slider'; -export * from './Slider'; diff --git a/semcore/slider/src/index.ts b/semcore/slider/src/index.ts new file mode 100644 index 0000000000..c6a5a2b43b --- /dev/null +++ b/semcore/slider/src/index.ts @@ -0,0 +1,2 @@ +export { default, wrapSlider } from './Slider'; +export * from './Slider.type'; diff --git a/semcore/slider/vite.config.ts b/semcore/slider/vite.config.ts index 0991a16528..90f46b4cb2 100644 --- a/semcore/slider/vite.config.ts +++ b/semcore/slider/vite.config.ts @@ -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\/*/], diff --git a/semcore/tab-line/src/TabLine.tsx b/semcore/tab-line/src/TabLine.tsx index 5308aec12d..a365b2f3b8 100644 --- a/semcore/tab-line/src/TabLine.tsx +++ b/semcore/tab-line/src/TabLine.tsx @@ -24,16 +24,17 @@ class TabLineRoot extends Component< typeof TabLineRoot.enhance, NSTabLine.Handlers, {}, - State + State, + NSTabLine.DefaultProps > { static displayName = 'TabLine'; static style = style; static defaultProps = { - defaultValue: null, + defaultValue: 0, size: 'm', underlined: true, behavior: 'auto', - }; + } as const; static enhance = [a11yEnhance({ onNeighborChange: (neighborElement, props) => { @@ -248,9 +249,12 @@ function Addon( return sstyled(styles)(); } -const TabLine = createComponent(TabLineRoot, { +const TabLine = createComponent< + NSTabLine.Component, + typeof TabLineRoot +>(TabLineRoot, { Item: [TabLineItem, { Text, Addon }], -}) as unknown as NSTabLine.Component; +}); export const wrapTabLine = (wrapper: ( props: Intergalactic.InternalTypings.UntypeRefAndTag< diff --git a/semcore/tab-line/src/TabLine.type.ts b/semcore/tab-line/src/TabLine.type.ts index 967334998e..721857954f 100644 --- a/semcore/tab-line/src/TabLine.type.ts +++ b/semcore/tab-line/src/TabLine.type.ts @@ -41,6 +41,13 @@ declare namespace NSTabLine { value: null; }; + type DefaultProps = { + defaultValue: 0; + size: 'm'; + underlined: true; + behavior: 'auto'; + }; + namespace Item { type Props = BoxProps & NeighborItemProps & { diff --git a/semcore/tab-panel/src/TabPanel.tsx b/semcore/tab-panel/src/TabPanel.tsx index f50698119e..f97d6252a8 100644 --- a/semcore/tab-panel/src/TabPanel.tsx +++ b/semcore/tab-panel/src/TabPanel.tsx @@ -12,14 +12,17 @@ import type { NSTabPanel } from './TabPanel.type'; class TabPanelRoot extends Component< Intergalactic.InternalTypings.InferComponentProps, typeof TabPanelRoot.enhance, - NSTabPanel.Handlers + NSTabPanel.Handlers, + {}, + {}, + NSTabPanel.DefaultProps > { static displayName = 'TabPanel'; static style = style; static defaultProps = { - defaultValue: null, + defaultValue: 0, behavior: 'manual', - }; + } as const; static enhance = [ a11yEnhance({ @@ -125,9 +128,12 @@ function Addon( return sstyled(styles)(); } -const TabPanel = createComponent(TabPanelRoot, { +const TabPanel = createComponent< + NSTabPanel.Component, + typeof TabPanelRoot +>(TabPanelRoot, { Item: [TabPanelItem, { Text, Addon }], -}) as unknown as NSTabPanel.Component; +}); export const wrapTabPanel = (wrapper: ( props: Intergalactic.InternalTypings.UntypeRefAndTag< diff --git a/semcore/tab-panel/src/TabPanel.type.ts b/semcore/tab-panel/src/TabPanel.type.ts index 22d3d856c6..b52b85fa6f 100644 --- a/semcore/tab-panel/src/TabPanel.type.ts +++ b/semcore/tab-panel/src/TabPanel.type.ts @@ -29,6 +29,10 @@ declare namespace NSTabPanel { type Handlers = { value: null; }; + type DefaultProps = { + defaultValue: 0; + behavior: 'manual'; + }; namespace Item { type Props = BoxProps & { diff --git a/semcore/time-picker/src/component/TimePicker/TimePicker.tsx b/semcore/time-picker/src/component/TimePicker/TimePicker.tsx index 04e2989686..3d80691355 100644 --- a/semcore/time-picker/src/component/TimePicker/TimePicker.tsx +++ b/semcore/time-picker/src/component/TimePicker/TimePicker.tsx @@ -12,6 +12,7 @@ import type { TimePickerProps, TimePickerField, TimePickerSeparatorProps, + TimePickerDefaultProps, } from './TimePicker.type'; import TimePickerEntity from '../../entity/TimePickerEntity'; import { localizedMessages } from '../../translations/__intergalactic-dynamic-locales'; @@ -19,10 +20,18 @@ import Format from '../PickerFormat/PickerFormat'; import { Hours, Minutes } from '../PickerInput/PickerInput'; @propsObserver(['value', 'is12Hour']) -class TimePickerRoot extends Component { +class TimePickerRoot extends Component< + TimePickerProps, + typeof TimePickerRoot.enhance, + { value: null }, + {}, + {}, + TimePickerDefaultProps + > { static displayName = 'TimePicker'; static style = style; static enhance = [i18nEnhance(localizedMessages)] as const; + static defaultProps = ({ is12Hour }: TimePickerProps) => ({ defaultValue: '', size: 'm', @@ -35,7 +44,7 @@ class TimePickerRoot extends Component ), locale: 'en', - }); + } as const); hoursInputRef = React.createRef(); minutesInputRef = React.createRef(); @@ -184,11 +193,14 @@ class Separator extends Component { } } -const TimePicker = createComponent(TimePickerRoot, { +const TimePicker = createComponent< + TimePickerComponent, + typeof TimePickerRoot +>(TimePickerRoot, { Hours, Minutes, Separator, Format, -}) as TimePickerComponent; +}); export default TimePicker; diff --git a/semcore/time-picker/src/component/TimePicker/TimePicker.type.ts b/semcore/time-picker/src/component/TimePicker/TimePicker.type.ts index 683148121c..44c4055368 100644 --- a/semcore/time-picker/src/component/TimePicker/TimePicker.type.ts +++ b/semcore/time-picker/src/component/TimePicker/TimePicker.type.ts @@ -22,6 +22,13 @@ export type TimePickerProps = Omit & { locale?: string; }; +export type TimePickerDefaultProps = { + defaultValue: ''; + size: 'm'; + children: React.ReactNode; + locale: 'en'; +}; + export type TimePickerSeparatorProps = { /** @Internal */ hoursInputRef: React.RefObject; diff --git a/semcore/typography/src/components/Blockquote/Blockquote.tsx b/semcore/typography/src/components/Blockquote/Blockquote.tsx index 313ea5e646..b14ab2510c 100644 --- a/semcore/typography/src/components/Blockquote/Blockquote.tsx +++ b/semcore/typography/src/components/Blockquote/Blockquote.tsx @@ -9,7 +9,7 @@ import styles from '../../style/blockquote.shadow.css'; function BlockquoteRoot( props: Intergalactic.InternalTypings.InferComponentProps, - ref: React.ForwardedRef, + ref: React.Ref, ) { const SBlockquote = Root; const SDoubleQuotation = 'span'; @@ -29,6 +29,6 @@ function BlockquoteRoot( BlockquoteRoot.displayName = 'Blockquote'; -const Blockquote = createBaseComponent(BlockquoteRoot) as NSBlockquote.Component; +const Blockquote = createBaseComponent(BlockquoteRoot); export default Blockquote; diff --git a/semcore/typography/src/components/List/List.tsx b/semcore/typography/src/components/List/List.tsx index 55ce6bfacd..885822359b 100644 --- a/semcore/typography/src/components/List/List.tsx +++ b/semcore/typography/src/components/List/List.tsx @@ -9,12 +9,19 @@ import type { NSList } from './List.type'; import style from '../../style/list.shadow.css'; import Text from '../Text/Text'; -class ListRoot extends Component> { +class ListRoot extends Component< + Intergalactic.InternalTypings.InferComponentProps, + [], + {}, + {}, + {}, + NSList.DefaultProps +> { static displayName = 'List'; static style = style; static defaultProps = { marker: '•', - }; + } as const; getItemProps() { const { marker } = this.asProps; @@ -62,8 +69,14 @@ function Content(props: Intergalactic.InternalTypings.InferComponentProps(ItemRoot, { Content }); -const List = createComponent(ListRoot, { Item }) as NSList.Component; +const List = createComponent< + NSList.Component, + typeof ListRoot +>(ListRoot, { Item }); export default List; diff --git a/semcore/typography/src/components/List/List.type.ts b/semcore/typography/src/components/List/List.type.ts index 555d00ff00..6036142a89 100644 --- a/semcore/typography/src/components/List/List.type.ts +++ b/semcore/typography/src/components/List/List.type.ts @@ -11,6 +11,10 @@ declare namespace NSList { marker?: React.ReactNode; }; + type DefaultProps = { + marker: '•'; + }; + namespace Item { type Props = NSText.Props & { /** Individual marker of a list item */ diff --git a/semcore/typography/src/components/Text/Text.tsx b/semcore/typography/src/components/Text/Text.tsx index 37acb1eea0..017e9f0fce 100644 --- a/semcore/typography/src/components/Text/Text.tsx +++ b/semcore/typography/src/components/Text/Text.tsx @@ -134,6 +134,9 @@ class TextRoot extends Component< } } -const Text = createComponent(TextRoot) as NSText.Component; +const Text = createComponent< + NSText.Component, + typeof TextRoot +>(TextRoot); export default Text; diff --git a/semcore/wizard/src/Wizard.tsx b/semcore/wizard/src/Wizard.tsx index bfec761f59..3a5faa611f 100644 --- a/semcore/wizard/src/Wizard.tsx +++ b/semcore/wizard/src/Wizard.tsx @@ -2,6 +2,7 @@ import { ScreenReaderOnly, Box } from '@semcore/base-components'; import Button from '@semcore/button'; import { createComponent, Component, Root, sstyled } from '@semcore/core'; import type { IRootComponentProps, Intergalactic } from '@semcore/core'; +import type { WithI18nEnhanceProps } from '@semcore/core/lib/utils/enhances/i18nEnhance'; import i18nEnhance from '@semcore/core/lib/utils/enhances/i18nEnhance'; import findComponent from '@semcore/core/lib/utils/findComponent'; import uniqueIDEnhancement from '@semcore/core/lib/utils/uniqueID'; @@ -25,21 +26,29 @@ import type { WizardType, WizardStepBackProps, WizardStepNextProps, + WizardDefaultProps, } from './Wizard.types'; type State = { highlighted: number; }; -class WizardRoot extends Component { +class WizardRoot extends Component< + WizardProps, + typeof WizardRoot.enhance, + {}, + WithI18nEnhanceProps, + State, + WizardDefaultProps +> { static displayName = 'Wizard'; static style = style; static enhance = [i18nEnhance(localizedMessages), uniqueIDEnhancement()] as const; static defaultProps = { - step: null, + step: 0, i18n: localizedMessages, locale: 'en', - }; + } as const; _steps = new Map(); modalRef = React.createRef(); @@ -345,14 +354,17 @@ function StepNext(props: Required & IRootComponentProps) { ); } -const Wizard = createComponent(WizardRoot, { +const Wizard = createComponent< + WizardType, + typeof WizardRoot +>(WizardRoot, { Sidebar, Content, Step, Stepper, StepBack, StepNext, -}) as WizardType; +}); export const wrapWizardStepper = ( wrapper: ( diff --git a/semcore/wizard/src/Wizard.types.ts b/semcore/wizard/src/Wizard.types.ts index 5cd3d9dd01..a7e6db79c0 100644 --- a/semcore/wizard/src/Wizard.types.ts +++ b/semcore/wizard/src/Wizard.types.ts @@ -131,6 +131,11 @@ export type WizardStepNextProps = ButtonProps & { */ getI18nText?: ReturnType; }; +export type WizardDefaultProps = { + step: WizardStep; + i18n: Record; + locale: 'en'; +}; export type IntergalacticWizardStepperComponent = (< Tag extends Intergalactic.Tag = 'div', diff --git a/semcore/wizard/vite.config.ts b/semcore/wizard/vite.config.ts index 0991a16528..90f46b4cb2 100644 --- a/semcore/wizard/vite.config.ts +++ b/semcore/wizard/vite.config.ts @@ -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\/*/], diff --git a/stories/components/base-trigger/tests/examples/link-trigger/base.tsx b/stories/components/base-trigger/tests/examples/link-trigger/base.tsx index 6bdfdc10bf..0ba08b1568 100644 --- a/stories/components/base-trigger/tests/examples/link-trigger/base.tsx +++ b/stories/components/base-trigger/tests/examples/link-trigger/base.tsx @@ -3,7 +3,7 @@ import MathPlusAltM from '@semcore/icon/MathPlusAlt/m'; import Badge from '@semcore/ui/badge'; import { LinkTrigger } from '@semcore/ui/base-trigger'; import type { LinkTriggerProps } from '@semcore/ui/base-trigger'; -import Counter, { type CounterProps } from '@semcore/ui/counter'; +import Counter, { type NSCounter } from '@semcore/ui/counter'; import Flags from '@semcore/ui/flags'; import Tag, { type TagSize } from '@semcore/ui/tag'; import type { NSText } from '@semcore/ui/typography'; @@ -48,7 +48,7 @@ const Demo = (props: BasicLinktriggerProps) => { const numSize = Number(size); const IconAddon = numSize < 600 ? MathPlusAltM : MathPlusAltL; - let counterSize: CounterProps['size']; + let counterSize: NSCounter.Props['size']; if (numSize >= 600) { counterSize = 'l'; } else if (numSize >= 300) { diff --git a/stories/components/base-trigger/tests/examples/link-trigger/link-trigger-different-sizes.tsx b/stories/components/base-trigger/tests/examples/link-trigger/link-trigger-different-sizes.tsx index 94c94335da..741884235f 100644 --- a/stories/components/base-trigger/tests/examples/link-trigger/link-trigger-different-sizes.tsx +++ b/stories/components/base-trigger/tests/examples/link-trigger/link-trigger-different-sizes.tsx @@ -2,7 +2,7 @@ import MathPlusAltL from '@semcore/icon/MathPlusAlt/l'; import MathPlusAltM from '@semcore/icon/MathPlusAlt/m'; import Badge from '@semcore/ui/badge'; import { LinkTrigger } from '@semcore/ui/base-trigger'; -import Counter, { type CounterProps } from '@semcore/ui/counter'; +import Counter, { type NSCounter } from '@semcore/ui/counter'; import Flags from '@semcore/ui/flags'; import Tag, { type TagSize } from '@semcore/ui/tag'; import { Text } from '@semcore/ui/typography'; @@ -25,7 +25,7 @@ const Demo = (props: LinkTriggerSizesProps) => { return ( <> {sizes.map((size) => { - let counterSize: CounterProps['size']; + let counterSize: NSCounter.Props['size']; if (size >= 600) { counterSize = 'l'; } else if (size >= 300) { diff --git a/stories/components/base-trigger/tests/examples/link-trigger/with-select.tsx b/stories/components/base-trigger/tests/examples/link-trigger/with-select.tsx index 1910bdc851..7fcd2c0da4 100644 --- a/stories/components/base-trigger/tests/examples/link-trigger/with-select.tsx +++ b/stories/components/base-trigger/tests/examples/link-trigger/with-select.tsx @@ -4,7 +4,7 @@ import Badge from '@semcore/ui/badge'; import { Flex } from '@semcore/ui/base-components'; import { LinkTrigger } from '@semcore/ui/base-trigger'; import type { LinkTriggerProps } from '@semcore/ui/base-trigger'; -import Counter, { type CounterProps } from '@semcore/ui/counter'; +import Counter, { type NSCounter } from '@semcore/ui/counter'; import Flags from '@semcore/ui/flags'; import Select from '@semcore/ui/select'; import Tag, { type TagSize } from '@semcore/ui/tag'; @@ -51,7 +51,7 @@ const Demo = (props: LinkTriggerSelectDDMenuExample) => { const numSize = Number(size); const IconAddon = numSize < 600 ? MathPlusAltM : MathPlusAltL; - let counterSize: CounterProps['size']; + let counterSize: NSCounter.Props['size']; if (numSize >= 600) { counterSize = 'l'; } else if (numSize >= 300) { diff --git a/stories/components/button/tests/examples/button-link/button-link-base.tsx b/stories/components/button/tests/examples/button-link/button-link-base.tsx index c647cd22dc..b875687a32 100644 --- a/stories/components/button/tests/examples/button-link/button-link-base.tsx +++ b/stories/components/button/tests/examples/button-link/button-link-base.tsx @@ -3,7 +3,7 @@ import MathPlusAltM from '@semcore/icon/MathPlusAlt/m'; import Badge from '@semcore/ui/badge'; import { ButtonLink } from '@semcore/ui/button'; import type { ButtonLinkProps } from '@semcore/ui/button'; -import Counter, { type CounterProps } from '@semcore/ui/counter'; +import Counter, { type NSCounter } from '@semcore/ui/counter'; import Spin, { type SpinSize } from '@semcore/ui/spin'; import type { NSText } from '@semcore/ui/typography'; import { Text } from '@semcore/ui/typography'; @@ -53,7 +53,7 @@ const Demo = (props: BasicButtonLinkProps) => { spinSize = 's'; } - let counterSize: CounterProps['size']; + let counterSize: NSCounter.Props['size']; if (numSize >= 600) { counterSize = 'l'; } else if (numSize >= 300) { diff --git a/stories/components/button/tests/examples/button-link/button-link-sizes-addons.tsx b/stories/components/button/tests/examples/button-link/button-link-sizes-addons.tsx index c63b7c65ea..2b1a7a0388 100644 --- a/stories/components/button/tests/examples/button-link/button-link-sizes-addons.tsx +++ b/stories/components/button/tests/examples/button-link/button-link-sizes-addons.tsx @@ -2,7 +2,7 @@ import MathPlusAltL from '@semcore/icon/MathPlusAlt/l'; import MathPlusAltM from '@semcore/icon/MathPlusAlt/m'; import Badge from '@semcore/ui/badge'; import { ButtonLink } from '@semcore/ui/button'; -import type { CounterProps } from '@semcore/ui/counter'; +import type { NSCounter } from '@semcore/ui/counter'; import Counter from '@semcore/ui/counter'; import type { SpinSize } from '@semcore/ui/spin'; import Spin from '@semcore/ui/spin'; @@ -32,7 +32,7 @@ const Demo = (props: ButtonLinkSizesProps) => { spinSize = 's'; } - let counterSize: CounterProps['size']; + let counterSize: NSCounter.Props['size']; if (size >= 600) { counterSize = 'l'; } else if (size >= 300) { diff --git a/stories/components/counter/tests/examples/counter.tsx b/stories/components/counter/tests/examples/counter.tsx index 6a70082db4..a7e183d085 100644 --- a/stories/components/counter/tests/examples/counter.tsx +++ b/stories/components/counter/tests/examples/counter.tsx @@ -1,8 +1,8 @@ import Counter from '@semcore/ui/counter'; -import type { CounterProps } from '@semcore/ui/counter'; +import type { NSCounter } from '@semcore/ui/counter'; import React from 'react'; -const Demo = (props: CounterProps) => { +const Demo = (props: NSCounter.Props) => { return ( <> @@ -12,7 +12,7 @@ const Demo = (props: CounterProps) => { ); }; -export const defaultProps: CounterProps = { +export const defaultProps: NSCounter.Props = { size: 'm', theme: undefined, }; diff --git a/stories/components/link/tests/examples/basic_usage.tsx b/stories/components/link/tests/examples/basic_usage.tsx index 82cadde130..5a00539070 100644 --- a/stories/components/link/tests/examples/basic_usage.tsx +++ b/stories/components/link/tests/examples/basic_usage.tsx @@ -1,7 +1,7 @@ import MathPlusAltL from '@semcore/icon/MathPlusAlt/l'; import MathPlusAltM from '@semcore/icon/MathPlusAlt/m'; import Badge from '@semcore/ui/badge'; -import Counter, { type CounterProps } from '@semcore/ui/counter'; +import Counter, { type NSCounter } from '@semcore/ui/counter'; import Link, { type LinkProps } from '@semcore/ui/link'; import Spin, { type SpinSize } from '@semcore/ui/spin'; import type { NSText } from '@semcore/ui/typography'; @@ -57,7 +57,7 @@ const Demo = (props: BasicLinkProps) => { spinSize = 's'; } - let counterSize: CounterProps['size']; + let counterSize: NSCounter.Props['size']; if (numSize >= 600) { counterSize = 'l'; } else if (numSize >= 300) { diff --git a/stories/components/link/tests/examples/link-different-sizes.tsx b/stories/components/link/tests/examples/link-different-sizes.tsx index f75e7facda..2fc3ff6476 100644 --- a/stories/components/link/tests/examples/link-different-sizes.tsx +++ b/stories/components/link/tests/examples/link-different-sizes.tsx @@ -1,7 +1,7 @@ import MathPlusAltL from '@semcore/icon/MathPlusAlt/l'; import MathPlusAltM from '@semcore/icon/MathPlusAlt/m'; import Badge from '@semcore/ui/badge'; -import Counter, { type CounterProps } from '@semcore/ui/counter'; +import Counter, { type NSCounter } from '@semcore/ui/counter'; import Link from '@semcore/ui/link'; import Spin, { type SpinSize } from '@semcore/ui/spin'; import { Text } from '@semcore/ui/typography'; @@ -31,7 +31,7 @@ const Demo = (props: LinkSizesProps) => { spinSize = 's'; } - let counterSize: CounterProps['size']; + let counterSize: NSCounter.Props['size']; if (size >= 600) { counterSize = 'l'; } else if (size >= 300) { diff --git a/stories/components/slider/tests/examples/basic_usage.tsx b/stories/components/slider/tests/examples/basic_usage.tsx index cb9be29344..0d4077c928 100644 --- a/stories/components/slider/tests/examples/basic_usage.tsx +++ b/stories/components/slider/tests/examples/basic_usage.tsx @@ -1,8 +1,8 @@ import Slider from '@semcore/ui/slider'; -import type { SliderProps } from '@semcore/ui/slider'; +import type { NSSlider } from '@semcore/ui/slider'; import React from 'react'; -export type BasicSliderProps = SliderProps & { +export type BasicSliderProps = NSSlider.Props & { showKnob?: boolean; showBar?: boolean; }; diff --git a/website/docs/components/color-picker/color-picker-api.md b/website/docs/components/color-picker/color-picker-api.md index d7566567d3..0722e98b3d 100644 --- a/website/docs/components/color-picker/color-picker-api.md +++ b/website/docs/components/color-picker/color-picker-api.md @@ -13,7 +13,7 @@ import ColorPicker from '@semcore/ui/color-picker'; ; ``` - + ## ColorPicker.Trigger @@ -42,7 +42,7 @@ import ColorPicker from '@semcore/ui/color-picker'; ; ``` - + ## ColorPicker.Item @@ -68,7 +68,7 @@ import { PaletteManager } from '@semcore/ui/color-picker'; ; ``` - + ## PaletteManager.Colors @@ -79,7 +79,7 @@ import { PaletteManager } from '@semcore/ui/color-picker'; ; ``` - + ## PaletteManager.Item @@ -105,6 +105,6 @@ import { PaletteManager } from '@semcore/ui/color-picker'; ; ``` - + diff --git a/website/docs/components/counter/counter-api.md b/website/docs/components/counter/counter-api.md index f179445d54..54e63fbf9f 100644 --- a/website/docs/components/counter/counter-api.md +++ b/website/docs/components/counter/counter-api.md @@ -10,7 +10,7 @@ import Counter from '@semcore/ui/counter'; ; ``` - + ## AnimatedNumber @@ -21,6 +21,6 @@ import { AnimatedNumber } from '@semcore/ui/counter'; ; ``` - + diff --git a/website/docs/components/slider/slider-api.md b/website/docs/components/slider/slider-api.md index fa7e340d2b..ed11c539a2 100644 --- a/website/docs/components/slider/slider-api.md +++ b/website/docs/components/slider/slider-api.md @@ -11,7 +11,7 @@ import Slider from '@semcore/ui/slider'; ; ``` - + ## Slider.Bar