UNPKG

json-schema-form-render

Version:

A powerful and flexible form builder based on JSON Schema

1,714 lines (1,532 loc) 94.8 kB
// Define the countries array const countries = [ { name: 'Afghanistan', code: 'af', prefix: '93' }, { name: 'Albania', code: 'al', prefix: '355' }, { name: 'Algeria', code: 'dz', prefix: '213' }, { name: 'American Samoa', code: 'as', prefix: '1' }, { name: 'Andorra', code: 'ad', prefix: '376' }, { name: 'Angola', code: 'ao', prefix: '244' }, { name: 'Anguilla', code: 'ai', prefix: '1' }, { name: 'Antigua and Barbuda', code: 'ag', prefix: '1' }, { name: 'Argentina', code: 'ar', prefix: '54' }, { name: 'Armenia', code: 'am', prefix: '374' }, { name: 'Aruba', code: 'aw', prefix: '297' }, { name: 'Australia', code: 'au', prefix: '61' }, { name: 'Austria', code: 'at', prefix: '43' }, { name: 'Azerbaijan', code: 'az', prefix: '994' }, { name: 'Bahamas', code: 'bs', prefix: '1' }, { name: 'Bahrain', code: 'bh', prefix: '973' }, { name: 'Bangladesh', code: 'bd', prefix: '880' }, { name: 'Barbados', code: 'bb', prefix: '1' }, { name: 'Belarus', code: 'by', prefix: '375' }, { name: 'Belgium', code: 'be', prefix: '32' }, { name: 'Belize', code: 'bz', prefix: '501' }, { name: 'Benin', code: 'bj', prefix: '229' }, { name: 'Bermuda', code: 'bm', prefix: '1' }, { name: 'Bhutan', code: 'bt', prefix: '975' }, { name: 'Bonaire, Sint Eustatius and Saba', code: 'bq', prefix: '599' }, { name: 'Bosnia and Herzegovina', code: 'ba', prefix: '387' }, { name: 'Botswana', code: 'bw', prefix: '267' }, { name: 'Brazil', code: 'br', prefix: '55' }, { name: 'British Virgin Islands', code: 'vg', prefix: '1' }, { name: 'Brunei Darussalam', code: 'bn', prefix: '673' }, { name: 'Bulgaria', code: 'bg', prefix: '359' }, { name: 'Burkina Faso', code: 'bf', prefix: '226' }, { name: 'Burundi', code: 'bi', prefix: '257' }, { name: 'Cambodia', code: 'kh', prefix: '855' }, { name: 'Cameroon', code: 'cm', prefix: '237' }, { name: 'Canada', code: 'ca', prefix: '1' }, { name: 'Cayman Islands', code: 'ky', prefix: '1' }, { name: 'Chad', code: 'td', prefix: '235' }, { name: 'Chile', code: 'cl', prefix: '56' }, { name: 'China', code: 'cn', prefix: '86' }, { name: 'Colombia', code: 'co', prefix: '57' }, { name: 'Comoros', code: 'km', prefix: '269' }, { name: 'Congo', code: 'cg', prefix: '242' }, { name: 'Cook Islands', code: 'ck', prefix: '682' }, { name: 'Costa Rica', code: 'cr', prefix: '506' }, { name: 'Croatia', code: 'hr', prefix: '385' }, { name: 'Cuba', code: 'cu', prefix: '53' }, { name: 'Curaçao', code: 'cw', prefix: '599' }, { name: 'Cyprus', code: 'cy', prefix: '357' }, { name: "Côte d'Ivoire", code: 'ci', prefix: '225' }, { name: 'Denmark', code: 'dk', prefix: '45' }, { name: 'Djibouti', code: 'dj', prefix: '253' }, { name: 'Dominica', code: 'dm', prefix: '1' }, { name: 'Ecuador', code: 'ec', prefix: '593' }, { name: 'Egypt', code: 'eg', prefix: '20' }, { name: 'El Salvador', code: 'sv', prefix: '503' }, { name: 'Equatorial Guinea', code: 'gq', prefix: '240' }, { name: 'Eritrea', code: 'er', prefix: '291' }, { name: 'Estonia', code: 'ee', prefix: '372' }, { name: 'Ethiopia', code: 'et', prefix: '251' }, { name: 'Falkland Islands (Malvinas)', code: 'fk', prefix: '500' }, { name: 'Faroe Islands', code: 'fo', prefix: '298' }, { name: 'Fiji', code: 'fj', prefix: '679' }, { name: 'Finland', code: 'fi', prefix: '358' }, { name: 'France', code: 'fr', prefix: '33' }, { name: 'French Guiana', code: 'gf', prefix: '594' }, { name: 'French Polynesia', code: 'pf', prefix: '689' }, { name: 'Gabon', code: 'ga', prefix: '241' }, { name: 'Gambia', code: 'gm', prefix: '220' }, { name: 'Georgia', code: 'ge', prefix: '995' }, { name: 'Germany', code: 'de', prefix: '49' }, { name: 'Ghana', code: 'gh', prefix: '233' }, { name: 'Gibraltar', code: 'gi', prefix: '350' }, { name: 'Greece', code: 'gr', prefix: '30' }, { name: 'Greenland', code: 'gl', prefix: '299' }, { name: 'Grenada', code: 'gd', prefix: '1' }, { name: 'Guadeloupe', code: 'gp', prefix: '590' }, { name: 'Guam', code: 'gu', prefix: '1' }, { name: 'Guatemala', code: 'gt', prefix: '502' }, { name: 'Guinea', code: 'gn', prefix: '224' }, { name: 'Guinea-Bissau', code: 'gw', prefix: '245' }, { name: 'Guyana', code: 'gy', prefix: '592' }, { name: 'Haiti', code: 'ht', prefix: '509' }, { name: 'Honduras', code: 'hn', prefix: '504' }, { name: 'Hungary', code: 'hu', prefix: '36' }, { name: 'Iceland', code: 'is', prefix: '354' }, { name: 'India', code: 'in', prefix: '91' }, { name: 'Indonesia', code: 'id', prefix: '62' }, { name: 'Iraq', code: 'iq', prefix: '964' }, { name: 'Ireland', code: 'ie', prefix: '353' }, { name: 'Israel', code: 'il', prefix: '972' }, { name: 'Italy', code: 'it', prefix: '39' }, { name: 'Jamaica', code: 'jm', prefix: '1' }, { name: 'Japan', code: 'jp', prefix: '81' }, { name: 'Jordan', code: 'jo', prefix: '962' }, { name: 'Kazakhstan', code: 'kz', prefix: '7' }, { name: 'Kenya', code: 'ke', prefix: '254' }, { name: 'Kiribati', code: 'ki', prefix: '686' }, { name: 'Kuwait', code: 'kw', prefix: '965' }, { name: 'Kyrgyzstan', code: 'kg', prefix: '996' }, { name: 'Latvia', code: 'lv', prefix: '371' }, { name: 'Lebanon', code: 'lb', prefix: '961' }, { name: 'Lesotho', code: 'ls', prefix: '266' }, { name: 'Liberia', code: 'lr', prefix: '231' }, { name: 'Libya', code: 'ly', prefix: '218' }, { name: 'Liechtenstein', code: 'li', prefix: '423' }, { name: 'Lithuania', code: 'lt', prefix: '370' }, { name: 'Luxembourg', code: 'lu', prefix: '352' }, { name: 'Madagascar', code: 'mg', prefix: '261' }, { name: 'Malawi', code: 'mw', prefix: '265' }, { name: 'Malaysia', code: 'my', prefix: '60' }, { name: 'Maldives', code: 'mv', prefix: '960' }, { name: 'Mali', code: 'ml', prefix: '223' }, { name: 'Malta', code: 'mt', prefix: '356' }, { name: 'Marshall Islands', code: 'mh', prefix: '692' }, { name: 'Martinique', code: 'mq', prefix: '596' }, { name: 'Mauritania', code: 'mr', prefix: '222' }, { name: 'Mauritius', code: 'mu', prefix: '230' }, { name: 'Mexico', code: 'mx', prefix: '52' }, { name: 'Monaco', code: 'mc', prefix: '377' }, { name: 'Mongolia', code: 'mn', prefix: '976' }, { name: 'Montenegro', code: 'me', prefix: '382' }, { name: 'Montserrat', code: 'ms', prefix: '1' }, { name: 'Morocco', code: 'ma', prefix: '212' }, { name: 'Mozambique', code: 'mz', prefix: '258' }, { name: 'Myanmar', code: 'mm', prefix: '95' }, { name: 'Namibia', code: 'na', prefix: '264' }, { name: 'Nauru', code: 'nr', prefix: '674' }, { name: 'Nepal', code: 'np', prefix: '977' }, { name: 'Netherlands', code: 'nl', prefix: '31' }, { name: 'New Caledonia', code: 'nc', prefix: '687' }, { name: 'New Zealand', code: 'nz', prefix: '64' }, { name: 'Nicaragua', code: 'ni', prefix: '505' }, { name: 'Niger', code: 'ne', prefix: '227' }, { name: 'Nigeria', code: 'ng', prefix: '234' }, { name: 'Niue', code: 'nu', prefix: '683' }, { name: 'Norway', code: 'no', prefix: '47' }, { name: 'Oman', code: 'om', prefix: '968' }, { name: 'Pakistan', code: 'pk', prefix: '92' }, { name: 'Palau', code: 'pw', prefix: '680' }, { name: 'Panama', code: 'pa', prefix: '507' }, { name: 'Papua New Guinea', code: 'pg', prefix: '675' }, { name: 'Paraguay', code: 'py', prefix: '595' }, { name: 'Peru', code: 'pe', prefix: '51' }, { name: 'Philippines', code: 'ph', prefix: '63' }, { name: 'Poland', code: 'pl', prefix: '48' }, { name: 'Portugal', code: 'pt', prefix: '351' }, { name: 'Puerto Rico', code: 'pr', prefix: '1' }, { name: 'Qatar', code: 'qa', prefix: '974' }, { name: 'Romania', code: 'ro', prefix: '40' }, { name: 'Russian Federation', code: 'ru', prefix: '7' }, { name: 'Rwanda', code: 'rw', prefix: '250' }, { name: 'Saint Helena, Ascension and Tristan da Cunha', code: 'sh', prefix: '247' }, { name: 'Saint Kitts and Nevis', code: 'kn', prefix: '1' }, { name: 'Saint Lucia', code: 'lc', prefix: '1' }, { name: 'Saint Pierre and Miquelon', code: 'pm', prefix: '508' }, { name: 'Saint Vincent and the Grenadines', code: 'vc', prefix: '1' }, { name: 'Samoa', code: 'ws', prefix: '685' }, { name: 'San Marino', code: 'sm', prefix: '378' }, { name: 'Sao Tome and Principe', code: 'st', prefix: '239' }, { name: 'Saudi Arabia', code: 'sa', prefix: '966' }, { name: 'Senegal', code: 'sn', prefix: '221' }, { name: 'Serbia', code: 'rs', prefix: '381' }, { name: 'Seychelles', code: 'sc', prefix: '248' }, { name: 'Sierra Leone', code: 'sl', prefix: '232' }, { name: 'Singapore', code: 'sg', prefix: '65' }, { name: 'Sint Maarten (Dutch part)', code: 'sx', prefix: '1' }, { name: 'Slovakia', code: 'sk', prefix: '421' }, { name: 'Slovenia', code: 'si', prefix: '386' }, { name: 'Solomon Islands', code: 'sb', prefix: '677' }, { name: 'Somalia', code: 'so', prefix: '252' }, { name: 'South Africa', code: 'za', prefix: '27' }, { name: 'South Sudan', code: 'ss', prefix: '211' }, { name: 'Spain', code: 'es', prefix: '34' }, { name: 'Sri Lanka', code: 'lk', prefix: '94' }, { name: 'Sudan', code: 'sd', prefix: '249' }, { name: 'Suriname', code: 'sr', prefix: '597' }, { name: 'Sweden', code: 'se', prefix: '46' }, { name: 'Switzerland', code: 'ch', prefix: '41' }, { name: 'Syrian Arab Republic', code: 'sy', prefix: '963' }, { name: 'Tajikistan', code: 'tj', prefix: '992' }, { name: 'Tanzania', code: 'tz', prefix: '255' }, { name: 'Thailand', code: 'th', prefix: '66' }, { name: 'Timor-Leste', code: 'tl', prefix: '670' }, { name: 'Togo', code: 'tg', prefix: '228' }, { name: 'Tokelau', code: 'tk', prefix: '690' }, { name: 'Tonga', code: 'to', prefix: '676' }, { name: 'Trinidad and Tobago', code: 'tt', prefix: '1' }, { name: 'Tunisia', code: 'tn', prefix: '216' }, { name: 'Turkey', code: 'tr', prefix: '90' }, { name: 'Turkmenistan', code: 'tm', prefix: '993' }, { name: 'Turks and Caicos Islands', code: 'tc', prefix: '1' }, { name: 'Tuvalu', code: 'tv', prefix: '688' }, { name: 'Uganda', code: 'ug', prefix: '256' }, { name: 'Ukraine', code: 'ua', prefix: '380' }, { name: 'United Arab Emirates', code: 'ae', prefix: '971' }, { name: 'United Kingdom', code: 'gb', prefix: '44' }, { name: 'United States', code: 'us', prefix: '1' }, { name: 'Uruguay', code: 'uy', prefix: '598' }, { name: 'Uzbekistan', code: 'uz', prefix: '998' }, { name: 'Vanuatu', code: 'vu', prefix: '678' }, { name: 'Viet Nam', code: 'vn', prefix: '84' }, { name: 'Wallis and Futuna', code: 'wf', prefix: '681' }, { name: 'Yemen', code: 'ye', prefix: '967' }, { name: 'Zambia', code: 'zm', prefix: '260' }, { name: 'Zimbabwe', code: 'zw', prefix: '263' }, ]; // Add this function before the countries array function getCountryFlagEmoji(countryCode) { const codePoints = countryCode .toUpperCase() .split('') .map(char => 127397 + char.charCodeAt(0)); return String.fromCodePoint(...codePoints); } export class FormBuilder extends HTMLElement { static get observedAttributes() { return ['schema', 'theme', 'schema-url', 'theme-style', 'theme-color', 'font-family']; } constructor() { super(); this.schema = []; this._values = {}; this.searchableSelects = new Map(); this.currentTheme = { style: 'modern', color: 'ocean' }; this.shadow = this.attachShadow({ mode: 'open' }); this.form = document.createElement('form'); this.setupStyles(); this.setupForm(); } getThemeVariables() { const { style, color, fontFamily } = this.currentTheme; // Modern color palettes const colors = { ocean: { primary: '#00BCD4', secondary: '#008BA3', accent: '#E0F7FA', text: '#263238', background: '#FFFFFF', border: '#B2EBF2', error: '#E57373', success: '#81C784' }, sunset: { primary: '#FF6E40', secondary: '#D84315', accent: '#FBE9E7', text: '#4E342E', background: '#FFFFFF', border: '#FFCCBC', error: '#E53935', success: '#43A047' }, forest: { primary: '#2E7D32', secondary: '#1B5E20', accent: '#E8F5E9', text: '#1B262C', background: '#FFFFFF', border: '#C8E6C9', error: '#D32F2F', success: '#388E3C' }, cosmic: { primary: '#673AB7', secondary: '#512DA8', accent: '#EDE7F6', text: '#212121', background: '#FFFFFF', border: '#D1C4E9', error: '#E91E63', success: '#4CAF50' }, solarized: { primary: '#268BD2', secondary: '#2AA198', accent: '#FDF6E3', text: '#073642', background: '#FFFFFF', border: '#EEE8D5', error: '#DC322F', success: '#859900' } }; // Style configurations const styles = { modern: { borderRadius: '8px', padding: '0.75rem 1rem', borderWidth: '2px', shadow: '0 2px 6px rgba(0,0,0,0.12)', transition: 'all 0.2s ease' }, minimal: { borderRadius: '0', padding: '0.5rem 0.75rem', borderWidth: '1px', shadow: 'none', transition: 'all 0.1s ease' }, rounded: { borderRadius: '24px', padding: '0.75rem 1.25rem', borderWidth: '2px', shadow: '0 2px 4px rgba(0,0,0,0.05)', transition: 'all 0.2s ease' }, flat: { borderRadius: '4px', padding: '0.75rem 1rem', borderWidth: '0', shadow: 'none', transition: 'all 0.2s ease' }, outlined: { borderRadius: '4px', padding: '0.75rem 1rem', borderWidth: '2px', shadow: 'none', transition: 'all 0.2s ease' } }; const palette = colors[color] || colors.ocean; const styleConfig = styles[style] || styles.modern; const defaultFont = "-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif"; return ` :host { /* Colors */ --primary-color: ${palette.primary}; --secondary-color: ${palette.secondary}; --accent-color: ${palette.accent}; --text-color: ${palette.text}; --background-color: ${palette.background}; --border-color: ${palette.border}; --error-color: ${palette.error}; --success-color: ${palette.success}; /* Typography */ --font-family: ${fontFamily || defaultFont}; --line-height: 1.6; --font-size-base: 16px; --font-size-small: 0.875rem; --font-size-large: 1.125rem; --font-weight-normal: 400; --font-weight-medium: 500; --font-weight-bold: 600; /* Border & Shadows */ --border-radius: ${styleConfig.borderRadius}; --input-padding: ${styleConfig.padding}; --border-width: ${styleConfig.borderWidth}; --box-shadow: ${styleConfig.shadow}; --transition: ${styleConfig.transition}; /* Form & Inputs */ --form-padding: 2rem; --label-color: var(--text-color); --input-bg: var(--background-color); --input-hover-bg: var(--accent-color); --focus-color: var(--primary-color); --checkbox-size: 20px; --select-option-hover: var(--accent-color); --select-option-selected: var(--primary-color); /* Buttons */ --button-bg: var(--primary-color); --button-hover-bg: var(--secondary-color); --button-color: #FFFFFF; --button-padding: var(--input-padding); --button-border-radius: var(--border-radius); --button-font-size: var(--font-size-base); --button-font-weight: var(--font-weight-medium); --button-transition: var(--transition); } /* Base Styles */ :host { display: block; font-family: var(--font-family); font-size: var(--font-size-base); line-height: var(--line-height); color: var(--text-color); } form { padding: var(--form-padding); background: var(--background-color); border-radius: var(--border-radius); box-shadow: var(--box-shadow); display: flex; flex-direction: column; gap: 1.5rem; } label { display: block; color: var(--label-color); font-weight: var(--font-weight-medium); font-size: var(--font-size-base); margin-bottom: 0.5rem; } input, select, textarea { width: 100%; padding: var(--input-padding); border: var(--border-width) solid var(--border-color); border-radius: var(--border-radius); font-size: var(--font-size-base); font-family: var(--font-family); background: var(--input-bg); transition: var(--transition); color: var(--text-color); box-sizing: border-box; } input:hover, select:hover, textarea:hover { background: var(--input-hover-bg); border-color: var(--primary-color); } input:focus, select:focus, textarea:focus { outline: none; border-color: var(--focus-color); box-shadow: 0 0 0 3px var(--accent-color); background: var(--input-hover-bg); } .help-text { font-size: var(--font-size-small); color: var(--text-color); opacity: 0.8; margin-top: 0.25rem; } .error { color: var(--error-color); font-size: var(--font-size-small); margin-top: 0.25rem; display: flex; align-items: center; gap: 0.5rem; } button[type="submit"] { background-color: var(--button-bg); color: var(--button-color); padding: var(--button-padding); border: none; border-radius: var(--button-border-radius); font-size: var(--button-font-size); font-weight: var(--button-font-weight); font-family: var(--font-family); cursor: pointer; transition: var(--button-transition); align-self: flex-start; min-width: 120px; } button[type="submit"]:hover { background-color: var(--button-hover-bg); transform: translateY(-1px); box-shadow: var(--box-shadow); } /* Custom Select Styling */ .select-wrapper { position: relative; width: 100%; } .select-search { width: 100%; padding: var(--input-padding); border: var(--border-width) solid var(--border-color); border-radius: var(--border-radius); font-size: 1rem; background: var(--input-bg); transition: all var(--transition-speed) ease; cursor: pointer; } .select-options { position: absolute; top: calc(100% + 0.5rem); left: 0; right: 0; background: var(--background-color); border: var(--border-width) solid var(--border-color); border-radius: var(--border-radius); max-height: 200px; overflow-y: auto; z-index: 1000; box-shadow: var(--box-shadow); display: none; } .select-options.show { display: block; } .select-option { padding: 0.75rem 1rem; cursor: pointer; transition: background-color var(--transition-speed) ease; } .select-option:hover { background-color: var(--select-option-hover); } .select-option.selected { background-color: var(--select-option-selected); } /* Custom Checkbox Styling */ .checkbox-wrapper { display: flex; align-items: center; gap: 0.75rem; padding: 0.5rem; border-radius: var(--border-radius); transition: background-color var(--transition-speed) ease; cursor: pointer; } .checkbox-wrapper:hover { background-color: var(--input-bg); } .checkbox-wrapper input[type="checkbox"] { position: absolute; opacity: 0; width: 0; height: 0; } .checkbox-custom { position: relative; width: var(--checkbox-size); height: var(--checkbox-size); border: 2px solid var(--border-color); border-radius: var(--border-radius); transition: all var(--transition-speed) ease; flex-shrink: 0; } .checkbox-wrapper input[type="checkbox"]:checked + .checkbox-custom { background-color: var(--focus-color); border-color: var(--focus-color); } .checkbox-wrapper input[type="checkbox"]:checked + .checkbox-custom::after { content: "✓"; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); color: white; font-size: 14px; } /* Radio Group Styling */ .radio-group { display: flex; flex-direction: column; gap: 0.5rem; } .radio-wrapper { display: flex; align-items: center; gap: 0.75rem; padding: 0.5rem; border-radius: var(--border-radius); transition: background-color var(--transition-speed) ease; cursor: pointer; } .radio-wrapper:hover { background-color: var(--input-bg); } .radio-wrapper input[type="radio"] { position: absolute; opacity: 0; width: 0; height: 0; } .radio-custom { position: relative; width: var(--checkbox-size); height: var(--checkbox-size); border: 2px solid var(--border-color); border-radius: 50%; transition: all var(--transition-speed) ease; flex-shrink: 0; } .radio-wrapper input[type="radio"]:checked + .radio-custom { border-color: var(--focus-color); } .radio-wrapper input[type="radio"]:checked + .radio-custom::after { content: ""; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 10px; height: 10px; background-color: var(--focus-color); border-radius: 50%; } /* Telephone Input Styling */ .telephone-wrapper { display: flex; gap: 0.5rem; align-items: center; } .country-code-wrapper { position: relative; min-width: 80px; max-width: 100px; } .country-code-display { display: flex; align-items: center; gap: 0.25rem; padding: var(--input-padding); background: var(--input-bg); border: var(--border-width) solid var(--border-color); border-radius: var(--border-radius); font-size: 0.9rem; color: var(--text-color); cursor: pointer; transition: var(--transition); white-space: nowrap; overflow: hidden; } .country-code-display:hover { border-color: var(--primary-color); background: var(--accent-color); } .country-code-display img { width: 16px; height: 12px; object-fit: cover; border-radius: 2px; flex-shrink: 0; } .country-options { position: absolute; top: calc(100% + 0.5rem); left: 0; right: 0; background: var(--background-color); border: var(--border-width) solid var(--border-color); border-radius: var(--border-radius); max-height: 300px; overflow-y: auto; z-index: 1000; display: none; box-shadow: var(--box-shadow); padding: 0.5rem; min-width: 200px; } .country-options .select-search { width: 100%; padding: var(--input-padding); margin-bottom: 0.5rem; border: var(--border-width) solid var(--border-color); border-radius: var(--border-radius); font-size: 0.9rem; background: var(--input-bg); color: var(--text-color); } .options-container { max-height: 200px; overflow-y: auto; scrollbar-width: thin; scrollbar-color: var(--primary-color) var(--input-bg); } .options-container::-webkit-scrollbar { width: 6px; } .options-container::-webkit-scrollbar-track { background: var(--input-bg); border-radius: 3px; } .options-container::-webkit-scrollbar-thumb { background: var(--primary-color); border-radius: 3px; } .country-option { display: flex; align-items: center; gap: 0.5rem; padding: 0.5rem; cursor: pointer; transition: background-color 0.2s; color: var(--text-color); white-space: nowrap; } .country-option:hover { background-color: var(--accent-color); } .country-option img { width: 16px; height: 12px; object-fit: cover; border-radius: 2px; flex-shrink: 0; } .country-name { flex: 1; font-size: 0.9rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; color: var(--text-color); } .country-prefix { color: var(--primary-color); font-weight: 500; flex-shrink: 0; } .telephone-input { flex: 1; } @media (max-width: 768px) { .country-options { position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 90%; max-width: 400px; max-height: 80vh; margin: 0; z-index: 1000; background: var(--background-color); } .options-container { max-height: calc(80vh - 60px); } .country-option { padding: 0.75rem; } .country-name { font-size: 1rem; } } /* Password Input Styling */ .password-wrapper { position: relative; width: 100%; display: flex; align-items: center; } .password-toggle { position: absolute; right: 10px; top: 50%; transform: translateY(-50%); background: none; border: none; padding: 5px; cursor: pointer; color: var(--text-color); opacity: 0.7; transition: opacity 0.2s; display: flex; align-items: center; justify-content: center; } .password-toggle:hover { opacity: 1; } .password-toggle svg { width: 20px; height: 20px; fill: currentColor; } .password-wrapper input[type="password"], .password-wrapper input[type="text"] { padding-right: 40px; } /* Color Input Styling */ .color-wrapper { display: flex; align-items: center; gap: 1rem; } input[type="color"] { -webkit-appearance: none; width: 50px; height: 50px; padding: 0; border: var(--border-width) solid var(--border-color); border-radius: var(--border-radius); cursor: pointer; background: none; } input[type="color"]::-webkit-color-swatch-wrapper { padding: 0; border-radius: var(--border-radius); } input[type="color"]::-webkit-color-swatch { border: none; border-radius: var(--border-radius); } input[type="color"]:hover { border-color: var(--primary-color); } .color-preview { font-size: 0.9rem; color: var(--text-color); opacity: 0.8; } /* File Input Styling */ .file-wrapper { position: relative; width: 100%; } .file-input { position: absolute; left: 0; top: 0; width: 100%; height: 100%; opacity: 0; cursor: pointer; z-index: 2; } .file-label { display: flex; align-items: center; gap: 1rem; padding: var(--input-padding); border: 2px dashed var(--border-color); border-radius: var(--border-radius); background: var(--input-bg); transition: var(--transition); cursor: pointer; } .file-label:hover { border-color: var(--primary-color); background: var(--input-hover-bg); } .file-icon { width: 24px; height: 24px; color: var(--primary-color); } .file-text { color: var(--text-color); font-size: 0.9rem; } .file-list { margin-top: 0.5rem; display: flex; flex-direction: column; gap: 0.5rem; } .file-item { display: flex; align-items: center; gap: 0.5rem; padding: 0.5rem; background: var(--input-bg); border-radius: var(--border-radius); font-size: 0.9rem; color: var(--text-color); } .file-item-name { flex: 1; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .file-item-size { color: var(--text-color); opacity: 0.7; font-size: 0.8rem; } .file-item-remove { background: none; border: none; color: var(--error-color); cursor: pointer; padding: 0.25rem; opacity: 0.7; transition: opacity 0.2s; } .file-item-remove:hover { opacity: 1; } /* Time Input Styling */ input[type="time"] { position: relative; cursor: pointer; } input[type="time"]::-webkit-calendar-picker-indicator { cursor: pointer; opacity: 0.7; transition: opacity 0.2s; } input[type="time"]::-webkit-calendar-picker-indicator:hover { opacity: 1; } input[type="time"]::-webkit-datetime-edit { padding: 0; } input[type="time"]::-webkit-datetime-edit-fields-wrapper { padding: 0; } input[type="time"]::-webkit-datetime-edit-text { padding: 0 0.2em; } input[type="time"]::-webkit-datetime-edit-hour-field, input[type="time"]::-webkit-datetime-edit-minute-field, input[type="time"]::-webkit-datetime-edit-second-field { padding: 0 0.2em; } /* Image Input Styling */ .image-wrapper { position: relative; width: 100%; } .image-preview-container { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 1rem; margin-top: 1rem; } .image-preview { position: relative; aspect-ratio: 1; border-radius: var(--border-radius); overflow: hidden; background: var(--input-bg); border: 2px solid var(--border-color); } .image-preview img { width: 100%; height: 100%; object-fit: cover; } .image-preview .remove-image { position: absolute; top: 0.5rem; right: 0.5rem; background: rgba(0, 0, 0, 0.5); color: white; border: none; border-radius: 50%; width: 24px; height: 24px; display: flex; align-items: center; justify-content: center; cursor: pointer; opacity: 0; transition: opacity 0.2s; } .image-preview:hover .remove-image { opacity: 1; } .image-preview .remove-image:hover { background: rgba(0, 0, 0, 0.7); } .image-input-label { display: flex; align-items: center; gap: 1rem; padding: var(--input-padding); border: 2px dashed var(--border-color); border-radius: var(--border-radius); background: var(--input-bg); transition: var(--transition); cursor: pointer; } .image-input-label:hover { border-color: var(--primary-color); background: var(--input-hover-bg); } .image-icon { width: 24px; height: 24px; color: var(--primary-color); } `; } setupStyles() { const style = document.createElement('style'); style.textContent = this.getThemeVariables() + ` form { padding: var(--form-padding); background: var(--background-color); border-radius: var(--border-radius); box-shadow: var(--box-shadow); display: flex; flex-direction: column; gap: 1.5rem; } .field-group { margin-bottom: 0; position: relative; display: flex; flex-direction: column; gap: 0.5rem; } label { display: block; color: var(--label-color); font-weight: 500; font-size: 0.95rem; transition: var(--transition); } input, select, textarea { width: 100%; padding: var(--input-padding); border: var(--border-width) solid var(--border-color); border-radius: var(--border-radius); font-size: 1rem; background: var(--input-bg); transition: var(--transition); color: var(--text-color); box-sizing: border-box; } input:hover, select:hover, textarea:hover { background: var(--input-hover-bg); border-color: var(--primary-color); } input:focus, select:focus, textarea:focus { outline: none; border-color: var(--focus-color); box-shadow: 0 0 0 3px var(--accent-color); background: var(--input-hover-bg); } /* Custom Select Styling */ .select-wrapper { position: relative; width: 100%; } .select-search { width: 100%; padding: var(--input-padding); border: var(--border-width) solid var(--border-color); border-radius: var(--border-radius); font-size: 1rem; background: var(--input-bg); transition: all var(--transition-speed) ease; cursor: pointer; } .select-options { position: absolute; top: calc(100% + 0.5rem); left: 0; right: 0; background: var(--background-color); border: var(--border-width) solid var(--border-color); border-radius: var(--border-radius); max-height: 200px; overflow-y: auto; z-index: 1000; box-shadow: var(--box-shadow); display: none; } .select-options.show { display: block; } .select-option { padding: 0.75rem 1rem; cursor: pointer; transition: background-color var(--transition-speed) ease; } .select-option:hover { background-color: var(--select-option-hover); } .select-option.selected { background-color: var(--select-option-selected); } /* Custom Checkbox Styling */ .checkbox-wrapper { display: flex; align-items: center; gap: 0.75rem; padding: 0.5rem; border-radius: var(--border-radius); transition: background-color var(--transition-speed) ease; cursor: pointer; } .checkbox-wrapper:hover { background-color: var(--input-bg); } .checkbox-wrapper input[type="checkbox"] { position: absolute; opacity: 0; width: 0; height: 0; } .checkbox-custom { position: relative; width: var(--checkbox-size); height: var(--checkbox-size); border: 2px solid var(--border-color); border-radius: var(--border-radius); transition: all var(--transition-speed) ease; flex-shrink: 0; } .checkbox-wrapper input[type="checkbox"]:checked + .checkbox-custom { background-color: var(--focus-color); border-color: var(--focus-color); } .checkbox-wrapper input[type="checkbox"]:checked + .checkbox-custom::after { content: "✓"; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); color: white; font-size: 14px; } /* Radio Group Styling */ .radio-group { display: flex; flex-direction: column; gap: 0.5rem; } .radio-wrapper { display: flex; align-items: center; gap: 0.75rem; padding: 0.5rem; border-radius: var(--border-radius); transition: background-color var(--transition-speed) ease; cursor: pointer; } .radio-wrapper:hover { background-color: var(--input-bg); } .radio-wrapper input[type="radio"] { position: absolute; opacity: 0; width: 0; height: 0; } .radio-custom { position: relative; width: var(--checkbox-size); height: var(--checkbox-size); border: 2px solid var(--border-color); border-radius: 50%; transition: all var(--transition-speed) ease; flex-shrink: 0; } .radio-wrapper input[type="radio"]:checked + .radio-custom { border-color: var(--focus-color); } .radio-wrapper input[type="radio"]:checked + .radio-custom::after { content: ""; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 10px; height: 10px; background-color: var(--focus-color); border-radius: 50%; } /* Button Styling */ button[type="submit"] { background-color: var(--button-bg); color: var(--button-color); padding: var(--button-padding); border: none; border-radius: var(--button-border-radius); font-size: var(--button-font-size); font-weight: var(--button-font-weight); cursor: pointer; transition: var(--button-transition); align-self: flex-start; min-width: 120px; } button[type="submit"]:hover { background-color: var(--button-hover-bg); transform: translateY(-1px); box-shadow: var(--shadow-md); } button[type="submit"]:active { transform: translateY(0); box-shadow: var(--shadow-sm); } /* Help Text Styling */ .help-text { font-size: 0.875rem; color: #666; margin-top: 0.25rem; } /* Error Message Styling */ .error { color: var(--error-color); font-size: 0.875rem; margin-top: 0.25rem; display: flex; align-items: center; gap: 0.5rem; } .error::before { content: "⚠️"; } /* Dark Mode Support */ @media (prefers-color-scheme: dark) { :host { --label-color: #ecf0f1; --border-color: #34495e; --input-bg: #2c3e50; --input-hover-bg: #34495e; --background-color: #2c3e50; --select-option-hover: #34495e; --select-option-selected: #2c3e50; --text-color: #ecf0f1; } input, select, textarea { color: var(--text-color); } .select-options { background: var(--background-color); border-color: var(--border-color); } .help-text { color: #bdc3c7; } /* Preserve theme style in dark mode */ .country-code-display, .select-search, input, select, textarea { border-width: var(--border-width); border-radius: var(--border-radius); padding: var(--input-padding); } } /* Enhanced Number Input Styling */ input[type="number"] { -moz-appearance: textfield; } input[type="number"]::-webkit-outer-spin-button, input[type="number"]::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; position: absolute; top: 0; right: 0; bottom: 0; width: 2.5em; border-left: 1px solid var(--border-color); opacity: 0.5; cursor: pointer; display: flex; align-items: center; justify-content: center; transition: opacity 0.2s; background: var(--input-bg); } input[type="number"]:hover::-webkit-outer-spin-button, input[type="number"]:hover::-webkit-inner-spin-button { opacity: 1; } input[type="number"]::-webkit-outer-spin-button::before, input[type="number"]::-webkit-inner-spin-button::before { content: ""; position: absolute; width: 0; height: 0; border-left: 5px solid transparent; border-right: 5px solid transparent; } input[type="number"]::-webkit-outer-spin-button::before { border-bottom: 5px solid var(--text-color); top: 25%; } input[type="number"]::-webkit-inner-spin-button::before { border-top: 5px solid var(--text-color); bottom: 25%; } /* Custom Scrollbar Styling */ .select-options::-webkit-scrollbar { width: 8px; } .select-options::-webkit-scrollbar-track { background: var(--input-bg); border-radius: 4px; } .select-options::-webkit-scrollbar-thumb { background: var(--primary-color); border-radius: 4px; } .select-options::-webkit-scrollbar-thumb:hover { background: var(--secondary-color); } /* Telephone Input Styling */ .telephone-wrapper { display: flex; gap: 0.5rem; align-items: center; } .country-code-wrapper { position: relative; min-width: 80px; max-width: 100px; } .country-code-display { display: flex; align-items: center; gap: 0.25rem; padding: var(--input-padding); background: var(--input-bg); border: var(--border-width) solid var(--border-color); border-radius: var(--border-radius); font-size: 0.9rem; color: var(--text-color); cursor: pointer; transition: var(--transition); white-space: nowrap; overflow: hidden; } .country-code-display:hover { border-color: var(--primary-color); background: var(--accent-color); } .country-code-display img { width: 16px; height: 12px; object-fit: cover; border-radius: 2px; flex-shrink: 0; } .country-options { position: absolute; top: calc(100% + 0.5rem); left: 0; right: 0; background: var(--background-color); border: var(--border-width) solid var(--border-color); border-radius: var(--border-radius); max-height: 300px; overflow-y: auto; z-index: 1000; display: none; box-shadow: var(--box-shadow); padding: 0.5rem; min-width: 200px; } .country-options .select-search { width: 100%; padding: var(--input-padding); margin-bottom: 0.5rem; border: var(--border-width) solid var(--border-color); border-radius: var(--border-radius); font-size: 0.9rem; background: var(--input-bg); color: var(--text-color); } .country-options .select-search:focus { outline: none; border-color: var(--primary-color); box-shadow: 0 0 0 2px var(--accent-color); } .options-container { max-height: 200px; overflow-y: auto; scrollbar-width: thin; scrollbar-color: var(--primary-color) var(--input-bg); } .options-container::-webkit-scrollbar { width: 6px; } .options-container::-webkit-scrollbar-track { background: var(--input-bg); border-radius: 3px; } .options-container::-webkit-scrollbar-thumb { background: var(--primary-color); border-radius: 3px; } .country-option { display: flex; align-items: center; gap: 0.5rem; padding: 0.5rem; cursor: pointer; transition: background-color 0.2s; color: var(--text-color); white-space: nowrap; } .country-option:hover { background-color: var(--accent-color); } .country-option img { width: 16px; height: 12px; object-fit: cover; border-radius: 2px; flex-shrink: 0; } .country-name { flex: 1; font-size: 0.9rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; color: var(--text-color); } .country-prefix { color: var(--primary-color); font-weight: 500; flex-shrink: 0; } .telephone-input { flex: 1; } @media (max-width: 768px) { .country-options { position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 90%; max-width: 400px; max-height: 80vh; margin: 0; z-index: 1000; background: var(--background-color); } .options-container { max-height: calc(80vh - 60px); } .country-option { padding: 0.75rem; } .country-name { font-size: 1rem; } } /* Password Input Styling */ .password-wrapper { position: relative; width: 100%; display: flex; align-items: center; } .password-toggle { position: absolute; right: 10px; top: 50%; transform: translateY(-50%); background: none; border: none; padding: 5px; cursor: pointer; color: var(--text-color); opacity: 0.7; transition: opacity 0.2s; display: flex; align-items: center; justify-content: center; } .password-toggle:hover { opacity: 1; } .password-toggle svg { width: 20px; height: 20px; fill: currentColor; } .password-wrapper input[type="password"], .password-wrapper input[type="text"] { padding-right: 40px; } /* Color Input Styling */ .color-wrapper { display: flex; align-items: center; gap: 1rem; } input[type="color"] { -webkit-appearance: none; width: 50px; height: 50px; padding: 0; border: var(--border-width) solid var(--border-color); border-radius: var(--border-radius); cursor: pointer; background: none; } input[type="color"]::-webkit-color-swatch-wrapper { padding: 0; border-radius: var(--border-radius); } input[type="color"]::-webkit-color-swatch { border: none; border-radius: var(--border-radius); } input[type="color"]:hover { border-color: var(--primary-color); } .color-preview { font-size: 0.9rem; color: var(--text-color); opacity: 0.8; } /* File Input Styling */ .file-wrapper { position: relative; width: 100%; } .file-input { position: absolute; left: 0; top: 0; width: 100%; height: 100%; opacity: 0; cursor: pointer; z-index: 2; } .file-label { display: flex; align-items: center; gap: 1rem; padding: var(--input-padding); border: 2px dashed var(--border-color); border-radius: var(--border-radius); background: var(--input-bg); transition: var(--transition); cursor: pointer; } .file-label:hover { border-color: var(--primary-color); background: var(--input-hover-bg); } .file-icon { width: 24px; height: 24px; color: var(--primary-color); } .file-text { color: var(--text-color); font-size: 0.9rem; } .file-list { margin-top: 0.5rem; display: flex; flex-direction: column; gap: 0.5rem; } .file-item { display: flex; align-items: cent