@spaced-out/ui-design-system 0.5.9 → 0.5.10
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/.github/workflows/publish_to_npm.yml +21 -27
- package/.storybook/main.ts +1 -1
- package/CHANGELOG.md +16 -0
- package/eslint.config.mjs +41 -25
- package/lib/utils/index.d.ts +1 -0
- package/lib/utils/index.d.ts.map +1 -1
- package/lib/utils/index.js +11 -0
- package/lib/utils/qa/index.d.ts +2 -0
- package/lib/utils/qa/index.d.ts.map +1 -0
- package/lib/utils/qa/index.js +16 -0
- package/lib/utils/qa/qa.d.ts +30 -0
- package/lib/utils/qa/qa.d.ts.map +1 -0
- package/lib/utils/qa/qa.js +52 -0
- package/package.json +2 -1
|
@@ -2,14 +2,10 @@
|
|
|
2
2
|
# Note: Do not change
|
|
3
3
|
|
|
4
4
|
name: Release Genesis to NPM
|
|
5
|
+
|
|
5
6
|
on:
|
|
6
7
|
workflow_dispatch:
|
|
7
8
|
inputs:
|
|
8
|
-
branch:
|
|
9
|
-
# Note(Nishant): New input added to dynamically select release branch from UI
|
|
10
|
-
description: 'Branch to release from'
|
|
11
|
-
required: true
|
|
12
|
-
default: master
|
|
13
9
|
release-type:
|
|
14
10
|
description: 'Select Release type (prerelease appends beta in build number)'
|
|
15
11
|
type: choice
|
|
@@ -19,6 +15,7 @@ on:
|
|
|
19
15
|
- major
|
|
20
16
|
- prerelease
|
|
21
17
|
required: true
|
|
18
|
+
|
|
22
19
|
jobs:
|
|
23
20
|
release:
|
|
24
21
|
runs-on: ubuntu-latest
|
|
@@ -40,8 +37,8 @@ jobs:
|
|
|
40
37
|
uses: actions/checkout@v4
|
|
41
38
|
with:
|
|
42
39
|
token: ${{ secrets.NPM_PUBLISH_USER_ACCESS_TOKEN }}
|
|
43
|
-
fetch-depth:
|
|
44
|
-
ref: ${{ github.
|
|
40
|
+
fetch-depth: 0
|
|
41
|
+
ref: ${{ github.ref }} # e.g. refs/heads/master (from the UI selector)
|
|
45
42
|
|
|
46
43
|
- name: Setup Node.js
|
|
47
44
|
uses: actions/setup-node@v4
|
|
@@ -49,25 +46,20 @@ jobs:
|
|
|
49
46
|
registry-url: https://registry.npmjs.org/
|
|
50
47
|
node-version: '22.18.0'
|
|
51
48
|
|
|
52
|
-
# -------------------------------------------------------------------------------------
|
|
53
|
-
# Note(Nishant): Install isolated dependencies
|
|
54
|
-
# -------------------------------------------------------------------------------------
|
|
55
49
|
- name: Install dependencies
|
|
56
|
-
run:
|
|
57
|
-
yarn install
|
|
50
|
+
run: yarn install
|
|
58
51
|
|
|
59
52
|
# ToDo(Nishant): Activate this once we have chromatic tests ready.
|
|
60
|
-
|
|
61
|
-
#
|
|
53
|
+
# - name: Run tests
|
|
54
|
+
# run: yarn test
|
|
62
55
|
|
|
63
|
-
# Configure Git. TODO(Nishant): update with a org bot instead of personal detail
|
|
64
56
|
- name: Git configuration
|
|
65
57
|
run: |
|
|
66
58
|
git config --global user.email "86281150+superrover@users.noreply.github.com"
|
|
67
59
|
git config --global user.name "Nishant Gaurav"
|
|
68
|
-
git fetch --all
|
|
69
|
-
git checkout ${
|
|
70
|
-
git pull origin ${
|
|
60
|
+
git fetch --all --tags
|
|
61
|
+
git checkout "${GITHUB_REF_NAME}"
|
|
62
|
+
git pull --ff-only origin "${GITHUB_REF_NAME}"
|
|
71
63
|
|
|
72
64
|
# Bump package version
|
|
73
65
|
# Use tag latest
|
|
@@ -76,7 +68,7 @@ jobs:
|
|
|
76
68
|
- name: Validate release type against selected branch
|
|
77
69
|
id: validate-release
|
|
78
70
|
run: |
|
|
79
|
-
BRANCH="${
|
|
71
|
+
BRANCH="${GITHUB_REF_NAME}"
|
|
80
72
|
RELEASE_TYPE="${{ github.event.inputs.release-type }}"
|
|
81
73
|
|
|
82
74
|
if [[ "$BRANCH" != "master" && "$RELEASE_TYPE" != "prerelease" ]]; then
|
|
@@ -85,11 +77,11 @@ jobs:
|
|
|
85
77
|
fi
|
|
86
78
|
|
|
87
79
|
if [[ "$RELEASE_TYPE" == "prerelease" ]]; then
|
|
88
|
-
echo "RELEASE_TAG=beta" >> $GITHUB_ENV
|
|
89
|
-
echo "IS_PRERELEASE=true" >> $GITHUB_ENV
|
|
80
|
+
echo "RELEASE_TAG=beta" >> "$GITHUB_ENV"
|
|
81
|
+
echo "IS_PRERELEASE=true" >> "$GITHUB_ENV"
|
|
90
82
|
else
|
|
91
|
-
echo "RELEASE_TAG=latest" >> $GITHUB_ENV
|
|
92
|
-
echo "IS_PRERELEASE=false" >> $GITHUB_ENV
|
|
83
|
+
echo "RELEASE_TAG=latest" >> "$GITHUB_ENV"
|
|
84
|
+
echo "IS_PRERELEASE=false" >> "$GITHUB_ENV"
|
|
93
85
|
fi
|
|
94
86
|
# Note(Nishant): Enforces prerelease-only behavior on non-master branches
|
|
95
87
|
|
|
@@ -102,16 +94,18 @@ jobs:
|
|
|
102
94
|
fi
|
|
103
95
|
# Note(Nishant): Unified step for version bump, respecting prerelease condition
|
|
104
96
|
|
|
105
|
-
|
|
97
|
+
# Push changes
|
|
106
98
|
- name: Push CHANGELOG.md and created release tag
|
|
107
|
-
run: |
|
|
108
|
-
git push --follow-tags origin ${{ github.event.inputs.branch }}
|
|
109
99
|
env:
|
|
110
100
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
101
|
+
run: |
|
|
102
|
+
# Push to the same branch the workflow was dispatched from
|
|
103
|
+
git push --follow-tags origin "${GITHUB_REF_NAME}"
|
|
104
|
+
|
|
111
105
|
# Note(Nishant): Push to selected branch, not hardcoded master
|
|
112
106
|
|
|
113
107
|
# Publish version to NPM repository
|
|
114
108
|
- name: Publish to NPM
|
|
115
|
-
run: yarn publish --verbose --access public --tag ${{ env.RELEASE_TAG }}
|
|
116
109
|
env:
|
|
117
110
|
NODE_AUTH_TOKEN: ${{ secrets.NPM_PUBLISH_TOKEN }}
|
|
111
|
+
run: yarn publish --verbose --access public --tag "$RELEASE_TAG"
|
package/.storybook/main.ts
CHANGED
|
@@ -59,7 +59,7 @@ const config: StorybookConfig = {
|
|
|
59
59
|
process: require.resolve('process/browser'),
|
|
60
60
|
};
|
|
61
61
|
|
|
62
|
-
// Fix font rule clobbering images
|
|
62
|
+
// Fix font rule clobbering images
|
|
63
63
|
config.module!.rules = (config.module!.rules || []).map((rule: any) => {
|
|
64
64
|
if (rule.test && rule.test.toString().includes('woff')) {
|
|
65
65
|
return {
|
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,22 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
|
4
4
|
|
|
5
|
+
### [0.5.10](https://github.com/spaced-out/ui-design-system/compare/v0.5.9...v0.5.10) (2025-09-23)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### Features
|
|
9
|
+
|
|
10
|
+
* introduces new util and story for generating data-testids ([4baf068](https://github.com/spaced-out/ui-design-system/commit/4baf0680bfe3d1aa9cf86b88c150df97c85271be))
|
|
11
|
+
* release workflow changes ([90a910e](https://github.com/spaced-out/ui-design-system/commit/90a910ea75517b3da60e2156cc508d660b2cc8c4))
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
### Bug Fixes
|
|
15
|
+
|
|
16
|
+
* added stricter eslint rules ([45c42b9](https://github.com/spaced-out/ui-design-system/commit/45c42b9b1a3de57c5420047a247b2028aac5e9dd))
|
|
17
|
+
* added stricter rules ([2ca45da](https://github.com/spaced-out/ui-design-system/commit/2ca45dada041a412c3d43a84b6b442a44542fbf0))
|
|
18
|
+
* fixed scripts to work with alias paths ([b3f1542](https://github.com/spaced-out/ui-design-system/commit/b3f1542710f4347611235b7770858209092dcb0b))
|
|
19
|
+
* rules of hooks fixed ([2eaba73](https://github.com/spaced-out/ui-design-system/commit/2eaba73ab64bd4191852f9926d7e54c1469b5c1b))
|
|
20
|
+
|
|
5
21
|
### [0.5.9](https://github.com/spaced-out/ui-design-system/compare/v0.5.8...v0.5.9) (2025-09-17)
|
|
6
22
|
|
|
7
23
|
|
package/eslint.config.mjs
CHANGED
|
@@ -65,21 +65,21 @@ export default [
|
|
|
65
65
|
files: ['src/**/*.{ts,tsx}'],
|
|
66
66
|
rules: {
|
|
67
67
|
// Core
|
|
68
|
-
'arrow-body-style': ['
|
|
69
|
-
curly: ['
|
|
70
|
-
'comma-spacing': ['
|
|
71
|
-
'eol-last': '
|
|
68
|
+
'arrow-body-style': ['error', 'as-needed'],
|
|
69
|
+
curly: ['error', 'all'],
|
|
70
|
+
'comma-spacing': ['error', {before: false, after: true}],
|
|
71
|
+
'eol-last': 'error',
|
|
72
72
|
eqeqeq: ['error', 'always', {null: 'ignore'}],
|
|
73
73
|
indent: 'off',
|
|
74
|
-
'max-params': ['
|
|
75
|
-
'no-alert': '
|
|
74
|
+
'max-params': ['error', {max: 4}],
|
|
75
|
+
'no-alert': 'error',
|
|
76
76
|
'no-console': ['error', {allow: ['warn', 'error']}],
|
|
77
77
|
'no-dupe-args': 'error',
|
|
78
78
|
'no-dupe-keys': 'error',
|
|
79
79
|
'no-duplicate-case': 'error',
|
|
80
80
|
// Allow TS overloads
|
|
81
81
|
'no-dupe-class-members': 'off',
|
|
82
|
-
'no-empty-function': '
|
|
82
|
+
'no-empty-function': 'error',
|
|
83
83
|
'no-empty-pattern': 'error',
|
|
84
84
|
'no-eval': 'error',
|
|
85
85
|
'no-extend-native': 'error',
|
|
@@ -94,43 +94,51 @@ export default [
|
|
|
94
94
|
'no-redeclare': 'off', // use TS rule
|
|
95
95
|
'no-restricted-globals': ['error', 'event', 'location'],
|
|
96
96
|
'no-sparse-arrays': 'error',
|
|
97
|
-
'no-tabs': '
|
|
97
|
+
'no-tabs': 'error',
|
|
98
98
|
'no-this-before-super': 'error',
|
|
99
|
-
'no-trailing-spaces': '
|
|
99
|
+
'no-trailing-spaces': 'error',
|
|
100
100
|
'no-underscore-dangle': 'off',
|
|
101
|
-
'no-unmodified-loop-condition': '
|
|
101
|
+
'no-unmodified-loop-condition': 'error',
|
|
102
102
|
'no-undef': 'off', // TS handles this
|
|
103
|
-
'no-unreachable': '
|
|
103
|
+
'no-unreachable': 'error',
|
|
104
104
|
'no-useless-constructor': 'off', // use TS rule
|
|
105
105
|
'no-var': 'error',
|
|
106
106
|
'no-with': 'error',
|
|
107
107
|
'object-shorthand': 'error',
|
|
108
108
|
'prefer-arrow-callback': 'error',
|
|
109
|
-
'prefer-const': '
|
|
110
|
-
'prefer-spread': '
|
|
111
|
-
quotes: ['
|
|
109
|
+
'prefer-const': 'error',
|
|
110
|
+
'prefer-spread': 'error',
|
|
111
|
+
quotes: ['error', 'single', {allowTemplateLiterals: true}],
|
|
112
112
|
'require-yield': 'error',
|
|
113
113
|
'rest-spread-spacing': 'error',
|
|
114
|
-
strict: ['
|
|
114
|
+
strict: ['error', 'never'],
|
|
115
115
|
|
|
116
116
|
// import
|
|
117
|
-
'import/newline-after-import': ['
|
|
117
|
+
'import/newline-after-import': ['error', {count: 2}],
|
|
118
118
|
'import/no-duplicates': 'error',
|
|
119
|
+
'no-restricted-imports': [
|
|
120
|
+
'error',
|
|
121
|
+
{
|
|
122
|
+
patterns: [
|
|
123
|
+
'./*', // ban same-folder
|
|
124
|
+
'../*', // ban parent-folder
|
|
125
|
+
],
|
|
126
|
+
},
|
|
127
|
+
],
|
|
119
128
|
|
|
120
129
|
// react
|
|
121
130
|
'react/jsx-no-undef': 'error',
|
|
122
|
-
'react/jsx-pascal-case': '
|
|
131
|
+
'react/jsx-pascal-case': 'error',
|
|
123
132
|
'react/jsx-uses-react': 'off',
|
|
124
133
|
'react/jsx-uses-vars': 'error',
|
|
125
|
-
'react/no-array-index-key': '
|
|
134
|
+
'react/no-array-index-key': 'error',
|
|
126
135
|
'react/no-deprecated': 'error',
|
|
127
136
|
'react/no-direct-mutation-state': 'error',
|
|
128
|
-
'react/no-string-refs': '
|
|
137
|
+
'react/no-string-refs': 'error',
|
|
129
138
|
'react/prop-types': 'off',
|
|
130
139
|
'react/react-in-jsx-scope': 'off',
|
|
131
140
|
|
|
132
|
-
|
|
133
|
-
'react-hooks/rules-of-hooks': 'warn',
|
|
141
|
+
'react-hooks/rules-of-hooks': 'error',
|
|
134
142
|
|
|
135
143
|
// unused
|
|
136
144
|
'unused-imports/no-unused-imports': 'error',
|
|
@@ -169,11 +177,19 @@ export default [
|
|
|
169
177
|
'@typescript-eslint/ban-ts-comment': 'error',
|
|
170
178
|
'@typescript-eslint/no-empty-object-type': 'error',
|
|
171
179
|
'@typescript-eslint/no-unnecessary-type-constraint': 'error',
|
|
172
|
-
'@typescript-eslint/no-non-null-assertion': '
|
|
180
|
+
'@typescript-eslint/no-non-null-assertion': 'error',
|
|
173
181
|
'@typescript-eslint/prefer-as-const': 'error',
|
|
174
182
|
|
|
175
183
|
// ADDITIONAL NON TYPE-AWARE RULES (Valid for v8.39.1)
|
|
176
|
-
|
|
184
|
+
'@typescript-eslint/consistent-type-definitions': ['error', 'interface'],
|
|
185
|
+
'@typescript-eslint/consistent-type-imports': [
|
|
186
|
+
'error',
|
|
187
|
+
{
|
|
188
|
+
prefer: 'type-imports', // enforce `import type`
|
|
189
|
+
disallowTypeAnnotations: false, // allow `import Foo = require(...)` style if needed
|
|
190
|
+
fixStyle: 'separate-type-imports', // auto-fix groups type imports separately
|
|
191
|
+
},
|
|
192
|
+
],
|
|
177
193
|
'@typescript-eslint/explicit-function-return-type': 'off', // Too strict for most projects
|
|
178
194
|
'@typescript-eslint/explicit-member-accessibility': 'off', // Too strict for most projects
|
|
179
195
|
'@typescript-eslint/explicit-module-boundary-types': 'off', // Too strict for most projects
|
|
@@ -214,7 +230,7 @@ export default [
|
|
|
214
230
|
{
|
|
215
231
|
files: ['**/*.stories.{jsx,tsx}'],
|
|
216
232
|
rules: {
|
|
217
|
-
semi: ['
|
|
233
|
+
semi: ['error', 'always'],
|
|
218
234
|
},
|
|
219
235
|
},
|
|
220
236
|
|
|
@@ -256,7 +272,7 @@ export default [
|
|
|
256
272
|
],
|
|
257
273
|
|
|
258
274
|
// optional: keep two blank lines after imports (helps readability)
|
|
259
|
-
'import/newline-after-import': ['
|
|
275
|
+
'import/newline-after-import': ['error', {count: 2}],
|
|
260
276
|
},
|
|
261
277
|
},
|
|
262
278
|
];
|
package/lib/utils/index.d.ts
CHANGED
package/lib/utils/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC;AAChC,cAAc,kBAAkB,CAAC;AACjC,cAAc,oBAAoB,CAAC;AACnC,cAAc,sBAAsB,CAAC;AACrC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,eAAe,CAAC;AAC9B,cAAc,mBAAmB,CAAC;AAClC,cAAc,kCAAkC,CAAC;AACjD,cAAc,gBAAgB,CAAC;AAC/B,cAAc,sBAAsB,CAAC;AACrC,cAAc,kBAAkB,CAAC;AACjC,cAAc,qBAAqB,CAAC;AACpC,cAAc,kBAAkB,CAAC;AACjC,cAAc,kBAAkB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC;AAChC,cAAc,kBAAkB,CAAC;AACjC,cAAc,oBAAoB,CAAC;AACnC,cAAc,sBAAsB,CAAC;AACrC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,eAAe,CAAC;AAC9B,cAAc,mBAAmB,CAAC;AAClC,cAAc,kCAAkC,CAAC;AACjD,cAAc,gBAAgB,CAAC;AAC/B,cAAc,sBAAsB,CAAC;AACrC,cAAc,kBAAkB,CAAC;AACjC,cAAc,qBAAqB,CAAC;AACpC,cAAc,kBAAkB,CAAC;AACjC,cAAc,kBAAkB,CAAC;AACjC,cAAc,cAAc,CAAC"}
|
package/lib/utils/index.js
CHANGED
|
@@ -156,4 +156,15 @@ Object.keys(_tokens).forEach(function (key) {
|
|
|
156
156
|
return _tokens[key];
|
|
157
157
|
}
|
|
158
158
|
});
|
|
159
|
+
});
|
|
160
|
+
var _qa = require("./qa");
|
|
161
|
+
Object.keys(_qa).forEach(function (key) {
|
|
162
|
+
if (key === "default" || key === "__esModule") return;
|
|
163
|
+
if (key in exports && exports[key] === _qa[key]) return;
|
|
164
|
+
Object.defineProperty(exports, key, {
|
|
165
|
+
enumerable: true,
|
|
166
|
+
get: function () {
|
|
167
|
+
return _qa[key];
|
|
168
|
+
}
|
|
169
|
+
});
|
|
159
170
|
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/utils/qa/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
var _qa = require("./qa");
|
|
7
|
+
Object.keys(_qa).forEach(function (key) {
|
|
8
|
+
if (key === "default" || key === "__esModule") return;
|
|
9
|
+
if (key in exports && exports[key] === _qa[key]) return;
|
|
10
|
+
Object.defineProperty(exports, key, {
|
|
11
|
+
enumerable: true,
|
|
12
|
+
get: function () {
|
|
13
|
+
return _qa[key];
|
|
14
|
+
}
|
|
15
|
+
});
|
|
16
|
+
});
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generate a stable `data-testid` string.
|
|
3
|
+
*
|
|
4
|
+
* Format:
|
|
5
|
+
* <base>[__<slot>][--<index>][--<modifierA>--<modifierB>...]
|
|
6
|
+
*
|
|
7
|
+
* Examples:
|
|
8
|
+
* generateTestId({ base: "profile__email", slot: "input" })
|
|
9
|
+
* // "profile__email__input"
|
|
10
|
+
*
|
|
11
|
+
* generateTestId({ base: "users", slot: "item", index: "u-100" })
|
|
12
|
+
* // "users__item--u-100"
|
|
13
|
+
*
|
|
14
|
+
* generateTestId({ base: "filters", slot: "chip", modifiers: ["selected", "lg"] })
|
|
15
|
+
* // "filters__chip--selected--lg"
|
|
16
|
+
*
|
|
17
|
+
* Guidance:
|
|
18
|
+
* - Keep `base` stable and human-readable (don’t derive from user text or use UUIDs).
|
|
19
|
+
* - For repeated items, prefer stable business keys for `index` (e.g., `user.id`).
|
|
20
|
+
* - Use `modifiers` to encode state/variants cleanly in selectors.
|
|
21
|
+
*/
|
|
22
|
+
export interface GenerateTestIdParams {
|
|
23
|
+
base?: string;
|
|
24
|
+
slot?: string;
|
|
25
|
+
index?: number | string;
|
|
26
|
+
modifiers?: ReadonlyArray<string | number | boolean | null | undefined>;
|
|
27
|
+
}
|
|
28
|
+
/** Returns the composed id, or `undefined` if `base` is missing. */
|
|
29
|
+
export declare function generateTestId(params: GenerateTestIdParams): string | undefined;
|
|
30
|
+
//# sourceMappingURL=qa.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"qa.d.ts","sourceRoot":"","sources":["../../../src/utils/qa/qa.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,WAAW,oBAAoB;IACnC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACxB,SAAS,CAAC,EAAE,aAAa,CAAC,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,SAAS,CAAC,CAAC;CACzE;AAKD,oEAAoE;AACpE,wBAAgB,cAAc,CAC5B,MAAM,EAAE,oBAAoB,GAC3B,MAAM,GAAG,SAAS,CAsBpB"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.generateTestId = generateTestId;
|
|
7
|
+
/**
|
|
8
|
+
* Generate a stable `data-testid` string.
|
|
9
|
+
*
|
|
10
|
+
* Format:
|
|
11
|
+
* <base>[__<slot>][--<index>][--<modifierA>--<modifierB>...]
|
|
12
|
+
*
|
|
13
|
+
* Examples:
|
|
14
|
+
* generateTestId({ base: "profile__email", slot: "input" })
|
|
15
|
+
* // "profile__email__input"
|
|
16
|
+
*
|
|
17
|
+
* generateTestId({ base: "users", slot: "item", index: "u-100" })
|
|
18
|
+
* // "users__item--u-100"
|
|
19
|
+
*
|
|
20
|
+
* generateTestId({ base: "filters", slot: "chip", modifiers: ["selected", "lg"] })
|
|
21
|
+
* // "filters__chip--selected--lg"
|
|
22
|
+
*
|
|
23
|
+
* Guidance:
|
|
24
|
+
* - Keep `base` stable and human-readable (don’t derive from user text or use UUIDs).
|
|
25
|
+
* - For repeated items, prefer stable business keys for `index` (e.g., `user.id`).
|
|
26
|
+
* - Use `modifiers` to encode state/variants cleanly in selectors.
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
const SLOT_SEP = '__';
|
|
30
|
+
const MOD_SEP = '--';
|
|
31
|
+
|
|
32
|
+
/** Returns the composed id, or `undefined` if `base` is missing. */
|
|
33
|
+
function generateTestId(params) {
|
|
34
|
+
const {
|
|
35
|
+
base,
|
|
36
|
+
slot,
|
|
37
|
+
index,
|
|
38
|
+
modifiers = []
|
|
39
|
+
} = params;
|
|
40
|
+
if (!base) {
|
|
41
|
+
return undefined;
|
|
42
|
+
}
|
|
43
|
+
let id = slot ? `${base}${SLOT_SEP}${slot}` : base;
|
|
44
|
+
if (typeof index !== 'undefined') {
|
|
45
|
+
id += `${MOD_SEP}${String(index)}`;
|
|
46
|
+
}
|
|
47
|
+
const mods = modifiers.filter(m => Boolean(m)).map(String);
|
|
48
|
+
if (mods.length > 0) {
|
|
49
|
+
id += `${MOD_SEP}${mods.join(MOD_SEP)}`;
|
|
50
|
+
}
|
|
51
|
+
return id;
|
|
52
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@spaced-out/ui-design-system",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.10",
|
|
4
4
|
"description": "Sense UI components library",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Spaced Out"
|
|
@@ -143,6 +143,7 @@
|
|
|
143
143
|
"husky": "2.1.0",
|
|
144
144
|
"invariant": "^2.2.4",
|
|
145
145
|
"jest": "^29.3.1",
|
|
146
|
+
"jscodeshift": "^17.3.0",
|
|
146
147
|
"lint-staged": "^10.5.1",
|
|
147
148
|
"paths.macro": "^3.0.1",
|
|
148
149
|
"prettier": "^2.5.1",
|