Skip to content

Commit 18ca79b

Browse files
committed
Refactor component schemas and props for improved type safety and validation
- Introduced new prop types for alert, input, and textarea components to enhance type safety. - Added validation functions for new prop types including alert types, placeholder, max length, and resize options. - Updated existing components to utilize the new prop types and validation methods. - Removed deprecated progress type definitions and refactored related components. - Enhanced the alert and toast components to support new prop types for better customization. - Cleaned up imports and organized schema files for better maintainability.
1 parent 03951c0 commit 18ca79b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

60 files changed

+663
-370
lines changed

AGENTS.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,7 @@ The samples are located in `packages/samples/react` and demonstrate how to use t
226226

227227
- Formatting is enforced via **Prettier** with settings defined in `prettier.config.js` (print width 160, single quotes, tabs).
228228
- `.editorconfig` sets `indent_style = tab` and `max_line_length = 160` for code files. Markdown and YAML files use spaces.
229-
- ESLint and Stylelint are run using `pnpm lint`. Pre‑commit hooks run `lint-staged` which formats and lints changed files.
229+
- ESLint and Stylelint are run using `pnpm lint`. Pre‑commit hooks run `lint-staged` which formats and lints changed files. Lint rules should **not** be disabled via inline comments. Instead, describe the problem and work towards a clean solution.
230230
- Lists and enumerations in code should be kept in alphanumeric order. This also applies to import specifiers and union type literals.
231231
- Commit messages follow the **Conventional Commits** specification.
232232
- See also the [Contributing Guide](CONTRIBUTING.md) for more details on coding conventions and best practices.

packages/components/AGENTS.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,14 @@ To make the components easier to learn, property names and their descriptions sh
5757
- Whenever possible, keep the types of identical property names the same.
5858
- Minimize the number of different properties, descriptions and types.
5959

60+
#### Props Handling
61+
62+
Every property lives in a dedicated file under `src/schema/props`. The file
63+
contains the prop type, the prop schema and a validator function. Components and
64+
their controllers must import these validators instead of implementing custom
65+
logic. Always use the validator exported from the prop schema to keep behaviour
66+
consistent across components.
67+
6068
#### Open vs Show
6169

6270
Use `_open` when the component renders an element on demand, for example a drawer or popover that appears from nothing. Use `_show` when the element already exists in the DOM and you only toggle its visibility.

packages/components/src/components/@deprecated/input/controller.ts

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,21 +18,21 @@ import type {
1818
} from '../../../schema';
1919
import {
2020
a11yHint,
21-
a11yHintDisabled,
2221
devHint,
2322
objectObjectHandler,
2423
parseJson,
2524
setState,
2625
validateAccessKey,
2726
validateAdjustHeight,
27+
validateDisabled,
2828
validateHideMsg,
2929
validateHideLabel,
3030
validateLabelWithExpertSlot,
3131
validateMsg,
32+
validateHint,
3233
validateShortKey,
3334
validateTabIndex,
3435
validateTooltipAlign,
35-
watchBoolean,
3636
watchString,
3737
} from '../../../schema';
3838

@@ -66,10 +66,7 @@ export class InputController extends ControlledInputController implements Watche
6666
}
6767

6868
public validateDisabled(value?: DisabledPropType): void {
69-
watchBoolean(this.component, '_disabled', value);
70-
if (value === true) {
71-
a11yHintDisabled();
72-
}
69+
validateDisabled(this.component, value);
7370
}
7471
public validateTooltipAlign(value?: TooltipAlignPropType): void {
7572
validateTooltipAlign(this.component, value);
@@ -100,7 +97,7 @@ export class InputController extends ControlledInputController implements Watche
10097
}
10198

10299
public validateHint(value?: HintPropType): void {
103-
watchString(this.component, '_hint', value);
100+
validateHint(this.component, value);
104101
}
105102

