tailwind-to-style 2.7.2 → 2.7.4

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/dist/index.esm.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * tailwind-to-style v2.7.2
2
+ * tailwind-to-style v2.7.4
3
3
  * Convert tailwind classes to inline style
4
4
  *
5
5
  * @author Bigetion
@@ -1529,12 +1529,10 @@ function getConfigOptions() {
1529
1529
  const themeKeys = Object.keys(configOptions.theme);
1530
1530
  themeKeys.forEach(key => {
1531
1531
  newTheme[key] = theme[key] || configOptions.theme[key];
1532
- if (isFunction(newTheme[key])) {
1533
- newTheme[key] = newTheme[key]({
1534
- theme: keyRef => {
1535
- return configOptions.theme[keyRef];
1536
- }
1537
- });
1532
+ });
1533
+ themeKeys.forEach(key => {
1534
+ if (themeExtend[key] && newTheme[key]) {
1535
+ newTheme[key] = Object.assign({}, newTheme[key], themeExtend[key]);
1538
1536
  }
1539
1537
  });
1540
1538
  themeKeys.forEach(key => {
@@ -1545,9 +1543,6 @@ function getConfigOptions() {
1545
1543
  }
1546
1544
  });
1547
1545
  }
1548
- if (themeExtend[key]) {
1549
- newTheme[key] = Object.assign({}, newTheme[key], themeExtend[key]);
1550
- }
1551
1546
  });
