@db-ux/react-core-components 4.5.4 → 4.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +15 -0
- package/README.md +91 -0
- package/dist/components/input/input.js +1 -3
- package/dist/components/textarea/textarea.js +1 -3
- package/dist/shared/model.d.ts +1 -1
- package/dist/utils/form-components.d.ts +1 -1
- package/dist/utils/form-components.js +25 -3
- package/dist/utils/form-components.spec.d.ts +1 -0
- package/dist/utils/form-components.spec.js +167 -0
- package/package.json +4 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
# @db-ux/react-core-components
|
|
2
2
|
|
|
3
|
+
## 4.6.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- refactor: exclude whitelabel-theme from default bundle to reduce size and to align with "how to import a theme" - [see commit f272967](https://github.com/db-ux-design-system/core-web/commit/f272967acb7a37dc9b07d9786134e437b284e9b6)
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- fix: issue with tailwind duplicating some classes by using `@theme` inline - [see commit 92de4e6](https://github.com/db-ux-design-system/core-web/commit/92de4e6e5fdad3be5629d7457944d3b9b7396cf4)
|
|
12
|
+
|
|
13
|
+
- docs(vite): mentioning version 8 configuration in `README.md` file - [see commit 4c5fc92](https://github.com/db-ux-design-system/core-web/commit/4c5fc9266402d9585087f4738a1a800cff1515f1)
|
|
14
|
+
|
|
15
|
+
- fix(number input): prevent from clearing on intermediate decimal entry - [see commit aa85967](https://github.com/db-ux-design-system/core-web/commit/aa85967ffeaa685f6b647069d0e1d415d812dc87):
|
|
16
|
+
- fix(input,textarea): allow using `undefined` as `value`
|
|
17
|
+
|
|
3
18
|
## 4.5.4
|
|
4
19
|
|
|
5
20
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -44,8 +44,61 @@ import "@db-ux/core-components/build/styles/rollup.css";
|
|
|
44
44
|
|
|
45
45
|
</details>
|
|
46
46
|
|
|
47
|
+
### Vite 8
|
|
48
|
+
|
|
49
|
+
Starting with Vite 8, the default CSS minifier was changed to [LightningCSS](https://lightningcss.dev/), which provides buggy transformations for modern CSS features used by the DB UX Design System (e.g. `light-dark()` CSS function). To keep CSS output stable, configure `vite.config.ts` like this:
|
|
50
|
+
|
|
51
|
+
```ts
|
|
52
|
+
// vite.config.ts
|
|
53
|
+
export default defineConfig({
|
|
54
|
+
build: {
|
|
55
|
+
cssMinify: "esbuild"
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
> Alternatively, you could define a [browserslist](https://browsersl.ist/) based on your individual browser support strategy — which might be totally different from the list Vite 8 defines by default (targeting browsers from the early 2020s):
|
|
61
|
+
|
|
62
|
+
```ts
|
|
63
|
+
// Note: You need to install the required packages first:
|
|
64
|
+
// npm install -D lightningcss browserslist
|
|
65
|
+
|
|
66
|
+
// vite.config.ts
|
|
67
|
+
import { browserslistToTargets } from "lightningcss";
|
|
68
|
+
import browserslist from "browserslist";
|
|
69
|
+
|
|
70
|
+
export default defineConfig({
|
|
71
|
+
css: {
|
|
72
|
+
lightningcss: {
|
|
73
|
+
targets: browserslistToTargets(browserslist(">= 0.5%, last 2 major versions, Firefox ESR, not dead"))
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
```
|
|
78
|
+
|
|
47
79
|
> **Note:** The `@db-ux/core-components/build/styles/relative` file contains optional and all components styles. If you consider performance issues see [@db-ux/core-components](https://www.npmjs.com/package/@db-ux/core-components) for more information.
|
|
48
80
|
|
|
81
|
+
### Next 16
|
|
82
|
+
|
|
83
|
+
Starting with Next 16, the default CSS minifier was changed to [LightningCSS](https://lightningcss.dev/), which provides buggy transformations for modern CSS features used by the DB UX Design System (e.g. `light-dark()` CSS function). We might provide a specific configuration necessary to mitigate those problems in the near future. To keep CSS output stable in the meantime, configure `next.config.ts` like this:
|
|
84
|
+
|
|
85
|
+
````ts
|
|
86
|
+
// next.config.ts
|
|
87
|
+
|
|
88
|
+
import type { NextConfig } from 'next'
|
|
89
|
+
|
|
90
|
+
const nextConfig: NextConfig = {
|
|
91
|
+
experimental: {
|
|
92
|
+
useLightningcss: true,
|
|
93
|
+
lightningCssFeatures: {
|
|
94
|
+
exclude: ['light-dark'],
|
|
95
|
+
},
|
|
96
|
+
},
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export default nextConfig
|
|
100
|
+
````
|
|
101
|
+
|
|
49
102
|
### DB Theme
|
|
50
103
|
|
|
51
104
|
In case that you're building a website or application for Deutsche Bahn, you'll additionally have to install the DB Theme via the [`@db-ux/db-theme`](https://www.npmjs.com/package/@db-ux/db-theme) node package (even also available as an inner source node package, as described within that packages README).
|
|
@@ -75,6 +128,44 @@ This will create or update `.github/copilot-instructions.md` with component docu
|
|
|
75
128
|
|
|
76
129
|
📖 **[Learn more about `@db-ux/agent-cli` node package](packages/agent-cli/README.md)**
|
|
77
130
|
|
|
131
|
+
## Code Quality
|
|
132
|
+
|
|
133
|
+
To enforce correct usage of DB UX Design System components in your React project, we provide the [`@db-ux/core-eslint-plugin`](https://www.npmjs.com/package/@db-ux/core-eslint-plugin) ESLint plugin.
|
|
134
|
+
|
|
135
|
+
### Installation
|
|
136
|
+
|
|
137
|
+
```shell
|
|
138
|
+
npm install eslint @db-ux/core-eslint-plugin @typescript-eslint/parser --save-dev
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### Setup
|
|
142
|
+
|
|
143
|
+
```js
|
|
144
|
+
// eslint.config.js
|
|
145
|
+
import dbUx from "@db-ux/core-eslint-plugin";
|
|
146
|
+
import tsParser from "@typescript-eslint/parser";
|
|
147
|
+
|
|
148
|
+
export default [
|
|
149
|
+
{
|
|
150
|
+
files: ["**/*.ts", "**/*.tsx"],
|
|
151
|
+
languageOptions: {
|
|
152
|
+
parser: tsParser,
|
|
153
|
+
parserOptions: {
|
|
154
|
+
ecmaVersion: "latest",
|
|
155
|
+
sourceType: "module",
|
|
156
|
+
ecmaFeatures: { jsx: true }
|
|
157
|
+
}
|
|
158
|
+
},
|
|
159
|
+
plugins: {
|
|
160
|
+
"db-ux": dbUx
|
|
161
|
+
},
|
|
162
|
+
rules: dbUx.configs.recommended.rules
|
|
163
|
+
}
|
|
164
|
+
];
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
📖 **[Learn more about `@db-ux/core-eslint-plugin` node package](https://www.npmjs.com/package/@db-ux/core-eslint-plugin)**
|
|
168
|
+
|
|
78
169
|
## Deutsche Bahn brand
|
|
79
170
|
|
|
80
171
|
As we'd like to perfectly support our users and customers on their digital journey, the usage of Deutsche Bahn brand and trademarks are bound of clear guidelines and restrictions even if being used with the code that we're providing with this product; Deutsche Bahn fully reserves all rights regarding the Deutsche Bahn brand, even though that we're providing the code of DB UX Design System products free to use and release it under the Apache 2.0 license.
|
|
@@ -125,9 +125,7 @@ function DBInputFn(props, component) {
|
|
|
125
125
|
}
|
|
126
126
|
}, [_id]);
|
|
127
127
|
useEffect(() => {
|
|
128
|
-
|
|
129
|
-
set_value(props.value);
|
|
130
|
-
}
|
|
128
|
+
set_value(props.value);
|
|
131
129
|
}, [props.value]);
|
|
132
130
|
useEffect(() => {
|
|
133
131
|
// If angular uses ngModel value and _value are null
|
|
@@ -112,9 +112,7 @@ function DBTextareaFn(props, component) {
|
|
|
112
112
|
}
|
|
113
113
|
}, [_id]);
|
|
114
114
|
useEffect(() => {
|
|
115
|
-
|
|
116
|
-
set_value(props.value);
|
|
117
|
-
}
|
|
115
|
+
set_value(props.value);
|
|
118
116
|
}, [props.value]);
|
|
119
117
|
useEffect(() => {
|
|
120
118
|
// If angular uses ngModel value and _value are null
|
package/dist/shared/model.d.ts
CHANGED
|
@@ -22,7 +22,7 @@ export interface GlobalProps {
|
|
|
22
22
|
*/
|
|
23
23
|
autofocus?: boolean | string;
|
|
24
24
|
/**
|
|
25
|
-
* Allows overriding specific props on nested elements or internal component structure.
|
|
25
|
+
* Allows overriding specific props on nested elements or internal component structure. Currently only supports propOverrides.id
|
|
26
26
|
*/
|
|
27
27
|
propOverrides?: PropOverridesType;
|
|
28
28
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export declare const handleFrameworkEventAngular: (component: any, event: any, modelValue?: string) => void;
|
|
1
|
+
export declare const handleFrameworkEventAngular: (component: any, event: any, modelValue?: string, lastValue?: any) => void;
|
|
2
2
|
export declare const handleFrameworkEventVue: (emit: (event: string, ...args: any[]) => void, event: any, modelValue?: string) => void;
|
|
3
3
|
export declare const addResetEventListener: (element: any, resetFunction: (event: Event) => void, signal: AbortSignal) => void;
|
|
4
4
|
export declare const addCheckedResetEventListener: (element: any, props: {
|
|
@@ -1,8 +1,30 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
2
|
import { delay } from './index';
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
const specialNumberCharacters = ['.', ',', 'e', 'E', '+', '-'];
|
|
4
|
+
export const handleFrameworkEventAngular = (component, event, modelValue = 'value', lastValue) => {
|
|
5
|
+
var _a;
|
|
6
|
+
const value = event.target[modelValue];
|
|
7
|
+
const type = (_a = event.target) === null || _a === void 0 ? void 0 : _a.type;
|
|
8
|
+
if (!value && value !== '' && ['date', 'time', 'week', 'month', 'datetime-local'].includes(type)) {
|
|
9
|
+
// If value is empty and type date we skip `writingValue` function
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
if (type === 'number') {
|
|
13
|
+
if (event.type === 'input') {
|
|
14
|
+
if (specialNumberCharacters.includes(event.data) || specialNumberCharacters.some(specialCharacter => lastValue === null || lastValue === void 0 ? void 0 : lastValue.toString().includes(specialCharacter)) && event.inputType === 'deleteContentBackward') {
|
|
15
|
+
// Skip `writingValue` function if number type and input event
|
|
16
|
+
// and `.` or `,` or 'e', 'E', '+', '-' was typed
|
|
17
|
+
// or content was deleted but last number had a `.`
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
else if (event.type === 'change') {
|
|
22
|
+
// Skip `writingValue` function if number type and change event
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
component.propagateChange(value);
|
|
27
|
+
component.writeValue(value);
|
|
6
28
|
};
|
|
7
29
|
export const handleFrameworkEventVue = (emit, event, modelValue = 'value') => {
|
|
8
30
|
// TODO: Replace this with the solution out of https://github.com/BuilderIO/mitosis/issues/833 after this has been "solved"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
2
|
+
import { handleFrameworkEventAngular, handleFrameworkEventVue } from './form-components';
|
|
3
|
+
const createNumberEvent = (value, badInput, inputType) => ({
|
|
4
|
+
inputType,
|
|
5
|
+
target: {
|
|
6
|
+
type: 'number',
|
|
7
|
+
value,
|
|
8
|
+
validity: {
|
|
9
|
+
badInput
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
});
|
|
13
|
+
const createTextEvent = (value) => ({
|
|
14
|
+
target: {
|
|
15
|
+
type: 'text',
|
|
16
|
+
value,
|
|
17
|
+
validity: {
|
|
18
|
+
badInput: false
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
describe('handleFrameworkEventAngular', () => {
|
|
23
|
+
it('calls propagateChange and writeValue for valid number value', () => {
|
|
24
|
+
const component = {
|
|
25
|
+
propagateChange: vi.fn(),
|
|
26
|
+
writeValue: vi.fn()
|
|
27
|
+
};
|
|
28
|
+
const event = createNumberEvent('1.5', false);
|
|
29
|
+
handleFrameworkEventAngular(component, event);
|
|
30
|
+
expect(component.propagateChange).toHaveBeenCalledWith('1.5');
|
|
31
|
+
expect(component.writeValue).toHaveBeenCalledWith('1.5');
|
|
32
|
+
});
|
|
33
|
+
it('skips propagateChange and writeValue when "." is typed (intermediate state)', () => {
|
|
34
|
+
const component = {
|
|
35
|
+
propagateChange: vi.fn(),
|
|
36
|
+
writeValue: vi.fn()
|
|
37
|
+
};
|
|
38
|
+
const event = {
|
|
39
|
+
type: 'input',
|
|
40
|
+
data: '.',
|
|
41
|
+
inputType: 'insertText',
|
|
42
|
+
target: {
|
|
43
|
+
type: 'number',
|
|
44
|
+
value: '1.'
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
handleFrameworkEventAngular(component, event, 'value', '1');
|
|
48
|
+
expect(component.propagateChange).not.toHaveBeenCalled();
|
|
49
|
+
expect(component.writeValue).not.toHaveBeenCalled();
|
|
50
|
+
});
|
|
51
|
+
it('skips propagateChange and writeValue when "," is typed (intermediate state)', () => {
|
|
52
|
+
const component = {
|
|
53
|
+
propagateChange: vi.fn(),
|
|
54
|
+
writeValue: vi.fn()
|
|
55
|
+
};
|
|
56
|
+
const event = {
|
|
57
|
+
type: 'input',
|
|
58
|
+
data: ',',
|
|
59
|
+
inputType: 'insertText',
|
|
60
|
+
target: {
|
|
61
|
+
type: 'number',
|
|
62
|
+
value: ''
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
handleFrameworkEventAngular(component, event, 'value', '1');
|
|
66
|
+
expect(component.propagateChange).not.toHaveBeenCalled();
|
|
67
|
+
expect(component.writeValue).not.toHaveBeenCalled();
|
|
68
|
+
});
|
|
69
|
+
it.each(['e', 'E', '+', '-'])('skips propagateChange and writeValue when "%s" is typed (intermediate state)', char => {
|
|
70
|
+
const component = {
|
|
71
|
+
propagateChange: vi.fn(),
|
|
72
|
+
writeValue: vi.fn()
|
|
73
|
+
};
|
|
74
|
+
const event = {
|
|
75
|
+
type: 'input',
|
|
76
|
+
data: char,
|
|
77
|
+
inputType: 'insertText',
|
|
78
|
+
target: {
|
|
79
|
+
type: 'number',
|
|
80
|
+
value: ''
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
handleFrameworkEventAngular(component, event, 'value', '1');
|
|
84
|
+
expect(component.propagateChange).not.toHaveBeenCalled();
|
|
85
|
+
expect(component.writeValue).not.toHaveBeenCalled();
|
|
86
|
+
});
|
|
87
|
+
it('skips propagateChange and writeValue when deleting content and lastValue has decimal', () => {
|
|
88
|
+
const component = {
|
|
89
|
+
propagateChange: vi.fn(),
|
|
90
|
+
writeValue: vi.fn()
|
|
91
|
+
};
|
|
92
|
+
const event = {
|
|
93
|
+
type: 'input',
|
|
94
|
+
data: null,
|
|
95
|
+
inputType: 'deleteContentBackward',
|
|
96
|
+
target: {
|
|
97
|
+
type: 'number',
|
|
98
|
+
value: ''
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
handleFrameworkEventAngular(component, event, 'value', '1.5');
|
|
102
|
+
expect(component.propagateChange).not.toHaveBeenCalled();
|
|
103
|
+
expect(component.writeValue).not.toHaveBeenCalled();
|
|
104
|
+
});
|
|
105
|
+
it('calls propagateChange and writeValue when number input is cleared via backspace (no decimal in lastValue)', () => {
|
|
106
|
+
const component = {
|
|
107
|
+
propagateChange: vi.fn(),
|
|
108
|
+
writeValue: vi.fn()
|
|
109
|
+
};
|
|
110
|
+
const event = createNumberEvent('', false, 'deleteContentBackward');
|
|
111
|
+
handleFrameworkEventAngular(component, event);
|
|
112
|
+
expect(component.propagateChange).toHaveBeenCalledWith('');
|
|
113
|
+
expect(component.writeValue).toHaveBeenCalledWith('');
|
|
114
|
+
});
|
|
115
|
+
it('skips propagateChange and writeValue for number change events', () => {
|
|
116
|
+
const component = {
|
|
117
|
+
propagateChange: vi.fn(),
|
|
118
|
+
writeValue: vi.fn()
|
|
119
|
+
};
|
|
120
|
+
const event = {
|
|
121
|
+
type: 'change',
|
|
122
|
+
target: {
|
|
123
|
+
type: 'number',
|
|
124
|
+
value: '5'
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
handleFrameworkEventAngular(component, event);
|
|
128
|
+
expect(component.propagateChange).not.toHaveBeenCalled();
|
|
129
|
+
expect(component.writeValue).not.toHaveBeenCalled();
|
|
130
|
+
});
|
|
131
|
+
it('calls propagateChange and writeValue for text input type', () => {
|
|
132
|
+
const component = {
|
|
133
|
+
propagateChange: vi.fn(),
|
|
134
|
+
writeValue: vi.fn()
|
|
135
|
+
};
|
|
136
|
+
const event = createTextEvent('hello');
|
|
137
|
+
handleFrameworkEventAngular(component, event);
|
|
138
|
+
expect(component.propagateChange).toHaveBeenCalledWith('hello');
|
|
139
|
+
expect(component.writeValue).toHaveBeenCalledWith('hello');
|
|
140
|
+
});
|
|
141
|
+
});
|
|
142
|
+
describe('handleFrameworkEventVue', () => {
|
|
143
|
+
it('emits update:value for valid number value', () => {
|
|
144
|
+
const emit = vi.fn();
|
|
145
|
+
const event = createNumberEvent('1.5', false);
|
|
146
|
+
handleFrameworkEventVue(emit, event);
|
|
147
|
+
expect(emit).toHaveBeenCalledWith('update:value', '1.5');
|
|
148
|
+
});
|
|
149
|
+
it('emits update:value with empty string when number input has badInput (intermediate state like "1.")', () => {
|
|
150
|
+
const emit = vi.fn();
|
|
151
|
+
const event = createNumberEvent('', true);
|
|
152
|
+
handleFrameworkEventVue(emit, event);
|
|
153
|
+
expect(emit).toHaveBeenCalledWith('update:value', '');
|
|
154
|
+
});
|
|
155
|
+
it('emits update:value when number input is cleared (empty, no badInput)', () => {
|
|
156
|
+
const emit = vi.fn();
|
|
157
|
+
const event = createNumberEvent('', false);
|
|
158
|
+
handleFrameworkEventVue(emit, event);
|
|
159
|
+
expect(emit).toHaveBeenCalledWith('update:value', '');
|
|
160
|
+
});
|
|
161
|
+
it('emits update:value for text input type', () => {
|
|
162
|
+
const emit = vi.fn();
|
|
163
|
+
const event = createTextEvent('hello');
|
|
164
|
+
handleFrameworkEventVue(emit, event);
|
|
165
|
+
expect(emit).toHaveBeenCalledWith('update:value', 'hello');
|
|
166
|
+
});
|
|
167
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@db-ux/react-core-components",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.6.0",
|
|
4
4
|
"description": "React components for @db-ux/core-components",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"tsc": "tsc --project . --sourceMap false"
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
33
|
-
"@playwright/experimental-ct-react": "1.
|
|
33
|
+
"@playwright/experimental-ct-react": "1.59.1",
|
|
34
34
|
"@types/react": "19.2.14",
|
|
35
35
|
"react": "19.2.4",
|
|
36
36
|
"react-dom": "19.2.4"
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
},
|
|
42
42
|
"sideEffects": false,
|
|
43
43
|
"dependencies": {
|
|
44
|
-
"@db-ux/core-components": "4.
|
|
45
|
-
"@db-ux/core-foundations": "4.
|
|
44
|
+
"@db-ux/core-components": "4.6.0",
|
|
45
|
+
"@db-ux/core-foundations": "4.6.0"
|
|
46
46
|
}
|
|
47
47
|
}
|