106103
public validateId(value?: string): void {

packages/components/src/components/alert/component.tsx

Lines changed: 17 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,17 @@
11
import type { JSX } from '@stencil/core';
2-
import { alertTypeOptions, alertVariantOptions, setState, validateHasCloser, validateLabel, watchBoolean, watchValidator } from '../../schema';
2+
import { setState, validateAlertType, validateAlertVariant, validateHasCloser, validateLabel, watchBoolean } from '../../schema';
33
import { Component, Element, h, Prop, State, Watch } from '@stencil/core';
44
import { watchHeadingLevel } from '../heading/validation';
5-
import type { AlertAPI, AlertStates, AlertType, AlertVariant, HasCloserPropType, HeadingLevel, KoliBriAlertEventCallbacks, LabelPropType } from '../../schema';
5+
import type {
6+
AlertAPI,
7+
AlertStates,
8+
AlertTypePropType,
9+
AlertVariantPropType,
10+
HasCloserPropType,
11+
HeadingLevel,
12+
KoliBriAlertEventCallbacks,
13+
LabelPropType,
14+
} from '../../schema';
615
import KolAlertFc, { type KolAlertFcProps } from '../../functional-components/Alert';
716
import { dispatchDomEvent, KolEvent } from '../../utils/events';
817

@@ -78,12 +87,12 @@ export class KolAlertWc implements AlertAPI {
7887
/**
7988
* Defines either the type of the component or of the components interactive element.
8089
*/
81-
@Prop() public _type?: AlertType = 'default';
90+
@Prop() public _type?: AlertTypePropType = 'default';
8291

8392
/**
8493
* Defines which variant should be used for presentation.
8594
*/
86-
@Prop() public _variant?: AlertVariant = 'msg';
95+
@Prop() public _variant?: AlertVariantPropType = 'msg';
8796

8897
@State() public state: AlertStates = {
8998
_level: 0,
@@ -137,25 +146,13 @@ export class KolAlertWc implements AlertAPI {
137146
}
138147

139148
@Watch('_type')
140-
public validateType(value?: AlertType): void {
141-
watchValidator(
142-
this,
143-
'_type',
144-
(value?) => typeof value === 'string' && alertTypeOptions.includes(value),
145-
new Set(`String {${alertTypeOptions.join(', ')}`),
146-
value,
147-
);
149+
public validateType(value?: AlertTypePropType): void {
150+
validateAlertType(this, value);
148151
}
149152

150153
@Watch('_variant')
151-
public validateVariant(value?: AlertVariant): void {
152-
watchValidator(
153-
this,
154-
'_variant',
155-
(value?) => typeof value === 'string' && alertVariantOptions.includes(value),
156-
new Set(`AlertVariant {${alertVariantOptions.join(', ')}`),
157-
value,
158-
);
154+
public validateVariant(value?: AlertVariantPropType): void {
155+
validateAlertVariant(this, value);
159156
}
160157

161158
public componentWillLoad(): void {

packages/components/src/components/alert/shadow.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { AlertProps, AlertStates, AlertType, AlertVariant, HeadingLevel, KoliBriAlertEventCallbacks, LabelPropType } from '../../schema';
1+
import type { AlertProps, AlertStates, AlertTypePropType, AlertVariantPropType, HeadingLevel, KoliBriAlertEventCallbacks, LabelPropType } from '../../schema';
22
import type { JSX } from '@stencil/core';
33
import { Component, h, Prop, State } from '@stencil/core';
44
import { KolAlertWcTag } from '../../core/component-names';
@@ -59,12 +59,12 @@ export class KolAlert implements AlertProps {
5959
/**
6060
* Defines either the type of the component or of the components interactive element.
6161
*/
62-
@Prop() public _type?: AlertType = 'default';
62+
@Prop() public _type?: AlertTypePropType = 'default';
6363

6464
/**
6565
* Defines which variant should be used for presentation.
6666
*/
67-
@Prop() public _variant?: AlertVariant = 'msg';
67+
@Prop() public _variant?: AlertVariantPropType = 'msg';
6868

6969
@State() public state: AlertStates = {
7070
_level: 0,

packages/components/src/components/combobox/controller.ts

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import type { ComboboxWatches, ComboboxProps, SuggestionsPropType } from '../../schema';
2-
import { watchBoolean, validateSuggestions, watchString } from '../../schema';
1+
import type { ComboboxProps, ComboboxWatches, PlaceholderPropType, RequiredPropType, SuggestionsPropType } from '../../schema';
2+
import { validatePlaceholder, validateRequired, validateSuggestions, watchString } from '../../schema';
33

44
import { InputIconController } from '../@deprecated/input/controller-icon';
55

@@ -13,11 +13,12 @@ export class ComboboxController extends InputIconController implements ComboboxW
1313
this.component = component;
1414
}
1515

16-
public validatePlaceholder(value?: string): void {
17-
watchString(this.component, '_placeholder', value);
16+
public validatePlaceholder(value?: PlaceholderPropType): void {
17+
validatePlaceholder(this.component, value);
1818
}
19-
public validateRequired(value?: boolean): void {
20-
watchBoolean(this.component, '_required', value);
19+
20+
public validateRequired(value?: RequiredPropType): void {
21+
validateRequired(this.component, value);
2122
}
2223

2324
public validateSuggestions(value?: SuggestionsPropType): void {

packages/components/src/components/combobox/shadow.tsx

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,39 @@
11
import type { JSX } from '@stencil/core';
22
import { Component, Element, h, Listen, Method, Prop, State, Watch } from '@stencil/core';
3+
import clsx from 'clsx';
4+
import { getRenderStates } from '../../functional-component-wrappers/_helpers/getRenderStates';
5+
import KolFormFieldStateWrapperFc, { type FormFieldStateWrapperProps } from '../../functional-component-wrappers/FormFieldStateWrapper/FormFieldStateWrapper';
6+
import KolInputContainerFc from '../../functional-component-wrappers/InputContainerStateWrapper/InputContainerStateWrapper';
7+
import type { InputStateWrapperProps } from '../../functional-component-wrappers/InputStateWrapper/InputStateWrapper';
8+
import KolInputStateWrapperFc from '../../functional-component-wrappers/InputStateWrapper/InputStateWrapper';
9+
import CustomSuggestionsOptionFc from '../../functional-components/CustomSuggestionsOption/CustomSuggestionsOption';
10+
import CustomSuggestionsOptionsGroupFc from '../../functional-components/CustomSuggestionsOptionsGroup';
11+
import CustomSuggestionsToggleFc from '../../functional-components/CustomSuggestionsToggle';
312
import type {
413
ComboboxAPI,
514
ComboboxStates,
15+
DisabledPropType,
16+
HideLabelPropType,
617
HideMsgPropType,
18+
HintPropType,
719
IconsHorizontalPropType,
820
IdPropType,
921
InputTypeOnDefault,
1022
LabelWithExpertSlotPropType,
1123
MsgPropType,
1224
NamePropType,
25+
PlaceholderPropType,
26+
RequiredPropType,
1327
ShortKeyPropType,
1428
Stringified,
1529
SuggestionsPropType,
1630
SyncValueBySelectorPropType,
1731
TooltipAlignPropType,
18-
DisabledPropType,
19-
HideLabelPropType,
20-
HintPropType,
2132
W3CInputValue,
2233
} from '../../schema';
23-
import clsx from 'clsx';
34+
import type { EventDetail } from '../../schema/interfaces/EventDetail';
2435
import { nonce } from '../../utils/dev.utils';
25-
import KolFormFieldStateWrapperFc, { type FormFieldStateWrapperProps } from '../../functional-component-wrappers/FormFieldStateWrapper/FormFieldStateWrapper';
2636
import { ComboboxController } from './controller';
27-
import { getRenderStates } from '../../functional-component-wrappers/_helpers/getRenderStates';
28-
import type { InputStateWrapperProps } from '../../functional-component-wrappers/InputStateWrapper/InputStateWrapper';
29-
import KolInputStateWrapperFc from '../../functional-component-wrappers/InputStateWrapper/InputStateWrapper';
30-
import KolInputContainerFc from '../../functional-component-wrappers/InputContainerStateWrapper/InputContainerStateWrapper';
31-
import CustomSuggestionsToggleFc from '../../functional-components/CustomSuggestionsToggle';
32-
import CustomSuggestionsOptionFc from '../../functional-components/CustomSuggestionsOption/CustomSuggestionsOption';
33-
import CustomSuggestionsOptionsGroupFc from '../../functional-components/CustomSuggestionsOptionsGroup';
34-
import type { EventDetail } from '../../schema/interfaces/EventDetail';
3537

3638
/**
3739
* @slot - Die Beschriftung des Eingabefeldes.
@@ -490,7 +492,7 @@ export class KolCombobox implements ComboboxAPI {
490492
}
491493

492494
@Watch('_placeholder')
493-
public validatePlaceholder(value?: string): void {
495+
public validatePlaceholder(value?: PlaceholderPropType): void {
494496
this.controller.validatePlaceholder(value);
495497
}
496498

@@ -561,7 +563,7 @@ export class KolCombobox implements ComboboxAPI {
561563
}
562564

563565
@Watch('_required')
564-
public validateRequired(value?: boolean): void {
566+
public validateRequired(value?: RequiredPropType): void {
565567
this.controller.validateRequired(value);
566568
}
567569

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,8 @@
11
import type { HeadingLevel } from '../../schema';
2-
import { headingLevelOptions, watchValidator } from '../../schema';
2+
import { validateLevel } from '../../schema';
33

44
import type { Generic } from 'adopted-style-sheets';
55

66
export const watchHeadingLevel = (component: Generic.Element.Component, value?: HeadingLevel): void => {
7-
watchValidator(
8-
component,
9-
'_level',
10-
(value?: HeadingLevel): boolean => {
11-
return typeof value === 'number' && headingLevelOptions.includes(value);
12-
},
13-
new Set([`Number {${headingLevelOptions.join(', ')}`]),
14-
value,
15-
{
16-
// TODO: options not in the validator
17-
defaultValue: 1,
18-
required: true,
19-
},
20-
);
7+
validateLevel(component, value);
218
};

packages/components/src/components/input-checkbox/controller.ts

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,15 @@ import type {
22
CheckedPropType,
33
IndeterminatePropType,
44
InputCheckboxIconsProp,
5+
InputCheckboxIconsPropType,
56
InputCheckboxIconsState,
67
InputCheckboxProps,
7-
InputCheckboxVariant,
8+
InputCheckboxVariantPropType,
89
InputCheckboxWatches,
910
LabelAlignPropType,
1011
StencilUnknown,
11-
Stringified,
1212
} from '../../schema';
13-
import { inputCheckboxVariantOptions, isString, setState, validateChecked, validateIndeterminate, validateLabelAlign, watchValidator } from '../../schema';
13+
import { isString, setState, validateChecked, validateIndeterminate, validateLabelAlign, validateVariantInputCheckbox, watchValidator } from '../../schema';
1414

1515
import { InputCheckboxRadioController } from '../input-radio/controller';
1616

@@ -36,15 +36,16 @@ export class InputCheckboxController extends InputCheckboxRadioController implem
3636
this.setFormAssociatedCheckboxValue(this.component.state._value as StencilUnknown);
3737
}
3838

39-
public validateIcons(value?: Stringified<InputCheckboxIconsProp>): void {
40-
watchValidator(
39+
public validateIcons(value?: InputCheckboxIconsPropType): void {
40+
watchValidator<unknown>(
4141
this.component,
4242
'_icons',
4343
(value): boolean => {
44-
return typeof value === 'object' && value !== null && (isString(value.checked, 1) || isString(value.indeterminate, 1) || isString(value.unchecked, 1));
44+
const v = value as Record<string, unknown>;
45+
return typeof v === 'object' && v !== null && (isString(v.checked, 1) || isString(v.indeterminate, 1) || isString(v.unchecked, 1));
4546
},
4647
new Set(['InputCheckboxIcons']),
47-
value,
48+
value as unknown,
4849
{
4950
hooks: {
5051
beforePatch: (nextValue: unknown, nextState: Map<string, unknown>, component: Generic.Element.Component) => {
@@ -71,14 +72,8 @@ export class InputCheckboxController extends InputCheckboxRadioController implem
7172
this.setFormAssociatedCheckboxValue(this.component.state._value as StencilUnknown);
7273
}
7374

74-
public validateVariant(value?: InputCheckboxVariant): void {
75-
watchValidator(
76-
this.component,
77-
'_variant',
78-
(value): boolean => typeof value === 'string' && inputCheckboxVariantOptions.includes(value),
79-
new Set([`String {${inputCheckboxVariantOptions.join(', ')}`]),
80-
value,
81-
);
75+
public validateVariant(value?: InputCheckboxVariantPropType): void {
76+
validateVariantInputCheckbox(this.component, value);
8277
}
8378

8479
public componentWillLoad(): void {

0 commit comments

Comments
 (0)