@descope-ui/common 3.1.13 → 3.2.1
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 +9 -0
- package/package.json +1 -1
- package/src/constants.js +0 -1
- package/src/themeHelpers/index.js +80 -33
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
This file was generated using [@jscutlery/semver](https://github.com/jscutlery/semver).
|
|
4
4
|
|
|
5
|
+
## [3.2.1](https://github.com/descope/web-components-ui/compare/web-components-ui-3.2.0...web-components-ui-3.2.1) (2026-04-16)
|
|
6
|
+
|
|
7
|
+
## [3.2.0](https://github.com/descope/web-components-ui/compare/web-components-ui-3.1.13...web-components-ui-3.2.0) (2026-04-16)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
### Features
|
|
11
|
+
|
|
12
|
+
* add descope-last-auth-badge component ([#982](https://github.com/descope/web-components-ui/issues/982)) ([055b461](https://github.com/descope/web-components-ui/commit/055b4618abbdf518494a2984e56d66e58fdb4809))
|
|
13
|
+
|
|
5
14
|
## [3.1.13](https://github.com/descope/web-components-ui/compare/web-components-ui-3.1.12...web-components-ui-3.1.13) (2026-04-15)
|
|
6
15
|
|
|
7
16
|
## [3.1.12](https://github.com/descope/web-components-ui/compare/web-components-ui-3.1.11...web-components-ui-3.1.12) (2026-04-15)
|
package/package.json
CHANGED
package/src/constants.js
CHANGED
|
@@ -1,9 +1,5 @@
|
|
|
1
1
|
import merge from 'lodash.merge';
|
|
2
|
-
import {
|
|
3
|
-
BASE_THEME_SECTION,
|
|
4
|
-
DESCOPE_PREFIX,
|
|
5
|
-
PORTAL_THEME_PREFIX,
|
|
6
|
-
} from '../constants';
|
|
2
|
+
import { BASE_THEME_SECTION, DESCOPE_PREFIX } from '../constants';
|
|
7
3
|
import { isUrl, kebabCase } from '../utils';
|
|
8
4
|
import { getComponentName, getCssVarName } from '../componentsHelpers';
|
|
9
5
|
|
|
@@ -73,9 +69,16 @@ export const globalsThemeToStyle = (theme, themeName = '') => {
|
|
|
73
69
|
|
|
74
70
|
function splitAmpersands(str) {
|
|
75
71
|
const match = str.match(/^(&+)?(.*)$/);
|
|
76
|
-
return [match[1] ||
|
|
72
|
+
return [match[1] || '', match[2] || ''];
|
|
77
73
|
}
|
|
78
74
|
|
|
75
|
+
const CONTAINER_QUERY_PREFIX = '@container';
|
|
76
|
+
const isContainerQuery = (key) => key.startsWith(CONTAINER_QUERY_PREFIX);
|
|
77
|
+
|
|
78
|
+
const BREAKPOINTS_KEY = '$breakpoints';
|
|
79
|
+
const BREAKPOINTS_REF_PREFIX = '$breakpoints.';
|
|
80
|
+
const isBreakpointRef = (key) => key.startsWith(BREAKPOINTS_REF_PREFIX);
|
|
81
|
+
|
|
79
82
|
// st attributes are also using selector multiplication
|
|
80
83
|
// so we need to limit the multiplication
|
|
81
84
|
const MAX_SELECTOR_MULTIPLY = 3;
|
|
@@ -83,70 +86,114 @@ const MAX_SELECTOR_MULTIPLY = 3;
|
|
|
83
86
|
const componentsThemeToStyleObj = (componentsTheme) =>
|
|
84
87
|
transformTheme(componentsTheme, [], (path, val) => {
|
|
85
88
|
const [component, ...restPath] = path;
|
|
89
|
+
|
|
90
|
+
// skip $breakpoints definitions — they are metadata, not CSS output
|
|
91
|
+
if (restPath[0] === BREAKPOINTS_KEY) return {};
|
|
92
|
+
|
|
86
93
|
const property = restPath.pop();
|
|
87
94
|
const componentName = getComponentName(component);
|
|
88
95
|
|
|
89
96
|
if (property === 'undefined') {
|
|
90
|
-
|
|
91
|
-
|
|
97
|
+
console.warn(
|
|
98
|
+
componentName,
|
|
99
|
+
`theme value: "${val}" is mapped to an invalid property`,
|
|
100
|
+
);
|
|
92
101
|
}
|
|
93
102
|
|
|
94
|
-
// we need a support for portal components theme (e.g. overlay)
|
|
95
|
-
// this allows us to generate those themes under different sections
|
|
96
|
-
// if the theme has root level attribute that starts with #
|
|
97
|
-
// we are generating a new theme
|
|
98
103
|
let themeName = BASE_THEME_SECTION;
|
|
99
104
|
|
|
100
|
-
|
|
101
|
-
|
|
105
|
+
// extract @container queries from restPath at any position,
|
|
106
|
+
// resolving breakpoints.X references via the component's $breakpoints map
|
|
107
|
+
const componentBreakpoints =
|
|
108
|
+
componentsTheme[component]?.[BREAKPOINTS_KEY] || {};
|
|
109
|
+
const resolveKey = (key) =>
|
|
110
|
+
isBreakpointRef(key)
|
|
111
|
+
? `${CONTAINER_QUERY_PREFIX} ${componentBreakpoints[key.slice(BREAKPOINTS_REF_PREFIX.length)]}`
|
|
112
|
+
: key;
|
|
113
|
+
const breakpointRefs = restPath.filter(isBreakpointRef);
|
|
114
|
+
const missingRef = breakpointRefs.find(
|
|
115
|
+
(key) => !componentBreakpoints[key.slice(BREAKPOINTS_REF_PREFIX.length)],
|
|
116
|
+
);
|
|
117
|
+
if (missingRef) {
|
|
118
|
+
console.warn(
|
|
119
|
+
componentName,
|
|
120
|
+
`theme references undefined breakpoint "${missingRef}"`,
|
|
121
|
+
);
|
|
122
|
+
return {};
|
|
102
123
|
}
|
|
124
|
+
const containerQueries = breakpointRefs.map(resolveKey);
|
|
125
|
+
// remove breakpoint refs from restPath so the remaining parts are processed as attribute selectors
|
|
126
|
+
restPath.splice(
|
|
127
|
+
0,
|
|
128
|
+
restPath.length,
|
|
129
|
+
...restPath.filter((s) => !isBreakpointRef(s)),
|
|
130
|
+
);
|
|
103
131
|
|
|
104
132
|
// do not start with underscore -> key:value, must have 2 no underscore attrs in a row
|
|
105
133
|
// starts with underscore -> attribute selector
|
|
106
134
|
const attrsSelector = restPath.reduce((acc, section, idx) => {
|
|
107
135
|
const [ampersands, content] = splitAmpersands(section);
|
|
108
136
|
const selectorMultiplier = Math.min(
|
|
109
|
-
ampersands.length + 1,
|
|
110
|
-
MAX_SELECTOR_MULTIPLY
|
|
137
|
+
ampersands.length + 1, // if there are no & we need to multiply by 1
|
|
138
|
+
MAX_SELECTOR_MULTIPLY,
|
|
111
139
|
);
|
|
112
140
|
|
|
113
|
-
if (content.startsWith('_'))
|
|
141
|
+
if (content.startsWith('_'))
|
|
142
|
+
return (
|
|
143
|
+
acc +
|
|
144
|
+
`[${kebabCase(content.replace(/^_/, ''))}="true"]`.repeat(
|
|
145
|
+
selectorMultiplier,
|
|
146
|
+
)
|
|
147
|
+
);
|
|
114
148
|
|
|
115
149
|
const nextSection = restPath[idx + 1];
|
|
116
150
|
|
|
117
|
-
if (
|
|
118
|
-
|
|
151
|
+
if (
|
|
152
|
+
typeof nextSection !== 'string' ||
|
|
153
|
+
nextSection.startsWith('_') ||
|
|
154
|
+
nextSection.startsWith('&')
|
|
155
|
+
) {
|
|
119
156
|
console.error(
|
|
120
157
|
'theme generator',
|
|
121
|
-
`your theme structure is invalid, attribute "${section}" is followed by "${nextSection}" which is not allowed
|
|
158
|
+
`your theme structure is invalid, attribute "${section}" is followed by "${nextSection}" which is not allowed`,
|
|
122
159
|
);
|
|
123
160
|
return acc;
|
|
124
161
|
}
|
|
125
162
|
|
|
126
|
-
return
|
|
163
|
+
return (
|
|
164
|
+
acc +
|
|
165
|
+
`[${kebabCase(content)}="${restPath.splice(idx + 1, 1).join('')}"]`.repeat(
|
|
166
|
+
selectorMultiplier,
|
|
167
|
+
)
|
|
168
|
+
);
|
|
127
169
|
}, '');
|
|
128
170
|
|
|
129
171
|
const selector = `:host${attrsSelector ? `(${attrsSelector})` : ''}`;
|
|
130
172
|
|
|
173
|
+
// wrap the selector rule in container queries from innermost to outermost
|
|
174
|
+
// e.g. ['@container (max-width: 80px)'] + { ':host': { prop: val } }
|
|
175
|
+
// => { '@container (max-width: 80px)': { ':host': { prop: val } } }
|
|
176
|
+
const leaf = containerQueries.reduceRight(
|
|
177
|
+
(acc, query) => ({ [query]: acc }),
|
|
178
|
+
{ [selector]: { [property]: getCssVarValue(val) } },
|
|
179
|
+
);
|
|
180
|
+
|
|
131
181
|
return {
|
|
132
182
|
[componentName]: {
|
|
133
|
-
[themeName]:
|
|
134
|
-
[selector]: {
|
|
135
|
-
[property]: getCssVarValue(val),
|
|
136
|
-
},
|
|
137
|
-
},
|
|
183
|
+
[themeName]: leaf,
|
|
138
184
|
},
|
|
139
185
|
};
|
|
140
186
|
});
|
|
141
187
|
|
|
142
188
|
const componentsThemeToStyle = (componentsTheme) =>
|
|
143
|
-
Object.entries(componentsTheme).reduce(
|
|
144
|
-
(
|
|
145
|
-
`${acc}${
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
189
|
+
Object.entries(componentsTheme).reduce((acc, [key, value]) => {
|
|
190
|
+
if (isContainerQuery(key)) {
|
|
191
|
+
return `${acc}${key} {\n${componentsThemeToStyle(value)}}\n\n`;
|
|
192
|
+
}
|
|
193
|
+
return `${acc}${key} { \n${Object.entries(value)
|
|
194
|
+
.map(([prop, val]) => `${prop}: ${val}`)
|
|
195
|
+
.join(';\n')} \n}\n\n`;
|
|
196
|
+
}, '');
|
|
150
197
|
|
|
151
198
|
export const createComponentsTheme = (componentsTheme) => {
|
|
152
199
|
const styleObj = componentsThemeToStyleObj(componentsTheme);
|