1552
1547
  return {
1553
1548
  prefix: "",
@@ -6309,10 +6304,10 @@ function parseCustomClassWithPatterns(className) {
6309
6304
  return null;
6310
6305
  }
6311
6306
 
6312
- /**
6313
- * Resolve all CSS custom properties (var) in a CSS string and output only clear CSS (no custom property)
6314
- * @param {string} cssString
6315
- * @returns {string} e.g. 'color: rgba(255,255,255,1); background: #fff;'
6307
+ /**
6308
+ * Resolve all CSS custom properties (var) in a CSS string and output only clear CSS (no custom property)
6309
+ * @param {string} cssString
6310
+ * @returns {string} e.g. 'color: rgba(255,255,255,1); background: #fff;'
6316
6311
  */
6317
6312
  function resolveCssToClearCss(cssString) {
6318
6313
  const customVars = {};
@@ -6379,19 +6374,196 @@ function convertCssToObject(cssString) {
6379
6374
  }
6380
6375
  let twString = null;
6381
6376
  let cssObject = null;
6382
- if (!twString) {
6383
- twString = generateTailwindCssString().replace(/\s\s+/g, " ");
6377
+
6378
+ // Global config storage key
6379
+ const CONFIG_STORAGE_KEY = "__tailwind_to_style_global_config__";
6380
+
6381
+ // Default configuration
6382
+ const defaultConfig = {
6383
+ theme: {
6384
+ extend: {
6385
+ colors: {}
6386
+ },
6387
+ screens: {
6388
+ sm: "640px",
6389
+ md: "768px",
6390
+ lg: "1024px",
6391
+ xl: "1280px",
6392
+ "2xl": "1536px"
6393
+ }
6394
+ },
6395
+ inject: true
6396
+ };
6397
+
6398
+ // Detect environment and create global storage
6399
+ function getGlobalStorage() {
6400
+ if (typeof window !== "undefined") {
6401
+ // Browser environment - use window object
6402
+ if (!window[CONFIG_STORAGE_KEY]) {
6403
+ window[CONFIG_STORAGE_KEY] = {
6404
+ ...defaultConfig
6405
+ };
6406
+ }
6407
+ return window[CONFIG_STORAGE_KEY];
6408
+ } else if (typeof global !== "undefined") {
6409
+ // Node.js environment - use global object
6410
+ if (!global[CONFIG_STORAGE_KEY]) {
6411
+ global[CONFIG_STORAGE_KEY] = {
6412
+ ...defaultConfig
6413
+ };
6414
+ }
6415
+ return global[CONFIG_STORAGE_KEY];
6416
+ } else {
6417
+ // Fallback - use module-level variable (will work only within same file)
6418
+ console.warn("tailwind-to-style: Unable to create global config storage. Config will only work within the same module.");
6419
+ return defaultConfig;
6420
+ }
6421
+ }
6422
+
6423
+ // Get global config reference
6424
+ let globalConfig = getGlobalStorage();
6425
+ function initializeCss() {
6426
+ if (!twString) {
6427
+ // Always get fresh config from global storage
6428
+ const currentConfig = getGlobalStorage();
6429
+ const configForGeneration = {
6430
+ ...currentConfig,
6431
+ theme: {
6432
+ ...currentConfig.theme
6433
+ }
6434
+ };
6435
+ twString = generateTailwindCssString(configForGeneration).replace(/\s\s+/g, " ");
6436
+ }
6437
+ if (!cssObject) {
6438
+ cssObject = convertCssToObject(twString);
6439
+ }
6440
+ }
6441
+ initializeCss();
6442
+ function convertScreensToBreakpoints(screens) {
6443
+ const breakpoints = {};
6444
+ for (const [key, value] of Object.entries(screens)) {
6445
+ breakpoints[key] = `@media (min-width: ${value})`;
6446
+ }
6447
+ return breakpoints;
6448
+ }
6449
+
6450
+ /**
6451
+ * Set global configuration for both tws and twsx functions
6452
+ * @param {Object} config - Global configuration object
6453
+ * @returns {Object} Current global configuration
6454
+ */
6455
+ function setConfig(config) {
6456
+ var _config$theme, _config$theme2, _config$theme2$extend, _config$theme3;
6457
+ // Reset CSS object cache when config changes
6458
+ twString = null;
6459
+ cssObject = null;
6460
+ configOptionsCache.clear();
6461
+
6462
+ // Get current global storage reference
6463
+ const globalStorage = getGlobalStorage();
6464
+
6465
+ // Update global storage directly
6466
+ Object.assign(globalStorage, {
6467
+ ...globalStorage,
6468
+ ...config,
6469
+ theme: {
6470
+ ...globalStorage.theme,
6471
+ ...(config.theme || {}),
6472
+ extend: {
6473
+ ...globalStorage.theme.extend,
6474
+ ...(((_config$theme = config.theme) === null || _config$theme === void 0 ? void 0 : _config$theme.extend) || {}),
6475
+ colors: {
6476
+ ...globalStorage.theme.extend.colors,
6477
+ ...(((_config$theme2 = config.theme) === null || _config$theme2 === void 0 ? void 0 : (_config$theme2$extend = _config$theme2.extend) === null || _config$theme2$extend === void 0 ? void 0 : _config$theme2$extend.colors) || {})
6478
+ }
6479
+ }
6480
+ }
6481
+ });
6482
+
6483
+ // Handle screens configuration
6484
+ if ((_config$theme3 = config.theme) !== null && _config$theme3 !== void 0 && _config$theme3.screens) {
6485
+ globalStorage.theme.screens = {
6486
+ ...globalStorage.theme.screens,
6487
+ ...config.theme.screens
6488
+ };
6489
+ }
6490
+
6491
+ // Handle legacy breakpoints with deprecation warning
6492
+ if (config.breakpoints) {
6493
+ console.warn("Warning: config.breakpoints is deprecated. Use config.theme.screens instead.");
6494
+
6495
+ // Convert legacy breakpoints to screens format
6496
+ const screens = {};
6497
+ for (const [key, value] of Object.entries(config.breakpoints)) {
6498
+ // Extract min-width value from media query
6499
+ const match = value.match(/min-width:\s*([^)]+)/);
6500
+ if (match) {
6501
+ screens[key] = match[1].trim();
6502
+ }
6503
+ }
6504
+ globalStorage.theme.screens = {
6505
+ ...globalStorage.theme.screens,
6506
+ ...screens
6507
+ };
6508
+ }
6509
+
6510
+ // Update local reference
6511
+ globalConfig = globalStorage;
6512
+ initializeCss();
6513
+ return {
6514
+ ...globalConfig
6515
+ };
6516
+ }
6517
+
6518
+ /**
6519
+ * Get current global configuration
6520
+ * @returns {Object} Current global configuration
6521
+ */
6522
+ function getConfig() {
6523
+ // Always get fresh reference from global storage
6524
+ globalConfig = getGlobalStorage();
6525
+ return {
6526
+ ...globalConfig
6527
+ };
6384
6528
  }
6385
- if (!cssObject) {
6529
+
6530
+ /**
6531
+ * Reset global configuration to default
6532
+ * @returns {Object} Default configuration
6533
+ */
6534
+ function resetConfig() {
6535
+ twString = null;
6536
+ cssObject = null;
6537
+ configOptionsCache.clear();
6538
+
6539
+ // Get global storage reference and reset it
6540
+ const globalStorage = getGlobalStorage();
6541
+
6542
+ // Reset to default config
6543
+ Object.assign(globalStorage, {
6544
+ theme: {
6545
+ extend: {
6546
+ colors: {}
6547
+ },
6548
+ screens: {
6549
+ sm: "640px",
6550
+ md: "768px",
6551
+ lg: "1024px",
6552
+ xl: "1280px",
6553
+ "2xl": "1536px"
6554
+ }
6555
+ },
6556
+ inject: true
6557
+ });
6558
+
6559
+ // Update local reference
6560
+ globalConfig = globalStorage;
6561
+ twString = generateTailwindCssString(globalConfig).replace(/\s\s+/g, " ");
6386
6562
  cssObject = convertCssToObject(twString);
6563
+ return {
6564
+ ...globalConfig
6565
+ };
6387
6566
  }
6388
- const breakpoints = {
6389
- sm: "@media (min-width: 640px)",
6390
- md: "@media (min-width: 768px)",
6391
- lg: "@media (min-width: 1024px)",
6392
- xl: "@media (min-width: 1280px)",
6393
- "2xl": "@media (min-width: 1536px)"
6394
- };
6395
6567
  const pseudoVariants = new Set(["hover", "focus", "focus-within", "active", "visited", "disabled", "first", "last", "checked", "invalid", "required"]);
6396
6568
  const specialVariants = {
6397
6569
  group: (state, sel) => `.group:${state} ${sel}`,
@@ -6441,6 +6613,9 @@ function resolveVariants(selector, variants) {
6441
6613
  let media = null;
6442
6614
  let finalSelector = selector;
6443
6615
  for (const v of variants) {
6616
+ // Always get fresh config from global storage
6617
+ const currentConfig = getGlobalStorage();
6618
+ const breakpoints = convertScreensToBreakpoints(currentConfig.theme.screens || {});
6444
6619
  if (breakpoints[v]) {
6445
6620
  media = breakpoints[v];
6446
6621
  } else if (pseudoVariants.has(v)) {
@@ -6502,7 +6677,7 @@ function debounce(func) {
6502
6677
  callCount++;
6503
6678
  clearTimeout(timeout);
6504
6679
  timeout = setTimeout(() => {
6505
- const marker = performanceMonitor.start(`debounced:${func.name || 'anonymous'}`);
6680
+ const marker = performanceMonitor.start(`debounced:${func.name || "anonymous"}`);
6506
6681
  try {
6507
6682
  const result = func.apply(context, args);
6508
6683
  performanceMonitor.end(marker);
@@ -6590,11 +6765,11 @@ function separateAndResolveCSS(arr) {
6590
6765
  }
6591
6766
  }
6592
6767
 
6593
- /**
6594
- * Process opacity modifier from class name (e.g., text-red-500/50 -> 50% opacity)
6595
- * @param {string} className - Class name with potential opacity modifier
6596
- * @param {string} cssDeclaration - CSS declaration to modify
6597
- * @returns {string} Modified CSS declaration with opacity applied
6768
+ /**
6769
+ * Process opacity modifier from class name (e.g., text-red-500/50 -> 50% opacity)
6770
+ * @param {string} className - Class name with potential opacity modifier
6771
+ * @param {string} cssDeclaration - CSS declaration to modify
6772
+ * @returns {string} Modified CSS declaration with opacity applied
6598
6773
  */
6599
6774
  function processOpacityModifier(className, cssDeclaration) {
6600
6775
  const opacityMatch = className.match(/\/(\d+)$/);
@@ -6607,20 +6782,20 @@ function processOpacityModifier(className, cssDeclaration) {
6607
6782
  let modifiedDeclaration = cssDeclaration;
6608
6783
 
6609
6784
  // Replace opacity custom properties
6610
- const opacityProperties = ['--text-opacity', '--bg-opacity', '--border-opacity', '--ring-opacity', '--divide-opacity', '--placeholder-opacity', '--text-decoration-opacity', '--outline-opacity', '--accent-opacity', '--caret-opacity'];
6785
+ const opacityProperties = ["--text-opacity", "--bg-opacity", "--border-opacity", "--ring-opacity", "--divide-opacity", "--placeholder-opacity", "--text-decoration-opacity", "--outline-opacity", "--accent-opacity", "--caret-opacity"];
6611
6786
  opacityProperties.forEach(prop => {
6612
- const propRegex = new RegExp(`${prop}\\s*:\\s*[\\d.]+`, 'gi');
6787
+ const propRegex = new RegExp(`${prop}\\s*:\\s*[\\d.]+`, "gi");
6613
6788
  modifiedDeclaration = modifiedDeclaration.replace(propRegex, `${prop}: ${alphaValue}`);
6614
6789
  });
6615
6790
 
6616
6791
  // Also handle direct color values that might not use CSS variables
6617
- const colorProperties = ['color', 'background-color', 'border-color', 'text-decoration-color', 'outline-color', 'fill', 'stroke', 'caret-color', 'accent-color'];
6792
+ const colorProperties = ["color", "background-color", "border-color", "text-decoration-color", "outline-color", "fill", "stroke", "caret-color", "accent-color"];
6618
6793
  colorProperties.forEach(prop => {
6619
6794
  // Match rgb(), rgba(), hsl(), hsla() functions
6620
- const rgbRegex = new RegExp(`(${prop}\\s*:\\s*)rgb\\((\\d+),\\s*(\\d+),\\s*(\\d+)\\)`, 'gi');
6621
- const rgbaRegex = new RegExp(`(${prop}\\s*:\\s*)rgba\\((\\d+),\\s*(\\d+),\\s*(\\d+),\\s*[\\d.]+\\)`, 'gi');
6622
- const hslRegex = new RegExp(`(${prop}\\s*:\\s*)hsl\\((\\d+),\\s*([\\d.]+%),\\s*([\\d.]+%)\\)`, 'gi');
6623
- const hslaRegex = new RegExp(`(${prop}\\s*:\\s*)hsla\\((\\d+),\\s*([\\d.]+%),\\s*([\\d.]+%),\\s*[\\d.]+\\)`, 'gi');
6795
+ const rgbRegex = new RegExp(`(${prop}\\s*:\\s*)rgb\\((\\d+),\\s*(\\d+),\\s*(\\d+)\\)`, "gi");
6796
+ const rgbaRegex = new RegExp(`(${prop}\\s*:\\s*)rgba\\((\\d+),\\s*(\\d+),\\s*(\\d+),\\s*[\\d.]+\\)`, "gi");
6797
+ const hslRegex = new RegExp(`(${prop}\\s*:\\s*)hsl\\((\\d+),\\s*([\\d.]+%),\\s*([\\d.]+%)\\)`, "gi");
6798
+ const hslaRegex = new RegExp(`(${prop}\\s*:\\s*)hsla\\((\\d+),\\s*([\\d.]+%),\\s*([\\d.]+%),\\s*[\\d.]+\\)`, "gi");
6624
6799
 
6625
6800
  // Convert rgb to rgba with opacity
6626
6801
  modifiedDeclaration = modifiedDeclaration.replace(rgbRegex, `$1rgba($2, $3, $4, ${alphaValue})`);
@@ -6635,10 +6810,10 @@ function processOpacityModifier(className, cssDeclaration) {
6635
6810
  modifiedDeclaration = modifiedDeclaration.replace(hslaRegex, `$1hsla($2, $3, $4, ${alphaValue})`);
6636
6811
 
6637
6812
  // Handle hex colors
6638
- const hexRegex = new RegExp(`(${prop}\\s*:\\s*)(#[0-9a-fA-F]{3,6})`, 'gi');
6639
- modifiedDeclaration = modifiedDeclaration.replace(hexRegex, (match, propPart, hexColor) => {
6813
+ const hexRegex = new RegExp(`(${prop}\\s*:\\s*)(#[0-9a-fA-F]{3,6})`, "gi");
6814
+ modifiedDeclaration = modifiedDeclaration.replace(hexRegex, (_, propPart, hexColor) => {
6640
6815
  // Convert hex to rgba
6641
- const hex = hexColor.replace('#', '');
6816
+ const hex = hexColor.replace("#", "");
6642
6817
  let r, g, b;
6643
6818
  if (hex.length === 3) {
6644
6819
  r = parseInt(hex[0] + hex[0], 16);
@@ -6655,15 +6830,17 @@ function processOpacityModifier(className, cssDeclaration) {
6655
6830
  return modifiedDeclaration;
6656
6831
  }
6657
6832
 
6658
- /**
6659
- * Convert Tailwind class string to inline CSS styles or JSON object
6660
- * @param {string} classNames - String containing Tailwind classes to convert
6661
- * @param {boolean} convertToJson - If true, result will be JSON object, if false becomes CSS string
6662
- * @returns {string|Object} Inline CSS string or style JSON object
6833
+ /**
6834
+ * Convert Tailwind class string to inline CSS styles or JSON object
6835
+ * @param {string} classNames - String containing Tailwind classes to convert
6836
+ * @param {boolean} convertToJson - If true, result will be JSON object, if false becomes CSS string
6837
+ * @returns {string|Object} Inline CSS string or style JSON object
6663
6838
  */
6664
6839
  function tws(classNames, convertToJson) {
6665
6840
  const totalMarker = performanceMonitor.start("tws:total");
6666
6841
  try {
6842
+ // Ensure CSS is initialized with current global config
6843
+ initializeCss();
6667
6844
  if ([!classNames, typeof classNames !== "string", classNames.trim() === ""].includes(true)) {
6668
6845
  performanceMonitor.end(totalMarker);
6669
6846
  return convertToJson ? {} : "";
@@ -6690,11 +6867,11 @@ function tws(classNames, convertToJson) {
6690
6867
  const processMarker = performanceMonitor.start("tws:process");
6691
6868
  let cssResult = classes.map(className => {
6692
6869
  // Extract base class name without opacity modifier
6693
- const baseClassName = className.replace(/\/\d+$/, '');
6870
+ const baseClassName = className.replace(/\/\d+$/, "");
6694
6871
  let result = cssObject[baseClassName] || cssObject[baseClassName.replace(/(\/)/g, "\\$1")] || cssObject[baseClassName.replace(/\./g, "\\.")];
6695
6872
  if (result) {
6696
6873
  // Apply opacity modifier if present
6697
- if (className.includes('/') && /\/\d+$/.test(className)) {
6874
+ if (className.includes("/") && /\/\d+$/.test(className)) {
6698
6875
  result = processOpacityModifier(className, result);
6699
6876
  }
6700
6877
  return resolveCssToClearCss(result);
@@ -6706,7 +6883,7 @@ function tws(classNames, convertToJson) {
6706
6883
  if (cssObject[`${baseKey}custom`]) {
6707
6884
  let customResult = cssObject[`${baseKey}custom`].replace(/custom_value/g, customValue);
6708
6885
  // Apply opacity modifier to custom values too
6709
- if (className.includes('/') && /\/\d+$/.test(className)) {
6886
+ if (className.includes("/") && /\/\d+$/.test(className)) {
6710
6887
  customResult = processOpacityModifier(className, customResult);
6711
6888
  }
6712
6889
  return customResult;
@@ -6842,7 +7019,7 @@ function processClass(cls, selector, styles) {
6842
7019
  } = resolveVariants(selector, rawVariants);
6843
7020
 
6844
7021
  // Extract base class name without opacity modifier for CSS lookup
6845
- const baseClassName = pureClassName.replace(/\/\d+$/, '');
7022
+ const baseClassName = pureClassName.replace(/\/\d+$/, "");
6846
7023
  let declarations = cssObject[baseClassName] || cssObject[baseClassName.replace(/(\/)/g, "\\$1")] || cssObject[baseClassName.replace(/\./g, "\\.")];
6847
7024
  if (!declarations && baseClassName.includes("[")) {
6848
7025
  const match = baseClassName.match(/^(.+?)\[(.+)\]$/);
@@ -6863,7 +7040,7 @@ function processClass(cls, selector, styles) {
6863
7040
  }
6864
7041
 
6865
7042
  // Apply opacity modifier if present
6866
- if (pureClassName.includes('/') && /\/\d+$/.test(pureClassName)) {
7043
+ if (pureClassName.includes("/") && /\/\d+$/.test(pureClassName)) {
6867
7044
  declarations = processOpacityModifier(pureClassName, declarations);
6868
7045
  }
6869
7046
  if (isImportant) {
@@ -7038,12 +7215,12 @@ function generateCssString(styles) {
7038
7215
  return cssString.trim();
7039
7216
  }
7040
7217
 
7041
- /**
7042
- * Generate CSS string from style object with SCSS-like syntax
7043
- * Supports nested selectors, state variants, responsive variants, and @css directives
7044
- * @param {Object} obj - Object with SCSS-like style format
7045
- * @param {Object} [options] - Additional options, e.g. { inject: true/false }
7046
- * @returns {string} Generated CSS string
7218
+ /**
7219
+ * Generate CSS string from style object with SCSS-like syntax
7220
+ * Supports nested selectors, state variants, responsive variants, and @css directives
7221
+ * @param {Object} obj - Object with SCSS-like style format
7222
+ * @param {Object} [options] - Additional options, merges with global config
7223
+ * @returns {string} Generated CSS string
7047
7224
  */
7048
7225
  function twsx(obj) {
7049
7226
  let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
@@ -7053,9 +7230,13 @@ function twsx(obj) {
7053
7230
  console.warn("twsx: Expected an object but received:", obj);
7054
7231
  return "";
7055
7232
  }
7233
+ const mergedOptions = {
7234
+ ...getGlobalStorage(),
7235
+ ...options
7236
+ };
7056
7237
  const {
7057
7238
  inject = true
7058
- } = options;
7239
+ } = mergedOptions;
7059
7240
  const styles = {};
7060
7241
 
7061
7242
  // Create walk function with closure over styles
@@ -7150,19 +7331,19 @@ function autoInjectCss(cssString) {
7150
7331
  }
7151
7332
 
7152
7333
  // Enhanced debounced functions with performance monitoring configuration
7153
- /**
7154
- * Debounced version of tws function with performance monitoring
7155
- * @param {string} classNames - String containing Tailwind classes to convert
7156
- * @param {boolean} convertToJson - If true, result will be JSON object, if false becomes CSS string
7157
- * @returns {string|Object} Inline CSS string or style JSON object
7334
+ /**
7335
+ * Debounced version of tws function with performance monitoring
7336
+ * @param {string} classNames - String containing Tailwind classes to convert
7337
+ * @param {boolean} convertToJson - If true, result will be JSON object, if false becomes CSS string
7338
+ * @returns {string|Object} Inline CSS string or style JSON object
7158
7339
  */
7159
7340
  const debouncedTws = debounce(tws, 50); // Faster debounce for tws
7160
7341
 
7161
- /**
7162
- * Debounced version of twsx function with performance monitoring
7163
- * @param {Object} obj - Object with SCSS-like style format
7164
- * @param {Object} [options] - Additional options
7165
- * @returns {string} Generated CSS string
7342
+ /**
7343
+ * Debounced version of twsx function with performance monitoring
7344
+ * @param {Object} obj - Object with SCSS-like style format
7345
+ * @param {Object} [options] - Additional options
7346
+ * @returns {string} Generated CSS string
7166
7347
  */
7167
7348
  const debouncedTwsx = debounce(twsx, 100); // Standard debounce for twsx
7168
7349
 
@@ -7194,8 +7375,8 @@ const performanceUtils = {
7194
7375
  enablePerformanceLogging() {
7195
7376
  let enabled = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
7196
7377
  performanceMonitor.enabled = enabled && typeof performance !== "undefined";
7197
- console.log(`Performance monitoring ${enabled ? 'enabled' : 'disabled'}`);
7378
+ console.log(`Performance monitoring ${enabled ? "enabled" : "disabled"}`);
7198
7379
  }
7199
7380
  };
7200
7381
 
7201
- export { debouncedTws, debouncedTwsx, performanceUtils, tws, twsx };
7382
+ export { debouncedTws, debouncedTwsx, getConfig, performanceUtils, resetConfig, setConfig, tws, twsx };