@idealyst/theme 1.2.30 → 1.2.32
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/package.json +2 -2
- package/src/babel/plugin.js +114 -2
- package/src/babel/theme-analyzer.js +126 -26
- package/src/builder.ts +3 -0
- package/src/lightTheme.ts +7 -0
- package/src/theme/extensions.ts +1 -0
- package/src/theme/structures.ts +5 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@idealyst/theme",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.32",
|
|
4
4
|
"description": "Theming system for Idealyst Framework",
|
|
5
5
|
"readme": "README.md",
|
|
6
6
|
"main": "src/index.ts",
|
|
@@ -63,7 +63,7 @@
|
|
|
63
63
|
"publish:npm": "npm publish"
|
|
64
64
|
},
|
|
65
65
|
"dependencies": {
|
|
66
|
-
"@idealyst/tooling": "^1.2.
|
|
66
|
+
"@idealyst/tooling": "^1.2.30"
|
|
67
67
|
},
|
|
68
68
|
"peerDependencies": {
|
|
69
69
|
"react-native-unistyles": ">=3.0.0"
|
package/src/babel/plugin.js
CHANGED
|
@@ -210,6 +210,14 @@ function expandIterators(t, callback, themeParam, keys, verbose, expandedVariant
|
|
|
210
210
|
}
|
|
211
211
|
}
|
|
212
212
|
|
|
213
|
+
// Look for compoundVariants: [ { type: 'filled', selected: true, styles: { ... } }, ... ]
|
|
214
|
+
if (t.isObjectProperty(node) && t.isIdentifier(node.key, { name: 'compoundVariants' })) {
|
|
215
|
+
if (t.isArrayExpression(node.value)) {
|
|
216
|
+
const expanded = expandCompoundVariantsArray(t, node.value, themeParam, keys, verbose, expandedVariants);
|
|
217
|
+
return t.objectProperty(node.key, expanded);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
213
221
|
if (t.isObjectExpression(node)) {
|
|
214
222
|
return t.objectExpression(
|
|
215
223
|
node.properties.map(prop => processNode(prop, depth + 1))
|
|
@@ -352,6 +360,112 @@ function expandVariantsObject(t, variantsObj, themeParam, keys, verbose, expande
|
|
|
352
360
|
return t.objectExpression(newProperties);
|
|
353
361
|
}
|
|
354
362
|
|
|
363
|
+
/**
|
|
364
|
+
* Expand $iterator patterns in compoundVariants arrays.
|
|
365
|
+
*
|
|
366
|
+
* Input:
|
|
367
|
+
* compoundVariants: [
|
|
368
|
+
* { type: 'filled', selected: true, styles: { backgroundColor: theme.$intents.contrast } }
|
|
369
|
+
* ]
|
|
370
|
+
*
|
|
371
|
+
* Output (for intents = ['primary', 'success', 'danger', ...]):
|
|
372
|
+
* compoundVariants: [
|
|
373
|
+
* { type: 'filled', selected: true, intent: 'primary', styles: { backgroundColor: theme.intents.primary.contrast } },
|
|
374
|
+
* { type: 'filled', selected: true, intent: 'success', styles: { backgroundColor: theme.intents.success.contrast } },
|
|
375
|
+
* { type: 'filled', selected: true, intent: 'danger', styles: { backgroundColor: theme.intents.danger.contrast } },
|
|
376
|
+
* ...
|
|
377
|
+
* ]
|
|
378
|
+
*/
|
|
379
|
+
function expandCompoundVariantsArray(t, arrayNode, themeParam, keys, verbose, expandedVariants) {
|
|
380
|
+
const newElements = [];
|
|
381
|
+
|
|
382
|
+
verbose(` expandCompoundVariantsArray: processing ${arrayNode.elements?.length || 0} compound variants`);
|
|
383
|
+
|
|
384
|
+
for (const element of arrayNode.elements) {
|
|
385
|
+
if (!t.isObjectExpression(element)) {
|
|
386
|
+
newElements.push(element);
|
|
387
|
+
continue;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
// Find the 'styles' property in this compound variant entry
|
|
391
|
+
let stylesProperty = null;
|
|
392
|
+
const otherProperties = [];
|
|
393
|
+
|
|
394
|
+
for (const prop of element.properties) {
|
|
395
|
+
if (t.isObjectProperty(prop)) {
|
|
396
|
+
const keyName = t.isIdentifier(prop.key) ? prop.key.name :
|
|
397
|
+
t.isStringLiteral(prop.key) ? prop.key.value : null;
|
|
398
|
+
if (keyName === 'styles') {
|
|
399
|
+
stylesProperty = prop;
|
|
400
|
+
} else {
|
|
401
|
+
otherProperties.push(prop);
|
|
402
|
+
}
|
|
403
|
+
} else {
|
|
404
|
+
otherProperties.push(prop);
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
if (!stylesProperty) {
|
|
409
|
+
// No styles property, keep as-is
|
|
410
|
+
newElements.push(element);
|
|
411
|
+
continue;
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
// Check if the styles object contains $iterator patterns
|
|
415
|
+
const iteratorInfo = findIteratorPattern(t, stylesProperty.value, themeParam);
|
|
416
|
+
|
|
417
|
+
if (!iteratorInfo) {
|
|
418
|
+
// No $iterator pattern, keep as-is
|
|
419
|
+
newElements.push(element);
|
|
420
|
+
continue;
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
verbose(` Found $iterator in compoundVariant styles: ${iteratorInfo.type}`);
|
|
424
|
+
|
|
425
|
+
// Get keys to expand
|
|
426
|
+
let keysToExpand = [];
|
|
427
|
+
let variantKeyName = 'intent'; // Default for intents
|
|
428
|
+
|
|
429
|
+
if (iteratorInfo.type === 'intents') {
|
|
430
|
+
keysToExpand = keys?.intents || [];
|
|
431
|
+
variantKeyName = 'intent';
|
|
432
|
+
} else if (iteratorInfo.type === 'typography') {
|
|
433
|
+
keysToExpand = keys?.typography || [];
|
|
434
|
+
variantKeyName = 'typography';
|
|
435
|
+
} else if (iteratorInfo.type === 'sizes' && iteratorInfo.componentName) {
|
|
436
|
+
keysToExpand = keys?.sizes?.[iteratorInfo.componentName] || [];
|
|
437
|
+
variantKeyName = 'size';
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
if (keysToExpand.length === 0) {
|
|
441
|
+
// No keys to expand, keep as-is
|
|
442
|
+
newElements.push(element);
|
|
443
|
+
continue;
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
verbose(` Expanding compoundVariant for ${keysToExpand.length} ${variantKeyName} keys`);
|
|
447
|
+
|
|
448
|
+
// Expand this compound variant for each key
|
|
449
|
+
for (const key of keysToExpand) {
|
|
450
|
+
// Replace $iterator refs in the styles
|
|
451
|
+
const expandedStyles = replaceIteratorRefs(t, stylesProperty.value, themeParam, iteratorInfo, key);
|
|
452
|
+
|
|
453
|
+
// Create new compound variant entry with the variant key added as a condition
|
|
454
|
+
const newProps = [
|
|
455
|
+
...otherProperties.map(p => t.cloneDeep(p)),
|
|
456
|
+
t.objectProperty(t.identifier(variantKeyName), t.stringLiteral(key)),
|
|
457
|
+
t.objectProperty(t.identifier('styles'), expandedStyles),
|
|
458
|
+
];
|
|
459
|
+
|
|
460
|
+
newElements.push(t.objectExpression(newProps));
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
expandedVariants.push({ variant: 'compoundVariants', iterator: iteratorInfo.type });
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
return t.arrayExpression(newElements);
|
|
467
|
+
}
|
|
468
|
+
|
|
355
469
|
function findIteratorPattern(t, node, themeParam, debugLog = () => {}) {
|
|
356
470
|
let result = null;
|
|
357
471
|
|
|
@@ -578,8 +692,6 @@ module.exports = function idealystStylesPlugin({ types: t }) {
|
|
|
578
692
|
}
|
|
579
693
|
}
|
|
580
694
|
|
|
581
|
-
// Plugin initialization logged in debug mode only
|
|
582
|
-
|
|
583
695
|
return {
|
|
584
696
|
name: 'idealyst-styles',
|
|
585
697
|
|
|
@@ -16,6 +16,31 @@ const fs = require('fs');
|
|
|
16
16
|
let themeKeys = null;
|
|
17
17
|
let themeLoadAttempted = false;
|
|
18
18
|
|
|
19
|
+
// Global aliases configuration (set via plugin options)
|
|
20
|
+
let packageAliases = {};
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Resolve an import source using configured aliases (static version for use outside AST traversal).
|
|
24
|
+
* Returns the resolved path or null if no alias matches.
|
|
25
|
+
*/
|
|
26
|
+
function resolveWithAliasesStatic(source, fromDir) {
|
|
27
|
+
for (const [aliasPrefix, aliasPath] of Object.entries(packageAliases)) {
|
|
28
|
+
if (source === aliasPrefix || source.startsWith(aliasPrefix + '/')) {
|
|
29
|
+
// Replace the alias prefix with the actual path
|
|
30
|
+
const remainder = source.slice(aliasPrefix.length);
|
|
31
|
+
let resolved = aliasPath + remainder;
|
|
32
|
+
|
|
33
|
+
// If aliasPath is relative, resolve from fromDir
|
|
34
|
+
if (!nodePath.isAbsolute(resolved)) {
|
|
35
|
+
resolved = nodePath.resolve(fromDir, resolved);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return resolved;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
|
|
19
44
|
/**
|
|
20
45
|
* Extract theme keys by statically analyzing the theme file's AST.
|
|
21
46
|
*/
|
|
@@ -99,6 +124,29 @@ function extractThemeKeysFromAST(themeFilePath, babelTypes, verboseMode) {
|
|
|
99
124
|
return { calls, baseThemeVar: null };
|
|
100
125
|
}
|
|
101
126
|
|
|
127
|
+
/**
|
|
128
|
+
* Resolve an import source using configured aliases.
|
|
129
|
+
* Returns the resolved path or null if no alias matches.
|
|
130
|
+
*/
|
|
131
|
+
function resolveWithAliases(source, fromDir) {
|
|
132
|
+
for (const [aliasPrefix, aliasPath] of Object.entries(packageAliases)) {
|
|
133
|
+
if (source === aliasPrefix || source.startsWith(aliasPrefix + '/')) {
|
|
134
|
+
// Replace the alias prefix with the actual path
|
|
135
|
+
const remainder = source.slice(aliasPrefix.length);
|
|
136
|
+
let resolved = aliasPath + remainder;
|
|
137
|
+
|
|
138
|
+
// If aliasPath is relative, resolve from fromDir
|
|
139
|
+
if (!nodePath.isAbsolute(resolved)) {
|
|
140
|
+
resolved = nodePath.resolve(fromDir, resolved);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
log('Resolved alias:', source, '->', resolved);
|
|
144
|
+
return resolved;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
return null;
|
|
148
|
+
}
|
|
149
|
+
|
|
102
150
|
/**
|
|
103
151
|
* Resolve and analyze a base theme from an import.
|
|
104
152
|
*/
|
|
@@ -122,42 +170,75 @@ function extractThemeKeysFromAST(themeFilePath, babelTypes, verboseMode) {
|
|
|
122
170
|
} else {
|
|
123
171
|
const packageDir = nodePath.dirname(themeFilePath);
|
|
124
172
|
|
|
125
|
-
//
|
|
126
|
-
const
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
nodePath.
|
|
135
|
-
|
|
136
|
-
nodePath.resolve(packageDir, `../theme/src/${themeFileName}`),
|
|
137
|
-
nodePath.resolve(packageDir, `../../theme/src/${themeFileName}`),
|
|
138
|
-
nodePath.resolve(packageDir, `../../../theme/src/${themeFileName}`),
|
|
139
|
-
nodePath.resolve(packageDir, `../../packages/theme/src/${themeFileName}`),
|
|
140
|
-
nodePath.resolve(packageDir, `../../../packages/theme/src/${themeFileName}`),
|
|
141
|
-
// This plugin's own package location
|
|
142
|
-
nodePath.resolve(__dirname, `../${themeFileName}`),
|
|
173
|
+
// First, try to resolve using configured aliases
|
|
174
|
+
const aliasResolved = resolveWithAliases(importInfo.source, packageDir);
|
|
175
|
+
if (aliasResolved) {
|
|
176
|
+
// Determine which theme file to look for based on variable name
|
|
177
|
+
const themeFileName = varName.includes('dark') ? 'darkTheme.ts' : 'lightTheme.ts';
|
|
178
|
+
|
|
179
|
+
// Check if alias points to a directory or a specific file
|
|
180
|
+
let possiblePaths = [
|
|
181
|
+
aliasResolved,
|
|
182
|
+
nodePath.join(aliasResolved, 'src', themeFileName),
|
|
183
|
+
nodePath.join(aliasResolved, themeFileName),
|
|
143
184
|
];
|
|
144
185
|
|
|
145
|
-
|
|
186
|
+
// Add .ts extension if needed
|
|
187
|
+
possiblePaths = possiblePaths.flatMap(p => {
|
|
188
|
+
if (p.endsWith('.ts') || p.endsWith('.tsx')) return [p];
|
|
189
|
+
return [p, p + '.ts', p + '.tsx'];
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
log('Looking for aliased theme in:', possiblePaths);
|
|
146
193
|
|
|
147
194
|
for (const p of possiblePaths) {
|
|
148
195
|
if (fs.existsSync(p)) {
|
|
149
196
|
baseThemePath = p;
|
|
150
|
-
log('Found
|
|
197
|
+
log('Found aliased theme at:', p);
|
|
151
198
|
break;
|
|
152
199
|
}
|
|
153
200
|
}
|
|
154
201
|
}
|
|
155
202
|
|
|
203
|
+
// If no alias match, use default resolution for @idealyst/theme
|
|
156
204
|
if (!baseThemePath) {
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
205
|
+
// Determine which theme file to look for based on variable name
|
|
206
|
+
const themeFileName = varName.includes('dark') ? 'darkTheme.ts' : 'lightTheme.ts';
|
|
207
|
+
let possiblePaths = [];
|
|
208
|
+
|
|
209
|
+
if (importInfo.source === '@idealyst/theme') {
|
|
210
|
+
possiblePaths = [
|
|
211
|
+
// Symlinked packages at root level
|
|
212
|
+
`/idealyst-packages/theme/src/${themeFileName}`,
|
|
213
|
+
// Standard node_modules
|
|
214
|
+
nodePath.resolve(packageDir, `node_modules/@idealyst/theme/src/${themeFileName}`),
|
|
215
|
+
// Monorepo structure - walk up to find packages dir
|
|
216
|
+
nodePath.resolve(packageDir, `../theme/src/${themeFileName}`),
|
|
217
|
+
nodePath.resolve(packageDir, `../../theme/src/${themeFileName}`),
|
|
218
|
+
nodePath.resolve(packageDir, `../../../theme/src/${themeFileName}`),
|
|
219
|
+
nodePath.resolve(packageDir, `../../packages/theme/src/${themeFileName}`),
|
|
220
|
+
nodePath.resolve(packageDir, `../../../packages/theme/src/${themeFileName}`),
|
|
221
|
+
nodePath.resolve(packageDir, `../../../../packages/theme/src/${themeFileName}`),
|
|
222
|
+
nodePath.resolve(packageDir, `../../../../../packages/theme/src/${themeFileName}`),
|
|
223
|
+
nodePath.resolve(packageDir, `../../../../../../packages/theme/src/${themeFileName}`),
|
|
224
|
+
// This plugin's own package location
|
|
225
|
+
nodePath.resolve(__dirname, `../${themeFileName}`),
|
|
226
|
+
];
|
|
227
|
+
|
|
228
|
+
log('Looking for base theme in:', possiblePaths);
|
|
229
|
+
|
|
230
|
+
for (const p of possiblePaths) {
|
|
231
|
+
if (fs.existsSync(p)) {
|
|
232
|
+
baseThemePath = p;
|
|
233
|
+
log('Found base theme at:', p);
|
|
234
|
+
break;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
160
237
|
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
if (!baseThemePath) {
|
|
241
|
+
log('Could not resolve base theme path for:', importInfo.source);
|
|
161
242
|
return;
|
|
162
243
|
}
|
|
163
244
|
}
|
|
@@ -366,11 +447,23 @@ function extractThemeKeysFromAST(themeFilePath, babelTypes, verboseMode) {
|
|
|
366
447
|
*
|
|
367
448
|
* REQUIRED Options:
|
|
368
449
|
* - themePath: Path to the consumer's theme file (e.g., './src/theme/styles.ts')
|
|
450
|
+
*
|
|
451
|
+
* OPTIONAL Options:
|
|
452
|
+
* - aliases: Object mapping package prefixes to paths for resolution
|
|
453
|
+
* Example: { '@idealyst/theme': '/path/to/packages/theme' }
|
|
369
454
|
*/
|
|
370
455
|
function loadThemeKeys(opts, rootDir, babelTypes, verboseMode) {
|
|
371
456
|
if (themeLoadAttempted) return themeKeys;
|
|
372
457
|
themeLoadAttempted = true;
|
|
373
458
|
|
|
459
|
+
// Set up package aliases for resolution
|
|
460
|
+
if (opts.aliases && typeof opts.aliases === 'object') {
|
|
461
|
+
packageAliases = opts.aliases;
|
|
462
|
+
if (verboseMode) {
|
|
463
|
+
console.log('[idealyst-plugin] Configured aliases:', packageAliases);
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
|
|
374
467
|
const themePath = opts.themePath;
|
|
375
468
|
|
|
376
469
|
if (!themePath) {
|
|
@@ -381,9 +474,16 @@ function loadThemeKeys(opts, rootDir, babelTypes, verboseMode) {
|
|
|
381
474
|
);
|
|
382
475
|
}
|
|
383
476
|
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
477
|
+
// First try to resolve using aliases
|
|
478
|
+
let resolvedPath;
|
|
479
|
+
const aliasResolved = resolveWithAliasesStatic(themePath, rootDir);
|
|
480
|
+
if (aliasResolved && fs.existsSync(aliasResolved)) {
|
|
481
|
+
resolvedPath = aliasResolved;
|
|
482
|
+
} else {
|
|
483
|
+
resolvedPath = themePath.startsWith('.')
|
|
484
|
+
? nodePath.resolve(rootDir, themePath)
|
|
485
|
+
: require.resolve(themePath, { paths: [rootDir] });
|
|
486
|
+
}
|
|
387
487
|
|
|
388
488
|
if (verboseMode) {
|
|
389
489
|
console.log('[idealyst-plugin] Analyzing theme file:', resolvedPath);
|
package/src/builder.ts
CHANGED
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
Typography,
|
|
8
8
|
TypographyValue,
|
|
9
9
|
ButtonSizeValue,
|
|
10
|
+
IconButtonSizeValue,
|
|
10
11
|
ChipSizeValue,
|
|
11
12
|
BadgeSizeValue,
|
|
12
13
|
IconSizeValue,
|
|
@@ -56,6 +57,7 @@ export type BuiltTheme<
|
|
|
56
57
|
};
|
|
57
58
|
sizes: {
|
|
58
59
|
button: Record<TSize, ButtonSizeValue>;
|
|
60
|
+
iconButton: Record<TSize, IconButtonSizeValue>;
|
|
59
61
|
chip: Record<TSize, ChipSizeValue>;
|
|
60
62
|
badge: Record<TSize, BadgeSizeValue>;
|
|
61
63
|
icon: Record<TSize, IconSizeValue>;
|
|
@@ -248,6 +250,7 @@ export class ThemeBuilder<
|
|
|
248
250
|
*/
|
|
249
251
|
setSizes<S extends string>(sizes: {
|
|
250
252
|
button: Record<S, ButtonSizeValue>;
|
|
253
|
+
iconButton: Record<S, IconButtonSizeValue>;
|
|
251
254
|
chip: Record<S, ChipSizeValue>;
|
|
252
255
|
badge: Record<S, BadgeSizeValue>;
|
|
253
256
|
icon: Record<S, IconSizeValue>;
|
package/src/lightTheme.ts
CHANGED
|
@@ -120,6 +120,13 @@ export const lightTheme = createTheme()
|
|
|
120
120
|
lg: { paddingVertical: 10, paddingHorizontal: 20, minHeight: 48, fontSize: 18, lineHeight: 28, iconSize: 18 },
|
|
121
121
|
xl: { paddingVertical: 12, paddingHorizontal: 24, minHeight: 56, fontSize: 20, lineHeight: 32, iconSize: 20 },
|
|
122
122
|
},
|
|
123
|
+
iconButton: {
|
|
124
|
+
xs: { size: 24, iconSize: 12 },
|
|
125
|
+
sm: { size: 32, iconSize: 14 },
|
|
126
|
+
md: { size: 40, iconSize: 16 },
|
|
127
|
+
lg: { size: 48, iconSize: 18 },
|
|
128
|
+
xl: { size: 56, iconSize: 20 },
|
|
129
|
+
},
|
|
123
130
|
chip: {
|
|
124
131
|
xs: { paddingVertical: 1, paddingHorizontal: 6, minHeight: 16, borderRadius: 999, fontSize: 10, lineHeight: 12, iconSize: 10 },
|
|
125
132
|
sm: { paddingVertical: 2, paddingHorizontal: 8, minHeight: 20, borderRadius: 999, fontSize: 11, lineHeight: 14, iconSize: 12 },
|
package/src/theme/extensions.ts
CHANGED
|
@@ -22,6 +22,7 @@ export interface DefaultTheme {
|
|
|
22
22
|
chip: Record<string, ChipSizeValue>;
|
|
23
23
|
badge: Record<string, BadgeSizeValue>;
|
|
24
24
|
icon: Record<string, IconSizeValue>;
|
|
25
|
+
iconButton: Record<string, IconSizeValue>;
|
|
25
26
|
input: Record<string, InputSizeValue>;
|
|
26
27
|
radioButton: Record<string, RadioButtonSizeValue>;
|
|
27
28
|
select: Record<string, SelectSizeValue>;
|
package/src/theme/structures.ts
CHANGED
|
@@ -98,6 +98,11 @@ export type ButtonSizeValue = {
|
|
|
98
98
|
iconSize: SizeValue;
|
|
99
99
|
};
|
|
100
100
|
|
|
101
|
+
export type IconButtonSizeValue = {
|
|
102
|
+
size: SizeValue;
|
|
103
|
+
iconSize: SizeValue;
|
|
104
|
+
};
|
|
105
|
+
|
|
101
106
|
export type ChipSizeValue = {
|
|
102
107
|
paddingVertical: SizeValue;
|
|
103
108
|
paddingHorizontal: SizeValue;
|