@dmitryvim/form-builder 0.2.17 → 0.2.18

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.
@@ -729,6 +729,21 @@ function updateTextField(element, fieldPath, value, context) {
729
729
  }
730
730
 
731
731
  // src/components/textarea.ts
732
+ function applyAutoExpand(textarea) {
733
+ textarea.style.overflow = "hidden";
734
+ textarea.style.resize = "none";
735
+ const lineCount = (textarea.value.match(/\n/g) || []).length + 1;
736
+ textarea.rows = Math.max(1, lineCount);
737
+ const resize = () => {
738
+ if (!textarea.isConnected) return;
739
+ textarea.style.height = "0";
740
+ textarea.style.height = `${textarea.scrollHeight}px`;
741
+ };
742
+ textarea.addEventListener("input", resize);
743
+ setTimeout(() => {
744
+ if (textarea.isConnected) resize();
745
+ }, 0);
746
+ }
732
747
  function renderTextareaElement(element, ctx, wrapper, pathKey) {
733
748
  const state = ctx.state;
734
749
  const textareaWrapper = document.createElement("div");
@@ -749,6 +764,9 @@ function renderTextareaElement(element, ctx, wrapper, pathKey) {
749
764
  textareaInput.addEventListener("blur", handleChange);
750
765
  textareaInput.addEventListener("input", handleChange);
751
766
  }
767
+ if (element.autoExpand || state.config.readonly) {
768
+ applyAutoExpand(textareaInput);
769
+ }
752
770
  textareaWrapper.appendChild(textareaInput);
753
771
  if (!state.config.readonly && (element.minLength != null || element.maxLength != null)) {
754
772
  const counter = createCharCounter(element, textareaInput, true);
@@ -798,6 +816,9 @@ function renderMultipleTextareaElement(element, ctx, wrapper, pathKey) {
798
816
  textareaInput.addEventListener("blur", handleChange);
799
817
  textareaInput.addEventListener("input", handleChange);
800
818
  }
819
+ if (element.autoExpand || state.config.readonly) {
820
+ applyAutoExpand(textareaInput);
821
+ }
801
822
  textareaContainer.appendChild(textareaInput);
802
823
  if (!state.config.readonly && (element.minLength != null || element.maxLength != null)) {
803
824
  const counter = createCharCounter(element, textareaInput, true);
@@ -899,6 +920,24 @@ function validateTextareaElement(element, key, context) {
899
920
  }
900
921
  function updateTextareaField(element, fieldPath, value, context) {
901
922
  updateTextField(element, fieldPath, value, context);
923
+ const { scopeRoot, state } = context;
924
+ const shouldAutoExpand = element.autoExpand || state.config.readonly;
925
+ if (!shouldAutoExpand) return;
926
+ if (element.multiple) {
927
+ const textareas = scopeRoot.querySelectorAll(
928
+ `textarea[name^="${fieldPath}["]`
929
+ );
930
+ textareas.forEach((textarea) => {
931
+ textarea.dispatchEvent(new Event("input"));
932
+ });
933
+ } else {
934
+ const textarea = scopeRoot.querySelector(
935
+ `textarea[name="${fieldPath}"]`
936
+ );
937
+ if (textarea) {
938
+ textarea.dispatchEvent(new Event("input"));
939
+ }
940
+ }
902
941
  }
903
942
 
904
943
  // src/components/number.ts
@@ -1567,6 +1606,430 @@ function updateSelectField(element, fieldPath, value, context) {
1567
1606
  }
1568
1607
  }
1569
1608
 
1609
+ // src/components/switcher.ts
1610
+ function applySelectedStyle(btn) {
1611
+ btn.style.backgroundColor = "var(--fb-primary-color)";
1612
+ btn.style.color = "#ffffff";
1613
+ btn.style.borderColor = "var(--fb-primary-color)";
1614
+ }
1615
+ function applyUnselectedStyle(btn) {
1616
+ btn.style.backgroundColor = "transparent";
1617
+ btn.style.color = "var(--fb-text-color)";
1618
+ btn.style.borderColor = "var(--fb-border-color)";
1619
+ }
1620
+ function buildSegmentedGroup(element, currentValue, hiddenInput, readonly, onChange) {
1621
+ const options = element.options || [];
1622
+ const group = document.createElement("div");
1623
+ group.className = "fb-switcher-group";
1624
+ group.style.cssText = `
1625
+ display: inline-flex;
1626
+ flex-direction: row;
1627
+ flex-wrap: nowrap;
1628
+ `;
1629
+ const buttons = [];
1630
+ options.forEach((option, index) => {
1631
+ const btn = document.createElement("button");
1632
+ btn.type = "button";
1633
+ btn.className = "fb-switcher-btn";
1634
+ btn.dataset.value = option.value;
1635
+ btn.textContent = option.label;
1636
+ btn.style.cssText = `
1637
+ padding: var(--fb-input-padding-y) var(--fb-input-padding-x);
1638
+ font-size: var(--fb-font-size);
1639
+ border-width: var(--fb-border-width);
1640
+ border-style: solid;
1641
+ cursor: ${readonly ? "default" : "pointer"};
1642
+ transition: background-color var(--fb-transition-duration), color var(--fb-transition-duration), border-color var(--fb-transition-duration);
1643
+ white-space: nowrap;
1644
+ line-height: 1.25;
1645
+ outline: none;
1646
+ `;
1647
+ if (options.length === 1) {
1648
+ btn.style.borderRadius = "var(--fb-border-radius)";
1649
+ } else if (index === 0) {
1650
+ btn.style.borderRadius = "var(--fb-border-radius) 0 0 var(--fb-border-radius)";
1651
+ btn.style.borderRightWidth = "0";
1652
+ } else if (index === options.length - 1) {
1653
+ btn.style.borderRadius = "0 var(--fb-border-radius) var(--fb-border-radius) 0";
1654
+ } else {
1655
+ btn.style.borderRadius = "0";
1656
+ btn.style.borderRightWidth = "0";
1657
+ }
1658
+ if (option.value === currentValue) {
1659
+ applySelectedStyle(btn);
1660
+ } else {
1661
+ applyUnselectedStyle(btn);
1662
+ }
1663
+ if (!readonly) {
1664
+ btn.addEventListener("click", () => {
1665
+ hiddenInput.value = option.value;
1666
+ buttons.forEach((b) => {
1667
+ if (b.dataset.value === option.value) {
1668
+ applySelectedStyle(b);
1669
+ } else {
1670
+ applyUnselectedStyle(b);
1671
+ }
1672
+ });
1673
+ if (onChange) {
1674
+ onChange(option.value);
1675
+ }
1676
+ });
1677
+ btn.addEventListener("mouseenter", () => {
1678
+ if (hiddenInput.value !== option.value) {
1679
+ btn.style.backgroundColor = "var(--fb-background-hover-color)";
1680
+ }
1681
+ });
1682
+ btn.addEventListener("mouseleave", () => {
1683
+ if (hiddenInput.value !== option.value) {
1684
+ btn.style.backgroundColor = "transparent";
1685
+ }
1686
+ });
1687
+ }
1688
+ buttons.push(btn);
1689
+ group.appendChild(btn);
1690
+ });
1691
+ return group;
1692
+ }
1693
+ function renderSwitcherElement(element, ctx, wrapper, pathKey) {
1694
+ var _a, _b;
1695
+ const state = ctx.state;
1696
+ const initialValue = String((_b = (_a = ctx.prefill[element.key]) != null ? _a : element.default) != null ? _b : "");
1697
+ const hiddenInput = document.createElement("input");
1698
+ hiddenInput.type = "hidden";
1699
+ hiddenInput.name = pathKey;
1700
+ hiddenInput.value = initialValue;
1701
+ const readonly = state.config.readonly;
1702
+ const onChange = !readonly && ctx.instance ? (value) => {
1703
+ ctx.instance.triggerOnChange(pathKey, value);
1704
+ } : null;
1705
+ const group = buildSegmentedGroup(
1706
+ element,
1707
+ initialValue,
1708
+ hiddenInput,
1709
+ readonly,
1710
+ onChange
1711
+ );
1712
+ wrapper.appendChild(hiddenInput);
1713
+ wrapper.appendChild(group);
1714
+ if (!readonly) {
1715
+ const hint = document.createElement("p");
1716
+ hint.className = "text-xs text-gray-500 mt-1";
1717
+ hint.textContent = makeFieldHint(element, state);
1718
+ wrapper.appendChild(hint);
1719
+ }
1720
+ }
1721
+ function renderMultipleSwitcherElement(element, ctx, wrapper, pathKey) {
1722
+ var _a, _b, _c, _d;
1723
+ const state = ctx.state;
1724
+ const prefillValues = ctx.prefill[element.key] || [];
1725
+ const values = Array.isArray(prefillValues) ? [...prefillValues] : [];
1726
+ const minCount = (_a = element.minCount) != null ? _a : 1;
1727
+ const maxCount = (_b = element.maxCount) != null ? _b : Infinity;
1728
+ while (values.length < minCount) {
1729
+ values.push(element.default || ((_d = (_c = element.options) == null ? void 0 : _c[0]) == null ? void 0 : _d.value) || "");
1730
+ }
1731
+ const readonly = state.config.readonly;
1732
+ const container = document.createElement("div");
1733
+ container.className = "space-y-2";
1734
+ wrapper.appendChild(container);
1735
+ function updateIndices() {
1736
+ const items = container.querySelectorAll(".multiple-switcher-item");
1737
+ items.forEach((item, index) => {
1738
+ const input = item.querySelector("input[type=hidden]");
1739
+ if (input) {
1740
+ input.name = `${pathKey}[${index}]`;
1741
+ }
1742
+ });
1743
+ }
1744
+ function addSwitcherItem(value = "", index = -1) {
1745
+ const currentIndex = index === -1 ? container.children.length : index;
1746
+ const itemPathKey = `${pathKey}[${currentIndex}]`;
1747
+ const itemWrapper = document.createElement("div");
1748
+ itemWrapper.className = "multiple-switcher-item flex items-center gap-2";
1749
+ const hiddenInput = document.createElement("input");
1750
+ hiddenInput.type = "hidden";
1751
+ hiddenInput.name = itemPathKey;
1752
+ hiddenInput.value = value;
1753
+ itemWrapper.appendChild(hiddenInput);
1754
+ const onChange = !readonly && ctx.instance ? (val) => {
1755
+ ctx.instance.triggerOnChange(hiddenInput.name, val);
1756
+ } : null;
1757
+ const group = buildSegmentedGroup(
1758
+ element,
1759
+ value,
1760
+ hiddenInput,
1761
+ readonly,
1762
+ onChange
1763
+ );
1764
+ itemWrapper.appendChild(group);
1765
+ if (index === -1) {
1766
+ container.appendChild(itemWrapper);
1767
+ } else {
1768
+ container.insertBefore(itemWrapper, container.children[index]);
1769
+ }
1770
+ updateIndices();
1771
+ return itemWrapper;
1772
+ }
1773
+ function updateRemoveButtons() {
1774
+ if (readonly) return;
1775
+ const items = container.querySelectorAll(".multiple-switcher-item");
1776
+ const currentCount = items.length;
1777
+ items.forEach((item) => {
1778
+ let removeBtn = item.querySelector(
1779
+ ".remove-item-btn"
1780
+ );
1781
+ if (!removeBtn) {
1782
+ removeBtn = document.createElement("button");
1783
+ removeBtn.type = "button";
1784
+ removeBtn.className = "remove-item-btn px-2 py-1 rounded";
1785
+ removeBtn.style.cssText = `
1786
+ color: var(--fb-error-color);
1787
+ background-color: transparent;
1788
+ transition: background-color var(--fb-transition-duration);
1789
+ `;
1790
+ removeBtn.innerHTML = "\u2715";
1791
+ removeBtn.addEventListener("mouseenter", () => {
1792
+ removeBtn.style.backgroundColor = "var(--fb-background-hover-color)";
1793
+ });
1794
+ removeBtn.addEventListener("mouseleave", () => {
1795
+ removeBtn.style.backgroundColor = "transparent";
1796
+ });
1797
+ removeBtn.onclick = () => {
1798
+ const currentIndex = Array.from(container.children).indexOf(
1799
+ item
1800
+ );
1801
+ if (container.children.length > minCount) {
1802
+ values.splice(currentIndex, 1);
1803
+ item.remove();
1804
+ updateIndices();
1805
+ updateAddButton();
1806
+ updateRemoveButtons();
1807
+ }
1808
+ };
1809
+ item.appendChild(removeBtn);
1810
+ }
1811
+ const disabled = currentCount <= minCount;
1812
+ removeBtn.disabled = disabled;
1813
+ removeBtn.style.opacity = disabled ? "0.5" : "1";
1814
+ removeBtn.style.pointerEvents = disabled ? "none" : "auto";
1815
+ });
1816
+ }
1817
+ let addRow = null;
1818
+ let countDisplay = null;
1819
+ if (!readonly) {
1820
+ addRow = document.createElement("div");
1821
+ addRow.className = "flex items-center gap-3 mt-2";
1822
+ const addBtn = document.createElement("button");
1823
+ addBtn.type = "button";
1824
+ addBtn.className = "add-switcher-btn px-3 py-1 rounded";
1825
+ addBtn.style.cssText = `
1826
+ color: var(--fb-primary-color);
1827
+ border: var(--fb-border-width) solid var(--fb-primary-color);
1828
+ background-color: transparent;
1829
+ font-size: var(--fb-font-size);
1830
+ transition: all var(--fb-transition-duration);
1831
+ `;
1832
+ addBtn.textContent = "+";
1833
+ addBtn.addEventListener("mouseenter", () => {
1834
+ addBtn.style.backgroundColor = "var(--fb-background-hover-color)";
1835
+ });
1836
+ addBtn.addEventListener("mouseleave", () => {
1837
+ addBtn.style.backgroundColor = "transparent";
1838
+ });
1839
+ addBtn.onclick = () => {
1840
+ var _a2, _b2;
1841
+ const defaultValue = element.default || ((_b2 = (_a2 = element.options) == null ? void 0 : _a2[0]) == null ? void 0 : _b2.value) || "";
1842
+ values.push(defaultValue);
1843
+ addSwitcherItem(defaultValue);
1844
+ updateAddButton();
1845
+ updateRemoveButtons();
1846
+ };
1847
+ countDisplay = document.createElement("span");
1848
+ countDisplay.className = "text-sm text-gray-500";
1849
+ addRow.appendChild(addBtn);
1850
+ addRow.appendChild(countDisplay);
1851
+ wrapper.appendChild(addRow);
1852
+ }
1853
+ function updateAddButton() {
1854
+ if (!addRow || !countDisplay) return;
1855
+ const addBtn = addRow.querySelector(
1856
+ ".add-switcher-btn"
1857
+ );
1858
+ if (addBtn) {
1859
+ const disabled = values.length >= maxCount;
1860
+ addBtn.disabled = disabled;
1861
+ addBtn.style.opacity = disabled ? "0.5" : "1";
1862
+ addBtn.style.pointerEvents = disabled ? "none" : "auto";
1863
+ }
1864
+ countDisplay.textContent = `${values.length}/${maxCount === Infinity ? "\u221E" : maxCount}`;
1865
+ }
1866
+ values.forEach((value) => addSwitcherItem(value));
1867
+ updateAddButton();
1868
+ updateRemoveButtons();
1869
+ if (!readonly) {
1870
+ const hint = document.createElement("p");
1871
+ hint.className = "text-xs text-gray-500 mt-1";
1872
+ hint.textContent = makeFieldHint(element, state);
1873
+ wrapper.appendChild(hint);
1874
+ }
1875
+ }
1876
+ function validateSwitcherElement(element, key, context) {
1877
+ var _a;
1878
+ const errors = [];
1879
+ const { scopeRoot, skipValidation } = context;
1880
+ const markValidity = (input, errorMessage) => {
1881
+ var _a2, _b;
1882
+ if (!input) return;
1883
+ const errorId = `error-${input.getAttribute("name") || Math.random().toString(36).substring(7)}`;
1884
+ let errorElement = document.getElementById(errorId);
1885
+ if (errorMessage) {
1886
+ input.classList.add("invalid");
1887
+ input.title = errorMessage;
1888
+ if (!errorElement) {
1889
+ errorElement = document.createElement("div");
1890
+ errorElement.id = errorId;
1891
+ errorElement.className = "error-message";
1892
+ errorElement.style.cssText = `
1893
+ color: var(--fb-error-color);
1894
+ font-size: var(--fb-font-size-small);
1895
+ margin-top: 0.25rem;
1896
+ `;
1897
+ if (input.nextSibling) {
1898
+ (_a2 = input.parentNode) == null ? void 0 : _a2.insertBefore(errorElement, input.nextSibling);
1899
+ } else {
1900
+ (_b = input.parentNode) == null ? void 0 : _b.appendChild(errorElement);
1901
+ }
1902
+ }
1903
+ errorElement.textContent = errorMessage;
1904
+ errorElement.style.display = "block";
1905
+ } else {
1906
+ input.classList.remove("invalid");
1907
+ input.title = "";
1908
+ if (errorElement) {
1909
+ errorElement.remove();
1910
+ }
1911
+ }
1912
+ };
1913
+ const validateMultipleCount = (fieldKey, values, el, filterFn) => {
1914
+ var _a2, _b;
1915
+ if (skipValidation) return;
1916
+ const { state } = context;
1917
+ const filteredValues = values.filter(filterFn);
1918
+ const minCount = "minCount" in el ? (_a2 = el.minCount) != null ? _a2 : 1 : 1;
1919
+ const maxCount = "maxCount" in el ? (_b = el.maxCount) != null ? _b : Infinity : Infinity;
1920
+ if (el.required && filteredValues.length === 0) {
1921
+ errors.push(`${fieldKey}: ${t("required", state)}`);
1922
+ }
1923
+ if (filteredValues.length < minCount) {
1924
+ errors.push(`${fieldKey}: ${t("minItems", state, { min: minCount })}`);
1925
+ }
1926
+ if (filteredValues.length > maxCount) {
1927
+ errors.push(`${fieldKey}: ${t("maxItems", state, { max: maxCount })}`);
1928
+ }
1929
+ };
1930
+ const validOptionValues = new Set(
1931
+ "options" in element ? element.options.map((o) => o.value) : []
1932
+ );
1933
+ if ("multiple" in element && element.multiple) {
1934
+ const inputs = scopeRoot.querySelectorAll(
1935
+ `input[type="hidden"][name^="${key}["]`
1936
+ );
1937
+ const values = [];
1938
+ inputs.forEach((input) => {
1939
+ var _a2;
1940
+ const val = (_a2 = input == null ? void 0 : input.value) != null ? _a2 : "";
1941
+ values.push(val);
1942
+ if (!skipValidation && val !== "" && !validOptionValues.has(val)) {
1943
+ const msg = t("invalidOption", context.state);
1944
+ markValidity(input, msg);
1945
+ errors.push(`${key}: ${msg}`);
1946
+ } else {
1947
+ markValidity(input, null);
1948
+ }
1949
+ });
1950
+ validateMultipleCount(key, values, element, (v) => v !== "");
1951
+ return { value: values, errors };
1952
+ } else {
1953
+ const input = scopeRoot.querySelector(
1954
+ `input[type="hidden"][name$="${key}"]`
1955
+ );
1956
+ const val = (_a = input == null ? void 0 : input.value) != null ? _a : "";
1957
+ if (!skipValidation && element.required && val === "") {
1958
+ const msg = t("required", context.state);
1959
+ errors.push(`${key}: ${msg}`);
1960
+ markValidity(input, msg);
1961
+ return { value: null, errors };
1962
+ }
1963
+ if (!skipValidation && val !== "" && !validOptionValues.has(val)) {
1964
+ const msg = t("invalidOption", context.state);
1965
+ errors.push(`${key}: ${msg}`);
1966
+ markValidity(input, msg);
1967
+ return { value: null, errors };
1968
+ }
1969
+ markValidity(input, null);
1970
+ return { value: val === "" ? null : val, errors };
1971
+ }
1972
+ }
1973
+ function updateSwitcherField(element, fieldPath, value, context) {
1974
+ var _a;
1975
+ const { scopeRoot } = context;
1976
+ if ("multiple" in element && element.multiple) {
1977
+ if (!Array.isArray(value)) {
1978
+ console.warn(
1979
+ `updateSwitcherField: Expected array for multiple field "${fieldPath}", got ${typeof value}`
1980
+ );
1981
+ return;
1982
+ }
1983
+ const inputs = scopeRoot.querySelectorAll(
1984
+ `input[type="hidden"][name^="${fieldPath}["]`
1985
+ );
1986
+ inputs.forEach((input, index) => {
1987
+ var _a2;
1988
+ if (index < value.length) {
1989
+ const newVal = value[index] != null ? String(value[index]) : "";
1990
+ input.value = newVal;
1991
+ const group = (_a2 = input.parentElement) == null ? void 0 : _a2.querySelector(".fb-switcher-group");
1992
+ if (group) {
1993
+ group.querySelectorAll(".fb-switcher-btn").forEach((btn) => {
1994
+ if (btn.dataset.value === newVal) {
1995
+ applySelectedStyle(btn);
1996
+ } else {
1997
+ applyUnselectedStyle(btn);
1998
+ }
1999
+ });
2000
+ }
2001
+ input.classList.remove("invalid");
2002
+ input.title = "";
2003
+ }
2004
+ });
2005
+ if (value.length !== inputs.length) {
2006
+ console.warn(
2007
+ `updateSwitcherField: Multiple field "${fieldPath}" has ${inputs.length} inputs but received ${value.length} values. Consider re-rendering for add/remove.`
2008
+ );
2009
+ }
2010
+ } else {
2011
+ const input = scopeRoot.querySelector(
2012
+ `input[type="hidden"][name="${fieldPath}"]`
2013
+ );
2014
+ if (input) {
2015
+ const newVal = value != null ? String(value) : "";
2016
+ input.value = newVal;
2017
+ const group = (_a = input.parentElement) == null ? void 0 : _a.querySelector(".fb-switcher-group");
2018
+ if (group) {
2019
+ group.querySelectorAll(".fb-switcher-btn").forEach((btn) => {
2020
+ if (btn.dataset.value === newVal) {
2021
+ applySelectedStyle(btn);
2022
+ } else {
2023
+ applyUnselectedStyle(btn);
2024
+ }
2025
+ });
2026
+ }
2027
+ input.classList.remove("invalid");
2028
+ input.title = "";
2029
+ }
2030
+ }
2031
+ }
2032
+
1570
2033
  // src/components/file.ts
1571
2034
  function renderLocalImagePreview(container, file, fileName, state) {
1572
2035
  const img = document.createElement("img");
@@ -4617,6 +5080,13 @@ function dispatchToRenderer(element, ctx, wrapper, pathKey) {
4617
5080
  renderSelectElement(element, ctx, wrapper, pathKey);
4618
5081
  }
4619
5082
  break;
5083
+ case "switcher":
5084
+ if (isMultiple) {
5085
+ renderMultipleSwitcherElement(element, ctx, wrapper, pathKey);
5086
+ } else {
5087
+ renderSwitcherElement(element, ctx, wrapper, pathKey);
5088
+ }
5089
+ break;
4620
5090
  case "file":
4621
5091
  if (isMultiple) {
4622
5092
  renderMultipleFileElement(element, ctx, wrapper, pathKey);
@@ -4740,7 +5210,8 @@ var defaultConfig = {
4740
5210
  invalidHexColour: "Invalid hex color",
4741
5211
  minFiles: "Minimum {min} files required",
4742
5212
  maxFiles: "Maximum {max} files allowed",
4743
- unsupportedFieldType: "Unsupported field type: {type}"
5213
+ unsupportedFieldType: "Unsupported field type: {type}",
5214
+ invalidOption: "Invalid option"
4744
5215
  },
4745
5216
  ru: {
4746
5217
  // UI texts
@@ -4785,7 +5256,8 @@ var defaultConfig = {
4785
5256
  invalidHexColour: "\u041D\u0435\u0432\u0435\u0440\u043D\u044B\u0439 \u0444\u043E\u0440\u043C\u0430\u0442 \u0446\u0432\u0435\u0442\u0430",
4786
5257
  minFiles: "\u041C\u0438\u043D\u0438\u043C\u0443\u043C {min} \u0444\u0430\u0439\u043B\u043E\u0432",
4787
5258
  maxFiles: "\u041C\u0430\u043A\u0441\u0438\u043C\u0443\u043C {max} \u0444\u0430\u0439\u043B\u043E\u0432",
4788
- unsupportedFieldType: "\u041D\u0435\u043F\u043E\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u043C\u044B\u0439 \u0442\u0438\u043F \u043F\u043E\u043B\u044F: {type}"
5259
+ unsupportedFieldType: "\u041D\u0435\u043F\u043E\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u043C\u044B\u0439 \u0442\u0438\u043F \u043F\u043E\u043B\u044F: {type}",
5260
+ invalidOption: "\u041D\u0435\u0434\u043E\u043F\u0443\u0441\u0442\u0438\u043C\u043E\u0435 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435"
4789
5261
  }
4790
5262
  },
4791
5263
  theme: {}
@@ -5030,6 +5502,10 @@ var componentRegistry = {
5030
5502
  validate: validateSelectElement,
5031
5503
  update: updateSelectField
5032
5504
  },
5505
+ switcher: {
5506
+ validate: validateSwitcherElement,
5507
+ update: updateSwitcherField
5508
+ },
5033
5509
  file: {
5034
5510
  validate: validateFileElement,
5035
5511
  update: updateFileField